• 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 ark::ets::interop::js::js_proxy {
22 
23 extern "C" void CallJSProxyBridge(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 
InitProxyMethod(Class * cls,Method * src,Method * proxy)51 static void InitProxyMethod(Class *cls, Method *src, Method *proxy)
52 {
53     new (proxy) Method(src);
54 
55     proxy->SetAccessFlags((src->GetAccessFlags() & ~(ACC_ABSTRACT | ACC_DEFAULT_INTERFACE_METHOD)) | ACC_FINAL);
56     proxy->SetClass(cls);
57     proxy->SetCompiledEntryPoint(reinterpret_cast<void *>(CallJSProxyBridge));
58 }
59 
60 /*static*/
Create(EtsClass * etsClass,Span<Method * > targetMethods)61 std::unique_ptr<JSProxy> JSProxy::Create(EtsClass *etsClass, Span<Method *> targetMethods)
62 {
63     Class *cls = etsClass->GetRuntimeClass();
64     ASSERT(!IsProxyClass(cls) && !etsClass->IsFinal());
65     ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
66 
67     PandaVector<size_t> targetMethodsIdx;
68 
69     for (size_t i = 0; i < targetMethods.size(); ++i) {
70         auto m = targetMethods[i];
71         if (!m->IsFinal()) {  // NOTE(vpukhov): consider internal methods, final methods in builtins
72             targetMethodsIdx.push_back(i);
73         }
74     }
75 
76     size_t const numTargets = targetMethodsIdx.size();
77     Span<Method> proxyMethods {classLinker->GetAllocator()->AllocArray<Method>(numTargets), numTargets};
78 
79     for (size_t i = 0; i < numTargets; ++i) {
80         InitProxyMethod(cls, targetMethods[targetMethodsIdx[i]], &proxyMethods[i]);
81     }
82 
83     auto descriptor = MakeProxyDescriptor(cls->GetDescriptor());
84     uint32_t accessFlags = cls->GetAccessFlags() | ACC_PROXY | ACC_FINAL;
85     Span<Field> fields {};
86     Class *baseClass = cls;
87     Span<Class *> interfaces {};
88     ClassLinkerContext *context = cls->GetLoadContext();
89 
90     Class *proxyCls = classLinker->BuildClass(descriptor.get(), true, accessFlags, proxyMethods, fields, baseClass,
91                                               interfaces, context, false);
92     proxyCls->SetState(Class::State::INITIALIZING);
93     proxyCls->SetState(Class::State::INITIALIZED);
94 
95     ASSERT(IsProxyClass(proxyCls));
96 
97     // CC-OFFNXT(G.RES.09) private constructor
98     auto jsProxy = std::unique_ptr<JSProxy>(new JSProxy(EtsClass::FromRuntimeClass(proxyCls)));
99     return jsProxy;
100 }
101 
102 }  // namespace ark::ets::interop::js::js_proxy
103