mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-10-07 08:03:29 +00:00
Merge remote-tracking branch 'oh/master'
This commit is contained in:
commit
c2ee264a82
26
BUILD.gn
26
BUILD.gn
@ -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
|
||||
|
140
ecmascript/base/atomic_helper.cpp
Normal file
140
ecmascript/base/atomic_helper.cpp
Normal 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
|
||||
|
104
ecmascript/base/atomic_helper.h
Normal file
104
ecmascript/base/atomic_helper.h
Normal 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
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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_);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
587
ecmascript/builtins/builtins_atomics.cpp
Normal file
587
ecmascript/builtins/builtins_atomics.cpp
Normal 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
|
94
ecmascript/builtins/builtins_atomics.h
Normal file
94
ecmascript/builtins/builtins_atomics.h
Normal 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
|
@ -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
|
||||
|
@ -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 typedArray’s [[ArrayLength]] internal slot.
|
||||
// 22. Let srcByteOffset be the value of typedArray’s [[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 O’s [[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 A’s [[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
|
||||
|
@ -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",
|
||||
|
626
ecmascript/builtins/tests/builtins_atomics_test.cpp
Normal file
626
ecmascript/builtins/tests/builtins_atomics_test.cpp
Normal 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);
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 = [
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
|
@ -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
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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_;
|
||||
|
@ -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
|
||||
|
@ -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]);
|
||||
}
|
||||
|
@ -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_ {};
|
||||
|
@ -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)
|
||||
|
@ -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, ¬NormalCallType); \
|
||||
Bind(¬NormalCallType); \
|
||||
{ \
|
||||
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(¬Exception);
|
||||
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(¬Exception);
|
||||
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(¬Exception);
|
||||
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(¬Exception);
|
||||
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(¬Exception);
|
||||
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(¬Exception);
|
||||
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
@ -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
|
||||
|
@ -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
|
@ -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;
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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());
|
||||
|
@ -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:
|
||||
|
@ -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" ]
|
||||
|
@ -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
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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};
|
||||
|
@ -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 =
|
||||
|
428
ecmascript/containers/containers_linked_list.cpp
Normal file
428
ecmascript/containers/containers_linked_list.cpp
Normal 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
|
51
ecmascript/containers/containers_linked_list.h
Normal file
51
ecmascript/containers/containers_linked_list.h
Normal 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
|
409
ecmascript/containers/containers_list.cpp
Normal file
409
ecmascript/containers/containers_list.cpp
Normal 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
|
49
ecmascript/containers/containers_list.h
Normal file
49
ecmascript/containers/containers_list.h
Normal 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
|
@ -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());
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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",
|
||||
|
453
ecmascript/containers/tests/containers_linked_list_test.cpp
Normal file
453
ecmascript/containers/tests/containers_linked_list_test.cpp
Normal 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
|
461
ecmascript/containers/tests/containers_list_test.cpp
Normal file
461
ecmascript/containers/tests/containers_list_test.cpp
Normal 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
|
@ -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));
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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:
|
||||
|
@ -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));
|
||||
|
@ -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) \
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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: {
|
||||
|
@ -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 {
|
||||
|
@ -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());
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user