blob: 59749a2b001a41cffeddd16333587658ed90529d [file] [log] [blame]
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.debugger.ui.tree.render;
import com.intellij.debugger.DebuggerManager;
import com.intellij.debugger.engine.DebugProcess;
import com.intellij.debugger.engine.DebugProcessAdapter;
import com.intellij.debugger.engine.SuspendContext;
import com.intellij.debugger.engine.SuspendContextImpl;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
import com.intellij.debugger.engine.evaluation.EvaluationContext;
import com.intellij.debugger.engine.jdi.ThreadReferenceProxy;
import com.intellij.debugger.engine.managerThread.SuspendContextCommand;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.rt.debugger.BatchEvaluatorServer;
import com.intellij.util.containers.HashMap;
import com.sun.jdi.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* User: lex
* Date: Jul 7, 2003
* Time: 11:13:52 PM
*/
public class BatchEvaluator {
private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.tree.render.BatchEvaluator");
private final DebugProcess myDebugProcess;
private boolean myBatchEvaluatorChecked;
private ObjectReference myBatchEvaluatorObject;
private Method myBatchEvaluatorMethod;
private static final Key<BatchEvaluator> BATCH_EVALUATOR_KEY = new Key<BatchEvaluator>("BatchEvaluator");
public static final Key<Boolean> REMOTE_SESSION_KEY = new Key<Boolean>("is_remote_session_key");
private final HashMap<SuspendContext, List<ToStringCommand>> myBuffer = new HashMap<SuspendContext, List<ToStringCommand>>();
private BatchEvaluator(DebugProcess process) {
myDebugProcess = process;
myDebugProcess.addDebugProcessListener(new DebugProcessAdapter() {
public void processDetached(DebugProcess process, boolean closedByUser) {
myBatchEvaluatorChecked = false;
myBatchEvaluatorObject= null;
myBatchEvaluatorMethod = null;
}
});
}
@SuppressWarnings({"HardCodedStringLiteral"}) public boolean hasBatchEvaluator(EvaluationContext evaluationContext) {
if (!myBatchEvaluatorChecked) {
myBatchEvaluatorChecked = true;
final Boolean isRemote = myDebugProcess.getUserData(REMOTE_SESSION_KEY);
if (isRemote != null && isRemote.booleanValue()) {
// optimization: for remote sessions the BatchEvaluator is not there for sure
return false;
}
ThreadReferenceProxy thread = evaluationContext.getSuspendContext().getThread();
if (thread == null) {
return false;
}
ThreadReference threadReference = thread.getThreadReference();
if(threadReference == null) {
return false;
}
ClassType batchEvaluatorClass = null;
try {
batchEvaluatorClass = (ClassType)myDebugProcess.findClass(evaluationContext, BatchEvaluatorServer.class.getName(),
evaluationContext.getClassLoader());
}
catch (EvaluateException e) {
}
if (batchEvaluatorClass != null) {
Method constructor = batchEvaluatorClass.concreteMethodByName("<init>", "()V");
if(constructor != null){
ObjectReference evaluator = null;
try {
evaluator = myDebugProcess.newInstance(evaluationContext, batchEvaluatorClass, constructor, new ArrayList());
}
catch (Exception e) {
LOG.debug(e);
}
myBatchEvaluatorObject = evaluator;
if(myBatchEvaluatorObject != null) {
myBatchEvaluatorMethod = batchEvaluatorClass.concreteMethodByName("evaluate", "([Ljava/lang/Object;)[Ljava/lang/Object;");
}
}
}
}
return myBatchEvaluatorMethod != null;
}
public void invoke(ToStringCommand command) {
LOG.assertTrue(DebuggerManager.getInstance(myDebugProcess.getProject()).isDebuggerManagerThread());
final EvaluationContext evaluationContext = command.getEvaluationContext();
final SuspendContext suspendContext = evaluationContext.getSuspendContext();
if(!Registry.is("debugger.batch.evaluation") || !hasBatchEvaluator(evaluationContext)) {
myDebugProcess.getManagerThread().invokeCommand(command);
}
else {
List<ToStringCommand> toStringCommands = myBuffer.get(suspendContext);
if(toStringCommands == null) {
final List<ToStringCommand> commands = new ArrayList<ToStringCommand>();
toStringCommands = commands;
myBuffer.put(suspendContext, commands);
myDebugProcess.getManagerThread().invokeCommand(new SuspendContextCommand() {
public SuspendContext getSuspendContext() {
return suspendContext;
}
public void action() {
myBuffer.remove(suspendContext);
if(!doEvaluateBatch(commands, evaluationContext)) {
for (Iterator<ToStringCommand> iterator = commands.iterator(); iterator.hasNext();) {
ToStringCommand toStringCommand = iterator.next();
toStringCommand.action();
}
}
}
public void commandCancelled() {
myBuffer.remove(suspendContext);
}
});
}
toStringCommands.add(command);
}
}
public static BatchEvaluator getBatchEvaluator(DebugProcess debugProcess) {
BatchEvaluator batchEvaluator = debugProcess.getUserData(BATCH_EVALUATOR_KEY);
if(batchEvaluator == null) {
batchEvaluator = new BatchEvaluator(debugProcess);
debugProcess.putUserData(BATCH_EVALUATOR_KEY, batchEvaluator);
}
return batchEvaluator;
}
@SuppressWarnings({"HardCodedStringLiteral"})
private boolean doEvaluateBatch(List<ToStringCommand> requests, EvaluationContext evaluationContext) {
try {
DebugProcess debugProcess = evaluationContext.getDebugProcess();
List<Value> values = new ArrayList<Value>();
for (Iterator<ToStringCommand> iterator = requests.iterator(); iterator.hasNext();) {
ToStringCommand toStringCommand = iterator.next();
final Value value = toStringCommand.getValue();
values.add(value instanceof ObjectReference? ((ObjectReference)value) : value);
}
ArrayType objectArrayClass = (ArrayType)debugProcess.findClass(
evaluationContext,
"java.lang.Object[]",
evaluationContext.getClassLoader());
if (objectArrayClass == null) {
return false;
}
ArrayReference argArray = debugProcess.newInstance(objectArrayClass, values.size());
((SuspendContextImpl)evaluationContext.getSuspendContext()).keep(argArray); // to avoid ObjectCollectedException
argArray.setValues(values);
List argList = new ArrayList(1);
argList.add(argArray);
Value value = debugProcess.invokeMethod(evaluationContext, myBatchEvaluatorObject,
myBatchEvaluatorMethod, argList);
if (value instanceof ArrayReference) {
((SuspendContextImpl)evaluationContext.getSuspendContext()).keep((ArrayReference)value); // to avoid ObjectCollectedException for both the array and its elements
final ArrayReference strings = (ArrayReference)value;
final List<Value> allValuesArray = strings.getValues();
final Value[] allValues = allValuesArray.toArray(new Value[allValuesArray.size()]);
int idx = 0;
for (Iterator<ToStringCommand> iterator = requests.iterator(); iterator.hasNext(); idx++) {
ToStringCommand request = iterator.next();
final Value strValue = allValues[idx];
if(strValue == null || strValue instanceof StringReference){
try {
String str = (strValue == null)? null : ((StringReference)strValue).value();
request.evaluationResult(str);
}
catch (ObjectCollectedException e) {
// ignored
}
}
else if(strValue instanceof ObjectReference){
request.evaluationError(EvaluateExceptionUtil.createEvaluateException(new InvocationException((ObjectReference)strValue)).getMessage());
}
else {
LOG.assertTrue(false);
}
request.setEvaluated();
}
}
return true;
}
catch (ClassNotLoadedException e) {
}
catch (InvalidTypeException e) {
}
catch (EvaluateException e) {
}
catch (ObjectCollectedException e) {
}
return false;
}
}