• 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 #include "ecmascript/module/module_resolver.h"
26 
27 using namespace panda::ecmascript;
28 using namespace panda::panda_file;
29 using namespace panda::pandasm;
30 
31 namespace panda::test {
32 using Program = panda::ecmascript::Program;
33 class QuickFixTest : public testing::Test {
34 public:
SetUpTestCase()35     static void SetUpTestCase()
36     {
37         GTEST_LOG_(INFO) << "SetUpTestCase";
38     }
39 
TearDownTestCase()40     static void TearDownTestCase()
41     {
42         GTEST_LOG_(INFO) << "TearDownCase";
43     }
44 
SetUp()45     void SetUp() override
46     {
47         TestHelper::CreateEcmaVMWithScope(instance, thread, scope, false, false, false);
48     }
49 
TearDown()50     void TearDown() override
51     {
52         TestHelper::DestroyEcmaVMWithScope(instance, scope, false);
53     }
54 
55     EcmaVM *instance {nullptr};
56     EcmaHandleScope *scope {nullptr};
57     JSThread *thread {nullptr};
58 };
59 
HWTEST_F_L0(QuickFixTest,HotReload_SingleFile)60 HWTEST_F_L0(QuickFixTest, HotReload_SingleFile)
61 {
62     std::string baseFileName = QUICKFIX_ABC_PATH "single_file/base/index.abc";
63     std::string patchFileName = QUICKFIX_ABC_PATH "single_file/patch/index.abc";
64 
65     JSNApi::EnableUserUncaughtErrorHandler(instance);
66 
67     JSNApi::SetBundle(instance, false);
68 
69     bool result = JSNApi::Execute(instance, baseFileName, "index");
70     EXPECT_TRUE(result);
71 
72     auto res = JSNApi::LoadPatch(instance, patchFileName, baseFileName);
73     EXPECT_TRUE(res == PatchErrorCode::SUCCESS);
74 
75     Local<ObjectRef> exception = JSNApi::GetAndClearUncaughtException(instance);
76     result = JSNApi::IsQuickFixCausedException(instance, exception, patchFileName);
77     EXPECT_FALSE(result);
78 
79     res = JSNApi::UnloadPatch(instance, patchFileName);
80     EXPECT_TRUE(res == PatchErrorCode::SUCCESS);
81 }
82 
HWTEST_F_L0(QuickFixTest,HotReload_MultiFile)83 HWTEST_F_L0(QuickFixTest, HotReload_MultiFile)
84 {
85     std::string baseFileName = QUICKFIX_ABC_PATH "multi_file/base/merge.abc";
86     std::string patchFileName = QUICKFIX_ABC_PATH "multi_file/patch/merge.abc";
87 
88     JSNApi::EnableUserUncaughtErrorHandler(instance);
89 
90     JSNApi::SetBundle(instance, false);
91 
92     bool result = JSNApi::Execute(instance, baseFileName, "main");
93     EXPECT_TRUE(result);
94 
95     auto res = JSNApi::LoadPatch(instance, patchFileName, baseFileName);
96     EXPECT_TRUE(res == PatchErrorCode::SUCCESS);
97 
98     Local<ObjectRef> exception = JSNApi::GetAndClearUncaughtException(instance);
99     result = JSNApi::IsQuickFixCausedException(instance, exception, patchFileName);
100     EXPECT_FALSE(result);
101 
102     res = JSNApi::UnloadPatch(instance, patchFileName);
103     EXPECT_TRUE(res == PatchErrorCode::SUCCESS);
104 }
105 
HWTEST_F_L0(QuickFixTest,HotReload_MultiHap)106 HWTEST_F_L0(QuickFixTest, HotReload_MultiHap)
107 {
108     std::string baseFileName1 = QUICKFIX_ABC_PATH "single_file/base/index.abc";
109     std::string patchFileName1 = QUICKFIX_ABC_PATH "single_file/patch/index.abc";
110 
111     std::string baseFileName2 = QUICKFIX_ABC_PATH "multi_file/base/merge.abc";
112     std::string patchFileName2 = QUICKFIX_ABC_PATH "multi_file/patch/merge.abc";
113 
114     JSNApi::SetBundle(instance, false);
115 
116     bool result = JSNApi::Execute(instance, baseFileName1, "index");
117     EXPECT_TRUE(result);
118 
119     result = JSNApi::Execute(instance, baseFileName2, "main");
120     EXPECT_TRUE(result);
121 
122     auto res = JSNApi::LoadPatch(instance, patchFileName1, baseFileName1);
123     EXPECT_TRUE(res == PatchErrorCode::SUCCESS);
124 
125     res = JSNApi::LoadPatch(instance, patchFileName2, baseFileName2);
126     EXPECT_TRUE(res == PatchErrorCode::SUCCESS);
127 
128     res = JSNApi::UnloadPatch(instance, patchFileName1);
129     EXPECT_TRUE(res == PatchErrorCode::SUCCESS);
130 
131     res = JSNApi::UnloadPatch(instance, patchFileName2);
132     EXPECT_TRUE(res == PatchErrorCode::SUCCESS);
133 }
134 
HWTEST_F_L0(QuickFixTest,HotReload_Buffer)135 HWTEST_F_L0(QuickFixTest, HotReload_Buffer)
136 {
137     const char *baseFileName = "__base.pa";
138     const char *baseData = R"(
139         .function void foo() {}
140     )";
141     const char *patchFileName = "__patch.pa";
142     const char *patchData = R"(
143         .function void foo() {}
144     )";
145 
146     JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
147     Parser parser;
148     auto res = parser.Parse(patchData);
149     std::unique_ptr<const File> basePF = pandasm::AsmEmitter::Emit(res.Value());
150     std::unique_ptr<const File> patchPF = pandasm::AsmEmitter::Emit(res.Value());
151     std::shared_ptr<JSPandaFile> baseFile = pfManager->NewJSPandaFile(basePF.release(), CString(baseFileName));
152     std::shared_ptr<JSPandaFile> patchFile = pfManager->NewJSPandaFile(patchPF.release(), CString(patchFileName));
153     pfManager->AddJSPandaFile(baseFile);
154     pfManager->AddJSPandaFile(patchFile);
155 
156     auto result = JSNApi::LoadPatch(instance, patchFileName, (uint8_t *)patchData, sizeof(patchData),
157                                     baseFileName, (uint8_t *)baseData, sizeof(baseData));
158     EXPECT_FALSE(result == PatchErrorCode::SUCCESS);
159 
160     pfManager->RemoveJSPandaFile(baseFile.get());
161     pfManager->RemoveJSPandaFile(patchFile.get());
162 }
163 
HWTEST_F_L0(QuickFixTest,HotReload_Instantiate)164 HWTEST_F_L0(QuickFixTest, HotReload_Instantiate)
165 {
166     ecmascript::ThreadManagedScope managedScope(thread);
167 
168     CString baseFileName = QUICKFIX_ABC_PATH "multi_file/base/merge.abc";
169     std::shared_ptr<JSPandaFile> baseFile =
170         JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, baseFileName, "");
171     EXPECT_TRUE(baseFile != nullptr);
172 
173     CString patchFileName = QUICKFIX_ABC_PATH "multi_file/patch/merge.abc";
174     std::shared_ptr<JSPandaFile> patchFile =
175         JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, patchFileName, "");
176     EXPECT_TRUE(patchFile != nullptr);
177 
178     CString replacedRecordName = "main";
179     thread->SetStageOfHotReload(StageOfHotReload::BEGIN_EXECUTE_PATCHMAIN);
180 
181     JSHandle<JSTaggedValue> module = ModuleResolver::HostResolveImportedModuleForHotReload(thread,
182         patchFileName, replacedRecordName);
183     EXPECT_FALSE(module->IsHole());
184 
185     JSHandle<Program> program =
186         JSPandaFileManager::GetInstance()->GenerateProgram(instance, patchFile.get(), replacedRecordName);
187     EXPECT_FALSE(program.IsEmpty());
188 
189     SourceTextModule::Instantiate(thread, module);
190     EXPECT_TRUE(JSHandle<SourceTextModule>::Cast(module)->GetStatus() == ModuleStatus::INSTANTIATED);
191 
192     thread->SetStageOfHotReload(StageOfHotReload::LOAD_END_EXECUTE_PATCHMAIN);
193     JSHandle<SourceTextModule>::Cast(module)->SetStatus(ModuleStatus::UNINSTANTIATED);
194     SourceTextModule::Instantiate(thread, module);
195     EXPECT_TRUE(JSHandle<SourceTextModule>::Cast(module)->GetStatus() == ModuleStatus::INSTANTIATED);
196 }
197 
QuickFixQueryFunc(std::string baseFileName,std::string & patchFileName,uint8_t ** patchBuffer,size_t & patchBufferSize)198 bool QuickFixQueryFunc(
199     std::string baseFileName, std::string &patchFileName, uint8_t ** patchBuffer, size_t &patchBufferSize)
200 {
201     if (baseFileName != QUICKFIX_ABC_PATH "multi_file/base/merge.abc") {
202         return false;
203     }
204 
205     patchFileName = "__index.pa";
206     const char data[] = R"(
207         .function void foo() {}
208     )";
209 
210     Parser parser;
211     auto res = parser.Parse(data);
212     uint8_t *bufferData = reinterpret_cast<uint8_t *>((const_cast<char *>(data)));
213     *patchBuffer = bufferData;
214     patchBufferSize = sizeof(data);
215     return true;
216 }
217 
HWTEST_F_L0(QuickFixTest,HotReload_RegisterQuickFixQueryFunc)218 HWTEST_F_L0(QuickFixTest, HotReload_RegisterQuickFixQueryFunc)
219 {
220     std::string baseFileName = QUICKFIX_ABC_PATH "multi_file/base/merge.abc";
221     std::string patchFileName = "__index.pa";
222     JSNApi::RegisterQuickFixQueryFunc(instance, QuickFixQueryFunc);
223 
224     std::shared_ptr<JSPandaFile> baseFile =
225         JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, baseFileName.c_str(), "");
226     EXPECT_TRUE(baseFile != nullptr);
227     std::shared_ptr<JSPandaFile> patchFile =
228         JSPandaFileManager::GetInstance()->FindJSPandaFile(patchFileName.c_str());
229     EXPECT_TRUE(patchFile == nullptr);
230 
231     QuickFixManager *quickFixManager = instance->GetQuickFixManager();
232     quickFixManager->LoadPatchIfNeeded(thread, baseFile.get());
233 
234     JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
235     pfManager->RemoveJSPandaFile(baseFile.get());
236 }
237 }  // namespace panda::test
238