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
32namespace 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
39JSTaggedValue 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
48JSTaggedValue 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
67JSTaggedValue 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
90JSTaggedValue 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
123JSTaggedValue 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
161JSTaggedValue FastRuntimeStub::CallGetter(JSThread *thread, JSTaggedValue receiver, JSTaggedValue holder,
162                                          JSTaggedValue value)
163{
164    return ObjectFastOperator::CallGetter(thread, receiver, holder, value);
165}
166
167JSTaggedValue FastRuntimeStub::CallSetter(JSThread *thread, JSTaggedValue receiver, JSTaggedValue value,
168                                          JSTaggedValue accessorValue)
169{
170    return ObjectFastOperator::CallSetter(thread, receiver, value, accessorValue);
171}
172
173template<ObjectFastOperator::Status status>
174JSTaggedValue FastRuntimeStub::GetPropertyByIndex(JSThread *thread, JSTaggedValue receiver, uint32_t index)
175{
176    return ObjectFastOperator::GetPropertyByIndex<status>(thread, receiver, index);
177}
178
179template<ObjectFastOperator::Status status>
180JSTaggedValue FastRuntimeStub::GetPropertyByValue(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)
181{
182    return ObjectFastOperator::GetPropertyByValue<status>(thread, receiver, key);
183}
184
185template<ObjectFastOperator::Status status>
186JSTaggedValue FastRuntimeStub::GetPropertyByName(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)
187{
188    return ObjectFastOperator::GetPropertyByName<status>(thread, receiver, key);
189}
190
191template<ObjectFastOperator::Status status>
192JSTaggedValue 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
199template<ObjectFastOperator::Status status>
200JSTaggedValue 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
207template<ObjectFastOperator::Status status>
208JSTaggedValue 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
215JSTaggedValue 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
232JSTaggedValue 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
270JSTaggedValue 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
284JSTaggedValue 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