Commit 529f4c87 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Assign appropriate types to some Date builtins.

Infer exact types for the various Date getter builtins, and also inline
the Date.prototype.getTime() builtin, which just returns the Date value
and thus doesn't need to check the cache stamp.

R=epertoso@chromium.org

Review-Url: https://codereview.chromium.org/2285213002
Cr-Commit-Position: refs/heads/master@{#38973}
parent 93358294
......@@ -268,6 +268,17 @@ FieldAccess AccessBuilder::ForJSTypedArrayLength() {
return access;
}
// static
FieldAccess AccessBuilder::ForJSDateValue() {
FieldAccess access = {kTaggedBase,
JSDate::kValueOffset,
MaybeHandle<Name>(),
TypeCache::Get().kJSDateValueType,
MachineType::AnyTagged(),
kFullWriteBarrier};
return access;
}
// static
FieldAccess AccessBuilder::ForJSDateField(JSDate::FieldIndex index) {
FieldAccess access = {kTaggedBase,
......
......@@ -89,6 +89,9 @@ class AccessBuilder final : public AllStatic {
// Provides access to JSTypedArray::length() field.
static FieldAccess ForJSTypedArrayLength();
// Provides access to JSDate::value() field.
static FieldAccess ForJSDateValue();
// Provides access to JSDate fields.
static FieldAccess ForJSDateField(JSDate::FieldIndex index);
......
......@@ -314,6 +314,67 @@ Reduction JSBuiltinReducer::ReduceArrayPush(Node* node) {
return NoChange();
}
namespace {
bool HasInstanceTypeWitness(Node* receiver, Node* effect,
InstanceType instance_type) {
for (Node* dominator = effect;;) {
if (dominator->opcode() == IrOpcode::kCheckMaps &&
dominator->InputAt(0) == receiver) {
// Check if all maps have the given {instance_type}.
for (int i = 1; i < dominator->op()->ValueInputCount(); ++i) {
Node* const map = NodeProperties::GetValueInput(dominator, i);
Type* const map_type = NodeProperties::GetType(map);
if (!map_type->IsConstant()) return false;
Handle<Map> const map_value =
Handle<Map>::cast(map_type->AsConstant()->Value());
if (map_value->instance_type() != instance_type) return false;
}
return true;
}
switch (dominator->opcode()) {
case IrOpcode::kStoreField: {
FieldAccess const& access = FieldAccessOf(dominator->op());
if (access.base_is_tagged == kTaggedBase &&
access.offset == HeapObject::kMapOffset) {
return false;
}
break;
}
case IrOpcode::kStoreElement:
case IrOpcode::kStoreTypedElement:
break;
default: {
DCHECK_EQ(1, dominator->op()->EffectOutputCount());
if (dominator->op()->EffectInputCount() != 1 ||
!dominator->op()->HasProperty(Operator::kNoWrite)) {
// Didn't find any appropriate CheckMaps node.
return false;
}
break;
}
}
dominator = NodeProperties::GetEffectInput(dominator);
}
}
} // namespace
// ES6 section 20.3.4.10 Date.prototype.getTime ( )
Reduction JSBuiltinReducer::ReduceDateGetTime(Node* node) {
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
if (HasInstanceTypeWitness(receiver, effect, JS_DATE_TYPE)) {
Node* value = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSDateValue()), receiver,
effect, control);
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
return NoChange();
}
// ES6 section 20.2.2.1 Math.abs ( x )
Reduction JSBuiltinReducer::ReduceMathAbs(Node* node) {
JSCallReduction r(node);
......@@ -878,51 +939,6 @@ Reduction JSBuiltinReducer::ReduceStringCharCodeAt(Node* node) {
return NoChange();
}
namespace {
bool HasInstanceTypeWitness(Node* receiver, Node* effect,
InstanceType instance_type) {
for (Node* dominator = effect;;) {
if (dominator->opcode() == IrOpcode::kCheckMaps &&
dominator->InputAt(0) == receiver) {
// Check if all maps have the given {instance_type}.
for (int i = 1; i < dominator->op()->ValueInputCount(); ++i) {
Node* const map = NodeProperties::GetValueInput(dominator, i);
Type* const map_type = NodeProperties::GetType(map);
if (!map_type->IsConstant()) return false;
Handle<Map> const map_value =
Handle<Map>::cast(map_type->AsConstant()->Value());
if (map_value->instance_type() != instance_type) return false;
}
return true;
}
switch (dominator->opcode()) {
case IrOpcode::kStoreField: {
FieldAccess const& access = FieldAccessOf(dominator->op());
if (access.base_is_tagged == kTaggedBase &&
access.offset == HeapObject::kMapOffset) {
return false;
}
break;
}
case IrOpcode::kStoreElement:
break;
default: {
DCHECK_EQ(1, dominator->op()->EffectOutputCount());
if (dominator->op()->EffectInputCount() != 1 ||
!dominator->op()->HasProperty(Operator::kNoWrite)) {
// Didn't find any appropriate CheckMaps node.
return false;
}
break;
}
}
dominator = NodeProperties::GetEffectInput(dominator);
}
}
} // namespace
Reduction JSBuiltinReducer::ReduceArrayBufferViewAccessor(
Node* node, InstanceType instance_type, FieldAccess const& access) {
Node* receiver = NodeProperties::GetValueInput(node, 1);
......@@ -963,6 +979,8 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
return ReduceArrayPop(node);
case kArrayPush:
return ReduceArrayPush(node);
case kDateGetTime:
return ReduceDateGetTime(node);
case kMathAbs:
reduction = ReduceMathAbs(node);
break;
......
......@@ -42,6 +42,7 @@ class JSBuiltinReducer final : public AdvancedReducer {
private:
Reduction ReduceArrayPop(Node* node);
Reduction ReduceArrayPush(Node* node);
Reduction ReduceDateGetTime(Node* node);
Reduction ReduceMathAbs(Node* node);
Reduction ReduceMathAcos(Node* node);
Reduction ReduceMathAcosh(Node* node);
......
......@@ -5,6 +5,7 @@
#ifndef V8_COMPILER_TYPE_CACHE_H_
#define V8_COMPILER_TYPE_CACHE_H_
#include "src/date.h"
#include "src/types.h"
namespace v8 {
......@@ -103,6 +104,12 @@ class TypeCache final {
Type* const kStringLengthType =
CreateNative(CreateRange(0.0, String::kMaxLength), Type::TaggedSigned());
// The JSDate::value properties always contains a tagged number in the range
// [-kMaxTimeInMs, kMaxTimeInMs] or NaN.
Type* const kJSDateValueType = Type::Union(
CreateRange(-DateCache::kMaxTimeInMs, DateCache::kMaxTimeInMs),
Type::NaN(), zone());
#define TYPED_ARRAY(TypeName, type_name, TYPE_NAME, ctype, size) \
Type* const k##TypeName##Array = CreateArray(k##TypeName);
TYPED_ARRAYS(TYPED_ARRAY)
......
......@@ -1335,6 +1335,27 @@ Type* Typer::Visitor::JSCallFunctionTyper(Type* fun, Typer* t) {
return Type::Signed32();
case kMathClz32:
return t->cache_.kZeroToThirtyTwo;
// Date functions.
case kDateGetFullYear:
return Type::Union(Type::Range(-271821.0, 275760.0, t->zone()),
Type::NaN(), t->zone());
case kDateGetDate:
return Type::Union(Type::Range(1.0, 31.0, t->zone()), Type::NaN(),
t->zone());
case kDateGetHours:
return Type::Union(Type::Range(0.0, 23.0, t->zone()), Type::NaN(),
t->zone());
case kDateGetMilliseconds:
return Type::Union(Type::Range(0.0, 59.0, t->zone()), Type::NaN(),
t->zone());
case kDateGetMonth:
return Type::Union(Type::Range(0.0, 11.0, t->zone()), Type::NaN(),
t->zone());
case kDateGetSeconds:
return Type::Union(Type::Range(0.0, 59.0, t->zone()), Type::NaN(),
t->zone());
case kDateGetTime:
return t->cache_.kJSDateValueType;
// Number functions.
case kNumberParseInt:
return t->cache_.kIntegerOrMinusZeroOrNaN;
......
......@@ -6882,6 +6882,13 @@ class Script: public Struct {
V(Array.prototype, push, ArrayPush) \
V(Array.prototype, pop, ArrayPop) \
V(Array.prototype, shift, ArrayShift) \
V(Date.prototype, getDate, DateGetDate) \
V(Date.prototype, getFullYear, DateGetFullYear) \
V(Date.prototype, getHours, DateGetHours) \
V(Date.prototype, getMilliseconds, DateGetMilliseconds) \
V(Date.prototype, getMonth, DateGetMonth) \
V(Date.prototype, getSeconds, DateGetSeconds) \
V(Date.prototype, getTime, DateGetTime) \
V(Function.prototype, apply, FunctionApply) \
V(Function.prototype, call, FunctionCall) \
V(Object.prototype, hasOwnProperty, ObjectHasOwnProperty) \
......
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