[stubs] Introduce a proper ToBooleanStub.

Rename the existing (patching) ToBooleanStub to ToBooleanICStub to match
our naming convention, and add a new TurboFan-powered ToBooleanStub,
which just does the ToBoolean conversion without any runtime call or
code patching, so we can use it for Ignition (and TurboFan).

Drive-by-fix: Add an Oddball::to_boolean field similar to the ones we
already have for to_string and to_number, so we don't need to actually
dispatch on the concrete Oddball at all.

R=epertoso@chromium.org, rmcilroy@chromium.org, yangguo@chromium.org

Review URL: https://codereview.chromium.org/1744163002

Cr-Commit-Position: refs/heads/master@{#34361}
This commit is contained in:
bmeurer 2016-02-29 04:16:00 -08:00 committed by Commit bot
parent 4d659edfcd
commit d1df58e8d7
55 changed files with 476 additions and 364 deletions

View File

@ -7164,7 +7164,7 @@ class Internals {
1 * kApiPointerSize + kApiIntSize;
static const int kStringResourceOffset = 3 * kApiPointerSize;
static const int kOddballKindOffset = 4 * kApiPointerSize;
static const int kOddballKindOffset = 5 * kApiPointerSize;
static const int kForeignAddressOffset = kApiPointerSize;
static const int kJSObjectHeaderSize = 3 * kApiPointerSize;
static const int kFixedArrayHeaderSize = 2 * kApiPointerSize;

View File

@ -134,8 +134,8 @@ Callable CodeFactory::InstanceOf(Isolate* isolate) {
// static
Callable CodeFactory::ToBoolean(Isolate* isolate) {
Handle<Code> code = ToBooleanStub::GetUninitialized(isolate);
return Callable(code, ToBooleanDescriptor(isolate));
ToBooleanStub stub(isolate);
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
}

View File

@ -1681,10 +1681,9 @@ Handle<Code> StringAddStub::GenerateCode() {
return DoGenerateCode(this);
}
template <>
HValue* CodeStubGraphBuilder<ToBooleanStub>::BuildCodeInitializedStub() {
ToBooleanStub* stub = casted_stub();
HValue* CodeStubGraphBuilder<ToBooleanICStub>::BuildCodeInitializedStub() {
ToBooleanICStub* stub = casted_stub();
IfBuilder if_true(this);
if_true.If<HBranch>(GetParameter(0), stub->types());
if_true.Then();
@ -1694,11 +1693,7 @@ HValue* CodeStubGraphBuilder<ToBooleanStub>::BuildCodeInitializedStub() {
return graph()->GetConstantFalse();
}
Handle<Code> ToBooleanStub::GenerateCode() {
return DoGenerateCode(this);
}
Handle<Code> ToBooleanICStub::GenerateCode() { return DoGenerateCode(this); }
template <>
HValue* CodeStubGraphBuilder<StoreGlobalStub>::BuildCodeInitializedStub() {

View File

@ -473,6 +473,144 @@ void StringLengthStub::GenerateAssembly(
assembler->Return(result);
}
void ToBooleanStub::GenerateAssembly(
compiler::CodeStubAssembler* assembler) const {
typedef compiler::Node Node;
typedef compiler::CodeStubAssembler::Label Label;
Node* value = assembler->Parameter(0);
Label if_valueissmi(assembler), if_valueisnotsmi(assembler);
// Check if {value} is a Smi or a HeapObject.
assembler->Branch(assembler->WordIsSmi(value), &if_valueissmi,
&if_valueisnotsmi);
assembler->Bind(&if_valueissmi);
{
// The {value} is a Smi, only need to check against zero.
Label if_valueiszero(assembler), if_valueisnotzero(assembler);
assembler->Branch(assembler->SmiEqual(value, assembler->SmiConstant(0)),
&if_valueiszero, &if_valueisnotzero);
assembler->Bind(&if_valueiszero);
assembler->Return(assembler->BooleanConstant(false));
assembler->Bind(&if_valueisnotzero);
assembler->Return(assembler->BooleanConstant(true));
}
assembler->Bind(&if_valueisnotsmi);
{
Label if_valueisstring(assembler), if_valueisheapnumber(assembler),
if_valueisoddball(assembler), if_valueisother(assembler);
// The {value} is a HeapObject, load its map.
Node* value_map = assembler->LoadObjectField(value, HeapObject::kMapOffset);
// Load the {value}s instance type.
Node* value_instancetype = assembler->Load(
MachineType::Uint8(), value_map,
assembler->IntPtrConstant(Map::kInstanceTypeOffset - kHeapObjectTag));
// Dispatch based on the instance type; we distinguish all String instance
// types, the HeapNumber type and the Oddball type.
size_t const kNumCases = FIRST_NONSTRING_TYPE + 2;
Label* case_labels[kNumCases];
int32_t case_values[kNumCases];
for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) {
case_labels[i] = new Label(assembler);
case_values[i] = i;
}
case_labels[FIRST_NONSTRING_TYPE + 0] = &if_valueisheapnumber;
case_values[FIRST_NONSTRING_TYPE + 0] = HEAP_NUMBER_TYPE;
case_labels[FIRST_NONSTRING_TYPE + 1] = &if_valueisoddball;
case_values[FIRST_NONSTRING_TYPE + 1] = ODDBALL_TYPE;
assembler->Switch(value_instancetype, &if_valueisother, case_values,
case_labels, arraysize(case_values));
for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) {
assembler->Bind(case_labels[i]);
assembler->Goto(&if_valueisstring);
delete case_labels[i];
}
assembler->Bind(&if_valueisstring);
{
// Load the string length field of the {value}.
Node* value_length =
assembler->LoadObjectField(value, String::kLengthOffset);
// Check if the {value} is the empty string.
Label if_valueisempty(assembler), if_valueisnotempty(assembler);
assembler->Branch(
assembler->SmiEqual(value_length, assembler->SmiConstant(0)),
&if_valueisempty, &if_valueisnotempty);
assembler->Bind(&if_valueisempty);
assembler->Return(assembler->BooleanConstant(false));
assembler->Bind(&if_valueisnotempty);
assembler->Return(assembler->BooleanConstant(true));
}
assembler->Bind(&if_valueisheapnumber);
{
Node* value_value = assembler->Load(
MachineType::Float64(), value,
assembler->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag));
Label if_valueispositive(assembler), if_valueisnotpositive(assembler),
if_valueisnegative(assembler), if_valueisnanorzero(assembler);
assembler->Branch(assembler->Float64LessThan(
assembler->Float64Constant(0.0), value_value),
&if_valueispositive, &if_valueisnotpositive);
assembler->Bind(&if_valueispositive);
assembler->Return(assembler->BooleanConstant(true));
assembler->Bind(&if_valueisnotpositive);
assembler->Branch(assembler->Float64LessThan(
value_value, assembler->Float64Constant(0.0)),
&if_valueisnegative, &if_valueisnanorzero);
assembler->Bind(&if_valueisnegative);
assembler->Return(assembler->BooleanConstant(true));
assembler->Bind(&if_valueisnanorzero);
assembler->Return(assembler->BooleanConstant(false));
}
assembler->Bind(&if_valueisoddball);
{
// The {value} is an Oddball, and every Oddball knows its boolean value.
Node* value_toboolean =
assembler->LoadObjectField(value, Oddball::kToBooleanOffset);
assembler->Return(value_toboolean);
}
assembler->Bind(&if_valueisother);
{
Node* value_map_bitfield = assembler->Load(
MachineType::Uint8(), value_map,
assembler->IntPtrConstant(Map::kBitFieldOffset - kHeapObjectTag));
Node* value_map_undetectable = assembler->Word32And(
value_map_bitfield,
assembler->Int32Constant(1 << Map::kIsUndetectable));
// Check if the {value} is undetectable.
Label if_valueisundetectable(assembler),
if_valueisnotundetectable(assembler);
assembler->Branch(assembler->Word32Equal(value_map_undetectable,
assembler->Int32Constant(0)),
&if_valueisnotundetectable, &if_valueisundetectable);
assembler->Bind(&if_valueisundetectable);
assembler->Return(assembler->BooleanConstant(false));
assembler->Bind(&if_valueisnotundetectable);
assembler->Return(assembler->BooleanConstant(true));
}
}
}
template<class StateType>
void HydrogenCodeStub::TraceTransition(StateType from, StateType to) {
@ -667,8 +805,7 @@ void AllocateInNewSpaceStub::InitializeDescriptor(
descriptor->Initialize();
}
void ToBooleanStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
void ToBooleanICStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
descriptor->Initialize(FUNCTION_ADDR(Runtime_ToBooleanIC_Miss));
descriptor->SetMissHandler(ExternalReference(
Runtime::FunctionForId(Runtime::kToBooleanIC_Miss), isolate()));
@ -770,8 +907,7 @@ std::ostream& ArrayConstructorStubBase::BasePrintName(
return os;
}
bool ToBooleanStub::UpdateStatus(Handle<Object> object) {
bool ToBooleanICStub::UpdateStatus(Handle<Object> object) {
Types new_types = types();
Types old_types = new_types;
bool to_boolean_value = new_types.UpdateStatus(object);
@ -780,30 +916,27 @@ bool ToBooleanStub::UpdateStatus(Handle<Object> object) {
return to_boolean_value;
}
void ToBooleanStub::PrintState(std::ostream& os) const { // NOLINT
void ToBooleanICStub::PrintState(std::ostream& os) const { // NOLINT
os << types();
}
std::ostream& operator<<(std::ostream& os, const ToBooleanStub::Types& s) {
std::ostream& operator<<(std::ostream& os, const ToBooleanICStub::Types& s) {
os << "(";
SimpleListPrinter p(os);
if (s.IsEmpty()) p.Add("None");
if (s.Contains(ToBooleanStub::UNDEFINED)) p.Add("Undefined");
if (s.Contains(ToBooleanStub::BOOLEAN)) p.Add("Bool");
if (s.Contains(ToBooleanStub::NULL_TYPE)) p.Add("Null");
if (s.Contains(ToBooleanStub::SMI)) p.Add("Smi");
if (s.Contains(ToBooleanStub::SPEC_OBJECT)) p.Add("SpecObject");
if (s.Contains(ToBooleanStub::STRING)) p.Add("String");
if (s.Contains(ToBooleanStub::SYMBOL)) p.Add("Symbol");
if (s.Contains(ToBooleanStub::HEAP_NUMBER)) p.Add("HeapNumber");
if (s.Contains(ToBooleanStub::SIMD_VALUE)) p.Add("SimdValue");
if (s.Contains(ToBooleanICStub::UNDEFINED)) p.Add("Undefined");
if (s.Contains(ToBooleanICStub::BOOLEAN)) p.Add("Bool");
if (s.Contains(ToBooleanICStub::NULL_TYPE)) p.Add("Null");
if (s.Contains(ToBooleanICStub::SMI)) p.Add("Smi");
if (s.Contains(ToBooleanICStub::SPEC_OBJECT)) p.Add("SpecObject");
if (s.Contains(ToBooleanICStub::STRING)) p.Add("String");
if (s.Contains(ToBooleanICStub::SYMBOL)) p.Add("Symbol");
if (s.Contains(ToBooleanICStub::HEAP_NUMBER)) p.Add("HeapNumber");
if (s.Contains(ToBooleanICStub::SIMD_VALUE)) p.Add("SimdValue");
return os << ")";
}
bool ToBooleanStub::Types::UpdateStatus(Handle<Object> object) {
bool ToBooleanICStub::Types::UpdateStatus(Handle<Object> object) {
if (object->IsUndefined()) {
Add(UNDEFINED);
return false;
@ -841,12 +974,12 @@ bool ToBooleanStub::Types::UpdateStatus(Handle<Object> object) {
}
}
bool ToBooleanStub::Types::NeedsMap() const {
return Contains(ToBooleanStub::SPEC_OBJECT) ||
Contains(ToBooleanStub::STRING) || Contains(ToBooleanStub::SYMBOL) ||
Contains(ToBooleanStub::HEAP_NUMBER) ||
Contains(ToBooleanStub::SIMD_VALUE);
bool ToBooleanICStub::Types::NeedsMap() const {
return Contains(ToBooleanICStub::SPEC_OBJECT) ||
Contains(ToBooleanICStub::STRING) ||
Contains(ToBooleanICStub::SYMBOL) ||
Contains(ToBooleanICStub::HEAP_NUMBER) ||
Contains(ToBooleanICStub::SIMD_VALUE);
}

View File

@ -95,12 +95,13 @@ namespace internal {
V(StoreGlobalViaContext) \
V(StoreScriptContextField) \
V(StringAdd) \
V(ToBoolean) \
V(ToBooleanIC) \
V(TransitionElementsKind) \
V(KeyedLoadIC) \
V(LoadIC) \
/* TurboFanCodeStubs */ \
V(StringLength) \
V(ToBoolean) \
/* IC Handler stubs */ \
V(ArrayBufferViewLoadField) \
V(LoadConstant) \
@ -630,6 +631,15 @@ class StringLengthStub : public TurboFanCodeStub {
DEFINE_CODE_STUB(StringLength, TurboFanCodeStub);
};
class ToBooleanStub final : public TurboFanCodeStub {
public:
explicit ToBooleanStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
void GenerateAssembly(compiler::CodeStubAssembler* assembler) const final;
DEFINE_CALL_INTERFACE_DESCRIPTOR(ToBoolean);
DEFINE_CODE_STUB(ToBoolean, TurboFanCodeStub);
};
enum StringAddFlags {
// Omit both parameter checks.
@ -2636,8 +2646,7 @@ class StoreElementStub : public PlatformCodeStub {
DEFINE_PLATFORM_CODE_STUB(StoreElement, PlatformCodeStub);
};
class ToBooleanStub: public HydrogenCodeStub {
class ToBooleanICStub : public HydrogenCodeStub {
public:
enum Type {
UNDEFINED,
@ -2664,14 +2673,14 @@ class ToBooleanStub: public HydrogenCodeStub {
bool UpdateStatus(Handle<Object> object);
bool NeedsMap() const;
bool CanBeUndetectable() const {
return Contains(ToBooleanStub::SPEC_OBJECT);
return Contains(ToBooleanICStub::SPEC_OBJECT);
}
bool IsGeneric() const { return ToIntegral() == Generic().ToIntegral(); }
static Types Generic() { return Types((1 << NUMBER_OF_TYPES) - 1); }
};
ToBooleanStub(Isolate* isolate, ExtraICState state)
ToBooleanICStub(Isolate* isolate, ExtraICState state)
: HydrogenCodeStub(isolate) {
set_sub_minor_key(TypesBits::encode(static_cast<uint16_t>(state)));
}
@ -2685,7 +2694,7 @@ class ToBooleanStub: public HydrogenCodeStub {
bool SometimesSetsUpAFrame() override { return false; }
static Handle<Code> GetUninitialized(Isolate* isolate) {
return ToBooleanStub(isolate, UNINITIALIZED).GetCode();
return ToBooleanICStub(isolate, UNINITIALIZED).GetCode();
}
ExtraICState GetExtraICState() const override { return types().ToIntegral(); }
@ -2699,19 +2708,16 @@ class ToBooleanStub: public HydrogenCodeStub {
}
private:
ToBooleanStub(Isolate* isolate, InitializationState init_state)
: HydrogenCodeStub(isolate, init_state) {
}
ToBooleanICStub(Isolate* isolate, InitializationState init_state)
: HydrogenCodeStub(isolate, init_state) {}
class TypesBits : public BitField<uint16_t, 0, NUMBER_OF_TYPES> {};
DEFINE_CALL_INTERFACE_DESCRIPTOR(ToBoolean);
DEFINE_HYDROGEN_CODE_STUB(ToBoolean, HydrogenCodeStub);
DEFINE_HYDROGEN_CODE_STUB(ToBooleanIC, HydrogenCodeStub);
};
std::ostream& operator<<(std::ostream& os, const ToBooleanStub::Types& t);
std::ostream& operator<<(std::ostream& os, const ToBooleanICStub::Types& t);
class ElementsTransitionAndStoreStub : public HydrogenCodeStub {
public:

View File

@ -89,6 +89,10 @@ Node* CodeStubAssembler::ExternalConstant(ExternalReference address) {
return raw_assembler_->ExternalConstant(address);
}
Node* CodeStubAssembler::Float64Constant(double value) {
return raw_assembler_->Float64Constant(value);
}
Node* CodeStubAssembler::Parameter(int value) {
return raw_assembler_->Parameter(value);
}
@ -130,6 +134,8 @@ Node* CodeStubAssembler::SmiUntag(Node* value) {
Node* CodeStubAssembler::SmiAdd(Node* a, Node* b) { return IntPtrAdd(a, b); }
Node* CodeStubAssembler::SmiEqual(Node* a, Node* b) { return WordEqual(a, b); }
#define DEFINE_CODE_STUB_ASSEMBER_BINARY_OP(name) \
Node* CodeStubAssembler::name(Node* a, Node* b) { \
return raw_assembler_->name(a, b); \

View File

@ -34,6 +34,9 @@ class RawMachineLabel;
class Schedule;
#define CODE_STUB_ASSEMBLER_BINARY_OP_LIST(V) \
V(Float64Equal) \
V(Float64LessThan) \
V(Float64LessThanOrEqual) \
V(IntPtrAdd) \
V(IntPtrSub) \
V(Int32Add) \
@ -107,6 +110,7 @@ class CodeStubAssembler {
Node* HeapConstant(Handle<HeapObject> object);
Node* BooleanConstant(bool value);
Node* ExternalConstant(ExternalReference address);
Node* Float64Constant(double value);
Node* Parameter(int value);
void Return(Node* value);
@ -197,7 +201,8 @@ class CodeStubAssembler {
Node* SmiUntag(Node* value);
// Smi operations.
Node* SmiAdd(Node* lhs, Node* rhs);
Node* SmiAdd(Node* a, Node* b);
Node* SmiEqual(Node* a, Node* b);
// Load a value from the root array.
Node* LoadRoot(Heap::RootListIndex root_index);

View File

@ -139,8 +139,7 @@ void JSGenericLowering::LowerJSTypeOf(Node* node) {
void JSGenericLowering::LowerJSToBoolean(Node* node) {
CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
Callable callable = CodeFactory::ToBoolean(isolate());
ReplaceWithStubCall(node, callable,
CallDescriptor::kPatchableCallSite | flags);
ReplaceWithStubCall(node, callable, flags);
}

View File

@ -400,7 +400,8 @@ CallDescriptor* Linkage::GetStubCallDescriptor(
properties, // properties
kNoCalleeSaved, // callee-saved registers
kNoCalleeSaved, // callee-saved fp
flags, // flags
CallDescriptor::kCanUseRoots | // flags
flags, // flags
descriptor.DebugName(isolate));
}

View File

@ -1214,23 +1214,27 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
MipsOperandGenerator g(this);
InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
// Emit either ArchTableSwitch or ArchLookupSwitch.
size_t table_space_cost = 9 + sw.value_range;
size_t table_time_cost = 3;
size_t lookup_space_cost = 2 + 2 * sw.case_count;
size_t lookup_time_cost = sw.case_count;
if (sw.case_count > 0 &&
table_space_cost + 3 * table_time_cost <=
lookup_space_cost + 3 * lookup_time_cost &&
sw.min_value > std::numeric_limits<int32_t>::min()) {
InstructionOperand index_operand = value_operand;
if (sw.min_value) {
index_operand = g.TempRegister();
Emit(kMipsSub, index_operand, value_operand,
g.TempImmediate(sw.min_value));
// TODO(mips): TableSwitch is broken, as it messes with ra without saving it
// properly (which breaks with frame elision, i.e. inside stubs).
if (false) {
// Emit either ArchTableSwitch or ArchLookupSwitch.
size_t table_space_cost = 9 + sw.value_range;
size_t table_time_cost = 3;
size_t lookup_space_cost = 2 + 2 * sw.case_count;
size_t lookup_time_cost = sw.case_count;
if (sw.case_count > 0 &&
table_space_cost + 3 * table_time_cost <=
lookup_space_cost + 3 * lookup_time_cost &&
sw.min_value > std::numeric_limits<int32_t>::min()) {
InstructionOperand index_operand = value_operand;
if (sw.min_value) {
index_operand = g.TempRegister();
Emit(kMipsSub, index_operand, value_operand,
g.TempImmediate(sw.min_value));
}
// Generate a table lookup.
return EmitTableSwitch(sw, index_operand);
}
// Generate a table lookup.
return EmitTableSwitch(sw, index_operand);
}
// Generate a sequence of conditional jumps.

View File

@ -1711,23 +1711,27 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
Mips64OperandGenerator g(this);
InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
// Emit either ArchTableSwitch or ArchLookupSwitch.
size_t table_space_cost = 10 + 2 * sw.value_range;
size_t table_time_cost = 3;
size_t lookup_space_cost = 2 + 2 * sw.case_count;
size_t lookup_time_cost = sw.case_count;
if (sw.case_count > 0 &&
table_space_cost + 3 * table_time_cost <=
lookup_space_cost + 3 * lookup_time_cost &&
sw.min_value > std::numeric_limits<int32_t>::min()) {
InstructionOperand index_operand = value_operand;
if (sw.min_value) {
index_operand = g.TempRegister();
Emit(kMips64Sub, index_operand, value_operand,
g.TempImmediate(sw.min_value));
// TODO(mips): TableSwitch is broken, as it messes with ra without saving it
// properly (which breaks with frame elision, i.e. inside stubs).
if (false) {
// Emit either ArchTableSwitch or ArchLookupSwitch.
size_t table_space_cost = 10 + 2 * sw.value_range;
size_t table_time_cost = 3;
size_t lookup_space_cost = 2 + 2 * sw.case_count;
size_t lookup_time_cost = sw.case_count;
if (sw.case_count > 0 &&
table_space_cost + 3 * table_time_cost <=
lookup_space_cost + 3 * lookup_time_cost &&
sw.min_value > std::numeric_limits<int32_t>::min()) {
InstructionOperand index_operand = value_operand;
if (sw.min_value) {
index_operand = g.TempRegister();
Emit(kMips64Sub, index_operand, value_operand,
g.TempImmediate(sw.min_value));
}
// Generate a table lookup.
return EmitTableSwitch(sw, index_operand);
}
// Generate a table lookup.
return EmitTableSwitch(sw, index_operand);
}
// Generate a sequence of conditional jumps.

View File

@ -48,10 +48,10 @@ bool TypeHintAnalysis::GetToBooleanHints(TypeFeedbackId id,
if (i == infos_.end()) return false;
Handle<Code> code = i->second;
DCHECK_EQ(Code::TO_BOOLEAN_IC, code->kind());
ToBooleanStub stub(code->GetIsolate(), code->extra_ic_state());
// TODO(bmeurer): Replace ToBooleanStub::Types with ToBooleanHints.
#define ASSERT_COMPATIBLE(NAME, Name) \
STATIC_ASSERT(1 << ToBooleanStub::NAME == \
ToBooleanICStub stub(code->GetIsolate(), code->extra_ic_state());
// TODO(bmeurer): Replace ToBooleanICStub::Types with ToBooleanHints.
#define ASSERT_COMPATIBLE(NAME, Name) \
STATIC_ASSERT(1 << ToBooleanICStub::NAME == \
static_cast<int>(ToBooleanHint::k##Name))
ASSERT_COMPATIBLE(UNDEFINED, Undefined);
ASSERT_COMPATIBLE(BOOLEAN, Boolean);

View File

@ -904,14 +904,14 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
HValue* value = instr->value();
Representation r = value->representation();
HType type = value->type();
ToBooleanStub::Types expected = instr->expected_input_types();
if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
ToBooleanICStub::Types expected = instr->expected_input_types();
if (expected.IsEmpty()) expected = ToBooleanICStub::Types::Generic();
bool easy_case = !r.IsTagged() || type.IsBoolean() || type.IsSmi() ||
type.IsJSArray() || type.IsHeapNumber() || type.IsString();
LInstruction* branch = new(zone()) LBranch(UseRegister(value));
if (!easy_case &&
((!expected.Contains(ToBooleanStub::SMI) && expected.NeedsMap()) ||
((!expected.Contains(ToBooleanICStub::SMI) && expected.NeedsMap()) ||
!expected.IsGeneric())) {
branch = AssignEnvironment(branch);
}

View File

@ -2070,29 +2070,30 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ cmp(ip, Operand::Zero());
EmitBranch(instr, ne);
} else {
ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
ToBooleanICStub::Types expected =
instr->hydrogen()->expected_input_types();
// Avoid deopts in the case where we've never executed this path before.
if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
if (expected.IsEmpty()) expected = ToBooleanICStub::Types::Generic();
if (expected.Contains(ToBooleanStub::UNDEFINED)) {
if (expected.Contains(ToBooleanICStub::UNDEFINED)) {
// undefined -> false.
__ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
__ b(eq, instr->FalseLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::BOOLEAN)) {
if (expected.Contains(ToBooleanICStub::BOOLEAN)) {
// Boolean -> its value.
__ CompareRoot(reg, Heap::kTrueValueRootIndex);
__ b(eq, instr->TrueLabel(chunk_));
__ CompareRoot(reg, Heap::kFalseValueRootIndex);
__ b(eq, instr->FalseLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
if (expected.Contains(ToBooleanICStub::NULL_TYPE)) {
// 'null' -> false.
__ CompareRoot(reg, Heap::kNullValueRootIndex);
__ b(eq, instr->FalseLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::SMI)) {
if (expected.Contains(ToBooleanICStub::SMI)) {
// Smis: 0 -> false, all other -> true.
__ cmp(reg, Operand::Zero());
__ b(eq, instr->FalseLabel(chunk_));
@ -2115,13 +2116,13 @@ void LCodeGen::DoBranch(LBranch* instr) {
}
}
if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
if (expected.Contains(ToBooleanICStub::SPEC_OBJECT)) {
// spec object -> true.
__ CompareInstanceType(map, ip, FIRST_JS_RECEIVER_TYPE);
__ b(ge, instr->TrueLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::STRING)) {
if (expected.Contains(ToBooleanICStub::STRING)) {
// String value -> false iff empty.
Label not_string;
__ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
@ -2133,19 +2134,19 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ bind(&not_string);
}
if (expected.Contains(ToBooleanStub::SYMBOL)) {
if (expected.Contains(ToBooleanICStub::SYMBOL)) {
// Symbol value -> true.
__ CompareInstanceType(map, ip, SYMBOL_TYPE);
__ b(eq, instr->TrueLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::SIMD_VALUE)) {
if (expected.Contains(ToBooleanICStub::SIMD_VALUE)) {
// SIMD value -> true.
__ CompareInstanceType(map, ip, SIMD128_VALUE_TYPE);
__ b(eq, instr->TrueLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
if (expected.Contains(ToBooleanICStub::HEAP_NUMBER)) {
// heap number -> false iff +0, -0, or NaN.
DwVfpRegister dbl_scratch = double_scratch0();
Label not_heap_number;

View File

@ -972,7 +972,7 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
return new(zone()) LBranch(UseRegister(value), TempRegister(), NULL);
}
ToBooleanStub::Types expected = instr->expected_input_types();
ToBooleanICStub::Types expected = instr->expected_input_types();
bool needs_temps = expected.NeedsMap() || expected.IsEmpty();
LOperand* temp1 = needs_temps ? TempRegister() : NULL;
LOperand* temp2 = needs_temps ? TempRegister() : NULL;

View File

@ -1731,17 +1731,18 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ Ldr(temp, FieldMemOperand(value, String::kLengthOffset));
EmitCompareAndBranch(instr, ne, temp, 0);
} else {
ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
ToBooleanICStub::Types expected =
instr->hydrogen()->expected_input_types();
// Avoid deopts in the case where we've never executed this path before.
if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
if (expected.IsEmpty()) expected = ToBooleanICStub::Types::Generic();
if (expected.Contains(ToBooleanStub::UNDEFINED)) {
if (expected.Contains(ToBooleanICStub::UNDEFINED)) {
// undefined -> false.
__ JumpIfRoot(
value, Heap::kUndefinedValueRootIndex, false_label);
}
if (expected.Contains(ToBooleanStub::BOOLEAN)) {
if (expected.Contains(ToBooleanICStub::BOOLEAN)) {
// Boolean -> its value.
__ JumpIfRoot(
value, Heap::kTrueValueRootIndex, true_label);
@ -1749,13 +1750,13 @@ void LCodeGen::DoBranch(LBranch* instr) {
value, Heap::kFalseValueRootIndex, false_label);
}
if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
if (expected.Contains(ToBooleanICStub::NULL_TYPE)) {
// 'null' -> false.
__ JumpIfRoot(
value, Heap::kNullValueRootIndex, false_label);
}
if (expected.Contains(ToBooleanStub::SMI)) {
if (expected.Contains(ToBooleanICStub::SMI)) {
// Smis: 0 -> false, all other -> true.
DCHECK(Smi::FromInt(0) == 0);
__ Cbz(value, false_label);
@ -1783,13 +1784,13 @@ void LCodeGen::DoBranch(LBranch* instr) {
}
}
if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
if (expected.Contains(ToBooleanICStub::SPEC_OBJECT)) {
// spec object -> true.
__ CompareInstanceType(map, scratch, FIRST_JS_RECEIVER_TYPE);
__ B(ge, true_label);
}
if (expected.Contains(ToBooleanStub::STRING)) {
if (expected.Contains(ToBooleanICStub::STRING)) {
// String value -> false iff empty.
Label not_string;
__ CompareInstanceType(map, scratch, FIRST_NONSTRING_TYPE);
@ -1800,19 +1801,19 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ Bind(&not_string);
}
if (expected.Contains(ToBooleanStub::SYMBOL)) {
if (expected.Contains(ToBooleanICStub::SYMBOL)) {
// Symbol value -> true.
__ CompareInstanceType(map, scratch, SYMBOL_TYPE);
__ B(eq, true_label);
}
if (expected.Contains(ToBooleanStub::SIMD_VALUE)) {
if (expected.Contains(ToBooleanICStub::SIMD_VALUE)) {
// SIMD value -> true.
__ CompareInstanceType(map, scratch, SIMD128_VALUE_TYPE);
__ B(eq, true_label);
}
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
if (expected.Contains(ToBooleanICStub::HEAP_NUMBER)) {
Label not_heap_number;
__ JumpIfNotRoot(map, Heap::kHeapNumberMapRootIndex, &not_heap_number);

View File

@ -1095,23 +1095,23 @@ std::ostream& HReturn::PrintDataTo(std::ostream& os) const { // NOLINT
Representation HBranch::observed_input_representation(int index) {
if (expected_input_types_.Contains(ToBooleanStub::NULL_TYPE) ||
expected_input_types_.Contains(ToBooleanStub::SPEC_OBJECT) ||
expected_input_types_.Contains(ToBooleanStub::STRING) ||
expected_input_types_.Contains(ToBooleanStub::SYMBOL) ||
expected_input_types_.Contains(ToBooleanStub::SIMD_VALUE)) {
if (expected_input_types_.Contains(ToBooleanICStub::NULL_TYPE) ||
expected_input_types_.Contains(ToBooleanICStub::SPEC_OBJECT) ||
expected_input_types_.Contains(ToBooleanICStub::STRING) ||
expected_input_types_.Contains(ToBooleanICStub::SYMBOL) ||
expected_input_types_.Contains(ToBooleanICStub::SIMD_VALUE)) {
return Representation::Tagged();
}
if (expected_input_types_.Contains(ToBooleanStub::UNDEFINED)) {
if (expected_input_types_.Contains(ToBooleanStub::HEAP_NUMBER)) {
if (expected_input_types_.Contains(ToBooleanICStub::UNDEFINED)) {
if (expected_input_types_.Contains(ToBooleanICStub::HEAP_NUMBER)) {
return Representation::Double();
}
return Representation::Tagged();
}
if (expected_input_types_.Contains(ToBooleanStub::HEAP_NUMBER)) {
if (expected_input_types_.Contains(ToBooleanICStub::HEAP_NUMBER)) {
return Representation::Double();
}
if (expected_input_types_.Contains(ToBooleanStub::SMI)) {
if (expected_input_types_.Contains(ToBooleanICStub::SMI)) {
return Representation::Smi();
}
return Representation::None();

View File

@ -1366,10 +1366,8 @@ class HUnaryControlInstruction : public HTemplateControlInstruction<2, 1> {
class HBranch final : public HUnaryControlInstruction {
public:
DECLARE_INSTRUCTION_FACTORY_P1(HBranch, HValue*);
DECLARE_INSTRUCTION_FACTORY_P2(HBranch, HValue*,
ToBooleanStub::Types);
DECLARE_INSTRUCTION_FACTORY_P4(HBranch, HValue*,
ToBooleanStub::Types,
DECLARE_INSTRUCTION_FACTORY_P2(HBranch, HValue*, ToBooleanICStub::Types);
DECLARE_INSTRUCTION_FACTORY_P4(HBranch, HValue*, ToBooleanICStub::Types,
HBasicBlock*, HBasicBlock*);
Representation RequiredInputRepresentation(int index) override {
@ -1381,23 +1379,22 @@ class HBranch final : public HUnaryControlInstruction {
std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
ToBooleanStub::Types expected_input_types() const {
ToBooleanICStub::Types expected_input_types() const {
return expected_input_types_;
}
DECLARE_CONCRETE_INSTRUCTION(Branch)
private:
HBranch(HValue* value,
ToBooleanStub::Types expected_input_types = ToBooleanStub::Types(),
HBasicBlock* true_target = NULL,
HBasicBlock* false_target = NULL)
HBranch(HValue* value, ToBooleanICStub::Types expected_input_types =
ToBooleanICStub::Types(),
HBasicBlock* true_target = NULL, HBasicBlock* false_target = NULL)
: HUnaryControlInstruction(value, true_target, false_target),
expected_input_types_(expected_input_types) {
SetFlag(kAllowUndefinedAsNaN);
}
ToBooleanStub::Types expected_input_types_;
ToBooleanICStub::Types expected_input_types_;
};

View File

@ -30,7 +30,7 @@ HBasicBlock* HOsrBuilder::BuildOsrLoopEntry(IterationStatement* statement) {
HBasicBlock* non_osr_entry = graph->CreateBasicBlock();
osr_entry_ = graph->CreateBasicBlock();
HValue* true_value = graph->GetConstantTrue();
HBranch* test = builder_->New<HBranch>(true_value, ToBooleanStub::Types(),
HBranch* test = builder_->New<HBranch>(true_value, ToBooleanICStub::Types(),
non_osr_entry, osr_entry_);
builder_->FinishCurrentBlock(test);

View File

@ -906,8 +906,8 @@ void HGraphBuilder::IfBuilder::Then() {
// so that the graph builder visits it and sees any live range extending
// constructs within it.
HConstant* constant_false = builder()->graph()->GetConstantFalse();
ToBooleanStub::Types boolean_type = ToBooleanStub::Types();
boolean_type.Add(ToBooleanStub::BOOLEAN);
ToBooleanICStub::Types boolean_type = ToBooleanICStub::Types();
boolean_type.Add(ToBooleanICStub::BOOLEAN);
HBranch* branch = builder()->New<HBranch>(
constant_false, boolean_type, first_true_block_, first_false_block_);
builder()->FinishCurrentBlock(branch);
@ -4298,7 +4298,7 @@ void TestContext::BuildBranch(HValue* value) {
if (value != NULL && value->CheckFlag(HValue::kIsArguments)) {
builder->Bailout(kArgumentsObjectValueInATestContext);
}
ToBooleanStub::Types expected(condition()->to_boolean_types());
ToBooleanICStub::Types expected(condition()->to_boolean_types());
ReturnControl(owner()->New<HBranch>(value, expected), BailoutId::None());
}
@ -11293,7 +11293,7 @@ void HOptimizedGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) {
// We need an extra block to maintain edge-split form.
HBasicBlock* empty_block = graph()->CreateBasicBlock();
HBasicBlock* eval_right = graph()->CreateBasicBlock();
ToBooleanStub::Types expected(expr->left()->to_boolean_types());
ToBooleanICStub::Types expected(expr->left()->to_boolean_types());
HBranch* test = is_logical_and
? New<HBranch>(left_value, expected, eval_right, empty_block)
: New<HBranch>(left_value, expected, empty_block, eval_right);

View File

@ -1869,15 +1869,16 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ cmp(FieldOperand(reg, String::kLengthOffset), Immediate(0));
EmitBranch(instr, not_equal);
} else {
ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
ToBooleanICStub::Types expected =
instr->hydrogen()->expected_input_types();
if (expected.IsEmpty()) expected = ToBooleanICStub::Types::Generic();
if (expected.Contains(ToBooleanStub::UNDEFINED)) {
if (expected.Contains(ToBooleanICStub::UNDEFINED)) {
// undefined -> false.
__ cmp(reg, factory()->undefined_value());
__ j(equal, instr->FalseLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::BOOLEAN)) {
if (expected.Contains(ToBooleanICStub::BOOLEAN)) {
// true -> true.
__ cmp(reg, factory()->true_value());
__ j(equal, instr->TrueLabel(chunk_));
@ -1885,13 +1886,13 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ cmp(reg, factory()->false_value());
__ j(equal, instr->FalseLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
if (expected.Contains(ToBooleanICStub::NULL_TYPE)) {
// 'null' -> false.
__ cmp(reg, factory()->null_value());
__ j(equal, instr->FalseLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::SMI)) {
if (expected.Contains(ToBooleanICStub::SMI)) {
// Smis: 0 -> false, all other -> true.
__ test(reg, Operand(reg));
__ j(equal, instr->FalseLabel(chunk_));
@ -1916,13 +1917,13 @@ void LCodeGen::DoBranch(LBranch* instr) {
}
}
if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
if (expected.Contains(ToBooleanICStub::SPEC_OBJECT)) {
// spec object -> true.
__ CmpInstanceType(map, FIRST_JS_RECEIVER_TYPE);
__ j(above_equal, instr->TrueLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::STRING)) {
if (expected.Contains(ToBooleanICStub::STRING)) {
// String value -> false iff empty.
Label not_string;
__ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
@ -1933,19 +1934,19 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ bind(&not_string);
}
if (expected.Contains(ToBooleanStub::SYMBOL)) {
if (expected.Contains(ToBooleanICStub::SYMBOL)) {
// Symbol value -> true.
__ CmpInstanceType(map, SYMBOL_TYPE);
__ j(equal, instr->TrueLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::SIMD_VALUE)) {
if (expected.Contains(ToBooleanICStub::SIMD_VALUE)) {
// SIMD value -> true.
__ CmpInstanceType(map, SIMD128_VALUE_TYPE);
__ j(equal, instr->TrueLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
if (expected.Contains(ToBooleanICStub::HEAP_NUMBER)) {
// heap number -> false iff +0, -0, or NaN.
Label not_heap_number;
__ cmp(FieldOperand(reg, HeapObject::kMapOffset),

View File

@ -936,15 +936,15 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
HValue* value = instr->value();
Representation r = value->representation();
HType type = value->type();
ToBooleanStub::Types expected = instr->expected_input_types();
if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
ToBooleanICStub::Types expected = instr->expected_input_types();
if (expected.IsEmpty()) expected = ToBooleanICStub::Types::Generic();
bool easy_case = !r.IsTagged() || type.IsBoolean() || type.IsSmi() ||
type.IsJSArray() || type.IsHeapNumber() || type.IsString();
LOperand* temp = !easy_case && expected.NeedsMap() ? TempRegister() : NULL;
LInstruction* branch = new(zone()) LBranch(UseRegister(value), temp);
if (!easy_case &&
((!expected.Contains(ToBooleanStub::SMI) && expected.NeedsMap()) ||
((!expected.Contains(ToBooleanICStub::SMI) && expected.NeedsMap()) ||
!expected.IsGeneric())) {
branch = AssignEnvironment(branch);
}

View File

@ -1966,29 +1966,30 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ lw(at, FieldMemOperand(reg, String::kLengthOffset));
EmitBranch(instr, ne, at, Operand(zero_reg));
} else {
ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
ToBooleanICStub::Types expected =
instr->hydrogen()->expected_input_types();
// Avoid deopts in the case where we've never executed this path before.
if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
if (expected.IsEmpty()) expected = ToBooleanICStub::Types::Generic();
if (expected.Contains(ToBooleanStub::UNDEFINED)) {
if (expected.Contains(ToBooleanICStub::UNDEFINED)) {
// undefined -> false.
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
__ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(at));
}
if (expected.Contains(ToBooleanStub::BOOLEAN)) {
if (expected.Contains(ToBooleanICStub::BOOLEAN)) {
// Boolean -> its value.
__ LoadRoot(at, Heap::kTrueValueRootIndex);
__ Branch(instr->TrueLabel(chunk_), eq, reg, Operand(at));
__ LoadRoot(at, Heap::kFalseValueRootIndex);
__ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(at));
}
if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
if (expected.Contains(ToBooleanICStub::NULL_TYPE)) {
// 'null' -> false.
__ LoadRoot(at, Heap::kNullValueRootIndex);
__ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(at));
}
if (expected.Contains(ToBooleanStub::SMI)) {
if (expected.Contains(ToBooleanICStub::SMI)) {
// Smis: 0 -> false, all other -> true.
__ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(zero_reg));
__ JumpIfSmi(reg, instr->TrueLabel(chunk_));
@ -2009,14 +2010,14 @@ void LCodeGen::DoBranch(LBranch* instr) {
}
}
if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
if (expected.Contains(ToBooleanICStub::SPEC_OBJECT)) {
// spec object -> true.
__ lbu(at, FieldMemOperand(map, Map::kInstanceTypeOffset));
__ Branch(instr->TrueLabel(chunk_),
ge, at, Operand(FIRST_JS_RECEIVER_TYPE));
}
if (expected.Contains(ToBooleanStub::STRING)) {
if (expected.Contains(ToBooleanICStub::STRING)) {
// String value -> false iff empty.
Label not_string;
__ lbu(at, FieldMemOperand(map, Map::kInstanceTypeOffset));
@ -2027,14 +2028,14 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ bind(&not_string);
}
if (expected.Contains(ToBooleanStub::SYMBOL)) {
if (expected.Contains(ToBooleanICStub::SYMBOL)) {
// Symbol value -> true.
const Register scratch = scratch1();
__ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
__ Branch(instr->TrueLabel(chunk_), eq, scratch, Operand(SYMBOL_TYPE));
}
if (expected.Contains(ToBooleanStub::SIMD_VALUE)) {
if (expected.Contains(ToBooleanICStub::SIMD_VALUE)) {
// SIMD value -> true.
const Register scratch = scratch1();
__ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
@ -2042,7 +2043,7 @@ void LCodeGen::DoBranch(LBranch* instr) {
Operand(SIMD128_VALUE_TYPE));
}
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
if (expected.Contains(ToBooleanICStub::HEAP_NUMBER)) {
// heap number -> false iff +0, -0, or NaN.
DoubleRegister dbl_scratch = double_scratch0();
Label not_heap_number;

View File

@ -914,14 +914,14 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
HValue* value = instr->value();
Representation r = value->representation();
HType type = value->type();
ToBooleanStub::Types expected = instr->expected_input_types();
if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
ToBooleanICStub::Types expected = instr->expected_input_types();
if (expected.IsEmpty()) expected = ToBooleanICStub::Types::Generic();
bool easy_case = !r.IsTagged() || type.IsBoolean() || type.IsSmi() ||
type.IsJSArray() || type.IsHeapNumber() || type.IsString();
LInstruction* branch = new(zone()) LBranch(UseRegister(value));
if (!easy_case &&
((!expected.Contains(ToBooleanStub::SMI) && expected.NeedsMap()) ||
((!expected.Contains(ToBooleanICStub::SMI) && expected.NeedsMap()) ||
!expected.IsGeneric())) {
branch = AssignEnvironment(branch);
}

View File

@ -2083,29 +2083,30 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ ld(at, FieldMemOperand(reg, String::kLengthOffset));
EmitBranch(instr, ne, at, Operand(zero_reg));
} else {
ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
ToBooleanICStub::Types expected =
instr->hydrogen()->expected_input_types();
// Avoid deopts in the case where we've never executed this path before.
if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
if (expected.IsEmpty()) expected = ToBooleanICStub::Types::Generic();
if (expected.Contains(ToBooleanStub::UNDEFINED)) {
if (expected.Contains(ToBooleanICStub::UNDEFINED)) {
// undefined -> false.
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
__ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(at));
}
if (expected.Contains(ToBooleanStub::BOOLEAN)) {
if (expected.Contains(ToBooleanICStub::BOOLEAN)) {
// Boolean -> its value.
__ LoadRoot(at, Heap::kTrueValueRootIndex);
__ Branch(instr->TrueLabel(chunk_), eq, reg, Operand(at));
__ LoadRoot(at, Heap::kFalseValueRootIndex);
__ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(at));
}
if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
if (expected.Contains(ToBooleanICStub::NULL_TYPE)) {
// 'null' -> false.
__ LoadRoot(at, Heap::kNullValueRootIndex);
__ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(at));
}
if (expected.Contains(ToBooleanStub::SMI)) {
if (expected.Contains(ToBooleanICStub::SMI)) {
// Smis: 0 -> false, all other -> true.
__ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(zero_reg));
__ JumpIfSmi(reg, instr->TrueLabel(chunk_));
@ -2126,14 +2127,14 @@ void LCodeGen::DoBranch(LBranch* instr) {
}
}
if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
if (expected.Contains(ToBooleanICStub::SPEC_OBJECT)) {
// spec object -> true.
__ lbu(at, FieldMemOperand(map, Map::kInstanceTypeOffset));
__ Branch(instr->TrueLabel(chunk_),
ge, at, Operand(FIRST_JS_RECEIVER_TYPE));
}
if (expected.Contains(ToBooleanStub::STRING)) {
if (expected.Contains(ToBooleanICStub::STRING)) {
// String value -> false iff empty.
Label not_string;
__ lbu(at, FieldMemOperand(map, Map::kInstanceTypeOffset));
@ -2144,14 +2145,14 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ bind(&not_string);
}
if (expected.Contains(ToBooleanStub::SYMBOL)) {
if (expected.Contains(ToBooleanICStub::SYMBOL)) {
// Symbol value -> true.
const Register scratch = scratch1();
__ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
__ Branch(instr->TrueLabel(chunk_), eq, scratch, Operand(SYMBOL_TYPE));
}
if (expected.Contains(ToBooleanStub::SIMD_VALUE)) {
if (expected.Contains(ToBooleanICStub::SIMD_VALUE)) {
// SIMD value -> true.
const Register scratch = scratch1();
__ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
@ -2159,7 +2160,7 @@ void LCodeGen::DoBranch(LBranch* instr) {
Operand(SIMD128_VALUE_TYPE));
}
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
if (expected.Contains(ToBooleanICStub::HEAP_NUMBER)) {
// heap number -> false iff +0, -0, or NaN.
DoubleRegister dbl_scratch = double_scratch0();
Label not_heap_number;

View File

@ -914,14 +914,14 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
HValue* value = instr->value();
Representation r = value->representation();
HType type = value->type();
ToBooleanStub::Types expected = instr->expected_input_types();
if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
ToBooleanICStub::Types expected = instr->expected_input_types();
if (expected.IsEmpty()) expected = ToBooleanICStub::Types::Generic();
bool easy_case = !r.IsTagged() || type.IsBoolean() || type.IsSmi() ||
type.IsJSArray() || type.IsHeapNumber() || type.IsString();
LInstruction* branch = new(zone()) LBranch(UseRegister(value));
if (!easy_case &&
((!expected.Contains(ToBooleanStub::SMI) && expected.NeedsMap()) ||
((!expected.Contains(ToBooleanICStub::SMI) && expected.NeedsMap()) ||
!expected.IsGeneric())) {
branch = AssignEnvironment(branch);
}

View File

@ -2103,29 +2103,30 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ cmpi(ip, Operand::Zero());
EmitBranch(instr, ne);
} else {
ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
ToBooleanICStub::Types expected =
instr->hydrogen()->expected_input_types();
// Avoid deopts in the case where we've never executed this path before.
if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
if (expected.IsEmpty()) expected = ToBooleanICStub::Types::Generic();
if (expected.Contains(ToBooleanStub::UNDEFINED)) {
if (expected.Contains(ToBooleanICStub::UNDEFINED)) {
// undefined -> false.
__ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
__ beq(instr->FalseLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::BOOLEAN)) {
if (expected.Contains(ToBooleanICStub::BOOLEAN)) {
// Boolean -> its value.
__ CompareRoot(reg, Heap::kTrueValueRootIndex);
__ beq(instr->TrueLabel(chunk_));
__ CompareRoot(reg, Heap::kFalseValueRootIndex);
__ beq(instr->FalseLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
if (expected.Contains(ToBooleanICStub::NULL_TYPE)) {
// 'null' -> false.
__ CompareRoot(reg, Heap::kNullValueRootIndex);
__ beq(instr->FalseLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::SMI)) {
if (expected.Contains(ToBooleanICStub::SMI)) {
// Smis: 0 -> false, all other -> true.
__ cmpi(reg, Operand::Zero());
__ beq(instr->FalseLabel(chunk_));
@ -2148,13 +2149,13 @@ void LCodeGen::DoBranch(LBranch* instr) {
}
}
if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
if (expected.Contains(ToBooleanICStub::SPEC_OBJECT)) {
// spec object -> true.
__ CompareInstanceType(map, ip, FIRST_JS_RECEIVER_TYPE);
__ bge(instr->TrueLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::STRING)) {
if (expected.Contains(ToBooleanICStub::STRING)) {
// String value -> false iff empty.
Label not_string;
__ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
@ -2166,20 +2167,20 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ bind(&not_string);
}
if (expected.Contains(ToBooleanStub::SYMBOL)) {
if (expected.Contains(ToBooleanICStub::SYMBOL)) {
// Symbol value -> true.
__ CompareInstanceType(map, ip, SYMBOL_TYPE);
__ beq(instr->TrueLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::SIMD_VALUE)) {
if (expected.Contains(ToBooleanICStub::SIMD_VALUE)) {
// SIMD value -> true.
Label not_simd;
__ CompareInstanceType(map, ip, SIMD128_VALUE_TYPE);
__ beq(instr->TrueLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
if (expected.Contains(ToBooleanICStub::HEAP_NUMBER)) {
// heap number -> false iff +0, -0, or NaN.
Label not_heap_number;
__ CompareRoot(map, Heap::kHeapNumberMapRootIndex);

View File

@ -918,14 +918,14 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
HValue* value = instr->value();
Representation r = value->representation();
HType type = value->type();
ToBooleanStub::Types expected = instr->expected_input_types();
if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
ToBooleanICStub::Types expected = instr->expected_input_types();
if (expected.IsEmpty()) expected = ToBooleanICStub::Types::Generic();
bool easy_case = !r.IsTagged() || type.IsBoolean() || type.IsSmi() ||
type.IsJSArray() || type.IsHeapNumber() || type.IsString();
LInstruction* branch = new (zone()) LBranch(UseRegister(value));
if (!easy_case &&
((!expected.Contains(ToBooleanStub::SMI) && expected.NeedsMap()) ||
((!expected.Contains(ToBooleanICStub::SMI) && expected.NeedsMap()) ||
!expected.IsGeneric())) {
branch = AssignEnvironment(branch);
}

View File

@ -2012,16 +2012,17 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ cmpp(FieldOperand(reg, String::kLengthOffset), Immediate(0));
EmitBranch(instr, not_equal);
} else {
ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
ToBooleanICStub::Types expected =
instr->hydrogen()->expected_input_types();
// Avoid deopts in the case where we've never executed this path before.
if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
if (expected.IsEmpty()) expected = ToBooleanICStub::Types::Generic();
if (expected.Contains(ToBooleanStub::UNDEFINED)) {
if (expected.Contains(ToBooleanICStub::UNDEFINED)) {
// undefined -> false.
__ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
__ j(equal, instr->FalseLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::BOOLEAN)) {
if (expected.Contains(ToBooleanICStub::BOOLEAN)) {
// true -> true.
__ CompareRoot(reg, Heap::kTrueValueRootIndex);
__ j(equal, instr->TrueLabel(chunk_));
@ -2029,13 +2030,13 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ CompareRoot(reg, Heap::kFalseValueRootIndex);
__ j(equal, instr->FalseLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
if (expected.Contains(ToBooleanICStub::NULL_TYPE)) {
// 'null' -> false.
__ CompareRoot(reg, Heap::kNullValueRootIndex);
__ j(equal, instr->FalseLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::SMI)) {
if (expected.Contains(ToBooleanICStub::SMI)) {
// Smis: 0 -> false, all other -> true.
__ Cmp(reg, Smi::FromInt(0));
__ j(equal, instr->FalseLabel(chunk_));
@ -2058,13 +2059,13 @@ void LCodeGen::DoBranch(LBranch* instr) {
}
}
if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
if (expected.Contains(ToBooleanICStub::SPEC_OBJECT)) {
// spec object -> true.
__ CmpInstanceType(map, FIRST_JS_RECEIVER_TYPE);
__ j(above_equal, instr->TrueLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::STRING)) {
if (expected.Contains(ToBooleanICStub::STRING)) {
// String value -> false iff empty.
Label not_string;
__ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
@ -2075,19 +2076,19 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ bind(&not_string);
}
if (expected.Contains(ToBooleanStub::SYMBOL)) {
if (expected.Contains(ToBooleanICStub::SYMBOL)) {
// Symbol value -> true.
__ CmpInstanceType(map, SYMBOL_TYPE);
__ j(equal, instr->TrueLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::SIMD_VALUE)) {
if (expected.Contains(ToBooleanICStub::SIMD_VALUE)) {
// SIMD value -> true.
__ CmpInstanceType(map, SIMD128_VALUE_TYPE);
__ j(equal, instr->TrueLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
if (expected.Contains(ToBooleanICStub::HEAP_NUMBER)) {
// heap number -> false iff +0, -0, or NaN.
Label not_heap_number;
__ CompareRoot(map, Heap::kHeapNumberMapRootIndex);

View File

@ -933,14 +933,14 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
HValue* value = instr->value();
Representation r = value->representation();
HType type = value->type();
ToBooleanStub::Types expected = instr->expected_input_types();
if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
ToBooleanICStub::Types expected = instr->expected_input_types();
if (expected.IsEmpty()) expected = ToBooleanICStub::Types::Generic();
bool easy_case = !r.IsTagged() || type.IsBoolean() || type.IsSmi() ||
type.IsJSArray() || type.IsHeapNumber() || type.IsString();
LInstruction* branch = new(zone()) LBranch(UseRegister(value));
if (!easy_case &&
((!expected.Contains(ToBooleanStub::SMI) && expected.NeedsMap()) ||
((!expected.Contains(ToBooleanICStub::SMI) && expected.NeedsMap()) ||
!expected.IsGeneric())) {
branch = AssignEnvironment(branch);
}

View File

@ -2137,15 +2137,16 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ cmp(FieldOperand(reg, String::kLengthOffset), Immediate(0));
EmitBranch(instr, not_equal);
} else {
ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
ToBooleanICStub::Types expected =
instr->hydrogen()->expected_input_types();
if (expected.IsEmpty()) expected = ToBooleanICStub::Types::Generic();
if (expected.Contains(ToBooleanStub::UNDEFINED)) {
if (expected.Contains(ToBooleanICStub::UNDEFINED)) {
// undefined -> false.
__ cmp(reg, factory()->undefined_value());
__ j(equal, instr->FalseLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::BOOLEAN)) {
if (expected.Contains(ToBooleanICStub::BOOLEAN)) {
// true -> true.
__ cmp(reg, factory()->true_value());
__ j(equal, instr->TrueLabel(chunk_));
@ -2153,13 +2154,13 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ cmp(reg, factory()->false_value());
__ j(equal, instr->FalseLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
if (expected.Contains(ToBooleanICStub::NULL_TYPE)) {
// 'null' -> false.
__ cmp(reg, factory()->null_value());
__ j(equal, instr->FalseLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::SMI)) {
if (expected.Contains(ToBooleanICStub::SMI)) {
// Smis: 0 -> false, all other -> true.
__ test(reg, Operand(reg));
__ j(equal, instr->FalseLabel(chunk_));
@ -2184,13 +2185,13 @@ void LCodeGen::DoBranch(LBranch* instr) {
}
}
if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
if (expected.Contains(ToBooleanICStub::SPEC_OBJECT)) {
// spec object -> true.
__ CmpInstanceType(map, FIRST_JS_RECEIVER_TYPE);
__ j(above_equal, instr->TrueLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::STRING)) {
if (expected.Contains(ToBooleanICStub::STRING)) {
// String value -> false iff empty.
Label not_string;
__ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
@ -2201,19 +2202,19 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ bind(&not_string);
}
if (expected.Contains(ToBooleanStub::SYMBOL)) {
if (expected.Contains(ToBooleanICStub::SYMBOL)) {
// Symbol value -> true.
__ CmpInstanceType(map, SYMBOL_TYPE);
__ j(equal, instr->TrueLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::SIMD_VALUE)) {
if (expected.Contains(ToBooleanICStub::SIMD_VALUE)) {
// SIMD value -> true.
__ CmpInstanceType(map, SIMD128_VALUE_TYPE);
__ j(equal, instr->TrueLabel(chunk_));
}
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
if (expected.Contains(ToBooleanICStub::HEAP_NUMBER)) {
// heap number -> false iff +0, -0, or NaN.
Label not_heap_number;
__ cmp(FieldOperand(reg, HeapObject::kMapOffset),

View File

@ -952,8 +952,8 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
HValue* value = instr->value();
Representation r = value->representation();
HType type = value->type();
ToBooleanStub::Types expected = instr->expected_input_types();
if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
ToBooleanICStub::Types expected = instr->expected_input_types();
if (expected.IsEmpty()) expected = ToBooleanICStub::Types::Generic();
bool easy_case = !r.IsTagged() || type.IsBoolean() || type.IsSmi() ||
type.IsJSArray() || type.IsHeapNumber() || type.IsString();
@ -962,7 +962,7 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
temp != NULL ? new (zone()) LBranch(UseRegister(value), temp)
: new (zone()) LBranch(UseRegisterAtStart(value), temp);
if (!easy_case &&
((!expected.Contains(ToBooleanStub::SMI) && expected.NeedsMap()) ||
((!expected.Contains(ToBooleanICStub::SMI) && expected.NeedsMap()) ||
!expected.IsGeneric())) {
branch = AssignEnvironment(branch);
}

View File

@ -112,12 +112,12 @@ Factory::NewSloppyBlockWithEvalContextExtension(
return result;
}
Handle<Oddball> Factory::NewOddball(Handle<Map> map, const char* to_string,
Handle<Object> to_number,
Handle<Object> to_number, bool to_boolean,
const char* type_of, byte kind) {
Handle<Oddball> oddball = New<Oddball>(map, OLD_SPACE);
Oddball::Initialize(isolate(), oddball, to_string, to_number, type_of, kind);
Oddball::Initialize(isolate(), oddball, to_string, to_number, to_boolean,
type_of, kind);
return oddball;
}

View File

@ -16,8 +16,8 @@ namespace internal {
class Factory final {
public:
Handle<Oddball> NewOddball(Handle<Map> map, const char* to_string,
Handle<Object> to_number, const char* type_of,
byte kind);
Handle<Object> to_number, bool to_boolean,
const char* type_of, byte kind);
// Allocates a fixed array initialized with undefined values.
Handle<FixedArray> NewFixedArray(

View File

@ -643,7 +643,7 @@ void FullCodeGenerator::DoTest(Expression* condition,
Label* if_true,
Label* if_false,
Label* fall_through) {
Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate());
Handle<Code> ic = ToBooleanICStub::GetUninitialized(isolate());
CallIC(ic, condition->test_id());
__ CompareRoot(result_register(), Heap::kTrueValueRootIndex);
Split(eq, if_true, if_false, fall_through);

View File

@ -640,7 +640,7 @@ void FullCodeGenerator::DoTest(Expression* condition,
Label* if_true,
Label* if_false,
Label* fall_through) {
Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate());
Handle<Code> ic = ToBooleanICStub::GetUninitialized(isolate());
CallIC(ic, condition->test_id());
__ CompareRoot(result_register(), Heap::kTrueValueRootIndex);
Split(eq, if_true, if_false, fall_through);

View File

@ -595,7 +595,7 @@ void FullCodeGenerator::DoTest(Expression* condition,
Label* if_true,
Label* if_false,
Label* fall_through) {
Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate());
Handle<Code> ic = ToBooleanICStub::GetUninitialized(isolate());
CallIC(ic, condition->test_id());
__ CompareRoot(result_register(), Heap::kTrueValueRootIndex);
Split(equal, if_true, if_false, fall_through);

View File

@ -637,7 +637,7 @@ void FullCodeGenerator::DoTest(Expression* condition,
Label* if_false,
Label* fall_through) {
__ mov(a0, result_register());
Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate());
Handle<Code> ic = ToBooleanICStub::GetUninitialized(isolate());
CallIC(ic, condition->test_id());
__ LoadRoot(at, Heap::kTrueValueRootIndex);
Split(eq, result_register(), Operand(at), if_true, if_false, fall_through);

View File

@ -637,7 +637,7 @@ void FullCodeGenerator::DoTest(Expression* condition,
Label* if_false,
Label* fall_through) {
__ mov(a0, result_register());
Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate());
Handle<Code> ic = ToBooleanICStub::GetUninitialized(isolate());
CallIC(ic, condition->test_id());
__ LoadRoot(at, Heap::kTrueValueRootIndex);
Split(eq, result_register(), Operand(at), if_true, if_false, fall_through);

View File

@ -616,7 +616,7 @@ void FullCodeGenerator::TestContext::Plug(bool flag) const {
void FullCodeGenerator::DoTest(Expression* condition, Label* if_true,
Label* if_false, Label* fall_through) {
Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate());
Handle<Code> ic = ToBooleanICStub::GetUninitialized(isolate());
CallIC(ic, condition->test_id());
__ CompareRoot(result_register(), Heap::kTrueValueRootIndex);
Split(eq, if_true, if_false, fall_through);

View File

@ -606,7 +606,7 @@ void FullCodeGenerator::DoTest(Expression* condition,
Label* if_true,
Label* if_false,
Label* fall_through) {
Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate());
Handle<Code> ic = ToBooleanICStub::GetUninitialized(isolate());
CallIC(ic, condition->test_id());
__ CompareRoot(result_register(), Heap::kTrueValueRootIndex);
Split(equal, if_true, if_false, fall_through);

View File

@ -592,7 +592,7 @@ void FullCodeGenerator::DoTest(Expression* condition,
Label* if_true,
Label* if_false,
Label* fall_through) {
Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate());
Handle<Code> ic = ToBooleanICStub::GetUninitialized(isolate());
CallIC(ic, condition->test_id());
__ CompareRoot(result_register(), Heap::kTrueValueRootIndex);
Split(equal, if_true, if_false, fall_through);

View File

@ -655,8 +655,7 @@ void Heap::ClearInstanceofCache() {
set_instanceof_cache_function(Smi::FromInt(0));
}
Object* Heap::ToBoolean(bool condition) {
Oddball* Heap::ToBoolean(bool condition) {
return condition ? true_value() : false_value();
}

View File

@ -2403,6 +2403,20 @@ bool Heap::CreateInitialMaps() {
#undef ALLOCATE_MAP
}
{
AllocationResult allocation = Allocate(boolean_map(), OLD_SPACE);
if (!allocation.To(&obj)) return false;
}
set_true_value(Oddball::cast(obj));
Oddball::cast(obj)->set_kind(Oddball::kTrue);
{
AllocationResult allocation = Allocate(boolean_map(), OLD_SPACE);
if (!allocation.To(&obj)) return false;
}
set_false_value(Oddball::cast(obj));
Oddball::cast(obj)->set_kind(Oddball::kFalse);
{ // Empty arrays
{
ByteArray* byte_array;
@ -2620,48 +2634,54 @@ void Heap::CreateInitialObjects() {
// Allocate initial string table.
set_string_table(*StringTable::New(isolate(), kInitialStringTableSize));
// Allocate
// Finish initializing oddballs after creating the string table.
Oddball::Initialize(isolate(), factory->undefined_value(), "undefined",
factory->nan_value(), "undefined", Oddball::kUndefined);
factory->nan_value(), false, "undefined",
Oddball::kUndefined);
// Initialize the null_value.
Oddball::Initialize(isolate(), factory->null_value(), "null",
handle(Smi::FromInt(0), isolate()), "object",
handle(Smi::FromInt(0), isolate()), false, "object",
Oddball::kNull);
set_true_value(*factory->NewOddball(factory->boolean_map(), "true",
handle(Smi::FromInt(1), isolate()),
"boolean", Oddball::kTrue));
// Initialize the true_value.
Oddball::Initialize(isolate(), factory->true_value(), "true",
handle(Smi::FromInt(1), isolate()), true, "boolean",
Oddball::kTrue);
set_false_value(*factory->NewOddball(factory->boolean_map(), "false",
handle(Smi::FromInt(0), isolate()),
"boolean", Oddball::kFalse));
// Initialize the false_value.
Oddball::Initialize(isolate(), factory->false_value(), "false",
handle(Smi::FromInt(0), isolate()), false, "boolean",
Oddball::kFalse);
set_the_hole_value(*factory->NewOddball(factory->the_hole_map(), "hole",
handle(Smi::FromInt(-1), isolate()),
"undefined", Oddball::kTheHole));
set_the_hole_value(*factory->NewOddball(
factory->the_hole_map(), "hole", handle(Smi::FromInt(-1), isolate()),
false, "undefined", Oddball::kTheHole));
set_uninitialized_value(
*factory->NewOddball(factory->uninitialized_map(), "uninitialized",
handle(Smi::FromInt(-1), isolate()), "undefined",
Oddball::kUninitialized));
handle(Smi::FromInt(-1), isolate()), false,
"undefined", Oddball::kUninitialized));
set_arguments_marker(
*factory->NewOddball(factory->arguments_marker_map(), "arguments_marker",
handle(Smi::FromInt(-4), isolate()), "undefined",
Oddball::kArgumentsMarker));
handle(Smi::FromInt(-4), isolate()), false,
"undefined", Oddball::kArgumentsMarker));
set_no_interceptor_result_sentinel(*factory->NewOddball(
factory->no_interceptor_result_sentinel_map(),
"no_interceptor_result_sentinel", handle(Smi::FromInt(-2), isolate()),
"undefined", Oddball::kOther));
false, "undefined", Oddball::kOther));
set_termination_exception(*factory->NewOddball(
factory->termination_exception_map(), "termination_exception",
handle(Smi::FromInt(-3), isolate()), "undefined", Oddball::kOther));
handle(Smi::FromInt(-3), isolate()), false, "undefined",
Oddball::kOther));
set_exception(*factory->NewOddball(factory->exception_map(), "exception",
handle(Smi::FromInt(-5), isolate()),
handle(Smi::FromInt(-5), isolate()), false,
"undefined", Oddball::kException));
for (unsigned i = 0; i < arraysize(constant_string_table); i++) {

View File

@ -652,7 +652,7 @@ class Heap {
void RightTrimFixedArray(FixedArrayBase* obj, int elements_to_trim);
// Converts the given boolean condition to JavaScript boolean value.
inline Object* ToBoolean(bool condition);
inline Oddball* ToBoolean(bool condition);
// Check whether the heap is currently iterable.
bool IsHeapIterable();

View File

@ -2720,7 +2720,7 @@ RUNTIME_FUNCTION(Runtime_Unreachable) {
Handle<Object> ToBooleanIC::ToBoolean(Handle<Object> object) {
ToBooleanStub stub(isolate(), target()->extra_ic_state());
ToBooleanICStub stub(isolate(), target()->extra_ic_state());
bool to_boolean_value = stub.UpdateStatus(object);
Handle<Code> code = stub.GetCode();
set_target(*code);

View File

@ -886,15 +886,29 @@ void Interpreter::DoDec(InterpreterAssembler* assembler) {
// Perform logical-not on the accumulator, first casting the
// accumulator to a boolean value if required.
void Interpreter::DoLogicalNot(InterpreterAssembler* assembler) {
Callable callable = CodeFactory::ToBoolean(isolate_);
Node* target = __ HeapConstant(callable.code());
Node* accumulator = __ GetAccumulator();
Node* context = __ GetContext();
Node* result =
__ CallRuntime(Runtime::kInterpreterLogicalNot, context, accumulator);
__ SetAccumulator(result);
__ Dispatch();
Node* to_boolean_value =
__ CallStub(callable.descriptor(), target, context, accumulator);
InterpreterAssembler::Label if_true(assembler), if_false(assembler);
Node* true_value = __ BooleanConstant(true);
Node* false_value = __ BooleanConstant(false);
Node* condition = __ WordEqual(to_boolean_value, true_value);
__ Branch(condition, &if_true, &if_false);
__ Bind(&if_true);
{
__ SetAccumulator(false_value);
__ Dispatch();
}
__ Bind(&if_false);
{
__ SetAccumulator(true_value);
__ Dispatch();
}
}
// TypeOf
//
// Load the accumulator with the string representating type of the
@ -1363,10 +1377,12 @@ void Interpreter::DoJumpIfFalseConstantWide(InterpreterAssembler* assembler) {
// Jump by number of bytes represented by an immediate operand if the object
// referenced by the accumulator is true when the object is cast to boolean.
void Interpreter::DoJumpIfToBooleanTrue(InterpreterAssembler* assembler) {
Callable callable = CodeFactory::ToBoolean(isolate_);
Node* target = __ HeapConstant(callable.code());
Node* accumulator = __ GetAccumulator();
Node* context = __ GetContext();
Node* to_boolean_value =
__ CallRuntime(Runtime::kInterpreterToBoolean, context, accumulator);
__ CallStub(callable.descriptor(), target, context, accumulator);
Node* relative_jump = __ BytecodeOperandImm(0);
Node* true_value = __ BooleanConstant(true);
__ JumpIfWordEqual(to_boolean_value, true_value, relative_jump);
@ -1380,10 +1396,12 @@ void Interpreter::DoJumpIfToBooleanTrue(InterpreterAssembler* assembler) {
// to boolean.
void Interpreter::DoJumpIfToBooleanTrueConstant(
InterpreterAssembler* assembler) {
Callable callable = CodeFactory::ToBoolean(isolate_);
Node* target = __ HeapConstant(callable.code());
Node* accumulator = __ GetAccumulator();
Node* context = __ GetContext();
Node* to_boolean_value =
__ CallRuntime(Runtime::kInterpreterToBoolean, context, accumulator);
__ CallStub(callable.descriptor(), target, context, accumulator);
Node* index = __ BytecodeOperandIdx(0);
Node* constant = __ LoadConstantPoolEntry(index);
Node* relative_jump = __ SmiUntag(constant);
@ -1408,10 +1426,12 @@ void Interpreter::DoJumpIfToBooleanTrueConstantWide(
// Jump by number of bytes represented by an immediate operand if the object
// referenced by the accumulator is false when the object is cast to boolean.
void Interpreter::DoJumpIfToBooleanFalse(InterpreterAssembler* assembler) {
Callable callable = CodeFactory::ToBoolean(isolate_);
Node* target = __ HeapConstant(callable.code());
Node* accumulator = __ GetAccumulator();
Node* context = __ GetContext();
Node* to_boolean_value =
__ CallRuntime(Runtime::kInterpreterToBoolean, context, accumulator);
__ CallStub(callable.descriptor(), target, context, accumulator);
Node* relative_jump = __ BytecodeOperandImm(0);
Node* false_value = __ BooleanConstant(false);
__ JumpIfWordEqual(to_boolean_value, false_value, relative_jump);
@ -1425,10 +1445,12 @@ void Interpreter::DoJumpIfToBooleanFalse(InterpreterAssembler* assembler) {
// to boolean.
void Interpreter::DoJumpIfToBooleanFalseConstant(
InterpreterAssembler* assembler) {
Callable callable = CodeFactory::ToBoolean(isolate_);
Node* target = __ HeapConstant(callable.code());
Node* accumulator = __ GetAccumulator();
Node* context = __ GetContext();
Node* to_boolean_value =
__ CallRuntime(Runtime::kInterpreterToBoolean, context, accumulator);
__ CallStub(callable.descriptor(), target, context, accumulator);
Node* index = __ BytecodeOperandIdx(0);
Node* constant = __ LoadConstantPoolEntry(index);
Node* relative_jump = __ SmiUntag(constant);

View File

@ -1847,6 +1847,7 @@ InterceptorInfo* JSObject::GetIndexedInterceptor() {
ACCESSORS(Oddball, to_string, String, kToStringOffset)
ACCESSORS(Oddball, to_number, Object, kToNumberOffset)
ACCESSORS(Oddball, to_boolean, Oddball, kToBooleanOffset)
ACCESSORS(Oddball, type_of, String, kTypeOfOffset)

View File

@ -13396,14 +13396,14 @@ Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
return builder.Finish().ToHandleChecked();
}
void Oddball::Initialize(Isolate* isolate, Handle<Oddball> oddball,
const char* to_string, Handle<Object> to_number,
const char* type_of, byte kind) {
bool to_boolean, const char* type_of, byte kind) {
Handle<String> internalized_to_string =
isolate->factory()->InternalizeUtf8String(to_string);
Handle<String> internalized_type_of =
isolate->factory()->InternalizeUtf8String(type_of);
oddball->set_to_boolean(isolate->heap()->ToBoolean(to_boolean));
oddball->set_to_number(*to_number);
oddball->set_to_string(*internalized_to_string);
oddball->set_type_of(*internalized_type_of);

View File

@ -9546,6 +9546,9 @@ class Oddball: public HeapObject {
// [to_number]: Cached to_number computed at startup.
DECL_ACCESSORS(to_number, Object)
// [to_number]: Cached to_boolean computed at startup.
DECL_ACCESSORS(to_boolean, Oddball)
// [typeof]: Cached type_of computed at startup.
DECL_ACCESSORS(type_of, String)
@ -9563,12 +9566,13 @@ class Oddball: public HeapObject {
// Initialize the fields.
static void Initialize(Isolate* isolate, Handle<Oddball> oddball,
const char* to_string, Handle<Object> to_number,
const char* type_of, byte kind);
bool to_boolean, const char* type_of, byte kind);
// Layout description.
static const int kToStringOffset = HeapObject::kHeaderSize;
static const int kToNumberOffset = kToStringOffset + kPointerSize;
static const int kTypeOfOffset = kToNumberOffset + kPointerSize;
static const int kToBooleanOffset = kToNumberOffset + kPointerSize;
static const int kTypeOfOffset = kToBooleanOffset + kPointerSize;
static const int kKindOffset = kTypeOfOffset + kPointerSize;
static const int kSize = kKindOffset + kPointerSize;

View File

@ -16,22 +16,6 @@
namespace v8 {
namespace internal {
RUNTIME_FUNCTION(Runtime_InterpreterToBoolean) {
SealHandleScope shs(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_CHECKED(Object, x, 0);
return isolate->heap()->ToBoolean(x->BooleanValue());
}
RUNTIME_FUNCTION(Runtime_InterpreterLogicalNot) {
SealHandleScope shs(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_CHECKED(Object, x, 0);
return isolate->heap()->ToBoolean(!x->BooleanValue());
}
RUNTIME_FUNCTION(Runtime_InterpreterNewClosure) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());

View File

@ -206,8 +206,6 @@ namespace internal {
F(ForInStep, 1, 1)
#define FOR_EACH_INTRINSIC_INTERPRETER(F) \
F(InterpreterToBoolean, 1, 1) \
F(InterpreterLogicalNot, 1, 1) \
F(InterpreterNewClosure, 2, 1) \
F(InterpreterTraceBytecodeEntry, 3, 1) \
F(InterpreterTraceBytecodeExit, 3, 1) \

View File

@ -71,7 +71,7 @@ class TypeFeedbackOracle: public ZoneObject {
Handle<JSFunction> GetCallNewTarget(FeedbackVectorSlot slot);
Handle<AllocationSite> GetCallNewAllocationSite(FeedbackVectorSlot slot);
// TODO(1571) We can't use ToBooleanStub::Types as the return value because
// TODO(1571) We can't use ToBooleanICStub::Types as the return value because
// of various cycles in our headers. Death to tons of implementations in
// headers!! :-P
uint16_t ToBooleanTypes(TypeFeedbackId id);

View File

@ -1,73 +0,0 @@
// 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.
#include "src/v8.h"
#include "src/factory.h"
#include "src/heap/heap.h"
#include "src/heap/heap-inl.h"
#include "src/runtime/runtime.h"
#include "test/unittests/test-utils.h"
namespace v8 {
namespace internal {
namespace interpreter {
class RuntimeInterpreterTest : public TestWithIsolateAndZone {
public:
typedef Object* (*RuntimeMethod)(int, Object**, Isolate*);
RuntimeInterpreterTest() {}
~RuntimeInterpreterTest() override {}
bool TestOperatorWithObjects(RuntimeMethod method, Handle<Object> lhs,
Handle<Object> rhs, bool expected);
};
bool RuntimeInterpreterTest::TestOperatorWithObjects(RuntimeMethod method,
Handle<Object> lhs,
Handle<Object> rhs,
bool expected) {
Object* args_object[] = {*rhs, *lhs};
Handle<Object> result =
handle(method(2, &args_object[1], isolate()), isolate());
CHECK(result->IsTrue() || result->IsFalse());
return result->IsTrue() == expected;
}
TEST_F(RuntimeInterpreterTest, ToBoolean) {
double quiet_nan = std::numeric_limits<double>::quiet_NaN();
std::pair<Handle<Object>, bool> cases[] = {
std::make_pair(isolate()->factory()->NewNumberFromInt(0), false),
std::make_pair(isolate()->factory()->NewNumberFromInt(1), true),
std::make_pair(isolate()->factory()->NewNumberFromInt(100), true),
std::make_pair(isolate()->factory()->NewNumberFromInt(-1), true),
std::make_pair(isolate()->factory()->NewNumber(7.7), true),
std::make_pair(isolate()->factory()->NewNumber(0.00001), true),
std::make_pair(isolate()->factory()->NewNumber(quiet_nan), false),
std::make_pair(isolate()->factory()->NewHeapNumber(0.0), false),
std::make_pair(isolate()->factory()->undefined_value(), false),
std::make_pair(isolate()->factory()->null_value(), false),
std::make_pair(isolate()->factory()->true_value(), true),
std::make_pair(isolate()->factory()->false_value(), false),
std::make_pair(isolate()->factory()->NewStringFromStaticChars(""), false),
std::make_pair(isolate()->factory()->NewStringFromStaticChars("_"), true),
};
for (size_t i = 0; i < arraysize(cases); i++) {
auto& value_expected_tuple = cases[i];
Object* args_object[] = {*value_expected_tuple.first};
Handle<Object> result = handle(
Runtime_InterpreterToBoolean(1, &args_object[0], isolate()), isolate());
CHECK(result->IsBoolean());
CHECK_EQ(result->IsTrue(), value_expected_tuple.second);
}
}
} // namespace interpreter
} // namespace internal
} // namespace v8

View File

@ -115,7 +115,6 @@
'heap/remembered-set-unittest.cc',
'locked-queue-unittest.cc',
'run-all-unittests.cc',
'runtime/runtime-interpreter-unittest.cc',
'test-utils.h',
'test-utils.cc',
'wasm/ast-decoder-unittest.cc',