1 /* Copyright 2018 Mozilla Foundation
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 // Safe wrappers to the low-level ABI.  This re-exports all types in low_level but none of the
17 // functions.
18 
19 use std::{mem, slice};
20 
21 use cranelift_codegen::binemit::CodeOffset;
22 use cranelift_codegen::cursor::FuncCursor;
23 use cranelift_codegen::entity::EntityRef;
24 use cranelift_codegen::ir::immediates::{Ieee32, Ieee64};
25 use cranelift_codegen::ir::{self, InstBuilder, SourceLoc};
26 use cranelift_codegen::isa;
27 
28 use cranelift_wasm::{
29     wasmparser, FuncIndex, GlobalIndex, SignatureIndex, TableIndex, TypeIndex, WasmResult,
30 };
31 
32 use crate::compile;
33 use crate::utils::BasicError;
34 use crate::wasm2clif::REF_TYPE;
35 
36 use self::low_level::*;
37 
38 pub use self::low_level::BD_SymbolicAddress as SymbolicAddress;
39 pub use self::low_level::CraneliftCompiledFunc as CompiledFunc;
40 pub use self::low_level::CraneliftFuncCompileInput as FuncCompileInput;
41 pub use self::low_level::CraneliftMetadataEntry as MetadataEntry;
42 pub use self::low_level::CraneliftModuleEnvironment as LowLevelModuleEnvironment;
43 pub use self::low_level::CraneliftStaticEnvironment as StaticEnvironment;
44 pub use self::low_level::Trap;
45 pub use self::low_level::TypeIdDescKind;
46 
47 mod low_level;
48 
49 /// Converts a `TypeCode` into the equivalent Cranelift type, if it's a known type, or an error
50 /// otherwise.
51 #[inline]
typecode_to_type(type_code: TypeCode) -> WasmResult<Option<ir::Type>>52 fn typecode_to_type(type_code: TypeCode) -> WasmResult<Option<ir::Type>> {
53     match type_code {
54         TypeCode::I32 => Ok(Some(ir::types::I32)),
55         TypeCode::I64 => Ok(Some(ir::types::I64)),
56         TypeCode::F32 => Ok(Some(ir::types::F32)),
57         TypeCode::F64 => Ok(Some(ir::types::F64)),
58         TypeCode::V128 => Ok(Some(ir::types::I8X16)),
59         TypeCode::FuncRef => Ok(Some(REF_TYPE)),
60         TypeCode::ExternRef => Ok(Some(REF_TYPE)),
61         TypeCode::BlockVoid => Ok(None),
62         _ => Err(BasicError::new(format!("unknown type code: {:?}", type_code)).into()),
63     }
64 }
65 
66 /// Convert a non-void `TypeCode` into the equivalent Cranelift type.
67 #[inline]
typecode_to_nonvoid_type(type_code: TypeCode) -> WasmResult<ir::Type>68 pub(crate) fn typecode_to_nonvoid_type(type_code: TypeCode) -> WasmResult<ir::Type> {
69     Ok(typecode_to_type(type_code)?.expect("unexpected void type"))
70 }
71 
72 /// Convert a u32 into a `BD_SymbolicAddress`.
73 impl From<u32> for SymbolicAddress {
from(x: u32) -> SymbolicAddress74     fn from(x: u32) -> SymbolicAddress {
75         assert!(x < SymbolicAddress::Limit as u32);
76         unsafe { mem::transmute(x) }
77     }
78 }
79 
80 #[derive(Clone, Copy)]
81 pub struct GlobalDesc(*const low_level::GlobalDesc);
82 
83 impl GlobalDesc {
value_type(self) -> WasmResult<ir::Type>84     pub fn value_type(self) -> WasmResult<ir::Type> {
85         let type_code = unsafe { low_level::global_type(self.0) };
86         typecode_to_nonvoid_type(type_code)
87     }
88 
is_constant(self) -> bool89     pub fn is_constant(self) -> bool {
90         unsafe { low_level::global_isConstant(self.0) }
91     }
92 
is_mutable(self) -> bool93     pub fn is_mutable(self) -> bool {
94         unsafe { low_level::global_isMutable(self.0) }
95     }
96 
is_indirect(self) -> bool97     pub fn is_indirect(self) -> bool {
98         unsafe { low_level::global_isIndirect(self.0) }
99     }
100 
101     /// Insert an instruction at `pos` that materializes the constant value.
emit_constant(self, pos: &mut FuncCursor) -> WasmResult<ir::Value>102     pub fn emit_constant(self, pos: &mut FuncCursor) -> WasmResult<ir::Value> {
103         unsafe {
104             let v = low_level::global_constantValue(self.0);
105             match v.t {
106                 TypeCode::I32 => Ok(pos.ins().iconst(ir::types::I32, i64::from(v.u.i32_))),
107                 TypeCode::I64 => Ok(pos.ins().iconst(ir::types::I64, v.u.i64_)),
108                 TypeCode::F32 => Ok(pos.ins().f32const(Ieee32::with_bits(v.u.i32_ as u32))),
109                 TypeCode::F64 => Ok(pos.ins().f64const(Ieee64::with_bits(v.u.i64_ as u64))),
110                 TypeCode::V128 => {
111                     let c = pos
112                         .func
113                         .dfg
114                         .constants
115                         .insert(ir::ConstantData::from(&v.u.v128 as &[u8]));
116                     Ok(pos.ins().vconst(ir::types::I8X16, c))
117                 }
118                 TypeCode::NullableRef | TypeCode::ExternRef | TypeCode::FuncRef => {
119                     assert!(v.u.r as usize == 0);
120                     Ok(pos.ins().null(REF_TYPE))
121                 }
122                 _ => Err(BasicError::new(format!("unexpected type: {}", v.t as u64)).into()),
123             }
124         }
125     }
126 
127     /// Get the offset from the `WasmTlsReg` to the memory representing this global variable.
tls_offset(self) -> usize128     pub fn tls_offset(self) -> usize {
129         unsafe { low_level::global_tlsOffset(self.0) }
130     }
131 
content_type(self) -> wasmparser::Type132     pub fn content_type(self) -> wasmparser::Type {
133         typecode_to_parser_type(unsafe { low_level::global_type(self.0) })
134     }
135 }
136 
137 #[derive(Clone, Copy)]
138 pub struct TableDesc(*const low_level::TableDesc);
139 
140 impl TableDesc {
141     /// Get the offset from the `WasmTlsReg` to the `wasm::TableTls` representing this table.
tls_offset(self) -> usize142     pub fn tls_offset(self) -> usize {
143         unsafe { low_level::table_tlsOffset(self.0) }
144     }
145 
element_type(self) -> wasmparser::Type146     pub fn element_type(self) -> wasmparser::Type {
147         typecode_to_parser_type(unsafe { low_level::table_elementTypeCode(self.0) })
148     }
149 
resizable_limits(self) -> wasmparser::ResizableLimits150     pub fn resizable_limits(self) -> wasmparser::ResizableLimits {
151         let initial = unsafe { low_level::table_initialLimit(self.0) };
152         let maximum = unsafe { low_level::table_initialLimit(self.0) };
153         let maximum = if maximum == u32::max_value() {
154             None
155         } else {
156             Some(maximum)
157         };
158         wasmparser::ResizableLimits { initial, maximum }
159     }
160 }
161 
162 #[derive(Clone)]
163 pub struct FuncType {
164     ptr: *const low_level::FuncType,
165     args: Vec<TypeCode>,
166     results: Vec<TypeCode>,
167 }
168 
169 impl FuncType {
170     /// Creates a new FuncType, caching all the values it requires.
new(ptr: *const low_level::FuncType) -> Self171     pub(crate) fn new(ptr: *const low_level::FuncType) -> Self {
172         let num_args = unsafe { low_level::funcType_numArgs(ptr) };
173         let args = unsafe { slice::from_raw_parts(low_level::funcType_args(ptr), num_args) };
174         let args = args
175             .iter()
176             .map(|val_type| unsafe { low_level::env_unpack(*val_type) })
177             .collect();
178 
179         let num_results = unsafe { low_level::funcType_numResults(ptr) };
180         let results =
181             unsafe { slice::from_raw_parts(low_level::funcType_results(ptr), num_results) };
182         let results = results
183             .iter()
184             .map(|val_type| unsafe { low_level::env_unpack(*val_type) })
185             .collect();
186 
187         Self { ptr, args, results }
188     }
189 
args(&self) -> &[TypeCode]190     pub(crate) fn args(&self) -> &[TypeCode] {
191         &self.args
192     }
results(&self) -> &[TypeCode]193     pub(crate) fn results(&self) -> &[TypeCode] {
194         &self.results
195     }
196 }
197 
198 #[derive(Clone)]
199 pub struct TypeIdDesc {
200     ptr: *const low_level::TypeIdDesc,
201 }
202 
203 impl TypeIdDesc {
new(ptr: *const low_level::TypeIdDesc) -> Self204     pub(crate) fn new(ptr: *const low_level::TypeIdDesc) -> Self {
205         Self { ptr }
206     }
207 
id_kind(&self) -> TypeIdDescKind208     pub(crate) fn id_kind(&self) -> TypeIdDescKind {
209         unsafe { low_level::funcType_idKind(self.ptr) }
210     }
id_immediate(&self) -> usize211     pub(crate) fn id_immediate(&self) -> usize {
212         unsafe { low_level::funcType_idImmediate(self.ptr) }
213     }
id_tls_offset(&self) -> usize214     pub(crate) fn id_tls_offset(&self) -> usize {
215         unsafe { low_level::funcType_idTlsOffset(self.ptr) }
216     }
217 }
218 
typecode_to_parser_type(ty: TypeCode) -> wasmparser::Type219 fn typecode_to_parser_type(ty: TypeCode) -> wasmparser::Type {
220     match ty {
221         TypeCode::I32 => wasmparser::Type::I32,
222         TypeCode::I64 => wasmparser::Type::I64,
223         TypeCode::F32 => wasmparser::Type::F32,
224         TypeCode::F64 => wasmparser::Type::F64,
225         TypeCode::V128 => wasmparser::Type::V128,
226         TypeCode::FuncRef => wasmparser::Type::FuncRef,
227         TypeCode::ExternRef => wasmparser::Type::ExternRef,
228         TypeCode::BlockVoid => wasmparser::Type::EmptyBlockType,
229         _ => panic!("unknown type code: {:?}", ty),
230     }
231 }
232 
233 impl wasmparser::WasmFuncType for FuncType {
len_inputs(&self) -> usize234     fn len_inputs(&self) -> usize {
235         self.args.len()
236     }
len_outputs(&self) -> usize237     fn len_outputs(&self) -> usize {
238         self.results.len()
239     }
input_at(&self, at: u32) -> Option<wasmparser::Type>240     fn input_at(&self, at: u32) -> Option<wasmparser::Type> {
241         self.args
242             .get(at as usize)
243             .map(|ty| typecode_to_parser_type(*ty))
244     }
output_at(&self, at: u32) -> Option<wasmparser::Type>245     fn output_at(&self, at: u32) -> Option<wasmparser::Type> {
246         self.results
247             .get(at as usize)
248             .map(|ty| typecode_to_parser_type(*ty))
249     }
250 }
251 
252 /// Thin wrapper for the CraneliftModuleEnvironment structure.
253 
254 pub struct ModuleEnvironment<'a> {
255     env: &'a CraneliftModuleEnvironment,
256     /// The `WasmModuleResources` trait requires us to return a borrow to a `FuncType`, so we
257     /// eagerly construct these.
258     types: Vec<FuncType>,
259     /// Similar to `types`, we need to have a persistently-stored `FuncType` to return. The
260     /// types in `func_sigs` are a subset of those in `types`, but we don't want to have to
261     /// maintain an index from function to signature ID, so we store these directly.
262     func_sigs: Vec<FuncType>,
263 }
264 
265 impl<'a> ModuleEnvironment<'a> {
new(env: &'a CraneliftModuleEnvironment) -> Self266     pub(crate) fn new(env: &'a CraneliftModuleEnvironment) -> Self {
267         let num_types = unsafe { low_level::env_num_types(env) };
268         let mut types = Vec::with_capacity(num_types);
269         for i in 0..num_types {
270             let t = FuncType::new(unsafe { low_level::env_signature(env, i) });
271             types.push(t);
272         }
273         let num_func_sigs = unsafe { low_level::env_num_funcs(env) };
274         let mut func_sigs = Vec::with_capacity(num_func_sigs);
275         for i in 0..num_func_sigs {
276             let t = FuncType::new(unsafe { low_level::env_func_sig(env, i) });
277             func_sigs.push(t);
278         }
279         Self {
280             env,
281             types,
282             func_sigs,
283         }
284     }
has_memory(&self) -> bool285     pub fn has_memory(&self) -> bool {
286         unsafe { low_level::env_has_memory(self.env) }
287     }
uses_shared_memory(&self) -> bool288     pub fn uses_shared_memory(&self) -> bool {
289         unsafe { low_level::env_uses_shared_memory(self.env) }
290     }
num_tables(&self) -> usize291     pub fn num_tables(&self) -> usize {
292         unsafe { low_level::env_num_tables(self.env) }
293     }
num_types(&self) -> usize294     pub fn num_types(&self) -> usize {
295         self.types.len()
296     }
type_(&self, index: usize) -> FuncType297     pub fn type_(&self, index: usize) -> FuncType {
298         self.types[index].clone()
299     }
num_func_sigs(&self) -> usize300     pub fn num_func_sigs(&self) -> usize {
301         self.func_sigs.len()
302     }
func_sig(&self, func_index: FuncIndex) -> FuncType303     pub fn func_sig(&self, func_index: FuncIndex) -> FuncType {
304         self.func_sigs[func_index.index()].clone()
305     }
func_sig_index(&self, func_index: FuncIndex) -> SignatureIndex306     pub fn func_sig_index(&self, func_index: FuncIndex) -> SignatureIndex {
307         SignatureIndex::new(unsafe { low_level::env_func_sig_index(self.env, func_index.index()) })
308     }
func_import_tls_offset(&self, func_index: FuncIndex) -> usize309     pub fn func_import_tls_offset(&self, func_index: FuncIndex) -> usize {
310         unsafe { low_level::env_func_import_tls_offset(self.env, func_index.index()) }
311     }
func_is_import(&self, func_index: FuncIndex) -> bool312     pub fn func_is_import(&self, func_index: FuncIndex) -> bool {
313         unsafe { low_level::env_func_is_import(self.env, func_index.index()) }
314     }
signature(&self, type_index: TypeIndex) -> FuncType315     pub fn signature(&self, type_index: TypeIndex) -> FuncType {
316         // This function takes `TypeIndex` rather than the `SignatureIndex` that one
317         // might expect.  Why?  https://github.com/bytecodealliance/wasmtime/pull/2115
318         // introduces two new types to the type section as viewed by Cranelift.  This is
319         // in support of the module linking proposal.  So now a type index (for
320         // Cranelift) can refer to a func, module, or instance type.  When the type index
321         // refers to a func type, it can also be used to get the signature index which
322         // can be used to get the ir::Signature for that func type.  For us, Cranelift is
323         // only used with function types so we can just assume type index and signature
324         // index are 1:1.  If and when we come to support the module linking proposal,
325         // this will need to be revisited.
326         FuncType::new(unsafe { low_level::env_signature(self.env, type_index.index()) })
327     }
signature_id(&self, type_index: TypeIndex) -> TypeIdDesc328     pub fn signature_id(&self, type_index: TypeIndex) -> TypeIdDesc {
329         TypeIdDesc::new(unsafe { low_level::env_signature_id(self.env, type_index.index()) })
330     }
table(&self, table_index: TableIndex) -> TableDesc331     pub fn table(&self, table_index: TableIndex) -> TableDesc {
332         TableDesc(unsafe { low_level::env_table(self.env, table_index.index()) })
333     }
global(&self, global_index: GlobalIndex) -> GlobalDesc334     pub fn global(&self, global_index: GlobalIndex) -> GlobalDesc {
335         GlobalDesc(unsafe { low_level::env_global(self.env, global_index.index()) })
336     }
min_memory_length(&self) -> u32337     pub fn min_memory_length(&self) -> u32 {
338         self.env.min_memory_length
339     }
max_memory_length(&self) -> Option<u32>340     pub fn max_memory_length(&self) -> Option<u32> {
341         let max = unsafe { low_level::env_max_memory(self.env) };
342         if max == u32::max_value() {
343             None
344         } else {
345             Some(max)
346         }
347     }
348 }
349 
350 impl<'module> wasmparser::WasmModuleResources for ModuleEnvironment<'module> {
351     type FuncType = FuncType;
table_at(&self, at: u32) -> Option<wasmparser::TableType>352     fn table_at(&self, at: u32) -> Option<wasmparser::TableType> {
353         if (at as usize) < self.num_tables() {
354             let desc = TableDesc(unsafe { low_level::env_table(self.env, at as usize) });
355             let element_type = desc.element_type();
356             let limits = desc.resizable_limits();
357             Some(wasmparser::TableType {
358                 element_type,
359                 limits,
360             })
361         } else {
362             None
363         }
364     }
memory_at(&self, at: u32) -> Option<wasmparser::MemoryType>365     fn memory_at(&self, at: u32) -> Option<wasmparser::MemoryType> {
366         if at == 0 {
367             let has_memory = self.has_memory();
368             if has_memory {
369                 let shared = self.uses_shared_memory();
370                 let initial = self.min_memory_length() as u32;
371                 let maximum = self.max_memory_length();
372                 Some(wasmparser::MemoryType::M32 {
373                     limits: wasmparser::ResizableLimits { initial, maximum },
374                     shared,
375                 })
376             } else {
377                 None
378             }
379         } else {
380             None
381         }
382     }
event_at(&self, _at: u32) -> Option<&Self::FuncType>383     fn event_at(&self, _at: u32) -> Option<&Self::FuncType> {
384         panic!("unexpected exception operation");
385     }
global_at(&self, at: u32) -> Option<wasmparser::GlobalType>386     fn global_at(&self, at: u32) -> Option<wasmparser::GlobalType> {
387         let num_globals = unsafe { low_level::env_num_globals(self.env) };
388         if (at as usize) < num_globals {
389             let desc = self.global(GlobalIndex::new(at as usize));
390             let mutable = desc.is_mutable();
391             let content_type = desc.content_type();
392             Some(wasmparser::GlobalType {
393                 mutable,
394                 content_type,
395             })
396         } else {
397             None
398         }
399     }
func_type_at(&self, type_idx: u32) -> Option<&Self::FuncType>400     fn func_type_at(&self, type_idx: u32) -> Option<&Self::FuncType> {
401         if (type_idx as usize) < self.types.len() {
402             Some(&self.types[type_idx as usize])
403         } else {
404             None
405         }
406     }
type_of_function(&self, func_idx: u32) -> Option<&Self::FuncType>407     fn type_of_function(&self, func_idx: u32) -> Option<&Self::FuncType> {
408         if (func_idx as usize) < self.func_sigs.len() {
409             Some(&self.func_sigs[func_idx as usize])
410         } else {
411             None
412         }
413     }
element_type_at(&self, at: u32) -> Option<wasmparser::Type>414     fn element_type_at(&self, at: u32) -> Option<wasmparser::Type> {
415         let num_elems = self.element_count();
416         if at < num_elems {
417             let elem_type = unsafe { low_level::env_elem_typecode(self.env, at) };
418             Some(typecode_to_parser_type(elem_type))
419         } else {
420             None
421         }
422     }
element_count(&self) -> u32423     fn element_count(&self) -> u32 {
424         unsafe { low_level::env_num_elems(self.env) as u32 }
425     }
data_count(&self) -> u32426     fn data_count(&self) -> u32 {
427         unsafe { low_level::env_num_datas(self.env) as u32 }
428     }
is_function_referenced(&self, idx: u32) -> bool429     fn is_function_referenced(&self, idx: u32) -> bool {
430         unsafe { low_level::env_is_func_valid_for_ref(self.env, idx) }
431     }
432 }
433 
434 /// Extra methods for some C++ wrappers.
435 
436 impl FuncCompileInput {
bytecode(&self) -> &[u8]437     pub fn bytecode(&self) -> &[u8] {
438         unsafe { slice::from_raw_parts(self.bytecode, self.bytecode_size) }
439     }
440 
stackmaps(&self) -> Stackmaps441     pub fn stackmaps(&self) -> Stackmaps {
442         Stackmaps(self.stackmaps)
443     }
444 }
445 
446 impl CompiledFunc {
reset(&mut self, compiled_func: &compile::CompiledFunc)447     pub fn reset(&mut self, compiled_func: &compile::CompiledFunc) {
448         self.num_metadata = compiled_func.metadata.len();
449         self.metadatas = compiled_func.metadata.as_ptr();
450 
451         self.frame_pushed = compiled_func.frame_pushed as usize;
452         self.contains_calls = compiled_func.contains_calls;
453 
454         self.code = compiled_func.code_buffer.as_ptr();
455         self.code_size = compiled_func.code_size as usize;
456         self.jumptables_size = compiled_func.jumptables_size as usize;
457         self.rodata_size = compiled_func.rodata_size as usize;
458         self.total_size = compiled_func.code_buffer.len();
459 
460         self.num_rodata_relocs = compiled_func.rodata_relocs.len();
461         self.rodata_relocs = compiled_func.rodata_relocs.as_ptr();
462     }
463 }
464 
465 impl MetadataEntry {
direct_call(code_offset: CodeOffset, srcloc: SourceLoc, func_index: FuncIndex) -> Self466     pub fn direct_call(code_offset: CodeOffset, srcloc: SourceLoc, func_index: FuncIndex) -> Self {
467         Self {
468             which: CraneliftMetadataEntry_Which_DirectCall,
469             code_offset,
470             module_bytecode_offset: srcloc.bits(),
471             extra: func_index.index(),
472         }
473     }
indirect_call(ret_addr: CodeOffset, srcloc: SourceLoc) -> Self474     pub fn indirect_call(ret_addr: CodeOffset, srcloc: SourceLoc) -> Self {
475         Self {
476             which: CraneliftMetadataEntry_Which_IndirectCall,
477             code_offset: ret_addr,
478             module_bytecode_offset: srcloc.bits(),
479             extra: 0,
480         }
481     }
trap(code_offset: CodeOffset, srcloc: SourceLoc, which: Trap) -> Self482     pub fn trap(code_offset: CodeOffset, srcloc: SourceLoc, which: Trap) -> Self {
483         Self {
484             which: CraneliftMetadataEntry_Which_Trap,
485             code_offset,
486             module_bytecode_offset: srcloc.bits(),
487             extra: which as usize,
488         }
489     }
symbolic_access( code_offset: CodeOffset, srcloc: SourceLoc, sym: SymbolicAddress, ) -> Self490     pub fn symbolic_access(
491         code_offset: CodeOffset,
492         srcloc: SourceLoc,
493         sym: SymbolicAddress,
494     ) -> Self {
495         Self {
496             which: CraneliftMetadataEntry_Which_SymbolicAccess,
497             code_offset,
498             module_bytecode_offset: srcloc.bits(),
499             extra: sym as usize,
500         }
501     }
502 }
503 
504 impl StaticEnvironment {
505     /// Returns the default calling convention on this machine.
call_conv(&self) -> isa::CallConv506     pub fn call_conv(&self) -> isa::CallConv {
507         if self.platform_is_windows {
508             unimplemented!("No FastCall variant of Baldrdash2020")
509         } else {
510             isa::CallConv::Baldrdash2020
511         }
512     }
513 }
514 
515 pub struct Stackmaps(*mut self::low_level::BD_Stackmaps);
516 
517 impl Stackmaps {
add_stackmap( &mut self, inbound_args_size: u32, offset: CodeOffset, map: &cranelift_codegen::binemit::StackMap, )518     pub fn add_stackmap(
519         &mut self,
520         inbound_args_size: u32,
521         offset: CodeOffset,
522         map: &cranelift_codegen::binemit::StackMap,
523     ) {
524         unsafe {
525             let bitslice = map.as_slice();
526             low_level::stackmaps_add(
527                 self.0,
528                 std::mem::transmute(bitslice.as_ptr()),
529                 map.mapped_words() as usize,
530                 inbound_args_size as usize,
531                 offset as usize,
532             );
533         }
534     }
535 }
536