1/*
2 * Copyright 2014-2016, Rene Gollent, rene@gollent.com.
3 * Distributed under the terms of the MIT License.
4 */
5
6#include "Jobs.h"
7
8#include <String.h>
9
10#include <AutoLocker.h>
11
12#include "DebuggerInterface.h"
13#include "ExpressionInfo.h"
14#include "model/Thread.h"
15#include "SourceLanguage.h"
16#include "StackFrame.h"
17#include "Team.h"
18#include "Type.h"
19#include "Value.h"
20#include "ValueNode.h"
21#include "ValueNodeManager.h"
22#include "Variable.h"
23
24
25ExpressionEvaluationJob::ExpressionEvaluationJob(Team* team,
26	DebuggerInterface* debuggerInterface, SourceLanguage* language,
27	ExpressionInfo* info, StackFrame* frame,
28	::Thread* thread)
29	:
30	fKey(info->Expression(), JOB_TYPE_EVALUATE_EXPRESSION),
31	fTeam(team),
32	fDebuggerInterface(debuggerInterface),
33	fArchitecture(debuggerInterface->GetArchitecture()),
34	fTypeInformation(team->GetTeamTypeInformation()),
35	fLanguage(language),
36	fExpressionInfo(info),
37	fFrame(frame),
38	fThread(thread),
39	fManager(NULL),
40	fResultValue(NULL)
41{
42	fLanguage->AcquireReference();
43	fExpressionInfo->AcquireReference();
44
45	if (fFrame != NULL)
46		fFrame->AcquireReference();
47	if (fThread != NULL)
48		fThread->AcquireReference();
49}
50
51
52ExpressionEvaluationJob::~ExpressionEvaluationJob()
53{
54	fLanguage->ReleaseReference();
55	fExpressionInfo->ReleaseReference();
56	if (fFrame != NULL)
57		fFrame->ReleaseReference();
58	if (fThread != NULL)
59		fThread->ReleaseReference();
60	if (fManager != NULL)
61		fManager->ReleaseReference();
62	if (fResultValue != NULL)
63		fResultValue->ReleaseReference();
64}
65
66
67const JobKey&
68ExpressionEvaluationJob::Key() const
69{
70	return fKey;
71}
72
73
74status_t
75ExpressionEvaluationJob::Do()
76{
77	BReference<Value> reference;
78	status_t result = B_OK;
79	if (fFrame != NULL && fManager == NULL) {
80		fManager = new(std::nothrow) ValueNodeManager();
81		if (fManager == NULL)
82			result = B_NO_MEMORY;
83		else
84			result = fManager->SetStackFrame(fThread, fFrame);
85	}
86
87	if (result != B_OK) {
88		fExpressionInfo->NotifyExpressionEvaluated(result, NULL);
89		return result;
90	}
91
92	ValueNode* neededNode = NULL;
93	result = fLanguage->EvaluateExpression(fExpressionInfo->Expression(),
94		fManager, fTeam->GetTeamTypeInformation(), fResultValue, neededNode);
95	if (neededNode != NULL) {
96		result = ResolveNodeValue(neededNode);
97		if (State() == JOB_STATE_WAITING)
98			return B_OK;
99		// if result != B_OK, fall through
100	}
101
102	fExpressionInfo->NotifyExpressionEvaluated(result, fResultValue);
103
104	return B_OK;
105}
106
107
108status_t
109ExpressionEvaluationJob::ResolveNodeValue(ValueNode* node)
110{
111	AutoLocker<Worker> workerLocker(GetWorker());
112	SimpleJobKey jobKey(node, JOB_TYPE_RESOLVE_VALUE_NODE_VALUE);
113
114	status_t error = B_OK;
115	if (GetWorker()->GetJob(jobKey) == NULL) {
116		workerLocker.Unlock();
117
118		// schedule the job
119		error = GetWorker()->ScheduleJob(
120			new(std::nothrow) ResolveValueNodeValueJob(fDebuggerInterface,
121				fArchitecture, fThread->GetCpuState(), fTypeInformation,
122				fManager->GetContainer(), node));
123		if (error != B_OK) {
124			// scheduling failed -- set the value to invalid
125			node->SetLocationAndValue(NULL, NULL, error);
126			return error;
127		}
128	}
129
130	// wait for the job to finish
131	workerLocker.Unlock();
132
133
134	switch (WaitFor(jobKey)) {
135		case JOB_DEPENDENCY_SUCCEEDED:
136		case JOB_DEPENDENCY_NOT_FOUND:
137		case JOB_DEPENDENCY_ACTIVE:
138			error = B_OK;
139			break;
140		case JOB_DEPENDENCY_FAILED:
141		case JOB_DEPENDENCY_ABORTED:
142		default:
143			error = B_ERROR;
144			break;
145	}
146
147	return error;
148}
149