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