Commit e61bd68e authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Introduce a dedicated ConvertTaggedHoleToUndefined operator.

Separate ConvertTaggedHoleToUndefined and CheckTaggedHole into two
separate operators, where the former is pure and just turns into
trivial control flow in the EffectControlLinearizer.

R=jarin@chromium.org

Review-Url: https://codereview.chromium.org/2236443004
Cr-Commit-Position: refs/heads/master@{#38559}
parent 73b0f157
...@@ -714,6 +714,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node, ...@@ -714,6 +714,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kCheckTaggedHole: case IrOpcode::kCheckTaggedHole:
state = LowerCheckTaggedHole(node, frame_state, *effect, *control); state = LowerCheckTaggedHole(node, frame_state, *effect, *control);
break; break;
case IrOpcode::kConvertTaggedHoleToUndefined:
state = LowerConvertTaggedHoleToUndefined(node, *effect, *control);
break;
case IrOpcode::kPlainPrimitiveToNumber: case IrOpcode::kPlainPrimitiveToNumber:
state = LowerPlainPrimitiveToNumber(node, *effect, *control); state = LowerPlainPrimitiveToNumber(node, *effect, *control);
break; break;
...@@ -2418,22 +2421,35 @@ EffectControlLinearizer::LowerCheckFloat64Hole(Node* node, Node* frame_state, ...@@ -2418,22 +2421,35 @@ EffectControlLinearizer::LowerCheckFloat64Hole(Node* node, Node* frame_state,
EffectControlLinearizer::ValueEffectControl EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckTaggedHole(Node* node, Node* frame_state, EffectControlLinearizer::LowerCheckTaggedHole(Node* node, Node* frame_state,
Node* effect, Node* control) { Node* effect, Node* control) {
CheckTaggedHoleMode mode = CheckTaggedHoleModeOf(node->op());
Node* value = node->InputAt(0); Node* value = node->InputAt(0);
Node* check = graph()->NewNode(machine()->WordEqual(), value, Node* check = graph()->NewNode(machine()->WordEqual(), value,
jsgraph()->TheHoleConstant()); jsgraph()->TheHoleConstant());
switch (mode) { control = effect =
case CheckTaggedHoleMode::kConvertHoleToUndefined: graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kHole), check,
value = graph()->NewNode( frame_state, effect, control);
common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse),
check, jsgraph()->UndefinedConstant(), value); return ValueEffectControl(value, effect, control);
break; }
case CheckTaggedHoleMode::kNeverReturnHole:
control = effect = EffectControlLinearizer::ValueEffectControl
graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kHole), EffectControlLinearizer::LowerConvertTaggedHoleToUndefined(Node* node,
check, frame_state, effect, control); Node* effect,
break; Node* control) {
} Node* value = node->InputAt(0);
Node* check = graph()->NewNode(machine()->WordEqual(), value,
jsgraph()->TheHoleConstant());
Node* branch =
graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* vtrue = jsgraph()->UndefinedConstant();
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* vfalse = value;
control = graph()->NewNode(common()->Merge(2), if_true, if_false);
value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
vtrue, vfalse, control);
return ValueEffectControl(value, effect, control); return ValueEffectControl(value, effect, control);
} }
......
...@@ -130,6 +130,8 @@ class EffectControlLinearizer { ...@@ -130,6 +130,8 @@ class EffectControlLinearizer {
Node* effect, Node* control); Node* effect, Node* control);
ValueEffectControl LowerCheckTaggedHole(Node* node, Node* frame_state, ValueEffectControl LowerCheckTaggedHole(Node* node, Node* frame_state,
Node* effect, Node* control); Node* effect, Node* control);
ValueEffectControl LowerConvertTaggedHoleToUndefined(Node* node, Node* effect,
Node* control);
ValueEffectControl LowerPlainPrimitiveToNumber(Node* node, Node* effect, ValueEffectControl LowerPlainPrimitiveToNumber(Node* node, Node* effect,
Node* control); Node* control);
ValueEffectControl LowerPlainPrimitiveToWord32(Node* node, Node* effect, ValueEffectControl LowerPlainPrimitiveToWord32(Node* node, Node* effect,
......
...@@ -1158,7 +1158,7 @@ JSNativeContextSpecialization::BuildElementAccess( ...@@ -1158,7 +1158,7 @@ JSNativeContextSpecialization::BuildElementAccess(
} }
// Compute the element access. // Compute the element access.
Type* element_type = Type::Any(); Type* element_type = Type::NonInternal();
MachineType element_machine_type = MachineType::AnyTagged(); MachineType element_machine_type = MachineType::AnyTagged();
if (IsFastDoubleElementsKind(elements_kind)) { if (IsFastDoubleElementsKind(elements_kind)) {
element_type = Type::Number(); element_type = Type::Number();
...@@ -1176,10 +1176,8 @@ JSNativeContextSpecialization::BuildElementAccess( ...@@ -1176,10 +1176,8 @@ JSNativeContextSpecialization::BuildElementAccess(
// of holey backing stores. // of holey backing stores.
if (elements_kind == FAST_HOLEY_ELEMENTS || if (elements_kind == FAST_HOLEY_ELEMENTS ||
elements_kind == FAST_HOLEY_SMI_ELEMENTS) { elements_kind == FAST_HOLEY_SMI_ELEMENTS) {
element_access.type = Type::Union( element_access.type =
element_type, Type::Union(element_type, Type::Hole(), graph()->zone());
Type::Constant(factory()->the_hole_value(), graph()->zone()),
graph()->zone());
} }
// Perform the actual backing store access. // Perform the actual backing store access.
value = effect = value = effect =
...@@ -1189,15 +1187,16 @@ JSNativeContextSpecialization::BuildElementAccess( ...@@ -1189,15 +1187,16 @@ JSNativeContextSpecialization::BuildElementAccess(
// the hole to undefined if possible, or deoptimizing otherwise. // the hole to undefined if possible, or deoptimizing otherwise.
if (elements_kind == FAST_HOLEY_ELEMENTS || if (elements_kind == FAST_HOLEY_ELEMENTS ||
elements_kind == FAST_HOLEY_SMI_ELEMENTS) { elements_kind == FAST_HOLEY_SMI_ELEMENTS) {
// Perform the hole check on the result.
CheckTaggedHoleMode mode = CheckTaggedHoleMode::kNeverReturnHole;
// Check if we are allowed to turn the hole into undefined. // Check if we are allowed to turn the hole into undefined.
if (CanTreatHoleAsUndefined(receiver_maps, native_context)) { if (CanTreatHoleAsUndefined(receiver_maps, native_context)) {
// Turn the hole into undefined. // Turn the hole into undefined.
mode = CheckTaggedHoleMode::kConvertHoleToUndefined; value = graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(),
value);
} else {
// Bailout if we see the hole.
value = effect = graph()->NewNode(simplified()->CheckTaggedHole(),
value, effect, control);
} }
value = effect = graph()->NewNode(simplified()->CheckTaggedHole(mode),
value, effect, control);
} else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) { } else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) {
// Perform the hole check on the result. // Perform the hole check on the result.
CheckFloat64HoleMode mode = CheckFloat64HoleMode::kNeverReturnHole; CheckFloat64HoleMode mode = CheckFloat64HoleMode::kNeverReturnHole;
......
...@@ -290,6 +290,7 @@ ...@@ -290,6 +290,7 @@
V(CheckTaggedSigned) \ V(CheckTaggedSigned) \
V(CheckFloat64Hole) \ V(CheckFloat64Hole) \
V(CheckTaggedHole) \ V(CheckTaggedHole) \
V(ConvertTaggedHoleToUndefined) \
V(Allocate) \ V(Allocate) \
V(LoadField) \ V(LoadField) \
V(LoadBuffer) \ V(LoadBuffer) \
......
...@@ -2392,17 +2392,29 @@ class RepresentationSelector { ...@@ -2392,17 +2392,29 @@ class RepresentationSelector {
return; return;
} }
case IrOpcode::kCheckTaggedHole: { case IrOpcode::kCheckTaggedHole: {
CheckTaggedHoleMode mode = CheckTaggedHoleModeOf(node->op()); VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
if (truncation.IsUsedAsWord32() && return;
mode == CheckTaggedHoleMode::kConvertHoleToUndefined) { }
ProcessInput(node, 0, UseInfo::CheckedSigned32AsWord32()); case IrOpcode::kConvertTaggedHoleToUndefined: {
ProcessRemainingInputs(node, 1); if (InputIs(node, Type::NumberOrOddball()) &&
SetOutput(node, MachineRepresentation::kWord32); truncation.IsUsedAsWord32()) {
// Propagate the Word32 truncation.
VisitUnop(node, UseInfo::TruncatingWord32(),
MachineRepresentation::kWord32);
if (lower()) DeferReplacement(node, node->InputAt(0));
} else if (InputIs(node, Type::NumberOrOddball()) &&
truncation.IsUsedAsFloat64()) {
// Propagate the Float64 truncation.
VisitUnop(node, UseInfo::TruncatingFloat64(),
MachineRepresentation::kFloat64);
if (lower()) DeferReplacement(node, node->InputAt(0));
} else if (InputIs(node, Type::NonInternal())) {
VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
if (lower()) DeferReplacement(node, node->InputAt(0)); if (lower()) DeferReplacement(node, node->InputAt(0));
} else { } else {
ProcessInput(node, 0, UseInfo::AnyTagged()); // TODO(turbofan): Add a (Tagged) truncation that identifies hole
ProcessRemainingInputs(node, 1); // and undefined, i.e. for a[i] === obj cases.
SetOutput(node, MachineRepresentation::kTagged); VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
} }
return; return;
} }
......
This diff is collapsed.
...@@ -119,17 +119,6 @@ std::ostream& operator<<(std::ostream&, CheckFloat64HoleMode); ...@@ -119,17 +119,6 @@ std::ostream& operator<<(std::ostream&, CheckFloat64HoleMode);
CheckFloat64HoleMode CheckFloat64HoleModeOf(const Operator*) WARN_UNUSED_RESULT; CheckFloat64HoleMode CheckFloat64HoleModeOf(const Operator*) WARN_UNUSED_RESULT;
enum class CheckTaggedHoleMode : uint8_t {
kNeverReturnHole, // Never return the hole (deoptimize instead).
kConvertHoleToUndefined // Convert the hole to undefined.
};
size_t hash_value(CheckTaggedHoleMode);
std::ostream& operator<<(std::ostream&, CheckTaggedHoleMode);
CheckTaggedHoleMode CheckTaggedHoleModeOf(const Operator*) WARN_UNUSED_RESULT;
enum class CheckTaggedInputMode : uint8_t { enum class CheckTaggedInputMode : uint8_t {
kNumber, kNumber,
kNumberOrOddball, kNumberOrOddball,
...@@ -339,7 +328,8 @@ class SimplifiedOperatorBuilder final : public ZoneObject { ...@@ -339,7 +328,8 @@ class SimplifiedOperatorBuilder final : public ZoneObject {
const Operator* CheckedTruncateTaggedToWord32(); const Operator* CheckedTruncateTaggedToWord32();
const Operator* CheckFloat64Hole(CheckFloat64HoleMode); const Operator* CheckFloat64Hole(CheckFloat64HoleMode);
const Operator* CheckTaggedHole(CheckTaggedHoleMode); const Operator* CheckTaggedHole();
const Operator* ConvertTaggedHoleToUndefined();
const Operator* ObjectIsCallable(); const Operator* ObjectIsCallable();
const Operator* ObjectIsNumber(); const Operator* ObjectIsNumber();
......
...@@ -1234,7 +1234,7 @@ Type* Typer::Visitor::WrapContextTypeForInput(Node* node) { ...@@ -1234,7 +1234,7 @@ Type* Typer::Visitor::WrapContextTypeForInput(Node* node) {
if (outer->Is(Type::None())) { if (outer->Is(Type::None())) {
return Type::None(); return Type::None();
} else { } else {
DCHECK(outer->Maybe(Type::Internal())); DCHECK(outer->Maybe(Type::OtherInternal()));
return Type::Context(outer, zone()); return Type::Context(outer, zone());
} }
} }
...@@ -1583,19 +1583,17 @@ Type* Typer::Visitor::TypeCheckFloat64Hole(Node* node) { ...@@ -1583,19 +1583,17 @@ Type* Typer::Visitor::TypeCheckFloat64Hole(Node* node) {
} }
Type* Typer::Visitor::TypeCheckTaggedHole(Node* node) { Type* Typer::Visitor::TypeCheckTaggedHole(Node* node) {
CheckTaggedHoleMode mode = CheckTaggedHoleModeOf(node->op());
Type* type = Operand(node, 0); Type* type = Operand(node, 0);
type = Type::Intersect(type, Type::NonInternal(), zone()); type = Type::Intersect(type, Type::NonInternal(), zone());
switch (mode) { return type;
case CheckTaggedHoleMode::kConvertHoleToUndefined: { }
// The hole is turned into undefined.
type = Type::Union(type, Type::Undefined(), zone()); Type* Typer::Visitor::TypeConvertTaggedHoleToUndefined(Node* node) {
break; Type* type = Operand(node, 0);
} if (type->Maybe(Type::Hole())) {
case CheckTaggedHoleMode::kNeverReturnHole: { // Turn "the hole" into undefined.
// We deoptimize in case of the hole. type = Type::Intersect(type, Type::NonInternal(), zone());
break; type = Type::Union(type, Type::Undefined(), zone());
}
} }
return type; return type;
} }
......
...@@ -1042,7 +1042,11 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -1042,7 +1042,11 @@ void Verifier::Visitor::Check(Node* node) {
break; break;
case IrOpcode::kCheckTaggedHole: case IrOpcode::kCheckTaggedHole:
CheckValueInputIs(node, 0, Type::Any()); CheckValueInputIs(node, 0, Type::Any());
CheckUpperIs(node, Type::Any()); CheckUpperIs(node, Type::NonInternal());
break;
case IrOpcode::kConvertTaggedHoleToUndefined:
CheckValueInputIs(node, 0, Type::Any());
CheckUpperIs(node, Type::NonInternal());
break; break;
case IrOpcode::kLoadField: case IrOpcode::kLoadField:
......
...@@ -2609,6 +2609,8 @@ void Heap::CreateInitialObjects() { ...@@ -2609,6 +2609,8 @@ void Heap::CreateInitialObjects() {
set_nan_value(*factory->NewHeapNumber( set_nan_value(*factory->NewHeapNumber(
std::numeric_limits<double>::quiet_NaN(), IMMUTABLE, TENURED)); std::numeric_limits<double>::quiet_NaN(), IMMUTABLE, TENURED));
set_hole_nan_value(*factory->NewHeapNumber(bit_cast<double>(kHoleNanInt64),
IMMUTABLE, TENURED));
set_infinity_value(*factory->NewHeapNumber(V8_INFINITY, IMMUTABLE, TENURED)); set_infinity_value(*factory->NewHeapNumber(V8_INFINITY, IMMUTABLE, TENURED));
set_minus_infinity_value( set_minus_infinity_value(
*factory->NewHeapNumber(-V8_INFINITY, IMMUTABLE, TENURED)); *factory->NewHeapNumber(-V8_INFINITY, IMMUTABLE, TENURED));
...@@ -2629,7 +2631,7 @@ void Heap::CreateInitialObjects() { ...@@ -2629,7 +2631,7 @@ void Heap::CreateInitialObjects() {
// Initialize the_hole_value. // Initialize the_hole_value.
Oddball::Initialize(isolate(), factory->the_hole_value(), "hole", Oddball::Initialize(isolate(), factory->the_hole_value(), "hole",
handle(Smi::FromInt(-1), isolate()), "undefined", factory->hole_nan_value(), "undefined",
Oddball::kTheHole); Oddball::kTheHole);
// Initialize the true_value. // Initialize the true_value.
......
...@@ -166,6 +166,7 @@ using v8::MemoryPressureLevel; ...@@ -166,6 +166,7 @@ using v8::MemoryPressureLevel;
V(Cell, species_protector, SpeciesProtector) \ V(Cell, species_protector, SpeciesProtector) \
/* Special numbers */ \ /* Special numbers */ \
V(HeapNumber, nan_value, NanValue) \ V(HeapNumber, nan_value, NanValue) \
V(HeapNumber, hole_nan_value, HoleNanValue) \
V(HeapNumber, infinity_value, InfinityValue) \ V(HeapNumber, infinity_value, InfinityValue) \
V(HeapNumber, minus_zero_value, MinusZeroValue) \ V(HeapNumber, minus_zero_value, MinusZeroValue) \
V(HeapNumber, minus_infinity_value, MinusInfinityValue) \ V(HeapNumber, minus_infinity_value, MinusInfinityValue) \
......
...@@ -601,7 +601,8 @@ void Oddball::OddballVerify() { ...@@ -601,7 +601,8 @@ void Oddball::OddballVerify() {
VerifyHeapPointer(to_string()); VerifyHeapPointer(to_string());
Object* number = to_number(); Object* number = to_number();
if (number->IsHeapObject()) { if (number->IsHeapObject()) {
CHECK(number == heap->nan_value()); CHECK(number == heap->nan_value() ||
number == heap->hole_nan_value());
} else { } else {
CHECK(number->IsSmi()); CHECK(number->IsSmi());
int value = Smi::cast(number)->value(); int value = Smi::cast(number)->value();
......
...@@ -147,10 +147,10 @@ Type::bitset BitsetType::Lub(Type* type) { ...@@ -147,10 +147,10 @@ Type::bitset BitsetType::Lub(Type* type) {
if (type->IsClass()) return type->AsClass()->Lub(); if (type->IsClass()) return type->AsClass()->Lub();
if (type->IsConstant()) return type->AsConstant()->Lub(); if (type->IsConstant()) return type->AsConstant()->Lub();
if (type->IsRange()) return type->AsRange()->Lub(); if (type->IsRange()) return type->AsRange()->Lub();
if (type->IsContext()) return kInternal & kTaggedPointer; if (type->IsContext()) return kOtherInternal & kTaggedPointer;
if (type->IsArray()) return kOtherObject; if (type->IsArray()) return kOtherObject;
if (type->IsFunction()) return kFunction; if (type->IsFunction()) return kFunction;
if (type->IsTuple()) return kInternal; if (type->IsTuple()) return kOtherInternal;
UNREACHABLE(); UNREACHABLE();
return kNone; return kNone;
} }
...@@ -187,14 +187,14 @@ Type::bitset BitsetType::Lub(i::Map* map) { ...@@ -187,14 +187,14 @@ Type::bitset BitsetType::Lub(i::Map* map) {
if (map == heap->undefined_map()) return kUndefined; if (map == heap->undefined_map()) return kUndefined;
if (map == heap->null_map()) return kNull; if (map == heap->null_map()) return kNull;
if (map == heap->boolean_map()) return kBoolean; if (map == heap->boolean_map()) return kBoolean;
DCHECK(map == heap->the_hole_map() || if (map == heap->the_hole_map()) return kHole;
map == heap->uninitialized_map() || DCHECK(map == heap->uninitialized_map() ||
map == heap->no_interceptor_result_sentinel_map() || map == heap->no_interceptor_result_sentinel_map() ||
map == heap->termination_exception_map() || map == heap->termination_exception_map() ||
map == heap->arguments_marker_map() || map == heap->arguments_marker_map() ||
map == heap->optimized_out_map() || map == heap->optimized_out_map() ||
map == heap->stale_register_map()); map == heap->stale_register_map());
return kInternal & kTaggedPointer; return kOtherInternal & kTaggedPointer;
} }
case HEAP_NUMBER_TYPE: case HEAP_NUMBER_TYPE:
return kNumber & kTaggedPointer; return kNumber & kTaggedPointer;
...@@ -250,10 +250,10 @@ Type::bitset BitsetType::Lub(i::Map* map) { ...@@ -250,10 +250,10 @@ Type::bitset BitsetType::Lub(i::Map* map) {
case SCRIPT_TYPE: case SCRIPT_TYPE:
case CODE_TYPE: case CODE_TYPE:
case PROPERTY_CELL_TYPE: case PROPERTY_CELL_TYPE:
return kInternal & kTaggedPointer; return kOtherInternal & kTaggedPointer;
// Remaining instance types are unsupported for now. If any of them do // Remaining instance types are unsupported for now. If any of them do
// require bit set types, they should get kInternal & kTaggedPointer. // require bit set types, they should get kOtherInternal & kTaggedPointer.
case MUTABLE_HEAP_NUMBER_TYPE: case MUTABLE_HEAP_NUMBER_TYPE:
case FREE_SPACE_TYPE: case FREE_SPACE_TYPE:
#define FIXED_TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ #define FIXED_TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
......
...@@ -199,7 +199,8 @@ namespace internal { ...@@ -199,7 +199,8 @@ namespace internal {
V(OtherUndetectable, 1u << 16 | REPRESENTATION(kTaggedPointer)) \ V(OtherUndetectable, 1u << 16 | REPRESENTATION(kTaggedPointer)) \
V(Proxy, 1u << 18 | REPRESENTATION(kTaggedPointer)) \ V(Proxy, 1u << 18 | REPRESENTATION(kTaggedPointer)) \
V(Function, 1u << 19 | REPRESENTATION(kTaggedPointer)) \ V(Function, 1u << 19 | REPRESENTATION(kTaggedPointer)) \
V(Internal, 1u << 20 | REPRESENTATION(kTagged | kUntagged)) \ V(Hole, 1u << 20 | REPRESENTATION(kTaggedPointer)) \
V(OtherInternal, 1u << 21 | REPRESENTATION(kTagged | kUntagged)) \
\ \
V(Signed31, kUnsigned30 | kNegative31) \ V(Signed31, kUnsigned30 | kNegative31) \
V(Signed32, kSigned31 | kOtherUnsigned31 | kOtherSigned32) \ V(Signed32, kSigned31 | kOtherUnsigned31 | kOtherSigned32) \
...@@ -225,7 +226,7 @@ namespace internal { ...@@ -225,7 +226,7 @@ namespace internal {
V(NullOrNumber, kNull | kNumber) \ V(NullOrNumber, kNull | kNumber) \
V(NullOrUndefined, kNull | kUndefined) \ V(NullOrUndefined, kNull | kUndefined) \
V(Undetectable, kNullOrUndefined | kOtherUndetectable) \ V(Undetectable, kNullOrUndefined | kOtherUndetectable) \
V(NumberOrOddball, kNumber | kNullOrUndefined | kBoolean) \ V(NumberOrOddball, kNumber | kNullOrUndefined | kBoolean | kHole) \
V(NumberOrSimdOrString, kNumber | kSimd | kString) \ V(NumberOrSimdOrString, kNumber | kSimd | kString) \
V(NumberOrString, kNumber | kString) \ V(NumberOrString, kNumber | kString) \
V(NumberOrUndefined, kNumber | kUndefined) \ V(NumberOrUndefined, kNumber | kUndefined) \
...@@ -237,6 +238,7 @@ namespace internal { ...@@ -237,6 +238,7 @@ namespace internal {
V(StringOrReceiver, kString | kReceiver) \ V(StringOrReceiver, kString | kReceiver) \
V(Unique, kBoolean | kUniqueName | kNull | kUndefined | \ V(Unique, kBoolean | kUniqueName | kNull | kUndefined | \
kReceiver) \ kReceiver) \
V(Internal, kHole | kOtherInternal) \
V(NonInternal, kPrimitive | kReceiver) \ V(NonInternal, kPrimitive | kReceiver) \
V(NonNumber, kUnique | kString | kInternal) \ V(NonNumber, kUnique | kString | kInternal) \
V(Any, 0xfffffffeu) V(Any, 0xfffffffeu)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment