LCOV - code coverage report
Current view: top level - src - property-descriptor.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 115 115 100.0 %
Date: 2017-04-26 Functions: 6 6 100.0 %

          Line data    Source code
       1             : // Copyright 2011 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/property-descriptor.h"
       6             : 
       7             : #include "src/bootstrapper.h"
       8             : #include "src/factory.h"
       9             : #include "src/isolate-inl.h"
      10             : #include "src/lookup.h"
      11             : #include "src/objects-inl.h"
      12             : 
      13             : namespace v8 {
      14             : namespace internal {
      15             : 
      16             : namespace {
      17             : 
      18             : // Helper function for ToPropertyDescriptor. Comments describe steps for
      19             : // "enumerable", other properties are handled the same way.
      20             : // Returns false if an exception was thrown.
      21       50109 : bool GetPropertyIfPresent(Handle<JSReceiver> receiver, Handle<String> name,
      22             :                           Handle<Object>* value) {
      23       50109 :   LookupIterator it(receiver, name, receiver);
      24             :   // 4. Let hasEnumerable be HasProperty(Obj, "enumerable").
      25       50109 :   Maybe<bool> has_property = JSReceiver::HasProperty(&it);
      26             :   // 5. ReturnIfAbrupt(hasEnumerable).
      27       50109 :   if (has_property.IsNothing()) return false;
      28             :   // 6. If hasEnumerable is true, then
      29       50109 :   if (has_property.FromJust() == true) {
      30             :     // 6a. Let enum be ToBoolean(Get(Obj, "enumerable")).
      31             :     // 6b. ReturnIfAbrupt(enum).
      32       32734 :     if (!Object::GetProperty(&it).ToHandle(value)) return false;
      33             :   }
      34             :   return true;
      35             : }
      36             : 
      37             : 
      38             : // Helper function for ToPropertyDescriptor. Handles the case of "simple"
      39             : // objects: nothing on the prototype chain, just own fast data properties.
      40             : // Must not have observable side effects, because the slow path will restart
      41             : // the entire conversion!
      42      949071 : bool ToPropertyDescriptorFastPath(Isolate* isolate, Handle<JSReceiver> obj,
      43             :                                   PropertyDescriptor* desc) {
      44      476562 :   if (!obj->IsJSObject()) return false;
      45             :   Map* map = Handle<JSObject>::cast(obj)->map();
      46      475456 :   if (map->instance_type() != JS_OBJECT_TYPE) return false;
      47      474857 :   if (map->is_access_check_needed()) return false;
      48      949714 :   if (map->prototype() != *isolate->initial_object_prototype()) return false;
      49             :   // During bootstrapping, the object_function_prototype_map hasn't been
      50             :   // set up yet.
      51      472509 :   if (isolate->bootstrapper()->IsActive()) return false;
      52      472114 :   if (JSObject::cast(map->prototype())->map() !=
      53      944228 :       isolate->native_context()->object_function_prototype_map()) {
      54             :     return false;
      55             :   }
      56             :   // TODO(jkummerow): support dictionary properties?
      57      470147 :   if (map->is_dictionary_map()) return false;
      58             :   Handle<DescriptorArray> descs =
      59             :       Handle<DescriptorArray>(map->instance_descriptors());
      60     2719442 :   for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
      61      891564 :     PropertyDetails details = descs->GetDetails(i);
      62             :     Name* key = descs->GetKey(i);
      63             :     Handle<Object> value;
      64      891564 :     if (details.location() == kField) {
      65      891415 :       if (details.kind() == kData) {
      66             :         value = JSObject::FastPropertyAt(Handle<JSObject>::cast(obj),
      67             :                                          details.representation(),
      68     1782830 :                                          FieldIndex::ForDescriptor(map, i));
      69             :       } else {
      70             :         DCHECK_EQ(kAccessor, details.kind());
      71             :         // Bail out to slow path.
      72             :         return false;
      73             :       }
      74             : 
      75             :     } else {
      76             :       DCHECK_EQ(kDescriptor, details.location());
      77         149 :       if (details.kind() == kData) {
      78             :         value = handle(descs->GetValue(i), isolate);
      79             :       } else {
      80             :         DCHECK_EQ(kAccessor, details.kind());
      81             :         // Bail out to slow path.
      82             :         return false;
      83             :       }
      84             :     }
      85     2862859 :     Heap* heap = isolate->heap();
      86      891549 :     if (key == heap->enumerable_string()) {
      87      130293 :       desc->set_enumerable(value->BooleanValue());
      88      761256 :     } else if (key == heap->configurable_string()) {
      89       84684 :       desc->set_configurable(value->BooleanValue());
      90      676572 :     } else if (key == heap->value_string()) {
      91             :       desc->set_value(value);
      92      415733 :     } else if (key == heap->writable_string()) {
      93      328272 :       desc->set_writable(value->BooleanValue());
      94       87461 :     } else if (key == heap->get_string()) {
      95             :       // Bail out to slow path to throw an exception if necessary.
      96       57173 :       if (!value->IsCallable()) return false;
      97             :       desc->set_get(value);
      98       30288 :     } else if (key == heap->set_string()) {
      99             :       // Bail out to slow path to throw an exception if necessary.
     100       29794 :       if (!value->IsCallable()) return false;
     101             :       desc->set_set(value);
     102             :     }
     103             :   }
     104     1416170 :   if ((desc->has_get() || desc->has_set()) &&
     105       68186 :       (desc->has_value() || desc->has_writable())) {
     106             :     // Bail out to slow path to throw an exception.
     107             :     return false;
     108             :   }
     109      468042 :   return true;
     110             : }
     111             : 
     112             : 
     113        2562 : void CreateDataProperty(Isolate* isolate, Handle<JSObject> object,
     114             :                         Handle<String> name, Handle<Object> value) {
     115        2562 :   LookupIterator it(object, name, object, LookupIterator::OWN_SKIP_INTERCEPTOR);
     116        2562 :   Maybe<bool> result = JSObject::CreateDataProperty(&it, value);
     117        5124 :   CHECK(result.IsJust() && result.FromJust());
     118        2562 : }
     119             : 
     120             : }  // namespace
     121             : 
     122             : 
     123             : // ES6 6.2.4.4 "FromPropertyDescriptor"
     124     3487879 : Handle<Object> PropertyDescriptor::ToObject(Isolate* isolate) {
     125             :   DCHECK(!(PropertyDescriptor::IsAccessorDescriptor(this) &&
     126             :            PropertyDescriptor::IsDataDescriptor(this)));
     127             :   Factory* factory = isolate->factory();
     128     3487879 :   if (IsRegularAccessorProperty()) {
     129             :     // Fast case for regular accessor properties.
     130             :     Handle<JSObject> result = factory->NewJSObjectFromMap(
     131       16335 :         isolate->accessor_property_descriptor_map());
     132             :     result->InObjectPropertyAtPut(JSAccessorPropertyDescriptor::kGetIndex,
     133       16335 :                                   *get());
     134             :     result->InObjectPropertyAtPut(JSAccessorPropertyDescriptor::kSetIndex,
     135       16335 :                                   *set());
     136             :     result->InObjectPropertyAtPut(
     137             :         JSAccessorPropertyDescriptor::kEnumerableIndex,
     138       16335 :         isolate->heap()->ToBoolean(enumerable()));
     139             :     result->InObjectPropertyAtPut(
     140             :         JSAccessorPropertyDescriptor::kConfigurableIndex,
     141       16335 :         isolate->heap()->ToBoolean(configurable()));
     142       16335 :     return result;
     143             :   }
     144     3471544 :   if (IsRegularDataProperty()) {
     145             :     // Fast case for regular data properties.
     146             :     Handle<JSObject> result =
     147     3469402 :         factory->NewJSObjectFromMap(isolate->data_property_descriptor_map());
     148             :     result->InObjectPropertyAtPut(JSDataPropertyDescriptor::kValueIndex,
     149     3469402 :                                   *value());
     150             :     result->InObjectPropertyAtPut(JSDataPropertyDescriptor::kWritableIndex,
     151     3469402 :                                   isolate->heap()->ToBoolean(writable()));
     152             :     result->InObjectPropertyAtPut(JSDataPropertyDescriptor::kEnumerableIndex,
     153     3469402 :                                   isolate->heap()->ToBoolean(enumerable()));
     154             :     result->InObjectPropertyAtPut(JSDataPropertyDescriptor::kConfigurableIndex,
     155     3469402 :                                   isolate->heap()->ToBoolean(configurable()));
     156     3469402 :     return result;
     157             :   }
     158        2142 :   Handle<JSObject> result = factory->NewJSObject(isolate->object_function());
     159        2142 :   if (has_value()) {
     160        1442 :     CreateDataProperty(isolate, result, factory->value_string(), value());
     161             :   }
     162        2142 :   if (has_writable()) {
     163             :     CreateDataProperty(isolate, result, factory->writable_string(),
     164         308 :                        factory->ToBoolean(writable()));
     165             :   }
     166        2142 :   if (has_get()) {
     167         175 :     CreateDataProperty(isolate, result, factory->get_string(), get());
     168             :   }
     169        2142 :   if (has_set()) {
     170          63 :     CreateDataProperty(isolate, result, factory->set_string(), set());
     171             :   }
     172        2142 :   if (has_enumerable()) {
     173             :     CreateDataProperty(isolate, result, factory->enumerable_string(),
     174         364 :                        factory->ToBoolean(enumerable()));
     175             :   }
     176        2142 :   if (has_configurable()) {
     177             :     CreateDataProperty(isolate, result, factory->configurable_string(),
     178        1092 :                        factory->ToBoolean(configurable()));
     179             :   }
     180        2142 :   return result;
     181             : }
     182             : 
     183             : 
     184             : // ES6 6.2.4.5
     185             : // Returns false in case of exception.
     186             : // static
     187      476805 : bool PropertyDescriptor::ToPropertyDescriptor(Isolate* isolate,
     188             :                                               Handle<Object> obj,
     189             :                                               PropertyDescriptor* desc) {
     190             :   // 1. ReturnIfAbrupt(Obj).
     191             :   // 2. If Type(Obj) is not Object, throw a TypeError exception.
     192      476805 :   if (!obj->IsJSReceiver()) {
     193             :     isolate->Throw(*isolate->factory()->NewTypeError(
     194         486 :         MessageTemplate::kPropertyDescObject, obj));
     195         243 :     return false;
     196             :   }
     197             :   // 3. Let desc be a new Property Descriptor that initially has no fields.
     198             :   DCHECK(desc->is_empty());
     199             : 
     200      476562 :   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(obj);
     201      476562 :   if (ToPropertyDescriptorFastPath(isolate, receiver, desc)) {
     202             :     return true;
     203             :   }
     204             : 
     205             :   // enumerable?
     206             :   Handle<Object> enumerable;
     207             :   // 4 through 6b.
     208        8520 :   if (!GetPropertyIfPresent(receiver, isolate->factory()->enumerable_string(),
     209        8520 :                             &enumerable)) {
     210             :     return false;
     211             :   }
     212             :   // 6c. Set the [[Enumerable]] field of desc to enum.
     213        8464 :   if (!enumerable.is_null()) {
     214        1887 :     desc->set_enumerable(enumerable->BooleanValue());
     215             :   }
     216             : 
     217             :   // configurable?
     218             :   Handle<Object> configurable;
     219             :   // 7 through 9b.
     220        8464 :   if (!GetPropertyIfPresent(receiver, isolate->factory()->configurable_string(),
     221        8464 :                             &configurable)) {
     222             :     return false;
     223             :   }
     224             :   // 9c. Set the [[Configurable]] field of desc to conf.
     225        8464 :   if (!configurable.is_null()) {
     226        2591 :     desc->set_configurable(configurable->BooleanValue());
     227             :   }
     228             : 
     229             :   // value?
     230             :   Handle<Object> value;
     231             :   // 10 through 12b.
     232        8464 :   if (!GetPropertyIfPresent(receiver, isolate->factory()->value_string(),
     233        8464 :                             &value)) {
     234             :     return false;
     235             :   }
     236             :   // 12c. Set the [[Value]] field of desc to value.
     237        8240 :   if (!value.is_null()) desc->set_value(value);
     238             : 
     239             :   // writable?
     240             :   Handle<Object> writable;
     241             :   // 13 through 15b.
     242        8240 :   if (!GetPropertyIfPresent(receiver, isolate->factory()->writable_string(),
     243        8240 :                             &writable)) {
     244             :     return false;
     245             :   }
     246             :   // 15c. Set the [[Writable]] field of desc to writable.
     247       10384 :   if (!writable.is_null()) desc->set_writable(writable->BooleanValue());
     248             : 
     249             :   // getter?
     250             :   Handle<Object> getter;
     251             :   // 16 through 18b.
     252        8240 :   if (!GetPropertyIfPresent(receiver, isolate->factory()->get_string(),
     253        8240 :                             &getter)) {
     254             :     return false;
     255             :   }
     256        8240 :   if (!getter.is_null()) {
     257             :     // 18c. If IsCallable(getter) is false and getter is not undefined,
     258             :     // throw a TypeError exception.
     259        3634 :     if (!getter->IsCallable() && !getter->IsUndefined(isolate)) {
     260             :       isolate->Throw(*isolate->factory()->NewTypeError(
     261         118 :           MessageTemplate::kObjectGetterCallable, getter));
     262          59 :       return false;
     263             :     }
     264             :     // 18d. Set the [[Get]] field of desc to getter.
     265             :     desc->set_get(getter);
     266             :   }
     267             :   // setter?
     268             :   Handle<Object> setter;
     269             :   // 19 through 21b.
     270        8181 :   if (!GetPropertyIfPresent(receiver, isolate->factory()->set_string(),
     271        8181 :                             &setter)) {
     272             :     return false;
     273             :   }
     274        8181 :   if (!setter.is_null()) {
     275             :     // 21c. If IsCallable(setter) is false and setter is not undefined,
     276             :     // throw a TypeError exception.
     277        4918 :     if (!setter->IsCallable() && !setter->IsUndefined(isolate)) {
     278             :       isolate->Throw(*isolate->factory()->NewTypeError(
     279          88 :           MessageTemplate::kObjectSetterCallable, setter));
     280          44 :       return false;
     281             :     }
     282             :     // 21d. Set the [[Set]] field of desc to setter.
     283             :     desc->set_set(setter);
     284             :   }
     285             : 
     286             :   // 22. If either desc.[[Get]] or desc.[[Set]] is present, then
     287             :   // 22a. If either desc.[[Value]] or desc.[[Writable]] is present,
     288             :   // throw a TypeError exception.
     289       25578 :   if ((desc->has_get() || desc->has_set()) &&
     290        4167 :       (desc->has_value() || desc->has_writable())) {
     291             :     isolate->Throw(*isolate->factory()->NewTypeError(
     292         288 :         MessageTemplate::kValueAndAccessor, obj));
     293         144 :     return false;
     294             :   }
     295             : 
     296             :   // 23. Return desc.
     297             :   return true;
     298             : }
     299             : 
     300             : 
     301             : // ES6 6.2.4.6
     302             : // static
     303        6062 : void PropertyDescriptor::CompletePropertyDescriptor(Isolate* isolate,
     304             :                                                     PropertyDescriptor* desc) {
     305             :   // 1. ReturnIfAbrupt(Desc).
     306             :   // 2. Assert: Desc is a Property Descriptor.
     307             :   // 3. Let like be Record{
     308             :   //        [[Value]]: undefined, [[Writable]]: false,
     309             :   //        [[Get]]: undefined, [[Set]]: undefined,
     310             :   //        [[Enumerable]]: false, [[Configurable]]: false}.
     311             :   // 4. If either IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true,
     312             :   // then:
     313        6062 :   if (!IsAccessorDescriptor(desc)) {
     314             :     // 4a. If Desc does not have a [[Value]] field, set Desc.[[Value]] to
     315             :     //     like.[[Value]].
     316        5768 :     if (!desc->has_value()) {
     317             :       desc->set_value(isolate->factory()->undefined_value());
     318             :     }
     319             :     // 4b. If Desc does not have a [[Writable]] field, set Desc.[[Writable]]
     320             :     //     to like.[[Writable]].
     321        5768 :     if (!desc->has_writable()) desc->set_writable(false);
     322             :   } else {
     323             :     // 5. Else,
     324             :     // 5a. If Desc does not have a [[Get]] field, set Desc.[[Get]] to
     325             :     //     like.[[Get]].
     326         294 :     if (!desc->has_get()) {
     327             :       desc->set_get(isolate->factory()->undefined_value());
     328             :     }
     329             :     // 5b. If Desc does not have a [[Set]] field, set Desc.[[Set]] to
     330             :     //     like.[[Set]].
     331         294 :     if (!desc->has_set()) {
     332             :       desc->set_set(isolate->factory()->undefined_value());
     333             :     }
     334             :   }
     335             :   // 6. If Desc does not have an [[Enumerable]] field, set
     336             :   //    Desc.[[Enumerable]] to like.[[Enumerable]].
     337        6062 :   if (!desc->has_enumerable()) desc->set_enumerable(false);
     338             :   // 7. If Desc does not have a [[Configurable]] field, set
     339             :   //    Desc.[[Configurable]] to like.[[Configurable]].
     340        6062 :   if (!desc->has_configurable()) desc->set_configurable(false);
     341             :   // 8. Return Desc.
     342        6062 : }
     343             : 
     344             : }  // namespace internal
     345             : }  // namespace v8

Generated by: LCOV version 1.10