Home | History | Annotate | Download | only in value
      1 /*
      2  * Copyright 2016, Google Inc.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are
      7  * met:
      8  *
      9  * Redistributions of source code must retain the above copyright
     10  * notice, this list of conditions and the following disclaimer.
     11  * Redistributions in binary form must reproduce the above
     12  * copyright notice, this list of conditions and the following disclaimer
     13  * in the documentation and/or other materials provided with the
     14  * distribution.
     15  * Neither the name of Google Inc. nor the names of its
     16  * contributors may be used to endorse or promote products derived from
     17  * this software without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 package org.jf.smalidea.debugging.value;
     33 
     34 import com.intellij.debugger.DebuggerManagerEx;
     35 import com.intellij.debugger.engine.DebugProcessImpl;
     36 import com.intellij.debugger.engine.evaluation.EvaluateException;
     37 import com.intellij.debugger.engine.evaluation.EvaluationContext;
     38 import com.intellij.debugger.impl.DebuggerContextImpl;
     39 import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
     40 import com.intellij.openapi.project.Project;
     41 import com.sun.jdi.Type;
     42 import com.sun.jdi.Value;
     43 import com.sun.jdi.VirtualMachine;
     44 import org.jf.smalidea.debugging.SmaliCodeFragmentFactory;
     45 import org.jf.smalidea.psi.impl.SmaliMethod;
     46 
     47 import javax.annotation.Nonnull;
     48 import javax.annotation.Nullable;
     49 
     50 public class LazyValue<T extends Value> implements Value {
     51     private final int registerNumber;
     52     private final Project project;
     53     private final SmaliMethod method;
     54     private final String type;
     55 
     56     private EvaluationContext evaluationContext;
     57     private Value value;
     58 
     59     public LazyValue(SmaliMethod method, Project project, int registerNumber, String type) {
     60         this.method = method;
     61         this.project = project;
     62         this.registerNumber = registerNumber;
     63         this.type = type;
     64     }
     65 
     66     public static LazyValue create(@Nonnull SmaliMethod method, @Nonnull Project project, int registerNumber,
     67                                    @Nonnull String type) {
     68         if (type.equals("B")) {
     69             return new LazyByteValue(method, project, registerNumber, type);
     70         } else if (type.equals("S")) {
     71             return new LazyShortValue(method, project, registerNumber, type);
     72         } else if (type.equals("J")) {
     73             return new LazyLongValue(method, project, registerNumber, type);
     74         } else if (type.equals("I")) {
     75             return new LazyIntegerValue(method, project, registerNumber, type);
     76         } else if (type.equals("F")) {
     77             return new LazyFloatValue(method, project, registerNumber, type);
     78         } else if (type.equals("D")) {
     79             return new LazyDoubleValue(method, project, registerNumber, type);
     80         } else if (type.equals("Z")) {
     81             return new LazyBooleanValue(method, project, registerNumber, type);
     82         } else if (type.equals("C")) {
     83             return new LazyCharValue(method, project, registerNumber, type);
     84         } else if (type.equals("V")) {
     85             return new LazyVoidValue(method, project, registerNumber, type);
     86         } else if (type.startsWith("[")) {
     87             return new LazyArrayReference(method, project, registerNumber, type);
     88         } else if (type.equals("Ljava/lang/String;")) {
     89             return new LazyStringReference(method, project, registerNumber, type);
     90         } else if (type.equals("Ljava/lang/Class;")) {
     91             return new LazyClassObjectReference(method, project, registerNumber, type);
     92         } else if (type.equals("Ljava/lang/ThreadGroup;")) {
     93             return new LazyThreadGroupReference(method, project, registerNumber, type);
     94         } else if (type.equals("Ljava/lang/Thread;")) {
     95             return new LazyThreadReference(method, project, registerNumber, type);
     96         } else if (type.equals("Ljava/lang/ClassLoader;")) {
     97             return new LazyClassLoaderReference(method, project, registerNumber, type);
     98         } else if (type.startsWith("L")) {
     99             return new LazyObjectReference(method, project, registerNumber, type);
    100         }
    101         return new LazyValue(method, project, registerNumber, type);
    102     }
    103 
    104     @Nullable
    105     private T getNullableValue() {
    106         if (value == null) {
    107             try {
    108                 if (evaluationContext == null) {
    109                     final DebuggerContextImpl debuggerContext = DebuggerManagerEx.getInstanceEx(project).getContext();
    110                     evaluationContext = debuggerContext.createEvaluationContext();
    111                     if (evaluationContext == null) {
    112                         return null;
    113                     }
    114                 }
    115 
    116                 value = SmaliCodeFragmentFactory.evaluateRegister(evaluationContext, method, registerNumber, type);
    117                 evaluationContext = null;
    118             } catch (EvaluateException ex) {
    119                 return null;
    120             }
    121         }
    122         return (T)value;
    123     }
    124 
    125     @Nonnull
    126     protected T getValue() {
    127         T value = getNullableValue();
    128         assert value != null;
    129         return value;
    130     }
    131 
    132     @Override
    133     public Type type() {
    134         return getValue().type();
    135     }
    136 
    137     @Override
    138     public VirtualMachine virtualMachine() {
    139         if (evaluationContext != null) {
    140             return ((VirtualMachineProxyImpl)evaluationContext.getDebugProcess().getVirtualMachineProxy())
    141                     .getVirtualMachine();
    142         } else {
    143             final DebuggerContextImpl debuggerContext = DebuggerManagerEx.getInstanceEx(project).getContext();
    144             final DebugProcessImpl process = debuggerContext.getDebugProcess();
    145             if (process != null) {
    146                 return process.getVirtualMachineProxy().getVirtualMachine();
    147             }
    148         }
    149         return null;
    150     }
    151 
    152     public void setEvaluationContext(@Nonnull EvaluationContext evaluationContext) {
    153         this.evaluationContext = evaluationContext;
    154     }
    155 
    156     @Override public boolean equals(Object obj) {
    157         Value value = getNullableValue();
    158         if (value != null) {
    159             return value.equals(obj);
    160         }
    161         return super.equals(obj);
    162     }
    163 
    164     @Override public int hashCode() {
    165         Value value = getNullableValue();
    166         if (value != null) {
    167             return value.hashCode();
    168         }
    169         return super.hashCode();
    170     }
    171 
    172     @Override public String toString() {
    173         Value value = getNullableValue();
    174         if (value != null) {
    175             return value.toString();
    176         }
    177         return super.toString();
    178     }
    179 }
    180