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