1 // Copyright 2015 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/objects/objects.h"
6 
7 #include <algorithm>
8 #include <cmath>
9 #include <memory>
10 #include <sstream>
11 #include <vector>
12 
13 #include "src/api/api-arguments-inl.h"
14 #include "src/api/api-natives.h"
15 #include "src/api/api.h"
16 #include "src/ast/ast.h"
17 #include "src/ast/scopes.h"
18 #include "src/base/bits.h"
19 #include "src/base/debug/stack_trace.h"
20 #include "src/base/overflowing-math.h"
21 #include "src/base/utils/random-number-generator.h"
22 #include "src/builtins/accessors.h"
23 #include "src/builtins/builtins.h"
24 #include "src/codegen/compiler.h"
25 #include "src/common/globals.h"
26 #include "src/common/message-template.h"
27 #include "src/date/date.h"
28 #include "src/debug/debug.h"
29 #include "src/diagnostics/code-tracer.h"
30 #include "src/execution/arguments.h"
31 #include "src/execution/execution.h"
32 #include "src/execution/frames-inl.h"
33 #include "src/execution/isolate-inl.h"
34 #include "src/execution/isolate-utils-inl.h"
35 #include "src/execution/isolate-utils.h"
36 #include "src/execution/microtask-queue.h"
37 #include "src/execution/protectors-inl.h"
38 #include "src/heap/factory-inl.h"
39 #include "src/heap/heap-inl.h"
40 #include "src/heap/local-factory-inl.h"
41 #include "src/heap/read-only-heap.h"
42 #include "src/ic/ic.h"
43 #include "src/init/bootstrapper.h"
44 #include "src/logging/counters.h"
45 #include "src/logging/log.h"
46 #include "src/logging/runtime-call-stats-scope.h"
47 #include "src/objects/allocation-site-inl.h"
48 #include "src/objects/allocation-site-scopes.h"
49 #include "src/objects/api-callbacks.h"
50 #include "src/objects/arguments-inl.h"
51 #include "src/objects/bigint.h"
52 #include "src/objects/cell-inl.h"
53 #include "src/objects/code-inl.h"
54 #include "src/objects/compilation-cache-table-inl.h"
55 #include "src/objects/debug-objects-inl.h"
56 #include "src/objects/elements.h"
57 #include "src/objects/embedder-data-array-inl.h"
58 #include "src/objects/field-index-inl.h"
59 #include "src/objects/field-index.h"
60 #include "src/objects/field-type.h"
61 #include "src/objects/foreign.h"
62 #include "src/objects/free-space-inl.h"
63 #include "src/objects/function-kind.h"
64 #include "src/objects/hash-table-inl.h"
65 #include "src/objects/instance-type.h"
66 #include "src/objects/js-array-buffer-inl.h"
67 #include "src/objects/js-array-inl.h"
68 #include "src/objects/keys.h"
69 #include "src/objects/lookup-inl.h"
70 #include "src/objects/map-updater.h"
71 #include "src/objects/objects-body-descriptors-inl.h"
72 #include "src/objects/objects-inl.h"
73 #include "src/objects/property-details.h"
74 #include "src/roots/roots.h"
75 #include "src/snapshot/deserializer.h"
76 #include "src/utils/identity-map.h"
77 #ifdef V8_INTL_SUPPORT
78 #include "src/objects/js-break-iterator.h"
79 #include "src/objects/js-collator.h"
80 #endif  // V8_INTL_SUPPORT
81 #include "src/objects/js-collection-inl.h"
82 #ifdef V8_INTL_SUPPORT
83 #include "src/objects/js-date-time-format.h"
84 #endif  // V8_INTL_SUPPORT
85 #include "src/objects/js-generator-inl.h"
86 #ifdef V8_INTL_SUPPORT
87 #include "src/objects/js-list-format.h"
88 #include "src/objects/js-locale.h"
89 #include "src/objects/js-number-format.h"
90 #include "src/objects/js-plural-rules.h"
91 #endif  // V8_INTL_SUPPORT
92 #include "src/objects/js-regexp-inl.h"
93 #include "src/objects/js-regexp-string-iterator.h"
94 #ifdef V8_INTL_SUPPORT
95 #include "src/objects/js-relative-time-format.h"
96 #include "src/objects/js-segment-iterator.h"
97 #include "src/objects/js-segmenter.h"
98 #include "src/objects/js-segments.h"
99 #endif  // V8_INTL_SUPPORT
100 #include "src/codegen/source-position-table.h"
101 #include "src/objects/js-weak-refs-inl.h"
102 #include "src/objects/literal-objects-inl.h"
103 #include "src/objects/map-inl.h"
104 #include "src/objects/map.h"
105 #include "src/objects/megadom-handler-inl.h"
106 #include "src/objects/microtask-inl.h"
107 #include "src/objects/module-inl.h"
108 #include "src/objects/promise-inl.h"
109 #include "src/objects/property-descriptor-object-inl.h"
110 #include "src/objects/property-descriptor.h"
111 #include "src/objects/prototype.h"
112 #include "src/objects/slots-atomic-inl.h"
113 #include "src/objects/stack-frame-info-inl.h"
114 #include "src/objects/string-comparator.h"
115 #include "src/objects/string-set-inl.h"
116 #include "src/objects/struct-inl.h"
117 #include "src/objects/template-objects-inl.h"
118 #include "src/objects/transitions-inl.h"
119 #include "src/parsing/preparse-data.h"
120 #include "src/regexp/regexp.h"
121 #include "src/strings/string-builder-inl.h"
122 #include "src/strings/string-search.h"
123 #include "src/strings/string-stream.h"
124 #include "src/strings/unicode-decoder.h"
125 #include "src/strings/unicode-inl.h"
126 #include "src/utils/ostreams.h"
127 #include "src/utils/utils-inl.h"
128 #include "src/zone/zone.h"
129 
130 #if V8_ENABLE_WEBASSEMBLY
131 #include "src/wasm/wasm-objects.h"
132 #endif  // V8_ENABLE_WEBASSEMBLY
133 
134 namespace v8 {
135 namespace internal {
136 
GetShouldThrow(Isolate * isolate,Maybe<ShouldThrow> should_throw)137 ShouldThrow GetShouldThrow(Isolate* isolate, Maybe<ShouldThrow> should_throw) {
138   if (should_throw.IsJust()) return should_throw.FromJust();
139 
140   LanguageMode mode = isolate->context().scope_info().language_mode();
141   if (mode == LanguageMode::kStrict) return kThrowOnError;
142 
143   for (StackFrameIterator it(isolate); !it.done(); it.Advance()) {
144     if (!(it.frame()->is_optimized() || it.frame()->is_unoptimized())) {
145       continue;
146     }
147     // Get the language mode from closure.
148     JavaScriptFrame* js_frame = static_cast<JavaScriptFrame*>(it.frame());
149     std::vector<SharedFunctionInfo> functions;
150     js_frame->GetFunctions(&functions);
151     LanguageMode closure_language_mode = functions.back().language_mode();
152     if (closure_language_mode > mode) {
153       mode = closure_language_mode;
154     }
155     break;
156   }
157 
158   return is_sloppy(mode) ? kDontThrow : kThrowOnError;
159 }
160 
ComparisonResultToBool(Operation op,ComparisonResult result)161 bool ComparisonResultToBool(Operation op, ComparisonResult result) {
162   switch (op) {
163     case Operation::kLessThan:
164       return result == ComparisonResult::kLessThan;
165     case Operation::kLessThanOrEqual:
166       return result == ComparisonResult::kLessThan ||
167              result == ComparisonResult::kEqual;
168     case Operation::kGreaterThan:
169       return result == ComparisonResult::kGreaterThan;
170     case Operation::kGreaterThanOrEqual:
171       return result == ComparisonResult::kGreaterThan ||
172              result == ComparisonResult::kEqual;
173     default:
174       break;
175   }
176   UNREACHABLE();
177 }
178 
operator <<(std::ostream & os,InstanceType instance_type)179 std::ostream& operator<<(std::ostream& os, InstanceType instance_type) {
180   switch (instance_type) {
181 #define WRITE_TYPE(TYPE) \
182   case TYPE:             \
183     return os << #TYPE;
184     INSTANCE_TYPE_LIST(WRITE_TYPE)
185 #undef WRITE_TYPE
186   }
187   UNREACHABLE();
188 }
189 
operator <<(std::ostream & os,PropertyCellType type)190 std::ostream& operator<<(std::ostream& os, PropertyCellType type) {
191   switch (type) {
192     case PropertyCellType::kUndefined:
193       return os << "Undefined";
194     case PropertyCellType::kConstant:
195       return os << "Constant";
196     case PropertyCellType::kConstantType:
197       return os << "ConstantType";
198     case PropertyCellType::kMutable:
199       return os << "Mutable";
200     case PropertyCellType::kInTransition:
201       return os << "InTransition";
202   }
203   UNREACHABLE();
204 }
205 
OptimalType(Isolate * isolate,Representation representation)206 Handle<FieldType> Object::OptimalType(Isolate* isolate,
207                                       Representation representation) {
208   if (representation.IsNone()) return FieldType::None(isolate);
209   if (FLAG_track_field_types) {
210     if (representation.IsHeapObject() && IsHeapObject()) {
211       // We can track only JavaScript objects with stable maps.
212       Handle<Map> map(HeapObject::cast(*this).map(), isolate);
213       if (map->is_stable() && map->IsJSReceiverMap()) {
214         return FieldType::Class(map, isolate);
215       }
216     }
217   }
218   return FieldType::Any(isolate);
219 }
220 
NewStorageFor(Isolate * isolate,Handle<Object> object,Representation representation)221 Handle<Object> Object::NewStorageFor(Isolate* isolate, Handle<Object> object,
222                                      Representation representation) {
223   if (!representation.IsDouble()) return object;
224   auto result = isolate->factory()->NewHeapNumberWithHoleNaN();
225   if (object->IsUninitialized(isolate)) {
226     result->set_value_as_bits(kHoleNanInt64, kRelaxedStore);
227   } else if (object->IsHeapNumber()) {
228     // Ensure that all bits of the double value are preserved.
229     result->set_value_as_bits(
230         HeapNumber::cast(*object).value_as_bits(kRelaxedLoad), kRelaxedStore);
231   } else {
232     result->set_value(object->Number(), kRelaxedStore);
233   }
234   return result;
235 }
236 
237 template <AllocationType allocation_type, typename IsolateT>
WrapForRead(IsolateT * isolate,Handle<Object> object,Representation representation)238 Handle<Object> Object::WrapForRead(IsolateT* isolate, Handle<Object> object,
239                                    Representation representation) {
240   DCHECK(!object->IsUninitialized(isolate));
241   if (!representation.IsDouble()) {
242     DCHECK(object->FitsRepresentation(representation));
243     return object;
244   }
245   return isolate->factory()->template NewHeapNumberFromBits<allocation_type>(
246       HeapNumber::cast(*object).value_as_bits(kRelaxedLoad));
247 }
248 
249 template Handle<Object> Object::WrapForRead<AllocationType::kYoung>(
250     Isolate* isolate, Handle<Object> object, Representation representation);
251 template Handle<Object> Object::WrapForRead<AllocationType::kOld>(
252     LocalIsolate* isolate, Handle<Object> object,
253     Representation representation);
254 
ToObjectImpl(Isolate * isolate,Handle<Object> object,const char * method_name)255 MaybeHandle<JSReceiver> Object::ToObjectImpl(Isolate* isolate,
256                                              Handle<Object> object,
257                                              const char* method_name) {
258   DCHECK(!object->IsJSReceiver());  // Use ToObject() for fast path.
259   Handle<Context> native_context = isolate->native_context();
260   Handle<JSFunction> constructor;
261   if (object->IsSmi()) {
262     constructor = handle(native_context->number_function(), isolate);
263   } else {
264     int constructor_function_index =
265         Handle<HeapObject>::cast(object)->map().GetConstructorFunctionIndex();
266     if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
267       if (method_name != nullptr) {
268         THROW_NEW_ERROR(
269             isolate,
270             NewTypeError(
271                 MessageTemplate::kCalledOnNullOrUndefined,
272                 isolate->factory()->NewStringFromAsciiChecked(method_name)),
273             JSReceiver);
274       }
275       THROW_NEW_ERROR(isolate,
276                       NewTypeError(MessageTemplate::kUndefinedOrNullToObject),
277                       JSReceiver);
278     }
279     constructor = handle(
280         JSFunction::cast(native_context->get(constructor_function_index)),
281         isolate);
282   }
283   Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
284   Handle<JSPrimitiveWrapper>::cast(result)->set_value(*object);
285   return result;
286 }
287 
288 // ES6 section 9.2.1.2, OrdinaryCallBindThis for sloppy callee.
289 // static
ConvertReceiver(Isolate * isolate,Handle<Object> object)290 MaybeHandle<JSReceiver> Object::ConvertReceiver(Isolate* isolate,
291                                                 Handle<Object> object) {
292   if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
293   if (object->IsNullOrUndefined(isolate)) {
294     return isolate->global_proxy();
295   }
296   return Object::ToObject(isolate, object);
297 }
298 
299 // static
ConvertToNumberOrNumeric(Isolate * isolate,Handle<Object> input,Conversion mode)300 MaybeHandle<Object> Object::ConvertToNumberOrNumeric(Isolate* isolate,
301                                                      Handle<Object> input,
302                                                      Conversion mode) {
303   while (true) {
304     if (input->IsNumber()) {
305       return input;
306     }
307     if (input->IsString()) {
308       return String::ToNumber(isolate, Handle<String>::cast(input));
309     }
310     if (input->IsOddball()) {
311       return Oddball::ToNumber(isolate, Handle<Oddball>::cast(input));
312     }
313     if (input->IsSymbol()) {
314       THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber),
315                       Object);
316     }
317     if (input->IsBigInt()) {
318       if (mode == Conversion::kToNumeric) return input;
319       DCHECK_EQ(mode, Conversion::kToNumber);
320       THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kBigIntToNumber),
321                       Object);
322     }
323     ASSIGN_RETURN_ON_EXCEPTION(
324         isolate, input,
325         JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
326                                 ToPrimitiveHint::kNumber),
327         Object);
328   }
329 }
330 
331 // static
ConvertToInteger(Isolate * isolate,Handle<Object> input)332 MaybeHandle<Object> Object::ConvertToInteger(Isolate* isolate,
333                                              Handle<Object> input) {
334   ASSIGN_RETURN_ON_EXCEPTION(
335       isolate, input,
336       ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object);
337   if (input->IsSmi()) return input;
338   return isolate->factory()->NewNumber(DoubleToInteger(input->Number()));
339 }
340 
341 // static
ConvertToInt32(Isolate * isolate,Handle<Object> input)342 MaybeHandle<Object> Object::ConvertToInt32(Isolate* isolate,
343                                            Handle<Object> input) {
344   ASSIGN_RETURN_ON_EXCEPTION(
345       isolate, input,
346       ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object);
347   if (input->IsSmi()) return input;
348   return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number()));
349 }
350 
351 // static
ConvertToUint32(Isolate * isolate,Handle<Object> input)352 MaybeHandle<Object> Object::ConvertToUint32(Isolate* isolate,
353                                             Handle<Object> input) {
354   ASSIGN_RETURN_ON_EXCEPTION(
355       isolate, input,
356       ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object);
357   if (input->IsSmi()) return handle(Smi::cast(*input).ToUint32Smi(), isolate);
358   return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number()));
359 }
360 
361 // static
ConvertToName(Isolate * isolate,Handle<Object> input)362 MaybeHandle<Name> Object::ConvertToName(Isolate* isolate,
363                                         Handle<Object> input) {
364   ASSIGN_RETURN_ON_EXCEPTION(
365       isolate, input, Object::ToPrimitive(input, ToPrimitiveHint::kString),
366       Name);
367   if (input->IsName()) return Handle<Name>::cast(input);
368   return ToString(isolate, input);
369 }
370 
371 // ES6 7.1.14
372 // static
ConvertToPropertyKey(Isolate * isolate,Handle<Object> value)373 MaybeHandle<Object> Object::ConvertToPropertyKey(Isolate* isolate,
374                                                  Handle<Object> value) {
375   // 1. Let key be ToPrimitive(argument, hint String).
376   MaybeHandle<Object> maybe_key =
377       Object::ToPrimitive(value, ToPrimitiveHint::kString);
378   // 2. ReturnIfAbrupt(key).
379   Handle<Object> key;
380   if (!maybe_key.ToHandle(&key)) return key;
381   // 3. If Type(key) is Symbol, then return key.
382   if (key->IsSymbol()) return key;
383   // 4. Return ToString(key).
384   // Extending spec'ed behavior, we'd be happy to return an element index.
385   if (key->IsSmi()) return key;
386   if (key->IsHeapNumber()) {
387     uint32_t uint_value;
388     if (value->ToArrayLength(&uint_value) &&
389         uint_value <= static_cast<uint32_t>(Smi::kMaxValue)) {
390       return handle(Smi::FromInt(static_cast<int>(uint_value)), isolate);
391     }
392   }
393   return Object::ToString(isolate, key);
394 }
395 
396 // static
ConvertToString(Isolate * isolate,Handle<Object> input)397 MaybeHandle<String> Object::ConvertToString(Isolate* isolate,
398                                             Handle<Object> input) {
399   while (true) {
400     if (input->IsOddball()) {
401       return handle(Handle<Oddball>::cast(input)->to_string(), isolate);
402     }
403     if (input->IsNumber()) {
404       return isolate->factory()->NumberToString(input);
405     }
406     if (input->IsSymbol()) {
407       THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToString),
408                       String);
409     }
410     if (input->IsBigInt()) {
411       return BigInt::ToString(isolate, Handle<BigInt>::cast(input));
412     }
413     ASSIGN_RETURN_ON_EXCEPTION(
414         isolate, input,
415         JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
416                                 ToPrimitiveHint::kString),
417         String);
418     // The previous isString() check happened in Object::ToString and thus we
419     // put it at the end of the loop in this helper.
420     if (input->IsString()) {
421       return Handle<String>::cast(input);
422     }
423   }
424 }
425 
426 namespace {
427 
IsErrorObject(Isolate * isolate,Handle<Object> object)428 bool IsErrorObject(Isolate* isolate, Handle<Object> object) {
429   if (!object->IsJSReceiver()) return false;
430   Handle<Symbol> symbol = isolate->factory()->stack_trace_symbol();
431   return JSReceiver::HasOwnProperty(Handle<JSReceiver>::cast(object), symbol)
432       .FromMaybe(false);
433 }
434 
AsStringOrEmpty(Isolate * isolate,Handle<Object> object)435 Handle<String> AsStringOrEmpty(Isolate* isolate, Handle<Object> object) {
436   return object->IsString() ? Handle<String>::cast(object)
437                             : isolate->factory()->empty_string();
438 }
439 
NoSideEffectsErrorToString(Isolate * isolate,Handle<JSReceiver> error)440 Handle<String> NoSideEffectsErrorToString(Isolate* isolate,
441                                           Handle<JSReceiver> error) {
442   Handle<Name> name_key = isolate->factory()->name_string();
443   Handle<Object> name = JSReceiver::GetDataProperty(error, name_key);
444   Handle<String> name_str = AsStringOrEmpty(isolate, name);
445 
446   Handle<Name> msg_key = isolate->factory()->message_string();
447   Handle<Object> msg = JSReceiver::GetDataProperty(error, msg_key);
448   Handle<String> msg_str = AsStringOrEmpty(isolate, msg);
449 
450   if (name_str->length() == 0) return msg_str;
451   if (msg_str->length() == 0) return name_str;
452 
453   IncrementalStringBuilder builder(isolate);
454   builder.AppendString(name_str);
455   builder.AppendCString(": ");
456 
457   if (builder.Length() + msg_str->length() <= String::kMaxLength) {
458     builder.AppendString(msg_str);
459   } else {
460     builder.AppendCString("<a very large string>");
461   }
462 
463   return builder.Finish().ToHandleChecked();
464 }
465 
466 }  // namespace
467 
468 // static
NoSideEffectsToMaybeString(Isolate * isolate,Handle<Object> input)469 MaybeHandle<String> Object::NoSideEffectsToMaybeString(Isolate* isolate,
470                                                        Handle<Object> input) {
471   DisallowJavascriptExecution no_js(isolate);
472 
473   if (input->IsString() || input->IsNumber() || input->IsOddball()) {
474     return Object::ToString(isolate, input).ToHandleChecked();
475   } else if (input->IsJSProxy()) {
476     Handle<Object> currInput = input;
477     do {
478       HeapObject target = Handle<JSProxy>::cast(currInput)->target(isolate);
479       currInput = Handle<Object>(target, isolate);
480     } while (currInput->IsJSProxy());
481     return NoSideEffectsToString(isolate, currInput);
482   } else if (input->IsBigInt()) {
483     MaybeHandle<String> maybe_string =
484         BigInt::ToString(isolate, Handle<BigInt>::cast(input), 10, kDontThrow);
485     Handle<String> result;
486     if (maybe_string.ToHandle(&result)) return result;
487     // BigInt-to-String conversion can fail on 32-bit platforms where
488     // String::kMaxLength is too small to fit this BigInt.
489     return isolate->factory()->NewStringFromStaticChars(
490         "<a very large BigInt>");
491   } else if (input->IsFunction()) {
492     // -- F u n c t i o n
493     Handle<String> fun_str;
494     if (input->IsJSBoundFunction()) {
495       fun_str = JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(input));
496     } else {
497       DCHECK(input->IsJSFunction());
498       fun_str = JSFunction::ToString(Handle<JSFunction>::cast(input));
499     }
500 
501     if (fun_str->length() > 128) {
502       IncrementalStringBuilder builder(isolate);
503       builder.AppendString(isolate->factory()->NewSubString(fun_str, 0, 111));
504       builder.AppendCString("...<omitted>...");
505       builder.AppendString(isolate->factory()->NewSubString(
506           fun_str, fun_str->length() - 2, fun_str->length()));
507 
508       return builder.Finish().ToHandleChecked();
509     }
510     return fun_str;
511   } else if (input->IsSymbol()) {
512     // -- S y m b o l
513     Handle<Symbol> symbol = Handle<Symbol>::cast(input);
514 
515     if (symbol->is_private_name()) {
516       return Handle<String>(String::cast(symbol->description()), isolate);
517     }
518 
519     IncrementalStringBuilder builder(isolate);
520     builder.AppendCString("Symbol(");
521     if (symbol->description().IsString()) {
522       builder.AppendString(
523           handle(String::cast(symbol->description()), isolate));
524     }
525     builder.AppendCharacter(')');
526 
527     return builder.Finish().ToHandleChecked();
528   } else if (input->IsJSReceiver()) {
529     // -- J S R e c e i v e r
530     Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input);
531     Handle<Object> to_string = JSReceiver::GetDataProperty(
532         receiver, isolate->factory()->toString_string());
533 
534     if (IsErrorObject(isolate, input) ||
535         *to_string == *isolate->error_to_string()) {
536       // When internally formatting error objects, use a side-effects-free
537       // version of Error.prototype.toString independent of the actually
538       // installed toString method.
539       return NoSideEffectsErrorToString(isolate,
540                                         Handle<JSReceiver>::cast(input));
541     } else if (*to_string == *isolate->object_to_string()) {
542       Handle<Object> ctor = JSReceiver::GetDataProperty(
543           receiver, isolate->factory()->constructor_string());
544       if (ctor->IsFunction()) {
545         Handle<String> ctor_name;
546         if (ctor->IsJSBoundFunction()) {
547           ctor_name = JSBoundFunction::GetName(
548                           isolate, Handle<JSBoundFunction>::cast(ctor))
549                           .ToHandleChecked();
550         } else if (ctor->IsJSFunction()) {
551           Handle<Object> ctor_name_obj =
552               JSFunction::GetName(isolate, Handle<JSFunction>::cast(ctor));
553           ctor_name = AsStringOrEmpty(isolate, ctor_name_obj);
554         }
555 
556         if (ctor_name->length() != 0) {
557           IncrementalStringBuilder builder(isolate);
558           builder.AppendCString("#<");
559           builder.AppendString(ctor_name);
560           builder.AppendCString(">");
561 
562           return builder.Finish().ToHandleChecked();
563         }
564       }
565     }
566   }
567   return MaybeHandle<String>(kNullMaybeHandle);
568 }
569 
570 // static
NoSideEffectsToString(Isolate * isolate,Handle<Object> input)571 Handle<String> Object::NoSideEffectsToString(Isolate* isolate,
572                                              Handle<Object> input) {
573   DisallowJavascriptExecution no_js(isolate);
574 
575   // Try to convert input to a meaningful string.
576   MaybeHandle<String> maybe_string = NoSideEffectsToMaybeString(isolate, input);
577   Handle<String> string_handle;
578   if (maybe_string.ToHandle(&string_handle)) {
579     return string_handle;
580   }
581 
582   // At this point, input is either none of the above or a JSReceiver.
583 
584   Handle<JSReceiver> receiver;
585   if (input->IsJSReceiver()) {
586     receiver = Handle<JSReceiver>::cast(input);
587   } else {
588     // This is the only case where Object::ToObject throws.
589     DCHECK(!input->IsSmi());
590     int constructor_function_index =
591         Handle<HeapObject>::cast(input)->map().GetConstructorFunctionIndex();
592     if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
593       return isolate->factory()->NewStringFromAsciiChecked("[object Unknown]");
594     }
595 
596     receiver = Object::ToObjectImpl(isolate, input).ToHandleChecked();
597   }
598 
599   Handle<String> builtin_tag = handle(receiver->class_name(), isolate);
600   Handle<Object> tag_obj = JSReceiver::GetDataProperty(
601       receiver, isolate->factory()->to_string_tag_symbol());
602   Handle<String> tag =
603       tag_obj->IsString() ? Handle<String>::cast(tag_obj) : builtin_tag;
604 
605   IncrementalStringBuilder builder(isolate);
606   builder.AppendCString("[object ");
607   builder.AppendString(tag);
608   builder.AppendCString("]");
609 
610   return builder.Finish().ToHandleChecked();
611 }
612 
613 // static
ConvertToLength(Isolate * isolate,Handle<Object> input)614 MaybeHandle<Object> Object::ConvertToLength(Isolate* isolate,
615                                             Handle<Object> input) {
616   ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(isolate, input), Object);
617   if (input->IsSmi()) {
618     int value = std::max(Smi::ToInt(*input), 0);
619     return handle(Smi::FromInt(value), isolate);
620   }
621   double len = DoubleToInteger(input->Number());
622   if (len <= 0.0) {
623     return handle(Smi::zero(), isolate);
624   } else if (len >= kMaxSafeInteger) {
625     len = kMaxSafeInteger;
626   }
627   return isolate->factory()->NewNumber(len);
628 }
629 
630 // static
ConvertToIndex(Isolate * isolate,Handle<Object> input,MessageTemplate error_index)631 MaybeHandle<Object> Object::ConvertToIndex(Isolate* isolate,
632                                            Handle<Object> input,
633                                            MessageTemplate error_index) {
634   if (input->IsUndefined(isolate)) return handle(Smi::zero(), isolate);
635   ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(isolate, input), Object);
636   if (input->IsSmi() && Smi::ToInt(*input) >= 0) return input;
637   double len = DoubleToInteger(input->Number());
638   auto js_len = isolate->factory()->NewNumber(len);
639   if (len < 0.0 || len > kMaxSafeInteger) {
640     THROW_NEW_ERROR(isolate, NewRangeError(error_index, js_len), Object);
641   }
642   return js_len;
643 }
644 
BooleanValue(Isolate * isolate)645 bool Object::BooleanValue(Isolate* isolate) {
646   if (IsSmi()) return Smi::ToInt(*this) != 0;
647   DCHECK(IsHeapObject());
648   if (IsBoolean()) return IsTrue(isolate);
649   if (IsNullOrUndefined(isolate)) return false;
650   if (IsUndetectable()) return false;  // Undetectable object is false.
651   if (IsString()) return String::cast(*this).length() != 0;
652   if (IsHeapNumber()) return DoubleToBoolean(HeapNumber::cast(*this).value());
653   if (IsBigInt()) return BigInt::cast(*this).ToBoolean();
654   return true;
655 }
656 
ToBoolean(Isolate * isolate)657 Object Object::ToBoolean(Isolate* isolate) {
658   if (IsBoolean()) return *this;
659   return isolate->heap()->ToBoolean(BooleanValue(isolate));
660 }
661 
662 namespace {
663 
664 // TODO(bmeurer): Maybe we should introduce a marker interface Number,
665 // where we put all these methods at some point?
StrictNumberCompare(double x,double y)666 ComparisonResult StrictNumberCompare(double x, double y) {
667   if (std::isnan(x) || std::isnan(y)) {
668     return ComparisonResult::kUndefined;
669   } else if (x < y) {
670     return ComparisonResult::kLessThan;
671   } else if (x > y) {
672     return ComparisonResult::kGreaterThan;
673   } else {
674     return ComparisonResult::kEqual;
675   }
676 }
677 
678 // See Number case of ES6#sec-strict-equality-comparison
679 // Returns false if x or y is NaN, treats -0.0 as equal to 0.0.
StrictNumberEquals(double x,double y)680 bool StrictNumberEquals(double x, double y) {
681   // Must check explicitly for NaN's on Windows, but -0 works fine.
682   if (std::isnan(x) || std::isnan(y)) return false;
683   return x == y;
684 }
685 
StrictNumberEquals(const Object x,const Object y)686 bool StrictNumberEquals(const Object x, const Object y) {
687   return StrictNumberEquals(x.Number(), y.Number());
688 }
689 
StrictNumberEquals(Handle<Object> x,Handle<Object> y)690 bool StrictNumberEquals(Handle<Object> x, Handle<Object> y) {
691   return StrictNumberEquals(*x, *y);
692 }
693 
Reverse(ComparisonResult result)694 ComparisonResult Reverse(ComparisonResult result) {
695   if (result == ComparisonResult::kLessThan) {
696     return ComparisonResult::kGreaterThan;
697   }
698   if (result == ComparisonResult::kGreaterThan) {
699     return ComparisonResult::kLessThan;
700   }
701   return result;
702 }
703 
704 }  // anonymous namespace
705 
706 // static
Compare(Isolate * isolate,Handle<Object> x,Handle<Object> y)707 Maybe<ComparisonResult> Object::Compare(Isolate* isolate, Handle<Object> x,
708                                         Handle<Object> y) {
709   // ES6 section 7.2.11 Abstract Relational Comparison step 3 and 4.
710   if (!Object::ToPrimitive(x, ToPrimitiveHint::kNumber).ToHandle(&x) ||
711       !Object::ToPrimitive(y, ToPrimitiveHint::kNumber).ToHandle(&y)) {
712     return Nothing<ComparisonResult>();
713   }
714   if (x->IsString() && y->IsString()) {
715     // ES6 section 7.2.11 Abstract Relational Comparison step 5.
716     return Just(String::Compare(isolate, Handle<String>::cast(x),
717                                 Handle<String>::cast(y)));
718   }
719   if (x->IsBigInt() && y->IsString()) {
720     return BigInt::CompareToString(isolate, Handle<BigInt>::cast(x),
721                                    Handle<String>::cast(y));
722   }
723   if (x->IsString() && y->IsBigInt()) {
724     Maybe<ComparisonResult> maybe_result = BigInt::CompareToString(
725         isolate, Handle<BigInt>::cast(y), Handle<String>::cast(x));
726     ComparisonResult result;
727     if (maybe_result.To(&result)) {
728       return Just(Reverse(result));
729     } else {
730       return Nothing<ComparisonResult>();
731     }
732   }
733   // ES6 section 7.2.11 Abstract Relational Comparison step 6.
734   if (!Object::ToNumeric(isolate, x).ToHandle(&x) ||
735       !Object::ToNumeric(isolate, y).ToHandle(&y)) {
736     return Nothing<ComparisonResult>();
737   }
738 
739   bool x_is_number = x->IsNumber();
740   bool y_is_number = y->IsNumber();
741   if (x_is_number && y_is_number) {
742     return Just(StrictNumberCompare(x->Number(), y->Number()));
743   } else if (!x_is_number && !y_is_number) {
744     return Just(BigInt::CompareToBigInt(Handle<BigInt>::cast(x),
745                                         Handle<BigInt>::cast(y)));
746   } else if (x_is_number) {
747     return Just(Reverse(BigInt::CompareToNumber(Handle<BigInt>::cast(y), x)));
748   } else {
749     return Just(BigInt::CompareToNumber(Handle<BigInt>::cast(x), y));
750   }
751 }
752 
753 // static
Equals(Isolate * isolate,Handle<Object> x,Handle<Object> y)754 Maybe<bool> Object::Equals(Isolate* isolate, Handle<Object> x,
755                            Handle<Object> y) {
756   // This is the generic version of Abstract Equality Comparison. Must be in
757   // sync with CodeStubAssembler::Equal.
758   while (true) {
759     if (x->IsNumber()) {
760       if (y->IsNumber()) {
761         return Just(StrictNumberEquals(x, y));
762       } else if (y->IsBoolean()) {
763         return Just(
764             StrictNumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
765       } else if (y->IsString()) {
766         return Just(StrictNumberEquals(
767             x, String::ToNumber(isolate, Handle<String>::cast(y))));
768       } else if (y->IsBigInt()) {
769         return Just(BigInt::EqualToNumber(Handle<BigInt>::cast(y), x));
770       } else if (y->IsJSReceiver()) {
771         if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
772                  .ToHandle(&y)) {
773           return Nothing<bool>();
774         }
775       } else {
776         return Just(false);
777       }
778     } else if (x->IsString()) {
779       if (y->IsString()) {
780         return Just(String::Equals(isolate, Handle<String>::cast(x),
781                                    Handle<String>::cast(y)));
782       } else if (y->IsNumber()) {
783         x = String::ToNumber(isolate, Handle<String>::cast(x));
784         return Just(StrictNumberEquals(x, y));
785       } else if (y->IsBoolean()) {
786         x = String::ToNumber(isolate, Handle<String>::cast(x));
787         return Just(
788             StrictNumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
789       } else if (y->IsBigInt()) {
790         return BigInt::EqualToString(isolate, Handle<BigInt>::cast(y),
791                                      Handle<String>::cast(x));
792       } else if (y->IsJSReceiver()) {
793         if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
794                  .ToHandle(&y)) {
795           return Nothing<bool>();
796         }
797       } else {
798         return Just(false);
799       }
800     } else if (x->IsBoolean()) {
801       if (y->IsOddball()) {
802         return Just(x.is_identical_to(y));
803       } else if (y->IsNumber()) {
804         return Just(
805             StrictNumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
806       } else if (y->IsString()) {
807         y = String::ToNumber(isolate, Handle<String>::cast(y));
808         return Just(
809             StrictNumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
810       } else if (y->IsBigInt()) {
811         x = Oddball::ToNumber(isolate, Handle<Oddball>::cast(x));
812         return Just(BigInt::EqualToNumber(Handle<BigInt>::cast(y), x));
813       } else if (y->IsJSReceiver()) {
814         if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
815                  .ToHandle(&y)) {
816           return Nothing<bool>();
817         }
818         x = Oddball::ToNumber(isolate, Handle<Oddball>::cast(x));
819       } else {
820         return Just(false);
821       }
822     } else if (x->IsSymbol()) {
823       if (y->IsSymbol()) {
824         return Just(x.is_identical_to(y));
825       } else if (y->IsJSReceiver()) {
826         if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
827                  .ToHandle(&y)) {
828           return Nothing<bool>();
829         }
830       } else {
831         return Just(false);
832       }
833     } else if (x->IsBigInt()) {
834       if (y->IsBigInt()) {
835         return Just(BigInt::EqualToBigInt(BigInt::cast(*x), BigInt::cast(*y)));
836       }
837       return Equals(isolate, y, x);
838     } else if (x->IsJSReceiver()) {
839       if (y->IsJSReceiver()) {
840         return Just(x.is_identical_to(y));
841       } else if (y->IsUndetectable()) {
842         return Just(x->IsUndetectable());
843       } else if (y->IsBoolean()) {
844         y = Oddball::ToNumber(isolate, Handle<Oddball>::cast(y));
845       } else if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(x))
846                       .ToHandle(&x)) {
847         return Nothing<bool>();
848       }
849     } else {
850       return Just(x->IsUndetectable() && y->IsUndetectable());
851     }
852   }
853 }
854 
StrictEquals(Object that)855 bool Object::StrictEquals(Object that) {
856   if (this->IsNumber()) {
857     if (!that.IsNumber()) return false;
858     return StrictNumberEquals(*this, that);
859   } else if (this->IsString()) {
860     if (!that.IsString()) return false;
861     return String::cast(*this).Equals(String::cast(that));
862   } else if (this->IsBigInt()) {
863     if (!that.IsBigInt()) return false;
864     return BigInt::EqualToBigInt(BigInt::cast(*this), BigInt::cast(that));
865   }
866   return *this == that;
867 }
868 
869 // static
TypeOf(Isolate * isolate,Handle<Object> object)870 Handle<String> Object::TypeOf(Isolate* isolate, Handle<Object> object) {
871   if (object->IsNumber()) return isolate->factory()->number_string();
872   if (object->IsOddball())
873     return handle(Oddball::cast(*object).type_of(), isolate);
874   if (object->IsUndetectable()) {
875     return isolate->factory()->undefined_string();
876   }
877   if (object->IsString()) return isolate->factory()->string_string();
878   if (object->IsSymbol()) return isolate->factory()->symbol_string();
879   if (object->IsBigInt()) return isolate->factory()->bigint_string();
880   if (object->IsCallable()) return isolate->factory()->function_string();
881   return isolate->factory()->object_string();
882 }
883 
884 // static
Add(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)885 MaybeHandle<Object> Object::Add(Isolate* isolate, Handle<Object> lhs,
886                                 Handle<Object> rhs) {
887   if (lhs->IsNumber() && rhs->IsNumber()) {
888     return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
889   } else if (lhs->IsString() && rhs->IsString()) {
890     return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
891                                              Handle<String>::cast(rhs));
892   }
893   ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToPrimitive(lhs), Object);
894   ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToPrimitive(rhs), Object);
895   if (lhs->IsString() || rhs->IsString()) {
896     ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToString(isolate, rhs),
897                                Object);
898     ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToString(isolate, lhs),
899                                Object);
900     return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
901                                              Handle<String>::cast(rhs));
902   }
903   ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(isolate, rhs),
904                              Object);
905   ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(isolate, lhs),
906                              Object);
907   return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
908 }
909 
910 // static
OrdinaryHasInstance(Isolate * isolate,Handle<Object> callable,Handle<Object> object)911 MaybeHandle<Object> Object::OrdinaryHasInstance(Isolate* isolate,
912                                                 Handle<Object> callable,
913                                                 Handle<Object> object) {
914   // The {callable} must have a [[Call]] internal method.
915   if (!callable->IsCallable()) return isolate->factory()->false_value();
916 
917   // Check if {callable} is a bound function, and if so retrieve its
918   // [[BoundTargetFunction]] and use that instead of {callable}.
919   if (callable->IsJSBoundFunction()) {
920     // Since there is a mutual recursion here, we might run out of stack
921     // space for long chains of bound functions.
922     STACK_CHECK(isolate, MaybeHandle<Object>());
923     Handle<Object> bound_callable(
924         Handle<JSBoundFunction>::cast(callable)->bound_target_function(),
925         isolate);
926     return Object::InstanceOf(isolate, object, bound_callable);
927   }
928 
929   // If {object} is not a receiver, return false.
930   if (!object->IsJSReceiver()) return isolate->factory()->false_value();
931 
932   // Get the "prototype" of {callable}; raise an error if it's not a receiver.
933   Handle<Object> prototype;
934   ASSIGN_RETURN_ON_EXCEPTION(
935       isolate, prototype,
936       Object::GetProperty(isolate, callable,
937                           isolate->factory()->prototype_string()),
938       Object);
939   if (!prototype->IsJSReceiver()) {
940     THROW_NEW_ERROR(
941         isolate,
942         NewTypeError(MessageTemplate::kInstanceofNonobjectProto, prototype),
943         Object);
944   }
945 
946   // Return whether or not {prototype} is in the prototype chain of {object}.
947   Maybe<bool> result = JSReceiver::HasInPrototypeChain(
948       isolate, Handle<JSReceiver>::cast(object), prototype);
949   if (result.IsNothing()) return MaybeHandle<Object>();
950   return isolate->factory()->ToBoolean(result.FromJust());
951 }
952 
953 // static
InstanceOf(Isolate * isolate,Handle<Object> object,Handle<Object> callable)954 MaybeHandle<Object> Object::InstanceOf(Isolate* isolate, Handle<Object> object,
955                                        Handle<Object> callable) {
956   // The {callable} must be a receiver.
957   if (!callable->IsJSReceiver()) {
958     THROW_NEW_ERROR(isolate,
959                     NewTypeError(MessageTemplate::kNonObjectInInstanceOfCheck),
960                     Object);
961   }
962 
963   // Lookup the @@hasInstance method on {callable}.
964   Handle<Object> inst_of_handler;
965   ASSIGN_RETURN_ON_EXCEPTION(
966       isolate, inst_of_handler,
967       Object::GetMethod(Handle<JSReceiver>::cast(callable),
968                         isolate->factory()->has_instance_symbol()),
969       Object);
970   if (!inst_of_handler->IsUndefined(isolate)) {
971     // Call the {inst_of_handler} on the {callable}.
972     Handle<Object> result;
973     ASSIGN_RETURN_ON_EXCEPTION(
974         isolate, result,
975         Execution::Call(isolate, inst_of_handler, callable, 1, &object),
976         Object);
977     return isolate->factory()->ToBoolean(result->BooleanValue(isolate));
978   }
979 
980   // The {callable} must have a [[Call]] internal method.
981   if (!callable->IsCallable()) {
982     THROW_NEW_ERROR(
983         isolate, NewTypeError(MessageTemplate::kNonCallableInInstanceOfCheck),
984         Object);
985   }
986 
987   // Fall back to OrdinaryHasInstance with {callable} and {object}.
988   Handle<Object> result;
989   ASSIGN_RETURN_ON_EXCEPTION(
990       isolate, result, Object::OrdinaryHasInstance(isolate, callable, object),
991       Object);
992   return result;
993 }
994 
995 // static
GetMethod(Handle<JSReceiver> receiver,Handle<Name> name)996 MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
997                                       Handle<Name> name) {
998   Handle<Object> func;
999   Isolate* isolate = receiver->GetIsolate();
1000   ASSIGN_RETURN_ON_EXCEPTION(
1001       isolate, func, JSReceiver::GetProperty(isolate, receiver, name), Object);
1002   if (func->IsNullOrUndefined(isolate)) {
1003     return isolate->factory()->undefined_value();
1004   }
1005   if (!func->IsCallable()) {
1006     THROW_NEW_ERROR(isolate,
1007                     NewTypeError(MessageTemplate::kPropertyNotFunction, func,
1008                                  name, receiver),
1009                     Object);
1010   }
1011   return func;
1012 }
1013 
1014 namespace {
1015 
CreateListFromArrayLikeFastPath(Isolate * isolate,Handle<Object> object,ElementTypes element_types)1016 MaybeHandle<FixedArray> CreateListFromArrayLikeFastPath(
1017     Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
1018   if (element_types == ElementTypes::kAll) {
1019     if (object->IsJSArray()) {
1020       Handle<JSArray> array = Handle<JSArray>::cast(object);
1021       uint32_t length;
1022       if (!array->HasArrayPrototype(isolate) ||
1023           !array->length().ToUint32(&length) || !array->HasFastElements() ||
1024           !JSObject::PrototypeHasNoElements(isolate, *array)) {
1025         return MaybeHandle<FixedArray>();
1026       }
1027       return array->GetElementsAccessor()->CreateListFromArrayLike(
1028           isolate, array, length);
1029     } else if (object->IsJSTypedArray()) {
1030       Handle<JSTypedArray> array = Handle<JSTypedArray>::cast(object);
1031       size_t length = array->length();
1032       if (array->WasDetached() ||
1033           length > static_cast<size_t>(FixedArray::kMaxLength)) {
1034         return MaybeHandle<FixedArray>();
1035       }
1036       STATIC_ASSERT(FixedArray::kMaxLength <=
1037                     std::numeric_limits<uint32_t>::max());
1038       return array->GetElementsAccessor()->CreateListFromArrayLike(
1039           isolate, array, static_cast<uint32_t>(length));
1040     }
1041   }
1042   return MaybeHandle<FixedArray>();
1043 }
1044 
1045 }  // namespace
1046 
1047 // static
CreateListFromArrayLike(Isolate * isolate,Handle<Object> object,ElementTypes element_types)1048 MaybeHandle<FixedArray> Object::CreateListFromArrayLike(
1049     Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
1050   // Fast-path for JSArray and JSTypedArray.
1051   MaybeHandle<FixedArray> fast_result =
1052       CreateListFromArrayLikeFastPath(isolate, object, element_types);
1053   if (!fast_result.is_null()) return fast_result;
1054   // 1. ReturnIfAbrupt(object).
1055   // 2. (default elementTypes -- not applicable.)
1056   // 3. If Type(obj) is not Object, throw a TypeError exception.
1057   if (!object->IsJSReceiver()) {
1058     THROW_NEW_ERROR(isolate,
1059                     NewTypeError(MessageTemplate::kCalledOnNonObject,
1060                                  isolate->factory()->NewStringFromAsciiChecked(
1061                                      "CreateListFromArrayLike")),
1062                     FixedArray);
1063   }
1064 
1065   // 4. Let len be ? ToLength(? Get(obj, "length")).
1066   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
1067   Handle<Object> raw_length_number;
1068   ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number,
1069                              Object::GetLengthFromArrayLike(isolate, receiver),
1070                              FixedArray);
1071   uint32_t len;
1072   if (!raw_length_number->ToUint32(&len) ||
1073       len > static_cast<uint32_t>(FixedArray::kMaxLength)) {
1074     THROW_NEW_ERROR(isolate,
1075                     NewRangeError(MessageTemplate::kInvalidArrayLength),
1076                     FixedArray);
1077   }
1078   // 5. Let list be an empty List.
1079   Handle<FixedArray> list = isolate->factory()->NewFixedArray(len);
1080   // 6. Let index be 0.
1081   // 7. Repeat while index < len:
1082   for (uint32_t index = 0; index < len; ++index) {
1083     // 7a. Let indexName be ToString(index).
1084     // 7b. Let next be ? Get(obj, indexName).
1085     Handle<Object> next;
1086     ASSIGN_RETURN_ON_EXCEPTION(isolate, next,
1087                                JSReceiver::GetElement(isolate, receiver, index),
1088                                FixedArray);
1089     switch (element_types) {
1090       case ElementTypes::kAll:
1091         // Nothing to do.
1092         break;
1093       case ElementTypes::kStringAndSymbol: {
1094         // 7c. If Type(next) is not an element of elementTypes, throw a
1095         //     TypeError exception.
1096         if (!next->IsName()) {
1097           THROW_NEW_ERROR(isolate,
1098                           NewTypeError(MessageTemplate::kNotPropertyName, next),
1099                           FixedArray);
1100         }
1101         // 7d. Append next as the last element of list.
1102         // Internalize on the fly so we can use pointer identity later.
1103         next = isolate->factory()->InternalizeName(Handle<Name>::cast(next));
1104         break;
1105       }
1106     }
1107     list->set(index, *next);
1108     // 7e. Set index to index + 1. (See loop header.)
1109   }
1110   // 8. Return list.
1111   return list;
1112 }
1113 
1114 // static
GetLengthFromArrayLike(Isolate * isolate,Handle<JSReceiver> object)1115 MaybeHandle<Object> Object::GetLengthFromArrayLike(Isolate* isolate,
1116                                                    Handle<JSReceiver> object) {
1117   Handle<Object> val;
1118   Handle<Name> key = isolate->factory()->length_string();
1119   ASSIGN_RETURN_ON_EXCEPTION(
1120       isolate, val, JSReceiver::GetProperty(isolate, object, key), Object);
1121   return Object::ToLength(isolate, val);
1122 }
1123 
1124 // static
GetProperty(LookupIterator * it,bool is_global_reference)1125 MaybeHandle<Object> Object::GetProperty(LookupIterator* it,
1126                                         bool is_global_reference) {
1127   for (; it->IsFound(); it->Next()) {
1128     switch (it->state()) {
1129       case LookupIterator::NOT_FOUND:
1130       case LookupIterator::TRANSITION:
1131         UNREACHABLE();
1132       case LookupIterator::JSPROXY: {
1133         bool was_found;
1134         Handle<Object> receiver = it->GetReceiver();
1135         // In case of global IC, the receiver is the global object. Replace by
1136         // the global proxy.
1137         if (receiver->IsJSGlobalObject()) {
1138           receiver = handle(JSGlobalObject::cast(*receiver).global_proxy(),
1139                             it->isolate());
1140         }
1141         if (is_global_reference) {
1142           Maybe<bool> maybe = JSProxy::HasProperty(
1143               it->isolate(), it->GetHolder<JSProxy>(), it->GetName());
1144           if (maybe.IsNothing()) return MaybeHandle<Object>();
1145           if (!maybe.FromJust()) {
1146             it->NotFound();
1147             return it->isolate()->factory()->undefined_value();
1148           }
1149         }
1150         MaybeHandle<Object> result =
1151             JSProxy::GetProperty(it->isolate(), it->GetHolder<JSProxy>(),
1152                                  it->GetName(), receiver, &was_found);
1153         if (!was_found && !is_global_reference) it->NotFound();
1154         return result;
1155       }
1156       case LookupIterator::INTERCEPTOR: {
1157         bool done;
1158         Handle<Object> result;
1159         ASSIGN_RETURN_ON_EXCEPTION(
1160             it->isolate(), result,
1161             JSObject::GetPropertyWithInterceptor(it, &done), Object);
1162         if (done) return result;
1163         break;
1164       }
1165       case LookupIterator::ACCESS_CHECK:
1166         if (it->HasAccess()) break;
1167         return JSObject::GetPropertyWithFailedAccessCheck(it);
1168       case LookupIterator::ACCESSOR:
1169         return GetPropertyWithAccessor(it);
1170       case LookupIterator::INTEGER_INDEXED_EXOTIC:
1171         return it->isolate()->factory()->undefined_value();
1172       case LookupIterator::DATA:
1173         return it->GetDataValue();
1174     }
1175   }
1176 
1177   return it->isolate()->factory()->undefined_value();
1178 }
1179 
1180 // static
GetProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Name> name,Handle<Object> receiver,bool * was_found)1181 MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
1182                                          Handle<JSProxy> proxy,
1183                                          Handle<Name> name,
1184                                          Handle<Object> receiver,
1185                                          bool* was_found) {
1186   *was_found = true;
1187 
1188   DCHECK(!name->IsPrivate());
1189   STACK_CHECK(isolate, MaybeHandle<Object>());
1190   Handle<Name> trap_name = isolate->factory()->get_string();
1191   // 1. Assert: IsPropertyKey(P) is true.
1192   // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
1193   Handle<Object> handler(proxy->handler(), isolate);
1194   // 3. If handler is null, throw a TypeError exception.
1195   // 4. Assert: Type(handler) is Object.
1196   if (proxy->IsRevoked()) {
1197     THROW_NEW_ERROR(isolate,
1198                     NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1199                     Object);
1200   }
1201   // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
1202   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
1203   // 6. Let trap be ? GetMethod(handler, "get").
1204   Handle<Object> trap;
1205   ASSIGN_RETURN_ON_EXCEPTION(
1206       isolate, trap,
1207       Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), Object);
1208   // 7. If trap is undefined, then
1209   if (trap->IsUndefined(isolate)) {
1210     // 7.a Return target.[[Get]](P, Receiver).
1211     PropertyKey key(isolate, name);
1212     LookupIterator it(isolate, receiver, key, target);
1213     MaybeHandle<Object> result = Object::GetProperty(&it);
1214     *was_found = it.IsFound();
1215     return result;
1216   }
1217   // 8. Let trapResult be ? Call(trap, handler, «target, P, Receiver»).
1218   Handle<Object> trap_result;
1219   Handle<Object> args[] = {target, name, receiver};
1220   ASSIGN_RETURN_ON_EXCEPTION(
1221       isolate, trap_result,
1222       Execution::Call(isolate, trap, handler, arraysize(args), args), Object);
1223 
1224   MaybeHandle<Object> result =
1225       JSProxy::CheckGetSetTrapResult(isolate, name, target, trap_result, kGet);
1226   if (result.is_null()) {
1227     return result;
1228   }
1229 
1230   // 11. Return trap_result
1231   return trap_result;
1232 }
1233 
1234 // static
CheckGetSetTrapResult(Isolate * isolate,Handle<Name> name,Handle<JSReceiver> target,Handle<Object> trap_result,AccessKind access_kind)1235 MaybeHandle<Object> JSProxy::CheckGetSetTrapResult(Isolate* isolate,
1236                                                    Handle<Name> name,
1237                                                    Handle<JSReceiver> target,
1238                                                    Handle<Object> trap_result,
1239                                                    AccessKind access_kind) {
1240   // 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
1241   PropertyDescriptor target_desc;
1242   Maybe<bool> target_found =
1243       JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
1244   MAYBE_RETURN_NULL(target_found);
1245   // 10. If targetDesc is not undefined, then
1246   if (target_found.FromJust()) {
1247     // 10.a. If IsDataDescriptor(targetDesc) and targetDesc.[[Configurable]] is
1248     //       false and targetDesc.[[Writable]] is false, then
1249     // 10.a.i. If SameValue(trapResult, targetDesc.[[Value]]) is false,
1250     //        throw a TypeError exception.
1251     bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
1252                         !target_desc.configurable() &&
1253                         !target_desc.writable() &&
1254                         !trap_result->SameValue(*target_desc.value());
1255     if (inconsistent) {
1256       if (access_kind == kGet) {
1257         THROW_NEW_ERROR(
1258             isolate,
1259             NewTypeError(MessageTemplate::kProxyGetNonConfigurableData, name,
1260                          target_desc.value(), trap_result),
1261             Object);
1262       } else {
1263         isolate->Throw(*isolate->factory()->NewTypeError(
1264             MessageTemplate::kProxySetFrozenData, name));
1265         return MaybeHandle<Object>();
1266       }
1267     }
1268     // 10.b. If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]]
1269     //       is false and targetDesc.[[Get]] is undefined, then
1270     // 10.b.i. If trapResult is not undefined, throw a TypeError exception.
1271     if (access_kind == kGet) {
1272       inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
1273                      !target_desc.configurable() &&
1274                      target_desc.get()->IsUndefined(isolate) &&
1275                      !trap_result->IsUndefined(isolate);
1276     } else {
1277       inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
1278                      !target_desc.configurable() &&
1279                      target_desc.set()->IsUndefined(isolate);
1280     }
1281     if (inconsistent) {
1282       if (access_kind == kGet) {
1283         THROW_NEW_ERROR(
1284             isolate,
1285             NewTypeError(MessageTemplate::kProxyGetNonConfigurableAccessor,
1286                          name, trap_result),
1287             Object);
1288       } else {
1289         isolate->Throw(*isolate->factory()->NewTypeError(
1290             MessageTemplate::kProxySetFrozenAccessor, name));
1291         return MaybeHandle<Object>();
1292       }
1293     }
1294   }
1295   return isolate->factory()->undefined_value();
1296 }
1297 
ToInt32(int32_t * value)1298 bool Object::ToInt32(int32_t* value) {
1299   if (IsSmi()) {
1300     *value = Smi::ToInt(*this);
1301     return true;
1302   }
1303   if (IsHeapNumber()) {
1304     double num = HeapNumber::cast(*this).value();
1305     // Check range before conversion to avoid undefined behavior.
1306     if (num >= kMinInt && num <= kMaxInt && FastI2D(FastD2I(num)) == num) {
1307       *value = FastD2I(num);
1308       return true;
1309     }
1310   }
1311   return false;
1312 }
1313 
1314 // static
New(Isolate * isolate,int size)1315 Handle<TemplateList> TemplateList::New(Isolate* isolate, int size) {
1316   Handle<FixedArray> list =
1317       isolate->factory()->NewFixedArray(kLengthIndex + size);
1318   list->set(kLengthIndex, Smi::zero());
1319   return Handle<TemplateList>::cast(list);
1320 }
1321 
1322 // static
Add(Isolate * isolate,Handle<TemplateList> list,Handle<i::Object> value)1323 Handle<TemplateList> TemplateList::Add(Isolate* isolate,
1324                                        Handle<TemplateList> list,
1325                                        Handle<i::Object> value) {
1326   STATIC_ASSERT(kFirstElementIndex == 1);
1327   int index = list->length() + 1;
1328   Handle<i::FixedArray> fixed_array = Handle<FixedArray>::cast(list);
1329   fixed_array = FixedArray::SetAndGrow(isolate, fixed_array, index, value);
1330   fixed_array->set(kLengthIndex, Smi::FromInt(index));
1331   return Handle<TemplateList>::cast(fixed_array);
1332 }
1333 
1334 // ES6 9.5.1
1335 // static
GetPrototype(Handle<JSProxy> proxy)1336 MaybeHandle<HeapObject> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
1337   Isolate* isolate = proxy->GetIsolate();
1338   Handle<String> trap_name = isolate->factory()->getPrototypeOf_string();
1339 
1340   STACK_CHECK(isolate, MaybeHandle<HeapObject>());
1341 
1342   // 1. Let handler be the value of the [[ProxyHandler]] internal slot.
1343   // 2. If handler is null, throw a TypeError exception.
1344   // 3. Assert: Type(handler) is Object.
1345   // 4. Let target be the value of the [[ProxyTarget]] internal slot.
1346   if (proxy->IsRevoked()) {
1347     THROW_NEW_ERROR(isolate,
1348                     NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1349                     HeapObject);
1350   }
1351   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
1352   Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
1353 
1354   // 5. Let trap be ? GetMethod(handler, "getPrototypeOf").
1355   Handle<Object> trap;
1356   ASSIGN_RETURN_ON_EXCEPTION(isolate, trap,
1357                              Object::GetMethod(handler, trap_name), HeapObject);
1358   // 6. If trap is undefined, then return target.[[GetPrototypeOf]]().
1359   if (trap->IsUndefined(isolate)) {
1360     return JSReceiver::GetPrototype(isolate, target);
1361   }
1362   // 7. Let handlerProto be ? Call(trap, handler, «target»).
1363   Handle<Object> argv[] = {target};
1364   Handle<Object> handler_proto;
1365   ASSIGN_RETURN_ON_EXCEPTION(
1366       isolate, handler_proto,
1367       Execution::Call(isolate, trap, handler, arraysize(argv), argv),
1368       HeapObject);
1369   // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError.
1370   if (!(handler_proto->IsJSReceiver() || handler_proto->IsNull(isolate))) {
1371     THROW_NEW_ERROR(isolate,
1372                     NewTypeError(MessageTemplate::kProxyGetPrototypeOfInvalid),
1373                     HeapObject);
1374   }
1375   // 9. Let extensibleTarget be ? IsExtensible(target).
1376   Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
1377   MAYBE_RETURN(is_extensible, MaybeHandle<HeapObject>());
1378   // 10. If extensibleTarget is true, return handlerProto.
1379   if (is_extensible.FromJust()) return Handle<HeapObject>::cast(handler_proto);
1380   // 11. Let targetProto be ? target.[[GetPrototypeOf]]().
1381   Handle<HeapObject> target_proto;
1382   ASSIGN_RETURN_ON_EXCEPTION(isolate, target_proto,
1383                              JSReceiver::GetPrototype(isolate, target),
1384                              HeapObject);
1385   // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError.
1386   if (!handler_proto->SameValue(*target_proto)) {
1387     THROW_NEW_ERROR(
1388         isolate,
1389         NewTypeError(MessageTemplate::kProxyGetPrototypeOfNonExtensible),
1390         HeapObject);
1391   }
1392   // 13. Return handlerProto.
1393   return Handle<HeapObject>::cast(handler_proto);
1394 }
1395 
GetPropertyWithAccessor(LookupIterator * it)1396 MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) {
1397   Isolate* isolate = it->isolate();
1398   Handle<Object> structure = it->GetAccessors();
1399   Handle<Object> receiver = it->GetReceiver();
1400   // In case of global IC, the receiver is the global object. Replace by the
1401   // global proxy.
1402   if (receiver->IsJSGlobalObject()) {
1403     receiver = handle(JSGlobalObject::cast(*receiver).global_proxy(), isolate);
1404   }
1405 
1406   // We should never get here to initialize a const with the hole value since a
1407   // const declaration would conflict with the getter.
1408   DCHECK(!structure->IsForeign());
1409 
1410   // API style callbacks.
1411   Handle<JSObject> holder = it->GetHolder<JSObject>();
1412   if (structure->IsAccessorInfo()) {
1413     Handle<Name> name = it->GetName();
1414     Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
1415     if (!info->IsCompatibleReceiver(*receiver)) {
1416       THROW_NEW_ERROR(isolate,
1417                       NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
1418                                    name, receiver),
1419                       Object);
1420     }
1421 
1422     if (!info->has_getter()) return isolate->factory()->undefined_value();
1423 
1424     if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1425       ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver,
1426                                  Object::ConvertReceiver(isolate, receiver),
1427                                  Object);
1428     }
1429 
1430     PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1431                                    Just(kDontThrow));
1432     Handle<Object> result = args.CallAccessorGetter(info, name);
1433     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1434     if (result.is_null()) return isolate->factory()->undefined_value();
1435     Handle<Object> reboxed_result = handle(*result, isolate);
1436     if (info->replace_on_access() && receiver->IsJSReceiver()) {
1437       RETURN_ON_EXCEPTION(isolate,
1438                           Accessors::ReplaceAccessorWithDataProperty(
1439                               isolate, receiver, holder, name, result),
1440                           Object);
1441     }
1442     return reboxed_result;
1443   }
1444 
1445   Handle<AccessorPair> accessor_pair = Handle<AccessorPair>::cast(structure);
1446   // AccessorPair with 'cached' private property.
1447   if (it->TryLookupCachedProperty(accessor_pair)) {
1448     return Object::GetProperty(it);
1449   }
1450 
1451   // Regular accessor.
1452   Handle<Object> getter(accessor_pair->getter(), isolate);
1453   if (getter->IsFunctionTemplateInfo()) {
1454     SaveAndSwitchContext save(isolate,
1455                               *holder->GetCreationContext().ToHandleChecked());
1456     return Builtins::InvokeApiFunction(
1457         isolate, false, Handle<FunctionTemplateInfo>::cast(getter), receiver, 0,
1458         nullptr, isolate->factory()->undefined_value());
1459   } else if (getter->IsCallable()) {
1460     // TODO(rossberg): nicer would be to cast to some JSCallable here...
1461     return Object::GetPropertyWithDefinedGetter(
1462         receiver, Handle<JSReceiver>::cast(getter));
1463   }
1464   // Getter is not a function.
1465   return isolate->factory()->undefined_value();
1466 }
1467 
1468 // static
redirect(Address address,AccessorComponent component)1469 Address AccessorInfo::redirect(Address address, AccessorComponent component) {
1470   ApiFunction fun(address);
1471   DCHECK_EQ(ACCESSOR_GETTER, component);
1472   ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
1473   return ExternalReference::Create(&fun, type).address();
1474 }
1475 
redirected_getter() const1476 Address AccessorInfo::redirected_getter() const {
1477   Address accessor = v8::ToCData<Address>(getter());
1478   if (accessor == kNullAddress) return kNullAddress;
1479   return redirect(accessor, ACCESSOR_GETTER);
1480 }
1481 
redirected_callback() const1482 Address CallHandlerInfo::redirected_callback() const {
1483   Address address = v8::ToCData<Address>(callback());
1484   ApiFunction fun(address);
1485   ExternalReference::Type type = ExternalReference::DIRECT_API_CALL;
1486   return ExternalReference::Create(&fun, type).address();
1487 }
1488 
IsCompatibleReceiverMap(Handle<AccessorInfo> info,Handle<Map> map)1489 bool AccessorInfo::IsCompatibleReceiverMap(Handle<AccessorInfo> info,
1490                                            Handle<Map> map) {
1491   if (!info->HasExpectedReceiverType()) return true;
1492   if (!map->IsJSObjectMap()) return false;
1493   return FunctionTemplateInfo::cast(info->expected_receiver_type())
1494       .IsTemplateFor(*map);
1495 }
1496 
SetPropertyWithAccessor(LookupIterator * it,Handle<Object> value,Maybe<ShouldThrow> maybe_should_throw)1497 Maybe<bool> Object::SetPropertyWithAccessor(
1498     LookupIterator* it, Handle<Object> value,
1499     Maybe<ShouldThrow> maybe_should_throw) {
1500   Isolate* isolate = it->isolate();
1501   Handle<Object> structure = it->GetAccessors();
1502   Handle<Object> receiver = it->GetReceiver();
1503   // In case of global IC, the receiver is the global object. Replace by the
1504   // global proxy.
1505   if (receiver->IsJSGlobalObject()) {
1506     receiver = handle(JSGlobalObject::cast(*receiver).global_proxy(), isolate);
1507   }
1508 
1509   // We should never get here to initialize a const with the hole value since a
1510   // const declaration would conflict with the setter.
1511   DCHECK(!structure->IsForeign());
1512 
1513   // API style callbacks.
1514   Handle<JSObject> holder = it->GetHolder<JSObject>();
1515   if (structure->IsAccessorInfo()) {
1516     Handle<Name> name = it->GetName();
1517     Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
1518     if (!info->IsCompatibleReceiver(*receiver)) {
1519       isolate->Throw(*isolate->factory()->NewTypeError(
1520           MessageTemplate::kIncompatibleMethodReceiver, name, receiver));
1521       return Nothing<bool>();
1522     }
1523 
1524     if (!info->has_setter()) {
1525       // TODO(verwaest): We should not get here anymore once all AccessorInfos
1526       // are marked as special_data_property. They cannot both be writable and
1527       // not have a setter.
1528       return Just(true);
1529     }
1530 
1531     if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1532       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1533           isolate, receiver, Object::ConvertReceiver(isolate, receiver),
1534           Nothing<bool>());
1535     }
1536 
1537     // The actual type of setter callback is either
1538     // v8::AccessorNameSetterCallback or
1539     // i::Accesors::AccessorNameBooleanSetterCallback, depending on whether the
1540     // AccessorInfo was created by the API or internally (see accessors.cc).
1541     // Here we handle both cases using GenericNamedPropertySetterCallback and
1542     // its Call method.
1543     PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1544                                    maybe_should_throw);
1545     Handle<Object> result = args.CallAccessorSetter(info, name, value);
1546     // In the case of AccessorNameSetterCallback, we know that the result value
1547     // cannot have been set, so the result of Call will be null.  In the case of
1548     // AccessorNameBooleanSetterCallback, the result will either be null
1549     // (signalling an exception) or a boolean Oddball.
1550     RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1551     if (result.is_null()) return Just(true);
1552     DCHECK(result->BooleanValue(isolate) ||
1553            GetShouldThrow(isolate, maybe_should_throw) == kDontThrow);
1554     return Just(result->BooleanValue(isolate));
1555   }
1556 
1557   // Regular accessor.
1558   Handle<Object> setter(AccessorPair::cast(*structure).setter(), isolate);
1559   if (setter->IsFunctionTemplateInfo()) {
1560     SaveAndSwitchContext save(isolate,
1561                               *holder->GetCreationContext().ToHandleChecked());
1562     Handle<Object> argv[] = {value};
1563     RETURN_ON_EXCEPTION_VALUE(
1564         isolate,
1565         Builtins::InvokeApiFunction(isolate, false,
1566                                     Handle<FunctionTemplateInfo>::cast(setter),
1567                                     receiver, arraysize(argv), argv,
1568                                     isolate->factory()->undefined_value()),
1569         Nothing<bool>());
1570     return Just(true);
1571   } else if (setter->IsCallable()) {
1572     // TODO(rossberg): nicer would be to cast to some JSCallable here...
1573     return SetPropertyWithDefinedSetter(
1574         receiver, Handle<JSReceiver>::cast(setter), value, maybe_should_throw);
1575   }
1576 
1577   RETURN_FAILURE(isolate, GetShouldThrow(isolate, maybe_should_throw),
1578                  NewTypeError(MessageTemplate::kNoSetterInCallback,
1579                               it->GetName(), it->GetHolder<JSObject>()));
1580 }
1581 
GetPropertyWithDefinedGetter(Handle<Object> receiver,Handle<JSReceiver> getter)1582 MaybeHandle<Object> Object::GetPropertyWithDefinedGetter(
1583     Handle<Object> receiver, Handle<JSReceiver> getter) {
1584   Isolate* isolate = getter->GetIsolate();
1585 
1586   // Platforms with simulators like arm/arm64 expose a funny issue. If the
1587   // simulator has a separate JS stack pointer from the C++ stack pointer, it
1588   // can miss C++ stack overflows in the stack guard at the start of JavaScript
1589   // functions. It would be very expensive to check the C++ stack pointer at
1590   // that location. The best solution seems to be to break the impasse by
1591   // adding checks at possible recursion points. What's more, we don't put
1592   // this stack check behind the USE_SIMULATOR define in order to keep
1593   // behavior the same between hardware and simulators.
1594   StackLimitCheck check(isolate);
1595   if (check.JsHasOverflowed()) {
1596     isolate->StackOverflow();
1597     return MaybeHandle<Object>();
1598   }
1599 
1600   return Execution::Call(isolate, getter, receiver, 0, nullptr);
1601 }
1602 
SetPropertyWithDefinedSetter(Handle<Object> receiver,Handle<JSReceiver> setter,Handle<Object> value,Maybe<ShouldThrow> should_throw)1603 Maybe<bool> Object::SetPropertyWithDefinedSetter(
1604     Handle<Object> receiver, Handle<JSReceiver> setter, Handle<Object> value,
1605     Maybe<ShouldThrow> should_throw) {
1606   Isolate* isolate = setter->GetIsolate();
1607 
1608   Handle<Object> argv[] = {value};
1609   RETURN_ON_EXCEPTION_VALUE(
1610       isolate,
1611       Execution::Call(isolate, setter, receiver, arraysize(argv), argv),
1612       Nothing<bool>());
1613   return Just(true);
1614 }
1615 
GetPrototypeChainRootMap(Isolate * isolate) const1616 Map Object::GetPrototypeChainRootMap(Isolate* isolate) const {
1617   DisallowGarbageCollection no_alloc;
1618   if (IsSmi()) {
1619     Context native_context = isolate->context().native_context();
1620     return native_context.number_function().initial_map();
1621   }
1622 
1623   const HeapObject heap_object = HeapObject::cast(*this);
1624   return heap_object.map().GetPrototypeChainRootMap(isolate);
1625 }
1626 
GetOrCreateHash(Isolate * isolate)1627 Smi Object::GetOrCreateHash(Isolate* isolate) {
1628   DisallowGarbageCollection no_gc;
1629   Object hash = Object::GetSimpleHash(*this);
1630   if (hash.IsSmi()) return Smi::cast(hash);
1631 
1632   DCHECK(IsJSReceiver());
1633   return JSReceiver::cast(*this).GetOrCreateIdentityHash(isolate);
1634 }
1635 
SameValue(Object other)1636 bool Object::SameValue(Object other) {
1637   if (other == *this) return true;
1638 
1639   if (IsNumber() && other.IsNumber()) {
1640     return SameNumberValue(Number(), other.Number());
1641   }
1642   if (IsString() && other.IsString()) {
1643     return String::cast(*this).Equals(String::cast(other));
1644   }
1645   if (IsBigInt() && other.IsBigInt()) {
1646     return BigInt::EqualToBigInt(BigInt::cast(*this), BigInt::cast(other));
1647   }
1648   return false;
1649 }
1650 
SameValueZero(Object other)1651 bool Object::SameValueZero(Object other) {
1652   if (other == *this) return true;
1653 
1654   if (IsNumber() && other.IsNumber()) {
1655     double this_value = Number();
1656     double other_value = other.Number();
1657     // +0 == -0 is true
1658     return this_value == other_value ||
1659            (std::isnan(this_value) && std::isnan(other_value));
1660   }
1661   if (IsString() && other.IsString()) {
1662     return String::cast(*this).Equals(String::cast(other));
1663   }
1664   if (IsBigInt() && other.IsBigInt()) {
1665     return BigInt::EqualToBigInt(BigInt::cast(*this), BigInt::cast(other));
1666   }
1667   return false;
1668 }
1669 
ArraySpeciesConstructor(Isolate * isolate,Handle<Object> original_array)1670 MaybeHandle<Object> Object::ArraySpeciesConstructor(
1671     Isolate* isolate, Handle<Object> original_array) {
1672   Handle<Object> default_species = isolate->array_function();
1673   if (!FLAG_builtin_subclassing) return default_species;
1674   if (original_array->IsJSArray() &&
1675       Handle<JSArray>::cast(original_array)->HasArrayPrototype(isolate) &&
1676       Protectors::IsArraySpeciesLookupChainIntact(isolate)) {
1677     return default_species;
1678   }
1679   Handle<Object> constructor = isolate->factory()->undefined_value();
1680   Maybe<bool> is_array = Object::IsArray(original_array);
1681   MAYBE_RETURN_NULL(is_array);
1682   if (is_array.FromJust()) {
1683     ASSIGN_RETURN_ON_EXCEPTION(
1684         isolate, constructor,
1685         Object::GetProperty(isolate, original_array,
1686                             isolate->factory()->constructor_string()),
1687         Object);
1688     if (constructor->IsConstructor()) {
1689       Handle<Context> constructor_context;
1690       ASSIGN_RETURN_ON_EXCEPTION(
1691           isolate, constructor_context,
1692           JSReceiver::GetFunctionRealm(Handle<JSReceiver>::cast(constructor)),
1693           Object);
1694       if (*constructor_context != *isolate->native_context() &&
1695           *constructor == constructor_context->array_function()) {
1696         constructor = isolate->factory()->undefined_value();
1697       }
1698     }
1699     if (constructor->IsJSReceiver()) {
1700       ASSIGN_RETURN_ON_EXCEPTION(
1701           isolate, constructor,
1702           JSReceiver::GetProperty(isolate,
1703                                   Handle<JSReceiver>::cast(constructor),
1704                                   isolate->factory()->species_symbol()),
1705           Object);
1706       if (constructor->IsNull(isolate)) {
1707         constructor = isolate->factory()->undefined_value();
1708       }
1709     }
1710   }
1711   if (constructor->IsUndefined(isolate)) {
1712     return default_species;
1713   } else {
1714     if (!constructor->IsConstructor()) {
1715       THROW_NEW_ERROR(isolate,
1716                       NewTypeError(MessageTemplate::kSpeciesNotConstructor),
1717                       Object);
1718     }
1719     return constructor;
1720   }
1721 }
1722 
1723 // ES6 section 7.3.20 SpeciesConstructor ( O, defaultConstructor )
SpeciesConstructor(Isolate * isolate,Handle<JSReceiver> recv,Handle<JSFunction> default_ctor)1724 V8_WARN_UNUSED_RESULT MaybeHandle<Object> Object::SpeciesConstructor(
1725     Isolate* isolate, Handle<JSReceiver> recv,
1726     Handle<JSFunction> default_ctor) {
1727   Handle<Object> ctor_obj;
1728   ASSIGN_RETURN_ON_EXCEPTION(
1729       isolate, ctor_obj,
1730       JSObject::GetProperty(isolate, recv,
1731                             isolate->factory()->constructor_string()),
1732       Object);
1733 
1734   if (ctor_obj->IsUndefined(isolate)) return default_ctor;
1735 
1736   if (!ctor_obj->IsJSReceiver()) {
1737     THROW_NEW_ERROR(isolate,
1738                     NewTypeError(MessageTemplate::kConstructorNotReceiver),
1739                     Object);
1740   }
1741 
1742   Handle<JSReceiver> ctor = Handle<JSReceiver>::cast(ctor_obj);
1743 
1744   Handle<Object> species;
1745   ASSIGN_RETURN_ON_EXCEPTION(
1746       isolate, species,
1747       JSObject::GetProperty(isolate, ctor,
1748                             isolate->factory()->species_symbol()),
1749       Object);
1750 
1751   if (species->IsNullOrUndefined(isolate)) {
1752     return default_ctor;
1753   }
1754 
1755   if (species->IsConstructor()) return species;
1756 
1757   THROW_NEW_ERROR(
1758       isolate, NewTypeError(MessageTemplate::kSpeciesNotConstructor), Object);
1759 }
1760 
IterationHasObservableEffects()1761 bool Object::IterationHasObservableEffects() {
1762   // Check that this object is an array.
1763   if (!IsJSArray()) return true;
1764   JSArray array = JSArray::cast(*this);
1765   Isolate* isolate = array.GetIsolate();
1766 
1767   // Check that we have the original ArrayPrototype.
1768   i::HandleScope handle_scope(isolate);
1769   i::Handle<i::Context> context;
1770   if (!array.GetCreationContext().ToHandle(&context)) return false;
1771   if (!array.map().prototype().IsJSObject()) return true;
1772   JSObject array_proto = JSObject::cast(array.map().prototype());
1773   auto initial_array_prototype =
1774       context->native_context().initial_array_prototype();
1775   if (initial_array_prototype != array_proto) return true;
1776 
1777   // Check that the ArrayPrototype hasn't been modified in a way that would
1778   // affect iteration.
1779   if (!Protectors::IsArrayIteratorLookupChainIntact(isolate)) return true;
1780 
1781   // For FastPacked kinds, iteration will have the same effect as simply
1782   // accessing each property in order.
1783   ElementsKind array_kind = array.GetElementsKind();
1784   if (IsFastPackedElementsKind(array_kind)) return false;
1785 
1786   // For FastHoley kinds, an element access on a hole would cause a lookup on
1787   // the prototype. This could have different results if the prototype has been
1788   // changed.
1789   if (IsHoleyElementsKind(array_kind) &&
1790       Protectors::IsNoElementsIntact(isolate)) {
1791     return false;
1792   }
1793   return true;
1794 }
1795 
IsCodeLike(Isolate * isolate) const1796 bool Object::IsCodeLike(Isolate* isolate) const {
1797   DisallowGarbageCollection no_gc;
1798   return IsJSReceiver() && JSReceiver::cast(*this).IsCodeLike(isolate);
1799 }
1800 
ShortPrint(FILE * out) const1801 void Object::ShortPrint(FILE* out) const {
1802   OFStream os(out);
1803   os << Brief(*this);
1804 }
1805 
ShortPrint(StringStream * accumulator) const1806 void Object::ShortPrint(StringStream* accumulator) const {
1807   std::ostringstream os;
1808   os << Brief(*this);
1809   accumulator->Add(os.str().c_str());
1810 }
1811 
ShortPrint(std::ostream & os) const1812 void Object::ShortPrint(std::ostream& os) const { os << Brief(*this); }
1813 
operator <<(std::ostream & os,const Object & obj)1814 std::ostream& operator<<(std::ostream& os, const Object& obj) {
1815   obj.ShortPrint(os);
1816   return os;
1817 }
1818 
operator <<(std::ostream & os,const Brief & v)1819 std::ostream& operator<<(std::ostream& os, const Brief& v) {
1820   MaybeObject maybe_object(v.value);
1821   Smi smi;
1822   HeapObject heap_object;
1823   if (maybe_object->ToSmi(&smi)) {
1824     smi.SmiPrint(os);
1825   } else if (maybe_object->IsCleared()) {
1826     os << "[cleared]";
1827   } else if (maybe_object->GetHeapObjectIfWeak(&heap_object)) {
1828     os << "[weak] ";
1829     heap_object.HeapObjectShortPrint(os);
1830   } else if (maybe_object->GetHeapObjectIfStrong(&heap_object)) {
1831     heap_object.HeapObjectShortPrint(os);
1832   } else {
1833     UNREACHABLE();
1834   }
1835   return os;
1836 }
1837 
SmiPrint(std::ostream & os) const1838 void Smi::SmiPrint(std::ostream& os) const { os << value(); }
1839 
HeapObjectShortPrint(std::ostream & os)1840 void HeapObject::HeapObjectShortPrint(std::ostream& os) {
1841   os << AsHex::Address(this->ptr()) << " ";
1842 
1843   if (IsString()) {
1844     HeapStringAllocator allocator;
1845     StringStream accumulator(&allocator);
1846     String::cast(*this).StringShortPrint(&accumulator);
1847     os << accumulator.ToCString().get();
1848     return;
1849   }
1850   if (IsJSObject()) {
1851     HeapStringAllocator allocator;
1852     StringStream accumulator(&allocator);
1853     JSObject::cast(*this).JSObjectShortPrint(&accumulator);
1854     os << accumulator.ToCString().get();
1855     return;
1856   }
1857   switch (map().instance_type()) {
1858     case MAP_TYPE: {
1859       os << "<Map";
1860       Map mapInstance = Map::cast(*this);
1861       if (mapInstance.IsJSObjectMap()) {
1862         os << "(" << ElementsKindToString(mapInstance.elements_kind()) << ")";
1863       } else if (mapInstance.instance_size() != kVariableSizeSentinel) {
1864         os << "[" << mapInstance.instance_size() << "]";
1865       }
1866       os << ">";
1867     } break;
1868     case AWAIT_CONTEXT_TYPE: {
1869       os << "<AwaitContext generator= ";
1870       HeapStringAllocator allocator;
1871       StringStream accumulator(&allocator);
1872       Context::cast(*this).extension().ShortPrint(&accumulator);
1873       os << accumulator.ToCString().get();
1874       os << '>';
1875       break;
1876     }
1877     case BLOCK_CONTEXT_TYPE:
1878       os << "<BlockContext[" << Context::cast(*this).length() << "]>";
1879       break;
1880     case CATCH_CONTEXT_TYPE:
1881       os << "<CatchContext[" << Context::cast(*this).length() << "]>";
1882       break;
1883     case DEBUG_EVALUATE_CONTEXT_TYPE:
1884       os << "<DebugEvaluateContext[" << Context::cast(*this).length() << "]>";
1885       break;
1886     case EVAL_CONTEXT_TYPE:
1887       os << "<EvalContext[" << Context::cast(*this).length() << "]>";
1888       break;
1889     case FUNCTION_CONTEXT_TYPE:
1890       os << "<FunctionContext[" << Context::cast(*this).length() << "]>";
1891       break;
1892     case MODULE_CONTEXT_TYPE:
1893       os << "<ModuleContext[" << Context::cast(*this).length() << "]>";
1894       break;
1895     case NATIVE_CONTEXT_TYPE:
1896       os << "<NativeContext[" << Context::cast(*this).length() << "]>";
1897       break;
1898     case SCRIPT_CONTEXT_TYPE:
1899       os << "<ScriptContext[" << Context::cast(*this).length() << "]>";
1900       break;
1901     case WITH_CONTEXT_TYPE:
1902       os << "<WithContext[" << Context::cast(*this).length() << "]>";
1903       break;
1904     case SCRIPT_CONTEXT_TABLE_TYPE:
1905       os << "<ScriptContextTable[" << FixedArray::cast(*this).length() << "]>";
1906       break;
1907     case HASH_TABLE_TYPE:
1908       os << "<HashTable[" << FixedArray::cast(*this).length() << "]>";
1909       break;
1910     case ORDERED_HASH_MAP_TYPE:
1911       os << "<OrderedHashMap[" << FixedArray::cast(*this).length() << "]>";
1912       break;
1913     case ORDERED_HASH_SET_TYPE:
1914       os << "<OrderedHashSet[" << FixedArray::cast(*this).length() << "]>";
1915       break;
1916     case ORDERED_NAME_DICTIONARY_TYPE:
1917       os << "<OrderedNameDictionary[" << FixedArray::cast(*this).length()
1918          << "]>";
1919       break;
1920     case NAME_DICTIONARY_TYPE:
1921       os << "<NameDictionary[" << FixedArray::cast(*this).length() << "]>";
1922       break;
1923     case SWISS_NAME_DICTIONARY_TYPE:
1924       os << "<SwissNameDictionary["
1925          << SwissNameDictionary::cast(*this).Capacity() << "]>";
1926       break;
1927     case GLOBAL_DICTIONARY_TYPE:
1928       os << "<GlobalDictionary[" << FixedArray::cast(*this).length() << "]>";
1929       break;
1930     case NUMBER_DICTIONARY_TYPE:
1931       os << "<NumberDictionary[" << FixedArray::cast(*this).length() << "]>";
1932       break;
1933     case SIMPLE_NUMBER_DICTIONARY_TYPE:
1934       os << "<SimpleNumberDictionary[" << FixedArray::cast(*this).length()
1935          << "]>";
1936       break;
1937     case FIXED_ARRAY_TYPE:
1938       os << "<FixedArray[" << FixedArray::cast(*this).length() << "]>";
1939       break;
1940     case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
1941       os << "<ObjectBoilerplateDescription[" << FixedArray::cast(*this).length()
1942          << "]>";
1943       break;
1944     case FIXED_DOUBLE_ARRAY_TYPE:
1945       os << "<FixedDoubleArray[" << FixedDoubleArray::cast(*this).length()
1946          << "]>";
1947       break;
1948     case BYTE_ARRAY_TYPE:
1949       os << "<ByteArray[" << ByteArray::cast(*this).length() << "]>";
1950       break;
1951     case BYTECODE_ARRAY_TYPE:
1952       os << "<BytecodeArray[" << BytecodeArray::cast(*this).length() << "]>";
1953       break;
1954     case DESCRIPTOR_ARRAY_TYPE:
1955       os << "<DescriptorArray["
1956          << DescriptorArray::cast(*this).number_of_descriptors() << "]>";
1957       break;
1958     case TRANSITION_ARRAY_TYPE:
1959       os << "<TransitionArray[" << TransitionArray::cast(*this).length()
1960          << "]>";
1961       break;
1962     case PROPERTY_ARRAY_TYPE:
1963       os << "<PropertyArray[" << PropertyArray::cast(*this).length() << "]>";
1964       break;
1965     case FEEDBACK_CELL_TYPE: {
1966       {
1967         ReadOnlyRoots roots = GetReadOnlyRoots();
1968         os << "<FeedbackCell[";
1969         if (map() == roots.no_closures_cell_map()) {
1970           os << "no feedback";
1971         } else if (map() == roots.no_closures_cell_map()) {
1972           os << "no closures";
1973         } else if (map() == roots.one_closure_cell_map()) {
1974           os << "one closure";
1975         } else if (map() == roots.many_closures_cell_map()) {
1976           os << "many closures";
1977         } else {
1978           os << "!!!INVALID MAP!!!";
1979         }
1980         os << "]>";
1981       }
1982       break;
1983     }
1984     case CLOSURE_FEEDBACK_CELL_ARRAY_TYPE:
1985       os << "<ClosureFeedbackCellArray["
1986          << ClosureFeedbackCellArray::cast(*this).length() << "]>";
1987       break;
1988     case FEEDBACK_VECTOR_TYPE:
1989       os << "<FeedbackVector[" << FeedbackVector::cast(*this).length() << "]>";
1990       break;
1991     case FREE_SPACE_TYPE:
1992       os << "<FreeSpace[" << FreeSpace::cast(*this).size(kRelaxedLoad) << "]>";
1993       break;
1994 
1995     case PREPARSE_DATA_TYPE: {
1996       PreparseData data = PreparseData::cast(*this);
1997       os << "<PreparseData[data=" << data.data_length()
1998          << " children=" << data.children_length() << "]>";
1999       break;
2000     }
2001 
2002     case UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE: {
2003       UncompiledDataWithoutPreparseData data =
2004           UncompiledDataWithoutPreparseData::cast(*this);
2005       os << "<UncompiledDataWithoutPreparseData (" << data.start_position()
2006          << ", " << data.end_position() << ")]>";
2007       break;
2008     }
2009 
2010     case UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE: {
2011       UncompiledDataWithPreparseData data =
2012           UncompiledDataWithPreparseData::cast(*this);
2013       os << "<UncompiledDataWithPreparseData (" << data.start_position() << ", "
2014          << data.end_position() << ") preparsed=" << Brief(data.preparse_data())
2015          << ">";
2016       break;
2017     }
2018 
2019     case SHARED_FUNCTION_INFO_TYPE: {
2020       SharedFunctionInfo shared = SharedFunctionInfo::cast(*this);
2021       std::unique_ptr<char[]> debug_name = shared.DebugNameCStr();
2022       if (debug_name[0] != '\0') {
2023         os << "<SharedFunctionInfo " << debug_name.get() << ">";
2024       } else {
2025         os << "<SharedFunctionInfo>";
2026       }
2027       break;
2028     }
2029     case JS_MESSAGE_OBJECT_TYPE:
2030       os << "<JSMessageObject>";
2031       break;
2032 #define MAKE_STRUCT_CASE(TYPE, Name, name)   \
2033   case TYPE:                                 \
2034     os << "<" #Name;                         \
2035     Name::cast(*this).BriefPrintDetails(os); \
2036     os << ">";                               \
2037     break;
2038       STRUCT_LIST(MAKE_STRUCT_CASE)
2039 #undef MAKE_STRUCT_CASE
2040     case ALLOCATION_SITE_TYPE: {
2041       os << "<AllocationSite";
2042       AllocationSite::cast(*this).BriefPrintDetails(os);
2043       os << ">";
2044       break;
2045     }
2046     case SCOPE_INFO_TYPE: {
2047       ScopeInfo scope = ScopeInfo::cast(*this);
2048       os << "<ScopeInfo";
2049       if (!scope.IsEmpty()) os << " " << scope.scope_type();
2050       os << ">";
2051       break;
2052     }
2053     case CODE_TYPE: {
2054       Code code = Code::cast(*this);
2055       os << "<Code " << CodeKindToString(code.kind());
2056       if (code.is_builtin()) {
2057         os << " " << Builtins::name(code.builtin_id());
2058       }
2059       os << ">";
2060       break;
2061     }
2062     case ODDBALL_TYPE: {
2063       if (IsUndefined()) {
2064         os << "<undefined>";
2065       } else if (IsTheHole()) {
2066         os << "<the_hole>";
2067       } else if (IsNull()) {
2068         os << "<null>";
2069       } else if (IsTrue()) {
2070         os << "<true>";
2071       } else if (IsFalse()) {
2072         os << "<false>";
2073       } else {
2074         os << "<Odd Oddball: ";
2075         os << Oddball::cast(*this).to_string().ToCString().get();
2076         os << ">";
2077       }
2078       break;
2079     }
2080     case SYMBOL_TYPE: {
2081       Symbol symbol = Symbol::cast(*this);
2082       symbol.SymbolShortPrint(os);
2083       break;
2084     }
2085     case HEAP_NUMBER_TYPE: {
2086       os << "<HeapNumber ";
2087       HeapNumber::cast(*this).HeapNumberShortPrint(os);
2088       os << ">";
2089       break;
2090     }
2091     case BIGINT_TYPE: {
2092       os << "<BigInt ";
2093       BigInt::cast(*this).BigIntShortPrint(os);
2094       os << ">";
2095       break;
2096     }
2097     case JS_PROXY_TYPE:
2098       os << "<JSProxy>";
2099       break;
2100     case FOREIGN_TYPE:
2101       os << "<Foreign>";
2102       break;
2103     case CELL_TYPE: {
2104       os << "<Cell value= ";
2105       HeapStringAllocator allocator;
2106       StringStream accumulator(&allocator);
2107       Cell::cast(*this).value().ShortPrint(&accumulator);
2108       os << accumulator.ToCString().get();
2109       os << '>';
2110       break;
2111     }
2112     case PROPERTY_CELL_TYPE: {
2113       PropertyCell cell = PropertyCell::cast(*this);
2114       os << "<PropertyCell name=";
2115       cell.name().ShortPrint(os);
2116       os << " value=";
2117       HeapStringAllocator allocator;
2118       StringStream accumulator(&allocator);
2119       cell.value(kAcquireLoad).ShortPrint(&accumulator);
2120       os << accumulator.ToCString().get();
2121       os << '>';
2122       break;
2123     }
2124     case CALL_HANDLER_INFO_TYPE: {
2125       CallHandlerInfo info = CallHandlerInfo::cast(*this);
2126       os << "<CallHandlerInfo ";
2127       os << "callback= " << Brief(info.callback());
2128       os << ", js_callback= " << Brief(info.js_callback());
2129       os << ", data= " << Brief(info.data());
2130       if (info.IsSideEffectFreeCallHandlerInfo()) {
2131         os << ", side_effect_free= true>";
2132       } else {
2133         os << ", side_effect_free= false>";
2134       }
2135       break;
2136     }
2137     default:
2138       os << "<Other heap object (" << map().instance_type() << ")>";
2139       break;
2140   }
2141 }
2142 
BriefPrintDetails(std::ostream & os)2143 void Struct::BriefPrintDetails(std::ostream& os) {}
2144 
BriefPrintDetails(std::ostream & os)2145 void Tuple2::BriefPrintDetails(std::ostream& os) {
2146   os << " " << Brief(value1()) << ", " << Brief(value2());
2147 }
2148 
BriefPrintDetails(std::ostream & os)2149 void MegaDomHandler::BriefPrintDetails(std::ostream& os) {
2150   os << " " << Brief(accessor()) << ", " << Brief(context());
2151 }
2152 
BriefPrintDetails(std::ostream & os)2153 void ClassPositions::BriefPrintDetails(std::ostream& os) {
2154   os << " " << start() << ", " << end();
2155 }
2156 
BriefPrintDetails(std::ostream & os)2157 void CallableTask::BriefPrintDetails(std::ostream& os) {
2158   os << " callable=" << Brief(callable());
2159 }
2160 
Iterate(ObjectVisitor * v)2161 void HeapObject::Iterate(ObjectVisitor* v) { IterateFast<ObjectVisitor>(v); }
2162 
IterateBody(ObjectVisitor * v)2163 void HeapObject::IterateBody(ObjectVisitor* v) {
2164   Map m = map();
2165   IterateBodyFast<ObjectVisitor>(m, SizeFromMap(m), v);
2166 }
2167 
IterateBody(Map map,int object_size,ObjectVisitor * v)2168 void HeapObject::IterateBody(Map map, int object_size, ObjectVisitor* v) {
2169   IterateBodyFast<ObjectVisitor>(map, object_size, v);
2170 }
2171 
2172 struct CallIsValidSlot {
2173   template <typename BodyDescriptor>
applyv8::internal::CallIsValidSlot2174   static bool apply(Map map, HeapObject obj, int offset, int) {
2175     return BodyDescriptor::IsValidSlot(map, obj, offset);
2176   }
2177 };
2178 
IsValidSlot(Map map,int offset)2179 bool HeapObject::IsValidSlot(Map map, int offset) {
2180   DCHECK_NE(0, offset);
2181   return BodyDescriptorApply<CallIsValidSlot, bool>(map.instance_type(), map,
2182                                                     *this, offset, 0);
2183 }
2184 
SizeFromMap(Map map) const2185 int HeapObject::SizeFromMap(Map map) const {
2186   int instance_size = map.instance_size();
2187   if (instance_size != kVariableSizeSentinel) return instance_size;
2188   // Only inline the most frequent cases.
2189   InstanceType instance_type = map.instance_type();
2190   if (base::IsInRange(instance_type, FIRST_FIXED_ARRAY_TYPE,
2191                       LAST_FIXED_ARRAY_TYPE)) {
2192     return FixedArray::SizeFor(
2193         FixedArray::unchecked_cast(*this).length(kAcquireLoad));
2194   }
2195   if (base::IsInRange(instance_type, FIRST_CONTEXT_TYPE, LAST_CONTEXT_TYPE)) {
2196     if (instance_type == NATIVE_CONTEXT_TYPE) return NativeContext::kSize;
2197     return Context::SizeFor(Context::unchecked_cast(*this).length());
2198   }
2199   if (instance_type == ONE_BYTE_STRING_TYPE ||
2200       instance_type == ONE_BYTE_INTERNALIZED_STRING_TYPE) {
2201     // Strings may get concurrently truncated, hence we have to access its
2202     // length synchronized.
2203     return SeqOneByteString::SizeFor(
2204         SeqOneByteString::unchecked_cast(*this).length(kAcquireLoad));
2205   }
2206   if (instance_type == BYTE_ARRAY_TYPE) {
2207     return ByteArray::SizeFor(
2208         ByteArray::unchecked_cast(*this).length(kAcquireLoad));
2209   }
2210   if (instance_type == BYTECODE_ARRAY_TYPE) {
2211     return BytecodeArray::SizeFor(
2212         BytecodeArray::unchecked_cast(*this).length(kAcquireLoad));
2213   }
2214   if (instance_type == FREE_SPACE_TYPE) {
2215     return FreeSpace::unchecked_cast(*this).size(kRelaxedLoad);
2216   }
2217   if (instance_type == STRING_TYPE ||
2218       instance_type == INTERNALIZED_STRING_TYPE) {
2219     // Strings may get concurrently truncated, hence we have to access its
2220     // length synchronized.
2221     return SeqTwoByteString::SizeFor(
2222         SeqTwoByteString::unchecked_cast(*this).length(kAcquireLoad));
2223   }
2224   if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) {
2225     return FixedDoubleArray::SizeFor(
2226         FixedDoubleArray::unchecked_cast(*this).length(kAcquireLoad));
2227   }
2228   if (instance_type == FEEDBACK_METADATA_TYPE) {
2229     return FeedbackMetadata::SizeFor(
2230         FeedbackMetadata::unchecked_cast(*this).slot_count(kAcquireLoad));
2231   }
2232   if (base::IsInRange(instance_type, FIRST_DESCRIPTOR_ARRAY_TYPE,
2233                       LAST_DESCRIPTOR_ARRAY_TYPE)) {
2234     return DescriptorArray::SizeFor(
2235         DescriptorArray::unchecked_cast(*this).number_of_all_descriptors());
2236   }
2237   if (base::IsInRange(instance_type, FIRST_WEAK_FIXED_ARRAY_TYPE,
2238                       LAST_WEAK_FIXED_ARRAY_TYPE)) {
2239     return WeakFixedArray::SizeFor(
2240         WeakFixedArray::unchecked_cast(*this).length(kAcquireLoad));
2241   }
2242   if (instance_type == WEAK_ARRAY_LIST_TYPE) {
2243     return WeakArrayList::SizeForCapacity(
2244         WeakArrayList::unchecked_cast(*this).capacity());
2245   }
2246   if (instance_type == SMALL_ORDERED_HASH_SET_TYPE) {
2247     return SmallOrderedHashSet::SizeFor(
2248         SmallOrderedHashSet::unchecked_cast(*this).Capacity());
2249   }
2250   if (instance_type == SMALL_ORDERED_HASH_MAP_TYPE) {
2251     return SmallOrderedHashMap::SizeFor(
2252         SmallOrderedHashMap::unchecked_cast(*this).Capacity());
2253   }
2254   if (instance_type == SMALL_ORDERED_NAME_DICTIONARY_TYPE) {
2255     return SmallOrderedNameDictionary::SizeFor(
2256         SmallOrderedNameDictionary::unchecked_cast(*this).Capacity());
2257   }
2258   if (instance_type == SWISS_NAME_DICTIONARY_TYPE) {
2259     return SwissNameDictionary::SizeFor(
2260         SwissNameDictionary::unchecked_cast(*this).Capacity());
2261   }
2262   if (instance_type == PROPERTY_ARRAY_TYPE) {
2263     return PropertyArray::SizeFor(
2264         PropertyArray::cast(*this).length(kAcquireLoad));
2265   }
2266   if (instance_type == FEEDBACK_VECTOR_TYPE) {
2267     return FeedbackVector::SizeFor(
2268         FeedbackVector::unchecked_cast(*this).length());
2269   }
2270   if (instance_type == BIGINT_TYPE) {
2271     return BigInt::SizeFor(BigInt::unchecked_cast(*this).length());
2272   }
2273   if (instance_type == PREPARSE_DATA_TYPE) {
2274     PreparseData data = PreparseData::unchecked_cast(*this);
2275     return PreparseData::SizeFor(data.data_length(), data.children_length());
2276   }
2277 #define MAKE_TORQUE_SIZE_FOR(TYPE, TypeName)                \
2278   if (instance_type == TYPE) {                              \
2279     return TypeName::unchecked_cast(*this).AllocatedSize(); \
2280   }
2281   TORQUE_INSTANCE_TYPE_TO_BODY_DESCRIPTOR_LIST(MAKE_TORQUE_SIZE_FOR)
2282 #undef MAKE_TORQUE_SIZE_FOR
2283 
2284   if (instance_type == CODE_TYPE) {
2285     return Code::unchecked_cast(*this).CodeSize();
2286   }
2287   if (instance_type == COVERAGE_INFO_TYPE) {
2288     return CoverageInfo::SizeFor(
2289         CoverageInfo::unchecked_cast(*this).slot_count());
2290   }
2291 #if V8_ENABLE_WEBASSEMBLY
2292   if (instance_type == WASM_STRUCT_TYPE) {
2293     return WasmStruct::GcSafeSize(map);
2294   }
2295   if (instance_type == WASM_ARRAY_TYPE) {
2296     return WasmArray::SizeFor(map, WasmArray::cast(*this).length());
2297   }
2298 #endif  // V8_ENABLE_WEBASSEMBLY
2299   DCHECK_EQ(instance_type, EMBEDDER_DATA_ARRAY_TYPE);
2300   return EmbedderDataArray::SizeFor(
2301       EmbedderDataArray::unchecked_cast(*this).length());
2302 }
2303 
NeedsRehashing() const2304 bool HeapObject::NeedsRehashing() const {
2305   return NeedsRehashing(map().instance_type());
2306 }
2307 
NeedsRehashing(InstanceType instance_type) const2308 bool HeapObject::NeedsRehashing(InstanceType instance_type) const {
2309   DCHECK_EQ(instance_type, map().instance_type());
2310   switch (instance_type) {
2311     case DESCRIPTOR_ARRAY_TYPE:
2312     case STRONG_DESCRIPTOR_ARRAY_TYPE:
2313       return DescriptorArray::cast(*this).number_of_descriptors() > 1;
2314     case TRANSITION_ARRAY_TYPE:
2315       return TransitionArray::cast(*this).number_of_entries() > 1;
2316     case ORDERED_HASH_MAP_TYPE:
2317     case ORDERED_HASH_SET_TYPE:
2318       return false;  // We'll rehash from the JSMap or JSSet referencing them.
2319     case NAME_DICTIONARY_TYPE:
2320     case GLOBAL_DICTIONARY_TYPE:
2321     case NUMBER_DICTIONARY_TYPE:
2322     case SIMPLE_NUMBER_DICTIONARY_TYPE:
2323     case HASH_TABLE_TYPE:
2324     case SMALL_ORDERED_HASH_MAP_TYPE:
2325     case SMALL_ORDERED_HASH_SET_TYPE:
2326     case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
2327     case SWISS_NAME_DICTIONARY_TYPE:
2328     case JS_MAP_TYPE:
2329     case JS_SET_TYPE:
2330       return true;
2331     default:
2332       return false;
2333   }
2334 }
2335 
CanBeRehashed() const2336 bool HeapObject::CanBeRehashed() const {
2337   DCHECK(NeedsRehashing());
2338   switch (map().instance_type()) {
2339     case JS_MAP_TYPE:
2340     case JS_SET_TYPE:
2341       return true;
2342     case ORDERED_HASH_MAP_TYPE:
2343     case ORDERED_HASH_SET_TYPE:
2344       UNREACHABLE();  // We'll rehash from the JSMap or JSSet referencing them.
2345     case ORDERED_NAME_DICTIONARY_TYPE:
2346       return false;
2347     case NAME_DICTIONARY_TYPE:
2348     case GLOBAL_DICTIONARY_TYPE:
2349     case NUMBER_DICTIONARY_TYPE:
2350     case SIMPLE_NUMBER_DICTIONARY_TYPE:
2351     case SWISS_NAME_DICTIONARY_TYPE:
2352       return true;
2353     case DESCRIPTOR_ARRAY_TYPE:
2354     case STRONG_DESCRIPTOR_ARRAY_TYPE:
2355       return true;
2356     case TRANSITION_ARRAY_TYPE:
2357       return true;
2358     case SMALL_ORDERED_HASH_MAP_TYPE:
2359       return SmallOrderedHashMap::cast(*this).NumberOfElements() == 0;
2360     case SMALL_ORDERED_HASH_SET_TYPE:
2361       return SmallOrderedHashMap::cast(*this).NumberOfElements() == 0;
2362     case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
2363       return SmallOrderedNameDictionary::cast(*this).NumberOfElements() == 0;
2364     default:
2365       return false;
2366   }
2367 }
2368 
2369 template <typename IsolateT>
RehashBasedOnMap(IsolateT * isolate)2370 void HeapObject::RehashBasedOnMap(IsolateT* isolate) {
2371   switch (map().instance_type()) {
2372     case HASH_TABLE_TYPE:
2373       UNREACHABLE();
2374     case NAME_DICTIONARY_TYPE:
2375       NameDictionary::cast(*this).Rehash(isolate);
2376       break;
2377     case SWISS_NAME_DICTIONARY_TYPE:
2378       SwissNameDictionary::cast(*this).Rehash(isolate);
2379       break;
2380     case GLOBAL_DICTIONARY_TYPE:
2381       GlobalDictionary::cast(*this).Rehash(isolate);
2382       break;
2383     case NUMBER_DICTIONARY_TYPE:
2384       NumberDictionary::cast(*this).Rehash(isolate);
2385       break;
2386     case SIMPLE_NUMBER_DICTIONARY_TYPE:
2387       SimpleNumberDictionary::cast(*this).Rehash(isolate);
2388       break;
2389     case DESCRIPTOR_ARRAY_TYPE:
2390       DCHECK_LE(1, DescriptorArray::cast(*this).number_of_descriptors());
2391       DescriptorArray::cast(*this).Sort();
2392       break;
2393     case TRANSITION_ARRAY_TYPE:
2394       TransitionArray::cast(*this).Sort();
2395       break;
2396     case SMALL_ORDERED_HASH_MAP_TYPE:
2397       DCHECK_EQ(0, SmallOrderedHashMap::cast(*this).NumberOfElements());
2398       break;
2399     case SMALL_ORDERED_HASH_SET_TYPE:
2400       DCHECK_EQ(0, SmallOrderedHashSet::cast(*this).NumberOfElements());
2401       break;
2402     case ORDERED_HASH_MAP_TYPE:
2403     case ORDERED_HASH_SET_TYPE:
2404       UNREACHABLE();  // We'll rehash from the JSMap or JSSet referencing them.
2405     case JS_MAP_TYPE: {
2406       JSMap::cast(*this).Rehash(isolate->AsIsolate());
2407       break;
2408     }
2409     case JS_SET_TYPE: {
2410       JSSet::cast(*this).Rehash(isolate->AsIsolate());
2411       break;
2412     }
2413     case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
2414       DCHECK_EQ(0, SmallOrderedNameDictionary::cast(*this).NumberOfElements());
2415       break;
2416     case ONE_BYTE_INTERNALIZED_STRING_TYPE:
2417     case INTERNALIZED_STRING_TYPE:
2418       // Rare case, rehash read-only space strings before they are sealed.
2419       DCHECK(ReadOnlyHeap::Contains(*this));
2420       String::cast(*this).EnsureHash();
2421       break;
2422     default:
2423       UNREACHABLE();
2424   }
2425 }
2426 template void HeapObject::RehashBasedOnMap(Isolate* isolate);
2427 template void HeapObject::RehashBasedOnMap(LocalIsolate* isolate);
2428 
IsExternal(Isolate * isolate) const2429 bool HeapObject::IsExternal(Isolate* isolate) const {
2430   return map().FindRootMap(isolate) == isolate->heap()->external_map();
2431 }
2432 
GeneralizeAllFields()2433 void DescriptorArray::GeneralizeAllFields() {
2434   int length = number_of_descriptors();
2435   for (InternalIndex i : InternalIndex::Range(length)) {
2436     PropertyDetails details = GetDetails(i);
2437     details = details.CopyWithRepresentation(Representation::Tagged());
2438     if (details.location() == PropertyLocation::kField) {
2439       DCHECK_EQ(kData, details.kind());
2440       details = details.CopyWithConstness(PropertyConstness::kMutable);
2441       SetValue(i, MaybeObject::FromObject(FieldType::Any()));
2442     }
2443     SetDetails(i, details);
2444   }
2445 }
2446 
SetProperty(Isolate * isolate,Handle<Object> object,Handle<Name> name,Handle<Object> value,StoreOrigin store_origin,Maybe<ShouldThrow> should_throw)2447 MaybeHandle<Object> Object::SetProperty(Isolate* isolate, Handle<Object> object,
2448                                         Handle<Name> name, Handle<Object> value,
2449                                         StoreOrigin store_origin,
2450                                         Maybe<ShouldThrow> should_throw) {
2451   LookupIterator it(isolate, object, name);
2452   MAYBE_RETURN_NULL(SetProperty(&it, value, store_origin, should_throw));
2453   return value;
2454 }
2455 
SetPropertyInternal(LookupIterator * it,Handle<Object> value,Maybe<ShouldThrow> should_throw,StoreOrigin store_origin,bool * found)2456 Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
2457                                         Handle<Object> value,
2458                                         Maybe<ShouldThrow> should_throw,
2459                                         StoreOrigin store_origin, bool* found) {
2460   it->UpdateProtector();
2461   DCHECK(it->IsFound());
2462 
2463   // Make sure that the top context does not change when doing callbacks or
2464   // interceptor calls.
2465   AssertNoContextChange ncc(it->isolate());
2466 
2467   do {
2468     switch (it->state()) {
2469       case LookupIterator::NOT_FOUND:
2470         UNREACHABLE();
2471 
2472       case LookupIterator::ACCESS_CHECK:
2473         if (it->HasAccess()) break;
2474         // Check whether it makes sense to reuse the lookup iterator. Here it
2475         // might still call into setters up the prototype chain.
2476         return JSObject::SetPropertyWithFailedAccessCheck(it, value,
2477                                                           should_throw);
2478 
2479       case LookupIterator::JSPROXY: {
2480         Handle<Object> receiver = it->GetReceiver();
2481         // In case of global IC, the receiver is the global object. Replace by
2482         // the global proxy.
2483         if (receiver->IsJSGlobalObject()) {
2484           receiver = handle(JSGlobalObject::cast(*receiver).global_proxy(),
2485                             it->isolate());
2486         }
2487         return JSProxy::SetProperty(it->GetHolder<JSProxy>(), it->GetName(),
2488                                     value, receiver, should_throw);
2489       }
2490 
2491       case LookupIterator::INTERCEPTOR: {
2492         if (it->HolderIsReceiverOrHiddenPrototype()) {
2493           Maybe<bool> result =
2494               JSObject::SetPropertyWithInterceptor(it, should_throw, value);
2495           if (result.IsNothing() || result.FromJust()) return result;
2496         } else {
2497           Maybe<PropertyAttributes> maybe_attributes =
2498               JSObject::GetPropertyAttributesWithInterceptor(it);
2499           if (maybe_attributes.IsNothing()) return Nothing<bool>();
2500           if ((maybe_attributes.FromJust() & READ_ONLY) != 0) {
2501             return WriteToReadOnlyProperty(it, value, should_throw);
2502           }
2503           // At this point we might have called interceptor's query or getter
2504           // callback. Assuming that the callbacks have side effects, we use
2505           // Object::SetSuperProperty() which works properly regardless on
2506           // whether the property was present on the receiver or not when
2507           // storing to the receiver.
2508           if (maybe_attributes.FromJust() == ABSENT) {
2509             // Proceed lookup from the next state.
2510             it->Next();
2511           } else {
2512             // Finish lookup in order to make Object::SetSuperProperty() store
2513             // property to the receiver.
2514             it->NotFound();
2515           }
2516           return Object::SetSuperProperty(it, value, store_origin,
2517                                           should_throw);
2518         }
2519         break;
2520       }
2521 
2522       case LookupIterator::ACCESSOR: {
2523         if (it->IsReadOnly()) {
2524           return WriteToReadOnlyProperty(it, value, should_throw);
2525         }
2526         Handle<Object> accessors = it->GetAccessors();
2527         if (accessors->IsAccessorInfo() &&
2528             !it->HolderIsReceiverOrHiddenPrototype() &&
2529             AccessorInfo::cast(*accessors).is_special_data_property()) {
2530           *found = false;
2531           return Nothing<bool>();
2532         }
2533         return SetPropertyWithAccessor(it, value, should_throw);
2534       }
2535       case LookupIterator::INTEGER_INDEXED_EXOTIC: {
2536         // IntegerIndexedElementSet converts value to a Number/BigInt prior to
2537         // the bounds check. The bounds check has already happened here, but
2538         // perform the possibly effectful ToNumber (or ToBigInt) operation
2539         // anyways.
2540         auto holder = it->GetHolder<JSTypedArray>();
2541         Handle<Object> throwaway_value;
2542         if (holder->type() == kExternalBigInt64Array ||
2543             holder->type() == kExternalBigUint64Array) {
2544           ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2545               it->isolate(), throwaway_value,
2546               BigInt::FromObject(it->isolate(), value), Nothing<bool>());
2547         } else {
2548           ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2549               it->isolate(), throwaway_value,
2550               Object::ToNumber(it->isolate(), value), Nothing<bool>());
2551         }
2552 
2553         // FIXME: Throw a TypeError if the holder is detached here
2554         // (IntegerIndexedElementSpec step 5).
2555 
2556         // TODO(verwaest): Per spec, we should return false here (steps 6-9
2557         // in IntegerIndexedElementSpec), resulting in an exception being thrown
2558         // on OOB accesses in strict code. Historically, v8 has not done made
2559         // this change due to uncertainty about web compat. (v8:4901)
2560         return Just(true);
2561       }
2562 
2563       case LookupIterator::DATA:
2564         if (it->IsReadOnly()) {
2565           return WriteToReadOnlyProperty(it, value, should_throw);
2566         }
2567         if (it->HolderIsReceiverOrHiddenPrototype()) {
2568           return SetDataProperty(it, value);
2569         }
2570         V8_FALLTHROUGH;
2571       case LookupIterator::TRANSITION:
2572         *found = false;
2573         return Nothing<bool>();
2574     }
2575     it->Next();
2576   } while (it->IsFound());
2577 
2578   *found = false;
2579   return Nothing<bool>();
2580 }
2581 
2582 namespace {
2583 
2584 // If the receiver is the JSGlobalObject, the store was contextual. In case
2585 // the property did not exist yet on the global object itself, we have to
2586 // throw a reference error in strict mode.  In sloppy mode, we continue.
2587 // Returns false if the exception was thrown, otherwise true.
CheckContextualStoreToJSGlobalObject(LookupIterator * it,Maybe<ShouldThrow> should_throw)2588 bool CheckContextualStoreToJSGlobalObject(LookupIterator* it,
2589                                           Maybe<ShouldThrow> should_throw) {
2590   Isolate* isolate = it->isolate();
2591 
2592   if (it->GetReceiver()->IsJSGlobalObject(isolate) &&
2593       (GetShouldThrow(isolate, should_throw) == ShouldThrow::kThrowOnError)) {
2594     if (it->state() == LookupIterator::TRANSITION) {
2595       // The property cell that we have created is garbage because we are going
2596       // to throw now instead of putting it into the global dictionary. However,
2597       // the cell might already have been stored into the feedback vector, so
2598       // we must invalidate it nevertheless.
2599       it->transition_cell()->ClearAndInvalidate(ReadOnlyRoots(isolate));
2600     }
2601     isolate->Throw(*isolate->factory()->NewReferenceError(
2602         MessageTemplate::kNotDefined, it->GetName()));
2603     return false;
2604   }
2605   return true;
2606 }
2607 
2608 }  // namespace
2609 
SetProperty(LookupIterator * it,Handle<Object> value,StoreOrigin store_origin,Maybe<ShouldThrow> should_throw)2610 Maybe<bool> Object::SetProperty(LookupIterator* it, Handle<Object> value,
2611                                 StoreOrigin store_origin,
2612                                 Maybe<ShouldThrow> should_throw) {
2613   if (it->IsFound()) {
2614     bool found = true;
2615     Maybe<bool> result =
2616         SetPropertyInternal(it, value, should_throw, store_origin, &found);
2617     if (found) return result;
2618   }
2619 
2620   if (!CheckContextualStoreToJSGlobalObject(it, should_throw)) {
2621     return Nothing<bool>();
2622   }
2623   return AddDataProperty(it, value, NONE, should_throw, store_origin);
2624 }
2625 
SetSuperProperty(LookupIterator * it,Handle<Object> value,StoreOrigin store_origin,Maybe<ShouldThrow> should_throw)2626 Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
2627                                      StoreOrigin store_origin,
2628                                      Maybe<ShouldThrow> should_throw) {
2629   Isolate* isolate = it->isolate();
2630 
2631   if (it->IsFound()) {
2632     bool found = true;
2633     Maybe<bool> result =
2634         SetPropertyInternal(it, value, should_throw, store_origin, &found);
2635     if (found) return result;
2636   }
2637 
2638   it->UpdateProtector();
2639 
2640   // The property either doesn't exist on the holder or exists there as a data
2641   // property.
2642 
2643   if (!it->GetReceiver()->IsJSReceiver()) {
2644     return WriteToReadOnlyProperty(it, value, should_throw);
2645   }
2646   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
2647 
2648   // Note, the callers rely on the fact that this code is redoing the full own
2649   // lookup from scratch.
2650   LookupIterator::Configuration c = LookupIterator::OWN;
2651   LookupIterator own_lookup =
2652       it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c)
2653                       : LookupIterator(isolate, receiver, it->name(), c);
2654 
2655   for (; own_lookup.IsFound(); own_lookup.Next()) {
2656     switch (own_lookup.state()) {
2657       case LookupIterator::ACCESS_CHECK:
2658         if (!own_lookup.HasAccess()) {
2659           return JSObject::SetPropertyWithFailedAccessCheck(&own_lookup, value,
2660                                                             should_throw);
2661         }
2662         break;
2663 
2664       case LookupIterator::ACCESSOR:
2665         if (own_lookup.GetAccessors()->IsAccessorInfo()) {
2666           if (own_lookup.IsReadOnly()) {
2667             return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
2668           }
2669           return Object::SetPropertyWithAccessor(&own_lookup, value,
2670                                                  should_throw);
2671         }
2672         V8_FALLTHROUGH;
2673       case LookupIterator::INTEGER_INDEXED_EXOTIC:
2674         return RedefineIncompatibleProperty(isolate, it->GetName(), value,
2675                                             should_throw);
2676 
2677       case LookupIterator::DATA: {
2678         if (own_lookup.IsReadOnly()) {
2679           return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
2680         }
2681         return SetDataProperty(&own_lookup, value);
2682       }
2683 
2684       case LookupIterator::INTERCEPTOR:
2685       case LookupIterator::JSPROXY: {
2686         PropertyDescriptor desc;
2687         Maybe<bool> owned =
2688             JSReceiver::GetOwnPropertyDescriptor(&own_lookup, &desc);
2689         MAYBE_RETURN(owned, Nothing<bool>());
2690         if (!owned.FromJust()) {
2691           return JSReceiver::CreateDataProperty(&own_lookup, value,
2692                                                 should_throw);
2693         }
2694         if (PropertyDescriptor::IsAccessorDescriptor(&desc) ||
2695             !desc.writable()) {
2696           return RedefineIncompatibleProperty(isolate, it->GetName(), value,
2697                                               should_throw);
2698         }
2699 
2700         PropertyDescriptor value_desc;
2701         value_desc.set_value(value);
2702         return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
2703                                              &value_desc, should_throw);
2704       }
2705 
2706       case LookupIterator::NOT_FOUND:
2707       case LookupIterator::TRANSITION:
2708         UNREACHABLE();
2709     }
2710   }
2711 
2712   if (!CheckContextualStoreToJSGlobalObject(&own_lookup, should_throw)) {
2713     return Nothing<bool>();
2714   }
2715   return AddDataProperty(&own_lookup, value, NONE, should_throw, store_origin);
2716 }
2717 
CannotCreateProperty(Isolate * isolate,Handle<Object> receiver,Handle<Object> name,Handle<Object> value,Maybe<ShouldThrow> should_throw)2718 Maybe<bool> Object::CannotCreateProperty(Isolate* isolate,
2719                                          Handle<Object> receiver,
2720                                          Handle<Object> name,
2721                                          Handle<Object> value,
2722                                          Maybe<ShouldThrow> should_throw) {
2723   RETURN_FAILURE(
2724       isolate, GetShouldThrow(isolate, should_throw),
2725       NewTypeError(MessageTemplate::kStrictCannotCreateProperty, name,
2726                    Object::TypeOf(isolate, receiver), receiver));
2727 }
2728 
WriteToReadOnlyProperty(LookupIterator * it,Handle<Object> value,Maybe<ShouldThrow> maybe_should_throw)2729 Maybe<bool> Object::WriteToReadOnlyProperty(
2730     LookupIterator* it, Handle<Object> value,
2731     Maybe<ShouldThrow> maybe_should_throw) {
2732   ShouldThrow should_throw = GetShouldThrow(it->isolate(), maybe_should_throw);
2733   if (it->IsFound() && !it->HolderIsReceiver()) {
2734     // "Override mistake" attempted, record a use count to track this per
2735     // v8:8175
2736     v8::Isolate::UseCounterFeature feature =
2737         should_throw == kThrowOnError
2738             ? v8::Isolate::kAttemptOverrideReadOnlyOnPrototypeStrict
2739             : v8::Isolate::kAttemptOverrideReadOnlyOnPrototypeSloppy;
2740     it->isolate()->CountUsage(feature);
2741   }
2742   return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(),
2743                                  it->GetName(), value, should_throw);
2744 }
2745 
WriteToReadOnlyProperty(Isolate * isolate,Handle<Object> receiver,Handle<Object> name,Handle<Object> value,ShouldThrow should_throw)2746 Maybe<bool> Object::WriteToReadOnlyProperty(Isolate* isolate,
2747                                             Handle<Object> receiver,
2748                                             Handle<Object> name,
2749                                             Handle<Object> value,
2750                                             ShouldThrow should_throw) {
2751   RETURN_FAILURE(isolate, should_throw,
2752                  NewTypeError(MessageTemplate::kStrictReadOnlyProperty, name,
2753                               Object::TypeOf(isolate, receiver), receiver));
2754 }
2755 
RedefineIncompatibleProperty(Isolate * isolate,Handle<Object> name,Handle<Object> value,Maybe<ShouldThrow> should_throw)2756 Maybe<bool> Object::RedefineIncompatibleProperty(
2757     Isolate* isolate, Handle<Object> name, Handle<Object> value,
2758     Maybe<ShouldThrow> should_throw) {
2759   RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw),
2760                  NewTypeError(MessageTemplate::kRedefineDisallowed, name));
2761 }
2762 
SetDataProperty(LookupIterator * it,Handle<Object> value)2763 Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) {
2764   Isolate* isolate = it->isolate();
2765   DCHECK_IMPLIES(it->GetReceiver()->IsJSProxy(isolate),
2766                  it->GetName()->IsPrivateName(isolate));
2767   DCHECK_IMPLIES(!it->IsElement() && it->GetName()->IsPrivateName(isolate),
2768                  it->state() == LookupIterator::DATA);
2769   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
2770 
2771   // Store on the holder which may be hidden behind the receiver.
2772   DCHECK(it->HolderIsReceiverOrHiddenPrototype());
2773 
2774   Handle<Object> to_assign = value;
2775   // Convert the incoming value to a number for storing into typed arrays.
2776   if (it->IsElement() && receiver->IsJSObject(isolate) &&
2777       JSObject::cast(*receiver).HasTypedArrayOrRabGsabTypedArrayElements(
2778           isolate)) {
2779     ElementsKind elements_kind = JSObject::cast(*receiver).GetElementsKind();
2780     if (IsBigIntTypedArrayElementsKind(elements_kind)) {
2781       ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, to_assign,
2782                                        BigInt::FromObject(isolate, value),
2783                                        Nothing<bool>());
2784       // We have to recheck the length. However, it can only change if the
2785       // underlying buffer was detached, so just check that.
2786       if (Handle<JSArrayBufferView>::cast(receiver)->WasDetached()) {
2787         return Just(true);
2788         // TODO(neis): According to the spec, this should throw a TypeError.
2789       }
2790     } else if (!value->IsNumber() && !value->IsUndefined(isolate)) {
2791       ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, to_assign,
2792                                        Object::ToNumber(isolate, value),
2793                                        Nothing<bool>());
2794       // We have to recheck the length. However, it can only change if the
2795       // underlying buffer was detached, so just check that.
2796       if (Handle<JSArrayBufferView>::cast(receiver)->WasDetached()) {
2797         return Just(true);
2798         // TODO(neis): According to the spec, this should throw a TypeError.
2799       }
2800     }
2801   }
2802 
2803 #if V8_ENABLE_WEBASSEMBLY
2804   if (receiver->IsWasmObject(isolate)) {
2805     // Prepares given value for being stored into a field of given Wasm type
2806     // or throw if the value can't be stored into the field.
2807     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2808         isolate, to_assign,
2809         WasmObject::ToWasmValue(isolate, it->wasm_value_type(), to_assign),
2810         Nothing<bool>());
2811 
2812     // Store prepared value.
2813     it->WriteDataValueToWasmObject(to_assign);
2814 
2815   } else  // NOLINT(readability/braces)
2816 #endif    // V8_ENABLE_WEBASSEMBLY
2817   {
2818     // Possibly migrate to the most up-to-date map that will be able to store
2819     // |value| under it->name().
2820     it->PrepareForDataProperty(to_assign);
2821 
2822     // Write the property value.
2823     it->WriteDataValue(to_assign, false);
2824   }
2825 
2826 #if VERIFY_HEAP
2827   if (FLAG_verify_heap) {
2828     receiver->HeapObjectVerify(isolate);
2829   }
2830 #endif
2831   return Just(true);
2832 }
2833 
AddDataProperty(LookupIterator * it,Handle<Object> value,PropertyAttributes attributes,Maybe<ShouldThrow> should_throw,StoreOrigin store_origin)2834 Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value,
2835                                     PropertyAttributes attributes,
2836                                     Maybe<ShouldThrow> should_throw,
2837                                     StoreOrigin store_origin) {
2838   if (!it->GetReceiver()->IsJSReceiver()) {
2839     return CannotCreateProperty(it->isolate(), it->GetReceiver(), it->GetName(),
2840                                 value, should_throw);
2841   }
2842 
2843   // Private symbols should be installed on JSProxy using
2844   // JSProxy::SetPrivateSymbol.
2845   if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate() &&
2846       !it->GetName()->IsPrivateName()) {
2847     RETURN_FAILURE(it->isolate(), GetShouldThrow(it->isolate(), should_throw),
2848                    NewTypeError(MessageTemplate::kProxyPrivate));
2849   }
2850 
2851   DCHECK_NE(LookupIterator::INTEGER_INDEXED_EXOTIC, it->state());
2852 
2853   Handle<JSReceiver> receiver = it->GetStoreTarget<JSReceiver>();
2854   DCHECK_IMPLIES(receiver->IsJSProxy(), it->GetName()->IsPrivateName());
2855   DCHECK_IMPLIES(receiver->IsJSProxy(),
2856                  it->state() == LookupIterator::NOT_FOUND);
2857 
2858   // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject)
2859   // instead. If the prototype is Null, the proxy is detached.
2860   if (receiver->IsJSGlobalProxy()) return Just(true);
2861 
2862   Isolate* isolate = it->isolate();
2863 
2864   if (it->ExtendingNonExtensible(receiver)) {
2865     RETURN_FAILURE(
2866         isolate, GetShouldThrow(it->isolate(), should_throw),
2867         NewTypeError(MessageTemplate::kObjectNotExtensible, it->GetName()));
2868   }
2869 
2870   if (it->IsElement(*receiver)) {
2871     if (receiver->IsJSArray()) {
2872       Handle<JSArray> array = Handle<JSArray>::cast(receiver);
2873       if (JSArray::WouldChangeReadOnlyLength(array, it->array_index())) {
2874         RETURN_FAILURE(isolate, GetShouldThrow(it->isolate(), should_throw),
2875                        NewTypeError(MessageTemplate::kStrictReadOnlyProperty,
2876                                     isolate->factory()->length_string(),
2877                                     Object::TypeOf(isolate, array), array));
2878       }
2879     }
2880 
2881     Handle<JSObject> receiver_obj = Handle<JSObject>::cast(receiver);
2882     MAYBE_RETURN(JSObject::AddDataElement(receiver_obj, it->array_index(),
2883                                           value, attributes),
2884                  Nothing<bool>());
2885     JSObject::ValidateElements(*receiver_obj);
2886     return Just(true);
2887   } else {
2888     it->UpdateProtector();
2889     // Migrate to the most up-to-date map that will be able to store |value|
2890     // under it->name() with |attributes|.
2891     it->PrepareTransitionToDataProperty(receiver, value, attributes,
2892                                         store_origin);
2893     DCHECK_EQ(LookupIterator::TRANSITION, it->state());
2894     it->ApplyTransitionToDataProperty(receiver);
2895 
2896     // Write the property value.
2897     it->WriteDataValue(value, true);
2898 
2899 #if VERIFY_HEAP
2900     if (FLAG_verify_heap) {
2901       receiver->HeapObjectVerify(isolate);
2902     }
2903 #endif
2904   }
2905 
2906   return Just(true);
2907 }
2908 
2909 template <class T>
AppendUniqueCallbacks(Isolate * isolate,Handle<TemplateList> callbacks,Handle<typename T::Array> array,int valid_descriptors)2910 static int AppendUniqueCallbacks(Isolate* isolate,
2911                                  Handle<TemplateList> callbacks,
2912                                  Handle<typename T::Array> array,
2913                                  int valid_descriptors) {
2914   int nof_callbacks = callbacks->length();
2915 
2916   // Fill in new callback descriptors.  Process the callbacks from
2917   // back to front so that the last callback with a given name takes
2918   // precedence over previously added callbacks with that name.
2919   for (int i = nof_callbacks - 1; i >= 0; i--) {
2920     Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)), isolate);
2921     Handle<Name> key(Name::cast(entry->name()), isolate);
2922     DCHECK(key->IsUniqueName());
2923     // Check if a descriptor with this name already exists before writing.
2924     if (!T::Contains(key, entry, valid_descriptors, array)) {
2925       T::Insert(key, entry, valid_descriptors, array);
2926       valid_descriptors++;
2927     }
2928   }
2929 
2930   return valid_descriptors;
2931 }
2932 
2933 struct FixedArrayAppender {
2934   using Array = FixedArray;
Containsv8::internal::FixedArrayAppender2935   static bool Contains(Handle<Name> key, Handle<AccessorInfo> entry,
2936                        int valid_descriptors, Handle<FixedArray> array) {
2937     for (int i = 0; i < valid_descriptors; i++) {
2938       if (*key == AccessorInfo::cast(array->get(i)).name()) return true;
2939     }
2940     return false;
2941   }
Insertv8::internal::FixedArrayAppender2942   static void Insert(Handle<Name> key, Handle<AccessorInfo> entry,
2943                      int valid_descriptors, Handle<FixedArray> array) {
2944     DisallowGarbageCollection no_gc;
2945     array->set(valid_descriptors, *entry);
2946   }
2947 };
2948 
AppendUnique(Isolate * isolate,Handle<Object> descriptors,Handle<FixedArray> array,int valid_descriptors)2949 int AccessorInfo::AppendUnique(Isolate* isolate, Handle<Object> descriptors,
2950                                Handle<FixedArray> array,
2951                                int valid_descriptors) {
2952   Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors);
2953   DCHECK_GE(array->length(), callbacks->length() + valid_descriptors);
2954   return AppendUniqueCallbacks<FixedArrayAppender>(isolate, callbacks, array,
2955                                                    valid_descriptors);
2956 }
2957 
Revoke(Handle<JSProxy> proxy)2958 void JSProxy::Revoke(Handle<JSProxy> proxy) {
2959   Isolate* isolate = proxy->GetIsolate();
2960   // ES#sec-proxy-revocation-functions
2961   if (!proxy->IsRevoked()) {
2962     // 5. Set p.[[ProxyTarget]] to null.
2963     proxy->set_target(ReadOnlyRoots(isolate).null_value());
2964     // 6. Set p.[[ProxyHandler]] to null.
2965     proxy->set_handler(ReadOnlyRoots(isolate).null_value());
2966   }
2967   DCHECK(proxy->IsRevoked());
2968 }
2969 
2970 // static
IsArray(Handle<JSProxy> proxy)2971 Maybe<bool> JSProxy::IsArray(Handle<JSProxy> proxy) {
2972   Isolate* isolate = proxy->GetIsolate();
2973   Handle<JSReceiver> object = Handle<JSReceiver>::cast(proxy);
2974   for (int i = 0; i < JSProxy::kMaxIterationLimit; i++) {
2975     Handle<JSProxy> proxy = Handle<JSProxy>::cast(object);
2976     if (proxy->IsRevoked()) {
2977       isolate->Throw(*isolate->factory()->NewTypeError(
2978           MessageTemplate::kProxyRevoked,
2979           isolate->factory()->NewStringFromAsciiChecked("IsArray")));
2980       return Nothing<bool>();
2981     }
2982     object = handle(JSReceiver::cast(proxy->target()), isolate);
2983     if (object->IsJSArray()) return Just(true);
2984     if (!object->IsJSProxy()) return Just(false);
2985   }
2986 
2987   // Too deep recursion, throw a RangeError.
2988   isolate->StackOverflow();
2989   return Nothing<bool>();
2990 }
2991 
HasProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Name> name)2992 Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy,
2993                                  Handle<Name> name) {
2994   DCHECK(!name->IsPrivate());
2995   STACK_CHECK(isolate, Nothing<bool>());
2996   // 1. (Assert)
2997   // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
2998   Handle<Object> handler(proxy->handler(), isolate);
2999   // 3. If handler is null, throw a TypeError exception.
3000   // 4. Assert: Type(handler) is Object.
3001   if (proxy->IsRevoked()) {
3002     isolate->Throw(*isolate->factory()->NewTypeError(
3003         MessageTemplate::kProxyRevoked, isolate->factory()->has_string()));
3004     return Nothing<bool>();
3005   }
3006   // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
3007   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
3008   // 6. Let trap be ? GetMethod(handler, "has").
3009   Handle<Object> trap;
3010   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3011       isolate, trap,
3012       Object::GetMethod(Handle<JSReceiver>::cast(handler),
3013                         isolate->factory()->has_string()),
3014       Nothing<bool>());
3015   // 7. If trap is undefined, then
3016   if (trap->IsUndefined(isolate)) {
3017     // 7a. Return target.[[HasProperty]](P).
3018     return JSReceiver::HasProperty(target, name);
3019   }
3020   // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, P»)).
3021   Handle<Object> trap_result_obj;
3022   Handle<Object> args[] = {target, name};
3023   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3024       isolate, trap_result_obj,
3025       Execution::Call(isolate, trap, handler, arraysize(args), args),
3026       Nothing<bool>());
3027   bool boolean_trap_result = trap_result_obj->BooleanValue(isolate);
3028   // 9. If booleanTrapResult is false, then:
3029   if (!boolean_trap_result) {
3030     MAYBE_RETURN(JSProxy::CheckHasTrap(isolate, name, target), Nothing<bool>());
3031   }
3032   // 10. Return booleanTrapResult.
3033   return Just(boolean_trap_result);
3034 }
3035 
CheckHasTrap(Isolate * isolate,Handle<Name> name,Handle<JSReceiver> target)3036 Maybe<bool> JSProxy::CheckHasTrap(Isolate* isolate, Handle<Name> name,
3037                                   Handle<JSReceiver> target) {
3038   // 9a. Let targetDesc be ? target.[[GetOwnProperty]](P).
3039   PropertyDescriptor target_desc;
3040   Maybe<bool> target_found =
3041       JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
3042   MAYBE_RETURN(target_found, Nothing<bool>());
3043   // 9b. If targetDesc is not undefined, then:
3044   if (target_found.FromJust()) {
3045     // 9b i. If targetDesc.[[Configurable]] is false, throw a TypeError
3046     //       exception.
3047     if (!target_desc.configurable()) {
3048       isolate->Throw(*isolate->factory()->NewTypeError(
3049           MessageTemplate::kProxyHasNonConfigurable, name));
3050       return Nothing<bool>();
3051     }
3052     // 9b ii. Let extensibleTarget be ? IsExtensible(target).
3053     Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
3054     MAYBE_RETURN(extensible_target, Nothing<bool>());
3055     // 9b iii. If extensibleTarget is false, throw a TypeError exception.
3056     if (!extensible_target.FromJust()) {
3057       isolate->Throw(*isolate->factory()->NewTypeError(
3058           MessageTemplate::kProxyHasNonExtensible, name));
3059       return Nothing<bool>();
3060     }
3061   }
3062   return Just(true);
3063 }
3064 
SetProperty(Handle<JSProxy> proxy,Handle<Name> name,Handle<Object> value,Handle<Object> receiver,Maybe<ShouldThrow> should_throw)3065 Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name,
3066                                  Handle<Object> value, Handle<Object> receiver,
3067                                  Maybe<ShouldThrow> should_throw) {
3068   DCHECK(!name->IsPrivate());
3069   Isolate* isolate = proxy->GetIsolate();
3070   STACK_CHECK(isolate, Nothing<bool>());
3071   Factory* factory = isolate->factory();
3072   Handle<String> trap_name = factory->set_string();
3073 
3074   if (proxy->IsRevoked()) {
3075     isolate->Throw(
3076         *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
3077     return Nothing<bool>();
3078   }
3079   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
3080   Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
3081 
3082   Handle<Object> trap;
3083   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3084       isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
3085   if (trap->IsUndefined(isolate)) {
3086     PropertyKey key(isolate, name);
3087     LookupIterator it(isolate, receiver, key, target);
3088 
3089     return Object::SetSuperProperty(&it, value, StoreOrigin::kMaybeKeyed,
3090                                     should_throw);
3091   }
3092 
3093   Handle<Object> trap_result;
3094   Handle<Object> args[] = {target, name, value, receiver};
3095   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3096       isolate, trap_result,
3097       Execution::Call(isolate, trap, handler, arraysize(args), args),
3098       Nothing<bool>());
3099   if (!trap_result->BooleanValue(isolate)) {
3100     RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw),
3101                    NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
3102                                 trap_name, name));
3103   }
3104 
3105   MaybeHandle<Object> result =
3106       JSProxy::CheckGetSetTrapResult(isolate, name, target, value, kSet);
3107 
3108   if (result.is_null()) {
3109     return Nothing<bool>();
3110   }
3111   return Just(true);
3112 }
3113 
DeletePropertyOrElement(Handle<JSProxy> proxy,Handle<Name> name,LanguageMode language_mode)3114 Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy,
3115                                              Handle<Name> name,
3116                                              LanguageMode language_mode) {
3117   DCHECK(!name->IsPrivate());
3118   ShouldThrow should_throw =
3119       is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
3120   Isolate* isolate = proxy->GetIsolate();
3121   STACK_CHECK(isolate, Nothing<bool>());
3122   Factory* factory = isolate->factory();
3123   Handle<String> trap_name = factory->deleteProperty_string();
3124 
3125   if (proxy->IsRevoked()) {
3126     isolate->Throw(
3127         *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
3128     return Nothing<bool>();
3129   }
3130   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
3131   Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
3132 
3133   Handle<Object> trap;
3134   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3135       isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
3136   if (trap->IsUndefined(isolate)) {
3137     return JSReceiver::DeletePropertyOrElement(target, name, language_mode);
3138   }
3139 
3140   Handle<Object> trap_result;
3141   Handle<Object> args[] = {target, name};
3142   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3143       isolate, trap_result,
3144       Execution::Call(isolate, trap, handler, arraysize(args), args),
3145       Nothing<bool>());
3146   if (!trap_result->BooleanValue(isolate)) {
3147     RETURN_FAILURE(isolate, should_throw,
3148                    NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
3149                                 trap_name, name));
3150   }
3151 
3152   // Enforce the invariant.
3153   return JSProxy::CheckDeleteTrap(isolate, name, target);
3154 }
3155 
CheckDeleteTrap(Isolate * isolate,Handle<Name> name,Handle<JSReceiver> target)3156 Maybe<bool> JSProxy::CheckDeleteTrap(Isolate* isolate, Handle<Name> name,
3157                                      Handle<JSReceiver> target) {
3158   // 10. Let targetDesc be ? target.[[GetOwnProperty]](P).
3159   PropertyDescriptor target_desc;
3160   Maybe<bool> target_found =
3161       JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
3162   MAYBE_RETURN(target_found, Nothing<bool>());
3163   // 11. If targetDesc is undefined, return true.
3164   if (target_found.FromJust()) {
3165     // 12. If targetDesc.[[Configurable]] is false, throw a TypeError exception.
3166     if (!target_desc.configurable()) {
3167       isolate->Throw(*isolate->factory()->NewTypeError(
3168           MessageTemplate::kProxyDeletePropertyNonConfigurable, name));
3169       return Nothing<bool>();
3170     }
3171     // 13. Let extensibleTarget be ? IsExtensible(target).
3172     Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
3173     MAYBE_RETURN(extensible_target, Nothing<bool>());
3174     // 14. If extensibleTarget is false, throw a TypeError exception.
3175     if (!extensible_target.FromJust()) {
3176       isolate->Throw(*isolate->factory()->NewTypeError(
3177           MessageTemplate::kProxyDeletePropertyNonExtensible, name));
3178       return Nothing<bool>();
3179     }
3180   }
3181   return Just(true);
3182 }
3183 
3184 // static
New(Isolate * isolate,Handle<Object> target,Handle<Object> handler)3185 MaybeHandle<JSProxy> JSProxy::New(Isolate* isolate, Handle<Object> target,
3186                                   Handle<Object> handler) {
3187   if (!target->IsJSReceiver()) {
3188     THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
3189                     JSProxy);
3190   }
3191   if (!handler->IsJSReceiver()) {
3192     THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
3193                     JSProxy);
3194   }
3195   return isolate->factory()->NewJSProxy(Handle<JSReceiver>::cast(target),
3196                                         Handle<JSReceiver>::cast(handler));
3197 }
3198 
GetPropertyAttributes(LookupIterator * it)3199 Maybe<PropertyAttributes> JSProxy::GetPropertyAttributes(LookupIterator* it) {
3200   PropertyDescriptor desc;
3201   Maybe<bool> found = JSProxy::GetOwnPropertyDescriptor(
3202       it->isolate(), it->GetHolder<JSProxy>(), it->GetName(), &desc);
3203   MAYBE_RETURN(found, Nothing<PropertyAttributes>());
3204   if (!found.FromJust()) return Just(ABSENT);
3205   return Just(desc.ToAttributes());
3206 }
3207 
3208 // TODO(jkummerow): Consider unification with FastAsArrayLength() in
3209 // accessors.cc.
PropertyKeyToArrayLength(Handle<Object> value,uint32_t * length)3210 bool PropertyKeyToArrayLength(Handle<Object> value, uint32_t* length) {
3211   DCHECK(value->IsNumber() || value->IsName());
3212   if (value->ToArrayLength(length)) return true;
3213   if (value->IsString()) return String::cast(*value).AsArrayIndex(length);
3214   return false;
3215 }
3216 
PropertyKeyToArrayIndex(Handle<Object> index_obj,uint32_t * output)3217 bool PropertyKeyToArrayIndex(Handle<Object> index_obj, uint32_t* output) {
3218   return PropertyKeyToArrayLength(index_obj, output) && *output != kMaxUInt32;
3219 }
3220 
3221 // ES6 9.4.2.1
3222 // static
DefineOwnProperty(Isolate * isolate,Handle<JSArray> o,Handle<Object> name,PropertyDescriptor * desc,Maybe<ShouldThrow> should_throw)3223 Maybe<bool> JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o,
3224                                        Handle<Object> name,
3225                                        PropertyDescriptor* desc,
3226                                        Maybe<ShouldThrow> should_throw) {
3227   // 1. Assert: IsPropertyKey(P) is true. ("P" is |name|.)
3228   // 2. If P is "length", then:
3229   // TODO(jkummerow): Check if we need slow string comparison.
3230   if (*name == ReadOnlyRoots(isolate).length_string()) {
3231     // 2a. Return ArraySetLength(A, Desc).
3232     return ArraySetLength(isolate, o, desc, should_throw);
3233   }
3234   // 3. Else if P is an array index, then:
3235   uint32_t index = 0;
3236   if (PropertyKeyToArrayIndex(name, &index)) {
3237     // 3a. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
3238     PropertyDescriptor old_len_desc;
3239     Maybe<bool> success = GetOwnPropertyDescriptor(
3240         isolate, o, isolate->factory()->length_string(), &old_len_desc);
3241     // 3b. (Assert)
3242     DCHECK(success.FromJust());
3243     USE(success);
3244     // 3c. Let oldLen be oldLenDesc.[[Value]].
3245     uint32_t old_len = 0;
3246     CHECK(old_len_desc.value()->ToArrayLength(&old_len));
3247     // 3d. Let index be ToUint32(P).
3248     // (Already done above.)
3249     // 3e. (Assert)
3250     // 3f. If index >= oldLen and oldLenDesc.[[Writable]] is false,
3251     //     return false.
3252     if (index >= old_len && old_len_desc.has_writable() &&
3253         !old_len_desc.writable()) {
3254       RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw),
3255                      NewTypeError(MessageTemplate::kDefineDisallowed, name));
3256     }
3257     // 3g. Let succeeded be OrdinaryDefineOwnProperty(A, P, Desc).
3258     Maybe<bool> succeeded =
3259         OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
3260     // 3h. Assert: succeeded is not an abrupt completion.
3261     //     In our case, if should_throw == kThrowOnError, it can be!
3262     // 3i. If succeeded is false, return false.
3263     if (succeeded.IsNothing() || !succeeded.FromJust()) return succeeded;
3264     // 3j. If index >= oldLen, then:
3265     if (index >= old_len) {
3266       // 3j i. Set oldLenDesc.[[Value]] to index + 1.
3267       old_len_desc.set_value(isolate->factory()->NewNumberFromUint(index + 1));
3268       // 3j ii. Let succeeded be
3269       //        OrdinaryDefineOwnProperty(A, "length", oldLenDesc).
3270       succeeded = OrdinaryDefineOwnProperty(isolate, o,
3271                                             isolate->factory()->length_string(),
3272                                             &old_len_desc, should_throw);
3273       // 3j iii. Assert: succeeded is true.
3274       DCHECK(succeeded.FromJust());
3275       USE(succeeded);
3276     }
3277     // 3k. Return true.
3278     return Just(true);
3279   }
3280 
3281   // 4. Return OrdinaryDefineOwnProperty(A, P, Desc).
3282   return OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
3283 }
3284 
3285 // Part of ES6 9.4.2.4 ArraySetLength.
3286 // static
AnythingToArrayLength(Isolate * isolate,Handle<Object> length_object,uint32_t * output)3287 bool JSArray::AnythingToArrayLength(Isolate* isolate,
3288                                     Handle<Object> length_object,
3289                                     uint32_t* output) {
3290   // Fast path: check numbers and strings that can be converted directly
3291   // and unobservably.
3292   if (length_object->ToArrayLength(output)) return true;
3293   if (length_object->IsString() &&
3294       Handle<String>::cast(length_object)->AsArrayIndex(output)) {
3295     return true;
3296   }
3297   // Slow path: follow steps in ES6 9.4.2.4 "ArraySetLength".
3298   // 3. Let newLen be ToUint32(Desc.[[Value]]).
3299   Handle<Object> uint32_v;
3300   if (!Object::ToUint32(isolate, length_object).ToHandle(&uint32_v)) {
3301     // 4. ReturnIfAbrupt(newLen).
3302     return false;
3303   }
3304   // 5. Let numberLen be ToNumber(Desc.[[Value]]).
3305   Handle<Object> number_v;
3306   if (!Object::ToNumber(isolate, length_object).ToHandle(&number_v)) {
3307     // 6. ReturnIfAbrupt(newLen).
3308     return false;
3309   }
3310   // 7. If newLen != numberLen, throw a RangeError exception.
3311   if (uint32_v->Number() != number_v->Number()) {
3312     Handle<Object> exception =
3313         isolate->factory()->NewRangeError(MessageTemplate::kInvalidArrayLength);
3314     isolate->Throw(*exception);
3315     return false;
3316   }
3317   CHECK(uint32_v->ToArrayLength(output));
3318   return true;
3319 }
3320 
3321 // ES6 9.4.2.4
3322 // static
ArraySetLength(Isolate * isolate,Handle<JSArray> a,PropertyDescriptor * desc,Maybe<ShouldThrow> should_throw)3323 Maybe<bool> JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a,
3324                                     PropertyDescriptor* desc,
3325                                     Maybe<ShouldThrow> should_throw) {
3326   // 1. If the [[Value]] field of Desc is absent, then
3327   if (!desc->has_value()) {
3328     // 1a. Return OrdinaryDefineOwnProperty(A, "length", Desc).
3329     return OrdinaryDefineOwnProperty(
3330         isolate, a, isolate->factory()->length_string(), desc, should_throw);
3331   }
3332   // 2. Let newLenDesc be a copy of Desc.
3333   // (Actual copying is not necessary.)
3334   PropertyDescriptor* new_len_desc = desc;
3335   // 3. - 7. Convert Desc.[[Value]] to newLen.
3336   uint32_t new_len = 0;
3337   if (!AnythingToArrayLength(isolate, desc->value(), &new_len)) {
3338     DCHECK(isolate->has_pending_exception());
3339     return Nothing<bool>();
3340   }
3341   // 8. Set newLenDesc.[[Value]] to newLen.
3342   // (Done below, if needed.)
3343   // 9. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
3344   PropertyDescriptor old_len_desc;
3345   Maybe<bool> success = GetOwnPropertyDescriptor(
3346       isolate, a, isolate->factory()->length_string(), &old_len_desc);
3347   // 10. (Assert)
3348   DCHECK(success.FromJust());
3349   USE(success);
3350   // 11. Let oldLen be oldLenDesc.[[Value]].
3351   uint32_t old_len = 0;
3352   CHECK(old_len_desc.value()->ToArrayLength(&old_len));
3353   // 12. If newLen >= oldLen, then
3354   if (new_len >= old_len) {
3355     // 8. Set newLenDesc.[[Value]] to newLen.
3356     // 12a. Return OrdinaryDefineOwnProperty(A, "length", newLenDesc).
3357     new_len_desc->set_value(isolate->factory()->NewNumberFromUint(new_len));
3358     return OrdinaryDefineOwnProperty(isolate, a,
3359                                      isolate->factory()->length_string(),
3360                                      new_len_desc, should_throw);
3361   }
3362   // 13. If oldLenDesc.[[Writable]] is false, return false.
3363   if (!old_len_desc.writable() ||
3364       // Also handle the {configurable: true} and enumerable changes
3365       // since we later use JSArray::SetLength instead of
3366       // OrdinaryDefineOwnProperty to change the length,
3367       // and it doesn't have access to the descriptor anymore.
3368       new_len_desc->configurable() ||
3369       (new_len_desc->has_enumerable() &&
3370        (old_len_desc.enumerable() != new_len_desc->enumerable()))) {
3371     RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw),
3372                    NewTypeError(MessageTemplate::kRedefineDisallowed,
3373                                 isolate->factory()->length_string()));
3374   }
3375   // 14. If newLenDesc.[[Writable]] is absent or has the value true,
3376   // let newWritable be true.
3377   bool new_writable = false;
3378   if (!new_len_desc->has_writable() || new_len_desc->writable()) {
3379     new_writable = true;
3380   } else {
3381     // 15. Else,
3382     // 15a. Need to defer setting the [[Writable]] attribute to false in case
3383     //      any elements cannot be deleted.
3384     // 15b. Let newWritable be false. (It's initialized as "false" anyway.)
3385     // 15c. Set newLenDesc.[[Writable]] to true.
3386     // (Not needed.)
3387   }
3388   // Most of steps 16 through 19 is implemented by JSArray::SetLength.
3389   MAYBE_RETURN(JSArray::SetLength(a, new_len), Nothing<bool>());
3390   // Steps 19d-ii, 20.
3391   if (!new_writable) {
3392     PropertyDescriptor readonly;
3393     readonly.set_writable(false);
3394     Maybe<bool> success = OrdinaryDefineOwnProperty(
3395         isolate, a, isolate->factory()->length_string(), &readonly,
3396         should_throw);
3397     DCHECK(success.FromJust());
3398     USE(success);
3399   }
3400   uint32_t actual_new_len = 0;
3401   CHECK(a->length().ToArrayLength(&actual_new_len));
3402   // Steps 19d-v, 21. Return false if there were non-deletable elements.
3403   bool result = actual_new_len == new_len;
3404   if (!result) {
3405     RETURN_FAILURE(
3406         isolate, GetShouldThrow(isolate, should_throw),
3407         NewTypeError(MessageTemplate::kStrictDeleteProperty,
3408                      isolate->factory()->NewNumberFromUint(actual_new_len - 1),
3409                      a));
3410   }
3411   return Just(result);
3412 }
3413 
3414 // ES6 9.5.6
3415 // static
DefineOwnProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Object> key,PropertyDescriptor * desc,Maybe<ShouldThrow> should_throw)3416 Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy,
3417                                        Handle<Object> key,
3418                                        PropertyDescriptor* desc,
3419                                        Maybe<ShouldThrow> should_throw) {
3420   STACK_CHECK(isolate, Nothing<bool>());
3421   if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) {
3422     DCHECK(!Handle<Symbol>::cast(key)->IsPrivateName());
3423     return JSProxy::SetPrivateSymbol(isolate, proxy, Handle<Symbol>::cast(key),
3424                                      desc, should_throw);
3425   }
3426   Handle<String> trap_name = isolate->factory()->defineProperty_string();
3427   // 1. Assert: IsPropertyKey(P) is true.
3428   DCHECK(key->IsName() || key->IsNumber());
3429   // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
3430   Handle<Object> handler(proxy->handler(), isolate);
3431   // 3. If handler is null, throw a TypeError exception.
3432   // 4. Assert: Type(handler) is Object.
3433   if (proxy->IsRevoked()) {
3434     isolate->Throw(*isolate->factory()->NewTypeError(
3435         MessageTemplate::kProxyRevoked, trap_name));
3436     return Nothing<bool>();
3437   }
3438   // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
3439   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
3440   // 6. Let trap be ? GetMethod(handler, "defineProperty").
3441   Handle<Object> trap;
3442   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3443       isolate, trap,
3444       Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
3445       Nothing<bool>());
3446   // 7. If trap is undefined, then:
3447   if (trap->IsUndefined(isolate)) {
3448     // 7a. Return target.[[DefineOwnProperty]](P, Desc).
3449     return JSReceiver::DefineOwnProperty(isolate, target, key, desc,
3450                                          should_throw);
3451   }
3452   // 8. Let descObj be FromPropertyDescriptor(Desc).
3453   Handle<Object> desc_obj = desc->ToObject(isolate);
3454   // 9. Let booleanTrapResult be
3455   //    ToBoolean(? Call(trap, handler, «target, P, descObj»)).
3456   Handle<Name> property_name =
3457       key->IsName()
3458           ? Handle<Name>::cast(key)
3459           : Handle<Name>::cast(isolate->factory()->NumberToString(key));
3460   // Do not leak private property names.
3461   DCHECK(!property_name->IsPrivate());
3462   Handle<Object> trap_result_obj;
3463   Handle<Object> args[] = {target, property_name, desc_obj};
3464   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3465       isolate, trap_result_obj,
3466       Execution::Call(isolate, trap, handler, arraysize(args), args),
3467       Nothing<bool>());
3468   // 10. If booleanTrapResult is false, return false.
3469   if (!trap_result_obj->BooleanValue(isolate)) {
3470     RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw),
3471                    NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
3472                                 trap_name, property_name));
3473   }
3474   // 11. Let targetDesc be ? target.[[GetOwnProperty]](P).
3475   PropertyDescriptor target_desc;
3476   Maybe<bool> target_found =
3477       JSReceiver::GetOwnPropertyDescriptor(isolate, target, key, &target_desc);
3478   MAYBE_RETURN(target_found, Nothing<bool>());
3479   // 12. Let extensibleTarget be ? IsExtensible(target).
3480   Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
3481   MAYBE_RETURN(maybe_extensible, Nothing<bool>());
3482   bool extensible_target = maybe_extensible.FromJust();
3483   // 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]]
3484   //     is false, then:
3485   // 13a. Let settingConfigFalse be true.
3486   // 14. Else let settingConfigFalse be false.
3487   bool setting_config_false = desc->has_configurable() && !desc->configurable();
3488   // 15. If targetDesc is undefined, then
3489   if (!target_found.FromJust()) {
3490     // 15a. If extensibleTarget is false, throw a TypeError exception.
3491     if (!extensible_target) {
3492       isolate->Throw(*isolate->factory()->NewTypeError(
3493           MessageTemplate::kProxyDefinePropertyNonExtensible, property_name));
3494       return Nothing<bool>();
3495     }
3496     // 15b. If settingConfigFalse is true, throw a TypeError exception.
3497     if (setting_config_false) {
3498       isolate->Throw(*isolate->factory()->NewTypeError(
3499           MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
3500       return Nothing<bool>();
3501     }
3502   } else {
3503     // 16. Else targetDesc is not undefined,
3504     // 16a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc,
3505     //      targetDesc) is false, throw a TypeError exception.
3506     Maybe<bool> valid = IsCompatiblePropertyDescriptor(
3507         isolate, extensible_target, desc, &target_desc, property_name,
3508         Just(kDontThrow));
3509     MAYBE_RETURN(valid, Nothing<bool>());
3510     if (!valid.FromJust()) {
3511       isolate->Throw(*isolate->factory()->NewTypeError(
3512           MessageTemplate::kProxyDefinePropertyIncompatible, property_name));
3513       return Nothing<bool>();
3514     }
3515     // 16b. If settingConfigFalse is true and targetDesc.[[Configurable]] is
3516     //      true, throw a TypeError exception.
3517     if (setting_config_false && target_desc.configurable()) {
3518       isolate->Throw(*isolate->factory()->NewTypeError(
3519           MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
3520       return Nothing<bool>();
3521     }
3522     // 16c. If IsDataDescriptor(targetDesc) is true,
3523     // targetDesc.[[Configurable]] is
3524     //       false, and targetDesc.[[Writable]] is true, then
3525     if (PropertyDescriptor::IsDataDescriptor(&target_desc) &&
3526         !target_desc.configurable() && target_desc.writable()) {
3527       // 16c i. If Desc has a [[Writable]] field and Desc.[[Writable]] is false,
3528       // throw a TypeError exception.
3529       if (desc->has_writable() && !desc->writable()) {
3530         isolate->Throw(*isolate->factory()->NewTypeError(
3531             MessageTemplate::kProxyDefinePropertyNonConfigurableWritable,
3532             property_name));
3533         return Nothing<bool>();
3534       }
3535     }
3536   }
3537   // 17. Return true.
3538   return Just(true);
3539 }
3540 
3541 // static
SetPrivateSymbol(Isolate * isolate,Handle<JSProxy> proxy,Handle<Symbol> private_name,PropertyDescriptor * desc,Maybe<ShouldThrow> should_throw)3542 Maybe<bool> JSProxy::SetPrivateSymbol(Isolate* isolate, Handle<JSProxy> proxy,
3543                                       Handle<Symbol> private_name,
3544                                       PropertyDescriptor* desc,
3545                                       Maybe<ShouldThrow> should_throw) {
3546   DCHECK(!private_name->IsPrivateName());
3547   // Despite the generic name, this can only add private data properties.
3548   if (!PropertyDescriptor::IsDataDescriptor(desc) ||
3549       desc->ToAttributes() != DONT_ENUM) {
3550     RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw),
3551                    NewTypeError(MessageTemplate::kProxyPrivate));
3552   }
3553   DCHECK(proxy->map().is_dictionary_map());
3554   Handle<Object> value =
3555       desc->has_value()
3556           ? desc->value()
3557           : Handle<Object>::cast(isolate->factory()->undefined_value());
3558 
3559   LookupIterator it(isolate, proxy, private_name, proxy);
3560 
3561   if (it.IsFound()) {
3562     DCHECK_EQ(LookupIterator::DATA, it.state());
3563     DCHECK_EQ(DONT_ENUM, it.property_attributes());
3564     // We are not tracking constness for private symbols added to JSProxy
3565     // objects.
3566     DCHECK_EQ(PropertyConstness::kMutable, it.property_details().constness());
3567     it.WriteDataValue(value, false);
3568     return Just(true);
3569   }
3570 
3571   PropertyDetails details(kData, DONT_ENUM, PropertyConstness::kMutable);
3572   if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
3573     Handle<SwissNameDictionary> dict(proxy->property_dictionary_swiss(),
3574                                      isolate);
3575     Handle<SwissNameDictionary> result =
3576         SwissNameDictionary::Add(isolate, dict, private_name, value, details);
3577     if (!dict.is_identical_to(result)) proxy->SetProperties(*result);
3578   } else {
3579     Handle<NameDictionary> dict(proxy->property_dictionary(), isolate);
3580     Handle<NameDictionary> result =
3581         NameDictionary::Add(isolate, dict, private_name, value, details);
3582     if (!dict.is_identical_to(result)) proxy->SetProperties(*result);
3583   }
3584   return Just(true);
3585 }
3586 
3587 // ES6 9.5.5
3588 // static
GetOwnPropertyDescriptor(Isolate * isolate,Handle<JSProxy> proxy,Handle<Name> name,PropertyDescriptor * desc)3589 Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate,
3590                                               Handle<JSProxy> proxy,
3591                                               Handle<Name> name,
3592                                               PropertyDescriptor* desc) {
3593   DCHECK(!name->IsPrivate());
3594   STACK_CHECK(isolate, Nothing<bool>());
3595 
3596   Handle<String> trap_name =
3597       isolate->factory()->getOwnPropertyDescriptor_string();
3598   // 1. (Assert)
3599   // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
3600   Handle<Object> handler(proxy->handler(), isolate);
3601   // 3. If handler is null, throw a TypeError exception.
3602   // 4. Assert: Type(handler) is Object.
3603   if (proxy->IsRevoked()) {
3604     isolate->Throw(*isolate->factory()->NewTypeError(
3605         MessageTemplate::kProxyRevoked, trap_name));
3606     return Nothing<bool>();
3607   }
3608   // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
3609   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
3610   // 6. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor").
3611   Handle<Object> trap;
3612   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3613       isolate, trap,
3614       Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
3615       Nothing<bool>());
3616   // 7. If trap is undefined, then
3617   if (trap->IsUndefined(isolate)) {
3618     // 7a. Return target.[[GetOwnProperty]](P).
3619     return JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, desc);
3620   }
3621   // 8. Let trapResultObj be ? Call(trap, handler, «target, P»).
3622   Handle<Object> trap_result_obj;
3623   Handle<Object> args[] = {target, name};
3624   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3625       isolate, trap_result_obj,
3626       Execution::Call(isolate, trap, handler, arraysize(args), args),
3627       Nothing<bool>());
3628   // 9. If Type(trapResultObj) is neither Object nor Undefined, throw a
3629   //    TypeError exception.
3630   if (!trap_result_obj->IsJSReceiver() &&
3631       !trap_result_obj->IsUndefined(isolate)) {
3632     isolate->Throw(*isolate->factory()->NewTypeError(
3633         MessageTemplate::kProxyGetOwnPropertyDescriptorInvalid, name));
3634     return Nothing<bool>();
3635   }
3636   // 10. Let targetDesc be ? target.[[GetOwnProperty]](P).
3637   PropertyDescriptor target_desc;
3638   Maybe<bool> found =
3639       JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
3640   MAYBE_RETURN(found, Nothing<bool>());
3641   // 11. If trapResultObj is undefined, then
3642   if (trap_result_obj->IsUndefined(isolate)) {
3643     // 11a. If targetDesc is undefined, return undefined.
3644     if (!found.FromJust()) return Just(false);
3645     // 11b. If targetDesc.[[Configurable]] is false, throw a TypeError
3646     //      exception.
3647     if (!target_desc.configurable()) {
3648       isolate->Throw(*isolate->factory()->NewTypeError(
3649           MessageTemplate::kProxyGetOwnPropertyDescriptorUndefined, name));
3650       return Nothing<bool>();
3651     }
3652     // 11c. Let extensibleTarget be ? IsExtensible(target).
3653     Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
3654     MAYBE_RETURN(extensible_target, Nothing<bool>());
3655     // 11d. (Assert)
3656     // 11e. If extensibleTarget is false, throw a TypeError exception.
3657     if (!extensible_target.FromJust()) {
3658       isolate->Throw(*isolate->factory()->NewTypeError(
3659           MessageTemplate::kProxyGetOwnPropertyDescriptorNonExtensible, name));
3660       return Nothing<bool>();
3661     }
3662     // 11f. Return undefined.
3663     return Just(false);
3664   }
3665   // 12. Let extensibleTarget be ? IsExtensible(target).
3666   Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
3667   MAYBE_RETURN(extensible_target, Nothing<bool>());
3668   // 13. Let resultDesc be ? ToPropertyDescriptor(trapResultObj).
3669   if (!PropertyDescriptor::ToPropertyDescriptor(isolate, trap_result_obj,
3670                                                 desc)) {
3671     DCHECK(isolate->has_pending_exception());
3672     return Nothing<bool>();
3673   }
3674   // 14. Call CompletePropertyDescriptor(resultDesc).
3675   PropertyDescriptor::CompletePropertyDescriptor(isolate, desc);
3676   // 15. Let valid be IsCompatiblePropertyDescriptor (extensibleTarget,
3677   //     resultDesc, targetDesc).
3678   Maybe<bool> valid = IsCompatiblePropertyDescriptor(
3679       isolate, extensible_target.FromJust(), desc, &target_desc, name,
3680       Just(kDontThrow));
3681   MAYBE_RETURN(valid, Nothing<bool>());
3682   // 16. If valid is false, throw a TypeError exception.
3683   if (!valid.FromJust()) {
3684     isolate->Throw(*isolate->factory()->NewTypeError(
3685         MessageTemplate::kProxyGetOwnPropertyDescriptorIncompatible, name));
3686     return Nothing<bool>();
3687   }
3688   // 17. If resultDesc.[[Configurable]] is false, then
3689   if (!desc->configurable()) {
3690     // 17a. If targetDesc is undefined or targetDesc.[[Configurable]] is true:
3691     if (target_desc.is_empty() || target_desc.configurable()) {
3692       // 17a i. Throw a TypeError exception.
3693       isolate->Throw(*isolate->factory()->NewTypeError(
3694           MessageTemplate::kProxyGetOwnPropertyDescriptorNonConfigurable,
3695           name));
3696       return Nothing<bool>();
3697     }
3698     // 17b. If resultDesc has a [[Writable]] field and resultDesc.[[Writable]]
3699     // is false, then
3700     if (desc->has_writable() && !desc->writable()) {
3701       // 17b i. If targetDesc.[[Writable]] is true, throw a TypeError exception.
3702       if (target_desc.writable()) {
3703         isolate->Throw(*isolate->factory()->NewTypeError(
3704             MessageTemplate::
3705                 kProxyGetOwnPropertyDescriptorNonConfigurableWritable,
3706             name));
3707         return Nothing<bool>();
3708       }
3709     }
3710   }
3711   // 18. Return resultDesc.
3712   return Just(true);
3713 }
3714 
PreventExtensions(Handle<JSProxy> proxy,ShouldThrow should_throw)3715 Maybe<bool> JSProxy::PreventExtensions(Handle<JSProxy> proxy,
3716                                        ShouldThrow should_throw) {
3717   Isolate* isolate = proxy->GetIsolate();
3718   STACK_CHECK(isolate, Nothing<bool>());
3719   Factory* factory = isolate->factory();
3720   Handle<String> trap_name = factory->preventExtensions_string();
3721 
3722   if (proxy->IsRevoked()) {
3723     isolate->Throw(
3724         *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
3725     return Nothing<bool>();
3726   }
3727   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
3728   Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
3729 
3730   Handle<Object> trap;
3731   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3732       isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
3733   if (trap->IsUndefined(isolate)) {
3734     return JSReceiver::PreventExtensions(target, should_throw);
3735   }
3736 
3737   Handle<Object> trap_result;
3738   Handle<Object> args[] = {target};
3739   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3740       isolate, trap_result,
3741       Execution::Call(isolate, trap, handler, arraysize(args), args),
3742       Nothing<bool>());
3743   if (!trap_result->BooleanValue(isolate)) {
3744     RETURN_FAILURE(
3745         isolate, should_throw,
3746         NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
3747   }
3748 
3749   // Enforce the invariant.
3750   Maybe<bool> target_result = JSReceiver::IsExtensible(target);
3751   MAYBE_RETURN(target_result, Nothing<bool>());
3752   if (target_result.FromJust()) {
3753     isolate->Throw(*factory->NewTypeError(
3754         MessageTemplate::kProxyPreventExtensionsExtensible));
3755     return Nothing<bool>();
3756   }
3757   return Just(true);
3758 }
3759 
IsExtensible(Handle<JSProxy> proxy)3760 Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) {
3761   Isolate* isolate = proxy->GetIsolate();
3762   STACK_CHECK(isolate, Nothing<bool>());
3763   Factory* factory = isolate->factory();
3764   Handle<String> trap_name = factory->isExtensible_string();
3765 
3766   if (proxy->IsRevoked()) {
3767     isolate->Throw(
3768         *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
3769     return Nothing<bool>();
3770   }
3771   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
3772   Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
3773 
3774   Handle<Object> trap;
3775   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3776       isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
3777   if (trap->IsUndefined(isolate)) {
3778     return JSReceiver::IsExtensible(target);
3779   }
3780 
3781   Handle<Object> trap_result;
3782   Handle<Object> args[] = {target};
3783   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3784       isolate, trap_result,
3785       Execution::Call(isolate, trap, handler, arraysize(args), args),
3786       Nothing<bool>());
3787 
3788   // Enforce the invariant.
3789   Maybe<bool> target_result = JSReceiver::IsExtensible(target);
3790   MAYBE_RETURN(target_result, Nothing<bool>());
3791   if (target_result.FromJust() != trap_result->BooleanValue(isolate)) {
3792     isolate->Throw(
3793         *factory->NewTypeError(MessageTemplate::kProxyIsExtensibleInconsistent,
3794                                factory->ToBoolean(target_result.FromJust())));
3795     return Nothing<bool>();
3796   }
3797   return target_result;
3798 }
3799 
CopyUpTo(Isolate * isolate,Handle<DescriptorArray> desc,int enumeration_index,int slack)3800 Handle<DescriptorArray> DescriptorArray::CopyUpTo(Isolate* isolate,
3801                                                   Handle<DescriptorArray> desc,
3802                                                   int enumeration_index,
3803                                                   int slack) {
3804   return DescriptorArray::CopyUpToAddAttributes(isolate, desc,
3805                                                 enumeration_index, NONE, slack);
3806 }
3807 
CopyUpToAddAttributes(Isolate * isolate,Handle<DescriptorArray> desc,int enumeration_index,PropertyAttributes attributes,int slack)3808 Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
3809     Isolate* isolate, Handle<DescriptorArray> desc, int enumeration_index,
3810     PropertyAttributes attributes, int slack) {
3811   if (enumeration_index + slack == 0) {
3812     return isolate->factory()->empty_descriptor_array();
3813   }
3814 
3815   int size = enumeration_index;
3816 
3817   Handle<DescriptorArray> descriptors =
3818       DescriptorArray::Allocate(isolate, size, slack);
3819 
3820   if (attributes != NONE) {
3821     for (InternalIndex i : InternalIndex::Range(size)) {
3822       MaybeObject value_or_field_type = desc->GetValue(i);
3823       Name key = desc->GetKey(i);
3824       PropertyDetails details = desc->GetDetails(i);
3825       // Bulk attribute changes never affect private properties.
3826       if (!key.IsPrivate()) {
3827         int mask = DONT_DELETE | DONT_ENUM;
3828         // READ_ONLY is an invalid attribute for JS setters/getters.
3829         HeapObject heap_object;
3830         if (details.kind() != kAccessor ||
3831             !(value_or_field_type->GetHeapObjectIfStrong(&heap_object) &&
3832               heap_object.IsAccessorPair())) {
3833           mask |= READ_ONLY;
3834         }
3835         details = details.CopyAddAttributes(
3836             static_cast<PropertyAttributes>(attributes & mask));
3837       }
3838       descriptors->Set(i, key, value_or_field_type, details);
3839     }
3840   } else {
3841     for (InternalIndex i : InternalIndex::Range(size)) {
3842       descriptors->CopyFrom(i, *desc);
3843     }
3844   }
3845 
3846   if (desc->number_of_descriptors() != enumeration_index) descriptors->Sort();
3847 
3848   return descriptors;
3849 }
3850 
3851 // Create a new descriptor array with only enumerable, configurable, writeable
3852 // data properties, but identical field locations.
CopyForFastObjectClone(Isolate * isolate,Handle<DescriptorArray> src,int enumeration_index,int slack)3853 Handle<DescriptorArray> DescriptorArray::CopyForFastObjectClone(
3854     Isolate* isolate, Handle<DescriptorArray> src, int enumeration_index,
3855     int slack) {
3856   if (enumeration_index + slack == 0) {
3857     return isolate->factory()->empty_descriptor_array();
3858   }
3859 
3860   int size = enumeration_index;
3861   Handle<DescriptorArray> descriptors =
3862       DescriptorArray::Allocate(isolate, size, slack);
3863 
3864   for (InternalIndex i : InternalIndex::Range(size)) {
3865     Name key = src->GetKey(i);
3866     PropertyDetails details = src->GetDetails(i);
3867     Representation new_representation = details.representation();
3868 
3869     DCHECK(!key.IsPrivateName());
3870     DCHECK(details.IsEnumerable());
3871     DCHECK_EQ(details.kind(), kData);
3872     // If the new representation is an in-place changeable field, make it
3873     // generic as possible (under in-place changes) to avoid type confusion if
3874     // the source representation changes after this feedback has been collected.
3875     MaybeObject type = src->GetValue(i);
3876     if (details.location() == PropertyLocation::kField) {
3877       type = MaybeObject::FromObject(FieldType::Any());
3878       // TODO(bmeurer,ishell): Igor suggested to use some kind of dynamic
3879       // checks in the fast-path for CloneObjectIC instead to avoid the
3880       // need to generalize the descriptors here. That will also enable
3881       // us to skip the defensive copying of the target map whenever a
3882       // CloneObjectIC misses.
3883       new_representation = new_representation.MostGenericInPlaceChange();
3884     }
3885 
3886     // Ensure the ObjectClone property details are NONE, and that all source
3887     // details did not contain DONT_ENUM.
3888     PropertyDetails new_details(kData, NONE, details.location(),
3889                                 details.constness(), new_representation,
3890                                 details.field_index());
3891 
3892     descriptors->Set(i, key, type, new_details);
3893   }
3894 
3895   descriptors->Sort();
3896 
3897   return descriptors;
3898 }
3899 
IsEqualUpTo(DescriptorArray desc,int nof_descriptors)3900 bool DescriptorArray::IsEqualUpTo(DescriptorArray desc, int nof_descriptors) {
3901   for (InternalIndex i : InternalIndex::Range(nof_descriptors)) {
3902     if (GetKey(i) != desc.GetKey(i) || GetValue(i) != desc.GetValue(i)) {
3903       return false;
3904     }
3905     PropertyDetails details = GetDetails(i);
3906     PropertyDetails other_details = desc.GetDetails(i);
3907     if (details.kind() != other_details.kind() ||
3908         details.location() != other_details.location() ||
3909         !details.representation().Equals(other_details.representation())) {
3910       return false;
3911     }
3912   }
3913   return true;
3914 }
3915 
SetAndGrow(Isolate * isolate,Handle<FixedArray> array,int index,Handle<Object> value)3916 Handle<FixedArray> FixedArray::SetAndGrow(Isolate* isolate,
3917                                           Handle<FixedArray> array, int index,
3918                                           Handle<Object> value) {
3919   if (index < array->length()) {
3920     array->set(index, *value);
3921     return array;
3922   }
3923   int capacity = array->length();
3924   do {
3925     capacity = JSObject::NewElementsCapacity(capacity);
3926   } while (capacity <= index);
3927   Handle<FixedArray> new_array = isolate->factory()->NewFixedArray(capacity);
3928   array->CopyTo(0, *new_array, 0, array->length());
3929   new_array->FillWithHoles(array->length(), new_array->length());
3930   new_array->set(index, *value);
3931   return new_array;
3932 }
3933 
ShrinkOrEmpty(Isolate * isolate,Handle<FixedArray> array,int new_length)3934 Handle<FixedArray> FixedArray::ShrinkOrEmpty(Isolate* isolate,
3935                                              Handle<FixedArray> array,
3936                                              int new_length) {
3937   if (new_length == 0) {
3938     return array->GetReadOnlyRoots().empty_fixed_array_handle();
3939   } else {
3940     array->Shrink(isolate, new_length);
3941     return array;
3942   }
3943 }
3944 
Shrink(Isolate * isolate,int new_length)3945 void FixedArray::Shrink(Isolate* isolate, int new_length) {
3946   DCHECK(0 < new_length && new_length <= length());
3947   if (new_length < length()) {
3948     isolate->heap()->RightTrimFixedArray(*this, length() - new_length);
3949   }
3950 }
3951 
CopyTo(int pos,FixedArray dest,int dest_pos,int len) const3952 void FixedArray::CopyTo(int pos, FixedArray dest, int dest_pos, int len) const {
3953   DisallowGarbageCollection no_gc;
3954   // Return early if len == 0 so that we don't try to read the write barrier off
3955   // a canonical read-only empty fixed array.
3956   if (len == 0) return;
3957   WriteBarrierMode mode = dest.GetWriteBarrierMode(no_gc);
3958   for (int index = 0; index < len; index++) {
3959     dest.set(dest_pos + index, get(pos + index), mode);
3960   }
3961 }
3962 
3963 // static
Add(Isolate * isolate,Handle<ArrayList> array,Handle<Object> obj)3964 Handle<ArrayList> ArrayList::Add(Isolate* isolate, Handle<ArrayList> array,
3965                                  Handle<Object> obj) {
3966   int length = array->Length();
3967   array = EnsureSpace(isolate, array, length + 1);
3968   // Check that GC didn't remove elements from the array.
3969   DCHECK_EQ(array->Length(), length);
3970   {
3971     DisallowGarbageCollection no_gc;
3972     ArrayList raw_array = *array;
3973     raw_array.Set(length, *obj);
3974     raw_array.SetLength(length + 1);
3975   }
3976   return array;
3977 }
3978 
3979 // static
Add(Isolate * isolate,Handle<ArrayList> array,Handle<Object> obj1,Handle<Object> obj2)3980 Handle<ArrayList> ArrayList::Add(Isolate* isolate, Handle<ArrayList> array,
3981                                  Handle<Object> obj1, Handle<Object> obj2) {
3982   int length = array->Length();
3983   array = EnsureSpace(isolate, array, length + 2);
3984   // Check that GC didn't remove elements from the array.
3985   DCHECK_EQ(array->Length(), length);
3986   {
3987     DisallowGarbageCollection no_gc;
3988     ArrayList raw_array = *array;
3989     raw_array.Set(length, *obj1);
3990     raw_array.Set(length + 1, *obj2);
3991     raw_array.SetLength(length + 2);
3992   }
3993   return array;
3994 }
3995 
Add(Isolate * isolate,Handle<ArrayList> array,Handle<Object> obj1,Smi obj2,Smi obj3,Smi obj4)3996 Handle<ArrayList> ArrayList::Add(Isolate* isolate, Handle<ArrayList> array,
3997                                  Handle<Object> obj1, Smi obj2, Smi obj3,
3998                                  Smi obj4) {
3999   int length = array->Length();
4000   array = EnsureSpace(isolate, array, length + 4);
4001   // Check that GC didn't remove elements from the array.
4002   DCHECK_EQ(array->Length(), length);
4003   {
4004     DisallowGarbageCollection no_gc;
4005     ArrayList raw_array = *array;
4006     raw_array.Set(length, *obj1);
4007     raw_array.Set(length + 1, obj2);
4008     raw_array.Set(length + 2, obj3);
4009     raw_array.Set(length + 3, obj4);
4010     raw_array.SetLength(length + 4);
4011   }
4012   return array;
4013 }
4014 
4015 // static
New(Isolate * isolate,int size)4016 Handle<ArrayList> ArrayList::New(Isolate* isolate, int size) {
4017   Handle<FixedArray> fixed_array =
4018       isolate->factory()->NewFixedArray(size + kFirstIndex);
4019   fixed_array->set_map_no_write_barrier(
4020       ReadOnlyRoots(isolate).array_list_map());
4021   Handle<ArrayList> result = Handle<ArrayList>::cast(fixed_array);
4022   result->SetLength(0);
4023   return result;
4024 }
4025 
Elements(Isolate * isolate,Handle<ArrayList> array)4026 Handle<FixedArray> ArrayList::Elements(Isolate* isolate,
4027                                        Handle<ArrayList> array) {
4028   int length = array->Length();
4029   Handle<FixedArray> result = isolate->factory()->NewFixedArray(length);
4030   // Do not copy the first entry, i.e., the length.
4031   array->CopyTo(kFirstIndex, *result, 0, length);
4032   return result;
4033 }
4034 
4035 namespace {
4036 
EnsureSpaceInFixedArray(Isolate * isolate,Handle<FixedArray> array,int length)4037 Handle<FixedArray> EnsureSpaceInFixedArray(Isolate* isolate,
4038                                            Handle<FixedArray> array,
4039                                            int length) {
4040   int capacity = array->length();
4041   if (capacity < length) {
4042     int new_capacity = length;
4043     new_capacity = new_capacity + std::max(new_capacity / 2, 2);
4044     int grow_by = new_capacity - capacity;
4045     array = isolate->factory()->CopyFixedArrayAndGrow(array, grow_by);
4046   }
4047   return array;
4048 }
4049 
4050 }  // namespace
4051 
4052 // static
EnsureSpace(Isolate * isolate,Handle<ArrayList> array,int length)4053 Handle<ArrayList> ArrayList::EnsureSpace(Isolate* isolate,
4054                                          Handle<ArrayList> array, int length) {
4055   const bool empty = (array->length() == 0);
4056   Handle<FixedArray> ret =
4057       EnsureSpaceInFixedArray(isolate, array, kFirstIndex + length);
4058   if (empty) {
4059     ret->set_map_no_write_barrier(array->GetReadOnlyRoots().array_list_map());
4060 
4061     Handle<ArrayList>::cast(ret)->SetLength(0);
4062   }
4063   return Handle<ArrayList>::cast(ret);
4064 }
4065 
4066 // static
AddToEnd(Isolate * isolate,Handle<WeakArrayList> array,const MaybeObjectHandle & value)4067 Handle<WeakArrayList> WeakArrayList::AddToEnd(Isolate* isolate,
4068                                               Handle<WeakArrayList> array,
4069                                               const MaybeObjectHandle& value) {
4070   int length = array->length();
4071   array = EnsureSpace(isolate, array, length + 1);
4072   // Reload length; GC might have removed elements from the array.
4073   length = array->length();
4074   array->Set(length, *value);
4075   array->set_length(length + 1);
4076   return array;
4077 }
4078 
AddToEnd(Isolate * isolate,Handle<WeakArrayList> array,const MaybeObjectHandle & value1,const MaybeObjectHandle & value2)4079 Handle<WeakArrayList> WeakArrayList::AddToEnd(Isolate* isolate,
4080                                               Handle<WeakArrayList> array,
4081                                               const MaybeObjectHandle& value1,
4082                                               const MaybeObjectHandle& value2) {
4083   int length = array->length();
4084   array = EnsureSpace(isolate, array, length + 2);
4085   // Reload length; GC might have removed elements from the array.
4086   length = array->length();
4087   array->Set(length, *value1);
4088   array->Set(length + 1, *value2);
4089   array->set_length(length + 2);
4090   return array;
4091 }
4092 
4093 // static
Append(Isolate * isolate,Handle<WeakArrayList> array,const MaybeObjectHandle & value,AllocationType allocation)4094 Handle<WeakArrayList> WeakArrayList::Append(Isolate* isolate,
4095                                             Handle<WeakArrayList> array,
4096                                             const MaybeObjectHandle& value,
4097                                             AllocationType allocation) {
4098   int length = array->length();
4099 
4100   if (length < array->capacity()) {
4101     array->Set(length, *value);
4102     array->set_length(length + 1);
4103     return array;
4104   }
4105 
4106   // Not enough space in the array left, either grow, shrink or
4107   // compact the array.
4108   int new_length = array->CountLiveElements() + 1;
4109 
4110   bool shrink = new_length < length / 4;
4111   bool grow = 3 * (length / 4) < new_length;
4112 
4113   if (shrink || grow) {
4114     // Grow or shrink array and compact out-of-place.
4115     int new_capacity = CapacityForLength(new_length);
4116     array = isolate->factory()->CompactWeakArrayList(array, new_capacity,
4117                                                      allocation);
4118 
4119   } else {
4120     // Perform compaction in the current array.
4121     array->Compact(isolate);
4122   }
4123 
4124   // Now append value to the array, there should always be enough space now.
4125   DCHECK_LT(array->length(), array->capacity());
4126 
4127   // Reload length, allocation might have killed some weak refs.
4128   int index = array->length();
4129   array->Set(index, *value);
4130   array->set_length(index + 1);
4131   return array;
4132 }
4133 
Compact(Isolate * isolate)4134 void WeakArrayList::Compact(Isolate* isolate) {
4135   int length = this->length();
4136   int new_length = 0;
4137 
4138   for (int i = 0; i < length; i++) {
4139     MaybeObject value = Get(isolate, i);
4140 
4141     if (!value->IsCleared()) {
4142       if (new_length != i) {
4143         Set(new_length, value);
4144       }
4145       ++new_length;
4146     }
4147   }
4148 
4149   set_length(new_length);
4150 }
4151 
IsFull()4152 bool WeakArrayList::IsFull() { return length() == capacity(); }
4153 
4154 // static
EnsureSpace(Isolate * isolate,Handle<WeakArrayList> array,int length,AllocationType allocation)4155 Handle<WeakArrayList> WeakArrayList::EnsureSpace(Isolate* isolate,
4156                                                  Handle<WeakArrayList> array,
4157                                                  int length,
4158                                                  AllocationType allocation) {
4159   int capacity = array->capacity();
4160   if (capacity < length) {
4161     int grow_by = CapacityForLength(length) - capacity;
4162     array = isolate->factory()->CopyWeakArrayListAndGrow(array, grow_by,
4163                                                          allocation);
4164   }
4165   return array;
4166 }
4167 
CountLiveWeakReferences() const4168 int WeakArrayList::CountLiveWeakReferences() const {
4169   int live_weak_references = 0;
4170   for (int i = 0; i < length(); i++) {
4171     if (Get(i)->IsWeak()) {
4172       ++live_weak_references;
4173     }
4174   }
4175   return live_weak_references;
4176 }
4177 
CountLiveElements() const4178 int WeakArrayList::CountLiveElements() const {
4179   int non_cleared_objects = 0;
4180   for (int i = 0; i < length(); i++) {
4181     if (!Get(i)->IsCleared()) {
4182       ++non_cleared_objects;
4183     }
4184   }
4185   return non_cleared_objects;
4186 }
4187 
RemoveOne(const MaybeObjectHandle & value)4188 bool WeakArrayList::RemoveOne(const MaybeObjectHandle& value) {
4189   if (length() == 0) return false;
4190   // Optimize for the most recently added element to be removed again.
4191   MaybeObject cleared_weak_ref =
4192       HeapObjectReference::ClearedValue(GetIsolate());
4193   int last_index = length() - 1;
4194   for (int i = last_index; i >= 0; --i) {
4195     if (Get(i) == *value) {
4196       // Move the last element into the this slot (or no-op, if this is the
4197       // last slot).
4198       Set(i, Get(last_index));
4199       Set(last_index, cleared_weak_ref);
4200       set_length(last_index);
4201       return true;
4202     }
4203   }
4204   return false;
4205 }
4206 
4207 // static
Add(Isolate * isolate,Handle<WeakArrayList> array,Handle<Map> value,int * assigned_index)4208 Handle<WeakArrayList> PrototypeUsers::Add(Isolate* isolate,
4209                                           Handle<WeakArrayList> array,
4210                                           Handle<Map> value,
4211                                           int* assigned_index) {
4212   int length = array->length();
4213   if (length == 0) {
4214     // Uninitialized WeakArrayList; need to initialize empty_slot_index.
4215     array = WeakArrayList::EnsureSpace(isolate, array, kFirstIndex + 1);
4216     set_empty_slot_index(*array, kNoEmptySlotsMarker);
4217     array->Set(kFirstIndex, HeapObjectReference::Weak(*value));
4218     array->set_length(kFirstIndex + 1);
4219     if (assigned_index != nullptr) *assigned_index = kFirstIndex;
4220     return array;
4221   }
4222 
4223   // If the array has unfilled space at the end, use it.
4224   if (!array->IsFull()) {
4225     array->Set(length, HeapObjectReference::Weak(*value));
4226     array->set_length(length + 1);
4227     if (assigned_index != nullptr) *assigned_index = length;
4228     return array;
4229   }
4230 
4231   // If there are empty slots, use one of them.
4232   int empty_slot = Smi::ToInt(empty_slot_index(*array));
4233 
4234   if (empty_slot == kNoEmptySlotsMarker) {
4235     // GCs might have cleared some references, rescan the array for empty slots.
4236     PrototypeUsers::ScanForEmptySlots(*array);
4237     empty_slot = Smi::ToInt(empty_slot_index(*array));
4238   }
4239 
4240   if (empty_slot != kNoEmptySlotsMarker) {
4241     DCHECK_GE(empty_slot, kFirstIndex);
4242     CHECK_LT(empty_slot, array->length());
4243     int next_empty_slot = array->Get(empty_slot).ToSmi().value();
4244 
4245     array->Set(empty_slot, HeapObjectReference::Weak(*value));
4246     if (assigned_index != nullptr) *assigned_index = empty_slot;
4247 
4248     set_empty_slot_index(*array, next_empty_slot);
4249     return array;
4250   } else {
4251     DCHECK_EQ(empty_slot, kNoEmptySlotsMarker);
4252   }
4253 
4254   // Array full and no empty slots. Grow the array.
4255   array = WeakArrayList::EnsureSpace(isolate, array, length + 1);
4256   array->Set(length, HeapObjectReference::Weak(*value));
4257   array->set_length(length + 1);
4258   if (assigned_index != nullptr) *assigned_index = length;
4259   return array;
4260 }
4261 
4262 // static
ScanForEmptySlots(WeakArrayList array)4263 void PrototypeUsers::ScanForEmptySlots(WeakArrayList array) {
4264   for (int i = kFirstIndex; i < array.length(); i++) {
4265     if (array.Get(i)->IsCleared()) {
4266       PrototypeUsers::MarkSlotEmpty(array, i);
4267     }
4268   }
4269 }
4270 
Compact(Handle<WeakArrayList> array,Heap * heap,CompactionCallback callback,AllocationType allocation)4271 WeakArrayList PrototypeUsers::Compact(Handle<WeakArrayList> array, Heap* heap,
4272                                       CompactionCallback callback,
4273                                       AllocationType allocation) {
4274   if (array->length() == 0) {
4275     return *array;
4276   }
4277   int new_length = kFirstIndex + array->CountLiveWeakReferences();
4278   if (new_length == array->length()) {
4279     return *array;
4280   }
4281 
4282   Handle<WeakArrayList> new_array = WeakArrayList::EnsureSpace(
4283       heap->isolate(),
4284       handle(ReadOnlyRoots(heap).empty_weak_array_list(), heap->isolate()),
4285       new_length, allocation);
4286   // Allocation might have caused GC and turned some of the elements into
4287   // cleared weak heap objects. Count the number of live objects again.
4288   int copy_to = kFirstIndex;
4289   for (int i = kFirstIndex; i < array->length(); i++) {
4290     MaybeObject element = array->Get(i);
4291     HeapObject value;
4292     if (element->GetHeapObjectIfWeak(&value)) {
4293       callback(value, i, copy_to);
4294       new_array->Set(copy_to++, element);
4295     } else {
4296       DCHECK(element->IsCleared() || element->IsSmi());
4297     }
4298   }
4299   new_array->set_length(copy_to);
4300   set_empty_slot_index(*new_array, kNoEmptySlotsMarker);
4301   return *new_array;
4302 }
4303 
New(Isolate * isolate,int capture_count)4304 Handle<RegExpMatchInfo> RegExpMatchInfo::New(Isolate* isolate,
4305                                              int capture_count) {
4306   Handle<RegExpMatchInfo> match_info = isolate->factory()->NewRegExpMatchInfo();
4307   return ReserveCaptures(isolate, match_info, capture_count);
4308 }
4309 
ReserveCaptures(Isolate * isolate,Handle<RegExpMatchInfo> match_info,int capture_count)4310 Handle<RegExpMatchInfo> RegExpMatchInfo::ReserveCaptures(
4311     Isolate* isolate, Handle<RegExpMatchInfo> match_info, int capture_count) {
4312   DCHECK_GE(match_info->length(), kLastMatchOverhead);
4313 
4314   int capture_register_count =
4315       JSRegExp::RegistersForCaptureCount(capture_count);
4316   const int required_length = kFirstCaptureIndex + capture_register_count;
4317   Handle<RegExpMatchInfo> result = Handle<RegExpMatchInfo>::cast(
4318       EnsureSpaceInFixedArray(isolate, match_info, required_length));
4319   result->SetNumberOfCaptureRegisters(capture_register_count);
4320   return result;
4321 }
4322 
4323 template <typename IsolateT>
Allocate(IsolateT * isolate,int nof_descriptors,int slack,AllocationType allocation)4324 Handle<DescriptorArray> DescriptorArray::Allocate(IsolateT* isolate,
4325                                                   int nof_descriptors,
4326                                                   int slack,
4327                                                   AllocationType allocation) {
4328   return nof_descriptors + slack == 0
4329              ? isolate->factory()->empty_descriptor_array()
4330              : isolate->factory()->NewDescriptorArray(nof_descriptors, slack,
4331                                                       allocation);
4332 }
4333 template Handle<DescriptorArray> DescriptorArray::Allocate(
4334     Isolate* isolate, int nof_descriptors, int slack,
4335     AllocationType allocation);
4336 template Handle<DescriptorArray> DescriptorArray::Allocate(
4337     LocalIsolate* isolate, int nof_descriptors, int slack,
4338     AllocationType allocation);
4339 
Initialize(EnumCache empty_enum_cache,HeapObject undefined_value,int nof_descriptors,int slack)4340 void DescriptorArray::Initialize(EnumCache empty_enum_cache,
4341                                  HeapObject undefined_value,
4342                                  int nof_descriptors, int slack) {
4343   DCHECK_GE(nof_descriptors, 0);
4344   DCHECK_GE(slack, 0);
4345   DCHECK_LE(nof_descriptors + slack, kMaxNumberOfDescriptors);
4346   set_number_of_all_descriptors(nof_descriptors + slack);
4347   set_number_of_descriptors(nof_descriptors);
4348   set_raw_number_of_marked_descriptors(0);
4349   set_filler16bits(0);
4350   set_enum_cache(empty_enum_cache, SKIP_WRITE_BARRIER);
4351   MemsetTagged(GetDescriptorSlot(0), undefined_value,
4352                number_of_all_descriptors() * kEntrySize);
4353 }
4354 
ClearEnumCache()4355 void DescriptorArray::ClearEnumCache() {
4356   set_enum_cache(GetReadOnlyRoots().empty_enum_cache(), SKIP_WRITE_BARRIER);
4357 }
4358 
Replace(InternalIndex index,Descriptor * descriptor)4359 void DescriptorArray::Replace(InternalIndex index, Descriptor* descriptor) {
4360   descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index.as_int()));
4361   Set(index, descriptor);
4362 }
4363 
4364 // static
InitializeOrChangeEnumCache(Handle<DescriptorArray> descriptors,Isolate * isolate,Handle<FixedArray> keys,Handle<FixedArray> indices)4365 void DescriptorArray::InitializeOrChangeEnumCache(
4366     Handle<DescriptorArray> descriptors, Isolate* isolate,
4367     Handle<FixedArray> keys, Handle<FixedArray> indices) {
4368   EnumCache enum_cache = descriptors->enum_cache();
4369   if (enum_cache == ReadOnlyRoots(isolate).empty_enum_cache()) {
4370     enum_cache = *isolate->factory()->NewEnumCache(keys, indices);
4371     descriptors->set_enum_cache(enum_cache);
4372   } else {
4373     enum_cache.set_keys(*keys);
4374     enum_cache.set_indices(*indices);
4375   }
4376 }
4377 
CopyFrom(InternalIndex index,DescriptorArray src)4378 void DescriptorArray::CopyFrom(InternalIndex index, DescriptorArray src) {
4379   PropertyDetails details = src.GetDetails(index);
4380   Set(index, src.GetKey(index), src.GetValue(index), details);
4381 }
4382 
Sort()4383 void DescriptorArray::Sort() {
4384   // In-place heap sort.
4385   int len = number_of_descriptors();
4386   // Reset sorting since the descriptor array might contain invalid pointers.
4387   for (int i = 0; i < len; ++i) SetSortedKey(i, i);
4388   // Bottom-up max-heap construction.
4389   // Index of the last node with children.
4390   const int max_parent_index = (len / 2) - 1;
4391   for (int i = max_parent_index; i >= 0; --i) {
4392     int parent_index = i;
4393     const uint32_t parent_hash = GetSortedKey(i).hash();
4394     while (parent_index <= max_parent_index) {
4395       int child_index = 2 * parent_index + 1;
4396       uint32_t child_hash = GetSortedKey(child_index).hash();
4397       if (child_index + 1 < len) {
4398         uint32_t right_child_hash = GetSortedKey(child_index + 1).hash();
4399         if (right_child_hash > child_hash) {
4400           child_index++;
4401           child_hash = right_child_hash;
4402         }
4403       }
4404       if (child_hash <= parent_hash) break;
4405       SwapSortedKeys(parent_index, child_index);
4406       // Now element at child_index could be < its children.
4407       parent_index = child_index;  // parent_hash remains correct.
4408     }
4409   }
4410 
4411   // Extract elements and create sorted array.
4412   for (int i = len - 1; i > 0; --i) {
4413     // Put max element at the back of the array.
4414     SwapSortedKeys(0, i);
4415     // Shift down the new top element.
4416     int parent_index = 0;
4417     const uint32_t parent_hash = GetSortedKey(parent_index).hash();
4418     const int max_parent_index = (i / 2) - 1;
4419     while (parent_index <= max_parent_index) {
4420       int child_index = parent_index * 2 + 1;
4421       uint32_t child_hash = GetSortedKey(child_index).hash();
4422       if (child_index + 1 < i) {
4423         uint32_t right_child_hash = GetSortedKey(child_index + 1).hash();
4424         if (right_child_hash > child_hash) {
4425           child_index++;
4426           child_hash = right_child_hash;
4427         }
4428       }
4429       if (child_hash <= parent_hash) break;
4430       SwapSortedKeys(parent_index, child_index);
4431       parent_index = child_index;
4432     }
4433   }
4434   DCHECK(IsSortedNoDuplicates());
4435 }
4436 
UpdateNumberOfMarkedDescriptors(unsigned mark_compact_epoch,int16_t new_marked)4437 int16_t DescriptorArray::UpdateNumberOfMarkedDescriptors(
4438     unsigned mark_compact_epoch, int16_t new_marked) {
4439   STATIC_ASSERT(kMaxNumberOfDescriptors <=
4440                 NumberOfMarkedDescriptors::kMaxNumberOfMarkedDescriptors);
4441   int16_t old_raw_marked = raw_number_of_marked_descriptors();
4442   int16_t old_marked =
4443       NumberOfMarkedDescriptors::decode(mark_compact_epoch, old_raw_marked);
4444   int16_t new_raw_marked =
4445       NumberOfMarkedDescriptors::encode(mark_compact_epoch, new_marked);
4446   while (old_marked < new_marked) {
4447     int16_t actual_raw_marked = CompareAndSwapRawNumberOfMarkedDescriptors(
4448         old_raw_marked, new_raw_marked);
4449     if (actual_raw_marked == old_raw_marked) {
4450       break;
4451     }
4452     old_raw_marked = actual_raw_marked;
4453     old_marked =
4454         NumberOfMarkedDescriptors::decode(mark_compact_epoch, old_raw_marked);
4455   }
4456   return old_marked;
4457 }
4458 
Copy(Isolate * isolate,Handle<AccessorPair> pair)4459 Handle<AccessorPair> AccessorPair::Copy(Isolate* isolate,
4460                                         Handle<AccessorPair> pair) {
4461   Handle<AccessorPair> copy = isolate->factory()->NewAccessorPair();
4462   copy->set_getter(pair->getter());
4463   copy->set_setter(pair->setter());
4464   return copy;
4465 }
4466 
GetComponent(Isolate * isolate,Handle<NativeContext> native_context,Handle<AccessorPair> accessor_pair,AccessorComponent component)4467 Handle<Object> AccessorPair::GetComponent(Isolate* isolate,
4468                                           Handle<NativeContext> native_context,
4469                                           Handle<AccessorPair> accessor_pair,
4470                                           AccessorComponent component) {
4471   Handle<Object> accessor(accessor_pair->get(component), isolate);
4472   if (accessor->IsFunctionTemplateInfo()) {
4473     auto function = ApiNatives::InstantiateFunction(
4474                         isolate, native_context,
4475                         Handle<FunctionTemplateInfo>::cast(accessor))
4476                         .ToHandleChecked();
4477     accessor_pair->set(component, *function, kReleaseStore);
4478     return function;
4479   }
4480   if (accessor->IsNull(isolate)) {
4481     return isolate->factory()->undefined_value();
4482   }
4483   return accessor;
4484 }
4485 
4486 #ifdef DEBUG
IsEqualTo(DescriptorArray other)4487 bool DescriptorArray::IsEqualTo(DescriptorArray other) {
4488   if (number_of_all_descriptors() != other.number_of_all_descriptors()) {
4489     return false;
4490   }
4491   for (InternalIndex i : InternalIndex::Range(number_of_descriptors())) {
4492     if (GetKey(i) != other.GetKey(i)) return false;
4493     if (GetDetails(i).AsSmi() != other.GetDetails(i).AsSmi()) return false;
4494     if (GetValue(i) != other.GetValue(i)) return false;
4495   }
4496   return true;
4497 }
4498 #endif
4499 
4500 // static
ToFunctionName(Isolate * isolate,Handle<Name> name)4501 MaybeHandle<String> Name::ToFunctionName(Isolate* isolate, Handle<Name> name) {
4502   if (name->IsString()) return Handle<String>::cast(name);
4503   // ES6 section 9.2.11 SetFunctionName, step 4.
4504   Handle<Object> description(Handle<Symbol>::cast(name)->description(),
4505                              isolate);
4506   if (description->IsUndefined(isolate)) {
4507     return isolate->factory()->empty_string();
4508   }
4509   IncrementalStringBuilder builder(isolate);
4510   builder.AppendCharacter('[');
4511   builder.AppendString(Handle<String>::cast(description));
4512   builder.AppendCharacter(']');
4513   return builder.Finish();
4514 }
4515 
4516 // static
ToFunctionName(Isolate * isolate,Handle<Name> name,Handle<String> prefix)4517 MaybeHandle<String> Name::ToFunctionName(Isolate* isolate, Handle<Name> name,
4518                                          Handle<String> prefix) {
4519   Handle<String> name_string;
4520   ASSIGN_RETURN_ON_EXCEPTION(isolate, name_string,
4521                              ToFunctionName(isolate, name), String);
4522   IncrementalStringBuilder builder(isolate);
4523   builder.AppendString(prefix);
4524   builder.AppendCharacter(' ');
4525   builder.AppendString(name_string);
4526   return builder.Finish();
4527 }
4528 
PostGarbageCollectionProcessing(Isolate * isolate)4529 void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) {
4530   Relocatable* current = isolate->relocatable_top();
4531   while (current != nullptr) {
4532     current->PostGarbageCollection();
4533     current = current->prev_;
4534   }
4535 }
4536 
4537 // Reserve space for statics needing saving and restoring.
ArchiveSpacePerThread()4538 int Relocatable::ArchiveSpacePerThread() { return sizeof(Relocatable*); }
4539 
4540 // Archive statics that are thread-local.
ArchiveState(Isolate * isolate,char * to)4541 char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
4542   *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
4543   isolate->set_relocatable_top(nullptr);
4544   return to + ArchiveSpacePerThread();
4545 }
4546 
4547 // Restore statics that are thread-local.
RestoreState(Isolate * isolate,char * from)4548 char* Relocatable::RestoreState(Isolate* isolate, char* from) {
4549   isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
4550   return from + ArchiveSpacePerThread();
4551 }
4552 
Iterate(RootVisitor * v,char * thread_storage)4553 char* Relocatable::Iterate(RootVisitor* v, char* thread_storage) {
4554   Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
4555   Iterate(v, top);
4556   return thread_storage + ArchiveSpacePerThread();
4557 }
4558 
Iterate(Isolate * isolate,RootVisitor * v)4559 void Relocatable::Iterate(Isolate* isolate, RootVisitor* v) {
4560   Iterate(v, isolate->relocatable_top());
4561 }
4562 
Iterate(RootVisitor * v,Relocatable * top)4563 void Relocatable::Iterate(RootVisitor* v, Relocatable* top) {
4564   Relocatable* current = top;
4565   while (current != nullptr) {
4566     current->IterateInstance(v);
4567     current = current->prev_;
4568   }
4569 }
4570 
4571 namespace {
4572 
4573 template <typename sinkchar>
WriteFixedArrayToFlat(FixedArray fixed_array,int length,String separator,sinkchar * sink,int sink_length)4574 void WriteFixedArrayToFlat(FixedArray fixed_array, int length, String separator,
4575                            sinkchar* sink, int sink_length) {
4576   DisallowGarbageCollection no_gc;
4577   CHECK_GT(length, 0);
4578   CHECK_LE(length, fixed_array.length());
4579 #ifdef DEBUG
4580   sinkchar* sink_end = sink + sink_length;
4581 #endif
4582 
4583   const int separator_length = separator.length();
4584   const bool use_one_byte_separator_fast_path =
4585       separator_length == 1 && sizeof(sinkchar) == 1 &&
4586       StringShape(separator).IsSequentialOneByte();
4587   uint8_t separator_one_char;
4588   if (use_one_byte_separator_fast_path) {
4589     CHECK(StringShape(separator).IsSequentialOneByte());
4590     CHECK_EQ(separator.length(), 1);
4591     separator_one_char = SeqOneByteString::cast(separator).GetChars(no_gc)[0];
4592   }
4593 
4594   uint32_t num_separators = 0;
4595   for (int i = 0; i < length; i++) {
4596     Object element = fixed_array.get(i);
4597     const bool element_is_separator_sequence = element.IsSmi();
4598 
4599     // If element is a Smi, it represents the number of separators to write.
4600     if (V8_UNLIKELY(element_is_separator_sequence)) {
4601       CHECK(element.ToUint32(&num_separators));
4602       // Verify that Smis (number of separators) only occur when necessary:
4603       //   1) at the beginning
4604       //   2) at the end
4605       //   3) when the number of separators > 1
4606       //     - It is assumed that consecutive Strings will have one separator,
4607       //       so there is no need for a Smi.
4608       DCHECK(i == 0 || i == length - 1 || num_separators > 1);
4609     }
4610 
4611     // Write separator(s) if necessary.
4612     if (num_separators > 0 && separator_length > 0) {
4613       // TODO(pwong): Consider doubling strategy employed by runtime-strings.cc
4614       //              WriteRepeatToFlat().
4615       // Fast path for single character, single byte separators.
4616       if (use_one_byte_separator_fast_path) {
4617         DCHECK_LE(sink + num_separators, sink_end);
4618         memset(sink, separator_one_char, num_separators);
4619         DCHECK_EQ(separator_length, 1);
4620         sink += num_separators;
4621       } else {
4622         for (uint32_t j = 0; j < num_separators; j++) {
4623           DCHECK_LE(sink + separator_length, sink_end);
4624           String::WriteToFlat(separator, sink, 0, separator_length);
4625           sink += separator_length;
4626         }
4627       }
4628     }
4629 
4630     if (V8_UNLIKELY(element_is_separator_sequence)) {
4631       num_separators = 0;
4632     } else {
4633       DCHECK(element.IsString());
4634       String string = String::cast(element);
4635       const int string_length = string.length();
4636 
4637       DCHECK(string_length == 0 || sink < sink_end);
4638       String::WriteToFlat(string, sink, 0, string_length);
4639       sink += string_length;
4640 
4641       // Next string element, needs at least one separator preceding it.
4642       num_separators = 1;
4643     }
4644   }
4645 
4646   // Verify we have written to the end of the sink.
4647   DCHECK_EQ(sink, sink_end);
4648 }
4649 
4650 }  // namespace
4651 
4652 // static
ArrayJoinConcatToSequentialString(Isolate * isolate,Address raw_fixed_array,intptr_t length,Address raw_separator,Address raw_dest)4653 Address JSArray::ArrayJoinConcatToSequentialString(Isolate* isolate,
4654                                                    Address raw_fixed_array,
4655                                                    intptr_t length,
4656                                                    Address raw_separator,
4657                                                    Address raw_dest) {
4658   DisallowGarbageCollection no_gc;
4659   DisallowJavascriptExecution no_js(isolate);
4660   FixedArray fixed_array = FixedArray::cast(Object(raw_fixed_array));
4661   String separator = String::cast(Object(raw_separator));
4662   String dest = String::cast(Object(raw_dest));
4663   DCHECK(fixed_array.IsFixedArray());
4664   DCHECK(StringShape(dest).IsSequentialOneByte() ||
4665          StringShape(dest).IsSequentialTwoByte());
4666 
4667   if (StringShape(dest).IsSequentialOneByte()) {
4668     WriteFixedArrayToFlat(fixed_array, static_cast<int>(length), separator,
4669                           SeqOneByteString::cast(dest).GetChars(no_gc),
4670                           dest.length());
4671   } else {
4672     DCHECK(StringShape(dest).IsSequentialTwoByte());
4673     WriteFixedArrayToFlat(fixed_array, static_cast<int>(length), separator,
4674                           SeqTwoByteString::cast(dest).GetChars(no_gc),
4675                           dest.length());
4676   }
4677   return dest.ptr();
4678 }
4679 
MakeArrayIndexHash(uint32_t value,int length)4680 uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
4681   // For array indexes mix the length into the hash as an array index could
4682   // be zero.
4683   DCHECK_GT(length, 0);
4684   DCHECK_LE(length, String::kMaxArrayIndexSize);
4685   DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
4686          (1 << String::kArrayIndexValueBits));
4687 
4688   value <<= String::ArrayIndexValueBits::kShift;
4689   value |= length << String::ArrayIndexLengthBits::kShift;
4690 
4691   DCHECK_EQ(value & String::kIsNotIntegerIndexMask, 0);
4692   DCHECK_EQ(length <= String::kMaxCachedArrayIndexLength,
4693             Name::ContainsCachedArrayIndex(value));
4694   return value;
4695 }
4696 
CacheInitialJSArrayMaps(Isolate * isolate,Handle<Context> native_context,Handle<Map> initial_map)4697 Handle<Object> CacheInitialJSArrayMaps(Isolate* isolate,
4698                                        Handle<Context> native_context,
4699                                        Handle<Map> initial_map) {
4700   // Replace all of the cached initial array maps in the native context with
4701   // the appropriate transitioned elements kind maps.
4702   Handle<Map> current_map = initial_map;
4703   ElementsKind kind = current_map->elements_kind();
4704   DCHECK_EQ(GetInitialFastElementsKind(), kind);
4705   native_context->set(Context::ArrayMapIndex(kind), *current_map,
4706                       UPDATE_WRITE_BARRIER, kReleaseStore);
4707   for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1;
4708        i < kFastElementsKindCount; ++i) {
4709     Handle<Map> new_map;
4710     ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
4711     Map maybe_elements_transition = current_map->ElementsTransitionMap(
4712         isolate, ConcurrencyMode::kNotConcurrent);
4713     if (!maybe_elements_transition.is_null()) {
4714       new_map = handle(maybe_elements_transition, isolate);
4715     } else {
4716       new_map = Map::CopyAsElementsKind(isolate, current_map, next_kind,
4717                                         INSERT_TRANSITION);
4718     }
4719     DCHECK_EQ(next_kind, new_map->elements_kind());
4720     native_context->set(Context::ArrayMapIndex(next_kind), *new_map,
4721                         UPDATE_WRITE_BARRIER, kReleaseStore);
4722     current_map = new_map;
4723   }
4724   return initial_map;
4725 }
4726 
4727 STATIC_ASSERT_FIELD_OFFSETS_EQUAL(HeapNumber::kValueOffset,
4728                                   Oddball::kToNumberRawOffset);
4729 
Initialize(Isolate * isolate,Handle<Oddball> oddball,const char * to_string,Handle<Object> to_number,const char * type_of,byte kind)4730 void Oddball::Initialize(Isolate* isolate, Handle<Oddball> oddball,
4731                          const char* to_string, Handle<Object> to_number,
4732                          const char* type_of, byte kind) {
4733   Handle<String> internalized_to_string =
4734       isolate->factory()->InternalizeUtf8String(to_string);
4735   Handle<String> internalized_type_of =
4736       isolate->factory()->InternalizeUtf8String(type_of);
4737   if (to_number->IsHeapNumber()) {
4738     oddball->set_to_number_raw_as_bits(
4739         Handle<HeapNumber>::cast(to_number)->value_as_bits(kRelaxedLoad));
4740   } else {
4741     oddball->set_to_number_raw(to_number->Number());
4742   }
4743   oddball->set_to_number(*to_number);
4744   oddball->set_to_string(*internalized_to_string);
4745   oddball->set_type_of(*internalized_type_of);
4746   oddball->set_kind(kind);
4747 }
4748 
4749 // static
GetEvalPosition(Isolate * isolate,Handle<Script> script)4750 int Script::GetEvalPosition(Isolate* isolate, Handle<Script> script) {
4751   DCHECK(script->compilation_type() == Script::COMPILATION_TYPE_EVAL);
4752   int position = script->eval_from_position();
4753   if (position < 0) {
4754     // Due to laziness, the position may not have been translated from code
4755     // offset yet, which would be encoded as negative integer. In that case,
4756     // translate and set the position.
4757     if (!script->has_eval_from_shared()) {
4758       position = 0;
4759     } else {
4760       Handle<SharedFunctionInfo> shared =
4761           handle(script->eval_from_shared(), isolate);
4762       SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate, shared);
4763       position = shared->abstract_code(isolate).SourcePosition(-position);
4764     }
4765     DCHECK_GE(position, 0);
4766     script->set_eval_from_position(position);
4767   }
4768   return position;
4769 }
4770 
4771 template <typename IsolateT>
4772 // static
InitLineEnds(IsolateT * isolate,Handle<Script> script)4773 void Script::InitLineEnds(IsolateT* isolate, Handle<Script> script) {
4774   if (!script->line_ends().IsUndefined(isolate)) return;
4775 #if V8_ENABLE_WEBASSEMBLY
4776   DCHECK(script->type() != Script::TYPE_WASM ||
4777          script->source_mapping_url().IsString());
4778 #endif  // V8_ENABLE_WEBASSEMBLY
4779 
4780   Object src_obj = script->source();
4781   if (!src_obj.IsString()) {
4782     DCHECK(src_obj.IsUndefined(isolate));
4783     script->set_line_ends(ReadOnlyRoots(isolate).empty_fixed_array());
4784   } else {
4785     DCHECK(src_obj.IsString());
4786     Handle<String> src(String::cast(src_obj), isolate);
4787     Handle<FixedArray> array = String::CalculateLineEnds(isolate, src, true);
4788     script->set_line_ends(*array);
4789   }
4790 
4791   DCHECK(script->line_ends().IsFixedArray());
4792 }
4793 
4794 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) void Script::InitLineEnds(
4795     Isolate* isolate, Handle<Script> script);
4796 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) void Script::InitLineEnds(
4797     LocalIsolate* isolate, Handle<Script> script);
4798 
GetPositionInfo(Handle<Script> script,int position,PositionInfo * info,OffsetFlag offset_flag)4799 bool Script::GetPositionInfo(Handle<Script> script, int position,
4800                              PositionInfo* info, OffsetFlag offset_flag) {
4801   bool init_line_ends = true;
4802 #if V8_ENABLE_WEBASSEMBLY
4803   // For wasm, we do not create an artificial line_ends array, but do the
4804   // translation directly.
4805   init_line_ends = script->type() != Script::TYPE_WASM;
4806 #endif  // V8_ENABLE_WEBASSEMBLY
4807   if (init_line_ends) InitLineEnds(script->GetIsolate(), script);
4808   return script->GetPositionInfo(position, info, offset_flag);
4809 }
4810 
IsUserJavaScript() const4811 bool Script::IsUserJavaScript() const { return type() == Script::TYPE_NORMAL; }
4812 
4813 #if V8_ENABLE_WEBASSEMBLY
ContainsAsmModule()4814 bool Script::ContainsAsmModule() {
4815   DisallowGarbageCollection no_gc;
4816   SharedFunctionInfo::ScriptIterator iter(this->GetIsolate(), *this);
4817   for (SharedFunctionInfo info = iter.Next(); !info.is_null();
4818        info = iter.Next()) {
4819     if (info.HasAsmWasmData()) return true;
4820   }
4821   return false;
4822 }
4823 #endif  // V8_ENABLE_WEBASSEMBLY
4824 
4825 namespace {
4826 
4827 template <typename Char>
GetPositionInfoSlowImpl(const base::Vector<Char> & source,int position,Script::PositionInfo * info)4828 bool GetPositionInfoSlowImpl(const base::Vector<Char>& source, int position,
4829                              Script::PositionInfo* info) {
4830   if (position < 0) {
4831     position = 0;
4832   }
4833   int line = 0;
4834   const auto begin = std::cbegin(source);
4835   const auto end = std::cend(source);
4836   for (auto line_begin = begin; line_begin < end;) {
4837     const auto line_end = std::find(line_begin, end, '\n');
4838     if (position <= (line_end - begin)) {
4839       info->line = line;
4840       info->column = static_cast<int>((begin + position) - line_begin);
4841       info->line_start = static_cast<int>(line_begin - begin);
4842       info->line_end = static_cast<int>(line_end - begin);
4843       return true;
4844     }
4845     ++line;
4846     line_begin = line_end + 1;
4847   }
4848   return false;
4849 }
GetPositionInfoSlow(const Script script,int position,const DisallowGarbageCollection & no_gc,Script::PositionInfo * info)4850 bool GetPositionInfoSlow(const Script script, int position,
4851                          const DisallowGarbageCollection& no_gc,
4852                          Script::PositionInfo* info) {
4853   if (!script.source().IsString()) {
4854     return false;
4855   }
4856   auto source = String::cast(script.source());
4857   const auto flat = source.GetFlatContent(no_gc);
4858   return flat.IsOneByte()
4859              ? GetPositionInfoSlowImpl(flat.ToOneByteVector(), position, info)
4860              : GetPositionInfoSlowImpl(flat.ToUC16Vector(), position, info);
4861 }
4862 
4863 }  // namespace
4864 
GetPositionInfo(int position,PositionInfo * info,OffsetFlag offset_flag) const4865 bool Script::GetPositionInfo(int position, PositionInfo* info,
4866                              OffsetFlag offset_flag) const {
4867   DisallowGarbageCollection no_gc;
4868 
4869 #if V8_ENABLE_WEBASSEMBLY
4870   // For wasm, we use the byte offset as the column.
4871   if (type() == Script::TYPE_WASM) {
4872     DCHECK_LE(0, position);
4873     wasm::NativeModule* native_module = wasm_native_module();
4874     const wasm::WasmModule* module = native_module->module();
4875     if (module->functions.size() == 0) return false;
4876     info->line = 0;
4877     info->column = position;
4878     info->line_start = module->functions[0].code.offset();
4879     info->line_end = module->functions.back().code.end_offset();
4880     return true;
4881   }
4882 #endif  // V8_ENABLE_WEBASSEMBLY
4883 
4884   if (line_ends().IsUndefined()) {
4885     // Slow mode: we do not have line_ends. We have to iterate through source.
4886     if (!GetPositionInfoSlow(*this, position, no_gc, info)) {
4887       return false;
4888     }
4889   } else {
4890     DCHECK(line_ends().IsFixedArray());
4891     FixedArray ends = FixedArray::cast(line_ends());
4892 
4893     const int ends_len = ends.length();
4894     if (ends_len == 0) return false;
4895 
4896     // Return early on invalid positions. Negative positions behave as if 0 was
4897     // passed, and positions beyond the end of the script return as failure.
4898     if (position < 0) {
4899       position = 0;
4900     } else if (position > Smi::ToInt(ends.get(ends_len - 1))) {
4901       return false;
4902     }
4903 
4904     // Determine line number by doing a binary search on the line ends array.
4905     if (Smi::ToInt(ends.get(0)) >= position) {
4906       info->line = 0;
4907       info->line_start = 0;
4908       info->column = position;
4909     } else {
4910       int left = 0;
4911       int right = ends_len - 1;
4912 
4913       while (right > 0) {
4914         DCHECK_LE(left, right);
4915         const int mid = (left + right) / 2;
4916         if (position > Smi::ToInt(ends.get(mid))) {
4917           left = mid + 1;
4918         } else if (position <= Smi::ToInt(ends.get(mid - 1))) {
4919           right = mid - 1;
4920         } else {
4921           info->line = mid;
4922           break;
4923         }
4924       }
4925       DCHECK(Smi::ToInt(ends.get(info->line)) >= position &&
4926              Smi::ToInt(ends.get(info->line - 1)) < position);
4927       info->line_start = Smi::ToInt(ends.get(info->line - 1)) + 1;
4928       info->column = position - info->line_start;
4929     }
4930 
4931     // Line end is position of the linebreak character.
4932     info->line_end = Smi::ToInt(ends.get(info->line));
4933     if (info->line_end > 0) {
4934       DCHECK(source().IsString());
4935       String src = String::cast(source());
4936       if (src.length() >= info->line_end &&
4937           src.Get(info->line_end - 1) == '\r') {
4938         info->line_end--;
4939       }
4940     }
4941   }
4942 
4943   // Add offsets if requested.
4944   if (offset_flag == WITH_OFFSET) {
4945     if (info->line == 0) {
4946       info->column += column_offset();
4947     }
4948     info->line += line_offset();
4949   }
4950 
4951   return true;
4952 }
4953 
GetColumnNumber(Handle<Script> script,int code_pos)4954 int Script::GetColumnNumber(Handle<Script> script, int code_pos) {
4955   PositionInfo info;
4956   GetPositionInfo(script, code_pos, &info, WITH_OFFSET);
4957   return info.column;
4958 }
4959 
GetColumnNumber(int code_pos) const4960 int Script::GetColumnNumber(int code_pos) const {
4961   PositionInfo info;
4962   GetPositionInfo(code_pos, &info, WITH_OFFSET);
4963   return info.column;
4964 }
4965 
GetLineNumber(Handle<Script> script,int code_pos)4966 int Script::GetLineNumber(Handle<Script> script, int code_pos) {
4967   PositionInfo info;
4968   GetPositionInfo(script, code_pos, &info, WITH_OFFSET);
4969   return info.line;
4970 }
4971 
GetLineNumber(int code_pos) const4972 int Script::GetLineNumber(int code_pos) const {
4973   PositionInfo info;
4974   GetPositionInfo(code_pos, &info, WITH_OFFSET);
4975   return info.line;
4976 }
4977 
GetNameOrSourceURL()4978 Object Script::GetNameOrSourceURL() {
4979   // Keep in sync with ScriptNameOrSourceURL in messages.js.
4980   if (!source_url().IsUndefined()) return source_url();
4981   return name();
4982 }
4983 
4984 template <typename IsolateT>
FindSharedFunctionInfo(Handle<Script> script,IsolateT * isolate,FunctionLiteral * function_literal)4985 MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
4986     Handle<Script> script, IsolateT* isolate,
4987     FunctionLiteral* function_literal) {
4988   int function_literal_id = function_literal->function_literal_id();
4989   if V8_UNLIKELY (script->type() == Script::TYPE_WEB_SNAPSHOT &&
4990                   function_literal_id >= script->shared_function_info_count()) {
4991     return FindWebSnapshotSharedFunctionInfo(script, isolate, function_literal);
4992   }
4993 
4994   CHECK_NE(function_literal_id, kFunctionLiteralIdInvalid);
4995   // If this check fails, the problem is most probably the function id
4996   // renumbering done by AstFunctionLiteralIdReindexer; in particular, that
4997   // AstTraversalVisitor doesn't recurse properly in the construct which
4998   // triggers the mismatch.
4999   CHECK_LT(function_literal_id, script->shared_function_info_count());
5000   MaybeObject shared = script->shared_function_infos().Get(function_literal_id);
5001   HeapObject heap_object;
5002   if (!shared->GetHeapObject(&heap_object) ||
5003       heap_object.IsUndefined(isolate)) {
5004     return MaybeHandle<SharedFunctionInfo>();
5005   }
5006   return handle(SharedFunctionInfo::cast(heap_object), isolate);
5007 }
5008 template MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
5009     Handle<Script> script, Isolate* isolate, FunctionLiteral* function_literal);
5010 template MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
5011     Handle<Script> script, LocalIsolate* isolate,
5012     FunctionLiteral* function_literal);
5013 
FindWebSnapshotSharedFunctionInfo(Handle<Script> script,Isolate * isolate,FunctionLiteral * function_literal)5014 MaybeHandle<SharedFunctionInfo> Script::FindWebSnapshotSharedFunctionInfo(
5015     Handle<Script> script, Isolate* isolate,
5016     FunctionLiteral* function_literal) {
5017   // We might be able to de-dupe the SFI against a SFI that was
5018   // created when deserializing the snapshot (or when calling a function which
5019   // was included in the snapshot). In that case, we can find it based on the
5020   // start position in shared_function_info_table.
5021   Handle<ObjectHashTable> shared_function_info_table = handle(
5022       ObjectHashTable::cast(script->shared_function_info_table()), isolate);
5023   {
5024     DisallowHeapAllocation no_gc;
5025     Object index_object = shared_function_info_table->Lookup(
5026         handle(Smi::FromInt(function_literal->start_position()), isolate));
5027     if (!index_object.IsTheHole()) {
5028       int index = Smi::cast(index_object).value();
5029       DCHECK_LT(index, script->shared_function_info_count());
5030       MaybeObject maybe_shared = script->shared_function_infos().Get(index);
5031       HeapObject heap_object;
5032       if (!maybe_shared->GetHeapObject(&heap_object)) {
5033         // We found the correct location but it's not filled in (e.g., the weak
5034         // pointer to the SharedFunctionInfo has been cleared). Record the
5035         // location in the FunctionLiteral, so that it will be refilled later.
5036         // SharedFunctionInfo::SetScript will write the SharedFunctionInfo in
5037         // the shared_function_infos.
5038         function_literal->set_function_literal_id(index);
5039         return MaybeHandle<SharedFunctionInfo>();
5040       }
5041       SharedFunctionInfo shared = SharedFunctionInfo::cast(heap_object);
5042       DCHECK_EQ(shared.StartPosition(), function_literal->start_position());
5043       DCHECK_EQ(shared.EndPosition(), function_literal->end_position());
5044       return handle(shared, isolate);
5045     }
5046   }
5047 
5048   // It's possible that FunctionLiterals which were processed before this one
5049   // were deduplicated against existing ones. Decrease function_literal_id to
5050   // avoid holes in shared_function_infos.
5051   int old_length = script->shared_function_info_count();
5052   int function_literal_id = old_length;
5053   function_literal->set_function_literal_id(function_literal_id);
5054 
5055   // Also add to shared_function_info_table.
5056   shared_function_info_table = ObjectHashTable::Put(
5057       shared_function_info_table,
5058       handle(Smi::FromInt(function_literal->start_position()), isolate),
5059       handle(Smi::FromInt(function_literal_id), isolate));
5060   script->set_shared_function_info_table(*shared_function_info_table);
5061 
5062   // Grow shared_function_infos if needed (we don't know the correct amount of
5063   // space needed upfront).
5064   int new_length = old_length + 1;
5065   Handle<WeakFixedArray> old_infos =
5066       handle(script->shared_function_infos(), isolate);
5067   if (new_length > old_infos->length()) {
5068     int capacity = WeakArrayList::CapacityForLength(new_length);
5069     Handle<WeakFixedArray> new_infos(
5070         isolate->factory()->NewWeakFixedArray(capacity, AllocationType::kOld));
5071     new_infos->CopyElements(isolate, 0, *old_infos, 0, old_length,
5072                             WriteBarrierMode::UPDATE_WRITE_BARRIER);
5073     script->set_shared_function_infos(*new_infos);
5074   }
5075   return MaybeHandle<SharedFunctionInfo>();
5076 }
5077 
FindWebSnapshotSharedFunctionInfo(Handle<Script> script,LocalIsolate * isolate,FunctionLiteral * function_literal)5078 MaybeHandle<SharedFunctionInfo> Script::FindWebSnapshotSharedFunctionInfo(
5079     Handle<Script> script, LocalIsolate* isolate,
5080     FunctionLiteral* function_literal) {
5081   // Off-thread serialization of web snapshots is not implemented.
5082   UNREACHABLE();
5083 }
5084 
Iterator(Isolate * isolate)5085 Script::Iterator::Iterator(Isolate* isolate)
5086     : iterator_(isolate->heap()->script_list()) {}
5087 
Next()5088 Script Script::Iterator::Next() {
5089   Object o = iterator_.Next();
5090   if (o != Object()) {
5091     return Script::cast(o);
5092   }
5093   return Script();
5094 }
5095 
5096 // static
Initialize(Handle<JSArray> array,int capacity,int length)5097 void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
5098   DCHECK_GE(capacity, 0);
5099   array->GetIsolate()->factory()->NewJSArrayStorage(
5100       array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
5101 }
5102 
SetLength(Handle<JSArray> array,uint32_t new_length)5103 Maybe<bool> JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) {
5104   // We should never end in here with a pixel or external array.
5105   DCHECK(array->AllowsSetLength());
5106   if (array->SetLengthWouldNormalize(new_length)) {
5107     JSObject::NormalizeElements(array);
5108   }
5109   return array->GetElementsAccessor()->SetLength(array, new_length);
5110 }
5111 
5112 // ES6: 9.5.2 [[SetPrototypeOf]] (V)
5113 // static
SetPrototype(Handle<JSProxy> proxy,Handle<Object> value,bool from_javascript,ShouldThrow should_throw)5114 Maybe<bool> JSProxy::SetPrototype(Handle<JSProxy> proxy, Handle<Object> value,
5115                                   bool from_javascript,
5116                                   ShouldThrow should_throw) {
5117   Isolate* isolate = proxy->GetIsolate();
5118   STACK_CHECK(isolate, Nothing<bool>());
5119   Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string();
5120   // 1. Assert: Either Type(V) is Object or Type(V) is Null.
5121   DCHECK(value->IsJSReceiver() || value->IsNull(isolate));
5122   // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
5123   Handle<Object> handler(proxy->handler(), isolate);
5124   // 3. If handler is null, throw a TypeError exception.
5125   // 4. Assert: Type(handler) is Object.
5126   if (proxy->IsRevoked()) {
5127     isolate->Throw(*isolate->factory()->NewTypeError(
5128         MessageTemplate::kProxyRevoked, trap_name));
5129     return Nothing<bool>();
5130   }
5131   // 5. Let target be the value of the [[ProxyTarget]] internal slot.
5132   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
5133   // 6. Let trap be ? GetMethod(handler, "getPrototypeOf").
5134   Handle<Object> trap;
5135   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5136       isolate, trap,
5137       Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
5138       Nothing<bool>());
5139   // 7. If trap is undefined, then return target.[[SetPrototypeOf]]().
5140   if (trap->IsUndefined(isolate)) {
5141     return JSReceiver::SetPrototype(target, value, from_javascript,
5142                                     should_throw);
5143   }
5144   // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, V»)).
5145   Handle<Object> argv[] = {target, value};
5146   Handle<Object> trap_result;
5147   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5148       isolate, trap_result,
5149       Execution::Call(isolate, trap, handler, arraysize(argv), argv),
5150       Nothing<bool>());
5151   bool bool_trap_result = trap_result->BooleanValue(isolate);
5152   // 9. If booleanTrapResult is false, return false.
5153   if (!bool_trap_result) {
5154     RETURN_FAILURE(
5155         isolate, should_throw,
5156         NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
5157   }
5158   // 10. Let extensibleTarget be ? IsExtensible(target).
5159   Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
5160   if (is_extensible.IsNothing()) return Nothing<bool>();
5161   // 11. If extensibleTarget is true, return true.
5162   if (is_extensible.FromJust()) {
5163     if (bool_trap_result) return Just(true);
5164     RETURN_FAILURE(
5165         isolate, should_throw,
5166         NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
5167   }
5168   // 12. Let targetProto be ? target.[[GetPrototypeOf]]().
5169   Handle<Object> target_proto;
5170   ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_proto,
5171                                    JSReceiver::GetPrototype(isolate, target),
5172                                    Nothing<bool>());
5173   // 13. If SameValue(V, targetProto) is false, throw a TypeError exception.
5174   if (bool_trap_result && !value->SameValue(*target_proto)) {
5175     isolate->Throw(*isolate->factory()->NewTypeError(
5176         MessageTemplate::kProxySetPrototypeOfNonExtensible));
5177     return Nothing<bool>();
5178   }
5179   // 14. Return true.
5180   return Just(true);
5181 }
5182 
SetLengthWouldNormalize(uint32_t new_length)5183 bool JSArray::SetLengthWouldNormalize(uint32_t new_length) {
5184   if (!HasFastElements()) return false;
5185   uint32_t capacity = static_cast<uint32_t>(elements().length());
5186   uint32_t new_capacity;
5187   return JSArray::SetLengthWouldNormalize(GetHeap(), new_length) &&
5188          ShouldConvertToSlowElements(*this, capacity, new_length - 1,
5189                                      &new_capacity);
5190 }
5191 
5192 const double AllocationSite::kPretenureRatio = 0.85;
5193 
ResetPretenureDecision()5194 void AllocationSite::ResetPretenureDecision() {
5195   set_pretenure_decision(kUndecided);
5196   set_memento_found_count(0);
5197   set_memento_create_count(0);
5198 }
5199 
GetAllocationType() const5200 AllocationType AllocationSite::GetAllocationType() const {
5201   PretenureDecision mode = pretenure_decision();
5202   // Zombie objects "decide" to be untenured.
5203   return mode == kTenure ? AllocationType::kOld : AllocationType::kYoung;
5204 }
5205 
IsNested()5206 bool AllocationSite::IsNested() {
5207   DCHECK(FLAG_trace_track_allocation_sites);
5208   Object current = boilerplate().GetHeap()->allocation_sites_list();
5209   while (current.IsAllocationSite()) {
5210     AllocationSite current_site = AllocationSite::cast(current);
5211     if (current_site.nested_site() == *this) {
5212       return true;
5213     }
5214     current = current_site.weak_next();
5215   }
5216   return false;
5217 }
5218 
ShouldTrack(ElementsKind from,ElementsKind to)5219 bool AllocationSite::ShouldTrack(ElementsKind from, ElementsKind to) {
5220   if (!V8_ALLOCATION_SITE_TRACKING_BOOL) return false;
5221   return IsMoreGeneralElementsKindTransition(from, to);
5222 }
5223 
PretenureDecisionName(PretenureDecision decision)5224 const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) {
5225   switch (decision) {
5226     case kUndecided:
5227       return "undecided";
5228     case kDontTenure:
5229       return "don't tenure";
5230     case kMaybeTenure:
5231       return "maybe tenure";
5232     case kTenure:
5233       return "tenure";
5234     case kZombie:
5235       return "zombie";
5236     default:
5237       UNREACHABLE();
5238   }
5239 }
5240 
5241 // static
MayHaveReadOnlyLength(Map js_array_map)5242 bool JSArray::MayHaveReadOnlyLength(Map js_array_map) {
5243   DCHECK(js_array_map.IsJSArrayMap());
5244   if (js_array_map.is_dictionary_map()) return true;
5245 
5246   // Fast path: "length" is the first fast property of arrays with non
5247   // dictionary properties. Since it's not configurable, it's guaranteed to be
5248   // the first in the descriptor array.
5249   InternalIndex first(0);
5250   DCHECK(js_array_map.instance_descriptors().GetKey(first) ==
5251          js_array_map.GetReadOnlyRoots().length_string());
5252   return js_array_map.instance_descriptors().GetDetails(first).IsReadOnly();
5253 }
5254 
HasReadOnlyLength(Handle<JSArray> array)5255 bool JSArray::HasReadOnlyLength(Handle<JSArray> array) {
5256   Map map = array->map();
5257 
5258   // If map guarantees that there can't be a read-only length, we are done.
5259   if (!MayHaveReadOnlyLength(map)) return false;
5260 
5261   // Look at the object.
5262   Isolate* isolate = array->GetIsolate();
5263   LookupIterator it(isolate, array, isolate->factory()->length_string(), array,
5264                     LookupIterator::OWN_SKIP_INTERCEPTOR);
5265   CHECK_EQ(LookupIterator::ACCESSOR, it.state());
5266   return it.IsReadOnly();
5267 }
5268 
WouldChangeReadOnlyLength(Handle<JSArray> array,uint32_t index)5269 bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array, uint32_t index) {
5270   uint32_t length = 0;
5271   CHECK(array->length().ToArrayLength(&length));
5272   if (length <= index) return HasReadOnlyLength(array);
5273   return false;
5274 }
5275 
GetMaxLengthForNewSpaceAllocation(ElementsKind kind)5276 int FixedArrayBase::GetMaxLengthForNewSpaceAllocation(ElementsKind kind) {
5277   return ((kMaxRegularHeapObjectSize - FixedArrayBase::kHeaderSize) >>
5278           ElementsKindToShiftSize(kind));
5279 }
5280 
IsCowArray() const5281 bool FixedArrayBase::IsCowArray() const {
5282   return map() == GetReadOnlyRoots().fixed_cow_array_map();
5283 }
5284 
PrivateSymbolToName() const5285 const char* Symbol::PrivateSymbolToName() const {
5286   ReadOnlyRoots roots = GetReadOnlyRoots();
5287 #define SYMBOL_CHECK_AND_PRINT(_, name) \
5288   if (*this == roots.name()) return #name;
5289   PRIVATE_SYMBOL_LIST_GENERATOR(SYMBOL_CHECK_AND_PRINT, /* not used */)
5290 #undef SYMBOL_CHECK_AND_PRINT
5291   return "UNKNOWN";
5292 }
5293 
SymbolShortPrint(std::ostream & os)5294 void Symbol::SymbolShortPrint(std::ostream& os) {
5295   os << "<Symbol:";
5296   if (!description().IsUndefined()) {
5297     os << " ";
5298     String description_as_string = String::cast(description());
5299     description_as_string.PrintUC16(os, 0, description_as_string.length());
5300   } else {
5301     os << " (" << PrivateSymbolToName() << ")";
5302   }
5303   os << ">";
5304 }
5305 
status() const5306 v8::Promise::PromiseState JSPromise::status() const {
5307   int value = flags() & StatusBits::kMask;
5308   DCHECK(value == 0 || value == 1 || value == 2);
5309   return static_cast<v8::Promise::PromiseState>(value);
5310 }
5311 
set_status(Promise::PromiseState status)5312 void JSPromise::set_status(Promise::PromiseState status) {
5313   int value = flags() & ~StatusBits::kMask;
5314   set_flags(value | status);
5315 }
5316 
5317 // static
Status(v8::Promise::PromiseState status)5318 const char* JSPromise::Status(v8::Promise::PromiseState status) {
5319   switch (status) {
5320     case v8::Promise::kFulfilled:
5321       return "fulfilled";
5322     case v8::Promise::kPending:
5323       return "pending";
5324     case v8::Promise::kRejected:
5325       return "rejected";
5326   }
5327   UNREACHABLE();
5328 }
5329 
async_task_id() const5330 int JSPromise::async_task_id() const {
5331   return AsyncTaskIdBits::decode(flags());
5332 }
5333 
set_async_task_id(int id)5334 void JSPromise::set_async_task_id(int id) {
5335   set_flags(AsyncTaskIdBits::update(flags(), id));
5336 }
5337 
5338 // static
Fulfill(Handle<JSPromise> promise,Handle<Object> value)5339 Handle<Object> JSPromise::Fulfill(Handle<JSPromise> promise,
5340                                   Handle<Object> value) {
5341   Isolate* const isolate = promise->GetIsolate();
5342 
5343   // 1. Assert: The value of promise.[[PromiseState]] is "pending".
5344   CHECK_EQ(Promise::kPending, promise->status());
5345 
5346   // 2. Let reactions be promise.[[PromiseFulfillReactions]].
5347   Handle<Object> reactions(promise->reactions(), isolate);
5348 
5349   // 3. Set promise.[[PromiseResult]] to value.
5350   // 4. Set promise.[[PromiseFulfillReactions]] to undefined.
5351   // 5. Set promise.[[PromiseRejectReactions]] to undefined.
5352   promise->set_reactions_or_result(*value);
5353 
5354   // 6. Set promise.[[PromiseState]] to "fulfilled".
5355   promise->set_status(Promise::kFulfilled);
5356 
5357   // 7. Return TriggerPromiseReactions(reactions, value).
5358   return TriggerPromiseReactions(isolate, reactions, value,
5359                                  PromiseReaction::kFulfill);
5360 }
5361 
MoveMessageToPromise(Isolate * isolate,Handle<JSPromise> promise)5362 static void MoveMessageToPromise(Isolate* isolate, Handle<JSPromise> promise) {
5363   if (!isolate->has_pending_message()) return;
5364 
5365   Handle<Object> message = handle(isolate->pending_message(), isolate);
5366   Handle<Symbol> key = isolate->factory()->promise_debug_message_symbol();
5367   Object::SetProperty(isolate, promise, key, message, StoreOrigin::kMaybeKeyed,
5368                       Just(ShouldThrow::kThrowOnError))
5369       .Assert();
5370 
5371   // The message object for a rejected promise was only stored for this purpose.
5372   // Clear it, otherwise we might leak memory.
5373   isolate->clear_pending_message();
5374 }
5375 
5376 // static
Reject(Handle<JSPromise> promise,Handle<Object> reason,bool debug_event)5377 Handle<Object> JSPromise::Reject(Handle<JSPromise> promise,
5378                                  Handle<Object> reason, bool debug_event) {
5379   Isolate* const isolate = promise->GetIsolate();
5380   DCHECK(
5381       !reinterpret_cast<v8::Isolate*>(isolate)->GetCurrentContext().IsEmpty());
5382 
5383   if (isolate->debug()->is_active()) MoveMessageToPromise(isolate, promise);
5384 
5385   if (debug_event) isolate->debug()->OnPromiseReject(promise, reason);
5386   isolate->RunAllPromiseHooks(PromiseHookType::kResolve, promise,
5387                               isolate->factory()->undefined_value());
5388 
5389   // 1. Assert: The value of promise.[[PromiseState]] is "pending".
5390   CHECK_EQ(Promise::kPending, promise->status());
5391 
5392   // 2. Let reactions be promise.[[PromiseRejectReactions]].
5393   Handle<Object> reactions(promise->reactions(), isolate);
5394 
5395   // 3. Set promise.[[PromiseResult]] to reason.
5396   // 4. Set promise.[[PromiseFulfillReactions]] to undefined.
5397   // 5. Set promise.[[PromiseRejectReactions]] to undefined.
5398   promise->set_reactions_or_result(*reason);
5399 
5400   // 6. Set promise.[[PromiseState]] to "rejected".
5401   promise->set_status(Promise::kRejected);
5402 
5403   // 7. If promise.[[PromiseIsHandled]] is false, perform
5404   //    HostPromiseRejectionTracker(promise, "reject").
5405   if (!promise->has_handler()) {
5406     isolate->ReportPromiseReject(promise, reason, kPromiseRejectWithNoHandler);
5407   }
5408 
5409   // 8. Return TriggerPromiseReactions(reactions, reason).
5410   return TriggerPromiseReactions(isolate, reactions, reason,
5411                                  PromiseReaction::kReject);
5412 }
5413 
5414 // https://tc39.es/ecma262/#sec-promise-resolve-functions
5415 // static
Resolve(Handle<JSPromise> promise,Handle<Object> resolution)5416 MaybeHandle<Object> JSPromise::Resolve(Handle<JSPromise> promise,
5417                                        Handle<Object> resolution) {
5418   Isolate* const isolate = promise->GetIsolate();
5419   DCHECK(
5420       !reinterpret_cast<v8::Isolate*>(isolate)->GetCurrentContext().IsEmpty());
5421 
5422   isolate->RunAllPromiseHooks(PromiseHookType::kResolve, promise,
5423                               isolate->factory()->undefined_value());
5424 
5425   // 7. If SameValue(resolution, promise) is true, then
5426   if (promise.is_identical_to(resolution)) {
5427     // a. Let selfResolutionError be a newly created TypeError object.
5428     Handle<Object> self_resolution_error = isolate->factory()->NewTypeError(
5429         MessageTemplate::kPromiseCyclic, resolution);
5430     // b. Return RejectPromise(promise, selfResolutionError).
5431     return Reject(promise, self_resolution_error);
5432   }
5433 
5434   // 8. If Type(resolution) is not Object, then
5435   if (!resolution->IsJSReceiver()) {
5436     // a. Return FulfillPromise(promise, resolution).
5437     return Fulfill(promise, resolution);
5438   }
5439 
5440   // 9. Let then be Get(resolution, "then").
5441   MaybeHandle<Object> then;
5442   Handle<JSReceiver> receiver(Handle<JSReceiver>::cast(resolution));
5443 
5444   // Make sure a lookup of "then" on any JSPromise whose [[Prototype]] is the
5445   // initial %PromisePrototype% yields the initial method. In addition this
5446   // protector also guards the negative lookup of "then" on the intrinsic
5447   // %ObjectPrototype%, meaning that such lookups are guaranteed to yield
5448   // undefined without triggering any side-effects.
5449   if (receiver->IsJSPromise() &&
5450       isolate->IsInAnyContext(receiver->map().prototype(),
5451                               Context::PROMISE_PROTOTYPE_INDEX) &&
5452       Protectors::IsPromiseThenLookupChainIntact(isolate)) {
5453     // We can skip the "then" lookup on {resolution} if its [[Prototype]]
5454     // is the (initial) Promise.prototype and the Promise#then protector
5455     // is intact, as that guards the lookup path for the "then" property
5456     // on JSPromise instances which have the (initial) %PromisePrototype%.
5457     then = isolate->promise_then();
5458   } else {
5459     then = JSReceiver::GetProperty(isolate, receiver,
5460                                    isolate->factory()->then_string());
5461   }
5462 
5463   // 10. If then is an abrupt completion, then
5464   Handle<Object> then_action;
5465   if (!then.ToHandle(&then_action)) {
5466     // The "then" lookup can cause termination.
5467     if (!isolate->is_catchable_by_javascript(isolate->pending_exception())) {
5468       return kNullMaybeHandle;
5469     }
5470 
5471     // a. Return RejectPromise(promise, then.[[Value]]).
5472     Handle<Object> reason(isolate->pending_exception(), isolate);
5473     isolate->clear_pending_exception();
5474     return Reject(promise, reason, false);
5475   }
5476 
5477   // 11. Let thenAction be then.[[Value]].
5478   // 12. If IsCallable(thenAction) is false, then
5479   if (!then_action->IsCallable()) {
5480     // a. Return FulfillPromise(promise, resolution).
5481     return Fulfill(promise, resolution);
5482   }
5483 
5484   // 13. Let job be NewPromiseResolveThenableJob(promise, resolution,
5485   //                                             thenAction).
5486   Handle<NativeContext> then_context;
5487   if (!JSReceiver::GetContextForMicrotask(Handle<JSReceiver>::cast(then_action))
5488            .ToHandle(&then_context)) {
5489     then_context = isolate->native_context();
5490   }
5491 
5492   Handle<PromiseResolveThenableJobTask> task =
5493       isolate->factory()->NewPromiseResolveThenableJobTask(
5494           promise, Handle<JSReceiver>::cast(resolution),
5495           Handle<JSReceiver>::cast(then_action), then_context);
5496   if (isolate->debug()->is_active() && resolution->IsJSPromise()) {
5497     // Mark the dependency of the new {promise} on the {resolution}.
5498     Object::SetProperty(isolate, resolution,
5499                         isolate->factory()->promise_handled_by_symbol(),
5500                         promise)
5501         .Check();
5502   }
5503   MicrotaskQueue* microtask_queue = then_context->microtask_queue();
5504   if (microtask_queue) microtask_queue->EnqueueMicrotask(*task);
5505 
5506   // 15. Return undefined.
5507   return isolate->factory()->undefined_value();
5508 }
5509 
5510 // static
TriggerPromiseReactions(Isolate * isolate,Handle<Object> reactions,Handle<Object> argument,PromiseReaction::Type type)5511 Handle<Object> JSPromise::TriggerPromiseReactions(Isolate* isolate,
5512                                                   Handle<Object> reactions,
5513                                                   Handle<Object> argument,
5514                                                   PromiseReaction::Type type) {
5515   CHECK(reactions->IsSmi() || reactions->IsPromiseReaction());
5516 
5517   // We need to reverse the {reactions} here, since we record them
5518   // on the JSPromise in the reverse order.
5519   {
5520     DisallowGarbageCollection no_gc;
5521     Object current = *reactions;
5522     Object reversed = Smi::zero();
5523     while (!current.IsSmi()) {
5524       Object next = PromiseReaction::cast(current).next();
5525       PromiseReaction::cast(current).set_next(reversed);
5526       reversed = current;
5527       current = next;
5528     }
5529     reactions = handle(reversed, isolate);
5530   }
5531 
5532   // Morph the {reactions} into PromiseReactionJobTasks
5533   // and push them onto the microtask queue.
5534   while (!reactions->IsSmi()) {
5535     Handle<HeapObject> task = Handle<HeapObject>::cast(reactions);
5536     Handle<PromiseReaction> reaction = Handle<PromiseReaction>::cast(task);
5537     reactions = handle(reaction->next(), isolate);
5538 
5539     // According to HTML, we use the context of the appropriate handler as the
5540     // context of the microtask. See step 3 of HTML's EnqueueJob:
5541     // https://html.spec.whatwg.org/C/#enqueuejob(queuename,-job,-arguments)
5542     Handle<NativeContext> handler_context;
5543 
5544     Handle<HeapObject> primary_handler;
5545     Handle<HeapObject> secondary_handler;
5546     if (type == PromiseReaction::kFulfill) {
5547       primary_handler = handle(reaction->fulfill_handler(), isolate);
5548       secondary_handler = handle(reaction->reject_handler(), isolate);
5549     } else {
5550       primary_handler = handle(reaction->reject_handler(), isolate);
5551       secondary_handler = handle(reaction->fulfill_handler(), isolate);
5552     }
5553 
5554     bool has_handler_context = false;
5555     if (primary_handler->IsJSReceiver()) {
5556       has_handler_context = JSReceiver::GetContextForMicrotask(
5557                                 Handle<JSReceiver>::cast(primary_handler))
5558                                 .ToHandle(&handler_context);
5559     }
5560     if (!has_handler_context && secondary_handler->IsJSReceiver()) {
5561       has_handler_context = JSReceiver::GetContextForMicrotask(
5562                                 Handle<JSReceiver>::cast(secondary_handler))
5563                                 .ToHandle(&handler_context);
5564     }
5565     if (!has_handler_context) handler_context = isolate->native_context();
5566 
5567     STATIC_ASSERT(
5568         static_cast<int>(PromiseReaction::kSize) ==
5569         static_cast<int>(
5570             PromiseReactionJobTask::kSizeOfAllPromiseReactionJobTasks));
5571     if (type == PromiseReaction::kFulfill) {
5572       task->set_map(
5573           ReadOnlyRoots(isolate).promise_fulfill_reaction_job_task_map(),
5574           kReleaseStore);
5575       Handle<PromiseFulfillReactionJobTask>::cast(task)->set_argument(
5576           *argument);
5577       Handle<PromiseFulfillReactionJobTask>::cast(task)->set_context(
5578           *handler_context);
5579       STATIC_ASSERT(
5580           static_cast<int>(PromiseReaction::kFulfillHandlerOffset) ==
5581           static_cast<int>(PromiseFulfillReactionJobTask::kHandlerOffset));
5582       STATIC_ASSERT(
5583           static_cast<int>(PromiseReaction::kPromiseOrCapabilityOffset) ==
5584           static_cast<int>(
5585               PromiseFulfillReactionJobTask::kPromiseOrCapabilityOffset));
5586       STATIC_ASSERT(
5587           static_cast<int>(
5588               PromiseReaction::kContinuationPreservedEmbedderDataOffset) ==
5589           static_cast<int>(PromiseFulfillReactionJobTask::
5590                                kContinuationPreservedEmbedderDataOffset));
5591     } else {
5592       DisallowGarbageCollection no_gc;
5593       task->set_map(
5594           ReadOnlyRoots(isolate).promise_reject_reaction_job_task_map(),
5595           kReleaseStore);
5596       Handle<PromiseRejectReactionJobTask>::cast(task)->set_argument(*argument);
5597       Handle<PromiseRejectReactionJobTask>::cast(task)->set_context(
5598           *handler_context);
5599       Handle<PromiseRejectReactionJobTask>::cast(task)->set_handler(
5600           *primary_handler);
5601       STATIC_ASSERT(
5602           static_cast<int>(PromiseReaction::kPromiseOrCapabilityOffset) ==
5603           static_cast<int>(
5604               PromiseRejectReactionJobTask::kPromiseOrCapabilityOffset));
5605       STATIC_ASSERT(
5606           static_cast<int>(
5607               PromiseReaction::kContinuationPreservedEmbedderDataOffset) ==
5608           static_cast<int>(PromiseRejectReactionJobTask::
5609                                kContinuationPreservedEmbedderDataOffset));
5610     }
5611 
5612     MicrotaskQueue* microtask_queue = handler_context->microtask_queue();
5613     if (microtask_queue) {
5614       microtask_queue->EnqueueMicrotask(
5615           *Handle<PromiseReactionJobTask>::cast(task));
5616     }
5617   }
5618 
5619   return isolate->factory()->undefined_value();
5620 }
5621 
5622 template <typename Derived, typename Shape>
IteratePrefix(ObjectVisitor * v)5623 void HashTable<Derived, Shape>::IteratePrefix(ObjectVisitor* v) {
5624   BodyDescriptorBase::IteratePointers(*this, 0, kElementsStartOffset, v);
5625 }
5626 
5627 template <typename Derived, typename Shape>
IterateElements(ObjectVisitor * v)5628 void HashTable<Derived, Shape>::IterateElements(ObjectVisitor* v) {
5629   BodyDescriptorBase::IteratePointers(*this, kElementsStartOffset,
5630                                       SizeFor(length()), v);
5631 }
5632 
5633 template <typename Derived, typename Shape>
5634 template <typename IsolateT>
New(IsolateT * isolate,int at_least_space_for,AllocationType allocation,MinimumCapacity capacity_option)5635 Handle<Derived> HashTable<Derived, Shape>::New(
5636     IsolateT* isolate, int at_least_space_for, AllocationType allocation,
5637     MinimumCapacity capacity_option) {
5638   DCHECK_LE(0, at_least_space_for);
5639   DCHECK_IMPLIES(capacity_option == USE_CUSTOM_MINIMUM_CAPACITY,
5640                  base::bits::IsPowerOfTwo(at_least_space_for));
5641 
5642   int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
5643                      ? at_least_space_for
5644                      : ComputeCapacity(at_least_space_for);
5645   if (capacity > HashTable::kMaxCapacity) {
5646     isolate->FatalProcessOutOfHeapMemory("invalid table size");
5647   }
5648   return NewInternal(isolate, capacity, allocation);
5649 }
5650 
5651 template <typename Derived, typename Shape>
5652 template <typename IsolateT>
NewInternal(IsolateT * isolate,int capacity,AllocationType allocation)5653 Handle<Derived> HashTable<Derived, Shape>::NewInternal(
5654     IsolateT* isolate, int capacity, AllocationType allocation) {
5655   auto* factory = isolate->factory();
5656   int length = EntryToIndex(InternalIndex(capacity));
5657   Handle<FixedArray> array = factory->NewFixedArrayWithMap(
5658       Derived::GetMap(ReadOnlyRoots(isolate)), length, allocation);
5659   Handle<Derived> table = Handle<Derived>::cast(array);
5660 
5661   table->SetNumberOfElements(0);
5662   table->SetNumberOfDeletedElements(0);
5663   table->SetCapacity(capacity);
5664   return table;
5665 }
5666 
5667 template <typename Derived, typename Shape>
Rehash(PtrComprCageBase cage_base,Derived new_table)5668 void HashTable<Derived, Shape>::Rehash(PtrComprCageBase cage_base,
5669                                        Derived new_table) {
5670   DisallowGarbageCollection no_gc;
5671   WriteBarrierMode mode = new_table.GetWriteBarrierMode(no_gc);
5672 
5673   DCHECK_LT(NumberOfElements(), new_table.Capacity());
5674 
5675   // Copy prefix to new array.
5676   for (int i = kPrefixStartIndex; i < kElementsStartIndex; i++) {
5677     new_table.set(i, get(cage_base, i), mode);
5678   }
5679 
5680   // Rehash the elements.
5681   ReadOnlyRoots roots = GetReadOnlyRoots(cage_base);
5682   for (InternalIndex i : this->IterateEntries()) {
5683     uint32_t from_index = EntryToIndex(i);
5684     Object k = this->get(cage_base, from_index);
5685     if (!IsKey(roots, k)) continue;
5686     uint32_t hash = Shape::HashForObject(roots, k);
5687     uint32_t insertion_index =
5688         EntryToIndex(new_table.FindInsertionEntry(cage_base, roots, hash));
5689     new_table.set_key(insertion_index, get(cage_base, from_index), mode);
5690     for (int j = 1; j < Shape::kEntrySize; j++) {
5691       new_table.set(insertion_index + j, get(cage_base, from_index + j), mode);
5692     }
5693   }
5694   new_table.SetNumberOfElements(NumberOfElements());
5695   new_table.SetNumberOfDeletedElements(0);
5696 }
5697 
5698 template <typename Derived, typename Shape>
EntryForProbe(ReadOnlyRoots roots,Object k,int probe,InternalIndex expected)5699 InternalIndex HashTable<Derived, Shape>::EntryForProbe(ReadOnlyRoots roots,
5700                                                        Object k, int probe,
5701                                                        InternalIndex expected) {
5702   uint32_t hash = Shape::HashForObject(roots, k);
5703   uint32_t capacity = this->Capacity();
5704   InternalIndex entry = FirstProbe(hash, capacity);
5705   for (int i = 1; i < probe; i++) {
5706     if (entry == expected) return expected;
5707     entry = NextProbe(entry, i, capacity);
5708   }
5709   return entry;
5710 }
5711 
5712 template <typename Derived, typename Shape>
Swap(InternalIndex entry1,InternalIndex entry2,WriteBarrierMode mode)5713 void HashTable<Derived, Shape>::Swap(InternalIndex entry1, InternalIndex entry2,
5714                                      WriteBarrierMode mode) {
5715   int index1 = EntryToIndex(entry1);
5716   int index2 = EntryToIndex(entry2);
5717   Object temp[Shape::kEntrySize];
5718   Derived* self = static_cast<Derived*>(this);
5719   for (int j = 0; j < Shape::kEntrySize; j++) {
5720     temp[j] = get(index1 + j);
5721   }
5722   self->set_key(index1, get(index2), mode);
5723   for (int j = 1; j < Shape::kEntrySize; j++) {
5724     set(index1 + j, get(index2 + j), mode);
5725   }
5726   self->set_key(index2, temp[0], mode);
5727   for (int j = 1; j < Shape::kEntrySize; j++) {
5728     set(index2 + j, temp[j], mode);
5729   }
5730 }
5731 
5732 template <typename Derived, typename Shape>
Rehash(PtrComprCageBase cage_base)5733 void HashTable<Derived, Shape>::Rehash(PtrComprCageBase cage_base) {
5734   DisallowGarbageCollection no_gc;
5735   WriteBarrierMode mode = GetWriteBarrierMode(no_gc);
5736   ReadOnlyRoots roots = GetReadOnlyRoots(cage_base);
5737   uint32_t capacity = Capacity();
5738   bool done = false;
5739   for (int probe = 1; !done; probe++) {
5740     // All elements at entries given by one of the first _probe_ probes
5741     // are placed correctly. Other elements might need to be moved.
5742     done = true;
5743     for (InternalIndex current(0); current.raw_value() < capacity;
5744          /* {current} is advanced manually below, when appropriate.*/) {
5745       Object current_key = KeyAt(cage_base, current);
5746       if (!IsKey(roots, current_key)) {
5747         ++current;  // Advance to next entry.
5748         continue;
5749       }
5750       InternalIndex target = EntryForProbe(roots, current_key, probe, current);
5751       if (current == target) {
5752         ++current;  // Advance to next entry.
5753         continue;
5754       }
5755       Object target_key = KeyAt(cage_base, target);
5756       if (!IsKey(roots, target_key) ||
5757           EntryForProbe(roots, target_key, probe, target) != target) {
5758         // Put the current element into the correct position.
5759         Swap(current, target, mode);
5760         // The other element will be processed on the next iteration,
5761         // so don't advance {current} here!
5762       } else {
5763         // The place for the current element is occupied. Leave the element
5764         // for the next probe.
5765         done = false;
5766         ++current;  // Advance to next entry.
5767       }
5768     }
5769   }
5770   // Wipe deleted entries.
5771   Object the_hole = roots.the_hole_value();
5772   HeapObject undefined = roots.undefined_value();
5773   Derived* self = static_cast<Derived*>(this);
5774   for (InternalIndex current : InternalIndex::Range(capacity)) {
5775     if (KeyAt(cage_base, current) == the_hole) {
5776       self->set_key(EntryToIndex(current) + kEntryKeyIndex, undefined,
5777                     SKIP_WRITE_BARRIER);
5778     }
5779   }
5780   SetNumberOfDeletedElements(0);
5781 }
5782 
5783 template <typename Derived, typename Shape>
5784 template <typename IsolateT>
EnsureCapacity(IsolateT * isolate,Handle<Derived> table,int n,AllocationType allocation)5785 Handle<Derived> HashTable<Derived, Shape>::EnsureCapacity(
5786     IsolateT* isolate, Handle<Derived> table, int n,
5787     AllocationType allocation) {
5788   if (table->HasSufficientCapacityToAdd(n)) return table;
5789 
5790   int capacity = table->Capacity();
5791   int new_nof = table->NumberOfElements() + n;
5792 
5793   bool should_pretenure = allocation == AllocationType::kOld ||
5794                           ((capacity > kMinCapacityForPretenure) &&
5795                            !Heap::InYoungGeneration(*table));
5796   Handle<Derived> new_table = HashTable::New(
5797       isolate, new_nof,
5798       should_pretenure ? AllocationType::kOld : AllocationType::kYoung);
5799 
5800   table->Rehash(isolate, *new_table);
5801   return new_table;
5802 }
5803 
5804 template <typename Derived, typename Shape>
HasSufficientCapacityToAdd(int number_of_additional_elements)5805 bool HashTable<Derived, Shape>::HasSufficientCapacityToAdd(
5806     int number_of_additional_elements) {
5807   return HasSufficientCapacityToAdd(Capacity(), NumberOfElements(),
5808                                     NumberOfDeletedElements(),
5809                                     number_of_additional_elements);
5810 }
5811 
5812 // static
5813 template <typename Derived, typename Shape>
HasSufficientCapacityToAdd(int capacity,int number_of_elements,int number_of_deleted_elements,int number_of_additional_elements)5814 bool HashTable<Derived, Shape>::HasSufficientCapacityToAdd(
5815     int capacity, int number_of_elements, int number_of_deleted_elements,
5816     int number_of_additional_elements) {
5817   int nof = number_of_elements + number_of_additional_elements;
5818   // Return true if:
5819   //   50% is still free after adding number_of_additional_elements elements and
5820   //   at most 50% of the free elements are deleted elements.
5821   if ((nof < capacity) &&
5822       ((number_of_deleted_elements <= (capacity - nof) / 2))) {
5823     int needed_free = nof / 2;
5824     if (nof + needed_free <= capacity) return true;
5825   }
5826   return false;
5827 }
5828 
5829 // static
5830 template <typename Derived, typename Shape>
ComputeCapacityWithShrink(int current_capacity,int at_least_room_for)5831 int HashTable<Derived, Shape>::ComputeCapacityWithShrink(
5832     int current_capacity, int at_least_room_for) {
5833   // Shrink to fit the number of elements if only a quarter of the
5834   // capacity is filled with elements.
5835   if (at_least_room_for > (current_capacity / 4)) return current_capacity;
5836   // Recalculate the smaller capacity actually needed.
5837   int new_capacity = ComputeCapacity(at_least_room_for);
5838   DCHECK_GE(new_capacity, at_least_room_for);
5839   // Don't go lower than room for {kMinShrinkCapacity} elements.
5840   if (new_capacity < Derived::kMinShrinkCapacity) return current_capacity;
5841   return new_capacity;
5842 }
5843 
5844 // static
5845 template <typename Derived, typename Shape>
Shrink(Isolate * isolate,Handle<Derived> table,int additional_capacity)5846 Handle<Derived> HashTable<Derived, Shape>::Shrink(Isolate* isolate,
5847                                                   Handle<Derived> table,
5848                                                   int additional_capacity) {
5849   int new_capacity = ComputeCapacityWithShrink(
5850       table->Capacity(), table->NumberOfElements() + additional_capacity);
5851   if (new_capacity == table->Capacity()) return table;
5852   DCHECK_GE(new_capacity, Derived::kMinShrinkCapacity);
5853 
5854   bool pretenure = (new_capacity > kMinCapacityForPretenure) &&
5855                    !Heap::InYoungGeneration(*table);
5856   Handle<Derived> new_table =
5857       HashTable::New(isolate, new_capacity,
5858                      pretenure ? AllocationType::kOld : AllocationType::kYoung,
5859                      USE_CUSTOM_MINIMUM_CAPACITY);
5860 
5861   table->Rehash(isolate, *new_table);
5862   return new_table;
5863 }
5864 
5865 template <typename Derived, typename Shape>
FindInsertionEntry(PtrComprCageBase cage_base,ReadOnlyRoots roots,uint32_t hash)5866 InternalIndex HashTable<Derived, Shape>::FindInsertionEntry(
5867     PtrComprCageBase cage_base, ReadOnlyRoots roots, uint32_t hash) {
5868   uint32_t capacity = Capacity();
5869   uint32_t count = 1;
5870   // EnsureCapacity will guarantee the hash table is never full.
5871   for (InternalIndex entry = FirstProbe(hash, capacity);;
5872        entry = NextProbe(entry, count++, capacity)) {
5873     if (!IsKey(roots, KeyAt(cage_base, entry))) return entry;
5874   }
5875 }
5876 
5877 template <typename Derived, typename Shape>
FindInsertionEntry(Isolate * isolate,uint32_t hash)5878 InternalIndex HashTable<Derived, Shape>::FindInsertionEntry(Isolate* isolate,
5879                                                             uint32_t hash) {
5880   return FindInsertionEntry(isolate, ReadOnlyRoots(isolate), hash);
5881 }
5882 
5883 base::Optional<PropertyCell>
TryFindPropertyCellForConcurrentLookupIterator(Isolate * isolate,Handle<Name> name,RelaxedLoadTag tag)5884 GlobalDictionary::TryFindPropertyCellForConcurrentLookupIterator(
5885     Isolate* isolate, Handle<Name> name, RelaxedLoadTag tag) {
5886   // This reimplements HashTable::FindEntry for use in a concurrent setting.
5887   // 1) Atomic loads.
5888   // 2) IsPendingAllocation checks.
5889   // 3) Return the PropertyCell value instead of the InternalIndex to avoid a
5890   //   repeated load (unsafe with concurrent modifications).
5891 
5892   DisallowGarbageCollection no_gc;
5893   PtrComprCageBase cage_base{isolate};
5894   ReadOnlyRoots roots(isolate);
5895   const int32_t hash = ShapeT::Hash(roots, name);
5896   const uint32_t capacity = Capacity();
5897   uint32_t count = 1;
5898   Object undefined = roots.undefined_value();
5899   Object the_hole = roots.the_hole_value();
5900   // EnsureCapacity will guarantee the hash table is never full.
5901   for (InternalIndex entry = FirstProbe(hash, capacity);;
5902        entry = NextProbe(entry, count++, capacity)) {
5903     Object element = KeyAt(cage_base, entry, kRelaxedLoad);
5904     if (isolate->heap()->IsPendingAllocation(element)) return {};
5905     if (element == undefined) return {};
5906     if (ShapeT::kMatchNeedsHoleCheck && element == the_hole) continue;
5907     if (!ShapeT::IsMatch(name, element)) continue;
5908     CHECK(element.IsPropertyCell(cage_base));
5909     return PropertyCell::cast(element);
5910   }
5911 }
5912 
New(Isolate * isolate)5913 Handle<StringSet> StringSet::New(Isolate* isolate) {
5914   return HashTable::New(isolate, 0);
5915 }
5916 
Add(Isolate * isolate,Handle<StringSet> stringset,Handle<String> name)5917 Handle<StringSet> StringSet::Add(Isolate* isolate, Handle<StringSet> stringset,
5918                                  Handle<String> name) {
5919   if (!stringset->Has(isolate, name)) {
5920     stringset = EnsureCapacity(isolate, stringset);
5921     uint32_t hash = ShapeT::Hash(ReadOnlyRoots(isolate), *name);
5922     InternalIndex entry = stringset->FindInsertionEntry(isolate, hash);
5923     stringset->set(EntryToIndex(entry), *name);
5924     stringset->ElementAdded();
5925   }
5926   return stringset;
5927 }
5928 
Has(Isolate * isolate,Handle<String> name)5929 bool StringSet::Has(Isolate* isolate, Handle<String> name) {
5930   return FindEntry(isolate, *name).is_found();
5931 }
5932 
Add(Isolate * isolate,Handle<ObjectHashSet> set,Handle<Object> key)5933 Handle<ObjectHashSet> ObjectHashSet::Add(Isolate* isolate,
5934                                          Handle<ObjectHashSet> set,
5935                                          Handle<Object> key) {
5936   int32_t hash = key->GetOrCreateHash(isolate).value();
5937   if (!set->Has(isolate, key, hash)) {
5938     set = EnsureCapacity(isolate, set);
5939     InternalIndex entry = set->FindInsertionEntry(isolate, hash);
5940     set->set(EntryToIndex(entry), *key);
5941     set->ElementAdded();
5942   }
5943   return set;
5944 }
5945 
5946 template <typename Derived, typename Shape>
5947 template <typename IsolateT>
New(IsolateT * isolate,int at_least_space_for,AllocationType allocation,MinimumCapacity capacity_option)5948 Handle<Derived> BaseNameDictionary<Derived, Shape>::New(
5949     IsolateT* isolate, int at_least_space_for, AllocationType allocation,
5950     MinimumCapacity capacity_option) {
5951   DCHECK_LE(0, at_least_space_for);
5952   Handle<Derived> dict = Dictionary<Derived, Shape>::New(
5953       isolate, at_least_space_for, allocation, capacity_option);
5954   dict->SetHash(PropertyArray::kNoHashSentinel);
5955   dict->set_next_enumeration_index(PropertyDetails::kInitialIndex);
5956   return dict;
5957 }
5958 
5959 template <typename Derived, typename Shape>
NextEnumerationIndex(Isolate * isolate,Handle<Derived> dictionary)5960 int BaseNameDictionary<Derived, Shape>::NextEnumerationIndex(
5961     Isolate* isolate, Handle<Derived> dictionary) {
5962   int index = dictionary->next_enumeration_index();
5963   // Check whether the next enumeration index is valid.
5964   if (!PropertyDetails::IsValidIndex(index)) {
5965     // If not, we generate new indices for the properties.
5966     Handle<FixedArray> iteration_order = IterationIndices(isolate, dictionary);
5967     int length = iteration_order->length();
5968     DCHECK_LE(length, dictionary->NumberOfElements());
5969 
5970     // Iterate over the dictionary using the enumeration order and update
5971     // the dictionary with new enumeration indices.
5972     for (int i = 0; i < length; i++) {
5973       InternalIndex index(Smi::ToInt(iteration_order->get(i)));
5974       DCHECK(dictionary->IsKey(dictionary->GetReadOnlyRoots(),
5975                                dictionary->KeyAt(isolate, index)));
5976 
5977       int enum_index = PropertyDetails::kInitialIndex + i;
5978 
5979       PropertyDetails details = dictionary->DetailsAt(index);
5980       PropertyDetails new_details = details.set_index(enum_index);
5981       dictionary->DetailsAtPut(index, new_details);
5982     }
5983 
5984     index = PropertyDetails::kInitialIndex + length;
5985   }
5986 
5987   // Don't update the next enumeration index here, since we might be looking at
5988   // an immutable empty dictionary.
5989   return index;
5990 }
5991 
5992 template <typename Derived, typename Shape>
DeleteEntry(Isolate * isolate,Handle<Derived> dictionary,InternalIndex entry)5993 Handle<Derived> Dictionary<Derived, Shape>::DeleteEntry(
5994     Isolate* isolate, Handle<Derived> dictionary, InternalIndex entry) {
5995   DCHECK(Shape::kEntrySize != 3 ||
5996          dictionary->DetailsAt(entry).IsConfigurable());
5997   dictionary->ClearEntry(entry);
5998   dictionary->ElementRemoved();
5999   return Shrink(isolate, dictionary);
6000 }
6001 
6002 template <typename Derived, typename Shape>
AtPut(Isolate * isolate,Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details)6003 Handle<Derived> Dictionary<Derived, Shape>::AtPut(Isolate* isolate,
6004                                                   Handle<Derived> dictionary,
6005                                                   Key key, Handle<Object> value,
6006                                                   PropertyDetails details) {
6007   InternalIndex entry = dictionary->FindEntry(isolate, key);
6008 
6009   // If the entry is present set the value;
6010   if (entry.is_not_found()) {
6011     return Derived::Add(isolate, dictionary, key, value, details);
6012   }
6013 
6014   // We don't need to copy over the enumeration index.
6015   dictionary->ValueAtPut(entry, *value);
6016   if (Shape::kEntrySize == 3) dictionary->DetailsAtPut(entry, details);
6017   return dictionary;
6018 }
6019 
6020 template <typename Derived, typename Shape>
6021 template <typename IsolateT>
6022 Handle<Derived>
AddNoUpdateNextEnumerationIndex(IsolateT * isolate,Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details,InternalIndex * entry_out)6023 BaseNameDictionary<Derived, Shape>::AddNoUpdateNextEnumerationIndex(
6024     IsolateT* isolate, Handle<Derived> dictionary, Key key,
6025     Handle<Object> value, PropertyDetails details, InternalIndex* entry_out) {
6026   // Insert element at empty or deleted entry.
6027   return Dictionary<Derived, Shape>::Add(isolate, dictionary, key, value,
6028                                          details, entry_out);
6029 }
6030 
6031 template <typename Derived, typename Shape>
Add(Isolate * isolate,Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details,InternalIndex * entry_out)6032 Handle<Derived> BaseNameDictionary<Derived, Shape>::Add(
6033     Isolate* isolate, Handle<Derived> dictionary, Key key, Handle<Object> value,
6034     PropertyDetails details, InternalIndex* entry_out) {
6035   // Insert element at empty or deleted entry
6036   DCHECK_EQ(0, details.dictionary_index());
6037   // Assign an enumeration index to the property and update
6038   // SetNextEnumerationIndex.
6039   int index = Derived::NextEnumerationIndex(isolate, dictionary);
6040   details = details.set_index(index);
6041   dictionary = AddNoUpdateNextEnumerationIndex(isolate, dictionary, key, value,
6042                                                details, entry_out);
6043   // Update enumeration index here in order to avoid potential modification of
6044   // the canonical empty dictionary which lives in read only space.
6045   dictionary->set_next_enumeration_index(index + 1);
6046   return dictionary;
6047 }
6048 
6049 template <typename Derived, typename Shape>
6050 template <typename IsolateT>
Add(IsolateT * isolate,Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details,InternalIndex * entry_out)6051 Handle<Derived> Dictionary<Derived, Shape>::Add(IsolateT* isolate,
6052                                                 Handle<Derived> dictionary,
6053                                                 Key key, Handle<Object> value,
6054                                                 PropertyDetails details,
6055                                                 InternalIndex* entry_out) {
6056   ReadOnlyRoots roots(isolate);
6057   uint32_t hash = Shape::Hash(roots, key);
6058   // Validate that the key is absent.
6059   SLOW_DCHECK(dictionary->FindEntry(isolate, key).is_not_found());
6060   // Check whether the dictionary should be extended.
6061   dictionary = Derived::EnsureCapacity(isolate, dictionary);
6062 
6063   // Compute the key object.
6064   Handle<Object> k = Shape::AsHandle(isolate, key);
6065 
6066   InternalIndex entry = dictionary->FindInsertionEntry(isolate, roots, hash);
6067   dictionary->SetEntry(entry, *k, *value, details);
6068   DCHECK(dictionary->KeyAt(isolate, entry).IsNumber() ||
6069          Shape::Unwrap(dictionary->KeyAt(isolate, entry)).IsUniqueName());
6070   dictionary->ElementAdded();
6071   if (entry_out) *entry_out = entry;
6072   return dictionary;
6073 }
6074 
6075 template <typename Derived, typename Shape>
ShallowCopy(Isolate * isolate,Handle<Derived> dictionary)6076 Handle<Derived> Dictionary<Derived, Shape>::ShallowCopy(
6077     Isolate* isolate, Handle<Derived> dictionary) {
6078   return Handle<Derived>::cast(isolate->factory()->CopyFixedArrayWithMap(
6079       dictionary, Derived::GetMap(ReadOnlyRoots(isolate))));
6080 }
6081 
6082 // static
Set(Isolate * isolate,Handle<SimpleNumberDictionary> dictionary,uint32_t key,Handle<Object> value)6083 Handle<SimpleNumberDictionary> SimpleNumberDictionary::Set(
6084     Isolate* isolate, Handle<SimpleNumberDictionary> dictionary, uint32_t key,
6085     Handle<Object> value) {
6086   return AtPut(isolate, dictionary, key, value, PropertyDetails::Empty());
6087 }
6088 
UpdateMaxNumberKey(uint32_t key,Handle<JSObject> dictionary_holder)6089 void NumberDictionary::UpdateMaxNumberKey(uint32_t key,
6090                                           Handle<JSObject> dictionary_holder) {
6091   DisallowGarbageCollection no_gc;
6092   // If the dictionary requires slow elements an element has already
6093   // been added at a high index.
6094   if (requires_slow_elements()) return;
6095   // Check if this index is high enough that we should require slow
6096   // elements.
6097   if (key > kRequiresSlowElementsLimit) {
6098     if (!dictionary_holder.is_null()) {
6099       dictionary_holder->RequireSlowElements(*this);
6100     }
6101     set_requires_slow_elements();
6102     return;
6103   }
6104   // Update max key value.
6105   Object max_index_object = get(kMaxNumberKeyIndex);
6106   if (!max_index_object.IsSmi() || max_number_key() < key) {
6107     FixedArray::set(kMaxNumberKeyIndex,
6108                     Smi::FromInt(key << kRequiresSlowElementsTagSize));
6109   }
6110 }
6111 
Set(Isolate * isolate,Handle<NumberDictionary> dictionary,uint32_t key,Handle<Object> value,Handle<JSObject> dictionary_holder,PropertyDetails details)6112 Handle<NumberDictionary> NumberDictionary::Set(
6113     Isolate* isolate, Handle<NumberDictionary> dictionary, uint32_t key,
6114     Handle<Object> value, Handle<JSObject> dictionary_holder,
6115     PropertyDetails details) {
6116   // We could call Set with empty dictionaries. UpdateMaxNumberKey doesn't
6117   // expect empty dictionaries so make sure to call AtPut that correctly handles
6118   // them by creating new dictionary when required.
6119   Handle<NumberDictionary> new_dictionary =
6120       AtPut(isolate, dictionary, key, value, details);
6121   new_dictionary->UpdateMaxNumberKey(key, dictionary_holder);
6122   return new_dictionary;
6123 }
6124 
CopyValuesTo(FixedArray elements)6125 void NumberDictionary::CopyValuesTo(FixedArray elements) {
6126   ReadOnlyRoots roots = GetReadOnlyRoots();
6127   int pos = 0;
6128   DisallowGarbageCollection no_gc;
6129   WriteBarrierMode mode = elements.GetWriteBarrierMode(no_gc);
6130   for (InternalIndex i : this->IterateEntries()) {
6131     Object k;
6132     if (this->ToKey(roots, i, &k)) {
6133       elements.set(pos++, this->ValueAt(i), mode);
6134     }
6135   }
6136   DCHECK_EQ(pos, elements.length());
6137 }
6138 
6139 template <typename Derived, typename Shape>
NumberOfEnumerableProperties()6140 int Dictionary<Derived, Shape>::NumberOfEnumerableProperties() {
6141   ReadOnlyRoots roots = this->GetReadOnlyRoots();
6142   int result = 0;
6143   for (InternalIndex i : this->IterateEntries()) {
6144     Object k;
6145     if (!this->ToKey(roots, i, &k)) continue;
6146     if (k.FilterKey(ENUMERABLE_STRINGS)) continue;
6147     PropertyDetails details = this->DetailsAt(i);
6148     PropertyAttributes attr = details.attributes();
6149     if ((attr & ONLY_ENUMERABLE) == 0) result++;
6150   }
6151   return result;
6152 }
6153 
6154 template <typename Derived, typename Shape>
IterationIndices(Isolate * isolate,Handle<Derived> dictionary)6155 Handle<FixedArray> BaseNameDictionary<Derived, Shape>::IterationIndices(
6156     Isolate* isolate, Handle<Derived> dictionary) {
6157   Handle<FixedArray> array =
6158       isolate->factory()->NewFixedArray(dictionary->NumberOfElements());
6159   ReadOnlyRoots roots(isolate);
6160   int array_size = 0;
6161   {
6162     DisallowGarbageCollection no_gc;
6163     Derived raw_dictionary = *dictionary;
6164     for (InternalIndex i : dictionary->IterateEntries()) {
6165       Object k;
6166       if (!raw_dictionary.ToKey(roots, i, &k)) continue;
6167       array->set(array_size++, Smi::FromInt(i.as_int()));
6168     }
6169 
6170     // The global dictionary doesn't track its deletion count, so we may iterate
6171     // fewer entries than the count of elements claimed by the dictionary.
6172     if (std::is_same<Derived, GlobalDictionary>::value) {
6173       DCHECK_LE(array_size, dictionary->NumberOfElements());
6174     } else {
6175       DCHECK_EQ(array_size, dictionary->NumberOfElements());
6176     }
6177 
6178     EnumIndexComparator<Derived> cmp(raw_dictionary);
6179     // Use AtomicSlot wrapper to ensure that std::sort uses atomic load and
6180     // store operations that are safe for concurrent marking.
6181     AtomicSlot start(array->GetFirstElementAddress());
6182     std::sort(start, start + array_size, cmp);
6183   }
6184   return FixedArray::ShrinkOrEmpty(isolate, array, array_size);
6185 }
6186 
6187 // Backwards lookup (slow).
6188 template <typename Derived, typename Shape>
SlowReverseLookup(Object value)6189 Object Dictionary<Derived, Shape>::SlowReverseLookup(Object value) {
6190   Derived dictionary = Derived::cast(*this);
6191   ReadOnlyRoots roots = dictionary.GetReadOnlyRoots();
6192   for (InternalIndex i : dictionary.IterateEntries()) {
6193     Object k;
6194     if (!dictionary.ToKey(roots, i, &k)) continue;
6195     Object e = dictionary.ValueAt(i);
6196     if (e == value) return k;
6197   }
6198   return roots.undefined_value();
6199 }
6200 
6201 template <typename Derived, typename Shape>
FillEntriesWithHoles(Handle<Derived> table)6202 void ObjectHashTableBase<Derived, Shape>::FillEntriesWithHoles(
6203     Handle<Derived> table) {
6204   int length = table->length();
6205   for (int i = Derived::EntryToIndex(InternalIndex(0)); i < length; i++) {
6206     table->set_the_hole(i);
6207   }
6208 }
6209 
6210 template <typename Derived, typename Shape>
Lookup(PtrComprCageBase cage_base,Handle<Object> key,int32_t hash)6211 Object ObjectHashTableBase<Derived, Shape>::Lookup(PtrComprCageBase cage_base,
6212                                                    Handle<Object> key,
6213                                                    int32_t hash) {
6214   DisallowGarbageCollection no_gc;
6215   ReadOnlyRoots roots = this->GetReadOnlyRoots(cage_base);
6216   DCHECK(this->IsKey(roots, *key));
6217 
6218   InternalIndex entry = this->FindEntry(cage_base, roots, key, hash);
6219   if (entry.is_not_found()) return roots.the_hole_value();
6220   return this->get(Derived::EntryToIndex(entry) + 1);
6221 }
6222 
6223 template <typename Derived, typename Shape>
Lookup(Handle<Object> key)6224 Object ObjectHashTableBase<Derived, Shape>::Lookup(Handle<Object> key) {
6225   DisallowGarbageCollection no_gc;
6226 
6227   PtrComprCageBase cage_base = GetPtrComprCageBase(*this);
6228   ReadOnlyRoots roots = this->GetReadOnlyRoots(cage_base);
6229   DCHECK(this->IsKey(roots, *key));
6230 
6231   // If the object does not have an identity hash, it was never used as a key.
6232   Object hash = key->GetHash();
6233   if (hash.IsUndefined(roots)) {
6234     return roots.the_hole_value();
6235   }
6236   return Lookup(cage_base, key, Smi::ToInt(hash));
6237 }
6238 
6239 template <typename Derived, typename Shape>
Lookup(Handle<Object> key,int32_t hash)6240 Object ObjectHashTableBase<Derived, Shape>::Lookup(Handle<Object> key,
6241                                                    int32_t hash) {
6242   return Lookup(GetPtrComprCageBase(*this), key, hash);
6243 }
6244 
6245 template <typename Derived, typename Shape>
ValueAt(InternalIndex entry)6246 Object ObjectHashTableBase<Derived, Shape>::ValueAt(InternalIndex entry) {
6247   return this->get(EntryToValueIndex(entry));
6248 }
6249 
6250 template <typename Derived, typename Shape>
Put(Handle<Derived> table,Handle<Object> key,Handle<Object> value)6251 Handle<Derived> ObjectHashTableBase<Derived, Shape>::Put(Handle<Derived> table,
6252                                                          Handle<Object> key,
6253                                                          Handle<Object> value) {
6254   Isolate* isolate = Heap::FromWritableHeapObject(*table)->isolate();
6255   DCHECK(table->IsKey(ReadOnlyRoots(isolate), *key));
6256   DCHECK(!value->IsTheHole(ReadOnlyRoots(isolate)));
6257 
6258   // Make sure the key object has an identity hash code.
6259   int32_t hash = key->GetOrCreateHash(isolate).value();
6260 
6261   return ObjectHashTableBase<Derived, Shape>::Put(isolate, table, key, value,
6262                                                   hash);
6263 }
6264 
6265 template <typename Derived, typename Shape>
Put(Isolate * isolate,Handle<Derived> table,Handle<Object> key,Handle<Object> value,int32_t hash)6266 Handle<Derived> ObjectHashTableBase<Derived, Shape>::Put(Isolate* isolate,
6267                                                          Handle<Derived> table,
6268                                                          Handle<Object> key,
6269                                                          Handle<Object> value,
6270                                                          int32_t hash) {
6271   ReadOnlyRoots roots(isolate);
6272   DCHECK(table->IsKey(roots, *key));
6273   DCHECK(!value->IsTheHole(roots));
6274 
6275   InternalIndex entry = table->FindEntry(isolate, roots, key, hash);
6276 
6277   // Key is already in table, just overwrite value.
6278   if (entry.is_found()) {
6279     table->set(Derived::EntryToValueIndex(entry), *value);
6280     return table;
6281   }
6282 
6283   // Rehash if more than 33% of the entries are deleted entries.
6284   // TODO(jochen): Consider to shrink the fixed array in place.
6285   if ((table->NumberOfDeletedElements() << 1) > table->NumberOfElements()) {
6286     table->Rehash(isolate);
6287   }
6288   // If we're out of luck, we didn't get a GC recently, and so rehashing
6289   // isn't enough to avoid a crash.
6290   if (!table->HasSufficientCapacityToAdd(1)) {
6291     int nof = table->NumberOfElements() + 1;
6292     int capacity = ObjectHashTable::ComputeCapacity(nof * 2);
6293     if (capacity > ObjectHashTable::kMaxCapacity) {
6294       for (size_t i = 0; i < 2; ++i) {
6295         isolate->heap()->CollectAllGarbage(
6296             Heap::kNoGCFlags, GarbageCollectionReason::kFullHashtable);
6297       }
6298       table->Rehash(isolate);
6299     }
6300   }
6301 
6302   // Check whether the hash table should be extended.
6303   table = Derived::EnsureCapacity(isolate, table);
6304   table->AddEntry(table->FindInsertionEntry(isolate, hash), *key, *value);
6305   return table;
6306 }
6307 
6308 template <typename Derived, typename Shape>
Remove(Isolate * isolate,Handle<Derived> table,Handle<Object> key,bool * was_present)6309 Handle<Derived> ObjectHashTableBase<Derived, Shape>::Remove(
6310     Isolate* isolate, Handle<Derived> table, Handle<Object> key,
6311     bool* was_present) {
6312   DCHECK(table->IsKey(table->GetReadOnlyRoots(), *key));
6313 
6314   Object hash = key->GetHash();
6315   if (hash.IsUndefined()) {
6316     *was_present = false;
6317     return table;
6318   }
6319 
6320   return Remove(isolate, table, key, was_present, Smi::ToInt(hash));
6321 }
6322 
6323 template <typename Derived, typename Shape>
Remove(Isolate * isolate,Handle<Derived> table,Handle<Object> key,bool * was_present,int32_t hash)6324 Handle<Derived> ObjectHashTableBase<Derived, Shape>::Remove(
6325     Isolate* isolate, Handle<Derived> table, Handle<Object> key,
6326     bool* was_present, int32_t hash) {
6327   ReadOnlyRoots roots = table->GetReadOnlyRoots();
6328   DCHECK(table->IsKey(roots, *key));
6329 
6330   InternalIndex entry = table->FindEntry(isolate, roots, key, hash);
6331   if (entry.is_not_found()) {
6332     *was_present = false;
6333     return table;
6334   }
6335 
6336   *was_present = true;
6337   table->RemoveEntry(entry);
6338   return Derived::Shrink(isolate, table);
6339 }
6340 
6341 template <typename Derived, typename Shape>
AddEntry(InternalIndex entry,Object key,Object value)6342 void ObjectHashTableBase<Derived, Shape>::AddEntry(InternalIndex entry,
6343                                                    Object key, Object value) {
6344   Derived* self = static_cast<Derived*>(this);
6345   self->set_key(Derived::EntryToIndex(entry), key);
6346   self->set(Derived::EntryToValueIndex(entry), value);
6347   self->ElementAdded();
6348 }
6349 
6350 template <typename Derived, typename Shape>
RemoveEntry(InternalIndex entry)6351 void ObjectHashTableBase<Derived, Shape>::RemoveEntry(InternalIndex entry) {
6352   this->set_the_hole(Derived::EntryToIndex(entry));
6353   this->set_the_hole(Derived::EntryToValueIndex(entry));
6354   this->ElementRemoved();
6355 }
6356 
Initialize(Handle<JSSet> set,Isolate * isolate)6357 void JSSet::Initialize(Handle<JSSet> set, Isolate* isolate) {
6358   Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
6359   set->set_table(*table);
6360 }
6361 
Clear(Isolate * isolate,Handle<JSSet> set)6362 void JSSet::Clear(Isolate* isolate, Handle<JSSet> set) {
6363   Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()), isolate);
6364   table = OrderedHashSet::Clear(isolate, table);
6365   set->set_table(*table);
6366 }
6367 
Rehash(Isolate * isolate)6368 void JSSet::Rehash(Isolate* isolate) {
6369   Handle<OrderedHashSet> table_handle(OrderedHashSet::cast(table()), isolate);
6370   Handle<OrderedHashSet> new_table =
6371       OrderedHashSet::Rehash(isolate, table_handle).ToHandleChecked();
6372   set_table(*new_table);
6373 }
6374 
Initialize(Handle<JSMap> map,Isolate * isolate)6375 void JSMap::Initialize(Handle<JSMap> map, Isolate* isolate) {
6376   Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
6377   map->set_table(*table);
6378 }
6379 
Clear(Isolate * isolate,Handle<JSMap> map)6380 void JSMap::Clear(Isolate* isolate, Handle<JSMap> map) {
6381   Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()), isolate);
6382   table = OrderedHashMap::Clear(isolate, table);
6383   map->set_table(*table);
6384 }
6385 
Rehash(Isolate * isolate)6386 void JSMap::Rehash(Isolate* isolate) {
6387   Handle<OrderedHashMap> table_handle(OrderedHashMap::cast(table()), isolate);
6388   Handle<OrderedHashMap> new_table =
6389       OrderedHashMap::Rehash(isolate, table_handle).ToHandleChecked();
6390   set_table(*new_table);
6391 }
6392 
Initialize(Handle<JSWeakCollection> weak_collection,Isolate * isolate)6393 void JSWeakCollection::Initialize(Handle<JSWeakCollection> weak_collection,
6394                                   Isolate* isolate) {
6395   Handle<EphemeronHashTable> table = EphemeronHashTable::New(isolate, 0);
6396   weak_collection->set_table(*table);
6397 }
6398 
Set(Handle<JSWeakCollection> weak_collection,Handle<Object> key,Handle<Object> value,int32_t hash)6399 void JSWeakCollection::Set(Handle<JSWeakCollection> weak_collection,
6400                            Handle<Object> key, Handle<Object> value,
6401                            int32_t hash) {
6402   DCHECK(key->IsJSReceiver() || key->IsSymbol());
6403   Handle<EphemeronHashTable> table(
6404       EphemeronHashTable::cast(weak_collection->table()),
6405       weak_collection->GetIsolate());
6406   DCHECK(table->IsKey(weak_collection->GetReadOnlyRoots(), *key));
6407   Handle<EphemeronHashTable> new_table = EphemeronHashTable::Put(
6408       weak_collection->GetIsolate(), table, key, value, hash);
6409   weak_collection->set_table(*new_table);
6410   if (*table != *new_table) {
6411     // Zap the old table since we didn't record slots for its elements.
6412     EphemeronHashTable::FillEntriesWithHoles(table);
6413   }
6414 }
6415 
Delete(Handle<JSWeakCollection> weak_collection,Handle<Object> key,int32_t hash)6416 bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection,
6417                               Handle<Object> key, int32_t hash) {
6418   DCHECK(key->IsJSReceiver() || key->IsSymbol());
6419   Handle<EphemeronHashTable> table(
6420       EphemeronHashTable::cast(weak_collection->table()),
6421       weak_collection->GetIsolate());
6422   DCHECK(table->IsKey(weak_collection->GetReadOnlyRoots(), *key));
6423   bool was_present = false;
6424   Handle<EphemeronHashTable> new_table = EphemeronHashTable::Remove(
6425       weak_collection->GetIsolate(), table, key, &was_present, hash);
6426   weak_collection->set_table(*new_table);
6427   if (*table != *new_table) {
6428     // Zap the old table since we didn't record slots for its elements.
6429     EphemeronHashTable::FillEntriesWithHoles(table);
6430   }
6431   return was_present;
6432 }
6433 
GetEntries(Handle<JSWeakCollection> holder,int max_entries)6434 Handle<JSArray> JSWeakCollection::GetEntries(Handle<JSWeakCollection> holder,
6435                                              int max_entries) {
6436   Isolate* isolate = holder->GetIsolate();
6437   Handle<EphemeronHashTable> table(EphemeronHashTable::cast(holder->table()),
6438                                    isolate);
6439   if (max_entries == 0 || max_entries > table->NumberOfElements()) {
6440     max_entries = table->NumberOfElements();
6441   }
6442   int values_per_entry = holder->IsJSWeakMap() ? 2 : 1;
6443   Handle<FixedArray> entries =
6444       isolate->factory()->NewFixedArray(max_entries * values_per_entry);
6445   // Recompute max_values because GC could have removed elements from the table.
6446   if (max_entries > table->NumberOfElements()) {
6447     max_entries = table->NumberOfElements();
6448   }
6449 
6450   {
6451     DisallowGarbageCollection no_gc;
6452     ReadOnlyRoots roots = ReadOnlyRoots(isolate);
6453     int count = 0;
6454     for (int i = 0;
6455          count / values_per_entry < max_entries && i < table->Capacity(); i++) {
6456       Object key;
6457       if (table->ToKey(roots, InternalIndex(i), &key)) {
6458         entries->set(count++, key);
6459         if (values_per_entry > 1) {
6460           Object value = table->Lookup(handle(key, isolate));
6461           entries->set(count++, value);
6462         }
6463       }
6464     }
6465     DCHECK_EQ(max_entries * values_per_entry, count);
6466   }
6467   return isolate->factory()->NewJSArrayWithElements(entries);
6468 }
6469 
ClearAndInvalidate(ReadOnlyRoots roots)6470 void PropertyCell::ClearAndInvalidate(ReadOnlyRoots roots) {
6471   DCHECK(!value().IsTheHole(roots));
6472   PropertyDetails details = property_details();
6473   details = details.set_cell_type(PropertyCellType::kConstant);
6474   Transition(details, roots.the_hole_value_handle());
6475   dependent_code().DeoptimizeDependentCodeGroup(
6476       DependentCode::kPropertyCellChangedGroup);
6477 }
6478 
6479 // static
InvalidateAndReplaceEntry(Isolate * isolate,Handle<GlobalDictionary> dictionary,InternalIndex entry,PropertyDetails new_details,Handle<Object> new_value)6480 Handle<PropertyCell> PropertyCell::InvalidateAndReplaceEntry(
6481     Isolate* isolate, Handle<GlobalDictionary> dictionary, InternalIndex entry,
6482     PropertyDetails new_details, Handle<Object> new_value) {
6483   Handle<PropertyCell> cell(dictionary->CellAt(entry), isolate);
6484   Handle<Name> name(cell->name(), isolate);
6485   DCHECK(cell->property_details().IsConfigurable());
6486   DCHECK(!cell->value().IsTheHole(isolate));
6487 
6488   // Swap with a new property cell.
6489   Handle<PropertyCell> new_cell =
6490       isolate->factory()->NewPropertyCell(name, new_details, new_value);
6491   dictionary->ValueAtPut(entry, *new_cell);
6492 
6493   cell->ClearAndInvalidate(ReadOnlyRoots(isolate));
6494   return new_cell;
6495 }
6496 
RemainsConstantType(Handle<PropertyCell> cell,Handle<Object> value)6497 static bool RemainsConstantType(Handle<PropertyCell> cell,
6498                                 Handle<Object> value) {
6499   // TODO(dcarney): double->smi and smi->double transition from kConstant
6500   if (cell->value().IsSmi() && value->IsSmi()) {
6501     return true;
6502   } else if (cell->value().IsHeapObject() && value->IsHeapObject()) {
6503     return HeapObject::cast(cell->value()).map() ==
6504                HeapObject::cast(*value).map() &&
6505            HeapObject::cast(*value).map().is_stable();
6506   }
6507   return false;
6508 }
6509 
6510 // static
InitialType(Isolate * isolate,Handle<Object> value)6511 PropertyCellType PropertyCell::InitialType(Isolate* isolate,
6512                                            Handle<Object> value) {
6513   return value->IsUndefined(isolate) ? PropertyCellType::kUndefined
6514                                      : PropertyCellType::kConstant;
6515 }
6516 
6517 // static
UpdatedType(Isolate * isolate,Handle<PropertyCell> cell,Handle<Object> value,PropertyDetails details)6518 PropertyCellType PropertyCell::UpdatedType(Isolate* isolate,
6519                                            Handle<PropertyCell> cell,
6520                                            Handle<Object> value,
6521                                            PropertyDetails details) {
6522   DCHECK(!value->IsTheHole(isolate));
6523   DCHECK(!cell->value().IsTheHole(isolate));
6524   switch (details.cell_type()) {
6525     case PropertyCellType::kUndefined:
6526       return PropertyCellType::kConstant;
6527     case PropertyCellType::kConstant:
6528       if (*value == cell->value()) return PropertyCellType::kConstant;
6529       V8_FALLTHROUGH;
6530     case PropertyCellType::kConstantType:
6531       if (RemainsConstantType(cell, value)) {
6532         return PropertyCellType::kConstantType;
6533       }
6534       V8_FALLTHROUGH;
6535     case PropertyCellType::kMutable:
6536       return PropertyCellType::kMutable;
6537     case PropertyCellType::kInTransition:
6538       UNREACHABLE();
6539   }
6540 }
6541 
PrepareForAndSetValue(Isolate * isolate,Handle<GlobalDictionary> dictionary,InternalIndex entry,Handle<Object> value,PropertyDetails details)6542 Handle<PropertyCell> PropertyCell::PrepareForAndSetValue(
6543     Isolate* isolate, Handle<GlobalDictionary> dictionary, InternalIndex entry,
6544     Handle<Object> value, PropertyDetails details) {
6545   DCHECK(!value->IsTheHole(isolate));
6546   Handle<PropertyCell> cell(dictionary->CellAt(entry), isolate);
6547   CHECK(!cell->value().IsTheHole(isolate));
6548   const PropertyDetails original_details = cell->property_details();
6549   // Data accesses could be cached in ics or optimized code.
6550   bool invalidate =
6551       original_details.kind() == kData && details.kind() == kAccessor;
6552   int index = original_details.dictionary_index();
6553   DCHECK_LT(0, index);
6554   details = details.set_index(index);
6555 
6556   PropertyCellType new_type =
6557       UpdatedType(isolate, cell, value, original_details);
6558   details = details.set_cell_type(new_type);
6559 
6560   if (invalidate) {
6561     cell = PropertyCell::InvalidateAndReplaceEntry(isolate, dictionary, entry,
6562                                                    details, value);
6563   } else {
6564     cell->Transition(details, value);
6565     // Deopt when transitioning from a constant type or when making a writable
6566     // property read-only. Making a read-only property writable again is not
6567     // interesting because Turbofan does not currently rely on read-only unless
6568     // the property is also configurable, in which case it will stay read-only
6569     // forever.
6570     if (original_details.cell_type() != new_type ||
6571         (!original_details.IsReadOnly() && details.IsReadOnly())) {
6572       cell->dependent_code().DeoptimizeDependentCodeGroup(
6573           DependentCode::kPropertyCellChangedGroup);
6574     }
6575   }
6576   return cell;
6577 }
6578 
6579 // static
InvalidateProtector()6580 void PropertyCell::InvalidateProtector() {
6581   if (value() != Smi::FromInt(Protectors::kProtectorInvalid)) {
6582     DCHECK_EQ(value(), Smi::FromInt(Protectors::kProtectorValid));
6583     set_value(Smi::FromInt(Protectors::kProtectorInvalid), kReleaseStore);
6584     dependent_code().DeoptimizeDependentCodeGroup(
6585         DependentCode::kPropertyCellChangedGroup);
6586   }
6587 }
6588 
6589 // static
CheckDataIsCompatible(PropertyDetails details,Object value)6590 bool PropertyCell::CheckDataIsCompatible(PropertyDetails details,
6591                                          Object value) {
6592   DisallowGarbageCollection no_gc;
6593   PropertyCellType cell_type = details.cell_type();
6594   CHECK_NE(cell_type, PropertyCellType::kInTransition);
6595   if (value.IsTheHole()) {
6596     CHECK_EQ(cell_type, PropertyCellType::kConstant);
6597   } else {
6598     CHECK_EQ(value.IsAccessorInfo() || value.IsAccessorPair(),
6599              details.kind() == kAccessor);
6600     DCHECK_IMPLIES(cell_type == PropertyCellType::kUndefined,
6601                    value.IsUndefined());
6602   }
6603   return true;
6604 }
6605 
6606 #ifdef DEBUG
CanTransitionTo(PropertyDetails new_details,Object new_value) const6607 bool PropertyCell::CanTransitionTo(PropertyDetails new_details,
6608                                    Object new_value) const {
6609   // Extending the implementation of PropertyCells with additional states
6610   // and/or transitions likely requires changes to PropertyCellData::Serialize.
6611   DisallowGarbageCollection no_gc;
6612   DCHECK(CheckDataIsCompatible(new_details, new_value));
6613   switch (property_details().cell_type()) {
6614     case PropertyCellType::kUndefined:
6615       return new_details.cell_type() != PropertyCellType::kUndefined;
6616     case PropertyCellType::kConstant:
6617       return !value().IsTheHole() &&
6618              new_details.cell_type() != PropertyCellType::kUndefined;
6619     case PropertyCellType::kConstantType:
6620       return new_details.cell_type() == PropertyCellType::kConstantType ||
6621              new_details.cell_type() == PropertyCellType::kMutable ||
6622              (new_details.cell_type() == PropertyCellType::kConstant &&
6623               new_value.IsTheHole());
6624     case PropertyCellType::kMutable:
6625       return new_details.cell_type() == PropertyCellType::kMutable ||
6626              (new_details.cell_type() == PropertyCellType::kConstant &&
6627               new_value.IsTheHole());
6628     case PropertyCellType::kInTransition:
6629       UNREACHABLE();
6630   }
6631 }
6632 #endif  // DEBUG
6633 
source_position() const6634 int JSGeneratorObject::source_position() const {
6635   CHECK(is_suspended());
6636   DCHECK(function().shared().HasBytecodeArray());
6637   Isolate* isolate = GetIsolate();
6638   DCHECK(
6639       function().shared().GetBytecodeArray(isolate).HasSourcePositionTable());
6640 
6641   int code_offset = Smi::ToInt(input_or_debug_pos());
6642 
6643   // The stored bytecode offset is relative to a different base than what
6644   // is used in the source position table, hence the subtraction.
6645   code_offset -= BytecodeArray::kHeaderSize - kHeapObjectTag;
6646   AbstractCode code =
6647       AbstractCode::cast(function().shared().GetBytecodeArray(isolate));
6648   return code.SourcePosition(code_offset);
6649 }
6650 
6651 // static
Get(Isolate * isolate,Handle<JSObject> receiver)6652 AccessCheckInfo AccessCheckInfo::Get(Isolate* isolate,
6653                                      Handle<JSObject> receiver) {
6654   DisallowGarbageCollection no_gc;
6655   DCHECK(receiver->map().is_access_check_needed());
6656   Object maybe_constructor = receiver->map().GetConstructor();
6657   if (maybe_constructor.IsFunctionTemplateInfo()) {
6658     Object data_obj =
6659         FunctionTemplateInfo::cast(maybe_constructor).GetAccessCheckInfo();
6660     if (data_obj.IsUndefined(isolate)) return AccessCheckInfo();
6661     return AccessCheckInfo::cast(data_obj);
6662   }
6663   // Might happen for a detached context.
6664   if (!maybe_constructor.IsJSFunction()) return AccessCheckInfo();
6665   JSFunction constructor = JSFunction::cast(maybe_constructor);
6666   // Might happen for the debug context.
6667   if (!constructor.shared().IsApiFunction()) return AccessCheckInfo();
6668 
6669   Object data_obj =
6670       constructor.shared().get_api_func_data().GetAccessCheckInfo();
6671   if (data_obj.IsUndefined(isolate)) return AccessCheckInfo();
6672 
6673   return AccessCheckInfo::cast(data_obj);
6674 }
6675 
LexicographicCompare(Isolate * isolate,Smi x,Smi y)6676 Address Smi::LexicographicCompare(Isolate* isolate, Smi x, Smi y) {
6677   DisallowGarbageCollection no_gc;
6678   DisallowJavascriptExecution no_js(isolate);
6679 
6680   int x_value = Smi::ToInt(x);
6681   int y_value = Smi::ToInt(y);
6682 
6683   // If the integers are equal so are the string representations.
6684   if (x_value == y_value) return Smi::FromInt(0).ptr();
6685 
6686   // If one of the integers is zero the normal integer order is the
6687   // same as the lexicographic order of the string representations.
6688   if (x_value == 0 || y_value == 0) {
6689     return Smi::FromInt(x_value < y_value ? -1 : 1).ptr();
6690   }
6691 
6692   // If only one of the integers is negative the negative number is
6693   // smallest because the char code of '-' is less than the char code
6694   // of any digit.  Otherwise, we make both values positive.
6695 
6696   // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
6697   // architectures using 32-bit Smis.
6698   uint32_t x_scaled = x_value;
6699   uint32_t y_scaled = y_value;
6700   if (x_value < 0) {
6701     if (y_value >= 0) {
6702       return Smi::FromInt(-1).ptr();
6703     } else {
6704       y_scaled = base::NegateWithWraparound(y_value);
6705     }
6706     x_scaled = base::NegateWithWraparound(x_value);
6707   } else if (y_value < 0) {
6708     return Smi::FromInt(1).ptr();
6709   }
6710 
6711   // clang-format off
6712   static const uint32_t kPowersOf10[] = {
6713       1,                 10,                100,         1000,
6714       10 * 1000,         100 * 1000,        1000 * 1000, 10 * 1000 * 1000,
6715       100 * 1000 * 1000, 1000 * 1000 * 1000};
6716   // clang-format on
6717 
6718   // If the integers have the same number of decimal digits they can be
6719   // compared directly as the numeric order is the same as the
6720   // lexicographic order.  If one integer has fewer digits, it is scaled
6721   // by some power of 10 to have the same number of digits as the longer
6722   // integer.  If the scaled integers are equal it means the shorter
6723   // integer comes first in the lexicographic order.
6724 
6725   // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
6726   int x_log2 = 31 - base::bits::CountLeadingZeros(x_scaled);
6727   int x_log10 = ((x_log2 + 1) * 1233) >> 12;
6728   x_log10 -= x_scaled < kPowersOf10[x_log10];
6729 
6730   int y_log2 = 31 - base::bits::CountLeadingZeros(y_scaled);
6731   int y_log10 = ((y_log2 + 1) * 1233) >> 12;
6732   y_log10 -= y_scaled < kPowersOf10[y_log10];
6733 
6734   int tie = 0;
6735 
6736   if (x_log10 < y_log10) {
6737     // X has fewer digits.  We would like to simply scale up X but that
6738     // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
6739     // be scaled up to 9_000_000_000. So we scale up by the next
6740     // smallest power and scale down Y to drop one digit. It is OK to
6741     // drop one digit from the longer integer since the final digit is
6742     // past the length of the shorter integer.
6743     x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
6744     y_scaled /= 10;
6745     tie = -1;
6746   } else if (y_log10 < x_log10) {
6747     y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
6748     x_scaled /= 10;
6749     tie = 1;
6750   }
6751 
6752   if (x_scaled < y_scaled) return Smi::FromInt(-1).ptr();
6753   if (x_scaled > y_scaled) return Smi::FromInt(1).ptr();
6754   return Smi::FromInt(tie).ptr();
6755 }
6756 
6757 // Force instantiation of template instances class.
6758 // Please note this list is compiler dependent.
6759 // Keep this at the end of this file
6760 
6761 #define EXTERN_DEFINE_HASH_TABLE(DERIVED, SHAPE)                            \
6762   template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)                  \
6763       HashTable<DERIVED, SHAPE>;                                            \
6764                                                                             \
6765   template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) Handle<DERIVED>        \
6766   HashTable<DERIVED, SHAPE>::New(Isolate*, int, AllocationType,             \
6767                                  MinimumCapacity);                          \
6768   template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) Handle<DERIVED>        \
6769   HashTable<DERIVED, SHAPE>::New(LocalIsolate*, int, AllocationType,        \
6770                                  MinimumCapacity);                          \
6771                                                                             \
6772   template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) Handle<DERIVED>        \
6773   HashTable<DERIVED, SHAPE>::EnsureCapacity(Isolate*, Handle<DERIVED>, int, \
6774                                             AllocationType);                \
6775   template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) Handle<DERIVED>        \
6776   HashTable<DERIVED, SHAPE>::EnsureCapacity(LocalIsolate*, Handle<DERIVED>, \
6777                                             int, AllocationType);
6778 
6779 #define EXTERN_DEFINE_OBJECT_BASE_HASH_TABLE(DERIVED, SHAPE) \
6780   EXTERN_DEFINE_HASH_TABLE(DERIVED, SHAPE)                   \
6781   template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)   \
6782       ObjectHashTableBase<DERIVED, SHAPE>;
6783 
6784 #define EXTERN_DEFINE_DICTIONARY(DERIVED, SHAPE)                               \
6785   EXTERN_DEFINE_HASH_TABLE(DERIVED, SHAPE)                                     \
6786   template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)                     \
6787       Dictionary<DERIVED, SHAPE>;                                              \
6788                                                                                \
6789   template V8_EXPORT_PRIVATE Handle<DERIVED> Dictionary<DERIVED, SHAPE>::Add(  \
6790       Isolate* isolate, Handle<DERIVED>, Key, Handle<Object>, PropertyDetails, \
6791       InternalIndex*);                                                         \
6792   template V8_EXPORT_PRIVATE Handle<DERIVED> Dictionary<DERIVED, SHAPE>::Add(  \
6793       LocalIsolate* isolate, Handle<DERIVED>, Key, Handle<Object>,             \
6794       PropertyDetails, InternalIndex*);
6795 
6796 #define EXTERN_DEFINE_BASE_NAME_DICTIONARY(DERIVED, SHAPE)                     \
6797   EXTERN_DEFINE_DICTIONARY(DERIVED, SHAPE)                                     \
6798   template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)                     \
6799       BaseNameDictionary<DERIVED, SHAPE>;                                      \
6800                                                                                \
6801   template V8_EXPORT_PRIVATE Handle<DERIVED>                                   \
6802   BaseNameDictionary<DERIVED, SHAPE>::New(Isolate*, int, AllocationType,       \
6803                                           MinimumCapacity);                    \
6804   template V8_EXPORT_PRIVATE Handle<DERIVED>                                   \
6805   BaseNameDictionary<DERIVED, SHAPE>::New(LocalIsolate*, int, AllocationType,  \
6806                                           MinimumCapacity);                    \
6807                                                                                \
6808   template Handle<DERIVED>                                                     \
6809   BaseNameDictionary<DERIVED, SHAPE>::AddNoUpdateNextEnumerationIndex(         \
6810       Isolate* isolate, Handle<DERIVED>, Key, Handle<Object>, PropertyDetails, \
6811       InternalIndex*);                                                         \
6812   template Handle<DERIVED>                                                     \
6813   BaseNameDictionary<DERIVED, SHAPE>::AddNoUpdateNextEnumerationIndex(         \
6814       LocalIsolate* isolate, Handle<DERIVED>, Key, Handle<Object>,             \
6815       PropertyDetails, InternalIndex*);
6816 
EXTERN_DEFINE_HASH_TABLE(StringSet,StringSetShape)6817 EXTERN_DEFINE_HASH_TABLE(StringSet, StringSetShape)
6818 EXTERN_DEFINE_HASH_TABLE(CompilationCacheTable, CompilationCacheShape)
6819 EXTERN_DEFINE_HASH_TABLE(ObjectHashSet, ObjectHashSetShape)
6820 
6821 EXTERN_DEFINE_OBJECT_BASE_HASH_TABLE(ObjectHashTable, ObjectHashTableShape)
6822 EXTERN_DEFINE_OBJECT_BASE_HASH_TABLE(EphemeronHashTable, ObjectHashTableShape)
6823 
6824 EXTERN_DEFINE_DICTIONARY(SimpleNumberDictionary, SimpleNumberDictionaryShape)
6825 EXTERN_DEFINE_DICTIONARY(NumberDictionary, NumberDictionaryShape)
6826 
6827 EXTERN_DEFINE_BASE_NAME_DICTIONARY(NameDictionary, NameDictionaryShape)
6828 EXTERN_DEFINE_BASE_NAME_DICTIONARY(GlobalDictionary, GlobalDictionaryShape)
6829 
6830 #undef EXTERN_DEFINE_HASH_TABLE
6831 #undef EXTERN_DEFINE_OBJECT_BASE_HASH_TABLE
6832 #undef EXTERN_DEFINE_DICTIONARY
6833 #undef EXTERN_DEFINE_BASE_NAME_DICTIONARY
6834 
6835 void JSFinalizationRegistry::RemoveCellFromUnregisterTokenMap(
6836     Isolate* isolate, Address raw_finalization_registry,
6837     Address raw_weak_cell) {
6838   DisallowGarbageCollection no_gc;
6839   JSFinalizationRegistry finalization_registry =
6840       JSFinalizationRegistry::cast(Object(raw_finalization_registry));
6841   WeakCell weak_cell = WeakCell::cast(Object(raw_weak_cell));
6842   DCHECK(!weak_cell.unregister_token().IsUndefined(isolate));
6843   HeapObject undefined = ReadOnlyRoots(isolate).undefined_value();
6844 
6845   // Remove weak_cell from the linked list of other WeakCells with the same
6846   // unregister token and remove its unregister token from key_map if necessary
6847   // without shrinking it. Since shrinking may allocate, it is performed by the
6848   // caller after looping, or on exception.
6849   if (weak_cell.key_list_prev().IsUndefined(isolate)) {
6850     SimpleNumberDictionary key_map =
6851         SimpleNumberDictionary::cast(finalization_registry.key_map());
6852     HeapObject unregister_token = weak_cell.unregister_token();
6853     uint32_t key = Smi::ToInt(unregister_token.GetHash());
6854     InternalIndex entry = key_map.FindEntry(isolate, key);
6855     DCHECK(entry.is_found());
6856 
6857     if (weak_cell.key_list_next().IsUndefined(isolate)) {
6858       // weak_cell is the only one associated with its key; remove the key
6859       // from the hash table.
6860       key_map.ClearEntry(entry);
6861       key_map.ElementRemoved();
6862     } else {
6863       // weak_cell is the list head for its key; we need to change the value
6864       // of the key in the hash table.
6865       WeakCell next = WeakCell::cast(weak_cell.key_list_next());
6866       DCHECK_EQ(next.key_list_prev(), weak_cell);
6867       next.set_key_list_prev(undefined);
6868       key_map.ValueAtPut(entry, next);
6869     }
6870   } else {
6871     // weak_cell is somewhere in the middle of its key list.
6872     WeakCell prev = WeakCell::cast(weak_cell.key_list_prev());
6873     prev.set_key_list_next(weak_cell.key_list_next());
6874     if (!weak_cell.key_list_next().IsUndefined()) {
6875       WeakCell next = WeakCell::cast(weak_cell.key_list_next());
6876       next.set_key_list_prev(weak_cell.key_list_prev());
6877     }
6878   }
6879 
6880   // weak_cell is now removed from the unregister token map, so clear its
6881   // unregister token-related fields for heap verification.
6882   weak_cell.set_unregister_token(undefined);
6883   weak_cell.set_key_list_prev(undefined);
6884   weak_cell.set_key_list_next(undefined);
6885 }
6886 
6887 }  // namespace internal
6888 }  // namespace v8
6889