• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "panda_file_translator.h"
17 
18 #include <string>
19 #include <string_view>
20 #include <vector>
21 
22 #include "ecmascript/class_info_extractor.h"
23 #include "ecmascript/jspandafile/program_object-inl.h"
24 #include "ecmascript/global_env.h"
25 #include "ecmascript/interpreter/interpreter.h"
26 #include "ecmascript/jspandafile/js_pandafile_manager.h"
27 #include "ecmascript/js_array.h"
28 #include "ecmascript/js_function.h"
29 #include "ecmascript/js_thread.h"
30 #include "ecmascript/literal_data_extractor.h"
31 #include "ecmascript/object_factory.h"
32 #include "ecmascript/tagged_array.h"
33 #include "ecmascript/ts_types/ts_type_table.h"
34 #include "ecmascript/ts_types/ts_loader.h"
35 #include "libpandabase/mem/mem.h"
36 #include "libpandabase/utils/logger.h"
37 #include "libpandabase/utils/utf.h"
38 #include "libpandafile/bytecode_instruction-inl.h"
39 #include "libpandafile/class_data_accessor-inl.h"
40 
41 namespace panda::ecmascript {
PandaFileTranslator(EcmaVM * vm,const JSPandaFile * jsPandaFile)42 PandaFileTranslator::PandaFileTranslator(EcmaVM *vm, const JSPandaFile *jsPandaFile)
43     : ecmaVm_(vm),
44       factory_(vm->GetFactory()),
45       thread_(vm->GetJSThread()),
46       jsPandaFile_(jsPandaFile)
47 {
48 }
49 
TranslateAndCollectPandaFile(const CString & methodName,std::vector<BytecodeTranslationInfo> * infoList)50 void PandaFileTranslator::TranslateAndCollectPandaFile(const CString &methodName,
51                                                        std::vector<BytecodeTranslationInfo> *infoList)
52 {
53     if (ecmaVm_->GetJSOptions().IsEnableTsAot()) {
54         TSLoader *tsLoader = ecmaVm_->GetTSLoader();
55         tsLoader->DecodeTSTypes(*jsPandaFile_->GetPandaFile());
56     }
57     TranslateClasses(const_cast<JSPandaFile *>(jsPandaFile_), methodName, infoList);
58 }
59 
60 template<class T, class... Args>
InitializeMemory(T * mem,Args...args)61 static T *InitializeMemory(T *mem, Args... args)
62 {
63     return new (mem) T(std::forward<Args>(args)...);
64 }
65 
TranslateClasses(JSPandaFile * jsPandaFile,const CString & methodName,std::vector<BytecodeTranslationInfo> * infoList)66 void PandaFileTranslator::TranslateClasses(JSPandaFile *jsPandaFile, const CString &methodName,
67                                            std::vector<BytecodeTranslationInfo> *infoList)
68 {
69     JSMethod *methods = jsPandaFile->GetMethods();
70     const panda_file::File *pf = jsPandaFile->GetPandaFile();
71     size_t methodIdx = 0;
72     panda_file::File::StringData sd = {static_cast<uint32_t>(methodName.size()),
73                                        reinterpret_cast<const uint8_t *>(methodName.c_str())};
74     std::set<const uint8_t *> translatedCode;
75     Span<const uint32_t> classIndexes = jsPandaFile->GetClasses();
76     for (const uint32_t index : classIndexes) {
77         panda_file::File::EntityId classId(index);
78         if (pf->IsExternal(classId)) {
79             continue;
80         }
81         panda_file::ClassDataAccessor cda(*pf, classId);
82         cda.EnumerateMethods([jsPandaFile, &translatedCode, &sd, methods, &methodIdx, pf, &infoList]
83             (panda_file::MethodDataAccessor &mda) {
84             auto codeId = mda.GetCodeId();
85             ASSERT(codeId.has_value());
86 
87             JSMethod *method = methods + (methodIdx++);
88             panda_file::CodeDataAccessor codeDataAccessor(*pf, codeId.value());
89             uint32_t codeSize = codeDataAccessor.GetCodeSize();
90 
91             uint32_t mainMethodIndex = jsPandaFile->GetMainMethodIndex();
92             if (mainMethodIndex == 0 && pf->GetStringData(mda.GetNameId()) == sd) {
93                 jsPandaFile->UpdateMainMethodIndex(mda.GetMethodId().GetOffset());
94             }
95 
96             InitializeMemory(method, jsPandaFile, mda.GetMethodId(), codeDataAccessor.GetCodeId(),
97                              mda.GetAccessFlags(), codeDataAccessor.GetNumArgs(), nullptr);
98             method->SetHotnessCounter(EcmaInterpreter::METHOD_HOTNESS_THRESHOLD);
99             method->InitializeCallField();
100             const uint8_t *insns = codeDataAccessor.GetInstructions();
101             if (translatedCode.find(insns) == translatedCode.end()) {
102                 translatedCode.insert(insns);
103                 TranslateBytecode(jsPandaFile, codeSize, insns, method, infoList);
104             }
105             jsPandaFile->SetMethodToMap(method);
106         });
107     }
108 }
109 
GenerateProgram()110 Program *PandaFileTranslator::GenerateProgram()
111 {
112     EcmaHandleScope handleScope(thread_);
113 
114     JSHandle<Program> program = factory_->NewProgram();
115     uint32_t mainMethodIndex = jsPandaFile_->GetMainMethodIndex();
116     auto mainMethod = const_cast<JSMethod *>(jsPandaFile_->FindMethods(mainMethodIndex));
117     ASSERT(mainMethod != nullptr);
118 
119     JSHandle<GlobalEnv> env = ecmaVm_->GetGlobalEnv();
120     JSHandle<JSHClass> dynclass = JSHandle<JSHClass>::Cast(env->GetFunctionClassWithProto());
121     JSHandle<JSFunction> mainFunc =
122         factory_->NewJSFunctionByDynClass(mainMethod, dynclass, FunctionKind::BASE_CONSTRUCTOR);
123 
124     program->SetMainFunction(thread_, mainFunc.GetTaggedValue());
125 
126     JSTaggedValue shareConstpool = ecmaVm_->FindConstpool(jsPandaFile_);
127     if (!shareConstpool.IsHole()) {
128         mainFunc->SetConstantPool(thread_, shareConstpool);
129         return *program;
130     }
131     uint32_t constpoolIndex = jsPandaFile_->GetConstpoolIndex();
132     JSHandle<ConstantPool> constpool = factory_->NewConstantPool(constpoolIndex + 1);
133     ecmaVm_->SetConstpool(jsPandaFile_, constpool.GetTaggedValue());
134     const panda_file::File *pf = jsPandaFile_->GetPandaFile();
135 
136     JSHandle<JSHClass> normalDynclass = JSHandle<JSHClass>::Cast(env->GetFunctionClassWithoutProto());
137     JSHandle<JSHClass> asyncDynclass = JSHandle<JSHClass>::Cast(env->GetAsyncFunctionClass());
138     JSHandle<JSHClass> generatorDynclass = JSHandle<JSHClass>::Cast(env->GetGeneratorFunctionClass());
139 
140     const std::unordered_map<uint32_t, uint64_t> &constpoolMap = jsPandaFile_->GetConstpoolMap();
141 
142     for (const auto &it : constpoolMap) {
143         ConstPoolValue value(it.second);
144         if (value.GetConstpoolType() == ConstPoolType::STRING) {
145             panda_file::File::EntityId id(it.first);
146             auto foundStr = pf->GetStringData(id);
147             auto string = factory_->GetRawStringFromStringTable(foundStr.data,
148                                                                 foundStr.utf16_length, foundStr.is_ascii);
149             constpool->Set(thread_, value.GetConstpoolIndex(), JSTaggedValue(string));
150         } else if (value.GetConstpoolType() == ConstPoolType::BASE_FUNCTION) {
151             ASSERT(mainMethodIndex != it.first);
152             panda_file::File::EntityId id(it.first);
153             auto method = const_cast<JSMethod *>(jsPandaFile_->FindMethods(it.first));
154             ASSERT(method != nullptr);
155 
156             JSHandle<JSFunction> jsFunc =
157                 factory_->NewJSFunctionByDynClass(method, dynclass, FunctionKind::BASE_CONSTRUCTOR);
158             constpool->Set(thread_, value.GetConstpoolIndex(), jsFunc.GetTaggedValue());
159             jsFunc->SetConstantPool(thread_, constpool.GetTaggedValue());
160         } else if (value.GetConstpoolType() == ConstPoolType::NC_FUNCTION) {
161             ASSERT(mainMethodIndex != it.first);
162             panda_file::File::EntityId id(it.first);
163             auto method = const_cast<JSMethod *>(jsPandaFile_->FindMethods(it.first));
164             ASSERT(method != nullptr);
165 
166             JSHandle<JSFunction> jsFunc =
167                 factory_->NewJSFunctionByDynClass(method, normalDynclass, FunctionKind::NORMAL_FUNCTION);
168             constpool->Set(thread_, value.GetConstpoolIndex(), jsFunc.GetTaggedValue());
169             jsFunc->SetConstantPool(thread_, constpool.GetTaggedValue());
170         } else if (value.GetConstpoolType() == ConstPoolType::GENERATOR_FUNCTION) {
171             ASSERT(mainMethodIndex != it.first);
172             panda_file::File::EntityId id(it.first);
173             auto method = const_cast<JSMethod *>(jsPandaFile_->FindMethods(it.first));
174             ASSERT(method != nullptr);
175 
176             JSHandle<JSFunction> jsFunc =
177                 factory_->NewJSFunctionByDynClass(method, generatorDynclass, FunctionKind::GENERATOR_FUNCTION);
178             // 26.3.4.3 prototype
179             // Whenever a GeneratorFunction instance is created another ordinary object is also created and
180             // is the initial value of the generator function's "prototype" property.
181             JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
182             JSHandle<JSObject> initialGeneratorFuncPrototype =
183                 factory_->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
184             JSObject::SetPrototype(thread_, initialGeneratorFuncPrototype, env->GetGeneratorPrototype());
185             jsFunc->SetProtoOrDynClass(thread_, initialGeneratorFuncPrototype);
186 
187             constpool->Set(thread_, value.GetConstpoolIndex(), jsFunc.GetTaggedValue());
188             jsFunc->SetConstantPool(thread_, constpool.GetTaggedValue());
189         } else if (value.GetConstpoolType() == ConstPoolType::ASYNC_FUNCTION) {
190             ASSERT(mainMethodIndex != it.first);
191             panda_file::File::EntityId id(it.first);
192             auto method = const_cast<JSMethod *>(jsPandaFile_->FindMethods(it.first));
193             ASSERT(method != nullptr);
194 
195             JSHandle<JSFunction> jsFunc =
196                 factory_->NewJSFunctionByDynClass(method, asyncDynclass, FunctionKind::ASYNC_FUNCTION);
197             constpool->Set(thread_, value.GetConstpoolIndex(), jsFunc.GetTaggedValue());
198             jsFunc->SetConstantPool(thread_, constpool.GetTaggedValue());
199         } else if (value.GetConstpoolType() == ConstPoolType::CLASS_FUNCTION) {
200             ASSERT(mainMethodIndex != it.first);
201             panda_file::File::EntityId id(it.first);
202             auto method = const_cast<JSMethod *>(jsPandaFile_->FindMethods(it.first));
203             ASSERT(method != nullptr);
204             JSHandle<ClassInfoExtractor> classInfoExtractor = factory_->NewClassInfoExtractor(method);
205             constpool->Set(thread_, value.GetConstpoolIndex(), classInfoExtractor.GetTaggedValue());
206         } else if (value.GetConstpoolType() == ConstPoolType::METHOD) {
207             ASSERT(mainMethodIndex != it.first);
208             panda_file::File::EntityId id(it.first);
209             auto method = const_cast<JSMethod *>(jsPandaFile_->FindMethods(it.first));
210             ASSERT(method != nullptr);
211 
212             JSHandle<JSFunction> jsFunc =
213                 factory_->NewJSFunctionByDynClass(method, normalDynclass, FunctionKind::NORMAL_FUNCTION);
214             constpool->Set(thread_, value.GetConstpoolIndex(), jsFunc.GetTaggedValue());
215             jsFunc->SetConstantPool(thread_, constpool.GetTaggedValue());
216         } else if (value.GetConstpoolType() == ConstPoolType::OBJECT_LITERAL) {
217             size_t index = it.first;
218             JSMutableHandle<TaggedArray> elements(thread_, JSTaggedValue::Undefined());
219             JSMutableHandle<TaggedArray> properties(thread_, JSTaggedValue::Undefined());
220             LiteralDataExtractor::ExtractObjectDatas(thread_, pf, index, elements, properties, this);
221             JSHandle<JSObject> obj = JSObject::CreateObjectFromProperties(thread_, properties);
222 
223             JSMutableHandle<JSTaggedValue> key(thread_, JSTaggedValue::Undefined());
224             JSMutableHandle<JSTaggedValue> valueHandle(thread_, JSTaggedValue::Undefined());
225             size_t elementsLen = elements->GetLength();
226             for (size_t i = 0; i < elementsLen; i += 2) {  // 2: Each literal buffer contains a pair of key-value.
227                 key.Update(elements->Get(i));
228                 if (key->IsHole()) {
229                     break;
230                 }
231                 valueHandle.Update(elements->Get(i + 1));
232                 JSObject::DefinePropertyByLiteral(thread_, obj, key, valueHandle);
233             }
234             constpool->Set(thread_, value.GetConstpoolIndex(), obj.GetTaggedValue());
235         } else if (value.GetConstpoolType() == ConstPoolType::ARRAY_LITERAL) {
236             size_t index = it.first;
237             JSHandle<TaggedArray> literal =
238                 LiteralDataExtractor::GetDatasIgnoreType(thread_, pf, static_cast<size_t>(index));
239             uint32_t length = literal->GetLength();
240 
241             JSHandle<JSArray> arr(JSArray::ArrayCreate(thread_, JSTaggedNumber(length)));
242             arr->SetElements(thread_, literal);
243             constpool->Set(thread_, value.GetConstpoolIndex(), arr.GetTaggedValue());
244         } else if (value.GetConstpoolType() == ConstPoolType::CLASS_LITERAL) {
245             size_t index = it.first;
246             JSHandle<TaggedArray> literal =
247                 LiteralDataExtractor::GetDatasIgnoreType(thread_, pf, static_cast<size_t>(index), this);
248             constpool->Set(thread_, value.GetConstpoolIndex(), literal.GetTaggedValue());
249         }
250     }
251     JSHandle<JSNativePointer> jsPandaFilePointer = factory_->NewJSNativePointer(
252         const_cast<JSPandaFile *>(jsPandaFile_), JSPandaFileManager::RemoveJSPandaFile,
253         JSPandaFileManager::GetInstance());
254     constpool->Set(thread_, constpoolIndex, jsPandaFilePointer.GetTaggedValue());
255 
256     DefineClassInConstPool(constpool);
257     mainFunc->SetConstantPool(thread_, constpool.GetTaggedValue());
258     return *program;
259 }
260 
FixOpcode(uint8_t * pc)261 void PandaFileTranslator::FixOpcode(uint8_t *pc)
262 {
263     auto opcode = static_cast<BytecodeInstruction::Opcode>(*pc);
264 
265     switch (opcode) {
266         case BytecodeInstruction::Opcode::MOV_V4_V4:
267             *pc = static_cast<uint8_t>(EcmaOpcode::MOV_V4_V4);
268             break;
269         case BytecodeInstruction::Opcode::MOV_DYN_V8_V8:
270             *pc = static_cast<uint8_t>(EcmaOpcode::MOV_DYN_V8_V8);
271             break;
272         case BytecodeInstruction::Opcode::MOV_DYN_V16_V16:
273             *pc = static_cast<uint8_t>(EcmaOpcode::MOV_DYN_V16_V16);
274             break;
275         case BytecodeInstruction::Opcode::LDA_STR_ID32:
276             *pc = static_cast<uint8_t>(EcmaOpcode::LDA_STR_ID32);
277             break;
278         case BytecodeInstruction::Opcode::JMP_IMM8:
279             *pc = static_cast<uint8_t>(EcmaOpcode::JMP_IMM8);
280             break;
281         case BytecodeInstruction::Opcode::JMP_IMM16:
282             *pc = static_cast<uint8_t>(EcmaOpcode::JMP_IMM16);
283             break;
284         case BytecodeInstruction::Opcode::JMP_IMM32:
285             *pc = static_cast<uint8_t>(EcmaOpcode::JMP_IMM32);
286             break;
287         case BytecodeInstruction::Opcode::JEQZ_IMM8:
288             *pc = static_cast<uint8_t>(EcmaOpcode::JEQZ_IMM8);
289             break;
290         case BytecodeInstruction::Opcode::JEQZ_IMM16:
291             *pc = static_cast<uint8_t>(EcmaOpcode::JEQZ_IMM16);
292             break;
293         case BytecodeInstruction::Opcode::JNEZ_IMM8:
294             *pc = static_cast<uint8_t>(EcmaOpcode::JNEZ_IMM8);
295             break;
296         case BytecodeInstruction::Opcode::JNEZ_IMM16:
297             *pc = static_cast<uint8_t>(EcmaOpcode::JNEZ_IMM16);
298             break;
299         case BytecodeInstruction::Opcode::LDA_DYN_V8:
300             *pc = static_cast<uint8_t>(EcmaOpcode::LDA_DYN_V8);
301             break;
302         case BytecodeInstruction::Opcode::STA_DYN_V8:
303             *pc = static_cast<uint8_t>(EcmaOpcode::STA_DYN_V8);
304             break;
305         case BytecodeInstruction::Opcode::LDAI_DYN_IMM32:
306             *pc = static_cast<uint8_t>(EcmaOpcode::LDAI_DYN_IMM32);
307             break;
308         case BytecodeInstruction::Opcode::FLDAI_DYN_IMM64:
309             *pc = static_cast<uint8_t>(EcmaOpcode::FLDAI_DYN_IMM64);
310             break;
311         case BytecodeInstruction::Opcode::RETURN_DYN:
312             *pc = static_cast<uint8_t>(EcmaOpcode::RETURN_DYN);
313             break;
314         default:
315             if (*pc != static_cast<uint8_t>(BytecodeInstruction::Opcode::ECMA_LDNAN_PREF_NONE)) {
316                 LOG_ECMA(FATAL) << "Is not an Ecma Opcode opcode: " << static_cast<uint16_t>(opcode);
317                 UNREACHABLE();
318             }
319             *pc = *(pc + 1);
320             *(pc + 1) = 0xFF;
321             break;
322     }
323 }
324 
325 // reuse prefix 8bits to store slotid
UpdateICOffset(JSMethod * method,uint8_t * pc)326 void PandaFileTranslator::UpdateICOffset(JSMethod *method, uint8_t *pc)
327 {
328     uint8_t offset = method->GetSlotSize();
329     if (UNLIKELY(offset == JSMethod::MAX_SLOT_SIZE)) {
330         return;
331     }
332 
333     auto opcode = static_cast<EcmaOpcode>(*pc);
334     switch (opcode) {
335         case EcmaOpcode::TRYLDGLOBALBYNAME_PREF_ID32:
336         case EcmaOpcode::TRYSTGLOBALBYNAME_PREF_ID32:
337         case EcmaOpcode::LDGLOBALVAR_PREF_ID32:
338         case EcmaOpcode::STGLOBALVAR_PREF_ID32:
339         case EcmaOpcode::ADD2DYN_PREF_V8:
340         case EcmaOpcode::SUB2DYN_PREF_V8:
341         case EcmaOpcode::MUL2DYN_PREF_V8:
342         case EcmaOpcode::DIV2DYN_PREF_V8:
343         case EcmaOpcode::MOD2DYN_PREF_V8:
344         case EcmaOpcode::SHL2DYN_PREF_V8:
345         case EcmaOpcode::SHR2DYN_PREF_V8:
346         case EcmaOpcode::ASHR2DYN_PREF_V8:
347         case EcmaOpcode::AND2DYN_PREF_V8:
348         case EcmaOpcode::OR2DYN_PREF_V8:
349         case EcmaOpcode::XOR2DYN_PREF_V8:
350         case EcmaOpcode::EQDYN_PREF_V8:
351         case EcmaOpcode::NOTEQDYN_PREF_V8:
352         case EcmaOpcode::LESSDYN_PREF_V8:
353         case EcmaOpcode::LESSEQDYN_PREF_V8:
354         case EcmaOpcode::GREATERDYN_PREF_V8:
355         case EcmaOpcode::GREATEREQDYN_PREF_V8:
356             method->UpdateSlotSize(1);
357             break;
358         case EcmaOpcode::LDOBJBYVALUE_PREF_V8_V8:
359         case EcmaOpcode::STOBJBYVALUE_PREF_V8_V8:
360         case EcmaOpcode::STOWNBYVALUE_PREF_V8_V8:
361         case EcmaOpcode::LDOBJBYNAME_PREF_ID32_V8:
362         case EcmaOpcode::STOBJBYNAME_PREF_ID32_V8:
363         case EcmaOpcode::STOWNBYNAME_PREF_ID32_V8:
364         case EcmaOpcode::LDOBJBYINDEX_PREF_V8_IMM32:
365         case EcmaOpcode::STOBJBYINDEX_PREF_V8_IMM32:
366         case EcmaOpcode::STOWNBYINDEX_PREF_V8_IMM32:
367         case EcmaOpcode::LDSUPERBYVALUE_PREF_V8_V8:
368         case EcmaOpcode::STSUPERBYVALUE_PREF_V8_V8:
369         case EcmaOpcode::LDSUPERBYNAME_PREF_ID32_V8:
370         case EcmaOpcode::STSUPERBYNAME_PREF_ID32_V8:
371         case EcmaOpcode::LDMODVARBYNAME_PREF_ID32_V8:
372         case EcmaOpcode::STMODULEVAR_PREF_ID32:
373             method->UpdateSlotSize(2);
374             break;
375         default:
376             return;
377     }
378     *(pc + 1) = offset;
379 }
380 
FixInstructionId32(const BytecodeInstruction & inst,uint32_t index,uint32_t fixOrder)381 void PandaFileTranslator::FixInstructionId32(const BytecodeInstruction &inst, uint32_t index,
382                                              uint32_t fixOrder)
383 {
384     // NOLINTNEXTLINE(hicpp-use-auto)
385     auto pc = const_cast<uint8_t *>(inst.GetAddress());
386     switch (inst.GetFormat()) {
387         case BytecodeInstruction::Format::ID32: {
388             uint8_t size = sizeof(uint32_t);
389             // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
390             if (memcpy_s(pc + FixInstructionIndex::FIX_ONE, size, &index, size) != EOK) {
391                 LOG_ECMA(FATAL) << "memcpy_s failed";
392                 UNREACHABLE();
393             }
394             break;
395         }
396         case BytecodeInstruction::Format::PREF_ID16_IMM16_V8: {
397             uint16_t u16Index = index;
398             uint8_t size = sizeof(uint16_t);
399             // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
400             if (memcpy_s(pc + FixInstructionIndex::FIX_TWO, size, &u16Index, size) != EOK) {
401                 LOG_ECMA(FATAL) << "memcpy_s failed";
402                 UNREACHABLE();
403             }
404             break;
405         }
406         case BytecodeInstruction::Format::PREF_ID32:
407         case BytecodeInstruction::Format::PREF_ID32_V8:
408         case BytecodeInstruction::Format::PREF_ID32_IMM8: {
409             uint8_t size = sizeof(uint32_t);
410             // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
411             if (memcpy_s(pc + FixInstructionIndex::FIX_TWO, size, &index, size) != EOK) {
412                 LOG_ECMA(FATAL) << "memcpy_s failed";
413                 UNREACHABLE();
414             }
415             break;
416         }
417         case BytecodeInstruction::Format::PREF_IMM16: {
418             ASSERT(static_cast<uint16_t>(index) == index);
419             uint16_t u16Index = index;
420             uint8_t size = sizeof(uint16_t);
421             // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
422             if (memcpy_s(pc + FixInstructionIndex::FIX_TWO, size, &u16Index, size) != EOK) {
423                 LOG_ECMA(FATAL) << "memcpy_s failed";
424                 UNREACHABLE();
425             }
426             break;
427         }
428         case BytecodeInstruction::Format::PREF_ID16_IMM16_IMM16_V8_V8: {
429             // Usually, we fix one part of instruction one time. But as for instruction DefineClassWithBuffer,
430             // which use both method id and literal buffer id.Using fixOrder indicates fix Location.
431             if (fixOrder == 0) {
432                 uint8_t size = sizeof(uint16_t);
433                 ASSERT(static_cast<uint16_t>(index) == index);
434                 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
435                 if (memcpy_s(pc + FixInstructionIndex::FIX_TWO, size, &index, size) != EOK) {
436                     LOG_ECMA(FATAL) << "memcpy_s failed";
437                     UNREACHABLE();
438                 }
439                 break;
440             }
441             if (fixOrder == 1) {
442                 ASSERT(static_cast<uint16_t>(index) == index);
443                 uint16_t u16Index = index;
444                 uint8_t size = sizeof(uint16_t);
445                 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
446                 if (memcpy_s(pc + FixInstructionIndex::FIX_FOUR, size, &u16Index, size) != EOK) {
447                     LOG_ECMA(FATAL) << "memcpy_s failed";
448                     UNREACHABLE();
449                 }
450                 break;
451             }
452             break;
453         }
454         default:
455             UNREACHABLE();
456     }
457 }
458 
TranslateBytecode(JSPandaFile * jsPandaFile,uint32_t insSz,const uint8_t * insArr,const JSMethod * method,std::vector<BytecodeTranslationInfo> * infoList)459 void PandaFileTranslator::TranslateBytecode(JSPandaFile *jsPandaFile, uint32_t insSz, const uint8_t *insArr,
460                                             const JSMethod *method, std::vector<BytecodeTranslationInfo> *infoList)
461 {
462     const panda_file::File *pf = jsPandaFile->GetPandaFile();
463     auto bcIns = BytecodeInstruction(insArr);
464     auto bcInsLast = bcIns.JumpTo(insSz);
465     if (infoList != nullptr && EcmaVM::GetJSOptions().IsEnableTsAot()) {
466         infoList->push_back(BytecodeTranslationInfo{{}, pf, method});
467     }
468 
469     while (bcIns.GetAddress() != bcInsLast.GetAddress()) {
470         if (bcIns.HasFlag(BytecodeInstruction::Flags::STRING_ID) &&
471             BytecodeInstruction::HasId(bcIns.GetFormat(), 0)) {
472             auto index = jsPandaFile->GetOrInsertConstantPool(
473                 ConstPoolType::STRING, bcIns.GetId().AsFileId().GetOffset());
474             FixInstructionId32(bcIns, index);
475         } else {
476             BytecodeInstruction::Opcode opcode = static_cast<BytecodeInstruction::Opcode>(bcIns.GetOpcode());
477             switch (opcode) {
478                 uint32_t index;
479                 uint32_t methodId;
480                 case BytecodeInstruction::Opcode::ECMA_DEFINEFUNCDYN_PREF_ID16_IMM16_V8:
481                     methodId = pf->ResolveMethodIndex(method->GetFileId(), bcIns.GetId().AsIndex()).GetOffset();
482                     index = jsPandaFile->GetOrInsertConstantPool(ConstPoolType::BASE_FUNCTION, methodId);
483                     FixInstructionId32(bcIns, index);
484                     break;
485                 case BytecodeInstruction::Opcode::ECMA_DEFINENCFUNCDYN_PREF_ID16_IMM16_V8:
486                     methodId = pf->ResolveMethodIndex(method->GetFileId(), bcIns.GetId().AsIndex()).GetOffset();
487                     index = jsPandaFile->GetOrInsertConstantPool(ConstPoolType::NC_FUNCTION, methodId);
488                     FixInstructionId32(bcIns, index);
489                     break;
490                 case BytecodeInstruction::Opcode::ECMA_DEFINEGENERATORFUNC_PREF_ID16_IMM16_V8:
491                     methodId = pf->ResolveMethodIndex(method->GetFileId(), bcIns.GetId().AsIndex()).GetOffset();
492                     index = jsPandaFile->GetOrInsertConstantPool(ConstPoolType::GENERATOR_FUNCTION, methodId);
493                     FixInstructionId32(bcIns, index);
494                     break;
495                 case BytecodeInstruction::Opcode::ECMA_DEFINEASYNCFUNC_PREF_ID16_IMM16_V8:
496                     methodId = pf->ResolveMethodIndex(method->GetFileId(), bcIns.GetId().AsIndex()).GetOffset();
497                     index = jsPandaFile->GetOrInsertConstantPool(ConstPoolType::ASYNC_FUNCTION, methodId);
498                     FixInstructionId32(bcIns, index);
499                     break;
500                 case BytecodeInstruction::Opcode::ECMA_DEFINEMETHOD_PREF_ID16_IMM16_V8:
501                     methodId = pf->ResolveMethodIndex(method->GetFileId(), bcIns.GetId().AsIndex()).GetOffset();
502                     index = jsPandaFile->GetOrInsertConstantPool(ConstPoolType::METHOD, methodId);
503                     FixInstructionId32(bcIns, index);
504                     break;
505                 case BytecodeInstruction::Opcode::ECMA_CREATEOBJECTWITHBUFFER_PREF_IMM16:
506                 case BytecodeInstruction::Opcode::ECMA_CREATEOBJECTHAVINGMETHOD_PREF_IMM16:
507                     index = jsPandaFile->GetOrInsertConstantPool(
508                         ConstPoolType::OBJECT_LITERAL, bcIns.GetImm<BytecodeInstruction::Format::PREF_IMM16>());
509                     FixInstructionId32(bcIns, index);
510                     break;
511                 case BytecodeInstruction::Opcode::ECMA_CREATEARRAYWITHBUFFER_PREF_IMM16:
512                     index = jsPandaFile->GetOrInsertConstantPool(
513                         ConstPoolType::ARRAY_LITERAL, bcIns.GetImm<BytecodeInstruction::Format::PREF_IMM16>());
514                     FixInstructionId32(bcIns, index);
515                     break;
516                 case BytecodeInstruction::Opcode::ECMA_DEFINECLASSWITHBUFFER_PREF_ID16_IMM16_IMM16_V8_V8:
517                     methodId = pf->ResolveMethodIndex(method->GetFileId(), bcIns.GetId().AsIndex()).GetOffset();
518                     index = jsPandaFile->GetOrInsertConstantPool(ConstPoolType::CLASS_FUNCTION, methodId);
519                     FixInstructionId32(bcIns, index);
520                     index = jsPandaFile->GetOrInsertConstantPool(
521                         ConstPoolType::CLASS_LITERAL,
522                         bcIns.GetImm<BytecodeInstruction::Format::PREF_ID16_IMM16_IMM16_V8_V8>());
523                     FixInstructionId32(bcIns, index, 1);
524                     break;
525                 default:
526                     break;
527             }
528         }
529         // NOLINTNEXTLINE(hicpp-use-auto)
530         auto pc = const_cast<uint8_t *>(bcIns.GetAddress());
531         bcIns = bcIns.GetNext();
532         FixOpcode(pc);
533         UpdateICOffset(const_cast<JSMethod *>(method), pc);
534         if (infoList != nullptr && EcmaVM::GetJSOptions().IsEnableTsAot()) {
535             auto &pcArray = infoList->back().pcArray;
536             pcArray.emplace_back(pc);
537         }
538     }
539     if (infoList != nullptr && EcmaVM::GetJSOptions().IsEnableTsAot()) {
540         auto &pcArray = infoList->back().pcArray;
541         pcArray.emplace_back(const_cast<uint8_t *>(bcInsLast.GetAddress()));
542     }
543 }
544 
DefineMethodInLiteral(JSThread * thread,uint32_t methodId,FunctionKind kind,uint16_t length) const545 JSHandle<JSFunction> PandaFileTranslator::DefineMethodInLiteral(JSThread *thread, uint32_t methodId, FunctionKind kind,
546                                                                 uint16_t length) const
547 {
548     auto method = const_cast<JSMethod *>(jsPandaFile_->FindMethods(methodId));
549     ASSERT(method != nullptr);
550 
551     JSHandle<GlobalEnv> env = thread_->GetEcmaVM()->GetGlobalEnv();
552     JSHandle<JSHClass> functionClass;
553     if (kind == FunctionKind::NORMAL_FUNCTION) {
554         functionClass = JSHandle<JSHClass>::Cast(env->GetFunctionClassWithoutProto());
555     } else {
556         functionClass = JSHandle<JSHClass>::Cast(env->GetGeneratorFunctionClass());
557     }
558     JSHandle<JSFunction> jsFunc = factory_->NewJSFunctionByDynClass(method, functionClass, kind);
559 
560     if (kind == FunctionKind::GENERATOR_FUNCTION) {
561         JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
562         JSHandle<JSObject> initialGeneratorFuncPrototype =
563             factory_->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
564         JSObject::SetPrototype(thread_, initialGeneratorFuncPrototype, env->GetGeneratorPrototype());
565         jsFunc->SetProtoOrDynClass(thread_, initialGeneratorFuncPrototype);
566     }
567     jsFunc->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length));
568     return jsFunc;
569 }
570 
DefineClassInConstPool(const JSHandle<ConstantPool> & constpool) const571 void PandaFileTranslator::DefineClassInConstPool(const JSHandle<ConstantPool> &constpool) const
572 {
573     uint32_t length = constpool->GetLength();
574     uint32_t index = 0;
575     while (index < length - 1) {
576         JSTaggedValue value = constpool->Get(index);
577         if (!value.IsClassInfoExtractor()) {
578             index++;
579             continue;
580         }
581 
582         // Here, using a law: when inserting ctor in index of constantpool, the index + 1 location will be inserted by
583         // corresponding class literal. Because translator fixes ECMA_DEFINECLASSWITHBUFFER two consecutive times.
584         JSTaggedValue nextValue = constpool->Get(index + 1);
585         ASSERT(nextValue.IsTaggedArray());
586 
587         JSHandle<ClassInfoExtractor> extractor(thread_, value);
588         JSHandle<TaggedArray> literal(thread_, nextValue);
589         ClassInfoExtractor::BuildClassInfoExtractorFromLiteral(thread_, extractor, literal);
590         JSHandle<JSFunction> cls = ClassHelper::DefineClassTemplate(thread_, extractor, constpool);
591         constpool->Set(thread_, index, cls);
592         index += 2;  // 2: pair of extractor and literal
593     }
594 }
595 }  // namespace panda::ecmascript
596