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