e7f91ca0创建于 2025年5月21日历史提交
/*

 * Copyright (c) 2022 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_COMPILER_BUILTINS_CONTAINERS_STUB_BUILDER_H

#define ECMASCRIPT_COMPILER_BUILTINS_CONTAINERS_STUB_BUILDER_H

#include "ecmascript/compiler/builtins/builtins_stubs.h"

#include "ecmascript/compiler/stub_builder-inl.h"

#include "ecmascript/js_api/js_api_arraylist.h"

#include "ecmascript/js_api/js_api_hashmap.h"

#include "ecmascript/js_api/js_api_hashset.h"

#include "ecmascript/js_api/js_api_lightweightmap.h"

#include "ecmascript/js_api/js_api_lightweightset.h"

#include "ecmascript/js_api/js_api_linked_list.h"

#include "ecmascript/js_api/js_api_list.h"

#include "ecmascript/js_api/js_api_plain_array.h"

#include "ecmascript/js_api/js_api_stack.h"

#include "ecmascript/js_api/js_api_vector.h"



namespace panda::ecmascript::kungfu {

// enumerate container functions that use function call

enum class ContainersType : uint8_t {

    VECTOR_FOREACH = 0,

    VECTOR_REPLACEALLELEMENTS,

    STACK_FOREACH,

    PLAINARRAY_FOREACH,

    QUEUE_FOREACH,

    DEQUE_FOREACH,

    LIGHTWEIGHTMAP_FOREACH,

    LIGHTWEIGHTSET_FOREACH,

    HASHMAP_FOREACH,

    HASHSET_FOREACH,

    LINKEDLIST_FOREACH,

    LIST_FOREACH,

    ARRAYLIST_FOREACH,

    ARRAYLIST_REPLACEALLELEMENTS,

};



class ContainersCommonStubBuilder : public BuiltinsStubBuilder {

public:

    explicit ContainersCommonStubBuilder(StubBuilder *parent, GateRef globalEnv)

        : BuiltinsStubBuilder(parent, globalEnv) {}

    ~ContainersCommonStubBuilder() override = default;

    NO_MOVE_SEMANTIC(ContainersCommonStubBuilder);

    NO_COPY_SEMANTIC(ContainersCommonStubBuilder);

    void GenerateCircuit() override {}



    void ContainersCommonFuncCall(GateRef glue, GateRef thisValue, GateRef numArgs,

        Variable* result, Label *exit, Label *slowPath, ContainersType type);



    void ContainersLightWeightCall(GateRef glue, GateRef thisValue, GateRef numArgs,

        Variable* result, Label *exit, Label *slowPath, ContainersType type);



    void ContainersHashCall(GateRef glue, GateRef thisValue, GateRef numArgs,

        Variable* result, Label *exit, Label *slowPath, ContainersType type);



    void ContainersLinkedListCall(GateRef glue, GateRef thisValue, GateRef numArgs,

        Variable* result, Label *exit, Label *slowPath, ContainersType type);



    GateRef IsContainer(GateRef glue, GateRef obj, ContainersType type)

    {

        switch (type) {

            case ContainersType::VECTOR_FOREACH:

            case ContainersType::VECTOR_REPLACEALLELEMENTS:

                return IsJSAPIVector(glue, obj);

            case ContainersType::STACK_FOREACH:

                return IsJSAPIStack(glue, obj);

            case ContainersType::PLAINARRAY_FOREACH:

                return IsJSAPIPlainArray(glue, obj);

            case ContainersType::QUEUE_FOREACH:

                return IsJSAPIQueue(glue, obj);

            case ContainersType::DEQUE_FOREACH:

                return IsJSAPIDeque(glue, obj);

            case ContainersType::LIGHTWEIGHTMAP_FOREACH:

                return IsJSAPILightWeightMap(glue, obj);

            case ContainersType::LIGHTWEIGHTSET_FOREACH:

                return IsJSAPILightWeightSet(glue, obj);

            case ContainersType::HASHMAP_FOREACH:

                return IsJSAPIHashMap(glue, obj);

            case ContainersType::HASHSET_FOREACH:

                return IsJSAPIHashSet(glue, obj);

            case ContainersType::LINKEDLIST_FOREACH:

                return IsJSAPILinkedList(glue, obj);

            case ContainersType::LIST_FOREACH:

                return IsJSAPIList(glue, obj);

            case ContainersType::ARRAYLIST_FOREACH:

            case ContainersType::ARRAYLIST_REPLACEALLELEMENTS:

                return IsJSAPIArrayList(glue, obj);

            default:

                LOG_ECMA(FATAL) << "this branch is unreachable";

                UNREACHABLE();

        }

        return False();

    }



    bool IsReplaceAllElements(ContainersType type)

    {

        switch (type) {

            case ContainersType::STACK_FOREACH:

            case ContainersType::VECTOR_FOREACH:

            case ContainersType::PLAINARRAY_FOREACH:

            case ContainersType::QUEUE_FOREACH:

            case ContainersType::DEQUE_FOREACH:

            case ContainersType::ARRAYLIST_FOREACH:

                return false;

            case ContainersType::VECTOR_REPLACEALLELEMENTS:

            case ContainersType::ARRAYLIST_REPLACEALLELEMENTS:

                return true;

            default:

                LOG_ECMA(FATAL) << "this branch is unreachable";

                UNREACHABLE();

        }

        return false;

    }



    bool IsPlainArray(ContainersType type)

    {

        switch (type) {

            case ContainersType::STACK_FOREACH:

            case ContainersType::VECTOR_FOREACH:

            case ContainersType::VECTOR_REPLACEALLELEMENTS:

            case ContainersType::QUEUE_FOREACH:

            case ContainersType::DEQUE_FOREACH:

            case ContainersType::ARRAYLIST_FOREACH:

            case ContainersType::ARRAYLIST_REPLACEALLELEMENTS:

                return false;

            case ContainersType::PLAINARRAY_FOREACH:

                return true;

            default:

                LOG_ECMA(FATAL) << "this branch is unreachable";

                UNREACHABLE();

        }

        return false;

    }



    bool IsArrayListReplaceAllelements(ContainersType type)

    {

        switch (type) {

            case ContainersType::STACK_FOREACH:

            case ContainersType::VECTOR_FOREACH:

            case ContainersType::VECTOR_REPLACEALLELEMENTS:

            case ContainersType::QUEUE_FOREACH:

            case ContainersType::DEQUE_FOREACH:

            case ContainersType::ARRAYLIST_FOREACH:

            case ContainersType::PLAINARRAY_FOREACH:

                return false;

            case ContainersType::ARRAYLIST_REPLACEALLELEMENTS:

                return true;

            default:

                LOG_ECMA(FATAL) << "this branch is unreachable";

                UNREACHABLE();

        }

        return false;

    }



    GateRef ContainerGetSize(GateRef glue, GateRef obj, ContainersType type)

    {

        switch (type) {

            case ContainersType::VECTOR_FOREACH:

            case ContainersType::VECTOR_REPLACEALLELEMENTS: {

                return LoadPrimitive(VariableType::INT32(), obj, IntPtr(JSAPIVector::ELEMENT_COUNT_OFFSET));

            }

            case ContainersType::STACK_FOREACH: {

                GateRef top = LoadPrimitive(VariableType::INT32(), obj, IntPtr(JSAPIStack::TOP_OFFSET));

                return Int32Add(top, Int32(1));

            }

            case ContainersType::PLAINARRAY_FOREACH: {

                return LoadPrimitive(VariableType::INT32(), obj, IntPtr(JSAPIPlainArray::LENGTH_OFFSET));

            }

            case ContainersType::ARRAYLIST_REPLACEALLELEMENTS:

            case ContainersType::ARRAYLIST_FOREACH: {

                GateRef len = Load(VariableType::JS_ANY(), glue, obj, IntPtr(JSAPIArrayList::LENGTH_OFFSET));

                return TaggedGetInt(len);

            }

            case ContainersType::LIGHTWEIGHTSET_FOREACH: {

                return LoadPrimitive(VariableType::INT32(), obj, IntPtr(JSAPILightWeightSet::LENGTH_OFFSET));

            }

            case ContainersType::LIGHTWEIGHTMAP_FOREACH: {

                return LoadPrimitive(VariableType::INT32(), obj, IntPtr(JSAPILightWeightMap::LWP_LENGTH_OFFSET));

            }

            case ContainersType::HASHMAP_FOREACH: {

                GateRef tableOffset = IntPtr(JSAPIHashMap::HASHMAP_TABLE_INDEX);

                GateRef table = Load(VariableType::JS_POINTER(), glue, obj, tableOffset);

                return GetLengthOfTaggedArray(table);

            }

            case ContainersType::HASHSET_FOREACH: {

                GateRef tableOffset = IntPtr(JSAPIHashSet::HASHSET_TABLE_INDEX);

                GateRef table = Load(VariableType::JS_POINTER(), glue, obj, tableOffset);

                return GetLengthOfTaggedArray(table);

            }

            case ContainersType::LINKEDLIST_FOREACH: {

                GateRef tableOffset = IntPtr(JSAPILinkedList::DOUBLE_LIST_OFFSET);

                GateRef table = Load(VariableType::JS_POINTER(), glue, obj, tableOffset);

                GateRef value = GetValueFromTaggedArray(glue, table, Int32(TaggedDoubleList::NUMBER_OF_NODE_INDEX));

                return TaggedGetInt(value);

            }

            case ContainersType::LIST_FOREACH: {

                GateRef tableOffset = IntPtr(JSAPIList::SINGLY_LIST_OFFSET);

                GateRef table = Load(VariableType::JS_POINTER(), glue, obj, tableOffset);

                GateRef value = GetValueFromTaggedArray(glue, table, Int32(TaggedSingleList::NUMBER_OF_NODE_INDEX));

                return TaggedGetInt(value);

            }

            default:

                LOG_ECMA(FATAL) << "this branch is unreachable";

                UNREACHABLE();

        }

        return False();

    }



    GateRef ContainerGetValue(GateRef glue, GateRef obj, GateRef index, ContainersType type)

    {

        switch (type) {

            case ContainersType::VECTOR_FOREACH:

            case ContainersType::VECTOR_REPLACEALLELEMENTS: {

                GateRef elementsOffset = IntPtr(JSObject::ELEMENTS_OFFSET);

                GateRef elements = Load(VariableType::JS_POINTER(), glue, obj, elementsOffset);

                return GetValueFromTaggedArray(glue, elements, index);

            }

            case ContainersType::STACK_FOREACH: {

                GateRef elementsOffset = IntPtr(JSObject::ELEMENTS_OFFSET);

                GateRef elements = Load(VariableType::JS_POINTER(), glue, obj, elementsOffset);

                return GetValueFromTaggedArray(glue, elements, index);

            }

            case ContainersType::PLAINARRAY_FOREACH: {

                GateRef elementsOffset = IntPtr(JSAPIPlainArray::VALUES_OFFSET);

                GateRef elements = Load(VariableType::JS_POINTER(), glue, obj, elementsOffset);

                return GetValueFromTaggedArray(glue, elements, index);

            }

            case ContainersType::ARRAYLIST_REPLACEALLELEMENTS:

            case ContainersType::ARRAYLIST_FOREACH: {

                GateRef elementsOffset = IntPtr(JSObject::ELEMENTS_OFFSET);

                GateRef elements = Load(VariableType::JS_POINTER(), glue, obj, elementsOffset);

                return GetValueFromTaggedArray(glue, elements, index);

            }

            case ContainersType::LIGHTWEIGHTSET_FOREACH: {

                GateRef valuesOffset = IntPtr(JSAPILightWeightSet::VALUES_OFFSET);

                GateRef values = Load(VariableType::JS_POINTER(), glue, obj, valuesOffset);

                return GetValueFromTaggedArray(glue, values, index);

            }

            case ContainersType::LIGHTWEIGHTMAP_FOREACH: {

                GateRef valuesOffset = IntPtr(JSAPILightWeightMap::LWP_VALUES_OFFSET);

                GateRef values = Load(VariableType::JS_POINTER(), glue, obj, valuesOffset);

                return GetValueFromTaggedArray(glue, values, index);

            }

            default:

                LOG_ECMA(FATAL) << "this branch is unreachable";

                UNREACHABLE();

        }

        return False();

    }



    GateRef ContainerGetKey(GateRef glue, GateRef obj, GateRef index, ContainersType type)

    {

        switch (type) {

            case ContainersType::LIGHTWEIGHTMAP_FOREACH: {

                GateRef keysOffset = IntPtr(JSAPILightWeightMap::LWP_KEYS_OFFSET);

                GateRef keys = Load(VariableType::JS_POINTER(), glue, obj, keysOffset);

                return GetValueFromTaggedArray(glue, keys, index);

            }

            case ContainersType::LIGHTWEIGHTSET_FOREACH: {

                GateRef valuesOffset = IntPtr(JSAPILightWeightSet::VALUES_OFFSET);

                GateRef values = Load(VariableType::JS_POINTER(), glue, obj, valuesOffset);

                return GetValueFromTaggedArray(glue, values, index);

            }

            default:

                LOG_ECMA(FATAL) << "this branch is unreachable";

                UNREACHABLE();

        }

        return False();

    }



    GateRef ContainerGetNode(GateRef glue, GateRef obj, GateRef index, ContainersType type)

    {

        switch (type) {

            case ContainersType::HASHMAP_FOREACH: {

                GateRef tableOffset = IntPtr(JSAPIHashMap::HASHMAP_TABLE_INDEX);

                GateRef table = Load(VariableType::JS_POINTER(), glue, obj, tableOffset);

                return GetValueFromTaggedArray(glue, table, index);

            }

            case ContainersType::HASHSET_FOREACH: {

                GateRef tableOffset = IntPtr(JSAPIHashSet::HASHSET_TABLE_INDEX);

                GateRef table = Load(VariableType::JS_POINTER(), glue, obj, tableOffset);

                return GetValueFromTaggedArray(glue, table, index);

            }

            case ContainersType::LINKEDLIST_FOREACH: {

                GateRef tableOffset = IntPtr(JSAPILinkedList::DOUBLE_LIST_OFFSET);

                GateRef table = Load(VariableType::JS_POINTER(), glue, obj, tableOffset);

                return GetValueFromTaggedArray(glue, table, index);

            }

            case ContainersType::LIST_FOREACH: {

                GateRef tableOffset = IntPtr(JSAPIList::SINGLY_LIST_OFFSET);

                GateRef table = Load(VariableType::JS_POINTER(), glue, obj, tableOffset);

                return GetValueFromTaggedArray(glue, table, index);

            }

            default:

                LOG_ECMA(FATAL) << "this branch is unreachable";

                UNREACHABLE();

        }

        return False();

    }



    GateRef PlainArrayGetKey(GateRef glue, GateRef obj, GateRef index)

    {

        GateRef elementsOffset = IntPtr(JSAPIPlainArray::KEYS_OFFSET);

        GateRef elements = Load(VariableType::JS_POINTER(), glue, obj, elementsOffset);

        return GetValueFromTaggedArray(glue, elements, index);

    }

};

}  // namespace panda::ecmascript::kungfu

#endif  // ECMASCRIPT_COMPILER_BUILTINS_CONTAINERS_STUB_BUILDER_H