Fix HashMap And HashSet

Description
    Modify the format problem and add protection to taggedhasharray length == 0.
Related issue
    https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I5M90M

Signed-off-by: chenqi <chenqi151@huawei.com>
This commit is contained in:
chenqi 2022-08-15 09:49:07 +08:00
parent d64f47a281
commit 0ca2fb1ce3
11 changed files with 55 additions and 39 deletions

View File

@ -108,7 +108,7 @@ JSTaggedValue ContainersHashMap::ForEach(EcmaRuntimeCallInfo *argv)
}
JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
if (!callbackFnHandle->IsCallable()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception());
THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
JSHandle<JSAPIHashMap> hashMap = JSHandle<JSAPIHashMap>::Cast(thisHandle);
@ -172,9 +172,9 @@ JSTaggedValue ContainersHashMap::SetAll(EcmaRuntimeCallInfo *argv)
THROW_TYPE_ERROR_AND_RETURN(thread, "Incorrect parameters, it should be HashMap", JSTaggedValue::Exception());
}
JSHandle<JSAPIHashMap> dmap = JSHandle<JSAPIHashMap>::Cast(self);
JSHandle<JSAPIHashMap> smap = JSHandle<JSAPIHashMap>::Cast(obj);
JSAPIHashMap::SetAll(thread, dmap, smap);
JSHandle<JSAPIHashMap> targetMap = JSHandle<JSAPIHashMap>::Cast(self);
JSHandle<JSAPIHashMap> sourceMap = JSHandle<JSAPIHashMap>::Cast(obj);
JSAPIHashMap::SetAll(thread, targetMap, sourceMap);
return self.GetTaggedValue();
}

View File

@ -188,7 +188,7 @@ JSTaggedValue ContainersHashSet::ForEach(EcmaRuntimeCallInfo *argv)
}
JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
if (!callbackFnHandle->IsCallable()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception());
THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
JSHandle<JSAPIHashSet> hashSet = JSHandle<JSAPIHashSet>::Cast(thisHandle);

View File

@ -1077,7 +1077,7 @@ JSHandle<JSTaggedValue> ContainersPrivate::InitializeHashMap(JSThread *thread)
// HashMap.prototype_or_dynclass
JSHandle<JSHClass> hashMapInstanceDynclass =
factory->NewEcmaDynClass(JSAPIHashMap::SIZE, JSType::JS_API_HASH_MAP, hashMapFuncPrototypeValue);
// HashMap() = new Function()
JSHandle<JSTaggedValue> hashMapFunction(NewContainerConstructor(
thread, hashMapFuncPrototype, ContainersHashMap::HashMapConstructor, "HashMap", FuncLength::ZERO));
JSHandle<JSFunction>::Cast(hashMapFunction)->SetFunctionPrototype(thread, hashMapInstanceDynclass.GetTaggedValue());
@ -1157,7 +1157,7 @@ JSHandle<JSTaggedValue> ContainersPrivate::InitializeHashSet(JSThread *thread)
// HashSet.prototype_or_dynclass
JSHandle<JSHClass> hashSetInstanceDynclass =
factory->NewEcmaDynClass(JSAPIHashSet::SIZE, JSType::JS_API_HASH_SET, hashSetFuncPrototypeValue);
// HashSet() = new Function()
JSHandle<JSTaggedValue> hashSetFunction(NewContainerConstructor(
thread, hashSetFuncPrototype, ContainersHashSet::HashSetConstructor, "HashSet", FuncLength::ZERO));
JSHandle<JSFunction>::Cast(hashSetFunction)->SetFunctionPrototype(thread, hashSetInstanceDynclass.GetTaggedValue());

View File

@ -165,6 +165,9 @@ JSTaggedValue JSAPIHashMap::Remove(JSThread *thread, JSHandle<JSAPIHashMap> hash
}
hashMap->SetSize(--nodeNum);
uint32_t length = hashArray->GetLength();
ASSERT_PRINT(length >= TaggedHashArray::DEFAULT_INITIAL_CAPACITY,
"TaggedHashArray length must greater than or equal to the default minimum value");
uint32_t index = (length - 1) & hash;
JSTaggedValue rootVa = hashArray->Get(index);
if (rootVa.IsRBTreeNode()) {

View File

@ -65,7 +65,7 @@ JSTaggedValue JSAPIHashMapIterator::Next(EcmaRuntimeCallInfo *argv)
if (itemKind == IterationKind::VALUE) {
return JSIterator::CreateIterResultObject(thread, valueHandle, false).GetTaggedValue();
}
// Else
array.Update(factory->NewTaggedArray(2)); // 2 means the length of array
array->Set(thread, 0, keyHandle);
array->Set(thread, 1, valueHandle);

View File

@ -61,7 +61,7 @@ JSTaggedValue JSAPIHashSetIterator::Next(EcmaRuntimeCallInfo *argv)
if (itemKind == IterationKind::VALUE) {
return JSIterator::CreateIterResultObject(thread, valueHandle, false).GetTaggedValue();
}
// Else
array.Update(factory->NewTaggedArray(2)); // 2 means the length of array
array->Set(thread, 0, JSTaggedValue(--index));
array->Set(thread, 1, valueHandle);

View File

@ -1144,60 +1144,74 @@ void ObjectFactory::InitializeJSObject(const JSHandle<JSObject> &obj, const JSHa
JSDataView::Cast(*obj)->SetByteOffset(0);
break;
// non ECMA standard jsapi container
case JSType::JS_API_ARRAY_LIST:
case JSType::JS_API_ARRAY_LIST: {
JSAPIArrayList::Cast(*obj)->SetLength(thread_, JSTaggedValue(0));
break;
case JSType::JS_API_HASH_MAP:
}
case JSType::JS_API_HASH_MAP: {
JSAPIHashMap::Cast(*obj)->SetSize(0);
JSAPIHashMap::Cast(*obj)->SetTable(thread_, JSTaggedValue::Undefined());
break;
case JSType::JS_API_HASH_SET:
}
case JSType::JS_API_HASH_SET: {
JSAPIHashSet::Cast(*obj)->SetSize(0);
JSAPIHashSet::Cast(*obj)->SetTable(thread_, JSTaggedValue::Undefined());
break;
case JSType::JS_API_TREE_MAP:
}
case JSType::JS_API_TREE_MAP: {
JSAPITreeMap::Cast(*obj)->SetTreeMap(thread_, JSTaggedValue::Undefined());
break;
case JSType::JS_API_TREE_SET:
}
case JSType::JS_API_TREE_SET: {
JSAPITreeSet::Cast(*obj)->SetTreeSet(thread_, JSTaggedValue::Undefined());
break;
case JSType::JS_API_QUEUE:
}
case JSType::JS_API_QUEUE: {
JSAPIQueue::Cast(*obj)->SetLength(thread_, JSTaggedValue(0));
JSAPIQueue::Cast(*obj)->SetFront(0);
JSAPIQueue::Cast(*obj)->SetTail(0);
break;
case JSType::JS_API_PLAIN_ARRAY:
}
case JSType::JS_API_PLAIN_ARRAY: {
JSAPIPlainArray::Cast(*obj)->SetLength(0);
JSAPIPlainArray::Cast(*obj)->SetValues(thread_, JSTaggedValue(0));
JSAPIPlainArray::Cast(*obj)->SetKeys(thread_, JSTaggedValue(0));
break;
case JSType::JS_API_STACK:
}
case JSType::JS_API_STACK: {
JSAPIStack::Cast(*obj)->SetTop(0);
break;
case JSType::JS_API_DEQUE:
}
case JSType::JS_API_DEQUE: {
JSAPIDeque::Cast(*obj)->SetFirst(0);
JSAPIDeque::Cast(*obj)->SetLast(0);
break;
case JSType::JS_API_LIGHT_WEIGHT_MAP:
}
case JSType::JS_API_LIGHT_WEIGHT_MAP: {
JSAPILightWeightMap::Cast(*obj)->SetLength(0);
JSAPILightWeightMap::Cast(*obj)->SetHashes(thread_, JSTaggedValue::Undefined());
JSAPILightWeightMap::Cast(*obj)->SetKeys(thread_, JSTaggedValue::Undefined());
JSAPILightWeightMap::Cast(*obj)->SetValues(thread_, JSTaggedValue::Undefined());
break;
case JSType::JS_API_LIGHT_WEIGHT_SET:
}
case JSType::JS_API_LIGHT_WEIGHT_SET: {
JSAPILightWeightSet::Cast(*obj)->SetLength(0);
JSAPILightWeightSet::Cast(*obj)->SetHashes(thread_, JSTaggedValue::Undefined());
JSAPILightWeightSet::Cast(*obj)->SetValues(thread_, JSTaggedValue::Undefined());
break;
case JSType::JS_API_VECTOR:
}
case JSType::JS_API_VECTOR: {
JSAPIVector::Cast(*obj)->SetLength(0);
break;
case JSType::JS_API_LIST:
}
case JSType::JS_API_LIST: {
JSAPIList::Cast(*obj)->SetSingleList(thread_, JSTaggedValue::Undefined());
break;
case JSType::JS_API_LINKED_LIST:
}
case JSType::JS_API_LINKED_LIST: {
JSAPILinkedList::Cast(*obj)->SetDoubleList(thread_, JSTaggedValue::Undefined());
break;
}
case JSType::JS_ASYNC_FUNC_OBJECT:
JSAsyncFuncObject::Cast(*obj)->SetGeneratorContext(thread_, JSTaggedValue::Undefined());
JSAsyncFuncObject::Cast(*obj)->SetResumeResult(thread_, JSTaggedValue::Undefined());

View File

@ -184,18 +184,18 @@ JSTaggedValue TaggedHashArray::SetVal(JSThread *thread, JSHandle<TaggedHashArray
JSMutableHandle<LinkedNode> root(thread, JSTaggedValue::Undefined());
uint32_t count = 0;
JSMutableHandle<JSTaggedValue> currentKey(thread, JSTaggedValue::Undefined());
JSMutableHandle<JSTaggedValue> nextVa(thread, node.GetTaggedValue());
JSMutableHandle<JSTaggedValue> nextVal(thread, node.GetTaggedValue());
do {
root.Update(nextVa);
root.Update(nextVal);
currentKey.Update(root->GetKey());
if (root->GetHash().GetInt() == hash && (!key->IsHole() &&
JSTaggedValue::Equal(thread, key, currentKey))) {
root->SetValue(thread, value.GetTaggedValue());
return JSTaggedValue::Undefined();
}
nextVa.Update(root->GetNext());
nextVal.Update(root->GetNext());
count++;
} while (!nextVa->IsHole());
} while (!nextVal->IsHole());
JSHandle<LinkedNode> newNode = TaggedHashArray::NewLinkedNode(thread, hash, key, value);
root->SetNext(thread, newNode);
table->Set(thread, index, node.GetTaggedValue());

View File

@ -27,7 +27,7 @@ class TaggedHashArray : public TaggedArray {
public:
static constexpr uint32_t MAXIMUM_CAPACITY = 1 << 30;
static constexpr uint32_t UNTREEIFY_THRESHOLD = 6;
static constexpr uint32_t DEFAULT_INITIAL_CAPACITY = 1 << 4; // 16
static constexpr uint32_t DEFAULT_INITIAL_CAPACITY = 1 << 4;
static constexpr float DEFAULT_LOAD_FACTOR = 0.75f;
static constexpr uint32_t TREEIFY_THRESHOLD = 8;

View File

@ -38,11 +38,11 @@ JSHandle<RBTreeNode> LinkedNode::Treeing(JSThread *thread, const JSHandle<Linked
void RBTreeNode::InitRBTreeNode(JSThread *thread, int hash, JSHandle<JSTaggedValue> key,
JSHandle<JSTaggedValue> value, int count)
{
this->InitTaggedNode(thread, hash, key, value);
this->SetLeft(thread, JSTaggedValue::Hole());
this->SetRight(thread, JSTaggedValue::Hole());
this->SetIsRed(thread, JSTaggedValue(true));
this->SetCount(count);
InitTaggedNode(thread, hash, key, value);
SetLeft(thread, JSTaggedValue::Hole());
SetRight(thread, JSTaggedValue::Hole());
SetIsRed(thread, JSTaggedValue(true));
SetCount(count);
}
// number of node in subtree rooted at treeNode; 0 if treeNode is Hole
@ -111,7 +111,6 @@ void RBTreeNode::InOrderTraverse(JSThread *thread, const JSHandle<RBTreeNode> &t
JSHandle<RBTreeNode> rightChild(thread, treeNode->GetRight());
InOrderTraverse(thread, rightChild, bit, nodeStruct);
}
return;
}
void RBTreeNode::Divide(JSThread *thread, JSHandle<TaggedHashArray> table,

View File

@ -25,9 +25,9 @@ class TaggedNode : public TaggedObject {
public:
void InitTaggedNode(JSThread *thread, int hash, JSHandle<JSTaggedValue> key, JSHandle<JSTaggedValue> value)
{
this->SetHash(thread, JSTaggedValue(hash));
this->SetKey(thread, key.GetTaggedValue());
this->SetValue(thread, value.GetTaggedValue());
SetHash(thread, JSTaggedValue(hash));
SetKey(thread, key.GetTaggedValue());
SetValue(thread, value.GetTaggedValue());
}
static TaggedNode *Cast(TaggedObject *object)
@ -84,8 +84,8 @@ public:
void InitLinkedNode(JSThread *thread, int hash, JSHandle<JSTaggedValue> key,
JSHandle<JSTaggedValue> value, JSHandle<LinkedNode> next)
{
this->SetNext(thread, next);
this->InitTaggedNode(thread, hash, key, value);
SetNext(thread, next);
InitTaggedNode(thread, hash, key, value);
}
static LinkedNode *Cast(TaggedObject *object)