LCOV - code coverage report
Current view: top level - src - property-descriptor.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 132 132 100.0 %
Date: 2019-04-18 Functions: 8 8 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/heap/factory.h"
       9             : #include "src/heap/heap-inl.h"  // For ToBoolean. TODO(jkummerow): Drop.
      10             : #include "src/isolate-inl.h"
      11             : #include "src/lookup.h"
      12             : #include "src/objects-inl.h"
      13             : #include "src/objects/property-descriptor-object-inl.h"
      14             : 
      15             : namespace v8 {
      16             : namespace internal {
      17             : 
      18             : namespace {
      19             : 
      20             : // Helper function for ToPropertyDescriptor. Comments describe steps for
      21             : // "enumerable", other properties are handled the same way.
      22             : // Returns false if an exception was thrown.
      23       35646 : bool GetPropertyIfPresent(Handle<JSReceiver> receiver, Handle<String> name,
      24             :                           Handle<Object>* value) {
      25             :   LookupIterator it(receiver, name, receiver);
      26             :   // 4. Let hasEnumerable be HasProperty(Obj, "enumerable").
      27       35646 :   Maybe<bool> has_property = JSReceiver::HasProperty(&it);
      28             :   // 5. ReturnIfAbrupt(hasEnumerable).
      29       35646 :   if (has_property.IsNothing()) return false;
      30             :   // 6. If hasEnumerable is true, then
      31       35646 :   if (has_property.FromJust() == true) {
      32             :     // 6a. Let enum be ToBoolean(Get(Obj, "enumerable")).
      33             :     // 6b. ReturnIfAbrupt(enum).
      34       22382 :     if (!Object::GetProperty(&it).ToHandle(value)) return false;
      35             :   }
      36             :   return true;
      37             : }
      38             : 
      39             : 
      40             : // Helper function for ToPropertyDescriptor. Handles the case of "simple"
      41             : // objects: nothing on the prototype chain, just own fast data properties.
      42             : // Must not have observable side effects, because the slow path will restart
      43             : // the entire conversion!
      44      141188 : bool ToPropertyDescriptorFastPath(Isolate* isolate, Handle<JSReceiver> obj,
      45             :                                   PropertyDescriptor* desc) {
      46      141188 :   if (!obj->IsJSObject()) return false;
      47             :   Map map = Handle<JSObject>::cast(obj)->map();
      48      140477 :   if (map->instance_type() != JS_OBJECT_TYPE) return false;
      49      140053 :   if (map->is_access_check_needed()) return false;
      50      280106 :   if (map->prototype() != *isolate->initial_object_prototype()) return false;
      51             :   // During bootstrapping, the object_function_prototype_map hasn't been
      52             :   // set up yet.
      53      137329 :   if (isolate->bootstrapper()->IsActive()) return false;
      54      137329 :   if (JSObject::cast(map->prototype())->map() !=
      55      411987 :       isolate->native_context()->object_function_prototype_map()) {
      56             :     return false;
      57             :   }
      58             :   // TODO(jkummerow): support dictionary properties?
      59      136501 :   if (map->is_dictionary_map()) return false;
      60             :   Handle<DescriptorArray> descs =
      61             :       Handle<DescriptorArray>(map->instance_descriptors(), isolate);
      62      584603 :   for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
      63      225125 :     PropertyDetails details = descs->GetDetails(i);
      64             :     Name key = descs->GetKey(i);
      65             :     Handle<Object> value;
      66      225125 :     if (details.location() == kField) {
      67      225116 :       if (details.kind() == kData) {
      68             :         value = JSObject::FastPropertyAt(Handle<JSObject>::cast(obj),
      69             :                                          details.representation(),
      70      450232 :                                          FieldIndex::ForDescriptor(map, i));
      71             :       } else {
      72             :         DCHECK_EQ(kAccessor, details.kind());
      73             :         // Bail out to slow path.
      74             :         return false;
      75             :       }
      76             : 
      77             :     } else {
      78             :       DCHECK_EQ(kDescriptor, details.location());
      79           9 :       if (details.kind() == kData) {
      80             :         value = handle(descs->GetStrongValue(i), isolate);
      81             :       } else {
      82             :         DCHECK_EQ(kAccessor, details.kind());
      83             :         // Bail out to slow path.
      84             :         return false;
      85             :       }
      86             :     }
      87             :     ReadOnlyRoots roots(isolate);
      88      225116 :     if (key == roots.enumerable_string()) {
      89       50260 :       desc->set_enumerable(value->BooleanValue(isolate));
      90      199986 :     } else if (key == roots.configurable_string()) {
      91       83148 :       desc->set_configurable(value->BooleanValue(isolate));
      92      158412 :     } else if (key == roots.value_string()) {
      93             :       desc->set_value(value);
      94       93373 :     } else if (key == roots.writable_string()) {
      95       71408 :       desc->set_writable(value->BooleanValue(isolate));
      96       57669 :     } else if (key == roots.get_string()) {
      97             :       // Bail out to slow path to throw an exception if necessary.
      98       38012 :       if (!value->IsCallable()) return false;
      99             :       desc->set_get(value);
     100       19657 :     } else if (key == roots.set_string()) {
     101             :       // Bail out to slow path to throw an exception if necessary.
     102       19396 :       if (!value->IsCallable()) return false;
     103             :       desc->set_set(value);
     104             :     }
     105             :   }
     106      413240 :   if ((desc->has_get() || desc->has_set()) &&
     107       45166 :       (desc->has_value() || desc->has_writable())) {
     108             :     // Bail out to slow path to throw an exception.
     109             :     return false;
     110             :   }
     111      135139 :   return true;
     112             : }
     113             : 
     114        1629 : void CreateDataProperty(Handle<JSObject> object, Handle<String> name,
     115             :                         Handle<Object> value) {
     116             :   LookupIterator it(object, name, object, LookupIterator::OWN_SKIP_INTERCEPTOR);
     117        1629 :   Maybe<bool> result = JSObject::CreateDataProperty(&it, value);
     118        3258 :   CHECK(result.IsJust() && result.FromJust());
     119        1629 : }
     120             : 
     121             : }  // namespace
     122             : 
     123             : 
     124             : // ES6 6.2.4.4 "FromPropertyDescriptor"
     125       19037 : Handle<Object> PropertyDescriptor::ToObject(Isolate* isolate) {
     126             :   DCHECK(!(PropertyDescriptor::IsAccessorDescriptor(this) &&
     127             :            PropertyDescriptor::IsDataDescriptor(this)));
     128             :   Factory* factory = isolate->factory();
     129       19037 :   if (IsRegularAccessorProperty()) {
     130             :     // Fast case for regular accessor properties.
     131             :     Handle<JSObject> result = factory->NewJSObjectFromMap(
     132          86 :         isolate->accessor_property_descriptor_map());
     133             :     result->InObjectPropertyAtPut(JSAccessorPropertyDescriptor::kGetIndex,
     134          86 :                                   *get());
     135             :     result->InObjectPropertyAtPut(JSAccessorPropertyDescriptor::kSetIndex,
     136          86 :                                   *set());
     137             :     result->InObjectPropertyAtPut(
     138             :         JSAccessorPropertyDescriptor::kEnumerableIndex,
     139         172 :         isolate->heap()->ToBoolean(enumerable()));
     140             :     result->InObjectPropertyAtPut(
     141             :         JSAccessorPropertyDescriptor::kConfigurableIndex,
     142         172 :         isolate->heap()->ToBoolean(configurable()));
     143          86 :     return result;
     144             :   }
     145       18951 :   if (IsRegularDataProperty()) {
     146             :     // Fast case for regular data properties.
     147             :     Handle<JSObject> result =
     148        9565 :         factory->NewJSObjectFromMap(isolate->data_property_descriptor_map());
     149             :     result->InObjectPropertyAtPut(JSDataPropertyDescriptor::kValueIndex,
     150        9565 :                                   *value());
     151             :     result->InObjectPropertyAtPut(JSDataPropertyDescriptor::kWritableIndex,
     152       19130 :                                   isolate->heap()->ToBoolean(writable()));
     153             :     result->InObjectPropertyAtPut(JSDataPropertyDescriptor::kEnumerableIndex,
     154       19130 :                                   isolate->heap()->ToBoolean(enumerable()));
     155             :     result->InObjectPropertyAtPut(JSDataPropertyDescriptor::kConfigurableIndex,
     156       19130 :                                   isolate->heap()->ToBoolean(configurable()));
     157        9565 :     return result;
     158             :   }
     159        9386 :   Handle<JSObject> result = factory->NewJSObject(isolate->object_function());
     160        9386 :   if (has_value()) {
     161         936 :     CreateDataProperty(result, factory->value_string(), value());
     162             :   }
     163        9386 :   if (has_writable()) {
     164          99 :     CreateDataProperty(result, factory->writable_string(),
     165          99 :                        factory->ToBoolean(writable()));
     166             :   }
     167        9386 :   if (has_get()) {
     168         108 :     CreateDataProperty(result, factory->get_string(), get());
     169             :   }
     170        9386 :   if (has_set()) {
     171          36 :     CreateDataProperty(result, factory->set_string(), set());
     172             :   }
     173        9386 :   if (has_enumerable()) {
     174         108 :     CreateDataProperty(result, factory->enumerable_string(),
     175         108 :                        factory->ToBoolean(enumerable()));
     176             :   }
     177        9386 :   if (has_configurable()) {
     178         342 :     CreateDataProperty(result, factory->configurable_string(),
     179         342 :                        factory->ToBoolean(configurable()));
     180             :   }
     181        9386 :   return result;
     182             : }
     183             : 
     184             : 
     185             : // ES6 6.2.4.5
     186             : // Returns false in case of exception.
     187             : // static
     188      141341 : bool PropertyDescriptor::ToPropertyDescriptor(Isolate* isolate,
     189             :                                               Handle<Object> obj,
     190             :                                               PropertyDescriptor* desc) {
     191             :   // 1. ReturnIfAbrupt(Obj).
     192             :   // 2. If Type(Obj) is not Object, throw a TypeError exception.
     193      141341 :   if (!obj->IsJSReceiver()) {
     194         306 :     isolate->Throw(*isolate->factory()->NewTypeError(
     195         306 :         MessageTemplate::kPropertyDescObject, obj));
     196         153 :     return false;
     197             :   }
     198             :   // 3. Let desc be a new Property Descriptor that initially has no fields.
     199             :   DCHECK(desc->is_empty());
     200             : 
     201      141188 :   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(obj);
     202      141188 :   if (ToPropertyDescriptorFastPath(isolate, receiver, desc)) {
     203             :     return true;
     204             :   }
     205             : 
     206             :   // enumerable?
     207             :   Handle<Object> enumerable;
     208             :   // 4 through 6b.
     209        6049 :   if (!GetPropertyIfPresent(receiver, isolate->factory()->enumerable_string(),
     210             :                             &enumerable)) {
     211             :     return false;
     212             :   }
     213             :   // 6c. Set the [[Enumerable]] field of desc to enum.
     214        6013 :   if (!enumerable.is_null()) {
     215        1508 :     desc->set_enumerable(enumerable->BooleanValue(isolate));
     216             :   }
     217             : 
     218             :   // configurable?
     219             :   Handle<Object> configurable;
     220             :   // 7 through 9b.
     221        6013 :   if (!GetPropertyIfPresent(receiver, isolate->factory()->configurable_string(),
     222             :                             &configurable)) {
     223             :     return false;
     224             :   }
     225             :   // 9c. Set the [[Configurable]] field of desc to conf.
     226        6013 :   if (!configurable.is_null()) {
     227        2730 :     desc->set_configurable(configurable->BooleanValue(isolate));
     228             :   }
     229             : 
     230             :   // value?
     231             :   Handle<Object> value;
     232             :   // 10 through 12b.
     233        6013 :   if (!GetPropertyIfPresent(receiver, isolate->factory()->value_string(),
     234             :                             &value)) {
     235             :     return false;
     236             :   }
     237             :   // 12c. Set the [[Value]] field of desc to value.
     238        5869 :   if (!value.is_null()) desc->set_value(value);
     239             : 
     240             :   // writable?
     241             :   Handle<Object> writable;
     242             :   // 13 through 15b.
     243        5869 :   if (!GetPropertyIfPresent(receiver, isolate->factory()->writable_string(),
     244             :                             &writable)) {
     245             :     return false;
     246             :   }
     247             :   // 15c. Set the [[Writable]] field of desc to writable.
     248        7417 :   if (!writable.is_null()) desc->set_writable(writable->BooleanValue(isolate));
     249             : 
     250             :   // getter?
     251             :   Handle<Object> getter;
     252             :   // 16 through 18b.
     253        5869 :   if (!GetPropertyIfPresent(receiver, isolate->factory()->get_string(),
     254             :                             &getter)) {
     255             :     return false;
     256             :   }
     257        5869 :   if (!getter.is_null()) {
     258             :     // 18c. If IsCallable(getter) is false and getter is not undefined,
     259             :     // throw a TypeError exception.
     260        3528 :     if (!getter->IsCallable() && !getter->IsUndefined(isolate)) {
     261          72 :       isolate->Throw(*isolate->factory()->NewTypeError(
     262          72 :           MessageTemplate::kObjectGetterCallable, getter));
     263          36 :       return false;
     264             :     }
     265             :     // 18d. Set the [[Get]] field of desc to getter.
     266             :     desc->set_get(getter);
     267             :   }
     268             :   // setter?
     269             :   Handle<Object> setter;
     270             :   // 19 through 21b.
     271        5833 :   if (!GetPropertyIfPresent(receiver, isolate->factory()->set_string(),
     272             :                             &setter)) {
     273             :     return false;
     274             :   }
     275        5833 :   if (!setter.is_null()) {
     276             :     // 21c. If IsCallable(setter) is false and setter is not undefined,
     277             :     // throw a TypeError exception.
     278        4611 :     if (!setter->IsCallable() && !setter->IsUndefined(isolate)) {
     279          54 :       isolate->Throw(*isolate->factory()->NewTypeError(
     280          54 :           MessageTemplate::kObjectSetterCallable, setter));
     281          27 :       return false;
     282             :     }
     283             :     // 21d. Set the [[Set]] field of desc to setter.
     284             :     desc->set_set(setter);
     285             :   }
     286             : 
     287             :   // 22. If either desc.[[Get]] or desc.[[Set]] is present, then
     288             :   // 22a. If either desc.[[Value]] or desc.[[Writable]] is present,
     289             :   // throw a TypeError exception.
     290       18363 :   if ((desc->has_get() || desc->has_set()) &&
     291        4077 :       (desc->has_value() || desc->has_writable())) {
     292         180 :     isolate->Throw(*isolate->factory()->NewTypeError(
     293         180 :         MessageTemplate::kValueAndAccessor, obj));
     294          90 :     return false;
     295             :   }
     296             : 
     297             :   // 23. Return desc.
     298             :   return true;
     299             : }
     300             : 
     301             : 
     302             : // ES6 6.2.4.6
     303             : // static
     304        3987 : void PropertyDescriptor::CompletePropertyDescriptor(Isolate* isolate,
     305             :                                                     PropertyDescriptor* desc) {
     306             :   // 1. ReturnIfAbrupt(Desc).
     307             :   // 2. Assert: Desc is a Property Descriptor.
     308             :   // 3. Let like be Record{
     309             :   //        [[Value]]: undefined, [[Writable]]: false,
     310             :   //        [[Get]]: undefined, [[Set]]: undefined,
     311             :   //        [[Enumerable]]: false, [[Configurable]]: false}.
     312             :   // 4. If either IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true,
     313             :   // then:
     314        3987 :   if (!IsAccessorDescriptor(desc)) {
     315             :     // 4a. If Desc does not have a [[Value]] field, set Desc.[[Value]] to
     316             :     //     like.[[Value]].
     317        3780 :     if (!desc->has_value()) {
     318             :       desc->set_value(isolate->factory()->undefined_value());
     319             :     }
     320             :     // 4b. If Desc does not have a [[Writable]] field, set Desc.[[Writable]]
     321             :     //     to like.[[Writable]].
     322        3780 :     if (!desc->has_writable()) desc->set_writable(false);
     323             :   } else {
     324             :     // 5. Else,
     325             :     // 5a. If Desc does not have a [[Get]] field, set Desc.[[Get]] to
     326             :     //     like.[[Get]].
     327         207 :     if (!desc->has_get()) {
     328             :       desc->set_get(isolate->factory()->undefined_value());
     329             :     }
     330             :     // 5b. If Desc does not have a [[Set]] field, set Desc.[[Set]] to
     331             :     //     like.[[Set]].
     332         207 :     if (!desc->has_set()) {
     333             :       desc->set_set(isolate->factory()->undefined_value());
     334             :     }
     335             :   }
     336             :   // 6. If Desc does not have an [[Enumerable]] field, set
     337             :   //    Desc.[[Enumerable]] to like.[[Enumerable]].
     338        3987 :   if (!desc->has_enumerable()) desc->set_enumerable(false);
     339             :   // 7. If Desc does not have a [[Configurable]] field, set
     340             :   //    Desc.[[Configurable]] to like.[[Configurable]].
     341        3987 :   if (!desc->has_configurable()) desc->set_configurable(false);
     342             :   // 8. Return Desc.
     343        3987 : }
     344             : 
     345       74072 : Handle<PropertyDescriptorObject> PropertyDescriptor::ToPropertyDescriptorObject(
     346             :     Isolate* isolate) {
     347             :   Handle<PropertyDescriptorObject> obj = Handle<PropertyDescriptorObject>::cast(
     348       74072 :       isolate->factory()->NewFixedArray(PropertyDescriptorObject::kLength));
     349             : 
     350             :   int flags =
     351      148144 :       PropertyDescriptorObject::IsEnumerableBit::encode(enumerable_) |
     352      148144 :       PropertyDescriptorObject::HasEnumerableBit::encode(has_enumerable_) |
     353      148144 :       PropertyDescriptorObject::IsConfigurableBit::encode(configurable_) |
     354      148144 :       PropertyDescriptorObject::HasConfigurableBit::encode(has_configurable_) |
     355      148144 :       PropertyDescriptorObject::IsWritableBit::encode(writable_) |
     356      148144 :       PropertyDescriptorObject::HasWritableBit::encode(has_writable_) |
     357       74072 :       PropertyDescriptorObject::HasValueBit::encode(has_value()) |
     358       74072 :       PropertyDescriptorObject::HasGetBit::encode(has_get()) |
     359       74072 :       PropertyDescriptorObject::HasSetBit::encode(has_set());
     360             : 
     361             :   obj->set(PropertyDescriptorObject::kFlagsIndex, Smi::FromInt(flags));
     362             : 
     363      224014 :   obj->set(PropertyDescriptorObject::kValueIndex,
     364       74072 :            has_value() ? *value_ : ReadOnlyRoots(isolate).the_hole_value());
     365      294490 :   obj->set(PropertyDescriptorObject::kGetIndex,
     366       74072 :            has_get() ? *get_ : ReadOnlyRoots(isolate).the_hole_value());
     367      294490 :   obj->set(PropertyDescriptorObject::kSetIndex,
     368       74072 :            has_set() ? *set_ : ReadOnlyRoots(isolate).the_hole_value());
     369             : 
     370       74072 :   return obj;
     371             : }
     372             : 
     373             : }  // namespace internal
     374      122036 : }  // namespace v8

Generated by: LCOV version 1.10