Loads the address of the table element at a given index. Returns the address of the table element using the provided register as base.
(
&mut self,
index: Reg,
base: Reg,
table_data: &TableData,
)
| 1418 | /// Loads the address of the table element at a given index. Returns the |
| 1419 | /// address of the table element using the provided register as base. |
| 1420 | pub fn emit_compute_table_elem_addr( |
| 1421 | &mut self, |
| 1422 | index: Reg, |
| 1423 | base: Reg, |
| 1424 | table_data: &TableData, |
| 1425 | ) -> Result<M::Address> { |
| 1426 | let bound = self.context.any_gpr(self.masm)?; |
| 1427 | let tmp = self.context.any_gpr(self.masm)?; |
| 1428 | let ptr_size: OperandSize = self.env.ptr_type().try_into()?; |
| 1429 | |
| 1430 | if let Some(offset) = table_data.import_from { |
| 1431 | // If the table data declares a particular offset base, |
| 1432 | // load the address into a register to further use it as |
| 1433 | // the table address. |
| 1434 | self.masm |
| 1435 | .load_ptr(self.masm.address_at_vmctx(offset)?, writable!(base))?; |
| 1436 | } else { |
| 1437 | // Else, simply move the vmctx register into the addr register as |
| 1438 | // the base to calculate the table address. |
| 1439 | self.masm.mov(writable!(base), vmctx!(M).into(), ptr_size)?; |
| 1440 | }; |
| 1441 | |
| 1442 | // OOB check. |
| 1443 | let bound_addr = self |
| 1444 | .masm |
| 1445 | .address_at_reg(base, table_data.current_elems_offset)?; |
| 1446 | let bound_size = table_data.current_elements_size; |
| 1447 | self.masm.load(bound_addr, writable!(bound), bound_size)?; |
| 1448 | self.masm.cmp(index, bound.into(), bound_size)?; |
| 1449 | self.masm |
| 1450 | .trapif(IntCmpKind::GeU, TRAP_TABLE_OUT_OF_BOUNDS)?; |
| 1451 | |
| 1452 | // Move the index into the scratch register to calculate the table |
| 1453 | // element address. |
| 1454 | // Moving the value of the index register to the scratch register |
| 1455 | // also avoids overwriting the context of the index register. |
| 1456 | self.masm.with_scratch::<IntScratch, _>(|masm, scratch| { |
| 1457 | masm.mov(scratch.writable(), index.into(), bound_size)?; |
| 1458 | masm.mul( |
| 1459 | scratch.writable(), |
| 1460 | scratch.inner(), |
| 1461 | RegImm::i32(table_data.element_size.bytes() as i32), |
| 1462 | table_data.element_size, |
| 1463 | )?; |
| 1464 | masm.load_ptr( |
| 1465 | masm.address_at_reg(base, table_data.offset)?, |
| 1466 | writable!(base), |
| 1467 | )?; |
| 1468 | // Copy the value of the table base into a temporary register |
| 1469 | // so that we can use it later in case of a misspeculation. |
| 1470 | masm.mov(writable!(tmp), base.into(), ptr_size)?; |
| 1471 | // Calculate the address of the table element. |
| 1472 | masm.add(writable!(base), base, scratch.inner().into(), ptr_size) |
| 1473 | })?; |
| 1474 | if self.env.table_access_spectre_mitigation() { |
| 1475 | // Perform a bounds check and override the value of the |
| 1476 | // table element address in case the index is out of bounds. |
| 1477 | self.masm.cmp(index, bound.into(), bound_size)?; |
no test coverage detected