builtins-object.cc 13.7 KB
Newer Older
1 2 3 4
// Copyright 2016 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.

5
#include "src/builtins/builtins-utils-inl.h"
6
#include "src/builtins/builtins.h"
7
#include "src/codegen/code-factory.h"
8
#include "src/common/message-template.h"
9
#include "src/heap/heap-inl.h"  // For ToBoolean. TODO(jkummerow): Drop.
10
#include "src/logging/counters.h"
11
#include "src/objects/keys.h"
12
#include "src/objects/lookup.h"
13
#include "src/objects/objects-inl.h"
14
#include "src/objects/property-descriptor.h"
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

namespace v8 {
namespace internal {

// -----------------------------------------------------------------------------
// ES6 section 19.1 Object Objects

// ES6 section 19.1.3.4 Object.prototype.propertyIsEnumerable ( V )
BUILTIN(ObjectPrototypePropertyIsEnumerable) {
  HandleScope scope(isolate);
  Handle<JSReceiver> object;
  Handle<Name> name;
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
      isolate, name, Object::ToName(isolate, args.atOrUndefined(isolate, 1)));
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
30
      isolate, object, Object::ToObject(isolate, args.receiver()));
31 32
  Maybe<PropertyAttributes> maybe =
      JSReceiver::GetOwnPropertyAttributes(object, name);
33 34
  if (maybe.IsNothing()) return ReadOnlyRoots(isolate).exception();
  if (maybe.FromJust() == ABSENT) return ReadOnlyRoots(isolate).false_value();
35 36 37 38 39 40
  return isolate->heap()->ToBoolean((maybe.FromJust() & DONT_ENUM) == 0);
}

// ES6 section 19.1.2.3 Object.defineProperties
BUILTIN(ObjectDefineProperties) {
  HandleScope scope(isolate);
41
  DCHECK_LE(3, args.length());
42 43
  Handle<Object> target = args.at(1);
  Handle<Object> properties = args.at(2);
44 45 46 47 48 49 50 51

  RETURN_RESULT_OR_FAILURE(
      isolate, JSReceiver::DefineProperties(isolate, target, properties));
}

// ES6 section 19.1.2.4 Object.defineProperty
BUILTIN(ObjectDefineProperty) {
  HandleScope scope(isolate);
52
  DCHECK_LE(4, args.length());
53 54 55
  Handle<Object> target = args.at(1);
  Handle<Object> key = args.at(2);
  Handle<Object> attributes = args.at(3);
56 57 58 59 60 61 62

  return JSReceiver::DefineProperty(isolate, target, key, attributes);
}

namespace {

template <AccessorComponent which_accessor>
63 64
Object ObjectDefineAccessor(Isolate* isolate, Handle<Object> object,
                            Handle<Object> name, Handle<Object> accessor) {
65 66
  // 1. Let O be ? ToObject(this value).
  Handle<JSReceiver> receiver;
67 68
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver,
                                     Object::ToObject(isolate, object));
69 70
  // 2. If IsCallable(getter) is false, throw a TypeError exception.
  if (!accessor->IsCallable()) {
71
    MessageTemplate message =
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
        which_accessor == ACCESSOR_GETTER
            ? MessageTemplate::kObjectGetterExpectingFunction
            : MessageTemplate::kObjectSetterExpectingFunction;
    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(message));
  }
  // 3. Let desc be PropertyDescriptor{[[Get]]: getter, [[Enumerable]]: true,
  //                                   [[Configurable]]: true}.
  PropertyDescriptor desc;
  if (which_accessor == ACCESSOR_GETTER) {
    desc.set_get(accessor);
  } else {
    DCHECK(which_accessor == ACCESSOR_SETTER);
    desc.set_set(accessor);
  }
  desc.set_enumerable(true);
  desc.set_configurable(true);
  // 4. Let key be ? ToPropertyKey(P).
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
                                     Object::ToPropertyKey(isolate, name));
  // 5. Perform ? DefinePropertyOrThrow(O, key, desc).
  // To preserve legacy behavior, we ignore errors silently rather than
  // throwing an exception.
94 95
  Maybe<bool> success = JSReceiver::DefineOwnProperty(
      isolate, receiver, name, &desc, Just(kThrowOnError));
96
  MAYBE_RETURN(success, ReadOnlyRoots(isolate).exception());
97 98 99 100
  if (!success.FromJust()) {
    isolate->CountUsage(v8::Isolate::kDefineGetterOrSetterWouldThrow);
  }
  // 6. Return undefined.
101
  return ReadOnlyRoots(isolate).undefined_value();
102 103
}

104 105
Object ObjectLookupAccessor(Isolate* isolate, Handle<Object> object,
                            Handle<Object> key, AccessorComponent component) {
106 107
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, object,
                                     Object::ToObject(isolate, object));
108 109 110
  // TODO(jkummerow/verwaest): LookupIterator::Key(..., bool*) performs a
  // functionally equivalent conversion, but handles element indices slightly
  // differently. Does one of the approaches have a performance advantage?
111 112
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key,
                                     Object::ToPropertyKey(isolate, key));
113 114 115
  LookupIterator::Key lookup_key(isolate, key);
  LookupIterator it(isolate, object, lookup_key,
                    LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
116 117 118 119 120 121 122 123 124 125 126 127

  for (; it.IsFound(); it.Next()) {
    switch (it.state()) {
      case LookupIterator::INTERCEPTOR:
      case LookupIterator::NOT_FOUND:
      case LookupIterator::TRANSITION:
        UNREACHABLE();

      case LookupIterator::ACCESS_CHECK:
        if (it.HasAccess()) continue;
        isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>());
        RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
128
        return ReadOnlyRoots(isolate).undefined_value();
129

130 131 132 133
      case LookupIterator::JSPROXY: {
        PropertyDescriptor desc;
        Maybe<bool> found = JSProxy::GetOwnPropertyDescriptor(
            isolate, it.GetHolder<JSProxy>(), it.GetName(), &desc);
134
        MAYBE_RETURN(found, ReadOnlyRoots(isolate).exception());
135 136 137 138 139 140 141
        if (found.FromJust()) {
          if (component == ACCESSOR_GETTER && desc.has_get()) {
            return *desc.get();
          }
          if (component == ACCESSOR_SETTER && desc.has_set()) {
            return *desc.set();
          }
142
          return ReadOnlyRoots(isolate).undefined_value();
143 144 145 146 147
        }
        Handle<Object> prototype;
        ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
            isolate, prototype, JSProxy::GetPrototype(it.GetHolder<JSProxy>()));
        if (prototype->IsNull(isolate)) {
148
          return ReadOnlyRoots(isolate).undefined_value();
149 150 151
        }
        return ObjectLookupAccessor(isolate, prototype, key, component);
      }
152 153 154

      case LookupIterator::INTEGER_INDEXED_EXOTIC:
      case LookupIterator::DATA:
155
        return ReadOnlyRoots(isolate).undefined_value();
156

157 158 159
      case LookupIterator::ACCESSOR: {
        Handle<Object> maybe_pair = it.GetAccessors();
        if (maybe_pair->IsAccessorPair()) {
160 161 162
          Handle<NativeContext> native_context = it.GetHolder<JSReceiver>()
                                                     ->GetCreationContext()
                                                     .ToHandleChecked();
163
          return *AccessorPair::GetComponent(
164 165
              isolate, native_context, Handle<AccessorPair>::cast(maybe_pair),
              component);
166 167 168 169 170
        }
      }
    }
  }

171
  return ReadOnlyRoots(isolate).undefined_value();
172 173 174 175 176 177 178 179
}

}  // namespace

// ES6 B.2.2.2 a.k.a.
// https://tc39.github.io/ecma262/#sec-object.prototype.__defineGetter__
BUILTIN(ObjectDefineGetter) {
  HandleScope scope(isolate);
180 181 182
  Handle<Object> object = args.at(0);  // Receiver.
  Handle<Object> name = args.at(1);
  Handle<Object> getter = args.at(2);
183 184 185 186 187 188 189
  return ObjectDefineAccessor<ACCESSOR_GETTER>(isolate, object, name, getter);
}

// ES6 B.2.2.3 a.k.a.
// https://tc39.github.io/ecma262/#sec-object.prototype.__defineSetter__
BUILTIN(ObjectDefineSetter) {
  HandleScope scope(isolate);
190 191 192
  Handle<Object> object = args.at(0);  // Receiver.
  Handle<Object> name = args.at(1);
  Handle<Object> setter = args.at(2);
193 194 195 196 197 198 199
  return ObjectDefineAccessor<ACCESSOR_SETTER>(isolate, object, name, setter);
}

// ES6 B.2.2.4 a.k.a.
// https://tc39.github.io/ecma262/#sec-object.prototype.__lookupGetter__
BUILTIN(ObjectLookupGetter) {
  HandleScope scope(isolate);
200 201
  Handle<Object> object = args.at(0);
  Handle<Object> name = args.at(1);
202 203 204 205 206 207 208
  return ObjectLookupAccessor(isolate, object, name, ACCESSOR_GETTER);
}

// ES6 B.2.2.5 a.k.a.
// https://tc39.github.io/ecma262/#sec-object.prototype.__lookupSetter__
BUILTIN(ObjectLookupSetter) {
  HandleScope scope(isolate);
209 210
  Handle<Object> object = args.at(0);
  Handle<Object> name = args.at(1);
211 212 213 214 215 216 217 218 219
  return ObjectLookupAccessor(isolate, object, name, ACCESSOR_SETTER);
}

// ES6 section 19.1.2.5 Object.freeze ( O )
BUILTIN(ObjectFreeze) {
  HandleScope scope(isolate);
  Handle<Object> object = args.atOrUndefined(isolate, 1);
  if (object->IsJSReceiver()) {
    MAYBE_RETURN(JSReceiver::SetIntegrityLevel(Handle<JSReceiver>::cast(object),
220
                                               FROZEN, kThrowOnError),
221
                 ReadOnlyRoots(isolate).exception());
222 223 224 225
  }
  return *object;
}

226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
// ES6 section B.2.2.1.1 get Object.prototype.__proto__
BUILTIN(ObjectPrototypeGetProto) {
  HandleScope scope(isolate);
  // 1. Let O be ? ToObject(this value).
  Handle<JSReceiver> receiver;
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
      isolate, receiver, Object::ToObject(isolate, args.receiver()));

  // 2. Return ? O.[[GetPrototypeOf]]().
  RETURN_RESULT_OR_FAILURE(isolate,
                           JSReceiver::GetPrototype(isolate, receiver));
}

// ES6 section B.2.2.1.2 set Object.prototype.__proto__
BUILTIN(ObjectPrototypeSetProto) {
  HandleScope scope(isolate);
  // 1. Let O be ? RequireObjectCoercible(this value).
  Handle<Object> object = args.receiver();
244
  if (object->IsNullOrUndefined(isolate)) {
245 246 247 248 249 250 251
    THROW_NEW_ERROR_RETURN_FAILURE(
        isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
                              isolate->factory()->NewStringFromAsciiChecked(
                                  "set Object.prototype.__proto__")));
  }

  // 2. If Type(proto) is neither Object nor Null, return undefined.
252
  Handle<Object> proto = args.at(1);
253
  if (!proto->IsNull(isolate) && !proto->IsJSReceiver()) {
254
    return ReadOnlyRoots(isolate).undefined_value();
255 256 257
  }

  // 3. If Type(O) is not Object, return undefined.
258
  if (!object->IsJSReceiver()) return ReadOnlyRoots(isolate).undefined_value();
259 260 261 262
  Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);

  // 4. Let status be ? O.[[SetPrototypeOf]](proto).
  // 5. If status is false, throw a TypeError exception.
263
  MAYBE_RETURN(JSReceiver::SetPrototype(receiver, proto, true, kThrowOnError),
264
               ReadOnlyRoots(isolate).exception());
265 266

  // Return undefined.
267
  return ReadOnlyRoots(isolate).undefined_value();
268 269
}

270 271
namespace {

272 273
Object GetOwnPropertyKeys(Isolate* isolate, BuiltinArguments args,
                          PropertyFilter filter) {
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
  HandleScope scope(isolate);
  Handle<Object> object = args.atOrUndefined(isolate, 1);
  Handle<JSReceiver> receiver;
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver,
                                     Object::ToObject(isolate, object));
  Handle<FixedArray> keys;
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
      isolate, keys,
      KeyAccumulator::GetKeys(receiver, KeyCollectionMode::kOwnOnly, filter,
                              GetKeysConversion::kConvertToString));
  return *isolate->factory()->NewJSArrayWithElements(keys);
}

}  // namespace

// ES6 section 19.1.2.8 Object.getOwnPropertySymbols ( O )
BUILTIN(ObjectGetOwnPropertySymbols) {
  return GetOwnPropertyKeys(isolate, args, SKIP_STRINGS);
}

// ES6 section 19.1.2.12 Object.isFrozen ( O )
BUILTIN(ObjectIsFrozen) {
  HandleScope scope(isolate);
  Handle<Object> object = args.atOrUndefined(isolate, 1);
  Maybe<bool> result = object->IsJSReceiver()
                           ? JSReceiver::TestIntegrityLevel(
                                 Handle<JSReceiver>::cast(object), FROZEN)
                           : Just(true);
302
  MAYBE_RETURN(result, ReadOnlyRoots(isolate).exception());
303 304 305 306 307 308 309 310 311 312 313
  return isolate->heap()->ToBoolean(result.FromJust());
}

// ES6 section 19.1.2.13 Object.isSealed ( O )
BUILTIN(ObjectIsSealed) {
  HandleScope scope(isolate);
  Handle<Object> object = args.atOrUndefined(isolate, 1);
  Maybe<bool> result = object->IsJSReceiver()
                           ? JSReceiver::TestIntegrityLevel(
                                 Handle<JSReceiver>::cast(object), SEALED)
                           : Just(true);
314
  MAYBE_RETURN(result, ReadOnlyRoots(isolate).exception());
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
  return isolate->heap()->ToBoolean(result.FromJust());
}

BUILTIN(ObjectGetOwnPropertyDescriptors) {
  HandleScope scope(isolate);
  Handle<Object> object = args.atOrUndefined(isolate, 1);

  Handle<JSReceiver> receiver;
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver,
                                     Object::ToObject(isolate, object));

  Handle<FixedArray> keys;
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
      isolate, keys, KeyAccumulator::GetKeys(
                         receiver, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES,
                         GetKeysConversion::kConvertToString));

  Handle<JSObject> descriptors =
      isolate->factory()->NewJSObject(isolate->object_function());

  for (int i = 0; i < keys->length(); ++i) {
    Handle<Name> key = Handle<Name>::cast(FixedArray::get(*keys, i, isolate));
    PropertyDescriptor descriptor;
    Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor(
        isolate, receiver, key, &descriptor);
340
    MAYBE_RETURN(did_get_descriptor, ReadOnlyRoots(isolate).exception());
341 342 343 344

    if (!did_get_descriptor.FromJust()) continue;
    Handle<Object> from_descriptor = descriptor.ToObject(isolate);

345
    Maybe<bool> success = JSReceiver::CreateDataProperty(
346
        isolate, descriptors, key, from_descriptor, Just(kDontThrow));
347 348 349 350 351 352 353 354 355 356 357 358
    CHECK(success.FromJust());
  }

  return *descriptors;
}

// ES6 section 19.1.2.17 Object.seal ( O )
BUILTIN(ObjectSeal) {
  HandleScope scope(isolate);
  Handle<Object> object = args.atOrUndefined(isolate, 1);
  if (object->IsJSReceiver()) {
    MAYBE_RETURN(JSReceiver::SetIntegrityLevel(Handle<JSReceiver>::cast(object),
359
                                               SEALED, kThrowOnError),
360
                 ReadOnlyRoots(isolate).exception());
361 362 363 364 365 366
  }
  return *object;
}

}  // namespace internal
}  // namespace v8