Adapt to hot patch and add testcases

Signed-off-by: lijiamin <lijiamin24@huawei.com>
Change-Id: Ida501c720acd3c78005d9252aed11606dc522d53
This commit is contained in:
lijiamin 2022-11-22 17:05:27 +08:00
parent 2dc5a68cf3
commit b58a685052
13 changed files with 215 additions and 42 deletions

View File

@ -101,7 +101,12 @@ bool QuickFixLoader::LoadPatchInternal(JSThread *thread, const JSPandaFile *base
}
if (!ReplaceMethod(thread, baseFile, patchFile, baseConstpoolValues.value())) {
LOG_ECMA(ERROR) << "replace method failed";
LOG_ECMA(ERROR) << "Replace method failed";
return false;
}
if (isHotPatch_ && !ExecutePatchMain(thread, patchPrograms, patchFile)) {
LOG_ECMA(ERROR) << "Execute patch main failed";
return false;
}
@ -138,6 +143,13 @@ CVector<JSHandle<Program>> QuickFixLoader::ParseAllConstpoolWithMerge(JSThread *
uint32_t mainMethodIndex = jsPandaFile->GetMainMethodIndex(recordName);
ASSERT(mainMethodIndex != 0);
const char *mainMethodName =
MethodLiteral::GetMethodName(jsPandaFile, panda_file::File::EntityId(mainMethodIndex));
if (!isHotPatch_ && std::strcmp(mainMethodName, JSPandaFile::PATCH_FUNCTION_NAME_0) == 0) {
isHotPatch_ = true;
}
if (!isNewVersion) {
PandaFileTranslator::ParseFuncAndLiteralConstPool(vm, jsPandaFile, recordName, constpool);
} else {
@ -404,49 +416,48 @@ bool QuickFixLoader::UnloadPatch(JSThread *thread, const CString &patchFileName)
return false;
}
for (const auto &iter : baseConstpoolValues.value().get()) {
uint32_t index = iter.first;
ConstantPool *baseConstpool = ConstantPool::Cast((iter.second).GetTaggedObject());
for (const auto &item : reservedBaseNormalMethodInfo_) {
NormalMethodIndex normalMethodIndex = item.first;
if (index == normalMethodIndex.constpoolNum) {
uint32_t constpoolIndex = normalMethodIndex.constpoolIndex;
MethodLiteral *base = item.second;
JSTaggedValue value = baseConstpool->GetObjectFromCache(constpoolIndex);
ASSERT(value.IsMethod());
Method *method = Method::Cast(value.GetTaggedObject());
JSTaggedValue baseConstpoolValue = FindConstpoolVal(thread, baseFile, base->GetMethodId());
ReplaceMethodInner(thread, method, base, baseConstpoolValue);
LOG_ECMA(INFO) << "Replace normal method: " << method->GetMethodName();
}
}
for (auto &item : reservedBaseClassMethodInfo_) {
ClassMethodIndex classMethodIndex = item.first;
if (index == classMethodIndex.constpoolNum) {
uint32_t constpoolIndex = classMethodIndex.constpoolIndex;
MethodLiteral *base = item.second;
TaggedArray *classLiteral = TaggedArray::Cast(baseConstpool->GetObjectFromCache(constpoolIndex));
JSTaggedValue value = classLiteral->Get(thread, classMethodIndex.literalIndex);
ASSERT(value.IsJSFunctionBase());
JSFunctionBase *func = JSFunctionBase::Cast(value.GetTaggedObject());
Method *method = Method::Cast(func->GetMethod().GetTaggedObject());
for (const auto &item : reservedBaseNormalMethodInfo_) {
NormalMethodIndex normalMethodIndex = item.first;
ConstantPool *baseConstpool = ConstantPool::Cast(
(baseConstpoolValues.value().get()[normalMethodIndex.constpoolNum]).GetTaggedObject());
JSTaggedValue baseConstpoolValue = FindConstpoolVal(thread, baseFile, base->GetMethodId());
ReplaceMethodInner(thread, method, base, baseConstpoolValue);
LOG_ECMA(INFO) << "Replace class method: " << method->GetMethodName();
}
}
uint32_t constpoolIndex = normalMethodIndex.constpoolIndex;
MethodLiteral *base = item.second;
JSTaggedValue value = baseConstpool->GetObjectFromCache(constpoolIndex);
ASSERT(value.IsMethod());
Method *method = Method::Cast(value.GetTaggedObject());
JSTaggedValue baseConstpoolValue = FindConstpoolVal(thread, baseFile, base->GetMethodId());
ReplaceMethodInner(thread, method, base, baseConstpoolValue);
LOG_ECMA(INFO) << "Replace normal method: " << method->GetMethodName();
}
for (auto &item : reservedBaseClassMethodInfo_) {
ClassMethodIndex classMethodIndex = item.first;
ConstantPool *baseConstpool = ConstantPool::Cast(
(baseConstpoolValues.value().get()[classMethodIndex.constpoolNum]).GetTaggedObject());
uint32_t constpoolIndex = classMethodIndex.constpoolIndex;
MethodLiteral *base = item.second;
TaggedArray *classLiteral = TaggedArray::Cast(baseConstpool->GetObjectFromCache(constpoolIndex));
JSTaggedValue value = classLiteral->Get(thread, classMethodIndex.literalIndex);
ASSERT(value.IsJSFunctionBase());
JSFunctionBase *func = JSFunctionBase::Cast(value.GetTaggedObject());
Method *method = Method::Cast(func->GetMethod().GetTaggedObject());
JSTaggedValue baseConstpoolValue = FindConstpoolVal(thread, baseFile, base->GetMethodId());
ReplaceMethodInner(thread, method, base, baseConstpoolValue);
LOG_ECMA(INFO) << "Replace class method: " << method->GetMethodName();
}
vm->GetJsDebuggerManager()->GetHotReloadManager()->NotifyPatchUnloaded(patchFile);
ClearReservedInfo();
ClearPatchInfo(thread, patchFileName);
isHotPatch_ = false;
LOG_ECMA(INFO) << "UnloadPatch success!";
return true;
}

View File

@ -84,6 +84,7 @@ private:
static bool CheckStarExportEntryMismatch(StarExportEntry *patch, StarExportEntry *base);
CString baseFileName_;
bool isHotPatch_ {false}; // true: HotPatch; false: HotReload.
struct NormalMethodIndex {
uint32_t constpoolNum {UINT32_MAX};

View File

@ -105,7 +105,7 @@ int Main(const int argc, const char **argv)
#endif
uint32_t len = fileNames.size();
if (len < 4) { // 4: four abc file
std::cout << "Must include base.abc, patch.abc, test1.abc, test2.abc absolute path" << std::endl;
std::cout << "Must include base.abc, patch.abc, test.abc, retest.abc absolute path" << std::endl;
return -1;
}
std::string baseFileName = fileNames[0];

View File

@ -13,7 +13,7 @@
import("//arkcompiler/ets_runtime/test/test_helper.gni")
test_list = [
hot_reload_test_list = [
"check_import",
"class_inheritance",
"class_mem_func",
@ -28,7 +28,7 @@ test_list = [
]
if (!is_debug) {
test_list += [
hot_reload_test_list += [
"multi_classconstpool",
"multi_closureconstpool",
"multi_constructorconstpool",
@ -37,6 +37,8 @@ if (!is_debug) {
]
}
hot_patch_test_list = [ "add_callfunction" ]
host_quickfix_test_action("multi_patch") {
extra_patches = [
"patch1",
@ -45,17 +47,28 @@ host_quickfix_test_action("multi_patch") {
entry_point = "--entry-point=base"
}
foreach(testcase, test_list) {
foreach(testcase, hot_reload_test_list) {
host_quickfix_test_action("${testcase}") {
entry_point = "--entry-point=base"
}
}
foreach(testcase, hot_patch_test_list) {
host_quickfix_test_action("${testcase}") {
entry_point = "--entry-point=base"
is_hotpatch = true
}
}
group("ark_quickfix_test") {
testonly = true
deps = []
foreach(testcase, test_list) {
foreach(testcase, hot_reload_test_list) {
deps += [ ":${testcase}QuickfixAction" ]
}
foreach(testcase, hot_patch_test_list) {
deps += [ ":${testcase}QuickfixAction" ]
}

View File

@ -0,0 +1,25 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function A() {
print("base A()");
B();
}
function B() {
print("base B()");
}
globalThis.A = A;
globalThis.B = B;

View File

@ -0,0 +1,2 @@
base.js;base;module;base.js
module.js;module;module;module.js

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function A() {
print("patch A()");
B();
C();
}
function B() {
print("patch B()");
}
function C() {
print("patch C()");
}
globalThis.C = C;

View File

@ -0,0 +1,26 @@
# Copyright (c) 2022 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
QuickFix Execute start
QuickFix start load patch
QuickFix load patch success
patch A()
patch B()
patch C()
QuickFix start check exception
QuickFix have no exception
QuickFix start unload patch
QuickFix unload patch success
base A()
base B()
QuickFix Execute end

View File

@ -0,0 +1,16 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export var nop = undefined

View File

@ -0,0 +1,16 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export var nop = undefined

View File

@ -0,0 +1,2 @@
base_modify.js;base;module;base.js
module_modify.js;module;module;module.js

View File

@ -0,0 +1,15 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
A()

View File

@ -630,6 +630,10 @@ template("host_quickfix_test_action") {
_script_args_ = invoker.entry_point + " "
}
if (defined(invoker.is_hotpatch) && invoker.is_hotpatch) {
_test_map_path_ = "$target_out_dir/${_target_name_}/base.map"
}
foreach(filename, _test_file_name_) {
merge_file_raw = "//arkcompiler/ets_runtime/test/quickfix/"
if (filename == "test" || filename == "retest") {
@ -670,10 +674,23 @@ template("host_quickfix_test_action") {
"--merge-abc",
]
if (defined(invoker.is_hotpatch) && filename == "patch") {
extra_args += [ "--generate-patch" ]
}
if (defined(invoker.is_hotpatch) && filename == "base") {
dump_symbol_table = rebase_path(_test_map_path_)
}
if (defined(invoker.is_hotpatch) && filename == "patch") {
input_symbol_table = rebase_path(_test_map_path_)
}
in_puts = [
_test_expect_path_,
merge_file,
]
out_puts = [ abc_path ]
}