mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-10-07 16:13:49 +00:00
ec2887a79d
Issue: #I8YKFK Change-Id: I5fe2ff3ca8ac2d2d5e99a1de17c70641342a9fc3 Signed-off-by: yingguofeng@huawei.com <yingguofeng@huawei.com>
288 lines
12 KiB
C++
288 lines
12 KiB
C++
/*
|
|
* 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.
|
|
*/
|
|
|
|
#include "ecmascript/elements.h"
|
|
#include "ecmascript/base/bit_helper.h"
|
|
#include "ecmascript/global_env_constants.h"
|
|
#include "ecmascript/js_tagged_value-inl.h"
|
|
#include "ecmascript/tagged_array-inl.h"
|
|
|
|
namespace panda::ecmascript {
|
|
CMap<ElementsKind, ConstantIndex> Elements::InitializeHClassMap()
|
|
{
|
|
CMap<ElementsKind, ConstantIndex> result;
|
|
result.emplace(ElementsKind::NONE, ConstantIndex::ELEMENT_NONE_HCLASS_INDEX);
|
|
result.emplace(ElementsKind::HOLE, ConstantIndex::ELEMENT_HOLE_HCLASS_INDEX);
|
|
result.emplace(ElementsKind::INT, ConstantIndex::ELEMENT_INT_HCLASS_INDEX);
|
|
result.emplace(ElementsKind::NUMBER, ConstantIndex::ELEMENT_NUMBER_HCLASS_INDEX);
|
|
result.emplace(ElementsKind::STRING, ConstantIndex::ELEMENT_STRING_HCLASS_INDEX);
|
|
result.emplace(ElementsKind::OBJECT, ConstantIndex::ELEMENT_OBJECT_HCLASS_INDEX);
|
|
result.emplace(ElementsKind::TAGGED, ConstantIndex::ELEMENT_TAGGED_HCLASS_INDEX);
|
|
result.emplace(ElementsKind::HOLE_INT, ConstantIndex::ELEMENT_HOLE_INT_HCLASS_INDEX);
|
|
result.emplace(ElementsKind::HOLE_NUMBER, ConstantIndex::ELEMENT_HOLE_NUMBER_HCLASS_INDEX);
|
|
result.emplace(ElementsKind::HOLE_STRING, ConstantIndex::ELEMENT_HOLE_STRING_HCLASS_INDEX);
|
|
result.emplace(ElementsKind::HOLE_OBJECT, ConstantIndex::ELEMENT_HOLE_OBJECT_HCLASS_INDEX);
|
|
result.emplace(ElementsKind::HOLE_TAGGED, ConstantIndex::ELEMENT_HOLE_TAGGED_HCLASS_INDEX);
|
|
return result;
|
|
}
|
|
|
|
std::string Elements::GetString(ElementsKind kind)
|
|
{
|
|
return std::to_string(static_cast<uint32_t>(kind));
|
|
}
|
|
|
|
bool Elements::IsInt(ElementsKind kind)
|
|
{
|
|
return kind == ElementsKind::INT;
|
|
}
|
|
|
|
bool Elements::IsNumber(ElementsKind kind)
|
|
{
|
|
return kind == ElementsKind::NUMBER;
|
|
}
|
|
|
|
bool Elements::IsTagged(ElementsKind kind)
|
|
{
|
|
return kind == ElementsKind::TAGGED;
|
|
}
|
|
|
|
bool Elements::IsObject(ElementsKind kind)
|
|
{
|
|
return kind == ElementsKind::OBJECT;
|
|
}
|
|
|
|
bool Elements::IsHole(ElementsKind kind)
|
|
{
|
|
static constexpr uint8_t EVEN_NUMBER = 2;
|
|
return static_cast<uint8_t>(kind) % EVEN_NUMBER == 1;
|
|
}
|
|
|
|
ConstantIndex Elements::GetGlobalContantIndexByKind(ElementsKind kind)
|
|
{
|
|
switch (kind) {
|
|
case ElementsKind::NONE:
|
|
return ConstantIndex::ELEMENT_NONE_HCLASS_INDEX;
|
|
case ElementsKind::INT:
|
|
return ConstantIndex::ELEMENT_INT_HCLASS_INDEX;
|
|
case ElementsKind::NUMBER:
|
|
return ConstantIndex::ELEMENT_NUMBER_HCLASS_INDEX;
|
|
case ElementsKind::STRING:
|
|
return ConstantIndex::ELEMENT_STRING_HCLASS_INDEX;
|
|
case ElementsKind::OBJECT:
|
|
return ConstantIndex::ELEMENT_OBJECT_HCLASS_INDEX;
|
|
case ElementsKind::TAGGED:
|
|
return ConstantIndex::ELEMENT_TAGGED_HCLASS_INDEX;
|
|
case ElementsKind::HOLE:
|
|
return ConstantIndex::ELEMENT_HOLE_HCLASS_INDEX;
|
|
case ElementsKind::HOLE_INT:
|
|
return ConstantIndex::ELEMENT_HOLE_INT_HCLASS_INDEX;
|
|
case ElementsKind::HOLE_NUMBER:
|
|
return ConstantIndex::ELEMENT_HOLE_NUMBER_HCLASS_INDEX;
|
|
case ElementsKind::HOLE_STRING:
|
|
return ConstantIndex::ELEMENT_HOLE_STRING_HCLASS_INDEX;
|
|
case ElementsKind::HOLE_OBJECT:
|
|
return ConstantIndex::ELEMENT_HOLE_OBJECT_HCLASS_INDEX;
|
|
case ElementsKind::HOLE_TAGGED:
|
|
return ConstantIndex::ELEMENT_HOLE_TAGGED_HCLASS_INDEX;
|
|
default:
|
|
LOG_ECMA(FATAL) << "Unknown elementsKind when getting constantIndx: " << static_cast<int32_t>(kind);
|
|
}
|
|
}
|
|
|
|
ElementsKind Elements::MergeElementsKind(ElementsKind curKind, ElementsKind newKind)
|
|
{
|
|
auto result = ElementsKind(static_cast<uint8_t>(curKind) | static_cast<uint8_t>(newKind));
|
|
result = FixElementsKind(result);
|
|
return result;
|
|
}
|
|
|
|
ElementsKind Elements::FixElementsKind(ElementsKind oldKind)
|
|
{
|
|
auto result = oldKind;
|
|
switch (result) {
|
|
case ElementsKind::NONE:
|
|
case ElementsKind::INT:
|
|
case ElementsKind::NUMBER:
|
|
case ElementsKind::STRING:
|
|
case ElementsKind::OBJECT:
|
|
case ElementsKind::HOLE:
|
|
case ElementsKind::HOLE_INT:
|
|
case ElementsKind::HOLE_NUMBER:
|
|
case ElementsKind::HOLE_STRING:
|
|
case ElementsKind::HOLE_OBJECT:
|
|
break;
|
|
default:
|
|
if (IsHole(result)) {
|
|
result = ElementsKind::HOLE_TAGGED;
|
|
} else {
|
|
result = ElementsKind::TAGGED;
|
|
}
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
ElementsKind Elements::ToElementsKind(JSTaggedValue value, ElementsKind kind)
|
|
{
|
|
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 MergeElementsKind(valueKind, kind);
|
|
}
|
|
|
|
void Elements::MigrateArrayWithKind(const JSThread *thread, const JSHandle<JSObject> &object,
|
|
const ElementsKind oldKind, const ElementsKind newKind)
|
|
{
|
|
if (!thread->GetEcmaVM()->IsEnableElementsKind()) {
|
|
return;
|
|
}
|
|
if (oldKind == newKind) {
|
|
return;
|
|
}
|
|
// When create ArrayLiteral from constantPool, we need to preserve the COW property if necessary.
|
|
// When transition happens to Array, e.g. arr.x = 1, we need to preserve the COW property if necessary.
|
|
bool needCOW = object->GetElements().IsCOWArray();
|
|
if ((oldKind == ElementsKind::INT && newKind == ElementsKind::HOLE_INT) ||
|
|
(oldKind == ElementsKind::NUMBER && newKind == ElementsKind::HOLE_NUMBER)) {
|
|
return;
|
|
} else if (oldKind == ElementsKind::INT || oldKind == ElementsKind::HOLE_INT) {
|
|
if (static_cast<uint32_t>(newKind) >= static_cast<uint32_t>(ElementsKind::STRING) ||
|
|
newKind == ElementsKind::NONE || newKind == ElementsKind::HOLE) {
|
|
JSTaggedValue newElements = MigrateFromRawValueToHeapValue(thread, object, needCOW, true);
|
|
object->SetElements(thread, newElements);
|
|
} else if (newKind == ElementsKind::NUMBER || newKind == ElementsKind::HOLE_NUMBER) {
|
|
MigrateFromHoleIntToHoleNumber(thread, object);
|
|
}
|
|
} else if (static_cast<uint32_t>(oldKind) >= static_cast<uint32_t>(ElementsKind::NUMBER) &&
|
|
static_cast<uint32_t>(oldKind) <= static_cast<uint32_t>(ElementsKind::HOLE_NUMBER)) {
|
|
if (static_cast<uint32_t>(newKind) >= static_cast<uint32_t>(ElementsKind::STRING) ||
|
|
newKind == ElementsKind::NONE || newKind == ElementsKind::HOLE) {
|
|
JSTaggedValue newElements = MigrateFromRawValueToHeapValue(thread, object, needCOW, false);
|
|
object->SetElements(thread, newElements);
|
|
} else if (newKind == ElementsKind::INT || newKind == ElementsKind::HOLE_INT) {
|
|
MigrateFromHoleNumberToHoleInt(thread, object);
|
|
}
|
|
} else {
|
|
if (newKind == ElementsKind::INT || newKind == ElementsKind::HOLE_INT) {
|
|
JSTaggedValue newElements = MigrateFromHeapValueToRawValue(thread, object, needCOW, true);
|
|
object->SetElements(thread, newElements);
|
|
} else if (static_cast<uint32_t>(newKind) >= static_cast<uint32_t>(ElementsKind::NUMBER) &&
|
|
static_cast<uint32_t>(newKind) <= static_cast<uint32_t>(ElementsKind::HOLE_NUMBER)) {
|
|
JSTaggedValue newElements = MigrateFromHeapValueToRawValue(thread, object, needCOW, false);
|
|
object->SetElements(thread, newElements);
|
|
}
|
|
}
|
|
}
|
|
|
|
JSTaggedValue Elements::MigrateFromRawValueToHeapValue(const JSThread *thread, const JSHandle<JSObject> object,
|
|
bool needCOW, bool isIntKind)
|
|
{
|
|
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
|
JSHandle<MutantTaggedArray> elements = JSHandle<MutantTaggedArray>(thread, object->GetElements());
|
|
uint32_t length = elements->GetLength();
|
|
JSMutableHandle<TaggedArray> newElements(thread, JSTaggedValue::Undefined());
|
|
if (needCOW) {
|
|
newElements.Update(factory->NewCOWTaggedArray(length));
|
|
} else {
|
|
newElements.Update(factory->NewTaggedArray(length));
|
|
}
|
|
for (uint32_t i = 0; i < length; i++) {
|
|
JSTaggedType value = elements->Get(i).GetRawData();
|
|
if (value == base::SPECIAL_HOLE) {
|
|
newElements->Set(thread, i, JSTaggedValue::Hole());
|
|
} else if (isIntKind) {
|
|
int convertedValue = static_cast<int>(value);
|
|
newElements->Set(thread, i, JSTaggedValue(convertedValue));
|
|
} else {
|
|
double convertedValue = base::bit_cast<double>(value);
|
|
newElements->Set(thread, i, JSTaggedValue(convertedValue));
|
|
}
|
|
}
|
|
return newElements.GetTaggedValue();
|
|
}
|
|
|
|
JSTaggedValue Elements::MigrateFromHeapValueToRawValue(const JSThread *thread, const JSHandle<JSObject> object,
|
|
bool needCOW, bool isIntKind)
|
|
{
|
|
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
|
JSHandle<TaggedArray> elements = JSHandle<TaggedArray>(thread, object->GetElements());
|
|
uint32_t length = elements->GetLength();
|
|
JSMutableHandle<MutantTaggedArray> newElements(thread, JSTaggedValue::Undefined());
|
|
if (needCOW) {
|
|
newElements.Update(factory->NewCOWMutantTaggedArray(length));
|
|
} else {
|
|
newElements.Update(factory->NewMutantTaggedArray(length));
|
|
}
|
|
for (uint32_t i = 0; i < length; i++) {
|
|
JSTaggedValue value = elements->Get(i);
|
|
JSTaggedType convertedValue = 0;
|
|
// To distinguish Hole (0x5) in taggedvalue with Interger 5
|
|
if (value.IsHole()) {
|
|
convertedValue = base::SPECIAL_HOLE;
|
|
} else if (isIntKind) {
|
|
convertedValue = static_cast<JSTaggedType>(value.GetInt());
|
|
} else if (value.IsInt()) {
|
|
int intValue = value.GetInt();
|
|
convertedValue = base::bit_cast<JSTaggedType>(static_cast<double>(intValue));
|
|
} else {
|
|
convertedValue = base::bit_cast<JSTaggedType>(value.GetDouble());
|
|
}
|
|
newElements->Set<false>(thread, i, JSTaggedValue(convertedValue));
|
|
}
|
|
return newElements.GetTaggedValue();
|
|
}
|
|
|
|
void Elements::MigrateFromHoleIntToHoleNumber(const JSThread *thread, const JSHandle<JSObject> object)
|
|
{
|
|
JSHandle<MutantTaggedArray> elements = JSHandle<MutantTaggedArray>(thread, object->GetElements());
|
|
uint32_t length = elements->GetLength();
|
|
for (uint32_t i = 0; i < length; i++) {
|
|
JSTaggedType value = elements->Get(i).GetRawData();
|
|
if (value == base::SPECIAL_HOLE) {
|
|
continue;
|
|
}
|
|
int intValue = static_cast<int>(elements->Get(i).GetRawData());
|
|
double convertedValue = static_cast<double>(intValue);
|
|
elements->Set<false>(thread, i, JSTaggedValue(base::bit_cast<JSTaggedType>(convertedValue)));
|
|
}
|
|
}
|
|
|
|
void Elements::MigrateFromHoleNumberToHoleInt(const JSThread *thread, const JSHandle<JSObject> object)
|
|
{
|
|
JSHandle<MutantTaggedArray> elements = JSHandle<MutantTaggedArray>(thread, object->GetElements());
|
|
uint32_t length = elements->GetLength();
|
|
for (uint32_t i = 0; i < length; i++) {
|
|
JSTaggedType value = elements->Get(i).GetRawData();
|
|
if (value == base::SPECIAL_HOLE) {
|
|
continue;
|
|
}
|
|
double intValue = base::bit_cast<double>(elements->Get(i).GetRawData());
|
|
int64_t convertedValue = static_cast<int64_t>(intValue);
|
|
elements->Set<false>(thread, i, JSTaggedValue(base::bit_cast<JSTaggedType>(convertedValue)));
|
|
}
|
|
}
|
|
} // namespace panda::ecmascript
|