v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
bytecode-array-builder.cc
Go to the documentation of this file.
1// Copyright 2015 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
6
7#include <optional>
8
9#include "src/ast/scopes.h"
10#include "src/ast/variables.h"
12#include "src/common/globals.h"
21#include "src/objects/smi.h"
22
23namespace v8 {
24namespace internal {
25namespace interpreter {
26
28 : public NON_EXPORTED_BASE(BytecodeRegisterOptimizer::BytecodeWriter),
29 public NON_EXPORTED_BASE(ZoneObject) {
30 public:
32 : builder_(builder) {}
33 ~RegisterTransferWriter() override = default;
34
35 void EmitLdar(Register input) override { builder_->OutputLdarRaw(input); }
36
37 void EmitStar(Register output) override { builder_->OutputStarRaw(output); }
38
39 void EmitMov(Register input, Register output) override {
40 builder_->OutputMovRaw(input, output);
41 }
42
43 private:
45};
46
48 Zone* zone, int parameter_count, int locals_count,
49 FeedbackVectorSpec* feedback_vector_spec,
51 : zone_(zone),
52 feedback_vector_spec_(feedback_vector_spec),
53 bytecode_generated_(false),
54 constant_array_builder_(zone),
55 handler_table_builder_(zone),
56 parameter_count_(parameter_count),
57 max_arguments_(0),
58 local_register_count_(locals_count),
59 register_allocator_(fixed_register_count()),
60 bytecode_array_writer_(zone, &constant_array_builder_,
61 source_position_mode),
62 register_optimizer_(nullptr) {
64 DCHECK_LE(parameter_count_, std::numeric_limits<uint16_t>::max());
66
67 if (v8_flags.ignition_reo) {
71 }
72}
73
74Register BytecodeArrayBuilder::Parameter(int parameter_index) const {
75 DCHECK_GE(parameter_index, 0);
76 // The parameter indices are shifted by 1 (receiver is the
77 // first entry).
78 return Register::FromParameterIndex(parameter_index + 1);
79}
80
84
86 DCHECK_LT(index, locals_count());
87 return Register(index);
88}
89
90template <typename IsolateT>
95
96 int register_count = total_register_count();
97
100 register_count = register_optimizer_->maxiumum_register_index() + 1;
101 }
102
103 DirectHandle<TrustedByteArray> handler_table =
105 return bytecode_array_writer_.ToBytecodeArray(isolate, register_count,
107 max_arguments(), handler_table);
108}
109
112 Isolate* isolate);
115 LocalIsolate* isolate);
116
117#ifdef DEBUG
118int BytecodeArrayBuilder::CheckBytecodeMatches(Tagged<BytecodeArray> bytecode) {
120 return bytecode_array_writer_.CheckBytecodeMatches(bytecode);
121}
122#endif
123
124template <typename IsolateT>
126 IsolateT* isolate) {
128
130}
131
133 DirectHandle<TrustedByteArray> BytecodeArrayBuilder::ToSourcePositionTable(
134 Isolate* isolate);
136 DirectHandle<TrustedByteArray> BytecodeArrayBuilder::ToSourcePositionTable(
137 LocalIsolate* isolate);
138
140 Bytecode bytecode) {
141 BytecodeSourceInfo source_position;
143 // Statement positions need to be emitted immediately. Expression
144 // positions can be pushed back until a bytecode is found that can
145 // throw (if expression position filtering is turned on). We only
146 // invalidate the existing source position information if it is used.
148 !v8_flags.ignition_filter_expression_positions ||
150 source_position = latest_source_info_;
152 }
153 }
154 return source_position;
155}
156
158 BytecodeSourceInfo source_info) {
159 if (!source_info.is_valid()) return;
160 deferred_source_info_ = source_info;
161}
162
164 if (!deferred_source_info_.is_valid()) return;
165 if (!node->source_info().is_valid()) {
166 node->set_source_info(deferred_source_info_);
167 } else if (deferred_source_info_.is_statement() &&
168 node->source_info().is_expression()) {
169 BytecodeSourceInfo source_position = node->source_info();
170 source_position.MakeStatementPosition(source_position.source_position());
171 node->set_source_info(source_position);
172 }
174}
175
180
185
191
197
199 uint32_t operand = static_cast<uint32_t>(reg.ToOperand());
200 BytecodeNode node(BytecodeNode::Ldar(BytecodeSourceInfo(), operand));
201 Write(&node);
202}
203
205 uint32_t operand = static_cast<uint32_t>(reg.ToOperand());
206 std::optional<Bytecode> short_code = reg.TryToShortStar();
207 BytecodeNode node = short_code
208 ? BytecodeNode(*short_code)
209 : BytecodeNode::Star(BytecodeSourceInfo(), operand);
210 Write(&node);
211}
212
214 uint32_t operand0 = static_cast<uint32_t>(src.ToOperand());
215 uint32_t operand1 = static_cast<uint32_t>(dest.ToOperand());
217 BytecodeNode::Mov(BytecodeSourceInfo(), operand0, operand1));
218 Write(&node);
219}
220
221namespace {
222
223template <OperandTypeInfo type_info>
224class UnsignedOperandHelper {
225 public:
226 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder,
227 size_t value) {
228 DCHECK(IsValid(value));
229 return static_cast<uint32_t>(value);
230 }
231
232 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder, int value) {
233 DCHECK_GE(value, 0);
234 return Convert(builder, static_cast<size_t>(value));
235 }
236
237 private:
238 static bool IsValid(size_t value) {
239 switch (type_info) {
240 case OperandTypeInfo::kFixedUnsignedByte:
241 return value <= kMaxUInt8;
242 case OperandTypeInfo::kFixedUnsignedShort:
243 return value <= kMaxUInt16;
244 case OperandTypeInfo::kScalableUnsignedByte:
245 return value <= kMaxUInt32;
246 default:
247 UNREACHABLE();
248 }
249 }
250};
251
252template <OperandType>
253class OperandHelper {};
254
255#define DEFINE_UNSIGNED_OPERAND_HELPER(Name, Type) \
256 template <> \
257 class OperandHelper<OperandType::k##Name> \
258 : public UnsignedOperandHelper<Type> {};
261#undef DEFINE_UNSIGNED_OPERAND_HELPER
262
263template <>
264class OperandHelper<OperandType::kImm> {
265 public:
266 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder, int value) {
267 return static_cast<uint32_t>(value);
268 }
269};
270
271template <>
272class OperandHelper<OperandType::kReg> {
273 public:
274 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder,
275 Register reg) {
276 return builder->GetInputRegisterOperand(reg);
277 }
278};
279
280template <>
281class OperandHelper<OperandType::kRegList> {
282 public:
283 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder,
284 RegisterList reg_list) {
285 return builder->GetInputRegisterListOperand(reg_list);
286 }
287};
288
289template <>
290class OperandHelper<OperandType::kRegPair> {
291 public:
292 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder,
293 RegisterList reg_list) {
294 DCHECK_EQ(reg_list.register_count(), 2);
295 return builder->GetInputRegisterListOperand(reg_list);
296 }
297};
298
299template <>
300class OperandHelper<OperandType::kRegOut> {
301 public:
302 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder,
303 Register reg) {
304 return builder->GetOutputRegisterOperand(reg);
305 }
306};
307
308template <>
309class OperandHelper<OperandType::kRegOutList> {
310 public:
311 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder,
312 RegisterList reg_list) {
313 return builder->GetOutputRegisterListOperand(reg_list);
314 }
315};
316
317template <>
318class OperandHelper<OperandType::kRegOutPair> {
319 public:
320 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder,
321 RegisterList reg_list) {
322 DCHECK_EQ(2, reg_list.register_count());
323 return builder->GetOutputRegisterListOperand(reg_list);
324 }
325};
326
327template <>
328class OperandHelper<OperandType::kRegOutTriple> {
329 public:
330 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder,
331 RegisterList reg_list) {
332 DCHECK_EQ(3, reg_list.register_count());
333 return builder->GetOutputRegisterListOperand(reg_list);
334 }
335};
336
337template <>
338class OperandHelper<OperandType::kRegInOut> {
339 public:
340 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder,
341 Register reg) {
342 return builder->GetInputOutputRegisterOperand(reg);
343 }
344};
345
346} // namespace
347
348template <Bytecode bytecode, ImplicitRegisterUse implicit_register_use,
349 OperandType... operand_types>
351 public:
352 template <typename... Operands>
354 Operands... operands) {
355 static_assert(sizeof...(Operands) <= Bytecodes::kMaxOperands,
356 "too many operands for bytecode");
357 builder->PrepareToOutputBytecode<bytecode, implicit_register_use>();
358 // The "OperandHelper<operand_types>::Convert(builder, operands)..." will
359 // expand both the OperandType... and Operands... parameter packs e.g. for:
360 // BytecodeNodeBuilder<OperandType::kReg, OperandType::kImm>::Make<
361 // Register, int>(..., Register reg, int immediate)
362 // the code will expand into:
363 // OperandHelper<OperandType::kReg>::Convert(builder, reg),
364 // OperandHelper<OperandType::kImm>::Convert(builder, immediate),
365 return BytecodeNode::Create<bytecode, implicit_register_use,
366 operand_types...>(
367 builder->CurrentSourcePosition(bytecode),
368 OperandHelper<operand_types>::Convert(builder, operands)...);
369 }
370};
371
372#define DEFINE_BYTECODE_OUTPUT(name, ...) \
373 template <typename... Operands> \
374 BytecodeNode BytecodeArrayBuilder::Create##name##Node( \
375 Operands... operands) { \
376 return BytecodeNodeBuilder<Bytecode::k##name, __VA_ARGS__>::Make( \
377 this, operands...); \
378 } \
379 \
380 template <typename... Operands> \
381 void BytecodeArrayBuilder::Output##name(Operands... operands) { \
382 BytecodeNode node(Create##name##Node(operands...)); \
383 Write(&node); \
384 } \
385 \
386 template <typename... Operands> \
387 void BytecodeArrayBuilder::Output##name(BytecodeLabel* label, \
388 Operands... operands) { \
389 DCHECK(Bytecodes::IsForwardJump(Bytecode::k##name)); \
390 BytecodeNode node(Create##name##Node(operands...)); \
391 WriteJump(&node, label); \
392 }
394#undef DEFINE_BYTECODE_OUTPUT
395
397 int loop_depth, int feedback_slot) {
398 BytecodeNode node(CreateJumpLoopNode(0, loop_depth, feedback_slot));
399 WriteJumpLoop(&node, loop_header);
400}
401
403 BytecodeJumpTable* jump_table) {
404 BytecodeNode node(CreateSwitchOnSmiNoFeedbackNode(
405 jump_table->constant_pool_index(), jump_table->size(),
406 jump_table->case_value_base()));
407 WriteSwitch(&node, jump_table);
408}
409
412 int feedback_slot) {
413 switch (op) {
414 case Token::kAdd:
415 OutputAdd(reg, feedback_slot);
416 break;
417 case Token::kSub:
418 OutputSub(reg, feedback_slot);
419 break;
420 case Token::kMul:
421 OutputMul(reg, feedback_slot);
422 break;
423 case Token::kDiv:
424 OutputDiv(reg, feedback_slot);
425 break;
426 case Token::kMod:
427 OutputMod(reg, feedback_slot);
428 break;
429 case Token::kExp:
430 OutputExp(reg, feedback_slot);
431 break;
432 case Token::kBitOr:
433 OutputBitwiseOr(reg, feedback_slot);
434 break;
435 case Token::kBitXor:
436 OutputBitwiseXor(reg, feedback_slot);
437 break;
438 case Token::kBitAnd:
439 OutputBitwiseAnd(reg, feedback_slot);
440 break;
441 case Token::kShl:
442 OutputShiftLeft(reg, feedback_slot);
443 break;
444 case Token::kSar:
445 OutputShiftRight(reg, feedback_slot);
446 break;
447 case Token::kShr:
448 OutputShiftRightLogical(reg, feedback_slot);
449 break;
450 default:
451 UNREACHABLE();
452 }
453 return *this;
454}
455
457 Token::Value op, Tagged<Smi> literal, int feedback_slot) {
458 switch (op) {
459 case Token::kAdd:
460 OutputAddSmi(literal.value(), feedback_slot);
461 break;
462 case Token::kSub:
463 OutputSubSmi(literal.value(), feedback_slot);
464 break;
465 case Token::kMul:
466 OutputMulSmi(literal.value(), feedback_slot);
467 break;
468 case Token::kDiv:
469 OutputDivSmi(literal.value(), feedback_slot);
470 break;
471 case Token::kMod:
472 OutputModSmi(literal.value(), feedback_slot);
473 break;
474 case Token::kExp:
475 OutputExpSmi(literal.value(), feedback_slot);
476 break;
477 case Token::kBitOr:
478 OutputBitwiseOrSmi(literal.value(), feedback_slot);
479 break;
480 case Token::kBitXor:
481 OutputBitwiseXorSmi(literal.value(), feedback_slot);
482 break;
483 case Token::kBitAnd:
484 OutputBitwiseAndSmi(literal.value(), feedback_slot);
485 break;
486 case Token::kShl:
487 OutputShiftLeftSmi(literal.value(), feedback_slot);
488 break;
489 case Token::kSar:
490 OutputShiftRightSmi(literal.value(), feedback_slot);
491 break;
492 case Token::kShr:
493 OutputShiftRightLogicalSmi(literal.value(), feedback_slot);
494 break;
495 default:
496 UNREACHABLE();
497 }
498 return *this;
499}
500
502 int feedback_slot) {
503 switch (op) {
504 case Token::kInc:
505 OutputInc(feedback_slot);
506 break;
507 case Token::kDec:
508 OutputDec(feedback_slot);
509 break;
510 case Token::kAdd:
511 OutputToNumber(feedback_slot);
512 break;
513 case Token::kSub:
514 OutputNegate(feedback_slot);
515 break;
516 case Token::kBitNot:
517 OutputBitwiseNot(feedback_slot);
518 break;
519 default:
520 UNREACHABLE();
521 }
522 return *this;
523}
524
526 if (mode == ToBooleanMode::kAlreadyBoolean) {
527 OutputLogicalNot();
528 } else {
530 OutputToBooleanLogicalNot();
531 }
532 return *this;
533}
534
536 OutputTypeOf(feedback_slot);
537 return *this;
538}
539
541 OutputGetSuperConstructor(out);
542 return *this;
543}
544
547 Register this_function, Register new_target, RegisterList output) {
548 OutputFindNonDefaultConstructorOrConstruct(this_function, new_target, output);
549 return *this;
550}
551
553 Token::Value op, Register reg, int feedback_slot) {
554 switch (op) {
555 case Token::kEq:
556 OutputTestEqual(reg, feedback_slot);
557 break;
558 case Token::kEqStrict:
559 OutputTestEqualStrict(reg, feedback_slot);
560 break;
561 case Token::kLessThan:
562 OutputTestLessThan(reg, feedback_slot);
563 break;
564 case Token::kGreaterThan:
565 OutputTestGreaterThan(reg, feedback_slot);
566 break;
567 case Token::kLessThanEq:
568 OutputTestLessThanOrEqual(reg, feedback_slot);
569 break;
570 case Token::kGreaterThanEq:
571 OutputTestGreaterThanOrEqual(reg, feedback_slot);
572 break;
573 case Token::kInstanceOf:
574 OutputTestInstanceOf(reg, feedback_slot);
575 break;
576 case Token::kIn:
577 OutputTestIn(reg, feedback_slot);
578 break;
579 default:
580 UNREACHABLE();
581 }
582 return *this;
583}
584
586 OutputTestReferenceEqual(reg);
587 return *this;
588}
589
591 OutputTestUndetectable();
592 return *this;
593}
594
596 OutputTestUndefined();
597 return *this;
598}
599
601 OutputTestNull();
602 return *this;
603}
604
606 NilValue nil) {
607 if (op == Token::kEq) {
608 return CompareUndetectable();
609 } else {
610 DCHECK_EQ(Token::kEqStrict, op);
611 if (nil == kUndefinedValue) {
612 return CompareUndefined();
613 } else {
614 DCHECK_EQ(kNullValue, nil);
615 return CompareNull();
616 }
617 }
618}
619
621 TestTypeOfFlags::LiteralFlag literal_flag) {
622 DCHECK_NE(literal_flag, TestTypeOfFlags::LiteralFlag::kOther);
623 OutputTestTypeOf(TestTypeOfFlags::Encode(literal_flag));
624 return *this;
625}
626
628 size_t entry) {
629 OutputLdaConstant(entry);
630 return *this;
631}
632
634 int32_t raw_smi = smi.value();
635 if (raw_smi == 0) {
636 OutputLdaZero();
637 } else {
638 OutputLdaSmi(raw_smi);
639 }
640 return *this;
641}
642
644 // If we can encode the value as a Smi, we should.
645 int smi;
646 if (DoubleToSmiInteger(value, &smi)) {
648 } else {
649 size_t entry = GetConstantPoolEntry(value);
650 OutputLdaConstant(entry);
651 }
652 return *this;
653}
654
656 const AstRawString* raw_string) {
657 size_t entry = GetConstantPoolEntry(raw_string);
658 OutputLdaConstant(entry);
659 return *this;
660}
661
663 const AstConsString* cons_string) {
664 size_t entry = GetConstantPoolEntry(cons_string);
665 OutputLdaConstant(entry);
666 return *this;
667}
668
670 size_t entry = GetConstantPoolEntry(scope);
671 OutputLdaConstant(entry);
672 return *this;
673}
674
676 size_t entry = GetConstantPoolEntry(bigint);
677 OutputLdaConstant(entry);
678 return *this;
679}
680
682 OutputLdaUndefined();
683 return *this;
684}
685
687 OutputLdaNull();
688 return *this;
689}
690
692 OutputLdaTheHole();
693 return *this;
694}
695
697 OutputLdaTrue();
698 return *this;
699}
700
702 OutputLdaFalse();
703 return *this;
704}
705
707 return value ? LoadTrue() : LoadFalse();
708}
709
711 Register reg) {
713 // Defer source info so that if we elide the bytecode transfer, we attach
714 // the source info to a subsequent bytecode if it exists.
717 } else {
718 OutputLdar(reg);
719 }
720 return *this;
721}
722
724 Register reg) {
726 // Defer source info so that if we elide the bytecode transfer, we attach
727 // the source info to a subsequent bytecode if it exists.
730 } else {
732 }
733 return *this;
734}
735
737 Register to) {
738 DCHECK(from != to);
740 // Defer source info so that if we elide the bytecode transfer, we attach
741 // the source info to a subsequent bytecode if it exists.
743 register_optimizer_->DoMov(from, to);
744 } else {
745 OutputMov(from, to);
746 }
747 return *this;
748}
749
751 int feedback_slot,
752 TypeofMode typeof_mode) {
753 size_t name_index = GetConstantPoolEntry(name);
754 // Ensure that typeof mode is in sync with the IC slot kind.
756 FeedbackVector::ToSlot(feedback_slot))),
757 typeof_mode);
758 switch (typeof_mode) {
760 OutputLdaGlobalInsideTypeof(name_index, feedback_slot);
761 break;
763 OutputLdaGlobal(name_index, feedback_slot);
764 break;
765 }
766 return *this;
767}
768
770 const AstRawString* name, int feedback_slot) {
771 size_t name_index = GetConstantPoolEntry(name);
772 OutputStaGlobal(name_index, feedback_slot);
773 return *this;
774}
775
777 Register context, Variable* variable, int depth,
778 ContextSlotMutability mutability) {
779 int slot_index = variable->index();
780 if (mutability == kImmutableSlot) {
781 if (context.is_current_context() && depth == 0) {
782 OutputLdaImmutableCurrentContextSlot(slot_index);
783 } else {
784 OutputLdaImmutableContextSlot(context, slot_index, depth);
785 }
786 } else {
787 DCHECK_EQ(kMutableSlot, mutability);
788 if (v8_flags.script_context_mutable_heap_number &&
789 variable->scope()->is_script_scope()) {
790 if (context.is_current_context() && depth == 0) {
791 OutputLdaCurrentScriptContextSlot(slot_index);
792 } else {
793 OutputLdaScriptContextSlot(context, slot_index, depth);
794 }
795 } else {
796 if (context.is_current_context() && depth == 0) {
797 OutputLdaCurrentContextSlot(slot_index);
798 } else {
799 OutputLdaContextSlot(context, slot_index, depth);
800 }
801 }
802 }
803 return *this;
804}
805
807 Variable* variable,
808 int depth) {
809 int slot_index = variable->index();
810 if ((v8_flags.script_context_mutable_heap_number ||
811 (v8_flags.const_tracking_let &&
812 variable->mode() == VariableMode::kLet)) &&
813 variable->scope()->is_script_scope()) {
814 if (context.is_current_context() && depth == 0) {
815 OutputStaCurrentScriptContextSlot(slot_index);
816 } else {
817 OutputStaScriptContextSlot(context, slot_index, depth);
818 }
819 } else {
820 if (context.is_current_context() && depth == 0) {
821 OutputStaCurrentContextSlot(slot_index);
822 } else {
823 OutputStaContextSlot(context, slot_index, depth);
824 }
825 }
826 return *this;
827}
828
830 const AstRawString* name, TypeofMode typeof_mode) {
831 size_t name_index = GetConstantPoolEntry(name);
832 switch (typeof_mode) {
834 OutputLdaLookupSlotInsideTypeof(name_index);
835 break;
837 OutputLdaLookupSlot(name_index);
838 break;
839 }
840 return *this;
841}
842
844 const AstRawString* name, TypeofMode typeof_mode, ContextKind context_kind,
845 int slot_index, int depth) {
846 size_t name_index = GetConstantPoolEntry(name);
847 switch (typeof_mode) {
849 if (v8_flags.script_context_mutable_heap_number &&
850 context_kind == ContextKind::kScriptContext) {
851 OutputLdaLookupScriptContextSlotInsideTypeof(name_index, slot_index,
852 depth);
853 } else {
854 OutputLdaLookupContextSlotInsideTypeof(name_index, slot_index, depth);
855 }
856 break;
858 if (v8_flags.script_context_mutable_heap_number &&
859 context_kind == ContextKind::kScriptContext) {
860 OutputLdaLookupScriptContextSlot(name_index, slot_index, depth);
861 } else {
862 OutputLdaLookupContextSlot(name_index, slot_index, depth);
863 }
864 break;
865 }
866 return *this;
867}
868
870 const AstRawString* name, TypeofMode typeof_mode, int feedback_slot,
871 int depth) {
872 size_t name_index = GetConstantPoolEntry(name);
873 switch (typeof_mode) {
875 OutputLdaLookupGlobalSlotInsideTypeof(name_index, feedback_slot, depth);
876 break;
878 OutputLdaLookupGlobalSlot(name_index, feedback_slot, depth);
879 break;
880 }
881 return *this;
882}
883
885 const AstRawString* name, LanguageMode language_mode,
886 LookupHoistingMode lookup_hoisting_mode) {
887 size_t name_index = GetConstantPoolEntry(name);
888 uint8_t flags =
889 StoreLookupSlotFlags::Encode(language_mode, lookup_hoisting_mode);
890 OutputStaLookupSlot(name_index, flags);
891 return *this;
892}
893
895 Register object, const AstRawString* name, int feedback_slot) {
896 size_t name_index = GetConstantPoolEntry(name);
897 OutputGetNamedProperty(object, name_index, feedback_slot);
898 return *this;
899}
900
902 Register object, const AstRawString* name, int feedback_slot) {
903 size_t name_index = GetConstantPoolEntry(name);
904 OutputGetNamedPropertyFromSuper(object, name_index, feedback_slot);
905 return *this;
906}
907
909 Register object, int feedback_slot) {
910 OutputGetKeyedProperty(object, feedback_slot);
911 return *this;
912}
913
915 Register object, Register enum_index, Register cache_type,
916 int feedback_slot) {
917 OutputGetEnumeratedKeyedProperty(object, enum_index, cache_type,
918 feedback_slot);
919 return *this;
920}
921
923 Register object, int feedback_slot) {
924 size_t name_index = IteratorSymbolConstantPoolEntry();
925 OutputGetNamedProperty(object, name_index, feedback_slot);
926 return *this;
927}
928
930 Register object, int load_feedback_slot, int call_feedback_slot) {
931 OutputGetIterator(object, load_feedback_slot, call_feedback_slot);
932 return *this;
933}
934
936 Register object, int feedback_slot) {
937 size_t name_index = AsyncIteratorSymbolConstantPoolEntry();
938 OutputGetNamedProperty(object, name_index, feedback_slot);
939 return *this;
940}
941
944 int feedback_slot) {
945 OutputDefineKeyedOwnPropertyInLiteral(object, name, flags, feedback_slot);
946 return *this;
947}
948
950 Register object, size_t name_index, int feedback_slot,
951 LanguageMode language_mode) {
952 // Ensure that language mode is in sync with the IC slot kind.
954 FeedbackVector::ToSlot(feedback_slot))),
955 language_mode);
956 OutputSetNamedProperty(object, name_index, feedback_slot);
957 return *this;
958}
959
961 Register object, const AstRawString* name, int feedback_slot,
962 LanguageMode language_mode) {
963 size_t name_index = GetConstantPoolEntry(name);
964 return SetNamedProperty(object, name_index, feedback_slot, language_mode);
965}
966
968 Register object, const AstRawString* name, int feedback_slot) {
969 size_t name_index = GetConstantPoolEntry(name);
970 // Ensure that the store operation is in sync with the IC slot kind.
971 DCHECK_EQ(
973 feedback_vector_spec()->GetKind(FeedbackVector::ToSlot(feedback_slot)));
974 OutputDefineNamedOwnProperty(object, name_index, feedback_slot);
975 return *this;
976}
977
979 Register object, Register key, int feedback_slot,
980 LanguageMode language_mode) {
981 // Ensure that language mode is in sync with the IC slot kind.
983 FeedbackVector::ToSlot(feedback_slot))),
984 language_mode);
985 OutputSetKeyedProperty(object, key, feedback_slot);
986 return *this;
987}
988
991 int feedback_slot) {
992 // Ensure that the IC uses a strict language mode, as this is the only
993 // supported mode for this use case.
995 FeedbackVector::ToSlot(feedback_slot))),
997 OutputDefineKeyedOwnProperty(object, key, flags, feedback_slot);
998 return *this;
999}
1000
1002 Register array, Register index, int feedback_slot) {
1003 OutputStaInArrayLiteral(array, index, feedback_slot);
1004 return *this;
1005}
1006
1008 Register constructor, int feedback_slot) {
1009 size_t name_index = ClassFieldsSymbolConstantPoolEntry();
1010 return SetNamedProperty(constructor, name_index, feedback_slot,
1012}
1013
1015 Register constructor, int feedback_slot) {
1016 size_t name_index = ClassFieldsSymbolConstantPoolEntry();
1017 OutputGetNamedProperty(constructor, name_index, feedback_slot);
1018 return *this;
1019}
1020
1022 size_t shared_function_info_entry, int slot, int flags) {
1023 OutputCreateClosure(shared_function_info_entry, slot, flags);
1024 return *this;
1025}
1026
1028 const Scope* scope) {
1029 size_t entry = GetConstantPoolEntry(scope);
1030 OutputCreateBlockContext(entry);
1031 return *this;
1032}
1033
1035 Register exception, const Scope* scope) {
1036 size_t scope_index = GetConstantPoolEntry(scope);
1037 OutputCreateCatchContext(exception, scope_index);
1038 return *this;
1039}
1040
1042 const Scope* scope, int slots) {
1043 size_t scope_index = GetConstantPoolEntry(scope);
1044 OutputCreateFunctionContext(scope_index, slots);
1045 return *this;
1046}
1047
1049 const Scope* scope, int slots) {
1050 size_t scope_index = GetConstantPoolEntry(scope);
1051 OutputCreateEvalContext(scope_index, slots);
1052 return *this;
1053}
1054
1056 Register object, const Scope* scope) {
1057 size_t scope_index = GetConstantPoolEntry(scope);
1058 OutputCreateWithContext(object, scope_index);
1059 return *this;
1060}
1061
1063 CreateArgumentsType type) {
1064 switch (type) {
1066 OutputCreateMappedArguments();
1067 break;
1069 OutputCreateUnmappedArguments();
1070 break;
1072 OutputCreateRestParameter();
1073 break;
1074 default:
1075 UNREACHABLE();
1076 }
1077 return *this;
1078}
1079
1081 const AstRawString* pattern, int literal_index, int flags) {
1082 size_t pattern_entry = GetConstantPoolEntry(pattern);
1083 OutputCreateRegExpLiteral(pattern_entry, literal_index, flags);
1084 return *this;
1085}
1086
1088 int literal_index) {
1089 OutputCreateEmptyArrayLiteral(literal_index);
1090 return *this;
1091}
1092
1094 size_t constant_elements_entry, int literal_index, int flags) {
1095 OutputCreateArrayLiteral(constant_elements_entry, literal_index, flags);
1096 return *this;
1097}
1098
1100 OutputCreateArrayFromIterable();
1101 return *this;
1102}
1103
1105 size_t constant_properties_entry, int literal_index, int flags) {
1106 OutputCreateObjectLiteral(constant_properties_entry, literal_index, flags);
1107 return *this;
1108}
1109
1111 OutputCreateEmptyObjectLiteral();
1112 return *this;
1113}
1114
1116 int flags,
1117 int feedback_slot) {
1118 OutputCloneObject(source, flags, feedback_slot);
1119 return *this;
1120}
1121
1123 size_t template_object_description_entry, int feedback_slot) {
1124 OutputGetTemplateObject(template_object_description_entry, feedback_slot);
1125 return *this;
1126}
1127
1129 OutputPushContext(context);
1130 return *this;
1131}
1132
1134 OutputPopContext(context);
1135 return *this;
1136}
1137
1139 OutputToObject(out);
1140 return *this;
1141}
1142
1144 OutputToName();
1145 return *this;
1146}
1147
1149 OutputToString();
1150 return *this;
1151}
1152
1154 if (mode == ToBooleanMode::kAlreadyBoolean) {
1155 // No-op, the accumulator is already a boolean and ToBoolean both reads and
1156 // writes the accumulator.
1157 } else {
1159 OutputToBoolean();
1160 }
1161 return *this;
1162}
1163
1165 OutputToNumber(feedback_slot);
1166 return *this;
1167}
1168
1170 OutputToNumeric(feedback_slot);
1171 return *this;
1172}
1173
1175 // Don't generate code for a label which hasn't had a corresponding forward
1176 // jump generated already. For backwards jumps, use BindLoopHeader.
1177 if (!label->has_referrer_jump()) return *this;
1178
1179 // Flush the register optimizer when binding a label to ensure all
1180 // expected registers are valid when jumping to this label.
1181 if (register_optimizer_) {
1184 }
1186 return *this;
1187}
1188
1190 BytecodeLoopHeader* loop_header) {
1191 // Flush the register optimizer when starting a loop to ensure all expected
1192 // registers are valid when jumping to the loop header.
1193 if (register_optimizer_) {
1196 }
1198 return *this;
1199}
1200
1202 int case_value) {
1203 // Flush the register optimizer when binding a jump table entry to ensure
1204 // all expected registers are valid when jumping to this location.
1205 if (register_optimizer_) {
1208 }
1209 bytecode_array_writer_.BindJumpTableEntry(jump_table, case_value);
1210 return *this;
1211}
1212
1214 int handler_id, HandlerTable::CatchPrediction catch_prediction) {
1215 // The handler starts a new basic block, and any reasonable try block won't
1216 // let control fall through into it.
1222 handler_table_builder()->SetPrediction(handler_id, catch_prediction);
1223 return *this;
1224}
1225
1227 Register context) {
1228 // Flush registers to make sure everything visible to the handler is
1229 // materialized.
1232 handler_id);
1233 handler_table_builder()->SetContextRegister(handler_id, context);
1234 return *this;
1235}
1236
1244
1246 DCHECK(!label->is_bound());
1247 OutputJump(label, 0);
1248 return *this;
1249}
1250
1253 DCHECK(!label->is_bound());
1254 if (mode == ToBooleanMode::kAlreadyBoolean) {
1255 OutputJumpIfTrue(label, 0);
1256 } else {
1258 OutputJumpIfToBooleanTrue(label, 0);
1259 }
1260 return *this;
1261}
1262
1265 DCHECK(!label->is_bound());
1266 if (mode == ToBooleanMode::kAlreadyBoolean) {
1267 OutputJumpIfFalse(label, 0);
1268 } else {
1270 OutputJumpIfToBooleanFalse(label, 0);
1271 }
1272 return *this;
1273}
1274
1276 DCHECK(!label->is_bound());
1277 OutputJumpIfNull(label, 0);
1278 return *this;
1279}
1280
1283 DCHECK(!label->is_bound());
1284 OutputJumpIfNotNull(label, 0);
1285 return *this;
1286}
1287
1290 DCHECK(!label->is_bound());
1291 OutputJumpIfUndefined(label, 0);
1292 return *this;
1293}
1294
1297 DCHECK(!label->is_bound());
1298 OutputJumpIfUndefinedOrNull(label, 0);
1299 return *this;
1300}
1301
1304 DCHECK(!label->is_bound());
1305 OutputJumpIfNotUndefined(label, 0);
1306 return *this;
1307}
1308
1310 Token::Value op,
1311 NilValue nil) {
1312 if (op == Token::kEq) {
1313 // TODO(rmcilroy): Implement JumpIfUndetectable.
1315 label);
1316 } else {
1317 DCHECK_EQ(Token::kEqStrict, op);
1318 if (nil == kUndefinedValue) {
1319 return JumpIfUndefined(label);
1320 } else {
1321 DCHECK_EQ(kNullValue, nil);
1322 return JumpIfNull(label);
1323 }
1324 }
1325}
1326
1328 Token::Value op,
1329 NilValue nil) {
1330 if (op == Token::kEq) {
1331 // TODO(rmcilroy): Implement JumpIfUndetectable.
1333 label);
1334 } else {
1335 DCHECK_EQ(Token::kEqStrict, op);
1336 if (nil == kUndefinedValue) {
1337 return JumpIfNotUndefined(label);
1338 } else {
1339 DCHECK_EQ(kNullValue, nil);
1340 return JumpIfNotNull(label);
1341 }
1342 }
1343}
1344
1347 DCHECK(!label->is_bound());
1348 OutputJumpIfJSReceiver(label, 0);
1349 return *this;
1350}
1351
1353 BytecodeLabel* label, Register index, Register cache_length) {
1354 DCHECK(!label->is_bound());
1355 OutputJumpIfForInDone(label, 0, index, cache_length);
1356 return *this;
1357}
1358
1360 BytecodeLoopHeader* loop_header, int loop_depth, int position,
1361 int feedback_slot) {
1362 if (position != kNoSourcePosition) {
1363 // We need to attach a non-breakable source position to JumpLoop for its
1364 // implicit stack check, so we simply add it as expression position. There
1365 // can be a prior statement position from constructs like:
1366 //
1367 // do var x; while (false);
1368 //
1369 // A Nop could be inserted for empty statements, but since no code
1370 // is associated with these positions, instead we force the jump loop's
1371 // expression position which eliminates the empty statement's position.
1373 }
1374 OutputJumpLoop(loop_header, loop_depth, feedback_slot);
1375 return *this;
1376}
1377
1383
1385 OutputSetPendingMessage();
1386 return *this;
1387}
1388
1390 OutputThrow();
1391 return *this;
1392}
1393
1395 OutputReThrow();
1396 return *this;
1397}
1398
1400 DCHECK_LT(reason, AbortReason::kLastErrorMessage);
1401 DCHECK_GE(reason, AbortReason::kNoReason);
1402 OutputAbort(static_cast<int>(reason));
1403 return *this;
1404}
1405
1407 OutputReturn();
1408 return *this;
1409}
1410
1412 const AstRawString* name) {
1413 size_t entry = GetConstantPoolEntry(name);
1414 OutputThrowReferenceErrorIfHole(entry);
1415 return *this;
1416}
1417
1419 OutputThrowSuperNotCalledIfHole();
1420 return *this;
1421}
1422
1424 OutputThrowSuperAlreadyCalledIfNotHole();
1425 return *this;
1426}
1427
1429 Register constructor) {
1430 OutputThrowIfNotSuperConstructor(constructor);
1431 return *this;
1432}
1433
1435 OutputDebugger();
1436 return *this;
1437}
1438
1440 int coverage_array_slot) {
1441 OutputIncBlockCounter(coverage_array_slot);
1442 return *this;
1443}
1444
1446 OutputForInEnumerate(receiver);
1447 return *this;
1448}
1449
1451 RegisterList cache_info_triple, int feedback_slot) {
1452 DCHECK_EQ(3, cache_info_triple.register_count());
1453 OutputForInPrepare(cache_info_triple, feedback_slot);
1454 return *this;
1455}
1456
1458 Register receiver, Register index, RegisterList cache_type_array_pair,
1459 int feedback_slot) {
1460 DCHECK_EQ(2, cache_type_array_pair.register_count());
1461 OutputForInNext(receiver, index, cache_type_array_pair, feedback_slot);
1462 return *this;
1463}
1464
1466 OutputForInStep(index);
1467 return *this;
1468}
1469
1471 int depth) {
1472 OutputStaModuleVariable(cell_index, depth);
1473 return *this;
1474}
1475
1477 int depth) {
1478 OutputLdaModuleVariable(cell_index, depth);
1479 return *this;
1480}
1481
1483 Register generator, RegisterList registers, int suspend_id) {
1484 OutputSuspendGenerator(generator, registers, registers.register_count(),
1485 suspend_id);
1486 return *this;
1487}
1488
1490 Register generator, BytecodeJumpTable* jump_table) {
1491 DCHECK_EQ(jump_table->case_value_base(), 0);
1492 BytecodeNode node(CreateSwitchOnGeneratorStateNode(
1493 generator, jump_table->constant_pool_index(), jump_table->size()));
1494 WriteSwitch(&node, jump_table);
1495 return *this;
1496}
1497
1499 Register generator, RegisterList registers) {
1500 OutputResumeGenerator(generator, registers, registers.register_count());
1501 return *this;
1502}
1503
1506 int feedback_slot) {
1507 if (args.register_count() == 1) {
1508 OutputCallProperty0(callable, args[0], feedback_slot);
1509 } else if (args.register_count() == 2) {
1510 OutputCallProperty1(callable, args[0], args[1], feedback_slot);
1511 } else if (args.register_count() == 3) {
1512 OutputCallProperty2(callable, args[0], args[1], args[2], feedback_slot);
1513 } else {
1514 OutputCallProperty(callable, args, args.register_count(), feedback_slot);
1515 }
1516 return *this;
1517}
1518
1520 Register callable, RegisterList args, int feedback_slot) {
1521 if (args.register_count() == 0) {
1522 OutputCallUndefinedReceiver0(callable, feedback_slot);
1523 } else if (args.register_count() == 1) {
1524 OutputCallUndefinedReceiver1(callable, args[0], feedback_slot);
1525 } else if (args.register_count() == 2) {
1526 OutputCallUndefinedReceiver2(callable, args[0], args[1], feedback_slot);
1527 } else {
1528 OutputCallUndefinedReceiver(callable, args, args.register_count(),
1529 feedback_slot);
1530 }
1531 return *this;
1532}
1533
1536 int feedback_slot) {
1537 OutputCallAnyReceiver(callable, args, args.register_count(), feedback_slot);
1538 return *this;
1539}
1540
1543 int feedback_slot) {
1544 OutputCallWithSpread(callable, args, args.register_count(), feedback_slot);
1545 return *this;
1546}
1547
1550 int feedback_slot_id) {
1551 OutputConstruct(constructor, args, args.register_count(), feedback_slot_id);
1552 return *this;
1553}
1554
1556 Register constructor, RegisterList args, int feedback_slot_id) {
1557 OutputConstructWithSpread(constructor, args, args.register_count(),
1558 feedback_slot_id);
1559 return *this;
1560}
1561
1563 Register constructor, int feedback_slot_id) {
1564 OutputConstructForwardAllArgs(constructor, feedback_slot_id);
1565 return *this;
1566}
1567
1569 Runtime::FunctionId function_id, RegisterList args) {
1570 DCHECK_EQ(1, Runtime::FunctionForId(function_id)->result_size);
1573 if (IntrinsicsHelper::IsSupported(function_id)) {
1574 IntrinsicsHelper::IntrinsicId intrinsic_id =
1576 OutputInvokeIntrinsic(static_cast<int>(intrinsic_id), args,
1577 args.register_count());
1578 } else {
1579 OutputCallRuntime(static_cast<int>(function_id), args,
1580 args.register_count());
1581 }
1582 return *this;
1583}
1584
1589
1594
1597 RegisterList return_pair) {
1598 DCHECK_EQ(2, Runtime::FunctionForId(function_id)->result_size);
1601 DCHECK_EQ(2, return_pair.register_count());
1602 OutputCallRuntimeForPair(static_cast<uint16_t>(function_id), args,
1603 args.register_count(), return_pair);
1604 return *this;
1605}
1606
1608 Runtime::FunctionId function_id, Register arg, RegisterList return_pair) {
1609 return CallRuntimeForPair(function_id, RegisterList(arg), return_pair);
1610}
1611
1614 OutputCallJSRuntime(context_index, args, args.register_count());
1615 return *this;
1616}
1617
1619 LanguageMode language_mode) {
1620 if (language_mode == LanguageMode::kSloppy) {
1621 OutputDeletePropertySloppy(object);
1622 } else {
1623 DCHECK_EQ(language_mode, LanguageMode::kStrict);
1624 OutputDeletePropertyStrict(object);
1625 }
1626 return *this;
1627}
1628
1630 const AstRawString* raw_string) {
1631 return constant_array_builder()->Insert(raw_string);
1632}
1633
1635 const AstConsString* cons_string) {
1636 return constant_array_builder()->Insert(cons_string);
1637}
1638
1642
1644 return constant_array_builder()->Insert(scope);
1645}
1646
1648 return constant_array_builder()->Insert(number);
1649}
1650
1651#define ENTRY_GETTER(NAME, ...) \
1652 size_t BytecodeArrayBuilder::NAME##ConstantPoolEntry() { \
1653 return constant_array_builder()->Insert##NAME(); \
1654 }
1656#undef ENTRY_GETTER
1657
1659 int size, int case_value_base) {
1660 DCHECK_GT(size, 0);
1661
1662 size_t constant_pool_index = constant_array_builder()->InsertJumpTable(size);
1663
1664 return zone()->New<BytecodeJumpTable>(constant_pool_index, size,
1665 case_value_base, zone());
1666}
1667
1671
1676
1678 if (!reg.is_valid()) {
1679 return false;
1680 }
1681
1682 if (reg.is_current_context() || reg.is_function_closure()) {
1683 return true;
1684 } else if (reg.is_parameter()) {
1685 int parameter_index = reg.ToParameterIndex();
1686 return parameter_index >= 0 && parameter_index < parameter_count();
1687 } else if (reg.index() < fixed_register_count()) {
1688 return true;
1689 } else {
1691 }
1692}
1693
1695 if (reg_list.register_count() == 0) {
1696 return reg_list.first_register() == Register(0);
1697 } else {
1698 int first_reg_index = reg_list.first_register().index();
1699 for (int i = 0; i < reg_list.register_count(); i++) {
1700 if (!RegisterIsValid(Register(first_reg_index + i))) {
1701 return false;
1702 }
1703 }
1704 return true;
1705 }
1706}
1707
1708template <Bytecode bytecode, ImplicitRegisterUse implicit_register_use>
1714
1718 return static_cast<uint32_t>(reg.ToOperand());
1719}
1720
1726
1735
1737 RegisterList reg_list) {
1738 DCHECK(RegisterListIsValid(reg_list));
1740 reg_list = register_optimizer_->GetInputRegisterList(reg_list);
1741 return static_cast<uint32_t>(reg_list.first_register().ToOperand());
1742}
1743
1745 RegisterList reg_list) {
1746 DCHECK(RegisterListIsValid(reg_list));
1749 return static_cast<uint32_t>(reg_list.first_register().ToOperand());
1750}
1751
1754 // Force an expression position to make sure we have one. If the next bytecode
1755 // overwrites it, it’s fine since it would mean we have a source position
1756 // anyway.
1758}
1759
1760std::ostream& operator<<(std::ostream& os,
1762 switch (mode) {
1764 return os << "AlreadyBoolean";
1766 return os << "ConvertToBoolean";
1767 }
1768 UNREACHABLE();
1769}
1770
1771} // namespace interpreter
1772} // namespace internal
1773} // namespace v8
int16_t parameter_count
Definition builtins.cc:67
interpreter::Bytecode bytecode
Definition builtins.cc:43
#define ENTRY_GETTER(NAME,...)
#define DEFINE_UNSIGNED_OPERAND_HELPER(Name, Type)
#define DEFINE_BYTECODE_OUTPUT(name,...)
#define UNSIGNED_SCALABLE_SCALAR_OPERAND_TYPE_LIST(V)
#define UNSIGNED_FIXED_SCALAR_OPERAND_TYPE_LIST(V)
#define BYTECODE_LIST(V, V_TSA)
Definition bytecodes.h:479
static FeedbackSlot ToSlot(intptr_t index)
static V8_EXPORT_PRIVATE const Function * FunctionForId(FunctionId id)
Definition runtime.cc:350
static constexpr Tagged< Smi > FromInt(int value)
Definition smi.h:38
T * New(Args &&... args)
Definition zone.h:114
BytecodeArrayBuilder & LoadLookupSlot(const AstRawString *name, TypeofMode typeof_mode)
BytecodeArrayBuilder(Zone *zone, int parameter_count, int locals_count, FeedbackVectorSpec *feedback_vector_spec=nullptr, SourcePositionTableBuilder::RecordingMode source_position_mode=SourcePositionTableBuilder::RECORD_SOURCE_POSITIONS)
BytecodeArrayBuilder & ThrowIfNotSuperConstructor(Register constructor)
BytecodeArrayBuilder & UnaryOperation(Token::Value op, int feedback_slot)
BytecodeArrayBuilder & ForInStep(Register index)
BytecodeArrayBuilder & StoreInArrayLiteral(Register array, Register index, int feedback_slot)
BytecodeArrayBuilder & CallJSRuntime(int context_index, RegisterList args)
BytecodeArrayBuilder & SetNamedProperty(Register object, const AstRawString *name, int feedback_slot, LanguageMode language_mode)
void SetDeferredSourceInfo(BytecodeSourceInfo source_info)
BytecodeArrayBuilder & TypeOf(int feedback_slot)
BytecodeArrayBuilder & ForInNext(Register receiver, Register index, RegisterList cache_type_array_pair, int feedback_slot)
BytecodeArrayBuilder & CallAnyReceiver(Register callable, RegisterList args, int feedback_slot)
BytecodeArrayBuilder & CreateCatchContext(Register exception, const Scope *scope)
BytecodeArrayBuilder & LoadIteratorProperty(Register object, int feedback_slot)
BytecodeArrayBuilder & GetTemplateObject(size_t template_object_description_entry, int feedback_slot)
BytecodeArrayBuilder & LoadAsyncIteratorProperty(Register object, int feedback_slot)
BytecodeArrayBuilder & ForInPrepare(RegisterList cache_info_triple, int feedback_slot)
BytecodeArrayBuilder & LoadClassFieldsInitializer(Register constructor, int feedback_slot)
BytecodeArrayBuilder & CreateBlockContext(const Scope *scope)
BytecodeArrayBuilder & ToNumber(int feedback_slot)
BytecodeArrayBuilder & Delete(Register object, LanguageMode language_mode)
BytecodeArrayBuilder & StoreContextSlot(Register context, Variable *variable, int depth)
BytecodeArrayBuilder & Abort(AbortReason reason)
BytecodeArrayBuilder & ToBoolean(ToBooleanMode mode)
BytecodeArrayBuilder & LoadGlobal(const AstRawString *name, int feedback_slot, TypeofMode typeof_mode)
BytecodeArrayBuilder & CallUndefinedReceiver(Register callable, RegisterList args, int feedback_slot)
BytecodeArrayBuilder & LoadModuleVariable(int cell_index, int depth)
BytecodeArrayBuilder & SuspendGenerator(Register generator, RegisterList registers, int suspend_id)
BytecodeArrayBuilder & CreateClosure(size_t shared_function_info_entry, int slot, int flags)
V8_INLINE void OutputJumpLoop(BytecodeLoopHeader *loop_header, int loop_depth, int feedback_slot)
BytecodeArrayBuilder & GetIterator(Register object, int load_feedback_slot, int call_feedback_slot)
BytecodeArrayBuilder & JumpIfNotNil(BytecodeLabel *label, Token::Value op, NilValue nil)
BytecodeArrayBuilder & LoadContextSlot(Register context, Variable *variable, int depth, ContextSlotMutability immutable)
BytecodeArrayBuilder & DefineKeyedOwnPropertyInLiteral(Register object, Register name, DefineKeyedOwnPropertyInLiteralFlags flags, int feedback_slot)
BytecodeArrayBuilder & JumpIfForInDone(BytecodeLabel *label, Register index, Register cache_length)
BytecodeArrayBuilder & JumpIfNull(BytecodeLabel *label)
BytecodeArrayBuilder & CompareNil(Token::Value op, NilValue nil)
BytecodeJumpTable * AllocateJumpTable(int size, int case_value_base)
BytecodeArrayBuilder & ToNumeric(int feedback_slot)
BytecodeArrayBuilder & LoadLiteral(Tagged< Smi > value)
BytecodeArrayBuilder & StoreAccumulatorInRegister(Register reg)
BytecodeArrayBuilder & LogicalNot(ToBooleanMode mode)
V8_INLINE void OutputSwitchOnSmiNoFeedback(BytecodeJumpTable *jump_table)
BytecodeArrayBuilder & CreateRegExpLiteral(const AstRawString *pattern, int literal_index, int flags)
BytecodeArrayBuilder & CompareReference(Register reg)
BytecodeArrayBuilder & LoadNamedProperty(Register object, const AstRawString *name, int feedback_slot)
BytecodeArrayBuilder & MarkTryEnd(int handler_id)
BytecodeArrayBuilder & JumpIfFalse(ToBooleanMode mode, BytecodeLabel *label)
BytecodeArrayBuilder & ResumeGenerator(Register generator, RegisterList registers)
BytecodeArrayBuilder & MarkTryBegin(int handler_id, Register context)
void WriteJumpLoop(BytecodeNode *node, BytecodeLoopHeader *loop_header)
BytecodeArrayBuilder & Bind(BytecodeLabel *label)
BytecodeArrayBuilder & JumpIfUndefined(BytecodeLabel *label)
BytecodeArrayBuilder & SwitchOnSmiNoFeedback(BytecodeJumpTable *jump_table)
BytecodeArrayBuilder & JumpIfTrue(ToBooleanMode mode, BytecodeLabel *label)
BytecodeArrayBuilder & CallRuntimeForPair(Runtime::FunctionId function_id, RegisterList args, RegisterList return_pair)
BytecodeArrayBuilder & JumpIfNotNull(BytecodeLabel *label)
BytecodeArrayBuilder & CompareOperation(Token::Value op, Register reg, int feedback_slot)
BytecodeArrayBuilder & MarkHandler(int handler_id, HandlerTable::CatchPrediction will_catch)
BytecodeArrayBuilder & ForInEnumerate(Register receiver)
BytecodeArrayBuilder & CreateEvalContext(const Scope *scope, int slots)
BytecodeArrayBuilder & FindNonDefaultConstructorOrConstruct(Register this_function, Register new_target, RegisterList output)
BytecodeArrayBuilder & LoadKeyedProperty(Register object, int feedback_slot)
BytecodeArrayBuilder & CreateFunctionContext(const Scope *scope, int slots)
BytecodeArrayBuilder & ThrowReferenceErrorIfHole(const AstRawString *name)
void WriteSwitch(BytecodeNode *node, BytecodeJumpTable *label)
BytecodeArrayBuilder & CloneObject(Register source, int flags, int feedback_slot)
BytecodeArrayBuilder & LoadLookupContextSlot(const AstRawString *name, TypeofMode typeof_mode, ContextKind context_kind, int slot_index, int depth)
BytecodeArrayBuilder & MoveRegister(Register from, Register to)
BytecodeArrayBuilder & PopContext(Register context)
BytecodeArrayBuilder & BinaryOperationSmiLiteral(Token::Value binop, Tagged< Smi > literal, int feedback_slot)
BytecodeArrayBuilder & JumpIfNotUndefined(BytecodeLabel *label)
BytecodeArrayBuilder & StoreClassFieldsInitializer(Register constructor, int feedback_slot)
BytecodeArrayBuilder & CreateEmptyArrayLiteral(int literal_index)
BytecodeArrayBuilder & StoreLookupSlot(const AstRawString *name, LanguageMode language_mode, LookupHoistingMode lookup_hoisting_mode)
BytecodeArrayBuilder & StoreModuleVariable(int cell_index, int depth)
BytecodeArrayBuilder & ConstructForwardAllArgs(Register constructor, int feedback_slot)
void WriteJump(BytecodeNode *node, BytecodeLabel *label)
V8_INLINE BytecodeSourceInfo CurrentSourcePosition(Bytecode bytecode)
BytecodeArrayBuilder & SwitchOnGeneratorState(Register generator, BytecodeJumpTable *jump_table)
BytecodeArrayBuilder & CallWithSpread(Register callable, RegisterList args, int feedback_slot)
BytecodeArrayBuilder & GetSuperConstructor(Register out)
BytecodeArrayBuilder & ConstructWithSpread(Register constructor, RegisterList args, int feedback_slot)
BytecodeArrayBuilder & LoadEnumeratedKeyedProperty(Register object, Register enum_index, Register cache_type, int feedback_slot)
BytecodeArrayBuilder & DefineNamedOwnProperty(Register object, const AstRawString *name, int feedback_slot)
BytecodeArrayBuilder & JumpLoop(BytecodeLoopHeader *loop_header, int loop_depth, int position, int feedback_slot)
BytecodeArrayBuilder & BinaryOperation(Token::Value binop, Register reg, int feedback_slot)
BytecodeArrayBuilder & StoreGlobal(const AstRawString *name, int feedback_slot)
BytecodeArrayBuilder & SetKeyedProperty(Register object, Register key, int feedback_slot, LanguageMode language_mode)
DirectHandle< TrustedByteArray > ToSourcePositionTable(IsolateT *isolate)
BytecodeArrayBuilder & CreateObjectLiteral(size_t constant_properties_entry, int literal_index, int flags)
BytecodeArrayBuilder & LoadAccumulatorWithRegister(Register reg)
BytecodeArrayBuilder & Jump(BytecodeLabel *label)
BytecodeArrayBuilder & CallProperty(Register callable, RegisterList args, int feedback_slot)
Handle< BytecodeArray > ToBytecodeArray(IsolateT *isolate)
BytecodeArrayBuilder & LoadLookupGlobalSlot(const AstRawString *name, TypeofMode typeof_mode, int feedback_slot, int depth)
BytecodeArrayBuilder & DefineKeyedOwnProperty(Register object, Register key, DefineKeyedOwnPropertyFlags flags, int feedback_slot)
BytecodeArrayBuilder & PushContext(Register context)
size_t GetConstantPoolEntry(const AstRawString *raw_string)
BytecodeArrayBuilder & LoadConstantPoolEntry(size_t entry)
BytecodeArrayBuilder & CreateWithContext(Register object, const Scope *scope)
BytecodeArrayBuilder & Construct(Register constructor, RegisterList args, int feedback_slot)
BytecodeArrayBuilder & CreateArguments(CreateArgumentsType type)
BytecodeArrayBuilder & JumpIfJSReceiver(BytecodeLabel *label)
BytecodeArrayBuilder & LoadNamedPropertyFromSuper(Register object, const AstRawString *name, int feedback_slot)
BytecodeArrayBuilder & JumpIfUndefinedOrNull(BytecodeLabel *label)
BytecodeArrayBuilder & CompareTypeOf(TestTypeOfFlags::LiteralFlag literal_flag)
BytecodeArrayBuilder & CreateArrayLiteral(size_t constant_elements_entry, int literal_index, int flags)
BytecodeArrayBuilder & JumpIfNil(BytecodeLabel *label, Token::Value op, NilValue nil)
const FeedbackVectorSpec * feedback_vector_spec() const
void SetDeferredConstantPoolEntry(size_t entry, Handle< Object > object)
BytecodeArrayBuilder & CallRuntime(Runtime::FunctionId function_id, RegisterList args)
void BindLoopHeader(BytecodeLoopHeader *loop_header)
void WriteSwitch(BytecodeNode *node, BytecodeJumpTable *jump_table)
void WriteJump(BytecodeNode *node, BytecodeLabel *label)
Handle< BytecodeArray > ToBytecodeArray(IsolateT *isolate, int register_count, uint16_t parameter_count, uint16_t max_arguments, DirectHandle< TrustedByteArray > handler_table)
DirectHandle< TrustedByteArray > ToSourcePositionTable(IsolateT *isolate)
void BindTryRegionEnd(HandlerTableBuilder *handler_table_builder, int handler_id)
void BindHandlerTarget(HandlerTableBuilder *handler_table_builder, int handler_id)
void BindJumpTableEntry(BytecodeJumpTable *jump_table, int case_value)
void WriteJumpLoop(BytecodeNode *node, BytecodeLoopHeader *loop_header)
void BindTryRegionStart(HandlerTableBuilder *handler_table_builder, int handler_id)
static V8_INLINE BytecodeNode Make(BytecodeArrayBuilder *builder, Operands... operands)
static V8_INLINE BytecodeNode Create(BytecodeSourceInfo source_info)
static constexpr bool IsWithoutExternalSideEffects(Bytecode bytecode)
Definition bytecodes.h:826
static OperandSize SizeForUnsignedOperand(uint32_t value)
Definition bytecodes.h:1096
void SetDeferredAt(size_t index, Handle< Object > object)
void SetContextRegister(int handler_id, Register reg)
void SetPrediction(int handler_id, HandlerTable::CatchPrediction prediction)
DirectHandle< TrustedByteArray > ToHandlerTable(IsolateT *isolate)
static V8_EXPORT_PRIVATE bool IsSupported(Runtime::FunctionId function_id)
static IntrinsicId FromRuntimeId(Runtime::FunctionId function_id)
void EmitMov(Register input, Register output) override
static constexpr Register FromParameterIndex(int index)
constexpr int32_t ToOperand() const
static uint8_t Encode(LanguageMode language_mode, LookupHoistingMode lookup_hoisting_mode)
static uint8_t Encode(LiteralFlag literal_flag)
Zone * zone_
#define SINGLETON_CONSTANT_ENTRY_TYPES(V)
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
DirectHandle< Object > new_target
Definition execution.cc:75
Label label
#define EXPORT_TEMPLATE_DEFINE(export)
TNode< Object > receiver
std::string pattern
Node * node
LiftoffRegister reg
FunctionLiteral * literal
Definition liveedit.cc:294
int position
Definition liveedit.cc:290
RegListBase< RegisterT > registers
std::ostream & operator<<(std::ostream &os, PaddingSpace padding)
constexpr int kNoSourcePosition
Definition globals.h:850
constexpr int kMaxUInt8
Definition globals.h:378
bool DoubleToSmiInteger(double value, int *smi_int_value)
constexpr int kMaxUInt16
Definition globals.h:382
LanguageMode GetLanguageModeFromSlotKind(FeedbackSlotKind kind)
TypeofMode GetTypeofModeFromSlotKind(FeedbackSlotKind kind)
V8_EXPORT_PRIVATE FlagValues v8_flags
return value
Definition map-inl.h:893
constexpr uint32_t kMaxUInt32
Definition globals.h:387
#define NON_EXPORTED_BASE(code)
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487
#define V8_EXPORT_PRIVATE
Definition macros.h:460
#define V8_INLINE
Definition v8config.h:500