| /* |
| * Copyright 2013 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package com.google.gwt.dev.jjs.impl.codesplitter; |
| |
| import com.google.gwt.dev.jjs.ast.JRunAsync; |
| import com.google.gwt.thirdparty.guava.common.base.Preconditions; |
| |
| import java.util.Collection; |
| |
| /** |
| * A read-only class that holds some information about the result of the |
| * partition process. |
| */ |
| public class FragmentPartitioningResult { |
| private final int[] runAsyncIdToFragment; |
| private final int fragmentCount; |
| private final int lastInitialFragmentId; |
| |
| FragmentPartitioningResult(Collection<Fragment> fragments, int runAsyncCount) { |
| checkFragmentNumberingAssumptions(fragments); |
| |
| fragmentCount = fragments.size(); |
| // runAsync ids start from 1. |
| this.runAsyncIdToFragment = new int[runAsyncCount + 1]; |
| int lastInitialFragmentIdSoFar = -1; |
| for (Fragment fragment : fragments) { |
| // Fragments are assumed ordered by increasing ids. |
| if (fragment.getType() == Fragment.Type.INITIAL) { |
| Preconditions.checkState(lastInitialFragmentIdSoFar < fragment.getFragmentId()); |
| lastInitialFragmentIdSoFar = fragment.getFragmentId(); |
| } |
| for (JRunAsync runAsync : fragment.getRunAsyncs()) { |
| runAsyncIdToFragment[runAsync.getRunAsyncId()] = fragment.getFragmentId(); |
| } |
| } |
| this.lastInitialFragmentId = lastInitialFragmentIdSoFar; |
| } |
| |
| /** |
| * @return the fragmentId for a fragment that is guaranteed to be loaded before |
| * thisFragmentId and thatFragmentId |
| */ |
| public int getCommonAncestorFragmentId(int thisFragmentId, int thatFragmentId) { |
| if (thisFragmentId == thatFragmentId) { |
| return thisFragmentId; |
| } |
| |
| // If none of the fragments is initial, move to leftovers |
| if (thisFragmentId > lastInitialFragmentId && thatFragmentId > lastInitialFragmentId) { |
| return getLeftoverFragmentId(); |
| } |
| // Return the one that occurs first in the initial load sequence. |
| return Math.min(thisFragmentId, thatFragmentId); |
| } |
| |
| /** |
| * @return Fragment index from a splitpoint number. |
| */ |
| public int getFragmentForRunAsync(int splitpoint) { |
| return runAsyncIdToFragment[splitpoint]; |
| } |
| |
| /** |
| * @return Fragment number of the left over fragment. |
| */ |
| public int getLeftoverFragmentId() { |
| return getFragmentCount() - 1; |
| } |
| |
| /** |
| * @return Total number of code fragments in the compilation (initial + exclusives + leftovers). |
| */ |
| public int getFragmentCount() { |
| return fragmentCount; |
| } |
| |
| private void checkFragmentNumberingAssumptions(Collection<Fragment> fragments) { |
| int lastSeenId = -1; |
| Fragment.Type lastTypeSeen = Fragment.Type.INITIAL; |
| boolean leftoversFragmentSeen = false; |
| int leftoversFragmentId = -1; |
| for (Fragment fragment : fragments) { |
| // Fragments appear in the fragment list in ascending id order. first one being 0. |
| Preconditions.checkState(fragment.getFragmentId() == lastSeenId + 1); |
| lastSeenId = fragment.getFragmentId(); |
| |
| // Fragments appear in the following order, first INTIALs, then EXCLUSIVEs and last 1 |
| // NOT_EXCLUSIVE (leftovers fragment). |
| Preconditions.checkState(fragment.getType().ordinal() >= lastTypeSeen.ordinal()); |
| lastTypeSeen = fragment.getType(); |
| |
| if (fragment.getType() == Fragment.Type.NOT_EXCLUSIVE) { |
| Preconditions.checkState(!leftoversFragmentSeen); |
| leftoversFragmentSeen = true; |
| leftoversFragmentId = fragment.getFragmentId(); |
| } |
| } |
| // Lastly check that the left over is the last one if any. |
| Preconditions.checkState(leftoversFragmentId == -1 || leftoversFragmentId == lastSeenId); |
| } |
| } |