• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_BYTECODES_H
17 #define ECMASCRIPT_COMPILER_BYTECODES_H
18 
19 #include <cstddef>
20 #include <array>
21 
22 #include "libpandabase/macros.h"
23 #include "libpandabase/utils/bit_field.h"
24 #include "libpandafile/bytecode_instruction-inl.h"
25 #include "ecmascript/js_tagged_value.h"
26 
27 namespace panda::ecmascript::kungfu {
28 using VRegIDType = uint32_t;
29 using ICSlotIdType = uint16_t;
30 using ImmValueType = uint64_t;
31 using EcmaOpcode = BytecodeInstruction::Opcode;
32 
33 class BytecodeCircuitBuilder;
34 class Bytecodes;
35 class BytecodeInfo;
36 class BytecodeIterator;
37 enum BytecodeFlags : uint32_t {
38     READ_ACC = 1 << 0, // 1: flag bit
39     WRITE_ACC = 1 << 1, // 1: flag 1
40     SUPPORT_DEOPT = 1 << 2, // 2: flag 2
41     GENERAL_BC = 1 << 3,
42     READ_THIS_OBJECT = 1 << 4,
43     NO_SIDE_EFFECTS = 1 << 5,
44     READ_ENV = 1 << 7,
45     WRITE_ENV = 1 << 8,
46 };
47 
48 enum BytecodeKind : uint32_t {
49     GENERAL = 0,
50     THROW_BC,
51     RETURN_BC,
52     JUMP_IMM,
53     CONDITIONAL_JUMP,
54     MOV,
55     SET_CONSTANT,
56     SUSPEND,
57     RESUME,
58     DISCARDED,
59 };
60 
61 class BytecodeMetaData {
62 public:
63     static constexpr uint32_t MAX_OPCODE_SIZE = 16;
64     static constexpr uint32_t MAX_SIZE_BITS = 4;
65     static constexpr uint32_t BYTECODE_FLAGS_SIZE = 9;
66     static constexpr uint32_t BYTECODE_KIND_SIZE = 4;
67 
68     using OpcodeField = panda::BitField<EcmaOpcode, 0, MAX_OPCODE_SIZE>;
69     using SizeField = OpcodeField::NextField<size_t, MAX_SIZE_BITS>;
70     using KindField = SizeField::NextField<BytecodeKind, BYTECODE_KIND_SIZE>;
71     using FlagsField = KindField::NextField<BytecodeFlags, BYTECODE_FLAGS_SIZE>;
72 
HasAccIn()73     bool HasAccIn() const
74     {
75         return HasFlag(BytecodeFlags::READ_ACC);
76     }
77 
IsNoSideEffects()78     bool IsNoSideEffects() const
79     {
80         return HasFlag(BytecodeFlags::NO_SIDE_EFFECTS);
81     }
82 
HasThisIn()83     bool HasThisIn() const
84     {
85         return HasFlag(BytecodeFlags::READ_THIS_OBJECT);
86     }
87 
HasAccOut()88     bool HasAccOut() const
89     {
90         return HasFlag(BytecodeFlags::WRITE_ACC);
91     }
92 
HasEnvIn()93     bool HasEnvIn() const
94     {
95         return HasFlag(BytecodeFlags::READ_ENV);
96     }
97 
HasEnvOut()98     bool HasEnvOut() const
99     {
100         return HasFlag(BytecodeFlags::WRITE_ENV);
101     }
102 
IsMov()103     bool IsMov() const
104     {
105         return GetKind() == BytecodeKind::MOV;
106     }
107 
IsReturn()108     bool IsReturn() const
109     {
110         return GetKind() == BytecodeKind::RETURN_BC;
111     }
112 
IsThrow()113     bool IsThrow() const
114     {
115         return GetKind() == BytecodeKind::THROW_BC;
116     }
117 
IsJump()118     bool IsJump() const
119     {
120         return IsJumpImm() || IsCondJump();
121     }
122 
IsCondJump()123     bool IsCondJump() const
124     {
125         return GetKind() == BytecodeKind::CONDITIONAL_JUMP;
126     }
127 
IsJumpImm()128     bool IsJumpImm() const
129     {
130         return GetKind() == BytecodeKind::JUMP_IMM;
131     }
132 
IsSuspend()133     bool IsSuspend() const
134     {
135         return GetKind() == BytecodeKind::SUSPEND;
136     }
137 
IsSetConstant()138     bool IsSetConstant() const
139     {
140         return GetKind() == BytecodeKind::SET_CONSTANT;
141     }
142 
SupportDeopt()143     bool SupportDeopt() const
144     {
145         return HasFlag(BytecodeFlags::SUPPORT_DEOPT);
146     }
147 
GetSize()148     size_t GetSize() const
149     {
150         return SizeField::Get(value_);
151     }
152 
IsGeneral()153     bool IsGeneral() const
154     {
155         return HasFlag(BytecodeFlags::GENERAL_BC);
156     }
157 
IsGeneratorRelative()158     bool IsGeneratorRelative() const
159     {
160         return (GetKind() == BytecodeKind::RESUME) || (GetKind() == BytecodeKind::SUSPEND);
161     }
162 
IsDiscarded()163     bool IsDiscarded() const
164     {
165         return GetKind() == BytecodeKind::DISCARDED;
166     }
167 
GetOpcode()168     inline EcmaOpcode GetOpcode() const
169     {
170         return OpcodeField::Get(value_);
171     }
172 
173 private:
174     BytecodeMetaData() = default;
175     DEFAULT_NOEXCEPT_MOVE_SEMANTIC(BytecodeMetaData);
176     DEFAULT_COPY_SEMANTIC(BytecodeMetaData);
BytecodeMetaData(uint64_t value)177     BytecodeMetaData(uint64_t value) : value_(value) {}
178 
179     static BytecodeMetaData InitBytecodeMetaData(const uint8_t *pc);
180 
HasFlag(BytecodeFlags flag)181     inline bool HasFlag(BytecodeFlags flag) const
182     {
183         return (GetFlags() & flag) == flag;
184     }
185 
GetFlags()186     inline BytecodeFlags GetFlags() const
187     {
188         return FlagsField::Get(value_);
189     }
190 
GetKind()191     inline BytecodeKind GetKind() const
192     {
193         return KindField::Get(value_);
194     }
195 
196     uint64_t value_ {0};
197     friend class Bytecodes;
198     friend class BytecodeInfo;
199     friend class BytecodeCircuitBuilder;
200 };
201 
202 class Bytecodes {
203 public:
204     static constexpr uint32_t NUM_BYTECODES = 0xFF;
205     static constexpr uint32_t OPCODE_MASK = 0xFF00;
206     static constexpr uint32_t BYTE_SIZE = 8;
207     static constexpr uint32_t CALLRUNTIME_PREFIX_OPCODE_INDEX = 251;
208     static constexpr uint32_t DEPRECATED_PREFIX_OPCODE_INDEX = 252;
209     static constexpr uint32_t WIDE_PREFIX_OPCODE_INDEX = 253;
210     static constexpr uint32_t THROW_PREFIX_OPCODE_INDEX = 254;
211     static constexpr uint32_t MIN_PREFIX_OPCODE_INDEX = CALLRUNTIME_PREFIX_OPCODE_INDEX;
212 
213     static constexpr uint32_t LAST_OPCODE =
214         static_cast<uint32_t>(EcmaOpcode::GETASYNCITERATOR_IMM8);
215     static constexpr uint32_t LAST_DEPRECATED_OPCODE =
216         static_cast<uint32_t>(EcmaOpcode::DEPRECATED_DYNAMICIMPORT_PREF_V8);
217     static constexpr uint32_t LAST_WIDE_OPCODE =
218         static_cast<uint32_t>(EcmaOpcode::WIDE_STPATCHVAR_PREF_IMM16);
219     static constexpr uint32_t LAST_THROW_OPCODE =
220         static_cast<uint32_t>(EcmaOpcode::THROW_UNDEFINEDIFHOLEWITHNAME_PREF_ID16);
221     static constexpr uint32_t LAST_CALLRUNTIME_OPCODE =
222         static_cast<uint32_t>(EcmaOpcode::CALLRUNTIME_NOTIFYCONCURRENTRESULT_PREF_NONE);
223 
224     static_assert(CALLRUNTIME_PREFIX_OPCODE_INDEX ==
225         static_cast<uint32_t>(EcmaOpcode::CALLRUNTIME_NOTIFYCONCURRENTRESULT_PREF_NONE));
226     static_assert(DEPRECATED_PREFIX_OPCODE_INDEX ==
227         static_cast<uint32_t>(EcmaOpcode::DEPRECATED_LDLEXENV_PREF_NONE));
228     static_assert(WIDE_PREFIX_OPCODE_INDEX ==
229         static_cast<uint32_t>(EcmaOpcode::WIDE_CREATEOBJECTWITHEXCLUDEDKEYS_PREF_IMM16_V8_V8));
230     static_assert(THROW_PREFIX_OPCODE_INDEX ==
231         static_cast<uint32_t>(EcmaOpcode::THROW_PREF_NONE));
232 
233     Bytecodes();
234     Bytecodes(const Bytecodes&) = delete;
235     void operator=(const Bytecodes&) = delete;
236 
GetOpcode(const uint8_t * pc)237     static EcmaOpcode GetOpcode(const uint8_t *pc)
238     {
239         uint8_t primary = ReadByte(pc);
240         if (primary >= MIN_PREFIX_OPCODE_INDEX) {
241             uint8_t secondary = ReadByte1(pc);
242             return static_cast<EcmaOpcode>((secondary << 8U) | primary); // 8: byte size
243         }
244         return static_cast<EcmaOpcode>(primary);
245     }
246 
GetBytecodeMetaData(const uint8_t * pc)247     BytecodeMetaData GetBytecodeMetaData(const uint8_t *pc) const
248     {
249         uint8_t primary = ReadByte(pc);
250         if (primary >= MIN_PREFIX_OPCODE_INDEX) {
251             uint8_t secondary = ReadByte1(pc);
252             if (primary == CALLRUNTIME_PREFIX_OPCODE_INDEX) {
253                 return callRuntimeBytecodes_[secondary];
254             } else if (primary == DEPRECATED_PREFIX_OPCODE_INDEX) {
255                 return deprecatedBytecodes_[secondary];
256             } else if (primary == WIDE_PREFIX_OPCODE_INDEX) {
257                 return wideBytecodes_[secondary];
258             } else {
259                 ASSERT(primary == THROW_PREFIX_OPCODE_INDEX);
260                 return throwBytecodes_[secondary];
261             }
262         }
263         return bytecodes_[primary];
264     }
265 
266 private:
ReadByte(const uint8_t * pc)267     static uint8_t ReadByte(const uint8_t *pc)
268     {
269         return *pc;
270     }
ReadByte1(const uint8_t * pc)271     static uint8_t ReadByte1(const uint8_t *pc)
272     {
273         return *(pc + 1); // 1: byte1
274     }
275     BytecodeMetaData InitBytecodeMetaData(const uint8_t *pc);
276 
277     std::array<BytecodeMetaData, NUM_BYTECODES> bytecodes_{};
278     std::array<BytecodeMetaData, NUM_BYTECODES> callRuntimeBytecodes_{};
279     std::array<BytecodeMetaData, NUM_BYTECODES> deprecatedBytecodes_{};
280     std::array<BytecodeMetaData, NUM_BYTECODES> wideBytecodes_{};
281     std::array<BytecodeMetaData, NUM_BYTECODES> throwBytecodes_{};
282 };
283 
284 enum class ConstDataIDType : uint8_t {
285     StringIDType,
286     MethodIDType,
287     ArrayLiteralIDType,
288     ObjectLiteralIDType,
289     ClassLiteralIDType,
290 };
291 
292 class VirtualRegister {
293 public:
VirtualRegister(VRegIDType id)294     explicit VirtualRegister(VRegIDType id) : id_(id)
295     {
296     }
297     ~VirtualRegister() = default;
298 
SetId(VRegIDType id)299     void SetId(VRegIDType id)
300     {
301         id_ = id;
302     }
303 
GetId()304     VRegIDType GetId() const
305     {
306         return id_;
307     }
308 
309 private:
310     VRegIDType id_;
311 };
312 
313 class Immediate {
314 public:
Immediate(ImmValueType value)315     explicit Immediate(ImmValueType value) : value_(value)
316     {
317     }
318     ~Immediate() = default;
319 
SetValue(ImmValueType value)320     void SetValue(ImmValueType value)
321     {
322         value_ = value;
323     }
324 
ToJSTaggedValueInt()325     ImmValueType ToJSTaggedValueInt() const
326     {
327         return value_ | JSTaggedValue::TAG_INT;
328     }
329 
ToJSTaggedValueDouble()330     ImmValueType ToJSTaggedValueDouble() const
331     {
332         return JSTaggedValue(bit_cast<double>(value_)).GetRawData();
333     }
334 
GetValue()335     ImmValueType GetValue() const
336     {
337         return value_;
338     }
339 
340 private:
341     ImmValueType value_;
342 };
343 
344 
345 class ICSlotId {
346 public:
ICSlotId(ICSlotIdType id)347     explicit ICSlotId(ICSlotIdType id) : id_(id)
348     {
349     }
350     ~ICSlotId() = default;
351 
SetId(ICSlotIdType id)352     void SetId(ICSlotIdType id)
353     {
354         id_ = id;
355     }
356 
GetId()357     ICSlotIdType GetId() const
358     {
359         return id_;
360     }
361 
362 private:
363     ICSlotIdType id_;
364 };
365 
366 class ConstDataId {
367 public:
ConstDataId(ConstDataIDType type,uint16_t id)368     explicit ConstDataId(ConstDataIDType type, uint16_t id)
369         :type_(type), id_(id)
370     {
371     }
372 
ConstDataId(uint64_t bitfield)373     explicit ConstDataId(uint64_t bitfield)
374     {
375         type_ = ConstDataIDType(bitfield >> TYPE_SHIFT);
376         id_ = bitfield & ((1 << TYPE_SHIFT) - 1);
377     }
378 
379     ~ConstDataId() = default;
380 
SetId(uint16_t id)381     void SetId(uint16_t id)
382     {
383         id_ = id;
384     }
385 
GetId()386     uint16_t GetId() const
387     {
388         return id_;
389     }
390 
SetType(ConstDataIDType type)391     void SetType(ConstDataIDType type)
392     {
393         type_ = type;
394     }
395 
GetType()396     ConstDataIDType GetType() const
397     {
398         return type_;
399     }
400 
IsStringId()401     bool IsStringId() const
402     {
403         return type_ == ConstDataIDType::StringIDType;
404     }
405 
IsMethodId()406     bool IsMethodId() const
407     {
408         return type_ == ConstDataIDType::MethodIDType;
409     }
410 
IsClassLiteraId()411     bool IsClassLiteraId() const
412     {
413         return type_ == ConstDataIDType::ClassLiteralIDType;
414     }
415 
IsObjectLiteralID()416     bool IsObjectLiteralID() const
417     {
418         return type_ == ConstDataIDType::ObjectLiteralIDType;
419     }
420 
IsArrayLiteralID()421     bool IsArrayLiteralID() const
422     {
423         return type_ == ConstDataIDType::ArrayLiteralIDType;
424     }
425 
CaculateBitField()426     uint64_t CaculateBitField() const
427     {
428         return (static_cast<uint8_t>(type_) << TYPE_SHIFT) | id_;
429     }
430 
431 private:
432     static constexpr int TYPE_SHIFT = 16;
433     ConstDataIDType type_;
434     uint16_t id_;
435 };
436 
437 class BytecodeInfo {
438 public:
439     // set of id, immediate and read register
440     std::vector<std::variant<ConstDataId, ICSlotId, Immediate, VirtualRegister>> inputs {};
441     std::vector<VRegIDType> vregOut {}; // write register
442 
Deopt()443     bool Deopt() const
444     {
445         return metaData_.SupportDeopt();
446     }
447 
AccOut()448     bool AccOut() const
449     {
450         return metaData_.HasAccOut();
451     }
452 
AccIn()453     bool AccIn() const
454     {
455         return metaData_.HasAccIn();
456     }
457 
EnvIn()458     bool EnvIn() const
459     {
460         return metaData_.HasEnvIn();
461     }
462 
EnvOut()463     bool EnvOut() const
464     {
465         return metaData_.HasEnvOut();
466     }
467 
NoSideEffects()468     bool NoSideEffects() const
469     {
470         return metaData_.IsNoSideEffects();
471     }
472 
ThisObjectIn()473     bool ThisObjectIn() const
474     {
475         return metaData_.HasThisIn();
476     }
477 
GetSize()478     size_t GetSize() const
479     {
480         return metaData_.GetSize();
481     }
482 
IsDef()483     bool IsDef() const
484     {
485         return (!vregOut.empty()) || AccOut();
486     }
487 
IsOut(VRegIDType reg,uint32_t index)488     bool IsOut(VRegIDType reg, uint32_t index) const
489     {
490         bool isDefined = (!vregOut.empty() && (reg == vregOut.at(index)));
491         return isDefined;
492     }
493 
IsMov()494     bool IsMov() const
495     {
496         return metaData_.IsMov();
497     }
498 
IsJump()499     bool IsJump() const
500     {
501         return metaData_.IsJump();
502     }
503 
IsCondJump()504     bool IsCondJump() const
505     {
506         return metaData_.IsCondJump();
507     }
508 
IsReturn()509     bool IsReturn() const
510     {
511         return metaData_.IsReturn();
512     }
513 
IsThrow()514     bool IsThrow() const
515     {
516         return metaData_.IsThrow();
517     }
518 
IsSuspend()519     bool IsSuspend() const
520     {
521         return metaData_.IsSuspend();
522     }
523 
IsDiscarded()524     bool IsDiscarded() const
525     {
526         return metaData_.IsDiscarded();
527     }
528 
IsSetConstant()529     bool IsSetConstant() const
530     {
531         return metaData_.IsSetConstant();
532     }
533 
IsGeneral()534     bool IsGeneral() const
535     {
536         return metaData_.IsGeneral();
537     }
538 
IsGeneratorRelative()539     bool IsGeneratorRelative() const
540     {
541         return metaData_.IsGeneratorRelative();
542     }
543 
ComputeValueInputCount()544     size_t ComputeValueInputCount() const
545     {
546         return (AccIn() ? 1 : 0) + (ThisObjectIn() ? 1 : 0) + inputs.size();
547     }
548 
ComputeOutCount()549     size_t ComputeOutCount() const
550     {
551         return (AccOut() ? 1 : 0) + vregOut.size();
552     }
553 
IsBc(EcmaOpcode ecmaOpcode)554     bool IsBc(EcmaOpcode ecmaOpcode) const
555     {
556         return metaData_.GetOpcode() == ecmaOpcode;
557     }
558 
GetOpcode()559     inline EcmaOpcode GetOpcode() const
560     {
561         return metaData_.GetOpcode();
562     }
563 
564     static void InitBytecodeInfo(BytecodeCircuitBuilder *builder,
565         BytecodeInfo &info, const uint8_t* pc);
566 
567 private:
568     BytecodeMetaData metaData_ { 0 };
569     friend class BytecodeCircuitBuilder;
570 };
571 
572 class BytecodeIterator {
573 public:
574     BytecodeIterator() = default;
BytecodeIterator(BytecodeCircuitBuilder * builder,uint32_t start,uint32_t end)575     explicit BytecodeIterator(BytecodeCircuitBuilder *builder,
576         uint32_t start, uint32_t end)
577         : builder_(builder), start_(start), end_(end) {}
Reset(BytecodeCircuitBuilder * builder,uint32_t start,uint32_t end)578     void Reset(BytecodeCircuitBuilder *builder,
579         uint32_t start, uint32_t end)
580     {
581         builder_ = builder;
582         start_ = start;
583         end_ = end;
584     }
585 
586     BytecodeIterator& operator++()
587     {
588         if (InRange()) {
589             index_++;
590         }
591         return *this;
592     }
593     BytecodeIterator& operator--()
594     {
595         if (InRange()) {
596             index_--;
597         }
598         return *this;
599     }
600 
Goto(uint32_t i)601     void Goto(uint32_t i)
602     {
603         index_ = i;
604     }
605 
GotoStart()606     void GotoStart()
607     {
608         index_ = start_;
609         ASSERT(InRange());
610     }
611 
GotoEnd()612     void GotoEnd()
613     {
614         index_ = end_;
615         ASSERT(InRange());
616     }
617 
InRange()618     bool InRange() const
619     {
620         return (index_ <= end_) && (index_ >= start_);
621     }
622 
Done()623     bool Done() const
624     {
625         return !InRange();
626     }
627 
Index()628     uint32_t Index() const
629     {
630         return index_;
631     }
632 
633     const BytecodeInfo &GetBytecodeInfo() const;
634     const uint8_t *PeekNextPc(size_t i) const;
635     const uint8_t *PeekPrevPc(size_t i) const;
636 
637 private:
638     static constexpr int32_t INVALID_INDEX = -1;
639 
640     BytecodeCircuitBuilder *builder_ {nullptr};
641     uint32_t start_ {0};
642     uint32_t end_ {0};
643     uint32_t index_{ INVALID_INDEX };
644 };
645 }  // panda::ecmascript::kungfu
646 #endif  // ECMASCRIPT_COMPILER_BYTECODES_H