1/*
2 * Copyright (c) 2023-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/ecma_context.h"
17#include "ecmascript/global_env.h"
18#include "ecmascript/global_index_map.h"
19
20namespace panda::ecmascript {
21void GlobalIndexMap::Initialize(const JSThread *thread,
22                                JSMutableHandle<PointerToIndexDictionary> globalIndexMap)
23{
24    // GlobalIndex map should be created when it is first used.
25    InitGlobalIndexMap(thread, globalIndexMap);
26
27    // Init GlobalIndex map
28    InitGlobalConst(thread, globalIndexMap);
29    InitGlobalEnv(thread, globalIndexMap);
30    InitBuiltinEntries(thread, globalIndexMap);
31}
32
33void GlobalIndexMap::InitGlobalIndexMap(const JSThread *thread,
34                                        JSMutableHandle<PointerToIndexDictionary> globalIndexMap)
35{
36    if (globalIndexMap.GetTaggedValue().IsHeapObject()) {
37        return;
38    }
39    globalIndexMap.Update(PointerToIndexDictionary::Create(thread));
40}
41
42void GlobalIndexMap::InitGlobalConst(const JSThread *thread,
43                                     JSMutableHandle<PointerToIndexDictionary> globalIndexMap)
44{
45    ASSERT_PRINT(globalIndexMap.GetTaggedValue().IsHeapObject(), "Global's IndexMap is not existed.");
46    auto globalConst = const_cast<GlobalEnvConstants *>(thread->GlobalConstants());
47    uint32_t constantCount = globalConst->GetConstantCount();
48    JSMutableHandle<PointerToIndexDictionary> globalIndexMapHandle(thread, globalIndexMap);
49    JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
50    JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
51    for (uint32_t index = 0; index < constantCount; index++) {
52        JSTaggedValue objectValue = globalConst->GetGlobalConstantObject(index);
53        if (objectValue.IsHeapObject() && !objectValue.IsString()) {
54            keyHandle.Update(objectValue);
55
56            GlobalIndex globalIndex;
57            globalIndex.UpdateGlobalConstId(index);
58            valueHandle.Update(JSTaggedValue(globalIndex.GetGlobalIndex()));
59            JSHandle<PointerToIndexDictionary> newDict =
60                PointerToIndexDictionary::PutIfAbsent(thread, globalIndexMapHandle, keyHandle, valueHandle);
61            globalIndexMapHandle.Update(newDict);
62        }
63    }
64    globalIndexMap.Update(globalIndexMapHandle);
65}
66
67void GlobalIndexMap::InitGlobalEnv(const JSThread *thread,
68                                   JSMutableHandle<PointerToIndexDictionary> globalIndexMap)
69{
70    ASSERT_PRINT(globalIndexMap.GetTaggedValue().IsHeapObject(), "Global's IndexMap is not existed.");
71    auto globalEnv = thread->GetEcmaVM()->GetGlobalEnv();
72    uint32_t globalEnvFieldSize = globalEnv->GetGlobalEnvFieldSize();
73    JSMutableHandle<PointerToIndexDictionary> globalIndexMapHandle(thread, globalIndexMap);
74    JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
75    JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
76    for (uint32_t index = 0; index < globalEnvFieldSize; index++) {
77        JSTaggedValue objectValue = globalEnv->GetGlobalEnvObjectByIndex(index).GetTaggedValue();
78        if (objectValue.IsHeapObject()) {
79            keyHandle.Update(objectValue);
80
81            GlobalIndex globalIndex;
82            globalIndex.UpdateGlobalEnvId(index);
83            valueHandle.Update(JSTaggedValue(globalIndex.GetGlobalIndex()));
84            JSHandle<PointerToIndexDictionary> newDict =
85                PointerToIndexDictionary::PutIfAbsent(thread, globalIndexMapHandle, keyHandle, valueHandle);
86            globalIndexMapHandle.Update(newDict);
87        }
88    }
89    globalIndexMap.Update(globalIndexMapHandle);
90}
91
92void GlobalIndexMap::InitBuiltinEntries(const JSThread *thread,
93                                        JSMutableHandle<PointerToIndexDictionary> globalIndexMap)
94{
95    ASSERT_PRINT(globalIndexMap.GetTaggedValue().IsHeapObject(), "Global's IndexMap is not existed.");
96    auto builtinEntries = thread->GetBuiltinEntries();
97    uint32_t builtinEntriesCount = BuiltinEntries::COUNT;
98    JSMutableHandle<PointerToIndexDictionary> globalIndexMapHandle(thread, globalIndexMap);
99    JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
100    JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
101    for (uint32_t index = 0; index < builtinEntriesCount; index++) {
102        JSTaggedValue objectValue = builtinEntries.builtin_[index].hClass_;
103        keyHandle.Update(objectValue);
104        if (objectValue.IsHeapObject()) {
105            GlobalIndex globalIndex;
106            globalIndex.UpdateBuiltinEntriesId(index);
107            valueHandle.Update(JSTaggedValue(globalIndex.GetGlobalIndex()));
108            JSHandle<PointerToIndexDictionary> newDict =
109                PointerToIndexDictionary::PutIfAbsent(thread, globalIndexMapHandle, keyHandle, valueHandle);
110            globalIndexMapHandle.Update(newDict);
111        }
112    }
113    globalIndexMap.Update(globalIndexMapHandle);
114}
115
116void GlobalIndexMap::FindGlobalIndex(JSHandle<PointerToIndexDictionary> globalIndexMap,
117                                     JSTaggedValue objAddress, GlobalIndex *globalIndex)
118{
119    int entry = globalIndexMap->FindEntry(objAddress);
120    if (entry != -1) {
121        *globalIndex = GlobalIndex(globalIndexMap->GetValue(entry).GetInt());
122    }
123}
124} // namespace panda::ecmascript
125