1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#ifndef ECMASCRIPT_COMPILER_EXTENDED_ASSEMBLER_X64_H
17#define ECMASCRIPT_COMPILER_EXTENDED_ASSEMBLER_X64_H
18
19#include "ecmascript/compiler/assembler/x64/assembler_x64.h"
20#include "ecmascript/compiler/assembler_module.h"
21#include "ecmascript/compiler/bc_call_signature.h"
22
23namespace panda::ecmascript::x64 {
24// ExtendedAssembler implements frequently-used assembler macros with some extended usages.
25class ExtendedAssembler : public AssemblerX64 {
26public:
27    static constexpr int FRAME_SLOT_SIZE = 8;
28    ExtendedAssembler(Chunk *chunk, kungfu::AssemblerModule *module)
29        : AssemblerX64(chunk), module_(module)
30    {
31    }
32    void CallAssemblerStub(int id, bool isTail);
33    void BindAssemblerStub(int id);
34    void PushAlignBytes();
35    void PopAlignBytes();
36    void PushCppCalleeSaveRegisters();
37    void PopCppCalleeSaveRegisters();
38    void UpdateCalleeSaveRegisters();
39    void PushGhcCalleeSaveRegisters();
40    void PopGhcCalleeSaveRegisters();
41    void PushArgsWithArgv(Register argc, Register argv, Register operatorRegister);
42    void PushArgc(int32_t argc, Register tempArgcRegister);
43    void PushArgc(Register argcRegister, Register tempArgcRegister);
44
45    Register TempRegister()
46    {
47        if (tempInUse_) {
48            LOG_COMPILER(FATAL) << "temp register inuse.";
49            UNREACHABLE();
50        }
51        tempInUse_ = true;
52        return rax;
53    }
54    Register AvailableRegister1() const
55    {
56        // r10 is neither callee saved reegister nor argument register
57        return r10;
58    }
59    Register AvailableRegister2() const
60    {
61        // r11 is neither callee saved reegister nor argument register
62        return r11;
63    }
64    Register CppJSCallAvailableRegister1() const
65    {
66        return r13;
67    }
68    Register CppJSCallAvailableRegister2() const
69    {
70        return r14;
71    }
72    Register CallDispatcherArgument(kungfu::CallDispatchInputs index)
73    {
74        size_t i = static_cast<size_t>(index);
75        Register ret = isGhcCallingConv_ ? ghcJSCallDispacherArgs_[i] : cppJSCallDispacherArgs_[i];
76        if (ret == rInvalid) {
77            LOG_COMPILER(FATAL) << "x64 invalid call argument:" << i;
78        }
79        return ret;
80    }
81    Register GlueRegister()
82    {
83        return isGhcCallingConv_ ? r13 : rdi;
84    }
85
86    bool FromInterpreterHandler() const
87    {
88        return isGhcCallingConv_;
89    }
90
91private:
92    kungfu::AssemblerModule *module_;
93    bool isGhcCallingConv_ {false};
94    bool tempInUse_ {false};
95    friend class TempRegisterScope;
96
97    static constexpr size_t JS_CALL_DISPATCHER_ARGS_COUNT =
98        static_cast<size_t>(kungfu::CallDispatchInputs::NUM_OF_INPUTS);
99    static Register ghcJSCallDispacherArgs_[JS_CALL_DISPATCHER_ARGS_COUNT];
100    static Register cppJSCallDispacherArgs_[JS_CALL_DISPATCHER_ARGS_COUNT];
101};
102
103class TempRegisterScope {
104public:
105    explicit TempRegisterScope(ExtendedAssembler *assembler) : assembler_(assembler) {}
106    ~TempRegisterScope()
107    {
108        assembler_->tempInUse_ = false;
109    }
110
111    NO_COPY_SEMANTIC(TempRegisterScope);
112    NO_MOVE_SEMANTIC(TempRegisterScope);
113private:
114    ExtendedAssembler *assembler_;
115};
116}  // panda::ecmascript::x64
117#endif  // ECMASCRIPT_COMPILER_EXTENDED_ASSEMBLER_X64_H