11cb0ef41Sopenharmony_ci// Copyright 2021 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#ifndef V8_BASELINE_BASELINE_ASSEMBLER_H_
61cb0ef41Sopenharmony_ci#define V8_BASELINE_BASELINE_ASSEMBLER_H_
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci// TODO(v8:11421): Remove #if once baseline compiler is ported to other
91cb0ef41Sopenharmony_ci// architectures.
101cb0ef41Sopenharmony_ci#include "src/flags/flags.h"
111cb0ef41Sopenharmony_ci#if ENABLE_SPARKPLUG
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_ci#include "src/codegen/macro-assembler.h"
141cb0ef41Sopenharmony_ci#include "src/objects/tagged-index.h"
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_cinamespace v8 {
171cb0ef41Sopenharmony_cinamespace internal {
181cb0ef41Sopenharmony_cinamespace baseline {
191cb0ef41Sopenharmony_ci
201cb0ef41Sopenharmony_cienum class Condition : uint32_t;
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ciclass BaselineAssembler {
231cb0ef41Sopenharmony_ci public:
241cb0ef41Sopenharmony_ci  class ScratchRegisterScope;
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_ci  explicit BaselineAssembler(MacroAssembler* masm) : masm_(masm) {}
271cb0ef41Sopenharmony_ci  inline static MemOperand RegisterFrameOperand(
281cb0ef41Sopenharmony_ci      interpreter::Register interpreter_register);
291cb0ef41Sopenharmony_ci  inline void RegisterFrameAddress(interpreter::Register interpreter_register,
301cb0ef41Sopenharmony_ci                                   Register rscratch);
311cb0ef41Sopenharmony_ci  inline MemOperand ContextOperand();
321cb0ef41Sopenharmony_ci  inline MemOperand FunctionOperand();
331cb0ef41Sopenharmony_ci  inline MemOperand FeedbackVectorOperand();
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci  inline void GetCode(Isolate* isolate, CodeDesc* desc);
361cb0ef41Sopenharmony_ci  inline int pc_offset() const;
371cb0ef41Sopenharmony_ci  inline void CodeEntry() const;
381cb0ef41Sopenharmony_ci  inline void ExceptionHandler() const;
391cb0ef41Sopenharmony_ci  V8_INLINE void RecordComment(const char* string);
401cb0ef41Sopenharmony_ci  inline void Trap();
411cb0ef41Sopenharmony_ci  inline void DebugBreak();
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci  inline void Bind(Label* label);
441cb0ef41Sopenharmony_ci  // Binds the label without marking it as a valid jump target.
451cb0ef41Sopenharmony_ci  // This is only useful, when the position is already marked as a valid jump
461cb0ef41Sopenharmony_ci  // target (i.e. at the beginning of the bytecode).
471cb0ef41Sopenharmony_ci  inline void BindWithoutJumpTarget(Label* label);
481cb0ef41Sopenharmony_ci  // Marks the current position as a valid jump target on CFI enabled
491cb0ef41Sopenharmony_ci  // architectures.
501cb0ef41Sopenharmony_ci  inline void JumpTarget();
511cb0ef41Sopenharmony_ci  inline void Jump(Label* target, Label::Distance distance = Label::kFar);
521cb0ef41Sopenharmony_ci  inline void JumpIfRoot(Register value, RootIndex index, Label* target,
531cb0ef41Sopenharmony_ci                         Label::Distance distance = Label::kFar);
541cb0ef41Sopenharmony_ci  inline void JumpIfNotRoot(Register value, RootIndex index, Label* target,
551cb0ef41Sopenharmony_ci                            Label ::Distance distance = Label::kFar);
561cb0ef41Sopenharmony_ci  inline void JumpIfSmi(Register value, Label* target,
571cb0ef41Sopenharmony_ci                        Label::Distance distance = Label::kFar);
581cb0ef41Sopenharmony_ci  inline void JumpIfNotSmi(Register value, Label* target,
591cb0ef41Sopenharmony_ci                           Label::Distance distance = Label::kFar);
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci  inline void TestAndBranch(Register value, int mask, Condition cc,
621cb0ef41Sopenharmony_ci                            Label* target,
631cb0ef41Sopenharmony_ci                            Label::Distance distance = Label::kFar);
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ci  inline void JumpIf(Condition cc, Register lhs, const Operand& rhs,
661cb0ef41Sopenharmony_ci                     Label* target, Label::Distance distance = Label::kFar);
671cb0ef41Sopenharmony_ci  inline void JumpIfObjectType(Condition cc, Register object,
681cb0ef41Sopenharmony_ci                               InstanceType instance_type, Register map,
691cb0ef41Sopenharmony_ci                               Label* target,
701cb0ef41Sopenharmony_ci                               Label::Distance distance = Label::kFar);
711cb0ef41Sopenharmony_ci  inline void JumpIfInstanceType(Condition cc, Register map,
721cb0ef41Sopenharmony_ci                                 InstanceType instance_type, Label* target,
731cb0ef41Sopenharmony_ci                                 Label::Distance distance = Label::kFar);
741cb0ef41Sopenharmony_ci  inline void JumpIfPointer(Condition cc, Register value, MemOperand operand,
751cb0ef41Sopenharmony_ci                            Label* target,
761cb0ef41Sopenharmony_ci                            Label::Distance distance = Label::kFar);
771cb0ef41Sopenharmony_ci  inline Condition CheckSmi(Register value);
781cb0ef41Sopenharmony_ci  inline void JumpIfSmi(Condition cc, Register value, Smi smi, Label* target,
791cb0ef41Sopenharmony_ci                        Label::Distance distance = Label::kFar);
801cb0ef41Sopenharmony_ci  inline void JumpIfSmi(Condition cc, Register lhs, Register rhs, Label* target,
811cb0ef41Sopenharmony_ci                        Label::Distance distance = Label::kFar);
821cb0ef41Sopenharmony_ci  inline void JumpIfImmediate(Condition cc, Register left, int right,
831cb0ef41Sopenharmony_ci                              Label* target,
841cb0ef41Sopenharmony_ci                              Label::Distance distance = Label::kFar);
851cb0ef41Sopenharmony_ci  inline void JumpIfTagged(Condition cc, Register value, MemOperand operand,
861cb0ef41Sopenharmony_ci                           Label* target,
871cb0ef41Sopenharmony_ci                           Label::Distance distance = Label::kFar);
881cb0ef41Sopenharmony_ci  inline void JumpIfTagged(Condition cc, MemOperand operand, Register value,
891cb0ef41Sopenharmony_ci                           Label* target,
901cb0ef41Sopenharmony_ci                           Label::Distance distance = Label::kFar);
911cb0ef41Sopenharmony_ci  inline void JumpIfByte(Condition cc, Register value, int32_t byte,
921cb0ef41Sopenharmony_ci                         Label* target, Label::Distance distance = Label::kFar);
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_ci  inline void LoadMap(Register output, Register value);
951cb0ef41Sopenharmony_ci  inline void LoadRoot(Register output, RootIndex index);
961cb0ef41Sopenharmony_ci  inline void LoadNativeContextSlot(Register output, uint32_t index);
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_ci  inline void Move(Register output, Register source);
991cb0ef41Sopenharmony_ci  inline void Move(Register output, MemOperand operand);
1001cb0ef41Sopenharmony_ci  inline void Move(Register output, Smi value);
1011cb0ef41Sopenharmony_ci  inline void Move(Register output, TaggedIndex value);
1021cb0ef41Sopenharmony_ci  inline void Move(Register output, interpreter::Register source);
1031cb0ef41Sopenharmony_ci  inline void Move(interpreter::Register output, Register source);
1041cb0ef41Sopenharmony_ci  inline void Move(Register output, RootIndex source);
1051cb0ef41Sopenharmony_ci  inline void Move(MemOperand output, Register source);
1061cb0ef41Sopenharmony_ci  inline void Move(Register output, ExternalReference reference);
1071cb0ef41Sopenharmony_ci  inline void Move(Register output, Handle<HeapObject> value);
1081cb0ef41Sopenharmony_ci  inline void Move(Register output, int32_t immediate);
1091cb0ef41Sopenharmony_ci  inline void MoveMaybeSmi(Register output, Register source);
1101cb0ef41Sopenharmony_ci  inline void MoveSmi(Register output, Register source);
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ci  // Push the given values, in the given order. If the stack needs alignment
1131cb0ef41Sopenharmony_ci  // (looking at you Arm64), the stack is padded from the front (i.e. before the
1141cb0ef41Sopenharmony_ci  // first value is pushed).
1151cb0ef41Sopenharmony_ci  //
1161cb0ef41Sopenharmony_ci  // This supports pushing a RegisterList as the last value -- the list is
1171cb0ef41Sopenharmony_ci  // iterated and each interpreter Register is pushed.
1181cb0ef41Sopenharmony_ci  //
1191cb0ef41Sopenharmony_ci  // The total number of values pushed is returned. Note that this might be
1201cb0ef41Sopenharmony_ci  // different from sizeof(T...), specifically if there was a RegisterList.
1211cb0ef41Sopenharmony_ci  template <typename... T>
1221cb0ef41Sopenharmony_ci  inline int Push(T... vals);
1231cb0ef41Sopenharmony_ci
1241cb0ef41Sopenharmony_ci  // Like Push(vals...), but pushes in reverse order, to support our reversed
1251cb0ef41Sopenharmony_ci  // order argument JS calling convention. Doesn't return the number of
1261cb0ef41Sopenharmony_ci  // arguments pushed though.
1271cb0ef41Sopenharmony_ci  //
1281cb0ef41Sopenharmony_ci  // Note that padding is still inserted before the first pushed value (i.e. the
1291cb0ef41Sopenharmony_ci  // last value).
1301cb0ef41Sopenharmony_ci  template <typename... T>
1311cb0ef41Sopenharmony_ci  inline void PushReverse(T... vals);
1321cb0ef41Sopenharmony_ci
1331cb0ef41Sopenharmony_ci  // Pop values off the stack into the given registers.
1341cb0ef41Sopenharmony_ci  //
1351cb0ef41Sopenharmony_ci  // Note that this inserts into registers in the given order, i.e. in reverse
1361cb0ef41Sopenharmony_ci  // order if the registers were pushed. This means that to spill registers,
1371cb0ef41Sopenharmony_ci  // push and pop have to be in reverse order, e.g.
1381cb0ef41Sopenharmony_ci  //
1391cb0ef41Sopenharmony_ci  //     Push(r1, r2, ..., rN);
1401cb0ef41Sopenharmony_ci  //     ClobberRegisters();
1411cb0ef41Sopenharmony_ci  //     Pop(rN, ..., r2, r1);
1421cb0ef41Sopenharmony_ci  //
1431cb0ef41Sopenharmony_ci  // On stack-alignment architectures, any padding is popped off after the last
1441cb0ef41Sopenharmony_ci  // register. This the behaviour of Push, which means that the above code still
1451cb0ef41Sopenharmony_ci  // works even if the number of registers doesn't match stack alignment.
1461cb0ef41Sopenharmony_ci  template <typename... T>
1471cb0ef41Sopenharmony_ci  inline void Pop(T... registers);
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_ci  inline void CallBuiltin(Builtin builtin);
1501cb0ef41Sopenharmony_ci  inline void TailCallBuiltin(Builtin builtin);
1511cb0ef41Sopenharmony_ci  inline void CallRuntime(Runtime::FunctionId function, int nargs);
1521cb0ef41Sopenharmony_ci
1531cb0ef41Sopenharmony_ci  inline void LoadTaggedPointerField(Register output, Register source,
1541cb0ef41Sopenharmony_ci                                     int offset);
1551cb0ef41Sopenharmony_ci  inline void LoadTaggedSignedField(Register output, Register source,
1561cb0ef41Sopenharmony_ci                                    int offset);
1571cb0ef41Sopenharmony_ci  inline void LoadTaggedAnyField(Register output, Register source, int offset);
1581cb0ef41Sopenharmony_ci  inline void LoadWord16FieldZeroExtend(Register output, Register source,
1591cb0ef41Sopenharmony_ci                                        int offset);
1601cb0ef41Sopenharmony_ci  inline void LoadWord8Field(Register output, Register source, int offset);
1611cb0ef41Sopenharmony_ci  inline void StoreTaggedSignedField(Register target, int offset, Smi value);
1621cb0ef41Sopenharmony_ci  inline void StoreTaggedFieldWithWriteBarrier(Register target, int offset,
1631cb0ef41Sopenharmony_ci                                               Register value);
1641cb0ef41Sopenharmony_ci  inline void StoreTaggedFieldNoWriteBarrier(Register target, int offset,
1651cb0ef41Sopenharmony_ci                                             Register value);
1661cb0ef41Sopenharmony_ci  inline void LoadFixedArrayElement(Register output, Register array,
1671cb0ef41Sopenharmony_ci                                    int32_t index);
1681cb0ef41Sopenharmony_ci  inline void LoadPrototype(Register prototype, Register object);
1691cb0ef41Sopenharmony_ci
1701cb0ef41Sopenharmony_ci  // Loads the feedback cell from the function, and sets flags on add so that
1711cb0ef41Sopenharmony_ci  // we can compare afterward.
1721cb0ef41Sopenharmony_ci  inline void AddToInterruptBudgetAndJumpIfNotExceeded(
1731cb0ef41Sopenharmony_ci      int32_t weight, Label* skip_interrupt_label);
1741cb0ef41Sopenharmony_ci  inline void AddToInterruptBudgetAndJumpIfNotExceeded(
1751cb0ef41Sopenharmony_ci      Register weight, Label* skip_interrupt_label);
1761cb0ef41Sopenharmony_ci
1771cb0ef41Sopenharmony_ci  inline void AddSmi(Register lhs, Smi rhs);
1781cb0ef41Sopenharmony_ci  inline void SmiUntag(Register value);
1791cb0ef41Sopenharmony_ci  inline void SmiUntag(Register output, Register value);
1801cb0ef41Sopenharmony_ci
1811cb0ef41Sopenharmony_ci  inline void Word32And(Register output, Register lhs, int rhs);
1821cb0ef41Sopenharmony_ci
1831cb0ef41Sopenharmony_ci  inline void Switch(Register reg, int case_value_base, Label** labels,
1841cb0ef41Sopenharmony_ci                     int num_labels);
1851cb0ef41Sopenharmony_ci
1861cb0ef41Sopenharmony_ci  // Register operands.
1871cb0ef41Sopenharmony_ci  inline void LoadRegister(Register output, interpreter::Register source);
1881cb0ef41Sopenharmony_ci  inline void StoreRegister(interpreter::Register output, Register value);
1891cb0ef41Sopenharmony_ci
1901cb0ef41Sopenharmony_ci  // Frame values
1911cb0ef41Sopenharmony_ci  inline void LoadFunction(Register output);
1921cb0ef41Sopenharmony_ci  inline void LoadContext(Register output);
1931cb0ef41Sopenharmony_ci  inline void StoreContext(Register context);
1941cb0ef41Sopenharmony_ci
1951cb0ef41Sopenharmony_ci  inline static void EmitReturn(MacroAssembler* masm);
1961cb0ef41Sopenharmony_ci
1971cb0ef41Sopenharmony_ci  MacroAssembler* masm() { return masm_; }
1981cb0ef41Sopenharmony_ci
1991cb0ef41Sopenharmony_ci private:
2001cb0ef41Sopenharmony_ci  MacroAssembler* masm_;
2011cb0ef41Sopenharmony_ci  ScratchRegisterScope* scratch_register_scope_ = nullptr;
2021cb0ef41Sopenharmony_ci};
2031cb0ef41Sopenharmony_ci
2041cb0ef41Sopenharmony_ciclass SaveAccumulatorScope final {
2051cb0ef41Sopenharmony_ci public:
2061cb0ef41Sopenharmony_ci  inline explicit SaveAccumulatorScope(BaselineAssembler* assembler);
2071cb0ef41Sopenharmony_ci
2081cb0ef41Sopenharmony_ci  inline ~SaveAccumulatorScope();
2091cb0ef41Sopenharmony_ci
2101cb0ef41Sopenharmony_ci private:
2111cb0ef41Sopenharmony_ci  BaselineAssembler* assembler_;
2121cb0ef41Sopenharmony_ci};
2131cb0ef41Sopenharmony_ci
2141cb0ef41Sopenharmony_ciclass EnsureAccumulatorPreservedScope final {
2151cb0ef41Sopenharmony_ci public:
2161cb0ef41Sopenharmony_ci  inline explicit EnsureAccumulatorPreservedScope(BaselineAssembler* assembler);
2171cb0ef41Sopenharmony_ci
2181cb0ef41Sopenharmony_ci  inline ~EnsureAccumulatorPreservedScope();
2191cb0ef41Sopenharmony_ci
2201cb0ef41Sopenharmony_ci private:
2211cb0ef41Sopenharmony_ci  inline void AssertEqualToAccumulator(Register reg);
2221cb0ef41Sopenharmony_ci
2231cb0ef41Sopenharmony_ci  BaselineAssembler* assembler_;
2241cb0ef41Sopenharmony_ci#ifdef V8_CODE_COMMENTS
2251cb0ef41Sopenharmony_ci  Assembler::CodeComment comment_;
2261cb0ef41Sopenharmony_ci#endif
2271cb0ef41Sopenharmony_ci};
2281cb0ef41Sopenharmony_ci
2291cb0ef41Sopenharmony_ci}  // namespace baseline
2301cb0ef41Sopenharmony_ci}  // namespace internal
2311cb0ef41Sopenharmony_ci}  // namespace v8
2321cb0ef41Sopenharmony_ci
2331cb0ef41Sopenharmony_ci#endif
2341cb0ef41Sopenharmony_ci
2351cb0ef41Sopenharmony_ci#endif  // V8_BASELINE_BASELINE_ASSEMBLER_H_
236