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 #ifndef ECMASCRIPT_JS_TAGGED_VALUE_H
17 #define ECMASCRIPT_JS_TAGGED_VALUE_H
18
19 #include "ecmascript/mem/c_string.h"
20 #include "include/coretypes/tagged_value.h"
21
22 namespace panda::ecmascript {
23 class JSObject;
24 class JSTaggedNumber;
25 template<typename T>
26 class JSHandle;
27 class TaggedArray;
28 class LinkedHashMap;
29 class LinkedHashSet;
30 class PropertyDescriptor;
31 class OperationResult;
32 class EcmaString;
33 class JSThread;
34
35 // Don't switch the order!
36 enum PreferredPrimitiveType : uint8_t { PREFER_NUMBER = 0, PREFER_STRING, NO_PREFERENCE };
37
38 // Result of an abstract relational comparison of x and y, implemented according
39 // to ES6 section 7.2.11 Abstract Relational Comparison.
40 enum class ComparisonResult {
41 LESS, // x < y
42 EQUAL, // x = y
43 GREAT, // x > y
44 UNDEFINED // at least one of x or y was undefined or NaN
45 };
46
47 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
48 #define RETURN_TAGGED_VALUE_IF_ABRUPT(thread) RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Undefined());
49
50 using JSTaggedType = coretypes::TaggedType;
51
ReinterpretDoubleToTaggedType(double value)52 static inline JSTaggedType ReinterpretDoubleToTaggedType(double value)
53 {
54 return bit_cast<JSTaggedType>(value);
55 }
ReinterpretTaggedTypeToDouble(JSTaggedType value)56 static inline double ReinterpretTaggedTypeToDouble(JSTaggedType value)
57 {
58 return bit_cast<double>(value);
59 }
60
61 class JSTaggedValue : public coretypes::TaggedValue {
62 public:
Cast(ObjectHeader * object)63 static JSTaggedValue Cast(ObjectHeader *object)
64 {
65 return JSTaggedValue(object);
66 }
67
68 JSTaggedValue(void *) = delete;
69
70 constexpr JSTaggedValue() = default;
JSTaggedValue(coretypes::TaggedType v)71 constexpr explicit JSTaggedValue(coretypes::TaggedType v) : coretypes::TaggedValue(v) {}
JSTaggedValue(int v)72 constexpr explicit JSTaggedValue(int v) : coretypes::TaggedValue(v) {}
JSTaggedValue(unsigned int v)73 explicit JSTaggedValue(unsigned int v) : coretypes::TaggedValue(v) {}
JSTaggedValue(bool v)74 constexpr explicit JSTaggedValue(bool v) : coretypes::TaggedValue(v) {}
JSTaggedValue(double v)75 explicit JSTaggedValue(double v) : coretypes::TaggedValue(v) {}
JSTaggedValue(const ObjectHeader * v)76 explicit JSTaggedValue(const ObjectHeader *v) : coretypes::TaggedValue(v) {}
JSTaggedValue(const TaggedObject * v)77 explicit JSTaggedValue(const TaggedObject *v) : coretypes::TaggedValue(v) {}
JSTaggedValue(const coretypes::TaggedValue & other)78 explicit JSTaggedValue(const coretypes::TaggedValue &other) : coretypes::TaggedValue(other.GetRawData()) {}
JSTaggedValue(int64_t v)79 explicit JSTaggedValue(int64_t v) : coretypes::TaggedValue(v){};
80
81 ~JSTaggedValue() = default;
82 DEFAULT_COPY_SEMANTIC(JSTaggedValue);
83 DEFAULT_MOVE_SEMANTIC(JSTaggedValue);
84
GetWeakReferentUnChecked()85 inline TaggedObject *GetWeakReferentUnChecked() const
86 {
87 return reinterpret_cast<TaggedObject *>(GetRawData() & (~TAG_WEAK_MASK));
88 }
89
IsWeakForHeapObject()90 inline bool IsWeakForHeapObject() const
91 {
92 return (GetRawData() & TAG_WEAK_MASK) == 1U;
93 }
94
False()95 static inline constexpr JSTaggedValue False()
96 {
97 return JSTaggedValue(VALUE_FALSE);
98 }
99
True()100 static inline constexpr JSTaggedValue True()
101 {
102 return JSTaggedValue(VALUE_TRUE);
103 }
104
Undefined()105 static inline constexpr JSTaggedValue Undefined()
106 {
107 return JSTaggedValue(VALUE_UNDEFINED);
108 }
109
Null()110 static inline constexpr JSTaggedValue Null()
111 {
112 return JSTaggedValue(VALUE_NULL);
113 }
114
Hole()115 static inline constexpr JSTaggedValue Hole()
116 {
117 return JSTaggedValue(VALUE_HOLE);
118 }
119
Exception()120 static inline constexpr JSTaggedValue Exception()
121 {
122 return JSTaggedValue(VALUE_EXCEPTION);
123 }
124
GetNumber()125 inline double GetNumber() const
126 {
127 return IsInt() ? GetInt() : GetDouble();
128 }
129
GetTaggedObject()130 inline TaggedObject *GetTaggedObject() const
131 {
132 return reinterpret_cast<TaggedObject *>(GetHeapObject());
133 }
134
GetRawTaggedObject()135 inline TaggedObject *GetRawTaggedObject() const
136 {
137 return reinterpret_cast<TaggedObject *>(GetRawHeapObject());
138 }
139
GetTaggedWeakRef()140 inline TaggedObject *GetTaggedWeakRef() const
141 {
142 return reinterpret_cast<TaggedObject *>(GetWeakReferent());
143 }
144
145 static JSTaggedValue OrdinaryToPrimitive(JSThread *thread, const JSHandle<JSTaggedValue> &tagged,
146 PreferredPrimitiveType type = PREFER_NUMBER);
147
148 // ecma6 7.1 Type Conversion
149 static JSTaggedValue ToPrimitive(JSThread *thread, const JSHandle<JSTaggedValue> &tagged,
150 PreferredPrimitiveType type = NO_PREFERENCE);
151 bool ToBoolean() const;
152 static JSTaggedNumber ToNumber(JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
153 static JSTaggedValue ToBigInt(JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
154 static JSTaggedValue ToBigInt64(JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
155 static JSTaggedValue ToBigUint64(JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
156 static JSTaggedNumber ToInteger(JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
157 static JSTaggedValue ToNumeric(JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
158 static int32_t ToInt32(JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
159 static uint32_t ToUint32(JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
160 static int16_t ToInt16(JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
161 static uint16_t ToUint16(JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
162 static int8_t ToInt8(JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
163 static uint8_t ToUint8(JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
164 static uint8_t ToUint8Clamp(JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
165 static JSHandle<EcmaString> ToString(JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
166 static JSHandle<JSObject> ToObject(JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
167 static JSHandle<JSTaggedValue> ToPropertyKey(JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
168 static JSTaggedNumber ToLength(JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
169 static JSTaggedValue CanonicalNumericIndexString(JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
170 static JSTaggedNumber ToIndex(JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
171
172 static bool ToArrayLength(JSThread *thread, const JSHandle<JSTaggedValue> &tagged, uint32_t *output);
173 static bool ToElementIndex(JSTaggedValue key, uint32_t *output);
174 static bool StringToElementIndex(JSTaggedValue key, uint32_t *output);
175 uint32_t GetArrayLength() const;
176
177 // ecma6 7.2 Testing and Comparison Operations
178 bool IsCallable() const;
179 bool IsConstructor() const;
180 bool IsExtensible(JSThread *thread) const;
181 bool IsInteger() const;
182 bool WithinInt32() const;
183 bool IsZero() const;
184 static bool IsPropertyKey(const JSHandle<JSTaggedValue> &key);
185 static JSHandle<JSTaggedValue> RequireObjectCoercible(JSThread *thread, const JSHandle<JSTaggedValue> &tagged);
186 static bool SameValue(const JSTaggedValue &x, const JSTaggedValue &y);
187 static bool SameValue(const JSHandle<JSTaggedValue> &xHandle, const JSHandle<JSTaggedValue> &yHandle);
188 static bool SameValueZero(const JSTaggedValue &x, const JSTaggedValue &y);
189 static bool Less(JSThread *thread, const JSHandle<JSTaggedValue> &x, const JSHandle<JSTaggedValue> &y);
190 static bool Equal(JSThread *thread, const JSHandle<JSTaggedValue> &x, const JSHandle<JSTaggedValue> &y);
191 static bool StrictEqual(const JSThread *thread, const JSHandle<JSTaggedValue> &x, const JSHandle<JSTaggedValue> &y);
192 static bool SameValueNumberic(const JSTaggedValue &x, const JSTaggedValue &y);
193
194 // ES6 7.4 Operations on Iterator Objects
195 static JSObject *CreateIterResultObject(JSThread *thread, const JSHandle<JSTaggedValue> &value, bool done);
196
197 // ecma6 7.3
198 static OperationResult GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
199 const JSHandle<JSTaggedValue> &key);
200
201 static OperationResult GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key);
202 static OperationResult GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
203 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &receiver);
204 static bool SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key,
205 const JSHandle<JSTaggedValue> &value, bool mayThrow = false);
206
207 static bool SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
208 const JSHandle<JSTaggedValue> &value, bool mayThrow = false);
209
210 static bool SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
211 const JSHandle<JSTaggedValue> &value, const JSHandle<JSTaggedValue> &receiver,
212 bool mayThrow = false);
213 static bool DeleteProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
214 const JSHandle<JSTaggedValue> &key);
215 static bool DeletePropertyOrThrow(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
216 const JSHandle<JSTaggedValue> &key);
217 static bool DefinePropertyOrThrow(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
218 const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc);
219 static bool DefineOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
220 const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc);
221 static bool GetOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
222 PropertyDescriptor &desc);
223 static bool SetPrototype(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
224 const JSHandle<JSTaggedValue> &proto);
225 static bool PreventExtensions(JSThread *thread, const JSHandle<JSTaggedValue> &obj);
226 static JSHandle<TaggedArray> GetOwnPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj);
227 static bool HasProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key);
228 static bool HasProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key);
229 static bool HasOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
230 const JSHandle<JSTaggedValue> &key);
231 static bool GlobalHasOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &key);
232
233 // Type
234 bool IsJSMap() const;
235 bool IsJSSet() const;
236 bool IsJSWeakMap() const;
237 bool IsJSWeakSet() const;
238 bool IsJSRegExp() const;
239 bool IsNumber() const;
240 bool IsBigInt() const;
241 bool IsString() const;
242 bool IsStringOrSymbol() const;
243 bool IsTaggedArray() const;
244 bool IsNativePointer() const;
245 bool IsJSNativePointer() const;
246 bool IsBoolean() const;
247 bool IsSymbol() const;
248 bool IsJSObject() const;
249 bool IsJSGlobalObject() const;
250 bool IsJSError() const;
251 bool IsArray(JSThread *thread) const;
252 bool IsJSArray() const;
253 bool IsStableJSArray(JSThread *thread) const;
254 bool IsStableJSArguments(JSThread *thread) const;
255 bool HasStableElements(JSThread *thread) const;
256 bool IsTypedArray() const;
257 bool IsJSTypedArray() const;
258 bool IsJSInt8Array() const;
259 bool IsJSUint8Array() const;
260 bool IsJSUint8ClampedArray() const;
261 bool IsJSInt16Array() const;
262 bool IsJSUint16Array() const;
263 bool IsJSInt32Array() const;
264 bool IsJSUint32Array() const;
265 bool IsJSFloat32Array() const;
266 bool IsJSFloat64Array() const;
267 bool IsArguments() const;
268 bool IsDate() const;
269 bool IsBoundFunction() const;
270 bool IsJSIntlBoundFunction() const;
271 bool IsProxyRevocFunction() const;
272 bool IsJSAsyncFunction() const;
273 bool IsJSAsyncAwaitStatusFunction() const;
274 bool IsClassConstructor() const;
275 bool IsClassPrototype() const;
276 bool IsJSFunction() const;
277 bool IsJSFunctionBase() const;
278 bool IsECMAObject() const;
279 bool IsJSPrimitiveRef() const;
280 bool IsJSPrimitive() const;
281 bool IsAccessorData() const;
282 bool IsInternalAccessor() const;
283 bool IsAccessor() const;
284 bool IsJSGlobalEnv() const;
285 bool IsJSProxy() const;
286 bool IsDynClass() const;
287 bool IsJSHClass() const;
288 bool IsForinIterator() const;
289 bool IsStringIterator() const;
290 bool IsArrayBuffer() const;
291
292 bool IsJSSetIterator() const;
293 bool IsJSMapIterator() const;
294 bool IsJSArrayIterator() const;
295 bool IsIterator() const;
296 bool IsGeneratorFunction() const;
297 bool IsGeneratorObject() const;
298 bool IsGeneratorContext() const;
299 bool IsAsyncFuncObject() const;
300 bool IsJSPromise() const;
301 bool IsRecord() const;
302 bool IsPromiseReaction() const;
303 bool IsProgram() const;
304 bool IsJSPromiseReactionFunction() const;
305 bool IsJSPromiseExecutorFunction() const;
306 bool IsJSPromiseAllResolveElementFunction() const;
307 bool IsPromiseCapability() const;
308 bool IsPromiseIteratorRecord() const;
309 bool IsPromiseRecord() const;
310 bool IsResolvingFunctionsRecord() const;
311 bool IsCompletionRecord() const;
312 bool IsDataView() const;
313 bool IsTemplateMap() const;
314 bool IsMicroJobQueue() const;
315 bool IsPendingJob() const;
316 bool IsJSLocale() const;
317 bool IsJSDateTimeFormat() const;
318 bool IsJSRelativeTimeFormat() const;
319 bool IsJSIntl() const;
320 bool IsJSNumberFormat() const;
321 bool IsJSCollator() const;
322 bool IsJSPluralRules() const;
323
324 // non ECMA standard jsapis
325 bool IsJSAPIArrayList() const;
326 bool IsJSAPIArrayListIterator() const;
327 bool IsJSAPITreeMap() const;
328 bool IsJSAPITreeSet() const;
329 bool IsJSAPITreeMapIterator() const;
330 bool IsJSAPITreeSetIterator() const;
331 bool IsSpecialContainer() const;
332
333 bool IsPrototypeHandler() const;
334 bool IsTransitionHandler() const;
335 bool IsPropertyBox() const;
336 bool IsProtoChangeMarker() const;
337 bool IsProtoChangeDetails() const;
338 bool IsMachineCodeObject() const;
339 bool IsClassInfoExtractor() const;
340 bool IsTSObjectType() const;
341 bool IsTSClassType() const;
342 bool IsTSUnionType() const;
343 bool IsTSInterfaceType() const;
344 bool IsTSClassInstanceType() const;
345 bool IsTSImportType() const;
346 static bool IsSameTypeOrHClass(JSTaggedValue x, JSTaggedValue y);
347
348 static ComparisonResult Compare(JSThread *thread, const JSHandle<JSTaggedValue> &x,
349 const JSHandle<JSTaggedValue> &y);
350 static ComparisonResult StrictNumberCompare(double x, double y);
351 static bool StrictNumberEquals(double x, double y);
352
353 static JSHandle<JSTaggedValue> ToPrototypeOrObj(JSThread *thread, const JSHandle<JSTaggedValue> &obj);
354 inline uint32_t GetKeyHashCode() const;
355 static JSTaggedValue GetSuperBase(JSThread *thread, const JSHandle<JSTaggedValue> &obj);
356
357 void DumpTaggedValue(JSThread *thread, std::ostream &os) const DUMP_API_ATTR;
358 void Dump(JSThread *thread, std::ostream &os) const DUMP_API_ATTR;
359 void D() const DUMP_API_ATTR;
360 void DumpForSnapshot(JSThread *thread, std::vector<std::pair<CString, JSTaggedValue>> &vec,
361 bool isVmMode = true) const;
362 static void DV(JSTaggedType val) DUMP_API_ATTR;
363
364 private:
365 inline double ExtractNumber() const;
366
367 void DumpSpecialValue([[maybe_unused]] JSThread *thread, std::ostream &os) const;
368 void DumpHeapObjectType([[maybe_unused]] JSThread *thread, std::ostream &os) const;
369
370 // non ECMA standard jsapis
371 static bool HasContainerProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
372 const JSHandle<JSTaggedValue> &key);
373 static JSHandle<TaggedArray> GetOwnContainerPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj);
374 static bool GetContainerProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
375 const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc);
376 };
377 } // namespace panda::ecmascript
378 #endif // ECMASCRIPT_JS_TAGGED_VALUE_H
379