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