• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "assembler/assembly-emitter.h"
17 #include "assembler/assembly-parser.h"
18 
19 #include "ecmascript/jspandafile/js_pandafile.h"
20 #include "ecmascript/jspandafile/js_pandafile_manager.h"
21 #include "ecmascript/tests/test_helper.h"
22 #include "ecmascript/napi/include/jsnapi.h"
23 #include "ecmascript/patch/quick_fix_manager.h"
24 #include "ecmascript/jspandafile/program_object.h"
25 
26 using namespace panda::ecmascript;
27 using namespace panda::panda_file;
28 using namespace panda::pandasm;
29 
30 namespace panda::test {
31 using PatchErrorCode = panda::JSNApi::PatchErrorCode;
32 using Program = panda::ecmascript::Program;
33 using EcmaContext = panda::ecmascript::EcmaContext;
34 class QuickFixTest : public testing::Test {
35 public:
SetUpTestCase()36     static void SetUpTestCase()
37     {
38         GTEST_LOG_(INFO) << "SetUpTestCase";
39     }
40 
TearDownTestCase()41     static void TearDownTestCase()
42     {
43         GTEST_LOG_(INFO) << "TearDownCase";
44     }
45 
SetUp()46     void SetUp() override
47     {
48         TestHelper::CreateEcmaVMWithScope(instance, thread, scope, false, false, false);
49     }
50 
TearDown()51     void TearDown() override
52     {
53         TestHelper::DestroyEcmaVMWithScope(instance, scope, false);
54     }
55 
56     EcmaVM *instance {nullptr};
57     EcmaHandleScope *scope {nullptr};
58     JSThread *thread {nullptr};
59 };
60 
HWTEST_F_L0(QuickFixTest,HotReload_SingleFile)61 HWTEST_F_L0(QuickFixTest, HotReload_SingleFile)
62 {
63     std::string baseFileName = QUICKFIX_ABC_PATH "single_file/base/index.abc";
64     std::string patchFileName = QUICKFIX_ABC_PATH "single_file/patch/index.abc";
65 
66     JSNApi::EnableUserUncaughtErrorHandler(instance);
67 
68     JSNApi::SetBundle(instance, false);
69 
70     bool result = JSNApi::Execute(instance, baseFileName, "index");
71     EXPECT_TRUE(result);
72 
73     auto res = JSNApi::LoadPatch(instance, patchFileName, baseFileName);
74     EXPECT_TRUE(res == PatchErrorCode::SUCCESS);
75 
76     Local<ObjectRef> exception = JSNApi::GetAndClearUncaughtException(instance);
77     result = JSNApi::IsQuickFixCausedException(instance, exception, patchFileName);
78     EXPECT_FALSE(result);
79 
80     res = JSNApi::UnloadPatch(instance, patchFileName);
81     EXPECT_TRUE(res == PatchErrorCode::SUCCESS);
82 }
83 
HWTEST_F_L0(QuickFixTest,HotReload_MultiFile)84 HWTEST_F_L0(QuickFixTest, HotReload_MultiFile)
85 {
86     std::string baseFileName = QUICKFIX_ABC_PATH "multi_file/base/merge.abc";
87     std::string patchFileName = QUICKFIX_ABC_PATH "multi_file/patch/merge.abc";
88 
89     JSNApi::EnableUserUncaughtErrorHandler(instance);
90 
91     JSNApi::SetBundle(instance, false);
92 
93     bool result = JSNApi::Execute(instance, baseFileName, "main");
94     EXPECT_TRUE(result);
95 
96     auto res = JSNApi::LoadPatch(instance, patchFileName, baseFileName);
97     EXPECT_TRUE(res == PatchErrorCode::SUCCESS);
98 
99     Local<ObjectRef> exception = JSNApi::GetAndClearUncaughtException(instance);
100     result = JSNApi::IsQuickFixCausedException(instance, exception, patchFileName);
101     EXPECT_FALSE(result);
102 
103     res = JSNApi::UnloadPatch(instance, patchFileName);
104     EXPECT_TRUE(res == PatchErrorCode::SUCCESS);
105 }
106 
HWTEST_F_L0(QuickFixTest,HotReload_MultiHap)107 HWTEST_F_L0(QuickFixTest, HotReload_MultiHap)
108 {
109     std::string baseFileName1 = QUICKFIX_ABC_PATH "single_file/base/index.abc";
110     std::string patchFileName1 = QUICKFIX_ABC_PATH "single_file/patch/index.abc";
111 
112     std::string baseFileName2 = QUICKFIX_ABC_PATH "multi_file/base/merge.abc";
113     std::string patchFileName2 = QUICKFIX_ABC_PATH "multi_file/patch/merge.abc";
114 
115     JSNApi::SetBundle(instance, false);
116 
117     bool result = JSNApi::Execute(instance, baseFileName1, "index");
118     EXPECT_TRUE(result);
119 
120     result = JSNApi::Execute(instance, baseFileName2, "main");
121     EXPECT_TRUE(result);
122 
123     auto res = JSNApi::LoadPatch(instance, patchFileName1, baseFileName1);
124     EXPECT_TRUE(res == PatchErrorCode::SUCCESS);
125 
126     res = JSNApi::LoadPatch(instance, patchFileName2, baseFileName2);
127     EXPECT_TRUE(res == PatchErrorCode::SUCCESS);
128 
129     res = JSNApi::UnloadPatch(instance, patchFileName1);
130     EXPECT_TRUE(res == PatchErrorCode::SUCCESS);
131 
132     res = JSNApi::UnloadPatch(instance, patchFileName2);
133     EXPECT_TRUE(res == PatchErrorCode::SUCCESS);
134 }
135 
HWTEST_F_L0(QuickFixTest,HotReload_Buffer)136 HWTEST_F_L0(QuickFixTest, HotReload_Buffer)
137 {
138     const char *baseFileName = "__base.pa";
139     const char *baseData = R"(
140         .function void foo() {}
141     )";
142     const char *patchFileName = "__patch.pa";
143     const char *patchData = R"(
144         .function void foo() {}
145     )";
146 
147     JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
148     Parser parser;
149     auto res = parser.Parse(patchData);
150     std::unique_ptr<const File> basePF = pandasm::AsmEmitter::Emit(res.Value());
151     std::unique_ptr<const File> patchPF = pandasm::AsmEmitter::Emit(res.Value());
152     std::shared_ptr<JSPandaFile> baseFile = pfManager->NewJSPandaFile(basePF.release(), CString(baseFileName));
153     std::shared_ptr<JSPandaFile> patchFile = pfManager->NewJSPandaFile(patchPF.release(), CString(patchFileName));
154     pfManager->AddJSPandaFile(baseFile);
155     pfManager->AddJSPandaFile(patchFile);
156 
157     auto result = JSNApi::LoadPatch(instance, patchFileName, (uint8_t *)patchData, sizeof(patchData),
158                                     baseFileName, (uint8_t *)baseData, sizeof(baseData));
159     EXPECT_FALSE(result == PatchErrorCode::SUCCESS);
160 
161     pfManager->RemoveJSPandaFile(baseFile.get());
162     pfManager->RemoveJSPandaFile(patchFile.get());
163 }
164 
HWTEST_F_L0(QuickFixTest,HotReload_Instantiate)165 HWTEST_F_L0(QuickFixTest, HotReload_Instantiate)
166 {
167     ThreadManagedScope managedScope(thread);
168 
169     CString baseFileName = QUICKFIX_ABC_PATH "multi_file/base/merge.abc";
170     std::shared_ptr<JSPandaFile> baseFile =
171         JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, baseFileName, "");
172     EXPECT_TRUE(baseFile != nullptr);
173 
174     CString patchFileName = QUICKFIX_ABC_PATH "multi_file/patch/merge.abc";
175     std::shared_ptr<JSPandaFile> patchFile =
176         JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, patchFileName, "");
177     EXPECT_TRUE(patchFile != nullptr);
178 
179     CString replacedRecordName = "main";
180     EcmaContext *context = thread->GetCurrentEcmaContext();
181     context->SetStageOfHotReload(StageOfHotReload::BEGIN_EXECUTE_PATCHMAIN);
182 
183     ModuleManager *moduleManager = context->GetModuleManager();
184     JSHandle<JSTaggedValue> module =
185         moduleManager->HostResolveImportedModuleWithMergeForHotReload(patchFileName, replacedRecordName, false);
186     EXPECT_FALSE(module->IsHole());
187 
188     JSHandle<Program> program =
189         JSPandaFileManager::GetInstance()->GenerateProgram(instance, patchFile.get(), replacedRecordName);
190     EXPECT_FALSE(program.IsEmpty());
191 
192     SourceTextModule::Instantiate(thread, module, false);
193     EXPECT_TRUE(JSHandle<SourceTextModule>::Cast(module)->GetStatus() == ModuleStatus::INSTANTIATED);
194 
195     context->SetStageOfHotReload(StageOfHotReload::LOAD_END_EXECUTE_PATCHMAIN);
196     JSHandle<SourceTextModule>::Cast(module)->SetStatus(ModuleStatus::UNINSTANTIATED);
197     SourceTextModule::Instantiate(thread, module, false);
198     EXPECT_TRUE(JSHandle<SourceTextModule>::Cast(module)->GetStatus() == ModuleStatus::INSTANTIATED);
199 }
200 
QuickFixQueryFunc(std::string baseFileName,std::string & patchFileName,uint8_t ** patchBuffer,size_t & patchBufferSize)201 bool QuickFixQueryFunc(
202     std::string baseFileName, std::string &patchFileName, uint8_t ** patchBuffer, size_t &patchBufferSize)
203 {
204     if (baseFileName != QUICKFIX_ABC_PATH "multi_file/base/merge.abc") {
205         return false;
206     }
207 
208     patchFileName = "__index.pa";
209     const char data[] = R"(
210         .function void foo() {}
211     )";
212 
213     Parser parser;
214     auto res = parser.Parse(data);
215     uint8_t *bufferData = reinterpret_cast<uint8_t *>((const_cast<char *>(data)));
216     *patchBuffer = bufferData;
217     patchBufferSize = sizeof(data);
218     return true;
219 }
220 
HWTEST_F_L0(QuickFixTest,HotReload_RegisterQuickFixQueryFunc)221 HWTEST_F_L0(QuickFixTest, HotReload_RegisterQuickFixQueryFunc)
222 {
223     std::string baseFileName = QUICKFIX_ABC_PATH "multi_file/base/merge.abc";
224     std::string patchFileName = "__index.pa";
225     JSNApi::RegisterQuickFixQueryFunc(instance, QuickFixQueryFunc);
226 
227     std::shared_ptr<JSPandaFile> baseFile =
228         JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, baseFileName.c_str(), "");
229     EXPECT_TRUE(baseFile != nullptr);
230     std::shared_ptr<JSPandaFile> patchFile =
231         JSPandaFileManager::GetInstance()->FindJSPandaFile(patchFileName.c_str());
232     EXPECT_TRUE(patchFile == nullptr);
233 
234     QuickFixManager *quickFixManager = instance->GetQuickFixManager();
235     quickFixManager->LoadPatchIfNeeded(thread, baseFile.get());
236 
237     JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
238     pfManager->RemoveJSPandaFile(baseFile.get());
239 }
240 }  // namespace panda::test
241