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