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 #ifndef ECMASCRIPT_COMPILER_ASSEMBLER_H 16 #define ECMASCRIPT_COMPILER_ASSEMBLER_H 17 18 #include "ecmascript/mem/dyn_chunk.h" 19 20 namespace panda::ecmascript { 21 class GCStackMapRegisters { 22 public: 23 #if defined(PANDA_TARGET_AMD64) 24 static constexpr int SP = 7; 25 static constexpr int FP = 6; 26 #elif defined(PANDA_TARGET_ARM64) 27 static constexpr int SP = 31; /* x31 */ 28 static constexpr int FP = 29; /* x29 */ 29 #elif defined(PANDA_TARGET_ARM32) 30 static constexpr int SP = 13; 31 static constexpr int FP = 11; 32 #else 33 static constexpr int SP = -1; 34 static constexpr int FP = -1; 35 #endif 36 }; 37 38 enum Distance { 39 Near, 40 Far 41 }; 42 43 // When run from cpp to assembly code, there are some insts before the assembly frame is ready. 44 // When return from assembly code to cpp, there are some insts after the assembly frame is broken. 45 // And here are the numbers of insts. Only AsmInterpreterEntryFrame is dealt here, and there is no need 46 // for OptimizedEntryFrame because insts for OptimizedEntryFrame are negligible. 47 enum FrameCompletionPos : uint64_t { 48 // X64 49 X64CppToAsmInterp = 28, 50 X64AsmInterpToCpp = 9, 51 X64EntryFrameDuration = 70, 52 // ARM64 53 ARM64CppToAsmInterp = 56, 54 ARM64AsmInterpToCpp = 40, 55 ARM64EntryFrameDuration = 116, 56 }; 57 58 class Label { 59 public: IsBound()60 bool IsBound() const 61 { 62 return pos_ > 0; 63 } 64 IsLinked()65 bool IsLinked() const 66 { 67 return pos_ < 0; 68 } 69 IsLinkedNear()70 bool IsLinkedNear() const 71 { 72 return nearPos_ > 0; 73 } 74 GetPos()75 uint32_t GetPos() const 76 { 77 return static_cast<uint32_t>(pos_ - 1); 78 } 79 GetLinkedPos()80 uint32_t GetLinkedPos() const 81 { 82 ASSERT(!IsBound()); 83 return static_cast<uint32_t>(-pos_ - 1); 84 } 85 BindTo(int32_t pos)86 void BindTo(int32_t pos) 87 { 88 // +1 skip offset 0 89 pos_ = pos + 1; 90 } 91 LinkTo(int32_t pos)92 void LinkTo(int32_t pos) 93 { 94 // +1 skip offset 0 95 pos_ = - (pos + 1); 96 } 97 UnlinkNearPos()98 void UnlinkNearPos() 99 { 100 nearPos_ = 0; 101 } 102 LinkNearPos(uint32_t pos)103 void LinkNearPos(uint32_t pos) 104 { 105 // +1 skip offset 0 106 nearPos_ = pos + 1; 107 } 108 GetLinkedNearPos()109 uint32_t GetLinkedNearPos() const 110 { 111 ASSERT(!IsBound()); 112 return static_cast<uint32_t>(nearPos_ - 1); 113 } 114 115 private: 116 int32_t pos_ = 0; 117 uint32_t nearPos_ = 0; 118 }; 119 120 class Assembler { 121 public: Assembler(Chunk * chunk)122 explicit Assembler(Chunk *chunk) 123 : buffer_(chunk) {} 124 ~Assembler() = default; 125 EmitU8(uint8_t v)126 void EmitU8(uint8_t v) 127 { 128 buffer_.EmitChar(v); 129 } 130 EmitI8(int8_t v)131 void EmitI8(int8_t v) 132 { 133 buffer_.EmitChar(static_cast<uint8_t>(v)); 134 } 135 EmitU16(uint16_t v)136 void EmitU16(uint16_t v) 137 { 138 buffer_.EmitU16(v); 139 } 140 EmitU32(uint32_t v)141 void EmitU32(uint32_t v) 142 { 143 buffer_.EmitU32(v); 144 } 145 EmitI32(int32_t v)146 void EmitI32(int32_t v) 147 { 148 buffer_.EmitU32(static_cast<uint32_t>(v)); 149 } 150 EmitU64(uint64_t v)151 void EmitU64(uint64_t v) 152 { 153 buffer_.EmitU64(v); 154 } 155 PutI8(size_t offset,int8_t data)156 void PutI8(size_t offset, int8_t data) 157 { 158 buffer_.PutU8(offset, static_cast<int8_t>(data)); 159 } 160 PutI32(size_t offset,int32_t data)161 void PutI32(size_t offset, int32_t data) 162 { 163 buffer_.PutU32(offset, static_cast<int32_t>(data)); 164 } 165 GetU32(size_t offset)166 uint32_t GetU32(size_t offset) const 167 { 168 return buffer_.GetU32(offset); 169 } 170 GetI8(size_t offset)171 int8_t GetI8(size_t offset) const 172 { 173 return static_cast<int8_t>(buffer_.GetU8(offset)); 174 } 175 GetU8(size_t offset)176 uint8_t GetU8(size_t offset) const 177 { 178 return buffer_.GetU8(offset); 179 } 180 GetCurrentPosition()181 size_t GetCurrentPosition() const 182 { 183 return buffer_.GetSize(); 184 } 185 GetBegin()186 uint8_t *GetBegin() const 187 { 188 return buffer_.GetBegin(); 189 } 190 InRangeN(int32_t x,uint32_t n)191 static bool InRangeN(int32_t x, uint32_t n) 192 { 193 int32_t limit = 1 << (n - 1); 194 return (x >= -limit) && (x < limit); 195 } 196 InRange8(int32_t x)197 static bool InRange8(int32_t x) 198 { 199 // 8: range8 200 return InRangeN(x, 8); 201 } 202 GetFrameCompletionPos(uint64_t & headerSize,uint64_t & tailSize,uint64_t & entryDuration)203 static void GetFrameCompletionPos(uint64_t &headerSize, uint64_t &tailSize, uint64_t &entryDuration) 204 { 205 #if defined(PANDA_TARGET_AMD64) 206 headerSize = FrameCompletionPos::X64CppToAsmInterp; 207 tailSize = FrameCompletionPos::X64AsmInterpToCpp; 208 entryDuration = FrameCompletionPos::X64EntryFrameDuration; 209 #elif defined(PANDA_TARGET_ARM64) 210 headerSize = FrameCompletionPos::ARM64CppToAsmInterp; 211 tailSize = FrameCompletionPos::ARM64AsmInterpToCpp; 212 entryDuration = FrameCompletionPos::ARM64EntryFrameDuration; 213 #else 214 headerSize = 0; 215 tailSize = 0; 216 entryDuration = 0; 217 LOG_ECMA(FATAL) << "Assembler does not currently support other platforms, please run on x64 and arm64"; 218 #endif 219 } 220 private: 221 DynChunk buffer_; 222 }; 223 } // panda::ecmascript 224 #endif // ECMASCRIPT_COMPILER_ASSEMBLER_H 225