@@ -75,6 +75,8 @@ let assertion_error_closure_ident =
7575 Ident . create_persistent("GRAIN$EXPORT$AssertionError" );
7676let index_out_of_bounds_ident =
7777 Ident . create_persistent("GRAIN$EXPORT$IndexOutOfBounds" );
78+ let index_non_integer_ident =
79+ Ident . create_persistent("GRAIN$EXPORT$IndexNonInteger" );
7880let match_failure_ident =
7981 Ident . create_persistent("GRAIN$EXPORT$MatchFailure" );
8082
@@ -136,6 +138,15 @@ let required_global_imports = [
136138 mimp_setup: MSetupNone ,
137139 mimp_used: false ,
138140 },
141+ {
142+ mimp_id: index_non_integer_ident,
143+ mimp_mod: exception_mod,
144+ mimp_name: Ident . name(index_non_integer_ident),
145+ mimp_type: MGlobalImport (Types . Unmanaged (WasmI32 ), true ),
146+ mimp_kind: MImportWasm ,
147+ mimp_setup: MSetupNone ,
148+ mimp_used: false ,
149+ },
139150 {
140151 mimp_id: match_failure_ident,
141152 mimp_mod: exception_mod,
@@ -1009,6 +1020,7 @@ let call_error_handler = (wasm_mod, env, err, args) => {
10091020 switch (err) {
10101021 | Runtime_errors . MatchFailure => (match_failure_ident, None )
10111022 | Runtime_errors . IndexOutOfBounds => (index_out_of_bounds_ident, None )
1023+ | Runtime_errors . IndexNonInteger => (index_non_integer_ident, None )
10121024 | Runtime_errors . AssertionError => (
10131025 assertion_error_closure_ident,
10141026 Some (get_wasm_imported_name(exception_mod, assertion_error_ident)),
@@ -1124,56 +1136,136 @@ let compile_array_op = (wasm_mod, env, arr_imm, op) => {
11241136 // incref/decref pair). Since it won't live in a local, it wouldn't be
11251137 // cleaned up automatically anyway.
11261138 compile_imm(~skip_incref= true , wasm_mod, env, arr_imm);
1127- switch (op) {
1128- | MArrayGet (idx_imm ) =>
1129- // ASSUMPTION: idx is a basic (non-heap) int
1130- let idx = compile_imm(wasm_mod, env, idx_imm);
1131- let set_idx = () => set_swap(1 , untag_number(wasm_mod, idx));
1132- let get_idx = () => get_swap(1 );
1133- let set_arr = () => set_swap(2 , get_arr_value() );
1134- let get_arr = () => get_swap(2 );
1135- /* Check that the index is in bounds */
1139+ let resolve_idx = () => {
1140+ // PRECONDITION: idx is in swap slot 1
1141+ // PRECONDITION: arr is in swap slot 2
11361142 Expression . Block . make(
11371143 wasm_mod,
1138- gensym_label("MArrayGet " ),
1144+ gensym_label("resolve_idx " ),
11391145 [
1140- set_idx() ,
1141- set_arr() ,
1142- /*
1143- Check index not out of bounds (negative end)
1144- */
1145- error_if_true(
1146+ /* Maximum array length in 32-bit mode is less than 2^30, so any heap-allocated int is out of bounds. */
1147+ /* Check that the index is a simple int. */
1148+ Expression . If . make(
1149+ wasm_mod,
1150+ Expression . Unary . make(
1151+ wasm_mod,
1152+ Op . eq_z_int32,
1153+ Expression . Binary . make(
1154+ wasm_mod,
1155+ Op . and_int32,
1156+ get_swap(1 ),
1157+ Expression . Const . make(wasm_mod, const_int32(1 )),
1158+ ),
1159+ ),
1160+ Expression . Block . make(
1161+ wasm_mod,
1162+ gensym_label("IndexNotSimpleInteger" ),
1163+ [
1164+ set_swap(1 , load(~offset= 4 , wasm_mod, get_swap(1 ))),
1165+ Expression . Drop . make(
1166+ wasm_mod,
1167+ Expression . If . make(
1168+ wasm_mod,
1169+ Expression . Binary . make(
1170+ wasm_mod,
1171+ Op . or_int32,
1172+ Expression . Binary . make(
1173+ wasm_mod,
1174+ Op . or_int32,
1175+ Expression . Binary . make(
1176+ wasm_mod,
1177+ Op . eq_int32,
1178+ get_swap(1 ),
1179+ Expression . Const . make(
1180+ wasm_mod,
1181+ const_int32(
1182+ tag_val_of_boxed_number_tag_type(BoxedInt32 ),
1183+ ),
1184+ ),
1185+ ),
1186+ Expression . Binary . make(
1187+ wasm_mod,
1188+ Op . eq_int32,
1189+ get_swap(1 ),
1190+ Expression . Const . make(
1191+ wasm_mod,
1192+ const_int32(
1193+ tag_val_of_boxed_number_tag_type(BoxedInt64 ),
1194+ ),
1195+ ),
1196+ ),
1197+ ),
1198+ Expression . Binary . make(
1199+ wasm_mod,
1200+ Op . eq_int32,
1201+ get_swap(1 ),
1202+ Expression . Const . make(
1203+ wasm_mod,
1204+ const_int32(
1205+ tag_val_of_boxed_number_tag_type(BoxedBigInt ),
1206+ ),
1207+ ),
1208+ ),
1209+ ),
1210+ call_error_handler(wasm_mod, env, IndexOutOfBounds , [] ),
1211+ call_error_handler(wasm_mod, env, IndexNonInteger , [] ),
1212+ ),
1213+ ),
1214+ ] ,
1215+ ),
1216+ Expression . Null . make() ,
1217+ ),
1218+ set_swap(1 , untag_number(wasm_mod, get_swap(1 ))),
1219+ /* Resolve a negative index */
1220+ Expression . If . make(
11461221 wasm_mod,
1147- env,
11481222 Expression . Binary . make(
11491223 wasm_mod,
1150- Op . gt_s_int32,
1224+ Op . lt_s_int32,
1225+ get_swap(1 ),
1226+ Expression . Const . make(wasm_mod, const_int32(0 )),
1227+ ),
1228+ set_swap(
1229+ 1 ,
11511230 Expression . Binary . make(
11521231 wasm_mod,
1153- Op . mul_int32 ,
1154- load(~offset = 4 , wasm_mod , get_arr () ),
1155- Expression . Const . make( wasm_mod, const_int32( - 1 )),
1232+ Op . add_int32 ,
1233+ get_swap( 1 ),
1234+ load(~offset = 4 , wasm_mod, get_swap( 2 )),
11561235 ),
1157- get_idx() ,
11581236 ),
1159- IndexOutOfBounds ,
1160- [] ,
1237+ Expression . Null . make() ,
11611238 ),
11621239 /*
1163- Check index not out of bounds (positive end)
1240+ Check index not out of bounds
11641241 */
11651242 error_if_true(
11661243 wasm_mod,
11671244 env,
11681245 Expression . Binary . make(
11691246 wasm_mod,
1170- Op . le_s_int32 ,
1171- load(~offset= 4 , wasm_mod, get_arr ( ) ),
1172- get_idx ( ),
1247+ Op . le_u_int32 ,
1248+ load(~offset= 4 , wasm_mod, get_swap( 2 )),
1249+ get_swap( 1 ),
11731250 ),
11741251 IndexOutOfBounds ,
11751252 [] ,
11761253 ),
1254+ ] ,
1255+ );
1256+ };
1257+ switch (op) {
1258+ | MArrayLength =>
1259+ tag_number(wasm_mod, load(~offset= 4 , wasm_mod, get_arr_value() ))
1260+ | MArrayGet (idx_imm ) =>
1261+ let idx = compile_imm(wasm_mod, env, idx_imm);
1262+ Expression . Block . make(
1263+ wasm_mod,
1264+ gensym_label("MArrayGet" ),
1265+ [
1266+ set_swap(1 , idx),
1267+ set_swap(2 , get_arr_value() ),
1268+ resolve_idx() ,
11771269 /*
11781270 Load item at array+8+(4*idx) and incRef it
11791271 */
@@ -1188,108 +1280,44 @@ let compile_array_op = (wasm_mod, env, arr_imm, op) => {
11881280 Op . add_int32,
11891281 Expression . Binary . make(
11901282 wasm_mod,
1191- Op . mul_int32,
1192- /* Resolve a negative index */
1193- Expression . If . make(
1194- wasm_mod,
1195- Expression . Binary . make(
1196- wasm_mod,
1197- Op . lt_s_int32,
1198- get_idx() ,
1199- Expression . Const . make(wasm_mod, const_int32(0 )),
1200- ),
1201- Expression . Binary . make(
1202- wasm_mod,
1203- Op . add_int32,
1204- get_idx() ,
1205- load(~offset= 4 , wasm_mod, get_arr() ),
1206- ),
1207- get_idx() ,
1208- ),
1209- Expression . Const . make(wasm_mod, const_int32(4 )),
1283+ Op . shl_int32,
1284+ get_swap(1 ),
1285+ Expression . Const . make(wasm_mod, const_int32(2 )),
12101286 ),
1211- get_arr ( ),
1287+ get_swap( 2 ),
12121288 ),
12131289 ),
12141290 ),
12151291 ] ,
12161292 );
1217- | MArrayLength =>
1218- tag_number(wasm_mod, load(~offset= 4 , wasm_mod, get_arr_value() ))
12191293 | MArraySet (idx_imm , val_imm ) =>
1220- // ASSUMPTION: idx is a basic (non-heap) int
12211294 let idx = compile_imm(wasm_mod, env, idx_imm);
12221295 let val_ = compile_imm(wasm_mod, env, val_imm);
1223- let get_idx = () => get_swap(1 );
1224- let set_arr = () => set_swap(2 , get_arr_value() );
1225- let get_arr = () => get_swap(2 );
1226- /* Check that the index is in bounds */
12271296 Expression . Block . make(
12281297 wasm_mod,
1229- gensym_label("MArrayGet " ),
1298+ gensym_label("MArraySet " ),
12301299 [
1231- set_swap(1 , untag_number(wasm_mod , idx) ),
1232- set_arr ( ),
1233- error_if_true(
1234- wasm_mod ,
1235- env ,
1300+ set_swap(1 , idx),
1301+ set_swap( 2 , get_arr_value () ),
1302+ resolve_idx () ,
1303+ set_swap(
1304+ 2 ,
12361305 Expression . Binary . make(
12371306 wasm_mod,
1238- Op . gt_s_int32 ,
1307+ Op . add_int32 ,
12391308 Expression . Binary . make(
12401309 wasm_mod,
1241- Op . mul_int32 ,
1242- load(~offset = 4 , wasm_mod , get_arr () ),
1243- Expression . Const . make(wasm_mod, const_int32(- 1 )),
1310+ Op . shl_int32 ,
1311+ get_swap( 1 ),
1312+ Expression . Const . make(wasm_mod, const_int32(2 )),
12441313 ),
1245- get_idx() ,
1246- ),
1247- IndexOutOfBounds ,
1248- [] ,
1249- ),
1250- error_if_true(
1251- wasm_mod,
1252- env,
1253- Expression . Binary . make(
1254- wasm_mod,
1255- Op . le_s_int32,
1256- load(~offset= 4 , wasm_mod, get_arr() ),
1257- get_idx() ,
1314+ get_swap(2 ),
12581315 ),
1259- IndexOutOfBounds ,
1260- [] ,
12611316 ),
12621317 store(
12631318 ~offset= 8 ,
12641319 wasm_mod,
1265- Expression . Binary . make(
1266- wasm_mod,
1267- Op . add_int32,
1268- Expression . Binary . make(
1269- wasm_mod,
1270- Op . mul_int32,
1271- /* Resolve a negative index */
1272- Expression . If . make(
1273- wasm_mod,
1274- Expression . Binary . make(
1275- wasm_mod,
1276- Op . lt_s_int32,
1277- get_idx() ,
1278- Expression . Const . make(wasm_mod, const_int32(0 )),
1279- ),
1280- Expression . Binary . make(
1281- wasm_mod,
1282- Op . add_int32,
1283- get_idx() ,
1284- load(~offset= 4 , wasm_mod, get_arr() ),
1285- ),
1286- get_idx() ,
1287- ),
1288- Expression . Const . make(wasm_mod, const_int32(4 )),
1289- ),
1290- get_arr() ,
1291- ),
1292- // TODO: decref the old item more efficiently (using a swap slot, most likely)
1320+ get_swap(2 ),
12931321 Expression . Tuple_extract . make(
12941322 wasm_mod,
12951323 Expression . Tuple_make . make(
@@ -1299,37 +1327,7 @@ let compile_array_op = (wasm_mod, env, arr_imm, op) => {
12991327 call_decref(
13001328 wasm_mod,
13011329 env,
1302- load(
1303- ~offset= 8 ,
1304- wasm_mod,
1305- Expression . Binary . make(
1306- wasm_mod,
1307- Op . add_int32,
1308- Expression . Binary . make(
1309- wasm_mod,
1310- Op . mul_int32,
1311- /* Resolve a negative index */
1312- Expression . If . make(
1313- wasm_mod,
1314- Expression . Binary . make(
1315- wasm_mod,
1316- Op . lt_s_int32,
1317- get_idx() ,
1318- Expression . Const . make(wasm_mod, const_int32(0 )),
1319- ),
1320- Expression . Binary . make(
1321- wasm_mod,
1322- Op . add_int32,
1323- get_idx() ,
1324- load(~offset= 4 , wasm_mod, get_arr() ),
1325- ),
1326- get_idx() ,
1327- ),
1328- Expression . Const . make(wasm_mod, const_int32(4 )),
1329- ),
1330- get_arr() ,
1331- ),
1332- ),
1330+ load(~offset= 8 , wasm_mod, get_swap(2 )),
13331331 ),
13341332 ] ,
13351333 ),
0 commit comments