1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
//! Global variables.

use ir::immediates::Offset32;
use ir::{ExternalName, GlobalVar};
use std::fmt;

/// Information about a global variable declaration.
#[derive(Clone)]
pub enum GlobalVarData {
    /// Variable is part of the VM context struct, it's address is a constant offset from the VM
    /// context pointer.
    VMContext {
        /// Offset from the `vmctx` pointer to this global.
        offset: Offset32,
    },

    /// Variable is part of a struct pointed to by another global variable.
    ///
    /// The `base` global variable is assumed to contain a pointer to a struct. This global
    /// variable lives at an offset into the struct. The memory must be accessible, and
    /// naturally aligned to hold a pointer value.
    Deref {
        /// The base pointer global variable.
        base: GlobalVar,

        /// Byte offset to be added to the pointer loaded from `base`.
        offset: Offset32,
    },

    /// Variable is at an address identified by a symbolic name. Cretonne itself
    /// does not interpret this name; it's used by embedders to link with other
    /// data structures.
    Sym {
        /// The symbolic name.
        name: ExternalName,

        /// Will this variable be defined nearby, such that it will always be a certain distance
        /// away, after linking? If so, references to it can avoid going through a GOT. Note that
        /// symbols meant to be preemptible cannot be colocated.
        colocated: bool,
    },
}

impl GlobalVarData {
    /// Assume that `self` is an `GlobalVarData::Sym` and return its name.
    pub fn symbol_name(&self) -> &ExternalName {
        match *self {
            GlobalVarData::Sym { ref name, .. } => name,
            _ => panic!("only symbols have names"),
        }
    }
}

impl fmt::Display for GlobalVarData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GlobalVarData::VMContext { offset } => write!(f, "vmctx{}", offset),
            GlobalVarData::Deref { base, offset } => write!(f, "deref({}){}", base, offset),
            GlobalVarData::Sym {
                ref name,
                colocated,
            } => {
                if colocated {
                    write!(f, "colocated ")?;
                }
                write!(f, "globalsym {}", name)
            }
        }
    }
}