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 "ecmascript/ecma_string-inl.h"
17#include "ecmascript/ecma_vm.h"
18#include "ecmascript/global_env.h"
19#include "ecmascript/js_array.h"
20#include "ecmascript/js_function.h"
21#include "ecmascript/js_hclass.h"
22#include "ecmascript/js_object-inl.h"
23#include "ecmascript/js_primitive_ref.h"
24#include "ecmascript/js_tagged_value-inl.h"
25#include "ecmascript/lexical_env.h"
26#include "ecmascript/object_factory.h"
27#include "ecmascript/tagged_array-inl.h"
28#include "ecmascript/tests/test_helper.h"
29
30using namespace panda;
31
32using namespace panda::ecmascript;
33
34namespace panda::test {
35class ObjectFactoryTest : public BaseTestWithScope<false> {
36};
37
38JSHandle<GlobalEnv> GetGlobal(JSThread *thread)
39{
40    return thread->GetEcmaVM()->GetGlobalEnv();
41}
42
43HWTEST_F_L0(ObjectFactoryTest, NewJSObjectByConstructor)
44{
45    thread->GetEcmaVM()->SetEnableForceGC(false);
46    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
47    JSHandle<JSTaggedValue> objFun = GetGlobal(thread)->GetObjectFunction();
48
49    // check mem alloc
50    JSHandle<JSObject> newObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
51    JSHandle<JSHClass> newObjCls(thread, newObj->GetJSHClass());
52    EXPECT_TRUE(*newObj != nullptr);
53    EXPECT_TRUE(*newObjCls != nullptr);
54
55    // check feild
56    EXPECT_EQ(newObj->GetProperties(), thread->GlobalConstants()->GetEmptyArray());
57    EXPECT_EQ(newObj->GetElements(), thread->GlobalConstants()->GetEmptyArray());
58    EXPECT_TRUE(JSTaggedValue(*newObj).IsECMAObject());
59
60    // check jshclass
61    JSHClass *cls = *newObjCls;
62    EXPECT_TRUE(cls->GetObjectSize() ==
63                JSObject::SIZE + JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS * JSTaggedValue::TaggedTypeSize());
64    EXPECT_TRUE(cls->GetPrototype() == GetGlobal(thread)->GetObjectFunctionPrototype().GetTaggedValue());
65    EXPECT_TRUE(cls->GetObjectType() == JSType::JS_OBJECT);
66
67    // check gc handle update
68    auto *prototype = cls->GetPrototype().GetTaggedObject();
69    thread->GetEcmaVM()->CollectGarbage(TriggerGCType::FULL_GC);
70    // After FullGC
71    if (thread->GetEcmaVM()->GetJSOptions().EnableSnapshotDeserialize()) {
72        EXPECT_TRUE(prototype == newObjCls->GetPrototype().GetTaggedObject());
73    } else {
74        EXPECT_TRUE(prototype != newObjCls->GetPrototype().GetTaggedObject());
75    }
76    thread->GetEcmaVM()->SetEnableForceGC(true);
77}
78
79HWTEST_F_L0(ObjectFactoryTest, NewJSFunction)
80{
81    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
82    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
83
84    // check mem alloc
85    JSHandle<JSFunction> newFun = factory->NewJSFunction(env);
86    JSHandle<JSHClass> newFunCls(thread, newFun->GetJSHClass());
87    EXPECT_TRUE(*newFun != nullptr);
88    EXPECT_TRUE(*newFunCls != nullptr);
89
90    // check feild
91    EXPECT_EQ(newFun->GetProperties(), thread->GlobalConstants()->GetEmptyArray());
92    EXPECT_EQ(newFun->GetElements(), thread->GlobalConstants()->GetEmptyArray());
93    EXPECT_EQ(newFun->GetProtoOrHClass(), JSTaggedValue::Hole());
94    EXPECT_EQ(newFun->GetHomeObject(), JSTaggedValue::Undefined());
95    EXPECT_TRUE(JSTaggedValue(*newFun).IsJSFunction());
96
97    // check jshclass
98    JSHClass *cls = *newFunCls;
99    EXPECT_TRUE(cls->GetObjectSize() ==
100                JSFunction::SIZE + JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS * JSTaggedValue::TaggedTypeSize());
101    EXPECT_TRUE(cls->GetPrototype() == GetGlobal(thread)->GetFunctionPrototype().GetTaggedValue());
102    EXPECT_TRUE(cls->GetObjectType() == JSType::JS_FUNCTION);
103    EXPECT_TRUE(cls->IsCallable());
104    EXPECT_TRUE(cls->IsExtensible());
105    EXPECT_TRUE(!cls->IsConstructor());
106}
107
108HWTEST_F_L0(ObjectFactoryTest, NewJSBoundFunction)
109{
110    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
111
112    // test prepare
113    JSHandle<JSFunction> funFun(GetGlobal(thread)->GetObjectFunction());
114    JSHandle<JSTaggedValue> bound(thread, GetGlobal(thread)->GetObjectFunctionPrototype().GetTaggedValue());
115    const JSHandle<TaggedArray> array(thread->GlobalConstants()->GetHandledEmptyArray());
116
117    // check mem alloc
118    JSHandle<JSBoundFunction> newBoundFun =
119        factory->NewJSBoundFunction(JSHandle<JSTaggedValue>::Cast(funFun), bound, array);
120    JSHandle<JSHClass> newBoundFunCls(thread, newBoundFun->GetJSHClass());
121    EXPECT_TRUE(*newBoundFun != nullptr);
122    EXPECT_TRUE(*newBoundFunCls != nullptr);
123}
124
125HWTEST_F_L0(ObjectFactoryTest, NewJSPrimitiveRef)
126{
127    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
128
129    // test prepare
130    JSHandle<JSFunction> numberFun(GetGlobal(thread)->GetNumberFunction());
131    JSHandle<JSTaggedValue> primitive(thread, JSTaggedValue(1));
132
133    // check mem alloc
134    JSHandle<JSPrimitiveRef> newPrimitive = factory->NewJSPrimitiveRef(numberFun, primitive);
135    JSHandle<JSHClass> newPrimitiveCls(thread, newPrimitive->GetJSHClass());
136    EXPECT_TRUE(*newPrimitive != nullptr);
137    EXPECT_TRUE(*newPrimitiveCls != nullptr);
138
139    EXPECT_TRUE(newPrimitive->GetValue() == JSTaggedValue(1));
140}
141
142HWTEST_F_L0(ObjectFactoryTest, NewLexicalEnv)
143{
144    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
145
146    // check mem alloc
147    JSHandle<LexicalEnv> newLexicalEnv = factory->NewLexicalEnv(0);
148    JSHandle<JSHClass> newLexicalEnvCls(thread, newLexicalEnv->GetClass());
149    EXPECT_TRUE(*newLexicalEnv != nullptr);
150    EXPECT_TRUE(*newLexicalEnvCls != nullptr);
151}
152
153HWTEST_F_L0(ObjectFactoryTest, NewJSArray)
154{
155    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
156
157    // check mem alloc
158    JSHandle<JSArray> newJSAarray = factory->NewJSArray();
159    JSHandle<JSHClass> newJSArrayCls(thread, newJSAarray->GetJSHClass());
160    EXPECT_TRUE(*newJSAarray != nullptr);
161    EXPECT_TRUE(*newJSArrayCls != nullptr);
162}
163
164HWTEST_F_L0(ObjectFactoryTest, NewAndCopyTaggedArray)
165{
166    constexpr uint32_t SHORT_ELEMENT_NUMS = 20;
167    constexpr uint32_t LONG_ELEMENT_NUMS = 100;
168    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
169    JSHandle<TaggedArray> shortTaggedarray = factory->NewTaggedArray(SHORT_ELEMENT_NUMS);
170    // init tagggedArray
171    for (uint32_t i = 0; i < SHORT_ELEMENT_NUMS; i++) {
172        shortTaggedarray->Set(thread, i, JSTaggedValue(i));
173    }
174    JSHandle<TaggedArray> copiedShort = factory->NewAndCopyTaggedArray(shortTaggedarray, SHORT_ELEMENT_NUMS,
175                                                                       SHORT_ELEMENT_NUMS);
176    JSHandle<TaggedArray> copiedLong = factory->NewAndCopyTaggedArray(shortTaggedarray, LONG_ELEMENT_NUMS,
177                                                                       SHORT_ELEMENT_NUMS);
178    // check
179    for (uint32_t i = 0; i < SHORT_ELEMENT_NUMS; i++) {
180        EXPECT_EQ(copiedShort->Get(thread, i), shortTaggedarray->Get(thread, i));
181        EXPECT_EQ(copiedLong->Get(thread, i), shortTaggedarray->Get(thread, i));
182    }
183    for (uint32_t i = SHORT_ELEMENT_NUMS; i < LONG_ELEMENT_NUMS; i++) {
184        EXPECT_EQ(copiedLong->Get(thread, i), JSTaggedValue::Hole());
185    }
186}
187
188HWTEST_F_L0(ObjectFactoryTest, NewAndCopyTaggedArrayNeedBarrier)
189{
190    constexpr uint32_t SHORT_ELEMENT_NUMS = 20;
191    constexpr uint32_t LONG_ELEMENT_NUMS = 100;
192    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
193    JSHandle<TaggedArray> shortTaggedarray = factory->NewTaggedArray(SHORT_ELEMENT_NUMS);
194    // init tagggedArray
195    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
196    for (uint32_t i = 0; i < SHORT_ELEMENT_NUMS; i++) {
197        JSHandle<JSFunction> newFun = factory->NewJSFunction(env);
198        shortTaggedarray->Set(thread, i, newFun);
199    }
200    JSHandle<TaggedArray> copiedShort = factory->NewAndCopyTaggedArray(shortTaggedarray, SHORT_ELEMENT_NUMS,
201                                                                       SHORT_ELEMENT_NUMS);
202    JSHandle<TaggedArray> copiedLong = factory->NewAndCopyTaggedArray(shortTaggedarray, LONG_ELEMENT_NUMS,
203                                                                       SHORT_ELEMENT_NUMS);
204    // check
205    for (uint32_t i = 0; i < SHORT_ELEMENT_NUMS; i++) {
206        EXPECT_EQ(copiedShort->Get(thread, i), shortTaggedarray->Get(thread, i));
207        EXPECT_EQ(copiedLong->Get(thread, i), shortTaggedarray->Get(thread, i));
208    }
209    for (uint32_t i = SHORT_ELEMENT_NUMS; i < LONG_ELEMENT_NUMS; i++) {
210        EXPECT_EQ(copiedLong->Get(thread, i), JSTaggedValue::Hole());
211    }
212}
213}  // namespace panda::test
214