• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 "ecmascript/ic/invoke_cache.h"
17 
18 #include "ecmascript/interpreter/interpreter-inl.h"
19 
20 namespace panda::ecmascript {
21 // Build the infrastructure and wait for TS to invoke.
SetMonoConstuctCacheSlot(JSThread * thread,ProfileTypeInfo * profileTypeInfo,uint32_t slotId,JSTaggedValue newTarget,JSTaggedValue initialHClass)22 bool InvokeCache::SetMonoConstuctCacheSlot(JSThread *thread, ProfileTypeInfo *profileTypeInfo, uint32_t slotId,
23                                            JSTaggedValue newTarget, JSTaggedValue initialHClass)
24 {
25     // only cache class constructor
26     if (UNLIKELY(!newTarget.IsClassConstructor())) {
27         return false;
28     }
29 
30     profileTypeInfo->Set(thread, slotId, newTarget);
31     profileTypeInfo->Set(thread, slotId + 1, initialHClass);
32 
33     return true;
34 }
35 
SetPolyConstuctCacheSlot(JSThread * thread,ProfileTypeInfo * profileTypeInfo,uint32_t slotId,uint8_t length,JSTaggedValue newTargetArray,JSTaggedValue initialHClassArray)36 bool InvokeCache::SetPolyConstuctCacheSlot(JSThread *thread, ProfileTypeInfo *profileTypeInfo, uint32_t slotId,
37                                            uint8_t length, JSTaggedValue newTargetArray,
38                                            JSTaggedValue initialHClassArray)
39 {
40     ASSERT(length <= POLY_CASE_NUM && newTargetArray.IsTaggedArray() && initialHClassArray.IsTaggedArray());
41 
42     JSHandle<TaggedArray> profileTypeInfoArr(thread, profileTypeInfo);
43     JSHandle<TaggedArray> newTargetArr(thread, newTargetArray);
44     JSHandle<TaggedArray> initialHClassArr(thread, initialHClassArray);
45 
46     auto factory = thread->GetEcmaVM()->GetFactory();
47     constexpr uint8_t step = 2;
48     JSHandle<TaggedArray> newArray = factory->NewTaggedArray(length * step);  // 2: newTarget and hclass
49 
50     for (uint8_t index = 0; index < length; ++index) {
51         ASSERT(newTargetArr->Get(index).IsClassConstructor());
52 
53         newArray->Set(thread, index * step, newTargetArr->Get(index));
54         newArray->Set(thread, index * step + 1, initialHClassArr->Get(index));
55     }
56 
57     profileTypeInfoArr->Set(thread, slotId, newArray);
58     profileTypeInfoArr->Set(thread, slotId + 1, JSTaggedValue::Hole());
59 
60     return true;
61 }
62 
CheckPolyInvokeCache(JSTaggedValue cachedArray,JSTaggedValue func)63 JSTaggedValue InvokeCache::CheckPolyInvokeCache(JSTaggedValue cachedArray, JSTaggedValue func)
64 {
65     ASSERT(cachedArray.IsTaggedArray());
66     TaggedArray *array = TaggedArray::Cast(cachedArray.GetTaggedObject());
67     uint32_t length = array->GetLength();
68     for (uint32_t index = 0; index < length; index += 2) {  // 2: means one ic, two slot
69         auto result = array->Get(index);
70         if (JSFunction::Cast(result.GetTaggedObject())->GetMethod() ==
71             JSFunction::Cast(func.GetTaggedObject())->GetMethod()) {
72             return array->Get(index + 1);
73         }
74     }
75 
76     return JSTaggedValue::Hole();
77 }
78 
Construct(JSThread * thread,JSTaggedValue firstValue,JSTaggedValue secondValue,JSTaggedValue ctor,JSTaggedValue newTarget,uint16_t firstArgIdx,uint16_t length)79 JSTaggedValue InvokeCache::Construct(JSThread *thread, JSTaggedValue firstValue, JSTaggedValue secondValue,
80                                      JSTaggedValue ctor, JSTaggedValue newTarget, uint16_t firstArgIdx, uint16_t length)
81 {
82     // ic miss
83     if (UNLIKELY(!firstValue.IsHeapObject())) {
84         return JSTaggedValue::Hole();
85     }
86 
87     // gc protection
88     JSHandle<JSFunction> constructor(thread, ctor);
89     JSHandle<JSFunction> newTgt(thread, newTarget);
90 
91     JSHandle<JSHClass> instanceHClass;
92     // monomorphic
93     if (LIKELY(firstValue.IsJSFunction() &&
94         newTgt->GetMethod() == JSFunction::Cast(firstValue.GetTaggedObject())->GetMethod())) {
95         instanceHClass = JSHandle<JSHClass>(thread, JSHClass::Cast(secondValue.GetTaggedObject()));
96     } else {
97         // polymorphic
98         ASSERT(firstValue.IsTaggedArray());
99         JSTaggedValue polyCache = CheckPolyInvokeCache(firstValue, newTarget);
100         if (UNLIKELY(polyCache.IsHole())) {
101             return JSTaggedValue::Hole();
102         }
103         instanceHClass = JSHandle<JSHClass>(thread, JSHClass::Cast(polyCache.GetTaggedObject()));
104     }
105 
106     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
107     JSHandle<JSObject> obj = factory->NewJSObject(instanceHClass);
108     EcmaRuntimeCallInfo *info =
109         EcmaInterpreter::NewRuntimeCallInfo(thread, JSHandle<JSTaggedValue>(constructor), JSHandle<JSTaggedValue>(obj),
110         JSHandle<JSTaggedValue>(newTgt), length);
111     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
112     FrameHandler frameHandler(thread);
113     for (size_t i = 0; i < length; i++) {
114         info->SetCallArg(i, frameHandler.GetVRegValue(firstArgIdx + i));
115     }
116     EcmaInterpreter::Execute(info);
117     return obj.GetTaggedValue();
118 }
119 
120 // just identify simple callee case which can be inlined, the implement of inline need wait TS AOT
SetMonoInlineCallCacheSlot(JSThread * thread,ProfileTypeInfo * profileTypeInfo,uint32_t slotId,JSTaggedValue callee)121 bool InvokeCache::SetMonoInlineCallCacheSlot(JSThread *thread, ProfileTypeInfo *profileTypeInfo, uint32_t slotId,
122                                              JSTaggedValue callee)
123 {
124     ASSERT(callee.IsJSFunction());
125     Method *calleeMethod = JSFunction::Cast(callee.GetTaggedObject())->GetCallTarget();
126     if (DecideCanBeInlined(calleeMethod)) {
127         profileTypeInfo->Set(thread, slotId, callee);
128         return true;
129     }
130 
131     profileTypeInfo->Set(thread, slotId, JSTaggedValue::Hole());
132     return false;
133 }
134 
SetPolyInlineCallCacheSlot(JSThread * thread,ProfileTypeInfo * profileTypeInfo,uint32_t slotId,uint8_t length,JSTaggedValue calleeArray)135 bool InvokeCache::SetPolyInlineCallCacheSlot(JSThread *thread, ProfileTypeInfo *profileTypeInfo, uint32_t slotId,
136                                              uint8_t length, JSTaggedValue calleeArray)
137 {
138     ASSERT(calleeArray.IsTaggedArray() && length >= MONO_CASE_NUM && length <= POLY_CASE_NUM);
139     JSHandle<TaggedArray> calleeArr(thread, calleeArray);
140     ASSERT(calleeArr->GetLength() == length);
141     JSHandle<TaggedArray> profileTypeInfoArr(thread, profileTypeInfo);
142 
143     auto factory = thread->GetEcmaVM()->GetFactory();
144     JSHandle<TaggedArray> newArray = factory->NewTaggedArray(length);
145 
146     for (uint8_t index = 0; index < length; ++index) {
147         JSTaggedValue calleeElement = calleeArr->Get(index);
148         Method *calleeMethod = JSFunction::Cast(calleeElement.GetTaggedObject())->GetCallTarget();
149         if (DecideCanBeInlined(calleeMethod)) {
150             newArray->Set(thread, index, calleeElement);
151         } else {
152             newArray->Set(thread, index, JSTaggedValue::Hole());
153         }
154     }
155 
156     profileTypeInfoArr->Set(thread, slotId, newArray);
157     return true;
158 }
159 
DecideCanBeInlined(Method * method)160 bool InvokeCache::DecideCanBeInlined(Method *method)
161 {
162     constexpr uint32_t MAX_INLINED_BYTECODE_SIZE = 128;
163     uint32_t bcSize = method->GetCodeSize();
164     return (bcSize > 0 && bcSize < MAX_INLINED_BYTECODE_SIZE);  // 0 is invalid
165 }
166 }  // namespace panda::ecmascript
167