1/*
2 * Copyright (c) 2023 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/vtable.h"
17#include "ecmascript/layout_info-inl.h"
18
19namespace panda::ecmascript {
20VTable::Tuple VTable::CreateTuple(const JSThread *thread, JSTaggedValue phc,
21                                  const JSHandle<JSTaggedValue> &owner, uint32_t propIndex)
22{
23    DISALLOW_GARBAGE_COLLECTION;
24    JSHClass *phcPoint = JSHClass::Cast(phc.GetTaggedObject());
25    LayoutInfo *layoutInfo = LayoutInfo::Cast(phcPoint->GetLayout().GetTaggedObject());
26    JSHandle<JSTaggedValue> name(thread, layoutInfo->GetKey(propIndex));
27
28    // get type
29    JSTaggedValue typeVal;
30    PropertyAttributes attr = layoutInfo->GetAttr(propIndex);
31    if (attr.IsAccessor()) {
32        typeVal = JSTaggedValue(VTable::TypeKind::ACCESSOR);
33    } else {
34        typeVal = JSTaggedValue(VTable::TypeKind::FUNCTION);
35    }
36    JSHandle<JSTaggedValue> type(thread, typeVal);
37
38    // get offset
39    uint32_t propsNumber = phcPoint->NumberOfProps();
40    int entry = layoutInfo->FindElementWithCache(thread, phcPoint, name.GetTaggedValue(), propsNumber);
41    ASSERT(entry != -1);
42    uint32_t offsetInt = phcPoint->GetInlinedPropertiesOffset(static_cast<uint32_t>(entry));
43    JSHandle<JSTaggedValue> offset(thread, JSTaggedValue(offsetInt));
44
45    CVector<JSHandle<JSTaggedValue>> vec {name, type, owner, offset};
46    return VTable::Tuple(vec);
47}
48
49VTable::Tuple VTable::GetTuple(const JSThread *thread, uint32_t tupleIdx) const
50{
51    CVector<JSHandle<JSTaggedValue>> vec;
52    for (uint32_t loc = 0; loc < ITEM_NUM; ++loc) {
53        JSTaggedValue val = Get(tupleIdx * TUPLE_SIZE + loc);
54        vec.emplace_back(JSHandle<JSTaggedValue>(thread, val));
55    }
56    return Tuple(vec);
57}
58
59void VTable::SetByIndex(const JSThread *thread, uint32_t idx, const VTable::Tuple &tuple)
60{
61    uint32_t beginIdx = idx * TUPLE_SIZE;
62    for (uint32_t i = 0; i < TUPLE_SIZE; ++i) {
63        uint32_t currIdx = beginIdx + i;
64        JSTaggedValue val = tuple.GetItem(TupleItem(i)).GetTaggedValue();
65        Set(thread, currIdx, val);
66    }
67}
68
69void VTable::Trim(const JSThread *thread, uint32_t newLength)
70{
71    TaggedArray::Trim(thread, newLength * VTable::TUPLE_SIZE);
72}
73
74int VTable::GetTupleIndexByName(JSTaggedValue name) const
75{
76    DISALLOW_GARBAGE_COLLECTION;
77    uint32_t len = GetNumberOfTuples();
78    if (len == 0) {
79        return -1;
80    }
81
82    [[maybe_unused]] EcmaString *str = EcmaString::Cast(name.GetTaggedObject());
83    ASSERT_PRINT(EcmaStringAccessor(str).IsInternString(), "The name of the property is not an intern string");
84
85    for (uint32_t index = 0; index < len; ++index) {
86        JSTaggedValue nameVal = GetTupleItem(index, VTable::TupleItem::NAME);
87        if (nameVal == name) {
88            return index;
89        }
90    }
91
92    return -1;
93}
94
95bool VTable::Find(JSTaggedValue name) const
96{
97    return GetTupleIndexByName(name) != -1;
98}
99
100JSHandle<VTable> VTable::Copy(const JSThread *thread, const JSHandle<VTable> &vtable)
101{
102    uint32_t length = vtable->GetLength();
103    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
104    JSHandle<TaggedArray> copyVtable = factory->CopyArray(JSHandle<TaggedArray>(vtable), length, length);
105    return JSHandle<VTable>(copyVtable);
106}
107}  // namespace panda::ecmascript
108