Merge remote-tracking branch 'oh/master'

This commit is contained in:
Yuqiang Xian 2022-06-08 11:21:28 +08:00
commit c2ee264a82
288 changed files with 13410 additions and 6924 deletions

View File

@ -109,6 +109,7 @@ if (defined(ark_independent_build)) {
if (is_standard_system) {
deps += [ "//ark/js_runtime/test/aottest:ark_aot_test" ]
deps += [ "//ark/js_runtime/test/moduletest:ark_asm_test" ]
deps += [ "//ark/js_runtime/test/typeinfer:ark_typeinfer_test" ]
}
}
}
@ -301,6 +302,7 @@ config("icu_path_test_config") {
ecma_source = [
"ecmascript/base/array_helper.cpp",
"ecmascript/base/atomic_helper.cpp",
"ecmascript/base/builtins_base.cpp",
"ecmascript/base/error_helper.cpp",
"ecmascript/base/json_parser.cpp",
@ -314,6 +316,7 @@ ecma_source = [
"ecmascript/builtins/builtins_array.cpp",
"ecmascript/builtins/builtins_arraybuffer.cpp",
"ecmascript/builtins/builtins_async_function.cpp",
"ecmascript/builtins/builtins_atomics.cpp",
"ecmascript/builtins/builtins_bigint.cpp",
"ecmascript/builtins/builtins_boolean.cpp",
"ecmascript/builtins/builtins_dataview.cpp",
@ -346,6 +349,8 @@ ecma_source = [
"ecmascript/builtins/builtins_weak_set.cpp",
"ecmascript/containers/containers_arraylist.cpp",
"ecmascript/containers/containers_deque.cpp",
"ecmascript/containers/containers_linked_list.cpp",
"ecmascript/containers/containers_list.cpp",
"ecmascript/containers/containers_plainarray.cpp",
"ecmascript/containers/containers_private.cpp",
"ecmascript/containers/containers_queue.cpp",
@ -391,6 +396,10 @@ ecma_source = [
"ecmascript/js_api_arraylist_iterator.cpp",
"ecmascript/js_api_deque.cpp",
"ecmascript/js_api_deque_iterator.cpp",
"ecmascript/js_api_linked_list.cpp",
"ecmascript/js_api_linked_list_iterator.cpp",
"ecmascript/js_api_list.cpp",
"ecmascript/js_api_list_iterator.cpp",
"ecmascript/js_api_plain_array.cpp",
"ecmascript/js_api_plain_array_iterator.cpp",
"ecmascript/js_api_queue.cpp",
@ -477,8 +486,10 @@ ecma_source = [
"ecmascript/regexp/regexp_parser_cache.cpp",
"ecmascript/shared_mm/shared_mm.cpp",
"ecmascript/tagged_dictionary.cpp",
"ecmascript/tagged_list.cpp",
"ecmascript/tagged_tree.cpp",
"ecmascript/template_string.cpp",
"ecmascript/waiter_list.cpp",
"ecmascript/weak_vector.cpp",
"ecmascript/compiler/llvm/llvm_stackmap_parser.cpp",
"ecmascript/stubs/runtime_stubs.cpp",
@ -521,21 +532,6 @@ if (!is_mingw && !is_mac) {
]
}
if (current_cpu == "arm") {
ecma_source += [ "ecmascript/trampoline/arm32/call.S" ]
} else if (current_cpu == "arm64") {
ecma_source += [ "ecmascript/trampoline/aarch64/call.S" ]
} else if (current_cpu == "amd64" || current_cpu == "x64" ||
current_cpu == "x86_64") {
if (is_linux) {
ecma_source += [ "ecmascript/trampoline/x64/call.S" ]
} else if (is_mingw) {
ecma_source += [ "ecmascript/trampoline/win_x64/call.S" ]
} else if (is_mac) {
ecma_source += [ "ecmascript/trampoline/mac_x64/call.S" ]
}
}
source_set("libark_jsruntime_set") {
sources = ecma_source
sources += ecma_profiler_source

View File

@ -0,0 +1,140 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/base/atomic_helper.h"
#include "ecmascript/base/typed_array_helper-inl.h"
namespace panda::ecmascript::base {
using BuiltinsArrayBuffer = builtins::BuiltinsArrayBuffer;
JSTaggedValue AtomicHelper::ValidateIntegerTypedArray(JSThread *thread, JSHandle<JSTaggedValue> typedArray,
bool waitable)
{
// 1. If waitable is not present, set waitable to false.
// 2. Let buffer be ? ValidateTypedArray(typedArray).
JSTaggedValue buffer = TypedArrayHelper::ValidateTypedArray(thread, typedArray);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> bufferHandle(thread, buffer);
// 3. Let typeName be typedArray.[[TypedArrayName]].
// 4. Let type be the Element Type value in Table 60 for typeName.
JSHandle<JSTaggedValue> typeName(thread, JSTypedArray::Cast(typedArray->GetTaggedObject())->GetTypedArrayName());
DataViewType type = JSTypedArray::GetTypeFromName(thread, typeName);
// 5. If waitable is true, then
// a. If typeName is not "Int32Array" or "BigInt64Array", throw a TypeError exception.
// 6. Else,
// a. If ! IsUnclampedIntegerElementType(type) is false and ! IsBigIntElementType(type) is false,
// throw a TypeError exception.
if (waitable) {
if (!(type == DataViewType::INT32 || type == DataViewType::BIGINT64)) {
THROW_TYPE_ERROR_AND_RETURN(thread, "The typeName is not Int32Array/BigInt64Array.",
JSTaggedValue::Exception());
}
} else {
if (!(BuiltinsArrayBuffer::IsUnclampedIntegerElementType(type) ||
BuiltinsArrayBuffer::IsBigIntElementType(type))) {
THROW_TYPE_ERROR_AND_RETURN(thread, "The typedArray type is not UnclampedInteger/BigInt.",
JSTaggedValue::Exception());
}
}
// 7. Return buffer.
return bufferHandle.GetTaggedValue();
}
int32_t AtomicHelper::ValidateAtomicAccess(JSThread *thread, const JSHandle<JSTaggedValue> typedArray,
JSHandle<JSTaggedValue> requestIndex)
{
// 1. Assert: typedArray is an Object that has a [[ViewedArrayBuffer]] internal slot.
ASSERT(typedArray->IsECMAObject() && typedArray->IsTypedArray());
// 2. Let length be typedArray.[[ArrayLength]].
JSHandle<JSObject> typedArrayObj(typedArray);
JSHandle<JSTypedArray> srcObj(typedArray);
int32_t length = static_cast<int32_t>(srcObj->GetArrayLength());
// 3. Let accessIndex be ? ToIndex(requestIndex).
JSTaggedNumber accessIndex = JSTaggedValue::ToIndex(thread, requestIndex);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0);
int32_t index = base::NumberHelper::DoubleInRangeInt32(accessIndex.GetNumber());
// 4. Assert: accessIndex ≥ 0.
ASSERT(index >= 0);
// 5. If accessIndex ≥ length, throw a RangeError exception.
if (index >= length) {
THROW_RANGE_ERROR_AND_RETURN(thread, "Index is overflow.", 0);
}
// 6. Let arrayTypeName be typedArray.[[TypedArrayName]].
// 7. Let elementSize be the Element Size value specified in Table 60 for arrayTypeName.
// 8. Let offset be typedArray.[[ByteOffset]].
JSHandle<JSTaggedValue> arrayTypeName(thread, JSTypedArray::Cast(*typedArrayObj)->GetTypedArrayName());
int32_t elementSize = TypedArrayHelper::GetSizeFromName(thread, arrayTypeName);
uint32_t offset = srcObj->GetByteOffset();
// 9. Return (accessIndex × elementSize) + offset.
int32_t allOffset = index * elementSize + offset;
return allOffset;
}
JSTaggedValue AtomicHelper::AtomicStore(JSThread *thread, const JSHandle<JSTaggedValue> &typedArray,
JSHandle<JSTaggedValue> index, JSHandle<JSTaggedValue> &value)
{
JSTaggedValue bufferValue = ValidateIntegerTypedArray(thread, typedArray);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> buffer(thread, bufferValue);
uint32_t indexedPosition = ValidateAtomicAccess(thread, typedArray, index);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> arrayTypeName(thread,
JSTypedArray::Cast(typedArray->GetTaggedObject())->GetTypedArrayName());
DataViewType type = JSTypedArray::GetTypeFromName(thread, arrayTypeName);
JSHandle<JSTaggedValue> bufferTag;
if (type == DataViewType::BIGUINT64 || type == DataViewType::BIGINT64) {
JSTaggedValue integerValue = JSTaggedValue::ToBigInt(thread, value);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
bufferTag = JSHandle<JSTaggedValue>(thread, integerValue);
} else {
JSTaggedNumber integerValue = JSTaggedValue::ToInteger(thread, value);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
bufferTag = JSHandle<JSTaggedValue>(thread, integerValue);
}
if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer.GetTaggedValue())) {
THROW_TYPE_ERROR_AND_RETURN(thread, "The ArrayBuffer of this value is detached buffer.",
JSTaggedValue::Exception());
}
BuiltinsArrayBuffer::SetValueInBuffer(thread, buffer.GetTaggedValue(), indexedPosition, type, bufferTag, true);
return bufferTag.GetTaggedValue();
}
JSTaggedValue AtomicHelper::AtomicLoad(JSThread *thread, const JSHandle<JSTaggedValue> &typedArray,
JSHandle<JSTaggedValue> index)
{
JSTaggedValue bufferValue = ValidateIntegerTypedArray(thread, typedArray);
JSHandle<JSTaggedValue> buffer(thread, bufferValue);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
int32_t indexedPosition = ValidateAtomicAccess(thread, typedArray, index);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer.GetTaggedValue())) {
THROW_TYPE_ERROR_AND_RETURN(thread, "The ArrayBuffer of this value is detached buffer.",
JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> arrayTypeName(thread,
JSTypedArray::Cast(typedArray->GetTaggedObject())->GetTypedArrayName());
DataViewType elementType = JSTypedArray::GetTypeFromName(thread, arrayTypeName);
return BuiltinsArrayBuffer::GetValueFromBuffer(thread, buffer.GetTaggedValue(),
indexedPosition, elementType, true);
}
} // panda::ecmascript::base

View File

@ -0,0 +1,104 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_BASE_ATOMIC_HELPER_H
#define ECMASCRIPT_BASE_ATOMIC_HELPER_H
#include "ecmascript/js_dataview.h"
namespace panda::ecmascript::base {
enum class BytesSize : int32_t {ONEBYTES = 1, TWOBYTES = 2, FOURBYTES = 4, EIGHTBYTES = 8};
class AtomicHelper final {
public:
struct SubFun {
template<typename T>
T operator()(T *ptr, const T *arg) const
{
std::atomic<T> *atomicValue = reinterpret_cast<std::atomic<T> *>(ptr);
return atomicValue->fetch_sub(arg[0], std::memory_order_seq_cst);
}
};
struct AddFun {
template<typename T>
T operator()(T *ptr, const T *arg) const
{
std::atomic<T> *atomicValue = reinterpret_cast<std::atomic<T> *>(ptr);
return atomicValue->fetch_add(arg[0], std::memory_order_seq_cst);
}
};
struct AndFun {
template<typename T>
T operator()(T *ptr, const T *arg) const
{
std::atomic<T> *atomicValue = reinterpret_cast<std::atomic<T> *>(ptr);
return atomicValue->fetch_and(arg[0], std::memory_order_seq_cst);
}
};
struct OrFun {
template<typename T>
T operator()(T *ptr, const T *arg) const
{
std::atomic<T> *atomicValue = reinterpret_cast<std::atomic<T> *>(ptr);
return atomicValue->fetch_or(arg[0], std::memory_order_seq_cst);
}
};
struct XorFun {
template<typename T>
T operator()(T *ptr, const T *arg) const
{
std::atomic<T> *atomicValue = reinterpret_cast<std::atomic<T> *>(ptr);
return atomicValue->fetch_xor(arg[0], std::memory_order_seq_cst);
}
};
struct CompareExchangeFun {
template<typename T>
T operator()(T *ptr, const T *arg) const
{
T a = arg[0];
std::atomic<T> *atomicValue = reinterpret_cast<std::atomic<T> *>(ptr);
atomicValue->compare_exchange_strong(a, arg[1], std::memory_order_seq_cst);
return a;
}
};
struct ExchangeFun {
template<typename T>
T operator()(T *ptr, const T *arg) const
{
std::atomic<T> *atomicValue = reinterpret_cast<std::atomic<T> *>(ptr);
return atomicValue->exchange(arg[0], std::memory_order_seq_cst);
}
};
// 25.4.1.1 ValidateIntegerTypedArray ( typedArray [ , waitable ] )
static JSTaggedValue ValidateIntegerTypedArray(JSThread *thread, JSHandle<JSTaggedValue> typedArray,
bool waitable = false);
// 25.4.2.2 ValidateAtomicAccess ( typedArray, requestIndex )
static int32_t ValidateAtomicAccess(JSThread *thread, const JSHandle<JSTaggedValue> typedArray,
JSHandle<JSTaggedValue> requestIndex);
static JSTaggedValue AtomicStore(JSThread *thread, const JSHandle<JSTaggedValue> &typedArray,
JSHandle<JSTaggedValue> index, JSHandle<JSTaggedValue> &value);
static JSTaggedValue AtomicLoad(JSThread *thread, const JSHandle<JSTaggedValue> &typedArray,
JSHandle<JSTaggedValue> index);
};
} // namespace panda::ecmascript::base
#endif // ECMASCRIPT_BASE_ATOMIC_HELPER_H

View File

@ -22,7 +22,6 @@ namespace panda::ecmascript {
#define ECMASCRIPT_ENABLE_DEBUG_MODE 0
#define ECMASCRIPT_ENABLE_ARK_CONTAINER 1
#define ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK 0
#define ECMASCRIPT_ENABLE_ASM_INTERPRETER_LOG 0
#define ECMASCRIPT_ENABLE_RUNTIME_STAT 0 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)

View File

@ -172,7 +172,7 @@ JSTaggedValue ErrorHelper::ErrorCommonConstructor(EcmaRuntimeCallInfo *argv,
return nativeInstanceObj.GetTaggedValue();
}
CString ErrorHelper::DecodeFunctionName(const CString &name)
std::string ErrorHelper::DecodeFunctionName(const std::string &name)
{
if (name.empty()) {
return "anonymous";
@ -182,31 +182,34 @@ CString ErrorHelper::DecodeFunctionName(const CString &name)
JSHandle<EcmaString> ErrorHelper::BuildEcmaStackTrace(JSThread *thread)
{
CString data = BuildNativeAndJsStackTrace(thread);
std::string data = BuildJsStackTrace(thread, false);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
LOG(DEBUG, ECMASCRIPT) << data;
return factory->NewFromUtf8(data);
return factory->NewFromStdString(data);
}
CString ErrorHelper::BuildNativeEcmaStackTrace(JSThread *thread)
std::string ErrorHelper::BuildJsStackTrace(JSThread *thread, bool needNative)
{
CString data;
CString fristLineSrcCode;
std::string data;
std::string fristLineSrcCode;
bool isFirstLine = true;
FrameHandler frameHandler(thread);
for (; frameHandler.HasFrame(); frameHandler.PrevInterpretedFrame()) {
if (frameHandler.IsEntryFrame()) {
if (!frameHandler.IsInterpretedFrame()) {
continue;
}
auto method = frameHandler.CheckAndGetMethod();
if (method == nullptr) {
continue;
}
auto method = frameHandler.GetMethod();
if (!method->IsNativeWithCallField()) {
data.append(" at ");
data += DecodeFunctionName(method->ParseFunctionName());
data += DecodeFunctionName(method->ParseFunctionName().c_str());
data.append(" (");
// source file
tooling::JSPtExtractor *debugExtractor =
JSPandaFileManager::GetInstance()->GetJSPtExtractor(method->GetJSPandaFile());
const CString &sourceFile = debugExtractor->GetSourceFile(method->GetMethodId());
const std::string &sourceFile = debugExtractor->GetSourceFile(method->GetMethodId());
if (sourceFile.empty()) {
data.push_back('?');
} else {
@ -234,11 +237,20 @@ CString ErrorHelper::BuildNativeEcmaStackTrace(JSThread *thread)
data.push_back(')');
data.push_back('\n');
if (isFirstLine) {
const CString &sourceCode = debugExtractor->GetSourceCode(
const std::string &sourceCode = debugExtractor->GetSourceCode(
panda_file::File::EntityId(method->GetJSPandaFile()->GetMainMethodIndex()));
fristLineSrcCode = StringHelper::GetSpecifiedLine(sourceCode, lineNumber);
isFirstLine = false;
}
} else if (needNative) {
data.append(" at native method");
data.append(" (");
auto addr = method->GetNativePointer();
std::stringstream strm;
strm << addr;
data.append(strm.str());
data.push_back(')');
data.push_back('\n');
}
}
if (!fristLineSrcCode.empty()) {
@ -246,17 +258,13 @@ CString ErrorHelper::BuildNativeEcmaStackTrace(JSThread *thread)
if (fristLineSrcCode[codeLen - 1] == '\r') {
fristLineSrcCode = fristLineSrcCode.substr(0, codeLen - 1);
}
fristLineSrcCode = "SourceCode (" + fristLineSrcCode;
fristLineSrcCode.push_back(')');
fristLineSrcCode.push_back('\n');
data = fristLineSrcCode + data;
if (fristLineSrcCode != "ANDA") {
fristLineSrcCode = "SourceCode (" + fristLineSrcCode;
fristLineSrcCode.push_back(')');
fristLineSrcCode.push_back('\n');
data = fristLineSrcCode + data;
}
}
return data;
}
CString ErrorHelper::BuildNativeAndJsStackTrace(JSThread *thread)
{
CString data = BuildNativeEcmaStackTrace(thread);
return data;
}
} // namespace panda::ecmascript::base

View File

@ -31,12 +31,10 @@ public:
static JSTaggedValue ErrorCommonConstructor(EcmaRuntimeCallInfo *argv, const ErrorType &errorType);
static CString BuildNativeEcmaStackTrace(JSThread *thread);
static CString BuildNativeAndJsStackTrace(JSThread *thread);
static std::string BuildJsStackTrace(JSThread *thread, bool needNative);
private:
static CString DecodeFunctionName(const CString &name);
static std::string DecodeFunctionName(const std::string &name);
static JSHandle<EcmaString> BuildEcmaStackTrace(JSThread *thread);

View File

@ -20,6 +20,7 @@
#include <iomanip>
#include <sstream>
#include "ecmascript/base/builtins_base.h"
#include "ecmascript/base/string_helper.h"
#include "ecmascript/js_tagged_value-inl.h"
#include "ecmascript/object_factory.h"
@ -49,21 +50,6 @@ static inline uint8_t ToDigit(uint8_t c)
return '$';
}
bool NumberHelper::IsNonspace(uint16_t c)
{
int i;
int len = sizeof(SPACE_OR_LINE_TERMINAL) / sizeof(SPACE_OR_LINE_TERMINAL[0]);
for (i = 0; i < len; i++) {
if (c == SPACE_OR_LINE_TERMINAL[i]) {
return false;
}
if (c < SPACE_OR_LINE_TERMINAL[i]) {
return true;
}
}
return true;
}
bool NumberHelper::GotoNonspace(uint8_t **ptr, const uint8_t *end)
{
while (*ptr < end) {
@ -80,7 +66,7 @@ bool NumberHelper::GotoNonspace(uint8_t **ptr, const uint8_t *end)
return true;
}
}
if (IsNonspace(c)) {
if (!StringHelper::IsNonspace(c)) {
return true;
}
*ptr += size; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)

View File

@ -22,12 +22,6 @@
#include "ecmascript/js_tagged_value.h"
namespace panda::ecmascript::base {
// NOLINTNEXTLINE(modernize-avoid-c-arrays)
static constexpr uint16_t SPACE_OR_LINE_TERMINAL[] = {
0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x0020, 0x00A0, 0x1680, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004,
0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x2028, 0x2029, 0x202F, 0x205F, 0x3000, 0xFEFF,
};
constexpr double MIN_RADIX = 2;
constexpr double MAX_RADIX = 36;
constexpr double MIN_FRACTION = 0;
@ -107,7 +101,6 @@ private:
static char Carry(char current, int radix);
static double Strtod(const char *str, int exponent, uint8_t radix);
static CString DecimalsToString(double *numberInteger, double fraction, int radix, double delta);
static bool IsNonspace(uint16_t c);
static bool GotoNonspace(uint8_t **ptr, const uint8_t *end);
static void GetBase(double d, int digits, int *decpt, char *buf, char *bufTmp, int size);
static int GetMinmumDigits(double d, int *decpt, char *buf);

View File

@ -59,29 +59,4 @@ EcmaString *StringHelper::Repeat(JSThread *thread, const std::u16string &thisStr
return canBeCompress ? *factory->NewFromUtf16Compress(uint16tData, length) :
*factory->NewFromUtf16NotCompress(uint16tData, length);
}
EcmaString *StringHelper::Trim(JSThread *thread, const std::u16string &thisStr)
{
ecmascript::ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
std::u16string tmpStr = thisStr;
if (tmpStr.empty()) {
return *factory->GetEmptyString();
}
std::string str = U16stringToString(tmpStr);
std::wstring wstr = StringToWstring(str);
std::wregex r(
L"^["
L"\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007"
L"\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]+|["
L"\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007"
L"\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]+$");
wstr = regex_replace(wstr, r, L"");
str = WstringToString(wstr);
tmpStr = StringToU16string(str);
const char16_t *constChar16tData = tmpStr.data();
auto *char16tData = const_cast<char16_t *>(constChar16tData);
auto *uint16tData = reinterpret_cast<uint16_t *>(char16tData);
uint32_t length = tmpStr.size();
return *factory->NewFromUtf16(uint16tData, length);
}
} // namespace panda::ecmascript::base

View File

@ -34,6 +34,13 @@
#include "unicode/unistr.h"
namespace panda::ecmascript::base {
// White Space Code Points and Line Terminators Code Point
// NOLINTNEXTLINE(modernize-avoid-c-arrays)
static constexpr uint16_t SPACE_OR_LINE_TERMINAL[] = {
0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x0020, 0x00A0, 0x1680, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004,
0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x2028, 0x2029, 0x202F, 0x205F, 0x3000, 0xFEFF,
};
class StringHelper {
public:
static std::string ToStdString(EcmaString *string);
@ -194,21 +201,55 @@ public:
return res;
}
static inline CString GetSpecifiedLine(const CString &srcStr, int lineNumber)
static inline std::string GetSpecifiedLine(const std::string &srcStr, int lineNumber)
{
std::stringstream ss(CstringConvertToStdString(srcStr));
std::stringstream ss(srcStr);
int count = 0;
CString lineStr = "";
std::string lineStr = "";
std::string tempLine;
while (getline(ss, tempLine, '\n')) {
count++;
if (count == lineNumber) {
lineStr = ConvertToString(tempLine);
lineStr = tempLine;
break;
}
}
return lineStr;
}
static inline bool IsNonspace(uint16_t c)
{
uint32_t len = sizeof(SPACE_OR_LINE_TERMINAL) / sizeof(SPACE_OR_LINE_TERMINAL[0]);
for (uint32_t i = 0; i < len; i++) {
if (c == SPACE_OR_LINE_TERMINAL[i]) {
return true;
}
if (c < SPACE_OR_LINE_TERMINAL[i]) {
return false;
}
}
return false;
}
template<typename T>
static inline uint32_t GetStart(Span<T> &data, uint32_t length)
{
uint32_t start = 0;
while (start < length && IsNonspace(data[start])) {
start++;
}
return start;
}
template<typename T>
static inline uint32_t GetEnd(Span<T> &data, uint32_t start, uint32_t length)
{
uint32_t end = length - 1;
while (end >= start && IsNonspace(data[end])) {
end--;
}
return end;
}
};
} // namespace panda::ecmascript::base
#endif // ECMASCRIPT_BASE_STRING_HELP_H

View File

@ -92,42 +92,6 @@ uint32_t TypedArrayHelper::GetElementSize(JSType type)
}
}
DataViewType TypedArrayHelper::GetTypeFromName(JSThread *thread, const JSHandle<JSTaggedValue> &typeName)
{
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledInt8ArrayString())) {
return DataViewType::INT8;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledUint8ArrayString())) {
return DataViewType::UINT8;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledUint8ClampedArrayString())) {
return DataViewType::UINT8_CLAMPED;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledInt16ArrayString())) {
return DataViewType::INT16;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledUint16ArrayString())) {
return DataViewType::UINT16;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledInt32ArrayString())) {
return DataViewType::INT32;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledUint32ArrayString())) {
return DataViewType::UINT32;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledFloat32ArrayString())) {
return DataViewType::FLOAT32;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledFloat64ArrayString())) {
return DataViewType::FLOAT64;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledBigInt64ArrayString())) {
return DataViewType::BIGINT64;
}
return DataViewType::BIGUINT64;
}
JSHandle<JSTaggedValue> TypedArrayHelper::GetConstructor(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
{
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();

View File

@ -186,14 +186,14 @@ JSTaggedValue TypedArrayHelper::CreateFromTypedArray(EcmaRuntimeCallInfo *argv,
THROW_TYPE_ERROR_AND_RETURN(thread, "The srcData is detached buffer.", JSTaggedValue::Exception());
}
// 8. Let elementType be the Element Type value in Table 61 for constructorName.
DataViewType elementType = TypedArrayHelper::GetTypeFromName(thread, constructorName);
DataViewType elementType = JSTypedArray::GetTypeFromName(thread, constructorName);
// 9. Let elementLength be srcArray.[[ArrayLength]].
// 10. Let srcName be the String value of srcArray.[[TypedArrayName]].
// 11. Let srcType be the Element Type value in Table 61 for srcName.
// 12. Let srcElementSize be the Element Size value specified in Table 61 for srcName.
uint32_t elementLength = srcObj->GetArrayLength();
JSHandle<JSTaggedValue> srcName(thread, srcObj->GetTypedArrayName());
DataViewType srcType = TypedArrayHelper::GetTypeFromName(thread, srcName);
DataViewType srcType = JSTypedArray::GetTypeFromName(thread, srcName);
uint32_t srcElementSize = TypedArrayHelper::GetSizeFromName(thread, srcName);
// 13. Let srcByteOffset be srcArray.[[ByteOffset]].
// 14. Let elementSize be the Element Size value specified in Table 61 for constructorName.

View File

@ -43,7 +43,6 @@ public:
inline static DataViewType GetType(JSType type);
inline static uint32_t GetElementSize(const JSHandle<JSTypedArray> &obj);
inline static uint32_t GetElementSize(JSType type);
inline static DataViewType GetTypeFromName(JSThread *thread, const JSHandle<JSTaggedValue> &typeName);
inline static JSHandle<JSTaggedValue> GetConstructor(JSThread *thread, const JSHandle<JSTaggedValue> &obj);
inline static JSHandle<JSFunction> GetConstructorFromName(JSThread *thread,
const JSHandle<JSTaggedValue> &typeName);

View File

@ -30,6 +30,7 @@
#include "ecmascript/builtins/builtins_array.h"
#include "ecmascript/builtins/builtins_arraybuffer.h"
#include "ecmascript/builtins/builtins_async_function.h"
#include "ecmascript/builtins/builtins_atomics.h"
#include "ecmascript/builtins/builtins_bigint.h"
#include "ecmascript/builtins/builtins_boolean.h"
#include "ecmascript/builtins/builtins_collator.h"
@ -140,6 +141,7 @@ using StringIterator = builtins::BuiltinsStringIterator;
using RegExp = builtins::BuiltinsRegExp;
using Function = builtins::BuiltinsFunction;
using Math = builtins::BuiltinsMath;
using Atomics = builtins::BuiltinsAtomics;
using ArrayBuffer = builtins::BuiltinsArrayBuffer;
using Json = builtins::BuiltinsJson;
using Proxy = builtins::BuiltinsProxy;
@ -320,6 +322,7 @@ void Builtins::Initialize(const JSHandle<GlobalEnv> &env, JSThread *thread)
InitializeGlobalObject(env, globalObject);
InitializeMath(env, objFuncPrototypeVal);
InitializeAtomics(env, objFuncPrototypeVal);
InitializeJson(env, objFuncPrototypeVal);
InitializeIterator(env, objFuncDynclass);
InitializeProxy(env);
@ -586,6 +589,10 @@ void Builtins::InitializeSymbol(const JSHandle<GlobalEnv> &env, const JSHandle<J
SetNoneAttributeProperty(symbolFunction, "toPrimitive", toPrimitiveSymbol);
JSHandle<JSTaggedValue> unscopablesSymbol(factory_->NewPublicSymbolWithChar("Symbol.unscopables"));
SetNoneAttributeProperty(symbolFunction, "unscopables", unscopablesSymbol);
JSHandle<JSTaggedValue> attachSymbol(factory_->NewPublicSymbolWithChar("Symbol.attach"));
SetNoneAttributeProperty(symbolFunction, "attach", attachSymbol);
JSHandle<JSTaggedValue> detachSymbol(factory_->NewPublicSymbolWithChar("Symbol.detach"));
SetNoneAttributeProperty(symbolFunction, "detach", detachSymbol);
// symbol.prototype.description
PropertyDescriptor descriptionDesc(thread_);
@ -615,6 +622,8 @@ void Builtins::InitializeSymbol(const JSHandle<GlobalEnv> &env, const JSHandle<J
env->SetSplitSymbol(thread_, splitSymbol);
env->SetToPrimitiveSymbol(thread_, toPrimitiveSymbol);
env->SetUnscopablesSymbol(thread_, unscopablesSymbol);
env->SetAttachSymbol(thread_, attachSymbol);
env->SetDetachSymbol(thread_, detachSymbol);
// Setup %SymbolPrototype%
SetStringTagSymbol(env, symbolFuncPrototype, "Symbol");
@ -670,6 +679,8 @@ void Builtins::InitializeSymbolWithRealm(const JSHandle<GlobalEnv> &realm,
SetNoneAttributeProperty(symbolFunction, "split", env->GetSplitSymbol());
SetNoneAttributeProperty(symbolFunction, "toPrimitive", env->GetToPrimitiveSymbol());
SetNoneAttributeProperty(symbolFunction, "unscopables", env->GetUnscopablesSymbol());
SetNoneAttributeProperty(symbolFunction, "attach", env->GetAttachSymbol());
SetNoneAttributeProperty(symbolFunction, "detach", env->GetDetachSymbol());
// symbol.prototype.description
PropertyDescriptor descriptionDesc(thread_);
@ -700,6 +711,8 @@ void Builtins::InitializeSymbolWithRealm(const JSHandle<GlobalEnv> &realm,
realm->SetSplitSymbol(thread_, env->GetSplitSymbol());
realm->SetToPrimitiveSymbol(thread_, env->GetToPrimitiveSymbol());
realm->SetUnscopablesSymbol(thread_, env->GetUnscopablesSymbol());
realm->SetAttachSymbol(thread_, env->GetAttachSymbol());
realm->SetDetachSymbol(thread_, env->GetDetachSymbol());
// Setup %SymbolPrototype%
SetStringTagSymbol(realm, symbolFuncPrototype, "Symbol");
@ -1363,6 +1376,34 @@ void Builtins::InitializeWeakSet(const JSHandle<GlobalEnv> &env, const JSHandle<
env->SetBuiltinsWeakSetFunction(thread_, weakSetFunction);
}
void Builtins::InitializeAtomics(const JSHandle<GlobalEnv> &env,
const JSHandle<JSTaggedValue> &objFuncPrototypeVal) const
{
[[maybe_unused]] EcmaHandleScope scope(thread_);
JSHandle<JSHClass> atomicsDynclass = factory_->NewEcmaDynClass(JSObject::SIZE, JSType::JS_OBJECT,
objFuncPrototypeVal);
JSHandle<JSObject> atomicsObject = factory_->NewJSObject(atomicsDynclass);
SetFunction(env, atomicsObject, "add", Atomics::Add, FunctionLength::THREE);
SetFunction(env, atomicsObject, "and", Atomics::And, FunctionLength::THREE);
SetFunction(env, atomicsObject, "sub", Atomics::Sub, FunctionLength::THREE);
SetFunction(env, atomicsObject, "or", Atomics::Or, FunctionLength::THREE);
SetFunction(env, atomicsObject, "xor", Atomics::Xor, FunctionLength::THREE);
SetFunction(env, atomicsObject, "compareExchange", Atomics::CompareExchange, FunctionLength::FOUR);
SetFunction(env, atomicsObject, "exchange", Atomics::Exchange, FunctionLength::THREE);
SetFunction(env, atomicsObject, "isLockFree", Atomics::IsLockFree, FunctionLength::ONE);
SetFunction(env, atomicsObject, "load", Atomics::Load, FunctionLength::TWO);
SetFunction(env, atomicsObject, "store", Atomics::Store, FunctionLength::THREE);
SetFunction(env, atomicsObject, "wait", Atomics::Wait, FunctionLength::FOUR);
SetFunction(env, atomicsObject, "notify", Atomics::Notify, FunctionLength::THREE);
JSHandle<JSTaggedValue> atomicsString(factory_->NewFromASCII("Atomics"));
JSHandle<JSObject> globalObject(thread_, env->GetGlobalObject());
PropertyDescriptor atomicsDesc(thread_, JSHandle<JSTaggedValue>::Cast(atomicsObject), true, false, true);
JSObject::DefineOwnProperty(thread_, globalObject, atomicsString, atomicsDesc);
// @@ToStringTag
SetStringTagSymbol(env, atomicsObject, "Atomics");
env->SetAtomicsFunction(thread_, atomicsObject);
}
void Builtins::InitializeWeakRef(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
[[maybe_unused]] EcmaHandleScope scope(thread_);

View File

@ -146,6 +146,8 @@ private:
void InitializeMath(const JSHandle<GlobalEnv> &env, const JSHandle<JSTaggedValue> &objFuncPrototypeVal) const;
void InitializeAtomics(const JSHandle<GlobalEnv> &env, const JSHandle<JSTaggedValue> &objFuncPrototypeVal) const;
void InitializeJson(const JSHandle<GlobalEnv> &env, const JSHandle<JSTaggedValue> &objFuncPrototypeVal) const;
void InitializeString(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &primRefObjDynclass) const;

View File

@ -386,6 +386,22 @@ bool BuiltinsArrayBuffer::IsBigIntElementType(DataViewType type)
return false;
}
// es12 25.1.2.6 IsUnclampedIntegerElementType ( type )
bool BuiltinsArrayBuffer::IsUnclampedIntegerElementType(DataViewType type)
{
switch (type) {
case DataViewType::INT8:
case DataViewType::INT16:
case DataViewType::INT32:
case DataViewType::UINT8:
case DataViewType::UINT16:
case DataViewType::UINT32:
return true;
default:
return false;
}
}
template<typename T>
void BuiltinsArrayBuffer::SetTypeData(uint8_t *block, T value, uint32_t index)
{

View File

@ -66,6 +66,8 @@ public:
// 24.1.1.1 AllocateArrayBuffer(constructor, byteLength)
static JSTaggedValue AllocateArrayBuffer(JSThread *thread, const JSHandle<JSTaggedValue> &newTarget,
double byteLength);
// es12 25.1.2.6 IsUnclampedIntegerElementType ( type )
static bool IsUnclampedIntegerElementType(DataViewType type);
// es12 25.1.2.7 IsBigIntElementType ( type )
static bool IsBigIntElementType(DataViewType type);

View File

@ -0,0 +1,587 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/builtins/builtins_atomics.h"
#include "ecmascript/base/atomic_helper.h"
#include "ecmascript/base/typed_array_helper-inl.h"
#include "utils/time.h"
namespace panda::ecmascript::builtins {
using NumberHelper = base::NumberHelper;
using AtomicHelper = base::AtomicHelper;
using BytesSize = base::BytesSize;
using BuiltinsArrayBuffer = builtins::BuiltinsArrayBuffer;
WaiterList *g_waitLists = Singleton<WaiterList>::GetInstance();
Mutex *g_mutex = Singleton<Mutex>::GetInstance();
// 25.4.2 Atomics.add ( typedArray, index, value )
JSTaggedValue BuiltinsAtomics::Sub(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Atomics, Sub);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> typedArray = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
return AtomicReadModifyWrite(thread, typedArray, index, argv, AtomicHelper::SubFun());
}
JSTaggedValue BuiltinsAtomics::Add(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Atomics, Add);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> typedArray = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
return AtomicReadModifyWrite(thread, typedArray, index, argv, AtomicHelper::AddFun());
}
JSTaggedValue BuiltinsAtomics::And(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Atomics, And);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> typedArray = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
return AtomicReadModifyWrite(thread, typedArray, index, argv, AtomicHelper::AndFun());
}
JSTaggedValue BuiltinsAtomics::Or(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Atomics, Or);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> typedArray = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
return AtomicReadModifyWrite(thread, typedArray, index, argv, AtomicHelper::OrFun());
}
JSTaggedValue BuiltinsAtomics::Xor(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Atomics, Xor);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> typedArray = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
return AtomicReadModifyWrite(thread, typedArray, index, argv, AtomicHelper::XorFun());
}
JSTaggedValue BuiltinsAtomics::CompareExchange(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Atomics, CompareExchange);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> typedArray = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
return AtomicReadModifyWrite(thread, typedArray, index, argv, AtomicHelper::CompareExchangeFun());
}
JSTaggedValue BuiltinsAtomics::Exchange(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Atomics, Exchange);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> typedArray = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
return AtomicReadModifyWrite(thread, typedArray, index, argv, AtomicHelper::ExchangeFun());
}
JSTaggedValue BuiltinsAtomics::Store(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Atomics, Store);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> typedArray = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
JSHandle<JSTaggedValue> value = GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
return AtomicHelper::AtomicStore(thread, typedArray, index, value);
}
JSTaggedValue BuiltinsAtomics::Load(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Atomics, Load);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> typedArray = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
return AtomicHelper::AtomicLoad(thread, typedArray, index);
}
JSTaggedValue BuiltinsAtomics::IsLockFree(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Atomics, IsLockFree);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> sizeTag = GetCallArg(argv, 0);
BytesSize size = BytesSize(JSTaggedValue::ToInt32(thread, sizeTag));
bool result;
switch (size) {
case BytesSize::ONEBYTES:
case BytesSize::TWOBYTES:
case BytesSize::FOURBYTES:
case BytesSize::EIGHTBYTES:
result = true;
break;
default:
result = false;
break;
}
return JSTaggedValue(result);
}
// 25.4.11 Atomics.wait ( typedArray, index, value, timeout )
JSTaggedValue BuiltinsAtomics::Wait(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Atomic, Wait);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> array = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
JSHandle<JSTaggedValue> value = GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
JSHandle<JSTaggedValue> timeout = GetCallArg(argv, BuiltinsBase::ArgsPosition::FOURTH);
// 1. Let buffer be ? ValidateIntegerTypedArray(typedArray, true).
JSHandle<JSTaggedValue> arrayBuffer(thread, AtomicHelper::ValidateIntegerTypedArray(thread, array, true));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 2. If IsSharedArrayBuffer(buffer) is false, throw a TypeError exception.
if (!arrayBuffer->IsSharedArrayBuffer()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "buffer is not sharedArrayBuffer.",
JSTaggedValue::Exception());
}
// 3. Let indexedPosition be ? ValidateAtomicAccess(typedArray, index).
int32_t indexedPosition = AtomicHelper::ValidateAtomicAccess(thread, array, index);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 4. If typedArray.[[TypedArrayName]] is "BigInt64Array", let v be ? ToBigInt64(value).
// 5. Otherwise, let v be ? ToInt32(value).
int64_t v = 0;
if (array->IsJSBigInt64Array()) {
v = JSHandle<BigInt>::Cast(value)->ToInt64();
} else {
v = static_cast<int64_t>(JSTaggedValue::ToInt32(thread, value));
}
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 6. Let q be ? ToNumber(timeout).
// 7. If q is NaN or +∞𝔽, let t be +∞; else if q is -∞𝔽, let t be 0; else let t be max((q), 0).
double t = 0;
if (timeout->IsUndefined()) {
t = base::POSITIVE_INFINITY;
} else {
JSTaggedNumber q = JSTaggedValue::ToNumber(thread, timeout);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
t = q.GetNumber();
if (NumberHelper::IsNaN(q) || (!NumberHelper::IsFinite(q) && t > 0)) {
t = base::POSITIVE_INFINITY;
} else if (t < 0) {
t = 0;
}
}
// 8. Let B be AgentCanSuspend().
// 9. If B is false, throw a TypeError exception.
if (!thread->GetEcmaVM()->GetAllowAtomicWait()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "vm does not allow wait to block.",
JSTaggedValue::Exception());
}
WaitResult res = WaitResult::OK;
if (array->IsJSBigInt64Array()) {
// AtomicHelper::Wait<int64_t>(thread, arrayBuffer, indexedPosition, v, t);
res = DoWait<int64_t>(thread, arrayBuffer, indexedPosition, v, t);
} else {
// AtomicHelper::Wait<int32_t>(thread, arrayBuffer, indexedPosition, static_cast<int32_t>(v), t);
res = DoWait<int32_t>(thread, arrayBuffer, indexedPosition, static_cast<int32_t>(v), t);
}
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
if (res == WaitResult::OK) {
return globalConst->GetOkString();
} else if (res == WaitResult::NOT_EQ) {
return globalConst->GetNotEqualString();
}
return globalConst->GetTimeoutString();
}
// 25.4.12 Atomics.notify ( typedArray, index, count )
JSTaggedValue BuiltinsAtomics::Notify(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Atomic, Notify);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> array = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
JSHandle<JSTaggedValue> count = GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
// 1. Let buffer be ? ValidateIntegerTypedArray(typedArray, true).
JSHandle<JSTaggedValue> arrayBuffer(thread, AtomicHelper::ValidateIntegerTypedArray(thread, array, true));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 2. Let indexedPosition be ? ValidateAtomicAccess(typedArray, index).
int32_t indexedPosition = AtomicHelper::ValidateAtomicAccess(thread, array, index);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 3. If count is undefined, let c be +∞.
// 4. Else,
// a. Let intCount be ? ToIntegerOrInfinity(count).
// b. Let c be max(intCount, 0).
double c = 0;
if (count->IsUndefined()) {
c = base::POSITIVE_INFINITY;
} else {
JSTaggedNumber countTemp = JSTaggedValue::ToNumber(thread, count);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
c = base::NumberHelper::TruncateDouble(countTemp.GetNumber());
c = c < 0 ? 0 : c;
}
// 6. If IsSharedArrayBuffer(buffer) is false, return +0𝔽.
if (!arrayBuffer->IsSharedArrayBuffer()) {
return JSTaggedValue(0);
}
return JSTaggedValue(Signal(arrayBuffer, indexedPosition, c));
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::AtomicReadModifyWrite(JSThread *thread, const JSHandle<JSTaggedValue> &typedArray,
JSHandle<JSTaggedValue> &index, EcmaRuntimeCallInfo *argv,
const callbackfun &op)
{
if (!typedArray->IsTypedArray()) {
THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
}
// 1. Let buffer be ? ValidateIntegerTypedArray(typedArray).
JSTaggedValue bufferValue = base::AtomicHelper::ValidateIntegerTypedArray(thread, typedArray);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> buffer(thread, bufferValue);
// 2. Let indexedPosition be ? ValidateAtomicAccess(typedArray, index).
int32_t indexedPosition = base::AtomicHelper::ValidateAtomicAccess(thread, typedArray, index);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 3. Let arrayTypeName be typedArray.[[TypedArrayName]].
JSHandle<JSTaggedValue> arrayTypeName(thread,
JSTypedArray::Cast(typedArray->GetTaggedObject())->GetTypedArrayName());
if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer.GetTaggedValue())) {
THROW_TYPE_ERROR_AND_RETURN(thread, "The ArrayBuffer of this value is detached buffer.",
JSTaggedValue::Exception());
}
// 7. NOTE: The above check is not redundant with the check in ValidateIntegerTypedArray because the call to
// ToBigInt or ToIntegerOrInfinity on the preceding lines can have arbitrary side effects, which could cause the
// buffer to become detached.
// 8. Let elementType be the Element Type value in Table 60 for arrayTypeName.
DataViewType elementType = JSTypedArray::GetTypeFromName(thread, arrayTypeName);
// 9. Return GetModifySetValueInBuffer(buffer, indexedPosition, elementType, v, op).
return AtomicReadModifyWriteCase(thread, buffer.GetTaggedValue(), elementType, indexedPosition, argv, op);
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::AtomicReadModifyWriteCase(JSThread *thread, JSTaggedValue arrBuf,
DataViewType type, int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op)
{
JSArrayBuffer *jsArrayBuffer = JSArrayBuffer::Cast(arrBuf.GetTaggedObject());
JSTaggedValue data = jsArrayBuffer->GetArrayBufferData();
void *pointer = JSNativePointer::Cast(data.GetTaggedObject())->GetExternalPointer();
auto *block = reinterpret_cast<uint8_t *>(pointer);
uint32_t size = argv->GetArgsNumber();
switch (type) {
case DataViewType::UINT8:
return HandleWithUint8(thread, size, block, indexedPosition, argv, op);
case DataViewType::INT8:
return HandleWithInt8(thread, size, block, indexedPosition, argv, op);
case DataViewType::UINT16:
return HandleWithUint16(thread, size, block, indexedPosition, argv, op);
case DataViewType::INT16:
return HandleWithInt16(thread, size, block, indexedPosition, argv, op);
case DataViewType::UINT32:
return HandleWithUint32(thread, size, block, indexedPosition, argv, op);
case DataViewType::INT32:
return HandleWithInt32(thread, size, block, indexedPosition, argv, op);
case DataViewType::BIGINT64:
return HandleWithBigInt64(thread, size, block, indexedPosition, argv, op);
case DataViewType::BIGUINT64:
return HandleWithBigUint64(thread, size, block, indexedPosition, argv, op);
default:
break;
}
UNREACHABLE();
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::HandleWithUint8(JSThread *thread, uint32_t size, uint8_t *block,
int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op)
{
JSHandle<JSTaggedValue> value = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
uint8_t tag = JSTaggedValue::ToUint8(thread, value);
if (size == 3) { // the number of parameters is 3
auto result = op((block + indexedPosition), &tag);
return BuiltinsBase::GetTaggedInt(result);
}
JSHandle<JSTaggedValue> newValue = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::FOURTH);
uint8_t newTag = JSTaggedValue::ToUint8(thread, newValue);
uint8_t arg[ARGS_NUMBER] = {0};
arg[0] = tag;
arg[1] = newTag;
auto result = op((block + indexedPosition), arg);
return JSTaggedValue(result);
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::HandleWithInt8(JSThread *thread, uint32_t size, uint8_t *block,
int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op)
{
JSHandle<JSTaggedValue> value = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
int8_t tag = JSTaggedValue::ToInt8(thread, value);
if (size == 3) { // the number of parameters is 3
auto result = op(reinterpret_cast<int8_t *>(block + indexedPosition), &tag);
return BuiltinsBase::GetTaggedInt(result);
}
JSHandle<JSTaggedValue> newValue = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::FOURTH);
int8_t newTag = JSTaggedValue::ToInt8(thread, newValue);
int8_t arg[ARGS_NUMBER] = {0};
arg[0] = tag;
arg[1] = newTag;
auto result = op(reinterpret_cast<int8_t *>(block + indexedPosition), arg);
return JSTaggedValue(result);
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::HandleWithUint16(JSThread *thread, uint32_t size, uint8_t *block,
int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op)
{
JSHandle<JSTaggedValue> value = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
uint16_t tag = JSTaggedValue::ToUint16(thread, value);
if (size == 3) { // the number of parameters is 3
auto result = op(reinterpret_cast<uint16_t *>(block + indexedPosition), &tag);
return BuiltinsBase::GetTaggedInt(result);
}
JSHandle<JSTaggedValue> newValue = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::FOURTH);
uint16_t newTag = JSTaggedValue::ToUint16(thread, newValue);
uint16_t arg[ARGS_NUMBER] = {0};
arg[0] = tag;
arg[1] = newTag;
auto result = op(reinterpret_cast<uint16_t *>(block + indexedPosition), arg);
return JSTaggedValue(result);
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::HandleWithInt16(JSThread *thread, uint32_t size, uint8_t *block,
int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op)
{
JSHandle<JSTaggedValue> value = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
int16_t tag = JSTaggedValue::ToInt16(thread, value);
if (size == 3) { // the number of parameters is 3
auto result = op(reinterpret_cast<int16_t *>(block + indexedPosition), &tag);
return BuiltinsBase::GetTaggedInt(result);
}
JSHandle<JSTaggedValue> newValue = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::FOURTH);
int16_t newTag = JSTaggedValue::ToInt16(thread, newValue);
int16_t arg[ARGS_NUMBER] = {0};
arg[0] = tag;
arg[1] = newTag;
auto result = op(reinterpret_cast<int16_t *>(block + indexedPosition), arg);
return JSTaggedValue(result);
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::HandleWithUint32(JSThread *thread, uint32_t size, uint8_t *block,
int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op)
{
JSHandle<JSTaggedValue> value = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
uint32_t tag = JSTaggedValue::ToUint32(thread, value);
if (size == 3) { // the number of parameters is 3
auto result = op(reinterpret_cast<uint32_t *>(block + indexedPosition), &tag);
return JSTaggedValue(result);
}
JSHandle<JSTaggedValue> newValue = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::FOURTH);
uint32_t newTag = JSTaggedValue::ToUint32(thread, newValue);
uint32_t arg[ARGS_NUMBER] = {0};
arg[0] = tag;
arg[1] = newTag;
auto result = op(reinterpret_cast<uint32_t *>(block + indexedPosition), arg);
return JSTaggedValue(result);
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::HandleWithInt32(JSThread *thread, uint32_t size, uint8_t *block,
int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op)
{
JSHandle<JSTaggedValue> value = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
int32_t tag = JSTaggedValue::ToInt32(thread, value);
if (size == 3) { // the number of parameters is 3
auto result = op(reinterpret_cast<int32_t *>(block + indexedPosition), &tag);
return BuiltinsBase::GetTaggedInt(result);
}
JSHandle<JSTaggedValue> newValue = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::FOURTH);
int32_t newTag = JSTaggedValue::ToInt32(thread, newValue);
int32_t arg[ARGS_NUMBER] = {0};
arg[0] = tag;
arg[1] = newTag;
auto result = op(reinterpret_cast<int32_t *>(block + indexedPosition), arg);
return JSTaggedValue(result);
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::HandleWithBigInt64(JSThread *thread, uint32_t size, uint8_t *block,
int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op)
{
JSHandle<JSTaggedValue> value = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
int64_t val = 0;
bool lossless = true;
BigInt::BigIntToInt64(thread, value, &val, &lossless);
if (size == 3) { // the number of parameters is 3
auto result = op(reinterpret_cast<int64_t *>(block + indexedPosition), &val);
return BigInt::Int64ToBigInt(thread, result).GetTaggedValue();
}
JSHandle<JSTaggedValue> newValue = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::FOURTH);
int64_t newVal = 0;
BigInt::BigIntToInt64(thread, newValue, &newVal, &lossless);
int64_t arg[ARGS_NUMBER] = {0};
arg[0] = val;
arg[1] = newVal;
auto result = op(reinterpret_cast<int64_t *>(block + indexedPosition), arg);
return BigInt::Int64ToBigInt(thread, result).GetTaggedValue();
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::HandleWithBigUint64(JSThread *thread, uint32_t size, uint8_t *block,
int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op)
{
JSHandle<JSTaggedValue> value = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
uint64_t val = 0;
bool lossless = true;
BigInt::BigIntToUint64(thread, value, &val, &lossless);
if (size == 3) { // the number of parameters is 3
auto result = op(reinterpret_cast<uint64_t *>(block + indexedPosition), &val);
return BigInt::Uint64ToBigInt(thread, result).GetTaggedValue();
}
JSHandle<JSTaggedValue> newValue = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::FOURTH);
uint64_t newVal = 0;
BigInt::BigIntToUint64(thread, newValue, &newVal, &lossless);
uint64_t arg[ARGS_NUMBER] = {0};
arg[0] = val;
arg[1] = newVal;
auto result = op(reinterpret_cast<uint64_t *>(block + indexedPosition), arg);
return BigInt::Uint64ToBigInt(thread, result).GetTaggedValue();
}
template <typename T>
WaitResult BuiltinsAtomics::DoWait(JSThread *thread, JSHandle<JSTaggedValue> &arrayBuffer,
size_t index, T execpt, double timeout)
{
MutexGuard lock_guard(g_mutex);
JSHandle<JSNativePointer> np(thread, JSHandle<JSArrayBuffer>::Cast(arrayBuffer)->GetArrayBufferData());
void *buffer = np->GetExternalPointer();
ASSERT(buffer != nullptr);
WaiterListNode *node = thread->GetEcmaVM()->GetWaiterListNode();
node->date_ = buffer;
node->index_ = index;
node->waitPointer_ = reinterpret_cast<int8_t*>(buffer) + index;
node->waiting_ = true;
std::atomic<T> *atomicValue = reinterpret_cast<std::atomic<T> *>(node->waitPointer_);
T value = atomicValue->load();
if (value != execpt) {
return WaitResult::NOT_EQ;
}
g_waitLists->AddNode(node);
uint64_t currentTime = 0;
uint64_t timeoutTime = 0;
bool hasTimeout = timeout != base::POSITIVE_INFINITY;
if (hasTimeout) {
currentTime = time::GetCurrentTimeInMillis();
timeoutTime = currentTime + static_cast<uint64_t>(timeout);
}
WaitResult res = WaitResult::OK;
while (true) {
if (!node->waiting_) {
res = WaitResult::OK;
break;
}
if (hasTimeout) {
currentTime = time::GetCurrentTimeInMillis();
if (currentTime >= timeoutTime) {
res = WaitResult::TIME_OUT;
break;
}
uint64_t untilTime = timeoutTime - currentTime;
ASSERT(untilTime != 0);
node->cond_.TimedWait(g_mutex, untilTime);
} else {
node->cond_.Wait(g_mutex);
}
}
g_waitLists->DeleteNode(node);
node->waiting_ = false;
return res;
}
uint32_t BuiltinsAtomics::Signal(JSHandle<JSTaggedValue> &arrayBuffer, const size_t &index, double wakeCount)
{
JSTaggedValue data = JSHandle<JSArrayBuffer>::Cast(arrayBuffer)->GetArrayBufferData();
void *buffer = JSNativePointer::Cast(data.GetTaggedObject())->GetExternalPointer();
ASSERT(buffer != nullptr);
MutexGuard lock_guard(g_mutex);
auto &locationListMap = g_waitLists->locationListMap_;
auto iter = locationListMap.find(reinterpret_cast<int8_t *>(buffer) + index);
if (iter == locationListMap.end()) {
return 0;
}
WaiterListNode *node = iter->second.pHead;
uint32_t wokenUpCount = 0;
while (node != nullptr && wakeCount > 0.0) {
if (!node->waiting_) {
node = node->next_;
continue;
}
if (buffer == node->date_) {
ASSERT(index == node->index_);
node->waiting_ = false;
WaiterListNode *oldNode = node;
node = node->next_;
oldNode->cond_.Signal();
if (wakeCount != base::POSITIVE_INFINITY) {
wakeCount--;
}
wokenUpCount++;
continue;
}
node = node->next_;
}
return wokenUpCount;
}
} // namespace panda::ecmascript::builtins

View File

@ -0,0 +1,94 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_BUILTINS_BUILTINS_ATOMICS_H
#define ECMASCRIPT_BUILTINS_BUILTINS_ATOMICS_H
#include "ecmascript/base/builtins_base.h"
#include "ecmascript/js_dataview.h"
#include "ecmascript/waiter_list.h"
namespace panda::ecmascript::builtins {
enum class WaitResult: uint8_t {OK = 0, NOT_EQ, TIME_OUT};
class BuiltinsAtomics : public base::BuiltinsBase {
public:
// 25.4.2 Atomics.add ( typedArray, index, value )
static JSTaggedValue Add(EcmaRuntimeCallInfo *argv);
// 25.4.3 Atomics.and ( typedArray, index, value )
static JSTaggedValue And(EcmaRuntimeCallInfo *argv);
// 25.4.4 Atomics.compareExchange ( typedArray, index, expectedValue, replacementValue)
static JSTaggedValue CompareExchange(EcmaRuntimeCallInfo *argv);
// 25.4.5 Atomics.exchange ( typedArray, index, value )
static JSTaggedValue Exchange(EcmaRuntimeCallInfo *argv);
// 25.4.6 Atomics.isLockFree ( size )
static JSTaggedValue IsLockFree(EcmaRuntimeCallInfo *argv);
// 25.4.7 Atomics.load ( typedArray, index )
static JSTaggedValue Load(EcmaRuntimeCallInfo *argv);
// 25.4.8 Atomics.or ( typedArray, index, value )
static JSTaggedValue Or(EcmaRuntimeCallInfo *argv);
// 25.4.9 Atomics.store ( typedArray, index, value )
static JSTaggedValue Store(EcmaRuntimeCallInfo *argv);
// 25.4.10 Atomics.sub ( typedArray, index, value )
static JSTaggedValue Sub(EcmaRuntimeCallInfo *argv);
// 25.4.11 Atomics.wait ( typedArray, index, value, timeout)
static JSTaggedValue Wait(EcmaRuntimeCallInfo *argv);
// 25.4.12 Atomics.notify ( typedArray, index, count)
static JSTaggedValue Notify(EcmaRuntimeCallInfo *argv);
// 25.4.13 Atomics.xor ( typedArray, index, value )
static JSTaggedValue Xor(EcmaRuntimeCallInfo *argv);
private:
static uint32_t Signal(JSHandle<JSTaggedValue> &arrayBuffer, const size_t &index, double wakeCount);
template <typename T>
static WaitResult DoWait(JSThread *thread, JSHandle<JSTaggedValue> &arrayBuffer,
size_t index, T execpt, double timeout);
template<typename callbackfun>
static JSTaggedValue AtomicReadModifyWrite(JSThread *thread, const JSHandle<JSTaggedValue> &typedArray,
JSHandle<JSTaggedValue> &index, EcmaRuntimeCallInfo *argv,
const callbackfun &op);
template<typename callbackfun>
static JSTaggedValue AtomicReadModifyWriteCase(JSThread *thread, JSTaggedValue buffer, DataViewType type,
int32_t indexedPosition, EcmaRuntimeCallInfo *argv,
const callbackfun &op);
template<typename callbackfun>
static JSTaggedValue HandleWithUint8(JSThread *thread, uint32_t size, uint8_t *block, int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op);
template<typename callbackfun>
static JSTaggedValue HandleWithInt8(JSThread *thread, uint32_t size, uint8_t *block, int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op);
template<typename callbackfun>
static JSTaggedValue HandleWithUint16(JSThread *thread, uint32_t size, uint8_t *block, int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op);
template<typename callbackfun>
static JSTaggedValue HandleWithInt16(JSThread *thread, uint32_t size, uint8_t *block, int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op);
template<typename callbackfun>
static JSTaggedValue HandleWithUint32(JSThread *thread, uint32_t size, uint8_t *block, int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op);
template<typename callbackfun>
static JSTaggedValue HandleWithInt32(JSThread *thread, uint32_t size, uint8_t *block, int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op);
template<typename callbackfun>
static JSTaggedValue HandleWithBigInt64(JSThread *thread, uint32_t size, uint8_t *block, int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op);
template<typename callbackfun>
static JSTaggedValue HandleWithBigUint64(JSThread *thread, uint32_t size, uint8_t *block, int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op);
static constexpr int ARGS_NUMBER = 2;
};
} // namespace panda::ecmascript::builtins
#endif // ECMASCRIPT_BUILTINS_BUILTINS_MATH_H

View File

@ -1535,16 +1535,23 @@ JSTaggedValue BuiltinsString::Trim(EcmaRuntimeCallInfo *argv)
JSHandle<EcmaString> thisHandle = JSTaggedValue::ToString(thread, thisTag);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
uint32_t thisLen = thisHandle->GetLength();
std::u16string u16strThis;
if (thisHandle->IsUtf16()) {
u16strThis = base::StringHelper::Utf16ToU16String(thisHandle->GetDataUtf16(), thisLen);
} else {
const uint8_t *uint8This = thisHandle->GetDataUtf8();
u16strThis = base::StringHelper::Utf8ToU16String(uint8This, thisLen);
if (UNLIKELY(thisLen == 0)) {
return thread->GlobalConstants()->GetEmptyString();
}
EcmaString *str = base::StringHelper::Trim(thread, u16strThis);
return JSTaggedValue(str);
if (thisHandle->IsUtf8()) {
Span<const uint8_t> data(reinterpret_cast<const uint8_t *>(thisHandle->GetData()), thisLen);
uint32_t start = base::StringHelper::GetStart(data, thisLen);
uint32_t end = base::StringHelper::GetEnd(data, start, thisLen);
EcmaString *res = EcmaString::FastSubUtf8String(thread->GetEcmaVM(), thisHandle, start, end + 1 - start);
return JSTaggedValue(res);
}
Span<const uint16_t> data(thisHandle->GetData(), thisLen);
uint32_t start = base::StringHelper::GetStart(data, thisLen);
uint32_t end = base::StringHelper::GetEnd(data, start, thisLen);
EcmaString *res = EcmaString::FastSubUtf16String(thread->GetEcmaVM(), thisHandle, start, end + 1 - start);
return JSTaggedValue(res);
}
// 21.1.3.26

View File

@ -992,7 +992,7 @@ JSTaggedValue BuiltinsTypedArray::Set(EcmaRuntimeCallInfo *argv)
uint32_t targetLength = targetObj->GetArrayLength();
JSHandle<JSTaggedValue> targetName(thread, targetObj->GetTypedArrayName());
uint32_t targetElementSize = TypedArrayHelper::GetSizeFromName(thread, targetName);
DataViewType targetType = TypedArrayHelper::GetTypeFromName(thread, targetName);
DataViewType targetType = JSTypedArray::GetTypeFromName(thread, targetName);
uint32_t targetByteOffset = targetObj->GetByteOffset();
JSHandle<JSTaggedValue> argArray = GetCallArg(argv, 0);
@ -1084,7 +1084,7 @@ JSTaggedValue BuiltinsTypedArray::Set(EcmaRuntimeCallInfo *argv)
// 21. Let srcLength be the value of typedArrays [[ArrayLength]] internal slot.
// 22. Let srcByteOffset be the value of typedArrays [[ByteOffset]] internal slot.
JSHandle<JSTaggedValue> srcName(thread, typedArray->GetTypedArrayName());
DataViewType srcType = TypedArrayHelper::GetTypeFromName(thread, srcName);
DataViewType srcType = JSTypedArray::GetTypeFromName(thread, srcName);
uint32_t srcElementSize = TypedArrayHelper::GetSizeFromName(thread, srcName);
uint32_t srcLength = typedArray->GetArrayLength();
uint32_t srcByteOffset = typedArray->GetByteOffset();
@ -1214,11 +1214,11 @@ JSTaggedValue BuiltinsTypedArray::Slice(EcmaRuntimeCallInfo *argv)
// 17. Let srcName be the String value of Os [[TypedArrayName]] internal slot.
// 18. Let srcType be the String value of the Element Type value in Table 49 for srcName.
JSHandle<JSTaggedValue> srcName(thread, thisObj->GetTypedArrayName());
DataViewType srcType = TypedArrayHelper::GetTypeFromName(thread, srcName);
DataViewType srcType = JSTypedArray::GetTypeFromName(thread, srcName);
// 19. Let targetName be the String value of As [[TypedArrayName]] internal slot.
// 20. Let targetType be the String value of the Element Type value in Table 49 for targetName.
JSHandle<JSTaggedValue> targetName(thread, JSTypedArray::Cast(*newArrObj)->GetTypedArrayName());
DataViewType targetType = TypedArrayHelper::GetTypeFromName(thread, targetName);
DataViewType targetType = JSTypedArray::GetTypeFromName(thread, targetName);
// 21. If SameValue(srcType, targetType) is false, then
// a. Let n be 0.
// b. Repeat, while k < final

View File

@ -52,6 +52,7 @@ host_unittest_action("BuiltinsNaturalTest") {
# test file
"builtins_array_test.cpp",
"builtins_arraybuffer_test.cpp",
"builtins_atomics_test.cpp",
"builtins_boolean_test.cpp",
"builtins_dataview_test.cpp",
"builtins_date_test.cpp",

View File

@ -0,0 +1,626 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/builtins/builtins_array.h"
#include "ecmascript/builtins/builtins_atomics.h"
#include "ecmascript/builtins/builtins_typedarray.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_array.h"
#include "ecmascript/js_handle.h"
#include "ecmascript/js_thread.h"
#include "ecmascript/js_typed_array.h"
#include "ecmascript/tests/test_helper.h"
using namespace panda::ecmascript;
using namespace panda::ecmascript::builtins;
namespace panda::test {
using TypedArray = ecmascript::builtins::BuiltinsTypedArray;
class BuiltinsAtomicsTest : public testing::Test {
public:
static void SetUpTestCase()
{
GTEST_LOG_(INFO) << "SetUpTestCase";
}
static void TearDownTestCase()
{
GTEST_LOG_(INFO) << "TearDownCase";
}
void SetUp() override
{
TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
}
void TearDown() override
{
TestHelper::DestroyEcmaVMWithScope(instance, scope);
}
EcmaVM *instance {nullptr};
EcmaHandleScope *scope {nullptr};
JSThread *thread {nullptr};
};
JSTypedArray *CreateTypedArray(JSThread *thread, const JSHandle<TaggedArray> &array)
{
auto ecmaVM = thread->GetEcmaVM();
JSHandle<GlobalEnv> env = ecmaVM->GetGlobalEnv();
JSHandle<JSTaggedValue> jsarray(JSArray::CreateArrayFromList(thread, array));
JSHandle<JSFunction> int8_array(env->GetInt8ArrayFunction());
JSHandle<JSObject> globalObject(thread, env->GetGlobalObject());
// 6 : test case
auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*int8_array), 6);
ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue(*int8_array));
ecmaRuntimeCallInfo1->SetThis(JSTaggedValue(*globalObject));
ecmaRuntimeCallInfo1->SetCallArg(0, jsarray.GetTaggedValue());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1.get());
JSTaggedValue result = TypedArray::Int8ArrayConstructor(ecmaRuntimeCallInfo1.get());
EXPECT_TRUE(result.IsECMAObject());
JSTypedArray *int8arr = JSTypedArray::Cast(reinterpret_cast<TaggedObject *>(result.GetRawData()));
return int8arr;
}
HWTEST_F_L0(BuiltinsAtomicsTest, Add_1)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(7));
array->Set(thread, 1, JSTaggedValue(8));
array->Set(thread, 2, JSTaggedValue(9));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(5)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Add(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 7);
}
HWTEST_F_L0(BuiltinsAtomicsTest, Add_2)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(10));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Add(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 0);
}
HWTEST_F_L0(BuiltinsAtomicsTest, Add_3)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Add(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 0);
auto ecmaRuntimeCallInfos = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
ecmaRuntimeCallInfos->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfos->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfos.get());
JSTaggedValue results = BuiltinsAtomics::Load(ecmaRuntimeCallInfos.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(results.GetInt(), 2);
}
HWTEST_F_L0(BuiltinsAtomicsTest, And_1)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(10));
array->Set(thread, 0, JSTaggedValue(7));
array->Set(thread, 1, JSTaggedValue(0));
array->Set(thread, 2, JSTaggedValue(0));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Add(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 7);
}
HWTEST_F_L0(BuiltinsAtomicsTest, And_2)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(10));
array->Set(thread, 0, JSTaggedValue(7));
array->Set(thread, 1, JSTaggedValue(0));
array->Set(thread, 2, JSTaggedValue(0));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::And(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 7);
auto ecmaRuntimeCallInfos = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
ecmaRuntimeCallInfos->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfos->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfos.get());
result = BuiltinsAtomics::Load(ecmaRuntimeCallInfos.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 2);
}
HWTEST_F_L0(BuiltinsAtomicsTest, CompareExchange_1)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(5));
array->Set(thread, 1, JSTaggedValue(0));
array->Set(thread, 2, JSTaggedValue(0));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 12);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(5)));
ecmaRuntimeCallInfo->SetCallArg(3, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::CompareExchange(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 5);
}
HWTEST_F_L0(BuiltinsAtomicsTest, CompareExchange_2)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(5));
array->Set(thread, 1, JSTaggedValue(0));
array->Set(thread, 2, JSTaggedValue(0));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 12);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(5)));
ecmaRuntimeCallInfo->SetCallArg(3, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::CompareExchange(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 5);
auto ecmaRuntimeCallInfos = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
ecmaRuntimeCallInfos->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfos->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfos.get());
result = BuiltinsAtomics::Load(ecmaRuntimeCallInfos.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 2);
}
HWTEST_F_L0(BuiltinsAtomicsTest, Exchange_1)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(3));
array->Set(thread, 1, JSTaggedValue(0));
array->Set(thread, 2, JSTaggedValue(0));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(6)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Exchange(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 3);
}
HWTEST_F_L0(BuiltinsAtomicsTest, Exchange_2)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(3));
array->Set(thread, 1, JSTaggedValue(0));
array->Set(thread, 2, JSTaggedValue(0));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(6)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Exchange(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 3);
auto ecmaRuntimeCallInfos = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
ecmaRuntimeCallInfos->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfos->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfos.get());
result = BuiltinsAtomics::Load(ecmaRuntimeCallInfos.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 6);
}
HWTEST_F_L0(BuiltinsAtomicsTest, Or_1)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(5));
array->Set(thread, 1, JSTaggedValue(0));
array->Set(thread, 2, JSTaggedValue(0));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Or(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 5);
}
HWTEST_F_L0(BuiltinsAtomicsTest, Or_2)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(5));
array->Set(thread, 1, JSTaggedValue(0));
array->Set(thread, 2, JSTaggedValue(0));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 12);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Or(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 5);
auto ecmaRuntimeCallInfos = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
ecmaRuntimeCallInfos->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfos->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfos.get());
result = BuiltinsAtomics::Load(ecmaRuntimeCallInfos.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 7);
}
HWTEST_F_L0(BuiltinsAtomicsTest, Sub_1)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(5));
array->Set(thread, 1, JSTaggedValue(0));
array->Set(thread, 2, JSTaggedValue(0));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Sub(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 5);
}
HWTEST_F_L0(BuiltinsAtomicsTest, Sub_2)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(0));
array->Set(thread, 1, JSTaggedValue(5));
array->Set(thread, 2, JSTaggedValue(0));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(1)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Sub(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 5);
auto ecmaRuntimeCallInfos = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
ecmaRuntimeCallInfos->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfos->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(1)));
prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfos.get());
result = BuiltinsAtomics::Load(ecmaRuntimeCallInfos.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 3);
}
HWTEST_F_L0(BuiltinsAtomicsTest, Xor_1)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(5));
array->Set(thread, 1, JSTaggedValue(7));
array->Set(thread, 2, JSTaggedValue(0));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(1)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Xor(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 7);
}
HWTEST_F_L0(BuiltinsAtomicsTest, Xor_2)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(5));
array->Set(thread, 1, JSTaggedValue(7));
array->Set(thread, 2, JSTaggedValue(0));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(1)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Xor(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 7);
auto ecmaRuntimeCallInfos = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
ecmaRuntimeCallInfos->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfos->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(1)));
prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfos.get());
result = BuiltinsAtomics::Load(ecmaRuntimeCallInfos.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 5);
}
HWTEST_F_L0(BuiltinsAtomicsTest, IsLockFree_1)
{
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int32_t>(1)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::IsLockFree(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_TRUE(result.ToBoolean());
}
HWTEST_F_L0(BuiltinsAtomicsTest, IsLockFree_2)
{
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::IsLockFree(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_TRUE(result.ToBoolean());
}
HWTEST_F_L0(BuiltinsAtomicsTest, IsLockFree_3)
{
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int32_t>(4)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::IsLockFree(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_TRUE(result.ToBoolean());
}
HWTEST_F_L0(BuiltinsAtomicsTest, IsLockFree_4)
{
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int32_t>(-3)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::IsLockFree(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_FALSE(result.ToBoolean());
}
HWTEST_F_L0(BuiltinsAtomicsTest, IsLockFree_5)
{
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int32_t>(8)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::IsLockFree(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_TRUE(result.ToBoolean());
}
HWTEST_F_L0(BuiltinsAtomicsTest, Store_1)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(5));
array->Set(thread, 1, JSTaggedValue(6));
array->Set(thread, 2, JSTaggedValue(7));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Store(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetDouble(), 2);
}
HWTEST_F_L0(BuiltinsAtomicsTest, Store_2)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(5));
array->Set(thread, 1, JSTaggedValue(6));
array->Set(thread, 2, JSTaggedValue(7));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Store(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetDouble(), 2);
auto ecmaRuntimeCallInfos = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
ecmaRuntimeCallInfos->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfos->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfos.get());
result = BuiltinsAtomics::Load(ecmaRuntimeCallInfos.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 2);
}
}

View File

@ -17,6 +17,7 @@
#include "ecmascript/js_finalization_registry.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/global_env.h"
#include "ecmascript/jobs/micro_job_queue.h"
#include "ecmascript/js_array.h"
#include "ecmascript/js_array_iterator.h"
@ -32,12 +33,10 @@
#include "ecmascript/tests/test_helper.h"
#include "utils/bit_utils.h"
#include "ecmascript/jobs/micro_job_queue.h"
using namespace panda::ecmascript;
using namespace panda::ecmascript::builtins;
using BuiltinsBase = panda::ecmascript::base::BuiltinsBase;
static JSTaggedValue testArgv = JSTaggedValue(0);
static int testValue = 0;
namespace panda::test {
class BuiltinsFinalizationRegistryTest : public testing::Test {
@ -70,7 +69,7 @@ public:
public:
static JSTaggedValue cleanupCallback()
{
testArgv = JSTaggedValue(10); // number of 10
++testValue;
return JSTaggedValue::Undefined();
}
};
@ -116,6 +115,7 @@ HWTEST_F_L0(BuiltinsFinalizationRegistryTest, FinalizationRegistryConstructor)
// finalizationRegistry.Register(target, heldValue [ , unregisterToken ])
HWTEST_F_L0(BuiltinsFinalizationRegistryTest, Register1)
{
testValue = 0;
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSTaggedValue> objectFunc = env->GetObjectFunction();
@ -136,12 +136,13 @@ HWTEST_F_L0(BuiltinsFinalizationRegistryTest, Register1)
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
BuiltinsFinalizationRegistry::Register(ecmaRuntimeCallInfo.get());
ASSERT_EQ(testArgv, JSTaggedValue(0));
ASSERT_EQ(testValue, 0);
}
// finalizationRegistry.Register(target, heldValue [ , unregisterToken ])
HWTEST_F_L0(BuiltinsFinalizationRegistryTest, Register2)
{
testValue = 0;
EcmaVM *vm = thread->GetEcmaVM();
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
@ -149,31 +150,143 @@ HWTEST_F_L0(BuiltinsFinalizationRegistryTest, Register2)
JSTaggedValue result = CreateFinalizationRegistryConstructor(thread);
JSHandle<JSFinalizationRegistry> jsfinalizationRegistry(thread, result);
JSTaggedValue target =
factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objectFunc), objectFunc).GetTaggedValue();
vm->SetEnableForceGC(false);
JSTaggedValue target = JSTaggedValue::Undefined();
{
[[maybe_unused]] EcmaHandleScope handleScope(thread);
auto obj =
factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objectFunc), objectFunc);
target = obj.GetTaggedValue();
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(jsfinalizationRegistry.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(0, target);
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(10));
ecmaRuntimeCallInfo->SetCallArg(2, target);
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(jsfinalizationRegistry.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(0, target);
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(10));
ecmaRuntimeCallInfo->SetCallArg(2, target);
target = JSTaggedValue::Undefined();
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
BuiltinsFinalizationRegistry::Register(ecmaRuntimeCallInfo.get());
[[maybe_unused]] JSTaggedValue target22 =
factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objectFunc), objectFunc).GetTaggedValue();
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
BuiltinsFinalizationRegistry::Register(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
}
vm->CollectGarbage(TriggerGCType::FULL_GC);
if (!thread->HasPendingException()) {
job::MicroJobQueue::ExecutePendingJob(thread, vm->GetMicroJobQueue());
}
ASSERT_EQ(testArgv, JSTaggedValue(0));
vm->SetEnableForceGC(true);
ASSERT_EQ(testValue, 1);
}
// finalizationRegistry.Register(target, heldValue [ , unregisterToken ])
HWTEST_F_L0(BuiltinsFinalizationRegistryTest, Register3)
{
testValue = 0;
EcmaVM *vm = thread->GetEcmaVM();
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSTaggedValue> objectFunc = env->GetObjectFunction();
JSTaggedValue result = CreateFinalizationRegistryConstructor(thread);
JSHandle<JSFinalizationRegistry> jsfinalizationRegistry(thread, result);
vm->SetEnableForceGC(false);
JSTaggedValue target = JSTaggedValue::Undefined();
JSTaggedValue target1 = JSTaggedValue::Undefined();
{
[[maybe_unused]] EcmaHandleScope handleScope(thread);
auto obj =
factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objectFunc), objectFunc);
auto obj1 =
factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objectFunc), objectFunc);
target = obj.GetTaggedValue();
target1 = obj1.GetTaggedValue();
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(jsfinalizationRegistry.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(0, target);
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(10));
ecmaRuntimeCallInfo->SetCallArg(2, target);
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
BuiltinsFinalizationRegistry::Register(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo1->SetThis(jsfinalizationRegistry.GetTaggedValue());
ecmaRuntimeCallInfo1->SetCallArg(0, target1);
ecmaRuntimeCallInfo1->SetCallArg(1, JSTaggedValue(10));
ecmaRuntimeCallInfo1->SetCallArg(2, target1);
[[maybe_unused]] auto prev1 = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1.get());
BuiltinsFinalizationRegistry::Register(ecmaRuntimeCallInfo1.get());
TestHelper::TearDownFrame(thread, prev1);
}
vm->CollectGarbage(TriggerGCType::FULL_GC);
if (!thread->HasPendingException()) {
job::MicroJobQueue::ExecutePendingJob(thread, vm->GetMicroJobQueue());
}
vm->SetEnableForceGC(true);
ASSERT_EQ(testValue, 2);
}
// finalizationRegistry.Register(target, heldValue [ , unregisterToken ])
HWTEST_F_L0(BuiltinsFinalizationRegistryTest, Register4)
{
testValue = 0;
EcmaVM *vm = thread->GetEcmaVM();
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSTaggedValue> objectFunc = env->GetObjectFunction();
JSTaggedValue result = CreateFinalizationRegistryConstructor(thread);
JSHandle<JSFinalizationRegistry> jsfinalizationRegistry(thread, result);
JSTaggedValue result1 = CreateFinalizationRegistryConstructor(thread);
JSHandle<JSFinalizationRegistry> jsfinalizationRegistry1(thread, result1);
vm->SetEnableForceGC(false);
JSTaggedValue target = JSTaggedValue::Undefined();
JSTaggedValue target1 = JSTaggedValue::Undefined();
{
[[maybe_unused]] EcmaHandleScope handleScope(thread);
auto obj =
factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objectFunc), objectFunc);
auto obj1 =
factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objectFunc), objectFunc);
target = obj.GetTaggedValue();
target1 = obj1.GetTaggedValue();
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(jsfinalizationRegistry.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(0, target);
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(10));
ecmaRuntimeCallInfo->SetCallArg(2, target);
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
BuiltinsFinalizationRegistry::Register(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo1->SetThis(jsfinalizationRegistry1.GetTaggedValue());
ecmaRuntimeCallInfo1->SetCallArg(0, target1);
ecmaRuntimeCallInfo1->SetCallArg(1, JSTaggedValue(10));
ecmaRuntimeCallInfo1->SetCallArg(2, target1);
[[maybe_unused]] auto prev1 = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1.get());
BuiltinsFinalizationRegistry::Register(ecmaRuntimeCallInfo1.get());
TestHelper::TearDownFrame(thread, prev1);
}
vm->CollectGarbage(TriggerGCType::FULL_GC);
if (!thread->HasPendingException()) {
job::MicroJobQueue::ExecutePendingJob(thread, vm->GetMicroJobQueue());
}
vm->SetEnableForceGC(true);
ASSERT_EQ(testValue, 2);
}
// finalizationRegistry.Unregister(unregisterToken ])
HWTEST_F_L0(BuiltinsFinalizationRegistryTest, Unregister)
HWTEST_F_L0(BuiltinsFinalizationRegistryTest, Unregister1)
{
testValue = 0;
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSTaggedValue> objectFunc = env->GetObjectFunction();
@ -201,7 +314,50 @@ HWTEST_F_L0(BuiltinsFinalizationRegistryTest, Unregister)
ecmaRuntimeCallInfo1->SetCallArg(0, target.GetTaggedValue());
[[maybe_unused]] auto prev1 = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1.get());
BuiltinsFinalizationRegistry::Register(ecmaRuntimeCallInfo1.get());
ASSERT_EQ(testArgv, JSTaggedValue(0));
BuiltinsFinalizationRegistry::Unregister(ecmaRuntimeCallInfo1.get());
ASSERT_EQ(testValue, 0);
}
HWTEST_F_L0(BuiltinsFinalizationRegistryTest, Unregister2)
{
testValue = 0;
EcmaVM *vm = thread->GetEcmaVM();
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSTaggedValue> objectFunc = env->GetObjectFunction();
JSTaggedValue result = CreateFinalizationRegistryConstructor(thread);
JSHandle<JSFinalizationRegistry> jsfinalizationRegistry(thread, result);
vm->SetEnableForceGC(false);
JSTaggedValue target = JSTaggedValue::Undefined();
{
[[maybe_unused]] EcmaHandleScope handleScope(thread);
auto obj =
factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objectFunc), objectFunc);
target = obj.GetTaggedValue();
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(jsfinalizationRegistry.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(0, target);
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(10));
ecmaRuntimeCallInfo->SetCallArg(2, target);
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
BuiltinsFinalizationRegistry::Register(ecmaRuntimeCallInfo.get());
auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo1->SetThis(jsfinalizationRegistry.GetTaggedValue());
ecmaRuntimeCallInfo1->SetCallArg(0, target);
BuiltinsFinalizationRegistry::Unregister(ecmaRuntimeCallInfo1.get());
TestHelper::TearDownFrame(thread, prev);
}
vm->CollectGarbage(TriggerGCType::FULL_GC);
if (!thread->HasPendingException()) {
job::MicroJobQueue::ExecutePendingJob(thread, vm->GetMicroJobQueue());
}
vm->SetEnableForceGC(true);
ASSERT_EQ(testValue, 0);
}
} // namespace panda::test

View File

@ -15,6 +15,7 @@
#include "ecmascript/base/builtins_base.h"
#include "ecmascript/builtins/builtins_weak_ref.h"
#include "ecmascript/jobs/micro_job_queue.h"
#include "ecmascript/js_weak_ref.h"
#include "ecmascript/tests/test_helper.h"
#include "ecmascript/ecma_runtime_call_info.h"
@ -65,15 +66,29 @@ public:
JSThread *thread {nullptr};
};
JSTaggedValue CreateWeakRefConstructor(JSThread *thread, JSTaggedValue target)
{
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSObject> globalObject(thread, env->GetGlobalObject());
JSHandle<JSFunction> weakRef(env->GetBuiltinsWeakRefFunction());
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*weakRef), 6);
ecmaRuntimeCallInfo->SetFunction(weakRef.GetTaggedValue());
ecmaRuntimeCallInfo->SetThis(globalObject.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(0, target);
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
return JSTaggedValue(BuiltinsWeakRef::WeakRefConstructor(ecmaRuntimeCallInfo.get()));
}
// new WeakRef(target)
HWTEST_F_L0(BuiltinsWeakRefTest, WeakRefConstructor)
{
JSHandle<GlobalEnv> globalEnv = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSTaggedValue> objectFunc(globalEnv->GetObjectFunction());
JSHandle<JSTaggedValue> objectFunc(env->GetObjectFunction());
JSHandle<JSObject> target(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objectFunc), objectFunc));
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSFunction> weakRef(env->GetBuiltinsWeakRefFunction());
JSHandle<JSObject> globalObject(thread, env->GetGlobalObject());
@ -96,31 +111,16 @@ HWTEST_F_L0(BuiltinsWeakRefTest, Deref1)
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSTaggedValue> objectFunc(env->GetObjectFunction());
JSHandle<JSFunction> weakRef(env->GetBuiltinsWeakRefFunction());
JSHandle<JSObject> globalObject(thread, env->GetGlobalObject());
JSHandle<JSObject> target(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objectFunc), objectFunc));
JSHandle<JSTaggedValue> formatStyle = thread->GlobalConstants()->GetHandledStyleString();
JSHandle<JSTaggedValue> styleKey(factory->NewFromASCII("currency"));
JSHandle<JSTaggedValue> styleValue(factory->NewFromASCII("EUR"));
JSObject::SetProperty(thread, target, formatStyle, styleKey);
JSObject::SetProperty(thread, target, styleKey, styleValue);
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, weakRef.GetTaggedValue(), 6);
ecmaRuntimeCallInfo->SetFunction(weakRef.GetTaggedValue());
ecmaRuntimeCallInfo->SetThis(globalObject.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(0, target.GetTaggedValue());
JSTaggedValue result = CreateWeakRefConstructor(thread, target.GetTaggedValue());
JSHandle<JSWeakRef> jsWeakRef(thread, JSWeakRef::Cast(reinterpret_cast<TaggedObject *>(result.GetRawData())));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(jsWeakRef.GetTaggedValue());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsWeakRef::WeakRefConstructor(ecmaRuntimeCallInfo.get());
JSHandle<JSWeakRef> jsWeakRef(thread, JSWeakRef::Cast(reinterpret_cast<TaggedObject *>(result.GetRawData())));
auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo1->SetThis(jsWeakRef.GetTaggedValue());
ecmaRuntimeCallInfo1->SetCallArg(0, target.GetTaggedValue());
[[maybe_unused]] auto prev1 = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1.get());
JSTaggedValue result1 = BuiltinsWeakRef::Deref(ecmaRuntimeCallInfo1.get());
EXPECT_TRUE(!result1.IsUndefined());
TestHelper::TearDownFrame(thread, prev);
JSTaggedValue result1 = BuiltinsWeakRef::Deref(ecmaRuntimeCallInfo.get());
ASSERT_EQ(result1, target.GetTaggedValue());
}
@ -130,33 +130,60 @@ HWTEST_F_L0(BuiltinsWeakRefTest, Deref2)
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSTaggedValue> objectFunc(env->GetObjectFunction());
JSHandle<JSFunction> weakRef(env->GetBuiltinsWeakRefFunction());
JSHandle<JSObject> globalObject(thread, env->GetGlobalObject());
JSHandle<JSObject> target(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objectFunc), objectFunc));
JSHandle<JSTaggedValue> formatStyle = thread->GlobalConstants()->GetHandledStyleString();
JSHandle<JSTaggedValue> styleKey(factory->NewFromASCII("currency"));
JSHandle<JSTaggedValue> styleValue(factory->NewFromASCII("EUR"));
JSHandle<JSObject> target(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objectFunc), objectFunc));
JSObject::SetProperty(thread, target, formatStyle, styleKey);
JSObject::SetProperty(thread, target, styleKey, styleValue);
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, weakRef.GetTaggedValue(), 6);
ecmaRuntimeCallInfo->SetFunction(weakRef.GetTaggedValue());
ecmaRuntimeCallInfo->SetThis(globalObject.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(0, target.GetTaggedValue());
JSTaggedValue result = CreateWeakRefConstructor(thread, target.GetTaggedValue());
JSHandle<JSWeakRef> jsWeakRef(thread, JSWeakRef::Cast(reinterpret_cast<TaggedObject *>(result.GetRawData())));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(jsWeakRef.GetTaggedValue());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsWeakRef::WeakRefConstructor(ecmaRuntimeCallInfo.get());
JSHandle<JSWeakRef> jsWeakRef(thread, JSWeakRef::Cast(reinterpret_cast<TaggedObject *>(result.GetRawData())));
auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo1->SetThis(jsWeakRef.GetTaggedValue());
ecmaRuntimeCallInfo1->SetCallArg(0, target.GetTaggedValue());
[[maybe_unused]] auto prev1 = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1.get());
JSTaggedValue result1 = BuiltinsWeakRef::Deref(ecmaRuntimeCallInfo1.get());
TestHelper::TearDownFrame(thread, prev);
JSTaggedValue result1 = BuiltinsWeakRef::Deref(ecmaRuntimeCallInfo.get());
ASSERT_EQ(result1, target.GetTaggedValue());
JSObject::SetProperty(thread, target, styleKey, styleValue);
ASSERT_EQ(result1, target.GetTaggedValue());
}
// weakRef.Deref()
HWTEST_F_L0(BuiltinsWeakRefTest, Deref3)
{
EcmaVM *vm = thread->GetEcmaVM();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSTaggedValue> objectFunc(env->GetObjectFunction());
JSTaggedValue target =
factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objectFunc), objectFunc).GetTaggedValue();
JSTaggedValue result = CreateWeakRefConstructor(thread, target);
JSHandle<JSWeakRef> jsWeakRef(thread, JSWeakRef::Cast(reinterpret_cast<TaggedObject *>(result.GetRawData())));
JSTaggedValue result2 = JSTaggedValue::Undefined();
{
[[maybe_unused]] EcmaHandleScope handleScope(thread);
auto obj =
factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objectFunc), objectFunc);
target = obj.GetTaggedValue();
auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo1->SetThis(jsWeakRef.GetTaggedValue());
[[maybe_unused]] auto prev1 = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1.get());
result2 = BuiltinsWeakRef::Deref(ecmaRuntimeCallInfo1.get());
TestHelper::TearDownFrame(thread, prev1);
}
vm->CollectGarbage(TriggerGCType::FULL_GC);
if (!thread->HasPendingException()) {
job::MicroJobQueue::ExecutePendingJob(thread, vm->GetMicroJobQueue());
}
vm->SetEnableForceGC(true);
ASSERT_TRUE(!result2.IsUndefined());
}
} // namespace panda::test

View File

@ -28,8 +28,8 @@ if (defined(ark_independent_build)) {
config("include_llvm") {
if (compile_llvm_online) {
include_dirs = [
"//third_party/llvm-project/build/include",
"//third_party/llvm-project/llvm/include/",
"//third_party/third_party_llvm-project/build/include",
"//third_party/third_party_llvm-project/llvm/include/",
]
} else {
include_dirs = [
@ -78,7 +78,7 @@ source_set("libark_jsoptimizer_set") {
]
if (compile_llvm_online) {
lib_dirs = [ "//third_party/llvm-project/build/lib" ]
lib_dirs = [ "//third_party/third_party_llvm-project/build/lib" ]
} else {
lib_dirs =
[ "//prebuilts/ark_tools/ark_js_prebuilts/llvm_prebuilts/build/lib" ]
@ -137,12 +137,13 @@ source_set("libark_jsoptimizer_set") {
"LLVMAArch64Desc",
"LLVMAArch64Disassembler",
"LLVMAArch64AsmParser",
"LLVMX86Utils",
"LLVMX86AsmParser",
"LLVMX86CodeGen",
"LLVMX86Desc",
"LLVMX86Disassembler",
"LLVMX86Info",
"LLVMFrontendOpenMP",
"LLVMBitWriter",
]
deps = [

View File

@ -335,6 +335,30 @@ void AssemblerAarch64::Str(const Register &rt, const MemoryOperand &operand)
UNREACHABLE();
}
void AssemblerAarch64::Ldur(const Register &rt, const MemoryOperand &operand)
{
bool regX = !rt.IsW();
uint32_t op = LDUR_Offset;
ASSERT(operand.IsImmediateOffset());
uint64_t imm = static_cast<uint64_t>(operand.GetImmediate().Value());
// 30: 30bit indicate the size of LDUR Reg
uint32_t instructionCode = (regX << 30) | op | LoadAndStoreImm(imm, true)
| Rn(operand.GetRegBase().GetId()) | Rt(rt.GetId());
EmitU32(instructionCode);
}
void AssemblerAarch64::Stur(const Register &rt, const MemoryOperand &operand)
{
bool regX = !rt.IsW();
uint32_t op = STUR_Offset;
ASSERT(operand.IsImmediateOffset());
uint64_t imm = static_cast<uint64_t>(operand.GetImmediate().Value());
// 30: 30bit indicate the size of LDUR Reg
uint32_t instructionCode = (regX << 30) | op | LoadAndStoreImm(imm, true)
| Rn(operand.GetRegBase().GetId()) | Rt(rt.GetId());
EmitU32(instructionCode);
}
void AssemblerAarch64::Mov(const Register &rd, const Immediate &imm)
{
ASSERT_PRINT(!rd.IsSp(), "sp can't load immediate, please use add instruction");
@ -710,12 +734,12 @@ void AssemblerAarch64::Lsr(const Register &rd, const Register &rn, unsigned shif
{
unsigned imms = 0;
if (rd.IsW()) {
// 31 : 32-bit variant Applies when sf == 0 && N == 0 && imms == 011111
// 31 : 31 32-bit variant Applies when sf == 0 && N == 0 && imms == 011111
// LSR <Wd>, <Wn>, #<shift> is equivalent to UBFM <Wd>, <Wn>, #<shift>, #31
// and is always the preferred disassembly
imms = 31;
} else {
// 63 : 64-bit variant Applies when sf == 1 && N == 1 && imms == 111111
// 63 : 63 64-bit variant Applies when sf == 1 && N == 1 && imms == 111111
// LSR <Xd>, <Xn>, #<shift> is equivalent to UBFM <Xd>, <Xn>, #<shift>, #63
// and is always the preferred disassembly
imms = 63;

View File

@ -291,6 +291,8 @@ public:
void Ldrh(const Register &rt, const MemoryOperand &operand);
void Ldrb(const Register &rt, const MemoryOperand &operand);
void Str(const Register &rt, const MemoryOperand &operand);
void Ldur(const Register &rt, const MemoryOperand &operand);
void Stur(const Register &rt, const MemoryOperand &operand);
void Mov(const Register &rd, const Immediate &imm);
void Mov(const Register &rd, const Register &rm);
void Movz(const Register &rd, uint64_t imm, int shift);

View File

@ -22,6 +22,7 @@ enum RegisterId : uint8_t {
X16, X17, X18, X19, X20, X21, X22, X23,
X24, X25, X26, X27, X28, X29, X30, SP,
Zero = SP,
FP = X29,
INVALID_REG = 0xFF,
};
@ -183,6 +184,8 @@ enum LoadStoreOpCode {
LDR_Register = 0xb8600800,
LDRB_Register = 0x38600800,
LDRH_Register = 0x78600800,
LDUR_Offset = 0xb8400000,
STUR_Offset = 0xb8000000,
};
enum AddrMode {

View File

@ -16,6 +16,11 @@
#include "ecmascript/frames.h"
namespace panda::ecmascript::aarch64 {
Register ExtendedAssembler::ghcJSCallDispacherArgs_[JS_CALL_DISPATCHER_ARGS_COUNT] =
{ X19, FP, X20, X21, X22, X23, X24, X25 };
Register ExtendedAssembler::cppJSCallDispacherArgs_[JS_CALL_DISPATCHER_ARGS_COUNT] =
{ X0, FP, X1, X2, X3, X4, X5, INVALID_REG};
void ExtendedAssembler::CalleeSave()
{
Register sp(SP);
@ -55,6 +60,15 @@ void ExtendedAssembler::BindAssemblerStub(int id)
{
Label *target = module_->GetFunctionLabel(id);
Bind(target);
auto callSigns = module_->GetCSigns();
auto cs = callSigns[id];
isGhcCallingConv_ = cs->GetCallConv() == CallSignature::CallConv::GHCCallConv;
}
void ExtendedAssembler::PushFpAndLr()
{
Register sp(SP);
Stp(Register(X29), Register(X30), MemoryOperand(sp, -16, PREINDEX));
}
void ExtendedAssembler::SaveFpAndLr()

View File

@ -17,6 +17,7 @@
#include "assembler_aarch64.h"
#include "ecmascript/compiler/assembler_module.h"
#include "ecmascript/compiler/bc_call_signature.h"
namespace panda::ecmascript::aarch64 {
using namespace panda::ecmascript::kungfu;
@ -31,13 +32,95 @@ public:
void CalleeSave();
void CalleeRestore();
void CallAssemblerStub(int id, bool isTail = false);
void PushFpAndLr();
void SaveFpAndLr();
void RestoreFpAndLr();
void PushArgsWithArgv(Register argc, Register argv, Register op, panda::ecmascript::Label *next);
void PushArgc(int32_t argc, Register op);
void PushArgc(Register argc, Register op);
Register TempRegister1()
{
if (temp1InUse_) {
COMPILER_LOG(ERROR) << "temp register1 inuse.";
UNREACHABLE();
}
temp1InUse_ = true;
return X7;
}
Register TempRegister2()
{
if (temp2InUse_) {
COMPILER_LOG(ERROR) << "temp register2 inuse.";
UNREACHABLE();
}
temp2InUse_ = true;
return X16;
}
Register AvailableRegister1() const
{
// X17 is neither callee saved reegister nor argument register
return X17;
}
Register AvailableRegister2() const
{
// X18 is neither callee saved reegister nor argument register
return X18;
}
Register CallDispatcherArgument(kungfu::CallDispatchInputs index)
{
size_t i = static_cast<size_t>(index);
return isGhcCallingConv_ ? ghcJSCallDispacherArgs_[i] : cppJSCallDispacherArgs_[i];
}
Register GlueRegister()
{
return isGhcCallingConv_ ? X19 : X0;
}
bool FromInterpreterHandler() const
{
return isGhcCallingConv_;
}
private:
AssemblerModule *module_ {nullptr};
bool isGhcCallingConv_ {false};
bool temp1InUse_ {false};
bool temp2InUse_ {false};
friend class TempRegister1Scope;
friend class TempRegister2Scope;
static constexpr size_t JS_CALL_DISPATCHER_ARGS_COUNT =
static_cast<size_t>(kungfu::CallDispatchInputs::NUM_OF_INPUTS);
static Register ghcJSCallDispacherArgs_[JS_CALL_DISPATCHER_ARGS_COUNT];
static Register cppJSCallDispacherArgs_[JS_CALL_DISPATCHER_ARGS_COUNT];
};
class TempRegister1Scope {
public:
explicit TempRegister1Scope(ExtendedAssembler *assembler) : assembler_(assembler) {}
~TempRegister1Scope()
{
assembler_->temp1InUse_ = false;
}
NO_COPY_SEMANTIC(TempRegister1Scope);
NO_MOVE_SEMANTIC(TempRegister1Scope);
private:
ExtendedAssembler *assembler_;
};
class TempRegister2Scope {
public:
explicit TempRegister2Scope(ExtendedAssembler *assembler) : assembler_(assembler) {}
~TempRegister2Scope()
{
assembler_->temp2InUse_ = false;
}
NO_COPY_SEMANTIC(TempRegister2Scope);
NO_MOVE_SEMANTIC(TempRegister2Scope);
private:
ExtendedAssembler *assembler_;
};
} // panda::ecmascript::aarch64
#endif // ECMASCRIPT_COMPILER_AARCH64_EXTEND_ASSEMBLER_H

View File

@ -185,7 +185,9 @@ HWTEST_F_L0(AssemblerAarch64Test, LdrStr)
"00000014:38408fe1 \tldrb\tw1, [sp, #8]!\n"
"00000018:394023e1 \tldrb\tw1, [sp, #8]\n"
"0000001c:78408fe1 \tldrh\tw1, [sp, #8]!\n"
"00000020:794013e1 \tldrh\tw1, [sp, #8]\n");
"00000020:794013e1 \tldrh\tw1, [sp, #8]\n"
"00000024:f85f83e1 \tldur\tx1, [sp, #-8]\n"
"00000028:f81f83e3 \tstur\tx3, [sp, #-8]\n");
AssemblerAarch64 masm(chunk_);
__ Str(Register(X1), MemoryOperand(Register(SP), 8, POSTINDEX));
@ -197,6 +199,8 @@ HWTEST_F_L0(AssemblerAarch64Test, LdrStr)
__ Ldrb(Register(X1).W(), MemoryOperand(Register(SP), 8, OFFSET));
__ Ldrh(Register(X1).W(), MemoryOperand(Register(SP), 8, PREINDEX));
__ Ldrh(Register(X1).W(), MemoryOperand(Register(SP), 8, OFFSET));
__ Ldur(Register(X1), MemoryOperand(Register(SP), -8, OFFSET));
__ Stur(Register(X3), MemoryOperand(Register(SP), -8, OFFSET));
std::ostringstream oss;
DisassembleChunk("aarch64-unknown-linux-gnu", &masm, oss);
ASSERT_EQ(oss.str(), expectResult);

View File

@ -262,7 +262,10 @@ enum class CallDispatchInputs : size_t {
ARG0,
ARG1,
ARG2,
NUM_OF_INPUTS
NUM_OF_INPUTS,
ARGC = ARG0,
ARGV = ARG1,
};
#define BYTECODE_STUB_END_ID BytecodeStubCSigns::ID_ExceptionHandler

View File

@ -149,10 +149,9 @@ std::map<std::pair<uint8_t *, uint8_t *>, std::vector<uint8_t *>> BytecodeCircui
std::map<uint8_t *, uint8_t*> &byteCodeCurPrePc, std::vector<CfgInfo> &bytecodeBlockInfos)
{
// try contains many catch
const panda_file::File *file = file_->GetPandaFile();
std::map<std::pair<uint8_t *, uint8_t *>, std::vector<uint8_t *>> byteCodeException;
panda_file::MethodDataAccessor mda(*file, method_->GetMethodId());
panda_file::CodeDataAccessor cda(*file, mda.GetCodeId().value());
panda_file::MethodDataAccessor mda(*pf_, method_->GetMethodId());
panda_file::CodeDataAccessor cda(*pf_, mda.GetCodeId().value());
cda.EnumerateTryBlocks([this, &byteCodeCurPrePc, &bytecodeBlockInfos, &byteCodeException](
panda_file::CodeDataAccessor::TryBlock &try_block) {
auto tryStartOffset = try_block.GetStartPc();
@ -2324,10 +2323,13 @@ GateRef BytecodeCircuitBuilder::NewPhi(BytecodeRegion &bb, uint16_t reg, bool ac
GateType BytecodeCircuitBuilder::GetRealGateType(const uint16_t reg, const GateType gateType)
{
const panda_file::File *pf = file_->GetPandaFile();
auto curType = static_cast<GateType>(tsLoader_->GetGTFromPandaFile(*pf, reg, method_).GetData());
auto type = (curType == GateType::JS_ANY) ? gateType : curType;
return type;
if (file_->HasTSTypes()) {
auto curType = static_cast<GateType>(tsLoader_->GetGTFromPandaFile(*pf_, reg, method_).GetData());
auto type = (curType == GateType::JS_ANY) ? gateType : curType;
return type;
}
return GateType::JS_ANY;
}
// recursive variables renaming algorithm

View File

@ -351,7 +351,7 @@ class BytecodeCircuitBuilder {
public:
explicit BytecodeCircuitBuilder(const BytecodeTranslationInfo &translationInfo, size_t index,
TSLoader *tsLoader, bool enableLog)
: tsLoader_(tsLoader), file_(translationInfo.jsPandaFile),
: tsLoader_(tsLoader), file_(translationInfo.jsPandaFile), pf_(translationInfo.jsPandaFile->GetPandaFile()),
method_(translationInfo.methodPcInfos[index].method),
pcArray_(translationInfo.methodPcInfos[index].pcArray),
constantPool_(translationInfo.constantPool),
@ -469,6 +469,7 @@ private:
std::vector<GateRef> actualArgs_ {};
TSLoader *tsLoader_ {nullptr};
const JSPandaFile *file_ {nullptr};
const panda_file::File *pf_ {nullptr};
const JSMethod *method_ {nullptr};
const std::vector<uint8_t *> pcArray_;
JSHandle<JSTaggedValue> constantPool_;

View File

@ -28,14 +28,12 @@ echo ${BASE_HOME}
if [ ! -d "${BASE_HOME}/third_party/llvm-project" ]; then
cd ${BASE_HOME}/third_party
dd if=/dev/zero of=/tmp/mem.swap bs=1M count=4096
git clone https://gitee.com/surpassgoodchao/llvm-project.git
git clone git@gitee.com:openharmony-sig/third_party_llvm-project.git -b llvmorg-12.0.1-ark
git checkout 12.0.1-ark-1.0
fi
cd ${BASE_HOME}/third_party/llvm-project
if [ ! -d "build" ];then
git checkout -b local llvmorg-10.0.1
cp ../../ark/js_runtime/ecmascript/compiler/llvm/llvm_new.patch .
git apply --reject llvm_new.patch
mkdir build && cd build
cmake -GNinja -DCMAKE_BUILD_TYPE=Release -DBUILD_ARK_GC_SUPPORT=ON -DLLVM_ENABLE_TERMINFO=OFF DLLVM_STATIC_LINK_CXX_STDLIB=OFF -DLLVM_ENABLE_ZLIB=OFF ../llvm
ninja

View File

@ -23,14 +23,22 @@ void StubFileGenerator::CollectAsmStubCodeInfo(std::map<uintptr_t, std::string>
{
uintptr_t codeBegin = asmModule_.GetCodeBufferOffset();
auto asmCallSigns = asmModule_.GetCSigns();
uint32_t funSize = 0;
for (size_t i = 0; i < asmModule_.GetFunctionCount(); i++) {
auto cs = asmCallSigns[i];
auto entryOffset = asmModule_.GetFunction(cs->GetID());
stubInfo_.AddStubEntry(cs->GetTargetKind(), cs->GetID(), entryOffset + codeBegin, 0);
if (i < asmModule_.GetFunctionCount() - 1) {
auto nextcs = asmCallSigns[i + 1];
funSize = asmModule_.GetFunction(nextcs->GetID()) - entryOffset;
} else {
funSize = asmModule_.GetBufferSize() - entryOffset;
}
stubInfo_.AddStubEntry(cs->GetTargetKind(), cs->GetID(), entryOffset + codeBegin, 0, 0, funSize);
ASSERT(!cs->GetName().empty());
auto codeBuffer = modulePackage_[0].GetCodeBuffer();
uintptr_t entry = codeBuffer + entryOffset + codeBegin;
addr2name[entry] = cs->GetName();
DisassembleEachFunc(addr2name);
}
}
@ -38,7 +46,7 @@ void StubFileGenerator::CollectCodeInfo()
{
std::map<uintptr_t, std::string> addr2name;
for (size_t i = 0; i < modulePackage_.size(); i++) {
modulePackage_[i].CollectFuncEntryInfo(addr2name, stubInfo_, i);
modulePackage_[i].CollectFuncEntryInfo(addr2name, stubInfo_, i, GetLog());
if (i == 0) {
CollectAsmStubCodeInfo(addr2name);
}
@ -52,7 +60,7 @@ void AOTFileGenerator::CollectCodeInfo()
{
std::map<uintptr_t, std::string> addr2name;
for (size_t i = 0; i < modulePackage_.size(); i++) {
modulePackage_[i].CollectFuncEntryInfo(addr2name, aotInfo_, i);
modulePackage_[i].CollectFuncEntryInfo(addr2name, aotInfo_, i, GetLog());
auto des = modulePackage_[i].GetModuleSectionDes();
aotInfo_.AddModuleDes(des, aotfileHashs_[i]);
}

View File

@ -15,6 +15,7 @@
#ifndef ECMASCRIPT_COMPILER_FILE_GENERATORS_H
#define ECMASCRIPT_COMPILER_FILE_GENERATORS_H
#include <tuple>
#include "ecmascript/compiler/assembler_module.h"
#include "ecmascript/compiler/compiler_log.h"
#include "ecmascript/compiler/llvm_codegen.h"
@ -32,35 +33,71 @@ public:
}
void CollectFuncEntryInfo(std::map<uintptr_t, std::string> &addr2name, StubModulePackInfo &stubInfo,
uint32_t moduleIndex)
uint32_t moduleIndex, const CompilerLog &log)
{
auto codeBuff = assembler_->GetCodeBuffer();
auto engine = assembler_->GetEngine();
auto callSigns = llvmModule_->GetCSigns();
std::map<uintptr_t, int> addr2FpToPrevFrameSpDelta;
std::vector<uint64_t> funSizeVec;
std::vector<uintptr_t> entrys;
for (size_t j = 0; j < llvmModule_->GetFuncCount(); j++) {
auto cs = callSigns[j];
LLVMValueRef func = llvmModule_->GetFunction(j);
ASSERT(func != nullptr);
uintptr_t entry = reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(engine, func));
stubInfo.AddStubEntry(cs->GetTargetKind(), cs->GetID(), entry - codeBuff, moduleIndex);
ASSERT(!cs->GetName().empty());
addr2name[entry] = cs->GetName();
entrys.push_back(entry);
}
const size_t funcCount = llvmModule_->GetFuncCount();
for (size_t j = 0; j < funcCount; j++) {
auto cs = callSigns[j];
LLVMValueRef func = llvmModule_->GetFunction(j);
ASSERT(func != nullptr);
int delta = assembler_->GetFpDeltaPrevFramSp(func, log);
ASSERT(delta >= 0 && (delta % sizeof(uintptr_t) == 0));
uint32_t funcSize = 0;
if (j < funcCount - 1) {
funcSize = entrys[j + 1] - entrys[j];
} else {
funcSize = codeBuff + assembler_->GetCodeSize() - entrys[j];
}
stubInfo.AddStubEntry(cs->GetTargetKind(), cs->GetID(), entrys[j] - codeBuff, moduleIndex, delta, funcSize);
ASSERT(!cs->GetName().empty());
addr2name[entrys[j]] = cs->GetName();
}
// GetCodeSize
}
void CollectFuncEntryInfo(std::map<uintptr_t, std::string> &addr2name, AOTModulePackInfo &aotInfo,
uint32_t moduleIndex)
uint32_t moduleIndex, const CompilerLog &log)
{
auto codeBuff = assembler_->GetCodeBuffer();
auto engine = assembler_->GetEngine();
std::vector<std::tuple<uint64_t, size_t, int>> funcInfo; // entry、idx、delta
llvmModule_->IteratefuncIndexMap([&](size_t idx, LLVMValueRef func) {
uint64_t funcEntry = reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(engine, func));
uint64_t length = 0;
std::string funcName(LLVMGetValueName2(func, &length));
assert(length != 0);
COMPILER_LOG(INFO) << "CollectCodeInfo for AOT func: " << funcName.c_str();
aotInfo.AddStubEntry(CallSignature::TargetKind::JSFUNCTION, idx, funcEntry - codeBuff, moduleIndex);
addr2name[funcEntry] = funcName;
int delta = assembler_->GetFpDeltaPrevFramSp(func, log);
ASSERT(delta >= 0 && (delta % sizeof(uintptr_t) == 0));
funcInfo.emplace_back(std::tuple(funcEntry, idx, delta));
});
const size_t funcCount = funcInfo.size();
for (size_t i = 0; i < funcInfo.size(); i++) {
uint64_t funcEntry;
size_t idx;
int delta;
uint32_t funcSize;
std::tie(funcEntry, idx, delta) = funcInfo[i];
if (i < funcCount - 1) {
funcSize = std::get<0>(funcInfo[i + 1]) - funcEntry;
} else {
funcSize = codeBuff + assembler_->GetCodeSize() - funcEntry;
}
aotInfo.AddStubEntry(CallSignature::TargetKind::JSFUNCTION, idx,
funcEntry - codeBuff, moduleIndex, delta, funcSize);
}
}
ModuleSectionDes GetModuleSectionDes()
@ -126,9 +163,9 @@ public:
explicit FileGenerator(const CompilerLog *log) : log_(log) {};
virtual ~FileGenerator() = default;
const CompilerLog *GetLog() const
const CompilerLog GetLog() const
{
return log_;
return *log_;
}
protected:
std::vector<Module> modulePackage_ {};

View File

@ -405,11 +405,7 @@ GateRef InterpreterStub::PushRange(GateRef glue, GateRef sp, GateRef array, Gate
GateRef InterpreterStub::GetCurrentFrame(GateRef glue)
{
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
return GetLastLeaveFrame(glue);
#else
return GetCurrentSpFrame(glue);
#endif
}
GateRef InterpreterStub::ReadInst32_0(GateRef pc)

View File

@ -352,179 +352,6 @@ DECLARE_ASM_HANDLER(HandleNewObjDynRangePrefImm16V8)
GateRef firstArgOffset = Int16(2);
GateRef ctor = GetVregValue(sp, ZExtInt16ToPtr(firstArgRegIdx));
GateRef newTarget = GetVregValue(sp, PtrAdd(ZExtInt16ToPtr(firstArgRegIdx), IntPtr(1)));
#if !ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
Label ctorIsHeapObject(env);
Label ctorIsJSFunction(env);
Label fastPath(env);
Label slowPath(env);
Branch(TaggedIsHeapObject(ctor), &ctorIsHeapObject, &slowPath);
Bind(&ctorIsHeapObject);
Branch(IsJSFunction(ctor), &ctorIsJSFunction, &slowPath);
Bind(&ctorIsJSFunction);
Branch(IsConstructor(ctor), &fastPath, &slowPath);
Bind(&fastPath);
{
GateRef methodOffset = IntPtr(JSFunction::METHOD_OFFSET);
GateRef ctorMethod = Load(VariableType::NATIVE_POINTER(), ctor, methodOffset);
Label ctorIsBuiltinsConstructor(env);
Label ctorNotBuiltinsConstructor(env);
Branch(IsBuiltinsConstructor(ctor), &ctorIsBuiltinsConstructor, &ctorNotBuiltinsConstructor);
Bind(&ctorIsBuiltinsConstructor);
{
// Changed to push newSp like call for further asm.
DEFVARIABLE(newSp, VariableType::NATIVE_POINTER(),
PointerSub(sp, IntPtr(AsmInterpretedFrame::GetSize(env->IsArch32Bit()))));
DEFVARIABLE(i, VariableType::INT32(), ZExtInt16ToInt32(numArgs));
i = Int32Sub(*i, Int32(1));
GateRef startIndex = Int32Add(ZExtInt16ToInt32(firstArgRegIdx), ZExtInt16ToInt32(firstArgOffset));
GateRef endIndex = Int32Add(ZExtInt16ToInt32(firstArgRegIdx), *i);
newSp = PushRange(glue, *newSp, sp, startIndex, endIndex);
// push this
newSp = PushArg(glue, *newSp, Int64(JSTaggedValue::VALUE_UNDEFINED));
// push newTarget
newSp = PushArg(glue, *newSp, newTarget);
// push func
newSp = PushArg(glue, *newSp, ctor);
// ASSERT(ctorMethod->GetNumVregsWithCallField() == 0)
Label stackOverflow(env);
Label stackNotOverflow(env);
Branch(CheckStackOverflow(glue, *newSp), &stackOverflow, &stackNotOverflow);
Bind(&stackOverflow);
{
CallRuntime(glue, RTSTUB_ID(ThrowStackOverflowException), {});
DISPATCH_LAST();
}
Bind(&stackNotOverflow);
SetFrameState(glue, *newSp, ctor, Hole(VariableType::JS_ANY()), Hole(VariableType::JS_ANY()),
IntPtr(0), sp, Int64(static_cast<uint64_t>(FrameType::ASM_INTERPRETER_FRAME)));
SetCurrentSpFrame(glue, *newSp);
GateRef numArgsWithThis = Int16Add(numArgs,
Int16(1 - static_cast<int16_t>(NUM_MANDATORY_JSFUNC_ARGS))); // 1: this
GateRef retValue = CallRuntime(glue, RTSTUB_ID(CallNative),
{Int16BuildTaggedTypeWithNoGC(numArgsWithThis)});
SetCurrentSpFrame(glue, sp);
Label hasPendingException(env);
Label noPendingException(env);
Branch(TaggedIsException(retValue), &hasPendingException, &noPendingException);
Bind(&hasPendingException);
{
DISPATCH_LAST();
}
Bind(&noPendingException);
varAcc = retValue;
DISPATCH_WITH_ACC(PREF_IMM16_V8);
}
Bind(&ctorNotBuiltinsConstructor);
// IsFastNewFrameEnter is not considered in asm.
GateRef callFieldOffset = IntPtr(JSMethod::GetCallFieldOffset(env->IsArch32Bit()));
GateRef callField = Load(VariableType::INT64(), ctorMethod, callFieldOffset);
GateRef isNativeMask = Int64(static_cast<uint64_t>(1) << JSMethod::IsNativeBit::START_BIT);
Label ctorMethodNotNative(env);
Branch(Int64NotEqual(Int64And(callField, isNativeMask), Int64(0)), &slowPath, &ctorMethodNotNative);
Bind(&ctorMethodNotNative);
{
SetPcToFrame(glue, GetFrame(sp), pc);
SetCallSizeToFrame(glue, GetFrame(sp),
IntPtr(BytecodeInstruction::Size(BytecodeInstruction::Format::PREF_IMM16_V8)));
DEFVARIABLE(thisObj, VariableType::JS_ANY(), Undefined());
Label ctorIsBase(env);
Label ctorNotBase(env); // ASSERT(ctorFunc->IsDerivedConstructor())
Branch(IsBase(ctor), &ctorIsBase, &ctorNotBase);
Bind(&ctorIsBase);
{
thisObj = CallRuntime(glue, RTSTUB_ID(NewThisObject), {ctor, newTarget});
// INTERPRETER_RETURN_IF_ABRUPT(thisObj)
Label thisObjIsException(env);
Branch(TaggedIsException(*thisObj), &thisObjIsException, &ctorNotBase);
Bind(&thisObjIsException);
{
DISPATCH_LAST();
}
}
Bind(&ctorNotBase);
// Changed to push newSp like call for further asm.
DEFVARIABLE(newSp, VariableType::NATIVE_POINTER(),
PointerSub(sp, IntPtr(AsmInterpretedFrame::GetSize(env->IsArch32Bit()))));
DEFVARIABLE(i, VariableType::INT32(), Int32(0));
GateRef numArgsOffset = Int64(JSMethod::NumArgsBits::START_BIT);
GateRef numArgsMask = Int64((static_cast<uint64_t>(1) << JSMethod::NumArgsBits::SIZE) - 1);
GateRef declaredNumArgs = ChangeInt64ToInt32(Int64And(Int64LSR(callField, numArgsOffset), numArgsMask));
GateRef actualNumArgs = ZExtInt16ToInt32(Int16Sub(numArgs, firstArgOffset)); // exclude func and newTarget
// Ignore haveExtra to hide this object in the 2nd last index
newSp = PushArg(glue, *newSp, IntBuildTaggedTypeWithNoGC(actualNumArgs));
newSp = PushArg(glue, *newSp, *thisObj);
GateRef undefinedNumArgs = Int32Sub(declaredNumArgs, actualNumArgs);
newSp = PushUndefined(glue, *newSp, undefinedNumArgs);
i = actualNumArgs;
i = Int32Add(*i, Int32(1)); // +2 for func and newTarget, -1 to get last index
GateRef startIndex = Int32Add(ZExtInt16ToInt32(firstArgRegIdx), ZExtInt16ToInt32(firstArgOffset));
GateRef endIndex = Int32Add(ZExtInt16ToInt32(firstArgRegIdx), *i);
newSp = PushRange(glue, *newSp, sp, startIndex, endIndex);
GateRef haveThisMask = Int64(static_cast<uint64_t>(1) << JSMethod::HaveThisBit::START_BIT);
Label ctorMethodHaveThis(env);
Label ctorMethodNoThis(env);
Branch(Int64NotEqual(Int64And(callField, haveThisMask), Int64(0)),
&ctorMethodHaveThis, &ctorMethodNoThis);
Bind(&ctorMethodHaveThis);
{
newSp = PushArg(glue, *newSp, *thisObj);
Jump(&ctorMethodNoThis);
}
Bind(&ctorMethodNoThis);
GateRef haveNewTargetMask = Int64(static_cast<uint64_t>(1) << JSMethod::HaveNewTargetBit::START_BIT);
Label ctorMethodHaveNewTarget(env);
Label ctorMethodNoNewTarget(env);
Branch(Int64NotEqual(Int64And(callField, haveNewTargetMask), Int64(0)),
&ctorMethodHaveNewTarget, &ctorMethodNoNewTarget);
Bind(&ctorMethodHaveNewTarget);
{
newSp = PushArg(glue, *newSp, newTarget);
Jump(&ctorMethodNoNewTarget);
}
Bind(&ctorMethodNoNewTarget);
GateRef haveFuncMask = Int64(static_cast<uint64_t>(1) << JSMethod::HaveFuncBit::START_BIT);
Label ctorMethodHaveFunc(env);
Label ctorMethodNoFunc(env);
Branch(Int64NotEqual(Int64And(callField, haveFuncMask), Int64(0)),
&ctorMethodHaveFunc, &ctorMethodNoFunc);
Bind(&ctorMethodHaveFunc);
{
newSp = PushArg(glue, *newSp, ctor);
Jump(&ctorMethodNoFunc);
}
Bind(&ctorMethodNoFunc);
// push vregs
GateRef numVregsOffset = Int64(JSMethod::NumVregsBits::START_BIT);
GateRef numVregsMask = Int64((static_cast<uint64_t>(1) << JSMethod::NumVregsBits::SIZE) - 1);
GateRef numVregs = ChangeInt64ToInt32(Int64And(Int64LSR(callField, numVregsOffset), numVregsMask));
newSp = PushUndefined(glue, *newSp, numVregs);
Label stackOverflow(env);
Label stackNotOverflow(env);
Branch(CheckStackOverflow(glue, *newSp), &stackOverflow, &stackNotOverflow);
Bind(&stackOverflow);
{
CallRuntime(glue, RTSTUB_ID(ThrowStackOverflowException), {});
DISPATCH_LAST();
}
Bind(&stackNotOverflow);
GateRef newEnv = GetEnvFromFunction(ctor);
GateRef bytecodeArrayOffset = IntPtr(JSMethod::GetBytecodeArrayOffset(env->IsArch32Bit()));
GateRef bytecodeArray = Load(VariableType::NATIVE_POINTER(), ctorMethod, bytecodeArrayOffset);
SetFrameState(glue, *newSp, ctor, Hole(VariableType::JS_ANY()), newEnv, bytecodeArray, sp,
Int64(static_cast<uint64_t>(FrameType::INTERPRETER_CONSTRUCTOR_FRAME)));
SetCurrentSpFrame(glue, *newSp);
GateRef newConstpool = GetConstpoolFromFunction(ctor);
GateRef newProfileTypeInfo = GetProfileTypeInfoFromFunction(ctor);
GateRef newHotnessCounter = Load(VariableType::INT32(), ctorMethod,
IntPtr(JSMethod::GetHotnessCounterOffset(env->IsArch32Bit())));
Dispatch(glue, *newSp, bytecodeArray, newConstpool, newProfileTypeInfo,
Hole(VariableType::JS_ANY()), newHotnessCounter, IntPtr(0));
}
}
Bind(&slowPath);
#endif
GateRef firstArgIdx = Int16Add(firstArgRegIdx, firstArgOffset);
GateRef length = Int16Sub(numArgs, firstArgOffset);
GateRef res = CallRuntime(glue, RTSTUB_ID(NewObjDynRange),
@ -4371,47 +4198,6 @@ DECLARE_ASM_HANDLER(HandleReturnDyn)
}
Bind(&pcNotEqualNullptr);
{
#if !ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
SetCurrentSpFrame(glue, *varSp);
GateRef frameTypeOffset = IntPtr(AsmInterpretedFrame::GetBaseOffset(env->IsArch32Bit()) +
InterpretedFrameBase::GetTypeOffset(env->IsArch32Bit()));
GateRef currentFrameType = Load(VariableType::INT64(), frame, frameTypeOffset);
Label isFastNewFrameExit(env);
Label interpreterStubReturn(env);
Branch(Int64Equal(currentFrameType, Int64(static_cast<uint64_t>(FrameType::INTERPRETER_CONSTRUCTOR_FRAME))),
&isFastNewFrameExit, &interpreterStubReturn);
Bind(&isFastNewFrameExit);
{
GateRef func = GetFunctionFromFrame(frame);
Label accNotEcmaObject(env);
Branch(IsEcmaObject(*varAcc), &interpreterStubReturn, &accNotEcmaObject);
Bind(&accNotEcmaObject);
Label funcIsBase(env);
Label funcNotBase(env);
Branch(IsBase(func), &funcIsBase, &funcNotBase);
Bind(&funcIsBase);
{
GateRef thisObject = GetThisObjectFromFastNewFrame(*varSp);
varAcc = thisObject;
Jump(&interpreterStubReturn);
}
Bind(&funcNotBase);
Label accIsUndefined(env);
Label accNotUndefined(env);
Branch(TaggedIsUndefined(*varAcc), &accIsUndefined, &accNotUndefined);
Bind(&accNotUndefined);
{
SetCurrentSpFrame(glue, currentSp); // Exception should be thrown in currentSp instead of prevSp.
CallRuntime(glue, RTSTUB_ID(ThrowDerivedMustReturnException), {});
DISPATCH_LAST();
}
Bind(&accIsUndefined);
GateRef thisObject = GetThisObjectFromFastNewFrame(*varSp);
varAcc = thisObject;
Jump(&interpreterStubReturn);
}
Bind(&interpreterStubReturn);
#endif
GateRef function = GetFunctionFromFrame(prevState);
varConstpool = GetConstpoolFromFunction(function);
varProfileTypeInfo = GetProfileTypeInfoFromFunction(function);
@ -4419,15 +4205,10 @@ DECLARE_ASM_HANDLER(HandleReturnDyn)
IntPtr(JSFunctionBase::METHOD_OFFSET));
varHotnessCounter = GetHotnessCounterFromMethod(method);
GateRef jumpSize = GetCallSizeFromFrame(prevState);
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
CallNGCRuntime(glue, RTSTUB_ID(ResumeRspAndDispatch),
{ glue, currentSp, *varPc, *varConstpool, *varProfileTypeInfo,
*varAcc, *varHotnessCounter, jumpSize });
Return();
#else
Dispatch(glue, *varSp, *varPc, *varConstpool, *varProfileTypeInfo, *varAcc,
*varHotnessCounter, jumpSize);
#endif
}
}
@ -4478,44 +4259,6 @@ DECLARE_ASM_HANDLER(HandleReturnUndefinedPref)
}
Bind(&pcNotEqualNullptr);
{
#if !ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
SetCurrentSpFrame(glue, *varSp);
GateRef frameTypeOffset = IntPtr(AsmInterpretedFrame::GetBaseOffset(env->IsArch32Bit()) +
InterpretedFrameBase::GetTypeOffset(env->IsArch32Bit()));
GateRef currentFrameType = Load(VariableType::INT64(), frame, frameTypeOffset);
Label isFastNewFrameExit(env);
Label interpreterStubReturn(env);
Branch(Int64Equal(currentFrameType, Int64(static_cast<uint64_t>(FrameType::INTERPRETER_CONSTRUCTOR_FRAME))),
&isFastNewFrameExit, &interpreterStubReturn);
Bind(&isFastNewFrameExit);
{
GateRef func = GetFunctionFromFrame(frame);
Label funcIsBase(env);
Label funcNotBase(env);
Branch(IsBase(func), &funcIsBase, &funcNotBase);
Bind(&funcIsBase);
{
GateRef thisObject = GetThisObjectFromFastNewFrame(*varSp);
varAcc = thisObject;
Jump(&interpreterStubReturn);
}
Bind(&funcNotBase);
Label accIsUndefined(env);
Label accNotUndefined(env);
Branch(TaggedIsUndefined(*varAcc), &accIsUndefined, &accNotUndefined);
Bind(&accNotUndefined);
{
SetCurrentSpFrame(glue, currentSp); // Exception should be thrown in currentSp instead of prevSp.
CallRuntime(glue, RTSTUB_ID(ThrowDerivedMustReturnException), {});
DISPATCH_LAST();
}
Bind(&accIsUndefined);
GateRef thisObject = GetThisObjectFromFastNewFrame(*varSp);
varAcc = thisObject;
Jump(&interpreterStubReturn);
}
Bind(&interpreterStubReturn);
#endif
GateRef function = GetFunctionFromFrame(prevState);
varConstpool = GetConstpoolFromFunction(function);
varProfileTypeInfo = GetProfileTypeInfoFromFunction(function);
@ -4523,15 +4266,10 @@ DECLARE_ASM_HANDLER(HandleReturnUndefinedPref)
IntPtr(JSFunctionBase::METHOD_OFFSET));
varHotnessCounter = GetHotnessCounterFromMethod(method);
GateRef jumpSize = GetCallSizeFromFrame(prevState);
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
CallNGCRuntime(glue, RTSTUB_ID(ResumeRspAndDispatch),
{ glue, currentSp, *varPc, *varConstpool, *varProfileTypeInfo,
*varAcc, *varHotnessCounter, jumpSize });
Return();
#else
Dispatch(glue, *varSp, *varPc, *varConstpool, *varProfileTypeInfo, *varAcc,
*varHotnessCounter, jumpSize);
#endif
}
}
@ -4580,9 +4318,7 @@ DECLARE_ASM_HANDLER(HandleSuspendGeneratorPrefV8V8)
}
Bind(&tryContinue);
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
GateRef currentSp = *varSp;
#endif
varSp = Load(VariableType::NATIVE_POINTER(), frame,
IntPtr(AsmInterpretedFrame::GetBaseOffset(env->IsArch32Bit())));
GateRef prevState = GetFrame(*varSp);
@ -4595,9 +4331,6 @@ DECLARE_ASM_HANDLER(HandleSuspendGeneratorPrefV8V8)
}
Bind(&pcNotEqualNullptr);
{
#if !ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
SetCurrentSpFrame(glue, *varSp);
#endif
GateRef function = GetFunctionFromFrame(prevState);
varConstpool = GetConstpoolFromFunction(function);
varProfileTypeInfo = GetProfileTypeInfoFromFunction(function);
@ -4605,15 +4338,10 @@ DECLARE_ASM_HANDLER(HandleSuspendGeneratorPrefV8V8)
IntPtr(JSFunctionBase::METHOD_OFFSET));
varHotnessCounter = GetHotnessCounterFromMethod(method);
GateRef jumpSize = GetCallSizeFromFrame(prevState);
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
CallNGCRuntime(glue, RTSTUB_ID(ResumeRspAndDispatch),
{ glue, currentSp, *varPc, *varConstpool, *varProfileTypeInfo,
*varAcc, *varHotnessCounter, jumpSize });
Return();
#else
Dispatch(glue, *varSp, *varPc, *varConstpool, *varProfileTypeInfo, *varAcc,
*varHotnessCounter, jumpSize);
#endif
}
}
@ -4635,11 +4363,7 @@ DECLARE_ASM_HANDLER(ExceptionHandler)
Branch(IntPtrEqual(*varPc, IntPtr(0)), &pcIsInvalid, &pcNotInvalid);
Bind(&pcIsInvalid);
{
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
CallNGCRuntime(glue, RTSTUB_ID(ResumeUncaughtFrameAndReturn), { glue });
#else
CallNGCRuntime(glue, RTSTUB_ID(ResumeRspAndReturn), { Undefined() });
#endif
Return();
}
Bind(&pcNotInvalid);
@ -4654,15 +4378,10 @@ DECLARE_ASM_HANDLER(ExceptionHandler)
GateRef method = Load(VariableType::NATIVE_POINTER(), function,
IntPtr(JSFunctionBase::METHOD_OFFSET));
varHotnessCounter = GetHotnessCounterFromMethod(method);
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
CallNGCRuntime(glue, RTSTUB_ID(ResumeCaughtFrameAndDispatch), {
glue, *varSp, *varPc, *varConstpool,
*varProfileTypeInfo, *varAcc, *varHotnessCounter});
Return();
#else
Dispatch(glue, *varSp, *varPc, *varConstpool, *varProfileTypeInfo, *varAcc,
*varHotnessCounter, IntPtr(0));
#endif
}
}
@ -5148,318 +4867,11 @@ DECLARE_ASM_HANDLER(HandleSub2DynPrefV8)
DISPATCH_WITH_ACC(PREF_V8);
}
#define CALL_INITIALIZE() \
SetPcToFrame(glue, GetFrame(sp), pc); \
GateRef func = GetVregValue(sp, ZExtInt8ToPtr(funcReg)); \
Label funcIsHeapObject(env); \
Label funcIsCallable(env); \
Label funcNotCallable(env); \
Branch(TaggedIsHeapObject(func), &funcIsHeapObject, &funcNotCallable); \
Bind(&funcIsHeapObject); \
Branch(IsCallable(func), &funcIsCallable, &funcNotCallable); \
Bind(&funcNotCallable); \
{ \
CallRuntime(glue, RTSTUB_ID(ThrowNotCallableException), {}); \
DISPATCH_LAST(); \
} \
Bind(&funcIsCallable); \
GateRef method = GetMethodFromJSFunction(func); \
GateRef callField = GetCallFieldFromMethod(method); \
DEFVARIABLE(newSp, VariableType::NATIVE_POINTER(), \
PointerSub(sp, IntPtr(AsmInterpretedFrame::GetSize(env->IsArch32Bit()))))
#define CALL_PUSH_ARGS(format) \
DEFVARIABLE(i, VariableType::INT32(), Int32(0)); \
GateRef isNativeMask = Int64(static_cast<uint64_t>(1) << JSMethod::IsNativeBit::START_BIT); \
Label methodIsNative(env); \
Label methodNotNative(env); \
Branch(Int64NotEqual(Int64And(callField, isNativeMask), Int64(0)), &methodIsNative, &methodNotNative); \
Bind(&methodIsNative); \
{ \
CALL_PUSH_ARGS_##format(); \
SET_VREGS_AND_FRAME_NATIVE(format); \
} \
Bind(&methodNotNative); \
GateRef numArgsOffset = Int64(JSMethod::NumArgsBits::START_BIT); \
GateRef numArgsMask = Int64((static_cast<uint64_t>(1) << JSMethod::NumArgsBits::SIZE) - 1); \
GateRef declaredNumArgs = ChangeInt64ToInt32(Int64And(Int64LSR(callField, numArgsOffset), numArgsMask)); \
Label fastPath(env); \
Label slowPath(env); \
Label setVregsAndFrameNotNative(env); \
Branch(Int32Equal(actualNumArgs, declaredNumArgs), &fastPath, &slowPath); \
Bind(&fastPath); \
{ \
CALL_PUSH_ARGS_##format(); \
Jump(&setVregsAndFrameNotNative); \
} \
Bind(&slowPath); \
GateRef haveExtraMask = Int64(static_cast<uint64_t>(1) << JSMethod::HaveExtraBit::START_BIT); \
Label methodNoExtra(env); \
Label methodHaveExtra(env); \
Branch(Int64NotEqual(Int64And(callField, haveExtraMask), Int64(0)), &methodHaveExtra, &methodNoExtra); \
Bind(&methodNoExtra); \
{ \
GateRef undefinedNumArgs = Int32Sub(declaredNumArgs, actualNumArgs); \
newSp = PushUndefined(glue, *newSp, undefinedNumArgs); \
CALL_PUSH_ARGS_NO_EXTRA_##format(); \
Jump(&setVregsAndFrameNotNative); \
} \
Bind(&methodHaveExtra); \
{ \
newSp = PushArg(glue, *newSp, IntBuildTaggedTypeWithNoGC(actualNumArgs)); \
GateRef undefinedNumArgs = Int32Sub(declaredNumArgs, actualNumArgs); \
newSp = PushUndefined(glue, *newSp, undefinedNumArgs); \
CALL_PUSH_ARGS_##format(); \
Jump(&setVregsAndFrameNotNative); \
} \
Bind(&setVregsAndFrameNotNative); \
SET_VREGS_AND_FRAME_NOT_NATIVE(format)
#define SET_VREGS_AND_FRAME_NATIVE(format) \
Label pushThis(env); \
Label pushThisUndefined(env); \
Label pushNewTarget(env); \
Branch(callThis, &pushThis, &pushThisUndefined); \
Bind(&pushThis); \
{ \
GateRef thisValue = GetVregValue(sp, PtrAdd(ZExtInt8ToPtr(funcReg), IntPtr(1))); \
newSp = PushArg(glue, *newSp, thisValue); \
Jump(&pushNewTarget); \
} \
Bind(&pushThisUndefined); \
{ \
newSp = PushArg(glue, *newSp, Int64(JSTaggedValue::VALUE_UNDEFINED)); \
Jump(&pushNewTarget); \
} \
Bind(&pushNewTarget); \
newSp = PushArg(glue, *newSp, Int64(JSTaggedValue::VALUE_UNDEFINED)); \
newSp = PushArg(glue, *newSp, func); \
/* ASSERT(JSMethod::NumVregsBits::Decode(callField) == 0) */ \
Label stackOverflow(env); \
Label stackNotOverflow(env); \
Branch(CheckStackOverflow(glue, *newSp), &stackOverflow, &stackNotOverflow); \
Bind(&stackOverflow); \
{ \
CallRuntime(glue, RTSTUB_ID(ThrowStackOverflowException), {}); \
DISPATCH_LAST(); \
} \
Bind(&stackNotOverflow); \
SetFrameState(glue, *newSp, func, Hole(VariableType::JS_ANY()), \
Hole(VariableType::JS_ANY()), IntPtr(0), sp, \
Int64(static_cast<uint64_t>(FrameType::ASM_INTERPRETER_FRAME))); \
SetCurrentSpFrame(glue, *newSp); \
GateRef retValue = CallRuntime(glue, RTSTUB_ID(CallNative), \
{IntBuildTaggedTypeWithNoGC(actualNumArgs)}); \
SetCurrentSpFrame(glue, sp); \
Label hasPendingException(env); \
Label noPendingException(env); \
Branch(TaggedIsException(retValue), &hasPendingException, &noPendingException); \
Bind(&hasPendingException); \
{ \
DISPATCH_LAST(); \
} \
Bind(&noPendingException); \
DEFVARIABLE(varAcc, VariableType::JS_ANY(), retValue); \
DISPATCH_WITH_ACC(format)
#define SET_VREGS_AND_FRAME_NOT_NATIVE(format) \
Label funcIsClassConstructor(env); \
Label funcNotClassConstructor(env); \
Branch(IsClassConstructor(func), &funcIsClassConstructor, &funcNotClassConstructor); \
Bind(&funcIsClassConstructor); \
{ \
CallRuntime(glue, RTSTUB_ID(ThrowCallConstructorException), {}); \
DISPATCH_LAST(); \
} \
Bind(&funcNotClassConstructor); \
Label notNormalCallType(env); \
Label isNormalCallType(env); \
Branch(Int64Equal(Int64And(callField, Int64(CALL_TYPE_MASK)), Int64(0)), \
&isNormalCallType, &notNormalCallType); \
Bind(&notNormalCallType); \
{ \
GateRef haveThisMask = Int64(static_cast<uint64_t>(1) << JSMethod::HaveThisBit::START_BIT); \
Label methodHaveThis(env); \
Label methodNoThis(env); \
Branch(Int64NotEqual(Int64And(callField, haveThisMask), Int64(0)), \
&methodHaveThis, &methodNoThis); \
Bind(&methodHaveThis); \
{ \
Label pushThis(env); \
Label pushThisUndefined(env); \
Branch(callThis, &pushThis, &pushThisUndefined); \
Bind(&pushThis); \
{ \
GateRef thisValue = GetVregValue(sp, PtrAdd(ZExtInt8ToPtr(funcReg), IntPtr(1))); \
newSp = PushArg(glue, *newSp, thisValue); \
Jump(&methodNoThis); \
} \
Bind(&pushThisUndefined); \
{ \
newSp = PushArg(glue, *newSp, Int64(JSTaggedValue::VALUE_UNDEFINED)); \
Jump(&methodNoThis); \
} \
} \
Bind(&methodNoThis); \
GateRef haveNewTargetMask = Int64(static_cast<uint64_t>(1) << JSMethod::HaveNewTargetBit::START_BIT); \
Label methodHaveNewTarget(env); \
Label methodNoNewTarget(env); \
Branch(Int64NotEqual(Int64And(callField, haveNewTargetMask), Int64(0)), \
&methodHaveNewTarget, &methodNoNewTarget); \
Bind(&methodHaveNewTarget); \
{ \
newSp = PushArg(glue, *newSp, Int64(JSTaggedValue::VALUE_UNDEFINED)); \
Jump(&methodNoNewTarget); \
} \
Bind(&methodNoNewTarget); \
GateRef haveFuncMask = Int64(static_cast<uint64_t>(1) << JSMethod::HaveFuncBit::START_BIT); \
Label methodHaveFunc(env); \
Label methodNoFunc(env); \
Branch(Int64NotEqual(Int64And(callField, haveFuncMask), Int64(0)), \
&methodHaveFunc, &methodNoFunc); \
Bind(&methodHaveFunc); \
{ \
newSp = PushArg(glue, *newSp, func); \
Jump(&methodNoFunc); \
} \
Bind(&methodNoFunc); \
Jump(&isNormalCallType); \
} \
Bind(&isNormalCallType); \
{ \
GateRef numVregsOffset = Int64(JSMethod::NumVregsBits::START_BIT); \
GateRef numVregsMask = Int64((static_cast<uint64_t>(1) << JSMethod::NumVregsBits::SIZE) - 1); \
GateRef numVregs = ChangeInt64ToInt32(Int64And(Int64LSR(callField, numVregsOffset), numVregsMask)); \
newSp = PushUndefined(glue, *newSp, numVregs); \
Label stackOverflow(env); \
Label stackNotOverflow(env); \
Branch(CheckStackOverflow(glue, *newSp), &stackOverflow, &stackNotOverflow); \
Bind(&stackOverflow); \
{ \
CallRuntime(glue, RTSTUB_ID(ThrowStackOverflowException), {}); \
DISPATCH_LAST(); \
} \
Bind(&stackNotOverflow); \
SetCallSizeToFrame(glue, GetFrame(sp), \
IntPtr(BytecodeInstruction::Size(BytecodeInstruction::Format::format))); \
GateRef newEnv = GetEnvFromFunction(func); \
GateRef bytecodeArrayOffset = IntPtr(JSMethod::GetBytecodeArrayOffset(env->IsArch32Bit())); \
GateRef bytecodeArray = Load(VariableType::NATIVE_POINTER(), method, bytecodeArrayOffset); \
SetFrameState(glue, *newSp, func, Hole(VariableType::JS_ANY()), newEnv, bytecodeArray, sp, \
Int64(static_cast<uint64_t>(FrameType::ASM_INTERPRETER_FRAME))); \
SetCurrentSpFrame(glue, *newSp); \
GateRef newConstpool = GetConstpoolFromFunction(func); \
GateRef newProfileTypeInfo = GetProfileTypeInfoFromFunction(func); \
GateRef newHotnessCounter = GetHotnessCounterFromMethod(method); \
Dispatch(glue, *newSp, bytecodeArray, newConstpool, newProfileTypeInfo, \
Hole(VariableType::JS_ANY()), newHotnessCounter, IntPtr(0)); \
}
#define CALL_PUSH_ARGS_PREF_V8() \
static_cast<void>(0) // do nothing when 0 arg
#define CALL_PUSH_ARGS_NO_EXTRA_PREF_V8() \
static_cast<void>(0) // do nothing when 0 arg
#define CALL_PUSH_ARGS_PREF_V8_V8() \
GateRef a0Value = GetVregValue(sp, ZExtInt8ToPtr(a0)); \
newSp = PushArg(glue, *newSp, a0Value)
#define CALL_PUSH_ARGS_NO_EXTRA_PREF_V8_V8() \
Label push0(env); \
Label skip0(env); \
Branch(Int32GreaterThanOrEqual(declaredNumArgs, \
Int32(InterpreterAssembly::ActualNumArgsOfCall::CALLARG1)), &push0, &skip0); \
Bind(&push0); \
{ \
GateRef a0Value = GetVregValue(sp, ZExtInt8ToPtr(a0)); \
newSp = PushArg(glue, *newSp, a0Value); \
Jump(&skip0); \
} \
Bind(&skip0)
#define CALL_PUSH_ARGS_PREF_V8_V8_V8() \
GateRef a1Value = GetVregValue(sp, ZExtInt8ToPtr(a1)); \
newSp = PushArg(glue, *newSp, a1Value); \
CALL_PUSH_ARGS_PREF_V8_V8()
#define CALL_PUSH_ARGS_NO_EXTRA_PREF_V8_V8_V8() \
Label push1(env); \
Label skip1(env); \
Branch(Int32GreaterThanOrEqual(declaredNumArgs, \
Int32(InterpreterAssembly::ActualNumArgsOfCall::CALLARGS2)), &push1, &skip1); \
Bind(&push1); \
{ \
GateRef a1Value = GetVregValue(sp, ZExtInt8ToPtr(a1)); \
newSp = PushArg(glue, *newSp, a1Value); \
Jump(&skip1); \
} \
Bind(&skip1); \
CALL_PUSH_ARGS_NO_EXTRA_PREF_V8_V8()
#define CALL_PUSH_ARGS_PREF_V8_V8_V8_V8() \
GateRef a2Value = GetVregValue(sp, ZExtInt8ToPtr(a2)); \
newSp = PushArg(glue, *newSp, a2Value); \
CALL_PUSH_ARGS_PREF_V8_V8_V8()
#define CALL_PUSH_ARGS_NO_EXTRA_PREF_V8_V8_V8_V8() \
Label push2(env); \
Label skip2(env); \
Branch(Int32GreaterThanOrEqual(declaredNumArgs, \
Int32(InterpreterAssembly::ActualNumArgsOfCall::CALLARGS3)), &push2, &skip2); \
Bind(&push2); \
{ \
GateRef a2Value = GetVregValue(sp, ZExtInt8ToPtr(a2)); \
newSp = PushArg(glue, *newSp, a2Value); \
Jump(&skip2); \
} \
Bind(&skip2); \
CALL_PUSH_ARGS_NO_EXTRA_PREF_V8_V8_V8()
#define CALL_PUSH_ARGS_PREF_IMM16_V8() \
i = actualNumArgs; \
CALL_PUSH_ARGS_I()
#define CALL_PUSH_ARGS_NO_EXTRA_PREF_IMM16_V8() \
/* i = std::min(actualNumArgs, declaredNumArgs) */ \
i = actualNumArgs; \
Label declaredNumArgsSmaller(env); \
Label callPushArgsI(env); \
Branch(Int32LessThan(*i, declaredNumArgs), &callPushArgsI, &declaredNumArgsSmaller); \
Bind(&declaredNumArgsSmaller); \
i = declaredNumArgs; \
Jump(&callPushArgsI); \
Bind(&callPushArgsI); \
CALL_PUSH_ARGS_I()
#define CALL_PUSH_ARGS_I() \
Label pushWithThis(env); \
Label pushWithoutThis(env); \
Label pushArgsEnd(env); \
Branch(callThis, &pushWithThis, &pushWithoutThis); \
Bind(&pushWithThis); \
{ \
i = Int32Add(*i, Int32(1)); /* 1: skip this */ \
GateRef startIndex = Int32Add(ZExtInt8ToInt32(funcReg), Int32(2)); /* 2: skip this */ \
GateRef endIndex = Int32Add(ZExtInt8ToInt32(funcReg), *i); \
newSp = PushRange(glue, *newSp, sp, startIndex, endIndex); \
Jump(&pushArgsEnd); \
} \
Bind(&pushWithoutThis); \
{ \
GateRef startIndex = Int32Add(ZExtInt8ToInt32(funcReg), Int32(1)); \
GateRef endIndex = Int32Add(ZExtInt8ToInt32(funcReg), *i); \
newSp = PushRange(glue, *newSp, sp, startIndex, endIndex); \
Jump(&pushArgsEnd); \
} \
Bind(&pushArgsEnd)
DECLARE_ASM_HANDLER(HandleCallArg0DynPrefV8)
{
auto env = GetEnvironment();
GateRef actualNumArgs = Int32(InterpreterAssembly::ActualNumArgsOfCall::CALLARG0);
GateRef funcReg = ReadInst8_1(pc);
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
GateRef func = GetVregValue(sp, ZExtInt8ToPtr(funcReg));
GateRef jumpSize = IntPtr(BytecodeInstruction::Size(BytecodeInstruction::Format::PREF_V8));
GateRef res = JSCallDispatch(glue, func, actualNumArgs, JSCallMode::CALL_ARG0, {});
@ -5472,11 +4884,6 @@ DECLARE_ASM_HANDLER(HandleCallArg0DynPrefV8)
}
Bind(&notException);
Dispatch(glue, sp, pc, constpool, profileTypeInfo, res, hotnessCounter, jumpSize);
#else
CALL_INITIALIZE();
GateRef callThis = False();
CALL_PUSH_ARGS(PREF_V8);
#endif
}
DECLARE_ASM_HANDLER(HandleCallArg1DynPrefV8V8)
@ -5485,7 +4892,6 @@ DECLARE_ASM_HANDLER(HandleCallArg1DynPrefV8V8)
GateRef actualNumArgs = Int32(InterpreterAssembly::ActualNumArgsOfCall::CALLARG1);
GateRef funcReg = ReadInst8_1(pc);
GateRef a0 = ReadInst8_2(pc);
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
GateRef func = GetVregValue(sp, ZExtInt8ToPtr(funcReg));
GateRef a0Value = GetVregValue(sp, ZExtInt8ToPtr(a0));
GateRef jumpSize = IntPtr(BytecodeInstruction::Size(BytecodeInstruction::Format::PREF_V8_V8));
@ -5499,11 +4905,6 @@ DECLARE_ASM_HANDLER(HandleCallArg1DynPrefV8V8)
}
Bind(&notException);
Dispatch(glue, sp, pc, constpool, profileTypeInfo, res, hotnessCounter, jumpSize);
#else
CALL_INITIALIZE();
GateRef callThis = False();
CALL_PUSH_ARGS(PREF_V8_V8);
#endif
}
DECLARE_ASM_HANDLER(HandleCallArgs2DynPrefV8V8V8)
@ -5513,7 +4914,6 @@ DECLARE_ASM_HANDLER(HandleCallArgs2DynPrefV8V8V8)
GateRef funcReg = ReadInst8_1(pc);
GateRef a0 = ReadInst8_2(pc);
GateRef a1 = ReadInst8_3(pc);
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
GateRef func = GetVregValue(sp, ZExtInt8ToPtr(funcReg));
GateRef a0Value = GetVregValue(sp, ZExtInt8ToPtr(a0));
GateRef a1Value = GetVregValue(sp, ZExtInt8ToPtr(a1));
@ -5529,11 +4929,6 @@ DECLARE_ASM_HANDLER(HandleCallArgs2DynPrefV8V8V8)
}
Bind(&notException);
Dispatch(glue, sp, pc, constpool, profileTypeInfo, res, hotnessCounter, jumpSize);
#else
CALL_INITIALIZE();
GateRef callThis = False();
CALL_PUSH_ARGS(PREF_V8_V8_V8);
#endif
}
DECLARE_ASM_HANDLER(HandleCallArgs3DynPrefV8V8V8V8)
@ -5544,7 +4939,6 @@ DECLARE_ASM_HANDLER(HandleCallArgs3DynPrefV8V8V8V8)
GateRef a0 = ReadInst8_2(pc);
GateRef a1 = ReadInst8_3(pc);
GateRef a2 = ReadInst8_4(pc);
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
GateRef func = GetVregValue(sp, ZExtInt8ToPtr(funcReg));
GateRef a0Value = GetVregValue(sp, ZExtInt8ToPtr(a0));
GateRef a1Value = GetVregValue(sp, ZExtInt8ToPtr(a1));
@ -5561,11 +4955,6 @@ DECLARE_ASM_HANDLER(HandleCallArgs3DynPrefV8V8V8V8)
}
Bind(&notException);
Dispatch(glue, sp, pc, constpool, profileTypeInfo, res, hotnessCounter, jumpSize);
#else
CALL_INITIALIZE();
GateRef callThis = False();
CALL_PUSH_ARGS(PREF_V8_V8_V8_V8);
#endif
}
DECLARE_ASM_HANDLER(HandleCallIRangeDynPrefImm16V8)
@ -5573,7 +4962,6 @@ DECLARE_ASM_HANDLER(HandleCallIRangeDynPrefImm16V8)
auto env = GetEnvironment();
GateRef actualNumArgs = ZExtInt16ToInt32(ReadInst16_1(pc));
GateRef funcReg = ReadInst8_3(pc);
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
GateRef func = GetVregValue(sp, ZExtInt8ToPtr(funcReg));
GateRef argv = PtrAdd(sp, PtrMul(
PtrAdd(ZExtInt8ToPtr(funcReg), IntPtr(1)), IntPtr(8))); // 1: skip function
@ -5590,11 +4978,6 @@ DECLARE_ASM_HANDLER(HandleCallIRangeDynPrefImm16V8)
}
Bind(&notException);
Dispatch(glue, sp, pc, constpool, profileTypeInfo, res, hotnessCounter, jumpSize);
#else
CALL_INITIALIZE();
GateRef callThis = False();
CALL_PUSH_ARGS(PREF_IMM16_V8);
#endif
}
DECLARE_ASM_HANDLER(HandleCallIThisRangeDynPrefImm16V8)
@ -5602,7 +4985,6 @@ DECLARE_ASM_HANDLER(HandleCallIThisRangeDynPrefImm16V8)
auto env = GetEnvironment();
GateRef actualNumArgs = Int32Sub(ZExtInt16ToInt32(ReadInst16_1(pc)), Int32(1)); // 1: exclude this
GateRef funcReg = ReadInst8_3(pc);
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
funcReg = ZExtInt8ToPtr(funcReg);
GateRef func = GetVregValue(sp, funcReg);
GateRef thisValue = GetVregValue(sp, PtrAdd(funcReg, IntPtr(1)));
@ -5621,11 +5003,6 @@ DECLARE_ASM_HANDLER(HandleCallIThisRangeDynPrefImm16V8)
}
Bind(&notException);
Dispatch(glue, sp, pc, constpool, profileTypeInfo, res, hotnessCounter, jumpSize);
#else
CALL_INITIALIZE();
GateRef callThis = True();
CALL_PUSH_ARGS(PREF_IMM16_V8);
#endif
}
DECLARE_ASM_HANDLER(HandleLdBigIntPrefId32)

File diff suppressed because it is too large Load Diff

View File

@ -93,7 +93,7 @@ void LLVMStackMapParser::PrintCallSiteInfo(const CallSiteInfo *infos, OptimizedL
}
}
void LLVMStackMapParser::PrintCallSiteInfo(const CallSiteInfo *infos, uintptr_t *fp) const
void LLVMStackMapParser::PrintCallSiteInfo(const CallSiteInfo *infos, uintptr_t *fp, uintptr_t curPc) const
{
if (!IsLogEnabled()) {
return;
@ -105,7 +105,7 @@ void LLVMStackMapParser::PrintCallSiteInfo(const CallSiteInfo *infos, uintptr_t
uintptr_t derived = 0;
uintptr_t callsiteFp = *fp;
uintptr_t callSiteSp = FrameHandler::GetPrevFrameCallSiteSp(reinterpret_cast<JSTaggedType *>(fp));
uintptr_t callSiteSp = FrameHandler::GetPrevFrameCallSiteSp(reinterpret_cast<JSTaggedType *>(fp), curPc);
for (auto &info: *infos) {
if (info.first == GCStackMapRegisters::SP) {
@ -138,24 +138,26 @@ bool LLVMStackMapParser::IsDeriveredPointer(int callsitetime) const
}
bool LLVMStackMapParser::CollectStackMapSlots(uintptr_t callSiteAddr, uintptr_t frameFp,
std::set<uintptr_t> &baseSet, ChunkMap<DerivedDataKey, uintptr_t> *data, [[maybe_unused]] bool isVerifying) const
std::set<uintptr_t> &baseSet, ChunkMap<DerivedDataKey, uintptr_t> *data, [[maybe_unused]] bool isVerifying,
uintptr_t curPc) const
{
const CallSiteInfo *infos = GetCallSiteInfoByPc(callSiteAddr);
if (infos == nullptr) {
return false;
}
uintptr_t *fp = reinterpret_cast<uintptr_t *>(frameFp);
uintptr_t callsiteFp = *fp;
uintptr_t callSiteSp = FrameHandler::GetPrevFrameCallSiteSp(reinterpret_cast<JSTaggedType *>(frameFp), curPc);
uintptr_t address = 0;
uintptr_t base = 0;
uintptr_t derived = 0;
int i = 0;
if (IsLogEnabled()) {
PrintCallSiteInfo(infos, fp);
PrintCallSiteInfo(infos, fp, curPc);
}
uintptr_t callsiteFp = *fp;
uintptr_t callSiteSp = FrameHandler::GetPrevFrameCallSiteSp(reinterpret_cast<JSTaggedType *>(frameFp));
for (auto &info: *infos) {
if (info.first == GCStackMapRegisters::SP) {
address = callSiteSp + info.second;
@ -180,6 +182,7 @@ bool LLVMStackMapParser::CollectStackMapSlots(uintptr_t callSiteAddr, uintptr_t
}
} else {
base = reinterpret_cast<uintptr_t>(address);
baseSet.emplace(base);
}
i++;
}
@ -189,7 +192,9 @@ bool LLVMStackMapParser::CollectStackMapSlots(uintptr_t callSiteAddr, uintptr_t
void LLVMStackMapParser::CalcCallSite()
{
uint64_t recordNum = 0;
auto calStkMapRecordFunc = [this, &recordNum](uintptr_t address, int recordId) {
Pc2CallSiteInfo pc2CallSiteInfo;
Pc2ConstInfo pc2ConstInfo;
auto calStkMapRecordFunc = [this, &recordNum, &pc2CallSiteInfo, &pc2ConstInfo](uintptr_t address, int recordId) {
struct StkMapRecordHeadTy recordHead = llvmStackMap_.StkMapRecord[recordNum + recordId].head;
for (int j = 0; j < recordHead.NumLocations; j++) {
struct LocationTy loc = llvmStackMap_.StkMapRecord[recordNum + recordId].Locations[j];
@ -202,12 +207,16 @@ void LLVMStackMapParser::CalcCallSite()
instructionOffset << " callsite:" << " patchPointID :" << std::hex << patchPointID <<
callsite;
DwarfRegAndOffsetType info(loc.DwarfRegNum, loc.OffsetOrSmallConstant);
auto it = pc2CallSiteInfo_.find(callsite);
if (pc2CallSiteInfo_.find(callsite) == pc2CallSiteInfo_.end()) {
pc2CallSiteInfo_.insert(std::pair<uintptr_t, CallSiteInfo>(callsite, {info}));
auto it = pc2CallSiteInfo.find(callsite);
if (pc2CallSiteInfo.find(callsite) == pc2CallSiteInfo.end()) {
pc2CallSiteInfo.insert(std::pair<uintptr_t, CallSiteInfo>(callsite, {info}));
} else {
it->second.emplace_back(info);
}
} else if (loc.location == LocationTy::Kind::CONSTANT) {
if (j >= LocationTy::CONSTANT_FIRST_ELEMENT_INDEX) {
pc2ConstInfo[callsite].push_back(loc.OffsetOrSmallConstant);
}
}
}
};
@ -219,16 +228,17 @@ void LLVMStackMapParser::CalcCallSite()
}
recordNum += recordCount;
}
pc2CallSiteInfoVec_.emplace_back(pc2CallSiteInfo);
pc2ConstInfoVec_.emplace_back(pc2ConstInfo);
}
bool LLVMStackMapParser::CalculateStackMap(std::unique_ptr<uint8_t []> stackMapAddr)
{
stackMapAddr_ = std::move(stackMapAddr);
if (!stackMapAddr_) {
COMPILER_LOG(ERROR) << "stackMapAddr_ nullptr error ! ";
if (!stackMapAddr) {
COMPILER_LOG(ERROR) << "stackMapAddr nullptr error ! ";
return false;
}
dataInfo_ = std::make_unique<DataInfo>(std::move(stackMapAddr_));
dataInfo_ = std::make_unique<DataInfo>(std::move(stackMapAddr));
llvmStackMap_.head = dataInfo_->Read<struct Header>();
uint32_t numFunctions, numConstants, numRecords;
numFunctions = dataInfo_->Read<uint32_t>();
@ -288,9 +298,56 @@ bool LLVMStackMapParser::CalculateStackMap(std::unique_ptr<uint8_t []> stackMapA
COMPILER_OPTIONAL_LOG(DEBUG) << std::dec << i << "th function " << std::hex << hostAddr << " ---> "
<< deviceAddr;
}
pc2CallSiteInfo_.clear();
CalcCallSite();
pc2CallSiteInfoVec_.push_back(pc2CallSiteInfo_);
return true;
}
void LLVMStackMapParser::CalculateFuncFpDelta(Func2FpDelta info)
{
bool find = std::find(fun2FpDelta_.begin(), fun2FpDelta_.end(), info) == fun2FpDelta_.end();
if (!info.empty() && find) {
fun2FpDelta_.emplace_back(info);
}
for (auto &it: info) {
funAddr_.insert(it.first);
}
}
int LLVMStackMapParser::FindFpDelta(uintptr_t funcAddr, uintptr_t callsitePc) const
{
int delta = 0;
// next optimization can be performed via sorted/map.
for (auto &info: fun2FpDelta_) {
if (info.find(funcAddr) != info.end()) {
delta = info.at(funcAddr).first;
int funcSize = info.at(funcAddr).second;
if (callsitePc <= funcAddr + funcSize && callsitePc >= funcAddr) {
return delta;
}
}
}
return delta;
}
int LLVMStackMapParser::GetFuncFpDelta(uintptr_t callsitePc) const
{
int delta = 0;
auto itupper = funAddr_.upper_bound(callsitePc);
if (itupper != funAddr_.end()) { // find first element >= callsitePc
--itupper;
// callsitePC may jscall or entry, thus not existed in funAddr_
if ((itupper == funAddr_.end()) || (*itupper > callsitePc)) {
return delta;
}
delta = FindFpDelta(*itupper, callsitePc);
} else {
auto rit = funAddr_.crbegin(); // find last element
// callsitePC may jscall or entry, thus not existed in funAddr_
if ((rit == funAddr_.crend()) || (*rit > callsitePc)) {
return delta;
}
delta = FindFpDelta(*rit, callsitePc);
}
return delta;
}
} // namespace panda::ecmascript::kungfu

View File

@ -32,6 +32,10 @@ using DwarfRegAndOffsetType = std::pair<DwarfRegType, OffsetType>;
using CallSiteInfo = std::vector<DwarfRegAndOffsetType>;
using Fun2InfoType = std::pair<uintptr_t, DwarfRegAndOffsetType>;
using Pc2CallSiteInfo = std::unordered_map<uintptr_t, CallSiteInfo>;
using FpDelta = std::pair<int, uint32_t>;
using Func2FpDelta = std::unordered_map<uintptr_t, FpDelta>; // value: fpDelta & funcSize
using ConstInfo = std::vector<OffsetType>;
using Pc2ConstInfo = std::unordered_map<uintptr_t, ConstInfo>;
struct Header {
uint8_t stackmapversion; // Stack Map Version (current version is 3)
@ -89,6 +93,7 @@ struct LocationTy {
CONSTANT = 4,
CONSTANTNDEX = 5,
};
static constexpr int CONSTANT_FIRST_ELEMENT_INDEX = 3;
Kind location;
uint8_t Reserved_0;
uint16_t LocationSize;
@ -204,42 +209,59 @@ public:
const CallSiteInfo *GetCallSiteInfoByPc(uintptr_t funcAddr) const;
bool CollectStackMapSlots(uintptr_t callSiteAddr, uintptr_t frameFp,
std::set<uintptr_t> &baseSet, ChunkMap<DerivedDataKey, uintptr_t> *data,
[[maybe_unused]] bool isVerifying) const;
[[maybe_unused]] bool isVerifying,
uintptr_t curPc) const;
bool IsLogEnabled() const
{
return enableLog_;
}
void PUBLIC_API CalculateFuncFpDelta(Func2FpDelta info);
int PUBLIC_API GetFuncFpDelta(uintptr_t callsitePc) const;
ConstInfo GetConstInfo(uintptr_t callsite)
{
// next optimization can be performed via sorted/map to accelerate the search
for (auto &pc2ConstInfo : pc2ConstInfoVec_) {
auto it = pc2ConstInfo.find(callsite);
if (it != pc2ConstInfo.end()) {
return pc2ConstInfo[callsite];
}
}
return {};
}
private:
explicit LLVMStackMapParser(bool enableLog)
{
stackMapAddr_ = nullptr;
pc2CallSiteInfo_.clear();
pc2CallSiteInfoVec_.clear();
dataInfo_ = nullptr;
enableLog_ = enableLog;
funAddr_.clear();
fun2FpDelta_.clear();
pc2ConstInfoVec_.clear();
}
~LLVMStackMapParser()
{
if (stackMapAddr_) {
stackMapAddr_.release();
}
pc2CallSiteInfo_.clear();
pc2CallSiteInfoVec_.clear();
dataInfo_ = nullptr;
funAddr_.clear();
fun2FpDelta_.clear();
pc2ConstInfoVec_.clear();
}
void CalcCallSite();
bool IsDeriveredPointer(int callsitetime) const;
void PrintCallSiteInfo(const CallSiteInfo *infos, OptimizedLeaveFrame *frame) const;
void PrintCallSiteInfo(const CallSiteInfo *infos, uintptr_t *fp) const;
void PrintCallSiteInfo(const CallSiteInfo *infos, uintptr_t *fp, uintptr_t curPc) const;
int FindFpDelta(uintptr_t funcAddr, uintptr_t callsitePc) const;
std::unique_ptr<uint8_t[]> stackMapAddr_;
struct LLVMStackMap llvmStackMap_;
Pc2CallSiteInfo pc2CallSiteInfo_;
std::vector<Pc2CallSiteInfo> pc2CallSiteInfoVec_;
[[maybe_unused]] std::unique_ptr<DataInfo> dataInfo_;
bool enableLog_ {false};
std::set<uintptr_t> funAddr_;
std::vector<Func2FpDelta> fun2FpDelta_;
std::vector<Pc2ConstInfo> pc2ConstInfoVec_;
};
} // namespace panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_LLVM_LLVMSTACKPARSE_H

View File

@ -87,6 +87,7 @@ void LLVMIRGeneratorImpl::GenerateCode(Circuit *circuit, const ControlFlowGraph
const panda::ecmascript::JSMethod *method)
{
auto function = module_->AddFunc(method);
circuit->SetFrameType(FrameType::OPTIMIZED_JS_FUNCTION_FRAME);
LLVMIRBuilder builder(&graph, circuit, module_, function, cfg, CallSignature::CallConv::WebKitJSCallConv,
enableLog_);
builder.Build();
@ -248,7 +249,26 @@ static const char *SymbolLookupCallback([[maybe_unused]] void *disInfo, [[maybe_
return nullptr;
}
void LLVMAssembler::Disassemble(const std::map<uint64_t, std::string> &addr2name, const CompilerLog &log) const
int LLVMAssembler::GetFpDeltaPrevFramSp(LLVMValueRef fn, const CompilerLog &log)
{
int fpToCallerSpDelta = 0;
const char attrKey[] = "fpToCallerSpDelta"; // this key must consistent with llvm backend.
LLVMAttributeRef attrirbuteRef = LLVMGetStringAttributeAtIndex(fn,
llvm::AttributeList::FunctionIndex, attrKey, strlen(attrKey));
if (attrirbuteRef) {
llvm::Attribute attr = llvm::unwrap(attrirbuteRef);
auto value = attr.getValueAsString().data();
fpToCallerSpDelta = atoi(value);
if (log.IsAlwaysEnabled()) {
size_t length;
COMPILER_LOG(INFO) << " funcName: " << LLVMGetValueName2(fn, &length) << " fpToCallerSpDelta:"
<< fpToCallerSpDelta;
}
}
return fpToCallerSpDelta;
}
void LLVMAssembler::Disassemble(const std::map<uintptr_t, std::string> &addr2name, const CompilerLog &log) const
{
LLVMDisasmContextRef dcr = LLVMCreateDisasm(LLVMGetTarget(module_), nullptr, 0, nullptr, SymbolLookupCallback);
bool logFlag = false;

View File

@ -194,7 +194,8 @@ public:
{
return engine_;
}
void Disassemble(const std::map<uint64_t, std::string> &addr2name, const CompilerLog &log) const;
void Disassemble(const std::map<uintptr_t, std::string> &addr2name, const CompilerLog &log) const;
static int GetFpDeltaPrevFramSp(LLVMValueRef fn, const CompilerLog &log);
static void Disassemble(uint8_t *buf, size_t size);
uintptr_t GetStackMapsSection() const
{

View File

@ -371,10 +371,14 @@ void LLVMIRBuilder::GenPrologue([[maybe_unused]] LLVMModuleRef &module, LLVMBuil
LLVMValueRef addr = LLVMBuildIntToPtr(builder, frameTypeSlotAddr,
LLVMPointerType(slotType_, 0), "frameType.Addr");
int reservedSlotsSize = slotSize_ * static_cast<int>(ReservedSlots::OPTIMIZED_RESERVED_SLOT);
if (frameType == panda::ecmascript::FrameType::OPTIMIZED_FRAME) {
LLVMAddTargetDependentFunctionAttr(function_, "js-stub-call", "0");
} else if (frameType == panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME) {
LLVMAddTargetDependentFunctionAttr(function_, "js-stub-call", "1");
LLVMAddTargetDependentFunctionAttr(function_, "frame-reserved-slots",
std::to_string(reservedSlotsSize).c_str());
} else if (frameType == panda::ecmascript::FrameType::OPTIMIZED_JS_FUNCTION_FRAME) {
reservedSlotsSize = slotSize_ * static_cast<int>(ReservedSlots::OPTIMIZED_JS_FUNCTION_RESERVED_SLOT);
LLVMAddTargetDependentFunctionAttr(function_, "frame-reserved-slots",
std::to_string(reservedSlotsSize).c_str());
} else {
COMPILER_OPTIONAL_LOG(FATAL) << "frameType interpret type error !";
ASSERT_PRINT(static_cast<uintptr_t>(frameType), "is not support !");
@ -629,56 +633,6 @@ LLVMValueRef LLVMIRBuilder::GetCurrentSP()
return spValue;
}
void LLVMIRBuilder::SaveCurrentSP()
{
if (compCfg_->Is64Bit()) {
LLVMValueRef llvmFpAddr = CallingFp(module_, builder_, false);
LLVMValueRef frameAddr = LLVMBuildPtrToInt(builder_, llvmFpAddr, slotType_, "cast_int_t");
auto callSiteSpOffset = IsInterpreted() ?
AsmInterpretedFrame::GetCallSiteFpToSpDelta(compCfg_->Is32Bit()) :
OptimizedFrame::GetCallSiteFpToSpDelta(compCfg_->Is32Bit());
LLVMValueRef frameSpSlotAddr = LLVMBuildSub(builder_, frameAddr, LLVMConstInt(slotType_,
callSiteSpOffset, false), "");
LLVMValueRef addr = LLVMBuildIntToPtr(builder_, frameSpSlotAddr,
LLVMPointerType(slotType_, 0), "frameCallSiteSP.Addr");
LLVMMetadataRef meta;
if (compCfg_->IsAmd64()) {
meta = LLVMMDStringInContext2(context_, "rsp", 4); // 4 : 4 means len of "rsp"
} else {
meta = LLVMMDStringInContext2(context_, "sp", 3); // 3 : 3 means len of "sp"
}
LLVMMetadataRef metadataNode = LLVMMDNodeInContext2(context_, &meta, 1);
LLVMValueRef spValue = ReadRegister(module_, builder_, metadataNode);
LLVMBuildStore(builder_, spValue, addr);
}
}
LLVMValueRef LLVMIRBuilder::GetCurrentSPFrameAddr()
{
LLVMValueRef glue = LLVMGetParam(function_, 0);
LLVMTypeRef glueType = LLVMTypeOf(glue);
LLVMValueRef rtoffset = LLVMConstInt(glueType,
JSThread::GlueData::GetCurrentFrameOffset(compCfg_->Is32Bit()),
0);
LLVMValueRef rtbaseoffset = LLVMBuildAdd(builder_, glue, rtoffset, "");
return rtbaseoffset;
}
LLVMValueRef LLVMIRBuilder::GetCurrentSPFrame()
{
LLVMValueRef addr = GetCurrentSPFrameAddr();
LLVMValueRef rtbaseAddr = LLVMBuildIntToPtr(builder_, addr, LLVMPointerType(slotType_, 0), "");
LLVMValueRef currentSpFrame = LLVMBuildLoad(builder_, rtbaseAddr, "");
return currentSpFrame;
}
void LLVMIRBuilder::SetCurrentSPFrame(LLVMValueRef sp)
{
LLVMValueRef addr = GetCurrentSPFrameAddr();
LLVMValueRef rtbaseAddr = LLVMBuildIntToPtr(builder_, addr, LLVMPointerType(slotType_, 0), "");
LLVMBuildStore(builder_, sp, rtbaseAddr);
}
LLVMValueRef LLVMIRBuilder::GetCurrentFrameType(LLVMValueRef currentSpFrameAddr)
{
LLVMValueRef tmp = LLVMBuildSub(builder_, currentSpFrameAddr, LLVMConstInt(slotType_, slotSize_, 1), "");
@ -749,9 +703,6 @@ void LLVMIRBuilder::VisitCall(GateRef gate, const std::vector<GateRef> &inList,
GateRef gateTmp = inList[paraIdx];
params.push_back(gate2LValue_[gateTmp]);
}
if (op == OpCode::CALL) {
SaveCurrentSP();
}
LLVMValueRef call = LLVMBuildCall(builder_, callee, params.data(),
inList.size() - firstArg + extraParameterCnt, "");
SetCallConvAttr(calleeDescriptor, call);

View File

@ -124,12 +124,18 @@ public:
void SetFunction(size_t index, LLVMValueRef func)
{
funcIndexMap_[index] = func;
funcIndexMap_.emplace_back(std::make_pair(index, func));
}
LLVMValueRef GetFunction(size_t index)
{
return funcIndexMap_.at(index);
// next optimization can be performed
for (auto &it: funcIndexMap_) {
if (it.first == index) {
return it.second;
}
}
return nullptr;
}
size_t GetFuncCount() const
@ -166,7 +172,7 @@ private:
// index:
// stub scenario - sequence of function adding to llvmModule
// aot scenario - method Id of function generated by panda files
std::map<size_t, LLVMValueRef> funcIndexMap_;
std::vector<std::pair<size_t, LLVMValueRef>> funcIndexMap_;
std::vector<const CallSignature *> callSigns_;
LLVMModuleRef module_;
CompilationConfig cfg_;
@ -245,7 +251,6 @@ private:
void LinkToLLVMCfg(int bbId, const OperandsVector &predecessors);
BasicBlock *EnsureBB(int id);
LLVMValueRef CallingFp(LLVMModuleRef &module, LLVMBuilderRef &builder, bool isCaller);
void SaveCurrentSP();
LLVMValueRef GetCurrentSP();
LLVMValueRef ReadRegister(LLVMModuleRef &module, LLVMBuilderRef &builder,
LLVMMetadataRef meta);
@ -276,9 +281,6 @@ private:
LLVMValueRef VectorAdd(LLVMValueRef e1Value, LLVMValueRef e2Value, LLVMTypeRef rep);
LLVMValueRef CanonicalizeToInt(LLVMValueRef value);
LLVMValueRef CanonicalizeToPtr(LLVMValueRef value);
LLVMValueRef GetCurrentSPFrame();
LLVMValueRef GetCurrentSPFrameAddr();
void SetCurrentSPFrame(LLVMValueRef sp);
LLVMValueRef GetCurrentFrameType(LLVMValueRef currentSpFrameAddr);
bool IsGCRelated(GateType typeCode) const;
void SetFunctionCallConv();

View File

@ -81,8 +81,12 @@ bool PassManager::CollectInfoOfPandaFile(const std::string &fileName, std::strin
}
translateInfo->jsPandaFile = jsPandaFile;
TSLoader *tsLoader = vm_->GetTSLoader();
tsLoader->DecodeTSTypes(jsPandaFile);
if (jsPandaFile->HasTSTypes()) {
TSLoader *tsLoader = vm_->GetTSLoader();
tsLoader->DecodeTSTypes(jsPandaFile);
} else {
COMPILER_LOG(INFO) << fileName << " has no type info";
}
auto program = PandaFileTranslator::GenerateProgram(vm_, jsPandaFile);
JSHandle<JSFunction> mainFunc(vm_->GetJSThread(), program->GetMainFunction());

View File

@ -3786,22 +3786,14 @@ GateRef Stub::JSCallDispatch(GateRef glue, GateRef func, GateRef actualNumArgs,
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
break;
case JSCallMode::CALL_GETTER:
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
{ glue, nativeCode, actualNumArgs, func,
newTarget, data[0] });
#else
result = Hole();
#endif
break;
case JSCallMode::CALL_SETTER:
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
result = CallNGCRuntime(glue, RTSTUB_ID(PushCallArgsAndDispatchNative),
{ glue, nativeCode, actualNumArgs, func,
newTarget, data[0], data[1] });
#else
result = Hole();
#endif
break;
default:
UNREACHABLE();
@ -3858,21 +3850,13 @@ GateRef Stub::JSCallDispatch(GateRef glue, GateRef func, GateRef actualNumArgs,
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
break;
case JSCallMode::CALL_GETTER:
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
result = CallNGCRuntime(glue, RTSTUB_ID(CallGetter),
{ glue, func, method, callField, data[0] });
#else
result = Hole();
#endif
Jump(&exit);
break;
case JSCallMode::CALL_SETTER:
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
result = CallNGCRuntime(glue, RTSTUB_ID(CallSetter),
{ glue, func, method, callField, data[0], data[1], });
#else
result = Hole();
#endif
Jump(&exit);
break;
default:

View File

@ -18,8 +18,8 @@ import("//build/test.gni")
config("include_llvm_config") {
if (compile_llvm_online) {
include_dirs = [
"//third_party/llvm-project/build/include",
"//third_party/llvm-project/llvm/include/",
"//third_party/third_party_llvm-project/build/include",
"//third_party/third_party_llvm-project/llvm/include/",
]
} else {
include_dirs = [
@ -46,7 +46,7 @@ host_unittest_action("StubTest") {
]
if (compile_llvm_online) {
lib_dirs = [ "//third_party/llvm-project/build/lib" ]
lib_dirs = [ "//third_party/third_party_llvm-project/build/lib" ]
} else {
lib_dirs =
[ "//prebuilts/ark_tools/ark_js_prebuilts/llvm_prebuilts/build/lib" ]
@ -135,7 +135,7 @@ host_unittest_action("AssemblerTest") {
]
if (compile_llvm_online) {
lib_dirs = [ "//third_party/llvm-project/build/lib" ]
lib_dirs = [ "//third_party/third_party_llvm-project/build/lib" ]
} else {
lib_dirs =
[ "//prebuilts/ark_tools/ark_js_prebuilts/llvm_prebuilts/build/lib" ]

View File

@ -555,7 +555,8 @@ HWTEST_F_L0(StubTest, JSEntryTest)
/* implement stub1 */
LLVMValueRef stub1 = LLVMAddFunction(module, "stub1", LLVMFunctionType(LLVMInt64Type(), paramTys0, 1, 0));
LLVMAddTargetDependentFunctionAttr(stub1, "frame-pointer", "all");
LLVMAddTargetDependentFunctionAttr(stub1, "js-stub-call", "1");
int reservedSlotsSize = sizeof(uint64_t) * static_cast<int>(ReservedSlots::OPTIMIZED_ENTRY_RESERVED_SLOT);
LLVMAddTargetDependentFunctionAttr(stub1, "frame-reserved-slots", std::to_string(reservedSlotsSize).c_str());
LLVMBasicBlockRef entryBb = LLVMAppendBasicBlock(stub1, "entry");
LLVMPositionBuilderAtEnd(builder, entryBb);
@ -593,7 +594,8 @@ HWTEST_F_L0(StubTest, JSEntryTest)
/* implement stub2 call stub3 */
LLVMValueRef stub2 = LLVMAddFunction(module, "stub2", LLVMFunctionType(LLVMInt64Type(), paramTys0, 1, 0));
LLVMAddTargetDependentFunctionAttr(stub2, "frame-pointer", "all");
LLVMAddTargetDependentFunctionAttr(stub2, "js-stub-call", "1");
int reservedSlotsSize = sizeof(uint64_t) * static_cast<int>(ReservedSlots::OPTIMIZED_ENTRY_RESERVED_SLOT);
LLVMAddTargetDependentFunctionAttr(stub2, "frame-reserved-slots", std::to_string(reservedSlotsSize).c_str());
entryBb = LLVMAppendBasicBlock(stub2, "entry");
LLVMPositionBuilderAtEnd(builder, entryBb);
@ -623,7 +625,8 @@ HWTEST_F_L0(StubTest, JSEntryTest)
/* implement stub3 call RuntimeFunc2 */
LLVMAddTargetDependentFunctionAttr(stub3, "frame-pointer", "all");
LLVMAddTargetDependentFunctionAttr(stub3, "js-stub-call", "0");
int reservedSlotsSize = sizeof(uint64_t) * static_cast<int>(ReservedSlots::OPTIMIZED_RESERVED_SLOT);
LLVMAddTargetDependentFunctionAttr(stub3, "frame-reserved-slots", std::to_string(reservedSlotsSize).c_str());
entryBb = LLVMAppendBasicBlock(stub3, "entry");
LLVMPositionBuilderAtEnd(builder, entryBb);
@ -686,7 +689,8 @@ HWTEST_F_L0(StubTest, Prologue)
/* implement main implement */
LLVMValueRef func = LLVMAddFunction(module, "main", LLVMFunctionType(LLVMInt64Type(), nullptr, 0, 0));
LLVMAddTargetDependentFunctionAttr(func, "frame-pointer", "all");
LLVMAddTargetDependentFunctionAttr(func, "js-stub-call", "1");
int reservedSlotsSize = sizeof(uint64_t) * static_cast<int>(ReservedSlots::OPTIMIZED_ENTRY_RESERVED_SLOT);
LLVMAddTargetDependentFunctionAttr(func, "frame-reserved-slots", std::to_string(reservedSlotsSize).c_str());
LLVMBasicBlockRef entryBb = LLVMAppendBasicBlock(func, "entry");
LLVMPositionBuilderAtEnd(builder, entryBb);
@ -695,7 +699,8 @@ HWTEST_F_L0(StubTest, Prologue)
LLVMBuilderRef builderBar = LLVMCreateBuilder();
LLVMValueRef bar = LLVMAddFunction(module, "bar", LLVMFunctionType(LLVMInt64Type(), paramTys0, 2, 0));
LLVMAddTargetDependentFunctionAttr(bar, "frame-pointer", "all");
LLVMAddTargetDependentFunctionAttr(bar, "js-stub-call", "0");
int reservedSlotsSize = sizeof(uint64_t) * static_cast<int>(ReservedSlots::OPTIMIZED_RESERVED_SLOT);
LLVMAddTargetDependentFunctionAttr(bar, "frame-reserved-slots", std::to_string(reservedSlotsSize).c_str());
LLVMBasicBlockRef entryBbBar = LLVMAppendBasicBlock(bar, "entry");
LLVMPositionBuilderAtEnd(builderBar, entryBbBar);
LLVMValueRef value0Bar = LLVMGetParam(bar, 0);
@ -744,7 +749,8 @@ HWTEST_F_L0(StubTest, CEntryFp)
/* implement main call RuntimeFunc */
LLVMValueRef func = LLVMAddFunction(module, "main", LLVMFunctionType(LLVMInt64Type(), paramTys0, 1, 0));
LLVMAddTargetDependentFunctionAttr(func, "frame-pointer", "all");
LLVMAddTargetDependentFunctionAttr(func, "js-stub-call", "1");
int reservedSlotsSize = sizeof(uint64_t) * static_cast<int>(ReservedSlots::OPTIMIZED_ENTRY_RESERVED_SLOT);
LLVMAddTargetDependentFunctionAttr(func, "frame-reserved-slots", std::to_string(reservedSlotsSize).c_str());
LLVMBasicBlockRef entryBb = LLVMAppendBasicBlock(func, "entry");
LLVMPositionBuilderAtEnd(builder, entryBb);

File diff suppressed because it is too large Load Diff

View File

@ -75,18 +75,6 @@ public:
static void PushCallArgs0AndDispatch(ExtendedAssembler *assembler);
static void PushCallIThisRangeAndDispatchSlowPath(ExtendedAssembler *assembler);
static void PushCallIRangeAndDispatchSlowPath(ExtendedAssembler *assembler);
static void PushCallArgs3AndDispatchSlowPath(ExtendedAssembler *assembler);
static void PushCallArgs2AndDispatchSlowPath(ExtendedAssembler *assembler);
static void PushCallArgs1AndDispatchSlowPath(ExtendedAssembler *assembler);
static void PushCallArgs0AndDispatchSlowPath(ExtendedAssembler *assembler);
static void PushCallIThisRangeAndDispatchNative(ExtendedAssembler *assembler);
static void PushCallIRangeAndDispatchNative(ExtendedAssembler *assembler);
@ -108,21 +96,21 @@ public:
private:
static void JSCallBody(ExtendedAssembler *assembler, Register jsfunc);
static void CallIThisRangeNoExtraEntry(ExtendedAssembler *assembler, Register declaredNumArgs);
static void CallIThisRangeNoExtraEntry(ExtendedAssembler *assembler);
static void CallIRangeNoExtraEntry(ExtendedAssembler *assembler, Register declaredNumArgs);
static void CallIRangeNoExtraEntry(ExtendedAssembler *assembler);
static void Callargs3NoExtraEntry(ExtendedAssembler *assembler, Register declaredNumArgs);
static void Callargs3NoExtraEntry(ExtendedAssembler *assembler);
static void Callargs2NoExtraEntry(ExtendedAssembler *assembler, Register declaredNumArgs);
static void Callargs2NoExtraEntry(ExtendedAssembler *assembler);
static void Callargs1NoExtraEntry(ExtendedAssembler *assembler, Register declaredNumArgs);
static void Callargs1NoExtraEntry(ExtendedAssembler *assembler);
static void Callargs0NoExtraEntry(ExtendedAssembler *assembler);
static void CallIThisRangeEntry(ExtendedAssembler *assembler);
static void PushCallThis(ExtendedAssembler *assembler);
static void PushCallThis(ExtendedAssembler *assembler, Register thisRegister, bool isUndefined);
static void CallIRangeEntry(ExtendedAssembler *assembler);
@ -150,6 +138,19 @@ private:
static void PushFrameState(ExtendedAssembler *assembler, Register prevSp, Register fp, Register callTarget,
Register method, Register pc, Register op);
using AssemblerClosure = std::function<void(ExtendedAssembler *assembler)>;
static void JSCallCommonEntry(ExtendedAssembler *assembler, JSCallMode mode,
const AssemblerClosure& fastEntry, const AssemblerClosure& slowEntry);
static void JSCallCommonSlowPath(ExtendedAssembler *assembler, JSCallMode mode,
const AssemblerClosure& entry,
const AssemblerClosure& extraEntry);
static void PushCallIThisRangeAndDispatchSlowPath(ExtendedAssembler *assembler);
static void PushCallIRangeAndDispatchSlowPath(ExtendedAssembler *assembler);
static void PushCallArgs3AndDispatchSlowPath(ExtendedAssembler *assembler);
static void PushCallArgs2AndDispatchSlowPath(ExtendedAssembler *assembler);
static void PushCallArgs1AndDispatchSlowPath(ExtendedAssembler *assembler);
static void PushCallArgs0AndDispatchSlowPath(ExtendedAssembler *assembler);
static void GetNumVregsFromCallField(ExtendedAssembler *assembler, Register callField, Register numVregs);
static void GetDeclaredNumArgsFromCallField(ExtendedAssembler *assembler, Register callField,
@ -167,17 +168,16 @@ private:
static void StackOverflowCheck([[maybe_unused]] ExtendedAssembler *assembler);
static void PushAsmInterpEntryFrame(ExtendedAssembler *assembler, Register &frameTypeRegister,
Register &prevFrameRegister, Register &pcRegister);
static void PushAsmInterpEntryFrame(ExtendedAssembler *assembler, bool saveLeave);
static void PopAsmInterpEntryFrame(ExtendedAssembler *assembler, Register &prevFrameRegister);
static void PopAsmInterpEntryFrame(ExtendedAssembler *assembler, bool saveLeave);
static void PushGeneratorFrameState(ExtendedAssembler *assembler, Register &frameTypeRegister,
Register &prevSpRegister, Register &fpRegister, Register &callTargetRegister, Register &methodRegister,
Register &contextRegister, Register &pcRegister, Register &operatorRegister);
static void PushGeneratorFrameState(ExtendedAssembler *assembler, Register &prevSpRegister, Register &fpRegister,
Register &callTargetRegister, Register &methodRegister, Register &contextRegister, Register &pcRegister,
Register &operatorRegister);
static void CallBCStub(ExtendedAssembler *assembler, Register &newSp, Register &glue,
Register &callTarget, Register &method, Register &pc, Register &temp, bool isReturn);
Register &callTarget, Register &method, Register &pc, Register &temp);
static void CallNativeEntry(ExtendedAssembler *assembler);
@ -188,6 +188,12 @@ private:
static void PushArgsSlowPath(ExtendedAssembler *assembler, Register &glueRegister,
Register &declaredNumArgsRegister, Register &argcRegister, Register &argvRegister, Register &callTargetRegister,
Register &methodRegister, Register &prevSpRegister, Register &callFieldRegister);
static void CallGetterSlow(ExtendedAssembler *assembler);
static void CallSetterSlow(ExtendedAssembler *assembler);
static void CallGetterEntry(ExtendedAssembler *assembler);
static void CallSetterEntry(ExtendedAssembler *assembler);
static void CallNoExtraSetterEntry(ExtendedAssembler *assembler);
};
} // namespace panda::ecmascript::x64
#endif // ECMASCRIPT_COMPILER_ASSEMBLER_MODULE_X64_H

View File

@ -193,7 +193,7 @@ void AssemblerStubsX64::OptimizedCallOptimized(ExtendedAssembler *assembler)
Label lPopFrame1;
__ Pushq(rbp);
__ Movq(rsp, rbp);
__ Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_FRAME));
__ Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME));
// callee save
__ Pushq(r14);
__ Pushq(rbx);
@ -402,7 +402,7 @@ void AssemblerStubsX64::JSCallWithArgV(ExtendedAssembler *assembler)
{
__ Pushq(rbp);
__ Movq(rsp, rbp); // set frame pointer
__ Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_FRAME)); // set frame type
__ Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)); // set frame type
__ Movq(MessageString::Message_NonCallable, rax);
__ Pushq(rax); // message id
__ Pushq(1); // argc
@ -473,7 +473,7 @@ void AssemblerStubsX64::JSCallWithArgV(ExtendedAssembler *assembler)
{
__ Pushq(rbp);
__ Movq(rsp, rbp);
__ Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_FRAME));
__ Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME));
__ Pushq(r10); // callee save
__ Movq(rsp, rdx);
__ Addq(32, rdx); // 32: sp + 32 argv
@ -653,7 +653,7 @@ void AssemblerStubsX64::JSCall(ExtendedAssembler *assembler)
{
__ Pushq(rbp);
__ Movq(rsp, rbp); // set frame pointer
__ Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_FRAME)); // set frame type
__ Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)); // set frame type
__ Movq(MessageString::Message_NonCallable, rax);
__ Pushq(rax); // message id
__ Pushq(1); // argc
@ -724,7 +724,7 @@ void AssemblerStubsX64::JSCall(ExtendedAssembler *assembler)
{
__ Pushq(rbp);
__ Movq(rsp, rbp);
__ Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_FRAME));
__ Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME));
__ Pushq(r10); // callee save
__ Movq(rsp, rdx);
__ Addq(32, rdx); // 32: sp + 32 argv
@ -1278,7 +1278,8 @@ void AssemblerStubsX64::JSCallCommonEntry(ExtendedAssembler *assembler, JSCallMo
if (assembler->FromInterpreterHandler()) {
auto jumpSize = kungfu::AssemblerModule::GetJumpSizeFromJSCallMode(mode);
auto offset = AsmInterpretedFrame::GetCallSizeOffset(false) - AsmInterpretedFrame::GetSize(false);
int32_t offset = static_cast<int32_t>(
AsmInterpretedFrame::GetCallSizeOffset(false) - AsmInterpretedFrame::GetSize(false));
__ Movq(static_cast<int>(jumpSize), Operand(rbp, offset));
}
@ -2039,12 +2040,10 @@ void AssemblerStubsX64::CallSetterSlow(ExtendedAssembler *assembler)
void AssemblerStubsX64::ResumeRspAndReturn([[maybe_unused]] ExtendedAssembler *assembler)
{
__ BindAssemblerStub(RTSTUB_ID(ResumeRspAndReturn));
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
Register fpRegister = r10;
auto offset = AsmInterpretedFrame::GetFpOffset(false) - AsmInterpretedFrame::GetSize(false);
__ Movq(Operand(rbp, offset), fpRegister);
__ Movq(fpRegister, rsp);
#endif
// return
{
__ Movq(r13, rax);

View File

@ -54,6 +54,26 @@ void TypeInfer::TraverseCircuit()
COMPILER_LOG(INFO) << "TypeInfer:======================================================";
circuit_->PrintAllGates(*builder_);
}
if (tsLoader_->GetTypeInferenceLog()) {
TypeInferPrint();
}
}
void TypeInfer::TypeInferPrint() const
{
const auto &gateList = circuit_->GetAllGates();
std::string log("TestInfer:");
for (const auto &gate : gateList) {
auto op = gateAccessor_.GetOpCode(gate);
if (op == OpCode::JS_BYTECODE) {
log += "&" + builder_->GetBytecodeStr(gate) + ":";
auto gateType = gateAccessor_.GetGateType(gate);
auto type = gateType > GlobalTSTypeRef::TS_TYPE_RESERVED_COUNT ? "INF" : std::to_string(gateType);
log += type;
}
}
COMPILER_LOG(INFO) << std::dec << log;
}
bool TypeInfer::UpdateType(GateRef gate, const GateType type)

View File

@ -67,6 +67,7 @@ private:
bool InferDefineGetterSetterByValue(GateRef gate);
bool InferNewObjSpread(GateRef gate);
bool InferSuperCall(GateRef gate);
void TypeInferPrint() const;
BytecodeCircuitBuilder *builder_ {nullptr};
Circuit *circuit_ {nullptr};

View File

@ -76,10 +76,11 @@ JSTaggedValue ContainersArrayList::Insert(EcmaRuntimeCallInfo *argv)
JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
if (!index->IsNumber()) {
if (!index->IsInteger()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "index is not Integer", JSTaggedValue::Exception());
}
JSAPIArrayList::Insert(thread, JSHandle<JSAPIArrayList>::Cast(self), value, JSTaggedValue::ToUint32(thread, index));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return JSTaggedValue::Undefined();
}
@ -166,7 +167,7 @@ JSTaggedValue ContainersArrayList::IncreaseCapacityTo(EcmaRuntimeCallInfo *argv)
}
JSHandle<JSTaggedValue> newCapacity = GetCallArg(argv, 0);
if (!newCapacity->IsNumber()) {
if (!newCapacity->IsInteger()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "newCapacity is not Integer", JSTaggedValue::Exception());
}
@ -274,7 +275,7 @@ JSTaggedValue ContainersArrayList::RemoveByIndex(EcmaRuntimeCallInfo *argv)
}
JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
if (!value->IsNumber()) {
if (!value->IsInteger()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "index is not Integer", JSTaggedValue::Exception());
}
@ -318,7 +319,7 @@ JSTaggedValue ContainersArrayList::RemoveByRange(EcmaRuntimeCallInfo *argv)
JSHandle<JSTaggedValue> startIndex = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> endIndex = GetCallArg(argv, 1);
if (!startIndex->IsNumber() || !endIndex->IsNumber()) {
if (!startIndex->IsInteger() || !endIndex->IsInteger()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "startIndex or endIndex is not Integer", JSTaggedValue::Exception());
}
JSAPIArrayList::RemoveByRange(thread, JSHandle<JSAPIArrayList>::Cast(self), startIndex, endIndex);
@ -382,7 +383,7 @@ JSTaggedValue ContainersArrayList::SubArrayList(EcmaRuntimeCallInfo *argv)
JSHandle<JSTaggedValue> value1 = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> value2 = GetCallArg(argv, 1);
if (!value1->IsNumber() || !value2->IsNumber()) {
if (!value1->IsInteger() || !value2->IsInteger()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "startIndex or endIndex is not Integer", JSTaggedValue::Exception());
}
JSHandle<JSAPIArrayList> newArrayList =

View File

@ -0,0 +1,428 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "containers_linked_list.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/interpreter/interpreter.h"
#include "ecmascript/js_api_linked_list.h"
#include "ecmascript/js_api_linked_list_iterator.h"
#include "ecmascript/js_function.h"
#include "ecmascript/object_factory.h"
#include "ecmascript/tagged_array-inl.h"
#include "ecmascript/tagged_list.h"
namespace panda::ecmascript::containers {
JSTaggedValue ContainersLinkedList::LinkedListConstructor(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, LinkedList, Constructor);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
if (newTarget->IsUndefined()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "new target can't be undefined", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> constructor = GetConstructor(argv);
JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSAPILinkedList> linkedList = JSHandle<JSAPILinkedList>::Cast(obj);
JSTaggedValue doubleList = TaggedDoubleList::Create(thread);
linkedList->SetDoubleList(thread, doubleList);
return linkedList.GetTaggedValue();
}
JSTaggedValue ContainersLinkedList::Add(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, LinkedList, Add);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPILinkedList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPILinkedList", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self);
JSAPILinkedList::Add(thread, jsAPILinkedList, value);
return JSTaggedValue::True();
}
JSTaggedValue ContainersLinkedList::AddFirst(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, LinkedList, AddFirst);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPILinkedList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPILinkedList", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self);
JSAPILinkedList::AddFirst(thread, jsAPILinkedList, value);
return JSTaggedValue::True();
}
JSTaggedValue ContainersLinkedList::GetFirst(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, LinkedList, GetFirst);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPILinkedList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPILinkedList", JSTaggedValue::Exception());
}
JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self);
return jsAPILinkedList->GetFirst();
}
JSTaggedValue ContainersLinkedList::GetLast(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, LinkedList, GetLast);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPILinkedList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPILinkedList", JSTaggedValue::Exception());
}
JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self);
return jsAPILinkedList->GetLast();
}
JSTaggedValue ContainersLinkedList::Length(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, LinkedList, Length);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPILinkedList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPILinkedList", JSTaggedValue::Exception());
}
JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self);
return JSTaggedValue(jsAPILinkedList->Length());
}
JSTaggedValue ContainersLinkedList::Insert(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, LinkedList, Insert);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPILinkedList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPILinkedList", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> value = GetCallArg(argv, 1);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 0);
if (!index->IsInteger()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "the index is not integer", JSTaggedValue::Exception());
}
JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self);
JSTaggedValue result =
JSAPILinkedList::Insert(thread, jsAPILinkedList, value, index->GetInt());
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return result;
}
JSTaggedValue ContainersLinkedList::Clear(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, LinkedList, Clear);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPILinkedList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPILinkedList", JSTaggedValue::Exception());
}
JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self);
jsAPILinkedList->Clear(thread);
return JSTaggedValue::Undefined();
}
JSTaggedValue ContainersLinkedList::Clone(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, LinkedList, Clone);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPILinkedList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPILinkedList", JSTaggedValue::Exception());
}
JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self);
JSHandle<JSAPILinkedList> newLinkedList = JSAPILinkedList::Clone(thread, jsAPILinkedList);
return newLinkedList.GetTaggedValue();
}
JSTaggedValue ContainersLinkedList::Has(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, LinkedList, Has);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPILinkedList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPILinkedList", JSTaggedValue::Exception());
}
JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self);
JSHandle<JSTaggedValue> element = GetCallArg(argv, 0);
return GetTaggedBoolean(jsAPILinkedList->Has(element.GetTaggedValue()));
}
JSTaggedValue ContainersLinkedList::Get(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, LinkedList, Get);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPILinkedList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPILinkedList", JSTaggedValue::Exception());
}
JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 0);
if (!index->IsInteger()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "the index is not integer", JSTaggedValue::Exception());
}
return jsAPILinkedList->Get(index->GetInt());
}
JSTaggedValue ContainersLinkedList::GetIndexOf(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, LinkedList, GetIndexOf);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPILinkedList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPILinkedList", JSTaggedValue::Exception());
}
JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self);
JSHandle<JSTaggedValue> element = GetCallArg(argv, 0);
return jsAPILinkedList->GetIndexOf(element.GetTaggedValue());
}
JSTaggedValue ContainersLinkedList::GetLastIndexOf(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, LinkedList, GetLastIndexOf);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPILinkedList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPILinkedList", JSTaggedValue::Exception());
}
JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self);
JSHandle<JSTaggedValue> element(GetCallArg(argv, 0));
return jsAPILinkedList->GetLastIndexOf(element.GetTaggedValue());
}
JSTaggedValue ContainersLinkedList::RemoveByIndex(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, LinkedList, RemoveByIndex);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPILinkedList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPILinkedList", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> index = GetCallArg(argv, 0);
if (!index->IsInteger()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "the index is not integer", JSTaggedValue::Exception());
}
JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self);
JSTaggedValue nodeData =
JSAPILinkedList::RemoveByIndex(thread, jsAPILinkedList, index->GetInt());
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return nodeData;
}
JSTaggedValue ContainersLinkedList::Remove(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, LinkedList, Remove);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPILinkedList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPILinkedList", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> element = GetCallArg(argv, 0);
JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self);
return jsAPILinkedList->Remove(thread, element.GetTaggedValue());
}
JSTaggedValue ContainersLinkedList::RemoveFirst(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, LinkedList, RemoveFirst);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPILinkedList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPILinkedList", JSTaggedValue::Exception());
}
JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self);
JSTaggedValue lastValue = JSAPILinkedList::RemoveFirst(thread, jsAPILinkedList);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return lastValue;
}
JSTaggedValue ContainersLinkedList::RemoveFirstFound(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, LinkedList, RemoveFirstFound);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPILinkedList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPILinkedList", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> element = GetCallArg(argv, 0);
JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self);
JSTaggedValue result = JSAPILinkedList::RemoveFirstFound(thread, jsAPILinkedList, element.GetTaggedValue());
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return result;
}
JSTaggedValue ContainersLinkedList::RemoveLast(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, LinkedList, RemoveLast);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPILinkedList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPILinkedList", JSTaggedValue::Exception());
}
JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self);
JSTaggedValue lastValue = JSAPILinkedList::RemoveLast(thread, jsAPILinkedList);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return lastValue;
}
JSTaggedValue ContainersLinkedList::RemoveLastFound(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, LinkedList, RemoveLastFound);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPILinkedList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPILinkedList", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> element = GetCallArg(argv, 0);
JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self);
JSTaggedValue result = JSAPILinkedList::RemoveLastFound(thread, jsAPILinkedList, element.GetTaggedValue());
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return result;
}
JSTaggedValue ContainersLinkedList::Set(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, LinkedList, Set);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPILinkedList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPILinkedList", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> index = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> element = GetCallArg(argv, 1);
if (!index->IsInteger()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "the index is not integer", JSTaggedValue::Exception());
}
JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self);
JSTaggedValue oldValue =
JSAPILinkedList::Set(thread, jsAPILinkedList, index->GetInt(), element);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return oldValue;
}
JSTaggedValue ContainersLinkedList::ConvertToArray(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, LinkedList, ConvertToArray);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPILinkedList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPILinkedList", JSTaggedValue::Exception());
}
JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self);
return JSAPILinkedList::ConvertToArray(thread, jsAPILinkedList);
}
JSTaggedValue ContainersLinkedList::ForEach(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, LinkedList, ForEach);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
if (!thisHandle->IsJSAPILinkedList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPILinkedList", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> callbackFnHandle(GetCallArg(argv, 0));
if (!callbackFnHandle->IsCallable()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "The first arg is not Callable", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
JSHandle<JSAPILinkedList> linkedList = JSHandle<JSAPILinkedList>::Cast(thisHandle);
JSHandle<TaggedDoubleList> doubleList(thread, linkedList->GetDoubleList());
int length = linkedList->Length();
int index = 0;
const uint32_t argsLength = 3; // 3: «kValue, k, O»
JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
while (index < length) {
JSTaggedValue value = doubleList->Get(index);
EcmaRuntimeCallInfo info =
EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
info.SetCallArg(value, JSTaggedValue(index), thisHandle.GetTaggedValue());
JSTaggedValue funcResult = JSFunction::Call(&info);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
index++;
}
return JSTaggedValue::Undefined();
}
JSTaggedValue ContainersLinkedList::GetIteratorObj(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, LinkedList, GetIteratorObj);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
JSHandle<JSTaggedValue> iter = JSAPILinkedListIterator::CreateLinkedListIterator(thread, self);
return iter.GetTaggedValue();
}
} // namespace panda::ecmascript::containers

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_CONTAINERS_CONTAINERS_LINKED_LIST_H
#define ECMASCRIPT_CONTAINERS_CONTAINERS_LINKED_LIST_H
#include "ecmascript/base/builtins_base.h"
#include "ecmascript/ecma_runtime_call_info.h"
namespace panda::ecmascript::containers {
class ContainersLinkedList : public base::BuiltinsBase {
public:
static JSTaggedValue LinkedListConstructor(EcmaRuntimeCallInfo *argv);
static JSTaggedValue Add(EcmaRuntimeCallInfo *argv);
static JSTaggedValue GetFirst(EcmaRuntimeCallInfo *argv);
static JSTaggedValue GetLast(EcmaRuntimeCallInfo *argv);
static JSTaggedValue Insert(EcmaRuntimeCallInfo *argv);
static JSTaggedValue AddFirst(EcmaRuntimeCallInfo *argv);
static JSTaggedValue Clear(EcmaRuntimeCallInfo *argv);
static JSTaggedValue Clone(EcmaRuntimeCallInfo *argv);
static JSTaggedValue Has(EcmaRuntimeCallInfo *argv);
static JSTaggedValue Get(EcmaRuntimeCallInfo *argv);
static JSTaggedValue GetIndexOf(EcmaRuntimeCallInfo *argv);
static JSTaggedValue GetLastIndexOf(EcmaRuntimeCallInfo *argv);
static JSTaggedValue RemoveByIndex(EcmaRuntimeCallInfo *argv);
static JSTaggedValue Remove(EcmaRuntimeCallInfo *argv);
static JSTaggedValue RemoveFirst(EcmaRuntimeCallInfo *argv);
static JSTaggedValue RemoveFirstFound(EcmaRuntimeCallInfo *argv);
static JSTaggedValue RemoveLast(EcmaRuntimeCallInfo *argv);
static JSTaggedValue RemoveLastFound(EcmaRuntimeCallInfo *argv);
static JSTaggedValue Set(EcmaRuntimeCallInfo *argv);
static JSTaggedValue Length(EcmaRuntimeCallInfo *argv);
static JSTaggedValue ConvertToArray(EcmaRuntimeCallInfo *argv);
static JSTaggedValue ForEach(EcmaRuntimeCallInfo *argv);
static JSTaggedValue GetIteratorObj(EcmaRuntimeCallInfo *argv);
};
} // namespace panda::ecmascript::containers
#endif // ECMASCRIPT_CONTAINERS_CONTAINERS_LINKED_LIST_H

View File

@ -0,0 +1,409 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "containers_list.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/interpreter/interpreter.h"
#include "ecmascript/js_api_list.h"
#include "ecmascript/js_api_list_iterator.h"
#include "ecmascript/js_function.h"
#include "ecmascript/object_factory.h"
#include "ecmascript/tagged_array-inl.h"
#include "ecmascript/tagged_list.h"
namespace panda::ecmascript::containers {
JSTaggedValue ContainersList::ListConstructor(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, List, Constructor);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
if (newTarget->IsUndefined()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "new target can't be undefined", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> constructor = GetConstructor(argv);
JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSAPIList> list = JSHandle<JSAPIList>::Cast(obj);
JSTaggedValue singleList = TaggedSingleList::Create(thread);
list->SetSingleList(thread, singleList);
return list.GetTaggedValue();
}
JSTaggedValue ContainersList::Add(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, List, Add);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIList", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
JSHandle<JSAPIList> jSAPIList = JSHandle<JSAPIList>::Cast(self);
JSAPIList::Add(thread, jSAPIList, value);
return JSTaggedValue::True();
}
JSTaggedValue ContainersList::Insert(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, List, Insert);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIList", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
if (!index->IsInteger()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "index is not integer", JSTaggedValue::Exception());
}
JSHandle<JSAPIList> jSAPIList = JSHandle<JSAPIList>::Cast(self);
JSAPIList::Insert(thread, jSAPIList, value, index->GetInt());
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return JSTaggedValue::True();
}
JSTaggedValue ContainersList::GetFirst(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, List, GetFirst);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIList", JSTaggedValue::Exception());
}
JSHandle<JSAPIList> jSAPIList = JSHandle<JSAPIList>::Cast(self);
return jSAPIList->GetFirst();
}
JSTaggedValue ContainersList::GetLast(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, List, GetLast);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIList", JSTaggedValue::Exception());
}
JSHandle<JSAPIList> jSAPIList = JSHandle<JSAPIList>::Cast(self);
return jSAPIList->GetLast();
}
JSTaggedValue ContainersList::Has(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, List, Has);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIList", JSTaggedValue::Exception());
}
JSHandle<JSAPIList> jSAPIList = JSHandle<JSAPIList>::Cast(self);
JSHandle<JSTaggedValue> element= GetCallArg(argv, 0);
return GetTaggedBoolean(jSAPIList->Has(element.GetTaggedValue()));
}
JSTaggedValue ContainersList::IsEmpty(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, List, IsEmpty);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIList", JSTaggedValue::Exception());
}
JSHandle<JSAPIList> jSAPIList = JSHandle<JSAPIList>::Cast(self);
return GetTaggedBoolean(jSAPIList->IsEmpty());
}
JSTaggedValue ContainersList::Get(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, List, Get);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIList", JSTaggedValue::Exception());
}
JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 0);
if (!index->IsInteger()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "index is not integer", JSTaggedValue::Exception());
}
return jsAPIList->Get(index->GetInt());
}
JSTaggedValue ContainersList::GetIndexOf(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, List, GetIndexOf);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIList", JSTaggedValue::Exception());
}
JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
JSHandle<JSTaggedValue> element = GetCallArg(argv, 0);
return jsAPIList->GetIndexOf(element.GetTaggedValue());
}
JSTaggedValue ContainersList::GetLastIndexOf(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, List, GetLastIndexOf);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIList", JSTaggedValue::Exception());
}
JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
JSHandle<JSTaggedValue> element = GetCallArg(argv, 0);
return jsAPIList->GetLastIndexOf(element.GetTaggedValue());
}
JSTaggedValue ContainersList::Set(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, List, Set);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIList", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> index = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> element = GetCallArg(argv, 1);
if (!index->IsInteger()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "index is not integer", JSTaggedValue::Exception());
}
JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
JSTaggedValue oldValue = JSAPIList::Set(thread, jsAPIList, index->GetInt(), element);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return oldValue;
}
JSTaggedValue ContainersList::ForEach(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, List, ForEach);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
// get and check List object
JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
if (!thisHandle->IsJSAPIList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIList", JSTaggedValue::Exception());
}
// get and check callback function
JSHandle<JSTaggedValue> callbackFnHandle(GetCallArg(argv, 0));
if (!callbackFnHandle->IsCallable()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "The first arg is not Callable", JSTaggedValue::Exception());
}
// If thisArgHandle was supplied, let T be thisArgHandle; else let T be undefined.
JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
JSHandle<JSAPIList> list = JSHandle<JSAPIList>::Cast(thisHandle);
JSHandle<TaggedSingleList> singleList(thread, list->GetSingleList());
int length = list->Length();
JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
int index = 0;
const uint32_t argsLength = 3; // 3: «kValue, k, O»
while (index < length) {
JSTaggedValue value = singleList->Get(index);
EcmaRuntimeCallInfo info =
EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
info.SetCallArg(value, JSTaggedValue(index), thisHandle.GetTaggedValue());
JSTaggedValue funcResult = JSFunction::Call(&info);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
index++;
}
return JSTaggedValue::Undefined();
}
JSTaggedValue ContainersList::Clear(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, List, Clear);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
jsAPIList->Clear(thread);
return JSTaggedValue::Undefined();
}
JSTaggedValue ContainersList::RemoveByIndex(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, List, RemoveByIndex);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 0);
if (!index->IsInteger()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "index is not integer", JSTaggedValue::Exception());
}
JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
JSTaggedValue result = JSAPIList::RemoveByIndex(thread, jsAPIList, index->GetInt());
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return result;
}
JSTaggedValue ContainersList::Remove(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, List, Remove);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
JSHandle<JSTaggedValue> element = GetCallArg(argv, 0);
JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
return jsAPIList->Remove(thread, element.GetTaggedValue());
}
JSTaggedValue ContainersList::ReplaceAllElements(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, List, ReplaceAllElements);
JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
if (!callbackFnHandle->IsCallable()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
return JSAPIList::ReplaceAllElements(thread, thisHandle, callbackFnHandle, thisArgHandle);
}
JSTaggedValue ContainersList::Equal(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, List, Equal);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIList", JSTaggedValue::Exception());
}
JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
if (!obj->IsJSAPIList()) {
return JSTaggedValue::False();
}
JSHandle<JSAPIList> handleObj = JSHandle<JSAPIList>::Cast(obj);
return jsAPIList->Equal(thread, handleObj);
}
JSTaggedValue ContainersList::Sort(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, List, Sort);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not IsJSAPIList", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
if (!callbackFnHandle->IsUndefined() && !callbackFnHandle->IsCallable()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "Callable is false", JSTaggedValue::Exception());
}
return JSAPIList::Sort(thread, self, callbackFnHandle);
}
JSTaggedValue ContainersList::GetIteratorObj(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, List, GetIteratorObj);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
JSHandle<JSTaggedValue> iter = JSAPIListIterator::CreateListIterator(thread, self);
return iter.GetTaggedValue();
}
JSTaggedValue ContainersList::ConvertToArray(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, List, ConvertToArray);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIList", JSTaggedValue::Exception());
}
JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
return JSAPIList::ConvertToArray(thread, jsAPIList);
}
JSTaggedValue ContainersList::GetSubList(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, List, GetSubList);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIList", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> fromIndex= GetCallArg(argv, 0);
if (!fromIndex->IsInteger()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "index is not integer", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> toIndex = GetCallArg(argv, 1);
if (!toIndex->IsInteger()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "index is not integer", JSTaggedValue::Exception());
}
JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
JSTaggedValue newList = JSAPIList::GetSubList(thread, jsAPIList, fromIndex->GetInt(), toIndex->GetInt());
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return newList;
}
JSTaggedValue ContainersList::Length(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, List, Length);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIList()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIList", JSTaggedValue::Exception());
}
JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
return JSTaggedValue(jsAPIList->Length());
}
} // namespace panda::ecmascript::containers

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_CONTAINERS_CONTAINERS_LIST_H
#define ECMASCRIPT_CONTAINERS_CONTAINERS_LIST_H
#include "ecmascript/base/builtins_base.h"
#include "ecmascript/ecma_runtime_call_info.h"
namespace panda::ecmascript::containers {
class ContainersList : public base::BuiltinsBase {
public:
static JSTaggedValue ListConstructor(EcmaRuntimeCallInfo *argv);
static JSTaggedValue Add(EcmaRuntimeCallInfo *argv);
static JSTaggedValue GetFirst(EcmaRuntimeCallInfo *argv);
static JSTaggedValue GetLast(EcmaRuntimeCallInfo *argv);
static JSTaggedValue Insert(EcmaRuntimeCallInfo *argv);
static JSTaggedValue Clear(EcmaRuntimeCallInfo *argv);
static JSTaggedValue RemoveByIndex(EcmaRuntimeCallInfo *argv);
static JSTaggedValue Remove(EcmaRuntimeCallInfo *argv);
static JSTaggedValue Has(EcmaRuntimeCallInfo *argv);
static JSTaggedValue IsEmpty(EcmaRuntimeCallInfo *argv);
static JSTaggedValue Get(EcmaRuntimeCallInfo *argv);
static JSTaggedValue GetIndexOf(EcmaRuntimeCallInfo *argv);
static JSTaggedValue GetLastIndexOf(EcmaRuntimeCallInfo *argv);
static JSTaggedValue Set(EcmaRuntimeCallInfo *argv);
static JSTaggedValue ForEach(EcmaRuntimeCallInfo *argv);
static JSTaggedValue ReplaceAllElements(EcmaRuntimeCallInfo *argv);
static JSTaggedValue GetIteratorObj(EcmaRuntimeCallInfo *argv);
static JSTaggedValue Equal(EcmaRuntimeCallInfo *argv);
static JSTaggedValue Sort(EcmaRuntimeCallInfo *argv);
static JSTaggedValue ConvertToArray(EcmaRuntimeCallInfo *argv);
static JSTaggedValue GetSubList(EcmaRuntimeCallInfo *argv);
static JSTaggedValue Length(EcmaRuntimeCallInfo *argv);
};
} // namespace panda::ecmascript::containers
#endif // ECMASCRIPT_CONTAINERS_CONTAINERS_LIST_H

View File

@ -57,7 +57,7 @@ JSTaggedValue ContainersPlainArray::Add(EcmaRuntimeCallInfo *argv)
}
JSHandle<JSTaggedValue> key(GetCallArg(argv, 0));
JSHandle<JSTaggedValue> value(GetCallArg(argv, 1));
if (!key->IsNumber()) {
if (!key->IsInteger()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "the index is not integer", JSTaggedValue::Exception());
}
JSAPIPlainArray::Add(thread, JSHandle<JSAPIPlainArray>::Cast(self), key, value);
@ -125,7 +125,7 @@ JSTaggedValue ContainersPlainArray::Get(EcmaRuntimeCallInfo *argv)
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIPlainArray", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> key(GetCallArg(argv, 0));
if (!key->IsNumber()) {
if (!key->IsInteger()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "the key is not integer", JSTaggedValue::Exception());
}
JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
@ -253,7 +253,7 @@ JSTaggedValue ContainersPlainArray::Remove(EcmaRuntimeCallInfo *argv)
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIPlainArray", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> key(GetCallArg(argv, 0));
if (!key->IsNumber()) {
if (!key->IsInteger()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "the key is not integer", JSTaggedValue::Undefined());
}
JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
@ -271,7 +271,7 @@ JSTaggedValue ContainersPlainArray::RemoveAt(EcmaRuntimeCallInfo *argv)
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIPlainArray", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> index(GetCallArg(argv, 0));
if (!index->IsNumber()) {
if (!index->IsInteger()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "the index is not integer", JSTaggedValue::Undefined());
}
JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
@ -290,7 +290,7 @@ JSTaggedValue ContainersPlainArray::RemoveRangeFrom(EcmaRuntimeCallInfo *argv)
}
JSHandle<JSTaggedValue> valueIndex(GetCallArg(argv, 0));
JSHandle<JSTaggedValue> valueSize(GetCallArg(argv, 1));
if (!valueIndex->IsNumber() || !valueSize->IsNumber()) {
if (!valueIndex->IsInteger() || !valueSize->IsInteger()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "the index or the value is not integer", JSTaggedValue::Undefined());
}
int32_t index = valueIndex->GetNumber();
@ -312,7 +312,7 @@ JSTaggedValue ContainersPlainArray::SetValueAt(EcmaRuntimeCallInfo *argv)
}
JSHandle<JSTaggedValue> index(GetCallArg(argv, 0));
JSHandle<JSTaggedValue> value(GetCallArg(argv, 1));
if (!index->IsNumber()) {
if (!index->IsInteger()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "the index is not integer", JSTaggedValue::Exception());
}
JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
@ -331,7 +331,7 @@ JSTaggedValue ContainersPlainArray::GetValueAt(EcmaRuntimeCallInfo *argv)
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIPlainArray", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> idx(GetCallArg(argv, 0));
if (!idx->IsNumber()) {
if (!idx->IsInteger()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "the index is not integer", JSTaggedValue::Undefined());
}
JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());

View File

@ -17,6 +17,8 @@
#include "containers_arraylist.h"
#include "containers_deque.h"
#include "containers_linked_list.h"
#include "containers_list.h"
#include "containers_plainarray.h"
#include "containers_queue.h"
#include "containers_stack.h"
@ -30,6 +32,10 @@
#include "ecmascript/js_api_arraylist_iterator.h"
#include "ecmascript/js_api_deque.h"
#include "ecmascript/js_api_deque_iterator.h"
#include "ecmascript/js_api_linked_list.h"
#include "ecmascript/js_api_linked_list_iterator.h"
#include "ecmascript/js_api_list.h"
#include "ecmascript/js_api_list_iterator.h"
#include "ecmascript/js_api_plain_array.h"
#include "ecmascript/js_api_plain_array_iterator.h"
#include "ecmascript/js_api_queue.h"
@ -92,8 +98,14 @@ JSTaggedValue ContainersPrivate::Load(EcmaRuntimeCallInfo *msg)
res = InitializeContainer(thread, thisValue, InitializeVector, "VectorConstructor");
break;
}
case ContainerTag::List:
case ContainerTag::LinkedList:
case ContainerTag::List: {
res = InitializeContainer(thread, thisValue, InitializeList, "ListConstructor");
break;
}
case ContainerTag::LinkedList: {
res = InitializeContainer(thread, thisValue, InitializeLinkedList, "LinkedListConstructor");
break;
}
case ContainerTag::HashMap:
case ContainerTag::HashSet:
case ContainerTag::LightWeightMap:
@ -237,7 +249,8 @@ JSHandle<JSTaggedValue> ContainersPrivate::InitializeArrayList(JSThread *thread)
// ArrayList() = new Function()
JSHandle<JSTaggedValue> arrayListFunction(NewContainerConstructor(
thread, prototype, ContainersArrayList::ArrayListConstructor, "ArrayList", FuncLength::ZERO));
JSHandle<JSFunction>(arrayListFunction)->SetFunctionPrototype(thread, arrayListInstanceDynclass.GetTaggedValue());
JSHandle<JSFunction>::Cast(arrayListFunction)->SetFunctionPrototype(thread,
arrayListInstanceDynclass.GetTaggedValue());
// "constructor" property on the prototype
JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
@ -311,7 +324,7 @@ JSHandle<JSTaggedValue> ContainersPrivate::InitializeTreeMap(JSThread *thread)
// TreeMap() = new Function()
JSHandle<JSTaggedValue> mapFunction(NewContainerConstructor(
thread, mapFuncPrototype, ContainersTreeMap::TreeMapConstructor, "TreeMap", FuncLength::ZERO));
JSHandle<JSFunction>(mapFunction)->SetFunctionPrototype(thread, mapInstanceDynclass.GetTaggedValue());
JSHandle<JSFunction>::Cast(mapFunction)->SetFunctionPrototype(thread, mapInstanceDynclass.GetTaggedValue());
// "constructor" property on the prototype
JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
@ -386,7 +399,7 @@ JSHandle<JSTaggedValue> ContainersPrivate::InitializeTreeSet(JSThread *thread)
// TreeSet() = new Function()
JSHandle<JSTaggedValue> setFunction(NewContainerConstructor(
thread, setFuncPrototype, ContainersTreeSet::TreeSetConstructor, "TreeSet", FuncLength::ZERO));
JSHandle<JSFunction>(setFunction)->SetFunctionPrototype(thread, setInstanceDynclass.GetTaggedValue());
JSHandle<JSFunction>::Cast(setFunction)->SetFunctionPrototype(thread, setInstanceDynclass.GetTaggedValue());
// "constructor" property on the prototype
JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
@ -458,8 +471,9 @@ JSHandle<JSTaggedValue> ContainersPrivate::InitializePlainArray(JSThread *thread
JSHandle<JSTaggedValue> plainArrayFunction(
NewContainerConstructor(thread, plainArrayFuncPrototype, ContainersPlainArray::PlainArrayConstructor,
"PlainArray", FuncLength::ZERO));
JSHandle<JSFunction>(plainArrayFunction)->SetFunctionPrototype(thread,
plainArrayInstanceDynclass.GetTaggedValue());
JSHandle<JSFunction>::Cast(plainArrayFunction)->SetFunctionPrototype(thread,
plainArrayInstanceDynclass.GetTaggedValue());
// "constructor" property on the prototype
JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(plainArrayFuncPrototype), constructorKey,
@ -531,7 +545,7 @@ JSHandle<JSTaggedValue> ContainersPrivate::InitializeStack(JSThread *thread)
// Stack() = new Function()
JSHandle<JSTaggedValue> stackFunction(NewContainerConstructor(
thread, stackFuncPrototype, ContainersStack::StackConstructor, "Stack", FuncLength::ZERO));
JSHandle<JSFunction>(stackFunction)->SetFunctionPrototype(thread, stackInstanceDynclass.GetTaggedValue());
JSHandle<JSFunction>::Cast(stackFunction)->SetFunctionPrototype(thread, stackInstanceDynclass.GetTaggedValue());
// "constructor" property on the prototype
JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
@ -589,7 +603,7 @@ JSHandle<JSTaggedValue> ContainersPrivate::InitializeVector(JSThread *thread)
// Vector() = new Function()
JSHandle<JSTaggedValue> vectorFunction(NewContainerConstructor(
thread, prototype, ContainersVector::VectorConstructor, "Vector", FuncLength::ZERO));
JSHandle<JSFunction>(vectorFunction)->SetFunctionPrototype(thread, vectorInstanceDynclass.GetTaggedValue());
JSHandle<JSFunction>::Cast(vectorFunction)->SetFunctionPrototype(thread, vectorInstanceDynclass.GetTaggedValue());
// "constructor" property on the prototype
JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
@ -668,7 +682,7 @@ JSHandle<JSTaggedValue> ContainersPrivate::InitializeQueue(JSThread *thread)
// Queue() = new Function()
JSHandle<JSTaggedValue> queueFunction(NewContainerConstructor(
thread, queueFuncPrototype, ContainersQueue::QueueConstructor, "Queue", FuncLength::ZERO));
JSHandle<JSFunction>(queueFunction)->SetFunctionPrototype(thread, queueInstanceDynclass.GetTaggedValue());
JSHandle<JSFunction>::Cast(queueFunction)->SetFunctionPrototype(thread, queueInstanceDynclass.GetTaggedValue());
// "constructor" property on the prototype
JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
@ -721,7 +735,7 @@ JSHandle<JSTaggedValue> ContainersPrivate::InitializeDeque(JSThread *thread)
// Deque() = new Function()
JSHandle<JSTaggedValue> dequeFunction(NewContainerConstructor(
thread, dequeFuncPrototype, ContainersDeque::DequeConstructor, "Deque", FuncLength::ZERO));
JSHandle<JSFunction>(dequeFunction)->SetFunctionPrototype(thread, dequeInstanceDynclass.GetTaggedValue());
JSHandle<JSFunction>::Cast(dequeFunction)->SetFunctionPrototype(thread, dequeInstanceDynclass.GetTaggedValue());
// "constructor" property on the prototype
JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
@ -762,4 +776,135 @@ void ContainersPrivate::InitializeDequeIterator(JSThread *thread, const JSHandle
SetStringTagSymbol(thread, env, dequeIteratorPrototype, "Deque Iterator");
globalConst->SetConstant(ConstantIndex::DEQUE_ITERATOR_PROTOTYPE_INDEX, dequeIteratorPrototype.GetTaggedValue());
}
JSHandle<JSTaggedValue> ContainersPrivate::InitializeList(JSThread *thread)
{
auto globalConst = const_cast<GlobalEnvConstants *>(thread->GlobalConstants());
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSObject> listFuncPrototype = factory->NewEmptyJSObject();
JSHandle<JSTaggedValue> listFuncPrototypeValue(listFuncPrototype);
JSHandle<JSHClass> listInstanceDynclass =
factory->NewEcmaDynClass(JSAPIList::SIZE, JSType::JS_API_LIST, listFuncPrototypeValue);
JSHandle<JSTaggedValue> listFunction(NewContainerConstructor(
thread, listFuncPrototype, ContainersList::ListConstructor, "List", FuncLength::ZERO));
JSHandle<JSFunction>::Cast(listFunction)->SetFunctionPrototype(thread, listInstanceDynclass.GetTaggedValue());
JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(listFuncPrototype), constructorKey, listFunction);
SetFrozenFunction(thread, listFuncPrototype, "add", ContainersList::Add, FuncLength::ONE);
SetFrozenFunction(thread, listFuncPrototype, "getFirst", ContainersList::GetFirst, FuncLength::ONE);
SetFrozenFunction(thread, listFuncPrototype, "getLast", ContainersList::GetLast, FuncLength::ONE);
SetFrozenFunction(thread, listFuncPrototype, "insert", ContainersList::Insert, FuncLength::ONE);
SetFrozenFunction(thread, listFuncPrototype, "clear", ContainersList::Clear, FuncLength::ONE);
SetFrozenFunction(thread, listFuncPrototype, "removeByIndex", ContainersList::RemoveByIndex, FuncLength::ONE);
SetFrozenFunction(thread, listFuncPrototype, "remove", ContainersList::Remove, FuncLength::ONE);
SetFrozenFunction(thread, listFuncPrototype, "has", ContainersList::Has, FuncLength::ONE);
SetFrozenFunction(thread, listFuncPrototype, "isEmpty", ContainersList::IsEmpty, FuncLength::ONE);
SetFrozenFunction(thread, listFuncPrototype, "get", ContainersList::Get, FuncLength::ONE);
SetFrozenFunction(thread, listFuncPrototype, "getIndexOf", ContainersList::GetIndexOf, FuncLength::ONE);
SetFrozenFunction(thread, listFuncPrototype, "getLastIndexOf", ContainersList::GetLastIndexOf, FuncLength::ONE);
SetFrozenFunction(thread, listFuncPrototype, "set", ContainersList::Set, FuncLength::ONE);
SetFrozenFunction(thread, listFuncPrototype, "forEach", ContainersList::ForEach, FuncLength::ONE);
SetFrozenFunction(thread, listFuncPrototype, "replaceAllElements", ContainersList::ReplaceAllElements,
FuncLength::ONE);
SetFrozenFunction(thread, listFuncPrototype, "equal", ContainersList::Equal, FuncLength::ONE);
SetFrozenFunction(thread, listFuncPrototype, "sort", ContainersList::Sort, FuncLength::ONE);
SetFrozenFunction(thread, listFuncPrototype, "convertToArray", ContainersList::ConvertToArray, FuncLength::ONE);
SetFrozenFunction(thread, listFuncPrototype, "getSubList", ContainersList::GetSubList, FuncLength::ONE);
JSHandle<JSTaggedValue> lengthGetter = CreateGetter(thread, ContainersList::Length, "length", FuncLength::ZERO);
JSHandle<JSTaggedValue> lengthKey(factory->NewFromASCII("length"));
SetGetter(thread, listFuncPrototype, lengthKey, lengthGetter);
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
SetFunctionAtSymbol(thread, env, listFuncPrototype, env->GetIteratorSymbol(), "[Symbol.iterator]",
ContainersList::GetIteratorObj, FuncLength::ONE);
InitializeListIterator(thread, env);
globalConst->SetConstant(ConstantIndex::LIST_FUNCTION_INDEX, listFunction.GetTaggedValue());
return listFunction;
}
JSHandle<JSTaggedValue> ContainersPrivate::InitializeLinkedList(JSThread *thread)
{
auto globalConst = const_cast<GlobalEnvConstants *>(thread->GlobalConstants());
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSObject> linkedListFuncPrototype = factory->NewEmptyJSObject();
JSHandle<JSTaggedValue> linkedListFuncPrototypeValue(linkedListFuncPrototype);
JSHandle<JSHClass> linkedListInstanceDynclass =
factory->NewEcmaDynClass(JSAPILinkedList::SIZE, JSType::JS_API_LINKED_LIST, linkedListFuncPrototypeValue);
JSHandle<JSTaggedValue> linkedListFunction(NewContainerConstructor(
thread, linkedListFuncPrototype, ContainersLinkedList::LinkedListConstructor, "LinkedList", FuncLength::ZERO));
JSHandle<JSFunction>::Cast(linkedListFunction)->SetFunctionPrototype(thread,
linkedListInstanceDynclass.GetTaggedValue());
JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(linkedListFuncPrototype), constructorKey, linkedListFunction);
SetFrozenFunction(thread, linkedListFuncPrototype, "add", ContainersLinkedList::Add, FuncLength::ONE);
SetFrozenFunction(thread, linkedListFuncPrototype, "insert", ContainersLinkedList::Insert, FuncLength::ONE);
SetFrozenFunction(thread, linkedListFuncPrototype, "clear", ContainersLinkedList::Clear, FuncLength::ONE);
SetFrozenFunction(thread, linkedListFuncPrototype, "clone", ContainersLinkedList::Clone, FuncLength::ONE);
SetFrozenFunction(thread, linkedListFuncPrototype, "removeFirst", ContainersLinkedList::RemoveFirst,
FuncLength::ONE);
SetFrozenFunction(thread, linkedListFuncPrototype, "removeLast", ContainersLinkedList::RemoveLast, FuncLength::ONE);
SetFrozenFunction(thread, linkedListFuncPrototype, "removeFirstFound", ContainersLinkedList::RemoveFirstFound,
FuncLength::ONE);
SetFrozenFunction(thread, linkedListFuncPrototype, "removeByIndex", ContainersLinkedList::RemoveByIndex,
FuncLength::ONE);
SetFrozenFunction(thread, linkedListFuncPrototype, "remove", ContainersLinkedList::Remove, FuncLength::ONE);
SetFrozenFunction(thread, linkedListFuncPrototype, "removeLastFound", ContainersLinkedList::RemoveLastFound,
FuncLength::ONE);
SetFrozenFunction(thread, linkedListFuncPrototype, "has", ContainersLinkedList::Has, FuncLength::ONE);
SetFrozenFunction(thread, linkedListFuncPrototype, "get", ContainersLinkedList::Get, FuncLength::ONE);
SetFrozenFunction(thread, linkedListFuncPrototype, "addFirst", ContainersLinkedList::AddFirst, FuncLength::ONE);
SetFrozenFunction(thread, linkedListFuncPrototype, "getFirst", ContainersLinkedList::GetFirst, FuncLength::ONE);
SetFrozenFunction(thread, linkedListFuncPrototype, "getLast", ContainersLinkedList::GetLast, FuncLength::ONE);
SetFrozenFunction(thread, linkedListFuncPrototype, "getIndexOf", ContainersLinkedList::GetIndexOf, FuncLength::ONE);
SetFrozenFunction(thread, linkedListFuncPrototype, "getLastIndexOf", ContainersLinkedList::GetLastIndexOf,
FuncLength::ONE);
SetFrozenFunction(thread, linkedListFuncPrototype, "convertToArray", ContainersLinkedList::ConvertToArray,
FuncLength::ONE);
SetFrozenFunction(thread, linkedListFuncPrototype, "set", ContainersLinkedList::Set, FuncLength::ONE);
SetFrozenFunction(thread, linkedListFuncPrototype, "forEach", ContainersLinkedList::ForEach, FuncLength::ONE);
JSHandle<JSTaggedValue> lengthGetter = CreateGetter(thread, ContainersLinkedList::Length, "length",
FuncLength::ZERO);
JSHandle<JSTaggedValue> lengthKey(factory->NewFromASCII("length"));
SetGetter(thread, linkedListFuncPrototype, lengthKey, lengthGetter);
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
SetFunctionAtSymbol(thread, env, linkedListFuncPrototype, env->GetIteratorSymbol(), "[Symbol.iterator]",
ContainersLinkedList::GetIteratorObj, FuncLength::ONE);
InitializeLinkedListIterator(thread, env);
globalConst->SetConstant(ConstantIndex::LINKED_LIST_FUNCTION_INDEX, linkedListFunction.GetTaggedValue());
return linkedListFunction;
}
void ContainersPrivate::InitializeLinkedListIterator(JSThread *thread, const JSHandle<GlobalEnv> &env)
{
auto globalConst = const_cast<GlobalEnvConstants *>(thread->GlobalConstants());
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSHClass> iteratorDynclass =
JSHandle<JSHClass>(thread, globalConst->GetHandledJSAPIIteratorFuncDynClass().GetObject<JSHClass>());
JSHandle<JSObject> setIteratorPrototype(factory->NewJSObject(iteratorDynclass));
SetFrozenFunction(thread, setIteratorPrototype, "next", JSAPILinkedListIterator::Next, FuncLength::ONE);
SetStringTagSymbol(thread, env, setIteratorPrototype, "linkedlist Iterator");
globalConst->SetConstant(ConstantIndex::LINKED_LIST_ITERATOR_PROTOTYPE_INDEX,
setIteratorPrototype.GetTaggedValue());
}
void ContainersPrivate::InitializeListIterator(JSThread *thread, const JSHandle<GlobalEnv> &env)
{
auto globalConst = const_cast<GlobalEnvConstants *>(thread->GlobalConstants());
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSHClass> iteratorDynclass =
JSHandle<JSHClass>(thread, globalConst->GetHandledJSAPIIteratorFuncDynClass().GetObject<JSHClass>());
JSHandle<JSObject> setIteratorPrototype(factory->NewJSObject(iteratorDynclass));
SetFrozenFunction(thread, setIteratorPrototype, "next", JSAPIListIterator::Next, FuncLength::ONE);
SetStringTagSymbol(thread, env, setIteratorPrototype, "list Iterator");
globalConst->SetConstant(ConstantIndex::LIST_ITERATOR_PROTOTYPE_INDEX, setIteratorPrototype.GetTaggedValue());
}
} // namespace panda::ecmascript::containers

View File

@ -87,6 +87,10 @@ private:
GlobalEnvConstants *globalConst);
static JSHandle<JSTaggedValue> InitializeStack(JSThread *thread);
static void InitializeStackIterator(JSThread *thread, GlobalEnvConstants *globalConst);
static JSHandle<JSTaggedValue> InitializeList(JSThread *thread);
static JSHandle<JSTaggedValue> InitializeLinkedList(JSThread *thread);
static void InitializeLinkedListIterator(JSThread *thread, const JSHandle<GlobalEnv> &env);
static void InitializeListIterator(JSThread *thread, const JSHandle<GlobalEnv> &env);
};
} // namespace panda::ecmascript::containers

View File

@ -23,6 +23,8 @@ host_unittest_action("ContainersTest") {
sources = [
# test file
"containers_deque_test.cpp",
"containers_linked_list_test.cpp",
"containers_list_test.cpp",
"containers_plainarray_test.cpp",
"containers_stack_test.cpp",
"containers_treemap_test.cpp",

View File

@ -0,0 +1,453 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/containers/containers_linked_list.h"
#include "ecmascript/containers/containers_private.h"
#include "ecmascript/ecma_runtime_call_info.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_api_linked_list.h"
#include "ecmascript/js_api_linked_list_iterator.h"
#include "ecmascript/js_handle.h"
#include "ecmascript/js_tagged_value-inl.h"
#include "ecmascript/js_thread.h"
#include "ecmascript/object_factory.h"
#include "ecmascript/tests/test_helper.h"
using namespace panda::ecmascript;
using namespace panda::ecmascript::containers;
namespace panda::test {
class ContainersLinkedListTest : public testing::Test {
public:
static void SetUpTestCase()
{
GTEST_LOG_(INFO) << "SetUpTestCase";
}
static void TearDownTestCase()
{
GTEST_LOG_(INFO) << "TearDownCase";
}
void SetUp() override
{
TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
}
void TearDown() override
{
TestHelper::DestroyEcmaVMWithScope(instance, scope);
}
EcmaVM *instance {nullptr};
EcmaHandleScope *scope {nullptr};
JSThread *thread {nullptr};
class TestClass : public base::BuiltinsBase {
public:
static JSTaggedValue TestForEachFunc(EcmaRuntimeCallInfo *argv)
{
JSThread *thread = argv->GetThread();
JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
JSHandle<JSTaggedValue> list = GetCallArg(argv, 2); // 2 means the secode arg
if (!list->IsUndefined()) {
if (index->IsNumber() && value->IsNumber()) {
JSHandle<JSTaggedValue> newValue(thread, JSTaggedValue(value->GetInt() * 2)); // 2 means mul by 2
JSAPILinkedList::Set(thread, JSHandle<JSAPILinkedList>::Cast(list), index->GetInt(), newValue);
}
}
return JSTaggedValue::True();
}
};
protected:
JSTaggedValue InitializeLinkedListConstructor()
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSTaggedValue> globalObject = env->GetJSGlobalObject();
JSHandle<JSTaggedValue> key(factory->NewFromASCII("ArkPrivate"));
JSHandle<JSTaggedValue> value =
JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(globalObject), key).GetValue();
auto objCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
objCallInfo->SetFunction(JSTaggedValue::Undefined());
objCallInfo->SetThis(value.GetTaggedValue());
objCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int>(ContainerTag::LinkedList)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo.get());
JSTaggedValue result = ContainersPrivate::Load(objCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
return result;
}
JSHandle<JSAPILinkedList> CreateJSAPILinkedList(JSTaggedValue compare = JSTaggedValue::Undefined())
{
JSHandle<JSTaggedValue> compareHandle(thread, compare);
JSHandle<JSFunction> newTarget(thread, InitializeLinkedListConstructor());
auto objCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
objCallInfo->SetFunction(newTarget.GetTaggedValue());
objCallInfo->SetNewTarget(newTarget.GetTaggedValue());
objCallInfo->SetThis(JSTaggedValue::Undefined());
objCallInfo->SetCallArg(0, compareHandle.GetTaggedValue());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo.get());
JSTaggedValue result = ContainersLinkedList::LinkedListConstructor(objCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
JSHandle<JSAPILinkedList> linkedlist(thread, result);
return linkedlist;
}
};
HWTEST_F_L0(ContainersLinkedListTest, LinkedListConstructor)
{
InitializeLinkedListConstructor();
JSHandle<JSFunction> newTarget(thread, InitializeLinkedListConstructor());
auto objCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
objCallInfo->SetFunction(newTarget.GetTaggedValue());
objCallInfo->SetNewTarget(newTarget.GetTaggedValue());
objCallInfo->SetThis(JSTaggedValue::Undefined());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo.get());
JSTaggedValue result = ContainersLinkedList::LinkedListConstructor(objCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_TRUE(result.IsJSAPILinkedList());
JSHandle<JSAPILinkedList> list(thread, result);
JSTaggedValue resultProto = JSTaggedValue::GetPrototype(thread, JSHandle<JSTaggedValue>(list));
JSTaggedValue funcProto = newTarget->GetFunctionPrototype();
ASSERT_EQ(resultProto, funcProto);
int size = list->Length();
ASSERT_EQ(size, 0);
}
HWTEST_F_L0(ContainersLinkedListTest, InsertAndGet)
{
constexpr uint32_t NODE_NUMBERS = 8;
JSHandle<JSAPILinkedList> linkedlist = CreateJSAPILinkedList();
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(linkedlist.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(i));
callInfo->SetCallArg(1, JSTaggedValue(i));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersLinkedList::Insert(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue::True());
EXPECT_EQ(linkedlist->Length(), static_cast<int>(i + 1));
}
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(linkedlist.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(i));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersLinkedList::Get(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue(i));
}
}
HWTEST_F_L0(ContainersLinkedListTest, Remove)
{
constexpr uint32_t NODE_NUMBERS = 20;
JSHandle<JSAPILinkedList> linkedlist = CreateJSAPILinkedList();
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(linkedlist.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(i));
callInfo->SetCallArg(1, JSTaggedValue(i));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersLinkedList::Insert(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue::True());
EXPECT_EQ(linkedlist->Length(), static_cast<int>(i + 1));
}
{
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(linkedlist.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(NODE_NUMBERS / 2));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue rvalue = ContainersLinkedList::Remove(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(rvalue, JSTaggedValue::True());
EXPECT_EQ(linkedlist->Length(), static_cast<int>(NODE_NUMBERS - 1));
}
{
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(linkedlist.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(6));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue rvalue = ContainersLinkedList::RemoveByIndex(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(rvalue, JSTaggedValue(6));
EXPECT_EQ(linkedlist->Length(), static_cast<int>(NODE_NUMBERS - 2));
}
}
HWTEST_F_L0(ContainersLinkedListTest, RemoveFirst)
{
constexpr uint32_t NODE_NUMBERS = 20;
JSHandle<JSAPILinkedList> linkedlist = CreateJSAPILinkedList();
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(linkedlist.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(i));
callInfo->SetCallArg(1, JSTaggedValue(i));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersLinkedList::Insert(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue::True());
EXPECT_EQ(linkedlist->Length(), static_cast<int>(i + 1));
}
{
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(linkedlist.GetTaggedValue());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue rvalue = ContainersLinkedList::RemoveFirst(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(rvalue, JSTaggedValue(0));
EXPECT_EQ(linkedlist->Length(), static_cast<int>(NODE_NUMBERS - 1));
}
{
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(linkedlist.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(15));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue rvalue = ContainersLinkedList::RemoveFirstFound(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(rvalue, JSTaggedValue::True());
EXPECT_EQ(linkedlist->Length(), static_cast<int>(NODE_NUMBERS - 2));
}
}
HWTEST_F_L0(ContainersLinkedListTest, RemoveLast)
{
constexpr uint32_t NODE_NUMBERS = 20;
JSHandle<JSAPILinkedList> linkedlist = CreateJSAPILinkedList();
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(linkedlist.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(i));
callInfo->SetCallArg(1, JSTaggedValue(i));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersLinkedList::Insert(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue::True());
EXPECT_EQ(linkedlist->Length(), static_cast<int>(i + 1));
}
{
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(linkedlist.GetTaggedValue());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue rvalue = ContainersLinkedList::RemoveLast(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(rvalue, JSTaggedValue(19));
EXPECT_EQ(linkedlist->Length(), static_cast<int>(NODE_NUMBERS - 1));
}
{
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(linkedlist.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(8));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue rvalue = ContainersLinkedList::RemoveLastFound(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(rvalue, JSTaggedValue::True());
EXPECT_EQ(linkedlist->Length(), static_cast<int>(NODE_NUMBERS - 2));
}
}
HWTEST_F_L0(ContainersLinkedListTest, Clear)
{
constexpr uint32_t NODE_NUMBERS = 8;
JSHandle<JSAPILinkedList> linkedlist = CreateJSAPILinkedList();
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(linkedlist.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(i));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersLinkedList::Add(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue::True());
EXPECT_EQ(linkedlist->Length(), static_cast<int>(i + 1));
}
{
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(linkedlist.GetTaggedValue());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
ContainersLinkedList::Clear(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(linkedlist->Length(), 0);
}
}
HWTEST_F_L0(ContainersLinkedListTest, Clone)
{
constexpr uint32_t NODE_NUMBERS = 8;
JSHandle<JSAPILinkedList> linkedList = CreateJSAPILinkedList();
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(linkedList.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(i));
callInfo->SetCallArg(1, JSTaggedValue(i));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersLinkedList::Add(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue::True());
EXPECT_EQ(linkedList->Length(), static_cast<int>(i + 1));
}
linkedList->Dump();
auto callInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
callInfo1->SetFunction(JSTaggedValue::Undefined());
callInfo1->SetThis(linkedList.GetTaggedValue());
JSTaggedValue newlinkedList = ContainersLinkedList::Clone(callInfo1.get());
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(newlinkedList);
callInfo->SetCallArg(0, JSTaggedValue(i));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersLinkedList::Get(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue(i));
}
}
HWTEST_F_L0(ContainersLinkedListTest, Values)
{
constexpr uint32_t NODE_NUMBERS = 8;
JSHandle<JSAPILinkedList> linkedlist = CreateJSAPILinkedList();
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(linkedlist.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(i));
callInfo->SetCallArg(1, JSTaggedValue(i));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersLinkedList::Add(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue::True());
EXPECT_EQ(linkedlist->Length(), static_cast<int>(i + 1));
}
// test values
auto callInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
callInfo1->SetFunction(JSTaggedValue::Undefined());
callInfo1->SetThis(linkedlist.GetTaggedValue());
[[maybe_unused]] auto prev1 = TestHelper::SetupFrame(thread, callInfo1.get());
JSHandle<JSTaggedValue> iterValues(thread, ContainersLinkedList::GetIteratorObj(callInfo1.get()));
TestHelper::TearDownFrame(thread, prev1);
EXPECT_TRUE(iterValues->IsJSAPILinkedListIterator());
JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined());
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(iterValues.GetTaggedValue());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
result.Update(JSAPILinkedListIterator::Next(callInfo.get()));
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(static_cast<int>(i), JSIterator::IteratorValue(thread, result)->GetInt());
}
}
HWTEST_F_L0(ContainersLinkedListTest, ForEach)
{
constexpr uint32_t NODE_NUMBERS = 8;
JSHandle<JSAPILinkedList> linkedlist = CreateJSAPILinkedList();
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(linkedlist.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(i));
callInfo->SetCallArg(1, JSTaggedValue(i));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersLinkedList::Add(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue::True());
EXPECT_EQ(linkedlist->Length(), static_cast<int>(i + 1));
}
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSAPILinkedList> newLinkedlist = CreateJSAPILinkedList();
{
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSFunction> func = factory->NewJSFunction(env, reinterpret_cast<void *>(TestClass::TestForEachFunc));
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(linkedlist.GetTaggedValue());
callInfo->SetCallArg(0, func.GetTaggedValue());
callInfo->SetCallArg(1, newLinkedlist.GetTaggedValue());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
ContainersLinkedList::ForEach(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
}
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(linkedlist.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(i));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersLinkedList::Get(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue(i * 2));
}
}
} // namespace panda::test

View File

@ -0,0 +1,461 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/containers/containers_list.h"
#include "ecmascript/containers/containers_private.h"
#include "ecmascript/ecma_runtime_call_info.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_api_list.h"
#include "ecmascript/js_api_list_iterator.h"
#include "ecmascript/js_handle.h"
#include "ecmascript/js_tagged_value-inl.h"
#include "ecmascript/js_thread.h"
#include "ecmascript/object_factory.h"
#include "ecmascript/tests/test_helper.h"
using namespace panda::ecmascript;
using namespace panda::ecmascript::containers;
namespace panda::test {
class ContainersListTest : public testing::Test {
public:
static void SetUpTestCase()
{
GTEST_LOG_(INFO) << "SetUpTestCase";
}
static void TearDownTestCase()
{
GTEST_LOG_(INFO) << "TearDownCase";
}
void SetUp() override
{
TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
}
void TearDown() override
{
TestHelper::DestroyEcmaVMWithScope(instance, scope);
}
EcmaVM *instance {nullptr};
EcmaHandleScope *scope {nullptr};
JSThread *thread {nullptr};
class TestClass : public base::BuiltinsBase {
public:
static JSTaggedValue TestForEachFunc(EcmaRuntimeCallInfo *argv)
{
JSThread *thread = argv->GetThread();
JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
JSHandle<JSTaggedValue> list = GetCallArg(argv, 2); // 2 means the secode arg
if (!list->IsUndefined()) {
if (index->IsNumber() && value->IsNumber()) {
JSHandle<JSTaggedValue> newValue(thread, JSTaggedValue(value->GetInt() * 2)); // 2 means mul by 2
JSAPIList::Set(thread, JSHandle<JSAPIList>::Cast(list), index->GetInt(), newValue);
}
}
return JSTaggedValue::True();
}
};
protected:
JSTaggedValue InitializeListConstructor()
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSTaggedValue> globalObject = env->GetJSGlobalObject();
JSHandle<JSTaggedValue> key(factory->NewFromASCII("ArkPrivate"));
JSHandle<JSTaggedValue> value =
JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(globalObject), key).GetValue();
auto objCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
objCallInfo->SetFunction(JSTaggedValue::Undefined());
objCallInfo->SetThis(value.GetTaggedValue());
objCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int>(ContainerTag::List)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo.get());
JSTaggedValue result = ContainersPrivate::Load(objCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
return result;
}
JSHandle<JSAPIList> CreateJSAPIList(JSTaggedValue compare = JSTaggedValue::Undefined())
{
JSHandle<JSTaggedValue> compareHandle(thread, compare);
JSHandle<JSFunction> newTarget(thread, InitializeListConstructor());
auto objCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
objCallInfo->SetFunction(newTarget.GetTaggedValue());
objCallInfo->SetNewTarget(newTarget.GetTaggedValue());
objCallInfo->SetThis(JSTaggedValue::Undefined());
objCallInfo->SetCallArg(0, compareHandle.GetTaggedValue());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo.get());
JSTaggedValue result = ContainersList::ListConstructor(objCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
JSHandle<JSAPIList> list(thread, result);
return list;
}
};
HWTEST_F_L0(ContainersListTest, ListConstructor)
{
InitializeListConstructor();
JSHandle<JSFunction> newTarget(thread, InitializeListConstructor());
auto objCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
objCallInfo->SetFunction(newTarget.GetTaggedValue());
objCallInfo->SetNewTarget(newTarget.GetTaggedValue());
objCallInfo->SetThis(JSTaggedValue::Undefined());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo.get());
JSTaggedValue result = ContainersList::ListConstructor(objCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_TRUE(result.IsJSAPIList());
JSHandle<JSAPIList> list(thread, result);
JSTaggedValue resultProto = JSTaggedValue::GetPrototype(thread, JSHandle<JSTaggedValue>(list));
JSTaggedValue funcProto = newTarget->GetFunctionPrototype();
ASSERT_EQ(resultProto, funcProto);
int size = list->Length();
ASSERT_EQ(size, 0);
}
HWTEST_F_L0(ContainersListTest, InsertAndGet)
{
constexpr uint32_t NODE_NUMBERS = 8;
JSHandle<JSAPIList> list = CreateJSAPIList();
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(list.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(i));
callInfo->SetCallArg(1, JSTaggedValue(i));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersList::Insert(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue::True());
EXPECT_EQ(list->Length(), static_cast<int>(i + 1));
}
{
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(list.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(20));
callInfo->SetCallArg(1, JSTaggedValue(20));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersList::Insert(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue::Exception());
}
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(list.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(i));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersList::Get(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue(i));
}
}
HWTEST_F_L0(ContainersListTest, Remove)
{
constexpr uint32_t NODE_NUMBERS = 20;
JSHandle<JSAPIList> list = CreateJSAPIList();
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(list.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(i));
callInfo->SetCallArg(1, JSTaggedValue(i));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersList::Insert(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue::True());
EXPECT_EQ(list->Length(), static_cast<int>(i + 1));
}
{
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(list.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(NODE_NUMBERS / 2));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue rvalue = ContainersList::Remove(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(rvalue, JSTaggedValue::True());
EXPECT_EQ(list->Length(), static_cast<int>(NODE_NUMBERS - 1));
}
{
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(list.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(6));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue rvalue = ContainersList::RemoveByIndex(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(rvalue, JSTaggedValue(6));
EXPECT_EQ(list->Length(), static_cast<int>(NODE_NUMBERS - 2));
}
}
HWTEST_F_L0(ContainersListTest, Equal)
{
constexpr uint32_t NODE_NUMBERS = 8;
JSHandle<JSAPIList> list = CreateJSAPIList();
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(list.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(i));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersList::Add(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue::True());
EXPECT_EQ(list->Length(), static_cast<int>(i + 1));
}
JSHandle<JSAPIList> list1 = CreateJSAPIList();
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(list1.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(i));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersList::Add(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue::True());
EXPECT_EQ(list1->Length(), static_cast<int>(i + 1));
}
{
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(list.GetTaggedValue());
callInfo->SetCallArg(0, list1.GetTaggedValue());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue res = ContainersList::Equal(callInfo.get());
EXPECT_EQ(res, JSTaggedValue::True());
TestHelper::TearDownFrame(thread, prev);
}
}
HWTEST_F_L0(ContainersListTest, GetSubList)
{
constexpr uint32_t NODE_NUMBERS = 10;
JSHandle<JSAPIList> list = CreateJSAPIList();
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(list.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(i));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersList::Add(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue::True());
EXPECT_EQ(list->Length(), static_cast<int>(i + 1));
}
{
auto callInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
callInfo1->SetFunction(JSTaggedValue::Undefined());
callInfo1->SetThis(list.GetTaggedValue());
callInfo1->SetCallArg(0, JSTaggedValue(2));
callInfo1->SetCallArg(1, JSTaggedValue(5));
[[maybe_unused]] auto prev1 = TestHelper::SetupFrame(thread, callInfo1.get());
JSTaggedValue newList = ContainersList::GetSubList(callInfo1.get());
TestHelper::TearDownFrame(thread, prev1);
EXPECT_EQ(list->Length(), 10);
for (uint32_t i = 0; i < 3; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(newList);
callInfo->SetCallArg(0, JSTaggedValue(i));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersList::Get(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue(i + 2));
}
}
}
HWTEST_F_L0(ContainersListTest, ConvertToArray)
{
constexpr uint32_t NODE_NUMBERS = 8;
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSAPIList> list = CreateJSAPIList();
JSHandle<TaggedArray> oldArray(factory->NewTaggedArray(NODE_NUMBERS, JSTaggedValue::Hole()));
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(list.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(i));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersList::Add(callInfo.get());
oldArray->Set(thread, i, JSTaggedValue(i));
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue::True());
EXPECT_EQ(list->Length(), static_cast<int>(i + 1));
}
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(list.GetTaggedValue());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue newArray = ContainersList::ConvertToArray(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
JSTaggedValue newArrayValue =
JSTaggedValue::ToObject(thread, JSHandle<JSTaggedValue>(thread, newArray))->GetElements();
JSHandle<TaggedArray> newArrayHandle(thread, newArrayValue);
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
EXPECT_EQ(newArrayHandle->Get(i), oldArray->Get(i));
}
}
HWTEST_F_L0(ContainersListTest, Clear)
{
constexpr uint32_t NODE_NUMBERS = 8;
JSHandle<JSAPIList> list = CreateJSAPIList();
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(list.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(i));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersList::Add(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue::True());
EXPECT_EQ(list->Length(), static_cast<int>(i + 1));
}
{
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(list.GetTaggedValue());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
ContainersList::Clear(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(list->Length(), 0);
}
}
HWTEST_F_L0(ContainersListTest, Values)
{
constexpr int NODE_NUMBERS = 8;
JSHandle<JSAPIList> list = CreateJSAPIList();
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(list.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(i));
callInfo->SetCallArg(1, JSTaggedValue(i));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersList::Add(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue::True());
EXPECT_EQ(list->Length(), static_cast<int>(i + 1));
}
auto callInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
callInfo1->SetFunction(JSTaggedValue::Undefined());
callInfo1->SetThis(list.GetTaggedValue());
[[maybe_unused]] auto prev1 = TestHelper::SetupFrame(thread, callInfo1.get());
JSHandle<JSTaggedValue> iterValues(thread, ContainersList::GetIteratorObj(callInfo1.get()));
TestHelper::TearDownFrame(thread, prev1);
EXPECT_TRUE(iterValues->IsJSAPIListIterator());
JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined());
for (int i = 0; i < NODE_NUMBERS; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(iterValues.GetTaggedValue());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
result.Update(JSAPIListIterator::Next(callInfo.get()));
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(i, JSIterator::IteratorValue(thread, result)->GetInt());
}
}
HWTEST_F_L0(ContainersListTest, ForEach)
{
constexpr uint32_t NODE_NUMBERS = 8;
JSHandle<JSAPIList> list = CreateJSAPIList();
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(list.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(i));
callInfo->SetCallArg(1, JSTaggedValue(i));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersList::Add(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue::True());
EXPECT_EQ(list->Length(), static_cast<int>(i + 1));
}
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSAPIList> dlist = CreateJSAPIList();
{
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSFunction> func = factory->NewJSFunction(env, reinterpret_cast<void *>(TestClass::TestForEachFunc));
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(list.GetTaggedValue());
callInfo->SetCallArg(0, func.GetTaggedValue());
callInfo->SetCallArg(1, dlist.GetTaggedValue());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
ContainersList::ForEach(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
}
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(list.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(i));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersList::Get(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue(i * 2));
}
}
} // namespace panda::test

View File

@ -161,6 +161,11 @@ std::unique_ptr<struct ProfileInfo> CpuProfiler::StopCpuProfilerForInfo()
return profileInfo;
}
void CpuProfiler::SetCpuSamplingInterval(int interval)
{
interval_ = interval;
}
void CpuProfiler::StopCpuProfilerForFile()
{
if (!isProfiling_) {
@ -273,20 +278,20 @@ void CpuProfiler::ParseMethodInfo(JSMethod *method, FrameHandler frameHandler)
staticStackInfo_.insert(std::make_pair(method, codeEntry));
} else if (method != nullptr) {
codeEntry.codeType = "JS";
const CString &functionName = method->ParseFunctionName();
const std::string &functionName = method->ParseFunctionName();
if (functionName.empty()) {
codeEntry.functionName = "anonymous";
} else {
codeEntry.functionName = functionName.c_str();
codeEntry.functionName = functionName;
}
// source file
tooling::JSPtExtractor *debugExtractor =
JSPandaFileManager::GetInstance()->GetJSPtExtractor(method->GetJSPandaFile());
const CString &sourceFile = debugExtractor->GetSourceFile(method->GetMethodId());
const std::string &sourceFile = debugExtractor->GetSourceFile(method->GetMethodId());
if (sourceFile.empty()) {
codeEntry.url = "";
} else {
codeEntry.url = sourceFile.c_str();
codeEntry.url = sourceFile;
auto iter = scriptIdMap_.find(codeEntry.url);
if (iter == scriptIdMap_.end()) {
scriptIdMap_.insert(std::make_pair(codeEntry.url, scriptIdMap_.size() + 1));

View File

@ -62,6 +62,7 @@ public:
std::unique_ptr<struct ProfileInfo> StopCpuProfilerForInfo();
void StartCpuProfilerForFile(const EcmaVM *vm, const std::string &fileName);
void StopCpuProfilerForFile();
void SetCpuSamplingInterval(int interval);
std::string GetProfileName() const;
virtual ~CpuProfiler();

View File

@ -24,7 +24,7 @@ SamplesRecord::SamplesRecord()
{
stackTopLines_.push_back(0);
struct MethodKey methodkey;
struct ProfileNode methodNode;
struct CpuProfileNode methodNode;
methodkey.method = reinterpret_cast<JSMethod*>(INT_MAX - 1);
methodMap_.insert(std::make_pair(methodkey, methodMap_.size() + 1));
methodNode.parentId = 0;
@ -46,7 +46,7 @@ void SamplesRecord::AddSample(CVector<JSMethod *> sample, uint64_t sampleTimeSta
{
static int PreviousId = 0;
struct MethodKey methodkey;
struct ProfileNode methodNode;
struct CpuProfileNode methodNode;
if (staticGcState_) {
methodkey.method = reinterpret_cast<JSMethod*>(INT_MAX);
methodNode.parentId = methodkey.parentId = PreviousId;
@ -191,7 +191,7 @@ void SamplesRecord::WriteMethodsAndSampleInfo(bool timeEnd)
std::to_string(tts) + "},\n";
}
CVector<struct ProfileNode> SamplesRecord::GetMethodNodes() const
CVector<struct CpuProfileNode> SamplesRecord::GetMethodNodes() const
{
return profileInfo_->nodes;
}

View File

@ -33,7 +33,7 @@ struct FrameInfo {
int scriptId = 0;
std::string url = "";
};
struct ProfileNode {
struct CpuProfileNode {
int id = 0;
int parentId = 0;
int hitCount = 0;
@ -43,7 +43,7 @@ struct ProfileNode {
struct ProfileInfo {
uint64_t startTime = 0;
uint64_t stopTime = 0;
CVector<struct ProfileNode> nodes;
CVector<struct CpuProfileNode> nodes;
CVector<int> samples;
CVector<int> timeDeltas;
};
@ -68,7 +68,7 @@ public:
void AddSample(CVector<JSMethod *> sample, uint64_t sampleTimeStamp, bool outToFile);
void WriteMethodsAndSampleInfo(bool timeEnd);
CVector<struct ProfileNode> GetMethodNodes() const;
CVector<struct CpuProfileNode> GetMethodNodes() const;
CDeque<struct SampleInfo> GetSamples() const;
std::string GetSampleData() const;
void SetThreadStartTime(uint64_t threadStartTime);

View File

@ -54,13 +54,14 @@ bool HeapProfiler::DumpHeapSnapshot(DumpFormat dumpFormat, Stream *stream, Progr
return jsonSerializer_->Serialize(snapshot, stream);
}
bool HeapProfiler::StartHeapTracking(double timeInterval, bool isVmMode)
bool HeapProfiler::StartHeapTracking(double timeInterval, bool isVmMode, Stream *stream)
{
HeapSnapshot *snapshot = MakeHeapSnapshot(SampleType::REAL_TIME, isVmMode);
if (snapshot == nullptr) {
return false;
}
heapTracker_ = std::make_unique<HeapTracker>(snapshot, timeInterval);
heapTracker_ = std::make_unique<HeapTracker>(snapshot, timeInterval, stream);
const_cast<EcmaVM *>(vm_)->StartHeapTracking(heapTracker_.get());
heapTracker_->StartTracing();
return true;

View File

@ -53,7 +53,7 @@ public:
void AddSnapshot(HeapSnapshot *snapshot);
bool StartHeapTracking(double timeInterval, bool isVmMode = true) override;
bool StartHeapTracking(double timeInterval, bool isVmMode = true, Stream *stream = nullptr) override;
bool StopHeapTracking(Stream *stream, Progress *progress = nullptr) override;
private:

View File

@ -35,7 +35,7 @@ public:
virtual bool DumpHeapSnapshot(DumpFormat dumpFormat, Stream *stream, Progress *progress = nullptr,
bool isVmMode = true, bool isPrivate = false) = 0;
virtual bool StartHeapTracking(double timeInterval, bool isVmMode = true) = 0;
virtual bool StartHeapTracking(double timeInterval, bool isVmMode = true, Stream *stream = nullptr) = 0;
virtual bool StopHeapTracking(Stream *stream, Progress *progress = nullptr) = 0;
NO_MOVE_SEMANTIC(HeapProfilerInterface);

View File

@ -119,15 +119,62 @@ bool HeapSnapshot::FinishSnapshot()
void HeapSnapshot::RecordSampleTime()
{
timeStamps_.emplace_back(sequenceId_);
int len = timeStamps_.size();
if (len > 0) {
if (sequenceId_ != timeStamps_[len - 1].GetLastSequenceId()) {
timeStamps_.emplace_back(sequenceId_);
}
} else {
timeStamps_.emplace_back(sequenceId_);
}
}
void HeapSnapshot::AddNode(uintptr_t address)
void HeapSnapshot::PushHeapStat(Stream* stream)
{
CVector<HeapStat> statsBuffer;
if (stream == nullptr) {
LOG(ERROR, DEBUGGER) << "HeapSnapshot::PushHeapStat::stream is nullptr";
return;
}
int preChunkSize = stream->GetSize();
uint32_t sequenceId = 0;
auto iter = nodes_.begin();
for (size_t timeIndex = 0; timeIndex < timeStamps_.size(); ++timeIndex) {
TimeStamp& timeStamp = timeStamps_[timeIndex];
sequenceId = timeStamp.GetLastSequenceId();
uint32_t nodesSize = 0;
uint32_t nodesCount = 0;
while (iter != nodes_.end() && (*iter)->GetId() <= sequenceId) {
nodesCount++;
nodesSize += (*iter)->GetSelfSize();
iter++;
}
if (((timeStamp.GetCount() != nodesCount) || (timeStamp.GetSize() != nodesSize))
&& ((nodesCount != 0) && (nodesSize != 0))) {
timeStamp.SetCount(nodesCount);
timeStamp.SetSize(nodesSize);
statsBuffer.emplace_back(static_cast<uint32_t>(timeIndex), nodesCount, nodesSize);
if (static_cast<int>(statsBuffer.size()) >= preChunkSize) {
stream->UpdateHeapStats(&statsBuffer.front(), static_cast<int>(statsBuffer.size()));
statsBuffer.clear();
}
}
}
if (!statsBuffer.empty()) {
stream->UpdateHeapStats(&statsBuffer.front(), static_cast<int>(statsBuffer.size()));
statsBuffer.clear();
}
stream->UpdateLastSeenObjectId(sequenceId);
}
void HeapSnapshot::AddNode(TaggedObject* address)
{
GenerateNode(JSTaggedValue(address));
}
void HeapSnapshot::MoveNode(uintptr_t address, uintptr_t forward_address)
void HeapSnapshot::MoveNode(uintptr_t address, TaggedObject* forward_address)
{
int sequenceId = -1;
Node *node = entryMap_.FindAndEraseNode(address);
@ -361,6 +408,10 @@ CString *HeapSnapshot::GenerateNodeName(TaggedObject *entry)
return GetString("Stack");
case JSType::JS_API_STACK_ITERATOR:
return GetString("StackIterator");
case JSType::JS_API_LIST:
return GetString("List");
case JSType::JS_API_LINKED_LIST:
return GetString("LinkedList");
case JSType::SOURCE_TEXT_MODULE_RECORD:
return GetString("SourceTextModule");
case JSType::IMPORTENTRY_RECORD:

View File

@ -29,6 +29,7 @@
#include "ecmascript/js_tagged_value.h"
#include "ecmascript/mem/c_containers.h"
#include "os/mem.h"
#include "ecmascript/tooling/interface/stream.h"
namespace panda::ecmascript {
// Define the Object Graphic
@ -196,6 +197,26 @@ public:
return timeStampUs_;
}
uint32_t GetSize() const
{
return size_;
}
void SetSize(uint32_t size)
{
size_ = size;
}
uint32_t GetCount() const
{
return count_;
}
void SetCount(uint32_t count)
{
count_ = count;
}
private:
static int64_t Now()
{
@ -207,6 +228,8 @@ private:
int lastSequenceId_ {0};
int64_t timeStampUs_ {0};
uint32_t size_ {0};
uint32_t count_ {0};
};
class HeapEntryMap {
@ -248,10 +271,11 @@ public:
void PrepareSnapshot();
void UpdateNode();
void AddNode(uintptr_t address);
void MoveNode(uintptr_t address, uintptr_t forward_address);
void AddNode(TaggedObject* address);
void MoveNode(uintptr_t address, TaggedObject* forward_address);
void RecordSampleTime();
bool FinishSnapshot();
void PushHeapStat(Stream* stream);
const CVector<TimeStamp> &GetTimeStamps() const
{

View File

@ -24,18 +24,21 @@ void HeapTrackerSample::Run()
{
while (!isInterrupt_) {
snapshot_->RecordSampleTime();
if (stream_ != nullptr) {
snapshot_->PushHeapStat(stream_);
}
usleep(timeInterval_ * MILLI_TO_MICRO);
}
}
void HeapTracker::AllocationEvent(uintptr_t address)
void HeapTracker::AllocationEvent(TaggedObject* address)
{
if (snapshot_ != nullptr) {
snapshot_->AddNode(address);
}
}
void HeapTracker::MoveEvent(uintptr_t address, uintptr_t forward_address)
void HeapTracker::MoveEvent(uintptr_t address, TaggedObject* forward_address)
{
if (snapshot_ != nullptr) {
snapshot_->MoveNode(address, forward_address);

View File

@ -21,14 +21,16 @@
#include <thread>
#include "libpandabase/macros.h"
#include "ecmascript/tooling/interface/stream.h"
#include "ecmascript/mem/tagged_object.h"
namespace panda::ecmascript {
class HeapSnapshot;
class HeapTrackerSample {
public:
explicit HeapTrackerSample(HeapSnapshot *snapshot, double timeInterval)
: timeInterval_(timeInterval), snapshot_(snapshot)
explicit HeapTrackerSample(HeapSnapshot *snapshot, double timeInterval, Stream *stream)
: timeInterval_(timeInterval), snapshot_(snapshot), stream_(stream)
{
}
@ -61,11 +63,13 @@ private:
std::atomic_bool isInterrupt_ = true;
double timeInterval_ = 0;
HeapSnapshot *snapshot_;
Stream *stream_ {nullptr};
};
class HeapTracker {
public:
HeapTracker(HeapSnapshot *snapshot, double timeInterval) : snapshot_(snapshot), sample_(snapshot, timeInterval) {}
HeapTracker(HeapSnapshot *snapshot, double timeInterval, Stream *stream)
: snapshot_(snapshot), sample_(snapshot, timeInterval, stream) {}
~HeapTracker() = default;
void StartTracing()
@ -78,8 +82,8 @@ public:
sample_.Stop();
}
void AllocationEvent(uintptr_t address);
void MoveEvent(uintptr_t address, uintptr_t forward_address);
void AllocationEvent(TaggedObject* address);
void MoveEvent(uintptr_t address, TaggedObject* forward_address);
NO_COPY_SEMANTIC(HeapTracker);
NO_MOVE_SEMANTIC(HeapTracker);

View File

@ -34,6 +34,10 @@
#include "ecmascript/js_api_arraylist_iterator.h"
#include "ecmascript/js_api_deque.h"
#include "ecmascript/js_api_deque_iterator.h"
#include "ecmascript/js_api_linked_list.h"
#include "ecmascript/js_api_linked_list_iterator.h"
#include "ecmascript/js_api_list.h"
#include "ecmascript/js_api_list_iterator.h"
#include "ecmascript/js_api_plain_array.h"
#include "ecmascript/js_api_plain_array_iterator.h"
#include "ecmascript/js_api_queue.h"
@ -93,6 +97,7 @@
#include "ecmascript/module/js_module_source_text.h"
#include "ecmascript/tagged_array.h"
#include "ecmascript/tagged_dictionary.h"
#include "ecmascript/tagged_list.h"
#include "ecmascript/tagged_tree.h"
#include "ecmascript/template_map.h"
#include "ecmascript/transitions_dictionary.h"
@ -341,6 +346,14 @@ CString JSHClass::DumpJSType(JSType type)
return "Stack";
case JSType::JS_API_STACK_ITERATOR:
return "StackIterator";
case JSType::JS_API_LIST:
return "List";
case JSType::JS_API_LIST_ITERATOR:
return "ListIterator";
case JSType::JS_API_LINKED_LIST:
return "LinkedList";
case JSType::JS_API_LINKED_LIST_ITERATOR:
return "LinkedListIterator";
default: {
CString ret = "unknown type ";
return ret + static_cast<char>(type);
@ -764,6 +777,18 @@ static void DumpObject(TaggedObject *obj, std::ostream &os)
case JSType::JS_API_STACK_ITERATOR:
JSAPIStackIterator::Cast(obj)->Dump(os);
break;
case JSType::JS_API_LIST:
JSAPIList::Cast(obj)->Dump(os);
break;
case JSType::JS_API_LIST_ITERATOR:
JSAPIListIterator::Cast(obj)->Dump(os);
break;
case JSType::JS_API_LINKED_LIST:
JSAPILinkedList::Cast(obj)->Dump(os);
break;
case JSType::JS_API_LINKED_LIST_ITERATOR:
JSAPILinkedListIterator::Cast(obj)->Dump(os);
break;
case JSType::SOURCE_TEXT_MODULE_RECORD:
SourceTextModule::Cast(obj)->Dump(os);
break;
@ -1007,6 +1032,58 @@ void LinkedHashMap::Dump(std::ostream &os) const
}
}
void TaggedDoubleList::Dump(std::ostream &os) const
{
DISALLOW_GARBAGE_COLLECTION;
int capacity = NumberOfNodes();
os << " - node num: " << std::dec << capacity << "\n";
os << " - delete node num: " << std::dec << NumberOfDeletedNodes() << "\n";
os << "head-next: ";
// 5 : 5 first element next ptr
GetElement(5).D();
os << "head-pre: ";
// 6 : 6 first element per ptr
GetElement(6).D();
os << "\n";
int i = 0;
int next = GetElement(5).GetInt();
while (capacity > i) {
os << " value: ";
GetElement(next).DumpTaggedValue(os);
os << " next: ";
// 1 : 1 current element next ptr offset
GetElement(next + 1).D();
os << " pre: ";
// 2 : 2 current element pre ptr offset
GetElement(next + 2).D();
os << "\n";
next = GetElement(next + 1).GetInt();
i++;
}
}
void TaggedSingleList::Dump(std::ostream &os) const
{
DISALLOW_GARBAGE_COLLECTION;
int capacity = NumberOfNodes();
os << "head-next: ";
// 5 : 5 first element next ptr
GetElement(5).D();
os << "\n";
int i = 0;
int next = GetElement(5).GetInt();
while (capacity > i) {
os << " value: ";
GetElement(next).DumpTaggedValue(os);
os << " next: ";
// 1 : 1 current element next ptr offset
GetElement(next + 1).D();
os << "\n";
next = GetElement(next + 1).GetInt();
i++;
}
}
void JSObject::Dump(std::ostream &os) const
{
DISALLOW_GARBAGE_COLLECTION;
@ -1561,14 +1638,14 @@ void JSArray::Dump(std::ostream &os) const
void JSAPIArrayList::Dump(std::ostream &os) const
{
os << " - length: " << std::dec << GetLength().GetArrayLength() << "\n";
os << " - length: " << std::dec << GetSize() << "\n";
JSObject::Dump(os);
}
void JSAPIArrayListIterator::Dump(std::ostream &os) const
{
JSAPIArrayList *arrayList = JSAPIArrayList::Cast(GetIteratedArrayList().GetTaggedObject());
os << " - length: " << std::dec << arrayList->GetLength().GetArrayLength() << "\n";
os << " - length: " << std::dec << arrayList->GetSize() << "\n";
os << " - nextIndex: " << std::dec << GetNextIndex() << "\n";
JSObject::Dump(os);
}
@ -1611,6 +1688,80 @@ void JSArrayIterator::Dump(std::ostream &os) const
JSObject::Dump(os);
}
void JSAPIList::Dump(std::ostream &os) const
{
TaggedSingleList *list = TaggedSingleList::Cast(GetSingleList().GetTaggedObject());
os << " - length: " << std::dec << list->GetCapacityFromTaggedArray() << "\n";
os << " - node num: " << std::dec << list->NumberOfNodes() << "\n";
os << " - delete node num: " << std::dec << list->NumberOfDeletedNodes() << "\n";
JSObject::Dump(os);
list->Dump(os);
}
void JSAPIList::DumpForSnapshot(std::vector<std::pair<CString, JSTaggedValue>> &vec) const
{
TaggedSingleList *map = TaggedSingleList::Cast(GetSingleList().GetTaggedObject());
map->DumpForSnapshot(vec);
JSObject::DumpForSnapshot(vec);
}
void JSAPIListIterator::Dump(std::ostream &os) const
{
TaggedSingleList *list = TaggedSingleList::Cast(GetIteratedList().GetTaggedObject());
os << " - length: " << std::dec << list->GetCapacityFromTaggedArray() << "\n";
os << " - node num: " << std::dec << list->NumberOfNodes() << "\n";
os << " - delete node num: " << std::dec << list->NumberOfDeletedNodes() << "\n";
os << " - nextIndex: " << std::dec << GetNextIndex() << "\n";
JSObject::Dump(os);
list->Dump(os);
}
void JSAPIListIterator::DumpForSnapshot(std::vector<std::pair<CString, JSTaggedValue>> &vec) const
{
TaggedSingleList *list = TaggedSingleList::Cast(GetIteratedList().GetTaggedObject());
list->DumpForSnapshot(vec);
vec.push_back(std::make_pair(CString("NextIndex"), JSTaggedValue(GetNextIndex())));
JSObject::DumpForSnapshot(vec);
}
void JSAPILinkedList::Dump(std::ostream &os) const
{
TaggedDoubleList *linkedList = TaggedDoubleList::Cast(GetDoubleList().GetTaggedObject());
os << " - length: " << std::dec << linkedList->GetCapacityFromTaggedArray() << "\n";
os << " - node num: " << std::dec << linkedList->NumberOfNodes() << "\n";
os << " - delete node num: " << std::dec << linkedList->NumberOfDeletedNodes() << "\n";
JSObject::Dump(os);
linkedList->Dump(os);
}
void JSAPILinkedList::DumpForSnapshot(std::vector<std::pair<CString, JSTaggedValue>> &vec) const
{
TaggedDoubleList *map = TaggedDoubleList::Cast(GetDoubleList().GetTaggedObject());
map->DumpForSnapshot(vec);
JSObject::DumpForSnapshot(vec);
}
void JSAPILinkedListIterator::Dump(std::ostream &os) const
{
TaggedDoubleList *linkedList = TaggedDoubleList::Cast(GetIteratedLinkedList().GetTaggedObject());
os << " - length: " << std::dec << linkedList->GetCapacityFromTaggedArray() << "\n";
os << " - node num: " << std::dec << linkedList->NumberOfNodes() << "\n";
os << " - delete node num: " << std::dec << linkedList->NumberOfDeletedNodes() << "\n";
os << " - nextIndex: " << std::dec << GetNextIndex() << "\n";
JSObject::Dump(os);
linkedList->Dump(os);
}
void JSAPILinkedListIterator::DumpForSnapshot(std::vector<std::pair<CString, JSTaggedValue>> &vec) const
{
TaggedDoubleList *linkedList = TaggedDoubleList::Cast(GetIteratedLinkedList().GetTaggedObject());
linkedList->DumpForSnapshot(vec);
vec.push_back(std::make_pair(CString("NextIndex"), JSTaggedValue(GetNextIndex())));
JSObject::DumpForSnapshot(vec);
}
void JSAPIQueue::Dump(std::ostream &os) const
{
os << " - length: " << std::dec << GetSize() << "\n";
@ -1766,6 +1917,8 @@ void GlobalEnv::Dump(std::ostream &os) const
GetBuiltinsFinalizationRegistryFunction().GetTaggedValue().Dump(os);
os << " - MathFunction: ";
GetMathFunction().GetTaggedValue().Dump(os);
os << " - AtomicsFunction: ";
GetAtomicsFunction().GetTaggedValue().Dump(os);
os << " - JsonFunction: ";
GetJsonFunction().GetTaggedValue().Dump(os);
os << " - StringFunction: ";
@ -1814,6 +1967,10 @@ void GlobalEnv::Dump(std::ostream &os) const
GetUnscopablesSymbol().GetTaggedValue().Dump(os);
os << " - HoleySymbol: ";
GetHoleySymbol().GetTaggedValue().Dump(os);
os << " - AttachSymbol: ";
GetAttachSymbol().GetTaggedValue().Dump(os);
os << " - DetachSymbol: ";
GetDetachSymbol().GetTaggedValue().Dump(os);
os << " - ConstructorString: ";
globalConst->GetConstructorString().Dump(os);
os << " - IteratorPrototype: ";
@ -3082,6 +3239,18 @@ static void DumpObject(TaggedObject *obj,
case JSType::JS_API_STACK_ITERATOR:
JSAPIStackIterator::Cast(obj)->DumpForSnapshot(vec);
return;
case JSType::JS_API_LIST:
JSAPIList::Cast(obj)->DumpForSnapshot(vec);
return;
case JSType::JS_API_LINKED_LIST:
JSAPILinkedList::Cast(obj)->DumpForSnapshot(vec);
return;
case JSType::JS_API_LIST_ITERATOR:
JSAPIListIterator::Cast(obj)->DumpForSnapshot(vec);
return;
case JSType::JS_API_LINKED_LIST_ITERATOR:
JSAPILinkedListIterator::Cast(obj)->DumpForSnapshot(vec);
return;
case JSType::SOURCE_TEXT_MODULE_RECORD:
SourceTextModule::Cast(obj)->DumpForSnapshot(vec);
return;
@ -3312,6 +3481,30 @@ void TaggedTreeSet::DumpForSnapshot(std::vector<std::pair<CString, JSTaggedValue
}
}
void TaggedDoubleList::DumpForSnapshot(std::vector<std::pair<CString, JSTaggedValue>> &vec) const
{
DISALLOW_GARBAGE_COLLECTION;
int capacity = NumberOfNodes();
for (int index = 0; index < capacity; index++) {
JSTaggedValue val = GetElement(index);
CString str;
KeyToStd(str, JSTaggedValue(index));
vec.push_back(std::make_pair(str, val));
}
}
void TaggedSingleList::DumpForSnapshot(std::vector<std::pair<CString, JSTaggedValue>> &vec) const
{
DISALLOW_GARBAGE_COLLECTION;
int capacity = NumberOfNodes();
for (int index = 0; index < capacity; index++) {
JSTaggedValue val = GetElement(index);
CString str;
KeyToStd(str, JSTaggedValue(index));
vec.push_back(std::make_pair(str, val));
}
}
void JSObject::DumpForSnapshot(std::vector<std::pair<CString, JSTaggedValue>> &vec) const
{
DISALLOW_GARBAGE_COLLECTION;
@ -3678,6 +3871,7 @@ void GlobalEnv::DumpForSnapshot(std::vector<std::pair<CString, JSTaggedValue>> &
vec.push_back(std::make_pair(CString("BuiltinsFinalizationRegistryFunction"),
GetBuiltinsFinalizationRegistryFunction().GetTaggedValue()));
vec.push_back(std::make_pair(CString("MathFunction"), GetMathFunction().GetTaggedValue()));
vec.push_back(std::make_pair(CString("AtomicsFunction"), GetAtomicsFunction().GetTaggedValue()));
vec.push_back(std::make_pair(CString("JsonFunction"), GetJsonFunction().GetTaggedValue()));
vec.push_back(std::make_pair(CString("StringFunction"), GetStringFunction().GetTaggedValue()));
vec.push_back(std::make_pair(CString("ProxyFunction"), GetProxyFunction().GetTaggedValue()));
@ -3702,6 +3896,8 @@ void GlobalEnv::DumpForSnapshot(std::vector<std::pair<CString, JSTaggedValue>> &
vec.push_back(std::make_pair(CString("ToPrimitiveSymbol"), GetToPrimitiveSymbol().GetTaggedValue()));
vec.push_back(std::make_pair(CString("UnscopablesSymbol"), GetUnscopablesSymbol().GetTaggedValue()));
vec.push_back(std::make_pair(CString("HoleySymbol"), GetHoleySymbol().GetTaggedValue()));
vec.push_back(std::make_pair(CString("AttachSymbol"), GetAttachSymbol().GetTaggedValue()));
vec.push_back(std::make_pair(CString("DetachSymbol"), GetDetachSymbol().GetTaggedValue()));
vec.push_back(std::make_pair(CString("ConstructorString"), globalConst->GetConstructorString()));
vec.push_back(std::make_pair(CString("IteratorPrototype"), GetIteratorPrototype().GetTaggedValue()));
vec.push_back(std::make_pair(CString("ForinIteratorPrototype"), GetForinIteratorPrototype().GetTaggedValue()));
@ -3769,6 +3965,9 @@ void GlobalEnv::DumpForSnapshot(std::vector<std::pair<CString, JSTaggedValue>> &
std::make_pair(CString("PlainArrayIteratorPrototype"), globalConst->GetPlainArrayIteratorPrototype()));
vec.push_back(std::make_pair(CString("DequeIteratorPrototype"), globalConst->GetDequeIteratorPrototype()));
vec.push_back(std::make_pair(CString("StackIteratorPrototype"), globalConst->GetStackIteratorPrototype()));
vec.push_back(std::make_pair(CString(
"LinkedListIteratorPrototype"), globalConst->GetLinkedListIteratorPrototype()));
vec.push_back(std::make_pair(CString("ListIteratorPrototype"), globalConst->GetListIteratorPrototype()));
}
void JSDataView::DumpForSnapshot(std::vector<std::pair<CString, JSTaggedValue>> &vec) const

View File

@ -189,6 +189,45 @@ void EcmaString::WriteData(char src, uint32_t start)
*(GetDataUtf16Writable() + start) = src;
}
}
} // namespace panda::ecmascript
/* static */
EcmaString *EcmaString::FastSubUtf8String(const EcmaVM *vm, const JSHandle<EcmaString> &src, uint32_t start,
uint32_t length)
{
if (length == 0) {
return *vm->GetFactory()->GetEmptyString();
}
auto string = AllocStringObject(length, true, vm);
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
Span<uint8_t> dst(string->GetDataUtf8Writable(), length);
Span<const uint8_t> source(src->GetDataUtf8() + start, length);
EcmaString::StringCopy(dst, length, source, length);
ASSERT_PRINT(CanBeCompressed(string), "canBeCompresse does not match the real value!");
return string;
}
/* static */
EcmaString *EcmaString::FastSubUtf16String(const EcmaVM *vm, const JSHandle<EcmaString> &src, uint32_t start,
uint32_t length)
{
if (length == 0) {
return *vm->GetFactory()->GetEmptyString();
}
bool canBeCompressed = CanBeCompressed(src->GetDataUtf16() + start, length);
auto string = AllocStringObject(length, canBeCompressed, vm);
if (canBeCompressed) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
CopyUtf16AsUtf8(src->GetDataUtf16() + start, string->GetDataUtf8Writable(), length);
} else {
uint32_t len = length * (sizeof(uint16_t) / sizeof(uint8_t));
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
Span<uint16_t> dst(string->GetDataUtf16Writable(), length);
Span<const uint16_t> source(src->GetDataUtf16() + start, length);
EcmaString::StringCopy(dst, len, source, len);
}
ASSERT_PRINT(canBeCompressed == CanBeCompressed(string), "canBeCompresse does not match the real value!");
return string;
}
} // namespace panda::ecmascript
#endif

View File

@ -80,35 +80,10 @@ EcmaString *EcmaString::Concat(const JSHandle<EcmaString> &str1Handle, const JSH
EcmaString *EcmaString::FastSubString(const JSHandle<EcmaString> &src, uint32_t start, uint32_t utf16Len,
const EcmaVM *vm)
{
if (utf16Len == 0) {
return vm->GetFactory()->GetEmptyString().GetObject<EcmaString>();
if (src->IsUtf8()) {
return FastSubUtf8String(vm, src, start, utf16Len);
}
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
bool canBeCompressed = src->IsUtf8() ? true : CanBeCompressed(src->GetDataUtf16() + start, utf16Len);
// allocator may trig gc and move src, need to hold it
auto string = AllocStringObject(utf16Len, canBeCompressed, vm);
if (src->IsUtf16()) {
if (canBeCompressed) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
CopyUtf16AsUtf8(src->GetDataUtf16() + start, string->GetDataUtf8Writable(), utf16Len);
} else {
uint32_t len = utf16Len * (sizeof(uint16_t) / sizeof(uint8_t));
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
Span<uint16_t> dst(string->GetDataUtf16Writable(), utf16Len);
Span<const uint16_t> source(src->GetDataUtf16() + start, utf16Len);
EcmaString::StringCopy(dst, len, source, len);
}
} else {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
Span<uint8_t> dst(string->GetDataUtf8Writable(), utf16Len);
Span<const uint8_t> source(src->GetDataUtf8() + start, utf16Len);
EcmaString::StringCopy(dst, utf16Len, source, utf16Len);
}
ASSERT_PRINT(canBeCompressed == CanBeCompressed(string), "canBeCompresse does not match the real value!");
return string;
return FastSubUtf16String(vm, src, start, utf16Len);
}
template<typename T1, typename T2>

View File

@ -314,6 +314,10 @@ public:
// Data can be stored in utf8 or utf16 form according to compressed bit.
static constexpr size_t DATA_OFFSET = SIZE; // DATA_OFFSET equal to Empty String size
static inline EcmaString *FastSubUtf8String(const EcmaVM *vm, const JSHandle<EcmaString> &src, uint32_t start,
uint32_t length);
static inline EcmaString *FastSubUtf16String(const EcmaVM *vm, const JSHandle<EcmaString> &src, uint32_t start,
uint32_t length);
private:
void SetLength(uint32_t length, bool compressed = false)
{

View File

@ -146,8 +146,8 @@ bool EcmaVM::Initialize()
JSHandle<JSHClass> globalEnvClass = factory_->NewEcmaDynClass(*dynClassClassHandle,
GlobalEnv::SIZE,
JSType::GLOBAL_ENV);
globalConst->InitRootsClass(thread_, *dynClassClassHandle);
globalConst->InitGlobalConstant(thread_);
globalConst->Init(thread_, *dynClassClassHandle);
globalConstInitialized_ = true;
JSHandle<GlobalEnv> globalEnv = factory_->NewGlobalEnv(*globalEnvClass);
globalEnv->Init(thread_);
globalEnv_ = globalEnv.GetTaggedValue();

View File

@ -24,6 +24,7 @@
#include "ecmascript/mem/c_string.h"
#include "ecmascript/mem/chunk_containers.h"
#include "ecmascript/taskpool/taskpool.h"
#include "ecmascript/waiter_list.h"
namespace panda {
class JSNApi;
@ -94,6 +95,11 @@ public:
return vmInitialized_;
}
bool IsGlobalConstInitialized() const
{
return globalConstInitialized_;
}
ObjectFactory *GetFactory() const
{
return factory_;
@ -273,6 +279,21 @@ public:
hostPromiseRejectionTracker_ = cb;
}
void SetAllowAtomicWait(bool wait)
{
AllowAtomicWait_ = wait;
}
bool GetAllowAtomicWait() const
{
return AllowAtomicWait_;
}
WaiterListNode *GetWaiterListNode()
{
return &waiterListNode_;
}
void PromiseRejectionTracker(const JSHandle<JSPromise> &promise,
const JSHandle<JSTaggedValue> &reason, PromiseRejectionEvent operation)
{
@ -335,6 +356,7 @@ private:
JSRuntimeOptions options_;
bool icEnabled_ {true};
bool vmInitialized_ {false};
bool globalConstInitialized_ {false};
GCStats *gcStats_ {nullptr};
bool snapshotSerializeEnable_ {false};
bool snapshotDeserializeEnable_ {false};
@ -383,6 +405,9 @@ private:
void* data_ {nullptr};
bool isProcessingPendingJob_ = false;
// atomics
bool AllowAtomicWait_ {true};
WaiterListNode waiterListNode_;
friend class Snapshot;
friend class SnapshotProcessor;

View File

@ -105,6 +105,17 @@ bool StubModulePackInfo::Load(EcmaVM *vm, const std::string &filename)
des_[i].GetHostCodeSecAddr(), startAddr);
}
}
for (auto &funcEntryDes : GetStubs()) {
auto codeAddr = funcEntryDes.codeAddr_; // offset
auto moduleIndex = funcEntryDes.moduleIndex_;
auto startAddr = des_[moduleIndex].GetDeviceCodeSecAddr();
auto delta = funcEntryDes.fpDeltaPrevFramSp_;
uintptr_t funAddr = startAddr + codeAddr;
kungfu::Func2FpDelta fun2fpDelta;
auto funSize = funcEntryDes.funcSize_;
fun2fpDelta[funAddr] = std::make_pair(delta, funSize);
kungfu::LLVMStackMapParser::GetInstance().CalculateFuncFpDelta(fun2fpDelta);
}
for (size_t i = 0; i < entries_.size(); i++) {
auto des = des_[entries_[i].moduleIndex_];
entries_[i].codeAddr_ += des.GetDeviceCodeSecAddr();
@ -184,6 +195,18 @@ bool AOTModulePackInfo::Load(EcmaVM *vm, const std::string &filename)
des_[i].GetHostCodeSecAddr(), startAddr);
}
}
for (auto &funcEntryDes : GetStubs()) {
auto codeAddr = funcEntryDes.codeAddr_; // offset
auto moduleIndex = funcEntryDes.moduleIndex_;
auto delta = funcEntryDes.fpDeltaPrevFramSp_;
auto funSize = funcEntryDes.funcSize_;
auto startAddr = des_[moduleIndex].GetDeviceCodeSecAddr();
uintptr_t funAddr = startAddr + codeAddr;
kungfu::Func2FpDelta fun2fpDelta;
fun2fpDelta[funAddr] = std::make_pair(delta, funSize);
kungfu::LLVMStackMapParser::GetInstance().CalculateFuncFpDelta(fun2fpDelta);
}
for (size_t i = 0; i < entries_.size(); i++) {
auto des = des_[entries_[i].moduleIndex_];
entries_[i].codeAddr_ += des.GetDeviceCodeSecAddr();
@ -262,7 +285,7 @@ void FileLoader::UpdateJSMethods(JSHandle<JSFunction> mainFunc, const JSPandaFil
auto mainEntry = GetAOTFuncEntry(fileHash, mainFuncMethodId);
// 1 : default para number
JSMethod *mainMethod = factory_->NewMethodForAOTFunction(reinterpret_cast<void *>(mainEntry), 1);
mainFunc->SetCallTarget(thread, mainMethod);
mainFunc->SetMethod(mainMethod);
mainFunc->SetCodeEntry(reinterpret_cast<uintptr_t>(mainEntry));
const CUnorderedMap<uint32_t, uint64_t> &constpoolMap = jsPandaFile->GetConstpoolMap();
@ -277,7 +300,7 @@ void FileLoader::UpdateJSMethods(JSHandle<JSFunction> mainFunc, const JSPandaFil
auto codeEntry = GetAOTFuncEntry(fileHash, it.first);
JSMethod *curMethod = factory_->NewMethodForAOTFunction(reinterpret_cast<void *>(codeEntry), 1);
auto curFunction = JSFunction::Cast(curPool->GetObjectFromCache(id).GetTaggedObject());
curFunction->SetCallTarget(thread, curMethod);
curFunction->SetMethod(curMethod);
curFunction->SetCodeEntry(reinterpret_cast<uintptr_t>(codeEntry));
}
}

View File

@ -95,6 +95,8 @@ public:
CallSignature::TargetKind kind_;
uint32_t indexInKind_;
uint32_t moduleIndex_;
int fpDeltaPrevFramSp_;
uint32_t funcSize_;
bool IsStub() const
{
return CallSignature::TargetKind::STUB_BEGIN <= kind_ && kind_ < CallSignature::TargetKind::STUB_END;
@ -154,13 +156,16 @@ public:
entryNum_ = n;
}
void AddStubEntry(CallSignature::TargetKind kind, int indexInKind, uint64_t offset, uint32_t moduleIndex)
void AddStubEntry(CallSignature::TargetKind kind, int indexInKind, uint64_t offset,
uint32_t moduleIndex, int delta, uint32_t size)
{
FuncEntryDes des;
des.kind_ = kind;
des.indexInKind_ = static_cast<uint32_t>(indexInKind);
des.codeAddr_ = offset;
des.moduleIndex_ = moduleIndex;
des.fpDeltaPrevFramSp_ = delta;
des.funcSize_ = size;
entries_.emplace_back(des);
}

View File

@ -17,7 +17,6 @@
#define ECMASCRIPT_FRAMES_H
#include "ecmascript/js_tagged_value.h"
#include "ecmascript/trampoline/asm_defines.h"
// Frame Layout
// Interpreter Frame(alias **iframe** ) Layout as follow:
@ -238,17 +237,19 @@ namespace panda::ecmascript {
enum class FrameType: uintptr_t {
OPTIMIZED_FRAME = 0,
OPTIMIZED_ENTRY_FRAME = 1,
LEAVE_FRAME = 2,
LEAVE_FRAME_WITH_ARGV = 3,
INTERPRETER_FRAME = 4,
ASM_INTERPRETER_FRAME = 5,
INTERPRETER_CONSTRUCTOR_FRAME = 6,
BUILTIN_FRAME = 7,
BUILTIN_FRAME_WITH_ARGV = 8,
BUILTIN_ENTRY_FRAME = 9,
INTERPRETER_FAST_NEW_FRAME = 10,
INTERPRETER_ENTRY_FRAME = 11,
ASM_INTERPRETER_ENTRY_FRAME = 12,
OPTIMIZED_JS_FUNCTION_FRAME = 2,
LEAVE_FRAME = 3,
LEAVE_FRAME_WITH_ARGV = 4,
INTERPRETER_FRAME = 5,
ASM_INTERPRETER_FRAME = 6,
INTERPRETER_CONSTRUCTOR_FRAME = 7,
BUILTIN_FRAME = 8,
BUILTIN_FRAME_WITH_ARGV = 9,
BUILTIN_ENTRY_FRAME = 10,
INTERPRETER_FAST_NEW_FRAME = 11,
INTERPRETER_ENTRY_FRAME = 12,
ASM_INTERPRETER_ENTRY_FRAME = 13,
OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME = 14,
INTERPRETER_BEGIN = INTERPRETER_FRAME,
INTERPRETER_END = INTERPRETER_FAST_NEW_FRAME,
@ -256,6 +257,12 @@ enum class FrameType: uintptr_t {
BUILTIN_END = BUILTIN_ENTRY_FRAME,
};
enum class ReservedSlots: int {
OPTIMIZED_RESERVED_SLOT = 1,
OPTIMIZED_JS_FUNCTION_RESERVED_SLOT = 1,
OPTIMIZED_ENTRY_RESERVED_SLOT = 2,
};
enum class JSCallMode : uintptr_t {
CALL_ARG0 = 0,
CALL_ARG1,
@ -279,9 +286,9 @@ struct OptimizedFrame : public base::AlignedStruct<base::AlignedPointer::Size(),
base::AlignedPointer> {
public:
enum class Index : size_t {
CallSiteSpIndex = 0,
TypeIndex,
TypeIndex = 0,
PrevFpIndex,
ReturnAddrIndex,
NumOfMembers
};
static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes);
@ -295,22 +302,84 @@ public:
{
return prevFp;
}
inline uintptr_t GetCallSiteSp() const
{
return callSiteSp;
}
static int32_t GetCallSiteFpToSpDelta(bool isArch32)
{
auto prevFpOffset = GetOffset<static_cast<size_t>(Index::PrevFpIndex)>(isArch32);
auto callSiteSpOffset = GetOffset<static_cast<size_t>(Index::CallSiteSpIndex)>(isArch32);
return prevFpOffset - callSiteSpOffset;
}
alignas(EAS) FrameType type {0};
alignas(EAS) JSTaggedType *prevFp {nullptr};
alignas(EAS) uintptr_t returnAddr {0};
};
STATIC_ASSERT_EQ_ARCH(sizeof(OptimizedFrame), OptimizedFrame::SizeArch32, OptimizedFrame::SizeArch64);
alignas(EAS) uintptr_t callSiteSp {0};
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
struct OptimizedJSFunctionArgConfigFrame : public base::AlignedStruct<base::AlignedPointer::Size(),
base::AlignedPointer,
base::AlignedPointer> {
public:
enum class Index : size_t {
TypeIndex = 0,
PrevFpIndex,
NumOfMembers
};
static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes);
static OptimizedJSFunctionArgConfigFrame* GetFrameFromSp(const JSTaggedType *sp)
{
return reinterpret_cast<OptimizedJSFunctionArgConfigFrame *>(reinterpret_cast<uintptr_t>(sp)
- MEMBER_OFFSET(OptimizedJSFunctionArgConfigFrame, prevFp));
}
inline JSTaggedType* GetPrevFrameFp()
{
return prevFp;
}
alignas(EAS) FrameType type {0};
alignas(EAS) JSTaggedType *prevFp {nullptr};
};
STATIC_ASSERT_EQ_ARCH(sizeof(OptimizedFrame), OptimizedFrame::SizeArch32, OptimizedFrame::SizeArch64);
STATIC_ASSERT_EQ_ARCH(sizeof(OptimizedJSFunctionArgConfigFrame),
OptimizedJSFunctionArgConfigFrame::SizeArch32, OptimizedJSFunctionArgConfigFrame::SizeArch64);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
struct OptimizedJSFunctionFrame : public base::AlignedStruct<base::AlignedPointer::Size(),
base::AlignedPointer,
base::AlignedPointer,
base::AlignedPointer> {
public:
enum class Index : size_t {
TypeIndex = 0,
PrevFpIndex,
ReturnAddrIndex,
NumOfMembers
};
static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes);
static OptimizedJSFunctionFrame* GetFrameFromSp(const JSTaggedType *sp)
{
return reinterpret_cast<OptimizedJSFunctionFrame *>(reinterpret_cast<uintptr_t>(sp)
- MEMBER_OFFSET(OptimizedJSFunctionFrame, prevFp));
}
inline JSTaggedType* GetPrevFrameFp()
{
return prevFp;
}
uintptr_t* ComputePrevFrameSp(const JSTaggedType *sp, int delta)
{
uintptr_t *preFrameSp = reinterpret_cast<uintptr_t *>(const_cast<JSTaggedType *>(sp))
+ delta / sizeof(uintptr_t);
return preFrameSp;
}
JSTaggedType* GetArgv(uintptr_t *preFrameSp)
{
return reinterpret_cast<JSTaggedType *>(preFrameSp + sizeof(uint64_t) / sizeof(uintptr_t));
}
// dynamic callee saveregisters for x86-64
alignas(EAS) FrameType type {0};
alignas(EAS) JSTaggedType *prevFp {nullptr};
alignas(EAS) uintptr_t returnAddr {0};
// dynamic callee saveregisters for arm64
// argc
// argv[0]
// argv[1]
// ... argv[n - 1]
};
STATIC_ASSERT_EQ_ARCH(sizeof(OptimizedJSFunctionFrame), OptimizedJSFunctionFrame::SizeArch32,
OptimizedJSFunctionFrame::SizeArch64);
struct OptimizedEntryFrame {
public:
@ -428,7 +497,7 @@ struct AsmInterpretedFrame : public base::AlignedStruct<JSTaggedValue::TaggedTyp
FunctionIndex = 0,
AccIndex,
EnvIndex,
CallSizeOrCallSiteSpIndex,
CallSizeIndex,
FpIndex,
PcIndex,
BaseIndex,
@ -459,7 +528,7 @@ struct AsmInterpretedFrame : public base::AlignedStruct<JSTaggedValue::TaggedTyp
static size_t GetCallSizeOffset(bool isArch32)
{
return GetOffset<static_cast<size_t>(Index::CallSizeOrCallSiteSpIndex)>(isArch32);
return GetOffset<static_cast<size_t>(Index::CallSizeIndex)>(isArch32);
}
static size_t GetFunctionOffset(bool isArch32)
@ -492,18 +561,6 @@ struct AsmInterpretedFrame : public base::AlignedStruct<JSTaggedValue::TaggedTyp
return isArch32 ? AsmInterpretedFrame::SizeArch32 : AsmInterpretedFrame::SizeArch64;
}
inline uintptr_t GetCallSiteSp() const
{
return callSizeOrCallSiteSp;
}
static int32_t GetCallSiteFpToSpDelta(bool isArch32)
{
auto fpOffset = GetSize(isArch32);
auto callSiteSpOffset = GetOffset<static_cast<size_t>(Index::CallSizeOrCallSiteSpIndex)>(isArch32);
return fpOffset - callSiteSpOffset;
}
static uint32_t NumOfMembers()
{
return sizeof(AsmInterpretedFrame) / JSTaggedValue::TaggedTypeSize();
@ -512,7 +569,7 @@ struct AsmInterpretedFrame : public base::AlignedStruct<JSTaggedValue::TaggedTyp
alignas(EAS) JSTaggedValue function {JSTaggedValue::Hole()};
alignas(EAS) JSTaggedValue acc {JSTaggedValue::Hole()};
alignas(EAS) JSTaggedValue env {JSTaggedValue::Hole()};
alignas(EAS) uintptr_t callSizeOrCallSiteSp {0};
alignas(EAS) uintptr_t callSize {0};
alignas(EAS) JSTaggedType *fp {nullptr};
alignas(EAS) const uint8_t *pc {nullptr};
alignas(EAS) InterpretedFrameBase base;
@ -698,7 +755,7 @@ struct BuiltinFrame : public base::AlignedStruct<base::AlignedPointer::Size(),
}
size_t GetNumArgs()
{
return numArgs;
return numArgs & 0xFFFFFFFF;
}
alignas(EAS) FrameType type;

View File

@ -20,7 +20,7 @@
#include "ecmascript/mem/barriers.h"
#include "ecmascript/mem/tagged_object-inl.h"
#define INVALID_OBJECT ((FreeObject *)0x06)
#define INVALID_OBJECT ((FreeObject *)NULL_POINTER)
namespace panda::ecmascript {
class FreeObject : public TaggedObject {

View File

@ -83,6 +83,7 @@ class JSThread;
V(JSTaggedValue, BuiltinsFinalizationRegistryFunction, BUILTINS_FINALIZATION_REGISTRY_FUNCTION_INDEX) \
V(JSTaggedValue, MapPrototype, MAP_PROTOTYPE_INDEX) \
V(JSTaggedValue, MathFunction, MATH_FUNCTION_INDEX) \
V(JSTaggedValue, AtomicsFunction, ATOMICS_FUNCTION_INDEX) \
V(JSTaggedValue, JsonFunction, JSON_FUNCTION_INDEX) \
V(JSTaggedValue, StringFunction, STRING_FUNCTION_INDEX) \
V(JSTaggedValue, ProxyFunction, PROXY_FUNCTION_INDEX) \
@ -149,7 +150,9 @@ class JSThread;
V(JSTaggedValue, ModuleNamespaceClass, MODULENAMESPACE_CLASS) \
V(JSTaggedValue, ObjectLiteralHClassCache, OBJECT_LITERAL_HCLASS_CACHE) \
V(JSTaggedValue, WeakRefKeepObjects, WEAK_REF_KEEP_OBJECTS) \
V(JSTaggedValue, FinRegLists, FIN_REG_LISTS)
V(JSTaggedValue, FinRegLists, FIN_REG_LISTS) \
V(JSTaggedValue, AttachSymbol, ATTACH_SYMBOL_INDEX) \
V(JSTaggedValue, DetachSymbol, DETACH_SYMBOL_INDEX)
class GlobalEnv : public TaggedObject {
public:

View File

@ -29,6 +29,8 @@
#include "ecmascript/jobs/pending_job.h"
#include "ecmascript/js_api_arraylist_iterator.h"
#include "ecmascript/js_api_deque_iterator.h"
#include "ecmascript/js_api_linked_list_iterator.h"
#include "ecmascript/js_api_list_iterator.h"
#include "ecmascript/js_api_plain_array_iterator.h"
#include "ecmascript/js_api_queue_iterator.h"
#include "ecmascript/js_api_stack_iterator.h"
@ -190,6 +192,11 @@ void GlobalEnvConstants::InitRootsClass([[maybe_unused]] JSThread *thread, JSHCl
factory->NewEcmaDynClass(dynClassClass, JSAPIArrayListIterator::SIZE, JSType::JS_API_ARRAYLIST_ITERATOR));
SetConstant(ConstantIndex::JS_API_DEQUE_ITERATOR_CLASS_INDEX,
factory->NewEcmaDynClass(dynClassClass, JSAPIDequeIterator::SIZE, JSType::JS_API_DEQUE_ITERATOR));
SetConstant(
ConstantIndex::JS_API_LINKED_LIST_ITERATOR_CLASS_INDEX,
factory->NewEcmaDynClass(dynClassClass, JSAPILinkedListIterator::SIZE, JSType::JS_API_LINKED_LIST_ITERATOR));
SetConstant(ConstantIndex::JS_API_LIST_ITERATOR_CLASS_INDEX,
factory->NewEcmaDynClass(dynClassClass, JSAPIListIterator::SIZE, JSType::JS_API_LIST_ITERATOR));
SetConstant(
ConstantIndex::JS_API_PLAIN_ARRAY_ITERATOR_CLASS_INDEX,
factory->NewEcmaDynClass(dynClassClass, JSAPIPlainArrayIterator::SIZE, JSType::JS_API_PLAIN_ARRAY_ITERATOR));
@ -246,6 +253,10 @@ void GlobalEnvConstants::InitGlobalConstant(JSThread *thread)
SetConstant(ConstantIndex::STACK_ITERATOR_PROTOTYPE_INDEX, JSTaggedValue::Undefined());
SetConstant(ConstantIndex::VECTOR_FUNCTION_INDEX, JSTaggedValue::Undefined());
SetConstant(ConstantIndex::VECTOR_ITERATOR_PROTOTYPE_INDEX, JSTaggedValue::Undefined());
SetConstant(ConstantIndex::LIST_FUNCTION_INDEX, JSTaggedValue::Undefined());
SetConstant(ConstantIndex::LINKED_LIST_FUNCTION_INDEX, JSTaggedValue::Undefined());
SetConstant(ConstantIndex::LIST_ITERATOR_PROTOTYPE_INDEX, JSTaggedValue::Undefined());
SetConstant(ConstantIndex::LINKED_LIST_ITERATOR_PROTOTYPE_INDEX, JSTaggedValue::Undefined());
/* SymbolTable *RegisterSymbols */
SetConstant(ConstantIndex::NAME_STRING_INDEX, factory->NewFromASCIINonMovable("name"));
SetConstant(ConstantIndex::GETPROTOTYPEOF_STRING_INDEX, factory->NewFromASCIINonMovable("getPrototypeOf"));
@ -496,6 +507,9 @@ void GlobalEnvConstants::InitGlobalConstant(JSThread *thread)
SetConstant(ConstantIndex::BACKSLASH_INDEX, factory->NewFromASCIINonMovable("/"));
SetConstant(ConstantIndex::SPACE_INDEX, factory->NewFromASCIINonMovable(" "));
SetConstant(ConstantIndex::NAN_INDEX, factory->NewFromASCIINonMovable("NaN"));
SetConstant(ConstantIndex::NOT_EQUAL_INDEX, factory->NewFromASCIINonMovable("not-equal"));
SetConstant(ConstantIndex::OK_INDEX, factory->NewFromASCIINonMovable("ok"));
SetConstant(ConstantIndex::TIMEOUT_INDEX, factory->NewFromASCIINonMovable("timed-out"));
auto accessor = factory->NewInternalAccessor(reinterpret_cast<void *>(JSFunction::PrototypeSetter),
reinterpret_cast<void *>(JSFunction::PrototypeGetter));

View File

@ -85,6 +85,8 @@ class JSThread;
V(JSTaggedValue, JSAPIArrayListIteratorClass, JS_API_ARRAYLIST_ITERATOR_CLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, JSAPIDequeIteratorClass, JS_API_DEQUE_ITERATOR_CLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, JSAPIPlainArrayIteratorClass, JS_API_PLAIN_ARRAY_ITERATOR_CLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, JSAPILinkedListIteratorClass, JS_API_LINKED_LIST_ITERATOR_CLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, JSAPIListIteratorClass, JS_API_LIST_ITERATOR_CLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, JSAPIQueueIteratorClass, JS_API_QUEUE_ITERATOR_CLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, JSAPIStackIteratorClass, JS_API_STACK_ITERATOR_CLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, JSAPIVectorIteratorClass, JS_API_VECTOR_ITERATOR_CLASS_INDEX, ecma_roots_class) \
@ -125,6 +127,10 @@ class JSThread;
V(JSTaggedValue, PlainArrayFunction, PLAIN_ARRAY_FUNCTION_INDEX, PlainArrayFunction) \
V(JSTaggedValue, DequeIteratorPrototype, DEQUE_ITERATOR_PROTOTYPE_INDEX, DequeIterator) \
V(JSTaggedValue, StackIteratorPrototype, STACK_ITERATOR_PROTOTYPE_INDEX, StackIterator) \
V(JSTaggedValue, ListFunction, LIST_FUNCTION_INDEX, ListFunction) \
V(JSTaggedValue, LinkedListFunction, LINKED_LIST_FUNCTION_INDEX, LinkedListFunction) \
V(JSTaggedValue, ListIteratorPrototype, LIST_ITERATOR_PROTOTYPE_INDEX, ListIterator) \
V(JSTaggedValue, LinkedListIteratorPrototype, LINKED_LIST_ITERATOR_PROTOTYPE_INDEX, LinkedListIterator) \
/* SymbolTable*RegisterSymbols */ \
V(JSTaggedValue, NameString, NAME_STRING_INDEX, name) \
V(JSTaggedValue, GetPrototypeOfString, GETPROTOTYPEOF_STRING_INDEX, getPrototypeOf) \
@ -343,6 +349,9 @@ class JSThread;
V(JSTaggedValue, ElementString, ELEMENT_INDEX, element) \
V(JSTaggedValue, FlagsString, FLAGS_INDEX, flags) \
V(JSTaggedValue, GString, G_INDEX, g) \
V(JSTaggedValue, NotEqualString, NOT_EQUAL_INDEX, notEqual) \
V(JSTaggedValue, OkString, OK_INDEX, ok) \
V(JSTaggedValue, TimeoutString, TIMEOUT_INDEX, timedout) \
V(JSTaggedValue, NfcString, NFC_INDEX, nfc) \
V(JSTaggedValue, EntriesString, ENTRIES_INDEX, entries) \
V(JSTaggedValue, LeftSquareBracketString, LEFT_SQUARE_BRACKET_INDEX, leftsquarebracket) \

View File

@ -135,7 +135,7 @@ void ICRuntime::TraceIC([[maybe_unused]] JSHandle<JSTaggedValue> receiver,
JSTaggedValue LoadICRuntime::LoadMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key)
{
if (receiver->IsTypedArray() || !receiver->IsJSObject()) {
if (receiver->IsTypedArray() || !receiver->IsJSObject() || receiver->IsSpecialContainer()) {
return JSTaggedValue::GetProperty(thread_, receiver, key).GetValue().GetTaggedValue();
}

View File

@ -23,6 +23,8 @@
#include "ecmascript/interpreter/interpreter.h"
#include "ecmascript/js_api_arraylist.h"
#include "ecmascript/js_api_deque.h"
#include "ecmascript/js_api_linked_list.h"
#include "ecmascript/js_api_list.h"
#include "ecmascript/js_api_plain_array.h"
#include "ecmascript/js_api_queue.h"
#include "ecmascript/js_api_stack.h"
@ -1411,6 +1413,14 @@ JSTaggedValue FastRuntimeStub::GetContainerProperty(JSThread *thread, JSTaggedVa
res = JSAPIVector::Get(thread, JSHandle<JSAPIVector>::Cast(self), index);
break;
}
case JSType::JS_API_LIST: {
res = JSAPIList::Cast(receiver.GetTaggedObject())->Get(index);
break;
}
case JSType::JS_API_LINKED_LIST: {
res = JSAPILinkedList::Cast(receiver.GetTaggedObject())->Get(index);
break;
}
default:
break;
}
@ -1428,9 +1438,11 @@ JSTaggedValue FastRuntimeStub::SetContainerProperty(JSThread *thread, JSTaggedVa
case JSType::JS_API_QUEUE:
res = JSAPIQueue::Cast(receiver.GetTaggedObject())->Set(thread, index, value);
break;
case JSType::JS_API_PLAIN_ARRAY:
res = JSAPIPlainArray::Set(thread, JSHandle<JSAPIPlainArray> (thread, receiver), index, value);
case JSType::JS_API_PLAIN_ARRAY: {
JSHandle<JSAPIPlainArray> plainArray(thread, receiver);
res = JSAPIPlainArray::Set(thread, plainArray, index, value);
break;
}
case JSType::JS_API_DEQUE:
res = JSAPIDeque::Cast(receiver.GetTaggedObject())->Set(thread, index, value);
break;
@ -1440,6 +1452,16 @@ JSTaggedValue FastRuntimeStub::SetContainerProperty(JSThread *thread, JSTaggedVa
case JSType::JS_API_VECTOR:
res = JSAPIVector::Cast(receiver.GetTaggedObject())->Set(thread, index, value);
break;
case JSType::JS_API_LIST: {
JSHandle<JSAPIList> singleList(thread, receiver);
res = JSAPIList::Set(thread, singleList, index, JSHandle<JSTaggedValue>(thread, value));
break;
}
case JSType::JS_API_LINKED_LIST: {
JSHandle<JSAPILinkedList> doubleList(thread, receiver);
res = JSAPILinkedList::Set(thread, doubleList, index, JSHandle<JSTaggedValue>(thread, value));
break;
}
default:
break;
}

View File

@ -33,6 +33,16 @@ void FrameHandler::PrevFrame()
sp_ = frame->GetPrevFrameFp();
break;
}
case FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME: {
auto frame = OptimizedJSFunctionArgConfigFrame::GetFrameFromSp(sp_);
sp_ = frame->GetPrevFrameFp();
break;
}
case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: {
auto frame = OptimizedJSFunctionFrame::GetFrameFromSp(sp_);
sp_ = frame->GetPrevFrameFp();
break;
}
case FrameType::OPTIMIZED_ENTRY_FRAME: {
auto frame = OptimizedEntryFrame::GetFrameFromSp(sp_);
sp_ = frame->GetPrevFrameFp();
@ -41,13 +51,9 @@ void FrameHandler::PrevFrame()
case FrameType::ASM_INTERPRETER_FRAME: {
auto frame = AsmInterpretedFrame::GetFrameFromSp(sp_);
sp_ = frame->GetPrevFrameFp();
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
if (thread_->IsAsmInterpreter() &&
sp_ != nullptr &&
GetFrameType() != FrameType::ASM_INTERPRETER_ENTRY_FRAME) {
if (thread_->IsAsmInterpreter()) {
fp_ = frame->GetCurrentFramePointer();
}
#endif
break;
}
case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
@ -99,7 +105,7 @@ void FrameHandler::PrevFrame()
}
}
uintptr_t FrameHandler::GetPrevFrameCallSiteSp(const JSTaggedType *sp)
uintptr_t FrameHandler::GetPrevFrameCallSiteSp(const JSTaggedType *sp, uintptr_t curPc)
{
if (sp == nullptr) {
return 0U;
@ -123,11 +129,11 @@ uintptr_t FrameHandler::GetPrevFrameCallSiteSp(const JSTaggedType *sp)
auto frame = BuiltinFrame::GetFrameFromSp(sp);
return frame->GetCallSiteSp();
}
case FrameType::OPTIMIZED_FRAME: {
auto frame = OptimizedFrame::GetFrameFromSp(sp);
sp = frame->GetPrevFrameFp();
type = GetFrameType(sp);
break;
case FrameType::OPTIMIZED_FRAME:
case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: {
auto callSiteSp = reinterpret_cast<uintptr_t>(sp) +
kungfu::LLVMStackMapParser::GetInstance().GetFuncFpDelta(curPc);
return callSiteSp;
}
case FrameType::BUILTIN_ENTRY_FRAME:
case FrameType::ASM_INTERPRETER_FRAME:
@ -142,14 +148,6 @@ uintptr_t FrameHandler::GetPrevFrameCallSiteSp(const JSTaggedType *sp)
UNREACHABLE();
}
}
if (type == FrameType::OPTIMIZED_FRAME) {
auto frame = OptimizedFrame::GetFrameFromSp(sp);
return frame->GetCallSiteSp();
}
auto frame = AsmInterpretedFrame::GetFrameFromSp(sp);
return frame->GetCallSiteSp();
}
ARK_INLINE void FrameHandler::AdvanceToInterpretedFrame()
@ -180,12 +178,10 @@ JSTaggedType* FrameHandler::GetPrevInterpretedFrame()
uint32_t FrameHandler::GetNumberArgs()
{
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
if (thread_->IsAsmInterpreter()) {
auto *frame = AsmInterpretedFrame::GetFrameFromSp(sp_);
return static_cast<uint32_t>(frame->GetCurrentFramePointer() - sp_);
}
#endif
ASSERT(IsInterpretedFrame());
JSTaggedType *prevSp = nullptr;
if (IsAsmInterpretedFrame()) {
@ -240,6 +236,16 @@ JSMethod *FrameHandler::GetMethod() const
return ECMAObject::Cast(function.GetTaggedObject())->GetCallTarget();
}
JSMethod *FrameHandler::CheckAndGetMethod() const
{
ASSERT(IsInterpretedFrame());
auto function = GetFunction();
if (function.IsJSFunctionBase() || function.IsJSProxy()) {
return ECMAObject::Cast(function.GetTaggedObject())->GetCallTarget();
}
return nullptr;
}
JSTaggedValue FrameHandler::GetFunction() const
{
ASSERT(IsInterpretedFrame());
@ -402,7 +408,6 @@ ARK_INLINE void FrameHandler::AsmInterpretedFrameIterate(const JSTaggedType *sp,
const RootVisitor &v0,
const RootRangeVisitor &v1) const
{
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
AsmInterpretedFrame *frame = AsmInterpretedFrame::GetFrameFromSp(sp);
uintptr_t start = ToUintPtr(sp);
uintptr_t end = ToUintPtr(frame->GetCurrentFramePointer());
@ -412,22 +417,6 @@ ARK_INLINE void FrameHandler::AsmInterpretedFrameIterate(const JSTaggedType *sp,
v0(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&frame->acc)));
v0(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&frame->env)));
}
#else
AsmInterpretedFrame *frame = AsmInterpretedFrame::GetFrameFromSp(sp);
if (frame->function == JSTaggedValue::Hole()) {
return;
}
JSTaggedType *prevSp = frame->GetPrevFrameFp();
uintptr_t start = ToUintPtr(sp);
uintptr_t end = GetInterpretedFrameEnd(prevSp);
v1(Root::ROOT_FRAME, ObjectSlot(start), ObjectSlot(end));
v0(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&frame->function)));
if (frame->pc != nullptr) {
v0(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&frame->acc)));
v0(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&frame->env)));
}
#endif // ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
}
ARK_INLINE void FrameHandler::BuiltinFrameIterate(const JSTaggedType *sp,
@ -451,7 +440,8 @@ ARK_INLINE void FrameHandler::BuiltinFrameIterate(const JSTaggedType *sp,
std::set<uintptr_t> slotAddrs;
bool ret = kungfu::LLVMStackMapParser::GetInstance().CollectStackMapSlots(
frame->returnAddr, reinterpret_cast<uintptr_t>(sp), slotAddrs, derivedPointers, isVerifying);
frame->returnAddr, reinterpret_cast<uintptr_t>(sp), slotAddrs, derivedPointers, isVerifying,
optimizedReturnAddr_);
if (!ret) {
#ifndef NDEBUG
LOG_ECMA(DEBUG) << " stackmap don't found returnAddr " << frame->returnAddr;
@ -479,7 +469,8 @@ ARK_INLINE void FrameHandler::BuiltinWithArgvFrameIterate(const JSTaggedType *sp
std::set<uintptr_t> slotAddrs;
bool ret = kungfu::LLVMStackMapParser::GetInstance().CollectStackMapSlots(
frame->returnAddr, reinterpret_cast<uintptr_t>(sp), slotAddrs, derivedPointers, isVerifying);
frame->returnAddr, reinterpret_cast<uintptr_t>(sp), slotAddrs,
derivedPointers, isVerifying, optimizedReturnAddr_);
if (!ret) {
#ifndef NDEBUG
LOG_ECMA(DEBUG) << " stackmap don't found returnAddr " << frame->returnAddr;
@ -510,10 +501,10 @@ ARK_INLINE void FrameHandler::InterpretedEntryFrameIterate(const JSTaggedType *s
}
ARK_INLINE void FrameHandler::OptimizedFrameIterate(const JSTaggedType *sp,
const RootVisitor &v0,
[[maybe_unused]] const RootRangeVisitor &v1,
ChunkMap<DerivedDataKey, uintptr_t> *derivedPointers,
bool isVerifying) const
const RootVisitor &v0,
[[maybe_unused]] const RootRangeVisitor &v1,
ChunkMap<DerivedDataKey, uintptr_t> *derivedPointers,
bool isVerifying) const
{
std::set<uintptr_t> slotAddrs;
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
@ -521,7 +512,45 @@ ARK_INLINE void FrameHandler::OptimizedFrameIterate(const JSTaggedType *sp,
reinterpret_cast<uintptr_t>(*(reinterpret_cast<uintptr_t*>(const_cast<JSTaggedType *>(sp)) + 1));
bool enableCompilerLog = thread_->GetEcmaVM()->GetJSOptions().WasSetlogCompiledMethods();
bool ret = kungfu::LLVMStackMapParser::GetInstance(enableCompilerLog).CollectStackMapSlots(
returnAddr, reinterpret_cast<uintptr_t>(sp), slotAddrs, derivedPointers, isVerifying);
returnAddr, reinterpret_cast<uintptr_t>(sp), slotAddrs, derivedPointers, isVerifying, optimizedReturnAddr_);
if (!ret) {
#ifndef NDEBUG
LOG_ECMA(DEBUG) << " stackmap don't found returnAddr " << returnAddr;
#endif
return;
}
for (const auto &slot : slotAddrs) {
v0(Root::ROOT_FRAME, ObjectSlot(slot));
}
}
ARK_INLINE void FrameHandler::OptimizedJSFunctionFrameIterate(const JSTaggedType *sp,
const RootVisitor &v0,
[[maybe_unused]] const RootRangeVisitor &v1,
ChunkMap<DerivedDataKey, uintptr_t> *derivedPointers,
bool isVerifying)
{
OptimizedJSFunctionFrame *frame = OptimizedJSFunctionFrame::GetFrameFromSp(sp);
auto currentPc = optimizedReturnAddr_;
optimizedReturnAddr_ = frame->returnAddr;
int delta = kungfu::LLVMStackMapParser::GetInstance().GetFuncFpDelta(currentPc);
uintptr_t *preFrameSp = frame->ComputePrevFrameSp(sp, delta);
auto argc = *(reinterpret_cast<uint64_t *>(preFrameSp));
JSTaggedType *argv = frame->GetArgv(preFrameSp);
if (argc > 0) {
uintptr_t start = ToUintPtr(argv); // argv
uintptr_t end = ToUintPtr(argv + argc);
v1(Root::ROOT_FRAME, ObjectSlot(start), ObjectSlot(end));
}
std::set<uintptr_t> slotAddrs;
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
auto returnAddr =
reinterpret_cast<uintptr_t>(*(reinterpret_cast<uintptr_t*>(const_cast<JSTaggedType *>(sp)) + 1));
bool enableCompilerLog = thread_->GetEcmaVM()->GetJSOptions().WasSetlogCompiledMethods();
bool ret = kungfu::LLVMStackMapParser::GetInstance(enableCompilerLog).CollectStackMapSlots(
returnAddr, reinterpret_cast<uintptr_t>(sp), slotAddrs, derivedPointers, isVerifying, optimizedReturnAddr_);
if (!ret) {
#ifndef NDEBUG
LOG_ECMA(DEBUG) << " stackmap don't found returnAddr " << returnAddr;
@ -538,14 +567,14 @@ ARK_INLINE void FrameHandler::OptimizedEntryFrameIterate(const JSTaggedType *sp,
const RootVisitor &v0,
[[maybe_unused]] const RootRangeVisitor &v1,
ChunkMap<DerivedDataKey, uintptr_t> *derivedPointers,
bool isVerifying) const
bool isVerifying)
{
std::set<uintptr_t> slotAddrs;
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
auto returnAddr = reinterpret_cast<uintptr_t>(*(reinterpret_cast<uintptr_t*>(const_cast<JSTaggedType *>(sp)) + 1));
bool enableCompilerLog = thread_->GetEcmaVM()->GetJSOptions().WasSetlogCompiledMethods();
bool ret = kungfu::LLVMStackMapParser::GetInstance(enableCompilerLog).CollectStackMapSlots(
returnAddr, reinterpret_cast<uintptr_t>(sp), slotAddrs, derivedPointers, isVerifying);
returnAddr, reinterpret_cast<uintptr_t>(sp), slotAddrs, derivedPointers, isVerifying, optimizedReturnAddr_);
if (!ret) {
#ifndef NDEBUG
LOG_ECMA(DEBUG) << " stackmap don't found returnAddr " << returnAddr;
@ -562,7 +591,7 @@ ARK_INLINE void FrameHandler::OptimizedLeaveFrameIterate(const JSTaggedType *sp,
const RootVisitor &v0,
[[maybe_unused]] const RootRangeVisitor &v1,
ChunkMap<DerivedDataKey, uintptr_t> *derivedPointers,
bool isVerifying) const
bool isVerifying)
{
OptimizedLeaveFrame *frame = OptimizedLeaveFrame::GetFrameFromSp(sp);
if (frame->argc > 0) {
@ -574,7 +603,8 @@ ARK_INLINE void FrameHandler::OptimizedLeaveFrameIterate(const JSTaggedType *sp,
std::set<uintptr_t> slotAddrs;
bool ret = kungfu::LLVMStackMapParser::GetInstance().CollectStackMapSlots(
frame->returnAddr, reinterpret_cast<uintptr_t>(sp), slotAddrs, derivedPointers, isVerifying);
frame->returnAddr, reinterpret_cast<uintptr_t>(sp), slotAddrs,
derivedPointers, isVerifying, optimizedReturnAddr_);
if (!ret) {
return;
}
@ -588,7 +618,7 @@ ARK_INLINE void FrameHandler::OptimizedWithArgvLeaveFrameIterate(const JSTaggedT
const RootVisitor &v0,
[[maybe_unused]] const RootRangeVisitor &v1,
ChunkMap<DerivedDataKey, uintptr_t> *derivedPointers,
bool isVerifying) const
bool isVerifying)
{
OptimizedLeaveFrame *frame = OptimizedLeaveFrame::GetFrameFromSp(sp);
if (frame->argc > 0) {
@ -601,7 +631,8 @@ ARK_INLINE void FrameHandler::OptimizedWithArgvLeaveFrameIterate(const JSTaggedT
std::set<uintptr_t> slotAddrs;
bool ret = kungfu::LLVMStackMapParser::GetInstance().CollectStackMapSlots(
frame->returnAddr, reinterpret_cast<uintptr_t>(sp), slotAddrs, derivedPointers, isVerifying);
frame->returnAddr, reinterpret_cast<uintptr_t>(sp), slotAddrs,
derivedPointers, isVerifying, optimizedReturnAddr_);
if (!ret) {
return;
}
@ -611,13 +642,13 @@ ARK_INLINE void FrameHandler::OptimizedWithArgvLeaveFrameIterate(const JSTaggedT
}
}
void FrameHandler::IterateRsp(const RootVisitor &v0, const RootRangeVisitor &v1) const
void FrameHandler::IterateRsp(const RootVisitor &v0, const RootRangeVisitor &v1)
{
JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetLastLeaveFrame());
IterateFrameChain(current, v0, v1);
}
void FrameHandler::IterateSp(const RootVisitor &v0, const RootRangeVisitor &v1) const
void FrameHandler::IterateSp(const RootVisitor &v0, const RootRangeVisitor &v1)
{
JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetCurrentSPFrame());
while (current) {
@ -629,15 +660,13 @@ void FrameHandler::IterateSp(const RootVisitor &v0, const RootRangeVisitor &v1)
}
}
void FrameHandler::Iterate(const RootVisitor &v0, const RootRangeVisitor &v1) const
void FrameHandler::Iterate(const RootVisitor &v0, const RootRangeVisitor &v1)
{
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
if (thread_->IsAsmInterpreter()) {
IterateSp(v0, v1);
IterateRsp(v0, v1);
return;
}
#endif
JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetCurrentSPFrame());
FrameType frameType = FrameHandler::GetFrameType(current);
if (frameType != FrameType::INTERPRETER_ENTRY_FRAME) {
@ -649,7 +678,7 @@ void FrameHandler::Iterate(const RootVisitor &v0, const RootRangeVisitor &v1) co
IterateFrameChain(current, v0, v1);
}
void FrameHandler::IterateFrameChain(JSTaggedType *start, const RootVisitor &v0, const RootRangeVisitor &v1) const
void FrameHandler::IterateFrameChain(JSTaggedType *start, const RootVisitor &v0, const RootRangeVisitor &v1)
{
ChunkMap<DerivedDataKey, uintptr_t> *derivedPointers = thread_->GetEcmaVM()->GetHeap()->GetDerivedPointers();
bool isVerifying = false;
@ -663,18 +692,36 @@ void FrameHandler::IterateFrameChain(JSTaggedType *start, const RootVisitor &v0,
switch (type) {
case FrameType::OPTIMIZED_FRAME: {
auto frame = OptimizedFrame::GetFrameFromSp(current);
auto prevFrame = frame->GetPrevFrameFp();
OptimizedFrameIterate(current, v0, v1, derivedPointers, isVerifying);
current = prevFrame;
optimizedReturnAddr_ = frame->returnAddr;
break;
}
case FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME: {
OptimizedJSFunctionFrame *frame = OptimizedJSFunctionFrame::GetFrameFromSp(current);
optimizedReturnAddr_ = frame->returnAddr;
current = frame->GetPrevFrameFp();
break;
}
case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: {
auto frame = OptimizedJSFunctionFrame::GetFrameFromSp(current);
auto prevFrame = frame->GetPrevFrameFp();
OptimizedJSFunctionFrameIterate(current, v0, v1, derivedPointers, isVerifying);
current = prevFrame;
optimizedReturnAddr_ = frame->returnAddr;
break;
}
case FrameType::OPTIMIZED_ENTRY_FRAME: {
auto frame = OptimizedEntryFrame::GetFrameFromSp(current);
current = frame->GetPrevFrameFp();
optimizedReturnAddr_ = 0;
break;
}
case FrameType::ASM_INTERPRETER_ENTRY_FRAME: {
auto frame = AsmInterpretedEntryFrame::GetFrameFromSp(current);
current = frame->GetPrevFrameFp();
optimizedReturnAddr_ = 0;
break;
}
case FrameType::ASM_INTERPRETER_FRAME:
@ -682,6 +729,7 @@ void FrameHandler::IterateFrameChain(JSTaggedType *start, const RootVisitor &v0,
auto frame = AsmInterpretedFrame::GetFrameFromSp(current);
AsmInterpretedFrameIterate(current, v0, v1);
current = frame->GetPrevFrameFp();
optimizedReturnAddr_ = 0;
break;
}
case FrameType::INTERPRETER_FRAME:
@ -689,24 +737,28 @@ void FrameHandler::IterateFrameChain(JSTaggedType *start, const RootVisitor &v0,
auto frame = InterpretedFrame::GetFrameFromSp(current);
InterpretedFrameIterate(current, v0, v1);
current = frame->GetPrevFrameFp();
optimizedReturnAddr_ = 0;
break;
}
case FrameType::LEAVE_FRAME: {
auto frame = OptimizedLeaveFrame::GetFrameFromSp(current);
OptimizedLeaveFrameIterate(current, v0, v1, derivedPointers, isVerifying);
current = frame->GetPrevFrameFp();
optimizedReturnAddr_ = frame->returnAddr;
break;
}
case FrameType::LEAVE_FRAME_WITH_ARGV: {
auto frame = OptimizedLeaveFrame::GetFrameFromSp(current);
OptimizedWithArgvLeaveFrameIterate(current, v0, v1, derivedPointers, isVerifying);
current = frame->GetPrevFrameFp();
optimizedReturnAddr_ = frame->returnAddr;
break;
}
case FrameType::BUILTIN_FRAME_WITH_ARGV: {
auto frame = BuiltinWithArgvFrame::GetFrameFromSp(current);
BuiltinWithArgvFrameIterate(current, v0, v1, derivedPointers, isVerifying);
current = frame->GetPrevFrameFp();
optimizedReturnAddr_ = frame->returnAddr;
break;
}
case FrameType::BUILTIN_ENTRY_FRAME:
@ -714,12 +766,14 @@ void FrameHandler::IterateFrameChain(JSTaggedType *start, const RootVisitor &v0,
auto frame = BuiltinFrame::GetFrameFromSp(current);
BuiltinFrameIterate(current, v0, v1, derivedPointers, isVerifying);
current = frame->GetPrevFrameFp();
optimizedReturnAddr_ = frame->returnAddr;
break;
}
case FrameType::INTERPRETER_ENTRY_FRAME: {
auto frame = InterpretedEntryFrame::GetFrameFromSp(current);
InterpretedEntryFrameIterate(current, v0, v1);
current = frame->GetPrevFrameFp();
optimizedReturnAddr_ = 0;
break;
}
default: {

View File

@ -89,11 +89,9 @@ public:
bool IsInterpretedEntryFrame() const
{
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
if (thread_->IsAsmInterpreter()) {
return (GetFrameType() == FrameType::ASM_INTERPRETER_ENTRY_FRAME);
}
#endif
return (GetFrameType() == FrameType::INTERPRETER_ENTRY_FRAME);
}
@ -117,7 +115,7 @@ public:
JSTaggedType *GetPrevInterpretedFrame();
// for llvm.
static uintptr_t GetPrevFrameCallSiteSp(const JSTaggedType *sp);
static uintptr_t GetPrevFrameCallSiteSp(const JSTaggedType *sp, uintptr_t curPc);
// for InterpretedFrame.
JSTaggedValue GetVRegValue(size_t index) const;
@ -128,6 +126,7 @@ public:
uint32_t GetNumberArgs();
uint32_t GetBytecodeOffset() const;
JSMethod *GetMethod() const;
JSMethod *CheckAndGetMethod() const;
JSTaggedValue GetFunction() const;
const uint8_t *GetPc() const;
ConstantPool *GetConstpool() const;
@ -148,10 +147,10 @@ public:
static JSTaggedType* GetInterpretedEntryFrameStart(const JSTaggedType *sp);
// for Frame GC.
void Iterate(const RootVisitor &v0, const RootRangeVisitor &v1) const;
void IterateFrameChain(JSTaggedType *start, const RootVisitor &v0, const RootRangeVisitor &v1) const;
void IterateRsp(const RootVisitor &v0, const RootRangeVisitor &v1) const;
void IterateSp(const RootVisitor &v0, const RootRangeVisitor &v1) const;
void Iterate(const RootVisitor &v0, const RootRangeVisitor &v1);
void IterateFrameChain(JSTaggedType *start, const RootVisitor &v0, const RootRangeVisitor &v1);
void IterateRsp(const RootVisitor &v0, const RootRangeVisitor &v1);
void IterateSp(const RootVisitor &v0, const RootRangeVisitor &v1);
private:
FrameType GetFrameType() const
@ -178,20 +177,24 @@ private:
void OptimizedFrameIterate(
const JSTaggedType *sp, const RootVisitor &v0, const RootRangeVisitor &v1,
ChunkMap<DerivedDataKey, uintptr_t> *derivedPointers, bool isVerifying) const;
void OptimizedJSFunctionFrameIterate(
const JSTaggedType *sp, const RootVisitor &v0, const RootRangeVisitor &v1,
ChunkMap<DerivedDataKey, uintptr_t> *derivedPointers, bool isVerifying);
void OptimizedEntryFrameIterate(
const JSTaggedType *sp, const RootVisitor &v0, const RootRangeVisitor &v1,
ChunkMap<DerivedDataKey, uintptr_t> *derivedPointers, bool isVerifying) const;
ChunkMap<DerivedDataKey, uintptr_t> *derivedPointers, bool isVerifying);
void OptimizedLeaveFrameIterate(
const JSTaggedType *sp, const RootVisitor &v0, const RootRangeVisitor &v1,
ChunkMap<DerivedDataKey, uintptr_t> *derivedPointers, bool isVerifying) const;
ChunkMap<DerivedDataKey, uintptr_t> *derivedPointers, bool isVerifying);
void OptimizedWithArgvLeaveFrameIterate(
const JSTaggedType *sp, const RootVisitor &v0, const RootRangeVisitor &v1,
ChunkMap<DerivedDataKey, uintptr_t> *derivedPointers, bool isVerifying) const;
ChunkMap<DerivedDataKey, uintptr_t> *derivedPointers, bool isVerifying);
private:
JSTaggedType *sp_ {nullptr};
JSTaggedType *fp_ {nullptr};
const JSThread *thread_ {nullptr};
uintptr_t optimizedReturnAddr_ {0};
};
class StackAssertScope {

View File

@ -446,15 +446,7 @@ JSTaggedValue EcmaInterpreter::Execute(EcmaRuntimeCallInfo *info)
JSThread *thread = info->GetThread();
INTERPRETER_TRACE(thread, Execute);
if (thread->IsAsmInterpreter()) {
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
return InterpreterAssembly::Execute(info);
#else
auto prevLeaveFrame = const_cast<JSTaggedType *>(thread->GetLastLeaveFrame());
thread->SetLastLeaveFrame(nullptr); // avoid setting again in NewRuntimeCallInfo()
JSTaggedValue asmResult = InterpreterAssembly::Execute(info);
thread->SetLastLeaveFrame(prevLeaveFrame);
return asmResult;
#endif
}
JSHandle<JSTaggedValue> func = info->GetFunction();
ECMAObject *callTarget = reinterpret_cast<ECMAObject*>(func.GetTaggedValue().GetTaggedObject());

View File

@ -44,15 +44,7 @@ EcmaRuntimeCallInfo EcmaInterpreter::NewRuntimeCallInfo(
JSTaggedType *newSp;
JSTaggedType *prevSp = sp;
if (thread->IsAsmInterpreter()) {
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
newSp = FrameHandler::GetInterpretedEntryFrameStart(sp);
#else
newSp = sp - AsmInterpretedFrame::NumOfMembers(); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
auto leaveFrame = const_cast<JSTaggedType *>(thread->GetLastLeaveFrame());
if (leaveFrame != nullptr) {
prevSp = leaveFrame;
}
#endif
} else {
newSp = sp - InterpretedFrame::NumOfMembers(); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
}

View File

@ -98,8 +98,8 @@ using panda::ecmascript::kungfu::CommonStubCSigns;
JSFunction* prevFunc = JSFunction::Cast(prevState->function.GetTaggedObject()); \
method = prevFunc->GetMethod(); \
hotnessCounter = static_cast<int32_t>(method->GetHotnessCounter()); \
ASSERT(prevState->callSizeOrCallSiteSp == GetJumpSizeAfterCall(pc)); \
DISPATCH_OFFSET(prevState->callSizeOrCallSiteSp); \
ASSERT(prevState->callSize == GetJumpSizeAfterCall(pc)); \
DISPATCH_OFFSET(prevState->callSize); \
} while (false)
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
@ -351,7 +351,7 @@ using panda::ecmascript::kungfu::CommonStubCSigns;
EcmaRuntimeCallInfo ecmaRuntimeCallInfo(thread, static_cast<size_t>(actualNumArgs), newSp); \
AsmInterpretedFrame *state = GET_ASM_FRAME(newSp); \
state->base.prev = sp; \
state->base.type = FrameType::ASM_INTERPRETER_FRAME; \
state->base.type = FrameType::ASM_INTERPRETER_FRAME; \
state->pc = nullptr; \
state->function = funcValue; \
thread->SetCurrentSPFrame(newSp); \
@ -401,10 +401,10 @@ using panda::ecmascript::kungfu::CommonStubCSigns;
INTERPRETER_GOTO_EXCEPTION_HANDLER(); \
} \
SAVE_PC(); \
GET_ASM_FRAME(sp)->callSizeOrCallSiteSp = GetJumpSizeAfterCall(pc); \
GET_ASM_FRAME(sp)->callSize = GetJumpSizeAfterCall(pc); \
AsmInterpretedFrame *state = GET_ASM_FRAME(newSp); \
state->base.prev = sp; \
state->base.type = FrameType::ASM_INTERPRETER_FRAME; \
state->base.type = FrameType::ASM_INTERPRETER_FRAME; \
pc = method->GetBytecodeArray(); /* will be stored in DISPATCH_OFFSET */ \
sp = newSp; /* for DISPATCH_OFFSET */ \
state->function = funcValue; \
@ -419,29 +419,11 @@ using panda::ecmascript::kungfu::CommonStubCSigns;
DISPATCH_OFFSET(0); \
} while (false)
extern "C" JSTaggedType JSCallEntry(uintptr_t glue, JSTaggedType *sp, const uint8_t *pc, JSTaggedValue constpool,
JSTaggedValue profileTypeInfo, JSTaggedValue acc, uint32_t hotnessCounter);
using InterpreterEntry = JSTaggedType (*)(uintptr_t glue, uint32_t argc, uintptr_t argv);
using GeneratorReEnterInterpEntry = JSTaggedType (*)(uintptr_t glue, JSTaggedType context);
// NOLINTNEXTLINE(readability-function-size)
JSTaggedType InterpreterAssembly::RunInternal(JSThread *thread, ConstantPool *constpool, const uint8_t *pc, JSTaggedType *sp)
{
// check is or not debugger
thread->CheckSwitchDebuggerBCStub();
JSTaggedValue acc = JSTaggedValue::Hole();
AsmInterpretedFrame *state = GET_ASM_FRAME(sp);
auto method = ECMAObject::Cast(state->function.GetTaggedObject())->GetCallTarget();
auto hotnessCounter = method->GetHotnessCounter();
auto profileTypeInfo = JSFunction::Cast(state->function.GetTaggedObject())->GetProfileTypeInfo();
return JSCallEntry(thread->GetGlueAddr(), sp, pc, JSTaggedValue(constpool), profileTypeInfo, acc, hotnessCounter);
}
void InterpreterAssembly::InitStackFrame(JSThread *thread)
{
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
JSTaggedType *prevSp = const_cast<JSTaggedType *>(thread->GetCurrentSPFrame());
InterpretedEntryFrame *entryState = InterpretedEntryFrame::GetFrameFromSp(prevSp);
entryState->base.type = FrameType::INTERPRETER_ENTRY_FRAME;
@ -453,15 +435,6 @@ void InterpreterAssembly::InitStackFrame(JSThread *thread)
*(--newSp) = JSTaggedValue::Undefined().GetRawData();
*(--newSp) = JSTaggedValue::Undefined().GetRawData();
*(--newSp) = JSTaggedValue::Undefined().GetRawData();
#else
uint64_t *prevSp = const_cast<uint64_t *>(thread->GetCurrentSPFrame());
AsmInterpretedFrame *state = GET_ASM_FRAME(prevSp);
state->pc = nullptr;
state->function = JSTaggedValue::Hole();
state->acc = JSTaggedValue::Hole();
state->base.type = FrameType::ASM_INTERPRETER_FRAME;
state->base.prev = nullptr;
#endif
}
JSTaggedValue InterpreterAssembly::ExecuteNative(EcmaRuntimeCallInfo *info)
@ -515,7 +488,6 @@ JSTaggedValue InterpreterAssembly::ExecuteNative(EcmaRuntimeCallInfo *info)
return tagged;
}
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
JSTaggedValue InterpreterAssembly::Execute(EcmaRuntimeCallInfo *info)
{
ASSERT(info);
@ -539,187 +511,13 @@ JSTaggedValue InterpreterAssembly::Execute(EcmaRuntimeCallInfo *info)
#endif
return JSTaggedValue(acc);
}
#else
JSTaggedValue InterpreterAssembly::Execute(EcmaRuntimeCallInfo *info)
{
JSThread *thread = info->GetThread();
ECMAObject *callTarget = reinterpret_cast<ECMAObject*>(info->GetFunctionValue().GetTaggedObject());
ASSERT(callTarget != nullptr);
JSMethod *method = callTarget->GetCallTarget();
if (method->IsNativeWithCallField()) {
return InterpreterAssembly::ExecuteNative(info);
}
// current sp is entry frame.
JSTaggedType *sp = const_cast<JSTaggedType *>(thread->GetCurrentSPFrame());
FrameHandler frameHandler(thread);
JSTaggedType *prevSp = frameHandler.GetPrevInterpretedFrame();
int32_t actualNumArgs = static_cast<int32_t>(info->GetArgsNumber());
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
JSTaggedType *newSp = sp - GET_ENTRY_FRAME_WITH_ARGS_SIZE(static_cast<uint32_t>(actualNumArgs));
if (thread->DoStackOverflowCheck(newSp - actualNumArgs - RESERVED_CALL_ARGCOUNT)) {
return JSTaggedValue::Undefined();
}
int32_t declaredNumArgs = static_cast<int32_t>(method->GetNumArgsWithCallField());
// push args
if (actualNumArgs == declaredNumArgs) {
// fast path, just push all args directly
for (int i = actualNumArgs - 1; i >= 0; i--) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
*(--newSp) = info->GetCallArgValue(i).GetRawData();
}
} else {
// slow path
if (!method->HaveExtraWithCallField()) {
// push length = declaredNumArgs, may push undefined
if (declaredNumArgs > actualNumArgs) {
CALL_PUSH_UNDEFINED(declaredNumArgs - actualNumArgs);
}
for (int32_t i = std::min(actualNumArgs, declaredNumArgs) - 1; i >= 0; i--) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
*(--newSp) = info->GetCallArgValue(i).GetRawData();
}
} else {
// push actualNumArgs in the end, then all args, may push undefined
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
*(--newSp) = JSTaggedValue(actualNumArgs).GetRawData();
if (declaredNumArgs > actualNumArgs) {
CALL_PUSH_UNDEFINED(declaredNumArgs - actualNumArgs);
}
for (int32_t i = actualNumArgs - 1; i >= 0; i--) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
*(--newSp) = info->GetCallArgValue(i).GetRawData();
}
}
}
uint64_t callField = method->GetCallField();
if ((callField & CALL_TYPE_MASK) != 0) {
// not normal call type, setting func/newTarget/this cannot be skipped
if (method->HaveThisWithCallField()) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
*(--newSp) = info->GetThisValue().GetRawData(); // push this
}
if (method->HaveNewTargetWithCallField()) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
*(--newSp) = info->GetNewTargetValue().GetRawData(); // push new target
}
if (method->HaveFuncWithCallField()) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
*(--newSp) = info->GetFunctionValue().GetRawData(); // push func
}
}
int32_t numVregs = static_cast<int32_t>(method->GetNumVregsWithCallField());
// push vregs
CALL_PUSH_UNDEFINED(numVregs);
if (UNLIKELY(thread->DoStackOverflowCheck(newSp))) {
return JSTaggedValue::Undefined();
}
const uint8_t *pc = method->GetBytecodeArray();
AsmInterpretedFrame *state = GET_ASM_FRAME(newSp);
state->pc = pc;
state->function = info->GetFunctionValue();
state->acc = JSTaggedValue::Hole();
JSHandle<JSFunction> thisFunc = JSHandle<JSFunction>::Cast(info->GetFunction());
JSTaggedValue constpool = thisFunc->GetConstantPool();
state->base.prev = sp;
state->base.type = FrameType::ASM_INTERPRETER_FRAME;
state->env = thisFunc->GetLexicalEnv();
thread->SetCurrentSPFrame(newSp);
#if ECMASCRIPT_ENABLE_ACTIVE_CPUPROFILER
CpuProfiler::IsNeedAndGetStack(thread);
#endif
thread->CheckSafepoint();
LOG(DEBUG, INTERPRETER) << "break Entry: Runtime Call " << std::hex << reinterpret_cast<uintptr_t>(newSp) << " "
<< std::hex << reinterpret_cast<uintptr_t>(pc);
auto res = InterpreterAssembly::RunInternal(thread, ConstantPool::Cast(constpool.GetTaggedObject()), pc, newSp);
// NOLINTNEXTLINE(readability-identifier-naming)
const JSTaggedValue resAcc = JSTaggedValue(res);
// pop frame
thread->SetCurrentSPFrame(prevSp);
#if ECMASCRIPT_ENABLE_ACTIVE_CPUPROFILER
CpuProfiler::IsNeedAndGetStack(thread);
#endif
return resAcc;
}
#endif
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
JSTaggedValue InterpreterAssembly::GeneratorReEnterInterpreter(JSThread *thread, JSHandle<GeneratorContext> context)
{
auto entry = thread->GetRTInterface(kungfu::RuntimeStubCSigns::ID_GeneratorReEnterAsmInterp);
auto acc = reinterpret_cast<GeneratorReEnterInterpEntry>(entry)(thread->GetGlueAddr(), context.GetTaggedType());
return JSTaggedValue(acc);
}
#else
JSTaggedValue InterpreterAssembly::GeneratorReEnterInterpreter(JSThread *thread, JSHandle<GeneratorContext> context)
{
JSHandle<JSFunction> func = JSHandle<JSFunction>::Cast(JSHandle<JSTaggedValue>(thread, context->GetMethod()));
JSMethod *method = func->GetCallTarget();
JSTaggedType *currentSp = const_cast<JSTaggedType *>(thread->GetCurrentSPFrame());
JSTaggedType *currentLeaveFrame = const_cast<JSTaggedType *>(thread->GetLastLeaveFrame());
// push break frame
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
JSTaggedType *breakSp = currentSp - AsmInterpretedFrame::NumOfMembers();
if (thread->DoStackOverflowCheck(breakSp) || thread->HasPendingException()) {
return JSTaggedValue::Exception();
}
AsmInterpretedFrame *breakState = GET_ASM_FRAME(breakSp);
breakState->pc = nullptr;
breakState->function = JSTaggedValue::Hole();
if (currentLeaveFrame == nullptr) {
// no leave frame, set frame chain as usual
breakState->base.prev = currentSp;
} else {
// set current leave frame into the frame chain
breakState->base.prev = currentLeaveFrame;
thread->SetLastLeaveFrame(nullptr);
}
breakState->base.type = FrameType::ASM_INTERPRETER_FRAME;
// create new frame and resume sp and pc
uint32_t nregs = context->GetNRegs();
size_t newFrameSize = AsmInterpretedFrame::NumOfMembers() + nregs;
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic
JSTaggedType *newSp = breakSp - newFrameSize;
if (thread->DoStackOverflowCheck(newSp) || thread->HasPendingException()) {
return JSTaggedValue::Exception();
}
JSHandle<TaggedArray> regsArray(thread, context->GetRegsArray());
for (size_t i = 0; i < nregs; i++) {
newSp[i] = regsArray->Get(i).GetRawData(); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
}
JSTaggedValue constpool = func->GetConstantPool();
uint32_t pcOffset = context->GetBCOffset();
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
const uint8_t *resumePc = method->GetBytecodeArray() + pcOffset +
BytecodeInstruction::Size(BytecodeInstruction::Format::PREF_V8_V8);
AsmInterpretedFrame *state = GET_ASM_FRAME(newSp);
state->pc = resumePc;
state->function = func.GetTaggedValue();
state->acc = context->GetAcc();
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
state->base.prev = breakSp;
state->base.type = FrameType::ASM_INTERPRETER_FRAME;
JSTaggedValue env = context->GetLexicalEnv();
state->env = env;
// execute interpreter
thread->SetCurrentSPFrame(newSp);
auto res = InterpreterAssembly::RunInternal(thread, ConstantPool::Cast(constpool.GetTaggedObject()), resumePc, newSp);
JSTaggedValue acc = JSTaggedValue(res);
// pop frame
thread->SetCurrentSPFrame(currentSp);
thread->SetLastLeaveFrame(currentLeaveFrame);
return acc;
}
#endif
void InterpreterAssembly::HandleMovV4V4(
JSThread *thread, const uint8_t *pc, JSTaggedType *sp, JSTaggedValue constpool, JSTaggedValue profileTypeInfo,
@ -2275,7 +2073,7 @@ void InterpreterAssembly::HandleNewObjDynRangePrefImm16V8(
if (IsFastNewFrameEnter(ctorFunc, ctorMethod)) {
SAVE_PC();
GET_ASM_FRAME(sp)->callSizeOrCallSiteSp = GetJumpSizeAfterCall(pc);
GET_ASM_FRAME(sp)->callSize = GetJumpSizeAfterCall(pc);
uint32_t numVregs = ctorMethod->GetNumVregsWithCallField();
uint32_t numDeclaredArgs = ctorFunc->IsBase() ?
ctorMethod->GetNumArgsWithCallField() + 1 : // +1 for this
@ -2667,8 +2465,8 @@ void InterpreterAssembly::HandleSuspendGeneratorPrefV8V8(
return;
}
ASSERT(prevState->callSizeOrCallSiteSp == GetJumpSizeAfterCall(pc));
DISPATCH_OFFSET(prevState->callSizeOrCallSiteSp);
ASSERT(prevState->callSize == GetJumpSizeAfterCall(pc));
DISPATCH_OFFSET(prevState->callSize);
}
void InterpreterAssembly::HandleAsyncFunctionAwaitUncaughtPrefV8V8(
@ -4216,18 +4014,7 @@ JSTaggedValue InterpreterAssembly::GetNewTarget(JSTaggedType *sp)
JSTaggedType *InterpreterAssembly::GetAsmInterpreterFramePointer(AsmInterpretedFrame *state)
{
JSTaggedType *fp = nullptr;
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_RSP_STACK
fp = state->GetCurrentFramePointer();
#else
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
JSTaggedType *lastFrame = state->base.prev;
// The prev frame of InterpretedFrame may entry frame or interpreter frame.
if (FrameHandler::GetFrameType(state->base.prev) == FrameType::INTERPRETER_ENTRY_FRAME) {
fp = FrameHandler::GetInterpretedEntryFrameStart(state->base.prev);
} else {
fp = lastFrame - AsmInterpretedFrame::NumOfMembers();
}
#endif
return fp;
}

View File

@ -36,7 +36,6 @@ class InterpreterAssembly {
public:
static const uint32_t METHOD_HOTNESS_THRESHOLD = 512;
enum ActualNumArgsOfCall : uint8_t { CALLARG0 = 0, CALLARG1, CALLARGS2, CALLARGS3 };
static JSTaggedType RunInternal(JSThread *thread, ConstantPool *constpool, const uint8_t *pc, JSTaggedType *sp);
static void InitStackFrame(JSThread *thread);
static JSTaggedValue Execute(EcmaRuntimeCallInfo *info);
static JSTaggedValue ExecuteNative(EcmaRuntimeCallInfo *info);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@ -117,7 +117,7 @@ JSTaggedValue JSAPIArrayList::Get(JSThread *thread, const uint32_t index)
bool JSAPIArrayList::IsEmpty(const JSHandle<JSAPIArrayList> &arrayList)
{
return arrayList->GetLength().GetArrayLength() == 0;
return arrayList->GetSize() == 0;
}
int JSAPIArrayList::GetIndexOf(JSThread *thread, const JSHandle<JSAPIArrayList> &arrayList,
@ -226,14 +226,14 @@ JSTaggedValue JSAPIArrayList::ReplaceAllElements(JSThread *thread, const JSHandl
const JSHandle<JSTaggedValue> &callbackFn,
const JSHandle<JSTaggedValue> &thisArg)
{
JSHandle<JSAPIArrayList> arraylist = JSHandle<JSAPIArrayList>::Cast(thisHandle);
uint32_t length = static_cast<uint32_t>(arraylist->GetSize());
JSHandle<JSAPIArrayList> arrayList = JSHandle<JSAPIArrayList>::Cast(thisHandle);
uint32_t length = static_cast<uint32_t>(arrayList->GetSize());
JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
const size_t argsLength = 3;
JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
for (uint32_t k = 0; k < length; k++) {
kValue.Update(arraylist->Get(thread, k));
kValue.Update(arrayList->Get(thread, k));
key.Update(JSTaggedValue(k));
EcmaRuntimeCallInfo info =
EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFn, thisArg, undefined, argsLength);
@ -241,7 +241,7 @@ JSTaggedValue JSAPIArrayList::ReplaceAllElements(JSThread *thread, const JSHandl
JSTaggedValue funcResult = JSFunction::Call(&info);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
arraylist->Set(thread, k, funcResult);
arrayList->Set(thread, k, funcResult);
}
return JSTaggedValue::Undefined();
@ -338,7 +338,7 @@ JSHandle<TaggedArray> JSAPIArrayList::GrowCapacity(const JSThread *thread, const
return newElements;
}
bool JSAPIArrayList::Has(JSTaggedValue value) const
bool JSAPIArrayList::Has(const JSTaggedValue value) const
{
TaggedArray *elements = TaggedArray::Cast(GetElements().GetTaggedObject());
int32_t length = GetSize();
@ -368,10 +368,10 @@ JSHandle<TaggedArray> JSAPIArrayList::OwnKeys(JSThread *thread, const JSHandle<J
}
bool JSAPIArrayList::GetOwnProperty(JSThread *thread, const JSHandle<JSAPIArrayList> &obj,
const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
const JSHandle<JSTaggedValue> &key)
{
uint32_t index = 0;
if (!UNLIKELY(JSTaggedValue::ToElementIndex(key.GetTaggedValue(), &index))) {
if (UNLIKELY(!JSTaggedValue::ToElementIndex(key.GetTaggedValue(), &index))) {
THROW_TYPE_ERROR_AND_RETURN(thread, "Can not obtain attributes of no-number type", false);
}
@ -379,7 +379,10 @@ bool JSAPIArrayList::GetOwnProperty(JSThread *thread, const JSHandle<JSAPIArrayL
if (index >= length) {
THROW_RANGE_ERROR_AND_RETURN(thread, "GetOwnProperty index out-of-bounds", false);
}
return JSObject::GetOwnProperty(thread, JSHandle<JSObject>::Cast(obj), key, desc);
obj->Get(thread, index);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
return true;
}
JSTaggedValue JSAPIArrayList::GetIteratorObj(JSThread *thread, const JSHandle<JSAPIArrayList> &obj)
@ -389,4 +392,17 @@ JSTaggedValue JSAPIArrayList::GetIteratorObj(JSThread *thread, const JSHandle<JS
return iter.GetTaggedValue();
}
OperationResult JSAPIArrayList::GetProperty(JSThread *thread, const JSHandle<JSAPIArrayList> &obj,
const JSHandle<JSTaggedValue> &key)
{
int length = obj->GetLength().GetInt();
int index = key->GetInt();
if (index < 0 || index >= length) {
THROW_RANGE_ERROR_AND_RETURN(thread, "GetProperty index out-of-bounds",
OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
}
return OperationResult(thread, obj->Get(thread, index), PropertyMetaData(false));
}
} // namespace panda::ecmascript

Some files were not shown because too many files have changed in this diff Show More