[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:
parent
4d659edfcd
commit
d1df58e8d7
@ -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;
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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); \
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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(¬_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;
|
||||
|
@ -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;
|
||||
|
@ -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(¬_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, ¬_heap_number);
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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(¬_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),
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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(¬_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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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(¬_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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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(¬_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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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(¬_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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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(¬_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),
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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++) {
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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) \
|
||||
|
@ -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);
|
||||
|
@ -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
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user