blob: fb75070cb17e06fbd4fa34eaf17c8d434743245f [file] [log] [blame]
/*
* 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);
}
}