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