}
+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
//
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,
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;
? Representation::Smi() : Representation::Tagged());
}
- static HObjectAccess ForTypedArrayLength() {
- return HObjectAccess(
- kInobject,
- JSTypedArray::kLengthOffset,
- Representation::Tagged());
- }
-
static HObjectAccess ForAllocationSiteTransitionInfo() {
return HObjectAccess(kInobject, AllocationSite::kTransitionInfoOffset);
}
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();
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;
}
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;
}
-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) {
#include "v8.h"
+#include "accessors.h"
#include "allocation.h"
#include "ast.h"
#include "compiler.h"
// 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(); }
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();
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);
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);