Commit 39877060 authored by dslomov@chromium.org's avatar dslomov@chromium.org

Speed up ArrayBuffer/typed array/DataView properties.

Optimizes byteLength, byteOffset, buffer and other properties on
ArrayBuffer, typed arrays and DataView into simple field loads. Some
unification with the way Array.length and String.length are treated.

R=verwaest@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16930 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 7fd3d6ad
......@@ -78,6 +78,61 @@ MaybeObject* Accessors::ReadOnlySetAccessor(Isolate* isolate,
}
static V8_INLINE bool CheckForName(Handle<String> name,
String* property_name,
int offset,
int* object_offset) {
if (name->Equals(property_name)) {
*object_offset = offset;
return true;
}
return false;
}
bool Accessors::IsJSObjectFieldAccessor(
Handle<Map> map, Handle<String> name,
int* object_offset) {
Isolate* isolate = map->GetIsolate();
switch (map->instance_type()) {
case JS_ARRAY_TYPE:
return
CheckForName(name, isolate->heap()->length_string(),
JSArray::kLengthOffset, object_offset);
case JS_TYPED_ARRAY_TYPE:
return
CheckForName(name, isolate->heap()->length_string(),
JSTypedArray::kLengthOffset, object_offset) ||
CheckForName(name, isolate->heap()->byte_length_string(),
JSTypedArray::kByteLengthOffset, object_offset) ||
CheckForName(name, isolate->heap()->byte_offset_string(),
JSTypedArray::kByteOffsetOffset, object_offset) ||
CheckForName(name, isolate->heap()->buffer_string(),
JSTypedArray::kBufferOffset, object_offset);
case JS_ARRAY_BUFFER_TYPE:
return
CheckForName(name, isolate->heap()->byte_length_string(),
JSArrayBuffer::kByteLengthOffset, object_offset);
case JS_DATA_VIEW_TYPE:
return
CheckForName(name, isolate->heap()->byte_length_string(),
JSDataView::kByteLengthOffset, object_offset) ||
CheckForName(name, isolate->heap()->byte_offset_string(),
JSDataView::kByteOffsetOffset, object_offset) ||
CheckForName(name, isolate->heap()->buffer_string(),
JSDataView::kBufferOffset, object_offset);
default: {
if (map->instance_type() < FIRST_NONSTRING_TYPE) {
return
CheckForName(name, isolate->heap()->length_string(),
String::kLengthOffset, object_offset);
}
return false;
}
}
}
//
// Accessors::ArrayLength
//
......
......@@ -86,6 +86,13 @@ class Accessors : public AllStatic {
static Handle<AccessorInfo> MakeModuleExport(
Handle<String> name, int index, PropertyAttributes attributes);
// Returns true for properties that are accessors to object fields.
// If true, *object_offset contains offset of object field.
static bool IsJSObjectFieldAccessor(
Handle<Map> map, Handle<String> name,
int* object_offset);
private:
// Accessor functions only used through the descriptor.
static MaybeObject* FunctionSetPrototype(Isolate* isolate,
......
......@@ -292,7 +292,10 @@ namespace internal {
V(throw_string, "throw") \
V(done_string, "done") \
V(value_string, "value") \
V(next_string, "next")
V(next_string, "next") \
V(byte_length_string, "byteLength") \
V(byte_offset_string, "byteOffset") \
V(buffer_string, "buffer")
// Forward declarations.
class GCTracer;
......
......@@ -5626,13 +5626,6 @@ class HObjectAccess V8_FINAL {
? Representation::Smi() : Representation::Tagged());
}
static HObjectAccess ForTypedArrayLength() {
return HObjectAccess(
kInobject,
JSTypedArray::kLengthOffset,
Representation::Tagged());
}
static HObjectAccess ForAllocationSiteTransitionInfo() {
return HObjectAccess(kInobject, AllocationSite::kTransitionInfoOffset);
}
......
......@@ -4766,7 +4766,7 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() {
bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadMonomorphic() {
if (!CanInlinePropertyAccess(*map_)) return IsStringLength();
if (IsArrayLength()) return true;
if (IsJSObjectFieldAccessor()) return true;
if (!LookupDescriptor()) return false;
if (lookup_.IsFound()) return true;
return LookupInPrototypes();
......@@ -4798,9 +4798,10 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic(
return true;
}
if (IsTypedArrayLength()) {
if (IsJSObjectFieldAccessor()) {
InstanceType instance_type = map_->instance_type();
for (int i = 1; i < types->length(); ++i) {
if (types->at(i)->instance_type() != JS_TYPED_ARRAY_TYPE) return false;
if (types->at(i)->instance_type() != instance_type) return false;
}
return true;
}
......@@ -4821,20 +4822,10 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadMonomorphic(
BailoutId ast_id,
BailoutId return_id,
bool can_inline_accessor) {
if (info->IsStringLength()) {
return New<HLoadNamedField>(
checked_object, HObjectAccess::ForStringLength());
}
if (info->IsArrayLength()) {
return New<HLoadNamedField>(
checked_object, HObjectAccess::ForArrayLength(
info->map()->elements_kind()));
}
if (info->IsTypedArrayLength()) {
return New<HLoadNamedField>(
checked_object, HObjectAccess::ForTypedArrayLength());
HObjectAccess access = HObjectAccess::ForMap(); // bogus default
if (info->GetJSObjectFieldAccess(&access)) {
return New<HLoadNamedField>(checked_object, access);
}
HValue* checked_holder = checked_object;
......@@ -5537,16 +5528,6 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedGeneric(
}
HInstruction* HOptimizedGraphBuilder::BuildCallGetter(
HValue* object,
Handle<Map> map,
Handle<JSFunction> getter,
Handle<JSObject> holder) {
AddCheckConstantFunction(holder, object, map);
Add<HPushArgument>(object);
return new(zone()) HCallConstantFunction(getter, 1);
}
HInstruction* HOptimizedGraphBuilder::BuildLoadKeyedGeneric(HValue* object,
HValue* key) {
......
......@@ -30,6 +30,7 @@
#include "v8.h"
#include "accessors.h"
#include "allocation.h"
#include "ast.h"
#include "compiler.h"
......@@ -2046,19 +2047,26 @@ class HOptimizedGraphBuilder V8_FINAL
// PropertyAccessInfo is built for types->first().
bool CanLoadAsMonomorphic(SmallMapList* types);
bool IsStringLength() {
return map_->instance_type() < FIRST_NONSTRING_TYPE &&
name_->Equals(isolate()->heap()->length_string());
bool IsJSObjectFieldAccessor() {
int offset; // unused
return Accessors::IsJSObjectFieldAccessor(map_, name_, &offset);
}
bool IsArrayLength() {
return map_->instance_type() == JS_ARRAY_TYPE &&
name_->Equals(isolate()->heap()->length_string());
}
bool IsTypedArrayLength() {
return map_->instance_type() == JS_TYPED_ARRAY_TYPE &&
name_->Equals(isolate()->heap()->length_string());
bool GetJSObjectFieldAccess(HObjectAccess* access) {
if (IsStringLength()) {
*access = HObjectAccess::ForStringLength();
return true;
} else if (IsArrayLength()) {
*access = HObjectAccess::ForArrayLength(map_->elements_kind());
return true;
} else {
int offset;
if (Accessors::IsJSObjectFieldAccessor(map_, name_, &offset)) {
*access = HObjectAccess::ForJSObjectOffset(offset);
return true;
}
return false;
}
}
bool has_holder() { return !holder_.is_null(); }
......@@ -2073,6 +2081,16 @@ class HOptimizedGraphBuilder V8_FINAL
private:
Isolate* isolate() { return lookup_.isolate(); }
bool IsStringLength() {
return map_->instance_type() < FIRST_NONSTRING_TYPE &&
name_->Equals(isolate()->heap()->length_string());
}
bool IsArrayLength() {
return map_->instance_type() == JS_ARRAY_TYPE &&
name_->Equals(isolate()->heap()->length_string());
}
bool LoadResult(Handle<Map> map);
bool LookupDescriptor();
bool LookupInPrototypes();
......@@ -2173,10 +2191,6 @@ class HOptimizedGraphBuilder V8_FINAL
HInstruction* BuildLoadNamedGeneric(HValue* object,
Handle<String> name,
Property* expr);
HInstruction* BuildCallGetter(HValue* object,
Handle<Map> map,
Handle<JSFunction> getter,
Handle<JSObject> holder);
HCheckMaps* AddCheckMap(HValue* object, Handle<Map> map);
......
......@@ -1348,20 +1348,19 @@ Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup,
if (!holder.is_identical_to(receiver)) break;
return isolate()->stub_cache()->ComputeLoadNormal(name, receiver);
case CALLBACKS: {
Handle<Object> callback(lookup->GetCallbackObject(), isolate());
if (name->Equals(isolate()->heap()->length_string())) {
if (receiver->IsJSArray()) {
PropertyIndex lengthIndex = PropertyIndex::NewHeaderIndex(
JSArray::kLengthOffset / kPointerSize);
return isolate()->stub_cache()->ComputeLoadField(
name, receiver, receiver, lengthIndex, Representation::Tagged());
} else if (receiver->IsJSTypedArray()) {
PropertyIndex lengthIndex = PropertyIndex::NewHeaderIndex(
JSTypedArray::kLengthOffset / kPointerSize);
{
// Use simple field loads for some well-known callback properties.
int object_offset;
Handle<Map> map(receiver->map());
if (Accessors::IsJSObjectFieldAccessor(map, name, &object_offset)) {
PropertyIndex index =
PropertyIndex::NewHeaderIndex(object_offset / kPointerSize);
return isolate()->stub_cache()->ComputeLoadField(
name, receiver, receiver, lengthIndex, Representation::Tagged());
name, receiver, receiver, index, Representation::Tagged());
}
}
Handle<Object> callback(lookup->GetCallbackObject(), isolate());
if (callback->IsExecutableAccessorInfo()) {
Handle<ExecutableAccessorInfo> info =
Handle<ExecutableAccessorInfo>::cast(callback);
......
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