/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.max.vm.log.java;
import com.sun.max.annotate.*;
import com.sun.max.unsafe.*;
import com.sun.max.vm.*;
import com.sun.max.vm.actor.member.*;
import com.sun.max.vm.heap.*;
import com.sun.max.vm.log.*;
import com.sun.max.vm.log.VMLog.*;
import com.sun.max.vm.reference.*;
import com.sun.max.vm.thread.*;
/**
* Common superclass for implementations using an indexed array of {@link Record} instances.
*/
public abstract class VMLogArray extends VMLog {
@CONSTANT_WHEN_NOT_ZERO
private int arg1Offset;
@INSPECTED
@CONSTANT
public Record[] buffer;
@Override
public void initialize(MaxineVM.Phase phase) {
super.initialize(phase);
if (phase == MaxineVM.Phase.BOOTSTRAPPING) {
buffer = new Record[logEntries];
try {
arg1Offset = FieldActor.fromJava(Record1.class.getDeclaredField("arg1")).offset();
} catch (NoSuchFieldException ex) {
// cannot happen
}
}
}
/*
* Subclasses RecordN, that can hold N arguments, whose values can been read out by the Inspector.
*/
public static class Record0 extends Record {
@INSPECTED
protected volatile int header;
@Override
public void setHeader(int header) {
this.header = header;
}
@Override
public int getHeader() {
return header;
}
}
public static class Record1 extends Record0 {
@INSPECTED
public Word arg1;
@Override
public Word getArg(int n) {
// Checkstyle: stop
switch (n) {
case 1: return arg1;
default: return argError();
}
// Checkstyle: resume
}
@Override
public void setArgs(Word arg1) {
this.arg1 = arg1;
}
}
public static class Record2 extends Record1 {
@INSPECTED
public Word arg2;
@Override
public Word getArg(int n) {
// Checkstyle: stop
switch (n) {
case 1: return arg1;
case 2: return arg2;
default: return argError();
}
// Checkstyle: resume
}
@Override
public void setArgs(Word arg1, Word arg2) {
this.arg1 = arg1;
this.arg2 = arg2;
}
}
public static class Record3 extends Record2 {
@INSPECTED
public Word arg3;
@Override
public Word getArg(int n) {
// Checkstyle: stop
switch (n) {
case 1: return arg1;
case 2: return arg2;
case 3: return arg3;
default: return argError();
}
// Checkstyle: resume
}
@Override
public void setArgs(Word arg1, Word arg2, Word arg3) {
this.arg1 = arg1;
this.arg2 = arg2;
this.arg3 = arg3;
}
}
public static class Record4 extends Record3 {
@INSPECTED
public Word arg4;
@Override
public Word getArg(int n) {
// Checkstyle: stop
switch (n) {
case 1: return arg1;
case 2: return arg2;
case 3: return arg3;
case 4: return arg4;
default: return argError();
}
// Checkstyle: resume
}
@Override
public void setArgs(Word arg1, Word arg2, Word arg3, Word arg4) {
this.arg1 = arg1;
this.arg2 = arg2;
this.arg3 = arg3;
this.arg4 = arg4;
}
}
public static class Record5 extends Record4 {
@INSPECTED
public Word arg5;
@Override
public Word getArg(int n) {
// Checkstyle: stop
switch (n) {
case 1: return arg1;
case 2: return arg2;
case 3: return arg3;
case 4: return arg4;
case 5: return arg5;
default: return argError();
}
// Checkstyle: resume
}
@Override
public void setArgs(Word arg1, Word arg2, Word arg3, Word arg4, Word arg5) {
this.arg1 = arg1;
this.arg2 = arg2;
this.arg3 = arg3;
this.arg4 = arg4;
this.arg5 = arg5;
}
}
public static class Record6 extends Record5 {
@INSPECTED
public Word arg6;
@Override
public Word getArg(int n) {
// Checkstyle: stop
switch (n) {
case 1: return arg1;
case 2: return arg2;
case 3: return arg3;
case 4: return arg4;
case 5: return arg5;
case 6: return arg6;
default: return argError();
}
// Checkstyle: resume
}
@Override
public void setArgs(Word arg1, Word arg2, Word arg3, Word arg4, Word arg5, Word arg6) {
this.arg1 = arg1;
this.arg2 = arg2;
this.arg3 = arg3;
this.arg4 = arg4;
this.arg5 = arg5;
this.arg6 = arg6;
}
}
public static class Record7 extends Record6 {
@INSPECTED
public Word arg7;
@Override
public Word getArg(int n) {
// Checkstyle: stop
switch (n) {
case 1: return arg1;
case 2: return arg2;
case 3: return arg3;
case 4: return arg4;
case 5: return arg5;
case 6: return arg6;
case 7: return arg7;
default: return argError();
}
// Checkstyle: resume
}
@Override
public void setArgs(Word arg1, Word arg2, Word arg3, Word arg4, Word arg5, Word arg6, Word arg7) {
this.arg1 = arg1;
this.arg2 = arg2;
this.arg3 = arg3;
this.arg4 = arg4;
this.arg5 = arg5;
this.arg6 = arg6;
this.arg7 = arg7;
}
}
public static class Record8 extends Record7 {
@INSPECTED
public Word arg8;
@Override
public Word getArg(int n) {
// Checkstyle: stop
switch (n) {
case 1: return arg1;
case 2: return arg2;
case 3: return arg3;
case 4: return arg4;
case 5: return arg5;
case 6: return arg6;
case 7: return arg7;
case 8: return arg8;
default: return argError();
}
// Checkstyle: resume
}
@Override
public void setArgs(Word arg1, Word arg2, Word arg3, Word arg4, Word arg5, Word arg6, Word arg7, Word arg8) {
this.arg1 = arg1;
this.arg2 = arg2;
this.arg3 = arg3;
this.arg4 = arg4;
this.arg5 = arg5;
this.arg6 = arg6;
this.arg7 = arg7;
this.arg7 = arg8;
}
}
static final VmThreadLocal VMLOG_THREADSTATE = new VmThreadLocal("VMLOG_THREADSTATE", false, "VMLog state");
@Override
public boolean setThreadState(boolean state) {
Word old = VMLOG_THREADSTATE.load(VmThread.currentTLA());
VMLOG_THREADSTATE.store3(state ? Word.zero() : Word.allOnes());
return old.isZero();
}
@Override
public boolean threadIsEnabled() {
return VMLOG_THREADSTATE.load(VmThread.currentTLA()).isZero();
}
/**
* Called to scan/update {@link VMLog} buffer, once per-thread.
* Since we have a global log, we only need to scan once.
*/
@Override
public void scanLog(Pointer tla, PointerIndexVisitor visitor) {
if (isRepeatScanLogVisitor(visitor)) {
return;
}
// order doesn't matter, just how many entries are in use
int hwm = nextId > logEntries ? logEntries : nextId;
for (int i = 0; i < hwm; i++) {
Record r = buffer[i];
scanArgs(r, Reference.fromJava(r).toOrigin().plus(arg1Offset), visitor);
}
}
@NEVER_INLINE
private void doVisit(int index, PointerIndexVisitor visitor, Pointer argBase, int argIndex) {
visitor.visit(argBase, argIndex);
}
}