• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2023-2024 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 "plugins/ets/runtime/interop_js/js_proxy/js_proxy.h"
17 #include "plugins/ets/runtime/interop_js/interop_context.h"
18 
19 #include "plugins/ets/runtime/types/ets_object.h"
20 
21 namespace panda::ets::interop::js::js_proxy {
22 
23 extern "C" void JSProxyCallBridge(Method *method, ...);
24 
25 // Create JSProxy class descriptor that will respond to IsProxyClass
26 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
MakeProxyDescriptor(const uint8_t * descriptorP)27 static std::unique_ptr<uint8_t[]> MakeProxyDescriptor(const uint8_t *descriptorP)
28 {
29     Span<const uint8_t> descriptor(descriptorP, utf::Mutf8Size(descriptorP));
30 
31     ASSERT(descriptor.size() > 2U);
32     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
33     ASSERT(descriptor[0] == 'L');
34     ASSERT(descriptor[descriptor.size() - 1] == ';');
35 
36     size_t proxyDescriptorSize = descriptor.size() + 3U;  // + $$\0
37     // NOLINTNEXTLINE(modernize-avoid-c-arrays)
38     auto proxyDescriptorData = std::make_unique<uint8_t[]>(proxyDescriptorSize);
39     Span<uint8_t> proxyDescriptor(proxyDescriptorData.get(), proxyDescriptorSize);
40 
41     proxyDescriptor[0] = 'L';
42     proxyDescriptor[1] = '$';
43     std::copy_n(&descriptor[1], descriptor.size() - 2U, &proxyDescriptor[2U]);
44     proxyDescriptor[proxyDescriptor.size() - 3U] = '$';
45     proxyDescriptor[proxyDescriptor.size() - 2U] = ';';
46     proxyDescriptor[proxyDescriptor.size() - 1U] = '\0';
47 
48     return proxyDescriptorData;
49 }
50 
51 /*static*/
Create(EtsClass * etsClass,Span<Method * > proxyMethods)52 std::unique_ptr<JSProxy> JSProxy::Create(EtsClass *etsClass, Span<Method *> proxyMethods)
53 {
54     Class *cls = etsClass->GetRuntimeClass();
55     ASSERT(!IsProxyClass(cls));
56 
57     auto methodsBuffer = new uint8_t[proxyMethods.size() * sizeof(Method)];
58     Span<Method> implMethods {reinterpret_cast<Method *>(methodsBuffer), proxyMethods.size()};
59 
60     for (size_t i = 0; i < proxyMethods.size(); ++i) {
61         auto *m = proxyMethods[i];
62         auto newMethod = new (&implMethods[i]) Method(m);
63         newMethod->SetCompiledEntryPoint(reinterpret_cast<void *>(JSProxyCallBridge));
64     }
65 
66     auto descriptor = MakeProxyDescriptor(cls->GetDescriptor());
67     uint32_t accessFlags = cls->GetAccessFlags();
68     Span<Field> fields {};
69     Class *baseClass = cls;
70     Span<Class *> interfaces {};
71     ClassLinkerContext *context = cls->GetLoadContext();
72 
73     ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
74     Class *proxyCls =
75         classLinker->BuildClass(descriptor.get(), true, accessFlags, {implMethods.data(), implMethods.size()}, fields,
76                                 baseClass, interfaces, context, false);
77     proxyCls->SetState(Class::State::INITIALIZING);
78     proxyCls->SetState(Class::State::INITIALIZED);
79 
80     ASSERT(IsProxyClass(proxyCls));
81 
82     auto jsProxy = std::unique_ptr<JSProxy>(new JSProxy(EtsClass::FromRuntimeClass(proxyCls)));
83     jsProxy->proxyMethods_.reset(reinterpret_cast<Method *>(methodsBuffer));
84     return jsProxy;
85 }
86 
87 }  // namespace panda::ets::interop::js::js_proxy
88