1 /* 2 * Copyright (c) 2021 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_REGEXP_OPCODE_H 17 #define ECMASCRIPT_REGEXP_OPCODE_H 18 19 #include <list> 20 21 #include "ecmascript/mem/dyn_chunk.h" 22 23 namespace panda { 24 namespace ecmascript { 25 class RegExpOpCode { 26 public: 27 enum : uint8_t { 28 OP_SAVE_START = 0U, 29 OP_SAVE_END, 30 OP_CHAR, 31 OP_GOTO, 32 OP_SPLIT_FIRST, 33 OP_SPLIT_NEXT, 34 OP_NEGATIVE_MATCH_AHEAD, 35 OP_MATCH_AHEAD, 36 OP_MATCH, 37 OP_LOOP, 38 OP_LOOP_GREEDY, 39 OP_PUSH_CHAR, 40 OP_CHECK_CHAR, 41 OP_PUSH, 42 OP_POP, 43 OP_SAVE_RESET, 44 OP_LINE_START, 45 OP_LINE_END, 46 OP_WORD_BOUNDARY, 47 OP_NOT_WORD_BOUNDARY, 48 OP_ALL, 49 OP_DOTS, 50 OP_MATCH_END, 51 OP_PREV, 52 OP_RANGE, 53 OP_BACKREFERENCE, 54 OP_BACKWARD_BACKREFERENCE, 55 OP_CHAR32, 56 OP_RANGE32, 57 OP_SPARSE, 58 OP_INVALID, 59 }; 60 61 static constexpr size_t OP_SIZE_ONE = 1; 62 static constexpr size_t OP_SIZE_TWO = 2; 63 static constexpr size_t OP_SIZE_THREE = 3; 64 static constexpr size_t OP_SIZE_FOUR = 4; 65 static constexpr size_t OP_SIZE_FIVE = 5; 66 static constexpr size_t OP_SIZE_SIX = 6; 67 static constexpr size_t OP_SIZE_EIGHT = 8; 68 static constexpr size_t OP_SIZE_NINE = 9; 69 static constexpr size_t OP_SIZE_THIRTEEN = 13; 70 71 RegExpOpCode(uint8_t opCode, int size); 72 NO_COPY_SEMANTIC(RegExpOpCode); 73 NO_MOVE_SEMANTIC(RegExpOpCode); 74 75 virtual ~RegExpOpCode() = default; 76 static RegExpOpCode *GetRegExpOpCode(const DynChunk &buf, int pcOffset); 77 static RegExpOpCode *GetRegExpOpCode(uint8_t opCode); 78 static void DumpRegExpOpCode(std::ostream &out, const DynChunk &buf); GetSize()79 inline uint8_t GetSize() const 80 { 81 return size_; 82 } GetOpCode()83 inline uint8_t GetOpCode() const 84 { 85 return opCode_; 86 } GetDynChunkfSize(const DynChunk & buf)87 inline int GetDynChunkfSize(const DynChunk &buf) const 88 { 89 return buf.size_; 90 } 91 virtual uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const = 0; 92 93 private: 94 uint8_t opCode_ {0}; 95 uint8_t size_ {0}; 96 }; 97 98 class SaveStartOpCode : public RegExpOpCode { 99 public: SaveStartOpCode()100 SaveStartOpCode() : RegExpOpCode(OP_SAVE_START, RegExpOpCode::OP_SIZE_TWO) {} 101 uint32_t EmitOpCode(DynChunk *buf, uint32_t para) const; 102 ~SaveStartOpCode() override = default; 103 NO_COPY_SEMANTIC(SaveStartOpCode); 104 NO_MOVE_SEMANTIC(SaveStartOpCode); 105 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 106 }; 107 108 class SaveEndOpCode : public RegExpOpCode { 109 public: SaveEndOpCode()110 SaveEndOpCode() : RegExpOpCode(OP_SAVE_END, RegExpOpCode::OP_SIZE_TWO) {} 111 uint32_t EmitOpCode(DynChunk *buf, uint32_t para) const; 112 ~SaveEndOpCode() override = default; 113 NO_COPY_SEMANTIC(SaveEndOpCode); 114 NO_MOVE_SEMANTIC(SaveEndOpCode); 115 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 116 }; 117 118 class CharOpCode : public RegExpOpCode { 119 public: CharOpCode()120 CharOpCode() : RegExpOpCode(OP_CHAR, RegExpOpCode::OP_SIZE_THREE) {} 121 uint32_t EmitOpCode(DynChunk *buf, uint32_t para) const; 122 ~CharOpCode() override = default; 123 NO_COPY_SEMANTIC(CharOpCode); 124 NO_MOVE_SEMANTIC(CharOpCode); 125 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 126 }; 127 128 class GotoOpCode : public RegExpOpCode { 129 public: GotoOpCode()130 GotoOpCode() : RegExpOpCode(OP_GOTO, RegExpOpCode::OP_SIZE_FIVE) {} 131 uint32_t EmitOpCode(DynChunk *buf, uint32_t para) const; 132 void UpdateOpPara(DynChunk *buf, uint32_t offset, uint32_t para) const; 133 ~GotoOpCode() override = default; 134 NO_COPY_SEMANTIC(GotoOpCode); 135 NO_MOVE_SEMANTIC(GotoOpCode); 136 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 137 }; 138 139 class SplitNextOpCode : public RegExpOpCode { 140 public: SplitNextOpCode()141 SplitNextOpCode() : RegExpOpCode(OP_SPLIT_NEXT, RegExpOpCode::OP_SIZE_FIVE) {} 142 uint32_t InsertOpCode(DynChunk *buf, uint32_t offset, uint32_t para) const; 143 uint32_t EmitOpCode(DynChunk *buf, uint32_t para) const; 144 ~SplitNextOpCode() override = default; 145 NO_COPY_SEMANTIC(SplitNextOpCode); 146 NO_MOVE_SEMANTIC(SplitNextOpCode); 147 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 148 }; 149 150 class SplitFirstOpCode : public RegExpOpCode { 151 public: SplitFirstOpCode()152 SplitFirstOpCode() : RegExpOpCode(OP_SPLIT_FIRST, RegExpOpCode::OP_SIZE_FIVE) {} 153 uint32_t InsertOpCode(DynChunk *buf, uint32_t offset, uint32_t para) const; 154 uint32_t EmitOpCode(DynChunk *buf, uint32_t para) const; 155 ~SplitFirstOpCode() override = default; 156 NO_COPY_SEMANTIC(SplitFirstOpCode); 157 NO_MOVE_SEMANTIC(SplitFirstOpCode); 158 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 159 }; 160 161 class PushOpCode : public RegExpOpCode { 162 public: PushOpCode()163 PushOpCode() : RegExpOpCode(OP_PUSH, RegExpOpCode::OP_SIZE_ONE) {} 164 uint32_t InsertOpCode(DynChunk *buf, uint32_t offset) const; 165 ~PushOpCode() override = default; 166 NO_COPY_SEMANTIC(PushOpCode); 167 NO_MOVE_SEMANTIC(PushOpCode); 168 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 169 }; 170 171 class PopOpCode : public RegExpOpCode { 172 public: PopOpCode()173 PopOpCode() : RegExpOpCode(OP_POP, RegExpOpCode::OP_SIZE_ONE) {} 174 uint32_t EmitOpCode(DynChunk *buf) const; 175 ~PopOpCode() override = default; 176 NO_COPY_SEMANTIC(PopOpCode); 177 NO_MOVE_SEMANTIC(PopOpCode); 178 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 179 }; 180 181 class PushCharOpCode : public RegExpOpCode { 182 public: PushCharOpCode()183 PushCharOpCode() : RegExpOpCode(OP_PUSH_CHAR, RegExpOpCode::OP_SIZE_ONE) {} 184 uint32_t InsertOpCode(DynChunk *buf, uint32_t offset) const; 185 ~PushCharOpCode() override = default; 186 NO_COPY_SEMANTIC(PushCharOpCode); 187 NO_MOVE_SEMANTIC(PushCharOpCode); 188 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 189 }; 190 191 class CheckCharOpCode : public RegExpOpCode { 192 public: CheckCharOpCode()193 CheckCharOpCode() : RegExpOpCode(OP_CHECK_CHAR, RegExpOpCode::OP_SIZE_FIVE) {} 194 uint32_t EmitOpCode(DynChunk *buf, uint32_t offset) const; 195 ~CheckCharOpCode() override = default; 196 NO_COPY_SEMANTIC(CheckCharOpCode); 197 NO_MOVE_SEMANTIC(CheckCharOpCode); 198 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 199 }; 200 201 class LoopOpCode : public RegExpOpCode { 202 public: LoopOpCode()203 LoopOpCode() : RegExpOpCode(OP_LOOP, RegExpOpCode::OP_SIZE_THIRTEEN) {} 204 uint32_t EmitOpCode(DynChunk *buf, uint32_t start, uint32_t min, uint32_t max) const; 205 ~LoopOpCode() override = default; 206 NO_COPY_SEMANTIC(LoopOpCode); 207 NO_MOVE_SEMANTIC(LoopOpCode); 208 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 209 }; 210 211 class LoopGreedyOpCode : public RegExpOpCode { 212 public: LoopGreedyOpCode()213 LoopGreedyOpCode() : RegExpOpCode(OP_LOOP_GREEDY, RegExpOpCode::OP_SIZE_THIRTEEN) {} 214 uint32_t EmitOpCode(DynChunk *buf, uint32_t start, uint32_t min, uint32_t max) const; 215 ~LoopGreedyOpCode() override = default; 216 NO_COPY_SEMANTIC(LoopGreedyOpCode); 217 NO_MOVE_SEMANTIC(LoopGreedyOpCode); 218 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 219 }; 220 221 class SaveResetOpCode : public RegExpOpCode { 222 public: SaveResetOpCode()223 SaveResetOpCode() : RegExpOpCode(OP_SAVE_RESET, RegExpOpCode::OP_SIZE_THREE) {} 224 uint32_t InsertOpCode(DynChunk *buf, uint32_t offset, uint32_t start, uint32_t end) const; 225 ~SaveResetOpCode() override = default; 226 NO_COPY_SEMANTIC(SaveResetOpCode); 227 NO_MOVE_SEMANTIC(SaveResetOpCode); 228 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 229 }; 230 231 class MatchOpCode : public RegExpOpCode { 232 public: MatchOpCode()233 MatchOpCode() : RegExpOpCode(OP_MATCH, RegExpOpCode::OP_SIZE_ONE) {} 234 uint32_t EmitOpCode(DynChunk *buf, uint32_t para) const; 235 ~MatchOpCode() override = default; 236 NO_COPY_SEMANTIC(MatchOpCode); 237 NO_MOVE_SEMANTIC(MatchOpCode); 238 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 239 }; 240 241 class MatchEndOpCode : public RegExpOpCode { 242 public: MatchEndOpCode()243 MatchEndOpCode() : RegExpOpCode(OP_MATCH_END, RegExpOpCode::OP_SIZE_ONE) {} 244 uint32_t EmitOpCode(DynChunk *buf, uint32_t para) const; 245 ~MatchEndOpCode() override = default; 246 NO_COPY_SEMANTIC(MatchEndOpCode); 247 NO_MOVE_SEMANTIC(MatchEndOpCode); 248 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 249 }; 250 251 class LineStartOpCode : public RegExpOpCode { 252 public: LineStartOpCode()253 LineStartOpCode() : RegExpOpCode(OP_LINE_START, RegExpOpCode::OP_SIZE_ONE) {} 254 uint32_t EmitOpCode(DynChunk *buf, uint32_t para) const; 255 ~LineStartOpCode() override = default; 256 NO_COPY_SEMANTIC(LineStartOpCode); 257 NO_MOVE_SEMANTIC(LineStartOpCode); 258 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 259 }; 260 261 class LineEndOpCode : public RegExpOpCode { 262 public: LineEndOpCode()263 LineEndOpCode() : RegExpOpCode(OP_LINE_END, RegExpOpCode::OP_SIZE_ONE) {} 264 uint32_t EmitOpCode(DynChunk *buf, uint32_t para) const; 265 ~LineEndOpCode() override = default; 266 NO_COPY_SEMANTIC(LineEndOpCode); 267 NO_MOVE_SEMANTIC(LineEndOpCode); 268 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 269 }; 270 271 class WordBoundaryOpCode : public RegExpOpCode { 272 public: WordBoundaryOpCode()273 WordBoundaryOpCode() : RegExpOpCode(OP_WORD_BOUNDARY, RegExpOpCode::OP_SIZE_ONE) {} 274 uint32_t EmitOpCode(DynChunk *buf, uint32_t para) const; 275 ~WordBoundaryOpCode() override = default; 276 NO_COPY_SEMANTIC(WordBoundaryOpCode); 277 NO_MOVE_SEMANTIC(WordBoundaryOpCode); 278 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 279 }; 280 281 class NotWordBoundaryOpCode : public RegExpOpCode { 282 public: NotWordBoundaryOpCode()283 NotWordBoundaryOpCode() : RegExpOpCode(OP_NOT_WORD_BOUNDARY, RegExpOpCode::OP_SIZE_ONE) {} 284 uint32_t EmitOpCode(DynChunk *buf, uint32_t para) const; 285 ~NotWordBoundaryOpCode() override = default; 286 NO_COPY_SEMANTIC(NotWordBoundaryOpCode); 287 NO_MOVE_SEMANTIC(NotWordBoundaryOpCode); 288 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 289 }; 290 291 class AllOpCode : public RegExpOpCode { 292 public: AllOpCode()293 AllOpCode() : RegExpOpCode(OP_ALL, RegExpOpCode::OP_SIZE_ONE) {} 294 uint32_t EmitOpCode(DynChunk *buf, uint32_t para) const; 295 ~AllOpCode() override = default; 296 NO_COPY_SEMANTIC(AllOpCode); 297 NO_MOVE_SEMANTIC(AllOpCode); 298 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 299 }; 300 301 class DotsOpCode : public RegExpOpCode { 302 public: DotsOpCode()303 DotsOpCode() : RegExpOpCode(OP_DOTS, RegExpOpCode::OP_SIZE_ONE) {} 304 uint32_t EmitOpCode(DynChunk *buf, uint32_t para) const; 305 ~DotsOpCode() override = default; 306 NO_COPY_SEMANTIC(DotsOpCode); 307 NO_MOVE_SEMANTIC(DotsOpCode); 308 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 309 }; 310 311 class RangeSet { 312 public: 313 RangeSet() = default; RangeSet(uint32_t value)314 explicit RangeSet(uint32_t value) 315 { 316 Insert(value, value); 317 } RangeSet(uint32_t start,uint32_t end)318 RangeSet(uint32_t start, uint32_t end) 319 { 320 Insert(start, end); 321 } RangeSet(const std::list<std::pair<uint32_t,uint32_t>> & rangeSet)322 explicit RangeSet(const std::list<std::pair<uint32_t, uint32_t>> &rangeSet) 323 { 324 rangeSet_ = rangeSet; 325 } 326 ~RangeSet() = default; 327 IsIntersect(uint64_t start,uint64_t end,uint64_t start1,uint64_t end1)328 inline bool IsIntersect(uint64_t start, uint64_t end, uint64_t start1, uint64_t end1) const 329 { 330 return ((start1 > start) && (start1 < end)) || ((start > start1) && (start < end1)); 331 } IsAdjacent(uint64_t start,uint64_t end,uint64_t start1,uint64_t end1)332 inline bool IsAdjacent(uint64_t start, uint64_t end, uint64_t start1, uint64_t end1) const 333 { 334 return ((end == start1 || (end + 1) == start1)) || ((end1 == start) || (end1 + 1 == start)); 335 } 336 337 inline bool operator==(const RangeSet &other) const 338 { 339 return rangeSet_ == other.rangeSet_; 340 } 341 IsContain(uint32_t value)342 inline bool IsContain(uint32_t value) const 343 { 344 for (auto range : rangeSet_) { 345 if (value >= range.first && value <= range.second) { 346 return true; 347 } 348 } 349 return false; 350 } HighestValue()351 inline uint32_t HighestValue() const 352 { 353 if (!rangeSet_.empty()) { 354 return rangeSet_.back().second; 355 } 356 return 0; 357 } 358 RangeSet(RangeSet const &) = default; 359 RangeSet &operator=(RangeSet const &) = default; 360 RangeSet(RangeSet &&) = default; 361 RangeSet &operator=(RangeSet &&) = default; 362 363 void Insert(uint32_t start, uint32_t end); 364 void Insert(const RangeSet &s1); 365 void Invert(bool isUtf16); 366 void Inter(RangeSet &cr, const RangeSet &s1); 367 void Compress(); 368 369 private: 370 friend class RangeOpCode; 371 friend class Range32OpCode; 372 std::list<std::pair<uint32_t, uint32_t>> rangeSet_ {}; 373 }; 374 375 class RangeOpCode : public RegExpOpCode { 376 public: RangeOpCode()377 RangeOpCode() : RegExpOpCode(OP_RANGE, RegExpOpCode::OP_SIZE_ONE) {} 378 ~RangeOpCode() override = default; 379 NO_COPY_SEMANTIC(RangeOpCode); 380 NO_MOVE_SEMANTIC(RangeOpCode); 381 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 382 uint32_t InsertOpCode(DynChunk *buf, const RangeSet &rangeSet) const; 383 }; 384 385 class MatchAheadOpCode : public RegExpOpCode { 386 public: MatchAheadOpCode()387 MatchAheadOpCode() : RegExpOpCode(OP_MATCH_AHEAD, RegExpOpCode::OP_SIZE_FIVE) {} 388 ~MatchAheadOpCode() override = default; 389 NO_COPY_SEMANTIC(MatchAheadOpCode); 390 NO_MOVE_SEMANTIC(MatchAheadOpCode); 391 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 392 uint32_t InsertOpCode(DynChunk *buf, uint32_t offset, uint32_t para) const; 393 }; 394 395 class NegativeMatchAheadOpCode : public RegExpOpCode { 396 public: NegativeMatchAheadOpCode()397 NegativeMatchAheadOpCode() : RegExpOpCode(OP_NEGATIVE_MATCH_AHEAD, RegExpOpCode::OP_SIZE_FIVE) {} 398 uint32_t InsertOpCode(DynChunk *buf, uint32_t offset, uint32_t para) const; 399 ~NegativeMatchAheadOpCode() override = default; 400 NO_COPY_SEMANTIC(NegativeMatchAheadOpCode); 401 NO_MOVE_SEMANTIC(NegativeMatchAheadOpCode); 402 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 403 }; 404 405 class PrevOpCode : public RegExpOpCode { 406 public: PrevOpCode()407 PrevOpCode() : RegExpOpCode(OP_PREV, RegExpOpCode::OP_SIZE_ONE) {} 408 uint32_t EmitOpCode(DynChunk *buf, uint32_t para) const; 409 ~PrevOpCode() override = default; 410 NO_COPY_SEMANTIC(PrevOpCode); 411 NO_MOVE_SEMANTIC(PrevOpCode); 412 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 413 }; 414 415 class BackReferenceOpCode : public RegExpOpCode { 416 public: BackReferenceOpCode()417 BackReferenceOpCode() : RegExpOpCode(OP_BACKREFERENCE, RegExpOpCode::OP_SIZE_TWO) {} 418 uint32_t EmitOpCode(DynChunk *buf, uint32_t para) const; 419 ~BackReferenceOpCode() override = default; 420 NO_COPY_SEMANTIC(BackReferenceOpCode); 421 NO_MOVE_SEMANTIC(BackReferenceOpCode); 422 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 423 }; 424 425 class BackwardBackReferenceOpCode : public RegExpOpCode { 426 public: BackwardBackReferenceOpCode()427 BackwardBackReferenceOpCode() : RegExpOpCode(OP_BACKWARD_BACKREFERENCE, RegExpOpCode::OP_SIZE_TWO) {} 428 uint32_t EmitOpCode(DynChunk *buf, uint32_t para) const; 429 ~BackwardBackReferenceOpCode() override = default; 430 NO_COPY_SEMANTIC(BackwardBackReferenceOpCode); 431 NO_MOVE_SEMANTIC(BackwardBackReferenceOpCode); 432 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 433 }; 434 435 class Char32OpCode : public RegExpOpCode { 436 public: Char32OpCode()437 Char32OpCode() : RegExpOpCode(OP_CHAR32, RegExpOpCode::OP_SIZE_FIVE) {} 438 uint32_t EmitOpCode(DynChunk *buf, uint32_t para) const; 439 ~Char32OpCode() override = default; 440 NO_COPY_SEMANTIC(Char32OpCode); 441 NO_MOVE_SEMANTIC(Char32OpCode); 442 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 443 }; 444 445 class Range32OpCode : public RegExpOpCode { 446 public: Range32OpCode()447 Range32OpCode() : RegExpOpCode(OP_RANGE32, RegExpOpCode::OP_SIZE_ONE) {} 448 ~Range32OpCode() override = default; 449 NO_COPY_SEMANTIC(Range32OpCode); 450 NO_MOVE_SEMANTIC(Range32OpCode); 451 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 452 uint32_t InsertOpCode(DynChunk *buf, const RangeSet &rangeSet) const; 453 }; 454 455 class SparseOpCode : public RegExpOpCode { 456 public: SparseOpCode()457 SparseOpCode() : RegExpOpCode(OP_RANGE32, RegExpOpCode::OP_SIZE_ONE) {} 458 ~SparseOpCode() override = default; 459 NO_COPY_SEMANTIC(SparseOpCode); 460 NO_MOVE_SEMANTIC(SparseOpCode); 461 uint32_t DumpOpCode(std::ostream &out, const DynChunk &buf, uint32_t offset) const override; 462 }; 463 } // namespace ecmascript 464 } // namespace panda 465 #endif 466