func (v *V8Context) Eval(javascript string, filename string) (res interface{}, err error) {
	if v.v8context == nil {
		panic("Context is uninitialized.")
	}
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()
	jsPtr := C.CString(javascript)
	defer C.free(unsafe.Pointer(jsPtr))
	var filenamePtr *C.char
	if len(filename) > 0 {
		filenamePtr = C.CString(filename)
		defer C.free(unsafe.Pointer(filenamePtr))
	}
	ret := C.v8_execute(v.v8context, jsPtr, filenamePtr)
	if ret != nil {
		out := C.GoString(ret)
		if out != "" {
			C.free(unsafe.Pointer(ret))
			err := json.Unmarshal([]byte(out), &res)
			return res, err
		}
		return out, nil
	}
	if C.v8_context_has_terminated(v.v8context) {
		return "", ErrTerminated
	}
	ret = C.v8_error(v.v8context)
	out := C.GoString(ret)
	C.free(unsafe.Pointer(ret))
	return nil, errors.New(out)
}
Eval executes the provided javascript within the V8 context.  The javascript
is executed as if it was from the specified file, so that any errors or stack
traces are annotated with the corresponding file/line number.

The result of the javascript is returned as POD serialized via JSON and
unmarshaled back into Go, otherwise an error is returned.
package v8
import "C"
import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"path"
	"reflect"
	"runtime"
	"sync"
	"text/template"
	"unsafe"
)
var contexts = make(map[uint]*V8Context)
var contextsMutex sync.RWMutex
var highestContextId uint
var ErrTerminated = errors.New("Operation terminated prematurely")
const NO_FILE = ""
type Value struct {
	ptr C.PersistentValuePtr
	ctx *V8Context
}
func (v *Value) ToJSON() (string, error) {
	if v.ctx == nil || v.ptr == nil {
		panic("Value or context were reset.")
	}
	str := C.PersistentToJSON(v.ctx.v8context, v.ptr)
	if str == nil {
		if C.v8_context_has_terminated(v.ctx.v8context) {
			return "", ErrTerminated
		}
		err := C.v8_error(v.ctx.v8context)
		out := C.GoString(err)
		C.free(unsafe.Pointer(err))
		return "", errors.New(out)
	}
	defer C.free(unsafe.Pointer(str))
	return C.GoString(str), nil
}
func (v *Value) ToString() (string, error) {
	if v.ctx == nil || v.ptr == nil {
		panic("Value or context were reset.")
	}
	jsonStr, err := v.ToJSON()
	if err != nil {
		return "", err
	}
	var str string
	err = json.Unmarshal([]byte(jsonStr), &str)
	return str, err
}
func (v *Value) Burst() (map[string]*Value, error) {
	if v.ctx == nil || v.ptr == nil {
		panic("Value or context were reset.")
	}
	var numKeys C.int
	keyValuesPtr := C.v8_BurstPersistent(v.ctx.v8context, v.ptr, &numKeys)
	if keyValuesPtr == nil {
		if C.v8_context_has_terminated(v.ctx.v8context) {
			return nil, ErrTerminated
		}
		err := C.v8_error(v.ctx.v8context)
		defer C.free(unsafe.Pointer(err))
		return nil, errors.New(C.GoString(err))
	}
	var keyValues []C.struct_KeyValuePair
	sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&keyValues)))
	sliceHeader.Cap = int(numKeys)
	sliceHeader.Len = int(numKeys)
	sliceHeader.Data = uintptr(unsafe.Pointer(keyValuesPtr))
	result := make(map[string]*Value)
	for _, keyVal := range keyValues {
		key := C.GoString(keyVal.keyName)
		val := v.ctx.newValue(keyVal.value)
		result[key] = val
		C.free(unsafe.Pointer(keyVal.keyName))
	}
	return result, nil
}
func (v *Value) Get(field string) (*Value, error) {
	if v == nil {
		panic("nil value")
	}
	if v.ctx == nil || v.ptr == nil {
		panic("Value or context were reset.")
	}
	fields, err := v.Burst()
	if err != nil {
		return nil, err
	}
	res, exists := fields[field]
	if !exists || res == nil {
		return nil, fmt.Errorf("field '%s' is undefined.", field)
	}
	return res, nil
}
func (v *Value) Set(field string, val *Value) error {
	if v.ctx == nil || v.ptr == nil {
		panic("Value or context were reset.")
	}
	fieldPtr := C.CString(field)
	defer C.free(unsafe.Pointer(fieldPtr))
	errmsg := C.v8_setPersistentField(v.ctx.v8context, v.ptr, fieldPtr, val.ptr)
	if errmsg != nil {
		return errors.New(C.GoString(errmsg))
	}
	return nil
}
func _go_v8_callback(ctxID uint, name, args *C.char) *C.char {
	runtime.UnlockOSThread()
	defer runtime.LockOSThread()
	contextsMutex.RLock()
	c := contexts[ctxID]
	contextsMutex.RUnlock()
	f := c.funcs[C.GoString(name)]
	if f != nil {
		var argv []interface{}
		json.Unmarshal([]byte(C.GoString(args)), &argv)
		ret := f(argv...)
		if ret != nil {
			b, _ := json.Marshal(ret)
			return C.CString(string(b))
		}
		return nil
	}
	return C.CString("undefined")
}
func _go_v8_callback_raw(
	ctxID uint,
	name *C.char,
	callerFuncName, callerScriptName *C.char,
	callerLineNumber, callerColumn C.int,
	argc C.int,
	argvptr C.PersistentValuePtr,
) C.PersistentValuePtr {
	runtime.UnlockOSThread()
	defer runtime.LockOSThread()
	funcname := C.GoString(name)
	caller := Loc{
		Funcname: C.GoString(callerFuncName),
		Filename: C.GoString(callerScriptName),
		Line:     int(callerLineNumber),
		Column:   int(callerColumn),
	}
	contextsMutex.RLock()
	ctx := contexts[ctxID]
	contextsMutex.RUnlock()
	function := ctx.rawFuncs[funcname]
	var argv []C.PersistentValuePtr
	sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&argv)))
	sliceHeader.Cap = int(argc)
	sliceHeader.Len = int(argc)
	sliceHeader.Data = uintptr(unsafe.Pointer(argvptr))
	if function == nil {
		panic(fmt.Errorf("No such registered raw function: %s", C.GoString(name)))
	}
	args := make([]*Value, argc)
	for i := 0; i < int(argc); i++ {
		args[i] = ctx.newValue(argv[i])
	}
	res, err := function(caller, args...)
	if err != nil {
		ctx.throw(err)
		return nil
	}
	if res == nil {
		return nil
	}
	if res.ctx.v8context != ctx.v8context {
		panic(fmt.Errorf("Error processing return value of raw function callback %s: "+
			"Return value was generated from another context.", C.GoString(name)))
	}
	return res.ptr
}
type Function func(...interface{}) interface{}
type Loc struct {
	Funcname, Filename string
	Line, Column       int
}
type RawFunction func(from Loc, args ...*Value) (*Value, error)
type V8Isolate struct {
	v8isolate C.IsolatePtr
}
type V8Context struct {
	id        uint
	v8context C.ContextPtr
	v8isolate *V8Isolate
	funcs     map[string]Function
	rawFuncs  map[string]RawFunction
	values    map[*Value]bool
	valuesMu  *sync.Mutex
}
var platform C.PlatformPtr
var defaultIsolate *V8Isolate
func init() {
	platform = C.v8_init()
	defaultIsolate = NewIsolate()
}
func NewIsolate() *V8Isolate {
	res := &V8Isolate{C.v8_create_isolate()}
	runtime.SetFinalizer(res, func(i *V8Isolate) {
		C.v8_release_isolate(i.v8isolate)
	})
	return res
}
func NewIsolateWithSnapshot(js string) (*V8Isolate, error) {
	jsCstr := C.CString(js)
	defer C.free(unsafe.Pointer(jsCstr))
	snapshot := C.v8_create_snapshot(jsCstr)
	if snapshot == nil {
		return nil, errors.New("Unable to create snapshot from provided javascript")
	}
	res := &V8Isolate{C.v8_create_isolate_with_snapshot(snapshot)}
	runtime.SetFinalizer(res, func(i *V8Isolate) {
		C.v8_release_isolate(i.v8isolate)
		C.v8_release_snapshot(snapshot)
	})
	return res, nil
}
func NewContext() *V8Context {
	return NewContextInIsolate(defaultIsolate)
}
func NewContextInIsolate(isolate *V8Isolate) *V8Context {
	v := &V8Context{
		v8context: C.v8_create_context(isolate.v8isolate),
		v8isolate: isolate,
		funcs:     make(map[string]Function),
		rawFuncs:  make(map[string]RawFunction),
		values:    make(map[*Value]bool),
		valuesMu:  &sync.Mutex{},
	}
	contextsMutex.Lock()
	highestContextId += 1
	v.id = highestContextId
	contexts[v.id] = v
	contextsMutex.Unlock()
	runtime.SetFinalizer(v, func(p *V8Context) {
		p.Destroy()
	})
	return v
}
func (v *V8Context) Destroy() error {
	if v.v8context == nil {
		return errors.New("Context is uninitialized.")
	}
	v.ClearValues()
	contextsMutex.Lock()
	delete(contexts, v.id)
	contextsMutex.Unlock()
	C.v8_release_context(v.v8context)
	v.v8context = nil
	v.v8isolate = nil
	return nil
}
func (v *V8Context) ClearValues() error {
	if v.v8context == nil {
		panic("Context is uninitialized.")
	}
	v.valuesMu.Lock()
	for val, _ := range v.values {
		v.releaseValueLocked(val)
	}
	v.valuesMu.Unlock()
	return nil
}
func (v *V8Context) ReleaseValue(val *Value) error {
	if v.v8context == nil {
		panic("Context is uninitialized.")
	}
	v.valuesMu.Lock()
	defer v.valuesMu.Unlock()
	if val.ptr == nil {
		return errors.New("Value has been already released.")
	}
	v.releaseValueLocked(val)
	return nil
}
func (v *V8Context) releaseValueLocked(val *Value) {
	val.ctx = nil
	delete(v.values, val)
	C.v8_release_persistent(v.v8context, val.ptr)
}
func (v *V8Context) newValue(ptr C.PersistentValuePtr) *Value {
	res := &Value{ptr, v}
	v.valuesMu.Lock()
	v.values[res] = true
	v.valuesMu.Unlock()
	return res
}
func (iso *V8Isolate) Terminate() {
	C.v8_terminate(iso.v8isolate)
}