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_ECMA_RUNTIM_CALL_INFO_H 17 #define ECMASCRIPT_ECMA_RUNTIM_CALL_INFO_H 18 19 #include <algorithm> 20 21 #include "ecmascript/common.h" 22 #include "ecmascript/js_handle.h" 23 #include "ecmascript/js_tagged_value.h" 24 #include "ecmascript/js_thread.h" 25 #include "ecmascript/tagged_array.h" 26 27 namespace panda::ecmascript { 28 struct EcmaRuntimeCallInfo; 29 using EcmaEntrypoint = JSTaggedValue (*)(EcmaRuntimeCallInfo *); 30 31 struct EcmaRuntimeCallInfo : public base::AlignedStruct<base::AlignedPointer::Size(), 32 base::AlignedPointer, 33 base::AlignedPointer, 34 base::AlignedPointer> { 35 enum class Index : size_t { 36 ThreadIndex = 0, 37 NumArgsIndex, 38 StackArgsIndex, 39 NumOfMembers 40 }; 41 static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes); 42 43 public: GetThreadEcmaRuntimeCallInfo44 inline JSThread *GetThread() const 45 { 46 return thread_; 47 } 48 GetThreadOffsetEcmaRuntimeCallInfo49 static size_t GetThreadOffset(bool isArch32) 50 { 51 return GetOffset<static_cast<size_t>(Index::ThreadIndex)>(isArch32); 52 } 53 GetNumArgsOffsetEcmaRuntimeCallInfo54 static size_t GetNumArgsOffset(bool isArch32) 55 { 56 return GetOffset<static_cast<size_t>(Index::NumArgsIndex)>(isArch32); 57 } 58 GetStackArgsOffsetEcmaRuntimeCallInfo59 static size_t GetStackArgsOffset(bool isArch32) 60 { 61 return GetOffset<static_cast<size_t>(Index::StackArgsIndex)>(isArch32); 62 } 63 GetNewTargetOffsetEcmaRuntimeCallInfo64 static size_t GetNewTargetOffset(bool isArch32) 65 { 66 return GetOffset<static_cast<size_t>(Index::StackArgsIndex)>(isArch32) + 67 NEW_TARGET_INDEX * sizeof(JSTaggedType); 68 } 69 GetThisOffsetEcmaRuntimeCallInfo70 static size_t GetThisOffset(bool isArch32) 71 { 72 return GetOffset<static_cast<size_t>(Index::StackArgsIndex)>(isArch32) + 73 THIS_INDEX * sizeof(JSTaggedType); 74 } 75 GetCallArgOffsetEcmaRuntimeCallInfo76 static size_t GetCallArgOffset(bool isArch32) 77 { 78 return GetOffset<static_cast<size_t>(Index::StackArgsIndex)>(isArch32) + 79 FIRST_ARGS_INDEX * sizeof(JSTaggedType); 80 } 81 SetNewTargetEcmaRuntimeCallInfo82 inline void SetNewTarget(const JSTaggedValue tagged) 83 { 84 SetArg(NEW_TARGET_INDEX, tagged); 85 } 86 SetFunctionEcmaRuntimeCallInfo87 inline void SetFunction(const JSTaggedValue tagged) 88 { 89 SetArg(FUNC_INDEX, tagged); 90 } 91 SetThisEcmaRuntimeCallInfo92 inline void SetThis(const JSTaggedValue tagged) 93 { 94 SetArg(THIS_INDEX, tagged); 95 } 96 SetCallArgEcmaRuntimeCallInfo97 inline void SetCallArg(uint32_t idx, const JSTaggedValue tagged) 98 { 99 ASSERT_PRINT(idx < GetArgsNumber(), "Can not set values out of index range"); 100 SetArg(idx + FIRST_ARGS_INDEX, tagged); 101 } 102 SetCallArgEcmaRuntimeCallInfo103 inline void SetCallArg(const JSTaggedValue arg) 104 { 105 ASSERT_PRINT(GetArgsNumber() == 1, "args number is not 1"); 106 SetArg(FIRST_ARGS_INDEX, arg); 107 } 108 SetCallArgEcmaRuntimeCallInfo109 inline void SetCallArg(const JSTaggedValue arg0, const JSTaggedValue arg1) 110 { 111 ASSERT_PRINT(GetArgsNumber() == 2, "args number is not 2"); // 2: args number 112 SetArg(FIRST_ARGS_INDEX, arg0); 113 SetArg(FIRST_ARGS_INDEX + 1, arg1); 114 } 115 SetCallArgEcmaRuntimeCallInfo116 inline void SetCallArg(const JSTaggedValue arg0, const JSTaggedValue arg1, const JSTaggedValue arg2) 117 { 118 ASSERT_PRINT(GetArgsNumber() == 3, "args number is not 3"); // 3: args number 119 SetArg(FIRST_ARGS_INDEX, arg0); 120 SetArg(FIRST_ARGS_INDEX + 1, arg1); 121 SetArg(FIRST_ARGS_INDEX + 2, arg2); // 2: second index 122 } 123 SetCallArgEcmaRuntimeCallInfo124 inline void SetCallArg(const JSTaggedValue arg0, const JSTaggedValue arg1, const JSTaggedValue arg2, 125 const JSTaggedValue arg3) 126 { 127 ASSERT_PRINT(GetArgsNumber() == 4, "args number is not 4"); // 4: args number 128 SetArg(FIRST_ARGS_INDEX, arg0); 129 SetArg(FIRST_ARGS_INDEX + 1, arg1); 130 SetArg(FIRST_ARGS_INDEX + 2, arg2); // 2: second index 131 SetArg(FIRST_ARGS_INDEX + 3, arg3); // 3: third index 132 } 133 SetCallArgEcmaRuntimeCallInfo134 inline void SetCallArg(const JSTaggedValue arg0, const JSTaggedValue arg1, const JSTaggedValue arg2, 135 const JSTaggedValue arg3, const JSTaggedValue arg4) 136 { 137 ASSERT_PRINT(GetArgsNumber() == 5, "args number is not 5"); // 5: args number 138 SetArg(FIRST_ARGS_INDEX, arg0); 139 SetArg(FIRST_ARGS_INDEX + 1, arg1); 140 SetArg(FIRST_ARGS_INDEX + 2, arg2); // 2: second index 141 SetArg(FIRST_ARGS_INDEX + 3, arg3); // 3: third index 142 SetArg(FIRST_ARGS_INDEX + 4, arg4); // 4: fourth index 143 } 144 SetCallArgEcmaRuntimeCallInfo145 inline void SetCallArg(int32_t argc, const JSTaggedType argv[]) 146 { 147 for (int32_t i = 0; i < argc; i++) { 148 SetCallArg(i, JSTaggedValue(argv[i])); 149 } 150 } 151 SetCallArgEcmaRuntimeCallInfo152 inline void SetCallArg(uint32_t argsLength, const JSHandle<TaggedArray> args) 153 { 154 for (uint32_t i = 0; i < argsLength; i++) { 155 SetCallArg(i, args->Get(GetThread(), i)); 156 } 157 } 158 SetCallArgEcmaRuntimeCallInfo159 inline void SetCallArg(uint32_t argsLength, const TaggedArray* args) 160 { 161 for (uint32_t i = 0; i < argsLength; i++) { 162 SetCallArg(i, args->Get(GetThread(), i)); 163 } 164 } 165 SetCallArgEcmaRuntimeCallInfo166 inline void SetCallArg(uint32_t argsLength, uint32_t startIndex, const EcmaRuntimeCallInfo* argv, int32_t offset) 167 { 168 for (uint32_t i = startIndex; i < argsLength; i++) { 169 SetCallArg(i, argv->GetCallArgValue(i - startIndex + offset)); 170 } 171 } 172 GetFunctionEcmaRuntimeCallInfo173 inline JSHandle<JSTaggedValue> GetFunction() const 174 { 175 return GetArg(FUNC_INDEX); 176 } 177 GetNewTargetEcmaRuntimeCallInfo178 inline JSHandle<JSTaggedValue> GetNewTarget() const 179 { 180 return GetArg(NEW_TARGET_INDEX); 181 } 182 GetThisEcmaRuntimeCallInfo183 inline JSHandle<JSTaggedValue> GetThis() const 184 { 185 return GetArg(THIS_INDEX); 186 } 187 GetCallArgEcmaRuntimeCallInfo188 inline JSHandle<JSTaggedValue> GetCallArg(uint32_t idx) const 189 { 190 return GetArg(idx + FIRST_ARGS_INDEX); 191 } 192 GetFunctionValueEcmaRuntimeCallInfo193 inline JSTaggedValue GetFunctionValue() const 194 { 195 JSHandle<JSTaggedValue> func = GetFunction(); 196 return func.GetTaggedValue(); 197 } 198 GetNewTargetValueEcmaRuntimeCallInfo199 inline JSTaggedValue GetNewTargetValue() const 200 { 201 JSHandle<JSTaggedValue> newTarget = GetNewTarget(); 202 return newTarget.GetTaggedValue(); 203 } 204 GetThisValueEcmaRuntimeCallInfo205 inline JSTaggedValue GetThisValue() const 206 { 207 JSHandle<JSTaggedValue> thisObj = GetThis(); 208 return thisObj.GetTaggedValue(); 209 } 210 GetCallArgValueEcmaRuntimeCallInfo211 inline JSTaggedValue GetCallArgValue(uint32_t idx) const 212 { 213 JSHandle<JSTaggedValue> arg = GetCallArg(idx); 214 return arg.GetTaggedValue(); 215 } 216 217 /* 218 * The number of arguments pairs excluding the 'func', 'new.target' and 'this'. For instance: 219 * for code fragment: " foo(v1); ", GetArgsNumber() returns 1 220 */ GetArgsNumberEcmaRuntimeCallInfo221 inline uint32_t GetArgsNumber() const 222 { 223 return numArgs_ - NUM_MANDATORY_JSFUNC_ARGS; 224 } 225 GetArgsEcmaRuntimeCallInfo226 inline JSTaggedType *GetArgs() 227 { 228 return stackArgs_; 229 } 230 231 private: 232 enum ArgsIndex : uint8_t { FUNC_INDEX = 0, NEW_TARGET_INDEX, THIS_INDEX, FIRST_ARGS_INDEX }; 233 GetArgAddressEcmaRuntimeCallInfo234 inline uintptr_t GetArgAddress(uint32_t idx) const 235 { 236 if (idx < GetArgsNumber() + NUM_MANDATORY_JSFUNC_ARGS) { 237 return reinterpret_cast<uintptr_t>(&stackArgs_[idx]); 238 } 239 return 0U; 240 } 241 SetArgEcmaRuntimeCallInfo242 inline void SetArg(uint32_t idx, const JSTaggedValue tagged) 243 { 244 uintptr_t addr = GetArgAddress(idx); 245 if (addr != 0U) { 246 *reinterpret_cast<JSTaggedValue *>(addr) = tagged; 247 } 248 } 249 GetArgEcmaRuntimeCallInfo250 inline JSHandle<JSTaggedValue> GetArg(uint32_t idx) const 251 { 252 return JSHandle<JSTaggedValue>(GetArgAddress(idx)); 253 } 254 255 private: 256 alignas(sizeof(JSTaggedType)) JSThread *thread_ {nullptr}; 257 alignas(sizeof(JSTaggedType)) uint32_t numArgs_ {0}; // include func, newTarget, this, equal to stackArgs size. 258 __extension__ alignas(sizeof(JSTaggedType)) JSTaggedType stackArgs_[0]; // NOLINT(modernize-avoid-c-arrays) 259 }; 260 } // namespace panda::ecmascript 261 262 #endif // ECMASCRIPT_ECMA_RUNTIM_CALL_INFO_H 263