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