1 /*
2 * Copyright (c) 2022-2024 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 "ecmascript/jspandafile/program_object.h"
17
18 namespace panda::ecmascript {
19
GetClassLiteralFromCache(JSThread * thread,JSHandle<ConstantPool> constpool,uint32_t literal,CString entry,JSHandle<JSTaggedValue> sendableEnv,ClassKind kind)20 JSTaggedValue ConstantPool::GetClassLiteralFromCache(JSThread *thread, JSHandle<ConstantPool> constpool,
21 uint32_t literal, CString entry, JSHandle<JSTaggedValue> sendableEnv, ClassKind kind)
22 {
23 [[maybe_unused]] EcmaHandleScope handleScope(thread);
24 // Do not use cache when sendable for get wrong obj from cache,
25 // shall be fix or refactor during shared object implements
26 JSTaggedValue val = constpool->GetObjectFromCache(literal);
27 JSPandaFile *jsPandaFile = constpool->GetJSPandaFile();
28
29 // For AOT
30 bool isLoadedAOT = jsPandaFile->IsLoadedAOT();
31 JSHandle<AOTLiteralInfo> entryIndexes(thread, JSTaggedValue::Undefined());
32 if (isLoadedAOT && val.IsAOTLiteralInfo()) {
33 entryIndexes = JSHandle<AOTLiteralInfo>(thread, val);
34 val = JSTaggedValue::Hole();
35 }
36
37 if (val.IsHole()) {
38 EcmaVM *vm = thread->GetEcmaVM();
39 ObjectFactory *factory = vm->GetFactory();
40 ASSERT(jsPandaFile->IsNewVersion());
41 panda_file::File::EntityId literalId = constpool->GetEntityId(literal);
42 bool needSetAotFlag = isLoadedAOT && !entryIndexes.GetTaggedValue().IsUndefined();
43 JSHandle<TaggedArray> literalArray = LiteralDataExtractor::GetDatasIgnoreTypeForClass(thread,
44 jsPandaFile, literalId, constpool, entry, needSetAotFlag, entryIndexes, nullptr, sendableEnv, kind);
45 JSHandle<ClassLiteral> classLiteral;
46 if (kind == ClassKind::SENDABLE) {
47 classLiteral = factory->NewSClassLiteral();
48 } else {
49 classLiteral = factory->NewClassLiteral();
50 }
51 classLiteral->SetArray(thread, literalArray);
52 val = classLiteral.GetTaggedValue();
53 if (kind == ClassKind::SENDABLE) {
54 CASSetObjectToCache(thread, constpool.GetTaggedValue(), literal, val);
55 } else {
56 constpool->SetObjectToCache(thread, literal, val);
57 }
58 }
59
60 return val;
61 }
62
GetFieldLiteral(JSThread * thread,JSHandle<ConstantPool> constpool,uint32_t literal,CString entry)63 JSHandle<TaggedArray> ConstantPool::GetFieldLiteral(JSThread *thread, JSHandle<ConstantPool> constpool,
64 uint32_t literal, CString entry)
65 {
66 JSPandaFile *jsPandaFile = constpool->GetJSPandaFile();
67 JSHandle<AOTLiteralInfo> entryIndexes(thread, JSTaggedValue::Undefined());
68 ASSERT(jsPandaFile->IsNewVersion());
69 panda_file::File::EntityId literalId(literal);
70 JSHandle<TaggedArray> literalArray = LiteralDataExtractor::GetDatasIgnoreType(
71 thread, jsPandaFile, literalId, constpool, entry, false, entryIndexes);
72 return literalArray;
73 }
74
GetStringFromCacheForJit(JSThread * thread,JSTaggedValue constpool,uint32_t index,bool allowAlloc)75 JSTaggedValue ConstantPool::GetStringFromCacheForJit(JSThread *thread, JSTaggedValue constpool, uint32_t index,
76 bool allowAlloc)
77 {
78 const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject());
79 auto val = taggedPool->Get(index);
80 if (!allowAlloc && val.IsHole()) {
81 return JSTaggedValue::Undefined();
82 }
83 if (val.IsHole()) {
84 JSPandaFile *jsPandaFile = taggedPool->GetJSPandaFile();
85 panda_file::File::EntityId id = taggedPool->GetEntityId(index);
86 auto foundStr = jsPandaFile->GetStringData(id);
87 EcmaVM *vm = thread->GetEcmaVM();
88 ObjectFactory *factory = vm->GetFactory();
89 auto string = factory->GetRawStringFromStringTableWithoutJSHandle(foundStr, MemSpaceType::SHARED_OLD_SPACE,
90 jsPandaFile->IsFirstMergedAbc(), id.GetOffset());
91 val = JSTaggedValue(string);
92 }
93 return val;
94 }
95
GetStringFromCache(JSThread * thread,JSTaggedValue constpool,uint32_t index)96 JSTaggedValue ConstantPool::GetStringFromCache(JSThread *thread, JSTaggedValue constpool, uint32_t index)
97 {
98 const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject());
99 auto val = taggedPool->Get(index);
100 if (val.IsHole()) {
101 if (!taggedPool->GetJSPandaFile()->IsNewVersion()) {
102 JSTaggedValue unsharedCp = thread->GetCurrentEcmaContext()->FindOrCreateUnsharedConstpool(constpool);
103 taggedPool = ConstantPool::Cast(unsharedCp.GetTaggedObject());
104 return taggedPool->Get(index);
105 }
106 [[maybe_unused]] EcmaHandleScope handleScope(thread);
107
108 JSPandaFile *jsPandaFile = taggedPool->GetJSPandaFile();
109 panda_file::File::EntityId id = taggedPool->GetEntityId(index);
110 auto foundStr = jsPandaFile->GetStringData(id);
111
112 EcmaVM *vm = thread->GetEcmaVM();
113 ObjectFactory *factory = vm->GetFactory();
114 JSHandle<ConstantPool> constpoolHandle(thread, constpool);
115 auto string = factory->GetRawStringFromStringTable(foundStr, MemSpaceType::SHARED_OLD_SPACE,
116 jsPandaFile->IsFirstMergedAbc(), id.GetOffset());
117
118 val = JSTaggedValue(string);
119 CASSetObjectToCache(thread, constpoolHandle.GetTaggedValue(), index, val);
120 }
121
122 return val;
123 }
124
GetDeserializedConstantPool(EcmaVM * vm,const JSPandaFile * jsPandaFile,int32_t cpID)125 JSHandle<JSTaggedValue> ConstantPool::GetDeserializedConstantPool(EcmaVM *vm, const JSPandaFile *jsPandaFile,
126 int32_t cpID)
127 {
128 auto aotFileManager = vm->GetAOTFileManager();
129 auto constantPool = aotFileManager->GetDeserializedConstantPool(jsPandaFile, cpID);
130 MergeObjectLiteralHClassCache(vm, constantPool);
131 return constantPool;
132 }
133
MergeObjectLiteralHClassCache(EcmaVM * vm,const JSHandle<JSTaggedValue> & constpool)134 void ConstantPool::MergeObjectLiteralHClassCache(EcmaVM *vm, const JSHandle<JSTaggedValue> &constpool)
135 {
136 if (constpool->IsHole()) {
137 return;
138 }
139 JSHandle<ConstantPool> pool(constpool);
140 auto aotHCInfo = pool->GetAotHClassInfo();
141 if (!aotHCInfo.IsTaggedArray()) {
142 return;
143 }
144 auto aotHCInfoArray = TaggedArray::Cast(aotHCInfo);
145 if (aotHCInfoArray->GetLength() <= 0) {
146 return;
147 }
148 auto last = aotHCInfoArray->Get(aotHCInfoArray->GetLength() - 1);
149 if (!last.IsTaggedArray()) {
150 return;
151 }
152 auto snapshotCachedArray = TaggedArray::Cast(last);
153 auto curCached = vm->GetGlobalEnv()->GetObjectLiteralHClassCache();
154 auto length = snapshotCachedArray->GetLength();
155 auto prototype = vm->GetGlobalEnv()->GetObjectFunctionPrototype();
156 JSThread *thread = vm->GetJSThread();
157 if (curCached->IsHole()) {
158 for (uint32_t i = 0; i < length; i++) {
159 auto newValue = snapshotCachedArray->Get(i);
160 if (newValue.IsJSHClass()) {
161 JSHClass::Cast(newValue.GetTaggedObject())->SetPrototype(thread, prototype);
162 }
163 }
164 vm->GetGlobalEnv()->SetObjectLiteralHClassCache(thread, last);
165 return;
166 }
167 auto curCachedArray = TaggedArray::Cast(curCached.GetTaggedValue());
168 for (uint32_t i = 0; i < length; i++) {
169 auto newValue = snapshotCachedArray->Get(i);
170 if (newValue.IsHole()) {
171 continue;
172 }
173 auto curValue = curCachedArray->Get(i);
174 // If already merged, stop to merge.
175 if (curValue.IsJSHClass() && JSHClass::Cast(curValue.GetTaggedObject())->IsAOT()) {
176 break;
177 }
178 JSHClass::Cast(newValue.GetTaggedObject())->SetPrototype(thread, prototype);
179 curCachedArray->Set(thread, i, newValue);
180 }
181 }
182
GetMethodFromCache(JSTaggedValue constpool,uint32_t index)183 JSTaggedValue ConstantPool::GetMethodFromCache(JSTaggedValue constpool, uint32_t index)
184 {
185 const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject());
186 auto val = taggedPool->GetObjectFromCache(index);
187 JSPandaFile *jsPandaFile = taggedPool->GetJSPandaFile();
188
189 if (IsLoadedMethodInfoFromAOT(jsPandaFile, val)) {
190 val = JSTaggedValue::Hole();
191 }
192
193 return val.IsHole() ? JSTaggedValue::Undefined() : val;
194 }
195
IsAotMethodLiteralInfo(JSTaggedValue literalInfo)196 bool ConstantPool::IsAotMethodLiteralInfo(JSTaggedValue literalInfo)
197 {
198 return literalInfo.IsAOTLiteralInfo() && (AOTLiteralInfo::Cast(literalInfo.GetTaggedObject())->
199 GetLiteralType() == AOTLiteralInfo::METHOD_LITERAL_TYPE);
200 }
201
UpdateConstpoolWhenDeserialAI(EcmaVM * vm,JSHandle<ConstantPool> aiCP,JSHandle<ConstantPool> sharedCP,JSHandle<ConstantPool> unsharedCP)202 void ConstantPool::UpdateConstpoolWhenDeserialAI(EcmaVM *vm, JSHandle<ConstantPool> aiCP,
203 JSHandle<ConstantPool> sharedCP, JSHandle<ConstantPool> unsharedCP)
204 {
205 uint32_t constpoolLen = aiCP->GetCacheLength();
206 auto aiCPLength = aiCP->GetLength();
207 JSMutableHandle<JSTaggedValue> valHandle(vm->GetJSThread(), JSTaggedValue::Undefined());
208 for (uint32_t i = 0; i < constpoolLen; i++) {
209 // We need preserve unshared constantPool index and shared constantPool id instead of fetching from ai.
210 // Because framework abc's ai does not contain those infos.
211 if (i == (aiCPLength - ConstantPool::UNSHARED_CONSTPOOL_INDEX) ||
212 i == (aiCPLength - ConstantPool::SHARED_CONSTPOOL_ID)) {
213 continue;
214 }
215 JSThread *thread = vm->GetJSThread();
216 JSTaggedValue val = aiCP->GetObjectFromCache(i);
217 valHandle.Update(val);
218 if (IsAotMethodLiteralInfo(valHandle.GetTaggedValue())) {
219 JSHandle<AOTLiteralInfo> value(thread, val);
220 JSHandle<AOTLiteralInfo> methodLiteral = CopySharedMethodAOTLiteralInfo(vm, value);
221 sharedCP->SetObjectToCache(thread, i, methodLiteral.GetTaggedValue());
222 } else if (valHandle->IsInt()) {
223 // For MethodInfo which does not have ihc infos, we store codeEntry directly.
224 sharedCP->SetObjectToCache(thread, i, valHandle.GetTaggedValue());
225 unsharedCP->SetObjectToCache(thread, i, valHandle.GetTaggedValue());
226 }
227 // update method, class and object aotliteralinfo
228 if (valHandle->IsAOTLiteralInfo()) {
229 unsharedCP->SetObjectToCache(thread, i, valHandle.GetTaggedValue());
230 }
231 }
232 unsharedCP->InitConstantPoolTail(vm->GetJSThread(), aiCP);
233 }
234 }
235