• 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/ic_runtime.h"
17 
18 #include "ecmascript/global_dictionary-inl.h"
19 #include "ecmascript/global_env.h"
20 #include "ecmascript/ic/ic_handler.h"
21 #include "ecmascript/ic/profile_type_info.h"
22 #include "ecmascript/interpreter/slow_runtime_stub.h"
23 #include "ecmascript/js_function.h"
24 #include "ecmascript/js_hclass-inl.h"
25 #include "ecmascript/js_proxy.h"
26 #include "ecmascript/js_tagged_value-inl.h"
27 #include "ecmascript/js_typed_array.h"
28 #include "ecmascript/object_factory-inl.h"
29 #include "ecmascript/tagged_dictionary.h"
30 
31 namespace panda::ecmascript {
32 #define TRACE_IC 0  // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
33 
UpdateLoadHandler(const ObjectOperator & op,JSHandle<JSTaggedValue> key,JSHandle<JSTaggedValue> receiver)34 void ICRuntime::UpdateLoadHandler(const ObjectOperator &op, JSHandle<JSTaggedValue> key,
35                                   JSHandle<JSTaggedValue> receiver)
36 {
37     if (icAccessor_.GetICState() == ProfileTypeAccessor::ICState::MEGA) {
38         return;
39     }
40     if (IsNamedIC(GetICKind())) {
41         key = JSHandle<JSTaggedValue>();
42     }
43     JSHandle<JSTaggedValue> handlerValue;
44     JSHandle<JSHClass> hclass(GetThread(), JSHandle<JSObject>::Cast(receiver)->GetClass());
45     if (op.IsElement()) {
46         if (!op.IsFound() && hclass->IsDictionaryElement()) {
47             return;
48         }
49         handlerValue = LoadHandler::LoadElement(thread_);
50     } else {
51         if (!op.IsFound()) {
52             JSTaggedValue proto = hclass->GetPrototype();
53             if (!proto.IsECMAObject()) {
54                 handlerValue = LoadHandler::LoadProperty(thread_, op);
55             } else {
56                 handlerValue = PrototypeHandler::LoadPrototype(thread_, op, hclass);
57             }
58         } else if (!op.IsOnPrototype()) {
59             handlerValue = LoadHandler::LoadProperty(thread_, op);
60         } else {
61             // do not support global prototype ic
62             if (IsGlobalLoadIC(GetICKind())) {
63                 return;
64             }
65             handlerValue = PrototypeHandler::LoadPrototype(thread_, op, hclass);
66         }
67     }
68 
69     if (key.IsEmpty()) {
70         icAccessor_.AddHandlerWithoutKey(JSHandle<JSTaggedValue>::Cast(hclass), handlerValue);
71     } else if (op.IsElement()) {
72         // do not support global element ic
73         if (IsGlobalLoadIC(GetICKind())) {
74             return;
75         }
76         icAccessor_.AddElementHandler(JSHandle<JSTaggedValue>::Cast(hclass), handlerValue);
77     } else {
78         icAccessor_.AddHandlerWithKey(key, JSHandle<JSTaggedValue>::Cast(hclass), handlerValue);
79     }
80 }
81 
UpdateStoreHandler(const ObjectOperator & op,JSHandle<JSTaggedValue> key,JSHandle<JSTaggedValue> receiver)82 void ICRuntime::UpdateStoreHandler(const ObjectOperator &op, JSHandle<JSTaggedValue> key,
83                                    JSHandle<JSTaggedValue> receiver)
84 {
85     if (icAccessor_.GetICState() == ProfileTypeAccessor::ICState::MEGA) {
86         return;
87     }
88     if (IsNamedIC(GetICKind())) {
89         key = JSHandle<JSTaggedValue>();
90     }
91     JSHandle<JSTaggedValue> handlerValue;
92     ASSERT(op.IsFound());
93 
94     if (op.IsTSHClass()) {
95         JSHandle<JSHClass> hclass(thread_, JSHandle<JSObject>::Cast(receiver)->GetClass());
96         handlerValue = StoreTSHandler::StoreAOT(thread_, op, hclass);
97     } else if (op.IsTransition()) {
98         ASSERT(!op.IsElement());
99         if (op.IsOnPrototype()) {
100             JSHandle<JSHClass> hclass(thread_, JSHandle<JSObject>::Cast(receiver)->GetClass());
101             handlerValue = TransWithProtoHandler::StoreTransition(thread_, op, hclass);
102         } else {
103             handlerValue = TransitionHandler::StoreTransition(thread_, op);
104         }
105     } else if (op.IsOnPrototype()) {
106         // do not support global prototype ic
107         if (IsGlobalStoreIC(GetICKind())) {
108             return;
109         }
110         JSHandle<JSHClass> hclass(thread_, JSHandle<JSObject>::Cast(receiver)->GetClass());
111         handlerValue = PrototypeHandler::StorePrototype(thread_, op, hclass);
112     } else {
113         handlerValue = StoreHandler::StoreProperty(thread_, op);
114     }
115 
116     if (key.IsEmpty()) {
117         icAccessor_.AddHandlerWithoutKey(receiverHClass_, handlerValue);
118     } else if (op.IsElement()) {
119         // do not support global element ic
120         if (IsGlobalStoreIC(GetICKind())) {
121             return;
122         }
123         icAccessor_.AddElementHandler(receiverHClass_, handlerValue);
124     } else {
125         icAccessor_.AddHandlerWithKey(key, receiverHClass_, handlerValue);
126     }
127 }
128 
TraceIC(JSHandle<JSTaggedValue> receiver,JSHandle<JSTaggedValue> key) const129 void ICRuntime::TraceIC([[maybe_unused]] JSHandle<JSTaggedValue> receiver,
130                         [[maybe_unused]] JSHandle<JSTaggedValue> key) const
131 {
132 #if TRACE_IC
133     auto kind = ICKindToString(GetICKind());
134     auto state = ProfileTypeAccessor::ICStateToString(icAccessor_.GetICState());
135     if (key->IsString()) {
136         auto keyStrHandle = JSHandle<EcmaString>::Cast(key);
137         LOG_ECMA(ERROR) << kind << " miss key is: " << EcmaStringAccessor(keyStrHandle).ToCString()
138                             << ", receiver is " << receiver->GetTaggedObject()->GetClass()->IsDictionaryMode()
139                             << ", state is " << state;
140     } else {
141         LOG_ECMA(ERROR) << kind << " miss " << ", state is "
142                             << ", receiver is " << receiver->GetTaggedObject()->GetClass()->IsDictionaryMode()
143                             << state;
144     }
145 #endif
146 }
147 
LoadMiss(JSHandle<JSTaggedValue> receiver,JSHandle<JSTaggedValue> key)148 JSTaggedValue LoadICRuntime::LoadMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key)
149 {
150     if (!receiver->IsJSObject() || receiver->HasOrdinaryGet()) {
151         icAccessor_.SetAsMega();
152         return JSTaggedValue::GetProperty(thread_, receiver, key).GetValue().GetTaggedValue();
153     }
154 
155     ICKind kind = GetICKind();
156     // global variable find from global record firstly
157     if (kind == ICKind::NamedGlobalLoadIC || kind == ICKind::NamedGlobalTryLoadIC) {
158         JSTaggedValue box = SlowRuntimeStub::LdGlobalRecord(thread_, key.GetTaggedValue());
159         if (!box.IsUndefined()) {
160             ASSERT(box.IsPropertyBox());
161             if (icAccessor_.GetICState() != ProfileTypeAccessor::ICState::MEGA) {
162                 icAccessor_.AddGlobalRecordHandler(JSHandle<JSTaggedValue>(thread_, box));
163             }
164             return PropertyBox::Cast(box.GetTaggedObject())->GetValue();
165         }
166     }
167 
168     ObjectOperator op(GetThread(), receiver, key);
169     auto result = JSHandle<JSTaggedValue>(thread_, JSObject::GetProperty(GetThread(), &op));
170     if (!op.IsFound() && kind == ICKind::NamedGlobalTryLoadIC) {
171         return SlowRuntimeStub::ThrowReferenceError(GetThread(), key.GetTaggedValue(), " is not definded");
172     }
173     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
174     // ic-switch
175     if (!GetThread()->GetEcmaVM()->ICEnabled()) {
176         icAccessor_.SetAsMega();
177         return result.GetTaggedValue();
178     }
179     TraceIC(receiver, key);
180     // do not cache element
181     if (!op.IsFastMode()) {
182         icAccessor_.SetAsMega();
183         return result.GetTaggedValue();
184     }
185 
186     UpdateLoadHandler(op, key, receiver);
187     return result.GetTaggedValue();
188 }
189 
StoreMiss(JSHandle<JSTaggedValue> receiver,JSHandle<JSTaggedValue> key,JSHandle<JSTaggedValue> value)190 JSTaggedValue StoreICRuntime::StoreMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key,
191                                         JSHandle<JSTaggedValue> value)
192 {
193     if (!receiver->IsJSObject() || receiver->HasOrdinaryGet()) {
194         icAccessor_.SetAsMega();
195         bool success = JSTaggedValue::SetProperty(GetThread(), receiver, key, value, true);
196         return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
197     }
198 
199     ICKind kind = GetICKind();
200     // global variable find from global record firstly
201     if (kind == ICKind::NamedGlobalStoreIC || kind == ICKind::NamedGlobalTryStoreIC) {
202         JSTaggedValue box = SlowRuntimeStub::LdGlobalRecord(thread_, key.GetTaggedValue());
203         if (!box.IsUndefined()) {
204             ASSERT(box.IsPropertyBox());
205             SlowRuntimeStub::TryUpdateGlobalRecord(thread_, key.GetTaggedValue(), value.GetTaggedValue());
206             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
207             if (icAccessor_.GetICState() != ProfileTypeAccessor::ICState::MEGA) {
208                 icAccessor_.AddGlobalRecordHandler(JSHandle<JSTaggedValue>(thread_, box));
209             }
210             return JSTaggedValue::Undefined();
211         }
212     }
213     UpdateReceiverHClass(JSHandle<JSTaggedValue>(GetThread(), JSHandle<JSObject>::Cast(receiver)->GetClass()));
214 
215     ObjectOperator op(GetThread(), receiver, key);
216     if (!op.IsFound()) {
217         if (kind == ICKind::NamedGlobalStoreIC) {
218             PropertyAttributes attr = PropertyAttributes::Default(true, true, false);
219             op.SetAttr(attr);
220         } else if (kind == ICKind::NamedGlobalTryStoreIC) {
221             return SlowRuntimeStub::ThrowReferenceError(GetThread(), key.GetTaggedValue(), " is not defined");
222         }
223     }
224     bool success = JSObject::SetProperty(&op, value, true);
225     // ic-switch
226     if (!GetThread()->GetEcmaVM()->ICEnabled()) {
227         icAccessor_.SetAsMega();
228         return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
229     }
230     TraceIC(receiver, key);
231     // do not cache element
232     if (!op.IsFastMode()) {
233         icAccessor_.SetAsMega();
234         return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
235     }
236     if (success) {
237         UpdateStoreHandler(op, key, receiver);
238         return JSTaggedValue::Undefined();
239     }
240     return JSTaggedValue::Exception();
241 }
242 }  // namespace panda::ecmascript
243