14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci
164514f5e3Sopenharmony_ci#include "ecmascript/mem/work_manager.h"
174514f5e3Sopenharmony_ci
184514f5e3Sopenharmony_ci#include "ecmascript/mem/incremental_marker.h"
194514f5e3Sopenharmony_ci#include "ecmascript/mem/tlab_allocator-inl.h"
204514f5e3Sopenharmony_ci
214514f5e3Sopenharmony_cinamespace panda::ecmascript {
224514f5e3Sopenharmony_ciWorkManagerBase::WorkManagerBase(NativeAreaAllocator *allocator)
234514f5e3Sopenharmony_ci    : spaceChunk_(allocator), workSpace_(0), spaceStart_(0), spaceEnd_(0)
244514f5e3Sopenharmony_ci{
254514f5e3Sopenharmony_ci    auto allocatedSpace = GetSpaceChunk()->Allocate(WORKNODE_SPACE_SIZE);
264514f5e3Sopenharmony_ci    ASSERT(allocatedSpace != nullptr);
274514f5e3Sopenharmony_ci    workSpace_ = ToUintPtr(allocatedSpace);
284514f5e3Sopenharmony_ci}
294514f5e3Sopenharmony_ci
304514f5e3Sopenharmony_ciWorkNode *WorkManagerBase::AllocateWorkNode()
314514f5e3Sopenharmony_ci{
324514f5e3Sopenharmony_ci    LockHolder lock(mtx_);
334514f5e3Sopenharmony_ci    size_t allocatedSize = sizeof(WorkNode) + sizeof(Stack) + STACK_AREA_SIZE;
344514f5e3Sopenharmony_ci    ASSERT(allocatedSize < WORKNODE_SPACE_SIZE);
354514f5e3Sopenharmony_ci
364514f5e3Sopenharmony_ci    uintptr_t begin = spaceStart_;
374514f5e3Sopenharmony_ci    if (begin + allocatedSize >= spaceEnd_) {
384514f5e3Sopenharmony_ci        agedSpaces_.emplace_back(workSpace_);
394514f5e3Sopenharmony_ci        workSpace_ = ToUintPtr(GetSpaceChunk()->Allocate(WORKNODE_SPACE_SIZE));
404514f5e3Sopenharmony_ci        spaceStart_ = workSpace_;
414514f5e3Sopenharmony_ci        spaceEnd_ = workSpace_ + WORKNODE_SPACE_SIZE;
424514f5e3Sopenharmony_ci        begin = spaceStart_;
434514f5e3Sopenharmony_ci    }
444514f5e3Sopenharmony_ci    spaceStart_ = begin + allocatedSize;
454514f5e3Sopenharmony_ci    Stack *stack = reinterpret_cast<Stack *>(begin + sizeof(WorkNode));
464514f5e3Sopenharmony_ci    stack->ResetBegin(begin + sizeof(WorkNode) + sizeof(Stack), begin + allocatedSize);
474514f5e3Sopenharmony_ci    WorkNode *work = reinterpret_cast<WorkNode *>(begin);
484514f5e3Sopenharmony_ci    return new (work) WorkNode(stack);
494514f5e3Sopenharmony_ci}
504514f5e3Sopenharmony_ci
514514f5e3Sopenharmony_ciWorkManagerBase::~WorkManagerBase()
524514f5e3Sopenharmony_ci{
534514f5e3Sopenharmony_ci    GetSpaceChunk()->Free(reinterpret_cast<void *>(workSpace_));
544514f5e3Sopenharmony_ci}
554514f5e3Sopenharmony_ci
564514f5e3Sopenharmony_ciWorkManager::WorkManager(Heap *heap, uint32_t threadNum)
574514f5e3Sopenharmony_ci    : WorkManagerBase(heap->GetNativeAreaAllocator()), heap_(heap), threadNum_(threadNum),
584514f5e3Sopenharmony_ci      continuousQueue_ { nullptr }, parallelGCTaskPhase_(UNDEFINED_TASK)
594514f5e3Sopenharmony_ci{
604514f5e3Sopenharmony_ci    for (uint32_t i = 0; i < threadNum_; i++) {
614514f5e3Sopenharmony_ci        continuousQueue_.at(i) = new ProcessQueue();
624514f5e3Sopenharmony_ci    }
634514f5e3Sopenharmony_ci}
644514f5e3Sopenharmony_ci
654514f5e3Sopenharmony_ciWorkManager::~WorkManager()
664514f5e3Sopenharmony_ci{
674514f5e3Sopenharmony_ci    Finish();
684514f5e3Sopenharmony_ci    for (uint32_t i = 0; i < threadNum_; i++) {
694514f5e3Sopenharmony_ci        continuousQueue_.at(i)->Destroy();
704514f5e3Sopenharmony_ci        delete continuousQueue_.at(i);
714514f5e3Sopenharmony_ci        continuousQueue_.at(i) = nullptr;
724514f5e3Sopenharmony_ci    }
734514f5e3Sopenharmony_ci}
744514f5e3Sopenharmony_ci
754514f5e3Sopenharmony_cibool WorkManager::Push(uint32_t threadId, TaggedObject *object)
764514f5e3Sopenharmony_ci{
774514f5e3Sopenharmony_ci    WorkNode *&inNode = works_.at(threadId).inNode_;
784514f5e3Sopenharmony_ci    if (!inNode->PushObject(ToUintPtr(object))) {
794514f5e3Sopenharmony_ci        PushWorkNodeToGlobal(threadId);
804514f5e3Sopenharmony_ci        return inNode->PushObject(ToUintPtr(object));
814514f5e3Sopenharmony_ci    }
824514f5e3Sopenharmony_ci    return true;
834514f5e3Sopenharmony_ci}
844514f5e3Sopenharmony_ci
854514f5e3Sopenharmony_civoid WorkManager::PushWorkNodeToGlobal(uint32_t threadId, bool postTask)
864514f5e3Sopenharmony_ci{
874514f5e3Sopenharmony_ci    WorkNode *&inNode = works_.at(threadId).inNode_;
884514f5e3Sopenharmony_ci    if (!inNode->IsEmpty()) {
894514f5e3Sopenharmony_ci        workStack_.Push(inNode);
904514f5e3Sopenharmony_ci        inNode = AllocateWorkNode();
914514f5e3Sopenharmony_ci        if (postTask && heap_->IsParallelGCEnabled() && heap_->CheckCanDistributeTask() &&
924514f5e3Sopenharmony_ci            !(heap_->IsMarking() && heap_->GetIncrementalMarker()->IsTriggeredIncrementalMark())) {
934514f5e3Sopenharmony_ci            heap_->PostParallelGCTask(parallelGCTaskPhase_);
944514f5e3Sopenharmony_ci        }
954514f5e3Sopenharmony_ci    }
964514f5e3Sopenharmony_ci}
974514f5e3Sopenharmony_ci
984514f5e3Sopenharmony_cibool WorkManager::Pop(uint32_t threadId, TaggedObject **object)
994514f5e3Sopenharmony_ci{
1004514f5e3Sopenharmony_ci    WorkNode *&outNode = works_.at(threadId).outNode_;
1014514f5e3Sopenharmony_ci    WorkNode *&inNode = works_.at(threadId).inNode_;
1024514f5e3Sopenharmony_ci    if (!outNode->PopObject(reinterpret_cast<uintptr_t *>(object))) {
1034514f5e3Sopenharmony_ci        if (!inNode->IsEmpty()) {
1044514f5e3Sopenharmony_ci            WorkNode *tmp = outNode;
1054514f5e3Sopenharmony_ci            outNode = inNode;
1064514f5e3Sopenharmony_ci            inNode = tmp;
1074514f5e3Sopenharmony_ci        } else if (!PopWorkNodeFromGlobal(threadId)) {
1084514f5e3Sopenharmony_ci            return false;
1094514f5e3Sopenharmony_ci        }
1104514f5e3Sopenharmony_ci        return outNode->PopObject(reinterpret_cast<uintptr_t *>(object));
1114514f5e3Sopenharmony_ci    }
1124514f5e3Sopenharmony_ci    return true;
1134514f5e3Sopenharmony_ci}
1144514f5e3Sopenharmony_ci
1154514f5e3Sopenharmony_cibool WorkManager::PopWorkNodeFromGlobal(uint32_t threadId)
1164514f5e3Sopenharmony_ci{
1174514f5e3Sopenharmony_ci    return workStack_.Pop(&works_.at(threadId).outNode_);
1184514f5e3Sopenharmony_ci}
1194514f5e3Sopenharmony_ci
1204514f5e3Sopenharmony_cisize_t WorkManager::Finish()
1214514f5e3Sopenharmony_ci{
1224514f5e3Sopenharmony_ci    size_t aliveSize = 0;
1234514f5e3Sopenharmony_ci    for (uint32_t i = 0; i < threadNum_; i++) {
1244514f5e3Sopenharmony_ci        WorkNodeHolder &holder = works_.at(i);
1254514f5e3Sopenharmony_ci        if (holder.weakQueue_ != nullptr) {
1264514f5e3Sopenharmony_ci            holder.weakQueue_->FinishMarking(continuousQueue_.at(i));
1274514f5e3Sopenharmony_ci            delete holder.weakQueue_;
1284514f5e3Sopenharmony_ci            holder.weakQueue_ = nullptr;
1294514f5e3Sopenharmony_ci        }
1304514f5e3Sopenharmony_ci        if (holder.allocator_ != nullptr) {
1314514f5e3Sopenharmony_ci            holder.allocator_->Finalize();
1324514f5e3Sopenharmony_ci            delete holder.allocator_;
1334514f5e3Sopenharmony_ci            holder.allocator_ = nullptr;
1344514f5e3Sopenharmony_ci        }
1354514f5e3Sopenharmony_ci        holder.pendingUpdateSlots_.clear();
1364514f5e3Sopenharmony_ci        aliveSize += holder.aliveSize_;
1374514f5e3Sopenharmony_ci    }
1384514f5e3Sopenharmony_ci    FinishBase();
1394514f5e3Sopenharmony_ci    initialized_.store(false, std::memory_order_release);
1404514f5e3Sopenharmony_ci    return aliveSize;
1414514f5e3Sopenharmony_ci}
1424514f5e3Sopenharmony_ci
1434514f5e3Sopenharmony_civoid WorkManager::Finish(size_t &aliveSize, size_t &promotedSize)
1444514f5e3Sopenharmony_ci{
1454514f5e3Sopenharmony_ci    aliveSize = Finish();
1464514f5e3Sopenharmony_ci    for (uint32_t i = 0; i < threadNum_; i++) {
1474514f5e3Sopenharmony_ci        WorkNodeHolder &holder = works_.at(i);
1484514f5e3Sopenharmony_ci        promotedSize += holder.promotedSize_;
1494514f5e3Sopenharmony_ci        if (holder.allocator_ != nullptr) {
1504514f5e3Sopenharmony_ci            holder.allocator_->Finalize();
1514514f5e3Sopenharmony_ci            delete holder.allocator_;
1524514f5e3Sopenharmony_ci            holder.allocator_ = nullptr;
1534514f5e3Sopenharmony_ci        }
1544514f5e3Sopenharmony_ci    }
1554514f5e3Sopenharmony_ci    initialized_.store(false, std::memory_order_release);
1564514f5e3Sopenharmony_ci}
1574514f5e3Sopenharmony_ci
1584514f5e3Sopenharmony_civoid WorkManager::Initialize(TriggerGCType gcType, ParallelGCTaskPhase taskPhase)
1594514f5e3Sopenharmony_ci{
1604514f5e3Sopenharmony_ci    parallelGCTaskPhase_ = taskPhase;
1614514f5e3Sopenharmony_ci    InitializeBase();
1624514f5e3Sopenharmony_ci    for (uint32_t i = 0; i < threadNum_; i++) {
1634514f5e3Sopenharmony_ci        WorkNodeHolder &holder = works_.at(i);
1644514f5e3Sopenharmony_ci        holder.inNode_ = AllocateWorkNode();
1654514f5e3Sopenharmony_ci        holder.outNode_ = AllocateWorkNode();
1664514f5e3Sopenharmony_ci        holder.weakQueue_ = new ProcessQueue();
1674514f5e3Sopenharmony_ci        holder.weakQueue_->BeginMarking(continuousQueue_.at(i));
1684514f5e3Sopenharmony_ci        holder.aliveSize_ = 0;
1694514f5e3Sopenharmony_ci        holder.promotedSize_ = 0;
1704514f5e3Sopenharmony_ci        if (gcType != TriggerGCType::OLD_GC) {
1714514f5e3Sopenharmony_ci            holder.allocator_ = new TlabAllocator(heap_);
1724514f5e3Sopenharmony_ci        }
1734514f5e3Sopenharmony_ci    }
1744514f5e3Sopenharmony_ci    if (initialized_.load(std::memory_order_acquire)) { // LOCV_EXCL_BR_LINE
1754514f5e3Sopenharmony_ci        LOG_ECMA(FATAL) << "this branch is unreachable";
1764514f5e3Sopenharmony_ci        UNREACHABLE();
1774514f5e3Sopenharmony_ci    }
1784514f5e3Sopenharmony_ci    initialized_.store(true, std::memory_order_release);
1794514f5e3Sopenharmony_ci}
1804514f5e3Sopenharmony_ci
1814514f5e3Sopenharmony_ciSharedGCWorkManager::SharedGCWorkManager(SharedHeap *heap, uint32_t threadNum)
1824514f5e3Sopenharmony_ci    : WorkManagerBase(heap->GetNativeAreaAllocator()), sHeap_(heap), threadNum_(threadNum),
1834514f5e3Sopenharmony_ci      continuousQueue_ { nullptr }, sharedTaskPhase_(SHARED_UNDEFINED_TASK)
1844514f5e3Sopenharmony_ci{
1854514f5e3Sopenharmony_ci    for (uint32_t i = 0; i < threadNum_; i++) {
1864514f5e3Sopenharmony_ci        continuousQueue_.at(i) = new ProcessQueue();
1874514f5e3Sopenharmony_ci    }
1884514f5e3Sopenharmony_ci}
1894514f5e3Sopenharmony_ci
1904514f5e3Sopenharmony_ciSharedGCWorkManager::~SharedGCWorkManager()
1914514f5e3Sopenharmony_ci{
1924514f5e3Sopenharmony_ci    Finish();
1934514f5e3Sopenharmony_ci    for (uint32_t i = 0; i < threadNum_; i++) {
1944514f5e3Sopenharmony_ci        continuousQueue_.at(i)->Destroy();
1954514f5e3Sopenharmony_ci        delete continuousQueue_.at(i);
1964514f5e3Sopenharmony_ci        continuousQueue_.at(i) = nullptr;
1974514f5e3Sopenharmony_ci    }
1984514f5e3Sopenharmony_ci}
1994514f5e3Sopenharmony_ci
2004514f5e3Sopenharmony_civoid SharedGCWorkManager::Initialize(TriggerGCType gcType, SharedParallelMarkPhase taskPhase)
2014514f5e3Sopenharmony_ci{
2024514f5e3Sopenharmony_ci    sharedTaskPhase_ = taskPhase;
2034514f5e3Sopenharmony_ci    InitializeBase();
2044514f5e3Sopenharmony_ci    for (uint32_t i = 0; i < threadNum_; i++) {
2054514f5e3Sopenharmony_ci        SharedGCWorkNodeHolder &holder = works_.at(i);
2064514f5e3Sopenharmony_ci        holder.inNode_ = AllocateWorkNode();
2074514f5e3Sopenharmony_ci        holder.outNode_ = AllocateWorkNode();
2084514f5e3Sopenharmony_ci        holder.weakQueue_ = new ProcessQueue();
2094514f5e3Sopenharmony_ci        holder.weakQueue_->BeginMarking(continuousQueue_.at(i));
2104514f5e3Sopenharmony_ci        if (gcType == TriggerGCType::SHARED_FULL_GC) {
2114514f5e3Sopenharmony_ci            holder.allocator_ = new SharedTlabAllocator(sHeap_);
2124514f5e3Sopenharmony_ci        }
2134514f5e3Sopenharmony_ci    }
2144514f5e3Sopenharmony_ci    if (initialized_.load(std::memory_order_acquire)) { // LOCV_EXCL_BR_LINE
2154514f5e3Sopenharmony_ci        LOG_ECMA(FATAL) << "this branch is unreachable";
2164514f5e3Sopenharmony_ci        UNREACHABLE();
2174514f5e3Sopenharmony_ci    }
2184514f5e3Sopenharmony_ci    initialized_.store(true, std::memory_order_release);
2194514f5e3Sopenharmony_ci}
2204514f5e3Sopenharmony_ci
2214514f5e3Sopenharmony_cisize_t SharedGCWorkManager::Finish()
2224514f5e3Sopenharmony_ci{
2234514f5e3Sopenharmony_ci    size_t aliveSize = 0;
2244514f5e3Sopenharmony_ci    for (uint32_t i = 0; i < threadNum_; i++) {
2254514f5e3Sopenharmony_ci        SharedGCWorkNodeHolder &holder = works_.at(i);
2264514f5e3Sopenharmony_ci        if (holder.weakQueue_ != nullptr) {
2274514f5e3Sopenharmony_ci            holder.weakQueue_->FinishMarking(continuousQueue_.at(i));
2284514f5e3Sopenharmony_ci            delete holder.weakQueue_;
2294514f5e3Sopenharmony_ci            holder.weakQueue_ = nullptr;
2304514f5e3Sopenharmony_ci        }
2314514f5e3Sopenharmony_ci        aliveSize += holder.aliveSize_;
2324514f5e3Sopenharmony_ci        if (holder.allocator_ != nullptr) {
2334514f5e3Sopenharmony_ci            holder.allocator_->Finalize();
2344514f5e3Sopenharmony_ci            delete holder.allocator_;
2354514f5e3Sopenharmony_ci            holder.allocator_ = nullptr;
2364514f5e3Sopenharmony_ci        }
2374514f5e3Sopenharmony_ci    }
2384514f5e3Sopenharmony_ci    FinishBase();
2394514f5e3Sopenharmony_ci    initialized_.store(false, std::memory_order_release);
2404514f5e3Sopenharmony_ci    return aliveSize;
2414514f5e3Sopenharmony_ci}
2424514f5e3Sopenharmony_ci
2434514f5e3Sopenharmony_cibool SharedGCWorkManager::Push(uint32_t threadId, TaggedObject *object)
2444514f5e3Sopenharmony_ci{
2454514f5e3Sopenharmony_ci    WorkNode *&inNode = works_.at(threadId).inNode_;
2464514f5e3Sopenharmony_ci    if (!inNode->PushObject(ToUintPtr(object))) {
2474514f5e3Sopenharmony_ci        PushWorkNodeToGlobal(threadId);
2484514f5e3Sopenharmony_ci        return inNode->PushObject(ToUintPtr(object));
2494514f5e3Sopenharmony_ci    }
2504514f5e3Sopenharmony_ci    return true;
2514514f5e3Sopenharmony_ci}
2524514f5e3Sopenharmony_ci
2534514f5e3Sopenharmony_cibool SharedGCWorkManager::PushToLocalMarkingBuffer(WorkNode *&markingBuffer, TaggedObject *object)
2544514f5e3Sopenharmony_ci{
2554514f5e3Sopenharmony_ci    if (UNLIKELY(markingBuffer == nullptr)) {
2564514f5e3Sopenharmony_ci        markingBuffer = AllocateWorkNode();
2574514f5e3Sopenharmony_ci    }
2584514f5e3Sopenharmony_ci    ASSERT(markingBuffer != nullptr);
2594514f5e3Sopenharmony_ci    if (UNLIKELY(!markingBuffer->PushObject(ToUintPtr(object)))) {
2604514f5e3Sopenharmony_ci        PushLocalBufferToGlobal(markingBuffer);
2614514f5e3Sopenharmony_ci        ASSERT(markingBuffer == nullptr);
2624514f5e3Sopenharmony_ci        markingBuffer = AllocateWorkNode();
2634514f5e3Sopenharmony_ci        return markingBuffer->PushObject(ToUintPtr(object));
2644514f5e3Sopenharmony_ci    }
2654514f5e3Sopenharmony_ci    return true;
2664514f5e3Sopenharmony_ci}
2674514f5e3Sopenharmony_ci
2684514f5e3Sopenharmony_civoid SharedGCWorkManager::PushWorkNodeToGlobal(uint32_t threadId, bool postTask)
2694514f5e3Sopenharmony_ci{
2704514f5e3Sopenharmony_ci    WorkNode *&inNode = works_.at(threadId).inNode_;
2714514f5e3Sopenharmony_ci    if (!inNode->IsEmpty()) {
2724514f5e3Sopenharmony_ci        workStack_.Push(inNode);
2734514f5e3Sopenharmony_ci        inNode = AllocateWorkNode();
2744514f5e3Sopenharmony_ci        if (postTask && sHeap_->IsParallelGCEnabled() && sHeap_->CheckCanDistributeTask()) {
2754514f5e3Sopenharmony_ci            sHeap_->PostGCMarkingTask(sharedTaskPhase_);
2764514f5e3Sopenharmony_ci        }
2774514f5e3Sopenharmony_ci    }
2784514f5e3Sopenharmony_ci}
2794514f5e3Sopenharmony_ci
2804514f5e3Sopenharmony_civoid SharedGCWorkManager::PushLocalBufferToGlobal(WorkNode *&node, bool postTask)
2814514f5e3Sopenharmony_ci{
2824514f5e3Sopenharmony_ci    ASSERT(node != nullptr);
2834514f5e3Sopenharmony_ci    ASSERT(!node->IsEmpty());
2844514f5e3Sopenharmony_ci    workStack_.Push(node);
2854514f5e3Sopenharmony_ci    if (postTask && sHeap_->IsParallelGCEnabled() && sHeap_->CheckCanDistributeTask()) {
2864514f5e3Sopenharmony_ci        sHeap_->PostGCMarkingTask(sharedTaskPhase_);
2874514f5e3Sopenharmony_ci    }
2884514f5e3Sopenharmony_ci    node = nullptr;
2894514f5e3Sopenharmony_ci}
2904514f5e3Sopenharmony_ci
2914514f5e3Sopenharmony_cibool SharedGCWorkManager::Pop(uint32_t threadId, TaggedObject **object)
2924514f5e3Sopenharmony_ci{
2934514f5e3Sopenharmony_ci    WorkNode *&outNode = works_.at(threadId).outNode_;
2944514f5e3Sopenharmony_ci    WorkNode *&inNode = works_.at(threadId).inNode_;
2954514f5e3Sopenharmony_ci    if (!outNode->PopObject(reinterpret_cast<uintptr_t *>(object))) {
2964514f5e3Sopenharmony_ci        if (!inNode->IsEmpty()) {
2974514f5e3Sopenharmony_ci            WorkNode *tmp = outNode;
2984514f5e3Sopenharmony_ci            outNode = inNode;
2994514f5e3Sopenharmony_ci            inNode = tmp;
3004514f5e3Sopenharmony_ci        } else if (!PopWorkNodeFromGlobal(threadId)) {
3014514f5e3Sopenharmony_ci            return false;
3024514f5e3Sopenharmony_ci        }
3034514f5e3Sopenharmony_ci        return outNode->PopObject(reinterpret_cast<uintptr_t *>(object));
3044514f5e3Sopenharmony_ci    }
3054514f5e3Sopenharmony_ci    return true;
3064514f5e3Sopenharmony_ci}
3074514f5e3Sopenharmony_ci
3084514f5e3Sopenharmony_cibool SharedGCWorkManager::PopWorkNodeFromGlobal(uint32_t threadId)
3094514f5e3Sopenharmony_ci{
3104514f5e3Sopenharmony_ci    return workStack_.Pop(&works_.at(threadId).outNode_);
3114514f5e3Sopenharmony_ci}
3124514f5e3Sopenharmony_ci}  // namespace panda::ecmascript
313