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