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#ifndef ECMASCRIPT_OBJECT_FACTORY_INL_H
17#define ECMASCRIPT_OBJECT_FACTORY_INL_H
18
19#include "ecmascript/global_env_constants-inl.h"
20#include "ecmascript/global_env_constants.h"
21#include "ecmascript/js_hclass-inl.h"
22#include "ecmascript/js_thread.h"
23#include "ecmascript/lexical_env.h"
24#include "ecmascript/mem/heap-inl.h"
25#include "ecmascript/mem/barriers-inl.h"
26#include "ecmascript/mem/space.h"
27#include "ecmascript/object_factory.h"
28#include "ecmascript/tagged_array-inl.h"
29
30namespace panda::ecmascript {
31EcmaString *ObjectFactory::AllocLineStringObjectNoGC(size_t size)
32{
33    TaggedObject *object = nullptr;
34    if (size > MAX_REGULAR_HEAP_OBJECT_SIZE) {
35        object = reinterpret_cast<TaggedObject *>(sHeap_->GetHugeObjectSpace()->Allocate(thread_, size));
36    } else {
37        object = reinterpret_cast<TaggedObject *>(sHeap_->GetOldSpace()->TryAllocateAndExpand(thread_, size, true));
38    }
39    if (object == nullptr) {
40        LOG_ECMA(FATAL) << "Alloc size " << size << " bytes string fail";
41        UNREACHABLE();
42    }
43    object->SetClass(thread_, JSHClass::Cast(thread_->GlobalConstants()->GetLineStringClass().GetTaggedObject()));
44    return EcmaString::Cast(object);
45}
46
47EcmaString *ObjectFactory::AllocNonMovableLineStringObject(size_t size)
48{
49    NewSObjectHook();
50    return reinterpret_cast<EcmaString *>(sHeap_->AllocateNonMovableOrHugeObject(
51        thread_, JSHClass::Cast(thread_->GlobalConstants()->GetLineStringClass().GetTaggedObject()), size));
52}
53
54EcmaString *ObjectFactory::AllocLineStringObject(size_t size)
55{
56    NewSObjectHook();
57    return reinterpret_cast<EcmaString *>(sHeap_->AllocateOldOrHugeObject(
58        thread_, JSHClass::Cast(thread_->GlobalConstants()->GetLineStringClass().GetTaggedObject()), size));
59}
60
61EcmaString *ObjectFactory::AllocOldSpaceLineStringObject(size_t size)
62{
63    NewSObjectHook();
64    return reinterpret_cast<EcmaString *>(sHeap_->AllocateOldOrHugeObject(
65        thread_, JSHClass::Cast(thread_->GlobalConstants()->GetLineStringClass().GetTaggedObject()), size));
66}
67
68EcmaString *ObjectFactory::AllocReadOnlyLineStringObject(size_t size)
69{
70    NewSObjectHook();
71    return reinterpret_cast<EcmaString *>(sHeap_->AllocateReadOnlyOrHugeObject(
72        thread_, JSHClass::Cast(thread_->GlobalConstants()->GetLineStringClass().GetTaggedObject()), size));
73}
74
75EcmaString *ObjectFactory::AllocSlicedStringObject(MemSpaceType type)
76{
77    ASSERT(IsSMemSpace(type));
78    NewSObjectHook();
79    return reinterpret_cast<EcmaString *>(AllocObjectWithSpaceType(SlicedString::SIZE,
80        JSHClass::Cast(thread_->GlobalConstants()->GetSlicedStringClass().GetTaggedObject()), type));
81}
82
83EcmaString *ObjectFactory::AllocConstantStringObject(MemSpaceType type)
84{
85    ASSERT(IsSMemSpace(type));
86    NewSObjectHook();
87    return reinterpret_cast<EcmaString *>(AllocObjectWithSpaceType(ConstantString::SIZE,
88        JSHClass::Cast(thread_->GlobalConstants()->GetConstantStringClass().GetTaggedObject()), type));
89}
90
91EcmaString *ObjectFactory::AllocTreeStringObject()
92{
93    NewSObjectHook();
94    return reinterpret_cast<EcmaString *>(sHeap_->AllocateOldOrHugeObject(
95        thread_, JSHClass::Cast(thread_->GlobalConstants()->GetTreeStringClass().GetTaggedObject()),
96        TreeEcmaString::SIZE));
97}
98
99JSHandle<JSNativePointer> ObjectFactory::NewJSNativePointer(void *externalPointer,
100                                                            const NativePointerCallback &callBack,
101                                                            void *data,
102                                                            bool nonMovable,
103                                                            size_t nativeBindingsize,
104                                                            Concurrent isConcurrent,
105                                                            NativeFlag flag)
106{
107    NewObjectHook();
108    TaggedObject *header;
109    auto jsNativePointerClass = JSHClass::Cast(thread_->GlobalConstants()->GetJSNativePointerClass().GetTaggedObject());
110    if (nonMovable) {
111        header = heap_->AllocateNonMovableOrHugeObject(jsNativePointerClass);
112    } else {
113        header = heap_->AllocateOldOrHugeObject(jsNativePointerClass);
114    }
115    JSHandle<JSNativePointer> obj(thread_, header);
116    obj->SetExternalPointer(externalPointer);
117    obj->SetDeleter(callBack);
118    obj->SetData(data);
119    uint32_t fixedNativeBindingsize = nativeBindingsize < UINT32_MAX ? nativeBindingsize
120                                                                     : UINT32_MAX;
121    obj->SetBindingSize(fixedNativeBindingsize);
122    obj->SetNativeFlag(flag);
123
124    heap_->IncreaseNativeBindingSize(fixedNativeBindingsize);
125    if (callBack != nullptr) {
126        vm_->PushToNativePointerList(static_cast<JSNativePointer *>(header), isConcurrent);
127        // In some cases, the size of JS/TS object is too small and the native binding size is too large.
128        // Check and try trigger concurrent mark here.
129        heap_->TryTriggerFullMarkOrGCByNativeSize();
130    }
131    return obj;
132}
133
134LexicalEnv *ObjectFactory::InlineNewLexicalEnv(int numSlots)
135{
136    NewObjectHook();
137    size_t size = LexicalEnv::ComputeSize(numSlots);
138    auto header = heap_->TryAllocateYoungGeneration(
139        JSHClass::Cast(thread_->GlobalConstants()->GetEnvClass().GetTaggedObject()), size);
140    if (UNLIKELY(header == nullptr)) {
141        return nullptr;
142    }
143    LexicalEnv *array = LexicalEnv::Cast(header);
144    array->InitializeWithSpecialValue(JSTaggedValue::Hole(), numSlots + LexicalEnv::RESERVED_ENV_LENGTH);
145    return array;
146}
147
148template<typename T, typename S>
149void ObjectFactory::NewJSIntlIcuData(const JSHandle<T> &obj, const S &icu, const NativePointerCallback &callback)
150{
151    S *icuPoint = vm_->GetNativeAreaAllocator()->New<S>(icu);
152    ASSERT(icuPoint != nullptr);
153    JSTaggedValue data = obj->GetIcuField();
154    if (data.IsHeapObject() && data.IsJSNativePointer()) {
155        JSNativePointer *native = JSNativePointer::Cast(data.GetTaggedObject());
156        native->ResetExternalPointer(thread_, icuPoint);
157        return;
158    }
159    JSHandle<JSNativePointer> pointer = NewJSNativePointer(icuPoint, callback, vm_);
160    obj->SetIcuField(thread_, pointer.GetTaggedValue());
161}
162
163TaggedObject *ObjectFactory::AllocObjectWithSpaceType(size_t size, JSHClass *cls, MemSpaceType type)
164{
165    switch (type) {
166        case MemSpaceType::SEMI_SPACE:
167            return heap_->AllocateYoungOrHugeObject(cls, size);
168        case MemSpaceType::OLD_SPACE:
169            return heap_->AllocateOldOrHugeObject(cls, size);
170        case MemSpaceType::NON_MOVABLE:
171            return heap_->AllocateNonMovableOrHugeObject(cls, size);
172        case MemSpaceType::SHARED_OLD_SPACE:
173            return sHeap_->AllocateOldOrHugeObject(thread_, cls, size);
174        case MemSpaceType::SHARED_NON_MOVABLE:
175            return sHeap_->AllocateNonMovableOrHugeObject(thread_, cls, size);
176        default:
177            LOG_ECMA(FATAL) << "this branch is unreachable";
178            UNREACHABLE();
179    }
180}
181}  // namespace panda::ecmascript
182#endif  // ECMASCRIPT_OBJECT_FACTORY_INL_H
183