* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_ELEMENTS_H
#define ECMASCRIPT_ELEMENTS_H
#include "ecmascript/global_env_fields.h"
#include "ecmascript/js_tagged_value.h"
#include "ecmascript/mem/c_containers.h"
namespace panda::ecmascript {
#define ELEMENTS_KIND_INIT_HCLASS_LIST(V) \
V(NONE) \
V(HOLE) \
V(INT) \
V(NUMBER) \
V(STRING) \
V(OBJECT) \
V(TAGGED) \
V(HOLE_INT) \
V(HOLE_NUMBER) \
V(HOLE_STRING) \
V(HOLE_OBJECT) \
V(HOLE_TAGGED)
enum class ElementsKind : uint8_t {
NONE = 0x00UL,
HOLE = 0x01UL,
INT = 0x1UL << 1,
NUMBER = (0x1UL << 2) | INT,
STRING = 0x1UL << 3,
OBJECT = 0x1UL << 4,
TAGGED = 0x1EUL,
HOLE_INT = HOLE | INT,
HOLE_NUMBER = HOLE | NUMBER,
HOLE_STRING = HOLE | STRING,
HOLE_OBJECT = HOLE | OBJECT,
HOLE_TAGGED = HOLE | TAGGED,
GENERIC = HOLE_TAGGED,
DICTIONARY = HOLE_TAGGED,
};
class PUBLIC_API Elements {
public:
static constexpr int32_t KIND_COUNT = static_cast<uint8_t>(ElementsKind::HOLE_TAGGED) + 1;
static constexpr uint32_t ToUint(ElementsKind kind)
{
return static_cast<uint32_t>(kind);
}
static std::string GetString(ElementsKind kind);
static bool IsInt(ElementsKind kind);
static bool IsNumber(ElementsKind kind);
static bool IsTagged(ElementsKind kind);
static bool IsObject(ElementsKind kind);
static bool IsHole(ElementsKind kind);
static bool IsGeneric(ElementsKind kind)
{
return kind == ElementsKind::GENERIC;
}
static bool IsNone(ElementsKind kind)
{
return kind == ElementsKind::NONE;
}
static bool IsComplex(ElementsKind kind)
{
return IsNumber(kind) || IsTagged(kind);
}
static bool IsInNumbers(ElementsKind kind)
{
return (ToUint(kind) > ToUint(ElementsKind::HOLE) &&
ToUint(kind) < ToUint(ElementsKind::STRING));
}
static bool IsIntOrHoleInt(ElementsKind kind)
{
return kind == ElementsKind::INT || kind == ElementsKind::HOLE_INT;
}
static bool IsNumberOrHoleNumber(ElementsKind kind)
{
return kind == ElementsKind::NUMBER || kind == ElementsKind::HOLE_NUMBER;
}
static bool IsStringOrHoleString(ElementsKind kind)
{
return kind == ElementsKind::STRING || kind == ElementsKind::HOLE_STRING;
}
static ElementsKind MergeElementsKind(ElementsKind curKind, ElementsKind newKind);
static ElementsKind FixElementsKind(ElementsKind oldKind);
static inline ElementsKind ToElementsKind(JSTaggedValue value)
{
ElementsKind valueKind = ElementsKind::NONE;
if (value.IsInt()) {
valueKind = ElementsKind::INT;
} else if (value.IsDouble()) {
valueKind = ElementsKind::NUMBER;
} else if (value.IsString()) {
valueKind = ElementsKind::STRING;
} else if (value.IsHeapObject()) {
valueKind = ElementsKind::OBJECT;
} else if (value.IsHole()) {
valueKind = ElementsKind::HOLE;
} else {
valueKind = ElementsKind::TAGGED;
}
return valueKind;
}
static ElementsKind ToElementsKind(JSTaggedValue value, ElementsKind kind);
static ElementsKind MergeElementsKindNoFix(JSTaggedValue value, ElementsKind curKind, ElementsKind newKind)
{
return static_cast<ElementsKind>(static_cast<uint8_t>(ToElementsKind(value)) | static_cast<uint8_t>(curKind) |
static_cast<uint8_t>(newKind));
}
static void MigrateArrayWithKind(const JSThread *thread, const JSHandle<JSObject> &object,
const ElementsKind oldKind, const ElementsKind newKind);
private:
static JSTaggedValue MigrateFromRawValueToHeapValue(const JSThread *thread, const JSHandle<JSObject> object,
bool needCOW, bool isIntKind);
static void HandleIntKindMigration(const JSThread *thread, const JSHandle<JSObject> &object,
const ElementsKind newKind, bool needCOW);
static bool IsNumberKind(const ElementsKind kind);
static bool IsStringOrNoneOrHole(const ElementsKind kind);
static void HandleNumberKindMigration(const JSThread *thread,
const JSHandle<JSObject> &object,
const ElementsKind newKind, bool needCOW);
static void HandleOtherKindMigration(const JSThread *thread, const JSHandle<JSObject> &object,
const ElementsKind newKind, bool needCOW);
static JSTaggedValue MigrateFromHeapValueToRawValue(const JSThread *thread, const JSHandle<JSObject> object,
bool needCOW, bool isIntKind);
static void MigrateFromHoleIntToHoleNumber(const JSThread *thread, const JSHandle<JSObject> object);
static void MigrateFromHoleNumberToHoleInt(const JSThread *thread, const JSHandle<JSObject> object);
};
}
#endif