mirror of
https://github.com/autc04/Retro68.git
synced 2024-06-01 15:41:39 +00:00
1282 lines
30 KiB
C++
1282 lines
30 KiB
C++
/* Copyright (C) 2021 Free Software Foundation, Inc.
|
|
Contributed by Oracle.
|
|
|
|
This file is part of GNU Binutils.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, 51 Franklin Street - Fifth Floor, Boston,
|
|
MA 02110-1301, USA. */
|
|
|
|
#include "config.h"
|
|
#include <assert.h>
|
|
#include "CallStack.h"
|
|
#include "DbeSession.h"
|
|
#include "DbeView.h"
|
|
#include "DataObject.h"
|
|
#include "Exp_Layout.h"
|
|
#include "Experiment.h"
|
|
#include "Module.h"
|
|
#include "LoadObject.h"
|
|
#include "Expression.h"
|
|
#include "Function.h"
|
|
#include "Histable.h"
|
|
#include "Sample.h"
|
|
#include "Table.h"
|
|
|
|
//////////////////////////////////////////////////////////
|
|
// class Expression::Context
|
|
|
|
static const uint64_t INDXOBJ_EXPGRID_SHIFT = 60;
|
|
static const uint64_t INDXOBJ_EXPID_SHIFT = 32;
|
|
|
|
Expression::Context::Context (DbeView *_dbev, Experiment *_exp)
|
|
{
|
|
dbev = _dbev;
|
|
exp = _exp;
|
|
dview = NULL;
|
|
eventId = 0;
|
|
}
|
|
|
|
Expression::Context::Context (DbeView *_dbev, Experiment *_exp,
|
|
DataView *_dview, long _eventId)
|
|
{
|
|
dbev = _dbev;
|
|
exp = _exp;
|
|
dview = _dview;
|
|
eventId = _eventId;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////
|
|
// class Expression
|
|
Expression::Expression (OpCode _op, uint64_t _v)
|
|
{
|
|
op = _op;
|
|
v = Value (_v);
|
|
arg0 = NULL;
|
|
arg1 = NULL;
|
|
}
|
|
|
|
Expression::Expression (OpCode _op, const Expression *_arg0,
|
|
const Expression *_arg1)
|
|
{
|
|
op = _op;
|
|
v = Value ();
|
|
arg0 = NULL;
|
|
arg1 = NULL;
|
|
if (_arg0)
|
|
arg0 = _arg0->copy ();
|
|
if (_arg1)
|
|
arg1 = _arg1->copy ();
|
|
}
|
|
|
|
Expression::~Expression ()
|
|
{
|
|
delete arg0;
|
|
delete arg1;
|
|
}
|
|
|
|
Expression::Expression (const Expression &rhs)
|
|
{
|
|
op = rhs.op;
|
|
arg0 = NULL;
|
|
arg1 = NULL;
|
|
v = Value (rhs.v);
|
|
if (rhs.arg0)
|
|
{
|
|
arg0 = rhs.arg0->copy ();
|
|
if (v.next)
|
|
{
|
|
assert (arg0 && v.next == &(rhs.arg0->v));
|
|
v.next = &(arg0->v);
|
|
}
|
|
}
|
|
if (rhs.arg1)
|
|
arg1 = rhs.arg1->copy ();
|
|
}
|
|
|
|
Expression::Expression (const Expression *rhs)
|
|
{
|
|
arg0 = NULL;
|
|
arg1 = NULL;
|
|
copy (rhs);
|
|
}
|
|
|
|
void
|
|
Expression::copy (const Expression *rhs)
|
|
{
|
|
op = rhs->op;
|
|
delete arg0;
|
|
delete arg1;
|
|
arg0 = NULL;
|
|
arg1 = NULL;
|
|
v = Value (rhs->v);
|
|
if (rhs->arg0)
|
|
{
|
|
arg0 = rhs->arg0->copy ();
|
|
if (v.next)
|
|
{
|
|
assert (arg0 && v.next == &(rhs->arg0->v));
|
|
v.next = &(arg0->v);
|
|
}
|
|
}
|
|
if (rhs->arg1)
|
|
arg1 = rhs->arg1->copy ();
|
|
}
|
|
|
|
Expression &
|
|
Expression::operator= (const Expression &rhs)
|
|
{
|
|
if (this == &rhs)
|
|
return *this;
|
|
copy (&rhs);
|
|
return *this;
|
|
}
|
|
|
|
bool
|
|
Expression::getVal (int propId, Context *ctx)
|
|
{
|
|
v.val = 0;
|
|
v.next = NULL;
|
|
int origPropId = propId;
|
|
switch (propId)
|
|
{
|
|
default:
|
|
{
|
|
if (!ctx->dview)
|
|
return false;
|
|
PropDescr *propDscr = ctx->dview->getProp (propId);
|
|
if (!propDscr)
|
|
return false;
|
|
switch (propDscr->vtype)
|
|
{
|
|
case TYPE_INT32:
|
|
v.val = ctx->dview->getIntValue (propId, ctx->eventId);
|
|
break;
|
|
case TYPE_UINT32:
|
|
v.val = (uint32_t) ctx->dview->getIntValue (propId, ctx->eventId); //prevent sign extension
|
|
break;
|
|
case TYPE_INT64:
|
|
case TYPE_UINT64:
|
|
v.val = ctx->dview->getLongValue (propId, ctx->eventId);
|
|
break;
|
|
case TYPE_OBJ:
|
|
// YM: not sure if we should allow this
|
|
v.val = (long long) ctx->dview->getObjValue (propId, ctx->eventId);
|
|
break;
|
|
case TYPE_STRING:
|
|
case TYPE_DOUBLE:
|
|
default:
|
|
return false; // Weird, programming error?
|
|
}
|
|
break;
|
|
}
|
|
case PROP_FREQ_MHZ:
|
|
if (ctx->exp && ctx->exp->clock)
|
|
v.val = ctx->exp->clock;
|
|
else
|
|
return false;
|
|
break;
|
|
case PROP_PID:
|
|
if (ctx->exp == NULL)
|
|
return false;
|
|
v.val = ctx->exp->getPID ();
|
|
break;
|
|
case PROP_EXPID:
|
|
if (ctx->exp == NULL)
|
|
return false;
|
|
v.val = ctx->exp->getUserExpId ();
|
|
break;
|
|
case PROP_EXPID_CMP:
|
|
if (ctx->exp == NULL)
|
|
return false;
|
|
else
|
|
{
|
|
Experiment *exp = ctx->exp;
|
|
if (ctx->dbev && ctx->dbev->comparingExperiments ())
|
|
exp = (Experiment *) exp->get_compare_obj ();
|
|
v.val = exp->getUserExpId ();
|
|
}
|
|
break;
|
|
case PROP_EXPGRID:
|
|
if (ctx->exp == NULL)
|
|
return false;
|
|
v.val = ctx->exp->groupId;
|
|
break;
|
|
case PROP_NTICK_USEC:
|
|
if (ctx->exp == NULL)
|
|
return false;
|
|
if (ctx->dview && ctx->dview->getProp (PROP_NTICK))
|
|
v.val = ctx->dview->getIntValue (PROP_NTICK, ctx->eventId)
|
|
* ctx->exp->get_params ()->ptimer_usec;
|
|
else
|
|
return false;
|
|
break;
|
|
case PROP_ATSTAMP:
|
|
case PROP_ETSTAMP:
|
|
if (ctx->exp == NULL)
|
|
return false;
|
|
if (ctx->dview && ctx->dview->getProp (PROP_TSTAMP))
|
|
v.val = ctx->dview->getLongValue (PROP_TSTAMP, ctx->eventId);
|
|
else
|
|
return false;
|
|
if (propId == PROP_ATSTAMP)
|
|
break; // absolute time, no adjustments
|
|
// propId==PROP_ETSTAMP
|
|
// calculate relative time from start of this experiment
|
|
v.val -= ctx->exp->getStartTime ();
|
|
break;
|
|
case PROP_TSTAMP:
|
|
case PROP_TSTAMP_LO:
|
|
case PROP_TSTAMP_HI:
|
|
{
|
|
if (ctx->exp == NULL)
|
|
return false;
|
|
if (!(ctx->dview && ctx->dview->getProp (PROP_TSTAMP)))
|
|
return false;
|
|
hrtime_t tstamp = ctx->dview->getLongValue (PROP_TSTAMP, ctx->eventId);
|
|
// compute relative time from start of founder experiment
|
|
v.val = tstamp - ctx->exp->getStartTime ()
|
|
+ ctx->exp->getRelativeStartTime ();
|
|
if (propId == PROP_TSTAMP)
|
|
break;
|
|
if (ctx->dview->getProp (PROP_EVT_TIME))
|
|
{
|
|
hrtime_t delta = ctx->dview->getLongValue (PROP_EVT_TIME, ctx->eventId);
|
|
if (propId == PROP_TSTAMP_LO)
|
|
{
|
|
if (delta > 0)
|
|
{ // positive delta means TSTAMP is at end
|
|
// TSTAMP_LO = TSTAMP-delta
|
|
v.val -= delta;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
else
|
|
{ // PROP_TSTAMP_HI
|
|
if (delta < 0)
|
|
{ // negative delta means TSTAMP is at start
|
|
// TSTAMP_HI = TSTAMP+(-delta)
|
|
v.val -= delta;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else if (ctx->dview->getProp (PROP_TSTAMP2))
|
|
{
|
|
if (propId == PROP_TSTAMP_HI)
|
|
{
|
|
hrtime_t tstamp2 = ctx->dview->getLongValue (PROP_TSTAMP2,
|
|
ctx->eventId);
|
|
if (tstamp2 == 0)
|
|
break; // if not initialized, event does not have duration
|
|
if (tstamp2 == MAX_TIME)
|
|
tstamp2 = ctx->exp->getLastEvent ();
|
|
hrtime_t delta = tstamp2 - tstamp;
|
|
if (delta >= 0)
|
|
{
|
|
v.val += delta;
|
|
break;
|
|
}
|
|
break; // weird, delta should not be negative
|
|
}
|
|
break; // PROP_TSTAMP_LO, no modification needed
|
|
}
|
|
break; // should never be hit
|
|
}
|
|
case PROP_IOHEAPBYTES:
|
|
{
|
|
propId = PROP_IONBYTE;
|
|
if (ctx->dview == NULL)
|
|
return false;
|
|
if (!ctx->dview->getProp (propId))
|
|
{ // has property?
|
|
propId = PROP_HSIZE;
|
|
if (!ctx->dview->getProp (propId))
|
|
return false;
|
|
}
|
|
v.val = ctx->dview->getLongValue (propId, ctx->eventId);
|
|
break;
|
|
}
|
|
case PROP_SAMPLE_MAP:
|
|
{
|
|
if (ctx->exp == NULL)
|
|
return false;
|
|
if (ctx->dview == NULL)
|
|
return false;
|
|
if (ctx->dview->getProp (PROP_SAMPLE))
|
|
v.val = ctx->dview->getIntValue (PROP_SAMPLE, ctx->eventId);
|
|
else
|
|
{ // does not have property, convert to time.
|
|
uint64_t tstamp;
|
|
tstamp = ctx->dview->getLongValue (PROP_TSTAMP, ctx->eventId);
|
|
Sample *sample = ctx->exp->map_event_to_Sample (tstamp);
|
|
v.val = sample ? sample->get_number () : -1;
|
|
}
|
|
break;
|
|
}
|
|
case PROP_GCEVENT_MAP:
|
|
{
|
|
if (ctx->exp == NULL)
|
|
return false;
|
|
if (ctx->dview == NULL)
|
|
return false;
|
|
if (ctx->dview->getProp (PROP_GCEVENT))
|
|
v.val = ctx->dview->getIntValue (PROP_GCEVENT, ctx->eventId);
|
|
else
|
|
{ // does not have property, convert to time.
|
|
uint64_t tstamp;
|
|
tstamp = ctx->dview->getLongValue (PROP_TSTAMP, ctx->eventId);
|
|
GCEvent *gcevent = ctx->exp->map_event_to_GCEvent (tstamp);
|
|
v.val = gcevent ? gcevent->id : 0;
|
|
}
|
|
break;
|
|
}
|
|
case PROP_LEAF:
|
|
{
|
|
if (ctx->dview == NULL)
|
|
return false;
|
|
VMode vmode = ctx->dbev ? ctx->dbev->get_view_mode () : VMODE_USER;
|
|
int prop_id;
|
|
if (vmode == VMODE_MACHINE)
|
|
prop_id = PROP_MSTACK;
|
|
else if (vmode == VMODE_EXPERT)
|
|
prop_id = PROP_XSTACK;
|
|
else
|
|
prop_id = PROP_USTACK;
|
|
if (!ctx->dview->getProp (prop_id))
|
|
return false;
|
|
Histable *obj = CallStack::getStackPC (ctx->dview->getObjValue (prop_id, ctx->eventId), 0);
|
|
Function *func = (Function*) obj->convertto (Histable::FUNCTION);
|
|
v.val = func->id; // LEAF
|
|
break;
|
|
}
|
|
case PROP_STACKID:
|
|
{
|
|
VMode vmode = ctx->dbev ? ctx->dbev->get_view_mode () : VMODE_USER;
|
|
if (vmode == VMODE_MACHINE)
|
|
propId = PROP_MSTACK;
|
|
else if (vmode == VMODE_EXPERT)
|
|
propId = PROP_XSTACK;
|
|
else
|
|
propId = PROP_USTACK;
|
|
if (ctx->dview == NULL)
|
|
return false;
|
|
if (!ctx->dview->getProp (propId))
|
|
return false;
|
|
v.val = (long) ctx->dview->getObjValue (propId, ctx->eventId);
|
|
break;
|
|
}
|
|
case PROP_STACKL:
|
|
case PROP_STACKI:
|
|
case PROP_STACK:
|
|
{
|
|
VMode vmode = ctx->dbev ? ctx->dbev->get_view_mode () : VMODE_USER;
|
|
if (vmode == VMODE_MACHINE)
|
|
propId = PROP_MSTACK;
|
|
else if (vmode == VMODE_EXPERT)
|
|
propId = PROP_XSTACK;
|
|
else
|
|
propId = PROP_USTACK;
|
|
}
|
|
// no break;
|
|
case PROP_MSTACKL:
|
|
case PROP_XSTACKL:
|
|
case PROP_USTACKL:
|
|
case PROP_MSTACKI:
|
|
case PROP_XSTACKI:
|
|
case PROP_USTACKI:
|
|
switch (propId)
|
|
{
|
|
case PROP_MSTACKL:
|
|
case PROP_MSTACKI:
|
|
propId = PROP_MSTACK;
|
|
break;
|
|
case PROP_XSTACKL:
|
|
case PROP_XSTACKI:
|
|
propId = PROP_XSTACK;
|
|
break;
|
|
case PROP_USTACKL:
|
|
case PROP_USTACKI:
|
|
propId = PROP_USTACK;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
// no break;
|
|
case PROP_MSTACK:
|
|
case PROP_XSTACK:
|
|
case PROP_USTACK:
|
|
{
|
|
if (ctx->dview == NULL)
|
|
return false;
|
|
if (!ctx->dview->getProp (propId))
|
|
return false;
|
|
bool hide_mode = !ctx->dbev->isShowAll ()
|
|
|| ctx->dbev->isFilterHideMode ();
|
|
Expression *cur = this;
|
|
for (CallStackNode *stack = (CallStackNode *)
|
|
ctx->dview->getObjValue (propId, ctx->eventId);
|
|
stack; stack = stack->get_ancestor ())
|
|
{
|
|
Histable *hist = stack->get_instr ();
|
|
if (origPropId == PROP_STACK || origPropId == PROP_MSTACK
|
|
|| origPropId == PROP_XSTACK || origPropId == PROP_USTACK)
|
|
{
|
|
cur->v.val = hist->convertto (Histable::FUNCTION)->id;
|
|
cur->v.fn = cur->v.val;
|
|
}
|
|
else if (origPropId == PROP_STACKL || origPropId == PROP_MSTACKL
|
|
|| origPropId == PROP_XSTACKL || origPropId == PROP_USTACKL)
|
|
{
|
|
cur->v.val = hist->convertto (Histable::LINE)->id;
|
|
if (hide_mode)
|
|
cur->v.fn = hist->convertto (Histable::FUNCTION)->id;
|
|
else
|
|
cur->v.fn = 0;
|
|
}
|
|
else if (origPropId == PROP_STACKI || origPropId == PROP_MSTACKI
|
|
|| origPropId == PROP_XSTACKI || origPropId == PROP_USTACKI)
|
|
{
|
|
cur->v.val = hist->convertto (Histable::INSTR)->id;
|
|
if (hide_mode)
|
|
cur->v.fn = hist->convertto (Histable::FUNCTION)->id;
|
|
else
|
|
cur->v.fn = 0;
|
|
}
|
|
if (cur->arg1 == NULL)
|
|
cur->arg1 = new Expression (OP_NONE, (uint64_t) 0);
|
|
if (stack->get_ancestor () == NULL)
|
|
{
|
|
if (origPropId == PROP_STACKL || origPropId == PROP_MSTACKL
|
|
|| origPropId == PROP_XSTACKL || origPropId == PROP_USTACKL
|
|
|| origPropId == PROP_STACKI || origPropId == PROP_MSTACKI
|
|
|| origPropId == PROP_XSTACKI || origPropId == PROP_USTACKI)
|
|
{
|
|
cur->v.next = NULL;
|
|
continue;
|
|
}
|
|
}
|
|
cur->v.next = &cur->arg1->v;
|
|
cur = cur->arg1;
|
|
}
|
|
if (origPropId == PROP_STACK || origPropId == PROP_MSTACK
|
|
|| origPropId == PROP_XSTACK || origPropId == PROP_USTACK)
|
|
{
|
|
cur->v.val = dbeSession->get_Total_Function ()->id;
|
|
cur->v.fn = cur->v.val;
|
|
cur->v.next = NULL;
|
|
}
|
|
break;
|
|
}
|
|
case PROP_DOBJ:
|
|
{
|
|
if (ctx->dview == NULL)
|
|
return false;
|
|
if (!ctx->dview->getProp (PROP_DOBJ))
|
|
return false;
|
|
DataObject *dobj = (DataObject*)
|
|
ctx->dview->getObjValue (PROP_DOBJ, ctx->eventId);
|
|
if (dobj != NULL)
|
|
{
|
|
Expression *cur = this;
|
|
for (;;)
|
|
{
|
|
cur->v.val = dobj->id;
|
|
dobj = dobj->parent;
|
|
if (dobj == NULL)
|
|
break;
|
|
if (cur->arg1 == NULL)
|
|
cur->arg1 = new Expression (OP_NONE, (uint64_t) 0);
|
|
cur->v.next = &cur->arg1->v;
|
|
cur = cur->arg1;
|
|
}
|
|
cur->v.next = NULL;
|
|
}
|
|
break;
|
|
}
|
|
case PROP_CPRID:
|
|
case PROP_TSKID:
|
|
{
|
|
if (ctx->dview == NULL)
|
|
return false;
|
|
if (!ctx->dview->getProp (propId))
|
|
return false;
|
|
CallStackNode *ompstack = (CallStackNode *)
|
|
ctx->dview->getObjValue (propId, ctx->eventId);
|
|
Histable *hobj = ompstack->get_instr ();
|
|
if (hobj != NULL)
|
|
v.val = hobj->id;
|
|
break;
|
|
}
|
|
case PROP_JTHREAD:
|
|
{
|
|
if (ctx->exp == NULL)
|
|
return false;
|
|
if (ctx->dview == NULL)
|
|
return false;
|
|
if (!ctx->dview->getProp (propId))
|
|
return false;
|
|
uint64_t tstamp;
|
|
tstamp = ctx->dview->getLongValue (PROP_TSTAMP, ctx->eventId);
|
|
uint32_t thrid;
|
|
uint64_t jthr_id = 0;
|
|
thrid = ctx->dview->getIntValue (PROP_THRID, ctx->eventId);
|
|
JThread *jthread = ctx->exp->map_pckt_to_Jthread (thrid, tstamp);
|
|
if (jthread != JTHREAD_NONE && jthread != JTHREAD_DEFAULT)
|
|
{
|
|
jthr_id = jthread->jthr_id;
|
|
uint64_t grid = ctx->exp->groupId;
|
|
uint64_t expid = ctx->exp->getUserExpId ();
|
|
v.val = (grid << INDXOBJ_EXPGRID_SHIFT) |
|
|
(expid << INDXOBJ_EXPID_SHIFT) | jthr_id;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
Expression::bEval (Context *ctx)
|
|
{
|
|
uint64_t v0, v1;
|
|
switch (op)
|
|
{
|
|
case OP_DEG:
|
|
if (!arg1->bEval (ctx))
|
|
return false;
|
|
if (arg1->v.val < 0)
|
|
{
|
|
v.val = 0;
|
|
return true;
|
|
}
|
|
if (!arg0->bEval (ctx))
|
|
{
|
|
return false;
|
|
}
|
|
v0 = arg0->v.val;
|
|
v1 = arg1->v.val;
|
|
for (v.val = 1; v1 > 0; v1--)
|
|
v.val *= v0;
|
|
return true;
|
|
case OP_MUL:
|
|
if (arg0->bEval (ctx) && arg1->bEval (ctx))
|
|
{
|
|
v.val = arg0->v.val * arg1->v.val;
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_DIV:
|
|
if (arg0->bEval (ctx) && arg1->bEval (ctx))
|
|
{
|
|
v1 = arg1->v.val;
|
|
v.val = (v1 == 0) ? 0 : (arg0->v.val / v1);
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_REM:
|
|
if (arg0->bEval (ctx) && arg1->bEval (ctx))
|
|
{
|
|
v1 = arg1->v.val;
|
|
v.val = (v1 == 0) ? 0 : (arg0->v.val % v1);
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_ADD:
|
|
if (arg0->bEval (ctx) && arg1->bEval (ctx))
|
|
{
|
|
v.val = arg0->v.val + arg1->v.val;
|
|
// DBFIXME LIBRARY VISIBILITY
|
|
// hack to pass v.fn value to new expression for leaf filters USTACK+0
|
|
v.fn = arg0->v.fn + arg1->v.fn;
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_MINUS:
|
|
if (arg0->bEval (ctx) && arg1->bEval (ctx))
|
|
{
|
|
v.val = arg0->v.val - arg1->v.val;
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_LS:
|
|
if (arg0->bEval (ctx) && arg1->bEval (ctx))
|
|
{
|
|
v.val = arg0->v.val << arg1->v.val;
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_RS:
|
|
if (arg0->bEval (ctx) && arg1->bEval (ctx))
|
|
{
|
|
v.val = arg0->v.val >> arg1->v.val;
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_LT:
|
|
if (arg0->bEval (ctx) && arg1->bEval (ctx))
|
|
{
|
|
v.val = arg0->v.val < arg1->v.val ? 1 : 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_LE:
|
|
if (arg0->bEval (ctx) && arg1->bEval (ctx))
|
|
{
|
|
v.val = arg0->v.val <= arg1->v.val ? 1 : 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_GT:
|
|
if (arg0->bEval (ctx) && arg1->bEval (ctx))
|
|
{
|
|
v.val = arg0->v.val > arg1->v.val ? 1 : 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_GE:
|
|
if (arg0->bEval (ctx) && arg1->bEval (ctx))
|
|
{
|
|
v.val = arg0->v.val >= arg1->v.val ? 1 : 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_EQ:
|
|
if (arg0->bEval (ctx) && arg1->bEval (ctx))
|
|
{
|
|
v.val = arg0->v.val == arg1->v.val ? 1 : 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_NE:
|
|
if (arg0->bEval (ctx) && arg1->bEval (ctx))
|
|
{
|
|
v.val = arg0->v.val != arg1->v.val ? 1 : 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_BITAND:
|
|
if (arg0->bEval (ctx) && arg1->bEval (ctx))
|
|
{
|
|
v.val = arg0->v.val & arg1->v.val;
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_BITXOR:
|
|
if (arg0->bEval (ctx) && arg1->bEval (ctx))
|
|
{
|
|
v.val = arg0->v.val ^ arg1->v.val;
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_BITOR:
|
|
if (arg0->bEval (ctx) && arg1->bEval (ctx))
|
|
{
|
|
v.val = arg0->v.val | arg1->v.val;
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_AND:
|
|
if (arg0->bEval (ctx))
|
|
{
|
|
if (arg0->v.val == 0)
|
|
{
|
|
v.val = 0;
|
|
return true;
|
|
}
|
|
if (arg1->bEval (ctx))
|
|
{
|
|
v.val = arg1->v.val == 0 ? 0 : 1;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
if (arg1->bEval (ctx) && arg1->v.val == 0)
|
|
{
|
|
v.val = 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_OR:
|
|
if (arg0->bEval (ctx))
|
|
{
|
|
if (arg0->v.val != 0)
|
|
{
|
|
v.val = 1;
|
|
return true;
|
|
}
|
|
if (arg1->bEval (ctx))
|
|
{
|
|
v.val = arg1->v.val == 0 ? 0 : 1;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
if (arg1->bEval (ctx) && arg1->v.val != 0)
|
|
{
|
|
v.val = 1;
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_NEQV:
|
|
if (arg0->bEval (ctx) && arg1->bEval (ctx))
|
|
{
|
|
v0 = arg0->v.val;
|
|
v1 = arg1->v.val;
|
|
v.val = (v0 == 0 && v1 != 0) || (v0 != 0 && v1 == 0) ? 1 : 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_EQV:
|
|
if (arg0->bEval (ctx) && arg1->bEval (ctx))
|
|
{
|
|
v0 = arg0->v.val;
|
|
v1 = arg1->v.val;
|
|
v.val = (v0 == 0 && v1 == 0) || (v0 != 0 && v1 != 0) ? 1 : 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_QWE:
|
|
if (arg0->bEval (ctx))
|
|
{
|
|
if (arg0->v.val != 0)
|
|
{
|
|
if (arg1->arg0->bEval (ctx))
|
|
{
|
|
v.val = arg1->arg0->v.val;
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (arg1->arg1->bEval (ctx))
|
|
{
|
|
v.val = arg1->arg1->v.val;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
case OP_COMMA:
|
|
if (arg0->bEval (ctx))
|
|
{
|
|
v.next = &arg0->v;
|
|
if (arg1->bEval (ctx))
|
|
{
|
|
v.val = arg1->v.val;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
case OP_IN:
|
|
if (arg0->bEval (ctx) && arg1->bEval (ctx))
|
|
{
|
|
for (Value *s = &arg0->v; s; s = s->next)
|
|
{
|
|
bool found = false;
|
|
for (Value *t = &arg1->v; t; t = t->next)
|
|
{
|
|
if (t->val == s->val)
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found)
|
|
{
|
|
v.val = 0;
|
|
return true;
|
|
}
|
|
}
|
|
v.val = 1;
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_SOMEIN:
|
|
if (arg0->bEval (ctx) && arg1->bEval (ctx))
|
|
{
|
|
for (Value *s = &arg0->v; s; s = s->next)
|
|
{
|
|
for (Value *t = &arg1->v; t; t = t->next)
|
|
{
|
|
if (t->val == s->val)
|
|
{
|
|
v.val = 1;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
v.val = 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_ORDRIN:
|
|
if (arg0->bEval (ctx) && arg1->bEval (ctx))
|
|
{
|
|
for (Value *t0 = &arg1->v; t0; t0 = t0->next)
|
|
{
|
|
bool found = true;
|
|
for (Value *s = &arg0->v, *t = t0; s; s = s->next, t = t->next)
|
|
{
|
|
if (t == NULL || t->val != s->val)
|
|
{
|
|
found = false;
|
|
break;
|
|
}
|
|
}
|
|
if (found)
|
|
{
|
|
v.val = 1;
|
|
return true;
|
|
}
|
|
}
|
|
v.val = 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
// LIBRARY_VISIBILITY
|
|
case OP_LIBRARY_IN:
|
|
if (arg0->bEval (ctx) && arg1->bEval (ctx))
|
|
{
|
|
for (Value *s = &arg0->v; s; s = s->next)
|
|
{
|
|
bool found = false;
|
|
uint64_t objId = s->val;
|
|
Histable *obj = dbeSession->findObjectById (objId);
|
|
bool libraryFound = false;
|
|
Function *fn;
|
|
if (obj != NULL && obj->get_type () == Histable::FUNCTION)
|
|
{
|
|
fn = (Function *) obj;
|
|
if (fn->isHideFunc)
|
|
// this belongss to a loadobject in hide/library mode
|
|
libraryFound = true;
|
|
}
|
|
|
|
if (libraryFound)
|
|
{
|
|
uint64_t lo_id = fn->module->loadobject->id;
|
|
for (Value *t = &arg1->v; t; t = t->next)
|
|
{
|
|
uint64_t t_id = t->fn;
|
|
Histable *obj2 = dbeSession->findObjectById (t_id);
|
|
if (obj2 != NULL
|
|
&& obj2->get_type () == Histable::FUNCTION)
|
|
{
|
|
Function *func2 = (Function *) obj2;
|
|
uint64_t lo_id2 = func2->module->loadobject->id;
|
|
if (lo_id2 == lo_id)
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Not a loadobject
|
|
for (Value *t = &arg1->v; t; t = t->next)
|
|
{
|
|
if (t->val == s->val)
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!found)
|
|
{
|
|
v.val = 0;
|
|
return true;
|
|
}
|
|
}
|
|
v.val = 1;
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_LIBRARY_SOMEIN:
|
|
if (arg0->bEval (ctx) && arg1->bEval (ctx))
|
|
{
|
|
for (Value *s = &arg0->v; s; s = s->next)
|
|
{
|
|
uint64_t objId = s->val;
|
|
Histable *obj = dbeSession->findObjectById (objId);
|
|
bool libraryFound = false;
|
|
Function *fn;
|
|
if (obj != NULL && obj->get_type () == Histable::FUNCTION)
|
|
{
|
|
fn = (Function *) obj;
|
|
if (fn->isHideFunc)
|
|
// this belongs to a loadobject in hide/library mode
|
|
libraryFound = true;
|
|
}
|
|
|
|
if (libraryFound)
|
|
{
|
|
uint64_t lo_id = fn->module->loadobject->id;
|
|
for (Value *t = &arg1->v; t; t = t->next)
|
|
{
|
|
uint64_t t_id = t->fn;
|
|
Histable *obj2 = dbeSession->findObjectById (t_id);
|
|
if (obj2 != NULL && obj2->get_type () == Histable::FUNCTION)
|
|
{
|
|
Function *func2 = (Function *) obj2;
|
|
uint64_t lo_id2 = func2->module->loadobject->id;
|
|
if (lo_id2 == lo_id)
|
|
{
|
|
v.val = 1;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (Value *t = &arg1->v; t; t = t->next)
|
|
if (t->val == s->val)
|
|
{
|
|
v.val = 1;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
v.val = 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_LIBRARY_ORDRIN:
|
|
if (arg0->bEval (ctx) && arg1->bEval (ctx))
|
|
{
|
|
for (Value *t0 = &arg1->v; t0; t0 = t0->next)
|
|
{
|
|
bool found = true;
|
|
Value *t = t0;
|
|
for (Value *s = &arg0->v; s; s = s->next)
|
|
{
|
|
// start comparing s->val with t->val
|
|
// if matches move on to s->next and t->next
|
|
uint64_t objId = s->val;
|
|
Histable *obj = dbeSession->findObjectById (objId);
|
|
bool libraryFound = false;
|
|
Function *fn;
|
|
if (obj != NULL && obj->get_type () == Histable::FUNCTION)
|
|
{
|
|
fn = (Function *) obj;
|
|
if (fn->isHideFunc)
|
|
libraryFound = true;
|
|
}
|
|
if (libraryFound)
|
|
{
|
|
// s->val is from a loadobject
|
|
// check if t->val is a func whose loadobject matches s->val
|
|
uint64_t lo_id = fn->module->loadobject->id;
|
|
uint64_t t_id = t->fn;
|
|
Histable *obj2 = dbeSession->findObjectById (t_id);
|
|
if (obj2 != NULL
|
|
&& obj2->get_type () == Histable::FUNCTION)
|
|
{
|
|
Function *func2 = (Function *) obj2;
|
|
uint64_t lo_id2 = func2->module->loadobject->id;
|
|
if (lo_id2 != lo_id)
|
|
{
|
|
// no match
|
|
found = false;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// t->val is a func whose loadobject matches s->val
|
|
while (t != NULL && lo_id2 == lo_id)
|
|
{
|
|
// skip frames with same load object
|
|
t = t->next;
|
|
t_id = t->fn;
|
|
obj2 = dbeSession->findObjectById (t_id);
|
|
if (obj2 != NULL
|
|
&& obj2->get_type () == Histable::FUNCTION)
|
|
{
|
|
func2 = (Function *) obj2;
|
|
lo_id2 = func2->module->loadobject->id;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (t == NULL || t->val != s->val)
|
|
{
|
|
found = false;
|
|
break;
|
|
}
|
|
t = t->next;
|
|
}
|
|
}
|
|
if (found)
|
|
{
|
|
v.val = 1;
|
|
return true;
|
|
}
|
|
}
|
|
v.val = 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_BITNOT:
|
|
if (arg0->bEval (ctx))
|
|
{
|
|
v.val = ~arg0->v.val;
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_NOT:
|
|
if (arg0->bEval (ctx))
|
|
{
|
|
v.val = !arg0->v.val;
|
|
return true;
|
|
}
|
|
return false;
|
|
case OP_NUM:
|
|
return true;
|
|
case OP_NAME:
|
|
if (ctx && arg0->bEval (ctx) && getVal ((int) arg0->v.val, ctx))
|
|
return true;
|
|
return false;
|
|
case OP_FUNC:
|
|
// FNAME is completely processed by pEval for now
|
|
v.val = 0;
|
|
return true;
|
|
case OP_HASPROP:
|
|
if (!ctx || !ctx->dview)
|
|
return false; // can't be resolved (occurs during pEval() )
|
|
else if (arg0->op != OP_NAME || !arg0->arg0)
|
|
return false; // weird, wrong arg type
|
|
else
|
|
{
|
|
int propId = (int) arg0->arg0->v.val;
|
|
if (ctx->dview->getProp (propId))
|
|
v.val = 1;
|
|
else
|
|
v.val = 0;
|
|
return true;
|
|
}
|
|
case OP_FILE:
|
|
// FILENAME is completely processed by pEval for now
|
|
v.val = 0;
|
|
return true;
|
|
case OP_JAVA:
|
|
//JGROUP & JPARENT is completely processed by pEval for now
|
|
v.val = 0;
|
|
return true;
|
|
case OP_COLON:
|
|
return false; // OK for arg1 of OP_QWE
|
|
default:
|
|
#ifdef IPC_LOG
|
|
fprintf (stderr, "INTERNAL ERROR: Expression::eval op=%d\n", op);
|
|
#endif
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Expression *
|
|
Expression::pEval (Context *ctx) // partial evaluation (dview may be NULL)
|
|
{
|
|
Expression *res = NULL;
|
|
switch (op)
|
|
{
|
|
case OP_FUNC:
|
|
{
|
|
Vector<Histable*> *objs = NULL;
|
|
if (arg0->v.val == FUNC_FNAME)
|
|
{
|
|
Histable::NameFormat nfmt = ctx ? ctx->dbev->get_name_format () : Histable::NA;
|
|
objs = (Vector<Histable*>*)dbeSession->match_func_names ((char*) arg1->v.val, nfmt);
|
|
}
|
|
else if (arg0->v.val == FUNC_DNAME)
|
|
objs = (Vector<Histable*>*)dbeSession->match_dobj_names ((char*) arg1->v.val);
|
|
Expression *cur = new Expression (Expression::OP_NUM, (uint64_t) 0);
|
|
res = cur;
|
|
int i = objs ? objs->size () - 1 : -1;
|
|
for (; i >= 0; i--)
|
|
{
|
|
cur->v.val = objs->fetch (i)->id;
|
|
if (i == 0)
|
|
break;
|
|
cur->arg0 = new Expression (OP_NONE, (uint64_t) 0);
|
|
cur->v.next = &cur->arg0->v;
|
|
cur = cur->arg0;
|
|
}
|
|
cur->v.next = NULL;
|
|
if (objs)
|
|
delete objs;
|
|
break;
|
|
}
|
|
case OP_JAVA:
|
|
{
|
|
Vector<JThread*> *objs = NULL;
|
|
Vector<uint64_t> *grids = NULL;
|
|
Vector<uint64_t> *expids = NULL;
|
|
if (arg0->v.val == JAVA_JGROUP)
|
|
objs = dbeSession->match_java_threads ((char*) arg1->v.val, 0, grids,
|
|
expids);
|
|
else if (arg0->v.val == JAVA_JPARENT)
|
|
objs = dbeSession->match_java_threads ((char*) arg1->v.val, 1, grids,
|
|
expids);
|
|
Expression *cur = new Expression (Expression::OP_NUM, (uint64_t) 0);
|
|
res = cur;
|
|
int i = objs ? objs->size () - 1 : -1;
|
|
for (; i >= 0; i--)
|
|
{
|
|
uint64_t jthr_id = 0;
|
|
JThread *jthread = (JThread *) (objs->fetch (i));
|
|
jthr_id = jthread->jthr_id;
|
|
uint64_t grid = grids->fetch (i);
|
|
uint64_t expid = expids->fetch (i);
|
|
cur->v.val = (grid << INDXOBJ_EXPGRID_SHIFT) |
|
|
(expid << INDXOBJ_EXPID_SHIFT) | jthr_id;
|
|
if (i == 0)
|
|
break;
|
|
cur->arg0 = new Expression (OP_NONE, (uint64_t) 0);
|
|
cur->v.next = &cur->arg0->v;
|
|
cur = cur->arg0;
|
|
}
|
|
cur->v.next = NULL;
|
|
delete objs;
|
|
delete grids;
|
|
delete expids;
|
|
break;
|
|
}
|
|
case OP_FILE:
|
|
{
|
|
Vector<Histable*> *objs = NULL;
|
|
Histable::NameFormat nfmt = ctx ? ctx->dbev->get_name_format () : Histable::NA;
|
|
if (ctx)
|
|
objs = (Vector<Histable*>*)dbeSession->match_file_names ((char*) arg1->v.val, nfmt);
|
|
Expression *cur = new Expression (Expression::OP_NUM, (uint64_t) 0);
|
|
res = cur;
|
|
int i = objs ? objs->size () - 1 : -1;
|
|
for (; i >= 0; i--)
|
|
{
|
|
cur->v.val = objs->fetch (i)->id;
|
|
if (i == 0)
|
|
break;
|
|
cur->arg0 = new Expression (OP_NONE, (uint64_t) 0);
|
|
cur->v.next = &cur->arg0->v;
|
|
cur = cur->arg0;
|
|
}
|
|
cur->v.next = NULL;
|
|
if (objs)
|
|
delete objs;
|
|
break;
|
|
}
|
|
case OP_NUM:
|
|
case OP_COMMA:
|
|
res = copy ();
|
|
break;
|
|
case OP_IN:
|
|
case OP_SOMEIN:
|
|
case OP_ORDRIN:
|
|
{
|
|
// LIBRARY_VISIBILITY:
|
|
// Evaluate the arg0 of OP_IN, OP_SOMEIN, OP_ORDRIN to see if it has any library/loadobject
|
|
// Change it to OP_LIBRARY_IN, OP_LIBRARY_SOMEIN or OP_LIBRARY_ORDRIN respectively
|
|
if (dbeSession->is_lib_visibility_used () && (arg0->hasLoadObject ()
|
|
|| arg1->hasLoadObject ()))
|
|
{
|
|
OpCode new_op;
|
|
switch (op)
|
|
{
|
|
case OP_IN:
|
|
new_op = OP_LIBRARY_IN;
|
|
break;
|
|
case OP_SOMEIN:
|
|
new_op = OP_LIBRARY_SOMEIN;
|
|
break;
|
|
case OP_ORDRIN:
|
|
new_op = OP_LIBRARY_ORDRIN;
|
|
break;
|
|
default:
|
|
new_op = op; // Should never reach here
|
|
break;
|
|
}
|
|
if (arg1->hasLoadObject ())
|
|
res = new Expression (new_op, arg1 ? arg1->pEval (ctx) : NULL,
|
|
arg0 ? arg0->pEval (ctx) : NULL);
|
|
else
|
|
res = new Expression (new_op, arg0 ? arg0->pEval (ctx) : NULL,
|
|
arg1 ? arg1->pEval (ctx) : NULL);
|
|
res->v = v;
|
|
ctx->dbev->setFilterHideMode ();
|
|
return res;
|
|
}
|
|
}
|
|
// no break; if no loadobjects found fall thru to the default case
|
|
default:
|
|
if (bEval (ctx))
|
|
{
|
|
res = new Expression (OP_NUM, v.val);
|
|
break;
|
|
}
|
|
res = new Expression (op, arg0 ? arg0->pEval (ctx) : NULL,
|
|
arg1 ? arg1->pEval (ctx) : NULL);
|
|
res->v = v;
|
|
break;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
bool
|
|
Expression::verifyObjectInExpr (Histable *obj)
|
|
{
|
|
uint64_t id = ((uint64_t) obj->id);
|
|
if (op == OP_NUM && v.val == id)
|
|
return true;
|
|
bool inArg0 = false;
|
|
bool inArg1 = false;
|
|
if (arg0 != NULL)
|
|
inArg0 = arg0->verifyObjectInExpr (obj);
|
|
if (inArg0)
|
|
return true;
|
|
if (arg1 != NULL)
|
|
inArg1 = arg1->verifyObjectInExpr (obj);
|
|
if (inArg1)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
Expression::hasLoadObject ()
|
|
{
|
|
if (op == OP_NUM)
|
|
{
|
|
uint64_t id = v.val;
|
|
Histable *obj = dbeSession->findObjectById (id);
|
|
if (obj != NULL && obj->get_type () == Histable::FUNCTION)
|
|
{
|
|
Function *func = (Function *) obj;
|
|
if (func->isHideFunc)
|
|
return true;
|
|
}
|
|
}
|
|
if (arg0 && arg0->hasLoadObject ())
|
|
return true;
|
|
if (arg1 && arg1->hasLoadObject ())
|
|
return true;
|
|
return false;
|
|
}
|