Line data Source code
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.h"
6 :
7 : #include <algorithm>
8 : #include <cmath>
9 : #include <iomanip>
10 : #include <memory>
11 : #include <sstream>
12 : #include <vector>
13 :
14 : #include "src/objects-inl.h"
15 :
16 : #include "src/accessors.h"
17 : #include "src/allocation-site-scopes.h"
18 : #include "src/api-arguments-inl.h"
19 : #include "src/api-natives.h"
20 : #include "src/api.h"
21 : #include "src/arguments.h"
22 : #include "src/assembler-inl.h"
23 : #include "src/ast/ast.h"
24 : #include "src/ast/scopes.h"
25 : #include "src/base/bits.h"
26 : #include "src/base/utils/random-number-generator.h"
27 : #include "src/bootstrapper.h"
28 : #include "src/builtins/builtins.h"
29 : #include "src/compiler.h"
30 : #include "src/counters-inl.h"
31 : #include "src/counters.h"
32 : #include "src/date.h"
33 : #include "src/debug/debug.h"
34 : #include "src/deoptimizer.h"
35 : #include "src/elements.h"
36 : #include "src/execution.h"
37 : #include "src/field-index-inl.h"
38 : #include "src/field-index.h"
39 : #include "src/field-type.h"
40 : #include "src/frames-inl.h"
41 : #include "src/globals.h"
42 : #include "src/ic/ic.h"
43 : #include "src/identity-map.h"
44 : #include "src/interpreter/bytecode-array-iterator.h"
45 : #include "src/interpreter/bytecode-decoder.h"
46 : #include "src/interpreter/interpreter.h"
47 : #include "src/isolate-inl.h"
48 : #include "src/keys.h"
49 : #include "src/log.h"
50 : #include "src/lookup-inl.h"
51 : #include "src/map-updater.h"
52 : #include "src/message-template.h"
53 : #include "src/microtask-queue.h"
54 : #include "src/objects-body-descriptors-inl.h"
55 : #include "src/objects/api-callbacks.h"
56 : #include "src/objects/arguments-inl.h"
57 : #include "src/objects/bigint.h"
58 : #include "src/objects/cell-inl.h"
59 : #include "src/objects/code-inl.h"
60 : #include "src/objects/compilation-cache-inl.h"
61 : #include "src/objects/debug-objects-inl.h"
62 : #include "src/objects/foreign.h"
63 : #include "src/objects/frame-array-inl.h"
64 : #include "src/objects/hash-table-inl.h"
65 : #include "src/objects/js-array-inl.h"
66 : #ifdef V8_INTL_SUPPORT
67 : #include "src/objects/js-break-iterator.h"
68 : #include "src/objects/js-collator.h"
69 : #endif // V8_INTL_SUPPORT
70 : #include "src/objects/js-collection-inl.h"
71 : #ifdef V8_INTL_SUPPORT
72 : #include "src/objects/js-date-time-format.h"
73 : #endif // V8_INTL_SUPPORT
74 : #include "src/objects/js-generator-inl.h"
75 : #ifdef V8_INTL_SUPPORT
76 : #include "src/objects/js-list-format.h"
77 : #include "src/objects/js-locale.h"
78 : #include "src/objects/js-number-format.h"
79 : #include "src/objects/js-plural-rules.h"
80 : #endif // V8_INTL_SUPPORT
81 : #include "src/objects/js-regexp-inl.h"
82 : #include "src/objects/js-regexp-string-iterator.h"
83 : #ifdef V8_INTL_SUPPORT
84 : #include "src/objects/js-relative-time-format.h"
85 : #include "src/objects/js-segment-iterator.h"
86 : #include "src/objects/js-segmenter.h"
87 : #endif // V8_INTL_SUPPORT
88 : #include "src/code-comments.h"
89 : #include "src/objects/js-weak-refs-inl.h"
90 : #include "src/objects/literal-objects-inl.h"
91 : #include "src/objects/map.h"
92 : #include "src/objects/microtask-inl.h"
93 : #include "src/objects/module-inl.h"
94 : #include "src/objects/promise-inl.h"
95 : #include "src/objects/slots-atomic-inl.h"
96 : #include "src/objects/stack-frame-info-inl.h"
97 : #include "src/objects/struct-inl.h"
98 : #include "src/parsing/preparse-data.h"
99 : #include "src/property-descriptor.h"
100 : #include "src/prototype.h"
101 : #include "src/regexp/jsregexp.h"
102 : #include "src/safepoint-table.h"
103 : #include "src/snapshot/code-serializer.h"
104 : #include "src/snapshot/snapshot.h"
105 : #include "src/source-position-table.h"
106 : #include "src/string-builder-inl.h"
107 : #include "src/string-search.h"
108 : #include "src/string-stream.h"
109 : #include "src/unicode-decoder.h"
110 : #include "src/unicode-inl.h"
111 : #include "src/utils-inl.h"
112 : #include "src/wasm/wasm-engine.h"
113 : #include "src/wasm/wasm-objects.h"
114 : #include "src/zone/zone.h"
115 :
116 : #ifdef ENABLE_DISASSEMBLER
117 : #include "src/disasm.h"
118 : #include "src/disassembler.h"
119 : #include "src/eh-frame.h"
120 : #endif
121 :
122 : namespace v8 {
123 : namespace internal {
124 :
125 4428077 : bool ComparisonResultToBool(Operation op, ComparisonResult result) {
126 4428077 : switch (op) {
127 : case Operation::kLessThan:
128 17879 : return result == ComparisonResult::kLessThan;
129 : case Operation::kLessThanOrEqual:
130 3124720 : return result == ComparisonResult::kLessThan ||
131 3124720 : result == ComparisonResult::kEqual;
132 : case Operation::kGreaterThan:
133 981 : return result == ComparisonResult::kGreaterThan;
134 : case Operation::kGreaterThanOrEqual:
135 1284497 : return result == ComparisonResult::kGreaterThan ||
136 1284497 : result == ComparisonResult::kEqual;
137 : default:
138 : break;
139 : }
140 0 : UNREACHABLE();
141 : }
142 :
143 40179 : std::ostream& operator<<(std::ostream& os, InstanceType instance_type) {
144 40179 : switch (instance_type) {
145 : #define WRITE_TYPE(TYPE) \
146 : case TYPE: \
147 : return os << #TYPE;
148 17 : INSTANCE_TYPE_LIST(WRITE_TYPE)
149 : #undef WRITE_TYPE
150 : }
151 0 : UNREACHABLE();
152 : }
153 :
154 7576041 : Handle<FieldType> Object::OptimalType(Isolate* isolate,
155 : Representation representation) {
156 7576041 : if (representation.IsNone()) return FieldType::None(isolate);
157 7353517 : if (FLAG_track_field_types) {
158 10401923 : if (representation.IsHeapObject() && IsHeapObject()) {
159 : // We can track only JavaScript objects with stable maps.
160 : Handle<Map> map(HeapObject::cast(*this)->map(), isolate);
161 5798840 : if (map->is_stable() && map->IsJSReceiverMap()) {
162 781992 : return FieldType::Class(map, isolate);
163 : }
164 : }
165 : }
166 6571525 : return FieldType::Any(isolate);
167 : }
168 :
169 7076 : MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
170 : Handle<Object> object,
171 : Handle<Context> native_context,
172 : const char* method_name) {
173 14152 : if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
174 : Handle<JSFunction> constructor;
175 14152 : if (object->IsSmi()) {
176 1056 : constructor = handle(native_context->number_function(), isolate);
177 : } else {
178 : int constructor_function_index =
179 13096 : Handle<HeapObject>::cast(object)->map()->GetConstructorFunctionIndex();
180 6548 : if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
181 1698 : if (method_name != nullptr) {
182 900 : THROW_NEW_ERROR(
183 : isolate,
184 : NewTypeError(
185 : MessageTemplate::kCalledOnNullOrUndefined,
186 : isolate->factory()->NewStringFromAsciiChecked(method_name)),
187 : JSReceiver);
188 : }
189 1248 : THROW_NEW_ERROR(isolate,
190 : NewTypeError(MessageTemplate::kUndefinedOrNullToObject),
191 : JSReceiver);
192 : }
193 : constructor = handle(
194 : JSFunction::cast(native_context->get(constructor_function_index)),
195 9700 : isolate);
196 : }
197 5378 : Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
198 10756 : Handle<JSValue>::cast(result)->set_value(*object);
199 5378 : return result;
200 : }
201 :
202 : // ES6 section 9.2.1.2, OrdinaryCallBindThis for sloppy callee.
203 : // static
204 180 : MaybeHandle<JSReceiver> Object::ConvertReceiver(Isolate* isolate,
205 : Handle<Object> object) {
206 360 : if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
207 360 : if (object->IsNullOrUndefined(isolate)) {
208 6 : return isolate->global_proxy();
209 : }
210 174 : return Object::ToObject(isolate, object);
211 : }
212 :
213 : // static
214 3240113 : MaybeHandle<Object> Object::ConvertToNumberOrNumeric(Isolate* isolate,
215 : Handle<Object> input,
216 : Conversion mode) {
217 : while (true) {
218 6491366 : if (input->IsNumber()) {
219 106919 : return input;
220 : }
221 6277528 : if (input->IsString()) {
222 3542 : return String::ToNumber(isolate, Handle<String>::cast(input));
223 : }
224 6270444 : if (input->IsOddball()) {
225 3124697 : return Oddball::ToNumber(isolate, Handle<Oddball>::cast(input));
226 : }
227 21050 : if (input->IsSymbol()) {
228 3767 : THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber),
229 : Object);
230 : }
231 13516 : if (input->IsBigInt()) {
232 582 : if (mode == Conversion::kToNumeric) return input;
233 : DCHECK_EQ(mode, Conversion::kToNumber);
234 582 : THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kBigIntToNumber),
235 : Object);
236 : }
237 12352 : ASSIGN_RETURN_ON_EXCEPTION(
238 : isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
239 : ToPrimitiveHint::kNumber),
240 : Object);
241 : }
242 : }
243 :
244 : // static
245 107089 : MaybeHandle<Object> Object::ConvertToInteger(Isolate* isolate,
246 : Handle<Object> input) {
247 214178 : ASSIGN_RETURN_ON_EXCEPTION(
248 : isolate, input,
249 : ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object);
250 213728 : if (input->IsSmi()) return input;
251 105415 : return isolate->factory()->NewNumber(DoubleToInteger(input->Number()));
252 : }
253 :
254 : // static
255 1466 : MaybeHandle<Object> Object::ConvertToInt32(Isolate* isolate,
256 : Handle<Object> input) {
257 2932 : ASSIGN_RETURN_ON_EXCEPTION(
258 : isolate, input,
259 : ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object);
260 2908 : if (input->IsSmi()) return input;
261 1246 : return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number()));
262 : }
263 :
264 : // static
265 436857 : MaybeHandle<Object> Object::ConvertToUint32(Isolate* isolate,
266 : Handle<Object> input) {
267 873714 : ASSIGN_RETURN_ON_EXCEPTION(
268 : isolate, input,
269 : ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object);
270 1310361 : if (input->IsSmi()) return handle(Smi::cast(*input)->ToUint32Smi(), isolate);
271 294 : return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number()));
272 : }
273 :
274 : // static
275 78286 : MaybeHandle<Name> Object::ConvertToName(Isolate* isolate,
276 : Handle<Object> input) {
277 156572 : ASSIGN_RETURN_ON_EXCEPTION(
278 : isolate, input, Object::ToPrimitive(input, ToPrimitiveHint::kString),
279 : Name);
280 156100 : if (input->IsName()) return Handle<Name>::cast(input);
281 72385 : return ToString(isolate, input);
282 : }
283 :
284 : // ES6 7.1.14
285 : // static
286 486 : MaybeHandle<Object> Object::ConvertToPropertyKey(Isolate* isolate,
287 : Handle<Object> value) {
288 : // 1. Let key be ToPrimitive(argument, hint String).
289 : MaybeHandle<Object> maybe_key =
290 486 : Object::ToPrimitive(value, ToPrimitiveHint::kString);
291 : // 2. ReturnIfAbrupt(key).
292 : Handle<Object> key;
293 486 : if (!maybe_key.ToHandle(&key)) return key;
294 : // 3. If Type(key) is Symbol, then return key.
295 972 : if (key->IsSymbol()) return key;
296 : // 4. Return ToString(key).
297 : // Extending spec'ed behavior, we'd be happy to return an element index.
298 972 : if (key->IsSmi()) return key;
299 972 : if (key->IsHeapNumber()) {
300 : uint32_t uint_value;
301 45 : if (value->ToArrayLength(&uint_value) &&
302 9 : uint_value <= static_cast<uint32_t>(Smi::kMaxValue)) {
303 0 : return handle(Smi::FromInt(static_cast<int>(uint_value)), isolate);
304 : }
305 : }
306 486 : return Object::ToString(isolate, key);
307 : }
308 :
309 : // static
310 8280172 : MaybeHandle<String> Object::ConvertToString(Isolate* isolate,
311 : Handle<Object> input) {
312 : while (true) {
313 16927940 : if (input->IsOddball()) {
314 8084493 : return handle(Handle<Oddball>::cast(input)->to_string(), isolate);
315 : }
316 11538278 : if (input->IsNumber()) {
317 264458 : return isolate->factory()->NumberToString(input);
318 : }
319 11009362 : if (input->IsSymbol()) {
320 2078 : THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToString),
321 : String);
322 : }
323 11005206 : if (input->IsBigInt()) {
324 8842 : return BigInt::ToString(isolate, Handle<BigInt>::cast(input));
325 : }
326 10987522 : ASSIGN_RETURN_ON_EXCEPTION(
327 : isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
328 : ToPrimitiveHint::kString),
329 : String);
330 : // The previous isString() check happened in Object::ToString and thus we
331 : // put it at the end of the loop in this helper.
332 10970224 : if (input->IsString()) {
333 5301314 : return Handle<String>::cast(input);
334 : }
335 : }
336 : }
337 :
338 : namespace {
339 :
340 31084 : bool IsErrorObject(Isolate* isolate, Handle<Object> object) {
341 62168 : if (!object->IsJSReceiver()) return false;
342 : Handle<Symbol> symbol = isolate->factory()->stack_trace_symbol();
343 62168 : return JSReceiver::HasOwnProperty(Handle<JSReceiver>::cast(object), symbol)
344 62168 : .FromMaybe(false);
345 : }
346 :
347 27634 : Handle<String> AsStringOrEmpty(Isolate* isolate, Handle<Object> object) {
348 55268 : return object->IsString() ? Handle<String>::cast(object)
349 55268 : : isolate->factory()->empty_string();
350 : }
351 :
352 4833 : Handle<String> NoSideEffectsErrorToString(Isolate* isolate,
353 : Handle<Object> input) {
354 4833 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input);
355 :
356 : Handle<Name> name_key = isolate->factory()->name_string();
357 4833 : Handle<Object> name = JSReceiver::GetDataProperty(receiver, name_key);
358 4833 : Handle<String> name_str = AsStringOrEmpty(isolate, name);
359 :
360 : Handle<Name> msg_key = isolate->factory()->message_string();
361 4833 : Handle<Object> msg = JSReceiver::GetDataProperty(receiver, msg_key);
362 4833 : Handle<String> msg_str = AsStringOrEmpty(isolate, msg);
363 :
364 4833 : if (name_str->length() == 0) return msg_str;
365 4815 : if (msg_str->length() == 0) return name_str;
366 :
367 4653 : IncrementalStringBuilder builder(isolate);
368 4653 : builder.AppendString(name_str);
369 : builder.AppendCString(": ");
370 4653 : builder.AppendString(msg_str);
371 :
372 9306 : return builder.Finish().ToHandleChecked();
373 : }
374 :
375 : } // namespace
376 :
377 : // static
378 3486854 : Handle<String> Object::NoSideEffectsToString(Isolate* isolate,
379 : Handle<Object> input) {
380 3486854 : DisallowJavascriptExecution no_js(isolate);
381 :
382 17765368 : if (input->IsString() || input->IsNumber() || input->IsOddball()) {
383 6906858 : return Object::ToString(isolate, input).ToHandleChecked();
384 66850 : } else if (input->IsBigInt()) {
385 : MaybeHandle<String> maybe_string =
386 14 : BigInt::ToString(isolate, Handle<BigInt>::cast(input), 10, kDontThrow);
387 : Handle<String> result;
388 14 : if (maybe_string.ToHandle(&result)) return result;
389 : // BigInt-to-String conversion can fail on 32-bit platforms where
390 : // String::kMaxLength is too small to fit this BigInt.
391 : return isolate->factory()->NewStringFromStaticChars(
392 0 : "<a very large BigInt>");
393 66822 : } else if (input->IsFunction()) {
394 : // -- F u n c t i o n
395 : Handle<String> fun_str;
396 1044 : if (input->IsJSBoundFunction()) {
397 0 : fun_str = JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(input));
398 : } else {
399 : DCHECK(input->IsJSFunction());
400 522 : fun_str = JSFunction::ToString(Handle<JSFunction>::cast(input));
401 : }
402 :
403 522 : if (fun_str->length() > 128) {
404 9 : IncrementalStringBuilder builder(isolate);
405 9 : builder.AppendString(isolate->factory()->NewSubString(fun_str, 0, 111));
406 : builder.AppendCString("...<omitted>...");
407 : builder.AppendString(isolate->factory()->NewSubString(
408 9 : fun_str, fun_str->length() - 2, fun_str->length()));
409 :
410 18 : return builder.Finish().ToHandleChecked();
411 : }
412 513 : return fun_str;
413 65778 : } else if (input->IsSymbol()) {
414 : // -- S y m b o l
415 1805 : Handle<Symbol> symbol = Handle<Symbol>::cast(input);
416 :
417 1805 : IncrementalStringBuilder builder(isolate);
418 : builder.AppendCString("Symbol(");
419 3610 : if (symbol->name()->IsString()) {
420 2530 : builder.AppendString(handle(String::cast(symbol->name()), isolate));
421 : }
422 : builder.AppendCharacter(')');
423 :
424 3610 : return builder.Finish().ToHandleChecked();
425 62168 : } else if (input->IsJSReceiver()) {
426 : // -- J S R e c e i v e r
427 31084 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input);
428 : Handle<Object> to_string = JSReceiver::GetDataProperty(
429 31084 : receiver, isolate->factory()->toString_string());
430 :
431 93252 : if (IsErrorObject(isolate, input) ||
432 83604 : *to_string == *isolate->error_to_string()) {
433 : // When internally formatting error objects, use a side-effects-free
434 : // version of Error.prototype.toString independent of the actually
435 : // installed toString method.
436 26894 : return NoSideEffectsErrorToString(isolate, input);
437 52502 : } else if (*to_string == *isolate->object_to_string()) {
438 : Handle<Object> ctor = JSReceiver::GetDataProperty(
439 18193 : receiver, isolate->factory()->constructor_string());
440 36386 : if (ctor->IsFunction()) {
441 : Handle<String> ctor_name;
442 35936 : if (ctor->IsJSBoundFunction()) {
443 : ctor_name = JSBoundFunction::GetName(
444 0 : isolate, Handle<JSBoundFunction>::cast(ctor))
445 0 : .ToHandleChecked();
446 35936 : } else if (ctor->IsJSFunction()) {
447 : Handle<Object> ctor_name_obj =
448 17968 : JSFunction::GetName(isolate, Handle<JSFunction>::cast(ctor));
449 17968 : ctor_name = AsStringOrEmpty(isolate, ctor_name_obj);
450 : }
451 :
452 17968 : if (ctor_name->length() != 0) {
453 17228 : IncrementalStringBuilder builder(isolate);
454 : builder.AppendCString("#<");
455 17228 : builder.AppendString(ctor_name);
456 : builder.AppendCString(">");
457 :
458 34456 : return builder.Finish().ToHandleChecked();
459 : }
460 : }
461 : }
462 : }
463 :
464 : // At this point, input is either none of the above or a JSReceiver.
465 :
466 : Handle<JSReceiver> receiver;
467 18046 : if (input->IsJSReceiver()) {
468 9023 : receiver = Handle<JSReceiver>::cast(input);
469 : } else {
470 : // This is the only case where Object::ToObject throws.
471 : DCHECK(!input->IsSmi());
472 : int constructor_function_index =
473 0 : Handle<HeapObject>::cast(input)->map()->GetConstructorFunctionIndex();
474 0 : if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
475 0 : return isolate->factory()->NewStringFromAsciiChecked("[object Unknown]");
476 : }
477 :
478 0 : receiver = Object::ToObject(isolate, input, isolate->native_context())
479 0 : .ToHandleChecked();
480 : }
481 :
482 18046 : Handle<String> builtin_tag = handle(receiver->class_name(), isolate);
483 : Handle<Object> tag_obj = JSReceiver::GetDataProperty(
484 9023 : receiver, isolate->factory()->to_string_tag_symbol());
485 : Handle<String> tag =
486 18046 : tag_obj->IsString() ? Handle<String>::cast(tag_obj) : builtin_tag;
487 :
488 9023 : IncrementalStringBuilder builder(isolate);
489 : builder.AppendCString("[object ");
490 9023 : builder.AppendString(tag);
491 : builder.AppendCString("]");
492 :
493 18046 : return builder.Finish().ToHandleChecked();
494 : }
495 :
496 : // static
497 2322 : MaybeHandle<Object> Object::ConvertToLength(Isolate* isolate,
498 : Handle<Object> input) {
499 4644 : ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(isolate, input), Object);
500 4302 : if (input->IsSmi()) {
501 1647 : int value = std::max(Smi::ToInt(*input), 0);
502 549 : return handle(Smi::FromInt(value), isolate);
503 : }
504 1602 : double len = DoubleToInteger(input->Number());
505 1602 : if (len <= 0.0) {
506 1179 : return handle(Smi::kZero, isolate);
507 423 : } else if (len >= kMaxSafeInteger) {
508 : len = kMaxSafeInteger;
509 : }
510 423 : return isolate->factory()->NewNumber(len);
511 : }
512 :
513 : // static
514 1293 : MaybeHandle<Object> Object::ConvertToIndex(Isolate* isolate,
515 : Handle<Object> input,
516 : MessageTemplate error_index) {
517 3411 : if (input->IsUndefined(isolate)) return handle(Smi::kZero, isolate);
518 936 : ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(isolate, input), Object);
519 1012 : if (input->IsSmi() && Smi::ToInt(*input) >= 0) return input;
520 396 : double len = DoubleToInteger(input->Number()) + 0.0;
521 396 : auto js_len = isolate->factory()->NewNumber(len);
522 396 : if (len < 0.0 || len > kMaxSafeInteger) {
523 108 : THROW_NEW_ERROR(isolate, NewRangeError(error_index, js_len), Object);
524 : }
525 288 : return js_len;
526 : }
527 :
528 89990686 : bool Object::BooleanValue(Isolate* isolate) {
529 89990740 : if (IsSmi()) return Smi::ToInt(*this) != 0;
530 : DCHECK(IsHeapObject());
531 91265280 : if (IsBoolean()) return IsTrue(isolate);
532 88705334 : if (IsNullOrUndefined(isolate)) return false;
533 87723282 : if (IsUndetectable()) return false; // Undetectable object is false.
534 95222760 : if (IsString()) return String::cast(*this)->length() != 0;
535 80685558 : if (IsHeapNumber()) return DoubleToBoolean(HeapNumber::cast(*this)->value());
536 79766547 : if (IsBigInt()) return BigInt::cast(*this)->ToBoolean();
537 : return true;
538 : }
539 :
540 : namespace {
541 :
542 : // TODO(bmeurer): Maybe we should introduce a marker interface Number,
543 : // where we put all these methods at some point?
544 : ComparisonResult NumberCompare(double x, double y) {
545 660 : if (std::isnan(x) || std::isnan(y)) {
546 : return ComparisonResult::kUndefined;
547 480 : } else if (x < y) {
548 : return ComparisonResult::kLessThan;
549 260 : } else if (x > y) {
550 : return ComparisonResult::kGreaterThan;
551 : } else {
552 : return ComparisonResult::kEqual;
553 : }
554 : }
555 :
556 : bool NumberEquals(double x, double y) {
557 : // Must check explicitly for NaN's on Windows, but -0 works fine.
558 11421 : if (std::isnan(x)) return false;
559 11329 : if (std::isnan(y)) return false;
560 11262 : return x == y;
561 : }
562 :
563 11421 : bool NumberEquals(const Object x, const Object y) {
564 22842 : return NumberEquals(x->Number(), y->Number());
565 : }
566 :
567 4227 : bool NumberEquals(Handle<Object> x, Handle<Object> y) {
568 4227 : return NumberEquals(*x, *y);
569 : }
570 :
571 : ComparisonResult Reverse(ComparisonResult result) {
572 153 : if (result == ComparisonResult::kLessThan) {
573 : return ComparisonResult::kGreaterThan;
574 : }
575 135 : if (result == ComparisonResult::kGreaterThan) {
576 : return ComparisonResult::kLessThan;
577 : }
578 : return result;
579 : }
580 :
581 : } // anonymous namespace
582 :
583 : // static
584 1069 : Maybe<ComparisonResult> Object::Compare(Isolate* isolate, Handle<Object> x,
585 : Handle<Object> y) {
586 : // ES6 section 7.2.11 Abstract Relational Comparison step 3 and 4.
587 4276 : if (!Object::ToPrimitive(x, ToPrimitiveHint::kNumber).ToHandle(&x) ||
588 2138 : !Object::ToPrimitive(y, ToPrimitiveHint::kNumber).ToHandle(&y)) {
589 : return Nothing<ComparisonResult>();
590 : }
591 2544 : if (x->IsString() && y->IsString()) {
592 : // ES6 section 7.2.11 Abstract Relational Comparison step 5.
593 : return Just(String::Compare(isolate, Handle<String>::cast(x),
594 40 : Handle<String>::cast(y)));
595 : }
596 2472 : if (x->IsBigInt() && y->IsString()) {
597 : return Just(BigInt::CompareToString(isolate, Handle<BigInt>::cast(x),
598 63 : Handle<String>::cast(y)));
599 : }
600 2258 : if (x->IsString() && y->IsBigInt()) {
601 : return Just(Reverse(BigInt::CompareToString(
602 63 : isolate, Handle<BigInt>::cast(y), Handle<String>::cast(x))));
603 : }
604 : // ES6 section 7.2.11 Abstract Relational Comparison step 6.
605 3603 : if (!Object::ToNumeric(isolate, x).ToHandle(&x) ||
606 1797 : !Object::ToNumeric(isolate, y).ToHandle(&y)) {
607 : return Nothing<ComparisonResult>();
608 : }
609 :
610 1770 : bool x_is_number = x->IsNumber();
611 1770 : bool y_is_number = y->IsNumber();
612 885 : if (x_is_number && y_is_number) {
613 1980 : return Just(NumberCompare(x->Number(), y->Number()));
614 225 : } else if (!x_is_number && !y_is_number) {
615 : return Just(BigInt::CompareToBigInt(Handle<BigInt>::cast(x),
616 45 : Handle<BigInt>::cast(y)));
617 180 : } else if (x_is_number) {
618 90 : return Just(Reverse(BigInt::CompareToNumber(Handle<BigInt>::cast(y), x)));
619 : } else {
620 90 : return Just(BigInt::CompareToNumber(Handle<BigInt>::cast(x), y));
621 : }
622 : }
623 :
624 :
625 : // static
626 169241 : Maybe<bool> Object::Equals(Isolate* isolate, Handle<Object> x,
627 : Handle<Object> y) {
628 : // This is the generic version of Abstract Equality Comparison. Must be in
629 : // sync with CodeStubAssembler::Equal.
630 : while (true) {
631 338638 : if (x->IsNumber()) {
632 9100 : if (y->IsNumber()) {
633 4092 : return Just(NumberEquals(x, y));
634 916 : } else if (y->IsBoolean()) {
635 0 : return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
636 916 : } else if (y->IsString()) {
637 : return Just(NumberEquals(
638 80 : x, String::ToNumber(isolate, Handle<String>::cast(y))));
639 756 : } else if (y->IsBigInt()) {
640 378 : return Just(BigInt::EqualToNumber(Handle<BigInt>::cast(y), x));
641 0 : } else if (y->IsJSReceiver()) {
642 0 : if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
643 0 : .ToHandle(&y)) {
644 : return Nothing<bool>();
645 : }
646 : } else {
647 : return Just(false);
648 : }
649 329538 : } else if (x->IsString()) {
650 286232 : if (y->IsString()) {
651 : return Just(String::Equals(isolate, Handle<String>::cast(x),
652 142899 : Handle<String>::cast(y)));
653 434 : } else if (y->IsNumber()) {
654 55 : x = String::ToNumber(isolate, Handle<String>::cast(x));
655 55 : return Just(NumberEquals(x, y));
656 324 : } else if (y->IsBoolean()) {
657 0 : x = String::ToNumber(isolate, Handle<String>::cast(x));
658 0 : return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
659 324 : } else if (y->IsBigInt()) {
660 : return Just(BigInt::EqualToString(isolate, Handle<BigInt>::cast(y),
661 162 : Handle<String>::cast(x)));
662 0 : } else if (y->IsJSReceiver()) {
663 0 : if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
664 0 : .ToHandle(&y)) {
665 : return Nothing<bool>();
666 : }
667 : } else {
668 : return Just(false);
669 : }
670 43306 : } else if (x->IsBoolean()) {
671 1632 : if (y->IsOddball()) {
672 : return Just(x.is_identical_to(y));
673 432 : } else if (y->IsNumber()) {
674 0 : return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
675 432 : } else if (y->IsString()) {
676 0 : y = String::ToNumber(isolate, Handle<String>::cast(y));
677 0 : return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
678 432 : } else if (y->IsBigInt()) {
679 216 : x = Oddball::ToNumber(isolate, Handle<Oddball>::cast(x));
680 216 : return Just(BigInt::EqualToNumber(Handle<BigInt>::cast(y), x));
681 0 : } else if (y->IsJSReceiver()) {
682 0 : if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
683 0 : .ToHandle(&y)) {
684 : return Nothing<bool>();
685 : }
686 0 : x = Oddball::ToNumber(isolate, Handle<Oddball>::cast(x));
687 : } else {
688 : return Just(false);
689 : }
690 41674 : } else if (x->IsSymbol()) {
691 180 : if (y->IsSymbol()) {
692 : return Just(x.is_identical_to(y));
693 72 : } else if (y->IsJSReceiver()) {
694 0 : if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
695 0 : .ToHandle(&y)) {
696 : return Nothing<bool>();
697 : }
698 : } else {
699 : return Just(false);
700 : }
701 41494 : } else if (x->IsBigInt()) {
702 954 : if (y->IsBigInt()) {
703 81 : return Just(BigInt::EqualToBigInt(BigInt::cast(*x), BigInt::cast(*y)));
704 : }
705 396 : return Equals(isolate, y, x);
706 40540 : } else if (x->IsJSReceiver()) {
707 40336 : if (y->IsJSReceiver()) {
708 : return Just(x.is_identical_to(y));
709 156 : } else if (y->IsUndetectable()) {
710 0 : return Just(x->IsUndetectable());
711 156 : } else if (y->IsBoolean()) {
712 0 : y = Oddball::ToNumber(isolate, Handle<Oddball>::cast(y));
713 156 : } else if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(x))
714 156 : .ToHandle(&x)) {
715 : return Nothing<bool>();
716 : }
717 : } else {
718 510 : return Just(x->IsUndetectable() && y->IsUndetectable());
719 : }
720 : }
721 : }
722 :
723 10337 : bool Object::StrictEquals(Object that) {
724 10337 : if (this->IsNumber()) {
725 7751 : if (!that->IsNumber()) return false;
726 7194 : return NumberEquals(*this, that);
727 2586 : } else if (this->IsString()) {
728 1337 : if (!that->IsString()) return false;
729 1272 : return String::cast(*this)->Equals(String::cast(that));
730 1249 : } else if (this->IsBigInt()) {
731 90 : if (!that->IsBigInt()) return false;
732 72 : return BigInt::EqualToBigInt(BigInt::cast(*this), BigInt::cast(that));
733 : }
734 1159 : return *this == that;
735 : }
736 :
737 : // static
738 12779 : Handle<String> Object::TypeOf(Isolate* isolate, Handle<Object> object) {
739 25558 : if (object->IsNumber()) return isolate->factory()->number_string();
740 24902 : if (object->IsOddball())
741 3144 : return handle(Oddball::cast(*object)->type_of(), isolate);
742 21758 : if (object->IsUndetectable()) {
743 : return isolate->factory()->undefined_string();
744 : }
745 21758 : if (object->IsString()) return isolate->factory()->string_string();
746 21280 : if (object->IsSymbol()) return isolate->factory()->symbol_string();
747 21180 : if (object->IsBigInt()) return isolate->factory()->bigint_string();
748 21144 : if (object->IsCallable()) return isolate->factory()->function_string();
749 : return isolate->factory()->object_string();
750 : }
751 :
752 :
753 : // static
754 40 : MaybeHandle<Object> Object::Add(Isolate* isolate, Handle<Object> lhs,
755 : Handle<Object> rhs) {
756 140 : if (lhs->IsNumber() && rhs->IsNumber()) {
757 60 : return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
758 20 : } else if (lhs->IsString() && rhs->IsString()) {
759 : return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
760 0 : Handle<String>::cast(rhs));
761 : }
762 20 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToPrimitive(lhs), Object);
763 20 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToPrimitive(rhs), Object);
764 40 : if (lhs->IsString() || rhs->IsString()) {
765 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToString(isolate, rhs),
766 : Object);
767 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToString(isolate, lhs),
768 : Object);
769 : return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
770 0 : Handle<String>::cast(rhs));
771 : }
772 20 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(isolate, rhs),
773 : Object);
774 20 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(isolate, lhs),
775 : Object);
776 20 : return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
777 : }
778 :
779 :
780 : // static
781 107560 : MaybeHandle<Object> Object::OrdinaryHasInstance(Isolate* isolate,
782 : Handle<Object> callable,
783 : Handle<Object> object) {
784 : // The {callable} must have a [[Call]] internal method.
785 215155 : if (!callable->IsCallable()) return isolate->factory()->false_value();
786 :
787 : // Check if {callable} is a bound function, and if so retrieve its
788 : // [[BoundTargetFunction]] and use that instead of {callable}.
789 215050 : if (callable->IsJSBoundFunction()) {
790 : Handle<Object> bound_callable(
791 876 : Handle<JSBoundFunction>::cast(callable)->bound_target_function(),
792 584 : isolate);
793 292 : return Object::InstanceOf(isolate, object, bound_callable);
794 : }
795 :
796 : // If {object} is not a receiver, return false.
797 221754 : if (!object->IsJSReceiver()) return isolate->factory()->false_value();
798 :
799 : // Get the "prototype" of {callable}; raise an error if it's not a receiver.
800 : Handle<Object> prototype;
801 199890 : ASSIGN_RETURN_ON_EXCEPTION(
802 : isolate, prototype,
803 : Object::GetProperty(isolate, callable,
804 : isolate->factory()->prototype_string()),
805 : Object);
806 199890 : if (!prototype->IsJSReceiver()) {
807 99603 : THROW_NEW_ERROR(
808 : isolate,
809 : NewTypeError(MessageTemplate::kInstanceofNonobjectProto, prototype),
810 : Object);
811 : }
812 :
813 : // Return whether or not {prototype} is in the prototype chain of {object}.
814 : Maybe<bool> result = JSReceiver::HasInPrototypeChain(
815 342 : isolate, Handle<JSReceiver>::cast(object), prototype);
816 342 : if (result.IsNothing()) return MaybeHandle<Object>();
817 342 : return isolate->factory()->ToBoolean(result.FromJust());
818 : }
819 :
820 : // static
821 8924 : MaybeHandle<Object> Object::InstanceOf(Isolate* isolate, Handle<Object> object,
822 : Handle<Object> callable) {
823 : // The {callable} must be a receiver.
824 17848 : if (!callable->IsJSReceiver()) {
825 0 : THROW_NEW_ERROR(isolate,
826 : NewTypeError(MessageTemplate::kNonObjectInInstanceOfCheck),
827 : Object);
828 : }
829 :
830 : // Lookup the @@hasInstance method on {callable}.
831 : Handle<Object> inst_of_handler;
832 17848 : ASSIGN_RETURN_ON_EXCEPTION(
833 : isolate, inst_of_handler,
834 : Object::GetMethod(Handle<JSReceiver>::cast(callable),
835 : isolate->factory()->has_instance_symbol()),
836 : Object);
837 17848 : if (!inst_of_handler->IsUndefined(isolate)) {
838 : // Call the {inst_of_handler} on the {callable}.
839 : Handle<Object> result;
840 17836 : ASSIGN_RETURN_ON_EXCEPTION(
841 : isolate, result,
842 : Execution::Call(isolate, inst_of_handler, callable, 1, &object),
843 : Object);
844 8912 : return isolate->factory()->ToBoolean(result->BooleanValue(isolate));
845 : }
846 :
847 : // The {callable} must have a [[Call]] internal method.
848 12 : if (!callable->IsCallable()) {
849 6 : THROW_NEW_ERROR(
850 : isolate, NewTypeError(MessageTemplate::kNonCallableInInstanceOfCheck),
851 : Object);
852 : }
853 :
854 : // Fall back to OrdinaryHasInstance with {callable} and {object}.
855 : Handle<Object> result;
856 0 : ASSIGN_RETURN_ON_EXCEPTION(
857 : isolate, result, Object::OrdinaryHasInstance(isolate, callable, object),
858 : Object);
859 0 : return result;
860 : }
861 :
862 : // static
863 10771302 : MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
864 : Handle<Name> name) {
865 : Handle<Object> func;
866 : Isolate* isolate = receiver->GetIsolate();
867 21542604 : ASSIGN_RETURN_ON_EXCEPTION(
868 : isolate, func, JSReceiver::GetProperty(isolate, receiver, name), Object);
869 21495876 : if (func->IsNullOrUndefined(isolate)) {
870 9696416 : return isolate->factory()->undefined_value();
871 : }
872 2103044 : if (!func->IsCallable()) {
873 234 : THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kPropertyNotFunction,
874 : func, name, receiver),
875 : Object);
876 : }
877 1051288 : return func;
878 : }
879 :
880 : namespace {
881 :
882 17699 : MaybeHandle<FixedArray> CreateListFromArrayLikeFastPath(
883 : Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
884 17699 : if (element_types == ElementTypes::kAll) {
885 33076 : if (object->IsJSArray()) {
886 395 : Handle<JSArray> array = Handle<JSArray>::cast(object);
887 : uint32_t length;
888 1185 : if (!array->HasArrayPrototype(isolate) ||
889 2190 : !array->length()->ToUint32(&length) || !array->HasFastElements() ||
890 610 : !JSObject::PrototypeHasNoElements(isolate, *array)) {
891 279 : return MaybeHandle<FixedArray>();
892 : }
893 232 : return array->GetElementsAccessor()->CreateListFromArrayLike(
894 232 : isolate, array, length);
895 32286 : } else if (object->IsJSTypedArray()) {
896 657 : Handle<JSTypedArray> array = Handle<JSTypedArray>::cast(object);
897 : size_t length = array->length_value();
898 657 : if (array->WasDetached() ||
899 : length > static_cast<size_t>(FixedArray::kMaxLength)) {
900 0 : return MaybeHandle<FixedArray>();
901 : }
902 1314 : return array->GetElementsAccessor()->CreateListFromArrayLike(
903 1314 : isolate, array, static_cast<uint32_t>(length));
904 : }
905 : }
906 16647 : return MaybeHandle<FixedArray>();
907 : }
908 :
909 : } // namespace
910 :
911 : // static
912 17699 : MaybeHandle<FixedArray> Object::CreateListFromArrayLike(
913 : Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
914 : // Fast-path for JSArray and JSTypedArray.
915 : MaybeHandle<FixedArray> fast_result =
916 17699 : CreateListFromArrayLikeFastPath(isolate, object, element_types);
917 17699 : if (!fast_result.is_null()) return fast_result;
918 : // 1. ReturnIfAbrupt(object).
919 : // 2. (default elementTypes -- not applicable.)
920 : // 3. If Type(obj) is not Object, throw a TypeError exception.
921 33852 : if (!object->IsJSReceiver()) {
922 918 : THROW_NEW_ERROR(isolate,
923 : NewTypeError(MessageTemplate::kCalledOnNonObject,
924 : isolate->factory()->NewStringFromAsciiChecked(
925 : "CreateListFromArrayLike")),
926 : FixedArray);
927 : }
928 :
929 : // 4. Let len be ? ToLength(? Get(obj, "length")).
930 16467 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
931 : Handle<Object> raw_length_number;
932 32934 : ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number,
933 : Object::GetLengthFromArrayLike(isolate, receiver),
934 : FixedArray);
935 : uint32_t len;
936 32853 : if (!raw_length_number->ToUint32(&len) ||
937 16422 : len > static_cast<uint32_t>(FixedArray::kMaxLength)) {
938 27 : THROW_NEW_ERROR(isolate,
939 : NewRangeError(MessageTemplate::kInvalidArrayLength),
940 : FixedArray);
941 : }
942 : // 5. Let list be an empty List.
943 16404 : Handle<FixedArray> list = isolate->factory()->NewFixedArray(len);
944 : // 6. Let index be 0.
945 : // 7. Repeat while index < len:
946 40159821 : for (uint32_t index = 0; index < len; ++index) {
947 : // 7a. Let indexName be ToString(index).
948 : // 7b. Let next be ? Get(obj, indexName).
949 : Handle<Object> next;
950 80286978 : ASSIGN_RETURN_ON_EXCEPTION(isolate, next,
951 : JSReceiver::GetElement(isolate, receiver, index),
952 : FixedArray);
953 40143453 : switch (element_types) {
954 : case ElementTypes::kAll:
955 : // Nothing to do.
956 : break;
957 : case ElementTypes::kStringAndSymbol: {
958 : // 7c. If Type(next) is not an element of elementTypes, throw a
959 : // TypeError exception.
960 6048 : if (!next->IsName()) {
961 36 : THROW_NEW_ERROR(isolate,
962 : NewTypeError(MessageTemplate::kNotPropertyName, next),
963 : FixedArray);
964 : }
965 : // 7d. Append next as the last element of list.
966 : // Internalize on the fly so we can use pointer identity later.
967 2988 : next = isolate->factory()->InternalizeName(Handle<Name>::cast(next));
968 2988 : break;
969 : }
970 : }
971 80286834 : list->set(index, *next);
972 : // 7e. Set index to index + 1. (See loop header.)
973 : }
974 : // 8. Return list.
975 16332 : return list;
976 : }
977 :
978 :
979 : // static
980 55078 : MaybeHandle<Object> Object::GetLengthFromArrayLike(Isolate* isolate,
981 : Handle<JSReceiver> object) {
982 : Handle<Object> val;
983 : Handle<Name> key = isolate->factory()->length_string();
984 110156 : ASSIGN_RETURN_ON_EXCEPTION(
985 : isolate, val, JSReceiver::GetProperty(isolate, object, key), Object);
986 54979 : return Object::ToLength(isolate, val);
987 : }
988 :
989 : // static
990 10349419 : Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) {
991 10325592 : for (; it->IsFound(); it->Next()) {
992 1614448 : switch (it->state()) {
993 : case LookupIterator::NOT_FOUND:
994 : case LookupIterator::TRANSITION:
995 0 : UNREACHABLE();
996 : case LookupIterator::JSPROXY:
997 : return JSProxy::HasProperty(it->isolate(), it->GetHolder<JSProxy>(),
998 105806 : it->GetName());
999 : case LookupIterator::INTERCEPTOR: {
1000 : Maybe<PropertyAttributes> result =
1001 226 : JSObject::GetPropertyAttributesWithInterceptor(it);
1002 300 : if (result.IsNothing()) return Nothing<bool>();
1003 220 : if (result.FromJust() != ABSENT) return Just(true);
1004 152 : break;
1005 : }
1006 : case LookupIterator::ACCESS_CHECK: {
1007 28964 : if (it->HasAccess()) break;
1008 : Maybe<PropertyAttributes> result =
1009 40 : JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
1010 80 : if (result.IsNothing()) return Nothing<bool>();
1011 0 : return Just(result.FromJust() != ABSENT);
1012 : }
1013 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
1014 : // TypedArray out-of-bounds access.
1015 : return Just(false);
1016 : case LookupIterator::ACCESSOR:
1017 : case LookupIterator::DATA:
1018 : return Just(true);
1019 : }
1020 : }
1021 : return Just(false);
1022 : }
1023 :
1024 : // static
1025 421660 : Maybe<bool> JSReceiver::HasOwnProperty(Handle<JSReceiver> object,
1026 : Handle<Name> name) {
1027 843320 : if (object->IsJSModuleNamespace()) {
1028 : PropertyDescriptor desc;
1029 : return JSReceiver::GetOwnPropertyDescriptor(object->GetIsolate(), object,
1030 171 : name, &desc);
1031 : }
1032 :
1033 842978 : if (object->IsJSObject()) { // Shortcut.
1034 : LookupIterator it = LookupIterator::PropertyOrElement(
1035 420100 : object->GetIsolate(), object, name, object, LookupIterator::OWN);
1036 420100 : return HasProperty(&it);
1037 : }
1038 :
1039 : Maybe<PropertyAttributes> attributes =
1040 1389 : JSReceiver::GetOwnPropertyAttributes(object, name);
1041 1389 : MAYBE_RETURN(attributes, Nothing<bool>());
1042 1299 : return Just(attributes.FromJust() != ABSENT);
1043 : }
1044 :
1045 : // static
1046 114983596 : MaybeHandle<Object> Object::GetProperty(LookupIterator* it,
1047 : OnNonExistent on_non_existent) {
1048 93562750 : for (; it->IsFound(); it->Next()) {
1049 24751250 : switch (it->state()) {
1050 : case LookupIterator::NOT_FOUND:
1051 : case LookupIterator::TRANSITION:
1052 0 : UNREACHABLE();
1053 : case LookupIterator::JSPROXY: {
1054 : bool was_found;
1055 : Handle<Object> receiver = it->GetReceiver();
1056 : // In case of global IC, the receiver is the global object. Replace by
1057 : // the global proxy.
1058 335572 : if (receiver->IsJSGlobalObject()) {
1059 : receiver = handle(JSGlobalObject::cast(*receiver)->global_proxy(),
1060 200 : it->isolate());
1061 : }
1062 : MaybeHandle<Object> result =
1063 : JSProxy::GetProperty(it->isolate(), it->GetHolder<JSProxy>(),
1064 335572 : it->GetName(), receiver, &was_found);
1065 167786 : if (!was_found) it->NotFound();
1066 167786 : return result;
1067 : }
1068 : case LookupIterator::INTERCEPTOR: {
1069 : bool done;
1070 : Handle<Object> result;
1071 228166 : ASSIGN_RETURN_ON_EXCEPTION(
1072 : it->isolate(), result,
1073 : JSObject::GetPropertyWithInterceptor(it, &done), Object);
1074 114065 : if (done) return result;
1075 110871 : break;
1076 : }
1077 : case LookupIterator::ACCESS_CHECK:
1078 670249 : if (it->HasAccess()) break;
1079 1169 : return JSObject::GetPropertyWithFailedAccessCheck(it);
1080 : case LookupIterator::ACCESSOR:
1081 918600 : return GetPropertyWithAccessor(it);
1082 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
1083 2782 : return it->isolate()->factory()->undefined_value();
1084 : case LookupIterator::DATA:
1085 22877752 : return it->GetDataValue();
1086 : }
1087 : }
1088 :
1089 22030127 : if (on_non_existent == OnNonExistent::kThrowReferenceError) {
1090 35 : THROW_NEW_ERROR(it->isolate(),
1091 : NewReferenceError(MessageTemplate::kNotDefined, it->name()),
1092 : Object);
1093 : }
1094 22030092 : return it->isolate()->factory()->undefined_value();
1095 : }
1096 :
1097 :
1098 : // static
1099 167786 : MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
1100 : Handle<JSProxy> proxy,
1101 : Handle<Name> name,
1102 : Handle<Object> receiver,
1103 : bool* was_found) {
1104 167786 : *was_found = true;
1105 :
1106 : DCHECK(!name->IsPrivate());
1107 167786 : STACK_CHECK(isolate, MaybeHandle<Object>());
1108 : Handle<Name> trap_name = isolate->factory()->get_string();
1109 : // 1. Assert: IsPropertyKey(P) is true.
1110 : // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
1111 335230 : Handle<Object> handler(proxy->handler(), isolate);
1112 : // 3. If handler is null, throw a TypeError exception.
1113 : // 4. Assert: Type(handler) is Object.
1114 335230 : if (proxy->IsRevoked()) {
1115 36 : THROW_NEW_ERROR(isolate,
1116 : NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1117 : Object);
1118 : }
1119 : // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
1120 335158 : Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
1121 : // 6. Let trap be ? GetMethod(handler, "get").
1122 : Handle<Object> trap;
1123 335158 : ASSIGN_RETURN_ON_EXCEPTION(
1124 : isolate, trap,
1125 : Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), Object);
1126 : // 7. If trap is undefined, then
1127 289178 : if (trap->IsUndefined(isolate)) {
1128 : // 7.a Return target.[[Get]](P, Receiver).
1129 : LookupIterator it =
1130 112408 : LookupIterator::PropertyOrElement(isolate, receiver, name, target);
1131 112408 : MaybeHandle<Object> result = Object::GetProperty(&it);
1132 224816 : *was_found = it.IsFound();
1133 112408 : return result;
1134 : }
1135 : // 8. Let trapResult be ? Call(trap, handler, «target, P, Receiver»).
1136 : Handle<Object> trap_result;
1137 32181 : Handle<Object> args[] = {target, name, receiver};
1138 64362 : ASSIGN_RETURN_ON_EXCEPTION(
1139 : isolate, trap_result,
1140 : Execution::Call(isolate, trap, handler, arraysize(args), args), Object);
1141 :
1142 : MaybeHandle<Object> result =
1143 25012 : JSProxy::CheckGetSetTrapResult(isolate, name, target, trap_result, kGet);
1144 25012 : if (result.is_null()) {
1145 45 : return result;
1146 : }
1147 :
1148 : // 11. Return trap_result
1149 24967 : return trap_result;
1150 : }
1151 :
1152 : // static
1153 27397 : MaybeHandle<Object> JSProxy::CheckGetSetTrapResult(Isolate* isolate,
1154 : Handle<Name> name,
1155 : Handle<JSReceiver> target,
1156 : Handle<Object> trap_result,
1157 : AccessKind access_kind) {
1158 : // 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
1159 : PropertyDescriptor target_desc;
1160 : Maybe<bool> target_found =
1161 27397 : JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
1162 27397 : MAYBE_RETURN_NULL(target_found);
1163 : // 10. If targetDesc is not undefined, then
1164 27388 : if (target_found.FromJust()) {
1165 : // 10.a. If IsDataDescriptor(targetDesc) and targetDesc.[[Configurable]] is
1166 : // false and targetDesc.[[Writable]] is false, then
1167 : // 10.a.i. If SameValue(trapResult, targetDesc.[[Value]]) is false,
1168 : // throw a TypeError exception.
1169 7965 : bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
1170 2430 : !target_desc.configurable() &&
1171 9999 : !target_desc.writable() &&
1172 9999 : !trap_result->SameValue(*target_desc.value());
1173 8343 : if (inconsistent) {
1174 234 : if (access_kind == kGet) {
1175 54 : THROW_NEW_ERROR(
1176 : isolate,
1177 : NewTypeError(MessageTemplate::kProxyGetNonConfigurableData, name,
1178 : target_desc.value(), trap_result),
1179 : Object);
1180 : } else {
1181 : isolate->Throw(*isolate->factory()->NewTypeError(
1182 360 : MessageTemplate::kProxySetFrozenData, name));
1183 180 : return MaybeHandle<Object>();
1184 : }
1185 : }
1186 : // 10.b. If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]]
1187 : // is false and targetDesc.[[Get]] is undefined, then
1188 : // 10.b.i. If trapResult is not undefined, throw a TypeError exception.
1189 8109 : if (access_kind == kGet) {
1190 0 : inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
1191 0 : !target_desc.configurable() &&
1192 13446 : target_desc.get()->IsUndefined(isolate) &&
1193 6723 : !trap_result->IsUndefined(isolate);
1194 : } else {
1195 378 : inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
1196 1575 : !target_desc.configurable() &&
1197 1575 : target_desc.set()->IsUndefined(isolate);
1198 : }
1199 8109 : if (inconsistent) {
1200 189 : if (access_kind == kGet) {
1201 0 : THROW_NEW_ERROR(
1202 : isolate,
1203 : NewTypeError(MessageTemplate::kProxyGetNonConfigurableAccessor,
1204 : name, trap_result),
1205 : Object);
1206 : } else {
1207 : isolate->Throw(*isolate->factory()->NewTypeError(
1208 378 : MessageTemplate::kProxySetFrozenAccessor, name));
1209 189 : return MaybeHandle<Object>();
1210 : }
1211 : }
1212 : }
1213 26965 : return isolate->factory()->undefined_value();
1214 : }
1215 :
1216 :
1217 9847588 : Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it) {
1218 9270916 : for (; it->IsFound(); it->Next()) {
1219 4582145 : switch (it->state()) {
1220 : case LookupIterator::INTERCEPTOR:
1221 : case LookupIterator::NOT_FOUND:
1222 : case LookupIterator::TRANSITION:
1223 0 : UNREACHABLE();
1224 : case LookupIterator::ACCESS_CHECK:
1225 : // Support calling this method without an active context, but refuse
1226 : // access to access-checked objects in that case.
1227 596643 : if (!it->isolate()->context().is_null() && it->HasAccess()) continue;
1228 : V8_FALLTHROUGH;
1229 : case LookupIterator::JSPROXY:
1230 : it->NotFound();
1231 3006 : return it->isolate()->factory()->undefined_value();
1232 : case LookupIterator::ACCESSOR:
1233 : // TODO(verwaest): For now this doesn't call into AccessorInfo, since
1234 : // clients don't need it. Update once relevant.
1235 : it->NotFound();
1236 519529 : return it->isolate()->factory()->undefined_value();
1237 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
1238 0 : return it->isolate()->factory()->undefined_value();
1239 : case LookupIterator::DATA:
1240 3463791 : return it->GetDataValue();
1241 : }
1242 : }
1243 53313 : return it->isolate()->factory()->undefined_value();
1244 : }
1245 :
1246 :
1247 7079606 : bool Object::ToInt32(int32_t* value) {
1248 7079610 : if (IsSmi()) {
1249 7079439 : *value = Smi::ToInt(*this);
1250 7079439 : return true;
1251 : }
1252 171 : if (IsHeapNumber()) {
1253 : double num = HeapNumber::cast(*this)->value();
1254 : // Check range before conversion to avoid undefined behavior.
1255 135 : if (num >= kMinInt && num <= kMaxInt && FastI2D(FastD2I(num)) == num) {
1256 0 : *value = FastD2I(num);
1257 0 : return true;
1258 : }
1259 : }
1260 : return false;
1261 : }
1262 :
1263 : // static constexpr object declarations need a definition to make the
1264 : // compiler happy.
1265 : constexpr Object Smi::kZero;
1266 : constexpr Object SharedFunctionInfo::kNoSharedNameSentinel;
1267 :
1268 3837926 : Handle<SharedFunctionInfo> FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(
1269 : Isolate* isolate, Handle<FunctionTemplateInfo> info,
1270 : MaybeHandle<Name> maybe_name) {
1271 3837926 : Object current_info = info->shared_function_info();
1272 3837925 : if (current_info->IsSharedFunctionInfo()) {
1273 : return handle(SharedFunctionInfo::cast(current_info), isolate);
1274 : }
1275 : Handle<Name> name;
1276 : Handle<String> name_string;
1277 10946224 : if (maybe_name.ToHandle(&name) && name->IsString()) {
1278 3608634 : name_string = Handle<String>::cast(name);
1279 240628 : } else if (info->class_name()->IsString()) {
1280 468 : name_string = handle(String::cast(info->class_name()), isolate);
1281 : } else {
1282 : name_string = isolate->factory()->empty_string();
1283 : }
1284 : FunctionKind function_kind;
1285 3728948 : if (info->remove_prototype()) {
1286 : function_kind = kConciseMethod;
1287 : } else {
1288 : function_kind = kNormalFunction;
1289 : }
1290 : Handle<SharedFunctionInfo> result =
1291 : isolate->factory()->NewSharedFunctionInfoForApiFunction(name_string, info,
1292 7457894 : function_kind);
1293 :
1294 : result->set_length(info->length());
1295 : result->DontAdaptArguments();
1296 : DCHECK(result->IsApiFunction());
1297 :
1298 7457898 : info->set_shared_function_info(*result);
1299 3728951 : return result;
1300 : }
1301 :
1302 17779 : bool FunctionTemplateInfo::IsTemplateFor(Map map) {
1303 : // There is a constraint on the object; check.
1304 17779 : if (!map->IsJSObjectMap()) return false;
1305 : // Fetch the constructor function of the object.
1306 17779 : Object cons_obj = map->GetConstructor();
1307 17779 : Object type;
1308 17779 : if (cons_obj->IsJSFunction()) {
1309 17765 : JSFunction fun = JSFunction::cast(cons_obj);
1310 35530 : type = fun->shared()->function_data();
1311 14 : } else if (cons_obj->IsFunctionTemplateInfo()) {
1312 14 : type = FunctionTemplateInfo::cast(cons_obj);
1313 : } else {
1314 : return false;
1315 : }
1316 : // Iterate through the chain of inheriting function templates to
1317 : // see if the required one occurs.
1318 18850 : while (type->IsFunctionTemplateInfo()) {
1319 11521 : if (type == *this) return true;
1320 1071 : type = FunctionTemplateInfo::cast(type)->GetParentTemplate();
1321 : }
1322 : // Didn't find the required type in the inheritance chain.
1323 : return false;
1324 : }
1325 :
1326 : // static
1327 620119 : FunctionTemplateRareData FunctionTemplateInfo::AllocateFunctionTemplateRareData(
1328 : Isolate* isolate, Handle<FunctionTemplateInfo> function_template_info) {
1329 : DCHECK(function_template_info->rare_data()->IsUndefined(isolate));
1330 : Handle<Struct> struct_obj =
1331 620119 : isolate->factory()->NewStruct(FUNCTION_TEMPLATE_RARE_DATA_TYPE, TENURED);
1332 : Handle<FunctionTemplateRareData> rare_data =
1333 620119 : i::Handle<FunctionTemplateRareData>::cast(struct_obj);
1334 1240238 : function_template_info->set_rare_data(*rare_data);
1335 620119 : return *rare_data;
1336 : }
1337 :
1338 : // static
1339 365846 : Handle<TemplateList> TemplateList::New(Isolate* isolate, int size) {
1340 : Handle<FixedArray> list =
1341 365846 : isolate->factory()->NewFixedArray(kLengthIndex + size);
1342 365846 : list->set(kLengthIndex, Smi::kZero);
1343 365846 : return Handle<TemplateList>::cast(list);
1344 : }
1345 :
1346 : // static
1347 5952417 : Handle<TemplateList> TemplateList::Add(Isolate* isolate,
1348 : Handle<TemplateList> list,
1349 : Handle<i::Object> value) {
1350 : STATIC_ASSERT(kFirstElementIndex == 1);
1351 5952417 : int index = list->length() + 1;
1352 5952417 : Handle<i::FixedArray> fixed_array = Handle<FixedArray>::cast(list);
1353 5952417 : fixed_array = FixedArray::SetAndGrow(isolate, fixed_array, index, value);
1354 : fixed_array->set(kLengthIndex, Smi::FromInt(index));
1355 5952417 : return Handle<TemplateList>::cast(fixed_array);
1356 : }
1357 :
1358 : // static
1359 2729088 : MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor,
1360 : Handle<JSReceiver> new_target,
1361 : Handle<AllocationSite> site) {
1362 : // If called through new, new.target can be:
1363 : // - a subclass of constructor,
1364 : // - a proxy wrapper around constructor, or
1365 : // - the constructor itself.
1366 : // If called through Reflect.construct, it's guaranteed to be a constructor.
1367 : Isolate* const isolate = constructor->GetIsolate();
1368 : DCHECK(constructor->IsConstructor());
1369 : DCHECK(new_target->IsConstructor());
1370 : DCHECK(!constructor->has_initial_map() ||
1371 : constructor->initial_map()->instance_type() != JS_FUNCTION_TYPE);
1372 :
1373 : Handle<Map> initial_map;
1374 5458232 : ASSIGN_RETURN_ON_EXCEPTION(
1375 : isolate, initial_map,
1376 : JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject);
1377 : Handle<JSObject> result =
1378 2729040 : isolate->factory()->NewJSObjectFromMap(initial_map, NOT_TENURED, site);
1379 2729037 : if (initial_map->is_dictionary_map()) {
1380 : Handle<NameDictionary> dictionary =
1381 0 : NameDictionary::New(isolate, NameDictionary::kInitialCapacity);
1382 0 : result->SetProperties(*dictionary);
1383 : }
1384 2729037 : isolate->counters()->constructed_objects()->Increment();
1385 2729039 : isolate->counters()->constructed_objects_runtime()->Increment();
1386 2729038 : return result;
1387 : }
1388 :
1389 : // 9.1.12 ObjectCreate ( proto [ , internalSlotsList ] )
1390 : // Notice: This is NOT 19.1.2.2 Object.create ( O, Properties )
1391 119997 : MaybeHandle<JSObject> JSObject::ObjectCreate(Isolate* isolate,
1392 : Handle<Object> prototype) {
1393 : // Generate the map with the specified {prototype} based on the Object
1394 : // function's initial map from the current native context.
1395 : // TODO(bmeurer): Use a dedicated cache for Object.create; think about
1396 : // slack tracking for Object.create.
1397 : Handle<Map> map =
1398 119997 : Map::GetObjectCreateMap(isolate, Handle<HeapObject>::cast(prototype));
1399 :
1400 : // Actually allocate the object.
1401 : Handle<JSObject> object;
1402 119997 : if (map->is_dictionary_map()) {
1403 366 : object = isolate->factory()->NewSlowJSObjectFromMap(map);
1404 : } else {
1405 119631 : object = isolate->factory()->NewJSObjectFromMap(map);
1406 : }
1407 119997 : return object;
1408 : }
1409 :
1410 5918908 : void JSObject::EnsureWritableFastElements(Handle<JSObject> object) {
1411 : DCHECK(object->HasSmiOrObjectElements() ||
1412 : object->HasFastStringWrapperElements());
1413 11837818 : FixedArray raw_elems = FixedArray::cast(object->elements());
1414 : Heap* heap = object->GetHeap();
1415 11823218 : if (raw_elems->map() != ReadOnlyRoots(heap).fixed_cow_array_map()) return;
1416 : Isolate* isolate = heap->isolate();
1417 : Handle<FixedArray> elems(raw_elems, isolate);
1418 : Handle<FixedArray> writable_elems = isolate->factory()->CopyFixedArrayWithMap(
1419 14596 : elems, isolate->factory()->fixed_array_map());
1420 29192 : object->set_elements(*writable_elems);
1421 14596 : isolate->counters()->cow_arrays_converted()->Increment();
1422 : }
1423 :
1424 5859622 : int JSObject::GetHeaderSize(InstanceType type,
1425 : bool function_has_prototype_slot) {
1426 5859622 : switch (type) {
1427 : case JS_OBJECT_TYPE:
1428 : case JS_API_OBJECT_TYPE:
1429 : case JS_SPECIAL_API_OBJECT_TYPE:
1430 : return JSObject::kHeaderSize;
1431 : case JS_GENERATOR_OBJECT_TYPE:
1432 7263 : return JSGeneratorObject::kSize;
1433 : case JS_ASYNC_FUNCTION_OBJECT_TYPE:
1434 0 : return JSAsyncFunctionObject::kSize;
1435 : case JS_ASYNC_GENERATOR_OBJECT_TYPE:
1436 1375 : return JSAsyncGeneratorObject::kSize;
1437 : case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
1438 0 : return JSAsyncFromSyncIterator::kSize;
1439 : case JS_GLOBAL_PROXY_TYPE:
1440 54454 : return JSGlobalProxy::kSize;
1441 : case JS_GLOBAL_OBJECT_TYPE:
1442 55066 : return JSGlobalObject::kSize;
1443 : case JS_BOUND_FUNCTION_TYPE:
1444 838 : return JSBoundFunction::kSize;
1445 : case JS_FUNCTION_TYPE:
1446 469341 : return JSFunction::GetHeaderSize(function_has_prototype_slot);
1447 : case JS_VALUE_TYPE:
1448 6335 : return JSValue::kSize;
1449 : case JS_DATE_TYPE:
1450 1034 : return JSDate::kSize;
1451 : case JS_ARRAY_TYPE:
1452 61371 : return JSArray::kSize;
1453 : case JS_ARRAY_BUFFER_TYPE:
1454 904640 : return JSArrayBuffer::kHeaderSize;
1455 : case JS_ARRAY_ITERATOR_TYPE:
1456 189 : return JSArrayIterator::kSize;
1457 : case JS_TYPED_ARRAY_TYPE:
1458 11237 : return JSTypedArray::kHeaderSize;
1459 : case JS_DATA_VIEW_TYPE:
1460 8285 : return JSDataView::kHeaderSize;
1461 : case JS_SET_TYPE:
1462 1527 : return JSSet::kSize;
1463 : case JS_MAP_TYPE:
1464 1608 : return JSMap::kSize;
1465 : case JS_SET_KEY_VALUE_ITERATOR_TYPE:
1466 : case JS_SET_VALUE_ITERATOR_TYPE:
1467 63 : return JSSetIterator::kSize;
1468 : case JS_MAP_KEY_ITERATOR_TYPE:
1469 : case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
1470 : case JS_MAP_VALUE_ITERATOR_TYPE:
1471 45 : return JSMapIterator::kSize;
1472 : case JS_WEAK_CELL_TYPE:
1473 0 : return JSWeakCell::kSize;
1474 : case JS_WEAK_REF_TYPE:
1475 0 : return JSWeakRef::kSize;
1476 : case JS_WEAK_FACTORY_TYPE:
1477 0 : return JSWeakFactory::kSize;
1478 : case JS_WEAK_FACTORY_CLEANUP_ITERATOR_TYPE:
1479 0 : return JSWeakFactoryCleanupIterator::kSize;
1480 : case JS_WEAK_MAP_TYPE:
1481 1344 : return JSWeakMap::kSize;
1482 : case JS_WEAK_SET_TYPE:
1483 1419 : return JSWeakSet::kSize;
1484 : case JS_PROMISE_TYPE:
1485 461 : return JSPromise::kSize;
1486 : case JS_REGEXP_TYPE:
1487 1352 : return JSRegExp::kSize;
1488 : case JS_REGEXP_STRING_ITERATOR_TYPE:
1489 0 : return JSRegExpStringIterator::kSize;
1490 : case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
1491 : return JSObject::kHeaderSize;
1492 : case JS_MESSAGE_OBJECT_TYPE:
1493 0 : return JSMessageObject::kSize;
1494 : case JS_ARGUMENTS_TYPE:
1495 : return JSObject::kHeaderSize;
1496 : case JS_ERROR_TYPE:
1497 : return JSObject::kHeaderSize;
1498 : case JS_STRING_ITERATOR_TYPE:
1499 0 : return JSStringIterator::kSize;
1500 : case JS_MODULE_NAMESPACE_TYPE:
1501 116 : return JSModuleNamespace::kHeaderSize;
1502 : #ifdef V8_INTL_SUPPORT
1503 : case JS_INTL_V8_BREAK_ITERATOR_TYPE:
1504 18 : return JSV8BreakIterator::kSize;
1505 : case JS_INTL_COLLATOR_TYPE:
1506 0 : return JSCollator::kSize;
1507 : case JS_INTL_DATE_TIME_FORMAT_TYPE:
1508 0 : return JSDateTimeFormat::kSize;
1509 : case JS_INTL_LIST_FORMAT_TYPE:
1510 18 : return JSListFormat::kSize;
1511 : case JS_INTL_LOCALE_TYPE:
1512 0 : return JSLocale::kSize;
1513 : case JS_INTL_NUMBER_FORMAT_TYPE:
1514 0 : return JSNumberFormat::kSize;
1515 : case JS_INTL_PLURAL_RULES_TYPE:
1516 0 : return JSPluralRules::kSize;
1517 : case JS_INTL_RELATIVE_TIME_FORMAT_TYPE:
1518 18 : return JSRelativeTimeFormat::kSize;
1519 : case JS_INTL_SEGMENT_ITERATOR_TYPE:
1520 0 : return JSSegmentIterator::kSize;
1521 : case JS_INTL_SEGMENTER_TYPE:
1522 18 : return JSSegmenter::kSize;
1523 : #endif // V8_INTL_SUPPORT
1524 : case WASM_GLOBAL_TYPE:
1525 0 : return WasmGlobalObject::kSize;
1526 : case WASM_INSTANCE_TYPE:
1527 0 : return WasmInstanceObject::kSize;
1528 : case WASM_MEMORY_TYPE:
1529 0 : return WasmMemoryObject::kSize;
1530 : case WASM_MODULE_TYPE:
1531 0 : return WasmModuleObject::kSize;
1532 : case WASM_TABLE_TYPE:
1533 0 : return WasmTableObject::kSize;
1534 : case WASM_EXCEPTION_TYPE:
1535 0 : return WasmExceptionObject::kSize;
1536 : default:
1537 0 : UNREACHABLE();
1538 : }
1539 : }
1540 :
1541 : // ES6 9.5.1
1542 : // static
1543 3716688 : MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
1544 : Isolate* isolate = proxy->GetIsolate();
1545 : Handle<String> trap_name = isolate->factory()->getPrototypeOf_string();
1546 :
1547 3716688 : STACK_CHECK(isolate, MaybeHandle<Object>());
1548 :
1549 : // 1. Let handler be the value of the [[ProxyHandler]] internal slot.
1550 : // 2. If handler is null, throw a TypeError exception.
1551 : // 3. Assert: Type(handler) is Object.
1552 : // 4. Let target be the value of the [[ProxyTarget]] internal slot.
1553 7433358 : if (proxy->IsRevoked()) {
1554 18 : THROW_NEW_ERROR(isolate,
1555 : NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1556 : Object);
1557 : }
1558 7433322 : Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
1559 7433322 : Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
1560 :
1561 : // 5. Let trap be ? GetMethod(handler, "getPrototypeOf").
1562 : Handle<Object> trap;
1563 7433322 : ASSIGN_RETURN_ON_EXCEPTION(isolate, trap,
1564 : Object::GetMethod(handler, trap_name), Object);
1565 : // 6. If trap is undefined, then return target.[[GetPrototypeOf]]().
1566 7433322 : if (trap->IsUndefined(isolate)) {
1567 2794683 : return JSReceiver::GetPrototype(isolate, target);
1568 : }
1569 : // 7. Let handlerProto be ? Call(trap, handler, «target»).
1570 : Handle<Object> argv[] = {target};
1571 : Handle<Object> handler_proto;
1572 1843956 : ASSIGN_RETURN_ON_EXCEPTION(
1573 : isolate, handler_proto,
1574 : Execution::Call(isolate, trap, handler, arraysize(argv), argv), Object);
1575 : // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError.
1576 1843812 : if (!(handler_proto->IsJSReceiver() || handler_proto->IsNull(isolate))) {
1577 9 : THROW_NEW_ERROR(isolate,
1578 : NewTypeError(MessageTemplate::kProxyGetPrototypeOfInvalid),
1579 : Object);
1580 : }
1581 : // 9. Let extensibleTarget be ? IsExtensible(target).
1582 921870 : Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
1583 921870 : MAYBE_RETURN_NULL(is_extensible);
1584 : // 10. If extensibleTarget is true, return handlerProto.
1585 921870 : if (is_extensible.FromJust()) return handler_proto;
1586 : // 11. Let targetProto be ? target.[[GetPrototypeOf]]().
1587 : Handle<Object> target_proto;
1588 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, target_proto,
1589 : JSReceiver::GetPrototype(isolate, target), Object);
1590 : // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError.
1591 0 : if (!handler_proto->SameValue(*target_proto)) {
1592 0 : THROW_NEW_ERROR(
1593 : isolate,
1594 : NewTypeError(MessageTemplate::kProxyGetPrototypeOfNonExtensible),
1595 : Object);
1596 : }
1597 : // 13. Return handlerProto.
1598 0 : return handler_proto;
1599 : }
1600 :
1601 918939 : MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) {
1602 : Isolate* isolate = it->isolate();
1603 918939 : Handle<Object> structure = it->GetAccessors();
1604 : Handle<Object> receiver = it->GetReceiver();
1605 : // In case of global IC, the receiver is the global object. Replace by the
1606 : // global proxy.
1607 1837881 : if (receiver->IsJSGlobalObject()) {
1608 4072 : receiver = handle(JSGlobalObject::cast(*receiver)->global_proxy(), isolate);
1609 : }
1610 :
1611 : // We should never get here to initialize a const with the hole value since a
1612 : // const declaration would conflict with the getter.
1613 : DCHECK(!structure->IsForeign());
1614 :
1615 : // API style callbacks.
1616 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1617 1837881 : if (structure->IsAccessorInfo()) {
1618 641292 : Handle<Name> name = it->GetName();
1619 641292 : Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
1620 641292 : if (!info->IsCompatibleReceiver(*receiver)) {
1621 90 : THROW_NEW_ERROR(isolate,
1622 : NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
1623 : name, receiver),
1624 : Object);
1625 : }
1626 :
1627 1282524 : if (!info->has_getter()) return isolate->factory()->undefined_value();
1628 :
1629 883853 : if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1630 30 : ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver,
1631 : Object::ConvertReceiver(isolate, receiver),
1632 : Object);
1633 : }
1634 :
1635 : PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1636 641082 : kDontThrow);
1637 641081 : Handle<Object> result = args.CallAccessorGetter(info, name);
1638 641081 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1639 648803 : if (result.is_null()) return isolate->factory()->undefined_value();
1640 : Handle<Object> reboxed_result = handle(*result, isolate);
1641 632747 : if (info->replace_on_access() && receiver->IsJSReceiver()) {
1642 30 : RETURN_ON_EXCEPTION(isolate,
1643 : Accessors::ReplaceAccessorWithDataProperty(
1644 : receiver, holder, name, result),
1645 : Object);
1646 : }
1647 632715 : return reboxed_result;
1648 : }
1649 :
1650 : // AccessorPair with 'cached' private property.
1651 277649 : if (it->TryLookupCachedProperty()) {
1652 44 : return Object::GetProperty(it);
1653 : }
1654 :
1655 : // Regular accessor.
1656 555210 : Handle<Object> getter(AccessorPair::cast(*structure)->getter(), isolate);
1657 555210 : if (getter->IsFunctionTemplateInfo()) {
1658 113845 : SaveContext save(isolate);
1659 227690 : isolate->set_context(*holder->GetCreationContext());
1660 : return Builtins::InvokeApiFunction(
1661 : isolate, false, Handle<FunctionTemplateInfo>::cast(getter), receiver, 0,
1662 227690 : nullptr, isolate->factory()->undefined_value());
1663 327520 : } else if (getter->IsCallable()) {
1664 : // TODO(rossberg): nicer would be to cast to some JSCallable here...
1665 : return Object::GetPropertyWithDefinedGetter(
1666 159441 : receiver, Handle<JSReceiver>::cast(getter));
1667 : }
1668 : // Getter is not a function.
1669 4319 : return isolate->factory()->undefined_value();
1670 : }
1671 :
1672 : // static
1673 0 : Address AccessorInfo::redirect(Address address, AccessorComponent component) {
1674 : ApiFunction fun(address);
1675 : DCHECK_EQ(ACCESSOR_GETTER, component);
1676 : ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
1677 182134 : return ExternalReference::Create(&fun, type).address();
1678 : }
1679 :
1680 92069 : Address AccessorInfo::redirected_getter() const {
1681 92069 : Address accessor = v8::ToCData<Address>(getter());
1682 92069 : if (accessor == kNullAddress) return kNullAddress;
1683 91067 : return redirect(accessor, ACCESSOR_GETTER);
1684 : }
1685 :
1686 3618461 : Address CallHandlerInfo::redirected_callback() const {
1687 3618461 : Address address = v8::ToCData<Address>(callback());
1688 : ApiFunction fun(address);
1689 : ExternalReference::Type type = ExternalReference::DIRECT_API_CALL;
1690 7236925 : return ExternalReference::Create(&fun, type).address();
1691 : }
1692 :
1693 97376 : bool AccessorInfo::IsCompatibleReceiverMap(Handle<AccessorInfo> info,
1694 : Handle<Map> map) {
1695 97376 : if (!info->HasExpectedReceiverType()) return true;
1696 60 : if (!map->IsJSObjectMap()) return false;
1697 120 : return FunctionTemplateInfo::cast(info->expected_receiver_type())
1698 60 : ->IsTemplateFor(*map);
1699 : }
1700 :
1701 490400 : Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it,
1702 : Handle<Object> value,
1703 : ShouldThrow should_throw) {
1704 : Isolate* isolate = it->isolate();
1705 490400 : Handle<Object> structure = it->GetAccessors();
1706 : Handle<Object> receiver = it->GetReceiver();
1707 : // In case of global IC, the receiver is the global object. Replace by the
1708 : // global proxy.
1709 980800 : if (receiver->IsJSGlobalObject()) {
1710 15046 : receiver = handle(JSGlobalObject::cast(*receiver)->global_proxy(), isolate);
1711 : }
1712 :
1713 : // We should never get here to initialize a const with the hole value since a
1714 : // const declaration would conflict with the setter.
1715 : DCHECK(!structure->IsForeign());
1716 :
1717 : // API style callbacks.
1718 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1719 980800 : if (structure->IsAccessorInfo()) {
1720 247822 : Handle<Name> name = it->GetName();
1721 247822 : Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
1722 247822 : if (!info->IsCompatibleReceiver(*receiver)) {
1723 : isolate->Throw(*isolate->factory()->NewTypeError(
1724 180 : MessageTemplate::kIncompatibleMethodReceiver, name, receiver));
1725 : return Nothing<bool>();
1726 : }
1727 :
1728 495464 : if (!info->has_setter()) {
1729 : // TODO(verwaest): We should not get here anymore once all AccessorInfos
1730 : // are marked as special_data_property. They cannot both be writable and
1731 : // not have a setter.
1732 : return Just(true);
1733 : }
1734 :
1735 489100 : if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1736 0 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1737 : isolate, receiver, Object::ConvertReceiver(isolate, receiver),
1738 : Nothing<bool>());
1739 : }
1740 :
1741 : // The actual type of setter callback is either
1742 : // v8::AccessorNameSetterCallback or
1743 : // i::Accesors::AccessorNameBooleanSetterCallback, depending on whether the
1744 : // AccessorInfo was created by the API or internally (see accessors.cc).
1745 : // Here we handle both cases using GenericNamedPropertySetterCallback and
1746 : // its Call method.
1747 : PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1748 247666 : should_throw);
1749 247666 : Handle<Object> result = args.CallAccessorSetter(info, name, value);
1750 : // In the case of AccessorNameSetterCallback, we know that the result value
1751 : // cannot have been set, so the result of Call will be null. In the case of
1752 : // AccessorNameBooleanSetterCallback, the result will either be null
1753 : // (signalling an exception) or a boolean Oddball.
1754 247666 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1755 247447 : if (result.is_null()) return Just(true);
1756 : DCHECK(result->BooleanValue(isolate) || should_throw == kDontThrow);
1757 253602 : return Just(result->BooleanValue(isolate));
1758 : }
1759 :
1760 : // Regular accessor.
1761 485156 : Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
1762 485156 : if (setter->IsFunctionTemplateInfo()) {
1763 657 : SaveContext save(isolate);
1764 1314 : isolate->set_context(*holder->GetCreationContext());
1765 657 : Handle<Object> argv[] = {value};
1766 1971 : RETURN_ON_EXCEPTION_VALUE(
1767 : isolate, Builtins::InvokeApiFunction(
1768 : isolate, false, Handle<FunctionTemplateInfo>::cast(setter),
1769 : receiver, arraysize(argv), argv,
1770 : isolate->factory()->undefined_value()),
1771 : Nothing<bool>());
1772 657 : return Just(true);
1773 483842 : } else if (setter->IsCallable()) {
1774 : // TODO(rossberg): nicer would be to cast to some JSCallable here...
1775 : return SetPropertyWithDefinedSetter(
1776 230308 : receiver, Handle<JSReceiver>::cast(setter), value, should_throw);
1777 : }
1778 :
1779 28866 : RETURN_FAILURE(isolate, should_throw,
1780 : NewTypeError(MessageTemplate::kNoSetterInCallback,
1781 : it->GetName(), it->GetHolder<JSObject>()));
1782 : }
1783 :
1784 :
1785 159441 : MaybeHandle<Object> Object::GetPropertyWithDefinedGetter(
1786 : Handle<Object> receiver,
1787 : Handle<JSReceiver> getter) {
1788 : Isolate* isolate = getter->GetIsolate();
1789 :
1790 : // Platforms with simulators like arm/arm64 expose a funny issue. If the
1791 : // simulator has a separate JS stack pointer from the C++ stack pointer, it
1792 : // can miss C++ stack overflows in the stack guard at the start of JavaScript
1793 : // functions. It would be very expensive to check the C++ stack pointer at
1794 : // that location. The best solution seems to be to break the impasse by
1795 : // adding checks at possible recursion points. What's more, we don't put
1796 : // this stack check behind the USE_SIMULATOR define in order to keep
1797 : // behavior the same between hardware and simulators.
1798 : StackLimitCheck check(isolate);
1799 159441 : if (check.JsHasOverflowed()) {
1800 10 : isolate->StackOverflow();
1801 10 : return MaybeHandle<Object>();
1802 : }
1803 :
1804 159431 : return Execution::Call(isolate, getter, receiver, 0, nullptr);
1805 : }
1806 :
1807 :
1808 230308 : Maybe<bool> Object::SetPropertyWithDefinedSetter(Handle<Object> receiver,
1809 : Handle<JSReceiver> setter,
1810 : Handle<Object> value,
1811 : ShouldThrow should_throw) {
1812 : Isolate* isolate = setter->GetIsolate();
1813 :
1814 230308 : Handle<Object> argv[] = { value };
1815 460616 : RETURN_ON_EXCEPTION_VALUE(isolate, Execution::Call(isolate, setter, receiver,
1816 : arraysize(argv), argv),
1817 : Nothing<bool>());
1818 : return Just(true);
1819 : }
1820 :
1821 :
1822 : // static
1823 3636 : bool JSObject::AllCanRead(LookupIterator* it) {
1824 : // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of
1825 : // which have already been checked.
1826 : DCHECK(it->state() == LookupIterator::ACCESS_CHECK ||
1827 : it->state() == LookupIterator::INTERCEPTOR);
1828 4802 : for (it->Next(); it->IsFound(); it->Next()) {
1829 1236 : if (it->state() == LookupIterator::ACCESSOR) {
1830 122 : auto accessors = it->GetAccessors();
1831 244 : if (accessors->IsAccessorInfo()) {
1832 77 : if (AccessorInfo::cast(*accessors)->all_can_read()) return true;
1833 : }
1834 1114 : } else if (it->state() == LookupIterator::INTERCEPTOR) {
1835 1260 : if (it->GetInterceptor()->all_can_read()) return true;
1836 484 : } else if (it->state() == LookupIterator::JSPROXY) {
1837 : // Stop lookupiterating. And no, AllCanNotRead.
1838 : return false;
1839 : }
1840 : }
1841 : return false;
1842 : }
1843 :
1844 : namespace {
1845 :
1846 114228 : MaybeHandle<Object> GetPropertyWithInterceptorInternal(
1847 228068 : LookupIterator* it, Handle<InterceptorInfo> interceptor, bool* done) {
1848 114228 : *done = false;
1849 : Isolate* isolate = it->isolate();
1850 : // Make sure that the top context does not change when doing callbacks or
1851 : // interceptor calls.
1852 : AssertNoContextChange ncc(isolate);
1853 :
1854 228456 : if (interceptor->getter()->IsUndefined(isolate)) {
1855 388 : return isolate->factory()->undefined_value();
1856 : }
1857 :
1858 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1859 : Handle<Object> result;
1860 : Handle<Object> receiver = it->GetReceiver();
1861 227680 : if (!receiver->IsJSReceiver()) {
1862 32 : ASSIGN_RETURN_ON_EXCEPTION(
1863 : isolate, receiver, Object::ConvertReceiver(isolate, receiver), Object);
1864 : }
1865 : PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1866 113840 : *holder, kDontThrow);
1867 :
1868 113840 : if (it->IsElement()) {
1869 2350 : result = args.CallIndexedGetter(interceptor, it->index());
1870 : } else {
1871 111490 : result = args.CallNamedGetter(interceptor, it->name());
1872 : }
1873 :
1874 113840 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1875 224365 : if (result.is_null()) return isolate->factory()->undefined_value();
1876 3259 : *done = true;
1877 : // Rebox handle before return
1878 3259 : return handle(*result, isolate);
1879 : }
1880 :
1881 250398 : Maybe<PropertyAttributes> GetPropertyAttributesWithInterceptorInternal(
1882 500676 : LookupIterator* it, Handle<InterceptorInfo> interceptor) {
1883 : Isolate* isolate = it->isolate();
1884 : // Make sure that the top context does not change when doing
1885 : // callbacks or interceptor calls.
1886 : AssertNoContextChange ncc(isolate);
1887 : HandleScope scope(isolate);
1888 :
1889 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1890 : DCHECK_IMPLIES(!it->IsElement() && it->name()->IsSymbol(),
1891 : interceptor->can_intercept_symbols());
1892 : Handle<Object> receiver = it->GetReceiver();
1893 500796 : if (!receiver->IsJSReceiver()) {
1894 24 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1895 : Object::ConvertReceiver(isolate, receiver),
1896 : Nothing<PropertyAttributes>());
1897 : }
1898 : PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1899 250398 : *holder, kDontThrow);
1900 500796 : if (!interceptor->query()->IsUndefined(isolate)) {
1901 : Handle<Object> result;
1902 560 : if (it->IsElement()) {
1903 315 : result = args.CallIndexedQuery(interceptor, it->index());
1904 : } else {
1905 245 : result = args.CallNamedQuery(interceptor, it->name());
1906 : }
1907 560 : if (!result.is_null()) {
1908 : int32_t value;
1909 370 : CHECK(result->ToInt32(&value));
1910 370 : return Just(static_cast<PropertyAttributes>(value));
1911 : }
1912 499676 : } else if (!interceptor->getter()->IsUndefined(isolate)) {
1913 : // TODO(verwaest): Use GetPropertyWithInterceptor?
1914 : Handle<Object> result;
1915 249718 : if (it->IsElement()) {
1916 240203 : result = args.CallIndexedGetter(interceptor, it->index());
1917 : } else {
1918 9515 : result = args.CallNamedGetter(interceptor, it->name());
1919 : }
1920 249718 : if (!result.is_null()) return Just(DONT_ENUM);
1921 : }
1922 :
1923 240613 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
1924 : return Just(ABSENT);
1925 : }
1926 :
1927 193369 : Maybe<bool> SetPropertyWithInterceptorInternal(
1928 566347 : LookupIterator* it, Handle<InterceptorInfo> interceptor,
1929 : ShouldThrow should_throw, Handle<Object> value) {
1930 : Isolate* isolate = it->isolate();
1931 : // Make sure that the top context does not change when doing callbacks or
1932 : // interceptor calls.
1933 : AssertNoContextChange ncc(isolate);
1934 :
1935 386738 : if (interceptor->setter()->IsUndefined(isolate)) return Just(false);
1936 :
1937 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1938 : bool result;
1939 : Handle<Object> receiver = it->GetReceiver();
1940 372978 : if (!receiver->IsJSReceiver()) {
1941 0 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1942 : Object::ConvertReceiver(isolate, receiver),
1943 : Nothing<bool>());
1944 : }
1945 : PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1946 186489 : *holder, should_throw);
1947 :
1948 186489 : if (it->IsElement()) {
1949 : // TODO(neis): In the future, we may want to actually return the
1950 : // interceptor's result, which then should be a boolean.
1951 131338 : result = !args.CallIndexedSetter(interceptor, it->index(), value).is_null();
1952 : } else {
1953 241640 : result = !args.CallNamedSetter(interceptor, it->name(), value).is_null();
1954 : }
1955 :
1956 186489 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1957 : return Just(result);
1958 : }
1959 :
1960 183 : Maybe<bool> DefinePropertyWithInterceptorInternal(
1961 357 : LookupIterator* it, Handle<InterceptorInfo> interceptor,
1962 : ShouldThrow should_throw, PropertyDescriptor& desc) {
1963 : Isolate* isolate = it->isolate();
1964 : // Make sure that the top context does not change when doing callbacks or
1965 : // interceptor calls.
1966 : AssertNoContextChange ncc(isolate);
1967 :
1968 366 : if (interceptor->definer()->IsUndefined(isolate)) return Just(false);
1969 :
1970 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1971 : bool result;
1972 : Handle<Object> receiver = it->GetReceiver();
1973 174 : if (!receiver->IsJSReceiver()) {
1974 0 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1975 : Object::ConvertReceiver(isolate, receiver),
1976 : Nothing<bool>());
1977 : }
1978 : PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1979 87 : *holder, should_throw);
1980 :
1981 : std::unique_ptr<v8::PropertyDescriptor> descriptor(
1982 87 : new v8::PropertyDescriptor());
1983 87 : if (PropertyDescriptor::IsAccessorDescriptor(&desc)) {
1984 : descriptor.reset(new v8::PropertyDescriptor(
1985 66 : v8::Utils::ToLocal(desc.get()), v8::Utils::ToLocal(desc.set())));
1986 54 : } else if (PropertyDescriptor::IsDataDescriptor(&desc)) {
1987 44 : if (desc.has_writable()) {
1988 : descriptor.reset(new v8::PropertyDescriptor(
1989 18 : v8::Utils::ToLocal(desc.value()), desc.writable()));
1990 : } else {
1991 : descriptor.reset(
1992 76 : new v8::PropertyDescriptor(v8::Utils::ToLocal(desc.value())));
1993 : }
1994 : }
1995 87 : if (desc.has_enumerable()) {
1996 12 : descriptor->set_enumerable(desc.enumerable());
1997 : }
1998 87 : if (desc.has_configurable()) {
1999 12 : descriptor->set_configurable(desc.configurable());
2000 : }
2001 :
2002 87 : if (it->IsElement()) {
2003 : result = !args.CallIndexedDefiner(interceptor, it->index(), *descriptor)
2004 48 : .is_null();
2005 : } else {
2006 : result =
2007 126 : !args.CallNamedDefiner(interceptor, it->name(), *descriptor).is_null();
2008 : }
2009 :
2010 87 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
2011 : return Just(result);
2012 : }
2013 :
2014 : } // namespace
2015 :
2016 1169 : MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
2017 1267 : LookupIterator* it) {
2018 : Isolate* isolate = it->isolate();
2019 1169 : Handle<JSObject> checked = it->GetHolder<JSObject>();
2020 : Handle<InterceptorInfo> interceptor =
2021 1169 : it->GetInterceptorForFailedAccessCheck();
2022 1169 : if (interceptor.is_null()) {
2023 1064 : while (AllCanRead(it)) {
2024 46 : if (it->state() == LookupIterator::ACCESSOR) {
2025 52 : return Object::GetPropertyWithAccessor(it);
2026 : }
2027 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
2028 : bool done;
2029 : Handle<Object> result;
2030 60 : ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
2031 : GetPropertyWithInterceptor(it, &done), Object);
2032 30 : if (done) return result;
2033 : }
2034 :
2035 : } else {
2036 : Handle<Object> result;
2037 : bool done;
2038 230 : ASSIGN_RETURN_ON_EXCEPTION(
2039 : isolate, result,
2040 : GetPropertyWithInterceptorInternal(it, interceptor, &done), Object);
2041 105 : if (done) return result;
2042 : }
2043 :
2044 : // Cross-Origin [[Get]] of Well-Known Symbols does not throw, and returns
2045 : // undefined.
2046 1078 : Handle<Name> name = it->GetName();
2047 2213 : if (name->IsSymbol() && Symbol::cast(*name)->is_well_known_symbol()) {
2048 52 : return it->factory()->undefined_value();
2049 : }
2050 :
2051 1026 : isolate->ReportFailedAccessCheck(checked);
2052 1026 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
2053 0 : return it->factory()->undefined_value();
2054 : }
2055 :
2056 :
2057 121 : Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
2058 131 : LookupIterator* it) {
2059 : Isolate* isolate = it->isolate();
2060 121 : Handle<JSObject> checked = it->GetHolder<JSObject>();
2061 : Handle<InterceptorInfo> interceptor =
2062 121 : it->GetInterceptorForFailedAccessCheck();
2063 121 : if (interceptor.is_null()) {
2064 121 : while (AllCanRead(it)) {
2065 10 : if (it->state() == LookupIterator::ACCESSOR) {
2066 : return Just(it->property_attributes());
2067 : }
2068 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
2069 0 : auto result = GetPropertyAttributesWithInterceptor(it);
2070 0 : if (isolate->has_scheduled_exception()) break;
2071 0 : if (result.IsJust() && result.FromJust() != ABSENT) return result;
2072 : }
2073 : } else {
2074 : Maybe<PropertyAttributes> result =
2075 0 : GetPropertyAttributesWithInterceptorInternal(it, interceptor);
2076 0 : if (isolate->has_pending_exception()) return Nothing<PropertyAttributes>();
2077 0 : if (result.FromMaybe(ABSENT) != ABSENT) return result;
2078 : }
2079 111 : isolate->ReportFailedAccessCheck(checked);
2080 111 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
2081 : return Just(ABSENT);
2082 : }
2083 :
2084 :
2085 : // static
2086 269 : bool JSObject::AllCanWrite(LookupIterator* it) {
2087 382 : for (; it->IsFound() && it->state() != LookupIterator::JSPROXY; it->Next()) {
2088 123 : if (it->state() == LookupIterator::ACCESSOR) {
2089 25 : Handle<Object> accessors = it->GetAccessors();
2090 50 : if (accessors->IsAccessorInfo()) {
2091 15 : if (AccessorInfo::cast(*accessors)->all_can_write()) return true;
2092 : }
2093 : }
2094 : }
2095 : return false;
2096 : }
2097 :
2098 :
2099 108 : Maybe<bool> JSObject::SetPropertyWithFailedAccessCheck(
2100 108 : LookupIterator* it, Handle<Object> value, ShouldThrow should_throw) {
2101 : Isolate* isolate = it->isolate();
2102 108 : Handle<JSObject> checked = it->GetHolder<JSObject>();
2103 : Handle<InterceptorInfo> interceptor =
2104 108 : it->GetInterceptorForFailedAccessCheck();
2105 108 : if (interceptor.is_null()) {
2106 78 : if (AllCanWrite(it)) {
2107 10 : return Object::SetPropertyWithAccessor(it, value, should_throw);
2108 : }
2109 : } else {
2110 : Maybe<bool> result = SetPropertyWithInterceptorInternal(
2111 30 : it, interceptor, should_throw, value);
2112 60 : if (isolate->has_pending_exception()) return Nothing<bool>();
2113 20 : if (result.IsJust()) return result;
2114 : }
2115 68 : isolate->ReportFailedAccessCheck(checked);
2116 68 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
2117 : return Just(true);
2118 : }
2119 :
2120 :
2121 336337 : void JSObject::SetNormalizedProperty(Handle<JSObject> object,
2122 : Handle<Name> name,
2123 : Handle<Object> value,
2124 : PropertyDetails details) {
2125 : DCHECK(!object->HasFastProperties());
2126 : DCHECK(name->IsUniqueName());
2127 : Isolate* isolate = object->GetIsolate();
2128 :
2129 336337 : uint32_t hash = name->Hash();
2130 :
2131 672674 : if (object->IsJSGlobalObject()) {
2132 9621 : Handle<JSGlobalObject> global_obj = Handle<JSGlobalObject>::cast(object);
2133 : Handle<GlobalDictionary> dictionary(global_obj->global_dictionary(),
2134 19242 : isolate);
2135 19242 : int entry = dictionary->FindEntry(ReadOnlyRoots(isolate), name, hash);
2136 :
2137 9621 : if (entry == GlobalDictionary::kNotFound) {
2138 : DCHECK_IMPLIES(global_obj->map()->is_prototype_map(),
2139 : Map::IsPrototypeChainInvalidated(global_obj->map()));
2140 1014 : auto cell = isolate->factory()->NewPropertyCell(name);
2141 1014 : cell->set_value(*value);
2142 2028 : auto cell_type = value->IsUndefined(isolate)
2143 : ? PropertyCellType::kUndefined
2144 1014 : : PropertyCellType::kConstant;
2145 : details = details.set_cell_type(cell_type);
2146 : value = cell;
2147 : dictionary =
2148 1014 : GlobalDictionary::Add(isolate, dictionary, name, value, details);
2149 2028 : global_obj->set_global_dictionary(*dictionary);
2150 : } else {
2151 : Handle<PropertyCell> cell = PropertyCell::PrepareForValue(
2152 8607 : isolate, dictionary, entry, value, details);
2153 8607 : cell->set_value(*value);
2154 : }
2155 : } else {
2156 653432 : Handle<NameDictionary> dictionary(object->property_dictionary(), isolate);
2157 :
2158 326716 : int entry = dictionary->FindEntry(isolate, name);
2159 326716 : if (entry == NameDictionary::kNotFound) {
2160 : DCHECK_IMPLIES(object->map()->is_prototype_map(),
2161 : Map::IsPrototypeChainInvalidated(object->map()));
2162 : dictionary =
2163 96519 : NameDictionary::Add(isolate, dictionary, name, value, details);
2164 193038 : object->SetProperties(*dictionary);
2165 : } else {
2166 230197 : PropertyDetails original_details = dictionary->DetailsAt(entry);
2167 : int enumeration_index = original_details.dictionary_index();
2168 : DCHECK_GT(enumeration_index, 0);
2169 : details = details.set_index(enumeration_index);
2170 460394 : dictionary->SetEntry(isolate, entry, *name, *value, details);
2171 : }
2172 : }
2173 336337 : }
2174 :
2175 : // static
2176 1287 : Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate,
2177 : Handle<JSReceiver> object,
2178 : Handle<Object> proto) {
2179 1287 : PrototypeIterator iter(isolate, object, kStartAtReceiver);
2180 : while (true) {
2181 3688849 : if (!iter.AdvanceFollowingProxies()) return Nothing<bool>();
2182 3688741 : if (iter.IsAtEnd()) return Just(false);
2183 3687949 : if (PrototypeIterator::GetCurrent(iter).is_identical_to(proto)) {
2184 : return Just(true);
2185 : }
2186 : }
2187 : }
2188 :
2189 : namespace {
2190 :
2191 519 : bool HasExcludedProperty(
2192 : const ScopedVector<Handle<Object>>* excluded_properties,
2193 : Handle<Object> search_element) {
2194 : // TODO(gsathya): Change this to be a hashtable.
2195 1590 : for (int i = 0; i < excluded_properties->length(); i++) {
2196 1689 : if (search_element->SameValue(*excluded_properties->at(i))) {
2197 : return true;
2198 : }
2199 : }
2200 :
2201 : return false;
2202 : }
2203 :
2204 752 : V8_WARN_UNUSED_RESULT Maybe<bool> FastAssign(
2205 : Handle<JSReceiver> target, Handle<Object> source,
2206 : const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) {
2207 : // Non-empty strings are the only non-JSReceivers that need to be handled
2208 : // explicitly by Object.assign.
2209 1504 : if (!source->IsJSReceiver()) {
2210 36 : return Just(!source->IsString() || String::cast(*source)->length() == 0);
2211 : }
2212 :
2213 : // If the target is deprecated, the object will be updated on first store. If
2214 : // the source for that store equals the target, this will invalidate the
2215 : // cached representation of the source. Preventively upgrade the target.
2216 : // Do this on each iteration since any property load could cause deprecation.
2217 743 : if (target->map()->is_deprecated()) {
2218 18 : JSObject::MigrateInstance(Handle<JSObject>::cast(target));
2219 : }
2220 :
2221 : Isolate* isolate = target->GetIsolate();
2222 : Handle<Map> map(JSReceiver::cast(*source)->map(), isolate);
2223 :
2224 743 : if (!map->IsJSObjectMap()) return Just(false);
2225 635 : if (!map->OnlyHasSimpleProperties()) return Just(false);
2226 :
2227 446 : Handle<JSObject> from = Handle<JSObject>::cast(source);
2228 892 : if (from->elements() != ReadOnlyRoots(isolate).empty_fixed_array()) {
2229 : return Just(false);
2230 : }
2231 :
2232 694 : Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
2233 : int length = map->NumberOfOwnDescriptors();
2234 :
2235 : bool stable = true;
2236 :
2237 866 : for (int i = 0; i < length; i++) {
2238 1038 : Handle<Name> next_key(descriptors->GetKey(i), isolate);
2239 : Handle<Object> prop_value;
2240 : // Directly decode from the descriptor array if |from| did not change shape.
2241 519 : if (stable) {
2242 519 : PropertyDetails details = descriptors->GetDetails(i);
2243 519 : if (!details.IsEnumerable()) continue;
2244 492 : if (details.kind() == kData) {
2245 492 : if (details.location() == kDescriptor) {
2246 0 : prop_value = handle(descriptors->GetStrongValue(i), isolate);
2247 : } else {
2248 492 : Representation representation = details.representation();
2249 492 : FieldIndex index = FieldIndex::ForDescriptor(*map, i);
2250 492 : prop_value = JSObject::FastPropertyAt(from, representation, index);
2251 : }
2252 : } else {
2253 0 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2254 : isolate, prop_value,
2255 : JSReceiver::GetProperty(isolate, from, next_key), Nothing<bool>());
2256 : stable = from->map() == *map;
2257 : }
2258 : } else {
2259 : // If the map did change, do a slower lookup. We are still guaranteed that
2260 : // the object has a simple shape, and that the key is a name.
2261 : LookupIterator it(from, next_key, from,
2262 0 : LookupIterator::OWN_SKIP_INTERCEPTOR);
2263 0 : if (!it.IsFound()) continue;
2264 : DCHECK(it.state() == LookupIterator::DATA ||
2265 : it.state() == LookupIterator::ACCESSOR);
2266 0 : if (!it.IsEnumerable()) continue;
2267 0 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2268 : isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
2269 : }
2270 :
2271 492 : if (use_set) {
2272 36 : LookupIterator it(target, next_key, target);
2273 : Maybe<bool> result = Object::SetProperty(
2274 36 : &it, prop_value, LanguageMode::kStrict, StoreOrigin::kNamed);
2275 36 : if (result.IsNothing()) return result;
2276 36 : if (stable) stable = from->map() == *map;
2277 : } else {
2278 1368 : if (excluded_properties != nullptr &&
2279 1080 : HasExcludedProperty(excluded_properties, next_key)) {
2280 99 : continue;
2281 : }
2282 :
2283 : // 4a ii 2. Perform ? CreateDataProperty(target, nextKey, propValue).
2284 : bool success;
2285 : LookupIterator it = LookupIterator::PropertyOrElement(
2286 357 : isolate, target, next_key, &success, LookupIterator::OWN);
2287 357 : CHECK(success);
2288 714 : CHECK(JSObject::CreateDataProperty(&it, prop_value, kThrowOnError)
2289 : .FromJust());
2290 : }
2291 : }
2292 :
2293 : return Just(true);
2294 : }
2295 : } // namespace
2296 :
2297 : // static
2298 752 : Maybe<bool> JSReceiver::SetOrCopyDataProperties(
2299 : Isolate* isolate, Handle<JSReceiver> target, Handle<Object> source,
2300 : const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) {
2301 : Maybe<bool> fast_assign =
2302 752 : FastAssign(target, source, excluded_properties, use_set);
2303 752 : if (fast_assign.IsNothing()) return Nothing<bool>();
2304 752 : if (fast_assign.FromJust()) return Just(true);
2305 :
2306 810 : Handle<JSReceiver> from = Object::ToObject(isolate, source).ToHandleChecked();
2307 : // 3b. Let keys be ? from.[[OwnPropertyKeys]]().
2308 : Handle<FixedArray> keys;
2309 810 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2310 : isolate, keys,
2311 : KeyAccumulator::GetKeys(from, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES,
2312 : GetKeysConversion::kKeepNumbers),
2313 : Nothing<bool>());
2314 :
2315 : // 4. Repeat for each element nextKey of keys in List order,
2316 3807 : for (int j = 0; j < keys->length(); ++j) {
2317 : Handle<Object> next_key(keys->get(j), isolate);
2318 : // 4a i. Let desc be ? from.[[GetOwnProperty]](nextKey).
2319 : PropertyDescriptor desc;
2320 : Maybe<bool> found =
2321 1791 : JSReceiver::GetOwnPropertyDescriptor(isolate, from, next_key, &desc);
2322 1854 : if (found.IsNothing()) return Nothing<bool>();
2323 : // 4a ii. If desc is not undefined and desc.[[Enumerable]] is true, then
2324 3510 : if (found.FromJust() && desc.enumerable()) {
2325 : // 4a ii 1. Let propValue be ? Get(from, nextKey).
2326 : Handle<Object> prop_value;
2327 2241 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2328 : isolate, prop_value,
2329 : Runtime::GetObjectProperty(isolate, from, next_key), Nothing<bool>());
2330 :
2331 1080 : if (use_set) {
2332 : // 4c ii 2. Let status be ? Set(to, nextKey, propValue, true).
2333 : Handle<Object> status;
2334 1422 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2335 : isolate, status,
2336 : Runtime::SetObjectProperty(isolate, target, next_key, prop_value,
2337 : LanguageMode::kStrict,
2338 : StoreOrigin::kMaybeKeyed),
2339 : Nothing<bool>());
2340 : } else {
2341 576 : if (excluded_properties != nullptr &&
2342 207 : HasExcludedProperty(excluded_properties, next_key)) {
2343 72 : continue;
2344 : }
2345 :
2346 : // 4a ii 2. Perform ! CreateDataProperty(target, nextKey, propValue).
2347 : bool success;
2348 : LookupIterator it = LookupIterator::PropertyOrElement(
2349 297 : isolate, target, next_key, &success, LookupIterator::OWN);
2350 297 : CHECK(success);
2351 594 : CHECK(JSObject::CreateDataProperty(&it, prop_value, kThrowOnError)
2352 : .FromJust());
2353 : }
2354 : }
2355 : }
2356 :
2357 : return Just(true);
2358 : }
2359 :
2360 368432 : Map Object::GetPrototypeChainRootMap(Isolate* isolate) const {
2361 : DisallowHeapAllocation no_alloc;
2362 368433 : if (IsSmi()) {
2363 25625 : Context native_context = isolate->context()->native_context();
2364 25625 : return native_context->number_function()->initial_map();
2365 : }
2366 :
2367 : const HeapObject heap_object = HeapObject::cast(*this);
2368 342808 : return heap_object->map()->GetPrototypeChainRootMap(isolate);
2369 : }
2370 :
2371 3703553 : Map Map::GetPrototypeChainRootMap(Isolate* isolate) const {
2372 : DisallowHeapAllocation no_alloc;
2373 3703553 : if (IsJSReceiverMap()) {
2374 3325530 : return *this;
2375 : }
2376 : int constructor_function_index = GetConstructorFunctionIndex();
2377 378023 : if (constructor_function_index != Map::kNoConstructorFunctionIndex) {
2378 378023 : Context native_context = isolate->context()->native_context();
2379 : JSFunction constructor_function =
2380 378025 : JSFunction::cast(native_context->get(constructor_function_index));
2381 378025 : return constructor_function->initial_map();
2382 : }
2383 : return ReadOnlyRoots(isolate).null_value()->map();
2384 : }
2385 :
2386 10165765 : Smi Object::GetOrCreateHash(Isolate* isolate) {
2387 : DisallowHeapAllocation no_gc;
2388 10165765 : Object hash = Object::GetSimpleHash(*this);
2389 10165765 : if (hash->IsSmi()) return Smi::cast(hash);
2390 :
2391 : DCHECK(IsJSReceiver());
2392 20374 : return JSReceiver::cast(*this)->GetOrCreateIdentityHash(isolate);
2393 : }
2394 :
2395 802521 : bool Object::SameValue(Object other) {
2396 802521 : if (other == *this) return true;
2397 :
2398 174382 : if (IsNumber() && other->IsNumber()) {
2399 21292 : double this_value = Number();
2400 21292 : double other_value = other->Number();
2401 : // SameValue(NaN, NaN) is true.
2402 21292 : if (this_value != other_value) {
2403 18865 : return std::isnan(this_value) && std::isnan(other_value);
2404 : }
2405 : // SameValue(0.0, -0.0) is false.
2406 2427 : return (std::signbit(this_value) == std::signbit(other_value));
2407 : }
2408 217116 : if (IsString() && other->IsString()) {
2409 93490 : return String::cast(*this)->Equals(String::cast(other));
2410 : }
2411 29180 : if (IsBigInt() && other->IsBigInt()) {
2412 27 : return BigInt::EqualToBigInt(BigInt::cast(*this), BigInt::cast(other));
2413 : }
2414 : return false;
2415 : }
2416 :
2417 23484053 : bool Object::SameValueZero(Object other) {
2418 23484053 : if (other == *this) return true;
2419 :
2420 27520726 : if (IsNumber() && other->IsNumber()) {
2421 9287708 : double this_value = Number();
2422 9287708 : double other_value = other->Number();
2423 : // +0 == -0 is true
2424 9287708 : return this_value == other_value ||
2425 4 : (std::isnan(this_value) && std::isnan(other_value));
2426 : }
2427 17871564 : if (IsString() && other->IsString()) {
2428 8648576 : return String::cast(*this)->Equals(String::cast(other));
2429 : }
2430 292782 : if (IsBigInt() && other->IsBigInt()) {
2431 0 : return BigInt::EqualToBigInt(BigInt::cast(*this), BigInt::cast(other));
2432 : }
2433 : return false;
2434 : }
2435 :
2436 14499 : MaybeHandle<Object> Object::ArraySpeciesConstructor(
2437 : Isolate* isolate, Handle<Object> original_array) {
2438 14499 : Handle<Object> default_species = isolate->array_function();
2439 40059 : if (original_array->IsJSArray() &&
2440 35319 : Handle<JSArray>::cast(original_array)->HasArrayPrototype(isolate) &&
2441 9759 : isolate->IsArraySpeciesLookupChainIntact()) {
2442 8756 : return default_species;
2443 : }
2444 : Handle<Object> constructor = isolate->factory()->undefined_value();
2445 : Maybe<bool> is_array = Object::IsArray(original_array);
2446 5743 : MAYBE_RETURN_NULL(is_array);
2447 5743 : if (is_array.FromJust()) {
2448 4718 : ASSIGN_RETURN_ON_EXCEPTION(
2449 : isolate, constructor,
2450 : Object::GetProperty(isolate, original_array,
2451 : isolate->factory()->constructor_string()),
2452 : Object);
2453 4700 : if (constructor->IsConstructor()) {
2454 : Handle<Context> constructor_context;
2455 4074 : ASSIGN_RETURN_ON_EXCEPTION(
2456 : isolate, constructor_context,
2457 : JSReceiver::GetFunctionRealm(Handle<JSReceiver>::cast(constructor)),
2458 : Object);
2459 6129 : if (*constructor_context != *isolate->native_context() &&
2460 2055 : *constructor == constructor_context->array_function()) {
2461 : constructor = isolate->factory()->undefined_value();
2462 : }
2463 : }
2464 4700 : if (constructor->IsJSReceiver()) {
2465 4112 : ASSIGN_RETURN_ON_EXCEPTION(
2466 : isolate, constructor,
2467 : JSReceiver::GetProperty(isolate,
2468 : Handle<JSReceiver>::cast(constructor),
2469 : isolate->factory()->species_symbol()),
2470 : Object);
2471 4094 : if (constructor->IsNull(isolate)) {
2472 : constructor = isolate->factory()->undefined_value();
2473 : }
2474 : }
2475 : }
2476 11450 : if (constructor->IsUndefined(isolate)) {
2477 3705 : return default_species;
2478 : } else {
2479 4040 : if (!constructor->IsConstructor()) {
2480 0 : THROW_NEW_ERROR(isolate,
2481 : NewTypeError(MessageTemplate::kSpeciesNotConstructor),
2482 : Object);
2483 : }
2484 2020 : return constructor;
2485 : }
2486 : }
2487 :
2488 : // ES6 section 7.3.20 SpeciesConstructor ( O, defaultConstructor )
2489 782 : V8_WARN_UNUSED_RESULT MaybeHandle<Object> Object::SpeciesConstructor(
2490 : Isolate* isolate, Handle<JSReceiver> recv,
2491 : Handle<JSFunction> default_ctor) {
2492 : Handle<Object> ctor_obj;
2493 1564 : ASSIGN_RETURN_ON_EXCEPTION(
2494 : isolate, ctor_obj,
2495 : JSObject::GetProperty(isolate, recv,
2496 : isolate->factory()->constructor_string()),
2497 : Object);
2498 :
2499 1564 : if (ctor_obj->IsUndefined(isolate)) return default_ctor;
2500 :
2501 1546 : if (!ctor_obj->IsJSReceiver()) {
2502 0 : THROW_NEW_ERROR(isolate,
2503 : NewTypeError(MessageTemplate::kConstructorNotReceiver),
2504 : Object);
2505 : }
2506 :
2507 773 : Handle<JSReceiver> ctor = Handle<JSReceiver>::cast(ctor_obj);
2508 :
2509 : Handle<Object> species;
2510 1546 : ASSIGN_RETURN_ON_EXCEPTION(
2511 : isolate, species,
2512 : JSObject::GetProperty(isolate, ctor,
2513 : isolate->factory()->species_symbol()),
2514 : Object);
2515 :
2516 1546 : if (species->IsNullOrUndefined(isolate)) {
2517 0 : return default_ctor;
2518 : }
2519 :
2520 1546 : if (species->IsConstructor()) return species;
2521 :
2522 0 : THROW_NEW_ERROR(
2523 : isolate, NewTypeError(MessageTemplate::kSpeciesNotConstructor), Object);
2524 : }
2525 :
2526 0 : bool Object::IterationHasObservableEffects() {
2527 : // Check that this object is an array.
2528 0 : if (!IsJSArray()) return true;
2529 0 : JSArray array = JSArray::cast(*this);
2530 : Isolate* isolate = array->GetIsolate();
2531 :
2532 : #ifdef V8_ENABLE_FORCE_SLOW_PATH
2533 : if (isolate->force_slow_path()) return true;
2534 : #endif
2535 :
2536 : // Check that we have the original ArrayPrototype.
2537 0 : if (!array->map()->prototype()->IsJSObject()) return true;
2538 0 : JSObject array_proto = JSObject::cast(array->map()->prototype());
2539 0 : if (!isolate->is_initial_array_prototype(array_proto)) return true;
2540 :
2541 : // Check that the ArrayPrototype hasn't been modified in a way that would
2542 : // affect iteration.
2543 0 : if (!isolate->IsArrayIteratorLookupChainIntact()) return true;
2544 :
2545 : // For FastPacked kinds, iteration will have the same effect as simply
2546 : // accessing each property in order.
2547 0 : ElementsKind array_kind = array->GetElementsKind();
2548 0 : if (IsFastPackedElementsKind(array_kind)) return false;
2549 :
2550 : // For FastHoley kinds, an element access on a hole would cause a lookup on
2551 : // the prototype. This could have different results if the prototype has been
2552 : // changed.
2553 0 : if (IsHoleyElementsKind(array_kind) &&
2554 0 : isolate->IsNoElementsProtectorIntact()) {
2555 : return false;
2556 : }
2557 0 : return true;
2558 : }
2559 :
2560 8520 : void Object::ShortPrint(FILE* out) const {
2561 8520 : OFStream os(out);
2562 8520 : os << Brief(*this);
2563 8520 : }
2564 :
2565 14115 : void Object::ShortPrint(StringStream* accumulator) const {
2566 14115 : std::ostringstream os;
2567 14115 : os << Brief(*this);
2568 28230 : accumulator->Add(os.str().c_str());
2569 14115 : }
2570 :
2571 118720 : void Object::ShortPrint(std::ostream& os) const { os << Brief(*this); }
2572 :
2573 2 : std::ostream& operator<<(std::ostream& os, const Object& obj) {
2574 : obj.ShortPrint(os);
2575 2 : return os;
2576 : }
2577 :
2578 0 : void MaybeObject::ShortPrint(FILE* out) {
2579 0 : OFStream os(out);
2580 0 : os << Brief(*this);
2581 0 : }
2582 :
2583 0 : void MaybeObject::ShortPrint(StringStream* accumulator) {
2584 0 : std::ostringstream os;
2585 0 : os << Brief(*this);
2586 0 : accumulator->Add(os.str().c_str());
2587 0 : }
2588 :
2589 0 : void MaybeObject::ShortPrint(std::ostream& os) { os << Brief(*this); }
2590 :
2591 351124 : Brief::Brief(const Object v) : value(v->ptr()) {}
2592 0 : Brief::Brief(const MaybeObject v) : value(v.ptr()) {}
2593 :
2594 216969 : std::ostream& operator<<(std::ostream& os, const Brief& v) {
2595 216969 : MaybeObject maybe_object(v.value);
2596 216969 : Smi smi;
2597 216969 : HeapObject heap_object;
2598 216969 : if (maybe_object->ToSmi(&smi)) {
2599 : smi->SmiPrint(os);
2600 181559 : } else if (maybe_object->IsCleared()) {
2601 0 : os << "[cleared]";
2602 181559 : } else if (maybe_object->GetHeapObjectIfWeak(&heap_object)) {
2603 0 : os << "[weak] ";
2604 0 : heap_object->HeapObjectShortPrint(os);
2605 181559 : } else if (maybe_object->GetHeapObjectIfStrong(&heap_object)) {
2606 181559 : heap_object->HeapObjectShortPrint(os);
2607 : } else {
2608 0 : UNREACHABLE();
2609 : }
2610 216969 : return os;
2611 : }
2612 :
2613 725 : void Smi::SmiPrint(std::ostream& os) const { // NOLINT
2614 36135 : os << value();
2615 725 : }
2616 :
2617 5781661 : Handle<String> String::SlowFlatten(Isolate* isolate, Handle<ConsString> cons,
2618 : PretenureFlag pretenure) {
2619 : DCHECK_NE(cons->second()->length(), 0);
2620 :
2621 : // TurboFan can create cons strings with empty first parts.
2622 17344983 : while (cons->first()->length() == 0) {
2623 : // We do not want to call this function recursively. Therefore we call
2624 : // String::Flatten only in those cases where String::SlowFlatten is not
2625 : // called again.
2626 42 : if (cons->second()->IsConsString() && !cons->second()->IsFlat()) {
2627 0 : cons = handle(ConsString::cast(cons->second()), isolate);
2628 : } else {
2629 42 : return String::Flatten(isolate, handle(cons->second(), isolate));
2630 : }
2631 : }
2632 :
2633 : DCHECK(AllowHeapAllocation::IsAllowed());
2634 : int length = cons->length();
2635 5781640 : PretenureFlag tenure = Heap::InNewSpace(*cons) ? pretenure : TENURED;
2636 : Handle<SeqString> result;
2637 5781640 : if (cons->IsOneByteRepresentation()) {
2638 : Handle<SeqOneByteString> flat = isolate->factory()->NewRawOneByteString(
2639 11324488 : length, tenure).ToHandleChecked();
2640 : DisallowHeapAllocation no_gc;
2641 5662244 : WriteToFlat(*cons, flat->GetChars(no_gc), 0, length);
2642 : result = flat;
2643 : } else {
2644 : Handle<SeqTwoByteString> flat = isolate->factory()->NewRawTwoByteString(
2645 238792 : length, tenure).ToHandleChecked();
2646 : DisallowHeapAllocation no_gc;
2647 119396 : WriteToFlat(*cons, flat->GetChars(no_gc), 0, length);
2648 : result = flat;
2649 : }
2650 11563280 : cons->set_first(isolate, *result);
2651 5781640 : cons->set_second(isolate, ReadOnlyRoots(isolate).empty_string());
2652 : DCHECK(result->IsFlat());
2653 5781640 : return result;
2654 : }
2655 :
2656 :
2657 :
2658 306 : bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
2659 : DisallowHeapAllocation no_allocation;
2660 : // Externalizing twice leaks the external resource, so it's
2661 : // prohibited by the API.
2662 : DCHECK(this->SupportsExternalization());
2663 : DCHECK(resource->IsCacheable());
2664 : #ifdef ENABLE_SLOW_DCHECKS
2665 : if (FLAG_enable_slow_asserts) {
2666 : // Assert that the resource and the string are equivalent.
2667 : DCHECK(static_cast<size_t>(this->length()) == resource->length());
2668 : ScopedVector<uc16> smart_chars(this->length());
2669 : String::WriteToFlat(*this, smart_chars.start(), 0, this->length());
2670 : DCHECK_EQ(0, memcmp(smart_chars.start(), resource->data(),
2671 : resource->length() * sizeof(smart_chars[0])));
2672 : }
2673 : #endif // DEBUG
2674 306 : int size = this->Size(); // Byte size of the original string.
2675 : // Abort if size does not allow in-place conversion.
2676 306 : if (size < ExternalString::kUncachedSize) return false;
2677 : Isolate* isolate;
2678 : // Read-only strings cannot be made external, since that would mutate the
2679 : // string.
2680 306 : if (!Isolate::FromWritableHeapObject(*this, &isolate)) return false;
2681 306 : Heap* heap = isolate->heap();
2682 306 : bool is_one_byte = this->IsOneByteRepresentation();
2683 : bool is_internalized = this->IsInternalizedString();
2684 : bool has_pointers = StringShape(*this).IsIndirect();
2685 306 : if (has_pointers) {
2686 64 : heap->NotifyObjectLayoutChange(*this, size, no_allocation);
2687 : }
2688 : // Morph the string to an external string by replacing the map and
2689 : // reinitializing the fields. This won't work if the space the existing
2690 : // string occupies is too small for a regular external string. Instead, we
2691 : // resort to an uncached external string instead, omitting the field caching
2692 : // the address of the backing store. When we encounter uncached external
2693 : // strings in generated code, we need to bailout to runtime.
2694 : Map new_map;
2695 : ReadOnlyRoots roots(heap);
2696 306 : if (size < ExternalString::kSize) {
2697 110 : if (is_internalized) {
2698 20 : if (is_one_byte) {
2699 : new_map =
2700 : roots
2701 15 : .uncached_external_internalized_string_with_one_byte_data_map();
2702 : } else {
2703 5 : new_map = roots.uncached_external_internalized_string_map();
2704 : }
2705 : } else {
2706 : new_map = is_one_byte
2707 : ? roots.uncached_external_string_with_one_byte_data_map()
2708 180 : : roots.uncached_external_string_map();
2709 : }
2710 : } else {
2711 : new_map =
2712 : is_internalized
2713 : ? (is_one_byte
2714 : ? roots.external_internalized_string_with_one_byte_data_map()
2715 : : roots.external_internalized_string_map())
2716 : : (is_one_byte ? roots.external_string_with_one_byte_data_map()
2717 392 : : roots.external_string_map());
2718 : }
2719 :
2720 : // Byte size of the external String object.
2721 306 : int new_size = this->SizeFromMap(new_map);
2722 : heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
2723 612 : ClearRecordedSlots::kNo);
2724 306 : if (has_pointers) {
2725 64 : heap->ClearRecordedSlotRange(this->address(), this->address() + new_size);
2726 : }
2727 :
2728 : // We are storing the new map using release store after creating a filler for
2729 : // the left-over space to avoid races with the sweeper thread.
2730 306 : this->synchronized_set_map(new_map);
2731 :
2732 306 : ExternalTwoByteString self = ExternalTwoByteString::cast(*this);
2733 306 : self->SetResource(isolate, resource);
2734 : heap->RegisterExternalString(*this);
2735 306 : if (is_internalized) self->Hash(); // Force regeneration of the hash value.
2736 : return true;
2737 : }
2738 :
2739 :
2740 315 : bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
2741 : DisallowHeapAllocation no_allocation;
2742 : // Externalizing twice leaks the external resource, so it's
2743 : // prohibited by the API.
2744 : DCHECK(this->SupportsExternalization());
2745 : DCHECK(resource->IsCacheable());
2746 : #ifdef ENABLE_SLOW_DCHECKS
2747 : if (FLAG_enable_slow_asserts) {
2748 : // Assert that the resource and the string are equivalent.
2749 : DCHECK(static_cast<size_t>(this->length()) == resource->length());
2750 : if (this->IsTwoByteRepresentation()) {
2751 : ScopedVector<uint16_t> smart_chars(this->length());
2752 : String::WriteToFlat(*this, smart_chars.start(), 0, this->length());
2753 : DCHECK(String::IsOneByte(smart_chars.start(), this->length()));
2754 : }
2755 : ScopedVector<char> smart_chars(this->length());
2756 : String::WriteToFlat(*this, smart_chars.start(), 0, this->length());
2757 : DCHECK_EQ(0, memcmp(smart_chars.start(), resource->data(),
2758 : resource->length() * sizeof(smart_chars[0])));
2759 : }
2760 : #endif // DEBUG
2761 315 : int size = this->Size(); // Byte size of the original string.
2762 : // Abort if size does not allow in-place conversion.
2763 315 : if (size < ExternalString::kUncachedSize) return false;
2764 : Isolate* isolate;
2765 : // Read-only strings cannot be made external, since that would mutate the
2766 : // string.
2767 315 : if (!Isolate::FromWritableHeapObject(*this, &isolate)) return false;
2768 315 : Heap* heap = isolate->heap();
2769 : bool is_internalized = this->IsInternalizedString();
2770 : bool has_pointers = StringShape(*this).IsIndirect();
2771 :
2772 315 : if (has_pointers) {
2773 29 : heap->NotifyObjectLayoutChange(*this, size, no_allocation);
2774 : }
2775 :
2776 : // Morph the string to an external string by replacing the map and
2777 : // reinitializing the fields. This won't work if the space the existing
2778 : // string occupies is too small for a regular external string. Instead, we
2779 : // resort to an uncached external string instead, omitting the field caching
2780 : // the address of the backing store. When we encounter uncached external
2781 : // strings in generated code, we need to bailout to runtime.
2782 : Map new_map;
2783 : ReadOnlyRoots roots(heap);
2784 315 : if (size < ExternalString::kSize) {
2785 : new_map = is_internalized
2786 : ? roots.uncached_external_one_byte_internalized_string_map()
2787 38 : : roots.uncached_external_one_byte_string_map();
2788 : } else {
2789 : new_map = is_internalized
2790 : ? roots.external_one_byte_internalized_string_map()
2791 592 : : roots.external_one_byte_string_map();
2792 : }
2793 :
2794 : // Byte size of the external String object.
2795 315 : int new_size = this->SizeFromMap(new_map);
2796 : heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
2797 630 : ClearRecordedSlots::kNo);
2798 315 : if (has_pointers) {
2799 29 : heap->ClearRecordedSlotRange(this->address(), this->address() + new_size);
2800 : }
2801 :
2802 : // We are storing the new map using release store after creating a filler for
2803 : // the left-over space to avoid races with the sweeper thread.
2804 315 : this->synchronized_set_map(new_map);
2805 :
2806 315 : ExternalOneByteString self = ExternalOneByteString::cast(*this);
2807 315 : self->SetResource(isolate, resource);
2808 : heap->RegisterExternalString(*this);
2809 315 : if (is_internalized) self->Hash(); // Force regeneration of the hash value.
2810 : return true;
2811 : }
2812 :
2813 1504 : bool String::SupportsExternalization() {
2814 3008 : if (this->IsThinString()) {
2815 0 : return i::ThinString::cast(*this)->actual()->SupportsExternalization();
2816 : }
2817 :
2818 : Isolate* isolate;
2819 : // RO_SPACE strings cannot be externalized.
2820 1504 : if (!Isolate::FromWritableHeapObject(*this, &isolate)) {
2821 : return false;
2822 : }
2823 :
2824 : // Already an external string.
2825 1486 : if (StringShape(*this).IsExternal()) {
2826 : return false;
2827 : }
2828 :
2829 1138 : return !isolate->heap()->IsInGCPostProcessing();
2830 : }
2831 :
2832 41947 : void String::StringShortPrint(StringStream* accumulator, bool show_details) {
2833 83894 : const char* internalized_marker = this->IsInternalizedString() ? "#" : "";
2834 :
2835 : int len = length();
2836 41947 : if (len > kMaxShortPrintLength) {
2837 0 : accumulator->Add("<Very long string[%s%u]>", internalized_marker, len);
2838 0 : return;
2839 : }
2840 :
2841 41947 : if (!LooksValid()) {
2842 0 : accumulator->Add("<Invalid String>");
2843 0 : return;
2844 : }
2845 :
2846 41947 : StringCharacterStream stream(*this);
2847 :
2848 : bool truncated = false;
2849 41947 : if (len > kMaxShortPrintLength) {
2850 : len = kMaxShortPrintLength;
2851 : truncated = true;
2852 : }
2853 : bool one_byte = true;
2854 377495 : for (int i = 0; i < len; i++) {
2855 335548 : uint16_t c = stream.GetNext();
2856 :
2857 335548 : if (c < 32 || c >= 127) {
2858 : one_byte = false;
2859 : }
2860 : }
2861 41947 : stream.Reset(*this);
2862 41947 : if (one_byte) {
2863 41947 : if (show_details)
2864 39478 : accumulator->Add("<String[%s%u]: ", internalized_marker, length());
2865 335548 : for (int i = 0; i < len; i++) {
2866 335548 : accumulator->Put(static_cast<char>(stream.GetNext()));
2867 : }
2868 41947 : if (show_details) accumulator->Put('>');
2869 : } else {
2870 : // Backslash indicates that the string contains control
2871 : // characters and that backslashes are therefore escaped.
2872 0 : if (show_details)
2873 0 : accumulator->Add("<String[%s%u]\\: ", internalized_marker, length());
2874 0 : for (int i = 0; i < len; i++) {
2875 0 : uint16_t c = stream.GetNext();
2876 0 : if (c == '\n') {
2877 0 : accumulator->Add("\\n");
2878 0 : } else if (c == '\r') {
2879 0 : accumulator->Add("\\r");
2880 0 : } else if (c == '\\') {
2881 0 : accumulator->Add("\\\\");
2882 0 : } else if (c < 32 || c > 126) {
2883 0 : accumulator->Add("\\x%02x", c);
2884 : } else {
2885 0 : accumulator->Put(static_cast<char>(c));
2886 : }
2887 : }
2888 0 : if (truncated) {
2889 0 : accumulator->Put('.');
2890 0 : accumulator->Put('.');
2891 0 : accumulator->Put('.');
2892 : }
2893 0 : if (show_details) accumulator->Put('>');
2894 : }
2895 : return;
2896 : }
2897 :
2898 :
2899 45 : void String::PrintUC16(std::ostream& os, int start, int end) { // NOLINT
2900 45 : if (end < 0) end = length();
2901 45 : StringCharacterStream stream(*this, start);
2902 5823 : for (int i = start; i < end && stream.HasMore(); i++) {
2903 11556 : os << AsUC16(stream.GetNext());
2904 : }
2905 45 : }
2906 :
2907 :
2908 57573 : void JSObject::JSObjectShortPrint(StringStream* accumulator) {
2909 57573 : switch (map()->instance_type()) {
2910 : case JS_ARRAY_TYPE: {
2911 2250 : double length = JSArray::cast(*this)->length()->IsUndefined()
2912 : ? 0
2913 2250 : : JSArray::cast(*this)->length()->Number();
2914 1125 : accumulator->Add("<JSArray[%u]>", static_cast<uint32_t>(length));
2915 1125 : break;
2916 : }
2917 : case JS_BOUND_FUNCTION_TYPE: {
2918 0 : JSBoundFunction bound_function = JSBoundFunction::cast(*this);
2919 0 : accumulator->Add("<JSBoundFunction");
2920 : accumulator->Add(" (BoundTargetFunction %p)>",
2921 : reinterpret_cast<void*>(
2922 0 : bound_function->bound_target_function().ptr()));
2923 : break;
2924 : }
2925 : case JS_WEAK_MAP_TYPE: {
2926 0 : accumulator->Add("<JSWeakMap>");
2927 0 : break;
2928 : }
2929 : case JS_WEAK_SET_TYPE: {
2930 0 : accumulator->Add("<JSWeakSet>");
2931 0 : break;
2932 : }
2933 : case JS_REGEXP_TYPE: {
2934 18 : accumulator->Add("<JSRegExp");
2935 18 : JSRegExp regexp = JSRegExp::cast(*this);
2936 36 : if (regexp->source()->IsString()) {
2937 18 : accumulator->Add(" ");
2938 36 : String::cast(regexp->source())->StringShortPrint(accumulator);
2939 : }
2940 18 : accumulator->Add(">");
2941 :
2942 : break;
2943 : }
2944 : case JS_FUNCTION_TYPE: {
2945 44738 : JSFunction function = JSFunction::cast(*this);
2946 44738 : Object fun_name = function->shared()->DebugName();
2947 : bool printed = false;
2948 44738 : if (fun_name->IsString()) {
2949 : String str = String::cast(fun_name);
2950 44738 : if (str->length() > 0) {
2951 38587 : accumulator->Add("<JSFunction ");
2952 38587 : accumulator->Put(str);
2953 : printed = true;
2954 : }
2955 : }
2956 44738 : if (!printed) {
2957 6151 : accumulator->Add("<JSFunction");
2958 : }
2959 44738 : if (FLAG_trace_file_names) {
2960 0 : Object source_name = Script::cast(function->shared()->script())->name();
2961 0 : if (source_name->IsString()) {
2962 : String str = String::cast(source_name);
2963 0 : if (str->length() > 0) {
2964 0 : accumulator->Add(" <");
2965 0 : accumulator->Put(str);
2966 0 : accumulator->Add(">");
2967 : }
2968 : }
2969 : }
2970 : accumulator->Add(" (sfi = %p)",
2971 89476 : reinterpret_cast<void*>(function->shared().ptr()));
2972 44738 : accumulator->Put('>');
2973 : break;
2974 : }
2975 : case JS_GENERATOR_OBJECT_TYPE: {
2976 0 : accumulator->Add("<JSGenerator>");
2977 0 : break;
2978 : }
2979 : case JS_ASYNC_FUNCTION_OBJECT_TYPE: {
2980 0 : accumulator->Add("<JSAsyncFunctionObject>");
2981 0 : break;
2982 : }
2983 : case JS_ASYNC_GENERATOR_OBJECT_TYPE: {
2984 0 : accumulator->Add("<JS AsyncGenerator>");
2985 0 : break;
2986 : }
2987 :
2988 : // All other JSObjects are rather similar to each other (JSObject,
2989 : // JSGlobalProxy, JSGlobalObject, JSUndetectable, JSValue).
2990 : default: {
2991 11692 : Map map_of_this = map();
2992 : Heap* heap = GetHeap();
2993 11692 : Object constructor = map_of_this->GetConstructor();
2994 : bool printed = false;
2995 23384 : if (constructor->IsHeapObject() &&
2996 11692 : !heap->Contains(HeapObject::cast(constructor))) {
2997 0 : accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
2998 : } else {
2999 11692 : bool global_object = IsJSGlobalProxy();
3000 11692 : if (constructor->IsJSFunction()) {
3001 11692 : if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
3002 0 : accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
3003 : } else {
3004 : String constructor_name =
3005 11692 : JSFunction::cast(constructor)->shared()->Name();
3006 11692 : if (constructor_name->length() > 0) {
3007 10212 : accumulator->Add(global_object ? "<GlobalObject " : "<");
3008 10212 : accumulator->Put(constructor_name);
3009 : accumulator->Add(
3010 : " %smap = %p",
3011 10212 : map_of_this->is_deprecated() ? "deprecated-" : "",
3012 10212 : map_of_this);
3013 : printed = true;
3014 : }
3015 : }
3016 0 : } else if (constructor->IsFunctionTemplateInfo()) {
3017 0 : accumulator->Add(global_object ? "<RemoteObject>" : "<RemoteObject>");
3018 : printed = true;
3019 : }
3020 11692 : if (!printed) {
3021 1480 : accumulator->Add("<JS%sObject", global_object ? "Global " : "");
3022 : }
3023 : }
3024 23384 : if (IsJSValue()) {
3025 84 : accumulator->Add(" value = ");
3026 84 : JSValue::cast(*this)->value()->ShortPrint(accumulator);
3027 : }
3028 11692 : accumulator->Put('>');
3029 : break;
3030 : }
3031 : }
3032 57573 : }
3033 :
3034 :
3035 0 : void JSObject::PrintElementsTransition(
3036 : FILE* file, Handle<JSObject> object,
3037 : ElementsKind from_kind, Handle<FixedArrayBase> from_elements,
3038 : ElementsKind to_kind, Handle<FixedArrayBase> to_elements) {
3039 0 : if (from_kind != to_kind) {
3040 0 : OFStream os(file);
3041 0 : os << "elements transition [" << ElementsKindToString(from_kind) << " -> "
3042 0 : << ElementsKindToString(to_kind) << "] in ";
3043 0 : JavaScriptFrame::PrintTop(object->GetIsolate(), file, false, true);
3044 0 : PrintF(file, " for ");
3045 0 : object->ShortPrint(file);
3046 0 : PrintF(file, " from ");
3047 0 : from_elements->ShortPrint(file);
3048 0 : PrintF(file, " to ");
3049 0 : to_elements->ShortPrint(file);
3050 0 : PrintF(file, "\n");
3051 : }
3052 0 : }
3053 :
3054 :
3055 : // static
3056 27893 : MaybeHandle<JSFunction> Map::GetConstructorFunction(
3057 : Handle<Map> map, Handle<Context> native_context) {
3058 27893 : if (map->IsPrimitiveMap()) {
3059 : int const constructor_function_index = map->GetConstructorFunctionIndex();
3060 8560 : if (constructor_function_index != kNoConstructorFunctionIndex) {
3061 : return handle(
3062 : JSFunction::cast(native_context->get(constructor_function_index)),
3063 17120 : native_context->GetIsolate());
3064 : }
3065 : }
3066 19333 : return MaybeHandle<JSFunction>();
3067 : }
3068 :
3069 0 : void Map::PrintReconfiguration(Isolate* isolate, FILE* file, int modify_index,
3070 : PropertyKind kind,
3071 : PropertyAttributes attributes) {
3072 0 : OFStream os(file);
3073 0 : os << "[reconfiguring]";
3074 0 : Name name = instance_descriptors()->GetKey(modify_index);
3075 0 : if (name->IsString()) {
3076 0 : String::cast(name)->PrintOn(file);
3077 : } else {
3078 0 : os << "{symbol " << reinterpret_cast<void*>(name.ptr()) << "}";
3079 : }
3080 0 : os << ": " << (kind == kData ? "kData" : "ACCESSORS") << ", attrs: ";
3081 0 : os << attributes << " [";
3082 0 : JavaScriptFrame::PrintTop(isolate, file, false, true);
3083 0 : os << "]\n";
3084 0 : }
3085 :
3086 54733723 : VisitorId Map::GetVisitorId(Map map) {
3087 : STATIC_ASSERT(kVisitorIdCount <= 256);
3088 :
3089 54733723 : const int instance_type = map->instance_type();
3090 :
3091 54733723 : if (instance_type < FIRST_NONSTRING_TYPE) {
3092 1288 : switch (instance_type & kStringRepresentationMask) {
3093 : case kSeqStringTag:
3094 224 : if ((instance_type & kStringEncodingMask) == kOneByteStringTag) {
3095 : return kVisitSeqOneByteString;
3096 : } else {
3097 112 : return kVisitSeqTwoByteString;
3098 : }
3099 :
3100 : case kConsStringTag:
3101 112 : if (IsShortcutCandidate(instance_type)) {
3102 : return kVisitShortcutCandidate;
3103 : } else {
3104 0 : return kVisitConsString;
3105 : }
3106 :
3107 : case kSlicedStringTag:
3108 : return kVisitSlicedString;
3109 :
3110 : case kExternalStringTag:
3111 728 : return kVisitDataObject;
3112 :
3113 : case kThinStringTag:
3114 112 : return kVisitThinString;
3115 : }
3116 0 : UNREACHABLE();
3117 : }
3118 :
3119 54732435 : switch (instance_type) {
3120 : case BYTE_ARRAY_TYPE:
3121 : return kVisitByteArray;
3122 :
3123 : case BYTECODE_ARRAY_TYPE:
3124 56 : return kVisitBytecodeArray;
3125 :
3126 : case FREE_SPACE_TYPE:
3127 56 : return kVisitFreeSpace;
3128 :
3129 : case EMBEDDER_DATA_ARRAY_TYPE:
3130 56 : return kVisitEmbedderDataArray;
3131 :
3132 : case FIXED_ARRAY_TYPE:
3133 : case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
3134 : case HASH_TABLE_TYPE:
3135 : case ORDERED_HASH_MAP_TYPE:
3136 : case ORDERED_HASH_SET_TYPE:
3137 : case ORDERED_NAME_DICTIONARY_TYPE:
3138 : case NAME_DICTIONARY_TYPE:
3139 : case GLOBAL_DICTIONARY_TYPE:
3140 : case NUMBER_DICTIONARY_TYPE:
3141 : case SIMPLE_NUMBER_DICTIONARY_TYPE:
3142 : case STRING_TABLE_TYPE:
3143 : case SCOPE_INFO_TYPE:
3144 : case SCRIPT_CONTEXT_TABLE_TYPE:
3145 952 : return kVisitFixedArray;
3146 :
3147 : case AWAIT_CONTEXT_TYPE:
3148 : case BLOCK_CONTEXT_TYPE:
3149 : case CATCH_CONTEXT_TYPE:
3150 : case DEBUG_EVALUATE_CONTEXT_TYPE:
3151 : case EVAL_CONTEXT_TYPE:
3152 : case FUNCTION_CONTEXT_TYPE:
3153 : case MODULE_CONTEXT_TYPE:
3154 : case SCRIPT_CONTEXT_TYPE:
3155 : case WITH_CONTEXT_TYPE:
3156 504 : return kVisitContext;
3157 :
3158 : case NATIVE_CONTEXT_TYPE:
3159 56 : return kVisitNativeContext;
3160 :
3161 : case EPHEMERON_HASH_TABLE_TYPE:
3162 56 : return kVisitEphemeronHashTable;
3163 :
3164 : case WEAK_FIXED_ARRAY_TYPE:
3165 : case WEAK_ARRAY_LIST_TYPE:
3166 112 : return kVisitWeakArray;
3167 :
3168 : case FIXED_DOUBLE_ARRAY_TYPE:
3169 56 : return kVisitFixedDoubleArray;
3170 :
3171 : case PROPERTY_ARRAY_TYPE:
3172 56 : return kVisitPropertyArray;
3173 :
3174 : case FEEDBACK_CELL_TYPE:
3175 224 : return kVisitFeedbackCell;
3176 :
3177 : case FEEDBACK_VECTOR_TYPE:
3178 56 : return kVisitFeedbackVector;
3179 :
3180 : case ODDBALL_TYPE:
3181 616 : return kVisitOddball;
3182 :
3183 : case MAP_TYPE:
3184 56 : return kVisitMap;
3185 :
3186 : case CODE_TYPE:
3187 56 : return kVisitCode;
3188 :
3189 : case CELL_TYPE:
3190 56 : return kVisitCell;
3191 :
3192 : case PROPERTY_CELL_TYPE:
3193 56 : return kVisitPropertyCell;
3194 :
3195 : case DESCRIPTOR_ARRAY_TYPE:
3196 56 : return kVisitDescriptorArray;
3197 :
3198 : case TRANSITION_ARRAY_TYPE:
3199 56 : return kVisitTransitionArray;
3200 :
3201 : case JS_WEAK_MAP_TYPE:
3202 : case JS_WEAK_SET_TYPE:
3203 23222 : return kVisitJSWeakCollection;
3204 :
3205 : case CALL_HANDLER_INFO_TYPE:
3206 168 : return kVisitStruct;
3207 :
3208 : case SHARED_FUNCTION_INFO_TYPE:
3209 56 : return kVisitSharedFunctionInfo;
3210 :
3211 : case JS_PROXY_TYPE:
3212 555 : return kVisitStruct;
3213 :
3214 : case SYMBOL_TYPE:
3215 56 : return kVisitSymbol;
3216 :
3217 : case JS_ARRAY_BUFFER_TYPE:
3218 12856 : return kVisitJSArrayBuffer;
3219 :
3220 : case JS_DATA_VIEW_TYPE:
3221 901 : return kVisitJSDataView;
3222 :
3223 : case JS_TYPED_ARRAY_TYPE:
3224 31642 : return kVisitJSTypedArray;
3225 :
3226 : case SMALL_ORDERED_HASH_MAP_TYPE:
3227 56 : return kVisitSmallOrderedHashMap;
3228 :
3229 : case SMALL_ORDERED_HASH_SET_TYPE:
3230 56 : return kVisitSmallOrderedHashSet;
3231 :
3232 : case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
3233 56 : return kVisitSmallOrderedNameDictionary;
3234 :
3235 : case CODE_DATA_CONTAINER_TYPE:
3236 56 : return kVisitCodeDataContainer;
3237 :
3238 : case WASM_INSTANCE_TYPE:
3239 92999 : return kVisitWasmInstanceObject;
3240 :
3241 : case PREPARSE_DATA_TYPE:
3242 56 : return kVisitPreparseData;
3243 :
3244 : case UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE:
3245 56 : return kVisitUncompiledDataWithoutPreparseData;
3246 :
3247 : case UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE:
3248 56 : return kVisitUncompiledDataWithPreparseData;
3249 :
3250 : case JS_OBJECT_TYPE:
3251 : case JS_ERROR_TYPE:
3252 : case JS_ARGUMENTS_TYPE:
3253 : case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
3254 : case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
3255 : case JS_GENERATOR_OBJECT_TYPE:
3256 : case JS_ASYNC_FUNCTION_OBJECT_TYPE:
3257 : case JS_ASYNC_GENERATOR_OBJECT_TYPE:
3258 : case JS_MODULE_NAMESPACE_TYPE:
3259 : case JS_VALUE_TYPE:
3260 : case JS_DATE_TYPE:
3261 : case JS_ARRAY_ITERATOR_TYPE:
3262 : case JS_ARRAY_TYPE:
3263 : case JS_FUNCTION_TYPE:
3264 : case JS_GLOBAL_PROXY_TYPE:
3265 : case JS_GLOBAL_OBJECT_TYPE:
3266 : case JS_MESSAGE_OBJECT_TYPE:
3267 : case JS_SET_TYPE:
3268 : case JS_MAP_TYPE:
3269 : case JS_SET_KEY_VALUE_ITERATOR_TYPE:
3270 : case JS_SET_VALUE_ITERATOR_TYPE:
3271 : case JS_MAP_KEY_ITERATOR_TYPE:
3272 : case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
3273 : case JS_MAP_VALUE_ITERATOR_TYPE:
3274 : case JS_STRING_ITERATOR_TYPE:
3275 : case JS_PROMISE_TYPE:
3276 : case JS_REGEXP_TYPE:
3277 : case JS_REGEXP_STRING_ITERATOR_TYPE:
3278 : case JS_WEAK_FACTORY_CLEANUP_ITERATOR_TYPE:
3279 : case JS_WEAK_FACTORY_TYPE:
3280 : #ifdef V8_INTL_SUPPORT
3281 : case JS_INTL_V8_BREAK_ITERATOR_TYPE:
3282 : case JS_INTL_COLLATOR_TYPE:
3283 : case JS_INTL_DATE_TIME_FORMAT_TYPE:
3284 : case JS_INTL_LIST_FORMAT_TYPE:
3285 : case JS_INTL_LOCALE_TYPE:
3286 : case JS_INTL_NUMBER_FORMAT_TYPE:
3287 : case JS_INTL_PLURAL_RULES_TYPE:
3288 : case JS_INTL_RELATIVE_TIME_FORMAT_TYPE:
3289 : case JS_INTL_SEGMENT_ITERATOR_TYPE:
3290 : case JS_INTL_SEGMENTER_TYPE:
3291 : #endif // V8_INTL_SUPPORT
3292 : case WASM_EXCEPTION_TYPE:
3293 : case WASM_GLOBAL_TYPE:
3294 : case WASM_MEMORY_TYPE:
3295 : case WASM_MODULE_TYPE:
3296 : case WASM_TABLE_TYPE:
3297 : case JS_BOUND_FUNCTION_TYPE: {
3298 : const bool has_raw_data_fields =
3299 47050237 : (FLAG_unbox_double_fields && !map->HasFastPointerLayout()) ||
3300 : (COMPRESS_POINTERS_BOOL && JSObject::GetEmbedderFieldCount(map) > 0);
3301 47050278 : return has_raw_data_fields ? kVisitJSObject : kVisitJSObjectFast;
3302 : }
3303 : case JS_API_OBJECT_TYPE:
3304 : case JS_SPECIAL_API_OBJECT_TYPE:
3305 7511716 : return kVisitJSApiObject;
3306 :
3307 : case JS_WEAK_REF_TYPE:
3308 726 : return kVisitJSWeakRef;
3309 :
3310 : case JS_WEAK_CELL_TYPE:
3311 363 : return kVisitJSWeakCell;
3312 :
3313 : case FILLER_TYPE:
3314 : case FOREIGN_TYPE:
3315 : case HEAP_NUMBER_TYPE:
3316 : case MUTABLE_HEAP_NUMBER_TYPE:
3317 : case FEEDBACK_METADATA_TYPE:
3318 341 : return kVisitDataObject;
3319 :
3320 : case BIGINT_TYPE:
3321 56 : return kVisitBigInt;
3322 :
3323 : case FIXED_UINT8_ARRAY_TYPE:
3324 : case FIXED_INT8_ARRAY_TYPE:
3325 : case FIXED_UINT16_ARRAY_TYPE:
3326 : case FIXED_INT16_ARRAY_TYPE:
3327 : case FIXED_UINT32_ARRAY_TYPE:
3328 : case FIXED_INT32_ARRAY_TYPE:
3329 : case FIXED_FLOAT32_ARRAY_TYPE:
3330 : case FIXED_UINT8_CLAMPED_ARRAY_TYPE:
3331 : case FIXED_BIGUINT64_ARRAY_TYPE:
3332 : case FIXED_BIGINT64_ARRAY_TYPE:
3333 560 : return kVisitFixedTypedArrayBase;
3334 :
3335 : case FIXED_FLOAT64_ARRAY_TYPE:
3336 56 : return kVisitFixedFloat64Array;
3337 :
3338 : case ALLOCATION_SITE_TYPE:
3339 112 : return kVisitAllocationSite;
3340 :
3341 : #define MAKE_STRUCT_CASE(TYPE, Name, name) case TYPE:
3342 : STRUCT_LIST(MAKE_STRUCT_CASE)
3343 : #undef MAKE_STRUCT_CASE
3344 1792 : if (instance_type == PROTOTYPE_INFO_TYPE) {
3345 : return kVisitPrototypeInfo;
3346 : }
3347 1736 : return kVisitStruct;
3348 :
3349 : case LOAD_HANDLER_TYPE:
3350 : case STORE_HANDLER_TYPE:
3351 392 : return kVisitDataHandler;
3352 :
3353 : default:
3354 0 : UNREACHABLE();
3355 : }
3356 : }
3357 :
3358 0 : void Map::PrintGeneralization(
3359 : Isolate* isolate, FILE* file, const char* reason, int modify_index,
3360 : int split, int descriptors, bool descriptor_to_field,
3361 : Representation old_representation, Representation new_representation,
3362 : MaybeHandle<FieldType> old_field_type, MaybeHandle<Object> old_value,
3363 : MaybeHandle<FieldType> new_field_type, MaybeHandle<Object> new_value) {
3364 0 : OFStream os(file);
3365 0 : os << "[generalizing]";
3366 0 : Name name = instance_descriptors()->GetKey(modify_index);
3367 0 : if (name->IsString()) {
3368 0 : String::cast(name)->PrintOn(file);
3369 : } else {
3370 0 : os << "{symbol " << reinterpret_cast<void*>(name.ptr()) << "}";
3371 : }
3372 0 : os << ":";
3373 0 : if (descriptor_to_field) {
3374 0 : os << "c";
3375 : } else {
3376 0 : os << old_representation.Mnemonic() << "{";
3377 0 : if (old_field_type.is_null()) {
3378 0 : os << Brief(*(old_value.ToHandleChecked()));
3379 : } else {
3380 0 : old_field_type.ToHandleChecked()->PrintTo(os);
3381 : }
3382 0 : os << "}";
3383 : }
3384 0 : os << "->" << new_representation.Mnemonic() << "{";
3385 0 : if (new_field_type.is_null()) {
3386 0 : os << Brief(*(new_value.ToHandleChecked()));
3387 : } else {
3388 0 : new_field_type.ToHandleChecked()->PrintTo(os);
3389 : }
3390 0 : os << "} (";
3391 0 : if (strlen(reason) > 0) {
3392 0 : os << reason;
3393 : } else {
3394 0 : os << "+" << (descriptors - split) << " maps";
3395 : }
3396 0 : os << ") [";
3397 0 : JavaScriptFrame::PrintTop(isolate, file, false, true);
3398 0 : os << "]\n";
3399 0 : }
3400 :
3401 0 : void JSObject::PrintInstanceMigration(FILE* file, Map original_map,
3402 : Map new_map) {
3403 0 : if (new_map->is_dictionary_map()) {
3404 0 : PrintF(file, "[migrating to slow]\n");
3405 0 : return;
3406 : }
3407 0 : PrintF(file, "[migrating]");
3408 0 : DescriptorArray o = original_map->instance_descriptors();
3409 0 : DescriptorArray n = new_map->instance_descriptors();
3410 0 : for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) {
3411 0 : Representation o_r = o->GetDetails(i).representation();
3412 0 : Representation n_r = n->GetDetails(i).representation();
3413 0 : if (!o_r.Equals(n_r)) {
3414 0 : String::cast(o->GetKey(i))->PrintOn(file);
3415 0 : PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic());
3416 0 : } else if (o->GetDetails(i).location() == kDescriptor &&
3417 0 : n->GetDetails(i).location() == kField) {
3418 0 : Name name = o->GetKey(i);
3419 0 : if (name->IsString()) {
3420 0 : String::cast(name)->PrintOn(file);
3421 : } else {
3422 0 : PrintF(file, "{symbol %p}", reinterpret_cast<void*>(name.ptr()));
3423 : }
3424 0 : PrintF(file, " ");
3425 : }
3426 : }
3427 0 : if (original_map->elements_kind() != new_map->elements_kind()) {
3428 : PrintF(file, "elements_kind[%i->%i]", original_map->elements_kind(),
3429 0 : new_map->elements_kind());
3430 : }
3431 0 : PrintF(file, "\n");
3432 : }
3433 :
3434 138074 : bool JSObject::IsUnmodifiedApiObject(FullObjectSlot o) {
3435 138074 : Object object = *o;
3436 138074 : if (object->IsSmi()) return false;
3437 : HeapObject heap_object = HeapObject::cast(object);
3438 138074 : if (!object->IsJSObject()) return false;
3439 26797 : JSObject js_object = JSObject::cast(object);
3440 26797 : if (!js_object->IsDroppableApiWrapper()) return false;
3441 51 : Object maybe_constructor = js_object->map()->GetConstructor();
3442 51 : if (!maybe_constructor->IsJSFunction()) return false;
3443 51 : JSFunction constructor = JSFunction::cast(maybe_constructor);
3444 102 : if (js_object->elements()->length() != 0) return false;
3445 :
3446 92 : return constructor->initial_map() == heap_object->map();
3447 : }
3448 :
3449 181559 : void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
3450 181559 : os << AsHex(this->ptr(), kSystemPointerHexDigits, true) << " ";
3451 :
3452 181559 : if (IsString()) {
3453 : HeapStringAllocator allocator;
3454 : StringStream accumulator(&allocator);
3455 39460 : String::cast(*this)->StringShortPrint(&accumulator);
3456 118380 : os << accumulator.ToCString().get();
3457 : return;
3458 : }
3459 142099 : if (IsJSObject()) {
3460 : HeapStringAllocator allocator;
3461 : StringStream accumulator(&allocator);
3462 57573 : JSObject::cast(*this)->JSObjectShortPrint(&accumulator);
3463 172719 : os << accumulator.ToCString().get();
3464 : return;
3465 : }
3466 84526 : switch (map()->instance_type()) {
3467 : case MAP_TYPE: {
3468 1754 : os << "<Map";
3469 : Map mapInstance = Map::cast(*this);
3470 1754 : if (mapInstance->IsJSObjectMap()) {
3471 1754 : os << "(" << ElementsKindToString(mapInstance->elements_kind()) << ")";
3472 0 : } else if (mapInstance->instance_size() != kVariableSizeSentinel) {
3473 0 : os << "[" << mapInstance->instance_size() << "]";
3474 : }
3475 1754 : os << ">";
3476 1754 : } break;
3477 : case AWAIT_CONTEXT_TYPE: {
3478 0 : os << "<AwaitContext generator= ";
3479 : HeapStringAllocator allocator;
3480 : StringStream accumulator(&allocator);
3481 0 : Context::cast(*this)->extension()->ShortPrint(&accumulator);
3482 0 : os << accumulator.ToCString().get();
3483 : os << '>';
3484 : break;
3485 : }
3486 : case BLOCK_CONTEXT_TYPE:
3487 0 : os << "<BlockContext[" << Context::cast(*this)->length() << "]>";
3488 0 : break;
3489 : case CATCH_CONTEXT_TYPE:
3490 0 : os << "<CatchContext[" << Context::cast(*this)->length() << "]>";
3491 0 : break;
3492 : case DEBUG_EVALUATE_CONTEXT_TYPE:
3493 0 : os << "<DebugEvaluateContext[" << Context::cast(*this)->length() << "]>";
3494 0 : break;
3495 : case EVAL_CONTEXT_TYPE:
3496 0 : os << "<EvalContext[" << Context::cast(*this)->length() << "]>";
3497 0 : break;
3498 : case FUNCTION_CONTEXT_TYPE:
3499 0 : os << "<FunctionContext[" << Context::cast(*this)->length() << "]>";
3500 0 : break;
3501 : case MODULE_CONTEXT_TYPE:
3502 0 : os << "<ModuleContext[" << Context::cast(*this)->length() << "]>";
3503 0 : break;
3504 : case NATIVE_CONTEXT_TYPE:
3505 1388 : os << "<NativeContext[" << Context::cast(*this)->length() << "]>";
3506 694 : break;
3507 : case SCRIPT_CONTEXT_TYPE:
3508 0 : os << "<ScriptContext[" << Context::cast(*this)->length() << "]>";
3509 0 : break;
3510 : case WITH_CONTEXT_TYPE:
3511 0 : os << "<WithContext[" << Context::cast(*this)->length() << "]>";
3512 0 : break;
3513 : case SCRIPT_CONTEXT_TABLE_TYPE:
3514 0 : os << "<ScriptContextTable[" << FixedArray::cast(*this)->length() << "]>";
3515 0 : break;
3516 : case HASH_TABLE_TYPE:
3517 0 : os << "<HashTable[" << FixedArray::cast(*this)->length() << "]>";
3518 0 : break;
3519 : case ORDERED_HASH_MAP_TYPE:
3520 0 : os << "<OrderedHashMap[" << FixedArray::cast(*this)->length() << "]>";
3521 0 : break;
3522 : case ORDERED_HASH_SET_TYPE:
3523 0 : os << "<OrderedHashSet[" << FixedArray::cast(*this)->length() << "]>";
3524 0 : break;
3525 : case ORDERED_NAME_DICTIONARY_TYPE:
3526 0 : os << "<OrderedNameDictionary[" << FixedArray::cast(*this)->length()
3527 0 : << "]>";
3528 0 : break;
3529 : case NAME_DICTIONARY_TYPE:
3530 0 : os << "<NameDictionary[" << FixedArray::cast(*this)->length() << "]>";
3531 0 : break;
3532 : case GLOBAL_DICTIONARY_TYPE:
3533 0 : os << "<GlobalDictionary[" << FixedArray::cast(*this)->length() << "]>";
3534 0 : break;
3535 : case NUMBER_DICTIONARY_TYPE:
3536 0 : os << "<NumberDictionary[" << FixedArray::cast(*this)->length() << "]>";
3537 0 : break;
3538 : case SIMPLE_NUMBER_DICTIONARY_TYPE:
3539 0 : os << "<SimpleNumberDictionary[" << FixedArray::cast(*this)->length()
3540 0 : << "]>";
3541 0 : break;
3542 : case STRING_TABLE_TYPE:
3543 0 : os << "<StringTable[" << FixedArray::cast(*this)->length() << "]>";
3544 0 : break;
3545 : case FIXED_ARRAY_TYPE:
3546 0 : os << "<FixedArray[" << FixedArray::cast(*this)->length() << "]>";
3547 0 : break;
3548 : case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
3549 32 : os << "<ObjectBoilerplateDescription["
3550 32 : << FixedArray::cast(*this)->length() << "]>";
3551 32 : break;
3552 : case FIXED_DOUBLE_ARRAY_TYPE:
3553 0 : os << "<FixedDoubleArray[" << FixedDoubleArray::cast(*this)->length()
3554 0 : << "]>";
3555 0 : break;
3556 : case BYTE_ARRAY_TYPE:
3557 0 : os << "<ByteArray[" << ByteArray::cast(*this)->length() << "]>";
3558 0 : break;
3559 : case BYTECODE_ARRAY_TYPE:
3560 300 : os << "<BytecodeArray[" << BytecodeArray::cast(*this)->length() << "]>";
3561 300 : break;
3562 : case DESCRIPTOR_ARRAY_TYPE:
3563 15867 : os << "<DescriptorArray["
3564 31734 : << DescriptorArray::cast(*this)->number_of_descriptors() << "]>";
3565 15867 : break;
3566 : case TRANSITION_ARRAY_TYPE:
3567 125 : os << "<TransitionArray[" << TransitionArray::cast(*this)->length()
3568 125 : << "]>";
3569 125 : break;
3570 : case PROPERTY_ARRAY_TYPE:
3571 0 : os << "<PropertyArray[" << PropertyArray::cast(*this)->length() << "]>";
3572 0 : break;
3573 : case FEEDBACK_CELL_TYPE: {
3574 : {
3575 0 : ReadOnlyRoots roots = GetReadOnlyRoots();
3576 0 : os << "<FeedbackCell[";
3577 0 : if (map() == roots.no_closures_cell_map()) {
3578 0 : os << "no feedback";
3579 0 : } else if (map() == roots.no_closures_cell_map()) {
3580 0 : os << "no closures";
3581 0 : } else if (map() == roots.one_closure_cell_map()) {
3582 0 : os << "one closure";
3583 0 : } else if (map() == roots.many_closures_cell_map()) {
3584 0 : os << "many closures";
3585 : } else {
3586 0 : os << "!!!INVALID MAP!!!";
3587 : }
3588 0 : os << "]>";
3589 : }
3590 0 : break;
3591 : }
3592 : case FEEDBACK_VECTOR_TYPE:
3593 0 : os << "<FeedbackVector[" << FeedbackVector::cast(*this)->length() << "]>";
3594 0 : break;
3595 : case FREE_SPACE_TYPE:
3596 0 : os << "<FreeSpace[" << FreeSpace::cast(*this)->size() << "]>";
3597 0 : break;
3598 : #define TYPED_ARRAY_SHORT_PRINT(Type, type, TYPE, ctype) \
3599 : case FIXED_##TYPE##_ARRAY_TYPE: \
3600 : os << "<Fixed" #Type "Array[" << Fixed##Type##Array::cast(*this)->length() \
3601 : << "]>"; \
3602 : break;
3603 :
3604 0 : TYPED_ARRAYS(TYPED_ARRAY_SHORT_PRINT)
3605 : #undef TYPED_ARRAY_SHORT_PRINT
3606 :
3607 : case PREPARSE_DATA_TYPE: {
3608 : PreparseData data = PreparseData::cast(*this);
3609 0 : os << "<PreparseData[data=" << data->data_length()
3610 0 : << " children=" << data->children_length() << "]>";
3611 : break;
3612 : }
3613 :
3614 : case UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE: {
3615 : UncompiledDataWithoutPreparseData data =
3616 : UncompiledDataWithoutPreparseData::cast(*this);
3617 0 : os << "<UncompiledDataWithoutPreparseData (" << data->start_position()
3618 0 : << ", " << data->end_position() << ")]>";
3619 : break;
3620 : }
3621 :
3622 : case UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE: {
3623 : UncompiledDataWithPreparseData data =
3624 0 : UncompiledDataWithPreparseData::cast(*this);
3625 0 : os << "<UncompiledDataWithPreparseData (" << data->start_position()
3626 0 : << ", " << data->end_position()
3627 0 : << ") preparsed=" << Brief(data->preparse_data()) << ">";
3628 : break;
3629 : }
3630 :
3631 : case SHARED_FUNCTION_INFO_TYPE: {
3632 74 : SharedFunctionInfo shared = SharedFunctionInfo::cast(*this);
3633 148 : std::unique_ptr<char[]> debug_name = shared->DebugName()->ToCString();
3634 74 : if (debug_name[0] != 0) {
3635 74 : os << "<SharedFunctionInfo " << debug_name.get() << ">";
3636 : } else {
3637 0 : os << "<SharedFunctionInfo>";
3638 : }
3639 : break;
3640 : }
3641 : case JS_MESSAGE_OBJECT_TYPE:
3642 0 : os << "<JSMessageObject>";
3643 0 : break;
3644 : #define MAKE_STRUCT_CASE(TYPE, Name, name) \
3645 : case TYPE: \
3646 : os << "<" #Name; \
3647 : Name::cast(*this)->BriefPrintDetails(os); \
3648 : os << ">"; \
3649 : break;
3650 11799 : STRUCT_LIST(MAKE_STRUCT_CASE)
3651 : #undef MAKE_STRUCT_CASE
3652 : case ALLOCATION_SITE_TYPE: {
3653 0 : os << "<AllocationSite";
3654 : AllocationSite::cast(*this)->BriefPrintDetails(os);
3655 0 : os << ">";
3656 0 : break;
3657 : }
3658 : case SCOPE_INFO_TYPE: {
3659 0 : ScopeInfo scope = ScopeInfo::cast(*this);
3660 0 : os << "<ScopeInfo";
3661 0 : if (scope->length()) os << " " << scope->scope_type() << " ";
3662 0 : os << "[" << scope->length() << "]>";
3663 : break;
3664 : }
3665 : case CODE_TYPE: {
3666 : Code code = Code::cast(*this);
3667 50 : os << "<Code " << Code::Kind2String(code->kind());
3668 50 : if (code->is_builtin()) {
3669 50 : os << " " << Builtins::name(code->builtin_index());
3670 : }
3671 50 : os << ">";
3672 : break;
3673 : }
3674 : case ODDBALL_TYPE: {
3675 20363 : if (IsUndefined()) {
3676 11103 : os << "<undefined>";
3677 9260 : } else if (IsTheHole()) {
3678 0 : os << "<the_hole>";
3679 9260 : } else if (IsNull()) {
3680 6347 : os << "<null>";
3681 2913 : } else if (IsTrue()) {
3682 129 : os << "<true>";
3683 2784 : } else if (IsFalse()) {
3684 34 : os << "<false>";
3685 : } else {
3686 2750 : os << "<Odd Oddball: ";
3687 8250 : os << Oddball::cast(*this)->to_string()->ToCString().get();
3688 2750 : os << ">";
3689 : }
3690 : break;
3691 : }
3692 : case SYMBOL_TYPE: {
3693 4303 : Symbol symbol = Symbol::cast(*this);
3694 4303 : symbol->SymbolShortPrint(os);
3695 : break;
3696 : }
3697 : case HEAP_NUMBER_TYPE: {
3698 81 : os << "<HeapNumber ";
3699 81 : HeapNumber::cast(*this)->HeapNumberPrint(os);
3700 81 : os << ">";
3701 81 : break;
3702 : }
3703 : case MUTABLE_HEAP_NUMBER_TYPE: {
3704 0 : os << "<MutableHeapNumber ";
3705 0 : MutableHeapNumber::cast(*this)->MutableHeapNumberPrint(os);
3706 : os << '>';
3707 : break;
3708 : }
3709 : case BIGINT_TYPE: {
3710 0 : os << "<BigInt ";
3711 0 : BigInt::cast(*this)->BigIntShortPrint(os);
3712 0 : os << ">";
3713 0 : break;
3714 : }
3715 : case JS_PROXY_TYPE:
3716 9 : os << "<JSProxy>";
3717 9 : break;
3718 : case FOREIGN_TYPE:
3719 0 : os << "<Foreign>";
3720 0 : break;
3721 : case CELL_TYPE: {
3722 13208 : os << "<Cell value= ";
3723 : HeapStringAllocator allocator;
3724 : StringStream accumulator(&allocator);
3725 13208 : Cell::cast(*this)->value()->ShortPrint(&accumulator);
3726 39624 : os << accumulator.ToCString().get();
3727 : os << '>';
3728 : break;
3729 : }
3730 : case PROPERTY_CELL_TYPE: {
3731 0 : PropertyCell cell = PropertyCell::cast(*this);
3732 0 : os << "<PropertyCell name=";
3733 0 : cell->name()->ShortPrint(os);
3734 0 : os << " value=";
3735 : HeapStringAllocator allocator;
3736 : StringStream accumulator(&allocator);
3737 0 : cell->value()->ShortPrint(&accumulator);
3738 0 : os << accumulator.ToCString().get();
3739 : os << '>';
3740 : break;
3741 : }
3742 : case CALL_HANDLER_INFO_TYPE: {
3743 0 : CallHandlerInfo info = CallHandlerInfo::cast(*this);
3744 0 : os << "<CallHandlerInfo ";
3745 0 : os << "callback= " << Brief(info->callback());
3746 0 : os << ", js_callback= " << Brief(info->js_callback());
3747 0 : os << ", data= " << Brief(info->data());
3748 0 : if (info->IsSideEffectFreeCallHandlerInfo()) {
3749 0 : os << ", side_effect_free= true>";
3750 : } else {
3751 0 : os << ", side_effect_free= false>";
3752 : }
3753 : break;
3754 : }
3755 : default:
3756 15867 : os << "<Other heap object (" << map()->instance_type() << ")>";
3757 15867 : break;
3758 : }
3759 : }
3760 :
3761 0 : void Struct::BriefPrintDetails(std::ostream& os) {}
3762 :
3763 409 : void Tuple2::BriefPrintDetails(std::ostream& os) {
3764 1227 : os << " " << Brief(value1()) << ", " << Brief(value2());
3765 409 : }
3766 :
3767 0 : void Tuple3::BriefPrintDetails(std::ostream& os) {
3768 0 : os << " " << Brief(value1()) << ", " << Brief(value2()) << ", "
3769 0 : << Brief(value3());
3770 0 : }
3771 :
3772 0 : void ArrayBoilerplateDescription::BriefPrintDetails(std::ostream& os) {
3773 0 : os << " " << elements_kind() << ", " << Brief(constant_elements());
3774 0 : }
3775 :
3776 0 : void CallableTask::BriefPrintDetails(std::ostream& os) {
3777 0 : os << " callable=" << Brief(callable());
3778 0 : }
3779 :
3780 13391297 : void HeapObject::Iterate(ObjectVisitor* v) { IterateFast<ObjectVisitor>(v); }
3781 :
3782 :
3783 0 : void HeapObject::IterateBody(ObjectVisitor* v) {
3784 : Map m = map();
3785 0 : IterateBodyFast<ObjectVisitor>(m, SizeFromMap(m), v);
3786 0 : }
3787 :
3788 1837909 : void HeapObject::IterateBody(Map map, int object_size, ObjectVisitor* v) {
3789 : IterateBodyFast<ObjectVisitor>(map, object_size, v);
3790 1837909 : }
3791 :
3792 :
3793 : struct CallIsValidSlot {
3794 : template <typename BodyDescriptor>
3795 0 : static bool apply(Map map, HeapObject obj, int offset, int) {
3796 0 : return BodyDescriptor::IsValidSlot(map, obj, offset);
3797 : }
3798 : };
3799 :
3800 767216 : bool HeapObject::IsValidSlot(Map map, int offset) {
3801 : DCHECK_NE(0, offset);
3802 : return BodyDescriptorApply<CallIsValidSlot, bool>(map->instance_type(), map,
3803 767216 : *this, offset, 0);
3804 : }
3805 :
3806 878167 : String JSReceiver::class_name() {
3807 878167 : ReadOnlyRoots roots = GetReadOnlyRoots();
3808 878167 : if (IsFunction()) return roots.Function_string();
3809 878162 : if (IsJSArgumentsObject()) return roots.Arguments_string();
3810 878162 : if (IsJSArray()) return roots.Array_string();
3811 874287 : if (IsJSArrayBuffer()) {
3812 0 : if (JSArrayBuffer::cast(*this)->is_shared()) {
3813 : return roots.SharedArrayBuffer_string();
3814 : }
3815 : return roots.ArrayBuffer_string();
3816 : }
3817 874287 : if (IsJSArrayIterator()) return roots.ArrayIterator_string();
3818 874287 : if (IsJSDate()) return roots.Date_string();
3819 874278 : if (IsJSError()) return roots.Error_string();
3820 874278 : if (IsJSGeneratorObject()) return roots.Generator_string();
3821 874278 : if (IsJSMap()) return roots.Map_string();
3822 874278 : if (IsJSMapIterator()) return roots.MapIterator_string();
3823 874278 : if (IsJSProxy()) {
3824 : return map()->is_callable() ? roots.Function_string()
3825 1106 : : roots.Object_string();
3826 : }
3827 873172 : if (IsJSRegExp()) return roots.RegExp_string();
3828 872758 : if (IsJSSet()) return roots.Set_string();
3829 872758 : if (IsJSSetIterator()) return roots.SetIterator_string();
3830 872758 : if (IsJSTypedArray()) {
3831 : #define SWITCH_KIND(Type, type, TYPE, ctype) \
3832 : if (map()->elements_kind() == TYPE##_ELEMENTS) { \
3833 : return roots.Type##Array_string(); \
3834 : }
3835 4266 : TYPED_ARRAYS(SWITCH_KIND)
3836 : #undef SWITCH_KIND
3837 : }
3838 872047 : if (IsJSValue()) {
3839 2645 : Object value = JSValue::cast(*this)->value();
3840 2645 : if (value->IsBoolean()) return roots.Boolean_string();
3841 1812 : if (value->IsString()) return roots.String_string();
3842 871 : if (value->IsNumber()) return roots.Number_string();
3843 10 : if (value->IsBigInt()) return roots.BigInt_string();
3844 10 : if (value->IsSymbol()) return roots.Symbol_string();
3845 0 : if (value->IsScript()) return roots.Script_string();
3846 0 : UNREACHABLE();
3847 : }
3848 869402 : if (IsJSWeakMap()) return roots.WeakMap_string();
3849 869402 : if (IsJSWeakSet()) return roots.WeakSet_string();
3850 869402 : if (IsJSGlobalProxy()) return roots.global_string();
3851 :
3852 815292 : Object maybe_constructor = map()->GetConstructor();
3853 815292 : if (maybe_constructor->IsJSFunction()) {
3854 815160 : JSFunction constructor = JSFunction::cast(maybe_constructor);
3855 815160 : if (constructor->shared()->IsApiFunction()) {
3856 3045 : maybe_constructor = constructor->shared()->get_api_func_data();
3857 : }
3858 : }
3859 :
3860 815292 : if (maybe_constructor->IsFunctionTemplateInfo()) {
3861 3046 : FunctionTemplateInfo info = FunctionTemplateInfo::cast(maybe_constructor);
3862 6115 : if (info->class_name()->IsString()) return String::cast(info->class_name());
3863 : }
3864 :
3865 : return roots.Object_string();
3866 : }
3867 :
3868 35660 : bool HeapObject::CanBeRehashed() const {
3869 : DCHECK(NeedsRehashing());
3870 35660 : switch (map()->instance_type()) {
3871 : case ORDERED_HASH_MAP_TYPE:
3872 : case ORDERED_HASH_SET_TYPE:
3873 : case ORDERED_NAME_DICTIONARY_TYPE:
3874 : // TODO(yangguo): actually support rehashing OrderedHash{Map,Set}.
3875 : return false;
3876 : case NAME_DICTIONARY_TYPE:
3877 : case GLOBAL_DICTIONARY_TYPE:
3878 : case NUMBER_DICTIONARY_TYPE:
3879 : case SIMPLE_NUMBER_DICTIONARY_TYPE:
3880 : case STRING_TABLE_TYPE:
3881 1260 : return true;
3882 : case DESCRIPTOR_ARRAY_TYPE:
3883 34390 : return true;
3884 : case TRANSITION_ARRAY_TYPE:
3885 5 : return true;
3886 : case SMALL_ORDERED_HASH_MAP_TYPE:
3887 0 : return SmallOrderedHashMap::cast(*this)->NumberOfElements() == 0;
3888 : case SMALL_ORDERED_HASH_SET_TYPE:
3889 0 : return SmallOrderedHashMap::cast(*this)->NumberOfElements() == 0;
3890 : case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
3891 0 : return SmallOrderedNameDictionary::cast(*this)->NumberOfElements() == 0;
3892 : default:
3893 : return false;
3894 : }
3895 : return false;
3896 : }
3897 :
3898 14229956 : void HeapObject::RehashBasedOnMap(Isolate* isolate) {
3899 14229956 : switch (map()->instance_type()) {
3900 : case HASH_TABLE_TYPE:
3901 0 : UNREACHABLE();
3902 : break;
3903 : case NAME_DICTIONARY_TYPE:
3904 62822 : NameDictionary::cast(*this)->Rehash(isolate);
3905 62822 : break;
3906 : case GLOBAL_DICTIONARY_TYPE:
3907 91775 : GlobalDictionary::cast(*this)->Rehash(isolate);
3908 91775 : break;
3909 : case NUMBER_DICTIONARY_TYPE:
3910 62772 : NumberDictionary::cast(*this)->Rehash(isolate);
3911 62772 : break;
3912 : case SIMPLE_NUMBER_DICTIONARY_TYPE:
3913 91775 : SimpleNumberDictionary::cast(*this)->Rehash(isolate);
3914 91775 : break;
3915 : case STRING_TABLE_TYPE:
3916 62767 : StringTable::cast(*this)->Rehash(isolate);
3917 62767 : break;
3918 : case DESCRIPTOR_ARRAY_TYPE:
3919 : DCHECK_LE(1, DescriptorArray::cast(*this)->number_of_descriptors());
3920 13858044 : DescriptorArray::cast(*this)->Sort();
3921 13858040 : break;
3922 : case TRANSITION_ARRAY_TYPE:
3923 5 : TransitionArray::cast(*this)->Sort();
3924 5 : break;
3925 : case SMALL_ORDERED_HASH_MAP_TYPE:
3926 : DCHECK_EQ(0, SmallOrderedHashMap::cast(*this)->NumberOfElements());
3927 : break;
3928 : case SMALL_ORDERED_HASH_SET_TYPE:
3929 : DCHECK_EQ(0, SmallOrderedHashSet::cast(*this)->NumberOfElements());
3930 : break;
3931 : case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
3932 : DCHECK_EQ(0, SmallOrderedNameDictionary::cast(*this)->NumberOfElements());
3933 : break;
3934 : default:
3935 : break;
3936 : }
3937 14229952 : }
3938 :
3939 : namespace {
3940 3911543 : std::pair<MaybeHandle<JSFunction>, Handle<String>> GetConstructorHelper(
3941 : Handle<JSReceiver> receiver) {
3942 : Isolate* isolate = receiver->GetIsolate();
3943 :
3944 : // If the object was instantiated simply with base == new.target, the
3945 : // constructor on the map provides the most accurate name.
3946 : // Don't provide the info for prototypes, since their constructors are
3947 : // reclaimed and replaced by Object in OptimizeAsPrototype.
3948 15645535 : if (!receiver->IsJSProxy() && receiver->map()->new_target_is_base() &&
3949 : !receiver->map()->is_prototype_map()) {
3950 3737674 : Object maybe_constructor = receiver->map()->GetConstructor();
3951 3737674 : if (maybe_constructor->IsJSFunction()) {
3952 3499024 : JSFunction constructor = JSFunction::cast(maybe_constructor);
3953 3499024 : String name = constructor->shared()->DebugName();
3954 6402828 : if (name->length() != 0 &&
3955 2903804 : !name->Equals(ReadOnlyRoots(isolate).Object_string())) {
3956 : return std::make_pair(handle(constructor, isolate),
3957 2023241 : handle(name, isolate));
3958 : }
3959 238650 : } else if (maybe_constructor->IsFunctionTemplateInfo()) {
3960 0 : FunctionTemplateInfo info = FunctionTemplateInfo::cast(maybe_constructor);
3961 0 : if (info->class_name()->IsString()) {
3962 : return std::make_pair(
3963 : MaybeHandle<JSFunction>(),
3964 0 : handle(String::cast(info->class_name()), isolate));
3965 : }
3966 : }
3967 : }
3968 :
3969 : Handle<Object> maybe_tag = JSReceiver::GetDataProperty(
3970 1888302 : receiver, isolate->factory()->to_string_tag_symbol());
3971 3776604 : if (maybe_tag->IsString())
3972 : return std::make_pair(MaybeHandle<JSFunction>(),
3973 1428846 : Handle<String>::cast(maybe_tag));
3974 :
3975 1173879 : PrototypeIterator iter(isolate, receiver);
3976 1173879 : if (iter.IsAtEnd()) {
3977 : return std::make_pair(MaybeHandle<JSFunction>(),
3978 952716 : handle(receiver->class_name(), isolate));
3979 : }
3980 :
3981 697521 : Handle<JSReceiver> start = PrototypeIterator::GetCurrent<JSReceiver>(iter);
3982 : LookupIterator it(receiver, isolate->factory()->constructor_string(), start,
3983 697521 : LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
3984 697521 : Handle<Object> maybe_constructor = JSReceiver::GetDataProperty(&it);
3985 1395042 : if (maybe_constructor->IsJSFunction()) {
3986 697521 : JSFunction constructor = JSFunction::cast(*maybe_constructor);
3987 697521 : String name = constructor->shared()->DebugName();
3988 :
3989 1341372 : if (name->length() != 0 &&
3990 643851 : !name->Equals(ReadOnlyRoots(isolate).Object_string())) {
3991 : return std::make_pair(handle(constructor, isolate),
3992 307246 : handle(name, isolate));
3993 : }
3994 : }
3995 :
3996 : return std::make_pair(MaybeHandle<JSFunction>(),
3997 780550 : handle(receiver->class_name(), isolate));
3998 : }
3999 : } // anonymous namespace
4000 :
4001 : // static
4002 143253 : MaybeHandle<JSFunction> JSReceiver::GetConstructor(
4003 : Handle<JSReceiver> receiver) {
4004 143253 : return GetConstructorHelper(receiver).first;
4005 : }
4006 :
4007 : // static
4008 3768290 : Handle<String> JSReceiver::GetConstructorName(Handle<JSReceiver> receiver) {
4009 3768290 : return GetConstructorHelper(receiver).second;
4010 : }
4011 :
4012 417970 : Handle<Context> JSReceiver::GetCreationContext() {
4013 417970 : JSReceiver receiver = *this;
4014 : // Externals are JSObjects with null as a constructor.
4015 : DCHECK(!receiver->IsExternal(GetIsolate()));
4016 417970 : Object constructor = receiver->map()->GetConstructor();
4017 417970 : JSFunction function;
4018 417970 : if (constructor->IsJSFunction()) {
4019 211589 : function = JSFunction::cast(constructor);
4020 206381 : } else if (constructor->IsFunctionTemplateInfo()) {
4021 : // Remote objects don't have a creation context.
4022 2 : return Handle<Context>::null();
4023 206379 : } else if (receiver->IsJSGeneratorObject()) {
4024 0 : function = JSGeneratorObject::cast(receiver)->function();
4025 : } else {
4026 : // Functions have null as a constructor,
4027 : // but any JSFunction knows its context immediately.
4028 206379 : CHECK(receiver->IsJSFunction());
4029 206379 : function = JSFunction::cast(receiver);
4030 : }
4031 :
4032 417968 : return function->has_context()
4033 1253904 : ? Handle<Context>(function->context()->native_context(),
4034 : receiver->GetIsolate())
4035 835936 : : Handle<Context>::null();
4036 : }
4037 :
4038 : // static
4039 7595180 : MaybeObjectHandle Map::WrapFieldType(Isolate* isolate, Handle<FieldType> type) {
4040 7595186 : if (type->IsClass()) {
4041 1494974 : return MaybeObjectHandle::Weak(type->AsClass(), isolate);
4042 : }
4043 6847697 : return MaybeObjectHandle(type);
4044 : }
4045 :
4046 : // static
4047 39420503 : FieldType Map::UnwrapFieldType(MaybeObject wrapped_type) {
4048 39420503 : if (wrapped_type->IsCleared()) {
4049 45 : return FieldType::None();
4050 : }
4051 39420458 : HeapObject heap_object;
4052 39420458 : if (wrapped_type->GetHeapObjectIfWeak(&heap_object)) {
4053 2640083 : return FieldType::cast(heap_object);
4054 : }
4055 : return wrapped_type->cast<FieldType>();
4056 : }
4057 :
4058 7292153 : MaybeHandle<Map> Map::CopyWithField(Isolate* isolate, Handle<Map> map,
4059 : Handle<Name> name, Handle<FieldType> type,
4060 : PropertyAttributes attributes,
4061 : PropertyConstness constness,
4062 : Representation representation,
4063 : TransitionFlag flag) {
4064 : DCHECK(DescriptorArray::kNotFound ==
4065 : map->instance_descriptors()->Search(
4066 : *name, map->NumberOfOwnDescriptors()));
4067 :
4068 : // Ensure the descriptor array does not get too big.
4069 7292156 : if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
4070 82 : return MaybeHandle<Map>();
4071 : }
4072 :
4073 : // Compute the new index for new field.
4074 7292075 : int index = map->NextFreePropertyIndex();
4075 :
4076 7292077 : if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
4077 : constness = PropertyConstness::kMutable;
4078 2946 : representation = Representation::Tagged();
4079 2946 : type = FieldType::Any(isolate);
4080 : } else {
4081 : Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
4082 7289127 : isolate, map->instance_type(), &constness, &representation, &type);
4083 : }
4084 :
4085 7292076 : MaybeObjectHandle wrapped_type = WrapFieldType(isolate, type);
4086 :
4087 : DCHECK_IMPLIES(!FLAG_track_constant_fields,
4088 : constness == PropertyConstness::kMutable);
4089 : Descriptor d = Descriptor::DataField(name, index, attributes, constness,
4090 7292075 : representation, wrapped_type);
4091 7292076 : Handle<Map> new_map = Map::CopyAddDescriptor(isolate, map, &d, flag);
4092 7292076 : new_map->AccountAddedPropertyField();
4093 7292075 : return new_map;
4094 : }
4095 :
4096 9768767 : MaybeHandle<Map> Map::CopyWithConstant(Isolate* isolate, Handle<Map> map,
4097 : Handle<Name> name,
4098 : Handle<Object> constant,
4099 : PropertyAttributes attributes,
4100 : TransitionFlag flag) {
4101 : // Ensure the descriptor array does not get too big.
4102 9768774 : if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
4103 14 : return MaybeHandle<Map>();
4104 : }
4105 :
4106 : if (FLAG_track_constant_fields) {
4107 : Representation representation = constant->OptimalRepresentation();
4108 : Handle<FieldType> type = constant->OptimalType(isolate, representation);
4109 : return CopyWithField(isolate, map, name, type, attributes,
4110 : PropertyConstness::kConst, representation, flag);
4111 : } else {
4112 : // Allocate new instance descriptors with (name, constant) added.
4113 : Descriptor d =
4114 9768760 : Descriptor::DataConstant(isolate, name, 0, constant, attributes);
4115 9768771 : Handle<Map> new_map = Map::CopyAddDescriptor(isolate, map, &d, flag);
4116 9768762 : return new_map;
4117 : }
4118 : }
4119 :
4120 10744 : const char* Representation::Mnemonic() const {
4121 10744 : switch (kind_) {
4122 : case kNone: return "v";
4123 1890 : case kTagged: return "t";
4124 5758 : case kSmi: return "s";
4125 508 : case kDouble: return "d";
4126 0 : case kInteger32: return "i";
4127 2588 : case kHeapObject: return "h";
4128 0 : case kExternal: return "x";
4129 : default:
4130 0 : UNREACHABLE();
4131 : }
4132 : }
4133 :
4134 0 : bool Map::TransitionRemovesTaggedField(Map target) const {
4135 0 : int inobject = NumberOfFields();
4136 0 : int target_inobject = target->NumberOfFields();
4137 0 : for (int i = target_inobject; i < inobject; i++) {
4138 0 : FieldIndex index = FieldIndex::ForPropertyIndex(*this, i);
4139 0 : if (!IsUnboxedDoubleField(index)) return true;
4140 : }
4141 : return false;
4142 : }
4143 :
4144 0 : bool Map::TransitionChangesTaggedFieldToUntaggedField(Map target) const {
4145 0 : int inobject = NumberOfFields();
4146 0 : int target_inobject = target->NumberOfFields();
4147 : int limit = Min(inobject, target_inobject);
4148 0 : for (int i = 0; i < limit; i++) {
4149 0 : FieldIndex index = FieldIndex::ForPropertyIndex(target, i);
4150 0 : if (!IsUnboxedDoubleField(index) && target->IsUnboxedDoubleField(index)) {
4151 0 : return true;
4152 : }
4153 : }
4154 : return false;
4155 : }
4156 :
4157 0 : bool Map::TransitionRequiresSynchronizationWithGC(Map target) const {
4158 0 : return TransitionRemovesTaggedField(target) ||
4159 0 : TransitionChangesTaggedFieldToUntaggedField(target);
4160 : }
4161 :
4162 80120 : bool Map::InstancesNeedRewriting(Map target) const {
4163 80120 : int target_number_of_fields = target->NumberOfFields();
4164 80121 : int target_inobject = target->GetInObjectProperties();
4165 80121 : int target_unused = target->UnusedPropertyFields();
4166 : int old_number_of_fields;
4167 :
4168 : return InstancesNeedRewriting(target, target_number_of_fields,
4169 : target_inobject, target_unused,
4170 80121 : &old_number_of_fields);
4171 : }
4172 :
4173 16914123 : bool Map::InstancesNeedRewriting(Map target, int target_number_of_fields,
4174 : int target_inobject, int target_unused,
4175 : int* old_number_of_fields) const {
4176 : // If fields were added (or removed), rewrite the instance.
4177 16914123 : *old_number_of_fields = NumberOfFields();
4178 : DCHECK(target_number_of_fields >= *old_number_of_fields);
4179 16914134 : if (target_number_of_fields != *old_number_of_fields) return true;
4180 :
4181 : // If smi descriptors were replaced by double descriptors, rewrite.
4182 15154478 : DescriptorArray old_desc = instance_descriptors();
4183 15154482 : DescriptorArray new_desc = target->instance_descriptors();
4184 : int limit = NumberOfOwnDescriptors();
4185 57316631 : for (int i = 0; i < limit; i++) {
4186 84329059 : if (new_desc->GetDetails(i).representation().IsDouble() !=
4187 84329052 : old_desc->GetDetails(i).representation().IsDouble()) {
4188 : return true;
4189 : }
4190 : }
4191 :
4192 : // If no fields were added, and no inobject properties were removed, setting
4193 : // the map is sufficient.
4194 15152095 : if (target_inobject == GetInObjectProperties()) return false;
4195 : // In-object slack tracking may have reduced the object size of the new map.
4196 : // In that case, succeed if all existing fields were inobject, and they still
4197 : // fit within the new inobject size.
4198 : DCHECK(target_inobject < GetInObjectProperties());
4199 1 : if (target_number_of_fields <= target_inobject) {
4200 : DCHECK(target_number_of_fields + target_unused == target_inobject);
4201 : return false;
4202 : }
4203 : // Otherwise, properties will need to be moved to the backing store.
4204 0 : return true;
4205 : }
4206 :
4207 :
4208 : // static
4209 4252989 : void JSObject::UpdatePrototypeUserRegistration(Handle<Map> old_map,
4210 : Handle<Map> new_map,
4211 : Isolate* isolate) {
4212 : DCHECK(old_map->is_prototype_map());
4213 : DCHECK(new_map->is_prototype_map());
4214 4252989 : bool was_registered = JSObject::UnregisterPrototypeUser(old_map, isolate);
4215 4252987 : new_map->set_prototype_info(old_map->prototype_info());
4216 4252987 : old_map->set_prototype_info(Smi::kZero);
4217 4252992 : if (FLAG_trace_prototype_users) {
4218 : PrintF("Moving prototype_info %p from map %p to map %p.\n",
4219 : reinterpret_cast<void*>(new_map->prototype_info()->ptr()),
4220 : reinterpret_cast<void*>(old_map->ptr()),
4221 0 : reinterpret_cast<void*>(new_map->ptr()));
4222 : }
4223 4252986 : if (was_registered) {
4224 384498 : if (new_map->prototype_info()->IsPrototypeInfo()) {
4225 : // The new map isn't registered with its prototype yet; reflect this fact
4226 : // in the PrototypeInfo it just inherited from the old map.
4227 : PrototypeInfo::cast(new_map->prototype_info())
4228 : ->set_registry_slot(PrototypeInfo::UNREGISTERED);
4229 : }
4230 192249 : JSObject::LazyRegisterPrototypeUser(new_map, isolate);
4231 : }
4232 4252987 : }
4233 :
4234 : namespace {
4235 : // To migrate a fast instance to a fast map:
4236 : // - First check whether the instance needs to be rewritten. If not, simply
4237 : // change the map.
4238 : // - Otherwise, allocate a fixed array large enough to hold all fields, in
4239 : // addition to unused space.
4240 : // - Copy all existing properties in, in the following order: backing store
4241 : // properties, unused fields, inobject properties.
4242 : // - If all allocation succeeded, commit the state atomically:
4243 : // * Copy inobject properties from the backing store back into the object.
4244 : // * Trim the difference in instance size of the object. This also cleanly
4245 : // frees inobject properties that moved to the backing store.
4246 : // * If there are properties left in the backing store, trim of the space used
4247 : // to temporarily store the inobject properties.
4248 : // * If there are properties left in the backing store, install the backing
4249 : // store.
4250 28856456 : void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
4251 : Isolate* isolate = object->GetIsolate();
4252 : Handle<Map> old_map(object->map(), isolate);
4253 : // In case of a regular transition.
4254 57712991 : if (new_map->GetBackPointer() == *old_map) {
4255 : // If the map does not add named properties, simply set the map.
4256 12022471 : if (old_map->NumberOfOwnDescriptors() ==
4257 : new_map->NumberOfOwnDescriptors()) {
4258 541987 : object->synchronized_set_map(*new_map);
4259 541975 : return;
4260 : }
4261 :
4262 11480490 : PropertyDetails details = new_map->GetLastDescriptorDetails();
4263 11480488 : int target_index = details.field_index() - new_map->GetInObjectProperties();
4264 22960982 : int property_array_length = object->property_array()->length();
4265 26155486 : bool have_space = old_map->UnusedPropertyFields() > 0 ||
4266 6138922 : (details.location() == kField && target_index >= 0 &&
4267 3069461 : property_array_length > target_index);
4268 : // Either new_map adds an kDescriptor property, or a kField property for
4269 : // which there is still space, and which does not require a mutable double
4270 : // box (an out-of-object double).
4271 22960980 : if (details.location() == kDescriptor ||
4272 11988181 : (have_space && ((FLAG_unbox_double_fields && target_index < 0) ||
4273 : !details.representation().IsDouble()))) {
4274 8408314 : object->synchronized_set_map(*new_map);
4275 8408307 : return;
4276 : }
4277 :
4278 : // If there is still space in the object, we need to allocate a mutable
4279 : // double box.
4280 3072182 : if (have_space) {
4281 : FieldIndex index =
4282 6000 : FieldIndex::ForDescriptor(*new_map, new_map->LastAdded());
4283 : DCHECK(details.representation().IsDouble());
4284 : DCHECK(!new_map->IsUnboxedDoubleField(index));
4285 : auto value = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
4286 6000 : object->RawFastPropertyAtPut(index, *value);
4287 3000 : object->synchronized_set_map(*new_map);
4288 : return;
4289 : }
4290 :
4291 : // This migration is a transition from a map that has run out of property
4292 : // space. Extend the backing store.
4293 3069182 : int grow_by = new_map->UnusedPropertyFields() + 1;
4294 6138364 : Handle<PropertyArray> old_storage(object->property_array(), isolate);
4295 : Handle<PropertyArray> new_storage =
4296 3069182 : isolate->factory()->CopyPropertyArrayAndGrow(old_storage, grow_by);
4297 :
4298 : // Properly initialize newly added property.
4299 : Handle<Object> value;
4300 3069182 : if (details.representation().IsDouble()) {
4301 : value = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
4302 : } else {
4303 : value = isolate->factory()->uninitialized_value();
4304 : }
4305 : DCHECK_EQ(kField, details.location());
4306 : DCHECK_EQ(kData, details.kind());
4307 : DCHECK_GE(target_index, 0); // Must be a backing store index.
4308 3069182 : new_storage->set(target_index, *value);
4309 :
4310 : // From here on we cannot fail and we shouldn't GC anymore.
4311 : DisallowHeapAllocation no_allocation;
4312 :
4313 : // Set the new property value and do the map transition.
4314 6138364 : object->SetProperties(*new_storage);
4315 3069182 : object->synchronized_set_map(*new_map);
4316 3069182 : return;
4317 : }
4318 :
4319 : int old_number_of_fields;
4320 16834005 : int number_of_fields = new_map->NumberOfFields();
4321 16834012 : int inobject = new_map->GetInObjectProperties();
4322 16834009 : int unused = new_map->UnusedPropertyFields();
4323 :
4324 : // Nothing to do if no functions were converted to fields and no smis were
4325 : // converted to doubles.
4326 16834013 : if (!old_map->InstancesNeedRewriting(*new_map, number_of_fields, inobject,
4327 16834010 : unused, &old_number_of_fields)) {
4328 15072005 : object->synchronized_set_map(*new_map);
4329 15072013 : return;
4330 : }
4331 :
4332 1762005 : int total_size = number_of_fields + unused;
4333 1762005 : int external = total_size - inobject;
4334 1762005 : Handle<PropertyArray> array = isolate->factory()->NewPropertyArray(external);
4335 :
4336 : // We use this array to temporarily store the inobject properties.
4337 : Handle<FixedArray> inobject_props =
4338 1762004 : isolate->factory()->NewFixedArray(inobject);
4339 :
4340 : Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors(),
4341 3524012 : isolate);
4342 : Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors(),
4343 3524015 : isolate);
4344 : int old_nof = old_map->NumberOfOwnDescriptors();
4345 : int new_nof = new_map->NumberOfOwnDescriptors();
4346 :
4347 : // This method only supports generalizing instances to at least the same
4348 : // number of properties.
4349 : DCHECK(old_nof <= new_nof);
4350 :
4351 55705707 : for (int i = 0; i < old_nof; i++) {
4352 53943703 : PropertyDetails details = new_descriptors->GetDetails(i);
4353 53943703 : if (details.location() != kField) continue;
4354 : DCHECK_EQ(kData, details.kind());
4355 43934923 : PropertyDetails old_details = old_descriptors->GetDetails(i);
4356 : Representation old_representation = old_details.representation();
4357 : Representation representation = details.representation();
4358 : Handle<Object> value;
4359 43934924 : if (old_details.location() == kDescriptor) {
4360 20900 : if (old_details.kind() == kAccessor) {
4361 : // In case of kAccessor -> kData property reconfiguration, the property
4362 : // must already be prepared for data of certain type.
4363 : DCHECK(!details.representation().IsNone());
4364 14843 : if (details.representation().IsDouble()) {
4365 : value = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
4366 : } else {
4367 : value = isolate->factory()->uninitialized_value();
4368 : }
4369 : } else {
4370 : DCHECK_EQ(kData, old_details.kind());
4371 12114 : value = handle(old_descriptors->GetStrongValue(i), isolate);
4372 : DCHECK(!old_representation.IsDouble() && !representation.IsDouble());
4373 : }
4374 : } else {
4375 : DCHECK_EQ(kField, old_details.location());
4376 43914023 : FieldIndex index = FieldIndex::ForDescriptor(*old_map, i);
4377 43914022 : if (object->IsUnboxedDoubleField(index)) {
4378 : uint64_t old_bits = object->RawFastDoublePropertyAsBitsAt(index);
4379 6119 : if (representation.IsDouble()) {
4380 5440 : value = isolate->factory()->NewMutableHeapNumberFromBits(old_bits);
4381 : } else {
4382 679 : value = isolate->factory()->NewHeapNumberFromBits(old_bits);
4383 : }
4384 : } else {
4385 87815805 : value = handle(object->RawFastPropertyAt(index), isolate);
4386 43907902 : if (!old_representation.IsDouble() && representation.IsDouble()) {
4387 : DCHECK_IMPLIES(old_representation.IsNone(),
4388 : value->IsUninitialized(isolate));
4389 1932 : value = Object::NewStorageFor(isolate, value, representation);
4390 43905970 : } else if (old_representation.IsDouble() &&
4391 : !representation.IsDouble()) {
4392 609 : value = Object::WrapForRead(isolate, value, old_representation);
4393 : }
4394 : }
4395 : }
4396 : DCHECK(!(representation.IsDouble() && value->IsSmi()));
4397 87869842 : int target_index = new_descriptors->GetFieldIndex(i);
4398 43934921 : if (target_index < inobject) {
4399 307044 : inobject_props->set(target_index, *value);
4400 : } else {
4401 87255757 : array->set(target_index - inobject, *value);
4402 : }
4403 : }
4404 :
4405 1738831 : for (int i = old_nof; i < new_nof; i++) {
4406 1738828 : PropertyDetails details = new_descriptors->GetDetails(i);
4407 1738828 : if (details.location() != kField) continue;
4408 : DCHECK_EQ(kData, details.kind());
4409 : Handle<Object> value;
4410 1738828 : if (details.representation().IsDouble()) {
4411 : value = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
4412 : } else {
4413 : value = isolate->factory()->uninitialized_value();
4414 : }
4415 3477660 : int target_index = new_descriptors->GetFieldIndex(i);
4416 1738830 : if (target_index < inobject) {
4417 841456 : inobject_props->set(target_index, *value);
4418 : } else {
4419 1794750 : array->set(target_index - inobject, *value);
4420 : }
4421 : }
4422 :
4423 : // From here on we cannot fail and we shouldn't GC anymore.
4424 : DisallowHeapAllocation no_allocation;
4425 :
4426 1762007 : Heap* heap = isolate->heap();
4427 :
4428 : int old_instance_size = old_map->instance_size();
4429 :
4430 1762005 : heap->NotifyObjectLayoutChange(*object, old_instance_size, no_allocation);
4431 :
4432 : // Copy (real) inobject properties. If necessary, stop at number_of_fields to
4433 : // avoid overwriting |one_pointer_filler_map|.
4434 : int limit = Min(inobject, number_of_fields);
4435 2910501 : for (int i = 0; i < limit; i++) {
4436 1148499 : FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
4437 : Object value = inobject_props->get(i);
4438 : // Can't use JSObject::FastPropertyAtPut() because proper map was not set
4439 : // yet.
4440 1148500 : if (new_map->IsUnboxedDoubleField(index)) {
4441 : DCHECK(value->IsMutableHeapNumber());
4442 : // Ensure that all bits of the double value are preserved.
4443 : object->RawFastDoublePropertyAsBitsAtPut(
4444 : index, MutableHeapNumber::cast(value)->value_as_bits());
4445 14054 : if (i < old_number_of_fields && !old_map->IsUnboxedDoubleField(index)) {
4446 : // Transition from tagged to untagged slot.
4447 : heap->ClearRecordedSlot(*object,
4448 1366 : HeapObject::RawField(*object, index.offset()));
4449 : } else {
4450 : #ifdef DEBUG
4451 : heap->VerifyClearedSlot(*object,
4452 : HeapObject::RawField(*object, index.offset()));
4453 : #endif
4454 : }
4455 : } else {
4456 1141241 : object->RawFastPropertyAtPut(index, value);
4457 : }
4458 : }
4459 :
4460 3524010 : object->SetProperties(*array);
4461 :
4462 : // Create filler object past the new instance size.
4463 : int new_instance_size = new_map->instance_size();
4464 1762005 : int instance_size_delta = old_instance_size - new_instance_size;
4465 : DCHECK_GE(instance_size_delta, 0);
4466 :
4467 1762005 : if (instance_size_delta > 0) {
4468 : Address address = object->address();
4469 : heap->CreateFillerObjectAt(address + new_instance_size, instance_size_delta,
4470 12 : ClearRecordedSlots::kYes);
4471 : }
4472 :
4473 : // We are storing the new map using release store after creating a filler for
4474 : // the left-over space to avoid races with the sweeper thread.
4475 1762004 : object->synchronized_set_map(*new_map);
4476 : }
4477 :
4478 679150 : void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map,
4479 : int expected_additional_properties) {
4480 : // The global object is always normalized.
4481 : DCHECK(!object->IsJSGlobalObject());
4482 : // JSGlobalProxy must never be normalized
4483 : DCHECK(!object->IsJSGlobalProxy());
4484 :
4485 : DCHECK_IMPLIES(new_map->is_prototype_map(),
4486 : Map::IsPrototypeChainInvalidated(*new_map));
4487 :
4488 : Isolate* isolate = object->GetIsolate();
4489 : HandleScope scope(isolate);
4490 : Handle<Map> map(object->map(), isolate);
4491 :
4492 : // Allocate new content.
4493 : int real_size = map->NumberOfOwnDescriptors();
4494 : int property_count = real_size;
4495 679152 : if (expected_additional_properties > 0) {
4496 552 : property_count += expected_additional_properties;
4497 : } else {
4498 : // Make space for two more properties.
4499 678600 : property_count += NameDictionary::kInitialCapacity;
4500 : }
4501 : Handle<NameDictionary> dictionary =
4502 679152 : NameDictionary::New(isolate, property_count);
4503 :
4504 1358302 : Handle<DescriptorArray> descs(map->instance_descriptors(), isolate);
4505 3312012 : for (int i = 0; i < real_size; i++) {
4506 2632858 : PropertyDetails details = descs->GetDetails(i);
4507 5265701 : Handle<Name> key(descs->GetKey(i), isolate);
4508 : Handle<Object> value;
4509 2632844 : if (details.location() == kField) {
4510 1838741 : FieldIndex index = FieldIndex::ForDescriptor(*map, i);
4511 1838741 : if (details.kind() == kData) {
4512 1838741 : if (object->IsUnboxedDoubleField(index)) {
4513 : double old_value = object->RawFastDoublePropertyAt(index);
4514 979 : value = isolate->factory()->NewHeapNumber(old_value);
4515 : } else {
4516 3675524 : value = handle(object->RawFastPropertyAt(index), isolate);
4517 1837762 : if (details.representation().IsDouble()) {
4518 : DCHECK(value->IsMutableHeapNumber());
4519 370 : double old_value = Handle<MutableHeapNumber>::cast(value)->value();
4520 185 : value = isolate->factory()->NewHeapNumber(old_value);
4521 : }
4522 : }
4523 : } else {
4524 : DCHECK_EQ(kAccessor, details.kind());
4525 0 : value = handle(object->RawFastPropertyAt(index), isolate);
4526 : }
4527 :
4528 : } else {
4529 : DCHECK_EQ(kDescriptor, details.location());
4530 1588206 : value = handle(descs->GetStrongValue(i), isolate);
4531 : }
4532 : DCHECK(!value.is_null());
4533 : PropertyDetails d(details.kind(), details.attributes(),
4534 : PropertyCellType::kNoCell);
4535 2632847 : dictionary = NameDictionary::Add(isolate, dictionary, key, value, d);
4536 : }
4537 :
4538 : // Copy the next enumeration index from instance descriptor.
4539 679154 : dictionary->SetNextEnumerationIndex(real_size + 1);
4540 :
4541 : // From here on we cannot fail and we shouldn't GC anymore.
4542 : DisallowHeapAllocation no_allocation;
4543 :
4544 679154 : Heap* heap = isolate->heap();
4545 : int old_instance_size = map->instance_size();
4546 679154 : heap->NotifyObjectLayoutChange(*object, old_instance_size, no_allocation);
4547 :
4548 : // Resize the object in the heap if necessary.
4549 : int new_instance_size = new_map->instance_size();
4550 679152 : int instance_size_delta = old_instance_size - new_instance_size;
4551 : DCHECK_GE(instance_size_delta, 0);
4552 :
4553 679152 : if (instance_size_delta > 0) {
4554 : heap->CreateFillerObjectAt(object->address() + new_instance_size,
4555 303823 : instance_size_delta, ClearRecordedSlots::kYes);
4556 : }
4557 :
4558 : // We are storing the new map using release store after creating a filler for
4559 : // the left-over space to avoid races with the sweeper thread.
4560 679154 : object->synchronized_set_map(*new_map);
4561 :
4562 1358307 : object->SetProperties(*dictionary);
4563 :
4564 : // Ensure that in-object space of slow-mode object does not contain random
4565 : // garbage.
4566 679153 : int inobject_properties = new_map->GetInObjectProperties();
4567 679153 : if (inobject_properties) {
4568 : Heap* heap = isolate->heap();
4569 : heap->ClearRecordedSlotRange(
4570 : object->address() + map->GetInObjectPropertyOffset(0),
4571 630442 : object->address() + new_instance_size);
4572 :
4573 1676245 : for (int i = 0; i < inobject_properties; i++) {
4574 1361026 : FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
4575 1361023 : object->RawFastPropertyAtPut(index, Smi::kZero);
4576 : }
4577 : }
4578 :
4579 679153 : isolate->counters()->props_to_dictionary()->Increment();
4580 :
4581 : #ifdef DEBUG
4582 : if (FLAG_trace_normalization) {
4583 : StdoutStream os;
4584 : os << "Object properties have been normalized:\n";
4585 : object->Print(os);
4586 : }
4587 : #endif
4588 679154 : }
4589 :
4590 : } // namespace
4591 :
4592 : // static
4593 30513497 : void JSObject::NotifyMapChange(Handle<Map> old_map, Handle<Map> new_map,
4594 : Isolate* isolate) {
4595 61027002 : if (!old_map->is_prototype_map()) return;
4596 :
4597 : InvalidatePrototypeChains(*old_map);
4598 :
4599 : // If the map was registered with its prototype before, ensure that it
4600 : // registers with its new prototype now. This preserves the invariant that
4601 : // when a map on a prototype chain is registered with its prototype, then
4602 : // all prototypes further up the chain are also registered with their
4603 : // respective prototypes.
4604 4252990 : UpdatePrototypeUserRegistration(old_map, new_map, isolate);
4605 : }
4606 :
4607 33893702 : void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
4608 : int expected_additional_properties) {
4609 67787441 : if (object->map() == *new_map) return;
4610 : Handle<Map> old_map(object->map(), object->GetIsolate());
4611 30086681 : NotifyMapChange(old_map, new_map, object->GetIsolate());
4612 :
4613 30086678 : if (old_map->is_dictionary_map()) {
4614 : // For slow-to-fast migrations JSObject::MigrateSlowToFast()
4615 : // must be used instead.
4616 551054 : CHECK(new_map->is_dictionary_map());
4617 :
4618 : // Slow-to-slow migration is trivial.
4619 551054 : object->synchronized_set_map(*new_map);
4620 29535622 : } else if (!new_map->is_dictionary_map()) {
4621 28856467 : MigrateFastToFast(object, new_map);
4622 28856485 : if (old_map->is_prototype_map()) {
4623 : DCHECK(!old_map->is_stable());
4624 : DCHECK(new_map->is_stable());
4625 : DCHECK(new_map->owns_descriptors());
4626 : DCHECK(old_map->owns_descriptors());
4627 : // Transfer ownership to the new map. Keep the descriptor pointer of the
4628 : // old map intact because the concurrent marker might be iterating the
4629 : // object with the old map.
4630 3830903 : old_map->set_owns_descriptors(false);
4631 : DCHECK(old_map->is_abandoned_prototype_map());
4632 : // Ensure that no transition was inserted for prototype migrations.
4633 : DCHECK_EQ(0, TransitionsAccessor(object->GetIsolate(), old_map)
4634 : .NumberOfTransitions());
4635 : DCHECK(new_map->GetBackPointer()->IsUndefined());
4636 : DCHECK(object->map() != *old_map);
4637 : }
4638 : } else {
4639 679150 : MigrateFastToSlow(object, new_map, expected_additional_properties);
4640 : }
4641 :
4642 : // Careful: Don't allocate here!
4643 : // For some callers of this method, |object| might be in an inconsistent
4644 : // state now: the new map might have a new elements_kind, but the object's
4645 : // elements pointer hasn't been updated yet. Callers will fix this, but in
4646 : // the meantime, (indirectly) calling JSObjectVerify() must be avoided.
4647 : // When adding code here, add a DisallowHeapAllocation too.
4648 : }
4649 :
4650 295437 : void JSObject::ForceSetPrototype(Handle<JSObject> object,
4651 : Handle<Object> proto) {
4652 : // object.__proto__ = proto;
4653 : Handle<Map> old_map = Handle<Map>(object->map(), object->GetIsolate());
4654 : Handle<Map> new_map =
4655 295437 : Map::Copy(object->GetIsolate(), old_map, "ForceSetPrototype");
4656 295437 : Map::SetPrototype(object->GetIsolate(), new_map, proto);
4657 295437 : JSObject::MigrateToMap(object, new_map);
4658 295437 : }
4659 :
4660 41579192 : int Map::NumberOfFields() const {
4661 41579192 : DescriptorArray descriptors = instance_descriptors();
4662 : int result = 0;
4663 557930364 : for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
4664 474771940 : if (descriptors->GetDetails(i).location() == kField) result++;
4665 : }
4666 41579213 : return result;
4667 : }
4668 :
4669 2602154 : Map::FieldCounts Map::GetFieldCounts() const {
4670 2602154 : DescriptorArray descriptors = instance_descriptors();
4671 : int mutable_count = 0;
4672 : int const_count = 0;
4673 151657236 : for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
4674 73226464 : PropertyDetails details = descriptors->GetDetails(i);
4675 73226464 : if (details.location() == kField) {
4676 64417405 : switch (details.constness()) {
4677 : case PropertyConstness::kMutable:
4678 64417405 : mutable_count++;
4679 64417405 : break;
4680 : case PropertyConstness::kConst:
4681 0 : const_count++;
4682 0 : break;
4683 : }
4684 : }
4685 : }
4686 2602154 : return FieldCounts(mutable_count, const_count);
4687 : }
4688 :
4689 0 : bool Map::HasOutOfObjectProperties() const {
4690 0 : return GetInObjectProperties() < NumberOfFields();
4691 : }
4692 :
4693 5756253 : void DescriptorArray::GeneralizeAllFields() {
4694 5756253 : int length = number_of_descriptors();
4695 10844245 : for (int i = 0; i < length; i++) {
4696 5087990 : PropertyDetails details = GetDetails(i);
4697 : details = details.CopyWithRepresentation(Representation::Tagged());
4698 5087990 : if (details.location() == kField) {
4699 : DCHECK_EQ(kData, details.kind());
4700 : details = details.CopyWithConstness(PropertyConstness::kMutable);
4701 472460 : SetValue(i, FieldType::Any());
4702 : }
4703 5087990 : set(ToDetailsIndex(i), MaybeObject::FromObject(details.AsSmi()));
4704 : }
4705 5756255 : }
4706 :
4707 21191 : Handle<Map> Map::CopyGeneralizeAllFields(Isolate* isolate, Handle<Map> map,
4708 : ElementsKind elements_kind,
4709 : int modify_index, PropertyKind kind,
4710 : PropertyAttributes attributes,
4711 : const char* reason) {
4712 42382 : Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
4713 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
4714 : Handle<DescriptorArray> descriptors = DescriptorArray::CopyUpTo(
4715 : isolate, old_descriptors, number_of_own_descriptors);
4716 21191 : descriptors->GeneralizeAllFields();
4717 :
4718 : Handle<LayoutDescriptor> new_layout_descriptor(
4719 : LayoutDescriptor::FastPointerLayout(), isolate);
4720 : Handle<Map> new_map = CopyReplaceDescriptors(
4721 : isolate, map, descriptors, new_layout_descriptor, OMIT_TRANSITION,
4722 21191 : MaybeHandle<Name>(), reason, SPECIAL_TRANSITION);
4723 :
4724 : // Unless the instance is being migrated, ensure that modify_index is a field.
4725 21191 : if (modify_index >= 0) {
4726 21107 : PropertyDetails details = descriptors->GetDetails(modify_index);
4727 22181 : if (details.constness() != PropertyConstness::kMutable ||
4728 22181 : details.location() != kField || details.attributes() != attributes) {
4729 : int field_index = details.location() == kField
4730 : ? details.field_index()
4731 40343 : : new_map->NumberOfFields();
4732 : Descriptor d = Descriptor::DataField(
4733 : isolate, handle(descriptors->GetKey(modify_index), isolate),
4734 40620 : field_index, attributes, Representation::Tagged());
4735 20310 : descriptors->Replace(modify_index, &d);
4736 20310 : if (details.location() != kField) {
4737 20033 : new_map->AccountAddedPropertyField();
4738 : }
4739 : } else {
4740 : DCHECK(details.attributes() == attributes);
4741 : }
4742 :
4743 21107 : if (FLAG_trace_generalization) {
4744 0 : MaybeHandle<FieldType> field_type = FieldType::None(isolate);
4745 0 : if (details.location() == kField) {
4746 : field_type = handle(
4747 0 : map->instance_descriptors()->GetFieldType(modify_index), isolate);
4748 : }
4749 : map->PrintGeneralization(
4750 : isolate, stdout, reason, modify_index,
4751 : new_map->NumberOfOwnDescriptors(), new_map->NumberOfOwnDescriptors(),
4752 : details.location() == kDescriptor, details.representation(),
4753 : Representation::Tagged(), field_type, MaybeHandle<Object>(),
4754 0 : FieldType::Any(isolate), MaybeHandle<Object>());
4755 : }
4756 : }
4757 42382 : new_map->set_elements_kind(elements_kind);
4758 21191 : return new_map;
4759 : }
4760 :
4761 47920 : void Map::DeprecateTransitionTree(Isolate* isolate) {
4762 47872 : if (is_deprecated()) return;
4763 : DisallowHeapAllocation no_gc;
4764 : TransitionsAccessor transitions(isolate, *this, &no_gc);
4765 47872 : int num_transitions = transitions.NumberOfTransitions();
4766 76594 : for (int i = 0; i < num_transitions; ++i) {
4767 28722 : transitions.GetTarget(i)->DeprecateTransitionTree(isolate);
4768 : }
4769 : DCHECK(!constructor_or_backpointer()->IsFunctionTemplateInfo());
4770 47872 : set_is_deprecated(true);
4771 47872 : if (FLAG_trace_maps) {
4772 96 : LOG(isolate, MapEvent("Deprecate", *this, Map()));
4773 : }
4774 : dependent_code()->DeoptimizeDependentCodeGroup(
4775 47872 : isolate, DependentCode::kTransitionGroup);
4776 47872 : NotifyLeafMapLayoutChange(isolate);
4777 : }
4778 :
4779 :
4780 : // Installs |new_descriptors| over the current instance_descriptors to ensure
4781 : // proper sharing of descriptor arrays.
4782 20726 : void Map::ReplaceDescriptors(Isolate* isolate, DescriptorArray new_descriptors,
4783 : LayoutDescriptor new_layout_descriptor) {
4784 : // Don't overwrite the empty descriptor array or initial map's descriptors.
4785 29011 : if (NumberOfOwnDescriptors() == 0 || GetBackPointer()->IsUndefined(isolate)) {
4786 12735 : return;
4787 : }
4788 :
4789 7991 : DescriptorArray to_replace = instance_descriptors();
4790 : // Replace descriptors by new_descriptors in all maps that share it. The old
4791 : // descriptors will not be trimmed in the mark-compactor, we need to mark
4792 : // all its elements.
4793 7991 : Map current = *this;
4794 : MarkingBarrierForDescriptorArray(isolate->heap(), current, to_replace,
4795 7991 : to_replace->number_of_descriptors());
4796 58814 : while (current->instance_descriptors() == to_replace) {
4797 43151 : Object next = current->GetBackPointer();
4798 43151 : if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map.
4799 42832 : current->SetEnumLength(kInvalidEnumCacheSentinel);
4800 : current->UpdateDescriptors(isolate, new_descriptors, new_layout_descriptor,
4801 42832 : current->NumberOfOwnDescriptors());
4802 42832 : current = Map::cast(next);
4803 : }
4804 7991 : set_owns_descriptors(false);
4805 : }
4806 :
4807 982757 : Map Map::FindRootMap(Isolate* isolate) const {
4808 982757 : Map result = *this;
4809 : while (true) {
4810 1462305 : Object back = result->GetBackPointer();
4811 1462319 : if (back->IsUndefined(isolate)) {
4812 : // Initial map always owns descriptors and doesn't have unused entries
4813 : // in the descriptor array.
4814 : DCHECK(result->owns_descriptors());
4815 : DCHECK_EQ(result->NumberOfOwnDescriptors(),
4816 : result->instance_descriptors()->number_of_descriptors());
4817 982769 : return result;
4818 : }
4819 479548 : result = Map::cast(back);
4820 479548 : }
4821 : }
4822 :
4823 401293 : Map Map::FindFieldOwner(Isolate* isolate, int descriptor) const {
4824 : DisallowHeapAllocation no_allocation;
4825 : DCHECK_EQ(kField, instance_descriptors()->GetDetails(descriptor).location());
4826 401293 : Map result = *this;
4827 : while (true) {
4828 1513238 : Object back = result->GetBackPointer();
4829 1513240 : if (back->IsUndefined(isolate)) break;
4830 : const Map parent = Map::cast(back);
4831 1513239 : if (parent->NumberOfOwnDescriptors() <= descriptor) break;
4832 1111945 : result = parent;
4833 : }
4834 1111945 : return result;
4835 : }
4836 :
4837 436762 : void Map::UpdateFieldType(Isolate* isolate, int descriptor, Handle<Name> name,
4838 : PropertyConstness new_constness,
4839 : Representation new_representation,
4840 : const MaybeObjectHandle& new_wrapped_type) {
4841 : DCHECK(new_wrapped_type->IsSmi() || new_wrapped_type->IsWeak());
4842 : // We store raw pointers in the queue, so no allocations are allowed.
4843 : DisallowHeapAllocation no_allocation;
4844 218380 : PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
4845 218382 : if (details.location() != kField) return;
4846 : DCHECK_EQ(kData, details.kind());
4847 :
4848 218382 : Zone zone(isolate->allocator(), ZONE_NAME);
4849 218379 : ZoneQueue<Map> backlog(&zone);
4850 : backlog.push(*this);
4851 :
4852 1566198 : while (!backlog.empty()) {
4853 1347817 : Map current = backlog.front();
4854 : backlog.pop();
4855 :
4856 : TransitionsAccessor transitions(isolate, current, &no_allocation);
4857 1347820 : int num_transitions = transitions.NumberOfTransitions();
4858 2477256 : for (int i = 0; i < num_transitions; ++i) {
4859 1129436 : Map target = transitions.GetTarget(i);
4860 : backlog.push(target);
4861 : }
4862 1347820 : DescriptorArray descriptors = current->instance_descriptors();
4863 1347821 : PropertyDetails details = descriptors->GetDetails(descriptor);
4864 :
4865 : // Currently constness change implies map change.
4866 : DCHECK_IMPLIES(new_constness != details.constness(),
4867 : FLAG_modify_map_inplace);
4868 :
4869 : // It is allowed to change representation here only from None to something.
4870 : DCHECK(details.representation().Equals(new_representation) ||
4871 : details.representation().IsNone());
4872 :
4873 : // Skip if already updated the shared descriptor.
4874 4043457 : if ((FLAG_modify_map_inplace && new_constness != details.constness()) ||
4875 : descriptors->GetFieldType(descriptor) != *new_wrapped_type.object()) {
4876 : DCHECK_IMPLIES(!FLAG_track_constant_fields,
4877 : new_constness == PropertyConstness::kMutable);
4878 : Descriptor d = Descriptor::DataField(
4879 : name, descriptors->GetFieldIndex(descriptor), details.attributes(),
4880 218421 : new_constness, new_representation, new_wrapped_type);
4881 218420 : descriptors->Replace(descriptor, &d);
4882 : }
4883 218381 : }
4884 : }
4885 :
4886 0 : bool FieldTypeIsCleared(Representation rep, FieldType type) {
4887 1359884 : return type->IsNone() && rep.IsHeapObject();
4888 : }
4889 :
4890 :
4891 : // static
4892 565529 : Handle<FieldType> Map::GeneralizeFieldType(Representation rep1,
4893 : Handle<FieldType> type1,
4894 : Representation rep2,
4895 : Handle<FieldType> type2,
4896 : Isolate* isolate) {
4897 : // Cleared field types need special treatment. They represent lost knowledge,
4898 : // so we must be conservative, so their generalization with any other type
4899 : // is "Any".
4900 1131054 : if (FieldTypeIsCleared(rep1, *type1) || FieldTypeIsCleared(rep2, *type2)) {
4901 5455 : return FieldType::Any(isolate);
4902 : }
4903 560087 : if (type1->NowIs(type2)) return type2;
4904 49835 : if (type2->NowIs(type1)) return type1;
4905 20260 : return FieldType::Any(isolate);
4906 : }
4907 :
4908 : // static
4909 403312 : void Map::GeneralizeField(Isolate* isolate, Handle<Map> map, int modify_index,
4910 : PropertyConstness new_constness,
4911 : Representation new_representation,
4912 : Handle<FieldType> new_field_type) {
4913 : // Check if we actually need to generalize the field type at all.
4914 806622 : Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
4915 403314 : PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
4916 : PropertyConstness old_constness = old_details.constness();
4917 : Representation old_representation = old_details.representation();
4918 : Handle<FieldType> old_field_type(old_descriptors->GetFieldType(modify_index),
4919 806630 : isolate);
4920 :
4921 : // Return if the current map is general enough to hold requested constness and
4922 : // representation/field type.
4923 581936 : if (((FLAG_modify_map_inplace &&
4924 : IsGeneralizableTo(new_constness, old_constness)) ||
4925 403318 : (!FLAG_modify_map_inplace && (old_constness == new_constness))) &&
4926 224699 : old_representation.Equals(new_representation) &&
4927 628003 : !FieldTypeIsCleared(new_representation, *new_field_type) &&
4928 : // Checking old_field_type for being cleared is not necessary because
4929 : // the NowIs check below would fail anyway in that case.
4930 852693 : new_field_type->NowIs(old_field_type)) {
4931 : DCHECK(GeneralizeFieldType(old_representation, old_field_type,
4932 : new_representation, new_field_type, isolate)
4933 : ->NowIs(old_field_type));
4934 184935 : return;
4935 : }
4936 :
4937 : // Determine the field owner.
4938 436765 : Handle<Map> field_owner(map->FindFieldOwner(isolate, modify_index), isolate);
4939 : Handle<DescriptorArray> descriptors(field_owner->instance_descriptors(),
4940 436763 : isolate);
4941 : DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index));
4942 :
4943 : new_field_type =
4944 : Map::GeneralizeFieldType(old_representation, old_field_type,
4945 218381 : new_representation, new_field_type, isolate);
4946 : if (FLAG_modify_map_inplace) {
4947 : new_constness = GeneralizeConstness(old_constness, new_constness);
4948 : }
4949 :
4950 218385 : PropertyDetails details = descriptors->GetDetails(modify_index);
4951 436765 : Handle<Name> name(descriptors->GetKey(modify_index), isolate);
4952 :
4953 218380 : MaybeObjectHandle wrapped_type(WrapFieldType(isolate, new_field_type));
4954 : field_owner->UpdateFieldType(isolate, modify_index, name, new_constness,
4955 218383 : new_representation, wrapped_type);
4956 436759 : field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
4957 218380 : isolate, DependentCode::kFieldOwnerGroup);
4958 :
4959 218379 : if (FLAG_trace_generalization) {
4960 : map->PrintGeneralization(
4961 : isolate, stdout, "field type generalization", modify_index,
4962 : map->NumberOfOwnDescriptors(), map->NumberOfOwnDescriptors(), false,
4963 : details.representation(), details.representation(), old_field_type,
4964 0 : MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>());
4965 : }
4966 : }
4967 :
4968 : // TODO(ishell): remove.
4969 : // static
4970 495 : Handle<Map> Map::ReconfigureProperty(Isolate* isolate, Handle<Map> map,
4971 : int modify_index, PropertyKind new_kind,
4972 : PropertyAttributes new_attributes,
4973 : Representation new_representation,
4974 : Handle<FieldType> new_field_type) {
4975 : DCHECK_EQ(kData, new_kind); // Only kData case is supported.
4976 495 : MapUpdater mu(isolate, map);
4977 : return mu.ReconfigureToDataField(modify_index, new_attributes,
4978 : PropertyConstness::kConst,
4979 495 : new_representation, new_field_type);
4980 : }
4981 :
4982 : // TODO(ishell): remove.
4983 : // static
4984 30 : Handle<Map> Map::ReconfigureElementsKind(Isolate* isolate, Handle<Map> map,
4985 : ElementsKind new_elements_kind) {
4986 294665 : MapUpdater mu(isolate, map);
4987 294665 : return mu.ReconfigureElementsKind(new_elements_kind);
4988 : }
4989 :
4990 : namespace {
4991 :
4992 : Map SearchMigrationTarget(Isolate* isolate, Map old_map) {
4993 : DisallowHeapAllocation no_allocation;
4994 : DisallowDeoptimization no_deoptimization(isolate);
4995 :
4996 : Map target = old_map;
4997 : do {
4998 : target = TransitionsAccessor(isolate, target, &no_allocation)
4999 : .GetMigrationTarget();
5000 : } while (!target.is_null() && target->is_deprecated());
5001 : if (target.is_null()) return Map();
5002 :
5003 : // TODO(ishell): if this validation ever become a bottleneck consider adding a
5004 : // bit to the Map telling whether it contains fields whose field types may be
5005 : // cleared.
5006 : // TODO(ishell): revisit handling of cleared field types in
5007 : // TryReplayPropertyTransitions() and consider checking the target map's field
5008 : // types instead of old_map's types.
5009 : // Go to slow map updating if the old_map has fast properties with cleared
5010 : // field types.
5011 : int old_nof = old_map->NumberOfOwnDescriptors();
5012 : DescriptorArray old_descriptors = old_map->instance_descriptors();
5013 : for (int i = 0; i < old_nof; i++) {
5014 : PropertyDetails old_details = old_descriptors->GetDetails(i);
5015 : if (old_details.location() == kField && old_details.kind() == kData) {
5016 : FieldType old_type = old_descriptors->GetFieldType(i);
5017 : if (FieldTypeIsCleared(old_details.representation(), old_type)) {
5018 : return Map();
5019 : }
5020 : }
5021 : }
5022 :
5023 : SLOW_DCHECK(Map::TryUpdateSlow(isolate, old_map) == target);
5024 : return target;
5025 : }
5026 : } // namespace
5027 :
5028 : // TODO(ishell): Move TryUpdate() and friends to MapUpdater
5029 : // static
5030 185344 : MaybeHandle<Map> Map::TryUpdate(Isolate* isolate, Handle<Map> old_map) {
5031 : DisallowHeapAllocation no_allocation;
5032 : DisallowDeoptimization no_deoptimization(isolate);
5033 :
5034 185344 : if (!old_map->is_deprecated()) return old_map;
5035 :
5036 : if (FLAG_fast_map_update) {
5037 : Map target_map = SearchMigrationTarget(isolate, *old_map);
5038 : if (!target_map.is_null()) {
5039 : return handle(target_map, isolate);
5040 : }
5041 : }
5042 :
5043 560 : Map new_map = TryUpdateSlow(isolate, *old_map);
5044 560 : if (new_map.is_null()) return MaybeHandle<Map>();
5045 : if (FLAG_fast_map_update) {
5046 : TransitionsAccessor(isolate, *old_map, &no_allocation)
5047 : .SetMigrationTarget(new_map);
5048 : }
5049 460 : return handle(new_map, isolate);
5050 : }
5051 :
5052 560 : Map Map::TryUpdateSlow(Isolate* isolate, Map old_map) {
5053 : DisallowHeapAllocation no_allocation;
5054 : DisallowDeoptimization no_deoptimization(isolate);
5055 :
5056 : // Check the state of the root map.
5057 560 : Map root_map = old_map->FindRootMap(isolate);
5058 560 : if (root_map->is_deprecated()) {
5059 0 : JSFunction constructor = JSFunction::cast(root_map->GetConstructor());
5060 : DCHECK(constructor->has_initial_map());
5061 : DCHECK(constructor->initial_map()->is_dictionary_map());
5062 0 : if (constructor->initial_map()->elements_kind() !=
5063 : old_map->elements_kind()) {
5064 0 : return Map();
5065 : }
5066 0 : return constructor->initial_map();
5067 : }
5068 560 : if (!old_map->EquivalentToForTransition(root_map)) return Map();
5069 :
5070 : ElementsKind from_kind = root_map->elements_kind();
5071 : ElementsKind to_kind = old_map->elements_kind();
5072 490 : if (from_kind != to_kind) {
5073 : // Try to follow existing elements kind transitions.
5074 21 : root_map = root_map->LookupElementsTransitionMap(isolate, to_kind);
5075 21 : if (root_map.is_null()) return Map();
5076 : // From here on, use the map with correct elements kind as root map.
5077 : }
5078 490 : return root_map->TryReplayPropertyTransitions(isolate, old_map);
5079 : }
5080 :
5081 86685 : Map Map::TryReplayPropertyTransitions(Isolate* isolate, Map old_map) {
5082 : DisallowHeapAllocation no_allocation;
5083 : DisallowDeoptimization no_deoptimization(isolate);
5084 :
5085 : int root_nof = NumberOfOwnDescriptors();
5086 :
5087 : int old_nof = old_map->NumberOfOwnDescriptors();
5088 86685 : DescriptorArray old_descriptors = old_map->instance_descriptors();
5089 :
5090 86685 : Map new_map = *this;
5091 88915 : for (int i = root_nof; i < old_nof; ++i) {
5092 8335 : PropertyDetails old_details = old_descriptors->GetDetails(i);
5093 : Map transition =
5094 : TransitionsAccessor(isolate, new_map, &no_allocation)
5095 : .SearchTransition(old_descriptors->GetKey(i), old_details.kind(),
5096 16670 : old_details.attributes());
5097 8335 : if (transition.is_null()) return Map();
5098 2291 : new_map = transition;
5099 2291 : DescriptorArray new_descriptors = new_map->instance_descriptors();
5100 :
5101 2291 : PropertyDetails new_details = new_descriptors->GetDetails(i);
5102 : DCHECK_EQ(old_details.kind(), new_details.kind());
5103 : DCHECK_EQ(old_details.attributes(), new_details.attributes());
5104 2291 : if (!IsGeneralizableTo(old_details.constness(), new_details.constness())) {
5105 0 : return Map();
5106 : }
5107 : DCHECK(IsGeneralizableTo(old_details.location(), new_details.location()));
5108 6873 : if (!old_details.representation().fits_into(new_details.representation())) {
5109 38 : return Map();
5110 : }
5111 2253 : if (new_details.location() == kField) {
5112 2119 : if (new_details.kind() == kData) {
5113 2119 : FieldType new_type = new_descriptors->GetFieldType(i);
5114 : // Cleared field types need special treatment. They represent lost
5115 : // knowledge, so we must first generalize the new_type to "Any".
5116 2119 : if (FieldTypeIsCleared(new_details.representation(), new_type)) {
5117 0 : return Map();
5118 : }
5119 : DCHECK_EQ(kData, old_details.kind());
5120 2119 : if (old_details.location() == kField) {
5121 2012 : FieldType old_type = old_descriptors->GetFieldType(i);
5122 4024 : if (FieldTypeIsCleared(old_details.representation(), old_type) ||
5123 2012 : !old_type->NowIs(new_type)) {
5124 15 : return Map();
5125 : }
5126 : } else {
5127 : DCHECK_EQ(kDescriptor, old_details.location());
5128 : DCHECK(!FLAG_track_constant_fields);
5129 107 : Object old_value = old_descriptors->GetStrongValue(i);
5130 107 : if (!new_type->NowContains(old_value)) {
5131 0 : return Map();
5132 : }
5133 : }
5134 :
5135 : } else {
5136 : DCHECK_EQ(kAccessor, new_details.kind());
5137 : #ifdef DEBUG
5138 : FieldType new_type = new_descriptors->GetFieldType(i);
5139 : DCHECK(new_type->IsAny());
5140 : #endif
5141 0 : UNREACHABLE();
5142 : }
5143 : } else {
5144 : DCHECK_EQ(kDescriptor, new_details.location());
5145 402 : if (old_details.location() == kField ||
5146 402 : old_descriptors->GetStrongValue(i) !=
5147 : new_descriptors->GetStrongValue(i)) {
5148 8 : return Map();
5149 : }
5150 : }
5151 : }
5152 80580 : if (new_map->NumberOfOwnDescriptors() != old_nof) return Map();
5153 80580 : return new_map;
5154 : }
5155 :
5156 :
5157 : // static
5158 24318456 : Handle<Map> Map::Update(Isolate* isolate, Handle<Map> map) {
5159 24318467 : if (!map->is_deprecated()) return map;
5160 : if (FLAG_fast_map_update) {
5161 : Map target_map = SearchMigrationTarget(isolate, *map);
5162 : if (!target_map.is_null()) {
5163 : return handle(target_map, isolate);
5164 : }
5165 : }
5166 2981 : MapUpdater mu(isolate, map);
5167 2981 : return mu.Update();
5168 : }
5169 :
5170 193339 : Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
5171 : ShouldThrow should_throw,
5172 : Handle<Object> value) {
5173 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
5174 : return SetPropertyWithInterceptorInternal(it, it->GetInterceptor(),
5175 193339 : should_throw, value);
5176 : }
5177 :
5178 3788744 : MaybeHandle<Object> Object::SetProperty(Isolate* isolate, Handle<Object> object,
5179 : Handle<Name> name, Handle<Object> value,
5180 : LanguageMode language_mode,
5181 : StoreOrigin store_origin) {
5182 3788744 : LookupIterator it(isolate, object, name);
5183 3788744 : MAYBE_RETURN_NULL(SetProperty(&it, value, language_mode, store_origin));
5184 3788132 : return value;
5185 : }
5186 :
5187 11674401 : Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
5188 : Handle<Object> value,
5189 : LanguageMode language_mode,
5190 : StoreOrigin store_origin, bool* found) {
5191 5627950 : it->UpdateProtector();
5192 : DCHECK(it->IsFound());
5193 : ShouldThrow should_throw =
5194 5627953 : is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
5195 :
5196 : // Make sure that the top context does not change when doing callbacks or
5197 : // interceptor calls.
5198 : AssertNoContextChange ncc(it->isolate());
5199 :
5200 272575 : do {
5201 5771593 : switch (it->state()) {
5202 : case LookupIterator::NOT_FOUND:
5203 0 : UNREACHABLE();
5204 :
5205 : case LookupIterator::ACCESS_CHECK:
5206 79721 : if (it->HasAccess()) break;
5207 : // Check whether it makes sense to reuse the lookup iterator. Here it
5208 : // might still call into setters up the prototype chain.
5209 : return JSObject::SetPropertyWithFailedAccessCheck(it, value,
5210 103 : should_throw);
5211 :
5212 : case LookupIterator::JSPROXY: {
5213 : Handle<Object> receiver = it->GetReceiver();
5214 : // In case of global IC, the receiver is the global object. Replace by
5215 : // the global proxy.
5216 105542 : if (receiver->IsJSGlobalObject()) {
5217 : receiver = handle(JSGlobalObject::cast(*receiver)->global_proxy(),
5218 234 : it->isolate());
5219 : }
5220 : return JSProxy::SetProperty(it->GetHolder<JSProxy>(), it->GetName(),
5221 105542 : value, receiver, language_mode);
5222 : }
5223 :
5224 : case LookupIterator::INTERCEPTOR: {
5225 202368 : if (it->HolderIsReceiverOrHiddenPrototype()) {
5226 : Maybe<bool> result =
5227 193127 : JSObject::SetPropertyWithInterceptor(it, should_throw, value);
5228 386254 : if (result.IsNothing() || result.FromJust()) return result;
5229 : } else {
5230 : Maybe<PropertyAttributes> maybe_attributes =
5231 9241 : JSObject::GetPropertyAttributesWithInterceptor(it);
5232 18384 : if (maybe_attributes.IsNothing()) return Nothing<bool>();
5233 9241 : if ((maybe_attributes.FromJust() & READ_ONLY) != 0) {
5234 0 : return WriteToReadOnlyProperty(it, value, should_throw);
5235 : }
5236 9241 : if (maybe_attributes.FromJust() == ABSENT) break;
5237 9143 : *found = false;
5238 : return Nothing<bool>();
5239 : }
5240 : break;
5241 : }
5242 :
5243 : case LookupIterator::ACCESSOR: {
5244 487505 : if (it->IsReadOnly()) {
5245 1485 : return WriteToReadOnlyProperty(it, value, should_throw);
5246 : }
5247 486020 : Handle<Object> accessors = it->GetAccessors();
5248 1215482 : if (accessors->IsAccessorInfo() &&
5249 606709 : !it->HolderIsReceiverOrHiddenPrototype() &&
5250 606709 : AccessorInfo::cast(*accessors)->is_special_data_property()) {
5251 451 : *found = false;
5252 : return Nothing<bool>();
5253 : }
5254 485569 : return SetPropertyWithAccessor(it, value, should_throw);
5255 : }
5256 : case LookupIterator::INTEGER_INDEXED_EXOTIC: {
5257 : // IntegerIndexedElementSet converts value to a Number/BigInt prior to
5258 : // the bounds check. The bounds check has already happened here, but
5259 : // perform the possibly effectful ToNumber (or ToBigInt) operation
5260 : // anyways.
5261 : auto holder = it->GetHolder<JSTypedArray>();
5262 : Handle<Object> throwaway_value;
5263 6498 : if (holder->type() == kExternalBigInt64Array ||
5264 4332 : holder->type() == kExternalBigUint64Array) {
5265 36 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5266 : it->isolate(), throwaway_value,
5267 : BigInt::FromObject(it->isolate(), value), Nothing<bool>());
5268 : } else {
5269 4296 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5270 : it->isolate(), throwaway_value,
5271 : Object::ToNumber(it->isolate(), value), Nothing<bool>());
5272 : }
5273 :
5274 : // FIXME: Throw a TypeError if the holder is detached here
5275 : // (IntegerIndexedElementSpec step 5).
5276 :
5277 : // TODO(verwaest): Per spec, we should return false here (steps 6-9
5278 : // in IntegerIndexedElementSpec), resulting in an exception being thrown
5279 : // on OOB accesses in strict code. Historically, v8 has not done made
5280 : // this change due to uncertainty about web compat. (v8:4901)
5281 : return Just(true);
5282 : }
5283 :
5284 : case LookupIterator::DATA:
5285 4471377 : if (it->IsReadOnly()) {
5286 26668 : return WriteToReadOnlyProperty(it, value, should_throw);
5287 : }
5288 4444709 : if (it->HolderIsReceiverOrHiddenPrototype()) {
5289 4385491 : return SetDataProperty(it, value);
5290 : }
5291 : V8_FALLTHROUGH;
5292 : case LookupIterator::TRANSITION:
5293 534895 : *found = false;
5294 : return Nothing<bool>();
5295 : }
5296 272586 : it->Next();
5297 : } while (it->IsFound());
5298 :
5299 128935 : *found = false;
5300 : return Nothing<bool>();
5301 : }
5302 :
5303 10352113 : Maybe<bool> Object::SetProperty(LookupIterator* it, Handle<Object> value,
5304 : LanguageMode language_mode,
5305 : StoreOrigin store_origin) {
5306 10350995 : if (it->IsFound()) {
5307 5571808 : bool found = true;
5308 : Maybe<bool> result =
5309 5571808 : SetPropertyInternal(it, value, language_mode, store_origin, &found);
5310 5571807 : if (found) return result;
5311 : }
5312 :
5313 : // If the receiver is the JSGlobalObject, the store was contextual. In case
5314 : // the property did not exist yet on the global object itself, we have to
5315 : // throw a reference error in strict mode. In sloppy mode, we continue.
5316 9489899 : if (is_strict(language_mode) && it->GetReceiver()->IsJSGlobalObject()) {
5317 : it->isolate()->Throw(*it->isolate()->factory()->NewReferenceError(
5318 1118 : MessageTemplate::kNotDefined, it->name()));
5319 : return Nothing<bool>();
5320 : }
5321 :
5322 : ShouldThrow should_throw =
5323 5449857 : is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
5324 5449857 : return AddDataProperty(it, value, NONE, should_throw, store_origin);
5325 : }
5326 :
5327 66122 : Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
5328 : LanguageMode language_mode,
5329 : StoreOrigin store_origin) {
5330 : Isolate* isolate = it->isolate();
5331 :
5332 60400 : if (it->IsFound()) {
5333 56145 : bool found = true;
5334 : Maybe<bool> result =
5335 56145 : SetPropertyInternal(it, value, language_mode, store_origin, &found);
5336 56145 : if (found) return result;
5337 : }
5338 :
5339 6451 : it->UpdateProtector();
5340 :
5341 : // The property either doesn't exist on the holder or exists there as a data
5342 : // property.
5343 :
5344 : ShouldThrow should_throw =
5345 6451 : is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
5346 :
5347 12902 : if (!it->GetReceiver()->IsJSReceiver()) {
5348 729 : return WriteToReadOnlyProperty(it, value, should_throw);
5349 : }
5350 5722 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
5351 :
5352 : LookupIterator::Configuration c = LookupIterator::OWN;
5353 : LookupIterator own_lookup =
5354 : it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c)
5355 11444 : : LookupIterator(isolate, receiver, it->name(), c);
5356 :
5357 36 : for (; own_lookup.IsFound(); own_lookup.Next()) {
5358 4358 : switch (own_lookup.state()) {
5359 : case LookupIterator::ACCESS_CHECK:
5360 41 : if (!own_lookup.HasAccess()) {
5361 : return JSObject::SetPropertyWithFailedAccessCheck(&own_lookup, value,
5362 5 : should_throw);
5363 : }
5364 : break;
5365 :
5366 : case LookupIterator::ACCESSOR:
5367 2943 : if (own_lookup.GetAccessors()->IsAccessorInfo()) {
5368 9 : if (own_lookup.IsReadOnly()) {
5369 0 : return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
5370 : }
5371 : return Object::SetPropertyWithAccessor(&own_lookup, value,
5372 9 : should_throw);
5373 : }
5374 : V8_FALLTHROUGH;
5375 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
5376 : return RedefineIncompatibleProperty(isolate, it->GetName(), value,
5377 1944 : should_throw);
5378 :
5379 : case LookupIterator::DATA: {
5380 981 : if (own_lookup.IsReadOnly()) {
5381 297 : return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
5382 : }
5383 684 : return SetDataProperty(&own_lookup, value);
5384 : }
5385 :
5386 : case LookupIterator::INTERCEPTOR:
5387 : case LookupIterator::JSPROXY: {
5388 : PropertyDescriptor desc;
5389 : Maybe<bool> owned =
5390 2355 : JSReceiver::GetOwnPropertyDescriptor(&own_lookup, &desc);
5391 2355 : MAYBE_RETURN(owned, Nothing<bool>());
5392 1905 : if (!owned.FromJust()) {
5393 : return JSReceiver::CreateDataProperty(&own_lookup, value,
5394 1005 : should_throw);
5395 : }
5396 1800 : if (PropertyDescriptor::IsAccessorDescriptor(&desc) ||
5397 : !desc.writable()) {
5398 : return RedefineIncompatibleProperty(isolate, it->GetName(), value,
5399 0 : should_throw);
5400 : }
5401 :
5402 : PropertyDescriptor value_desc;
5403 : value_desc.set_value(value);
5404 : return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
5405 1800 : &value_desc, should_throw);
5406 : }
5407 :
5408 : case LookupIterator::NOT_FOUND:
5409 : case LookupIterator::TRANSITION:
5410 0 : UNREACHABLE();
5411 : }
5412 : }
5413 :
5414 1400 : return AddDataProperty(&own_lookup, value, NONE, should_throw, store_origin);
5415 : }
5416 :
5417 5990 : Maybe<bool> Object::CannotCreateProperty(Isolate* isolate,
5418 : Handle<Object> receiver,
5419 : Handle<Object> name,
5420 : Handle<Object> value,
5421 : ShouldThrow should_throw) {
5422 6224 : RETURN_FAILURE(
5423 : isolate, should_throw,
5424 : NewTypeError(MessageTemplate::kStrictCannotCreateProperty, name,
5425 : Object::TypeOf(isolate, receiver), receiver));
5426 : }
5427 :
5428 :
5429 58358 : Maybe<bool> Object::WriteToReadOnlyProperty(LookupIterator* it,
5430 : Handle<Object> value,
5431 : ShouldThrow should_throw) {
5432 : return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(),
5433 58358 : it->GetName(), value, should_throw);
5434 : }
5435 :
5436 :
5437 29179 : Maybe<bool> Object::WriteToReadOnlyProperty(Isolate* isolate,
5438 : Handle<Object> receiver,
5439 : Handle<Object> name,
5440 : Handle<Object> value,
5441 : ShouldThrow should_throw) {
5442 47053 : RETURN_FAILURE(isolate, should_throw,
5443 : NewTypeError(MessageTemplate::kStrictReadOnlyProperty, name,
5444 : Object::TypeOf(isolate, receiver), receiver));
5445 : }
5446 :
5447 :
5448 981 : Maybe<bool> Object::RedefineIncompatibleProperty(Isolate* isolate,
5449 : Handle<Object> name,
5450 : Handle<Object> value,
5451 : ShouldThrow should_throw) {
5452 1215 : RETURN_FAILURE(isolate, should_throw,
5453 : NewTypeError(MessageTemplate::kRedefineDisallowed, name));
5454 : }
5455 :
5456 :
5457 9797230 : Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) {
5458 : DCHECK_IMPLIES(it->GetReceiver()->IsJSProxy(),
5459 : it->GetName()->IsPrivateName());
5460 : DCHECK_IMPLIES(!it->IsElement() && it->GetName()->IsPrivateName(),
5461 : it->state() == LookupIterator::DATA);
5462 4897620 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
5463 :
5464 : // Store on the holder which may be hidden behind the receiver.
5465 : DCHECK(it->HolderIsReceiverOrHiddenPrototype());
5466 :
5467 4897621 : Handle<Object> to_assign = value;
5468 : // Convert the incoming value to a number for storing into typed arrays.
5469 12520031 : if (it->IsElement() && receiver->IsJSObject() &&
5470 5805883 : JSObject::cast(*receiver)->HasFixedTypedArrayElements()) {
5471 700825 : ElementsKind elements_kind = JSObject::cast(*receiver)->GetElementsKind();
5472 700825 : if (elements_kind == BIGINT64_ELEMENTS ||
5473 : elements_kind == BIGUINT64_ELEMENTS) {
5474 126 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(it->isolate(), to_assign,
5475 : BigInt::FromObject(it->isolate(), value),
5476 : Nothing<bool>());
5477 : // We have to recheck the length. However, it can only change if the
5478 : // underlying buffer was detached, so just check that.
5479 126 : if (Handle<JSArrayBufferView>::cast(receiver)->WasDetached()) {
5480 : return Just(true);
5481 : // TODO(neis): According to the spec, this should throw a TypeError.
5482 : }
5483 1403630 : } else if (!value->IsNumber() && !value->IsUndefined(it->isolate())) {
5484 1746 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(it->isolate(), to_assign,
5485 : Object::ToNumber(it->isolate(), value),
5486 : Nothing<bool>());
5487 : // We have to recheck the length. However, it can only change if the
5488 : // underlying buffer was detached, so just check that.
5489 1746 : if (Handle<JSArrayBufferView>::cast(receiver)->WasDetached()) {
5490 : return Just(true);
5491 : // TODO(neis): According to the spec, this should throw a TypeError.
5492 : }
5493 : }
5494 : }
5495 :
5496 : // Possibly migrate to the most up-to-date map that will be able to store
5497 : // |value| under it->name().
5498 4897620 : it->PrepareForDataProperty(to_assign);
5499 :
5500 : // Write the property value.
5501 4897626 : it->WriteDataValue(to_assign, false);
5502 :
5503 : #if VERIFY_HEAP
5504 : if (FLAG_verify_heap) {
5505 : receiver->HeapObjectVerify(it->isolate());
5506 : }
5507 : #endif
5508 : return Just(true);
5509 : }
5510 :
5511 128786279 : Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value,
5512 : PropertyAttributes attributes,
5513 : ShouldThrow should_throw,
5514 : StoreOrigin store_origin) {
5515 79903362 : if (!it->GetReceiver()->IsJSReceiver()) {
5516 : return CannotCreateProperty(it->isolate(), it->GetReceiver(), it->GetName(),
5517 11980 : value, should_throw);
5518 : }
5519 :
5520 : // Private symbols should be installed on JSProxy using
5521 : // JSProxy::SetPrivateSymbol.
5522 119837112 : if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate() &&
5523 39945756 : !it->GetName()->IsPrivateName()) {
5524 45 : RETURN_FAILURE(it->isolate(), should_throw,
5525 : NewTypeError(MessageTemplate::kProxyPrivate));
5526 : }
5527 :
5528 : DCHECK_NE(LookupIterator::INTEGER_INDEXED_EXOTIC, it->state());
5529 :
5530 39945639 : Handle<JSReceiver> receiver = it->GetStoreTarget<JSReceiver>();
5531 : DCHECK_IMPLIES(receiver->IsJSProxy(), it->GetName()->IsPrivateName());
5532 : DCHECK_IMPLIES(receiver->IsJSProxy(),
5533 : it->state() == LookupIterator::NOT_FOUND);
5534 :
5535 : // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject)
5536 : // instead. If the prototype is Null, the proxy is detached.
5537 79891297 : if (receiver->IsJSGlobalProxy()) return Just(true);
5538 :
5539 : Isolate* isolate = it->isolate();
5540 :
5541 39945652 : if (it->ExtendingNonExtensible(receiver)) {
5542 364967 : RETURN_FAILURE(
5543 : isolate, should_throw,
5544 : NewTypeError(MessageTemplate::kObjectNotExtensible, it->GetName()));
5545 : }
5546 :
5547 39852268 : if (it->IsElement()) {
5548 12378139 : if (receiver->IsJSArray()) {
5549 2841875 : Handle<JSArray> array = Handle<JSArray>::cast(receiver);
5550 2841875 : if (JSArray::WouldChangeReadOnlyLength(array, it->index())) {
5551 1035 : RETURN_FAILURE(isolate, should_throw,
5552 : NewTypeError(MessageTemplate::kStrictReadOnlyProperty,
5553 : isolate->factory()->length_string(),
5554 : Object::TypeOf(isolate, array), array));
5555 : }
5556 :
5557 8524791 : if (FLAG_trace_external_array_abuse &&
5558 2841597 : array->HasFixedTypedArrayElements()) {
5559 0 : CheckArrayAbuse(array, "typed elements write", it->index(), true);
5560 : }
5561 :
5562 2841597 : if (FLAG_trace_js_array_abuse && !array->HasFixedTypedArrayElements()) {
5563 0 : CheckArrayAbuse(array, "elements write", it->index(), false);
5564 : }
5565 : }
5566 :
5567 6188791 : Handle<JSObject> receiver_obj = Handle<JSObject>::cast(receiver);
5568 6188793 : JSObject::AddDataElement(receiver_obj, it->index(), value, attributes);
5569 : JSObject::ValidateElements(*receiver_obj);
5570 : return Just(true);
5571 : } else {
5572 33663198 : it->UpdateProtector();
5573 : // Migrate to the most up-to-date map that will be able to store |value|
5574 : // under it->name() with |attributes|.
5575 : it->PrepareTransitionToDataProperty(receiver, value, attributes,
5576 33663214 : store_origin);
5577 : DCHECK_EQ(LookupIterator::TRANSITION, it->state());
5578 33663215 : it->ApplyTransitionToDataProperty(receiver);
5579 :
5580 : // Write the property value.
5581 33663230 : it->WriteDataValue(value, true);
5582 :
5583 : #if VERIFY_HEAP
5584 : if (FLAG_verify_heap) {
5585 : receiver->HeapObjectVerify(isolate);
5586 : }
5587 : #endif
5588 : }
5589 :
5590 : return Just(true);
5591 : }
5592 :
5593 2277170 : void Map::EnsureDescriptorSlack(Isolate* isolate, Handle<Map> map, int slack) {
5594 : // Only supports adding slack to owned descriptors.
5595 : DCHECK(map->owns_descriptors());
5596 :
5597 4554344 : Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
5598 : int old_size = map->NumberOfOwnDescriptors();
5599 2281397 : if (slack <= descriptors->number_of_slack_descriptors()) return;
5600 :
5601 : Handle<DescriptorArray> new_descriptors =
5602 : DescriptorArray::CopyUpTo(isolate, descriptors, old_size, slack);
5603 :
5604 : DisallowHeapAllocation no_allocation;
5605 : // The descriptors are still the same, so keep the layout descriptor.
5606 4554348 : LayoutDescriptor layout_descriptor = map->GetLayoutDescriptor();
5607 :
5608 2277175 : if (old_size == 0) {
5609 : map->UpdateDescriptors(isolate, *new_descriptors, layout_descriptor,
5610 4223 : map->NumberOfOwnDescriptors());
5611 4223 : return;
5612 : }
5613 :
5614 : // If the source descriptors had an enum cache we copy it. This ensures
5615 : // that the maps to which we push the new descriptor array back can rely
5616 : // on a cache always being available once it is set. If the map has more
5617 : // enumerated descriptors than available in the original cache, the cache
5618 : // will be lazily replaced by the extended cache when needed.
5619 2272951 : new_descriptors->CopyEnumCacheFrom(*descriptors);
5620 :
5621 : // Replace descriptors by new_descriptors in all maps that share it. The old
5622 : // descriptors will not be trimmed in the mark-compactor, we need to mark
5623 : // all its elements.
5624 : MarkingBarrierForDescriptorArray(isolate->heap(), *map, *descriptors,
5625 6818857 : descriptors->number_of_descriptors());
5626 :
5627 2272949 : Map current = *map;
5628 53282529 : while (current->instance_descriptors() == *descriptors) {
5629 23232519 : Object next = current->GetBackPointer();
5630 23232526 : if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map.
5631 : current->UpdateDescriptors(isolate, *new_descriptors, layout_descriptor,
5632 23231843 : current->NumberOfOwnDescriptors());
5633 23231840 : current = Map::cast(next);
5634 : }
5635 : map->UpdateDescriptors(isolate, *new_descriptors, layout_descriptor,
5636 2272954 : map->NumberOfOwnDescriptors());
5637 : }
5638 :
5639 : // static
5640 119997 : Handle<Map> Map::GetObjectCreateMap(Isolate* isolate,
5641 : Handle<HeapObject> prototype) {
5642 359991 : Handle<Map> map(isolate->native_context()->object_function()->initial_map(),
5643 239994 : isolate);
5644 119997 : if (map->prototype() == *prototype) return map;
5645 239940 : if (prototype->IsNull(isolate)) {
5646 366 : return isolate->slow_object_with_null_prototype_map();
5647 : }
5648 239208 : if (prototype->IsJSObject()) {
5649 118875 : Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype);
5650 118875 : if (!js_prototype->map()->is_prototype_map()) {
5651 116302 : JSObject::OptimizeAsPrototype(js_prototype);
5652 : }
5653 : Handle<PrototypeInfo> info =
5654 118875 : Map::GetOrCreatePrototypeInfo(js_prototype, isolate);
5655 : // TODO(verwaest): Use inobject slack tracking for this map.
5656 118875 : if (info->HasObjectCreateMap()) {
5657 200 : map = handle(info->ObjectCreateMap(), isolate);
5658 : } else {
5659 118775 : map = Map::CopyInitialMap(isolate, map);
5660 118775 : Map::SetPrototype(isolate, map, prototype);
5661 118775 : PrototypeInfo::SetObjectCreateMap(info, map);
5662 : }
5663 118875 : return map;
5664 : }
5665 :
5666 729 : return Map::TransitionToPrototype(isolate, map, prototype);
5667 : }
5668 :
5669 : // static
5670 0 : MaybeHandle<Map> Map::TryGetObjectCreateMap(Isolate* isolate,
5671 : Handle<HeapObject> prototype) {
5672 0 : Handle<Map> map(isolate->native_context()->object_function()->initial_map(),
5673 0 : isolate);
5674 0 : if (map->prototype() == *prototype) return map;
5675 0 : if (prototype->IsNull(isolate)) {
5676 0 : return isolate->slow_object_with_null_prototype_map();
5677 : }
5678 0 : if (!prototype->IsJSObject()) return MaybeHandle<Map>();
5679 0 : Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype);
5680 0 : if (!js_prototype->map()->is_prototype_map()) return MaybeHandle<Map>();
5681 : Handle<PrototypeInfo> info =
5682 0 : Map::GetOrCreatePrototypeInfo(js_prototype, isolate);
5683 0 : if (!info->HasObjectCreateMap()) return MaybeHandle<Map>();
5684 0 : return handle(info->ObjectCreateMap(), isolate);
5685 : }
5686 :
5687 : template <class T>
5688 52023 : static int AppendUniqueCallbacks(Isolate* isolate,
5689 : Handle<TemplateList> callbacks,
5690 : Handle<typename T::Array> array,
5691 : int valid_descriptors) {
5692 52023 : int nof_callbacks = callbacks->length();
5693 :
5694 : // Fill in new callback descriptors. Process the callbacks from
5695 : // back to front so that the last callback with a given name takes
5696 : // precedence over previously added callbacks with that name.
5697 104331 : for (int i = nof_callbacks - 1; i >= 0; i--) {
5698 104616 : Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)), isolate);
5699 104616 : Handle<Name> key(Name::cast(entry->name()), isolate);
5700 : DCHECK(key->IsUniqueName());
5701 : // Check if a descriptor with this name already exists before writing.
5702 52308 : if (!T::Contains(key, entry, valid_descriptors, array)) {
5703 52296 : T::Insert(key, entry, valid_descriptors, array);
5704 52296 : valid_descriptors++;
5705 : }
5706 : }
5707 :
5708 52023 : return valid_descriptors;
5709 : }
5710 :
5711 : struct FixedArrayAppender {
5712 : typedef FixedArray Array;
5713 52308 : static bool Contains(Handle<Name> key,
5714 : Handle<AccessorInfo> entry,
5715 : int valid_descriptors,
5716 : Handle<FixedArray> array) {
5717 52833 : for (int i = 0; i < valid_descriptors; i++) {
5718 1074 : if (*key == AccessorInfo::cast(array->get(i))->name()) return true;
5719 : }
5720 : return false;
5721 : }
5722 52296 : static void Insert(Handle<Name> key,
5723 : Handle<AccessorInfo> entry,
5724 : int valid_descriptors,
5725 : Handle<FixedArray> array) {
5726 : DisallowHeapAllocation no_gc;
5727 104592 : array->set(valid_descriptors, *entry);
5728 52296 : }
5729 : };
5730 :
5731 52023 : int AccessorInfo::AppendUnique(Isolate* isolate, Handle<Object> descriptors,
5732 : Handle<FixedArray> array,
5733 : int valid_descriptors) {
5734 52023 : Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors);
5735 : DCHECK_GE(array->length(), callbacks->length() + valid_descriptors);
5736 : return AppendUniqueCallbacks<FixedArrayAppender>(isolate, callbacks, array,
5737 52023 : valid_descriptors);
5738 : }
5739 :
5740 80076 : static bool ContainsMap(MapHandles const& maps, Map map) {
5741 : DCHECK(!map.is_null());
5742 234836 : for (Handle<Map> current : maps) {
5743 177193 : if (!current.is_null() && *current == map) return true;
5744 : }
5745 : return false;
5746 : }
5747 :
5748 52112 : Map Map::FindElementsKindTransitionedMap(Isolate* isolate,
5749 : MapHandles const& candidates) {
5750 : DisallowHeapAllocation no_allocation;
5751 : DisallowDeoptimization no_deoptimization(isolate);
5752 :
5753 52112 : if (is_prototype_map()) return Map();
5754 :
5755 : ElementsKind kind = elements_kind();
5756 : bool packed = IsFastPackedElementsKind(kind);
5757 :
5758 : Map transition;
5759 51544 : if (IsTransitionableFastElementsKind(kind)) {
5760 : // Check the state of the root map.
5761 26577 : Map root_map = FindRootMap(isolate);
5762 26579 : if (!EquivalentToForElementsKindTransition(root_map)) return Map();
5763 26579 : root_map = root_map->LookupElementsTransitionMap(isolate, kind);
5764 : DCHECK(!root_map.is_null());
5765 : // Starting from the next existing elements kind transition try to
5766 : // replay the property transitions that does not involve instance rewriting
5767 : // (ElementsTransitionAndStoreStub does not support that).
5768 225547 : for (root_map = root_map->ElementsTransitionMap();
5769 201040 : !root_map.is_null() && root_map->has_fast_elements();
5770 : root_map = root_map->ElementsTransitionMap()) {
5771 86196 : Map current = root_map->TryReplayPropertyTransitions(isolate, *this);
5772 86195 : if (current.is_null()) continue;
5773 80120 : if (InstancesNeedRewriting(current)) continue;
5774 :
5775 160155 : if (ContainsMap(candidates, current) &&
5776 1347 : (packed || !IsFastPackedElementsKind(current->elements_kind()))) {
5777 : transition = current;
5778 26124 : packed = packed && IsFastPackedElementsKind(current->elements_kind());
5779 : }
5780 : }
5781 : }
5782 51545 : return transition;
5783 : }
5784 :
5785 3299158 : static Map FindClosestElementsTransition(Isolate* isolate, Map map,
5786 : ElementsKind to_kind) {
5787 : // Ensure we are requested to search elements kind transition "near the root".
5788 : DCHECK_EQ(map->FindRootMap(isolate)->NumberOfOwnDescriptors(),
5789 : map->NumberOfOwnDescriptors());
5790 3299158 : Map current_map = map;
5791 :
5792 : ElementsKind kind = map->elements_kind();
5793 11118665 : while (kind != to_kind) {
5794 7988236 : Map next_map = current_map->ElementsTransitionMap();
5795 7988253 : if (next_map.is_null()) return current_map;
5796 : kind = next_map->elements_kind();
5797 7819507 : current_map = next_map;
5798 : }
5799 :
5800 : DCHECK_EQ(to_kind, current_map->elements_kind());
5801 3130429 : return current_map;
5802 : }
5803 :
5804 26598 : Map Map::LookupElementsTransitionMap(Isolate* isolate, ElementsKind to_kind) {
5805 26598 : Map to_map = FindClosestElementsTransition(isolate, *this, to_kind);
5806 26598 : if (to_map->elements_kind() == to_kind) return to_map;
5807 0 : return Map();
5808 : }
5809 :
5810 147542 : bool Map::IsMapInArrayPrototypeChain(Isolate* isolate) const {
5811 295084 : if (isolate->initial_array_prototype()->map() == *this) {
5812 : return true;
5813 : }
5814 :
5815 293838 : if (isolate->initial_object_prototype()->map() == *this) {
5816 : return true;
5817 : }
5818 :
5819 146718 : return false;
5820 : }
5821 :
5822 168746 : static Handle<Map> AddMissingElementsTransitions(Isolate* isolate,
5823 : Handle<Map> map,
5824 : ElementsKind to_kind) {
5825 : DCHECK(IsTransitionElementsKind(map->elements_kind()));
5826 :
5827 : Handle<Map> current_map = map;
5828 :
5829 : ElementsKind kind = map->elements_kind();
5830 : TransitionFlag flag;
5831 168746 : if (map->is_prototype_map()) {
5832 : flag = OMIT_TRANSITION;
5833 : } else {
5834 : flag = INSERT_TRANSITION;
5835 167456 : if (IsFastElementsKind(kind)) {
5836 342928 : while (kind != to_kind && !IsTerminalElementsKind(kind)) {
5837 5273 : kind = GetNextTransitionElementsKind(kind);
5838 5273 : current_map = Map::CopyAsElementsKind(isolate, current_map, kind, flag);
5839 : }
5840 : }
5841 : }
5842 :
5843 : // In case we are exiting the fast elements kind system, just add the map in
5844 : // the end.
5845 168746 : if (kind != to_kind) {
5846 166390 : current_map = Map::CopyAsElementsKind(isolate, current_map, to_kind, flag);
5847 : }
5848 :
5849 : DCHECK(current_map->elements_kind() == to_kind);
5850 168746 : return current_map;
5851 : }
5852 :
5853 1214981 : Handle<Map> Map::TransitionElementsTo(Isolate* isolate, Handle<Map> map,
5854 : ElementsKind to_kind) {
5855 : ElementsKind from_kind = map->elements_kind();
5856 1214982 : if (from_kind == to_kind) return map;
5857 :
5858 469351 : Context native_context = isolate->context()->native_context();
5859 469353 : if (from_kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
5860 1482 : if (*map == native_context->fast_aliased_arguments_map()) {
5861 : DCHECK_EQ(SLOW_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
5862 678 : return handle(native_context->slow_aliased_arguments_map(), isolate);
5863 : }
5864 468612 : } else if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
5865 0 : if (*map == native_context->slow_aliased_arguments_map()) {
5866 : DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
5867 0 : return handle(native_context->fast_aliased_arguments_map(), isolate);
5868 : }
5869 468612 : } else if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) {
5870 : // Reuse map transitions for JSArrays.
5871 : DisallowHeapAllocation no_gc;
5872 357341 : if (native_context->GetInitialJSArrayMap(from_kind) == *map) {
5873 : Object maybe_transitioned_map =
5874 173544 : native_context->get(Context::ArrayMapIndex(to_kind));
5875 173544 : if (maybe_transitioned_map->IsMap()) {
5876 173542 : return handle(Map::cast(maybe_transitioned_map), isolate);
5877 : }
5878 : }
5879 : }
5880 :
5881 : DCHECK(!map->IsUndefined(isolate));
5882 : // Check if we can go back in the elements kind transition chain.
5883 875163 : if (IsHoleyElementsKind(from_kind) &&
5884 0 : to_kind == GetPackedElementsKind(from_kind) &&
5885 590264 : map->GetBackPointer()->IsMap() &&
5886 295132 : Map::cast(map->GetBackPointer())->elements_kind() == to_kind) {
5887 0 : return handle(Map::cast(map->GetBackPointer()), isolate);
5888 : }
5889 :
5890 : bool allow_store_transition = IsTransitionElementsKind(from_kind);
5891 : // Only store fast element maps in ascending generality.
5892 295132 : if (IsFastElementsKind(to_kind)) {
5893 : allow_store_transition =
5894 15896 : allow_store_transition && IsTransitionableFastElementsKind(from_kind) &&
5895 5127 : IsMoreGeneralElementsKindTransition(from_kind, to_kind);
5896 : }
5897 :
5898 295132 : if (!allow_store_transition) {
5899 524 : return Map::CopyAsElementsKind(isolate, map, to_kind, OMIT_TRANSITION);
5900 : }
5901 :
5902 : return Map::ReconfigureElementsKind(isolate, map, to_kind);
5903 : }
5904 :
5905 :
5906 : // static
5907 3272567 : Handle<Map> Map::AsElementsKind(Isolate* isolate, Handle<Map> map,
5908 : ElementsKind kind) {
5909 : Handle<Map> closest_map(FindClosestElementsTransition(isolate, *map, kind),
5910 6545145 : isolate);
5911 :
5912 3272580 : if (closest_map->elements_kind() == kind) {
5913 3103834 : return closest_map;
5914 : }
5915 :
5916 168746 : return AddMissingElementsTransitions(isolate, closest_map, kind);
5917 : }
5918 :
5919 :
5920 1192594 : Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
5921 : ElementsKind to_kind) {
5922 : Handle<Map> map(object->map(), object->GetIsolate());
5923 2385191 : return Map::TransitionElementsTo(object->GetIsolate(), map, to_kind);
5924 : }
5925 :
5926 :
5927 5 : void JSProxy::Revoke(Handle<JSProxy> proxy) {
5928 : Isolate* isolate = proxy->GetIsolate();
5929 : // ES#sec-proxy-revocation-functions
5930 10 : if (!proxy->IsRevoked()) {
5931 : // 5. Set p.[[ProxyTarget]] to null.
5932 10 : proxy->set_target(ReadOnlyRoots(isolate).null_value());
5933 : // 6. Set p.[[ProxyHandler]] to null.
5934 10 : proxy->set_handler(ReadOnlyRoots(isolate).null_value());
5935 : }
5936 : DCHECK(proxy->IsRevoked());
5937 5 : }
5938 :
5939 : // static
5940 1233 : Maybe<bool> JSProxy::IsArray(Handle<JSProxy> proxy) {
5941 : Isolate* isolate = proxy->GetIsolate();
5942 1233 : Handle<JSReceiver> object = Handle<JSReceiver>::cast(proxy);
5943 922860 : for (int i = 0; i < JSProxy::kMaxIterationLimit; i++) {
5944 922851 : Handle<JSProxy> proxy = Handle<JSProxy>::cast(object);
5945 1845702 : if (proxy->IsRevoked()) {
5946 : isolate->Throw(*isolate->factory()->NewTypeError(
5947 : MessageTemplate::kProxyRevoked,
5948 324 : isolate->factory()->NewStringFromAsciiChecked("IsArray")));
5949 : return Nothing<bool>();
5950 : }
5951 1845486 : object = handle(JSReceiver::cast(proxy->target()), isolate);
5952 1845486 : if (object->IsJSArray()) return Just(true);
5953 1844748 : if (!object->IsJSProxy()) return Just(false);
5954 : }
5955 :
5956 : // Too deep recursion, throw a RangeError.
5957 9 : isolate->StackOverflow();
5958 : return Nothing<bool>();
5959 : }
5960 :
5961 52903 : Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy,
5962 : Handle<Name> name) {
5963 : DCHECK(!name->IsPrivate());
5964 52903 : STACK_CHECK(isolate, Nothing<bool>());
5965 : // 1. (Assert)
5966 : // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
5967 105788 : Handle<Object> handler(proxy->handler(), isolate);
5968 : // 3. If handler is null, throw a TypeError exception.
5969 : // 4. Assert: Type(handler) is Object.
5970 105788 : if (proxy->IsRevoked()) {
5971 : isolate->Throw(*isolate->factory()->NewTypeError(
5972 0 : MessageTemplate::kProxyRevoked, isolate->factory()->has_string()));
5973 : return Nothing<bool>();
5974 : }
5975 : // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
5976 105788 : Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
5977 : // 6. Let trap be ? GetMethod(handler, "has").
5978 : Handle<Object> trap;
5979 105788 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5980 : isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
5981 : isolate->factory()->has_string()),
5982 : Nothing<bool>());
5983 : // 7. If trap is undefined, then
5984 105788 : if (trap->IsUndefined(isolate)) {
5985 : // 7a. Return target.[[HasProperty]](P).
5986 44470 : return JSReceiver::HasProperty(target, name);
5987 : }
5988 : // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, P»)).
5989 : Handle<Object> trap_result_obj;
5990 : Handle<Object> args[] = {target, name};
5991 16848 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5992 : isolate, trap_result_obj,
5993 : Execution::Call(isolate, trap, handler, arraysize(args), args),
5994 : Nothing<bool>());
5995 8379 : bool boolean_trap_result = trap_result_obj->BooleanValue(isolate);
5996 : // 9. If booleanTrapResult is false, then:
5997 8379 : if (!boolean_trap_result) {
5998 5481 : MAYBE_RETURN(JSProxy::CheckHasTrap(isolate, name, target), Nothing<bool>());
5999 : }
6000 : // 10. Return booleanTrapResult.
6001 : return Just(boolean_trap_result);
6002 : }
6003 :
6004 5490 : Maybe<bool> JSProxy::CheckHasTrap(Isolate* isolate, Handle<Name> name,
6005 : Handle<JSReceiver> target) {
6006 : // 9a. Let targetDesc be ? target.[[GetOwnProperty]](P).
6007 : PropertyDescriptor target_desc;
6008 : Maybe<bool> target_found =
6009 5490 : JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
6010 5490 : MAYBE_RETURN(target_found, Nothing<bool>());
6011 : // 9b. If targetDesc is not undefined, then:
6012 5490 : if (target_found.FromJust()) {
6013 : // 9b i. If targetDesc.[[Configurable]] is false, throw a TypeError
6014 : // exception.
6015 9 : if (!target_desc.configurable()) {
6016 : isolate->Throw(*isolate->factory()->NewTypeError(
6017 18 : MessageTemplate::kProxyHasNonConfigurable, name));
6018 9 : return Nothing<bool>();
6019 : }
6020 : // 9b ii. Let extensibleTarget be ? IsExtensible(target).
6021 0 : Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
6022 0 : MAYBE_RETURN(extensible_target, Nothing<bool>());
6023 : // 9b iii. If extensibleTarget is false, throw a TypeError exception.
6024 0 : if (!extensible_target.FromJust()) {
6025 : isolate->Throw(*isolate->factory()->NewTypeError(
6026 0 : MessageTemplate::kProxyHasNonExtensible, name));
6027 : return Nothing<bool>();
6028 : }
6029 : }
6030 : return Just(true);
6031 : }
6032 :
6033 52771 : Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name,
6034 : Handle<Object> value, Handle<Object> receiver,
6035 : LanguageMode language_mode) {
6036 : DCHECK(!name->IsPrivate());
6037 : Isolate* isolate = proxy->GetIsolate();
6038 52771 : STACK_CHECK(isolate, Nothing<bool>());
6039 : Factory* factory = isolate->factory();
6040 : Handle<String> trap_name = factory->set_string();
6041 : ShouldThrow should_throw =
6042 52743 : is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
6043 :
6044 105486 : if (proxy->IsRevoked()) {
6045 : isolate->Throw(
6046 36 : *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
6047 : return Nothing<bool>();
6048 : }
6049 105450 : Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
6050 105450 : Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
6051 :
6052 : Handle<Object> trap;
6053 105450 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
6054 : isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
6055 104946 : if (trap->IsUndefined(isolate)) {
6056 : LookupIterator it =
6057 44421 : LookupIterator::PropertyOrElement(isolate, receiver, name, target);
6058 : return Object::SetSuperProperty(&it, value, language_mode,
6059 44421 : StoreOrigin::kMaybeKeyed);
6060 : }
6061 :
6062 : Handle<Object> trap_result;
6063 8052 : Handle<Object> args[] = {target, name, value, receiver};
6064 16104 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
6065 : isolate, trap_result,
6066 : Execution::Call(isolate, trap, handler, arraysize(args), args),
6067 : Nothing<bool>());
6068 2781 : if (!trap_result->BooleanValue(isolate)) {
6069 585 : RETURN_FAILURE(isolate, should_throw,
6070 : NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
6071 : trap_name, name));
6072 : }
6073 :
6074 : MaybeHandle<Object> result =
6075 2286 : JSProxy::CheckGetSetTrapResult(isolate, name, target, value, kSet);
6076 :
6077 2286 : if (result.is_null()) {
6078 : return Nothing<bool>();
6079 : }
6080 : return Just(true);
6081 : }
6082 :
6083 :
6084 26664 : Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy,
6085 : Handle<Name> name,
6086 : LanguageMode language_mode) {
6087 : DCHECK(!name->IsPrivate());
6088 : ShouldThrow should_throw =
6089 26664 : is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
6090 : Isolate* isolate = proxy->GetIsolate();
6091 26664 : STACK_CHECK(isolate, Nothing<bool>());
6092 : Factory* factory = isolate->factory();
6093 : Handle<String> trap_name = factory->deleteProperty_string();
6094 :
6095 53294 : if (proxy->IsRevoked()) {
6096 : isolate->Throw(
6097 36 : *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
6098 : return Nothing<bool>();
6099 : }
6100 53258 : Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
6101 53258 : Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
6102 :
6103 : Handle<Object> trap;
6104 53258 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
6105 : isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
6106 52988 : if (trap->IsUndefined(isolate)) {
6107 17973 : return JSReceiver::DeletePropertyOrElement(target, name, language_mode);
6108 : }
6109 :
6110 : Handle<Object> trap_result;
6111 : Handle<Object> args[] = {target, name};
6112 17042 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
6113 : isolate, trap_result,
6114 : Execution::Call(isolate, trap, handler, arraysize(args), args),
6115 : Nothing<bool>());
6116 1809 : if (!trap_result->BooleanValue(isolate)) {
6117 1242 : RETURN_FAILURE(isolate, should_throw,
6118 : NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
6119 : trap_name, name));
6120 : }
6121 :
6122 : // Enforce the invariant.
6123 : PropertyDescriptor target_desc;
6124 : Maybe<bool> owned =
6125 1053 : JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
6126 1053 : MAYBE_RETURN(owned, Nothing<bool>());
6127 1593 : if (owned.FromJust() && !target_desc.configurable()) {
6128 : isolate->Throw(*factory->NewTypeError(
6129 720 : MessageTemplate::kProxyDeletePropertyNonConfigurable, name));
6130 : return Nothing<bool>();
6131 : }
6132 : return Just(true);
6133 : }
6134 :
6135 :
6136 : // static
6137 17 : MaybeHandle<JSProxy> JSProxy::New(Isolate* isolate, Handle<Object> target,
6138 : Handle<Object> handler) {
6139 34 : if (!target->IsJSReceiver()) {
6140 0 : THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
6141 : JSProxy);
6142 : }
6143 34 : if (target->IsJSProxy() && JSProxy::cast(*target)->IsRevoked()) {
6144 0 : THROW_NEW_ERROR(isolate,
6145 : NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
6146 : JSProxy);
6147 : }
6148 34 : if (!handler->IsJSReceiver()) {
6149 0 : THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
6150 : JSProxy);
6151 : }
6152 34 : if (handler->IsJSProxy() && JSProxy::cast(*handler)->IsRevoked()) {
6153 0 : THROW_NEW_ERROR(isolate,
6154 : NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
6155 : JSProxy);
6156 : }
6157 : return isolate->factory()->NewJSProxy(Handle<JSReceiver>::cast(target),
6158 17 : Handle<JSReceiver>::cast(handler));
6159 : }
6160 :
6161 :
6162 : // static
6163 36 : MaybeHandle<Context> JSProxy::GetFunctionRealm(Handle<JSProxy> proxy) {
6164 : DCHECK(proxy->map()->is_constructor());
6165 72 : if (proxy->IsRevoked()) {
6166 0 : THROW_NEW_ERROR(proxy->GetIsolate(),
6167 : NewTypeError(MessageTemplate::kProxyRevoked), Context);
6168 : }
6169 : Handle<JSReceiver> target(JSReceiver::cast(proxy->target()),
6170 72 : proxy->GetIsolate());
6171 36 : return JSReceiver::GetFunctionRealm(target);
6172 : }
6173 :
6174 :
6175 : // static
6176 9 : MaybeHandle<Context> JSBoundFunction::GetFunctionRealm(
6177 : Handle<JSBoundFunction> function) {
6178 : DCHECK(function->map()->is_constructor());
6179 : return JSReceiver::GetFunctionRealm(
6180 18 : handle(function->bound_target_function(), function->GetIsolate()));
6181 : }
6182 :
6183 : // static
6184 77 : MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate,
6185 : Handle<JSBoundFunction> function) {
6186 : Handle<String> prefix = isolate->factory()->bound__string();
6187 : Handle<String> target_name = prefix;
6188 : Factory* factory = isolate->factory();
6189 : // Concatenate the "bound " up to the last non-bound target.
6190 231 : while (function->bound_target_function()->IsJSBoundFunction()) {
6191 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, target_name,
6192 : factory->NewConsString(prefix, target_name),
6193 : String);
6194 0 : function = handle(JSBoundFunction::cast(function->bound_target_function()),
6195 0 : isolate);
6196 : }
6197 154 : if (function->bound_target_function()->IsJSFunction()) {
6198 : Handle<JSFunction> target(
6199 154 : JSFunction::cast(function->bound_target_function()), isolate);
6200 77 : Handle<Object> name = JSFunction::GetName(isolate, target);
6201 154 : if (!name->IsString()) return target_name;
6202 77 : return factory->NewConsString(target_name, Handle<String>::cast(name));
6203 : }
6204 : // This will omit the proper target name for bound JSProxies.
6205 0 : return target_name;
6206 : }
6207 :
6208 : // static
6209 311 : Maybe<int> JSBoundFunction::GetLength(Isolate* isolate,
6210 : Handle<JSBoundFunction> function) {
6211 622 : int nof_bound_arguments = function->bound_arguments()->length();
6212 1689 : while (function->bound_target_function()->IsJSBoundFunction()) {
6213 756 : function = handle(JSBoundFunction::cast(function->bound_target_function()),
6214 756 : isolate);
6215 : // Make sure we never overflow {nof_bound_arguments}, the number of
6216 : // arguments of a function is strictly limited by the max length of an
6217 : // JSAarray, Smi::kMaxValue is thus a reasonably good overestimate.
6218 756 : int length = function->bound_arguments()->length();
6219 378 : if (V8_LIKELY(Smi::kMaxValue - nof_bound_arguments > length)) {
6220 378 : nof_bound_arguments += length;
6221 : } else {
6222 : nof_bound_arguments = Smi::kMaxValue;
6223 : }
6224 : }
6225 : // All non JSFunction targets get a direct property and don't use this
6226 : // accessor.
6227 622 : Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()),
6228 622 : isolate);
6229 311 : Maybe<int> target_length = JSFunction::GetLength(isolate, target);
6230 311 : if (target_length.IsNothing()) return target_length;
6231 :
6232 311 : int length = Max(0, target_length.FromJust() - nof_bound_arguments);
6233 : return Just(length);
6234 : }
6235 :
6236 : // static
6237 128882 : Handle<Object> JSFunction::GetName(Isolate* isolate,
6238 : Handle<JSFunction> function) {
6239 128882 : if (function->shared()->name_should_print_as_anonymous()) {
6240 20 : return isolate->factory()->anonymous_string();
6241 : }
6242 257724 : return handle(function->shared()->Name(), isolate);
6243 : }
6244 :
6245 : // static
6246 54229 : Maybe<int> JSFunction::GetLength(Isolate* isolate,
6247 : Handle<JSFunction> function) {
6248 : int length = 0;
6249 54229 : IsCompiledScope is_compiled_scope(function->shared()->is_compiled_scope());
6250 54229 : if (is_compiled_scope.is_compiled()) {
6251 106278 : length = function->shared()->GetLength();
6252 : } else {
6253 : // If the function isn't compiled yet, the length is not computed
6254 : // correctly yet. Compile it now and return the right length.
6255 1090 : if (Compiler::Compile(function, Compiler::KEEP_EXCEPTION,
6256 : &is_compiled_scope)) {
6257 1510 : length = function->shared()->GetLength();
6258 : }
6259 1090 : if (isolate->has_pending_exception()) return Nothing<int>();
6260 : }
6261 : DCHECK_GE(length, 0);
6262 : return Just(length);
6263 : }
6264 :
6265 : // static
6266 3387 : Handle<Context> JSFunction::GetFunctionRealm(Handle<JSFunction> function) {
6267 : DCHECK(function->map()->is_constructor());
6268 6774 : return handle(function->context()->native_context(), function->GetIsolate());
6269 : }
6270 :
6271 :
6272 : // static
6273 0 : MaybeHandle<Context> JSObject::GetFunctionRealm(Handle<JSObject> object) {
6274 : DCHECK(object->map()->is_constructor());
6275 : DCHECK(!object->IsJSFunction());
6276 0 : return object->GetCreationContext();
6277 : }
6278 :
6279 :
6280 : // static
6281 3432 : MaybeHandle<Context> JSReceiver::GetFunctionRealm(Handle<JSReceiver> receiver) {
6282 6864 : if (receiver->IsJSProxy()) {
6283 36 : return JSProxy::GetFunctionRealm(Handle<JSProxy>::cast(receiver));
6284 : }
6285 :
6286 6792 : if (receiver->IsJSFunction()) {
6287 3387 : return JSFunction::GetFunctionRealm(Handle<JSFunction>::cast(receiver));
6288 : }
6289 :
6290 18 : if (receiver->IsJSBoundFunction()) {
6291 : return JSBoundFunction::GetFunctionRealm(
6292 9 : Handle<JSBoundFunction>::cast(receiver));
6293 : }
6294 :
6295 0 : return JSObject::GetFunctionRealm(Handle<JSObject>::cast(receiver));
6296 : }
6297 :
6298 :
6299 4266 : Maybe<PropertyAttributes> JSProxy::GetPropertyAttributes(LookupIterator* it) {
6300 : PropertyDescriptor desc;
6301 : Maybe<bool> found = JSProxy::GetOwnPropertyDescriptor(
6302 4266 : it->isolate(), it->GetHolder<JSProxy>(), it->GetName(), &desc);
6303 2133 : MAYBE_RETURN(found, Nothing<PropertyAttributes>());
6304 1836 : if (!found.FromJust()) return Just(ABSENT);
6305 1629 : return Just(desc.ToAttributes());
6306 : }
6307 :
6308 :
6309 7682027 : void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
6310 : DCHECK(object->map()->GetInObjectProperties() ==
6311 : map->GetInObjectProperties());
6312 : ElementsKind obj_kind = object->map()->elements_kind();
6313 : ElementsKind map_kind = map->elements_kind();
6314 7682027 : if (map_kind != obj_kind) {
6315 : ElementsKind to_kind = GetMoreGeneralElementsKind(map_kind, obj_kind);
6316 27 : if (IsDictionaryElementsKind(obj_kind)) {
6317 : to_kind = obj_kind;
6318 : }
6319 27 : if (IsDictionaryElementsKind(to_kind)) {
6320 27 : NormalizeElements(object);
6321 : } else {
6322 0 : TransitionElementsKind(object, to_kind);
6323 : }
6324 : map = Map::ReconfigureElementsKind(object->GetIsolate(), map, to_kind);
6325 : }
6326 7682027 : int number_of_fields = map->NumberOfFields();
6327 7682027 : int inobject = map->GetInObjectProperties();
6328 7682027 : int unused = map->UnusedPropertyFields();
6329 7682027 : int total_size = number_of_fields + unused;
6330 7682027 : int external = total_size - inobject;
6331 : // Allocate mutable double boxes if necessary. It is always necessary if we
6332 : // have external properties, but is also necessary if we only have inobject
6333 : // properties but don't unbox double fields.
6334 7682027 : if (!FLAG_unbox_double_fields || external > 0) {
6335 : Isolate* isolate = object->GetIsolate();
6336 :
6337 5819504 : Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
6338 : Handle<FixedArray> storage;
6339 : if (!FLAG_unbox_double_fields) {
6340 : storage = isolate->factory()->NewFixedArray(inobject);
6341 : }
6342 :
6343 : Handle<PropertyArray> array =
6344 2909752 : isolate->factory()->NewPropertyArray(external);
6345 :
6346 41507480 : for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
6347 17843988 : PropertyDetails details = descriptors->GetDetails(i);
6348 : Representation representation = details.representation();
6349 35687868 : if (!representation.IsDouble()) continue;
6350 6096 : FieldIndex index = FieldIndex::ForDescriptor(*map, i);
6351 6096 : if (map->IsUnboxedDoubleField(index)) continue;
6352 : auto box = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
6353 108 : if (index.is_inobject()) {
6354 0 : storage->set(index.property_index(), *box);
6355 : } else {
6356 216 : array->set(index.outobject_array_index(), *box);
6357 : }
6358 : }
6359 :
6360 5819504 : object->SetProperties(*array);
6361 :
6362 : if (!FLAG_unbox_double_fields) {
6363 : for (int i = 0; i < inobject; i++) {
6364 : FieldIndex index = FieldIndex::ForPropertyIndex(*map, i);
6365 : Object value = storage->get(i);
6366 : object->RawFastPropertyAtPut(index, value);
6367 : }
6368 : }
6369 : }
6370 7682027 : object->synchronized_set_map(*map);
6371 7682027 : }
6372 :
6373 :
6374 2457 : void JSObject::MigrateInstance(Handle<JSObject> object) {
6375 : Handle<Map> original_map(object->map(), object->GetIsolate());
6376 2457 : Handle<Map> map = Map::Update(object->GetIsolate(), original_map);
6377 2457 : map->set_is_migration_target(true);
6378 2457 : MigrateToMap(object, map);
6379 2457 : if (FLAG_trace_migration) {
6380 0 : object->PrintInstanceMigration(stdout, *original_map, *map);
6381 : }
6382 : #if VERIFY_HEAP
6383 : if (FLAG_verify_heap) {
6384 : object->JSObjectVerify(object->GetIsolate());
6385 : }
6386 : #endif
6387 2457 : }
6388 :
6389 :
6390 : // static
6391 6858 : bool JSObject::TryMigrateInstance(Handle<JSObject> object) {
6392 : Isolate* isolate = object->GetIsolate();
6393 : DisallowDeoptimization no_deoptimization(isolate);
6394 : Handle<Map> original_map(object->map(), isolate);
6395 : Handle<Map> new_map;
6396 13716 : if (!Map::TryUpdate(isolate, original_map).ToHandle(&new_map)) {
6397 : return false;
6398 : }
6399 6842 : JSObject::MigrateToMap(object, new_map);
6400 6842 : if (FLAG_trace_migration && *original_map != object->map()) {
6401 0 : object->PrintInstanceMigration(stdout, *original_map, object->map());
6402 : }
6403 : #if VERIFY_HEAP
6404 : if (FLAG_verify_heap) {
6405 : object->JSObjectVerify(isolate);
6406 : }
6407 : #endif
6408 : return true;
6409 : }
6410 :
6411 20246593 : void JSObject::AddProperty(Isolate* isolate, Handle<JSObject> object,
6412 : Handle<Name> name, Handle<Object> value,
6413 : PropertyAttributes attributes) {
6414 : LookupIterator it(isolate, object, name, object,
6415 20246593 : LookupIterator::OWN_SKIP_INTERCEPTOR);
6416 20246588 : CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
6417 : #ifdef DEBUG
6418 : uint32_t index;
6419 : DCHECK(!object->IsJSProxy());
6420 : DCHECK(!name->AsArrayIndex(&index));
6421 : Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
6422 : DCHECK(maybe.IsJust());
6423 : DCHECK(!it.IsFound());
6424 : DCHECK(object->map()->is_extensible() || name->IsPrivate());
6425 : #endif
6426 20246588 : CHECK(Object::AddDataProperty(&it, value, attributes, kThrowOnError,
6427 : StoreOrigin::kNamed)
6428 : .IsJust());
6429 20246585 : }
6430 :
6431 185521 : void JSObject::AddProperty(Isolate* isolate, Handle<JSObject> object,
6432 : const char* name, Handle<Object> value,
6433 : PropertyAttributes attributes) {
6434 : JSObject::AddProperty(isolate, object,
6435 : isolate->factory()->InternalizeUtf8String(name), value,
6436 371042 : attributes);
6437 185521 : }
6438 :
6439 : // Reconfigures a property to a data property with attributes, even if it is not
6440 : // reconfigurable.
6441 : // Requires a LookupIterator that does not look at the prototype chain beyond
6442 : // hidden prototypes.
6443 11682438 : MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes(
6444 : LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
6445 : AccessorInfoHandling handling) {
6446 11682438 : MAYBE_RETURN_NULL(DefineOwnPropertyIgnoreAttributes(it, value, attributes,
6447 : kThrowOnError, handling));
6448 11682435 : return value;
6449 : }
6450 :
6451 :
6452 12009159 : Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
6453 12031186 : LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
6454 : ShouldThrow should_throw, AccessorInfoHandling handling) {
6455 12009159 : it->UpdateProtector();
6456 12009190 : Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
6457 :
6458 24019602 : for (; it->IsFound(); it->Next()) {
6459 538865 : switch (it->state()) {
6460 : case LookupIterator::JSPROXY:
6461 : case LookupIterator::NOT_FOUND:
6462 : case LookupIterator::TRANSITION:
6463 0 : UNREACHABLE();
6464 :
6465 : case LookupIterator::ACCESS_CHECK:
6466 412 : if (!it->HasAccess()) {
6467 0 : it->isolate()->ReportFailedAccessCheck(it->GetHolder<JSObject>());
6468 0 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
6469 : return Just(true);
6470 : }
6471 : break;
6472 :
6473 : // If there's an interceptor, try to store the property with the
6474 : // interceptor.
6475 : // In case of success, the attributes will have been reset to the default
6476 : // attributes of the interceptor, rather than the incoming attributes.
6477 : //
6478 : // TODO(verwaest): JSProxy afterwards verify the attributes that the
6479 : // JSProxy claims it has, and verifies that they are compatible. If not,
6480 : // they throw. Here we should do the same.
6481 : case LookupIterator::INTERCEPTOR:
6482 212 : if (handling == DONT_FORCE_FIELD) {
6483 : Maybe<bool> result =
6484 212 : JSObject::SetPropertyWithInterceptor(it, should_throw, value);
6485 424 : if (result.IsNothing() || result.FromJust()) return result;
6486 : }
6487 : break;
6488 :
6489 : case LookupIterator::ACCESSOR: {
6490 5420 : Handle<Object> accessors = it->GetAccessors();
6491 :
6492 : // Special handling for AccessorInfo, which behaves like a data
6493 : // property.
6494 10840 : if (accessors->IsAccessorInfo() && handling == DONT_FORCE_FIELD) {
6495 : PropertyAttributes current_attributes = it->property_attributes();
6496 : // Ensure the context isn't changed after calling into accessors.
6497 : AssertNoContextChange ncc(it->isolate());
6498 :
6499 : // Update the attributes before calling the setter. The setter may
6500 : // later change the shape of the property.
6501 4812 : if (current_attributes != attributes) {
6502 1165 : it->TransitionToAccessorPair(accessors, attributes);
6503 : }
6504 :
6505 4812 : return Object::SetPropertyWithAccessor(it, value, should_throw);
6506 : }
6507 :
6508 608 : it->ReconfigureDataProperty(value, attributes);
6509 : return Just(true);
6510 : }
6511 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
6512 : return Object::RedefineIncompatibleProperty(
6513 18 : it->isolate(), it->GetName(), value, should_throw);
6514 :
6515 : case LookupIterator::DATA: {
6516 : // Regular property update if the attributes match.
6517 532812 : if (it->property_attributes() == attributes) {
6518 511435 : return Object::SetDataProperty(it, value);
6519 : }
6520 :
6521 : // Special case: properties of typed arrays cannot be reconfigured to
6522 : // non-writable nor to non-enumerable.
6523 40732 : if (it->IsElement() && object->HasFixedTypedArrayElements()) {
6524 : return Object::RedefineIncompatibleProperty(
6525 0 : it->isolate(), it->GetName(), value, should_throw);
6526 : }
6527 :
6528 : // Reconfigure the data property if the attributes mismatch.
6529 21377 : it->ReconfigureDataProperty(value, attributes);
6530 :
6531 : return Just(true);
6532 : }
6533 : }
6534 : }
6535 :
6536 : return Object::AddDataProperty(it, value, attributes, should_throw,
6537 11470935 : StoreOrigin::kNamed);
6538 : }
6539 :
6540 3965094 : MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
6541 : Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
6542 : PropertyAttributes attributes) {
6543 : DCHECK(!value->IsTheHole());
6544 3965094 : LookupIterator it(object, name, object, LookupIterator::OWN);
6545 3965096 : return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
6546 : }
6547 :
6548 2475634 : MaybeHandle<Object> JSObject::SetOwnElementIgnoreAttributes(
6549 : Handle<JSObject> object, uint32_t index, Handle<Object> value,
6550 : PropertyAttributes attributes) {
6551 : Isolate* isolate = object->GetIsolate();
6552 : LookupIterator it(isolate, object, index, object, LookupIterator::OWN);
6553 2475634 : return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
6554 : }
6555 :
6556 432276 : MaybeHandle<Object> JSObject::DefinePropertyOrElementIgnoreAttributes(
6557 : Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
6558 : PropertyAttributes attributes) {
6559 : Isolate* isolate = object->GetIsolate();
6560 : LookupIterator it = LookupIterator::PropertyOrElement(
6561 432276 : isolate, object, name, object, LookupIterator::OWN);
6562 432276 : return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
6563 : }
6564 :
6565 250398 : Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
6566 : LookupIterator* it) {
6567 250398 : return GetPropertyAttributesWithInterceptorInternal(it, it->GetInterceptor());
6568 : }
6569 :
6570 16666550 : Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
6571 18950932 : LookupIterator* it) {
6572 37901864 : for (; it->IsFound(); it->Next()) {
6573 12130427 : switch (it->state()) {
6574 : case LookupIterator::NOT_FOUND:
6575 : case LookupIterator::TRANSITION:
6576 0 : UNREACHABLE();
6577 : case LookupIterator::JSPROXY:
6578 909 : return JSProxy::GetPropertyAttributes(it);
6579 : case LookupIterator::INTERCEPTOR: {
6580 : Maybe<PropertyAttributes> result =
6581 682 : JSObject::GetPropertyAttributesWithInterceptor(it);
6582 1041 : if (result.IsNothing()) return result;
6583 682 : if (result.FromJust() != ABSENT) return result;
6584 323 : break;
6585 : }
6586 : case LookupIterator::ACCESS_CHECK:
6587 2284140 : if (it->HasAccess()) break;
6588 81 : return JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
6589 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
6590 : return Just(ABSENT);
6591 : case LookupIterator::ACCESSOR:
6592 430398 : if (it->GetHolder<Object>()->IsJSModuleNamespace()) {
6593 792 : return JSModuleNamespace::GetPropertyAttributes(it);
6594 : } else {
6595 : return Just(it->property_attributes());
6596 : }
6597 : case LookupIterator::DATA:
6598 : return Just(it->property_attributes());
6599 : }
6600 : }
6601 : return Just(ABSENT);
6602 : }
6603 :
6604 :
6605 111 : Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) {
6606 : Handle<WeakFixedArray> array(
6607 111 : isolate->factory()->NewWeakFixedArray(kEntries, TENURED));
6608 111 : return Handle<NormalizedMapCache>::cast(array);
6609 : }
6610 :
6611 :
6612 596975 : MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map,
6613 : PropertyNormalizationMode mode) {
6614 : DisallowHeapAllocation no_gc;
6615 596975 : MaybeObject value = WeakFixedArray::Get(GetIndex(fast_map));
6616 596975 : HeapObject heap_object;
6617 596975 : if (!value->GetHeapObjectIfWeak(&heap_object)) {
6618 69680 : return MaybeHandle<Map>();
6619 : }
6620 :
6621 527295 : Map normalized_map = Map::cast(heap_object);
6622 527295 : if (!normalized_map->EquivalentToForNormalization(*fast_map, mode)) {
6623 92193 : return MaybeHandle<Map>();
6624 : }
6625 435102 : return handle(normalized_map, GetIsolate());
6626 : }
6627 :
6628 161873 : void NormalizedMapCache::Set(Handle<Map> fast_map, Handle<Map> normalized_map) {
6629 : DisallowHeapAllocation no_gc;
6630 : DCHECK(normalized_map->is_dictionary_map());
6631 : WeakFixedArray::Set(GetIndex(fast_map),
6632 161873 : HeapObjectReference::Weak(*normalized_map));
6633 161873 : }
6634 :
6635 676519 : void JSObject::NormalizeProperties(Handle<JSObject> object,
6636 : PropertyNormalizationMode mode,
6637 : int expected_additional_properties,
6638 : const char* reason) {
6639 930376 : if (!object->HasFastProperties()) return;
6640 :
6641 : Handle<Map> map(object->map(), object->GetIsolate());
6642 422666 : Handle<Map> new_map = Map::Normalize(object->GetIsolate(), map, mode, reason);
6643 :
6644 422666 : MigrateToMap(object, new_map, expected_additional_properties);
6645 : }
6646 :
6647 :
6648 1125395 : void JSObject::MigrateSlowToFast(Handle<JSObject> object,
6649 : int unused_property_fields,
6650 : const char* reason) {
6651 1979601 : if (object->HasFastProperties()) return;
6652 : DCHECK(!object->IsJSGlobalObject());
6653 409 : Isolate* isolate = object->GetIsolate();
6654 : Factory* factory = isolate->factory();
6655 671085 : Handle<NameDictionary> dictionary(object->property_dictionary(), isolate);
6656 :
6657 : // Make sure we preserve dictionary representation if there are too many
6658 : // descriptors.
6659 335541 : int number_of_elements = dictionary->NumberOfElements();
6660 335542 : if (number_of_elements > kMaxNumberOfDescriptors) return;
6661 :
6662 : Handle<FixedArray> iteration_order =
6663 334947 : NameDictionary::IterationIndices(isolate, dictionary);
6664 :
6665 : int instance_descriptor_length = iteration_order->length();
6666 : int number_of_fields = 0;
6667 :
6668 : // Compute the length of the instance descriptor.
6669 : ReadOnlyRoots roots(isolate);
6670 2014277 : for (int i = 0; i < instance_descriptor_length; i++) {
6671 1679329 : int index = Smi::ToInt(iteration_order->get(i));
6672 : DCHECK(dictionary->IsKey(roots, dictionary->KeyAt(index)));
6673 :
6674 3358662 : PropertyKind kind = dictionary->DetailsAt(index).kind();
6675 1679332 : if (kind == kData) {
6676 : if (FLAG_track_constant_fields) {
6677 : number_of_fields += 1;
6678 : } else {
6679 1270218 : Object value = dictionary->ValueAt(index);
6680 1270215 : if (!value->IsJSFunction()) {
6681 241824 : number_of_fields += 1;
6682 : }
6683 : }
6684 : }
6685 : }
6686 :
6687 : Handle<Map> old_map(object->map(), isolate);
6688 :
6689 334949 : int inobject_props = old_map->GetInObjectProperties();
6690 :
6691 : // Allocate new map.
6692 334949 : Handle<Map> new_map = Map::CopyDropDescriptors(isolate, old_map);
6693 : // We should not only set this bit if we need to. We should not retain the
6694 : // old bit because turning a map into dictionary always sets this bit.
6695 669707 : new_map->set_may_have_interesting_symbols(new_map->has_named_interceptor() ||
6696 669898 : new_map->is_access_check_needed());
6697 334949 : new_map->set_is_dictionary_map(false);
6698 :
6699 334949 : NotifyMapChange(old_map, new_map, isolate);
6700 :
6701 :
6702 334948 : if (instance_descriptor_length == 0) {
6703 : DisallowHeapAllocation no_gc;
6704 : DCHECK_LE(unused_property_fields, inobject_props);
6705 : // Transform the object.
6706 63749 : new_map->SetInObjectUnusedPropertyFields(inobject_props);
6707 63749 : object->synchronized_set_map(*new_map);
6708 127498 : object->SetProperties(ReadOnlyRoots(isolate).empty_fixed_array());
6709 : // Check that it really works.
6710 : DCHECK(object->HasFastProperties());
6711 63749 : if (FLAG_trace_maps) {
6712 0 : LOG(isolate, MapEvent("SlowToFast", *old_map, *new_map, reason));
6713 : }
6714 : return;
6715 : }
6716 :
6717 : // Allocate the instance descriptor.
6718 : Handle<DescriptorArray> descriptors = DescriptorArray::Allocate(
6719 : isolate, instance_descriptor_length, 0, TENURED);
6720 :
6721 : int number_of_allocated_fields =
6722 271199 : number_of_fields + unused_property_fields - inobject_props;
6723 271199 : if (number_of_allocated_fields < 0) {
6724 : // There is enough inobject space for all fields (including unused).
6725 : number_of_allocated_fields = 0;
6726 65025 : unused_property_fields = inobject_props - number_of_fields;
6727 : }
6728 :
6729 : // Allocate the property array for the fields.
6730 : Handle<PropertyArray> fields =
6731 271199 : factory->NewPropertyArray(number_of_allocated_fields);
6732 :
6733 : bool is_transitionable_elements_kind =
6734 : IsTransitionableFastElementsKind(old_map->elements_kind());
6735 :
6736 : // Fill in the instance descriptor and the fields.
6737 : int current_offset = 0;
6738 1679323 : for (int i = 0; i < instance_descriptor_length; i++) {
6739 1679328 : int index = Smi::ToInt(iteration_order->get(i));
6740 1679323 : Name k = dictionary->NameAt(index);
6741 : // Dictionary keys are internalized upon insertion.
6742 : // TODO(jkummerow): Turn this into a DCHECK if it's not hit in the wild.
6743 1679325 : CHECK(k->IsUniqueName());
6744 : Handle<Name> key(k, isolate);
6745 :
6746 : // Properly mark the {new_map} if the {key} is an "interesting symbol".
6747 1679325 : if (key->IsInterestingSymbol()) {
6748 1962 : new_map->set_may_have_interesting_symbols(true);
6749 : }
6750 :
6751 1679326 : Object value = dictionary->ValueAt(index);
6752 :
6753 1679325 : PropertyDetails details = dictionary->DetailsAt(index);
6754 : DCHECK_EQ(kField, details.location());
6755 : DCHECK_EQ(PropertyConstness::kMutable, details.constness());
6756 :
6757 1679325 : Descriptor d;
6758 1679325 : if (details.kind() == kData) {
6759 1270212 : if (!FLAG_track_constant_fields && value->IsJSFunction()) {
6760 : d = Descriptor::DataConstant(key, handle(value, isolate),
6761 1028387 : details.attributes());
6762 : } else {
6763 : // Ensure that we make constant field only when elements kind is not
6764 : // transitionable.
6765 : PropertyConstness constness =
6766 : FLAG_track_constant_fields && !is_transitionable_elements_kind
6767 : ? PropertyConstness::kConst
6768 : : PropertyConstness::kMutable;
6769 : d = Descriptor::DataField(
6770 : key, current_offset, details.attributes(), constness,
6771 : // TODO(verwaest): value->OptimalRepresentation();
6772 : Representation::Tagged(),
6773 483648 : MaybeObjectHandle(FieldType::Any(isolate)));
6774 : }
6775 : } else {
6776 : DCHECK_EQ(kAccessor, details.kind());
6777 : d = Descriptor::AccessorConstant(key, handle(value, isolate),
6778 409112 : details.attributes());
6779 : }
6780 : details = d.GetDetails();
6781 1679329 : if (details.location() == kField) {
6782 241824 : if (current_offset < inobject_props) {
6783 : object->InObjectPropertyAtPut(current_offset, value,
6784 17539 : UPDATE_WRITE_BARRIER);
6785 : } else {
6786 224285 : int offset = current_offset - inobject_props;
6787 224285 : fields->set(offset, value);
6788 : }
6789 241824 : current_offset += details.field_width_in_words();
6790 : }
6791 1679328 : descriptors->Set(i, &d);
6792 : }
6793 : DCHECK(current_offset == number_of_fields);
6794 :
6795 271200 : descriptors->Sort();
6796 :
6797 : Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
6798 271198 : isolate, new_map, descriptors, descriptors->number_of_descriptors());
6799 :
6800 : DisallowHeapAllocation no_gc;
6801 271200 : new_map->InitializeDescriptors(isolate, *descriptors, *layout_descriptor);
6802 271199 : if (number_of_allocated_fields == 0) {
6803 242944 : new_map->SetInObjectUnusedPropertyFields(unused_property_fields);
6804 : } else {
6805 28255 : new_map->SetOutOfObjectUnusedPropertyFields(unused_property_fields);
6806 : }
6807 :
6808 271200 : if (FLAG_trace_maps) {
6809 818 : LOG(isolate, MapEvent("SlowToFast", *old_map, *new_map, reason));
6810 : }
6811 : // Transform the object.
6812 271199 : object->synchronized_set_map(*new_map);
6813 :
6814 542400 : object->SetProperties(*fields);
6815 : DCHECK(object->IsJSObject());
6816 :
6817 : // Check that it really works.
6818 : DCHECK(object->HasFastProperties());
6819 : }
6820 :
6821 74677 : void JSObject::RequireSlowElements(NumberDictionary dictionary) {
6822 149354 : if (dictionary->requires_slow_elements()) return;
6823 : dictionary->set_requires_slow_elements();
6824 42370 : if (map()->is_prototype_map()) {
6825 : // If this object is a prototype (the callee will check), invalidate any
6826 : // prototype chains involving it.
6827 : InvalidatePrototypeChains(map());
6828 : }
6829 : }
6830 :
6831 291140 : Handle<NumberDictionary> JSObject::NormalizeElements(Handle<JSObject> object) {
6832 : DCHECK(!object->HasFixedTypedArrayElements());
6833 : Isolate* isolate = object->GetIsolate();
6834 582280 : bool is_sloppy_arguments = object->HasSloppyArgumentsElements();
6835 : {
6836 : DisallowHeapAllocation no_gc;
6837 291140 : FixedArrayBase elements = object->elements();
6838 :
6839 291140 : if (is_sloppy_arguments) {
6840 777 : elements = SloppyArgumentsElements::cast(elements)->arguments();
6841 : }
6842 :
6843 291140 : if (elements->IsNumberDictionary()) {
6844 4284 : return handle(NumberDictionary::cast(elements), isolate);
6845 : }
6846 : }
6847 :
6848 : DCHECK(object->HasSmiOrObjectElements() || object->HasDoubleElements() ||
6849 : object->HasFastArgumentsElements() ||
6850 : object->HasFastStringWrapperElements());
6851 :
6852 : Handle<NumberDictionary> dictionary =
6853 573712 : object->GetElementsAccessor()->Normalize(object);
6854 :
6855 : // Switch to using the dictionary as the backing storage for elements.
6856 : ElementsKind target_kind = is_sloppy_arguments
6857 : ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS
6858 859086 : : object->HasFastStringWrapperElements()
6859 : ? SLOW_STRING_WRAPPER_ELEMENTS
6860 573712 : : DICTIONARY_ELEMENTS;
6861 286856 : Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind);
6862 : // Set the new map first to satify the elements type assert in set_elements().
6863 286856 : JSObject::MigrateToMap(object, new_map);
6864 :
6865 286856 : if (is_sloppy_arguments) {
6866 1482 : SloppyArgumentsElements::cast(object->elements())
6867 1482 : ->set_arguments(*dictionary);
6868 : } else {
6869 572230 : object->set_elements(*dictionary);
6870 : }
6871 :
6872 286856 : isolate->counters()->elements_to_dictionary()->Increment();
6873 :
6874 : #ifdef DEBUG
6875 : if (FLAG_trace_normalization) {
6876 : StdoutStream os;
6877 : os << "Object elements have been normalized:\n";
6878 : object->Print(os);
6879 : }
6880 : #endif
6881 :
6882 : DCHECK(object->HasDictionaryElements() ||
6883 : object->HasSlowArgumentsElements() ||
6884 : object->HasSlowStringWrapperElements());
6885 286856 : return dictionary;
6886 : }
6887 :
6888 : namespace {
6889 :
6890 39131 : Object SetHashAndUpdateProperties(HeapObject properties, int hash) {
6891 : DCHECK_NE(PropertyArray::kNoHashSentinel, hash);
6892 : DCHECK(PropertyArray::HashField::is_valid(hash));
6893 :
6894 39131 : ReadOnlyRoots roots = properties->GetReadOnlyRoots();
6895 44868 : if (properties == roots.empty_fixed_array() ||
6896 44858 : properties == roots.empty_property_array() ||
6897 : properties == roots.empty_property_dictionary()) {
6898 33782 : return Smi::FromInt(hash);
6899 : }
6900 :
6901 5349 : if (properties->IsPropertyArray()) {
6902 147 : PropertyArray::cast(properties)->SetHash(hash);
6903 : DCHECK_LT(0, PropertyArray::cast(properties)->length());
6904 147 : return properties;
6905 : }
6906 :
6907 5202 : if (properties->IsGlobalDictionary()) {
6908 : GlobalDictionary::cast(properties)->SetHash(hash);
6909 0 : return properties;
6910 : }
6911 :
6912 : DCHECK(properties->IsNameDictionary());
6913 : NameDictionary::cast(properties)->SetHash(hash);
6914 5202 : return properties;
6915 : }
6916 :
6917 29341265 : int GetIdentityHashHelper(JSReceiver object) {
6918 : DisallowHeapAllocation no_gc;
6919 29341265 : Object properties = object->raw_properties_or_hash();
6920 29341256 : if (properties->IsSmi()) {
6921 38793 : return Smi::ToInt(properties);
6922 : }
6923 :
6924 29302470 : if (properties->IsPropertyArray()) {
6925 11235938 : return PropertyArray::cast(properties)->Hash();
6926 : }
6927 :
6928 18066536 : if (properties->IsNameDictionary()) {
6929 3617501 : return NameDictionary::cast(properties)->Hash();
6930 : }
6931 :
6932 14449037 : if (properties->IsGlobalDictionary()) {
6933 8235072 : return GlobalDictionary::cast(properties)->Hash();
6934 : }
6935 :
6936 : #ifdef DEBUG
6937 : ReadOnlyRoots roots = object->GetReadOnlyRoots();
6938 : DCHECK(properties == roots.empty_fixed_array() ||
6939 : properties == roots.empty_property_dictionary());
6940 : #endif
6941 :
6942 : return PropertyArray::kNoHashSentinel;
6943 : }
6944 : } // namespace
6945 :
6946 33843 : void JSReceiver::SetIdentityHash(int hash) {
6947 : DisallowHeapAllocation no_gc;
6948 : DCHECK_NE(PropertyArray::kNoHashSentinel, hash);
6949 : DCHECK(PropertyArray::HashField::is_valid(hash));
6950 :
6951 67686 : HeapObject existing_properties = HeapObject::cast(raw_properties_or_hash());
6952 33843 : Object new_properties = SetHashAndUpdateProperties(existing_properties, hash);
6953 33843 : set_raw_properties_or_hash(new_properties);
6954 33843 : }
6955 :
6956 29279266 : void JSReceiver::SetProperties(HeapObject properties) {
6957 : DCHECK_IMPLIES(properties->IsPropertyArray() &&
6958 : PropertyArray::cast(properties)->length() == 0,
6959 : properties == GetReadOnlyRoots().empty_property_array());
6960 : DisallowHeapAllocation no_gc;
6961 29279266 : int hash = GetIdentityHashHelper(*this);
6962 29279269 : Object new_properties = properties;
6963 :
6964 : // TODO(cbruni): Make GetIdentityHashHelper return a bool so that we
6965 : // don't have to manually compare against kNoHashSentinel.
6966 29279269 : if (hash != PropertyArray::kNoHashSentinel) {
6967 5288 : new_properties = SetHashAndUpdateProperties(properties, hash);
6968 : }
6969 :
6970 29279269 : set_raw_properties_or_hash(new_properties);
6971 29279261 : }
6972 :
6973 40517 : Object JSReceiver::GetIdentityHash() {
6974 : DisallowHeapAllocation no_gc;
6975 :
6976 40517 : int hash = GetIdentityHashHelper(*this);
6977 40517 : if (hash == PropertyArray::kNoHashSentinel) {
6978 4190 : return GetReadOnlyRoots().undefined_value();
6979 : }
6980 :
6981 38422 : return Smi::FromInt(hash);
6982 : }
6983 :
6984 : // static
6985 33808 : Smi JSReceiver::CreateIdentityHash(Isolate* isolate, JSReceiver key) {
6986 : DisallowHeapAllocation no_gc;
6987 33808 : int hash = isolate->GenerateIdentityHash(PropertyArray::HashField::kMax);
6988 : DCHECK_NE(PropertyArray::kNoHashSentinel, hash);
6989 :
6990 33808 : key->SetIdentityHash(hash);
6991 33808 : return Smi::FromInt(hash);
6992 : }
6993 :
6994 21480 : Smi JSReceiver::GetOrCreateIdentityHash(Isolate* isolate) {
6995 : DisallowHeapAllocation no_gc;
6996 :
6997 21480 : int hash = GetIdentityHashHelper(*this);
6998 21480 : if (hash != PropertyArray::kNoHashSentinel) {
6999 : return Smi::FromInt(hash);
7000 : }
7001 :
7002 20999 : return JSReceiver::CreateIdentityHash(isolate, *this);
7003 : }
7004 :
7005 158 : Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it,
7006 : ShouldThrow should_throw) {
7007 : Isolate* isolate = it->isolate();
7008 : // Make sure that the top context does not change when doing callbacks or
7009 : // interceptor calls.
7010 : AssertNoContextChange ncc(isolate);
7011 :
7012 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
7013 100 : Handle<InterceptorInfo> interceptor(it->GetInterceptor());
7014 200 : if (interceptor->deleter()->IsUndefined(isolate)) return Nothing<bool>();
7015 :
7016 : Handle<JSObject> holder = it->GetHolder<JSObject>();
7017 : Handle<Object> receiver = it->GetReceiver();
7018 116 : if (!receiver->IsJSReceiver()) {
7019 0 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
7020 : Object::ConvertReceiver(isolate, receiver),
7021 : Nothing<bool>());
7022 : }
7023 :
7024 : PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
7025 58 : *holder, should_throw);
7026 : Handle<Object> result;
7027 58 : if (it->IsElement()) {
7028 23 : result = args.CallIndexedDeleter(interceptor, it->index());
7029 : } else {
7030 35 : result = args.CallNamedDeleter(interceptor, it->name());
7031 : }
7032 :
7033 58 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
7034 58 : if (result.is_null()) return Nothing<bool>();
7035 :
7036 : DCHECK(result->IsBoolean());
7037 : // Rebox CustomArguments::kReturnValueOffset before returning.
7038 48 : return Just(result->IsTrue(isolate));
7039 : }
7040 :
7041 54275 : void JSReceiver::DeleteNormalizedProperty(Handle<JSReceiver> object,
7042 : int entry) {
7043 : DCHECK(!object->HasFastProperties());
7044 : Isolate* isolate = object->GetIsolate();
7045 :
7046 108550 : if (object->IsJSGlobalObject()) {
7047 : // If we have a global object, invalidate the cell and swap in a new one.
7048 : Handle<GlobalDictionary> dictionary(
7049 22576 : JSGlobalObject::cast(*object)->global_dictionary(), isolate);
7050 : DCHECK_NE(GlobalDictionary::kNotFound, entry);
7051 :
7052 11288 : auto cell = PropertyCell::InvalidateEntry(isolate, dictionary, entry);
7053 22576 : cell->set_value(ReadOnlyRoots(isolate).the_hole_value());
7054 : cell->set_property_details(
7055 22576 : PropertyDetails::Empty(PropertyCellType::kUninitialized));
7056 : } else {
7057 85974 : Handle<NameDictionary> dictionary(object->property_dictionary(), isolate);
7058 : DCHECK_NE(NameDictionary::kNotFound, entry);
7059 :
7060 42987 : dictionary = NameDictionary::DeleteEntry(isolate, dictionary, entry);
7061 85974 : object->SetProperties(*dictionary);
7062 : }
7063 54275 : if (object->map()->is_prototype_map()) {
7064 : // Invalidate prototype validity cell as this may invalidate transitioning
7065 : // store IC handlers.
7066 : JSObject::InvalidatePrototypeChains(object->map());
7067 : }
7068 54275 : }
7069 :
7070 :
7071 19148293 : Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
7072 : LanguageMode language_mode) {
7073 6388351 : it->UpdateProtector();
7074 :
7075 : Isolate* isolate = it->isolate();
7076 :
7077 6388351 : if (it->state() == LookupIterator::JSPROXY) {
7078 : return JSProxy::DeletePropertyOrElement(it->GetHolder<JSProxy>(),
7079 53328 : it->GetName(), language_mode);
7080 : }
7081 :
7082 12723374 : if (it->GetReceiver()->IsJSProxy()) {
7083 39 : if (it->state() != LookupIterator::NOT_FOUND) {
7084 : DCHECK_EQ(LookupIterator::DATA, it->state());
7085 : DCHECK(it->name()->IsPrivate());
7086 6 : it->Delete();
7087 : }
7088 : return Just(true);
7089 : }
7090 6361648 : Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
7091 :
7092 12743104 : for (; it->IsFound(); it->Next()) {
7093 170165 : switch (it->state()) {
7094 : case LookupIterator::JSPROXY:
7095 : case LookupIterator::NOT_FOUND:
7096 : case LookupIterator::TRANSITION:
7097 0 : UNREACHABLE();
7098 : case LookupIterator::ACCESS_CHECK:
7099 9864 : if (it->HasAccess()) break;
7100 36 : isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
7101 36 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
7102 : return Just(false);
7103 : case LookupIterator::INTERCEPTOR: {
7104 : ShouldThrow should_throw =
7105 100 : is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
7106 : Maybe<bool> result =
7107 100 : JSObject::DeletePropertyWithInterceptor(it, should_throw);
7108 : // An exception was thrown in the interceptor. Propagate.
7109 124 : if (isolate->has_pending_exception()) return Nothing<bool>();
7110 : // Delete with interceptor succeeded. Return result.
7111 : // TODO(neis): In strict mode, we should probably throw if the
7112 : // interceptor returns false.
7113 100 : if (result.IsJust()) return result;
7114 76 : break;
7115 : }
7116 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
7117 : return Just(true);
7118 : case LookupIterator::DATA:
7119 : case LookupIterator::ACCESSOR: {
7120 160156 : if (!it->IsConfigurable()) {
7121 : // Fail if the property is not configurable.
7122 2485 : if (is_strict(language_mode)) {
7123 : isolate->Throw(*isolate->factory()->NewTypeError(
7124 : MessageTemplate::kStrictDeleteProperty, it->GetName(),
7125 2031 : receiver));
7126 : return Nothing<bool>();
7127 : }
7128 : return Just(false);
7129 : }
7130 :
7131 157671 : it->Delete();
7132 :
7133 : return Just(true);
7134 : }
7135 : }
7136 : }
7137 :
7138 : return Just(true);
7139 : }
7140 :
7141 :
7142 1027 : Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index,
7143 : LanguageMode language_mode) {
7144 : LookupIterator it(object->GetIsolate(), object, index, object,
7145 : LookupIterator::OWN);
7146 1027 : return DeleteProperty(&it, language_mode);
7147 : }
7148 :
7149 :
7150 899 : Maybe<bool> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
7151 : Handle<Name> name,
7152 : LanguageMode language_mode) {
7153 899 : LookupIterator it(object, name, object, LookupIterator::OWN);
7154 899 : return DeleteProperty(&it, language_mode);
7155 : }
7156 :
7157 :
7158 622058 : Maybe<bool> JSReceiver::DeletePropertyOrElement(Handle<JSReceiver> object,
7159 : Handle<Name> name,
7160 : LanguageMode language_mode) {
7161 : LookupIterator it = LookupIterator::PropertyOrElement(
7162 622058 : object->GetIsolate(), object, name, object, LookupIterator::OWN);
7163 622058 : return DeleteProperty(&it, language_mode);
7164 : }
7165 :
7166 : // ES6 19.1.2.4
7167 : // static
7168 114325 : Object JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object,
7169 : Handle<Object> key,
7170 : Handle<Object> attributes) {
7171 : // 1. If Type(O) is not Object, throw a TypeError exception.
7172 228650 : if (!object->IsJSReceiver()) {
7173 : Handle<String> fun_name =
7174 63 : isolate->factory()->InternalizeUtf8String("Object.defineProperty");
7175 126 : THROW_NEW_ERROR_RETURN_FAILURE(
7176 : isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name));
7177 : }
7178 : // 2. Let key be ToPropertyKey(P).
7179 : // 3. ReturnIfAbrupt(key).
7180 228524 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key,
7181 : Object::ToPropertyKey(isolate, key));
7182 : // 4. Let desc be ToPropertyDescriptor(Attributes).
7183 : // 5. ReturnIfAbrupt(desc).
7184 : PropertyDescriptor desc;
7185 114262 : if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) {
7186 135 : return ReadOnlyRoots(isolate).exception();
7187 : }
7188 : // 6. Let success be DefinePropertyOrThrow(O,key, desc).
7189 : Maybe<bool> success = DefineOwnProperty(
7190 114127 : isolate, Handle<JSReceiver>::cast(object), key, &desc, kThrowOnError);
7191 : // 7. ReturnIfAbrupt(success).
7192 115165 : MAYBE_RETURN(success, ReadOnlyRoots(isolate).exception());
7193 113089 : CHECK(success.FromJust());
7194 : // 8. Return O.
7195 : return *object;
7196 : }
7197 :
7198 : // ES6 19.1.2.3.1
7199 : // static
7200 1854 : MaybeHandle<Object> JSReceiver::DefineProperties(Isolate* isolate,
7201 : Handle<Object> object,
7202 : Handle<Object> properties) {
7203 : // 1. If Type(O) is not Object, throw a TypeError exception.
7204 3708 : if (!object->IsJSReceiver()) {
7205 : Handle<String> fun_name =
7206 27 : isolate->factory()->InternalizeUtf8String("Object.defineProperties");
7207 27 : THROW_NEW_ERROR(isolate,
7208 : NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name),
7209 : Object);
7210 : }
7211 : // 2. Let props be ToObject(Properties).
7212 : // 3. ReturnIfAbrupt(props).
7213 : Handle<JSReceiver> props;
7214 3654 : ASSIGN_RETURN_ON_EXCEPTION(isolate, props,
7215 : Object::ToObject(isolate, properties), Object);
7216 :
7217 : // 4. Let keys be props.[[OwnPropertyKeys]]().
7218 : // 5. ReturnIfAbrupt(keys).
7219 : Handle<FixedArray> keys;
7220 3636 : ASSIGN_RETURN_ON_EXCEPTION(
7221 : isolate, keys, KeyAccumulator::GetKeys(props, KeyCollectionMode::kOwnOnly,
7222 : ALL_PROPERTIES),
7223 : Object);
7224 : // 6. Let descriptors be an empty List.
7225 : int capacity = keys->length();
7226 1818 : std::vector<PropertyDescriptor> descriptors(capacity);
7227 : size_t descriptors_index = 0;
7228 : // 7. Repeat for each element nextKey of keys in List order,
7229 13786 : for (int i = 0; i < keys->length(); ++i) {
7230 : Handle<Object> next_key(keys->get(i), isolate);
7231 : // 7a. Let propDesc be props.[[GetOwnProperty]](nextKey).
7232 : // 7b. ReturnIfAbrupt(propDesc).
7233 5300 : bool success = false;
7234 : LookupIterator it = LookupIterator::PropertyOrElement(
7235 5300 : isolate, props, next_key, &success, LookupIterator::OWN);
7236 : DCHECK(success);
7237 5300 : Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
7238 5300 : if (maybe.IsNothing()) return MaybeHandle<Object>();
7239 : PropertyAttributes attrs = maybe.FromJust();
7240 : // 7c. If propDesc is not undefined and propDesc.[[Enumerable]] is true:
7241 6425 : if (attrs == ABSENT) continue;
7242 5300 : if (attrs & DONT_ENUM) continue;
7243 : // 7c i. Let descObj be Get(props, nextKey).
7244 : // 7c ii. ReturnIfAbrupt(descObj).
7245 : Handle<Object> desc_obj;
7246 8350 : ASSIGN_RETURN_ON_EXCEPTION(isolate, desc_obj, Object::GetProperty(&it),
7247 : Object);
7248 : // 7c iii. Let desc be ToPropertyDescriptor(descObj).
7249 : success = PropertyDescriptor::ToPropertyDescriptor(
7250 8350 : isolate, desc_obj, &descriptors[descriptors_index]);
7251 : // 7c iv. ReturnIfAbrupt(desc).
7252 4175 : if (!success) return MaybeHandle<Object>();
7253 : // 7c v. Append the pair (a two element List) consisting of nextKey and
7254 : // desc to the end of descriptors.
7255 3950 : descriptors[descriptors_index].set_name(next_key);
7256 3950 : descriptors_index++;
7257 : }
7258 : // 8. For each pair from descriptors in list order,
7259 3572 : for (size_t i = 0; i < descriptors_index; ++i) {
7260 3572 : PropertyDescriptor* desc = &descriptors[i];
7261 : // 8a. Let P be the first element of pair.
7262 : // 8b. Let desc be the second element of pair.
7263 : // 8c. Let status be DefinePropertyOrThrow(O, P, desc).
7264 : Maybe<bool> status =
7265 : DefineOwnProperty(isolate, Handle<JSReceiver>::cast(object),
7266 3572 : desc->name(), desc, kThrowOnError);
7267 : // 8d. ReturnIfAbrupt(status).
7268 3572 : if (status.IsNothing()) return MaybeHandle<Object>();
7269 3572 : CHECK(status.FromJust());
7270 : }
7271 : // 9. Return o.
7272 1593 : return object;
7273 : }
7274 :
7275 : // static
7276 599340 : Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate,
7277 : Handle<JSReceiver> object,
7278 : Handle<Object> key,
7279 : PropertyDescriptor* desc,
7280 : ShouldThrow should_throw) {
7281 1198693 : if (object->IsJSArray()) {
7282 : return JSArray::DefineOwnProperty(isolate, Handle<JSArray>::cast(object),
7283 30484 : key, desc, should_throw);
7284 : }
7285 1137729 : if (object->IsJSProxy()) {
7286 : return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object),
7287 41059 : key, desc, should_throw);
7288 : }
7289 1055612 : if (object->IsJSTypedArray()) {
7290 : return JSTypedArray::DefineOwnProperty(
7291 3610 : isolate, Handle<JSTypedArray>::cast(object), key, desc, should_throw);
7292 : }
7293 :
7294 : // OrdinaryDefineOwnProperty, by virtue of calling
7295 : // DefineOwnPropertyIgnoreAttributes, can handle arguments
7296 : // (ES#sec-arguments-exotic-objects-defineownproperty-p-desc).
7297 : return OrdinaryDefineOwnProperty(isolate, Handle<JSObject>::cast(object), key,
7298 524197 : desc, should_throw);
7299 : }
7300 :
7301 :
7302 : // static
7303 564157 : Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate,
7304 : Handle<JSObject> object,
7305 : Handle<Object> key,
7306 : PropertyDescriptor* desc,
7307 : ShouldThrow should_throw) {
7308 564157 : bool success = false;
7309 : DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
7310 : LookupIterator it = LookupIterator::PropertyOrElement(
7311 564157 : isolate, object, key, &success, LookupIterator::OWN);
7312 : DCHECK(success); // ...so creating a LookupIterator can't fail.
7313 :
7314 : // Deal with access checks first.
7315 564159 : if (it.state() == LookupIterator::ACCESS_CHECK) {
7316 2440 : if (!it.HasAccess()) {
7317 30 : isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>());
7318 30 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
7319 : return Just(true);
7320 : }
7321 2410 : it.Next();
7322 : }
7323 :
7324 564129 : return OrdinaryDefineOwnProperty(&it, desc, should_throw);
7325 : }
7326 :
7327 :
7328 : // ES6 9.1.6.1
7329 : // static
7330 1315746 : Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
7331 : PropertyDescriptor* desc,
7332 : ShouldThrow should_throw) {
7333 : Isolate* isolate = it->isolate();
7334 : // 1. Let current be O.[[GetOwnProperty]](P).
7335 : // 2. ReturnIfAbrupt(current).
7336 : PropertyDescriptor current;
7337 564122 : MAYBE_RETURN(GetOwnPropertyDescriptor(it, ¤t), Nothing<bool>());
7338 :
7339 564104 : it->Restart();
7340 : // Handle interceptor
7341 1503262 : for (; it->IsFound(); it->Next()) {
7342 187575 : if (it->state() == LookupIterator::INTERCEPTOR) {
7343 183 : if (it->HolderIsReceiverOrHiddenPrototype()) {
7344 : Maybe<bool> result = DefinePropertyWithInterceptorInternal(
7345 183 : it, it->GetInterceptor(), should_throw, *desc);
7346 366 : if (result.IsNothing() || result.FromJust()) {
7347 54 : return result;
7348 : }
7349 : }
7350 : }
7351 : }
7352 :
7353 : // TODO(jkummerow/verwaest): It would be nice if we didn't have to reset
7354 : // the iterator every time. Currently, the reasons why we need it are:
7355 : // - handle interceptors correctly
7356 : // - handle accessors correctly (which might change the holder's map)
7357 564049 : it->Restart();
7358 : // 3. Let extensible be the value of the [[Extensible]] internal slot of O.
7359 564051 : Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
7360 564060 : bool extensible = JSObject::IsExtensible(object);
7361 :
7362 : return ValidateAndApplyPropertyDescriptor(
7363 564061 : isolate, it, extensible, desc, ¤t, should_throw, Handle<Name>());
7364 : }
7365 :
7366 :
7367 : // ES6 9.1.6.2
7368 : // static
7369 0 : Maybe<bool> JSReceiver::IsCompatiblePropertyDescriptor(
7370 : Isolate* isolate, bool extensible, PropertyDescriptor* desc,
7371 : PropertyDescriptor* current, Handle<Name> property_name,
7372 : ShouldThrow should_throw) {
7373 : // 1. Return ValidateAndApplyPropertyDescriptor(undefined, undefined,
7374 : // Extensible, Desc, Current).
7375 : return ValidateAndApplyPropertyDescriptor(
7376 4806 : isolate, nullptr, extensible, desc, current, should_throw, property_name);
7377 : }
7378 :
7379 :
7380 : // ES6 9.1.6.3
7381 : // static
7382 568858 : Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor(
7383 : Isolate* isolate, LookupIterator* it, bool extensible,
7384 : PropertyDescriptor* desc, PropertyDescriptor* current,
7385 : ShouldThrow should_throw, Handle<Name> property_name) {
7386 : // We either need a LookupIterator, or a property name.
7387 : DCHECK((it == nullptr) != property_name.is_null());
7388 : Handle<JSObject> object;
7389 568858 : if (it != nullptr) object = Handle<JSObject>::cast(it->GetReceiver());
7390 : bool desc_is_data_descriptor = PropertyDescriptor::IsDataDescriptor(desc);
7391 : bool desc_is_accessor_descriptor =
7392 : PropertyDescriptor::IsAccessorDescriptor(desc);
7393 : bool desc_is_generic_descriptor =
7394 : PropertyDescriptor::IsGenericDescriptor(desc);
7395 : // 1. (Assert)
7396 : // 2. If current is undefined, then
7397 568856 : if (current->is_empty()) {
7398 : // 2a. If extensible is false, return false.
7399 381778 : if (!extensible) {
7400 262 : RETURN_FAILURE(
7401 : isolate, should_throw,
7402 : NewTypeError(MessageTemplate::kDefineDisallowed,
7403 : it != nullptr ? it->GetName() : property_name));
7404 : }
7405 : // 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then:
7406 : // (This is equivalent to !IsAccessorDescriptor(desc).)
7407 : DCHECK((desc_is_generic_descriptor || desc_is_data_descriptor) ==
7408 : !desc_is_accessor_descriptor);
7409 381678 : if (!desc_is_accessor_descriptor) {
7410 : // 2c i. If O is not undefined, create an own data property named P of
7411 : // object O whose [[Value]], [[Writable]], [[Enumerable]] and
7412 : // [[Configurable]] attribute values are described by Desc. If the value
7413 : // of an attribute field of Desc is absent, the attribute of the newly
7414 : // created property is set to its default value.
7415 313812 : if (it != nullptr) {
7416 311242 : if (!desc->has_writable()) desc->set_writable(false);
7417 311242 : if (!desc->has_enumerable()) desc->set_enumerable(false);
7418 311242 : if (!desc->has_configurable()) desc->set_configurable(false);
7419 : Handle<Object> value(
7420 : desc->has_value()
7421 : ? desc->value()
7422 320755 : : Handle<Object>::cast(isolate->factory()->undefined_value()));
7423 : MaybeHandle<Object> result =
7424 : JSObject::DefineOwnPropertyIgnoreAttributes(it, value,
7425 311242 : desc->ToAttributes());
7426 311245 : if (result.is_null()) return Nothing<bool>();
7427 : }
7428 : } else {
7429 : // 2d. Else Desc must be an accessor Property Descriptor,
7430 : DCHECK(desc_is_accessor_descriptor);
7431 : // 2d i. If O is not undefined, create an own accessor property named P
7432 : // of object O whose [[Get]], [[Set]], [[Enumerable]] and
7433 : // [[Configurable]] attribute values are described by Desc. If the value
7434 : // of an attribute field of Desc is absent, the attribute of the newly
7435 : // created property is set to its default value.
7436 67866 : if (it != nullptr) {
7437 67722 : if (!desc->has_enumerable()) desc->set_enumerable(false);
7438 67722 : if (!desc->has_configurable()) desc->set_configurable(false);
7439 : Handle<Object> getter(
7440 : desc->has_get()
7441 : ? desc->get()
7442 80177 : : Handle<Object>::cast(isolate->factory()->null_value()));
7443 : Handle<Object> setter(
7444 : desc->has_set()
7445 : ? desc->set()
7446 109664 : : Handle<Object>::cast(isolate->factory()->null_value()));
7447 : MaybeHandle<Object> result =
7448 67722 : JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes());
7449 67722 : if (result.is_null()) return Nothing<bool>();
7450 : }
7451 : }
7452 : // 2e. Return true.
7453 : return Just(true);
7454 : }
7455 : // 3. Return true, if every field in Desc is absent.
7456 : // 4. Return true, if every field in Desc also occurs in current and the
7457 : // value of every field in Desc is the same value as the corresponding field
7458 : // in current when compared using the SameValue algorithm.
7459 332034 : if ((!desc->has_enumerable() ||
7460 70918 : desc->enumerable() == current->enumerable()) &&
7461 47674 : (!desc->has_configurable() ||
7462 68530 : desc->configurable() == current->configurable()) &&
7463 50899 : (!desc->has_value() ||
7464 281836 : (current->has_value() && current->value()->SameValue(*desc->value()))) &&
7465 27436 : (!desc->has_writable() ||
7466 70622 : (current->has_writable() && current->writable() == desc->writable())) &&
7467 5808 : (!desc->has_get() ||
7468 415744 : (current->has_get() && current->get()->SameValue(*desc->get()))) &&
7469 7197 : (!desc->has_set() ||
7470 7008 : (current->has_set() && current->set()->SameValue(*desc->set())))) {
7471 : return Just(true);
7472 : }
7473 : // 5. If the [[Configurable]] field of current is false, then
7474 156563 : if (!current->configurable()) {
7475 : // 5a. Return false, if the [[Configurable]] field of Desc is true.
7476 8016 : if (desc->has_configurable() && desc->configurable()) {
7477 543 : RETURN_FAILURE(
7478 : isolate, should_throw,
7479 : NewTypeError(MessageTemplate::kRedefineDisallowed,
7480 : it != nullptr ? it->GetName() : property_name));
7481 : }
7482 : // 5b. Return false, if the [[Enumerable]] field of Desc is present and the
7483 : // [[Enumerable]] fields of current and Desc are the Boolean negation of
7484 : // each other.
7485 7352 : if (desc->has_enumerable() && desc->enumerable() != current->enumerable()) {
7486 284 : RETURN_FAILURE(
7487 : isolate, should_throw,
7488 : NewTypeError(MessageTemplate::kRedefineDisallowed,
7489 : it != nullptr ? it->GetName() : property_name));
7490 : }
7491 : }
7492 :
7493 : bool current_is_data_descriptor =
7494 : PropertyDescriptor::IsDataDescriptor(current);
7495 : // 6. If IsGenericDescriptor(Desc) is true, no further validation is required.
7496 156264 : if (desc_is_generic_descriptor) {
7497 : // Nothing to see here.
7498 :
7499 : // 7. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) have
7500 : // different results, then:
7501 155345 : } else if (current_is_data_descriptor != desc_is_data_descriptor) {
7502 : // 7a. Return false, if the [[Configurable]] field of current is false.
7503 118103 : if (!current->configurable()) {
7504 435 : RETURN_FAILURE(
7505 : isolate, should_throw,
7506 : NewTypeError(MessageTemplate::kRedefineDisallowed,
7507 : it != nullptr ? it->GetName() : property_name));
7508 : }
7509 : // 7b. If IsDataDescriptor(current) is true, then:
7510 : if (current_is_data_descriptor) {
7511 : // 7b i. If O is not undefined, convert the property named P of object O
7512 : // from a data property to an accessor property. Preserve the existing
7513 : // values of the converted property's [[Configurable]] and [[Enumerable]]
7514 : // attributes and set the rest of the property's attributes to their
7515 : // default values.
7516 : // --> Folded into step 10.
7517 : } else {
7518 : // 7c i. If O is not undefined, convert the property named P of object O
7519 : // from an accessor property to a data property. Preserve the existing
7520 : // values of the converted property’s [[Configurable]] and [[Enumerable]]
7521 : // attributes and set the rest of the property’s attributes to their
7522 : // default values.
7523 : // --> Folded into step 10.
7524 : }
7525 :
7526 : // 8. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both
7527 : // true, then:
7528 37242 : } else if (current_is_data_descriptor && desc_is_data_descriptor) {
7529 : // 8a. If the [[Configurable]] field of current is false, then:
7530 26246 : if (!current->configurable()) {
7531 : // 8a i. Return false, if the [[Writable]] field of current is false and
7532 : // the [[Writable]] field of Desc is true.
7533 4340 : if (!current->writable() && desc->has_writable() && desc->writable()) {
7534 189 : RETURN_FAILURE(
7535 : isolate, should_throw,
7536 : NewTypeError(MessageTemplate::kRedefineDisallowed,
7537 : it != nullptr ? it->GetName() : property_name));
7538 : }
7539 : // 8a ii. If the [[Writable]] field of current is false, then:
7540 3907 : if (!current->writable()) {
7541 : // 8a ii 1. Return false, if the [[Value]] field of Desc is present and
7542 : // SameValue(Desc.[[Value]], current.[[Value]]) is false.
7543 470 : if (desc->has_value() && !desc->value()->SameValue(*current->value())) {
7544 775 : RETURN_FAILURE(
7545 : isolate, should_throw,
7546 : NewTypeError(MessageTemplate::kRedefineDisallowed,
7547 : it != nullptr ? it->GetName() : property_name));
7548 : }
7549 : }
7550 : }
7551 : } else {
7552 : // 9. Else IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc)
7553 : // are both true,
7554 : DCHECK(PropertyDescriptor::IsAccessorDescriptor(current) &&
7555 : desc_is_accessor_descriptor);
7556 : // 9a. If the [[Configurable]] field of current is false, then:
7557 10996 : if (!current->configurable()) {
7558 : // 9a i. Return false, if the [[Set]] field of Desc is present and
7559 : // SameValue(Desc.[[Set]], current.[[Set]]) is false.
7560 143 : if (desc->has_set() && !desc->set()->SameValue(*current->set())) {
7561 117 : RETURN_FAILURE(
7562 : isolate, should_throw,
7563 : NewTypeError(MessageTemplate::kRedefineDisallowed,
7564 : it != nullptr ? it->GetName() : property_name));
7565 : }
7566 : // 9a ii. Return false, if the [[Get]] field of Desc is present and
7567 : // SameValue(Desc.[[Get]], current.[[Get]]) is false.
7568 106 : if (desc->has_get() && !desc->get()->SameValue(*current->get())) {
7569 170 : RETURN_FAILURE(
7570 : isolate, should_throw,
7571 : NewTypeError(MessageTemplate::kRedefineDisallowed,
7572 : it != nullptr ? it->GetName() : property_name));
7573 : }
7574 : }
7575 : }
7576 :
7577 : // 10. If O is not undefined, then:
7578 155757 : if (it != nullptr) {
7579 : // 10a. For each field of Desc that is present, set the corresponding
7580 : // attribute of the property named P of object O to the value of the field.
7581 : PropertyAttributes attrs = NONE;
7582 :
7583 155496 : if (desc->has_enumerable()) {
7584 : attrs = static_cast<PropertyAttributes>(
7585 121269 : attrs | (desc->enumerable() ? NONE : DONT_ENUM));
7586 : } else {
7587 : attrs = static_cast<PropertyAttributes>(
7588 34227 : attrs | (current->enumerable() ? NONE : DONT_ENUM));
7589 : }
7590 155496 : if (desc->has_configurable()) {
7591 : attrs = static_cast<PropertyAttributes>(
7592 133388 : attrs | (desc->configurable() ? NONE : DONT_DELETE));
7593 : } else {
7594 : attrs = static_cast<PropertyAttributes>(
7595 22108 : attrs | (current->configurable() ? NONE : DONT_DELETE));
7596 : }
7597 284729 : if (desc_is_data_descriptor ||
7598 129233 : (desc_is_generic_descriptor && current_is_data_descriptor)) {
7599 27083 : if (desc->has_writable()) {
7600 : attrs = static_cast<PropertyAttributes>(
7601 24179 : attrs | (desc->writable() ? NONE : READ_ONLY));
7602 : } else {
7603 : attrs = static_cast<PropertyAttributes>(
7604 2904 : attrs | (current->writable() ? NONE : READ_ONLY));
7605 : }
7606 : Handle<Object> value(
7607 : desc->has_value() ? desc->value()
7608 : : current->has_value()
7609 : ? current->value()
7610 : : Handle<Object>::cast(
7611 29914 : isolate->factory()->undefined_value()));
7612 : return JSObject::DefineOwnPropertyIgnoreAttributes(it, value, attrs,
7613 27083 : should_throw);
7614 : } else {
7615 : DCHECK(desc_is_accessor_descriptor ||
7616 : (desc_is_generic_descriptor &&
7617 : PropertyDescriptor::IsAccessorDescriptor(current)));
7618 : Handle<Object> getter(
7619 : desc->has_get()
7620 : ? desc->get()
7621 : : current->has_get()
7622 : ? current->get()
7623 135898 : : Handle<Object>::cast(isolate->factory()->null_value()));
7624 : Handle<Object> setter(
7625 : desc->has_set()
7626 : ? desc->set()
7627 : : current->has_set()
7628 : ? current->set()
7629 365801 : : Handle<Object>::cast(isolate->factory()->null_value()));
7630 : MaybeHandle<Object> result =
7631 128413 : JSObject::DefineAccessor(it, getter, setter, attrs);
7632 128413 : if (result.is_null()) return Nothing<bool>();
7633 : }
7634 : }
7635 :
7636 : // 11. Return true.
7637 : return Just(true);
7638 : }
7639 :
7640 : // static
7641 111580 : Maybe<bool> JSReceiver::CreateDataProperty(Isolate* isolate,
7642 : Handle<JSReceiver> object,
7643 : Handle<Name> key,
7644 : Handle<Object> value,
7645 : ShouldThrow should_throw) {
7646 : LookupIterator it = LookupIterator::PropertyOrElement(isolate, object, key,
7647 111580 : LookupIterator::OWN);
7648 111580 : return CreateDataProperty(&it, value, should_throw);
7649 : }
7650 :
7651 : // static
7652 2323470 : Maybe<bool> JSReceiver::CreateDataProperty(LookupIterator* it,
7653 : Handle<Object> value,
7654 : ShouldThrow should_throw) {
7655 : DCHECK(!it->check_prototype_chain());
7656 2323470 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
7657 : Isolate* isolate = receiver->GetIsolate();
7658 :
7659 4646940 : if (receiver->IsJSObject()) {
7660 2322438 : return JSObject::CreateDataProperty(it, value, should_throw); // Shortcut.
7661 : }
7662 :
7663 : PropertyDescriptor new_desc;
7664 : new_desc.set_value(value);
7665 : new_desc.set_writable(true);
7666 : new_desc.set_enumerable(true);
7667 : new_desc.set_configurable(true);
7668 :
7669 : return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
7670 2064 : &new_desc, should_throw);
7671 : }
7672 :
7673 4649437 : Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it,
7674 : Handle<Object> value,
7675 : ShouldThrow should_throw) {
7676 : DCHECK(it->GetReceiver()->IsJSObject());
7677 2324721 : MAYBE_RETURN(JSReceiver::GetPropertyAttributes(it), Nothing<bool>());
7678 2324716 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
7679 : Isolate* isolate = receiver->GetIsolate();
7680 :
7681 2324716 : if (it->IsFound()) {
7682 444 : Maybe<PropertyAttributes> attributes = GetPropertyAttributes(it);
7683 481 : MAYBE_RETURN(attributes, Nothing<bool>());
7684 444 : if ((attributes.FromJust() & DONT_DELETE) != 0) {
7685 118 : RETURN_FAILURE(
7686 : isolate, should_throw,
7687 : NewTypeError(MessageTemplate::kRedefineDisallowed, it->GetName()));
7688 : }
7689 : } else {
7690 2324272 : if (!JSObject::IsExtensible(Handle<JSObject>::cast(it->GetReceiver()))) {
7691 329 : RETURN_FAILURE(
7692 : isolate, should_throw,
7693 : NewTypeError(MessageTemplate::kDefineDisallowed, it->GetName()));
7694 : }
7695 : }
7696 :
7697 4649186 : RETURN_ON_EXCEPTION_VALUE(it->isolate(),
7698 : DefineOwnPropertyIgnoreAttributes(it, value, NONE),
7699 : Nothing<bool>());
7700 :
7701 : return Just(true);
7702 : }
7703 :
7704 : // TODO(jkummerow): Consider unification with FastAsArrayLength() in
7705 : // accessors.cc.
7706 32998 : bool PropertyKeyToArrayLength(Handle<Object> value, uint32_t* length) {
7707 : DCHECK(value->IsNumber() || value->IsName());
7708 65996 : if (value->ToArrayLength(length)) return true;
7709 88776 : if (value->IsString()) return String::cast(*value)->AsArrayIndex(length);
7710 : return false;
7711 : }
7712 :
7713 0 : bool PropertyKeyToArrayIndex(Handle<Object> index_obj, uint32_t* output) {
7714 32998 : return PropertyKeyToArrayLength(index_obj, output) && *output != kMaxUInt32;
7715 : }
7716 :
7717 :
7718 : // ES6 9.4.2.1
7719 : // static
7720 33364 : Maybe<bool> JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o,
7721 : Handle<Object> name,
7722 : PropertyDescriptor* desc,
7723 : ShouldThrow should_throw) {
7724 : // 1. Assert: IsPropertyKey(P) is true. ("P" is |name|.)
7725 : // 2. If P is "length", then:
7726 : // TODO(jkummerow): Check if we need slow string comparison.
7727 33364 : if (*name == ReadOnlyRoots(isolate).length_string()) {
7728 : // 2a. Return ArraySetLength(A, Desc).
7729 366 : return ArraySetLength(isolate, o, desc, should_throw);
7730 : }
7731 : // 3. Else if P is an array index, then:
7732 32998 : uint32_t index = 0;
7733 32998 : if (PropertyKeyToArrayIndex(name, &index)) {
7734 : // 3a. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
7735 : PropertyDescriptor old_len_desc;
7736 : Maybe<bool> success = GetOwnPropertyDescriptor(
7737 28065 : isolate, o, isolate->factory()->length_string(), &old_len_desc);
7738 : // 3b. (Assert)
7739 : DCHECK(success.FromJust());
7740 : USE(success);
7741 : // 3c. Let oldLen be oldLenDesc.[[Value]].
7742 28065 : uint32_t old_len = 0;
7743 56130 : CHECK(old_len_desc.value()->ToArrayLength(&old_len));
7744 : // 3d. Let index be ToUint32(P).
7745 : // (Already done above.)
7746 : // 3e. (Assert)
7747 : // 3f. If index >= oldLen and oldLenDesc.[[Writable]] is false,
7748 : // return false.
7749 34519 : if (index >= old_len && old_len_desc.has_writable() &&
7750 : !old_len_desc.writable()) {
7751 0 : RETURN_FAILURE(isolate, should_throw,
7752 : NewTypeError(MessageTemplate::kDefineDisallowed, name));
7753 : }
7754 : // 3g. Let succeeded be OrdinaryDefineOwnProperty(A, P, Desc).
7755 : Maybe<bool> succeeded =
7756 28065 : OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
7757 : // 3h. Assert: succeeded is not an abrupt completion.
7758 : // In our case, if should_throw == kThrowOnError, it can be!
7759 : // 3i. If succeeded is false, return false.
7760 56044 : if (succeeded.IsNothing() || !succeeded.FromJust()) return succeeded;
7761 : // 3j. If index >= oldLen, then:
7762 27970 : if (index >= old_len) {
7763 : // 3j i. Set oldLenDesc.[[Value]] to index + 1.
7764 3227 : old_len_desc.set_value(isolate->factory()->NewNumberFromUint(index + 1));
7765 : // 3j ii. Let succeeded be
7766 : // OrdinaryDefineOwnProperty(A, "length", oldLenDesc).
7767 : succeeded = OrdinaryDefineOwnProperty(isolate, o,
7768 : isolate->factory()->length_string(),
7769 3227 : &old_len_desc, should_throw);
7770 : // 3j iii. Assert: succeeded is true.
7771 : DCHECK(succeeded.FromJust());
7772 : USE(succeeded);
7773 : }
7774 : // 3k. Return true.
7775 : return Just(true);
7776 : }
7777 :
7778 : // 4. Return OrdinaryDefineOwnProperty(A, P, Desc).
7779 4933 : return OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
7780 : }
7781 :
7782 :
7783 : // Part of ES6 9.4.2.4 ArraySetLength.
7784 : // static
7785 485129 : bool JSArray::AnythingToArrayLength(Isolate* isolate,
7786 : Handle<Object> length_object,
7787 : uint32_t* output) {
7788 : // Fast path: check numbers and strings that can be converted directly
7789 : // and unobservably.
7790 970258 : if (length_object->ToArrayLength(output)) return true;
7791 1310598 : if (length_object->IsString() &&
7792 436896 : Handle<String>::cast(length_object)->AsArrayIndex(output)) {
7793 : return true;
7794 : }
7795 : // Slow path: follow steps in ES6 9.4.2.4 "ArraySetLength".
7796 : // 3. Let newLen be ToUint32(Desc.[[Value]]).
7797 : Handle<Object> uint32_v;
7798 873702 : if (!Object::ToUint32(isolate, length_object).ToHandle(&uint32_v)) {
7799 : // 4. ReturnIfAbrupt(newLen).
7800 : return false;
7801 : }
7802 : // 5. Let numberLen be ToNumber(Desc.[[Value]]).
7803 : Handle<Object> number_v;
7804 873684 : if (!Object::ToNumber(isolate, length_object).ToHandle(&number_v)) {
7805 : // 6. ReturnIfAbrupt(newLen).
7806 : return false;
7807 : }
7808 : // 7. If newLen != numberLen, throw a RangeError exception.
7809 873684 : if (uint32_v->Number() != number_v->Number()) {
7810 : Handle<Object> exception =
7811 153 : isolate->factory()->NewRangeError(MessageTemplate::kInvalidArrayLength);
7812 153 : isolate->Throw(*exception);
7813 : return false;
7814 : }
7815 873378 : CHECK(uint32_v->ToArrayLength(output));
7816 : return true;
7817 : }
7818 :
7819 :
7820 : // ES6 9.4.2.4
7821 : // static
7822 366 : Maybe<bool> JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a,
7823 : PropertyDescriptor* desc,
7824 : ShouldThrow should_throw) {
7825 : // 1. If the [[Value]] field of Desc is absent, then
7826 366 : if (!desc->has_value()) {
7827 : // 1a. Return OrdinaryDefineOwnProperty(A, "length", Desc).
7828 : return OrdinaryDefineOwnProperty(
7829 285 : isolate, a, isolate->factory()->length_string(), desc, should_throw);
7830 : }
7831 : // 2. Let newLenDesc be a copy of Desc.
7832 : // (Actual copying is not necessary.)
7833 : PropertyDescriptor* new_len_desc = desc;
7834 : // 3. - 7. Convert Desc.[[Value]] to newLen.
7835 81 : uint32_t new_len = 0;
7836 81 : if (!AnythingToArrayLength(isolate, desc->value(), &new_len)) {
7837 : DCHECK(isolate->has_pending_exception());
7838 : return Nothing<bool>();
7839 : }
7840 : // 8. Set newLenDesc.[[Value]] to newLen.
7841 : // (Done below, if needed.)
7842 : // 9. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
7843 : PropertyDescriptor old_len_desc;
7844 : Maybe<bool> success = GetOwnPropertyDescriptor(
7845 72 : isolate, a, isolate->factory()->length_string(), &old_len_desc);
7846 : // 10. (Assert)
7847 : DCHECK(success.FromJust());
7848 : USE(success);
7849 : // 11. Let oldLen be oldLenDesc.[[Value]].
7850 72 : uint32_t old_len = 0;
7851 144 : CHECK(old_len_desc.value()->ToArrayLength(&old_len));
7852 : // 12. If newLen >= oldLen, then
7853 72 : if (new_len >= old_len) {
7854 : // 8. Set newLenDesc.[[Value]] to newLen.
7855 : // 12a. Return OrdinaryDefineOwnProperty(A, "length", newLenDesc).
7856 63 : new_len_desc->set_value(isolate->factory()->NewNumberFromUint(new_len));
7857 : return OrdinaryDefineOwnProperty(isolate, a,
7858 : isolate->factory()->length_string(),
7859 63 : new_len_desc, should_throw);
7860 : }
7861 : // 13. If oldLenDesc.[[Writable]] is false, return false.
7862 9 : if (!old_len_desc.writable()) {
7863 0 : RETURN_FAILURE(isolate, should_throw,
7864 : NewTypeError(MessageTemplate::kRedefineDisallowed,
7865 : isolate->factory()->length_string()));
7866 : }
7867 : // 14. If newLenDesc.[[Writable]] is absent or has the value true,
7868 : // let newWritable be true.
7869 : bool new_writable = false;
7870 9 : if (!new_len_desc->has_writable() || new_len_desc->writable()) {
7871 : new_writable = true;
7872 : } else {
7873 : // 15. Else,
7874 : // 15a. Need to defer setting the [[Writable]] attribute to false in case
7875 : // any elements cannot be deleted.
7876 : // 15b. Let newWritable be false. (It's initialized as "false" anyway.)
7877 : // 15c. Set newLenDesc.[[Writable]] to true.
7878 : // (Not needed.)
7879 : }
7880 : // Most of steps 16 through 19 is implemented by JSArray::SetLength.
7881 9 : JSArray::SetLength(a, new_len);
7882 : // Steps 19d-ii, 20.
7883 9 : if (!new_writable) {
7884 : PropertyDescriptor readonly;
7885 : readonly.set_writable(false);
7886 : Maybe<bool> success = OrdinaryDefineOwnProperty(
7887 : isolate, a, isolate->factory()->length_string(), &readonly,
7888 0 : should_throw);
7889 : DCHECK(success.FromJust());
7890 : USE(success);
7891 : }
7892 9 : uint32_t actual_new_len = 0;
7893 18 : CHECK(a->length()->ToArrayLength(&actual_new_len));
7894 : // Steps 19d-v, 21. Return false if there were non-deletable elements.
7895 9 : bool result = actual_new_len == new_len;
7896 9 : if (!result) {
7897 9 : RETURN_FAILURE(
7898 : isolate, should_throw,
7899 : NewTypeError(MessageTemplate::kStrictDeleteProperty,
7900 : isolate->factory()->NewNumberFromUint(actual_new_len - 1),
7901 : a));
7902 : }
7903 : return Just(result);
7904 : }
7905 :
7906 :
7907 : // ES6 9.5.6
7908 : // static
7909 41059 : Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy,
7910 : Handle<Object> key,
7911 : PropertyDescriptor* desc,
7912 : ShouldThrow should_throw) {
7913 41059 : STACK_CHECK(isolate, Nothing<bool>());
7914 82388 : if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) {
7915 : DCHECK(!Handle<Symbol>::cast(key)->IsPrivateName());
7916 : return JSProxy::SetPrivateSymbol(isolate, proxy, Handle<Symbol>::cast(key),
7917 18 : desc, should_throw);
7918 : }
7919 : Handle<String> trap_name = isolate->factory()->defineProperty_string();
7920 : // 1. Assert: IsPropertyKey(P) is true.
7921 : DCHECK(key->IsName() || key->IsNumber());
7922 : // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
7923 82064 : Handle<Object> handler(proxy->handler(), isolate);
7924 : // 3. If handler is null, throw a TypeError exception.
7925 : // 4. Assert: Type(handler) is Object.
7926 82064 : if (proxy->IsRevoked()) {
7927 : isolate->Throw(*isolate->factory()->NewTypeError(
7928 18 : MessageTemplate::kProxyRevoked, trap_name));
7929 : return Nothing<bool>();
7930 : }
7931 : // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
7932 82046 : Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
7933 : // 6. Let trap be ? GetMethod(handler, "defineProperty").
7934 : Handle<Object> trap;
7935 82046 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7936 : isolate, trap,
7937 : Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
7938 : Nothing<bool>());
7939 : // 7. If trap is undefined, then:
7940 81866 : if (trap->IsUndefined(isolate)) {
7941 : // 7a. Return target.[[DefineOwnProperty]](P, Desc).
7942 : return JSReceiver::DefineOwnProperty(isolate, target, key, desc,
7943 31983 : should_throw);
7944 : }
7945 : // 8. Let descObj be FromPropertyDescriptor(Desc).
7946 8950 : Handle<Object> desc_obj = desc->ToObject(isolate);
7947 : // 9. Let booleanTrapResult be
7948 : // ToBoolean(? Call(trap, handler, «target, P, descObj»)).
7949 : Handle<Name> property_name =
7950 17900 : key->IsName()
7951 : ? Handle<Name>::cast(key)
7952 8950 : : Handle<Name>::cast(isolate->factory()->NumberToString(key));
7953 : // Do not leak private property names.
7954 : DCHECK(!property_name->IsPrivate());
7955 : Handle<Object> trap_result_obj;
7956 8950 : Handle<Object> args[] = {target, property_name, desc_obj};
7957 17900 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7958 : isolate, trap_result_obj,
7959 : Execution::Call(isolate, trap, handler, arraysize(args), args),
7960 : Nothing<bool>());
7961 : // 10. If booleanTrapResult is false, return false.
7962 1323 : if (!trap_result_obj->BooleanValue(isolate)) {
7963 99 : RETURN_FAILURE(isolate, should_throw,
7964 : NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
7965 : trap_name, property_name));
7966 : }
7967 : // 11. Let targetDesc be ? target.[[GetOwnProperty]](P).
7968 : PropertyDescriptor target_desc;
7969 : Maybe<bool> target_found =
7970 1242 : JSReceiver::GetOwnPropertyDescriptor(isolate, target, key, &target_desc);
7971 1242 : MAYBE_RETURN(target_found, Nothing<bool>());
7972 : // 12. Let extensibleTarget be ? IsExtensible(target).
7973 1242 : Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
7974 1242 : MAYBE_RETURN(maybe_extensible, Nothing<bool>());
7975 : bool extensible_target = maybe_extensible.FromJust();
7976 : // 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]]
7977 : // is false, then:
7978 : // 13a. Let settingConfigFalse be true.
7979 : // 14. Else let settingConfigFalse be false.
7980 1935 : bool setting_config_false = desc->has_configurable() && !desc->configurable();
7981 : // 15. If targetDesc is undefined, then
7982 1242 : if (!target_found.FromJust()) {
7983 : // 15a. If extensibleTarget is false, throw a TypeError exception.
7984 621 : if (!extensible_target) {
7985 : isolate->Throw(*isolate->factory()->NewTypeError(
7986 18 : MessageTemplate::kProxyDefinePropertyNonExtensible, property_name));
7987 : return Nothing<bool>();
7988 : }
7989 : // 15b. If settingConfigFalse is true, throw a TypeError exception.
7990 612 : if (setting_config_false) {
7991 : isolate->Throw(*isolate->factory()->NewTypeError(
7992 18 : MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
7993 : return Nothing<bool>();
7994 : }
7995 : } else {
7996 : // 16. Else targetDesc is not undefined,
7997 : // 16a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc,
7998 : // targetDesc) is false, throw a TypeError exception.
7999 : Maybe<bool> valid =
8000 : IsCompatiblePropertyDescriptor(isolate, extensible_target, desc,
8001 : &target_desc, property_name, kDontThrow);
8002 621 : MAYBE_RETURN(valid, Nothing<bool>());
8003 621 : if (!valid.FromJust()) {
8004 : isolate->Throw(*isolate->factory()->NewTypeError(
8005 18 : MessageTemplate::kProxyDefinePropertyIncompatible, property_name));
8006 : return Nothing<bool>();
8007 : }
8008 : // 16b. If settingConfigFalse is true and targetDesc.[[Configurable]] is
8009 : // true, throw a TypeError exception.
8010 702 : if (setting_config_false && target_desc.configurable()) {
8011 : isolate->Throw(*isolate->factory()->NewTypeError(
8012 18 : MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
8013 : return Nothing<bool>();
8014 : }
8015 : }
8016 : // 17. Return true.
8017 : return Just(true);
8018 : }
8019 :
8020 : // static
8021 36 : Maybe<bool> JSProxy::SetPrivateSymbol(Isolate* isolate, Handle<JSProxy> proxy,
8022 : Handle<Symbol> private_name,
8023 : PropertyDescriptor* desc,
8024 : ShouldThrow should_throw) {
8025 : DCHECK(!private_name->IsPrivateName());
8026 : // Despite the generic name, this can only add private data properties.
8027 54 : if (!PropertyDescriptor::IsDataDescriptor(desc) ||
8028 18 : desc->ToAttributes() != DONT_ENUM) {
8029 36 : RETURN_FAILURE(isolate, should_throw,
8030 : NewTypeError(MessageTemplate::kProxyPrivate));
8031 : }
8032 : DCHECK(proxy->map()->is_dictionary_map());
8033 : Handle<Object> value =
8034 : desc->has_value()
8035 : ? desc->value()
8036 18 : : Handle<Object>::cast(isolate->factory()->undefined_value());
8037 :
8038 18 : LookupIterator it(proxy, private_name, proxy);
8039 :
8040 18 : if (it.IsFound()) {
8041 : DCHECK_EQ(LookupIterator::DATA, it.state());
8042 : DCHECK_EQ(DONT_ENUM, it.property_attributes());
8043 6 : it.WriteDataValue(value, false);
8044 : return Just(true);
8045 : }
8046 :
8047 24 : Handle<NameDictionary> dict(proxy->property_dictionary(), isolate);
8048 : PropertyDetails details(kData, DONT_ENUM, PropertyCellType::kNoCell);
8049 : Handle<NameDictionary> result =
8050 12 : NameDictionary::Add(isolate, dict, private_name, value, details);
8051 24 : if (!dict.is_identical_to(result)) proxy->SetProperties(*result);
8052 : return Just(true);
8053 : }
8054 :
8055 : // static
8056 3167302 : Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate,
8057 : Handle<JSReceiver> object,
8058 : Handle<Object> key,
8059 : PropertyDescriptor* desc) {
8060 3167302 : bool success = false;
8061 : DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
8062 : LookupIterator it = LookupIterator::PropertyOrElement(
8063 3167302 : isolate, object, key, &success, LookupIterator::OWN);
8064 : DCHECK(success); // ...so creating a LookupIterator can't fail.
8065 3167302 : return GetOwnPropertyDescriptor(&it, desc);
8066 : }
8067 :
8068 : namespace {
8069 :
8070 7417527 : Maybe<bool> GetPropertyDescriptorWithInterceptor(LookupIterator* it,
8071 : PropertyDescriptor* desc) {
8072 3708480 : if (it->state() == LookupIterator::ACCESS_CHECK) {
8073 2294572 : if (it->HasAccess()) {
8074 2294522 : it->Next();
8075 55 : } else if (!JSObject::AllCanRead(it) ||
8076 : it->state() != LookupIterator::INTERCEPTOR) {
8077 50 : it->Restart();
8078 : return Just(false);
8079 : }
8080 : }
8081 :
8082 3708430 : if (it->state() != LookupIterator::INTERCEPTOR) return Just(false);
8083 :
8084 : Isolate* isolate = it->isolate();
8085 555 : Handle<InterceptorInfo> interceptor = it->GetInterceptor();
8086 1110 : if (interceptor->descriptor()->IsUndefined(isolate)) return Just(false);
8087 :
8088 : Handle<Object> result;
8089 : Handle<JSObject> holder = it->GetHolder<JSObject>();
8090 :
8091 : Handle<Object> receiver = it->GetReceiver();
8092 90 : if (!receiver->IsJSReceiver()) {
8093 0 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
8094 : Object::ConvertReceiver(isolate, receiver),
8095 : Nothing<bool>());
8096 : }
8097 :
8098 : PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
8099 45 : *holder, kDontThrow);
8100 45 : if (it->IsElement()) {
8101 12 : result = args.CallIndexedDescriptor(interceptor, it->index());
8102 : } else {
8103 33 : result = args.CallNamedDescriptor(interceptor, it->name());
8104 : }
8105 45 : if (!result.is_null()) {
8106 : // Request successfully intercepted, try to set the property
8107 : // descriptor.
8108 : Utils::ApiCheck(
8109 12 : PropertyDescriptor::ToPropertyDescriptor(isolate, result, desc),
8110 : it->IsElement() ? "v8::IndexedPropertyDescriptorCallback"
8111 : : "v8::NamedPropertyDescriptorCallback",
8112 12 : "Invalid property descriptor.");
8113 :
8114 : return Just(true);
8115 : }
8116 :
8117 33 : it->Next();
8118 : return Just(false);
8119 : }
8120 : } // namespace
8121 :
8122 : // ES6 9.1.5.1
8123 : // Returns true on success, false if the property didn't exist, nothing if
8124 : // an exception was thrown.
8125 : // static
8126 7031711 : Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it,
8127 : PropertyDescriptor* desc) {
8128 : Isolate* isolate = it->isolate();
8129 : // "Virtual" dispatch.
8130 10381268 : if (it->IsFound() && it->GetHolder<JSReceiver>()->IsJSProxy()) {
8131 : return JSProxy::GetOwnPropertyDescriptor(isolate, it->GetHolder<JSProxy>(),
8132 50596 : it->GetName(), desc);
8133 : }
8134 :
8135 3708480 : Maybe<bool> intercepted = GetPropertyDescriptorWithInterceptor(it, desc);
8136 3708480 : MAYBE_RETURN(intercepted, Nothing<bool>());
8137 3708480 : if (intercepted.FromJust()) {
8138 : return Just(true);
8139 : }
8140 :
8141 : // Request was not intercepted, continue as normal.
8142 : // 1. (Assert)
8143 : // 2. If O does not have an own property with key P, return undefined.
8144 3708468 : Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(it);
8145 3708470 : MAYBE_RETURN(maybe, Nothing<bool>());
8146 : PropertyAttributes attrs = maybe.FromJust();
8147 3708280 : if (attrs == ABSENT) return Just(false);
8148 : DCHECK(!isolate->has_pending_exception());
8149 :
8150 : // 3. Let D be a newly created Property Descriptor with no fields.
8151 : DCHECK(desc->is_empty());
8152 : // 4. Let X be O's own property whose key is P.
8153 : // 5. If X is a data property, then
8154 3470320 : bool is_accessor_pair = it->state() == LookupIterator::ACCESSOR &&
8155 3642707 : it->GetAccessors()->IsAccessorPair();
8156 3297933 : if (!is_accessor_pair) {
8157 : // 5a. Set D.[[Value]] to the value of X's [[Value]] attribute.
8158 : Handle<Object> value;
8159 6505266 : if (!Object::GetProperty(it).ToHandle(&value)) {
8160 : DCHECK(isolate->has_pending_exception());
8161 : return Nothing<bool>();
8162 : }
8163 : desc->set_value(value);
8164 : // 5b. Set D.[[Writable]] to the value of X's [[Writable]] attribute
8165 3252533 : desc->set_writable((attrs & READ_ONLY) == 0);
8166 : } else {
8167 : // 6. Else X is an accessor property, so
8168 : Handle<AccessorPair> accessors =
8169 45300 : Handle<AccessorPair>::cast(it->GetAccessors());
8170 : // 6a. Set D.[[Get]] to the value of X's [[Get]] attribute.
8171 : desc->set_get(
8172 45300 : AccessorPair::GetComponent(isolate, accessors, ACCESSOR_GETTER));
8173 : // 6b. Set D.[[Set]] to the value of X's [[Set]] attribute.
8174 : desc->set_set(
8175 45300 : AccessorPair::GetComponent(isolate, accessors, ACCESSOR_SETTER));
8176 : }
8177 :
8178 : // 7. Set D.[[Enumerable]] to the value of X's [[Enumerable]] attribute.
8179 3297833 : desc->set_enumerable((attrs & DONT_ENUM) == 0);
8180 : // 8. Set D.[[Configurable]] to the value of X's [[Configurable]] attribute.
8181 3297833 : desc->set_configurable((attrs & DONT_DELETE) == 0);
8182 : // 9. Return D.
8183 : DCHECK(PropertyDescriptor::IsAccessorDescriptor(desc) !=
8184 : PropertyDescriptor::IsDataDescriptor(desc));
8185 : return Just(true);
8186 : }
8187 :
8188 :
8189 : // ES6 9.5.5
8190 : // static
8191 29428 : Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate,
8192 : Handle<JSProxy> proxy,
8193 : Handle<Name> name,
8194 : PropertyDescriptor* desc) {
8195 : DCHECK(!name->IsPrivate());
8196 29428 : STACK_CHECK(isolate, Nothing<bool>());
8197 :
8198 : Handle<String> trap_name =
8199 : isolate->factory()->getOwnPropertyDescriptor_string();
8200 : // 1. (Assert)
8201 : // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
8202 58834 : Handle<Object> handler(proxy->handler(), isolate);
8203 : // 3. If handler is null, throw a TypeError exception.
8204 : // 4. Assert: Type(handler) is Object.
8205 58834 : if (proxy->IsRevoked()) {
8206 : isolate->Throw(*isolate->factory()->NewTypeError(
8207 36 : MessageTemplate::kProxyRevoked, trap_name));
8208 : return Nothing<bool>();
8209 : }
8210 : // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
8211 58798 : Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
8212 : // 6. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor").
8213 : Handle<Object> trap;
8214 58798 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8215 : isolate, trap,
8216 : Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
8217 : Nothing<bool>());
8218 : // 7. If trap is undefined, then
8219 58690 : if (trap->IsUndefined(isolate)) {
8220 : // 7a. Return target.[[GetOwnProperty]](P).
8221 17852 : return JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, desc);
8222 : }
8223 : // 8. Let trapResultObj be ? Call(trap, handler, «target, P»).
8224 : Handle<Object> trap_result_obj;
8225 : Handle<Object> args[] = {target, name};
8226 22986 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8227 : isolate, trap_result_obj,
8228 : Execution::Call(isolate, trap, handler, arraysize(args), args),
8229 : Nothing<bool>());
8230 : // 9. If Type(trapResultObj) is neither Object nor Undefined, throw a
8231 : // TypeError exception.
8232 16011 : if (!trap_result_obj->IsJSReceiver() &&
8233 5877 : !trap_result_obj->IsUndefined(isolate)) {
8234 : isolate->Throw(*isolate->factory()->NewTypeError(
8235 36 : MessageTemplate::kProxyGetOwnPropertyDescriptorInvalid, name));
8236 : return Nothing<bool>();
8237 : }
8238 : // 10. Let targetDesc be ? target.[[GetOwnProperty]](P).
8239 : PropertyDescriptor target_desc;
8240 : Maybe<bool> found =
8241 5049 : JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
8242 5049 : MAYBE_RETURN(found, Nothing<bool>());
8243 : // 11. If trapResultObj is undefined, then
8244 10098 : if (trap_result_obj->IsUndefined(isolate)) {
8245 : // 11a. If targetDesc is undefined, return undefined.
8246 792 : if (!found.FromJust()) return Just(false);
8247 : // 11b. If targetDesc.[[Configurable]] is false, throw a TypeError
8248 : // exception.
8249 45 : if (!target_desc.configurable()) {
8250 : isolate->Throw(*isolate->factory()->NewTypeError(
8251 54 : MessageTemplate::kProxyGetOwnPropertyDescriptorUndefined, name));
8252 : return Nothing<bool>();
8253 : }
8254 : // 11c. Let extensibleTarget be ? IsExtensible(target).
8255 18 : Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
8256 18 : MAYBE_RETURN(extensible_target, Nothing<bool>());
8257 : // 11d. (Assert)
8258 : // 11e. If extensibleTarget is false, throw a TypeError exception.
8259 18 : if (!extensible_target.FromJust()) {
8260 : isolate->Throw(*isolate->factory()->NewTypeError(
8261 0 : MessageTemplate::kProxyGetOwnPropertyDescriptorNonExtensible, name));
8262 : return Nothing<bool>();
8263 : }
8264 : // 11f. Return undefined.
8265 : return Just(false);
8266 : }
8267 : // 12. Let extensibleTarget be ? IsExtensible(target).
8268 4257 : Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
8269 4257 : MAYBE_RETURN(extensible_target, Nothing<bool>());
8270 : // 13. Let resultDesc be ? ToPropertyDescriptor(trapResultObj).
8271 4257 : if (!PropertyDescriptor::ToPropertyDescriptor(isolate, trap_result_obj,
8272 4257 : desc)) {
8273 : DCHECK(isolate->has_pending_exception());
8274 : return Nothing<bool>();
8275 : }
8276 : // 14. Call CompletePropertyDescriptor(resultDesc).
8277 4185 : PropertyDescriptor::CompletePropertyDescriptor(isolate, desc);
8278 : // 15. Let valid be IsCompatiblePropertyDescriptor (extensibleTarget,
8279 : // resultDesc, targetDesc).
8280 : Maybe<bool> valid =
8281 : IsCompatiblePropertyDescriptor(isolate, extensible_target.FromJust(),
8282 : desc, &target_desc, name, kDontThrow);
8283 4185 : MAYBE_RETURN(valid, Nothing<bool>());
8284 : // 16. If valid is false, throw a TypeError exception.
8285 4185 : if (!valid.FromJust()) {
8286 : isolate->Throw(*isolate->factory()->NewTypeError(
8287 36 : MessageTemplate::kProxyGetOwnPropertyDescriptorIncompatible, name));
8288 : return Nothing<bool>();
8289 : }
8290 : // 17. If resultDesc.[[Configurable]] is false, then
8291 4167 : if (!desc->configurable()) {
8292 : // 17a. If targetDesc is undefined or targetDesc.[[Configurable]] is true:
8293 639 : if (target_desc.is_empty() || target_desc.configurable()) {
8294 : // 17a i. Throw a TypeError exception.
8295 : isolate->Throw(*isolate->factory()->NewTypeError(
8296 : MessageTemplate::kProxyGetOwnPropertyDescriptorNonConfigurable,
8297 36 : name));
8298 : return Nothing<bool>();
8299 : }
8300 : }
8301 : // 18. Return resultDesc.
8302 : return Just(true);
8303 : }
8304 :
8305 :
8306 252893 : Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver,
8307 : IntegrityLevel level,
8308 : ShouldThrow should_throw) {
8309 : DCHECK(level == SEALED || level == FROZEN);
8310 :
8311 505803 : if (receiver->IsJSObject()) {
8312 252492 : Handle<JSObject> object = Handle<JSObject>::cast(receiver);
8313 :
8314 1009923 : if (!object->HasSloppyArgumentsElements() &&
8315 504939 : !object->IsJSModuleNamespace()) { // Fast path.
8316 : // Prevent memory leaks by not adding unnecessary transitions.
8317 252376 : Maybe<bool> test = JSObject::TestIntegrityLevel(object, level);
8318 252372 : MAYBE_RETURN(test, Nothing<bool>());
8319 252372 : if (test.FromJust()) return test;
8320 :
8321 247009 : if (level == SEALED) {
8322 : return JSObject::PreventExtensionsWithTransition<SEALED>(object,
8323 506 : should_throw);
8324 : } else {
8325 : return JSObject::PreventExtensionsWithTransition<FROZEN>(object,
8326 246503 : should_throw);
8327 : }
8328 : }
8329 : }
8330 :
8331 : Isolate* isolate = receiver->GetIsolate();
8332 :
8333 532 : MAYBE_RETURN(JSReceiver::PreventExtensions(receiver, should_throw),
8334 : Nothing<bool>());
8335 :
8336 : Handle<FixedArray> keys;
8337 532 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8338 : isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>());
8339 :
8340 : PropertyDescriptor no_conf;
8341 : no_conf.set_configurable(false);
8342 :
8343 : PropertyDescriptor no_conf_no_write;
8344 : no_conf_no_write.set_configurable(false);
8345 : no_conf_no_write.set_writable(false);
8346 :
8347 532 : if (level == SEALED) {
8348 452 : for (int i = 0; i < keys->length(); ++i) {
8349 : Handle<Object> key(keys->get(i), isolate);
8350 176 : MAYBE_RETURN(
8351 : DefineOwnProperty(isolate, receiver, key, &no_conf, kThrowOnError),
8352 : Nothing<bool>());
8353 : }
8354 : return Just(true);
8355 : }
8356 :
8357 2916 : for (int i = 0; i < keys->length(); ++i) {
8358 : Handle<Object> key(keys->get(i), isolate);
8359 : PropertyDescriptor current_desc;
8360 : Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
8361 1296 : isolate, receiver, key, ¤t_desc);
8362 1332 : MAYBE_RETURN(owned, Nothing<bool>());
8363 1287 : if (owned.FromJust()) {
8364 : PropertyDescriptor desc =
8365 : PropertyDescriptor::IsAccessorDescriptor(¤t_desc)
8366 : ? no_conf
8367 1287 : : no_conf_no_write;
8368 1287 : MAYBE_RETURN(
8369 : DefineOwnProperty(isolate, receiver, key, &desc, kThrowOnError),
8370 : Nothing<bool>());
8371 : }
8372 : }
8373 : return Just(true);
8374 : }
8375 :
8376 : namespace {
8377 :
8378 : template <typename Dictionary>
8379 6355 : bool TestDictionaryPropertiesIntegrityLevel(Dictionary dict,
8380 : ReadOnlyRoots roots,
8381 : PropertyAttributes level) {
8382 : DCHECK(level == SEALED || level == FROZEN);
8383 :
8384 6355 : uint32_t capacity = dict->Capacity();
8385 18227 : for (uint32_t i = 0; i < capacity; i++) {
8386 12009 : Object key;
8387 21037 : if (!dict->ToKey(roots, i, &key)) continue;
8388 2999 : if (key->FilterKey(ALL_PROPERTIES)) continue;
8389 2981 : PropertyDetails details = dict->DetailsAt(i);
8390 3118 : if (details.IsConfigurable()) return false;
8391 7269 : if (level == FROZEN && details.kind() == kData && !details.IsReadOnly()) {
8392 : return false;
8393 : }
8394 : }
8395 : return true;
8396 : }
8397 :
8398 6078 : bool TestFastPropertiesIntegrityLevel(Map map, PropertyAttributes level) {
8399 : DCHECK(level == SEALED || level == FROZEN);
8400 : DCHECK(!map->IsCustomElementsReceiverMap());
8401 : DCHECK(!map->is_dictionary_map());
8402 :
8403 6078 : DescriptorArray descriptors = map->instance_descriptors();
8404 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
8405 7932 : for (int i = 0; i < number_of_own_descriptors; i++) {
8406 1997 : if (descriptors->GetKey(i)->IsPrivate()) continue;
8407 1979 : PropertyDetails details = descriptors->GetDetails(i);
8408 1979 : if (details.IsConfigurable()) return false;
8409 4361 : if (level == FROZEN && details.kind() == kData && !details.IsReadOnly()) {
8410 : return false;
8411 : }
8412 : }
8413 : return true;
8414 : }
8415 :
8416 6169 : bool TestPropertiesIntegrityLevel(JSObject object, PropertyAttributes level) {
8417 : DCHECK(!object->map()->IsCustomElementsReceiverMap());
8418 :
8419 6169 : if (object->HasFastProperties()) {
8420 6078 : return TestFastPropertiesIntegrityLevel(object->map(), level);
8421 : }
8422 :
8423 : return TestDictionaryPropertiesIntegrityLevel(
8424 91 : object->property_dictionary(), object->GetReadOnlyRoots(), level);
8425 : }
8426 :
8427 6269 : bool TestElementsIntegrityLevel(JSObject object, PropertyAttributes level) {
8428 : DCHECK(!object->HasSloppyArgumentsElements());
8429 :
8430 6269 : ElementsKind kind = object->GetElementsKind();
8431 :
8432 6269 : if (IsDictionaryElementsKind(kind)) {
8433 : return TestDictionaryPropertiesIntegrityLevel(
8434 : NumberDictionary::cast(object->elements()), object->GetReadOnlyRoots(),
8435 12528 : level);
8436 : }
8437 5 : if (IsFixedTypedArrayElementsKind(kind)) {
8438 5 : return TestPropertiesIntegrityLevel(object, level);
8439 : }
8440 :
8441 : ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
8442 : // Only DICTIONARY_ELEMENTS and SLOW_SLOPPY_ARGUMENTS_ELEMENTS have
8443 : // PropertyAttributes so just test if empty
8444 0 : return accessor->NumberOfElements(object) == 0;
8445 : }
8446 :
8447 253250 : bool FastTestIntegrityLevel(JSObject object, PropertyAttributes level) {
8448 : DCHECK(!object->map()->IsCustomElementsReceiverMap());
8449 :
8450 6269 : return !object->map()->is_extensible() &&
8451 259414 : TestElementsIntegrityLevel(object, level) &&
8452 259414 : TestPropertiesIntegrityLevel(object, level);
8453 : }
8454 :
8455 273 : Maybe<bool> GenericTestIntegrityLevel(Handle<JSReceiver> receiver,
8456 : PropertyAttributes level) {
8457 : DCHECK(level == SEALED || level == FROZEN);
8458 :
8459 273 : Maybe<bool> extensible = JSReceiver::IsExtensible(receiver);
8460 273 : MAYBE_RETURN(extensible, Nothing<bool>());
8461 273 : if (extensible.FromJust()) return Just(false);
8462 :
8463 : Isolate* isolate = receiver->GetIsolate();
8464 :
8465 : Handle<FixedArray> keys;
8466 163 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8467 : isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>());
8468 :
8469 4781 : for (int i = 0; i < keys->length(); ++i) {
8470 : Handle<Object> key(keys->get(i), isolate);
8471 : PropertyDescriptor current_desc;
8472 : Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
8473 2390 : isolate, receiver, key, ¤t_desc);
8474 2471 : MAYBE_RETURN(owned, Nothing<bool>());
8475 2363 : if (owned.FromJust()) {
8476 2363 : if (current_desc.configurable()) return Just(false);
8477 3524 : if (level == FROZEN &&
8478 3515 : PropertyDescriptor::IsDataDescriptor(¤t_desc) &&
8479 : current_desc.writable()) {
8480 : return Just(false);
8481 : }
8482 : }
8483 : }
8484 : return Just(true);
8485 : }
8486 :
8487 : } // namespace
8488 :
8489 1157 : Maybe<bool> JSReceiver::TestIntegrityLevel(Handle<JSReceiver> receiver,
8490 : IntegrityLevel level) {
8491 1157 : if (!receiver->map()->IsCustomElementsReceiverMap()) {
8492 : return JSObject::TestIntegrityLevel(Handle<JSObject>::cast(receiver),
8493 1004 : level);
8494 : }
8495 153 : return GenericTestIntegrityLevel(receiver, level);
8496 : }
8497 :
8498 253365 : Maybe<bool> JSObject::TestIntegrityLevel(Handle<JSObject> object,
8499 : IntegrityLevel level) {
8500 760022 : if (!object->map()->IsCustomElementsReceiverMap() &&
8501 506651 : !object->HasSloppyArgumentsElements()) {
8502 253255 : return Just(FastTestIntegrityLevel(*object, level));
8503 : }
8504 120 : return GenericTestIntegrityLevel(Handle<JSReceiver>::cast(object), level);
8505 : }
8506 :
8507 77283 : Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object,
8508 : ShouldThrow should_throw) {
8509 154566 : if (object->IsJSProxy()) {
8510 : return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object),
8511 73237 : should_throw);
8512 : }
8513 : DCHECK(object->IsJSObject());
8514 : return JSObject::PreventExtensions(Handle<JSObject>::cast(object),
8515 4046 : should_throw);
8516 : }
8517 :
8518 :
8519 73237 : Maybe<bool> JSProxy::PreventExtensions(Handle<JSProxy> proxy,
8520 : ShouldThrow should_throw) {
8521 : Isolate* isolate = proxy->GetIsolate();
8522 73237 : STACK_CHECK(isolate, Nothing<bool>());
8523 : Factory* factory = isolate->factory();
8524 : Handle<String> trap_name = factory->preventExtensions_string();
8525 :
8526 146454 : if (proxy->IsRevoked()) {
8527 : isolate->Throw(
8528 36 : *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
8529 : return Nothing<bool>();
8530 : }
8531 146418 : Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
8532 146418 : Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
8533 :
8534 : Handle<Object> trap;
8535 146418 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8536 : isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
8537 146382 : if (trap->IsUndefined(isolate)) {
8538 63477 : return JSReceiver::PreventExtensions(target, should_throw);
8539 : }
8540 :
8541 : Handle<Object> trap_result;
8542 : Handle<Object> args[] = {target};
8543 19428 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8544 : isolate, trap_result,
8545 : Execution::Call(isolate, trap, handler, arraysize(args), args),
8546 : Nothing<bool>());
8547 54 : if (!trap_result->BooleanValue(isolate)) {
8548 18 : RETURN_FAILURE(
8549 : isolate, should_throw,
8550 : NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
8551 : }
8552 :
8553 : // Enforce the invariant.
8554 36 : Maybe<bool> target_result = JSReceiver::IsExtensible(target);
8555 36 : MAYBE_RETURN(target_result, Nothing<bool>());
8556 36 : if (target_result.FromJust()) {
8557 : isolate->Throw(*factory->NewTypeError(
8558 18 : MessageTemplate::kProxyPreventExtensionsExtensible));
8559 : return Nothing<bool>();
8560 : }
8561 : return Just(true);
8562 : }
8563 :
8564 :
8565 4491 : Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object,
8566 : ShouldThrow should_throw) {
8567 : Isolate* isolate = object->GetIsolate();
8568 :
8569 8982 : if (!object->HasSloppyArgumentsElements()) {
8570 4436 : return PreventExtensionsWithTransition<NONE>(object, should_throw);
8571 : }
8572 :
8573 110 : if (object->IsAccessCheckNeeded() &&
8574 0 : !isolate->MayAccess(handle(isolate->context(), isolate), object)) {
8575 0 : isolate->ReportFailedAccessCheck(object);
8576 0 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
8577 0 : RETURN_FAILURE(isolate, should_throw,
8578 : NewTypeError(MessageTemplate::kNoAccess));
8579 : }
8580 :
8581 55 : if (!object->map()->is_extensible()) return Just(true);
8582 :
8583 110 : if (object->IsJSGlobalProxy()) {
8584 0 : PrototypeIterator iter(isolate, object);
8585 0 : if (iter.IsAtEnd()) return Just(true);
8586 : DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
8587 : return PreventExtensions(PrototypeIterator::GetCurrent<JSObject>(iter),
8588 0 : should_throw);
8589 : }
8590 :
8591 110 : if (object->map()->has_named_interceptor() ||
8592 : object->map()->has_indexed_interceptor()) {
8593 0 : RETURN_FAILURE(isolate, should_throw,
8594 : NewTypeError(MessageTemplate::kCannotPreventExt));
8595 : }
8596 :
8597 55 : if (!object->HasFixedTypedArrayElements()) {
8598 : // If there are fast elements we normalize.
8599 55 : Handle<NumberDictionary> dictionary = NormalizeElements(object);
8600 : DCHECK(object->HasDictionaryElements() ||
8601 : object->HasSlowArgumentsElements());
8602 :
8603 : // Make sure that we never go back to fast case.
8604 55 : object->RequireSlowElements(*dictionary);
8605 : }
8606 :
8607 : // Do a map transition, other objects with this map may still
8608 : // be extensible.
8609 : // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
8610 : Handle<Map> new_map =
8611 55 : Map::Copy(isolate, handle(object->map(), isolate), "PreventExtensions");
8612 :
8613 : new_map->set_is_extensible(false);
8614 55 : JSObject::MigrateToMap(object, new_map);
8615 : DCHECK(!object->map()->is_extensible());
8616 :
8617 : return Just(true);
8618 : }
8619 :
8620 :
8621 1012968 : Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) {
8622 2025936 : if (object->IsJSProxy()) {
8623 81249 : return JSProxy::IsExtensible(Handle<JSProxy>::cast(object));
8624 : }
8625 931719 : return Just(JSObject::IsExtensible(Handle<JSObject>::cast(object)));
8626 : }
8627 :
8628 :
8629 81249 : Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) {
8630 : Isolate* isolate = proxy->GetIsolate();
8631 81249 : STACK_CHECK(isolate, Nothing<bool>());
8632 : Factory* factory = isolate->factory();
8633 : Handle<String> trap_name = factory->isExtensible_string();
8634 :
8635 162464 : if (proxy->IsRevoked()) {
8636 : isolate->Throw(
8637 36 : *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
8638 : return Nothing<bool>();
8639 : }
8640 162428 : Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
8641 162428 : Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
8642 :
8643 : Handle<Object> trap;
8644 162428 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8645 : isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
8646 162392 : if (trap->IsUndefined(isolate)) {
8647 70948 : return JSReceiver::IsExtensible(target);
8648 : }
8649 :
8650 : Handle<Object> trap_result;
8651 : Handle<Object> args[] = {target};
8652 20496 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8653 : isolate, trap_result,
8654 : Execution::Call(isolate, trap, handler, arraysize(args), args),
8655 : Nothing<bool>());
8656 :
8657 : // Enforce the invariant.
8658 423 : Maybe<bool> target_result = JSReceiver::IsExtensible(target);
8659 423 : MAYBE_RETURN(target_result, Nothing<bool>());
8660 423 : if (target_result.FromJust() != trap_result->BooleanValue(isolate)) {
8661 : isolate->Throw(
8662 : *factory->NewTypeError(MessageTemplate::kProxyIsExtensibleInconsistent,
8663 54 : factory->ToBoolean(target_result.FromJust())));
8664 : return Nothing<bool>();
8665 : }
8666 396 : return target_result;
8667 : }
8668 :
8669 :
8670 3820202 : bool JSObject::IsExtensible(Handle<JSObject> object) {
8671 : Isolate* isolate = object->GetIsolate();
8672 7640464 : if (object->IsAccessCheckNeeded() &&
8673 40 : !isolate->MayAccess(handle(isolate->context(), isolate), object)) {
8674 : return true;
8675 : }
8676 7640361 : if (object->IsJSGlobalProxy()) {
8677 : PrototypeIterator iter(isolate, *object);
8678 2783 : if (iter.IsAtEnd()) return false;
8679 : DCHECK(iter.GetCurrent()->IsJSGlobalObject());
8680 5566 : return iter.GetCurrent<JSObject>()->map()->is_extensible();
8681 : }
8682 : return object->map()->is_extensible();
8683 : }
8684 :
8685 : namespace {
8686 :
8687 : template <typename Dictionary>
8688 6693 : void ApplyAttributesToDictionary(Isolate* isolate, ReadOnlyRoots roots,
8689 : Handle<Dictionary> dictionary,
8690 : const PropertyAttributes attributes) {
8691 6693 : int capacity = dictionary->Capacity();
8692 78693 : for (int i = 0; i < capacity; i++) {
8693 72000 : Object k;
8694 111881 : if (!dictionary->ToKey(roots, i, &k)) continue;
8695 32137 : if (k->FilterKey(ALL_PROPERTIES)) continue;
8696 32119 : PropertyDetails details = dictionary->DetailsAt(i);
8697 32119 : int attrs = attributes;
8698 : // READ_ONLY is an invalid attribute for JS setters/getters.
8699 62375 : if ((attributes & READ_ONLY) && details.kind() == kAccessor) {
8700 54 : Object v = dictionary->ValueAt(i);
8701 45 : if (v->IsAccessorPair()) attrs &= ~READ_ONLY;
8702 : }
8703 : details = details.CopyAddAttributes(static_cast<PropertyAttributes>(attrs));
8704 32119 : dictionary->DetailsAtPut(isolate, i, details);
8705 : }
8706 6693 : }
8707 :
8708 : } // namespace
8709 :
8710 : template <PropertyAttributes attrs>
8711 251526 : Maybe<bool> JSObject::PreventExtensionsWithTransition(
8712 : Handle<JSObject> object, ShouldThrow should_throw) {
8713 : STATIC_ASSERT(attrs == NONE || attrs == SEALED || attrs == FROZEN);
8714 :
8715 : // Sealing/freezing sloppy arguments or namespace objects should be handled
8716 : // elsewhere.
8717 : DCHECK(!object->HasSloppyArgumentsElements());
8718 : DCHECK_IMPLIES(object->IsJSModuleNamespace(), attrs == NONE);
8719 :
8720 : Isolate* isolate = object->GetIsolate();
8721 503089 : if (object->IsAccessCheckNeeded() &&
8722 25 : !isolate->MayAccess(handle(isolate->context(), isolate), object)) {
8723 20 : isolate->ReportFailedAccessCheck(object);
8724 20 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
8725 0 : RETURN_FAILURE(isolate, should_throw,
8726 : NewTypeError(MessageTemplate::kNoAccess));
8727 : }
8728 :
8729 4435 : if (attrs == NONE && !object->map()->is_extensible()) return Just(true);
8730 :
8731 502868 : if (object->IsJSGlobalProxy()) {
8732 90 : PrototypeIterator iter(isolate, object);
8733 90 : if (iter.IsAtEnd()) return Just(true);
8734 : DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
8735 : return PreventExtensionsWithTransition<attrs>(
8736 90 : PrototypeIterator::GetCurrent<JSObject>(iter), should_throw);
8737 : }
8738 :
8739 502683 : if (object->map()->has_named_interceptor() ||
8740 : object->map()->has_indexed_interceptor()) {
8741 : MessageTemplate message = MessageTemplate::kNone;
8742 : switch (attrs) {
8743 : case NONE:
8744 : message = MessageTemplate::kCannotPreventExt;
8745 : break;
8746 :
8747 : case SEALED:
8748 : message = MessageTemplate::kCannotSeal;
8749 : break;
8750 :
8751 : case FROZEN:
8752 : message = MessageTemplate::kCannotFreeze;
8753 : break;
8754 : }
8755 3 : RETURN_FAILURE(isolate, should_throw, NewTypeError(message));
8756 : }
8757 :
8758 : Handle<NumberDictionary> new_element_dictionary;
8759 1005011 : if (!object->HasFixedTypedArrayElements() &&
8760 502625 : !object->HasDictionaryElements() &&
8761 502398 : !object->HasSlowStringWrapperElements()) {
8762 502120 : int length = object->IsJSArray()
8763 264492 : ? Smi::ToInt(Handle<JSArray>::cast(object)->length())
8764 753179 : : object->elements()->length();
8765 502120 : new_element_dictionary =
8766 : length == 0 ? isolate->factory()->empty_slow_element_dictionary()
8767 271454 : : object->GetElementsAccessor()->Normalize(object);
8768 : }
8769 :
8770 : Handle<Symbol> transition_marker;
8771 : if (attrs == NONE) {
8772 : transition_marker = isolate->factory()->nonextensible_symbol();
8773 : } else if (attrs == SEALED) {
8774 : transition_marker = isolate->factory()->sealed_symbol();
8775 : } else {
8776 : DCHECK(attrs == FROZEN);
8777 : transition_marker = isolate->factory()->frozen_symbol();
8778 : }
8779 :
8780 : Handle<Map> old_map(object->map(), isolate);
8781 251341 : TransitionsAccessor transitions(isolate, old_map);
8782 251346 : Map transition = transitions.SearchSpecial(*transition_marker);
8783 251345 : if (!transition.is_null()) {
8784 : Handle<Map> transition_map(transition, isolate);
8785 : DCHECK(transition_map->has_dictionary_elements() ||
8786 : transition_map->has_fixed_typed_array_elements() ||
8787 : transition_map->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
8788 : DCHECK(!transition_map->is_extensible());
8789 99755 : JSObject::MigrateToMap(object, transition_map);
8790 151590 : } else if (transitions.CanHaveMoreTransitions()) {
8791 : // Create a new descriptor array with the appropriate property attributes
8792 : Handle<Map> new_map = Map::CopyForPreventExtensions(
8793 150804 : isolate, old_map, attrs, transition_marker, "CopyForPreventExtensions");
8794 150801 : JSObject::MigrateToMap(object, new_map);
8795 : } else {
8796 : DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map());
8797 : // Slow path: need to normalize properties for safety
8798 788 : NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0,
8799 : "SlowPreventExtensions");
8800 :
8801 : // Create a new map, since other objects with this map may be extensible.
8802 : // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
8803 : Handle<Map> new_map = Map::Copy(isolate, handle(object->map(), isolate),
8804 788 : "SlowCopyForPreventExtensions");
8805 : new_map->set_is_extensible(false);
8806 788 : if (!new_element_dictionary.is_null()) {
8807 : ElementsKind new_kind =
8808 : IsStringWrapperElementsKind(old_map->elements_kind())
8809 : ? SLOW_STRING_WRAPPER_ELEMENTS
8810 788 : : DICTIONARY_ELEMENTS;
8811 1576 : new_map->set_elements_kind(new_kind);
8812 : }
8813 788 : JSObject::MigrateToMap(object, new_map);
8814 :
8815 : if (attrs != NONE) {
8816 : ReadOnlyRoots roots(isolate);
8817 308 : if (object->IsJSGlobalObject()) {
8818 : Handle<GlobalDictionary> dictionary(
8819 162 : JSGlobalObject::cast(*object)->global_dictionary(), isolate);
8820 81 : ApplyAttributesToDictionary(isolate, roots, dictionary, attrs);
8821 : } else {
8822 146 : Handle<NameDictionary> dictionary(object->property_dictionary(),
8823 73 : isolate);
8824 73 : ApplyAttributesToDictionary(isolate, roots, dictionary, attrs);
8825 : }
8826 : }
8827 : }
8828 :
8829 : // Both seal and preventExtensions always go through without modifications to
8830 : // typed array elements. Freeze works only if there are no actual elements.
8831 251344 : if (object->HasFixedTypedArrayElements()) {
8832 36 : if (attrs == FROZEN &&
8833 : JSArrayBufferView::cast(*object)->byte_length() > 0) {
8834 27 : isolate->Throw(*isolate->factory()->NewTypeError(
8835 54 : MessageTemplate::kCannotFreezeArrayBufferView));
8836 : return Nothing<bool>();
8837 : }
8838 : return Just(true);
8839 : }
8840 :
8841 : DCHECK(object->map()->has_dictionary_elements() ||
8842 : object->map()->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
8843 251286 : if (!new_element_dictionary.is_null()) {
8844 502120 : object->set_elements(*new_element_dictionary);
8845 : }
8846 :
8847 502563 : if (object->elements() !=
8848 : ReadOnlyRoots(isolate).empty_slow_element_dictionary()) {
8849 14014 : Handle<NumberDictionary> dictionary(object->element_dictionary(), isolate);
8850 : // Make sure we never go back to the fast case
8851 7007 : object->RequireSlowElements(*dictionary);
8852 : if (attrs != NONE) {
8853 6539 : ApplyAttributesToDictionary(isolate, ReadOnlyRoots(isolate), dictionary,
8854 6539 : attrs);
8855 : }
8856 : }
8857 :
8858 : return Just(true);
8859 : }
8860 :
8861 :
8862 6897117 : Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object,
8863 : Representation representation,
8864 : FieldIndex index) {
8865 : Isolate* isolate = object->GetIsolate();
8866 6897129 : if (object->IsUnboxedDoubleField(index)) {
8867 : double value = object->RawFastDoublePropertyAt(index);
8868 19998 : return isolate->factory()->NewHeapNumber(value);
8869 : }
8870 13754254 : Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate);
8871 6877132 : return Object::WrapForRead(isolate, raw_value, representation);
8872 : }
8873 :
8874 : // static
8875 5507131 : MaybeHandle<Object> JSReceiver::ToPrimitive(Handle<JSReceiver> receiver,
8876 : ToPrimitiveHint hint) {
8877 : Isolate* const isolate = receiver->GetIsolate();
8878 : Handle<Object> exotic_to_prim;
8879 11014262 : ASSIGN_RETURN_ON_EXCEPTION(
8880 : isolate, exotic_to_prim,
8881 : Object::GetMethod(receiver, isolate->factory()->to_primitive_symbol()),
8882 : Object);
8883 11014252 : if (!exotic_to_prim->IsUndefined(isolate)) {
8884 : Handle<Object> hint_string =
8885 6822 : isolate->factory()->ToPrimitiveHintString(hint);
8886 : Handle<Object> result;
8887 13644 : ASSIGN_RETURN_ON_EXCEPTION(
8888 : isolate, result,
8889 : Execution::Call(isolate, exotic_to_prim, receiver, 1, &hint_string),
8890 : Object);
8891 13338 : if (result->IsPrimitive()) return result;
8892 0 : THROW_NEW_ERROR(isolate,
8893 : NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8894 : Object);
8895 : }
8896 : return OrdinaryToPrimitive(receiver, (hint == ToPrimitiveHint::kString)
8897 : ? OrdinaryToPrimitiveHint::kString
8898 5500304 : : OrdinaryToPrimitiveHint::kNumber);
8899 : }
8900 :
8901 :
8902 : // static
8903 5500304 : MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive(
8904 : Handle<JSReceiver> receiver, OrdinaryToPrimitiveHint hint) {
8905 : Isolate* const isolate = receiver->GetIsolate();
8906 16500912 : Handle<String> method_names[2];
8907 5500304 : switch (hint) {
8908 : case OrdinaryToPrimitiveHint::kNumber:
8909 6152 : method_names[0] = isolate->factory()->valueOf_string();
8910 6152 : method_names[1] = isolate->factory()->toString_string();
8911 6152 : break;
8912 : case OrdinaryToPrimitiveHint::kString:
8913 5494152 : method_names[0] = isolate->factory()->toString_string();
8914 5494152 : method_names[1] = isolate->factory()->valueOf_string();
8915 5494152 : break;
8916 : }
8917 5504247 : for (Handle<String> name : method_names) {
8918 : Handle<Object> method;
8919 11004416 : ASSIGN_RETURN_ON_EXCEPTION(isolate, method,
8920 : JSReceiver::GetProperty(isolate, receiver, name),
8921 : Object);
8922 11004380 : if (method->IsCallable()) {
8923 : Handle<Object> result;
8924 11003480 : ASSIGN_RETURN_ON_EXCEPTION(
8925 : isolate, result,
8926 : Execution::Call(isolate, method, receiver, 0, nullptr), Object);
8927 10985084 : if (result->IsPrimitive()) return result;
8928 : }
8929 : }
8930 135 : THROW_NEW_ERROR(isolate,
8931 : NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8932 : Object);
8933 : }
8934 :
8935 :
8936 : // TODO(cbruni/jkummerow): Consider moving this into elements.cc.
8937 144303 : bool JSObject::HasEnumerableElements() {
8938 : // TODO(cbruni): cleanup
8939 144303 : JSObject object = *this;
8940 144303 : switch (object->GetElementsKind()) {
8941 : case PACKED_SMI_ELEMENTS:
8942 : case PACKED_ELEMENTS:
8943 : case PACKED_DOUBLE_ELEMENTS: {
8944 : int length = object->IsJSArray()
8945 89496 : ? Smi::ToInt(JSArray::cast(object)->length())
8946 89550 : : object->elements()->length();
8947 29850 : return length > 0;
8948 : }
8949 : case HOLEY_SMI_ELEMENTS:
8950 : case HOLEY_ELEMENTS: {
8951 228222 : FixedArray elements = FixedArray::cast(object->elements());
8952 : int length = object->IsJSArray()
8953 231465 : ? Smi::ToInt(JSArray::cast(object)->length())
8954 228222 : : elements->length();
8955 : Isolate* isolate = GetIsolate();
8956 2566764 : for (int i = 0; i < length; i++) {
8957 2463786 : if (!elements->is_the_hole(isolate, i)) return true;
8958 : }
8959 : return false;
8960 : }
8961 : case HOLEY_DOUBLE_ELEMENTS: {
8962 : int length = object->IsJSArray()
8963 135 : ? Smi::ToInt(JSArray::cast(object)->length())
8964 135 : : object->elements()->length();
8965 : // Zero-length arrays would use the empty FixedArray...
8966 45 : if (length == 0) return false;
8967 : // ...so only cast to FixedDoubleArray otherwise.
8968 90 : FixedDoubleArray elements = FixedDoubleArray::cast(object->elements());
8969 45 : for (int i = 0; i < length; i++) {
8970 45 : if (!elements->is_the_hole(i)) return true;
8971 : }
8972 : return false;
8973 : }
8974 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS:
8975 :
8976 : TYPED_ARRAYS(TYPED_ARRAY_CASE)
8977 : #undef TYPED_ARRAY_CASE
8978 : {
8979 0 : int length = object->elements()->length();
8980 0 : return length > 0;
8981 : }
8982 : case DICTIONARY_ELEMENTS: {
8983 432 : NumberDictionary elements = NumberDictionary::cast(object->elements());
8984 216 : return elements->NumberOfEnumerableProperties() > 0;
8985 : }
8986 : case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
8987 : case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
8988 : // We're approximating non-empty arguments objects here.
8989 : return true;
8990 : case FAST_STRING_WRAPPER_ELEMENTS:
8991 : case SLOW_STRING_WRAPPER_ELEMENTS:
8992 0 : if (String::cast(JSValue::cast(object)->value())->length() > 0) {
8993 : return true;
8994 : }
8995 0 : return object->elements()->length() > 0;
8996 : case NO_ELEMENTS:
8997 0 : return false;
8998 : }
8999 0 : UNREACHABLE();
9000 : }
9001 :
9002 169299 : int Map::NumberOfEnumerableProperties() const {
9003 : int result = 0;
9004 169299 : DescriptorArray descs = instance_descriptors();
9005 : int limit = NumberOfOwnDescriptors();
9006 805006 : for (int i = 0; i < limit; i++) {
9007 2236971 : if ((descs->GetDetails(i).attributes() & ONLY_ENUMERABLE) == 0 &&
9008 965557 : !descs->GetKey(i)->FilterKey(ENUMERABLE_STRINGS)) {
9009 328059 : result++;
9010 : }
9011 : }
9012 169299 : return result;
9013 : }
9014 :
9015 53893637 : int Map::NextFreePropertyIndex() const {
9016 : int free_index = 0;
9017 : int number_of_own_descriptors = NumberOfOwnDescriptors();
9018 53893637 : DescriptorArray descs = instance_descriptors();
9019 471448374 : for (int i = 0; i < number_of_own_descriptors; i++) {
9020 417554671 : PropertyDetails details = descs->GetDetails(i);
9021 417554671 : if (details.location() == kField) {
9022 281659766 : int candidate = details.field_index() + details.field_width_in_words();
9023 281659766 : if (candidate > free_index) free_index = candidate;
9024 : }
9025 : }
9026 53893703 : return free_index;
9027 : }
9028 :
9029 81558 : bool Map::OnlyHasSimpleProperties() const {
9030 : // Wrapped string elements aren't explicitly stored in the elements backing
9031 : // store, but are loaded indirectly from the underlying string.
9032 79453 : return !IsStringWrapperElementsKind(elements_kind()) &&
9033 202328 : !IsSpecialReceiverMap() && !has_hidden_prototype() &&
9034 141943 : !is_dictionary_map();
9035 : }
9036 :
9037 1431 : V8_WARN_UNUSED_RESULT Maybe<bool> FastGetOwnValuesOrEntries(
9038 : Isolate* isolate, Handle<JSReceiver> receiver, bool get_entries,
9039 : Handle<FixedArray>* result) {
9040 : Handle<Map> map(JSReceiver::cast(*receiver)->map(), isolate);
9041 :
9042 1431 : if (!map->IsJSObjectMap()) return Just(false);
9043 1431 : if (!map->OnlyHasSimpleProperties()) return Just(false);
9044 :
9045 : Handle<JSObject> object(JSObject::cast(*receiver), isolate);
9046 :
9047 2862 : Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
9048 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9049 : int number_of_own_elements =
9050 5724 : object->GetElementsAccessor()->GetCapacity(*object, object->elements());
9051 : Handle<FixedArray> values_or_entries = isolate->factory()->NewFixedArray(
9052 1431 : number_of_own_descriptors + number_of_own_elements);
9053 1431 : int count = 0;
9054 :
9055 2862 : if (object->elements() != ReadOnlyRoots(isolate).empty_fixed_array()) {
9056 2016 : MAYBE_RETURN(object->GetElementsAccessor()->CollectValuesOrEntries(
9057 : isolate, object, values_or_entries, get_entries, &count,
9058 : ENUMERABLE_STRINGS),
9059 : Nothing<bool>());
9060 : }
9061 :
9062 : bool stable = object->map() == *map;
9063 :
9064 3429 : for (int index = 0; index < number_of_own_descriptors; index++) {
9065 3996 : Handle<Name> next_key(descriptors->GetKey(index), isolate);
9066 3996 : if (!next_key->IsString()) continue;
9067 : Handle<Object> prop_value;
9068 :
9069 : // Directly decode from the descriptor array if |from| did not change shape.
9070 1818 : if (stable) {
9071 1728 : PropertyDetails details = descriptors->GetDetails(index);
9072 1728 : if (!details.IsEnumerable()) continue;
9073 1233 : if (details.kind() == kData) {
9074 1197 : if (details.location() == kDescriptor) {
9075 0 : prop_value = handle(descriptors->GetStrongValue(index), isolate);
9076 : } else {
9077 1197 : Representation representation = details.representation();
9078 1197 : FieldIndex field_index = FieldIndex::ForDescriptor(*map, index);
9079 : prop_value =
9080 1197 : JSObject::FastPropertyAt(object, representation, field_index);
9081 : }
9082 : } else {
9083 72 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
9084 : isolate, prop_value,
9085 : JSReceiver::GetProperty(isolate, object, next_key),
9086 : Nothing<bool>());
9087 : stable = object->map() == *map;
9088 : }
9089 : } else {
9090 : // If the map did change, do a slower lookup. We are still guaranteed that
9091 : // the object has a simple shape, and that the key is a name.
9092 : LookupIterator it(isolate, object, next_key,
9093 90 : LookupIterator::OWN_SKIP_INTERCEPTOR);
9094 162 : if (!it.IsFound()) continue;
9095 : DCHECK(it.state() == LookupIterator::DATA ||
9096 : it.state() == LookupIterator::ACCESSOR);
9097 54 : if (!it.IsEnumerable()) continue;
9098 36 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
9099 : isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
9100 : }
9101 :
9102 1251 : if (get_entries) {
9103 837 : prop_value = MakeEntryPair(isolate, next_key, prop_value);
9104 : }
9105 :
9106 2502 : values_or_entries->set(count, *prop_value);
9107 1251 : count++;
9108 : }
9109 :
9110 : DCHECK_LE(count, values_or_entries->length());
9111 1431 : *result = FixedArray::ShrinkOrEmpty(isolate, values_or_entries, count);
9112 : return Just(true);
9113 : }
9114 :
9115 2178 : MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate,
9116 : Handle<JSReceiver> object,
9117 : PropertyFilter filter,
9118 : bool try_fast_path,
9119 : bool get_entries) {
9120 : Handle<FixedArray> values_or_entries;
9121 2178 : if (try_fast_path && filter == ENUMERABLE_STRINGS) {
9122 : Maybe<bool> fast_values_or_entries = FastGetOwnValuesOrEntries(
9123 1431 : isolate, object, get_entries, &values_or_entries);
9124 1431 : if (fast_values_or_entries.IsNothing()) return MaybeHandle<FixedArray>();
9125 1431 : if (fast_values_or_entries.FromJust()) return values_or_entries;
9126 : }
9127 :
9128 : PropertyFilter key_filter =
9129 747 : static_cast<PropertyFilter>(filter & ~ONLY_ENUMERABLE);
9130 :
9131 : Handle<FixedArray> keys;
9132 1494 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
9133 : isolate, keys,
9134 : KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, key_filter,
9135 : GetKeysConversion::kConvertToString),
9136 : MaybeHandle<FixedArray>());
9137 :
9138 747 : values_or_entries = isolate->factory()->NewFixedArray(keys->length());
9139 : int length = 0;
9140 :
9141 6288 : for (int i = 0; i < keys->length(); ++i) {
9142 2433 : Handle<Name> key = Handle<Name>::cast(handle(keys->get(i), isolate));
9143 :
9144 2433 : if (filter & ONLY_ENUMERABLE) {
9145 : PropertyDescriptor descriptor;
9146 : Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor(
9147 2433 : isolate, object, key, &descriptor);
9148 2433 : MAYBE_RETURN(did_get_descriptor, MaybeHandle<FixedArray>());
9149 4737 : if (!did_get_descriptor.FromJust() || !descriptor.enumerable()) continue;
9150 : }
9151 :
9152 : Handle<Object> value;
9153 3168 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
9154 : isolate, value, Object::GetPropertyOrElement(isolate, object, key),
9155 : MaybeHandle<FixedArray>());
9156 :
9157 1584 : if (get_entries) {
9158 : Handle<FixedArray> entry_storage =
9159 1053 : isolate->factory()->NewUninitializedFixedArray(2);
9160 2106 : entry_storage->set(0, *key);
9161 1053 : entry_storage->set(1, *value);
9162 : value = isolate->factory()->NewJSArrayWithElements(entry_storage,
9163 1053 : PACKED_ELEMENTS, 2);
9164 : }
9165 :
9166 1584 : values_or_entries->set(length, *value);
9167 1584 : length++;
9168 : }
9169 : DCHECK_LE(length, values_or_entries->length());
9170 711 : return FixedArray::ShrinkOrEmpty(isolate, values_or_entries, length);
9171 : }
9172 :
9173 909 : MaybeHandle<FixedArray> JSReceiver::GetOwnValues(Handle<JSReceiver> object,
9174 : PropertyFilter filter,
9175 : bool try_fast_path) {
9176 : return GetOwnValuesOrEntries(object->GetIsolate(), object, filter,
9177 1818 : try_fast_path, false);
9178 : }
9179 :
9180 1269 : MaybeHandle<FixedArray> JSReceiver::GetOwnEntries(Handle<JSReceiver> object,
9181 : PropertyFilter filter,
9182 : bool try_fast_path) {
9183 : return GetOwnValuesOrEntries(object->GetIsolate(), object, filter,
9184 2538 : try_fast_path, true);
9185 : }
9186 :
9187 4698 : Handle<FixedArray> JSReceiver::GetOwnElementIndices(Isolate* isolate,
9188 : Handle<JSReceiver> receiver,
9189 : Handle<JSObject> object) {
9190 : KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly,
9191 : ALL_PROPERTIES);
9192 4698 : accumulator.CollectOwnElementIndices(receiver, object);
9193 : Handle<FixedArray> keys =
9194 4698 : accumulator.GetKeys(GetKeysConversion::kKeepNumbers);
9195 : DCHECK(keys->ContainsSortedNumbers());
9196 4698 : return keys;
9197 : }
9198 :
9199 60996 : bool Map::DictionaryElementsInPrototypeChainOnly(Isolate* isolate) {
9200 60996 : if (IsDictionaryElementsKind(elements_kind())) {
9201 : return false;
9202 : }
9203 :
9204 250656 : for (PrototypeIterator iter(isolate, *this); !iter.IsAtEnd();
9205 132118 : iter.Advance()) {
9206 : // Be conservative, don't walk into proxies.
9207 278711 : if (iter.GetCurrent()->IsJSProxy()) return true;
9208 : // String wrappers have non-configurable, non-writable elements.
9209 273886 : if (iter.GetCurrent()->IsStringWrapper()) return true;
9210 136925 : JSObject current = iter.GetCurrent<JSObject>();
9211 :
9212 410775 : if (current->HasDictionaryElements() &&
9213 146557 : current->element_dictionary()->requires_slow_elements()) {
9214 : return true;
9215 : }
9216 :
9217 132118 : if (current->HasSlowArgumentsElements()) {
9218 0 : FixedArray parameter_map = FixedArray::cast(current->elements());
9219 : Object arguments = parameter_map->get(1);
9220 0 : if (NumberDictionary::cast(arguments)->requires_slow_elements()) {
9221 : return true;
9222 : }
9223 : }
9224 : }
9225 :
9226 54444 : return false;
9227 : }
9228 :
9229 :
9230 572653 : MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
9231 : Handle<Name> name,
9232 : Handle<Object> getter,
9233 : Handle<Object> setter,
9234 : PropertyAttributes attributes) {
9235 : Isolate* isolate = object->GetIsolate();
9236 :
9237 : LookupIterator it = LookupIterator::PropertyOrElement(
9238 572654 : isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
9239 572653 : return DefineAccessor(&it, getter, setter, attributes);
9240 : }
9241 :
9242 :
9243 2306359 : MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it,
9244 : Handle<Object> getter,
9245 : Handle<Object> setter,
9246 : PropertyAttributes attributes) {
9247 : Isolate* isolate = it->isolate();
9248 :
9249 768788 : it->UpdateProtector();
9250 :
9251 768788 : if (it->state() == LookupIterator::ACCESS_CHECK) {
9252 1728 : if (!it->HasAccess()) {
9253 5 : isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
9254 5 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
9255 0 : return isolate->factory()->undefined_value();
9256 : }
9257 1723 : it->Next();
9258 : }
9259 :
9260 768783 : Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
9261 : // Ignore accessors on typed arrays.
9262 796345 : if (it->IsElement() && object->HasFixedTypedArrayElements()) {
9263 0 : return it->factory()->undefined_value();
9264 : }
9265 :
9266 : DCHECK(getter->IsCallable() || getter->IsUndefined(isolate) ||
9267 : getter->IsNull(isolate) || getter->IsFunctionTemplateInfo());
9268 : DCHECK(setter->IsCallable() || setter->IsUndefined(isolate) ||
9269 : setter->IsNull(isolate) || setter->IsFunctionTemplateInfo());
9270 768783 : it->TransitionToAccessorProperty(getter, setter, attributes);
9271 :
9272 768784 : return isolate->factory()->undefined_value();
9273 : }
9274 :
9275 60341 : MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
9276 : Handle<Name> name,
9277 : Handle<AccessorInfo> info,
9278 : PropertyAttributes attributes) {
9279 : Isolate* isolate = object->GetIsolate();
9280 :
9281 : LookupIterator it = LookupIterator::PropertyOrElement(
9282 60341 : isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
9283 :
9284 : // Duplicate ACCESS_CHECK outside of GetPropertyAttributes for the case that
9285 : // the FailedAccessCheckCallbackFunction doesn't throw an exception.
9286 : //
9287 : // TODO(verwaest): Force throw an exception if the callback doesn't, so we can
9288 : // remove reliance on default return values.
9289 60341 : if (it.state() == LookupIterator::ACCESS_CHECK) {
9290 7780 : if (!it.HasAccess()) {
9291 5 : isolate->ReportFailedAccessCheck(object);
9292 5 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
9293 0 : return it.factory()->undefined_value();
9294 : }
9295 7775 : it.Next();
9296 : }
9297 :
9298 : // Ignore accessors on typed arrays.
9299 60348 : if (it.IsElement() && object->HasFixedTypedArrayElements()) {
9300 0 : return it.factory()->undefined_value();
9301 : }
9302 :
9303 60336 : CHECK(GetPropertyAttributes(&it).IsJust());
9304 :
9305 : // ES5 forbids turning a property into an accessor if it's not
9306 : // configurable. See 8.6.1 (Table 5).
9307 60397 : if (it.IsFound() && !it.IsConfigurable()) {
9308 50 : return it.factory()->undefined_value();
9309 : }
9310 :
9311 60311 : it.TransitionToAccessorPair(info, attributes);
9312 :
9313 60311 : return object;
9314 : }
9315 :
9316 117 : Object JSObject::SlowReverseLookup(Object value) {
9317 117 : if (HasFastProperties()) {
9318 : int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
9319 90 : DescriptorArray descs = map()->instance_descriptors();
9320 : bool value_is_number = value->IsNumber();
9321 513 : for (int i = 0; i < number_of_own_descriptors; i++) {
9322 432 : PropertyDetails details = descs->GetDetails(i);
9323 432 : if (details.location() == kField) {
9324 : DCHECK_EQ(kData, details.kind());
9325 0 : FieldIndex field_index = FieldIndex::ForDescriptor(map(), i);
9326 0 : if (IsUnboxedDoubleField(field_index)) {
9327 0 : if (value_is_number) {
9328 : double property = RawFastDoublePropertyAt(field_index);
9329 0 : if (property == value->Number()) {
9330 0 : return descs->GetKey(i);
9331 : }
9332 : }
9333 : } else {
9334 0 : Object property = RawFastPropertyAt(field_index);
9335 0 : if (field_index.is_double()) {
9336 : DCHECK(property->IsMutableHeapNumber());
9337 0 : if (value_is_number && property->Number() == value->Number()) {
9338 0 : return descs->GetKey(i);
9339 : }
9340 0 : } else if (property == value) {
9341 0 : return descs->GetKey(i);
9342 : }
9343 : }
9344 : } else {
9345 : DCHECK_EQ(kDescriptor, details.location());
9346 432 : if (details.kind() == kData) {
9347 810 : if (descs->GetStrongValue(i) == value) {
9348 9 : return descs->GetKey(i);
9349 : }
9350 : }
9351 : }
9352 : }
9353 162 : return GetReadOnlyRoots().undefined_value();
9354 54 : } else if (IsJSGlobalObject()) {
9355 54 : return JSGlobalObject::cast(*this)->global_dictionary()->SlowReverseLookup(
9356 27 : value);
9357 : } else {
9358 0 : return property_dictionary()->SlowReverseLookup(value);
9359 : }
9360 : }
9361 :
9362 24895461 : Handle<Map> Map::RawCopy(Isolate* isolate, Handle<Map> map, int instance_size,
9363 : int inobject_properties) {
9364 : Handle<Map> result = isolate->factory()->NewMap(
9365 : map->instance_type(), instance_size, TERMINAL_FAST_ELEMENTS_KIND,
9366 24895475 : inobject_properties);
9367 : Handle<Object> prototype(map->prototype(), isolate);
9368 24895450 : Map::SetPrototype(isolate, result, prototype);
9369 49790942 : result->set_constructor_or_backpointer(map->GetConstructor());
9370 : result->set_bit_field(map->bit_field());
9371 : result->set_bit_field2(map->bit_field2());
9372 : int new_bit_field3 = map->bit_field3();
9373 : new_bit_field3 = OwnsDescriptorsBit::update(new_bit_field3, true);
9374 : new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0);
9375 : new_bit_field3 = EnumLengthBits::update(new_bit_field3,
9376 : kInvalidEnumCacheSentinel);
9377 24895475 : new_bit_field3 = IsDeprecatedBit::update(new_bit_field3, false);
9378 24895463 : if (!map->is_dictionary_map()) {
9379 23917123 : new_bit_field3 = IsUnstableBit::update(new_bit_field3, false);
9380 : }
9381 49790939 : result->set_bit_field3(new_bit_field3);
9382 24895476 : return result;
9383 : }
9384 :
9385 679572 : Handle<Map> Map::Normalize(Isolate* isolate, Handle<Map> fast_map,
9386 : PropertyNormalizationMode mode, const char* reason) {
9387 : DCHECK(!fast_map->is_dictionary_map());
9388 :
9389 2037455 : Handle<Object> maybe_cache(isolate->native_context()->normalized_map_cache(),
9390 679153 : isolate);
9391 : bool use_cache =
9392 1873325 : !fast_map->is_prototype_map() && !maybe_cache->IsUndefined(isolate);
9393 : Handle<NormalizedMapCache> cache;
9394 679153 : if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache);
9395 :
9396 : Handle<Map> new_map;
9397 1873103 : if (use_cache && cache->Get(fast_map, mode).ToHandle(&new_map)) {
9398 : #ifdef VERIFY_HEAP
9399 : if (FLAG_verify_heap) new_map->DictionaryMapVerify(isolate);
9400 : #endif
9401 : #ifdef ENABLE_SLOW_DCHECKS
9402 : if (FLAG_enable_slow_asserts) {
9403 : // The cached map should match newly created normalized map bit-by-bit,
9404 : // except for the code cache, which can contain some ICs which can be
9405 : // applied to the shared map, dependent code and weak cell cache.
9406 : Handle<Map> fresh = Map::CopyNormalized(isolate, fast_map, mode);
9407 :
9408 : if (new_map->is_prototype_map()) {
9409 : // For prototype maps, the PrototypeInfo is not copied.
9410 : DCHECK_EQ(0, memcmp(reinterpret_cast<void*>(fresh->address()),
9411 : reinterpret_cast<void*>(new_map->address()),
9412 : kTransitionsOrPrototypeInfoOffset));
9413 : DCHECK_EQ(fresh->raw_transitions(),
9414 : MaybeObject::FromObject(Smi::kZero));
9415 : STATIC_ASSERT(kDescriptorsOffset ==
9416 : kTransitionsOrPrototypeInfoOffset + kTaggedSize);
9417 : DCHECK_EQ(
9418 : 0,
9419 : memcmp(
9420 : HeapObject::RawField(*fresh, kDescriptorsOffset).ToVoidPtr(),
9421 : HeapObject::RawField(*new_map, kDescriptorsOffset).ToVoidPtr(),
9422 : kDependentCodeOffset - kDescriptorsOffset));
9423 : } else {
9424 : DCHECK_EQ(0, memcmp(reinterpret_cast<void*>(fresh->address()),
9425 : reinterpret_cast<void*>(new_map->address()),
9426 : Map::kDependentCodeOffset));
9427 : }
9428 : STATIC_ASSERT(Map::kPrototypeValidityCellOffset ==
9429 : Map::kDependentCodeOffset + kTaggedSize);
9430 : int offset = Map::kPrototypeValidityCellOffset + kTaggedSize;
9431 : DCHECK_EQ(0, memcmp(reinterpret_cast<void*>(fresh->address() + offset),
9432 : reinterpret_cast<void*>(new_map->address() + offset),
9433 : Map::kSize - offset));
9434 : }
9435 : #endif
9436 : } else {
9437 244051 : new_map = Map::CopyNormalized(isolate, fast_map, mode);
9438 244052 : if (use_cache) {
9439 161873 : cache->Set(fast_map, new_map);
9440 161873 : isolate->counters()->maps_normalized()->Increment();
9441 : }
9442 244052 : if (FLAG_trace_maps) {
9443 844 : LOG(isolate, MapEvent("Normalize", *fast_map, *new_map, reason));
9444 : }
9445 : }
9446 679153 : fast_map->NotifyLeafMapLayoutChange(isolate);
9447 679154 : return new_map;
9448 : }
9449 :
9450 244160 : Handle<Map> Map::CopyNormalized(Isolate* isolate, Handle<Map> map,
9451 : PropertyNormalizationMode mode) {
9452 : int new_instance_size = map->instance_size();
9453 244161 : if (mode == CLEAR_INOBJECT_PROPERTIES) {
9454 67784 : new_instance_size -= map->GetInObjectProperties() * kTaggedSize;
9455 : }
9456 :
9457 : Handle<Map> result = RawCopy(
9458 : isolate, map, new_instance_size,
9459 420538 : mode == CLEAR_INOBJECT_PROPERTIES ? 0 : map->GetInObjectProperties());
9460 : // Clear the unused_property_fields explicitly as this field should not
9461 : // be accessed for normalized maps.
9462 244162 : result->SetInObjectUnusedPropertyFields(0);
9463 244162 : result->set_is_dictionary_map(true);
9464 244163 : result->set_is_migration_target(false);
9465 244161 : result->set_may_have_interesting_symbols(true);
9466 244163 : result->set_construction_counter(kNoSlackTracking);
9467 :
9468 : #ifdef VERIFY_HEAP
9469 : if (FLAG_verify_heap) result->DictionaryMapVerify(isolate);
9470 : #endif
9471 :
9472 244163 : return result;
9473 : }
9474 :
9475 : // Return an immutable prototype exotic object version of the input map.
9476 : // Never even try to cache it in the transition tree, as it is intended
9477 : // for the global object and its prototype chain, and excluding it saves
9478 : // memory on the map transition tree.
9479 :
9480 : // static
9481 6 : Handle<Map> Map::TransitionToImmutableProto(Isolate* isolate, Handle<Map> map) {
9482 6 : Handle<Map> new_map = Map::Copy(isolate, map, "ImmutablePrototype");
9483 6 : new_map->set_is_immutable_proto(true);
9484 6 : return new_map;
9485 : }
9486 :
9487 : namespace {
9488 : void EnsureInitialMap(Isolate* isolate, Handle<Map> map) {
9489 : #ifdef DEBUG
9490 : // Strict function maps have Function as a constructor but the
9491 : // Function's initial map is a sloppy function map. Same holds for
9492 : // GeneratorFunction / AsyncFunction and its initial map.
9493 : Object constructor = map->GetConstructor();
9494 : DCHECK(constructor->IsJSFunction());
9495 : DCHECK(*map == JSFunction::cast(constructor)->initial_map() ||
9496 : *map == *isolate->strict_function_map() ||
9497 : *map == *isolate->strict_function_with_name_map() ||
9498 : *map == *isolate->generator_function_map() ||
9499 : *map == *isolate->generator_function_with_name_map() ||
9500 : *map == *isolate->generator_function_with_home_object_map() ||
9501 : *map == *isolate->generator_function_with_name_and_home_object_map() ||
9502 : *map == *isolate->async_function_map() ||
9503 : *map == *isolate->async_function_with_name_map() ||
9504 : *map == *isolate->async_function_with_home_object_map() ||
9505 : *map == *isolate->async_function_with_name_and_home_object_map());
9506 : #endif
9507 : // Initial maps must always own their descriptors and it's descriptor array
9508 : // does not contain descriptors that do not belong to the map.
9509 : DCHECK(map->owns_descriptors());
9510 : DCHECK_EQ(map->NumberOfOwnDescriptors(),
9511 : map->instance_descriptors()->number_of_descriptors());
9512 : }
9513 : } // namespace
9514 :
9515 : // static
9516 111 : Handle<Map> Map::CopyInitialMapNormalized(Isolate* isolate, Handle<Map> map,
9517 : PropertyNormalizationMode mode) {
9518 : EnsureInitialMap(isolate, map);
9519 111 : return CopyNormalized(isolate, map, mode);
9520 : }
9521 :
9522 : // static
9523 461357 : Handle<Map> Map::CopyInitialMap(Isolate* isolate, Handle<Map> map,
9524 : int instance_size, int inobject_properties,
9525 : int unused_property_fields) {
9526 : EnsureInitialMap(isolate, map);
9527 : Handle<Map> result =
9528 461357 : RawCopy(isolate, map, instance_size, inobject_properties);
9529 :
9530 : // Please note instance_type and instance_size are set when allocated.
9531 461364 : result->SetInObjectUnusedPropertyFields(unused_property_fields);
9532 :
9533 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9534 461362 : if (number_of_own_descriptors > 0) {
9535 : // The copy will use the same descriptors array.
9536 : result->UpdateDescriptors(isolate, map->instance_descriptors(),
9537 : map->GetLayoutDescriptor(),
9538 12726 : number_of_own_descriptors);
9539 :
9540 : DCHECK_EQ(result->NumberOfFields(),
9541 : result->GetInObjectProperties() - result->UnusedPropertyFields());
9542 : }
9543 :
9544 461363 : return result;
9545 : }
9546 :
9547 24189923 : Handle<Map> Map::CopyDropDescriptors(Isolate* isolate, Handle<Map> map) {
9548 : Handle<Map> result =
9549 : RawCopy(isolate, map, map->instance_size(),
9550 72569616 : map->IsJSObjectMap() ? map->GetInObjectProperties() : 0);
9551 :
9552 : // Please note instance_type and instance_size are set when allocated.
9553 24189953 : if (map->IsJSObjectMap()) {
9554 24189731 : result->CopyUnusedPropertyFields(*map);
9555 : }
9556 24189942 : map->NotifyLeafMapLayoutChange(isolate);
9557 24189951 : return result;
9558 : }
9559 :
9560 5292489 : Handle<Map> Map::ShareDescriptor(Isolate* isolate, Handle<Map> map,
9561 : Handle<DescriptorArray> descriptors,
9562 : Descriptor* descriptor) {
9563 : // Sanity check. This path is only to be taken if the map owns its descriptor
9564 : // array, implying that its NumberOfOwnDescriptors equals the number of
9565 : // descriptors in the descriptor array.
9566 : DCHECK_EQ(map->NumberOfOwnDescriptors(),
9567 : map->instance_descriptors()->number_of_descriptors());
9568 :
9569 5292489 : Handle<Map> result = CopyDropDescriptors(isolate, map);
9570 : Handle<Name> name = descriptor->GetKey();
9571 :
9572 : // Properly mark the {result} if the {name} is an "interesting symbol".
9573 5292493 : if (name->IsInterestingSymbol()) {
9574 64 : result->set_may_have_interesting_symbols(true);
9575 : }
9576 :
9577 : // Ensure there's space for the new descriptor in the shared descriptor array.
9578 5292493 : if (descriptors->number_of_slack_descriptors() == 0) {
9579 2272874 : int old_size = descriptors->number_of_descriptors();
9580 2272874 : if (old_size == 0) {
9581 : descriptors = DescriptorArray::Allocate(isolate, 0, 1);
9582 : } else {
9583 2272504 : int slack = SlackForArraySize(old_size, kMaxNumberOfDescriptors);
9584 2272504 : EnsureDescriptorSlack(isolate, map, slack);
9585 4545014 : descriptors = handle(map->instance_descriptors(), isolate);
9586 : }
9587 : }
9588 :
9589 : Handle<LayoutDescriptor> layout_descriptor =
9590 : FLAG_unbox_double_fields
9591 : ? LayoutDescriptor::ShareAppend(isolate, map,
9592 : descriptor->GetDetails())
9593 5292494 : : handle(LayoutDescriptor::FastPointerLayout(), isolate);
9594 :
9595 : {
9596 : DisallowHeapAllocation no_gc;
9597 5292490 : descriptors->Append(descriptor);
9598 5292494 : result->InitializeDescriptors(isolate, *descriptors, *layout_descriptor);
9599 : }
9600 :
9601 : DCHECK(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1);
9602 5292492 : ConnectTransition(isolate, map, result, name, SIMPLE_PROPERTY_TRANSITION);
9603 :
9604 5292491 : return result;
9605 : }
9606 :
9607 14039561 : void Map::ConnectTransition(Isolate* isolate, Handle<Map> parent,
9608 : Handle<Map> child, Handle<Name> name,
9609 : SimpleTransitionFlag flag) {
9610 : DCHECK_IMPLIES(name->IsInterestingSymbol(),
9611 : child->may_have_interesting_symbols());
9612 : DCHECK_IMPLIES(parent->may_have_interesting_symbols(),
9613 : child->may_have_interesting_symbols());
9614 : // Do not track transitions during bootstrap except for element transitions.
9615 21586529 : if (isolate->bootstrapper()->IsActive() &&
9616 : !name.is_identical_to(isolate->factory()->elements_transition_symbol())) {
9617 7548603 : if (FLAG_trace_maps) {
9618 4900 : LOG(isolate,
9619 : MapEvent("Transition", *parent, *child,
9620 : child->is_prototype_map() ? "prototype" : "", *name));
9621 : }
9622 14036708 : return;
9623 : }
9624 12976224 : if (!parent->GetBackPointer()->IsUndefined(isolate)) {
9625 5529598 : parent->set_owns_descriptors(false);
9626 : } else {
9627 : // |parent| is initial map and it must keep the ownership, there must be no
9628 : // descriptors in the descriptors array that do not belong to the map.
9629 : DCHECK(parent->owns_descriptors());
9630 : DCHECK_EQ(parent->NumberOfOwnDescriptors(),
9631 : parent->instance_descriptors()->number_of_descriptors());
9632 : }
9633 6488118 : if (parent->is_prototype_map()) {
9634 : DCHECK(child->is_prototype_map());
9635 0 : if (FLAG_trace_maps) {
9636 0 : LOG(isolate, MapEvent("Transition", *parent, *child, "prototype", *name));
9637 : }
9638 : } else {
9639 6488118 : TransitionsAccessor(isolate, parent).Insert(name, child, flag);
9640 6488105 : if (FLAG_trace_maps) {
9641 4887 : LOG(isolate, MapEvent("Transition", *parent, *child, "", *name));
9642 : }
9643 : }
9644 : }
9645 :
9646 18225476 : Handle<Map> Map::CopyReplaceDescriptors(
9647 1408 : Isolate* isolate, Handle<Map> map, Handle<DescriptorArray> descriptors,
9648 : Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag,
9649 : MaybeHandle<Name> maybe_name, const char* reason,
9650 : SimpleTransitionFlag simple_flag) {
9651 : DCHECK(descriptors->IsSortedNoDuplicates());
9652 :
9653 18225476 : Handle<Map> result = CopyDropDescriptors(isolate, map);
9654 :
9655 : // Properly mark the {result} if the {name} is an "interesting symbol".
9656 : Handle<Name> name;
9657 30641025 : if (maybe_name.ToHandle(&name) && name->IsInterestingSymbol()) {
9658 1024987 : result->set_may_have_interesting_symbols(true);
9659 : }
9660 :
9661 18225498 : if (!map->is_prototype_map()) {
9662 43011863 : if (flag == INSERT_TRANSITION &&
9663 31541755 : TransitionsAccessor(isolate, map).CanHaveMoreTransitions()) {
9664 8602233 : result->InitializeDescriptors(isolate, *descriptors, *layout_descriptor);
9665 :
9666 : DCHECK(!maybe_name.is_null());
9667 8602243 : ConnectTransition(isolate, map, result, name, simple_flag);
9668 : } else {
9669 5735055 : descriptors->GeneralizeAllFields();
9670 : result->InitializeDescriptors(isolate, *descriptors,
9671 5735068 : LayoutDescriptor::FastPointerLayout());
9672 : }
9673 : } else {
9674 3888207 : result->InitializeDescriptors(isolate, *descriptors, *layout_descriptor);
9675 : }
9676 36454901 : if (FLAG_trace_maps &&
9677 : // Mirror conditions above that did not call ConnectTransition().
9678 3255 : (map->is_prototype_map() ||
9679 : !(flag == INSERT_TRANSITION &&
9680 2551 : TransitionsAccessor(isolate, map).CanHaveMoreTransitions()))) {
9681 3520 : LOG(isolate, MapEvent("ReplaceDescriptors", *map, *result, reason,
9682 : maybe_name.is_null() ? Name() : *name));
9683 : }
9684 18225471 : return result;
9685 : }
9686 :
9687 :
9688 : // Creates transition tree starting from |split_map| and adding all descriptors
9689 : // starting from descriptor with index |split_map|.NumberOfOwnDescriptors().
9690 : // The way how it is done is tricky because of GC and special descriptors
9691 : // marking logic.
9692 20791 : Handle<Map> Map::AddMissingTransitions(
9693 : Isolate* isolate, Handle<Map> split_map,
9694 : Handle<DescriptorArray> descriptors,
9695 : Handle<LayoutDescriptor> full_layout_descriptor) {
9696 : DCHECK(descriptors->IsSortedNoDuplicates());
9697 : int split_nof = split_map->NumberOfOwnDescriptors();
9698 20791 : int nof_descriptors = descriptors->number_of_descriptors();
9699 : DCHECK_LT(split_nof, nof_descriptors);
9700 :
9701 : // Start with creating last map which will own full descriptors array.
9702 : // This is necessary to guarantee that GC will mark the whole descriptor
9703 : // array if any of the allocations happening below fail.
9704 : // Number of unused properties is temporarily incorrect and the layout
9705 : // descriptor could unnecessarily be in slow mode but we will fix after
9706 : // all the other intermediate maps are created.
9707 : // Also the last map might have interesting symbols, we temporarily set
9708 : // the flag and clear it right before the descriptors are installed. This
9709 : // makes heap verification happy and ensures the flag ends up accurate.
9710 20791 : Handle<Map> last_map = CopyDropDescriptors(isolate, split_map);
9711 : last_map->InitializeDescriptors(isolate, *descriptors,
9712 20791 : *full_layout_descriptor);
9713 20791 : last_map->SetInObjectUnusedPropertyFields(0);
9714 20791 : last_map->set_may_have_interesting_symbols(true);
9715 :
9716 : // During creation of intermediate maps we violate descriptors sharing
9717 : // invariant since the last map is not yet connected to the transition tree
9718 : // we create here. But it is safe because GC never trims map's descriptors
9719 : // if there are no dead transitions from that map and this is exactly the
9720 : // case for all the intermediate maps we create here.
9721 : Handle<Map> map = split_map;
9722 51422 : for (int i = split_nof; i < nof_descriptors - 1; ++i) {
9723 30631 : Handle<Map> new_map = CopyDropDescriptors(isolate, map);
9724 : InstallDescriptors(isolate, map, new_map, i, descriptors,
9725 30631 : full_layout_descriptor);
9726 :
9727 30631 : map = new_map;
9728 : }
9729 20791 : map->NotifyLeafMapLayoutChange(isolate);
9730 20791 : last_map->set_may_have_interesting_symbols(false);
9731 : InstallDescriptors(isolate, map, last_map, nof_descriptors - 1, descriptors,
9732 20791 : full_layout_descriptor);
9733 20791 : return last_map;
9734 : }
9735 :
9736 :
9737 : // Since this method is used to rewrite an existing transition tree, it can
9738 : // always insert transitions without checking.
9739 51422 : void Map::InstallDescriptors(Isolate* isolate, Handle<Map> parent,
9740 : Handle<Map> child, int new_descriptor,
9741 : Handle<DescriptorArray> descriptors,
9742 : Handle<LayoutDescriptor> full_layout_descriptor) {
9743 : DCHECK(descriptors->IsSortedNoDuplicates());
9744 :
9745 102844 : child->SetInstanceDescriptors(isolate, *descriptors, new_descriptor + 1);
9746 51422 : child->CopyUnusedPropertyFields(*parent);
9747 51422 : PropertyDetails details = descriptors->GetDetails(new_descriptor);
9748 51422 : if (details.location() == kField) {
9749 49538 : child->AccountAddedPropertyField();
9750 : }
9751 :
9752 : if (FLAG_unbox_double_fields) {
9753 : Handle<LayoutDescriptor> layout_descriptor =
9754 : LayoutDescriptor::AppendIfFastOrUseFull(isolate, parent, details,
9755 51422 : full_layout_descriptor);
9756 51422 : child->set_layout_descriptor(*layout_descriptor);
9757 : #ifdef VERIFY_HEAP
9758 : // TODO(ishell): remove these checks from VERIFY_HEAP mode.
9759 : if (FLAG_verify_heap) {
9760 : CHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
9761 : }
9762 : #else
9763 : SLOW_DCHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
9764 : #endif
9765 102844 : child->set_visitor_id(Map::GetVisitorId(*child));
9766 : }
9767 :
9768 102844 : Handle<Name> name = handle(descriptors->GetKey(new_descriptor), isolate);
9769 102781 : if (parent->may_have_interesting_symbols() || name->IsInterestingSymbol()) {
9770 300 : child->set_may_have_interesting_symbols(true);
9771 : }
9772 51422 : ConnectTransition(isolate, parent, child, name, SIMPLE_PROPERTY_TRANSITION);
9773 51422 : }
9774 :
9775 173297 : Handle<Map> Map::CopyAsElementsKind(Isolate* isolate, Handle<Map> map,
9776 : ElementsKind kind, TransitionFlag flag) {
9777 : // Only certain objects are allowed to have non-terminal fast transitional
9778 : // elements kinds.
9779 : DCHECK(map->IsJSObjectMap());
9780 : DCHECK_IMPLIES(
9781 : !map->CanHaveFastTransitionableElementsKind(),
9782 : IsDictionaryElementsKind(kind) || IsTerminalElementsKind(kind));
9783 :
9784 : Map maybe_elements_transition_map;
9785 173297 : if (flag == INSERT_TRANSITION) {
9786 : // Ensure we are requested to add elements kind transition "near the root".
9787 : DCHECK_EQ(map->FindRootMap(isolate)->NumberOfOwnDescriptors(),
9788 : map->NumberOfOwnDescriptors());
9789 :
9790 171483 : maybe_elements_transition_map = map->ElementsTransitionMap();
9791 : DCHECK(maybe_elements_transition_map.is_null() ||
9792 : (maybe_elements_transition_map->elements_kind() ==
9793 : DICTIONARY_ELEMENTS &&
9794 : kind == DICTIONARY_ELEMENTS));
9795 : DCHECK(!IsFastElementsKind(kind) ||
9796 : IsMoreGeneralElementsKindTransition(map->elements_kind(), kind));
9797 : DCHECK(kind != map->elements_kind());
9798 : }
9799 :
9800 : bool insert_transition =
9801 171483 : flag == INSERT_TRANSITION &&
9802 435227 : TransitionsAccessor(isolate, map).CanHaveMoreTransitions() &&
9803 1814 : maybe_elements_transition_map.is_null();
9804 :
9805 173297 : if (insert_transition) {
9806 90447 : Handle<Map> new_map = CopyForElementsTransition(isolate, map);
9807 180894 : new_map->set_elements_kind(kind);
9808 :
9809 : Handle<Name> name = isolate->factory()->elements_transition_symbol();
9810 90447 : ConnectTransition(isolate, map, new_map, name, SPECIAL_TRANSITION);
9811 90447 : return new_map;
9812 : }
9813 :
9814 : // Create a new free-floating map only if we are not allowed to store it.
9815 82850 : Handle<Map> new_map = Copy(isolate, map, "CopyAsElementsKind");
9816 165700 : new_map->set_elements_kind(kind);
9817 82850 : return new_map;
9818 : }
9819 :
9820 671 : Handle<Map> Map::AsLanguageMode(Isolate* isolate, Handle<Map> initial_map,
9821 : Handle<SharedFunctionInfo> shared_info) {
9822 : DCHECK_EQ(JS_FUNCTION_TYPE, initial_map->instance_type());
9823 : // Initial map for sloppy mode function is stored in the function
9824 : // constructor. Initial maps for strict mode are cached as special transitions
9825 : // using |strict_function_transition_symbol| as a key.
9826 671 : if (is_sloppy(shared_info->language_mode())) return initial_map;
9827 :
9828 459 : Handle<Map> function_map(Map::cast(isolate->native_context()->get(
9829 : shared_info->function_map_index())),
9830 306 : isolate);
9831 :
9832 : STATIC_ASSERT(LanguageModeSize == 2);
9833 : DCHECK_EQ(LanguageMode::kStrict, shared_info->language_mode());
9834 : Handle<Symbol> transition_symbol =
9835 : isolate->factory()->strict_function_transition_symbol();
9836 : Map maybe_transition = TransitionsAccessor(isolate, initial_map)
9837 153 : .SearchSpecial(*transition_symbol);
9838 153 : if (!maybe_transition.is_null()) {
9839 : return handle(maybe_transition, isolate);
9840 : }
9841 117 : initial_map->NotifyLeafMapLayoutChange(isolate);
9842 :
9843 : // Create new map taking descriptors from the |function_map| and all
9844 : // the other details from the |initial_map|.
9845 : Handle<Map> map =
9846 : Map::CopyInitialMap(isolate, function_map, initial_map->instance_size(),
9847 : initial_map->GetInObjectProperties(),
9848 351 : initial_map->UnusedPropertyFields());
9849 234 : map->SetConstructor(initial_map->GetConstructor());
9850 117 : map->set_prototype(initial_map->prototype());
9851 117 : map->set_construction_counter(initial_map->construction_counter());
9852 :
9853 117 : if (TransitionsAccessor(isolate, initial_map).CanHaveMoreTransitions()) {
9854 : Map::ConnectTransition(isolate, initial_map, map, transition_symbol,
9855 117 : SPECIAL_TRANSITION);
9856 : }
9857 117 : return map;
9858 : }
9859 :
9860 90447 : Handle<Map> Map::CopyForElementsTransition(Isolate* isolate, Handle<Map> map) {
9861 : DCHECK(!map->is_prototype_map());
9862 90447 : Handle<Map> new_map = CopyDropDescriptors(isolate, map);
9863 :
9864 90447 : if (map->owns_descriptors()) {
9865 : // In case the map owned its own descriptors, share the descriptors and
9866 : // transfer ownership to the new map.
9867 : // The properties did not change, so reuse descriptors.
9868 : new_map->InitializeDescriptors(isolate, map->instance_descriptors(),
9869 271167 : map->GetLayoutDescriptor());
9870 : } else {
9871 : // In case the map did not own its own descriptors, a split is forced by
9872 : // copying the map; creating a new descriptor array cell.
9873 116 : Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
9874 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9875 : Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
9876 : isolate, descriptors, number_of_own_descriptors);
9877 : Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9878 116 : isolate);
9879 : new_map->InitializeDescriptors(isolate, *new_descriptors,
9880 58 : *new_layout_descriptor);
9881 : }
9882 90447 : return new_map;
9883 : }
9884 :
9885 5788758 : Handle<Map> Map::Copy(Isolate* isolate, Handle<Map> map, const char* reason) {
9886 11577535 : Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
9887 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9888 : Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
9889 5788757 : isolate, descriptors, number_of_own_descriptors);
9890 : Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9891 11577525 : isolate);
9892 : return CopyReplaceDescriptors(
9893 : isolate, map, new_descriptors, new_layout_descriptor, OMIT_TRANSITION,
9894 5788763 : MaybeHandle<Name>(), reason, SPECIAL_TRANSITION);
9895 : }
9896 :
9897 :
9898 94202 : Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) {
9899 : Handle<Map> copy =
9900 188407 : Copy(isolate, handle(isolate->object_function()->initial_map(), isolate),
9901 188408 : "MapCreate");
9902 :
9903 : // Check that we do not overflow the instance size when adding the extra
9904 : // inobject properties. If the instance size overflows, we allocate as many
9905 : // properties as we can as inobject properties.
9906 94205 : if (inobject_properties > JSObject::kMaxInObjectProperties) {
9907 : inobject_properties = JSObject::kMaxInObjectProperties;
9908 : }
9909 :
9910 : int new_instance_size =
9911 94205 : JSObject::kHeaderSize + kTaggedSize * inobject_properties;
9912 :
9913 : // Adjust the map with the extra inobject properties.
9914 94205 : copy->set_instance_size(new_instance_size);
9915 94205 : copy->SetInObjectPropertiesStartInWords(JSObject::kHeaderSize / kTaggedSize);
9916 : DCHECK_EQ(copy->GetInObjectProperties(), inobject_properties);
9917 94205 : copy->SetInObjectUnusedPropertyFields(inobject_properties);
9918 188410 : copy->set_visitor_id(Map::GetVisitorId(*copy));
9919 94204 : return copy;
9920 : }
9921 :
9922 150805 : Handle<Map> Map::CopyForPreventExtensions(Isolate* isolate, Handle<Map> map,
9923 : PropertyAttributes attrs_to_add,
9924 : Handle<Symbol> transition_marker,
9925 : const char* reason) {
9926 : int num_descriptors = map->NumberOfOwnDescriptors();
9927 : Handle<DescriptorArray> new_desc = DescriptorArray::CopyUpToAddAttributes(
9928 : isolate, handle(map->instance_descriptors(), isolate), num_descriptors,
9929 301625 : attrs_to_add);
9930 : Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9931 301621 : isolate);
9932 : Handle<Map> new_map = CopyReplaceDescriptors(
9933 : isolate, map, new_desc, new_layout_descriptor, INSERT_TRANSITION,
9934 150807 : transition_marker, reason, SPECIAL_TRANSITION);
9935 : new_map->set_is_extensible(false);
9936 150814 : if (!IsFixedTypedArrayElementsKind(map->elements_kind())) {
9937 : ElementsKind new_kind = IsStringWrapperElementsKind(map->elements_kind())
9938 : ? SLOW_STRING_WRAPPER_ELEMENTS
9939 150764 : : DICTIONARY_ELEMENTS;
9940 301524 : new_map->set_elements_kind(new_kind);
9941 : }
9942 150810 : return new_map;
9943 : }
9944 :
9945 : namespace {
9946 :
9947 6519392 : bool CanHoldValue(DescriptorArray descriptors, int descriptor,
9948 : PropertyConstness constness, Object value) {
9949 6519392 : PropertyDetails details = descriptors->GetDetails(descriptor);
9950 6519392 : if (details.location() == kField) {
9951 6503570 : if (details.kind() == kData) {
9952 6503569 : return IsGeneralizableTo(constness, details.constness()) &&
9953 19286655 : value->FitsRepresentation(details.representation()) &&
9954 12783086 : descriptors->GetFieldType(descriptor)->NowContains(value);
9955 : } else {
9956 : DCHECK_EQ(kAccessor, details.kind());
9957 : return false;
9958 : }
9959 :
9960 : } else {
9961 : DCHECK_EQ(kDescriptor, details.location());
9962 : DCHECK_EQ(PropertyConstness::kConst, details.constness());
9963 15822 : if (details.kind() == kData) {
9964 : DCHECK(!FLAG_track_constant_fields);
9965 : DCHECK(descriptors->GetStrongValue(descriptor) != value ||
9966 : value->FitsRepresentation(details.representation()));
9967 31644 : return descriptors->GetStrongValue(descriptor) == value;
9968 : } else {
9969 : DCHECK_EQ(kAccessor, details.kind());
9970 : return false;
9971 : }
9972 : }
9973 : UNREACHABLE();
9974 : }
9975 :
9976 6519392 : Handle<Map> UpdateDescriptorForValue(Isolate* isolate, Handle<Map> map,
9977 : int descriptor,
9978 : PropertyConstness constness,
9979 : Handle<Object> value) {
9980 13038789 : if (CanHoldValue(map->instance_descriptors(), descriptor, constness,
9981 13038788 : *value)) {
9982 6256620 : return map;
9983 : }
9984 :
9985 : PropertyAttributes attributes =
9986 525548 : map->instance_descriptors()->GetDetails(descriptor).attributes();
9987 262774 : Representation representation = value->OptimalRepresentation();
9988 262776 : Handle<FieldType> type = value->OptimalType(isolate, representation);
9989 :
9990 262774 : MapUpdater mu(isolate, map);
9991 : return mu.ReconfigureToDataField(descriptor, attributes, constness,
9992 262777 : representation, type);
9993 : }
9994 :
9995 : } // namespace
9996 :
9997 : // static
9998 1218767 : Handle<Map> Map::PrepareForDataProperty(Isolate* isolate, Handle<Map> map,
9999 : int descriptor,
10000 : PropertyConstness constness,
10001 : Handle<Object> value) {
10002 : // Dictionaries can store any property value.
10003 : DCHECK(!map->is_dictionary_map());
10004 : // Update to the newest map before storing the property.
10005 : return UpdateDescriptorForValue(isolate, Update(isolate, map), descriptor,
10006 1218767 : constness, value);
10007 : }
10008 :
10009 22368830 : Handle<Map> Map::TransitionToDataProperty(Isolate* isolate, Handle<Map> map,
10010 : Handle<Name> name,
10011 : Handle<Object> value,
10012 : PropertyAttributes attributes,
10013 : PropertyConstness constness,
10014 : StoreOrigin store_origin) {
10015 : RuntimeCallTimerScope stats_scope(
10016 : isolate, *map,
10017 : map->is_prototype_map()
10018 : ? RuntimeCallCounterId::kPrototypeMap_TransitionToDataProperty
10019 22368839 : : RuntimeCallCounterId::kMap_TransitionToDataProperty);
10020 :
10021 : DCHECK(name->IsUniqueName());
10022 : DCHECK(!map->is_dictionary_map());
10023 :
10024 : // Migrate to the newest map before storing the property.
10025 22368828 : map = Update(isolate, map);
10026 :
10027 : Map maybe_transition = TransitionsAccessor(isolate, map)
10028 22368836 : .SearchTransition(*name, kData, attributes);
10029 22368834 : if (!maybe_transition.is_null()) {
10030 : Handle<Map> transition(maybe_transition, isolate);
10031 5300628 : int descriptor = transition->LastAdded();
10032 :
10033 : DCHECK_EQ(attributes, transition->instance_descriptors()
10034 : ->GetDetails(descriptor)
10035 : .attributes());
10036 :
10037 : return UpdateDescriptorForValue(isolate, transition, descriptor, constness,
10038 5300628 : value);
10039 : }
10040 :
10041 : TransitionFlag flag = INSERT_TRANSITION;
10042 : MaybeHandle<Map> maybe_map;
10043 17068203 : if (!map->TooManyFastProperties(store_origin)) {
10044 34085399 : if (!FLAG_track_constant_fields && value->IsJSFunction()) {
10045 : maybe_map =
10046 9768746 : Map::CopyWithConstant(isolate, map, name, value, attributes, flag);
10047 : } else {
10048 7273953 : Representation representation = value->OptimalRepresentation();
10049 7273951 : Handle<FieldType> type = value->OptimalType(isolate, representation);
10050 : maybe_map = Map::CopyWithField(isolate, map, name, type, attributes,
10051 7273942 : constness, representation, flag);
10052 : }
10053 : }
10054 :
10055 : Handle<Map> result;
10056 17068192 : if (!maybe_map.ToHandle(&result)) {
10057 : const char* reason = "TooManyFastProperties";
10058 : #if V8_TRACE_MAPS
10059 : std::unique_ptr<ScopedVector<char>> buffer;
10060 : if (FLAG_trace_maps) {
10061 : ScopedVector<char> name_buffer(100);
10062 : name->NameShortPrint(name_buffer);
10063 : buffer.reset(new ScopedVector<char>(128));
10064 : SNPrintF(*buffer, "TooManyFastProperties %s", name_buffer.start());
10065 : reason = buffer->start();
10066 : }
10067 : #endif
10068 51230 : Handle<Object> maybe_constructor(map->GetConstructor(), isolate);
10069 25615 : if (FLAG_feedback_normalization && map->new_target_is_base() &&
10070 51230 : maybe_constructor->IsJSFunction() &&
10071 25615 : !JSFunction::cast(*maybe_constructor)->shared()->native()) {
10072 : Handle<JSFunction> constructor =
10073 0 : Handle<JSFunction>::cast(maybe_constructor);
10074 : DCHECK_NE(*constructor,
10075 : constructor->context()->native_context()->object_function());
10076 0 : Handle<Map> initial_map(constructor->initial_map(), isolate);
10077 : result = Map::Normalize(isolate, initial_map, CLEAR_INOBJECT_PROPERTIES,
10078 0 : reason);
10079 0 : initial_map->DeprecateTransitionTree(isolate);
10080 : Handle<Object> prototype(result->prototype(), isolate);
10081 0 : JSFunction::SetInitialMap(constructor, result, prototype);
10082 :
10083 : // Deoptimize all code that embeds the previous initial map.
10084 0 : initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
10085 0 : isolate, DependentCode::kInitialMapChangedGroup);
10086 0 : if (!result->EquivalentToForNormalization(*map,
10087 0 : CLEAR_INOBJECT_PROPERTIES)) {
10088 : result =
10089 0 : Map::Normalize(isolate, map, CLEAR_INOBJECT_PROPERTIES, reason);
10090 : }
10091 : } else {
10092 25615 : result = Map::Normalize(isolate, map, CLEAR_INOBJECT_PROPERTIES, reason);
10093 : }
10094 : }
10095 :
10096 17068192 : return result;
10097 : }
10098 :
10099 16455 : Handle<Map> Map::ReconfigureExistingProperty(Isolate* isolate, Handle<Map> map,
10100 : int descriptor, PropertyKind kind,
10101 : PropertyAttributes attributes) {
10102 : // Dictionaries have to be reconfigured in-place.
10103 : DCHECK(!map->is_dictionary_map());
10104 :
10105 32910 : if (!map->GetBackPointer()->IsMap()) {
10106 : // There is no benefit from reconstructing transition tree for maps without
10107 : // back pointers.
10108 : return CopyGeneralizeAllFields(isolate, map, map->elements_kind(),
10109 : descriptor, kind, attributes,
10110 1242 : "GenAll_AttributesMismatchProtoMap");
10111 : }
10112 :
10113 15213 : if (FLAG_trace_generalization) {
10114 0 : map->PrintReconfiguration(isolate, stdout, descriptor, kind, attributes);
10115 : }
10116 :
10117 15213 : MapUpdater mu(isolate, map);
10118 : DCHECK_EQ(kData, kind); // Only kData case is supported so far.
10119 : Handle<Map> new_map = mu.ReconfigureToDataField(
10120 : descriptor, attributes, kDefaultFieldConstness, Representation::None(),
10121 15213 : FieldType::None(isolate));
10122 15213 : return new_map;
10123 : }
10124 :
10125 727735 : Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map,
10126 : Handle<Name> name, int descriptor,
10127 : Handle<Object> getter,
10128 : Handle<Object> setter,
10129 : PropertyAttributes attributes) {
10130 : RuntimeCallTimerScope stats_scope(
10131 : isolate,
10132 : map->is_prototype_map()
10133 : ? RuntimeCallCounterId::kPrototypeMap_TransitionToAccessorProperty
10134 727735 : : RuntimeCallCounterId::kMap_TransitionToAccessorProperty);
10135 :
10136 : // At least one of the accessors needs to be a new value.
10137 : DCHECK(!getter->IsNull(isolate) || !setter->IsNull(isolate));
10138 : DCHECK(name->IsUniqueName());
10139 :
10140 : // Dictionary maps can always have additional data properties.
10141 727735 : if (map->is_dictionary_map()) return map;
10142 :
10143 : // Migrate to the newest map before transitioning to the new property.
10144 727735 : map = Update(isolate, map);
10145 :
10146 : PropertyNormalizationMode mode = map->is_prototype_map()
10147 : ? KEEP_INOBJECT_PROPERTIES
10148 727736 : : CLEAR_INOBJECT_PROPERTIES;
10149 :
10150 : Map maybe_transition = TransitionsAccessor(isolate, map)
10151 727736 : .SearchTransition(*name, kAccessor, attributes);
10152 727735 : if (!maybe_transition.is_null()) {
10153 : Handle<Map> transition(maybe_transition, isolate);
10154 12135 : DescriptorArray descriptors = transition->instance_descriptors();
10155 12135 : int descriptor = transition->LastAdded();
10156 : DCHECK(descriptors->GetKey(descriptor)->Equals(*name));
10157 :
10158 : DCHECK_EQ(kAccessor, descriptors->GetDetails(descriptor).kind());
10159 : DCHECK_EQ(attributes, descriptors->GetDetails(descriptor).attributes());
10160 :
10161 12135 : Handle<Object> maybe_pair(descriptors->GetStrongValue(descriptor), isolate);
10162 24270 : if (!maybe_pair->IsAccessorPair()) {
10163 : return Map::Normalize(isolate, map, mode,
10164 0 : "TransitionToAccessorFromNonPair");
10165 : }
10166 :
10167 12135 : Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair);
10168 12135 : if (!pair->Equals(*getter, *setter)) {
10169 : return Map::Normalize(isolate, map, mode,
10170 11602 : "TransitionToDifferentAccessor");
10171 : }
10172 :
10173 533 : return transition;
10174 : }
10175 :
10176 : Handle<AccessorPair> pair;
10177 715600 : DescriptorArray old_descriptors = map->instance_descriptors();
10178 715600 : if (descriptor != DescriptorArray::kNotFound) {
10179 219444 : if (descriptor != map->LastAdded()) {
10180 117369 : return Map::Normalize(isolate, map, mode, "AccessorsOverwritingNonLast");
10181 : }
10182 102075 : PropertyDetails old_details = old_descriptors->GetDetails(descriptor);
10183 102075 : if (old_details.kind() != kAccessor) {
10184 : return Map::Normalize(isolate, map, mode,
10185 100395 : "AccessorsOverwritingNonAccessors");
10186 : }
10187 :
10188 1680 : if (old_details.attributes() != attributes) {
10189 81 : return Map::Normalize(isolate, map, mode, "AccessorsWithAttributes");
10190 : }
10191 :
10192 : Handle<Object> maybe_pair(old_descriptors->GetStrongValue(descriptor),
10193 1599 : isolate);
10194 3198 : if (!maybe_pair->IsAccessorPair()) {
10195 24 : return Map::Normalize(isolate, map, mode, "AccessorsOverwritingNonPair");
10196 : }
10197 :
10198 1575 : Handle<AccessorPair> current_pair = Handle<AccessorPair>::cast(maybe_pair);
10199 1575 : if (current_pair->Equals(*getter, *setter)) return map;
10200 :
10201 : bool overwriting_accessor = false;
10202 4711 : if (!getter->IsNull(isolate) &&
10203 6182 : !current_pair->get(ACCESSOR_GETTER)->IsNull(isolate) &&
10204 3046 : current_pair->get(ACCESSOR_GETTER) != *getter) {
10205 : overwriting_accessor = true;
10206 : }
10207 4716 : if (!setter->IsNull(isolate) &&
10208 5892 : !current_pair->get(ACCESSOR_SETTER)->IsNull(isolate) &&
10209 2751 : current_pair->get(ACCESSOR_SETTER) != *setter) {
10210 : overwriting_accessor = true;
10211 : }
10212 1575 : if (overwriting_accessor) {
10213 : return Map::Normalize(isolate, map, mode,
10214 1392 : "AccessorsOverwritingAccessors");
10215 : }
10216 :
10217 183 : pair = AccessorPair::Copy(isolate, Handle<AccessorPair>::cast(maybe_pair));
10218 1488470 : } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors ||
10219 992313 : map->TooManyFastProperties(StoreOrigin::kNamed)) {
10220 : return Map::Normalize(isolate, map, CLEAR_INOBJECT_PROPERTIES,
10221 0 : "TooManyAccessors");
10222 : } else {
10223 496157 : pair = isolate->factory()->NewAccessorPair();
10224 : }
10225 :
10226 496340 : pair->SetComponents(*getter, *setter);
10227 :
10228 : TransitionFlag flag = INSERT_TRANSITION;
10229 496340 : Descriptor d = Descriptor::AccessorConstant(name, pair, attributes);
10230 496339 : return Map::CopyInsertDescriptor(isolate, map, &d, flag);
10231 : }
10232 :
10233 17557024 : Handle<Map> Map::CopyAddDescriptor(Isolate* isolate, Handle<Map> map,
10234 : Descriptor* descriptor,
10235 : TransitionFlag flag) {
10236 35114067 : Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
10237 :
10238 : // Share descriptors only if map owns descriptors and it not an initial map.
10239 52622625 : if (flag == INSERT_TRANSITION && map->owns_descriptors() &&
10240 57915316 : !map->GetBackPointer()->IsUndefined(isolate) &&
10241 22849537 : TransitionsAccessor(isolate, map).CanHaveMoreTransitions()) {
10242 5292494 : return ShareDescriptor(isolate, map, descriptors, descriptor);
10243 : }
10244 :
10245 : int nof = map->NumberOfOwnDescriptors();
10246 : Handle<DescriptorArray> new_descriptors =
10247 : DescriptorArray::CopyUpTo(isolate, descriptors, nof, 1);
10248 12264545 : new_descriptors->Append(descriptor);
10249 :
10250 : Handle<LayoutDescriptor> new_layout_descriptor =
10251 : FLAG_unbox_double_fields
10252 12264560 : ? LayoutDescriptor::New(isolate, map, new_descriptors, nof + 1)
10253 12264560 : : handle(LayoutDescriptor::FastPointerLayout(), isolate);
10254 :
10255 : return CopyReplaceDescriptors(
10256 : isolate, map, new_descriptors, new_layout_descriptor, flag,
10257 12264556 : descriptor->GetKey(), "CopyAddDescriptor", SIMPLE_PROPERTY_TRANSITION);
10258 : }
10259 :
10260 496379 : Handle<Map> Map::CopyInsertDescriptor(Isolate* isolate, Handle<Map> map,
10261 : Descriptor* descriptor,
10262 : TransitionFlag flag) {
10263 992758 : Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
10264 :
10265 : // We replace the key if it is already present.
10266 : int index =
10267 992758 : old_descriptors->SearchWithCache(isolate, *descriptor->GetKey(), *map);
10268 496379 : if (index != DescriptorArray::kNotFound) {
10269 : return CopyReplaceDescriptor(isolate, map, old_descriptors, descriptor,
10270 183 : index, flag);
10271 : }
10272 496196 : return CopyAddDescriptor(isolate, map, descriptor, flag);
10273 : }
10274 :
10275 0 : Handle<DescriptorArray> DescriptorArray::CopyUpTo(Isolate* isolate,
10276 : Handle<DescriptorArray> desc,
10277 : int enumeration_index,
10278 : int slack) {
10279 : return DescriptorArray::CopyUpToAddAttributes(isolate, desc,
10280 20351929 : enumeration_index, NONE, slack);
10281 : }
10282 :
10283 20502704 : Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
10284 : Isolate* isolate, Handle<DescriptorArray> desc, int enumeration_index,
10285 : PropertyAttributes attributes, int slack) {
10286 20502704 : if (enumeration_index + slack == 0) {
10287 : return isolate->factory()->empty_descriptor_array();
10288 : }
10289 :
10290 : int size = enumeration_index;
10291 :
10292 : Handle<DescriptorArray> descriptors =
10293 : DescriptorArray::Allocate(isolate, size, slack);
10294 :
10295 19031287 : if (attributes != NONE) {
10296 245838 : for (int i = 0; i < size; ++i) {
10297 491671 : MaybeObject value_or_field_type = desc->GetValue(i);
10298 245836 : Name key = desc->GetKey(i);
10299 245834 : PropertyDetails details = desc->GetDetails(i);
10300 : // Bulk attribute changes never affect private properties.
10301 245836 : if (!key->IsPrivate()) {
10302 : int mask = DONT_DELETE | DONT_ENUM;
10303 : // READ_ONLY is an invalid attribute for JS setters/getters.
10304 245801 : HeapObject heap_object;
10305 492564 : if (details.kind() != kAccessor ||
10306 962 : !(value_or_field_type->GetHeapObjectIfStrong(&heap_object) &&
10307 962 : heap_object->IsAccessorPair())) {
10308 : mask |= READ_ONLY;
10309 : }
10310 : details = details.CopyAddAttributes(
10311 245801 : static_cast<PropertyAttributes>(attributes & mask));
10312 : }
10313 245838 : descriptors->Set(i, key, value_or_field_type, details);
10314 : }
10315 : } else {
10316 119354566 : for (int i = 0; i < size; ++i) {
10317 119354509 : descriptors->CopyFrom(i, *desc);
10318 : }
10319 : }
10320 :
10321 19083527 : if (desc->number_of_descriptors() != enumeration_index) descriptors->Sort();
10322 :
10323 19031305 : return descriptors;
10324 : }
10325 :
10326 : // Create a new descriptor array with only enumerable, configurable, writeable
10327 : // data properties, but identical field locations.
10328 261 : Handle<DescriptorArray> DescriptorArray::CopyForFastObjectClone(
10329 : Isolate* isolate, Handle<DescriptorArray> src, int enumeration_index,
10330 : int slack) {
10331 261 : if (enumeration_index + slack == 0) {
10332 : return isolate->factory()->empty_descriptor_array();
10333 : }
10334 :
10335 : int size = enumeration_index;
10336 : Handle<DescriptorArray> descriptors =
10337 : DescriptorArray::Allocate(isolate, size, slack);
10338 :
10339 711 : for (int i = 0; i < size; ++i) {
10340 450 : Name key = src->GetKey(i);
10341 450 : PropertyDetails details = src->GetDetails(i);
10342 :
10343 : DCHECK(!key->IsPrivateName());
10344 : DCHECK(details.IsEnumerable());
10345 : DCHECK_EQ(details.kind(), kData);
10346 :
10347 : // Ensure the ObjectClone property details are NONE, and that all source
10348 : // details did not contain DONT_ENUM.
10349 : PropertyDetails new_details(kData, NONE, details.location(),
10350 : details.constness(), details.representation(),
10351 : details.field_index());
10352 : // Do not propagate the field type of normal object fields from the
10353 : // original descriptors since FieldType changes don't create new maps.
10354 900 : MaybeObject type = src->GetValue(i);
10355 450 : if (details.location() == PropertyLocation::kField) {
10356 414 : type = MaybeObject::FromObject(FieldType::Any());
10357 : }
10358 450 : descriptors->Set(i, key, type, new_details);
10359 : }
10360 :
10361 261 : descriptors->Sort();
10362 :
10363 261 : return descriptors;
10364 : }
10365 :
10366 2012 : bool DescriptorArray::IsEqualUpTo(DescriptorArray desc, int nof_descriptors) {
10367 26977 : for (int i = 0; i < nof_descriptors; i++) {
10368 74895 : if (GetKey(i) != desc->GetKey(i) || GetValue(i) != desc->GetValue(i)) {
10369 : return false;
10370 : }
10371 24965 : PropertyDetails details = GetDetails(i);
10372 24965 : PropertyDetails other_details = desc->GetDetails(i);
10373 49930 : if (details.kind() != other_details.kind() ||
10374 49930 : details.location() != other_details.location() ||
10375 : !details.representation().Equals(other_details.representation())) {
10376 : return false;
10377 : }
10378 : }
10379 : return true;
10380 : }
10381 :
10382 183 : Handle<Map> Map::CopyReplaceDescriptor(Isolate* isolate, Handle<Map> map,
10383 : Handle<DescriptorArray> descriptors,
10384 : Descriptor* descriptor,
10385 : int insertion_index,
10386 : TransitionFlag flag) {
10387 : Handle<Name> key = descriptor->GetKey();
10388 : DCHECK_EQ(*key, descriptors->GetKey(insertion_index));
10389 : // This function does not support replacing property fields as
10390 : // that would break property field counters.
10391 : DCHECK_NE(kField, descriptor->GetDetails().location());
10392 : DCHECK_NE(kField, descriptors->GetDetails(insertion_index).location());
10393 :
10394 : Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
10395 : isolate, descriptors, map->NumberOfOwnDescriptors());
10396 :
10397 183 : new_descriptors->Replace(insertion_index, descriptor);
10398 : Handle<LayoutDescriptor> new_layout_descriptor = LayoutDescriptor::New(
10399 183 : isolate, map, new_descriptors, new_descriptors->number_of_descriptors());
10400 :
10401 : SimpleTransitionFlag simple_flag =
10402 183 : (insertion_index == descriptors->number_of_descriptors() - 1)
10403 : ? SIMPLE_PROPERTY_TRANSITION
10404 183 : : PROPERTY_TRANSITION;
10405 : return CopyReplaceDescriptors(isolate, map, new_descriptors,
10406 : new_layout_descriptor, flag, key,
10407 183 : "CopyReplaceDescriptor", simple_flag);
10408 : }
10409 :
10410 9873311 : Handle<FixedArray> FixedArray::SetAndGrow(Isolate* isolate,
10411 : Handle<FixedArray> array, int index,
10412 : Handle<Object> value,
10413 : PretenureFlag pretenure) {
10414 9873311 : if (index < array->length()) {
10415 9348246 : array->set(index, *value);
10416 9348244 : return array;
10417 : }
10418 : int capacity = array->length();
10419 525065 : do {
10420 1050130 : capacity = JSObject::NewElementsCapacity(capacity);
10421 : } while (capacity <= index);
10422 : Handle<FixedArray> new_array =
10423 525065 : isolate->factory()->NewUninitializedFixedArray(capacity, pretenure);
10424 525065 : array->CopyTo(0, *new_array, 0, array->length());
10425 1050129 : new_array->FillWithHoles(array->length(), new_array->length());
10426 525065 : new_array->set(index, *value);
10427 525065 : return new_array;
10428 : }
10429 :
10430 0 : bool FixedArray::ContainsSortedNumbers() {
10431 0 : for (int i = 1; i < length(); ++i) {
10432 0 : Object a_obj = get(i - 1);
10433 0 : Object b_obj = get(i);
10434 0 : if (!a_obj->IsNumber() || !b_obj->IsNumber()) return false;
10435 :
10436 0 : uint32_t a = NumberToUint32(a_obj);
10437 0 : uint32_t b = NumberToUint32(b_obj);
10438 :
10439 0 : if (a > b) return false;
10440 : }
10441 : return true;
10442 : }
10443 :
10444 846686 : Handle<FixedArray> FixedArray::ShrinkOrEmpty(Isolate* isolate,
10445 : Handle<FixedArray> array,
10446 : int new_length) {
10447 846686 : if (new_length == 0) {
10448 194782 : return array->GetReadOnlyRoots().empty_fixed_array_handle();
10449 : } else {
10450 749296 : array->Shrink(isolate, new_length);
10451 749296 : return array;
10452 : }
10453 : }
10454 :
10455 2003377 : void FixedArray::Shrink(Isolate* isolate, int new_length) {
10456 : DCHECK(0 < new_length && new_length <= length());
10457 2003377 : if (new_length < length()) {
10458 1362518 : isolate->heap()->RightTrimFixedArray(*this, length() - new_length);
10459 : }
10460 2003377 : }
10461 :
10462 545297 : void FixedArray::CopyTo(int pos, FixedArray dest, int dest_pos, int len) const {
10463 : DisallowHeapAllocation no_gc;
10464 : // Return early if len == 0 so that we don't try to read the write barrier off
10465 : // a canonical read-only empty fixed array.
10466 1090598 : if (len == 0) return;
10467 : WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
10468 9002870 : for (int index = 0; index < len; index++) {
10469 16931132 : dest->set(dest_pos + index, get(pos + index), mode);
10470 : }
10471 : }
10472 :
10473 0 : void JSObject::PrototypeRegistryCompactionCallback(HeapObject value,
10474 : int old_index,
10475 : int new_index) {
10476 : DCHECK(value->IsMap() && Map::cast(value)->is_prototype_map());
10477 : Map map = Map::cast(value);
10478 : DCHECK(map->prototype_info()->IsPrototypeInfo());
10479 : PrototypeInfo proto_info = PrototypeInfo::cast(map->prototype_info());
10480 : DCHECK_EQ(old_index, proto_info->registry_slot());
10481 : proto_info->set_registry_slot(new_index);
10482 0 : }
10483 :
10484 : // static
10485 2310 : Handle<ArrayList> ArrayList::Add(Isolate* isolate, Handle<ArrayList> array,
10486 : Handle<Object> obj) {
10487 2310 : int length = array->Length();
10488 2310 : array = EnsureSpace(isolate, array, length + 1);
10489 : // Check that GC didn't remove elements from the array.
10490 : DCHECK_EQ(array->Length(), length);
10491 2310 : array->Set(length, *obj);
10492 2310 : array->SetLength(length + 1);
10493 2310 : return array;
10494 : }
10495 :
10496 : // static
10497 5 : Handle<ArrayList> ArrayList::Add(Isolate* isolate, Handle<ArrayList> array,
10498 : Handle<Object> obj1, Handle<Object> obj2) {
10499 5 : int length = array->Length();
10500 5 : array = EnsureSpace(isolate, array, length + 2);
10501 : // Check that GC didn't remove elements from the array.
10502 : DCHECK_EQ(array->Length(), length);
10503 5 : array->Set(length, *obj1);
10504 10 : array->Set(length + 1, *obj2);
10505 5 : array->SetLength(length + 2);
10506 5 : return array;
10507 : }
10508 :
10509 : // static
10510 435 : Handle<ArrayList> ArrayList::New(Isolate* isolate, int size) {
10511 : Handle<FixedArray> fixed_array =
10512 435 : isolate->factory()->NewFixedArray(size + kFirstIndex);
10513 : fixed_array->set_map_no_write_barrier(
10514 : ReadOnlyRoots(isolate).array_list_map());
10515 435 : Handle<ArrayList> result = Handle<ArrayList>::cast(fixed_array);
10516 435 : result->SetLength(0);
10517 435 : return result;
10518 : }
10519 :
10520 402 : Handle<FixedArray> ArrayList::Elements(Isolate* isolate,
10521 : Handle<ArrayList> array) {
10522 402 : int length = array->Length();
10523 402 : Handle<FixedArray> result = isolate->factory()->NewFixedArray(length);
10524 : // Do not copy the first entry, i.e., the length.
10525 402 : array->CopyTo(kFirstIndex, *result, 0, length);
10526 402 : return result;
10527 : }
10528 :
10529 : namespace {
10530 :
10531 5115523 : Handle<FixedArray> EnsureSpaceInFixedArray(Isolate* isolate,
10532 : Handle<FixedArray> array,
10533 : int length) {
10534 : int capacity = array->length();
10535 5115523 : if (capacity < length) {
10536 : int new_capacity = length;
10537 5486 : new_capacity = new_capacity + Max(new_capacity / 2, 2);
10538 2743 : int grow_by = new_capacity - capacity;
10539 2743 : array = isolate->factory()->CopyFixedArrayAndGrow(array, grow_by);
10540 : }
10541 5115523 : return array;
10542 : }
10543 :
10544 : } // namespace
10545 :
10546 : // static
10547 2315 : Handle<ArrayList> ArrayList::EnsureSpace(Isolate* isolate,
10548 : Handle<ArrayList> array, int length) {
10549 : const bool empty = (array->length() == 0);
10550 : Handle<FixedArray> ret =
10551 4630 : EnsureSpaceInFixedArray(isolate, array, kFirstIndex + length);
10552 2315 : if (empty) {
10553 50 : ret->set_map_no_write_barrier(array->GetReadOnlyRoots().array_list_map());
10554 :
10555 50 : Handle<ArrayList>::cast(ret)->SetLength(0);
10556 : }
10557 2315 : return Handle<ArrayList>::cast(ret);
10558 : }
10559 :
10560 : // static
10561 14352905 : Handle<WeakArrayList> WeakArrayList::AddToEnd(Isolate* isolate,
10562 : Handle<WeakArrayList> array,
10563 : const MaybeObjectHandle& value) {
10564 : int length = array->length();
10565 14352915 : array = EnsureSpace(isolate, array, length + 1);
10566 : // Reload length; GC might have removed elements from the array.
10567 : length = array->length();
10568 28705849 : array->Set(length, *value);
10569 14352919 : array->set_length(length + 1);
10570 14352921 : return array;
10571 : }
10572 :
10573 849539 : bool WeakArrayList::IsFull() { return length() == capacity(); }
10574 :
10575 : // static
10576 14486442 : Handle<WeakArrayList> WeakArrayList::EnsureSpace(Isolate* isolate,
10577 : Handle<WeakArrayList> array,
10578 : int length,
10579 : PretenureFlag pretenure) {
10580 : int capacity = array->capacity();
10581 14486451 : if (capacity < length) {
10582 : int new_capacity = length;
10583 3682810 : new_capacity = new_capacity + Max(new_capacity / 2, 2);
10584 1841405 : int grow_by = new_capacity - capacity;
10585 : array =
10586 1841405 : isolate->factory()->CopyWeakArrayListAndGrow(array, grow_by, pretenure);
10587 : }
10588 14486451 : return array;
10589 : }
10590 :
10591 402 : int WeakArrayList::CountLiveWeakReferences() const {
10592 : int live_weak_references = 0;
10593 226668 : for (int i = 0; i < length(); i++) {
10594 225864 : if (Get(i)->IsWeak()) {
10595 112572 : ++live_weak_references;
10596 : }
10597 : }
10598 402 : return live_weak_references;
10599 : }
10600 :
10601 3564483 : bool WeakArrayList::RemoveOne(const MaybeObjectHandle& value) {
10602 3564491 : if (length() == 0) return false;
10603 : // Optimize for the most recently added element to be removed again.
10604 : MaybeObject cleared_weak_ref =
10605 3564489 : HeapObjectReference::ClearedValue(GetIsolate());
10606 3564492 : int last_index = length() - 1;
10607 3564512 : for (int i = last_index; i >= 0; --i) {
10608 7129016 : if (Get(i) == *value) {
10609 : // Move the last element into the this slot (or no-op, if this is the
10610 : // last slot).
10611 3564489 : Set(i, Get(last_index));
10612 3564495 : Set(last_index, cleared_weak_ref);
10613 : set_length(last_index);
10614 3564497 : return true;
10615 : }
10616 : }
10617 : return false;
10618 : }
10619 :
10620 : // static
10621 500894 : Handle<WeakArrayList> PrototypeUsers::Add(Isolate* isolate,
10622 : Handle<WeakArrayList> array,
10623 : Handle<Map> value,
10624 : int* assigned_index) {
10625 : int length = array->length();
10626 500898 : if (length == 0) {
10627 : // Uninitialized WeakArrayList; need to initialize empty_slot_index.
10628 118639 : array = WeakArrayList::EnsureSpace(isolate, array, kFirstIndex + 1);
10629 : set_empty_slot_index(*array, kNoEmptySlotsMarker);
10630 237276 : array->Set(kFirstIndex, HeapObjectReference::Weak(*value));
10631 : array->set_length(kFirstIndex + 1);
10632 118638 : if (assigned_index != nullptr) *assigned_index = kFirstIndex;
10633 118638 : return array;
10634 : }
10635 :
10636 : // If the array has unfilled space at the end, use it.
10637 382258 : if (!array->IsFull()) {
10638 539362 : array->Set(length, HeapObjectReference::Weak(*value));
10639 269682 : array->set_length(length + 1);
10640 269681 : if (assigned_index != nullptr) *assigned_index = length;
10641 269681 : return array;
10642 : }
10643 :
10644 : // If there are empty slots, use one of them.
10645 112578 : int empty_slot = Smi::ToInt(empty_slot_index(*array));
10646 112578 : if (empty_slot != kNoEmptySlotsMarker) {
10647 : DCHECK_GE(empty_slot, kFirstIndex);
10648 97798 : CHECK_LT(empty_slot, array->length());
10649 195596 : int next_empty_slot = array->Get(empty_slot).ToSmi().value();
10650 :
10651 195596 : array->Set(empty_slot, HeapObjectReference::Weak(*value));
10652 97798 : if (assigned_index != nullptr) *assigned_index = empty_slot;
10653 :
10654 : set_empty_slot_index(*array, next_empty_slot);
10655 97798 : return array;
10656 : } else {
10657 : DCHECK_EQ(empty_slot, kNoEmptySlotsMarker);
10658 : }
10659 :
10660 : // Array full and no empty slots. Grow the array.
10661 14780 : array = WeakArrayList::EnsureSpace(isolate, array, length + 1);
10662 29560 : array->Set(length, HeapObjectReference::Weak(*value));
10663 : array->set_length(length + 1);
10664 14780 : if (assigned_index != nullptr) *assigned_index = length;
10665 14780 : return array;
10666 : }
10667 :
10668 30 : WeakArrayList PrototypeUsers::Compact(Handle<WeakArrayList> array, Heap* heap,
10669 : CompactionCallback callback,
10670 : PretenureFlag pretenure) {
10671 30 : if (array->length() == 0) {
10672 : return *array;
10673 : }
10674 30 : int new_length = kFirstIndex + array->CountLiveWeakReferences();
10675 30 : if (new_length == array->length()) {
10676 : return *array;
10677 : }
10678 :
10679 : Handle<WeakArrayList> new_array = WeakArrayList::EnsureSpace(
10680 : heap->isolate(),
10681 : handle(ReadOnlyRoots(heap).empty_weak_array_list(), heap->isolate()),
10682 5 : new_length, pretenure);
10683 : // Allocation might have caused GC and turned some of the elements into
10684 : // cleared weak heap objects. Count the number of live objects again.
10685 : int copy_to = kFirstIndex;
10686 40 : for (int i = kFirstIndex; i < array->length(); i++) {
10687 15 : MaybeObject element = array->Get(i);
10688 15 : HeapObject value;
10689 15 : if (element->GetHeapObjectIfWeak(&value)) {
10690 5 : callback(value, i, copy_to);
10691 10 : new_array->Set(copy_to++, element);
10692 : } else {
10693 : DCHECK(element->IsCleared() || element->IsSmi());
10694 : }
10695 : }
10696 : new_array->set_length(copy_to);
10697 : set_empty_slot_index(*new_array, kNoEmptySlotsMarker);
10698 : return *new_array;
10699 : }
10700 :
10701 181946 : Handle<RegExpMatchInfo> RegExpMatchInfo::ReserveCaptures(
10702 : Isolate* isolate, Handle<RegExpMatchInfo> match_info, int capture_count) {
10703 : DCHECK_GE(match_info->length(), kLastMatchOverhead);
10704 181946 : const int required_length = kFirstCaptureIndex + capture_count;
10705 : return Handle<RegExpMatchInfo>::cast(
10706 181946 : EnsureSpaceInFixedArray(isolate, match_info, required_length));
10707 : }
10708 :
10709 : // static
10710 4756622 : Handle<FrameArray> FrameArray::AppendJSFrame(Handle<FrameArray> in,
10711 : Handle<Object> receiver,
10712 : Handle<JSFunction> function,
10713 : Handle<AbstractCode> code,
10714 : int offset, int flags) {
10715 4756622 : const int frame_count = in->FrameCount();
10716 4756622 : const int new_length = LengthFor(frame_count + 1);
10717 : Handle<FrameArray> array =
10718 4756622 : EnsureSpace(function->GetIsolate(), in, new_length);
10719 9513244 : array->SetReceiver(frame_count, *receiver);
10720 9513244 : array->SetFunction(frame_count, *function);
10721 9513244 : array->SetCode(frame_count, *code);
10722 4756622 : array->SetOffset(frame_count, Smi::FromInt(offset));
10723 4756622 : array->SetFlags(frame_count, Smi::FromInt(flags));
10724 : array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));
10725 4756622 : return array;
10726 : }
10727 :
10728 : // static
10729 174640 : Handle<FrameArray> FrameArray::AppendWasmFrame(
10730 : Handle<FrameArray> in, Handle<WasmInstanceObject> wasm_instance,
10731 : int wasm_function_index, wasm::WasmCode* code, int offset, int flags) {
10732 : Isolate* isolate = wasm_instance->GetIsolate();
10733 174640 : const int frame_count = in->FrameCount();
10734 174640 : const int new_length = LengthFor(frame_count + 1);
10735 174640 : Handle<FrameArray> array = EnsureSpace(isolate, in, new_length);
10736 : // The {code} will be {nullptr} for interpreted wasm frames.
10737 : Handle<Foreign> code_foreign =
10738 174640 : isolate->factory()->NewForeign(reinterpret_cast<Address>(code));
10739 349280 : array->SetWasmInstance(frame_count, *wasm_instance);
10740 174640 : array->SetWasmFunctionIndex(frame_count, Smi::FromInt(wasm_function_index));
10741 349280 : array->SetWasmCodeObject(frame_count, *code_foreign);
10742 174640 : array->SetOffset(frame_count, Smi::FromInt(offset));
10743 174640 : array->SetFlags(frame_count, Smi::FromInt(flags));
10744 : array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));
10745 174640 : return array;
10746 : }
10747 :
10748 1253133 : void FrameArray::ShrinkToFit(Isolate* isolate) {
10749 2506266 : Shrink(isolate, LengthFor(FrameCount()));
10750 1253133 : }
10751 :
10752 : // static
10753 4931262 : Handle<FrameArray> FrameArray::EnsureSpace(Isolate* isolate,
10754 : Handle<FrameArray> array,
10755 : int length) {
10756 : return Handle<FrameArray>::cast(
10757 4931262 : EnsureSpaceInFixedArray(isolate, array, length));
10758 : }
10759 :
10760 192938 : Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate,
10761 : int nof_descriptors,
10762 : int slack,
10763 : PretenureFlag pretenure) {
10764 192938 : return nof_descriptors + slack == 0
10765 : ? isolate->factory()->empty_descriptor_array()
10766 : : isolate->factory()->NewDescriptorArray(nof_descriptors, slack,
10767 38991774 : pretenure);
10768 : }
10769 :
10770 19496111 : void DescriptorArray::Initialize(EnumCache enum_cache,
10771 : HeapObject undefined_value,
10772 : int nof_descriptors, int slack) {
10773 : DCHECK_GE(nof_descriptors, 0);
10774 : DCHECK_GE(slack, 0);
10775 : DCHECK_LE(nof_descriptors + slack, kMaxNumberOfDescriptors);
10776 19496111 : set_number_of_all_descriptors(nof_descriptors + slack);
10777 19496111 : set_number_of_descriptors(nof_descriptors);
10778 : set_raw_number_of_marked_descriptors(0);
10779 : set_filler16bits(0);
10780 19496111 : set_enum_cache(enum_cache);
10781 : MemsetTagged(GetDescriptorSlot(0), undefined_value,
10782 19496122 : number_of_all_descriptors() * kEntrySize);
10783 19496114 : }
10784 :
10785 62 : void DescriptorArray::ClearEnumCache() {
10786 124 : set_enum_cache(GetReadOnlyRoots().empty_enum_cache());
10787 62 : }
10788 :
10789 239133 : void DescriptorArray::Replace(int index, Descriptor* descriptor) {
10790 : descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index));
10791 239134 : Set(index, descriptor);
10792 239136 : }
10793 :
10794 : // static
10795 47976 : void DescriptorArray::InitializeOrChangeEnumCache(
10796 : Handle<DescriptorArray> descriptors, Isolate* isolate,
10797 : Handle<FixedArray> keys, Handle<FixedArray> indices) {
10798 47976 : EnumCache enum_cache = descriptors->enum_cache();
10799 47976 : if (enum_cache == ReadOnlyRoots(isolate).empty_enum_cache()) {
10800 94408 : enum_cache = *isolate->factory()->NewEnumCache(keys, indices);
10801 47204 : descriptors->set_enum_cache(enum_cache);
10802 : } else {
10803 772 : enum_cache->set_keys(*keys);
10804 772 : enum_cache->set_indices(*indices);
10805 : }
10806 47976 : }
10807 :
10808 119354516 : void DescriptorArray::CopyFrom(int index, DescriptorArray src) {
10809 119354516 : PropertyDetails details = src->GetDetails(index);
10810 119354523 : Set(index, src->GetKey(index), src->GetValue(index), details);
10811 119354562 : }
10812 :
10813 14208666 : void DescriptorArray::Sort() {
10814 : // In-place heap sort.
10815 14208666 : int len = number_of_descriptors();
10816 : // Reset sorting since the descriptor array might contain invalid pointers.
10817 14208666 : for (int i = 0; i < len; ++i) SetSortedKey(i, i);
10818 : // Bottom-up max-heap construction.
10819 : // Index of the last node with children
10820 14208675 : const int max_parent_index = (len / 2) - 1;
10821 57328033 : for (int i = max_parent_index; i >= 0; --i) {
10822 : int parent_index = i;
10823 43119411 : const uint32_t parent_hash = GetSortedKey(i)->Hash();
10824 127147172 : while (parent_index <= max_parent_index) {
10825 63757077 : int child_index = 2 * parent_index + 1;
10826 63757077 : uint32_t child_hash = GetSortedKey(child_index)->Hash();
10827 63756994 : if (child_index + 1 < len) {
10828 50818908 : uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
10829 50818887 : if (right_child_hash > child_hash) {
10830 : child_index++;
10831 : child_hash = right_child_hash;
10832 : }
10833 : }
10834 63756973 : if (child_hash <= parent_hash) break;
10835 40908365 : SwapSortedKeys(parent_index, child_index);
10836 : // Now element at child_index could be < its children.
10837 : parent_index = child_index; // parent_hash remains correct.
10838 : }
10839 : }
10840 :
10841 : // Extract elements and create sorted array.
10842 92272565 : for (int i = len - 1; i > 0; --i) {
10843 : // Put max element at the back of the array.
10844 78063964 : SwapSortedKeys(0, i);
10845 : // Shift down the new top element.
10846 : int parent_index = 0;
10847 78063729 : const uint32_t parent_hash = GetSortedKey(parent_index)->Hash();
10848 78063688 : const int max_parent_index = (i / 2) - 1;
10849 281046868 : while (parent_index <= max_parent_index) {
10850 137496349 : int child_index = parent_index * 2 + 1;
10851 137496349 : uint32_t child_hash = GetSortedKey(child_index)->Hash();
10852 137496307 : if (child_index + 1 < i) {
10853 119131967 : uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
10854 119131859 : if (right_child_hash > child_hash) {
10855 : child_index++;
10856 : child_hash = right_child_hash;
10857 : }
10858 : }
10859 137496199 : if (child_hash <= parent_hash) break;
10860 124919087 : SwapSortedKeys(parent_index, child_index);
10861 : parent_index = child_index;
10862 : }
10863 : }
10864 : DCHECK(IsSortedNoDuplicates());
10865 14208601 : }
10866 :
10867 38596690 : int16_t DescriptorArray::UpdateNumberOfMarkedDescriptors(
10868 : unsigned mark_compact_epoch, int16_t new_marked) {
10869 : STATIC_ASSERT(kMaxNumberOfDescriptors <=
10870 : NumberOfMarkedDescriptors::kMaxNumberOfMarkedDescriptors);
10871 : int16_t old_raw_marked = raw_number_of_marked_descriptors();
10872 : int16_t old_marked =
10873 : NumberOfMarkedDescriptors::decode(mark_compact_epoch, old_raw_marked);
10874 : int16_t new_raw_marked =
10875 : NumberOfMarkedDescriptors::encode(mark_compact_epoch, new_marked);
10876 77193387 : while (old_marked < new_marked) {
10877 : int16_t actual_raw_marked = CompareAndSwapRawNumberOfMarkedDescriptors(
10878 24697599 : old_raw_marked, new_raw_marked);
10879 24737481 : if (actual_raw_marked == old_raw_marked) {
10880 : break;
10881 : }
10882 : old_raw_marked = actual_raw_marked;
10883 : old_marked =
10884 : NumberOfMarkedDescriptors::decode(mark_compact_epoch, old_raw_marked);
10885 : }
10886 38636572 : return old_marked;
10887 : }
10888 :
10889 15548 : Handle<AccessorPair> AccessorPair::Copy(Isolate* isolate,
10890 : Handle<AccessorPair> pair) {
10891 15548 : Handle<AccessorPair> copy = isolate->factory()->NewAccessorPair();
10892 31096 : copy->set_getter(pair->getter());
10893 31096 : copy->set_setter(pair->setter());
10894 15548 : return copy;
10895 : }
10896 :
10897 90809 : Handle<Object> AccessorPair::GetComponent(Isolate* isolate,
10898 : Handle<AccessorPair> accessor_pair,
10899 : AccessorComponent component) {
10900 90809 : Object accessor = accessor_pair->get(component);
10901 90809 : if (accessor->IsFunctionTemplateInfo()) {
10902 : return ApiNatives::InstantiateFunction(
10903 178 : handle(FunctionTemplateInfo::cast(accessor), isolate))
10904 178 : .ToHandleChecked();
10905 : }
10906 90720 : if (accessor->IsNull(isolate)) {
10907 4376 : return isolate->factory()->undefined_value();
10908 : }
10909 : return handle(accessor, isolate);
10910 : }
10911 :
10912 455962 : Handle<DeoptimizationData> DeoptimizationData::New(Isolate* isolate,
10913 : int deopt_entry_count,
10914 : PretenureFlag pretenure) {
10915 : return Handle<DeoptimizationData>::cast(isolate->factory()->NewFixedArray(
10916 455962 : LengthFor(deopt_entry_count), pretenure));
10917 : }
10918 :
10919 1744276 : Handle<DeoptimizationData> DeoptimizationData::Empty(Isolate* isolate) {
10920 : return Handle<DeoptimizationData>::cast(
10921 1744276 : isolate->factory()->empty_fixed_array());
10922 : }
10923 :
10924 86 : SharedFunctionInfo DeoptimizationData::GetInlinedFunction(int index) {
10925 86 : if (index == -1) {
10926 0 : return SharedFunctionInfo::cast(SharedFunctionInfo());
10927 : } else {
10928 172 : return SharedFunctionInfo::cast(LiteralArray()->get(index));
10929 : }
10930 : }
10931 :
10932 : #ifdef DEBUG
10933 : bool DescriptorArray::IsEqualTo(DescriptorArray other) {
10934 : if (number_of_all_descriptors() != other->number_of_all_descriptors()) {
10935 : return false;
10936 : }
10937 : for (int i = 0; i < number_of_all_descriptors(); ++i) {
10938 : if (get(i) != other->get(i)) return false;
10939 : }
10940 : return true;
10941 : }
10942 : #endif
10943 :
10944 : // static
10945 36 : Handle<String> String::Trim(Isolate* isolate, Handle<String> string,
10946 : TrimMode mode) {
10947 36 : string = String::Flatten(isolate, string);
10948 : int const length = string->length();
10949 :
10950 : // Perform left trimming if requested.
10951 : int left = 0;
10952 36 : if (mode == kTrim || mode == kTrimStart) {
10953 2412 : while (left < length && IsWhiteSpaceOrLineTerminator(string->Get(left))) {
10954 567 : left++;
10955 : }
10956 : }
10957 :
10958 : // Perform right trimming if requested.
10959 : int right = length;
10960 36 : if (mode == kTrim || mode == kTrimEnd) {
10961 108 : while (right > left &&
10962 180 : IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) {
10963 0 : right--;
10964 : }
10965 : }
10966 :
10967 36 : return isolate->factory()->NewSubString(string, left, right);
10968 : }
10969 :
10970 3684507 : bool String::LooksValid() {
10971 : // TODO(leszeks): Maybe remove this check entirely, Heap::Contains uses
10972 : // basically the same logic as the way we access the heap in the first place.
10973 1929964 : MemoryChunk* chunk = MemoryChunk::FromHeapObject(*this);
10974 : // RO_SPACE objects should always be valid.
10975 3684507 : if (chunk->owner()->identity() == RO_SPACE) return true;
10976 1929964 : if (chunk->heap() == nullptr) return false;
10977 1929964 : return chunk->heap()->Contains(*this);
10978 : }
10979 :
10980 : // static
10981 620972 : MaybeHandle<String> Name::ToFunctionName(Isolate* isolate, Handle<Name> name) {
10982 1241944 : if (name->IsString()) return Handle<String>::cast(name);
10983 : // ES6 section 9.2.11 SetFunctionName, step 4.
10984 17310 : Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate);
10985 11540 : if (description->IsUndefined(isolate)) {
10986 81 : return isolate->factory()->empty_string();
10987 : }
10988 5689 : IncrementalStringBuilder builder(isolate);
10989 : builder.AppendCharacter('[');
10990 5689 : builder.AppendString(Handle<String>::cast(description));
10991 : builder.AppendCharacter(']');
10992 5689 : return builder.Finish();
10993 : }
10994 :
10995 : // static
10996 560452 : MaybeHandle<String> Name::ToFunctionName(Isolate* isolate, Handle<Name> name,
10997 : Handle<String> prefix) {
10998 : Handle<String> name_string;
10999 1120904 : ASSIGN_RETURN_ON_EXCEPTION(isolate, name_string,
11000 : ToFunctionName(isolate, name), String);
11001 560452 : IncrementalStringBuilder builder(isolate);
11002 560453 : builder.AppendString(prefix);
11003 : builder.AppendCharacter(' ');
11004 560454 : builder.AppendString(name_string);
11005 560454 : return builder.Finish();
11006 : }
11007 :
11008 : namespace {
11009 :
11010 : bool AreDigits(const uint8_t* s, int from, int to) {
11011 34838 : for (int i = from; i < to; i++) {
11012 59817 : if (s[i] < '0' || s[i] > '9') return false;
11013 : }
11014 :
11015 : return true;
11016 : }
11017 :
11018 :
11019 : int ParseDecimalInteger(const uint8_t* s, int from, int to) {
11020 : DCHECK_LT(to - from, 10); // Overflow is not possible.
11021 : DCHECK(from < to);
11022 1561 : int d = s[from] - '0';
11023 :
11024 1930 : for (int i = from + 1; i < to; i++) {
11025 369 : d = 10 * d + (s[i] - '0');
11026 : }
11027 :
11028 : return d;
11029 : }
11030 :
11031 : } // namespace
11032 :
11033 : // static
11034 3766110 : Handle<Object> String::ToNumber(Isolate* isolate, Handle<String> subject) {
11035 : // Flatten {subject} string first.
11036 3766110 : subject = String::Flatten(isolate, subject);
11037 :
11038 : // Fast array index case.
11039 : uint32_t index;
11040 3766110 : if (subject->AsArrayIndex(&index)) {
11041 2233 : return isolate->factory()->NewNumberFromUint(index);
11042 : }
11043 :
11044 : // Fast case: short integer or some sorts of junk values.
11045 7527754 : if (subject->IsSeqOneByteString()) {
11046 : int len = subject->length();
11047 2582151 : if (len == 0) return handle(Smi::kZero, isolate);
11048 :
11049 : DisallowHeapAllocation no_gc;
11050 : uint8_t const* data =
11051 5123998 : Handle<SeqOneByteString>::cast(subject)->GetChars(no_gc);
11052 2561999 : bool minus = (data[0] == '-');
11053 2561999 : int start_pos = (minus ? 1 : 0);
11054 :
11055 2561999 : if (start_pos == len) {
11056 0 : return isolate->factory()->nan_value();
11057 2561999 : } else if (data[start_pos] > '9') {
11058 : // Fast check for a junk value. A valid string may start from a
11059 : // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit
11060 : // or the 'I' character ('Infinity'). All of that have codes not greater
11061 : // than '9' except 'I' and .
11062 2412523 : if (data[start_pos] != 'I' && data[start_pos] != 0xA0) {
11063 2406103 : return isolate->factory()->nan_value();
11064 : }
11065 176016 : } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
11066 : // The maximal/minimal smi has 10 digits. If the string has less digits
11067 : // we know it will fit into the smi-data type.
11068 : int d = ParseDecimalInteger(data, start_pos, len);
11069 1561 : if (minus) {
11070 1768 : if (d == 0) return isolate->factory()->minus_zero_value();
11071 1246 : d = -d;
11072 108 : } else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize &&
11073 0 : (len == 1 || data[0] != '0')) {
11074 : // String hash is not calculated yet but all the data are present.
11075 : // Update the hash field to speed up sequential convertions.
11076 0 : uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
11077 : #ifdef DEBUG
11078 : subject->Hash(); // Force hash calculation.
11079 : DCHECK_EQ(static_cast<int>(subject->hash_field()),
11080 : static_cast<int>(hash));
11081 : #endif
11082 : subject->set_hash_field(hash);
11083 : }
11084 1300 : return handle(Smi::FromInt(d), isolate);
11085 : }
11086 : }
11087 :
11088 : // Slower case.
11089 : int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY;
11090 1336061 : return isolate->factory()->NewNumber(StringToDouble(isolate, subject, flags));
11091 : }
11092 :
11093 148240895 : String::FlatContent String::GetFlatContent(
11094 : const DisallowHeapAllocation& no_gc) {
11095 : USE(no_gc);
11096 : int length = this->length();
11097 : StringShape shape(*this);
11098 148240895 : String string = *this;
11099 : int offset = 0;
11100 148240895 : if (shape.representation_tag() == kConsStringTag) {
11101 0 : ConsString cons = ConsString::cast(string);
11102 0 : if (cons->second()->length() != 0) {
11103 0 : return FlatContent();
11104 : }
11105 0 : string = cons->first();
11106 : shape = StringShape(string);
11107 148240895 : } else if (shape.representation_tag() == kSlicedStringTag) {
11108 1097732 : SlicedString slice = SlicedString::cast(string);
11109 : offset = slice->offset();
11110 1097732 : string = slice->parent();
11111 : shape = StringShape(string);
11112 : DCHECK(shape.representation_tag() != kConsStringTag &&
11113 : shape.representation_tag() != kSlicedStringTag);
11114 : }
11115 148240895 : if (shape.representation_tag() == kThinStringTag) {
11116 23 : ThinString thin = ThinString::cast(string);
11117 23 : string = thin->actual();
11118 : shape = StringShape(string);
11119 : DCHECK(!shape.IsCons());
11120 : DCHECK(!shape.IsSliced());
11121 : }
11122 148240895 : if (shape.encoding_tag() == kOneByteStringTag) {
11123 : const uint8_t* start;
11124 143255149 : if (shape.representation_tag() == kSeqStringTag) {
11125 : start = SeqOneByteString::cast(string)->GetChars(no_gc);
11126 : } else {
11127 : start = ExternalOneByteString::cast(string)->GetChars();
11128 : }
11129 143255141 : return FlatContent(start + offset, length);
11130 : } else {
11131 : DCHECK_EQ(shape.encoding_tag(), kTwoByteStringTag);
11132 : const uc16* start;
11133 4985746 : if (shape.representation_tag() == kSeqStringTag) {
11134 : start = SeqTwoByteString::cast(string)->GetChars(no_gc);
11135 : } else {
11136 : start = ExternalTwoByteString::cast(string)->GetChars();
11137 : }
11138 4985746 : return FlatContent(start + offset, length);
11139 : }
11140 : }
11141 :
11142 5130559 : std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
11143 : RobustnessFlag robust_flag,
11144 : int offset, int length,
11145 : int* length_return) {
11146 5130559 : if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
11147 : return std::unique_ptr<char[]>();
11148 : }
11149 : // Negative length means the to the end of the string.
11150 5130559 : if (length < 0) length = kMaxInt - offset;
11151 :
11152 : // Compute the size of the UTF-8 string. Start at the specified offset.
11153 5130559 : StringCharacterStream stream(*this, offset);
11154 : int character_position = offset;
11155 : int utf8_bytes = 0;
11156 : int last = unibrow::Utf16::kNoPreviousCharacter;
11157 38511494 : while (stream.HasMore() && character_position++ < offset + length) {
11158 28250357 : uint16_t character = stream.GetNext();
11159 56500708 : utf8_bytes += unibrow::Utf8::Length(character, last);
11160 28250354 : last = character;
11161 : }
11162 :
11163 5130571 : if (length_return) {
11164 3612115 : *length_return = utf8_bytes;
11165 : }
11166 :
11167 5130571 : char* result = NewArray<char>(utf8_bytes + 1);
11168 :
11169 : // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
11170 5130578 : stream.Reset(*this, offset);
11171 : character_position = offset;
11172 : int utf8_byte_position = 0;
11173 : last = unibrow::Utf16::kNoPreviousCharacter;
11174 38511515 : while (stream.HasMore() && character_position++ < offset + length) {
11175 28250365 : uint16_t character = stream.GetNext();
11176 28250366 : if (allow_nulls == DISALLOW_NULLS && character == 0) {
11177 : character = ' ';
11178 : }
11179 : utf8_byte_position +=
11180 28250366 : unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
11181 28250361 : last = character;
11182 : }
11183 5130571 : result[utf8_byte_position] = 0;
11184 : return std::unique_ptr<char[]>(result);
11185 : }
11186 :
11187 589581 : std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
11188 : RobustnessFlag robust_flag,
11189 : int* length_return) {
11190 1519061 : return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
11191 : }
11192 :
11193 :
11194 107086 : void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) {
11195 : Relocatable* current = isolate->relocatable_top();
11196 245240 : while (current != nullptr) {
11197 31068 : current->PostGarbageCollection();
11198 31068 : current = current->prev_;
11199 : }
11200 107086 : }
11201 :
11202 :
11203 : // Reserve space for statics needing saving and restoring.
11204 1111 : int Relocatable::ArchiveSpacePerThread() {
11205 1111 : return sizeof(Relocatable*); // NOLINT
11206 : }
11207 :
11208 :
11209 : // Archive statics that are thread-local.
11210 24256 : char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
11211 24256 : *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
11212 : isolate->set_relocatable_top(nullptr);
11213 24256 : return to + ArchiveSpacePerThread();
11214 : }
11215 :
11216 :
11217 : // Restore statics that are thread-local.
11218 24256 : char* Relocatable::RestoreState(Isolate* isolate, char* from) {
11219 24256 : isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
11220 24256 : return from + ArchiveSpacePerThread();
11221 : }
11222 :
11223 6344 : char* Relocatable::Iterate(RootVisitor* v, char* thread_storage) {
11224 6344 : Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
11225 : Iterate(v, top);
11226 6344 : return thread_storage + ArchiveSpacePerThread();
11227 : }
11228 :
11229 307250 : void Relocatable::Iterate(Isolate* isolate, RootVisitor* v) {
11230 : Iterate(v, isolate->relocatable_top());
11231 307250 : }
11232 :
11233 0 : void Relocatable::Iterate(RootVisitor* v, Relocatable* top) {
11234 : Relocatable* current = top;
11235 379134 : while (current != nullptr) {
11236 65540 : current->IterateInstance(v);
11237 65540 : current = current->prev_;
11238 : }
11239 0 : }
11240 :
11241 :
11242 1606028 : FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
11243 : : Relocatable(isolate),
11244 : str_(str.location()),
11245 4818084 : length_(str->length()) {
11246 1606028 : PostGarbageCollection();
11247 1606028 : }
11248 :
11249 1345 : FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
11250 : : Relocatable(isolate),
11251 : str_(nullptr),
11252 : is_one_byte_(true),
11253 1345 : length_(input.length()),
11254 4035 : start_(input.start()) {}
11255 :
11256 1606406 : void FlatStringReader::PostGarbageCollection() {
11257 1606406 : if (str_ == nullptr) return;
11258 : Handle<String> str(str_);
11259 : DCHECK(str->IsFlat());
11260 : DisallowHeapAllocation no_gc;
11261 : // This does not actually prevent the vector from being relocated later.
11262 1606406 : String::FlatContent content = str->GetFlatContent(no_gc);
11263 : DCHECK(content.IsFlat());
11264 3212812 : is_one_byte_ = content.IsOneByte();
11265 1606406 : if (is_one_byte_) {
11266 1468427 : start_ = content.ToOneByteVector().start();
11267 : } else {
11268 137979 : start_ = content.ToUC16Vector().start();
11269 : }
11270 : }
11271 :
11272 42896 : void ConsStringIterator::Initialize(ConsString cons_string, int offset) {
11273 : DCHECK(!cons_string.is_null());
11274 138960 : root_ = cons_string;
11275 138960 : consumed_ = offset;
11276 : // Force stack blown condition to trigger restart.
11277 138960 : depth_ = 1;
11278 138960 : maximum_depth_ = kStackSize + depth_;
11279 : DCHECK(StackBlown());
11280 42896 : }
11281 :
11282 10637895 : String ConsStringIterator::Continue(int* offset_out) {
11283 : DCHECK_NE(depth_, 0);
11284 : DCHECK_EQ(0, *offset_out);
11285 10637895 : bool blew_stack = StackBlown();
11286 : String string;
11287 : // Get the next leaf if there is one.
11288 10637895 : if (!blew_stack) string = NextLeaf(&blew_stack);
11289 : // Restart search from root.
11290 10637895 : if (blew_stack) {
11291 : DCHECK(string.is_null());
11292 163335 : string = Search(offset_out);
11293 : }
11294 : // Ensure future calls return null immediately.
11295 10637895 : if (string.is_null()) Reset(ConsString());
11296 10637895 : return string;
11297 : }
11298 :
11299 326525 : String ConsStringIterator::Search(int* offset_out) {
11300 163335 : ConsString cons_string = root_;
11301 : // Reset the stack, pushing the root string.
11302 163335 : depth_ = 1;
11303 163335 : maximum_depth_ = 1;
11304 163335 : frames_[0] = cons_string;
11305 163335 : const int consumed = consumed_;
11306 : int offset = 0;
11307 : while (true) {
11308 : // Loop until the string is found which contains the target offset.
11309 34906904 : String string = cons_string->first();
11310 : int length = string->length();
11311 : int32_t type;
11312 34906904 : if (consumed < offset + length) {
11313 : // Target offset is in the left branch.
11314 : // Keep going if we're still in a ConString.
11315 : type = string->map()->instance_type();
11316 33585879 : if ((type & kStringRepresentationMask) == kConsStringTag) {
11317 33452624 : cons_string = ConsString::cast(string);
11318 : PushLeft(cons_string);
11319 : continue;
11320 : }
11321 : // Tell the stack we're done descending.
11322 : AdjustMaximumDepth();
11323 : } else {
11324 : // Descend right.
11325 : // Update progress through the string.
11326 : offset += length;
11327 : // Keep going if we're still in a ConString.
11328 1321025 : string = cons_string->second();
11329 : type = string->map()->instance_type();
11330 1321025 : if ((type & kStringRepresentationMask) == kConsStringTag) {
11331 1290945 : cons_string = ConsString::cast(string);
11332 : PushRight(cons_string);
11333 : continue;
11334 : }
11335 : // Need this to be updated for the current string.
11336 : length = string->length();
11337 : // Account for the possibility of an empty right leaf.
11338 : // This happens only if we have asked for an offset outside the string.
11339 30080 : if (length == 0) {
11340 : // Reset so future operations will return null immediately.
11341 : Reset(ConsString());
11342 145 : return String();
11343 : }
11344 : // Tell the stack we're done descending.
11345 : AdjustMaximumDepth();
11346 : // Pop stack so next iteration is in correct place.
11347 : Pop();
11348 : }
11349 : DCHECK_NE(length, 0);
11350 : // Adjust return values and exit.
11351 163190 : consumed_ = offset + length;
11352 163190 : *offset_out = consumed - offset;
11353 163190 : return string;
11354 : }
11355 : UNREACHABLE();
11356 : }
11357 :
11358 26414291 : String ConsStringIterator::NextLeaf(bool* blew_stack) {
11359 : while (true) {
11360 : // Tree traversal complete.
11361 10893404 : if (depth_ == 0) {
11362 35344 : *blew_stack = false;
11363 35344 : return String();
11364 : }
11365 : // We've lost track of higher nodes.
11366 10858060 : if (StackBlown()) {
11367 695 : *blew_stack = true;
11368 695 : return String();
11369 : }
11370 : // Go right.
11371 21714730 : ConsString cons_string = frames_[OffsetForDepth(depth_ - 1)];
11372 10857365 : String string = cons_string->second();
11373 : int32_t type = string->map()->instance_type();
11374 10857365 : if ((type & kStringRepresentationMask) != kConsStringTag) {
11375 : // Pop stack so next iteration is in correct place.
11376 : Pop();
11377 : int length = string->length();
11378 : // Could be a flattened ConsString.
11379 6194538 : if (length == 0) continue;
11380 5358240 : consumed_ += length;
11381 5358240 : return string;
11382 : }
11383 5080976 : cons_string = ConsString::cast(string);
11384 : PushRight(cons_string);
11385 : // Need to traverse all the way left.
11386 : while (true) {
11387 : // Continue left.
11388 10119811 : string = cons_string->first();
11389 : type = string->map()->instance_type();
11390 10119811 : if ((type & kStringRepresentationMask) != kConsStringTag) {
11391 : AdjustMaximumDepth();
11392 : int length = string->length();
11393 5080976 : if (length == 0) break; // Skip empty left-hand sides of ConsStrings.
11394 5080976 : consumed_ += length;
11395 5080976 : return string;
11396 : }
11397 5038835 : cons_string = ConsString::cast(string);
11398 : PushLeft(cons_string);
11399 : }
11400 : }
11401 : UNREACHABLE();
11402 : }
11403 :
11404 273526 : uint16_t ConsString::ConsStringGet(int index) {
11405 : DCHECK(index >= 0 && index < this->length());
11406 :
11407 : // Check for a flattened cons string
11408 547052 : if (second()->length() == 0) {
11409 77526 : String left = first();
11410 : return left->Get(index);
11411 : }
11412 :
11413 196000 : String string = String::cast(*this);
11414 :
11415 : while (true) {
11416 1122445 : if (StringShape(string).IsCons()) {
11417 926445 : ConsString cons_string = ConsString::cast(string);
11418 926445 : String left = cons_string->first();
11419 926445 : if (left->length() > index) {
11420 518995 : string = left;
11421 : } else {
11422 407450 : index -= left->length();
11423 407450 : string = cons_string->second();
11424 : }
11425 : } else {
11426 196000 : return string->Get(index);
11427 : }
11428 : }
11429 :
11430 926445 : UNREACHABLE();
11431 : }
11432 :
11433 5248 : uint16_t ThinString::ThinStringGet(int index) { return actual()->Get(index); }
11434 :
11435 1095402 : uint16_t SlicedString::SlicedStringGet(int index) {
11436 2190804 : return parent()->Get(offset() + index);
11437 : }
11438 :
11439 : template <typename sinkchar>
11440 131288879 : void String::WriteToFlat(String src, sinkchar* sink, int f, int t) {
11441 : DisallowHeapAllocation no_gc;
11442 131288879 : String source = src;
11443 : int from = f;
11444 : int to = t;
11445 : while (true) {
11446 : DCHECK(0 <= from && from <= to && to <= source->length());
11447 192652335 : switch (StringShape(source).full_representation_tag()) {
11448 : case kOneByteStringTag | kExternalStringTag: {
11449 : CopyChars(sink, ExternalOneByteString::cast(source)->GetChars() + from,
11450 852134 : to - from);
11451 : return;
11452 : }
11453 : case kTwoByteStringTag | kExternalStringTag: {
11454 : const uc16* data =
11455 : ExternalTwoByteString::cast(source)->GetChars();
11456 : CopyChars(sink,
11457 : data + from,
11458 280345 : to - from);
11459 : return;
11460 : }
11461 : case kOneByteStringTag | kSeqStringTag: {
11462 : CopyChars(sink, SeqOneByteString::cast(source)->GetChars(no_gc) + from,
11463 171023086 : to - from);
11464 : return;
11465 : }
11466 : case kTwoByteStringTag | kSeqStringTag: {
11467 : CopyChars(sink, SeqTwoByteString::cast(source)->GetChars(no_gc) + from,
11468 12825068 : to - from);
11469 : return;
11470 : }
11471 : case kOneByteStringTag | kConsStringTag:
11472 : case kTwoByteStringTag | kConsStringTag: {
11473 98385963 : ConsString cons_string = ConsString::cast(source);
11474 98385963 : String first = cons_string->first();
11475 : int boundary = first->length();
11476 98385963 : if (to - boundary >= boundary - from) {
11477 : // Right hand side is longer. Recurse over left.
11478 45206160 : if (from < boundary) {
11479 45206160 : WriteToFlat(first, sink, from, boundary);
11480 90412320 : if (from == 0 && cons_string->second() == first) {
11481 37036955 : CopyChars(sink + boundary, sink, boundary);
11482 37036955 : return;
11483 : }
11484 8169205 : sink += boundary - from;
11485 : from = 0;
11486 : } else {
11487 0 : from -= boundary;
11488 : }
11489 : to -= boundary;
11490 8169205 : source = cons_string->second();
11491 : } else {
11492 : // Left hand side is longer. Recurse over right.
11493 53179803 : if (to > boundary) {
11494 52803976 : String second = cons_string->second();
11495 : // When repeatedly appending to a string, we get a cons string that
11496 : // is unbalanced to the left, a list, essentially. We inline the
11497 : // common case of sequential one-byte right child.
11498 52803977 : if (to - boundary == 1) {
11499 34326250 : sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
11500 35640852 : } else if (second->IsSeqOneByteString()) {
11501 24112139 : CopyChars(sink + boundary - from,
11502 : SeqOneByteString::cast(second)->GetChars(no_gc),
11503 48224278 : to - boundary);
11504 : } else {
11505 11528713 : WriteToFlat(second,
11506 11528713 : sink + boundary - from,
11507 : 0,
11508 11528713 : to - boundary);
11509 : }
11510 : to = boundary;
11511 : }
11512 53179804 : source = first;
11513 : }
11514 61349009 : break;
11515 : }
11516 : case kOneByteStringTag | kSlicedStringTag:
11517 : case kTwoByteStringTag | kSlicedStringTag: {
11518 1621437 : SlicedString slice = SlicedString::cast(source);
11519 1621437 : unsigned offset = slice->offset();
11520 1621437 : WriteToFlat(slice->parent(), sink, from + offset, to + offset);
11521 : return;
11522 : }
11523 : case kOneByteStringTag | kThinStringTag:
11524 : case kTwoByteStringTag | kThinStringTag:
11525 14447 : source = ThinString::cast(source)->actual();
11526 14447 : break;
11527 : }
11528 : }
11529 : }
11530 :
11531 : template <typename SourceChar>
11532 52700 : static void CalculateLineEndsImpl(Isolate* isolate, std::vector<int>* line_ends,
11533 : Vector<const SourceChar> src,
11534 : bool include_ending_line) {
11535 105400 : const int src_len = src.length();
11536 154346830 : for (int i = 0; i < src_len - 1; i++) {
11537 308588260 : SourceChar current = src[i];
11538 308588260 : SourceChar next = src[i + 1];
11539 154294130 : if (IsLineTerminatorSequence(current, next)) line_ends->push_back(i);
11540 : }
11541 :
11542 157530 : if (src_len > 0 && IsLineTerminatorSequence(src[src_len - 1], 0)) {
11543 33322 : line_ends->push_back(src_len - 1);
11544 : }
11545 52700 : if (include_ending_line) {
11546 : // Include one character beyond the end of script. The rewriter uses that
11547 : // position for the implicit return statement.
11548 50268 : line_ends->push_back(src_len);
11549 : }
11550 52700 : }
11551 :
11552 52700 : Handle<FixedArray> String::CalculateLineEnds(Isolate* isolate,
11553 : Handle<String> src,
11554 : bool include_ending_line) {
11555 52700 : src = Flatten(isolate, src);
11556 : // Rough estimate of line count based on a roughly estimated average
11557 : // length of (unpacked) code.
11558 52700 : int line_count_estimate = src->length() >> 4;
11559 : std::vector<int> line_ends;
11560 52700 : line_ends.reserve(line_count_estimate);
11561 : { DisallowHeapAllocation no_allocation; // ensure vectors stay valid.
11562 : // Dispatch on type of strings.
11563 52700 : String::FlatContent content = src->GetFlatContent(no_allocation);
11564 : DCHECK(content.IsFlat());
11565 52700 : if (content.IsOneByte()) {
11566 : CalculateLineEndsImpl(isolate,
11567 : &line_ends,
11568 : content.ToOneByteVector(),
11569 105360 : include_ending_line);
11570 : } else {
11571 : CalculateLineEndsImpl(isolate,
11572 : &line_ends,
11573 : content.ToUC16Vector(),
11574 40 : include_ending_line);
11575 : }
11576 : }
11577 105400 : int line_count = static_cast<int>(line_ends.size());
11578 52700 : Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count);
11579 9701746 : for (int i = 0; i < line_count; i++) {
11580 19298092 : array->set(i, Smi::FromInt(line_ends[i]));
11581 : }
11582 105400 : return array;
11583 : }
11584 :
11585 : namespace {
11586 :
11587 : template <typename sinkchar>
11588 105139 : void WriteFixedArrayToFlat(FixedArray fixed_array, int length, String separator,
11589 : sinkchar* sink, int sink_length) {
11590 : DisallowHeapAllocation no_allocation;
11591 105139 : CHECK_GT(length, 0);
11592 105139 : CHECK_LE(length, fixed_array->length());
11593 : #ifdef DEBUG
11594 : sinkchar* sink_end = sink + sink_length;
11595 : #endif
11596 :
11597 : const int separator_length = separator->length();
11598 : const bool use_one_byte_separator_fast_path =
11599 : separator_length == 1 && sizeof(sinkchar) == 1 &&
11600 165617 : StringShape(separator).IsSequentialOneByte();
11601 : uint8_t separator_one_char;
11602 103406 : if (use_one_byte_separator_fast_path) {
11603 62211 : CHECK(StringShape(separator).IsSequentialOneByte());
11604 62211 : CHECK_EQ(separator->length(), 1);
11605 62211 : separator_one_char =
11606 : SeqOneByteString::cast(separator)->GetChars(no_allocation)[0];
11607 : }
11608 :
11609 105139 : uint32_t num_separators = 0;
11610 31390589 : for (int i = 0; i < length; i++) {
11611 31390589 : Object element = fixed_array->get(i);
11612 : const bool element_is_separator_sequence = element->IsSmi();
11613 :
11614 : // If element is a Smi, it represents the number of separators to write.
11615 31390589 : if (V8_UNLIKELY(element_is_separator_sequence)) {
11616 6774 : CHECK(element->ToUint32(&num_separators));
11617 : // Verify that Smis (number of separators) only occur when necessary:
11618 : // 1) at the beginning
11619 : // 2) at the end
11620 : // 3) when the number of separators > 1
11621 : // - It is assumed that consecutive Strings will have one separator,
11622 : // so there is no need for a Smi.
11623 : DCHECK(i == 0 || i == length - 1 || num_separators > 1);
11624 : }
11625 :
11626 : // Write separator(s) if necessary.
11627 31390589 : if (num_separators > 0 && separator_length > 0) {
11628 : // TODO(pwong): Consider doubling strategy employed by runtime-strings.cc
11629 : // WriteRepeatToFlat().
11630 : // Fast path for single character, single byte separators.
11631 31106525 : if (use_one_byte_separator_fast_path) {
11632 : DCHECK_LE(sink + num_separators, sink_end);
11633 29487177 : memset(sink, separator_one_char, num_separators);
11634 : DCHECK_EQ(separator_length, 1);
11635 29487177 : sink += num_separators;
11636 : } else {
11637 2520944 : for (uint32_t j = 0; j < num_separators; j++) {
11638 : DCHECK_LE(sink + separator_length, sink_end);
11639 2520944 : String::WriteToFlat(separator, sink, 0, separator_length);
11640 2520944 : sink += separator_length;
11641 : }
11642 : }
11643 : }
11644 :
11645 31390589 : if (V8_UNLIKELY(element_is_separator_sequence)) {
11646 6774 : num_separators = 0;
11647 : } else {
11648 : DCHECK(element->IsString());
11649 : String string = String::cast(element);
11650 : const int string_length = string->length();
11651 :
11652 : DCHECK(string_length == 0 || sink < sink_end);
11653 31383815 : String::WriteToFlat(string, sink, 0, string_length);
11654 31383815 : sink += string_length;
11655 :
11656 : // Next string element, needs at least one separator preceding it.
11657 31383815 : num_separators = 1;
11658 : }
11659 : }
11660 :
11661 : // Verify we have written to the end of the sink.
11662 : DCHECK_EQ(sink, sink_end);
11663 105139 : }
11664 :
11665 : } // namespace
11666 :
11667 : // static
11668 105139 : Address JSArray::ArrayJoinConcatToSequentialString(Isolate* isolate,
11669 : Address raw_fixed_array,
11670 : intptr_t length,
11671 : Address raw_separator,
11672 : Address raw_dest) {
11673 : DisallowHeapAllocation no_allocation;
11674 105139 : DisallowJavascriptExecution no_js(isolate);
11675 105139 : FixedArray fixed_array = FixedArray::cast(Object(raw_fixed_array));
11676 105139 : String separator = String::cast(Object(raw_separator));
11677 : String dest = String::cast(Object(raw_dest));
11678 : DCHECK(fixed_array->IsFixedArray());
11679 : DCHECK(StringShape(dest).IsSequentialOneByte() ||
11680 : StringShape(dest).IsSequentialTwoByte());
11681 :
11682 105139 : if (StringShape(dest).IsSequentialOneByte()) {
11683 : WriteFixedArrayToFlat(fixed_array, static_cast<int>(length), separator,
11684 : SeqOneByteString::cast(dest)->GetChars(no_allocation),
11685 103406 : dest->length());
11686 : } else {
11687 : DCHECK(StringShape(dest).IsSequentialTwoByte());
11688 : WriteFixedArrayToFlat(fixed_array, static_cast<int>(length), separator,
11689 : SeqTwoByteString::cast(dest)->GetChars(no_allocation),
11690 1733 : dest->length());
11691 : }
11692 105139 : return dest->ptr();
11693 : }
11694 :
11695 : // Compares the contents of two strings by reading and comparing
11696 : // int-sized blocks of characters.
11697 : template <typename Char>
11698 : static inline bool CompareRawStringContents(const Char* const a,
11699 : const Char* const b,
11700 : int length) {
11701 19112538 : return CompareChars(a, b, length) == 0;
11702 : }
11703 :
11704 :
11705 : template<typename Chars1, typename Chars2>
11706 : class RawStringComparator : public AllStatic {
11707 : public:
11708 : static inline bool compare(const Chars1* a, const Chars2* b, int len) {
11709 : DCHECK(sizeof(Chars1) != sizeof(Chars2));
11710 933 : for (int i = 0; i < len; i++) {
11711 933 : if (a[i] != b[i]) {
11712 : return false;
11713 : }
11714 : }
11715 : return true;
11716 : }
11717 : };
11718 :
11719 :
11720 : template<>
11721 : class RawStringComparator<uint16_t, uint16_t> {
11722 : public:
11723 : static inline bool compare(const uint16_t* a, const uint16_t* b, int len) {
11724 : return CompareRawStringContents(a, b, len);
11725 : }
11726 : };
11727 :
11728 :
11729 : template<>
11730 : class RawStringComparator<uint8_t, uint8_t> {
11731 : public:
11732 : static inline bool compare(const uint8_t* a, const uint8_t* b, int len) {
11733 : return CompareRawStringContents(a, b, len);
11734 : }
11735 : };
11736 :
11737 :
11738 : class StringComparator {
11739 : class State {
11740 : public:
11741 124684 : State() : is_one_byte_(true), length_(0), buffer8_(nullptr) {}
11742 :
11743 124684 : void Init(String string) {
11744 124684 : ConsString cons_string = String::VisitFlat(this, string);
11745 : iter_.Reset(cons_string);
11746 124684 : if (!cons_string.is_null()) {
11747 : int offset;
11748 90 : string = iter_.Next(&offset);
11749 45 : String::VisitFlat(this, string, offset);
11750 : }
11751 124684 : }
11752 :
11753 : inline void VisitOneByteString(const uint8_t* chars, int length) {
11754 2382 : is_one_byte_ = true;
11755 2382 : buffer8_ = chars;
11756 2382 : length_ = length;
11757 : }
11758 :
11759 : inline void VisitTwoByteString(const uint16_t* chars, int length) {
11760 122652 : is_one_byte_ = false;
11761 122652 : buffer16_ = chars;
11762 122652 : length_ = length;
11763 : }
11764 :
11765 700 : void Advance(int consumed) {
11766 : DCHECK(consumed <= length_);
11767 : // Still in buffer.
11768 700 : if (length_ != consumed) {
11769 350 : if (is_one_byte_) {
11770 350 : buffer8_ += consumed;
11771 : } else {
11772 0 : buffer16_ += consumed;
11773 : }
11774 350 : length_ -= consumed;
11775 1050 : return;
11776 : }
11777 : // Advance state.
11778 : int offset;
11779 700 : String next = iter_.Next(&offset);
11780 : DCHECK_EQ(0, offset);
11781 : DCHECK(!next.is_null());
11782 350 : String::VisitFlat(this, next);
11783 : }
11784 :
11785 : ConsStringIterator iter_;
11786 : bool is_one_byte_;
11787 : int length_;
11788 : union {
11789 : const uint8_t* buffer8_;
11790 : const uint16_t* buffer16_;
11791 : };
11792 :
11793 : private:
11794 : DISALLOW_COPY_AND_ASSIGN(State);
11795 : };
11796 :
11797 : public:
11798 124684 : inline StringComparator() = default;
11799 :
11800 : template<typename Chars1, typename Chars2>
11801 : static inline bool Equals(State* state_1, State* state_2, int to_check) {
11802 : const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_);
11803 : const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_);
11804 : return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check);
11805 : }
11806 :
11807 62342 : bool Equals(String string_1, String string_2) {
11808 : int length = string_1->length();
11809 125034 : state_1_.Init(string_1);
11810 125034 : state_2_.Init(string_2);
11811 : while (true) {
11812 62692 : int to_check = Min(state_1_.length_, state_2_.length_);
11813 : DCHECK(to_check > 0 && to_check <= length);
11814 : bool is_equal;
11815 62692 : if (state_1_.is_one_byte_) {
11816 1281 : if (state_2_.is_one_byte_) {
11817 : is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check);
11818 : } else {
11819 : is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check);
11820 : }
11821 : } else {
11822 61411 : if (state_2_.is_one_byte_) {
11823 : is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check);
11824 : } else {
11825 : is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check);
11826 : }
11827 : }
11828 : // Looping done.
11829 62692 : if (!is_equal) return false;
11830 62692 : length -= to_check;
11831 : // Exit condition. Strings are equal.
11832 62692 : if (length == 0) return true;
11833 350 : state_1_.Advance(to_check);
11834 350 : state_2_.Advance(to_check);
11835 350 : }
11836 : }
11837 :
11838 : private:
11839 : State state_1_;
11840 : State state_2_;
11841 :
11842 : DISALLOW_COPY_AND_ASSIGN(StringComparator);
11843 : };
11844 :
11845 17204529 : bool String::SlowEquals(String other) {
11846 : DisallowHeapAllocation no_gc;
11847 : // Fast check: negative check with lengths.
11848 : int len = length();
11849 17204529 : if (len != other->length()) return false;
11850 9421112 : if (len == 0) return true;
11851 :
11852 : // Fast check: if at least one ThinString is involved, dereference it/them
11853 : // and restart.
11854 28253070 : if (this->IsThinString() || other->IsThinString()) {
11855 10258 : if (other->IsThinString()) other = ThinString::cast(other)->actual();
11856 10258 : if (this->IsThinString()) {
11857 10258 : return ThinString::cast(*this)->actual()->Equals(other);
11858 : } else {
11859 0 : return this->Equals(other);
11860 : }
11861 : }
11862 :
11863 : // Fast check: if hash code is computed for both strings
11864 : // a fast negative check can be performed.
11865 18821189 : if (HasHashCode() && other->HasHashCode()) {
11866 : #ifdef ENABLE_SLOW_DCHECKS
11867 : if (FLAG_enable_slow_asserts) {
11868 : if (Hash() != other->Hash()) {
11869 : bool found_difference = false;
11870 : for (int i = 0; i < len; i++) {
11871 : if (Get(i) != other->Get(i)) {
11872 : found_difference = true;
11873 : break;
11874 : }
11875 : }
11876 : DCHECK(found_difference);
11877 : }
11878 : }
11879 : #endif
11880 9390982 : if (Hash() != other->Hash()) return false;
11881 : }
11882 :
11883 : // We know the strings are both non-empty. Compare the first chars
11884 : // before we try to flatten the strings.
11885 7323147 : if (this->Get(0) != other->Get(0)) return false;
11886 :
11887 14569601 : if (IsSeqOneByteString() && other->IsSeqOneByteString()) {
11888 : const uint8_t* str1 = SeqOneByteString::cast(*this)->GetChars(no_gc);
11889 : const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars(no_gc);
11890 7253603 : return CompareRawStringContents(str1, str2, len);
11891 : }
11892 :
11893 62342 : StringComparator comparator;
11894 62342 : return comparator.Equals(*this, other);
11895 : }
11896 :
11897 742191 : bool String::SlowEquals(Isolate* isolate, Handle<String> one,
11898 : Handle<String> two) {
11899 : // Fast check: negative check with lengths.
11900 : int one_length = one->length();
11901 742191 : if (one_length != two->length()) return false;
11902 732826 : if (one_length == 0) return true;
11903 :
11904 : // Fast check: if at least one ThinString is involved, dereference it/them
11905 : // and restart.
11906 2931304 : if (one->IsThinString() || two->IsThinString()) {
11907 46 : if (one->IsThinString())
11908 0 : one = handle(ThinString::cast(*one)->actual(), isolate);
11909 46 : if (two->IsThinString())
11910 46 : two = handle(ThinString::cast(*two)->actual(), isolate);
11911 23 : return String::Equals(isolate, one, two);
11912 : }
11913 :
11914 : // Fast check: if hash code is computed for both strings
11915 : // a fast negative check can be performed.
11916 744102 : if (one->HasHashCode() && two->HasHashCode()) {
11917 : #ifdef ENABLE_SLOW_DCHECKS
11918 : if (FLAG_enable_slow_asserts) {
11919 : if (one->Hash() != two->Hash()) {
11920 : bool found_difference = false;
11921 : for (int i = 0; i < one_length; i++) {
11922 : if (one->Get(i) != two->Get(i)) {
11923 : found_difference = true;
11924 : break;
11925 : }
11926 : }
11927 : DCHECK(found_difference);
11928 : }
11929 : }
11930 : #endif
11931 13002 : if (one->Hash() != two->Hash()) return false;
11932 : }
11933 :
11934 : // We know the strings are both non-empty. Compare the first chars
11935 : // before we try to flatten the strings.
11936 2198334 : if (one->Get(0) != two->Get(0)) return false;
11937 :
11938 732621 : one = String::Flatten(isolate, one);
11939 732621 : two = String::Flatten(isolate, two);
11940 :
11941 : DisallowHeapAllocation no_gc;
11942 732621 : String::FlatContent flat1 = one->GetFlatContent(no_gc);
11943 732621 : String::FlatContent flat2 = two->GetFlatContent(no_gc);
11944 :
11945 732621 : if (flat1.IsOneByte() && flat2.IsOneByte()) {
11946 : return CompareRawStringContents(flat1.ToOneByteVector().start(),
11947 : flat2.ToOneByteVector().start(),
11948 : one_length);
11949 : } else {
11950 7643751 : for (int i = 0; i < one_length; i++) {
11951 7643751 : if (flat1.Get(i) != flat2.Get(i)) return false;
11952 : }
11953 : return true;
11954 : }
11955 : }
11956 :
11957 :
11958 : // static
11959 4806180 : ComparisonResult String::Compare(Isolate* isolate, Handle<String> x,
11960 : Handle<String> y) {
11961 : // A few fast case tests before we flatten.
11962 4806180 : if (x.is_identical_to(y)) {
11963 : return ComparisonResult::kEqual;
11964 4806180 : } else if (y->length() == 0) {
11965 : return x->length() == 0 ? ComparisonResult::kEqual
11966 0 : : ComparisonResult::kGreaterThan;
11967 4806180 : } else if (x->length() == 0) {
11968 : return ComparisonResult::kLessThan;
11969 : }
11970 :
11971 19224720 : int const d = x->Get(0) - y->Get(0);
11972 4806180 : if (d < 0) {
11973 : return ComparisonResult::kLessThan;
11974 3878046 : } else if (d > 0) {
11975 : return ComparisonResult::kGreaterThan;
11976 : }
11977 :
11978 : // Slow case.
11979 384688 : x = String::Flatten(isolate, x);
11980 384688 : y = String::Flatten(isolate, y);
11981 :
11982 : DisallowHeapAllocation no_gc;
11983 : ComparisonResult result = ComparisonResult::kEqual;
11984 : int prefix_length = x->length();
11985 384688 : if (y->length() < prefix_length) {
11986 : prefix_length = y->length();
11987 : result = ComparisonResult::kGreaterThan;
11988 337806 : } else if (y->length() > prefix_length) {
11989 : result = ComparisonResult::kLessThan;
11990 : }
11991 : int r;
11992 384688 : String::FlatContent x_content = x->GetFlatContent(no_gc);
11993 384688 : String::FlatContent y_content = y->GetFlatContent(no_gc);
11994 384688 : if (x_content.IsOneByte()) {
11995 : Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
11996 380089 : if (y_content.IsOneByte()) {
11997 : Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11998 380071 : r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11999 : } else {
12000 : Vector<const uc16> y_chars = y_content.ToUC16Vector();
12001 18 : r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
12002 : }
12003 : } else {
12004 : Vector<const uc16> x_chars = x_content.ToUC16Vector();
12005 4599 : if (y_content.IsOneByte()) {
12006 : Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
12007 18 : r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
12008 : } else {
12009 : Vector<const uc16> y_chars = y_content.ToUC16Vector();
12010 4581 : r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
12011 : }
12012 : }
12013 384688 : if (r < 0) {
12014 : result = ComparisonResult::kLessThan;
12015 156682 : } else if (r > 0) {
12016 : result = ComparisonResult::kGreaterThan;
12017 : }
12018 384688 : return result;
12019 : }
12020 :
12021 799 : Object String::IndexOf(Isolate* isolate, Handle<Object> receiver,
12022 : Handle<Object> search, Handle<Object> position) {
12023 1598 : if (receiver->IsNullOrUndefined(isolate)) {
12024 540 : THROW_NEW_ERROR_RETURN_FAILURE(
12025 : isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
12026 : isolate->factory()->NewStringFromAsciiChecked(
12027 : "String.prototype.indexOf")));
12028 : }
12029 : Handle<String> receiver_string;
12030 1238 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string,
12031 : Object::ToString(isolate, receiver));
12032 :
12033 : Handle<String> search_string;
12034 1238 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
12035 : Object::ToString(isolate, search));
12036 :
12037 1247 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
12038 : Object::ToInteger(isolate, position));
12039 :
12040 : uint32_t index = receiver_string->ToValidIndex(*position);
12041 : return Smi::FromInt(
12042 1220 : String::IndexOf(isolate, receiver_string, search_string, index));
12043 : }
12044 :
12045 : namespace {
12046 :
12047 : template <typename T>
12048 1052751 : int SearchString(Isolate* isolate, String::FlatContent receiver_content,
12049 : Vector<T> pat_vector, int start_index) {
12050 1052751 : if (receiver_content.IsOneByte()) {
12051 : return SearchString(isolate, receiver_content.ToOneByteVector(), pat_vector,
12052 1048881 : start_index);
12053 : }
12054 : return SearchString(isolate, receiver_content.ToUC16Vector(), pat_vector,
12055 3870 : start_index);
12056 : }
12057 :
12058 : } // namespace
12059 :
12060 1055850 : int String::IndexOf(Isolate* isolate, Handle<String> receiver,
12061 : Handle<String> search, int start_index) {
12062 : DCHECK_LE(0, start_index);
12063 : DCHECK(start_index <= receiver->length());
12064 :
12065 1055850 : uint32_t search_length = search->length();
12066 1055850 : if (search_length == 0) return start_index;
12067 :
12068 1055805 : uint32_t receiver_length = receiver->length();
12069 1055805 : if (start_index + search_length > receiver_length) return -1;
12070 :
12071 1052751 : receiver = String::Flatten(isolate, receiver);
12072 1052751 : search = String::Flatten(isolate, search);
12073 :
12074 : DisallowHeapAllocation no_gc; // ensure vectors stay valid
12075 : // Extract flattened substrings of cons strings before getting encoding.
12076 1052751 : String::FlatContent receiver_content = receiver->GetFlatContent(no_gc);
12077 1052751 : String::FlatContent search_content = search->GetFlatContent(no_gc);
12078 :
12079 : // dispatch on type of strings
12080 1052751 : if (search_content.IsOneByte()) {
12081 1050996 : Vector<const uint8_t> pat_vector = search_content.ToOneByteVector();
12082 : return SearchString<const uint8_t>(isolate, receiver_content, pat_vector,
12083 1050996 : start_index);
12084 : }
12085 1755 : Vector<const uc16> pat_vector = search_content.ToUC16Vector();
12086 : return SearchString<const uc16>(isolate, receiver_content, pat_vector,
12087 1755 : start_index);
12088 : }
12089 :
12090 3894 : MaybeHandle<String> String::GetSubstitution(Isolate* isolate, Match* match,
12091 : Handle<String> replacement,
12092 : int start_index) {
12093 : DCHECK_GE(start_index, 0);
12094 :
12095 : Factory* factory = isolate->factory();
12096 :
12097 : const int replacement_length = replacement->length();
12098 3894 : const int captures_length = match->CaptureCount();
12099 :
12100 3894 : replacement = String::Flatten(isolate, replacement);
12101 :
12102 : Handle<String> dollar_string =
12103 3894 : factory->LookupSingleCharacterStringFromCode('$');
12104 : int next_dollar_ix =
12105 3894 : String::IndexOf(isolate, replacement, dollar_string, start_index);
12106 3894 : if (next_dollar_ix < 0) {
12107 153 : return replacement;
12108 : }
12109 :
12110 3741 : IncrementalStringBuilder builder(isolate);
12111 :
12112 3741 : if (next_dollar_ix > 0) {
12113 279 : builder.AppendString(factory->NewSubString(replacement, 0, next_dollar_ix));
12114 : }
12115 :
12116 : while (true) {
12117 7962 : const int peek_ix = next_dollar_ix + 1;
12118 7962 : if (peek_ix >= replacement_length) {
12119 : builder.AppendCharacter('$');
12120 18 : return builder.Finish();
12121 : }
12122 :
12123 : int continue_from_ix = -1;
12124 15888 : const uint16_t peek = replacement->Get(peek_ix);
12125 7944 : switch (peek) {
12126 : case '$': // $$
12127 : builder.AppendCharacter('$');
12128 54 : continue_from_ix = peek_ix + 1;
12129 54 : break;
12130 : case '&': // $& - match
12131 54 : builder.AppendString(match->GetMatch());
12132 54 : continue_from_ix = peek_ix + 1;
12133 54 : break;
12134 : case '`': // $` - prefix
12135 36 : builder.AppendString(match->GetPrefix());
12136 36 : continue_from_ix = peek_ix + 1;
12137 36 : break;
12138 : case '\'': // $' - suffix
12139 36 : builder.AppendString(match->GetSuffix());
12140 36 : continue_from_ix = peek_ix + 1;
12141 36 : break;
12142 : case '0':
12143 : case '1':
12144 : case '2':
12145 : case '3':
12146 : case '4':
12147 : case '5':
12148 : case '6':
12149 : case '7':
12150 : case '8':
12151 : case '9': {
12152 : // Valid indices are $1 .. $9, $01 .. $09 and $10 .. $99
12153 7278 : int scaled_index = (peek - '0');
12154 : int advance = 1;
12155 :
12156 7278 : if (peek_ix + 1 < replacement_length) {
12157 12108 : const uint16_t next_peek = replacement->Get(peek_ix + 1);
12158 6054 : if (next_peek >= '0' && next_peek <= '9') {
12159 1341 : const int new_scaled_index = scaled_index * 10 + (next_peek - '0');
12160 1341 : if (new_scaled_index < captures_length) {
12161 : scaled_index = new_scaled_index;
12162 : advance = 2;
12163 : }
12164 : }
12165 : }
12166 :
12167 7278 : if (scaled_index == 0 || scaled_index >= captures_length) {
12168 : builder.AppendCharacter('$');
12169 : continue_from_ix = peek_ix;
12170 7368 : break;
12171 : }
12172 :
12173 : bool capture_exists;
12174 : Handle<String> capture;
12175 14376 : ASSIGN_RETURN_ON_EXCEPTION(
12176 : isolate, capture, match->GetCapture(scaled_index, &capture_exists),
12177 : String);
12178 7188 : if (capture_exists) builder.AppendString(capture);
12179 7188 : continue_from_ix = peek_ix + advance;
12180 7188 : break;
12181 : }
12182 : case '<': { // $<name> - named capture
12183 : typedef String::Match::CaptureState CaptureState;
12184 :
12185 459 : if (!match->HasNamedCaptures()) {
12186 : builder.AppendCharacter('$');
12187 : continue_from_ix = peek_ix;
12188 540 : break;
12189 : }
12190 :
12191 : Handle<String> bracket_string =
12192 378 : factory->LookupSingleCharacterStringFromCode('>');
12193 : const int closing_bracket_ix =
12194 378 : String::IndexOf(isolate, replacement, bracket_string, peek_ix + 1);
12195 :
12196 378 : if (closing_bracket_ix == -1) {
12197 : // No closing bracket was found, treat '$<' as a string literal.
12198 : builder.AppendCharacter('$');
12199 : continue_from_ix = peek_ix;
12200 72 : break;
12201 : }
12202 :
12203 : Handle<String> capture_name =
12204 306 : factory->NewSubString(replacement, peek_ix + 1, closing_bracket_ix);
12205 : Handle<String> capture;
12206 : CaptureState capture_state;
12207 612 : ASSIGN_RETURN_ON_EXCEPTION(
12208 : isolate, capture,
12209 : match->GetNamedCapture(capture_name, &capture_state), String);
12210 :
12211 306 : switch (capture_state) {
12212 : case CaptureState::INVALID:
12213 : case CaptureState::UNMATCHED:
12214 : break;
12215 : case CaptureState::MATCHED:
12216 126 : builder.AppendString(capture);
12217 126 : break;
12218 : }
12219 :
12220 306 : continue_from_ix = closing_bracket_ix + 1;
12221 306 : break;
12222 : }
12223 : default:
12224 : builder.AppendCharacter('$');
12225 : continue_from_ix = peek_ix;
12226 27 : break;
12227 : }
12228 :
12229 : // Go the the next $ in the replacement.
12230 : // TODO(jgruber): Single-char lookups could be much more efficient.
12231 : DCHECK_NE(continue_from_ix, -1);
12232 : next_dollar_ix =
12233 7944 : String::IndexOf(isolate, replacement, dollar_string, continue_from_ix);
12234 :
12235 : // Return if there are no more $ characters in the replacement. If we
12236 : // haven't reached the end, we need to append the suffix.
12237 7944 : if (next_dollar_ix < 0) {
12238 3723 : if (continue_from_ix < replacement_length) {
12239 : builder.AppendString(factory->NewSubString(
12240 1311 : replacement, continue_from_ix, replacement_length));
12241 : }
12242 3723 : return builder.Finish();
12243 : }
12244 :
12245 : // Append substring between the previous and the next $ character.
12246 4221 : if (next_dollar_ix > continue_from_ix) {
12247 : builder.AppendString(
12248 72 : factory->NewSubString(replacement, continue_from_ix, next_dollar_ix));
12249 : }
12250 : }
12251 :
12252 : UNREACHABLE();
12253 : }
12254 :
12255 : namespace { // for String.Prototype.lastIndexOf
12256 :
12257 : template <typename schar, typename pchar>
12258 1313 : int StringMatchBackwards(Vector<const schar> subject,
12259 : Vector<const pchar> pattern, int idx) {
12260 1313 : int pattern_length = pattern.length();
12261 : DCHECK_GE(pattern_length, 1);
12262 : DCHECK(idx + pattern_length <= subject.length());
12263 :
12264 : if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
12265 0 : for (int i = 0; i < pattern_length; i++) {
12266 0 : uc16 c = pattern[i];
12267 0 : if (c > String::kMaxOneByteCharCode) {
12268 : return -1;
12269 : }
12270 : }
12271 : }
12272 :
12273 1313 : pchar pattern_first_char = pattern[0];
12274 4999 : for (int i = idx; i >= 0; i--) {
12275 12354 : if (subject[i] != pattern_first_char) continue;
12276 : int j = 1;
12277 1869 : while (j < pattern_length) {
12278 2073 : if (pattern[j] != subject[i + j]) {
12279 : break;
12280 : }
12281 673 : j++;
12282 : }
12283 1196 : if (j == pattern_length) {
12284 : return i;
12285 : }
12286 : }
12287 : return -1;
12288 : }
12289 :
12290 : } // namespace
12291 :
12292 1727 : Object String::LastIndexOf(Isolate* isolate, Handle<Object> receiver,
12293 : Handle<Object> search, Handle<Object> position) {
12294 3454 : if (receiver->IsNullOrUndefined(isolate)) {
12295 486 : THROW_NEW_ERROR_RETURN_FAILURE(
12296 : isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
12297 : isolate->factory()->NewStringFromAsciiChecked(
12298 : "String.prototype.lastIndexOf")));
12299 : }
12300 : Handle<String> receiver_string;
12301 3130 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string,
12302 : Object::ToString(isolate, receiver));
12303 :
12304 : Handle<String> search_string;
12305 3130 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
12306 : Object::ToString(isolate, search));
12307 :
12308 3130 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
12309 : Object::ToNumber(isolate, position));
12310 :
12311 : uint32_t start_index;
12312 :
12313 3130 : if (position->IsNaN()) {
12314 1088 : start_index = receiver_string->length();
12315 : } else {
12316 954 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
12317 : Object::ToInteger(isolate, position));
12318 : start_index = receiver_string->ToValidIndex(*position);
12319 : }
12320 :
12321 1565 : uint32_t pattern_length = search_string->length();
12322 1565 : uint32_t receiver_length = receiver_string->length();
12323 :
12324 1565 : if (start_index + pattern_length > receiver_length) {
12325 1160 : start_index = receiver_length - pattern_length;
12326 : }
12327 :
12328 1565 : if (pattern_length == 0) {
12329 504 : return Smi::FromInt(start_index);
12330 : }
12331 :
12332 1313 : receiver_string = String::Flatten(isolate, receiver_string);
12333 1313 : search_string = String::Flatten(isolate, search_string);
12334 :
12335 : int last_index = -1;
12336 : DisallowHeapAllocation no_gc; // ensure vectors stay valid
12337 :
12338 1313 : String::FlatContent receiver_content = receiver_string->GetFlatContent(no_gc);
12339 1313 : String::FlatContent search_content = search_string->GetFlatContent(no_gc);
12340 :
12341 1313 : if (search_content.IsOneByte()) {
12342 1313 : Vector<const uint8_t> pat_vector = search_content.ToOneByteVector();
12343 1313 : if (receiver_content.IsOneByte()) {
12344 : last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
12345 1307 : pat_vector, start_index);
12346 : } else {
12347 : last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
12348 6 : pat_vector, start_index);
12349 : }
12350 : } else {
12351 0 : Vector<const uc16> pat_vector = search_content.ToUC16Vector();
12352 0 : if (receiver_content.IsOneByte()) {
12353 : last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
12354 0 : pat_vector, start_index);
12355 : } else {
12356 : last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
12357 0 : pat_vector, start_index);
12358 : }
12359 : }
12360 1313 : return Smi::FromInt(last_index);
12361 : }
12362 :
12363 20001978 : bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
12364 : int slen = length();
12365 : // Can't check exact length equality, but we can check bounds.
12366 20001978 : int str_len = str.length();
12367 20001978 : if (!allow_prefix_match &&
12368 17821493 : (str_len < slen ||
12369 17821493 : str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) {
12370 : return false;
12371 : }
12372 :
12373 : int i = 0;
12374 : unibrow::Utf8Iterator it = unibrow::Utf8Iterator(str);
12375 116021797 : while (i < slen && !it.Done()) {
12376 204547735 : if (Get(i++) != *it) return false;
12377 98339190 : ++it;
12378 : }
12379 :
12380 13747954 : return (allow_prefix_match || i == slen) && it.Done();
12381 : }
12382 :
12383 : template <>
12384 135 : bool String::IsEqualTo(Vector<const uint8_t> str) {
12385 135 : return IsOneByteEqualTo(str);
12386 : }
12387 :
12388 : template <>
12389 0 : bool String::IsEqualTo(Vector<const uc16> str) {
12390 0 : return IsTwoByteEqualTo(str);
12391 : }
12392 :
12393 110375854 : bool String::IsOneByteEqualTo(Vector<const uint8_t> str) {
12394 : int slen = length();
12395 220751708 : if (str.length() != slen) return false;
12396 : DisallowHeapAllocation no_gc;
12397 84992055 : FlatContent content = GetFlatContent(no_gc);
12398 84992051 : if (content.IsOneByte()) {
12399 : return CompareChars(content.ToOneByteVector().start(),
12400 169983830 : str.start(), slen) == 0;
12401 : }
12402 272 : return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
12403 : }
12404 :
12405 :
12406 74479 : bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
12407 : int slen = length();
12408 148958 : if (str.length() != slen) return false;
12409 : DisallowHeapAllocation no_gc;
12410 19388 : FlatContent content = GetFlatContent(no_gc);
12411 19388 : if (content.IsOneByte()) {
12412 3972 : return CompareChars(content.ToOneByteVector().start(), str.start(), slen) ==
12413 3972 : 0;
12414 : }
12415 30832 : return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
12416 : }
12417 :
12418 71369476 : uint32_t String::ComputeAndSetHash(Isolate* isolate) {
12419 : DisallowHeapAllocation no_gc;
12420 : // Should only be called if hash code has not yet been computed.
12421 : DCHECK(!HasHashCode());
12422 :
12423 : // Store the hash code in the object.
12424 : uint32_t field =
12425 71369476 : IteratingStringHasher::Hash(*this, isolate->heap()->HashSeed());
12426 : set_hash_field(field);
12427 :
12428 : // Check the hash code is there.
12429 : DCHECK(HasHashCode());
12430 71369617 : uint32_t result = field >> kHashShift;
12431 : DCHECK_NE(result, 0); // Ensure that the hash value of 0 is never computed.
12432 71369617 : return result;
12433 : }
12434 :
12435 :
12436 1443764 : bool String::ComputeArrayIndex(uint32_t* index) {
12437 : int length = this->length();
12438 1443764 : if (length == 0 || length > kMaxArrayIndexSize) return false;
12439 931022 : StringCharacterStream stream(*this);
12440 931022 : return StringToArrayIndex(&stream, index);
12441 : }
12442 :
12443 :
12444 8332243 : bool String::SlowAsArrayIndex(uint32_t* index) {
12445 : DisallowHeapAllocation no_gc;
12446 8332243 : if (length() <= kMaxCachedArrayIndexLength) {
12447 6888479 : Hash(); // force computation of hash code
12448 : uint32_t field = hash_field();
12449 6888491 : if ((field & kIsNotArrayIndexMask) != 0) return false;
12450 : // Isolate the array index form the full hash field.
12451 2219157 : *index = ArrayIndexValueBits::decode(field);
12452 2219157 : return true;
12453 : } else {
12454 1443764 : return ComputeArrayIndex(index);
12455 : }
12456 : }
12457 :
12458 :
12459 15926355 : Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
12460 21851256 : if (new_length == 0) return string->GetReadOnlyRoots().empty_string_handle();
12461 :
12462 : int new_size, old_size;
12463 : int old_length = string->length();
12464 12963905 : if (old_length <= new_length) return string;
12465 :
12466 23798759 : if (string->IsSeqOneByteString()) {
12467 : old_size = SeqOneByteString::SizeFor(old_length);
12468 : new_size = SeqOneByteString::SizeFor(new_length);
12469 : } else {
12470 : DCHECK(string->IsSeqTwoByteString());
12471 : old_size = SeqTwoByteString::SizeFor(old_length);
12472 : new_size = SeqTwoByteString::SizeFor(new_length);
12473 : }
12474 :
12475 11899379 : int delta = old_size - new_size;
12476 :
12477 : Address start_of_string = string->address();
12478 : DCHECK_OBJECT_ALIGNED(start_of_string);
12479 : DCHECK_OBJECT_ALIGNED(start_of_string + new_size);
12480 :
12481 : Heap* heap = Heap::FromWritableHeapObject(*string);
12482 : // Sizes are pointer size aligned, so that we can use filler objects
12483 : // that are a multiple of pointer size.
12484 : heap->CreateFillerObjectAt(start_of_string + new_size, delta,
12485 11899379 : ClearRecordedSlots::kNo);
12486 : // We are storing the new length using release store after creating a filler
12487 : // for the left-over space to avoid races with the sweeper thread.
12488 : string->synchronized_set_length(new_length);
12489 :
12490 11899379 : return string;
12491 : }
12492 :
12493 324429 : void SeqOneByteString::clear_padding() {
12494 324429 : int data_size = SeqString::kHeaderSize + length() * kOneByteSize;
12495 324429 : memset(reinterpret_cast<void*>(address() + data_size), 0,
12496 648858 : SizeFor(length()) - data_size);
12497 324429 : }
12498 :
12499 0 : void SeqTwoByteString::clear_padding() {
12500 0 : int data_size = SeqString::kHeaderSize + length() * kUC16Size;
12501 0 : memset(reinterpret_cast<void*>(address() + data_size), 0,
12502 0 : SizeFor(length()) - data_size);
12503 0 : }
12504 :
12505 88858 : int ExternalString::ExternalPayloadSize() const {
12506 88858 : int length_multiplier = IsTwoByteRepresentation() ? i::kShortSize : kCharSize;
12507 88858 : return length() * length_multiplier;
12508 : }
12509 :
12510 6361519 : uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
12511 : // For array indexes mix the length into the hash as an array index could
12512 : // be zero.
12513 : DCHECK_GT(length, 0);
12514 : DCHECK_LE(length, String::kMaxArrayIndexSize);
12515 : DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
12516 : (1 << String::kArrayIndexValueBits));
12517 :
12518 7157526 : value <<= String::ArrayIndexValueBits::kShift;
12519 7157526 : value |= length << String::ArrayIndexLengthBits::kShift;
12520 :
12521 : DCHECK_EQ(value & String::kIsNotArrayIndexMask, 0);
12522 : DCHECK_EQ(length <= String::kMaxCachedArrayIndexLength,
12523 : Name::ContainsCachedArrayIndex(value));
12524 6361519 : return value;
12525 : }
12526 :
12527 :
12528 85901429 : uint32_t StringHasher::GetHashField() {
12529 85901429 : if (length_ <= String::kMaxHashCalcLength) {
12530 85834817 : if (is_array_index_) {
12531 1586602 : return MakeArrayIndexHash(array_index_, length_);
12532 : }
12533 170083032 : return (GetHashCore(raw_running_hash_) << String::kHashShift) |
12534 85041516 : String::kIsNotArrayIndexMask;
12535 : } else {
12536 66612 : return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
12537 : }
12538 : }
12539 :
12540 14534349 : uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars, uint64_t seed,
12541 : int* utf16_length_out) {
12542 14534349 : int vector_length = chars.length();
12543 : // Handle some edge cases
12544 14534349 : if (vector_length <= 1) {
12545 : DCHECK(vector_length == 0 ||
12546 : static_cast<uint8_t>(chars.start()[0]) <=
12547 : unibrow::Utf8::kMaxOneByteChar);
12548 2559 : *utf16_length_out = vector_length;
12549 2559 : return HashSequentialString(chars.start(), vector_length, seed);
12550 : }
12551 :
12552 : // Start with a fake length which won't affect computation.
12553 : // It will be updated later.
12554 : StringHasher hasher(String::kMaxArrayIndexSize, seed);
12555 : DCHECK(hasher.is_array_index_);
12556 :
12557 : unibrow::Utf8Iterator it = unibrow::Utf8Iterator(chars);
12558 : int utf16_length = 0;
12559 : bool is_index = true;
12560 :
12561 134464543 : while (utf16_length < String::kMaxHashCalcLength && !it.Done()) {
12562 105400931 : utf16_length++;
12563 105400931 : uint16_t c = *it;
12564 105400859 : ++it;
12565 : hasher.AddCharacter(c);
12566 105400912 : if (is_index) is_index = hasher.UpdateIndex(c);
12567 : }
12568 :
12569 : // Now that hashing is done, we just need to calculate utf16_length
12570 14531805 : while (!it.Done()) {
12571 0 : ++it;
12572 0 : utf16_length++;
12573 : }
12574 :
12575 14531805 : *utf16_length_out = utf16_length;
12576 : // Must set length here so that hash computation is correct.
12577 14531805 : hasher.length_ = utf16_length;
12578 14531805 : return hasher.GetHashField();
12579 : }
12580 :
12581 124582 : void IteratingStringHasher::VisitConsString(ConsString cons_string) {
12582 : // Run small ConsStrings through ConsStringIterator.
12583 124582 : if (cons_string->length() < 64) {
12584 : ConsStringIterator iter(cons_string);
12585 : int offset;
12586 288331 : for (String string = iter.Next(&offset); !string.is_null();
12587 : string = iter.Next(&offset)) {
12588 : DCHECK_EQ(0, offset);
12589 128749 : String::VisitFlat(this, string, 0);
12590 : }
12591 124582 : return;
12592 : }
12593 : // Slow case.
12594 44791 : const int max_length = String::kMaxHashCalcLength;
12595 89582 : int length = std::min(cons_string->length(), max_length);
12596 44791 : if (cons_string->HasOnlyOneByteChars()) {
12597 44791 : uint8_t* buffer = new uint8_t[length];
12598 44791 : String::WriteToFlat(cons_string, buffer, 0, length);
12599 44791 : AddCharacters(buffer, length);
12600 44791 : delete[] buffer;
12601 : } else {
12602 0 : uint16_t* buffer = new uint16_t[length];
12603 0 : String::WriteToFlat(cons_string, buffer, 0, length);
12604 0 : AddCharacters(buffer, length);
12605 0 : delete[] buffer;
12606 : }
12607 : }
12608 :
12609 41680 : void String::PrintOn(FILE* file) {
12610 : int length = this->length();
12611 3513550 : for (int i = 0; i < length; i++) {
12612 3471870 : PrintF(file, "%c", Get(i));
12613 : }
12614 41680 : }
12615 :
12616 :
12617 758848 : int Map::Hash() {
12618 : // For performance reasons we only hash the 3 most variable fields of a map:
12619 : // constructor, prototype and bit_field2. For predictability reasons we
12620 : // use objects' offsets in respective pages for hashing instead of raw
12621 : // addresses.
12622 :
12623 : // Shift away the tag.
12624 1517696 : int hash = ObjectAddressForHashing(GetConstructor().ptr()) >> 2;
12625 :
12626 : // XOR-ing the prototype and constructor directly yields too many zero bits
12627 : // when the two pointers are close (which is fairly common).
12628 : // To avoid this we shift the prototype bits relatively to the constructor.
12629 758848 : hash ^= ObjectAddressForHashing(prototype().ptr()) << (32 - kPageSizeBits);
12630 :
12631 1517696 : return hash ^ (hash >> 16) ^ bit_field2();
12632 : }
12633 :
12634 :
12635 : namespace {
12636 :
12637 951943 : bool CheckEquivalent(const Map first, const Map second) {
12638 2822318 : return first->GetConstructor() == second->GetConstructor() &&
12639 909992 : first->prototype() == second->prototype() &&
12640 909993 : first->instance_type() == second->instance_type() &&
12641 909993 : first->bit_field() == second->bit_field() &&
12642 909835 : first->is_extensible() == second->is_extensible() &&
12643 2771607 : first->new_target_is_base() == second->new_target_is_base() &&
12644 1861764 : first->has_hidden_prototype() == second->has_hidden_prototype();
12645 : }
12646 :
12647 : } // namespace
12648 :
12649 424647 : bool Map::EquivalentToForTransition(const Map other) const {
12650 424647 : if (!CheckEquivalent(*this, other)) return false;
12651 424490 : if (instance_type() == JS_FUNCTION_TYPE) {
12652 : // JSFunctions require more checks to ensure that sloppy function is
12653 : // not equivalent to strict function.
12654 : int nof = Min(NumberOfOwnDescriptors(), other->NumberOfOwnDescriptors());
12655 : return instance_descriptors()->IsEqualUpTo(other->instance_descriptors(),
12656 2012 : nof);
12657 : }
12658 : return true;
12659 : }
12660 :
12661 0 : bool Map::EquivalentToForElementsKindTransition(const Map other) const {
12662 26579 : if (!EquivalentToForTransition(other)) return false;
12663 : #ifdef DEBUG
12664 : // Ensure that we don't try to generate elements kind transitions from maps
12665 : // with fields that may be generalized in-place. This must already be handled
12666 : // during addition of a new field.
12667 : DescriptorArray descriptors = instance_descriptors();
12668 : int nof = NumberOfOwnDescriptors();
12669 : for (int i = 0; i < nof; i++) {
12670 : PropertyDetails details = descriptors->GetDetails(i);
12671 : if (details.location() == kField) {
12672 : DCHECK(!IsInplaceGeneralizableField(details.constness(),
12673 : details.representation(),
12674 : descriptors->GetFieldType(i)));
12675 : }
12676 : }
12677 : #endif
12678 0 : return true;
12679 : }
12680 :
12681 527295 : bool Map::EquivalentToForNormalization(const Map other,
12682 : PropertyNormalizationMode mode) const {
12683 : int properties =
12684 527295 : mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other->GetInObjectProperties();
12685 1497955 : return CheckEquivalent(*this, other) && bit_field2() == other->bit_field2() &&
12686 1447727 : GetInObjectProperties() == properties &&
12687 435102 : JSObject::GetEmbedderFieldCount(*this) ==
12688 962397 : JSObject::GetEmbedderFieldCount(other);
12689 : }
12690 :
12691 :
12692 485174 : void JSFunction::MarkForOptimization(ConcurrencyMode mode) {
12693 969982 : Isolate* isolate = GetIsolate();
12694 969982 : if (!isolate->concurrent_recompilation_enabled() ||
12695 484802 : isolate->bootstrapper()->IsActive()) {
12696 : mode = ConcurrencyMode::kNotConcurrent;
12697 : }
12698 :
12699 : DCHECK(!is_compiled() || IsInterpreted());
12700 : DCHECK(shared()->IsInterpreted());
12701 : DCHECK(!IsOptimized());
12702 : DCHECK(!HasOptimizedCode());
12703 : DCHECK(shared()->allows_lazy_compilation() ||
12704 : !shared()->optimization_disabled());
12705 :
12706 485180 : if (mode == ConcurrencyMode::kConcurrent) {
12707 28894 : if (IsInOptimizationQueue()) {
12708 0 : if (FLAG_trace_concurrent_recompilation) {
12709 0 : PrintF(" ** Not marking ");
12710 0 : ShortPrint();
12711 0 : PrintF(" -- already in optimization queue.\n");
12712 : }
12713 485181 : return;
12714 : }
12715 28894 : if (FLAG_trace_concurrent_recompilation) {
12716 0 : PrintF(" ** Marking ");
12717 0 : ShortPrint();
12718 0 : PrintF(" for concurrent recompilation.\n");
12719 : }
12720 : }
12721 :
12722 : SetOptimizationMarker(mode == ConcurrencyMode::kConcurrent
12723 : ? OptimizationMarker::kCompileOptimizedConcurrent
12724 485181 : : OptimizationMarker::kCompileOptimized);
12725 : }
12726 :
12727 : // static
12728 8434330 : void JSFunction::EnsureFeedbackVector(Handle<JSFunction> function) {
12729 : Isolate* const isolate = function->GetIsolate();
12730 : DCHECK(function->shared()->is_compiled());
12731 : DCHECK(FLAG_lite_mode || function->shared()->HasFeedbackMetadata());
12732 19944613 : if (!function->has_feedback_vector() &&
12733 11510263 : function->shared()->HasFeedbackMetadata()) {
12734 6151791 : Handle<SharedFunctionInfo> shared(function->shared(), isolate);
12735 3075895 : if (!shared->HasAsmWasmData()) {
12736 : DCHECK(function->shared()->HasBytecodeArray());
12737 : Handle<FeedbackVector> feedback_vector =
12738 3073782 : FeedbackVector::New(isolate, shared);
12739 9221345 : if (function->raw_feedback_cell() ==
12740 3073781 : isolate->heap()->many_closures_cell()) {
12741 : Handle<FeedbackCell> feedback_cell =
12742 1524843 : isolate->factory()->NewOneClosureCell(feedback_vector);
12743 1524847 : function->set_raw_feedback_cell(*feedback_cell);
12744 : } else {
12745 3097878 : function->raw_feedback_cell()->set_value(*feedback_vector);
12746 : }
12747 : }
12748 : }
12749 8434360 : }
12750 :
12751 371777 : static void GetMinInobjectSlack(Map map, void* data) {
12752 371777 : int slack = map->UnusedPropertyFields();
12753 371779 : if (*reinterpret_cast<int*>(data) > slack) {
12754 36627 : *reinterpret_cast<int*>(data) = slack;
12755 : }
12756 371779 : }
12757 :
12758 : int Map::InstanceSizeFromSlack(int slack) const {
12759 269814 : return instance_size() - slack * kTaggedSize;
12760 : }
12761 :
12762 263470 : static void ShrinkInstanceSize(Map map, void* data) {
12763 263470 : int slack = *reinterpret_cast<int*>(data);
12764 : DCHECK_GE(slack, 0);
12765 : #ifdef DEBUG
12766 : int old_visitor_id = Map::GetVisitorId(map);
12767 : int new_unused = map->UnusedPropertyFields() - slack;
12768 : #endif
12769 263470 : map->set_instance_size(map->InstanceSizeFromSlack(slack));
12770 263471 : map->set_construction_counter(Map::kNoSlackTracking);
12771 : DCHECK_EQ(old_visitor_id, Map::GetVisitorId(map));
12772 : DCHECK_EQ(new_unused, map->UnusedPropertyFields());
12773 263471 : }
12774 :
12775 95412 : static void StopSlackTracking(Map map, void* data) {
12776 95412 : map->set_construction_counter(Map::kNoSlackTracking);
12777 95412 : }
12778 :
12779 135058 : int Map::ComputeMinObjectSlack(Isolate* isolate) {
12780 : DisallowHeapAllocation no_gc;
12781 : // Has to be an initial map.
12782 : DCHECK(GetBackPointer()->IsUndefined(isolate));
12783 :
12784 135058 : int slack = UnusedPropertyFields();
12785 : TransitionsAccessor transitions(isolate, *this, &no_gc);
12786 : transitions.TraverseTransitionTree(&GetMinInobjectSlack, &slack);
12787 135060 : return slack;
12788 : }
12789 :
12790 128714 : void Map::CompleteInobjectSlackTracking(Isolate* isolate) {
12791 : DisallowHeapAllocation no_gc;
12792 : // Has to be an initial map.
12793 : DCHECK(GetBackPointer()->IsUndefined(isolate));
12794 :
12795 128714 : int slack = ComputeMinObjectSlack(isolate);
12796 : TransitionsAccessor transitions(isolate, *this, &no_gc);
12797 128716 : if (slack != 0) {
12798 : // Resize the initial map and all maps in its transition tree.
12799 : transitions.TraverseTransitionTree(&ShrinkInstanceSize, &slack);
12800 : } else {
12801 : transitions.TraverseTransitionTree(&StopSlackTracking, nullptr);
12802 : }
12803 128717 : }
12804 :
12805 80195626 : void Map::SetInstanceDescriptors(Isolate* isolate, DescriptorArray descriptors,
12806 : int number_of_own_descriptors) {
12807 80195626 : set_synchronized_instance_descriptors(descriptors);
12808 80195627 : SetNumberOfOwnDescriptors(number_of_own_descriptors);
12809 : MarkingBarrierForDescriptorArray(isolate->heap(), *this, descriptors,
12810 80195607 : number_of_own_descriptors);
12811 80195600 : }
12812 :
12813 27434591 : static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) {
12814 : DisallowHeapAllocation no_gc;
12815 27434599 : if (!object->HasFastProperties()) return false;
12816 52456706 : if (object->IsJSGlobalProxy()) return false;
12817 26207029 : if (object->GetIsolate()->bootstrapper()->IsActive()) return false;
12818 9438501 : return !object->map()->is_prototype_map() ||
12819 9438501 : !object->map()->should_be_fast_prototype_map();
12820 : }
12821 :
12822 : // static
12823 4346350 : void JSObject::MakePrototypesFast(Handle<Object> receiver,
12824 : WhereToStart where_to_start,
12825 : Isolate* isolate) {
12826 8692731 : if (!receiver->IsJSReceiver()) return;
12827 12082094 : for (PrototypeIterator iter(isolate, Handle<JSReceiver>::cast(receiver),
12828 4300363 : where_to_start);
12829 11263164 : !iter.IsAtEnd(); iter.Advance()) {
12830 : Handle<Object> current = PrototypeIterator::GetCurrent(iter);
12831 19805809 : if (!current->IsJSObject()) return;
12832 7756196 : Handle<JSObject> current_obj = Handle<JSObject>::cast(current);
12833 7756198 : Map current_map = current_obj->map();
12834 7756198 : if (current_map->is_prototype_map()) {
12835 : // If the map is already marked as should be fast, we're done. Its
12836 : // prototypes will have been marked already as well.
12837 9100214 : if (current_map->should_be_fast_prototype_map()) return;
12838 : Handle<Map> map(current_map, isolate);
12839 550648 : Map::SetShouldBeFastPrototypeMap(map, true, isolate);
12840 550646 : JSObject::OptimizeAsPrototype(current_obj);
12841 : }
12842 : }
12843 : }
12844 :
12845 : // static
12846 27547732 : void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
12847 : bool enable_setup_mode) {
12848 82643258 : if (object->IsJSGlobalObject()) return;
12849 27449683 : if (enable_setup_mode && PrototypeBenefitsFromNormalization(object)) {
12850 : // First normalize to ensure all JSFunctions are DATA_CONSTANT.
12851 : JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0,
12852 328747 : "NormalizeAsPrototype");
12853 : }
12854 27449713 : if (object->map()->is_prototype_map()) {
12855 64972240 : if (object->map()->should_be_fast_prototype_map() &&
12856 42116570 : !object->HasFastProperties()) {
12857 283096 : JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype");
12858 : }
12859 : } else {
12860 : Handle<Map> new_map = Map::Copy(object->GetIsolate(),
12861 : handle(object->map(), object->GetIsolate()),
12862 4594048 : "CopyAsPrototype");
12863 4594047 : JSObject::MigrateToMap(object, new_map);
12864 : object->map()->set_is_prototype_map(true);
12865 :
12866 : // Replace the pointer to the exact constructor with the Object function
12867 : // from the same context if undetectable from JS. This is to avoid keeping
12868 : // memory alive unnecessarily.
12869 4594053 : Object maybe_constructor = object->map()->GetConstructor();
12870 4594047 : if (maybe_constructor->IsJSFunction()) {
12871 4593379 : JSFunction constructor = JSFunction::cast(maybe_constructor);
12872 4593379 : if (!constructor->shared()->IsApiFunction()) {
12873 4538493 : Context context = constructor->context()->native_context();
12874 4538494 : JSFunction object_function = context->object_function();
12875 4538494 : object->map()->SetConstructor(object_function);
12876 : }
12877 : }
12878 : }
12879 : }
12880 :
12881 :
12882 : // static
12883 360091 : void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) {
12884 360091 : if (!object->map()->is_prototype_map()) return;
12885 57570 : if (!object->map()->should_be_fast_prototype_map()) return;
12886 39112 : OptimizeAsPrototype(object);
12887 : }
12888 :
12889 :
12890 : // static
12891 1734944 : void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
12892 : // Contract: In line with InvalidatePrototypeChains()'s requirements,
12893 : // leaf maps don't need to register as users, only prototypes do.
12894 : DCHECK(user->is_prototype_map());
12895 :
12896 1734944 : Handle<Map> current_user = user;
12897 : Handle<PrototypeInfo> current_user_info =
12898 1734944 : Map::GetOrCreatePrototypeInfo(user, isolate);
12899 4471575 : for (PrototypeIterator iter(isolate, user); !iter.IsAtEnd(); iter.Advance()) {
12900 : // Walk up the prototype chain as far as links haven't been registered yet.
12901 1599908 : if (current_user_info->registry_slot() != PrototypeInfo::UNREGISTERED) {
12902 : break;
12903 : }
12904 : Handle<Object> maybe_proto = PrototypeIterator::GetCurrent(iter);
12905 : // Proxies on the prototype chain are not supported. They make it
12906 : // impossible to make any assumptions about the prototype chain anyway.
12907 2737560 : if (maybe_proto->IsJSProxy()) return;
12908 500838 : Handle<JSObject> proto = Handle<JSObject>::cast(maybe_proto);
12909 : Handle<PrototypeInfo> proto_info =
12910 500838 : Map::GetOrCreatePrototypeInfo(proto, isolate);
12911 1001676 : Handle<Object> maybe_registry(proto_info->prototype_users(), isolate);
12912 : Handle<WeakArrayList> registry =
12913 1001674 : maybe_registry->IsSmi()
12914 : ? handle(ReadOnlyRoots(isolate->heap()).empty_weak_array_list(),
12915 118629 : isolate)
12916 619466 : : Handle<WeakArrayList>::cast(maybe_registry);
12917 500837 : int slot = 0;
12918 : Handle<WeakArrayList> new_array =
12919 500837 : PrototypeUsers::Add(isolate, registry, current_user, &slot);
12920 500838 : current_user_info->set_registry_slot(slot);
12921 500838 : if (!maybe_registry.is_identical_to(new_array)) {
12922 266808 : proto_info->set_prototype_users(*new_array);
12923 : }
12924 500839 : if (FLAG_trace_prototype_users) {
12925 : PrintF("Registering %p as a user of prototype %p (map=%p).\n",
12926 : reinterpret_cast<void*>(current_user->ptr()),
12927 : reinterpret_cast<void*>(proto->ptr()),
12928 0 : reinterpret_cast<void*>(proto->map()->ptr()));
12929 : }
12930 :
12931 : current_user = handle(proto->map(), isolate);
12932 : current_user_info = proto_info;
12933 : }
12934 : }
12935 :
12936 :
12937 : // Can be called regardless of whether |user| was actually registered with
12938 : // |prototype|. Returns true when there was a registration.
12939 : // static
12940 4252986 : bool JSObject::UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
12941 : DCHECK(user->is_prototype_map());
12942 : // If it doesn't have a PrototypeInfo, it was never registered.
12943 8505976 : if (!user->prototype_info()->IsPrototypeInfo()) return false;
12944 : // If it had no prototype before, see if it had users that might expect
12945 : // registration.
12946 3167925 : if (!user->prototype()->IsJSObject()) {
12947 : Object users =
12948 69518 : PrototypeInfo::cast(user->prototype_info())->prototype_users();
12949 : return users->IsWeakArrayList();
12950 : }
12951 : Handle<JSObject> prototype(JSObject::cast(user->prototype()), isolate);
12952 : Handle<PrototypeInfo> user_info =
12953 1514445 : Map::GetOrCreatePrototypeInfo(user, isolate);
12954 : int slot = user_info->registry_slot();
12955 1514445 : if (slot == PrototypeInfo::UNREGISTERED) return false;
12956 : DCHECK(prototype->map()->is_prototype_map());
12957 : Object maybe_proto_info = prototype->map()->prototype_info();
12958 : // User knows its registry slot, prototype info and user registry must exist.
12959 : DCHECK(maybe_proto_info->IsPrototypeInfo());
12960 : Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info),
12961 : isolate);
12962 : Handle<WeakArrayList> prototype_users(
12963 251278 : WeakArrayList::cast(proto_info->prototype_users()), isolate);
12964 : DCHECK_EQ(prototype_users->Get(slot), HeapObjectReference::Weak(*user));
12965 125639 : PrototypeUsers::MarkSlotEmpty(*prototype_users, slot);
12966 125638 : if (FLAG_trace_prototype_users) {
12967 : PrintF("Unregistering %p as a user of prototype %p.\n",
12968 : reinterpret_cast<void*>(user->ptr()),
12969 0 : reinterpret_cast<void*>(prototype->ptr()));
12970 : }
12971 : return true;
12972 : }
12973 :
12974 : namespace {
12975 :
12976 : // This function must be kept in sync with
12977 : // AccessorAssembler::InvalidateValidityCellIfPrototype() which does pre-checks
12978 : // before jumping here.
12979 16296382 : void InvalidateOnePrototypeValidityCellInternal(Map map) {
12980 : DCHECK(map->is_prototype_map());
12981 16296382 : if (FLAG_trace_prototype_users) {
12982 : PrintF("Invalidating prototype map %p 's cell\n",
12983 0 : reinterpret_cast<void*>(map.ptr()));
12984 : }
12985 16296382 : Object maybe_cell = map->prototype_validity_cell();
12986 16296401 : if (maybe_cell->IsCell()) {
12987 : // Just set the value; the cell will be replaced lazily.
12988 16231688 : Cell cell = Cell::cast(maybe_cell);
12989 16231688 : cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid));
12990 : }
12991 16296395 : }
12992 :
12993 15415174 : void InvalidatePrototypeChainsInternal(Map map) {
12994 15415174 : InvalidateOnePrototypeValidityCellInternal(map);
12995 :
12996 15415178 : Object maybe_proto_info = map->prototype_info();
12997 28315987 : if (!maybe_proto_info->IsPrototypeInfo()) return;
12998 4424185 : PrototypeInfo proto_info = PrototypeInfo::cast(maybe_proto_info);
12999 8848370 : if (!proto_info->prototype_users()->IsWeakArrayList()) {
13000 : return;
13001 : }
13002 : WeakArrayList prototype_users =
13003 5028722 : WeakArrayList::cast(proto_info->prototype_users());
13004 : // For now, only maps register themselves as users.
13005 14491264 : for (int i = PrototypeUsers::kFirstIndex; i < prototype_users->length();
13006 : ++i) {
13007 4731271 : HeapObject heap_object;
13008 7184863 : if (prototype_users->Get(i)->GetHeapObjectIfWeak(&heap_object) &&
13009 : heap_object->IsMap()) {
13010 : // Walk the prototype chain (backwards, towards leaf objects) if
13011 : // necessary.
13012 2453592 : InvalidatePrototypeChainsInternal(Map::cast(heap_object));
13013 : }
13014 : }
13015 : }
13016 :
13017 : } // namespace
13018 :
13019 : // static
13020 8663007 : Map JSObject::InvalidatePrototypeChains(Map map) {
13021 : DisallowHeapAllocation no_gc;
13022 12961594 : InvalidatePrototypeChainsInternal(map);
13023 8663005 : return map;
13024 : }
13025 :
13026 : // We also invalidate global objects validity cell when a new lexical
13027 : // environment variable is added. This is necessary to ensure that
13028 : // Load/StoreGlobalIC handlers that load/store from global object's prototype
13029 : // get properly invalidated.
13030 : // Note, that the normal Load/StoreICs that load/store through the global object
13031 : // in the prototype chain are not affected by appearance of a new lexical
13032 : // variable and therefore we don't propagate invalidation down.
13033 : // static
13034 881215 : void JSObject::InvalidatePrototypeValidityCell(JSGlobalObject global) {
13035 : DisallowHeapAllocation no_gc;
13036 881215 : InvalidateOnePrototypeValidityCellInternal(global->map());
13037 881215 : }
13038 :
13039 : // static
13040 620044 : Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<JSObject> prototype,
13041 : Isolate* isolate) {
13042 620047 : Object maybe_proto_info = prototype->map()->prototype_info();
13043 620046 : if (maybe_proto_info->IsPrototypeInfo()) {
13044 : return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
13045 : }
13046 136148 : Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
13047 272296 : prototype->map()->set_prototype_info(*proto_info);
13048 136148 : return proto_info;
13049 : }
13050 :
13051 :
13052 : // static
13053 3891958 : Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<Map> prototype_map,
13054 : Isolate* isolate) {
13055 3891960 : Object maybe_proto_info = prototype_map->prototype_info();
13056 3891969 : if (maybe_proto_info->IsPrototypeInfo()) {
13057 : return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
13058 : }
13059 545063 : Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
13060 1090131 : prototype_map->set_prototype_info(*proto_info);
13061 545068 : return proto_info;
13062 : }
13063 :
13064 : // static
13065 642573 : void Map::SetShouldBeFastPrototypeMap(Handle<Map> map, bool value,
13066 : Isolate* isolate) {
13067 642573 : if (value == false && !map->prototype_info()->IsPrototypeInfo()) {
13068 : // "False" is the implicit default value, so there's nothing to do.
13069 642574 : return;
13070 : }
13071 1285147 : GetOrCreatePrototypeInfo(map, isolate)->set_should_be_fast_map(value);
13072 : }
13073 :
13074 : // static
13075 1609295 : Handle<Object> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
13076 : Isolate* isolate) {
13077 : Handle<Object> maybe_prototype;
13078 1609295 : if (map->IsJSGlobalObjectMap()) {
13079 : DCHECK(map->is_prototype_map());
13080 : // Global object is prototype of a global proxy and therefore we can
13081 : // use its validity cell for guarding global object's prototype change.
13082 43124 : maybe_prototype = isolate->global_object();
13083 : } else {
13084 : maybe_prototype =
13085 3132348 : handle(map->GetPrototypeChainRootMap(isolate)->prototype(), isolate);
13086 : }
13087 3218602 : if (!maybe_prototype->IsJSObject()) {
13088 66608 : return handle(Smi::FromInt(Map::kPrototypeChainValid), isolate);
13089 : }
13090 1542696 : Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype);
13091 : // Ensure the prototype is registered with its own prototypes so its cell
13092 : // will be invalidated when necessary.
13093 : JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate),
13094 1542697 : isolate);
13095 :
13096 1542702 : Object maybe_cell = prototype->map()->prototype_validity_cell();
13097 : // Return existing cell if it's still valid.
13098 1542706 : if (maybe_cell->IsCell()) {
13099 : Handle<Cell> cell(Cell::cast(maybe_cell), isolate);
13100 3085264 : if (cell->value() == Smi::FromInt(Map::kPrototypeChainValid)) {
13101 1126609 : return cell;
13102 : }
13103 : }
13104 : // Otherwise create a new cell.
13105 : Handle<Cell> cell = isolate->factory()->NewCell(
13106 416096 : handle(Smi::FromInt(Map::kPrototypeChainValid), isolate));
13107 832190 : prototype->map()->set_prototype_validity_cell(*cell);
13108 416097 : return cell;
13109 : }
13110 :
13111 : // static
13112 0 : bool Map::IsPrototypeChainInvalidated(Map map) {
13113 : DCHECK(map->is_prototype_map());
13114 0 : Object maybe_cell = map->prototype_validity_cell();
13115 0 : if (maybe_cell->IsCell()) {
13116 0 : Cell cell = Cell::cast(maybe_cell);
13117 0 : return cell->value() != Smi::FromInt(Map::kPrototypeChainValid);
13118 : }
13119 : return true;
13120 : }
13121 :
13122 : // static
13123 31305081 : void Map::SetPrototype(Isolate* isolate, Handle<Map> map,
13124 : Handle<Object> prototype,
13125 : bool enable_prototype_setup_mode) {
13126 : RuntimeCallTimerScope stats_scope(isolate, *map,
13127 : RuntimeCallCounterId::kMap_SetPrototype);
13128 :
13129 : bool is_hidden = false;
13130 62610274 : if (prototype->IsJSObject()) {
13131 26576543 : Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype);
13132 26576543 : JSObject::OptimizeAsPrototype(prototype_jsobj, enable_prototype_setup_mode);
13133 :
13134 26576589 : Object maybe_constructor = prototype_jsobj->map()->GetConstructor();
13135 26576595 : if (maybe_constructor->IsJSFunction()) {
13136 25581120 : JSFunction constructor = JSFunction::cast(maybe_constructor);
13137 51162241 : Object data = constructor->shared()->function_data();
13138 230423 : is_hidden = (data->IsFunctionTemplateInfo() &&
13139 77203945 : FunctionTemplateInfo::cast(data)->hidden_prototype()) ||
13140 76512655 : prototype->IsJSGlobalObject();
13141 995467 : } else if (maybe_constructor->IsFunctionTemplateInfo()) {
13142 : is_hidden =
13143 54 : FunctionTemplateInfo::cast(maybe_constructor)->hidden_prototype() ||
13144 36 : prototype->IsJSGlobalObject();
13145 : }
13146 : }
13147 62610330 : map->set_has_hidden_prototype(is_hidden);
13148 :
13149 : WriteBarrierMode wb_mode =
13150 62610250 : prototype->IsNull(isolate) ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER;
13151 31305128 : map->set_prototype(*prototype, wb_mode);
13152 31305124 : }
13153 :
13154 222 : Handle<Object> CacheInitialJSArrayMaps(Handle<Context> native_context,
13155 : Handle<Map> initial_map) {
13156 : // Replace all of the cached initial array maps in the native context with
13157 : // the appropriate transitioned elements kind maps.
13158 222 : Handle<Map> current_map = initial_map;
13159 : ElementsKind kind = current_map->elements_kind();
13160 : DCHECK_EQ(GetInitialFastElementsKind(), kind);
13161 444 : native_context->set(Context::ArrayMapIndex(kind), *current_map);
13162 1332 : for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1;
13163 : i < kFastElementsKindCount; ++i) {
13164 : Handle<Map> new_map;
13165 1110 : ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
13166 1110 : Map maybe_elements_transition = current_map->ElementsTransitionMap();
13167 1110 : if (!maybe_elements_transition.is_null()) {
13168 : new_map = handle(maybe_elements_transition, native_context->GetIsolate());
13169 : } else {
13170 : new_map =
13171 : Map::CopyAsElementsKind(native_context->GetIsolate(), current_map,
13172 2220 : next_kind, INSERT_TRANSITION);
13173 : }
13174 : DCHECK_EQ(next_kind, new_map->elements_kind());
13175 2220 : native_context->set(Context::ArrayMapIndex(next_kind), *new_map);
13176 : current_map = new_map;
13177 : }
13178 222 : return initial_map;
13179 : }
13180 :
13181 : namespace {
13182 :
13183 390144 : void SetInstancePrototype(Isolate* isolate, Handle<JSFunction> function,
13184 : Handle<JSReceiver> value) {
13185 : // Now some logic for the maps of the objects that are created by using this
13186 : // function as a constructor.
13187 274522 : if (function->has_initial_map()) {
13188 : // If the function has allocated the initial map replace it with a
13189 : // copy containing the new prototype. Also complete any in-object
13190 : // slack tracking that is in progress at this point because it is
13191 : // still tracking the old copy.
13192 115622 : function->CompleteInobjectSlackTrackingIfActive();
13193 :
13194 231244 : Handle<Map> initial_map(function->initial_map(), isolate);
13195 :
13196 230467 : if (!isolate->bootstrapper()->IsActive() &&
13197 : initial_map->instance_type() == JS_OBJECT_TYPE) {
13198 : // Put the value in the initial map field until an initial map is needed.
13199 : // At that point, a new initial map is created and the prototype is put
13200 : // into the initial map where it belongs.
13201 229024 : function->set_prototype_or_initial_map(*value);
13202 : } else {
13203 : Handle<Map> new_map =
13204 1110 : Map::Copy(isolate, initial_map, "SetInstancePrototype");
13205 1110 : JSFunction::SetInitialMap(function, new_map, value);
13206 :
13207 : // If the function is used as the global Array function, cache the
13208 : // updated initial maps (and transitioned versions) in the native context.
13209 2220 : Handle<Context> native_context(function->context()->native_context(),
13210 2220 : isolate);
13211 : Handle<Object> array_function(
13212 2220 : native_context->get(Context::ARRAY_FUNCTION_INDEX), isolate);
13213 3219 : if (array_function->IsJSFunction() &&
13214 : *function == JSFunction::cast(*array_function)) {
13215 111 : CacheInitialJSArrayMaps(native_context, new_map);
13216 : }
13217 : }
13218 :
13219 : // Deoptimize all code that embeds the previous initial map.
13220 231244 : initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
13221 115622 : isolate, DependentCode::kInitialMapChangedGroup);
13222 : } else {
13223 : // Put the value in the initial map field until an initial map is
13224 : // needed. At that point, a new initial map is created and the
13225 : // prototype is put into the initial map where it belongs.
13226 317800 : function->set_prototype_or_initial_map(*value);
13227 317800 : if (value->IsJSObject()) {
13228 : // Optimize as prototype to detach it from its transition tree.
13229 158837 : JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value));
13230 : }
13231 : }
13232 274522 : }
13233 :
13234 : } // anonymous namespace
13235 :
13236 274522 : void JSFunction::SetPrototype(Handle<JSFunction> function,
13237 : Handle<Object> value) {
13238 : DCHECK(function->IsConstructor() ||
13239 : IsGeneratorFunction(function->shared()->kind()));
13240 : Isolate* isolate = function->GetIsolate();
13241 : Handle<JSReceiver> construct_prototype;
13242 :
13243 : // If the value is not a JSReceiver, store the value in the map's
13244 : // constructor field so it can be accessed. Also, set the prototype
13245 : // used for constructing objects to the original object prototype.
13246 : // See ECMA-262 13.2.2.
13247 549044 : if (!value->IsJSReceiver()) {
13248 : // Copy the map so this does not affect unrelated functions.
13249 : // Remove map transitions because they point to maps with a
13250 : // different prototype.
13251 : Handle<Map> new_map =
13252 94213 : Map::Copy(isolate, handle(function->map(), isolate), "SetPrototype");
13253 :
13254 94213 : JSObject::MigrateToMap(function, new_map);
13255 94213 : new_map->SetConstructor(*value);
13256 : new_map->set_has_non_instance_prototype(true);
13257 :
13258 188426 : FunctionKind kind = function->shared()->kind();
13259 188426 : Handle<Context> native_context(function->context()->native_context(),
13260 188426 : isolate);
13261 :
13262 : construct_prototype = Handle<JSReceiver>(
13263 : IsGeneratorFunction(kind)
13264 : ? IsAsyncFunction(kind)
13265 94231 : ? native_context->initial_async_generator_prototype()
13266 94285 : : native_context->initial_generator_prototype()
13267 188345 : : native_context->initial_object_prototype(),
13268 376924 : isolate);
13269 : } else {
13270 180309 : construct_prototype = Handle<JSReceiver>::cast(value);
13271 : function->map()->set_has_non_instance_prototype(false);
13272 : }
13273 :
13274 274522 : SetInstancePrototype(isolate, function, construct_prototype);
13275 274522 : }
13276 :
13277 4970763 : void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
13278 : Handle<Object> prototype) {
13279 4970766 : if (map->prototype() != *prototype)
13280 4970216 : Map::SetPrototype(function->GetIsolate(), map, prototype);
13281 9941537 : function->set_prototype_or_initial_map(*map);
13282 9941544 : map->SetConstructor(*function);
13283 4970768 : if (FLAG_trace_maps) {
13284 3639 : LOG(function->GetIsolate(), MapEvent("InitialMap", Map(), *map, "",
13285 : function->shared()->DebugName()));
13286 : }
13287 4970768 : }
13288 :
13289 :
13290 : #ifdef DEBUG
13291 : namespace {
13292 :
13293 : bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
13294 : switch (instance_type) {
13295 : case JS_API_OBJECT_TYPE:
13296 : case JS_ARRAY_BUFFER_TYPE:
13297 : case JS_ARRAY_TYPE:
13298 : case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
13299 : case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
13300 : case JS_DATA_VIEW_TYPE:
13301 : case JS_DATE_TYPE:
13302 : case JS_FUNCTION_TYPE:
13303 : case JS_GENERATOR_OBJECT_TYPE:
13304 : #ifdef V8_INTL_SUPPORT
13305 : case JS_INTL_COLLATOR_TYPE:
13306 : case JS_INTL_DATE_TIME_FORMAT_TYPE:
13307 : case JS_INTL_LIST_FORMAT_TYPE:
13308 : case JS_INTL_LOCALE_TYPE:
13309 : case JS_INTL_NUMBER_FORMAT_TYPE:
13310 : case JS_INTL_PLURAL_RULES_TYPE:
13311 : case JS_INTL_RELATIVE_TIME_FORMAT_TYPE:
13312 : case JS_INTL_SEGMENT_ITERATOR_TYPE:
13313 : case JS_INTL_SEGMENTER_TYPE:
13314 : case JS_INTL_V8_BREAK_ITERATOR_TYPE:
13315 : #endif
13316 : case JS_ASYNC_FUNCTION_OBJECT_TYPE:
13317 : case JS_ASYNC_GENERATOR_OBJECT_TYPE:
13318 : case JS_MAP_TYPE:
13319 : case JS_MESSAGE_OBJECT_TYPE:
13320 : case JS_OBJECT_TYPE:
13321 : case JS_ERROR_TYPE:
13322 : case JS_ARGUMENTS_TYPE:
13323 : case JS_PROMISE_TYPE:
13324 : case JS_REGEXP_TYPE:
13325 : case JS_SET_TYPE:
13326 : case JS_SPECIAL_API_OBJECT_TYPE:
13327 : case JS_TYPED_ARRAY_TYPE:
13328 : case JS_VALUE_TYPE:
13329 : case JS_WEAK_MAP_TYPE:
13330 : case JS_WEAK_SET_TYPE:
13331 : case WASM_GLOBAL_TYPE:
13332 : case WASM_INSTANCE_TYPE:
13333 : case WASM_MEMORY_TYPE:
13334 : case WASM_MODULE_TYPE:
13335 : case WASM_TABLE_TYPE:
13336 : return true;
13337 :
13338 : case BIGINT_TYPE:
13339 : case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
13340 : case BYTECODE_ARRAY_TYPE:
13341 : case BYTE_ARRAY_TYPE:
13342 : case CELL_TYPE:
13343 : case CODE_TYPE:
13344 : case FILLER_TYPE:
13345 : case FIXED_ARRAY_TYPE:
13346 : case SCRIPT_CONTEXT_TABLE_TYPE:
13347 : case FIXED_DOUBLE_ARRAY_TYPE:
13348 : case FEEDBACK_METADATA_TYPE:
13349 : case FOREIGN_TYPE:
13350 : case FREE_SPACE_TYPE:
13351 : case HASH_TABLE_TYPE:
13352 : case ORDERED_HASH_MAP_TYPE:
13353 : case ORDERED_HASH_SET_TYPE:
13354 : case ORDERED_NAME_DICTIONARY_TYPE:
13355 : case NAME_DICTIONARY_TYPE:
13356 : case GLOBAL_DICTIONARY_TYPE:
13357 : case NUMBER_DICTIONARY_TYPE:
13358 : case SIMPLE_NUMBER_DICTIONARY_TYPE:
13359 : case STRING_TABLE_TYPE:
13360 : case HEAP_NUMBER_TYPE:
13361 : case JS_BOUND_FUNCTION_TYPE:
13362 : case JS_GLOBAL_OBJECT_TYPE:
13363 : case JS_GLOBAL_PROXY_TYPE:
13364 : case JS_PROXY_TYPE:
13365 : case MAP_TYPE:
13366 : case MUTABLE_HEAP_NUMBER_TYPE:
13367 : case ODDBALL_TYPE:
13368 : case PROPERTY_CELL_TYPE:
13369 : case SHARED_FUNCTION_INFO_TYPE:
13370 : case SYMBOL_TYPE:
13371 : case ALLOCATION_SITE_TYPE:
13372 :
13373 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
13374 : case FIXED_##TYPE##_ARRAY_TYPE:
13375 : #undef TYPED_ARRAY_CASE
13376 :
13377 : #define MAKE_STRUCT_CASE(TYPE, Name, name) case TYPE:
13378 : STRUCT_LIST(MAKE_STRUCT_CASE)
13379 : #undef MAKE_STRUCT_CASE
13380 : // We must not end up here for these instance types at all.
13381 : UNREACHABLE();
13382 : // Fall through.
13383 : default:
13384 : return false;
13385 : }
13386 : }
13387 :
13388 : } // namespace
13389 : #endif
13390 :
13391 :
13392 19744809 : void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
13393 : DCHECK(function->has_prototype_slot());
13394 : DCHECK(function->IsConstructor() ||
13395 : IsResumableFunction(function->shared()->kind()));
13396 39179492 : if (function->has_initial_map()) return;
13397 : Isolate* isolate = function->GetIsolate();
13398 :
13399 : // First create a new map with the size and number of in-object properties
13400 : // suggested by the function.
13401 : InstanceType instance_type;
13402 620341 : if (IsResumableFunction(function->shared()->kind())) {
13403 17256 : instance_type = IsAsyncGeneratorFunction(function->shared()->kind())
13404 : ? JS_ASYNC_GENERATOR_OBJECT_TYPE
13405 8628 : : JS_GENERATOR_OBJECT_TYPE;
13406 : } else {
13407 : instance_type = JS_OBJECT_TYPE;
13408 : }
13409 :
13410 : // The constructor should be compiled for the optimization hints to be
13411 : // available.
13412 : int expected_nof_properties = 0;
13413 310170 : IsCompiledScope is_compiled_scope(function->shared()->is_compiled_scope());
13414 337206 : if (is_compiled_scope.is_compiled() ||
13415 : Compiler::Compile(function, Compiler::CLEAR_EXCEPTION,
13416 27037 : &is_compiled_scope)) {
13417 : DCHECK(function->shared()->is_compiled());
13418 620319 : expected_nof_properties = function->shared()->expected_nof_properties();
13419 : }
13420 :
13421 : int instance_size;
13422 : int inobject_properties;
13423 : CalculateInstanceSizeHelper(instance_type, false, 0, expected_nof_properties,
13424 310168 : &instance_size, &inobject_properties);
13425 :
13426 : Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size,
13427 : TERMINAL_FAST_ELEMENTS_KIND,
13428 310167 : inobject_properties);
13429 :
13430 : // Fetch or allocate prototype.
13431 : Handle<Object> prototype;
13432 310170 : if (function->has_instance_prototype()) {
13433 499494 : prototype = handle(function->instance_prototype(), isolate);
13434 : } else {
13435 60422 : prototype = isolate->factory()->NewFunctionPrototype(function);
13436 : }
13437 : DCHECK(map->has_fast_object_elements());
13438 :
13439 : // Finally link initial map and constructor function.
13440 : DCHECK(prototype->IsJSReceiver());
13441 310168 : JSFunction::SetInitialMap(function, map, prototype);
13442 310171 : map->StartInobjectSlackTracking();
13443 : }
13444 :
13445 : namespace {
13446 497258 : bool FastInitializeDerivedMap(Isolate* isolate, Handle<JSFunction> new_target,
13447 : Handle<JSFunction> constructor,
13448 : Handle<Map> constructor_initial_map) {
13449 : // Use the default intrinsic prototype instead.
13450 497258 : if (!new_target->has_prototype_slot()) return false;
13451 : // Check that |function|'s initial map still in sync with the |constructor|,
13452 : // otherwise we must create a new initial map for |function|.
13453 1478733 : if (new_target->has_initial_map() &&
13454 981493 : new_target->initial_map()->GetConstructor() == *constructor) {
13455 : DCHECK(new_target->instance_prototype()->IsJSReceiver());
13456 : return true;
13457 : }
13458 : InstanceType instance_type = constructor_initial_map->instance_type();
13459 : DCHECK(CanSubclassHaveInobjectProperties(instance_type));
13460 : // Create a new map with the size and number of in-object properties
13461 : // suggested by |function|.
13462 :
13463 : // Link initial map and constructor function if the new.target is actually a
13464 : // subclass constructor.
13465 681488 : if (!IsDerivedConstructor(new_target->shared()->kind())) return false;
13466 :
13467 : int instance_size;
13468 : int in_object_properties;
13469 : int embedder_fields =
13470 11343 : JSObject::GetEmbedderFieldCount(*constructor_initial_map);
13471 : bool success = JSFunction::CalculateInstanceSizeForDerivedClass(
13472 : new_target, instance_type, embedder_fields, &instance_size,
13473 11343 : &in_object_properties);
13474 :
13475 : Handle<Map> map;
13476 11343 : if (success) {
13477 22686 : int pre_allocated = constructor_initial_map->GetInObjectProperties() -
13478 11343 : constructor_initial_map->UnusedPropertyFields();
13479 22684 : CHECK_LE(constructor_initial_map->UsedInstanceSize(), instance_size);
13480 11343 : int unused_property_fields = in_object_properties - pre_allocated;
13481 : map = Map::CopyInitialMap(isolate, constructor_initial_map, instance_size,
13482 11343 : in_object_properties, unused_property_fields);
13483 : } else {
13484 0 : map = Map::CopyInitialMap(isolate, constructor_initial_map);
13485 : }
13486 11343 : map->set_new_target_is_base(false);
13487 22686 : Handle<Object> prototype(new_target->instance_prototype(), isolate);
13488 11343 : JSFunction::SetInitialMap(new_target, map, prototype);
13489 : DCHECK(new_target->instance_prototype()->IsJSReceiver());
13490 22682 : map->SetConstructor(*constructor);
13491 11342 : map->set_construction_counter(Map::kNoSlackTracking);
13492 11343 : map->StartInobjectSlackTracking();
13493 11343 : return true;
13494 : }
13495 :
13496 : } // namespace
13497 :
13498 : // static
13499 3341697 : MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
13500 : Handle<JSFunction> constructor,
13501 : Handle<JSReceiver> new_target) {
13502 3341697 : EnsureHasInitialMap(constructor);
13503 :
13504 6683442 : Handle<Map> constructor_initial_map(constructor->initial_map(), isolate);
13505 3341725 : if (*new_target == *constructor) return constructor_initial_map;
13506 :
13507 : Handle<Map> result_map;
13508 : // Fast case, new.target is a subclass of constructor. The map is cacheable
13509 : // (and may already have been cached). new.target.prototype is guaranteed to
13510 : // be a JSReceiver.
13511 997493 : if (new_target->IsJSFunction()) {
13512 497258 : Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
13513 497258 : if (FastInitializeDerivedMap(isolate, function, constructor,
13514 : constructor_initial_map)) {
13515 335695 : return handle(function->initial_map(), isolate);
13516 : }
13517 : }
13518 :
13519 : // Slow path, new.target is either a proxy or can't cache the map.
13520 : // new.target.prototype is not guaranteed to be a JSReceiver, and may need to
13521 : // fall back to the intrinsicDefaultProto.
13522 : Handle<Object> prototype;
13523 661791 : if (new_target->IsJSFunction()) {
13524 329411 : Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
13525 329406 : if (function->has_prototype_slot()) {
13526 : // Make sure the new.target.prototype is cached.
13527 329397 : EnsureHasInitialMap(function);
13528 658794 : prototype = handle(function->prototype(), isolate);
13529 : } else {
13530 : // No prototype property, use the intrinsict default proto further down.
13531 : prototype = isolate->factory()->undefined_value();
13532 : }
13533 : } else {
13534 : Handle<String> prototype_string = isolate->factory()->prototype_string();
13535 2970 : ASSIGN_RETURN_ON_EXCEPTION(
13536 : isolate, prototype,
13537 : JSReceiver::GetProperty(isolate, new_target, prototype_string), Map);
13538 : // The above prototype lookup might change the constructor and its
13539 : // prototype, hence we have to reload the initial map.
13540 1404 : EnsureHasInitialMap(constructor);
13541 2808 : constructor_initial_map = handle(constructor->initial_map(), isolate);
13542 : }
13543 :
13544 : // If prototype is not a JSReceiver, fetch the intrinsicDefaultProto from the
13545 : // correct realm. Rather than directly fetching the .prototype, we fetch the
13546 : // constructor that points to the .prototype. This relies on
13547 : // constructor.prototype being FROZEN for those constructors.
13548 661612 : if (!prototype->IsJSReceiver()) {
13549 : Handle<Context> context;
13550 2700 : ASSIGN_RETURN_ON_EXCEPTION(isolate, context,
13551 : JSReceiver::GetFunctionRealm(new_target), Map);
13552 : DCHECK(context->IsNativeContext());
13553 : Handle<Object> maybe_index = JSReceiver::GetDataProperty(
13554 1350 : constructor, isolate->factory()->native_context_index_symbol());
13555 2700 : int index = maybe_index->IsSmi() ? Smi::ToInt(*maybe_index)
13556 2601 : : Context::OBJECT_FUNCTION_INDEX;
13557 : Handle<JSFunction> realm_constructor(JSFunction::cast(context->get(index)),
13558 2700 : isolate);
13559 2700 : prototype = handle(realm_constructor->prototype(), isolate);
13560 : }
13561 :
13562 330818 : Handle<Map> map = Map::CopyInitialMap(isolate, constructor_initial_map);
13563 330809 : map->set_new_target_is_base(false);
13564 661624 : CHECK(prototype->IsJSReceiver());
13565 330814 : if (map->prototype() != *prototype)
13566 330059 : Map::SetPrototype(isolate, map, prototype);
13567 661616 : map->SetConstructor(*constructor);
13568 330814 : return map;
13569 : }
13570 :
13571 3700530 : int JSFunction::ComputeInstanceSizeWithMinSlack(Isolate* isolate) {
13572 3700530 : CHECK(has_initial_map());
13573 7401064 : if (initial_map()->IsInobjectSlackTrackingInProgress()) {
13574 6344 : int slack = initial_map()->ComputeMinObjectSlack(isolate);
13575 12688 : return initial_map()->InstanceSizeFromSlack(slack);
13576 : }
13577 7388375 : return initial_map()->instance_size();
13578 : }
13579 :
13580 0 : void JSFunction::PrintName(FILE* out) {
13581 0 : std::unique_ptr<char[]> name = shared()->DebugName()->ToCString();
13582 0 : PrintF(out, "%s", name.get());
13583 0 : }
13584 :
13585 :
13586 507185 : Handle<String> JSFunction::GetName(Handle<JSFunction> function) {
13587 : Isolate* isolate = function->GetIsolate();
13588 : Handle<Object> name =
13589 507185 : JSReceiver::GetDataProperty(function, isolate->factory()->name_string());
13590 1014370 : if (name->IsString()) return Handle<String>::cast(name);
13591 1013024 : return handle(function->shared()->DebugName(), isolate);
13592 : }
13593 :
13594 :
13595 407372 : Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) {
13596 : Isolate* isolate = function->GetIsolate();
13597 : Handle<Object> name = JSReceiver::GetDataProperty(
13598 407372 : function, isolate->factory()->display_name_string());
13599 814744 : if (name->IsString()) return Handle<String>::cast(name);
13600 407338 : return JSFunction::GetName(function);
13601 : }
13602 :
13603 6925 : bool JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name,
13604 : Handle<String> prefix) {
13605 : Isolate* isolate = function->GetIsolate();
13606 : Handle<String> function_name;
13607 13850 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, function_name,
13608 : Name::ToFunctionName(isolate, name), false);
13609 6916 : if (prefix->length() > 0) {
13610 3183 : IncrementalStringBuilder builder(isolate);
13611 3183 : builder.AppendString(prefix);
13612 : builder.AppendCharacter(' ');
13613 3183 : builder.AppendString(function_name);
13614 6366 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, function_name, builder.Finish(),
13615 : false);
13616 : }
13617 13796 : RETURN_ON_EXCEPTION_VALUE(
13618 : isolate,
13619 : JSObject::DefinePropertyOrElementIgnoreAttributes(
13620 : function, isolate->factory()->name_string(), function_name,
13621 : static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY)),
13622 : false);
13623 6898 : return true;
13624 : }
13625 :
13626 : namespace {
13627 :
13628 1083056 : Handle<String> NativeCodeFunctionSourceString(
13629 : Handle<SharedFunctionInfo> shared_info) {
13630 : Isolate* const isolate = shared_info->GetIsolate();
13631 1083056 : IncrementalStringBuilder builder(isolate);
13632 : builder.AppendCString("function ");
13633 2166112 : builder.AppendString(handle(shared_info->Name(), isolate));
13634 : builder.AppendCString("() { [native code] }");
13635 2166112 : return builder.Finish().ToHandleChecked();
13636 : }
13637 :
13638 : } // namespace
13639 :
13640 :
13641 : // static
13642 55 : Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) {
13643 : Isolate* const isolate = function->GetIsolate();
13644 55 : return isolate->factory()->function_native_code_string();
13645 : }
13646 :
13647 :
13648 : // static
13649 1873132 : Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
13650 : Isolate* const isolate = function->GetIsolate();
13651 3746264 : Handle<SharedFunctionInfo> shared_info(function->shared(), isolate);
13652 :
13653 : // Check if {function} should hide its source code.
13654 1873132 : if (!shared_info->IsUserJavaScript()) {
13655 1082984 : return NativeCodeFunctionSourceString(shared_info);
13656 : }
13657 :
13658 : // Check if we should print {function} as a class.
13659 : Handle<Object> maybe_class_positions = JSReceiver::GetDataProperty(
13660 790148 : function, isolate->factory()->class_positions_symbol());
13661 1580296 : if (maybe_class_positions->IsTuple2()) {
13662 21722 : Tuple2 class_positions = Tuple2::cast(*maybe_class_positions);
13663 21722 : int start_position = Smi::ToInt(class_positions->value1());
13664 21722 : int end_position = Smi::ToInt(class_positions->value2());
13665 : Handle<String> script_source(
13666 65166 : String::cast(Script::cast(shared_info->script())->source()), isolate);
13667 : return isolate->factory()->NewSubString(script_source, start_position,
13668 21722 : end_position);
13669 : }
13670 :
13671 : // Check if we have source code for the {function}.
13672 768426 : if (!shared_info->HasSourceCode()) {
13673 0 : return NativeCodeFunctionSourceString(shared_info);
13674 : }
13675 :
13676 768426 : if (shared_info->function_token_position() == kNoSourcePosition) {
13677 : // If the function token position isn't valid, return [native code] to
13678 : // ensure calling eval on the returned source code throws rather than
13679 : // giving inconsistent call behaviour.
13680 : isolate->CountUsage(
13681 72 : v8::Isolate::UseCounterFeature::kFunctionTokenOffsetTooLongForToString);
13682 72 : return NativeCodeFunctionSourceString(shared_info);
13683 : }
13684 : return Handle<String>::cast(
13685 768354 : SharedFunctionInfo::GetSourceCodeHarmony(shared_info));
13686 : }
13687 :
13688 : STATIC_ASSERT(Oddball::kToNumberRawOffset == HeapNumber::kValueOffset);
13689 :
13690 672 : void Oddball::Initialize(Isolate* isolate, Handle<Oddball> oddball,
13691 : const char* to_string, Handle<Object> to_number,
13692 : const char* type_of, byte kind) {
13693 : Handle<String> internalized_to_string =
13694 672 : isolate->factory()->InternalizeUtf8String(to_string);
13695 : Handle<String> internalized_type_of =
13696 672 : isolate->factory()->InternalizeUtf8String(type_of);
13697 1344 : if (to_number->IsHeapNumber()) {
13698 : oddball->set_to_number_raw_as_bits(
13699 224 : Handle<HeapNumber>::cast(to_number)->value_as_bits());
13700 : } else {
13701 1120 : oddball->set_to_number_raw(to_number->Number());
13702 : }
13703 672 : oddball->set_to_number(*to_number);
13704 672 : oddball->set_to_string(*internalized_to_string);
13705 672 : oddball->set_type_of(*internalized_type_of);
13706 : oddball->set_kind(kind);
13707 672 : }
13708 :
13709 2099 : int Script::GetEvalPosition() {
13710 : DisallowHeapAllocation no_gc;
13711 : DCHECK(compilation_type() == Script::COMPILATION_TYPE_EVAL);
13712 : int position = eval_from_position();
13713 2099 : if (position < 0) {
13714 : // Due to laziness, the position may not have been translated from code
13715 : // offset yet, which would be encoded as negative integer. In that case,
13716 : // translate and set the position.
13717 772 : if (!has_eval_from_shared()) {
13718 : position = 0;
13719 : } else {
13720 772 : SharedFunctionInfo shared = eval_from_shared();
13721 772 : position = shared->abstract_code()->SourcePosition(-position);
13722 : }
13723 : DCHECK_GE(position, 0);
13724 : set_eval_from_position(position);
13725 : }
13726 2099 : return position;
13727 : }
13728 :
13729 2566722 : void Script::InitLineEnds(Handle<Script> script) {
13730 : Isolate* isolate = script->GetIsolate();
13731 7649893 : if (!script->line_ends()->IsUndefined(isolate)) return;
13732 : DCHECK(script->type() != Script::TYPE_WASM ||
13733 : script->source_mapping_url()->IsString());
13734 :
13735 50273 : Object src_obj = script->source();
13736 50273 : if (!src_obj->IsString()) {
13737 : DCHECK(src_obj->IsUndefined(isolate));
13738 10 : script->set_line_ends(ReadOnlyRoots(isolate).empty_fixed_array());
13739 : } else {
13740 : DCHECK(src_obj->IsString());
13741 : Handle<String> src(String::cast(src_obj), isolate);
13742 50268 : Handle<FixedArray> array = String::CalculateLineEnds(isolate, src, true);
13743 100536 : script->set_line_ends(*array);
13744 : }
13745 :
13746 : DCHECK(script->line_ends()->IsFixedArray());
13747 : }
13748 :
13749 2341477 : bool Script::GetPositionInfo(Handle<Script> script, int position,
13750 : PositionInfo* info, OffsetFlag offset_flag) {
13751 : // For wasm, we do not create an artificial line_ends array, but do the
13752 : // translation directly.
13753 2341477 : if (script->type() != Script::TYPE_WASM) InitLineEnds(script);
13754 2341477 : return script->GetPositionInfo(position, info, offset_flag);
13755 : }
13756 :
13757 19255512 : bool Script::IsUserJavaScript() { return type() == Script::TYPE_NORMAL; }
13758 :
13759 388 : bool Script::ContainsAsmModule() {
13760 : DisallowHeapAllocation no_gc;
13761 388 : SharedFunctionInfo::ScriptIterator iter(this->GetIsolate(), *this);
13762 14898 : for (SharedFunctionInfo info = iter.Next(); !info.is_null();
13763 : info = iter.Next()) {
13764 7070 : if (info->HasAsmWasmData()) return true;
13765 : }
13766 379 : return false;
13767 : }
13768 :
13769 : namespace {
13770 269534 : bool GetPositionInfoSlow(const Script script, int position,
13771 : Script::PositionInfo* info) {
13772 539068 : if (!script->source()->IsString()) return false;
13773 269534 : if (position < 0) position = 0;
13774 :
13775 539068 : String source_string = String::cast(script->source());
13776 : int line = 0;
13777 : int line_start = 0;
13778 : int len = source_string->length();
13779 5647902045 : for (int pos = 0; pos <= len; ++pos) {
13780 11295803042 : if (pos == len || source_string->Get(pos) == '\n') {
13781 180492594 : if (position <= pos) {
13782 269524 : info->line = line;
13783 269524 : info->column = position - line_start;
13784 269524 : info->line_start = line_start;
13785 269524 : info->line_end = pos;
13786 269524 : return true;
13787 : }
13788 180223070 : line++;
13789 180223070 : line_start = pos + 1;
13790 : }
13791 : }
13792 : return false;
13793 : }
13794 : } // namespace
13795 :
13796 : #define SMI_VALUE(x) (Smi::ToInt(x))
13797 5324883 : bool Script::GetPositionInfo(int position, PositionInfo* info,
13798 : OffsetFlag offset_flag) const {
13799 : DisallowHeapAllocation no_allocation;
13800 :
13801 : // For wasm, we do not rely on the line_ends array, but do the translation
13802 : // directly.
13803 5324883 : if (type() == Script::TYPE_WASM) {
13804 : DCHECK_LE(0, position);
13805 929 : return WasmModuleObject::cast(wasm_module_object())
13806 1858 : ->GetPositionInfo(static_cast<uint32_t>(position), info);
13807 : }
13808 :
13809 10647908 : if (line_ends()->IsUndefined()) {
13810 : // Slow mode: we do not have line_ends. We have to iterate through source.
13811 269534 : if (!GetPositionInfoSlow(*this, position, info)) return false;
13812 : } else {
13813 : DCHECK(line_ends()->IsFixedArray());
13814 5054420 : FixedArray ends = FixedArray::cast(line_ends());
13815 :
13816 : const int ends_len = ends->length();
13817 5054420 : if (ends_len == 0) return false;
13818 :
13819 : // Return early on invalid positions. Negative positions behave as if 0 was
13820 : // passed, and positions beyond the end of the script return as failure.
13821 5054405 : if (position < 0) {
13822 : position = 0;
13823 10108780 : } else if (position > SMI_VALUE(ends->get(ends_len - 1))) {
13824 : return false;
13825 : }
13826 :
13827 : // Determine line number by doing a binary search on the line ends array.
13828 5049064 : if (SMI_VALUE(ends->get(0)) >= position) {
13829 260303 : info->line = 0;
13830 260303 : info->line_start = 0;
13831 260303 : info->column = position;
13832 : } else {
13833 : int left = 0;
13834 4788761 : int right = ends_len - 1;
13835 :
13836 49007310 : while (right > 0) {
13837 : DCHECK_LE(left, right);
13838 44218549 : const int mid = (left + right) / 2;
13839 44218549 : if (position > SMI_VALUE(ends->get(mid))) {
13840 20571308 : left = mid + 1;
13841 47294482 : } else if (position <= SMI_VALUE(ends->get(mid - 1))) {
13842 : right = mid - 1;
13843 : } else {
13844 4788761 : info->line = mid;
13845 4788761 : break;
13846 : }
13847 : }
13848 : DCHECK(SMI_VALUE(ends->get(info->line)) >= position &&
13849 : SMI_VALUE(ends->get(info->line - 1)) < position);
13850 9577522 : info->line_start = SMI_VALUE(ends->get(info->line - 1)) + 1;
13851 4788761 : info->column = position - info->line_start;
13852 : }
13853 :
13854 : // Line end is position of the linebreak character.
13855 10098128 : info->line_end = SMI_VALUE(ends->get(info->line));
13856 5049064 : if (info->line_end > 0) {
13857 : DCHECK(source()->IsString());
13858 10096292 : String src = String::cast(source());
13859 10096292 : if (src->length() >= info->line_end &&
13860 5048146 : src->Get(info->line_end - 1) == '\r') {
13861 0 : info->line_end--;
13862 : }
13863 : }
13864 : }
13865 :
13866 : // Add offsets if requested.
13867 5318588 : if (offset_flag == WITH_OFFSET) {
13868 5185580 : if (info->line == 0) {
13869 440845 : info->column += column_offset();
13870 : }
13871 5185580 : info->line += line_offset();
13872 : }
13873 :
13874 : return true;
13875 : }
13876 : #undef SMI_VALUE
13877 :
13878 838415 : int Script::GetColumnNumber(Handle<Script> script, int code_pos) {
13879 : PositionInfo info;
13880 838415 : GetPositionInfo(script, code_pos, &info, WITH_OFFSET);
13881 838415 : return info.column;
13882 : }
13883 :
13884 134738 : int Script::GetColumnNumber(int code_pos) const {
13885 : PositionInfo info;
13886 134738 : GetPositionInfo(code_pos, &info, WITH_OFFSET);
13887 134738 : return info.column;
13888 : }
13889 :
13890 843561 : int Script::GetLineNumber(Handle<Script> script, int code_pos) {
13891 : PositionInfo info;
13892 843561 : GetPositionInfo(script, code_pos, &info, WITH_OFFSET);
13893 843561 : return info.line;
13894 : }
13895 :
13896 2848262 : int Script::GetLineNumber(int code_pos) const {
13897 : PositionInfo info;
13898 2848262 : GetPositionInfo(code_pos, &info, WITH_OFFSET);
13899 2848262 : return info.line;
13900 : }
13901 :
13902 25773 : Object Script::GetNameOrSourceURL() {
13903 : // Keep in sync with ScriptNameOrSourceURL in messages.js.
13904 51546 : if (!source_url()->IsUndefined()) return source_url();
13905 24025 : return name();
13906 : }
13907 :
13908 4078272 : MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
13909 8156558 : Isolate* isolate, const FunctionLiteral* fun) {
13910 4078272 : CHECK_NE(fun->function_literal_id(), FunctionLiteral::kIdTypeInvalid);
13911 : // If this check fails, the problem is most probably the function id
13912 : // renumbering done by AstFunctionLiteralIdReindexer; in particular, that
13913 : // AstTraversalVisitor doesn't recurse properly in the construct which
13914 : // triggers the mismatch.
13915 8156558 : CHECK_LT(fun->function_literal_id(), shared_function_infos()->length());
13916 4078286 : MaybeObject shared = shared_function_infos()->Get(fun->function_literal_id());
13917 4078294 : HeapObject heap_object;
13918 8156583 : if (!shared->GetHeapObject(&heap_object) ||
13919 : heap_object->IsUndefined(isolate)) {
13920 2557486 : return MaybeHandle<SharedFunctionInfo>();
13921 : }
13922 1520809 : return handle(SharedFunctionInfo::cast(heap_object), isolate);
13923 : }
13924 :
13925 135670 : Script::Iterator::Iterator(Isolate* isolate)
13926 271345 : : iterator_(isolate->heap()->script_list()) {}
13927 :
13928 5197484 : Script Script::Iterator::Next() {
13929 5197484 : Object o = iterator_.Next();
13930 5197484 : if (o != Object()) {
13931 : return Script::cast(o);
13932 : }
13933 4253 : return Script();
13934 : }
13935 :
13936 17681598 : Code SharedFunctionInfo::GetCode() const {
13937 : // ======
13938 : // NOTE: This chain of checks MUST be kept in sync with the equivalent CSA
13939 : // GetSharedFunctionInfoCode method in code-stub-assembler.cc.
13940 : // ======
13941 :
13942 : Isolate* isolate = GetIsolate();
13943 17681615 : Object data = function_data();
13944 17681607 : if (data->IsSmi()) {
13945 : // Holding a Smi means we are a builtin.
13946 : DCHECK(HasBuiltinId());
13947 3320394 : return isolate->builtins()->builtin(builtin_id());
13948 14361230 : } else if (data->IsBytecodeArray()) {
13949 : // Having a bytecode array means we are a compiled, interpreted function.
13950 : DCHECK(HasBytecodeArray());
13951 6961104 : return isolate->builtins()->builtin(Builtins::kInterpreterEntryTrampoline);
13952 7400127 : } else if (data->IsAsmWasmData()) {
13953 : // Having AsmWasmData means we are an asm.js/wasm function.
13954 : DCHECK(HasAsmWasmData());
13955 5048 : return isolate->builtins()->builtin(Builtins::kInstantiateAsmJs);
13956 7395073 : } else if (data->IsUncompiledData()) {
13957 : // Having uncompiled data (with or without scope) means we need to compile.
13958 : DCHECK(HasUncompiledData());
13959 3242113 : return isolate->builtins()->builtin(Builtins::kCompileLazy);
13960 4152962 : } else if (data->IsFunctionTemplateInfo()) {
13961 : // Having a function template info means we are an API function.
13962 : DCHECK(IsApiFunction());
13963 3887237 : return isolate->builtins()->builtin(Builtins::kHandleApiCall);
13964 265726 : } else if (data->IsWasmExportedFunctionData()) {
13965 : // Having a WasmExportedFunctionData means the code is in there.
13966 : DCHECK(HasWasmExportedFunctionData());
13967 265686 : return wasm_exported_function_data()->wrapper_code();
13968 40 : } else if (data->IsInterpreterData()) {
13969 : Code code = InterpreterTrampoline();
13970 : DCHECK(code->IsCode());
13971 : DCHECK(code->is_interpreter_trampoline_builtin());
13972 40 : return code;
13973 : }
13974 0 : UNREACHABLE();
13975 : }
13976 :
13977 887863 : WasmExportedFunctionData SharedFunctionInfo::wasm_exported_function_data()
13978 : const {
13979 : DCHECK(HasWasmExportedFunctionData());
13980 887866 : return WasmExportedFunctionData::cast(function_data());
13981 : }
13982 :
13983 132196 : SharedFunctionInfo::ScriptIterator::ScriptIterator(Isolate* isolate,
13984 : Script script)
13985 : : ScriptIterator(isolate,
13986 264392 : handle(script->shared_function_infos(), isolate)) {}
13987 :
13988 0 : SharedFunctionInfo::ScriptIterator::ScriptIterator(
13989 : Isolate* isolate, Handle<WeakFixedArray> shared_function_infos)
13990 : : isolate_(isolate),
13991 : shared_function_infos_(shared_function_infos),
13992 240410 : index_(0) {}
13993 :
13994 2006359 : SharedFunctionInfo SharedFunctionInfo::ScriptIterator::Next() {
13995 7819215 : while (index_ < shared_function_infos_->length()) {
13996 5548590 : MaybeObject raw = shared_function_infos_->Get(index_++);
13997 2774295 : HeapObject heap_object;
13998 5197836 : if (!raw->GetHeapObject(&heap_object) ||
13999 2423541 : heap_object->IsUndefined(isolate_)) {
14000 900069 : continue;
14001 : }
14002 1874226 : return SharedFunctionInfo::cast(heap_object);
14003 : }
14004 132133 : return SharedFunctionInfo();
14005 : }
14006 :
14007 10 : void SharedFunctionInfo::ScriptIterator::Reset(Script script) {
14008 20 : shared_function_infos_ = handle(script->shared_function_infos(), isolate_);
14009 10 : index_ = 0;
14010 10 : }
14011 :
14012 5 : SharedFunctionInfo::GlobalIterator::GlobalIterator(Isolate* isolate)
14013 : : script_iterator_(isolate),
14014 : noscript_sfi_iterator_(isolate->heap()->noscript_shared_function_infos()),
14015 10 : sfi_iterator_(isolate, script_iterator_.Next()) {}
14016 :
14017 3470 : SharedFunctionInfo SharedFunctionInfo::GlobalIterator::Next() {
14018 3470 : HeapObject next = noscript_sfi_iterator_.Next();
14019 3470 : if (!next.is_null()) return SharedFunctionInfo::cast(next);
14020 : for (;;) {
14021 65 : next = sfi_iterator_.Next();
14022 120 : if (!next.is_null()) return SharedFunctionInfo::cast(next);
14023 15 : Script next_script = script_iterator_.Next();
14024 15 : if (next_script.is_null()) return SharedFunctionInfo();
14025 10 : sfi_iterator_.Reset(next_script);
14026 10 : }
14027 : }
14028 :
14029 3564466 : void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
14030 : Handle<Object> script_object,
14031 : int function_literal_id,
14032 : bool reset_preparsed_scope_data) {
14033 10693423 : if (shared->script() == *script_object) return;
14034 : Isolate* isolate = shared->GetIsolate();
14035 :
14036 10693434 : if (reset_preparsed_scope_data &&
14037 3564738 : shared->HasUncompiledDataWithPreparseData()) {
14038 0 : shared->ClearPreparseData();
14039 : }
14040 :
14041 : // Add shared function info to new script's list. If a collection occurs,
14042 : // the shared function info may be temporarily in two lists.
14043 : // This is okay because the gc-time processing of these lists can tolerate
14044 : // duplicates.
14045 7128947 : if (script_object->IsScript()) {
14046 : DCHECK(!shared->script()->IsScript());
14047 3564469 : Handle<Script> script = Handle<Script>::cast(script_object);
14048 : Handle<WeakFixedArray> list =
14049 7128943 : handle(script->shared_function_infos(), isolate);
14050 : #ifdef DEBUG
14051 : DCHECK_LT(function_literal_id, list->length());
14052 : MaybeObject maybe_object = list->Get(function_literal_id);
14053 : HeapObject heap_object;
14054 : if (maybe_object->GetHeapObjectIfWeak(&heap_object)) {
14055 : DCHECK_EQ(heap_object, *shared);
14056 : }
14057 : #endif
14058 7128949 : list->Set(function_literal_id, HeapObjectReference::Weak(*shared));
14059 :
14060 : // Remove shared function info from root array.
14061 : WeakArrayList noscript_list =
14062 3564475 : isolate->heap()->noscript_shared_function_infos();
14063 3564469 : CHECK(noscript_list->RemoveOne(MaybeObjectHandle::Weak(shared)));
14064 : } else {
14065 : DCHECK(shared->script()->IsScript());
14066 : Handle<WeakArrayList> list =
14067 : isolate->factory()->noscript_shared_function_infos();
14068 :
14069 : #ifdef DEBUG
14070 : if (FLAG_enable_slow_asserts) {
14071 : WeakArrayList::Iterator iterator(*list);
14072 : for (HeapObject next = iterator.Next(); !next.is_null();
14073 : next = iterator.Next()) {
14074 : DCHECK_NE(next, *shared);
14075 : }
14076 : }
14077 : #endif // DEBUG
14078 :
14079 : list =
14080 0 : WeakArrayList::AddToEnd(isolate, list, MaybeObjectHandle::Weak(shared));
14081 :
14082 0 : isolate->heap()->SetRootNoScriptSharedFunctionInfos(*list);
14083 :
14084 : // Remove shared function info from old script's list.
14085 0 : Script old_script = Script::cast(shared->script());
14086 :
14087 : // Due to liveedit, it might happen that the old_script doesn't know
14088 : // about the SharedFunctionInfo, so we have to guard against that.
14089 0 : Handle<WeakFixedArray> infos(old_script->shared_function_infos(), isolate);
14090 0 : if (function_literal_id < infos->length()) {
14091 : MaybeObject raw =
14092 0 : old_script->shared_function_infos()->Get(function_literal_id);
14093 0 : HeapObject heap_object;
14094 0 : if (raw->GetHeapObjectIfWeak(&heap_object) && heap_object == *shared) {
14095 : old_script->shared_function_infos()->Set(
14096 : function_literal_id, HeapObjectReference::Strong(
14097 0 : ReadOnlyRoots(isolate).undefined_value()));
14098 : }
14099 : }
14100 : }
14101 :
14102 : // Finally set new script.
14103 3564469 : shared->set_script(*script_object);
14104 : }
14105 :
14106 8668073 : bool SharedFunctionInfo::HasBreakInfo() const {
14107 8668073 : if (!HasDebugInfo()) return false;
14108 477718 : DebugInfo info = GetDebugInfo();
14109 477718 : bool has_break_info = info->HasBreakInfo();
14110 477718 : return has_break_info;
14111 : }
14112 :
14113 16237 : bool SharedFunctionInfo::BreakAtEntry() const {
14114 16237 : if (!HasDebugInfo()) return false;
14115 470 : DebugInfo info = GetDebugInfo();
14116 470 : bool break_at_entry = info->BreakAtEntry();
14117 470 : return break_at_entry;
14118 : }
14119 :
14120 255459 : bool SharedFunctionInfo::HasCoverageInfo() const {
14121 255459 : if (!HasDebugInfo()) return false;
14122 239280 : DebugInfo info = GetDebugInfo();
14123 239280 : bool has_coverage_info = info->HasCoverageInfo();
14124 239280 : return has_coverage_info;
14125 : }
14126 :
14127 224265 : CoverageInfo SharedFunctionInfo::GetCoverageInfo() const {
14128 : DCHECK(HasCoverageInfo());
14129 448530 : return CoverageInfo::cast(GetDebugInfo()->coverage_info());
14130 : }
14131 :
14132 7217412 : String SharedFunctionInfo::DebugName() {
14133 : DisallowHeapAllocation no_gc;
14134 7217412 : String function_name = Name();
14135 7217439 : if (function_name->length() > 0) return function_name;
14136 1951627 : return inferred_name();
14137 : }
14138 :
14139 926643 : bool SharedFunctionInfo::PassesFilter(const char* raw_filter) {
14140 926643 : Vector<const char> filter = CStrVector(raw_filter);
14141 1853290 : std::unique_ptr<char[]> cstrname(DebugName()->ToCString());
14142 1853307 : return v8::internal::PassesFilter(CStrVector(cstrname.get()), filter);
14143 : }
14144 :
14145 6808968 : bool SharedFunctionInfo::HasSourceCode() const {
14146 : Isolate* isolate = GetIsolate();
14147 27235872 : return !script()->IsUndefined(isolate) &&
14148 27235872 : !Script::cast(script())->source()->IsUndefined(isolate);
14149 : }
14150 :
14151 364 : void SharedFunctionInfo::DiscardCompiledMetadata(
14152 : Isolate* isolate,
14153 : std::function<void(HeapObject object, ObjectSlot slot, HeapObject target)>
14154 : gc_notify_updated_slot) {
14155 : DisallowHeapAllocation no_gc;
14156 364 : if (is_compiled()) {
14157 : HeapObject outer_scope_info;
14158 357 : if (scope_info()->HasOuterScopeInfo()) {
14159 171 : outer_scope_info = scope_info()->OuterScopeInfo();
14160 : } else {
14161 186 : outer_scope_info = ReadOnlyRoots(isolate).the_hole_value();
14162 : }
14163 :
14164 : // Raw setter to avoid validity checks, since we're performing the unusual
14165 : // task of decompiling.
14166 357 : set_raw_outer_scope_info_or_feedback_metadata(outer_scope_info);
14167 : gc_notify_updated_slot(
14168 : *this,
14169 : RawField(SharedFunctionInfo::kOuterScopeInfoOrFeedbackMetadataOffset),
14170 357 : outer_scope_info);
14171 : } else {
14172 : DCHECK(outer_scope_info()->IsScopeInfo() ||
14173 : outer_scope_info()->IsTheHole());
14174 : }
14175 :
14176 : // TODO(rmcilroy): Possibly discard ScopeInfo here as well.
14177 364 : }
14178 :
14179 : // static
14180 253 : void SharedFunctionInfo::DiscardCompiled(
14181 : Isolate* isolate, Handle<SharedFunctionInfo> shared_info) {
14182 : DCHECK(shared_info->CanDiscardCompiled());
14183 :
14184 : Handle<String> inferred_name_val =
14185 506 : handle(shared_info->inferred_name(), isolate);
14186 253 : int start_position = shared_info->StartPosition();
14187 253 : int end_position = shared_info->EndPosition();
14188 253 : int function_literal_id = shared_info->FunctionLiteralId(isolate);
14189 :
14190 506 : shared_info->DiscardCompiledMetadata(isolate);
14191 :
14192 : // Replace compiled data with a new UncompiledData object.
14193 253 : if (shared_info->HasUncompiledDataWithPreparseData()) {
14194 : // If this is uncompiled data with a pre-parsed scope data, we can just
14195 : // clear out the scope data and keep the uncompiled data.
14196 7 : shared_info->ClearPreparseData();
14197 : } else {
14198 : // Create a new UncompiledData, without pre-parsed scope, and update the
14199 : // function data to point to it. Use the raw function data setter to avoid
14200 : // validity checks, since we're performing the unusual task of decompiling.
14201 : Handle<UncompiledData> data =
14202 : isolate->factory()->NewUncompiledDataWithoutPreparseData(
14203 : inferred_name_val, start_position, end_position,
14204 246 : function_literal_id);
14205 492 : shared_info->set_function_data(*data);
14206 : }
14207 253 : }
14208 :
14209 : // static
14210 567 : Handle<Object> SharedFunctionInfo::GetSourceCode(
14211 : Handle<SharedFunctionInfo> shared) {
14212 : Isolate* isolate = shared->GetIsolate();
14213 567 : if (!shared->HasSourceCode()) return isolate->factory()->undefined_value();
14214 1134 : Handle<String> source(String::cast(Script::cast(shared->script())->source()),
14215 1134 : isolate);
14216 : return isolate->factory()->NewSubString(source, shared->StartPosition(),
14217 1134 : shared->EndPosition());
14218 : }
14219 :
14220 : // static
14221 768354 : Handle<Object> SharedFunctionInfo::GetSourceCodeHarmony(
14222 : Handle<SharedFunctionInfo> shared) {
14223 : Isolate* isolate = shared->GetIsolate();
14224 768354 : if (!shared->HasSourceCode()) return isolate->factory()->undefined_value();
14225 : Handle<String> script_source(
14226 2305062 : String::cast(Script::cast(shared->script())->source()), isolate);
14227 768354 : int start_pos = shared->function_token_position();
14228 : DCHECK_NE(start_pos, kNoSourcePosition);
14229 : Handle<String> source = isolate->factory()->NewSubString(
14230 768354 : script_source, start_pos, shared->EndPosition());
14231 768354 : if (!shared->is_wrapped()) return source;
14232 :
14233 : DCHECK(!shared->name_should_print_as_anonymous());
14234 15 : IncrementalStringBuilder builder(isolate);
14235 : builder.AppendCString("function ");
14236 30 : builder.AppendString(Handle<String>(shared->Name(), isolate));
14237 : builder.AppendCString("(");
14238 30 : Handle<FixedArray> args(Script::cast(shared->script())->wrapped_arguments(),
14239 30 : isolate);
14240 : int argc = args->length();
14241 20 : for (int i = 0; i < argc; i++) {
14242 5 : if (i > 0) builder.AppendCString(", ");
14243 5 : builder.AppendString(Handle<String>(String::cast(args->get(i)), isolate));
14244 : }
14245 : builder.AppendCString(") {\n");
14246 15 : builder.AppendString(source);
14247 : builder.AppendCString("\n}");
14248 30 : return builder.Finish().ToHandleChecked();
14249 : }
14250 :
14251 284631 : bool SharedFunctionInfo::IsInlineable() {
14252 : // Check that the function has a script associated with it.
14253 569266 : if (!script()->IsScript()) return false;
14254 :
14255 247295 : if (GetIsolate()->is_precise_binary_code_coverage() &&
14256 10 : !has_reported_binary_coverage()) {
14257 : // We may miss invocations if this function is inlined.
14258 : return false;
14259 : }
14260 :
14261 247287 : if (optimization_disabled()) return false;
14262 :
14263 : // Built-in functions are handled by the JSCallReducer.
14264 246203 : if (HasBuiltinFunctionId()) return false;
14265 :
14266 : // Only choose user code for inlining.
14267 246202 : if (!IsUserJavaScript()) return false;
14268 :
14269 : // If there is no bytecode array, it is either not compiled or it is compiled
14270 : // with WebAssembly for the asm.js pipeline. In either case we don't want to
14271 : // inline.
14272 245849 : if (!HasBytecodeArray()) return false;
14273 :
14274 : // Quick check on the size of the bytecode to avoid inlining large functions.
14275 466789 : if (GetBytecodeArray()->length() > FLAG_max_inlined_bytecode_size) {
14276 : return false;
14277 : }
14278 :
14279 233145 : return true;
14280 : }
14281 :
14282 0 : int SharedFunctionInfo::SourceSize() { return EndPosition() - StartPosition(); }
14283 :
14284 108214 : int SharedFunctionInfo::FindIndexInScript(Isolate* isolate) const {
14285 : DisallowHeapAllocation no_gc;
14286 :
14287 108214 : Object script_obj = script();
14288 108214 : if (!script_obj->IsScript()) return FunctionLiteral::kIdTypeInvalid;
14289 :
14290 : WeakFixedArray shared_info_list =
14291 108214 : Script::cast(script_obj)->shared_function_infos();
14292 : SharedFunctionInfo::ScriptIterator iterator(
14293 : isolate,
14294 : Handle<WeakFixedArray>(reinterpret_cast<Address*>(&shared_info_list)));
14295 :
14296 686304 : for (SharedFunctionInfo shared = iterator.Next(); !shared.is_null();
14297 : shared = iterator.Next()) {
14298 686304 : if (shared == *this) {
14299 108214 : return iterator.CurrentIndex();
14300 : }
14301 : }
14302 :
14303 : return FunctionLiteral::kIdTypeInvalid;
14304 : }
14305 :
14306 321510 : void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type,
14307 : bool has_prototype_slot,
14308 : int requested_embedder_fields,
14309 : int requested_in_object_properties,
14310 : int* instance_size,
14311 : int* in_object_properties) {
14312 : DCHECK_LE(static_cast<unsigned>(requested_embedder_fields),
14313 : JSObject::kMaxEmbedderFields);
14314 321510 : int header_size = JSObject::GetHeaderSize(instance_type, has_prototype_slot);
14315 321510 : if (requested_embedder_fields) {
14316 : // If there are embedder fields, then the embedder fields start offset must
14317 : // be properly aligned (embedder fields are located between object header
14318 : // and inobject fields).
14319 : header_size = RoundUp<kSystemPointerSize>(header_size);
14320 : requested_embedder_fields *= kEmbedderDataSlotSizeInTaggedSlots;
14321 : }
14322 : int max_nof_fields =
14323 321510 : (JSObject::kMaxInstanceSize - header_size) >> kTaggedSizeLog2;
14324 321510 : CHECK_LE(max_nof_fields, JSObject::kMaxInObjectProperties);
14325 321510 : CHECK_LE(static_cast<unsigned>(requested_embedder_fields),
14326 : static_cast<unsigned>(max_nof_fields));
14327 : *in_object_properties = Min(requested_in_object_properties,
14328 643020 : max_nof_fields - requested_embedder_fields);
14329 : *instance_size =
14330 321510 : header_size +
14331 643020 : ((requested_embedder_fields + *in_object_properties) << kTaggedSizeLog2);
14332 321510 : CHECK_EQ(*in_object_properties,
14333 : ((*instance_size - header_size) >> kTaggedSizeLog2) -
14334 : requested_embedder_fields);
14335 321510 : CHECK_LE(static_cast<unsigned>(*instance_size),
14336 : static_cast<unsigned>(JSObject::kMaxInstanceSize));
14337 321510 : }
14338 :
14339 : // static
14340 11343 : bool JSFunction::CalculateInstanceSizeForDerivedClass(
14341 : Handle<JSFunction> function, InstanceType instance_type,
14342 : int requested_embedder_fields, int* instance_size,
14343 : int* in_object_properties) {
14344 : Isolate* isolate = function->GetIsolate();
14345 : int expected_nof_properties = 0;
14346 44947 : for (PrototypeIterator iter(isolate, function, kStartAtReceiver);
14347 22261 : !iter.IsAtEnd(); iter.Advance()) {
14348 : Handle<JSReceiver> current =
14349 : PrototypeIterator::GetCurrent<JSReceiver>(iter);
14350 67209 : if (!current->IsJSFunction()) break;
14351 33497 : Handle<JSFunction> func(Handle<JSFunction>::cast(current));
14352 : // The super constructor should be compiled for the number of expected
14353 : // properties to be available.
14354 66992 : Handle<SharedFunctionInfo> shared(func->shared(), isolate);
14355 33496 : IsCompiledScope is_compiled_scope(shared->is_compiled_scope());
14356 33505 : if (is_compiled_scope.is_compiled() ||
14357 : Compiler::Compile(func, Compiler::CLEAR_EXCEPTION,
14358 10 : &is_compiled_scope)) {
14359 : DCHECK(shared->is_compiled());
14360 33496 : int count = shared->expected_nof_properties();
14361 : // Check that the estimate is sane.
14362 33496 : if (expected_nof_properties <= JSObject::kMaxInObjectProperties - count) {
14363 28652 : expected_nof_properties += count;
14364 : } else {
14365 : expected_nof_properties = JSObject::kMaxInObjectProperties;
14366 : }
14367 : } else {
14368 : // In case there was a compilation error for the constructor we will
14369 : // throw an error during instantiation. Hence we directly return 0;
14370 0 : return false;
14371 : }
14372 33496 : if (!IsDerivedConstructor(shared->kind())) break;
14373 : }
14374 : CalculateInstanceSizeHelper(instance_type, true, requested_embedder_fields,
14375 : expected_nof_properties, instance_size,
14376 11343 : in_object_properties);
14377 11343 : return true;
14378 : }
14379 :
14380 :
14381 : // Output the source code without any allocation in the heap.
14382 27 : std::ostream& operator<<(std::ostream& os, const SourceCodeOf& v) {
14383 27 : const SharedFunctionInfo s = v.value;
14384 : // For some native functions there is no source.
14385 27 : if (!s->HasSourceCode()) return os << "<No Source>";
14386 :
14387 : // Get the source for the script which this function came from.
14388 : // Don't use String::cast because we don't want more assertion errors while
14389 : // we are already creating a stack dump.
14390 : String script_source =
14391 54 : String::unchecked_cast(Script::cast(s->script())->source());
14392 :
14393 27 : if (!script_source->LooksValid()) return os << "<Invalid Source>";
14394 :
14395 27 : if (!s->is_toplevel()) {
14396 18 : os << "function ";
14397 18 : String name = s->Name();
14398 18 : if (name->length() > 0) {
14399 18 : name->PrintUC16(os);
14400 : }
14401 : }
14402 :
14403 27 : int len = s->EndPosition() - s->StartPosition();
14404 27 : if (len <= v.max_length || v.max_length < 0) {
14405 9 : script_source->PrintUC16(os, s->StartPosition(), s->EndPosition());
14406 9 : return os;
14407 : } else {
14408 : script_source->PrintUC16(os, s->StartPosition(),
14409 18 : s->StartPosition() + v.max_length);
14410 18 : return os << "...\n";
14411 : }
14412 : }
14413 :
14414 :
14415 20123 : void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
14416 : DCHECK_NE(reason, BailoutReason::kNoReason);
14417 :
14418 : set_flags(DisabledOptimizationReasonBits::update(flags(), reason));
14419 : // Code should be the lazy compilation stub or else interpreted.
14420 : DCHECK(abstract_code()->kind() == AbstractCode::INTERPRETED_FUNCTION ||
14421 : abstract_code()->kind() == AbstractCode::BUILTIN);
14422 40246 : PROFILE(GetIsolate(), CodeDisableOptEvent(abstract_code(), *this));
14423 20123 : if (FLAG_trace_opt) {
14424 0 : PrintF("[disabled optimization for ");
14425 0 : ShortPrint();
14426 0 : PrintF(", reason: %s]\n", GetBailoutReason(reason));
14427 : }
14428 20123 : }
14429 :
14430 3564344 : void SharedFunctionInfo::InitFromFunctionLiteral(
14431 23943554 : Handle<SharedFunctionInfo> shared_info, FunctionLiteral* lit,
14432 : bool is_toplevel) {
14433 : Isolate* isolate = shared_info->GetIsolate();
14434 : bool needs_position_info = true;
14435 :
14436 : // When adding fields here, make sure DeclarationScope::AnalyzePartially is
14437 : // updated accordingly.
14438 : shared_info->set_internal_formal_parameter_count(lit->parameter_count());
14439 : shared_info->SetFunctionTokenPosition(lit->function_token_position(),
14440 10693047 : lit->start_position());
14441 3564348 : if (shared_info->scope_info()->HasPositionInfo()) {
14442 0 : shared_info->scope_info()->SetPositionInfo(lit->start_position(),
14443 0 : lit->end_position());
14444 : needs_position_info = false;
14445 : }
14446 7128692 : shared_info->set_is_declaration(lit->is_declaration());
14447 7128691 : shared_info->set_is_named_expression(lit->is_named_expression());
14448 7128689 : shared_info->set_is_anonymous_expression(lit->is_anonymous_expression());
14449 7128691 : shared_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
14450 7128695 : shared_info->set_language_mode(lit->language_mode());
14451 7128698 : shared_info->set_is_wrapped(lit->is_wrapped());
14452 : // shared_info->set_kind(lit->kind());
14453 : // FunctionKind must have already been set.
14454 : DCHECK(lit->kind() == shared_info->kind());
14455 7128684 : shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
14456 : DCHECK_IMPLIES(lit->requires_instance_members_initializer(),
14457 : IsClassConstructor(lit->kind()));
14458 : shared_info->set_requires_instance_members_initializer(
14459 7128694 : lit->requires_instance_members_initializer());
14460 :
14461 7128689 : shared_info->set_is_toplevel(is_toplevel);
14462 : DCHECK(shared_info->outer_scope_info()->IsTheHole());
14463 3564345 : if (!is_toplevel) {
14464 2557486 : Scope* outer_scope = lit->scope()->GetOuterScopeWithContext();
14465 2557482 : if (outer_scope) {
14466 4322427 : shared_info->set_outer_scope_info(*outer_scope->scope_info());
14467 : }
14468 : }
14469 :
14470 : // For lazy parsed functions, the following flags will be inaccurate since we
14471 : // don't have the information yet. They're set later in
14472 : // SetSharedFunctionFlagsFromLiteral (compiler.cc), when the function is
14473 : // really parsed and compiled.
14474 3564342 : if (lit->ShouldEagerCompile()) {
14475 : shared_info->set_length(lit->function_length());
14476 3041549 : shared_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
14477 3041558 : shared_info->SetExpectedNofPropertiesFromEstimate(lit);
14478 : DCHECK_NULL(lit->produced_preparse_data());
14479 : // If we're about to eager compile, we'll have the function literal
14480 : // available, so there's no need to wastefully allocate an uncompiled data.
14481 : // TODO(leszeks): This should be explicitly passed as a parameter, rather
14482 : // than relying on a property of the literal.
14483 : needs_position_info = false;
14484 : } else {
14485 : // Set an invalid length for lazy functions. This way we can set the correct
14486 : // value after compiling, but avoid overwriting values set manually by the
14487 : // bootstrapper.
14488 : shared_info->set_length(SharedFunctionInfo::kInvalidLength);
14489 : ProducedPreparseData* scope_data = lit->produced_preparse_data();
14490 2043566 : if (scope_data != nullptr) {
14491 : Handle<PreparseData> preparse_data =
14492 118694 : scope_data->Serialize(shared_info->GetIsolate());
14493 : Handle<UncompiledData> data =
14494 : isolate->factory()->NewUncompiledDataWithPreparseData(
14495 : lit->inferred_name(), lit->start_position(), lit->end_position(),
14496 59347 : lit->function_literal_id(), preparse_data);
14497 118694 : shared_info->set_uncompiled_data(*data);
14498 : needs_position_info = false;
14499 : }
14500 : }
14501 3564345 : if (needs_position_info) {
14502 : Handle<UncompiledData> data =
14503 : isolate->factory()->NewUncompiledDataWithoutPreparseData(
14504 : lit->inferred_name(), lit->start_position(), lit->end_position(),
14505 1984220 : lit->function_literal_id());
14506 3968441 : shared_info->set_uncompiled_data(*data);
14507 : }
14508 3564346 : }
14509 :
14510 2089347 : void SharedFunctionInfo::SetExpectedNofPropertiesFromEstimate(
14511 3610126 : FunctionLiteral* literal) {
14512 3610126 : int estimate = literal->expected_property_count();
14513 :
14514 : // If no properties are added in the constructor, they are more likely
14515 : // to be added later.
14516 3610126 : if (estimate == 0) estimate = 2;
14517 :
14518 : // Inobject slack tracking will reclaim redundant inobject space later,
14519 : // so we can afford to adjust the estimate generously.
14520 3610126 : estimate += 8;
14521 :
14522 : // Limit actual estimate to fit in a 8 bit field, we will never allocate
14523 : // more than this in any case.
14524 : STATIC_ASSERT(JSObject::kMaxInObjectProperties <= kMaxUInt8);
14525 3610126 : estimate = std::min(estimate, kMaxUInt8);
14526 :
14527 : set_expected_nof_properties(estimate);
14528 2089347 : }
14529 :
14530 1137 : void SharedFunctionInfo::SetFunctionTokenPosition(int function_token_position,
14531 : int start_position) {
14532 : int offset;
14533 3565486 : if (function_token_position == kNoSourcePosition) {
14534 : offset = 0;
14535 : } else {
14536 2533122 : offset = start_position - function_token_position;
14537 : }
14538 :
14539 3565486 : if (offset > kMaximumFunctionTokenOffset) {
14540 : offset = kFunctionTokenOutOfRange;
14541 : }
14542 : set_raw_function_token_offset(offset);
14543 1137 : }
14544 :
14545 10138624 : int SharedFunctionInfo::StartPosition() const {
14546 10138624 : Object maybe_scope_info = name_or_scope_info();
14547 10138634 : if (maybe_scope_info->IsScopeInfo()) {
14548 6268550 : ScopeInfo info = ScopeInfo::cast(maybe_scope_info);
14549 6268550 : if (info->HasPositionInfo()) {
14550 6268550 : return info->StartPosition();
14551 : }
14552 3870083 : } else if (HasUncompiledData()) {
14553 : // Works with or without scope.
14554 5679533 : return uncompiled_data()->start_position();
14555 1030314 : } else if (IsApiFunction() || HasBuiltinId()) {
14556 : DCHECK_IMPLIES(HasBuiltinId(), builtin_id() != Builtins::kCompileLazy);
14557 : return 0;
14558 : }
14559 : return kNoSourcePosition;
14560 : }
14561 :
14562 2281159 : int SharedFunctionInfo::EndPosition() const {
14563 2281159 : Object maybe_scope_info = name_or_scope_info();
14564 2281166 : if (maybe_scope_info->IsScopeInfo()) {
14565 464959 : ScopeInfo info = ScopeInfo::cast(maybe_scope_info);
14566 464959 : if (info->HasPositionInfo()) {
14567 464959 : return info->EndPosition();
14568 : }
14569 1816207 : } else if (HasUncompiledData()) {
14570 : // Works with or without scope.
14571 3632407 : return uncompiled_data()->end_position();
14572 0 : } else if (IsApiFunction() || HasBuiltinId()) {
14573 : DCHECK_IMPLIES(HasBuiltinId(), builtin_id() != Builtins::kCompileLazy);
14574 : return 0;
14575 : }
14576 : return kNoSourcePosition;
14577 : }
14578 :
14579 719686 : int SharedFunctionInfo::FunctionLiteralId(Isolate* isolate) const {
14580 : // Fast path for the common case when the SFI is uncompiled and so the
14581 : // function literal id is already in the uncompiled data.
14582 719686 : if (HasUncompiledData()) {
14583 1222973 : int id = uncompiled_data()->function_literal_id();
14584 : // Make sure the id is what we should have found with the slow path.
14585 : DCHECK_EQ(id, FindIndexInScript(isolate));
14586 611488 : return id;
14587 : }
14588 :
14589 : // Otherwise, search for the function in the SFI's script's function list,
14590 : // and return its index in that list.e
14591 108214 : return FindIndexInScript(isolate);
14592 : }
14593 :
14594 1137 : void SharedFunctionInfo::SetPosition(int start_position, int end_position) {
14595 1137 : Object maybe_scope_info = name_or_scope_info();
14596 1137 : if (maybe_scope_info->IsScopeInfo()) {
14597 1067 : ScopeInfo info = ScopeInfo::cast(maybe_scope_info);
14598 1067 : if (info->HasPositionInfo()) {
14599 1067 : info->SetPositionInfo(start_position, end_position);
14600 : }
14601 70 : } else if (HasUncompiledData()) {
14602 70 : if (HasUncompiledDataWithPreparseData()) {
14603 : // Clear out preparsed scope data, since the position setter invalidates
14604 : // any scope data.
14605 14 : ClearPreparseData();
14606 : }
14607 140 : uncompiled_data()->set_start_position(start_position);
14608 140 : uncompiled_data()->set_end_position(end_position);
14609 : } else {
14610 0 : UNREACHABLE();
14611 : }
14612 1137 : }
14613 :
14614 321510 : void Map::StartInobjectSlackTracking() {
14615 : DCHECK(!IsInobjectSlackTrackingInProgress());
14616 643023 : if (UnusedPropertyFields() == 0) return;
14617 227350 : set_construction_counter(Map::kSlackTrackingCounterStart);
14618 : }
14619 :
14620 390204089 : void ObjectVisitor::VisitRelocInfo(RelocIterator* it) {
14621 526686788 : for (; !it->done(); it->next()) {
14622 136713055 : it->rinfo()->Visit(this);
14623 : }
14624 126562681 : }
14625 :
14626 282 : void Code::ClearEmbeddedObjects(Heap* heap) {
14627 : HeapObject undefined = ReadOnlyRoots(heap).undefined_value();
14628 : int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
14629 4858 : for (RelocIterator it(*this, mode_mask); !it.done(); it.next()) {
14630 4576 : RelocInfo::Mode mode = it.rinfo()->rmode();
14631 4576 : if (mode == RelocInfo::EMBEDDED_OBJECT) {
14632 : it.rinfo()->set_target_object(heap, undefined, SKIP_WRITE_BARRIER);
14633 : }
14634 : }
14635 282 : set_embedded_objects_cleared(true);
14636 282 : }
14637 :
14638 :
14639 1678 : void Code::Relocate(intptr_t delta) {
14640 28999 : for (RelocIterator it(*this, RelocInfo::kApplyMask); !it.done(); it.next()) {
14641 27321 : it.rinfo()->apply(delta);
14642 : }
14643 : FlushICache();
14644 1679 : }
14645 :
14646 2200272 : void Code::FlushICache() const {
14647 2201951 : Assembler::FlushICache(raw_instruction_start(), raw_instruction_size());
14648 2200275 : }
14649 :
14650 4400544 : void Code::CopyFromNoFlush(Heap* heap, const CodeDesc& desc) {
14651 : // Copy code.
14652 : CopyBytes(reinterpret_cast<byte*>(raw_instruction_start()), desc.buffer,
14653 4400546 : static_cast<size_t>(desc.instr_size));
14654 :
14655 : // Copy unwinding info, if any.
14656 2200271 : if (desc.unwinding_info) {
14657 : DCHECK_GT(desc.unwinding_info_size, 0);
14658 28 : set_unwinding_info_size(desc.unwinding_info_size);
14659 : CopyBytes(reinterpret_cast<byte*>(unwinding_info_start()),
14660 : desc.unwinding_info,
14661 56 : static_cast<size_t>(desc.unwinding_info_size));
14662 : }
14663 :
14664 : // Copy reloc info.
14665 : CopyRelocInfoToByteArray(unchecked_relocation_info(), desc);
14666 :
14667 : // Unbox handles and relocate.
14668 2200274 : Assembler* origin = desc.origin;
14669 : AllowDeferredHandleDereference embedding_raw_address;
14670 : const int mode_mask = RelocInfo::PostCodegenRelocationMask();
14671 11818788 : for (RelocIterator it(*this, mode_mask); !it.done(); it.next()) {
14672 9618504 : RelocInfo::Mode mode = it.rinfo()->rmode();
14673 9618504 : if (mode == RelocInfo::EMBEDDED_OBJECT) {
14674 5953665 : Handle<HeapObject> p = it.rinfo()->target_object_handle(origin);
14675 : it.rinfo()->set_target_object(heap, *p, UPDATE_WRITE_BARRIER,
14676 : SKIP_ICACHE_FLUSH);
14677 3664839 : } else if (RelocInfo::IsCodeTargetMode(mode)) {
14678 : // Rewrite code handles to direct pointers to the first instruction in the
14679 : // code object.
14680 954278 : Handle<Object> p = it.rinfo()->target_object_handle(origin);
14681 : Code code = Code::cast(*p);
14682 : it.rinfo()->set_target_address(code->raw_instruction_start(),
14683 954287 : UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
14684 2710561 : } else if (RelocInfo::IsRuntimeEntry(mode)) {
14685 2702431 : Address p = it.rinfo()->target_runtime_entry(origin);
14686 : it.rinfo()->set_target_runtime_entry(p, UPDATE_WRITE_BARRIER,
14687 : SKIP_ICACHE_FLUSH);
14688 : } else {
14689 : intptr_t delta =
14690 8130 : raw_instruction_start() - reinterpret_cast<Address>(desc.buffer);
14691 8130 : it.rinfo()->apply(delta);
14692 : }
14693 : }
14694 2200280 : }
14695 :
14696 :
14697 3017306 : SafepointEntry Code::GetSafepointEntry(Address pc) {
14698 3017306 : SafepointTable table(*this);
14699 3017306 : return table.FindEntry(pc);
14700 : }
14701 :
14702 38309338 : int Code::OffHeapInstructionSize() const {
14703 : DCHECK(is_off_heap_trampoline());
14704 38309338 : if (Isolate::CurrentEmbeddedBlob() == nullptr) return raw_instruction_size();
14705 38309339 : EmbeddedData d = EmbeddedData::FromBlob();
14706 38309339 : return d.InstructionSizeOfBuiltin(builtin_index());
14707 : }
14708 :
14709 235608579 : Address Code::OffHeapInstructionStart() const {
14710 : DCHECK(is_off_heap_trampoline());
14711 235608579 : if (Isolate::CurrentEmbeddedBlob() == nullptr) return raw_instruction_start();
14712 235609642 : EmbeddedData d = EmbeddedData::FromBlob();
14713 235609642 : return d.InstructionStartOfBuiltin(builtin_index());
14714 : }
14715 :
14716 96694 : Address Code::OffHeapInstructionEnd() const {
14717 : DCHECK(is_off_heap_trampoline());
14718 96694 : if (Isolate::CurrentEmbeddedBlob() == nullptr) return raw_instruction_end();
14719 96694 : EmbeddedData d = EmbeddedData::FromBlob();
14720 193388 : return d.InstructionStartOfBuiltin(builtin_index()) +
14721 193388 : d.InstructionSizeOfBuiltin(builtin_index());
14722 : }
14723 :
14724 : namespace {
14725 : template <typename Code>
14726 10534 : void SetStackFrameCacheCommon(Isolate* isolate, Handle<Code> code,
14727 : Handle<SimpleNumberDictionary> cache) {
14728 21068 : Handle<Object> maybe_table(code->source_position_table(), isolate);
14729 21068 : if (maybe_table->IsSourcePositionTableWithFrameCache()) {
14730 2410 : Handle<SourcePositionTableWithFrameCache>::cast(maybe_table)
14731 7230 : ->set_stack_frame_cache(*cache);
14732 12944 : return;
14733 : }
14734 : DCHECK(maybe_table->IsByteArray());
14735 8124 : Handle<ByteArray> table(Handle<ByteArray>::cast(maybe_table));
14736 : Handle<SourcePositionTableWithFrameCache> table_with_cache =
14737 8124 : isolate->factory()->NewSourcePositionTableWithFrameCache(table, cache);
14738 16248 : code->set_source_position_table(*table_with_cache);
14739 : }
14740 : } // namespace
14741 :
14742 : // static
14743 10534 : void AbstractCode::SetStackFrameCache(Handle<AbstractCode> abstract_code,
14744 : Handle<SimpleNumberDictionary> cache) {
14745 21068 : if (abstract_code->IsCode()) {
14746 : SetStackFrameCacheCommon(
14747 : abstract_code->GetIsolate(),
14748 0 : handle(abstract_code->GetCode(), abstract_code->GetIsolate()), cache);
14749 : } else {
14750 : SetStackFrameCacheCommon(
14751 : abstract_code->GetIsolate(),
14752 : handle(abstract_code->GetBytecodeArray(), abstract_code->GetIsolate()),
14753 21068 : cache);
14754 : }
14755 10534 : }
14756 :
14757 : namespace {
14758 : template <typename Code>
14759 892156 : void DropStackFrameCacheCommon(Code code) {
14760 892156 : i::Object maybe_table = code->source_position_table();
14761 1784292 : if (maybe_table->IsByteArray()) return;
14762 : DCHECK(maybe_table->IsSourcePositionTableWithFrameCache());
14763 20 : code->set_source_position_table(
14764 : i::SourcePositionTableWithFrameCache::cast(maybe_table)
14765 40 : ->source_position_table());
14766 : }
14767 : } // namespace
14768 :
14769 892156 : void AbstractCode::DropStackFrameCache() {
14770 1784312 : if (IsCode()) {
14771 891701 : DropStackFrameCacheCommon(GetCode());
14772 : } else {
14773 455 : DropStackFrameCacheCommon(GetBytecodeArray());
14774 : }
14775 892156 : }
14776 :
14777 1414195 : int AbstractCode::SourcePosition(int offset) {
14778 : int position = 0;
14779 : // Subtract one because the current PC is one instruction after the call site.
14780 2828390 : if (IsCode()) offset--;
14781 38017080 : for (SourcePositionTableIterator iterator(source_position_table());
14782 36602885 : !iterator.done() && iterator.code_offset() <= offset;
14783 35188690 : iterator.Advance()) {
14784 35188690 : position = iterator.source_position().ScriptOffset();
14785 : }
14786 1414195 : return position;
14787 : }
14788 :
14789 107756 : int AbstractCode::SourceStatementPosition(int offset) {
14790 : // First find the closest position.
14791 107756 : int position = SourcePosition(offset);
14792 : // Now find the closest statement position before the position.
14793 : int statement_position = 0;
14794 11291536 : for (SourcePositionTableIterator it(source_position_table()); !it.done();
14795 11076024 : it.Advance()) {
14796 11076024 : if (it.is_statement()) {
14797 7018666 : int p = it.source_position().ScriptOffset();
14798 7018666 : if (statement_position < p && p <= position) {
14799 : statement_position = p;
14800 : }
14801 : }
14802 : }
14803 107756 : return statement_position;
14804 : }
14805 :
14806 52310 : void JSFunction::ClearTypeFeedbackInfo() {
14807 52310 : ResetIfBytecodeFlushed();
14808 52310 : if (has_feedback_vector()) {
14809 52288 : FeedbackVector vector = feedback_vector();
14810 : Isolate* isolate = GetIsolate();
14811 52288 : if (vector->ClearSlots(isolate)) {
14812 : IC::OnFeedbackChanged(isolate, vector, FeedbackSlot::Invalid(), *this,
14813 27472 : "ClearTypeFeedbackInfo");
14814 : }
14815 : }
14816 52310 : }
14817 :
14818 300 : void Code::PrintDeoptLocation(FILE* out, const char* str, Address pc) {
14819 300 : Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(*this, pc);
14820 300 : class SourcePosition pos = info.position;
14821 300 : if (info.deopt_reason != DeoptimizeReason::kUnknown || pos.IsKnown()) {
14822 300 : PrintF(out, "%s", str);
14823 300 : OFStream outstr(out);
14824 300 : pos.Print(outstr, *this);
14825 300 : PrintF(out, ", %s\n", DeoptimizeReasonToString(info.deopt_reason));
14826 : }
14827 300 : }
14828 :
14829 :
14830 9895 : bool Code::CanDeoptAt(Address pc) {
14831 : DeoptimizationData deopt_data =
14832 19790 : DeoptimizationData::cast(deoptimization_data());
14833 9895 : Address code_start_address = InstructionStart();
14834 92656 : for (int i = 0; i < deopt_data->DeoptCount(); i++) {
14835 182314 : if (deopt_data->Pc(i)->value() == -1) continue;
14836 119380 : Address address = code_start_address + deopt_data->Pc(i)->value();
14837 68086 : if (address == pc && deopt_data->BytecodeOffset(i) != BailoutId::None()) {
14838 : return true;
14839 : }
14840 : }
14841 : return false;
14842 : }
14843 :
14844 :
14845 : // Identify kind of code.
14846 20120 : const char* Code::Kind2String(Kind kind) {
14847 20120 : switch (kind) {
14848 : #define CASE(name) case name: return #name;
14849 0 : CODE_KIND_LIST(CASE)
14850 : #undef CASE
14851 : case NUMBER_OF_KINDS: break;
14852 : }
14853 0 : UNREACHABLE();
14854 : }
14855 :
14856 : // Identify kind of code.
14857 0 : const char* AbstractCode::Kind2String(Kind kind) {
14858 0 : if (kind < AbstractCode::INTERPRETED_FUNCTION)
14859 0 : return Code::Kind2String(static_cast<Code::Kind>(kind));
14860 0 : if (kind == AbstractCode::INTERPRETED_FUNCTION) return "INTERPRETED_FUNCTION";
14861 0 : UNREACHABLE();
14862 : }
14863 :
14864 84616 : bool Code::IsIsolateIndependent(Isolate* isolate) {
14865 : constexpr int all_real_modes_mask =
14866 : (1 << (RelocInfo::LAST_REAL_RELOC_MODE + 1)) - 1;
14867 : constexpr int mode_mask = all_real_modes_mask &
14868 : ~RelocInfo::ModeMask(RelocInfo::CONST_POOL) &
14869 : ~RelocInfo::ModeMask(RelocInfo::OFF_HEAP_TARGET) &
14870 : ~RelocInfo::ModeMask(RelocInfo::VENEER_POOL);
14871 : STATIC_ASSERT(RelocInfo::LAST_REAL_RELOC_MODE == RelocInfo::VENEER_POOL);
14872 : STATIC_ASSERT(mode_mask ==
14873 : (RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
14874 : RelocInfo::ModeMask(RelocInfo::RELATIVE_CODE_TARGET) |
14875 : RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
14876 : RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
14877 : RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
14878 : RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) |
14879 : RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
14880 : RelocInfo::ModeMask(RelocInfo::WASM_CALL) |
14881 : RelocInfo::ModeMask(RelocInfo::WASM_STUB_CALL)));
14882 :
14883 : bool is_process_independent = true;
14884 500024 : for (RelocIterator it(*this, mode_mask); !it.done(); it.next()) {
14885 : #if defined(V8_TARGET_ARCH_X64) || defined(V8_TARGET_ARCH_ARM64) || \
14886 : defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_MIPS) || \
14887 : defined(V8_TARGET_ARCH_S390) || defined(V8_TARGET_ARCH_IA32)
14888 : // On these platforms we emit relative builtin-to-builtin
14889 : // jumps for isolate independent builtins in the snapshot. They are later
14890 : // rewritten as pc-relative jumps to the off-heap instruction stream and are
14891 : // thus process-independent. See also: FinalizeEmbeddedCodeTargets.
14892 415408 : if (RelocInfo::IsCodeTargetMode(it.rinfo()->rmode())) {
14893 415408 : Address target_address = it.rinfo()->target_address();
14894 830816 : if (InstructionStream::PcIsOffHeap(isolate, target_address)) continue;
14895 :
14896 415408 : Code target = Code::GetCodeFromTargetAddress(target_address);
14897 415408 : CHECK(target->IsCode());
14898 415408 : if (Builtins::IsIsolateIndependentBuiltin(target)) continue;
14899 : }
14900 : #endif
14901 : is_process_independent = false;
14902 : }
14903 :
14904 84616 : return is_process_independent;
14905 : }
14906 :
14907 16913 : bool Code::Inlines(SharedFunctionInfo sfi) {
14908 : // We can only check for inlining for optimized code.
14909 : DCHECK(is_optimized_code());
14910 : DisallowHeapAllocation no_gc;
14911 : DeoptimizationData const data =
14912 33826 : DeoptimizationData::cast(deoptimization_data());
14913 16913 : if (data->length() == 0) return false;
14914 33826 : if (data->SharedFunctionInfo() == sfi) return true;
14915 16619 : FixedArray const literals = data->LiteralArray();
14916 33238 : int const inlined_count = data->InlinedFunctionCount()->value();
14917 16710 : for (int i = 0; i < inlined_count; ++i) {
14918 134 : if (SharedFunctionInfo::cast(literals->get(i)) == sfi) return true;
14919 : }
14920 : return false;
14921 : }
14922 :
14923 12357 : Code::OptimizedCodeIterator::OptimizedCodeIterator(Isolate* isolate) {
14924 12357 : isolate_ = isolate;
14925 12357 : Object list = isolate->heap()->native_contexts_list();
14926 24714 : next_context_ = list->IsUndefined(isolate_) ? Context() : Context::cast(list);
14927 12357 : }
14928 :
14929 29270 : Code Code::OptimizedCodeIterator::Next() {
14930 30020 : do {
14931 42377 : Object next;
14932 42377 : if (!current_code_.is_null()) {
14933 : // Get next code in the linked list.
14934 33826 : next = current_code_->next_code_link();
14935 25464 : } else if (!next_context_.is_null()) {
14936 : // Linked list of code exhausted. Get list of next context.
14937 13107 : next = next_context_->OptimizedCodeListHead();
14938 13107 : Object next_context = next_context_->next_context_link();
14939 13107 : next_context_ = next_context->IsUndefined(isolate_)
14940 : ? Context()
14941 13857 : : Context::cast(next_context);
14942 : } else {
14943 : // Exhausted contexts.
14944 12357 : return Code();
14945 : }
14946 76953 : current_code_ = next->IsUndefined(isolate_) ? Code() : Code::cast(next);
14947 : } while (current_code_.is_null());
14948 : DCHECK_EQ(Code::OPTIMIZED_FUNCTION, current_code_->kind());
14949 16913 : return current_code_;
14950 : }
14951 :
14952 : #ifdef ENABLE_DISASSEMBLER
14953 :
14954 : namespace {
14955 : void print_pc(std::ostream& os, int pc) {
14956 : if (pc == -1) {
14957 : os << "NA";
14958 : } else {
14959 : os << std::hex << pc << std::dec;
14960 : }
14961 : }
14962 : } // anonymous namespace
14963 :
14964 : void DeoptimizationData::DeoptimizationDataPrint(std::ostream& os) { // NOLINT
14965 : if (length() == 0) {
14966 : os << "Deoptimization Input Data invalidated by lazy deoptimization\n";
14967 : return;
14968 : }
14969 :
14970 : disasm::NameConverter converter;
14971 : int const inlined_function_count = InlinedFunctionCount()->value();
14972 : os << "Inlined functions (count = " << inlined_function_count << ")\n";
14973 : for (int id = 0; id < inlined_function_count; ++id) {
14974 : Object info = LiteralArray()->get(id);
14975 : os << " " << Brief(SharedFunctionInfo::cast(info)) << "\n";
14976 : }
14977 : os << "\n";
14978 : int deopt_count = DeoptCount();
14979 : os << "Deoptimization Input Data (deopt points = " << deopt_count << ")\n";
14980 : if (0 != deopt_count) {
14981 : os << " index bytecode-offset pc";
14982 : if (FLAG_print_code_verbose) os << " commands";
14983 : os << "\n";
14984 : }
14985 : for (int i = 0; i < deopt_count; i++) {
14986 : os << std::setw(6) << i << " " << std::setw(15)
14987 : << BytecodeOffset(i).ToInt() << " " << std::setw(4);
14988 : print_pc(os, Pc(i)->value());
14989 : os << std::setw(2);
14990 :
14991 : if (!FLAG_print_code_verbose) {
14992 : os << "\n";
14993 : continue;
14994 : }
14995 :
14996 : // Print details of the frame translation.
14997 : int translation_index = TranslationIndex(i)->value();
14998 : TranslationIterator iterator(TranslationByteArray(), translation_index);
14999 : Translation::Opcode opcode =
15000 : static_cast<Translation::Opcode>(iterator.Next());
15001 : DCHECK(Translation::BEGIN == opcode);
15002 : int frame_count = iterator.Next();
15003 : int jsframe_count = iterator.Next();
15004 : int update_feedback_count = iterator.Next();
15005 : os << " " << Translation::StringFor(opcode)
15006 : << " {frame count=" << frame_count
15007 : << ", js frame count=" << jsframe_count
15008 : << ", update_feedback_count=" << update_feedback_count << "}\n";
15009 :
15010 : while (iterator.HasNext() &&
15011 : Translation::BEGIN !=
15012 : (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
15013 : os << std::setw(31) << " " << Translation::StringFor(opcode) << " ";
15014 :
15015 : switch (opcode) {
15016 : case Translation::BEGIN:
15017 : UNREACHABLE();
15018 : break;
15019 :
15020 : case Translation::INTERPRETED_FRAME: {
15021 : int bytecode_offset = iterator.Next();
15022 : int shared_info_id = iterator.Next();
15023 : unsigned height = iterator.Next();
15024 : int return_value_offset = iterator.Next();
15025 : int return_value_count = iterator.Next();
15026 : Object shared_info = LiteralArray()->get(shared_info_id);
15027 : os << "{bytecode_offset=" << bytecode_offset << ", function="
15028 : << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
15029 : << ", height=" << height << ", retval=@" << return_value_offset
15030 : << "(#" << return_value_count << ")}";
15031 : break;
15032 : }
15033 :
15034 : case Translation::CONSTRUCT_STUB_FRAME: {
15035 : int bailout_id = iterator.Next();
15036 : int shared_info_id = iterator.Next();
15037 : Object shared_info = LiteralArray()->get(shared_info_id);
15038 : unsigned height = iterator.Next();
15039 : os << "{bailout_id=" << bailout_id << ", function="
15040 : << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
15041 : << ", height=" << height << "}";
15042 : break;
15043 : }
15044 :
15045 : case Translation::BUILTIN_CONTINUATION_FRAME:
15046 : case Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME:
15047 : case Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME: {
15048 : int bailout_id = iterator.Next();
15049 : int shared_info_id = iterator.Next();
15050 : Object shared_info = LiteralArray()->get(shared_info_id);
15051 : unsigned height = iterator.Next();
15052 : os << "{bailout_id=" << bailout_id << ", function="
15053 : << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
15054 : << ", height=" << height << "}";
15055 : break;
15056 : }
15057 :
15058 : case Translation::ARGUMENTS_ADAPTOR_FRAME: {
15059 : int shared_info_id = iterator.Next();
15060 : Object shared_info = LiteralArray()->get(shared_info_id);
15061 : unsigned height = iterator.Next();
15062 : os << "{function="
15063 : << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
15064 : << ", height=" << height << "}";
15065 : break;
15066 : }
15067 :
15068 : case Translation::REGISTER: {
15069 : int reg_code = iterator.Next();
15070 : os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
15071 : break;
15072 : }
15073 :
15074 : case Translation::INT32_REGISTER: {
15075 : int reg_code = iterator.Next();
15076 : os << "{input=" << converter.NameOfCPURegister(reg_code)
15077 : << " (int32)}";
15078 : break;
15079 : }
15080 :
15081 : case Translation::INT64_REGISTER: {
15082 : int reg_code = iterator.Next();
15083 : os << "{input=" << converter.NameOfCPURegister(reg_code)
15084 : << " (int64)}";
15085 : break;
15086 : }
15087 :
15088 : case Translation::UINT32_REGISTER: {
15089 : int reg_code = iterator.Next();
15090 : os << "{input=" << converter.NameOfCPURegister(reg_code)
15091 : << " (uint32)}";
15092 : break;
15093 : }
15094 :
15095 : case Translation::BOOL_REGISTER: {
15096 : int reg_code = iterator.Next();
15097 : os << "{input=" << converter.NameOfCPURegister(reg_code)
15098 : << " (bool)}";
15099 : break;
15100 : }
15101 :
15102 : case Translation::FLOAT_REGISTER: {
15103 : int reg_code = iterator.Next();
15104 : os << "{input=" << FloatRegister::from_code(reg_code) << "}";
15105 : break;
15106 : }
15107 :
15108 : case Translation::DOUBLE_REGISTER: {
15109 : int reg_code = iterator.Next();
15110 : os << "{input=" << DoubleRegister::from_code(reg_code) << "}";
15111 : break;
15112 : }
15113 :
15114 : case Translation::STACK_SLOT: {
15115 : int input_slot_index = iterator.Next();
15116 : os << "{input=" << input_slot_index << "}";
15117 : break;
15118 : }
15119 :
15120 : case Translation::INT32_STACK_SLOT: {
15121 : int input_slot_index = iterator.Next();
15122 : os << "{input=" << input_slot_index << " (int32)}";
15123 : break;
15124 : }
15125 :
15126 : case Translation::INT64_STACK_SLOT: {
15127 : int input_slot_index = iterator.Next();
15128 : os << "{input=" << input_slot_index << " (int64)}";
15129 : break;
15130 : }
15131 :
15132 : case Translation::UINT32_STACK_SLOT: {
15133 : int input_slot_index = iterator.Next();
15134 : os << "{input=" << input_slot_index << " (uint32)}";
15135 : break;
15136 : }
15137 :
15138 : case Translation::BOOL_STACK_SLOT: {
15139 : int input_slot_index = iterator.Next();
15140 : os << "{input=" << input_slot_index << " (bool)}";
15141 : break;
15142 : }
15143 :
15144 : case Translation::FLOAT_STACK_SLOT:
15145 : case Translation::DOUBLE_STACK_SLOT: {
15146 : int input_slot_index = iterator.Next();
15147 : os << "{input=" << input_slot_index << "}";
15148 : break;
15149 : }
15150 :
15151 : case Translation::LITERAL: {
15152 : int literal_index = iterator.Next();
15153 : Object literal_value = LiteralArray()->get(literal_index);
15154 : os << "{literal_id=" << literal_index << " (" << Brief(literal_value)
15155 : << ")}";
15156 : break;
15157 : }
15158 :
15159 : case Translation::DUPLICATED_OBJECT: {
15160 : int object_index = iterator.Next();
15161 : os << "{object_index=" << object_index << "}";
15162 : break;
15163 : }
15164 :
15165 : case Translation::ARGUMENTS_ELEMENTS:
15166 : case Translation::ARGUMENTS_LENGTH: {
15167 : CreateArgumentsType arguments_type =
15168 : static_cast<CreateArgumentsType>(iterator.Next());
15169 : os << "{arguments_type=" << arguments_type << "}";
15170 : break;
15171 : }
15172 :
15173 : case Translation::CAPTURED_OBJECT: {
15174 : int args_length = iterator.Next();
15175 : os << "{length=" << args_length << "}";
15176 : break;
15177 : }
15178 :
15179 : case Translation::UPDATE_FEEDBACK: {
15180 : int literal_index = iterator.Next();
15181 : FeedbackSlot slot(iterator.Next());
15182 : os << "{feedback={vector_index=" << literal_index << ", slot=" << slot
15183 : << "}}";
15184 : break;
15185 : }
15186 : }
15187 : os << "\n";
15188 : }
15189 : }
15190 : }
15191 :
15192 : const char* Code::GetName(Isolate* isolate) const {
15193 : if (kind() == BYTECODE_HANDLER) {
15194 : return isolate->interpreter()->LookupNameOfBytecodeHandler(*this);
15195 : } else {
15196 : // There are some handlers and ICs that we can also find names for with
15197 : // Builtins::Lookup.
15198 : return isolate->builtins()->Lookup(raw_instruction_start());
15199 : }
15200 : }
15201 :
15202 : namespace {
15203 :
15204 : inline void DisassembleCodeRange(Isolate* isolate, std::ostream& os, Code code,
15205 : Address begin, size_t size,
15206 : Address current_pc) {
15207 : Address end = begin + size;
15208 : // TODO(mstarzinger): Refactor CodeReference to avoid the
15209 : // unhandlified->handlified transition.
15210 : AllowHandleAllocation allow_handles;
15211 : DisallowHeapAllocation no_gc;
15212 : HandleScope handle_scope(isolate);
15213 : Disassembler::Decode(isolate, &os, reinterpret_cast<byte*>(begin),
15214 : reinterpret_cast<byte*>(end),
15215 : CodeReference(handle(code, isolate)), current_pc);
15216 : }
15217 :
15218 : } // namespace
15219 :
15220 : void Code::Disassemble(const char* name, std::ostream& os, Address current_pc) {
15221 : Isolate* isolate = GetIsolate();
15222 : os << "kind = " << Kind2String(kind()) << "\n";
15223 : if (name == nullptr) {
15224 : name = GetName(isolate);
15225 : }
15226 : if ((name != nullptr) && (name[0] != '\0')) {
15227 : os << "name = " << name << "\n";
15228 : }
15229 : if (kind() == OPTIMIZED_FUNCTION) {
15230 : os << "stack_slots = " << stack_slots() << "\n";
15231 : }
15232 : os << "compiler = " << (is_turbofanned() ? "turbofan" : "unknown") << "\n";
15233 : os << "address = " << static_cast<const void*>(this) << "\n\n";
15234 :
15235 : if (is_off_heap_trampoline()) {
15236 : int trampoline_size = raw_instruction_size();
15237 : os << "Trampoline (size = " << trampoline_size << ")\n";
15238 : DisassembleCodeRange(isolate, os, *this, raw_instruction_start(),
15239 : trampoline_size, current_pc);
15240 : os << "\n";
15241 : }
15242 :
15243 : {
15244 : int size = InstructionSize();
15245 : int safepoint_offset =
15246 : has_safepoint_info() ? safepoint_table_offset() : size;
15247 : int const_pool_offset = constant_pool_offset();
15248 : int handler_offset = handler_table_offset() ? handler_table_offset() : size;
15249 : int comments_offset = code_comments_offset();
15250 :
15251 : // Stop before reaching any embedded tables
15252 : int code_size = std::min(
15253 : {handler_offset, safepoint_offset, const_pool_offset, comments_offset});
15254 : os << "Instructions (size = " << code_size << ")\n";
15255 : DisassembleCodeRange(isolate, os, *this, InstructionStart(), code_size,
15256 : current_pc);
15257 :
15258 : if (int pool_size = constant_pool_size()) {
15259 : DCHECK_EQ(pool_size & kPointerAlignmentMask, 0);
15260 : os << "\nConstant Pool (size = " << pool_size << ")\n";
15261 : Vector<char> buf = Vector<char>::New(50);
15262 : intptr_t* ptr =
15263 : reinterpret_cast<intptr_t*>(InstructionStart() + const_pool_offset);
15264 : for (int i = 0; i < pool_size; i += kSystemPointerSize, ptr++) {
15265 : SNPrintF(buf, "%4d %08" V8PRIxPTR, i, *ptr);
15266 : os << static_cast<const void*>(ptr) << " " << buf.start() << "\n";
15267 : }
15268 : }
15269 : }
15270 : os << "\n";
15271 :
15272 : SourcePositionTableIterator it(SourcePositionTable());
15273 : if (!it.done()) {
15274 : os << "Source positions:\n pc offset position\n";
15275 : for (; !it.done(); it.Advance()) {
15276 : os << std::setw(10) << std::hex << it.code_offset() << std::dec
15277 : << std::setw(10) << it.source_position().ScriptOffset()
15278 : << (it.is_statement() ? " statement" : "") << "\n";
15279 : }
15280 : os << "\n";
15281 : }
15282 :
15283 : if (kind() == OPTIMIZED_FUNCTION) {
15284 : DeoptimizationData data =
15285 : DeoptimizationData::cast(this->deoptimization_data());
15286 : data->DeoptimizationDataPrint(os);
15287 : }
15288 : os << "\n";
15289 :
15290 : if (has_safepoint_info()) {
15291 : SafepointTable table(*this);
15292 : os << "Safepoints (size = " << table.size() << ")\n";
15293 : for (unsigned i = 0; i < table.length(); i++) {
15294 : unsigned pc_offset = table.GetPcOffset(i);
15295 : os << reinterpret_cast<const void*>(InstructionStart() + pc_offset)
15296 : << " ";
15297 : os << std::setw(6) << std::hex << pc_offset << " " << std::setw(4);
15298 : int trampoline_pc = table.GetTrampolinePcOffset(i);
15299 : print_pc(os, trampoline_pc);
15300 : os << std::dec << " ";
15301 : table.PrintEntry(i, os);
15302 : os << " (sp -> fp) ";
15303 : SafepointEntry entry = table.GetEntry(i);
15304 : if (entry.has_deoptimization_index()) {
15305 : os << std::setw(6) << entry.deoptimization_index();
15306 : } else {
15307 : os << "<none>";
15308 : }
15309 : if (entry.has_argument_count()) {
15310 : os << " argc: " << entry.argument_count();
15311 : }
15312 : os << "\n";
15313 : }
15314 : os << "\n";
15315 : }
15316 :
15317 : if (handler_table_offset() > 0) {
15318 : HandlerTable table(*this);
15319 : os << "Handler Table (size = " << table.NumberOfReturnEntries() << ")\n";
15320 : if (kind() == OPTIMIZED_FUNCTION) {
15321 : table.HandlerTableReturnPrint(os);
15322 : }
15323 : os << "\n";
15324 : }
15325 :
15326 : os << "RelocInfo (size = " << relocation_size() << ")\n";
15327 : for (RelocIterator it(*this); !it.done(); it.next()) {
15328 : it.rinfo()->Print(isolate, os);
15329 : }
15330 : os << "\n";
15331 :
15332 : if (has_unwinding_info()) {
15333 : os << "UnwindingInfo (size = " << unwinding_info_size() << ")\n";
15334 : EhFrameDisassembler eh_frame_disassembler(
15335 : reinterpret_cast<byte*>(unwinding_info_start()),
15336 : reinterpret_cast<byte*>(unwinding_info_end()));
15337 : eh_frame_disassembler.DisassembleToStream(os);
15338 : os << "\n";
15339 : }
15340 :
15341 : if (code_comments_offset() < InstructionSize()) {
15342 : PrintCodeCommentsSection(os, code_comments());
15343 : }
15344 : }
15345 : #endif // ENABLE_DISASSEMBLER
15346 :
15347 0 : void BytecodeArray::Disassemble(std::ostream& os) {
15348 : DisallowHeapAllocation no_gc;
15349 :
15350 0 : os << "Parameter count " << parameter_count() << "\n";
15351 0 : os << "Frame size " << frame_size() << "\n";
15352 :
15353 : Address base_address = GetFirstBytecodeAddress();
15354 0 : SourcePositionTableIterator source_positions(SourcePositionTable());
15355 :
15356 : // Storage for backing the handle passed to the iterator. This handle won't be
15357 : // updated by the gc, but that's ok because we've disallowed GCs anyway.
15358 0 : BytecodeArray handle_storage = *this;
15359 : Handle<BytecodeArray> handle(reinterpret_cast<Address*>(&handle_storage));
15360 0 : interpreter::BytecodeArrayIterator iterator(handle);
15361 0 : while (!iterator.done()) {
15362 0 : if (!source_positions.done() &&
15363 0 : iterator.current_offset() == source_positions.code_offset()) {
15364 0 : os << std::setw(5) << source_positions.source_position().ScriptOffset();
15365 0 : os << (source_positions.is_statement() ? " S> " : " E> ");
15366 0 : source_positions.Advance();
15367 : } else {
15368 0 : os << " ";
15369 : }
15370 0 : Address current_address = base_address + iterator.current_offset();
15371 0 : os << reinterpret_cast<const void*>(current_address) << " @ "
15372 0 : << std::setw(4) << iterator.current_offset() << " : ";
15373 : interpreter::BytecodeDecoder::Decode(
15374 0 : os, reinterpret_cast<byte*>(current_address), parameter_count());
15375 0 : if (interpreter::Bytecodes::IsJump(iterator.current_bytecode())) {
15376 0 : Address jump_target = base_address + iterator.GetJumpTargetOffset();
15377 0 : os << " (" << reinterpret_cast<void*>(jump_target) << " @ "
15378 0 : << iterator.GetJumpTargetOffset() << ")";
15379 : }
15380 0 : if (interpreter::Bytecodes::IsSwitch(iterator.current_bytecode())) {
15381 0 : os << " {";
15382 : bool first_entry = true;
15383 0 : for (const auto& entry : iterator.GetJumpTableTargetOffsets()) {
15384 0 : if (first_entry) {
15385 : first_entry = false;
15386 : } else {
15387 0 : os << ",";
15388 : }
15389 0 : os << " " << entry.case_value << ": @" << entry.target_offset;
15390 : }
15391 0 : os << " }";
15392 : }
15393 : os << std::endl;
15394 0 : iterator.Advance();
15395 : }
15396 :
15397 0 : os << "Constant pool (size = " << constant_pool()->length() << ")\n";
15398 : #ifdef OBJECT_PRINT
15399 : if (constant_pool()->length() > 0) {
15400 : constant_pool()->Print();
15401 : }
15402 : #endif
15403 :
15404 0 : os << "Handler Table (size = " << handler_table()->length() << ")\n";
15405 : #ifdef ENABLE_DISASSEMBLER
15406 : if (handler_table()->length() > 0) {
15407 : HandlerTable table(*this);
15408 : table.HandlerTableRangePrint(os);
15409 : }
15410 : #endif
15411 0 : }
15412 :
15413 10538 : void BytecodeArray::CopyBytecodesTo(BytecodeArray to) {
15414 10538 : BytecodeArray from = *this;
15415 : DCHECK_EQ(from->length(), to->length());
15416 : CopyBytes(reinterpret_cast<byte*>(to->GetFirstBytecodeAddress()),
15417 : reinterpret_cast<byte*>(from->GetFirstBytecodeAddress()),
15418 31614 : from->length());
15419 10538 : }
15420 :
15421 5049369 : void BytecodeArray::MakeOlder() {
15422 : // BytecodeArray is aged in concurrent marker.
15423 : // The word must be completely within the byte code array.
15424 5049369 : Address age_addr = address() + kBytecodeAgeOffset;
15425 : DCHECK_LE(RoundDown(age_addr, kSystemPointerSize) + kSystemPointerSize,
15426 : address() + Size());
15427 : Age age = bytecode_age();
15428 5049369 : if (age < kLastBytecodeAge) {
15429 : base::AsAtomic8::Release_CompareAndSwap(reinterpret_cast<byte*>(age_addr),
15430 1365231 : age, age + 1);
15431 : }
15432 :
15433 : DCHECK_GE(bytecode_age(), kFirstBytecodeAge);
15434 : DCHECK_LE(bytecode_age(), kLastBytecodeAge);
15435 5049369 : }
15436 :
15437 119 : bool BytecodeArray::IsOld() const {
15438 119 : return bytecode_age() >= kIsOldBytecodeAge;
15439 : }
15440 :
15441 : // static
15442 156414 : void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
15443 : DCHECK_GE(capacity, 0);
15444 : array->GetIsolate()->factory()->NewJSArrayStorage(
15445 156432 : array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
15446 156439 : }
15447 :
15448 924647 : void JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) {
15449 : // We should never end in here with a pixel or external array.
15450 : DCHECK(array->AllowsSetLength());
15451 924647 : if (array->SetLengthWouldNormalize(new_length)) {
15452 437 : JSObject::NormalizeElements(array);
15453 : }
15454 1849294 : array->GetElementsAccessor()->SetLength(array, new_length);
15455 924647 : }
15456 :
15457 867737 : DependentCode DependentCode::GetDependentCode(Handle<HeapObject> object) {
15458 1735474 : if (object->IsMap()) {
15459 474828 : return Handle<Map>::cast(object)->dependent_code();
15460 1260646 : } else if (object->IsPropertyCell()) {
15461 1239496 : return Handle<PropertyCell>::cast(object)->dependent_code();
15462 21150 : } else if (object->IsAllocationSite()) {
15463 21150 : return Handle<AllocationSite>::cast(object)->dependent_code();
15464 : }
15465 0 : UNREACHABLE();
15466 : }
15467 :
15468 315953 : void DependentCode::SetDependentCode(Handle<HeapObject> object,
15469 : Handle<DependentCode> dep) {
15470 631905 : if (object->IsMap()) {
15471 211208 : Handle<Map>::cast(object)->set_dependent_code(*dep);
15472 420696 : } else if (object->IsPropertyCell()) {
15473 400992 : Handle<PropertyCell>::cast(object)->set_dependent_code(*dep);
15474 19704 : } else if (object->IsAllocationSite()) {
15475 19704 : Handle<AllocationSite>::cast(object)->set_dependent_code(*dep);
15476 : } else {
15477 0 : UNREACHABLE();
15478 : }
15479 315953 : }
15480 :
15481 867737 : void DependentCode::InstallDependency(Isolate* isolate,
15482 : const MaybeObjectHandle& code,
15483 : Handle<HeapObject> object,
15484 : DependencyGroup group) {
15485 : Handle<DependentCode> old_deps(DependentCode::GetDependentCode(object),
15486 867737 : isolate);
15487 : Handle<DependentCode> new_deps =
15488 867737 : InsertWeakCode(isolate, old_deps, group, code);
15489 : // Update the list head if necessary.
15490 867736 : if (!new_deps.is_identical_to(old_deps))
15491 315953 : DependentCode::SetDependentCode(object, new_deps);
15492 867736 : }
15493 :
15494 868246 : Handle<DependentCode> DependentCode::InsertWeakCode(
15495 : Isolate* isolate, Handle<DependentCode> entries, DependencyGroup group,
15496 : const MaybeObjectHandle& code) {
15497 2171334 : if (entries->length() == 0 || entries->group() > group) {
15498 : // There is no such group.
15499 219402 : return DependentCode::New(isolate, group, code, entries);
15500 : }
15501 1297688 : if (entries->group() < group) {
15502 : // The group comes later in the list.
15503 1018 : Handle<DependentCode> old_next(entries->next_link(), isolate);
15504 : Handle<DependentCode> new_next =
15505 509 : InsertWeakCode(isolate, old_next, group, code);
15506 509 : if (!old_next.is_identical_to(new_next)) {
15507 604 : entries->set_next_link(*new_next);
15508 : }
15509 509 : return entries;
15510 : }
15511 : DCHECK_EQ(group, entries->group());
15512 1296670 : int count = entries->count();
15513 : // Check for existing entry to avoid duplicates.
15514 83580721 : for (int i = 0; i < count; i++) {
15515 249839481 : if (entries->object_at(i) == *code) return entries;
15516 : }
15517 601788 : if (entries->length() < kCodesStartIndex + count + 1) {
15518 100400 : entries = EnsureSpace(isolate, entries);
15519 : // Count could have changed, reload it.
15520 200800 : count = entries->count();
15521 : }
15522 902681 : entries->set_object_at(count, *code);
15523 601787 : entries->set_count(count + 1);
15524 300894 : return entries;
15525 : }
15526 :
15527 219402 : Handle<DependentCode> DependentCode::New(Isolate* isolate,
15528 : DependencyGroup group,
15529 : const MaybeObjectHandle& object,
15530 : Handle<DependentCode> next) {
15531 : Handle<DependentCode> result = Handle<DependentCode>::cast(
15532 219402 : isolate->factory()->NewWeakFixedArray(kCodesStartIndex + 1, TENURED));
15533 438804 : result->set_next_link(*next);
15534 658206 : result->set_flags(GroupField::encode(group) | CountField::encode(1));
15535 658206 : result->set_object_at(0, *object);
15536 219402 : return result;
15537 : }
15538 :
15539 100399 : Handle<DependentCode> DependentCode::EnsureSpace(
15540 : Isolate* isolate, Handle<DependentCode> entries) {
15541 100400 : if (entries->Compact()) return entries;
15542 193704 : int capacity = kCodesStartIndex + DependentCode::Grow(entries->count());
15543 96853 : int grow_by = capacity - entries->length();
15544 : return Handle<DependentCode>::cast(
15545 96853 : isolate->factory()->CopyWeakFixedArrayAndGrow(entries, grow_by, TENURED));
15546 : }
15547 :
15548 :
15549 100400 : bool DependentCode::Compact() {
15550 : int old_count = count();
15551 : int new_count = 0;
15552 1172923 : for (int i = 0; i < old_count; i++) {
15553 : MaybeObject obj = object_at(i);
15554 1072523 : if (!obj->IsCleared()) {
15555 1022491 : if (i != new_count) {
15556 12396 : copy(i, new_count);
15557 : }
15558 1022491 : new_count++;
15559 : }
15560 : }
15561 100400 : set_count(new_count);
15562 150431 : for (int i = new_count; i < old_count; i++) {
15563 50032 : clear_at(i);
15564 : }
15565 100399 : return new_count < old_count;
15566 : }
15567 :
15568 20025014 : bool DependentCode::MarkCodeForDeoptimization(
15569 : Isolate* isolate,
15570 : DependentCode::DependencyGroup group) {
15571 20029882 : if (this->length() == 0 || this->group() > group) {
15572 : // There is no such group.
15573 : return false;
15574 : }
15575 4588 : if (this->group() < group) {
15576 : // The group comes later in the list.
15577 170 : return next_link()->MarkCodeForDeoptimization(isolate, group);
15578 : }
15579 : DCHECK_EQ(group, this->group());
15580 : DisallowHeapAllocation no_allocation_scope;
15581 : // Mark all the code that needs to be deoptimized.
15582 : bool marked = false;
15583 : int count = this->count();
15584 12489 : for (int i = 0; i < count; i++) {
15585 8071 : MaybeObject obj = object_at(i);
15586 8095 : if (obj->IsCleared()) continue;
15587 8047 : Code code = Code::cast(obj->GetHeapObjectAssumeWeak());
15588 8047 : if (!code->marked_for_deoptimization()) {
15589 4998 : code->SetMarkedForDeoptimization(DependencyGroupName(group));
15590 : marked = true;
15591 : }
15592 : }
15593 8071 : for (int i = 0; i < count; i++) {
15594 8071 : clear_at(i);
15595 : }
15596 4418 : set_count(0);
15597 4418 : return marked;
15598 : }
15599 :
15600 :
15601 20024788 : void DependentCode::DeoptimizeDependentCodeGroup(
15602 : Isolate* isolate,
15603 : DependentCode::DependencyGroup group) {
15604 : DisallowHeapAllocation no_allocation_scope;
15605 20024788 : bool marked = MarkCodeForDeoptimization(isolate, group);
15606 20024789 : if (marked) {
15607 : DCHECK(AllowCodeDependencyChange::IsAllowed());
15608 2387 : Deoptimizer::DeoptimizeMarkedCode(isolate);
15609 : }
15610 20024789 : }
15611 :
15612 5062 : void Code::SetMarkedForDeoptimization(const char* reason) {
15613 5062 : set_marked_for_deoptimization(true);
15614 15186 : if (FLAG_trace_deopt &&
15615 5068 : (deoptimization_data() != GetReadOnlyRoots().empty_fixed_array())) {
15616 : DeoptimizationData deopt_data =
15617 4 : DeoptimizationData::cast(deoptimization_data());
15618 2 : CodeTracer::Scope scope(GetHeap()->isolate()->GetCodeTracer());
15619 : PrintF(scope.file(),
15620 : "[marking dependent code " V8PRIxPTR_FMT
15621 : " (opt #%d) for deoptimization, reason: %s]\n",
15622 4 : ptr(), deopt_data->OptimizationId()->value(), reason);
15623 : }
15624 5062 : }
15625 :
15626 :
15627 4998 : const char* DependentCode::DependencyGroupName(DependencyGroup group) {
15628 4998 : switch (group) {
15629 : case kTransitionGroup:
15630 : return "transition";
15631 : case kPrototypeCheckGroup:
15632 1081 : return "prototype-check";
15633 : case kPropertyCellChangedGroup:
15634 3701 : return "property-cell-changed";
15635 : case kFieldOwnerGroup:
15636 83 : return "field-owner";
15637 : case kInitialMapChangedGroup:
15638 104 : return "initial-map-changed";
15639 : case kAllocationSiteTenuringChangedGroup:
15640 6 : return "allocation-site-tenuring-changed";
15641 : case kAllocationSiteTransitionChangedGroup:
15642 4 : return "allocation-site-transition-changed";
15643 : }
15644 0 : UNREACHABLE();
15645 : }
15646 :
15647 185839 : Handle<Map> Map::TransitionToPrototype(Isolate* isolate, Handle<Map> map,
15648 : Handle<Object> prototype) {
15649 : Handle<Map> new_map =
15650 185839 : TransitionsAccessor(isolate, map).GetPrototypeTransition(prototype);
15651 185839 : if (new_map.is_null()) {
15652 169535 : new_map = Copy(isolate, map, "TransitionToPrototype");
15653 : TransitionsAccessor(isolate, map)
15654 169535 : .PutPrototypeTransition(prototype, new_map);
15655 169535 : Map::SetPrototype(isolate, new_map, prototype);
15656 : }
15657 185839 : return new_map;
15658 : }
15659 :
15660 :
15661 280478 : Maybe<bool> JSReceiver::SetPrototype(Handle<JSReceiver> object,
15662 : Handle<Object> value, bool from_javascript,
15663 : ShouldThrow should_throw) {
15664 560956 : if (object->IsJSProxy()) {
15665 : return JSProxy::SetPrototype(Handle<JSProxy>::cast(object), value,
15666 71931 : from_javascript, should_throw);
15667 : }
15668 : return JSObject::SetPrototype(Handle<JSObject>::cast(object), value,
15669 208547 : from_javascript, should_throw);
15670 : }
15671 :
15672 :
15673 : // ES6: 9.5.2 [[SetPrototypeOf]] (V)
15674 : // static
15675 71931 : Maybe<bool> JSProxy::SetPrototype(Handle<JSProxy> proxy, Handle<Object> value,
15676 : bool from_javascript,
15677 : ShouldThrow should_throw) {
15678 : Isolate* isolate = proxy->GetIsolate();
15679 71931 : STACK_CHECK(isolate, Nothing<bool>());
15680 : Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string();
15681 : // 1. Assert: Either Type(V) is Object or Type(V) is Null.
15682 : DCHECK(value->IsJSReceiver() || value->IsNull(isolate));
15683 : // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
15684 143842 : Handle<Object> handler(proxy->handler(), isolate);
15685 : // 3. If handler is null, throw a TypeError exception.
15686 : // 4. Assert: Type(handler) is Object.
15687 143842 : if (proxy->IsRevoked()) {
15688 : isolate->Throw(*isolate->factory()->NewTypeError(
15689 18 : MessageTemplate::kProxyRevoked, trap_name));
15690 : return Nothing<bool>();
15691 : }
15692 : // 5. Let target be the value of the [[ProxyTarget]] internal slot.
15693 143824 : Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
15694 : // 6. Let trap be ? GetMethod(handler, "getPrototypeOf").
15695 : Handle<Object> trap;
15696 143824 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15697 : isolate, trap,
15698 : Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
15699 : Nothing<bool>());
15700 : // 7. If trap is undefined, then return target.[[SetPrototypeOf]]().
15701 143824 : if (trap->IsUndefined(isolate)) {
15702 : return JSReceiver::SetPrototype(target, value, from_javascript,
15703 63182 : should_throw);
15704 : }
15705 : // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, V»)).
15706 8730 : Handle<Object> argv[] = {target, value};
15707 : Handle<Object> trap_result;
15708 17460 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15709 : isolate, trap_result,
15710 : Execution::Call(isolate, trap, handler, arraysize(argv), argv),
15711 : Nothing<bool>());
15712 90 : bool bool_trap_result = trap_result->BooleanValue(isolate);
15713 : // 9. If booleanTrapResult is false, return false.
15714 90 : if (!bool_trap_result) {
15715 90 : RETURN_FAILURE(
15716 : isolate, should_throw,
15717 : NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15718 : }
15719 : // 10. Let extensibleTarget be ? IsExtensible(target).
15720 54 : Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
15721 54 : if (is_extensible.IsNothing()) return Nothing<bool>();
15722 : // 11. If extensibleTarget is true, return true.
15723 54 : if (is_extensible.FromJust()) {
15724 27 : if (bool_trap_result) return Just(true);
15725 0 : RETURN_FAILURE(
15726 : isolate, should_throw,
15727 : NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15728 : }
15729 : // 12. Let targetProto be ? target.[[GetPrototypeOf]]().
15730 : Handle<Object> target_proto;
15731 54 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_proto,
15732 : JSReceiver::GetPrototype(isolate, target),
15733 : Nothing<bool>());
15734 : // 13. If SameValue(V, targetProto) is false, throw a TypeError exception.
15735 36 : if (bool_trap_result && !value->SameValue(*target_proto)) {
15736 : isolate->Throw(*isolate->factory()->NewTypeError(
15737 18 : MessageTemplate::kProxySetPrototypeOfNonExtensible));
15738 : return Nothing<bool>();
15739 : }
15740 : // 14. Return true.
15741 : return Just(true);
15742 : }
15743 :
15744 :
15745 210989 : Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object,
15746 : Handle<Object> value, bool from_javascript,
15747 : ShouldThrow should_throw) {
15748 : Isolate* isolate = object->GetIsolate();
15749 :
15750 : #ifdef DEBUG
15751 : int size = object->Size();
15752 : #endif
15753 :
15754 210989 : if (from_javascript) {
15755 382223 : if (object->IsAccessCheckNeeded() &&
15756 35 : !isolate->MayAccess(handle(isolate->context(), isolate), object)) {
15757 0 : isolate->ReportFailedAccessCheck(object);
15758 0 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
15759 0 : RETURN_FAILURE(isolate, should_throw,
15760 : NewTypeError(MessageTemplate::kNoAccess));
15761 : }
15762 : } else {
15763 : DCHECK(!object->IsAccessCheckNeeded());
15764 : }
15765 :
15766 : // Silently ignore the change if value is not a JSObject or null.
15767 : // SpiderMonkey behaves this way.
15768 445382 : if (!value->IsJSReceiver() && !value->IsNull(isolate)) return Just(true);
15769 :
15770 : bool all_extensible = object->map()->is_extensible();
15771 : Handle<JSObject> real_receiver = object;
15772 210974 : if (from_javascript) {
15773 : // Find the first object in the chain whose prototype object is not
15774 : // hidden.
15775 : PrototypeIterator iter(isolate, real_receiver, kStartAtPrototype,
15776 191094 : PrototypeIterator::END_AT_NON_HIDDEN);
15777 385368 : while (!iter.IsAtEnd()) {
15778 : // Casting to JSObject is fine because hidden prototypes are never
15779 : // JSProxies.
15780 : real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter);
15781 3180 : iter.Advance();
15782 6360 : all_extensible = all_extensible && real_receiver->map()->is_extensible();
15783 : }
15784 : }
15785 : Handle<Map> map(real_receiver->map(), isolate);
15786 :
15787 : // Nothing to do if prototype is already set.
15788 210974 : if (map->prototype() == *value) return Just(true);
15789 :
15790 185292 : bool immutable_proto = map->is_immutable_proto();
15791 185292 : if (immutable_proto) {
15792 171 : RETURN_FAILURE(
15793 : isolate, should_throw,
15794 : NewTypeError(MessageTemplate::kImmutablePrototypeSet, object));
15795 : }
15796 :
15797 : // From 8.6.2 Object Internal Methods
15798 : // ...
15799 : // In addition, if [[Extensible]] is false the value of the [[Class]] and
15800 : // [[Prototype]] internal properties of the object may not be modified.
15801 : // ...
15802 : // Implementation specific extensions that modify [[Class]], [[Prototype]]
15803 : // or [[Extensible]] must not violate the invariants defined in the preceding
15804 : // paragraph.
15805 185229 : if (!all_extensible) {
15806 495 : RETURN_FAILURE(isolate, should_throw,
15807 : NewTypeError(MessageTemplate::kNonExtensibleProto, object));
15808 : }
15809 :
15810 : // Before we can set the prototype we need to be sure prototype cycles are
15811 : // prevented. It is sufficient to validate that the receiver is not in the
15812 : // new prototype chain.
15813 369972 : if (value->IsJSReceiver()) {
15814 551711 : for (PrototypeIterator iter(isolate, JSReceiver::cast(*value),
15815 : kStartAtReceiver);
15816 378391 : !iter.IsAtEnd(); iter.Advance()) {
15817 756938 : if (iter.GetCurrent<JSReceiver>() == *object) {
15818 : // Cycle detected.
15819 198 : RETURN_FAILURE(isolate, should_throw,
15820 : NewTypeError(MessageTemplate::kCyclicProto));
15821 : }
15822 : }
15823 : }
15824 :
15825 : // Set the new prototype of the object.
15826 :
15827 : isolate->UpdateNoElementsProtectorOnSetPrototype(real_receiver);
15828 :
15829 184908 : Handle<Map> new_map = Map::TransitionToPrototype(isolate, map, value);
15830 : DCHECK(new_map->prototype() == *value);
15831 184908 : JSObject::MigrateToMap(real_receiver, new_map);
15832 :
15833 : DCHECK(size == object->Size());
15834 : return Just(true);
15835 : }
15836 :
15837 : // static
15838 24 : void JSObject::SetImmutableProto(Handle<JSObject> object) {
15839 : DCHECK(!object->IsAccessCheckNeeded()); // Never called from JS
15840 : Handle<Map> map(object->map(), object->GetIsolate());
15841 :
15842 : // Nothing to do if prototype is already set.
15843 42 : if (map->is_immutable_proto()) return;
15844 :
15845 : Handle<Map> new_map =
15846 6 : Map::TransitionToImmutableProto(object->GetIsolate(), map);
15847 6 : object->synchronized_set_map(*new_map);
15848 : }
15849 :
15850 455411 : void JSObject::EnsureCanContainElements(Handle<JSObject> object,
15851 : Arguments* args,
15852 : uint32_t first_arg,
15853 : uint32_t arg_count,
15854 : EnsureElementsMode mode) {
15855 : // Elements in |Arguments| are ordered backwards (because they're on the
15856 : // stack), but the method that's called here iterates over them in forward
15857 : // direction.
15858 : return EnsureCanContainElements(
15859 910822 : object, args->slot_at(first_arg + arg_count - 1), arg_count, mode);
15860 : }
15861 :
15862 :
15863 258321486 : ElementsAccessor* JSObject::GetElementsAccessor() {
15864 517864505 : return ElementsAccessor::ForKind(GetElementsKind());
15865 : }
15866 :
15867 3729166 : void JSObject::ValidateElements(JSObject object) {
15868 : #ifdef ENABLE_SLOW_DCHECKS
15869 : if (FLAG_enable_slow_asserts) {
15870 : object->GetElementsAccessor()->Validate(object);
15871 : }
15872 : #endif
15873 3729166 : }
15874 :
15875 5315114 : static bool ShouldConvertToSlowElements(JSObject object, uint32_t capacity,
15876 : uint32_t index,
15877 : uint32_t* new_capacity) {
15878 : STATIC_ASSERT(JSObject::kMaxUncheckedOldFastElementsLength <=
15879 : JSObject::kMaxUncheckedFastElementsLength);
15880 5315114 : if (index < capacity) {
15881 4751280 : *new_capacity = capacity;
15882 4751280 : return false;
15883 : }
15884 563834 : if (index - capacity >= JSObject::kMaxGap) return true;
15885 624132 : *new_capacity = JSObject::NewElementsCapacity(index + 1);
15886 : DCHECK_LT(index, *new_capacity);
15887 624132 : if (*new_capacity <= JSObject::kMaxUncheckedOldFastElementsLength ||
15888 44317 : (*new_capacity <= JSObject::kMaxUncheckedFastElementsLength &&
15889 : Heap::InNewSpace(object))) {
15890 : return false;
15891 : }
15892 : // If the fast-case backing storage takes up much more memory than a
15893 : // dictionary backing storage would, the object should have slow elements.
15894 1554 : int used_elements = object->GetFastElementsUsage();
15895 : uint32_t size_threshold = NumberDictionary::kPreferFastElementsSizeFactor *
15896 1554 : NumberDictionary::ComputeCapacity(used_elements) *
15897 1554 : NumberDictionary::kEntrySize;
15898 1554 : return size_threshold <= *new_capacity;
15899 : }
15900 :
15901 102992 : bool JSObject::WouldConvertToSlowElements(uint32_t index) {
15902 102992 : if (!HasFastElements()) return false;
15903 25242 : uint32_t capacity = static_cast<uint32_t>(elements()->length());
15904 : uint32_t new_capacity;
15905 12621 : return ShouldConvertToSlowElements(*this, capacity, index, &new_capacity);
15906 : }
15907 :
15908 488 : static ElementsKind BestFittingFastElementsKind(JSObject object) {
15909 488 : if (!object->map()->CanHaveFastTransitionableElementsKind()) {
15910 : return HOLEY_ELEMENTS;
15911 : }
15912 213 : if (object->HasSloppyArgumentsElements()) {
15913 : return FAST_SLOPPY_ARGUMENTS_ELEMENTS;
15914 : }
15915 213 : if (object->HasStringWrapperElements()) {
15916 : return FAST_STRING_WRAPPER_ELEMENTS;
15917 : }
15918 : DCHECK(object->HasDictionaryElements());
15919 204 : NumberDictionary dictionary = object->element_dictionary();
15920 : ElementsKind kind = HOLEY_SMI_ELEMENTS;
15921 217904 : for (int i = 0; i < dictionary->Capacity(); i++) {
15922 217745 : Object key = dictionary->KeyAt(i);
15923 217745 : if (key->IsNumber()) {
15924 72427 : Object value = dictionary->ValueAt(i);
15925 72472 : if (!value->IsNumber()) return HOLEY_ELEMENTS;
15926 72382 : if (!value->IsSmi()) {
15927 6838 : if (!FLAG_unbox_double_arrays) return HOLEY_ELEMENTS;
15928 : kind = HOLEY_DOUBLE_ELEMENTS;
15929 : }
15930 : }
15931 : }
15932 : return kind;
15933 : }
15934 :
15935 878518 : static bool ShouldConvertToFastElements(JSObject object,
15936 : NumberDictionary dictionary,
15937 : uint32_t index,
15938 : uint32_t* new_capacity) {
15939 : // If properties with non-standard attributes or accessors were added, we
15940 : // cannot go back to fast elements.
15941 878518 : if (dictionary->requires_slow_elements()) return false;
15942 :
15943 : // Adding a property with this index will require slow elements.
15944 855138 : if (index >= static_cast<uint32_t>(Smi::kMaxValue)) return false;
15945 :
15946 855015 : if (object->IsJSArray()) {
15947 569739 : Object length = JSArray::cast(object)->length();
15948 569739 : if (!length->IsSmi()) return false;
15949 569721 : *new_capacity = static_cast<uint32_t>(Smi::ToInt(length));
15950 285276 : } else if (object->IsJSSloppyArgumentsObject()) {
15951 : return false;
15952 : } else {
15953 186150 : *new_capacity = dictionary->max_number_key() + 1;
15954 : }
15955 1511742 : *new_capacity = Max(index + 1, *new_capacity);
15956 :
15957 755871 : uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
15958 755871 : NumberDictionary::kEntrySize;
15959 :
15960 : // Turn fast if the dictionary only saves 50% space.
15961 755871 : return 2 * dictionary_size >= *new_capacity;
15962 : }
15963 :
15964 : // static
15965 6199809 : void JSObject::AddDataElement(Handle<JSObject> object, uint32_t index,
15966 : Handle<Object> value,
15967 : PropertyAttributes attributes) {
15968 : DCHECK(object->map()->is_extensible());
15969 :
15970 : Isolate* isolate = object->GetIsolate();
15971 :
15972 6199812 : uint32_t old_length = 0;
15973 6199812 : uint32_t new_capacity = 0;
15974 :
15975 12399622 : if (object->IsJSArray()) {
15976 5705215 : CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length));
15977 : }
15978 :
15979 6199813 : ElementsKind kind = object->GetElementsKind();
15980 6199813 : FixedArrayBase elements = object->elements();
15981 : ElementsKind dictionary_kind = DICTIONARY_ELEMENTS;
15982 6199813 : if (IsSloppyArgumentsElementsKind(kind)) {
15983 119568 : elements = SloppyArgumentsElements::cast(elements)->arguments();
15984 : dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
15985 6080245 : } else if (IsStringWrapperElementsKind(kind)) {
15986 : dictionary_kind = SLOW_STRING_WRAPPER_ELEMENTS;
15987 : }
15988 :
15989 6199813 : if (attributes != NONE) {
15990 : kind = dictionary_kind;
15991 6180576 : } else if (elements->IsNumberDictionary()) {
15992 : kind = ShouldConvertToFastElements(
15993 878518 : *object, NumberDictionary::cast(elements), index, &new_capacity)
15994 : ? BestFittingFastElementsKind(*object)
15995 879006 : : dictionary_kind;
15996 5302057 : } else if (ShouldConvertToSlowElements(
15997 : *object, static_cast<uint32_t>(elements->length()), index,
15998 5302057 : &new_capacity)) {
15999 : kind = dictionary_kind;
16000 : }
16001 :
16002 6199812 : ElementsKind to = value->OptimalElementsKind();
16003 8987843 : if (IsHoleyElementsKind(kind) || !object->IsJSArray() || index > old_length) {
16004 : to = GetHoleyElementsKind(to);
16005 : kind = GetHoleyElementsKind(kind);
16006 : }
16007 : to = GetMoreGeneralElementsKind(kind, to);
16008 : ElementsAccessor* accessor = ElementsAccessor::ForKind(to);
16009 6199810 : accessor->Add(object, index, value, attributes, new_capacity);
16010 :
16011 12399624 : if (object->IsJSArray() && index >= old_length) {
16012 : Handle<Object> new_length =
16013 1548930 : isolate->factory()->NewNumberFromUint(index + 1);
16014 1548929 : JSArray::cast(*object)->set_length(*new_length);
16015 : }
16016 6199812 : }
16017 :
16018 :
16019 924647 : bool JSArray::SetLengthWouldNormalize(uint32_t new_length) {
16020 1849294 : if (!HasFastElements()) return false;
16021 1833806 : uint32_t capacity = static_cast<uint32_t>(elements()->length());
16022 : uint32_t new_capacity;
16023 917340 : return JSArray::SetLengthWouldNormalize(GetHeap(), new_length) &&
16024 : ShouldConvertToSlowElements(*this, capacity, new_length - 1,
16025 917340 : &new_capacity);
16026 : }
16027 :
16028 :
16029 : const double AllocationSite::kPretenureRatio = 0.85;
16030 :
16031 :
16032 0 : void AllocationSite::ResetPretenureDecision() {
16033 : set_pretenure_decision(kUndecided);
16034 : set_memento_found_count(0);
16035 : set_memento_create_count(0);
16036 0 : }
16037 :
16038 25047 : PretenureFlag AllocationSite::GetPretenureMode() const {
16039 : PretenureDecision mode = pretenure_decision();
16040 : // Zombie objects "decide" to be untenured.
16041 25047 : return mode == kTenure ? TENURED : NOT_TENURED;
16042 : }
16043 :
16044 0 : bool AllocationSite::IsNested() {
16045 : DCHECK(FLAG_trace_track_allocation_sites);
16046 0 : Object current = boilerplate()->GetHeap()->allocation_sites_list();
16047 0 : while (current->IsAllocationSite()) {
16048 0 : AllocationSite current_site = AllocationSite::cast(current);
16049 0 : if (current_site->nested_site() == *this) {
16050 0 : return true;
16051 : }
16052 0 : current = current_site->weak_next();
16053 : }
16054 : return false;
16055 : }
16056 :
16057 : template <AllocationSiteUpdateMode update_or_check>
16058 366979 : bool AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
16059 : ElementsKind to_kind) {
16060 : Isolate* isolate = site->GetIsolate();
16061 : bool result = false;
16062 :
16063 387442 : if (site->PointsToLiteral() && site->boilerplate()->IsJSArray()) {
16064 20462 : Handle<JSArray> boilerplate(JSArray::cast(site->boilerplate()), isolate);
16065 10231 : ElementsKind kind = boilerplate->GetElementsKind();
16066 : // if kind is holey ensure that to_kind is as well.
16067 10231 : if (IsHoleyElementsKind(kind)) {
16068 : to_kind = GetHoleyElementsKind(to_kind);
16069 : }
16070 10231 : if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
16071 : // If the array is huge, it's not likely to be defined in a local
16072 : // function, so we shouldn't make new instances of it very often.
16073 7782 : uint32_t length = 0;
16074 15564 : CHECK(boilerplate->length()->ToArrayLength(&length));
16075 7782 : if (length <= kMaximumArrayBytesToPretransition) {
16076 : if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) {
16077 0 : return true;
16078 : }
16079 7782 : if (FLAG_trace_track_allocation_sites) {
16080 0 : bool is_nested = site->IsNested();
16081 0 : PrintF("AllocationSite: JSArray %p boilerplate %supdated %s->%s\n",
16082 : reinterpret_cast<void*>(site->ptr()),
16083 : is_nested ? "(nested)" : " ", ElementsKindToString(kind),
16084 0 : ElementsKindToString(to_kind));
16085 : }
16086 7782 : JSObject::TransitionElementsKind(boilerplate, to_kind);
16087 23346 : site->dependent_code()->DeoptimizeDependentCodeGroup(
16088 15564 : isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
16089 : result = true;
16090 : }
16091 : }
16092 : } else {
16093 : // The AllocationSite is for a constructed Array.
16094 713495 : ElementsKind kind = site->GetElementsKind();
16095 : // if kind is holey ensure that to_kind is as well.
16096 356749 : if (IsHoleyElementsKind(kind)) {
16097 : to_kind = GetHoleyElementsKind(to_kind);
16098 : }
16099 356749 : if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
16100 : if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) return true;
16101 14892 : if (FLAG_trace_track_allocation_sites) {
16102 0 : PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
16103 : reinterpret_cast<void*>(site->ptr()), ElementsKindToString(kind),
16104 0 : ElementsKindToString(to_kind));
16105 : }
16106 14892 : site->SetElementsKind(to_kind);
16107 44681 : site->dependent_code()->DeoptimizeDependentCodeGroup(
16108 29787 : isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
16109 : result = true;
16110 : }
16111 : }
16112 : return result;
16113 : }
16114 :
16115 4984 : bool AllocationSite::ShouldTrack(ElementsKind from, ElementsKind to) {
16116 7840 : return IsSmiElementsKind(from) &&
16117 7840 : IsMoreGeneralElementsKindTransition(from, to);
16118 : }
16119 :
16120 0 : const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) {
16121 0 : switch (decision) {
16122 : case kUndecided: return "undecided";
16123 0 : case kDontTenure: return "don't tenure";
16124 0 : case kMaybeTenure: return "maybe tenure";
16125 0 : case kTenure: return "tenure";
16126 0 : case kZombie: return "zombie";
16127 0 : default: UNREACHABLE();
16128 : }
16129 : return nullptr;
16130 : }
16131 :
16132 : template <AllocationSiteUpdateMode update_or_check>
16133 885547 : bool JSObject::UpdateAllocationSite(Handle<JSObject> object,
16134 : ElementsKind to_kind) {
16135 1771095 : if (!object->IsJSArray()) return false;
16136 :
16137 631049 : if (!Heap::InNewSpace(*object)) return false;
16138 :
16139 : Handle<AllocationSite> site;
16140 : {
16141 : DisallowHeapAllocation no_allocation;
16142 :
16143 : Heap* heap = object->GetHeap();
16144 : AllocationMemento memento =
16145 1238072 : heap->FindAllocationMemento<Heap::kForRuntime>(object->map(), *object);
16146 619035 : if (memento.is_null()) return false;
16147 :
16148 : // Walk through to the Allocation Site
16149 733960 : site = handle(memento->GetAllocationSite(), heap->isolate());
16150 : }
16151 : return AllocationSite::DigestTransitionFeedback<update_or_check>(site,
16152 366979 : to_kind);
16153 : }
16154 :
16155 : template bool
16156 : JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kCheckOnly>(
16157 : Handle<JSObject> object, ElementsKind to_kind);
16158 :
16159 : template bool JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kUpdate>(
16160 : Handle<JSObject> object, ElementsKind to_kind);
16161 :
16162 142072 : void JSObject::TransitionElementsKind(Handle<JSObject> object,
16163 : ElementsKind to_kind) {
16164 142072 : ElementsKind from_kind = object->GetElementsKind();
16165 :
16166 142073 : if (IsHoleyElementsKind(from_kind)) {
16167 : to_kind = GetHoleyElementsKind(to_kind);
16168 : }
16169 :
16170 284145 : if (from_kind == to_kind) return;
16171 :
16172 : // This method should never be called for any other case.
16173 : DCHECK(IsFastElementsKind(from_kind));
16174 : DCHECK(IsFastElementsKind(to_kind));
16175 : DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind);
16176 :
16177 141931 : UpdateAllocationSite(object, to_kind);
16178 565374 : if (object->elements() == object->GetReadOnlyRoots().empty_fixed_array() ||
16179 : IsDoubleElementsKind(from_kind) == IsDoubleElementsKind(to_kind)) {
16180 : // No change is needed to the elements() buffer, the transition
16181 : // only requires a map change.
16182 136900 : Handle<Map> new_map = GetElementsTransitionMap(object, to_kind);
16183 136901 : MigrateToMap(object, new_map);
16184 : if (FLAG_trace_elements_transitions) {
16185 : Handle<FixedArrayBase> elms(object->elements(), object->GetIsolate());
16186 : PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms);
16187 : }
16188 : } else {
16189 : DCHECK((IsSmiElementsKind(from_kind) && IsDoubleElementsKind(to_kind)) ||
16190 : (IsDoubleElementsKind(from_kind) && IsObjectElementsKind(to_kind)));
16191 10060 : uint32_t c = static_cast<uint32_t>(object->elements()->length());
16192 5030 : ElementsAccessor::ForKind(to_kind)->GrowCapacityAndConvert(object, c);
16193 : }
16194 : }
16195 :
16196 :
16197 12985851 : bool JSArray::HasReadOnlyLength(Handle<JSArray> array) {
16198 12985877 : Map map = array->map();
16199 : // Fast path: "length" is the first fast property of arrays. Since it's not
16200 : // configurable, it's guaranteed to be the first in the descriptor array.
16201 12985877 : if (!map->is_dictionary_map()) {
16202 : DCHECK(map->instance_descriptors()->GetKey(0) ==
16203 : array->GetReadOnlyRoots().length_string());
16204 25970683 : return map->instance_descriptors()->GetDetails(0).IsReadOnly();
16205 : }
16206 :
16207 : Isolate* isolate = array->GetIsolate();
16208 : LookupIterator it(array, isolate->factory()->length_string(), array,
16209 565 : LookupIterator::OWN_SKIP_INTERCEPTOR);
16210 565 : CHECK_EQ(LookupIterator::ACCESSOR, it.state());
16211 565 : return it.IsReadOnly();
16212 : }
16213 :
16214 :
16215 2841876 : bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array,
16216 : uint32_t index) {
16217 2841876 : uint32_t length = 0;
16218 5683751 : CHECK(array->length()->ToArrayLength(&length));
16219 2841875 : if (length <= index) return HasReadOnlyLength(array);
16220 : return false;
16221 : }
16222 :
16223 : template <typename BackingStore>
16224 283342 : static int HoleyElementsUsage(JSObject object, BackingStore store) {
16225 : Isolate* isolate = object->GetIsolate();
16226 289180 : int limit = object->IsJSArray() ? Smi::ToInt(JSArray::cast(object)->length())
16227 566684 : : store->length();
16228 : int used = 0;
16229 290533753 : for (int i = 0; i < limit; ++i) {
16230 290533559 : if (!store->is_the_hole(isolate, i)) ++used;
16231 : }
16232 283342 : return used;
16233 : }
16234 :
16235 295208 : int JSObject::GetFastElementsUsage() {
16236 295208 : FixedArrayBase store = elements();
16237 295208 : switch (GetElementsKind()) {
16238 : case PACKED_SMI_ELEMENTS:
16239 : case PACKED_DOUBLE_ELEMENTS:
16240 : case PACKED_ELEMENTS:
16241 47162 : return IsJSArray() ? Smi::ToInt(JSArray::cast(*this)->length())
16242 35420 : : store->length();
16243 : case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
16244 741 : store = SloppyArgumentsElements::cast(store)->arguments();
16245 : V8_FALLTHROUGH;
16246 : case HOLEY_SMI_ELEMENTS:
16247 : case HOLEY_ELEMENTS:
16248 : case FAST_STRING_WRAPPER_ELEMENTS:
16249 283148 : return HoleyElementsUsage(*this, FixedArray::cast(store));
16250 : case HOLEY_DOUBLE_ELEMENTS:
16251 442 : if (elements()->length() == 0) return 0;
16252 194 : return HoleyElementsUsage(*this, FixedDoubleArray::cast(store));
16253 :
16254 : case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
16255 : case SLOW_STRING_WRAPPER_ELEMENTS:
16256 : case DICTIONARY_ELEMENTS:
16257 : case NO_ELEMENTS:
16258 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS:
16259 :
16260 : TYPED_ARRAYS(TYPED_ARRAY_CASE)
16261 : #undef TYPED_ARRAY_CASE
16262 0 : UNREACHABLE();
16263 : }
16264 : return 0;
16265 : }
16266 :
16267 :
16268 : // Certain compilers request function template instantiation when they
16269 : // see the definition of the other template functions in the
16270 : // class. This requires us to have the template functions put
16271 : // together, so even though this function belongs in objects-debug.cc,
16272 : // we keep it here instead to satisfy certain compilers.
16273 : #ifdef OBJECT_PRINT
16274 : template <typename Derived, typename Shape>
16275 : void Dictionary<Derived, Shape>::Print(std::ostream& os) {
16276 : DisallowHeapAllocation no_gc;
16277 : ReadOnlyRoots roots = this->GetReadOnlyRoots();
16278 : Derived dictionary = Derived::cast(*this);
16279 : int capacity = dictionary->Capacity();
16280 : for (int i = 0; i < capacity; i++) {
16281 : Object k = dictionary->KeyAt(i);
16282 : if (!dictionary->ToKey(roots, i, &k)) continue;
16283 : os << "\n ";
16284 : if (k->IsString()) {
16285 : String::cast(k)->StringPrint(os);
16286 : } else {
16287 : os << Brief(k);
16288 : }
16289 : os << ": " << Brief(dictionary->ValueAt(i)) << " ";
16290 : dictionary->DetailsAt(i).PrintAsSlowTo(os);
16291 : }
16292 : }
16293 : template <typename Derived, typename Shape>
16294 : void Dictionary<Derived, Shape>::Print() {
16295 : StdoutStream os;
16296 : Print(os);
16297 : os << std::endl;
16298 : }
16299 : #endif
16300 :
16301 :
16302 114113 : MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it,
16303 : bool* done) {
16304 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
16305 114113 : return GetPropertyWithInterceptorInternal(it, it->GetInterceptor(), done);
16306 : }
16307 :
16308 12042 : Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object,
16309 : Handle<Name> name) {
16310 : LookupIterator it = LookupIterator::PropertyOrElement(
16311 12042 : object->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
16312 12042 : return HasProperty(&it);
16313 : }
16314 :
16315 :
16316 17 : Maybe<bool> JSObject::HasRealElementProperty(Handle<JSObject> object,
16317 : uint32_t index) {
16318 : Isolate* isolate = object->GetIsolate();
16319 : LookupIterator it(isolate, object, index, object,
16320 : LookupIterator::OWN_SKIP_INTERCEPTOR);
16321 17 : return HasProperty(&it);
16322 : }
16323 :
16324 :
16325 5 : Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
16326 : Handle<Name> name) {
16327 : LookupIterator it = LookupIterator::PropertyOrElement(
16328 5 : object->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
16329 5 : Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
16330 5 : return maybe_result.IsJust() ? Just(it.state() == LookupIterator::ACCESSOR)
16331 10 : : Nothing<bool>();
16332 : }
16333 :
16334 5380 : int FixedArrayBase::GetMaxLengthForNewSpaceAllocation(ElementsKind kind) {
16335 : return ((kMaxRegularHeapObjectSize - FixedArrayBase::kHeaderSize) >>
16336 5380 : ElementsKindToShiftSize(kind));
16337 : }
16338 :
16339 477345 : bool FixedArrayBase::IsCowArray() const {
16340 954692 : return map() == GetReadOnlyRoots().fixed_cow_array_map();
16341 : }
16342 :
16343 0 : bool JSObject::IsApiWrapper() {
16344 : // These object types can carry information relevant for embedders. The
16345 : // *_API_* types are generated through templates which can have embedder
16346 : // fields. The other types have their embedder fields added at compile time.
16347 : auto instance_type = map()->instance_type();
16348 0 : return instance_type == JS_API_OBJECT_TYPE ||
16349 0 : instance_type == JS_ARRAY_BUFFER_TYPE ||
16350 0 : instance_type == JS_DATA_VIEW_TYPE ||
16351 0 : instance_type == JS_SPECIAL_API_OBJECT_TYPE ||
16352 0 : instance_type == JS_TYPED_ARRAY_TYPE;
16353 : }
16354 :
16355 26797 : bool JSObject::IsDroppableApiWrapper() {
16356 : auto instance_type = map()->instance_type();
16357 26797 : return instance_type == JS_API_OBJECT_TYPE ||
16358 26797 : instance_type == JS_SPECIAL_API_OBJECT_TYPE;
16359 : }
16360 :
16361 1834 : const char* Symbol::PrivateSymbolToName() const {
16362 1834 : ReadOnlyRoots roots = GetReadOnlyRoots();
16363 : #define SYMBOL_CHECK_AND_PRINT(_, name) \
16364 : if (*this == roots.name()) return #name;
16365 27879 : PRIVATE_SYMBOL_LIST_GENERATOR(SYMBOL_CHECK_AND_PRINT, /* not used */)
16366 : #undef SYMBOL_CHECK_AND_PRINT
16367 150 : return "UNKNOWN";
16368 : }
16369 :
16370 :
16371 4303 : void Symbol::SymbolShortPrint(std::ostream& os) {
16372 4303 : os << "<Symbol:";
16373 8606 : if (!name()->IsUndefined()) {
16374 2469 : os << " ";
16375 : HeapStringAllocator allocator;
16376 : StringStream accumulator(&allocator);
16377 4938 : String::cast(name())->StringShortPrint(&accumulator, false);
16378 7407 : os << accumulator.ToCString().get();
16379 : } else {
16380 1834 : os << " (" << PrivateSymbolToName() << ")";
16381 : }
16382 4303 : os << ">";
16383 4303 : }
16384 :
16385 :
16386 : // StringSharedKeys are used as keys in the eval cache.
16387 3521393 : class StringSharedKey : public HashTableKey {
16388 : public:
16389 : // This tuple unambiguously identifies calls to eval() or
16390 : // CreateDynamicFunction() (such as through the Function() constructor).
16391 : // * source is the string passed into eval(). For dynamic functions, this is
16392 : // the effective source for the function, some of which is implicitly
16393 : // generated.
16394 : // * shared is the shared function info for the function containing the call
16395 : // to eval(). for dynamic functions, shared is the native context closure.
16396 : // * When positive, position is the position in the source where eval is
16397 : // called. When negative, position is the negation of the position in the
16398 : // dynamic function's effective source where the ')' ends the parameters.
16399 5120613 : StringSharedKey(Handle<String> source, Handle<SharedFunctionInfo> shared,
16400 : LanguageMode language_mode, int position)
16401 : : HashTableKey(CompilationCacheShape::StringSharedHash(
16402 : *source, *shared, language_mode, position)),
16403 : source_(source),
16404 : shared_(shared),
16405 : language_mode_(language_mode),
16406 10241226 : position_(position) {}
16407 :
16408 6286751 : bool IsMatch(Object other) override {
16409 : DisallowHeapAllocation no_allocation;
16410 6286751 : if (!other->IsFixedArray()) {
16411 : DCHECK(other->IsNumber());
16412 1963807 : uint32_t other_hash = static_cast<uint32_t>(other->Number());
16413 1963807 : return Hash() == other_hash;
16414 : }
16415 : FixedArray other_array = FixedArray::cast(other);
16416 : SharedFunctionInfo shared = SharedFunctionInfo::cast(other_array->get(0));
16417 4322944 : if (shared != *shared_) return false;
16418 4158066 : int language_unchecked = Smi::ToInt(other_array->get(2));
16419 : DCHECK(is_valid_language_mode(language_unchecked));
16420 4158066 : LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
16421 4158066 : if (language_mode != language_mode_) return false;
16422 4145141 : int position = Smi::ToInt(other_array->get(3));
16423 4145141 : if (position != position_) return false;
16424 4144968 : String source = String::cast(other_array->get(1));
16425 4144968 : return source->Equals(*source_);
16426 : }
16427 :
16428 1327432 : Handle<Object> AsHandle(Isolate* isolate) {
16429 1327432 : Handle<FixedArray> array = isolate->factory()->NewFixedArray(4);
16430 2654864 : array->set(0, *shared_);
16431 2654864 : array->set(1, *source_);
16432 1327432 : array->set(2, Smi::FromEnum(language_mode_));
16433 1327432 : array->set(3, Smi::FromInt(position_));
16434 1327432 : array->set_map(ReadOnlyRoots(isolate).fixed_cow_array_map());
16435 1327432 : return array;
16436 : }
16437 :
16438 : private:
16439 : Handle<String> source_;
16440 : Handle<SharedFunctionInfo> shared_;
16441 : LanguageMode language_mode_;
16442 : int position_;
16443 : };
16444 :
16445 194863 : v8::Promise::PromiseState JSPromise::status() const {
16446 194863 : int value = flags() & kStatusMask;
16447 : DCHECK(value == 0 || value == 1 || value == 2);
16448 194863 : return static_cast<v8::Promise::PromiseState>(value);
16449 : }
16450 :
16451 40825 : void JSPromise::set_status(Promise::PromiseState status) {
16452 40825 : int value = flags() & ~kStatusMask;
16453 40825 : set_flags(value | status);
16454 40825 : }
16455 :
16456 : // static
16457 40 : const char* JSPromise::Status(v8::Promise::PromiseState status) {
16458 40 : switch (status) {
16459 : case v8::Promise::kFulfilled:
16460 : return "resolved";
16461 : case v8::Promise::kPending:
16462 15 : return "pending";
16463 : case v8::Promise::kRejected:
16464 5 : return "rejected";
16465 : }
16466 0 : UNREACHABLE();
16467 : }
16468 :
16469 21898 : int JSPromise::async_task_id() const {
16470 43796 : return AsyncTaskIdField::decode(flags());
16471 : }
16472 :
16473 6608 : void JSPromise::set_async_task_id(int id) {
16474 13216 : set_flags(AsyncTaskIdField::update(flags(), id));
16475 6608 : }
16476 :
16477 : // static
16478 29378 : Handle<Object> JSPromise::Fulfill(Handle<JSPromise> promise,
16479 : Handle<Object> value) {
16480 : Isolate* const isolate = promise->GetIsolate();
16481 :
16482 : // 1. Assert: The value of promise.[[PromiseState]] is "pending".
16483 : DCHECK_EQ(Promise::kPending, promise->status());
16484 :
16485 : // 2. Let reactions be promise.[[PromiseFulfillReactions]].
16486 58756 : Handle<Object> reactions(promise->reactions(), isolate);
16487 :
16488 : // 3. Set promise.[[PromiseResult]] to value.
16489 : // 4. Set promise.[[PromiseFulfillReactions]] to undefined.
16490 : // 5. Set promise.[[PromiseRejectReactions]] to undefined.
16491 29378 : promise->set_reactions_or_result(*value);
16492 :
16493 : // 6. Set promise.[[PromiseState]] to "fulfilled".
16494 29378 : promise->set_status(Promise::kFulfilled);
16495 :
16496 : // 7. Return TriggerPromiseReactions(reactions, value).
16497 : return TriggerPromiseReactions(isolate, reactions, value,
16498 29378 : PromiseReaction::kFulfill);
16499 : }
16500 :
16501 : // static
16502 11447 : Handle<Object> JSPromise::Reject(Handle<JSPromise> promise,
16503 : Handle<Object> reason, bool debug_event) {
16504 8039 : Isolate* const isolate = promise->GetIsolate();
16505 :
16506 19486 : if (debug_event) isolate->debug()->OnPromiseReject(promise, reason);
16507 : isolate->RunPromiseHook(PromiseHookType::kResolve, promise,
16508 11447 : isolate->factory()->undefined_value());
16509 :
16510 : // 1. Assert: The value of promise.[[PromiseState]] is "pending".
16511 : DCHECK_EQ(Promise::kPending, promise->status());
16512 :
16513 : // 2. Let reactions be promise.[[PromiseRejectReactions]].
16514 22894 : Handle<Object> reactions(promise->reactions(), isolate);
16515 :
16516 : // 3. Set promise.[[PromiseResult]] to reason.
16517 : // 4. Set promise.[[PromiseFulfillReactions]] to undefined.
16518 : // 5. Set promise.[[PromiseRejectReactions]] to undefined.
16519 11447 : promise->set_reactions_or_result(*reason);
16520 :
16521 : // 6. Set promise.[[PromiseState]] to "rejected".
16522 11447 : promise->set_status(Promise::kRejected);
16523 :
16524 : // 7. If promise.[[PromiseIsHandled]] is false, perform
16525 : // HostPromiseRejectionTracker(promise, "reject").
16526 11447 : if (!promise->has_handler()) {
16527 8970 : isolate->ReportPromiseReject(promise, reason, kPromiseRejectWithNoHandler);
16528 : }
16529 :
16530 : // 8. Return TriggerPromiseReactions(reactions, reason).
16531 : return TriggerPromiseReactions(isolate, reactions, reason,
16532 11447 : PromiseReaction::kReject);
16533 : }
16534 :
16535 : // static
16536 31037 : MaybeHandle<Object> JSPromise::Resolve(Handle<JSPromise> promise,
16537 : Handle<Object> resolution) {
16538 1545 : Isolate* const isolate = promise->GetIsolate();
16539 :
16540 : isolate->RunPromiseHook(PromiseHookType::kResolve, promise,
16541 31037 : isolate->factory()->undefined_value());
16542 :
16543 : // 6. If SameValue(resolution, promise) is true, then
16544 31037 : if (promise.is_identical_to(resolution)) {
16545 : // a. Let selfResolutionError be a newly created TypeError object.
16546 : Handle<Object> self_resolution_error = isolate->factory()->NewTypeError(
16547 50 : MessageTemplate::kPromiseCyclic, resolution);
16548 : // b. Return RejectPromise(promise, selfResolutionError).
16549 50 : return Reject(promise, self_resolution_error);
16550 : }
16551 :
16552 : // 7. If Type(resolution) is not Object, then
16553 61974 : if (!resolution->IsJSReceiver()) {
16554 : // a. Return FulfillPromise(promise, resolution).
16555 27228 : return Fulfill(promise, resolution);
16556 : }
16557 :
16558 : // 8. Let then be Get(resolution, "then").
16559 : MaybeHandle<Object> then;
16560 3759 : if (isolate->IsPromiseThenLookupChainIntact(
16561 3759 : Handle<JSReceiver>::cast(resolution))) {
16562 : // We can skip the "then" lookup on {resolution} if its [[Prototype]]
16563 : // is the (initial) Promise.prototype and the Promise#then protector
16564 : // is intact, as that guards the lookup path for the "then" property
16565 : // on JSPromise instances which have the (initial) %PromisePrototype%.
16566 1540 : then = isolate->promise_then();
16567 : } else {
16568 : then =
16569 : JSReceiver::GetProperty(isolate, Handle<JSReceiver>::cast(resolution),
16570 2219 : isolate->factory()->then_string());
16571 : }
16572 :
16573 : // 9. If then is an abrupt completion, then
16574 : Handle<Object> then_action;
16575 3759 : if (!then.ToHandle(&then_action)) {
16576 : // a. Return RejectPromise(promise, then.[[Value]]).
16577 : Handle<Object> reason(isolate->pending_exception(), isolate);
16578 64 : isolate->clear_pending_exception();
16579 64 : return Reject(promise, reason, false);
16580 : }
16581 :
16582 : // 10. Let thenAction be then.[[Value]].
16583 : // 11. If IsCallable(thenAction) is false, then
16584 7390 : if (!then_action->IsCallable()) {
16585 : // a. Return FulfillPromise(promise, resolution).
16586 2150 : return Fulfill(promise, resolution);
16587 : }
16588 :
16589 : // 12. Perform EnqueueJob("PromiseJobs", PromiseResolveThenableJob,
16590 : // «promise, resolution, thenAction»).
16591 : Handle<PromiseResolveThenableJobTask> task =
16592 : isolate->factory()->NewPromiseResolveThenableJobTask(
16593 : promise, Handle<JSReceiver>::cast(then_action),
16594 3090 : Handle<JSReceiver>::cast(resolution), isolate->native_context());
16595 4275 : if (isolate->debug()->is_active() && resolution->IsJSPromise()) {
16596 : // Mark the dependency of the new {promise} on the {resolution}.
16597 : Object::SetProperty(isolate, resolution,
16598 : isolate->factory()->promise_handled_by_symbol(),
16599 1365 : promise, LanguageMode::kStrict)
16600 2730 : .Check();
16601 : }
16602 3090 : isolate->native_context()->microtask_queue()->EnqueueMicrotask(*task);
16603 :
16604 : // 13. Return undefined.
16605 1545 : return isolate->factory()->undefined_value();
16606 : }
16607 :
16608 : // static
16609 40825 : Handle<Object> JSPromise::TriggerPromiseReactions(Isolate* isolate,
16610 : Handle<Object> reactions,
16611 : Handle<Object> argument,
16612 : PromiseReaction::Type type) {
16613 : DCHECK(reactions->IsSmi() || reactions->IsPromiseReaction());
16614 :
16615 : // We need to reverse the {reactions} here, since we record them
16616 : // on the JSPromise in the reverse order.
16617 : {
16618 : DisallowHeapAllocation no_gc;
16619 40825 : Object current = *reactions;
16620 : Object reversed = Smi::kZero;
16621 90638 : while (!current->IsSmi()) {
16622 8988 : Object next = PromiseReaction::cast(current)->next();
16623 8988 : PromiseReaction::cast(current)->set_next(reversed);
16624 8988 : reversed = current;
16625 8988 : current = next;
16626 : }
16627 : reactions = handle(reversed, isolate);
16628 : }
16629 :
16630 : // Morph the {reactions} into PromiseReactionJobTasks
16631 : // and push them onto the microtask queue.
16632 140451 : while (!reactions->IsSmi()) {
16633 8988 : Handle<HeapObject> task = Handle<HeapObject>::cast(reactions);
16634 8988 : Handle<PromiseReaction> reaction = Handle<PromiseReaction>::cast(task);
16635 17976 : reactions = handle(reaction->next(), isolate);
16636 :
16637 : STATIC_ASSERT(static_cast<int>(PromiseReaction::kSize) ==
16638 : static_cast<int>(PromiseReactionJobTask::kSize));
16639 8988 : if (type == PromiseReaction::kFulfill) {
16640 : task->synchronized_set_map(
16641 6491 : ReadOnlyRoots(isolate).promise_fulfill_reaction_job_task_map());
16642 19473 : Handle<PromiseFulfillReactionJobTask>::cast(task)->set_argument(
16643 6491 : *argument);
16644 19473 : Handle<PromiseFulfillReactionJobTask>::cast(task)->set_context(
16645 25964 : *isolate->native_context());
16646 : STATIC_ASSERT(
16647 : static_cast<int>(PromiseReaction::kFulfillHandlerOffset) ==
16648 : static_cast<int>(PromiseFulfillReactionJobTask::kHandlerOffset));
16649 : STATIC_ASSERT(
16650 : static_cast<int>(PromiseReaction::kPromiseOrCapabilityOffset) ==
16651 : static_cast<int>(
16652 : PromiseFulfillReactionJobTask::kPromiseOrCapabilityOffset));
16653 : } else {
16654 : DisallowHeapAllocation no_gc;
16655 2497 : HeapObject handler = reaction->reject_handler();
16656 : task->synchronized_set_map(
16657 2497 : ReadOnlyRoots(isolate).promise_reject_reaction_job_task_map());
16658 4994 : Handle<PromiseRejectReactionJobTask>::cast(task)->set_argument(*argument);
16659 7491 : Handle<PromiseRejectReactionJobTask>::cast(task)->set_context(
16660 9988 : *isolate->native_context());
16661 4994 : Handle<PromiseRejectReactionJobTask>::cast(task)->set_handler(handler);
16662 : STATIC_ASSERT(
16663 : static_cast<int>(PromiseReaction::kPromiseOrCapabilityOffset) ==
16664 : static_cast<int>(
16665 : PromiseRejectReactionJobTask::kPromiseOrCapabilityOffset));
16666 : }
16667 :
16668 17976 : isolate->native_context()->microtask_queue()->EnqueueMicrotask(
16669 35952 : *Handle<PromiseReactionJobTask>::cast(task));
16670 : }
16671 :
16672 40825 : return isolate->factory()->undefined_value();
16673 : }
16674 :
16675 : namespace {
16676 :
16677 : constexpr JSRegExp::Flag kCharFlagValues[] = {
16678 : JSRegExp::kGlobal, // g
16679 : JSRegExp::kInvalid, // h
16680 : JSRegExp::kIgnoreCase, // i
16681 : JSRegExp::kInvalid, // j
16682 : JSRegExp::kInvalid, // k
16683 : JSRegExp::kInvalid, // l
16684 : JSRegExp::kMultiline, // m
16685 : JSRegExp::kInvalid, // n
16686 : JSRegExp::kInvalid, // o
16687 : JSRegExp::kInvalid, // p
16688 : JSRegExp::kInvalid, // q
16689 : JSRegExp::kInvalid, // r
16690 : JSRegExp::kDotAll, // s
16691 : JSRegExp::kInvalid, // t
16692 : JSRegExp::kUnicode, // u
16693 : JSRegExp::kInvalid, // v
16694 : JSRegExp::kInvalid, // w
16695 : JSRegExp::kInvalid, // x
16696 : JSRegExp::kSticky, // y
16697 : };
16698 :
16699 : constexpr JSRegExp::Flag CharToFlag(uc16 flag_char) {
16700 76529 : return (flag_char < 'g' || flag_char > 'y')
16701 : ? JSRegExp::kInvalid
16702 76529 : : kCharFlagValues[flag_char - 'g'];
16703 : }
16704 :
16705 379521 : JSRegExp::Flags RegExpFlagsFromString(Isolate* isolate, Handle<String> flags,
16706 : bool* success) {
16707 : STATIC_ASSERT(CharToFlag('g') == JSRegExp::kGlobal);
16708 : STATIC_ASSERT(CharToFlag('i') == JSRegExp::kIgnoreCase);
16709 : STATIC_ASSERT(CharToFlag('m') == JSRegExp::kMultiline);
16710 : STATIC_ASSERT(CharToFlag('s') == JSRegExp::kDotAll);
16711 : STATIC_ASSERT(CharToFlag('u') == JSRegExp::kUnicode);
16712 : STATIC_ASSERT(CharToFlag('y') == JSRegExp::kSticky);
16713 :
16714 : int length = flags->length();
16715 379521 : if (length == 0) {
16716 304199 : *success = true;
16717 304199 : return JSRegExp::kNone;
16718 : }
16719 : // A longer flags string cannot be valid.
16720 75322 : if (length > JSRegExp::FlagCount()) return JSRegExp::Flags(0);
16721 : // Initialize {value} to {kInvalid} to allow 2-in-1 duplicate/invalid check.
16722 : JSRegExp::Flags value = JSRegExp::kInvalid;
16723 150644 : if (flags->IsSeqOneByteString()) {
16724 : DisallowHeapAllocation no_gc;
16725 : SeqOneByteString seq_flags = SeqOneByteString::cast(*flags);
16726 151707 : for (int i = 0; i < length; i++) {
16727 : JSRegExp::Flag flag = CharToFlag(seq_flags.SeqOneByteStringGet(i));
16728 : // Duplicate or invalid flag.
16729 76529 : if (value & flag) return JSRegExp::Flags(0);
16730 : value |= flag;
16731 : }
16732 : } else {
16733 0 : flags = String::Flatten(isolate, flags);
16734 : DisallowHeapAllocation no_gc;
16735 0 : String::FlatContent flags_content = flags->GetFlatContent(no_gc);
16736 0 : for (int i = 0; i < length; i++) {
16737 0 : JSRegExp::Flag flag = CharToFlag(flags_content.Get(i));
16738 : // Duplicate or invalid flag.
16739 0 : if (value & flag) return JSRegExp::Flags(0);
16740 : value |= flag;
16741 : }
16742 : }
16743 75178 : *success = true;
16744 : // Drop the initially set {kInvalid} bit.
16745 : value ^= JSRegExp::kInvalid;
16746 75178 : return value;
16747 : }
16748 :
16749 : } // namespace
16750 :
16751 :
16752 : // static
16753 82106 : MaybeHandle<JSRegExp> JSRegExp::New(Isolate* isolate, Handle<String> pattern,
16754 : Flags flags) {
16755 82106 : Handle<JSFunction> constructor = isolate->regexp_function();
16756 : Handle<JSRegExp> regexp =
16757 82106 : Handle<JSRegExp>::cast(isolate->factory()->NewJSObject(constructor));
16758 :
16759 82106 : return JSRegExp::Initialize(regexp, pattern, flags);
16760 : }
16761 :
16762 :
16763 : // static
16764 18621 : Handle<JSRegExp> JSRegExp::Copy(Handle<JSRegExp> regexp) {
16765 : Isolate* const isolate = regexp->GetIsolate();
16766 18621 : return Handle<JSRegExp>::cast(isolate->factory()->CopyJSObject(regexp));
16767 : }
16768 :
16769 : namespace {
16770 :
16771 : template <typename Char>
16772 461483 : int CountRequiredEscapes(Handle<String> source) {
16773 : DisallowHeapAllocation no_gc;
16774 : int escapes = 0;
16775 922966 : Vector<const Char> src = source->GetCharVector<Char>(no_gc);
16776 19348059582 : for (int i = 0; i < src.length(); i++) {
16777 19347136616 : const Char c = src[i];
16778 9673568308 : if (c == '\\') {
16779 : // Escape. Skip next character;
16780 131472 : i++;
16781 9673436836 : } else if (c == '/') {
16782 : // Not escaped forward-slash needs escape.
16783 1521 : escapes++;
16784 9673435315 : } else if (c == '\n') {
16785 1141 : escapes++;
16786 9673434174 : } else if (c == '\r') {
16787 36 : escapes++;
16788 446006 : } else if (static_cast<int>(c) == 0x2028) {
16789 20 : escapes += std::strlen("\\u2028") - 1;
16790 445986 : } else if (static_cast<int>(c) == 0x2029) {
16791 20 : escapes += std::strlen("\\u2029") - 1;
16792 : } else {
16793 : DCHECK(!unibrow::IsLineTerminator(static_cast<unibrow::uchar>(c)));
16794 : }
16795 : }
16796 461483 : return escapes;
16797 : }
16798 :
16799 : template <typename Char>
16800 : void WriteStringToCharVector(Vector<Char> v, int* d, const char* string) {
16801 : int s = 0;
16802 5188 : while (string[s] != '\0') v[(*d)++] = string[s++];
16803 : }
16804 :
16805 : template <typename Char, typename StringType>
16806 1774 : Handle<StringType> WriteEscapedRegExpSource(Handle<String> source,
16807 : Handle<StringType> result) {
16808 : DisallowHeapAllocation no_gc;
16809 3548 : Vector<const Char> src = source->GetCharVector<Char>(no_gc);
16810 : Vector<Char> dst(result->GetChars(no_gc), result->length());
16811 : int s = 0;
16812 : int d = 0;
16813 : // TODO(v8:1982): Fully implement
16814 : // https://tc39.github.io/ecma262/#sec-escaperegexppattern
16815 38171 : while (s < src.length()) {
16816 69246 : if (src[s] == '\\') {
16817 : // Escape. Copy this and next character.
16818 3990 : dst[d++] = src[s++];
16819 1995 : if (s == src.length()) break;
16820 32628 : } else if (src[s] == '/') {
16821 : // Not escaped forward-slash needs escape.
16822 3042 : dst[d++] = '\\';
16823 31107 : } else if (src[s] == '\n') {
16824 : WriteStringToCharVector(dst, &d, "\\n");
16825 1141 : s++;
16826 1141 : continue;
16827 29966 : } else if (src[s] == '\r') {
16828 : WriteStringToCharVector(dst, &d, "\\r");
16829 36 : s++;
16830 36 : continue;
16831 51 : } else if (static_cast<int>(src[s]) == 0x2028) {
16832 : WriteStringToCharVector(dst, &d, "\\u2028");
16833 20 : s++;
16834 20 : continue;
16835 31 : } else if (static_cast<int>(src[s]) == 0x2029) {
16836 : WriteStringToCharVector(dst, &d, "\\u2029");
16837 20 : s++;
16838 20 : continue;
16839 : }
16840 100218 : dst[d++] = src[s++];
16841 : }
16842 : DCHECK_EQ(result->length(), d);
16843 1774 : return result;
16844 : }
16845 :
16846 461483 : MaybeHandle<String> EscapeRegExpSource(Isolate* isolate,
16847 : Handle<String> source) {
16848 : DCHECK(source->IsFlat());
16849 461483 : if (source->length() == 0) return isolate->factory()->query_colon_string();
16850 461483 : bool one_byte = String::IsOneByteRepresentationUnderneath(*source);
16851 : int escapes = one_byte ? CountRequiredEscapes<uint8_t>(source)
16852 461483 : : CountRequiredEscapes<uc16>(source);
16853 461483 : if (escapes == 0) return source;
16854 1774 : int length = source->length() + escapes;
16855 1774 : if (one_byte) {
16856 : Handle<SeqOneByteString> result;
16857 3470 : ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
16858 : isolate->factory()->NewRawOneByteString(length),
16859 : String);
16860 1735 : return WriteEscapedRegExpSource<uint8_t>(source, result);
16861 : } else {
16862 : Handle<SeqTwoByteString> result;
16863 78 : ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
16864 : isolate->factory()->NewRawTwoByteString(length),
16865 : String);
16866 39 : return WriteEscapedRegExpSource<uc16>(source, result);
16867 : }
16868 : }
16869 :
16870 : } // namespace
16871 :
16872 : // static
16873 379521 : MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
16874 : Handle<String> source,
16875 : Handle<String> flags_string) {
16876 : Isolate* isolate = regexp->GetIsolate();
16877 379521 : bool success = false;
16878 379521 : Flags flags = RegExpFlagsFromString(isolate, flags_string, &success);
16879 379521 : if (!success) {
16880 144 : THROW_NEW_ERROR(
16881 : isolate,
16882 : NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string),
16883 : JSRegExp);
16884 : }
16885 379377 : return Initialize(regexp, source, flags);
16886 : }
16887 :
16888 :
16889 : // static
16890 461483 : MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
16891 : Handle<String> source, Flags flags) {
16892 : Isolate* isolate = regexp->GetIsolate();
16893 : Factory* factory = isolate->factory();
16894 : // If source is the empty string we set it to "(?:)" instead as
16895 : // suggested by ECMA-262, 5th, section 15.10.4.1.
16896 461483 : if (source->length() == 0) source = factory->query_colon_string();
16897 :
16898 461483 : source = String::Flatten(isolate, source);
16899 :
16900 : Handle<String> escaped_source;
16901 922966 : ASSIGN_RETURN_ON_EXCEPTION(isolate, escaped_source,
16902 : EscapeRegExpSource(isolate, source), JSRegExp);
16903 :
16904 922966 : RETURN_ON_EXCEPTION(
16905 : isolate, RegExpImpl::Compile(isolate, regexp, source, flags), JSRegExp);
16906 :
16907 917314 : regexp->set_source(*escaped_source);
16908 917314 : regexp->set_flags(Smi::FromInt(flags));
16909 :
16910 458657 : Map map = regexp->map();
16911 458657 : Object constructor = map->GetConstructor();
16912 1375971 : if (constructor->IsJSFunction() &&
16913 1375971 : JSFunction::cast(constructor)->initial_map() == map) {
16914 : // If we still have the original map, set in-object properties directly.
16915 916778 : regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, Smi::kZero,
16916 458389 : SKIP_WRITE_BARRIER);
16917 : } else {
16918 : // Map has changed, so use generic, but slower, method.
16919 536 : RETURN_ON_EXCEPTION(
16920 : isolate,
16921 : Object::SetProperty(isolate, regexp, factory->lastIndex_string(),
16922 : Handle<Smi>(Smi::zero(), isolate),
16923 : LanguageMode::kStrict),
16924 : JSRegExp);
16925 : }
16926 :
16927 458657 : return regexp;
16928 : }
16929 :
16930 :
16931 : // RegExpKey carries the source and flags of a regular expression as key.
16932 0 : class RegExpKey : public HashTableKey {
16933 : public:
16934 1043180 : RegExpKey(Handle<String> string, JSRegExp::Flags flags)
16935 : : HashTableKey(
16936 : CompilationCacheShape::RegExpHash(*string, Smi::FromInt(flags))),
16937 : string_(string),
16938 1043180 : flags_(Smi::FromInt(flags)) {}
16939 :
16940 : // Rather than storing the key in the hash table, a pointer to the
16941 : // stored value is stored where the key should be. IsMatch then
16942 : // compares the search key to the found object, rather than comparing
16943 : // a key to a key.
16944 551205 : bool IsMatch(Object obj) override {
16945 : FixedArray val = FixedArray::cast(obj);
16946 1102410 : return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
16947 1270333 : && (flags_ == val->get(JSRegExp::kFlagsIndex));
16948 : }
16949 :
16950 : Handle<String> string_;
16951 : Smi flags_;
16952 : };
16953 :
16954 42689 : Handle<String> OneByteStringKey::AsHandle(Isolate* isolate) {
16955 42689 : return isolate->factory()->NewOneByteInternalizedString(string_, HashField());
16956 : }
16957 :
16958 0 : Handle<String> TwoByteStringKey::AsHandle(Isolate* isolate) {
16959 0 : return isolate->factory()->NewTwoByteInternalizedString(string_, HashField());
16960 : }
16961 :
16962 473684 : Handle<String> SeqOneByteSubStringKey::AsHandle(Isolate* isolate) {
16963 : return isolate->factory()->NewOneByteInternalizedSubString(
16964 473684 : string_, from_, length_, HashField());
16965 : }
16966 :
16967 1813132 : bool SeqOneByteSubStringKey::IsMatch(Object string) {
16968 : DisallowHeapAllocation no_gc;
16969 3626264 : Vector<const uint8_t> chars(string_->GetChars(no_gc) + from_, length_);
16970 1813132 : return String::cast(string)->IsOneByteEqualTo(chars);
16971 : }
16972 :
16973 : // InternalizedStringKey carries a string/internalized-string object as key.
16974 0 : class InternalizedStringKey : public StringTableKey {
16975 : public:
16976 10644883 : explicit InternalizedStringKey(Handle<String> string)
16977 10644883 : : StringTableKey(0), string_(string) {
16978 : DCHECK(!string->IsInternalizedString());
16979 : DCHECK(string->IsFlat());
16980 : // Make sure hash_field is computed.
16981 10644893 : string->Hash();
16982 : set_hash_field(string->hash_field());
16983 10644882 : }
16984 :
16985 14343226 : bool IsMatch(Object string) override {
16986 14343227 : return string_->SlowEquals(String::cast(string));
16987 : }
16988 :
16989 4809208 : Handle<String> AsHandle(Isolate* isolate) override {
16990 : // Internalize the string if possible.
16991 : MaybeHandle<Map> maybe_map =
16992 4809208 : isolate->factory()->InternalizedStringMapForString(string_);
16993 : Handle<Map> map;
16994 4809207 : if (maybe_map.ToHandle(&map)) {
16995 : string_->set_map_no_write_barrier(*map);
16996 : DCHECK(string_->IsInternalizedString());
16997 50377 : return string_;
16998 : }
16999 4758830 : if (FLAG_thin_strings) {
17000 : // External strings get special treatment, to avoid copying their
17001 : // contents.
17002 9517664 : if (string_->IsExternalOneByteString()) {
17003 : return isolate->factory()
17004 5 : ->InternalizeExternalString<ExternalOneByteString>(string_);
17005 9517656 : } else if (string_->IsExternalTwoByteString()) {
17006 : return isolate->factory()
17007 0 : ->InternalizeExternalString<ExternalTwoByteString>(string_);
17008 : }
17009 : }
17010 : // Otherwise allocate a new internalized string.
17011 : return isolate->factory()->NewInternalizedStringImpl(
17012 4758828 : string_, string_->length(), string_->hash_field());
17013 : }
17014 :
17015 : private:
17016 : Handle<String> string_;
17017 : };
17018 :
17019 : template <typename Derived, typename Shape>
17020 83116 : void HashTable<Derived, Shape>::IteratePrefix(ObjectVisitor* v) {
17021 : BodyDescriptorBase::IteratePointers(*this, 0, kElementsStartOffset, v);
17022 83116 : }
17023 :
17024 : template <typename Derived, typename Shape>
17025 83492 : void HashTable<Derived, Shape>::IterateElements(ObjectVisitor* v) {
17026 : BodyDescriptorBase::IteratePointers(*this, kElementsStartOffset,
17027 : SizeFor(length()), v);
17028 83492 : }
17029 :
17030 : template <typename Derived, typename Shape>
17031 1464139 : Handle<Derived> HashTable<Derived, Shape>::New(
17032 : Isolate* isolate, int at_least_space_for, PretenureFlag pretenure,
17033 : MinimumCapacity capacity_option) {
17034 : DCHECK_LE(0, at_least_space_for);
17035 : DCHECK_IMPLIES(capacity_option == USE_CUSTOM_MINIMUM_CAPACITY,
17036 : base::bits::IsPowerOfTwo(at_least_space_for));
17037 :
17038 : int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
17039 : ? at_least_space_for
17040 1464139 : : ComputeCapacity(at_least_space_for);
17041 1464142 : if (capacity > HashTable::kMaxCapacity) {
17042 0 : isolate->heap()->FatalProcessOutOfMemory("invalid table size");
17043 : }
17044 1464142 : return NewInternal(isolate, capacity, pretenure);
17045 : }
17046 :
17047 : template <typename Derived, typename Shape>
17048 1464144 : Handle<Derived> HashTable<Derived, Shape>::NewInternal(
17049 : Isolate* isolate, int capacity, PretenureFlag pretenure) {
17050 : Factory* factory = isolate->factory();
17051 : int length = EntryToIndex(capacity);
17052 : RootIndex map_root_index = Shape::GetMapRootIndex();
17053 : Handle<FixedArray> array =
17054 1464144 : factory->NewFixedArrayWithMap(map_root_index, length, pretenure);
17055 1464141 : Handle<Derived> table = Handle<Derived>::cast(array);
17056 :
17057 : table->SetNumberOfElements(0);
17058 : table->SetNumberOfDeletedElements(0);
17059 : table->SetCapacity(capacity);
17060 1464143 : return table;
17061 : }
17062 :
17063 : template <typename Derived, typename Shape>
17064 239881 : void HashTable<Derived, Shape>::Rehash(Isolate* isolate, Derived new_table) {
17065 : DisallowHeapAllocation no_gc;
17066 : WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
17067 :
17068 : DCHECK_LT(NumberOfElements(), new_table->Capacity());
17069 :
17070 : // Copy prefix to new array.
17071 681672 : for (int i = kPrefixStartIndex; i < kElementsStartIndex; i++) {
17072 452029 : new_table->set(i, get(i), mode);
17073 : }
17074 :
17075 : // Rehash the elements.
17076 239881 : int capacity = this->Capacity();
17077 : ReadOnlyRoots roots(isolate);
17078 45315532 : for (int i = 0; i < capacity; i++) {
17079 45073340 : uint32_t from_index = EntryToIndex(i);
17080 44982616 : Object k = this->get(from_index);
17081 63398318 : if (!Shape::IsLive(roots, k)) continue;
17082 26657793 : uint32_t hash = Shape::HashForObject(isolate, k);
17083 : uint32_t insertion_index =
17084 53436340 : EntryToIndex(new_table->FindInsertionEntry(hash));
17085 71038568 : for (int j = 0; j < Shape::kEntrySize; j++) {
17086 88640888 : new_table->set(insertion_index + j, get(from_index + j), mode);
17087 : }
17088 : }
17089 239881 : new_table->SetNumberOfElements(NumberOfElements());
17090 : new_table->SetNumberOfDeletedElements(0);
17091 239881 : }
17092 :
17093 : template <typename Derived, typename Shape>
17094 532425234 : uint32_t HashTable<Derived, Shape>::EntryForProbe(Isolate* isolate, Object k,
17095 : int probe,
17096 : uint32_t expected) {
17097 532262399 : uint32_t hash = Shape::HashForObject(isolate, k);
17098 532428848 : uint32_t capacity = this->Capacity();
17099 : uint32_t entry = FirstProbe(hash, capacity);
17100 647619076 : for (int i = 1; i < probe; i++) {
17101 522133392 : if (entry == expected) return expected;
17102 136500369 : entry = NextProbe(entry, i, capacity);
17103 : }
17104 : return entry;
17105 : }
17106 :
17107 : template <typename Derived, typename Shape>
17108 59680760 : void HashTable<Derived, Shape>::Swap(uint32_t entry1, uint32_t entry2,
17109 : WriteBarrierMode mode) {
17110 59680760 : int index1 = EntryToIndex(entry1);
17111 59680760 : int index2 = EntryToIndex(entry2);
17112 119363480 : Object temp[Shape::kEntrySize];
17113 59682724 : for (int j = 0; j < Shape::kEntrySize; j++) {
17114 119365448 : temp[j] = get(index1 + j);
17115 : }
17116 59682575 : for (int j = 0; j < Shape::kEntrySize; j++) {
17117 119365460 : set(index1 + j, get(index2 + j), mode);
17118 : }
17119 59682371 : for (int j = 0; j < Shape::kEntrySize; j++) {
17120 59682578 : set(index2 + j, temp[j], mode);
17121 : }
17122 59680398 : }
17123 :
17124 : template <typename Derived, typename Shape>
17125 371926 : void HashTable<Derived, Shape>::Rehash(Isolate* isolate) {
17126 : DisallowHeapAllocation no_gc;
17127 : WriteBarrierMode mode = GetWriteBarrierMode(no_gc);
17128 : ReadOnlyRoots roots(isolate);
17129 371926 : uint32_t capacity = Capacity();
17130 : bool done = false;
17131 1373641 : for (int probe = 1; !done; probe++) {
17132 : // All elements at entries given by one of the first _probe_ probes
17133 : // are placed correctly. Other elements might need to be moved.
17134 : done = true;
17135 1175996748 : for (uint32_t current = 0; current < capacity; current++) {
17136 1175996748 : Object current_key = KeyAt(current);
17137 2268994751 : if (!Shape::IsLive(roots, current_key)) continue;
17138 494987686 : uint32_t target = EntryForProbe(isolate, current_key, probe, current);
17139 494993917 : if (current == target) continue;
17140 83005251 : Object target_key = KeyAt(target);
17141 120444891 : if (!Shape::IsLive(roots, target_key) ||
17142 37439572 : EntryForProbe(isolate, target_key, probe, target) != target) {
17143 : // Put the current element into the correct position.
17144 59680684 : Swap(current, target, mode);
17145 : // The other element will be processed on the next iteration.
17146 59680395 : current--;
17147 : } else {
17148 : // The place for the current element is occupied. Leave the element
17149 : // for the next probe.
17150 : done = false;
17151 : }
17152 : }
17153 : }
17154 : // Wipe deleted entries.
17155 : Object the_hole = roots.the_hole_value();
17156 371927 : Object undefined = roots.undefined_value();
17157 187783407 : for (uint32_t current = 0; current < capacity; current++) {
17158 374822961 : if (KeyAt(current) == the_hole) {
17159 1627317 : set(EntryToIndex(current) + kEntryKeyIndex, undefined);
17160 : }
17161 : }
17162 : SetNumberOfDeletedElements(0);
17163 371926 : }
17164 :
17165 : template <typename Derived, typename Shape>
17166 34051988 : Handle<Derived> HashTable<Derived, Shape>::EnsureCapacity(
17167 : Isolate* isolate, Handle<Derived> table, int n, PretenureFlag pretenure) {
17168 34051986 : if (table->HasSufficientCapacityToAdd(n)) return table;
17169 :
17170 239374 : int capacity = table->Capacity();
17171 239374 : int new_nof = table->NumberOfElements() + n;
17172 :
17173 : const int kMinCapacityForPretenure = 256;
17174 : bool should_pretenure =
17175 : pretenure == TENURED ||
17176 248366 : ((capacity > kMinCapacityForPretenure) && !Heap::InNewSpace(*table));
17177 : Handle<Derived> new_table = HashTable::New(
17178 239374 : isolate, new_nof, should_pretenure ? TENURED : NOT_TENURED);
17179 :
17180 239374 : table->Rehash(isolate, *new_table);
17181 239374 : return new_table;
17182 : }
17183 :
17184 : template bool
17185 : HashTable<NameDictionary, NameDictionaryShape>::HasSufficientCapacityToAdd(int);
17186 :
17187 : template <typename Derived, typename Shape>
17188 34084900 : bool HashTable<Derived, Shape>::HasSufficientCapacityToAdd(
17189 : int number_of_additional_elements) {
17190 34084900 : int capacity = Capacity();
17191 34084903 : int nof = NumberOfElements() + number_of_additional_elements;
17192 34084903 : int nod = NumberOfDeletedElements();
17193 : // Return true if:
17194 : // 50% is still free after adding number_of_additional_elements elements and
17195 : // at most 50% of the free elements are deleted elements.
17196 34084910 : if ((nof < capacity) && ((nod <= (capacity - nof) >> 1))) {
17197 34023675 : int needed_free = nof >> 1;
17198 34023675 : if (nof + needed_free <= capacity) return true;
17199 : }
17200 239826 : return false;
17201 : }
17202 :
17203 : template <typename Derived, typename Shape>
17204 78345 : Handle<Derived> HashTable<Derived, Shape>::Shrink(Isolate* isolate,
17205 : Handle<Derived> table,
17206 : int additionalCapacity) {
17207 78345 : int capacity = table->Capacity();
17208 78345 : int nof = table->NumberOfElements();
17209 :
17210 : // Shrink to fit the number of elements if only a quarter of the
17211 : // capacity is filled with elements.
17212 78345 : if (nof > (capacity >> 2)) return table;
17213 : // Allocate a new dictionary with room for at least the current number of
17214 : // elements + {additionalCapacity}. The allocation method will make sure that
17215 : // there is extra room in the dictionary for additions. Don't go lower than
17216 : // room for {kMinShrinkCapacity} elements.
17217 59864 : int at_least_room_for = nof + additionalCapacity;
17218 : int new_capacity = ComputeCapacity(at_least_room_for);
17219 59864 : if (new_capacity < Derived::kMinShrinkCapacity) return table;
17220 507 : if (new_capacity == capacity) return table;
17221 :
17222 : const int kMinCapacityForPretenure = 256;
17223 : bool pretenure = (at_least_room_for > kMinCapacityForPretenure) &&
17224 744 : !Heap::InNewSpace(*table);
17225 : Handle<Derived> new_table =
17226 : HashTable::New(isolate, new_capacity, pretenure ? TENURED : NOT_TENURED,
17227 507 : USE_CUSTOM_MINIMUM_CAPACITY);
17228 :
17229 507 : table->Rehash(isolate, *new_table);
17230 507 : return new_table;
17231 : }
17232 :
17233 : template <typename Derived, typename Shape>
17234 60774762 : uint32_t HashTable<Derived, Shape>::FindInsertionEntry(uint32_t hash) {
17235 60774762 : uint32_t capacity = Capacity();
17236 : uint32_t entry = FirstProbe(hash, capacity);
17237 : uint32_t count = 1;
17238 : // EnsureCapacity will guarantee the hash table is never full.
17239 60774767 : ReadOnlyRoots roots = GetReadOnlyRoots();
17240 : while (true) {
17241 142206850 : if (!Shape::IsLive(roots, KeyAt(entry))) break;
17242 81432088 : entry = NextProbe(entry, count++, capacity);
17243 : }
17244 81432088 : return entry;
17245 : }
17246 :
17247 881215 : void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global,
17248 : Handle<Name> name) {
17249 : // Regardless of whether the property is there or not invalidate
17250 : // Load/StoreGlobalICs that load/store through global object's prototype.
17251 881215 : JSObject::InvalidatePrototypeValidityCell(*global);
17252 :
17253 : DCHECK(!global->HasFastProperties());
17254 1762430 : auto dictionary = handle(global->global_dictionary(), global->GetIsolate());
17255 881215 : int entry = dictionary->FindEntry(global->GetIsolate(), name);
17256 1762430 : if (entry == GlobalDictionary::kNotFound) return;
17257 87 : PropertyCell::InvalidateEntry(global->GetIsolate(), dictionary, entry);
17258 : }
17259 :
17260 8238112 : Handle<PropertyCell> JSGlobalObject::EnsureEmptyPropertyCell(
17261 : Handle<JSGlobalObject> global, Handle<Name> name,
17262 : PropertyCellType cell_type, int* entry_out) {
17263 : Isolate* isolate = global->GetIsolate();
17264 : DCHECK(!global->HasFastProperties());
17265 16476223 : Handle<GlobalDictionary> dictionary(global->global_dictionary(), isolate);
17266 8238112 : int entry = dictionary->FindEntry(isolate, name);
17267 : Handle<PropertyCell> cell;
17268 8238116 : if (entry != GlobalDictionary::kNotFound) {
17269 3046 : if (entry_out) *entry_out = entry;
17270 6092 : cell = handle(dictionary->CellAt(entry), isolate);
17271 6092 : PropertyCellType original_cell_type = cell->property_details().cell_type();
17272 : DCHECK(original_cell_type == PropertyCellType::kInvalidated ||
17273 : original_cell_type == PropertyCellType::kUninitialized);
17274 : DCHECK(cell->value()->IsTheHole(isolate));
17275 3046 : if (original_cell_type == PropertyCellType::kInvalidated) {
17276 482 : cell = PropertyCell::InvalidateEntry(isolate, dictionary, entry);
17277 : }
17278 : PropertyDetails details(kData, NONE, cell_type);
17279 6092 : cell->set_property_details(details);
17280 3046 : return cell;
17281 : }
17282 8235070 : cell = isolate->factory()->NewPropertyCell(name);
17283 : PropertyDetails details(kData, NONE, cell_type);
17284 : dictionary = GlobalDictionary::Add(isolate, dictionary, name, cell, details,
17285 8235061 : entry_out);
17286 : // {*entry_out} is initialized inside GlobalDictionary::Add().
17287 16470140 : global->SetProperties(*dictionary);
17288 8235068 : return cell;
17289 : }
17290 :
17291 :
17292 : // This class is used for looking up two character strings in the string table.
17293 : // If we don't have a hit we don't want to waste much time so we unroll the
17294 : // string hash calculation loop here for speed. Doesn't work if the two
17295 : // characters form a decimal integer, since such strings have a different hash
17296 : // algorithm.
17297 0 : class TwoCharHashTableKey : public StringTableKey {
17298 : public:
17299 : TwoCharHashTableKey(uint16_t c1, uint16_t c2, uint64_t seed)
17300 3412136 : : StringTableKey(ComputeHashField(c1, c2, seed)), c1_(c1), c2_(c2) {}
17301 :
17302 2588981 : bool IsMatch(Object o) override {
17303 2588981 : String other = String::cast(o);
17304 2588981 : if (other->length() != 2) return false;
17305 96397 : if (other->Get(0) != c1_) return false;
17306 15853 : return other->Get(1) == c2_;
17307 : }
17308 :
17309 0 : Handle<String> AsHandle(Isolate* isolate) override {
17310 : // The TwoCharHashTableKey is only used for looking in the string
17311 : // table, not for adding to it.
17312 0 : UNREACHABLE();
17313 : }
17314 :
17315 : private:
17316 1706068 : uint32_t ComputeHashField(uint16_t c1, uint16_t c2, uint64_t seed) {
17317 : // Char 1.
17318 1706068 : uint32_t hash = static_cast<uint32_t>(seed);
17319 1706068 : hash += c1;
17320 1706068 : hash += hash << 10;
17321 1706068 : hash ^= hash >> 6;
17322 : // Char 2.
17323 1706068 : hash += c2;
17324 1706068 : hash += hash << 10;
17325 1706068 : hash ^= hash >> 6;
17326 : // GetHash.
17327 1706068 : hash += hash << 3;
17328 1706068 : hash ^= hash >> 11;
17329 1706068 : hash += hash << 15;
17330 1706068 : if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash;
17331 1706068 : hash = (hash << String::kHashShift) | String::kIsNotArrayIndexMask;
17332 : #ifdef DEBUG
17333 : // If this assert fails then we failed to reproduce the two-character
17334 : // version of the string hashing algorithm above. One reason could be
17335 : // that we were passed two digits as characters, since the hash
17336 : // algorithm is different in that case.
17337 : uint16_t chars[2] = {c1, c2};
17338 : uint32_t check_hash = StringHasher::HashSequentialString(chars, 2, seed);
17339 : DCHECK_EQ(hash, check_hash);
17340 : #endif
17341 1706068 : return hash;
17342 : }
17343 :
17344 : uint16_t c1_;
17345 : uint16_t c2_;
17346 : };
17347 :
17348 1706068 : MaybeHandle<String> StringTable::LookupTwoCharsStringIfExists(
17349 : Isolate* isolate,
17350 : uint16_t c1,
17351 : uint16_t c2) {
17352 1706068 : TwoCharHashTableKey key(c1, c2, isolate->heap()->HashSeed());
17353 : Handle<StringTable> string_table = isolate->factory()->string_table();
17354 1706068 : int entry = string_table->FindEntry(isolate, &key);
17355 1706068 : if (entry == kNotFound) return MaybeHandle<String>();
17356 :
17357 27382 : Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
17358 : DCHECK(StringShape(*result).IsInternalized());
17359 : DCHECK_EQ(result->Hash(), key.Hash());
17360 13691 : return result;
17361 : }
17362 :
17363 214 : void StringTable::EnsureCapacityForDeserialization(Isolate* isolate,
17364 : int expected) {
17365 : Handle<StringTable> table = isolate->factory()->string_table();
17366 : // We need a key instance for the virtual hash function.
17367 214 : table = StringTable::EnsureCapacity(isolate, table, expected);
17368 214 : isolate->heap()->SetRootStringTable(*table);
17369 214 : }
17370 :
17371 : namespace {
17372 :
17373 : template <class StringClass>
17374 14 : void MigrateExternalStringResource(Isolate* isolate, String from, String to) {
17375 14 : StringClass cast_from = StringClass::cast(from);
17376 14 : StringClass cast_to = StringClass::cast(to);
17377 : const typename StringClass::Resource* to_resource = cast_to->resource();
17378 14 : if (to_resource == nullptr) {
17379 : // |to| is a just-created internalized copy of |from|. Migrate the resource.
17380 5 : cast_to->SetResource(isolate, cast_from->resource());
17381 : // Zap |from|'s resource pointer to reflect the fact that |from| has
17382 : // relinquished ownership of its resource.
17383 5 : isolate->heap()->UpdateExternalString(
17384 10 : from, ExternalString::cast(from)->ExternalPayloadSize(), 0);
17385 5 : cast_from->SetResource(isolate, nullptr);
17386 9 : } else if (to_resource != cast_from->resource()) {
17387 : // |to| already existed and has its own resource. Finalize |from|.
17388 9 : isolate->heap()->FinalizeExternalString(from);
17389 : }
17390 14 : }
17391 :
17392 12160696 : void MakeStringThin(String string, String internalized, Isolate* isolate) {
17393 : DCHECK_NE(string, internalized);
17394 : DCHECK(internalized->IsInternalizedString());
17395 :
17396 12160713 : if (string->IsExternalString()) {
17397 14 : if (internalized->IsExternalOneByteString()) {
17398 : MigrateExternalStringResource<ExternalOneByteString>(isolate, string,
17399 14 : internalized);
17400 0 : } else if (internalized->IsExternalTwoByteString()) {
17401 : MigrateExternalStringResource<ExternalTwoByteString>(isolate, string,
17402 0 : internalized);
17403 : } else {
17404 : // If the external string is duped into an existing non-external
17405 : // internalized string, free its resource (it's about to be rewritten
17406 : // into a ThinString below).
17407 0 : isolate->heap()->FinalizeExternalString(string);
17408 : }
17409 : }
17410 :
17411 : DisallowHeapAllocation no_gc;
17412 12160713 : int old_size = string->Size();
17413 12160696 : isolate->heap()->NotifyObjectLayoutChange(string, old_size, no_gc);
17414 12160707 : bool one_byte = internalized->IsOneByteRepresentation();
17415 : Handle<Map> map = one_byte ? isolate->factory()->thin_one_byte_string_map()
17416 12160709 : : isolate->factory()->thin_string_map();
17417 : DCHECK_GE(old_size, ThinString::kSize);
17418 12160713 : string->synchronized_set_map(*map);
17419 12160711 : ThinString thin = ThinString::cast(string);
17420 12160711 : thin->set_actual(internalized);
17421 12160711 : Address thin_end = thin->address() + ThinString::kSize;
17422 12160711 : int size_delta = old_size - ThinString::kSize;
17423 12160711 : if (size_delta != 0) {
17424 : Heap* heap = isolate->heap();
17425 5382933 : heap->CreateFillerObjectAt(thin_end, size_delta, ClearRecordedSlots::kNo);
17426 : }
17427 12160711 : }
17428 :
17429 : } // namespace
17430 :
17431 : // static
17432 11497821 : Handle<String> StringTable::LookupString(Isolate* isolate,
17433 : Handle<String> string) {
17434 11497821 : string = String::Flatten(isolate, string);
17435 22995677 : if (string->IsInternalizedString()) return string;
17436 :
17437 10644892 : InternalizedStringKey key(string);
17438 10644881 : Handle<String> result = LookupKey(isolate, &key);
17439 :
17440 10644878 : if (FLAG_thin_strings) {
17441 21289771 : if (!string->IsInternalizedString()) {
17442 10594514 : MakeStringThin(*string, *result, isolate);
17443 : }
17444 : } else { // !FLAG_thin_strings
17445 0 : if (string->IsConsString()) {
17446 0 : Handle<ConsString> cons = Handle<ConsString>::cast(string);
17447 0 : cons->set_first(isolate, *result);
17448 0 : cons->set_second(isolate, ReadOnlyRoots(isolate).empty_string());
17449 0 : } else if (string->IsSlicedString()) {
17450 : STATIC_ASSERT(static_cast<int>(ConsString::kSize) ==
17451 : static_cast<int>(SlicedString::kSize));
17452 : DisallowHeapAllocation no_gc;
17453 0 : bool one_byte = result->IsOneByteRepresentation();
17454 : Handle<Map> map = one_byte
17455 : ? isolate->factory()->cons_one_byte_string_map()
17456 0 : : isolate->factory()->cons_string_map();
17457 0 : string->set_map(*map);
17458 0 : Handle<ConsString> cons = Handle<ConsString>::cast(string);
17459 0 : cons->set_first(isolate, *result);
17460 0 : cons->set_second(isolate, ReadOnlyRoots(isolate).empty_string());
17461 : }
17462 : }
17463 10644892 : return result;
17464 : }
17465 :
17466 : // static
17467 53669580 : Handle<String> StringTable::LookupKey(Isolate* isolate, StringTableKey* key) {
17468 : Handle<StringTable> table = isolate->factory()->string_table();
17469 53669582 : int entry = table->FindEntry(isolate, key);
17470 :
17471 : // String already in table.
17472 53669661 : if (entry != kNotFound) {
17473 77780369 : return handle(String::cast(table->KeyAt(entry)), isolate);
17474 : }
17475 :
17476 14779466 : table = StringTable::CautiousShrink(isolate, table);
17477 : // Adding new string. Grow table if needed.
17478 14779457 : table = StringTable::EnsureCapacity(isolate, table, 1);
17479 14779462 : isolate->heap()->SetRootStringTable(*table);
17480 :
17481 14779454 : return AddKeyNoResize(isolate, key);
17482 : }
17483 :
17484 14784208 : Handle<String> StringTable::AddKeyNoResize(Isolate* isolate,
17485 : StringTableKey* key) {
17486 : Handle<StringTable> table = isolate->factory()->string_table();
17487 : DCHECK(table->HasSufficientCapacityToAdd(1));
17488 : // Create string object.
17489 14784208 : Handle<String> string = key->AsHandle(isolate);
17490 : // There must be no attempts to internalize strings that could throw
17491 : // InvalidStringLength error.
17492 14784203 : CHECK(!string.is_null());
17493 : DCHECK(string->HasHashCode());
17494 : DCHECK_EQ(table->FindEntry(isolate, key), kNotFound);
17495 :
17496 : // Add the new string and return it along with the string table.
17497 29568411 : int entry = table->FindInsertionEntry(key->Hash());
17498 29568405 : table->set(EntryToIndex(entry), *string);
17499 14784211 : table->ElementAdded();
17500 :
17501 14784210 : return Handle<String>::cast(string);
17502 : }
17503 :
17504 14779465 : Handle<StringTable> StringTable::CautiousShrink(Isolate* isolate,
17505 : Handle<StringTable> table) {
17506 : // Only shrink if the table is very empty to avoid performance penalty.
17507 14779465 : int capacity = table->Capacity();
17508 14779463 : int nof = table->NumberOfElements();
17509 14779466 : if (capacity <= StringTable::kMinCapacity) return table;
17510 7413229 : if (nof > (capacity / kMaxEmptyFactor)) return table;
17511 : // Keep capacity for at least half of the current nof elements.
17512 30907 : int slack_capacity = nof >> 2;
17513 30907 : return Shrink(isolate, table, slack_capacity);
17514 : }
17515 :
17516 : namespace {
17517 :
17518 : class StringTableNoAllocateKey : public StringTableKey {
17519 : public:
17520 1955588 : StringTableNoAllocateKey(String string, uint64_t seed)
17521 1955588 : : StringTableKey(0), string_(string) {
17522 : StringShape shape(string);
17523 1955588 : one_byte_ = shape.HasOnlyOneByteChars();
17524 : DCHECK(!shape.IsInternalized());
17525 : DCHECK(!shape.IsThin());
17526 : int length = string->length();
17527 1955588 : if (shape.IsCons() && length <= String::kMaxHashCalcLength) {
17528 287805 : special_flattening_ = true;
17529 : uint32_t hash_field = 0;
17530 287805 : if (one_byte_) {
17531 287805 : if (V8_LIKELY(length <=
17532 : static_cast<int>(arraysize(one_byte_buffer_)))) {
17533 287805 : one_byte_content_ = one_byte_buffer_;
17534 : } else {
17535 0 : one_byte_content_ = new uint8_t[length];
17536 : }
17537 287805 : String::WriteToFlat(string, one_byte_content_, 0, length);
17538 : hash_field =
17539 287805 : StringHasher::HashSequentialString(one_byte_content_, length, seed);
17540 : } else {
17541 0 : if (V8_LIKELY(length <=
17542 : static_cast<int>(arraysize(two_byte_buffer_)))) {
17543 0 : two_byte_content_ = two_byte_buffer_;
17544 : } else {
17545 0 : two_byte_content_ = new uint16_t[length];
17546 : }
17547 0 : String::WriteToFlat(string, two_byte_content_, 0, length);
17548 : hash_field =
17549 0 : StringHasher::HashSequentialString(two_byte_content_, length, seed);
17550 : }
17551 : string->set_hash_field(hash_field);
17552 : } else {
17553 1667783 : special_flattening_ = false;
17554 1667783 : one_byte_content_ = nullptr;
17555 1667783 : string->Hash();
17556 : }
17557 :
17558 : DCHECK(string->HasHashCode());
17559 : set_hash_field(string->hash_field());
17560 1955588 : }
17561 :
17562 1955588 : ~StringTableNoAllocateKey() override {
17563 1955588 : if (one_byte_) {
17564 1214599 : if (one_byte_content_ != one_byte_buffer_) delete[] one_byte_content_;
17565 : } else {
17566 740989 : if (two_byte_content_ != two_byte_buffer_) delete[] two_byte_content_;
17567 : }
17568 1955588 : }
17569 :
17570 3524660 : bool IsMatch(Object otherstring) override {
17571 3524660 : String other = String::cast(otherstring);
17572 : DCHECK(other->IsInternalizedString());
17573 : DCHECK(other->IsFlat());
17574 3524660 : if (Hash() != other->Hash()) return false;
17575 : int len = string_->length();
17576 1565584 : if (len != other->length()) return false;
17577 :
17578 : DisallowHeapAllocation no_gc;
17579 1565584 : if (!special_flattening_) {
17580 2858476 : if (string_->Get(0) != other->Get(0)) return false;
17581 1429238 : if (string_->IsFlat()) {
17582 : StringShape shape1(string_);
17583 : StringShape shape2(other);
17584 2135781 : if (shape1.encoding_tag() == kOneByteStringTag &&
17585 : shape2.encoding_tag() == kOneByteStringTag) {
17586 706543 : String::FlatContent flat1 = string_->GetFlatContent(no_gc);
17587 706543 : String::FlatContent flat2 = other->GetFlatContent(no_gc);
17588 706543 : return CompareRawStringContents(flat1.ToOneByteVector().start(),
17589 706543 : flat2.ToOneByteVector().start(), len);
17590 : }
17591 1445390 : if (shape1.encoding_tag() == kTwoByteStringTag &&
17592 : shape2.encoding_tag() == kTwoByteStringTag) {
17593 722695 : String::FlatContent flat1 = string_->GetFlatContent(no_gc);
17594 722695 : String::FlatContent flat2 = other->GetFlatContent(no_gc);
17595 722695 : return CompareRawStringContents(flat1.ToUC16Vector().start(),
17596 722695 : flat2.ToUC16Vector().start(), len);
17597 : }
17598 : }
17599 0 : StringComparator comparator;
17600 0 : return comparator.Equals(string_, other);
17601 : }
17602 :
17603 136346 : String::FlatContent flat_content = other->GetFlatContent(no_gc);
17604 136346 : if (one_byte_) {
17605 136346 : if (flat_content.IsOneByte()) {
17606 : return CompareRawStringContents(
17607 136346 : one_byte_content_, flat_content.ToOneByteVector().start(), len);
17608 : } else {
17609 : DCHECK(flat_content.IsTwoByte());
17610 0 : for (int i = 0; i < len; i++) {
17611 0 : if (flat_content.Get(i) != one_byte_content_[i]) return false;
17612 : }
17613 : return true;
17614 : }
17615 : } else {
17616 0 : if (flat_content.IsTwoByte()) {
17617 : return CompareRawStringContents(
17618 0 : two_byte_content_, flat_content.ToUC16Vector().start(), len);
17619 : } else {
17620 : DCHECK(flat_content.IsOneByte());
17621 0 : for (int i = 0; i < len; i++) {
17622 0 : if (flat_content.Get(i) != two_byte_content_[i]) return false;
17623 : }
17624 : return true;
17625 : }
17626 : }
17627 : }
17628 :
17629 0 : V8_WARN_UNUSED_RESULT Handle<String> AsHandle(Isolate* isolate) override {
17630 0 : UNREACHABLE();
17631 : }
17632 :
17633 : private:
17634 : String string_;
17635 : bool one_byte_;
17636 : bool special_flattening_;
17637 : union {
17638 : uint8_t* one_byte_content_;
17639 : uint16_t* two_byte_content_;
17640 : };
17641 : union {
17642 : uint8_t one_byte_buffer_[256];
17643 : uint16_t two_byte_buffer_[128];
17644 : };
17645 : };
17646 :
17647 : } // namespace
17648 :
17649 : // static
17650 1955588 : Address StringTable::LookupStringIfExists_NoAllocate(Isolate* isolate,
17651 : Address raw_string) {
17652 : DisallowHeapAllocation no_gc;
17653 : String string = String::cast(Object(raw_string));
17654 1955588 : Heap* heap = isolate->heap();
17655 1955588 : StringTable table = heap->string_table();
17656 :
17657 1955588 : StringTableNoAllocateKey key(string, heap->HashSeed());
17658 :
17659 : // String could be an array index.
17660 : uint32_t hash = string->hash_field();
17661 :
17662 : // Valid array indices are >= 0, so they cannot be mixed up with any of
17663 : // the result sentinels, which are negative.
17664 : STATIC_ASSERT(
17665 : !String::ArrayIndexValueBits::is_valid(ResultSentinel::kUnsupported));
17666 : STATIC_ASSERT(
17667 : !String::ArrayIndexValueBits::is_valid(ResultSentinel::kNotFound));
17668 :
17669 1955588 : if (Name::ContainsCachedArrayIndex(hash)) {
17670 50 : return Smi::FromInt(String::ArrayIndexValueBits::decode(hash)).ptr();
17671 : }
17672 1955538 : if ((hash & Name::kIsNotArrayIndexMask) == 0) {
17673 : // It is an indexed, but it's not cached.
17674 : return Smi::FromInt(ResultSentinel::kUnsupported).ptr();
17675 : }
17676 :
17677 : DCHECK(!string->IsInternalizedString());
17678 3910928 : int entry = table->FindEntry(ReadOnlyRoots(isolate), &key, key.Hash());
17679 1955464 : if (entry != kNotFound) {
17680 1565584 : String internalized = String::cast(table->KeyAt(entry));
17681 1565584 : if (FLAG_thin_strings) {
17682 1565584 : MakeStringThin(string, internalized, isolate);
17683 : }
17684 : return internalized.ptr();
17685 : }
17686 : // A string that's not an array index, and not in the string table,
17687 : // cannot have been used as a property name before.
17688 1955588 : return Smi::FromInt(ResultSentinel::kNotFound).ptr();
17689 : }
17690 :
17691 5364 : String StringTable::ForwardStringIfExists(Isolate* isolate, StringTableKey* key,
17692 : String string) {
17693 : Handle<StringTable> table = isolate->factory()->string_table();
17694 5364 : int entry = table->FindEntry(isolate, key);
17695 5364 : if (entry == kNotFound) return String();
17696 :
17697 1224 : String canonical = String::cast(table->KeyAt(entry));
17698 612 : if (canonical != string) MakeStringThin(string, canonical, isolate);
17699 612 : return canonical;
17700 : }
17701 :
17702 12333 : Handle<StringSet> StringSet::New(Isolate* isolate) {
17703 12333 : return HashTable::New(isolate, 0);
17704 : }
17705 :
17706 16507 : Handle<StringSet> StringSet::Add(Isolate* isolate, Handle<StringSet> stringset,
17707 : Handle<String> name) {
17708 16507 : if (!stringset->Has(isolate, name)) {
17709 11613 : stringset = EnsureCapacity(isolate, stringset, 1);
17710 : uint32_t hash = ShapeT::Hash(isolate, *name);
17711 11613 : int entry = stringset->FindInsertionEntry(hash);
17712 23226 : stringset->set(EntryToIndex(entry), *name);
17713 11613 : stringset->ElementAdded();
17714 : }
17715 16507 : return stringset;
17716 : }
17717 :
17718 22219 : bool StringSet::Has(Isolate* isolate, Handle<String> name) {
17719 22219 : return FindEntry(isolate, *name) != kNotFound;
17720 : }
17721 :
17722 106186 : Handle<ObjectHashSet> ObjectHashSet::Add(Isolate* isolate,
17723 : Handle<ObjectHashSet> set,
17724 : Handle<Object> key) {
17725 212372 : int32_t hash = key->GetOrCreateHash(isolate)->value();
17726 106186 : if (!set->Has(isolate, key, hash)) {
17727 104587 : set = EnsureCapacity(isolate, set, 1);
17728 209174 : int entry = set->FindInsertionEntry(hash);
17729 104587 : set->set(EntryToIndex(entry), *key);
17730 104587 : set->ElementAdded();
17731 : }
17732 106186 : return set;
17733 : }
17734 :
17735 : namespace {
17736 :
17737 : const int kLiteralEntryLength = 2;
17738 : const int kLiteralInitialLength = 2;
17739 : const int kLiteralContextOffset = 0;
17740 : const int kLiteralLiteralsOffset = 1;
17741 :
17742 2971619 : int SearchLiteralsMapEntry(CompilationCacheTable cache, int cache_entry,
17743 : Context native_context) {
17744 : DisallowHeapAllocation no_gc;
17745 : DCHECK(native_context->IsNativeContext());
17746 2971619 : Object obj = cache->get(cache_entry);
17747 :
17748 : // Check that there's no confusion between FixedArray and WeakFixedArray (the
17749 : // object used to be a FixedArray here).
17750 : DCHECK(!obj->IsFixedArray());
17751 2971619 : if (obj->IsWeakFixedArray()) {
17752 2971619 : WeakFixedArray literals_map = WeakFixedArray::cast(obj);
17753 : int length = literals_map->length();
17754 7003417 : for (int i = 0; i < length; i += kLiteralEntryLength) {
17755 : DCHECK(literals_map->Get(i + kLiteralContextOffset)->IsWeakOrCleared());
17756 12539298 : if (literals_map->Get(i + kLiteralContextOffset) ==
17757 : HeapObjectReference::Weak(native_context)) {
17758 2237851 : return i;
17759 : }
17760 : }
17761 : }
17762 : return -1;
17763 : }
17764 :
17765 559169 : void AddToFeedbackCellsMap(Handle<CompilationCacheTable> cache, int cache_entry,
17766 : Handle<Context> native_context,
17767 : Handle<FeedbackCell> feedback_cell) {
17768 : Isolate* isolate = native_context->GetIsolate();
17769 : DCHECK(native_context->IsNativeContext());
17770 : STATIC_ASSERT(kLiteralEntryLength == 2);
17771 : Handle<WeakFixedArray> new_literals_map;
17772 : int entry;
17773 :
17774 559169 : Object obj = cache->get(cache_entry);
17775 :
17776 : // Check that there's no confusion between FixedArray and WeakFixedArray (the
17777 : // object used to be a FixedArray here).
17778 : DCHECK(!obj->IsFixedArray());
17779 933818 : if (!obj->IsWeakFixedArray() || WeakFixedArray::cast(obj)->length() == 0) {
17780 : new_literals_map =
17781 184520 : isolate->factory()->NewWeakFixedArray(kLiteralInitialLength, TENURED);
17782 : entry = 0;
17783 : } else {
17784 : Handle<WeakFixedArray> old_literals_map(WeakFixedArray::cast(obj), isolate);
17785 374649 : entry = SearchLiteralsMapEntry(*cache, cache_entry, *native_context);
17786 374649 : if (entry >= 0) {
17787 : // Just set the code of the entry.
17788 : old_literals_map->Set(entry + kLiteralLiteralsOffset,
17789 8154 : HeapObjectReference::Weak(*feedback_cell));
17790 559169 : return;
17791 : }
17792 :
17793 : // Can we reuse an entry?
17794 : DCHECK_LT(entry, 0);
17795 : int length = old_literals_map->length();
17796 1077491 : for (int i = 0; i < length; i += kLiteralEntryLength) {
17797 1458896 : if (old_literals_map->Get(i + kLiteralContextOffset)->IsCleared()) {
17798 : new_literals_map = old_literals_map;
17799 : entry = i;
17800 : break;
17801 : }
17802 : }
17803 :
17804 370572 : if (entry < 0) {
17805 : // Copy old optimized code map and append one new entry.
17806 : new_literals_map = isolate->factory()->CopyWeakFixedArrayAndGrow(
17807 348043 : old_literals_map, kLiteralEntryLength, TENURED);
17808 : entry = old_literals_map->length();
17809 : }
17810 : }
17811 :
17812 : new_literals_map->Set(entry + kLiteralContextOffset,
17813 1110184 : HeapObjectReference::Weak(*native_context));
17814 : new_literals_map->Set(entry + kLiteralLiteralsOffset,
17815 1110184 : HeapObjectReference::Weak(*feedback_cell));
17816 :
17817 : #ifdef DEBUG
17818 : for (int i = 0; i < new_literals_map->length(); i += kLiteralEntryLength) {
17819 : MaybeObject object = new_literals_map->Get(i + kLiteralContextOffset);
17820 : DCHECK(object->IsCleared() ||
17821 : object->GetHeapObjectAssumeWeak()->IsNativeContext());
17822 : object = new_literals_map->Get(i + kLiteralLiteralsOffset);
17823 : DCHECK(object->IsCleared() ||
17824 : object->GetHeapObjectAssumeWeak()->IsFeedbackCell());
17825 : }
17826 : #endif
17827 :
17828 : Object old_literals_map = cache->get(cache_entry);
17829 555092 : if (old_literals_map != *new_literals_map) {
17830 1065126 : cache->set(cache_entry, *new_literals_map);
17831 : }
17832 : }
17833 :
17834 2596970 : FeedbackCell SearchLiteralsMap(CompilationCacheTable cache, int cache_entry,
17835 : Context native_context) {
17836 : FeedbackCell result;
17837 2596970 : int entry = SearchLiteralsMapEntry(cache, cache_entry, native_context);
17838 2596970 : if (entry >= 0) {
17839 2233774 : WeakFixedArray literals_map = WeakFixedArray::cast(cache->get(cache_entry));
17840 : DCHECK_LE(entry + kLiteralEntryLength, literals_map->length());
17841 2233774 : MaybeObject object = literals_map->Get(entry + kLiteralLiteralsOffset);
17842 :
17843 2233774 : if (!object->IsCleared()) {
17844 : result = FeedbackCell::cast(object->GetHeapObjectAssumeWeak());
17845 : }
17846 : }
17847 : DCHECK(result.is_null() || result->IsFeedbackCell());
17848 2596970 : return result;
17849 : }
17850 :
17851 : } // namespace
17852 :
17853 271788 : MaybeHandle<SharedFunctionInfo> CompilationCacheTable::LookupScript(
17854 : Handle<CompilationCacheTable> table, Handle<String> src,
17855 : Handle<Context> native_context, LanguageMode language_mode) {
17856 : // We use the empty function SFI as part of the key. Although the
17857 : // empty_function is native context dependent, the SFI is de-duped on
17858 : // snapshot builds by the PartialSnapshotCache, and so this does not prevent
17859 : // reuse of scripts in the compilation cache across native contexts.
17860 543576 : Handle<SharedFunctionInfo> shared(native_context->empty_function()->shared(),
17861 543576 : native_context->GetIsolate());
17862 : Isolate* isolate = native_context->GetIsolate();
17863 271788 : src = String::Flatten(isolate, src);
17864 271788 : StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17865 271788 : int entry = table->FindEntry(isolate, &key);
17866 271788 : if (entry == kNotFound) return MaybeHandle<SharedFunctionInfo>();
17867 : int index = EntryToIndex(entry);
17868 261348 : if (!table->get(index)->IsFixedArray()) {
17869 0 : return MaybeHandle<SharedFunctionInfo>();
17870 : }
17871 261348 : Object obj = table->get(index + 1);
17872 130674 : if (obj->IsSharedFunctionInfo()) {
17873 130674 : return handle(SharedFunctionInfo::cast(obj), native_context->GetIsolate());
17874 : }
17875 0 : return MaybeHandle<SharedFunctionInfo>();
17876 : }
17877 :
17878 3521393 : InfoCellPair CompilationCacheTable::LookupEval(
17879 : Handle<CompilationCacheTable> table, Handle<String> src,
17880 : Handle<SharedFunctionInfo> outer_info, Handle<Context> native_context,
17881 : LanguageMode language_mode, int position) {
17882 : InfoCellPair empty_result;
17883 : Isolate* isolate = native_context->GetIsolate();
17884 3521393 : src = String::Flatten(isolate, src);
17885 3521393 : StringSharedKey key(src, outer_info, language_mode, position);
17886 3521393 : int entry = table->FindEntry(isolate, &key);
17887 3521393 : if (entry == kNotFound) return empty_result;
17888 : int index = EntryToIndex(entry);
17889 5558416 : if (!table->get(index)->IsFixedArray()) return empty_result;
17890 5193940 : Object obj = table->get(EntryToIndex(entry) + 1);
17891 2596970 : if (obj->IsSharedFunctionInfo()) {
17892 : FeedbackCell feedback_cell =
17893 5193940 : SearchLiteralsMap(*table, EntryToIndex(entry) + 2, *native_context);
17894 2596970 : return InfoCellPair(SharedFunctionInfo::cast(obj), feedback_cell);
17895 : }
17896 0 : return empty_result;
17897 : }
17898 :
17899 753104 : Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src,
17900 : JSRegExp::Flags flags) {
17901 : Isolate* isolate = GetIsolate();
17902 : DisallowHeapAllocation no_allocation;
17903 753104 : RegExpKey key(src, flags);
17904 753104 : int entry = FindEntry(isolate, &key);
17905 1338366 : if (entry == kNotFound) return isolate->factory()->undefined_value();
17906 335684 : return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
17907 : }
17908 :
17909 140120 : Handle<CompilationCacheTable> CompilationCacheTable::PutScript(
17910 : Handle<CompilationCacheTable> cache, Handle<String> src,
17911 : Handle<Context> native_context, LanguageMode language_mode,
17912 : Handle<SharedFunctionInfo> value) {
17913 : Isolate* isolate = native_context->GetIsolate();
17914 : // We use the empty function SFI as part of the key. Although the
17915 : // empty_function is native context dependent, the SFI is de-duped on
17916 : // snapshot builds by the PartialSnapshotCache, and so this does not prevent
17917 : // reuse of scripts in the compilation cache across native contexts.
17918 280240 : Handle<SharedFunctionInfo> shared(native_context->empty_function()->shared(),
17919 280240 : isolate);
17920 140120 : src = String::Flatten(isolate, src);
17921 140120 : StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17922 140120 : Handle<Object> k = key.AsHandle(isolate);
17923 140120 : cache = EnsureCapacity(isolate, cache, 1);
17924 280240 : int entry = cache->FindInsertionEntry(key.Hash());
17925 140120 : cache->set(EntryToIndex(entry), *k);
17926 280240 : cache->set(EntryToIndex(entry) + 1, *value);
17927 140120 : cache->ElementAdded();
17928 140120 : return cache;
17929 : }
17930 :
17931 1187312 : Handle<CompilationCacheTable> CompilationCacheTable::PutEval(
17932 : Handle<CompilationCacheTable> cache, Handle<String> src,
17933 : Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value,
17934 : Handle<Context> native_context, Handle<FeedbackCell> feedback_cell,
17935 : int position) {
17936 : Isolate* isolate = native_context->GetIsolate();
17937 1187312 : src = String::Flatten(isolate, src);
17938 1187312 : StringSharedKey key(src, outer_info, value->language_mode(), position);
17939 : {
17940 1187312 : Handle<Object> k = key.AsHandle(isolate);
17941 1187312 : int entry = cache->FindEntry(isolate, &key);
17942 1187312 : if (entry != kNotFound) {
17943 559169 : cache->set(EntryToIndex(entry), *k);
17944 1118338 : cache->set(EntryToIndex(entry) + 1, *value);
17945 : // AddToFeedbackCellsMap may allocate a new sub-array to live in the
17946 : // entry, but it won't change the cache array. Therefore EntryToIndex
17947 : // and entry remains correct.
17948 : AddToFeedbackCellsMap(cache, EntryToIndex(entry) + 2, native_context,
17949 559169 : feedback_cell);
17950 559169 : return cache;
17951 : }
17952 : }
17953 :
17954 628143 : cache = EnsureCapacity(isolate, cache, 1);
17955 1256286 : int entry = cache->FindInsertionEntry(key.Hash());
17956 : Handle<Object> k =
17957 628143 : isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
17958 628143 : cache->set(EntryToIndex(entry), *k);
17959 : cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
17960 628143 : cache->ElementAdded();
17961 628143 : return cache;
17962 : }
17963 :
17964 290076 : Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp(
17965 : Isolate* isolate, Handle<CompilationCacheTable> cache, Handle<String> src,
17966 : JSRegExp::Flags flags, Handle<FixedArray> value) {
17967 290076 : RegExpKey key(src, flags);
17968 290076 : cache = EnsureCapacity(isolate, cache, 1);
17969 580152 : int entry = cache->FindInsertionEntry(key.Hash());
17970 : // We store the value in the key slot, and compare the search key
17971 : // to the stored value with a custon IsMatch function during lookups.
17972 580152 : cache->set(EntryToIndex(entry), *value);
17973 580152 : cache->set(EntryToIndex(entry) + 1, *value);
17974 290076 : cache->ElementAdded();
17975 290076 : return cache;
17976 : }
17977 :
17978 :
17979 76391 : void CompilationCacheTable::Age() {
17980 : DisallowHeapAllocation no_allocation;
17981 152782 : Object the_hole_value = GetReadOnlyRoots().the_hole_value();
17982 12336526 : for (int entry = 0, size = Capacity(); entry < size; entry++) {
17983 : int entry_index = EntryToIndex(entry);
17984 12183744 : int value_index = entry_index + 1;
17985 :
17986 24367488 : if (get(entry_index)->IsNumber()) {
17987 : Smi count = Smi::cast(get(value_index));
17988 967970 : count = Smi::FromInt(count->value() - 1);
17989 967970 : if (count->value() == 0) {
17990 : NoWriteBarrierSet(*this, entry_index, the_hole_value);
17991 : NoWriteBarrierSet(*this, value_index, the_hole_value);
17992 75420 : ElementRemoved();
17993 : } else {
17994 : NoWriteBarrierSet(*this, value_index, count);
17995 : }
17996 22431548 : } else if (get(entry_index)->IsFixedArray()) {
17997 393236 : SharedFunctionInfo info = SharedFunctionInfo::cast(get(value_index));
17998 786472 : if (info->IsInterpreted() && info->GetBytecodeArray()->IsOld()) {
17999 76845 : for (int i = 0; i < kEntrySize; i++) {
18000 76845 : NoWriteBarrierSet(*this, entry_index + i, the_hole_value);
18001 : }
18002 25615 : ElementRemoved();
18003 : }
18004 : }
18005 : }
18006 76391 : }
18007 :
18008 804 : void CompilationCacheTable::Remove(Object value) {
18009 : DisallowHeapAllocation no_allocation;
18010 1608 : Object the_hole_value = GetReadOnlyRoots().the_hole_value();
18011 104520 : for (int entry = 0, size = Capacity(); entry < size; entry++) {
18012 : int entry_index = EntryToIndex(entry);
18013 102912 : int value_index = entry_index + 1;
18014 102912 : if (get(value_index) == value) {
18015 426 : for (int i = 0; i < kEntrySize; i++) {
18016 426 : NoWriteBarrierSet(*this, entry_index + i, the_hole_value);
18017 : }
18018 142 : ElementRemoved();
18019 : }
18020 : }
18021 804 : return;
18022 : }
18023 :
18024 : template <typename Derived, typename Shape>
18025 780554 : Handle<Derived> BaseNameDictionary<Derived, Shape>::New(
18026 : Isolate* isolate, int at_least_space_for, PretenureFlag pretenure,
18027 : MinimumCapacity capacity_option) {
18028 : DCHECK_LE(0, at_least_space_for);
18029 : Handle<Derived> dict = Dictionary<Derived, Shape>::New(
18030 780554 : isolate, at_least_space_for, pretenure, capacity_option);
18031 : dict->SetHash(PropertyArray::kNoHashSentinel);
18032 : dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
18033 780559 : return dict;
18034 : }
18035 :
18036 : template <typename Derived, typename Shape>
18037 14210588 : Handle<Derived> BaseNameDictionary<Derived, Shape>::EnsureCapacity(
18038 : Isolate* isolate, Handle<Derived> dictionary, int n) {
18039 : // Check whether there are enough enumeration indices to add n elements.
18040 28421172 : if (!PropertyDetails::IsValidIndex(dictionary->NextEnumerationIndex() + n)) {
18041 : // If not, we generate new indices for the properties.
18042 0 : int length = dictionary->NumberOfElements();
18043 :
18044 0 : Handle<FixedArray> iteration_order = IterationIndices(isolate, dictionary);
18045 : DCHECK_EQ(length, iteration_order->length());
18046 :
18047 : // Iterate over the dictionary using the enumeration order and update
18048 : // the dictionary with new enumeration indices.
18049 0 : for (int i = 0; i < length; i++) {
18050 0 : int index = Smi::ToInt(iteration_order->get(i));
18051 : DCHECK(dictionary->IsKey(dictionary->GetReadOnlyRoots(),
18052 : dictionary->KeyAt(index)));
18053 :
18054 0 : int enum_index = PropertyDetails::kInitialIndex + i;
18055 :
18056 0 : PropertyDetails details = dictionary->DetailsAt(index);
18057 0 : PropertyDetails new_details = details.set_index(enum_index);
18058 0 : dictionary->DetailsAtPut(isolate, index, new_details);
18059 : }
18060 :
18061 : // Set the next enumeration index.
18062 0 : dictionary->SetNextEnumerationIndex(PropertyDetails::kInitialIndex +
18063 : length);
18064 : }
18065 14210586 : return HashTable<Derived, Shape>::EnsureCapacity(isolate, dictionary, n);
18066 : }
18067 :
18068 : template <typename Derived, typename Shape>
18069 47172 : Handle<Derived> Dictionary<Derived, Shape>::DeleteEntry(
18070 : Isolate* isolate, Handle<Derived> dictionary, int entry) {
18071 : DCHECK(Shape::kEntrySize != 3 ||
18072 : dictionary->DetailsAt(entry).IsConfigurable());
18073 47172 : dictionary->ClearEntry(isolate, entry);
18074 47172 : dictionary->ElementRemoved();
18075 47172 : return Shrink(isolate, dictionary);
18076 : }
18077 :
18078 : template <typename Derived, typename Shape>
18079 491422 : Handle<Derived> Dictionary<Derived, Shape>::AtPut(Isolate* isolate,
18080 : Handle<Derived> dictionary,
18081 : Key key, Handle<Object> value,
18082 : PropertyDetails details) {
18083 491422 : int entry = dictionary->FindEntry(isolate, key);
18084 :
18085 : // If the entry is present set the value;
18086 491422 : if (entry == Dictionary::kNotFound) {
18087 489002 : return Derived::Add(isolate, dictionary, key, value, details);
18088 : }
18089 :
18090 : // We don't need to copy over the enumeration index.
18091 4840 : dictionary->ValueAtPut(entry, *value);
18092 2360 : if (Shape::kEntrySize == 3) dictionary->DetailsAtPut(isolate, entry, details);
18093 2420 : return dictionary;
18094 : }
18095 :
18096 : template <typename Derived, typename Shape>
18097 : Handle<Derived>
18098 5974452 : BaseNameDictionary<Derived, Shape>::AddNoUpdateNextEnumerationIndex(
18099 : Isolate* isolate, Handle<Derived> dictionary, Key key, Handle<Object> value,
18100 : PropertyDetails details, int* entry_out) {
18101 : // Insert element at empty or deleted entry
18102 : return Dictionary<Derived, Shape>::Add(isolate, dictionary, key, value,
18103 14210576 : details, entry_out);
18104 : }
18105 :
18106 : // GCC workaround: Explicitly instantiate template method for NameDictionary
18107 : // to avoid "undefined reference" issues during linking.
18108 : template Handle<NameDictionary>
18109 : BaseNameDictionary<NameDictionary, NameDictionaryShape>::
18110 : AddNoUpdateNextEnumerationIndex(Isolate* isolate, Handle<NameDictionary>,
18111 : Handle<Name>, Handle<Object>,
18112 : PropertyDetails, int*);
18113 :
18114 : template <typename Derived, typename Shape>
18115 14174865 : Handle<Derived> BaseNameDictionary<Derived, Shape>::Add(
18116 : Isolate* isolate, Handle<Derived> dictionary, Key key, Handle<Object> value,
18117 : PropertyDetails details, int* entry_out) {
18118 : // Insert element at empty or deleted entry
18119 : DCHECK_EQ(0, details.dictionary_index());
18120 : // Assign an enumeration index to the property and update
18121 : // SetNextEnumerationIndex.
18122 14174865 : int index = dictionary->NextEnumerationIndex();
18123 : details = details.set_index(index);
18124 5938758 : dictionary = AddNoUpdateNextEnumerationIndex(isolate, dictionary, key, value,
18125 : details, entry_out);
18126 : // Update enumeration index here in order to avoid potential modification of
18127 : // the canonical empty dictionary which lives in read only space.
18128 14174893 : dictionary->SetNextEnumerationIndex(index + 1);
18129 14174893 : return dictionary;
18130 : }
18131 :
18132 : template <typename Derived, typename Shape>
18133 18064860 : Handle<Derived> Dictionary<Derived, Shape>::Add(Isolate* isolate,
18134 : Handle<Derived> dictionary,
18135 : Key key, Handle<Object> value,
18136 : PropertyDetails details,
18137 : int* entry_out) {
18138 18064860 : uint32_t hash = Shape::Hash(isolate, key);
18139 : // Valdate key is absent.
18140 : SLOW_DCHECK((dictionary->FindEntry(isolate, key) == Dictionary::kNotFound));
18141 : // Check whether the dictionary should be extended.
18142 18064869 : dictionary = Derived::EnsureCapacity(isolate, dictionary, 1);
18143 :
18144 : // Compute the key object.
18145 : Handle<Object> k = Shape::AsHandle(isolate, key);
18146 :
18147 18064875 : uint32_t entry = dictionary->FindInsertionEntry(hash);
18148 36129732 : dictionary->SetEntry(isolate, entry, *k, *value, details);
18149 : DCHECK(dictionary->KeyAt(entry)->IsNumber() ||
18150 : Shape::Unwrap(dictionary->KeyAt(entry))->IsUniqueName());
18151 18064872 : dictionary->ElementAdded();
18152 18064873 : if (entry_out) *entry_out = entry;
18153 18064873 : return dictionary;
18154 : }
18155 :
18156 : // static
18157 85337 : Handle<SimpleNumberDictionary> SimpleNumberDictionary::Set(
18158 : Isolate* isolate, Handle<SimpleNumberDictionary> dictionary, uint32_t key,
18159 : Handle<Object> value) {
18160 85337 : return AtPut(isolate, dictionary, key, value, PropertyDetails::Empty());
18161 : }
18162 :
18163 0 : bool NumberDictionary::HasComplexElements() {
18164 0 : if (!requires_slow_elements()) return false;
18165 0 : ReadOnlyRoots roots = GetReadOnlyRoots();
18166 0 : int capacity = this->Capacity();
18167 0 : for (int i = 0; i < capacity; i++) {
18168 0 : Object k;
18169 0 : if (!this->ToKey(roots, i, &k)) continue;
18170 0 : PropertyDetails details = this->DetailsAt(i);
18171 0 : if (details.kind() == kAccessor) return true;
18172 : PropertyAttributes attr = details.attributes();
18173 0 : if (attr & ALL_ATTRIBUTES_MASK) return true;
18174 : }
18175 : return false;
18176 : }
18177 :
18178 1481387 : void NumberDictionary::UpdateMaxNumberKey(uint32_t key,
18179 : Handle<JSObject> dictionary_holder) {
18180 : DisallowHeapAllocation no_allocation;
18181 : // If the dictionary requires slow elements an element has already
18182 : // been added at a high index.
18183 1528914 : if (requires_slow_elements()) return;
18184 : // Check if this index is high enough that we should require slow
18185 : // elements.
18186 1435561 : if (key > kRequiresSlowElementsLimit) {
18187 1701 : if (!dictionary_holder.is_null()) {
18188 1449 : dictionary_holder->RequireSlowElements(*this);
18189 : }
18190 : set_requires_slow_elements();
18191 : return;
18192 : }
18193 : // Update max key value.
18194 1433860 : Object max_index_object = get(kMaxNumberKeyIndex);
18195 1433860 : if (!max_index_object->IsSmi() || max_number_key() < key) {
18196 : FixedArray::set(kMaxNumberKeyIndex,
18197 1146661 : Smi::FromInt(key << kRequiresSlowElementsTagSize));
18198 : }
18199 : }
18200 :
18201 406085 : Handle<NumberDictionary> NumberDictionary::Set(
18202 : Isolate* isolate, Handle<NumberDictionary> dictionary, uint32_t key,
18203 : Handle<Object> value, Handle<JSObject> dictionary_holder,
18204 : PropertyDetails details) {
18205 406085 : dictionary->UpdateMaxNumberKey(key, dictionary_holder);
18206 406085 : return AtPut(isolate, dictionary, key, value, details);
18207 : }
18208 :
18209 36 : void NumberDictionary::CopyValuesTo(FixedArray elements) {
18210 36 : ReadOnlyRoots roots = GetReadOnlyRoots();
18211 : int pos = 0;
18212 36 : int capacity = this->Capacity();
18213 : DisallowHeapAllocation no_gc;
18214 : WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
18215 612 : for (int i = 0; i < capacity; i++) {
18216 576 : Object k;
18217 576 : if (this->ToKey(roots, i, &k)) {
18218 270 : elements->set(pos++, this->ValueAt(i), mode);
18219 : }
18220 : }
18221 : DCHECK_EQ(pos, elements->length());
18222 36 : }
18223 :
18224 : template <typename Derived, typename Shape>
18225 43091 : int Dictionary<Derived, Shape>::NumberOfEnumerableProperties() {
18226 43091 : ReadOnlyRoots roots = this->GetReadOnlyRoots();
18227 43091 : int capacity = this->Capacity();
18228 : int result = 0;
18229 14611039 : for (int i = 0; i < capacity; i++) {
18230 14567948 : Object k;
18231 22191343 : if (!this->ToKey(roots, i, &k)) continue;
18232 6981055 : if (k->FilterKey(ENUMERABLE_STRINGS)) continue;
18233 6944553 : PropertyDetails details = this->DetailsAt(i);
18234 : PropertyAttributes attr = details.attributes();
18235 6944553 : if ((attr & ONLY_ENUMERABLE) == 0) result++;
18236 : }
18237 43091 : return result;
18238 : }
18239 :
18240 :
18241 : template <typename Dictionary>
18242 : struct EnumIndexComparator {
18243 492997 : explicit EnumIndexComparator(Dictionary dict) : dict(dict) {}
18244 119557023 : bool operator()(Tagged_t a, Tagged_t b) {
18245 : // TODO(ishell): revisit the code below
18246 : STATIC_ASSERT(kTaggedSize == kSystemPointerSize);
18247 119557023 : PropertyDetails da(dict->DetailsAt(Smi(a).value()));
18248 119557043 : PropertyDetails db(dict->DetailsAt(Smi(b).value()));
18249 119557043 : return da.dictionary_index() < db.dictionary_index();
18250 : }
18251 : Dictionary dict;
18252 : };
18253 :
18254 : template <typename Derived, typename Shape>
18255 42875 : void BaseNameDictionary<Derived, Shape>::CopyEnumKeysTo(
18256 : Isolate* isolate, Handle<Derived> dictionary, Handle<FixedArray> storage,
18257 : KeyCollectionMode mode, KeyAccumulator* accumulator) {
18258 : DCHECK_IMPLIES(mode != KeyCollectionMode::kOwnOnly, accumulator != nullptr);
18259 : int length = storage->length();
18260 42875 : int capacity = dictionary->Capacity();
18261 : int properties = 0;
18262 : ReadOnlyRoots roots(isolate);
18263 14037761 : for (int i = 0; i < capacity; i++) {
18264 14037323 : Object key;
18265 23281682 : if (!dictionary->ToKey(roots, i, &key)) continue;
18266 : bool is_shadowing_key = false;
18267 6911840 : if (key->IsSymbol()) continue;
18268 6875359 : PropertyDetails details = dictionary->DetailsAt(i);
18269 6875359 : if (details.IsDontEnum()) {
18270 2082395 : if (mode == KeyCollectionMode::kIncludePrototypes) {
18271 : is_shadowing_key = true;
18272 : } else {
18273 : continue;
18274 : }
18275 : }
18276 4805236 : if (is_shadowing_key) {
18277 12272 : accumulator->AddShadowingKey(key);
18278 12272 : continue;
18279 : } else {
18280 : storage->set(properties, Smi::FromInt(i));
18281 : }
18282 4792964 : properties++;
18283 4792964 : if (mode == KeyCollectionMode::kOwnOnly && properties == length) break;
18284 : }
18285 :
18286 42875 : CHECK_EQ(length, properties);
18287 : DisallowHeapAllocation no_gc;
18288 42875 : Derived raw_dictionary = *dictionary;
18289 42875 : FixedArray raw_storage = *storage;
18290 : EnumIndexComparator<Derived> cmp(raw_dictionary);
18291 : // Use AtomicSlot wrapper to ensure that std::sort uses atomic load and
18292 : // store operations that are safe for concurrent marking.
18293 : AtomicSlot start(storage->GetFirstElementAddress());
18294 42875 : std::sort(start, start + length, cmp);
18295 4835839 : for (int i = 0; i < length; i++) {
18296 4792964 : int index = Smi::ToInt(raw_storage->get(i));
18297 4792964 : raw_storage->set(i, raw_dictionary->NameAt(index));
18298 : }
18299 42875 : }
18300 :
18301 : template <typename Derived, typename Shape>
18302 426685 : Handle<FixedArray> BaseNameDictionary<Derived, Shape>::IterationIndices(
18303 : Isolate* isolate, Handle<Derived> dictionary) {
18304 426685 : int capacity = dictionary->Capacity();
18305 426686 : int length = dictionary->NumberOfElements();
18306 426688 : Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
18307 : ReadOnlyRoots roots(isolate);
18308 : int array_size = 0;
18309 : {
18310 : DisallowHeapAllocation no_gc;
18311 426679 : Derived raw_dictionary = *dictionary;
18312 16228252 : for (int i = 0; i < capacity; i++) {
18313 15801563 : Object k;
18314 24877767 : if (!raw_dictionary->ToKey(roots, i, &k)) continue;
18315 6725379 : array->set(array_size++, Smi::FromInt(i));
18316 : }
18317 :
18318 : DCHECK_EQ(array_size, length);
18319 :
18320 : EnumIndexComparator<Derived> cmp(raw_dictionary);
18321 : // Use AtomicSlot wrapper to ensure that std::sort uses atomic load and
18322 : // store operations that are safe for concurrent marking.
18323 : AtomicSlot start(array->GetFirstElementAddress());
18324 426689 : std::sort(start, start + array_size, cmp);
18325 : }
18326 426689 : return FixedArray::ShrinkOrEmpty(isolate, array, array_size);
18327 : }
18328 :
18329 : template <typename Derived, typename Shape>
18330 23433 : void BaseNameDictionary<Derived, Shape>::CollectKeysTo(
18331 : Handle<Derived> dictionary, KeyAccumulator* keys) {
18332 : Isolate* isolate = keys->isolate();
18333 : ReadOnlyRoots roots(isolate);
18334 23433 : int capacity = dictionary->Capacity();
18335 : Handle<FixedArray> array =
18336 23433 : isolate->factory()->NewFixedArray(dictionary->NumberOfElements());
18337 : int array_size = 0;
18338 : PropertyFilter filter = keys->filter();
18339 : {
18340 : DisallowHeapAllocation no_gc;
18341 23433 : Derived raw_dictionary = *dictionary;
18342 6304905 : for (int i = 0; i < capacity; i++) {
18343 6281472 : Object k;
18344 9660993 : if (!raw_dictionary->ToKey(roots, i, &k)) continue;
18345 2917344 : if (k->FilterKey(filter)) continue;
18346 2902911 : PropertyDetails details = raw_dictionary->DetailsAt(i);
18347 2902911 : if ((details.attributes() & filter) != 0) {
18348 590 : keys->AddShadowingKey(k);
18349 590 : continue;
18350 : }
18351 2902321 : if (filter & ONLY_ALL_CAN_READ) {
18352 756 : if (details.kind() != kAccessor) continue;
18353 26 : Object accessors = raw_dictionary->ValueAt(i);
18354 26 : if (!accessors->IsAccessorInfo()) continue;
18355 26 : if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
18356 : }
18357 2901951 : array->set(array_size++, Smi::FromInt(i));
18358 : }
18359 :
18360 : EnumIndexComparator<Derived> cmp(raw_dictionary);
18361 : // Use AtomicSlot wrapper to ensure that std::sort uses atomic load and
18362 : // store operations that are safe for concurrent marking.
18363 : AtomicSlot start(array->GetFirstElementAddress());
18364 23433 : std::sort(start, start + array_size, cmp);
18365 : }
18366 :
18367 : bool has_seen_symbol = false;
18368 2925384 : for (int i = 0; i < array_size; i++) {
18369 2901951 : int index = Smi::ToInt(array->get(i));
18370 5736567 : Object key = dictionary->NameAt(index);
18371 2901951 : if (key->IsSymbol()) {
18372 : has_seen_symbol = true;
18373 18219 : continue;
18374 : }
18375 2883732 : keys->AddKey(key, DO_NOT_CONVERT);
18376 : }
18377 23433 : if (has_seen_symbol) {
18378 2288242 : for (int i = 0; i < array_size; i++) {
18379 2288242 : int index = Smi::ToInt(array->get(i));
18380 4575943 : Object key = dictionary->NameAt(index);
18381 4558265 : if (!key->IsSymbol()) continue;
18382 18219 : keys->AddKey(key, DO_NOT_CONVERT);
18383 : }
18384 : }
18385 23433 : }
18386 :
18387 : // Backwards lookup (slow).
18388 : template <typename Derived, typename Shape>
18389 27 : Object Dictionary<Derived, Shape>::SlowReverseLookup(Object value) {
18390 27 : Derived dictionary = Derived::cast(*this);
18391 27 : ReadOnlyRoots roots = dictionary->GetReadOnlyRoots();
18392 27 : int capacity = dictionary->Capacity();
18393 6939 : for (int i = 0; i < capacity; i++) {
18394 6912 : Object k;
18395 10224 : if (!dictionary->ToKey(roots, i, &k)) continue;
18396 0 : Object e = dictionary->ValueAt(i);
18397 3600 : if (e == value) return k;
18398 : }
18399 27 : return roots.undefined_value();
18400 : }
18401 :
18402 : template <typename Derived, typename Shape>
18403 352 : void ObjectHashTableBase<Derived, Shape>::FillEntriesWithHoles(
18404 : Handle<Derived> table) {
18405 : int length = table->length();
18406 49144 : for (int i = Derived::EntryToIndex(0); i < length; i++) {
18407 48792 : table->set_the_hole(i);
18408 : }
18409 352 : }
18410 :
18411 : template <typename Derived, typename Shape>
18412 36477 : Object ObjectHashTableBase<Derived, Shape>::Lookup(ReadOnlyRoots roots,
18413 : Handle<Object> key,
18414 : int32_t hash) {
18415 : DisallowHeapAllocation no_gc;
18416 : DCHECK(this->IsKey(roots, *key));
18417 :
18418 36477 : int entry = this->FindEntry(roots, key, hash);
18419 37230 : if (entry == kNotFound) return roots.the_hole_value();
18420 35724 : return this->get(Derived::EntryToIndex(entry) + 1);
18421 : }
18422 :
18423 : template <typename Derived, typename Shape>
18424 36980 : Object ObjectHashTableBase<Derived, Shape>::Lookup(Handle<Object> key) {
18425 : DisallowHeapAllocation no_gc;
18426 :
18427 36980 : ReadOnlyRoots roots = this->GetReadOnlyRoots();
18428 : DCHECK(this->IsKey(roots, *key));
18429 :
18430 : // If the object does not have an identity hash, it was never used as a key.
18431 36980 : Object hash = key->GetHash();
18432 36980 : if (hash->IsUndefined(roots)) {
18433 510 : return roots.the_hole_value();
18434 : }
18435 36470 : return Lookup(roots, key, Smi::ToInt(hash));
18436 : }
18437 :
18438 : template <typename Derived, typename Shape>
18439 0 : Object ObjectHashTableBase<Derived, Shape>::Lookup(Handle<Object> key,
18440 : int32_t hash) {
18441 0 : return Lookup(this->GetReadOnlyRoots(), key, hash);
18442 : }
18443 :
18444 : template <typename Derived, typename Shape>
18445 205 : Object ObjectHashTableBase<Derived, Shape>::ValueAt(int entry) {
18446 205 : return this->get(EntryToValueIndex(entry));
18447 : }
18448 :
18449 : template <typename Derived, typename Shape>
18450 32379 : Handle<Derived> ObjectHashTableBase<Derived, Shape>::Put(Handle<Derived> table,
18451 : Handle<Object> key,
18452 : Handle<Object> value) {
18453 : Isolate* isolate = Heap::FromWritableHeapObject(*table)->isolate();
18454 : DCHECK(table->IsKey(ReadOnlyRoots(isolate), *key));
18455 : DCHECK(!value->IsTheHole(ReadOnlyRoots(isolate)));
18456 :
18457 : // Make sure the key object has an identity hash code.
18458 64758 : int32_t hash = key->GetOrCreateHash(isolate)->value();
18459 :
18460 : return ObjectHashTableBase<Derived, Shape>::Put(isolate, table, key, value,
18461 32379 : hash);
18462 : }
18463 :
18464 : template <typename Derived, typename Shape>
18465 33351 : Handle<Derived> ObjectHashTableBase<Derived, Shape>::Put(Isolate* isolate,
18466 : Handle<Derived> table,
18467 : Handle<Object> key,
18468 : Handle<Object> value,
18469 : int32_t hash) {
18470 : ReadOnlyRoots roots(isolate);
18471 : DCHECK(table->IsKey(roots, *key));
18472 : DCHECK(!value->IsTheHole(roots));
18473 :
18474 33351 : int entry = table->FindEntry(roots, key, hash);
18475 :
18476 : // Key is already in table, just overwrite value.
18477 33351 : if (entry != kNotFound) {
18478 882 : table->set(Derived::EntryToIndex(entry) + 1, *value);
18479 441 : return table;
18480 : }
18481 :
18482 : // Rehash if more than 33% of the entries are deleted entries.
18483 : // TODO(jochen): Consider to shrink the fixed array in place.
18484 65820 : if ((table->NumberOfDeletedElements() << 1) > table->NumberOfElements()) {
18485 5 : table->Rehash(isolate);
18486 : }
18487 : // If we're out of luck, we didn't get a GC recently, and so rehashing
18488 : // isn't enough to avoid a crash.
18489 32910 : if (!table->HasSufficientCapacityToAdd(1)) {
18490 452 : int nof = table->NumberOfElements() + 1;
18491 452 : int capacity = ObjectHashTable::ComputeCapacity(nof * 2);
18492 452 : if (capacity > ObjectHashTable::kMaxCapacity) {
18493 0 : for (size_t i = 0; i < 2; ++i) {
18494 0 : isolate->heap()->CollectAllGarbage(
18495 0 : Heap::kNoGCFlags, GarbageCollectionReason::kFullHashtable);
18496 : }
18497 0 : table->Rehash(isolate);
18498 : }
18499 : }
18500 :
18501 : // Check whether the hash table should be extended.
18502 32910 : table = Derived::EnsureCapacity(isolate, table, 1);
18503 98730 : table->AddEntry(table->FindInsertionEntry(hash), *key, *value);
18504 32910 : return table;
18505 : }
18506 :
18507 : template <typename Derived, typename Shape>
18508 5 : Handle<Derived> ObjectHashTableBase<Derived, Shape>::Remove(
18509 : Isolate* isolate, Handle<Derived> table, Handle<Object> key,
18510 : bool* was_present) {
18511 : DCHECK(table->IsKey(table->GetReadOnlyRoots(), *key));
18512 :
18513 5 : Object hash = key->GetHash();
18514 5 : if (hash->IsUndefined()) {
18515 0 : *was_present = false;
18516 0 : return table;
18517 : }
18518 :
18519 5 : return Remove(isolate, table, key, was_present, Smi::ToInt(hash));
18520 : }
18521 :
18522 : template <typename Derived, typename Shape>
18523 5 : Handle<Derived> ObjectHashTableBase<Derived, Shape>::Remove(
18524 : Isolate* isolate, Handle<Derived> table, Handle<Object> key,
18525 : bool* was_present, int32_t hash) {
18526 5 : ReadOnlyRoots roots = table->GetReadOnlyRoots();
18527 : DCHECK(table->IsKey(roots, *key));
18528 :
18529 5 : int entry = table->FindEntry(roots, key, hash);
18530 5 : if (entry == kNotFound) {
18531 0 : *was_present = false;
18532 0 : return table;
18533 : }
18534 :
18535 5 : *was_present = true;
18536 5 : table->RemoveEntry(entry);
18537 5 : return Derived::Shrink(isolate, table);
18538 : }
18539 :
18540 : template <typename Derived, typename Shape>
18541 32910 : void ObjectHashTableBase<Derived, Shape>::AddEntry(int entry, Object key,
18542 : Object value) {
18543 32910 : this->set(Derived::EntryToIndex(entry), key);
18544 32910 : this->set(Derived::EntryToIndex(entry) + 1, value);
18545 32910 : this->ElementAdded();
18546 32910 : }
18547 :
18548 : template <typename Derived, typename Shape>
18549 83 : void ObjectHashTableBase<Derived, Shape>::RemoveEntry(int entry) {
18550 83 : this->set_the_hole(Derived::EntryToIndex(entry));
18551 83 : this->set_the_hole(Derived::EntryToIndex(entry) + 1);
18552 83 : this->ElementRemoved();
18553 83 : }
18554 :
18555 :
18556 79595 : void JSSet::Initialize(Handle<JSSet> set, Isolate* isolate) {
18557 79595 : Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
18558 159190 : set->set_table(*table);
18559 79595 : }
18560 :
18561 42 : void JSSet::Clear(Isolate* isolate, Handle<JSSet> set) {
18562 84 : Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()), isolate);
18563 42 : table = OrderedHashSet::Clear(isolate, table);
18564 84 : set->set_table(*table);
18565 42 : }
18566 :
18567 :
18568 13 : void JSMap::Initialize(Handle<JSMap> map, Isolate* isolate) {
18569 13 : Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
18570 26 : map->set_table(*table);
18571 13 : }
18572 :
18573 212 : void JSMap::Clear(Isolate* isolate, Handle<JSMap> map) {
18574 424 : Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()), isolate);
18575 212 : table = OrderedHashMap::Clear(isolate, table);
18576 424 : map->set_table(*table);
18577 212 : }
18578 :
18579 :
18580 50089 : void JSWeakCollection::Initialize(Handle<JSWeakCollection> weak_collection,
18581 : Isolate* isolate) {
18582 50089 : Handle<EphemeronHashTable> table = EphemeronHashTable::New(isolate, 0);
18583 100178 : weak_collection->set_table(*table);
18584 50089 : }
18585 :
18586 :
18587 972 : void JSWeakCollection::Set(Handle<JSWeakCollection> weak_collection,
18588 : Handle<Object> key, Handle<Object> value,
18589 : int32_t hash) {
18590 : DCHECK(key->IsJSReceiver() || key->IsSymbol());
18591 : Handle<EphemeronHashTable> table(
18592 : EphemeronHashTable::cast(weak_collection->table()),
18593 1944 : weak_collection->GetIsolate());
18594 : DCHECK(table->IsKey(weak_collection->GetReadOnlyRoots(), *key));
18595 : Handle<EphemeronHashTable> new_table = EphemeronHashTable::Put(
18596 972 : weak_collection->GetIsolate(), table, key, value, hash);
18597 1944 : weak_collection->set_table(*new_table);
18598 972 : if (*table != *new_table) {
18599 : // Zap the old table since we didn't record slots for its elements.
18600 352 : EphemeronHashTable::FillEntriesWithHoles(table);
18601 : }
18602 972 : }
18603 :
18604 :
18605 0 : bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection,
18606 : Handle<Object> key, int32_t hash) {
18607 : DCHECK(key->IsJSReceiver() || key->IsSymbol());
18608 : Handle<EphemeronHashTable> table(
18609 : EphemeronHashTable::cast(weak_collection->table()),
18610 0 : weak_collection->GetIsolate());
18611 : DCHECK(table->IsKey(weak_collection->GetReadOnlyRoots(), *key));
18612 0 : bool was_present = false;
18613 : Handle<EphemeronHashTable> new_table = EphemeronHashTable::Remove(
18614 0 : weak_collection->GetIsolate(), table, key, &was_present, hash);
18615 0 : weak_collection->set_table(*new_table);
18616 0 : if (*table != *new_table) {
18617 : // Zap the old table since we didn't record slots for its elements.
18618 0 : EphemeronHashTable::FillEntriesWithHoles(table);
18619 : }
18620 0 : return was_present;
18621 : }
18622 :
18623 98 : Handle<JSArray> JSWeakCollection::GetEntries(Handle<JSWeakCollection> holder,
18624 : int max_entries) {
18625 : Isolate* isolate = holder->GetIsolate();
18626 : Handle<EphemeronHashTable> table(EphemeronHashTable::cast(holder->table()),
18627 196 : isolate);
18628 98 : if (max_entries == 0 || max_entries > table->NumberOfElements()) {
18629 98 : max_entries = table->NumberOfElements();
18630 : }
18631 196 : int values_per_entry = holder->IsJSWeakMap() ? 2 : 1;
18632 : Handle<FixedArray> entries =
18633 98 : isolate->factory()->NewFixedArray(max_entries * values_per_entry);
18634 : // Recompute max_values because GC could have removed elements from the table.
18635 98 : if (max_entries > table->NumberOfElements()) {
18636 0 : max_entries = table->NumberOfElements();
18637 : }
18638 :
18639 : {
18640 : DisallowHeapAllocation no_gc;
18641 : ReadOnlyRoots roots = ReadOnlyRoots(isolate);
18642 : int count = 0;
18643 504 : for (int i = 0;
18644 413 : count / values_per_entry < max_entries && i < table->Capacity(); i++) {
18645 105 : Object key;
18646 105 : if (table->ToKey(roots, i, &key)) {
18647 100 : entries->set(count++, key);
18648 50 : if (values_per_entry > 1) {
18649 25 : Object value = table->Lookup(handle(key, isolate));
18650 50 : entries->set(count++, value);
18651 : }
18652 : }
18653 : }
18654 : DCHECK_EQ(max_entries * values_per_entry, count);
18655 : }
18656 98 : return isolate->factory()->NewJSArrayWithElements(entries);
18657 : }
18658 :
18659 : // static
18660 148924 : MaybeHandle<JSDate> JSDate::New(Handle<JSFunction> constructor,
18661 : Handle<JSReceiver> new_target, double tv) {
18662 : Isolate* const isolate = constructor->GetIsolate();
18663 : Handle<JSObject> result;
18664 297848 : ASSIGN_RETURN_ON_EXCEPTION(
18665 : isolate, result,
18666 : JSObject::New(constructor, new_target, Handle<AllocationSite>::null()),
18667 : JSDate);
18668 148924 : if (-DateCache::kMaxTimeInMs <= tv && tv <= DateCache::kMaxTimeInMs) {
18669 148429 : tv = DoubleToInteger(tv) + 0.0;
18670 : } else {
18671 : tv = std::numeric_limits<double>::quiet_NaN();
18672 : }
18673 148924 : Handle<Object> value = isolate->factory()->NewNumber(tv);
18674 446772 : Handle<JSDate>::cast(result)->SetValue(*value, std::isnan(tv));
18675 148924 : return Handle<JSDate>::cast(result);
18676 : }
18677 :
18678 :
18679 : // static
18680 144393 : double JSDate::CurrentTimeValue(Isolate* isolate) {
18681 144393 : if (FLAG_log_internal_timer_events) LOG(isolate, CurrentTimeEvent());
18682 :
18683 : // According to ECMA-262, section 15.9.1, page 117, the precision of
18684 : // the number in a Date object representing a particular instant in
18685 : // time is milliseconds. Therefore, we floor the result of getting
18686 : // the OS time.
18687 288786 : return Floor(V8::GetCurrentPlatform()->CurrentClockTimeMillis());
18688 : }
18689 :
18690 :
18691 : // static
18692 11142 : Address JSDate::GetField(Address raw_object, Address smi_index) {
18693 : Object object(raw_object);
18694 : Smi index(smi_index);
18695 : return JSDate::cast(object)
18696 33426 : ->DoGetField(static_cast<FieldIndex>(index->value()))
18697 33426 : ->ptr();
18698 : }
18699 :
18700 11142 : Object JSDate::DoGetField(FieldIndex index) {
18701 : DCHECK_NE(index, kDateValue);
18702 :
18703 11142 : DateCache* date_cache = GetIsolate()->date_cache();
18704 :
18705 11142 : if (index < kFirstUncachedField) {
18706 5427 : Object stamp = cache_stamp();
18707 10854 : if (stamp != date_cache->stamp() && stamp->IsSmi()) {
18708 : // Since the stamp is not NaN, the value is also not NaN.
18709 : int64_t local_time_ms =
18710 756 : date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
18711 378 : SetCachedFields(local_time_ms, date_cache);
18712 : }
18713 5427 : switch (index) {
18714 891 : case kYear: return year();
18715 243 : case kMonth: return month();
18716 72 : case kDay: return day();
18717 0 : case kWeekday: return weekday();
18718 3150 : case kHour: return hour();
18719 846 : case kMinute: return min();
18720 225 : case kSecond: return sec();
18721 0 : default: UNREACHABLE();
18722 : }
18723 : }
18724 :
18725 5715 : if (index >= kFirstUTCField) {
18726 5553 : return GetUTCField(index, value()->Number(), date_cache);
18727 : }
18728 :
18729 162 : double time = value()->Number();
18730 216 : if (std::isnan(time)) return GetReadOnlyRoots().nan_value();
18731 :
18732 108 : int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
18733 : int days = DateCache::DaysFromTime(local_time_ms);
18734 :
18735 108 : if (index == kDays) return Smi::FromInt(days);
18736 :
18737 : int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
18738 216 : if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
18739 : DCHECK_EQ(index, kTimeInDay);
18740 0 : return Smi::FromInt(time_in_day_ms);
18741 : }
18742 :
18743 5553 : Object JSDate::GetUTCField(FieldIndex index, double value,
18744 : DateCache* date_cache) {
18745 : DCHECK_GE(index, kFirstUTCField);
18746 :
18747 10656 : if (std::isnan(value)) return GetReadOnlyRoots().nan_value();
18748 :
18749 450 : int64_t time_ms = static_cast<int64_t>(value);
18750 :
18751 450 : if (index == kTimezoneOffset) {
18752 126 : GetIsolate()->CountUsage(v8::Isolate::kDateGetTimezoneOffset);
18753 126 : return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
18754 : }
18755 :
18756 : int days = DateCache::DaysFromTime(time_ms);
18757 :
18758 333 : if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
18759 :
18760 315 : if (index <= kDayUTC) {
18761 : int year, month, day;
18762 117 : date_cache->YearMonthDayFromDays(days, &year, &month, &day);
18763 153 : if (index == kYearUTC) return Smi::FromInt(year);
18764 117 : if (index == kMonthUTC) return Smi::FromInt(month);
18765 : DCHECK_EQ(index, kDayUTC);
18766 90 : return Smi::FromInt(day);
18767 : }
18768 :
18769 : int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
18770 198 : switch (index) {
18771 180 : case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
18772 90 : case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
18773 72 : case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
18774 54 : case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
18775 0 : case kDaysUTC: return Smi::FromInt(days);
18776 0 : case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
18777 0 : default: UNREACHABLE();
18778 : }
18779 :
18780 : UNREACHABLE();
18781 : }
18782 :
18783 : // static
18784 11151 : Handle<Object> JSDate::SetValue(Handle<JSDate> date, double v) {
18785 : Isolate* const isolate = date->GetIsolate();
18786 11151 : Handle<Object> value = isolate->factory()->NewNumber(v);
18787 : bool value_is_nan = std::isnan(v);
18788 22302 : date->SetValue(*value, value_is_nan);
18789 11151 : return value;
18790 : }
18791 :
18792 160075 : void JSDate::SetValue(Object value, bool is_value_nan) {
18793 160075 : set_value(value);
18794 160075 : if (is_value_nan) {
18795 22320 : HeapNumber nan = GetReadOnlyRoots().nan_value();
18796 11160 : set_cache_stamp(nan, SKIP_WRITE_BARRIER);
18797 11160 : set_year(nan, SKIP_WRITE_BARRIER);
18798 11160 : set_month(nan, SKIP_WRITE_BARRIER);
18799 11160 : set_day(nan, SKIP_WRITE_BARRIER);
18800 11160 : set_hour(nan, SKIP_WRITE_BARRIER);
18801 11160 : set_min(nan, SKIP_WRITE_BARRIER);
18802 11160 : set_sec(nan, SKIP_WRITE_BARRIER);
18803 11160 : set_weekday(nan, SKIP_WRITE_BARRIER);
18804 : } else {
18805 148915 : set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
18806 : }
18807 160075 : }
18808 :
18809 378 : void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) {
18810 : int days = DateCache::DaysFromTime(local_time_ms);
18811 : int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
18812 : int year, month, day;
18813 378 : date_cache->YearMonthDayFromDays(days, &year, &month, &day);
18814 : int weekday = date_cache->Weekday(days);
18815 378 : int hour = time_in_day_ms / (60 * 60 * 1000);
18816 378 : int min = (time_in_day_ms / (60 * 1000)) % 60;
18817 378 : int sec = (time_in_day_ms / 1000) % 60;
18818 378 : set_cache_stamp(date_cache->stamp());
18819 756 : set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
18820 756 : set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
18821 756 : set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
18822 378 : set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
18823 378 : set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
18824 378 : set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
18825 378 : set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
18826 378 : }
18827 :
18828 8410 : int JSMessageObject::GetLineNumber() const {
18829 8410 : if (start_position() == -1) return Message::kNoLineNumberInfo;
18830 :
18831 8290 : Handle<Script> the_script(script(), GetIsolate());
18832 :
18833 : Script::PositionInfo info;
18834 : const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
18835 8290 : if (!Script::GetPositionInfo(the_script, start_position(), &info,
18836 8290 : offset_flag)) {
18837 : return Message::kNoLineNumberInfo;
18838 : }
18839 :
18840 8290 : return info.line + 1;
18841 : }
18842 :
18843 13386 : int JSMessageObject::GetColumnNumber() const {
18844 13386 : if (start_position() == -1) return -1;
18845 :
18846 13211 : Handle<Script> the_script(script(), GetIsolate());
18847 :
18848 : Script::PositionInfo info;
18849 : const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
18850 13211 : if (!Script::GetPositionInfo(the_script, start_position(), &info,
18851 13211 : offset_flag)) {
18852 : return -1;
18853 : }
18854 :
18855 13211 : return info.column; // Note: No '+1' in contrast to GetLineNumber.
18856 : }
18857 :
18858 5423 : Handle<String> JSMessageObject::GetSourceLine() const {
18859 : Isolate* isolate = GetIsolate();
18860 5423 : Handle<Script> the_script(script(), isolate);
18861 :
18862 5423 : if (the_script->type() == Script::TYPE_WASM) {
18863 : return isolate->factory()->empty_string();
18864 : }
18865 :
18866 : Script::PositionInfo info;
18867 : const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
18868 5423 : if (!Script::GetPositionInfo(the_script, start_position(), &info,
18869 5423 : offset_flag)) {
18870 : return isolate->factory()->empty_string();
18871 : }
18872 :
18873 10846 : Handle<String> src = handle(String::cast(the_script->source()), isolate);
18874 5423 : return isolate->factory()->NewSubString(src, info.line_start, info.line_end);
18875 : }
18876 :
18877 20000 : Handle<PropertyCell> PropertyCell::InvalidateEntry(
18878 : Isolate* isolate, Handle<GlobalDictionary> dictionary, int entry) {
18879 : // Swap with a copy.
18880 40000 : Handle<PropertyCell> cell(dictionary->CellAt(entry), isolate);
18881 40000 : Handle<Name> name(cell->name(), isolate);
18882 20000 : Handle<PropertyCell> new_cell = isolate->factory()->NewPropertyCell(name);
18883 40000 : new_cell->set_value(cell->value());
18884 40000 : dictionary->ValueAtPut(entry, *new_cell);
18885 40000 : bool is_the_hole = cell->value()->IsTheHole(isolate);
18886 : // Cell is officially mutable henceforth.
18887 20000 : PropertyDetails details = cell->property_details();
18888 : details = details.set_cell_type(is_the_hole ? PropertyCellType::kUninitialized
18889 20000 : : PropertyCellType::kMutable);
18890 40000 : new_cell->set_property_details(details);
18891 : // Old cell is ready for invalidation.
18892 20000 : if (is_the_hole) {
18893 16596 : cell->set_value(ReadOnlyRoots(isolate).undefined_value());
18894 : } else {
18895 23404 : cell->set_value(ReadOnlyRoots(isolate).the_hole_value());
18896 : }
18897 : details = details.set_cell_type(PropertyCellType::kInvalidated);
18898 40000 : cell->set_property_details(details);
18899 40000 : cell->dependent_code()->DeoptimizeDependentCodeGroup(
18900 20000 : isolate, DependentCode::kPropertyCellChangedGroup);
18901 20000 : return new_cell;
18902 : }
18903 :
18904 :
18905 0 : PropertyCellConstantType PropertyCell::GetConstantType() {
18906 0 : if (value()->IsSmi()) return PropertyCellConstantType::kSmi;
18907 0 : return PropertyCellConstantType::kStableMap;
18908 : }
18909 :
18910 :
18911 1085916 : static bool RemainsConstantType(Handle<PropertyCell> cell,
18912 : Handle<Object> value) {
18913 : // TODO(dcarney): double->smi and smi->double transition from kConstant
18914 3978896 : if (cell->value()->IsSmi() && value->IsSmi()) {
18915 : return true;
18916 732922 : } else if (cell->value()->IsHeapObject() && value->IsHeapObject()) {
18917 363358 : return HeapObject::cast(cell->value())->map() ==
18918 354477 : HeapObject::cast(*value)->map() &&
18919 354477 : HeapObject::cast(*value)->map()->is_stable();
18920 : }
18921 : return false;
18922 : }
18923 :
18924 12746102 : PropertyCellType PropertyCell::UpdatedType(Isolate* isolate,
18925 : Handle<PropertyCell> cell,
18926 : Handle<Object> value,
18927 : PropertyDetails details) {
18928 : PropertyCellType type = details.cell_type();
18929 : DCHECK(!value->IsTheHole(isolate));
18930 25492207 : if (cell->value()->IsTheHole(isolate)) {
18931 8245930 : switch (type) {
18932 : // Only allow a cell to transition once into constant state.
18933 : case PropertyCellType::kUninitialized:
18934 16491859 : if (value->IsUndefined(isolate)) return PropertyCellType::kUndefined;
18935 6572991 : return PropertyCellType::kConstant;
18936 : case PropertyCellType::kInvalidated:
18937 : return PropertyCellType::kMutable;
18938 : default:
18939 0 : UNREACHABLE();
18940 : }
18941 : }
18942 4500174 : switch (type) {
18943 : case PropertyCellType::kUndefined:
18944 : return PropertyCellType::kConstant;
18945 : case PropertyCellType::kConstant:
18946 3172236 : if (*value == cell->value()) return PropertyCellType::kConstant;
18947 : V8_FALLTHROUGH;
18948 : case PropertyCellType::kConstantType:
18949 1085916 : if (RemainsConstantType(cell, value)) {
18950 : return PropertyCellType::kConstantType;
18951 : }
18952 : V8_FALLTHROUGH;
18953 : case PropertyCellType::kMutable:
18954 : return PropertyCellType::kMutable;
18955 : }
18956 0 : UNREACHABLE();
18957 : }
18958 :
18959 4507990 : Handle<PropertyCell> PropertyCell::PrepareForValue(
18960 : Isolate* isolate, Handle<GlobalDictionary> dictionary, int entry,
18961 : Handle<Object> value, PropertyDetails details) {
18962 : DCHECK(!value->IsTheHole(isolate));
18963 9015980 : Handle<PropertyCell> cell(dictionary->CellAt(entry), isolate);
18964 4507990 : const PropertyDetails original_details = cell->property_details();
18965 : // Data accesses could be cached in ics or optimized code.
18966 : bool invalidate =
18967 13515282 : (original_details.kind() == kData && details.kind() == kAccessor) ||
18968 4499907 : (!original_details.IsReadOnly() && details.IsReadOnly());
18969 : int index;
18970 : PropertyCellType old_type = original_details.cell_type();
18971 : // Preserve the enumeration index unless the property was deleted or never
18972 : // initialized.
18973 9015980 : if (cell->value()->IsTheHole(isolate)) {
18974 7816 : index = dictionary->NextEnumerationIndex();
18975 7816 : dictionary->SetNextEnumerationIndex(index + 1);
18976 : } else {
18977 : index = original_details.dictionary_index();
18978 : }
18979 : DCHECK_LT(0, index);
18980 : details = details.set_index(index);
18981 :
18982 : PropertyCellType new_type =
18983 4507990 : UpdatedType(isolate, cell, value, original_details);
18984 4507990 : if (invalidate) {
18985 8143 : cell = PropertyCell::InvalidateEntry(isolate, dictionary, entry);
18986 : }
18987 :
18988 : // Install new property details.
18989 : details = details.set_cell_type(new_type);
18990 9015980 : cell->set_property_details(details);
18991 :
18992 4507990 : if (new_type == PropertyCellType::kConstant ||
18993 : new_type == PropertyCellType::kConstantType) {
18994 : // Store the value now to ensure that the cell contains the constant or
18995 : // type information. Otherwise subsequent store operation will turn
18996 : // the cell to mutable.
18997 4157403 : cell->set_value(*value);
18998 : }
18999 :
19000 : // Deopt when transitioning from a constant type.
19001 7424229 : if (!invalidate && (old_type != new_type ||
19002 : original_details.IsReadOnly() != details.IsReadOnly())) {
19003 3167234 : cell->dependent_code()->DeoptimizeDependentCodeGroup(
19004 1583617 : isolate, DependentCode::kPropertyCellChangedGroup);
19005 : }
19006 4507990 : return cell;
19007 : }
19008 :
19009 :
19010 : // static
19011 4888 : void PropertyCell::SetValueWithInvalidation(Isolate* isolate,
19012 : Handle<PropertyCell> cell,
19013 : Handle<Object> new_value) {
19014 9776 : if (cell->value() != *new_value) {
19015 4888 : cell->set_value(*new_value);
19016 9776 : cell->dependent_code()->DeoptimizeDependentCodeGroup(
19017 4888 : isolate, DependentCode::kPropertyCellChangedGroup);
19018 : }
19019 4888 : }
19020 :
19021 1430 : int JSGeneratorObject::source_position() const {
19022 1430 : CHECK(is_suspended());
19023 : DCHECK(function()->shared()->HasBytecodeArray());
19024 :
19025 1430 : int code_offset = Smi::ToInt(input_or_debug_pos());
19026 :
19027 : // The stored bytecode offset is relative to a different base than what
19028 : // is used in the source position table, hence the subtraction.
19029 1430 : code_offset -= BytecodeArray::kHeaderSize - kHeapObjectTag;
19030 : AbstractCode code =
19031 2860 : AbstractCode::cast(function()->shared()->GetBytecodeArray());
19032 1430 : return code->SourcePosition(code_offset);
19033 : }
19034 :
19035 : // static
19036 4707 : AccessCheckInfo AccessCheckInfo::Get(Isolate* isolate,
19037 : Handle<JSObject> receiver) {
19038 : DisallowHeapAllocation no_gc;
19039 : DCHECK(receiver->map()->is_access_check_needed());
19040 4707 : Object maybe_constructor = receiver->map()->GetConstructor();
19041 4707 : if (maybe_constructor->IsFunctionTemplateInfo()) {
19042 : Object data_obj =
19043 145 : FunctionTemplateInfo::cast(maybe_constructor)->GetAccessCheckInfo();
19044 145 : if (data_obj->IsUndefined(isolate)) return AccessCheckInfo();
19045 : return AccessCheckInfo::cast(data_obj);
19046 : }
19047 : // Might happen for a detached context.
19048 4562 : if (!maybe_constructor->IsJSFunction()) return AccessCheckInfo();
19049 4537 : JSFunction constructor = JSFunction::cast(maybe_constructor);
19050 : // Might happen for the debug context.
19051 4537 : if (!constructor->shared()->IsApiFunction()) return AccessCheckInfo();
19052 :
19053 : Object data_obj =
19054 4113 : constructor->shared()->get_api_func_data()->GetAccessCheckInfo();
19055 4113 : if (data_obj->IsUndefined(isolate)) return AccessCheckInfo();
19056 :
19057 : return AccessCheckInfo::cast(data_obj);
19058 : }
19059 :
19060 4128 : bool JSReceiver::HasProxyInPrototype(Isolate* isolate) {
19061 17052 : for (PrototypeIterator iter(isolate, *this, kStartAtReceiver,
19062 : PrototypeIterator::END_AT_NULL);
19063 12924 : !iter.IsAtEnd(); iter.AdvanceIgnoringProxies()) {
19064 25902 : if (iter.GetCurrent()->IsJSProxy()) return true;
19065 : }
19066 4101 : return false;
19067 : }
19068 :
19069 0 : bool JSReceiver::HasComplexElements() {
19070 0 : if (IsJSProxy()) return true;
19071 0 : JSObject this_object = JSObject::cast(*this);
19072 0 : if (this_object->HasIndexedInterceptor()) {
19073 : return true;
19074 : }
19075 0 : if (!this_object->HasDictionaryElements()) return false;
19076 0 : return this_object->element_dictionary()->HasComplexElements();
19077 : }
19078 :
19079 350039 : MaybeHandle<Name> FunctionTemplateInfo::TryGetCachedPropertyName(
19080 : Isolate* isolate, Handle<Object> getter) {
19081 700078 : if (getter->IsFunctionTemplateInfo()) {
19082 : Handle<FunctionTemplateInfo> fti =
19083 114254 : Handle<FunctionTemplateInfo>::cast(getter);
19084 : // Check if the accessor uses a cached property.
19085 228508 : if (!fti->cached_property_name()->IsTheHole(isolate)) {
19086 174 : return handle(Name::cast(fti->cached_property_name()), isolate);
19087 : }
19088 : }
19089 349952 : return MaybeHandle<Name>();
19090 : }
19091 :
19092 4459142 : Address Smi::LexicographicCompare(Isolate* isolate, Smi x, Smi y) {
19093 : DisallowHeapAllocation no_allocation;
19094 4459142 : DisallowJavascriptExecution no_js(isolate);
19095 :
19096 4459142 : int x_value = Smi::ToInt(x);
19097 4459142 : int y_value = Smi::ToInt(y);
19098 :
19099 : // If the integers are equal so are the string representations.
19100 4459142 : if (x_value == y_value) return Smi::FromInt(0).ptr();
19101 :
19102 : // If one of the integers is zero the normal integer order is the
19103 : // same as the lexicographic order of the string representations.
19104 4455120 : if (x_value == 0 || y_value == 0) {
19105 7764 : return Smi::FromInt(x_value < y_value ? -1 : 1).ptr();
19106 : }
19107 :
19108 : // If only one of the integers is negative the negative number is
19109 : // smallest because the char code of '-' is less than the char code
19110 : // of any digit. Otherwise, we make both values positive.
19111 :
19112 : // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
19113 : // architectures using 32-bit Smis.
19114 4447356 : uint32_t x_scaled = x_value;
19115 4447356 : uint32_t y_scaled = y_value;
19116 4447356 : if (x_value < 0 || y_value < 0) {
19117 1974828 : if (y_value >= 0) return Smi::FromInt(-1).ptr();
19118 1315974 : if (x_value >= 0) return Smi::FromInt(1).ptr();
19119 657120 : x_scaled = -x_value;
19120 657120 : y_scaled = -y_value;
19121 : }
19122 :
19123 : // clang-format off
19124 : static const uint32_t kPowersOf10[] = {
19125 : 1, 10, 100, 1000,
19126 : 10 * 1000, 100 * 1000, 1000 * 1000, 10 * 1000 * 1000,
19127 : 100 * 1000 * 1000, 1000 * 1000 * 1000};
19128 : // clang-format on
19129 :
19130 : // If the integers have the same number of decimal digits they can be
19131 : // compared directly as the numeric order is the same as the
19132 : // lexicographic order. If one integer has fewer digits, it is scaled
19133 : // by some power of 10 to have the same number of digits as the longer
19134 : // integer. If the scaled integers are equal it means the shorter
19135 : // integer comes first in the lexicographic order.
19136 :
19137 : // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
19138 3129648 : int x_log2 = 31 - base::bits::CountLeadingZeros(x_scaled);
19139 3129648 : int x_log10 = ((x_log2 + 1) * 1233) >> 12;
19140 3129648 : x_log10 -= x_scaled < kPowersOf10[x_log10];
19141 :
19142 3129648 : int y_log2 = 31 - base::bits::CountLeadingZeros(y_scaled);
19143 3129648 : int y_log10 = ((y_log2 + 1) * 1233) >> 12;
19144 3129648 : y_log10 -= y_scaled < kPowersOf10[y_log10];
19145 :
19146 : int tie = 0;
19147 :
19148 3129648 : if (x_log10 < y_log10) {
19149 : // X has fewer digits. We would like to simply scale up X but that
19150 : // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
19151 : // be scaled up to 9_000_000_000. So we scale up by the next
19152 : // smallest power and scale down Y to drop one digit. It is OK to
19153 : // drop one digit from the longer integer since the final digit is
19154 : // past the length of the shorter integer.
19155 585100 : x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
19156 585100 : y_scaled /= 10;
19157 : tie = -1;
19158 2544548 : } else if (y_log10 < x_log10) {
19159 1447453 : y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
19160 1447453 : x_scaled /= 10;
19161 : tie = 1;
19162 : }
19163 :
19164 3129648 : if (x_scaled < y_scaled) return Smi::FromInt(-1).ptr();
19165 1908040 : if (x_scaled > y_scaled) return Smi::FromInt(1).ptr();
19166 4459142 : return Smi::FromInt(tie).ptr();
19167 : }
19168 :
19169 : // Force instantiation of template instances class.
19170 : // Please note this list is compiler dependent.
19171 : // Keep this at the end of this file
19172 :
19173 : template class HashTable<StringTable, StringTableShape>;
19174 :
19175 : template class HashTable<CompilationCacheTable, CompilationCacheShape>;
19176 :
19177 : template class HashTable<ObjectHashTable, ObjectHashTableShape>;
19178 :
19179 : template class HashTable<EphemeronHashTable, EphemeronHashTableShape>;
19180 :
19181 : template class ObjectHashTableBase<ObjectHashTable, ObjectHashTableShape>;
19182 :
19183 : template class ObjectHashTableBase<EphemeronHashTable, EphemeronHashTableShape>;
19184 :
19185 : template class Dictionary<NameDictionary, NameDictionaryShape>;
19186 :
19187 : template class Dictionary<GlobalDictionary, GlobalDictionaryShape>;
19188 :
19189 : template class EXPORT_TEMPLATE_DEFINE(
19190 : V8_EXPORT_PRIVATE) HashTable<NumberDictionary, NumberDictionaryShape>;
19191 :
19192 : template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
19193 : Dictionary<NumberDictionary, NumberDictionaryShape>;
19194 :
19195 : template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
19196 : HashTable<SimpleNumberDictionary, SimpleNumberDictionaryShape>;
19197 :
19198 : template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
19199 : Dictionary<SimpleNumberDictionary, SimpleNumberDictionaryShape>;
19200 :
19201 : template Handle<NameDictionary>
19202 : BaseNameDictionary<NameDictionary, NameDictionaryShape>::New(
19203 : Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
19204 :
19205 : template Handle<GlobalDictionary>
19206 : BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::New(
19207 : Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
19208 :
19209 : template Handle<NameDictionary>
19210 : HashTable<NameDictionary, NameDictionaryShape>::New(Isolate*, int,
19211 : PretenureFlag,
19212 : MinimumCapacity);
19213 :
19214 : template Handle<ObjectHashSet>
19215 : HashTable<ObjectHashSet, ObjectHashSetShape>::New(Isolate*, int n,
19216 : PretenureFlag,
19217 : MinimumCapacity);
19218 :
19219 : template Handle<NameDictionary>
19220 : HashTable<NameDictionary, NameDictionaryShape>::Shrink(Isolate* isolate,
19221 : Handle<NameDictionary>,
19222 : int additionalCapacity);
19223 :
19224 : template Handle<NameDictionary>
19225 : BaseNameDictionary<NameDictionary, NameDictionaryShape>::Add(
19226 : Isolate* isolate, Handle<NameDictionary>, Handle<Name>, Handle<Object>,
19227 : PropertyDetails, int*);
19228 :
19229 : template Handle<GlobalDictionary>
19230 : BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::Add(
19231 : Isolate* isolate, Handle<GlobalDictionary>, Handle<Name>, Handle<Object>,
19232 : PropertyDetails, int*);
19233 :
19234 : template void HashTable<GlobalDictionary, GlobalDictionaryShape>::Rehash(
19235 : Isolate* isolate);
19236 :
19237 : template Handle<NameDictionary>
19238 : BaseNameDictionary<NameDictionary, NameDictionaryShape>::EnsureCapacity(
19239 : Isolate* isolate, Handle<NameDictionary>, int);
19240 :
19241 : template void
19242 : BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::CopyEnumKeysTo(
19243 : Isolate* isolate, Handle<GlobalDictionary> dictionary,
19244 : Handle<FixedArray> storage, KeyCollectionMode mode,
19245 : KeyAccumulator* accumulator);
19246 :
19247 : template void
19248 : BaseNameDictionary<NameDictionary, NameDictionaryShape>::CopyEnumKeysTo(
19249 : Isolate* isolate, Handle<NameDictionary> dictionary,
19250 : Handle<FixedArray> storage, KeyCollectionMode mode,
19251 : KeyAccumulator* accumulator);
19252 :
19253 : template Handle<FixedArray>
19254 : BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::IterationIndices(
19255 : Isolate* isolate, Handle<GlobalDictionary> dictionary);
19256 : template void
19257 : BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::CollectKeysTo(
19258 : Handle<GlobalDictionary> dictionary, KeyAccumulator* keys);
19259 :
19260 : template Handle<FixedArray>
19261 : BaseNameDictionary<NameDictionary, NameDictionaryShape>::IterationIndices(
19262 : Isolate* isolate, Handle<NameDictionary> dictionary);
19263 : template void
19264 : BaseNameDictionary<NameDictionary, NameDictionaryShape>::CollectKeysTo(
19265 : Handle<NameDictionary> dictionary, KeyAccumulator* keys);
19266 :
19267 243 : void JSWeakFactory::Cleanup(Handle<JSWeakFactory> weak_factory,
19268 : Isolate* isolate) {
19269 : // It's possible that the cleared_cells list is empty, since
19270 : // WeakCell.clear() was called on all its elements before this task ran. In
19271 : // that case, don't call the cleanup function.
19272 486 : if (!weak_factory->cleared_cells()->IsUndefined(isolate)) {
19273 : // Construct the iterator.
19274 : Handle<JSWeakFactoryCleanupIterator> iterator;
19275 : {
19276 : Handle<Map> cleanup_iterator_map(
19277 540 : isolate->native_context()->js_weak_factory_cleanup_iterator_map(),
19278 180 : isolate);
19279 : iterator = Handle<JSWeakFactoryCleanupIterator>::cast(
19280 : isolate->factory()->NewJSObjectFromMap(
19281 : cleanup_iterator_map, NOT_TENURED,
19282 180 : Handle<AllocationSite>::null()));
19283 180 : iterator->set_factory(*weak_factory);
19284 : }
19285 360 : Handle<Object> cleanup(weak_factory->cleanup(), isolate);
19286 :
19287 180 : v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
19288 : v8::Local<v8::Value> result;
19289 180 : MaybeHandle<Object> exception;
19290 : Handle<Object> args[] = {iterator};
19291 : bool has_pending_exception = !ToLocal<Value>(
19292 : Execution::TryCall(
19293 : isolate, cleanup,
19294 : handle(ReadOnlyRoots(isolate).undefined_value(), isolate), 1, args,
19295 : Execution::MessageHandling::kReport, &exception),
19296 360 : &result);
19297 : // TODO(marja): (spec): What if there's an exception?
19298 180 : USE(has_pending_exception);
19299 :
19300 : // TODO(marja): (spec): Should the iterator be invalidated after the
19301 : // function returns?
19302 : }
19303 243 : }
19304 :
19305 : } // namespace internal
19306 183867 : } // namespace v8
|