Maybe it is stupid question (I am newbie to C++, just wanted to use it as library for android), but I am not able to run evaluation of some JS multiple times.
I have started with "hello world" tutorial. But then I have wanted simple thing, re-run main (just wrap content of tutorial code into function and run it twice in newly empty main.
This is what I got:
#
# Fatal error in ../src/isolate.cc, line 1868
# Check failed: thread_data_table_.
#
==== C stack trace ===============================
1: 0xa890b9
2: 0x6a22fc
3: 0x42694f
4: 0x405f66
5: 0x405ec7
6: __libc_start_main
7: 0x405dc9
Illegal instruction (core dumped)
This cames after creating new isolate
Isolate* isolate = Isolate::New(create_params);
Well, what I should do? Am I using wrong construct or so? Should I close/delete/clear something more?
In bigger view I just want to do evaluate function, that can be triggered multiple times, and beside that also run multiple js snipets in same context (how to split this function?).
Any idea?
UPDATE:
Ok, lets say that the main can be split into three logical parts:
init
int main(int argc, char* argv[]) {
// Initialize V8.
V8::InitializeICU();
V8::InitializeExternalStartupData(argv[0]);
Platform* platform = platform::CreateDefaultPlatform();
V8::InitializePlatform(platform);
V8::Initialize();
// Create a new Isolate and make it the current one.
ArrayBufferAllocator allocator;
Isolate::CreateParams create_params;
create_params.array_buffer_allocator = &allocator;
evaluation
Isolate* isolate = Isolate::New(create_params);
{
Isolate::Scope isolate_scope(isolate);
// Create a stack-allocated handle scope.
HandleScope handle_scope(isolate);
// Create a new context.
Local<Context> context = Context::New(isolate);
// Enter the context for compiling and running the hello world script.
Context::Scope context_scope(context);
// Create a string containing the JavaScript source code.
Local<String> source =
String::NewFromUtf8(isolate, "'Hello' + ', World!'",
NewStringType::kNormal).ToLocalChecked();
// Compile the source code.
Local<Script> script = Script::Compile(context, source).ToLocalChecked();
// Run the script to get the result.
Local<Value> result = script->Run(context).ToLocalChecked();
// Convert the result to an UTF8 string and print it.
String::Utf8Value utf8(result);
printf("%s\n", *utf8);
}
isolate->Dispose();
and clean
// Dispose and tear down V8.
V8::Dispose();
V8::ShutdownPlatform();
delete platform;
return 0;
Now as I said before if I run main consists of init->evaluation->clean twice, that mean init->evaluation->clean->init->evaluation->clean, then the error occurs. I have figured out, that if I extract evaluation part into separate function I can run it multiple times e.g. as init->(evaluation){2}->clean
Is that how should it work? Next step is to divide this main into tree separate function that mean I have to have static member with platform? Could it cause leak somehow?
NOTE: that I want to run it from android, that mean e.g. click in UI, propagate js source to C via JNI and then call c++ V8, which is already initialized or not. hm?
Prefered way is to have "blackbox", but if I have to hold platform, so be it. It maybe could be also faster without re-initialization of V8, right?
UPDATE 2:
Well, still have problems with splitting evaluation part to achieve multiple runs in same isolate/context.
I have splitted it after creating context with stored isolate and context, but with no luck. When in second part try to create source string it fails, probably because of using stored isolate (something with isolate scope I guess).
:(
My assumption as I introduced in UPDATE1 was correct. That part works well.
According to UPDATE2 I have splitted evaluation part into two.
First for initialize isolate and context:
mIsolate = Isolate::New(mCreate_params);
Isolate::Scope isolate_scope(mIsolate);
{
// Create a stack-allocated handle scope.
HandleScope handle_scope(mIsolate);
v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(mIsolate);
// Bind the global 'print' function to the C++ Print callback.
global->Set(v8::String::NewFromUtf8(mIsolate, "print"), v8::FunctionTemplate::New(mIsolate, Print));
// Create a new context.
mContext = Context::New(mIsolate, NULL, global);
Persistent<Context, CopyablePersistentTraits<Context>> persistent(mIsolate, mContext);
mContext_persistent = persistent;
}
and second that will run js in same context:
Isolate::Scope isolate_scope(mIsolate);
{
HandleScope handle_scope(mIsolate);
mContext = Local<Context>::New(mIsolate, mContext_persistent);
// Enter the context for compiling and running the hello world script.
Context::Scope context_scope(mContext);
{
// Create a string containing the JavaScript source code.
Local<String> source =
String::NewFromUtf8(mIsolate, js_source, NewStringType::kNormal).ToLocalChecked();
// Compile the source code.
Local<Script> script = Script::Compile(mContext, source).ToLocalChecked();
TryCatch trycatch(mIsolate);
// Run the script to get the result.
v8::Local<v8::Value> result;
if(!script->Run(mContext).ToLocal(&result)){
v8::String::Utf8Value exception_str(trycatch.Exception());
dprint(*exception_str);
}else{
if(!result->IsUndefined()){
String::Utf8Value utf8(result);
dprint(*utf8);
}
}
}
}
Well the code works very well on linux, but I still have some issues when I try to run first part for the second time (create new context) on android:
A/art: art/runtime/thread.cc:986] pthread_getschedparam failed for DumpState: No such process
A/art: art/runtime/base/mutex.cc:485] Unexpected state_ 0 in unlock for logging lock
But that's another question I guess. Peace.
Did you initialize v8 more than once?
v8::V8::Initialize() this method should be called once per process.
deep into project source file "v8/src/v8.cc", you will find the prove
bool V8::Initialize() {
InitializeOncePerProcess();
return true;
}
Related
My node.js application has a lot of console logs, which are important for me to see (it's quite a big app so runs for a long time and I need to know that things are still progressing) but I'm ending up with thousands of lines of console logs.
Is it somehow possible to do a console.update that erases/replaces a console line rather than creating a new line?
Try playing with process.stdout methods instead on console:
process.stdout.write("Hello, World");
process.stdout.clearLine(0);
process.stdout.cursorTo(0);
process.stdout.write("\n"); // end the line
TypeScript: clearLine() takes -1, 0, or 1 as a direction parameter with the following meanings:
-1: to the left from cursor.
0: the entire line.
1 - to the right from cursor
Following #michelek's answer, you can use a function somewhat like this:
function printProgress(progress){
process.stdout.clearLine();
process.stdout.cursorTo(0);
process.stdout.write(progress + '%');
}
Sure, you can do this using a module I helped create: fknsrs/jetty
Install via
npm install jetty
Here's a usage example
// Yeah, Jetty!
var Jetty = require("jetty");
// Create a new Jetty object. This is a through stream with some additional
// methods on it. Additionally, connect it to process.stdout
var jetty = new Jetty(process.stdout);
// Clear the screen
jetty.clear();
// write something
jetty.text("hello world");
jetty.moveTo([0,0]);
jetty.text("hello panda");
Jetty is not super useful when used on it's own. It is much more effective when you build some abstraction on top of it to make your jetty calls less verbose.
Just use \r to terminate your line:
process.stdout.write('text\r');
Here's a simple example (wall clock):
setInterval(() => process.stdout.write(`clock: ${new Date()}\r`), 1000);
To write a partial line.
process.stdout.write('text');
process.stdout.write('more');
process.stdout.write('\n'); // end the line
If the volume of output is the real issue then you'll probably to rethink your logging. You could use a logging system that allows selective runtime logging to narrow your output to what you need.
// The sections we want to log and the minimum level
var LOG_LEVEL = 4;
var LOG_SECTIONS = ['section1', 'section2', 'section3'];
function logit(msg, section, level) {
if (LOG_SECTIONS.includes(section) && LOG_LEVEL >= level) {
console.log(section + ':' + msg);
}
}
logit('message 1', 'section1', 4); // will log
logit('message 2', 'section2', 4); // will log
logit('message 3', 'section3', 2); // wont log, below log level
logit('message 4', 'section4', 4); // wont log, not in a log section
if you see stdout exceptions like TypeError: process.stdout.clearLine is not a function in Debug Console window of Visual Studio Code (or Webstorm), run the app as external terminal application instead of internal console. The reason is that Debug Console window is not TTY (process.stdout.isTTY is false). Therefore update your launch configuration in launch.json with "console": "externalTerminal" option.
We can use log-update
const logUpdate = require('log-update');
logUpdate('this will be gone');
logUpdate('this will stay');
Among others, the answer by #michelek does the trick. However, when you start using this, you may run into Exception trouble when output gets redirected to a file or you are in a debugger or running in a linux screen-session, etc. You may see messages such as process.stdout.clearLine is not a function.
Therefore, at least add a test to check that the output is a 'TTY' and is able to do such things as 'clearLine()' and 'cursorTo()':
if (process.stdout.isTTY) {
process.stdout.write("Hello, World");
process.stdout.clearLine(0);
process.stdout.cursorTo(0);
process.stdout.write("\n"); // end the line
}
I'm using V8 to execute some custom javascript code, exposing OnUpdate function to JS world. Overall code works fine but currently I'm concerned about performance of below code - is it required to grab v8::Locker for executing any user defined function? Instruments.app shows code here spends way too much time in v8::Locker constructor and destructor -
90 ms (in actual code execution) vs ~4000ms (by Locker & ~Locker) - this is absurd and I feel I might be doing something wrong.
So my basic question is it really necessary to grab v8::Locker to execute a v8::Function::Call? In current state if I comment out v8::LockerI get below error message:
# Fatal error in HandleScope::HandleScope
# Entering the V8 API without proper locking in place
Code snippet:
int Bucket::send_doc_update_bucket(const char *msg) {
Locker locker(GetIsolate());
Isolate::Scope isolate_scope(GetIsolate());
HandleScope handle_scope(GetIsolate());
Local<Context> context = Local<Context>::New(GetIsolate(), context_);
Context::Scope context_scope(context);
TryCatch try_catch;
Local<Value> args[1];
args[0] = String::NewFromUtf8(GetIsolate(), msg);
assert(!try_catch.HasCaught());
Handle<Value> val;
if(!context->Global()->Get(context,
createUtf8String(GetIsolate(),
"OnUpdate")).ToLocal(&val) ||
!val->IsFunction()) {
return 3;
}
Handle<Function> on_doc_update = Handle<Function>::Cast(val);
on_doc_update->Call(context, context->Global(), 1, args);
if (try_catch.HasCaught()) {
//w->last_exception = ExceptionString(GetIsolate(), &try_catch);
return 2;
}
return 0;
}
If you're not doing any multithreading, you never need to touch v8::Locker. As soon as you do, though, then you have to have it pretty much everywhere.
A v8::Locker is to stop multiple v8::Context's from the same v8::Isolate from running at the same time.
If you want multiple simultaneous threads of execution, each context must be created in a different isolate.
In my logging helper class, I have the following:
this.myInfo = console.info.bind(console);
When I call my myInfo function from elsewhere, the calling object and line number are correctly retained and logged in the Chrome devtools.
When I run myInfo though, I also want to run another local function in addition to the console.info. Hence, I figured I could just wrap the above and it would work. I've come up with the following:
var obj = this;
this.myInfo = (function() {
console.info.apply(this, arguments);
myOtherFunc.apply(obj, arguments);
}).bind(console);
The problem is that unlike my first example, I lose the calling context for console.info, and the wrong line number and file are logged in the devTools.
How can I wrap the first example and retain the proper context for the console.info?
You can use getter. In getter you call your other function and then return console.info.bind(console) to caller.
Object.defineProperty(this, "myInfo", { get: function () {
myOtherFunc();
return console.info.bind(console);
}});
In case of passing arguments. You can define following function:
this.myInfo = function()
{
myOtherFunc.apply(null, arguments);
return console.bind.apply(console, arguments);
}
// example of call
this.myInfo(1,2,3)();
I've new solution. You can implement your console.log wrapper in separate JS file or evaluate it with sourceURL then go to Chrome DevTools settings and add "console-wrapper.js" url to blackbox pattern or blackbox this script by link when first message is arrived to console.
When script become blackboxed then all messages will have correct location in source code.
It works in last Google Chrome Canary build and will be available in stable in around two months.
eval("\
function myAwesomeConsoleLogWrapper() {\
console.log.call(console, arguments);\
makeAnotherWork();\
}\
//# sourceURL=console-wrapper.js");
Alexey Kozyatinskiy's approach is cool. However, if not-pretty code like this.myInfo(1,2,3)() is a more serious problem than ugly console output, you could use the wrapper you posted in your question and print needed filename and line number manually having it extracted from new Error().stack. I'd personnaly use Alexey's method unless there was a team working on this project.
I'm working on a project in C# that get scripts (VBScript, Jscript and JavaScript) from the EA database and executes certain functions at specific moments.
To be able to do this I use the Microsoft ScriptControl.
First I add all script code to the ScriptControl using ScriptControl.AddCode and then I functions with a specific name.
The code that adds the code to the script control looks like this:
//create new scriptcontroller
this.scriptController = new ScriptControl();
this.scriptController.Language = this.language.name;
this.scriptController.AddObject("Repository", model.getWrappedModel());
//Add the actual code. This must be done in a try/catch because a syntax error in the script will result in an exception from AddCode
try
{
//first add the included code
string includedCode = this.IncludeScripts(this._code);
//then remove any statements that execute a function or procedure because scriptControl.AddCode actually executes those statements
string cleanedCode = this.language.removeExecutingStatements(includedCode);
//then add the cleaned code to the scriptcontroller
this.scriptController.AddCode(cleanedCode);
The problem is that apparently AddCode also executes the script code in some way, which is not what I want.
Say I have following VBScript:
sub main
MsgBox("main executed")
end sub
main
As soon as I add the code of this script to the ScriptControl using AddCode the main sub is executed and I see the messagebox appear.
Does anyone know an easy way to avoid executing the main sub in cases like this?
My current workaround (currently only implemented for VBScript) involves parsing the script code and stripping the line that calls functions or procedures, but that is pretty tedious and error prone.
/// <summary>
/// removes the statements that execute a function/procedure from the code
/// </summary>
/// <param name="code">the code with executing statements</param>
/// <returns>the code without executing statements</returns>
public override string removeExecutingStatements(string code)
{
StringReader reader = new StringReader(code);
string cleanedCode = code;
string line;
bool functionStarted = false;
bool subStarted = false;
while (null != (line = reader.ReadLine()))
{
if (line != string.Empty)
{
if (line.StartsWith(this.functionStart))
{
functionStarted = true;
}else if (line.StartsWith(this.subStart))
{
subStarted = true;
}else if (functionStarted && line.StartsWith(this.functionEnd))
{
functionStarted = false;
}
else if (subStarted && line.StartsWith(this.subEnd))
{
subStarted = false;
}else if (!functionStarted && !subStarted)
{
//code outside of a function or sub, figure out if this code calls another sub or function
foreach (string linepart in line.Split(new char[] {' ' , '(' },StringSplitOptions.RemoveEmptyEntries))
{
if (cleanedCode.Contains(this.functionStart + linepart)
||cleanedCode.Contains(this.subStart + linepart))
{
//found a line that calls an existing function or sub, replace it by an empty string.
cleanedCode = cleanedCode.Replace(Environment.NewLine +line + Environment.NewLine,
Environment.NewLine + string.Empty + Environment.NewLine);
}
}
}
}
}
return cleanedCode;
}
Any better idea is welcome.
If you want the script code modules to act as code libraries without any static initializers then you can enforce it by declaring it in coding conventions
If you want the static initializers and other side-effects not to appear until the run-time then you can postpone the script activation through delay loading the script when it is required for the first time
If you want to have more fine-grained control over the scripting environment than you can implement a scripting host and interact with the script engines more directly (e.g. using the IActiveScriptParse interface will not probably trigger any unexpected side-effects).
MSDN: Windows Script Interfaces
...To make implementation of the host as flexible as possible, an OLE Automation wrapper for Windows Script is provided. However, a host that uses this wrapper object to instantiate the scripting engine does not have the degree of control over the run-time name space, the persistence model, and so on, that it would if it used Windows Script directly.
The Windows Script design isolates the interface elements required only in an authoring environment so that nonauthoring hosts (such as browsers and viewers) and script engines (for example, VBScript) can be kept lightweight...
Main executes because you call it from a top level command. Anything not in sub/functions is executed.
I noticed that if I execute a JavaScript script using the mongo command, the script can treat a cursor object as if it was an array.
var conn = new Mongo('localhost:27017');
var db = conn.getDB('learn');
db.test.remove({});
db.test.insert({foo: 'bar'});
var cur = db.test.find();
print(cur[0].foo); //prints: bar
print(cur[1]); // prints: undefined
This seems like it should be beyond the capabilities of the JavaScript language, since there is no way to "overload the subscript operator". So how does this actually work?
As documentation says, it is special ability of driver. It automagicly converts cursor[0] to cursor.toArray()[0]. You can prove it by overriding toArray() with print function or new Error().stack to get callstack back. Here it is:
at DBQuery.a.toArray ((shell):1:32)
at DBQuery.arrayAccess (src/mongo/shell/query.js:290:17)
at (shell):1:2
As you can see, indexing calls arrayAccess. How? Here we have a dbQueryIndexAccess function, which calls arrayAccess.
v8::Handle<v8::Value> arrayAccess = info.This()->GetPrototype()->ToObject()->Get(
v8::String::New("arrayAccess"));
...
v8::Handle<v8::Function> f = arrayAccess.As<v8::Function>();
...
return f->Call(info.This(), 1, argv);
And here we have a code, which sets indexed property handler to this function. WOW, v8 API gives us ability to add this handler!
DBQueryFT()->InstanceTemplate()->SetIndexedPropertyHandler(dbQueryIndexAccess);
... and injects it into JS cursor class, which is defined originaly in JS.
injectV8Function("DBQuery", DBQueryFT(), _global);
Tl;dr: It is hacked in C++ source code of mongo shell.