mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
Func: use class IntrusivePtr
This commit is contained in:
parent
b18573c804
commit
a0c831a1bd
15 changed files with 89 additions and 146 deletions
|
@ -234,7 +234,7 @@ static void parse_function_name(vector<ParseLocationRec>& result,
|
||||||
Stmt* body = 0; // the particular body we care about; 0 = all
|
Stmt* body = 0; // the particular body we care about; 0 = all
|
||||||
|
|
||||||
if ( bodies.size() == 1 )
|
if ( bodies.size() == 1 )
|
||||||
body = bodies[0].stmts;
|
body = bodies[0].stmts.get();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while ( 1 )
|
while ( 1 )
|
||||||
|
@ -245,7 +245,7 @@ static void parse_function_name(vector<ParseLocationRec>& result,
|
||||||
{
|
{
|
||||||
Stmt* first;
|
Stmt* first;
|
||||||
Location stmt_loc;
|
Location stmt_loc;
|
||||||
get_first_statement(bodies[i].stmts, first,
|
get_first_statement(bodies[i].stmts.get(), first,
|
||||||
stmt_loc);
|
stmt_loc);
|
||||||
debug_msg("[%d] %s:%d\n", i+1, stmt_loc.filename, stmt_loc.first_line);
|
debug_msg("[%d] %s:%d\n", i+1, stmt_loc.filename, stmt_loc.first_line);
|
||||||
}
|
}
|
||||||
|
@ -278,7 +278,7 @@ static void parse_function_name(vector<ParseLocationRec>& result,
|
||||||
int option = atoi(input.c_str());
|
int option = atoi(input.c_str());
|
||||||
if ( option > 0 && option <= (int) bodies.size() )
|
if ( option > 0 && option <= (int) bodies.size() )
|
||||||
{
|
{
|
||||||
body = bodies[option - 1].stmts;
|
body = bodies[option - 1].stmts.get();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -308,7 +308,7 @@ static void parse_function_name(vector<ParseLocationRec>& result,
|
||||||
|
|
||||||
for ( unsigned int i = 0; i < bodies.size(); ++i )
|
for ( unsigned int i = 0; i < bodies.size(); ++i )
|
||||||
{
|
{
|
||||||
get_first_statement(bodies[i].stmts, first, stmt_loc);
|
get_first_statement(bodies[i].stmts.get(), first, stmt_loc);
|
||||||
if ( ! first )
|
if ( ! first )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
@ -114,7 +114,7 @@ void EventHandler::Call(val_list* vl, bool no_remote)
|
||||||
|
|
||||||
if ( local )
|
if ( local )
|
||||||
// No try/catch here; we pass exceptions upstream.
|
// No try/catch here; we pass exceptions upstream.
|
||||||
Unref(local->Call(vl));
|
local->Call(vl);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for ( auto v : *vl )
|
for ( auto v : *vl )
|
||||||
|
|
|
@ -4241,7 +4241,7 @@ IntrusivePtr<Val> CallExpr::Eval(Frame* f) const
|
||||||
if ( f )
|
if ( f )
|
||||||
f->SetCall(this);
|
f->SetCall(this);
|
||||||
|
|
||||||
ret = {AdoptRef{}, func->Call(v, f)};
|
ret = func->Call(v, f);
|
||||||
|
|
||||||
if ( f )
|
if ( f )
|
||||||
f->SetCall(current_call);
|
f->SetCall(current_call);
|
||||||
|
@ -4307,9 +4307,8 @@ LambdaExpr::LambdaExpr(std::unique_ptr<function_ingredients> arg_ing,
|
||||||
|
|
||||||
// Install a dummy version of the function globally for use only
|
// Install a dummy version of the function globally for use only
|
||||||
// when broker provides a closure.
|
// when broker provides a closure.
|
||||||
::Ref(ingredients->body);
|
|
||||||
BroFunc* dummy_func = new BroFunc(
|
BroFunc* dummy_func = new BroFunc(
|
||||||
ingredients->id,
|
ingredients->id.get(),
|
||||||
ingredients->body,
|
ingredients->body,
|
||||||
ingredients->body && ingredients->inits && ingredients->inits->length() > 0 ? shallow_copy_id_list(*ingredients->inits).release() : nullptr,
|
ingredients->body && ingredients->inits && ingredients->inits->length() > 0 ? shallow_copy_id_list(*ingredients->inits).release() : nullptr,
|
||||||
ingredients->frame_size,
|
ingredients->frame_size,
|
||||||
|
@ -4355,9 +4354,8 @@ LambdaExpr::LambdaExpr(std::unique_ptr<function_ingredients> arg_ing,
|
||||||
|
|
||||||
IntrusivePtr<Val> LambdaExpr::Eval(Frame* f) const
|
IntrusivePtr<Val> LambdaExpr::Eval(Frame* f) const
|
||||||
{
|
{
|
||||||
::Ref(ingredients->body);
|
|
||||||
auto lamb = make_intrusive<BroFunc>(
|
auto lamb = make_intrusive<BroFunc>(
|
||||||
ingredients->id,
|
ingredients->id.get(),
|
||||||
ingredients->body,
|
ingredients->body,
|
||||||
ingredients->body && ingredients->inits && ingredients->inits->length() > 0 ? shallow_copy_id_list(*ingredients->inits).release() : nullptr,
|
ingredients->body && ingredients->inits && ingredients->inits->length() > 0 ? shallow_copy_id_list(*ingredients->inits).release() : nullptr,
|
||||||
ingredients->frame_size,
|
ingredients->frame_size,
|
||||||
|
|
104
src/Func.cc
104
src/Func.cc
|
@ -111,35 +111,36 @@ std::string render_call_stack()
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
Func::Func() : scope(0), type(0)
|
Func::Func()
|
||||||
{
|
{
|
||||||
unique_id = unique_ids.size();
|
unique_id = unique_ids.size();
|
||||||
unique_ids.push_back(this);
|
unique_ids.push_back(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Func::Func(Kind arg_kind) : scope(0), kind(arg_kind), type(0)
|
Func::Func(Kind arg_kind) : kind(arg_kind)
|
||||||
{
|
{
|
||||||
unique_id = unique_ids.size();
|
unique_id = unique_ids.size();
|
||||||
unique_ids.push_back(this);
|
unique_ids.push_back(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Func::~Func()
|
Func::~Func() = default;
|
||||||
{
|
|
||||||
Unref(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Func::AddBody(Stmt* /* new_body */, id_list* /* new_inits */,
|
void Func::AddBody(IntrusivePtr<Stmt> /* new_body */, id_list* /* new_inits */,
|
||||||
size_t /* new_frame_size */, int /* priority */)
|
size_t /* new_frame_size */, int /* priority */)
|
||||||
{
|
{
|
||||||
Internal("Func::AddBody called");
|
Internal("Func::AddBody called");
|
||||||
}
|
}
|
||||||
|
|
||||||
Func* Func::DoClone()
|
void Func::SetScope(IntrusivePtr<Scope> newscope)
|
||||||
|
{
|
||||||
|
scope = std::move(newscope);
|
||||||
|
}
|
||||||
|
|
||||||
|
IntrusivePtr<Func> Func::DoClone()
|
||||||
{
|
{
|
||||||
// By default, ok just to return a reference. Func does not have any state
|
// By default, ok just to return a reference. Func does not have any state
|
||||||
// that is different across instances.
|
// that is different across instances.
|
||||||
::Ref(this);
|
return {NewRef{}, this};
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Func::DescribeDebug(ODesc* d, const val_list* args) const
|
void Func::DescribeDebug(ODesc* d, const val_list* args) const
|
||||||
|
@ -180,7 +181,7 @@ TraversalCode Func::Traverse(TraversalCallback* cb) const
|
||||||
{
|
{
|
||||||
// FIXME: Make a fake scope for builtins?
|
// FIXME: Make a fake scope for builtins?
|
||||||
Scope* old_scope = cb->current_scope;
|
Scope* old_scope = cb->current_scope;
|
||||||
cb->current_scope = scope;
|
cb->current_scope = scope.get();
|
||||||
|
|
||||||
TraversalCode tc = cb->PreFunction(this);
|
TraversalCode tc = cb->PreFunction(this);
|
||||||
HANDLE_TC_STMT_PRE(tc);
|
HANDLE_TC_STMT_PRE(tc);
|
||||||
|
@ -206,13 +207,10 @@ TraversalCode Func::Traverse(TraversalCallback* cb) const
|
||||||
|
|
||||||
void Func::CopyStateInto(Func* other) const
|
void Func::CopyStateInto(Func* other) const
|
||||||
{
|
{
|
||||||
std::for_each(bodies.begin(), bodies.end(), [](const Body& b) { Ref(b.stmts); });
|
|
||||||
|
|
||||||
other->bodies = bodies;
|
other->bodies = bodies;
|
||||||
other->scope = scope;
|
other->scope = scope;
|
||||||
other->kind = kind;
|
other->kind = kind;
|
||||||
|
|
||||||
Ref(type);
|
|
||||||
other->type = type;
|
other->type = type;
|
||||||
|
|
||||||
other->name = name;
|
other->name = name;
|
||||||
|
@ -273,17 +271,17 @@ std::pair<bool, Val*> Func::HandlePluginResult(std::pair<bool, Val*> plugin_resu
|
||||||
return plugin_result;
|
return plugin_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
BroFunc::BroFunc(ID* arg_id, Stmt* arg_body, id_list* aggr_inits,
|
BroFunc::BroFunc(ID* arg_id, IntrusivePtr<Stmt> arg_body, id_list* aggr_inits,
|
||||||
size_t arg_frame_size, int priority) : Func(BRO_FUNC)
|
size_t arg_frame_size, int priority) : Func(BRO_FUNC)
|
||||||
{
|
{
|
||||||
name = arg_id->Name();
|
name = arg_id->Name();
|
||||||
type = arg_id->Type()->Ref();
|
type = {NewRef{}, arg_id->Type()};
|
||||||
frame_size = arg_frame_size;
|
frame_size = arg_frame_size;
|
||||||
|
|
||||||
if ( arg_body )
|
if ( arg_body )
|
||||||
{
|
{
|
||||||
Body b;
|
Body b;
|
||||||
b.stmts = AddInits(arg_body, aggr_inits);
|
b.stmts = AddInits(std::move(arg_body), aggr_inits);
|
||||||
b.priority = priority;
|
b.priority = priority;
|
||||||
bodies.push_back(b);
|
bodies.push_back(b);
|
||||||
}
|
}
|
||||||
|
@ -291,9 +289,6 @@ BroFunc::BroFunc(ID* arg_id, Stmt* arg_body, id_list* aggr_inits,
|
||||||
|
|
||||||
BroFunc::~BroFunc()
|
BroFunc::~BroFunc()
|
||||||
{
|
{
|
||||||
std::for_each(bodies.begin(), bodies.end(),
|
|
||||||
[](Body& b) { Unref(b.stmts); });
|
|
||||||
|
|
||||||
if ( ! weak_closure_ref )
|
if ( ! weak_closure_ref )
|
||||||
Unref(closure);
|
Unref(closure);
|
||||||
}
|
}
|
||||||
|
@ -304,7 +299,7 @@ int BroFunc::IsPure() const
|
||||||
[](const Body& b) { return b.stmts->IsPure(); });
|
[](const Body& b) { return b.stmts->IsPure(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
Val* BroFunc::Call(val_list* args, Frame* parent) const
|
IntrusivePtr<Val> BroFunc::Call(val_list* args, Frame* parent) const
|
||||||
{
|
{
|
||||||
#ifdef PROFILE_BRO_FUNCTIONS
|
#ifdef PROFILE_BRO_FUNCTIONS
|
||||||
DEBUG_MSG("Function: %s\n", Name());
|
DEBUG_MSG("Function: %s\n", Name());
|
||||||
|
@ -321,7 +316,7 @@ Val* BroFunc::Call(val_list* args, Frame* parent) const
|
||||||
if( plugin_result.first )
|
if( plugin_result.first )
|
||||||
{
|
{
|
||||||
Val *result = plugin_result.second;
|
Val *result = plugin_result.second;
|
||||||
return result;
|
return {AdoptRef{}, result};
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( bodies.empty() )
|
if ( bodies.empty() )
|
||||||
|
@ -331,10 +326,10 @@ Val* BroFunc::Call(val_list* args, Frame* parent) const
|
||||||
for ( const auto& arg : *args )
|
for ( const auto& arg : *args )
|
||||||
Unref(arg);
|
Unref(arg);
|
||||||
|
|
||||||
return Flavor() == FUNC_FLAVOR_HOOK ? val_mgr->GetTrue() : 0;
|
return Flavor() == FUNC_FLAVOR_HOOK ? IntrusivePtr{AdoptRef{}, val_mgr->GetTrue()} : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Frame* f = new Frame(frame_size, this, args);
|
auto f = make_intrusive<Frame>(frame_size, this, args);
|
||||||
|
|
||||||
if ( closure )
|
if ( closure )
|
||||||
f->CaptureClosure(closure, outer_ids);
|
f->CaptureClosure(closure, outer_ids);
|
||||||
|
@ -346,7 +341,7 @@ Val* BroFunc::Call(val_list* args, Frame* parent) const
|
||||||
f->SetCall(parent->GetCall());
|
f->SetCall(parent->GetCall());
|
||||||
}
|
}
|
||||||
|
|
||||||
g_frame_stack.push_back(f); // used for backtracing
|
g_frame_stack.push_back(f.get()); // used for backtracing
|
||||||
const CallExpr* call_expr = parent ? parent->GetCall() : nullptr;
|
const CallExpr* call_expr = parent ? parent->GetCall() : nullptr;
|
||||||
call_stack.emplace_back(CallInfo{call_expr, this, args});
|
call_stack.emplace_back(CallInfo{call_expr, this, args});
|
||||||
|
|
||||||
|
@ -360,7 +355,7 @@ Val* BroFunc::Call(val_list* args, Frame* parent) const
|
||||||
}
|
}
|
||||||
|
|
||||||
stmt_flow_type flow = FLOW_NEXT;
|
stmt_flow_type flow = FLOW_NEXT;
|
||||||
Val* result = 0;
|
IntrusivePtr<Val> result;
|
||||||
|
|
||||||
for ( const auto& body : bodies )
|
for ( const auto& body : bodies )
|
||||||
{
|
{
|
||||||
|
@ -368,8 +363,6 @@ Val* BroFunc::Call(val_list* args, Frame* parent) const
|
||||||
sample_logger->LocationSeen(
|
sample_logger->LocationSeen(
|
||||||
body.stmts->GetLocationInfo());
|
body.stmts->GetLocationInfo());
|
||||||
|
|
||||||
Unref(result);
|
|
||||||
|
|
||||||
// Fill in the rest of the frame with the function's arguments.
|
// Fill in the rest of the frame with the function's arguments.
|
||||||
loop_over_list(*args, j)
|
loop_over_list(*args, j)
|
||||||
{
|
{
|
||||||
|
@ -387,7 +380,7 @@ Val* BroFunc::Call(val_list* args, Frame* parent) const
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
result = body.stmts->Exec(f, flow).release();
|
result = body.stmts->Exec(f.get(), flow);
|
||||||
}
|
}
|
||||||
|
|
||||||
catch ( InterpreterException& e )
|
catch ( InterpreterException& e )
|
||||||
|
@ -397,7 +390,6 @@ Val* BroFunc::Call(val_list* args, Frame* parent) const
|
||||||
{
|
{
|
||||||
g_frame_stack.pop_back();
|
g_frame_stack.pop_back();
|
||||||
call_stack.pop_back();
|
call_stack.pop_back();
|
||||||
Unref(f);
|
|
||||||
// Result not set b/c exception was thrown
|
// Result not set b/c exception was thrown
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
@ -418,13 +410,12 @@ Val* BroFunc::Call(val_list* args, Frame* parent) const
|
||||||
{
|
{
|
||||||
// Ignore any return values of hook bodies, final return value
|
// Ignore any return values of hook bodies, final return value
|
||||||
// depends on whether a body returns as a result of break statement.
|
// depends on whether a body returns as a result of break statement.
|
||||||
Unref(result);
|
result = nullptr;
|
||||||
result = 0;
|
|
||||||
|
|
||||||
if ( flow == FLOW_BREAK )
|
if ( flow == FLOW_BREAK )
|
||||||
{
|
{
|
||||||
// Short-circuit execution of remaining hook handler bodies.
|
// Short-circuit execution of remaining hook handler bodies.
|
||||||
result = val_mgr->GetFalse();
|
result = {AdoptRef{}, val_mgr->GetFalse()};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -440,7 +431,7 @@ Val* BroFunc::Call(val_list* args, Frame* parent) const
|
||||||
if ( Flavor() == FUNC_FLAVOR_HOOK )
|
if ( Flavor() == FUNC_FLAVOR_HOOK )
|
||||||
{
|
{
|
||||||
if ( ! result )
|
if ( ! result )
|
||||||
result = val_mgr->GetTrue();
|
result = {AdoptRef{}, val_mgr->GetTrue()};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warn if the function returns something, but we returned from
|
// Warn if the function returns something, but we returned from
|
||||||
|
@ -462,25 +453,21 @@ Val* BroFunc::Call(val_list* args, Frame* parent) const
|
||||||
|
|
||||||
g_frame_stack.pop_back();
|
g_frame_stack.pop_back();
|
||||||
|
|
||||||
Unref(f);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BroFunc::AddBody(Stmt* new_body, id_list* new_inits,
|
void BroFunc::AddBody(IntrusivePtr<Stmt> new_body, id_list* new_inits,
|
||||||
size_t new_frame_size, int priority)
|
size_t new_frame_size, int priority)
|
||||||
{
|
{
|
||||||
if ( new_frame_size > frame_size )
|
if ( new_frame_size > frame_size )
|
||||||
frame_size = new_frame_size;
|
frame_size = new_frame_size;
|
||||||
|
|
||||||
new_body = AddInits(new_body, new_inits);
|
new_body = AddInits(std::move(new_body), new_inits);
|
||||||
|
|
||||||
if ( Flavor() == FUNC_FLAVOR_FUNCTION )
|
if ( Flavor() == FUNC_FLAVOR_FUNCTION )
|
||||||
{
|
{
|
||||||
// For functions, we replace the old body with the new one.
|
// For functions, we replace the old body with the new one.
|
||||||
assert(bodies.size() <= 1);
|
assert(bodies.size() <= 1);
|
||||||
for ( const auto& body : bodies )
|
|
||||||
Unref(body.stmts);
|
|
||||||
bodies.clear();
|
bodies.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -552,13 +539,13 @@ bool BroFunc::UpdateClosure(const broker::vector& data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Func* BroFunc::DoClone()
|
IntrusivePtr<Func> BroFunc::DoClone()
|
||||||
{
|
{
|
||||||
// BroFunc could hold a closure. In this case a clone of it must
|
// BroFunc could hold a closure. In this case a clone of it must
|
||||||
// store a copy of this closure.
|
// store a copy of this closure.
|
||||||
BroFunc* other = new BroFunc();
|
auto other = IntrusivePtr{AdoptRef{}, new BroFunc()};
|
||||||
|
|
||||||
CopyStateInto(other);
|
CopyStateInto(other.get());
|
||||||
|
|
||||||
other->frame_size = frame_size;
|
other->frame_size = frame_size;
|
||||||
other->closure = closure ? closure->SelectiveClone(outer_ids, this) : nullptr;
|
other->closure = closure ? closure->SelectiveClone(outer_ids, this) : nullptr;
|
||||||
|
@ -586,14 +573,14 @@ void BroFunc::Describe(ODesc* d) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Stmt* BroFunc::AddInits(Stmt* body, id_list* inits)
|
IntrusivePtr<Stmt> BroFunc::AddInits(IntrusivePtr<Stmt> body, id_list* inits)
|
||||||
{
|
{
|
||||||
if ( ! inits || inits->length() == 0 )
|
if ( ! inits || inits->length() == 0 )
|
||||||
return body;
|
return body;
|
||||||
|
|
||||||
StmtList* stmt_series = new StmtList;
|
auto stmt_series = make_intrusive<StmtList>();
|
||||||
stmt_series->Stmts().push_back(new InitStmt(inits));
|
stmt_series->Stmts().push_back(new InitStmt(inits));
|
||||||
stmt_series->Stmts().push_back(body);
|
stmt_series->Stmts().push_back(body.release());
|
||||||
|
|
||||||
return stmt_series;
|
return stmt_series;
|
||||||
}
|
}
|
||||||
|
@ -612,7 +599,7 @@ BuiltinFunc::BuiltinFunc(built_in_func arg_func, const char* arg_name,
|
||||||
if ( id->HasVal() )
|
if ( id->HasVal() )
|
||||||
reporter->InternalError("built-in function %s multiply defined", Name());
|
reporter->InternalError("built-in function %s multiply defined", Name());
|
||||||
|
|
||||||
type = id->Type()->Ref();
|
type = {NewRef{}, id->Type()};
|
||||||
id->SetVal(make_intrusive<Val>(this));
|
id->SetVal(make_intrusive<Val>(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -625,7 +612,7 @@ int BuiltinFunc::IsPure() const
|
||||||
return is_pure;
|
return is_pure;
|
||||||
}
|
}
|
||||||
|
|
||||||
Val* BuiltinFunc::Call(val_list* args, Frame* parent) const
|
IntrusivePtr<Val> BuiltinFunc::Call(val_list* args, Frame* parent) const
|
||||||
{
|
{
|
||||||
#ifdef PROFILE_BRO_FUNCTIONS
|
#ifdef PROFILE_BRO_FUNCTIONS
|
||||||
DEBUG_MSG("Function: %s\n", Name());
|
DEBUG_MSG("Function: %s\n", Name());
|
||||||
|
@ -642,7 +629,7 @@ Val* BuiltinFunc::Call(val_list* args, Frame* parent) const
|
||||||
if ( plugin_result.first )
|
if ( plugin_result.first )
|
||||||
{
|
{
|
||||||
Val *result = plugin_result.second;
|
Val *result = plugin_result.second;
|
||||||
return result;
|
return {AdoptRef{}, result};
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( g_trace_state.DoTrace() )
|
if ( g_trace_state.DoTrace() )
|
||||||
|
@ -655,7 +642,7 @@ Val* BuiltinFunc::Call(val_list* args, Frame* parent) const
|
||||||
|
|
||||||
const CallExpr* call_expr = parent ? parent->GetCall() : nullptr;
|
const CallExpr* call_expr = parent ? parent->GetCall() : nullptr;
|
||||||
call_stack.emplace_back(CallInfo{call_expr, this, args});
|
call_stack.emplace_back(CallInfo{call_expr, this, args});
|
||||||
Val* result = func(parent, args);
|
IntrusivePtr<Val> result{AdoptRef{}, func(parent, args)};
|
||||||
call_stack.pop_back();
|
call_stack.pop_back();
|
||||||
|
|
||||||
for ( const auto& arg : *args )
|
for ( const auto& arg : *args )
|
||||||
|
@ -885,29 +872,22 @@ static int get_func_priority(const attr_list& attrs)
|
||||||
return priority;
|
return priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
function_ingredients::function_ingredients(Scope* scope, Stmt* body)
|
function_ingredients::function_ingredients(IntrusivePtr<Scope> scope, IntrusivePtr<Stmt> body)
|
||||||
{
|
{
|
||||||
frame_size = scope->Length();
|
frame_size = scope->Length();
|
||||||
inits = scope->GetInits();
|
inits = scope->GetInits();
|
||||||
|
|
||||||
this->scope = scope;
|
this->scope = std::move(scope);
|
||||||
::Ref(this->scope);
|
id = {NewRef{}, this->scope->ScopeID()};
|
||||||
id = scope->ScopeID();
|
|
||||||
::Ref(id);
|
|
||||||
|
|
||||||
auto attrs = scope->Attrs();
|
auto attrs = this->scope->Attrs();
|
||||||
|
|
||||||
priority = (attrs ? get_func_priority(*attrs) : 0);
|
priority = (attrs ? get_func_priority(*attrs) : 0);
|
||||||
this->body = body;
|
this->body = std::move(body);
|
||||||
::Ref(this->body);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function_ingredients::~function_ingredients()
|
function_ingredients::~function_ingredients()
|
||||||
{
|
{
|
||||||
Unref(id);
|
|
||||||
Unref(body);
|
|
||||||
Unref(scope);
|
|
||||||
|
|
||||||
for ( const auto& i : *inits )
|
for ( const auto& i : *inits )
|
||||||
Unref(i);
|
Unref(i);
|
||||||
|
|
||||||
|
|
37
src/Func.h
37
src/Func.h
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include "BroList.h"
|
#include "BroList.h"
|
||||||
#include "Obj.h"
|
#include "Obj.h"
|
||||||
|
#include "IntrusivePtr.h"
|
||||||
#include "Type.h" /* for function_flavor */
|
#include "Type.h" /* for function_flavor */
|
||||||
#include "TraverseTypes.h"
|
#include "TraverseTypes.h"
|
||||||
|
|
||||||
|
@ -40,7 +41,7 @@ public:
|
||||||
function_flavor Flavor() const { return FType()->Flavor(); }
|
function_flavor Flavor() const { return FType()->Flavor(); }
|
||||||
|
|
||||||
struct Body {
|
struct Body {
|
||||||
Stmt* stmts;
|
IntrusivePtr<Stmt> stmts;
|
||||||
int priority;
|
int priority;
|
||||||
bool operator<(const Body& other) const
|
bool operator<(const Body& other) const
|
||||||
{ return priority > other.priority; } // reverse sort
|
{ return priority > other.priority; } // reverse sort
|
||||||
|
@ -50,14 +51,14 @@ public:
|
||||||
bool HasBodies() const { return bodies.size(); }
|
bool HasBodies() const { return bodies.size(); }
|
||||||
|
|
||||||
// virtual Val* Call(ListExpr* args) const = 0;
|
// virtual Val* Call(ListExpr* args) const = 0;
|
||||||
virtual Val* Call(val_list* args, Frame* parent = 0) const = 0;
|
virtual IntrusivePtr<Val> Call(val_list* args, Frame* parent = 0) const = 0;
|
||||||
|
|
||||||
// Add a new event handler to an existing function (event).
|
// Add a new event handler to an existing function (event).
|
||||||
virtual void AddBody(Stmt* new_body, id_list* new_inits,
|
virtual void AddBody(IntrusivePtr<Stmt> new_body, id_list* new_inits,
|
||||||
size_t new_frame_size, int priority = 0);
|
size_t new_frame_size, int priority = 0);
|
||||||
|
|
||||||
virtual void SetScope(Scope* newscope) { scope = newscope; }
|
virtual void SetScope(IntrusivePtr<Scope> newscope);
|
||||||
virtual Scope* GetScope() const { return scope; }
|
virtual Scope* GetScope() const { return scope.get(); }
|
||||||
|
|
||||||
virtual FuncType* FType() const { return type->AsFuncType(); }
|
virtual FuncType* FType() const { return type->AsFuncType(); }
|
||||||
|
|
||||||
|
@ -69,7 +70,7 @@ public:
|
||||||
void Describe(ODesc* d) const override = 0;
|
void Describe(ODesc* d) const override = 0;
|
||||||
virtual void DescribeDebug(ODesc* d, const val_list* args) const;
|
virtual void DescribeDebug(ODesc* d, const val_list* args) const;
|
||||||
|
|
||||||
virtual Func* DoClone();
|
virtual IntrusivePtr<Func> DoClone();
|
||||||
|
|
||||||
virtual TraversalCode Traverse(TraversalCallback* cb) const;
|
virtual TraversalCode Traverse(TraversalCallback* cb) const;
|
||||||
|
|
||||||
|
@ -87,9 +88,9 @@ protected:
|
||||||
std::pair<bool, Val*> HandlePluginResult(std::pair<bool, Val*> plugin_result, val_list* args, function_flavor flavor) const;
|
std::pair<bool, Val*> HandlePluginResult(std::pair<bool, Val*> plugin_result, val_list* args, function_flavor flavor) const;
|
||||||
|
|
||||||
vector<Body> bodies;
|
vector<Body> bodies;
|
||||||
Scope* scope;
|
IntrusivePtr<Scope> scope;
|
||||||
Kind kind;
|
Kind kind;
|
||||||
BroType* type;
|
IntrusivePtr<BroType> type;
|
||||||
string name;
|
string name;
|
||||||
uint32_t unique_id;
|
uint32_t unique_id;
|
||||||
static vector<Func*> unique_ids;
|
static vector<Func*> unique_ids;
|
||||||
|
@ -98,11 +99,11 @@ protected:
|
||||||
|
|
||||||
class BroFunc : public Func {
|
class BroFunc : public Func {
|
||||||
public:
|
public:
|
||||||
BroFunc(ID* id, Stmt* body, id_list* inits, size_t frame_size, int priority);
|
BroFunc(ID* id, IntrusivePtr<Stmt> body, id_list* inits, size_t frame_size, int priority);
|
||||||
~BroFunc() override;
|
~BroFunc() override;
|
||||||
|
|
||||||
int IsPure() const override;
|
int IsPure() const override;
|
||||||
Val* Call(val_list* args, Frame* parent) const override;
|
IntrusivePtr<Val> Call(val_list* args, Frame* parent) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds adds a closure to the function. Closures are cloned and
|
* Adds adds a closure to the function. Closures are cloned and
|
||||||
|
@ -133,7 +134,7 @@ public:
|
||||||
*/
|
*/
|
||||||
broker::expected<broker::data> SerializeClosure() const;
|
broker::expected<broker::data> SerializeClosure() const;
|
||||||
|
|
||||||
void AddBody(Stmt* new_body, id_list* new_inits,
|
void AddBody(IntrusivePtr<Stmt> new_body, id_list* new_inits,
|
||||||
size_t new_frame_size, int priority) override;
|
size_t new_frame_size, int priority) override;
|
||||||
|
|
||||||
/** Sets this function's outer_id list. */
|
/** Sets this function's outer_id list. */
|
||||||
|
@ -144,12 +145,12 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
BroFunc() : Func(BRO_FUNC) {}
|
BroFunc() : Func(BRO_FUNC) {}
|
||||||
Stmt* AddInits(Stmt* body, id_list* inits);
|
IntrusivePtr<Stmt> AddInits(IntrusivePtr<Stmt> body, id_list* inits);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clones this function along with its closures.
|
* Clones this function along with its closures.
|
||||||
*/
|
*/
|
||||||
Func* DoClone() override;
|
IntrusivePtr<Func> DoClone() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs a selective clone of *f* using the IDs that were
|
* Performs a selective clone of *f* using the IDs that were
|
||||||
|
@ -177,7 +178,7 @@ public:
|
||||||
~BuiltinFunc() override;
|
~BuiltinFunc() override;
|
||||||
|
|
||||||
int IsPure() const override;
|
int IsPure() const override;
|
||||||
Val* Call(val_list* args, Frame* parent) const override;
|
IntrusivePtr<Val> Call(val_list* args, Frame* parent) const override;
|
||||||
built_in_func TheFunc() const { return func; }
|
built_in_func TheFunc() const { return func; }
|
||||||
|
|
||||||
void Describe(ODesc* d) const override;
|
void Describe(ODesc* d) const override;
|
||||||
|
@ -208,16 +209,16 @@ struct function_ingredients {
|
||||||
|
|
||||||
// Gathers all of the information from a scope and a function body needed
|
// Gathers all of the information from a scope and a function body needed
|
||||||
// to build a function.
|
// to build a function.
|
||||||
function_ingredients(Scope* scope, Stmt* body);
|
function_ingredients(IntrusivePtr<Scope> scope, IntrusivePtr<Stmt> body);
|
||||||
|
|
||||||
~function_ingredients();
|
~function_ingredients();
|
||||||
|
|
||||||
ID* id;
|
IntrusivePtr<ID> id;
|
||||||
Stmt* body;
|
IntrusivePtr<Stmt> body;
|
||||||
id_list* inits;
|
id_list* inits;
|
||||||
int frame_size;
|
int frame_size;
|
||||||
int priority;
|
int priority;
|
||||||
Scope* scope;
|
IntrusivePtr<Scope> scope;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern vector<CallInfo> call_stack;
|
extern vector<CallInfo> call_stack;
|
||||||
|
|
|
@ -179,15 +179,9 @@ bool RuleConditionEval::DoMatch(Rule* rule, RuleEndpointState* state,
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Val* val = id->ID_Val()->AsFunc()->Call(&args);
|
auto val = id->ID_Val()->AsFunc()->Call(&args);
|
||||||
|
|
||||||
if ( val )
|
result = val && val->AsBool();
|
||||||
{
|
|
||||||
result = val->AsBool();
|
|
||||||
Unref(val);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
result = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
catch ( InterpreterException& e )
|
catch ( InterpreterException& e )
|
||||||
|
|
16
src/Val.cc
16
src/Val.cc
|
@ -111,12 +111,7 @@ Val* Val::DoClone(CloneState* state)
|
||||||
// Derived classes are responsible for this. Exception:
|
// Derived classes are responsible for this. Exception:
|
||||||
// Functions and files. There aren't any derived classes.
|
// Functions and files. There aren't any derived classes.
|
||||||
if ( type->Tag() == TYPE_FUNC )
|
if ( type->Tag() == TYPE_FUNC )
|
||||||
{
|
return new Val(AsFunc()->DoClone().get());
|
||||||
auto c = AsFunc()->DoClone();
|
|
||||||
auto rval = new Val(c);
|
|
||||||
Unref(c);
|
|
||||||
return rval;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( type->Tag() == TYPE_FILE )
|
if ( type->Tag() == TYPE_FILE )
|
||||||
{
|
{
|
||||||
|
@ -1793,7 +1788,7 @@ Val* TableVal::Default(Val* index)
|
||||||
vl = val_list{index->Ref()};
|
vl = val_list{index->Ref()};
|
||||||
}
|
}
|
||||||
|
|
||||||
Val* result = 0;
|
IntrusivePtr<Val> result;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -1809,7 +1804,7 @@ Val* TableVal::Default(Val* index)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
Val* TableVal::Lookup(Val* index, bool use_default_val)
|
Val* TableVal::Lookup(Val* index, bool use_default_val)
|
||||||
|
@ -2456,14 +2451,11 @@ double TableVal::CallExpireFunc(Val* idx)
|
||||||
else
|
else
|
||||||
vl.append(idx);
|
vl.append(idx);
|
||||||
|
|
||||||
Val* result = 0;
|
auto result = f->Call(&vl);
|
||||||
|
|
||||||
result = f->Call(&vl);
|
|
||||||
|
|
||||||
if ( result )
|
if ( result )
|
||||||
{
|
{
|
||||||
secs = result->AsInterval();
|
secs = result->AsInterval();
|
||||||
Unref(result);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -473,12 +473,11 @@ TraversalCode OuterIDBindingFinder::PostExpr(const Expr* expr)
|
||||||
|
|
||||||
void end_func(IntrusivePtr<Stmt> body)
|
void end_func(IntrusivePtr<Stmt> body)
|
||||||
{
|
{
|
||||||
auto ingredients = std::make_unique<function_ingredients>(
|
auto ingredients = std::make_unique<function_ingredients>(pop_scope(), std::move(body));
|
||||||
pop_scope().release(), body.release());
|
|
||||||
|
|
||||||
if ( streq(ingredients->id->Name(), "anonymous-function") )
|
if ( streq(ingredients->id->Name(), "anonymous-function") )
|
||||||
{
|
{
|
||||||
OuterIDBindingFinder cb(ingredients->scope);
|
OuterIDBindingFinder cb(ingredients->scope.get());
|
||||||
ingredients->body->Traverse(&cb);
|
ingredients->body->Traverse(&cb);
|
||||||
|
|
||||||
for ( size_t i = 0; i < cb.outer_id_references.size(); ++i )
|
for ( size_t i = 0; i < cb.outer_id_references.size(); ++i )
|
||||||
|
@ -495,7 +494,7 @@ void end_func(IntrusivePtr<Stmt> body)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Func* f = new BroFunc(
|
Func* f = new BroFunc(
|
||||||
ingredients->id,
|
ingredients->id.get(),
|
||||||
ingredients->body,
|
ingredients->body,
|
||||||
ingredients->inits,
|
ingredients->inits,
|
||||||
ingredients->frame_size,
|
ingredients->frame_size,
|
||||||
|
|
|
@ -550,7 +550,7 @@ bool Manager::PublishLogWrite(EnumVal* stream, EnumVal* writer, string path, int
|
||||||
new StringVal(path),
|
new StringVal(path),
|
||||||
};
|
};
|
||||||
|
|
||||||
Val* v = log_topic_func->Call(&vl);
|
auto v = log_topic_func->Call(&vl);
|
||||||
|
|
||||||
if ( ! v )
|
if ( ! v )
|
||||||
{
|
{
|
||||||
|
@ -561,7 +561,6 @@ bool Manager::PublishLogWrite(EnumVal* stream, EnumVal* writer, string path, int
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string topic = v->AsString()->CheckString();
|
std::string topic = v->AsString()->CheckString();
|
||||||
Unref(v);
|
|
||||||
|
|
||||||
auto bstream_id = broker::enum_value(move(stream_id));
|
auto bstream_id = broker::enum_value(move(stream_id));
|
||||||
auto bwriter_id = broker::enum_value(move(writer_id));
|
auto bwriter_id = broker::enum_value(move(writer_id));
|
||||||
|
|
|
@ -188,7 +188,6 @@ function Cluster::publish_rr%(pool: Pool, key: string, ...%): bool
|
||||||
|
|
||||||
if ( ! topic->AsString()->Len() )
|
if ( ! topic->AsString()->Len() )
|
||||||
{
|
{
|
||||||
Unref(topic);
|
|
||||||
return val_mgr->GetFalse();
|
return val_mgr->GetFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,7 +198,6 @@ function Cluster::publish_rr%(pool: Pool, key: string, ...%): bool
|
||||||
args.push_back((*bif_args)[i]);
|
args.push_back((*bif_args)[i]);
|
||||||
|
|
||||||
auto rval = publish_event_args(args, topic->AsString(), frame);
|
auto rval = publish_event_args(args, topic->AsString(), frame);
|
||||||
Unref(topic);
|
|
||||||
return val_mgr->GetBool(rval);
|
return val_mgr->GetBool(rval);
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
@ -228,10 +226,7 @@ function Cluster::publish_hrw%(pool: Pool, key: any, ...%): bool
|
||||||
auto topic = topic_func->Call(&vl);
|
auto topic = topic_func->Call(&vl);
|
||||||
|
|
||||||
if ( ! topic->AsString()->Len() )
|
if ( ! topic->AsString()->Len() )
|
||||||
{
|
|
||||||
Unref(topic);
|
|
||||||
return val_mgr->GetFalse();
|
return val_mgr->GetFalse();
|
||||||
}
|
|
||||||
|
|
||||||
val_list* bif_args = @ARGS@;
|
val_list* bif_args = @ARGS@;
|
||||||
val_list args(bif_args->length() - 2);
|
val_list args(bif_args->length() - 2);
|
||||||
|
@ -240,6 +235,5 @@ function Cluster::publish_hrw%(pool: Pool, key: any, ...%): bool
|
||||||
args.push_back((*bif_args)[i]);
|
args.push_back((*bif_args)[i]);
|
||||||
|
|
||||||
auto rval = publish_event_args(args, topic->AsString(), frame);
|
auto rval = publish_event_args(args, topic->AsString(), frame);
|
||||||
Unref(topic);
|
|
||||||
return val_mgr->GetBool(rval);
|
return val_mgr->GetBool(rval);
|
||||||
%}
|
%}
|
||||||
|
|
|
@ -1844,12 +1844,9 @@ bool Manager::CallPred(Func* pred_func, const int numvals, ...) const
|
||||||
|
|
||||||
va_end(lP);
|
va_end(lP);
|
||||||
|
|
||||||
Val* v = pred_func->Call(&vl);
|
auto v = pred_func->Call(&vl);
|
||||||
if ( v )
|
if ( v )
|
||||||
{
|
|
||||||
result = v->AsBool();
|
result = v->AsBool();
|
||||||
Unref(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -739,12 +739,9 @@ bool Manager::Write(EnumVal* id, RecordVal* columns)
|
||||||
|
|
||||||
int result = 1;
|
int result = 1;
|
||||||
|
|
||||||
Val* v = filter->pred->Call(&vl);
|
auto v = filter->pred->Call(&vl);
|
||||||
if ( v )
|
if ( v )
|
||||||
{
|
|
||||||
result = v->AsBool();
|
result = v->AsBool();
|
||||||
Unref(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! result )
|
if ( ! result )
|
||||||
continue;
|
continue;
|
||||||
|
@ -773,9 +770,7 @@ bool Manager::Write(EnumVal* id, RecordVal* columns)
|
||||||
rec_arg,
|
rec_arg,
|
||||||
};
|
};
|
||||||
|
|
||||||
Val* v = 0;
|
auto v = filter->path_func->Call(&vl);
|
||||||
|
|
||||||
v = filter->path_func->Call(&vl);
|
|
||||||
|
|
||||||
if ( ! v )
|
if ( ! v )
|
||||||
return false;
|
return false;
|
||||||
|
@ -783,7 +778,6 @@ bool Manager::Write(EnumVal* id, RecordVal* columns)
|
||||||
if ( v->Type()->Tag() != TYPE_STRING )
|
if ( v->Type()->Tag() != TYPE_STRING )
|
||||||
{
|
{
|
||||||
reporter->Error("path_func did not return string");
|
reporter->Error("path_func did not return string");
|
||||||
Unref(v);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -794,7 +788,6 @@ bool Manager::Write(EnumVal* id, RecordVal* columns)
|
||||||
}
|
}
|
||||||
|
|
||||||
path = v->AsString()->CheckString();
|
path = v->AsString()->CheckString();
|
||||||
Unref(v);
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
DBG_LOG(DBG_LOGGING, "Path function for filter '%s' on stream '%s' return '%s'",
|
DBG_LOG(DBG_LOGGING, "Path function for filter '%s' on stream '%s' return '%s'",
|
||||||
|
@ -1090,9 +1083,9 @@ threading::Value** Manager::RecordToFilterVals(Stream* stream, Filter* filter,
|
||||||
if ( filter->num_ext_fields > 0 )
|
if ( filter->num_ext_fields > 0 )
|
||||||
{
|
{
|
||||||
val_list vl{filter->path_val->Ref()};
|
val_list vl{filter->path_val->Ref()};
|
||||||
Val* res = filter->ext_func->Call(&vl);
|
auto res = filter->ext_func->Call(&vl);
|
||||||
if ( res )
|
if ( res )
|
||||||
ext_rec = res->AsRecordVal();
|
ext_rec = res.release()->AsRecordVal();
|
||||||
}
|
}
|
||||||
|
|
||||||
threading::Value** vals = new threading::Value*[filter->num_fields];
|
threading::Value** vals = new threading::Value*[filter->num_fields];
|
||||||
|
@ -1572,12 +1565,9 @@ bool Manager::FinishedRotation(WriterFrontend* writer, const char* new_name, con
|
||||||
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
Val* v = func->Call(&vl);
|
auto v = func->Call(&vl);
|
||||||
if ( v )
|
if ( v )
|
||||||
{
|
|
||||||
result = v->AsBool();
|
result = v->AsBool();
|
||||||
Unref(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ static bool call_option_handlers_and_set_value(StringVal* name, ID* i, Val* val,
|
||||||
if ( add_loc )
|
if ( add_loc )
|
||||||
vl.push_back(location->Ref());
|
vl.push_back(location->Ref());
|
||||||
|
|
||||||
val = handler_function->Call(&vl); // consumed by next call.
|
val = handler_function->Call(&vl).release(); // consumed by next call.
|
||||||
if ( ! val )
|
if ( ! val )
|
||||||
{
|
{
|
||||||
// Someone messed up, don't change value and just return
|
// Someone messed up, don't change value and just return
|
||||||
|
|
|
@ -1261,8 +1261,8 @@ anonymous_function:
|
||||||
// a lambda expression.
|
// a lambda expression.
|
||||||
|
|
||||||
// Gather the ingredients for a BroFunc from the current scope
|
// Gather the ingredients for a BroFunc from the current scope
|
||||||
auto ingredients = std::make_unique<function_ingredients>(current_scope(), $5);
|
auto ingredients = std::make_unique<function_ingredients>(IntrusivePtr{NewRef{}, current_scope()}, IntrusivePtr{AdoptRef{}, $5});
|
||||||
id_list outer_ids = gather_outer_ids(pop_scope().get(), $5);
|
id_list outer_ids = gather_outer_ids(pop_scope().get(), ingredients->body.get());
|
||||||
|
|
||||||
$$ = new LambdaExpr(std::move(ingredients), std::move(outer_ids));
|
$$ = new LambdaExpr(std::move(ingredients), std::move(outer_ids));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1339,9 +1339,8 @@ bool sort_function(Val* a, Val* b)
|
||||||
sort_func_args.push_back(a->Ref());
|
sort_func_args.push_back(a->Ref());
|
||||||
sort_func_args.push_back(b->Ref());
|
sort_func_args.push_back(b->Ref());
|
||||||
|
|
||||||
Val* result = sort_function_comp->Call(&sort_func_args);
|
auto result = sort_function_comp->Call(&sort_func_args);
|
||||||
int int_result = result->CoerceToInt();
|
int int_result = result->CoerceToInt();
|
||||||
Unref(result);
|
|
||||||
|
|
||||||
return int_result < 0;
|
return int_result < 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue