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