1/*
2 * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/**
25 * @test
26 * @bug 4628726
27 * @summary Test class redefinition - method data line numbers and local vars,
28 * @author Robert Field
29 *
30 * @library ..
31 *
32 * @run build TestScaffold VMConnection TargetListener TargetAdapter
33 * @run compile -g RedefineTest.java
34 * @run shell RedefineSetUp.sh
35 * @run driver RedefineTest -repeat 3
36 * @run driver RedefineTest
37 */
38import com.sun.jdi.*;
39import com.sun.jdi.event.*;
40import com.sun.jdi.request.*;
41import java.util.*;
42import java.io.*;
43
44    /********** target program **********/
45
46class RedefineTarg {
47    public static void main(String[] args){
48        RedefineSubTarg.stemcp();
49        RedefineSubTarg sub = new RedefineSubTarg();
50        sub.bottom();
51        RedefineSubTarg.stnemcp();
52        RedefineSubTarg.stemcp();
53    }
54}
55
56    /********** test program **********/
57
58public class RedefineTest extends TestScaffold {
59    static int redefineRepeat = 1;
60    int bpCnt = 0;
61
62    // isObsolete, linenumber, lv name, lv value, lv isArg
63    String[] before = {
64    "+ 3",
65    "+ 6 eights 888 T",
66    "+ 11 rot 4 F",
67    "+ 15",
68    "+ 20 myArg 56 T paramy 12 F",
69    "+ 24",
70    "+ 28",
71    "+ 33" };
72    String[] after = {
73    "+ 5",
74    "O",
75    "O",
76    "+ 16",
77    "+ 21 whoseArg 56 T parawham 12 F",
78    "+ 25",
79    "O",
80    "+ 34" };
81    String[] shorter = {
82    "+ 5",
83    "+ 9 eights 88 T",
84    "+ 13",
85    "+ 16",
86    "+ 21 whoseArg 56 T parawham 12 F",
87    "+ 25" };
88    String[] refresh = {
89    "+ 5",
90    "+ 9 eights 88 T",
91    "+ 13",
92    "+ 16",
93    "+ 21 whoseArg 56 T parawham 12 F",
94    "+ 25",
95    "+ 29",
96    "+ 34" };
97    int[] bps = {7, 12, 16, 21, 25, 30, 34};
98    String[][] bpPlaces = {
99        {"+ 16"},
100        {"+ 21 myArg 56 T paramy 12 F"},
101        {"+ 25"},
102        {"+ 34"} };
103
104    static String[] processArgs(String args[]) {
105        if (args.length > 0 && args[0].equals("-repeat")) {
106            redefineRepeat = Integer.decode(args[1]).intValue();
107            String[] args2 = new String[args.length - 2];
108            System.arraycopy(args, 2, args2, 0, args.length - 2);
109            return args2;
110        } else {
111            return args;
112        }
113    }
114
115    RedefineTest (String args[]) {
116        super(args);
117    }
118
119    public static void main(String[] args)      throws Exception {
120        new RedefineTest(processArgs(args)).startTests();
121    }
122
123
124    /********** event handlers **********/
125
126    public void breakpointReached(BreakpointEvent event) {
127        println("Got BreakpointEvent - " + event);
128        try {
129            checkFrames(event.thread(), bpPlaces[bpCnt++]);
130            if (bpCnt >= bpPlaces.length) {
131                eventRequestManager().deleteAllBreakpoints();
132            }
133        } catch (Exception exc) {
134            failure("FAIL: breakpoint checking threw " + exc);
135        }
136    }
137
138    /********** test assists **********/
139
140    // isObsolete, linenumber, lv name, lv value, lv isArg
141    // equals: ref type (always), method (not obsolete)
142    void checkFrames(ThreadReference thread, String[] matchList) throws Exception {
143        for (int i = 0; i < matchList.length; ++i) {
144            String match = matchList[i];
145            StackFrame frame = thread.frame(i);
146            Location loc = frame.location();
147            ReferenceType refType = loc.declaringType();
148            Method meth = loc.method();
149            String errInfo = "\nframe " + i + ": " + loc + "\n  match: " + match;
150            if (!findReferenceType("RedefineSubTarg").equals(refType)) {
151                 failure("FAIL: Bad reference type - " + errInfo);
152                 return; // might be bad class, but might have run past bottom
153            }
154            StringTokenizer st = new StringTokenizer(match);
155            boolean expectObs = st.nextToken().equals("O");
156            println("Frame " + i + ": " + meth);
157            if (meth.isObsolete()) {
158                if (!expectObs) {
159                    failure("FAIL: Method should NOT be obsolete - " + errInfo);
160                }
161            } else {
162                if (expectObs) {
163                    failure("FAIL: Method should be obsolete - " + errInfo);
164                    break; // no more data to read
165                }
166                if (!findMethod(refType, meth.name(), meth.signature()).equals(meth)) {
167                    failure("FAIL: Non matching method - " + errInfo);
168                }
169                int line = loc.lineNumber();
170                if (line != Integer.parseInt(st.nextToken())) {
171                    failure("FAIL: Unexpected line number: " + errInfo);
172                }
173                // local var matching
174                int lvCnt = 0;
175                while (st.hasMoreTokens()) {
176                    ++lvCnt;
177                    String lvName = st.nextToken();
178                    int lvValue = Integer.parseInt(st.nextToken());
179                    boolean isArg = st.nextToken().equals("T");
180                    LocalVariable lv = frame.visibleVariableByName(lvName);
181                    if (lv == null) {
182                        failure("FAIL: local var not found: '" + lvName +
183                                "' -- " + errInfo);
184                    } else {
185                        Value val = frame.getValue(lv);
186                        int ival = ((IntegerValue)val).value();
187                        if (ival != lvValue) {
188                            failure("FAIL: expected value: '" + lvValue +
189                                    "' got: '" + ival + "' -- " + errInfo);
190                        }
191                        if (lv.isArgument() != isArg) {
192                            failure("FAIL: expected argument: '" + isArg +
193                                    "' got: '" + lv.isArgument() + "' -- " + errInfo);
194                        }
195                    }
196                }
197                List locals = frame.visibleVariables();
198                if (locals.size() != lvCnt) {
199                        failure("FAIL: expected '" + lvCnt +
200                                "' locals were '" + locals.size() +
201                                "' -- " + errInfo + "' -- " + locals);
202                }
203            }
204        }
205    }
206
207
208    void doRedefine(String fileName) throws Exception {
209        File phyl = new File(fileName);
210        byte[] bytes = new byte[(int)phyl.length()];
211        InputStream in = new FileInputStream(phyl);
212        in.read(bytes);
213        in.close();
214
215        Map map = new HashMap();
216        map.put(findReferenceType("RedefineSubTarg"), bytes);
217
218        try {
219            for (int i = 0; i < redefineRepeat; ++i) {
220                vm().redefineClasses(map);
221            }
222        } catch (Exception thr) {
223            failure("FAIL: unexpected exception: " + thr);
224        }
225    }
226
227    ThreadReference toTop() {
228        BreakpointEvent bpe = resumeTo("RedefineSubTarg", "top", "()V");
229        return bpe.thread();
230    }
231
232    void setBP(int line) {
233        try {
234            Location loc = findLocation(findReferenceType("RedefineSubTarg"), line);
235            final BreakpointRequest request =
236                eventRequestManager().createBreakpointRequest(loc);
237            request.enable();
238        } catch (Exception exc) {
239            failure("FAIL: Attempt to set BP at line " + line + " threw " + exc);
240        }
241    }
242
243    /********** test core **********/
244
245    protected void runTests() throws Exception {
246
247        startToMain("RedefineTarg");
248
249        ThreadReference thread = toTop();
250
251        println("------ Before Redefine ------");
252        checkFrames(thread, before);
253
254        println("------ After Redefine ------");
255        doRedefine("Different_RedefineSubTarg.class");
256        checkFrames(thread, after);
257
258        println("------ Static 2 ------");
259        toTop();
260        checkFrames(thread, shorter);
261
262        println("------ Instance ------");
263        toTop();
264        checkFrames(thread, shorter);
265
266        println("------ Re-entered ------");
267        toTop();
268        checkFrames(thread, refresh);
269
270        println("------ Breakpoints ------");
271        doRedefine("RedefineSubTarg.class");
272        for (int i = 0; i < bps.length; ++i) {
273            setBP(bps[i]);
274        }
275
276        /*
277         * resume the target listening for events
278         */
279        listenUntilVMDisconnect();
280
281        if (bpCnt != bpPlaces.length) {
282            failure("FAIL: Wrong number of breakpoints encountered: " + bpCnt);
283        }
284
285        /*
286         * deal with results of test
287         * if anything has called failure("foo") testFailed will be true
288         */
289        if (!testFailed) {
290            println("RedefineTest(method): passed");
291        } else {
292            throw new Exception("RedefineTest(method): failed");
293        }
294    }
295}
296