* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/ecma_vm.h"
#include "ecmascript/js_runtime_options.h"
#include "ecmascript/tests/test_helper.h"
#if defined(PANDA_TARGET_OHOS) && !defined(STANDALONE_MODE)
#include "parameters.h"
#endif
#include <csetjmp>
#include <csignal>
using namespace panda::ecmascript;
using namespace common;
namespace panda::test {
class EcmaVMTest : public BaseTestWithOutScope {
};
static thread_local sigjmp_buf g_env;
static thread_local bool g_abortFlag = false;
static std::mutex g_signalMutex;
static void ProcessHandleAllocAbort(int sig)
{
ForceResetAssertData();
g_abortFlag = true;
siglongjmp(g_env, sig);
}
static int RegisterSignal(struct sigaction* oldAct = nullptr)
{
std::lock_guard<std::mutex> lock(g_signalMutex);
struct sigaction act;
act.sa_handler = ProcessHandleAllocAbort;
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask, SIGABRT);
act.sa_flags = 0;
return sigaction(SIGABRT, &act, oldAct);
}
static void RestoreSignal(const struct sigaction* oldAct)
{
std::lock_guard<std::mutex> lock(g_signalMutex);
sigaction(SIGABRT, oldAct, nullptr);
}
static void ResetAbortFlag()
{
g_abortFlag = false;
}
class EcmaVmIterator : public ecmascript::RootVisitor {
public:
EcmaVmIterator() = default;
~EcmaVmIterator() = default;
void VisitRoot([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot slot) override {}
void VisitRangeRoot([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot start,
[[maybe_unused]] ObjectSlot end) override
{
CHECK_NO_HANDLE_ALLOC;
}
void VisitBaseAndDerivedRoot([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot base,
[[maybe_unused]] ObjectSlot derived, [[maybe_unused]] uintptr_t baseOldObject) override {}
};
* @tc.name: CreateEcmaVMInTwoWays
* @tc.desc: Create EcmaVM in 2 ways, check the Options state
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(EcmaVMTest, CreateEcmaVMInTwoWays)
{
RuntimeOption options;
options.SetLogLevel(common::LOG_LEVEL::ERROR);
EcmaVM::SetMultiThreadCheck(true);
EcmaVM *ecmaVm1 = JSNApi::CreateJSVM(options);
EXPECT_TRUE(ecmaVm1->GetMultiThreadCheck());
auto jsthread1 = ecmaVm1->GetJSThread();
EXPECT_TRUE(jsthread1 != nullptr);
std::thread t1([&]() {
JSRuntimeOptions options2;
options2.SetEnableArkTools(false);
options2.SetEnableForceGC(false);
options2.SetForceFullGC(false);
options2.SetArkProperties(ArkProperties::GC_STATS_PRINT);
options2.SetMemConfigProperty("jsHeap500");
EcmaVM::SetMultiThreadCheck(false);
EcmaVM *ecmaVm2 = JSNApi::CreateEcmaVM(options2);
auto jsthread2 = ecmaVm2->GetJSThread();
EXPECT_FALSE(ecmaVm2->GetMultiThreadCheck());
EXPECT_TRUE(jsthread2 != nullptr);
EXPECT_TRUE(ecmaVm1 != ecmaVm2);
JSRuntimeOptions options1Out = ecmaVm1->GetJSOptions();
JSRuntimeOptions options2Out = ecmaVm2->GetJSOptions();
EXPECT_TRUE(&options1Out != &options2Out);
EXPECT_TRUE(options1Out.EnableArkTools() != options2Out.EnableArkTools());
EXPECT_TRUE(options1Out.EnableForceGC() != options2Out.EnableForceGC());
EXPECT_TRUE(options1Out.ForceFullGC() != options2Out.ForceFullGC());
EXPECT_TRUE(options1Out.GetArkProperties() != options2Out.GetArkProperties());
EXPECT_TRUE(options2Out.GetHeapSize() == 500_MB);
options2.SetAsmOpcodeDisableRange("1,10");
options2.ParseAsmInterOption();
EXPECT_TRUE(options2.GetAsmInterParsedOption().handleStart == 1);
EXPECT_TRUE(options2.GetAsmInterParsedOption().handleEnd == 10);
options2.SetAsmOpcodeDisableRange("0x1,0xa");
options2.ParseAsmInterOption();
EXPECT_TRUE(options2.GetAsmInterParsedOption().handleStart == 1);
EXPECT_TRUE(options2.GetAsmInterParsedOption().handleEnd == 10);
options2.SetAsmOpcodeDisableRange(",");
options2.ParseAsmInterOption();
EXPECT_TRUE(options2.GetAsmInterParsedOption().handleStart == 0);
EXPECT_TRUE(options2.GetAsmInterParsedOption().handleEnd == kungfu::BYTECODE_STUB_END_ID);
options2.SetAsmOpcodeDisableRange("@,@");
options2.ParseAsmInterOption();
EXPECT_TRUE(options2.GetAsmInterParsedOption().handleStart == 0);
EXPECT_TRUE(options2.GetAsmInterParsedOption().handleEnd == kungfu::BYTECODE_STUB_END_ID);
JSNApi::DestroyJSVM(ecmaVm2);
});
t1.join();
JSNApi::DestroyJSVM(ecmaVm1);
}
HWTEST_F_L0(EcmaVMTest, DumpExceptionObject)
{
RuntimeOption option;
option.SetLogLevel(common::LOG_LEVEL::ERROR);
EcmaVM *ecmaVm = JSNApi::CreateJSVM(option);
auto thread = ecmaVm->GetJSThread();
int arkProperties = thread->GetEcmaVM()->GetJSOptions().GetArkProperties();
ecmaVm->GetJSOptions().SetArkProperties(arkProperties | ArkProperties::EXCEPTION_BACKTRACE);
EXPECT_TRUE(ecmaVm->GetJSOptions().EnableExceptionBacktrace());
JSNApi::DestroyJSVM(ecmaVm);
}
HWTEST_F_L0(EcmaVMTest, LargeHeap)
{
RuntimeOption option;
option.SetLargeHeap(true);
EcmaVM *ecmaVm = JSNApi::CreateJSVM(option);
EXPECT_TRUE(ecmaVm->GetJSOptions().GetLargeHeap());
JSNApi::DestroyJSVM(ecmaVm);
}
HWTEST_F_L0(EcmaVMTest, TestHandleAlocate)
{
RuntimeOption option;
option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR);
EcmaVM *ecmaVm = JSNApi::CreateJSVM(option);
[[maybe_unused]]HeapProfilerInterface *heapProfile = HeapProfilerInterface::GetInstance(ecmaVm);
ObjectFactory *factory = ecmaVm->GetFactory();
factory->NewJSArrayBuffer(10);
factory->NewJSSharedArrayBuffer(10);
factory->NewPromiseReaction();
factory->NewPromiseCapability();
factory->NewPromiseRecord();
factory->NewResolvingFunctionsRecord();
struct sigaction oldAct;
ASSERT_TRUE(RegisterSignal(&oldAct) != -1);
{
EcmaVmIterator ecmaVmIterator;
auto ret = sigsetjmp(g_env, 1);
if (ret != SIGABRT) {
ecmaVm->Iterate(ecmaVmIterator);
} else {
EXPECT_TRUE(g_abortFlag);
}
}
RestoreSignal(&oldAct);
ResetAbortFlag();
ASSERT_TRUE(RegisterSignal(&oldAct) != -1);
{
EcmaVmIterator ecmaVmIterator;
auto ret = sigsetjmp(g_env, 1);
if (ret != SIGABRT) {
ecmaVm->IterateHandle(ecmaVmIterator);
} else {
EXPECT_TRUE(g_abortFlag);
}
}
RestoreSignal(&oldAct);
ResetAbortFlag();
JSNApi::DestroyJSVM(ecmaVm);
}
HWTEST_F_L0(EcmaVMTest, TestInitConfigurableParam)
{
#if defined(PANDA_TARGET_OHOS) && !defined(STANDALONE_MODE)
OHOS::system::SetParameter("persist.ark.sheap.growfactor", "1");
OHOS::system::SetParameter("persist.ark.sheap.growstep", "2");
OHOS::system::SetParameter("persist.ark.sensitive.threshold", "3");
OHOS::system::SetParameter("persist.ark.native.stepsize", "4");
OHOS::system::SetParameter("persist.ark.global.alloclimit", "4");
EcmaParamConfiguration cfg = EcmaParamConfiguration(EcmaParamConfiguration::HeapType::WORKER_HEAP,
MAX_HEAP_SIZE, MAX_HEAP_SIZE);
EcmaVM::InitConfigurableParam(cfg);
EXPECT_TRUE(cfg.GetSharedHeapLimitGrowingFactor() != 1);
EXPECT_TRUE(cfg.GetSharedHeapLimitGrowingStep() != 2_MB);
EXPECT_TRUE(cfg.GetIncObjSizeThresholdInSensitive() != 3_MB);
EXPECT_TRUE(cfg.GetStepNativeSizeInc() != 4_MB);
EXPECT_TRUE(cfg.GetDefaultGlobalAllocLimit() != 4_MB);
OHOS::system::SetParameter("persist.ark.sheap.growfactor", "4");
OHOS::system::SetParameter("persist.ark.sheap.growstep", "10");
OHOS::system::SetParameter("persist.ark.sensitive.threshold", "10");
OHOS::system::SetParameter("persist.ark.native.stepsize", "128");
OHOS::system::SetParameter("persist.ark.global.alloclimit", "10");
EcmaVM::InitConfigurableParam(cfg);
EXPECT_TRUE(cfg.GetSharedHeapLimitGrowingFactor() == 4);
EXPECT_TRUE(cfg.GetSharedHeapLimitGrowingStep() == 10_MB);
EXPECT_TRUE(cfg.GetIncObjSizeThresholdInSensitive() == 10_MB);
EXPECT_TRUE(cfg.GetStepNativeSizeInc() == 128_MB);
EXPECT_TRUE(cfg.GetDefaultGlobalAllocLimit() == 10_MB);
OHOS::system::SetParameter("persist.ark.sheap.growfactor", "10");
OHOS::system::SetParameter("persist.ark.sheap.growstep", "640");
OHOS::system::SetParameter("persist.ark.sensitive.threshold", "640");
OHOS::system::SetParameter("persist.ark.native.stepsize", "2048");
OHOS::system::SetParameter("persist.ark.global.alloclimit", "256");
EcmaVM::InitConfigurableParam(cfg);
EXPECT_TRUE(cfg.GetSharedHeapLimitGrowingFactor() != 10);
EXPECT_TRUE(cfg.GetSharedHeapLimitGrowingStep() != 640_MB);
EXPECT_TRUE(cfg.GetIncObjSizeThresholdInSensitive() != 640_MB);
EXPECT_TRUE(cfg.GetStepNativeSizeInc() != 2048_MB);
EXPECT_TRUE(cfg.GetDefaultGlobalAllocLimit() != 256_MB);
#endif
}
}