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_INTERPRETER_FAST_RUNTIME_STUB_INL_H
17 #define ECMASCRIPT_INTERPRETER_FAST_RUNTIME_STUB_INL_H
18
19 #include "ecmascript/interpreter/fast_runtime_stub.h"
20
21 #include "ecmascript/ecma_string-inl.h"
22 #include "ecmascript/global_dictionary-inl.h"
23 #include "ecmascript/global_env.h"
24 #include "ecmascript/interpreter/interpreter.h"
25 #include "ecmascript/js_function.h"
26 #include "ecmascript/js_proxy.h"
27 #include "ecmascript/js_tagged_value-inl.h"
28 #include "ecmascript/object_factory-inl.h"
29 #include "ecmascript/object_fast_operator-inl.h"
30 #include "ecmascript/runtime_call_id.h"
31
32 namespace panda::ecmascript {
33 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
34 #define CHECK_IS_ON_PROTOTYPE_CHAIN(receiver, holder) \
35 if (UNLIKELY((receiver) != (holder))) { \
36 return JSTaggedValue::Hole(); \
37 }
38
FastMul(JSTaggedValue left, JSTaggedValue right)39 JSTaggedValue FastRuntimeStub::FastMul(JSTaggedValue left, JSTaggedValue right)
40 {
41 if (left.IsNumber() && right.IsNumber()) {
42 return JSTaggedValue(left.GetNumber() * right.GetNumber());
43 }
44
45 return JSTaggedValue::Hole();
46 }
47
FastDiv(JSTaggedValue left, JSTaggedValue right)48 JSTaggedValue FastRuntimeStub::FastDiv(JSTaggedValue left, JSTaggedValue right)
49 {
50 if (left.IsNumber() && right.IsNumber()) {
51 double dLeft = left.IsInt() ? left.GetInt() : left.GetDouble();
52 double dRight = right.IsInt() ? right.GetInt() : right.GetDouble();
53 if (UNLIKELY(dRight == 0.0)) {
54 if (dLeft == 0.0 || std::isnan(dLeft)) {
55 return JSTaggedValue(base::NAN_VALUE);
56 }
57 uint64_t flagBit = ((base::bit_cast<uint64_t>(dLeft)) ^ (base::bit_cast<uint64_t>(dRight))) &
58 base::DOUBLE_SIGN_MASK;
59 return JSTaggedValue(base::bit_cast<double>(
60 flagBit ^ (base::bit_cast<uint64_t>(base::POSITIVE_INFINITY))));
61 }
62 return JSTaggedValue(dLeft / dRight);
63 }
64 return JSTaggedValue::Hole();
65 }
66
FastMod(JSTaggedValue left, JSTaggedValue right)67 JSTaggedValue FastRuntimeStub::FastMod(JSTaggedValue left, JSTaggedValue right)
68 {
69 if (right.IsInt() && left.IsInt()) {
70 int iRight = right.GetInt();
71 int iLeft = left.GetInt();
72 if (iRight > 0 && iLeft > 0) {
73 return JSTaggedValue(iLeft % iRight);
74 }
75 }
76 if (left.IsNumber() && right.IsNumber()) {
77 double dLeft = left.IsInt() ? left.GetInt() : left.GetDouble();
78 double dRight = right.IsInt() ? right.GetInt() : right.GetDouble();
79 if (dRight == 0.0 || std::isnan(dRight) || std::isnan(dLeft) || std::isinf(dLeft)) {
80 return JSTaggedValue(base::NAN_VALUE);
81 }
82 if (dLeft == 0.0 || std::isinf(dRight)) {
83 return JSTaggedValue(dLeft);
84 }
85 return JSTaggedValue(std::fmod(dLeft, dRight));
86 }
87 return JSTaggedValue::Hole();
88 }
89
FastEqual(JSTaggedValue left, JSTaggedValue right)90 JSTaggedValue FastRuntimeStub::FastEqual(JSTaggedValue left, JSTaggedValue right)
91 {
92 if (left == right) {
93 if (UNLIKELY(left.IsDouble())) {
94 return JSTaggedValue(!std::isnan(left.GetDouble()));
95 }
96 return JSTaggedValue::True();
97 }
98 if (left.IsNumber()) {
99 if (left.IsInt() && right.IsInt()) {
100 return JSTaggedValue::False();
101 }
102 }
103 if (right.IsUndefinedOrNull()) {
104 if (left.IsUndefinedOrNull()) {
105 return JSTaggedValue::True();
106 }
107 return JSTaggedValue::False();
108 }
109 if (left.IsUndefinedOrNull()) {
110 return JSTaggedValue::False();
111 }
112 if (left.IsBoolean()) {
113 if (right.IsSpecial()) {
114 return JSTaggedValue::False();
115 }
116 }
117 if (left.IsBigInt() && right.IsBigInt()) {
118 return JSTaggedValue(BigInt::Equal(left, right));
119 }
120 return JSTaggedValue::Hole();
121 }
122
FastStrictEqual(JSTaggedValue left, JSTaggedValue right)123 JSTaggedValue FastRuntimeStub::FastStrictEqual(JSTaggedValue left, JSTaggedValue right)
124 {
125 if (left.IsNumber()) {
126 if (right.IsNumber()) {
127 double dLeft = left.IsInt() ? left.GetInt() : left.GetDouble();
128 double dRight = right.IsInt() ? right.GetInt() : right.GetDouble();
129 return JSTaggedValue::StrictNumberEquals(dLeft, dRight) ? JSTaggedValue::True() : JSTaggedValue::False();
130 }
131 return JSTaggedValue::False();
132 }
133 if (right.IsNumber()) {
134 return JSTaggedValue::False();
135 }
136 if (left == right) {
137 return JSTaggedValue::True();
138 }
139 if (left.IsString() && right.IsString()) {
140 auto leftStr = static_cast<EcmaString *>(left.GetTaggedObject());
141 auto rightStr = static_cast<EcmaString *>(right.GetTaggedObject());
142 if (EcmaStringAccessor(leftStr).IsFlat() && EcmaStringAccessor(rightStr).IsFlat()) {
143 return EcmaStringAccessor::StringsAreEqual(static_cast<EcmaString *>(left.GetTaggedObject()),
144 static_cast<EcmaString *>(right.GetTaggedObject())) ?
145 JSTaggedValue::True() : JSTaggedValue::False();
146 }
147 return JSTaggedValue::Hole();
148 }
149 if (left.IsBigInt()) {
150 if (right.IsBigInt()) {
151 return BigInt::Equal(left, right) ? JSTaggedValue::True() : JSTaggedValue::False();
152 }
153 return JSTaggedValue::False();
154 }
155 if (right.IsBigInt()) {
156 return JSTaggedValue::False();
157 }
158 return JSTaggedValue::False();
159 }
160
CallGetter(JSThread *thread, JSTaggedValue receiver, JSTaggedValue holder, JSTaggedValue value)161 JSTaggedValue FastRuntimeStub::CallGetter(JSThread *thread, JSTaggedValue receiver, JSTaggedValue holder,
162 JSTaggedValue value)
163 {
164 return ObjectFastOperator::CallGetter(thread, receiver, holder, value);
165 }
166
CallSetter(JSThread *thread, JSTaggedValue receiver, JSTaggedValue value, JSTaggedValue accessorValue)167 JSTaggedValue FastRuntimeStub::CallSetter(JSThread *thread, JSTaggedValue receiver, JSTaggedValue value,
168 JSTaggedValue accessorValue)
169 {
170 return ObjectFastOperator::CallSetter(thread, receiver, value, accessorValue);
171 }
172
173 template<ObjectFastOperator::Status status>
GetPropertyByIndex(JSThread *thread, JSTaggedValue receiver, uint32_t index)174 JSTaggedValue FastRuntimeStub::GetPropertyByIndex(JSThread *thread, JSTaggedValue receiver, uint32_t index)
175 {
176 return ObjectFastOperator::GetPropertyByIndex<status>(thread, receiver, index);
177 }
178
179 template<ObjectFastOperator::Status status>
GetPropertyByValue(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)180 JSTaggedValue FastRuntimeStub::GetPropertyByValue(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)
181 {
182 return ObjectFastOperator::GetPropertyByValue<status>(thread, receiver, key);
183 }
184
185 template<ObjectFastOperator::Status status>
GetPropertyByName(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)186 JSTaggedValue FastRuntimeStub::GetPropertyByName(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)
187 {
188 return ObjectFastOperator::GetPropertyByName<status>(thread, receiver, key);
189 }
190
191 template<ObjectFastOperator::Status status>
SetPropertyByName(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key, JSTaggedValue value)192 JSTaggedValue FastRuntimeStub::SetPropertyByName(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key,
193 JSTaggedValue value)
194 {
195 [[maybe_unused]] EcmaHandleScope handleScope(thread);
196 return ObjectFastOperator::SetPropertyByName<status>(thread, receiver, key, value);
197 }
198
199 template<ObjectFastOperator::Status status>
SetPropertyByIndex(JSThread *thread, JSTaggedValue receiver, uint32_t index, JSTaggedValue value)200 JSTaggedValue FastRuntimeStub::SetPropertyByIndex(JSThread *thread, JSTaggedValue receiver, uint32_t index,
201 JSTaggedValue value)
202 {
203 [[maybe_unused]] EcmaHandleScope handleScope(thread);
204 return ObjectFastOperator::SetPropertyByIndex<status>(thread, receiver, index, value);
205 }
206
207 template<ObjectFastOperator::Status status>
SetPropertyByValue(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key, JSTaggedValue value)208 JSTaggedValue FastRuntimeStub::SetPropertyByValue(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key,
209 JSTaggedValue value)
210 {
211 [[maybe_unused]] EcmaHandleScope handleScope(thread);
212 return ObjectFastOperator::SetPropertyByValue<status>(thread, receiver, key, value);
213 }
214
GetGlobalOwnProperty(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)215 JSTaggedValue FastRuntimeStub::GetGlobalOwnProperty(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)
216 {
217 JSObject *obj = JSObject::Cast(receiver);
218 TaggedArray *properties = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
219 GlobalDictionary *dict = GlobalDictionary::Cast(properties);
220 int entry = dict->FindEntry(key);
221 if (entry != -1) {
222 auto value = dict->GetValue(entry);
223 if (UNLIKELY(value.IsAccessor())) {
224 return CallGetter(thread, receiver, receiver, value);
225 }
226 ASSERT(!value.IsAccessor());
227 return value;
228 }
229 return JSTaggedValue::Hole();
230 }
231
FastTypeOf(JSThread *thread, JSTaggedValue obj)232 JSTaggedValue FastRuntimeStub::FastTypeOf(JSThread *thread, JSTaggedValue obj)
233 {
234 INTERPRETER_TRACE(thread, FastTypeOf);
235 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
236 switch (obj.GetRawData()) {
237 case JSTaggedValue::VALUE_TRUE:
238 case JSTaggedValue::VALUE_FALSE:
239 return globalConst->GetBooleanString();
240 case JSTaggedValue::VALUE_NULL:
241 return globalConst->GetObjectString();
242 case JSTaggedValue::VALUE_UNDEFINED:
243 return globalConst->GetUndefinedString();
244 default:
245 if (obj.IsHeapObject()) {
246 if (obj.IsString()) {
247 return globalConst->GetStringString();
248 }
249 if (obj.IsSymbol()) {
250 return globalConst->GetSymbolString();
251 }
252 if (obj.IsCallable()) {
253 return globalConst->GetFunctionString();
254 }
255 if (obj.IsBigInt()) {
256 return globalConst->GetBigIntString();
257 }
258 if (obj.IsNativeModuleFailureInfo()) {
259 return globalConst->GetNativeModuleFailureInfoString();
260 }
261 return globalConst->GetObjectString();
262 }
263 if (obj.IsNumber()) {
264 return globalConst->GetNumberString();
265 }
266 }
267 return globalConst->GetUndefinedString();
268 }
269
NewLexicalEnv(JSThread *thread, ObjectFactory *factory, uint16_t numVars)270 JSTaggedValue FastRuntimeStub::NewLexicalEnv(JSThread *thread, ObjectFactory *factory, uint16_t numVars)
271 {
272 INTERPRETER_TRACE(thread, NewLexicalEnv);
273 [[maybe_unused]] EcmaHandleScope handleScope(thread);
274 LexicalEnv *newEnv = factory->InlineNewLexicalEnv(numVars);
275 if (UNLIKELY(newEnv == nullptr)) {
276 return JSTaggedValue::Hole();
277 }
278 JSTaggedValue currentLexenv = thread->GetCurrentLexenv();
279 newEnv->SetParentEnv(thread, currentLexenv);
280 newEnv->SetScopeInfo(thread, JSTaggedValue::Hole());
281 return JSTaggedValue(newEnv);
282 }
283
NewThisObject(JSThread *thread, JSTaggedValue ctor, JSTaggedValue newTarget, InterpretedFrame *state)284 JSTaggedValue FastRuntimeStub::NewThisObject(JSThread *thread, JSTaggedValue ctor, JSTaggedValue newTarget,
285 InterpretedFrame *state)
286 {
287 [[maybe_unused]] EcmaHandleScope handleScope(thread);
288 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
289
290 JSHandle<JSFunction> ctorHandle(thread, ctor);
291 JSHandle<JSTaggedValue> newTargetHandle(thread, newTarget);
292 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(ctorHandle, newTargetHandle);
293 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
294
295 Method *method = Method::Cast(ctorHandle->GetMethod().GetTaggedObject());
296 state->function = ctorHandle.GetTaggedValue();
297 state->constpool = method->GetConstantPool();
298 state->profileTypeInfo = ctorHandle->GetProfileTypeInfo();
299 state->env = ctorHandle->GetLexicalEnv();
300
301 return obj.GetTaggedValue();
302 }
303 } // namespace panda::ecmascript
304 #endif // ECMASCRIPT_INTERPRETER_FAST_RUNTIME_STUB_INL_H
305