• 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 PatchErrorCode = panda::JSNApi::PatchErrorCode;
33 using Program = panda::ecmascript::Program;
34 using EcmaContext = panda::ecmascript::EcmaContext;
35 class QuickFixTest : public testing::Test {
36 public:
SetUpTestCase()37     static void SetUpTestCase()
38     {
39         GTEST_LOG_(INFO) << "SetUpTestCase";
40     }
41 
TearDownTestCase()42     static void TearDownTestCase()
43     {
44         GTEST_LOG_(INFO) << "TearDownCase";
45     }
46 
SetUp()47     void SetUp() override
48     {
49         TestHelper::CreateEcmaVMWithScope(instance, thread, scope, false, false, false);
50     }
51 
TearDown()52     void TearDown() override
53     {
54         TestHelper::DestroyEcmaVMWithScope(instance, scope, false);
55     }
56 
57     EcmaVM *instance {nullptr};
58     EcmaHandleScope *scope {nullptr};
59     JSThread *thread {nullptr};
60 };
61 
HWTEST_F_L0(QuickFixTest,HotReload_SingleFile)62 HWTEST_F_L0(QuickFixTest, HotReload_SingleFile)
63 {
64     std::string baseFileName = QUICKFIX_ABC_PATH "single_file/base/index.abc";
65     std::string patchFileName = QUICKFIX_ABC_PATH "single_file/patch/index.abc";
66 
67     JSNApi::EnableUserUncaughtErrorHandler(instance);
68 
69     JSNApi::SetBundle(instance, false);
70 
71     bool result = JSNApi::Execute(instance, baseFileName, "index");
72     EXPECT_TRUE(result);
73 
74     auto res = JSNApi::LoadPatch(instance, patchFileName, baseFileName);
75     EXPECT_TRUE(res == PatchErrorCode::SUCCESS);
76 
77     Local<ObjectRef> exception = JSNApi::GetAndClearUncaughtException(instance);
78     result = JSNApi::IsQuickFixCausedException(instance, exception, patchFileName);
79     EXPECT_FALSE(result);
80 
81     res = JSNApi::UnloadPatch(instance, patchFileName);
82     EXPECT_TRUE(res == PatchErrorCode::SUCCESS);
83 }
84 
HWTEST_F_L0(QuickFixTest,HotReload_MultiFile)85 HWTEST_F_L0(QuickFixTest, HotReload_MultiFile)
86 {
87     std::string baseFileName = QUICKFIX_ABC_PATH "multi_file/base/merge.abc";
88     std::string patchFileName = QUICKFIX_ABC_PATH "multi_file/patch/merge.abc";
89 
90     JSNApi::EnableUserUncaughtErrorHandler(instance);
91 
92     JSNApi::SetBundle(instance, false);
93 
94     bool result = JSNApi::Execute(instance, baseFileName, "main");
95     EXPECT_TRUE(result);
96 
97     auto res = JSNApi::LoadPatch(instance, patchFileName, baseFileName);
98     EXPECT_TRUE(res == PatchErrorCode::SUCCESS);
99 
100     Local<ObjectRef> exception = JSNApi::GetAndClearUncaughtException(instance);
101     result = JSNApi::IsQuickFixCausedException(instance, exception, patchFileName);
102     EXPECT_FALSE(result);
103 
104     res = JSNApi::UnloadPatch(instance, patchFileName);
105     EXPECT_TRUE(res == PatchErrorCode::SUCCESS);
106 }
107 
HWTEST_F_L0(QuickFixTest,HotReload_MultiHap)108 HWTEST_F_L0(QuickFixTest, HotReload_MultiHap)
109 {
110     std::string baseFileName1 = QUICKFIX_ABC_PATH "single_file/base/index.abc";
111     std::string patchFileName1 = QUICKFIX_ABC_PATH "single_file/patch/index.abc";
112 
113     std::string baseFileName2 = QUICKFIX_ABC_PATH "multi_file/base/merge.abc";
114     std::string patchFileName2 = QUICKFIX_ABC_PATH "multi_file/patch/merge.abc";
115 
116     JSNApi::SetBundle(instance, false);
117 
118     bool result = JSNApi::Execute(instance, baseFileName1, "index");
119     EXPECT_TRUE(result);
120 
121     result = JSNApi::Execute(instance, baseFileName2, "main");
122     EXPECT_TRUE(result);
123 
124     auto res = JSNApi::LoadPatch(instance, patchFileName1, baseFileName1);
125     EXPECT_TRUE(res == PatchErrorCode::SUCCESS);
126 
127     res = JSNApi::LoadPatch(instance, patchFileName2, baseFileName2);
128     EXPECT_TRUE(res == PatchErrorCode::SUCCESS);
129 
130     res = JSNApi::UnloadPatch(instance, patchFileName1);
131     EXPECT_TRUE(res == PatchErrorCode::SUCCESS);
132 
133     res = JSNApi::UnloadPatch(instance, patchFileName2);
134     EXPECT_TRUE(res == PatchErrorCode::SUCCESS);
135 }
136 
HWTEST_F_L0(QuickFixTest,HotReload_Buffer)137 HWTEST_F_L0(QuickFixTest, HotReload_Buffer)
138 {
139     const char *baseFileName = "__base.pa";
140     const char *baseData = R"(
141         .function void foo() {}
142     )";
143     const char *patchFileName = "__patch.pa";
144     const char *patchData = R"(
145         .function void foo() {}
146     )";
147 
148     JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
149     Parser parser;
150     auto res = parser.Parse(patchData);
151     std::unique_ptr<const File> basePF = pandasm::AsmEmitter::Emit(res.Value());
152     std::unique_ptr<const File> patchPF = pandasm::AsmEmitter::Emit(res.Value());
153     std::shared_ptr<JSPandaFile> baseFile = pfManager->NewJSPandaFile(basePF.release(), CString(baseFileName));
154     std::shared_ptr<JSPandaFile> patchFile = pfManager->NewJSPandaFile(patchPF.release(), CString(patchFileName));
155     pfManager->AddJSPandaFile(baseFile);
156     pfManager->AddJSPandaFile(patchFile);
157 
158     auto result = JSNApi::LoadPatch(instance, patchFileName, (uint8_t *)patchData, sizeof(patchData),
159                                     baseFileName, (uint8_t *)baseData, sizeof(baseData));
160     EXPECT_FALSE(result == PatchErrorCode::SUCCESS);
161 
162     pfManager->RemoveJSPandaFile(baseFile.get());
163     pfManager->RemoveJSPandaFile(patchFile.get());
164 }
165 
HWTEST_F_L0(QuickFixTest,HotReload_Instantiate)166 HWTEST_F_L0(QuickFixTest, HotReload_Instantiate)
167 {
168     ThreadManagedScope managedScope(thread);
169 
170     CString baseFileName = QUICKFIX_ABC_PATH "multi_file/base/merge.abc";
171     std::shared_ptr<JSPandaFile> baseFile =
172         JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, baseFileName, "");
173     EXPECT_TRUE(baseFile != nullptr);
174 
175     CString patchFileName = QUICKFIX_ABC_PATH "multi_file/patch/merge.abc";
176     std::shared_ptr<JSPandaFile> patchFile =
177         JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, patchFileName, "");
178     EXPECT_TRUE(patchFile != nullptr);
179 
180     CString replacedRecordName = "main";
181     EcmaContext *context = thread->GetCurrentEcmaContext();
182     context->SetStageOfHotReload(StageOfHotReload::BEGIN_EXECUTE_PATCHMAIN);
183 
184     JSHandle<JSTaggedValue> module = ModuleResolver::HostResolveImportedModuleForHotReload(thread,
185         patchFileName, replacedRecordName);
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);
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);
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