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() { ...@@ -268,6 +268,17 @@ FieldAccess AccessBuilder::ForJSTypedArrayLength() {
return access; return access;
} }
// static
FieldAccess AccessBuilder::ForJSDateValue() {
FieldAccess access = {kTaggedBase,
JSDate::kValueOffset,
MaybeHandle<Name>(),
TypeCache::Get().kJSDateValueType,
MachineType::AnyTagged(),
kFullWriteBarrier};
return access;
}
// static // static
FieldAccess AccessBuilder::ForJSDateField(JSDate::FieldIndex index) { FieldAccess AccessBuilder::ForJSDateField(JSDate::FieldIndex index) {
FieldAccess access = {kTaggedBase, FieldAccess access = {kTaggedBase,
......
...@@ -89,6 +89,9 @@ class AccessBuilder final : public AllStatic { ...@@ -89,6 +89,9 @@ class AccessBuilder final : public AllStatic {
// Provides access to JSTypedArray::length() field. // Provides access to JSTypedArray::length() field.
static FieldAccess ForJSTypedArrayLength(); static FieldAccess ForJSTypedArrayLength();
// Provides access to JSDate::value() field.
static FieldAccess ForJSDateValue();
// Provides access to JSDate fields. // Provides access to JSDate fields.
static FieldAccess ForJSDateField(JSDate::FieldIndex index); static FieldAccess ForJSDateField(JSDate::FieldIndex index);
......
...@@ -314,6 +314,67 @@ Reduction JSBuiltinReducer::ReduceArrayPush(Node* node) { ...@@ -314,6 +314,67 @@ Reduction JSBuiltinReducer::ReduceArrayPush(Node* node) {
return NoChange(); 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 ) // ES6 section 20.2.2.1 Math.abs ( x )
Reduction JSBuiltinReducer::ReduceMathAbs(Node* node) { Reduction JSBuiltinReducer::ReduceMathAbs(Node* node) {
JSCallReduction r(node); JSCallReduction r(node);
...@@ -878,51 +939,6 @@ Reduction JSBuiltinReducer::ReduceStringCharCodeAt(Node* node) { ...@@ -878,51 +939,6 @@ Reduction JSBuiltinReducer::ReduceStringCharCodeAt(Node* node) {
return NoChange(); 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( Reduction JSBuiltinReducer::ReduceArrayBufferViewAccessor(
Node* node, InstanceType instance_type, FieldAccess const& access) { Node* node, InstanceType instance_type, FieldAccess const& access) {
Node* receiver = NodeProperties::GetValueInput(node, 1); Node* receiver = NodeProperties::GetValueInput(node, 1);
...@@ -963,6 +979,8 @@ Reduction JSBuiltinReducer::Reduce(Node* node) { ...@@ -963,6 +979,8 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
return ReduceArrayPop(node); return ReduceArrayPop(node);
case kArrayPush: case kArrayPush:
return ReduceArrayPush(node); return ReduceArrayPush(node);
case kDateGetTime:
return ReduceDateGetTime(node);
case kMathAbs: case kMathAbs:
reduction = ReduceMathAbs(node); reduction = ReduceMathAbs(node);
break; break;
......
...@@ -42,6 +42,7 @@ class JSBuiltinReducer final : public AdvancedReducer { ...@@ -42,6 +42,7 @@ class JSBuiltinReducer final : public AdvancedReducer {
private: private:
Reduction ReduceArrayPop(Node* node); Reduction ReduceArrayPop(Node* node);
Reduction ReduceArrayPush(Node* node); Reduction ReduceArrayPush(Node* node);
Reduction ReduceDateGetTime(Node* node);
Reduction ReduceMathAbs(Node* node); Reduction ReduceMathAbs(Node* node);
Reduction ReduceMathAcos(Node* node); Reduction ReduceMathAcos(Node* node);
Reduction ReduceMathAcosh(Node* node); Reduction ReduceMathAcosh(Node* node);
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef V8_COMPILER_TYPE_CACHE_H_ #ifndef V8_COMPILER_TYPE_CACHE_H_
#define V8_COMPILER_TYPE_CACHE_H_ #define V8_COMPILER_TYPE_CACHE_H_
#include "src/date.h"
#include "src/types.h" #include "src/types.h"
namespace v8 { namespace v8 {
...@@ -103,6 +104,12 @@ class TypeCache final { ...@@ -103,6 +104,12 @@ class TypeCache final {
Type* const kStringLengthType = Type* const kStringLengthType =
CreateNative(CreateRange(0.0, String::kMaxLength), Type::TaggedSigned()); 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) \ #define TYPED_ARRAY(TypeName, type_name, TYPE_NAME, ctype, size) \
Type* const k##TypeName##Array = CreateArray(k##TypeName); Type* const k##TypeName##Array = CreateArray(k##TypeName);
TYPED_ARRAYS(TYPED_ARRAY) TYPED_ARRAYS(TYPED_ARRAY)
......
...@@ -1335,6 +1335,27 @@ Type* Typer::Visitor::JSCallFunctionTyper(Type* fun, Typer* t) { ...@@ -1335,6 +1335,27 @@ Type* Typer::Visitor::JSCallFunctionTyper(Type* fun, Typer* t) {
return Type::Signed32(); return Type::Signed32();
case kMathClz32: case kMathClz32:
return t->cache_.kZeroToThirtyTwo; 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. // Number functions.
case kNumberParseInt: case kNumberParseInt:
return t->cache_.kIntegerOrMinusZeroOrNaN; return t->cache_.kIntegerOrMinusZeroOrNaN;
......
...@@ -6882,6 +6882,13 @@ class Script: public Struct { ...@@ -6882,6 +6882,13 @@ class Script: public Struct {
V(Array.prototype, push, ArrayPush) \ V(Array.prototype, push, ArrayPush) \
V(Array.prototype, pop, ArrayPop) \ V(Array.prototype, pop, ArrayPop) \
V(Array.prototype, shift, ArrayShift) \ 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, apply, FunctionApply) \
V(Function.prototype, call, FunctionCall) \ V(Function.prototype, call, FunctionCall) \
V(Object.prototype, hasOwnProperty, ObjectHasOwnProperty) \ 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