-
-
Notifications
You must be signed in to change notification settings - Fork 216
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
v8.Value becomes manually releaseable #361
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -48,6 +48,44 @@ func TestFunctionTemplate_panic_on_nil_callback(t *testing.T) { | |
defer iso.Dispose() | ||
v8.NewFunctionTemplate(iso, nil) | ||
} | ||
func TestFunctionTemplate_generates_values(t *testing.T) { | ||
t.Parallel() | ||
|
||
iso := v8.NewIsolate() | ||
defer iso.Dispose() | ||
global := v8.NewObjectTemplate(iso) | ||
printfn := v8.NewFunctionTemplate(iso, func(info *v8.FunctionCallbackInfo) *v8.Value { | ||
fmt.Printf("%+v\n", info.Args()) | ||
return nil | ||
}) | ||
global.Set("print", printfn, v8.ReadOnly) | ||
ctx := v8.NewContext(iso, global) | ||
defer ctx.Close() | ||
ctx.RunScript("print('foo', 'bar', 0, 1)", "") | ||
if ctx.RetainedValueCount() != 5 { | ||
t.Errorf("expected 5 retained values, got: %d", ctx.RetainedValueCount()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is failing for me locally:
Can you repro? |
||
} | ||
} | ||
|
||
func TestFunctionTemplate_releases_values(t *testing.T) { | ||
t.Parallel() | ||
|
||
iso := v8.NewIsolate() | ||
defer iso.Dispose() | ||
global := v8.NewObjectTemplate(iso) | ||
printfn := v8.NewFunctionTemplate(iso, func(info *v8.FunctionCallbackInfo) *v8.Value { | ||
defer info.Release() | ||
fmt.Printf("%+v\n", info.Args()) | ||
return nil | ||
}) | ||
global.Set("print", printfn, v8.ReadOnly) | ||
ctx := v8.NewContext(iso, global) | ||
defer ctx.Close() | ||
ctx.RunScript("print('foo', 'bar', 0, 1)", "") | ||
if ctx.RetainedValueCount() != 0 { | ||
t.Errorf("expected 0 retained values, got: %d", ctx.RetainedValueCount()) | ||
} | ||
} | ||
|
||
func TestFunctionTemplateGetFunction(t *testing.T) { | ||
t.Parallel() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ | |
#include <sstream> | ||
#include <string> | ||
#include <vector> | ||
#include <unordered_map> | ||
|
||
#include "_cgo_export.h" | ||
|
||
|
@@ -26,12 +27,14 @@ const int ScriptCompilerEagerCompile = ScriptCompiler::kEagerCompile; | |
|
||
struct m_ctx { | ||
Isolate* iso; | ||
std::vector<m_value*> vals; | ||
std::unordered_map<long, m_value*> vals; | ||
std::vector<m_unboundScript*> unboundScripts; | ||
Persistent<Context> ptr; | ||
long nextValId; | ||
}; | ||
|
||
struct m_value { | ||
long id; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we need a constructor here to enforce that this member is initialized to zero (eg, |
||
Isolate* iso; | ||
m_ctx* ctx; | ||
Persistent<Value, CopyablePersistentTraits<Value>> ptr; | ||
|
@@ -119,7 +122,10 @@ m_value* tracked_value(m_ctx* ctx, m_value* val) { | |
// Go <--> C, which would be a significant change, as there are places where | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔕 This to-do can probably be revised. |
||
// we get the context from the value, but if we then need the context to get | ||
// the value, we would be in a circular bind. | ||
ctx->vals.push_back(val); | ||
if (val->id == 0) { | ||
val->id = ctx->nextValId++; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this right? The initial value will be 0, not 1. It felt wrong because the conditional would be true for the initial call and the second call but never any subsequent calls. I think this should be preincrement. vals is an unordered map now so I don't think we care about filling in from key 0. |
||
ctx->vals[val->id] = val; | ||
} | ||
|
||
return val; | ||
} | ||
|
@@ -600,16 +606,22 @@ ContextPtr NewContext(IsolatePtr iso, | |
return ctx; | ||
} | ||
|
||
int ContextRetainedValueCount(ContextPtr ctx) { | ||
return ctx->vals.size(); | ||
} | ||
|
||
void ContextFree(ContextPtr ctx) { | ||
if (ctx == nullptr) { | ||
return; | ||
} | ||
ctx->ptr.Reset(); | ||
|
||
for (m_value* val : ctx->vals) { | ||
val->ptr.Reset(); | ||
delete val; | ||
|
||
for(auto& [key, value] : ctx->vals) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm getting a warning here:
I think this is only a c++14 part of the project. for(auto it = ctx->vals.begin(); it != ctx->vals.end(); ++it) {
it->second->ptr.Reset();
delete it->second;
} |
||
value->ptr.Reset(); | ||
delete value; | ||
} | ||
ctx->vals.clear(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔕 I don't know about perf but I think it'd be clearer to call ValueRelease() (but be careful about modifying while looping). |
||
|
||
for (m_unboundScript* us : ctx->unboundScripts) { | ||
us->ptr.Reset(); | ||
|
@@ -761,6 +773,17 @@ const char* JSONStringify(ContextPtr ctx, ValuePtr val) { | |
return CopyString(json); | ||
} | ||
|
||
|
||
void ValueRelease(ValuePtr ptr) { | ||
if (ptr == nullptr) { | ||
return; | ||
} | ||
|
||
ptr->ctx->vals.erase(ptr->id); | ||
ptr->ptr.Reset(); | ||
delete ptr; | ||
} | ||
|
||
ValuePtr ContextGlobal(ContextPtr ctx) { | ||
LOCAL_CONTEXT(ctx); | ||
m_value* val = new m_value; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -166,6 +166,7 @@ extern void CPUProfileDelete(CPUProfile* ptr); | |
extern ContextPtr NewContext(IsolatePtr iso_ptr, | ||
TemplatePtr global_template_ptr, | ||
int ref); | ||
extern int ContextRetainedValueCount(ContextPtr ctx); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔕 Maybe ctx_ptr and val_ptr to match other APIs. |
||
extern void ContextFree(ContextPtr ptr); | ||
extern RtnValue RunScript(ContextPtr ctx_ptr, | ||
const char* source, | ||
|
@@ -207,6 +208,7 @@ extern RtnValue NewValueBigIntFromWords(IsolatePtr iso_ptr, | |
int sign_bit, | ||
int word_count, | ||
const uint64_t* words); | ||
void ValueRelease(ValuePtr ptr); | ||
extern RtnString ValueToString(ValuePtr ptr); | ||
const uint32_t* ValueToArrayIndex(ValuePtr ptr); | ||
int ValueToBoolean(ValuePtr ptr); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to keep the test output clean, please consider removing any unneeded print statements here. I know the test is trying to show a print implementation but we should probably check the value here, not print it out. Same thing below.