* Copyright (c) 2025 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 <cstddef>
#include "assembler/assembly-emitter.h"
#include "assembler/assembly-parser.h"
#include "ecmascript/builtins/builtins.h"
#include "ecmascript/builtins/builtins_function.h"
#include "ecmascript/builtins/builtins_object.h"
#include "ecmascript/compiler/aot_file/an_file_data_manager.h"
#include "ecmascript/compiler/aot_file/aot_file_manager.h"
#include "ecmascript/compiler/circuit_builder_helper.h"
#include "ecmascript/deoptimizer/deoptimizer.h"
#include "ecmascript/ecma_global_storage.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_api/js_api_tree_map.h"
#include "ecmascript/js_api/js_api_tree_set.h"
#include "ecmascript/js_api/js_api_vector.h"
#include "ecmascript/js_array.h"
#include "ecmascript/js_bigint.h"
#include "ecmascript/js_date_time_format.h"
#include "ecmascript/js_generator_object.h"
#include "ecmascript/js_map.h"
#include "ecmascript/js_map_iterator.h"
#include "ecmascript/js_primitive_ref.h"
#include "ecmascript/js_regexp.h"
#include "ecmascript/js_runtime_options.h"
#include "ecmascript/js_set.h"
#include "ecmascript/js_set_iterator.h"
#include "ecmascript/js_proxy.h"
#include "ecmascript/js_tagged_value.h"
#include "ecmascript/js_thread.h"
#include "ecmascript/js_weak_container.h"
#include "ecmascript/ic/ic_info.h"
#include "ecmascript/ic/profile_type_info.h"
#include "ecmascript/linked_hash_table.h"
#include "ecmascript/mem/mem_map_allocator.h"
#include "ecmascript/jspandafile/js_pandafile.h"
#include "ecmascript/jspandafile/js_pandafile_manager.h"
#include "ecmascript/module/js_module_manager.h"
#include "ecmascript/module/js_module_source_text.h"
#include "ecmascript/module/module_path_helper.h"
#include "ecmascript/napi/include/jsnapi.h"
#include "ecmascript/napi/include/jsnapi_internals.h"
#include "ecmascript/napi/jsnapi_helper.h"
#include "ecmascript/object_factory.h"
#include "ecmascript/pgo_profiler/pgo_profiler.h"
#include "ecmascript/pgo_profiler/pgo_profiler_decoder.h"
#include "ecmascript/pgo_profiler/pgo_profiler_encoder.h"
#include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
#include "ecmascript/tagged_array.h"
#include "ecmascript/tests/test_helper.h"
#include "ecmascript/tagged_tree.h"
#include "ecmascript/weak_vector.h"
#include "gtest/gtest.h"
using namespace panda;
using namespace panda::ecmascript;
using namespace panda::ecmascript::kungfu;
static constexpr char16_t UTF_16[] = u"This is a char16 array";
static constexpr char ASCII[] = "hello world!";
static constexpr int TEST_REPEAT_COUNT = 32;
static constexpr const char *DUPLICATE_KEY = "duplicateKey";
static constexpr const char *SIMPLE_KEY = "simpleKey";
static constexpr const char ERROR_MESSAGE[] = "ErrorTest";
namespace panda::test {
using BuiltinsFunction = ecmascript::builtins::BuiltinsFunction;
using PGOProfilerManager = panda::ecmascript::pgo::PGOProfilerManager;
using FunctionForRef = Local<JSValueRef> (*)(JsiRuntimeCallInfo *);
class JSNApiTests : public testing::Test {
public:
static void SetUpTestCase()
{
GTEST_LOG_(INFO) << "SetUpTestCase";
}
static void TearDownTestCase()
{
GTEST_LOG_(INFO) << "TearDownCase";
}
void SetUp() override
{
RuntimeOption option;
option.SetLogLevel(common::LOG_LEVEL::ERROR);
vm_ = JSNApi::CreateJSVM(option);
ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime";
thread_ = vm_->GetJSThread();
vm_->SetEnableForceGC(true);
thread_->ManagedCodeBegin();
}
void TearDown() override
{
thread_->ManagedCodeEnd();
vm_->SetEnableForceGC(false);
JSNApi::DestroyJSVM(vm_);
}
template <typename T> void TestNumberRef(T val, TaggedType expected)
{
LocalScope scope(vm_);
Local<NumberRef> obj = NumberRef::New(vm_, val);
ASSERT_TRUE(obj->IsNumber());
JSTaggedType res = JSNApiHelper::ToJSTaggedValue(*obj).GetRawData();
ASSERT_EQ(res, expected);
if constexpr (std::is_floating_point_v<T>) {
if (std::isnan(val)) {
ASSERT_TRUE(std::isnan(obj->Value()));
} else {
ASSERT_EQ(obj->Value(), val);
}
} else if constexpr (sizeof(T) >= sizeof(int32_t)) {
ASSERT_EQ(obj->IntegerValue(vm_), val);
} else if constexpr (std::is_signed_v<T>) {
ASSERT_EQ(obj->Int32Value(vm_), val);
} else {
ASSERT_EQ(obj->Uint32Value(vm_), val);
}
}
TaggedType ConvertDouble(double val)
{
return base::bit_cast<JSTaggedType>(val) + JSTaggedValue::DOUBLE_ENCODE_OFFSET;
}
uintptr_t JSNApiGetXRefGlobalHandleAddr(const EcmaVM *vm, uintptr_t localAddress)
{
return JSNApi::GetXRefGlobalHandleAddr(vm, localAddress);
}
void JSNApiDisposeXRefGlobalHandleAddr(const EcmaVM *vm, uintptr_t addr)
{
JSNApi::DisposeXRefGlobalHandleAddr(vm, addr);
}
protected:
void RegisterStringCacheTable();
std::shared_ptr<JSPandaFile> NewMockJSPandaFile(const char *data, const CString &filename,
const CString &targetFileName, CString &entryPoint) const;
JSThread *thread_ = nullptr;
EcmaVM *vm_ = nullptr;
bool isStringCacheTableCreated_ = false;
};
void JSNApiTests::RegisterStringCacheTable()
{
constexpr uint32_t STRING_CACHE_TABLE_SIZE = 100;
auto res = ExternalStringCache::RegisterStringCacheTable(vm_, STRING_CACHE_TABLE_SIZE);
if (isStringCacheTableCreated_) {
ASSERT_FALSE(res);
} else {
ASSERT_TRUE(res);
}
}
std::shared_ptr<JSPandaFile> JSNApiTests::NewMockJSPandaFile(const char *data,
const CString &filename, const CString &targetFileName, CString &entryPoint) const
{
panda::pandasm::Parser parser;
auto res = parser.Parse(data);
JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
std::unique_ptr<const panda::panda_file::File> pfPtr = pandasm::AsmEmitter::Emit(res.Value());
std::shared_ptr<JSPandaFile> pf = pfManager->NewJSPandaFile(pfPtr.release(), filename);
pf->SetBundlePack(false);
entryPoint = panda::ecmascript::ModulePathHelper::ConcatFileNameWithMerge(thread_, pf.get(),
const_cast<CString &>(filename), "", targetFileName);
pf->InsertJSRecordInfo(entryPoint);
pfManager->AddJSPandaFile(pf);
return pf;
}
Local<JSValueRef> FunctionCallback(JsiRuntimeCallInfo *info)
{
EscapeLocalScope scope(info->GetVM());
return scope.Escape(ArrayRef::New(info->GetVM(), info->GetArgsNumber()));
}
void WeakRefCallback(EcmaVM *vm)
{
LocalScope scope(vm);
Local<ObjectRef> object = ObjectRef::New(vm);
Global<ObjectRef> globalObject(vm, object);
globalObject.SetWeak();
Local<ObjectRef> object1 = ObjectRef::New(vm);
Global<ObjectRef> globalObject1(vm, object1);
globalObject1.SetWeak();
vm->CollectGarbage(TriggerGCType::YOUNG_GC);
vm->CollectGarbage(TriggerGCType::OLD_GC);
globalObject.FreeGlobalHandleAddr();
}
void ThreadCheck(const EcmaVM *vm)
{
EXPECT_TRUE(vm->GetJSThread()->GetThreadId() != JSThread::GetCurrentThreadId());
}
void CheckReject(JsiRuntimeCallInfo *info)
{
ASSERT_EQ(info->GetArgsNumber(), 1U);
Local<JSValueRef> reason = info->GetCallArgRef(0);
ASSERT_TRUE(reason->IsString(info->GetVM()));
ASSERT_EQ(Local<StringRef>(reason)->ToString(info->GetVM()), "Reject");
}
Local<JSValueRef> RejectCallback(JsiRuntimeCallInfo *info)
{
LocalScope scope(info->GetVM());
CheckReject(info);
return JSValueRef::Undefined(info->GetVM());
}
struct StackInfo {
uint64_t stackLimit;
uint64_t lastLeaveFrame;
};
* @tc.number: ffi_interface_api_105
* @tc.name: JSValueRef_IsGeneratorObject
* @tc.desc: Determine if it is a Generator generator object
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, JSValueRef_IsGeneratorObject)
{
LocalScope scope(vm_);
ObjectFactory *factory = vm_->GetFactory();
auto env = vm_->GetGlobalEnv();
JSHandle<JSTaggedValue> genFunc = env->GetGeneratorFunctionFunction();
JSHandle<JSGeneratorObject> genObjHandleVal = factory->NewJSGeneratorObject(genFunc);
JSHandle<JSHClass> hclass = JSHandle<JSHClass>::Cast(env->GetGeneratorFunctionClass());
JSHandle<JSFunction> generatorFunc = JSHandle<JSFunction>::Cast(factory->NewJSObject(hclass));
JSFunction::InitializeJSFunction(thread_, generatorFunc, FunctionKind::GENERATOR_FUNCTION);
JSHandle<GeneratorContext> generatorContext = factory->NewGeneratorContext();
generatorContext->SetMethod(thread_, generatorFunc.GetTaggedValue());
JSHandle<JSTaggedValue> generatorContextVal = JSHandle<JSTaggedValue>::Cast(generatorContext);
genObjHandleVal->SetGeneratorContext(thread_, generatorContextVal.GetTaggedValue());
JSHandle<JSTaggedValue> genObjTagHandleVal = JSHandle<JSTaggedValue>::Cast(genObjHandleVal);
Local<JSValueRef> genObjectRef = JSNApiHelper::ToLocal<GeneratorObjectRef>(genObjTagHandleVal);
ASSERT_TRUE(genObjectRef->IsGeneratorObject(vm_));
}
static JSFunction *JSObjectTestCreate(JSThread *thread)
{
EcmaVM *ecmaVM = thread->GetEcmaVM();
JSHandle<GlobalEnv> globalEnv = ecmaVM->GetGlobalEnv();
return globalEnv->GetObjectFunction().GetObject<JSFunction>();
}
* @tc.number: ffi_interface_api_106
* @tc.name: JSValueRef_IsProxy
* @tc.desc: Determine if it is the type of proxy
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, JSValueRef_IsProxy)
{
LocalScope scope(vm_);
JSHandle<JSTaggedValue> hclass(thread_, JSObjectTestCreate(thread_));
JSHandle<JSTaggedValue> targetHandle(
thread_->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(JSHandle<JSFunction>::Cast(hclass), hclass));
JSHandle<JSTaggedValue> key(thread_->GetEcmaVM()->GetFactory()->NewFromASCII("x"));
JSHandle<JSTaggedValue> value(thread_, JSTaggedValue(1));
JSObject::SetProperty(thread_, targetHandle, key, value);
EXPECT_EQ(JSObject::GetProperty(thread_, targetHandle, key).GetValue()->GetInt(), 1);
JSHandle<JSTaggedValue> handlerHandle(
thread_->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(JSHandle<JSFunction>::Cast(hclass), hclass));
EXPECT_TRUE(handlerHandle->IsECMAObject());
JSHandle<JSProxy> proxyHandle = JSProxy::ProxyCreate(thread_, targetHandle, handlerHandle);
EXPECT_TRUE(*proxyHandle != nullptr);
EXPECT_EQ(JSProxy::GetProperty(thread_, proxyHandle, key).GetValue()->GetInt(), 1);
PropertyDescriptor desc(thread_);
JSProxy::GetOwnProperty(thread_, proxyHandle, key, desc);
EXPECT_EQ(desc.GetValue()->GetInt(), 1);
Local<JSValueRef> proxy = JSNApiHelper::ToLocal<JSProxy>(JSHandle<JSTaggedValue>(proxyHandle));
ASSERT_TRUE(proxy->IsProxy(vm_));
}
* @tc.number: ffi_interface_api_107
* @tc.name: BufferRef_New_ByteLength
* @tc.desc:
* New:Create a buffer and specify the length size
* ByteLength:Returns the length of the buffer
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, BufferRef_New_ByteLength)
{
LocalScope scope(vm_);
int32_t length = 10;
Local<BufferRef> buffer = BufferRef::New(vm_, length);
ASSERT_TRUE(buffer->IsBuffer(vm_));
EXPECT_EQ(buffer->ByteLength(vm_), length);
}
* @tc.number: ffi_interface_api_108
* @tc.name: BufferRef_New_ByteLength_GetBuffer
* @tc.desc:
* New:Create a buffer and specify the length size
* ByteLength:Returns the length of the buffer
* GetBuffer:Return buffer pointer
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, BufferRef_New_ByteLength_GetBuffer)
{
LocalScope scope(vm_);
int32_t length = 10;
Local<BufferRef> buffer = BufferRef::New(vm_, length);
ASSERT_TRUE(buffer->IsBuffer(vm_));
EXPECT_EQ(buffer->ByteLength(vm_), 10U);
ASSERT_NE(buffer->GetBuffer(vm_), nullptr);
}
* @tc.number: ffi_interface_api_109
* @tc.name: BufferRef_New01_ByteLength_GetBuffer_BufferToStringCallback
* @tc.desc:
* BufferToStringCallback:Implement callback when calling ToString (vm) mode in buffer
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, BufferRef_New01_ByteLength_GetBuffer_BufferToStringCallback)
{
LocalScope scope(vm_);
static bool isFree = false;
struct Data {
int32_t length;
};
const int32_t length = 15;
NativePointerCallback deleter = []([[maybe_unused]] void *env, void *buffer, void *data) -> void {
delete[] reinterpret_cast<uint8_t *>(buffer);
Data *currentData = reinterpret_cast<Data *>(data);
delete currentData;
isFree = true;
};
isFree = false;
uint8_t *buffer = new uint8_t[length]();
Data *data = new Data();
data->length = length;
Local<BufferRef> bufferRef = BufferRef::New(vm_, buffer, length, deleter, data);
ASSERT_TRUE(bufferRef->IsBuffer(vm_));
ASSERT_TRUE(bufferRef->IsBuffer(vm_));
EXPECT_EQ(bufferRef->ByteLength(vm_), 15U);
Local<StringRef> bufferStr = bufferRef->ToString(vm_);
ASSERT_TRUE(bufferStr->IsString(vm_));
}
* @tc.number: ffi_interface_api_110
* @tc.name: LocalScope_LocalScope
* @tc.desc: Build Escape LocalScope sub Vm scope
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, LocalScope_LocalScope)
{
EscapeLocalScope scope(vm_);
LocalScope *perScope = nullptr;
perScope = &scope;
ASSERT_TRUE(perScope != nullptr);
}
* @tc.number: ffi_interface_api_112
* @tc.name: JSNApi_CreateJSVM_DestroyJSVM
* @tc.desc: Create/delete JSVM
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, JSNApi_CreateJSVM_DestroyJSVM)
{
LocalScope scope(vm_);
std::thread t1([]() {
EcmaVM *vm1_ = nullptr;
RuntimeOption option;
option.SetLogLevel(common::LOG_LEVEL::ERROR);
vm1_ = JSNApi::CreateJSVM(option);
ASSERT_TRUE(vm1_ != nullptr) << "Cannot create Runtime";
vm1_->SetEnableForceGC(true);
vm1_->SetEnableForceGC(false);
JSNApi::DestroyJSVM(vm1_);
});
{
ecmascript::ThreadSuspensionScope suspensionScope(thread_);
t1.join();
}
}
* @tc.number: ffi_interface_api_114
* @tc.name: JSNApi_GetUncaughtException
* @tc.desc: Get uncaught exceptions
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, JSNApi_GetUncaughtException)
{
LocalScope scope(vm_);
Local<ObjectRef> excep = JSNApi::GetUncaughtException(vm_);
ASSERT_TRUE(excep.IsNull()) << "CreateInstance occur Exception";
}
Local<JSValueRef> FuncRefNewCallbackForTest(JsiRuntimeCallInfo *info)
{
GTEST_LOG_(INFO) << "running FuncRefNewCallbackForTest";
EscapeLocalScope scope(info->GetVM());
return scope.Escape(ArrayRef::New(info->GetVM(), info->GetArgsNumber()));
}
Local<JSValueRef> ThrowingAccessorCallback(JsiRuntimeCallInfo *info)
{
EcmaVM *vm = info->GetVM();
Local<JSValueRef> error = Exception::Error(vm, StringRef::NewFromUtf8(vm, "FastPathAccessorError"));
JSNApi::ThrowException(vm, error);
return JSValueRef::Undefined(vm);
}
Local<JSValueRef> UndefinedAccessorCallback(JsiRuntimeCallInfo *info)
{
return JSValueRef::Undefined(info->GetVM());
}
static bool g_throwInFastLoadIc = false;
static bool g_throwInFastStoreIc = false;
static int32_t g_nonThrowingGetterValue = 0;
static int32_t g_lastSetterValue = 0;
static uint32_t g_setterCallCount = 0;
Local<JSValueRef> ConditionalThrowingGetterCallback(JsiRuntimeCallInfo *info)
{
EcmaVM *vm = info->GetVM();
if (g_throwInFastLoadIc) {
Local<JSValueRef> error = Exception::Error(vm, StringRef::NewFromUtf8(vm, "Tier1LoadAccessorError"));
JSNApi::ThrowException(vm, error);
return IntegerRef::New(vm, 123);
}
return IntegerRef::New(vm, 123);
}
Local<JSValueRef> ConditionalThrowingSetterCallback(JsiRuntimeCallInfo *info)
{
EcmaVM *vm = info->GetVM();
if (g_throwInFastStoreIc) {
Local<JSValueRef> error = Exception::Error(vm, StringRef::NewFromUtf8(vm, "Tier1StoreAccessorError"));
JSNApi::ThrowException(vm, error);
}
return JSValueRef::Undefined(vm);
}
Local<JSValueRef> StableGetterCallback(JsiRuntimeCallInfo *info)
{
return IntegerRef::New(info->GetVM(), g_nonThrowingGetterValue);
}
Local<JSValueRef> RecordingSetterCallback(JsiRuntimeCallInfo *info)
{
EcmaVM *vm = info->GetVM();
if (info->GetArgsNumber() > 0) {
Local<JSValueRef> value = info->GetCallArgRef(0);
g_lastSetterValue = value->Int32Value(vm);
g_setterCallCount++;
}
return JSValueRef::Undefined(vm);
}
IcAccessor::ICState GetCallsiteState(JSThread *thread, uintptr_t info, ICKind kind)
{
JSTaggedValue infoVal = *reinterpret_cast<JSTaggedValue *>(info);
JSHandle<ICInfo> callsiteInfo(thread, ICInfo::Cast(infoVal.GetTaggedObject()));
IcAccessor accessor(thread, callsiteInfo, 0, kind);
return accessor.GetICState();
}
void VerifyICStateTransition(IcAccessor::ICState state, uint32_t index)
{
if (index == 0) {
EXPECT_EQ(state, IcAccessor::ICState::MONO);
return;
}
if (index < IcAccessor::POLY_CASE_NUM) {
EXPECT_EQ(state, IcAccessor::ICState::POLY);
return;
}
if (index >= IcAccessor::POLY_CASE_NUM) {
EXPECT_TRUE(state == IcAccessor::ICState::MEGA ||
state == IcAccessor::ICState::IC_MEGA);
return;
}
FAIL() << "Unexpected IC state " << static_cast<int>(state) << " at index " << index;
}
* @tc.number: ffi_interface_api_115
* @tc.name: ObjectRef_SetAccessorProperty
* @tc.desc:
* SetAccessorProperty:Set AccessorPro Properties
* GetVM:Obtain environment information for runtime calls
* LocalScope:Build Vm Scope
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, ObjectRef_SetAccessorProperty_JsiRuntimeCallInfo_GetVM)
{
LocalScope scope(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "TestKey");
FunctionForRef nativeFunc = FuncRefNewCallbackForTest;
Local<FunctionRef> getter = FunctionRef::New(vm_, nativeFunc);
Local<FunctionRef> setter = FunctionRef::New(vm_, nativeFunc);
Local<ObjectRef> object = ObjectRef::New(vm_);
ASSERT_TRUE(object->SetAccessorProperty(vm_, key, getter, setter));
}
* @tc.number: ffi_interface_api_116
* @tc.name: JSNApi_IsBoolean
* @tc.desc: Judge whether obj is a boolean type
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, IsBoolean)
{
LocalScope scope(vm_);
char16_t utf16[] = u"This is a char16 array";
int size = sizeof(utf16);
Local<StringRef> obj = StringRef::NewFromUtf16(vm_, utf16, size);
ASSERT_FALSE(obj->IsBoolean());
}
* @tc.number: ffi_interface_api_117
* @tc.name: JSNApi_IsNULL
* @tc.desc: Judge whether obj is a null type
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, IsNULL)
{
LocalScope scope(vm_);
char16_t utf16[] = u"This is a char16 array";
int size = sizeof(utf16);
Local<StringRef> obj = StringRef::NewFromUtf16(vm_, utf16, size);
ASSERT_FALSE(obj->IsNull());
}
* @tc.number: ffi_interface_api_118
* @tc.name: JSNApi_GetTime
* @tc.desc: This function is to catch time
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, GetTime)
{
LocalScope scope(vm_);
const double time = 14.29;
Local<DateRef> date = DateRef::New(vm_, time);
ASSERT_EQ(date->GetTime(vm_), time);
}
* @tc.number: ffi_interface_api_119
* @tc.name: JSNApi_IsDetach
* @tc.desc: Judge whether arraybuffer is detached
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, IsDetach)
{
LocalScope scope(vm_);
const int32_t length = 33;
Local<ArrayBufferRef> arraybuffer = ArrayBufferRef::New(vm_, length);
ASSERT_FALSE(arraybuffer->IsDetach(vm_));
}
* @tc.number: ffi_interface_api_120
* @tc.name: JSNApi_Detach
* @tc.desc: This function is to detach arraybuffer
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, Detach)
{
LocalScope scope(vm_);
const int32_t length = 33;
Local<ArrayBufferRef> arraybuffer = ArrayBufferRef::New(vm_, length);
arraybuffer->Detach(vm_);
}
* @tc.number: ffi_interface_api_121
* @tc.name: JSNApi_New1
* @tc.desc: create a obj that is a arraybuffer type
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, New1)
{
LocalScope scope(vm_);
const int32_t length = 33;
Local<ArrayBufferRef> arrayBuffer = ArrayBufferRef::New(vm_, length);
ASSERT_TRUE(arrayBuffer->IsArrayBuffer(vm_));
ASSERT_EQ(arrayBuffer->ByteLength(vm_), length);
ASSERT_NE(arrayBuffer->GetBuffer(vm_), nullptr);
}
* @tc.number: ffi_interface_api_122
* @tc.name: JSNApi_New1
* @tc.desc: create a obj that is a arraybuffer type
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, New2)
{
static bool isFree = false;
struct Data {
int32_t length;
};
const int32_t length = 15;
Data *data = new Data();
data->length = length;
NativePointerCallback deleter = []([[maybe_unused]] void *env, void *buffer, void *data) -> void {
delete[] reinterpret_cast<uint8_t *>(buffer);
Data *currentData = reinterpret_cast<Data *>(data);
ASSERT_EQ(currentData->length, 15);
delete currentData;
isFree = true;
};
{
LocalScope scope(vm_);
uint8_t *buffer = new uint8_t[length]();
Local<ArrayBufferRef> arrayBuffer = ArrayBufferRef::New(vm_, buffer, length, deleter, data);
ASSERT_TRUE(arrayBuffer->IsArrayBuffer(vm_));
ASSERT_EQ(arrayBuffer->ByteLength(vm_), length);
ASSERT_EQ(arrayBuffer->GetBuffer(vm_), buffer);
}
}
* @tc.number: ffi_interface_api_123
* @tc.name: JSNApi_Bytelength
* @tc.desc: capture bytelength of arraybuffer
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, Bytelength)
{
LocalScope scope(vm_);
const int32_t length = 33;
Local<ArrayBufferRef> arrayBuffer = ArrayBufferRef::New(vm_, length);
ASSERT_EQ(arrayBuffer->ByteLength(vm_), length);
}
* @tc.number: ffi_interface_api_124
* @tc.name: JSNApi_GetBuffer
* @tc.desc: capture buffer of arraybuffer
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, GetBuffer)
{
LocalScope scope(vm_);
const int32_t length = 33;
Local<ArrayBufferRef> arraybuffer = ArrayBufferRef::New(vm_, length);
ASSERT_NE(arraybuffer->GetBuffer(vm_), nullptr);
}
* @tc.number: ffi_interface_api_125
* @tc.name: JSNApi_Is32Arraytest
* @tc.desc: judge whether obj is a int32array type,
* judge whether obj is a uint32array type,
* judge whether obj is a float32array type,
* judge whether obj is a float64array type,
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, Is32Arraytest)
{
LocalScope scope(vm_);
char16_t utf16[] = u"This is a char16 array";
int size = sizeof(utf16);
Local<StringRef> obj = StringRef::NewFromUtf16(vm_, utf16, size);
ASSERT_FALSE(obj->IsInt32Array(vm_));
ASSERT_FALSE(obj->IsUint32Array(vm_));
ASSERT_FALSE(obj->IsFloat32Array(vm_));
ASSERT_FALSE(obj->IsFloat64Array(vm_));
}
* @tc.number: ffi_interface_api_126
* @tc.name: JSNApi_SynchronizVMInfo
* @tc.desc: capture synchronous info of vm
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, SynchronizVMInfo)
{
LocalScope scope(vm_);
std::thread t1([this]() {
JSRuntimeOptions option;
EcmaVM *hostVM = JSNApi::CreateEcmaVM(option);
{
LocalScope scope2(hostVM);
JSNApi::SynchronizVMInfo(vm_, hostVM);
}
JSNApi::DestroyJSVM(hostVM);
});
{
ecmascript::ThreadSuspensionScope suspensionScope(thread_);
t1.join();
}
}
* @tc.number: ffi_interface_api_127
* @tc.name: JSNApi_IsProfiling
* @tc.desc: judge whether vm is profiling
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, IsProfiling)
{
LocalScope scope(vm_);
ASSERT_FALSE(JSNApi::IsProfiling(vm_));
}
* @tc.number: ffi_interface_api_128
* @tc.name: JSNApi_SetProfilerState
* @tc.desc: This function is to set state of profiler
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, SetProfilerState)
{
bool value = true;
bool value2 = false;
LocalScope scope(vm_);
JSNApi::SetProfilerState(vm_, value);
JSNApi::SetProfilerState(vm_, value2);
}
* @tc.number: ffi_interface_api_129
* @tc.name: JSNApi_SetLoop
* @tc.desc: This function is to set loop
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, SetLoop)
{
LocalScope scope(vm_);
void *data = reinterpret_cast<void *>(BuiltinsFunction::FunctionPrototypeInvokeSelf);
JSNApi::SetLoop(vm_, data);
}
* @tc.number: ffi_interface_api_130
* @tc.name: JSNApi_SetHostPromiseRejectionTracker
* @tc.desc: This function is to set host promise rejection about tracker
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, SetHostPromiseRejectionTracker)
{
LocalScope scope(vm_);
void *data = reinterpret_cast<void *>(BuiltinsFunction::FunctionPrototypeInvokeSelf);
void *cb = reinterpret_cast<void *>(BuiltinsFunction::FunctionPrototypeInvokeSelf);
JSNApi::SetHostPromiseRejectionTracker(vm_, cb, data);
}
* @tc.number: ffi_interface_api_131
* @tc.name: JSNApi_SetHostResolveBufferTracker
* @tc.desc: This function is to set host resolve buffer about tracker
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, SetHostResolveBufferTracker)
{
LocalScope scope(vm_);
JSNApi::SetHostResolveBufferTracker(vm_,
[](std::string, uint8_t **, size_t *, std::string &) -> bool { return true; });
}
* @tc.number: ffi_interface_api_132
* @tc.name: JSNApi_SetUnloadNativeModuleCallback
* @tc.desc: This function is to set unload native module about callback
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, SetUnloadNativeModuleCallback)
{
LocalScope scope(vm_);
JSNApi::SetUnloadNativeModuleCallback(vm_, [](const std::string &) -> bool { return true; });
}
* @tc.number: ffi_interface_api_133
* @tc.name: JSNApi_SetNativePtrGetter
* @tc.desc: This function is to set a native pointer about getter
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, SetNativePtrGetter)
{
LocalScope scope(vm_);
void *cb = reinterpret_cast<void *>(BuiltinsFunction::FunctionPrototypeInvokeSelf);
JSNApi::SetNativePtrGetter(vm_, cb);
}
* @tc.number: ffi_interface_api_134
* @tc.name: JSNApi_PreFork
* @tc.desc: This function is to set prefork
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, PreFork)
{
RuntimeOption option;
ecmascript::ThreadNativeScope nativeScope(vm_->GetJSThread());
LocalScope scope(vm_);
JSNApi::PreFork(vm_);
JSNApi::PostFork(vm_, option);
}
* @tc.number: ffi_interface_api_135
* @tc.name: JSNApi_PostFork
* @tc.desc: This function is to set postfork
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, PostFork)
{
RuntimeOption option;
ecmascript::ThreadNativeScope nativeScope(vm_->GetJSThread());
LocalScope scope(vm_);
JSNApi::PreFork(vm_);
JSNApi::PostFork(vm_, option);
}
* @tc.number: ffi_interface_api_136
* @tc.name: JSNApi_NewFromUtf8
* @tc.desc: create a newfromutf8 object
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, NewFromUtf8)
{
LocalScope scope(vm_);
char utf8[] = "hello world!";
int length = strlen(utf8);
Local<StringRef> result = StringRef::NewFromUtf8(vm_, utf8, length);
ASSERT_EQ(result->Utf8Length(vm_), length + 1);
}
* @tc.number: ffi_interface_api_137
* @tc.name: JSNApi_NewFromUtf16
* @tc.desc: create a newfromutf16 object
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, NewFromUtf16)
{
LocalScope scope(vm_);
char16_t utf16[] = u"This is a char16 array";
int length = sizeof(utf16);
Local<StringRef> result = StringRef::NewFromUtf16(vm_, utf16, length);
ASSERT_EQ(result->Length(vm_), length);
}
HWTEST_F_L0(JSNApiTests, NewExternalFromAsciiLength)
{
LocalScope scope(vm_);
int length = strlen(ASCII);
char *str = new char[length];
std::copy(ASCII, ASCII + length, str);
Local<StringRef> result = StringRef::NewExternalFromAscii(vm_, const_cast<char *>(str),
length, nullptr, nullptr);
ASSERT_EQ(result->Utf8Length(vm_), length + 1);
delete[] str;
}
HWTEST_F_L0(JSNApiTests, NewExternalFromUtf16Length)
{
LocalScope scope(vm_);
int length = sizeof(UTF_16) / sizeof(char16_t) - 1;
char16_t *str = new char16_t[length];
std::copy(UTF_16, UTF_16 + length, str);
Local<StringRef> result = StringRef::NewExternalFromUtf16(vm_, const_cast<char16_t *>(str),
length, nullptr, nullptr);
ASSERT_EQ(result->Length(vm_), length);
delete[] str;
}
HWTEST_F_L0(JSNApiTests, NewExternalFromAsciiContent)
{
LocalScope scope(vm_);
int length = strlen(ASCII);
char *str = new char[length];
std::copy(ASCII, ASCII + length, str);
Local<StringRef> result = StringRef::NewExternalFromAscii(vm_, const_cast<char *>(str),
length, nullptr, nullptr);
EXPECT_EQ(result->ToString(vm_), "hello world!");
delete[] str;
}
HWTEST_F_L0(JSNApiTests, NewExternalFromUtf16Content)
{
LocalScope scope(vm_);
int length = sizeof(UTF_16) / sizeof(char16_t) - 1;
char16_t *str = new char16_t[length];
std::copy(UTF_16, UTF_16 + length, str);
Local<StringRef> result = StringRef::NewExternalFromUtf16(vm_, const_cast<char16_t *>(str),
length, nullptr, nullptr);
EXPECT_EQ(result->ToString(vm_), "This is a char16 array");
delete[] str;
}
HWTEST_F_L0(JSNApiTests, NewExternalFromAsciiOnGC)
{
auto sHeap = SharedHeap::GetInstance();
auto callback = [] (void* data, void* hint) -> void {
*reinterpret_cast<int *>(hint) += 1;
delete[] reinterpret_cast<char *>(data);
};
int hintNum = 0;
{
LocalScope scope(vm_);
for (int i = 0; i < TEST_REPEAT_COUNT; i++) {
int length = strlen(ASCII);
char *str = new char[length];
std::copy(ASCII, ASCII + length, str);
Local<StringRef> result = StringRef::NewExternalFromAscii(vm_, const_cast<char *>(str),
length, callback, &hintNum);
EXPECT_EQ(result->ToString(vm_), "hello world!");
}
EXPECT_EQ(hintNum, 0);
EXPECT_EQ(sHeap->GetExternalStringTable()->GetListSize(), TEST_REPEAT_COUNT);
}
sHeap->CollectGarbage<TriggerGCType::SHARED_FULL_GC, GCReason::OTHER>(vm_->GetJSThread());
EXPECT_EQ(sHeap->GetExternalStringTable()->GetListSize(), 0);
EXPECT_EQ(hintNum, TEST_REPEAT_COUNT);
}
HWTEST_F_L0(JSNApiTests, NewExternalFromUtf16OnGC)
{
auto sHeap = SharedHeap::GetInstance();
auto callback = [] (void* data, void* hint) -> void {
*reinterpret_cast<int *>(hint) += 1;
delete[] reinterpret_cast<char16_t *>(data);
};
int hintNum = 0;
{
LocalScope scope(vm_);
for (int i = 0; i < TEST_REPEAT_COUNT; i++) {
int length = sizeof(UTF_16) / sizeof(char16_t) - 1;
char16_t *str = new char16_t[length];
std::copy(UTF_16, UTF_16 + length, str);
Local<StringRef> result = StringRef::NewExternalFromUtf16(vm_, const_cast<char16_t *>(str),
length, callback, &hintNum);
EXPECT_EQ(result->ToString(vm_), "This is a char16 array");
}
EXPECT_EQ(hintNum, 0);
EXPECT_EQ(sHeap->GetExternalStringTable()->GetListSize(), TEST_REPEAT_COUNT);
}
sHeap->CollectGarbage<TriggerGCType::SHARED_FULL_GC, GCReason::OTHER>(vm_->GetJSThread());
EXPECT_EQ(sHeap->GetExternalStringTable()->GetListSize(), 0);
EXPECT_EQ(hintNum, TEST_REPEAT_COUNT);
}
* @tc.number: ffi_interface_api_138
* @tc.name: JSNApi_GetNapiWrapperString
* @tc.desc: This function is to get a napiwrapper string
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, GetNapiWrapperString)
{
LocalScope scope(vm_);
Local<StringRef> result = StringRef::GetNapiWrapperString(vm_);
ASSERT_TRUE(result->IsString(vm_));
}
* @tc.number: ffi_interface_api_139
* @tc.name: JSNApi_JSExecutionScope
* @tc.desc: This function is to construct a object of jsexecutionscope
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, JSExecutionScope)
{
LocalScope scope(vm_);
JSExecutionScope jsexecutionScope(vm_);
}
* @tc.number: ffi_interface_api_140
* @tc.name: WeakMapRef_GetSize_GetTotalElements_GetKey_GetValue
* @tc.desc: This function is to set a weakmap and capture it's size ,
* key, value and total elements
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, WeakMapRef_GetSize_GetTotalElements_GetKey_GetValue)
{
LocalScope scope(vm_);
JSThread *thread = vm_->GetJSThread();
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSTaggedValue> constructor = env->GetBuiltinsWeakMapFunction();
JSHandle<JSWeakMap> weakMap =
JSHandle<JSWeakMap>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), constructor));
JSHandle<WeakLinkedHashMap> hashMap = WeakLinkedHashMap::Create(thread);
weakMap->SetWeakLinkedMap(thread, hashMap);
JSHandle<JSTaggedValue> weakMapTag = JSHandle<JSTaggedValue>::Cast(weakMap);
Local<WeakMapRef> map = JSNApiHelper::ToLocal<WeakMapRef>(weakMapTag);
EXPECT_TRUE(map->IsWeakMap(vm_));
JSHandle<JSTaggedValue> value(factory->NewFromASCII("value"));
JSHandle<JSTaggedValue> key(factory->NewFromASCII("key"));
JSWeakMap::Set(thread, weakMap, key, value);
int32_t num = map->GetSize(vm_);
int32_t num1 = map->GetTotalElements(vm_);
ASSERT_EQ(num, 1);
ASSERT_EQ(num1, 1);
Local<JSValueRef> res1 = map->GetKey(vm_, 0);
ASSERT_EQ(res1->ToString(vm_)->ToString(vm_), "key");
Local<JSValueRef> res2 = map->GetValue(vm_, 0);
ASSERT_EQ(res2->ToString(vm_)->ToString(vm_), "value");
}
* @tc.number: ffi_interface_api_141
* @tc.name: JSNApi_ IsAGJA
* @tc.desc: This function is to judge whether object is a argumentsobject or
* is a generatorfunction or is a asyncfunction
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, IsAGJA)
{
LocalScope scope(vm_);
char16_t utf16[] = u"This is a char16 array";
int size = sizeof(utf16);
Local<StringRef> obj = StringRef::NewFromUtf16(vm_, utf16, size);
ASSERT_FALSE(obj->IsArgumentsObject(vm_));
ASSERT_FALSE(obj->IsGeneratorFunction(vm_));
ASSERT_FALSE(obj->IsAsyncFunction(vm_));
}
* @tc.number: ffi_interface_api_143
* @tc.name: Int32Array
* @tc.desc: Catch exceptions correctly
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, HasCaught)
{
LocalScope scope(vm_);
Local<StringRef> message = StringRef::NewFromUtf8(vm_, "ErrorTest");
Local<JSValueRef> error = Exception::Error(vm_, message);
ASSERT_TRUE(error->IsError(vm_));
JSNApi::ThrowException(vm_, error);
TryCatch tryCatch(vm_);
ASSERT_TRUE(tryCatch.HasCaught());
vm_->GetJSThread()->ClearException();
ASSERT_FALSE(tryCatch.HasCaught());
}
* @tc.number: ffi_interface_api_144
* @tc.name: Int32Array
* @tc.desc: Rethrow the exception
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, Rethrow)
{
LocalScope scope(vm_);
TryCatch tryCatch(vm_);
tryCatch.Rethrow();
ASSERT_TRUE(tryCatch.getrethrow_());
}
* @tc.number: ffi_interface_api_145
* @tc.name: Int32Array
* @tc.desc: Clear caught exceptions
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, GetAndClearException)
{
LocalScope scope(vm_);
Local<StringRef> message = StringRef::NewFromUtf8(vm_, "ErrorTest");
Local<JSValueRef> error = Exception::Error(vm_, message);
ASSERT_TRUE(error->IsError(vm_));
JSNApi::ThrowException(vm_, error);
ASSERT_TRUE(vm_->GetJSThread()->HasPendingException());
TryCatch tryCatch(vm_);
tryCatch.GetAndClearException();
EXPECT_FALSE(vm_->GetJSThread()->HasPendingException());
}
* @tc.number: ffi_interface_api_146
* @tc.name: Int32Array
* @tc.desc: trycatch class construction
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, TryCatch001)
{
LocalScope scope(vm_);
TryCatch tryCatch(vm_);
EXPECT_EQ(tryCatch.getrethrow_(), false);
EXPECT_FALSE(tryCatch.HasCaught());
tryCatch.Rethrow();
EXPECT_EQ(tryCatch.getrethrow_(), true);
}
* @tc.number: ffi_interface_api_147
* @tc.name: Int32Array
* @tc.desc: trycatch class construction
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, TryCatch002)
{
LocalScope scope(vm_);
TryCatch tryCatch(vm_);
EXPECT_EQ(JSNApi::GetEnv(vm_), tryCatch.GetEnv());
}
HWTEST_F_L0(JSNApiTests, NewObjectWithProperties)
{
LocalScope scope(vm_);
Local<JSValueRef> keys[1100];
Local<JSValueRef> values[1100];
PropertyAttribute attributes[1100];
for (int i = 0; i < 1100; i += (i < 80 ? (i < 10 ? 1 : 80) : 1000)) {
for (int j = 0; j <= i; ++j) {
std::string strKey("TestKey" + std::to_string(i) + "_" + std::to_string(j));
std::string strVal("TestValue" + std::to_string(i) + "_" + std::to_string(j));
keys[j] = StringRef::NewFromUtf8(vm_, strKey.c_str());
values[j] = StringRef::NewFromUtf8(vm_, strVal.c_str());
attributes[j] = PropertyAttribute(values[j], true, true, true);
}
Local<ObjectRef> object = ObjectRef::NewWithProperties(vm_, i + 1, keys, attributes);
for (int j = 0; j <= i; ++j) {
Local<JSValueRef> value1 = object->Get(vm_, keys[j]);
EXPECT_TRUE(values[j]->IsStrictEquals(vm_, value1));
}
JSHandle<JSObject> obj(JSNApiHelper::ToJSHandle(object));
uint32_t propCount = obj->GetJSHClass()->NumberOfProps();
if (i + 1 > PropertyAttributes::MAX_FAST_PROPS_CAPACITY) {
EXPECT_TRUE(propCount == 0);
EXPECT_TRUE(obj->GetJSHClass()->IsDictionaryMode());
JSHandle<NameDictionary> dict(thread_, obj->GetProperties(thread_));
EXPECT_TRUE(dict->EntriesCount() == i + 1);
} else {
EXPECT_TRUE(propCount == i + 1);
int32_t in_idx = obj->GetJSHClass()->GetNextInlinedPropsIndex();
int32_t nonin_idx = obj->GetJSHClass()->GetNextNonInlinedPropsIndex();
if (i + 1 < JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS) {
EXPECT_TRUE(in_idx == i + 1);
EXPECT_TRUE(nonin_idx == -1);
} else {
EXPECT_TRUE(in_idx == -1);
EXPECT_TRUE(nonin_idx == 0);
}
}
}
}
HWTEST_F_L0(JSNApiTests, NewObjectWithPropertieNonPureStringKey)
{
LocalScope scope(vm_);
Local<JSValueRef> keys[] = {
StringRef::NewFromUtf8(vm_, "1"),
};
Local<JSValueRef> values[] = {
StringRef::NewFromUtf8(vm_, "value1"),
};
PropertyAttribute attributes[] = {
PropertyAttribute(values[0], true, true, true),
};
Local<ObjectRef> object = ObjectRef::NewWithProperties(vm_, 1, keys, attributes);
JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(object);
EXPECT_TRUE(obj.GetTaggedValue() == JSTaggedValue::Undefined());
thread_->ClearException();
}
HWTEST_F_L0(JSNApiTests, NewObjectWithPropertiesDuplicate)
{
LocalScope scope(vm_);
Local<JSValueRef> keys[] = {
StringRef::NewFromUtf8(vm_, DUPLICATE_KEY),
StringRef::NewFromUtf8(vm_, SIMPLE_KEY),
StringRef::NewFromUtf8(vm_, DUPLICATE_KEY),
};
Local<JSValueRef> values[] = {
StringRef::NewFromUtf8(vm_, "value1"),
StringRef::NewFromUtf8(vm_, "value2"),
StringRef::NewFromUtf8(vm_, "value3"),
};
PropertyAttribute attributes[] = {
PropertyAttribute(values[0], true, true, true),
PropertyAttribute(values[1], true, true, true),
PropertyAttribute(values[2], true, true, true),
};
Local<ObjectRef> object = ObjectRef::NewWithProperties(vm_, 3, keys, attributes);
JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(object);
EXPECT_TRUE(obj.GetTaggedValue() == JSTaggedValue::Undefined());
thread_->ClearException();
}
HWTEST_F_L0(JSNApiTests, NewObjectWithNamedProperties)
{
LocalScope scope(vm_);
const char *keys[1100];
std::string strKeys[1100];
Local<JSValueRef> values[1100];
for (int i = 0; i < 1100; i += (i < 80 ? (i < 10 ? 1 : 80) : 1000)) {
for (int j = 0; j <= i; ++j) {
strKeys[j] = "TestKey" + std::to_string(i) + "_" + std::to_string(j);
std::string strVal("TestValue" + std::to_string(i) + "_" + std::to_string(j));
keys[j] = const_cast<char *>(strKeys[j].c_str());
values[j] = StringRef::NewFromUtf8(vm_, strVal.c_str());
}
Local<ObjectRef> object = ObjectRef::NewWithNamedProperties(vm_, i + 1, keys, values);
for (int j = 0; j <= i; ++j) {
Local<JSValueRef> value1 = object->Get(vm_, StringRef::NewFromUtf8(vm_, keys[j]));
EXPECT_TRUE(values[j]->IsStrictEquals(vm_, value1));
}
JSHandle<JSObject> obj(JSNApiHelper::ToJSHandle(object));
uint32_t propCount = obj->GetJSHClass()->NumberOfProps();
if (i + 1 > PropertyAttributes::MAX_FAST_PROPS_CAPACITY) {
EXPECT_TRUE(propCount == 0);
EXPECT_TRUE(obj->GetJSHClass()->IsDictionaryMode());
JSHandle<NameDictionary> dict(thread_, obj->GetProperties(thread_));
EXPECT_TRUE(dict->EntriesCount() == i + 1);
} else {
EXPECT_TRUE(propCount == i + 1);
int32_t in_idx = obj->GetJSHClass()->GetNextInlinedPropsIndex();
int32_t nonin_idx = obj->GetJSHClass()->GetNextNonInlinedPropsIndex();
if (i + 1 < JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS) {
EXPECT_TRUE(in_idx == i + 1);
EXPECT_TRUE(nonin_idx == -1);
} else {
EXPECT_TRUE(in_idx == -1);
EXPECT_TRUE(nonin_idx == 0);
}
}
}
}
HWTEST_F_L0(JSNApiTests, NewObjectWithNamedPropertieNonPureStringKey)
{
LocalScope scope(vm_);
const char *keys[] = {
"1",
};
Local<JSValueRef> values[] = {
StringRef::NewFromUtf8(vm_, "value1"),
};
Local<ObjectRef> object = ObjectRef::NewWithNamedProperties(vm_, 2, keys, values);
JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(object);
EXPECT_TRUE(obj.GetTaggedValue() == JSTaggedValue::Undefined());
thread_->ClearException();
}
HWTEST_F_L0(JSNApiTests, NewObjectWithNamedPropertiesDuplicate)
{
LocalScope scope(vm_);
const char *keys[] = {
DUPLICATE_KEY,
SIMPLE_KEY,
DUPLICATE_KEY,
};
Local<JSValueRef> values[] = {
StringRef::NewFromUtf8(vm_, "value1"),
StringRef::NewFromUtf8(vm_, "value2"),
StringRef::NewFromUtf8(vm_, "value3"),
};
Local<ObjectRef> object = ObjectRef::NewWithNamedProperties(vm_, 3, keys, values);
JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(object);
EXPECT_TRUE(obj.GetTaggedValue() == JSTaggedValue::Undefined());
thread_->ClearException();
}
HWTEST_F_L0(JSNApiTests, GetNamedPropertyByPassingUtf8Key)
{
LocalScope scope(vm_);
Local<ObjectRef> object = ObjectRef::New(vm_);
const char* utf8Key = "TestKey";
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, utf8Key);
Local<JSValueRef> value = ObjectRef::New(vm_);
PropertyAttribute attribute(value, true, true, true);
ASSERT_TRUE(object->DefineProperty(vm_, key, attribute));
Local<JSValueRef> value1 = object->Get(vm_, utf8Key);
ASSERT_TRUE(value->IsStrictEquals(vm_, value1));
}
HWTEST_F_L0(JSNApiTests, SetNamedPropertyByPassingUtf8Key)
{
LocalScope scope(vm_);
Local<ObjectRef> object = ObjectRef::New(vm_);
const char* utf8Key = "TestKey";
Local<JSValueRef> value = ObjectRef::New(vm_);
ASSERT_TRUE(object->Set(vm_, utf8Key, value));
Local<JSValueRef> value1 = object->Get(vm_, utf8Key);
ASSERT_TRUE(value->IsStrictEquals(vm_, value1));
}
HWTEST_F_L0(JSNApiTests, NapiFastPathGetNamedProperty)
{
LocalScope scope(vm_);
Local<ObjectRef> object = ObjectRef::New(vm_);
const char* utf8Key = "TestKey";
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, utf8Key);
Local<JSValueRef> value = ObjectRef::New(vm_);
PropertyAttribute attribute(value, true, true, true);
ASSERT_TRUE(object->DefineProperty(vm_, key, attribute));
Local<JSValueRef> value1 = JSNApi::NapiGetNamedProperty(vm_, reinterpret_cast<uintptr_t>(*object), utf8Key);
ASSERT_TRUE(value->IsStrictEquals(vm_, value1));
}
HWTEST_F_L0(JSNApiTests, NewObjectWithPropertiesDuplicateWithKeyNotFromStringTable)
{
LocalScope scope(vm_);
Local<JSValueRef> keys[] = {
StringRef::NewFromUtf8WithoutStringTable(vm_, DUPLICATE_KEY),
StringRef::NewFromUtf8WithoutStringTable(vm_, SIMPLE_KEY),
StringRef::NewFromUtf8WithoutStringTable(vm_, DUPLICATE_KEY),
};
Local<JSValueRef> values[] = {
StringRef::NewFromUtf8WithoutStringTable(vm_, "value1"),
StringRef::NewFromUtf8WithoutStringTable(vm_, "value2"),
StringRef::NewFromUtf8WithoutStringTable(vm_, "value3"),
};
PropertyAttribute attributes[] = {
PropertyAttribute(values[0], true, true, true),
PropertyAttribute(values[1], true, true, true),
PropertyAttribute(values[2], true, true, true),
};
Local<ObjectRef> object = ObjectRef::NewWithProperties(vm_, 3, keys, attributes);
JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(object);
EXPECT_TRUE(obj.GetTaggedValue() == JSTaggedValue::Undefined());
thread_->ClearException();
}
HWTEST_F_L0(JSNApiTests, NewObjectWithPropertiesDuplicateWithKeyNotFromStringTable1)
{
LocalScope scope(vm_);
Local<JSValueRef> keys[] = {
StringRef::NewFromUtf8WithoutStringTable(vm_, DUPLICATE_KEY, 0),
StringRef::NewFromUtf8WithoutStringTable(vm_, SIMPLE_KEY, 0),
StringRef::NewFromUtf8WithoutStringTable(vm_, DUPLICATE_KEY, 0),
};
Local<JSValueRef> values[] = {
StringRef::NewFromUtf16WithoutStringTable(vm_, UTF_16, 0),
StringRef::NewFromUtf16WithoutStringTable(vm_, UTF_16, 0),
StringRef::NewFromUtf16WithoutStringTable(vm_, UTF_16, 0),
};
PropertyAttribute attributes[] = {
PropertyAttribute(values[0], true, true, true),
PropertyAttribute(values[1], true, true, true),
PropertyAttribute(values[2], true, true, true),
};
Local<ObjectRef> object = ObjectRef::NewWithProperties(vm_, 3, keys, attributes);
JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(object);
EXPECT_TRUE(obj.GetTaggedValue() == JSTaggedValue::Undefined());
thread_->ClearException();
}
HWTEST_F_L0(JSNApiTests, EcmaObjectToInt)
{
LocalScope scope(vm_);
Local<FunctionRef> toPrimitiveFunc = FunctionRef::New(vm_,
[](JsiRuntimeCallInfo *runtimeInfo) -> Local<JSValueRef> {
EcmaVM *vm = runtimeInfo->GetVM();
return JSValueRef::True(vm);
});
Local<ObjectRef> obj = ObjectRef::New(vm_);
PropertyAttribute attribute(toPrimitiveFunc, true, true, true);
Local<JSValueRef> toPrimitiveKey = JSNApiHelper::ToLocal<JSValueRef>(
vm_->GetJSThread()->GlobalConstants()->GetHandledToPrimitiveSymbol());
obj->DefineProperty(vm_, toPrimitiveKey, attribute);
{
ecmascript::ThreadNativeScope nativeScope(thread_);
uint32_t res = obj->Uint32Value(vm_);
EXPECT_TRUE(res == 1);
res = obj->Int32Value(vm_);
EXPECT_TRUE(res == 1);
}
}
HWTEST_F_L0(JSNApiTests, NapiTryFastTest)
{
Local<ObjectRef> object = ObjectRef::New(vm_);
JSTaggedValue a(0);
JSHandle<JSTaggedValue> handle(thread_, a);
Local<JSValueRef> key = JSNApiHelper::ToLocal<JSValueRef>(handle);
const char* utf8Key = "TestKey";
Local<JSValueRef> key2 = StringRef::NewFromUtf8(vm_, utf8Key);
Local<JSValueRef> value = ObjectRef::New(vm_);
object->Set(vm_, key, value);
object->Set(vm_, key2, value);
Local<JSValueRef> res1 = JSNApi::NapiGetProperty(vm_, reinterpret_cast<uintptr_t>(*object),
reinterpret_cast<uintptr_t>(*key));
ASSERT_TRUE(value->IsStrictEquals(vm_, res1));
Local<JSValueRef> res2 = JSNApi::NapiGetProperty(vm_, reinterpret_cast<uintptr_t>(*object),
reinterpret_cast<uintptr_t>(*key2));
ASSERT_TRUE(value->IsStrictEquals(vm_, res2));
Local<JSValueRef> flag = JSNApi::NapiHasProperty(vm_, reinterpret_cast<uintptr_t>(*object),
reinterpret_cast<uintptr_t>(*key));
ASSERT_TRUE(flag->BooleaValue(vm_));
flag = JSNApi::NapiHasProperty(vm_, reinterpret_cast<uintptr_t>(*object), reinterpret_cast<uintptr_t>(*key2));
ASSERT_TRUE(flag->BooleaValue(vm_));
flag = JSNApi::NapiDeleteProperty(vm_, reinterpret_cast<uintptr_t>(*object), reinterpret_cast<uintptr_t>(*key));
ASSERT_TRUE(flag->BooleaValue(vm_));
flag = JSNApi::NapiDeleteProperty(vm_, reinterpret_cast<uintptr_t>(*object), reinterpret_cast<uintptr_t>(*key2));
ASSERT_TRUE(flag->BooleaValue(vm_));
flag = JSNApi::NapiHasProperty(vm_, reinterpret_cast<uintptr_t>(*object), reinterpret_cast<uintptr_t>(*key));
ASSERT_FALSE(flag->BooleaValue(vm_));
flag = JSNApi::NapiHasProperty(vm_, reinterpret_cast<uintptr_t>(*object), reinterpret_cast<uintptr_t>(*key2));
ASSERT_FALSE(flag->BooleaValue(vm_));
}
HWTEST_F_L0(JSNApiTests, NapiTryFastHasMethodTest)
{
LocalScope scope(vm_);
auto array = JSArray::ArrayCreate(thread_, JSTaggedNumber(0));
auto arr = JSNApiHelper::ToLocal<ObjectRef>(array);
const char* utf8Key = "concat";
Local<JSValueRef> key3 = StringRef::NewFromUtf8(vm_, utf8Key);
auto flag = JSNApi::NapiHasProperty(vm_, reinterpret_cast<uintptr_t>(*arr), reinterpret_cast<uintptr_t>(*key3));
ASSERT_TRUE(flag->BooleaValue(vm_));
}
HWTEST_F_L0(JSNApiTests, NapiCallsiteInfoCreateDelete)
{
LocalScope scope(vm_);
thread_->ClearException();
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
JSNApi::NapiDeleteCallsiteInfo(vm_, 0);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastWithCallsiteInfo)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> keyA = StringRef::NewFromUtf8(vm_, "fastKeyA");
Local<JSValueRef> keyB = StringRef::NewFromUtf8(vm_, "fastKeyB");
Local<JSValueRef> valueA = IntegerRef::New(vm_, 11);
Local<JSValueRef> valueB = IntegerRef::New(vm_, 22);
ASSERT_TRUE(object->Set(vm_, keyA, valueA));
ASSERT_TRUE(object->Set(vm_, keyB, valueB));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
uintptr_t keyAAddr = reinterpret_cast<uintptr_t>(*keyA);
uintptr_t keyBAddr = reinterpret_cast<uintptr_t>(*keyB);
bool hit = true;
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAAddr, info, &hit);
EXPECT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 11);
EXPECT_FALSE(hit);
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAAddr, info, &hit);
EXPECT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 11);
EXPECT_TRUE(hit);
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyBAddr, info);
EXPECT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 22);
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAAddr, info);
EXPECT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 11);
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAAddr, info, nullptr);
EXPECT_TRUE(res->IsNumber());
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastWithCallsiteInfo)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> keyA = StringRef::NewFromUtf8(vm_, "setKeyA");
Local<JSValueRef> keyB = StringRef::NewFromUtf8(vm_, "setKeyB");
ASSERT_TRUE(object->Set(vm_, keyA, IntegerRef::New(vm_, 1)));
ASSERT_TRUE(object->Set(vm_, keyB, IntegerRef::New(vm_, 2)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
uintptr_t keyAAddr = reinterpret_cast<uintptr_t>(*keyA);
uintptr_t keyBAddr = reinterpret_cast<uintptr_t>(*keyB);
Local<JSValueRef> setValueA = IntegerRef::New(vm_, 101);
Local<JSValueRef> setValueB = IntegerRef::New(vm_, 202);
Local<JSValueRef> setValueA2 = IntegerRef::New(vm_, 303);
bool setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, keyAAddr,
reinterpret_cast<uintptr_t>(*setValueA), info);
EXPECT_TRUE(setRes);
setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, keyBAddr,
reinterpret_cast<uintptr_t>(*setValueB), info);
EXPECT_TRUE(setRes);
setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, keyAAddr,
reinterpret_cast<uintptr_t>(*setValueA2), info);
EXPECT_TRUE(setRes);
Local<JSValueRef> valueA = object->Get(vm_, keyA);
Local<JSValueRef> valueB = object->Get(vm_, keyB);
EXPECT_TRUE(valueA->IsNumber());
EXPECT_TRUE(valueB->IsNumber());
EXPECT_EQ(valueA->Int32Value(vm_), 303);
EXPECT_EQ(valueB->Int32Value(vm_), 202);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastTier1StoreHit)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "tier1StoreKey");
Local<JSValueRef> setValue1 = IntegerRef::New(vm_, 1001);
Local<JSValueRef> setValue2 = IntegerRef::New(vm_, 1002);
ASSERT_TRUE(object->Set(vm_, key, IntegerRef::New(vm_, 0)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
bool hit = true;
bool setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr,
reinterpret_cast<uintptr_t>(*setValue1), info, &hit);
ASSERT_TRUE(setRes);
EXPECT_FALSE(hit);
EXPECT_EQ(object->Get(vm_, key)->Int32Value(vm_), 1001);
setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr,
reinterpret_cast<uintptr_t>(*setValue2), info, &hit);
ASSERT_TRUE(setRes);
EXPECT_TRUE(hit);
EXPECT_EQ(object->Get(vm_, key)->Int32Value(vm_), 1002);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastInvalidReceiver)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<JSValueRef> invalidObj = IntegerRef::New(vm_, 1);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "invalidReceiverKey");
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*invalidObj),
reinterpret_cast<uintptr_t>(*key), 0);
ASSERT_TRUE(res->IsHole());
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastInvalidReceiver)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<JSValueRef> invalidObj = IntegerRef::New(vm_, 1);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "invalidReceiverKey");
Local<JSValueRef> value = IntegerRef::New(vm_, 1);
bool setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*invalidObj),
reinterpret_cast<uintptr_t>(*key), reinterpret_cast<uintptr_t>(*value), 0);
ASSERT_FALSE(setRes);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastFunctionReceiverWithCallsiteInfo)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<FunctionRef> function = FunctionRef::New(vm_, FunctionCallback);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "funcFastGetKey");
Local<JSValueRef> value = IntegerRef::New(vm_, 123);
ASSERT_TRUE(function->Set(vm_, key, value));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t functionAddr = reinterpret_cast<uintptr_t>(*function);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, functionAddr, keyAddr, info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 123);
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, functionAddr, keyAddr, info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 123);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastFunctionReceiverWithCallsiteInfo)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<FunctionRef> function = FunctionRef::New(vm_, FunctionCallback);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "funcFastSetKey");
Local<JSValueRef> value1 = IntegerRef::New(vm_, 456);
Local<JSValueRef> value2 = IntegerRef::New(vm_, 789);
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t functionAddr = reinterpret_cast<uintptr_t>(*function);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
bool setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, functionAddr, keyAddr,
reinterpret_cast<uintptr_t>(*value1), info);
ASSERT_TRUE(setRes);
EXPECT_EQ(function->Get(vm_, key)->Int32Value(vm_), 456);
setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, functionAddr, keyAddr,
reinterpret_cast<uintptr_t>(*value2), info);
ASSERT_TRUE(setRes);
EXPECT_EQ(function->Get(vm_, key)->Int32Value(vm_), 789);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastInfoVariants)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "infoVariantKey");
Local<JSValueRef> value = IntegerRef::New(vm_, 66);
ASSERT_TRUE(object->Set(vm_, key, value));
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, 0);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 66);
JSTaggedValue fakeInfo = JSTaggedValue::Undefined();
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, reinterpret_cast<uintptr_t>(&fakeInfo));
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 66);
ASSERT_FALSE(thread_->HasPendingException());
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastInfoVariants)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "setInfoVariantKey");
Local<JSValueRef> initValue = IntegerRef::New(vm_, 10);
Local<JSValueRef> setValue1 = IntegerRef::New(vm_, 111);
Local<JSValueRef> setValue2 = IntegerRef::New(vm_, 222);
ASSERT_TRUE(object->Set(vm_, key, initValue));
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
bool setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr,
reinterpret_cast<uintptr_t>(*setValue1), 0);
ASSERT_TRUE(setRes);
EXPECT_EQ(object->Get(vm_, key)->Int32Value(vm_), 111);
JSTaggedValue fakeInfo = JSTaggedValue::Undefined();
setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr,
reinterpret_cast<uintptr_t>(*setValue2), reinterpret_cast<uintptr_t>(&fakeInfo));
ASSERT_TRUE(setRes);
EXPECT_EQ(object->Get(vm_, key)->Int32Value(vm_), 222);
ASSERT_FALSE(thread_->HasPendingException());
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastEquivalentStringKeysKeepMono)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<StringRef> initKey = StringRef::NewFromUtf8WithoutStringTable(vm_, "equivalentGetKey");
ASSERT_TRUE(object->Set(vm_, initKey, IntegerRef::New(vm_, 77)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
Local<StringRef> key1 = StringRef::NewFromUtf8WithoutStringTable(vm_, "equivalentGetKey");
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(
vm_, objectAddr, reinterpret_cast<uintptr_t>(*key1), info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 77);
Local<StringRef> key2 = StringRef::NewFromUtf8WithoutStringTable(vm_, "equivalentGetKey");
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, reinterpret_cast<uintptr_t>(*key2), info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 77);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::LoadIC), IcAccessor::ICState::MONO);
JSTaggedValue infoVal = *reinterpret_cast<JSTaggedValue *>(info);
ICInfo *callsiteInfo = ICInfo::Cast(infoVal.GetTaggedObject());
EXPECT_FALSE(callsiteInfo->GetIcSlot(thread_, 0).IsHole());
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastEquivalentStringKeysKeepMono)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<StringRef> initKey = StringRef::NewFromUtf8WithoutStringTable(vm_, "equivalentSetKey");
ASSERT_TRUE(object->Set(vm_, initKey, IntegerRef::New(vm_, 0)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
Local<StringRef> key1 = StringRef::NewFromUtf8WithoutStringTable(vm_, "equivalentSetKey");
bool setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, reinterpret_cast<uintptr_t>(*key1),
reinterpret_cast<uintptr_t>(*IntegerRef::New(vm_, 101)), info);
ASSERT_TRUE(setRes);
Local<StringRef> key2 = StringRef::NewFromUtf8WithoutStringTable(vm_, "equivalentSetKey");
setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, reinterpret_cast<uintptr_t>(*key2),
reinterpret_cast<uintptr_t>(*IntegerRef::New(vm_, 202)), info);
ASSERT_TRUE(setRes);
EXPECT_EQ(object->Get(vm_, initKey)->Int32Value(vm_), 202);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::StoreIC), IcAccessor::ICState::MONO);
JSTaggedValue infoVal = *reinterpret_cast<JSTaggedValue *>(info);
ICInfo *callsiteInfo = ICInfo::Cast(infoVal.GetTaggedObject());
EXPECT_FALSE(callsiteInfo->GetIcSlot(thread_, 0).IsHole());
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastNumericKeyGoesViaElementIC)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> initKey = IntegerRef::New(vm_, 0);
ASSERT_TRUE(object->Set(vm_, initKey, IntegerRef::New(vm_, 9)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
Local<JSValueRef> key1 = IntegerRef::New(vm_, 0);
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(
vm_, objectAddr, reinterpret_cast<uintptr_t>(*key1), info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 9);
Local<JSValueRef> key2 = IntegerRef::New(vm_, 0);
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, reinterpret_cast<uintptr_t>(*key2), info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 9);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::LoadIC), IcAccessor::ICState::MONO);
JSTaggedValue infoVal = *reinterpret_cast<JSTaggedValue *>(info);
ICInfo *callsiteInfo = ICInfo::Cast(infoVal.GetTaggedObject());
EXPECT_TRUE(callsiteInfo->GetIcSlot(thread_, 0).IsWeak());
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastNumericKeyGoesViaElementIC)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> initKey = IntegerRef::New(vm_, 0);
ASSERT_TRUE(object->Set(vm_, initKey, IntegerRef::New(vm_, 0)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
Local<JSValueRef> key1 = IntegerRef::New(vm_, 0);
bool setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, reinterpret_cast<uintptr_t>(*key1),
reinterpret_cast<uintptr_t>(*IntegerRef::New(vm_, 17)), info);
ASSERT_TRUE(setRes);
Local<JSValueRef> key2 = IntegerRef::New(vm_, 0);
setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, reinterpret_cast<uintptr_t>(*key2),
reinterpret_cast<uintptr_t>(*IntegerRef::New(vm_, 29)), info);
ASSERT_TRUE(setRes);
EXPECT_EQ(object->Get(vm_, initKey)->Int32Value(vm_), 29);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::StoreIC), IcAccessor::ICState::MONO);
JSTaggedValue infoVal = *reinterpret_cast<JSTaggedValue *>(info);
ICInfo *callsiteInfo = ICInfo::Cast(infoVal.GetTaggedObject());
EXPECT_TRUE(callsiteInfo->GetIcSlot(thread_, 0).IsWeak());
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastSymbolKeyWithCallsiteInfo)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<StringRef> desc = StringRef::NewFromUtf8(vm_, "symbolHeapInfoDesc");
Local<JSValueRef> symbolKey = SymbolRef::New(vm_, desc);
Local<JSValueRef> symbolValue = IntegerRef::New(vm_, 21);
ASSERT_TRUE(object->Set(vm_, symbolKey, symbolValue));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*symbolKey);
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 21);
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 21);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastIntegerKeyHitsElementIC)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> intKey = IntegerRef::New(vm_, 5);
ASSERT_TRUE(object->Set(vm_, intKey, IntegerRef::New(vm_, 42)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*object),
reinterpret_cast<uintptr_t>(*intKey), info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 42);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::LoadIC), IcAccessor::ICState::MONO);
JSTaggedValue infoVal = *reinterpret_cast<JSTaggedValue *>(info);
ICInfo *callsiteInfo = ICInfo::Cast(infoVal.GetTaggedObject());
EXPECT_TRUE(callsiteInfo->GetIcSlot(thread_, 0).IsWeak());
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastElementIndexStringKey)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> intKey = IntegerRef::New(vm_, 0);
ASSERT_TRUE(object->Set(vm_, intKey, IntegerRef::New(vm_, 77)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
Local<JSValueRef> strKey = StringRef::NewFromUtf8(vm_, "0");
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr,
reinterpret_cast<uintptr_t>(*strKey), info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 77);
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr,
reinterpret_cast<uintptr_t>(*strKey), info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 77);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::LoadIC), IcAccessor::ICState::MONO);
JSTaggedValue infoVal = *reinterpret_cast<JSTaggedValue *>(info);
ICInfo *callsiteInfo = ICInfo::Cast(infoVal.GetTaggedObject());
EXPECT_TRUE(callsiteInfo->GetIcSlot(thread_, 0).IsWeak());
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastElementIndexStringKey)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> intKey = IntegerRef::New(vm_, 0);
ASSERT_TRUE(object->Set(vm_, intKey, IntegerRef::New(vm_, 0)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
Local<JSValueRef> strKey = StringRef::NewFromUtf8(vm_, "0");
bool setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, reinterpret_cast<uintptr_t>(*strKey),
reinterpret_cast<uintptr_t>(*IntegerRef::New(vm_, 88)), info);
ASSERT_TRUE(setRes);
EXPECT_EQ(object->Get(vm_, intKey)->Int32Value(vm_), 88);
setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, reinterpret_cast<uintptr_t>(*strKey),
reinterpret_cast<uintptr_t>(*IntegerRef::New(vm_, 99)), info);
ASSERT_TRUE(setRes);
EXPECT_EQ(object->Get(vm_, intKey)->Int32Value(vm_), 99);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::StoreIC), IcAccessor::ICState::MONO);
JSTaggedValue infoVal = *reinterpret_cast<JSTaggedValue *>(info);
ICInfo *callsiteInfo = ICInfo::Cast(infoVal.GetTaggedObject());
EXPECT_TRUE(callsiteInfo->GetIcSlot(thread_, 0).IsWeak());
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastSymbolKeyViaKeyIC)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<StringRef> desc = StringRef::NewFromUtf8(vm_, "keyICSymbol");
Local<JSValueRef> symKey = SymbolRef::New(vm_, desc);
ASSERT_TRUE(object->Set(vm_, symKey, IntegerRef::New(vm_, 123)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*symKey);
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 123);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::LoadIC), IcAccessor::ICState::MONO);
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 123);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::LoadIC), IcAccessor::ICState::MONO);
JSTaggedValue infoVal = *reinterpret_cast<JSTaggedValue *>(info);
ICInfo *callsiteInfo = ICInfo::Cast(infoVal.GetTaggedObject());
EXPECT_TRUE(callsiteInfo->GetIcSlot(thread_, 0).IsSymbol());
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastMixedKeyTypes)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> intKey = IntegerRef::New(vm_, 0);
Local<JSValueRef> strKey = StringRef::NewFromUtf8(vm_, "mixedKey");
ASSERT_TRUE(object->Set(vm_, intKey, IntegerRef::New(vm_, 10)));
ASSERT_TRUE(object->Set(vm_, strKey, IntegerRef::New(vm_, 20)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr,
reinterpret_cast<uintptr_t>(*intKey), info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 10);
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr,
reinterpret_cast<uintptr_t>(*strKey), info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 20);
auto state = GetCallsiteState(thread_, info, ICKind::LoadIC);
ASSERT_TRUE(state == IcAccessor::ICState::MEGA ||
state == IcAccessor::ICState::IC_MEGA);
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr,
reinterpret_cast<uintptr_t>(*intKey), info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 10);
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr,
reinterpret_cast<uintptr_t>(*strKey), info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 20);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastSameContentDifferentPointer)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<StringRef> initKey = StringRef::NewFromUtf8(vm_, "contentKey");
ASSERT_TRUE(object->Set(vm_, initKey, IntegerRef::New(vm_, 55)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
Local<StringRef> key1 = StringRef::NewFromUtf8WithoutStringTable(vm_, "contentKey");
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr,
reinterpret_cast<uintptr_t>(*key1), info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 55);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::LoadIC), IcAccessor::ICState::MONO);
Local<StringRef> key2 = StringRef::NewFromUtf8WithoutStringTable(vm_, "contentKey");
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, reinterpret_cast<uintptr_t>(*key2), info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 55);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::LoadIC), IcAccessor::ICState::MONO);
JSTaggedValue infoVal = *reinterpret_cast<JSTaggedValue *>(info);
ICInfo *callsiteInfo = ICInfo::Cast(infoVal.GetTaggedObject());
EXPECT_TRUE(callsiteInfo->GetIcSlot(thread_, 0).IsString());
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastStaleICFallsBack)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object1 = ObjectRef::New(vm_);
Local<ObjectRef> object2 = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "staleLoadKey");
Local<JSValueRef> extraKey = StringRef::NewFromUtf8(vm_, "extraKey");
ASSERT_TRUE(object1->Set(vm_, key, IntegerRef::New(vm_, 101)));
ASSERT_TRUE(object2->Set(vm_, key, IntegerRef::New(vm_, 202)));
ASSERT_TRUE(object2->Set(vm_, extraKey, IntegerRef::New(vm_, 303)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(
vm_, reinterpret_cast<uintptr_t>(*object1), keyAddr, info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 101);
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*object2), keyAddr, info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 202);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastStaleICFallsBack)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object1 = ObjectRef::New(vm_);
Local<ObjectRef> object2 = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "staleStoreKey");
Local<JSValueRef> extraKey = StringRef::NewFromUtf8(vm_, "extraKey");
Local<JSValueRef> setValue1 = IntegerRef::New(vm_, 111);
Local<JSValueRef> setValue2 = IntegerRef::New(vm_, 222);
ASSERT_TRUE(object1->Set(vm_, key, IntegerRef::New(vm_, 1)));
ASSERT_TRUE(object2->Set(vm_, key, IntegerRef::New(vm_, 2)));
ASSERT_TRUE(object2->Set(vm_, extraKey, IntegerRef::New(vm_, 3)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
bool setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*object1),
keyAddr, reinterpret_cast<uintptr_t>(*setValue1), info);
ASSERT_TRUE(setRes);
setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*object2),
keyAddr, reinterpret_cast<uintptr_t>(*setValue2), info);
ASSERT_TRUE(setRes);
EXPECT_EQ(object2->Get(vm_, key)->Int32Value(vm_), 222);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastPrototypeChain)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> proto = ObjectRef::New(vm_);
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "protoKey");
Local<JSValueRef> value = IntegerRef::New(vm_, 333);
ASSERT_TRUE(proto->Set(vm_, key, value));
ASSERT_TRUE(object->SetPrototype(vm_, proto));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*object),
reinterpret_cast<uintptr_t>(*key), info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 333);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastPrototypeChainBaselineFallback)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> proto = ObjectRef::New(vm_);
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "protoFallbackKey");
Local<JSValueRef> value = IntegerRef::New(vm_, 334);
ASSERT_TRUE(proto->Set(vm_, key, value));
ASSERT_TRUE(object->SetPrototype(vm_, proto));
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, 0);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 334);
JSTaggedValue fakeInfo = JSTaggedValue::Undefined();
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, reinterpret_cast<uintptr_t>(&fakeInfo));
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 334);
ASSERT_FALSE(thread_->HasPendingException());
}
HWTEST_F_L0(JSNApiTests, NapiCreateCallsiteInfoWithPendingException)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<JSValueRef> error = Exception::Error(vm_, StringRef::NewFromUtf8(vm_, ERROR_MESSAGE));
ASSERT_TRUE(error->IsError(vm_));
JSNApi::ThrowException(vm_, error);
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
EXPECT_EQ(info, 0U);
thread_->ClearException();
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastWithPendingException)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "pendingGetKey");
ASSERT_TRUE(object->Set(vm_, key, IntegerRef::New(vm_, 88)));
Local<JSValueRef> error = Exception::Error(vm_, StringRef::NewFromUtf8(vm_, ERROR_MESSAGE));
ASSERT_TRUE(error->IsError(vm_));
JSNApi::ThrowException(vm_, error);
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*object),
reinterpret_cast<uintptr_t>(*key), 0);
EXPECT_TRUE(res->IsUndefined());
thread_->ClearException();
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastWithPendingException)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "pendingSetKey");
ASSERT_TRUE(object->Set(vm_, key, IntegerRef::New(vm_, 1)));
Local<JSValueRef> value = IntegerRef::New(vm_, 99);
Local<JSValueRef> error = Exception::Error(vm_, StringRef::NewFromUtf8(vm_, ERROR_MESSAGE));
ASSERT_TRUE(error->IsError(vm_));
JSNApi::ThrowException(vm_, error);
bool res = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*object),
reinterpret_cast<uintptr_t>(*key), reinterpret_cast<uintptr_t>(*value), 0);
EXPECT_FALSE(res);
thread_->ClearException();
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastDictionaryCachedKeyWithoutICSlot)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "dictLoadKey");
ASSERT_TRUE(object->Set(vm_, key, IntegerRef::New(vm_, 1234)));
JSHandle<JSObject> jsObj(JSNApiHelper::ToJSHandle(object));
JSObject::TransitionToDictionary(thread_, jsObj);
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
Local<JSValueRef> first = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
ASSERT_TRUE(first->IsNumber());
EXPECT_EQ(first->Int32Value(vm_), 1234);
Local<JSValueRef> second = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
ASSERT_TRUE(second->IsNumber());
EXPECT_EQ(second->Int32Value(vm_), 1234);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastDictionaryCachedKeyWithoutICSlot)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "dictStoreKey");
ASSERT_TRUE(object->Set(vm_, key, IntegerRef::New(vm_, 10)));
JSHandle<JSObject> jsObj(JSNApiHelper::ToJSHandle(object));
JSObject::TransitionToDictionary(thread_, jsObj);
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
Local<JSValueRef> value1 = IntegerRef::New(vm_, 1010);
Local<JSValueRef> value2 = IntegerRef::New(vm_, 2020);
bool setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr,
reinterpret_cast<uintptr_t>(*value1), info);
ASSERT_TRUE(setRes);
EXPECT_EQ(object->Get(vm_, key)->Int32Value(vm_), 1010);
setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(
vm_, objectAddr, keyAddr, reinterpret_cast<uintptr_t>(*value2), info);
ASSERT_TRUE(setRes);
EXPECT_EQ(object->Get(vm_, key)->Int32Value(vm_), 2020);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastTypedArrayGenericFallback)
{
LocalScope scope(vm_);
thread_->ClearException();
constexpr uint32_t length = 8;
Local<ArrayBufferRef> buffer = ArrayBufferRef::New(vm_, length);
Local<Uint8ArrayRef> typedArray = Uint8ArrayRef::New(vm_, buffer, 0, length);
Local<JSValueRef> maxIndexKey = StringRef::NewFromUtf8(vm_, "4294967295");
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*typedArray),
reinterpret_cast<uintptr_t>(*maxIndexKey), info);
EXPECT_TRUE(res->IsUndefined());
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastAccessorThrows)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "throwingGetterKey");
Local<FunctionRef> getter = FunctionRef::New(vm_, ThrowingAccessorCallback);
Local<FunctionRef> setter = FunctionRef::New(vm_, UndefinedAccessorCallback);
ASSERT_TRUE(object->SetAccessorProperty(vm_, key, getter, setter));
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*object),
reinterpret_cast<uintptr_t>(*key), 0);
EXPECT_TRUE(res->IsUndefined());
EXPECT_TRUE(thread_->HasPendingException());
thread_->ClearException();
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastPrototypeAccessorThrows)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> proto = ObjectRef::New(vm_);
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "throwingProtoGetterKey");
Local<FunctionRef> getter = FunctionRef::New(vm_, ThrowingAccessorCallback);
Local<FunctionRef> setter = FunctionRef::New(vm_, UndefinedAccessorCallback);
ASSERT_TRUE(proto->SetAccessorProperty(vm_, key, getter, setter));
ASSERT_TRUE(object->SetPrototype(vm_, proto));
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*object),
reinterpret_cast<uintptr_t>(*key), 0);
EXPECT_TRUE(res->IsUndefined());
EXPECT_TRUE(thread_->HasPendingException());
thread_->ClearException();
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastAccessorSetterThrows)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "throwingSetterKey");
Local<FunctionRef> getter = FunctionRef::New(vm_, UndefinedAccessorCallback);
Local<FunctionRef> setter = FunctionRef::New(vm_, ThrowingAccessorCallback);
ASSERT_TRUE(object->SetAccessorProperty(vm_, key, getter, setter));
Local<JSValueRef> value = IntegerRef::New(vm_, 42);
bool res = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*object),
reinterpret_cast<uintptr_t>(*key), reinterpret_cast<uintptr_t>(*value), 0);
EXPECT_FALSE(res);
EXPECT_TRUE(thread_->HasPendingException());
thread_->ClearException();
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastTier1AccessorThrows)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "tier1AccessorGetKey");
Local<FunctionRef> getter = FunctionRef::New(vm_, ConditionalThrowingGetterCallback);
Local<FunctionRef> setter = FunctionRef::New(vm_, UndefinedAccessorCallback);
ASSERT_TRUE(object->SetAccessorProperty(vm_, key, getter, setter));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
g_throwInFastLoadIc = false;
Local<JSValueRef> first = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
ASSERT_TRUE(first->IsNumber());
EXPECT_EQ(first->Int32Value(vm_), 123);
EXPECT_FALSE(thread_->HasPendingException());
g_throwInFastLoadIc = true;
Local<JSValueRef> second = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
EXPECT_TRUE(second->IsUndefined());
EXPECT_TRUE(thread_->HasPendingException());
thread_->ClearException();
g_throwInFastLoadIc = false;
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastTier1AccessorThrows)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "tier1AccessorSetKey");
Local<FunctionRef> getter = FunctionRef::New(vm_, UndefinedAccessorCallback);
Local<FunctionRef> setter = FunctionRef::New(vm_, ConditionalThrowingSetterCallback);
ASSERT_TRUE(object->SetAccessorProperty(vm_, key, getter, setter));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
Local<JSValueRef> value1 = IntegerRef::New(vm_, 1);
Local<JSValueRef> value2 = IntegerRef::New(vm_, 2);
g_throwInFastStoreIc = false;
bool first = JSNApi::NapiSetPropertyWithCallsiteInfo(
vm_, objectAddr, keyAddr, reinterpret_cast<uintptr_t>(*value1), info);
ASSERT_TRUE(first);
EXPECT_FALSE(thread_->HasPendingException());
g_throwInFastStoreIc = true;
bool second = JSNApi::NapiSetPropertyWithCallsiteInfo(
vm_, objectAddr, keyAddr, reinterpret_cast<uintptr_t>(*value2), info);
EXPECT_FALSE(second);
EXPECT_TRUE(thread_->HasPendingException());
thread_->ClearException();
g_throwInFastStoreIc = false;
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastTier2AccessorNoThrow)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "tier2AccessorGetNoThrow");
Local<FunctionRef> getter = FunctionRef::New(vm_, StableGetterCallback);
Local<FunctionRef> setter = FunctionRef::New(vm_, UndefinedAccessorCallback);
ASSERT_TRUE(object->SetAccessorProperty(vm_, key, getter, setter));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
g_nonThrowingGetterValue = 512;
Local<JSValueRef> first = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
ASSERT_TRUE(first->IsNumber());
EXPECT_EQ(first->Int32Value(vm_), 512);
EXPECT_FALSE(thread_->HasPendingException());
Local<JSValueRef> second = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
ASSERT_TRUE(second->IsNumber());
EXPECT_EQ(second->Int32Value(vm_), 512);
EXPECT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastTier2AccessorNoThrow)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "tier2AccessorSetNoThrow");
Local<FunctionRef> getter = FunctionRef::New(vm_, UndefinedAccessorCallback);
Local<FunctionRef> setter = FunctionRef::New(vm_, RecordingSetterCallback);
ASSERT_TRUE(object->SetAccessorProperty(vm_, key, getter, setter));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
Local<JSValueRef> value1 = IntegerRef::New(vm_, 700);
Local<JSValueRef> value2 = IntegerRef::New(vm_, 701);
g_lastSetterValue = -1;
g_setterCallCount = 0;
bool first = JSNApi::NapiSetPropertyWithCallsiteInfo(
vm_, objectAddr, keyAddr, reinterpret_cast<uintptr_t>(*value1), info);
ASSERT_TRUE(first);
EXPECT_FALSE(thread_->HasPendingException());
EXPECT_EQ(g_setterCallCount, 1U);
EXPECT_EQ(g_lastSetterValue, 700);
bool second = JSNApi::NapiSetPropertyWithCallsiteInfo(
vm_, objectAddr, keyAddr, reinterpret_cast<uintptr_t>(*value2), info);
ASSERT_TRUE(second);
EXPECT_FALSE(thread_->HasPendingException());
EXPECT_EQ(g_setterCallCount, 2U);
EXPECT_EQ(g_lastSetterValue, 701);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastMonoPolyMegaTransition)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "icTransitionGetKey");
const char *extraKeys[] = {"shapeGetA", "shapeGetB", "shapeGetC", "shapeGetD", "shapeGetE",
"shapeGetF", "shapeGetG", "shapeGetH"};
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::LoadIC), IcAccessor::ICState::UNINIT);
for (uint32_t i = 0; i < IcAccessor::POLY_CASE_NUM + 4; i++) {
Local<ObjectRef> object = ObjectRef::New(vm_);
ASSERT_TRUE(object->Set(vm_, key, IntegerRef::New(vm_, static_cast<int32_t>(100 + i))));
Local<JSValueRef> extraKey = StringRef::NewFromUtf8(vm_, extraKeys[i]);
ASSERT_TRUE(object->Set(vm_, extraKey, IntegerRef::New(vm_, static_cast<int32_t>(i))));
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*object),
reinterpret_cast<uintptr_t>(*key), info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), static_cast<int32_t>(100 + i));
auto state = GetCallsiteState(thread_, info, ICKind::LoadIC);
VerifyICStateTransition(state, i);
}
JSTaggedValue infoVal = *reinterpret_cast<JSTaggedValue *>(info);
ICInfo *callsiteInfo = ICInfo::Cast(infoVal.GetTaggedObject());
EXPECT_TRUE(callsiteInfo->GetIcSlot(thread_, 0).IsHole());
auto finalState = GetCallsiteState(thread_, info, ICKind::LoadIC);
if (finalState == IcAccessor::ICState::IC_MEGA) {
EXPECT_TRUE(callsiteInfo->GetIcSlot(thread_, 1).IsString());
} else {
EXPECT_TRUE(callsiteInfo->GetIcSlot(thread_, 1).IsHole());
}
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastMonoPolyMegaTransition)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "icTransitionSetKey");
const char *extraKeys[] = {"shapeSetA", "shapeSetB", "shapeSetC", "shapeSetD", "shapeSetE",
"shapeSetF", "shapeSetG", "shapeSetH"};
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::StoreIC), IcAccessor::ICState::UNINIT);
for (uint32_t i = 0; i < IcAccessor::POLY_CASE_NUM + 4; i++) {
Local<ObjectRef> object = ObjectRef::New(vm_);
ASSERT_TRUE(object->Set(vm_, key, IntegerRef::New(vm_, 0)));
Local<JSValueRef> extraKey = StringRef::NewFromUtf8(vm_, extraKeys[i]);
ASSERT_TRUE(object->Set(vm_, extraKey, IntegerRef::New(vm_, static_cast<int32_t>(i))));
Local<JSValueRef> value = IntegerRef::New(vm_, static_cast<int32_t>(1000 + i));
bool setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*object),
reinterpret_cast<uintptr_t>(*key), reinterpret_cast<uintptr_t>(*value), info);
ASSERT_TRUE(setRes);
EXPECT_EQ(object->Get(vm_, key)->Int32Value(vm_), static_cast<int32_t>(1000 + i));
auto state = GetCallsiteState(thread_, info, ICKind::StoreIC);
VerifyICStateTransition(state, i);
}
JSTaggedValue infoVal = *reinterpret_cast<JSTaggedValue *>(info);
ICInfo *callsiteInfo = ICInfo::Cast(infoVal.GetTaggedObject());
EXPECT_TRUE(callsiteInfo->GetIcSlot(thread_, 0).IsHole());
auto finalState = GetCallsiteState(thread_, info, ICKind::StoreIC);
if (finalState == IcAccessor::ICState::IC_MEGA) {
EXPECT_TRUE(callsiteInfo->GetIcSlot(thread_, 1).IsString());
} else {
EXPECT_TRUE(callsiteInfo->GetIcSlot(thread_, 1).IsHole());
}
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastParityWithInterpreterMatrix)
{
LocalScope scope(vm_);
thread_->ClearException();
auto runSlowGet = [this](Local<JSValueRef> obj, Local<JSValueRef> key) {
thread_->ClearException();
Local<JSValueRef> result = JSNApi::NapiGetProperty(vm_, reinterpret_cast<uintptr_t>(*obj),
reinterpret_cast<uintptr_t>(*key));
bool hasException = thread_->HasPendingException();
if (hasException) {
thread_->ClearException();
}
return std::pair<Local<JSValueRef>, bool>(result, hasException);
};
auto runFastGet = [this](Local<JSValueRef> obj, Local<JSValueRef> key, uintptr_t info) {
thread_->ClearException();
Local<JSValueRef> result = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*obj),
reinterpret_cast<uintptr_t>(*key), info);
bool hasException = thread_->HasPendingException();
if (hasException) {
thread_->ClearException();
}
return std::pair<Local<JSValueRef>, bool>(result, hasException);
};
auto expectParity = [this, &runSlowGet, &runFastGet](
Local<JSValueRef> slowObj, Local<JSValueRef> fastObj,
Local<JSValueRef> key, uintptr_t info) {
auto [slowResult, slowEx] = runSlowGet(slowObj, key);
auto [fastResult, fastEx] = runFastGet(fastObj, key, info);
EXPECT_EQ(slowEx, fastEx);
if (!slowEx) {
EXPECT_TRUE(slowResult->IsStrictEquals(vm_, fastResult));
} else {
EXPECT_TRUE(slowResult->IsUndefined());
EXPECT_TRUE(fastResult->IsUndefined());
}
};
{
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "parityOwnKey");
Local<JSValueRef> value = IntegerRef::New(vm_, 101);
ASSERT_TRUE(slowObj->Set(vm_, key, value));
ASSERT_TRUE(fastObj->Set(vm_, key, value));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
expectParity(slowObj, fastObj, key, info);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
{
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "parityMissingKey");
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
expectParity(slowObj, fastObj, key, info);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
{
Local<ObjectRef> slowProto = ObjectRef::New(vm_);
Local<ObjectRef> fastProto = ObjectRef::New(vm_);
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "parityProtoKey");
Local<JSValueRef> value = IntegerRef::New(vm_, 202);
ASSERT_TRUE(slowProto->Set(vm_, key, value));
ASSERT_TRUE(fastProto->Set(vm_, key, value));
ASSERT_TRUE(slowObj->SetPrototype(vm_, slowProto));
ASSERT_TRUE(fastObj->SetPrototype(vm_, fastProto));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
expectParity(slowObj, fastObj, key, info);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
{
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
Local<JSValueRef> symbolKey = SymbolRef::New(vm_, StringRef::NewFromUtf8(vm_, "paritySym"));
Local<JSValueRef> value = IntegerRef::New(vm_, 303);
ASSERT_TRUE(slowObj->Set(vm_, symbolKey, value));
ASSERT_TRUE(fastObj->Set(vm_, symbolKey, value));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
expectParity(slowObj, fastObj, symbolKey, info);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
{
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "parityAccessorKey");
Local<FunctionRef> getter = FunctionRef::New(vm_, StableGetterCallback);
Local<FunctionRef> setter = FunctionRef::New(vm_, UndefinedAccessorCallback);
ASSERT_TRUE(slowObj->SetAccessorProperty(vm_, key, getter, setter));
ASSERT_TRUE(fastObj->SetAccessorProperty(vm_, key, getter, setter));
g_nonThrowingGetterValue = 404;
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
expectParity(slowObj, fastObj, key, info);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
{
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "parityThrowAccessorKey");
Local<FunctionRef> getter = FunctionRef::New(vm_, ThrowingAccessorCallback);
Local<FunctionRef> setter = FunctionRef::New(vm_, UndefinedAccessorCallback);
ASSERT_TRUE(slowObj->SetAccessorProperty(vm_, key, getter, setter));
ASSERT_TRUE(fastObj->SetAccessorProperty(vm_, key, getter, setter));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
expectParity(slowObj, fastObj, key, info);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
{
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "parityDictKey");
Local<JSValueRef> value = IntegerRef::New(vm_, 505);
ASSERT_TRUE(slowObj->Set(vm_, key, value));
ASSERT_TRUE(fastObj->Set(vm_, key, value));
JSHandle<JSObject> slowJsObj(JSNApiHelper::ToJSHandle(slowObj));
JSHandle<JSObject> fastJsObj(JSNApiHelper::ToJSHandle(fastObj));
JSObject::TransitionToDictionary(thread_, slowJsObj);
JSObject::TransitionToDictionary(thread_, fastJsObj);
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
expectParity(slowObj, fastObj, key, info);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastParityWithInterpreterMatrix)
{
LocalScope scope(vm_);
thread_->ClearException();
auto runSlowSet = [this](Local<ObjectRef> obj, Local<JSValueRef> key, Local<JSValueRef> value) {
thread_->ClearException();
bool ok = obj->Set(vm_, key, value);
bool hasException = thread_->HasPendingException();
if (hasException) {
thread_->ClearException();
}
return std::pair<bool, bool>(ok, hasException);
};
auto runFastSet = [this](Local<ObjectRef> obj, Local<JSValueRef> key, Local<JSValueRef> value, uintptr_t info) {
thread_->ClearException();
bool ok = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*obj),
reinterpret_cast<uintptr_t>(*key), reinterpret_cast<uintptr_t>(*value), info);
bool hasException = thread_->HasPendingException();
if (hasException) {
thread_->ClearException();
}
return std::pair<bool, bool>(ok, hasException);
};
auto expectSetParity = [this, &runSlowSet, &runFastSet](
Local<ObjectRef> slowObj, Local<ObjectRef> fastObj,
Local<JSValueRef> key, Local<JSValueRef> value, uintptr_t info) {
auto [slowOk, slowEx] = runSlowSet(slowObj, key, value);
auto [fastOk, fastEx] = runFastSet(fastObj, key, value, info);
EXPECT_EQ(slowEx, fastEx);
if (!slowEx) {
EXPECT_TRUE(fastOk);
Local<JSValueRef> slowAfter = JSNApi::NapiGetProperty(vm_, reinterpret_cast<uintptr_t>(*slowObj),
reinterpret_cast<uintptr_t>(*key));
bool slowAfterEx = thread_->HasPendingException();
if (slowAfterEx) {
thread_->ClearException();
}
Local<JSValueRef> fastAfter = JSNApi::NapiGetProperty(vm_, reinterpret_cast<uintptr_t>(*fastObj),
reinterpret_cast<uintptr_t>(*key));
bool fastAfterEx = thread_->HasPendingException();
if (fastAfterEx) {
thread_->ClearException();
}
EXPECT_EQ(slowAfterEx, fastAfterEx);
if (!slowAfterEx) {
EXPECT_TRUE(slowAfter->IsStrictEquals(vm_, fastAfter));
}
if (!slowOk) {
EXPECT_TRUE(slowAfter->IsStrictEquals(vm_, fastAfter));
}
} else {
EXPECT_FALSE(fastOk);
}
};
{
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "setParityOwnKey");
ASSERT_TRUE(slowObj->Set(vm_, key, IntegerRef::New(vm_, 1)));
ASSERT_TRUE(fastObj->Set(vm_, key, IntegerRef::New(vm_, 1)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
expectSetParity(slowObj, fastObj, key, IntegerRef::New(vm_, 111), info);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
{
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "setParityNewKey");
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
expectSetParity(slowObj, fastObj, key, IntegerRef::New(vm_, 222), info);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
{
Local<ObjectRef> slowProto = ObjectRef::New(vm_);
Local<ObjectRef> fastProto = ObjectRef::New(vm_);
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "setParityProtoKey");
ASSERT_TRUE(slowProto->Set(vm_, key, IntegerRef::New(vm_, 10)));
ASSERT_TRUE(fastProto->Set(vm_, key, IntegerRef::New(vm_, 10)));
ASSERT_TRUE(slowObj->SetPrototype(vm_, slowProto));
ASSERT_TRUE(fastObj->SetPrototype(vm_, fastProto));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
expectSetParity(slowObj, fastObj, key, IntegerRef::New(vm_, 333), info);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
{
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
Local<JSValueRef> key = SymbolRef::New(vm_, StringRef::NewFromUtf8(vm_, "setParitySym"));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
expectSetParity(slowObj, fastObj, key, IntegerRef::New(vm_, 444), info);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
{
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "setParityAccessorKey");
Local<FunctionRef> getter = FunctionRef::New(vm_, UndefinedAccessorCallback);
Local<FunctionRef> setter = FunctionRef::New(vm_, RecordingSetterCallback);
ASSERT_TRUE(slowObj->SetAccessorProperty(vm_, key, getter, setter));
ASSERT_TRUE(fastObj->SetAccessorProperty(vm_, key, getter, setter));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
g_lastSetterValue = -1;
g_setterCallCount = 0;
expectSetParity(slowObj, fastObj, key, IntegerRef::New(vm_, 555), info);
EXPECT_GE(g_setterCallCount, 2U);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
{
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "setParityThrowAccessorKey");
Local<FunctionRef> getter = FunctionRef::New(vm_, UndefinedAccessorCallback);
Local<FunctionRef> setter = FunctionRef::New(vm_, ThrowingAccessorCallback);
ASSERT_TRUE(slowObj->SetAccessorProperty(vm_, key, getter, setter));
ASSERT_TRUE(fastObj->SetAccessorProperty(vm_, key, getter, setter));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
expectSetParity(slowObj, fastObj, key, IntegerRef::New(vm_, 666), info);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
{
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "setParityDictKey");
ASSERT_TRUE(slowObj->Set(vm_, key, IntegerRef::New(vm_, 1)));
ASSERT_TRUE(fastObj->Set(vm_, key, IntegerRef::New(vm_, 1)));
JSHandle<JSObject> slowJsObj(JSNApiHelper::ToJSHandle(slowObj));
JSHandle<JSObject> fastJsObj(JSNApiHelper::ToJSHandle(fastObj));
JSObject::TransitionToDictionary(thread_, slowJsObj);
JSObject::TransitionToDictionary(thread_, fastJsObj);
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
expectSetParity(slowObj, fastObj, key, IntegerRef::New(vm_, 777), info);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
{
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "setParityReadonlyKey");
Local<JSValueRef> init = IntegerRef::New(vm_, 9);
PropertyAttribute attr(init, false, true, true);
ASSERT_TRUE(slowObj->DefineProperty(vm_, key, attr));
ASSERT_TRUE(fastObj->DefineProperty(vm_, key, attr));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
expectSetParity(slowObj, fastObj, key, IntegerRef::New(vm_, 888), info);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastPostMegaSoakCorrectness)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "postMegaGetKey");
const char *shapeKeys[] = {
"pmgShape0", "pmgShape1", "pmgShape2", "pmgShape3", "pmgShape4", "pmgShape5", "pmgShape6"
};
constexpr int32_t warmupCount = 5;
constexpr int32_t soakCount = 200;
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
for (int32_t i = 0; i < warmupCount; i++) {
Local<ObjectRef> object = ObjectRef::New(vm_);
ASSERT_TRUE(object->Set(vm_, key, IntegerRef::New(vm_, i)));
ASSERT_TRUE(object->Set(vm_, StringRef::NewFromUtf8(vm_, shapeKeys[i]), IntegerRef::New(vm_, i)));
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*object),
reinterpret_cast<uintptr_t>(*key), info);
ASSERT_TRUE(res->IsNumber());
}
auto state = GetCallsiteState(thread_, info, ICKind::LoadIC);
ASSERT_TRUE(state == IcAccessor::ICState::MEGA || state == IcAccessor::ICState::IC_MEGA);
for (int32_t i = 0; i < soakCount; i++) {
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> expected = IntegerRef::New(vm_, 10000 + i);
ASSERT_TRUE(object->Set(vm_, key, expected));
ASSERT_TRUE(object->Set(vm_, StringRef::NewFromUtf8(vm_, shapeKeys[i % 7]), IntegerRef::New(vm_, i)));
thread_->ClearException();
Local<JSValueRef> slow = JSNApi::NapiGetProperty(vm_, reinterpret_cast<uintptr_t>(*object),
reinterpret_cast<uintptr_t>(*key));
bool slowEx = thread_->HasPendingException();
if (slowEx) {
thread_->ClearException();
}
thread_->ClearException();
Local<JSValueRef> fast = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*object),
reinterpret_cast<uintptr_t>(*key), info);
bool fastEx = thread_->HasPendingException();
if (fastEx) {
thread_->ClearException();
}
ASSERT_EQ(slowEx, fastEx);
ASSERT_FALSE(slowEx);
ASSERT_TRUE(slow->IsStrictEquals(vm_, fast));
if ((i % 40) == 0) {
auto runningState = GetCallsiteState(thread_, info, ICKind::LoadIC);
EXPECT_TRUE(runningState == IcAccessor::ICState::MEGA ||
runningState == IcAccessor::ICState::IC_MEGA);
}
}
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastPostMegaSoakCorrectness)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "postMegaSetKey");
const char *shapeKeys[] = {
"pmsShape0", "pmsShape1", "pmsShape2", "pmsShape3", "pmsShape4", "pmsShape5", "pmsShape6"
};
constexpr int32_t warmupCount = 5;
constexpr int32_t soakCount = 200;
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
for (int32_t i = 0; i < warmupCount; i++) {
Local<ObjectRef> object = ObjectRef::New(vm_);
ASSERT_TRUE(object->Set(vm_, key, IntegerRef::New(vm_, 0)));
ASSERT_TRUE(object->Set(vm_, StringRef::NewFromUtf8(vm_, shapeKeys[i]), IntegerRef::New(vm_, i)));
Local<JSValueRef> value = IntegerRef::New(vm_, i + 1);
bool res = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*object),
reinterpret_cast<uintptr_t>(*key), reinterpret_cast<uintptr_t>(*value), info);
ASSERT_TRUE(res);
}
auto state = GetCallsiteState(thread_, info, ICKind::StoreIC);
ASSERT_TRUE(state == IcAccessor::ICState::MEGA || state == IcAccessor::ICState::IC_MEGA);
for (int32_t i = 0; i < soakCount; i++) {
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
ASSERT_TRUE(slowObj->Set(vm_, key, IntegerRef::New(vm_, 0)));
ASSERT_TRUE(fastObj->Set(vm_, key, IntegerRef::New(vm_, 0)));
Local<JSValueRef> shapeKey = StringRef::NewFromUtf8(vm_, shapeKeys[i % 7]);
ASSERT_TRUE(slowObj->Set(vm_, shapeKey, IntegerRef::New(vm_, i)));
ASSERT_TRUE(fastObj->Set(vm_, shapeKey, IntegerRef::New(vm_, i)));
Local<JSValueRef> value = IntegerRef::New(vm_, 20000 + i);
thread_->ClearException();
bool slowOk = slowObj->Set(vm_, key, value);
bool slowEx = thread_->HasPendingException();
if (slowEx) {
thread_->ClearException();
}
thread_->ClearException();
bool fastOk = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*fastObj),
reinterpret_cast<uintptr_t>(*key), reinterpret_cast<uintptr_t>(*value), info);
bool fastEx = thread_->HasPendingException();
if (fastEx) {
thread_->ClearException();
}
ASSERT_EQ(slowEx, fastEx);
ASSERT_FALSE(slowEx);
ASSERT_TRUE(slowOk);
ASSERT_TRUE(fastOk);
Local<JSValueRef> slowAfter = JSNApi::NapiGetProperty(vm_, reinterpret_cast<uintptr_t>(*slowObj),
reinterpret_cast<uintptr_t>(*key));
bool slowAfterEx = thread_->HasPendingException();
if (slowAfterEx) {
thread_->ClearException();
}
Local<JSValueRef> fastAfter = JSNApi::NapiGetProperty(vm_, reinterpret_cast<uintptr_t>(*fastObj),
reinterpret_cast<uintptr_t>(*key));
bool fastAfterEx = thread_->HasPendingException();
if (fastAfterEx) {
thread_->ClearException();
}
ASSERT_EQ(slowAfterEx, fastAfterEx);
ASSERT_FALSE(slowAfterEx);
ASSERT_TRUE(slowAfter->IsStrictEquals(vm_, fastAfter));
if ((i % 40) == 0) {
auto runningState = GetCallsiteState(thread_, info, ICKind::StoreIC);
EXPECT_TRUE(runningState == IcAccessor::ICState::MEGA ||
runningState == IcAccessor::ICState::IC_MEGA);
}
}
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastNumericKeyParity)
{
LocalScope scope(vm_);
thread_->ClearException();
auto runSlowGet = [this](Local<JSValueRef> obj, Local<JSValueRef> key) {
thread_->ClearException();
Local<JSValueRef> result = JSNApi::NapiGetProperty(vm_, reinterpret_cast<uintptr_t>(*obj),
reinterpret_cast<uintptr_t>(*key));
bool hasException = thread_->HasPendingException();
if (hasException) {
thread_->ClearException();
}
return std::pair<Local<JSValueRef>, bool>(result, hasException);
};
auto runFastGet = [this](Local<JSValueRef> obj, Local<JSValueRef> key, uintptr_t info) {
thread_->ClearException();
Local<JSValueRef> result = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*obj),
reinterpret_cast<uintptr_t>(*key), info);
bool hasException = thread_->HasPendingException();
if (hasException) {
thread_->ClearException();
}
return std::pair<Local<JSValueRef>, bool>(result, hasException);
};
auto expectParity = [this, &runSlowGet, &runFastGet](
Local<JSValueRef> slowObj, Local<JSValueRef> fastObj,
Local<JSValueRef> key, uintptr_t info) {
auto [slowResult, slowEx] = runSlowGet(slowObj, key);
auto [fastResult, fastEx] = runFastGet(fastObj, key, info);
EXPECT_EQ(slowEx, fastEx);
if (!slowEx) {
EXPECT_TRUE(slowResult->IsStrictEquals(vm_, fastResult));
}
};
{
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
Local<JSValueRef> key = IntegerRef::New(vm_, 0);
Local<JSValueRef> value = IntegerRef::New(vm_, 42);
ASSERT_TRUE(slowObj->Set(vm_, key, value));
ASSERT_TRUE(fastObj->Set(vm_, key, value));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
expectParity(slowObj, fastObj, key, info);
auto [res, ex] = runFastGet(fastObj, key, info);
EXPECT_FALSE(ex);
EXPECT_TRUE(res->IsStrictEquals(vm_, value));
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
{
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
Local<JSValueRef> numKey = IntegerRef::New(vm_, 0);
Local<JSValueRef> strKey = StringRef::NewFromUtf8(vm_, "0");
Local<JSValueRef> value = IntegerRef::New(vm_, 77);
ASSERT_TRUE(slowObj->Set(vm_, numKey, value));
ASSERT_TRUE(fastObj->Set(vm_, numKey, value));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
expectParity(slowObj, fastObj, strKey, info);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
{
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
Local<JSValueRef> key = IntegerRef::New(vm_, 1000);
Local<JSValueRef> value = IntegerRef::New(vm_, 999);
ASSERT_TRUE(slowObj->Set(vm_, key, value));
ASSERT_TRUE(fastObj->Set(vm_, key, value));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
expectParity(slowObj, fastObj, key, info);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
{
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
Local<JSValueRef> key = IntegerRef::New(vm_, 5);
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
expectParity(slowObj, fastObj, key, info);
auto [res, ex] = runFastGet(fastObj, key, info);
EXPECT_FALSE(ex);
EXPECT_TRUE(res->IsUndefined());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
{
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
Local<JSValueRef> key = IntegerRef::New(vm_, 3);
Local<JSValueRef> value = IntegerRef::New(vm_, 33);
ASSERT_TRUE(slowObj->Set(vm_, key, value));
ASSERT_TRUE(fastObj->Set(vm_, key, value));
expectParity(slowObj, fastObj, key, 0);
}
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastNumericKeyParity)
{
LocalScope scope(vm_);
thread_->ClearException();
auto runSlowSet = [this](Local<ObjectRef> obj, Local<JSValueRef> key, Local<JSValueRef> value) {
thread_->ClearException();
bool ok = obj->Set(vm_, key, value);
bool hasException = thread_->HasPendingException();
if (hasException) {
thread_->ClearException();
}
return std::pair<bool, bool>(ok, hasException);
};
auto runFastSet = [this](Local<ObjectRef> obj, Local<JSValueRef> key,
Local<JSValueRef> value, uintptr_t info) {
thread_->ClearException();
bool ok = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*obj),
reinterpret_cast<uintptr_t>(*key), reinterpret_cast<uintptr_t>(*value), info);
bool hasException = thread_->HasPendingException();
if (hasException) {
thread_->ClearException();
}
return std::pair<bool, bool>(ok, hasException);
};
auto expectSetParity = [this, &runSlowSet, &runFastSet](
Local<ObjectRef> slowObj, Local<ObjectRef> fastObj,
Local<JSValueRef> key, Local<JSValueRef> value, uintptr_t info) {
auto [slowOk, slowEx] = runSlowSet(slowObj, key, value);
auto [fastOk, fastEx] = runFastSet(fastObj, key, value, info);
EXPECT_EQ(slowEx, fastEx);
if (!slowEx) {
EXPECT_TRUE(fastOk);
Local<JSValueRef> slowAfter = JSNApi::NapiGetProperty(vm_,
reinterpret_cast<uintptr_t>(*slowObj), reinterpret_cast<uintptr_t>(*key));
if (thread_->HasPendingException()) {
thread_->ClearException();
}
Local<JSValueRef> fastAfter = JSNApi::NapiGetProperty(vm_,
reinterpret_cast<uintptr_t>(*fastObj), reinterpret_cast<uintptr_t>(*key));
if (thread_->HasPendingException()) {
thread_->ClearException();
}
EXPECT_TRUE(slowAfter->IsStrictEquals(vm_, fastAfter));
}
};
{
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
Local<JSValueRef> key = IntegerRef::New(vm_, 0);
ASSERT_TRUE(slowObj->Set(vm_, key, IntegerRef::New(vm_, 0)));
ASSERT_TRUE(fastObj->Set(vm_, key, IntegerRef::New(vm_, 0)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
expectSetParity(slowObj, fastObj, key, IntegerRef::New(vm_, 42), info);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
{
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
Local<JSValueRef> numKey = IntegerRef::New(vm_, 0);
Local<JSValueRef> strKey = StringRef::NewFromUtf8(vm_, "0");
ASSERT_TRUE(slowObj->Set(vm_, numKey, IntegerRef::New(vm_, 0)));
ASSERT_TRUE(fastObj->Set(vm_, numKey, IntegerRef::New(vm_, 0)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
expectSetParity(slowObj, fastObj, strKey, IntegerRef::New(vm_, 88), info);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
{
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
Local<JSValueRef> key = IntegerRef::New(vm_, 500);
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
expectSetParity(slowObj, fastObj, key, IntegerRef::New(vm_, 500), info);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
{
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
Local<JSValueRef> key = IntegerRef::New(vm_, 7);
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
expectSetParity(slowObj, fastObj, key, IntegerRef::New(vm_, 77), info);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
{
Local<ObjectRef> slowObj = ObjectRef::New(vm_);
Local<ObjectRef> fastObj = ObjectRef::New(vm_);
Local<JSValueRef> key = IntegerRef::New(vm_, 2);
expectSetParity(slowObj, fastObj, key, IntegerRef::New(vm_, 22), 0);
}
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastKeyMismatchResetsIC)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> keyAlpha = StringRef::NewFromUtf8(vm_, "kmAlpha");
Local<JSValueRef> keyBeta = StringRef::NewFromUtf8(vm_, "kmBeta");
ASSERT_TRUE(object->Set(vm_, keyAlpha, IntegerRef::New(vm_, 10)));
ASSERT_TRUE(object->Set(vm_, keyBeta, IntegerRef::New(vm_, 20)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
uintptr_t keyAlphaAddr = reinterpret_cast<uintptr_t>(*keyAlpha);
uintptr_t keyBetaAddr = reinterpret_cast<uintptr_t>(*keyBeta);
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAlphaAddr, info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 10);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::LoadIC), IcAccessor::ICState::MONO);
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyBetaAddr, info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 20);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::LoadIC), IcAccessor::ICState::MONO);
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyBetaAddr, info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 20);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::LoadIC), IcAccessor::ICState::MONO);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastKeyMismatchResetsIC)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> keyAlpha = StringRef::NewFromUtf8(vm_, "skmAlpha");
Local<JSValueRef> keyBeta = StringRef::NewFromUtf8(vm_, "skmBeta");
ASSERT_TRUE(object->Set(vm_, keyAlpha, IntegerRef::New(vm_, 0)));
ASSERT_TRUE(object->Set(vm_, keyBeta, IntegerRef::New(vm_, 0)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
uintptr_t keyAlphaAddr = reinterpret_cast<uintptr_t>(*keyAlpha);
uintptr_t keyBetaAddr = reinterpret_cast<uintptr_t>(*keyBeta);
bool setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, keyAlphaAddr,
reinterpret_cast<uintptr_t>(*IntegerRef::New(vm_, 11)), info);
ASSERT_TRUE(setRes);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::StoreIC), IcAccessor::ICState::MONO);
setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, keyBetaAddr,
reinterpret_cast<uintptr_t>(*IntegerRef::New(vm_, 22)), info);
ASSERT_TRUE(setRes);
EXPECT_EQ(object->Get(vm_, keyBeta)->Int32Value(vm_), 22);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::StoreIC), IcAccessor::ICState::MONO);
setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, keyBetaAddr,
reinterpret_cast<uintptr_t>(*IntegerRef::New(vm_, 33)), info);
ASSERT_TRUE(setRes);
EXPECT_EQ(object->Get(vm_, keyBeta)->Int32Value(vm_), 33);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::StoreIC), IcAccessor::ICState::MONO);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastNonICInfoHeapObjectAsInfo)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "nonICInfoGetKey");
ASSERT_TRUE(object->Set(vm_, key, IntegerRef::New(vm_, 55)));
Local<ObjectRef> fakeInfoObj = ObjectRef::New(vm_);
uintptr_t fakeInfo = reinterpret_cast<uintptr_t>(*fakeInfoObj);
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*object),
reinterpret_cast<uintptr_t>(*key), fakeInfo);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 55);
ASSERT_FALSE(thread_->HasPendingException());
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastNonICInfoHeapObjectAsInfo)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "nonICInfoSetKey");
ASSERT_TRUE(object->Set(vm_, key, IntegerRef::New(vm_, 1)));
Local<ObjectRef> fakeInfoObj = ObjectRef::New(vm_);
uintptr_t fakeInfo = reinterpret_cast<uintptr_t>(*fakeInfoObj);
bool setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*object),
reinterpret_cast<uintptr_t>(*key),
reinterpret_cast<uintptr_t>(*IntegerRef::New(vm_, 99)), fakeInfo);
ASSERT_TRUE(setRes);
EXPECT_EQ(object->Get(vm_, key)->Int32Value(vm_), 99);
ASSERT_FALSE(thread_->HasPendingException());
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastHclassTransitionMidIC)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "hclassMidKey");
Local<JSValueRef> extraKey = StringRef::NewFromUtf8(vm_, "hclassMidExtra");
ASSERT_TRUE(object->Set(vm_, key, IntegerRef::New(vm_, 77)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 77);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::LoadIC), IcAccessor::ICState::MONO);
ASSERT_TRUE(object->Set(vm_, extraKey, IntegerRef::New(vm_, 999)));
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 77);
EXPECT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastHclassTransitionMidIC)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "hclassMidSetKey");
Local<JSValueRef> extraKey = StringRef::NewFromUtf8(vm_, "hclassMidSetExtra");
ASSERT_TRUE(object->Set(vm_, key, IntegerRef::New(vm_, 1)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
bool setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr,
reinterpret_cast<uintptr_t>(*IntegerRef::New(vm_, 10)), info);
ASSERT_TRUE(setRes);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::StoreIC), IcAccessor::ICState::MONO);
ASSERT_TRUE(object->Set(vm_, extraKey, IntegerRef::New(vm_, 999)));
setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr,
reinterpret_cast<uintptr_t>(*IntegerRef::New(vm_, 20)), info);
ASSERT_TRUE(setRes);
EXPECT_EQ(object->Get(vm_, key)->Int32Value(vm_), 20);
EXPECT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastNonExistentProperty)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "noSuchIcKey");
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
EXPECT_TRUE(res->IsUndefined());
EXPECT_FALSE(thread_->HasPendingException());
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
EXPECT_TRUE(res->IsUndefined());
EXPECT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastNewProperty)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "newIcPropKey");
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
bool setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*object),
reinterpret_cast<uintptr_t>(*key),
reinterpret_cast<uintptr_t>(*IntegerRef::New(vm_, 42)), info);
ASSERT_TRUE(setRes);
EXPECT_EQ(object->Get(vm_, key)->Int32Value(vm_), 42);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastUndefinedAndNullValues)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> keyUndef = StringRef::NewFromUtf8(vm_, "valueUndefIcKey");
Local<JSValueRef> keyNull = StringRef::NewFromUtf8(vm_, "valueNullIcKey");
ASSERT_TRUE(object->Set(vm_, keyUndef, JSValueRef::Undefined(vm_)));
ASSERT_TRUE(object->Set(vm_, keyNull, JSValueRef::Null(vm_)));
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
{
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*keyUndef);
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
EXPECT_TRUE(res->IsUndefined());
EXPECT_FALSE(thread_->HasPendingException());
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
EXPECT_TRUE(res->IsUndefined());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
{
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*keyNull);
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
EXPECT_TRUE(res->IsNull());
EXPECT_FALSE(thread_->HasPendingException());
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
EXPECT_TRUE(res->IsNull());
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastFrozenObject)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "frozenIcKey");
ASSERT_TRUE(object->Set(vm_, key, IntegerRef::New(vm_, 100)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
bool setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr,
reinterpret_cast<uintptr_t>(*IntegerRef::New(vm_, 200)), info);
ASSERT_TRUE(setRes);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::StoreIC), IcAccessor::ICState::MONO);
JSHandle<JSObject> jsObj(JSNApiHelper::ToJSHandle(object));
ASSERT_TRUE(JSObject::SetIntegrityLevel(thread_, jsObj, FROZEN));
setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr,
reinterpret_cast<uintptr_t>(*IntegerRef::New(vm_, 300)), info);
EXPECT_FALSE(setRes);
if (thread_->HasPendingException()) {
thread_->ClearException();
}
EXPECT_EQ(object->Get(vm_, key)->Int32Value(vm_), 200);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastScopeFreePath)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "scopeFreeIcKey");
ASSERT_TRUE(object->Set(vm_, key, IntegerRef::New(vm_, 999)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
Local<JSValueRef> key1 = StringRef::NewFromUtf8(vm_, "scopeFreeIcKey");
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr,
reinterpret_cast<uintptr_t>(*key1), info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 999);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::LoadIC), IcAccessor::ICState::MONO);
Local<JSValueRef> key2 = StringRef::NewFromUtf8(vm_, "scopeFreeIcKey");
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr,
reinterpret_cast<uintptr_t>(*key2), info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 999);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::LoadIC), IcAccessor::ICState::MONO);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastScopeFreePath)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "storeIcHitKey");
ASSERT_TRUE(object->Set(vm_, key, IntegerRef::New(vm_, 0)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
Local<JSValueRef> key1 = StringRef::NewFromUtf8(vm_, "storeIcHitKey");
bool setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr,
reinterpret_cast<uintptr_t>(*key1),
reinterpret_cast<uintptr_t>(*IntegerRef::New(vm_, 11)), info);
ASSERT_TRUE(setRes);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::StoreIC), IcAccessor::ICState::MONO);
Local<JSValueRef> key2 = StringRef::NewFromUtf8(vm_, "storeIcHitKey");
setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr,
reinterpret_cast<uintptr_t>(*key2),
reinterpret_cast<uintptr_t>(*IntegerRef::New(vm_, 22)), info);
ASSERT_TRUE(setRes);
EXPECT_EQ(object->Get(vm_, key)->Int32Value(vm_), 22);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::StoreIC), IcAccessor::ICState::MONO);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastDoubleAndBooleanValues)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> keyDouble = StringRef::NewFromUtf8(vm_, "doubleIcKey");
Local<JSValueRef> keyBool = StringRef::NewFromUtf8(vm_, "boolIcKey");
constexpr double pi = 3.14159;
ASSERT_TRUE(object->Set(vm_, keyDouble, NumberRef::New(vm_, pi)));
ASSERT_TRUE(object->Set(vm_, keyBool, BooleanRef::New(vm_, true)));
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
{
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*keyDouble);
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
ASSERT_TRUE(res->IsNumber());
EXPECT_DOUBLE_EQ(res->ToNumber(vm_)->Value(), pi);
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
ASSERT_TRUE(res->IsNumber());
EXPECT_DOUBLE_EQ(res->ToNumber(vm_)->Value(), pi);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
{
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*keyBool);
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
ASSERT_TRUE(res->IsBoolean());
EXPECT_TRUE(res->IsTrue());
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
ASSERT_TRUE(res->IsBoolean());
EXPECT_TRUE(res->IsTrue());
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastDeletedPropertyAfterIC)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "deleteAfterIcKey");
ASSERT_TRUE(object->Set(vm_, key, IntegerRef::New(vm_, 1)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 1);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::LoadIC), IcAccessor::ICState::MONO);
ASSERT_TRUE(object->Delete(vm_, key));
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
EXPECT_TRUE(res->IsUndefined());
EXPECT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastMultipleObjectsSameCallsite)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "sharedCallsiteIcKey");
Local<ObjectRef> obj1 = ObjectRef::New(vm_);
Local<ObjectRef> obj2 = ObjectRef::New(vm_);
ASSERT_TRUE(obj1->Set(vm_, key, IntegerRef::New(vm_, 1)));
ASSERT_TRUE(obj2->Set(vm_, key, IntegerRef::New(vm_, 2)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
bool setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*obj1),
keyAddr, reinterpret_cast<uintptr_t>(*IntegerRef::New(vm_, 10)), info);
ASSERT_TRUE(setRes);
EXPECT_EQ(obj1->Get(vm_, key)->Int32Value(vm_), 10);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::StoreIC), IcAccessor::ICState::MONO);
setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*obj2),
keyAddr, reinterpret_cast<uintptr_t>(*IntegerRef::New(vm_, 20)), info);
ASSERT_TRUE(setRes);
EXPECT_EQ(obj2->Get(vm_, key)->Int32Value(vm_), 20);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::StoreIC), IcAccessor::ICState::MONO);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastCallableNotECMAObject)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<FunctionRef> func = FunctionRef::New(vm_, FunctionCallback);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "callableGuardIcKey");
ASSERT_TRUE(func->Set(vm_, key, IntegerRef::New(vm_, 42)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t funcAddr = reinterpret_cast<uintptr_t>(*func);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, funcAddr, keyAddr, info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 42);
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, funcAddr, keyAddr, info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 42);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastPolyStateHit)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "polyGetHitKey");
Local<ObjectRef> obj1 = ObjectRef::New(vm_);
ASSERT_TRUE(obj1->Set(vm_, key, IntegerRef::New(vm_, 10)));
Local<ObjectRef> obj2 = ObjectRef::New(vm_);
Local<JSValueRef> extra = StringRef::NewFromUtf8(vm_, "polyGetExtra");
ASSERT_TRUE(obj2->Set(vm_, extra, IntegerRef::New(vm_, 0)));
ASSERT_TRUE(obj2->Set(vm_, key, IntegerRef::New(vm_, 20)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_,
reinterpret_cast<uintptr_t>(*obj1), keyAddr, info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 10);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::LoadIC), IcAccessor::ICState::MONO);
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_,
reinterpret_cast<uintptr_t>(*obj2), keyAddr, info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 20);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::LoadIC), IcAccessor::ICState::POLY);
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_,
reinterpret_cast<uintptr_t>(*obj1), keyAddr, info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 10);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::LoadIC), IcAccessor::ICState::POLY);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastPolyStateHit)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "polySetHitKey");
Local<ObjectRef> obj1 = ObjectRef::New(vm_);
ASSERT_TRUE(obj1->Set(vm_, key, IntegerRef::New(vm_, 0)));
Local<ObjectRef> obj2 = ObjectRef::New(vm_);
Local<JSValueRef> extra = StringRef::NewFromUtf8(vm_, "polySetExtra");
ASSERT_TRUE(obj2->Set(vm_, extra, IntegerRef::New(vm_, 0)));
ASSERT_TRUE(obj2->Set(vm_, key, IntegerRef::New(vm_, 0)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
bool setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_,
reinterpret_cast<uintptr_t>(*obj1), keyAddr,
reinterpret_cast<uintptr_t>(*IntegerRef::New(vm_, 10)), info);
ASSERT_TRUE(setRes);
EXPECT_EQ(obj1->Get(vm_, key)->Int32Value(vm_), 10);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::StoreIC), IcAccessor::ICState::MONO);
setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_,
reinterpret_cast<uintptr_t>(*obj2), keyAddr,
reinterpret_cast<uintptr_t>(*IntegerRef::New(vm_, 20)), info);
ASSERT_TRUE(setRes);
EXPECT_EQ(obj2->Get(vm_, key)->Int32Value(vm_), 20);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::StoreIC), IcAccessor::ICState::POLY);
setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_,
reinterpret_cast<uintptr_t>(*obj1), keyAddr,
reinterpret_cast<uintptr_t>(*IntegerRef::New(vm_, 30)), info);
ASSERT_TRUE(setRes);
EXPECT_EQ(obj1->Get(vm_, key)->Int32Value(vm_), 30);
EXPECT_EQ(GetCallsiteState(thread_, info, ICKind::StoreIC), IcAccessor::ICState::POLY);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastSealedObjectNewKey)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
JSHandle<JSObject> jsObj(JSNApiHelper::ToJSHandle(object));
ASSERT_TRUE(JSObject::SetIntegrityLevel(thread_, jsObj, SEALED));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "sealedNewPropKey");
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
bool setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr,
reinterpret_cast<uintptr_t>(*IntegerRef::New(vm_, 42)), info);
EXPECT_FALSE(setRes);
if (thread_->HasPendingException()) {
thread_->ClearException();
}
Local<JSValueRef> val = object->Get(vm_, key);
EXPECT_TRUE(val->IsUndefined());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiDeleteCallsiteInfoZeroIsNoop)
{
thread_->ClearException();
JSNApi::NapiDeleteCallsiteInfo(vm_, 0);
ASSERT_FALSE(thread_->HasPendingException());
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastDirectMegaSlotFallback)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "directMegaGetKey");
ASSERT_TRUE(object->Set(vm_, key, IntegerRef::New(vm_, 777)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
JSTaggedValue infoVal = *reinterpret_cast<JSTaggedValue *>(info);
ICInfo *icInfo = ICInfo::Cast(infoVal.GetTaggedObject());
icInfo->SetIcSlot(thread_, 0, JSTaggedValue::Hole());
icInfo->SetIcSlot(thread_, 1, JSTaggedValue::Hole());
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*object),
reinterpret_cast<uintptr_t>(*key), info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 777);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastDirectMegaSlotFallback)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "directMegaSetKey");
ASSERT_TRUE(object->Set(vm_, key, IntegerRef::New(vm_, 1)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
JSTaggedValue infoVal = *reinterpret_cast<JSTaggedValue *>(info);
ICInfo *icInfo = ICInfo::Cast(infoVal.GetTaggedObject());
icInfo->SetIcSlot(thread_, 0, JSTaggedValue::Hole());
icInfo->SetIcSlot(thread_, 1, JSTaggedValue::Hole());
Local<JSValueRef> value = IntegerRef::New(vm_, 888);
bool setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*object),
reinterpret_cast<uintptr_t>(*key), reinterpret_cast<uintptr_t>(*value), info);
ASSERT_TRUE(setRes);
EXPECT_EQ(object->Get(vm_, key)->Int32Value(vm_), 888);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastNonInternStringNamedIC)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "namedICKey");
ASSERT_TRUE(object->Set(vm_, key, IntegerRef::New(vm_, 321)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
Local<JSValueRef> res1 = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*object),
reinterpret_cast<uintptr_t>(*key), info);
ASSERT_TRUE(res1->IsNumber());
EXPECT_EQ(res1->Int32Value(vm_), 321);
std::string rawStr = "namedICKey";
Local<JSValueRef> freshKey = StringRef::NewFromUtf8(vm_, rawStr.c_str());
Local<JSValueRef> res2 = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*object),
reinterpret_cast<uintptr_t>(*freshKey), info);
ASSERT_TRUE(res2->IsNumber());
EXPECT_EQ(res2->Int32Value(vm_), 321);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastNonInternStringNamedIC)
{
LocalScope scope(vm_);
thread_->ClearException();
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "namedICSetKey");
ASSERT_TRUE(object->Set(vm_, key, IntegerRef::New(vm_, 0)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
Local<JSValueRef> value1 = IntegerRef::New(vm_, 111);
bool setRes1 = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*object),
reinterpret_cast<uintptr_t>(*key), reinterpret_cast<uintptr_t>(*value1), info);
ASSERT_TRUE(setRes1);
std::string rawStr = "namedICSetKey";
Local<JSValueRef> freshKey = StringRef::NewFromUtf8(vm_, rawStr.c_str());
Local<JSValueRef> value2 = IntegerRef::New(vm_, 222);
bool setRes2 = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*object),
reinterpret_cast<uintptr_t>(*freshKey), reinterpret_cast<uintptr_t>(*value2), info);
ASSERT_TRUE(setRes2);
EXPECT_EQ(object->Get(vm_, key)->Int32Value(vm_), 222);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiGetPropertyFastProxyObject)
{
LocalScope scope(vm_);
thread_->ClearException();
ObjectFactory *factory = vm_->GetFactory();
Local<ObjectRef> target = ObjectRef::New(vm_);
Local<JSValueRef> propKey = StringRef::NewFromUtf8(vm_, "proxyGetKey");
ASSERT_TRUE(target->Set(vm_, propKey, IntegerRef::New(vm_, 999)));
Local<ObjectRef> handlerObj = ObjectRef::New(vm_);
JSHandle<JSTaggedValue> targetHandle = JSNApiHelper::ToJSHandle(target);
JSHandle<JSTaggedValue> handlerHandle = JSNApiHelper::ToJSHandle(handlerObj);
JSHandle<JSProxy> proxy = factory->NewJSProxy(targetHandle, handlerHandle);
Local<JSValueRef> proxyLocal = JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(proxy));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*proxyLocal),
reinterpret_cast<uintptr_t>(*propKey), info);
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 999);
auto state = GetCallsiteState(thread_, info, ICKind::LoadIC);
EXPECT_TRUE(state == IcAccessor::ICState::MEGA || state == IcAccessor::ICState::IC_MEGA);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiSetPropertyFastProxyObject)
{
LocalScope scope(vm_);
thread_->ClearException();
ObjectFactory *factory = vm_->GetFactory();
Local<ObjectRef> target = ObjectRef::New(vm_);
Local<JSValueRef> propKey = StringRef::NewFromUtf8(vm_, "proxySetKey");
ASSERT_TRUE(target->Set(vm_, propKey, IntegerRef::New(vm_, 0)));
Local<ObjectRef> handlerObj = ObjectRef::New(vm_);
JSHandle<JSTaggedValue> targetHandle = JSNApiHelper::ToJSHandle(target);
JSHandle<JSTaggedValue> handlerHandle = JSNApiHelper::ToJSHandle(handlerObj);
JSHandle<JSProxy> proxy = factory->NewJSProxy(targetHandle, handlerHandle);
Local<JSValueRef> proxyLocal = JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(proxy));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
Local<JSValueRef> value = IntegerRef::New(vm_, 555);
bool setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*proxyLocal),
reinterpret_cast<uintptr_t>(*propKey), reinterpret_cast<uintptr_t>(*value), info);
ASSERT_TRUE(setRes);
auto state = GetCallsiteState(thread_, info, ICKind::StoreIC);
EXPECT_TRUE(state == IcAccessor::ICState::MEGA || state == IcAccessor::ICState::IC_MEGA);
Local<JSValueRef> value2 = IntegerRef::New(vm_, 666);
bool setRes2 = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, reinterpret_cast<uintptr_t>(*proxyLocal),
reinterpret_cast<uintptr_t>(*propKey), reinterpret_cast<uintptr_t>(*value2), info);
ASSERT_TRUE(setRes2);
ASSERT_FALSE(thread_->HasPendingException());
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiCallsiteInfoCrossUseGetThenSetFallsBack)
{
LocalScope scope(vm_);
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "crossUseKey");
ASSERT_TRUE(object->Set(vm_, key, IntegerRef::New(vm_, 42)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
ASSERT_FALSE(thread_->HasPendingException());
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 42);
Local<JSValueRef> newValue = IntegerRef::New(vm_, 99);
bool setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr,
reinterpret_cast<uintptr_t>(*newValue), info);
EXPECT_TRUE(setRes);
ASSERT_FALSE(thread_->HasPendingException());
EXPECT_EQ(object->Get(vm_, key)->Int32Value(vm_), 99);
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
ASSERT_FALSE(thread_->HasPendingException());
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 99);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiCallsiteInfoCrossUseSetThenGetFallsBack)
{
LocalScope scope(vm_);
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "crossUseKey2");
ASSERT_TRUE(object->Set(vm_, key, IntegerRef::New(vm_, 10)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
Local<JSValueRef> newValue = IntegerRef::New(vm_, 20);
bool setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr,
reinterpret_cast<uintptr_t>(*newValue), info);
ASSERT_TRUE(setRes);
ASSERT_FALSE(thread_->HasPendingException());
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info);
ASSERT_FALSE(thread_->HasPendingException());
ASSERT_TRUE(res->IsNumber());
EXPECT_EQ(res->Int32Value(vm_), 20);
Local<JSValueRef> newValue2 = IntegerRef::New(vm_, 30);
setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr,
reinterpret_cast<uintptr_t>(*newValue2), info);
ASSERT_TRUE(setRes);
ASSERT_FALSE(thread_->HasPendingException());
EXPECT_EQ(object->Get(vm_, key)->Int32Value(vm_), 30);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiCallsiteInfoCrossUseHitTracking)
{
LocalScope scope(vm_);
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "crossUseHitKey");
ASSERT_TRUE(object->Set(vm_, key, IntegerRef::New(vm_, 77)));
uintptr_t info = JSNApi::NapiCreateCallsiteInfo(vm_);
ASSERT_NE(info, 0U);
uintptr_t objectAddr = reinterpret_cast<uintptr_t>(*object);
uintptr_t keyAddr = reinterpret_cast<uintptr_t>(*key);
bool hit = true;
Local<JSValueRef> res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info, &hit);
ASSERT_FALSE(thread_->HasPendingException());
EXPECT_FALSE(hit);
EXPECT_EQ(res->Int32Value(vm_), 77);
res = JSNApi::NapiGetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr, info, &hit);
ASSERT_FALSE(thread_->HasPendingException());
EXPECT_TRUE(hit);
hit = true;
Local<JSValueRef> newValue = IntegerRef::New(vm_, 88);
bool setRes = JSNApi::NapiSetPropertyWithCallsiteInfo(vm_, objectAddr, keyAddr,
reinterpret_cast<uintptr_t>(*newValue), info, &hit);
EXPECT_TRUE(setRes);
EXPECT_FALSE(hit);
ASSERT_FALSE(thread_->HasPendingException());
EXPECT_EQ(object->Get(vm_, key)->Int32Value(vm_), 88);
JSNApi::NapiDeleteCallsiteInfo(vm_, info);
}
HWTEST_F_L0(JSNApiTests, NapiExternalStringCacheTest001)
{
isStringCacheTableCreated_ = ExternalStringCache::RegisterStringCacheTable(vm_, 0);
ASSERT_FALSE(isStringCacheTableCreated_);
}
HWTEST_F_L0(JSNApiTests, NapiExternalStringCacheTest002)
{
constexpr uint32_t STRING_CACHE_TABLE_SIZE = 300;
isStringCacheTableCreated_ = ExternalStringCache::RegisterStringCacheTable(vm_, STRING_CACHE_TABLE_SIZE);
ASSERT_FALSE(isStringCacheTableCreated_);
}
HWTEST_F_L0(JSNApiTests, NapiExternalStringCacheTest003)
{
constexpr uint32_t STRING_CACHE_TABLE_SIZE = 100;
isStringCacheTableCreated_ = ExternalStringCache::RegisterStringCacheTable(vm_, STRING_CACHE_TABLE_SIZE);
ASSERT_TRUE(isStringCacheTableCreated_);
}
HWTEST_F_L0(JSNApiTests, NapiExternalStringCacheTest004)
{
RegisterStringCacheTable();
constexpr uint32_t PROPERTY_INDEX = 101;
constexpr char property[] = "hello";
auto res = ExternalStringCache::SetCachedString(vm_, property, PROPERTY_INDEX);
ASSERT_FALSE(res);
}
HWTEST_F_L0(JSNApiTests, NapiExternalStringCacheTest005)
{
RegisterStringCacheTable();
constexpr uint32_t PROPERTY_INDEX = 0;
constexpr char property[] = "hello";
auto res = ExternalStringCache::SetCachedString(vm_, property, PROPERTY_INDEX);
ASSERT_TRUE(res);
}
HWTEST_F_L0(JSNApiTests, NapiExternalStringCacheTest006)
{
RegisterStringCacheTable();
constexpr uint32_t PROPERTY_INDEX = 1;
constexpr char property[] = "hello";
auto res = ExternalStringCache::SetCachedString(vm_, property, PROPERTY_INDEX);
ASSERT_TRUE(res);
constexpr uint32_t QUERY_PROPERTY_INDEX = 2;
res = ExternalStringCache::HasCachedString(vm_, QUERY_PROPERTY_INDEX);
ASSERT_FALSE(res);
}
HWTEST_F_L0(JSNApiTests, NapiExternalStringCacheTest007)
{
RegisterStringCacheTable();
constexpr uint32_t PROPERTY_INDEX = 2;
constexpr char property[] = "hello";
auto res = ExternalStringCache::SetCachedString(vm_, property, PROPERTY_INDEX);
ASSERT_TRUE(res);
constexpr uint32_t QUERY_PROPERTY_INDEX = 2;
res = ExternalStringCache::HasCachedString(vm_, QUERY_PROPERTY_INDEX);
ASSERT_TRUE(res);
}
HWTEST_F_L0(JSNApiTests, NapiExternalStringCacheTest008)
{
RegisterStringCacheTable();
constexpr uint32_t PROPERTY_INDEX = 3;
constexpr char property[] = "hello world";
auto res = ExternalStringCache::SetCachedString(vm_, property, PROPERTY_INDEX);
ASSERT_TRUE(res);
Local<StringRef> value = ExternalStringCache::GetCachedString(vm_, PROPERTY_INDEX);
ASSERT_FALSE(value->IsUndefined());
EXPECT_EQ(value->ToString(vm_), property);
}
HWTEST_F_L0(JSNApiTests, SetExecuteMode)
{
ecmascript::ModuleManager *moduleManager = thread_->GetModuleManager();
ecmascript::ModuleExecuteMode res1 = moduleManager->GetExecuteMode();
EXPECT_EQ(res1, ecmascript::ModuleExecuteMode::ExecuteZipMode);
JSNApi::SetExecuteBufferMode(vm_);
ecmascript::ModuleExecuteMode res2 = moduleManager->GetExecuteMode();
EXPECT_EQ(res2, ecmascript::ModuleExecuteMode::ExecuteBufferMode);
}
HWTEST_F_L0(JSNApiTests, ToEcmaObject)
{
LocalScope scope(vm_);
Local<ObjectRef> res = ObjectRef::New(vm_);
res->ToEcmaObject(vm_);
ASSERT_TRUE(res->IsObject(vm_));
}
HWTEST_F_L0(JSNApiTests, GetValueInt64)
{
LocalScope scope(vm_);
bool isNumber = true;
int32_t input = 4;
Local<IntegerRef> res = IntegerRef::New(vm_, input);
res->ToBigInt(vm_);
ASSERT_TRUE(res->GetValueInt64(isNumber));
res->ToNumber(vm_);
ASSERT_TRUE(res->GetValueInt64(isNumber));
isNumber = false;
ASSERT_TRUE(res->GetValueInt64(isNumber));
}
HWTEST_F_L0(JSNApiTests, GetDataViewInfo)
{
LocalScope scope(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "TestKey");
bool isDataView = false;
key->GetDataViewInfo(vm_, isDataView, nullptr, nullptr, nullptr, nullptr);
ASSERT_FALSE(isDataView);
isDataView = true;
key->GetDataViewInfo(vm_, isDataView, nullptr, nullptr, nullptr, nullptr);
ASSERT_FALSE(isDataView);
}
HWTEST_F_L0(JSNApiTests, ByteLength002)
{
LocalScope scope(vm_);
const int32_t length = 4;
Local<ArrayBufferRef> array = ArrayBufferRef::New(vm_, length);
int32_t arrayLen = array->ByteLength(vm_);
EXPECT_EQ(length, arrayLen);
}
HWTEST_F_L0(JSNApiTests, SetData)
{
LocalScope scope(vm_);
Local<FunctionRef> functioncallback = FunctionRef::New(vm_, FunctionCallback);
struct Data {
int32_t length;
};
const int32_t length = 15;
Data *data = new Data();
data->length = length;
functioncallback->SetData(vm_, data);
}
HWTEST_F_L0(JSNApiTests, GetData)
{
LocalScope scope(vm_);
Local<FunctionRef> functioncallback = FunctionRef::New(vm_, FunctionCallback);
functioncallback->GetData(vm_);
}
HWTEST_F_L0(JSNApiTests, GetData002)
{
LocalScope scope(vm_);
int32_t argvLength = 10;
auto ecmaRuntimeCallInfo =
TestHelper::CreateEcmaRuntimeCallInfo(vm_->GetJSThread(), JSTaggedValue::Undefined(), argvLength);
JsiRuntimeCallInfo *jsiRuntimeCallInfo = reinterpret_cast<JsiRuntimeCallInfo *>(ecmaRuntimeCallInfo);
jsiRuntimeCallInfo->GetData();
}
HWTEST_F_L0(JSNApiTests, SetStopPreLoadSoCallback)
{
auto callback = []()->void {
LOG_FULL(INFO) << "Call stopPreLoadSoCallback";
};
JSNApi::SetStopPreLoadSoCallback(vm_, callback);
auto stopPreLoadCallbacks = vm_->GetStopPreLoadCallbacks();
EXPECT_EQ(stopPreLoadCallbacks.size(), 1);
vm_->StopPreLoadSoOrAbc();
stopPreLoadCallbacks = vm_->GetStopPreLoadCallbacks();
EXPECT_EQ(stopPreLoadCallbacks.size(), 0);
}
HWTEST_F_L0(JSNApiTests, UpdatePkgContextInfoList)
{
std::map<std::string, std::vector<std::vector<std::string>>> pkgList;
std::vector<std::string> entryList = {
"entry", "packageName", "entry",
"bundleName", "",
"moduleName", "",
"version", "",
"entryPath", "src/main/",
"isSO", "false"
};
pkgList["entry"] = {entryList};
JSNApi::SetpkgContextInfoList(vm_, pkgList);
std::map<std::string, std::vector<std::vector<std::string>>> newPkgList;
std::vector<std::string> hspList = {
"hsp", "packageName", "hsp",
"bundleName", "",
"moduleName", "",
"version", "1.1.0",
"entryPath", "Index.ets",
"isSO", "false"
};
newPkgList["hsp"] = {hspList};
JSNApi::UpdatePkgContextInfoList(vm_, newPkgList);
CMap<CString, CMap<CString, CVector<CString>>> vmPkgList = vm_->GetPkgContextInfoList();
EXPECT_EQ(vmPkgList.size(), 2);
EXPECT_EQ(vmPkgList["entry"]["entry"].size(), 12);
EXPECT_EQ(vmPkgList["hsp"].size(), 1);
EXPECT_EQ(vmPkgList["hsp"]["hsp"].size(), 12);
#if ENABLE_LATEST_OPTIMIZATION
CVector<CString> hapInfo{};
vm_->GetPkgContextInfoListElements("entry", "entry", hapInfo);
EXPECT_EQ(hapInfo.size(), 12);
EXPECT_EQ(hapInfo[1], "entry");
EXPECT_EQ(hapInfo[3], "");
EXPECT_EQ(hapInfo[5], "");
EXPECT_EQ(hapInfo[7], "");
EXPECT_EQ(hapInfo[9], "src/main/");
EXPECT_EQ(hapInfo[11], "false");
CVector<CString> hspInfo{};
vm_->GetPkgContextInfoListElements("hsp", "hsp", hspInfo);
EXPECT_EQ(hspInfo.size(), 12);
EXPECT_EQ(hspInfo[1], "hsp");
EXPECT_EQ(hspInfo[3], "");
EXPECT_EQ(hspInfo[5], "");
EXPECT_EQ(hspInfo[7], "1.1.0");
EXPECT_EQ(hspInfo[9], "Index.ets");
EXPECT_EQ(hspInfo[11], "false");
#endif
}
HWTEST_F_L0(JSNApiTests, UpdatePkgNameList)
{
std::map<std::string, std::string> pkgNameList;
pkgNameList["moduleName1"] = "pkgName1";
JSNApi::SetPkgNameList(vm_, pkgNameList);
std::map<std::string, std::string> newPkgNameList;
newPkgNameList["moduleName2"] = "pkgName2";
JSNApi::UpdatePkgNameList(vm_, newPkgNameList);
CMap<CString, CString> vmPkgNameList = vm_->GetPkgNameList();
EXPECT_EQ(vmPkgNameList.size(), 2);
EXPECT_EQ(vmPkgNameList["moduleName1"], "pkgName1");
EXPECT_EQ(vmPkgNameList["moduleName2"], "pkgName2");
}
HWTEST_F_L0(JSNApiTests, UpdatePkgAliasList)
{
std::map<std::string, std::string> aliasNameList;
aliasNameList["aliasName1"] = "pkgName1";
JSNApi::SetPkgAliasList(vm_, aliasNameList);
std::map<std::string, std::string> newAliasNameList;
newAliasNameList["aliasName2"] = "pkgName2";
JSNApi::UpdatePkgAliasList(vm_, newAliasNameList);
CMap<CString, CString> vmAliasNameList = vm_->GetPkgAliasList();
EXPECT_EQ(vmAliasNameList.size(), 2);
EXPECT_EQ(vmAliasNameList["aliasName1"], "pkgName1");
EXPECT_EQ(vmAliasNameList["aliasName2"], "pkgName2");
}
HWTEST_F_L0(JSNApiTests, SetPkgContextInfoListWithBuffer)
{
std::unordered_map<std::string, std::pair<std::unique_ptr<uint8_t[]>, size_t>> modulePkgContentMap;
std::string entryString = R"({"entry":{"packageName":"entry", "bundleName":"", "moduleName":
"", "version":"", "entryPath":"src/main/", "isSO":false, "dependencyAlias":""}})";
std::string libraryString = R"({"library":{"packageName":"library", "bundleName":"com.xxx.xxxx", "moduleName":
"library", "version":"1.0.0", "entryPath":"Index.ets", "isSO":false, "dependencyAlias":"har"}})";
auto createBufferFromString = [](const std::string& str) {
size_t size = str.size();
auto buffer = std::make_unique<uint8_t[]>(size);
std::copy(str.begin(), str.end(), buffer.get());
return std::make_pair(std::move(buffer), size);
};
modulePkgContentMap["entry"] = createBufferFromString(entryString);
modulePkgContentMap["library"] = createBufferFromString(libraryString);
JSNApi::SetPkgContextInfoList(vm_, modulePkgContentMap);
CMap<CString, CMap<CString, CVector<CString>>> vmPkgList = vm_->GetPkgContextInfoList();
EXPECT_EQ(vmPkgList.size(), 2);
EXPECT_EQ(vmPkgList["entry"]["entry"].size(), 12);
EXPECT_EQ(vmPkgList["library"].size(), 1);
EXPECT_EQ(vmPkgList["library"]["library"].size(), 12);
#if ENABLE_LATEST_OPTIMIZATION
CVector<CString> hapInfo{};
vm_->GetPkgContextInfoListElements("entry", "entry", hapInfo);
EXPECT_EQ(hapInfo.size(), 12);
EXPECT_EQ(hapInfo[1], "entry");
EXPECT_EQ(hapInfo[3], "");
EXPECT_EQ(hapInfo[5], "");
EXPECT_EQ(hapInfo[7], "");
EXPECT_EQ(hapInfo[9], "src/main/");
EXPECT_EQ(hapInfo[11], "false");
CVector<CString> libraryInfo{};
vm_->GetPkgContextInfoListElements("library", "library", libraryInfo);
EXPECT_EQ(libraryInfo.size(), 12);
EXPECT_EQ(libraryInfo[1], "library");
EXPECT_EQ(libraryInfo[3], "com.xxx.xxxx");
EXPECT_EQ(libraryInfo[5], "library");
EXPECT_EQ(libraryInfo[7], "1.0.0");
EXPECT_EQ(libraryInfo[9], "Index.ets");
EXPECT_EQ(libraryInfo[11], "false");
#endif
}
HWTEST_F_L0(JSNApiTests, UpdatePkgContextInfoListWithBuffer)
{
std::string hspString = R"({"hsp":{"packageName":"hsp", "bundleName":"", "moduleName":
"hsp", "version":"1.1.0", "entryPath":"Index.ets", "isSO":false, "dependencyAlias": "har"}})";
auto createBufferFromString = [](const std::string& str) {
size_t size = str.size();
auto buffer = std::make_unique<uint8_t[]>(size);
std::copy(str.begin(), str.end(), buffer.get());
return std::make_pair(std::move(buffer), size);
};
std::unordered_map<std::string, std::pair<std::unique_ptr<uint8_t[]>, size_t>> updatePkgContentMap;
updatePkgContentMap["hsp"] = createBufferFromString(hspString);
JSNApi::UpdatePkgContextInfoList(vm_, updatePkgContentMap);
#if ENABLE_LATEST_OPTIMIZATION
CVector<CString> hspInfo{};
vm_->GetPkgContextInfoListElements("hsp", "hsp", hspInfo);
EXPECT_EQ(hspInfo.size(), 12);
EXPECT_EQ(hspInfo[1], "hsp");
EXPECT_EQ(hspInfo[3], "");
EXPECT_EQ(hspInfo[5], "hsp");
EXPECT_EQ(hspInfo[7], "1.1.0");
EXPECT_EQ(hspInfo[9], "Index.ets");
EXPECT_EQ(hspInfo[11], "false");
#endif
}
HWTEST_F_L0(JSNApiTests, TryGetArrayLengthTest001)
{
LocalScope scope(vm_);
const uint32_t ARRAY_LENGTH = 10;
Local<ArrayRef> array = ArrayRef::New(vm_, ARRAY_LENGTH);
Local<JSValueRef> value(array);
bool isJSArray = value->IsJSArray(vm_);
ASSERT_EQ(isJSArray, true);
bool isPendingException = true;
bool isArrayOrSharedArray = false;
uint32_t arrayLength = 0;
value->TryGetArrayLength(vm_, &isPendingException, &isArrayOrSharedArray, &arrayLength);
ASSERT_EQ(isPendingException, false);
ASSERT_EQ(isArrayOrSharedArray, true);
ASSERT_EQ(arrayLength, ARRAY_LENGTH);
}
HWTEST_F_L0(JSNApiTests, TryGetArrayLengthTest002)
{
LocalScope scope(vm_);
const uint32_t ARRAY_LENGTH = 10;
Local<SendableArrayRef> sArray = SendableArrayRef::New(vm_, ARRAY_LENGTH);
Local<JSValueRef> value(sArray);
bool isSArray = value->IsSharedArray(vm_);
ASSERT_EQ(isSArray, true);
bool isPendingException = true;
bool isArrayOrSharedArray = false;
uint32_t arrayLength = 0;
value->TryGetArrayLength(vm_, &isPendingException, &isArrayOrSharedArray, &arrayLength);
ASSERT_EQ(isPendingException, false);
ASSERT_EQ(isArrayOrSharedArray, true);
ASSERT_EQ(arrayLength, ARRAY_LENGTH);
}
HWTEST_F_L0(JSNApiTests, TryGetArrayLengthTest003)
{
LocalScope scope(vm_);
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> value(object);
bool isObject = value->IsObject(vm_);
ASSERT_EQ(isObject, true);
bool isPendingException = true;
bool isArrayOrSharedArray = false;
const uint32_t INIT_VALUE = 10;
uint32_t arrayLength = INIT_VALUE;
value->TryGetArrayLength(vm_, &isPendingException, &isArrayOrSharedArray, &arrayLength);
ASSERT_EQ(isPendingException, false);
ASSERT_EQ(isArrayOrSharedArray, false);
ASSERT_EQ(arrayLength, INIT_VALUE);
}
HWTEST_F_L0(JSNApiTests, TryGetArrayLengthTest004)
{
LocalScope scope(vm_);
const uint32_t ARRAY_LENGTH = 10;
Local<ArrayRef> array = ArrayRef::New(vm_, ARRAY_LENGTH);
Local<JSValueRef> value(array);
bool isJSArray = value->IsJSArray(vm_);
ASSERT_EQ(isJSArray, true);
Local<JSValueRef> error = Exception::Error(vm_, StringRef::NewFromUtf8(vm_, ERROR_MESSAGE));
ASSERT_EQ(error->IsError(vm_), true);
JSNApi::ThrowException(vm_, error);
JSThread *thread = vm_->GetJSThread();
ASSERT_EQ(thread->HasPendingException(), true);
bool isPendingException = false;
bool isArrayOrSharedArray = false;
uint32_t arrayLength = ARRAY_LENGTH;
value->TryGetArrayLength(vm_, &isPendingException, &isArrayOrSharedArray, &arrayLength);
ASSERT_EQ(isPendingException, true);
ASSERT_EQ(isArrayOrSharedArray, true);
ASSERT_EQ(arrayLength, 0);
JSNApi::GetAndClearUncaughtException(vm_);
ASSERT_EQ(thread->HasPendingException(), false);
}
HWTEST_F_L0(JSNApiTests, TryGetArrayLengthTest005)
{
LocalScope scope(vm_);
const uint32_t ARRAY_LENGTH = 10;
Local<SendableArrayRef> sArray = SendableArrayRef::New(vm_, ARRAY_LENGTH);
Local<JSValueRef> value(sArray);
bool isSArray = value->IsSharedArray(vm_);
ASSERT_EQ(isSArray, true);
Local<JSValueRef> error = Exception::Error(vm_, StringRef::NewFromUtf8(vm_, ERROR_MESSAGE));
ASSERT_EQ(error->IsError(vm_), true);
JSNApi::ThrowException(vm_, error);
JSThread *thread = vm_->GetJSThread();
ASSERT_EQ(thread->HasPendingException(), true);
bool isPendingException = false;
bool isArrayOrSharedArray = false;
uint32_t arrayLength = ARRAY_LENGTH;
value->TryGetArrayLength(vm_, &isPendingException, &isArrayOrSharedArray, &arrayLength);
ASSERT_EQ(isPendingException, true);
ASSERT_EQ(isArrayOrSharedArray, true);
ASSERT_EQ(arrayLength, 0);
JSNApi::GetAndClearUncaughtException(vm_);
ASSERT_EQ(thread->HasPendingException(), false);
}
HWTEST_F_L0(JSNApiTests, TryGetArrayLengthTest006)
{
LocalScope scope(vm_);
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> value(object);
bool isObject = value->IsObject(vm_);
ASSERT_EQ(isObject, true);
Local<JSValueRef> error = Exception::Error(vm_, StringRef::NewFromUtf8(vm_, ERROR_MESSAGE));
ASSERT_EQ(error->IsError(vm_), true);
JSNApi::ThrowException(vm_, error);
JSThread *thread = vm_->GetJSThread();
ASSERT_EQ(thread->HasPendingException(), true);
bool isPendingException = false;
bool isArrayOrSharedArray = true;
const uint32_t INIT_VALUE = 10;
uint32_t arrayLength = INIT_VALUE;
value->TryGetArrayLength(vm_, &isPendingException, &isArrayOrSharedArray, &arrayLength);
ASSERT_EQ(isPendingException, true);
ASSERT_EQ(isArrayOrSharedArray, false);
ASSERT_EQ(arrayLength, INIT_VALUE);
JSNApi::GetAndClearUncaughtException(vm_);
ASSERT_EQ(thread->HasPendingException(), false);
}
* @tc.number: ffi_interface_api_147
* @tc.name: UpdateStackInfo
* @tc.desc: Used to verify whether the function of update stack info was successful.
* @tc.type: FUNC
* @tc.require: parameter
*/
HWTEST_F_L0(JSNApiTests, UpdateStackInfo)
{
LocalScope scope(vm_);
StackInfo stackInfo = { 0x10000, 0 };
uint64_t currentStackLimit = vm_->GetJSThread()->GetStackLimit();
JSNApi::UpdateStackInfo(vm_, &stackInfo, 0);
ASSERT_EQ(vm_->GetJSThread()->GetStackLimit(), 0x10000);
JSNApi::UpdateStackInfo(vm_, &stackInfo, 1);
ASSERT_EQ(vm_->GetJSThread()->GetStackLimit(), currentStackLimit);
JSNApi::UpdateStackInfo(vm_, nullptr, 0);
ASSERT_EQ(vm_->GetJSThread()->GetStackLimit(), currentStackLimit);
}
HWTEST_F_L0(JSNApiTests, JSNApi_CreateContext001)
{
LocalScope scope(vm_);
Local<JSValueRef> contextValue = JSNApi::CreateContext(vm_);
EXPECT_TRUE(contextValue->IsHeapObject());
EXPECT_TRUE(contextValue->IsJsGlobalEnv(vm_));
}
HWTEST_F_L0(JSNApiTests, JSNApi_GetCurrentContext001)
{
LocalScope scope(vm_);
Local<JSValueRef> contextValue = JSNApi::GetCurrentContext(vm_);
EXPECT_TRUE(contextValue->IsHeapObject());
EXPECT_TRUE(contextValue->IsJsGlobalEnv(vm_));
}
HWTEST_F_L0(JSNApiTests, JSNApi_Local_Operator_equal001)
{
LocalScope scope(vm_);
Local<JSValueRef> contextValue = JSNApi::CreateContext(vm_);
Local<JSValueRef> newContext = Local<JSValueRef>(contextValue);
EXPECT_TRUE(contextValue == newContext);
}
HWTEST_F_L0(JSNApiTests, JSNApi_SwitchContext001)
{
LocalScope scope(vm_);
Local<JSValueRef> contextValue = JSNApi::CreateContext(vm_);
EXPECT_TRUE(contextValue->IsHeapObject());
EXPECT_TRUE(contextValue->IsJsGlobalEnv(vm_));
Local<JSValueRef> currentContext = JSNApi::GetCurrentContext(vm_);
EXPECT_FALSE(currentContext == contextValue);
JSNApi::SwitchContext(vm_, contextValue);
Local<JSValueRef> switchedContext = JSNApi::GetCurrentContext(vm_);
EXPECT_TRUE(switchedContext == contextValue);
}
HWTEST_F_L0(JSNApiTests, XRefGlobalHandleAddr)
{
JSNApi::InitHybridVMEnv(vm_);
JSHandle<TaggedArray> weakRefArray = vm_->GetFactory()->NewTaggedArray(2, JSTaggedValue::Hole());
uintptr_t xRefArrayAddress;
vm_->SetEnableForceGC(false);
{
[[maybe_unused]] EcmaHandleScope scope(thread_);
JSHandle<JSTaggedValue> xRefArray = JSArray::ArrayCreate(thread_, JSTaggedNumber(1));
JSHandle<JSTaggedValue> normalArray = JSArray::ArrayCreate(thread_, JSTaggedNumber(2));
xRefArrayAddress = JSNApiGetXRefGlobalHandleAddr(vm_, xRefArray.GetAddress());
weakRefArray->Set(thread_, 0, xRefArray.GetTaggedValue().CreateAndGetWeakRef());
weakRefArray->Set(thread_, 1, normalArray.GetTaggedValue().CreateAndGetWeakRef());
}
vm_->CollectGarbage(TriggerGCType::FULL_GC);
EXPECT_TRUE(!weakRefArray->Get(thread_, 0).IsUndefined());
EXPECT_TRUE(weakRefArray->Get(thread_, 1).IsUndefined());
JSNApiDisposeXRefGlobalHandleAddr(vm_, xRefArrayAddress);
vm_->CollectGarbage(TriggerGCType::FULL_GC);
vm_->SetEnableForceGC(true);
EXPECT_TRUE(weakRefArray->Get(thread_, 0).IsUndefined());
}
HWTEST_F_L0(JSNApiTests, InitHybridVMEnv)
{
LocalScope scope(vm_);
JSNApi::InitHybridVMEnv(vm_);
auto instance = ecmascript::Runtime::GetInstance();
ASSERT(instance != nullptr);
EXPECT_TRUE(instance->IsHybridVm());
}
HWTEST_F_L0(JSNApiTests, NewFromUtf8Replacement)
{
uint8_t u8Data[1024] = {0xcc, 0x5c, 0x0};
uint8_t u8Out[1024] = {0};
size_t u8OutLen = 0;
Local<StringRef> resStr = StringRef::NewFromUtf8Replacement(thread_->GetEcmaVM(),
reinterpret_cast<char*>(u8Data), 2);
u8OutLen = resStr-> Utf8Length(thread_->GetEcmaVM());
resStr -> WriteUtf8(thread_->GetEcmaVM(), reinterpret_cast<char*>(u8Out), u8OutLen);
ASSERT_TRUE(u8Out[0] == 0xef);
ASSERT_TRUE(u8Out[1] == 0xbf);
ASSERT_TRUE(u8Out[2] == 0xbd);
ASSERT_TRUE(u8Out[3] == 0x5c);
ASSERT_TRUE(u8Out[4] == 0x0);
{
std::string input[4];
input[0] = "ahskdjashdjkasdhashiwyqoieysodahlkdhjaldqdwqwertyuiopp;kjsxcvbnm,kqqaxvbnkhd";
input[1] = "埃里克多少啊收到了賀卡收到和拉丁八點幺五i一起玩按時打算到i的後期維護公司付款就大概的";
input[2] = "🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗";
input[3] = input[0] + input[1] + input[2];
for (int i = 0; i < 3; i++) {
input[0] = input[0] + input[0];
input[1] = input[1] + input[1];
input[2] = input[2] + input[2];
input[3] = input[3] + input[3];
}
input[0] += "\0";
input[1] += "\0";
input[2] += "\0";
input[3] += "\0";
for (int i = 0; i < 4; i++) {
Local<StringRef> resStr = StringRef::NewFromUtf8Replacement(
thread_->GetEcmaVM(), input[i].c_str(), input[i].length());
u8OutLen = resStr-> Utf8Length(thread_->GetEcmaVM());
uint8_t *u8Out = static_cast<uint8_t *>(malloc(u8OutLen + 1));
resStr -> WriteUtf8(thread_->GetEcmaVM(), reinterpret_cast<char*>(u8Out), u8OutLen);
for (int j = 0; j <= input[i].size(); j++) {
ASSERT_TRUE(u8Out[j] == (uint8_t)input[i][j]);
}
free(u8Out);
Local<StringRef> resStr1 = StringRef::NewFromUtf8(
thread_->GetEcmaVM(), input[i].c_str(), input[i].length());
uint32_t u8OutLen2 = resStr1-> Utf8Length(thread_->GetEcmaVM());
ASSERT_TRUE(u8OutLen2 == u8OutLen);
}
}
}
HWTEST_F_L0(JSNApiTests, NewFromUtf8WithoutStringTableReplacement)
{
uint8_t u8Data[1024] = {0xcc, 0x5c, 0x0};
uint8_t u8Out[1024] = {0};
size_t u8OutLen = 0;
Local<StringRef> resStr = StringRef::NewFromUtf8Replacement(thread_->GetEcmaVM(),
reinterpret_cast<char*>(u8Data), 2);
u8OutLen = resStr-> Utf8Length(thread_->GetEcmaVM());
resStr -> WriteUtf8(thread_->GetEcmaVM(), reinterpret_cast<char*>(u8Out), u8OutLen);
ASSERT_TRUE(u8Out[0] == 0xef);
ASSERT_TRUE(u8Out[1] == 0xbf);
ASSERT_TRUE(u8Out[2] == 0xbd);
ASSERT_TRUE(u8Out[3] == 0x5c);
ASSERT_TRUE(u8Out[4] == 0x0);
{
std::string input[4];
input[0] = "ahskdjashdjkasdhashiwyqoieysodahlkdhjaldqdwqwertyuiopp;kjsxcvbnm,kqqaxvbnkhd";
input[1] = "埃里克多少啊收到了賀卡收到和拉丁八點幺五i一起玩按時打算到i的後期維護公司付款就大概的";
input[2] = "🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗🤗";
input[3] = input[0] + input[1] + input[2];
for (int i = 0; i < 3; i++) {
input[0] = input[0] + input[0];
input[1] = input[1] + input[1];
input[2] = input[2] + input[2];
input[3] = input[3] + input[3];
}
input[0] += "\0";
input[1] += "\0";
input[2] += "\0";
input[3] += "\0";
for (int i = 0; i < 4; i++) {
Local<StringRef> resStr = StringRef::NewFromUtf8Replacement(
thread_->GetEcmaVM(), input[i].c_str(), input[i].length());
u8OutLen = resStr-> Utf8Length(thread_->GetEcmaVM());
uint8_t *u8Out = static_cast<uint8_t *>(malloc(u8OutLen + 1));
resStr -> WriteUtf8(thread_->GetEcmaVM(), reinterpret_cast<char*>(u8Out), u8OutLen);
for (int j = 0; j <= input[i].size(); j++) {
ASSERT_TRUE(u8Out[j] == (uint8_t)input[i][j]);
}
free(u8Out);
Local<StringRef> resStr1 = StringRef::NewFromUtf8(
thread_->GetEcmaVM(), input[i].c_str(), input[i].length());
uint32_t u8OutLen2 = resStr1-> Utf8Length(thread_->GetEcmaVM());
ASSERT_TRUE(u8OutLen2 == u8OutLen);
}
}
}
HWTEST_F_L0(JSNApiTests, FindModuleInAbcFile001)
{
LocalScope scope(vm_);
const std::string filename = "data/storage/el1/bundle/modulename/ets/modules.abc";
const std::string ohmUrl1 = "@normalized:N&&&entry/build/generated/r/table";
const char *data = R"(
.language ECMAScript
.function any func_main_0(any a0, any a1, any a2) {
ldai 1
return
}
)";
CString entryPoint = "";
std::shared_ptr<JSPandaFile> pf = NewMockJSPandaFile(data, filename.c_str(), ohmUrl1.c_str(), entryPoint);
bool res = JSNApi::FindModuleInAbcFile(vm_, filename, ohmUrl1);
EXPECT_TRUE(res);
}
HWTEST_F_L0(JSNApiTests, FindModuleInAbcFile002)
{
LocalScope scope(vm_);
const std::string filename = "data/storage/el1/bundle/modulename/ets/test.abc";
const std::string ohmUrl1 = "@normalized:N&&&entry/build/generated/r/table";
const std::string ohmUrl2 = "@normalized:N&&&entry/build/generated/r/desk";
const char *data = R"(
.language ECMAScript
.function any func_main_0(any a0, any a1, any a2) {
ldai 1
return
}
)";
CString entryPoint = "";
std::shared_ptr<JSPandaFile> pf = NewMockJSPandaFile(data, filename.c_str(), ohmUrl1.c_str(), entryPoint);
bool res = JSNApi::FindModuleInAbcFile(vm_, filename, ohmUrl2);
EXPECT_FALSE(res);
}
HWTEST_F_L0(JSNApiTests, FindModuleInAbcFile003)
{
LocalScope scope(vm_);
const std::string filename = "data/storage/el1/bundle/modulename/ets/test1.abc";
const std::string ohmUrl1 = "@normalized:N&&&entry/build/generated/r/desk";
const char *data = R"(
.language ECMAScript
.function any func_main_0(any a0, any a1, any a2) {
ldai 1
return
}
)";
CString entryPoint = "";
std::shared_ptr<JSPandaFile> pf = NewMockJSPandaFile(data, filename.c_str(), ohmUrl1.c_str(), entryPoint);
bool res = JSNApi::FindModuleInAbcFile(vm_, filename, ohmUrl1);
EXPECT_TRUE(res);
}
void UncatchableErrorHandlerImpl([[maybe_unused]]panda::TryCatch& tryCatch)
{
return;
}
HWTEST_F_L0(JSNApiTests, RegisterUncatchableErrorHandler001)
{
LocalScope scope(vm_);
UncatchableErrorHandler func1 = JSNApi::GetUncatchableErrorHandler(vm_);
EXPECT_EQ(func1, nullptr);
JSNApi::RegisterUncatchableErrorHandler(vm_, UncatchableErrorHandlerImpl);
UncatchableErrorHandler func2 = JSNApi::GetUncatchableErrorHandler(vm_);
EXPECT_NE(func2, nullptr);
}
HWTEST_F_L0(JSNApiTests, FindModuleInAbcFile004)
{
LocalScope scope(vm_);
const std::string filename = "data/storage/el1/bundle/modulename/ets/test2.abc";
const std::string ohmUrl1 = "@normalized:N&&&entry/build/generated/r/box";
const std::string ohmUrl2 = "@normalized:N&&&entry/build/generated/r/desk";
const char *data = R"(
.language ECMAScript
.function any func_main_0(any a0, any a1, any a2) {
ldai 1
return
}
)";
CString entryPoint = "";
std::shared_ptr<JSPandaFile> pf = NewMockJSPandaFile(data, filename.c_str(), ohmUrl1.c_str(), entryPoint);
bool res = JSNApi::FindModuleInAbcFile(vm_, filename, ohmUrl2);
EXPECT_FALSE(res);
}
HWTEST_F_L0(JSNApiTests, CrossThreadExecution)
{
bool res = JSNApi::CheckAndSetAllowCrossThreadExecution(vm_);
if (ecmascript::g_isEnableCMCGC) {
EXPECT_FALSE(res);
} else {
if (res) {
JSNApi::DisallowCrossThreadExecution(vm_);
} else {
GTEST_LOG_(INFO) << "vm is in the gc or shared gc";
}
}
}
HWTEST_F_L0(JSNApiTests, IsCrossBundleHsp)
{
JSNApi::SetBundleName(vm_, "com.application.demo");
const std::string ohmurl1 = "@normalized:N&hsp&com.application.demo&hsp/Index&";
bool res1 = JSNApi::IsCrossBundleHsp(vm_, ohmurl1);
EXPECT_EQ(res1, false);
const std::string ohmurl2 = "@normalized:N&crosshsp&com.application.demo1&crosshsp/Index&";
bool res2 = JSNApi::IsCrossBundleHsp(vm_, ohmurl2);
EXPECT_EQ(res2, true);
}
HWTEST_F_L0(JSNApiTests, GetModuleNameSpaceWithOhmurlForHybridApp)
{
LocalScope scope(vm_);
std::map<std::string, std::vector<std::vector<std::string>>> pkgList;
std::vector<std::string> entryList = {
"entry",
"packageName", "entry",
"bundleName", "",
"moduleName", "",
"version", "",
"entryPath", "src/main/",
"isSO", "false"
};
pkgList["entry"] = {entryList};
JSNApi::SetpkgContextInfoList(vm_, pkgList);
const std::string ohmurl = "@normalized:N&crosshsp&com.application.demo&crosshsp/Index&";
const std::string filename = "/data/storage/el1/bundle/com.application.demo/crosshsp/crosshsp/ets/modules.abc";
const char *data = R"(
.language ECMAScript
.function any func_main_0(any a0, any a1, any a2) {
ldai 1
return
}
)";
CString entryPoint = "";
std::shared_ptr<JSPandaFile> pf = NewMockJSPandaFile(data, filename.c_str(), ohmurl.c_str(), entryPoint);
JSHandle<SourceTextModule> testModule = vm_->GetFactory()->NewSourceTextModule();
ecmascript::ModuleManager *moduleManager = thread_->GetModuleManager();
testModule->SetStatus(ModuleStatus::EVALUATED);
moduleManager->AddResolveImportedModule("com.application.demo&crosshsp/Index&", testModule.GetTaggedValue());
Local<ObjectRef> res = JSNApi::GetModuleNameSpaceWithOhmurlForHybridApp(vm_, ohmurl);
JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(res);
EXPECT_TRUE(obj.GetTaggedValue() != JSTaggedValue::Undefined());
}
}