bytecodealliance / cranelift-jit-demo

JIT compiler and runtime for a toy language, using Cranelift
Apache License 2.0
648 stars 61 forks source link

how to concatenate strings? Send or get string args #56

Open zhuxiujia opened 3 years ago

zhuxiujia commented 3 years ago

Hello, I am a beginner wasm how do I concatenate strings? Send string?in this jit-demo

0xekez commented 3 years ago

This demo doesn't support that but adding the functionality wouldn't be too bad. In Cranelift you can make foreign calls to libc functions without too much trouble. See here for where I do that in my Cranelift Lisp.

Once you've got foreign calls working you could concatenate two strings the same way you normally would in C with calls to strcat and friends.

lechatthecat commented 2 years ago

You can define anonymous string like this:

fn create_anonymous_string(&mut self, string_content: &str) -> Value {
    self.data_ctx.define(string_content.as_bytes().to_vec().into_boxed_slice());

    let sym = self
        .module
        .declare_anonymous_data(true, false)
        .expect("problem declaring data object");

    let _result = self.module
         .define_data(sym, &self.data_ctx)
         .map_err(|e| e.to_string());

    let local_id = self
        .module
        .declare_data_in_func(sym, &mut self.builder.func);
    self.data_ctx.clear();

    let pointer = self.module.target_config().pointer_type();
    self.builder.ins().symbol_value(pointer, local_id)
}

Call this like:

let mut string_content_with_terminator = string_content.to_owned();
string_content_with_terminator.push('\0');
let symbol = self.create_anonymous_string(&string_content_with_terminator);

The string data created by the above function can be concatenated by using C functions as @ezekiiel said.

// anonymous string1
let value1 = self.translate_expr(expr1);
// anonymous string2
let value2 = self.translate_expr(expr2);

let len1 = self.get_str_len(value1);
let len2 = self.get_str_len(value2);
let len_both = self.builder.ins().iadd(len1, len2);
let one = self.builder.ins().iconst(self.int, 1);
let len_both = self.builder.ins().iadd(len_both, one);
let location = self.malloc(len_both);

self.strcpy(location, value1);
self.strcat(location, value2);

Each C function is called like this:

fn get_str_len(&mut self, val: Value) -> Value {
    let mut sig = self.module.make_signature();
    let word = self.module.target_config().pointer_type();
    sig.params.push(AbiParam::new(word));
    sig.returns.push(AbiParam::new(word));

    let callee = self.module
        .declare_function("strlen", cranelift_module::Linkage::Import, &sig)
        .map_err(|e| e.to_string()).unwrap();

    let local_callee = self.module
        .declare_func_in_func(callee, &mut self.builder.func);

    let arg = val;
    let args = vec![arg];

    let call = self.builder.ins().call(local_callee, &args);
    self.builder.inst_results(call)[0]
} 

fn malloc(&mut self, size: Value) -> Value {
    let mut sig = self.module.make_signature();
    let word = self.module.target_config().pointer_type();
    sig.params.push(AbiParam::new(word));
    sig.returns.push(AbiParam::new(word));

    let callee = self.module
        .declare_function("malloc", cranelift_module::Linkage::Import, &sig)
        .map_err(|e| e.to_string()).unwrap();

    let local_callee = self.module
        .declare_func_in_func(callee, &mut self.builder.func);

    let args = vec![size];

    let call = self.builder.ins().call(local_callee, &args);
    self.builder.inst_results(call)[0]
} 

fn strcpy(&mut self, message_buf: Value, message: Value) {
    let mut sig = self.module.make_signature();
    let word = self.module.target_config().pointer_type();
    sig.params.push(AbiParam::new(word));
    sig.params.push(AbiParam::new(word));

    let callee = self.module
        .declare_function("strcpy", cranelift_module::Linkage::Import, &sig)
        .map_err(|e| e.to_string()).unwrap();

    let local_callee = self.module
        .declare_func_in_func(callee, &mut self.builder.func);

    let args = vec![message_buf, message];

    let _call = self.builder.ins().call(local_callee, &args);
} 

fn strcat(&mut self, message_buf: Value, message: Value) {
    let mut sig = self.module.make_signature();
    let word = self.module.target_config().pointer_type();
    sig.params.push(AbiParam::new(word));
    sig.params.push(AbiParam::new(word));

    let callee = self.module
        .declare_function("strcat", cranelift_module::Linkage::Import, &sig)
        .map_err(|e| e.to_string()).unwrap();

    let local_callee = self.module
        .declare_func_in_func(callee, &mut self.builder.func);

    let args = vec![message_buf, message];

    let _call = self.builder.ins().call(local_callee, &args);
}