Skip to content

Commit 83c8a12

Browse files
committed
Implementing Object.values and Object.entries as per ES7 proposal https://github.com/tc39/proposal-object-values-entries/blob/master/spec.md
1 parent 59b31e5 commit 83c8a12

File tree

6 files changed

+342
-1
lines changed

6 files changed

+342
-1
lines changed

lib/Runtime/Library/JavascriptBuiltInFunctionList.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ BUILTIN(JavascriptObject, LookupGetter, EntryLookupGetter, FunctionInfo::ErrorOn
177177
BUILTIN(JavascriptObject, LookupSetter, EntryLookupSetter, FunctionInfo::ErrorOnNew)
178178
BUILTIN(JavascriptObject, Is, EntryIs, FunctionInfo::ErrorOnNew)
179179
BUILTIN(JavascriptObject, Assign, EntryAssign, FunctionInfo::ErrorOnNew)
180+
BUILTIN(JavascriptObject, Values, EntryValues, FunctionInfo::ErrorOnNew)
181+
BUILTIN(JavascriptObject, Entries, EntryEntries, FunctionInfo::ErrorOnNew)
180182
BUILTIN(ObjectPrototypeObject, __proto__getter, Entry__proto__getter, FunctionInfo::ErrorOnNew | FunctionInfo::DoNotProfile)
181183
BUILTIN(ObjectPrototypeObject, __proto__setter, Entry__proto__setter, FunctionInfo::ErrorOnNew | FunctionInfo::DoNotProfile)
182184
BUILTIN(JavascriptRegExp, NewInstance, NewInstance, FunctionInfo::SkipDefaultNewObject)

lib/Runtime/Library/JavascriptLibrary.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3602,6 +3602,14 @@ namespace Js
36023602
library->AddFunctionToLibraryObject(objectConstructor, PropertyIds::assign, &JavascriptObject::EntryInfo::Assign, 2));
36033603
}
36043604

3605+
if (scriptContext->GetConfig()->IsES7BuiltinsEnabled())
3606+
{
3607+
scriptContext->SetBuiltInLibraryFunction(JavascriptObject::EntryInfo::Values.GetOriginalEntryPoint(),
3608+
library->AddFunctionToLibraryObject(objectConstructor, PropertyIds::values, &JavascriptObject::EntryInfo::Values, 1));
3609+
scriptContext->SetBuiltInLibraryFunction(JavascriptObject::EntryInfo::Entries.GetOriginalEntryPoint(),
3610+
library->AddFunctionToLibraryObject(objectConstructor, PropertyIds::entries, &JavascriptObject::EntryInfo::Entries, 1));
3611+
}
3612+
36053613
objectConstructor->SetHasNoEnumerableProperties(true);
36063614
}
36073615

@@ -6183,6 +6191,12 @@ namespace Js
61836191
REG_OBJECTS_LIB_FUNC(assign, JavascriptObject::EntryAssign);
61846192
}
61856193

6194+
if (config.IsES7BuiltinsEnabled())
6195+
{
6196+
REG_OBJECTS_LIB_FUNC(values, JavascriptObject::EntryValues);
6197+
REG_OBJECTS_LIB_FUNC(entries, JavascriptObject::EntryEntries);
6198+
}
6199+
61866200
return hr;
61876201
}
61886202

lib/Runtime/Library/JavascriptObject.cpp

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,6 +1096,92 @@ namespace Js
10961096
return JavascriptOperators::GetOwnEnumerablePropertyNames(object, scriptContext);
10971097
}
10981098

1099+
Var JavascriptObject::GetValuesOrEntries(RecyclableObject* object, bool valuesToReturn, ScriptContext* scriptContext)
1100+
{
1101+
Assert(object != nullptr);
1102+
Assert(scriptContext != nullptr);
1103+
JavascriptArray* valuesArray = scriptContext->GetLibrary()->CreateArray(0);
1104+
1105+
Var ownKeysVar = JavascriptOperators::GetOwnPropertyNames(object, scriptContext);
1106+
JavascriptArray* ownKeysResult = nullptr;
1107+
if (JavascriptArray::Is(ownKeysVar))
1108+
{
1109+
ownKeysResult = JavascriptArray::FromVar(ownKeysVar);
1110+
}
1111+
else
1112+
{
1113+
return valuesArray;
1114+
}
1115+
1116+
uint32 length = ownKeysResult->GetLength();
1117+
1118+
Var nextKey;
1119+
const PropertyRecord* propertyRecord = nullptr;
1120+
PropertyId propertyId;
1121+
for (uint32 i = 0, index = 0; i < length; i++)
1122+
{
1123+
nextKey = ownKeysResult->DirectGetItem(i);
1124+
Assert(JavascriptString::Is(nextKey));
1125+
1126+
PropertyDescriptor propertyDescriptor;
1127+
1128+
BOOL propertyKeyResult = JavascriptConversion::ToPropertyKey(nextKey, scriptContext, &propertyRecord);
1129+
Assert(propertyKeyResult);
1130+
propertyId = propertyRecord->GetPropertyId();
1131+
Assert(propertyId != Constants::NoProperty);
1132+
if (JavascriptOperators::GetOwnPropertyDescriptor(object, propertyId, scriptContext, &propertyDescriptor))
1133+
{
1134+
if (propertyDescriptor.IsEnumerable())
1135+
{
1136+
Var value = JavascriptOperators::GetProperty(object, propertyId, scriptContext);
1137+
if (!valuesToReturn)
1138+
{
1139+
// For Object.entries each entry is key, value pair
1140+
JavascriptArray* entry = scriptContext->GetLibrary()->CreateArray(2);
1141+
entry->DirectSetItemAt(0, CrossSite::MarshalVar(scriptContext, nextKey));
1142+
entry->DirectSetItemAt(1, CrossSite::MarshalVar(scriptContext, value));
1143+
value = entry;
1144+
}
1145+
valuesArray->DirectSetItemAt(index++, CrossSite::MarshalVar(scriptContext, value));
1146+
}
1147+
}
1148+
}
1149+
1150+
return valuesArray;
1151+
}
1152+
1153+
Var JavascriptObject::EntryValues(RecyclableObject* function, CallInfo callInfo, ...)
1154+
{
1155+
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
1156+
1157+
ARGUMENTS(args, callInfo);
1158+
ScriptContext* scriptContext = function->GetScriptContext();
1159+
1160+
Assert(!(callInfo.Flags & CallFlags_New));
1161+
CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(ObjectValuesCount);
1162+
1163+
Var tempVar = args.Info.Count < 2 ? scriptContext->GetLibrary()->GetUndefined() : args[1];
1164+
RecyclableObject *object = RecyclableObject::FromVar(JavascriptOperators::ToObject(tempVar, scriptContext));
1165+
1166+
return GetValuesOrEntries(object, true /*valuesToReturn*/, scriptContext);
1167+
}
1168+
1169+
Var JavascriptObject::EntryEntries(RecyclableObject* function, CallInfo callInfo, ...)
1170+
{
1171+
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
1172+
1173+
ARGUMENTS(args, callInfo);
1174+
ScriptContext* scriptContext = function->GetScriptContext();
1175+
1176+
Assert(!(callInfo.Flags & CallFlags_New));
1177+
CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(ObjectEntriesCount);
1178+
1179+
Var tempVar = args.Info.Count < 2 ? scriptContext->GetLibrary()->GetUndefined() : args[1];
1180+
RecyclableObject *object = RecyclableObject::FromVar(JavascriptOperators::ToObject(tempVar, scriptContext));
1181+
1182+
return GetValuesOrEntries(object, false /*valuesToReturn*/, scriptContext);
1183+
}
1184+
10991185
Var JavascriptObject::CreateOwnSymbolPropertiesHelper(RecyclableObject* object, ScriptContext* scriptContext)
11001186
{
11011187
return CreateKeysHelper(object, scriptContext, TRUE, true /*includeSymbolsOnly */, false, true /*includeSpecialProperties*/);

lib/Runtime/Library/JavascriptObject.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ namespace Js
4747
static FunctionInfo LookupSetter;
4848
static FunctionInfo Is;
4949
static FunctionInfo Assign;
50+
static FunctionInfo Values;
51+
static FunctionInfo Entries;
5052
};
5153

5254
static Var NewInstance(RecyclableObject* function, CallInfo callInfo, ...);
@@ -77,7 +79,8 @@ namespace Js
7779
static Var EntryLookupSetter(RecyclableObject* function, CallInfo callInfo, ...);
7880
static Var EntryIs(RecyclableObject* function, CallInfo callInfo, ...);
7981
static Var EntryAssign(RecyclableObject* function, CallInfo callInfo, ...);
80-
82+
static Var EntryValues(RecyclableObject* function, CallInfo callInfo, ...);
83+
static Var EntryEntries(RecyclableObject* function, CallInfo callInfo, ...);
8184

8285
static Var GetPrototypeOf(RecyclableObject* obj, ScriptContext* scriptContext);
8386
static BOOL ChangePrototype(RecyclableObject* object, RecyclableObject* newPrototype, bool validate, ScriptContext* scriptContext);
@@ -91,6 +94,9 @@ namespace Js
9194
static Var GetOwnPropertyDescriptorHelper(RecyclableObject* obj, Var propertyKey, ScriptContext* scriptContext);
9295
static BOOL GetOwnPropertyDescriptorHelper(RecyclableObject* obj, PropertyId propertyId, ScriptContext* scriptContext, PropertyDescriptor& propertyDescriptor);
9396

97+
// Param valuesToReturn should be set to true when we are looking for values from an object otherwise entries will be returned
98+
static Var GetValuesOrEntries(RecyclableObject* object, bool valuesToReturn, ScriptContext* scriptContext);
99+
94100
// Presently used in the projection as a mechanism of calling the general object prototype toString.
95101
static JavascriptString* ToStringInternal(Var thisArg, ScriptContext* scriptContext)
96102
{

test/es7/rlexe.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,11 @@
3838
<compile-flags>-es7asyncawait -es6tostringtag -args summary -endargs</compile-flags>
3939
</default>
4040
</test>
41+
<test>
42+
<default>
43+
<files>valuesAndEntries.js</files>
44+
<compile-flags>-ES7Builtins -args summary -endargs</compile-flags>
45+
<tags>BugFix</tags>
46+
</default>
47+
</test>
4148
</regress-exe>

0 commit comments

Comments
 (0)