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_STRING_INL_H
17 #define ECMASCRIPT_STRING_INL_H
18
19 #include "ecmascript/ecma_string.h"
20 #include "ecmascript/base/string_helper.h"
21 #include "ecmascript/ecma_vm.h"
22 #include "ecmascript/js_handle.h"
23 #include "ecmascript/js_tagged_value-inl.h"
24 #include "ecmascript/object_factory-inl.h"
25
26 namespace panda::ecmascript {
27 /* static */
CreateEmptyString(const EcmaVM * vm)28 inline EcmaString *EcmaString::CreateEmptyString(const EcmaVM *vm)
29 {
30 auto string = vm->GetFactory()->AllocNonMovableStringObject(EcmaString::SIZE);
31 string->SetLength(0, true);
32 string->SetRawHashcode(0);
33 return string;
34 }
35
36 /* static */
AllocStringObjectWithSpaceType(const EcmaVM * vm,size_t length,bool compressed,MemSpaceType type)37 inline EcmaString *EcmaString::AllocStringObjectWithSpaceType(const EcmaVM *vm, size_t length, bool compressed,
38 MemSpaceType type)
39 {
40 size_t size = compressed ? ComputeSizeUtf8(length) : ComputeSizeUtf16(length);
41 EcmaString *string = nullptr;
42 switch (type) {
43 case MemSpaceType::SEMI_SPACE:
44 string = vm->GetFactory()->AllocStringObject(size);
45 break;
46 case MemSpaceType::OLD_SPACE:
47 string = vm->GetFactory()->AllocOldSpaceStringObject(size);
48 break;
49 case MemSpaceType::NON_MOVABLE:
50 string = vm->GetFactory()->AllocNonMovableStringObject(size);
51 break;
52 default:
53 UNREACHABLE();
54 }
55 string->SetLength(length, compressed);
56 string->SetRawHashcode(0);
57 return string;
58 }
59
60 /* static */
CreateFromUtf8(const EcmaVM * vm,const uint8_t * utf8Data,uint32_t utf8Len,bool canBeCompress,MemSpaceType type)61 inline EcmaString *EcmaString::CreateFromUtf8(const EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len,
62 bool canBeCompress, MemSpaceType type)
63 {
64 if (utf8Len == 0) {
65 return vm->GetFactory()->GetEmptyString().GetObject<EcmaString>();
66 }
67 EcmaString *string = nullptr;
68 if (canBeCompress) {
69 string = AllocStringObjectWithSpaceType(vm, utf8Len, true, type);
70 ASSERT(string != nullptr);
71
72 if (memcpy_s(string->GetDataUtf8Writable(), utf8Len, utf8Data, utf8Len) != EOK) {
73 LOG_FULL(FATAL) << "memcpy_s failed";
74 UNREACHABLE();
75 }
76 } else {
77 auto utf16Len = base::utf_helper::Utf8ToUtf16Size(utf8Data, utf8Len);
78 string = AllocStringObjectWithSpaceType(vm, utf16Len, false, type);
79 ASSERT(string != nullptr);
80
81 [[maybe_unused]] auto len =
82 base::utf_helper::ConvertRegionUtf8ToUtf16(utf8Data, string->GetDataUtf16Writable(), utf8Len, utf16Len, 0);
83 ASSERT(len == utf16Len);
84 }
85
86 ASSERT_PRINT(canBeCompress == CanBeCompressed(string), "Bad input canBeCompress!");
87 return string;
88 }
89
CreateFromUtf16(const EcmaVM * vm,const uint16_t * utf16Data,uint32_t utf16Len,bool canBeCompress,MemSpaceType type)90 inline EcmaString *EcmaString::CreateFromUtf16(const EcmaVM *vm, const uint16_t *utf16Data, uint32_t utf16Len,
91 bool canBeCompress, MemSpaceType type)
92 {
93 if (utf16Len == 0) {
94 return vm->GetFactory()->GetEmptyString().GetObject<EcmaString>();
95 }
96 auto string = AllocStringObjectWithSpaceType(vm, utf16Len, canBeCompress, type);
97 ASSERT(string != nullptr);
98
99 if (canBeCompress) {
100 CopyUtf16AsUtf8(utf16Data, string->GetDataUtf8Writable(), utf16Len);
101 } else {
102 uint32_t len = utf16Len * (sizeof(uint16_t) / sizeof(uint8_t));
103 if (memcpy_s(string->GetDataUtf16Writable(), len, utf16Data, len) != EOK) {
104 LOG_FULL(FATAL) << "memcpy_s failed";
105 UNREACHABLE();
106 }
107 }
108
109 ASSERT_PRINT(canBeCompress == CanBeCompressed(string), "Bad input canBeCompress!");
110 return string;
111 }
112
113 template<bool verify>
At(int32_t index)114 inline uint16_t EcmaString::At(int32_t index) const
115 {
116 int32_t length = static_cast<int32_t>(GetLength());
117 if (verify) {
118 if ((index < 0) || (index >= length)) {
119 return 0;
120 }
121 }
122 if (!IsUtf16()) {
123 Span<const uint8_t> sp(GetDataUtf8(), length);
124 return sp[index];
125 }
126 Span<const uint16_t> sp(GetDataUtf16(), length);
127 return sp[index];
128 }
129
130 /* static */
AllocStringObject(const EcmaVM * vm,size_t length,bool compressed)131 inline EcmaString *EcmaString::AllocStringObject(const EcmaVM *vm, size_t length, bool compressed)
132 {
133 size_t size = compressed ? ComputeSizeUtf8(length) : ComputeSizeUtf16(length);
134 auto string = reinterpret_cast<EcmaString *>(vm->GetFactory()->AllocStringObject(size));
135 string->SetLength(length, compressed);
136 string->SetRawHashcode(0);
137 return string;
138 }
139
140 /* static */
FastSubUtf8String(const EcmaVM * vm,const JSHandle<EcmaString> & src,uint32_t start,uint32_t length)141 EcmaString *EcmaString::FastSubUtf8String(const EcmaVM *vm, const JSHandle<EcmaString> &src, uint32_t start,
142 uint32_t length)
143 {
144 if (length == 0) {
145 return *vm->GetFactory()->GetEmptyString();
146 }
147 auto string = AllocStringObject(vm, length, true);
148 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
149 Span<uint8_t> dst(string->GetDataUtf8Writable(), length);
150 Span<const uint8_t> source(src->GetDataUtf8() + start, length);
151 EcmaString::StringCopy(dst, length, source, length);
152
153 ASSERT_PRINT(CanBeCompressed(string), "canBeCompresse does not match the real value!");
154 return string;
155 }
156
157 /* static */
FastSubUtf16String(const EcmaVM * vm,const JSHandle<EcmaString> & src,uint32_t start,uint32_t length)158 EcmaString *EcmaString::FastSubUtf16String(const EcmaVM *vm, const JSHandle<EcmaString> &src, uint32_t start,
159 uint32_t length)
160 {
161 if (length == 0) {
162 return *vm->GetFactory()->GetEmptyString();
163 }
164 bool canBeCompressed = CanBeCompressed(src->GetDataUtf16() + start, length);
165 auto string = AllocStringObject(vm, length, canBeCompressed);
166 if (canBeCompressed) {
167 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
168 CopyUtf16AsUtf8(src->GetDataUtf16() + start, string->GetDataUtf8Writable(), length);
169 } else {
170 uint32_t len = length * (sizeof(uint16_t) / sizeof(uint8_t));
171 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
172 Span<uint16_t> dst(string->GetDataUtf16Writable(), length);
173 Span<const uint16_t> source(src->GetDataUtf16() + start, length);
174 EcmaString::StringCopy(dst, len, source, len);
175 }
176 ASSERT_PRINT(canBeCompressed == CanBeCompressed(string), "canBeCompresse does not match the real value!");
177 return string;
178 }
179 } // namespace panda::ecmascript
180 #endif
181