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