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->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
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 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
DeleteObjectProperty(Isolate * isolate,Handle<JSReceiver> receiver,Handle<Object> key,LanguageMode language_mode)121 Maybe<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
RUNTIME_FUNCTION(Runtime_ObjectHasOwnProperty)134 RUNTIME_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.
RUNTIME_FUNCTION(Runtime_ObjectCreate)213 RUNTIME_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
SetObjectProperty(Isolate * isolate,Handle<Object> object,Handle<Object> key,Handle<Object> value,LanguageMode language_mode)274 MaybeHandle<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
RUNTIME_FUNCTION(Runtime_GetPrototype)298 RUNTIME_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
RUNTIME_FUNCTION(Runtime_InternalSetPrototype)306 RUNTIME_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
RUNTIME_FUNCTION(Runtime_OptimizeObjectForAddingMultipleProperties)317 RUNTIME_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
RUNTIME_FUNCTION(Runtime_GetProperty)332 RUNTIME_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.
RUNTIME_FUNCTION(Runtime_KeyedGetProperty)344 RUNTIME_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
RUNTIME_FUNCTION(Runtime_AddNamedProperty)355 RUNTIME_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.
RUNTIME_FUNCTION(Runtime_AddElement)380 RUNTIME_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
RUNTIME_FUNCTION(Runtime_AppendElement)409 RUNTIME_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
RUNTIME_FUNCTION(Runtime_SetProperty)427 RUNTIME_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
442 namespace {
443
444 // ES6 section 12.5.4.
DeleteProperty(Isolate * isolate,Handle<Object> object,Handle<Object> key,LanguageMode language_mode)445 Object* 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
RUNTIME_FUNCTION(Runtime_DeleteProperty_Sloppy)459 RUNTIME_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
RUNTIME_FUNCTION(Runtime_DeleteProperty_Strict)468 RUNTIME_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.
RUNTIME_FUNCTION(Runtime_HasProperty)478 RUNTIME_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
RUNTIME_FUNCTION(Runtime_GetOwnPropertyKeys)504 RUNTIME_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
RUNTIME_FUNCTION(Runtime_GetInterceptorInfo)523 RUNTIME_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
RUNTIME_FUNCTION(Runtime_ToFastProperties)539 RUNTIME_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
RUNTIME_FUNCTION(Runtime_AllocateHeapNumber)551 RUNTIME_FUNCTION(Runtime_AllocateHeapNumber) {
552 HandleScope scope(isolate);
553 DCHECK(args.length() == 0);
554 return *isolate->factory()->NewHeapNumber(0);
555 }
556
557
RUNTIME_FUNCTION(Runtime_NewObject)558 RUNTIME_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
RUNTIME_FUNCTION(Runtime_FinalizeInstanceSize)567 RUNTIME_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
RUNTIME_FUNCTION(Runtime_LoadMutableDouble)578 RUNTIME_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
RUNTIME_FUNCTION(Runtime_TryMigrateInstance)597 RUNTIME_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
RUNTIME_FUNCTION(Runtime_IsJSGlobalProxy)613 RUNTIME_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
IsValidAccessor(Isolate * isolate,Handle<Object> obj)620 static 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.
RUNTIME_FUNCTION(Runtime_DefineAccessorPropertyUnchecked)631 RUNTIME_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
RUNTIME_FUNCTION(Runtime_DefineDataPropertyInLiteral)649 RUNTIME_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
RUNTIME_FUNCTION(Runtime_DefineDataProperty)674 RUNTIME_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.
RUNTIME_FUNCTION(Runtime_GetDataProperty)707 RUNTIME_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
RUNTIME_FUNCTION(Runtime_GetConstructorName)715 RUNTIME_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
RUNTIME_FUNCTION(Runtime_HasFastPackedElements)725 RUNTIME_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
RUNTIME_FUNCTION(Runtime_ValueOf)734 RUNTIME_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
RUNTIME_FUNCTION(Runtime_IsJSReceiver)743 RUNTIME_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
RUNTIME_FUNCTION(Runtime_ClassOf)751 RUNTIME_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
RUNTIME_FUNCTION(Runtime_DefineGetterPropertyUnchecked)760 RUNTIME_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
RUNTIME_FUNCTION(Runtime_DefineSetterPropertyUnchecked)780 RUNTIME_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
RUNTIME_FUNCTION(Runtime_ToObject)800 RUNTIME_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
RUNTIME_FUNCTION(Runtime_ToPrimitive)808 RUNTIME_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
RUNTIME_FUNCTION(Runtime_ToPrimitive_Number)816 RUNTIME_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
RUNTIME_FUNCTION(Runtime_ToNumber)824 RUNTIME_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
RUNTIME_FUNCTION(Runtime_ToInteger)832 RUNTIME_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
RUNTIME_FUNCTION(Runtime_ToLength)840 RUNTIME_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
RUNTIME_FUNCTION(Runtime_ToString)848 RUNTIME_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
RUNTIME_FUNCTION(Runtime_ToName)856 RUNTIME_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
RUNTIME_FUNCTION(Runtime_SameValue)864 RUNTIME_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
RUNTIME_FUNCTION(Runtime_SameValueZero)873 RUNTIME_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.
RUNTIME_FUNCTION(Runtime_Compare)884 RUNTIME_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
RUNTIME_FUNCTION(Runtime_HasInPrototypeChain)907 RUNTIME_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 )
RUNTIME_FUNCTION(Runtime_CreateIterResultObject)920 RUNTIME_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
RUNTIME_FUNCTION(Runtime_CreateKeyValueArray)928 RUNTIME_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
RUNTIME_FUNCTION(Runtime_IsAccessCheckNeeded)940 RUNTIME_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
RUNTIME_FUNCTION(Runtime_CreateDataProperty)948 RUNTIME_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