001/*
002 * Copyright (c) 2012, 2014, 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.hotspot.stubs;
024
025import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
026import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*;
027import static com.oracle.graal.hotspot.stubs.NewInstanceStub.*;
028import static com.oracle.graal.hotspot.stubs.StubUtil.*;
029import static jdk.internal.jvmci.hotspot.HotSpotMetaAccessProvider.*;
030import jdk.internal.jvmci.code.*;
031import jdk.internal.jvmci.hotspot.*;
032import com.oracle.graal.api.replacements.*;
033import com.oracle.graal.compiler.common.spi.*;
034import com.oracle.graal.graph.Node.ConstantNodeParameter;
035import com.oracle.graal.graph.Node.NodeIntrinsic;
036import com.oracle.graal.hotspot.*;
037import com.oracle.graal.hotspot.meta.*;
038import com.oracle.graal.hotspot.nodes.*;
039import com.oracle.graal.hotspot.replacements.*;
040import com.oracle.graal.hotspot.word.*;
041import com.oracle.graal.nodes.*;
042import com.oracle.graal.replacements.*;
043import com.oracle.graal.replacements.Snippet.ConstantParameter;
044import com.oracle.graal.word.*;
045
046/**
047 * Stub implementing the fast path for TLAB refill during instance class allocation. This stub is
048 * called from the {@linkplain NewObjectSnippets inline} allocation code when TLAB allocation fails.
049 * If this stub fails to refill the TLAB or allocate the object, it calls out to the HotSpot C++
050 * runtime to complete the allocation.
051 */
052public class NewArrayStub extends SnippetStub {
053
054    public NewArrayStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
055        super("newArray", providers, linkage);
056    }
057
058    @Override
059    protected Object[] makeConstArgs() {
060        HotSpotResolvedObjectType intArrayType = (HotSpotResolvedObjectType) providers.getMetaAccess().lookupJavaType(int[].class);
061        int count = method.getSignature().getParameterCount(false);
062        Object[] args = new Object[count];
063        assert checkConstArg(2, "intArrayHub");
064        assert checkConstArg(3, "threadRegister");
065        args[2] = ConstantNode.forConstant(providers.getStampProvider().createHubStamp(true), intArrayType.klass(), null);
066        args[3] = providers.getRegisters().getThreadRegister();
067        return args;
068    }
069
070    @Fold
071    private static boolean logging() {
072        return Boolean.getBoolean("graal.logNewArrayStub");
073    }
074
075    /**
076     * Re-attempts allocation after an initial TLAB allocation failed or was skipped (e.g., due to
077     * -XX:-UseTLAB).
078     *
079     * @param hub the hub of the object to be allocated
080     * @param length the length of the array
081     * @param intArrayHub the hub for {@code int[].class}
082     */
083    @Snippet
084    private static Object newArray(KlassPointer hub, int length, @ConstantParameter KlassPointer intArrayHub, @ConstantParameter Register threadRegister) {
085        int layoutHelper = loadKlassLayoutHelperIntrinsic(hub);
086        int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask();
087        int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask();
088        int elementKind = (layoutHelper >> layoutHelperElementTypeShift()) & layoutHelperElementTypeMask();
089        int sizeInBytes = computeArrayAllocationSize(length, wordSize(), headerSize, log2ElementSize);
090        if (logging()) {
091            printf("newArray: element kind %d\n", elementKind);
092            printf("newArray: array length %d\n", length);
093            printf("newArray: array size %d\n", sizeInBytes);
094            printf("newArray: hub=%p\n", hub.asWord().rawValue());
095        }
096
097        // check that array length is small enough for fast path.
098        Word thread = registerAsWord(threadRegister);
099        if (length >= 0 && length <= MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH) {
100            Word memory = refillAllocate(thread, intArrayHub, sizeInBytes, logging());
101            if (memory.notEqual(0)) {
102                if (logging()) {
103                    printf("newArray: allocated new array at %p\n", memory.rawValue());
104                }
105                return verifyObject(formatArray(hub, sizeInBytes, length, headerSize, memory, Word.unsigned(arrayPrototypeMarkWord()), true, false, false));
106            }
107        }
108        if (logging()) {
109            printf("newArray: calling new_array_c\n");
110        }
111
112        newArrayC(NEW_ARRAY_C, thread, hub, length);
113        handlePendingException(thread, true);
114        return verifyObject(getAndClearObjectResult(thread));
115    }
116
117    public static final ForeignCallDescriptor NEW_ARRAY_C = newDescriptor(NewArrayStub.class, "newArrayC", void.class, Word.class, KlassPointer.class, int.class);
118
119    @NodeIntrinsic(StubForeignCallNode.class)
120    public static native void newArrayC(@ConstantNodeParameter ForeignCallDescriptor newArrayC, Word thread, KlassPointer hub, int length);
121}