| Index: src/property-descriptor.cc | 
| diff --git a/src/property-descriptor.cc b/src/property-descriptor.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..442d056a1c081a6ca22b78ccbfcd5ef8dc056dbc | 
| --- /dev/null | 
| +++ b/src/property-descriptor.cc | 
| @@ -0,0 +1,221 @@ | 
| +// Copyright 2011 the V8 project authors. All rights reserved. | 
| +// Use of this source code is governed by a BSD-style license that can be | 
| +// found in the LICENSE file. | 
| + | 
| +#include "src/property-descriptor.h" | 
| + | 
| +#include "src/factory.h" | 
| +#include "src/isolate-inl.h" | 
| +#include "src/lookup.h" | 
| +#include "src/objects-inl.h" | 
| + | 
| +namespace v8 { | 
| +namespace internal { | 
| + | 
| +// Helper function for ToPropertyDescriptor. Comments describe steps for | 
| +// "enumerable", other properties are handled the same way. | 
| +// Returns false if an exception was thrown. | 
| +bool GetPropertyIfPresent(Handle<Object> obj, Handle<String> name, | 
| +                          Handle<Object>* value) { | 
| +  LookupIterator it(obj, name); | 
| +  // 4. Let hasEnumerable be HasProperty(Obj, "enumerable"). | 
| +  Maybe<PropertyAttributes> maybe_attr = JSReceiver::GetPropertyAttributes(&it); | 
| +  // 5. ReturnIfAbrupt(hasEnumerable). | 
| +  if (!maybe_attr.IsJust()) return false; | 
| +  // 6. If hasEnumerable is true, then | 
| +  if (maybe_attr.FromJust() != ABSENT) { | 
| +    // 6a. Let enum be ToBoolean(Get(Obj, "enumerable")). | 
| +    // 6b. ReturnIfAbrupt(enum). | 
| +    if (!JSObject::GetProperty(&it).ToHandle(value)) return false; | 
| +  } | 
| +  return true; | 
| +} | 
| + | 
| + | 
| +// Helper function for ToPropertyDescriptor. Handles the case of "simple" | 
| +// objects: nothing on the prototype chain, just own fast data properties. | 
| +// Must not have observable side effects, because the slow path will restart | 
| +// the entire conversion! | 
| +bool ToPropertyDescriptorFastPath(Isolate* isolate, Handle<Object> obj, | 
| +                                  PropertyDescriptor* desc) { | 
| +  if (!obj->IsJSObject()) return false; | 
| +  Map* map = Handle<JSObject>::cast(obj)->map(); | 
| +  if (map->instance_type() != JS_OBJECT_TYPE) return false; | 
| +  if (map->is_access_check_needed()) return false; | 
| +  if (map->prototype() != *isolate->initial_object_prototype()) return false; | 
| +  if (JSObject::cast(map->prototype())->map() != | 
| +      isolate->native_context()->object_function_prototype_map()) { | 
| +    return false; | 
| +  } | 
| +  // TODO(jkummerow): support dictionary properties? | 
| +  if (map->is_dictionary_map()) return false; | 
| +  Handle<DescriptorArray> descs = | 
| +      Handle<DescriptorArray>(map->instance_descriptors()); | 
| +  for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) { | 
| +    PropertyDetails details = descs->GetDetails(i); | 
| +    Name* key = descs->GetKey(i); | 
| +    Handle<Object> value; | 
| +    switch (details.type()) { | 
| +      case DATA: | 
| +        value = JSObject::FastPropertyAt(Handle<JSObject>::cast(obj), | 
| +                                         details.representation(), | 
| +                                         FieldIndex::ForDescriptor(map, i)); | 
| +        break; | 
| +      case DATA_CONSTANT: | 
| +        value = handle(descs->GetConstant(i), isolate); | 
| +        break; | 
| +      case ACCESSOR: | 
| +      case ACCESSOR_CONSTANT: | 
| +        // Bail out to slow path. | 
| +        return false; | 
| +    } | 
| +    Heap* heap = isolate->heap(); | 
| +    if (key == heap->enumerable_string()) { | 
| +      desc->set_enumerable(value->BooleanValue()); | 
| +    } else if (key == heap->configurable_string()) { | 
| +      desc->set_configurable(value->BooleanValue()); | 
| +    } else if (key == heap->value_string()) { | 
| +      desc->set_value(value); | 
| +    } else if (key == heap->writable_string()) { | 
| +      desc->set_writable(value->BooleanValue()); | 
| +    } else if (key == heap->get_string()) { | 
| +      // Bail out to slow path to throw an exception if necessary. | 
| +      if (!value->IsCallable()) return false; | 
| +      desc->set_get(value); | 
| +    } else if (key == heap->set_string()) { | 
| +      // Bail out to slow path to throw an exception if necessary. | 
| +      if (!value->IsCallable()) return false; | 
| +      desc->set_set(value); | 
| +    } | 
| +  } | 
| +  if ((desc->has_get() || desc->has_set()) && | 
| +      (desc->has_value() || desc->has_writable())) { | 
| +    // Bail out to slow path to throw an exception. | 
| +    return false; | 
| +  } | 
| +  return true; | 
| +} | 
| + | 
| + | 
| +// ES6 6.2.4.5 | 
| +// Returns false in case of exception. | 
| +// static | 
| +bool PropertyDescriptor::ToPropertyDescriptor(Isolate* isolate, | 
| +                                              Handle<Object> obj, | 
| +                                              PropertyDescriptor* desc) { | 
| +  // 1. ReturnIfAbrupt(Obj). | 
| +  // 2. If Type(Obj) is not Object, throw a TypeError exception. | 
| +  if (!obj->IsSpecObject()) { | 
| +    isolate->Throw(*isolate->factory()->NewTypeError( | 
| +        MessageTemplate::kPropertyDescObject, obj)); | 
| +    return false; | 
| +  } | 
| +  // 3. Let desc be a new Property Descriptor that initially has no fields. | 
| +  DCHECK(desc->is_empty()); | 
| + | 
| +  if (ToPropertyDescriptorFastPath(isolate, obj, desc)) { | 
| +    return true; | 
| +  } | 
| + | 
| +  // TODO(jkummerow): Implement JSProxy support. | 
| +  // Specifically, instead of taking the attributes != ABSENT shortcut, we | 
| +  // have to implement proper HasProperty for proxies. | 
| +  if (!obj->IsJSProxy()) { | 
| +    {  // enumerable? | 
| +      Handle<Object> enumerable; | 
| +      // 4 through 6b. | 
| +      if (!GetPropertyIfPresent(obj, isolate->factory()->enumerable_string(), | 
| +                                &enumerable)) { | 
| +        return false; | 
| +      } | 
| +      // 6c. Set the [[Enumerable]] field of desc to enum. | 
| +      if (!enumerable.is_null()) { | 
| +        desc->set_enumerable(enumerable->BooleanValue()); | 
| +      } | 
| +    } | 
| +    {  // configurable? | 
| +      Handle<Object> configurable; | 
| +      // 7 through 9b. | 
| +      if (!GetPropertyIfPresent(obj, isolate->factory()->configurable_string(), | 
| +                                &configurable)) { | 
| +        return false; | 
| +      } | 
| +      // 9c. Set the [[Configurable]] field of desc to conf. | 
| +      if (!configurable.is_null()) { | 
| +        desc->set_configurable(configurable->BooleanValue()); | 
| +      } | 
| +    } | 
| +    {  // value? | 
| +      Handle<Object> value; | 
| +      // 10 through 12b. | 
| +      if (!GetPropertyIfPresent(obj, isolate->factory()->value_string(), | 
| +                                &value)) | 
| +        return false; | 
| +      // 12c. Set the [[Value]] field of desc to value. | 
| +      if (!value.is_null()) desc->set_value(value); | 
| +    } | 
| +    {  // writable? | 
| +      Handle<Object> writable; | 
| +      // 13 through 15b. | 
| +      if (!GetPropertyIfPresent(obj, isolate->factory()->writable_string(), | 
| +                                &writable)) { | 
| +        return false; | 
| +      } | 
| +      // 15c. Set the [[Writable]] field of desc to writable. | 
| +      if (!writable.is_null()) desc->set_writable(writable->BooleanValue()); | 
| +    } | 
| +    {  // getter? | 
| +      Handle<Object> getter; | 
| +      // 16 through 18b. | 
| +      if (!GetPropertyIfPresent(obj, isolate->factory()->get_string(), &getter)) | 
| +        return false; | 
| +      if (!getter.is_null()) { | 
| +        // 18c. If IsCallable(getter) is false and getter is not undefined, | 
| +        // throw a TypeError exception. | 
| +        if (!getter->IsCallable() && !getter->IsUndefined()) { | 
| +          isolate->Throw(*isolate->factory()->NewTypeError( | 
| +              MessageTemplate::kObjectGetterCallable, getter)); | 
| +          return false; | 
| +        } | 
| +        // 18d. Set the [[Get]] field of desc to getter. | 
| +        desc->set_get(getter); | 
| +      } | 
| +      {  // setter? | 
| +        Handle<Object> setter; | 
| +        // 19 through 21b. | 
| +        if (!GetPropertyIfPresent(obj, isolate->factory()->set_string(), | 
| +                                  &setter)) | 
| +          return false; | 
| +        if (!setter.is_null()) { | 
| +          // 21c. If IsCallable(setter) is false and setter is not undefined, | 
| +          // throw a TypeError exception. | 
| +          if (!setter->IsCallable() && !setter->IsUndefined()) { | 
| +            isolate->Throw(*isolate->factory()->NewTypeError( | 
| +                MessageTemplate::kObjectSetterCallable, setter)); | 
| +            return false; | 
| +          } | 
| +          // 21d. Set the [[Set]] field of desc to setter. | 
| +          desc->set_set(setter); | 
| +        } | 
| +      } | 
| +      // 22. If either desc.[[Get]] or desc.[[Set]] is present, then | 
| +      // 22a. If either desc.[[Value]] or desc.[[Writable]] is present, | 
| +      // throw a TypeError exception. | 
| +      if ((desc->has_get() || desc->has_set()) && | 
| +          (desc->has_value() || desc->has_writable())) { | 
| +        isolate->Throw(*isolate->factory()->NewTypeError( | 
| +            MessageTemplate::kValueAndAccessor, obj)); | 
| +        return false; | 
| +      } | 
| +    } | 
| +  } else { | 
| +    DCHECK(obj->IsJSProxy()); | 
| +    UNIMPLEMENTED(); | 
| +  } | 
| +  // 23. Return desc. | 
| +  return true; | 
| +} | 
| + | 
| + | 
| +}  // namespace internal | 
| +}  // namespace v8 | 
|  |