1 /*
2 * Copyright (c) 2024 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/compiler/builtins/builtins_collator_stub_builder.h"
17
18 #include "ecmascript/compiler/new_object_stub_builder.h"
19
20 namespace panda::ecmascript::kungfu {
ResolvedOptions(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)21 void BuiltinsCollatorStubBuilder::ResolvedOptions(GateRef glue, GateRef thisValue, [[maybe_unused]] GateRef numArgs,
22 Variable* res, Label* exit,
23 Label* slowPath)
24 {
25 auto env = GetEnvironment();
26 Label entryPass(env);
27 env->SubCfgEntry(&entryPass);
28
29 Label isHeapObject(env);
30 Label isJsCollator(env);
31
32 BRANCH_LIKELY(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
33 Bind(&isHeapObject);
34 BRANCH_LIKELY(IsJSCollator(thisValue), &isJsCollator, slowPath);
35
36 Bind(&isJsCollator);
37 GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
38 GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
39 GateRef funCtor = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::OBJECT_FUNCTION_INDEX);
40
41 NewObjectStubBuilder newObjectStubBuilder(this);
42 GateRef initialOptions = newObjectStubBuilder.NewJSObjectByConstructor(glue, funCtor, funCtor);
43 DEFVARIABLE(options, VariableType::JS_ANY(), initialOptions);
44
45 // [[Locale]]
46 GateRef localeKey = GetGlobalConstantValue(VariableType::JS_ANY(), glue, ConstantIndex::LOCALE_STRING_INDEX);
47 GateRef locale = Load(VariableType::JS_ANY(), thisValue, IntPtr(JSCollator::LOCALE_OFFSET));
48 CreateDataPropertyOrThrow(glue, *options, localeKey, locale);
49 ReturnExceptionIfAbruptCompletion(glue);
50
51 // [[Usage]]
52 GateRef usageKey = GetGlobalConstantValue(VariableType::JS_ANY(), glue, ConstantIndex::USAGE_INDEX);
53 GateRef usage = GetBitField<JSCollator::UsageBits>(thisValue);
54 usage = UsageOptionsToEcmaString(glue, usage);
55 CreateDataProperty(glue, *options, usageKey, usage);
56
57 // [[Sensitivity]]
58 GateRef sensitivityKey = GetGlobalConstantValue(VariableType::JS_ANY(), glue, ConstantIndex::SENSITIVITY_INDEX);
59 GateRef sensitivity = GetBitField<JSCollator::SensitivityBits>(thisValue);
60 sensitivity = SensitivityOptionsToEcmaString(glue, sensitivity);
61 CreateDataProperty(glue, *options, sensitivityKey, sensitivity);
62
63 // [[IgnorePunctuation]]
64 GateRef ignorePunctuationKey = GetGlobalConstantValue(VariableType::JS_ANY(), glue,
65 ConstantIndex::IGNORE_PUNCTUATION_INDEX);
66 GateRef ignorePunctuation = GetBitField<JSCollator::IgnorePunctuationBits>(thisValue);
67 ignorePunctuation = BooleanToTaggedBooleanPtr(TruncInt32ToInt1(ignorePunctuation));
68 CreateDataProperty(glue, *options, ignorePunctuationKey, ignorePunctuation);
69
70 // [[Collation]]
71 Label undefined(env);
72 Label notUndefined(env);
73 GateRef collation = Load(VariableType::JS_ANY(), thisValue, IntPtr(JSCollator::COLLATION_OFFSET));
74 GateRef collationKey = GetGlobalConstantValue(VariableType::JS_ANY(), glue,
75 ConstantIndex::COLLATION_STRING_CLASS_INDEX);
76 DEFVARIABLE(collationVar, VariableType::JS_ANY(), collation);
77 BRANCH_NO_WEIGHT(TaggedIsUndefined(*collationVar), &undefined, ¬Undefined);
78 Bind(&undefined);
79 {
80 collationVar = CallRuntime(glue, RTSTUB_ID(GetCollationValueFromIcuCollator), {thisValue});
81 Jump(¬Undefined);
82 }
83 Bind(¬Undefined);
84 CreateDataProperty(glue, *options, collationKey, *collationVar);
85
86 // [[Numeric]]
87 GateRef numericKey = GetGlobalConstantValue(VariableType::JS_ANY(), glue,
88 ConstantIndex::NUMERIC_STRING_CLASS_INDEX);
89 GateRef numeric = GetBitField<JSCollator::NumericBits>(thisValue);
90 numeric = BooleanToTaggedBooleanPtr(TruncInt32ToInt1(numeric));
91 CreateDataProperty(glue, *options, numericKey, numeric);
92
93 // [[CaseFirst]]
94 GateRef caseFirstKey = GetGlobalConstantValue(VariableType::JS_ANY(), glue,
95 ConstantIndex::CASE_FIRST_STRING_CLASS_INDEX);
96 GateRef caseFirst = GetBitField<JSCollator::CaseFirstBits>(thisValue);
97 caseFirst = CaseFirstOptionsToEcmaString(glue, caseFirst);
98 CreateDataProperty(glue, *options, caseFirstKey, caseFirst);
99 res->WriteVariable(*options);
100 Jump(exit);
101 env->SubCfgExit();
102 }
103
104 template <typename BitType>
GetBitField(GateRef collator)105 GateRef BuiltinsCollatorStubBuilder::GetBitField(GateRef collator)
106 {
107 GateRef bitFieldOffset = IntPtr(JSCollator::BIT_FIELD_OFFSET);
108 GateRef bitfield = Load(VariableType::INT32(), collator, bitFieldOffset);
109 GateRef bits = Int32And(Int32LSR(bitfield, Int32(BitType::START_BIT)),
110 Int32((1LU << BitType::SIZE) - 1));
111 return bits;
112 }
113
UsageOptionsToEcmaString(GateRef glue,GateRef usage)114 GateRef BuiltinsCollatorStubBuilder::UsageOptionsToEcmaString(GateRef glue, GateRef usage)
115 {
116 auto env = GetEnvironment();
117 Label subEntry(env);
118 env->SubCfgEntry(&subEntry);
119 Label exit(env);
120 DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
121
122 Label sort(env);
123 Label next(env);
124 Label search(env);
125 Label fatal(env);
126 BRANCH_NO_WEIGHT(Int32Equal(usage, Int32(static_cast<int32_t>(UsageOption::SORT))), &sort, &next)
127 Bind(&sort);
128 {
129 result = GetGlobalConstantValue(VariableType::JS_ANY(), glue, ConstantIndex::SORT_INDEX);
130 Jump(&exit);
131 }
132
133 Bind(&next);
134 BRANCH_NO_WEIGHT(Int32Equal(usage, Int32(static_cast<int32_t>(UsageOption::SEARCH))), &search, &fatal)
135 Bind(&search);
136 {
137 result = GetGlobalConstantValue(VariableType::JS_ANY(), glue, ConstantIndex::SEARCH_INDEX);
138 Jump(&exit);
139 }
140 Bind(&fatal);
141 {
142 FatalPrint(glue, {Int32(GET_MESSAGE_STRING_ID(ThisBranchIsUnreachable))});
143 Jump(&exit);
144 }
145
146 Bind(&exit);
147 auto ret = *result;
148 env->SubCfgExit();
149 return ret;
150 }
151
SensitivityOptionsToEcmaString(GateRef glue,GateRef sensitivity)152 GateRef BuiltinsCollatorStubBuilder::SensitivityOptionsToEcmaString(GateRef glue, GateRef sensitivity)
153 {
154 auto env = GetEnvironment();
155 Label subEntry(env);
156 env->SubCfgEntry(&subEntry);
157 Label exit(env);
158
159 DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
160 Label undefined(env);
161 Label fatal(env);
162
163 Label labels[SENSITIVITY_OPTION_CASES_NUM] = {Label(env), Label(env), Label(env), Label(env), undefined};
164 Switch(ZExtInt32ToInt64(sensitivity), &fatal, SensitivityOptionCases, labels, SENSITIVITY_OPTION_CASES_NUM);
165
166 for (size_t i = 0; i < SENSITIVITY_OPTION_CASES_NUM - 1; i++) {
167 Bind(&labels[i]);
168 result = GetGlobalConstantValue(VariableType::JS_ANY(), glue, SensitivityOptionIndexes[i]);
169 Jump(&exit);
170 }
171
172 Bind(&undefined);
173 {
174 Jump(&exit);
175 }
176 Bind(&fatal);
177 {
178 FatalPrint(glue, {Int32(GET_MESSAGE_STRING_ID(ThisBranchIsUnreachable))});
179 Jump(&exit);
180 }
181 Bind(&exit);
182 auto ret = *result;
183 env->SubCfgExit();
184 return ret;
185 }
186
CaseFirstOptionsToEcmaString(GateRef glue,GateRef sensitivity)187 GateRef BuiltinsCollatorStubBuilder::CaseFirstOptionsToEcmaString(GateRef glue, GateRef sensitivity)
188 {
189 auto env = GetEnvironment();
190 Label subEntry(env);
191 env->SubCfgEntry(&subEntry);
192 Label exit(env);
193
194 DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
195 Label fatal(env);
196
197 Label labels[CASE_FIRST_OPTION_NUM] = {Label(env), Label(env), Label(env), Label(env)};
198 Switch(ZExtInt32ToInt64(sensitivity), &fatal, CaseFirstOptionCases, labels, CASE_FIRST_OPTION_NUM);
199
200 for (size_t i = 0; i < CASE_FIRST_OPTION_NUM; i++) {
201 Bind(&labels[i]);
202 result = GetGlobalConstantValue(VariableType::JS_ANY(), glue, CaseFirstOptionIndexes[i]);
203 Jump(&exit);
204 }
205
206 Bind(&fatal);
207 {
208 FatalPrint(glue, {Int32(GET_MESSAGE_STRING_ID(ThisBranchIsUnreachable))});
209 Jump(&exit);
210 }
211 Bind(&exit);
212 auto ret = *result;
213 env->SubCfgExit();
214 return ret;
215 }
216
217 int64_t BuiltinsCollatorStubBuilder::SensitivityOptionCases[SENSITIVITY_OPTION_CASES_NUM] = {
218 static_cast<int64_t>(SensitivityOption::BASE), static_cast<int64_t>(SensitivityOption::ACCENT),
219 static_cast<int64_t>(SensitivityOption::CASE), static_cast<int64_t>(SensitivityOption::VARIANT),
220 static_cast<int64_t>(SensitivityOption::UNDEFINED)
221 };
222
223 ConstantIndex BuiltinsCollatorStubBuilder::SensitivityOptionIndexes[SENSITIVITY_OPTION_CASES_NUM - 1] = {
224 ConstantIndex::BASE_INDEX, ConstantIndex::ACCENT_INDEX,
225 ConstantIndex::CASE_INDEX, ConstantIndex::VARIANT_INDEX
226 };
227
228 int64_t BuiltinsCollatorStubBuilder::CaseFirstOptionCases[CASE_FIRST_OPTION_NUM] = {
229 static_cast<int64_t>(CaseFirstOption::UPPER), static_cast<int64_t>(CaseFirstOption::LOWER),
230 static_cast<int64_t>(CaseFirstOption::FALSE_OPTION), static_cast<int64_t>(CaseFirstOption::UNDEFINED)
231 };
232
233 ConstantIndex BuiltinsCollatorStubBuilder::CaseFirstOptionIndexes[CASE_FIRST_OPTION_NUM] = {
234 ConstantIndex::UPPER_INDEX, ConstantIndex::LOWER_INDEX,
235 ConstantIndex::FALSE_STRING_INDEX, ConstantIndex::UPPER_INDEX
236 };
237 }
238