Skip to content

Commit 1dc1d36

Browse files
art-snakeCommit Queue
authored andcommitted
[vm] Add C Api for maps making.
Also allow to write simple conversions from std::map to "Dart Map" using "c++ template magic". [email protected] TEST=vm/cc/DartAPI_MapCreate Bug: nothing Change-Id: I11f3271df6880825bd417ee5532c56bacfa7278d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/449280 Auto-Submit: Art Snake <[email protected]> Commit-Queue: Slava Egorov <[email protected]> Reviewed-by: Alexander Markov <[email protected]> Reviewed-by: Slava Egorov <[email protected]>
1 parent e41640d commit 1dc1d36

File tree

7 files changed

+233
-0
lines changed

7 files changed

+233
-0
lines changed

runtime/bin/dart_api_win.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,10 @@ typedef Dart_Handle (*Dart_ListSetAsBytesType)(Dart_Handle,
244244
typedef Dart_Handle (*Dart_MapGetAtType)(Dart_Handle, Dart_Handle);
245245
typedef Dart_Handle (*Dart_MapContainsKeyType)(Dart_Handle, Dart_Handle);
246246
typedef Dart_Handle (*Dart_MapKeysType)(Dart_Handle);
247+
typedef Dart_Handle (*Dart_NewMapType)(Dart_Handle,
248+
Dart_Handle,
249+
Dart_Handle,
250+
Dart_Handle);
247251
typedef Dart_TypedData_Type (*Dart_GetTypeOfTypedDataType)(Dart_Handle);
248252
typedef Dart_TypedData_Type (*Dart_GetTypeOfExternalTypedDataType)(Dart_Handle);
249253
typedef Dart_Handle (*Dart_NewTypedDataType)(Dart_TypedData_Type, intptr_t);
@@ -650,6 +654,7 @@ static Dart_ListSetAsBytesType Dart_ListSetAsBytesFn = NULL;
650654
static Dart_MapGetAtType Dart_MapGetAtFn = NULL;
651655
static Dart_MapContainsKeyType Dart_MapContainsKeyFn = NULL;
652656
static Dart_MapKeysType Dart_MapKeysFn = NULL;
657+
static Dart_NewMapType Dart_NewMapFn = NULL;
653658
static Dart_GetTypeOfTypedDataType Dart_GetTypeOfTypedDataFn = NULL;
654659
static Dart_GetTypeOfExternalTypedDataType Dart_GetTypeOfExternalTypedDataFn =
655660
NULL;
@@ -1135,6 +1140,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
11351140
Dart_MapContainsKeyFn =
11361141
(Dart_MapContainsKeyType)GetProcAddress(process, "Dart_MapContainsKey");
11371142
Dart_MapKeysFn = (Dart_MapKeysType)GetProcAddress(process, "Dart_MapKeys");
1143+
Dart_NewMapFn = (Dart_NewMapType)GetProcAddress(process, "Dart_NewMap");
11381144
Dart_GetTypeOfTypedDataFn = (Dart_GetTypeOfTypedDataType)GetProcAddress(
11391145
process, "Dart_GetTypeOfTypedData");
11401146
Dart_GetTypeOfExternalTypedDataFn =
@@ -2161,6 +2167,13 @@ Dart_Handle Dart_MapKeys(Dart_Handle map) {
21612167
return Dart_MapKeysFn(map);
21622168
}
21632169

2170+
Dart_Handle Dart_NewMap(Dart_Handle keys_type,
2171+
Dart_Handle keys_handle,
2172+
Dart_Handle values_type,
2173+
Dart_Handle values_handle) {
2174+
return Dart_NewMapFn(keys_type, keys_handle, values_type, values_handle);
2175+
}
2176+
21642177
Dart_TypedData_Type Dart_GetTypeOfTypedData(Dart_Handle object) {
21652178
return Dart_GetTypeOfTypedDataFn(object);
21662179
}

runtime/include/dart_api.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2603,6 +2603,26 @@ DART_EXPORT Dart_Handle Dart_MapContainsKey(Dart_Handle map, Dart_Handle key);
26032603
*/
26042604
DART_EXPORT Dart_Handle Dart_MapKeys(Dart_Handle map);
26052605

2606+
/**
2607+
* Returns a Map filled by key value pairs from the provided lists.
2608+
*
2609+
* \param keys_type Handle to a type of keys. E.g., from
2610+
* Dart_Get<XXX>Type.
2611+
* \param keys_handle Handle to a list with keys. E.g., from
2612+
* Dart_NewList<XXX>.
2613+
* \param values_type Handle to a type of values. E.g., from
2614+
* Dart_Get<XXX>Type.
2615+
* \param values_handle Handle to a list with values. E.g., from
2616+
* Dart_NewList<XXX>.
2617+
*
2618+
* \return The Map object if no error occurs. Otherwise returns
2619+
* an error handle.
2620+
*/
2621+
DART_EXPORT Dart_Handle Dart_NewMap(Dart_Handle keys_type,
2622+
Dart_Handle keys_handle,
2623+
Dart_Handle values_type,
2624+
Dart_Handle values_handle);
2625+
26062626
/*
26072627
* ==========
26082628
* Typed Data

runtime/tests/vm/dart/exported_symbols_test.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ main() {
255255
"Dart_NewList",
256256
"Dart_NewListOfType",
257257
"Dart_NewListOfTypeFilled",
258+
"Dart_NewMap",
258259
"Dart_NewNativePort",
259260
"Dart_NewPersistentHandle",
260261
"Dart_NewSendPort",

runtime/vm/dart_api_impl.cc

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3174,6 +3174,76 @@ DART_EXPORT Dart_Handle Dart_NewListOfType(Dart_Handle element_type,
31743174
return Api::NewHandle(T, Array::New(length, type));
31753175
}
31763176

3177+
DART_EXPORT Dart_Handle Dart_NewMap(Dart_Handle keys_type,
3178+
Dart_Handle keys_handle,
3179+
Dart_Handle values_type,
3180+
Dart_Handle values_handle) {
3181+
{ // Validate that keys and values are lists.
3182+
if (!Dart_IsList(keys_handle)) {
3183+
return Api::NewError("%s expects argument 'keys_handle' to be a list.",
3184+
CURRENT_FUNC);
3185+
}
3186+
if (!Dart_IsList(values_handle)) {
3187+
return Api::NewError("%s expects argument 'values_handle' to be a list.",
3188+
CURRENT_FUNC);
3189+
}
3190+
}
3191+
{ // Validate length of keys and values
3192+
intptr_t keys_len = 0;
3193+
intptr_t values_len = 0;
3194+
Dart_Handle api_result = Dart_ListLength(keys_handle, &keys_len);
3195+
if (Dart_IsError(api_result)) {
3196+
return api_result;
3197+
}
3198+
api_result = Dart_ListLength(values_handle, &values_len);
3199+
if (Dart_IsError(api_result)) {
3200+
return api_result;
3201+
}
3202+
if (keys_len != values_len) {
3203+
return Api::NewError(
3204+
"%s expects length of 'keys_handle' list to be equal to length of "
3205+
"'values_handle' list.",
3206+
CURRENT_FUNC);
3207+
}
3208+
}
3209+
3210+
DARTSCOPE(Thread::Current());
3211+
CHECK_CALLBACK_STATE(T);
3212+
3213+
const Type& keys_type_obj = Api::UnwrapTypeHandle(Z, keys_type);
3214+
if (keys_type_obj.IsNull()) {
3215+
RETURN_TYPE_ERROR(Z, keys_type, Type);
3216+
}
3217+
const Type& values_type_obj = Api::UnwrapTypeHandle(Z, values_type);
3218+
if (values_type_obj.IsNull()) {
3219+
RETURN_TYPE_ERROR(Z, values_type, Type);
3220+
}
3221+
const Object& keys_obj = Object::Handle(Z, Api::UnwrapHandle(keys_handle));
3222+
const Object& values_obj =
3223+
Object::Handle(Z, Api::UnwrapHandle(values_handle));
3224+
3225+
// Init type arguments
3226+
auto& type_arguments =
3227+
TypeArguments::Handle(Z, TypeArguments::New(2, Heap::kOld));
3228+
type_arguments.SetTypeAt(0, keys_type_obj);
3229+
type_arguments.SetTypeAt(1, values_type_obj);
3230+
type_arguments ^= type_arguments.Canonicalize(T);
3231+
3232+
const Class& map_class =
3233+
Class::Handle(Z, T->isolate_group()->object_store()->map_class());
3234+
map_class.EnsureIsFinalized(T);
3235+
3236+
// Invoke Map._fromKeysValue class factory:
3237+
Function& factory_method = Function::ZoneHandle(Z);
3238+
factory_method = map_class.LookupFactoryAllowPrivate(
3239+
Library::PrivateCoreLibName(Symbols::MapKeyValuesFactory()));
3240+
const Array& args = Array::Handle(Z, Array::New(3));
3241+
args.SetAt(0, type_arguments);
3242+
args.SetAt(1, keys_obj);
3243+
args.SetAt(2, values_obj);
3244+
return Api::NewHandle(T, DartEntry::InvokeFunction(factory_method, args));
3245+
}
3246+
31773247
DART_EXPORT Dart_Handle Dart_NewListOfTypeFilled(Dart_Handle element_type,
31783248
Dart_Handle fill_object,
31793249
intptr_t length) {

runtime/vm/dart_api_impl_test.cc

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2262,6 +2262,122 @@ TEST_CASE(DartAPI_MapAccess) {
22622262
EXPECT(Dart_IsError(Dart_MapKeys(a)));
22632263
}
22642264

2265+
TEST_CASE(DartAPI_MapCreate) {
2266+
const char* kScriptChars =
2267+
R"(
2268+
@pragma('vm:entry-point', 'call')
2269+
String testMain(Map<String, Object?> mp) {
2270+
List result = [];
2271+
String dump = "";
2272+
// Test no modifications
2273+
for (var k in mp.keys) {
2274+
dump += "|" + k + ":" + mp[k].toString() + "|";
2275+
}
2276+
result.add(dump);
2277+
2278+
dump = "";
2279+
// Test with modifications
2280+
mp["f"] = 42;
2281+
for (var k in mp.keys) {
2282+
dump += "|" + k + ":" + mp[k].toString() + "|";
2283+
}
2284+
result.add(dump);
2285+
return result.toString();
2286+
})";
2287+
// Create a test library and Load up a test script in it.
2288+
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr);
2289+
2290+
Dart_Handle core_lib = Dart_LookupLibrary(NewString("dart:core"));
2291+
EXPECT_VALID(core_lib);
2292+
2293+
Dart_Handle key_type =
2294+
Dart_GetNonNullableType(core_lib, NewString("String"), 0, nullptr);
2295+
EXPECT_VALID(key_type);
2296+
2297+
Dart_Handle value_type =
2298+
Dart_GetNullableType(core_lib, NewString("Object"), 0, nullptr);
2299+
EXPECT_VALID(value_type);
2300+
2301+
{ // Test empty
2302+
// Init list of keys
2303+
Dart_Handle keys = Dart_NewList(0);
2304+
EXPECT_VALID(keys);
2305+
2306+
// Init list of values
2307+
Dart_Handle values = Dart_NewList(0);
2308+
EXPECT_VALID(values);
2309+
2310+
Dart_Handle dart_map = Dart_NewMap(key_type, keys, value_type, values);
2311+
2312+
// Invoke a function which returns an object of type String.
2313+
Dart_Handle result = Dart_Invoke(lib, NewString("testMain"), 1, &dart_map);
2314+
EXPECT_VALID(result);
2315+
const char* encoded_str = nullptr;
2316+
EXPECT_VALID(Dart_StringToCString(result, &encoded_str));
2317+
EXPECT_STREQ("[, |f:42|]", encoded_str);
2318+
}
2319+
{ // Test 5 elements
2320+
// Init list of keys
2321+
Dart_Handle keys = Dart_NewList(5);
2322+
EXPECT_VALID(keys);
2323+
2324+
// Init list of values
2325+
Dart_Handle values = Dart_NewList(5);
2326+
EXPECT_VALID(values);
2327+
2328+
// Fill map.
2329+
EXPECT_VALID(Dart_ListSetAt(keys, 0, NewString("a")));
2330+
EXPECT_VALID(Dart_ListSetAt(values, 0, Dart_NewInteger(5)));
2331+
EXPECT_VALID(Dart_ListSetAt(keys, 1, NewString("b")));
2332+
EXPECT_VALID(Dart_ListSetAt(values, 1, Dart_NewInteger(4)));
2333+
EXPECT_VALID(Dart_ListSetAt(keys, 2, NewString("c")));
2334+
EXPECT_VALID(Dart_ListSetAt(values, 2, NewString("oO")));
2335+
EXPECT_VALID(Dart_ListSetAt(keys, 3, NewString("d")));
2336+
EXPECT_VALID(Dart_ListSetAt(values, 3, Dart_NewInteger(2)));
2337+
EXPECT_VALID(Dart_ListSetAt(keys, 4, NewString("e")));
2338+
EXPECT_VALID(Dart_ListSetAt(values, 4, Dart_Null()));
2339+
Dart_Handle dart_map = Dart_NewMap(key_type, keys, value_type, values);
2340+
2341+
// Invoke a function which returns an object of type String.
2342+
Dart_Handle result = Dart_Invoke(lib, NewString("testMain"), 1, &dart_map);
2343+
EXPECT_VALID(result);
2344+
const char* encoded_str = nullptr;
2345+
EXPECT_VALID(Dart_StringToCString(result, &encoded_str));
2346+
EXPECT_STREQ(
2347+
"[|a:5||b:4||c:oO||d:2||e:null|, "
2348+
"|a:5||b:4||c:oO||d:2||e:null||f:42|]",
2349+
encoded_str);
2350+
}
2351+
{ // Test 10 elements
2352+
static constexpr int kElementCount = 10;
2353+
// Init list of keys
2354+
Dart_Handle keys = Dart_NewList(kElementCount);
2355+
EXPECT_VALID(keys);
2356+
2357+
// Init list of values
2358+
Dart_Handle values = Dart_NewList(kElementCount);
2359+
EXPECT_VALID(values);
2360+
2361+
// Fill map.
2362+
for (int i = 0; i < kElementCount; ++i) {
2363+
const char key[2] = {static_cast<char>('a' + i), '\0'};
2364+
EXPECT_VALID(Dart_ListSetAt(keys, i, NewString(key)));
2365+
EXPECT_VALID(Dart_ListSetAt(values, i, Dart_NewInteger(i)));
2366+
}
2367+
Dart_Handle dart_map = Dart_NewMap(key_type, keys, value_type, values);
2368+
2369+
// Invoke a function which returns an object of type String.
2370+
Dart_Handle result = Dart_Invoke(lib, NewString("testMain"), 1, &dart_map);
2371+
EXPECT_VALID(result);
2372+
const char* encoded_str = nullptr;
2373+
EXPECT_VALID(Dart_StringToCString(result, &encoded_str));
2374+
EXPECT_STREQ(
2375+
"[|a:0||b:1||c:2||d:3||e:4||f:5||g:6||h:7||i:8||j:9|, "
2376+
"|a:0||b:1||c:2||d:3||e:4||f:42||g:6||h:7||i:8||j:9|]",
2377+
encoded_str);
2378+
}
2379+
}
2380+
22652381
TEST_CASE(DartAPI_IsFuture) {
22662382
const char* kScriptChars =
22672383
"import 'dart:async';"

runtime/vm/symbols.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ class ObjectPointerVisitor;
207207
V(LocalVarDescriptors, "LocalVarDescriptors") \
208208
V(Map, "Map") \
209209
V(MapLiteralFactory, "Map._fromLiteral") \
210+
V(MapKeyValuesFactory, "Map._fromKeyValues") \
210211
V(MegamorphicCache, "MegamorphicCache") \
211212
V(MonomorphicSmiableCall, "MonomorphicSmiableCall") \
212213
V(MoveNext, "moveNext") \

sdk/lib/_internal/vm_shared/lib/map_patch.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,18 @@ class Map<K, V> {
2323
return map;
2424
}
2525

26+
// Factory constructing a Map for Dart_NewMap C API
27+
// from list of keys and values.
28+
@pragma("vm:entry-point", "call")
29+
factory Map._fromKeyValues(List keys, List values) {
30+
var map = LinkedHashMap<K, V>();
31+
var len = keys.length;
32+
for (int i = 0; i < len; i++) {
33+
map[keys[i]] = values[i];
34+
}
35+
return map;
36+
}
37+
2638
@patch
2739
factory Map.unmodifiable(Map other) {
2840
return UnmodifiableMapView<K, V>(Map<K, V>.from(other));

0 commit comments

Comments
 (0)