2021-09-04 08:06:49 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2021 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/js_for_in_iterator.h"
|
|
|
|
|
|
|
|
#include "ecmascript/base/builtins_base.h"
|
|
|
|
#include "ecmascript/global_dictionary-inl.h"
|
|
|
|
#include "ecmascript/global_env.h"
|
|
|
|
#include "ecmascript/js_object-inl.h"
|
|
|
|
#include "ecmascript/js_primitive_ref.h"
|
|
|
|
#include "ecmascript/object_factory.h"
|
|
|
|
#include "ecmascript/tagged_array-inl.h"
|
|
|
|
#include "ecmascript/tagged_dictionary.h"
|
2022-04-05 13:28:18 +00:00
|
|
|
#include "ecmascript/tagged_queue.h"
|
2021-09-04 08:06:49 +00:00
|
|
|
#include "ecmascript/tagged_queue.h"
|
|
|
|
|
|
|
|
namespace panda::ecmascript {
|
|
|
|
using BuiltinsBase = base::BuiltinsBase;
|
|
|
|
|
|
|
|
bool JSForInIterator::CheckObjProto(const JSThread *thread, const JSHandle<JSForInIterator> &it)
|
|
|
|
{
|
|
|
|
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
|
|
|
|
JSHandle<JSTaggedValue> object(thread, it->GetObject());
|
|
|
|
if (!object->IsJSObject()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
auto *hclass = object->GetTaggedObject()->GetClass();
|
|
|
|
JSType jsType = hclass->GetObjectType();
|
|
|
|
if (jsType != JSType::JS_OBJECT) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
JSTaggedValue proto = hclass->GetPrototype();
|
|
|
|
if (!proto.IsJSObject()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return hclass->GetPrototype().GetTaggedObject()->GetClass() ==
|
|
|
|
env->GetObjectFunctionPrototypeClass().GetTaggedValue().GetTaggedObject()->GetClass();
|
|
|
|
}
|
|
|
|
|
2022-11-24 07:55:30 +00:00
|
|
|
void JSForInIterator::GetAllEnumKeys(JSThread *thread, const JSHandle<JSForInIterator> &it,
|
|
|
|
const JSHandle<JSTaggedValue> &object)
|
2021-09-04 08:06:49 +00:00
|
|
|
{
|
2022-11-24 07:55:30 +00:00
|
|
|
ASSERT(object->IsHeapObject());
|
2021-09-04 08:06:49 +00:00
|
|
|
JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
|
2022-11-24 07:55:30 +00:00
|
|
|
JSMutableHandle<TaggedQueue> remaining(thread, thread->GlobalConstants()->GetEmptyTaggedQueue());
|
|
|
|
if (object->IsJSProxy()) {
|
|
|
|
JSHandle<TaggedArray> proxyArr = JSProxy::OwnPropertyKeys(thread, JSHandle<JSProxy>(object));
|
|
|
|
uint32_t length = proxyArr->GetLength();
|
|
|
|
for (uint32_t i = 0; i < length; i++) {
|
|
|
|
value.Update(proxyArr->Get(i));
|
|
|
|
PropertyDescriptor desc(thread);
|
|
|
|
JSProxy::GetOwnProperty(thread, JSHandle<JSProxy>(object), value, desc);
|
|
|
|
if (desc.IsEnumerable()) {
|
|
|
|
TaggedQueue *newQueue = TaggedQueue::Push(thread, remaining, value);
|
|
|
|
remaining.Update(JSTaggedValue(newQueue));
|
2021-09-04 08:06:49 +00:00
|
|
|
}
|
2022-11-24 07:55:30 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
JSHandle<TaggedArray> arr = JSTaggedValue::GetOwnEnumPropertyKeys(thread, object);
|
|
|
|
uint32_t len = arr->GetLength();
|
|
|
|
for (uint32_t i = 0; i < len; i++) {
|
|
|
|
value.Update(arr->Get(i));
|
|
|
|
if (value->IsString()) {
|
|
|
|
TaggedQueue *newQueue = TaggedQueue::Push(thread, remaining, value);
|
|
|
|
remaining.Update(JSTaggedValue(newQueue));
|
2021-09-04 08:06:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-11-24 07:55:30 +00:00
|
|
|
if (it->GetHasVisitObjs()) {
|
|
|
|
JSMutableHandle<TaggedQueue> remained(thread, thread->GlobalConstants()->GetEmptyTaggedQueue());
|
|
|
|
JSMutableHandle<TaggedQueue> visited(thread, it->GetVisitedObjs());
|
|
|
|
uint32_t size = visited->Size();
|
|
|
|
while (!remaining->Empty()) {
|
|
|
|
JSHandle<JSTaggedValue> key(thread, remaining->Pop(thread));
|
|
|
|
bool has = false;
|
|
|
|
for (uint32_t i = 0; i < size; i++) {
|
|
|
|
value.Update(visited->Get(i));
|
|
|
|
PropertyDescriptor desc(thread);
|
|
|
|
has = JSTaggedValue::GetOwnProperty(thread, value, key, desc);
|
|
|
|
if (has) {
|
|
|
|
break;
|
2021-09-04 08:06:49 +00:00
|
|
|
}
|
|
|
|
}
|
2022-11-24 07:55:30 +00:00
|
|
|
if (!has) {
|
|
|
|
TaggedQueue *newQueue = TaggedQueue::Push(thread, remained, key);
|
|
|
|
remained.Update(JSTaggedValue(newQueue));
|
2021-09-04 08:06:49 +00:00
|
|
|
}
|
|
|
|
}
|
2022-11-24 07:55:30 +00:00
|
|
|
it->SetRemainingKeys(thread, remained);
|
|
|
|
} else {
|
|
|
|
it->SetRemainingKeys(thread, remaining);
|
2021-09-04 08:06:49 +00:00
|
|
|
}
|
2022-01-25 10:05:12 +00:00
|
|
|
it->SetWasVisited(true);
|
2022-11-24 07:55:30 +00:00
|
|
|
object->GetTaggedObject()->GetClass()->SetHasDeleteProperty(false);
|
2021-09-04 08:06:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<JSTaggedValue, bool> JSForInIterator::NextInternal(JSThread *thread, const JSHandle<JSForInIterator> &it)
|
|
|
|
{
|
|
|
|
while (true) {
|
|
|
|
JSHandle<JSTaggedValue> object(thread, it->GetObject());
|
|
|
|
if (object->IsNull() || object->IsUndefined()) {
|
|
|
|
return std::make_pair(JSTaggedValue::Undefined(), true);
|
|
|
|
}
|
2022-01-25 10:05:12 +00:00
|
|
|
if (!it->GetWasVisited()) {
|
2022-11-24 07:55:30 +00:00
|
|
|
GetAllEnumKeys(thread, it, object);
|
2021-09-04 08:06:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
JSHandle<TaggedQueue> remaining(thread, it->GetRemainingKeys());
|
|
|
|
while (!remaining->Empty()) {
|
2022-11-24 07:55:30 +00:00
|
|
|
ASSERT(object->IsHeapObject());
|
2021-09-04 08:06:49 +00:00
|
|
|
JSTaggedValue r = remaining->Pop(thread);
|
2022-11-24 07:55:30 +00:00
|
|
|
bool hasDelete = object->GetTaggedObject()->GetClass()->HasDeleteProperty();
|
|
|
|
if (object->IsJSObject() && !hasDelete) {
|
2021-09-04 08:06:49 +00:00
|
|
|
return std::make_pair(r, false);
|
|
|
|
}
|
|
|
|
JSHandle<JSTaggedValue> key(thread, r);
|
|
|
|
PropertyDescriptor desc(thread);
|
|
|
|
bool has = JSTaggedValue::GetOwnProperty(thread, object, key, desc);
|
|
|
|
if (has) {
|
|
|
|
if (desc.IsEnumerable()) {
|
|
|
|
return std::make_pair(key.GetTaggedValue(), false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-11-24 07:55:30 +00:00
|
|
|
JSMutableHandle<TaggedQueue> visited(thread, it->GetVisitedObjs());
|
|
|
|
TaggedQueue *newQueue = TaggedQueue::Push(thread, visited, object);
|
|
|
|
visited.Update(JSTaggedValue(newQueue));
|
|
|
|
it->SetVisitedObjs(thread, visited);
|
2022-04-09 06:48:08 +00:00
|
|
|
JSTaggedValue proto = JSTaggedValue::GetPrototype(thread, object);
|
2021-09-04 08:06:49 +00:00
|
|
|
it->SetObject(thread, proto);
|
2022-01-25 10:05:12 +00:00
|
|
|
it->SetWasVisited(false);
|
2022-11-24 07:55:30 +00:00
|
|
|
it->SetHasVisitObjs(true);
|
2021-09-04 08:06:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 13.7.5.16.2.1 %ForInIteratorPrototype%.next ( )
|
|
|
|
JSTaggedValue JSForInIterator::Next(EcmaRuntimeCallInfo *msg)
|
|
|
|
{
|
|
|
|
ASSERT(msg);
|
|
|
|
JSThread *thread = msg->GetThread();
|
|
|
|
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
|
|
|
// 1. Let O be the this value.
|
|
|
|
JSHandle<JSForInIterator> it(BuiltinsBase::GetThis(msg));
|
|
|
|
ASSERT(it->IsForinIterator());
|
|
|
|
std::pair<JSTaggedValue, bool> res = NextInternal(thread, it);
|
|
|
|
return res.first;
|
|
|
|
}
|
|
|
|
} // namespace panda::ecmascript
|