mirror of
https://github.com/darlinghq/darling-JavaScriptCore.git
synced 2025-04-07 09:21:41 +00:00
280 lines
9.2 KiB
C++
280 lines
9.2 KiB
C++
/*
|
|
* Copyright (C) 2016-2019 Apple Inc. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "B3FoldPathConstants.h"
|
|
|
|
#if ENABLE(B3_JIT)
|
|
|
|
#include "B3BasicBlockInlines.h"
|
|
#include "B3CaseCollectionInlines.h"
|
|
#include "B3Dominators.h"
|
|
#include "B3InsertionSet.h"
|
|
#include "B3PhaseScope.h"
|
|
#include "B3SwitchValue.h"
|
|
#include "B3ValueInlines.h"
|
|
|
|
namespace JSC { namespace B3 {
|
|
|
|
namespace {
|
|
|
|
namespace B3FoldPathConstantsInternal {
|
|
static constexpr bool verbose = false;
|
|
}
|
|
|
|
class FoldPathConstants {
|
|
public:
|
|
FoldPathConstants(Procedure& proc)
|
|
: m_proc(proc)
|
|
, m_insertionSet(proc)
|
|
{
|
|
}
|
|
|
|
void run()
|
|
{
|
|
bool changed = false;
|
|
|
|
if (B3FoldPathConstantsInternal::verbose)
|
|
dataLog("B3 before folding path constants: \n", m_proc, "\n");
|
|
|
|
// Find all of the values that are the subject of a branch or switch. For any successor
|
|
// that we dominate, install a value override at that block.
|
|
|
|
HashMap<Value*, Vector<Override>> overrides;
|
|
|
|
Dominators& dominators = m_proc.dominators();
|
|
|
|
auto addOverride = [&] (
|
|
BasicBlock* from, Value* value, const Override& override) {
|
|
|
|
if (override.block->numPredecessors() != 1)
|
|
return;
|
|
ASSERT(override.block->predecessor(0) == from);
|
|
|
|
Vector<Override>& forValue =
|
|
overrides.add(value, Vector<Override>()).iterator->value;
|
|
|
|
if (ASSERT_ENABLED) {
|
|
for (const Override& otherOverride : forValue)
|
|
ASSERT_UNUSED(otherOverride, otherOverride.block != override.block);
|
|
}
|
|
|
|
if (B3FoldPathConstantsInternal::verbose)
|
|
dataLog("Overriding ", *value, " from ", *from, ": ", override, "\n");
|
|
|
|
forValue.append(override);
|
|
};
|
|
|
|
for (BasicBlock* block : m_proc) {
|
|
Value* branch = block->last();
|
|
switch (branch->opcode()) {
|
|
case Branch:
|
|
if (block->successorBlock(0) == block->successorBlock(1))
|
|
continue;
|
|
addOverride(
|
|
block, branch->child(0),
|
|
Override::nonZero(block->successorBlock(0)));
|
|
addOverride(
|
|
block, branch->child(0),
|
|
Override::constant(block->successorBlock(1), 0));
|
|
break;
|
|
case Switch: {
|
|
SwitchValue* switchValue = branch->as<SwitchValue>();
|
|
|
|
HashMap<BasicBlock*, unsigned> targetUses;
|
|
for (SwitchCase switchCase : switchValue->cases(block))
|
|
targetUses.add(switchCase.targetBlock(), 0).iterator->value++;
|
|
targetUses.add(switchValue->fallThrough(block), 0).iterator->value++;
|
|
|
|
for (SwitchCase switchCase : switchValue->cases(block)) {
|
|
if (targetUses.find(switchCase.targetBlock())->value != 1)
|
|
continue;
|
|
|
|
addOverride(
|
|
block, branch->child(0),
|
|
Override::constant(switchCase.targetBlock(), switchCase.caseValue()));
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Install the constants in the override blocks. We use one-shot insertion sets because
|
|
// each block will get at most one thing inserted into it anyway.
|
|
for (auto& entry : overrides) {
|
|
for (Override& override : entry.value) {
|
|
if (!override.hasValue)
|
|
continue;
|
|
override.valueNode =
|
|
m_insertionSet.insertIntConstant(0, entry.key, override.value);
|
|
m_insertionSet.execute(override.block);
|
|
}
|
|
}
|
|
|
|
// Replace all uses of a value that has an override with that override, if appropriate.
|
|
// Certain instructions get special treatment.
|
|
auto getOverride = [&] (BasicBlock* block, Value* value) -> Override {
|
|
auto iter = overrides.find(value);
|
|
if (iter == overrides.end())
|
|
return Override();
|
|
|
|
Vector<Override>& forValue = iter->value;
|
|
Override result;
|
|
for (Override& override : forValue) {
|
|
if (dominators.dominates(override.block, block)
|
|
&& override.isBetterThan(result))
|
|
result = override;
|
|
}
|
|
|
|
if (B3FoldPathConstantsInternal::verbose)
|
|
dataLog("In block ", *block, " getting override for ", *value, ": ", result, "\n");
|
|
|
|
return result;
|
|
};
|
|
|
|
for (BasicBlock* block : m_proc) {
|
|
for (unsigned valueIndex = 0; valueIndex < block->size(); ++valueIndex) {
|
|
Value* value = block->at(valueIndex);
|
|
|
|
switch (value->opcode()) {
|
|
case Branch: {
|
|
if (getOverride(block, value->child(0)).isNonZero) {
|
|
value->replaceWithJump(block, block->taken());
|
|
changed = true;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case Equal: {
|
|
if (value->child(1)->isInt(0)
|
|
&& getOverride(block, value->child(0)).isNonZero) {
|
|
value->replaceWithIdentity(
|
|
m_insertionSet.insertIntConstant(valueIndex, value, 0));
|
|
}
|
|
break;
|
|
}
|
|
|
|
case NotEqual: {
|
|
if (value->child(1)->isInt(0)
|
|
&& getOverride(block, value->child(0)).isNonZero) {
|
|
value->replaceWithIdentity(
|
|
m_insertionSet.insertIntConstant(valueIndex, value, 1));
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
for (Value*& child : value->children()) {
|
|
Override override = getOverride(block, child);
|
|
if (override.valueNode)
|
|
child = override.valueNode;
|
|
}
|
|
}
|
|
m_insertionSet.execute(block);
|
|
}
|
|
|
|
if (changed) {
|
|
m_proc.resetReachability();
|
|
m_proc.invalidateCFG();
|
|
}
|
|
}
|
|
|
|
private:
|
|
struct Override {
|
|
Override()
|
|
{
|
|
}
|
|
|
|
static Override constant(BasicBlock* block, int64_t value)
|
|
{
|
|
Override result;
|
|
result.block = block;
|
|
result.hasValue = true;
|
|
result.value = value;
|
|
if (value)
|
|
result.isNonZero = true;
|
|
return result;
|
|
}
|
|
|
|
static Override nonZero(BasicBlock* block)
|
|
{
|
|
Override result;
|
|
result.block = block;
|
|
result.isNonZero = true;
|
|
return result;
|
|
}
|
|
|
|
bool isBetterThan(const Override& override)
|
|
{
|
|
if (hasValue && !override.hasValue)
|
|
return true;
|
|
if (isNonZero && !override.isNonZero)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
void dump(PrintStream& out) const
|
|
{
|
|
out.print("{block = ", pointerDump(block), ", value = ");
|
|
if (hasValue)
|
|
out.print(value);
|
|
else
|
|
out.print("<none>");
|
|
out.print(", isNonZero = ", isNonZero);
|
|
if (valueNode)
|
|
out.print(", valueNode = ", *valueNode);
|
|
out.print("}");
|
|
}
|
|
|
|
BasicBlock* block { nullptr };
|
|
bool hasValue { false };
|
|
bool isNonZero { false };
|
|
int64_t value { 0 };
|
|
Value* valueNode { nullptr };
|
|
};
|
|
|
|
Procedure& m_proc;
|
|
InsertionSet m_insertionSet;
|
|
};
|
|
|
|
} // anonymous namespace
|
|
|
|
void foldPathConstants(Procedure& proc)
|
|
{
|
|
PhaseScope phaseScope(proc, "foldPathConstants");
|
|
FoldPathConstants foldPathConstants(proc);
|
|
foldPathConstants.run();
|
|
}
|
|
|
|
} } // namespace JSC::B3
|
|
|
|
#endif // ENABLE(B3_JIT)
|
|
|