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/base/optional.h"
10 #include "src/compiler/access-info.h"
11 #include "src/compiler/bytecode-analysis.h"
12 #include "src/compiler/compilation-dependencies.h"
13 #include "src/compiler/js-heap-broker.h"
14 #include "src/compiler/serializer-hints.h"
15 #include "src/compiler/zone-stats.h"
16 #include "src/handles/handles-inl.h"
17 #include "src/ic/call-optimization.h"
18 #include "src/interpreter/bytecode-array-iterator.h"
19 #include "src/objects/code.h"
20 #include "src/objects/js-array-inl.h"
21 #include "src/objects/js-regexp-inl.h"
22 #include "src/objects/literal-objects-inl.h"
23 #include "src/objects/shared-function-info-inl.h"
24 #include "src/zone/zone-containers.h"
25 #include "src/zone/zone.h"
26
27 namespace v8 {
28 namespace internal {
29 namespace compiler {
30
31 #define KILL_ENVIRONMENT_LIST(V) \
32 V(Abort) \
33 V(ReThrow) \
34 V(Throw)
35
36 #define CLEAR_ACCUMULATOR_LIST(V) \
37 V(CallRuntime) \
38 V(CloneObject) \
39 V(CreateArrayFromIterable) \
40 V(CreateEmptyObjectLiteral) \
41 V(CreateMappedArguments) \
42 V(CreateRestParameter) \
43 V(CreateUnmappedArguments) \
44 V(DeletePropertySloppy) \
45 V(DeletePropertyStrict) \
46 V(ForInContinue) \
47 V(ForInEnumerate) \
48 V(ForInStep) \
49 V(LogicalNot) \
50 V(SetPendingMessage) \
51 V(TestNull) \
52 V(TestReferenceEqual) \
53 V(TestTypeOf) \
54 V(TestUndefined) \
55 V(TestUndetectable) \
56 V(ToBooleanLogicalNot) \
57 V(ToName) \
58 V(ToString) \
59 V(TypeOf)
60
61 #define UNCONDITIONAL_JUMPS_LIST(V) \
62 V(Jump) \
63 V(JumpConstant) \
64 V(JumpLoop)
65
66 #define CONDITIONAL_JUMPS_LIST(V) \
67 V(JumpIfFalse) \
68 V(JumpIfFalseConstant) \
69 V(JumpIfJSReceiver) \
70 V(JumpIfJSReceiverConstant) \
71 V(JumpIfNotNull) \
72 V(JumpIfNotNullConstant) \
73 V(JumpIfNotUndefined) \
74 V(JumpIfNotUndefinedConstant) \
75 V(JumpIfNull) \
76 V(JumpIfNullConstant) \
77 V(JumpIfToBooleanFalse) \
78 V(JumpIfToBooleanFalseConstant) \
79 V(JumpIfToBooleanTrue) \
80 V(JumpIfToBooleanTrueConstant) \
81 V(JumpIfTrue) \
82 V(JumpIfTrueConstant) \
83 V(JumpIfUndefined) \
84 V(JumpIfUndefinedConstant) \
85 V(JumpIfUndefinedOrNull) \
86 V(JumpIfUndefinedOrNullConstant)
87
88 #define IGNORED_BYTECODE_LIST(V) \
89 V(CallRuntimeForPair) \
90 V(CollectTypeProfile) \
91 V(DebugBreak0) \
92 V(DebugBreak1) \
93 V(DebugBreak2) \
94 V(DebugBreak3) \
95 V(DebugBreak4) \
96 V(DebugBreak5) \
97 V(DebugBreak6) \
98 V(DebugBreakExtraWide) \
99 V(DebugBreakWide) \
100 V(Debugger) \
101 V(IncBlockCounter) \
102 V(ResumeGenerator) \
103 V(SuspendGenerator) \
104 V(ThrowIfNotSuperConstructor) \
105 V(ThrowSuperAlreadyCalledIfNotHole) \
106 V(ThrowSuperNotCalledIfHole) \
107 V(ToObject)
108
109 #define UNREACHABLE_BYTECODE_LIST(V) \
110 V(ExtraWide) \
111 V(Illegal) \
112 V(Wide)
113
114 #define BINARY_OP_LIST(V) \
115 V(Add) \
116 V(AddSmi) \
117 V(BitwiseAnd) \
118 V(BitwiseAndSmi) \
119 V(BitwiseOr) \
120 V(BitwiseOrSmi) \
121 V(BitwiseXor) \
122 V(BitwiseXorSmi) \
123 V(Div) \
124 V(DivSmi) \
125 V(Exp) \
126 V(ExpSmi) \
127 V(Mod) \
128 V(ModSmi) \
129 V(Mul) \
130 V(MulSmi) \
131 V(ShiftLeft) \
132 V(ShiftLeftSmi) \
133 V(ShiftRight) \
134 V(ShiftRightSmi) \
135 V(ShiftRightLogical) \
136 V(ShiftRightLogicalSmi) \
137 V(Sub) \
138 V(SubSmi)
139
140 #define UNARY_OP_LIST(V) \
141 V(BitwiseNot) \
142 V(Dec) \
143 V(Inc) \
144 V(Negate)
145
146 #define COMPARE_OP_LIST(V) \
147 V(TestEqual) \
148 V(TestEqualStrict) \
149 V(TestGreaterThan) \
150 V(TestGreaterThanOrEqual) \
151 V(TestLessThan) \
152 V(TestLessThanOrEqual)
153
154 #define SUPPORTED_BYTECODE_LIST(V) \
155 V(CallAnyReceiver) \
156 V(CallJSRuntime) \
157 V(CallNoFeedback) \
158 V(CallProperty) \
159 V(CallProperty0) \
160 V(CallProperty1) \
161 V(CallProperty2) \
162 V(CallUndefinedReceiver) \
163 V(CallUndefinedReceiver0) \
164 V(CallUndefinedReceiver1) \
165 V(CallUndefinedReceiver2) \
166 V(CallWithSpread) \
167 V(Construct) \
168 V(ConstructWithSpread) \
169 V(CreateArrayLiteral) \
170 V(CreateBlockContext) \
171 V(CreateCatchContext) \
172 V(CreateClosure) \
173 V(CreateEmptyArrayLiteral) \
174 V(CreateEvalContext) \
175 V(CreateFunctionContext) \
176 V(CreateObjectLiteral) \
177 V(CreateRegExpLiteral) \
178 V(CreateWithContext) \
179 V(ForInNext) \
180 V(ForInPrepare) \
181 V(GetIterator) \
182 V(GetSuperConstructor) \
183 V(GetTemplateObject) \
184 V(InvokeIntrinsic) \
185 V(LdaConstant) \
186 V(LdaContextSlot) \
187 V(LdaCurrentContextSlot) \
188 V(LdaImmutableContextSlot) \
189 V(LdaImmutableCurrentContextSlot) \
190 V(LdaModuleVariable) \
191 V(LdaFalse) \
192 V(LdaGlobal) \
193 V(LdaGlobalInsideTypeof) \
194 V(LdaKeyedProperty) \
195 V(LdaLookupContextSlot) \
196 V(LdaLookupContextSlotInsideTypeof) \
197 V(LdaLookupGlobalSlot) \
198 V(LdaLookupGlobalSlotInsideTypeof) \
199 V(LdaLookupSlot) \
200 V(LdaLookupSlotInsideTypeof) \
201 V(LdaNamedProperty) \
202 V(LdaNamedPropertyFromSuper) \
203 V(LdaNamedPropertyNoFeedback) \
204 V(LdaNull) \
205 V(Ldar) \
206 V(LdaSmi) \
207 V(LdaTheHole) \
208 V(LdaTrue) \
209 V(LdaUndefined) \
210 V(LdaZero) \
211 V(Mov) \
212 V(PopContext) \
213 V(PushContext) \
214 V(Return) \
215 V(StaContextSlot) \
216 V(StaCurrentContextSlot) \
217 V(StaDataPropertyInLiteral) \
218 V(StaGlobal) \
219 V(StaInArrayLiteral) \
220 V(StaKeyedProperty) \
221 V(StaLookupSlot) \
222 V(StaModuleVariable) \
223 V(StaNamedOwnProperty) \
224 V(StaNamedProperty) \
225 V(StaNamedPropertyNoFeedback) \
226 V(Star) \
227 V(SwitchOnGeneratorState) \
228 V(SwitchOnSmiNoFeedback) \
229 V(TestIn) \
230 V(TestInstanceOf) \
231 V(ThrowReferenceErrorIfHole) \
232 V(ToNumber) \
233 V(ToNumeric) \
234 BINARY_OP_LIST(V) \
235 COMPARE_OP_LIST(V) \
236 CLEAR_ACCUMULATOR_LIST(V) \
237 CONDITIONAL_JUMPS_LIST(V) \
238 IGNORED_BYTECODE_LIST(V) \
239 KILL_ENVIRONMENT_LIST(V) \
240 UNARY_OP_LIST(V) \
241 UNCONDITIONAL_JUMPS_LIST(V) \
242 UNREACHABLE_BYTECODE_LIST(V)
243
244 struct HintsImpl : public ZoneObject {
HintsImplv8::internal::compiler::HintsImpl245 explicit HintsImpl(Zone* zone) : zone_(zone) {}
246
247 ConstantsSet constants_;
248 MapsSet maps_;
249 VirtualClosuresSet virtual_closures_;
250 VirtualContextsSet virtual_contexts_;
251 VirtualBoundFunctionsSet virtual_bound_functions_;
252
253 Zone* const zone_;
254 };
255
EnsureAllocated(Zone * zone,bool check_zone_equality)256 void Hints::EnsureAllocated(Zone* zone, bool check_zone_equality) {
257 if (IsAllocated()) {
258 if (check_zone_equality) CHECK_EQ(zone, impl_->zone_);
259 // ... else {zone} lives no longer than {impl_->zone_} but we have no way of
260 // checking that.
261 } else {
262 impl_ = zone->New<HintsImpl>(zone);
263 }
264 DCHECK(IsAllocated());
265 }
266
267 struct VirtualBoundFunction {
268 Hints const bound_target;
269 HintsVector const bound_arguments;
270
VirtualBoundFunctionv8::internal::compiler::VirtualBoundFunction271 VirtualBoundFunction(Hints const& target, const HintsVector& arguments)
272 : bound_target(target), bound_arguments(arguments) {}
273
operator ==v8::internal::compiler::VirtualBoundFunction274 bool operator==(const VirtualBoundFunction& other) const {
275 if (bound_arguments.size() != other.bound_arguments.size()) return false;
276 if (bound_target != other.bound_target) return false;
277
278 for (size_t i = 0; i < bound_arguments.size(); ++i) {
279 if (bound_arguments[i] != other.bound_arguments[i]) return false;
280 }
281 return true;
282 }
283 };
284
285 // A VirtualClosure is a SharedFunctionInfo and a FeedbackVector, plus
286 // Hints about the context in which a closure will be created from them.
287 class VirtualClosure {
288 public:
289 VirtualClosure(Handle<JSFunction> function, Isolate* isolate, Zone* zone);
290
291 VirtualClosure(Handle<SharedFunctionInfo> shared,
292 Handle<FeedbackVector> feedback_vector,
293 Hints const& context_hints);
294
shared() const295 Handle<SharedFunctionInfo> shared() const { return shared_; }
feedback_vector() const296 Handle<FeedbackVector> feedback_vector() const { return feedback_vector_; }
context_hints() const297 Hints const& context_hints() const { return context_hints_; }
298
operator ==(const VirtualClosure & other) const299 bool operator==(const VirtualClosure& other) const {
300 // A feedback vector is never used for more than one SFI. There might,
301 // however, be two virtual closures with the same SFI and vector, but
302 // different context hints. crbug.com/1024282 has a link to a document
303 // describing why the context_hints_ might be different in that case.
304 DCHECK_IMPLIES(feedback_vector_.equals(other.feedback_vector_),
305 shared_.equals(other.shared_));
306 return feedback_vector_.equals(other.feedback_vector_) &&
307 context_hints_ == other.context_hints_;
308 }
309
310 private:
311 Handle<SharedFunctionInfo> const shared_;
312 Handle<FeedbackVector> const feedback_vector_;
313 Hints const context_hints_;
314 };
315
316 // A CompilationSubject is a VirtualClosure, optionally with a matching
317 // concrete closure.
318 class CompilationSubject {
319 public:
CompilationSubject(VirtualClosure virtual_closure)320 explicit CompilationSubject(VirtualClosure virtual_closure)
321 : virtual_closure_(virtual_closure), closure_() {}
322
323 // The zone parameter is to correctly initialize the virtual closure,
324 // which contains zone-allocated context information.
325 CompilationSubject(Handle<JSFunction> closure, Isolate* isolate, Zone* zone);
326
virtual_closure() const327 const VirtualClosure& virtual_closure() const { return virtual_closure_; }
closure() const328 MaybeHandle<JSFunction> closure() const { return closure_; }
329
330 private:
331 VirtualClosure const virtual_closure_;
332 MaybeHandle<JSFunction> const closure_;
333 };
334
335 // A Callee is either a JSFunction (which may not have a feedback vector), or a
336 // VirtualClosure. Note that this is different from CompilationSubject, which
337 // always has a VirtualClosure.
338 class Callee {
339 public:
Callee(Handle<JSFunction> jsfunction)340 explicit Callee(Handle<JSFunction> jsfunction)
341 : jsfunction_(jsfunction), virtual_closure_() {}
Callee(VirtualClosure const & virtual_closure)342 explicit Callee(VirtualClosure const& virtual_closure)
343 : jsfunction_(), virtual_closure_(virtual_closure) {}
344
shared(Isolate * isolate) const345 Handle<SharedFunctionInfo> shared(Isolate* isolate) const {
346 return virtual_closure_.has_value()
347 ? virtual_closure_->shared()
348 : handle(jsfunction_.ToHandleChecked()->shared(), isolate);
349 }
350
HasFeedbackVector() const351 bool HasFeedbackVector() const {
352 Handle<JSFunction> function;
353 return virtual_closure_.has_value() ||
354 jsfunction_.ToHandleChecked()->has_feedback_vector();
355 }
356
ToCompilationSubject(Isolate * isolate,Zone * zone) const357 CompilationSubject ToCompilationSubject(Isolate* isolate, Zone* zone) const {
358 CHECK(HasFeedbackVector());
359 return virtual_closure_.has_value()
360 ? CompilationSubject(*virtual_closure_)
361 : CompilationSubject(jsfunction_.ToHandleChecked(), isolate,
362 zone);
363 }
364
365 private:
366 MaybeHandle<JSFunction> const jsfunction_;
367 base::Optional<VirtualClosure> const virtual_closure_;
368 };
369
370 // If a list of arguments (hints) is shorter than the function's parameter
371 // count, this enum expresses what we know about the missing arguments.
372 enum MissingArgumentsPolicy {
373 kMissingArgumentsAreUndefined, // ... as in the JS undefined value
374 kMissingArgumentsAreUnknown,
375 };
376
377 // The SerializerForBackgroundCompilation makes sure that the relevant function
378 // data such as bytecode, SharedFunctionInfo and FeedbackVector, used by later
379 // optimizations in the compiler, is copied to the heap broker.
380 class SerializerForBackgroundCompilation {
381 public:
382 SerializerForBackgroundCompilation(
383 ZoneStats* zone_stats, JSHeapBroker* broker,
384 CompilationDependencies* dependencies, Handle<JSFunction> closure,
385 SerializerForBackgroundCompilationFlags flags, BailoutId osr_offset);
386 Hints Run(); // NOTE: Returns empty for an
387 // already-serialized function.
388
389 class Environment;
390
391 private:
392 SerializerForBackgroundCompilation(
393 ZoneStats* zone_stats, JSHeapBroker* broker,
394 CompilationDependencies* dependencies, CompilationSubject function,
395 base::Optional<Hints> new_target, const HintsVector& arguments,
396 MissingArgumentsPolicy padding,
397 SerializerForBackgroundCompilationFlags flags, int nesting_level);
398
399 bool BailoutOnUninitialized(ProcessedFeedback const& feedback);
400
401 void TraverseBytecode();
402
403 #define DECLARE_VISIT_BYTECODE(name, ...) \
404 void Visit##name(interpreter::BytecodeArrayIterator* iterator);
405 SUPPORTED_BYTECODE_LIST(DECLARE_VISIT_BYTECODE)
406 #undef DECLARE_VISIT_BYTECODE
407
408 Hints& register_hints(interpreter::Register reg);
409
410 // Return a vector containing the hints for the given register range (in
411 // order). Also prepare these hints for feedback backpropagation by allocating
412 // any that aren't yet allocated.
413 HintsVector PrepareArgumentsHints(interpreter::Register first, size_t count);
414
415 // Like above except that the hints have to be given directly.
416 template <typename... MoreHints>
417 HintsVector PrepareArgumentsHints(Hints* hints, MoreHints... more);
418
419 void ProcessCalleeForCallOrConstruct(Callee const& callee,
420 base::Optional<Hints> new_target,
421 const HintsVector& arguments,
422 SpeculationMode speculation_mode,
423 MissingArgumentsPolicy padding,
424 Hints* result_hints);
425 void ProcessCalleeForCallOrConstruct(Handle<Object> callee,
426 base::Optional<Hints> new_target,
427 const HintsVector& arguments,
428 SpeculationMode speculation_mode,
429 MissingArgumentsPolicy padding,
430 Hints* result_hints);
431 void ProcessCallOrConstruct(Hints callee, base::Optional<Hints> new_target,
432 HintsVector* arguments, FeedbackSlot slot,
433 MissingArgumentsPolicy padding);
434 void ProcessCallOrConstructRecursive(Hints const& callee,
435 base::Optional<Hints> new_target,
436 const HintsVector& arguments,
437 SpeculationMode speculation_mode,
438 MissingArgumentsPolicy padding,
439 Hints* result_hints);
440 void ProcessNewTargetForConstruct(Hints const& new_target,
441 Hints* result_hints);
442 void ProcessCallVarArgs(
443 ConvertReceiverMode receiver_mode, Hints const& callee,
444 interpreter::Register first_reg, int reg_count, FeedbackSlot slot,
445 MissingArgumentsPolicy padding = kMissingArgumentsAreUndefined);
446 void ProcessApiCall(Handle<SharedFunctionInfo> target,
447 const HintsVector& arguments);
448 void ProcessReceiverMapForApiCall(FunctionTemplateInfoRef target,
449 Handle<Map> receiver);
450 void ProcessBuiltinCall(Handle<SharedFunctionInfo> target,
451 base::Optional<Hints> new_target,
452 const HintsVector& arguments,
453 SpeculationMode speculation_mode,
454 MissingArgumentsPolicy padding, Hints* result_hints);
455
456 void ProcessJump(interpreter::BytecodeArrayIterator* iterator);
457
458 void ProcessKeyedPropertyAccess(Hints* receiver, Hints const& key,
459 FeedbackSlot slot, AccessMode access_mode,
460 bool honor_bailout_on_uninitialized);
461 void ProcessNamedPropertyAccess(Hints* receiver, NameRef const& name,
462 FeedbackSlot slot, AccessMode access_mode);
463 void ProcessNamedSuperPropertyAccess(Hints* receiver, NameRef const& name,
464 FeedbackSlot slot,
465 AccessMode access_mode);
466 void ProcessNamedAccess(Hints* receiver, NamedAccessFeedback const& feedback,
467 AccessMode access_mode, Hints* result_hints);
468 void ProcessNamedSuperAccess(Hints* receiver,
469 NamedAccessFeedback const& feedback,
470 AccessMode access_mode, Hints* result_hints);
471 void ProcessElementAccess(Hints const& receiver, Hints const& key,
472 ElementAccessFeedback const& feedback,
473 AccessMode access_mode);
474 void ProcessMinimorphicPropertyAccess(
475 MinimorphicLoadPropertyAccessFeedback const& feedback,
476 FeedbackSource const& source);
477
478 void ProcessModuleVariableAccess(
479 interpreter::BytecodeArrayIterator* iterator);
480
481 void ProcessHintsForObjectCreate(Hints const& prototype);
482 void ProcessMapHintsForPromises(Hints const& receiver_hints);
483 void ProcessHintsForPromiseResolve(Hints const& resolution_hints);
484 void ProcessHintsForHasInPrototypeChain(Hints const& instance_hints);
485 void ProcessHintsForRegExpTest(Hints const& regexp_hints);
486 PropertyAccessInfo ProcessMapForRegExpTest(MapRef map);
487 void ProcessHintsForFunctionBind(Hints const& receiver_hints);
488 void ProcessHintsForObjectGetPrototype(Hints const& object_hints);
489 void ProcessConstantForOrdinaryHasInstance(HeapObjectRef const& constructor,
490 bool* walk_prototypes);
491 void ProcessConstantForInstanceOf(ObjectRef const& constant,
492 bool* walk_prototypes);
493 void ProcessHintsForOrdinaryHasInstance(Hints const& constructor_hints,
494 Hints const& instance_hints);
495
496 void ProcessGlobalAccess(FeedbackSlot slot, bool is_load);
497
498 void ProcessCompareOperation(FeedbackSlot slot);
499 void ProcessForIn(FeedbackSlot slot);
500 void ProcessUnaryOrBinaryOperation(FeedbackSlot slot,
501 bool honor_bailout_on_uninitialized);
502
503 PropertyAccessInfo ProcessMapForNamedPropertyAccess(
504 Hints* receiver, base::Optional<MapRef> receiver_map,
505 MapRef lookup_start_object_map, NameRef const& name,
506 AccessMode access_mode, base::Optional<JSObjectRef> concrete_receiver,
507 Hints* result_hints);
508
509 void ProcessCreateContext(interpreter::BytecodeArrayIterator* iterator,
510 int scopeinfo_operand_index);
511
512 enum ContextProcessingMode {
513 kIgnoreSlot,
514 kSerializeSlot,
515 };
516
517 void ProcessContextAccess(Hints const& context_hints, int slot, int depth,
518 ContextProcessingMode mode,
519 Hints* result_hints = nullptr);
520 void ProcessImmutableLoad(ContextRef const& context, int slot,
521 ContextProcessingMode mode,
522 Hints* new_accumulator_hints);
523 void ProcessLdaLookupGlobalSlot(interpreter::BytecodeArrayIterator* iterator);
524 void ProcessLdaLookupContextSlot(
525 interpreter::BytecodeArrayIterator* iterator);
526
527 // Performs extension lookups for [0, depth) like
528 // BytecodeGraphBuilder::CheckContextExtensions().
529 void ProcessCheckContextExtensions(int depth);
530
531 Hints RunChildSerializer(CompilationSubject function,
532 base::Optional<Hints> new_target,
533 const HintsVector& arguments,
534 MissingArgumentsPolicy padding);
535
536 // When (forward-)branching bytecodes are encountered, e.g. a conditional
537 // jump, we call ContributeToJumpTargetEnvironment to "remember" the current
538 // environment, associated with the jump target offset. When serialization
539 // eventually reaches that offset, we call IncorporateJumpTargetEnvironment to
540 // merge that environment back into whatever is the current environment then.
541 // Note: Since there may be multiple jumps to the same target,
542 // ContributeToJumpTargetEnvironment may actually do a merge as well.
543 void ContributeToJumpTargetEnvironment(int target_offset);
544 void IncorporateJumpTargetEnvironment(int target_offset);
545
function() const546 VirtualClosure function() const { return function_; }
547
return_value_hints()548 Hints& return_value_hints() { return return_value_hints_; }
549
550 Handle<FeedbackVector> feedback_vector() const;
551 Handle<BytecodeArray> bytecode_array() const;
552 BytecodeAnalysis const& GetBytecodeAnalysis(
553 SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
554
broker() const555 JSHeapBroker* broker() const { return broker_; }
dependencies() const556 CompilationDependencies* dependencies() const { return dependencies_; }
zone()557 Zone* zone() { return zone_scope_.zone(); }
environment() const558 Environment* environment() const { return environment_; }
flags() const559 SerializerForBackgroundCompilationFlags flags() const { return flags_; }
osr_offset() const560 BailoutId osr_offset() const { return osr_offset_; }
561
562 JSHeapBroker* const broker_;
563 CompilationDependencies* const dependencies_;
564 ZoneStats::Scope zone_scope_;
565 SerializerForBackgroundCompilationFlags const flags_;
566 // Instead of storing the virtual_closure here, we could extract it from the
567 // {closure_hints_} but that would be cumbersome.
568 VirtualClosure const function_;
569 BailoutId const osr_offset_;
570 ZoneUnorderedMap<int, Environment*> jump_target_environments_;
571 Environment* const environment_;
572 HintsVector const arguments_;
573 Hints return_value_hints_;
574 Hints closure_hints_;
575
576 int nesting_level_ = 0;
577 };
578
RunSerializerForBackgroundCompilation(ZoneStats * zone_stats,JSHeapBroker * broker,CompilationDependencies * dependencies,Handle<JSFunction> closure,SerializerForBackgroundCompilationFlags flags,BailoutId osr_offset)579 void RunSerializerForBackgroundCompilation(
580 ZoneStats* zone_stats, JSHeapBroker* broker,
581 CompilationDependencies* dependencies, Handle<JSFunction> closure,
582 SerializerForBackgroundCompilationFlags flags, BailoutId osr_offset) {
583 SerializerForBackgroundCompilation serializer(
584 zone_stats, broker, dependencies, closure, flags, osr_offset);
585 serializer.Run();
586 }
587
588 using BytecodeArrayIterator = interpreter::BytecodeArrayIterator;
589
VirtualClosure(Handle<SharedFunctionInfo> shared,Handle<FeedbackVector> feedback_vector,Hints const & context_hints)590 VirtualClosure::VirtualClosure(Handle<SharedFunctionInfo> shared,
591 Handle<FeedbackVector> feedback_vector,
592 Hints const& context_hints)
593 : shared_(shared),
594 feedback_vector_(feedback_vector),
595 context_hints_(context_hints) {
596 // The checked invariant rules out recursion and thus avoids complexity.
597 CHECK(context_hints_.virtual_closures().IsEmpty());
598 }
599
VirtualClosure(Handle<JSFunction> function,Isolate * isolate,Zone * zone)600 VirtualClosure::VirtualClosure(Handle<JSFunction> function, Isolate* isolate,
601 Zone* zone)
602 : shared_(handle(function->shared(), isolate)),
603 feedback_vector_(function->feedback_vector(), isolate),
604 context_hints_(
605 Hints::SingleConstant(handle(function->context(), isolate), zone)) {
606 // The checked invariant rules out recursion and thus avoids complexity.
607 CHECK(context_hints_.virtual_closures().IsEmpty());
608 }
609
CompilationSubject(Handle<JSFunction> closure,Isolate * isolate,Zone * zone)610 CompilationSubject::CompilationSubject(Handle<JSFunction> closure,
611 Isolate* isolate, Zone* zone)
612 : virtual_closure_(closure, isolate, zone), closure_(closure) {
613 CHECK(closure->has_feedback_vector());
614 }
615
Copy(Zone * zone) const616 Hints Hints::Copy(Zone* zone) const {
617 if (!IsAllocated()) return *this;
618 Hints result;
619 result.EnsureAllocated(zone);
620 result.impl_->constants_ = impl_->constants_;
621 result.impl_->maps_ = impl_->maps_;
622 result.impl_->virtual_contexts_ = impl_->virtual_contexts_;
623 result.impl_->virtual_closures_ = impl_->virtual_closures_;
624 result.impl_->virtual_bound_functions_ = impl_->virtual_bound_functions_;
625 return result;
626 }
627
operator ==(Hints const & other) const628 bool Hints::operator==(Hints const& other) const {
629 if (impl_ == other.impl_) return true;
630 if (IsEmpty() && other.IsEmpty()) return true;
631 return IsAllocated() && other.IsAllocated() &&
632 constants() == other.constants() &&
633 virtual_closures() == other.virtual_closures() &&
634 maps() == other.maps() &&
635 virtual_contexts() == other.virtual_contexts() &&
636 virtual_bound_functions() == other.virtual_bound_functions();
637 }
638
operator !=(Hints const & other) const639 bool Hints::operator!=(Hints const& other) const { return !(*this == other); }
640
641 #ifdef ENABLE_SLOW_DCHECKS
Includes(Hints const & other) const642 bool Hints::Includes(Hints const& other) const {
643 if (impl_ == other.impl_ || other.IsEmpty()) return true;
644 return IsAllocated() && constants().Includes(other.constants()) &&
645 virtual_closures().Includes(other.virtual_closures()) &&
646 maps().Includes(other.maps());
647 }
648 #endif
649
SingleConstant(Handle<Object> constant,Zone * zone)650 Hints Hints::SingleConstant(Handle<Object> constant, Zone* zone) {
651 Hints result;
652 result.AddConstant(constant, zone, nullptr);
653 return result;
654 }
655
SingleMap(Handle<Map> map,Zone * zone)656 Hints Hints::SingleMap(Handle<Map> map, Zone* zone) {
657 Hints result;
658 result.AddMap(map, zone, nullptr);
659 return result;
660 }
661
constants() const662 ConstantsSet Hints::constants() const {
663 return IsAllocated() ? impl_->constants_ : ConstantsSet();
664 }
665
maps() const666 MapsSet Hints::maps() const { return IsAllocated() ? impl_->maps_ : MapsSet(); }
667
virtual_closures() const668 VirtualClosuresSet Hints::virtual_closures() const {
669 return IsAllocated() ? impl_->virtual_closures_ : VirtualClosuresSet();
670 }
671
virtual_contexts() const672 VirtualContextsSet Hints::virtual_contexts() const {
673 return IsAllocated() ? impl_->virtual_contexts_ : VirtualContextsSet();
674 }
675
virtual_bound_functions() const676 VirtualBoundFunctionsSet Hints::virtual_bound_functions() const {
677 return IsAllocated() ? impl_->virtual_bound_functions_
678 : VirtualBoundFunctionsSet();
679 }
680
AddVirtualContext(VirtualContext const & virtual_context,Zone * zone,JSHeapBroker * broker)681 void Hints::AddVirtualContext(VirtualContext const& virtual_context, Zone* zone,
682 JSHeapBroker* broker) {
683 EnsureAllocated(zone);
684 if (impl_->virtual_contexts_.Size() >= kMaxHintsSize) {
685 TRACE_BROKER_MISSING(broker,
686 "opportunity - limit for virtual contexts reached.");
687 return;
688 }
689 impl_->virtual_contexts_.Add(virtual_context, impl_->zone_);
690 }
691
AddConstant(Handle<Object> constant,Zone * zone,JSHeapBroker * broker)692 void Hints::AddConstant(Handle<Object> constant, Zone* zone,
693 JSHeapBroker* broker) {
694 EnsureAllocated(zone);
695 if (impl_->constants_.Size() >= kMaxHintsSize) {
696 TRACE_BROKER_MISSING(broker, "opportunity - limit for constants reached.");
697 return;
698 }
699 impl_->constants_.Add(constant, impl_->zone_);
700 }
701
AddMap(Handle<Map> map,Zone * zone,JSHeapBroker * broker,bool check_zone_equality)702 void Hints::AddMap(Handle<Map> map, Zone* zone, JSHeapBroker* broker,
703 bool check_zone_equality) {
704 EnsureAllocated(zone, check_zone_equality);
705 if (impl_->maps_.Size() >= kMaxHintsSize) {
706 TRACE_BROKER_MISSING(broker, "opportunity - limit for maps reached.");
707 return;
708 }
709 impl_->maps_.Add(map, impl_->zone_);
710 }
711
AddVirtualClosure(VirtualClosure const & virtual_closure,Zone * zone,JSHeapBroker * broker)712 void Hints::AddVirtualClosure(VirtualClosure const& virtual_closure, Zone* zone,
713 JSHeapBroker* broker) {
714 EnsureAllocated(zone);
715 if (impl_->virtual_closures_.Size() >= kMaxHintsSize) {
716 TRACE_BROKER_MISSING(broker,
717 "opportunity - limit for virtual closures reached.");
718 return;
719 }
720 impl_->virtual_closures_.Add(virtual_closure, impl_->zone_);
721 }
722
AddVirtualBoundFunction(VirtualBoundFunction const & bound_function,Zone * zone,JSHeapBroker * broker)723 void Hints::AddVirtualBoundFunction(VirtualBoundFunction const& bound_function,
724 Zone* zone, JSHeapBroker* broker) {
725 EnsureAllocated(zone);
726 if (impl_->virtual_bound_functions_.Size() >= kMaxHintsSize) {
727 TRACE_BROKER_MISSING(
728 broker, "opportunity - limit for virtual bound functions reached.");
729 return;
730 }
731 // TODO(mslekova): Consider filtering the hints in the added bound function,
732 // for example: a) Remove any non-JS(Bound)Function constants, b) Truncate the
733 // argument vector the formal parameter count.
734 impl_->virtual_bound_functions_.Add(bound_function, impl_->zone_);
735 }
736
Add(Hints const & other,Zone * zone,JSHeapBroker * broker)737 void Hints::Add(Hints const& other, Zone* zone, JSHeapBroker* broker) {
738 if (impl_ == other.impl_ || other.IsEmpty()) return;
739 EnsureAllocated(zone);
740 if (!Union(other)) {
741 TRACE_BROKER_MISSING(broker, "opportunity - hints limit reached.");
742 }
743 }
744
CopyToParentZone(Zone * zone,JSHeapBroker * broker) const745 Hints Hints::CopyToParentZone(Zone* zone, JSHeapBroker* broker) const {
746 if (!IsAllocated()) return *this;
747
748 Hints result;
749
750 for (auto const& x : constants()) result.AddConstant(x, zone, broker);
751 for (auto const& x : maps()) result.AddMap(x, zone, broker);
752 for (auto const& x : virtual_contexts())
753 result.AddVirtualContext(x, zone, broker);
754
755 // Adding hints from a child serializer run means copying data out from
756 // a zone that's being destroyed. VirtualClosures and VirtualBoundFunction
757 // have zone allocated data, so we've got to make a deep copy to eliminate
758 // traces of the dying zone.
759 for (auto const& x : virtual_closures()) {
760 VirtualClosure new_virtual_closure(
761 x.shared(), x.feedback_vector(),
762 x.context_hints().CopyToParentZone(zone, broker));
763 result.AddVirtualClosure(new_virtual_closure, zone, broker);
764 }
765 for (auto const& x : virtual_bound_functions()) {
766 HintsVector new_arguments_hints(zone);
767 for (auto hint : x.bound_arguments) {
768 new_arguments_hints.push_back(hint.CopyToParentZone(zone, broker));
769 }
770 VirtualBoundFunction new_bound_function(
771 x.bound_target.CopyToParentZone(zone, broker), new_arguments_hints);
772 result.AddVirtualBoundFunction(new_bound_function, zone, broker);
773 }
774
775 return result;
776 }
777
IsEmpty() const778 bool Hints::IsEmpty() const {
779 if (!IsAllocated()) return true;
780 return constants().IsEmpty() && maps().IsEmpty() &&
781 virtual_closures().IsEmpty() && virtual_contexts().IsEmpty() &&
782 virtual_bound_functions().IsEmpty();
783 }
784
operator <<(std::ostream & out,const VirtualContext & virtual_context)785 std::ostream& operator<<(std::ostream& out,
786 const VirtualContext& virtual_context) {
787 out << "Distance " << virtual_context.distance << " from "
788 << Brief(*virtual_context.context) << std::endl;
789 return out;
790 }
791
792 std::ostream& operator<<(std::ostream& out, const Hints& hints);
793
operator <<(std::ostream & out,const VirtualClosure & virtual_closure)794 std::ostream& operator<<(std::ostream& out,
795 const VirtualClosure& virtual_closure) {
796 out << Brief(*virtual_closure.shared()) << std::endl;
797 out << Brief(*virtual_closure.feedback_vector()) << std::endl;
798 !virtual_closure.context_hints().IsEmpty() &&
799 out << virtual_closure.context_hints() << "):" << std::endl;
800 return out;
801 }
802
operator <<(std::ostream & out,const VirtualBoundFunction & virtual_bound_function)803 std::ostream& operator<<(std::ostream& out,
804 const VirtualBoundFunction& virtual_bound_function) {
805 out << std::endl << " Target: " << virtual_bound_function.bound_target;
806 out << " Arguments:" << std::endl;
807 for (auto hint : virtual_bound_function.bound_arguments) {
808 out << " " << hint;
809 }
810 return out;
811 }
812
operator <<(std::ostream & out,const Hints & hints)813 std::ostream& operator<<(std::ostream& out, const Hints& hints) {
814 out << "(impl_ = " << hints.impl_ << ")\n";
815 for (Handle<Object> constant : hints.constants()) {
816 out << " constant " << Brief(*constant) << std::endl;
817 }
818 for (Handle<Map> map : hints.maps()) {
819 out << " map " << Brief(*map) << std::endl;
820 }
821 for (VirtualClosure const& virtual_closure : hints.virtual_closures()) {
822 out << " virtual closure " << virtual_closure << std::endl;
823 }
824 for (VirtualContext const& virtual_context : hints.virtual_contexts()) {
825 out << " virtual context " << virtual_context << std::endl;
826 }
827 for (VirtualBoundFunction const& virtual_bound_function :
828 hints.virtual_bound_functions()) {
829 out << " virtual bound function " << virtual_bound_function << std::endl;
830 }
831 return out;
832 }
833
Reset(Hints * other,Zone * zone)834 void Hints::Reset(Hints* other, Zone* zone) {
835 other->EnsureShareable(zone);
836 *this = *other;
837 DCHECK(IsAllocated());
838 }
839
840 class SerializerForBackgroundCompilation::Environment : public ZoneObject {
841 public:
842 Environment(Zone* zone, CompilationSubject function);
843 Environment(Zone* zone, Isolate* isolate, CompilationSubject function,
844 base::Optional<Hints> new_target, const HintsVector& arguments,
845 MissingArgumentsPolicy padding);
846
IsDead() const847 bool IsDead() const { return !alive_; }
848
Kill()849 void Kill() {
850 DCHECK(!IsDead());
851 alive_ = false;
852 DCHECK(IsDead());
853 }
854
Resurrect()855 void Resurrect() {
856 DCHECK(IsDead());
857 alive_ = true;
858 DCHECK(!IsDead());
859 }
860
861 // Merge {other} into {this} environment (leaving {other} unmodified).
862 void Merge(Environment* other, Zone* zone, JSHeapBroker* broker);
863
current_context_hints() const864 Hints const& current_context_hints() const { return current_context_hints_; }
accumulator_hints() const865 Hints const& accumulator_hints() const { return accumulator_hints_; }
866
current_context_hints()867 Hints& current_context_hints() { return current_context_hints_; }
accumulator_hints()868 Hints& accumulator_hints() { return accumulator_hints_; }
869 Hints& register_hints(interpreter::Register reg);
870
871 private:
872 friend std::ostream& operator<<(std::ostream& out, const Environment& env);
873
874 Hints current_context_hints_;
875 Hints accumulator_hints_;
876
877 HintsVector parameters_hints_; // First parameter is the receiver.
878 HintsVector locals_hints_;
879
880 bool alive_ = true;
881 };
882
Environment(Zone * zone,CompilationSubject function)883 SerializerForBackgroundCompilation::Environment::Environment(
884 Zone* zone, CompilationSubject function)
885 : parameters_hints_(function.virtual_closure()
886 .shared()
887 ->GetBytecodeArray()
888 .parameter_count(),
889 Hints(), zone),
890 locals_hints_(function.virtual_closure()
891 .shared()
892 ->GetBytecodeArray()
893 .register_count(),
894 Hints(), zone) {
895 // Consume the virtual_closure's context hint information.
896 current_context_hints_ = function.virtual_closure().context_hints();
897 }
898
Environment(Zone * zone,Isolate * isolate,CompilationSubject function,base::Optional<Hints> new_target,const HintsVector & arguments,MissingArgumentsPolicy padding)899 SerializerForBackgroundCompilation::Environment::Environment(
900 Zone* zone, Isolate* isolate, CompilationSubject function,
901 base::Optional<Hints> new_target, const HintsVector& arguments,
902 MissingArgumentsPolicy padding)
903 : Environment(zone, function) {
904 // Set the hints for the actually passed arguments, at most up to
905 // the parameter_count.
906 for (size_t i = 0; i < std::min(arguments.size(), parameters_hints_.size());
907 ++i) {
908 parameters_hints_[i] = arguments[i];
909 }
910
911 if (padding == kMissingArgumentsAreUndefined) {
912 Hints const undefined_hint =
913 Hints::SingleConstant(isolate->factory()->undefined_value(), zone);
914 for (size_t i = arguments.size(); i < parameters_hints_.size(); ++i) {
915 parameters_hints_[i] = undefined_hint;
916 }
917 } else {
918 DCHECK_EQ(padding, kMissingArgumentsAreUnknown);
919 }
920
921 // Set hints for new_target.
922 interpreter::Register new_target_reg =
923 function.virtual_closure()
924 .shared()
925 ->GetBytecodeArray()
926 .incoming_new_target_or_generator_register();
927 if (new_target_reg.is_valid()) {
928 Hints& hints = register_hints(new_target_reg);
929 CHECK(hints.IsEmpty());
930 if (new_target.has_value()) hints = *new_target;
931 }
932 }
933
register_hints(interpreter::Register reg)934 Hints& SerializerForBackgroundCompilation::register_hints(
935 interpreter::Register reg) {
936 if (reg.is_function_closure()) return closure_hints_;
937 return environment()->register_hints(reg);
938 }
939
register_hints(interpreter::Register reg)940 Hints& SerializerForBackgroundCompilation::Environment::register_hints(
941 interpreter::Register reg) {
942 if (reg.is_current_context()) return current_context_hints_;
943 if (reg.is_parameter()) {
944 return parameters_hints_[reg.ToParameterIndex(
945 static_cast<int>(parameters_hints_.size()))];
946 }
947 DCHECK(!reg.is_function_closure());
948 CHECK_LT(reg.index(), locals_hints_.size());
949 return locals_hints_[reg.index()];
950 }
951
Merge(Environment * other,Zone * zone,JSHeapBroker * broker)952 void SerializerForBackgroundCompilation::Environment::Merge(
953 Environment* other, Zone* zone, JSHeapBroker* broker) {
954 // {other} is guaranteed to have the same layout because it comes from an
955 // earlier bytecode in the same function.
956 DCHECK_EQ(parameters_hints_.size(), other->parameters_hints_.size());
957 DCHECK_EQ(locals_hints_.size(), other->locals_hints_.size());
958
959 if (IsDead()) {
960 parameters_hints_ = other->parameters_hints_;
961 locals_hints_ = other->locals_hints_;
962 current_context_hints_ = other->current_context_hints_;
963 accumulator_hints_ = other->accumulator_hints_;
964 Resurrect();
965 } else {
966 for (size_t i = 0; i < parameters_hints_.size(); ++i) {
967 parameters_hints_[i].Merge(other->parameters_hints_[i], zone, broker);
968 }
969 for (size_t i = 0; i < locals_hints_.size(); ++i) {
970 locals_hints_[i].Merge(other->locals_hints_[i], zone, broker);
971 }
972 current_context_hints_.Merge(other->current_context_hints_, zone, broker);
973 accumulator_hints_.Merge(other->accumulator_hints_, zone, broker);
974 }
975
976 CHECK(!IsDead());
977 }
978
Union(Hints const & other)979 bool Hints::Union(Hints const& other) {
980 CHECK(IsAllocated());
981 if (impl_->constants_.Size() + other.constants().Size() > kMaxHintsSize ||
982 impl_->maps_.Size() + other.maps().Size() > kMaxHintsSize ||
983 impl_->virtual_closures_.Size() + other.virtual_closures().Size() >
984 kMaxHintsSize ||
985 impl_->virtual_contexts_.Size() + other.virtual_contexts().Size() >
986 kMaxHintsSize ||
987 impl_->virtual_bound_functions_.Size() +
988 other.virtual_bound_functions().Size() >
989 kMaxHintsSize) {
990 return false;
991 }
992 Zone* zone = impl_->zone_;
993 impl_->constants_.Union(other.constants(), zone);
994 impl_->maps_.Union(other.maps(), zone);
995 impl_->virtual_closures_.Union(other.virtual_closures(), zone);
996 impl_->virtual_contexts_.Union(other.virtual_contexts(), zone);
997 impl_->virtual_bound_functions_.Union(other.virtual_bound_functions(), zone);
998 return true;
999 }
1000
Merge(Hints const & other,Zone * zone,JSHeapBroker * broker)1001 void Hints::Merge(Hints const& other, Zone* zone, JSHeapBroker* broker) {
1002 if (impl_ == other.impl_) {
1003 return;
1004 }
1005 if (!IsAllocated()) {
1006 *this = other.Copy(zone);
1007 DCHECK(IsAllocated());
1008 return;
1009 }
1010 *this = this->Copy(zone);
1011 if (!Union(other)) {
1012 TRACE_BROKER_MISSING(broker, "opportunity - hints limit reached.");
1013 }
1014 DCHECK(IsAllocated());
1015 }
1016
operator <<(std::ostream & out,const SerializerForBackgroundCompilation::Environment & env)1017 std::ostream& operator<<(
1018 std::ostream& out,
1019 const SerializerForBackgroundCompilation::Environment& env) {
1020 std::ostringstream output_stream;
1021
1022 if (env.IsDead()) {
1023 output_stream << "dead\n";
1024 } else {
1025 output_stream << "alive\n";
1026 for (size_t i = 0; i < env.parameters_hints_.size(); ++i) {
1027 Hints const& hints = env.parameters_hints_[i];
1028 if (!hints.IsEmpty()) {
1029 if (i == 0) {
1030 output_stream << "Hints for <this>: ";
1031 } else {
1032 output_stream << "Hints for a" << i - 1 << ": ";
1033 }
1034 output_stream << hints;
1035 }
1036 }
1037 for (size_t i = 0; i < env.locals_hints_.size(); ++i) {
1038 Hints const& hints = env.locals_hints_[i];
1039 if (!hints.IsEmpty()) {
1040 output_stream << "Hints for r" << i << ": " << hints;
1041 }
1042 }
1043 }
1044
1045 if (!env.current_context_hints().IsEmpty()) {
1046 output_stream << "Hints for <context>: " << env.current_context_hints();
1047 }
1048 if (!env.accumulator_hints().IsEmpty()) {
1049 output_stream << "Hints for <accumulator>: " << env.accumulator_hints();
1050 }
1051
1052 out << output_stream.str();
1053 return out;
1054 }
1055
SerializerForBackgroundCompilation(ZoneStats * zone_stats,JSHeapBroker * broker,CompilationDependencies * dependencies,Handle<JSFunction> closure,SerializerForBackgroundCompilationFlags flags,BailoutId osr_offset)1056 SerializerForBackgroundCompilation::SerializerForBackgroundCompilation(
1057 ZoneStats* zone_stats, JSHeapBroker* broker,
1058 CompilationDependencies* dependencies, Handle<JSFunction> closure,
1059 SerializerForBackgroundCompilationFlags flags, BailoutId osr_offset)
1060 : broker_(broker),
1061 dependencies_(dependencies),
1062 zone_scope_(zone_stats, ZONE_NAME),
1063 flags_(flags),
1064 function_(closure, broker->isolate(), zone()),
1065 osr_offset_(osr_offset),
1066 jump_target_environments_(zone()),
1067 environment_(zone()->New<Environment>(
1068 zone(), CompilationSubject(closure, broker_->isolate(), zone()))),
1069 arguments_(zone()) {
1070 closure_hints_.AddConstant(closure, zone(), broker_);
1071 JSFunctionRef(broker, closure).Serialize();
1072
1073 TRACE_BROKER(broker_, "Hints for <closure>: " << closure_hints_);
1074 TRACE_BROKER(broker_, "Initial environment:\n" << *environment_);
1075 }
1076
SerializerForBackgroundCompilation(ZoneStats * zone_stats,JSHeapBroker * broker,CompilationDependencies * dependencies,CompilationSubject function,base::Optional<Hints> new_target,const HintsVector & arguments,MissingArgumentsPolicy padding,SerializerForBackgroundCompilationFlags flags,int nesting_level)1077 SerializerForBackgroundCompilation::SerializerForBackgroundCompilation(
1078 ZoneStats* zone_stats, JSHeapBroker* broker,
1079 CompilationDependencies* dependencies, CompilationSubject function,
1080 base::Optional<Hints> new_target, const HintsVector& arguments,
1081 MissingArgumentsPolicy padding,
1082 SerializerForBackgroundCompilationFlags flags, int nesting_level)
1083 : broker_(broker),
1084 dependencies_(dependencies),
1085 zone_scope_(zone_stats, ZONE_NAME),
1086 flags_(flags),
1087 function_(function.virtual_closure()),
1088 osr_offset_(BailoutId::None()),
1089 jump_target_environments_(zone()),
1090 environment_(zone()->New<Environment>(zone(), broker_->isolate(),
1091 function, new_target, arguments,
1092 padding)),
1093 arguments_(arguments),
1094 nesting_level_(nesting_level) {
1095 Handle<JSFunction> closure;
1096 if (function.closure().ToHandle(&closure)) {
1097 closure_hints_.AddConstant(closure, zone(), broker);
1098 JSFunctionRef(broker, closure).Serialize();
1099 } else {
1100 closure_hints_.AddVirtualClosure(function.virtual_closure(), zone(),
1101 broker);
1102 }
1103
1104 TRACE_BROKER(broker_, "Hints for <closure>: " << closure_hints_);
1105 TRACE_BROKER(broker_, "Initial environment:\n" << *environment_);
1106 }
1107
BailoutOnUninitialized(ProcessedFeedback const & feedback)1108 bool SerializerForBackgroundCompilation::BailoutOnUninitialized(
1109 ProcessedFeedback const& feedback) {
1110 DCHECK(!environment()->IsDead());
1111 if (!(flags() &
1112 SerializerForBackgroundCompilationFlag::kBailoutOnUninitialized)) {
1113 return false;
1114 }
1115 if (!osr_offset().IsNone()) {
1116 // Exclude OSR from this optimization because we might end up skipping the
1117 // OSR entry point. TODO(neis): Support OSR?
1118 return false;
1119 }
1120 if (broker()->is_turboprop() &&
1121 feedback.slot_kind() == FeedbackSlotKind::kCall) {
1122 return false;
1123 }
1124 if (feedback.IsInsufficient()) {
1125 environment()->Kill();
1126 return true;
1127 }
1128 return false;
1129 }
1130
Run()1131 Hints SerializerForBackgroundCompilation::Run() {
1132 TraceScope tracer(broker(), this, "SerializerForBackgroundCompilation::Run");
1133 if (nesting_level_ >= FLAG_max_serializer_nesting) {
1134 TRACE_BROKER_MISSING(
1135 broker(),
1136 "opportunity - Reached max nesting level for "
1137 "SerializerForBackgroundCompilation::Run, bailing out.\n");
1138 return Hints();
1139 }
1140
1141 TRACE_BROKER_MEMORY(broker(), "[serializer start] Broker zone usage: "
1142 << broker()->zone()->allocation_size());
1143 SharedFunctionInfoRef shared(broker(), function().shared());
1144 FeedbackVectorRef feedback_vector_ref(broker(), feedback_vector());
1145 if (!broker()->ShouldBeSerializedForCompilation(shared, feedback_vector_ref,
1146 arguments_)) {
1147 TRACE_BROKER(broker(),
1148 "opportunity - Already ran serializer for SharedFunctionInfo "
1149 << Brief(*shared.object()) << ", bailing out.\n");
1150 return Hints();
1151 }
1152
1153 {
1154 HintsVector arguments_copy_in_broker_zone(broker()->zone());
1155 for (auto const& hints : arguments_) {
1156 arguments_copy_in_broker_zone.push_back(
1157 hints.CopyToParentZone(broker()->zone(), broker()));
1158 }
1159 broker()->SetSerializedForCompilation(shared, feedback_vector_ref,
1160 arguments_copy_in_broker_zone);
1161 }
1162
1163 // We eagerly call the {EnsureSourcePositionsAvailable} for all serialized
1164 // SFIs while still on the main thread. Source positions will later be used
1165 // by JSInliner::ReduceJSCall.
1166 if (flags() &
1167 SerializerForBackgroundCompilationFlag::kCollectSourcePositions) {
1168 SharedFunctionInfo::EnsureSourcePositionsAvailable(broker()->isolate(),
1169 shared.object());
1170 }
1171
1172 feedback_vector_ref.Serialize();
1173 TraverseBytecode();
1174
1175 if (return_value_hints().IsEmpty()) {
1176 TRACE_BROKER(broker(), "Return value hints: none");
1177 } else {
1178 TRACE_BROKER(broker(), "Return value hints: " << return_value_hints());
1179 }
1180 TRACE_BROKER_MEMORY(broker(), "[serializer end] Broker zone usage: "
1181 << broker()->zone()->allocation_size());
1182 return return_value_hints();
1183 }
1184
1185 class HandlerRangeMatcher {
1186 public:
HandlerRangeMatcher(BytecodeArrayIterator const & bytecode_iterator,Handle<BytecodeArray> bytecode_array)1187 HandlerRangeMatcher(BytecodeArrayIterator const& bytecode_iterator,
1188 Handle<BytecodeArray> bytecode_array)
1189 : bytecode_iterator_(bytecode_iterator) {
1190 HandlerTable table(*bytecode_array);
1191 for (int i = 0, n = table.NumberOfRangeEntries(); i < n; ++i) {
1192 ranges_.insert({table.GetRangeStart(i), table.GetRangeEnd(i),
1193 table.GetRangeHandler(i)});
1194 }
1195 ranges_iterator_ = ranges_.cbegin();
1196 }
1197
1198 using OffsetReporter = std::function<void(int handler_offset)>;
1199
HandlerOffsetForCurrentPosition(const OffsetReporter & offset_reporter)1200 void HandlerOffsetForCurrentPosition(const OffsetReporter& offset_reporter) {
1201 CHECK(!bytecode_iterator_.done());
1202 const int current_offset = bytecode_iterator_.current_offset();
1203
1204 // Remove outdated try ranges from the stack.
1205 while (!stack_.empty()) {
1206 const int end = stack_.top().end;
1207 if (end < current_offset) {
1208 stack_.pop();
1209 } else {
1210 break;
1211 }
1212 }
1213
1214 // Advance the iterator and maintain the stack.
1215 while (ranges_iterator_ != ranges_.cend() &&
1216 ranges_iterator_->start <= current_offset) {
1217 if (ranges_iterator_->end >= current_offset) {
1218 stack_.push(*ranges_iterator_);
1219 if (ranges_iterator_->start == current_offset) {
1220 offset_reporter(ranges_iterator_->handler);
1221 }
1222 }
1223 ranges_iterator_++;
1224 }
1225
1226 if (!stack_.empty() && stack_.top().start < current_offset) {
1227 offset_reporter(stack_.top().handler);
1228 }
1229 }
1230
1231 private:
1232 BytecodeArrayIterator const& bytecode_iterator_;
1233
1234 struct Range {
1235 int start;
1236 int end;
1237 int handler;
operator <(const Range & a,const Range & b)1238 friend bool operator<(const Range& a, const Range& b) {
1239 if (a.start < b.start) return true;
1240 if (a.start == b.start) {
1241 if (a.end < b.end) return true;
1242 CHECK_GT(a.end, b.end);
1243 }
1244 return false;
1245 }
1246 };
1247 std::set<Range> ranges_;
1248 std::set<Range>::const_iterator ranges_iterator_;
1249 std::stack<Range> stack_;
1250 };
1251
feedback_vector() const1252 Handle<FeedbackVector> SerializerForBackgroundCompilation::feedback_vector()
1253 const {
1254 return function().feedback_vector();
1255 }
1256
bytecode_array() const1257 Handle<BytecodeArray> SerializerForBackgroundCompilation::bytecode_array()
1258 const {
1259 return handle(function().shared()->GetBytecodeArray(), broker()->isolate());
1260 }
1261
GetBytecodeAnalysis(SerializationPolicy policy)1262 BytecodeAnalysis const& SerializerForBackgroundCompilation::GetBytecodeAnalysis(
1263 SerializationPolicy policy) {
1264 return broker()->GetBytecodeAnalysis(
1265 bytecode_array(), osr_offset(),
1266 flags() &
1267 SerializerForBackgroundCompilationFlag::kAnalyzeEnvironmentLiveness,
1268 policy);
1269 }
1270
TraverseBytecode()1271 void SerializerForBackgroundCompilation::TraverseBytecode() {
1272 BytecodeAnalysis const& bytecode_analysis =
1273 GetBytecodeAnalysis(SerializationPolicy::kSerializeIfNeeded);
1274 BytecodeArrayRef(broker(), bytecode_array()).SerializeForCompilation();
1275
1276 BytecodeArrayIterator iterator(bytecode_array());
1277 HandlerRangeMatcher try_start_matcher(iterator, bytecode_array());
1278
1279 bool has_one_shot_bytecode = false;
1280 for (; !iterator.done(); iterator.Advance()) {
1281 has_one_shot_bytecode =
1282 has_one_shot_bytecode ||
1283 interpreter::Bytecodes::IsOneShotBytecode(iterator.current_bytecode());
1284
1285 int const current_offset = iterator.current_offset();
1286
1287 // TODO(mvstanton): we might want to ignore the current environment if we
1288 // are at the start of a catch handler.
1289 IncorporateJumpTargetEnvironment(current_offset);
1290
1291 TRACE_BROKER(broker(),
1292 "Handling bytecode: " << current_offset << " "
1293 << iterator.current_bytecode());
1294 TRACE_BROKER(broker(), "Current environment: " << *environment());
1295
1296 if (environment()->IsDead()) {
1297 continue; // Skip this bytecode since TF won't generate code for it.
1298 }
1299
1300 auto save_handler_environments = [&](int handler_offset) {
1301 auto it = jump_target_environments_.find(handler_offset);
1302 if (it == jump_target_environments_.end()) {
1303 ContributeToJumpTargetEnvironment(handler_offset);
1304 TRACE_BROKER(broker(),
1305 "Handler offset for current pos: " << handler_offset);
1306 }
1307 };
1308 try_start_matcher.HandlerOffsetForCurrentPosition(
1309 save_handler_environments);
1310
1311 if (bytecode_analysis.IsLoopHeader(current_offset)) {
1312 // Graph builder might insert jumps to resume targets in the loop body.
1313 LoopInfo const& loop_info =
1314 bytecode_analysis.GetLoopInfoFor(current_offset);
1315 for (const auto& target : loop_info.resume_jump_targets()) {
1316 ContributeToJumpTargetEnvironment(target.target_offset());
1317 }
1318 }
1319
1320 switch (iterator.current_bytecode()) {
1321 #define DEFINE_BYTECODE_CASE(name) \
1322 case interpreter::Bytecode::k##name: \
1323 Visit##name(&iterator); \
1324 break;
1325 SUPPORTED_BYTECODE_LIST(DEFINE_BYTECODE_CASE)
1326 #undef DEFINE_BYTECODE_CASE
1327 }
1328 }
1329
1330 if (has_one_shot_bytecode) {
1331 broker()->isolate()->CountUsage(
1332 v8::Isolate::UseCounterFeature::kOptimizedFunctionWithOneShotBytecode);
1333 }
1334 }
1335
VisitGetIterator(BytecodeArrayIterator * iterator)1336 void SerializerForBackgroundCompilation::VisitGetIterator(
1337 BytecodeArrayIterator* iterator) {
1338 Hints* receiver = ®ister_hints(iterator->GetRegisterOperand(0));
1339 FeedbackSlot load_slot = iterator->GetSlotOperand(1);
1340 FeedbackSlot call_slot = iterator->GetSlotOperand(2);
1341
1342 Handle<Name> name = broker()->isolate()->factory()->iterator_symbol();
1343 ProcessNamedPropertyAccess(receiver, NameRef(broker(), name), load_slot,
1344 AccessMode::kLoad);
1345 if (environment()->IsDead()) return;
1346
1347 Hints callee;
1348 HintsVector args = PrepareArgumentsHints(receiver);
1349
1350 ProcessCallOrConstruct(callee, base::nullopt, &args, call_slot,
1351 kMissingArgumentsAreUndefined);
1352 }
1353
VisitGetSuperConstructor(BytecodeArrayIterator * iterator)1354 void SerializerForBackgroundCompilation::VisitGetSuperConstructor(
1355 BytecodeArrayIterator* iterator) {
1356 interpreter::Register dst = iterator->GetRegisterOperand(0);
1357 Hints result_hints;
1358 for (auto constant : environment()->accumulator_hints().constants()) {
1359 // For JSNativeContextSpecialization::ReduceJSGetSuperConstructor.
1360 if (!constant->IsJSFunction()) continue;
1361 MapRef map(broker(),
1362 handle(HeapObject::cast(*constant).map(), broker()->isolate()));
1363 map.SerializePrototype();
1364 ObjectRef proto = map.prototype();
1365 if (proto.IsHeapObject() && proto.AsHeapObject().map().is_constructor()) {
1366 result_hints.AddConstant(proto.object(), zone(), broker());
1367 }
1368 }
1369 register_hints(dst) = result_hints;
1370 }
1371
VisitGetTemplateObject(BytecodeArrayIterator * iterator)1372 void SerializerForBackgroundCompilation::VisitGetTemplateObject(
1373 BytecodeArrayIterator* iterator) {
1374 TemplateObjectDescriptionRef description(
1375 broker(), iterator->GetConstantForIndexOperand(0, broker()->isolate()));
1376 FeedbackSlot slot = iterator->GetSlotOperand(1);
1377 FeedbackSource source(feedback_vector(), slot);
1378 SharedFunctionInfoRef shared(broker(), function().shared());
1379 JSArrayRef template_object = shared.GetTemplateObject(
1380 description, source, SerializationPolicy::kSerializeIfNeeded);
1381 environment()->accumulator_hints() =
1382 Hints::SingleConstant(template_object.object(), zone());
1383 }
1384
VisitLdaTrue(BytecodeArrayIterator * iterator)1385 void SerializerForBackgroundCompilation::VisitLdaTrue(
1386 BytecodeArrayIterator* iterator) {
1387 environment()->accumulator_hints() = Hints::SingleConstant(
1388 broker()->isolate()->factory()->true_value(), zone());
1389 }
1390
VisitLdaFalse(BytecodeArrayIterator * iterator)1391 void SerializerForBackgroundCompilation::VisitLdaFalse(
1392 BytecodeArrayIterator* iterator) {
1393 environment()->accumulator_hints() = Hints::SingleConstant(
1394 broker()->isolate()->factory()->false_value(), zone());
1395 }
1396
VisitLdaTheHole(BytecodeArrayIterator * iterator)1397 void SerializerForBackgroundCompilation::VisitLdaTheHole(
1398 BytecodeArrayIterator* iterator) {
1399 environment()->accumulator_hints() = Hints::SingleConstant(
1400 broker()->isolate()->factory()->the_hole_value(), zone());
1401 }
1402
VisitLdaUndefined(BytecodeArrayIterator * iterator)1403 void SerializerForBackgroundCompilation::VisitLdaUndefined(
1404 BytecodeArrayIterator* iterator) {
1405 environment()->accumulator_hints() = Hints::SingleConstant(
1406 broker()->isolate()->factory()->undefined_value(), zone());
1407 }
1408
VisitLdaNull(BytecodeArrayIterator * iterator)1409 void SerializerForBackgroundCompilation::VisitLdaNull(
1410 BytecodeArrayIterator* iterator) {
1411 environment()->accumulator_hints() = Hints::SingleConstant(
1412 broker()->isolate()->factory()->null_value(), zone());
1413 }
1414
VisitLdaZero(BytecodeArrayIterator * iterator)1415 void SerializerForBackgroundCompilation::VisitLdaZero(
1416 BytecodeArrayIterator* iterator) {
1417 environment()->accumulator_hints() = Hints::SingleConstant(
1418 handle(Smi::FromInt(0), broker()->isolate()), zone());
1419 }
1420
VisitLdaSmi(BytecodeArrayIterator * iterator)1421 void SerializerForBackgroundCompilation::VisitLdaSmi(
1422 BytecodeArrayIterator* iterator) {
1423 Handle<Smi> smi(Smi::FromInt(iterator->GetImmediateOperand(0)),
1424 broker()->isolate());
1425 environment()->accumulator_hints() = Hints::SingleConstant(smi, zone());
1426 }
1427
VisitInvokeIntrinsic(BytecodeArrayIterator * iterator)1428 void SerializerForBackgroundCompilation::VisitInvokeIntrinsic(
1429 BytecodeArrayIterator* iterator) {
1430 Runtime::FunctionId functionId = iterator->GetIntrinsicIdOperand(0);
1431 // For JSNativeContextSpecialization::ReduceJSAsyncFunctionResolve and
1432 // JSNativeContextSpecialization::ReduceJSResolvePromise.
1433 switch (functionId) {
1434 case Runtime::kInlineAsyncFunctionResolve: {
1435 ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
1436 Builtins::kAsyncFunctionResolve));
1437 interpreter::Register first_reg = iterator->GetRegisterOperand(1);
1438 size_t reg_count = iterator->GetRegisterCountOperand(2);
1439 CHECK_EQ(reg_count, 3);
1440 HintsVector args = PrepareArgumentsHints(first_reg, reg_count);
1441 Hints const& resolution_hints = args[1]; // The resolution object.
1442 ProcessHintsForPromiseResolve(resolution_hints);
1443 return;
1444 }
1445 case Runtime::kInlineAsyncGeneratorReject:
1446 case Runtime::kAsyncGeneratorReject: {
1447 ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
1448 Builtins::kAsyncGeneratorReject));
1449 break;
1450 }
1451 case Runtime::kInlineAsyncGeneratorResolve:
1452 case Runtime::kAsyncGeneratorResolve: {
1453 ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
1454 Builtins::kAsyncGeneratorResolve));
1455 break;
1456 }
1457 case Runtime::kInlineAsyncGeneratorYield:
1458 case Runtime::kAsyncGeneratorYield: {
1459 ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
1460 Builtins::kAsyncGeneratorYield));
1461 break;
1462 }
1463 case Runtime::kInlineAsyncGeneratorAwaitUncaught:
1464 case Runtime::kAsyncGeneratorAwaitUncaught: {
1465 ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
1466 Builtins::kAsyncGeneratorAwaitUncaught));
1467 break;
1468 }
1469 case Runtime::kInlineAsyncGeneratorAwaitCaught:
1470 case Runtime::kAsyncGeneratorAwaitCaught: {
1471 ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
1472 Builtins::kAsyncGeneratorAwaitCaught));
1473 break;
1474 }
1475 case Runtime::kInlineAsyncFunctionAwaitUncaught:
1476 case Runtime::kAsyncFunctionAwaitUncaught: {
1477 ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
1478 Builtins::kAsyncFunctionAwaitUncaught));
1479 break;
1480 }
1481 case Runtime::kInlineAsyncFunctionAwaitCaught:
1482 case Runtime::kAsyncFunctionAwaitCaught: {
1483 ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
1484 Builtins::kAsyncFunctionAwaitCaught));
1485 break;
1486 }
1487 case Runtime::kInlineAsyncFunctionReject:
1488 case Runtime::kAsyncFunctionReject: {
1489 ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
1490 Builtins::kAsyncFunctionReject));
1491 break;
1492 }
1493 case Runtime::kAsyncFunctionResolve: {
1494 ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
1495 Builtins::kAsyncFunctionResolve));
1496 break;
1497 }
1498 case Runtime::kInlineCopyDataProperties:
1499 case Runtime::kCopyDataProperties: {
1500 ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
1501 Builtins::kCopyDataProperties));
1502 break;
1503 }
1504 case Runtime::kInlineGetImportMetaObject: {
1505 Hints const& context_hints = environment()->current_context_hints();
1506 for (auto x : context_hints.constants()) {
1507 ContextRef(broker(), x)
1508 .GetModule(SerializationPolicy::kSerializeIfNeeded)
1509 .Serialize();
1510 }
1511 for (auto x : context_hints.virtual_contexts()) {
1512 ContextRef(broker(), x.context)
1513 .GetModule(SerializationPolicy::kSerializeIfNeeded)
1514 .Serialize();
1515 }
1516 break;
1517 }
1518 default: {
1519 break;
1520 }
1521 }
1522 environment()->accumulator_hints() = Hints();
1523 }
1524
VisitLdaConstant(BytecodeArrayIterator * iterator)1525 void SerializerForBackgroundCompilation::VisitLdaConstant(
1526 BytecodeArrayIterator* iterator) {
1527 ObjectRef object(
1528 broker(), iterator->GetConstantForIndexOperand(0, broker()->isolate()));
1529 environment()->accumulator_hints() =
1530 Hints::SingleConstant(object.object(), zone());
1531 }
1532
VisitPushContext(BytecodeArrayIterator * iterator)1533 void SerializerForBackgroundCompilation::VisitPushContext(
1534 BytecodeArrayIterator* iterator) {
1535 register_hints(iterator->GetRegisterOperand(0))
1536 .Reset(&environment()->current_context_hints(), zone());
1537 environment()->current_context_hints().Reset(
1538 &environment()->accumulator_hints(), zone());
1539 }
1540
VisitPopContext(BytecodeArrayIterator * iterator)1541 void SerializerForBackgroundCompilation::VisitPopContext(
1542 BytecodeArrayIterator* iterator) {
1543 environment()->current_context_hints().Reset(
1544 ®ister_hints(iterator->GetRegisterOperand(0)), zone());
1545 }
1546
ProcessImmutableLoad(ContextRef const & context_ref,int slot,ContextProcessingMode mode,Hints * result_hints)1547 void SerializerForBackgroundCompilation::ProcessImmutableLoad(
1548 ContextRef const& context_ref, int slot, ContextProcessingMode mode,
1549 Hints* result_hints) {
1550 DCHECK_EQ(mode, kSerializeSlot);
1551 base::Optional<ObjectRef> slot_value =
1552 context_ref.get(slot, SerializationPolicy::kSerializeIfNeeded);
1553
1554 // If requested, record the object as a hint for the result value.
1555 if (result_hints != nullptr && slot_value.has_value()) {
1556 result_hints->AddConstant(slot_value.value().object(), zone(), broker());
1557 }
1558 }
1559
ProcessContextAccess(Hints const & context_hints,int slot,int depth,ContextProcessingMode mode,Hints * result_hints)1560 void SerializerForBackgroundCompilation::ProcessContextAccess(
1561 Hints const& context_hints, int slot, int depth, ContextProcessingMode mode,
1562 Hints* result_hints) {
1563 // This function is for JSContextSpecialization::ReduceJSLoadContext and
1564 // ReduceJSStoreContext. Those reductions attempt to eliminate as many
1565 // loads as possible by making use of constant Context objects. In the
1566 // case of an immutable load, ReduceJSLoadContext even attempts to load
1567 // the value at {slot}, replacing the load with a constant.
1568 for (auto x : context_hints.constants()) {
1569 if (x->IsContext()) {
1570 // Walk this context to the given depth and serialize the slot found.
1571 ContextRef context_ref(broker(), x);
1572 size_t remaining_depth = depth;
1573 context_ref = context_ref.previous(
1574 &remaining_depth, SerializationPolicy::kSerializeIfNeeded);
1575 if (remaining_depth == 0 && mode != kIgnoreSlot) {
1576 ProcessImmutableLoad(context_ref, slot, mode, result_hints);
1577 }
1578 }
1579 }
1580 for (auto x : context_hints.virtual_contexts()) {
1581 if (x.distance <= static_cast<unsigned int>(depth)) {
1582 ContextRef context_ref(broker(), x.context);
1583 size_t remaining_depth = depth - x.distance;
1584 context_ref = context_ref.previous(
1585 &remaining_depth, SerializationPolicy::kSerializeIfNeeded);
1586 if (remaining_depth == 0 && mode != kIgnoreSlot) {
1587 ProcessImmutableLoad(context_ref, slot, mode, result_hints);
1588 }
1589 }
1590 }
1591 }
1592
VisitLdaContextSlot(BytecodeArrayIterator * iterator)1593 void SerializerForBackgroundCompilation::VisitLdaContextSlot(
1594 BytecodeArrayIterator* iterator) {
1595 Hints const& context_hints = register_hints(iterator->GetRegisterOperand(0));
1596 const int slot = iterator->GetIndexOperand(1);
1597 const int depth = iterator->GetUnsignedImmediateOperand(2);
1598 Hints new_accumulator_hints;
1599 ProcessContextAccess(context_hints, slot, depth, kIgnoreSlot,
1600 &new_accumulator_hints);
1601 environment()->accumulator_hints() = new_accumulator_hints;
1602 }
1603
VisitLdaCurrentContextSlot(BytecodeArrayIterator * iterator)1604 void SerializerForBackgroundCompilation::VisitLdaCurrentContextSlot(
1605 BytecodeArrayIterator* iterator) {
1606 const int slot = iterator->GetIndexOperand(0);
1607 const int depth = 0;
1608 Hints const& context_hints = environment()->current_context_hints();
1609 Hints new_accumulator_hints;
1610 ProcessContextAccess(context_hints, slot, depth, kIgnoreSlot,
1611 &new_accumulator_hints);
1612 environment()->accumulator_hints() = new_accumulator_hints;
1613 }
1614
VisitLdaImmutableContextSlot(BytecodeArrayIterator * iterator)1615 void SerializerForBackgroundCompilation::VisitLdaImmutableContextSlot(
1616 BytecodeArrayIterator* iterator) {
1617 const int slot = iterator->GetIndexOperand(1);
1618 const int depth = iterator->GetUnsignedImmediateOperand(2);
1619 Hints const& context_hints = register_hints(iterator->GetRegisterOperand(0));
1620 Hints new_accumulator_hints;
1621 ProcessContextAccess(context_hints, slot, depth, kSerializeSlot,
1622 &new_accumulator_hints);
1623 environment()->accumulator_hints() = new_accumulator_hints;
1624 }
1625
VisitLdaImmutableCurrentContextSlot(BytecodeArrayIterator * iterator)1626 void SerializerForBackgroundCompilation::VisitLdaImmutableCurrentContextSlot(
1627 BytecodeArrayIterator* iterator) {
1628 const int slot = iterator->GetIndexOperand(0);
1629 const int depth = 0;
1630 Hints const& context_hints = environment()->current_context_hints();
1631 Hints new_accumulator_hints;
1632 ProcessContextAccess(context_hints, slot, depth, kSerializeSlot,
1633 &new_accumulator_hints);
1634 environment()->accumulator_hints() = new_accumulator_hints;
1635 }
1636
ProcessModuleVariableAccess(BytecodeArrayIterator * iterator)1637 void SerializerForBackgroundCompilation::ProcessModuleVariableAccess(
1638 BytecodeArrayIterator* iterator) {
1639 const int slot = Context::EXTENSION_INDEX;
1640 const int depth = iterator->GetUnsignedImmediateOperand(1);
1641 Hints const& context_hints = environment()->current_context_hints();
1642
1643 Hints result_hints;
1644 ProcessContextAccess(context_hints, slot, depth, kSerializeSlot,
1645 &result_hints);
1646 for (Handle<Object> constant : result_hints.constants()) {
1647 ObjectRef object(broker(), constant);
1648 // For JSTypedLowering::BuildGetModuleCell.
1649 if (object.IsSourceTextModule()) object.AsSourceTextModule().Serialize();
1650 }
1651 }
1652
VisitLdaModuleVariable(BytecodeArrayIterator * iterator)1653 void SerializerForBackgroundCompilation::VisitLdaModuleVariable(
1654 BytecodeArrayIterator* iterator) {
1655 ProcessModuleVariableAccess(iterator);
1656 }
1657
VisitStaModuleVariable(BytecodeArrayIterator * iterator)1658 void SerializerForBackgroundCompilation::VisitStaModuleVariable(
1659 BytecodeArrayIterator* iterator) {
1660 ProcessModuleVariableAccess(iterator);
1661 }
1662
VisitStaLookupSlot(BytecodeArrayIterator * iterator)1663 void SerializerForBackgroundCompilation::VisitStaLookupSlot(
1664 BytecodeArrayIterator* iterator) {
1665 ObjectRef(broker(),
1666 iterator->GetConstantForIndexOperand(0, broker()->isolate()));
1667 environment()->accumulator_hints() = Hints();
1668 }
1669
VisitStaContextSlot(BytecodeArrayIterator * iterator)1670 void SerializerForBackgroundCompilation::VisitStaContextSlot(
1671 BytecodeArrayIterator* iterator) {
1672 const int slot = iterator->GetIndexOperand(1);
1673 const int depth = iterator->GetUnsignedImmediateOperand(2);
1674 Hints const& hints = register_hints(iterator->GetRegisterOperand(0));
1675 ProcessContextAccess(hints, slot, depth, kIgnoreSlot);
1676 }
1677
VisitStaCurrentContextSlot(BytecodeArrayIterator * iterator)1678 void SerializerForBackgroundCompilation::VisitStaCurrentContextSlot(
1679 BytecodeArrayIterator* iterator) {
1680 const int slot = iterator->GetIndexOperand(0);
1681 const int depth = 0;
1682 Hints const& context_hints = environment()->current_context_hints();
1683 ProcessContextAccess(context_hints, slot, depth, kIgnoreSlot);
1684 }
1685
VisitLdar(BytecodeArrayIterator * iterator)1686 void SerializerForBackgroundCompilation::VisitLdar(
1687 BytecodeArrayIterator* iterator) {
1688 environment()->accumulator_hints().Reset(
1689 ®ister_hints(iterator->GetRegisterOperand(0)), zone());
1690 }
1691
VisitStar(BytecodeArrayIterator * iterator)1692 void SerializerForBackgroundCompilation::VisitStar(
1693 BytecodeArrayIterator* iterator) {
1694 interpreter::Register reg = iterator->GetRegisterOperand(0);
1695 register_hints(reg).Reset(&environment()->accumulator_hints(), zone());
1696 }
1697
VisitMov(BytecodeArrayIterator * iterator)1698 void SerializerForBackgroundCompilation::VisitMov(
1699 BytecodeArrayIterator* iterator) {
1700 interpreter::Register src = iterator->GetRegisterOperand(0);
1701 interpreter::Register dst = iterator->GetRegisterOperand(1);
1702 register_hints(dst).Reset(®ister_hints(src), zone());
1703 }
1704
VisitCreateRegExpLiteral(BytecodeArrayIterator * iterator)1705 void SerializerForBackgroundCompilation::VisitCreateRegExpLiteral(
1706 BytecodeArrayIterator* iterator) {
1707 Handle<String> constant_pattern = Handle<String>::cast(
1708 iterator->GetConstantForIndexOperand(0, broker()->isolate()));
1709 StringRef description(broker(), constant_pattern);
1710 FeedbackSlot slot = iterator->GetSlotOperand(1);
1711 FeedbackSource source(feedback_vector(), slot);
1712 broker()->ProcessFeedbackForRegExpLiteral(source);
1713 environment()->accumulator_hints() = Hints();
1714 }
1715
VisitCreateArrayLiteral(BytecodeArrayIterator * iterator)1716 void SerializerForBackgroundCompilation::VisitCreateArrayLiteral(
1717 BytecodeArrayIterator* iterator) {
1718 Handle<ArrayBoilerplateDescription> array_boilerplate_description =
1719 Handle<ArrayBoilerplateDescription>::cast(
1720 iterator->GetConstantForIndexOperand(0, broker()->isolate()));
1721 ArrayBoilerplateDescriptionRef description(broker(),
1722 array_boilerplate_description);
1723 FeedbackSlot slot = iterator->GetSlotOperand(1);
1724 FeedbackSource source(feedback_vector(), slot);
1725 broker()->ProcessFeedbackForArrayOrObjectLiteral(source);
1726 environment()->accumulator_hints() = Hints();
1727 }
1728
VisitCreateEmptyArrayLiteral(BytecodeArrayIterator * iterator)1729 void SerializerForBackgroundCompilation::VisitCreateEmptyArrayLiteral(
1730 BytecodeArrayIterator* iterator) {
1731 FeedbackSlot slot = iterator->GetSlotOperand(0);
1732 FeedbackSource source(feedback_vector(), slot);
1733 broker()->ProcessFeedbackForArrayOrObjectLiteral(source);
1734 environment()->accumulator_hints() = Hints();
1735 }
1736
VisitCreateObjectLiteral(BytecodeArrayIterator * iterator)1737 void SerializerForBackgroundCompilation::VisitCreateObjectLiteral(
1738 BytecodeArrayIterator* iterator) {
1739 Handle<ObjectBoilerplateDescription> constant_properties =
1740 Handle<ObjectBoilerplateDescription>::cast(
1741 iterator->GetConstantForIndexOperand(0, broker()->isolate()));
1742 ObjectBoilerplateDescriptionRef description(broker(), constant_properties);
1743 FeedbackSlot slot = iterator->GetSlotOperand(1);
1744 FeedbackSource source(feedback_vector(), slot);
1745 broker()->ProcessFeedbackForArrayOrObjectLiteral(source);
1746 environment()->accumulator_hints() = Hints();
1747 }
1748
VisitCreateFunctionContext(BytecodeArrayIterator * iterator)1749 void SerializerForBackgroundCompilation::VisitCreateFunctionContext(
1750 BytecodeArrayIterator* iterator) {
1751 ProcessCreateContext(iterator, 0);
1752 }
1753
VisitCreateBlockContext(BytecodeArrayIterator * iterator)1754 void SerializerForBackgroundCompilation::VisitCreateBlockContext(
1755 BytecodeArrayIterator* iterator) {
1756 ProcessCreateContext(iterator, 0);
1757 }
1758
VisitCreateEvalContext(BytecodeArrayIterator * iterator)1759 void SerializerForBackgroundCompilation::VisitCreateEvalContext(
1760 BytecodeArrayIterator* iterator) {
1761 ProcessCreateContext(iterator, 0);
1762 }
1763
VisitCreateWithContext(BytecodeArrayIterator * iterator)1764 void SerializerForBackgroundCompilation::VisitCreateWithContext(
1765 BytecodeArrayIterator* iterator) {
1766 ProcessCreateContext(iterator, 1);
1767 }
1768
VisitCreateCatchContext(BytecodeArrayIterator * iterator)1769 void SerializerForBackgroundCompilation::VisitCreateCatchContext(
1770 BytecodeArrayIterator* iterator) {
1771 ProcessCreateContext(iterator, 1);
1772 }
1773
VisitForInNext(BytecodeArrayIterator * iterator)1774 void SerializerForBackgroundCompilation::VisitForInNext(
1775 BytecodeArrayIterator* iterator) {
1776 FeedbackSlot slot = iterator->GetSlotOperand(3);
1777 ProcessForIn(slot);
1778 }
1779
VisitForInPrepare(BytecodeArrayIterator * iterator)1780 void SerializerForBackgroundCompilation::VisitForInPrepare(
1781 BytecodeArrayIterator* iterator) {
1782 FeedbackSlot slot = iterator->GetSlotOperand(1);
1783 ProcessForIn(slot);
1784 }
1785
ProcessCreateContext(interpreter::BytecodeArrayIterator * iterator,int scopeinfo_operand_index)1786 void SerializerForBackgroundCompilation::ProcessCreateContext(
1787 interpreter::BytecodeArrayIterator* iterator, int scopeinfo_operand_index) {
1788 Handle<ScopeInfo> scope_info =
1789 Handle<ScopeInfo>::cast(iterator->GetConstantForIndexOperand(
1790 scopeinfo_operand_index, broker()->isolate()));
1791 ScopeInfoRef scope_info_ref(broker(), scope_info);
1792 scope_info_ref.SerializeScopeInfoChain();
1793
1794 Hints const& current_context_hints = environment()->current_context_hints();
1795 Hints result_hints;
1796
1797 // For each constant context, we must create a virtual context from
1798 // it of distance one.
1799 for (auto x : current_context_hints.constants()) {
1800 if (x->IsContext()) {
1801 Handle<Context> as_context(Handle<Context>::cast(x));
1802 result_hints.AddVirtualContext(VirtualContext(1, as_context), zone(),
1803 broker());
1804 }
1805 }
1806
1807 // For each virtual context, we must create a virtual context from
1808 // it of distance {existing distance} + 1.
1809 for (auto x : current_context_hints.virtual_contexts()) {
1810 result_hints.AddVirtualContext(VirtualContext(x.distance + 1, x.context),
1811 zone(), broker());
1812 }
1813
1814 environment()->accumulator_hints() = result_hints;
1815 }
1816
VisitCreateClosure(BytecodeArrayIterator * iterator)1817 void SerializerForBackgroundCompilation::VisitCreateClosure(
1818 BytecodeArrayIterator* iterator) {
1819 Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>::cast(
1820 iterator->GetConstantForIndexOperand(0, broker()->isolate()));
1821 Handle<FeedbackCell> feedback_cell =
1822 feedback_vector()->GetClosureFeedbackCell(iterator->GetIndexOperand(1));
1823 FeedbackCellRef feedback_cell_ref(broker(), feedback_cell);
1824 Handle<Object> cell_value(feedback_cell->value(), broker()->isolate());
1825 ObjectRef cell_value_ref(broker(), cell_value);
1826
1827 Hints result_hints;
1828 if (cell_value->IsFeedbackVector()) {
1829 VirtualClosure virtual_closure(shared,
1830 Handle<FeedbackVector>::cast(cell_value),
1831 environment()->current_context_hints());
1832 result_hints.AddVirtualClosure(virtual_closure, zone(), broker());
1833 }
1834 environment()->accumulator_hints() = result_hints;
1835 }
1836
VisitCallUndefinedReceiver(BytecodeArrayIterator * iterator)1837 void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver(
1838 BytecodeArrayIterator* iterator) {
1839 Hints const& callee = register_hints(iterator->GetRegisterOperand(0));
1840 interpreter::Register first_reg = iterator->GetRegisterOperand(1);
1841 int reg_count = static_cast<int>(iterator->GetRegisterCountOperand(2));
1842 FeedbackSlot slot = iterator->GetSlotOperand(3);
1843 ProcessCallVarArgs(ConvertReceiverMode::kNullOrUndefined, callee, first_reg,
1844 reg_count, slot);
1845 }
1846
VisitCallUndefinedReceiver0(BytecodeArrayIterator * iterator)1847 void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver0(
1848 BytecodeArrayIterator* iterator) {
1849 Hints const& callee = register_hints(iterator->GetRegisterOperand(0));
1850 FeedbackSlot slot = iterator->GetSlotOperand(1);
1851
1852 Hints const receiver = Hints::SingleConstant(
1853 broker()->isolate()->factory()->undefined_value(), zone());
1854 HintsVector parameters({receiver}, zone());
1855
1856 ProcessCallOrConstruct(callee, base::nullopt, ¶meters, slot,
1857 kMissingArgumentsAreUndefined);
1858 }
1859
1860 namespace {
PrepareArgumentsHintsInternal(Zone * zone,HintsVector * args)1861 void PrepareArgumentsHintsInternal(Zone* zone, HintsVector* args) {}
1862
1863 template <typename... MoreHints>
PrepareArgumentsHintsInternal(Zone * zone,HintsVector * args,Hints * hints,MoreHints...more)1864 void PrepareArgumentsHintsInternal(Zone* zone, HintsVector* args, Hints* hints,
1865 MoreHints... more) {
1866 hints->EnsureShareable(zone);
1867 args->push_back(*hints);
1868 PrepareArgumentsHintsInternal(zone, args, more...);
1869 }
1870 } // namespace
1871
1872 template <typename... MoreHints>
PrepareArgumentsHints(Hints * hints,MoreHints...more)1873 HintsVector SerializerForBackgroundCompilation::PrepareArgumentsHints(
1874 Hints* hints, MoreHints... more) {
1875 HintsVector args(zone());
1876 PrepareArgumentsHintsInternal(zone(), &args, hints, more...);
1877 return args;
1878 }
1879
PrepareArgumentsHints(interpreter::Register first,size_t count)1880 HintsVector SerializerForBackgroundCompilation::PrepareArgumentsHints(
1881 interpreter::Register first, size_t count) {
1882 HintsVector result(zone());
1883 const int reg_base = first.index();
1884 for (int i = 0; i < static_cast<int>(count); ++i) {
1885 Hints& hints = register_hints(interpreter::Register(reg_base + i));
1886 hints.EnsureShareable(zone());
1887 result.push_back(hints);
1888 }
1889 return result;
1890 }
1891
VisitCallUndefinedReceiver1(BytecodeArrayIterator * iterator)1892 void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver1(
1893 BytecodeArrayIterator* iterator) {
1894 Hints const& callee = register_hints(iterator->GetRegisterOperand(0));
1895 Hints* arg0 = ®ister_hints(iterator->GetRegisterOperand(1));
1896 FeedbackSlot slot = iterator->GetSlotOperand(2);
1897
1898 Hints receiver = Hints::SingleConstant(
1899 broker()->isolate()->factory()->undefined_value(), zone());
1900 HintsVector args = PrepareArgumentsHints(&receiver, arg0);
1901
1902 ProcessCallOrConstruct(callee, base::nullopt, &args, slot,
1903 kMissingArgumentsAreUndefined);
1904 }
1905
VisitCallUndefinedReceiver2(BytecodeArrayIterator * iterator)1906 void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver2(
1907 BytecodeArrayIterator* iterator) {
1908 Hints const& callee = register_hints(iterator->GetRegisterOperand(0));
1909 Hints* arg0 = ®ister_hints(iterator->GetRegisterOperand(1));
1910 Hints* arg1 = ®ister_hints(iterator->GetRegisterOperand(2));
1911 FeedbackSlot slot = iterator->GetSlotOperand(3);
1912
1913 Hints receiver = Hints::SingleConstant(
1914 broker()->isolate()->factory()->undefined_value(), zone());
1915 HintsVector args = PrepareArgumentsHints(&receiver, arg0, arg1);
1916
1917 ProcessCallOrConstruct(callee, base::nullopt, &args, slot,
1918 kMissingArgumentsAreUndefined);
1919 }
1920
VisitCallAnyReceiver(BytecodeArrayIterator * iterator)1921 void SerializerForBackgroundCompilation::VisitCallAnyReceiver(
1922 BytecodeArrayIterator* iterator) {
1923 Hints const& callee = register_hints(iterator->GetRegisterOperand(0));
1924 interpreter::Register first_reg = iterator->GetRegisterOperand(1);
1925 int reg_count = static_cast<int>(iterator->GetRegisterCountOperand(2));
1926 FeedbackSlot slot = iterator->GetSlotOperand(3);
1927 ProcessCallVarArgs(ConvertReceiverMode::kAny, callee, first_reg, reg_count,
1928 slot);
1929 }
1930
VisitCallNoFeedback(BytecodeArrayIterator * iterator)1931 void SerializerForBackgroundCompilation::VisitCallNoFeedback(
1932 BytecodeArrayIterator* iterator) {
1933 Hints const& callee = register_hints(iterator->GetRegisterOperand(0));
1934 interpreter::Register first_reg = iterator->GetRegisterOperand(1);
1935 int reg_count = static_cast<int>(iterator->GetRegisterCountOperand(2));
1936 ProcessCallVarArgs(ConvertReceiverMode::kAny, callee, first_reg, reg_count,
1937 FeedbackSlot::Invalid());
1938 }
1939
VisitCallProperty(BytecodeArrayIterator * iterator)1940 void SerializerForBackgroundCompilation::VisitCallProperty(
1941 BytecodeArrayIterator* iterator) {
1942 Hints const& callee = register_hints(iterator->GetRegisterOperand(0));
1943 interpreter::Register first_reg = iterator->GetRegisterOperand(1);
1944 int reg_count = static_cast<int>(iterator->GetRegisterCountOperand(2));
1945 FeedbackSlot slot = iterator->GetSlotOperand(3);
1946 ProcessCallVarArgs(ConvertReceiverMode::kNotNullOrUndefined, callee,
1947 first_reg, reg_count, slot);
1948 }
1949
VisitCallProperty0(BytecodeArrayIterator * iterator)1950 void SerializerForBackgroundCompilation::VisitCallProperty0(
1951 BytecodeArrayIterator* iterator) {
1952 Hints const& callee = register_hints(iterator->GetRegisterOperand(0));
1953 Hints* receiver = ®ister_hints(iterator->GetRegisterOperand(1));
1954 FeedbackSlot slot = iterator->GetSlotOperand(2);
1955
1956 HintsVector args = PrepareArgumentsHints(receiver);
1957
1958 ProcessCallOrConstruct(callee, base::nullopt, &args, slot,
1959 kMissingArgumentsAreUndefined);
1960 }
1961
VisitCallProperty1(BytecodeArrayIterator * iterator)1962 void SerializerForBackgroundCompilation::VisitCallProperty1(
1963 BytecodeArrayIterator* iterator) {
1964 Hints const& callee = register_hints(iterator->GetRegisterOperand(0));
1965 Hints* receiver = ®ister_hints(iterator->GetRegisterOperand(1));
1966 Hints* arg0 = ®ister_hints(iterator->GetRegisterOperand(2));
1967 FeedbackSlot slot = iterator->GetSlotOperand(3);
1968
1969 HintsVector args = PrepareArgumentsHints(receiver, arg0);
1970
1971 ProcessCallOrConstruct(callee, base::nullopt, &args, slot,
1972 kMissingArgumentsAreUndefined);
1973 }
1974
VisitCallProperty2(BytecodeArrayIterator * iterator)1975 void SerializerForBackgroundCompilation::VisitCallProperty2(
1976 BytecodeArrayIterator* iterator) {
1977 Hints const& callee = register_hints(iterator->GetRegisterOperand(0));
1978 Hints* receiver = ®ister_hints(iterator->GetRegisterOperand(1));
1979 Hints* arg0 = ®ister_hints(iterator->GetRegisterOperand(2));
1980 Hints* arg1 = ®ister_hints(iterator->GetRegisterOperand(3));
1981 FeedbackSlot slot = iterator->GetSlotOperand(4);
1982
1983 HintsVector args = PrepareArgumentsHints(receiver, arg0, arg1);
1984
1985 ProcessCallOrConstruct(callee, base::nullopt, &args, slot,
1986 kMissingArgumentsAreUndefined);
1987 }
1988
VisitCallWithSpread(BytecodeArrayIterator * iterator)1989 void SerializerForBackgroundCompilation::VisitCallWithSpread(
1990 BytecodeArrayIterator* iterator) {
1991 Hints const& callee = register_hints(iterator->GetRegisterOperand(0));
1992 interpreter::Register first_reg = iterator->GetRegisterOperand(1);
1993 int reg_count = static_cast<int>(iterator->GetRegisterCountOperand(2));
1994 FeedbackSlot slot = iterator->GetSlotOperand(3);
1995 ProcessCallVarArgs(ConvertReceiverMode::kAny, callee, first_reg, reg_count,
1996 slot, kMissingArgumentsAreUnknown);
1997 }
1998
VisitCallJSRuntime(BytecodeArrayIterator * iterator)1999 void SerializerForBackgroundCompilation::VisitCallJSRuntime(
2000 BytecodeArrayIterator* iterator) {
2001 const int runtime_index = iterator->GetNativeContextIndexOperand(0);
2002 ObjectRef constant =
2003 broker()
2004 ->target_native_context()
2005 .get(runtime_index, SerializationPolicy::kSerializeIfNeeded)
2006 .value();
2007 Hints const callee = Hints::SingleConstant(constant.object(), zone());
2008 interpreter::Register first_reg = iterator->GetRegisterOperand(1);
2009 int reg_count = static_cast<int>(iterator->GetRegisterCountOperand(2));
2010 ProcessCallVarArgs(ConvertReceiverMode::kNullOrUndefined, callee, first_reg,
2011 reg_count, FeedbackSlot::Invalid());
2012 }
2013
RunChildSerializer(CompilationSubject function,base::Optional<Hints> new_target,const HintsVector & arguments,MissingArgumentsPolicy padding)2014 Hints SerializerForBackgroundCompilation::RunChildSerializer(
2015 CompilationSubject function, base::Optional<Hints> new_target,
2016 const HintsVector& arguments, MissingArgumentsPolicy padding) {
2017 SerializerForBackgroundCompilation child_serializer(
2018 zone_scope_.zone_stats(), broker(), dependencies(), function, new_target,
2019 arguments, padding, flags(), nesting_level_ + 1);
2020 Hints result = child_serializer.Run();
2021 // The Hints returned by the call to Run are allocated in the zone
2022 // created by the child serializer. Adding those hints to a hints
2023 // object created in our zone will preserve the information.
2024 return result.CopyToParentZone(zone(), broker());
2025 }
2026
ProcessCalleeForCallOrConstruct(Callee const & callee,base::Optional<Hints> new_target,const HintsVector & arguments,SpeculationMode speculation_mode,MissingArgumentsPolicy padding,Hints * result_hints)2027 void SerializerForBackgroundCompilation::ProcessCalleeForCallOrConstruct(
2028 Callee const& callee, base::Optional<Hints> new_target,
2029 const HintsVector& arguments, SpeculationMode speculation_mode,
2030 MissingArgumentsPolicy padding, Hints* result_hints) {
2031 Handle<SharedFunctionInfo> shared = callee.shared(broker()->isolate());
2032 if (shared->IsApiFunction()) {
2033 ProcessApiCall(shared, arguments);
2034 DCHECK_NE(shared->GetInlineability(), SharedFunctionInfo::kIsInlineable);
2035 } else if (shared->HasBuiltinId()) {
2036 ProcessBuiltinCall(shared, new_target, arguments, speculation_mode, padding,
2037 result_hints);
2038 DCHECK_NE(shared->GetInlineability(), SharedFunctionInfo::kIsInlineable);
2039 } else if ((flags() &
2040 SerializerForBackgroundCompilationFlag::kEnableTurboInlining) &&
2041 shared->GetInlineability() == SharedFunctionInfo::kIsInlineable &&
2042 callee.HasFeedbackVector()) {
2043 CompilationSubject subject =
2044 callee.ToCompilationSubject(broker()->isolate(), zone());
2045 result_hints->Add(
2046 RunChildSerializer(subject, new_target, arguments, padding), zone(),
2047 broker());
2048 }
2049 }
2050
2051 namespace {
2052 // Returns the innermost bound target and inserts all bound arguments and
2053 // {original_arguments} into {expanded_arguments} in the appropriate order.
UnrollBoundFunction(JSBoundFunctionRef const & bound_function,JSHeapBroker * broker,const HintsVector & original_arguments,HintsVector * expanded_arguments,Zone * zone)2054 JSReceiverRef UnrollBoundFunction(JSBoundFunctionRef const& bound_function,
2055 JSHeapBroker* broker,
2056 const HintsVector& original_arguments,
2057 HintsVector* expanded_arguments, Zone* zone) {
2058 DCHECK(expanded_arguments->empty());
2059
2060 JSReceiverRef target = bound_function.AsJSReceiver();
2061 HintsVector reversed_bound_arguments(zone);
2062 for (; target.IsJSBoundFunction();
2063 target = target.AsJSBoundFunction().bound_target_function()) {
2064 for (int i = target.AsJSBoundFunction().bound_arguments().length() - 1;
2065 i >= 0; --i) {
2066 Hints const arg = Hints::SingleConstant(
2067 target.AsJSBoundFunction().bound_arguments().get(i).object(), zone);
2068 reversed_bound_arguments.push_back(arg);
2069 }
2070 Hints const arg = Hints::SingleConstant(
2071 target.AsJSBoundFunction().bound_this().object(), zone);
2072 reversed_bound_arguments.push_back(arg);
2073 }
2074
2075 expanded_arguments->insert(expanded_arguments->end(),
2076 reversed_bound_arguments.rbegin(),
2077 reversed_bound_arguments.rend());
2078 expanded_arguments->insert(expanded_arguments->end(),
2079 original_arguments.begin(),
2080 original_arguments.end());
2081
2082 return target;
2083 }
2084 } // namespace
2085
ProcessCalleeForCallOrConstruct(Handle<Object> callee,base::Optional<Hints> new_target,const HintsVector & arguments,SpeculationMode speculation_mode,MissingArgumentsPolicy padding,Hints * result_hints)2086 void SerializerForBackgroundCompilation::ProcessCalleeForCallOrConstruct(
2087 Handle<Object> callee, base::Optional<Hints> new_target,
2088 const HintsVector& arguments, SpeculationMode speculation_mode,
2089 MissingArgumentsPolicy padding, Hints* result_hints) {
2090 const HintsVector* actual_arguments = &arguments;
2091 HintsVector expanded_arguments(zone());
2092 if (callee->IsJSBoundFunction()) {
2093 JSBoundFunctionRef bound_function(broker(),
2094 Handle<JSBoundFunction>::cast(callee));
2095 if (!bound_function.Serialize()) return;
2096 callee = UnrollBoundFunction(bound_function, broker(), arguments,
2097 &expanded_arguments, zone())
2098 .object();
2099 actual_arguments = &expanded_arguments;
2100 }
2101 if (!callee->IsJSFunction()) return;
2102
2103 JSFunctionRef function(broker(), Handle<JSFunction>::cast(callee));
2104 function.Serialize();
2105 Callee new_callee(function.object());
2106 ProcessCalleeForCallOrConstruct(new_callee, new_target, *actual_arguments,
2107 speculation_mode, padding, result_hints);
2108 }
2109
ProcessCallOrConstruct(Hints callee,base::Optional<Hints> new_target,HintsVector * arguments,FeedbackSlot slot,MissingArgumentsPolicy padding)2110 void SerializerForBackgroundCompilation::ProcessCallOrConstruct(
2111 Hints callee, base::Optional<Hints> new_target, HintsVector* arguments,
2112 FeedbackSlot slot, MissingArgumentsPolicy padding) {
2113 SpeculationMode speculation_mode = SpeculationMode::kDisallowSpeculation;
2114
2115 if (!slot.IsInvalid()) {
2116 FeedbackSource source(feedback_vector(), slot);
2117 ProcessedFeedback const& feedback =
2118 broker()->ProcessFeedbackForCall(source);
2119 if (BailoutOnUninitialized(feedback)) return;
2120
2121 if (!feedback.IsInsufficient()) {
2122 // Incorporate feedback into hints copy to simplify processing.
2123 // TODO(neis): Modify the original hints instead?
2124 speculation_mode = feedback.AsCall().speculation_mode();
2125 // Incorporate target feedback into hints copy to simplify processing.
2126 base::Optional<HeapObjectRef> target = feedback.AsCall().target();
2127 if (target.has_value() &&
2128 (target->map().is_callable() || target->IsFeedbackCell())) {
2129 callee = callee.Copy(zone());
2130 // TODO(mvstanton): if the map isn't callable then we have an allocation
2131 // site, and it may make sense to add the Array JSFunction constant.
2132 if (new_target.has_value()) {
2133 // Construct; feedback is new_target, which often is also the callee.
2134 new_target = new_target->Copy(zone());
2135 new_target->AddConstant(target->object(), zone(), broker());
2136 callee.AddConstant(target->object(), zone(), broker());
2137 } else {
2138 // Call; target is feedback cell or callee.
2139 if (target->IsFeedbackCell() &&
2140 target->AsFeedbackCell().value().IsFeedbackVector()) {
2141 FeedbackVectorRef vector =
2142 target->AsFeedbackCell().value().AsFeedbackVector();
2143 vector.Serialize();
2144 VirtualClosure virtual_closure(
2145 vector.shared_function_info().object(), vector.object(),
2146 Hints());
2147 callee.AddVirtualClosure(virtual_closure, zone(), broker());
2148 } else {
2149 callee.AddConstant(target->object(), zone(), broker());
2150 }
2151 }
2152 }
2153 }
2154 }
2155
2156 Hints result_hints_from_new_target;
2157 if (new_target.has_value()) {
2158 ProcessNewTargetForConstruct(*new_target, &result_hints_from_new_target);
2159 // These hints are a good guess at the resulting object, so they are useful
2160 // for both the accumulator and the constructor call's receiver. The latter
2161 // is still missing completely in {arguments} so add it now.
2162 arguments->insert(arguments->begin(), result_hints_from_new_target);
2163 }
2164
2165 // For JSNativeContextSpecialization::InferRootMap
2166 Hints new_accumulator_hints = result_hints_from_new_target.Copy(zone());
2167
2168 ProcessCallOrConstructRecursive(callee, new_target, *arguments,
2169 speculation_mode, padding,
2170 &new_accumulator_hints);
2171 environment()->accumulator_hints() = new_accumulator_hints;
2172 }
2173
ProcessCallOrConstructRecursive(Hints const & callee,base::Optional<Hints> new_target,const HintsVector & arguments,SpeculationMode speculation_mode,MissingArgumentsPolicy padding,Hints * result_hints)2174 void SerializerForBackgroundCompilation::ProcessCallOrConstructRecursive(
2175 Hints const& callee, base::Optional<Hints> new_target,
2176 const HintsVector& arguments, SpeculationMode speculation_mode,
2177 MissingArgumentsPolicy padding, Hints* result_hints) {
2178 // For JSCallReducer::ReduceJSCall and JSCallReducer::ReduceJSConstruct.
2179 for (auto constant : callee.constants()) {
2180 ProcessCalleeForCallOrConstruct(constant, new_target, arguments,
2181 speculation_mode, padding, result_hints);
2182 }
2183
2184 // For JSCallReducer::ReduceJSCall and JSCallReducer::ReduceJSConstruct.
2185 for (auto hint : callee.virtual_closures()) {
2186 ProcessCalleeForCallOrConstruct(Callee(hint), new_target, arguments,
2187 speculation_mode, padding, result_hints);
2188 }
2189
2190 for (auto hint : callee.virtual_bound_functions()) {
2191 HintsVector new_arguments = hint.bound_arguments;
2192 new_arguments.insert(new_arguments.end(), arguments.begin(),
2193 arguments.end());
2194 ProcessCallOrConstructRecursive(hint.bound_target, new_target,
2195 new_arguments, speculation_mode, padding,
2196 result_hints);
2197 }
2198 }
2199
ProcessNewTargetForConstruct(Hints const & new_target_hints,Hints * result_hints)2200 void SerializerForBackgroundCompilation::ProcessNewTargetForConstruct(
2201 Hints const& new_target_hints, Hints* result_hints) {
2202 for (Handle<Object> target : new_target_hints.constants()) {
2203 if (target->IsJSBoundFunction()) {
2204 // Unroll the bound function.
2205 while (target->IsJSBoundFunction()) {
2206 target = handle(
2207 Handle<JSBoundFunction>::cast(target)->bound_target_function(),
2208 broker()->isolate());
2209 }
2210 }
2211 if (target->IsJSFunction()) {
2212 Handle<JSFunction> new_target(Handle<JSFunction>::cast(target));
2213 if (new_target->has_prototype_slot(broker()->isolate()) &&
2214 new_target->has_initial_map()) {
2215 result_hints->AddMap(
2216 handle(new_target->initial_map(), broker()->isolate()), zone(),
2217 broker());
2218 }
2219 }
2220 }
2221
2222 for (auto const& virtual_bound_function :
2223 new_target_hints.virtual_bound_functions()) {
2224 ProcessNewTargetForConstruct(virtual_bound_function.bound_target,
2225 result_hints);
2226 }
2227 }
2228
ProcessCallVarArgs(ConvertReceiverMode receiver_mode,Hints const & callee,interpreter::Register first_reg,int reg_count,FeedbackSlot slot,MissingArgumentsPolicy padding)2229 void SerializerForBackgroundCompilation::ProcessCallVarArgs(
2230 ConvertReceiverMode receiver_mode, Hints const& callee,
2231 interpreter::Register first_reg, int reg_count, FeedbackSlot slot,
2232 MissingArgumentsPolicy padding) {
2233 HintsVector args = PrepareArgumentsHints(first_reg, reg_count);
2234 // The receiver is either given in the first register or it is implicitly
2235 // the {undefined} value.
2236 if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
2237 args.insert(args.begin(),
2238 Hints::SingleConstant(
2239 broker()->isolate()->factory()->undefined_value(), zone()));
2240 }
2241 ProcessCallOrConstruct(callee, base::nullopt, &args, slot, padding);
2242 }
2243
ProcessApiCall(Handle<SharedFunctionInfo> target,const HintsVector & arguments)2244 void SerializerForBackgroundCompilation::ProcessApiCall(
2245 Handle<SharedFunctionInfo> target, const HintsVector& arguments) {
2246 ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
2247 Builtins::kCallFunctionTemplate_CheckAccess));
2248 ObjectRef(broker(),
2249 broker()->isolate()->builtins()->builtin_handle(
2250 Builtins::kCallFunctionTemplate_CheckCompatibleReceiver));
2251 ObjectRef(
2252 broker(),
2253 broker()->isolate()->builtins()->builtin_handle(
2254 Builtins::kCallFunctionTemplate_CheckAccessAndCompatibleReceiver));
2255
2256 FunctionTemplateInfoRef target_template_info(
2257 broker(),
2258 handle(target->function_data(kAcquireLoad), broker()->isolate()));
2259 if (!target_template_info.has_call_code()) return;
2260 target_template_info.SerializeCallCode();
2261
2262 SharedFunctionInfoRef target_ref(broker(), target);
2263 target_ref.SerializeFunctionTemplateInfo();
2264
2265 if (target_template_info.accept_any_receiver() &&
2266 target_template_info.is_signature_undefined()) {
2267 return;
2268 }
2269
2270 if (arguments.empty()) return;
2271 Hints const& receiver_hints = arguments[0];
2272 for (auto hint : receiver_hints.constants()) {
2273 if (hint->IsUndefined()) {
2274 // The receiver is the global proxy.
2275 Handle<JSGlobalProxy> global_proxy =
2276 broker()->target_native_context().global_proxy_object().object();
2277 ProcessReceiverMapForApiCall(
2278 target_template_info,
2279 handle(global_proxy->map(), broker()->isolate()));
2280 continue;
2281 }
2282
2283 if (!hint->IsJSReceiver()) continue;
2284 Handle<JSReceiver> receiver(Handle<JSReceiver>::cast(hint));
2285
2286 ProcessReceiverMapForApiCall(target_template_info,
2287 handle(receiver->map(), broker()->isolate()));
2288 }
2289
2290 for (auto receiver_map : receiver_hints.maps()) {
2291 ProcessReceiverMapForApiCall(target_template_info, receiver_map);
2292 }
2293 }
2294
ProcessReceiverMapForApiCall(FunctionTemplateInfoRef target,Handle<Map> receiver)2295 void SerializerForBackgroundCompilation::ProcessReceiverMapForApiCall(
2296 FunctionTemplateInfoRef target, Handle<Map> receiver) {
2297 if (!receiver->is_access_check_needed()) {
2298 MapRef receiver_map(broker(), receiver);
2299 TRACE_BROKER(broker(), "Serializing holder for target: " << target);
2300 target.LookupHolderOfExpectedType(receiver_map,
2301 SerializationPolicy::kSerializeIfNeeded);
2302 }
2303 }
2304
ProcessHintsForObjectCreate(Hints const & prototype)2305 void SerializerForBackgroundCompilation::ProcessHintsForObjectCreate(
2306 Hints const& prototype) {
2307 for (Handle<Object> constant_handle : prototype.constants()) {
2308 ObjectRef constant(broker(), constant_handle);
2309 if (constant.IsJSObject()) constant.AsJSObject().SerializeObjectCreateMap();
2310 }
2311 }
2312
ProcessBuiltinCall(Handle<SharedFunctionInfo> target,base::Optional<Hints> new_target,const HintsVector & arguments,SpeculationMode speculation_mode,MissingArgumentsPolicy padding,Hints * result_hints)2313 void SerializerForBackgroundCompilation::ProcessBuiltinCall(
2314 Handle<SharedFunctionInfo> target, base::Optional<Hints> new_target,
2315 const HintsVector& arguments, SpeculationMode speculation_mode,
2316 MissingArgumentsPolicy padding, Hints* result_hints) {
2317 DCHECK(target->HasBuiltinId());
2318 const int builtin_id = target->builtin_id();
2319 const char* name = Builtins::name(builtin_id);
2320 TRACE_BROKER(broker(), "Serializing for call to builtin " << name);
2321 switch (builtin_id) {
2322 case Builtins::kObjectCreate: {
2323 if (arguments.size() >= 2) {
2324 ProcessHintsForObjectCreate(arguments[1]);
2325 } else {
2326 ProcessHintsForObjectCreate(Hints::SingleConstant(
2327 broker()->isolate()->factory()->undefined_value(), zone()));
2328 }
2329 break;
2330 }
2331 case Builtins::kPromisePrototypeCatch: {
2332 // For JSCallReducer::ReducePromisePrototypeCatch.
2333 if (speculation_mode != SpeculationMode::kDisallowSpeculation) {
2334 if (arguments.size() >= 1) {
2335 ProcessMapHintsForPromises(arguments[0]);
2336 }
2337 }
2338 break;
2339 }
2340 case Builtins::kPromisePrototypeFinally: {
2341 // For JSCallReducer::ReducePromisePrototypeFinally.
2342 if (speculation_mode != SpeculationMode::kDisallowSpeculation) {
2343 if (arguments.size() >= 1) {
2344 ProcessMapHintsForPromises(arguments[0]);
2345 }
2346 SharedFunctionInfoRef(
2347 broker(),
2348 broker()->isolate()->factory()->promise_catch_finally_shared_fun());
2349 SharedFunctionInfoRef(
2350 broker(),
2351 broker()->isolate()->factory()->promise_then_finally_shared_fun());
2352 }
2353 break;
2354 }
2355 case Builtins::kPromisePrototypeThen: {
2356 // For JSCallReducer::ReducePromisePrototypeThen.
2357 if (speculation_mode != SpeculationMode::kDisallowSpeculation) {
2358 if (arguments.size() >= 1) {
2359 ProcessMapHintsForPromises(arguments[0]);
2360 }
2361 }
2362 break;
2363 }
2364 case Builtins::kPromiseResolveTrampoline:
2365 // For JSCallReducer::ReducePromiseInternalResolve and
2366 // JSNativeContextSpecialization::ReduceJSResolvePromise.
2367 if (arguments.size() >= 1) {
2368 Hints const resolution_hints =
2369 arguments.size() >= 2
2370 ? arguments[1]
2371 : Hints::SingleConstant(
2372 broker()->isolate()->factory()->undefined_value(),
2373 zone());
2374 ProcessHintsForPromiseResolve(resolution_hints);
2375 }
2376 break;
2377 case Builtins::kRegExpPrototypeTest:
2378 case Builtins::kRegExpPrototypeTestFast:
2379 // For JSCallReducer::ReduceRegExpPrototypeTest.
2380 if (arguments.size() >= 1 &&
2381 speculation_mode != SpeculationMode::kDisallowSpeculation) {
2382 Hints const& regexp_hints = arguments[0];
2383 ProcessHintsForRegExpTest(regexp_hints);
2384 }
2385 break;
2386 case Builtins::kArrayEvery:
2387 case Builtins::kArrayFilter:
2388 case Builtins::kArrayForEach:
2389 case Builtins::kArrayPrototypeFind:
2390 case Builtins::kArrayPrototypeFindIndex:
2391 case Builtins::kArrayMap:
2392 case Builtins::kArraySome:
2393 if (arguments.size() >= 2 &&
2394 speculation_mode != SpeculationMode::kDisallowSpeculation) {
2395 Hints const& callback = arguments[1];
2396 // "Call(callbackfn, T, « kValue, k, O »)"
2397 HintsVector new_arguments(zone());
2398 new_arguments.push_back(
2399 arguments.size() < 3
2400 ? Hints::SingleConstant(
2401 broker()->isolate()->factory()->undefined_value(), zone())
2402 : arguments[2]); // T
2403 new_arguments.push_back(Hints()); // kValue
2404 new_arguments.push_back(Hints()); // k
2405 new_arguments.push_back(arguments[0]); // O
2406 for (auto constant : callback.constants()) {
2407 ProcessCalleeForCallOrConstruct(
2408 constant, base::nullopt, new_arguments, speculation_mode,
2409 kMissingArgumentsAreUndefined, result_hints);
2410 }
2411 for (auto virtual_closure : callback.virtual_closures()) {
2412 ProcessCalleeForCallOrConstruct(
2413 Callee(virtual_closure), base::nullopt, new_arguments,
2414 speculation_mode, kMissingArgumentsAreUndefined, result_hints);
2415 }
2416 }
2417 break;
2418 case Builtins::kArrayReduce:
2419 case Builtins::kArrayReduceRight:
2420 if (arguments.size() >= 2 &&
2421 speculation_mode != SpeculationMode::kDisallowSpeculation) {
2422 Hints const& callback = arguments[1];
2423 // "Call(callbackfn, undefined, « accumulator, kValue, k, O »)"
2424 HintsVector new_arguments(zone());
2425 new_arguments.push_back(Hints::SingleConstant(
2426 broker()->isolate()->factory()->undefined_value(), zone()));
2427 new_arguments.push_back(Hints()); // accumulator
2428 new_arguments.push_back(Hints()); // kValue
2429 new_arguments.push_back(Hints()); // k
2430 new_arguments.push_back(arguments[0]); // O
2431 for (auto constant : callback.constants()) {
2432 ProcessCalleeForCallOrConstruct(
2433 constant, base::nullopt, new_arguments, speculation_mode,
2434 kMissingArgumentsAreUndefined, result_hints);
2435 }
2436 for (auto virtual_closure : callback.virtual_closures()) {
2437 ProcessCalleeForCallOrConstruct(
2438 Callee(virtual_closure), base::nullopt, new_arguments,
2439 speculation_mode, kMissingArgumentsAreUndefined, result_hints);
2440 }
2441 }
2442 break;
2443 case Builtins::kFunctionPrototypeApply:
2444 if (arguments.size() >= 1) {
2445 // Drop hints for all arguments except the user-given receiver.
2446 Hints const new_receiver =
2447 arguments.size() >= 2
2448 ? arguments[1]
2449 : Hints::SingleConstant(
2450 broker()->isolate()->factory()->undefined_value(),
2451 zone());
2452 HintsVector new_arguments({new_receiver}, zone());
2453 for (auto constant : arguments[0].constants()) {
2454 ProcessCalleeForCallOrConstruct(
2455 constant, base::nullopt, new_arguments, speculation_mode,
2456 kMissingArgumentsAreUnknown, result_hints);
2457 }
2458 for (auto const& virtual_closure : arguments[0].virtual_closures()) {
2459 ProcessCalleeForCallOrConstruct(
2460 Callee(virtual_closure), base::nullopt, new_arguments,
2461 speculation_mode, kMissingArgumentsAreUnknown, result_hints);
2462 }
2463 }
2464 break;
2465 case Builtins::kPromiseConstructor:
2466 if (arguments.size() >= 1) {
2467 // "Call(executor, undefined, « resolvingFunctions.[[Resolve]],
2468 // resolvingFunctions.[[Reject]] »)"
2469 HintsVector new_arguments(
2470 {Hints::SingleConstant(
2471 broker()->isolate()->factory()->undefined_value(), zone())},
2472 zone());
2473 for (auto constant : arguments[0].constants()) {
2474 ProcessCalleeForCallOrConstruct(
2475 constant, base::nullopt, new_arguments,
2476 SpeculationMode::kDisallowSpeculation,
2477 kMissingArgumentsAreUnknown, result_hints);
2478 }
2479 for (auto const& virtual_closure : arguments[0].virtual_closures()) {
2480 ProcessCalleeForCallOrConstruct(
2481 Callee(virtual_closure), base::nullopt, new_arguments,
2482 SpeculationMode::kDisallowSpeculation,
2483 kMissingArgumentsAreUnknown, result_hints);
2484 }
2485 }
2486 SharedFunctionInfoRef(
2487 broker(), broker()
2488 ->isolate()
2489 ->factory()
2490 ->promise_capability_default_reject_shared_fun());
2491 SharedFunctionInfoRef(
2492 broker(), broker()
2493 ->isolate()
2494 ->factory()
2495 ->promise_capability_default_resolve_shared_fun());
2496
2497 break;
2498 case Builtins::kFunctionPrototypeCall:
2499 if (arguments.size() >= 1) {
2500 HintsVector new_arguments(arguments.begin() + 1, arguments.end(),
2501 zone());
2502 for (auto constant : arguments[0].constants()) {
2503 ProcessCalleeForCallOrConstruct(constant, base::nullopt,
2504 new_arguments, speculation_mode,
2505 padding, result_hints);
2506 }
2507 for (auto const& virtual_closure : arguments[0].virtual_closures()) {
2508 ProcessCalleeForCallOrConstruct(
2509 Callee(virtual_closure), base::nullopt, new_arguments,
2510 speculation_mode, padding, result_hints);
2511 }
2512 }
2513 break;
2514 case Builtins::kReflectApply:
2515 case Builtins::kReflectConstruct:
2516 if (arguments.size() >= 2) {
2517 for (auto constant : arguments[1].constants()) {
2518 if (constant->IsJSFunction()) {
2519 JSFunctionRef(broker(), constant).Serialize();
2520 }
2521 }
2522 }
2523 break;
2524 case Builtins::kObjectPrototypeIsPrototypeOf:
2525 if (arguments.size() >= 2) {
2526 ProcessHintsForHasInPrototypeChain(arguments[1]);
2527 }
2528 break;
2529 case Builtins::kFunctionPrototypeHasInstance:
2530 // For JSCallReducer::ReduceFunctionPrototypeHasInstance.
2531 if (arguments.size() >= 2) {
2532 ProcessHintsForOrdinaryHasInstance(arguments[0], arguments[1]);
2533 }
2534 break;
2535 case Builtins::kFastFunctionPrototypeBind:
2536 if (arguments.size() >= 1 &&
2537 speculation_mode != SpeculationMode::kDisallowSpeculation) {
2538 Hints const& bound_target = arguments[0];
2539 ProcessHintsForFunctionBind(bound_target);
2540 HintsVector new_arguments(arguments.begin() + 1, arguments.end(),
2541 zone());
2542 result_hints->AddVirtualBoundFunction(
2543 VirtualBoundFunction(bound_target, new_arguments), zone(),
2544 broker());
2545 }
2546 break;
2547 case Builtins::kObjectGetPrototypeOf:
2548 case Builtins::kReflectGetPrototypeOf:
2549 if (arguments.size() >= 2) {
2550 ProcessHintsForObjectGetPrototype(arguments[1]);
2551 } else {
2552 Hints const undefined_hint = Hints::SingleConstant(
2553 broker()->isolate()->factory()->undefined_value(), zone());
2554 ProcessHintsForObjectGetPrototype(undefined_hint);
2555 }
2556 break;
2557 case Builtins::kObjectPrototypeGetProto:
2558 if (arguments.size() >= 1) {
2559 ProcessHintsForObjectGetPrototype(arguments[0]);
2560 }
2561 break;
2562 case Builtins::kMapIteratorPrototypeNext:
2563 ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
2564 Builtins::kOrderedHashTableHealIndex));
2565 ObjectRef(broker(),
2566 broker()->isolate()->factory()->empty_ordered_hash_map());
2567 break;
2568 case Builtins::kSetIteratorPrototypeNext:
2569 ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
2570 Builtins::kOrderedHashTableHealIndex));
2571 ObjectRef(broker(),
2572 broker()->isolate()->factory()->empty_ordered_hash_set());
2573 break;
2574 default:
2575 break;
2576 }
2577 }
2578
ProcessHintsForOrdinaryHasInstance(Hints const & constructor_hints,Hints const & instance_hints)2579 void SerializerForBackgroundCompilation::ProcessHintsForOrdinaryHasInstance(
2580 Hints const& constructor_hints, Hints const& instance_hints) {
2581 bool walk_prototypes = false;
2582 for (Handle<Object> constructor : constructor_hints.constants()) {
2583 // For JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance.
2584 if (constructor->IsHeapObject()) {
2585 ProcessConstantForOrdinaryHasInstance(
2586 HeapObjectRef(broker(), constructor), &walk_prototypes);
2587 }
2588 }
2589 // For JSNativeContextSpecialization::ReduceJSHasInPrototypeChain.
2590 if (walk_prototypes) ProcessHintsForHasInPrototypeChain(instance_hints);
2591 }
2592
ProcessHintsForHasInPrototypeChain(Hints const & instance_hints)2593 void SerializerForBackgroundCompilation::ProcessHintsForHasInPrototypeChain(
2594 Hints const& instance_hints) {
2595 auto processMap = [&](Handle<Map> map_handle) {
2596 MapRef map(broker(), map_handle);
2597 while (map.IsJSObjectMap()) {
2598 map.SerializePrototype();
2599 map = map.prototype().map();
2600 }
2601 };
2602
2603 for (auto hint : instance_hints.constants()) {
2604 if (!hint->IsHeapObject()) continue;
2605 Handle<HeapObject> object(Handle<HeapObject>::cast(hint));
2606 processMap(handle(object->map(), broker()->isolate()));
2607 }
2608 for (auto map_hint : instance_hints.maps()) {
2609 processMap(map_hint);
2610 }
2611 }
2612
ProcessHintsForPromiseResolve(Hints const & resolution_hints)2613 void SerializerForBackgroundCompilation::ProcessHintsForPromiseResolve(
2614 Hints const& resolution_hints) {
2615 auto processMap = [&](Handle<Map> map) {
2616 broker()->GetPropertyAccessInfo(
2617 MapRef(broker(), map),
2618 NameRef(broker(), broker()->isolate()->factory()->then_string()),
2619 AccessMode::kLoad, dependencies(),
2620 SerializationPolicy::kSerializeIfNeeded);
2621 };
2622
2623 for (auto hint : resolution_hints.constants()) {
2624 if (!hint->IsHeapObject()) continue;
2625 Handle<HeapObject> resolution(Handle<HeapObject>::cast(hint));
2626 processMap(handle(resolution->map(), broker()->isolate()));
2627 }
2628 for (auto map_hint : resolution_hints.maps()) {
2629 processMap(map_hint);
2630 }
2631 }
2632
ProcessMapHintsForPromises(Hints const & receiver_hints)2633 void SerializerForBackgroundCompilation::ProcessMapHintsForPromises(
2634 Hints const& receiver_hints) {
2635 // We need to serialize the prototypes on each receiver map.
2636 for (auto constant : receiver_hints.constants()) {
2637 if (!constant->IsJSPromise()) continue;
2638 Handle<Map> map(Handle<HeapObject>::cast(constant)->map(),
2639 broker()->isolate());
2640 MapRef(broker(), map).SerializePrototype();
2641 }
2642 for (auto map : receiver_hints.maps()) {
2643 if (!map->IsJSPromiseMap()) continue;
2644 MapRef(broker(), map).SerializePrototype();
2645 }
2646 }
2647
ProcessMapForRegExpTest(MapRef map)2648 PropertyAccessInfo SerializerForBackgroundCompilation::ProcessMapForRegExpTest(
2649 MapRef map) {
2650 PropertyAccessInfo ai_exec = broker()->GetPropertyAccessInfo(
2651 map, NameRef(broker(), broker()->isolate()->factory()->exec_string()),
2652 AccessMode::kLoad, dependencies(),
2653 SerializationPolicy::kSerializeIfNeeded);
2654
2655 Handle<JSObject> holder;
2656 if (ai_exec.IsDataConstant() && ai_exec.holder().ToHandle(&holder)) {
2657 // The property is on the prototype chain.
2658 JSObjectRef holder_ref(broker(), holder);
2659 holder_ref.GetOwnDataProperty(ai_exec.field_representation(),
2660 ai_exec.field_index(),
2661 SerializationPolicy::kSerializeIfNeeded);
2662 }
2663 return ai_exec;
2664 }
2665
ProcessHintsForRegExpTest(Hints const & regexp_hints)2666 void SerializerForBackgroundCompilation::ProcessHintsForRegExpTest(
2667 Hints const& regexp_hints) {
2668 for (auto hint : regexp_hints.constants()) {
2669 if (!hint->IsJSRegExp()) continue;
2670 Handle<JSRegExp> regexp(Handle<JSRegExp>::cast(hint));
2671 Handle<Map> regexp_map(regexp->map(), broker()->isolate());
2672 PropertyAccessInfo ai_exec =
2673 ProcessMapForRegExpTest(MapRef(broker(), regexp_map));
2674 Handle<JSObject> holder;
2675 if (ai_exec.IsDataConstant() && !ai_exec.holder().ToHandle(&holder)) {
2676 // The property is on the object itself.
2677 JSObjectRef holder_ref(broker(), regexp);
2678 holder_ref.GetOwnDataProperty(ai_exec.field_representation(),
2679 ai_exec.field_index(),
2680 SerializationPolicy::kSerializeIfNeeded);
2681 }
2682 }
2683
2684 for (auto map : regexp_hints.maps()) {
2685 if (!map->IsJSRegExpMap()) continue;
2686 ProcessMapForRegExpTest(MapRef(broker(), map));
2687 }
2688 }
2689
2690 namespace {
ProcessMapForFunctionBind(MapRef map)2691 void ProcessMapForFunctionBind(MapRef map) {
2692 map.SerializePrototype();
2693 int min_nof_descriptors = std::max({JSFunction::kLengthDescriptorIndex,
2694 JSFunction::kNameDescriptorIndex}) +
2695 1;
2696 if (map.NumberOfOwnDescriptors() >= min_nof_descriptors) {
2697 map.SerializeOwnDescriptor(
2698 InternalIndex(JSFunction::kLengthDescriptorIndex));
2699 map.SerializeOwnDescriptor(InternalIndex(JSFunction::kNameDescriptorIndex));
2700 }
2701 }
2702 } // namespace
2703
ProcessHintsForFunctionBind(Hints const & receiver_hints)2704 void SerializerForBackgroundCompilation::ProcessHintsForFunctionBind(
2705 Hints const& receiver_hints) {
2706 for (auto constant : receiver_hints.constants()) {
2707 if (!constant->IsJSFunction()) continue;
2708 JSFunctionRef function(broker(), constant);
2709 function.Serialize();
2710 ProcessMapForFunctionBind(function.map());
2711 }
2712
2713 for (auto map : receiver_hints.maps()) {
2714 if (!map->IsJSFunctionMap()) continue;
2715 MapRef map_ref(broker(), map);
2716 ProcessMapForFunctionBind(map_ref);
2717 }
2718 }
2719
ProcessHintsForObjectGetPrototype(Hints const & object_hints)2720 void SerializerForBackgroundCompilation::ProcessHintsForObjectGetPrototype(
2721 Hints const& object_hints) {
2722 for (auto constant : object_hints.constants()) {
2723 if (!constant->IsHeapObject()) continue;
2724 HeapObjectRef object(broker(), constant);
2725 object.map().SerializePrototype();
2726 }
2727
2728 for (auto map : object_hints.maps()) {
2729 MapRef map_ref(broker(), map);
2730 map_ref.SerializePrototype();
2731 }
2732 }
2733
ContributeToJumpTargetEnvironment(int target_offset)2734 void SerializerForBackgroundCompilation::ContributeToJumpTargetEnvironment(
2735 int target_offset) {
2736 auto it = jump_target_environments_.find(target_offset);
2737 if (it == jump_target_environments_.end()) {
2738 jump_target_environments_[target_offset] =
2739 zone()->New<Environment>(*environment());
2740 } else {
2741 it->second->Merge(environment(), zone(), broker());
2742 }
2743 }
2744
IncorporateJumpTargetEnvironment(int target_offset)2745 void SerializerForBackgroundCompilation::IncorporateJumpTargetEnvironment(
2746 int target_offset) {
2747 auto it = jump_target_environments_.find(target_offset);
2748 if (it != jump_target_environments_.end()) {
2749 environment()->Merge(it->second, zone(), broker());
2750 jump_target_environments_.erase(it);
2751 }
2752 }
2753
ProcessJump(interpreter::BytecodeArrayIterator * iterator)2754 void SerializerForBackgroundCompilation::ProcessJump(
2755 interpreter::BytecodeArrayIterator* iterator) {
2756 int jump_target = iterator->GetJumpTargetOffset();
2757 if (iterator->current_offset() < jump_target) {
2758 ContributeToJumpTargetEnvironment(jump_target);
2759 }
2760 }
2761
VisitReturn(BytecodeArrayIterator * iterator)2762 void SerializerForBackgroundCompilation::VisitReturn(
2763 BytecodeArrayIterator* iterator) {
2764 return_value_hints().Add(environment()->accumulator_hints(), zone(),
2765 broker());
2766 environment()->Kill();
2767 }
2768
VisitSwitchOnSmiNoFeedback(interpreter::BytecodeArrayIterator * iterator)2769 void SerializerForBackgroundCompilation::VisitSwitchOnSmiNoFeedback(
2770 interpreter::BytecodeArrayIterator* iterator) {
2771 interpreter::JumpTableTargetOffsets targets =
2772 iterator->GetJumpTableTargetOffsets();
2773 for (const auto& target : targets) {
2774 ContributeToJumpTargetEnvironment(target.target_offset);
2775 }
2776 }
2777
VisitSwitchOnGeneratorState(interpreter::BytecodeArrayIterator * iterator)2778 void SerializerForBackgroundCompilation::VisitSwitchOnGeneratorState(
2779 interpreter::BytecodeArrayIterator* iterator) {
2780 for (const auto& target : GetBytecodeAnalysis().resume_jump_targets()) {
2781 ContributeToJumpTargetEnvironment(target.target_offset());
2782 }
2783 }
2784
VisitConstruct(BytecodeArrayIterator * iterator)2785 void SerializerForBackgroundCompilation::VisitConstruct(
2786 BytecodeArrayIterator* iterator) {
2787 Hints& new_target = environment()->accumulator_hints();
2788 Hints const& callee = register_hints(iterator->GetRegisterOperand(0));
2789 interpreter::Register first_reg = iterator->GetRegisterOperand(1);
2790 size_t reg_count = iterator->GetRegisterCountOperand(2);
2791 FeedbackSlot slot = iterator->GetSlotOperand(3);
2792
2793 HintsVector args = PrepareArgumentsHints(first_reg, reg_count);
2794
2795 ProcessCallOrConstruct(callee, new_target, &args, slot,
2796 kMissingArgumentsAreUndefined);
2797 }
2798
VisitConstructWithSpread(BytecodeArrayIterator * iterator)2799 void SerializerForBackgroundCompilation::VisitConstructWithSpread(
2800 BytecodeArrayIterator* iterator) {
2801 Hints const& new_target = environment()->accumulator_hints();
2802 Hints const& callee = register_hints(iterator->GetRegisterOperand(0));
2803 interpreter::Register first_reg = iterator->GetRegisterOperand(1);
2804 size_t reg_count = iterator->GetRegisterCountOperand(2);
2805 FeedbackSlot slot = iterator->GetSlotOperand(3);
2806
2807 DCHECK_GT(reg_count, 0);
2808 reg_count--; // Pop the spread element.
2809 HintsVector args = PrepareArgumentsHints(first_reg, reg_count);
2810
2811 ProcessCallOrConstruct(callee, new_target, &args, slot,
2812 kMissingArgumentsAreUnknown);
2813 }
2814
ProcessGlobalAccess(FeedbackSlot slot,bool is_load)2815 void SerializerForBackgroundCompilation::ProcessGlobalAccess(FeedbackSlot slot,
2816 bool is_load) {
2817 if (slot.IsInvalid() || feedback_vector().is_null()) return;
2818 FeedbackSource source(feedback_vector(), slot);
2819 ProcessedFeedback const& feedback =
2820 broker()->ProcessFeedbackForGlobalAccess(source);
2821
2822 if (is_load) {
2823 Hints result_hints;
2824 if (feedback.kind() == ProcessedFeedback::kGlobalAccess) {
2825 // We may be able to contribute to accumulator constant hints.
2826 base::Optional<ObjectRef> value =
2827 feedback.AsGlobalAccess().GetConstantHint();
2828 if (value.has_value()) {
2829 result_hints.AddConstant(value->object(), zone(), broker());
2830 }
2831 } else {
2832 DCHECK(feedback.IsInsufficient());
2833 }
2834 environment()->accumulator_hints() = result_hints;
2835 }
2836 }
2837
VisitLdaGlobal(BytecodeArrayIterator * iterator)2838 void SerializerForBackgroundCompilation::VisitLdaGlobal(
2839 BytecodeArrayIterator* iterator) {
2840 NameRef(broker(),
2841 iterator->GetConstantForIndexOperand(0, broker()->isolate()));
2842 FeedbackSlot slot = iterator->GetSlotOperand(1);
2843 ProcessGlobalAccess(slot, true);
2844 }
2845
VisitLdaGlobalInsideTypeof(BytecodeArrayIterator * iterator)2846 void SerializerForBackgroundCompilation::VisitLdaGlobalInsideTypeof(
2847 BytecodeArrayIterator* iterator) {
2848 VisitLdaGlobal(iterator);
2849 }
2850
VisitLdaLookupSlot(BytecodeArrayIterator * iterator)2851 void SerializerForBackgroundCompilation::VisitLdaLookupSlot(
2852 BytecodeArrayIterator* iterator) {
2853 ObjectRef(broker(),
2854 iterator->GetConstantForIndexOperand(0, broker()->isolate()));
2855 environment()->accumulator_hints() = Hints();
2856 }
2857
VisitLdaLookupSlotInsideTypeof(BytecodeArrayIterator * iterator)2858 void SerializerForBackgroundCompilation::VisitLdaLookupSlotInsideTypeof(
2859 BytecodeArrayIterator* iterator) {
2860 ObjectRef(broker(),
2861 iterator->GetConstantForIndexOperand(0, broker()->isolate()));
2862 environment()->accumulator_hints() = Hints();
2863 }
2864
ProcessCheckContextExtensions(int depth)2865 void SerializerForBackgroundCompilation::ProcessCheckContextExtensions(
2866 int depth) {
2867 // for BytecodeGraphBuilder::CheckContextExtensions.
2868 Hints const& context_hints = environment()->current_context_hints();
2869 for (int i = 0; i < depth; i++) {
2870 ProcessContextAccess(context_hints, Context::EXTENSION_INDEX, i,
2871 kSerializeSlot);
2872 }
2873 SharedFunctionInfoRef shared(broker(), function().shared());
2874 shared.SerializeScopeInfoChain();
2875 }
2876
ProcessLdaLookupGlobalSlot(BytecodeArrayIterator * iterator)2877 void SerializerForBackgroundCompilation::ProcessLdaLookupGlobalSlot(
2878 BytecodeArrayIterator* iterator) {
2879 ProcessCheckContextExtensions(iterator->GetUnsignedImmediateOperand(2));
2880 // TODO(neis): BytecodeGraphBilder may insert a JSLoadGlobal.
2881 VisitLdaGlobal(iterator);
2882 }
2883
VisitLdaLookupGlobalSlot(BytecodeArrayIterator * iterator)2884 void SerializerForBackgroundCompilation::VisitLdaLookupGlobalSlot(
2885 BytecodeArrayIterator* iterator) {
2886 ProcessLdaLookupGlobalSlot(iterator);
2887 }
2888
VisitLdaLookupGlobalSlotInsideTypeof(BytecodeArrayIterator * iterator)2889 void SerializerForBackgroundCompilation::VisitLdaLookupGlobalSlotInsideTypeof(
2890 BytecodeArrayIterator* iterator) {
2891 ProcessLdaLookupGlobalSlot(iterator);
2892 }
2893
VisitStaGlobal(BytecodeArrayIterator * iterator)2894 void SerializerForBackgroundCompilation::VisitStaGlobal(
2895 BytecodeArrayIterator* iterator) {
2896 NameRef(broker(),
2897 iterator->GetConstantForIndexOperand(0, broker()->isolate()));
2898 FeedbackSlot slot = iterator->GetSlotOperand(1);
2899 ProcessGlobalAccess(slot, false);
2900 }
2901
ProcessLdaLookupContextSlot(BytecodeArrayIterator * iterator)2902 void SerializerForBackgroundCompilation::ProcessLdaLookupContextSlot(
2903 BytecodeArrayIterator* iterator) {
2904 const int slot_index = iterator->GetIndexOperand(1);
2905 const int depth = iterator->GetUnsignedImmediateOperand(2);
2906 NameRef(broker(),
2907 iterator->GetConstantForIndexOperand(0, broker()->isolate()));
2908 ProcessCheckContextExtensions(depth);
2909 environment()->accumulator_hints() = Hints();
2910 ProcessContextAccess(environment()->current_context_hints(), slot_index,
2911 depth, kIgnoreSlot);
2912 }
2913
VisitLdaLookupContextSlot(BytecodeArrayIterator * iterator)2914 void SerializerForBackgroundCompilation::VisitLdaLookupContextSlot(
2915 BytecodeArrayIterator* iterator) {
2916 ProcessLdaLookupContextSlot(iterator);
2917 }
2918
VisitLdaLookupContextSlotInsideTypeof(BytecodeArrayIterator * iterator)2919 void SerializerForBackgroundCompilation::VisitLdaLookupContextSlotInsideTypeof(
2920 BytecodeArrayIterator* iterator) {
2921 ProcessLdaLookupContextSlot(iterator);
2922 }
2923
2924 // TODO(neis): Avoid duplicating this.
2925 namespace {
2926 template <class MapContainer>
GetRelevantReceiverMaps(Isolate * isolate,MapContainer const & maps)2927 MapHandles GetRelevantReceiverMaps(Isolate* isolate, MapContainer const& maps) {
2928 MapHandles result;
2929 for (Handle<Map> map : maps) {
2930 if (Map::TryUpdate(isolate, map).ToHandle(&map) &&
2931 !map->is_abandoned_prototype_map()) {
2932 DCHECK(!map->is_deprecated());
2933 result.push_back(map);
2934 }
2935 }
2936 return result;
2937 }
2938 } // namespace
2939
ProcessCompareOperation(FeedbackSlot slot)2940 void SerializerForBackgroundCompilation::ProcessCompareOperation(
2941 FeedbackSlot slot) {
2942 if (slot.IsInvalid() || feedback_vector().is_null()) return;
2943 FeedbackSource source(function().feedback_vector(), slot);
2944 ProcessedFeedback const& feedback =
2945 broker()->ProcessFeedbackForCompareOperation(source);
2946 if (BailoutOnUninitialized(feedback)) return;
2947 environment()->accumulator_hints() = Hints();
2948 }
2949
ProcessForIn(FeedbackSlot slot)2950 void SerializerForBackgroundCompilation::ProcessForIn(FeedbackSlot slot) {
2951 if (slot.IsInvalid() || feedback_vector().is_null()) return;
2952 FeedbackSource source(feedback_vector(), slot);
2953 ProcessedFeedback const& feedback = broker()->ProcessFeedbackForForIn(source);
2954 if (BailoutOnUninitialized(feedback)) return;
2955 environment()->accumulator_hints() = Hints();
2956 }
2957
ProcessUnaryOrBinaryOperation(FeedbackSlot slot,bool honor_bailout_on_uninitialized)2958 void SerializerForBackgroundCompilation::ProcessUnaryOrBinaryOperation(
2959 FeedbackSlot slot, bool honor_bailout_on_uninitialized) {
2960 if (slot.IsInvalid() || feedback_vector().is_null()) return;
2961 FeedbackSource source(feedback_vector(), slot);
2962 // Internally V8 uses binary op feedback also for unary ops.
2963 ProcessedFeedback const& feedback =
2964 broker()->ProcessFeedbackForBinaryOperation(source);
2965 if (honor_bailout_on_uninitialized && BailoutOnUninitialized(feedback)) {
2966 return;
2967 }
2968 environment()->accumulator_hints() = Hints();
2969 }
2970
2971 PropertyAccessInfo
ProcessMapForNamedPropertyAccess(Hints * receiver,base::Optional<MapRef> receiver_map,MapRef lookup_start_object_map,NameRef const & name,AccessMode access_mode,base::Optional<JSObjectRef> concrete_receiver,Hints * result_hints)2972 SerializerForBackgroundCompilation::ProcessMapForNamedPropertyAccess(
2973 Hints* receiver, base::Optional<MapRef> receiver_map,
2974 MapRef lookup_start_object_map, NameRef const& name, AccessMode access_mode,
2975 base::Optional<JSObjectRef> concrete_receiver, Hints* result_hints) {
2976 DCHECK_IMPLIES(concrete_receiver.has_value(), receiver_map.has_value());
2977
2978 // For JSNativeContextSpecialization::InferRootMap
2979 lookup_start_object_map.SerializeRootMap();
2980
2981 // For JSNativeContextSpecialization::ReduceNamedAccess.
2982 JSGlobalProxyRef global_proxy =
2983 broker()->target_native_context().global_proxy_object();
2984 JSGlobalObjectRef global_object =
2985 broker()->target_native_context().global_object();
2986 if (lookup_start_object_map.equals(global_proxy.map())) {
2987 base::Optional<PropertyCellRef> cell = global_object.GetPropertyCell(
2988 name, SerializationPolicy::kSerializeIfNeeded);
2989 if (access_mode == AccessMode::kLoad && cell.has_value()) {
2990 result_hints->AddConstant(cell->value().object(), zone(), broker());
2991 }
2992 }
2993
2994 PropertyAccessInfo access_info = broker()->GetPropertyAccessInfo(
2995 lookup_start_object_map, name, access_mode, dependencies(),
2996 SerializationPolicy::kSerializeIfNeeded);
2997
2998 // For JSNativeContextSpecialization::InlinePropertySetterCall
2999 // and InlinePropertyGetterCall.
3000 if (access_info.IsAccessorConstant() && !access_info.constant().is_null()) {
3001 if (access_info.constant()->IsJSFunction()) {
3002 JSFunctionRef function(broker(), access_info.constant());
3003
3004 if (receiver_map.has_value()) {
3005 // For JSCallReducer and JSInlining(Heuristic).
3006 HintsVector arguments(
3007 {Hints::SingleMap(receiver_map->object(), zone())}, zone());
3008 // In the case of a setter any added result hints won't make sense, but
3009 // they will be ignored anyways by Process*PropertyAccess due to the
3010 // access mode not being kLoad.
3011 ProcessCalleeForCallOrConstruct(
3012 function.object(), base::nullopt, arguments,
3013 SpeculationMode::kDisallowSpeculation,
3014 kMissingArgumentsAreUndefined, result_hints);
3015
3016 // For JSCallReducer::ReduceCallApiFunction.
3017 Handle<SharedFunctionInfo> sfi = function.shared().object();
3018 if (sfi->IsApiFunction()) {
3019 FunctionTemplateInfoRef fti_ref(
3020 broker(), handle(sfi->get_api_func_data(), broker()->isolate()));
3021 if (fti_ref.has_call_code()) {
3022 fti_ref.SerializeCallCode();
3023 ProcessReceiverMapForApiCall(fti_ref, receiver_map->object());
3024 }
3025 }
3026 }
3027 } else if (access_info.constant()->IsJSBoundFunction()) {
3028 JSBoundFunctionRef function(broker(), access_info.constant());
3029
3030 // For JSCallReducer::ReduceJSCall.
3031 function.Serialize();
3032 } else {
3033 FunctionTemplateInfoRef fti(broker(), access_info.constant());
3034 if (fti.has_call_code()) fti.SerializeCallCode();
3035 }
3036 } else if (access_info.IsModuleExport()) {
3037 // For JSNativeContextSpecialization::BuildPropertyLoad
3038 DCHECK(!access_info.constant().is_null());
3039 CellRef(broker(), access_info.constant());
3040 }
3041
3042 switch (access_mode) {
3043 case AccessMode::kLoad:
3044 // For PropertyAccessBuilder::TryBuildLoadConstantDataField
3045 if (access_info.IsDataConstant()) {
3046 base::Optional<JSObjectRef> holder;
3047 Handle<JSObject> prototype;
3048 if (access_info.holder().ToHandle(&prototype)) {
3049 holder = JSObjectRef(broker(), prototype);
3050 } else {
3051 CHECK_IMPLIES(concrete_receiver.has_value(),
3052 concrete_receiver->map().equals(*receiver_map));
3053 holder = concrete_receiver;
3054 }
3055
3056 if (holder.has_value()) {
3057 base::Optional<ObjectRef> constant(holder->GetOwnDataProperty(
3058 access_info.field_representation(), access_info.field_index(),
3059 SerializationPolicy::kSerializeIfNeeded));
3060 if (constant.has_value()) {
3061 result_hints->AddConstant(constant->object(), zone(), broker());
3062 }
3063 }
3064 }
3065 break;
3066 case AccessMode::kStore:
3067 case AccessMode::kStoreInLiteral:
3068 // For MapInference (StoreField case).
3069 if (access_info.IsDataField() || access_info.IsDataConstant()) {
3070 Handle<Map> transition_map;
3071 if (access_info.transition_map().ToHandle(&transition_map)) {
3072 MapRef map_ref(broker(), transition_map);
3073 TRACE_BROKER(broker(), "Propagating transition map "
3074 << map_ref << " to receiver hints.");
3075 receiver->AddMap(transition_map, zone(), broker_, false);
3076 }
3077 }
3078 break;
3079 case AccessMode::kHas:
3080 break;
3081 }
3082
3083 return access_info;
3084 }
3085
ProcessMinimorphicPropertyAccess(MinimorphicLoadPropertyAccessFeedback const & feedback,FeedbackSource const & source)3086 void SerializerForBackgroundCompilation::ProcessMinimorphicPropertyAccess(
3087 MinimorphicLoadPropertyAccessFeedback const& feedback,
3088 FeedbackSource const& source) {
3089 broker()->GetPropertyAccessInfo(feedback, source,
3090 SerializationPolicy::kSerializeIfNeeded);
3091 }
3092
VisitLdaKeyedProperty(BytecodeArrayIterator * iterator)3093 void SerializerForBackgroundCompilation::VisitLdaKeyedProperty(
3094 BytecodeArrayIterator* iterator) {
3095 Hints const& key = environment()->accumulator_hints();
3096 Hints* receiver = ®ister_hints(iterator->GetRegisterOperand(0));
3097 FeedbackSlot slot = iterator->GetSlotOperand(1);
3098 ProcessKeyedPropertyAccess(receiver, key, slot, AccessMode::kLoad, true);
3099 }
3100
ProcessKeyedPropertyAccess(Hints * receiver,Hints const & key,FeedbackSlot slot,AccessMode access_mode,bool honor_bailout_on_uninitialized)3101 void SerializerForBackgroundCompilation::ProcessKeyedPropertyAccess(
3102 Hints* receiver, Hints const& key, FeedbackSlot slot,
3103 AccessMode access_mode, bool honor_bailout_on_uninitialized) {
3104 if (slot.IsInvalid() || feedback_vector().is_null()) return;
3105 FeedbackSource source(feedback_vector(), slot);
3106 ProcessedFeedback const& feedback =
3107 broker()->ProcessFeedbackForPropertyAccess(source, access_mode,
3108 base::nullopt);
3109 if (honor_bailout_on_uninitialized && BailoutOnUninitialized(feedback)) {
3110 return;
3111 }
3112
3113 Hints new_accumulator_hints;
3114 switch (feedback.kind()) {
3115 case ProcessedFeedback::kElementAccess:
3116 ProcessElementAccess(*receiver, key, feedback.AsElementAccess(),
3117 access_mode);
3118 break;
3119 case ProcessedFeedback::kNamedAccess:
3120 ProcessNamedAccess(receiver, feedback.AsNamedAccess(), access_mode,
3121 &new_accumulator_hints);
3122 break;
3123 case ProcessedFeedback::kInsufficient:
3124 break;
3125 default:
3126 UNREACHABLE();
3127 }
3128
3129 if (access_mode == AccessMode::kLoad) {
3130 environment()->accumulator_hints() = new_accumulator_hints;
3131 }
3132 }
3133
ProcessNamedPropertyAccess(Hints * receiver,NameRef const & name,FeedbackSlot slot,AccessMode access_mode)3134 void SerializerForBackgroundCompilation::ProcessNamedPropertyAccess(
3135 Hints* receiver, NameRef const& name, FeedbackSlot slot,
3136 AccessMode access_mode) {
3137 if (slot.IsInvalid() || feedback_vector().is_null()) return;
3138 FeedbackSource source(feedback_vector(), slot);
3139 ProcessedFeedback const& feedback =
3140 broker()->ProcessFeedbackForPropertyAccess(source, access_mode, name);
3141 if (BailoutOnUninitialized(feedback)) return;
3142
3143 Hints new_accumulator_hints;
3144 switch (feedback.kind()) {
3145 case ProcessedFeedback::kNamedAccess:
3146 DCHECK(name.equals(feedback.AsNamedAccess().name()));
3147 ProcessNamedAccess(receiver, feedback.AsNamedAccess(), access_mode,
3148 &new_accumulator_hints);
3149 break;
3150 case ProcessedFeedback::kMinimorphicPropertyAccess:
3151 DCHECK(name.equals(feedback.AsMinimorphicPropertyAccess().name()));
3152 ProcessMinimorphicPropertyAccess(feedback.AsMinimorphicPropertyAccess(),
3153 source);
3154 break;
3155 case ProcessedFeedback::kInsufficient:
3156 break;
3157 default:
3158 UNREACHABLE();
3159 }
3160
3161 if (access_mode == AccessMode::kLoad) {
3162 environment()->accumulator_hints() = new_accumulator_hints;
3163 }
3164 }
3165
ProcessNamedSuperPropertyAccess(Hints * receiver,NameRef const & name,FeedbackSlot slot,AccessMode access_mode)3166 void SerializerForBackgroundCompilation::ProcessNamedSuperPropertyAccess(
3167 Hints* receiver, NameRef const& name, FeedbackSlot slot,
3168 AccessMode access_mode) {
3169 if (slot.IsInvalid() || feedback_vector().is_null()) return;
3170 FeedbackSource source(feedback_vector(), slot);
3171 ProcessedFeedback const& feedback =
3172 broker()->ProcessFeedbackForPropertyAccess(source, access_mode, name);
3173 if (BailoutOnUninitialized(feedback)) return;
3174
3175 Hints new_accumulator_hints;
3176 switch (feedback.kind()) {
3177 case ProcessedFeedback::kNamedAccess:
3178 DCHECK(name.equals(feedback.AsNamedAccess().name()));
3179 ProcessNamedSuperAccess(receiver, feedback.AsNamedAccess(), access_mode,
3180 &new_accumulator_hints);
3181 break;
3182 case ProcessedFeedback::kMinimorphicPropertyAccess:
3183 DCHECK(name.equals(feedback.AsMinimorphicPropertyAccess().name()));
3184 ProcessMinimorphicPropertyAccess(feedback.AsMinimorphicPropertyAccess(),
3185 source);
3186 break;
3187 case ProcessedFeedback::kInsufficient:
3188 break;
3189 default:
3190 UNREACHABLE();
3191 }
3192
3193 if (access_mode == AccessMode::kLoad) {
3194 environment()->accumulator_hints() = new_accumulator_hints;
3195 }
3196 }
3197
ProcessNamedAccess(Hints * receiver,NamedAccessFeedback const & feedback,AccessMode access_mode,Hints * result_hints)3198 void SerializerForBackgroundCompilation::ProcessNamedAccess(
3199 Hints* receiver, NamedAccessFeedback const& feedback,
3200 AccessMode access_mode, Hints* result_hints) {
3201 for (Handle<Map> map : feedback.maps()) {
3202 MapRef map_ref(broker(), map);
3203 TRACE_BROKER(broker(), "Propagating feedback map "
3204 << map_ref << " to receiver hints.");
3205 receiver->AddMap(map, zone(), broker_, false);
3206 }
3207
3208 for (Handle<Map> map :
3209 GetRelevantReceiverMaps(broker()->isolate(), receiver->maps())) {
3210 MapRef map_ref(broker(), map);
3211 ProcessMapForNamedPropertyAccess(receiver, map_ref, map_ref,
3212 feedback.name(), access_mode,
3213 base::nullopt, result_hints);
3214 }
3215
3216 for (Handle<Object> hint : receiver->constants()) {
3217 ObjectRef object(broker(), hint);
3218 if (access_mode == AccessMode::kLoad && object.IsJSObject()) {
3219 MapRef map_ref = object.AsJSObject().map();
3220 ProcessMapForNamedPropertyAccess(receiver, map_ref, map_ref,
3221 feedback.name(), access_mode,
3222 object.AsJSObject(), result_hints);
3223 }
3224 // For JSNativeContextSpecialization::ReduceJSLoadNamed.
3225 if (access_mode == AccessMode::kLoad && object.IsJSFunction() &&
3226 feedback.name().equals(ObjectRef(
3227 broker(), broker()->isolate()->factory()->prototype_string()))) {
3228 JSFunctionRef function = object.AsJSFunction();
3229 function.Serialize();
3230 if (result_hints != nullptr && function.has_prototype()) {
3231 result_hints->AddConstant(function.prototype().object(), zone(),
3232 broker());
3233 }
3234 }
3235 // TODO(neis): Also record accumulator hint for string.length and maybe
3236 // more?
3237 }
3238 }
3239
ProcessNamedSuperAccess(Hints * receiver,NamedAccessFeedback const & feedback,AccessMode access_mode,Hints * result_hints)3240 void SerializerForBackgroundCompilation::ProcessNamedSuperAccess(
3241 Hints* receiver, NamedAccessFeedback const& feedback,
3242 AccessMode access_mode, Hints* result_hints) {
3243 MapHandles receiver_maps =
3244 GetRelevantReceiverMaps(broker()->isolate(), receiver->maps());
3245 for (Handle<Map> receiver_map : receiver_maps) {
3246 MapRef receiver_map_ref(broker(), receiver_map);
3247 for (Handle<Map> feedback_map : feedback.maps()) {
3248 MapRef feedback_map_ref(broker(), feedback_map);
3249 ProcessMapForNamedPropertyAccess(
3250 receiver, receiver_map_ref, feedback_map_ref, feedback.name(),
3251 access_mode, base::nullopt, result_hints);
3252 }
3253 }
3254 if (receiver_maps.empty()) {
3255 for (Handle<Map> feedback_map : feedback.maps()) {
3256 MapRef feedback_map_ref(broker(), feedback_map);
3257 ProcessMapForNamedPropertyAccess(
3258 receiver, base::nullopt, feedback_map_ref, feedback.name(),
3259 access_mode, base::nullopt, result_hints);
3260 }
3261 }
3262 }
3263
ProcessElementAccess(Hints const & receiver,Hints const & key,ElementAccessFeedback const & feedback,AccessMode access_mode)3264 void SerializerForBackgroundCompilation::ProcessElementAccess(
3265 Hints const& receiver, Hints const& key,
3266 ElementAccessFeedback const& feedback, AccessMode access_mode) {
3267 for (auto const& group : feedback.transition_groups()) {
3268 for (Handle<Map> map_handle : group) {
3269 MapRef map(broker(), map_handle);
3270 switch (access_mode) {
3271 case AccessMode::kHas:
3272 case AccessMode::kLoad:
3273 map.SerializeForElementLoad();
3274 break;
3275 case AccessMode::kStore:
3276 map.SerializeForElementStore();
3277 break;
3278 case AccessMode::kStoreInLiteral:
3279 // This operation is fairly local and simple, nothing to serialize.
3280 break;
3281 }
3282 }
3283 }
3284
3285 for (Handle<Object> hint : receiver.constants()) {
3286 ObjectRef receiver_ref(broker(), hint);
3287
3288 // For JSNativeContextSpecialization::InferRootMap
3289 if (receiver_ref.IsHeapObject()) {
3290 receiver_ref.AsHeapObject().map().SerializeRootMap();
3291 }
3292
3293 // For JSNativeContextSpecialization::ReduceElementAccess.
3294 if (receiver_ref.IsJSTypedArray()) {
3295 receiver_ref.AsJSTypedArray().Serialize();
3296 }
3297
3298 // For JSNativeContextSpecialization::ReduceElementLoadFromHeapConstant.
3299 if (access_mode == AccessMode::kLoad || access_mode == AccessMode::kHas) {
3300 for (Handle<Object> hint : key.constants()) {
3301 ObjectRef key_ref(broker(), hint);
3302 // TODO(neis): Do this for integer-HeapNumbers too?
3303 if (key_ref.IsSmi() && key_ref.AsSmi() >= 0) {
3304 base::Optional<ObjectRef> element =
3305 receiver_ref.GetOwnConstantElement(
3306 key_ref.AsSmi(), SerializationPolicy::kSerializeIfNeeded);
3307 if (!element.has_value() && receiver_ref.IsJSArray()) {
3308 // We didn't find a constant element, but if the receiver is a
3309 // cow-array we can exploit the fact that any future write to the
3310 // element will replace the whole elements storage.
3311 receiver_ref.AsJSArray().GetOwnCowElement(
3312 key_ref.AsSmi(), SerializationPolicy::kSerializeIfNeeded);
3313 }
3314 }
3315 }
3316 }
3317 }
3318
3319 // For JSNativeContextSpecialization::InferRootMap
3320 for (Handle<Map> map : receiver.maps()) {
3321 MapRef map_ref(broker(), map);
3322 map_ref.SerializeRootMap();
3323 }
3324 }
3325
VisitLdaNamedProperty(BytecodeArrayIterator * iterator)3326 void SerializerForBackgroundCompilation::VisitLdaNamedProperty(
3327 BytecodeArrayIterator* iterator) {
3328 Hints* receiver = ®ister_hints(iterator->GetRegisterOperand(0));
3329 NameRef name(broker(),
3330 iterator->GetConstantForIndexOperand(1, broker()->isolate()));
3331 FeedbackSlot slot = iterator->GetSlotOperand(2);
3332 ProcessNamedPropertyAccess(receiver, name, slot, AccessMode::kLoad);
3333 }
3334
VisitLdaNamedPropertyFromSuper(BytecodeArrayIterator * iterator)3335 void SerializerForBackgroundCompilation::VisitLdaNamedPropertyFromSuper(
3336 BytecodeArrayIterator* iterator) {
3337 Hints* receiver = ®ister_hints(iterator->GetRegisterOperand(0));
3338 NameRef name(broker(),
3339 iterator->GetConstantForIndexOperand(1, broker()->isolate()));
3340 FeedbackSlot slot = iterator->GetSlotOperand(2);
3341 ProcessNamedSuperPropertyAccess(receiver, name, slot, AccessMode::kLoad);
3342 }
3343
3344 // TODO(neis): Do feedback-independent serialization also for *NoFeedback
3345 // bytecodes.
VisitLdaNamedPropertyNoFeedback(BytecodeArrayIterator * iterator)3346 void SerializerForBackgroundCompilation::VisitLdaNamedPropertyNoFeedback(
3347 BytecodeArrayIterator* iterator) {
3348 NameRef(broker(),
3349 iterator->GetConstantForIndexOperand(1, broker()->isolate()));
3350 }
3351
VisitStaNamedProperty(BytecodeArrayIterator * iterator)3352 void SerializerForBackgroundCompilation::VisitStaNamedProperty(
3353 BytecodeArrayIterator* iterator) {
3354 Hints* receiver = ®ister_hints(iterator->GetRegisterOperand(0));
3355 NameRef name(broker(),
3356 iterator->GetConstantForIndexOperand(1, broker()->isolate()));
3357 FeedbackSlot slot = iterator->GetSlotOperand(2);
3358 ProcessNamedPropertyAccess(receiver, name, slot, AccessMode::kStore);
3359 }
3360
VisitStaNamedPropertyNoFeedback(BytecodeArrayIterator * iterator)3361 void SerializerForBackgroundCompilation::VisitStaNamedPropertyNoFeedback(
3362 BytecodeArrayIterator* iterator) {
3363 NameRef(broker(),
3364 iterator->GetConstantForIndexOperand(1, broker()->isolate()));
3365 }
3366
VisitStaNamedOwnProperty(BytecodeArrayIterator * iterator)3367 void SerializerForBackgroundCompilation::VisitStaNamedOwnProperty(
3368 BytecodeArrayIterator* iterator) {
3369 Hints* receiver = ®ister_hints(iterator->GetRegisterOperand(0));
3370 NameRef name(broker(),
3371 iterator->GetConstantForIndexOperand(1, broker()->isolate()));
3372 FeedbackSlot slot = iterator->GetSlotOperand(2);
3373 ProcessNamedPropertyAccess(receiver, name, slot, AccessMode::kStoreInLiteral);
3374 }
3375
VisitTestIn(BytecodeArrayIterator * iterator)3376 void SerializerForBackgroundCompilation::VisitTestIn(
3377 BytecodeArrayIterator* iterator) {
3378 Hints* receiver = &environment()->accumulator_hints();
3379 Hints const& key = register_hints(iterator->GetRegisterOperand(0));
3380 FeedbackSlot slot = iterator->GetSlotOperand(1);
3381 ProcessKeyedPropertyAccess(receiver, key, slot, AccessMode::kHas, false);
3382 }
3383
3384 // For JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance.
ProcessConstantForOrdinaryHasInstance(HeapObjectRef const & constructor,bool * walk_prototypes)3385 void SerializerForBackgroundCompilation::ProcessConstantForOrdinaryHasInstance(
3386 HeapObjectRef const& constructor, bool* walk_prototypes) {
3387 if (constructor.IsJSBoundFunction()) {
3388 constructor.AsJSBoundFunction().Serialize();
3389 ProcessConstantForInstanceOf(
3390 constructor.AsJSBoundFunction().bound_target_function(),
3391 walk_prototypes);
3392 } else if (constructor.IsJSFunction()) {
3393 constructor.AsJSFunction().Serialize();
3394 *walk_prototypes =
3395 *walk_prototypes ||
3396 (constructor.map().has_prototype_slot() &&
3397 constructor.AsJSFunction().has_prototype() &&
3398 !constructor.AsJSFunction().PrototypeRequiresRuntimeLookup());
3399 }
3400 }
3401
ProcessConstantForInstanceOf(ObjectRef const & constructor,bool * walk_prototypes)3402 void SerializerForBackgroundCompilation::ProcessConstantForInstanceOf(
3403 ObjectRef const& constructor, bool* walk_prototypes) {
3404 if (!constructor.IsHeapObject()) return;
3405 HeapObjectRef constructor_heap_object = constructor.AsHeapObject();
3406
3407 PropertyAccessInfo access_info = broker()->GetPropertyAccessInfo(
3408 constructor_heap_object.map(),
3409 NameRef(broker(), broker()->isolate()->factory()->has_instance_symbol()),
3410 AccessMode::kLoad, dependencies(),
3411 SerializationPolicy::kSerializeIfNeeded);
3412
3413 if (access_info.IsNotFound()) {
3414 ProcessConstantForOrdinaryHasInstance(constructor_heap_object,
3415 walk_prototypes);
3416 } else if (access_info.IsDataConstant()) {
3417 Handle<JSObject> holder;
3418 bool found_on_proto = access_info.holder().ToHandle(&holder);
3419 JSObjectRef holder_ref = found_on_proto ? JSObjectRef(broker(), holder)
3420 : constructor.AsJSObject();
3421 base::Optional<ObjectRef> constant = holder_ref.GetOwnDataProperty(
3422 access_info.field_representation(), access_info.field_index(),
3423 SerializationPolicy::kSerializeIfNeeded);
3424 CHECK(constant.has_value());
3425 if (constant->IsJSFunction()) {
3426 JSFunctionRef function = constant->AsJSFunction();
3427 function.Serialize();
3428 if (function.shared().HasBuiltinId() &&
3429 function.shared().builtin_id() ==
3430 Builtins::kFunctionPrototypeHasInstance) {
3431 // For JSCallReducer::ReduceFunctionPrototypeHasInstance.
3432 ProcessConstantForOrdinaryHasInstance(constructor_heap_object,
3433 walk_prototypes);
3434 }
3435 }
3436 }
3437 }
3438
VisitTestInstanceOf(BytecodeArrayIterator * iterator)3439 void SerializerForBackgroundCompilation::VisitTestInstanceOf(
3440 BytecodeArrayIterator* iterator) {
3441 Hints const& lhs = register_hints(iterator->GetRegisterOperand(0));
3442 Hints rhs = environment()->accumulator_hints();
3443 FeedbackSlot slot = iterator->GetSlotOperand(1);
3444
3445 if (slot.IsInvalid() || feedback_vector().is_null()) return;
3446 FeedbackSource source(feedback_vector(), slot);
3447 ProcessedFeedback const& feedback =
3448 broker()->ProcessFeedbackForInstanceOf(source);
3449
3450 // Incorporate feedback (about rhs) into hints copy to simplify processing.
3451 // TODO(neis): Propagate into original hints?
3452 if (!feedback.IsInsufficient()) {
3453 InstanceOfFeedback const& rhs_feedback = feedback.AsInstanceOf();
3454 if (rhs_feedback.value().has_value()) {
3455 rhs = rhs.Copy(zone());
3456 Handle<JSObject> constructor = rhs_feedback.value()->object();
3457 rhs.AddConstant(constructor, zone(), broker());
3458 }
3459 }
3460
3461 bool walk_prototypes = false;
3462 for (Handle<Object> constant : rhs.constants()) {
3463 ProcessConstantForInstanceOf(ObjectRef(broker(), constant),
3464 &walk_prototypes);
3465 }
3466 if (walk_prototypes) ProcessHintsForHasInPrototypeChain(lhs);
3467
3468 environment()->accumulator_hints() = Hints();
3469 }
3470
VisitToNumeric(BytecodeArrayIterator * iterator)3471 void SerializerForBackgroundCompilation::VisitToNumeric(
3472 BytecodeArrayIterator* iterator) {
3473 FeedbackSlot slot = iterator->GetSlotOperand(0);
3474 ProcessUnaryOrBinaryOperation(slot, false);
3475 }
3476
VisitToNumber(BytecodeArrayIterator * iterator)3477 void SerializerForBackgroundCompilation::VisitToNumber(
3478 BytecodeArrayIterator* iterator) {
3479 FeedbackSlot slot = iterator->GetSlotOperand(0);
3480 ProcessUnaryOrBinaryOperation(slot, false);
3481 }
3482
VisitThrowReferenceErrorIfHole(BytecodeArrayIterator * iterator)3483 void SerializerForBackgroundCompilation::VisitThrowReferenceErrorIfHole(
3484 BytecodeArrayIterator* iterator) {
3485 ObjectRef(broker(),
3486 iterator->GetConstantForIndexOperand(0, broker()->isolate()));
3487 }
3488
VisitStaKeyedProperty(BytecodeArrayIterator * iterator)3489 void SerializerForBackgroundCompilation::VisitStaKeyedProperty(
3490 BytecodeArrayIterator* iterator) {
3491 Hints* receiver = ®ister_hints(iterator->GetRegisterOperand(0));
3492 Hints const& key = register_hints(iterator->GetRegisterOperand(1));
3493 FeedbackSlot slot = iterator->GetSlotOperand(2);
3494 ProcessKeyedPropertyAccess(receiver, key, slot, AccessMode::kStore, true);
3495 }
3496
VisitStaInArrayLiteral(BytecodeArrayIterator * iterator)3497 void SerializerForBackgroundCompilation::VisitStaInArrayLiteral(
3498 BytecodeArrayIterator* iterator) {
3499 Hints* receiver = ®ister_hints(iterator->GetRegisterOperand(0));
3500 Hints const& key = register_hints(iterator->GetRegisterOperand(1));
3501 FeedbackSlot slot = iterator->GetSlotOperand(2);
3502 ProcessKeyedPropertyAccess(receiver, key, slot, AccessMode::kStoreInLiteral,
3503 true);
3504 }
3505
VisitStaDataPropertyInLiteral(BytecodeArrayIterator * iterator)3506 void SerializerForBackgroundCompilation::VisitStaDataPropertyInLiteral(
3507 BytecodeArrayIterator* iterator) {
3508 Hints* receiver = ®ister_hints(iterator->GetRegisterOperand(0));
3509 Hints const& key = register_hints(iterator->GetRegisterOperand(1));
3510 FeedbackSlot slot = iterator->GetSlotOperand(3);
3511 ProcessKeyedPropertyAccess(receiver, key, slot, AccessMode::kStoreInLiteral,
3512 false);
3513 }
3514
3515 #define DEFINE_CLEAR_ACCUMULATOR(name, ...) \
3516 void SerializerForBackgroundCompilation::Visit##name( \
3517 BytecodeArrayIterator* iterator) { \
3518 environment()->accumulator_hints() = Hints(); \
3519 }
3520 CLEAR_ACCUMULATOR_LIST(DEFINE_CLEAR_ACCUMULATOR)
3521 #undef DEFINE_CLEAR_ACCUMULATOR
3522
3523 #define DEFINE_CONDITIONAL_JUMP(name, ...) \
3524 void SerializerForBackgroundCompilation::Visit##name( \
3525 BytecodeArrayIterator* iterator) { \
3526 ProcessJump(iterator); \
3527 }
3528 CONDITIONAL_JUMPS_LIST(DEFINE_CONDITIONAL_JUMP)
3529 #undef DEFINE_CONDITIONAL_JUMP
3530
3531 #define DEFINE_UNCONDITIONAL_JUMP(name, ...) \
3532 void SerializerForBackgroundCompilation::Visit##name( \
3533 BytecodeArrayIterator* iterator) { \
3534 ProcessJump(iterator); \
3535 environment()->Kill(); \
3536 }
3537 UNCONDITIONAL_JUMPS_LIST(DEFINE_UNCONDITIONAL_JUMP)
3538 #undef DEFINE_UNCONDITIONAL_JUMP
3539
3540 #define DEFINE_IGNORE(name, ...) \
3541 void SerializerForBackgroundCompilation::Visit##name( \
3542 BytecodeArrayIterator* iterator) {}
3543 IGNORED_BYTECODE_LIST(DEFINE_IGNORE)
3544 #undef DEFINE_IGNORE
3545
3546 #define DEFINE_UNREACHABLE(name, ...) \
3547 void SerializerForBackgroundCompilation::Visit##name( \
3548 BytecodeArrayIterator* iterator) { \
3549 UNREACHABLE(); \
3550 }
3551 UNREACHABLE_BYTECODE_LIST(DEFINE_UNREACHABLE)
3552 #undef DEFINE_UNREACHABLE
3553
3554 #define DEFINE_KILL(name, ...) \
3555 void SerializerForBackgroundCompilation::Visit##name( \
3556 BytecodeArrayIterator* iterator) { \
3557 environment()->Kill(); \
3558 }
3559 KILL_ENVIRONMENT_LIST(DEFINE_KILL)
3560 #undef DEFINE_KILL
3561
3562 #define DEFINE_BINARY_OP(name, ...) \
3563 void SerializerForBackgroundCompilation::Visit##name( \
3564 BytecodeArrayIterator* iterator) { \
3565 FeedbackSlot slot = iterator->GetSlotOperand(1); \
3566 ProcessUnaryOrBinaryOperation(slot, true); \
3567 }
3568 BINARY_OP_LIST(DEFINE_BINARY_OP)
3569 #undef DEFINE_BINARY_OP
3570
3571 #define DEFINE_COMPARE_OP(name, ...) \
3572 void SerializerForBackgroundCompilation::Visit##name( \
3573 BytecodeArrayIterator* iterator) { \
3574 FeedbackSlot slot = iterator->GetSlotOperand(1); \
3575 ProcessCompareOperation(slot); \
3576 }
3577 COMPARE_OP_LIST(DEFINE_COMPARE_OP)
3578 #undef DEFINE_COMPARE_OP
3579
3580 #define DEFINE_UNARY_OP(name, ...) \
3581 void SerializerForBackgroundCompilation::Visit##name( \
3582 BytecodeArrayIterator* iterator) { \
3583 FeedbackSlot slot = iterator->GetSlotOperand(0); \
3584 ProcessUnaryOrBinaryOperation(slot, true); \
3585 }
3586 UNARY_OP_LIST(DEFINE_UNARY_OP)
3587 #undef DEFINE_UNARY_OP
3588
3589 #undef BINARY_OP_LIST
3590 #undef CLEAR_ACCUMULATOR_LIST
3591 #undef COMPARE_OP_LIST
3592 #undef CONDITIONAL_JUMPS_LIST
3593 #undef IGNORED_BYTECODE_LIST
3594 #undef KILL_ENVIRONMENT_LIST
3595 #undef SUPPORTED_BYTECODE_LIST
3596 #undef UNARY_OP_LIST
3597 #undef UNCONDITIONAL_JUMPS_LIST
3598 #undef UNREACHABLE_BYTECODE_LIST
3599
3600 } // namespace compiler
3601 } // namespace internal
3602 } // namespace v8
3603