v8/src/interpreter/bytecode-label.h
Leszek Swirski c7ebc5814f Reland "[ignition] Skip binding dead labels"
This is a reland of 35269f77f8

Switches on an expression that unconditionally throws would have all their
case statements dead, causing a DCHECK error in the SwitchBuilder. This
fixes up the DCHECK to allow dead labels.

Original change's description:
> [ignition] Skip binding dead labels
>
> BytecodeLabels for forward jumps may create a dead basic block if their
> corresponding jump was elided (due to it dead code elimination). We can
> avoid generating such dead basic blocks by skipping the label bind when
> no corresponding jump has been observed. This works because all jumps
> except JumpLoop are forward jumps, so we only have to special case one
> Bind for loop headers to bind unconditionally.
>
> Since Binds are now conditional on a jump existing, we can no longer rely
> on using Bind to get the current offset (e.g. at the beginning of a try
> block). Instead, we now expose the current offset in the bytecode array
> writer. Conveniently, this means that we can be a bit smarter about basic
> blocks around these statements.
>
> As a drive-by, remove the unused Bind(target,label) function.
>
> Bug: chromium:934166
> Change-Id: I532aa452fb083560d07b90da99caca0b1d082aa3
> Reviewed-on: https://chromium-review.googlesource.com/c/1488763
> Commit-Queue: Leszek Swirski <leszeks@chromium.org>
> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#59942}

TBR=rmcilroy@chromium.org

Bug: chromium:934166
Change-Id: If6eab4162106717ce64a2dc477000c6a76354cb4
Reviewed-on: https://chromium-review.googlesource.com/c/1494535
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59948}
2019-02-28 14:06:15 +00:00

115 lines
2.9 KiB
C++

// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_INTERPRETER_BYTECODE_LABEL_H_
#define V8_INTERPRETER_BYTECODE_LABEL_H_
#include <algorithm>
#include "src/zone/zone-containers.h"
namespace v8 {
namespace internal {
namespace interpreter {
class BytecodeArrayBuilder;
// A label representing a loop header in a bytecode array. It is bound before
// the jump is seen, so its position is always known by the time the jump is
// reached.
class V8_EXPORT_PRIVATE BytecodeLoopHeader final {
public:
BytecodeLoopHeader() : offset_(kInvalidOffset) {}
size_t offset() const {
DCHECK_NE(offset_, kInvalidOffset);
return offset_;
}
private:
static const size_t kInvalidOffset = static_cast<size_t>(-1);
void bind_to(size_t offset) {
DCHECK_NE(offset, kInvalidOffset);
DCHECK_EQ(offset_, kInvalidOffset);
offset_ = offset;
}
// The bytecode offset of the loop header.
size_t offset_;
friend class BytecodeArrayWriter;
};
// A label representing a forward branch target in a bytecode array. When a
// label is bound, it represents a known position in the bytecode array. A label
// can only have at most one referrer jump.
class V8_EXPORT_PRIVATE BytecodeLabel final {
public:
BytecodeLabel() : bound_(false), jump_offset_(kInvalidOffset) {}
bool is_bound() const { return bound_; }
size_t jump_offset() const {
DCHECK_NE(jump_offset_, kInvalidOffset);
return jump_offset_;
}
bool has_referrer_jump() const { return jump_offset_ != kInvalidOffset; }
private:
static const size_t kInvalidOffset = static_cast<size_t>(-1);
void bind() {
DCHECK(!bound_);
bound_ = true;
}
void set_referrer(size_t offset) {
DCHECK(!bound_);
DCHECK_NE(offset, kInvalidOffset);
DCHECK_EQ(jump_offset_, kInvalidOffset);
jump_offset_ = offset;
}
// Set when the label is bound (i.e. the start of the target basic block).
bool bound_;
// Set when the jump referrer is set (i.e. the location of the jump).
size_t jump_offset_;
friend class BytecodeArrayWriter;
};
// Class representing a branch target of multiple jumps.
class V8_EXPORT_PRIVATE BytecodeLabels {
public:
explicit BytecodeLabels(Zone* zone) : labels_(zone), is_bound_(false) {}
BytecodeLabel* New();
void Bind(BytecodeArrayBuilder* builder);
bool is_bound() const {
DCHECK_IMPLIES(
is_bound_,
std::all_of(labels_.begin(), labels_.end(), [](const BytecodeLabel& l) {
return !l.has_referrer_jump() || l.is_bound();
}));
return is_bound_;
}
bool empty() const { return labels_.empty(); }
private:
ZoneLinkedList<BytecodeLabel> labels_;
bool is_bound_;
DISALLOW_COPY_AND_ASSIGN(BytecodeLabels);
};
} // namespace interpreter
} // namespace internal
} // namespace v8
#endif // V8_INTERPRETER_BYTECODE_LABEL_H_