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 = ®ister_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 ®ister_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 ®ister_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(®ister_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, ¶meters, 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 = ®ister_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 = ®ister_hints(iterator->GetRegisterOperand(1));
1867 Hints* arg1 = ®ister_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 = ®ister_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 = ®ister_hints(iterator->GetRegisterOperand(1));
1923 Hints* arg0 = ®ister_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 = ®ister_hints(iterator->GetRegisterOperand(1));
1936 Hints* arg0 = ®ister_hints(iterator->GetRegisterOperand(2));
1937 Hints* arg1 = ®ister_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 = ®ister_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 = ®ister_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 = ®ister_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 = ®ister_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 = ®ister_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 = ®ister_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 = ®ister_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