CML code not giving output - sml

How to view the output of following code?
fun daughter () = let
val daughter_tid = getTid();
in
print ("DAUGHTER : my tid = " ^ (tidToString daughter_tid) ^ "\n")
end;
fun mother () =
let
val mother_tid = getTid();
val daughter_tid = spawn daughter;
in
print("MOTHER : my Tid = " ^ (tidToString mother_tid) ^ "Daughter's tid = " ^ (tidToString daughter_tid) ^ "\n")
end;
RunCML.doit(mother, SOME(Time.fromMilliseconds 10));
The code compiles fine and suppose to provide output as follows :
DAUGHTER : my tid = [0004]
MOTHER : my tid [0003] DAUGHETR's Tid = [0004]

You must use TextIO.print instead of print to get the right output. Without such an explicit reference, the CML version of TextIO does not get loaded when your program is compiled and the print function resolves to the SML/NJ version; since this version of print is not thread safe, problems will result. You can see CML FAQ for more details.

Related

how to log size of array with ilog

I have this code and just want to log size of array :
auto owner = abi_data["owner"].as<chain::authority>();
auto arrSize = std::size(owner.keys);
ilog(arrSize);
But have an error :
error: no matching constructor for initialization of 'fc::log_message'
How can i fix it?
I understand that the c ++ methodology is very specific. Therefore, I will expand my question and thus grope the way.
how to get public key string from auto owner.
i tried :
std::string k = owner.keys[0].key
error: no viable conversion from 'eosio::chain::public_key_type' (aka 'fc::crypto::public_key') to 'std::string'
I don’t understand how I should transform all this for correct work and get correct public key and replace hardcoded old_account_name .
full code :
else if (action.name == N(newaccount)) {
auto new_account_name = abi_data["newact"].as<chain::name>().to_string();
auto creator = abi_data["creator"].as<chain::name>().to_string();
std::string old_account_name = "EOS7ea3Dj15nUkKz3diU7BmE5FV5aNKsBKL6WScwEaKzNwDp41SSU";
auto owner = abi_data["owner"].as<chain::authority>();
auto active = abi_data["active"].as<chain::authority>();
ilog("new_account_name: " + new_account_name + " ,creator: " + creator);
*m_session << "UPDATE user_address SET address = :nan WHERE crypto_currency_asset_id = :ai AND address = :oan",
soci::use(new_account_name, "nan"),
soci::use(old_account_name, "oan"),
soci::use(asset_id, "ai");
}
FIXED!
auto arrSize = sizeof(owner.keys)/sizeof(owner.keys[0]);
auto ownerPK = static_cast<std::string>(owner.keys[0].key);

Adding an Object File to JIT and calling it from IR code

I created a modified version of HowToUseJIT.cpp (llvm version 11.x) that uses IRBuilder class to build a function that calls an external defined in an shared object file.
This example works fine (on my system) when the external has an int argument and return value, but it fails when the argument and return value are double.
The Source for the int case is included below. In addition, the source has instructions, at the top, for transforming it to the double case.
What is wrong with the double version of this example ?
/*
This file is a modified version of the llvm 11.x example HowToUseJIT.cpp:
The file callee.c contains the following text:
int callee(int arg)
{ return arg + 1; }
The shared library callee.so is created from callee.c as follows:
clang -shared callee.c -o callee.so
This example calls the funciton callee from a function that is generated using
the IRBuilder class. It links callee by loading callee.so into its LLJIT.
This works on my sytesm where the progam output is
add1(42) = 43
which is correct.
If I change the type of the function callee from "int (*)(int)" to
"double (*)(double)", the program output is
add1(42) = 4.200000e+01
which is incorrect.
I use following command to change callee.c so that it uses double:
sed -i callee.c \
-e 's|int callee(int arg)|double callee(double arg)|' \
-e 's|return arg + 1;|return arg + 1.0;|'
I use the following command to change this file so that it should porperly
link to the double version of callee:
sed -i add_obj2jit.cpp \
-e '30,$s|"int"|"double"|' \
-e '30,$s|getInt32Ty|getDoubleTy|g' \
-e '/getAddress/s|int|double|g' \
-e 's|int Result = Add1(42);|double Result = Add1(42.0);|
What is wrong with the double version of this example ?
*/
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
using namespace llvm::orc;
ExitOnError ExitOnErr;
// --------------------------------------------------------------------------
void add_obj2jit(LLJIT* jit, const std::string filename)
{ // load object file into memory_buffer
ErrorOr< std::unique_ptr<MemoryBuffer> > error_or_buffer =
MemoryBuffer::getFile(filename);
std::error_code std_error_code = error_or_buffer.getError();
if( std_error_code )
{ std::string msg = "add_obj2jit: " + filename + "\n";
msg += std_error_code.message();
std::fprintf(stderr, "%s\n", msg.c_str() );
std::exit( std_error_code.value() );
}
std::unique_ptr<MemoryBuffer> memory_buffer(
std::move( error_or_buffer.get() )
);
// move object file into jit
Error error = jit->addObjectFile( std::move(memory_buffer) );
if( error )
{ std::fprintf(stderr, "Can't load object file %s", filename.c_str());
std::exit(1);
}
}
// --------------------------------------------------------------------------
ThreadSafeModule createDemoModule() {
auto Context = std::make_unique<LLVMContext>();
auto M = std::make_unique<Module>("test", *Context);
// functiont_t
// function has a return type of "int" and take an argument of "int".
FunctionType* function_t = FunctionType::get(
Type::getInt32Ty(*Context), {Type::getInt32Ty(*Context)}, false
);
// declare the callee function
AttributeList empty_attributes;
FunctionCallee callee = M->getOrInsertFunction(
"callee", function_t, empty_attributes
);
// Create the add1 function entry and insert this entry into module M.
Function *Add1F = Function::Create(
function_t, Function::ExternalLinkage, "add1", M.get()
);
// Add a basic block to the function. As before, it automatically inserts
// because of the last argument.
BasicBlock *BB = BasicBlock::Create(*Context, "EntryBlock", Add1F);
// Create a basic block builder with default parameters. The builder will
// automatically append instructions to the basic block `BB'.
IRBuilder<> builder(BB);
// Get pointers to the integer argument of the add1 function...
assert(Add1F->arg_begin() +1 == Add1F->arg_end()); // Make sure there's an arg
Argument *ArgX = &*Add1F->arg_begin(); // Get the arg
ArgX->setName("AnArg"); // Give it a nice symbolic name for fun.
// Create the call instruction, inserting it into the end of BB.
Value *Add = builder.CreateCall( callee, {ArgX}, "Add=callee(ArgX)" );
// Create the return instruction and add it to the basic block
builder.CreateRet(Add);
return ThreadSafeModule(std::move(M), std::move(Context));
}
// --------------------------------------------------------------------------
int main(int argc, char *argv[]) {
// Initialize LLVM.
InitLLVM X(argc, argv);
InitializeNativeTarget();
InitializeNativeTargetAsmPrinter();
cl::ParseCommandLineOptions(argc, argv, "add_obj2jit");
ExitOnErr.setBanner(std::string(argv[0]) + ": ");
// Create an LLJIT instance.
auto J = ExitOnErr(LLJITBuilder().create());
auto M = createDemoModule();
ExitOnErr(J->addIRModule(std::move(M)));
add_obj2jit(J.get(), "callee.so");
// Look up the JIT'd function, cast it to a function pointer, then call it.
auto Add1Sym = ExitOnErr(J->lookup("add1"));
int (*Add1)(int) = (int (*)(int))Add1Sym.getAddress();
int Result = Add1(42);
outs() << "add1(42) = " << Result << "\n";
// return error number
if( Result != 43 )
return 1;
return 0;
}
Andrea:
Thanks for asking to see the IR outupt. Changing the example code line
// llvm::outs() << *M;
to the line
lvm::outs() << *M;
generates this output.
Looking at the output is was clear to me that second sed command had failed.
This was because it was missing a single quote at the end.
When I fixed this, the double case worked. Here is the outptut, including the IR, for the the int case:
; ModuleID = 'test'
source_filename = "test"
declare i32 #callee(i32)
define i32 #add1(i32 %AnArg) {
EntryBlock:
%0 = call i32 #callee(i32 %AnArg)
ret i32 %0
}
add1(42) = 43
Here is the output for the double case:
; ModuleID = 'test'
source_filename = "test"
declare double #callee(double)
define double #add1(double %AnArg) {
EntryBlock:
%0 = call double #callee(double %AnArg)
ret double %0
}
add1(42) = 4.300000e+01

How do I perform a replacement using a formatted string from a regex capture group?

I am doing multiple replacements at once using the regex crate:
extern crate regex;
use regex::{Captures, Regex};
fn transform(string: &str) {
let rgx = Regex::new(r"(\n)|(/\w+)").unwrap();
let res = rgx.replace_all(string, |caps: &Captures| {
if caps.get(1).is_some() {
return " ";
}
match caps.get(2).map(|m: regex::Match| m.as_str()) {
Some(z) => return "nope", // how to return formatted z instead?
None => (),
}
unreachable!();
});
println!("{}", res);
}
fn main() {
transform("no errors");
transform("big\nbad\n/string");
}
Output as expected:
no errors
big bad nope
Instead of "nope", I would like to return z formatted in some way instead. format! doesn't seem like it can be used here due to String / lifetime issues:
match caps.get(2).map(|m: regex::Match| m.as_str()) {
Some(z) => return format!("cmd: {}", z),
None => (),
}
error[E0308]: mismatched types
--> src/main.rs:12:31
|
12 | Some(z) => return format!("cmd: {}", z),
| ^^^^^^^^^^^^^^^^^^^^^ expected &str, found struct `std::string::String`
|
= note: expected type `&str`
found type `std::string::String`
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
What should be done instead?
Note in the error message:
expected &str
It expects a &str because that's the first type returned by your closure:
return " ";
A closure / function can have only one return type, not two.
The simplest fix is to return a String in both cases:
let res = rgx.replace_all(string, |caps: &Captures| {
if caps.get(1).is_some() {
return String::from(" ");
}
let m = caps.get(2).unwrap();
format!("cmd: {}", m.as_str())
});
To be slightly more efficient, you can avoid the String allocation for the space character:
use std::borrow::Cow;
let res = rgx.replace_all(string, |caps: &Captures| {
if caps.get(1).is_some() {
return Cow::from(" ");
}
let m = caps.get(2).unwrap();
Cow::from(format!("cmd: {}", m.as_str()))
});
playground
I've also replaced the match with the => () arm paired with the unreachable! with the shorter unwrap.
See also:
Cannot use `replace_all` from the regex crate: expected (), found String
Using str and String interchangably
Return local String as a slice (&str)

The param was changed by passed to a function when I call the function

The function is defined like this:
1 db_bool cm_text_equal(const cm_text_t *text1, const cm_text_t *text2, db_bool case_ins)
and it will be called like this:
cm_format_element_t * cm_fetch_fmt_element(cm_text_t * fmt)
{
db_uint32 i;
cm_text_t cmp_text;
CM_POINTER(fmt);
cmp_text.str = fmt->str;
for(i = 0; i < DATE_FORMAT_COUNT; i++)
{
cmp_text.len = g_fmt_elements[i].name.len;
if(cmp_text.len > fmt->len)
{
continue;
}
//2 the problem happens here where the function be called
if(cm_text_equal(&g_fmt_elements[i].name, &cmp_text, DB_TRUE))
{
fmt->str += cmp_text.len;
fmt->len = (db_uint16)(fmt->len - cmp_text.len);
return &g_fmt_elements[i];
}
}
return NULL;
}
the g_fmt_elements[] is defined like this:
cm_format_element_t g_fmt_elements[DATE_FORMAT_COUNT] =
{
{{1, (db_char *)" "}, FMT_SPACE_SPLIT, DB_TRUE},
{{1, (db_char *)"-"}, FMT_MINUS_SPLIT, DB_TRUE},
...
}
typedef struct tagcm_format_element
{
cm_text_t name;
db_uint16 id;
db_bool reverse_used;
}cm_format_element_t;
typedef struct tagcm_text
{
db_uint32 len;
db_char * str;
}cm_text_t;
I debug the program by gdb. so before the function cm_text_equal called. the threee parameters are:
&g_fmt_elements[i].name = (cm_text_t *) 0x7f24f8766890
&cmp_text=0x7f2553ef8790
DB_TRUE=1
when cm_fetch_fmt_element is running to the line "//2 the problem...".
the i=30. and the variable g_fmt_elements is a global static variable.
you can see its definition below.
(gdb) p g_fmt_elements[30]
$57 = {name = {len = 4, str = 0x7f24f854a949 "YYYY"}, id = 226, reverse_used = 1}
(gdb) p &g_fmt_elements[30]
$58 = (cm_format_element_t *) 0x7f24f8766890
Then I step into the function cm_text_equal, and it turns out:
(gdb) s
cm_text_equal (text1=0x7f256ec655d0, text2=0x7f2553ef8790, case_ins=1) at src/db_text.c:504
so you can see, the first param was changed from 0x7f24f8766890 to 0x7f256ec655d0, and I check the regesters:
(gdb) p/x $rdi
$52 = 0x7f256ec655d0
(gdb) p/x $rsi
$53 = 0x7f2553ef8790
(gdb) p/x $rdx
$54 = 0x1
you can see the first param passed into the rdi was real changed. Does anyone know how that happend?
I also checked two different addrs.
(gdb) p *(cm_format_element_t*)0x7f256ec655d0
$55 = {name = {len = 4, str = 0x7f256ea6275c "YYYY"}, id = 226, reverse_used = 0}
(gdb) p *(cm_format_element_t*)0x7f24f8766890
$56 = {name = {len = 4, str = 0x7f24f854a949 "YYYY"}, id = 226, reverse_used = 1}
you see, 0x7f24f8766890 is the right addr and its value is the same as definition. while the other addr 0x7f256ec655d0 is wrong, but I don't understand its value almost the same as the right one. However the last member is wrong, which makes my program runs abnormally.
here is more details that I found later
thank you all for trying to help.
I guess I found where to be wrong.
It almost took me two days to figure out the reason, I am not good at. Haha.
but I just still want to answer it for others who may have the same problems.
Ok, let's begin.
Because I have restart my program, so the addr have changed. so this time
before step into the function. the add of g_fmt_elements[30] is:
(gdb) p g_fmt_elements[30]
$6 = {name = {len = 4, str = 0x2ae97faa554e "YYYY"}, id = 226, reverse_used = 1}
(gdb) p &g_fmt_elements[30]
$7 = (cm_format_element_t *) 0x2ae97fcc34d0
(gdb)
and after step into the function, the param text1 become to :
(gdb) cm_text_equal (text1=0x2ae90be468f0, text2=0x2ae926d85540, case_ins=1) at src/db_text.c:499
so, you see, the (cm_format_element_t *) 0x2ae97fcc34d0 seems to changed to text1=0x2ae90be468f0, so I also check these two addr's context:
//-->the right one
(gdb)p *(cm_format_element_t*)0x2ae97fcc34d0
{name = {len = 4, str = 0x2ae97faa554e "YYYY"}, id = 226, reverse_used = 1}
//-->the wrong one
(gdb)p *(cm_format_element_t*)0x2ae90be468f0
{name = {len = 4, str = 0x2ae90bc432e6"YYYY"}, id = 226, reverse_used = 0}
the two's context almost same but the values of "addr of str" and "reverse_used".
so, how exactly the wrong addr 0x2ae90be468f0 comes, and why the context is almost the same?
so, info the libs addr of the program and found which lib does the addr 0x2ae90be468f0 belonged to.

What is invalid SourceLocation in clang and how to interact with it?

I need to replace some variable declarations with others.
For example
int a = 5;
becomes
T<int> a = 5;
More generic
X a = _const;
becomes
T<X> a = _const;
I tried to implement an ASTVisitor descendant in clang:
bool VisitVarDecl(Decl *f) {
if (VarDecl* VD = dyn_cast_or_null<VarDecl>(f)){
Expr* init = VD->getInit();
SourceRange definition = VD->getDefinition()->getSourceRange();
FullSourceLoc exprLoc = ctx.getFullLoc(init->getLocStart());
FullSourceLoc vLoc = ctx.getFullLoc(VD->getLocStart());
...
I want to replace the definition of variable in the next way:
TheRewriter.ReplaceText(VD->getLocStart(), exprLoc.getSpellingColumnNumber()-vLoc.getSpellingColumnNumber(), someSting);
But any call exprLoc.getSpellingColumnNumber() leads to segmentation fault. For example I just try to print exprLoc.getSpellingColumnNumber():
llvm::outs()<< "init start at "
<<exprLoc.getSpellingColumnNumber(&isValid)
<<" is "<<(isValid?"valid ":"invalid ")
<<", decl start at "
<<vLoc.getSpellingColumnNumber()
<<".\n";
And output is
init start at 9 is invalid , decl start at 1.
<…>
Segmentation fault
What does it mean “invalid” SourceLocation and how to interact with it?