Skip to content

Commit fc981d1

Browse files
committed
fix(interpreter): fix side-effects on type-info icalls
1 parent ea8551d commit fc981d1

4 files changed

Lines changed: 56 additions & 7 deletions

File tree

‎interpreter/src/builtins.rs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,8 @@ fn typeof_value<'a>(v: &Value<'_>) -> Value<'a> {
256256
Value::String(_) => b"string",
257257
Value::Regex(_) => b"regexp",
258258
Value::Array(_) => b"array",
259-
Value::Untyped | Value::Unassigned => b"untyped",
259+
Value::Untyped => b"untyped",
260+
Value::Unassigned => b"unassigned",
260261
};
261262
Value::String(name.into())
262263
}

‎interpreter/src/ir.rs‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ pub enum Instruction {
6969
StoreR { dest: Reg, src: Arg, arg: Arg, ty: ArgTy, tys: ArgTy },
7070
StoreA { dest: Reg, ty_place: ArgTy, start: Reg, end: Reg, var: NonLocal, arg: Reg },
7171
LoadA { dest: Reg, ty_place: ArgTy, start: Reg, end: Reg, var: NonLocal },
72+
PureCopy { dest: Reg, arg: Arg, ty: ArgTy },
7273
IntrinsicCall { dest: Reg, start: Reg, end: Reg, fun: BuiltinFunction },
7374
OutputCall { start: Reg, end: Reg, cmd: Command, redir: Option<Redirection> },
7475
UserCall { dest: Reg, start: Reg, end: Reg, name: NonLocal },
@@ -206,7 +207,8 @@ impl Display for Instruction {
206207
| Self::Negation { dest, arg, ty }
207208
| Self::ToInt { dest, arg, ty }
208209
| Self::Negative { dest, arg, ty }
209-
| Self::Copy { dest, arg, ty } => {
210+
| Self::Copy { dest, arg, ty }
211+
| Self::PureCopy { dest, arg, ty } => {
210212
write!(f, "{dest} <- {op}")?;
211213
fmt_arg(f, arg, ty, " ")
212214
}
@@ -316,6 +318,7 @@ impl Instruction {
316318
Self::StoreA { .. } => "astore",
317319
Self::LoadA { .. } => "aload",
318320
Self::Copy { .. } => "cpy",
321+
Self::PureCopy { .. } => "pcpy",
319322
Self::IntrinsicCall { .. } => "icall",
320323
Self::UserCall { .. } => "ucall",
321324
Self::IndirectCall { .. } => "vcall",

‎interpreter/src/ir/lower.rs‎

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ use std::{borrow::Cow, mem::forget, ops::Deref, vec::Vec as StdVec};
88
use bumpalo::{Bump, collections::Vec};
99
use either::Either;
1010
use parser::{
11-
ArrayOperator, Ast, Atom, BinaryOperator, BinaryPlaceOperator, Body, Command, Expr, ExprNode,
12-
Function as AstFunction, FunctionTable, Identifier, MetaId, Place, Rule, RulePattern,
13-
SimpleStatement, Statement, UnaryOperator, UnaryPlaceOperator, Variable,
11+
ArrayOperator, Ast, Atom, BinaryOperator, BinaryPlaceOperator, Body, BuiltinFunction, Command,
12+
Expr, ExprNode, Function as AstFunction, FunctionTable, Identifier, MetaId, Place, Rule,
13+
RulePattern, SimpleStatement, Statement, UnaryOperator, UnaryPlaceOperator, Variable,
1414
};
1515

1616
use crate::{
@@ -654,7 +654,31 @@ impl<'a> CodeGen<'a> {
654654
this.emit(Instruction::UserCall { dest, start, end, name });
655655
}
656656
ExprNode::BuiltinCall(fun, args) => {
657-
let (start, end, ()) = this.gen_call_convention(args, |_| ());
657+
// Bypass regular variable lookups on type-info funs.
658+
let (start, end, _) = match fun {
659+
BuiltinFunction::Typeof | BuiltinFunction::Isarray
660+
if let &[Expr::Leaf(Atom::Variable(var), _)] =
661+
args.as_slice() =>
662+
{
663+
let TypedArg(arg, ty) =
664+
this.load_place(dest, &Place::Variable(var));
665+
this.emit(Instruction::PureCopy { dest, arg, ty });
666+
(dest, Reg(dest.0 + 1), ())
667+
}
668+
BuiltinFunction::Typeof | BuiltinFunction::Isarray
669+
if let [expr] = args.as_slice() =>
670+
{
671+
this.lower_expr_into(expr, dest);
672+
(dest, Reg(dest.0 + 1), ())
673+
}
674+
BuiltinFunction::Typeof
675+
if let &[Expr::Leaf(Atom::Variable(_var), _), ref _arg2] =
676+
args.as_slice() =>
677+
{
678+
todo!()
679+
}
680+
_ => this.gen_call_convention(args, |_| ()),
681+
};
658682
this.emit(Instruction::IntrinsicCall { dest, start, end, fun: *fun });
659683
}
660684
ExprNode::IndirectCall(place, args) => {

‎interpreter/src/vm.rs‎

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ impl<'a> SymbolTable<'a> {
320320
.borrow()
321321
.get(key)
322322
.cloned()
323-
.unwrap_or(Value::Unassigned)
323+
.unwrap_or(Value::Untyped)
324324
}
325325

326326
fn store_user_array_elem(&mut self, var: NonLocal, key: String, value: Value<'a>) {
@@ -443,6 +443,10 @@ impl<'a> Interpreter<'a> {
443443
let val = arg.get_val(ty, self, &mut MaybeUninit::uninit()).clone();
444444
self.write_reg(dest, val);
445445
}
446+
Instruction::PureCopy { dest, arg, ty } => {
447+
let val = arg.get_pure(ty, self, &mut MaybeUninit::uninit()).clone();
448+
self.write_reg(dest, val);
449+
}
446450
Instruction::Eq { dest, lhs, rhs, tyl, tyr } => {
447451
let val = Arg::get_val2(lhs, tyl, rhs, tyr, self, |lhs, rhs| lhs == rhs);
448452
self.write_reg(dest, val);
@@ -841,6 +845,23 @@ impl Arg {
841845
f(lhs, rhs)
842846
}
843847

848+
/// Gets a value without scalar/array side-effects.
849+
fn get_pure<'v, 'a>(
850+
self,
851+
ty: ArgTy,
852+
intrp: &'v Interpreter<'a>,
853+
stack_space: &'v mut MaybeUninit<Value<'a>>,
854+
) -> &'v Value<'a> {
855+
match ty {
856+
ArgTy::Reg => intrp.read_reg(unsafe { self.reg }),
857+
ArgTy::Rec => todo!(),
858+
ArgTy::Imm => stack_space.write(Value::Int(unsafe { self.imm } as _)),
859+
ArgTy::Cnt | ArgTy::ImmF => &intrp.consts.0[unsafe { self.sym.0 } as usize],
860+
ArgTy::UsVal => intrp.symbols.raw_user_lookup(unsafe { self.sym }),
861+
_ => todo!(),
862+
}
863+
}
864+
844865
/// Only exists to make the borrow checker happy. To be used in conjunction
845866
/// w/ [`Self::read_already_prepared`]. Please, don't use either of these if
846867
/// you can help it; use [`Self::get_val`] or [`Self::get_val2`] instead.

0 commit comments

Comments
 (0)