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