* Copyright (c) 2026 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/compiler/builtins/builtins_shared_map_stub_builder.h"
#include "ecmascript/compiler/builtins/linked_hashtable_stub_builder.h"
#include "ecmascript/compiler/new_object_stub_builder.h"
#include "ecmascript/js_iterator.h"
#include "ecmascript/linked_hash_table.h"
#include "ecmascript/shared_objects/js_shared_map.h"
namespace panda::ecmascript::kungfu {
void BuiltinsSharedMapStubBuilder::Keys(GateRef glue, GateRef thisValue,
GateRef numArgs, Variable *result, Label *exit, Label *slowPath)
{
auto env = GetEnvironment();
Label isSharedMap(env);
BRANCH(IsJSObjectType(glue, thisValue, JSType::JS_SHARED_MAP), &isSharedMap, slowPath);
Bind(&isSharedMap);
{
NewObjectStubBuilder newBuilder(this);
newBuilder.SetParameters(glue, IntPtr(JSSharedMapIterator::SIZE));
GateRef kind = Int32(static_cast<int32_t>(IterationKind::KEY));
newBuilder.CreateJSSharedMapIterator(result, exit, thisValue, kind);
}
}
void BuiltinsSharedMapStubBuilder::Values(GateRef glue, GateRef thisValue,
GateRef numArgs, Variable *result, Label *exit, Label *slowPath)
{
auto env = GetEnvironment();
Label isSharedMap(env);
BRANCH(IsJSObjectType(glue, thisValue, JSType::JS_SHARED_MAP), &isSharedMap, slowPath);
Bind(&isSharedMap);
{
NewObjectStubBuilder newBuilder(this);
newBuilder.SetParameters(glue, IntPtr(JSSharedMapIterator::SIZE));
GateRef kind = Int32(static_cast<int32_t>(IterationKind::VALUE));
newBuilder.CreateJSSharedMapIterator(result, exit, thisValue, kind);
}
}
void BuiltinsSharedMapStubBuilder::Set(GateRef glue, GateRef thisValue,
GateRef numArgs, Variable *result, Label *exit, Label *slowPath)
{
auto env = GetEnvironment();
Label isSharedMap(env);
BRANCH(IsJSObjectType(glue, thisValue, JSType::JS_SHARED_MAP), &isSharedMap, slowPath);
Bind(&isSharedMap);
GateRef key = GetCallArg0(numArgs);
GateRef value = GetCallArg1(numArgs);
Label keyIsSharedType(env);
Label valueIsSharedType(env);
BRANCH(TaggedIsSharedType(glue, key), &keyIsSharedType, slowPath);
Bind(&keyIsSharedType);
BRANCH(TaggedIsSharedType(glue, value), &valueIsSharedType, slowPath);
Bind(&valueIsSharedType);
SetImpl(glue, thisValue, key, value);
*result = thisValue;
Jump(exit);
}
void BuiltinsSharedMapStubBuilder::SetImpl(GateRef glue, GateRef thisValue, GateRef key, GateRef value)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label canWriteExit(env);
Label writeDoneExit(env);
Label exit(env);
Label hasScopeException(env);
Label notScopeException(env);
DEFVARIABLE(scopeEntered, VariableType::BOOL(), False());
ASM_ASSERT(GET_MESSAGE_STRING_ID(SharedMapSet), TaggedIsSharedType(glue, key));
ASM_ASSERT(GET_MESSAGE_STRING_ID(SharedMapSet), TaggedIsSharedType(glue, value));
ConcurrentApiScopeCanWrite<JSSharedMap>(glue, thisValue, scopeEntered, &canWriteExit);
Bind(&canWriteExit);
BRANCH(HasPendingException(glue), &hasScopeException, ¬ScopeException);
Bind(&hasScopeException);
{
Jump(&exit);
}
Bind(¬ScopeException);
{
GateRef linkedMapOffset = IntPtr(JSSharedMap::LINKED_MAP_OFFSET);
GateRef linkedTable = Load(VariableType::JS_ANY(), glue, thisValue, linkedMapOffset);
LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject> linkedHashTableStubBuilder(
this, glue, GetCurrentGlobalEnv(), true);
GateRef newTable = linkedHashTableStubBuilder.Insert(linkedTable, key, value);
Store(VariableType::JS_ANY(), glue, thisValue, linkedMapOffset, newTable);
Jump(&exit);
}
Bind(&exit);
ConcurrentApiScopeWriteDone<JSSharedMap>(glue, thisValue, scopeEntered, &writeDoneExit);
Bind(&writeDoneExit);
env->SubCfgExit();
}
void BuiltinsSharedMapStubBuilder::Get(GateRef glue, GateRef thisValue,
GateRef numArgs, Variable *result, Label *exit, Label *slowPath)
{
auto env = GetEnvironment();
Label isSharedMap(env);
BRANCH(IsJSObjectType(glue, thisValue, JSType::JS_SHARED_MAP), &isSharedMap, slowPath);
Bind(&isSharedMap);
GateRef key = GetCallArg0(numArgs);
GateRef value = GetImpl(glue, thisValue, key);
*result = value;
Jump(exit);
}
GateRef BuiltinsSharedMapStubBuilder::GetImpl(GateRef glue, GateRef thisValue, GateRef key)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
Label exit(env);
Label hasException(env);
Label notException(env);
Label canReadExit(env);
Label readDoneExit(env);
DEFVARIABLE(expectModRecord, VariableType::INT32(), Int32(0));
DEFVARIABLE(desiredModRecord, VariableType::INT32(), Int32(0));
DEFVARIABLE(scopeEntered, VariableType::BOOL(), False());
ConcurrentApiScopeCanRead<JSSharedMap>(glue, thisValue, expectModRecord,
desiredModRecord, scopeEntered, &canReadExit);
Bind(&canReadExit);
BRANCH(HasPendingException(glue), &hasException, ¬Exception);
Bind(&hasException);
{
Jump(&exit);
}
Bind(¬Exception);
{
GateRef linkedMapOffset = IntPtr(JSSharedMap::LINKED_MAP_OFFSET);
GateRef linkedTable = Load(VariableType::JS_ANY(), glue, thisValue, linkedMapOffset);
LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject> linkedHashTableStubBuilder(
this, glue, GetCurrentGlobalEnv(), true);
result = linkedHashTableStubBuilder.Get(linkedTable, key);
Jump(&exit);
}
Bind(&exit);
ConcurrentApiScopeReadDone<JSSharedMap>(glue, thisValue, expectModRecord,
desiredModRecord, scopeEntered, &readDoneExit);
Bind(&readDoneExit);
auto res = *result;
env->SubCfgExit();
return res;
}
void BuiltinsSharedMapStubBuilder::Has(GateRef glue, GateRef thisValue,
GateRef numArgs, Variable *result, Label *exit, Label *slowPath)
{
auto env = GetEnvironment();
Label isSharedMap(env);
BRANCH(IsJSObjectType(glue, thisValue, JSType::JS_SHARED_MAP), &isSharedMap, slowPath);
Bind(&isSharedMap);
GateRef key = GetCallArg0(numArgs);
GateRef ret = HasImpl(glue, thisValue, key);
*result = ret;
Jump(exit);
}
GateRef BuiltinsSharedMapStubBuilder::HasImpl(GateRef glue, GateRef thisValue, GateRef key)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
DEFVARIABLE(result, VariableType::JS_ANY(), TaggedFalse());
Label exit(env);
Label hasException(env);
Label notException(env);
Label canReadExit(env);
Label readDoneExit(env);
DEFVARIABLE(expectModRecord, VariableType::INT32(), Int32(0));
DEFVARIABLE(desiredModRecord, VariableType::INT32(), Int32(0));
DEFVARIABLE(scopeEntered, VariableType::BOOL(), False());
ConcurrentApiScopeCanRead<JSSharedMap>(glue, thisValue, expectModRecord,
desiredModRecord, scopeEntered, &canReadExit);
Bind(&canReadExit);
BRANCH(HasPendingException(glue), &hasException, ¬Exception);
Bind(&hasException);
{
Jump(&exit);
}
Bind(¬Exception);
{
GateRef linkedMapOffset = IntPtr(JSSharedMap::LINKED_MAP_OFFSET);
GateRef linkedTable = Load(VariableType::JS_ANY(), glue, thisValue, linkedMapOffset);
LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject> linkedHashTableStubBuilder(
this, glue, GetCurrentGlobalEnv(), true);
result = BooleanToTaggedBooleanPtr(linkedHashTableStubBuilder.Has(linkedTable, key));
Jump(&exit);
}
Bind(&exit);
ConcurrentApiScopeReadDone<JSSharedMap>(glue, thisValue, expectModRecord,
desiredModRecord, scopeEntered, &readDoneExit);
Bind(&readDoneExit);
auto res = *result;
env->SubCfgExit();
return res;
}
void BuiltinsSharedMapStubBuilder::Delete(GateRef glue, GateRef thisValue,
GateRef numArgs, Variable *result, Label *exit, Label *slowPath)
{
auto env = GetEnvironment();
Label isSharedMap(env);
BRANCH(IsJSObjectType(glue, thisValue, JSType::JS_SHARED_MAP), &isSharedMap, slowPath);
Bind(&isSharedMap);
GateRef key = GetCallArg0(numArgs);
GateRef ret = DeleteImpl(glue, thisValue, key);
*result = ret;
Jump(exit);
}
GateRef BuiltinsSharedMapStubBuilder::DeleteImpl(GateRef glue, GateRef thisValue, GateRef key)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
DEFVARIABLE(result, VariableType::JS_ANY(), TaggedFalse());
Label canWriteExit(env);
Label writeDoneExit(env);
Label exit(env);
Label hasException(env);
Label notException(env);
DEFVARIABLE(scopeEntered, VariableType::BOOL(), False());
ConcurrentApiScopeCanWrite<JSSharedMap>(glue, thisValue, scopeEntered, &canWriteExit);
Bind(&canWriteExit);
BRANCH(HasPendingException(glue), &hasException, ¬Exception);
Bind(&hasException);
{
Jump(&exit);
}
Bind(¬Exception);
{
GateRef linkedMapOffset = IntPtr(JSSharedMap::LINKED_MAP_OFFSET);
GateRef linkedTable = Load(VariableType::JS_ANY(), glue, thisValue, linkedMapOffset);
LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject> linkedHashTableStubBuilder(
this, glue, GetCurrentGlobalEnv(), true);
result = BooleanToTaggedBooleanPtr(linkedHashTableStubBuilder.Delete(linkedTable, key));
Jump(&exit);
}
Bind(&exit);
ConcurrentApiScopeWriteDone<JSSharedMap>(glue, thisValue, scopeEntered, &writeDoneExit);
Bind(&writeDoneExit);
auto res = *result;
env->SubCfgExit();
return res;
}
}