* Copyright (c) 2023 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_object_stub_builder.h"
#include "ecmascript/compiler/builtins/builtins_typedarray_stub_builder.h"
#include "ecmascript/compiler/new_object_stub_builder.h"
#include "ecmascript/js_primitive_ref.h"
namespace panda::ecmascript::kungfu {
void BuiltinsObjectStubBuilder::ToStringFunc(Variable *result, Label *exit, Label *slowPath)
{
auto env = GetEnvironment();
Label ecmaObj(env);
Label undefined(env);
Label checknull(env);
BRANCH(TaggedIsUndefined(thisValue_), &undefined, &checknull);
Bind(&undefined);
{
*result = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_, ConstantIndex::UNDEFINED_TO_STRING_INDEX);
Jump(exit);
}
Bind(&checknull);
Label null(env);
Label checkObject(env);
BRANCH(TaggedIsUndefined(thisValue_), &null, &checkObject);
Bind(&null);
{
*result = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_, ConstantIndex::NULL_TO_STRING_INDEX);
Jump(exit);
}
Bind(&checkObject);
BRANCH(IsEcmaObject(glue_, thisValue_), &ecmaObj, slowPath);
Bind(&ecmaObj);
{
GateRef toStringTagSymbol = GetGlobalConstantValue(VariableType::JS_ANY(), glue_,
ConstantIndex::TOSTRINGTAG_SYMBOL_INDEX);
GateRef tag = FastGetPropertyByName(glue_, thisValue_, toStringTagSymbol, ProfileOperation());
Label defaultToString(env);
BRANCH(TaggedIsString(glue_, tag), slowPath, &defaultToString);
Bind(&defaultToString);
{
Label objectTag(env);
BRANCH(IsJSObjectType(glue_, thisValue_, JSType::JS_OBJECT), &objectTag, slowPath);
Bind(&objectTag);
{
*result = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_,
ConstantIndex::OBJECT_TO_STRING_INDEX);
Jump(exit);
}
}
}
}
void BuiltinsObjectStubBuilder::Create(Variable *result, Label *exit, Label *slowPath)
{
auto env = GetEnvironment();
Label newObject(env);
GateRef proto = GetCallArg0(numArgs_);
GateRef protoCheck = LogicAndBuilder(env).And(BoolNot(IsEcmaObject(glue_, proto)))
.And(BoolNot(TaggedIsNull(proto))).Done();
BRANCH(LogicOrBuilder(env).Or(protoCheck).Or(TaggedIsSharedObj(glue_, proto)).Done(), slowPath, &newObject);
Bind(&newObject);
{
Label noProperties(env);
GateRef propertiesObject = GetCallArg1(numArgs_);
BRANCH(TaggedIsUndefined(propertiesObject), &noProperties, slowPath);
Bind(&noProperties);
{
*result = OrdinaryNewJSObjectCreate(glue_, proto);
Jump(exit);
}
}
}
void BuiltinsObjectStubBuilder::AssignEnumElementProperty(Variable *result, Label *funcExit,
GateRef toAssign, GateRef source)
{
auto env = GetEnvironment();
Label entryLabel(env);
env->SubCfgEntry(&entryLabel);
Label exit(env);
GateRef elements = GetElementsArray(glue_, source);
Label dictionaryMode(env);
Label notDictionaryMode(env);
BRANCH(IsDictionaryMode(glue_, elements), &dictionaryMode, ¬DictionaryMode);
Bind(¬DictionaryMode);
{
GateRef len = GetLengthOfTaggedArray(elements);
DEFVARIABLE(idx, VariableType::INT32(), Int32(0));
Label loopHead(env);
Label loopEnd(env);
Label next(env);
Label loopExit(env);
Jump(&loopHead);
LoopBegin(&loopHead);
{
BRANCH(Int32LessThan(*idx, len), &next, &loopExit);
Bind(&next);
GateRef value = GetTaggedValueWithElementsKind(glue_, source, *idx);
Label notHole(env);
BRANCH(TaggedIsHole(value), &loopEnd, ¬Hole);
Bind(¬Hole);
{
FastSetPropertyByIndex(glue_, toAssign, *idx, value);
Label exception(env);
BRANCH(HasPendingException(glue_), &exception, &loopEnd);
Bind(&exception);
{
*result = Exception();
Jump(funcExit);
}
}
}
Bind(&loopEnd);
idx = Int32Add(*idx, Int32(1));
LoopEndWithCheckSafePoint(&loopHead, env, glue_);
Bind(&loopExit);
Jump(&exit);
}
Bind(&dictionaryMode);
{
GateRef sizeIndex = Int32(TaggedHashTable<NumberDictionary>::SIZE_INDEX);
GateRef size = GetInt32OfTInt(GetValueFromTaggedArray(glue_, elements, sizeIndex));
DEFVARIABLE(idx, VariableType::INT32(), Int32(0));
Label loopHead(env);
Label loopEnd(env);
Label next(env);
Label loopExit(env);
Jump(&loopHead);
LoopBegin(&loopHead);
{
BRANCH(Int32LessThan(*idx, size), &next, &loopExit);
Bind(&next);
GateRef key = GetKeyFromDictionary<NumberDictionary>(glue_, elements, *idx);
Label checkEnumerable(env);
BRANCH(LogicOrBuilder(env).Or(TaggedIsUndefined(key)).Or(TaggedIsHole(key)).Done(),
&loopEnd, &checkEnumerable);
Bind(&checkEnumerable);
{
GateRef attr = GetAttributesFromDictionary<NumberDictionary>(glue_, elements, *idx);
Label enumerable(env);
BRANCH(IsEnumerable(attr), &enumerable, &loopEnd);
Bind(&enumerable);
{
GateRef originalValue = GetValueFromDictionary<NumberDictionary>(glue_, elements, *idx);
Label notHole(env);
BRANCH(TaggedIsHole(originalValue), &loopEnd, ¬Hole);
Bind(¬Hole);
{
DEFVARIABLE(value, VariableType::JS_ANY(), originalValue);
Label isAccessor(env);
Label setValue(env);
Label exception(env);
BRANCH(IsAccessor(attr), &isAccessor, &setValue);
Bind(&isAccessor);
{
value = CallGetterHelper(glue_, source, source, *value, ProfileOperation());
BRANCH(HasPendingException(glue_), &exception, &setValue);
}
Bind(&setValue);
{
FastSetPropertyByIndex(glue_, toAssign, TaggedGetInt(key), *value);
BRANCH(HasPendingException(glue_), &exception, &loopEnd);
}
Bind(&exception);
{
*result = Exception();
Jump(funcExit);
}
}
}
}
}
Bind(&loopEnd);
idx = Int32Add(*idx, Int32(1));
LoopEndWithCheckSafePoint(&loopHead, env, glue_);
Bind(&loopExit);
Jump(&exit);
}
Bind(&exit);
env->SubCfgExit();
}
void BuiltinsObjectStubBuilder::LayoutInfoAssignAllEnumProperty(Variable *result, Label *funcExit,
GateRef toAssign, GateRef source)
{
auto env = GetEnvironment();
Label entryLabel(env);
env->SubCfgEntry(&entryLabel);
Label exit(env);
GateRef cls = LoadHClass(glue_, source);
GateRef num = GetNumberOfPropsFromHClass(cls);
GateRef layout = GetLayoutFromHClass(glue_, cls);
DEFVARIABLE(idx, VariableType::INT32(), Int32(0));
Label loopHead(env);
Label loopEnd(env);
Label next(env);
Label loopExit(env);
Jump(&loopHead);
LoopBegin(&loopHead);
{
BRANCH(Int32LessThan(*idx, num), &next, &loopExit);
Bind(&next);
GateRef key = GetKeyFromLayoutInfo(glue_, layout, *idx);
GateRef attr = GetPropAttrFromLayoutInfo(glue_, layout, *idx);
Label stringKey(env);
BRANCH(TaggedIsStringOrSymbol(glue_, key), &stringKey, &loopEnd);
Bind(&stringKey);
{
Label enumerable(env);
BRANCH(IsEnumerable(attr), &enumerable, &loopEnd);
Bind(&enumerable);
{
DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
value = JSObjectGetPropertyWithRep(glue_, source, cls, attr);
Label exception0(env);
Label noexception0(env);
BRANCH(HasPendingException(glue_), &exception0, &noexception0);
Bind(&exception0);
{
*result = Exception();
Jump(funcExit);
}
Bind(&noexception0);
Label propertyBox(env);
Label checkAccessor(env);
Label setValue(env);
BRANCH(TaggedIsPropertyBox(glue_, *value), &propertyBox, &checkAccessor);
Bind(&propertyBox);
{
value = GetValueFromPropertyBox(glue_, *value);
Jump(&setValue);
}
Bind(&checkAccessor);
Label isAccessor(env);
BRANCH(IsAccessor(attr), &isAccessor, &setValue);
Bind(&isAccessor);
{
value = CallGetterHelper(glue_, source, source, *value, ProfileOperation());
Label exception(env);
BRANCH(HasPendingException(glue_), &exception, &setValue);
Bind(&exception);
{
*result = Exception();
Jump(funcExit);
}
}
Bind(&setValue);
{
FastSetPropertyByName(glue_, toAssign, key, *value);
Label exception(env);
BRANCH(HasPendingException(glue_), &exception, &loopEnd);
Bind(&exception);
{
*result = Exception();
Jump(funcExit);
}
}
}
}
}
Bind(&loopEnd);
idx = Int32Add(*idx, Int32(1));
LoopEndWithCheckSafePoint(&loopHead, env, glue_);
Bind(&loopExit);
Jump(&exit);
Bind(&exit);
env->SubCfgExit();
}
void BuiltinsObjectStubBuilder::NameDictionaryAssignAllEnumProperty(Variable *result, Label *funcExit,
GateRef toAssign, GateRef source, GateRef properties)
{
auto env = GetEnvironment();
Label entryLabel(env);
env->SubCfgEntry(&entryLabel);
Label exit(env);
GateRef sizeIndex = Int32(TaggedHashTable<NameDictionary>::SIZE_INDEX);
GateRef size = GetInt32OfTInt(GetValueFromTaggedArray(glue_, properties, sizeIndex));
DEFVARIABLE(idx, VariableType::INT32(), Int32(0));
Label loopHead(env);
Label loopEnd(env);
Label next(env);
Label loopExit(env);
Jump(&loopHead);
LoopBegin(&loopHead);
{
BRANCH(Int32LessThan(*idx, size), &next, &loopExit);
Bind(&next);
GateRef key = GetKeyFromDictionary<NameDictionary>(glue_, properties, *idx);
Label stringKey(env);
BRANCH(TaggedIsStringOrSymbol(glue_, key), &stringKey, &loopEnd);
Bind(&stringKey);
{
GateRef attr = GetAttributesFromDictionary<NameDictionary>(glue_, properties, *idx);
Label enumerable(env);
BRANCH(IsEnumerable(attr), &enumerable, &loopEnd);
Bind(&enumerable);
{
DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
value = GetValueFromDictionary<NameDictionary>(glue_, properties, *idx);
Label notHole(env);
BRANCH(TaggedIsHole(*value), &loopEnd, ¬Hole);
Bind(¬Hole);
{
Label isAccessor(env);
Label notAccessor(env);
BRANCH(IsAccessor(attr), &isAccessor, ¬Accessor);
Bind(&isAccessor);
{
value = CallGetterHelper(glue_, source, source, *value, ProfileOperation());
Label exception(env);
BRANCH(HasPendingException(glue_), &exception, ¬Accessor);
Bind(&exception);
{
*result = Exception();
Jump(funcExit);
}
}
Bind(¬Accessor);
{
FastSetPropertyByName(glue_, toAssign, key, *value);
Label exception(env);
BRANCH(HasPendingException(glue_), &exception, &loopEnd);
Bind(&exception);
{
*result = Exception();
Jump(funcExit);
}
}
}
}
}
}
Bind(&loopEnd);
idx = Int32Add(*idx, Int32(1));
LoopEndWithCheckSafePoint(&loopHead, env, glue_);
Bind(&loopExit);
Jump(&exit);
Bind(&exit);
env->SubCfgExit();
}
void BuiltinsObjectStubBuilder::AssignAllEnumProperty(Variable *res, Label *funcExit,
GateRef toAssign, GateRef source)
{
auto env = GetEnvironment();
Label entryLabel(env);
env->SubCfgEntry(&entryLabel);
Label exit(env);
GateRef properties = GetPropertiesArray(glue_, source);
Label dictionaryMode(env);
Label notDictionaryMode(env);
BRANCH(IsDictionaryMode(glue_, properties), &dictionaryMode, ¬DictionaryMode);
Bind(¬DictionaryMode);
{
LayoutInfoAssignAllEnumProperty(res, funcExit, toAssign, source);
Jump(&exit);
}
Bind(&dictionaryMode);
{
NameDictionaryAssignAllEnumProperty(res, funcExit, toAssign, source, properties);
Jump(&exit);
}
Bind(&exit);
env->SubCfgExit();
}
void BuiltinsObjectStubBuilder::SlowAssign(Variable *result, Label *funcExit, GateRef toAssign, GateRef source)
{
auto env = GetEnvironment();
Label entryLabel(env);
env->SubCfgEntry(&entryLabel);
Label exit(env);
CallRuntimeWithGlobalEnv(glue_, GetCurrentGlobalEnv(), RTSTUB_ID(ObjectSlowAssign), { toAssign, source });
Label exception(env);
BRANCH(HasPendingException(glue_), &exception, &exit);
Bind(&exception);
{
*result = Exception();
Jump(funcExit);
}
Bind(&exit);
env->SubCfgExit();
}
void BuiltinsObjectStubBuilder::FastAssign(Variable *res, Label *funcExit, GateRef toAssign, GateRef source)
{
AssignEnumElementProperty(res, funcExit, toAssign, source);
AssignAllEnumProperty(res, funcExit, toAssign, source);
}
void BuiltinsObjectStubBuilder::Assign(Variable *res, Label *nextIt, Label *funcExit,
GateRef toAssign, GateRef source)
{
auto env = GetEnvironment();
Label checkJsObj(env);
BRANCH(TaggedIsUndefinedOrNull(source), nextIt, &checkJsObj);
Bind(&checkJsObj);
{
Label fastAssign(env);
Label slowAssign(env);
BRANCH(IsJSObjectType(glue_, source, JSType::JS_OBJECT), &fastAssign, &slowAssign);
Bind(&fastAssign);
{
FastAssign(res, funcExit, toAssign, source);
Jump(nextIt);
}
Bind(&slowAssign);
{
SlowAssign(res, funcExit, toAssign, source);
Jump(nextIt);
}
}
}
void BuiltinsObjectStubBuilder::Assign(Variable *result, Label *exit, Label *slowPath)
{
auto env = GetEnvironment();
Label thisCollectionObj(env);
GateRef target = GetCallArg0(numArgs_);
*result = target;
Label jsObject(env);
BRANCH(IsJSObjectType(glue_, target, JSType::JS_OBJECT), &jsObject, slowPath);
Bind(&jsObject);
{
Label twoArg(env);
Label notTwoArg(env);
BRANCH(Int64Equal(numArgs_, IntPtr(2)), &twoArg, ¬TwoArg);
Bind(&twoArg);
{
GateRef source = GetCallArg1(numArgs_);
Label next(env);
Assign(result, &next, exit, target, source);
Bind(&next);
Jump(exit);
}
Bind(¬TwoArg);
Label threeArg(env);
Label notThreeArg(env);
BRANCH(Int64Equal(numArgs_, IntPtr(3)), &threeArg, ¬ThreeArg);
Bind(&threeArg);
{
Label nextArg(env);
GateRef source = GetCallArg1(numArgs_);
Label next(env);
Assign(result, &next, exit, target, source);
Bind(&next);
Label next1(env);
GateRef source1 = GetCallArg2(numArgs_);
Assign(result, &next1, exit, target, source1);
Bind(&next1);
Jump(exit);
}
Bind(¬ThreeArg);
{
Jump(slowPath);
}
}
}
void BuiltinsObjectStubBuilder::HasOwnProperty(Variable *result, Label *exit, Label *slowPath)
{
GateRef prop = GetCallArg0(numArgs_);
HasOwnProperty(result, exit, slowPath, thisValue_, prop);
}
void BuiltinsObjectStubBuilder::HasOwnProperty(Variable *result, Label *exit, Label *slowPath, GateRef thisValue,
GateRef prop, GateRef hir)
{
auto env = GetEnvironment();
Label keyIsString(env);
Label valid(env);
Label isHeapObject(env);
BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
Bind(&isHeapObject);
BRANCH(TaggedIsRegularObject(glue_, thisValue), &valid, slowPath);
Bind(&valid);
{
Label isIndex(env);
Label notIndex(env);
BRANCH(TaggedIsString(glue_, prop), &keyIsString, slowPath);
Bind(&keyIsString);
{
BuiltinsStringStubBuilder stringStub(this, GetCurrentGlobalEnv());
GateRef res = stringStub.StringToUint(glue_, prop, JSObject::MAX_ELEMENT_INDEX - 1);
BRANCH(Int64NotEqual(res, Int64(-1)), &isIndex, ¬Index);
Bind(&isIndex);
{
GateRef index = TruncInt64ToInt32(res);
Label findByIndex(env);
GateRef elements = GetElementsArray(glue_, thisValue);
GateRef len = GetLengthOfTaggedArray(elements);
BRANCH(Int32Equal(len, Int32(0)), exit, &findByIndex);
Bind(&findByIndex);
{
Label isDictionaryElement(env);
Label notDictionaryElement(env);
BRANCH(IsDictionaryMode(glue_, elements), &isDictionaryElement, ¬DictionaryElement);
Bind(¬DictionaryElement);
{
Label lessThanLength(env);
Label notLessThanLength(env);
BRANCH(Int32UnsignedLessThanOrEqual(len, index), exit, &lessThanLength);
Bind(&lessThanLength);
{
Label notHole(env);
GateRef value = GetTaggedValueWithElementsKind(glue_, thisValue, index);
BRANCH(TaggedIsNotHole(value), ¬Hole, exit);
Bind(¬Hole);
{
*result = TaggedTrue();
Jump(exit);
}
}
}
Bind(&isDictionaryElement);
{
GateRef entryA = FindElementFromNumberDictionary(glue_, elements, index);
Label notNegtiveOne(env);
BRANCH(Int32NotEqual(entryA, Int32(-1)), ¬NegtiveOne, exit);
Bind(¬NegtiveOne);
{
*result = TaggedTrue();
Jump(exit);
}
}
}
}
Bind(¬Index);
{
Label findInStringTabel(env);
Label notInternString(env);
DEFVARIABLE(stringTable, VariableType::JS_ANY(), prop);
BRANCH(IsInternalString(prop), &findInStringTabel, ¬InternString);
Bind(¬InternString);
{
GateRef internString = CallRuntime(glue_, RTSTUB_ID(TryGetInternString), { prop });
stringTable = internString;
BRANCH(TaggedIsHole(internString), exit, &findInStringTabel)
}
Bind(&findInStringTabel);
{
Label isDicMode(env);
Label notDicMode(env);
GateRef hclass = LoadHClass(glue_, thisValue);
BRANCH(IsDictionaryModeByHClass(hclass), &isDicMode, ¬DicMode);
Bind(¬DicMode);
{
GateRef layOutInfo = GetLayoutFromHClass(glue_, hclass);
GateRef propsNum = GetNumberOfPropsFromHClass(hclass);
GateRef entryA = FindElementWithCache(glue_, layOutInfo, hclass, *stringTable, propsNum, hir);
Label hasEntry(env);
BRANCH(Int32NotEqual(entryA, Int32(-1)), &hasEntry, exit);
Bind(&hasEntry);
{
*result = TaggedTrue();
Jump(exit);
}
}
Bind(&isDicMode);
{
GateRef array = GetPropertiesArray(glue_, thisValue);
GateRef entryB = FindEntryFromHashTable<NameDictionary>(glue_, array, *stringTable, hir);
Label notNegtiveOne(env);
BRANCH(Int32NotEqual(entryB, Int32(-1)), ¬NegtiveOne, exit);
Bind(¬NegtiveOne);
{
*result = TaggedTrue();
Jump(exit);
}
}
}
}
}
}
}
GateRef BuiltinsObjectStubBuilder::GetNumKeysFromLayoutInfo(GateRef end, GateRef layoutInfo)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
DEFVARIABLE(result, VariableType::INT32(), Int32(0));
DEFVARIABLE(i, VariableType::INT32(), Int32(0));
Label loopHead(env);
Label loopEnd(env);
Label iLessEnd(env);
Label isString(env);
Label isEnumerable(env);
Jump(&loopHead);
LoopBegin(&loopHead);
{
BRANCH(Int32UnsignedLessThan(*i, end), &iLessEnd, &exit);
Bind(&iLessEnd);
{
GateRef key = GetKey(glue_, layoutInfo, *i);
BRANCH(TaggedIsString(glue_, key), &isString, &loopEnd);
Bind(&isString);
BRANCH(IsEnumerable(GetAttr(glue_, layoutInfo, *i)), &isEnumerable, &loopEnd);
Bind(&isEnumerable);
result = Int32Add(*result, Int32(1));
Jump(&loopEnd);
}
Bind(&loopEnd);
i = Int32Add(*i, Int32(1));
LoopEndWithCheckSafePoint(&loopHead, env, glue_);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef BuiltinsObjectStubBuilder::GetNumKeysFromDictionary(GateRef array)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
GateRef sizeIndex = Int32(TaggedHashTable<NameDictionary>::SIZE_INDEX);
GateRef size = GetInt32OfTInt(GetValueFromTaggedArray(glue_, array, sizeIndex));
DEFVARIABLE(i, VariableType::INT32(), Int32(0));
DEFVARIABLE(result, VariableType::INT32(), Int32(0));
Label loopHead(env);
Label loopEnd(env);
Label afterLoop(env);
Label iLessSize(env);
Label isString(env);
Label isEnumerable(env);
Jump(&loopHead);
LoopBegin(&loopHead);
{
BRANCH(Int32UnsignedLessThan(*i, size), &iLessSize, &afterLoop);
Bind(&iLessSize);
{
GateRef key = GetKeyFromDictionary<NameDictionary>(glue_, array, *i);
BRANCH(TaggedIsString(glue_, key), &isString, &loopEnd);
Bind(&isString);
GateRef attr = GetAttributesFromDictionary<NameDictionary>(glue_, array, *i);
BRANCH(IsEnumerable(attr), &isEnumerable, &loopEnd);
Bind(&isEnumerable);
result = Int32Add(*result, Int32(1));
Jump(&loopEnd);
}
Bind(&loopEnd);
i = Int32Add(*i, Int32(1));
LoopEndWithCheckSafePoint(&loopHead, env, glue_);
}
Bind(&afterLoop);
Jump(&exit);
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
void BuiltinsObjectStubBuilder::LayoutInfoGetAllEnumKeys(GateRef end, GateRef offset, GateRef array, GateRef layoutInfo)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
DEFVARIABLE(i, VariableType::INT32(), Int32(0));
DEFVARIABLE(enumKeys, VariableType::INT32(), Int32(0));
Label loopHead(env);
Label loopEnd(env);
Label afterLoop(env);
Label iLessEnd(env);
Label isEnumerable(env);
Jump(&loopHead);
LoopBegin(&loopHead);
{
BRANCH(Int32UnsignedLessThan(*i, end), &iLessEnd, &afterLoop);
Bind(&iLessEnd);
{
GateRef key = GetKey(glue_, layoutInfo, *i);
GateRef iVal = *i;
BRANCH(LogicAndBuilder(env).And(TaggedIsString(glue_, key))
.And(IsEnumerable(GetAttr(glue_, layoutInfo, iVal))).Done(), &isEnumerable, &loopEnd);
Bind(&isEnumerable);
SetValueToTaggedArray(VariableType::JS_ANY(), glue_, array, Int32Add(*enumKeys, offset), key);
enumKeys = Int32Add(*enumKeys, Int32(1));
Jump(&loopEnd);
}
Bind(&loopEnd);
i = Int32Add(*i, Int32(1));
LoopEndWithCheckSafePoint(&loopHead, env, glue_);
}
Bind(&afterLoop);
Jump(&exit);
Bind(&exit);
env->SubCfgExit();
}
GateRef BuiltinsObjectStubBuilder::CopyFromKeyArray(GateRef glue, GateRef elements)
{
auto env = GetEnvironment();
Label subEntry(env);
env->SubCfgEntry(&subEntry);
Label exit(env);
DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
DEFVARIABLE(index, VariableType::INT32(), Int32(0));
NewObjectStubBuilder newBuilder(this);
GateRef newLen = GetLengthOfTaggedArray(elements);
GateRef array = newBuilder.NewTaggedArray(glue, newLen);
Store(VariableType::INT32(), glue, array, IntPtr(TaggedArray::LENGTH_OFFSET), newLen);
GateRef oldExtractLen = GetExtraLengthOfTaggedArray(elements);
Store(VariableType::INT32(), glue, array, IntPtr(TaggedArray::EXTRA_LENGTH_OFFSET), oldExtractLen);
Label loopHead(env);
Label loopEnd(env);
Label afterLoop(env);
Label storeValue(env);
Jump(&loopHead);
LoopBegin(&loopHead);
{
BRANCH(Int32UnsignedLessThan(*index, newLen), &storeValue, &afterLoop);
Bind(&storeValue);
{
GateRef value = GetValueFromTaggedArray(glue, elements, *index);
SetValueToTaggedArray(VariableType::JS_ANY(), glue, array, *index, value);
index = Int32Add(*index, Int32(1));
Jump(&loopEnd);
}
}
Bind(&loopEnd);
LoopEndWithCheckSafePoint(&loopHead, env, glue);
Bind(&afterLoop);
{
result = array;
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef BuiltinsObjectStubBuilder::GetAllEnumKeys(GateRef glue, GateRef obj)
{
auto env = GetEnvironment();
Label subEntry(env);
env->SubCfgEntry(&subEntry);
Label exit(env);
Label isDictionary(env);
Label notDictionary(env);
DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
GateRef array = GetPropertiesArray(glue, obj);
BRANCH(IsDictionaryMode(glue, array), &isDictionary, ¬Dictionary);
Bind(&isDictionary);
{
Label propsNotZero(env);
Label propsIsZero(env);
GateRef numOfKeys = GetNumKeysFromDictionary(array);
BRANCH(Int32GreaterThan(numOfKeys, Int32(0)), &propsNotZero, &propsIsZero);
Bind(&propsNotZero);
result = CallRuntime(glue, RTSTUB_ID(NameDictionaryGetAllEnumKeys), { obj, IntToTaggedInt(numOfKeys) });
Jump(&exit);
Bind(&propsIsZero);
GateRef emptyArray = GetEmptyArray(glue);
result = emptyArray;
Jump(&exit);
}
Bind(¬Dictionary);
{
Label hasProps(env);
Label notHasProps(env);
GateRef hclass = LoadHClass(glue, obj);
GateRef num = GetNumberOfPropsFromHClass(hclass);
BRANCH(Int32GreaterThan(num, Int32(0)), &hasProps, ¬HasProps);
Bind(&hasProps);
{
Label hasEnumCacheOwn(env);
Label notHasEnumCacheOwn(env);
Label inSharedHeap(env);
Label notInSharedHeap(env);
GateRef layout = GetLayoutFromHClass(glue, hclass);
GateRef numOfKeys = GetNumKeysFromLayoutInfo(num, layout);
GateRef hclassRegion = ObjectAddressToRange(hclass);
BRANCH(InSharedHeap(hclassRegion), &inSharedHeap, ¬InSharedHeap);
Bind(¬InSharedHeap);
{
GateRef enumCache = GetOrCreateEnumCacheFromHClass(glue, hclass);
GateRef enumCacheOwn = GetEnumCacheOwnFromEnumCache(glue, enumCache);
BRANCH(TaggedIsNull(enumCacheOwn), ¬HasEnumCacheOwn, &hasEnumCacheOwn);
Bind(&hasEnumCacheOwn);
{
result = CopyFromKeyArray(glue, enumCacheOwn);
Jump(&exit);
}
Bind(¬HasEnumCacheOwn);
{
Label numNotZero(env);
BRANCH(Int32GreaterThan(numOfKeys, Int32(0)), &numNotZero, ¬HasProps);
Bind(&numNotZero);
NewObjectStubBuilder newBuilder(this);
GateRef keyArray = newBuilder.NewTaggedArray(glue, numOfKeys);
LayoutInfoGetAllEnumKeys(num, Int32(0), keyArray, layout);
GateRef enumCacheOwnOffset = IntPtr(EnumCache::ENUM_CACHE_OWN_OFFSET);
Store(VariableType::JS_ANY(), glue, enumCache, enumCacheOwnOffset, keyArray);
result = CopyFromKeyArray(glue, keyArray);
Jump(&exit);
}
}
Bind(&inSharedHeap);
{
Label numNotZeroShared(env);
BRANCH(Int32GreaterThan(numOfKeys, Int32(0)), &numNotZeroShared, ¬HasProps);
Bind(&numNotZeroShared);
NewObjectStubBuilder newBuilderShared(this);
GateRef keyArrayShared = newBuilderShared.NewTaggedArray(glue, numOfKeys);
LayoutInfoGetAllEnumKeys(num, Int32(0), keyArrayShared, layout);
result = CopyFromKeyArray(glue, keyArrayShared);
Jump(&exit);
}
}
Bind(¬HasProps);
{
GateRef emptyArray = GetEmptyArray(glue);
result = emptyArray;
Jump(&exit);
}
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef BuiltinsObjectStubBuilder::GetEnumElementKeys(GateRef glue, GateRef obj)
{
auto env = GetEnvironment();
Label subEntry(env);
env->SubCfgEntry(&subEntry);
Label exit(env);
DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
DEFVARIABLE(i, VariableType::INT32(), Int32(0));
DEFVARIABLE(j, VariableType::INT32(), Int32(0));
DEFVARIABLE(elementIndex, VariableType::INT32(), Int32(0));
Label propsNotZero(env);
Label propsIsZero(env);
GateRef numOfElements = GetNumberOfElements(glue, obj);
BRANCH(Int32GreaterThan(numOfElements, Int32(0)), &propsNotZero, &propsIsZero);
Bind(&propsNotZero);
{
Label isJSPrimitiveRef(env);
Label isPrimitiveString(env);
Label notPrimitiveString(env);
Label isDictMode(env);
Label notDictMode(env);
NewObjectStubBuilder newBuilder(this);
GateRef elementArray = newBuilder.NewTaggedArray(glue, numOfElements);
BRANCH(IsJSPrimitiveRef(glue, obj), &isJSPrimitiveRef, ¬PrimitiveString);
Bind(&isJSPrimitiveRef);
GateRef value = Load(VariableType::JS_ANY(), glue, obj, IntPtr(JSPrimitiveRef::VALUE_OFFSET));
BRANCH(TaggedIsString(glue, value), &isPrimitiveString, ¬PrimitiveString);
Bind(&isPrimitiveString);
{
Label loopHead(env);
Label loopEnd(env);
Label iLessLength(env);
GateRef strLen = GetLengthFromString(value);
Jump(&loopHead);
LoopBegin(&loopHead);
{
BRANCH(Int32UnsignedLessThan(*i, strLen), &iLessLength, ¬PrimitiveString);
Bind(&iLessLength);
{
GateRef str = IntToEcmaString(glue, *i);
SetValueToTaggedArray(VariableType::JS_ANY(), glue, elementArray,
*elementIndex, str);
elementIndex = Int32Add(*elementIndex, Int32(1));
Jump(&loopEnd);
}
Bind(&loopEnd);
i = Int32Add(*i, Int32(1));
LoopEndWithCheckSafePoint(&loopHead, env, glue);
}
}
Bind(¬PrimitiveString);
GateRef elements = GetElementsArray(glue, obj);
BRANCH(IsDictionaryMode(glue, elements), &isDictMode, ¬DictMode);
Bind(¬DictMode);
{
Label loopHead(env);
Label loopEnd(env);
Label iLessLength(env);
Label notHole(env);
Label afterLoop(env);
GateRef elementsLen = GetLengthOfTaggedArray(elements);
Jump(&loopHead);
LoopBegin(&loopHead);
{
BRANCH(Int32UnsignedLessThan(*j, elementsLen), &iLessLength, &afterLoop);
Bind(&iLessLength);
{
GateRef element = GetTaggedValueWithElementsKind(glue, obj, *j);
BRANCH(TaggedIsHole(element), &loopEnd, ¬Hole);
Bind(¬Hole);
GateRef str = IntToEcmaString(glue, *j);
SetValueToTaggedArray(VariableType::JS_ANY(), glue, elementArray,
*elementIndex, str);
elementIndex = Int32Add(*elementIndex, Int32(1));
Jump(&loopEnd);
}
Bind(&loopEnd);
j = Int32Add(*j, Int32(1));
LoopEndWithCheckSafePoint(&loopHead, env, glue);
Bind(&afterLoop);
{
result = elementArray;
Label needTrim(env);
BRANCH(Int32LessThan(*elementIndex, numOfElements), &needTrim, &exit);
Bind(&needTrim);
{
CallNGCRuntime(glue, RTSTUB_ID(ArrayTrim),
{glue, elementArray, ZExtInt32ToInt64(*elementIndex)});
Jump(&exit);
}
}
}
}
Bind(&isDictMode);
{
CallRuntime(glue, RTSTUB_ID(NumberDictionaryGetAllEnumKeys),
{ elements, elementArray, IntToTaggedInt(*elementIndex) });
result = elementArray;
Jump(&exit);
}
}
Bind(&propsIsZero);
{
GateRef emptyArray = GetEmptyArray(glue);
result = emptyArray;
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef BuiltinsObjectStubBuilder::IsNotSlowObjectKey(GateRef obj)
{
auto env = GetEnvironment();
return LogicAndBuilder(env)
.And(IsJSObject(glue_, obj))
.And(BoolNot(LogicOrBuilder(env).Or(IsTypedArray(glue_, obj)).Or(IsModuleNamespace(glue_, obj))
.Or(IsJSGlobalObject(glue_, obj)).Done()))
.Done();
}
void BuiltinsObjectStubBuilder::Keys(Variable *result, Label *exit, Label *slowPath)
{
auto env = GetEnvironment();
NewObjectStubBuilder newBuilder(this, GetCurrentGlobalEnv());
GateRef msg = GetCallArg0(numArgs_);
GateRef obj = ToObject(glue_, GetCurrentGlobalEnv(), msg);
Label isPendingException(env);
Label noPendingException(env);
BRANCH(HasPendingException(glue_), &isPendingException, &noPendingException);
Bind(&isPendingException);
Jump(exit);
Bind(&noPendingException);
Label isFast(env);
BRANCH(IsNotSlowObjectKey(obj), &isFast, slowPath);
Bind(&isFast);
{
Label hasKeyAndEle(env);
Label nonKeyAndEle(env);
GateRef elementKind = Int32(Elements::ToUint(ElementsKind::TAGGED));
GateRef elementArray = GetEnumElementKeys(glue_, obj);
GateRef keyArray = GetAllEnumKeys(glue_, obj);
GateRef lengthOfKeys = GetLengthOfTaggedArray(keyArray);
GateRef lengthOfElements = GetLengthOfTaggedArray(elementArray);
GateRef KeyAndEle = BitAnd(Int32NotEqual(lengthOfElements, Int32(0)), Int32NotEqual(lengthOfKeys, Int32(0)));
BRANCH(KeyAndEle, &hasKeyAndEle, &nonKeyAndEle);
Bind(&hasKeyAndEle);
{
GateRef allKeys = AppendSkipHole(glue_, elementArray, keyArray, Int32Add(lengthOfKeys, lengthOfElements));
*result = newBuilder.CreateArrayFromList(glue_, allKeys, elementKind);
Jump(exit);
}
Bind(&nonKeyAndEle);
{
Label hasKey(env);
Label nonKey(env);
BRANCH(Int32NotEqual(lengthOfKeys, Int32(0)), &hasKey, &nonKey);
Bind(&hasKey);
{
*result = newBuilder.CreateArrayFromList(glue_, keyArray, elementKind);
Jump(exit);
}
Bind(&nonKey);
{
Label hasEle(env);
Label nonEle(env);
BRANCH(Int32NotEqual(lengthOfElements, Int32(0)), &hasEle, &nonEle);
Bind(&hasEle);
{
*result = newBuilder.CreateArrayFromList(glue_, elementArray, elementKind);
Jump(exit);
}
Bind(&nonEle);
{
GateRef emptyArray = GetEmptyArray(glue_);
*result = newBuilder.CreateArrayFromList(glue_, emptyArray, elementKind);
Jump(exit);
}
}
}
}
}
void BuiltinsObjectStubBuilder::GetPrototypeOf(Variable *result, Label *exit, Label *slowPath)
{
auto env = GetEnvironment();
Label isPendingException(env);
Label noPendingException(env);
GateRef msg = GetCallArg0(numArgs_);
GateRef obj = ToObject(glue_, GetCurrentGlobalEnv(), msg);
BRANCH(HasPendingException(glue_), &isPendingException, &noPendingException);
Bind(&isPendingException);
{
Jump(exit);
}
Bind(&noPendingException);
{
Label isEcmaObject(env);
Label notJsProxy(env);
BRANCH(IsEcmaObject(glue_, obj), &isEcmaObject, slowPath);
Bind(&isEcmaObject);
{
BRANCH(IsJsProxy(glue_, obj), slowPath, ¬JsProxy);
Bind(¬JsProxy);
{
GateRef hClass = LoadHClass(glue_, obj);
GateRef prototype = GetPrototypeFromHClass(glue_, hClass);
*result = prototype;
Jump(exit);
}
}
}
}
void BuiltinsObjectStubBuilder::SetPrototypeOf(Variable *result, Label *exit, Label *slowPath)
{
auto env = GetEnvironment();
GateRef obj = GetCallArg0(numArgs_);
DEFVARIABLE(proto, VariableType::JS_ANY(), Undefined());
Label checkJsObj(env);
Label setProto(env);
BRANCH(TaggedIsUndefinedOrNull(obj), slowPath, &checkJsObj);
Bind(&checkJsObj);
{
Label checkProto(env);
proto = GetCallArg1(numArgs_);
GateRef protoVal = *proto;
BRANCH(LogicOrBuilder(env).Or(TaggedIsNull(protoVal)).Or(IsEcmaObject(glue_, protoVal)).Done(),
&checkProto, slowPath);
Bind(&checkProto);
{
Label isEcmaObject(env);
Label notEcmaObject(env);
BRANCH(IsEcmaObject(glue_, obj), &isEcmaObject, ¬EcmaObject);
Bind(&isEcmaObject);
Jump(&setProto);
Bind(¬EcmaObject);
{
*result = obj;
Jump(exit);
}
}
}
Bind(&setProto);
{
Label objNotSpecial(env);
GateRef protoVal = *proto;
GateRef isSpecialobj = LogicOrBuilder(env).Or(IsJsProxy(glue_, obj)).Or(TaggedIsSharedObj(glue_, obj))
.Or(TaggedIsSharedObj(glue_, protoVal)).Or(IsSpecialContainer(glue_, obj))
.Or(IsModuleNamespace(glue_, obj)).Done();
BRANCH(isSpecialobj, slowPath, &objNotSpecial);
Bind(&objNotSpecial);
Label isFunction(env);
Label notFunction(env);
GateRef isFunc = LogicAndBuilder(env)
.And(TaggedIsHeapObject(obj)).And(TaggedIsHeapObject(protoVal))
.And(IsJSFunction(glue_, obj)).And(IsJSFunction(glue_, protoVal))
.Done();
BRANCH(isFunc, &isFunction, ¬Function);
Bind(&isFunction);
{
Label isDerivedCtor(env);
auto protoOrHclass = Load(VariableType::JS_ANY(), glue_, obj,
IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
GateRef isDerivedCtorCheck = LogicAndBuilder(env).And(TaggedIsHeapObject(protoOrHclass))
.And(IsJSHClass(glue_, protoOrHclass)).And(IsDerived(glue_, obj)).Done();
BRANCH(isDerivedCtorCheck, &isDerivedCtor, ¬Function);
Bind(&isDerivedCtor);
auto cachedJSHClass = GetPrototypeFromHClass(glue_, protoOrHclass);
SetProtoOrHClassToFunction(glue_, obj, cachedJSHClass);
Jump(¬Function);
}
Bind(¬Function);
{
Label statusIsTrue(env);
Label statusIsFalse(env);
BRANCH(ObjectSetPrototype(glue_, obj, *proto), &statusIsTrue, &statusIsFalse);
Bind(&statusIsTrue);
*result = obj;
Jump(exit);
Bind(&statusIsFalse);
{
GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(SetPrototypeOfFailed));
CallRuntimeWithGlobalEnv(glue_, GetCurrentGlobalEnv(),
RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
*result = Exception();
Jump(exit);
}
}
}
}
GateRef BuiltinsObjectStubBuilder::ObjectSetPrototype(GateRef glue, GateRef obj, GateRef proto)
{
auto env = GetEnvironment();
Label subEntry(env);
env->SubCfgEntry(&subEntry);
Label exit(env);
DEFVARIABLE(result, VariableType::BOOL(), False());
Label isEqual(env);
Label notEqual(env);
Label isExtensible(env);
Label notExtensible(env);
GateRef current = GetPrototype(glue, obj);
BRANCH(IntPtrEqual(proto, current), &isEqual, ¬Equal);
Bind(&isEqual);
{
result = True();
Jump(&exit);
}
Bind(¬Equal);
{
BRANCH(IsExtensible(glue, obj), &isExtensible, ¬Extensible);
Bind(&isExtensible);
{
DEFVARIABLE(done, VariableType::BOOL(), False());
DEFVARIABLE(tempProto, VariableType::JS_ANY(), proto);
Label loopHead(env);
Label loopEnd(env);
Label next(env);
Label loopExit(env);
Jump(&loopHead);
LoopBegin(&loopHead);
{
BRANCH(BoolNot(*done), &next, &loopExit);
Bind(&next);
{
Label isNull(env);
Label notNull(env);
Label isEqual2(env);
Label notEqual2(env);
Label protoNotProxy(env);
GateRef tempProtoVal = *tempProto;
GateRef protoIsNull = LogicOrBuilder(env).Or(TaggedIsNull(tempProtoVal))
.Or(BoolNot(IsEcmaObject(glue, tempProtoVal))).Done();
BRANCH(protoIsNull, &isNull, ¬Null);
Bind(&isNull);
{
done = True();
Jump(&loopEnd);
}
Bind(¬Null);
{
BRANCH(IntPtrEqual(*tempProto, obj), &isEqual2, ¬Equal2);
Bind(&isEqual2);
{
result = False();
Jump(&exit);
}
Bind(¬Equal2);
{
BRANCH(IsJsProxy(glue, *tempProto), &loopExit, &protoNotProxy);
Bind(&protoNotProxy);
{
tempProto = GetPrototype(glue, *tempProto);
Jump(&loopEnd);
}
}
}
}
Bind(&loopEnd);
LoopEndWithCheckSafePoint(&loopHead, env, glue_);
}
Bind(&loopExit);
CallRuntime(glue, RTSTUB_ID(SetPrototypeTransition), { obj, proto});
result = True();
Jump(&exit);
}
Bind(¬Extensible);
{
result = False();
Jump(&exit);
}
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
void BuiltinsObjectStubBuilder::GetOwnPropertyNames(Variable *result, Label *exit, Label *slowPath)
{
auto env = GetEnvironment();
Label isPendingException(env);
Label noPendingException(env);
GateRef msg = GetCallArg0(numArgs_);
GateRef obj = ToObject(glue_, GetCurrentGlobalEnv(), msg);
BRANCH(HasPendingException(glue_), &isPendingException, &noPendingException);
Bind(&isPendingException);
{
Jump(exit);
}
Bind(&noPendingException);
{
Label isFast(env);
BRANCH(IsNotSlowObjectKey(obj), &isFast, slowPath);
Bind(&isFast);
{
Label notDictMode(env);
GateRef isDictMode = LogicOrBuilder(env).Or(IsDictionaryMode(glue_, GetElementsArray(glue_, obj)))
.Or(IsDictionaryMode(glue_, GetPropertiesArray(glue_, obj))).Done();
BRANCH(isDictMode, slowPath, ¬DictMode);
Bind(¬DictMode);
{
Label getAllElementKeys(env);
Label checkNumOfKeys(env);
GateRef hclass = LoadHClass(glue_, obj);
GateRef numOfElements = GetNumberOfElements(glue_, obj);
GateRef numOfKeys = GetNumberOfPropsFromHClass(hclass);
GateRef keyLen = Int32Add(numOfElements, numOfKeys);
GateRef elementKind = Int32(Elements::ToUint(ElementsKind::TAGGED));
NewObjectStubBuilder newBuilder(this, GetCurrentGlobalEnv());
GateRef keyArray = newBuilder.NewTaggedArray(glue_, keyLen);
BRANCH(Int32GreaterThan(numOfElements, Int32(0)), &getAllElementKeys, &checkNumOfKeys);
Bind(&getAllElementKeys);
{
GetAllElementKeys(glue_, obj, Int32(0), keyArray);
Jump(&checkNumOfKeys);
}
Bind(&checkNumOfKeys);
{
Label getAllPropertyKeys(env);
Label checkElementType(env);
BRANCH(Int32GreaterThan(numOfKeys, Int32(0)), &getAllPropertyKeys, &checkElementType);
Bind(&getAllPropertyKeys);
{
GetAllPropertyKeys(glue_, obj, numOfElements, keyArray);
Jump(&checkElementType);
}
Bind(&checkElementType);
{
DEFVARIABLE(i, VariableType::INT32(), Int32(0));
DEFVARIABLE(pos, VariableType::INT32(), Int32(0));
Label loopHead(env);
Label loopEnd(env);
Label next(env);
Label loopExit(env);
Label needTrim(env);
Label setResult(env);
Jump(&loopHead);
LoopBegin(&loopHead);
{
BRANCH(Int32UnsignedLessThan(*i, keyLen), &next, &loopExit);
Bind(&next);
{
Label isString(env);
Label setValue(env);
Label adjustPos(env);
GateRef element = GetValueFromTaggedArray(glue_, keyArray, *i);
BRANCH(TaggedIsString(glue_, element), &isString, &loopEnd);
Bind(&isString);
{
BRANCH(Int32Equal(*pos, *i), &adjustPos, &setValue);
Bind(&setValue);
{
SetValueToTaggedArray(VariableType::JS_ANY(), glue_, keyArray, *pos, element);
Jump(&adjustPos);
}
Bind(&adjustPos);
{
pos = Int32Add(*pos, Int32(1));
Jump(&loopEnd);
}
}
}
Bind(&loopEnd);
i = Int32Add(*i, Int32(1));
LoopEndWithCheckSafePoint(&loopHead, env, glue_);
}
Bind(&loopExit);
BRANCH(Int32UnsignedLessThan(*pos, keyLen), &needTrim, &setResult);
Bind(&needTrim);
{
CallNGCRuntime(glue_, RTSTUB_ID(ArrayTrim), {glue_, keyArray, ZExtInt32ToInt64(*pos)});
Jump(&setResult);
}
Bind(&setResult);
{
*result = newBuilder.CreateArrayFromList(glue_, keyArray, elementKind);
Jump(exit);
}
}
}
}
}
}
}
void BuiltinsObjectStubBuilder::GetOwnPropertySymbols(Variable *result, Label *exit, Label *slowPath)
{
auto env = GetEnvironment();
Label isPendingException(env);
Label noPendingException(env);
GateRef msg = GetCallArg0(numArgs_);
GateRef obj = ToObject(glue_, GetCurrentGlobalEnv(), msg);
BRANCH(HasPendingException(glue_), &isPendingException, &noPendingException);
Bind(&isPendingException);
{
Jump(exit);
}
Bind(&noPendingException);
{
Label isFast(env);
BRANCH(IsNotSlowObjectKey(obj), &isFast, slowPath);
Bind(&isFast);
{
Label notDictMode(env);
GateRef isDictMode = LogicOrBuilder(env).Or(IsDictionaryMode(glue_, GetElementsArray(glue_, obj)))
.Or(IsDictionaryMode(glue_, GetPropertiesArray(glue_, obj))).Done();
BRANCH(isDictMode, slowPath, ¬DictMode);
Bind(¬DictMode);
{
Label getAllElementKeys(env);
Label checkNumOfKeys(env);
GateRef hclass = LoadHClass(glue_, obj);
GateRef numOfElements = GetNumberOfElements(glue_, obj);
GateRef numOfKeys = GetNumberOfPropsFromHClass(hclass);
GateRef keyLen = Int32Add(numOfElements, numOfKeys);
GateRef elementKind = Int32(Elements::ToUint(ElementsKind::TAGGED));
NewObjectStubBuilder newBuilder(this, GetCurrentGlobalEnv());
GateRef keyArray = newBuilder.NewTaggedArray(glue_, keyLen);
BRANCH(Int32GreaterThan(numOfElements, Int32(0)), &getAllElementKeys, &checkNumOfKeys);
Bind(&getAllElementKeys);
{
GetAllElementKeys(glue_, obj, Int32(0), keyArray);
Jump(&checkNumOfKeys);
}
Bind(&checkNumOfKeys);
{
Label getAllPropertyKeys(env);
Label checkElementType(env);
BRANCH(Int32GreaterThan(numOfKeys, Int32(0)), &getAllPropertyKeys, &checkElementType);
Bind(&getAllPropertyKeys);
{
GetAllPropertyKeys(glue_, obj, numOfElements, keyArray);
Jump(&checkElementType);
}
Bind(&checkElementType);
{
DEFVARIABLE(i, VariableType::INT32(), Int32(0));
DEFVARIABLE(pos, VariableType::INT32(), Int32(0));
Label loopHead(env);
Label loopEnd(env);
Label next(env);
Label loopExit(env);
Label needTrim(env);
Label setResult(env);
Jump(&loopHead);
LoopBegin(&loopHead);
{
BRANCH(Int32UnsignedLessThan(*i, keyLen), &next, &loopExit);
Bind(&next);
{
Label isSymbol(env);
Label setValue(env);
Label adjustPos(env);
GateRef element = GetValueFromTaggedArray(glue_, keyArray, *i);
BRANCH(TaggedIsSymbol(glue_, element), &isSymbol, &loopEnd);
Bind(&isSymbol);
{
BRANCH(Int32Equal(*pos, *i), &adjustPos, &setValue);
Bind(&setValue);
{
SetValueToTaggedArray(VariableType::JS_ANY(), glue_, keyArray, *pos, element);
Jump(&adjustPos);
}
Bind(&adjustPos);
{
pos = Int32Add(*pos, Int32(1));
Jump(&loopEnd);
}
}
}
Bind(&loopEnd);
i = Int32Add(*i, Int32(1));
LoopEndWithCheckSafePoint(&loopHead, env, glue_);
}
Bind(&loopExit);
BRANCH(Int32UnsignedLessThan(*pos, keyLen), &needTrim, &setResult);
Bind(&needTrim);
{
CallNGCRuntime(glue_, RTSTUB_ID(ArrayTrim), {glue_, keyArray, ZExtInt32ToInt64(*pos)});
Jump(&setResult);
}
Bind(&setResult);
{
*result = newBuilder.CreateArrayFromList(glue_, keyArray, elementKind);
Jump(exit);
}
}
}
}
}
}
}
GateRef BuiltinsObjectStubBuilder::GetAllElementKeys(GateRef glue, GateRef obj, GateRef offset, GateRef array)
{
auto env = GetEnvironment();
Label subEntry(env);
env->SubCfgEntry(&subEntry);
DEFVARIABLE(i, VariableType::INT32(), offset);
DEFVARIABLE(j, VariableType::INT32(), Int32(0));
DEFVARIABLE(pos, VariableType::INT32(), Int32(0));
DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
Label isJSPrimitiveRef(env);
Label isPrimitiveString(env);
Label notPrimitiveString(env);
BRANCH(IsJSPrimitiveRef(glue, obj), &isJSPrimitiveRef, ¬PrimitiveString);
Bind(&isJSPrimitiveRef);
{
GateRef value = Load(VariableType::JS_ANY(), glue, obj, IntPtr(JSPrimitiveRef::VALUE_OFFSET));
BRANCH(TaggedIsString(glue, value), &isPrimitiveString, ¬PrimitiveString);
Bind(&isPrimitiveString);
{
Label loopHead(env);
Label loopEnd(env);
Label next(env);
GateRef elementIndex = Int32Add(GetLengthFromString(value), offset);
Jump(&loopHead);
LoopBegin(&loopHead);
{
BRANCH(Int32UnsignedLessThan(*i, elementIndex), &next, ¬PrimitiveString);
Bind(&next);
{
GateRef str = IntToEcmaString(glue, *i);
SetValueToTaggedArray(VariableType::JS_ANY(), glue, array, *pos, str);
pos = Int32Add(*pos, Int32(1));
Jump(&loopEnd);
}
Bind(&loopEnd);
i = Int32Add(*i, Int32(1));
LoopEndWithCheckSafePoint(&loopHead, env, glue);
}
}
}
Bind(¬PrimitiveString);
{
Label isDictMode(env);
Label notDictMode(env);
Label exit(env);
GateRef elements = GetElementsArray(glue, obj);
BRANCH(IsDictionaryMode(glue, elements), &isDictMode, ¬DictMode);
Bind(&isDictMode);
{
FatalPrint(glue, { Int32(GET_MESSAGE_STRING_ID(ThisBranchIsUnreachable)) });
Jump(&exit);
}
Bind(¬DictMode);
{
Label loopHead(env);
Label loopEnd(env);
Label next(env);
Label loopExit(env);
GateRef elementsLen = GetLengthOfTaggedArray(elements);
Jump(&loopHead);
LoopBegin(&loopHead);
{
Label notHole(env);
BRANCH(Int32UnsignedLessThan(*j, elementsLen), &next, &loopExit);
Bind(&next);
{
GateRef element = GetTaggedValueWithElementsKind(glue, obj, *j);
BRANCH(TaggedIsHole(element), &loopEnd, ¬Hole);
Bind(¬Hole);
{
GateRef str = IntToEcmaString(glue, *j);
SetValueToTaggedArray(VariableType::JS_ANY(), glue, array, *pos, str);
pos = Int32Add(*pos, Int32(1));
Jump(&loopEnd);
}
}
Bind(&loopEnd);
j = Int32Add(*j, Int32(1));
LoopEndWithCheckSafePoint(&loopHead, env, glue);
Bind(&loopExit);
result = array;
Jump(&exit);
}
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
}
GateRef BuiltinsObjectStubBuilder::GetAllPropertyKeys(GateRef glue, GateRef obj, GateRef offset, GateRef array)
{
auto env = GetEnvironment();
Label subEntry(env);
env->SubCfgEntry(&subEntry);
DEFVARIABLE(i, VariableType::INT32(), Int32(0));
DEFVARIABLE(pos, VariableType::INT32(), Int32(0));
DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
Label isDictionary(env);
Label notDictionary(env);
Label exit(env);
GateRef properties = GetPropertiesArray(glue, obj);
BRANCH(IsDictionaryMode(glue, properties), &isDictionary, ¬Dictionary);
Bind(&isDictionary);
{
FatalPrint(glue, { Int32(GET_MESSAGE_STRING_ID(ThisBranchIsUnreachable)) });
Jump(&exit);
}
Bind(¬Dictionary);
{
Label loopHead(env);
Label loopEnd(env);
Label next(env);
Label loopExit(env);
GateRef hclass = LoadHClass(glue, obj);
GateRef layout = GetLayoutFromHClass(glue, hclass);
GateRef number = GetNumberOfPropsFromHClass(hclass);
Jump(&loopHead);
LoopBegin(&loopHead);
{
BRANCH(Int32UnsignedLessThan(*i, number), &next, &loopExit);
Bind(&next);
{
Label checkSymbol(env);
Label setValue(env);
GateRef key = GetKey(glue, layout, *i);
BRANCH(TaggedIsString(glue, key), &setValue, &checkSymbol);
Bind(&checkSymbol);
{
BRANCH(TaggedIsSymbol(glue, key), &setValue, &loopEnd);
}
Bind(&setValue);
{
SetValueToTaggedArray(VariableType::JS_ANY(), glue_, array, Int32Add(*pos, offset), key);
pos = Int32Add(*pos, Int32(1));
Jump(&loopEnd);
}
}
Bind(&loopEnd);
i = Int32Add(*i, Int32(1));
LoopEndWithCheckSafePoint(&loopHead, env, glue_);
}
Bind(&loopExit);
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
void BuiltinsObjectStubBuilder::Entries(Variable* result, Label* exit, Label* slowPath)
{
auto env = GetEnvironment();
Label isPendingException(env);
Label noPendingException(env);
GateRef msg = GetCallArg0(numArgs_);
GateRef obj = ToObject(glue_, GetCurrentGlobalEnv(), msg);
NewObjectStubBuilder newBuilder(this, GetCurrentGlobalEnv());
BRANCH(HasPendingException(glue_), &isPendingException, &noPendingException);
Bind(&isPendingException);
{
Jump(exit);
}
Bind(&noPendingException);
{
Label isFast(env);
BRANCH(IsNotSlowObjectKey(obj), &isFast, slowPath);
Bind(&isFast);
{
Label notDictMode(env);
GateRef isDictMode = LogicOrBuilder(env).Or(IsDictionaryMode(glue_, GetElementsArray(glue_, obj)))
.Or(IsDictionaryMode(glue_, GetPropertiesArray(glue_, obj))).Done();
BRANCH(isDictMode, slowPath, ¬DictMode);
Bind(¬DictMode);
{
Label hasKeyAndEle(env);
Label nonKeyAndEle(env);
GateRef elementArray = GetEnumElementEntries(glue_, obj, slowPath);
GateRef propertyArray = GetEnumPropertyEntries(glue_, obj, slowPath);
GateRef elementLen = GetLengthOfTaggedArray(elementArray);
GateRef propertyLen = GetLengthOfTaggedArray(propertyArray);
GateRef elementKind = Int32(Elements::ToUint(ElementsKind::GENERIC));
GateRef keyAndEle = BitAnd(Int32NotEqual(elementLen, Int32(0)), Int32NotEqual(propertyLen, Int32(0)));
BRANCH(keyAndEle, &hasKeyAndEle, &nonKeyAndEle);
Bind(&hasKeyAndEle);
{
GateRef allEntries = AppendSkipHole(glue_, elementArray, propertyArray,
Int32Add(elementLen, propertyLen));
*result = newBuilder.CreateArrayFromList(glue_, allEntries, elementKind);
Jump(exit);
}
Bind(&nonKeyAndEle);
{
Label hasKey(env);
Label nonKey(env);
BRANCH(Int32NotEqual(propertyLen, Int32(0)), &hasKey, &nonKey);
Bind(&hasKey);
{
*result = newBuilder.CreateArrayFromList(glue_, propertyArray, elementKind);
Jump(exit);
}
Bind(&nonKey);
{
Label hasEle(env);
Label nonEle(env);
BRANCH(Int32NotEqual(elementLen, Int32(0)), &hasEle, &nonEle);
Bind(&hasEle);
{
*result = newBuilder.CreateArrayFromList(glue_, elementArray, elementKind);
Jump(exit);
}
Bind(&nonEle);
{
GateRef emptyArray = GetEmptyArray(glue_);
*result = newBuilder.CreateArrayFromList(glue_, emptyArray, elementKind);
Jump(exit);
}
}
}
}
}
}
}
GateRef BuiltinsObjectStubBuilder::GetEnumElementEntries(GateRef glue, GateRef obj, Label* slowPath)
{
auto env = GetEnvironment();
Label subEntry(env);
env->SubCfgEntry(&subEntry);
DEFVARIABLE(idx, VariableType::INT32(), Int32(0));
DEFVARIABLE(pos, VariableType::INT32(), Int32(0));
GateRef elementKeys = GetEnumElementKeys(glue, obj);
GateRef elements = GetElementsArray(glue, obj);
GateRef len = GetLengthOfTaggedArray(elements);
GateRef realLen = GetLengthOfTaggedArray(elementKeys);
NewObjectStubBuilder newBuilder(this, GetCurrentGlobalEnv());
GateRef numElementArray = newBuilder.NewTaggedArray(glue, realLen);
GateRef elementKind = Int32(Elements::ToUint(ElementsKind::TAGGED));
Label isJSPrimitiveRef(env);
Label notPrimitiveString(env);
Label notDictMode(env);
BRANCH(IsJSPrimitiveRef(glue, obj), &isJSPrimitiveRef, ¬PrimitiveString);
Bind(&isJSPrimitiveRef);
GateRef els = Load(VariableType::JS_ANY(), glue, obj, IntPtr(JSPrimitiveRef::VALUE_OFFSET));
BRANCH(TaggedIsString(glue, els), slowPath, ¬PrimitiveString);
Bind(¬PrimitiveString);
BRANCH(IsDictionaryMode(glue, elements), slowPath, ¬DictMode);
Bind(¬DictMode);
{
Label loopHead(env);
Label loopEnd(env);
Label LoopNext(env);
Label loopExit(env);
Jump(&loopHead);
LoopBegin(&loopHead);
{
BRANCH(Int32LessThan(*idx, len), &LoopNext, &loopExit);
Bind(&LoopNext);
GateRef value = GetTaggedValueWithElementsKind(glue, obj, *idx);
Label notHole(env);
BRANCH(TaggedIsHole(value), &loopEnd, ¬Hole);
Bind(¬Hole);
{
GateRef arrayProp = newBuilder.NewTaggedArray(glue, Int32(2));
GateRef str = IntToEcmaString(glue, *idx);
SetValueToTaggedArray(VariableType::JS_ANY(), glue, arrayProp, Int32(0), str);
SetValueToTaggedArray(VariableType::JS_ANY(), glue, arrayProp, Int32(1), value);
GateRef propArray = newBuilder.CreateArrayFromList(glue, arrayProp, elementKind);
SetValueToTaggedArray(VariableType::JS_ANY(), glue, numElementArray, *pos, propArray);
pos = Int32Add(*pos, Int32(1));
Jump(&loopEnd);
}
}
Bind(&loopEnd);
idx = Int32Add(*idx, Int32(1));
LoopEndWithCheckSafePoint(&loopHead, env, glue);
Bind(&loopExit);
auto ret = numElementArray;
env->SubCfgExit();
return ret;
}
}
GateRef BuiltinsObjectStubBuilder::GetEnumPropertyEntries(GateRef glue, GateRef obj, Label* slowPath)
{
auto env = GetEnvironment();
Label subEntry(env);
env->SubCfgEntry(&subEntry);
Label exit(env);
Label notDictionary(env);
GateRef array = GetPropertiesArray(glue, obj);
BRANCH(IsDictionaryMode(glue, array), slowPath, ¬Dictionary);
Bind(¬Dictionary);
DEFVARIABLE(idx, VariableType::INT32(), Int32(0));
DEFVARIABLE(length, VariableType::INT32(), Int32(0));
GateRef cls = LoadHClass(glue, obj);
GateRef len = GetNumberOfPropsFromHClass(cls);
GateRef layout = GetLayoutFromHClass(glue, cls);
NewObjectStubBuilder newBuilder(this, GetCurrentGlobalEnv());
GateRef allEnumArray = newBuilder.NewTaggedArray(glue, len);
GateRef elementKind = Int32(Elements::ToUint(ElementsKind::TAGGED));
Label loopHead(env);
Label loopEnd(env);
Label LoopNext(env);
Label loopExit(env);
Label propertyIsEnumerable(env);
Label propertyIsString(env);
Jump(&loopHead);
LoopBegin(&loopHead);
{
BRANCH(Int32LessThan(*idx, len), &LoopNext, &loopExit);
Bind(&LoopNext);
GateRef arrayProp = newBuilder.NewTaggedArray(glue, Int32(2));
GateRef key = GetKeyFromLayoutInfo(glue, layout, *idx);
GateRef attr = GetPropAttrFromLayoutInfo(glue, layout, *idx);
GateRef value = JSObjectGetPropertyWithRep(glue, obj, cls, attr);
Label notAccessor(env);
BRANCH(IsAccessor(attr), slowPath, ¬Accessor);
Bind(¬Accessor);
BRANCH(IsEnumerable(attr), &propertyIsEnumerable, &loopEnd);
Bind(&propertyIsEnumerable);
{
BRANCH(TaggedIsString(glue, key), &propertyIsString, &loopEnd);
Bind(&propertyIsString);
{
SetValueToTaggedArray(VariableType::JS_ANY(), glue, arrayProp, Int32(0), key);
SetValueToTaggedArray(VariableType::JS_ANY(), glue, arrayProp, Int32(1), value);
GateRef propArray = newBuilder.CreateArrayFromList(glue, arrayProp, elementKind);
SetValueToTaggedArray(VariableType::JS_ANY(), glue, allEnumArray, *length, propArray);
length = Int32Add(*length, Int32(1));
Jump(&loopEnd);
}
}
}
Bind(&loopEnd);
idx = Int32Add(*idx, Int32(1));
LoopEndWithCheckSafePoint(&loopHead, env, glue);
Bind(&loopExit);
Label needTrim(env);
BRANCH(Int32LessThan(*length, len), &needTrim, &exit);
Bind(&needTrim);
{
CallNGCRuntime(glue, RTSTUB_ID(ArrayTrim), {glue, allEnumArray, ZExtInt32ToInt64(*length)});
Jump(&exit);
}
Bind(&exit);
auto ret = allEnumArray;
env->SubCfgExit();
return ret;
}
void BuiltinsObjectStubBuilder::IsFrozen(Variable *result, Label *exit, Label *slowPath)
{
auto env = GetEnvironment();
GateRef obj = GetCallArg0(numArgs_);
Label isEcmaObj(env);
Label notEcmaObj(env);
BRANCH(BoolNot(IsEcmaObject(glue_, obj)), ¬EcmaObj, &isEcmaObj);
Bind(¬EcmaObj);
{
result->WriteVariable(TaggedTrue());
Jump(exit);
}
Bind(&isEcmaObj);
{
GateRef status = TestIntegrityLevel(glue_, obj, Int32(1), slowPath);
Label statusIsTrue(env);
Label statusIsFalse(env);
BRANCH(status, &statusIsTrue, &statusIsFalse);
Bind(&statusIsTrue);
{
result->WriteVariable(TaggedTrue());
Jump(exit);
}
Bind(&statusIsFalse);
{
result->WriteVariable(TaggedFalse());
Jump(exit);
}
}
}
void BuiltinsObjectStubBuilder::IsSealed(Variable *result, Label *exit, Label *slowPath)
{
auto env = GetEnvironment();
GateRef obj = GetCallArg0(numArgs_);
Label isEcmaObj(env);
Label notEcmaObj(env);
BRANCH(BoolNot(IsEcmaObject(glue_, obj)), ¬EcmaObj, &isEcmaObj);
Bind(¬EcmaObj);
{
result->WriteVariable(TaggedTrue());
Jump(exit);
}
Bind(&isEcmaObj);
{
GateRef status = TestIntegrityLevel(glue_, obj, Int32(0), slowPath);
Label statusIsTrue(env);
Label statusIsFalse(env);
BRANCH(status, &statusIsTrue, &statusIsFalse);
Bind(&statusIsTrue);
{
result->WriteVariable(TaggedTrue());
Jump(exit);
}
Bind(&statusIsFalse);
{
result->WriteVariable(TaggedFalse());
Jump(exit);
}
}
}
GateRef BuiltinsObjectStubBuilder::TestIntegrityLevel(GateRef glue,
GateRef obj, GateRef level, Label *slowPath)
{
auto env = GetEnvironment();
Label entryPass(env);
env->SubCfgEntry(&entryPass);
DEFVARIABLE(result, VariableType::BOOL(), False());
Label isExtensible(env);
Label isNotExtensible(env);
Label exit(env);
Label isNotJsProxy(env);
Label isNotTypedArray(env);
Label isNotModuleNamespace(env);
Label isNotSpecialContainer(env);
Label notDicMode(env);
Label notHasElementKey(env);
BRANCH(IsJsProxy(glue, obj), slowPath, &isNotJsProxy);
Bind(&isNotJsProxy);
BRANCH(IsTypedArray(glue, obj), slowPath, &isNotTypedArray);
Bind(&isNotTypedArray);
BRANCH(IsModuleNamespace(glue, obj), slowPath, &isNotModuleNamespace);
Bind(&isNotModuleNamespace);
BRANCH(IsArrayListOrVector(GetObjectType(LoadHClass(glue, obj))), slowPath, &isNotSpecialContainer);
Bind(&isNotSpecialContainer);
GateRef cls = LoadHClass(glue, obj);
BRANCH(IsDictionaryModeByHClass(cls), slowPath, ¬DicMode);
Bind(¬DicMode);
GateRef layout = GetLayoutFromHClass(glue, cls);
GateRef lengthOfKeys = GetNumberOfPropsFromHClass(cls);
GateRef elementArray = GetEnumElementKeys(glue_, obj);
GateRef lengthOfElements = GetLengthOfTaggedArray(elementArray);
BRANCH(Int32Equal(lengthOfElements, Int32(0)), ¬HasElementKey, slowPath);
Bind(¬HasElementKey);
GateRef status = IsExtensible(glue, obj);
BRANCH(status, &isExtensible, &isNotExtensible);
Bind(&isExtensible);
{
result = False();
Jump(&exit);
}
Bind(&isNotExtensible);
{
Label lengthIsZero(env);
Label lengthNotZero(env);
BRANCH(Int32Equal(lengthOfKeys, Int32(0)), &lengthIsZero, &lengthNotZero);
Bind(&lengthIsZero);
{
result = True();
Jump(&exit);
}
Bind(&lengthNotZero);
{
DEFVARIABLE(index, VariableType::INT32(), Int32(0));
Label loopHead(env);
Label loopEnd(env);
Label afterLoop(env);
Label inRange(env);
Jump(&loopHead);
LoopBegin(&loopHead);
{
BRANCH(Int32LessThan(*index, lengthOfKeys), &inRange, &afterLoop);
Bind(&inRange);
{
GateRef attr = GetPropAttrFromLayoutInfo(glue, layout, *index);
Label configable(env);
Label notConfigable(env);
Label notFrozen(env);
BRANCH(IsConfigable(attr), &configable, ¬Configable);
Bind(&configable);
{
result = False();
Jump(&exit);
}
Bind(¬Configable);
{
GateRef isFrozen = LogicAndBuilder(env).And(Int32Equal(level, Int32(1)))
.And(BoolNot(IsAccessor(attr))).And(IsWritable(attr)).Done();
BRANCH(isFrozen, ¬Frozen, &loopEnd);
Bind(¬Frozen);
{
result = False();
Jump(&exit);
}
}
}
}
Bind(&loopEnd);
index = Int32Add(*index, Int32(1));
LoopEndWithCheckSafePoint(&loopHead, env, glue);
Bind(&afterLoop);
{
result = True();
Jump(&exit);
}
}
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
void BuiltinsObjectStubBuilder::GetOwnPropertyDescriptors(Variable *result, Label *exit, Label *slowPath)
{
auto env = GetEnvironment();
GateRef msg = GetCallArg0(numArgs_);
GateRef obj = ToObject(glue_, GetCurrentGlobalEnv(), msg);
Label isPendingException(env);
Label noPendingException(env);
BRANCH(HasPendingException(glue_), &isPendingException, &noPendingException);
Bind(&isPendingException);
{
Jump(exit);
}
Bind(&noPendingException);
Label isFast(env);
BRANCH(IsNotSlowObjectKey(obj), &isFast, slowPath);
Bind(&isFast);
Label notDictMode(env);
GateRef properties = GetPropertiesArray(glue_, obj);
BRANCH(IsDictionaryMode(glue_, properties), slowPath, ¬DictMode);
Bind(¬DictMode);
Label onlyProperties(env);
GateRef numOfElements = GetNumberOfElements(glue_, obj);
BRANCH(Int32Equal(numOfElements, Int32(0)), &onlyProperties, slowPath);
Bind(&onlyProperties);
DEFVARIABLE(i, VariableType::INT32(), Int32(0));
GateRef hclass = LoadHClass(glue_, obj);
GateRef layout = GetLayoutFromHClass(glue_, hclass);
GateRef number = GetNumberOfPropsFromHClass(hclass);
GateRef valueStr = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_, ConstantIndex::VALUE_STRING_INDEX);
GateRef getterStr = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_, ConstantIndex::GET_STRING_INDEX);
GateRef setterStr = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_, ConstantIndex::SET_STRING_INDEX);
GateRef writableStr = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_,
ConstantIndex::WRITABLE_STRING_INDEX);
GateRef enumerableStr = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_,
ConstantIndex::ENUMERABLE_STRING_INDEX);
GateRef configurableStr = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_,
ConstantIndex::CONFIGURABLE_STRING_INDEX);
NewObjectStubBuilder newBuilder(this, GetCurrentGlobalEnv());
newBuilder.SetParameters(glue_, 0);
GateRef descriptors = newBuilder.CreateEmptyObject(glue_);
Label loopHead(env);
Label loopEnd(env);
Label next(env);
Label loopExit(env);
Jump(&loopHead);
LoopBegin(&loopHead);
{
BRANCH(Int32UnsignedLessThan(*i, number), &next, &loopExit);
Bind(&next);
{
Label isAccessor(env);
Label setValueAndIsWritable(env);
Label setIsEnumerable(env);
Label setIsConfigable(env);
Label setDescriptor(env);
GateRef key = GetKey(glue_, layout, *i);
GateRef attr = GetAttr(glue_, layout, *i);
GateRef descriptor = newBuilder.CreateEmptyObject(glue_);
DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
value = JSObjectGetPropertyWithRep(glue_, obj, hclass, attr);
BRANCH(IsAccessor(attr), &isAccessor, &setValueAndIsWritable);
Bind(&isAccessor);
{
Label propertyBox(env);
Label checkInternalAccessor(env);
BRANCH(TaggedIsPropertyBox(glue_, *value), &propertyBox, &checkInternalAccessor);
Bind(&propertyBox);
{
value = GetValueFromPropertyBox(glue_, *value);
Jump(&checkInternalAccessor);
}
Bind(&checkInternalAccessor);
Label isInternalAccesstor(env);
Label notInternalAccesstor(env);
BRANCH_UNLIKELY(TaggedIsInternalAccessor(glue_, *value), &isInternalAccesstor, ¬InternalAccesstor);
Bind(&isInternalAccesstor);
{
value = CallGetterHelper(glue_, obj, obj, *value, ProfileOperation());
Jump(&setValueAndIsWritable);
}
Bind(¬InternalAccesstor);
{
Label setGetter(env);
Label getSetter(env);
Label setSetter(env);
GateRef getter = GetAccGetter(glue_, *value);
BRANCH(TaggedIsHeapObject(getter), &setGetter, &getSetter);
Bind(&setGetter);
{
FastSetPropertyByName(glue_, descriptor, getterStr, getter);
Jump(&getSetter);
}
Bind(&getSetter);
GateRef setter = GetAccSetter(glue_, *value);
BRANCH(TaggedIsHeapObject(setter), &setSetter, &setIsEnumerable);
Bind(&setSetter);
{
FastSetPropertyByName(glue_, descriptor, setterStr, setter);
Jump(&setIsEnumerable);
}
}
}
Bind(&setValueAndIsWritable);
{
Label isWritable(env);
Label notWritable(env);
FastSetPropertyByName(glue_, descriptor, valueStr, *value);
BRANCH(IsWritable(attr), &isWritable, ¬Writable);
Bind(&isWritable);
{
FastSetPropertyByName(glue_, descriptor, writableStr, TaggedTrue());
Jump(&setIsEnumerable);
}
Bind(¬Writable);
{
FastSetPropertyByName(glue_, descriptor, writableStr, TaggedFalse());
Jump(&setIsEnumerable);
}
}
Bind(&setIsEnumerable);
{
Label isEnumerable(env);
Label notEnumerable(env);
BRANCH(IsEnumerable(attr), &isEnumerable, ¬Enumerable);
Bind(&isEnumerable);
{
FastSetPropertyByName(glue_, descriptor, enumerableStr, TaggedTrue());
Jump(&setIsConfigable);
}
Bind(¬Enumerable);
{
FastSetPropertyByName(glue_, descriptor, enumerableStr, TaggedFalse());
Jump(&setIsConfigable);
}
}
Bind(&setIsConfigable);
{
Label isConfigable(env);
Label notConfigable(env);
BRANCH(IsConfigable(attr), &isConfigable, ¬Configable);
Bind(&isConfigable);
{
FastSetPropertyByName(glue_, descriptor, configurableStr, TaggedTrue());
Jump(&setDescriptor);
}
Bind(¬Configable);
{
FastSetPropertyByName(glue_, descriptor, configurableStr, TaggedFalse());
Jump(&setDescriptor);
}
}
Bind(&setDescriptor);
{
FastSetPropertyByName(glue_, descriptors, key, descriptor);
Jump(&loopEnd);
}
}
}
Bind(&loopEnd);
i = Int32Add(*i, Int32(1));
LoopEndWithCheckSafePoint(&loopHead, env, glue_);
Bind(&loopExit);
*result = descriptors;
Jump(exit);
}
}