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