Skip to content

Commit

Permalink
Remove ClassId from the CallStatic instruction
Browse files Browse the repository at this point in the history
This isn't needed, because when generating LLVM IR we just call the
native function directly, instead of going through a class. As part of
this, the LLVM code generation is changed a bit to not store static
methods in method tables, as they'll never be used for virtual/dynamic
dispatch.

Changelog: changed
  • Loading branch information
yorickpeterse committed Jul 20, 2023
1 parent 8026b29 commit d455d8f
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 21 deletions.
3 changes: 2 additions & 1 deletion compiler/src/llvm/layouts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,8 @@ impl<'ctx> Layouts<'ctx> {
// We size classes larger than actually needed in an attempt to
// reduce collisions when performing dynamic dispatch.
let methods_len = max(
round_methods(mir_class.methods.len()) * METHOD_TABLE_FACTOR,
round_methods(mir_class.instance_methods_count(db))
* METHOD_TABLE_FACTOR,
METHOD_TABLE_MIN_SIZE,
);

Expand Down
6 changes: 6 additions & 0 deletions compiler/src/llvm/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,12 @@ impl<'a, 'b, 'ctx> Compile<'a, 'b, 'ctx> {
};

for method in &self.mir.classes[&class_id].methods {
// Static methods aren't stored in classes, nor can we call them
// through dynamic dispatch, so we can skip the rest.
if method.is_static(self.db) {
continue;
}

let info = &self.layouts.methods[method];
let name = &self.names.methods[method];
let func = self
Expand Down
12 changes: 6 additions & 6 deletions compiler/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::fmt;
use std::hash::{Hash, Hasher};
use std::rc::Rc;
use types::collections::IndexMap;
use types::BuiltinFunction;
use types::{BuiltinFunction, Database};

/// The number of reductions to perform after calling a method.
const CALL_COST: u16 = 1;
Expand Down Expand Up @@ -407,14 +407,12 @@ impl Block {
pub(crate) fn call_static(
&mut self,
register: RegisterId,
class: types::ClassId,
method: types::MethodId,
arguments: Vec<RegisterId>,
location: LocationId,
) {
self.instructions.push(Instruction::CallStatic(Box::new(CallStatic {
register,
class,
method,
arguments,
location,
Expand Down Expand Up @@ -890,7 +888,6 @@ pub(crate) struct StringLiteral {
#[derive(Clone)]
pub(crate) struct CallStatic {
pub(crate) register: RegisterId,
pub(crate) class: types::ClassId,
pub(crate) method: types::MethodId,
pub(crate) arguments: Vec<RegisterId>,
pub(crate) location: LocationId,
Expand Down Expand Up @@ -1223,9 +1220,8 @@ impl Instruction {
}
Instruction::CallStatic(ref v) => {
format!(
"r{} = call_static {}.{}({})",
"r{} = call_static {}({})",
v.register.0,
v.class.name(db),
v.method.name(db),
join(&v.arguments)
)
Expand Down Expand Up @@ -1368,6 +1364,10 @@ impl Class {
self.methods.push(method.id);
}
}

pub(crate) fn instance_methods_count(&self, db: &Database) -> usize {
self.methods.iter().filter(|m| !m.is_static(db)).count()
}
}

pub(crate) struct Trait {
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/mir/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1846,9 +1846,9 @@ impl<'a> LowerMethod<'a> {
// between the call and the check.
return result;
}
types::Receiver::Class(id) => {
types::Receiver::Class => {
self.current_block_mut()
.call_static(result, id, info.id, arguments, location);
.call_static(result, info.id, arguments, location);
self.reduce_call(info.returns, location);

return result;
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/type_check/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2554,7 +2554,7 @@ impl<'a> CheckMethodBody<'a> {
(
TypeRef::module(id),
TypeId::Module(id),
Receiver::with_module(self.db(), id, method),
Receiver::with_module(self.db(), method),
method,
)
} else {
Expand Down Expand Up @@ -2675,7 +2675,7 @@ impl<'a> CheckMethodBody<'a> {
(
TypeRef::module(id),
TypeId::Module(id),
Receiver::with_module(self.db(), id, method),
Receiver::with_module(self.db(), method),
method,
)
} else {
Expand Down Expand Up @@ -3702,7 +3702,7 @@ impl<'a> CheckMethodBody<'a> {
let mod_typ = TypeRef::Owned(id);

(
Receiver::with_module(self.db(), mod_id, method),
Receiver::with_module(self.db(), method),
mod_typ,
id,
method,
Expand Down
21 changes: 12 additions & 9 deletions types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1937,6 +1937,10 @@ impl MethodId {
)
}

pub fn is_static(self, db: &Database) -> bool {
matches!(self.get(db).kind, MethodKind::Static)
}

pub fn is_extern(self, db: &Database) -> bool {
matches!(self.get(db).kind, MethodKind::Extern)
}
Expand Down Expand Up @@ -2109,7 +2113,7 @@ pub enum Receiver {
///
/// This is separate from an explicit receiver as we don't need to process
/// the receiver expression in this case.
Class(ClassId),
Class,

/// The call is an extern call, and there's no receiver.
Extern,
Expand All @@ -2124,7 +2128,7 @@ impl Receiver {
method
.receiver(db)
.as_class(db)
.map(Receiver::Class)
.map(|_| Receiver::Class)
.unwrap_or(Receiver::Implicit)
}

Expand All @@ -2137,19 +2141,18 @@ impl Receiver {
return Receiver::Extern;
}

receiver.as_class(db).map(Receiver::Class).unwrap_or(Receiver::Explicit)
receiver
.as_class(db)
.map(|_| Receiver::Class)
.unwrap_or(Receiver::Explicit)
}

pub fn with_module(
db: &Database,
id: ModuleId,
method: MethodId,
) -> Receiver {
pub fn with_module(db: &Database, method: MethodId) -> Receiver {
if method.is_extern(db) {
return Receiver::Extern;
}

Receiver::Class(id.class(db))
Receiver::Class
}

pub fn is_explicit(&self) -> bool {
Expand Down

0 comments on commit d455d8f

Please sign in to comment.