Support loads from primitive values.
authorverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 30 Jan 2014 11:30:38 +0000 (11:30 +0000)
committerverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 30 Jan 2014 11:30:38 +0000 (11:30 +0000)
This also changes load computation to use HeapTypes rather than Maps.
TODO: move conversion between maps and heaptypes earlier in the process, already in the oracle.

BUG=
R=dcarney@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@18938 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/accessors.cc
src/accessors.h
src/hydrogen-instructions.h
src/hydrogen.cc
src/hydrogen.h
src/ic.cc
test/mjsunit/value-wrapper-accessor.js [new file with mode: 0644]

index cd41564..25ee305 100644 (file)
@@ -91,10 +91,19 @@ static V8_INLINE bool CheckForName(Handle<String> name,
 }
 
 
-bool Accessors::IsJSObjectFieldAccessor(
-      Handle<Map> map, Handle<String> name,
-      int* object_offset) {
-  Isolate* isolate = map->GetIsolate();
+bool Accessors::IsJSObjectFieldAccessor(Handle<HeapType> type,
+                                        Handle<String> name,
+                                        int* object_offset) {
+  Isolate* isolate = name->GetIsolate();
+
+  if (type->Is(HeapType::String())) {
+    return CheckForName(name, isolate->heap()->length_string(),
+                        String::kLengthOffset, object_offset);
+  }
+
+  if (!type->IsClass()) return false;
+  Handle<Map> map = type->AsClass();
+
   switch (map->instance_type()) {
     case JS_ARRAY_TYPE:
       return
@@ -122,14 +131,8 @@ bool Accessors::IsJSObjectFieldAccessor(
                      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);
-      }
+    default:
       return false;
-    }
   }
 }
 
index 723abd2..dedde32 100644 (file)
@@ -89,8 +89,7 @@ class Accessors : public AllStatic {
   // 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);
+      Handle<HeapType> map, Handle<String> name, int* object_offset);
 
 
  private:
index 93e4908..345c6b9 100644 (file)
@@ -4269,6 +4269,9 @@ class HIsStringAndBranch V8_FINAL : public HUnaryControlInstruction {
 
   DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch)
 
+ protected:
+  virtual int RedefinedOperandIndex() { return 0; }
+
  private:
   HIsStringAndBranch(HValue* value,
                      HBasicBlock* true_target = NULL,
@@ -4291,6 +4294,7 @@ class HIsSmiAndBranch V8_FINAL : public HUnaryControlInstruction {
 
  protected:
   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
+  virtual int RedefinedOperandIndex() { return 0; }
 
  private:
   HIsSmiAndBranch(HValue* value,
index 74262b9..3c7bf50 100644 (file)
@@ -4924,10 +4924,13 @@ void HOptimizedGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
 }
 
 
-static bool CanInlinePropertyAccess(Map* type) {
-  return type->IsJSObjectMap() &&
-      !type->is_dictionary_map() &&
-      !type->has_named_interceptor();
+static bool CanInlinePropertyAccess(Handle<HeapType> type) {
+  if (type->Is(HeapType::NumberOrString())) return true;
+  if (!type->IsClass()) return false;
+  Handle<Map> map = type->AsClass();
+  return map->IsJSObjectMap() &&
+      !map->is_dictionary_map() &&
+      !map->has_named_interceptor();
 }
 
 
@@ -4936,8 +4939,8 @@ static void LookupInPrototypes(Handle<Map> map,
                                LookupResult* lookup) {
   while (map->prototype()->IsJSObject()) {
     Handle<JSObject> holder(JSObject::cast(map->prototype()));
-    map = Handle<Map>(holder->map());
-    if (!CanInlinePropertyAccess(*map)) break;
+    map = handle(holder->map());
+    if (!CanInlinePropertyAccess(IC::MapToType(map))) break;
     map->LookupDescriptor(*holder, *name, lookup);
     if (lookup->IsFound()) return;
   }
@@ -5438,7 +5441,7 @@ static bool ComputeStoreField(Handle<Map> type,
                               LookupResult* lookup,
                               bool lookup_transition = true) {
   ASSERT(!type->is_observed());
-  if (!CanInlinePropertyAccess(*type)) {
+  if (!CanInlinePropertyAccess(IC::MapToType(type))) {
     lookup->NotFound();
     return false;
   }
@@ -5473,13 +5476,26 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedMonomorphic(
 
 bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatibleForLoad(
     PropertyAccessInfo* info) {
-  if (!CanInlinePropertyAccess(*map_)) return false;
+  if (!CanInlinePropertyAccess(type_)) return false;
+
+  // Currently only handle HeapType::Number as a polymorphic case.
+  // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber
+  // instruction.
+  if (type_->Is(HeapType::Number())) return false;
+
+  // Values are only compatible for monomorphic load if they all behave the same
+  // regarding value wrappers.
+  if (type_->Is(HeapType::NumberOrString())) {
+    if (!info->type_->Is(HeapType::NumberOrString())) return false;
+  } else {
+    if (info->type_->Is(HeapType::NumberOrString())) return false;
+  }
 
   if (!LookupDescriptor()) return false;
 
   if (!lookup_.IsFound()) {
     return (!info->lookup_.IsFound() || info->has_holder()) &&
-        map_->prototype() == info->map_->prototype();
+        map()->prototype() == info->map()->prototype();
   }
 
   // Mismatch if the other access info found the property in the prototype
@@ -5507,8 +5523,9 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatibleForLoad(
 
 
 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() {
-  map_->LookupDescriptor(NULL, *name_, &lookup_);
-  return LoadResult(map_);
+  if (!type_->IsClass()) return true;
+  map()->LookupDescriptor(NULL, *name_, &lookup_);
+  return LoadResult(map());
 }
 
 
@@ -5534,14 +5551,15 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) {
 
 
 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() {
-  Handle<Map> map = map_;
+  Handle<Map> map = this->map();
+
   while (map->prototype()->IsJSObject()) {
     holder_ = handle(JSObject::cast(map->prototype()));
     if (holder_->map()->is_deprecated()) {
       JSObject::TryMigrateInstance(holder_);
     }
     map = Handle<Map>(holder_->map());
-    if (!CanInlinePropertyAccess(*map)) {
+    if (!CanInlinePropertyAccess(IC::MapToType(map))) {
       lookup_.NotFound();
       return false;
     }
@@ -5554,7 +5572,7 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() {
 
 
 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadMonomorphic() {
-  if (!CanInlinePropertyAccess(*map_)) return IsStringLength();
+  if (!CanInlinePropertyAccess(type_)) return false;
   if (IsJSObjectFieldAccessor()) return true;
   if (!LookupDescriptor()) return false;
   if (lookup_.IsFound()) return true;
@@ -5564,19 +5582,12 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadMonomorphic() {
 
 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic(
     SmallMapList* types) {
-  ASSERT(map_.is_identical_to(types->first()));
+  ASSERT(type_->Is(IC::MapToType(types->first())));
   if (!CanLoadMonomorphic()) return false;
   if (types->length() > kMaxLoadPolymorphism) return false;
 
-  if (IsStringLength()) {
-    for (int i = 1; i < types->length(); ++i) {
-      if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false;
-    }
-    return true;
-  }
-
   if (IsArrayLength()) {
-    bool is_fast = IsFastElementsKind(map_->elements_kind());
+    bool is_fast = IsFastElementsKind(map()->elements_kind());
     for (int i = 1; i < types->length(); ++i) {
       Handle<Map> test_map = types->at(i);
       if (test_map->instance_type() != JS_ARRAY_TYPE) return false;
@@ -5587,16 +5598,25 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic(
     return true;
   }
 
-  if (IsJSObjectFieldAccessor()) {
-    InstanceType instance_type = map_->instance_type();
+  HObjectAccess access = HObjectAccess::ForMap();  // bogus default
+  if (GetJSObjectFieldAccess(&access)) {
     for (int i = 1; i < types->length(); ++i) {
-      if (types->at(i)->instance_type() != instance_type) return false;
+      PropertyAccessInfo test_info(
+          builder_, IC::MapToType(types->at(i)), name_);
+      HObjectAccess test_access = HObjectAccess::ForMap();  // bogus default
+      if (!test_info.GetJSObjectFieldAccess(&test_access)) return false;
+      if (!access.Equals(test_access)) return false;
     }
     return true;
   }
 
+  // Currently only handle HeapType::Number as a polymorphic case.
+  // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber
+  // instruction.
+  if (type_->Is(HeapType::Number())) return false;
+
   for (int i = 1; i < types->length(); ++i) {
-    PropertyAccessInfo test_info(isolate(), types->at(i), name_);
+    PropertyAccessInfo test_info(builder_, IC::MapToType(types->at(i)), name_);
     if (!test_info.IsCompatibleForLoad(this)) return false;
   }
 
@@ -5604,10 +5624,17 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic(
 }
 
 
+static bool NeedsWrappingFor(Handle<HeapType> type, Handle<JSFunction> target) {
+  return type->Is(HeapType::NumberOrString()) &&
+      target->shared()->is_classic_mode() &&
+      !target->shared()->native();
+}
+
+
 HInstruction* HOptimizedGraphBuilder::BuildLoadMonomorphic(
     PropertyAccessInfo* info,
     HValue* object,
-    HInstruction* checked_object,
+    HValue* checked_object,
     BailoutId ast_id,
     BailoutId return_id,
     bool can_inline_accessor) {
@@ -5631,14 +5658,21 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadMonomorphic(
   }
 
   if (info->lookup()->IsPropertyCallbacks()) {
-    Push(checked_object);
-    if (FLAG_inline_accessors &&
-        can_inline_accessor &&
-        TryInlineGetter(info->accessor(), ast_id, return_id)) {
-      return NULL;
+    if (NeedsWrappingFor(info->type(), info->accessor())) {
+      return New<HLoadNamedGeneric>(checked_object, info->name());
+      // HValue* function = Add<HConstant>(info->accessor());
+      // Add<HPushArgument>(checked_object);
+      // return New<HCallFunction>(function, 1, WRAP_AND_CALL);
+    } else {
+      Push(checked_object);
+      if (FLAG_inline_accessors &&
+          can_inline_accessor &&
+          TryInlineGetter(info->accessor(), ast_id, return_id)) {
+        return NULL;
+      }
+      Add<HPushArgument>(Pop());
+      return BuildCallConstantFunction(info->accessor(), 1);
     }
-    Add<HPushArgument>(Pop());
-    return BuildCallConstantFunction(info->accessor(), 1);
   }
 
   ASSERT(info->lookup()->IsConstant());
@@ -5655,36 +5689,88 @@ void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
   // Something did not match; must use a polymorphic load.
   int count = 0;
   HBasicBlock* join = NULL;
+  HBasicBlock* number_block = NULL;
+
+  bool handle_smi = false;
   for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
-    PropertyAccessInfo info(isolate(), types->at(i), name);
+    PropertyAccessInfo info(this, IC::MapToType(types->at(i)), name);
     if (info.CanLoadMonomorphic()) {
-      if (count == 0) {
-        BuildCheckHeapObject(object);
-        join = graph()->CreateBasicBlock();
+      count++;
+      if (info.type()->Is(HeapType::Number())) {
+        handle_smi = true;
+        break;
       }
-      ++count;
-      HBasicBlock* if_true = graph()->CreateBasicBlock();
-      HBasicBlock* if_false = graph()->CreateBasicBlock();
-      HCompareMap* compare = New<HCompareMap>(
-          object, info.map(),  if_true, if_false);
-      FinishCurrentBlock(compare);
+    }
+  }
 
-      set_current_block(if_true);
+  count = 0;
+  bool handled_string = false;
+  HControlInstruction* smi_check = NULL;
+
+  for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
+    PropertyAccessInfo info(this, IC::MapToType(types->at(i)), name);
+    if (info.type()->Is(HeapType::String())) {
+      if (handled_string) continue;
+      handled_string = true;
+    }
+    if (!info.CanLoadMonomorphic()) continue;
 
-      HInstruction* load = BuildLoadMonomorphic(
-          &info, object, compare, ast_id, return_id, FLAG_polymorphic_inlining);
-      if (load == NULL) {
-        if (HasStackOverflow()) return;
+    if (count == 0) {
+      join = graph()->CreateBasicBlock();
+      if (handle_smi) {
+        HBasicBlock* empty_smi_block = graph()->CreateBasicBlock();
+        HBasicBlock* not_smi_block = graph()->CreateBasicBlock();
+        number_block = graph()->CreateBasicBlock();
+        smi_check = New<HIsSmiAndBranch>(
+            object, empty_smi_block, not_smi_block);
+        FinishCurrentBlock(smi_check);
+        Goto(empty_smi_block, number_block);
+        set_current_block(not_smi_block);
       } else {
-        if (!load->IsLinked()) {
-          AddInstruction(load);
-        }
-        if (!ast_context()->IsEffect()) Push(load);
+        BuildCheckHeapObject(object);
       }
+    }
+    ++count;
+    HBasicBlock* if_true = graph()->CreateBasicBlock();
+    HBasicBlock* if_false = graph()->CreateBasicBlock();
+    HUnaryControlInstruction* compare;
 
-      if (current_block() != NULL) Goto(join);
-      set_current_block(if_false);
+    HValue* dependency;
+    if (info.type()->Is(HeapType::Number())) {
+      Handle<Map> heap_number_map = isolate()->factory()->heap_number_map();
+      compare = New<HCompareMap>(object, heap_number_map, if_true, if_false);
+      dependency = smi_check;
+    } else if (info.type()->Is(HeapType::String())) {
+      compare = New<HIsStringAndBranch>(object, if_true, if_false);
+      dependency = compare;
+    } else {
+      compare = New<HCompareMap>(object, info.map(), if_true, if_false);
+      dependency = compare;
     }
+    FinishCurrentBlock(compare);
+
+    if (info.type()->Is(HeapType::Number())) {
+      Goto(if_true, number_block);
+      if_true = number_block;
+      number_block->SetJoinId(ast_id);
+    }
+
+    set_current_block(if_true);
+
+    HInstruction* load = BuildLoadMonomorphic(
+        &info, object, dependency, ast_id,
+        return_id, FLAG_polymorphic_inlining);
+    if (load == NULL) {
+      if (HasStackOverflow()) return;
+    } else {
+      if (!load->IsLinked()) {
+        AddInstruction(load);
+      }
+      if (!ast_context()->IsEffect()) Push(load);
+    }
+
+    if (current_block() != NULL) Goto(join);
+    set_current_block(if_false);
   }
 
   // Finish up.  Unconditionally deoptimize if we've handled all the maps we
@@ -5868,7 +5954,7 @@ static bool ComputeReceiverTypes(Expression* expr,
     types->FilterForPossibleTransitions(root_map);
     monomorphic = types->length() == 1;
   }
-  return monomorphic && CanInlinePropertyAccess(*types->first());
+  return monomorphic && CanInlinePropertyAccess(IC::MapToType(types->first()));
 }
 
 
@@ -5915,15 +6001,21 @@ void HOptimizedGraphBuilder::BuildStore(Expression* expr,
     Handle<JSFunction> setter;
     Handle<JSObject> holder;
     if (LookupSetter(map, name, &setter, &holder)) {
-      AddCheckConstantFunction(holder, object, map);
-      if (FLAG_inline_accessors &&
-          TryInlineSetter(setter, ast_id, return_id, value)) {
+      AddCheckMap(object, map);
+      AddCheckPrototypeMaps(holder, map);
+      bool needs_wrapping = NeedsWrappingFor(IC::MapToType(map), setter);
+      bool try_inline = FLAG_inline_accessors && !needs_wrapping;
+      if (try_inline && TryInlineSetter(setter, ast_id, return_id, value)) {
         return;
       }
       Drop(2);
-      Add<HPushArgument>(object);
-      Add<HPushArgument>(value);
-      instr = BuildCallConstantFunction(setter, 2);
+      if (needs_wrapping) {
+        instr = BuildStoreNamedGeneric(object, name, value);
+      } else {
+        Add<HPushArgument>(object);
+        Add<HPushArgument>(value);
+        instr = BuildCallConstantFunction(setter, 2);
+      }
     } else {
       Drop(2);
       CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object,
@@ -6776,14 +6868,16 @@ void HOptimizedGraphBuilder::BuildLoad(Property* expr,
     ASSERT(types != NULL);
 
     if (types->length() > 0) {
-      PropertyAccessInfo info(isolate(), types->first(), name);
+      PropertyAccessInfo info(this, IC::MapToType(types->first()), name);
       if (!info.CanLoadAsMonomorphic(types)) {
         return HandlePolymorphicLoadNamedField(
             ast_id, expr->LoadId(), object, types, name);
       }
 
+      HValue* checked_object;
+      // HeapType::Number() is only supported by polymorphic load/call handling.
+      ASSERT(!info.type()->Is(HeapType::Number()));
       BuildCheckHeapObject(object);
-      HInstruction* checked_object;
       if (AreStringTypes(types)) {
         checked_object =
             Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING);
@@ -7010,7 +7104,7 @@ bool HOptimizedGraphBuilder::TryCallPolymorphicAsMonomorphic(
     Handle<String> name) {
   if (types->length() > kMaxCallPolymorphism) return false;
 
-  PropertyAccessInfo info(isolate(), types->at(0), name);
+  PropertyAccessInfo info(this, IC::MapToType(types->at(0)), name);
   if (!info.CanLoadAsMonomorphic(types)) return false;
   if (!expr->ComputeTarget(info.map(), name)) return false;
 
index 55e7274..a9c0d32 100644 (file)
@@ -2256,9 +2256,12 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
 
   class PropertyAccessInfo {
    public:
-    PropertyAccessInfo(Isolate* isolate, Handle<Map> map, Handle<String> name)
-        : lookup_(isolate),
-          map_(map),
+    PropertyAccessInfo(HOptimizedGraphBuilder* builder,
+                       Handle<HeapType> type,
+                       Handle<String> name)
+        : lookup_(builder->isolate()),
+          builder_(builder),
+          type_(type),
           name_(name),
           access_(HObjectAccess::ForMap()) { }
 
@@ -2275,32 +2278,48 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
     // PropertyAccessInfo is built for types->first().
     bool CanLoadAsMonomorphic(SmallMapList* types);
 
+    Handle<Map> map() {
+      if (type_->Is(HeapType::Number())) {
+        Context* context = current_info()->closure()->context();
+        context = context->native_context();
+        return handle(context->number_function()->initial_map());
+      } else if (type_->Is(HeapType::String())) {
+        Context* context = current_info()->closure()->context();
+        context = context->native_context();
+        return handle(context->string_function()->initial_map());
+      } else {
+        return type_->AsClass();
+      }
+    }
+    Handle<HeapType> type() const { return type_; }
+    Handle<String> name() const { return name_; }
+
     bool IsJSObjectFieldAccessor() {
       int offset;  // unused
-      return Accessors::IsJSObjectFieldAccessor(map_, name_, &offset);
+      return Accessors::IsJSObjectFieldAccessor(type_, name_, &offset);
     }
 
     bool GetJSObjectFieldAccess(HObjectAccess* access) {
-      if (IsStringLength()) {
-        *access = HObjectAccess::ForStringLength();
-        return true;
-      } else if (IsArrayLength()) {
-        *access = HObjectAccess::ForArrayLength(map_->elements_kind());
+      if (IsArrayLength()) {
+        *access = HObjectAccess::ForArrayLength(map()->elements_kind());
         return true;
-      } else {
-        int offset;
-        if (Accessors::IsJSObjectFieldAccessor(map_, name_, &offset)) {
+      }
+      int offset;
+      if (Accessors::IsJSObjectFieldAccessor(type_, name_, &offset)) {
+        if (type_->Is(HeapType::String())) {
+          ASSERT(name_->Equals(isolate()->heap()->length_string()));
+          *access = HObjectAccess::ForStringLength();
+        } else {
           *access = HObjectAccess::ForJSObjectOffset(offset);
-          return true;
         }
-        return false;
+        return true;
       }
+      return false;
     }
 
     bool has_holder() { return !holder_.is_null(); }
 
     LookupResult* lookup() { return &lookup_; }
-    Handle<Map> map() { return map_; }
     Handle<JSObject> holder() { return holder_; }
     Handle<JSFunction> accessor() { return accessor_; }
     Handle<Object> constant() { return constant_; }
@@ -2308,14 +2327,10 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
 
    private:
     Isolate* isolate() { return lookup_.isolate(); }
-
-    bool IsStringLength() {
-      return map_->instance_type() < FIRST_NONSTRING_TYPE &&
-          name_->Equals(isolate()->heap()->length_string());
-    }
+    CompilationInfo* current_info() { return builder_->current_info(); }
 
     bool IsArrayLength() {
-      return map_->instance_type() == JS_ARRAY_TYPE &&
+      return map()->instance_type() == JS_ARRAY_TYPE &&
           name_->Equals(isolate()->heap()->length_string());
     }
 
@@ -2330,7 +2345,8 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
     }
 
     LookupResult lookup_;
-    Handle<Map> map_;
+    HOptimizedGraphBuilder* builder_;
+    Handle<HeapType> type_;
     Handle<String> name_;
     Handle<JSObject> holder_;
     Handle<JSFunction> accessor_;
@@ -2340,7 +2356,7 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
 
   HInstruction* BuildLoadMonomorphic(PropertyAccessInfo* info,
                                      HValue* object,
-                                     HInstruction* checked_object,
+                                     HValue* checked_object,
                                      BailoutId ast_id,
                                      BailoutId return_id,
                                      bool can_inline_accessor = true);
index b465757..fd86f1e 100644 (file)
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -1208,9 +1208,9 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
       // Use simple field loads for some well-known callback properties.
       if (object->IsJSObject()) {
         Handle<JSObject> receiver = Handle<JSObject>::cast(object);
-        Handle<Map> map(receiver->map());
+        Handle<HeapType> type = IC::MapToType(handle(receiver->map()));
         int object_offset;
-        if (Accessors::IsJSObjectFieldAccessor(map, name, &object_offset)) {
+        if (Accessors::IsJSObjectFieldAccessor(type, name, &object_offset)) {
           return SimpleFieldLoad(object_offset / kPointerSize);
         }
       }
diff --git a/test/mjsunit/value-wrapper-accessor.js b/test/mjsunit/value-wrapper-accessor.js
new file mode 100644 (file)
index 0000000..2a51fee
--- /dev/null
@@ -0,0 +1,99 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// When calling user-defined accessors on strings, booleans or
+// numbers, we should create a wrapper object in classic-mode.
+
+// Flags: --allow-natives-syntax
+
+function test(object, prototype) {
+  var result;
+  Object.defineProperty(prototype, "nonstrict", {
+    get: function() { result = this; },
+    set: function(v) { result = this; }
+  });
+  Object.defineProperty(prototype, "strict", {
+    get: function() { "use strict"; result = this; },
+    set: function(v) { "use strict"; result = this; }
+  });
+
+  (function() {
+    function nonstrict(s) {
+      return s.nonstrict;
+    }
+    function strict(s) {
+      return s.strict;
+    }
+
+    nonstrict(object);
+    nonstrict(object);
+    %OptimizeFunctionOnNextCall(nonstrict);
+    result = undefined;
+    nonstrict(object);
+    assertEquals("object", typeof result);
+
+    strict(object);
+    strict(object);
+    %OptimizeFunctionOnNextCall(strict);
+    result = undefined;
+    strict(object);
+    assertEquals(typeof object, typeof result);
+  })();
+
+  (function() {
+    function nonstrict(s) {
+      return s.nonstrict = 10;
+    }
+    function strict(s) {
+      return s.strict = 10;
+    }
+
+    nonstrict(object);
+    nonstrict(object);
+    %OptimizeFunctionOnNextCall(nonstrict);
+    result = undefined;
+    nonstrict(object);
+    // TODO(1475): Support storing to primitive values.
+    // This should return "object" once storing to primitive values is
+    // supported.
+    assertEquals("undefined", typeof result);
+
+    strict(object);
+    strict(object);
+    %OptimizeFunctionOnNextCall(strict);
+    result = undefined;
+    strict(object);
+    // TODO(1475): Support storing to primitive values.
+    // This should return "object" once storing to primitive values is
+    // supported.
+    assertEquals("undefined", typeof result);
+  })();
+}
+
+test(1, Number.prototype);
+test("string", String.prototype);
+test(true, Boolean.prototype);