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