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(thread, 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(thread, index);
80 if (!allowAlloc && val.IsHole()) {
81 return JSTaggedValue::Undefined();
82 }
83
84 if (val.IsHole()) {
85 JSPandaFile *jsPandaFile = taggedPool->GetJSPandaFile();
86 panda_file::File::EntityId id = taggedPool->GetEntityId(index);
87 auto foundStr = jsPandaFile->GetStringData(id);
88 EcmaVM *vm = thread->GetEcmaVM();
89 ObjectFactory *factory = vm->GetFactory();
90 auto string = factory->GetRawStringFromStringTableWithoutJSHandle(foundStr, MemSpaceType::SHARED_OLD_SPACE);
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(thread, index);
100 if (val.IsHole()) {
101 if (!taggedPool->GetJSPandaFile()->IsNewVersion()) {
102 JSTaggedValue unsharedCp = thread->GetEcmaVM()->FindOrCreateUnsharedConstpool(constpool);
103 taggedPool = ConstantPool::Cast(unsharedCp.GetTaggedObject());
104 return taggedPool->Get(thread, 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
117 val = JSTaggedValue(string);
118 CASSetObjectToCache(thread, constpoolHandle.GetTaggedValue(), index, val);
119 }
120
121 return val;
122 }
123
GetDeserializedConstantPool(EcmaVM * vm,const JSPandaFile * jsPandaFile,int32_t cpID)124 JSHandle<JSTaggedValue> ConstantPool::GetDeserializedConstantPool(EcmaVM *vm, const JSPandaFile *jsPandaFile,
125 int32_t cpID)
126 {
127 auto aotFileManager = vm->GetAOTFileManager();
128 auto constantPool = aotFileManager->GetDeserializedConstantPool(jsPandaFile, cpID);
129 MergeObjectLiteralHClassCache(vm, constantPool);
130 return constantPool;
131 }
132
MergeObjectLiteralHClassCache(EcmaVM * vm,const JSHandle<JSTaggedValue> & constpool)133 void ConstantPool::MergeObjectLiteralHClassCache(EcmaVM *vm, const JSHandle<JSTaggedValue> &constpool)
134 {
135 if (constpool->IsHole()) {
136 return;
137 }
138 JSThread *thread = vm->GetJSThread();
139 JSHandle<ConstantPool> pool(constpool);
140 auto aotHCInfo = pool->GetAotHClassInfo(thread);
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(thread, 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 if (curCached->IsHole()) {
157 for (uint32_t i = 0; i < length; i++) {
158 auto newValue = snapshotCachedArray->Get(thread, i);
159 if (newValue.IsJSHClass()) {
160 JSHClass::Cast(newValue.GetTaggedObject())->SetPrototype(thread, prototype);
161 }
162 }
163 vm->GetGlobalEnv()->SetObjectLiteralHClassCache(thread, last);
164 return;
165 }
166 auto curCachedArray = TaggedArray::Cast(curCached.GetTaggedValue());
167 for (uint32_t i = 0; i < length; i++) {
168 auto newValue = snapshotCachedArray->Get(thread, i);
169 if (newValue.IsHole()) {
170 continue;
171 }
172 auto curValue = curCachedArray->Get(thread, i);
173 // If already merged, stop to merge.
174 if (curValue.IsJSHClass() && JSHClass::Cast(curValue.GetTaggedObject())->IsAOT()) {
175 break;
176 }
177 JSHClass::Cast(newValue.GetTaggedObject())->SetPrototype(thread, prototype);
178 curCachedArray->Set(thread, i, newValue);
179 }
180 }
181
GetMethodFromCache(JSTaggedValue constpool,uint32_t index,JSThread * thread)182 JSTaggedValue ConstantPool::GetMethodFromCache(JSTaggedValue constpool, uint32_t index, JSThread *thread)
183 {
184 const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject());
185 auto val = taggedPool->GetObjectFromCache(thread, index);
186 JSPandaFile *jsPandaFile = taggedPool->GetJSPandaFile();
187
188 if (IsLoadingAOTMethodInfo(jsPandaFile, val)) {
189 val = JSTaggedValue::Hole();
190 }
191
192 return val.IsHole() ? JSTaggedValue::Undefined() : val;
193 }
194
IsAotMethodLiteralInfo(JSTaggedValue literalInfo)195 bool ConstantPool::IsAotMethodLiteralInfo(JSTaggedValue literalInfo)
196 {
197 return literalInfo.IsAOTLiteralInfo() && (AOTLiteralInfo::Cast(literalInfo.GetTaggedObject())->
198 GetLiteralType() == AOTLiteralInfo::METHOD_LITERAL_TYPE);
199 }
200
GetIhcFromAOTLiteralInfo(JSThread * thread,JSTaggedValue constpool,uint32_t index)201 JSTaggedValue ConstantPool::GetIhcFromAOTLiteralInfo(JSThread *thread, JSTaggedValue constpool, uint32_t index)
202 {
203 ASSERT(constpool.IsConstantPool());
204 auto val = ConstantPool::Cast(constpool.GetTaggedObject())->Get(thread, index);
205 if (val.IsHeapObject() && val.IsAOTLiteralInfo()) {
206 return AOTLiteralInfo::Cast(val.GetTaggedObject())->GetIhc(thread);
207 }
208 return JSTaggedValue::Undefined();
209 }
UpdateConstpoolWhenDeserialAI(EcmaVM * vm,JSHandle<ConstantPool> aiCP,JSHandle<ConstantPool> sharedCP,JSHandle<ConstantPool> unsharedCP)210 void ConstantPool::UpdateConstpoolWhenDeserialAI(EcmaVM *vm, JSHandle<ConstantPool> aiCP,
211 JSHandle<ConstantPool> sharedCP, JSHandle<ConstantPool> unsharedCP)
212 {
213 JSThread *thread = vm->GetJSThread();
214 uint32_t constpoolLen = aiCP->GetCacheLength();
215 auto aiCPLength = aiCP->GetLength();
216 JSMutableHandle<JSTaggedValue> valHandle(thread, JSTaggedValue::Undefined());
217 for (uint32_t i = 0; i < constpoolLen; i++) {
218 // We need preserve unshared constantPool index and shared constantPool id instead of fetching from ai.
219 // Because framework abc's ai does not contain those infos.
220 if (i == (aiCPLength - ConstantPool::UNSHARED_CONSTPOOL_INDEX) ||
221 i == (aiCPLength - ConstantPool::SHARED_CONSTPOOL_ID)) {
222 continue;
223 }
224 JSTaggedValue val = aiCP->GetObjectFromCache(thread, i);
225 valHandle.Update(val);
226 if (IsAotMethodLiteralInfo(valHandle.GetTaggedValue())) {
227 JSHandle<AOTLiteralInfo> value(thread, val);
228 JSHandle<AOTLiteralInfo> methodLiteral = CopySharedMethodAOTLiteralInfo(vm, value);
229 sharedCP->SetObjectToCache(thread, i, methodLiteral.GetTaggedValue());
230 } else if (valHandle->IsInt()) {
231 // For MethodInfo which does not have ihc infos, we store codeEntry directly.
232 sharedCP->SetObjectToCache(thread, i, valHandle.GetTaggedValue());
233 unsharedCP->SetObjectToCache(thread, i, valHandle.GetTaggedValue());
234 }
235 // update method, class and object aotliteralinfo
236 if (valHandle->IsAOTLiteralInfo()) {
237 unsharedCP->SetObjectToCache(thread, i, valHandle.GetTaggedValue());
238 }
239 }
240 unsharedCP->InitConstantPoolTail(vm->GetJSThread(), aiCP);
241 }
242 }
243