Broken site based impl
This commit is contained in:
@@ -2,7 +2,7 @@ mod basic_block;
|
||||
|
||||
use crate::{
|
||||
flatten::FlatFn,
|
||||
libqjs::parse::{AtomRef, ImmOperand, Instr, JsValue, opcodes::OpCode},
|
||||
libqjs::parse::{ImmOperand, Instr, JsValue, opcodes::OpCode},
|
||||
};
|
||||
|
||||
pub use basic_block::BasicBlock;
|
||||
@@ -29,7 +29,6 @@ impl RegInstr {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RegFn {
|
||||
pub name: AtomRef,
|
||||
pub arg_count: usize,
|
||||
pub var_count: usize,
|
||||
/// Locals and args are not renamed: local `k` is value id `k`, and arg `k`
|
||||
@@ -119,8 +118,25 @@ impl RegFn {
|
||||
}
|
||||
}
|
||||
|
||||
// A define_field into an object that no creating op of this fn gave
|
||||
// (a class field on `this`, a static field on the class) is a write
|
||||
// like any other: a put_field. So a define_field is always a write
|
||||
// that builds an object before it goes anywhere (see infer)
|
||||
let mut created = vec![false; next_val];
|
||||
|
||||
for instr in &out {
|
||||
if matches!(instr.op, OpCode::Object | OpCode::Fclosure | OpCode::Fclosure8) {
|
||||
created[instr.dsts[0]] = true;
|
||||
}
|
||||
}
|
||||
|
||||
for instr in &mut out {
|
||||
if instr.op == OpCode::DefineField && !created[instr.args[1]] {
|
||||
instr.op = OpCode::PutField;
|
||||
}
|
||||
}
|
||||
|
||||
Self {
|
||||
name: f.name,
|
||||
arg_count: f.arg_count,
|
||||
var_count: f.var_count,
|
||||
val_count: next_val,
|
||||
@@ -209,7 +225,7 @@ fn walk_block(
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle `Dup` and `Swap`, which just push values
|
||||
// Handle `Dup`, `Dup2`, `Swap` and `ToPropkey2`, which just push values
|
||||
if instr.op == OpCode::Dup {
|
||||
stack.push(out_instr.args[0]);
|
||||
stack.push(out_instr.args[0]);
|
||||
@@ -219,6 +235,27 @@ fn walk_block(
|
||||
continue;
|
||||
}
|
||||
|
||||
if instr.op == OpCode::Dup2 {
|
||||
let (a, b) = (out_instr.args[1], out_instr.args[0]);
|
||||
stack.extend([a, b, a, b]);
|
||||
out_instr.op = OpCode::Nop;
|
||||
out_instr.imm = ImmOperand::None;
|
||||
out[instr_idx] = out_instr;
|
||||
continue;
|
||||
}
|
||||
|
||||
// to_propkey2 makes the key on top a property key, and keeps the
|
||||
// object under it. A key is a number, which it keeps as it is (see
|
||||
// infer), so it only gives both back
|
||||
if instr.op == OpCode::ToPropkey2 {
|
||||
stack.push(out_instr.args[1]);
|
||||
stack.push(out_instr.args[0]);
|
||||
out_instr.op = OpCode::Nop;
|
||||
out_instr.imm = ImmOperand::None;
|
||||
out[instr_idx] = out_instr;
|
||||
continue;
|
||||
}
|
||||
|
||||
if instr.op == OpCode::Swap {
|
||||
stack.push(out_instr.args[0]);
|
||||
stack.push(out_instr.args[1]);
|
||||
@@ -228,11 +265,11 @@ fn walk_block(
|
||||
continue;
|
||||
}
|
||||
|
||||
// A field write lands back in the object's own value: the object with
|
||||
// the field is the same object. define_field also leaves it on the
|
||||
// stack, put_field does not
|
||||
if matches!(instr.op, OpCode::PutField | OpCode::DefineField) {
|
||||
let obj = out_instr.args[1];
|
||||
// A field or element write lands back in the object's own value: the
|
||||
// object with the field is the same object. define_field also leaves
|
||||
// it on the stack, put_field and put_array_el do not
|
||||
if matches!(instr.op, OpCode::PutField | OpCode::DefineField | OpCode::PutArrayEl) {
|
||||
let obj = *out_instr.args.last().unwrap();
|
||||
|
||||
if n_push == 1 {
|
||||
stack.push(obj);
|
||||
|
||||
Reference in New Issue
Block a user