V8 compile error for basic example - c++

I am trying to compile the hello world example for V8, and I keep running into a compile time error. Here is the code:
#include <v8/src/v8.h>
using namespace v8;
int main(int argc, char* argv[]) {
// Create a string holding the JavaScript source code.
String source = String::New("Hi");
// Compile it.
Script script = Script::Compile(source) ;
// Run it.
Value result = script->Run();
// Convert the result to an ASCII string and display it.
String::AsciiValue ascii(result) ;
printf("%s\n", *ascii) ;
return 0;
}
This is the compile error:
error: conversion from ‘v8::Local<v8::String>’ to non-scalar type ‘v8::String’ requested
The error is for line 8 where it says: String source = String::New("Hi");
I have tried google'ing this error senseless, and cannot seem to find a fix for it that makes sense. Any ideas?
I have tried both:
svn checkout http://v8.googlecode.com/svn/trunk/ v8
and
svn checkout http://v8.googlecode.com/svn/branches/bleeding_edge/ v8
and get the same error for both.

Based on the error message, try:
Local<String> source = String::New("Hi");

try this code:
HandleScope handle_scope;
Persistent<Context> context = Context::New();
Context::Scope context_scope(context);
Handle<String> source = String::New("'Hello' + ', World!'");
Handle<Script> script = Script::Compile(source);
TryCatch trycatch;
Handle<Value> result = script->Run();
if ( result.IsEmpty() ) {
Handle<Value> excep = trycatch.Exception();
String::AsciiValue excep_str(excep);
printf("%s\n",*excep);
} else {
String::AsciiValue ascii(result);
printf("%s\n", *ascii);
}
context.Dispose();
return 0;

Related

crash took place when new context was created in MFC

v8 version : 10.5.0
IDE : vs2022
I am trying to embed v8 in MFC. To test simply, I created a dialog project, initialized v8 on OnInitDialog(), disposed it OnDestroy(). And then, I wrote the code to create the context in BN_CLICKED event and run script("Hello World!)". So, when the button was pressed, I wanted to show "Hello World!". But the crash took place in the code that create the context(v8::Local<v8::Context> context = v8::Context::New(isolate, nullptr);).
As a result of testing, this only happens in MFC. This crash does not happen in console programs.
Somebody, anybody help me~. there is my whole code below.
cpp
BOOL Cv8TestDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
...
// Initialize V8.
v8::V8::InitializeICUDefaultLocation("");
v8::V8::InitializeExternalStartupData("");
std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(platform.get());
v8::V8::Initialize();
// Create a new Isolate and make it the current one.
m_create_params.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
m_isolate = v8::Isolate::New(m_create_params);
return TRUE;
}
void Cv8TestDlg::OnDestroy()
{
CDialogEx::OnDestroy();
m_isolate->Dispose();
v8::V8::Dispose();
v8::V8::DisposePlatform();
delete m_create_params.array_buffer_allocator;
}
void Cv8TestDlg::OnRun()
{
CString text;
v8::Isolate* isolate = m_isolate;
v8::Isolate::Scope isolate_scope(isolate);
// Create a stack-allocated handle scope.
v8::HandleScope handle_scope(isolate);
// Create a new context.
v8::Local<v8::Context> context = v8::Context::New(isolate, nullptr);
// Enter the context for compiling and running the hello world script.
v8::Context::Scope context_scope(context);
{
// Create a string containing the JavaScript source code.
v8::Local<v8::String> source = v8::String::NewFromUtf8Literal(isolate, "'Hello' + ', World!'");
// Compile the source code.
v8::Local<v8::Script> script = v8::Script::Compile(context, source).ToLocalChecked();
// Run the script to get the result.
v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();
// Convert the result to an UTF8 string and print it.
v8::String::Value utf8(isolate, result);
text = (LPCWSTR)*utf8;
}
GetDlgItem(IDC_EDIT1)->SetWindowText(text);
}
h
class Cv8TestDlg : public CDialogEx
{
...
v8::Isolate::CreateParams m_create_params;
v8::Isolate* m_isolate = nullptr;
virtual BOOL OnInitDialog();
...
afx_msg void OnDestroy();
afx_msg void OnRun();
};
crash call stack
v8.dll!v8::internal::tracing::TraceEventHelper::GetTracingController()
v8.dll!v8::NewContext(v8::Isolate * external_isolate, v8::ExtensionConfiguration * extensions, v8::MaybeLocal<v8::ObjectTemplate> global_template, v8::MaybeLocal<v8::Value> global_object, unsigned __int64 context_snapshot_index, v8::DeserializeInternalFieldsCallback embedder_fields_deserializer, v8::MicrotaskQueue * microtask_queue) line 6391 C++
v8.dll!v8::Context::New(v8::Isolate * external_isolate, v8::ExtensionConfiguration * extensions, v8::MaybeLocal<v8::ObjectTemplate> global_template, v8::MaybeLocal<v8::Value> global_object, v8::DeserializeInternalFieldsCallback internal_fields_deserializer, v8::MicrotaskQueue * microtask_queue) line 6413 C++
v8Test.exe!Cv8TestDlg::OnRun() line 198 C++
exception message
(0x00007FFADBB43D53(v8.dll), v8Test.exe): 0xC0000005: 0x0000000000000088 access violation
break position(trace-event.cc)
v8::TracingController* TraceEventHelper::GetTracingController() {
-> return v8::internal::V8::GetCurrentPlatform()->GetTracingController();
}
I think the problem is std::unique_ptr<v8::Platform> platform in OnInitDialog. The purpose of a std::unique_ptr is to destroy the thing it points at when the pointer goes out of scope (i.e. in this case, at the end of the function). The v8::Platform should be long-lived, all the way until the v8::V8::DisposePlatform() call.

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

strtok_s was not declared in this scope

I am trying to split my actual key on dot and then extract all the fields after splitting it on dot.
My key would look like something this -
t26.example.1136580077.colox
Below is the code I have which I was in the impression, it should work fine. But somehow whenever I am compiling this code, I always get -
error: âstrtok_sâ was not declared in this scope
Below is my code
if(key) {
vector<string> res;
char* p;
char* totken = strtok_s(key, ".", &p);
while(totken != NULL)
{
res.push_back(totken);
totken = strtok_s(NULL, ".", &p);
}
string field1 = res[0]; // this should be t26
string field2 = res[1]; // this should be example
uint64_t field3 = atoi(res[2].c_str()); // this should be 1136580077
string field4 = res[3]; // this should be colox
cout<<field1<<" "<<field2<<" "<<field3<<" "<<field4<<endl;
}
I am running Ubuntu 12.04 and g++ version is -
g++ (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3
Any idea what wrong I am doing? And if there is any better way of doing it as well, then I am open to that suggestion as well. I am in the impression that using strtok_s will be more efficient and thread safe as well.
#ifndef _MSC_VER
inline
char* strtok_s(char* s, const char* delim, char** context)
{
return strtok_r(s, delim, context);
}
#endif

Calling Windows API with libffi on MinGW

I'm trying to have FFI support for my new programming language, which is written in C++ with QT Creator using the MinGW toolchain.
To do this I used a custom-built version of libffi found here: http://ftp.gnome.org/pub/GNOME/binaries/win32/dependencies/libffi-dev_3.0.6-1_win32.zip
I also tried it with another build: http://pkgs.org/fedora-14/fedora-updates-i386/mingw32-libffi-3.0.9-1.fc14.noarch.rpm.html by downloading the SRPM file on Linux, extracting it, and copying the needed files to a Windows partition.
Anyway, I included the required header file, added the import library to the project and put the .dll beside the application's .exe, it compiles and runs, calling MessageBeep() successfully. I tried it next with MessageBoxA(), but it keeps crashing. The debugger doesn't seem to provide much useful information (edit: beside the fact that a call to MessageBoxA did happen) so I keep fiddling with stuff and re-running to no avail.
To isolate the problem from the details of my language, I tried to manually call MessageBoxA by filling myself all the parameters, resulting in the code below, still crashing.
So my question distills to: How can I get the code snippet below to run under QT Creator/MinGW and actually show a message box?
#include "libffi/include/ffi.h"
#include <QLibrary>
void testMessageBox()
{
int n = 4;
ffi_cif cif;
ffi_type **ffi_argTypes = new ffi_type*[n];
void **values = new void*[n];
values[0] = new ulong(0);
values[1] = (void *) "hello";
values[2] = (void *) "mommy";
values[3] = new int32_t(0);
ffi_argTypes[0] = &ffi_type_ulong;
ffi_argTypes[1] = &ffi_type_pointer;
ffi_argTypes[2] = &ffi_type_pointer;
ffi_argTypes[3] = &ffi_type_uint32;
ffi_type *c_retType = &ffi_type_sint32;
int32_t rc; // return value
if (ffi_prep_cif(&cif, FFI_STDCALL, n, c_retType, ffi_argTypes) == FFI_OK)
{
QLibrary lib("user32.dll");
lib.load();
void *msgbox = lib.resolve("MessageBoxA");
ffi_call(&cif, (void (*)()) msgbox, &rc, values);
}
}
you should pass the address to the values array instead of the values. the working code under mingw64 is
#include <stdio.h>
#include <ffi.h>
#include <Windows.h>
int main()
{
ffi_cif cif;
HINSTANCE dllHandle = LoadLibrary("user32.dll");
int n = 4;
ffi_type *ffi_argTypes[4];
void *values[4];
UINT64 a=0;
UINT32 b=0;
TCHAR* s1= "hello";
TCHAR* s2= "hello2";
values[0] = &a;
values[1] = &s1;
values[2] = &s2;
values[3] = &b;
ffi_argTypes[0] = &ffi_type_uint64;
ffi_argTypes[1] = &ffi_type_pointer;
ffi_argTypes[2] = &ffi_type_pointer;
ffi_argTypes[3] = &ffi_type_uint;
ffi_type *c_retType = &ffi_type_sint;
ffi_type rc; // return value
if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, &ffi_type_sint, ffi_argTypes) == FFI_OK) {
ffi_call(&cif, FFI_FN(GetProcAddress(dllHandle,"MessageBoxA")), &rc, values);
}
return 0;
}

LLVM JIT segfaults. What am I doing wrong?

It is probably something basic because I am just starting to learn LLVM..
The following creates a factorial function and tries to git and execute it (I know the generated func is correct because I was able to static compile and execute it).
But I get segmentation fault upon execution of the function (in EE->runFunction(TheF, Args))
#include "llvm/Module.h"
#include "llvm/Function.h"
#include "llvm/PassManager.h"
#include "llvm/CallingConv.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Support/IRBuilder.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/ExecutionEngine/GenericValue.h"
using namespace llvm;
Module* makeLLVMModule() {
// Module Construction
LLVMContext& ctx = getGlobalContext();
Module* mod = new Module("test", ctx);
Constant* c = mod->getOrInsertFunction("fact64",
/*ret type*/ IntegerType::get(ctx,64),
IntegerType::get(ctx,64),
/*varargs terminated with null*/ NULL);
Function* fact64 = cast<Function>(c);
fact64->setCallingConv(CallingConv::C);
/* Arg names */
Function::arg_iterator args = fact64->arg_begin();
Value* x = args++;
x->setName("x");
/* Body */
BasicBlock* block = BasicBlock::Create(ctx, "entry", fact64);
BasicBlock* xLessThan2Block= BasicBlock::Create(ctx, "xlst2_block", fact64);
BasicBlock* elseBlock = BasicBlock::Create(ctx, "else_block", fact64);
IRBuilder<> builder(block);
Value *One = ConstantInt::get(Type::getInt64Ty(ctx), 1);
Value *Two = ConstantInt::get(Type::getInt64Ty(ctx), 2);
Value* xLessThan2 = builder.CreateICmpULT(x, Two, "tmp");
//builder.CreateCondBr(xLessThan2, xLessThan2Block, cond_false_2);
builder.CreateCondBr(xLessThan2, xLessThan2Block, elseBlock);
/* Recursion */
builder.SetInsertPoint(elseBlock);
Value* xMinus1 = builder.CreateSub(x, One, "tmp");
std::vector<Value*> args1;
args1.push_back(xMinus1);
Value* recur_1 = builder.CreateCall(fact64, args1.begin(), args1.end(), "tmp");
Value* retVal = builder.CreateBinOp(Instruction::Mul, x, recur_1, "tmp");
builder.CreateRet(retVal);
/* x<2 */
builder.SetInsertPoint(xLessThan2Block);
builder.CreateRet(One);
return mod;
}
int main(int argc, char**argv) {
long long x;
if(argc > 1)
x = atol(argv[1]);
else
x = 4;
Module* Mod = makeLLVMModule();
verifyModule(*Mod, PrintMessageAction);
PassManager PM;
PM.add(createPrintModulePass(&outs()));
PM.run(*Mod);
// Now we going to create JIT
ExecutionEngine *EE = EngineBuilder(Mod).create();
// Call the function with argument x:
std::vector<GenericValue> Args(1);
Args[0].IntVal = APInt(64, x);
Function* TheF = cast<Function>(Mod->getFunction("fact64")) ;
/* The following CRASHES.. */
GenericValue GV = EE->runFunction(TheF, Args);
outs() << "Result: " << GV.IntVal << "\n";
delete Mod;
return 0;
}
Edit:
The correct way to enable JIT (see the accepted answer below):
1.#include "llvm/ExecutionEngine/Jit.h"`
2.InitializeNativeTarget();
I would bet that the ExecutionEngine pointer is null.... You are missing a call to InitializeNativeTarget, the documentation says:
InitializeNativeTarget - The main program should call this function to initialize the native target corresponding to the host. This is useful for JIT applications to ensure that the target gets linked in correctly.
Since there is no JIT compiler available without calling InitializeNativeTarget, ModuleBuilder selects the interpreter (if available). Probably not what you wanted. You may want to look at my previous post on this subject.
#include "llvm/ExecutionEngine/Interpreter.h"
Including that header (llvm/ExecutionEngine/Interpreter.h) forces a static initialisation of the JIT. Not the best design decision, but at least it works.