001/*
002 * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.compiler.test;
024
025import static java.nio.file.StandardOpenOption.*;
026
027import java.io.*;
028import java.nio.*;
029import java.nio.channels.*;
030import java.nio.channels.FileChannel.*;
031import java.nio.file.*;
032
033import org.junit.*;
034
035import com.oracle.graal.nodes.*;
036import com.oracle.graal.phases.common.*;
037import com.oracle.graal.phases.common.inlining.*;
038import com.oracle.graal.phases.common.inlining.policy.*;
039import com.oracle.graal.phases.tiers.*;
040
041import jdk.internal.jvmci.code.*;
042import jdk.internal.jvmci.meta.*;
043import sun.misc.*;
044
045public class MarkUnsafeAccessTest extends GraalCompilerTest {
046
047    public static Unsafe unsafe;
048
049    public void getRaw() {
050        unsafe.getInt(0L);
051    }
052
053    public void get() {
054        unsafe.getInt(null, 0L);
055    }
056
057    public void putRaw() {
058        unsafe.putInt(0L, 0);
059    }
060
061    public void put() {
062        unsafe.putInt(null, 0L, 0);
063    }
064
065    public void cas() {
066        unsafe.compareAndSwapInt(null, 0, 0, 0);
067    }
068
069    public void noAccess() {
070        unsafe.addressSize();
071        unsafe.pageSize();
072    }
073
074    private void assertHasUnsafe(String name, boolean hasUnsafe) {
075        Assert.assertEquals(hasUnsafe, compile(getResolvedJavaMethod(name), null).hasUnsafeAccess());
076    }
077
078    @Test
079    public void testGet() {
080        assertHasUnsafe("get", true);
081        assertHasUnsafe("getRaw", true);
082    }
083
084    @Test
085    public void testPut() {
086        assertHasUnsafe("put", true);
087        assertHasUnsafe("putRaw", true);
088    }
089
090    @Test
091    public void testCas() {
092        assertHasUnsafe("cas", true);
093    }
094
095    @Test
096    public void testNoAcces() {
097        assertHasUnsafe("noAccess", false);
098    }
099
100    @FunctionalInterface
101    private interface MappedByteBufferGetter {
102        byte get(MappedByteBuffer mbb);
103    }
104
105    @Test
106    public void testStandard() throws IOException {
107        testMappedByteBuffer(MappedByteBuffer::get);
108    }
109
110    @Test
111    public void testCompiled() throws IOException {
112        ResolvedJavaMethod getMethod = asResolvedJavaMethod(getMethod(ByteBuffer.class, "get", new Class<?>[]{}));
113        ResolvedJavaType mbbClass = getMetaAccess().lookupJavaType(MappedByteBuffer.class);
114        ResolvedJavaMethod getMethodImpl = mbbClass.findUniqueConcreteMethod(getMethod).getResult();
115        Assert.assertNotNull(getMethodImpl);
116        StructuredGraph graph = parseForCompile(getMethodImpl);
117        HighTierContext highContext = getDefaultHighTierContext();
118        new CanonicalizerPhase().apply(graph, highContext);
119        new InliningPhase(new InlineEverythingPolicy(), new CanonicalizerPhase()).apply(graph, highContext);
120        InstalledCode compiledCode = getCode(getMethodImpl, graph);
121        testMappedByteBuffer(mbb -> {
122            try {
123                return (byte) compiledCode.executeVarargs(mbb);
124            } catch (InvalidInstalledCodeException e) {
125                Assert.fail();
126                return 0;
127            }
128        });
129    }
130
131    private static final int BLOCK_SIZE = 512;
132    private static final int BLOCK_COUNT = 16;
133
134    public void testMappedByteBuffer(MappedByteBufferGetter getter) throws IOException {
135        Path tmp = Files.createTempFile(null, null);
136        tmp.toFile().deleteOnExit();
137        FileChannel tmpFileChannel = FileChannel.open(tmp, READ, WRITE);
138        ByteBuffer bb = ByteBuffer.allocate(BLOCK_SIZE);
139        while (bb.remaining() >= 4) {
140            bb.putInt(0xA8A8A8A8);
141        }
142        for (int i = 0; i < BLOCK_COUNT; ++i) {
143            bb.flip();
144            while (bb.hasRemaining()) {
145                tmpFileChannel.write(bb);
146            }
147        }
148        tmpFileChannel.force(true);
149        MappedByteBuffer mbb = tmpFileChannel.map(MapMode.READ_WRITE, 0, BLOCK_SIZE * BLOCK_COUNT);
150        Assert.assertEquals((byte) 0xA8, mbb.get());
151        mbb.position(mbb.position() + BLOCK_SIZE);
152        Assert.assertEquals((byte) 0xA8, mbb.get());
153        boolean truncated = false;
154        try {
155            tmpFileChannel.truncate(0);
156            tmpFileChannel.force(true);
157            truncated = true;
158        } catch (IOException e) {
159            // not all platforms support truncating memory-mapped files
160        }
161        Assume.assumeTrue(truncated);
162        try {
163            mbb.position(BLOCK_SIZE);
164            getter.get(mbb);
165            System.currentTimeMillis(); // materialize async exception
166        } catch (InternalError e) {
167            return;
168        }
169        Assert.fail("Expected exception");
170    }
171}