Source code for apkutils.dex.jvm.optimization.consts

# Copyright 2015 Google Inc. All Rights Reserved.
#
# 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.

import collections

from .. import scalartypes as scalars
from .. import ir

[docs]def allocateRequiredConstants(pool, long_irs): # see comments in writebytecode.finishCodeAttrs # We allocate the constants pretty much greedily. This is far from optimal, # but it shouldn't be a big deal since this code is almost never required # in the first place. In fact, there are no known real world classes that # even come close to exhausting the constant pool. narrow_pairs = collections.Counter() wide_pairs = collections.Counter() alt_lens = {} for _ir in long_irs: for ins in _ir.flat_instructions: if isinstance(ins, ir.PrimConstant): key = ins.cpool_key() alt_lens[key] = len(ins.bytecode) if scalars.iswide(ins.st): if len(ins.bytecode) > 3: wide_pairs[key] += 1 else: if len(ins.bytecode) > 2: narrow_pairs[key] += 1 # see if already in the constant pool for x in pool.vals: del narrow_pairs[x] del wide_pairs[x] # if we have enough space for all required constants, preferentially allocate # most commonly used constants to first 255 slots if pool.space() >= len(narrow_pairs) + 2*len(wide_pairs) and pool.lowspace() > 0: # We can't use Counter.most_common here because it is nondeterminstic in # the case of ties. most_common = sorted(narrow_pairs, key=lambda p:(-narrow_pairs[p], p)) for key in most_common[:pool.lowspace()]: pool.insertDirectly(key, True) del narrow_pairs[key] scores = {} for p, count in narrow_pairs.items(): scores[p] = (alt_lens[p] - 3) * count for p, count in wide_pairs.items(): scores[p] = (alt_lens[p] - 3) * count # sort by score narrowq = sorted(narrow_pairs, key=lambda p:(scores[p], p)) wideq = sorted(wide_pairs, key=lambda p:(scores[p], p)) while pool.space() >= 1 and (narrowq or wideq): if not narrowq and pool.space() < 2: break wscore = sum(scores[p] for p in wideq[-1:]) nscore = sum(scores[p] for p in narrowq[-2:]) if pool.space() >= 2 and wscore > nscore and wscore > 0: pool.insertDirectly(wideq.pop(), False) elif nscore > 0: pool.insertDirectly(narrowq.pop(), True) else: break