highlight.js

Wednesday, May 19, 2021

Javet - Patch V8 Function at Source Code Level

Javet is Java + V8 (JAVa + V + EighT). It is an awesome way of embedding Node.js and V8 in Java.

With the release of v0.8.8, Javet supports patching V8 function at source code level on the fly.

Why is That Important?

Functions can be changed on the fly at JavaScript code level via Javet API. Why to choose this approach? Because sometimes local scoped context is required which is usually called closure. E.g:

const a = function () {
    const b = 1;
    return () => b;
}
const x = a();
console.log(x());
// Output is: 1

Local const b is visible to the anonymous function at line 3, but invisible to the function interceptor. Javet provides a way of changing the function at JavaScript source code level so that local scoped context is still visible.

How?

getSourceCode() and setSourceCode(String sourceCode) are designed for getting and setting the source code. setSourceCode(String sourceCode) actually performs the follow steps.

def setSourceCode(sourceCode):
    existingSourceCode = v8Function.getSourceCode()
    (startPosition, endPosition) = v8Function.getPosition()
    newSourceCode = existingSourceCode[:startPosition] + sourceCode + existingSourceCode[endPosition:]
    v8Function.setSourceCode(newSourceCode)
    v8Function.setPosition(startPosition, startPosition + len(sourceCode))

Be careful, setSourceCode(String sourceCode) has radical impacts that may break the execution because all functions during one execution share the same source code but have their own positions. The following diagram shows the rough memory layout. Assuming function (4) has been changed to something else with position changed, function (1) and (2) will not be impacted because their positions remain the same, but function (3) will be broken because its end position is not changed to the end position of function (4) accordingly.


Javet does not scan memory for all impacted function. So, it is caller's responsibility for restoring the original source code after invocation. The pseudo logic is as following.

originalSourceCode = v8ValueFunction.getSourceCode()
v8ValueFunction.setSourceCode(sourceCode)
v8ValueFunction.call(...)
v8ValueFunction.setSourceCode(originalSourceCode)

Why does setSourceCode() sometimes return false? Usually, that means the local scoped context hasn't been generated by V8. getJSScopeType().isClass() == true indicates that state. After callVoid(null), the local scoped context will be created with getJSScopeType().isFunction() == true and setSourceCode() will work. The pseudo logic is as following.

originalSourceCode = v8ValueFunction.getSourceCode()
if (v8ValueFunction.getJSScopeType().isClass()) {
    try {
        v8ValueFunction.callVoid(null);
        // Now v8ValueFunction.getJSScopeType().isFunction() is true
    } catch (JavetException e) {
    }
}
v8ValueFunction.setSourceCode(sourceCode) // true
v8ValueFunction.call(...)
v8ValueFunction.setSourceCode(originalSourceCode)

The rough lifecycle of a V8 function is as following.


What is the Source Code of a Function in V8?

When V8 calculates start position of a function, it does not include the keyword function and function name. E.g.

function abc(a, b, c) { ... } // Source code is (a, b, c) { ... }

(a, b, c) => { ... }          // Source code is (a, b, c) => { ... }

So, please always discard the keyword function and function name when calling setSourceCode().

Monday, May 10, 2021

Javet — An awesome way of embedding Node.js and V8 in Java

Javet is Java + V8 (JAVa + V + EighT). It is an awesome way of embedding Node.js and V8 in Java.

In Oct, 2020, I was looking for a solution about running JavaScript code in JVM with identical behavior as in a web browser. V8 seemed to be only candidate and the available solution was J2V8.

However, J2V8 has dropped support for Linux in 2017 and Windows in 2016. The V8 doesn’t even completely support ES6.

In Jan, 2021, I started an open-source project https://github.com/caoccao/Javet/ from scratch. Now, it is fully functional and reaches production level.

Major Features

  • 🐧Linux + 🖥️Windows

Quick Start

Dependency

Maven

<dependency>
<groupId>com.caoccao.javet</groupId>
<artifactId>javet</artifactId>
<version>0.8.7</version>
</dependency>

Gradle Kotlin DSL

implementation("com.caoccao.javet:javet:0.8.7")

Gradle Groovy DSL

implementation 'com.caoccao.javet:javet:0.8.7'

Hello Javet

// Node.js Mode
try (V8Runtime v8Runtime = V8Host.getNodeInstance().createV8Runtime()) {
System.out.println(v8Runtime.getExecutor("'Hello Javet'").executeString());
}
// V8 Mode
try (V8Runtime v8Runtime = V8Host.getV8Instance().createV8Runtime()) {
System.out.println(v8Runtime.getExecutor("'Hello Javet'").executeString());
}

Saturday, May 8, 2021

Javet v0.8.7 is released.

 

Javet is Java + V8 (JAVa + V + EighT). It is an awesome way of embedding Node.js and V8 in Java.

For more detail, please visit https://github.com/caoccao/Javet

Monday, May 3, 2021

Fix: Intellij IDEA BindException Address already in use

 Have you even met Address already in use on Windows?


The fix is very simple with the following 2 commands.

net stop winnat
net start winnat



IDEA / HandBrake / WSL Port Conflict

Recently I upgraded HandBrake to the latest version, however, it stopped working. The root cause is TCP port conflict. As usual, I ran net s...