Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the ThrowException fn to the isolate #221

Merged
merged 10 commits into from
Nov 10, 2021
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Support for setting and getting internal fields for template object instances
- Support for CPU profiling
- Add V8 build for Apple Silicon
- Add support for throwing an exception directly via the isolate's ThrowException function.

### Changed
- Removed error return value from NewIsolate which never fails
Expand Down
13 changes: 13 additions & 0 deletions isolate.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,19 @@ func (i *Isolate) Dispose() {
i.ptr = nil
}

// ThrowException schedules an exception to be thrown when returning to
// JavaScript. When an exception has been scheduled it is illegal to invoke
// any JavaScript operation; the caller must return immediately and only after
// the exception has been handled does it become legal to invoke JavaScript operations.
func (i *Isolate) ThrowException(value *Value) *Value {
if i.ptr == nil {
panic("Isolate has been disposed")
}
return &Value{
ptr: C.IsolateThrowException(i.ptr, value.ptr),
}
}

// Deprecated: use `iso.Dispose()`.
func (i *Isolate) Close() {
i.Dispose()
Expand Down
52 changes: 52 additions & 0 deletions isolate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,58 @@ func TestIsolateGarbageCollection(t *testing.T) {
time.Sleep(time.Second)
}

func TestIsolateThrowException(t *testing.T) {
t.Parallel()
iso := v8.NewIsolate()
defer iso.Dispose()

strErr, _ := v8.NewValue(iso, "some type error")

throwError := func(val *v8.Value) {
v := iso.ThrowException(val)

if !v.IsNullOrUndefined() {
t.Error("expected result to be null or undefined")
}
}

// Function that throws a simple string error from within the function. It is meant
// to emulate when an error is returned within Go.
fn := v8.NewFunctionTemplate(iso, func(info *v8.FunctionCallbackInfo) *v8.Value {
throwError(strErr)

return nil
})

// Function that is passed a TypeError from JavaScript.
fn2 := v8.NewFunctionTemplate(iso, func(info *v8.FunctionCallbackInfo) *v8.Value {
typeErr := info.Args()[0]

throwError(typeErr)

return nil
})

global := v8.NewObjectTemplate(iso)
global.Set("foo", fn)
global.Set("foo2", fn2)

ctx := v8.NewContext(iso, global)
defer ctx.Close()

_, e := ctx.RunScript("foo()", "foo.js")

if e.Error() != "some type error" {
t.Errorf("expected \"some type error\" error but got: %v", e)
}

_, e = ctx.RunScript("foo2(new TypeError('this is a test'))", "foo.js")

if e.Error() != "TypeError: this is a test" {
t.Errorf("expected \"TypeError: this is a test\" error but got: %v", e)
}
}

func BenchmarkIsolateInitialization(b *testing.B) {
b.ReportAllocs()
for n := 0; n < b.N; n++ {
Expand Down
17 changes: 17 additions & 0 deletions v8go.cc
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,23 @@ IsolateHStatistics IsolationGetHeapStatistics(IsolatePtr iso) {
hs.number_of_detached_contexts()};
}

/********** Exceptions & Errors **********/

ValuePtr IsolateThrowException(IsolatePtr iso, ValuePtr value) {
ISOLATE_SCOPE(iso);
m_ctx* ctx = value->ctx;

Local<Value> throw_ret_val = iso->ThrowException(value->ptr.Get(iso));

m_value* new_val = new m_value;
new_val->iso = iso;
new_val->ctx = ctx;
new_val->ptr = Persistent<Value, CopyablePersistentTraits<Value>>(
iso, throw_ret_val);

return tracked_value(ctx, new_val);
}

/********** CpuProfiler **********/

CPUProfiler* NewCPUProfiler(IsolatePtr iso_ptr) {
Expand Down
2 changes: 2 additions & 0 deletions v8go.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ extern void IsolateTerminateExecution(IsolatePtr ptr);
extern int IsolateIsExecutionTerminating(IsolatePtr ptr);
extern IsolateHStatistics IsolationGetHeapStatistics(IsolatePtr ptr);

extern ValuePtr IsolateThrowException(IsolatePtr iso, ValuePtr value);

extern CPUProfiler* NewCPUProfiler(IsolatePtr iso_ptr);
extern void CPUProfilerDispose(CPUProfiler* ptr);
extern void CPUProfilerStartProfiling(CPUProfiler* ptr, const char* title);
Expand Down