1// Copyright 2014 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/runtime/runtime-utils.h"
6
7#include "src/arguments.h"
8#include "src/bootstrapper.h"
9#include "src/debug/debug.h"
10#include "src/isolate-inl.h"
11#include "src/messages.h"
12#include "src/property-descriptor.h"
13#include "src/runtime/runtime.h"
14
15namespace v8 {
16namespace internal {
17
18MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate,
19                                               Handle<Object> object,
20                                               Handle<Object> key,
21                                               bool* is_found_out) {
22  if (object->IsUndefined(isolate) || object->IsNull(isolate)) {
23    THROW_NEW_ERROR(
24        isolate,
25        NewTypeError(MessageTemplate::kNonObjectPropertyLoad, key, object),
26        Object);
27  }
28
29  bool success = false;
30  LookupIterator it =
31      LookupIterator::PropertyOrElement(isolate, object, key, &success);
32  if (!success) return MaybeHandle<Object>();
33
34  MaybeHandle<Object> result = Object::GetProperty(&it);
35  if (is_found_out) *is_found_out = it.IsFound();
36  return result;
37}
38
39static MaybeHandle<Object> KeyedGetObjectProperty(Isolate* isolate,
40                                                  Handle<Object> receiver_obj,
41                                                  Handle<Object> key_obj) {
42  // Fast cases for getting named properties of the receiver JSObject
43  // itself.
44  //
45  // The global proxy objects has to be excluded since LookupOwn on
46  // the global proxy object can return a valid result even though the
47  // global proxy object never has properties.  This is the case
48  // because the global proxy object forwards everything to its hidden
49  // prototype including own lookups.
50  //
51  // Additionally, we need to make sure that we do not cache results
52  // for objects that require access checks.
53  if (receiver_obj->IsJSObject()) {
54    if (!receiver_obj->IsJSGlobalProxy() &&
55        !receiver_obj->IsAccessCheckNeeded() && key_obj->IsName()) {
56      DisallowHeapAllocation no_allocation;
57      Handle<JSObject> receiver = Handle<JSObject>::cast(receiver_obj);
58      Handle<Name> key = Handle<Name>::cast(key_obj);
59      if (receiver->IsJSGlobalObject()) {
60        // Attempt dictionary lookup.
61        GlobalDictionary* dictionary = receiver->global_dictionary();
62        int entry = dictionary->FindEntry(key);
63        if (entry != GlobalDictionary::kNotFound) {
64          DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
65          PropertyCell* cell = PropertyCell::cast(dictionary->ValueAt(entry));
66          if (cell->property_details().type() == DATA) {
67            Object* value = cell->value();
68            if (!value->IsTheHole(isolate)) {
69              return Handle<Object>(value, isolate);
70            }
71            // If value is the hole (meaning, absent) do the general lookup.
72          }
73        }
74      } else if (!receiver->HasFastProperties()) {
75        // Attempt dictionary lookup.
76        NameDictionary* dictionary = receiver->property_dictionary();
77        int entry = dictionary->FindEntry(key);
78        if ((entry != NameDictionary::kNotFound) &&
79            (dictionary->DetailsAt(entry).type() == DATA)) {
80          Object* value = dictionary->ValueAt(entry);
81          return Handle<Object>(value, isolate);
82        }
83      }
84    } else if (key_obj->IsSmi()) {
85      // JSObject without a name key. If the key is a Smi, check for a
86      // definite out-of-bounds access to elements, which is a strong indicator
87      // that subsequent accesses will also call the runtime. Proactively
88      // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of
89      // doubles for those future calls in the case that the elements would
90      // become FAST_DOUBLE_ELEMENTS.
91      Handle<JSObject> js_object = Handle<JSObject>::cast(receiver_obj);
92      ElementsKind elements_kind = js_object->GetElementsKind();
93      if (IsFastDoubleElementsKind(elements_kind)) {
94        if (Smi::cast(*key_obj)->value() >= js_object->elements()->length()) {
95          elements_kind = IsFastHoleyElementsKind(elements_kind)
96                              ? FAST_HOLEY_ELEMENTS
97                              : FAST_ELEMENTS;
98          JSObject::TransitionElementsKind(js_object, elements_kind);
99        }
100      } else {
101        DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) ||
102               !IsFastElementsKind(elements_kind));
103      }
104    }
105  } else if (receiver_obj->IsString() && key_obj->IsSmi()) {
106    // Fast case for string indexing using [] with a smi index.
107    Handle<String> str = Handle<String>::cast(receiver_obj);
108    int index = Handle<Smi>::cast(key_obj)->value();
109    if (index >= 0 && index < str->length()) {
110      Factory* factory = isolate->factory();
111      return factory->LookupSingleCharacterStringFromCode(
112          String::Flatten(str)->Get(index));
113    }
114  }
115
116  // Fall back to GetObjectProperty.
117  return Runtime::GetObjectProperty(isolate, receiver_obj, key_obj);
118}
119
120
121Maybe<bool> Runtime::DeleteObjectProperty(Isolate* isolate,
122                                          Handle<JSReceiver> receiver,
123                                          Handle<Object> key,
124                                          LanguageMode language_mode) {
125  bool success = false;
126  LookupIterator it = LookupIterator::PropertyOrElement(
127      isolate, receiver, key, &success, LookupIterator::OWN);
128  if (!success) return Nothing<bool>();
129
130  return JSReceiver::DeleteProperty(&it, language_mode);
131}
132
133// ES6 19.1.3.2
134RUNTIME_FUNCTION(Runtime_ObjectHasOwnProperty) {
135  HandleScope scope(isolate);
136  Handle<Object> property = args.at<Object>(1);
137
138  Handle<Name> key;
139  uint32_t index;
140  bool key_is_array_index = property->ToArrayIndex(&index);
141
142  if (!key_is_array_index) {
143    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key,
144                                       Object::ToName(isolate, property));
145    key_is_array_index = key->AsArrayIndex(&index);
146  }
147
148  Handle<Object> object = args.at<Object>(0);
149
150  if (object->IsJSObject()) {
151    Handle<JSObject> js_obj = Handle<JSObject>::cast(object);
152    // Fast case: either the key is a real named property or it is not
153    // an array index and there are no interceptors or hidden
154    // prototypes.
155    // TODO(jkummerow): Make JSReceiver::HasOwnProperty fast enough to
156    // handle all cases directly (without this custom fast path).
157    {
158      LookupIterator::Configuration c = LookupIterator::OWN_SKIP_INTERCEPTOR;
159      LookupIterator it =
160          key_is_array_index ? LookupIterator(isolate, js_obj, index, js_obj, c)
161                             : LookupIterator(js_obj, key, js_obj, c);
162      Maybe<bool> maybe = JSReceiver::HasProperty(&it);
163      if (maybe.IsNothing()) return isolate->heap()->exception();
164      DCHECK(!isolate->has_pending_exception());
165      if (maybe.FromJust()) return isolate->heap()->true_value();
166    }
167
168    Map* map = js_obj->map();
169    if (!map->has_hidden_prototype() &&
170        (key_is_array_index ? !map->has_indexed_interceptor()
171                            : !map->has_named_interceptor())) {
172      return isolate->heap()->false_value();
173    }
174
175    // Slow case.
176    LookupIterator::Configuration c = LookupIterator::OWN;
177    LookupIterator it = key_is_array_index
178                            ? LookupIterator(isolate, js_obj, index, js_obj, c)
179                            : LookupIterator(js_obj, key, js_obj, c);
180
181    Maybe<bool> maybe = JSReceiver::HasProperty(&it);
182    if (maybe.IsNothing()) return isolate->heap()->exception();
183    DCHECK(!isolate->has_pending_exception());
184    return isolate->heap()->ToBoolean(maybe.FromJust());
185
186  } else if (object->IsJSProxy()) {
187    if (key.is_null()) {
188      DCHECK(key_is_array_index);
189      key = isolate->factory()->Uint32ToString(index);
190    }
191
192    Maybe<bool> result =
193        JSReceiver::HasOwnProperty(Handle<JSProxy>::cast(object), key);
194    if (!result.IsJust()) return isolate->heap()->exception();
195    return isolate->heap()->ToBoolean(result.FromJust());
196
197  } else if (object->IsString()) {
198    return isolate->heap()->ToBoolean(
199        key_is_array_index
200            ? index < static_cast<uint32_t>(String::cast(*object)->length())
201            : key->Equals(isolate->heap()->length_string()));
202  } else if (object->IsNull(isolate) || object->IsUndefined(isolate)) {
203    THROW_NEW_ERROR_RETURN_FAILURE(
204        isolate, NewTypeError(MessageTemplate::kUndefinedOrNullToObject));
205  }
206
207  return isolate->heap()->false_value();
208}
209
210// ES6 section 19.1.2.2 Object.create ( O [ , Properties ] )
211// TODO(verwaest): Support the common cases with precached map directly in
212// an Object.create stub.
213RUNTIME_FUNCTION(Runtime_ObjectCreate) {
214  HandleScope scope(isolate);
215  Handle<Object> prototype = args.at<Object>(0);
216  if (!prototype->IsNull(isolate) && !prototype->IsJSReceiver()) {
217    THROW_NEW_ERROR_RETURN_FAILURE(
218        isolate, NewTypeError(MessageTemplate::kProtoObjectOrNull, prototype));
219  }
220
221  // Generate the map with the specified {prototype} based on the Object
222  // function's initial map from the current native context.
223  // TODO(bmeurer): Use a dedicated cache for Object.create; think about
224  // slack tracking for Object.create.
225  Handle<Map> map(isolate->native_context()->object_function()->initial_map(),
226                  isolate);
227  if (map->prototype() != *prototype) {
228    if (prototype->IsNull(isolate)) {
229      map = isolate->slow_object_with_null_prototype_map();
230    } else if (prototype->IsJSObject()) {
231      Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype);
232      if (!js_prototype->map()->is_prototype_map()) {
233        JSObject::OptimizeAsPrototype(js_prototype, FAST_PROTOTYPE);
234      }
235      Handle<PrototypeInfo> info =
236          Map::GetOrCreatePrototypeInfo(js_prototype, isolate);
237      // TODO(verwaest): Use inobject slack tracking for this map.
238      if (info->HasObjectCreateMap()) {
239        map = handle(info->ObjectCreateMap(), isolate);
240      } else {
241        map = Map::CopyInitialMap(map);
242        Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
243        PrototypeInfo::SetObjectCreateMap(info, map);
244      }
245    } else {
246      map = Map::TransitionToPrototype(map, prototype, REGULAR_PROTOTYPE);
247    }
248  }
249
250  bool is_dictionary_map = map->is_dictionary_map();
251  Handle<FixedArray> object_properties;
252  if (is_dictionary_map) {
253    // Allocate the actual properties dictionay up front to avoid invalid object
254    // state.
255    object_properties =
256        NameDictionary::New(isolate, NameDictionary::kInitialCapacity);
257  }
258  // Actually allocate the object.
259  Handle<JSObject> object = isolate->factory()->NewJSObjectFromMap(map);
260  if (is_dictionary_map) {
261    object->set_properties(*object_properties);
262  }
263
264  // Define the properties if properties was specified and is not undefined.
265  Handle<Object> properties = args.at<Object>(1);
266  if (!properties->IsUndefined(isolate)) {
267    RETURN_FAILURE_ON_EXCEPTION(
268        isolate, JSReceiver::DefineProperties(isolate, object, properties));
269  }
270
271  return *object;
272}
273
274MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate,
275                                               Handle<Object> object,
276                                               Handle<Object> key,
277                                               Handle<Object> value,
278                                               LanguageMode language_mode) {
279  if (object->IsUndefined(isolate) || object->IsNull(isolate)) {
280    THROW_NEW_ERROR(
281        isolate,
282        NewTypeError(MessageTemplate::kNonObjectPropertyStore, key, object),
283        Object);
284  }
285
286  // Check if the given key is an array index.
287  bool success = false;
288  LookupIterator it =
289      LookupIterator::PropertyOrElement(isolate, object, key, &success);
290  if (!success) return MaybeHandle<Object>();
291
292  MAYBE_RETURN_NULL(Object::SetProperty(&it, value, language_mode,
293                                        Object::MAY_BE_STORE_FROM_KEYED));
294  return value;
295}
296
297
298RUNTIME_FUNCTION(Runtime_GetPrototype) {
299  HandleScope scope(isolate);
300  DCHECK(args.length() == 1);
301  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0);
302  RETURN_RESULT_OR_FAILURE(isolate, JSReceiver::GetPrototype(isolate, obj));
303}
304
305
306RUNTIME_FUNCTION(Runtime_InternalSetPrototype) {
307  HandleScope scope(isolate);
308  DCHECK(args.length() == 2);
309  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0);
310  CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
311  MAYBE_RETURN(
312      JSReceiver::SetPrototype(obj, prototype, false, Object::THROW_ON_ERROR),
313      isolate->heap()->exception());
314  return *obj;
315}
316
317RUNTIME_FUNCTION(Runtime_OptimizeObjectForAddingMultipleProperties) {
318  HandleScope scope(isolate);
319  DCHECK(args.length() == 2);
320  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
321  CONVERT_SMI_ARG_CHECKED(properties, 1);
322  // Conservative upper limit to prevent fuzz tests from going OOM.
323  if (properties > 100000) return isolate->ThrowIllegalOperation();
324  if (object->HasFastProperties() && !object->IsJSGlobalProxy()) {
325    JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties,
326                                  "OptimizeForAdding");
327  }
328  return *object;
329}
330
331
332RUNTIME_FUNCTION(Runtime_GetProperty) {
333  HandleScope scope(isolate);
334  DCHECK(args.length() == 2);
335
336  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
337  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
338
339  RETURN_RESULT_OR_FAILURE(isolate,
340                           Runtime::GetObjectProperty(isolate, object, key));
341}
342
343// KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric.
344RUNTIME_FUNCTION(Runtime_KeyedGetProperty) {
345  HandleScope scope(isolate);
346  DCHECK(args.length() == 2);
347
348  CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0);
349  CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1);
350
351  RETURN_RESULT_OR_FAILURE(
352      isolate, KeyedGetObjectProperty(isolate, receiver_obj, key_obj));
353}
354
355RUNTIME_FUNCTION(Runtime_AddNamedProperty) {
356  HandleScope scope(isolate);
357  DCHECK_EQ(4, args.length());
358
359  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
360  CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
361  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
362  CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3);
363
364#ifdef DEBUG
365  uint32_t index = 0;
366  DCHECK(!name->ToArrayIndex(&index));
367  LookupIterator it(object, name, object, LookupIterator::OWN_SKIP_INTERCEPTOR);
368  Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
369  if (!maybe.IsJust()) return isolate->heap()->exception();
370  CHECK(!it.IsFound());
371#endif
372
373  RETURN_RESULT_OR_FAILURE(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
374                                        object, name, value, attrs));
375}
376
377
378// Adds an element to an array.
379// This is used to create an indexed data property into an array.
380RUNTIME_FUNCTION(Runtime_AddElement) {
381  HandleScope scope(isolate);
382  DCHECK_EQ(3, args.length());
383
384  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
385  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
386  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
387
388  uint32_t index = 0;
389  CHECK(key->ToArrayIndex(&index));
390
391#ifdef DEBUG
392  LookupIterator it(isolate, object, index, object,
393                    LookupIterator::OWN_SKIP_INTERCEPTOR);
394  Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
395  if (!maybe.IsJust()) return isolate->heap()->exception();
396  CHECK(!it.IsFound());
397
398  if (object->IsJSArray()) {
399    Handle<JSArray> array = Handle<JSArray>::cast(object);
400    CHECK(!JSArray::WouldChangeReadOnlyLength(array, index));
401  }
402#endif
403
404  RETURN_RESULT_OR_FAILURE(isolate, JSObject::SetOwnElementIgnoreAttributes(
405                                        object, index, value, NONE));
406}
407
408
409RUNTIME_FUNCTION(Runtime_AppendElement) {
410  HandleScope scope(isolate);
411  DCHECK_EQ(2, args.length());
412
413  CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
414  CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
415  CHECK(!value->IsTheHole(isolate));
416
417  uint32_t index;
418  CHECK(array->length()->ToArrayIndex(&index));
419
420  RETURN_FAILURE_ON_EXCEPTION(
421      isolate, JSObject::AddDataElement(array, index, value, NONE));
422  JSObject::ValidateElements(array);
423  return *array;
424}
425
426
427RUNTIME_FUNCTION(Runtime_SetProperty) {
428  HandleScope scope(isolate);
429  DCHECK_EQ(4, args.length());
430
431  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
432  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
433  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
434  CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 3);
435
436  RETURN_RESULT_OR_FAILURE(
437      isolate,
438      Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
439}
440
441
442namespace {
443
444// ES6 section 12.5.4.
445Object* DeleteProperty(Isolate* isolate, Handle<Object> object,
446                       Handle<Object> key, LanguageMode language_mode) {
447  Handle<JSReceiver> receiver;
448  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver,
449                                     Object::ToObject(isolate, object));
450  Maybe<bool> result =
451      Runtime::DeleteObjectProperty(isolate, receiver, key, language_mode);
452  MAYBE_RETURN(result, isolate->heap()->exception());
453  return isolate->heap()->ToBoolean(result.FromJust());
454}
455
456}  // namespace
457
458
459RUNTIME_FUNCTION(Runtime_DeleteProperty_Sloppy) {
460  HandleScope scope(isolate);
461  DCHECK_EQ(2, args.length());
462  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
463  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
464  return DeleteProperty(isolate, object, key, SLOPPY);
465}
466
467
468RUNTIME_FUNCTION(Runtime_DeleteProperty_Strict) {
469  HandleScope scope(isolate);
470  DCHECK_EQ(2, args.length());
471  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
472  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
473  return DeleteProperty(isolate, object, key, STRICT);
474}
475
476
477// ES6 section 12.9.3, operator in.
478RUNTIME_FUNCTION(Runtime_HasProperty) {
479  HandleScope scope(isolate);
480  DCHECK_EQ(2, args.length());
481  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
482  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
483
484  // Check that {object} is actually a receiver.
485  if (!object->IsJSReceiver()) {
486    THROW_NEW_ERROR_RETURN_FAILURE(
487        isolate,
488        NewTypeError(MessageTemplate::kInvalidInOperatorUse, key, object));
489  }
490  Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
491
492  // Convert the {key} to a name.
493  Handle<Name> name;
494  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
495                                     Object::ToName(isolate, key));
496
497  // Lookup the {name} on {receiver}.
498  Maybe<bool> maybe = JSReceiver::HasProperty(receiver, name);
499  if (!maybe.IsJust()) return isolate->heap()->exception();
500  return isolate->heap()->ToBoolean(maybe.FromJust());
501}
502
503
504RUNTIME_FUNCTION(Runtime_GetOwnPropertyKeys) {
505  HandleScope scope(isolate);
506  DCHECK(args.length() == 2);
507  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
508  CONVERT_SMI_ARG_CHECKED(filter_value, 1);
509  PropertyFilter filter = static_cast<PropertyFilter>(filter_value);
510
511  Handle<FixedArray> keys;
512  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
513      isolate, keys,
514      KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, filter,
515                              GetKeysConversion::kConvertToString));
516
517  return *isolate->factory()->NewJSArrayWithElements(keys);
518}
519
520
521// Return information on whether an object has a named or indexed interceptor.
522// args[0]: object
523RUNTIME_FUNCTION(Runtime_GetInterceptorInfo) {
524  HandleScope scope(isolate);
525  DCHECK(args.length() == 1);
526  if (!args[0]->IsJSObject()) {
527    return Smi::kZero;
528  }
529  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
530
531  int result = 0;
532  if (obj->HasNamedInterceptor()) result |= 2;
533  if (obj->HasIndexedInterceptor()) result |= 1;
534
535  return Smi::FromInt(result);
536}
537
538
539RUNTIME_FUNCTION(Runtime_ToFastProperties) {
540  HandleScope scope(isolate);
541  DCHECK(args.length() == 1);
542  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
543  if (object->IsJSObject() && !object->IsJSGlobalObject()) {
544    JSObject::MigrateSlowToFast(Handle<JSObject>::cast(object), 0,
545                                "RuntimeToFastProperties");
546  }
547  return *object;
548}
549
550
551RUNTIME_FUNCTION(Runtime_AllocateHeapNumber) {
552  HandleScope scope(isolate);
553  DCHECK(args.length() == 0);
554  return *isolate->factory()->NewHeapNumber(0);
555}
556
557
558RUNTIME_FUNCTION(Runtime_NewObject) {
559  HandleScope scope(isolate);
560  DCHECK_EQ(2, args.length());
561  CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
562  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, new_target, 1);
563  RETURN_RESULT_OR_FAILURE(isolate, JSObject::New(target, new_target));
564}
565
566
567RUNTIME_FUNCTION(Runtime_FinalizeInstanceSize) {
568  HandleScope scope(isolate);
569  DCHECK(args.length() == 1);
570
571  CONVERT_ARG_HANDLE_CHECKED(Map, initial_map, 0);
572  initial_map->CompleteInobjectSlackTracking();
573
574  return isolate->heap()->undefined_value();
575}
576
577
578RUNTIME_FUNCTION(Runtime_LoadMutableDouble) {
579  HandleScope scope(isolate);
580  DCHECK(args.length() == 2);
581  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
582  CONVERT_ARG_HANDLE_CHECKED(Smi, index, 1);
583  CHECK((index->value() & 1) == 1);
584  FieldIndex field_index =
585      FieldIndex::ForLoadByFieldIndex(object->map(), index->value());
586  if (field_index.is_inobject()) {
587    CHECK(field_index.property_index() <
588          object->map()->GetInObjectProperties());
589  } else {
590    CHECK(field_index.outobject_array_index() < object->properties()->length());
591  }
592  return *JSObject::FastPropertyAt(object, Representation::Double(),
593                                   field_index);
594}
595
596
597RUNTIME_FUNCTION(Runtime_TryMigrateInstance) {
598  HandleScope scope(isolate);
599  DCHECK(args.length() == 1);
600  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
601  if (!object->IsJSObject()) return Smi::kZero;
602  Handle<JSObject> js_object = Handle<JSObject>::cast(object);
603  if (!js_object->map()->is_deprecated()) return Smi::kZero;
604  // This call must not cause lazy deopts, because it's called from deferred
605  // code where we can't handle lazy deopts for lack of a suitable bailout
606  // ID. So we just try migration and signal failure if necessary,
607  // which will also trigger a deopt.
608  if (!JSObject::TryMigrateInstance(js_object)) return Smi::kZero;
609  return *object;
610}
611
612
613RUNTIME_FUNCTION(Runtime_IsJSGlobalProxy) {
614  SealHandleScope shs(isolate);
615  DCHECK(args.length() == 1);
616  CONVERT_ARG_CHECKED(Object, obj, 0);
617  return isolate->heap()->ToBoolean(obj->IsJSGlobalProxy());
618}
619
620static bool IsValidAccessor(Isolate* isolate, Handle<Object> obj) {
621  return obj->IsUndefined(isolate) || obj->IsCallable() || obj->IsNull(isolate);
622}
623
624
625// Implements part of 8.12.9 DefineOwnProperty.
626// There are 3 cases that lead here:
627// Step 4b - define a new accessor property.
628// Steps 9c & 12 - replace an existing data property with an accessor property.
629// Step 12 - update an existing accessor property with an accessor or generic
630//           descriptor.
631RUNTIME_FUNCTION(Runtime_DefineAccessorPropertyUnchecked) {
632  HandleScope scope(isolate);
633  DCHECK(args.length() == 5);
634  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
635  CHECK(!obj->IsNull(isolate));
636  CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
637  CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
638  CHECK(IsValidAccessor(isolate, getter));
639  CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
640  CHECK(IsValidAccessor(isolate, setter));
641  CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 4);
642
643  RETURN_FAILURE_ON_EXCEPTION(
644      isolate, JSObject::DefineAccessor(obj, name, getter, setter, attrs));
645  return isolate->heap()->undefined_value();
646}
647
648
649RUNTIME_FUNCTION(Runtime_DefineDataPropertyInLiteral) {
650  HandleScope scope(isolate);
651  DCHECK(args.length() == 5);
652  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
653  CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
654  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
655  CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3);
656  CONVERT_SMI_ARG_CHECKED(set_function_name, 4);
657
658  if (set_function_name) {
659    DCHECK(value->IsJSFunction());
660    JSFunction::SetName(Handle<JSFunction>::cast(value), name,
661                        isolate->factory()->empty_string());
662  }
663
664  LookupIterator it = LookupIterator::PropertyOrElement(
665      isolate, object, name, object, LookupIterator::OWN);
666  // Cannot fail since this should only be called when
667  // creating an object literal.
668  CHECK(JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, attrs,
669                                                    Object::DONT_THROW)
670            .IsJust());
671  return *object;
672}
673
674RUNTIME_FUNCTION(Runtime_DefineDataProperty) {
675  HandleScope scope(isolate);
676  DCHECK(args.length() == 5);
677  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
678  CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
679  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
680  CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3);
681  CONVERT_SMI_ARG_CHECKED(set_function_name, 4);
682
683  if (set_function_name) {
684    DCHECK(value->IsJSFunction());
685    JSFunction::SetName(Handle<JSFunction>::cast(value), name,
686                        isolate->factory()->empty_string());
687  }
688
689  PropertyDescriptor desc;
690  desc.set_writable(!(attrs & ReadOnly));
691  desc.set_enumerable(!(attrs & DontEnum));
692  desc.set_configurable(!(attrs & DontDelete));
693  desc.set_value(value);
694
695  Maybe<bool> result = JSReceiver::DefineOwnProperty(isolate, receiver, name,
696                                                     &desc, Object::DONT_THROW);
697  RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
698  if (result.IsNothing()) {
699    DCHECK(isolate->has_pending_exception());
700    return isolate->heap()->exception();
701  }
702
703  return *receiver;
704}
705
706// Return property without being observable by accessors or interceptors.
707RUNTIME_FUNCTION(Runtime_GetDataProperty) {
708  HandleScope scope(isolate);
709  DCHECK(args.length() == 2);
710  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
711  CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
712  return *JSReceiver::GetDataProperty(object, name);
713}
714
715RUNTIME_FUNCTION(Runtime_GetConstructorName) {
716  HandleScope scope(isolate);
717  DCHECK(args.length() == 1);
718  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
719
720  CHECK(!object->IsUndefined(isolate) && !object->IsNull(isolate));
721  Handle<JSReceiver> recv = Object::ToObject(isolate, object).ToHandleChecked();
722  return *JSReceiver::GetConstructorName(recv);
723}
724
725RUNTIME_FUNCTION(Runtime_HasFastPackedElements) {
726  SealHandleScope shs(isolate);
727  DCHECK(args.length() == 1);
728  CONVERT_ARG_CHECKED(HeapObject, obj, 0);
729  return isolate->heap()->ToBoolean(
730      IsFastPackedElementsKind(obj->map()->elements_kind()));
731}
732
733
734RUNTIME_FUNCTION(Runtime_ValueOf) {
735  SealHandleScope shs(isolate);
736  DCHECK(args.length() == 1);
737  CONVERT_ARG_CHECKED(Object, obj, 0);
738  if (!obj->IsJSValue()) return obj;
739  return JSValue::cast(obj)->value();
740}
741
742
743RUNTIME_FUNCTION(Runtime_IsJSReceiver) {
744  SealHandleScope shs(isolate);
745  DCHECK(args.length() == 1);
746  CONVERT_ARG_CHECKED(Object, obj, 0);
747  return isolate->heap()->ToBoolean(obj->IsJSReceiver());
748}
749
750
751RUNTIME_FUNCTION(Runtime_ClassOf) {
752  SealHandleScope shs(isolate);
753  DCHECK(args.length() == 1);
754  CONVERT_ARG_CHECKED(Object, obj, 0);
755  if (!obj->IsJSReceiver()) return isolate->heap()->null_value();
756  return JSReceiver::cast(obj)->class_name();
757}
758
759
760RUNTIME_FUNCTION(Runtime_DefineGetterPropertyUnchecked) {
761  HandleScope scope(isolate);
762  DCHECK(args.length() == 4);
763  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
764  CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
765  CONVERT_ARG_HANDLE_CHECKED(JSFunction, getter, 2);
766  CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3);
767
768  if (String::cast(getter->shared()->name())->length() == 0) {
769    JSFunction::SetName(getter, name, isolate->factory()->get_string());
770  }
771
772  RETURN_FAILURE_ON_EXCEPTION(
773      isolate,
774      JSObject::DefineAccessor(object, name, getter,
775                               isolate->factory()->null_value(), attrs));
776  return isolate->heap()->undefined_value();
777}
778
779
780RUNTIME_FUNCTION(Runtime_DefineSetterPropertyUnchecked) {
781  HandleScope scope(isolate);
782  DCHECK(args.length() == 4);
783  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
784  CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
785  CONVERT_ARG_HANDLE_CHECKED(JSFunction, setter, 2);
786  CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3);
787
788  if (String::cast(setter->shared()->name())->length() == 0) {
789    JSFunction::SetName(setter, name, isolate->factory()->set_string());
790  }
791
792  RETURN_FAILURE_ON_EXCEPTION(
793      isolate,
794      JSObject::DefineAccessor(object, name, isolate->factory()->null_value(),
795                               setter, attrs));
796  return isolate->heap()->undefined_value();
797}
798
799
800RUNTIME_FUNCTION(Runtime_ToObject) {
801  HandleScope scope(isolate);
802  DCHECK_EQ(1, args.length());
803  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
804  RETURN_RESULT_OR_FAILURE(isolate, Object::ToObject(isolate, object));
805}
806
807
808RUNTIME_FUNCTION(Runtime_ToPrimitive) {
809  HandleScope scope(isolate);
810  DCHECK_EQ(1, args.length());
811  CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
812  RETURN_RESULT_OR_FAILURE(isolate, Object::ToPrimitive(input));
813}
814
815
816RUNTIME_FUNCTION(Runtime_ToPrimitive_Number) {
817  HandleScope scope(isolate);
818  DCHECK_EQ(1, args.length());
819  CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
820  RETURN_RESULT_OR_FAILURE(
821      isolate, Object::ToPrimitive(input, ToPrimitiveHint::kNumber));
822}
823
824RUNTIME_FUNCTION(Runtime_ToNumber) {
825  HandleScope scope(isolate);
826  DCHECK_EQ(1, args.length());
827  CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
828  RETURN_RESULT_OR_FAILURE(isolate, Object::ToNumber(input));
829}
830
831
832RUNTIME_FUNCTION(Runtime_ToInteger) {
833  HandleScope scope(isolate);
834  DCHECK_EQ(1, args.length());
835  CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
836  RETURN_RESULT_OR_FAILURE(isolate, Object::ToInteger(isolate, input));
837}
838
839
840RUNTIME_FUNCTION(Runtime_ToLength) {
841  HandleScope scope(isolate);
842  DCHECK_EQ(1, args.length());
843  CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
844  RETURN_RESULT_OR_FAILURE(isolate, Object::ToLength(isolate, input));
845}
846
847
848RUNTIME_FUNCTION(Runtime_ToString) {
849  HandleScope scope(isolate);
850  DCHECK_EQ(1, args.length());
851  CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
852  RETURN_RESULT_OR_FAILURE(isolate, Object::ToString(isolate, input));
853}
854
855
856RUNTIME_FUNCTION(Runtime_ToName) {
857  HandleScope scope(isolate);
858  DCHECK_EQ(1, args.length());
859  CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
860  RETURN_RESULT_OR_FAILURE(isolate, Object::ToName(isolate, input));
861}
862
863
864RUNTIME_FUNCTION(Runtime_SameValue) {
865  SealHandleScope scope(isolate);
866  DCHECK_EQ(2, args.length());
867  CONVERT_ARG_CHECKED(Object, x, 0);
868  CONVERT_ARG_CHECKED(Object, y, 1);
869  return isolate->heap()->ToBoolean(x->SameValue(y));
870}
871
872
873RUNTIME_FUNCTION(Runtime_SameValueZero) {
874  SealHandleScope scope(isolate);
875  DCHECK_EQ(2, args.length());
876  CONVERT_ARG_CHECKED(Object, x, 0);
877  CONVERT_ARG_CHECKED(Object, y, 1);
878  return isolate->heap()->ToBoolean(x->SameValueZero(y));
879}
880
881
882// TODO(bmeurer): Kill this special wrapper and use TF compatible LessThan,
883// GreaterThan, etc. which return true or false.
884RUNTIME_FUNCTION(Runtime_Compare) {
885  HandleScope scope(isolate);
886  DCHECK_EQ(3, args.length());
887  CONVERT_ARG_HANDLE_CHECKED(Object, x, 0);
888  CONVERT_ARG_HANDLE_CHECKED(Object, y, 1);
889  CONVERT_ARG_HANDLE_CHECKED(Object, ncr, 2);
890  Maybe<ComparisonResult> result = Object::Compare(x, y);
891  if (result.IsJust()) {
892    switch (result.FromJust()) {
893      case ComparisonResult::kLessThan:
894        return Smi::FromInt(LESS);
895      case ComparisonResult::kEqual:
896        return Smi::FromInt(EQUAL);
897      case ComparisonResult::kGreaterThan:
898        return Smi::FromInt(GREATER);
899      case ComparisonResult::kUndefined:
900        return *ncr;
901    }
902    UNREACHABLE();
903  }
904  return isolate->heap()->exception();
905}
906
907RUNTIME_FUNCTION(Runtime_HasInPrototypeChain) {
908  HandleScope scope(isolate);
909  DCHECK_EQ(2, args.length());
910  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
911  CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
912  Maybe<bool> result =
913      JSReceiver::HasInPrototypeChain(isolate, object, prototype);
914  MAYBE_RETURN(result, isolate->heap()->exception());
915  return isolate->heap()->ToBoolean(result.FromJust());
916}
917
918
919// ES6 section 7.4.7 CreateIterResultObject ( value, done )
920RUNTIME_FUNCTION(Runtime_CreateIterResultObject) {
921  HandleScope scope(isolate);
922  DCHECK_EQ(2, args.length());
923  CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
924  CONVERT_ARG_HANDLE_CHECKED(Object, done, 1);
925  return *isolate->factory()->NewJSIteratorResult(value, done->BooleanValue());
926}
927
928RUNTIME_FUNCTION(Runtime_CreateKeyValueArray) {
929  HandleScope scope(isolate);
930  DCHECK_EQ(2, args.length());
931  CONVERT_ARG_HANDLE_CHECKED(Object, key, 0);
932  CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
933  Handle<FixedArray> elements = isolate->factory()->NewFixedArray(2);
934  elements->set(0, *key);
935  elements->set(1, *value);
936  return *isolate->factory()->NewJSArrayWithElements(elements, FAST_ELEMENTS,
937                                                     2);
938}
939
940RUNTIME_FUNCTION(Runtime_IsAccessCheckNeeded) {
941  SealHandleScope shs(isolate);
942  DCHECK_EQ(1, args.length());
943  CONVERT_ARG_CHECKED(Object, object, 0);
944  return isolate->heap()->ToBoolean(object->IsAccessCheckNeeded());
945}
946
947
948RUNTIME_FUNCTION(Runtime_CreateDataProperty) {
949  HandleScope scope(isolate);
950  DCHECK(args.length() == 3);
951  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, o, 0);
952  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
953  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
954  bool success;
955  LookupIterator it = LookupIterator::PropertyOrElement(
956      isolate, o, key, &success, LookupIterator::OWN);
957  if (!success) return isolate->heap()->exception();
958  MAYBE_RETURN(
959      JSReceiver::CreateDataProperty(&it, value, Object::THROW_ON_ERROR),
960      isolate->heap()->exception());
961  return *value;
962}
963
964
965}  // namespace internal
966}  // namespace v8
967