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 <cmath>
8 : #include <iomanip>
9 : #include <memory>
10 : #include <sstream>
11 : #include <vector>
12 :
13 : #include "src/objects-inl.h"
14 :
15 : #include "src/accessors.h"
16 : #include "src/allocation-site-scopes.h"
17 : #include "src/api-arguments-inl.h"
18 : #include "src/api-natives.h"
19 : #include "src/api.h"
20 : #include "src/arguments.h"
21 : #include "src/ast/ast.h"
22 : #include "src/ast/scopes.h"
23 : #include "src/base/bits.h"
24 : #include "src/base/utils/random-number-generator.h"
25 : #include "src/bootstrapper.h"
26 : #include "src/builtins/builtins.h"
27 : #include "src/code-stubs.h"
28 : #include "src/compilation-dependencies.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-evaluate.h"
34 : #include "src/debug/debug.h"
35 : #include "src/deoptimizer.h"
36 : #include "src/elements.h"
37 : #include "src/execution.h"
38 : #include "src/field-index-inl.h"
39 : #include "src/field-index.h"
40 : #include "src/field-type.h"
41 : #include "src/frames-inl.h"
42 : #include "src/globals.h"
43 : #include "src/ic/ic.h"
44 : #include "src/identity-map.h"
45 : #include "src/interpreter/bytecode-array-iterator.h"
46 : #include "src/interpreter/bytecode-decoder.h"
47 : #include "src/interpreter/interpreter.h"
48 : #include "src/isolate-inl.h"
49 : #include "src/keys.h"
50 : #include "src/log.h"
51 : #include "src/lookup.h"
52 : #include "src/macro-assembler.h"
53 : #include "src/map-updater.h"
54 : #include "src/messages.h"
55 : #include "src/objects-body-descriptors-inl.h"
56 : #include "src/objects/bigint.h"
57 : #include "src/objects/code-inl.h"
58 : #include "src/objects/compilation-cache-inl.h"
59 : #include "src/objects/debug-objects-inl.h"
60 : #include "src/objects/frame-array-inl.h"
61 : #include "src/objects/hash-table.h"
62 : #include "src/objects/map.h"
63 : #include "src/parsing/preparsed-scope-data.h"
64 : #include "src/property-descriptor.h"
65 : #include "src/prototype.h"
66 : #include "src/regexp/jsregexp.h"
67 : #include "src/safepoint-table.h"
68 : #include "src/snapshot/code-serializer.h"
69 : #include "src/source-position-table.h"
70 : #include "src/string-builder.h"
71 : #include "src/string-search.h"
72 : #include "src/string-stream.h"
73 : #include "src/unicode-cache-inl.h"
74 : #include "src/utils-inl.h"
75 : #include "src/wasm/wasm-objects.h"
76 : #include "src/zone/zone.h"
77 :
78 : #ifdef ENABLE_DISASSEMBLER
79 : #include "src/disasm.h"
80 : #include "src/disassembler.h"
81 : #include "src/eh-frame.h"
82 : #endif
83 :
84 : namespace v8 {
85 : namespace internal {
86 :
87 17418 : std::ostream& operator<<(std::ostream& os, InstanceType instance_type) {
88 17418 : switch (instance_type) {
89 : #define WRITE_TYPE(TYPE) \
90 : case TYPE: \
91 : return os << #TYPE;
92 0 : INSTANCE_TYPE_LIST(WRITE_TYPE)
93 : #undef WRITE_TYPE
94 : }
95 0 : UNREACHABLE();
96 : }
97 :
98 7118503 : Handle<FieldType> Object::OptimalType(Isolate* isolate,
99 : Representation representation) {
100 7118503 : if (representation.IsNone()) return FieldType::None(isolate);
101 6813578 : if (FLAG_track_field_types) {
102 9988308 : if (representation.IsHeapObject() && IsHeapObject()) {
103 : // We can track only JavaScript objects with stable maps.
104 : Handle<Map> map(HeapObject::cast(this)->map(), isolate);
105 5933847 : if (map->is_stable() && map->IsJSReceiverMap()) {
106 986339 : return FieldType::Class(map, isolate);
107 : }
108 : }
109 : }
110 5827240 : return FieldType::Any(isolate);
111 : }
112 :
113 6361 : MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
114 : Handle<Object> object,
115 : Handle<Context> native_context,
116 : const char* method_name) {
117 6361 : if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
118 : Handle<JSFunction> constructor;
119 6361 : if (object->IsSmi()) {
120 431 : constructor = handle(native_context->number_function(), isolate);
121 : } else {
122 : int constructor_function_index =
123 : Handle<HeapObject>::cast(object)->map()->GetConstructorFunctionIndex();
124 5930 : if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
125 1133 : if (method_name != nullptr) {
126 1434 : THROW_NEW_ERROR(
127 : isolate,
128 : NewTypeError(
129 : MessageTemplate::kCalledOnNullOrUndefined,
130 : isolate->factory()->NewStringFromAsciiChecked(method_name)),
131 : JSReceiver);
132 : }
133 1310 : THROW_NEW_ERROR(isolate,
134 : NewTypeError(MessageTemplate::kUndefinedOrNullToObject),
135 : JSReceiver);
136 : }
137 : constructor = handle(
138 : JSFunction::cast(native_context->get(constructor_function_index)),
139 4797 : isolate);
140 : }
141 5228 : Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
142 5228 : Handle<JSValue>::cast(result)->set_value(*object);
143 5228 : return result;
144 : }
145 :
146 : // ES6 section 9.2.1.2, OrdinaryCallBindThis for sloppy callee.
147 : // static
148 371 : MaybeHandle<JSReceiver> Object::ConvertReceiver(Isolate* isolate,
149 : Handle<Object> object) {
150 371 : if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
151 670 : if (*object == isolate->heap()->null_value() ||
152 : object->IsUndefined(isolate)) {
153 151 : return isolate->global_proxy();
154 : }
155 184 : return Object::ToObject(isolate, object);
156 : }
157 :
158 : // static
159 2348333 : MaybeHandle<Object> Object::ConvertToNumberOrNumeric(Isolate* isolate,
160 : Handle<Object> input,
161 : Conversion mode) {
162 : while (true) {
163 2352241 : if (input->IsNumber()) {
164 15786 : return input;
165 : }
166 2336455 : if (input->IsString()) {
167 4614 : return String::ToNumber(Handle<String>::cast(input));
168 : }
169 2331841 : if (input->IsOddball()) {
170 2323623 : return Oddball::ToNumber(Handle<Oddball>::cast(input));
171 : }
172 8218 : if (input->IsSymbol()) {
173 7094 : THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber),
174 : Object);
175 : }
176 4671 : if (input->IsBigInt()) {
177 108 : if (mode == Conversion::kToNumeric) return input;
178 : DCHECK_EQ(mode, Conversion::kToNumber);
179 216 : THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kBigIntToNumber),
180 : Object);
181 : }
182 9126 : ASSIGN_RETURN_ON_EXCEPTION(
183 : isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
184 : ToPrimitiveHint::kNumber),
185 : Object);
186 : }
187 : }
188 :
189 : // static
190 19540 : MaybeHandle<Object> Object::ConvertToInteger(Isolate* isolate,
191 : Handle<Object> input) {
192 39080 : ASSIGN_RETURN_ON_EXCEPTION(
193 : isolate, input,
194 : ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object);
195 19208 : if (input->IsSmi()) return input;
196 17244 : return isolate->factory()->NewNumber(DoubleToInteger(input->Number()));
197 : }
198 :
199 : // static
200 456 : MaybeHandle<Object> Object::ConvertToInt32(Isolate* isolate,
201 : Handle<Object> input) {
202 912 : ASSIGN_RETURN_ON_EXCEPTION(
203 : isolate, input,
204 : ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object);
205 444 : if (input->IsSmi()) return input;
206 274 : return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number()));
207 : }
208 :
209 : // static
210 473799 : MaybeHandle<Object> Object::ConvertToUint32(Isolate* isolate,
211 : Handle<Object> input) {
212 947598 : ASSIGN_RETURN_ON_EXCEPTION(
213 : isolate, input,
214 : ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object);
215 947306 : if (input->IsSmi()) return handle(Smi::cast(*input)->ToUint32Smi(), isolate);
216 248 : return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number()));
217 : }
218 :
219 : // static
220 3048727 : MaybeHandle<Name> Object::ConvertToName(Isolate* isolate,
221 : Handle<Object> input) {
222 6097454 : ASSIGN_RETURN_ON_EXCEPTION(
223 : isolate, input, Object::ToPrimitive(input, ToPrimitiveHint::kString),
224 : Name);
225 3048512 : if (input->IsName()) return Handle<Name>::cast(input);
226 44613 : return ToString(isolate, input);
227 : }
228 :
229 : // ES6 7.1.14
230 : // static
231 479 : MaybeHandle<Object> Object::ConvertToPropertyKey(Isolate* isolate,
232 : Handle<Object> value) {
233 : // 1. Let key be ToPrimitive(argument, hint String).
234 : MaybeHandle<Object> maybe_key =
235 479 : Object::ToPrimitive(value, ToPrimitiveHint::kString);
236 : // 2. ReturnIfAbrupt(key).
237 : Handle<Object> key;
238 479 : if (!maybe_key.ToHandle(&key)) return key;
239 : // 3. If Type(key) is Symbol, then return key.
240 479 : if (key->IsSymbol()) return key;
241 : // 4. Return ToString(key).
242 : // Extending spec'ed behavior, we'd be happy to return an element index.
243 479 : if (key->IsSmi()) return key;
244 479 : if (key->IsHeapNumber()) {
245 : uint32_t uint_value;
246 28 : if (value->ToArrayLength(&uint_value) &&
247 9 : uint_value <= static_cast<uint32_t>(Smi::kMaxValue)) {
248 0 : return handle(Smi::FromInt(static_cast<int>(uint_value)), isolate);
249 : }
250 : }
251 479 : return Object::ToString(isolate, key);
252 : }
253 :
254 : // static
255 5961382 : MaybeHandle<String> Object::ConvertToString(Isolate* isolate,
256 : Handle<Object> input) {
257 : while (true) {
258 6142351 : if (input->IsOddball()) {
259 2094722 : return handle(Handle<Oddball>::cast(input)->to_string(), isolate);
260 : }
261 4047629 : if (input->IsNumber()) {
262 269234 : return isolate->factory()->NumberToString(input);
263 : }
264 3778395 : if (input->IsSymbol()) {
265 4154 : THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToString),
266 : String);
267 : }
268 3776318 : if (input->IsBigInt()) {
269 36 : return BigInt::ToString(Handle<BigInt>::cast(input));
270 : }
271 7552564 : ASSIGN_RETURN_ON_EXCEPTION(
272 : isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
273 : ToPrimitiveHint::kString),
274 : String);
275 : // The previous isString() check happened in Object::ToString and thus we
276 : // put it at the end of the loop in this helper.
277 3763155 : if (input->IsString()) {
278 3582186 : return Handle<String>::cast(input);
279 : }
280 : }
281 : }
282 :
283 : namespace {
284 :
285 29239 : bool IsErrorObject(Isolate* isolate, Handle<Object> object) {
286 29239 : if (!object->IsJSReceiver()) return false;
287 : Handle<Symbol> symbol = isolate->factory()->stack_trace_symbol();
288 29239 : return JSReceiver::HasOwnProperty(Handle<JSReceiver>::cast(object), symbol)
289 58478 : .FromMaybe(false);
290 : }
291 :
292 27111 : Handle<String> AsStringOrEmpty(Isolate* isolate, Handle<Object> object) {
293 : return object->IsString() ? Handle<String>::cast(object)
294 54222 : : isolate->factory()->empty_string();
295 : }
296 :
297 4333 : Handle<String> NoSideEffectsErrorToString(Isolate* isolate,
298 : Handle<Object> input) {
299 4333 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input);
300 :
301 : Handle<Name> name_key = isolate->factory()->name_string();
302 4333 : Handle<Object> name = JSReceiver::GetDataProperty(receiver, name_key);
303 4333 : Handle<String> name_str = AsStringOrEmpty(isolate, name);
304 :
305 : Handle<Name> msg_key = isolate->factory()->message_string();
306 4333 : Handle<Object> msg = JSReceiver::GetDataProperty(receiver, msg_key);
307 4333 : Handle<String> msg_str = AsStringOrEmpty(isolate, msg);
308 :
309 4333 : if (name_str->length() == 0) return msg_str;
310 4313 : if (msg_str->length() == 0) return name_str;
311 :
312 4194 : IncrementalStringBuilder builder(isolate);
313 4194 : builder.AppendString(name_str);
314 : builder.AppendCString(": ");
315 4194 : builder.AppendString(msg_str);
316 :
317 8388 : return builder.Finish().ToHandleChecked();
318 : }
319 :
320 : } // namespace
321 :
322 : // static
323 3074602 : Handle<String> Object::NoSideEffectsToString(Isolate* isolate,
324 : Handle<Object> input) {
325 3074602 : DisallowJavascriptExecution no_js(isolate);
326 :
327 7333308 : if (input->IsString() || input->IsNumber() || input->IsOddball()) {
328 6087438 : return Object::ToString(isolate, input).ToHandleChecked();
329 30883 : } else if (input->IsFunction()) {
330 : // -- F u n c t i o n
331 : Handle<String> fun_str;
332 583 : if (input->IsJSBoundFunction()) {
333 0 : fun_str = JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(input));
334 : } else {
335 : DCHECK(input->IsJSFunction());
336 583 : fun_str = JSFunction::ToString(Handle<JSFunction>::cast(input));
337 : }
338 :
339 583 : if (fun_str->length() > 128) {
340 10 : IncrementalStringBuilder builder(isolate);
341 10 : builder.AppendString(isolate->factory()->NewSubString(fun_str, 0, 111));
342 : builder.AppendCString("...<omitted>...");
343 : builder.AppendString(isolate->factory()->NewSubString(
344 10 : fun_str, fun_str->length() - 2, fun_str->length()));
345 :
346 20 : return builder.Finish().ToHandleChecked();
347 : }
348 573 : return fun_str;
349 30300 : } else if (input->IsSymbol()) {
350 : // -- S y m b o l
351 : Handle<Symbol> symbol = Handle<Symbol>::cast(input);
352 :
353 1061 : IncrementalStringBuilder builder(isolate);
354 : builder.AppendCString("Symbol(");
355 1061 : if (symbol->name()->IsString()) {
356 557 : builder.AppendString(handle(String::cast(symbol->name()), isolate));
357 : }
358 : builder.AppendCharacter(')');
359 :
360 2122 : return builder.Finish().ToHandleChecked();
361 29239 : } else if (input->IsJSReceiver()) {
362 : // -- J S R e c e i v e r
363 29239 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input);
364 : Handle<Object> to_string = JSReceiver::GetDataProperty(
365 29239 : receiver, isolate->factory()->toString_string());
366 :
367 87717 : if (IsErrorObject(isolate, input) ||
368 79071 : *to_string == *isolate->error_to_string()) {
369 : // When internally formatting error objects, use a side-effects-free
370 : // version of Error.prototype.toString independent of the actually
371 : // installed toString method.
372 26593 : return NoSideEffectsErrorToString(isolate, input);
373 49812 : } else if (*to_string == *isolate->object_to_string()) {
374 : Handle<Object> ctor = JSReceiver::GetDataProperty(
375 18742 : receiver, isolate->factory()->constructor_string());
376 18742 : if (ctor->IsFunction()) {
377 : Handle<String> ctor_name;
378 18445 : if (ctor->IsJSBoundFunction()) {
379 : ctor_name = JSBoundFunction::GetName(
380 : isolate, Handle<JSBoundFunction>::cast(ctor))
381 0 : .ToHandleChecked();
382 18445 : } else if (ctor->IsJSFunction()) {
383 : Handle<Object> ctor_name_obj =
384 18445 : JSFunction::GetName(isolate, Handle<JSFunction>::cast(ctor));
385 18445 : ctor_name = AsStringOrEmpty(isolate, ctor_name_obj);
386 : }
387 :
388 18445 : if (ctor_name->length() != 0) {
389 17927 : IncrementalStringBuilder builder(isolate);
390 : builder.AppendCString("#<");
391 17927 : builder.AppendString(ctor_name);
392 : builder.AppendCString(">");
393 :
394 35854 : return builder.Finish().ToHandleChecked();
395 : }
396 : }
397 : }
398 : }
399 :
400 : // At this point, input is either none of the above or a JSReceiver.
401 :
402 : Handle<JSReceiver> receiver;
403 6979 : if (input->IsJSReceiver()) {
404 : receiver = Handle<JSReceiver>::cast(input);
405 : } else {
406 : // This is the only case where Object::ToObject throws.
407 : DCHECK(!input->IsSmi());
408 : int constructor_function_index =
409 : Handle<HeapObject>::cast(input)->map()->GetConstructorFunctionIndex();
410 0 : if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
411 0 : return isolate->factory()->NewStringFromAsciiChecked("[object Unknown]");
412 : }
413 :
414 0 : receiver = Object::ToObject(isolate, input, isolate->native_context())
415 0 : .ToHandleChecked();
416 : }
417 :
418 6979 : Handle<String> builtin_tag = handle(receiver->class_name(), isolate);
419 : Handle<Object> tag_obj = JSReceiver::GetDataProperty(
420 6979 : receiver, isolate->factory()->to_string_tag_symbol());
421 : Handle<String> tag =
422 6979 : tag_obj->IsString() ? Handle<String>::cast(tag_obj) : builtin_tag;
423 :
424 6979 : IncrementalStringBuilder builder(isolate);
425 : builder.AppendCString("[object ");
426 6979 : builder.AppendString(tag);
427 : builder.AppendCString("]");
428 :
429 13958 : return builder.Finish().ToHandleChecked();
430 : }
431 :
432 : // static
433 1606 : MaybeHandle<Object> Object::ConvertToLength(Isolate* isolate,
434 : Handle<Object> input) {
435 3212 : ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
436 1435 : if (input->IsSmi()) {
437 1647 : int value = std::max(Smi::ToInt(*input), 0);
438 549 : return handle(Smi::FromInt(value), isolate);
439 : }
440 886 : double len = DoubleToInteger(input->Number());
441 886 : if (len <= 0.0) {
442 591 : return handle(Smi::kZero, isolate);
443 295 : } else if (len >= kMaxSafeInteger) {
444 : len = kMaxSafeInteger;
445 : }
446 295 : return isolate->factory()->NewNumber(len);
447 : }
448 :
449 : // static
450 3561 : MaybeHandle<Object> Object::ConvertToIndex(
451 : Isolate* isolate, Handle<Object> input,
452 : MessageTemplate::Template error_index) {
453 5428 : if (input->IsUndefined(isolate)) return handle(Smi::kZero, isolate);
454 3388 : ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
455 2150 : if (input->IsSmi() && Smi::ToInt(*input) >= 0) return input;
456 1656 : double len = DoubleToInteger(input->Number()) + 0.0;
457 1656 : auto js_len = isolate->factory()->NewNumber(len);
458 1656 : if (len < 0.0 || len > kMaxSafeInteger) {
459 900 : THROW_NEW_ERROR(isolate, NewRangeError(error_index, js_len), Object);
460 : }
461 1206 : return js_len;
462 : }
463 :
464 868950 : bool Object::BooleanValue() {
465 874444 : if (IsSmi()) return Smi::ToInt(this) != 0;
466 : DCHECK(IsHeapObject());
467 : Isolate* isolate = HeapObject::cast(this)->GetIsolate();
468 1652468 : if (IsBoolean()) return IsTrue(isolate);
469 74444 : if (IsNullOrUndefined(isolate)) return false;
470 13656 : if (IsUndetectable()) return false; // Undetectable object is false.
471 19647 : if (IsString()) return String::cast(this)->length() != 0;
472 13341 : if (IsHeapNumber()) return DoubleToBoolean(HeapNumber::cast(this)->value());
473 2007 : if (IsBigInt()) return BigInt::cast(this)->ToBoolean();
474 : return true;
475 : }
476 :
477 :
478 : namespace {
479 :
480 : // TODO(bmeurer): Maybe we should introduce a marker interface Number,
481 : // where we put all these methods at some point?
482 : ComparisonResult NumberCompare(double x, double y) {
483 792 : if (std::isnan(x) || std::isnan(y)) {
484 : return ComparisonResult::kUndefined;
485 576 : } else if (x < y) {
486 : return ComparisonResult::kLessThan;
487 312 : } else if (x > y) {
488 : return ComparisonResult::kGreaterThan;
489 : } else {
490 : return ComparisonResult::kEqual;
491 : }
492 : }
493 :
494 :
495 : bool NumberEquals(double x, double y) {
496 : // Must check explicitly for NaN's on Windows, but -0 works fine.
497 9139 : if (std::isnan(x)) return false;
498 9033 : if (std::isnan(y)) return false;
499 8955 : return x == y;
500 : }
501 :
502 :
503 9139 : bool NumberEquals(const Object* x, const Object* y) {
504 9139 : return NumberEquals(x->Number(), y->Number());
505 : }
506 :
507 :
508 : bool NumberEquals(Handle<Object> x, Handle<Object> y) {
509 4341 : return NumberEquals(*x, *y);
510 : }
511 :
512 : } // namespace
513 :
514 :
515 : // static
516 840 : Maybe<ComparisonResult> Object::Compare(Handle<Object> x, Handle<Object> y) {
517 : // ES6 section 7.2.11 Abstract Relational Comparison step 3 and 4.
518 3360 : if (!Object::ToPrimitive(x, ToPrimitiveHint::kNumber).ToHandle(&x) ||
519 1680 : !Object::ToPrimitive(y, ToPrimitiveHint::kNumber).ToHandle(&y)) {
520 : return Nothing<ComparisonResult>();
521 : }
522 1008 : if (x->IsString() && y->IsString()) {
523 : // ES6 section 7.2.11 Abstract Relational Comparison step 5.
524 : return Just(
525 48 : String::Compare(Handle<String>::cast(x), Handle<String>::cast(y)));
526 : }
527 : // ES6 section 7.2.11 Abstract Relational Comparison step 6.
528 2376 : if (!Object::ToNumber(x).ToHandle(&x) || !Object::ToNumber(y).ToHandle(&y)) {
529 : return Nothing<ComparisonResult>();
530 : }
531 : return Just(NumberCompare(x->Number(), y->Number()));
532 : }
533 :
534 :
535 : // static
536 171507 : Maybe<bool> Object::Equals(Handle<Object> x, Handle<Object> y) {
537 : // This is the generic version of Abstract Equality Comparison. Must be in
538 : // sync with CodeStubAssembler::Equal.
539 : while (true) {
540 171585 : if (x->IsNumber()) {
541 4600 : if (y->IsNumber()) {
542 : return Just(NumberEquals(x, y));
543 420 : } else if (y->IsBoolean()) {
544 0 : return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
545 420 : } else if (y->IsString()) {
546 96 : return Just(NumberEquals(x, String::ToNumber(Handle<String>::cast(y))));
547 324 : } else if (y->IsBigInt()) {
548 324 : return Just(BigInt::EqualToNumber(Handle<BigInt>::cast(y), x));
549 0 : } else if (y->IsJSReceiver()) {
550 0 : if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
551 0 : .ToHandle(&y)) {
552 : return Nothing<bool>();
553 : }
554 : } else {
555 : return Just(false);
556 : }
557 166985 : } else if (x->IsString()) {
558 145291 : if (y->IsString()) {
559 : return Just(
560 145154 : String::Equals(Handle<String>::cast(x), Handle<String>::cast(y)));
561 137 : } else if (y->IsNumber()) {
562 65 : x = String::ToNumber(Handle<String>::cast(x));
563 : return Just(NumberEquals(x, y));
564 72 : } else if (y->IsBoolean()) {
565 0 : x = String::ToNumber(Handle<String>::cast(x));
566 0 : return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
567 72 : } else if (y->IsBigInt()) {
568 : return Just(BigInt::EqualToString(Handle<BigInt>::cast(y),
569 72 : Handle<String>::cast(x)));
570 0 : } else if (y->IsJSReceiver()) {
571 0 : if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
572 0 : .ToHandle(&y)) {
573 : return Nothing<bool>();
574 : }
575 : } else {
576 : return Just(false);
577 : }
578 21694 : } else if (x->IsBoolean()) {
579 816 : if (y->IsOddball()) {
580 : return Just(x.is_identical_to(y));
581 216 : } else if (y->IsNumber()) {
582 0 : return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
583 216 : } else if (y->IsString()) {
584 0 : y = String::ToNumber(Handle<String>::cast(y));
585 0 : return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
586 216 : } else if (y->IsBigInt()) {
587 216 : x = Oddball::ToNumber(Handle<Oddball>::cast(x));
588 216 : return Just(BigInt::EqualToNumber(Handle<BigInt>::cast(y), x));
589 0 : } else if (y->IsJSReceiver()) {
590 0 : if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
591 0 : .ToHandle(&y)) {
592 : return Nothing<bool>();
593 : }
594 0 : x = Oddball::ToNumber(Handle<Oddball>::cast(x));
595 : } else {
596 : return Just(false);
597 : }
598 20878 : } else if (x->IsSymbol()) {
599 90 : if (y->IsSymbol()) {
600 : return Just(x.is_identical_to(y));
601 36 : } else if (y->IsJSReceiver()) {
602 0 : if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
603 0 : .ToHandle(&y)) {
604 : return Nothing<bool>();
605 : }
606 : } else {
607 : return Just(false);
608 : }
609 20788 : } else if (x->IsBigInt()) {
610 396 : if (y->IsBigInt()) {
611 72 : return Just(BigInt::EqualToBigInt(BigInt::cast(*x), BigInt::cast(*y)));
612 : }
613 324 : return Equals(y, x);
614 20392 : } else if (x->IsJSReceiver()) {
615 20290 : if (y->IsJSReceiver()) {
616 : return Just(x.is_identical_to(y));
617 78 : } else if (y->IsUndetectable()) {
618 : return Just(x->IsUndetectable());
619 78 : } else if (y->IsBoolean()) {
620 0 : y = Oddball::ToNumber(Handle<Oddball>::cast(y));
621 78 : } else if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(x))
622 156 : .ToHandle(&x)) {
623 : return Nothing<bool>();
624 : }
625 : } else {
626 204 : return Just(x->IsUndetectable() && y->IsUndetectable());
627 : }
628 : }
629 : }
630 :
631 :
632 15883 : bool Object::StrictEquals(Object* that) {
633 15883 : if (this->IsNumber()) {
634 5382 : if (!that->IsNumber()) return false;
635 4798 : return NumberEquals(this, that);
636 10501 : } else if (this->IsString()) {
637 9237 : if (!that->IsString()) return false;
638 9162 : return String::cast(this)->Equals(String::cast(that));
639 1264 : } else if (this->IsBigInt()) {
640 90 : if (!that->IsBigInt()) return false;
641 72 : return BigInt::EqualToBigInt(BigInt::cast(this), BigInt::cast(that));
642 : }
643 1174 : return this == that;
644 : }
645 :
646 :
647 : // static
648 14081 : Handle<String> Object::TypeOf(Isolate* isolate, Handle<Object> object) {
649 14081 : if (object->IsNumber()) return isolate->factory()->number_string();
650 13557 : if (object->IsOddball()) return handle(Oddball::cast(*object)->type_of());
651 12175 : if (object->IsUndetectable()) {
652 : return isolate->factory()->undefined_string();
653 : }
654 12175 : if (object->IsString()) return isolate->factory()->string_string();
655 11812 : if (object->IsSymbol()) return isolate->factory()->symbol_string();
656 11759 : if (object->IsBigInt()) return isolate->factory()->bigint_string();
657 11741 : if (object->IsCallable()) return isolate->factory()->function_string();
658 : return isolate->factory()->object_string();
659 : }
660 :
661 :
662 : // static
663 0 : MaybeHandle<Object> Object::Multiply(Isolate* isolate, Handle<Object> lhs,
664 : Handle<Object> rhs) {
665 0 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
666 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
667 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
668 : }
669 0 : return isolate->factory()->NewNumber(lhs->Number() * rhs->Number());
670 : }
671 :
672 :
673 : // static
674 0 : MaybeHandle<Object> Object::Divide(Isolate* isolate, Handle<Object> lhs,
675 : Handle<Object> rhs) {
676 0 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
677 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
678 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
679 : }
680 0 : return isolate->factory()->NewNumber(lhs->Number() / rhs->Number());
681 : }
682 :
683 :
684 : // static
685 0 : MaybeHandle<Object> Object::Modulus(Isolate* isolate, Handle<Object> lhs,
686 : Handle<Object> rhs) {
687 0 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
688 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
689 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
690 : }
691 0 : return isolate->factory()->NewNumber(Modulo(lhs->Number(), rhs->Number()));
692 : }
693 :
694 :
695 : // static
696 48 : MaybeHandle<Object> Object::Add(Isolate* isolate, Handle<Object> lhs,
697 : Handle<Object> rhs) {
698 84 : if (lhs->IsNumber() && rhs->IsNumber()) {
699 36 : return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
700 12 : } else if (lhs->IsString() && rhs->IsString()) {
701 : return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
702 0 : Handle<String>::cast(rhs));
703 : }
704 24 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToPrimitive(lhs), Object);
705 24 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToPrimitive(rhs), Object);
706 24 : if (lhs->IsString() || rhs->IsString()) {
707 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToString(isolate, rhs),
708 : Object);
709 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToString(isolate, lhs),
710 : Object);
711 : return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
712 0 : Handle<String>::cast(rhs));
713 : }
714 24 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
715 24 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
716 12 : return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
717 : }
718 :
719 :
720 : // static
721 0 : MaybeHandle<Object> Object::Subtract(Isolate* isolate, Handle<Object> lhs,
722 : Handle<Object> rhs) {
723 0 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
724 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
725 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
726 : }
727 0 : return isolate->factory()->NewNumber(lhs->Number() - rhs->Number());
728 : }
729 :
730 :
731 : // static
732 0 : MaybeHandle<Object> Object::ShiftLeft(Isolate* isolate, Handle<Object> lhs,
733 : Handle<Object> rhs) {
734 0 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
735 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
736 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
737 : }
738 0 : return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs)
739 0 : << (NumberToUint32(*rhs) & 0x1F));
740 : }
741 :
742 :
743 : // static
744 0 : MaybeHandle<Object> Object::ShiftRight(Isolate* isolate, Handle<Object> lhs,
745 : Handle<Object> rhs) {
746 0 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
747 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
748 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
749 : }
750 0 : return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) >>
751 0 : (NumberToUint32(*rhs) & 0x1F));
752 : }
753 :
754 :
755 : // static
756 0 : MaybeHandle<Object> Object::ShiftRightLogical(Isolate* isolate,
757 : Handle<Object> lhs,
758 : Handle<Object> rhs) {
759 0 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
760 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
761 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
762 : }
763 0 : return isolate->factory()->NewNumberFromUint(NumberToUint32(*lhs) >>
764 0 : (NumberToUint32(*rhs) & 0x1F));
765 : }
766 :
767 :
768 : // static
769 0 : MaybeHandle<Object> Object::BitwiseAnd(Isolate* isolate, Handle<Object> lhs,
770 : Handle<Object> rhs) {
771 0 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
772 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
773 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
774 : }
775 0 : return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) &
776 0 : NumberToInt32(*rhs));
777 : }
778 :
779 :
780 : // static
781 0 : MaybeHandle<Object> Object::BitwiseOr(Isolate* isolate, Handle<Object> lhs,
782 : Handle<Object> rhs) {
783 0 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
784 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
785 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
786 : }
787 0 : return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) |
788 0 : NumberToInt32(*rhs));
789 : }
790 :
791 :
792 : // static
793 0 : MaybeHandle<Object> Object::BitwiseXor(Isolate* isolate, Handle<Object> lhs,
794 : Handle<Object> rhs) {
795 0 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
796 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
797 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
798 : }
799 0 : return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) ^
800 0 : NumberToInt32(*rhs));
801 : }
802 :
803 : // static
804 119654 : MaybeHandle<Object> Object::OrdinaryHasInstance(Isolate* isolate,
805 : Handle<Object> callable,
806 : Handle<Object> object) {
807 : // The {callable} must have a [[Call]] internal method.
808 119689 : if (!callable->IsCallable()) return isolate->factory()->false_value();
809 :
810 : // Check if {callable} is a bound function, and if so retrieve its
811 : // [[BoundTargetFunction]] and use that instead of {callable}.
812 119619 : if (callable->IsJSBoundFunction()) {
813 : Handle<Object> bound_callable(
814 : Handle<JSBoundFunction>::cast(callable)->bound_target_function(),
815 : isolate);
816 263 : return Object::InstanceOf(isolate, object, bound_callable);
817 : }
818 :
819 : // If {object} is not a receiver, return false.
820 128006 : if (!object->IsJSReceiver()) return isolate->factory()->false_value();
821 :
822 : // Get the "prototype" of {callable}; raise an error if it's not a receiver.
823 : Handle<Object> prototype;
824 221412 : ASSIGN_RETURN_ON_EXCEPTION(
825 : isolate, prototype,
826 : Object::GetProperty(callable, isolate->factory()->prototype_string()),
827 : Object);
828 110706 : if (!prototype->IsJSReceiver()) {
829 220692 : THROW_NEW_ERROR(
830 : isolate,
831 : NewTypeError(MessageTemplate::kInstanceofNonobjectProto, prototype),
832 : Object);
833 : }
834 :
835 : // Return whether or not {prototype} is in the prototype chain of {object}.
836 : Maybe<bool> result = JSReceiver::HasInPrototypeChain(
837 360 : isolate, Handle<JSReceiver>::cast(object), prototype);
838 360 : if (result.IsNothing()) return MaybeHandle<Object>();
839 360 : return isolate->factory()->ToBoolean(result.FromJust());
840 : }
841 :
842 : // static
843 335 : MaybeHandle<Object> Object::InstanceOf(Isolate* isolate, Handle<Object> object,
844 : Handle<Object> callable) {
845 : // The {callable} must be a receiver.
846 335 : if (!callable->IsJSReceiver()) {
847 0 : THROW_NEW_ERROR(isolate,
848 : NewTypeError(MessageTemplate::kNonObjectInInstanceOfCheck),
849 : Object);
850 : }
851 :
852 : // Lookup the @@hasInstance method on {callable}.
853 : Handle<Object> inst_of_handler;
854 670 : ASSIGN_RETURN_ON_EXCEPTION(
855 : isolate, inst_of_handler,
856 : JSReceiver::GetMethod(Handle<JSReceiver>::cast(callable),
857 : isolate->factory()->has_instance_symbol()),
858 : Object);
859 335 : if (!inst_of_handler->IsUndefined(isolate)) {
860 : // Call the {inst_of_handler} on the {callable}.
861 : Handle<Object> result;
862 658 : ASSIGN_RETURN_ON_EXCEPTION(
863 : isolate, result,
864 : Execution::Call(isolate, inst_of_handler, callable, 1, &object),
865 : Object);
866 323 : return isolate->factory()->ToBoolean(result->BooleanValue());
867 : }
868 :
869 : // The {callable} must have a [[Call]] internal method.
870 6 : if (!callable->IsCallable()) {
871 12 : THROW_NEW_ERROR(
872 : isolate, NewTypeError(MessageTemplate::kNonCallableInInstanceOfCheck),
873 : Object);
874 : }
875 :
876 : // Fall back to OrdinaryHasInstance with {callable} and {object}.
877 : Handle<Object> result;
878 0 : ASSIGN_RETURN_ON_EXCEPTION(
879 : isolate, result,
880 : JSReceiver::OrdinaryHasInstance(isolate, callable, object), Object);
881 0 : return result;
882 : }
883 :
884 : // static
885 11744922 : MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
886 : Handle<Name> name) {
887 : Handle<Object> func;
888 : Isolate* isolate = receiver->GetIsolate();
889 23489844 : ASSIGN_RETURN_ON_EXCEPTION(isolate, func,
890 : JSReceiver::GetProperty(receiver, name), Object);
891 11709418 : if (func->IsNullOrUndefined(isolate)) {
892 10630660 : return isolate->factory()->undefined_value();
893 : }
894 1078758 : if (!func->IsCallable()) {
895 468 : THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kPropertyNotFunction,
896 : func, name, receiver),
897 : Object);
898 : }
899 1078524 : return func;
900 : }
901 :
902 : namespace {
903 :
904 17548 : MaybeHandle<FixedArray> CreateListFromArrayLikeFastPath(
905 : Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
906 17548 : if (element_types == ElementTypes::kAll) {
907 16447 : if (object->IsJSArray()) {
908 : Handle<JSArray> array = Handle<JSArray>::cast(object);
909 : uint32_t length;
910 2004 : if (!array->HasArrayPrototype(isolate) ||
911 1742 : !array->length()->ToUint32(&length) || !array->HasFastElements() ||
912 188 : !JSObject::PrototypeHasNoElements(isolate, *array)) {
913 702 : return MaybeHandle<FixedArray>();
914 : }
915 116 : return array->GetElementsAccessor()->CreateListFromArrayLike(
916 232 : isolate, array, length);
917 15629 : } else if (object->IsJSTypedArray()) {
918 : Handle<JSTypedArray> array = Handle<JSTypedArray>::cast(object);
919 728 : uint32_t length = array->length_value();
920 728 : if (array->WasNeutered() ||
921 : length > static_cast<uint32_t>(FixedArray::kMaxLength)) {
922 0 : return MaybeHandle<FixedArray>();
923 : }
924 728 : return array->GetElementsAccessor()->CreateListFromArrayLike(
925 1456 : isolate, array, length);
926 : }
927 : }
928 16002 : return MaybeHandle<FixedArray>();
929 : }
930 :
931 : } // namespace
932 :
933 : // static
934 17548 : MaybeHandle<FixedArray> Object::CreateListFromArrayLike(
935 : Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
936 : // Fast-path for JSArray and JSTypedArray.
937 : MaybeHandle<FixedArray> fast_result =
938 17548 : CreateListFromArrayLikeFastPath(isolate, object, element_types);
939 17548 : if (!fast_result.is_null()) return fast_result;
940 : // 1. ReturnIfAbrupt(object).
941 : // 2. (default elementTypes -- not applicable.)
942 : // 3. If Type(obj) is not Object, throw a TypeError exception.
943 16704 : if (!object->IsJSReceiver()) {
944 1386 : THROW_NEW_ERROR(isolate,
945 : NewTypeError(MessageTemplate::kCalledOnNonObject,
946 : isolate->factory()->NewStringFromAsciiChecked(
947 : "CreateListFromArrayLike")),
948 : FixedArray);
949 : }
950 :
951 : // 4. Let len be ? ToLength(? Get(obj, "length")).
952 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
953 : Handle<Object> raw_length_number;
954 32484 : ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number,
955 : Object::GetLengthFromArrayLike(isolate, receiver),
956 : FixedArray);
957 : uint32_t len;
958 32403 : if (!raw_length_number->ToUint32(&len) ||
959 16197 : len > static_cast<uint32_t>(FixedArray::kMaxLength)) {
960 54 : THROW_NEW_ERROR(isolate,
961 : NewRangeError(MessageTemplate::kInvalidArrayLength),
962 : FixedArray);
963 : }
964 : // 5. Let list be an empty List.
965 16179 : Handle<FixedArray> list = isolate->factory()->NewFixedArray(len);
966 : // 6. Let index be 0.
967 : // 7. Repeat while index < len:
968 40162205 : for (uint32_t index = 0; index < len; ++index) {
969 : // 7a. Let indexName be ToString(index).
970 : // 7b. Let next be ? Get(obj, indexName).
971 : Handle<Object> next;
972 80292196 : ASSIGN_RETURN_ON_EXCEPTION(isolate, next,
973 : JSReceiver::GetElement(isolate, receiver, index),
974 : FixedArray);
975 40146062 : switch (element_types) {
976 : case ElementTypes::kAll:
977 : // Nothing to do.
978 : break;
979 : case ElementTypes::kStringAndSymbol: {
980 : // 7c. If Type(next) is not an element of elementTypes, throw a
981 : // TypeError exception.
982 2732 : if (!next->IsName()) {
983 72 : THROW_NEW_ERROR(isolate,
984 : NewTypeError(MessageTemplate::kNotPropertyName, next),
985 : FixedArray);
986 : }
987 : // 7d. Append next as the last element of list.
988 : // Internalize on the fly so we can use pointer identity later.
989 2696 : next = isolate->factory()->InternalizeName(Handle<Name>::cast(next));
990 2696 : break;
991 : }
992 : }
993 80292052 : list->set(index, *next);
994 : // 7e. Set index to index + 1. (See loop header.)
995 : }
996 : // 8. Return list.
997 16107 : return list;
998 : }
999 :
1000 :
1001 : // static
1002 39464 : MaybeHandle<Object> Object::GetLengthFromArrayLike(Isolate* isolate,
1003 : Handle<Object> object) {
1004 : Handle<Object> val;
1005 : Handle<Object> key = isolate->factory()->length_string();
1006 78928 : ASSIGN_RETURN_ON_EXCEPTION(
1007 : isolate, val, Runtime::GetObjectProperty(isolate, object, key), Object);
1008 39390 : return Object::ToLength(isolate, val);
1009 : }
1010 :
1011 : // static
1012 108447985 : Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) {
1013 108434010 : for (; it->IsFound(); it->Next()) {
1014 26953248 : switch (it->state()) {
1015 : case LookupIterator::NOT_FOUND:
1016 : case LookupIterator::TRANSITION:
1017 0 : UNREACHABLE();
1018 : case LookupIterator::JSPROXY:
1019 : return JSProxy::HasProperty(it->isolate(), it->GetHolder<JSProxy>(),
1020 85190 : it->GetName());
1021 : case LookupIterator::INTERCEPTOR: {
1022 : Maybe<PropertyAttributes> result =
1023 213 : JSObject::GetPropertyAttributesWithInterceptor(it);
1024 281 : if (result.IsNothing()) return Nothing<bool>();
1025 213 : if (result.FromJust() != ABSENT) return Just(true);
1026 145 : break;
1027 : }
1028 : case LookupIterator::ACCESS_CHECK: {
1029 28515 : if (it->HasAccess()) break;
1030 : Maybe<PropertyAttributes> result =
1031 40 : JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
1032 80 : if (result.IsNothing()) return Nothing<bool>();
1033 0 : return Just(result.FromJust() != ABSENT);
1034 : }
1035 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
1036 : // TypedArray out-of-bounds access.
1037 : return Just(false);
1038 : case LookupIterator::ACCESSOR:
1039 : case LookupIterator::DATA:
1040 : return Just(true);
1041 : }
1042 : }
1043 : return Just(false);
1044 : }
1045 :
1046 : // static
1047 7303357 : Maybe<bool> JSReceiver::HasOwnProperty(Handle<JSReceiver> object,
1048 : Handle<Name> name) {
1049 7303357 : if (object->IsJSModuleNamespace()) {
1050 : PropertyDescriptor desc;
1051 : return JSReceiver::GetOwnPropertyDescriptor(object->GetIsolate(), object,
1052 20 : name, &desc);
1053 : }
1054 :
1055 7303337 : if (object->IsJSObject()) { // Shortcut.
1056 : LookupIterator it = LookupIterator::PropertyOrElement(
1057 7302096 : object->GetIsolate(), object, name, object, LookupIterator::OWN);
1058 7302096 : return HasProperty(&it);
1059 : }
1060 :
1061 : Maybe<PropertyAttributes> attributes =
1062 1241 : JSReceiver::GetOwnPropertyAttributes(object, name);
1063 1241 : MAYBE_RETURN(attributes, Nothing<bool>());
1064 1151 : return Just(attributes.FromJust() != ABSENT);
1065 : }
1066 :
1067 : // static
1068 267103397 : MaybeHandle<Object> Object::GetProperty(LookupIterator* it) {
1069 245744882 : for (; it->IsFound(); it->Next()) {
1070 100818911 : switch (it->state()) {
1071 : case LookupIterator::NOT_FOUND:
1072 : case LookupIterator::TRANSITION:
1073 0 : UNREACHABLE();
1074 : case LookupIterator::JSPROXY: {
1075 : bool was_found;
1076 : MaybeHandle<Object> result =
1077 : JSProxy::GetProperty(it->isolate(), it->GetHolder<JSProxy>(),
1078 284672 : it->GetName(), it->GetReceiver(), &was_found);
1079 142336 : if (!was_found) it->NotFound();
1080 142336 : return result;
1081 : }
1082 : case LookupIterator::INTERCEPTOR: {
1083 : bool done;
1084 : Handle<Object> result;
1085 27878 : ASSIGN_RETURN_ON_EXCEPTION(
1086 : it->isolate(), result,
1087 : JSObject::GetPropertyWithInterceptor(it, &done), Object);
1088 13927 : if (done) return result;
1089 10765 : break;
1090 : }
1091 : case LookupIterator::ACCESS_CHECK:
1092 831582 : if (it->HasAccess()) break;
1093 1737 : return JSObject::GetPropertyWithFailedAccessCheck(it);
1094 : case LookupIterator::ACCESSOR:
1095 6747731 : return GetPropertyWithAccessor(it);
1096 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
1097 3249 : return it->isolate()->factory()->undefined_value();
1098 : case LookupIterator::DATA:
1099 93080076 : return it->GetDataValue();
1100 : }
1101 : }
1102 22053538 : return it->isolate()->factory()->undefined_value();
1103 : }
1104 :
1105 :
1106 : // static
1107 142336 : MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
1108 : Handle<JSProxy> proxy,
1109 : Handle<Name> name,
1110 : Handle<Object> receiver,
1111 : bool* was_found) {
1112 142336 : *was_found = true;
1113 :
1114 : DCHECK(!name->IsPrivate());
1115 142336 : STACK_CHECK(isolate, MaybeHandle<Object>());
1116 : Handle<Name> trap_name = isolate->factory()->get_string();
1117 : // 1. Assert: IsPropertyKey(P) is true.
1118 : // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
1119 : Handle<Object> handler(proxy->handler(), isolate);
1120 : // 3. If handler is null, throw a TypeError exception.
1121 : // 4. Assert: Type(handler) is Object.
1122 142192 : if (proxy->IsRevoked()) {
1123 72 : THROW_NEW_ERROR(isolate,
1124 : NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1125 : Object);
1126 : }
1127 : // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
1128 : Handle<JSReceiver> target(proxy->target(), isolate);
1129 : // 6. Let trap be ? GetMethod(handler, "get").
1130 : Handle<Object> trap;
1131 284312 : ASSIGN_RETURN_ON_EXCEPTION(
1132 : isolate, trap,
1133 : Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), Object);
1134 : // 7. If trap is undefined, then
1135 107026 : if (trap->IsUndefined(isolate)) {
1136 : // 7.a Return target.[[Get]](P, Receiver).
1137 : LookupIterator it =
1138 79948 : LookupIterator::PropertyOrElement(isolate, receiver, name, target);
1139 79948 : MaybeHandle<Object> result = Object::GetProperty(&it);
1140 159896 : *was_found = it.IsFound();
1141 79948 : return result;
1142 : }
1143 : // 8. Let trapResult be ? Call(trap, handler, «target, P, Receiver»).
1144 : Handle<Object> trap_result;
1145 27078 : Handle<Object> args[] = {target, name, receiver};
1146 54156 : ASSIGN_RETURN_ON_EXCEPTION(
1147 : isolate, trap_result,
1148 : Execution::Call(isolate, trap, handler, arraysize(args), args), Object);
1149 :
1150 : MaybeHandle<Object> result =
1151 25589 : JSProxy::CheckGetSetTrapResult(isolate, name, target, trap_result, kGet);
1152 25589 : if (result.is_null()) {
1153 30 : return result;
1154 : }
1155 :
1156 : // 11. Return trap_result
1157 25559 : return trap_result;
1158 : }
1159 :
1160 : // static
1161 27966 : MaybeHandle<Object> JSProxy::CheckGetSetTrapResult(Isolate* isolate,
1162 : Handle<Name> name,
1163 : Handle<JSReceiver> target,
1164 : Handle<Object> trap_result,
1165 : AccessKind access_kind) {
1166 : // 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
1167 : PropertyDescriptor target_desc;
1168 : Maybe<bool> target_found =
1169 27966 : JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
1170 27966 : MAYBE_RETURN_NULL(target_found);
1171 : // 10. If targetDesc is not undefined, then
1172 27957 : if (target_found.FromJust()) {
1173 : // 10.a. If IsDataDescriptor(targetDesc) and targetDesc.[[Configurable]] is
1174 : // false and targetDesc.[[Writable]] is false, then
1175 : // 10.a.i. If SameValue(trapResult, targetDesc.[[Value]]) is false,
1176 : // throw a TypeError exception.
1177 7349 : bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
1178 3556 : !target_desc.configurable() &&
1179 10517 : !target_desc.writable() &&
1180 2799 : !trap_result->SameValue(*target_desc.value());
1181 7718 : if (inconsistent) {
1182 219 : if (access_kind == kGet) {
1183 78 : THROW_NEW_ERROR(
1184 : isolate,
1185 : NewTypeError(MessageTemplate::kProxyGetNonConfigurableData, name,
1186 : target_desc.value(), trap_result),
1187 : Object);
1188 : } else {
1189 : isolate->Throw(*isolate->factory()->NewTypeError(
1190 360 : MessageTemplate::kProxySetFrozenData, name));
1191 180 : return MaybeHandle<Object>();
1192 : }
1193 : }
1194 : // 10.b. If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]]
1195 : // is false and targetDesc.[[Get]] is undefined, then
1196 : // 10.b.i. If trapResult is not undefined, throw a TypeError exception.
1197 7499 : if (access_kind == kGet) {
1198 0 : inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
1199 0 : !target_desc.configurable() &&
1200 6122 : target_desc.get()->IsUndefined(isolate) &&
1201 6122 : !trap_result->IsUndefined(isolate);
1202 : } else {
1203 369 : inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
1204 1566 : !target_desc.configurable() &&
1205 1377 : target_desc.set()->IsUndefined(isolate);
1206 : }
1207 7499 : if (inconsistent) {
1208 189 : if (access_kind == kGet) {
1209 0 : THROW_NEW_ERROR(
1210 : isolate,
1211 : NewTypeError(MessageTemplate::kProxyGetNonConfigurableAccessor,
1212 : name, trap_result),
1213 : Object);
1214 : } else {
1215 : isolate->Throw(*isolate->factory()->NewTypeError(
1216 378 : MessageTemplate::kProxySetFrozenAccessor, name));
1217 189 : return MaybeHandle<Object>();
1218 : }
1219 : }
1220 : }
1221 27549 : return isolate->factory()->undefined_value();
1222 : }
1223 :
1224 :
1225 9519283 : Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it) {
1226 9013446 : for (; it->IsFound(); it->Next()) {
1227 4463671 : switch (it->state()) {
1228 : case LookupIterator::INTERCEPTOR:
1229 : case LookupIterator::NOT_FOUND:
1230 : case LookupIterator::TRANSITION:
1231 0 : UNREACHABLE();
1232 : case LookupIterator::ACCESS_CHECK:
1233 : // Support calling this method without an active context, but refuse
1234 : // access to access-checked objects in that case.
1235 485918 : if (it->isolate()->context() != nullptr && it->HasAccess()) continue;
1236 : // Fall through.
1237 : case LookupIterator::JSPROXY:
1238 : it->NotFound();
1239 2764 : return it->isolate()->factory()->undefined_value();
1240 : case LookupIterator::ACCESSOR:
1241 : // TODO(verwaest): For now this doesn't call into AccessorInfo, since
1242 : // clients don't need it. Update once relevant.
1243 : it->NotFound();
1244 459094 : return it->isolate()->factory()->undefined_value();
1245 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
1246 0 : return it->isolate()->factory()->undefined_value();
1247 : case LookupIterator::DATA:
1248 3516822 : return it->GetDataValue();
1249 : }
1250 : }
1251 43052 : return it->isolate()->factory()->undefined_value();
1252 : }
1253 :
1254 :
1255 12816461 : bool Object::ToInt32(int32_t* value) {
1256 12816461 : if (IsSmi()) {
1257 12816461 : *value = Smi::ToInt(this);
1258 12816461 : return true;
1259 : }
1260 0 : if (IsHeapNumber()) {
1261 : double num = HeapNumber::cast(this)->value();
1262 0 : if (FastI2D(FastD2I(num)) == num) {
1263 0 : *value = FastD2I(num);
1264 0 : return true;
1265 : }
1266 : }
1267 : return false;
1268 : }
1269 :
1270 3115288 : Handle<SharedFunctionInfo> FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(
1271 : Isolate* isolate, Handle<FunctionTemplateInfo> info,
1272 : MaybeHandle<Name> maybe_name) {
1273 : Object* current_info = info->shared_function_info();
1274 3115288 : if (current_info->IsSharedFunctionInfo()) {
1275 : return handle(SharedFunctionInfo::cast(current_info), isolate);
1276 : }
1277 : Handle<Object> class_name(info->class_name(), isolate);
1278 : Handle<Name> name;
1279 : Handle<String> name_string;
1280 5655894 : if (maybe_name.ToHandle(&name) && name->IsString()) {
1281 : name_string = Handle<String>::cast(name);
1282 : } else {
1283 : name_string = class_name->IsString() ? Handle<String>::cast(class_name)
1284 382616 : : isolate->factory()->empty_string();
1285 : }
1286 3019252 : Handle<Code> code = BUILTIN_CODE(isolate, HandleApiCall);
1287 : bool is_constructor;
1288 : FunctionKind function_kind;
1289 3019252 : if (!info->remove_prototype()) {
1290 : is_constructor = true;
1291 : function_kind = kNormalFunction;
1292 : } else {
1293 : is_constructor = false;
1294 : function_kind = kConciseMethod;
1295 : }
1296 : Handle<SharedFunctionInfo> result = isolate->factory()->NewSharedFunctionInfo(
1297 6038504 : name_string, code, is_constructor, function_kind);
1298 3019252 : if (is_constructor) {
1299 5977748 : result->SetConstructStub(*BUILTIN_CODE(isolate, JSConstructStubApi));
1300 : }
1301 :
1302 : result->set_length(info->length());
1303 3064959 : if (class_name->IsString()) result->set_instance_class_name(*class_name);
1304 : result->set_api_func_data(*info);
1305 : result->DontAdaptArguments();
1306 : DCHECK(result->IsApiFunction());
1307 :
1308 3019252 : info->set_shared_function_info(*result);
1309 3019252 : return result;
1310 : }
1311 :
1312 16521 : bool FunctionTemplateInfo::IsTemplateFor(Map* map) {
1313 : // There is a constraint on the object; check.
1314 16521 : if (!map->IsJSObjectMap()) return false;
1315 : // Fetch the constructor function of the object.
1316 16521 : Object* cons_obj = map->GetConstructor();
1317 : Object* type;
1318 16521 : if (cons_obj->IsJSFunction()) {
1319 : JSFunction* fun = JSFunction::cast(cons_obj);
1320 : type = fun->shared()->function_data();
1321 16 : } else if (cons_obj->IsFunctionTemplateInfo()) {
1322 : type = FunctionTemplateInfo::cast(cons_obj);
1323 : } else {
1324 : return false;
1325 : }
1326 : // Iterate through the chain of inheriting function templates to
1327 : // see if the required one occurs.
1328 17593 : while (type->IsFunctionTemplateInfo()) {
1329 10272 : if (type == this) return true;
1330 : type = FunctionTemplateInfo::cast(type)->parent_template();
1331 : }
1332 : // Didn't find the required type in the inheritance chain.
1333 : return false;
1334 : }
1335 :
1336 :
1337 : // static
1338 324224 : Handle<TemplateList> TemplateList::New(Isolate* isolate, int size) {
1339 : Handle<FixedArray> list =
1340 324224 : isolate->factory()->NewFixedArray(kLengthIndex + size);
1341 : list->set(kLengthIndex, Smi::kZero);
1342 324224 : return Handle<TemplateList>::cast(list);
1343 : }
1344 :
1345 : // static
1346 5249611 : Handle<TemplateList> TemplateList::Add(Isolate* isolate,
1347 : Handle<TemplateList> list,
1348 : Handle<i::Object> value) {
1349 : STATIC_ASSERT(kFirstElementIndex == 1);
1350 5249611 : int index = list->length() + 1;
1351 : Handle<i::FixedArray> fixed_array = Handle<FixedArray>::cast(list);
1352 5249611 : fixed_array = FixedArray::SetAndGrow(fixed_array, index, value);
1353 : fixed_array->set(kLengthIndex, Smi::FromInt(index));
1354 5249611 : return Handle<TemplateList>::cast(fixed_array);
1355 : }
1356 :
1357 : // static
1358 2136901 : MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor,
1359 : Handle<JSReceiver> new_target,
1360 : Handle<AllocationSite> site) {
1361 : // If called through new, new.target can be:
1362 : // - a subclass of constructor,
1363 : // - a proxy wrapper around constructor, or
1364 : // - the constructor itself.
1365 : // If called through Reflect.construct, it's guaranteed to be a constructor.
1366 : Isolate* const isolate = constructor->GetIsolate();
1367 : DCHECK(constructor->IsConstructor());
1368 : DCHECK(new_target->IsConstructor());
1369 : DCHECK(!constructor->has_initial_map() ||
1370 : constructor->initial_map()->instance_type() != JS_FUNCTION_TYPE);
1371 :
1372 : Handle<Map> initial_map;
1373 4273802 : ASSIGN_RETURN_ON_EXCEPTION(
1374 : isolate, initial_map,
1375 : JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject);
1376 : Handle<JSObject> result =
1377 2136841 : isolate->factory()->NewJSObjectFromMap(initial_map, NOT_TENURED, site);
1378 2136841 : if (initial_map->is_dictionary_map()) {
1379 : Handle<NameDictionary> dictionary =
1380 0 : NameDictionary::New(isolate, NameDictionary::kInitialCapacity);
1381 0 : result->SetProperties(*dictionary);
1382 : }
1383 2136841 : isolate->counters()->constructed_objects()->Increment();
1384 2136841 : isolate->counters()->constructed_objects_runtime()->Increment();
1385 2136841 : return result;
1386 : }
1387 :
1388 4869754 : void JSObject::EnsureWritableFastElements(Handle<JSObject> object) {
1389 : DCHECK(object->HasSmiOrObjectElements() ||
1390 : object->HasFastStringWrapperElements());
1391 : FixedArray* raw_elems = FixedArray::cast(object->elements());
1392 4869754 : Heap* heap = object->GetHeap();
1393 9721243 : if (raw_elems->map() != heap->fixed_cow_array_map()) return;
1394 : Isolate* isolate = heap->isolate();
1395 : Handle<FixedArray> elems(raw_elems, isolate);
1396 : Handle<FixedArray> writable_elems = isolate->factory()->CopyFixedArrayWithMap(
1397 18265 : elems, isolate->factory()->fixed_array_map());
1398 18265 : object->set_elements(*writable_elems);
1399 18265 : isolate->counters()->cow_arrays_converted()->Increment();
1400 : }
1401 :
1402 7151007 : int JSObject::GetHeaderSize(InstanceType type,
1403 : bool function_has_prototype_slot) {
1404 7151007 : switch (type) {
1405 : case JS_OBJECT_TYPE:
1406 : case JS_API_OBJECT_TYPE:
1407 : case JS_SPECIAL_API_OBJECT_TYPE:
1408 : return JSObject::kHeaderSize;
1409 : case JS_GENERATOR_OBJECT_TYPE:
1410 11072 : return JSGeneratorObject::kSize;
1411 : case JS_ASYNC_GENERATOR_OBJECT_TYPE:
1412 1302 : return JSAsyncGeneratorObject::kSize;
1413 : case JS_GLOBAL_PROXY_TYPE:
1414 10 : return JSGlobalProxy::kSize;
1415 : case JS_GLOBAL_OBJECT_TYPE:
1416 622 : return JSGlobalObject::kSize;
1417 : case JS_BOUND_FUNCTION_TYPE:
1418 15 : return JSBoundFunction::kSize;
1419 : case JS_FUNCTION_TYPE:
1420 : return function_has_prototype_slot ? JSFunction::kSizeWithPrototype
1421 5950896 : : JSFunction::kSizeWithoutPrototype;
1422 : case JS_VALUE_TYPE:
1423 4591 : return JSValue::kSize;
1424 : case JS_DATE_TYPE:
1425 1740 : return JSDate::kSize;
1426 : case JS_ARRAY_TYPE:
1427 80574 : return JSArray::kSize;
1428 : case JS_ARRAY_BUFFER_TYPE:
1429 498590 : return JSArrayBuffer::kSize;
1430 : case JS_TYPED_ARRAY_TYPE:
1431 8817 : return JSTypedArray::kSize;
1432 : case JS_DATA_VIEW_TYPE:
1433 7580 : return JSDataView::kSize;
1434 : case JS_SET_TYPE:
1435 1439 : return JSSet::kSize;
1436 : case JS_MAP_TYPE:
1437 1285 : return JSMap::kSize;
1438 : case JS_SET_KEY_VALUE_ITERATOR_TYPE:
1439 : case JS_SET_VALUE_ITERATOR_TYPE:
1440 0 : return JSSetIterator::kSize;
1441 : case JS_MAP_KEY_ITERATOR_TYPE:
1442 : case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
1443 : case JS_MAP_VALUE_ITERATOR_TYPE:
1444 0 : return JSMapIterator::kSize;
1445 : case JS_WEAK_MAP_TYPE:
1446 1471 : return JSWeakMap::kSize;
1447 : case JS_WEAK_SET_TYPE:
1448 1473 : return JSWeakSet::kSize;
1449 : case JS_PROMISE_TYPE:
1450 275 : return JSPromise::kSize;
1451 : case JS_REGEXP_TYPE:
1452 1573 : return JSRegExp::kSize;
1453 : case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
1454 : return JSObject::kHeaderSize;
1455 : case JS_MESSAGE_OBJECT_TYPE:
1456 0 : return JSMessageObject::kSize;
1457 : case JS_ARGUMENTS_TYPE:
1458 : return JSObject::kHeaderSize;
1459 : case JS_ERROR_TYPE:
1460 : return JSObject::kHeaderSize;
1461 : case JS_STRING_ITERATOR_TYPE:
1462 0 : return JSStringIterator::kSize;
1463 : case JS_MODULE_NAMESPACE_TYPE:
1464 122 : return JSModuleNamespace::kHeaderSize;
1465 : case WASM_INSTANCE_TYPE:
1466 0 : return WasmInstanceObject::kSize;
1467 : case WASM_MEMORY_TYPE:
1468 0 : return WasmMemoryObject::kSize;
1469 : case WASM_MODULE_TYPE:
1470 0 : return WasmModuleObject::kSize;
1471 : case WASM_TABLE_TYPE:
1472 0 : return WasmTableObject::kSize;
1473 : default:
1474 20 : if (type >= FIRST_ARRAY_ITERATOR_TYPE &&
1475 : type <= LAST_ARRAY_ITERATOR_TYPE) {
1476 : return JSArrayIterator::kSize;
1477 : }
1478 0 : UNREACHABLE();
1479 : }
1480 : }
1481 :
1482 : // ES6 9.5.1
1483 : // static
1484 3790593 : MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
1485 : Isolate* isolate = proxy->GetIsolate();
1486 : Handle<String> trap_name = isolate->factory()->getPrototypeOf_string();
1487 :
1488 3790593 : STACK_CHECK(isolate, MaybeHandle<Object>());
1489 :
1490 : // 1. Let handler be the value of the [[ProxyHandler]] internal slot.
1491 : // 2. If handler is null, throw a TypeError exception.
1492 : // 3. Assert: Type(handler) is Object.
1493 : // 4. Let target be the value of the [[ProxyTarget]] internal slot.
1494 3790593 : if (proxy->IsRevoked()) {
1495 36 : THROW_NEW_ERROR(isolate,
1496 : NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1497 : Object);
1498 : }
1499 : Handle<JSReceiver> target(proxy->target(), isolate);
1500 : Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
1501 :
1502 : // 5. Let trap be ? GetMethod(handler, "getPrototypeOf").
1503 : Handle<Object> trap;
1504 7581150 : ASSIGN_RETURN_ON_EXCEPTION(isolate, trap, GetMethod(handler, trap_name),
1505 : Object);
1506 : // 6. If trap is undefined, then return target.[[GetPrototypeOf]]().
1507 3790575 : if (trap->IsUndefined(isolate)) {
1508 2766197 : return JSReceiver::GetPrototype(isolate, target);
1509 : }
1510 : // 7. Let handlerProto be ? Call(trap, handler, «target»).
1511 : Handle<Object> argv[] = {target};
1512 : Handle<Object> handler_proto;
1513 2048756 : ASSIGN_RETURN_ON_EXCEPTION(
1514 : isolate, handler_proto,
1515 : Execution::Call(isolate, trap, handler, arraysize(argv), argv), Object);
1516 : // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError.
1517 1024306 : if (!(handler_proto->IsJSReceiver() || handler_proto->IsNull(isolate))) {
1518 18 : THROW_NEW_ERROR(isolate,
1519 : NewTypeError(MessageTemplate::kProxyGetPrototypeOfInvalid),
1520 : Object);
1521 : }
1522 : // 9. Let extensibleTarget be ? IsExtensible(target).
1523 1024270 : Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
1524 1024270 : MAYBE_RETURN_NULL(is_extensible);
1525 : // 10. If extensibleTarget is true, return handlerProto.
1526 1024270 : if (is_extensible.FromJust()) return handler_proto;
1527 : // 11. Let targetProto be ? target.[[GetPrototypeOf]]().
1528 : Handle<Object> target_proto;
1529 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, target_proto,
1530 : JSReceiver::GetPrototype(isolate, target), Object);
1531 : // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError.
1532 0 : if (!handler_proto->SameValue(*target_proto)) {
1533 0 : THROW_NEW_ERROR(
1534 : isolate,
1535 : NewTypeError(MessageTemplate::kProxyGetPrototypeOfNonExtensible),
1536 : Object);
1537 : }
1538 : // 13. Return handlerProto.
1539 0 : return handler_proto;
1540 : }
1541 :
1542 6748099 : MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) {
1543 : Isolate* isolate = it->isolate();
1544 6748099 : Handle<Object> structure = it->GetAccessors();
1545 : Handle<Object> receiver = it->GetReceiver();
1546 : // In case of global IC, the receiver is the global object. Replace by the
1547 : // global proxy.
1548 6748099 : if (receiver->IsJSGlobalObject()) {
1549 : receiver = handle(JSGlobalObject::cast(*receiver)->global_proxy(), isolate);
1550 : }
1551 :
1552 : // We should never get here to initialize a const with the hole value since a
1553 : // const declaration would conflict with the getter.
1554 : DCHECK(!structure->IsForeign());
1555 :
1556 : // API style callbacks.
1557 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1558 6748099 : if (structure->IsAccessorInfo()) {
1559 559923 : Handle<Name> name = it->GetName();
1560 : Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
1561 559923 : if (!info->IsCompatibleReceiver(*receiver)) {
1562 180 : THROW_NEW_ERROR(isolate,
1563 : NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
1564 : name, receiver),
1565 : Object);
1566 : }
1567 :
1568 : v8::AccessorNameGetterCallback call_fun =
1569 : v8::ToCData<v8::AccessorNameGetterCallback>(info->getter());
1570 559953 : if (call_fun == nullptr) return isolate->factory()->undefined_value();
1571 :
1572 572711 : if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1573 30 : ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver,
1574 : Object::ConvertReceiver(isolate, receiver),
1575 : Object);
1576 : }
1577 :
1578 : PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1579 : Object::DONT_THROW);
1580 559713 : Handle<Object> result = args.Call(call_fun, name);
1581 559713 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1582 567079 : if (result.is_null()) return isolate->factory()->undefined_value();
1583 : Handle<Object> reboxed_result = handle(*result, isolate);
1584 551943 : if (info->replace_on_access() && receiver->IsJSReceiver()) {
1585 : args.Call(reinterpret_cast<GenericNamedPropertySetterCallback>(
1586 : &Accessors::ReconfigureToDataProperty),
1587 0 : name, result);
1588 0 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1589 : }
1590 551943 : return reboxed_result;
1591 : }
1592 :
1593 : // AccessorPair with 'cached' private property.
1594 6188176 : if (it->TryLookupCachedProperty()) {
1595 51 : return Object::GetProperty(it);
1596 : }
1597 :
1598 : // Regular accessor.
1599 : Handle<Object> getter(AccessorPair::cast(*structure)->getter(), isolate);
1600 6188125 : if (getter->IsFunctionTemplateInfo()) {
1601 667 : SaveContext save(isolate);
1602 1334 : isolate->set_context(*holder->GetCreationContext());
1603 : return Builtins::InvokeApiFunction(
1604 : isolate, false, Handle<FunctionTemplateInfo>::cast(getter), receiver, 0,
1605 667 : nullptr, isolate->factory()->undefined_value());
1606 6187458 : } else if (getter->IsCallable()) {
1607 : // TODO(rossberg): nicer would be to cast to some JSCallable here...
1608 : return Object::GetPropertyWithDefinedGetter(
1609 6182161 : receiver, Handle<JSReceiver>::cast(getter));
1610 : }
1611 : // Getter is not a function.
1612 5297 : return isolate->factory()->undefined_value();
1613 : }
1614 :
1615 : // static
1616 0 : Address AccessorInfo::redirect(Isolate* isolate, Address address,
1617 : AccessorComponent component) {
1618 : ApiFunction fun(address);
1619 : DCHECK_EQ(ACCESSOR_GETTER, component);
1620 : ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
1621 317262 : return ExternalReference(&fun, type, isolate).address();
1622 : }
1623 :
1624 159830 : Address AccessorInfo::redirected_getter() const {
1625 : Address accessor = v8::ToCData<Address>(getter());
1626 159830 : if (accessor == nullptr) return nullptr;
1627 158631 : return redirect(GetIsolate(), accessor, ACCESSOR_GETTER);
1628 : }
1629 :
1630 108163 : bool AccessorInfo::IsCompatibleReceiverMap(Isolate* isolate,
1631 : Handle<AccessorInfo> info,
1632 : Handle<Map> map) {
1633 108163 : if (!info->HasExpectedReceiverType()) return true;
1634 60 : if (!map->IsJSObjectMap()) return false;
1635 : return FunctionTemplateInfo::cast(info->expected_receiver_type())
1636 60 : ->IsTemplateFor(*map);
1637 : }
1638 :
1639 626670 : Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it,
1640 : Handle<Object> value,
1641 : ShouldThrow should_throw) {
1642 : Isolate* isolate = it->isolate();
1643 626670 : Handle<Object> structure = it->GetAccessors();
1644 : Handle<Object> receiver = it->GetReceiver();
1645 : // In case of global IC, the receiver is the global object. Replace by the
1646 : // global proxy.
1647 626670 : if (receiver->IsJSGlobalObject()) {
1648 : receiver = handle(JSGlobalObject::cast(*receiver)->global_proxy(), isolate);
1649 : }
1650 :
1651 : // We should never get here to initialize a const with the hole value since a
1652 : // const declaration would conflict with the setter.
1653 : DCHECK(!structure->IsForeign());
1654 :
1655 : // API style callbacks.
1656 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1657 626670 : if (structure->IsAccessorInfo()) {
1658 348644 : Handle<Name> name = it->GetName();
1659 : Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
1660 348644 : if (!info->IsCompatibleReceiver(*receiver)) {
1661 : isolate->Throw(*isolate->factory()->NewTypeError(
1662 180 : MessageTemplate::kIncompatibleMethodReceiver, name, receiver));
1663 : return Nothing<bool>();
1664 : }
1665 :
1666 : // The actual type of call_fun is either v8::AccessorNameSetterCallback or
1667 : // i::Accesors::AccessorNameBooleanSetterCallback, depending on whether the
1668 : // AccessorInfo was created by the API or internally (see accessors.cc).
1669 : // Here we handle both cases using GenericNamedPropertySetterCallback and
1670 : // its Call method.
1671 : GenericNamedPropertySetterCallback call_fun =
1672 : v8::ToCData<GenericNamedPropertySetterCallback>(info->setter());
1673 :
1674 348554 : if (call_fun == nullptr) {
1675 : // TODO(verwaest): We should not get here anymore once all AccessorInfos
1676 : // are marked as special_data_property. They cannot both be writable and
1677 : // not have a setter.
1678 : return Just(true);
1679 : }
1680 :
1681 469106 : if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1682 0 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1683 : isolate, receiver, Object::ConvertReceiver(isolate, receiver),
1684 : Nothing<bool>());
1685 : }
1686 :
1687 : PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1688 : should_throw);
1689 348488 : Handle<Object> result = args.Call(call_fun, name, value);
1690 : // In the case of AccessorNameSetterCallback, we know that the result value
1691 : // cannot have been set, so the result of Call will be null. In the case of
1692 : // AccessorNameBooleanSetterCallback, the result will either be null
1693 : // (signalling an exception) or a boolean Oddball.
1694 348488 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1695 348310 : if (result.is_null()) return Just(true);
1696 : DCHECK(result->BooleanValue() || should_throw == DONT_THROW);
1697 227758 : return Just(result->BooleanValue());
1698 : }
1699 :
1700 : // Regular accessor.
1701 : Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
1702 278026 : if (setter->IsFunctionTemplateInfo()) {
1703 534 : SaveContext save(isolate);
1704 1068 : isolate->set_context(*holder->GetCreationContext());
1705 534 : Handle<Object> argv[] = {value};
1706 1068 : RETURN_ON_EXCEPTION_VALUE(
1707 : isolate, Builtins::InvokeApiFunction(
1708 : isolate, false, Handle<FunctionTemplateInfo>::cast(setter),
1709 : receiver, arraysize(argv), argv,
1710 : isolate->factory()->undefined_value()),
1711 : Nothing<bool>());
1712 534 : return Just(true);
1713 277492 : } else if (setter->IsCallable()) {
1714 : // TODO(rossberg): nicer would be to cast to some JSCallable here...
1715 : return SetPropertyWithDefinedSetter(
1716 265025 : receiver, Handle<JSReceiver>::cast(setter), value, should_throw);
1717 : }
1718 :
1719 30554 : RETURN_FAILURE(isolate, should_throw,
1720 : NewTypeError(MessageTemplate::kNoSetterInCallback,
1721 : it->GetName(), it->GetHolder<JSObject>()));
1722 : }
1723 :
1724 :
1725 6182161 : MaybeHandle<Object> Object::GetPropertyWithDefinedGetter(
1726 : Handle<Object> receiver,
1727 : Handle<JSReceiver> getter) {
1728 : Isolate* isolate = getter->GetIsolate();
1729 :
1730 : // Platforms with simulators like arm/arm64 expose a funny issue. If the
1731 : // simulator has a separate JS stack pointer from the C++ stack pointer, it
1732 : // can miss C++ stack overflows in the stack guard at the start of JavaScript
1733 : // functions. It would be very expensive to check the C++ stack pointer at
1734 : // that location. The best solution seems to be to break the impasse by
1735 : // adding checks at possible recursion points. What's more, we don't put
1736 : // this stack check behind the USE_SIMULATOR define in order to keep
1737 : // behavior the same between hardware and simulators.
1738 : StackLimitCheck check(isolate);
1739 6182161 : if (check.JsHasOverflowed()) {
1740 26 : isolate->StackOverflow();
1741 26 : return MaybeHandle<Object>();
1742 : }
1743 :
1744 6182135 : return Execution::Call(isolate, getter, receiver, 0, nullptr);
1745 : }
1746 :
1747 :
1748 265025 : Maybe<bool> Object::SetPropertyWithDefinedSetter(Handle<Object> receiver,
1749 : Handle<JSReceiver> setter,
1750 : Handle<Object> value,
1751 : ShouldThrow should_throw) {
1752 : Isolate* isolate = setter->GetIsolate();
1753 :
1754 265025 : Handle<Object> argv[] = { value };
1755 530050 : RETURN_ON_EXCEPTION_VALUE(isolate, Execution::Call(isolate, setter, receiver,
1756 : arraysize(argv), argv),
1757 : Nothing<bool>());
1758 : return Just(true);
1759 : }
1760 :
1761 :
1762 : // static
1763 4700 : bool JSObject::AllCanRead(LookupIterator* it) {
1764 : // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of
1765 : // which have already been checked.
1766 : DCHECK(it->state() == LookupIterator::ACCESS_CHECK ||
1767 : it->state() == LookupIterator::INTERCEPTOR);
1768 5840 : for (it->Next(); it->IsFound(); it->Next()) {
1769 1210 : if (it->state() == LookupIterator::ACCESSOR) {
1770 122 : auto accessors = it->GetAccessors();
1771 122 : if (accessors->IsAccessorInfo()) {
1772 77 : if (AccessorInfo::cast(*accessors)->all_can_read()) return true;
1773 : }
1774 1088 : } else if (it->state() == LookupIterator::INTERCEPTOR) {
1775 1260 : if (it->GetInterceptor()->all_can_read()) return true;
1776 458 : } else if (it->state() == LookupIterator::JSPROXY) {
1777 : // Stop lookupiterating. And no, AllCanNotRead.
1778 : return false;
1779 : }
1780 : }
1781 : return false;
1782 : }
1783 :
1784 : namespace {
1785 :
1786 14107 : MaybeHandle<Object> GetPropertyWithInterceptorInternal(
1787 28056 : LookupIterator* it, Handle<InterceptorInfo> interceptor, bool* done) {
1788 14107 : *done = false;
1789 : Isolate* isolate = it->isolate();
1790 : // Make sure that the top context does not change when doing callbacks or
1791 : // interceptor calls.
1792 : AssertNoContextChange ncc(isolate);
1793 :
1794 14107 : if (interceptor->getter()->IsUndefined(isolate)) {
1795 158 : return isolate->factory()->undefined_value();
1796 : }
1797 :
1798 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1799 : Handle<Object> result;
1800 : Handle<Object> receiver = it->GetReceiver();
1801 13949 : if (!receiver->IsJSReceiver()) {
1802 32 : ASSIGN_RETURN_ON_EXCEPTION(
1803 : isolate, receiver, Object::ConvertReceiver(isolate, receiver), Object);
1804 : }
1805 : PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1806 : *holder, Object::DONT_THROW);
1807 :
1808 13949 : if (it->IsElement()) {
1809 : uint32_t index = it->index();
1810 : v8::IndexedPropertyGetterCallback getter =
1811 : v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
1812 2404 : result = args.Call(getter, index);
1813 : } else {
1814 11545 : Handle<Name> name = it->name();
1815 : DCHECK(!name->IsPrivate());
1816 :
1817 : DCHECK_IMPLIES(name->IsSymbol(), interceptor->can_intercept_symbols());
1818 :
1819 : v8::GenericNamedPropertyGetterCallback getter =
1820 : v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
1821 : interceptor->getter());
1822 11545 : result = args.Call(getter, name);
1823 : }
1824 :
1825 13949 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1826 24614 : if (result.is_null()) return isolate->factory()->undefined_value();
1827 3236 : *done = true;
1828 : // Rebox handle before return
1829 3236 : return handle(*result, isolate);
1830 : }
1831 :
1832 250419 : Maybe<PropertyAttributes> GetPropertyAttributesWithInterceptorInternal(
1833 500692 : LookupIterator* it, Handle<InterceptorInfo> interceptor) {
1834 : Isolate* isolate = it->isolate();
1835 : // Make sure that the top context does not change when doing
1836 : // callbacks or interceptor calls.
1837 : AssertNoContextChange ncc(isolate);
1838 : HandleScope scope(isolate);
1839 :
1840 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1841 : DCHECK_IMPLIES(!it->IsElement() && it->name()->IsSymbol(),
1842 : interceptor->can_intercept_symbols());
1843 : Handle<Object> receiver = it->GetReceiver();
1844 250419 : if (!receiver->IsJSReceiver()) {
1845 24 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1846 : Object::ConvertReceiver(isolate, receiver),
1847 : Nothing<PropertyAttributes>());
1848 : }
1849 : PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1850 : *holder, Object::DONT_THROW);
1851 250419 : if (!interceptor->query()->IsUndefined(isolate)) {
1852 : Handle<Object> result;
1853 545 : if (it->IsElement()) {
1854 : uint32_t index = it->index();
1855 : v8::IndexedPropertyQueryCallback query =
1856 : v8::ToCData<v8::IndexedPropertyQueryCallback>(interceptor->query());
1857 314 : result = args.Call(query, index);
1858 : } else {
1859 231 : Handle<Name> name = it->name();
1860 : DCHECK(!name->IsPrivate());
1861 : v8::GenericNamedPropertyQueryCallback query =
1862 : v8::ToCData<v8::GenericNamedPropertyQueryCallback>(
1863 : interceptor->query());
1864 231 : result = args.Call(query, name);
1865 : }
1866 545 : if (!result.is_null()) {
1867 : int32_t value;
1868 370 : CHECK(result->ToInt32(&value));
1869 370 : return Just(static_cast<PropertyAttributes>(value));
1870 : }
1871 249874 : } else if (!interceptor->getter()->IsUndefined(isolate)) {
1872 : // TODO(verwaest): Use GetPropertyWithInterceptor?
1873 : Handle<Object> result;
1874 249728 : if (it->IsElement()) {
1875 : uint32_t index = it->index();
1876 : v8::IndexedPropertyGetterCallback getter =
1877 : v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
1878 240213 : result = args.Call(getter, index);
1879 : } else {
1880 9515 : Handle<Name> name = it->name();
1881 : DCHECK(!name->IsPrivate());
1882 : v8::GenericNamedPropertyGetterCallback getter =
1883 : v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
1884 : interceptor->getter());
1885 9515 : result = args.Call(getter, name);
1886 : }
1887 249728 : if (!result.is_null()) return Just(DONT_ENUM);
1888 : }
1889 :
1890 240634 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
1891 : return Just(ABSENT);
1892 : }
1893 :
1894 193438 : Maybe<bool> SetPropertyWithInterceptorInternal(
1895 566504 : LookupIterator* it, Handle<InterceptorInfo> interceptor,
1896 : Object::ShouldThrow should_throw, Handle<Object> value) {
1897 : Isolate* isolate = it->isolate();
1898 : // Make sure that the top context does not change when doing callbacks or
1899 : // interceptor calls.
1900 : AssertNoContextChange ncc(isolate);
1901 :
1902 193438 : if (interceptor->setter()->IsUndefined(isolate)) return Just(false);
1903 :
1904 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1905 : bool result;
1906 : Handle<Object> receiver = it->GetReceiver();
1907 186533 : if (!receiver->IsJSReceiver()) {
1908 0 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1909 : Object::ConvertReceiver(isolate, receiver),
1910 : Nothing<bool>());
1911 : }
1912 : PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1913 : *holder, should_throw);
1914 :
1915 186533 : if (it->IsElement()) {
1916 : uint32_t index = it->index();
1917 : v8::IndexedPropertySetterCallback setter =
1918 : v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter());
1919 : // TODO(neis): In the future, we may want to actually return the
1920 : // interceptor's result, which then should be a boolean.
1921 131336 : result = !args.Call(setter, index, value).is_null();
1922 : } else {
1923 120865 : Handle<Name> name = it->name();
1924 : DCHECK(!name->IsPrivate());
1925 :
1926 : DCHECK_IMPLIES(name->IsSymbol(), interceptor->can_intercept_symbols());
1927 :
1928 : v8::GenericNamedPropertySetterCallback setter =
1929 : v8::ToCData<v8::GenericNamedPropertySetterCallback>(
1930 : interceptor->setter());
1931 241730 : result = !args.Call(setter, name, value).is_null();
1932 : }
1933 :
1934 186533 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1935 : return Just(result);
1936 : }
1937 :
1938 178 : Maybe<bool> DefinePropertyWithInterceptorInternal(
1939 342 : LookupIterator* it, Handle<InterceptorInfo> interceptor,
1940 : Object::ShouldThrow should_throw, PropertyDescriptor& desc) {
1941 : Isolate* isolate = it->isolate();
1942 : // Make sure that the top context does not change when doing callbacks or
1943 : // interceptor calls.
1944 : AssertNoContextChange ncc(isolate);
1945 :
1946 178 : if (interceptor->definer()->IsUndefined(isolate)) return Just(false);
1947 :
1948 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1949 : bool result;
1950 : Handle<Object> receiver = it->GetReceiver();
1951 82 : if (!receiver->IsJSReceiver()) {
1952 0 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1953 : Object::ConvertReceiver(isolate, receiver),
1954 : Nothing<bool>());
1955 : }
1956 : PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1957 : *holder, should_throw);
1958 :
1959 : std::unique_ptr<v8::PropertyDescriptor> descriptor(
1960 82 : new v8::PropertyDescriptor());
1961 82 : if (PropertyDescriptor::IsAccessorDescriptor(&desc)) {
1962 : descriptor.reset(new v8::PropertyDescriptor(
1963 60 : v8::Utils::ToLocal(desc.get()), v8::Utils::ToLocal(desc.set())));
1964 52 : } else if (PropertyDescriptor::IsDataDescriptor(&desc)) {
1965 42 : if (desc.has_writable()) {
1966 : descriptor.reset(new v8::PropertyDescriptor(
1967 18 : v8::Utils::ToLocal(desc.value()), desc.writable()));
1968 : } else {
1969 : descriptor.reset(
1970 72 : new v8::PropertyDescriptor(v8::Utils::ToLocal(desc.value())));
1971 : }
1972 : }
1973 82 : if (desc.has_enumerable()) {
1974 12 : descriptor->set_enumerable(desc.enumerable());
1975 : }
1976 82 : if (desc.has_configurable()) {
1977 12 : descriptor->set_configurable(desc.configurable());
1978 : }
1979 :
1980 82 : if (it->IsElement()) {
1981 : uint32_t index = it->index();
1982 : v8::IndexedPropertyDefinerCallback definer =
1983 : v8::ToCData<v8::IndexedPropertyDefinerCallback>(interceptor->definer());
1984 46 : result = !args.Call(definer, index, *descriptor).is_null();
1985 : } else {
1986 59 : Handle<Name> name = it->name();
1987 : DCHECK(!name->IsPrivate());
1988 :
1989 : DCHECK_IMPLIES(name->IsSymbol(), interceptor->can_intercept_symbols());
1990 :
1991 : v8::GenericNamedPropertyDefinerCallback definer =
1992 : v8::ToCData<v8::GenericNamedPropertyDefinerCallback>(
1993 : interceptor->definer());
1994 118 : result = !args.Call(definer, name, *descriptor).is_null();
1995 : }
1996 :
1997 82 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1998 : return Just(result);
1999 : }
2000 :
2001 : } // namespace
2002 :
2003 1737 : MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
2004 1808 : LookupIterator* it) {
2005 : Isolate* isolate = it->isolate();
2006 1737 : Handle<JSObject> checked = it->GetHolder<JSObject>();
2007 : Handle<InterceptorInfo> interceptor =
2008 1737 : it->GetInterceptorForFailedAccessCheck();
2009 1737 : if (interceptor.is_null()) {
2010 1609 : while (AllCanRead(it)) {
2011 46 : if (it->state() == LookupIterator::ACCESSOR) {
2012 52 : return GetPropertyWithAccessor(it);
2013 : }
2014 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
2015 : bool done;
2016 : Handle<Object> result;
2017 60 : ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
2018 : GetPropertyWithInterceptor(it, &done), Object);
2019 30 : if (done) return result;
2020 : }
2021 :
2022 : } else {
2023 : Handle<Object> result;
2024 : bool done;
2025 276 : ASSIGN_RETURN_ON_EXCEPTION(
2026 : isolate, result,
2027 : GetPropertyWithInterceptorInternal(it, interceptor, &done), Object);
2028 126 : if (done) return result;
2029 : }
2030 :
2031 : // Cross-Origin [[Get]] of Well-Known Symbols does not throw, and returns
2032 : // undefined.
2033 1635 : Handle<Name> name = it->GetName();
2034 1665 : if (name->IsSymbol() && Symbol::cast(*name)->is_well_known_symbol()) {
2035 25 : return it->factory()->undefined_value();
2036 : }
2037 :
2038 1610 : isolate->ReportFailedAccessCheck(checked);
2039 1610 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
2040 0 : return it->factory()->undefined_value();
2041 : }
2042 :
2043 :
2044 121 : Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
2045 131 : LookupIterator* it) {
2046 : Isolate* isolate = it->isolate();
2047 121 : Handle<JSObject> checked = it->GetHolder<JSObject>();
2048 : Handle<InterceptorInfo> interceptor =
2049 121 : it->GetInterceptorForFailedAccessCheck();
2050 121 : if (interceptor.is_null()) {
2051 121 : while (AllCanRead(it)) {
2052 10 : if (it->state() == LookupIterator::ACCESSOR) {
2053 : return Just(it->property_attributes());
2054 : }
2055 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
2056 0 : auto result = GetPropertyAttributesWithInterceptor(it);
2057 0 : if (isolate->has_scheduled_exception()) break;
2058 0 : if (result.IsJust() && result.FromJust() != ABSENT) return result;
2059 : }
2060 : } else {
2061 : Maybe<PropertyAttributes> result =
2062 0 : GetPropertyAttributesWithInterceptorInternal(it, interceptor);
2063 0 : if (isolate->has_pending_exception()) return Nothing<PropertyAttributes>();
2064 0 : if (result.FromMaybe(ABSENT) != ABSENT) return result;
2065 : }
2066 111 : isolate->ReportFailedAccessCheck(checked);
2067 111 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
2068 : return Just(ABSENT);
2069 : }
2070 :
2071 :
2072 : // static
2073 257 : bool JSObject::AllCanWrite(LookupIterator* it) {
2074 366 : for (; it->IsFound() && it->state() != LookupIterator::JSPROXY; it->Next()) {
2075 119 : if (it->state() == LookupIterator::ACCESSOR) {
2076 25 : Handle<Object> accessors = it->GetAccessors();
2077 25 : if (accessors->IsAccessorInfo()) {
2078 15 : if (AccessorInfo::cast(*accessors)->all_can_write()) return true;
2079 : }
2080 : }
2081 : }
2082 : return false;
2083 : }
2084 :
2085 :
2086 110 : Maybe<bool> JSObject::SetPropertyWithFailedAccessCheck(
2087 110 : LookupIterator* it, Handle<Object> value, ShouldThrow should_throw) {
2088 : Isolate* isolate = it->isolate();
2089 110 : Handle<JSObject> checked = it->GetHolder<JSObject>();
2090 : Handle<InterceptorInfo> interceptor =
2091 110 : it->GetInterceptorForFailedAccessCheck();
2092 110 : if (interceptor.is_null()) {
2093 74 : if (AllCanWrite(it)) {
2094 10 : return SetPropertyWithAccessor(it, value, should_throw);
2095 : }
2096 : } else {
2097 : Maybe<bool> result = SetPropertyWithInterceptorInternal(
2098 36 : it, interceptor, should_throw, value);
2099 72 : if (isolate->has_pending_exception()) return Nothing<bool>();
2100 24 : if (result.IsJust()) return result;
2101 : }
2102 64 : isolate->ReportFailedAccessCheck(checked);
2103 64 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
2104 : return Just(true);
2105 : }
2106 :
2107 :
2108 512493 : void JSObject::SetNormalizedProperty(Handle<JSObject> object,
2109 : Handle<Name> name,
2110 : Handle<Object> value,
2111 : PropertyDetails details) {
2112 : DCHECK(!object->HasFastProperties());
2113 : DCHECK(name->IsUniqueName());
2114 : Isolate* isolate = object->GetIsolate();
2115 :
2116 : uint32_t hash = name->Hash();
2117 :
2118 512493 : if (object->IsJSGlobalObject()) {
2119 : Handle<JSGlobalObject> global_obj(JSGlobalObject::cast(*object));
2120 : Handle<GlobalDictionary> dictionary(global_obj->global_dictionary());
2121 18482 : int entry = dictionary->FindEntry(isolate, name, hash);
2122 :
2123 9241 : if (entry == GlobalDictionary::kNotFound) {
2124 1057 : auto cell = isolate->factory()->NewPropertyCell(name);
2125 1057 : cell->set_value(*value);
2126 : auto cell_type = value->IsUndefined(isolate)
2127 : ? PropertyCellType::kUndefined
2128 1057 : : PropertyCellType::kConstant;
2129 : details = details.set_cell_type(cell_type);
2130 : value = cell;
2131 1057 : dictionary = GlobalDictionary::Add(dictionary, name, value, details);
2132 : global_obj->set_global_dictionary(*dictionary);
2133 : } else {
2134 : Handle<PropertyCell> cell =
2135 8184 : PropertyCell::PrepareForValue(dictionary, entry, value, details);
2136 8184 : cell->set_value(*value);
2137 : }
2138 : } else {
2139 : Handle<NameDictionary> dictionary(object->property_dictionary());
2140 :
2141 : int entry = dictionary->FindEntry(name);
2142 503252 : if (entry == NameDictionary::kNotFound) {
2143 168520 : dictionary = NameDictionary::Add(dictionary, name, value, details);
2144 168520 : object->SetProperties(*dictionary);
2145 : } else {
2146 : PropertyDetails original_details = dictionary->DetailsAt(entry);
2147 : int enumeration_index = original_details.dictionary_index();
2148 : DCHECK_GT(enumeration_index, 0);
2149 : details = details.set_index(enumeration_index);
2150 334732 : dictionary->SetEntry(entry, *name, *value, details);
2151 : }
2152 : }
2153 512493 : }
2154 :
2155 : // static
2156 1280 : Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate,
2157 : Handle<JSReceiver> object,
2158 : Handle<Object> proto) {
2159 1280 : PrototypeIterator iter(isolate, object, kStartAtReceiver);
2160 : while (true) {
2161 3893561 : if (!iter.AdvanceFollowingProxies()) return Nothing<bool>();
2162 3893452 : if (iter.IsAtEnd()) return Just(false);
2163 3892681 : if (PrototypeIterator::GetCurrent(iter).is_identical_to(proto)) {
2164 : return Just(true);
2165 : }
2166 : }
2167 : }
2168 :
2169 : namespace {
2170 :
2171 450 : bool HasExcludedProperty(
2172 : const ScopedVector<Handle<Object>>* excluded_properties,
2173 : Handle<Object> search_element) {
2174 : // TODO(gsathya): Change this to be a hashtable.
2175 1422 : for (int i = 0; i < excluded_properties->length(); i++) {
2176 1575 : if (search_element->SameValue(*excluded_properties->at(i))) {
2177 : return true;
2178 : }
2179 : }
2180 :
2181 : return false;
2182 : }
2183 :
2184 879 : MUST_USE_RESULT Maybe<bool> FastAssign(
2185 : Handle<JSReceiver> target, Handle<Object> source,
2186 : const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) {
2187 : // Non-empty strings are the only non-JSReceivers that need to be handled
2188 : // explicitly by Object.assign.
2189 879 : if (!source->IsJSReceiver()) {
2190 45 : return Just(!source->IsString() || String::cast(*source)->length() == 0);
2191 : }
2192 :
2193 : // If the target is deprecated, the object will be updated on first store. If
2194 : // the source for that store equals the target, this will invalidate the
2195 : // cached representation of the source. Preventively upgrade the target.
2196 : // Do this on each iteration since any property load could cause deprecation.
2197 852 : if (target->map()->is_deprecated()) {
2198 20 : JSObject::MigrateInstance(Handle<JSObject>::cast(target));
2199 : }
2200 :
2201 : Isolate* isolate = target->GetIsolate();
2202 : Handle<Map> map(JSReceiver::cast(*source)->map(), isolate);
2203 :
2204 852 : if (!map->IsJSObjectMap()) return Just(false);
2205 762 : if (!map->OnlyHasSimpleProperties()) return Just(false);
2206 :
2207 : Handle<JSObject> from = Handle<JSObject>::cast(source);
2208 679 : if (from->elements() != isolate->heap()->empty_fixed_array()) {
2209 : return Just(false);
2210 : }
2211 :
2212 : Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
2213 : int length = map->NumberOfOwnDescriptors();
2214 :
2215 : bool stable = true;
2216 :
2217 1952 : for (int i = 0; i < length; i++) {
2218 : Handle<Name> next_key(descriptors->GetKey(i), isolate);
2219 : Handle<Object> prop_value;
2220 : // Directly decode from the descriptor array if |from| did not change shape.
2221 1372 : if (stable) {
2222 1294 : PropertyDetails details = descriptors->GetDetails(i);
2223 1294 : if (!details.IsEnumerable()) continue;
2224 1216 : if (details.kind() == kData) {
2225 1216 : if (details.location() == kDescriptor) {
2226 420 : prop_value = handle(descriptors->GetValue(i), isolate);
2227 : } else {
2228 796 : Representation representation = details.representation();
2229 796 : FieldIndex index = FieldIndex::ForDescriptor(*map, i);
2230 796 : prop_value = JSObject::FastPropertyAt(from, representation, index);
2231 : }
2232 : } else {
2233 0 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2234 : isolate, prop_value, JSReceiver::GetProperty(from, next_key),
2235 : Nothing<bool>());
2236 0 : stable = from->map() == *map;
2237 : }
2238 : } else {
2239 : // If the map did change, do a slower lookup. We are still guaranteed that
2240 : // the object has a simple shape, and that the key is a name.
2241 : LookupIterator it(from, next_key, from,
2242 78 : LookupIterator::OWN_SKIP_INTERCEPTOR);
2243 87 : if (!it.IsFound()) continue;
2244 : DCHECK(it.state() == LookupIterator::DATA ||
2245 : it.state() == LookupIterator::ACCESSOR);
2246 78 : if (!it.IsEnumerable()) continue;
2247 138 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2248 : isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
2249 : }
2250 :
2251 1285 : if (use_set) {
2252 763 : LookupIterator it(target, next_key, target);
2253 : Maybe<bool> result =
2254 : Object::SetProperty(&it, prop_value, LanguageMode::kStrict,
2255 763 : Object::CERTAINLY_NOT_STORE_FROM_KEYED);
2256 763 : if (result.IsNothing()) return result;
2257 1403 : if (stable) stable = from->map() == *map;
2258 : } else {
2259 1566 : if (excluded_properties != nullptr &&
2260 1116 : HasExcludedProperty(excluded_properties, next_key)) {
2261 99 : continue;
2262 : }
2263 :
2264 : // 4a ii 2. Perform ? CreateDataProperty(target, nextKey, propValue).
2265 : bool success;
2266 : LookupIterator it = LookupIterator::PropertyOrElement(
2267 423 : isolate, target, next_key, &success, LookupIterator::OWN);
2268 423 : CHECK(success);
2269 846 : CHECK(
2270 : JSObject::CreateDataProperty(&it, prop_value, Object::THROW_ON_ERROR)
2271 : .FromJust());
2272 : }
2273 : }
2274 :
2275 : return Just(true);
2276 : }
2277 : } // namespace
2278 :
2279 : // static
2280 879 : Maybe<bool> JSReceiver::SetOrCopyDataProperties(
2281 : Isolate* isolate, Handle<JSReceiver> target, Handle<Object> source,
2282 : const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) {
2283 : Maybe<bool> fast_assign =
2284 879 : FastAssign(target, source, excluded_properties, use_set);
2285 879 : if (fast_assign.IsNothing()) return Nothing<bool>();
2286 852 : if (fast_assign.FromJust()) return Just(true);
2287 :
2288 526 : Handle<JSReceiver> from = Object::ToObject(isolate, source).ToHandleChecked();
2289 : // 3b. Let keys be ? from.[[OwnPropertyKeys]]().
2290 : Handle<FixedArray> keys;
2291 526 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2292 : isolate, keys,
2293 : KeyAccumulator::GetKeys(from, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES,
2294 : GetKeysConversion::kKeepNumbers),
2295 : Nothing<bool>());
2296 :
2297 : // 4. Repeat for each element nextKey of keys in List order,
2298 3153 : for (int j = 0; j < keys->length(); ++j) {
2299 : Handle<Object> next_key(keys->get(j), isolate);
2300 : // 4a i. Let desc be ? from.[[GetOwnProperty]](nextKey).
2301 : PropertyDescriptor desc;
2302 : Maybe<bool> found =
2303 1499 : JSReceiver::GetOwnPropertyDescriptor(isolate, from, next_key, &desc);
2304 1526 : if (found.IsNothing()) return Nothing<bool>();
2305 : // 4a ii. If desc is not undefined and desc.[[Enumerable]] is true, then
2306 2998 : if (found.FromJust() && desc.enumerable()) {
2307 : // 4a ii 1. Let propValue be ? Get(from, nextKey).
2308 : Handle<Object> prop_value;
2309 1853 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2310 : isolate, prop_value,
2311 : Runtime::GetObjectProperty(isolate, from, next_key), Nothing<bool>());
2312 :
2313 886 : if (use_set) {
2314 : // 4c ii 2. Let status be ? Set(to, nextKey, propValue, true).
2315 : Handle<Object> status;
2316 1340 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2317 : isolate, status,
2318 : Runtime::SetObjectProperty(isolate, target, next_key, prop_value,
2319 : LanguageMode::kStrict),
2320 : Nothing<bool>());
2321 : } else {
2322 369 : if (excluded_properties != nullptr &&
2323 153 : HasExcludedProperty(excluded_properties, next_key)) {
2324 72 : continue;
2325 : }
2326 :
2327 : // 4a ii 2. Perform ! CreateDataProperty(target, nextKey, propValue).
2328 : bool success;
2329 : LookupIterator it = LookupIterator::PropertyOrElement(
2330 144 : isolate, target, next_key, &success, LookupIterator::OWN);
2331 144 : CHECK(success);
2332 288 : CHECK(JSObject::CreateDataProperty(&it, prop_value,
2333 : Object::THROW_ON_ERROR)
2334 : .FromJust());
2335 : }
2336 : }
2337 : }
2338 :
2339 : return Just(true);
2340 : }
2341 :
2342 182833 : Map* Object::GetPrototypeChainRootMap(Isolate* isolate) const {
2343 : DisallowHeapAllocation no_alloc;
2344 163925 : if (IsSmi()) {
2345 : Context* native_context = isolate->context()->native_context();
2346 18908 : return native_context->number_function()->initial_map();
2347 : }
2348 :
2349 : const HeapObject* heap_object = HeapObject::cast(this);
2350 145017 : return heap_object->map()->GetPrototypeChainRootMap(isolate);
2351 : }
2352 :
2353 3909404 : Map* Map::GetPrototypeChainRootMap(Isolate* isolate) const {
2354 : DisallowHeapAllocation no_alloc;
2355 3659132 : if (IsJSReceiverMap()) {
2356 : return const_cast<Map*>(this);
2357 : }
2358 : int constructor_function_index = GetConstructorFunctionIndex();
2359 250272 : if (constructor_function_index != Map::kNoConstructorFunctionIndex) {
2360 : Context* native_context = isolate->context()->native_context();
2361 : JSFunction* constructor_function =
2362 : JSFunction::cast(native_context->get(constructor_function_index));
2363 250272 : return constructor_function->initial_map();
2364 : }
2365 0 : return isolate->heap()->null_value()->map();
2366 : }
2367 :
2368 : namespace {
2369 :
2370 : // Returns a non-SMI for JSReceivers, but returns the hash code for simple
2371 : // objects. This avoids a double lookup in the cases where we know we will
2372 : // add the hash to the JSReceiver if it does not already exist.
2373 51590512 : Object* GetSimpleHash(Object* object) {
2374 : DisallowHeapAllocation no_gc;
2375 51590512 : if (object->IsSmi()) {
2376 991850 : uint32_t hash = ComputeIntegerHash(Smi::ToInt(object));
2377 1983700 : return Smi::FromInt(hash & Smi::kMaxValue);
2378 : }
2379 50598658 : if (object->IsHeapNumber()) {
2380 : double num = HeapNumber::cast(object)->value();
2381 5901 : if (std::isnan(num)) return Smi::FromInt(Smi::kMaxValue);
2382 5446 : if (i::IsMinusZero(num)) num = 0;
2383 5446 : if (IsSmiDouble(num)) {
2384 476 : return Smi::FromInt(FastD2I(num))->GetHash();
2385 : }
2386 : uint32_t hash = ComputeLongHash(double_to_uint64(num));
2387 9940 : return Smi::FromInt(hash & Smi::kMaxValue);
2388 : }
2389 50592751 : if (object->IsName()) {
2390 : uint32_t hash = Name::cast(object)->Hash();
2391 101125300 : return Smi::FromInt(hash);
2392 : }
2393 30082 : if (object->IsOddball()) {
2394 : uint32_t hash = Oddball::cast(object)->to_string()->Hash();
2395 2826 : return Smi::FromInt(hash);
2396 : }
2397 28669 : if (object->IsBigInt()) {
2398 216 : uint32_t hash = BigInt::cast(object)->Hash();
2399 432 : return Smi::FromInt(hash & Smi::kMaxValue);
2400 : }
2401 : DCHECK(object->IsJSReceiver());
2402 : return object;
2403 : }
2404 :
2405 : } // namespace
2406 :
2407 4703050 : Object* Object::GetHash() {
2408 : DisallowHeapAllocation no_gc;
2409 4703050 : Object* hash = GetSimpleHash(this);
2410 4703050 : if (hash->IsSmi()) return hash;
2411 :
2412 : DCHECK(IsJSReceiver());
2413 : JSReceiver* receiver = JSReceiver::cast(this);
2414 : Isolate* isolate = receiver->GetIsolate();
2415 16960 : return receiver->GetIdentityHash(isolate);
2416 : }
2417 :
2418 : // static
2419 7938 : Smi* Object::GetOrCreateHash(Isolate* isolate, Object* key) {
2420 : DisallowHeapAllocation no_gc;
2421 7938 : return key->GetOrCreateHash(isolate);
2422 : }
2423 :
2424 46887464 : Smi* Object::GetOrCreateHash(Isolate* isolate) {
2425 : DisallowHeapAllocation no_gc;
2426 46887464 : Object* hash = GetSimpleHash(this);
2427 46887464 : if (hash->IsSmi()) return Smi::cast(hash);
2428 :
2429 : DCHECK(IsJSReceiver());
2430 11493 : return JSReceiver::cast(this)->GetOrCreateIdentityHash(isolate);
2431 : }
2432 :
2433 :
2434 938477 : bool Object::SameValue(Object* other) {
2435 938477 : if (other == this) return true;
2436 :
2437 204304 : if (IsNumber() && other->IsNumber()) {
2438 : double this_value = Number();
2439 : double other_value = other->Number();
2440 : // SameValue(NaN, NaN) is true.
2441 23756 : if (this_value != other_value) {
2442 20904 : return std::isnan(this_value) && std::isnan(other_value);
2443 : }
2444 : // SameValue(0.0, -0.0) is false.
2445 2852 : return (std::signbit(this_value) == std::signbit(other_value));
2446 : }
2447 260075 : if (IsString() && other->IsString()) {
2448 112465 : return String::cast(this)->Equals(String::cast(other));
2449 : }
2450 34210 : if (IsBigInt() && other->IsBigInt()) {
2451 45 : return BigInt::EqualToBigInt(BigInt::cast(this), BigInt::cast(other));
2452 : }
2453 : return false;
2454 : }
2455 :
2456 :
2457 19204640 : bool Object::SameValueZero(Object* other) {
2458 19204640 : if (other == this) return true;
2459 :
2460 19566217 : if (IsNumber() && other->IsNumber()) {
2461 : double this_value = Number();
2462 : double other_value = other->Number();
2463 : // +0 == -0 is true
2464 366498 : return this_value == other_value ||
2465 14 : (std::isnan(this_value) && std::isnan(other_value));
2466 : }
2467 37650299 : if (IsString() && other->IsString()) {
2468 18819586 : return String::cast(this)->Equals(String::cast(other));
2469 : }
2470 10639 : if (IsBigInt() && other->IsBigInt()) {
2471 18 : return BigInt::EqualToBigInt(BigInt::cast(this), BigInt::cast(other));
2472 : }
2473 : return false;
2474 : }
2475 :
2476 :
2477 11246 : MaybeHandle<Object> Object::ArraySpeciesConstructor(
2478 : Isolate* isolate, Handle<Object> original_array) {
2479 11246 : Handle<Object> default_species = isolate->array_function();
2480 19214 : if (original_array->IsJSArray() &&
2481 26027 : Handle<JSArray>::cast(original_array)->HasArrayPrototype(isolate) &&
2482 : isolate->IsArraySpeciesLookupChainIntact()) {
2483 6271 : return default_species;
2484 : }
2485 : Handle<Object> constructor = isolate->factory()->undefined_value();
2486 : Maybe<bool> is_array = Object::IsArray(original_array);
2487 4975 : MAYBE_RETURN_NULL(is_array);
2488 4975 : if (is_array.FromJust()) {
2489 3486 : ASSIGN_RETURN_ON_EXCEPTION(
2490 : isolate, constructor,
2491 : Object::GetProperty(original_array,
2492 : isolate->factory()->constructor_string()),
2493 : Object);
2494 1734 : if (constructor->IsConstructor()) {
2495 : Handle<Context> constructor_context;
2496 3060 : ASSIGN_RETURN_ON_EXCEPTION(
2497 : isolate, constructor_context,
2498 : JSReceiver::GetFunctionRealm(Handle<JSReceiver>::cast(constructor)),
2499 : Object);
2500 3078 : if (*constructor_context != *isolate->native_context() &&
2501 : *constructor == constructor_context->array_function()) {
2502 : constructor = isolate->factory()->undefined_value();
2503 : }
2504 : }
2505 1734 : if (constructor->IsJSReceiver()) {
2506 3076 : ASSIGN_RETURN_ON_EXCEPTION(
2507 : isolate, constructor,
2508 : JSReceiver::GetProperty(Handle<JSReceiver>::cast(constructor),
2509 : isolate->factory()->species_symbol()),
2510 : Object);
2511 1529 : if (constructor->IsNull(isolate)) {
2512 : constructor = isolate->factory()->undefined_value();
2513 : }
2514 : }
2515 : }
2516 4957 : if (constructor->IsUndefined(isolate)) {
2517 3457 : return default_species;
2518 : } else {
2519 1500 : if (!constructor->IsConstructor()) {
2520 0 : THROW_NEW_ERROR(isolate,
2521 : NewTypeError(MessageTemplate::kSpeciesNotConstructor),
2522 : Object);
2523 : }
2524 1500 : return constructor;
2525 : }
2526 : }
2527 :
2528 : // ES6 section 7.3.20 SpeciesConstructor ( O, defaultConstructor )
2529 11494 : MUST_USE_RESULT MaybeHandle<Object> Object::SpeciesConstructor(
2530 : Isolate* isolate, Handle<JSReceiver> recv,
2531 : Handle<JSFunction> default_ctor) {
2532 : Handle<Object> ctor_obj;
2533 22988 : ASSIGN_RETURN_ON_EXCEPTION(
2534 : isolate, ctor_obj,
2535 : JSObject::GetProperty(recv, isolate->factory()->constructor_string()),
2536 : Object);
2537 :
2538 11413 : if (ctor_obj->IsUndefined(isolate)) return default_ctor;
2539 :
2540 11323 : if (!ctor_obj->IsJSReceiver()) {
2541 0 : THROW_NEW_ERROR(isolate,
2542 : NewTypeError(MessageTemplate::kConstructorNotReceiver),
2543 : Object);
2544 : }
2545 :
2546 11323 : Handle<JSReceiver> ctor = Handle<JSReceiver>::cast(ctor_obj);
2547 :
2548 : Handle<Object> species;
2549 22646 : ASSIGN_RETURN_ON_EXCEPTION(
2550 : isolate, species,
2551 : JSObject::GetProperty(ctor, isolate->factory()->species_symbol()),
2552 : Object);
2553 :
2554 11242 : if (species->IsNullOrUndefined(isolate)) {
2555 81 : return default_ctor;
2556 : }
2557 :
2558 11161 : if (species->IsConstructor()) return species;
2559 :
2560 0 : THROW_NEW_ERROR(
2561 : isolate, NewTypeError(MessageTemplate::kSpeciesNotConstructor), Object);
2562 : }
2563 :
2564 25453 : bool Object::IterationHasObservableEffects() {
2565 : // Check that this object is an array.
2566 25453 : if (!IsJSArray()) return true;
2567 : JSArray* array = JSArray::cast(this);
2568 : Isolate* isolate = array->GetIsolate();
2569 :
2570 : // Check that we have the original ArrayPrototype.
2571 25453 : if (!array->map()->prototype()->IsJSObject()) return true;
2572 : JSObject* array_proto = JSObject::cast(array->map()->prototype());
2573 25443 : if (!isolate->is_initial_array_prototype(array_proto)) return true;
2574 :
2575 : // Check that the ArrayPrototype hasn't been modified in a way that would
2576 : // affect iteration.
2577 25281 : if (!isolate->IsArrayIteratorLookupChainIntact()) return true;
2578 :
2579 : // Check that the map of the initial array iterator hasn't changed.
2580 47812 : Map* iterator_map = isolate->initial_array_iterator_prototype()->map();
2581 23906 : if (!isolate->is_initial_array_iterator_prototype_map(iterator_map)) {
2582 : return true;
2583 : }
2584 :
2585 : // For FastPacked kinds, iteration will have the same effect as simply
2586 : // accessing each property in order.
2587 : ElementsKind array_kind = array->GetElementsKind();
2588 23906 : if (IsFastPackedElementsKind(array_kind)) return false;
2589 :
2590 : // For FastHoley kinds, an element access on a hole would cause a lookup on
2591 : // the prototype. This could have different results if the prototype has been
2592 : // changed.
2593 8056 : if (IsHoleyElementsKind(array_kind) &&
2594 4028 : isolate->IsFastArrayConstructorPrototypeChainIntact()) {
2595 : return false;
2596 : }
2597 175 : return true;
2598 : }
2599 :
2600 24 : void Object::ShortPrint(FILE* out) {
2601 24 : OFStream os(out);
2602 24 : os << Brief(this);
2603 24 : }
2604 :
2605 :
2606 50 : void Object::ShortPrint(StringStream* accumulator) {
2607 50 : std::ostringstream os;
2608 50 : os << Brief(this);
2609 100 : accumulator->Add(os.str().c_str());
2610 50 : }
2611 :
2612 :
2613 0 : void Object::ShortPrint(std::ostream& os) { os << Brief(this); }
2614 :
2615 :
2616 1125 : std::ostream& operator<<(std::ostream& os, const Brief& v) {
2617 2250 : if (v.value->IsSmi()) {
2618 : Smi::cast(v.value)->SmiPrint(os);
2619 : } else {
2620 : // TODO(svenpanne) Const-correct HeapObjectShortPrint!
2621 : HeapObject* obj = const_cast<HeapObject*>(HeapObject::cast(v.value));
2622 933 : obj->HeapObjectShortPrint(os);
2623 : }
2624 1125 : return os;
2625 : }
2626 :
2627 1056 : void Smi::SmiPrint(std::ostream& os) const { // NOLINT
2628 1248 : os << value();
2629 1056 : }
2630 :
2631 4013358 : Handle<String> String::SlowFlatten(Handle<ConsString> cons,
2632 : PretenureFlag pretenure) {
2633 : DCHECK_NE(cons->second()->length(), 0);
2634 :
2635 : // TurboFan can create cons strings with empty first parts.
2636 8026724 : while (cons->first()->length() == 0) {
2637 : // We do not want to call this function recursively. Therefore we call
2638 : // String::Flatten only in those cases where String::SlowFlatten is not
2639 : // called again.
2640 39 : if (cons->second()->IsConsString() && !cons->second()->IsFlat()) {
2641 : cons = handle(ConsString::cast(cons->second()));
2642 : } else {
2643 23 : return String::Flatten(handle(cons->second()));
2644 : }
2645 : }
2646 :
2647 : DCHECK(AllowHeapAllocation::IsAllowed());
2648 : Isolate* isolate = cons->GetIsolate();
2649 : int length = cons->length();
2650 : PretenureFlag tenure = isolate->heap()->InNewSpace(*cons) ? pretenure
2651 4013335 : : TENURED;
2652 : Handle<SeqString> result;
2653 4013335 : if (cons->IsOneByteRepresentation()) {
2654 : Handle<SeqOneByteString> flat = isolate->factory()->NewRawOneByteString(
2655 7690742 : length, tenure).ToHandleChecked();
2656 : DisallowHeapAllocation no_gc;
2657 7690742 : WriteToFlat(*cons, flat->GetChars(), 0, length);
2658 : result = flat;
2659 : } else {
2660 : Handle<SeqTwoByteString> flat = isolate->factory()->NewRawTwoByteString(
2661 335928 : length, tenure).ToHandleChecked();
2662 : DisallowHeapAllocation no_gc;
2663 335928 : WriteToFlat(*cons, flat->GetChars(), 0, length);
2664 : result = flat;
2665 : }
2666 4013335 : cons->set_first(*result);
2667 8026670 : cons->set_second(isolate->heap()->empty_string());
2668 : DCHECK(result->IsFlat());
2669 4013335 : return result;
2670 : }
2671 :
2672 :
2673 :
2674 335 : bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
2675 : DisallowHeapAllocation no_allocation;
2676 : // Externalizing twice leaks the external resource, so it's
2677 : // prohibited by the API.
2678 : DCHECK(!this->IsExternalString());
2679 : DCHECK(!resource->IsCompressible());
2680 : #ifdef ENABLE_SLOW_DCHECKS
2681 : if (FLAG_enable_slow_asserts) {
2682 : // Assert that the resource and the string are equivalent.
2683 : DCHECK(static_cast<size_t>(this->length()) == resource->length());
2684 : ScopedVector<uc16> smart_chars(this->length());
2685 : String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2686 : DCHECK_EQ(0, memcmp(smart_chars.start(), resource->data(),
2687 : resource->length() * sizeof(smart_chars[0])));
2688 : }
2689 : #endif // DEBUG
2690 335 : int size = this->Size(); // Byte size of the original string.
2691 : // Abort if size does not allow in-place conversion.
2692 335 : if (size < ExternalString::kShortSize) return false;
2693 203 : Heap* heap = GetHeap();
2694 : bool is_one_byte = this->IsOneByteRepresentation();
2695 : bool is_internalized = this->IsInternalizedString();
2696 : bool has_pointers = StringShape(this).IsIndirect();
2697 335 : if (has_pointers) {
2698 61 : heap->NotifyObjectLayoutChange(this, size, no_allocation);
2699 : }
2700 : // Morph the string to an external string by replacing the map and
2701 : // reinitializing the fields. This won't work if the space the existing
2702 : // string occupies is too small for a regular external string.
2703 : // Instead, we resort to a short external string instead, omitting
2704 : // the field caching the address of the backing store. When we encounter
2705 : // short external strings in generated code, we need to bailout to runtime.
2706 : Map* new_map;
2707 335 : if (size < ExternalString::kSize) {
2708 : new_map = is_internalized
2709 : ? (is_one_byte
2710 : ? heap->short_external_internalized_string_with_one_byte_data_map()
2711 : : heap->short_external_internalized_string_map())
2712 : : (is_one_byte ? heap->short_external_string_with_one_byte_data_map()
2713 223 : : heap->short_external_string_map());
2714 : } else {
2715 : new_map = is_internalized
2716 : ? (is_one_byte
2717 : ? heap->external_internalized_string_with_one_byte_data_map()
2718 : : heap->external_internalized_string_map())
2719 : : (is_one_byte ? heap->external_string_with_one_byte_data_map()
2720 385 : : heap->external_string_map());
2721 : }
2722 :
2723 : // Byte size of the external String object.
2724 335 : int new_size = this->SizeFromMap(new_map);
2725 335 : heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
2726 670 : ClearRecordedSlots::kNo);
2727 335 : if (has_pointers) {
2728 61 : heap->ClearRecordedSlotRange(this->address(), this->address() + new_size);
2729 : }
2730 :
2731 : // We are storing the new map using release store after creating a filler for
2732 : // the left-over space to avoid races with the sweeper thread.
2733 335 : this->synchronized_set_map(new_map);
2734 :
2735 : ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
2736 : self->set_resource(resource);
2737 335 : if (is_internalized) self->Hash(); // Force regeneration of the hash value.
2738 : return true;
2739 : }
2740 :
2741 :
2742 329 : bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
2743 : DisallowHeapAllocation no_allocation;
2744 : // Externalizing twice leaks the external resource, so it's
2745 : // prohibited by the API.
2746 : DCHECK(!this->IsExternalString());
2747 : DCHECK(!resource->IsCompressible());
2748 : #ifdef ENABLE_SLOW_DCHECKS
2749 : if (FLAG_enable_slow_asserts) {
2750 : // Assert that the resource and the string are equivalent.
2751 : DCHECK(static_cast<size_t>(this->length()) == resource->length());
2752 : if (this->IsTwoByteRepresentation()) {
2753 : ScopedVector<uint16_t> smart_chars(this->length());
2754 : String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2755 : DCHECK(String::IsOneByte(smart_chars.start(), this->length()));
2756 : }
2757 : ScopedVector<char> smart_chars(this->length());
2758 : String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2759 : DCHECK_EQ(0, memcmp(smart_chars.start(), resource->data(),
2760 : resource->length() * sizeof(smart_chars[0])));
2761 : }
2762 : #endif // DEBUG
2763 329 : int size = this->Size(); // Byte size of the original string.
2764 : // Abort if size does not allow in-place conversion.
2765 329 : if (size < ExternalString::kShortSize) return false;
2766 44 : Heap* heap = GetHeap();
2767 : bool is_internalized = this->IsInternalizedString();
2768 : bool has_pointers = StringShape(this).IsIndirect();
2769 :
2770 329 : if (has_pointers) {
2771 30 : heap->NotifyObjectLayoutChange(this, size, no_allocation);
2772 : }
2773 :
2774 : // Morph the string to an external string by replacing the map and
2775 : // reinitializing the fields. This won't work if the space the existing
2776 : // string occupies is too small for a regular external string.
2777 : // Instead, we resort to a short external string instead, omitting
2778 : // the field caching the address of the backing store. When we encounter
2779 : // short external strings in generated code, we need to bailout to runtime.
2780 : Map* new_map;
2781 329 : if (size < ExternalString::kSize) {
2782 : new_map = is_internalized
2783 : ? heap->short_external_one_byte_internalized_string_map()
2784 20 : : heap->short_external_one_byte_string_map();
2785 : } else {
2786 : new_map = is_internalized
2787 : ? heap->external_one_byte_internalized_string_map()
2788 309 : : heap->external_one_byte_string_map();
2789 : }
2790 :
2791 : // Byte size of the external String object.
2792 329 : int new_size = this->SizeFromMap(new_map);
2793 329 : heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
2794 658 : ClearRecordedSlots::kNo);
2795 329 : if (has_pointers) {
2796 30 : heap->ClearRecordedSlotRange(this->address(), this->address() + new_size);
2797 : }
2798 :
2799 : // We are storing the new map using release store after creating a filler for
2800 : // the left-over space to avoid races with the sweeper thread.
2801 329 : this->synchronized_set_map(new_map);
2802 :
2803 : ExternalOneByteString* self = ExternalOneByteString::cast(this);
2804 : self->set_resource(resource);
2805 329 : if (is_internalized) self->Hash(); // Force regeneration of the hash value.
2806 : return true;
2807 : }
2808 :
2809 64 : void String::StringShortPrint(StringStream* accumulator, bool show_details) {
2810 : int len = length();
2811 64 : if (len > kMaxShortPrintLength) {
2812 0 : accumulator->Add("<Very long string[%u]>", len);
2813 0 : return;
2814 : }
2815 :
2816 64 : if (!LooksValid()) {
2817 0 : accumulator->Add("<Invalid String>");
2818 0 : return;
2819 : }
2820 :
2821 : StringCharacterStream stream(this);
2822 :
2823 : bool truncated = false;
2824 64 : if (len > kMaxShortPrintLength) {
2825 : len = kMaxShortPrintLength;
2826 : truncated = true;
2827 : }
2828 : bool one_byte = true;
2829 532 : for (int i = 0; i < len; i++) {
2830 468 : uint16_t c = stream.GetNext();
2831 :
2832 468 : if (c < 32 || c >= 127) {
2833 : one_byte = false;
2834 : }
2835 : }
2836 64 : stream.Reset(this);
2837 64 : if (one_byte) {
2838 116 : if (show_details) accumulator->Add("<String[%u]: ", length());
2839 468 : for (int i = 0; i < len; i++) {
2840 468 : accumulator->Put(static_cast<char>(stream.GetNext()));
2841 : }
2842 64 : if (show_details) accumulator->Put('>');
2843 : } else {
2844 : // Backslash indicates that the string contains control
2845 : // characters and that backslashes are therefore escaped.
2846 0 : if (show_details) accumulator->Add("<String[%u]\\: ", length());
2847 0 : for (int i = 0; i < len; i++) {
2848 0 : uint16_t c = stream.GetNext();
2849 0 : if (c == '\n') {
2850 0 : accumulator->Add("\\n");
2851 0 : } else if (c == '\r') {
2852 0 : accumulator->Add("\\r");
2853 0 : } else if (c == '\\') {
2854 0 : accumulator->Add("\\\\");
2855 0 : } else if (c < 32 || c > 126) {
2856 0 : accumulator->Add("\\x%02x", c);
2857 : } else {
2858 0 : accumulator->Put(static_cast<char>(c));
2859 : }
2860 : }
2861 0 : if (truncated) {
2862 0 : accumulator->Put('.');
2863 0 : accumulator->Put('.');
2864 0 : accumulator->Put('.');
2865 : }
2866 0 : if (show_details) accumulator->Put('>');
2867 : }
2868 : return;
2869 : }
2870 :
2871 :
2872 0 : void String::PrintUC16(std::ostream& os, int start, int end) { // NOLINT
2873 0 : if (end < 0) end = length();
2874 : StringCharacterStream stream(this, start);
2875 0 : for (int i = start; i < end && stream.HasMore(); i++) {
2876 0 : os << AsUC16(stream.GetNext());
2877 : }
2878 0 : }
2879 :
2880 :
2881 565 : void JSObject::JSObjectShortPrint(StringStream* accumulator) {
2882 565 : switch (map()->instance_type()) {
2883 : case JS_ARRAY_TYPE: {
2884 : double length = JSArray::cast(this)->length()->IsUndefined(GetIsolate())
2885 : ? 0
2886 131 : : JSArray::cast(this)->length()->Number();
2887 131 : accumulator->Add("<JSArray[%u]>", static_cast<uint32_t>(length));
2888 131 : break;
2889 : }
2890 : case JS_BOUND_FUNCTION_TYPE: {
2891 : JSBoundFunction* bound_function = JSBoundFunction::cast(this);
2892 0 : accumulator->Add("<JSBoundFunction");
2893 : accumulator->Add(
2894 : " (BoundTargetFunction %p)>",
2895 0 : reinterpret_cast<void*>(bound_function->bound_target_function()));
2896 0 : break;
2897 : }
2898 : case JS_WEAK_MAP_TYPE: {
2899 0 : accumulator->Add("<JSWeakMap>");
2900 0 : break;
2901 : }
2902 : case JS_WEAK_SET_TYPE: {
2903 0 : accumulator->Add("<JSWeakSet>");
2904 0 : break;
2905 : }
2906 : case JS_REGEXP_TYPE: {
2907 20 : accumulator->Add("<JSRegExp");
2908 : JSRegExp* regexp = JSRegExp::cast(this);
2909 20 : if (regexp->source()->IsString()) {
2910 20 : accumulator->Add(" ");
2911 20 : String::cast(regexp->source())->StringShortPrint(accumulator);
2912 : }
2913 20 : accumulator->Add(">");
2914 :
2915 20 : break;
2916 : }
2917 : case JS_FUNCTION_TYPE: {
2918 : JSFunction* function = JSFunction::cast(this);
2919 30 : Object* fun_name = function->shared()->DebugName();
2920 : bool printed = false;
2921 30 : if (fun_name->IsString()) {
2922 : String* str = String::cast(fun_name);
2923 30 : if (str->length() > 0) {
2924 30 : accumulator->Add("<JSFunction ");
2925 30 : accumulator->Put(str);
2926 : printed = true;
2927 : }
2928 : }
2929 30 : if (!printed) {
2930 0 : accumulator->Add("<JSFunction");
2931 : }
2932 30 : if (FLAG_trace_file_names) {
2933 : Object* source_name =
2934 : Script::cast(function->shared()->script())->name();
2935 0 : if (source_name->IsString()) {
2936 : String* str = String::cast(source_name);
2937 0 : if (str->length() > 0) {
2938 0 : accumulator->Add(" <");
2939 0 : accumulator->Put(str);
2940 0 : accumulator->Add(">");
2941 : }
2942 : }
2943 : }
2944 : accumulator->Add(" (sfi = %p)",
2945 30 : reinterpret_cast<void*>(function->shared()));
2946 30 : accumulator->Put('>');
2947 30 : break;
2948 : }
2949 : case JS_GENERATOR_OBJECT_TYPE: {
2950 0 : accumulator->Add("<JSGenerator>");
2951 0 : break;
2952 : }
2953 : case JS_ASYNC_GENERATOR_OBJECT_TYPE: {
2954 0 : accumulator->Add("<JS AsyncGenerator>");
2955 0 : break;
2956 : }
2957 :
2958 : // All other JSObjects are rather similar to each other (JSObject,
2959 : // JSGlobalProxy, JSGlobalObject, JSUndetectable, JSValue).
2960 : default: {
2961 : Map* map_of_this = map();
2962 : Heap* heap = GetHeap();
2963 384 : Object* constructor = map_of_this->GetConstructor();
2964 : bool printed = false;
2965 768 : if (constructor->IsHeapObject() &&
2966 384 : !heap->Contains(HeapObject::cast(constructor))) {
2967 0 : accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
2968 : } else {
2969 : bool global_object = IsJSGlobalProxy();
2970 384 : if (constructor->IsJSFunction()) {
2971 384 : if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
2972 0 : accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
2973 : } else {
2974 : String* constructor_name =
2975 : JSFunction::cast(constructor)->shared()->name();
2976 384 : if (constructor_name->length() > 0) {
2977 354 : accumulator->Add(global_object ? "<GlobalObject " : "<");
2978 354 : accumulator->Put(constructor_name);
2979 : accumulator->Add(
2980 : " %smap = %p",
2981 : map_of_this->is_deprecated() ? "deprecated-" : "",
2982 354 : map_of_this);
2983 : printed = true;
2984 : }
2985 : }
2986 0 : } else if (constructor->IsFunctionTemplateInfo()) {
2987 0 : accumulator->Add(global_object ? "<RemoteObject>" : "<RemoteObject>");
2988 : printed = true;
2989 : }
2990 384 : if (!printed) {
2991 30 : accumulator->Add("<JS%sObject", global_object ? "Global " : "");
2992 : }
2993 : }
2994 384 : if (IsJSValue()) {
2995 10 : accumulator->Add(" value = ");
2996 10 : JSValue::cast(this)->value()->ShortPrint(accumulator);
2997 : }
2998 384 : accumulator->Put('>');
2999 384 : break;
3000 : }
3001 : }
3002 565 : }
3003 :
3004 :
3005 0 : void JSObject::PrintElementsTransition(
3006 : FILE* file, Handle<JSObject> object,
3007 : ElementsKind from_kind, Handle<FixedArrayBase> from_elements,
3008 : ElementsKind to_kind, Handle<FixedArrayBase> to_elements) {
3009 0 : if (from_kind != to_kind) {
3010 0 : OFStream os(file);
3011 0 : os << "elements transition [" << ElementsKindToString(from_kind) << " -> "
3012 0 : << ElementsKindToString(to_kind) << "] in ";
3013 0 : JavaScriptFrame::PrintTop(object->GetIsolate(), file, false, true);
3014 0 : PrintF(file, " for ");
3015 0 : object->ShortPrint(file);
3016 0 : PrintF(file, " from ");
3017 0 : from_elements->ShortPrint(file);
3018 0 : PrintF(file, " to ");
3019 0 : to_elements->ShortPrint(file);
3020 0 : PrintF(file, "\n");
3021 : }
3022 0 : }
3023 :
3024 :
3025 : // static
3026 65961 : MaybeHandle<JSFunction> Map::GetConstructorFunction(
3027 : Handle<Map> map, Handle<Context> native_context) {
3028 65961 : if (map->IsPrimitiveMap()) {
3029 : int const constructor_function_index = map->GetConstructorFunctionIndex();
3030 7014 : if (constructor_function_index != kNoConstructorFunctionIndex) {
3031 : return handle(
3032 7014 : JSFunction::cast(native_context->get(constructor_function_index)));
3033 : }
3034 : }
3035 58947 : return MaybeHandle<JSFunction>();
3036 : }
3037 :
3038 :
3039 0 : void Map::PrintReconfiguration(FILE* file, int modify_index, PropertyKind kind,
3040 : PropertyAttributes attributes) {
3041 0 : OFStream os(file);
3042 0 : os << "[reconfiguring]";
3043 : Name* name = instance_descriptors()->GetKey(modify_index);
3044 0 : if (name->IsString()) {
3045 0 : String::cast(name)->PrintOn(file);
3046 : } else {
3047 0 : os << "{symbol " << static_cast<void*>(name) << "}";
3048 : }
3049 0 : os << ": " << (kind == kData ? "kData" : "ACCESSORS") << ", attrs: ";
3050 0 : os << attributes << " [";
3051 0 : JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
3052 0 : os << "]\n";
3053 0 : }
3054 :
3055 47663674 : VisitorId Map::GetVisitorId(Map* map) {
3056 : STATIC_ASSERT(kVisitorIdCount <= 256);
3057 :
3058 47663674 : const int instance_type = map->instance_type();
3059 : const bool has_unboxed_fields =
3060 : FLAG_unbox_double_fields && !map->HasFastPointerLayout();
3061 47663674 : if (instance_type < FIRST_NONSTRING_TYPE) {
3062 713 : switch (instance_type & kStringRepresentationMask) {
3063 : case kSeqStringTag:
3064 124 : if ((instance_type & kStringEncodingMask) == kOneByteStringTag) {
3065 : return kVisitSeqOneByteString;
3066 : } else {
3067 62 : return kVisitSeqTwoByteString;
3068 : }
3069 :
3070 : case kConsStringTag:
3071 62 : if (IsShortcutCandidate(instance_type)) {
3072 : return kVisitShortcutCandidate;
3073 : } else {
3074 0 : return kVisitConsString;
3075 : }
3076 :
3077 : case kSlicedStringTag:
3078 : return kVisitSlicedString;
3079 :
3080 : case kExternalStringTag:
3081 403 : return kVisitDataObject;
3082 :
3083 : case kThinStringTag:
3084 62 : return kVisitThinString;
3085 : }
3086 0 : UNREACHABLE();
3087 : }
3088 :
3089 47662961 : switch (instance_type) {
3090 : case BYTE_ARRAY_TYPE:
3091 : return kVisitByteArray;
3092 :
3093 : case BYTECODE_ARRAY_TYPE:
3094 31 : return kVisitBytecodeArray;
3095 :
3096 : case FREE_SPACE_TYPE:
3097 31 : return kVisitFreeSpace;
3098 :
3099 : case HASH_TABLE_TYPE:
3100 : case FIXED_ARRAY_TYPE:
3101 558 : return kVisitFixedArray;
3102 :
3103 : case FIXED_DOUBLE_ARRAY_TYPE:
3104 31 : return kVisitFixedDoubleArray;
3105 :
3106 : case PROPERTY_ARRAY_TYPE:
3107 31 : return kVisitPropertyArray;
3108 :
3109 : case FEEDBACK_VECTOR_TYPE:
3110 31 : return kVisitFeedbackVector;
3111 :
3112 : case ODDBALL_TYPE:
3113 310 : return kVisitOddball;
3114 :
3115 : case MAP_TYPE:
3116 31 : return kVisitMap;
3117 :
3118 : case CODE_TYPE:
3119 31 : return kVisitCode;
3120 :
3121 : case CELL_TYPE:
3122 124 : return kVisitCell;
3123 :
3124 : case PROPERTY_CELL_TYPE:
3125 31 : return kVisitPropertyCell;
3126 :
3127 : case WEAK_CELL_TYPE:
3128 31 : return kVisitWeakCell;
3129 :
3130 : case TRANSITION_ARRAY_TYPE:
3131 31 : return kVisitTransitionArray;
3132 :
3133 : case JS_WEAK_MAP_TYPE:
3134 : case JS_WEAK_SET_TYPE:
3135 22961 : return kVisitJSWeakCollection;
3136 :
3137 : case JS_REGEXP_TYPE:
3138 14692 : return kVisitJSRegExp;
3139 :
3140 : case SHARED_FUNCTION_INFO_TYPE:
3141 31 : return kVisitSharedFunctionInfo;
3142 :
3143 : case JS_PROXY_TYPE:
3144 305 : return kVisitStruct;
3145 :
3146 : case SYMBOL_TYPE:
3147 31 : return kVisitSymbol;
3148 :
3149 : case JS_ARRAY_BUFFER_TYPE:
3150 12827 : return kVisitJSArrayBuffer;
3151 :
3152 : case SMALL_ORDERED_HASH_MAP_TYPE:
3153 31 : return kVisitSmallOrderedHashMap;
3154 :
3155 : case SMALL_ORDERED_HASH_SET_TYPE:
3156 31 : return kVisitSmallOrderedHashSet;
3157 :
3158 : case JS_OBJECT_TYPE:
3159 : case JS_ERROR_TYPE:
3160 : case JS_ARGUMENTS_TYPE:
3161 : case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
3162 : case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
3163 : case JS_GENERATOR_OBJECT_TYPE:
3164 : case JS_ASYNC_GENERATOR_OBJECT_TYPE:
3165 : case JS_MODULE_NAMESPACE_TYPE:
3166 : case JS_VALUE_TYPE:
3167 : case JS_DATE_TYPE:
3168 : case JS_ARRAY_TYPE:
3169 : case JS_GLOBAL_PROXY_TYPE:
3170 : case JS_GLOBAL_OBJECT_TYPE:
3171 : case JS_MESSAGE_OBJECT_TYPE:
3172 : case JS_TYPED_ARRAY_TYPE:
3173 : case JS_DATA_VIEW_TYPE:
3174 : case JS_SET_TYPE:
3175 : case JS_MAP_TYPE:
3176 : case JS_SET_KEY_VALUE_ITERATOR_TYPE:
3177 : case JS_SET_VALUE_ITERATOR_TYPE:
3178 : case JS_MAP_KEY_ITERATOR_TYPE:
3179 : case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
3180 : case JS_MAP_VALUE_ITERATOR_TYPE:
3181 : case JS_STRING_ITERATOR_TYPE:
3182 :
3183 : #define ARRAY_ITERATOR_CASE(type) case type:
3184 : ARRAY_ITERATOR_TYPE_LIST(ARRAY_ITERATOR_CASE)
3185 : #undef ARRAY_ITERATOR_CASE
3186 :
3187 : case JS_PROMISE_TYPE:
3188 : case WASM_INSTANCE_TYPE:
3189 : case WASM_MEMORY_TYPE:
3190 : case WASM_MODULE_TYPE:
3191 : case WASM_TABLE_TYPE:
3192 : case JS_BOUND_FUNCTION_TYPE:
3193 39981413 : return has_unboxed_fields ? kVisitJSObject : kVisitJSObjectFast;
3194 : case JS_API_OBJECT_TYPE:
3195 : case JS_SPECIAL_API_OBJECT_TYPE:
3196 6118312 : return kVisitJSApiObject;
3197 :
3198 : case JS_FUNCTION_TYPE:
3199 1509856 : return kVisitJSFunction;
3200 :
3201 : case FILLER_TYPE:
3202 : case FOREIGN_TYPE:
3203 : case HEAP_NUMBER_TYPE:
3204 : case MUTABLE_HEAP_NUMBER_TYPE:
3205 160 : return kVisitDataObject;
3206 :
3207 : case BIGINT_TYPE:
3208 31 : return kVisitBigInt;
3209 :
3210 : case FIXED_UINT8_ARRAY_TYPE:
3211 : case FIXED_INT8_ARRAY_TYPE:
3212 : case FIXED_UINT16_ARRAY_TYPE:
3213 : case FIXED_INT16_ARRAY_TYPE:
3214 : case FIXED_UINT32_ARRAY_TYPE:
3215 : case FIXED_INT32_ARRAY_TYPE:
3216 : case FIXED_FLOAT32_ARRAY_TYPE:
3217 : case FIXED_UINT8_CLAMPED_ARRAY_TYPE:
3218 248 : return kVisitFixedTypedArrayBase;
3219 :
3220 : case FIXED_FLOAT64_ARRAY_TYPE:
3221 31 : return kVisitFixedFloat64Array;
3222 :
3223 : #define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE:
3224 : STRUCT_LIST(MAKE_STRUCT_CASE)
3225 : #undef MAKE_STRUCT_CASE
3226 682 : if (instance_type == ALLOCATION_SITE_TYPE) {
3227 : return kVisitAllocationSite;
3228 : }
3229 :
3230 651 : return kVisitStruct;
3231 :
3232 : default:
3233 0 : UNREACHABLE();
3234 : }
3235 : }
3236 :
3237 0 : void Map::PrintGeneralization(
3238 : FILE* file, const char* reason, int modify_index, int split,
3239 : int descriptors, bool descriptor_to_field,
3240 : Representation old_representation, Representation new_representation,
3241 : MaybeHandle<FieldType> old_field_type, MaybeHandle<Object> old_value,
3242 : MaybeHandle<FieldType> new_field_type, MaybeHandle<Object> new_value) {
3243 0 : OFStream os(file);
3244 0 : os << "[generalizing]";
3245 : Name* name = instance_descriptors()->GetKey(modify_index);
3246 0 : if (name->IsString()) {
3247 0 : String::cast(name)->PrintOn(file);
3248 : } else {
3249 0 : os << "{symbol " << static_cast<void*>(name) << "}";
3250 : }
3251 0 : os << ":";
3252 0 : if (descriptor_to_field) {
3253 0 : os << "c";
3254 : } else {
3255 0 : os << old_representation.Mnemonic() << "{";
3256 0 : if (old_field_type.is_null()) {
3257 0 : os << Brief(*(old_value.ToHandleChecked()));
3258 : } else {
3259 0 : old_field_type.ToHandleChecked()->PrintTo(os);
3260 : }
3261 0 : os << "}";
3262 : }
3263 0 : os << "->" << new_representation.Mnemonic() << "{";
3264 0 : if (new_field_type.is_null()) {
3265 0 : os << Brief(*(new_value.ToHandleChecked()));
3266 : } else {
3267 0 : new_field_type.ToHandleChecked()->PrintTo(os);
3268 : }
3269 0 : os << "} (";
3270 0 : if (strlen(reason) > 0) {
3271 0 : os << reason;
3272 : } else {
3273 0 : os << "+" << (descriptors - split) << " maps";
3274 : }
3275 0 : os << ") [";
3276 0 : JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
3277 0 : os << "]\n";
3278 0 : }
3279 :
3280 :
3281 0 : void JSObject::PrintInstanceMigration(FILE* file,
3282 : Map* original_map,
3283 : Map* new_map) {
3284 0 : if (new_map->is_dictionary_map()) {
3285 0 : PrintF(file, "[migrating to slow]\n");
3286 0 : return;
3287 : }
3288 0 : PrintF(file, "[migrating]");
3289 : DescriptorArray* o = original_map->instance_descriptors();
3290 : DescriptorArray* n = new_map->instance_descriptors();
3291 0 : for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) {
3292 0 : Representation o_r = o->GetDetails(i).representation();
3293 0 : Representation n_r = n->GetDetails(i).representation();
3294 0 : if (!o_r.Equals(n_r)) {
3295 0 : String::cast(o->GetKey(i))->PrintOn(file);
3296 0 : PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic());
3297 0 : } else if (o->GetDetails(i).location() == kDescriptor &&
3298 0 : n->GetDetails(i).location() == kField) {
3299 : Name* name = o->GetKey(i);
3300 0 : if (name->IsString()) {
3301 0 : String::cast(name)->PrintOn(file);
3302 : } else {
3303 0 : PrintF(file, "{symbol %p}", static_cast<void*>(name));
3304 : }
3305 0 : PrintF(file, " ");
3306 : }
3307 : }
3308 0 : if (original_map->elements_kind() != new_map->elements_kind()) {
3309 : PrintF(file, "elements_kind[%i->%i]", original_map->elements_kind(),
3310 0 : new_map->elements_kind());
3311 : }
3312 0 : PrintF(file, "\n");
3313 : }
3314 :
3315 406434 : bool JSObject::IsUnmodifiedApiObject(Object** o) {
3316 406434 : Object* object = *o;
3317 406434 : if (object->IsSmi()) return false;
3318 : HeapObject* heap_object = HeapObject::cast(object);
3319 406434 : if (!object->IsJSObject()) return false;
3320 : JSObject* js_object = JSObject::cast(object);
3321 31702 : if (!js_object->WasConstructedFromApiFunction()) return false;
3322 21 : Object* maybe_constructor = js_object->map()->GetConstructor();
3323 21 : if (!maybe_constructor->IsJSFunction()) return false;
3324 : JSFunction* constructor = JSFunction::cast(maybe_constructor);
3325 21 : if (js_object->elements()->length() != 0) return false;
3326 :
3327 16 : return constructor->initial_map() == heap_object->map();
3328 : }
3329 :
3330 933 : void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
3331 : Heap* heap = GetHeap();
3332 : Isolate* isolate = heap->isolate();
3333 933 : if (!heap->Contains(this)) {
3334 0 : os << "!!!INVALID POINTER!!!";
3335 0 : return;
3336 : }
3337 933 : if (!heap->Contains(map())) {
3338 0 : os << "!!!INVALID MAP!!!";
3339 0 : return;
3340 : }
3341 :
3342 933 : os << this << " ";
3343 :
3344 933 : if (IsString()) {
3345 : HeapStringAllocator allocator;
3346 : StringStream accumulator(&allocator);
3347 32 : String::cast(this)->StringShortPrint(&accumulator);
3348 96 : os << accumulator.ToCString().get();
3349 : return;
3350 : }
3351 901 : if (IsJSObject()) {
3352 : HeapStringAllocator allocator;
3353 : StringStream accumulator(&allocator);
3354 565 : JSObject::cast(this)->JSObjectShortPrint(&accumulator);
3355 1695 : os << accumulator.ToCString().get();
3356 : return;
3357 : }
3358 336 : switch (map()->instance_type()) {
3359 : case MAP_TYPE:
3360 0 : os << "<Map(" << ElementsKindToString(Map::cast(this)->elements_kind())
3361 0 : << ")>";
3362 0 : break;
3363 : case HASH_TABLE_TYPE:
3364 0 : os << "<HashTable[" << FixedArray::cast(this)->length() << "]>";
3365 0 : break;
3366 : case FIXED_ARRAY_TYPE:
3367 0 : os << "<FixedArray[" << FixedArray::cast(this)->length() << "]>";
3368 0 : break;
3369 : case FIXED_DOUBLE_ARRAY_TYPE:
3370 0 : os << "<FixedDoubleArray[" << FixedDoubleArray::cast(this)->length()
3371 0 : << "]>";
3372 0 : break;
3373 : case BYTE_ARRAY_TYPE:
3374 0 : os << "<ByteArray[" << ByteArray::cast(this)->length() << "]>";
3375 0 : break;
3376 : case BYTECODE_ARRAY_TYPE:
3377 0 : os << "<BytecodeArray[" << BytecodeArray::cast(this)->length() << "]>";
3378 0 : break;
3379 : case TRANSITION_ARRAY_TYPE:
3380 0 : os << "<TransitionArray[" << TransitionArray::cast(this)->length()
3381 0 : << "]>";
3382 0 : break;
3383 : case PROPERTY_ARRAY_TYPE:
3384 0 : os << "<PropertyArray[" << PropertyArray::cast(this)->length() << "]>";
3385 0 : break;
3386 : case FEEDBACK_VECTOR_TYPE:
3387 0 : os << "<FeedbackVector[" << FeedbackVector::cast(this)->length() << "]>";
3388 0 : break;
3389 : case FREE_SPACE_TYPE:
3390 0 : os << "<FreeSpace[" << FreeSpace::cast(this)->size() << "]>";
3391 0 : break;
3392 : #define TYPED_ARRAY_SHORT_PRINT(Type, type, TYPE, ctype, size) \
3393 : case FIXED_##TYPE##_ARRAY_TYPE: \
3394 : os << "<Fixed" #Type "Array[" << Fixed##Type##Array::cast(this)->length() \
3395 : << "]>"; \
3396 : break;
3397 :
3398 0 : TYPED_ARRAYS(TYPED_ARRAY_SHORT_PRINT)
3399 : #undef TYPED_ARRAY_SHORT_PRINT
3400 :
3401 : case SHARED_FUNCTION_INFO_TYPE: {
3402 : SharedFunctionInfo* shared = SharedFunctionInfo::cast(this);
3403 0 : std::unique_ptr<char[]> debug_name = shared->DebugName()->ToCString();
3404 0 : if (debug_name[0] != 0) {
3405 0 : os << "<SharedFunctionInfo " << debug_name.get() << ">";
3406 : } else {
3407 0 : os << "<SharedFunctionInfo>";
3408 : }
3409 : break;
3410 : }
3411 : case JS_MESSAGE_OBJECT_TYPE:
3412 0 : os << "<JSMessageObject>";
3413 0 : break;
3414 : #define MAKE_STRUCT_CASE(NAME, Name, name) \
3415 : case NAME##_TYPE: \
3416 : os << "<" #Name; \
3417 : Name::cast(this)->BriefPrintDetails(os); \
3418 : os << ">"; \
3419 : break;
3420 0 : STRUCT_LIST(MAKE_STRUCT_CASE)
3421 : #undef MAKE_STRUCT_CASE
3422 : case CODE_TYPE: {
3423 : Code* code = Code::cast(this);
3424 0 : os << "<Code " << Code::Kind2String(code->kind()) << ">";
3425 0 : break;
3426 : }
3427 : case ODDBALL_TYPE: {
3428 64 : if (IsUndefined(isolate)) {
3429 32 : os << "<undefined>";
3430 32 : } else if (IsTheHole(isolate)) {
3431 0 : os << "<the_hole>";
3432 32 : } else if (IsNull(isolate)) {
3433 12 : os << "<null>";
3434 20 : } else if (IsTrue(isolate)) {
3435 10 : os << "<true>";
3436 10 : } else if (IsFalse(isolate)) {
3437 10 : os << "<false>";
3438 : } else {
3439 0 : os << "<Odd Oddball: ";
3440 0 : os << Oddball::cast(this)->to_string()->ToCString().get();
3441 0 : os << ">";
3442 : }
3443 : break;
3444 : }
3445 : case SYMBOL_TYPE: {
3446 : Symbol* symbol = Symbol::cast(this);
3447 192 : symbol->SymbolShortPrint(os);
3448 192 : break;
3449 : }
3450 : case HEAP_NUMBER_TYPE: {
3451 70 : os << "<Number ";
3452 : HeapNumber::cast(this)->HeapNumberPrint(os);
3453 70 : os << ">";
3454 70 : break;
3455 : }
3456 : case MUTABLE_HEAP_NUMBER_TYPE: {
3457 0 : os << "<MutableNumber ";
3458 : HeapNumber::cast(this)->HeapNumberPrint(os);
3459 : os << '>';
3460 : break;
3461 : }
3462 : case BIGINT_TYPE: {
3463 0 : os << "<BigInt ";
3464 0 : BigInt::cast(this)->BigIntShortPrint(os);
3465 0 : os << ">";
3466 0 : break;
3467 : }
3468 : case JS_PROXY_TYPE:
3469 10 : os << "<JSProxy>";
3470 10 : break;
3471 : case FOREIGN_TYPE:
3472 0 : os << "<Foreign>";
3473 0 : break;
3474 : case CELL_TYPE: {
3475 0 : os << "<Cell value= ";
3476 : HeapStringAllocator allocator;
3477 : StringStream accumulator(&allocator);
3478 0 : Cell::cast(this)->value()->ShortPrint(&accumulator);
3479 0 : os << accumulator.ToCString().get();
3480 : os << '>';
3481 : break;
3482 : }
3483 : case PROPERTY_CELL_TYPE: {
3484 : PropertyCell* cell = PropertyCell::cast(this);
3485 0 : os << "<PropertyCell name=";
3486 0 : cell->name()->ShortPrint(os);
3487 0 : os << " value=";
3488 : HeapStringAllocator allocator;
3489 : StringStream accumulator(&allocator);
3490 0 : cell->value()->ShortPrint(&accumulator);
3491 0 : os << accumulator.ToCString().get();
3492 : os << '>';
3493 : break;
3494 : }
3495 : case WEAK_CELL_TYPE: {
3496 0 : os << "<WeakCell value= ";
3497 : HeapStringAllocator allocator;
3498 : StringStream accumulator(&allocator);
3499 0 : WeakCell::cast(this)->value()->ShortPrint(&accumulator);
3500 0 : os << accumulator.ToCString().get();
3501 : os << '>';
3502 : break;
3503 : }
3504 : default:
3505 0 : os << "<Other heap object (" << map()->instance_type() << ")>";
3506 0 : break;
3507 : }
3508 : }
3509 :
3510 0 : void Struct::BriefPrintDetails(std::ostream& os) {}
3511 :
3512 0 : void Tuple2::BriefPrintDetails(std::ostream& os) {
3513 0 : os << " " << Brief(value1()) << ", " << Brief(value2());
3514 0 : }
3515 :
3516 0 : void Tuple3::BriefPrintDetails(std::ostream& os) {
3517 0 : os << " " << Brief(value1()) << ", " << Brief(value2()) << ", "
3518 0 : << Brief(value3());
3519 0 : }
3520 :
3521 19937875 : void HeapObject::Iterate(ObjectVisitor* v) { IterateFast<ObjectVisitor>(v); }
3522 :
3523 :
3524 58 : void HeapObject::IterateBody(ObjectVisitor* v) {
3525 : Map* m = map();
3526 58 : IterateBodyFast<ObjectVisitor>(m->instance_type(), SizeFromMap(m), v);
3527 58 : }
3528 :
3529 :
3530 56090874 : void HeapObject::IterateBody(InstanceType type, int object_size,
3531 : ObjectVisitor* v) {
3532 : IterateBodyFast<ObjectVisitor>(type, object_size, v);
3533 56065937 : }
3534 :
3535 :
3536 : struct CallIsValidSlot {
3537 : template <typename BodyDescriptor>
3538 : static bool apply(HeapObject* obj, int offset, int) {
3539 0 : return BodyDescriptor::IsValidSlot(obj, offset);
3540 : }
3541 : };
3542 :
3543 :
3544 906338 : bool HeapObject::IsValidSlot(int offset) {
3545 : DCHECK_NE(0, offset);
3546 : return BodyDescriptorApply<CallIsValidSlot, bool>(map()->instance_type(),
3547 906338 : this, offset, 0);
3548 : }
3549 :
3550 14202 : void HeapNumber::HeapNumberPrint(std::ostream& os) { // NOLINT
3551 : os << value();
3552 14202 : }
3553 :
3554 : #define FIELD_ADDR(p, offset) \
3555 : (reinterpret_cast<byte*>(p) + offset - kHeapObjectTag)
3556 :
3557 : #define FIELD_ADDR_CONST(p, offset) \
3558 : (reinterpret_cast<const byte*>(p) + offset - kHeapObjectTag)
3559 :
3560 : #define READ_INT32_FIELD(p, offset) \
3561 : (*reinterpret_cast<const int32_t*>(FIELD_ADDR_CONST(p, offset)))
3562 :
3563 : #define READ_INT64_FIELD(p, offset) \
3564 : (*reinterpret_cast<const int64_t*>(FIELD_ADDR_CONST(p, offset)))
3565 :
3566 : #define READ_BYTE_FIELD(p, offset) \
3567 : (*reinterpret_cast<const byte*>(FIELD_ADDR_CONST(p, offset)))
3568 :
3569 44808624 : String* JSReceiver::class_name() {
3570 44808624 : if (IsFunction()) {
3571 20769818 : return GetHeap()->Function_string();
3572 : }
3573 24038806 : Object* maybe_constructor = map()->GetConstructor();
3574 24038806 : if (maybe_constructor->IsJSFunction()) {
3575 : JSFunction* constructor = JSFunction::cast(maybe_constructor);
3576 24038725 : return String::cast(constructor->shared()->instance_class_name());
3577 81 : } else if (maybe_constructor->IsFunctionTemplateInfo()) {
3578 : FunctionTemplateInfo* info = FunctionTemplateInfo::cast(maybe_constructor);
3579 : return info->class_name()->IsString() ? String::cast(info->class_name())
3580 1 : : GetHeap()->empty_string();
3581 : }
3582 :
3583 : // If the constructor is not present, return "Object".
3584 80 : return GetHeap()->Object_string();
3585 : }
3586 :
3587 :
3588 : // static
3589 5200026 : Handle<String> JSReceiver::GetConstructorName(Handle<JSReceiver> receiver) {
3590 : Isolate* isolate = receiver->GetIsolate();
3591 :
3592 : // If the object was instantiated simply with base == new.target, the
3593 : // constructor on the map provides the most accurate name.
3594 : // Don't provide the info for prototypes, since their constructors are
3595 : // reclaimed and replaced by Object in OptimizeAsPrototype.
3596 15599538 : if (!receiver->IsJSProxy() && receiver->map()->new_target_is_base() &&
3597 : !receiver->map()->is_prototype_map()) {
3598 5053404 : Object* maybe_constructor = receiver->map()->GetConstructor();
3599 5053404 : if (maybe_constructor->IsJSFunction()) {
3600 : JSFunction* constructor = JSFunction::cast(maybe_constructor);
3601 : String* name = constructor->shared()->name();
3602 4508564 : if (name->length() == 0) name = constructor->shared()->inferred_name();
3603 8532749 : if (name->length() != 0 &&
3604 4024185 : !name->Equals(isolate->heap()->Object_string())) {
3605 : return handle(name, isolate);
3606 : }
3607 544840 : } else if (maybe_constructor->IsFunctionTemplateInfo()) {
3608 : FunctionTemplateInfo* info =
3609 : FunctionTemplateInfo::cast(maybe_constructor);
3610 0 : if (info->class_name()->IsString()) {
3611 : return handle(String::cast(info->class_name()), isolate);
3612 : }
3613 : }
3614 : }
3615 :
3616 : Handle<Object> maybe_tag = JSReceiver::GetDataProperty(
3617 1984580 : receiver, isolate->factory()->to_string_tag_symbol());
3618 1984580 : if (maybe_tag->IsString()) return Handle<String>::cast(maybe_tag);
3619 :
3620 1423800 : PrototypeIterator iter(isolate, receiver);
3621 1833827 : if (iter.IsAtEnd()) return handle(receiver->class_name());
3622 1013773 : Handle<JSReceiver> start = PrototypeIterator::GetCurrent<JSReceiver>(iter);
3623 : LookupIterator it(receiver, isolate->factory()->constructor_string(), start,
3624 1013773 : LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
3625 1013773 : Handle<Object> maybe_constructor = JSReceiver::GetDataProperty(&it);
3626 : Handle<String> result = isolate->factory()->Object_string();
3627 1013773 : if (maybe_constructor->IsJSFunction()) {
3628 : JSFunction* constructor = JSFunction::cast(*maybe_constructor);
3629 : String* name = constructor->shared()->name();
3630 1013643 : if (name->length() == 0) name = constructor->shared()->inferred_name();
3631 1013643 : if (name->length() > 0) result = handle(name, isolate);
3632 : }
3633 :
3634 : return result.is_identical_to(isolate->factory()->Object_string())
3635 392945 : ? handle(receiver->class_name())
3636 1634601 : : result;
3637 : }
3638 :
3639 222979 : Handle<Context> JSReceiver::GetCreationContext() {
3640 : JSReceiver* receiver = this;
3641 445970 : while (receiver->IsJSBoundFunction()) {
3642 : receiver = JSBoundFunction::cast(receiver)->bound_target_function();
3643 : }
3644 : // Externals are JSObjects with null as a constructor.
3645 : DCHECK(!receiver->IsExternal());
3646 222979 : Object* constructor = receiver->map()->GetConstructor();
3647 : JSFunction* function;
3648 222979 : if (constructor->IsJSFunction()) {
3649 : function = JSFunction::cast(constructor);
3650 126607 : } else if (constructor->IsFunctionTemplateInfo()) {
3651 : // Remote objects don't have a creation context.
3652 2 : return Handle<Context>::null();
3653 : } else {
3654 : // Functions have null as a constructor,
3655 : // but any JSFunction knows its context immediately.
3656 126605 : CHECK(receiver->IsJSFunction());
3657 : function = JSFunction::cast(receiver);
3658 : }
3659 :
3660 222977 : return function->has_context()
3661 : ? Handle<Context>(function->context()->native_context())
3662 222977 : : Handle<Context>::null();
3663 : }
3664 :
3665 : // static
3666 7162785 : Handle<Object> Map::WrapFieldType(Handle<FieldType> type) {
3667 7728439 : if (type->IsClass()) return Map::WeakCellForMap(type->AsClass());
3668 6597130 : return type;
3669 : }
3670 :
3671 : // static
3672 40094350 : FieldType* Map::UnwrapFieldType(Object* wrapped_type) {
3673 : Object* value = wrapped_type;
3674 40094350 : if (value->IsWeakCell()) {
3675 1351217 : if (WeakCell::cast(value)->cleared()) return FieldType::None();
3676 : value = WeakCell::cast(value)->value();
3677 : }
3678 40094166 : return FieldType::cast(value);
3679 : }
3680 :
3681 6747388 : MaybeHandle<Map> Map::CopyWithField(Handle<Map> map, Handle<Name> name,
3682 : Handle<FieldType> type,
3683 : PropertyAttributes attributes,
3684 : PropertyConstness constness,
3685 : Representation representation,
3686 : TransitionFlag flag) {
3687 : DCHECK(DescriptorArray::kNotFound ==
3688 : map->instance_descriptors()->Search(
3689 : *name, map->NumberOfOwnDescriptors()));
3690 :
3691 : // Ensure the descriptor array does not get too big.
3692 6747388 : if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
3693 78 : return MaybeHandle<Map>();
3694 : }
3695 :
3696 : Isolate* isolate = map->GetIsolate();
3697 :
3698 : // Compute the new index for new field.
3699 6747310 : int index = map->NextFreePropertyIndex();
3700 :
3701 6747310 : if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
3702 : representation = Representation::Tagged();
3703 3003 : type = FieldType::Any(isolate);
3704 7287693 : } else if (IsTransitionableFastElementsKind(map->elements_kind()) &&
3705 : IsInplaceGeneralizableField(constness, representation, *type)) {
3706 : // We don't support propagation of field generalization through elements
3707 : // kind transitions because they are inserted into the transition tree
3708 : // before field transitions. In order to avoid complexity of handling
3709 : // such a case we ensure that all maps with transitionable elements kinds
3710 : // do not have fields that can be generalized in-place (without creation
3711 : // of a new map).
3712 : DCHECK(representation.IsHeapObject());
3713 389663 : type = FieldType::Any(isolate);
3714 : }
3715 :
3716 6747310 : Handle<Object> wrapped_type(WrapFieldType(type));
3717 :
3718 : DCHECK_IMPLIES(!FLAG_track_constant_fields, constness == kMutable);
3719 : Descriptor d = Descriptor::DataField(name, index, attributes, constness,
3720 6747310 : representation, wrapped_type);
3721 6747310 : Handle<Map> new_map = Map::CopyAddDescriptor(map, &d, flag);
3722 6747311 : new_map->AccountAddedPropertyField();
3723 6747311 : return new_map;
3724 : }
3725 :
3726 :
3727 8384989 : MaybeHandle<Map> Map::CopyWithConstant(Handle<Map> map,
3728 : Handle<Name> name,
3729 : Handle<Object> constant,
3730 : PropertyAttributes attributes,
3731 : TransitionFlag flag) {
3732 : // Ensure the descriptor array does not get too big.
3733 8384989 : if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
3734 0 : return MaybeHandle<Map>();
3735 : }
3736 :
3737 : if (FLAG_track_constant_fields) {
3738 : Isolate* isolate = map->GetIsolate();
3739 : Representation representation = constant->OptimalRepresentation();
3740 : Handle<FieldType> type = constant->OptimalType(isolate, representation);
3741 : return CopyWithField(map, name, type, attributes, kConst, representation,
3742 : flag);
3743 : } else {
3744 : // Allocate new instance descriptors with (name, constant) added.
3745 8384989 : Descriptor d = Descriptor::DataConstant(name, 0, constant, attributes);
3746 8384989 : Handle<Map> new_map = Map::CopyAddDescriptor(map, &d, flag);
3747 8384987 : return new_map;
3748 : }
3749 : }
3750 :
3751 0 : const char* Representation::Mnemonic() const {
3752 0 : switch (kind_) {
3753 : case kNone: return "v";
3754 0 : case kTagged: return "t";
3755 0 : case kSmi: return "s";
3756 0 : case kDouble: return "d";
3757 0 : case kInteger32: return "i";
3758 0 : case kHeapObject: return "h";
3759 0 : case kExternal: return "x";
3760 : default:
3761 0 : UNREACHABLE();
3762 : }
3763 : }
3764 :
3765 0 : bool Map::TransitionRemovesTaggedField(Map* target) const {
3766 0 : int inobject = NumberOfFields();
3767 0 : int target_inobject = target->NumberOfFields();
3768 0 : for (int i = target_inobject; i < inobject; i++) {
3769 0 : FieldIndex index = FieldIndex::ForPropertyIndex(this, i);
3770 0 : if (!IsUnboxedDoubleField(index)) return true;
3771 : }
3772 : return false;
3773 : }
3774 :
3775 0 : bool Map::TransitionChangesTaggedFieldToUntaggedField(Map* target) const {
3776 0 : int inobject = NumberOfFields();
3777 0 : int target_inobject = target->NumberOfFields();
3778 : int limit = Min(inobject, target_inobject);
3779 0 : for (int i = 0; i < limit; i++) {
3780 0 : FieldIndex index = FieldIndex::ForPropertyIndex(target, i);
3781 0 : if (!IsUnboxedDoubleField(index) && target->IsUnboxedDoubleField(index)) {
3782 0 : return true;
3783 : }
3784 : }
3785 : return false;
3786 : }
3787 :
3788 0 : bool Map::TransitionRequiresSynchronizationWithGC(Map* target) const {
3789 0 : return TransitionRemovesTaggedField(target) ||
3790 0 : TransitionChangesTaggedFieldToUntaggedField(target);
3791 : }
3792 :
3793 92091 : bool Map::InstancesNeedRewriting(Map* target) const {
3794 92091 : int target_number_of_fields = target->NumberOfFields();
3795 : int target_inobject = target->GetInObjectProperties();
3796 : int target_unused = target->UnusedPropertyFields();
3797 : int old_number_of_fields;
3798 :
3799 : return InstancesNeedRewriting(target, target_number_of_fields,
3800 : target_inobject, target_unused,
3801 92091 : &old_number_of_fields);
3802 : }
3803 :
3804 17496415 : bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields,
3805 : int target_inobject, int target_unused,
3806 : int* old_number_of_fields) const {
3807 : // If fields were added (or removed), rewrite the instance.
3808 17496415 : *old_number_of_fields = NumberOfFields();
3809 : DCHECK(target_number_of_fields >= *old_number_of_fields);
3810 17496416 : if (target_number_of_fields != *old_number_of_fields) return true;
3811 :
3812 : // If smi descriptors were replaced by double descriptors, rewrite.
3813 : DescriptorArray* old_desc = instance_descriptors();
3814 : DescriptorArray* new_desc = target->instance_descriptors();
3815 : int limit = NumberOfOwnDescriptors();
3816 58813524 : for (int i = 0; i < limit; i++) {
3817 86028232 : if (new_desc->GetDetails(i).representation().IsDouble() !=
3818 86028234 : old_desc->GetDetails(i).representation().IsDouble()) {
3819 : return true;
3820 : }
3821 : }
3822 :
3823 : // If no fields were added, and no inobject properties were removed, setting
3824 : // the map is sufficient.
3825 15799409 : if (target_inobject == GetInObjectProperties()) return false;
3826 : // In-object slack tracking may have reduced the object size of the new map.
3827 : // In that case, succeed if all existing fields were inobject, and they still
3828 : // fit within the new inobject size.
3829 : DCHECK(target_inobject < GetInObjectProperties());
3830 1 : if (target_number_of_fields <= target_inobject) {
3831 : DCHECK(target_number_of_fields + target_unused == target_inobject);
3832 : return false;
3833 : }
3834 : // Otherwise, properties will need to be moved to the backing store.
3835 0 : return true;
3836 : }
3837 :
3838 :
3839 : // static
3840 3888596 : void JSObject::UpdatePrototypeUserRegistration(Handle<Map> old_map,
3841 : Handle<Map> new_map,
3842 : Isolate* isolate) {
3843 : DCHECK(old_map->is_prototype_map());
3844 : DCHECK(new_map->is_prototype_map());
3845 3888596 : bool was_registered = JSObject::UnregisterPrototypeUser(old_map, isolate);
3846 3888596 : new_map->set_prototype_info(old_map->prototype_info());
3847 3888596 : old_map->set_prototype_info(Smi::kZero);
3848 3888596 : if (FLAG_trace_prototype_users) {
3849 : PrintF("Moving prototype_info %p from map %p to map %p.\n",
3850 : reinterpret_cast<void*>(new_map->prototype_info()),
3851 : reinterpret_cast<void*>(*old_map),
3852 0 : reinterpret_cast<void*>(*new_map));
3853 : }
3854 3888596 : if (was_registered) {
3855 154799 : if (new_map->prototype_info()->IsPrototypeInfo()) {
3856 : // The new map isn't registered with its prototype yet; reflect this fact
3857 : // in the PrototypeInfo it just inherited from the old map.
3858 : PrototypeInfo::cast(new_map->prototype_info())
3859 : ->set_registry_slot(PrototypeInfo::UNREGISTERED);
3860 : }
3861 154799 : JSObject::LazyRegisterPrototypeUser(new_map, isolate);
3862 : }
3863 3888596 : }
3864 :
3865 : namespace {
3866 : // To migrate a fast instance to a fast map:
3867 : // - First check whether the instance needs to be rewritten. If not, simply
3868 : // change the map.
3869 : // - Otherwise, allocate a fixed array large enough to hold all fields, in
3870 : // addition to unused space.
3871 : // - Copy all existing properties in, in the following order: backing store
3872 : // properties, unused fields, inobject properties.
3873 : // - If all allocation succeeded, commit the state atomically:
3874 : // * Copy inobject properties from the backing store back into the object.
3875 : // * Trim the difference in instance size of the object. This also cleanly
3876 : // frees inobject properties that moved to the backing store.
3877 : // * If there are properties left in the backing store, trim of the space used
3878 : // to temporarily store the inobject properties.
3879 : // * If there are properties left in the backing store, install the backing
3880 : // store.
3881 29336856 : void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
3882 : Isolate* isolate = object->GetIsolate();
3883 : Handle<Map> old_map(object->map());
3884 : // In case of a regular transition.
3885 58673712 : if (new_map->GetBackPointer() == *old_map) {
3886 : // If the map does not add named properties, simply set the map.
3887 11932532 : if (old_map->NumberOfOwnDescriptors() ==
3888 : new_map->NumberOfOwnDescriptors()) {
3889 544169 : object->synchronized_set_map(*new_map);
3890 544169 : return;
3891 : }
3892 :
3893 : PropertyDetails details = new_map->GetLastDescriptorDetails();
3894 11388365 : int target_index = details.field_index() - new_map->GetInObjectProperties();
3895 : int property_array_length = object->property_array()->length();
3896 14557581 : bool have_space = old_map->UnusedPropertyFields() > 0 ||
3897 6008988 : (details.location() == kField && target_index >= 0 &&
3898 3004494 : property_array_length > target_index);
3899 : // Either new_map adds an kDescriptor property, or a kField property for
3900 : // which there is still space, and which does not require a mutable double
3901 : // box (an out-of-object double).
3902 22776730 : if (details.location() == kDescriptor ||
3903 11537651 : (have_space && ((FLAG_unbox_double_fields && target_index < 0) ||
3904 : !details.representation().IsDouble()))) {
3905 8381256 : object->synchronized_set_map(*new_map);
3906 8381256 : return;
3907 : }
3908 :
3909 : // If there is still space in the object, we need to allocate a mutable
3910 : // double box.
3911 3007109 : if (have_space) {
3912 : FieldIndex index =
3913 3468 : FieldIndex::ForDescriptor(*new_map, new_map->LastAdded());
3914 : DCHECK(details.representation().IsDouble());
3915 : DCHECK(!new_map->IsUnboxedDoubleField(index));
3916 : Handle<Object> value = isolate->factory()->NewMutableHeapNumber();
3917 3468 : object->RawFastPropertyAtPut(index, *value);
3918 3468 : object->synchronized_set_map(*new_map);
3919 : return;
3920 : }
3921 :
3922 : // This migration is a transition from a map that has run out of property
3923 : // space. Extend the backing store.
3924 3003641 : int grow_by = new_map->UnusedPropertyFields() + 1;
3925 : Handle<PropertyArray> old_storage(object->property_array());
3926 : Handle<PropertyArray> new_storage =
3927 3003641 : isolate->factory()->CopyPropertyArrayAndGrow(old_storage, grow_by);
3928 :
3929 : // Properly initialize newly added property.
3930 : Handle<Object> value;
3931 3003641 : if (details.representation().IsDouble()) {
3932 : value = isolate->factory()->NewMutableHeapNumber();
3933 : } else {
3934 : value = isolate->factory()->uninitialized_value();
3935 : }
3936 : DCHECK_EQ(kField, details.location());
3937 : DCHECK_EQ(kData, details.kind());
3938 : DCHECK_GE(target_index, 0); // Must be a backing store index.
3939 3003641 : new_storage->set(target_index, *value);
3940 :
3941 : // From here on we cannot fail and we shouldn't GC anymore.
3942 : DisallowHeapAllocation no_allocation;
3943 :
3944 : // Set the new property value and do the map transition.
3945 3003641 : object->SetProperties(*new_storage);
3946 3003641 : object->synchronized_set_map(*new_map);
3947 3003641 : return;
3948 : }
3949 :
3950 : int old_number_of_fields;
3951 17404325 : int number_of_fields = new_map->NumberOfFields();
3952 : int inobject = new_map->GetInObjectProperties();
3953 : int unused = new_map->UnusedPropertyFields();
3954 :
3955 : // Nothing to do if no functions were converted to fields and no smis were
3956 : // converted to doubles.
3957 17404323 : if (!old_map->InstancesNeedRewriting(*new_map, number_of_fields, inobject,
3958 17404324 : unused, &old_number_of_fields)) {
3959 15707366 : object->synchronized_set_map(*new_map);
3960 15707367 : return;
3961 : }
3962 :
3963 1696957 : int total_size = number_of_fields + unused;
3964 1696957 : int external = total_size - inobject;
3965 1696957 : Handle<PropertyArray> array = isolate->factory()->NewPropertyArray(external);
3966 :
3967 : // We use this array to temporarily store the inobject properties.
3968 : Handle<FixedArray> inobject_props =
3969 1696958 : isolate->factory()->NewFixedArray(inobject);
3970 :
3971 : Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors());
3972 : Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors());
3973 : int old_nof = old_map->NumberOfOwnDescriptors();
3974 : int new_nof = new_map->NumberOfOwnDescriptors();
3975 :
3976 : // This method only supports generalizing instances to at least the same
3977 : // number of properties.
3978 : DCHECK(old_nof <= new_nof);
3979 :
3980 53762535 : for (int i = 0; i < old_nof; i++) {
3981 52065577 : PropertyDetails details = new_descriptors->GetDetails(i);
3982 52065577 : if (details.location() != kField) continue;
3983 : DCHECK_EQ(kData, details.kind());
3984 42990590 : PropertyDetails old_details = old_descriptors->GetDetails(i);
3985 : Representation old_representation = old_details.representation();
3986 : Representation representation = details.representation();
3987 : Handle<Object> value;
3988 42990590 : if (old_details.location() == kDescriptor) {
3989 18570 : if (old_details.kind() == kAccessor) {
3990 : // In case of kAccessor -> kData property reconfiguration, the property
3991 : // must already be prepared for data of certain type.
3992 : DCHECK(!details.representation().IsNone());
3993 12080 : if (details.representation().IsDouble()) {
3994 : value = isolate->factory()->NewMutableHeapNumber();
3995 : } else {
3996 : value = isolate->factory()->uninitialized_value();
3997 : }
3998 : } else {
3999 : DCHECK_EQ(kData, old_details.kind());
4000 : value = handle(old_descriptors->GetValue(i), isolate);
4001 : DCHECK(!old_representation.IsDouble() && !representation.IsDouble());
4002 : }
4003 : } else {
4004 : DCHECK_EQ(kField, old_details.location());
4005 42972020 : FieldIndex index = FieldIndex::ForDescriptor(*old_map, i);
4006 42972020 : if (object->IsUnboxedDoubleField(index)) {
4007 : uint64_t old_bits = object->RawFastDoublePropertyAsBitsAt(index);
4008 : value = isolate->factory()->NewHeapNumberFromBits(
4009 5075 : old_bits, representation.IsDouble() ? MUTABLE : IMMUTABLE);
4010 :
4011 : } else {
4012 42966945 : value = handle(object->RawFastPropertyAt(index), isolate);
4013 42966945 : if (!old_representation.IsDouble() && representation.IsDouble()) {
4014 : DCHECK_IMPLIES(old_representation.IsNone(),
4015 : value->IsUninitialized(isolate));
4016 1945 : value = Object::NewStorageFor(isolate, value, representation);
4017 42965000 : } else if (old_representation.IsDouble() &&
4018 : !representation.IsDouble()) {
4019 318 : value = Object::WrapForRead(isolate, value, old_representation);
4020 : }
4021 : }
4022 : }
4023 : DCHECK(!(representation.IsDouble() && value->IsSmi()));
4024 : int target_index = new_descriptors->GetFieldIndex(i);
4025 42990590 : if (target_index < inobject) {
4026 1640228 : inobject_props->set(target_index, *value);
4027 : } else {
4028 82700724 : array->set(target_index - inobject, *value);
4029 : }
4030 : }
4031 :
4032 1676693 : for (int i = old_nof; i < new_nof; i++) {
4033 1676693 : PropertyDetails details = new_descriptors->GetDetails(i);
4034 1676693 : if (details.location() != kField) continue;
4035 : DCHECK_EQ(kData, details.kind());
4036 : Handle<Object> value;
4037 1676693 : if (details.representation().IsDouble()) {
4038 : value = isolate->factory()->NewMutableHeapNumber();
4039 : } else {
4040 : value = isolate->factory()->uninitialized_value();
4041 : }
4042 : int target_index = new_descriptors->GetFieldIndex(i);
4043 1676693 : if (target_index < inobject) {
4044 757062 : inobject_props->set(target_index, *value);
4045 : } else {
4046 1839262 : array->set(target_index - inobject, *value);
4047 : }
4048 : }
4049 :
4050 : // From here on we cannot fail and we shouldn't GC anymore.
4051 : DisallowHeapAllocation no_allocation;
4052 :
4053 1696958 : Heap* heap = isolate->heap();
4054 :
4055 : int old_instance_size = old_map->instance_size();
4056 :
4057 1696958 : heap->NotifyObjectLayoutChange(*object, old_instance_size, no_allocation);
4058 :
4059 : // Copy (real) inobject properties. If necessary, stop at number_of_fields to
4060 : // avoid overwriting |one_pointer_filler_map|.
4061 : int limit = Min(inobject, number_of_fields);
4062 4094248 : for (int i = 0; i < limit; i++) {
4063 2397290 : FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
4064 : Object* value = inobject_props->get(i);
4065 : // Can't use JSObject::FastPropertyAtPut() because proper map was not set
4066 : // yet.
4067 2397290 : if (new_map->IsUnboxedDoubleField(index)) {
4068 : DCHECK(value->IsMutableHeapNumber());
4069 : // Ensure that all bits of the double value are preserved.
4070 : object->RawFastDoublePropertyAsBitsAtPut(
4071 : index, HeapNumber::cast(value)->value_as_bits());
4072 11618 : if (i < old_number_of_fields && !old_map->IsUnboxedDoubleField(index)) {
4073 : // Transition from tagged to untagged slot.
4074 : heap->ClearRecordedSlot(*object,
4075 1307 : HeapObject::RawField(*object, index.offset()));
4076 : } else {
4077 : DCHECK(!heap->HasRecordedSlot(
4078 : *object, HeapObject::RawField(*object, index.offset())));
4079 : }
4080 : } else {
4081 2391354 : object->RawFastPropertyAtPut(index, value);
4082 : }
4083 : }
4084 :
4085 1696958 : if (external > 0) {
4086 936361 : object->SetProperties(*array);
4087 : }
4088 :
4089 : // Create filler object past the new instance size.
4090 : int new_instance_size = new_map->instance_size();
4091 1696958 : int instance_size_delta = old_instance_size - new_instance_size;
4092 : DCHECK_GE(instance_size_delta, 0);
4093 :
4094 1696958 : if (instance_size_delta > 0) {
4095 13 : Address address = object->address();
4096 : heap->CreateFillerObjectAt(address + new_instance_size, instance_size_delta,
4097 13 : ClearRecordedSlots::kYes);
4098 : }
4099 :
4100 : // We are storing the new map using release store after creating a filler for
4101 : // the left-over space to avoid races with the sweeper thread.
4102 1696958 : object->synchronized_set_map(*new_map);
4103 : }
4104 :
4105 918333 : void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map,
4106 : int expected_additional_properties) {
4107 : // The global object is always normalized.
4108 : DCHECK(!object->IsJSGlobalObject());
4109 : // JSGlobalProxy must never be normalized
4110 : DCHECK(!object->IsJSGlobalProxy());
4111 :
4112 : Isolate* isolate = object->GetIsolate();
4113 : HandleScope scope(isolate);
4114 : Handle<Map> map(object->map());
4115 :
4116 : // Allocate new content.
4117 : int real_size = map->NumberOfOwnDescriptors();
4118 : int property_count = real_size;
4119 918333 : if (expected_additional_properties > 0) {
4120 8569 : property_count += expected_additional_properties;
4121 : } else {
4122 : // Make space for two more properties.
4123 909764 : property_count += NameDictionary::kInitialCapacity;
4124 : }
4125 : Handle<NameDictionary> dictionary =
4126 918333 : NameDictionary::New(isolate, property_count);
4127 :
4128 : Handle<DescriptorArray> descs(map->instance_descriptors());
4129 3960506 : for (int i = 0; i < real_size; i++) {
4130 3042173 : PropertyDetails details = descs->GetDetails(i);
4131 : Handle<Name> key(descs->GetKey(i));
4132 : Handle<Object> value;
4133 3042173 : if (details.location() == kField) {
4134 2161922 : FieldIndex index = FieldIndex::ForDescriptor(*map, i);
4135 2161922 : if (details.kind() == kData) {
4136 2161922 : if (object->IsUnboxedDoubleField(index)) {
4137 : double old_value = object->RawFastDoublePropertyAt(index);
4138 : value = isolate->factory()->NewHeapNumber(old_value);
4139 : } else {
4140 2160984 : value = handle(object->RawFastPropertyAt(index), isolate);
4141 2160984 : if (details.representation().IsDouble()) {
4142 : DCHECK(value->IsMutableHeapNumber());
4143 : Handle<HeapNumber> old = Handle<HeapNumber>::cast(value);
4144 : value = isolate->factory()->NewHeapNumber(old->value());
4145 : }
4146 : }
4147 : } else {
4148 : DCHECK_EQ(kAccessor, details.kind());
4149 0 : value = handle(object->RawFastPropertyAt(index), isolate);
4150 : }
4151 :
4152 : } else {
4153 : DCHECK_EQ(kDescriptor, details.location());
4154 : value = handle(descs->GetValue(i), isolate);
4155 : }
4156 : DCHECK(!value.is_null());
4157 : PropertyDetails d(details.kind(), details.attributes(),
4158 : PropertyCellType::kNoCell);
4159 3042173 : dictionary = NameDictionary::Add(dictionary, key, value, d);
4160 : }
4161 :
4162 : // Copy the next enumeration index from instance descriptor.
4163 918333 : dictionary->SetNextEnumerationIndex(real_size + 1);
4164 :
4165 : // From here on we cannot fail and we shouldn't GC anymore.
4166 : DisallowHeapAllocation no_allocation;
4167 :
4168 918333 : Heap* heap = isolate->heap();
4169 : int old_instance_size = map->instance_size();
4170 918333 : heap->NotifyObjectLayoutChange(*object, old_instance_size, no_allocation);
4171 :
4172 : // Resize the object in the heap if necessary.
4173 : int new_instance_size = new_map->instance_size();
4174 918333 : int instance_size_delta = old_instance_size - new_instance_size;
4175 : DCHECK_GE(instance_size_delta, 0);
4176 :
4177 918333 : if (instance_size_delta > 0) {
4178 344814 : heap->CreateFillerObjectAt(object->address() + new_instance_size,
4179 344814 : instance_size_delta, ClearRecordedSlots::kYes);
4180 : }
4181 :
4182 : // We are storing the new map using release store after creating a filler for
4183 : // the left-over space to avoid races with the sweeper thread.
4184 918333 : object->synchronized_set_map(*new_map);
4185 :
4186 918333 : object->SetProperties(*dictionary);
4187 :
4188 : // Ensure that in-object space of slow-mode object does not contain random
4189 : // garbage.
4190 : int inobject_properties = new_map->GetInObjectProperties();
4191 918333 : if (inobject_properties) {
4192 : Heap* heap = isolate->heap();
4193 : heap->ClearRecordedSlotRange(
4194 323672 : object->address() + map->GetInObjectPropertyOffset(0),
4195 647344 : object->address() + new_instance_size);
4196 :
4197 1778845 : for (int i = 0; i < inobject_properties; i++) {
4198 1455173 : FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
4199 1455173 : object->RawFastPropertyAtPut(index, Smi::kZero);
4200 : }
4201 : }
4202 :
4203 918333 : isolate->counters()->props_to_dictionary()->Increment();
4204 :
4205 : #ifdef DEBUG
4206 : if (FLAG_trace_normalization) {
4207 : OFStream os(stdout);
4208 : os << "Object properties have been normalized:\n";
4209 : object->Print(os);
4210 : }
4211 : #endif
4212 918333 : }
4213 :
4214 : } // namespace
4215 :
4216 : // static
4217 31368350 : void JSObject::NotifyMapChange(Handle<Map> old_map, Handle<Map> new_map,
4218 : Isolate* isolate) {
4219 62736700 : if (!old_map->is_prototype_map()) return;
4220 :
4221 : InvalidatePrototypeChains(*old_map);
4222 :
4223 : // If the map was registered with its prototype before, ensure that it
4224 : // registers with its new prototype now. This preserves the invariant that
4225 : // when a map on a prototype chain is registered with its prototype, then
4226 : // all prototypes further up the chain are also registered with their
4227 : // respective prototypes.
4228 3888596 : UpdatePrototypeUserRegistration(old_map, new_map, isolate);
4229 : }
4230 :
4231 39970952 : void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
4232 : int expected_additional_properties) {
4233 79941909 : if (object->map() == *new_map) return;
4234 : Handle<Map> old_map(object->map());
4235 30840086 : NotifyMapChange(old_map, new_map, new_map->GetIsolate());
4236 :
4237 30840088 : if (old_map->is_dictionary_map()) {
4238 : // For slow-to-fast migrations JSObject::MigrateSlowToFast()
4239 : // must be used instead.
4240 584899 : CHECK(new_map->is_dictionary_map());
4241 :
4242 : // Slow-to-slow migration is trivial.
4243 584899 : object->synchronized_set_map(*new_map);
4244 30255189 : } else if (!new_map->is_dictionary_map()) {
4245 29336856 : MigrateFastToFast(object, new_map);
4246 29336859 : if (old_map->is_prototype_map()) {
4247 : DCHECK(!old_map->is_stable());
4248 : DCHECK(new_map->is_stable());
4249 : DCHECK(new_map->owns_descriptors());
4250 : DCHECK(old_map->owns_descriptors());
4251 : // Transfer ownership to the new map. Keep the descriptor pointer of the
4252 : // old map intact because the concurrent marker might be iterating the
4253 : // object with the old map.
4254 : old_map->set_owns_descriptors(false);
4255 : DCHECK(old_map->is_abandoned_prototype_map());
4256 : // Ensure that no transition was inserted for prototype migrations.
4257 : DCHECK_EQ(0, TransitionsAccessor(old_map).NumberOfTransitions());
4258 : DCHECK(new_map->GetBackPointer()->IsUndefined(new_map->GetIsolate()));
4259 : DCHECK(object->map() != *old_map);
4260 : }
4261 : } else {
4262 918333 : MigrateFastToSlow(object, new_map, expected_additional_properties);
4263 : }
4264 :
4265 : // Careful: Don't allocate here!
4266 : // For some callers of this method, |object| might be in an inconsistent
4267 : // state now: the new map might have a new elements_kind, but the object's
4268 : // elements pointer hasn't been updated yet. Callers will fix this, but in
4269 : // the meantime, (indirectly) calling JSObjectVerify() must be avoided.
4270 : // When adding code here, add a DisallowHeapAllocation too.
4271 : }
4272 :
4273 180568 : void JSObject::ForceSetPrototype(Handle<JSObject> object,
4274 : Handle<Object> proto) {
4275 : // object.__proto__ = proto;
4276 : Handle<Map> old_map = Handle<Map>(object->map());
4277 180568 : Handle<Map> new_map = Map::Copy(old_map, "ForceSetPrototype");
4278 180568 : Map::SetPrototype(new_map, proto);
4279 180568 : JSObject::MigrateToMap(object, new_map);
4280 180568 : }
4281 :
4282 43208621 : int Map::NumberOfFields() const {
4283 : DescriptorArray* descriptors = instance_descriptors();
4284 : int result = 0;
4285 645738662 : for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
4286 559321415 : if (descriptors->GetDetails(i).location() == kField) result++;
4287 : }
4288 43208626 : return result;
4289 : }
4290 :
4291 4827989 : void DescriptorArray::GeneralizeAllFields() {
4292 : int length = number_of_descriptors();
4293 13215663 : for (int i = 0; i < length; i++) {
4294 3559685 : PropertyDetails details = GetDetails(i);
4295 : details = details.CopyWithRepresentation(Representation::Tagged());
4296 3559685 : if (details.location() == kField) {
4297 : DCHECK_EQ(kData, details.kind());
4298 : details = details.CopyWithConstness(kMutable);
4299 142549 : SetValue(i, FieldType::Any());
4300 : }
4301 : set(ToDetailsIndex(i), details.AsSmi());
4302 : }
4303 4827989 : }
4304 :
4305 18130 : Handle<Map> Map::CopyGeneralizeAllFields(Handle<Map> map,
4306 : ElementsKind elements_kind,
4307 : int modify_index, PropertyKind kind,
4308 : PropertyAttributes attributes,
4309 : const char* reason) {
4310 : Isolate* isolate = map->GetIsolate();
4311 : Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
4312 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
4313 : Handle<DescriptorArray> descriptors =
4314 : DescriptorArray::CopyUpTo(old_descriptors, number_of_own_descriptors);
4315 18130 : descriptors->GeneralizeAllFields();
4316 :
4317 : Handle<LayoutDescriptor> new_layout_descriptor(
4318 : LayoutDescriptor::FastPointerLayout(), isolate);
4319 : Handle<Map> new_map = CopyReplaceDescriptors(
4320 : map, descriptors, new_layout_descriptor, OMIT_TRANSITION,
4321 18130 : MaybeHandle<Name>(), reason, SPECIAL_TRANSITION);
4322 :
4323 : // Unless the instance is being migrated, ensure that modify_index is a field.
4324 18130 : if (modify_index >= 0) {
4325 18046 : PropertyDetails details = descriptors->GetDetails(modify_index);
4326 20142 : if (details.constness() != kMutable || details.location() != kField ||
4327 : details.attributes() != attributes) {
4328 : int field_index = details.location() == kField
4329 : ? details.field_index()
4330 34269 : : new_map->NumberOfFields();
4331 : Descriptor d = Descriptor::DataField(
4332 : handle(descriptors->GetKey(modify_index), isolate), field_index,
4333 17271 : attributes, Representation::Tagged());
4334 17271 : descriptors->Replace(modify_index, &d);
4335 17271 : if (details.location() != kField) {
4336 16998 : new_map->AccountAddedPropertyField();
4337 : }
4338 : } else {
4339 : DCHECK(details.attributes() == attributes);
4340 : }
4341 :
4342 18046 : if (FLAG_trace_generalization) {
4343 0 : MaybeHandle<FieldType> field_type = FieldType::None(isolate);
4344 0 : if (details.location() == kField) {
4345 : field_type = handle(
4346 0 : map->instance_descriptors()->GetFieldType(modify_index), isolate);
4347 : }
4348 : map->PrintGeneralization(
4349 : stdout, reason, modify_index, new_map->NumberOfOwnDescriptors(),
4350 : new_map->NumberOfOwnDescriptors(), details.location() == kDescriptor,
4351 : details.representation(), Representation::Tagged(), field_type,
4352 : MaybeHandle<Object>(), FieldType::Any(isolate),
4353 0 : MaybeHandle<Object>());
4354 : }
4355 : }
4356 : new_map->set_elements_kind(elements_kind);
4357 18130 : return new_map;
4358 : }
4359 :
4360 58549 : void Map::DeprecateTransitionTree() {
4361 58549 : if (is_deprecated()) return;
4362 : DisallowHeapAllocation no_gc;
4363 : TransitionsAccessor transitions(this, &no_gc);
4364 58549 : int num_transitions = transitions.NumberOfTransitions();
4365 93897 : for (int i = 0; i < num_transitions; ++i) {
4366 35348 : transitions.GetTarget(i)->DeprecateTransitionTree();
4367 : }
4368 : DCHECK(!constructor_or_backpointer()->IsFunctionTemplateInfo());
4369 : deprecate();
4370 : dependent_code()->DeoptimizeDependentCodeGroup(
4371 58549 : GetIsolate(), DependentCode::kTransitionGroup);
4372 58549 : NotifyLeafMapLayoutChange();
4373 : }
4374 :
4375 :
4376 : // Installs |new_descriptors| over the current instance_descriptors to ensure
4377 : // proper sharing of descriptor arrays.
4378 24825 : void Map::ReplaceDescriptors(DescriptorArray* new_descriptors,
4379 : LayoutDescriptor* new_layout_descriptor) {
4380 : Isolate* isolate = GetIsolate();
4381 : // Don't overwrite the empty descriptor array or initial map's descriptors.
4382 36552 : if (NumberOfOwnDescriptors() == 0 || GetBackPointer()->IsUndefined(isolate)) {
4383 24825 : return;
4384 : }
4385 :
4386 : DescriptorArray* to_replace = instance_descriptors();
4387 : // Replace descriptors by new_descriptors in all maps that share it. The old
4388 : // descriptors will not be trimmed in the mark-compactor, we need to mark
4389 : // all its elements.
4390 11444 : isolate->heap()->incremental_marking()->RecordWrites(to_replace);
4391 : Map* current = this;
4392 74888 : while (current->instance_descriptors() == to_replace) {
4393 52337 : Object* next = current->GetBackPointer();
4394 52337 : if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map.
4395 : current->SetEnumLength(kInvalidEnumCacheSentinel);
4396 52000 : current->UpdateDescriptors(new_descriptors, new_layout_descriptor);
4397 : current = Map::cast(next);
4398 : }
4399 : set_owns_descriptors(false);
4400 : }
4401 :
4402 1031085 : Map* Map::FindRootMap() const {
4403 : const Map* result = this;
4404 : Isolate* isolate = GetIsolate();
4405 : while (true) {
4406 1368783 : Object* back = result->GetBackPointer();
4407 1368783 : if (back->IsUndefined(isolate)) {
4408 : // Initial map always owns descriptors and doesn't have unused entries
4409 : // in the descriptor array.
4410 : DCHECK(result->owns_descriptors());
4411 : DCHECK_EQ(result->NumberOfOwnDescriptors(),
4412 : result->instance_descriptors()->number_of_descriptors());
4413 1031085 : return const_cast<Map*>(result);
4414 : }
4415 : result = Map::cast(back);
4416 : }
4417 : }
4418 :
4419 591053 : Map* Map::FindFieldOwner(int descriptor) const {
4420 : DisallowHeapAllocation no_allocation;
4421 : DCHECK_EQ(kField, instance_descriptors()->GetDetails(descriptor).location());
4422 : const Map* result = this;
4423 : Isolate* isolate = GetIsolate();
4424 : while (true) {
4425 2139829 : Object* back = result->GetBackPointer();
4426 2139829 : if (back->IsUndefined(isolate)) break;
4427 : const Map* parent = Map::cast(back);
4428 2043763 : if (parent->NumberOfOwnDescriptors() <= descriptor) break;
4429 : result = parent;
4430 : }
4431 591053 : return const_cast<Map*>(result);
4432 : }
4433 :
4434 311973 : void Map::UpdateFieldType(int descriptor, Handle<Name> name,
4435 : PropertyConstness new_constness,
4436 : Representation new_representation,
4437 : Handle<Object> new_wrapped_type) {
4438 : DCHECK(new_wrapped_type->IsSmi() || new_wrapped_type->IsWeakCell());
4439 : // We store raw pointers in the queue, so no allocations are allowed.
4440 : DisallowHeapAllocation no_allocation;
4441 311973 : PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
4442 311973 : if (details.location() != kField) return;
4443 : DCHECK_EQ(kData, details.kind());
4444 :
4445 311973 : Zone zone(GetIsolate()->allocator(), ZONE_NAME);
4446 311973 : ZoneQueue<Map*> backlog(&zone);
4447 623946 : backlog.push(this);
4448 :
4449 2501385 : while (!backlog.empty()) {
4450 1877439 : Map* current = backlog.front();
4451 : backlog.pop();
4452 :
4453 : TransitionsAccessor transitions(current, &no_allocation);
4454 1877439 : int num_transitions = transitions.NumberOfTransitions();
4455 3442905 : for (int i = 0; i < num_transitions; ++i) {
4456 1565466 : Map* target = transitions.GetTarget(i);
4457 : backlog.push(target);
4458 : }
4459 : DescriptorArray* descriptors = current->instance_descriptors();
4460 1877439 : PropertyDetails details = descriptors->GetDetails(descriptor);
4461 :
4462 : // Currently constness change implies map change.
4463 : DCHECK_IMPLIES(new_constness != details.constness(),
4464 : FLAG_modify_map_inplace);
4465 :
4466 : // It is allowed to change representation here only from None to something.
4467 : DCHECK(details.representation().Equals(new_representation) ||
4468 : details.representation().IsNone());
4469 :
4470 : // Skip if already updated the shared descriptor.
4471 1877439 : if ((FLAG_modify_map_inplace && new_constness != details.constness()) ||
4472 : descriptors->GetValue(descriptor) != *new_wrapped_type) {
4473 : DCHECK_IMPLIES(!FLAG_track_constant_fields, new_constness == kMutable);
4474 : Descriptor d = Descriptor::DataField(
4475 : name, descriptors->GetFieldIndex(descriptor), details.attributes(),
4476 312021 : new_constness, new_representation, new_wrapped_type);
4477 312021 : descriptors->Replace(descriptor, &d);
4478 : }
4479 311973 : }
4480 : }
4481 :
4482 0 : bool FieldTypeIsCleared(Representation rep, FieldType* type) {
4483 1733161 : return type->IsNone() && rep.IsHeapObject();
4484 : }
4485 :
4486 :
4487 : // static
4488 762537 : Handle<FieldType> Map::GeneralizeFieldType(Representation rep1,
4489 : Handle<FieldType> type1,
4490 : Representation rep2,
4491 : Handle<FieldType> type2,
4492 : Isolate* isolate) {
4493 : // Cleared field types need special treatment. They represent lost knowledge,
4494 : // so we must be conservative, so their generalization with any other type
4495 : // is "Any".
4496 1524958 : if (FieldTypeIsCleared(rep1, *type1) || FieldTypeIsCleared(rep2, *type2)) {
4497 6153 : return FieldType::Any(isolate);
4498 : }
4499 756384 : if (type1->NowIs(type2)) return type2;
4500 42472 : if (type2->NowIs(type1)) return type1;
4501 20098 : return FieldType::Any(isolate);
4502 : }
4503 :
4504 : // static
4505 475511 : void Map::GeneralizeField(Handle<Map> map, int modify_index,
4506 : PropertyConstness new_constness,
4507 : Representation new_representation,
4508 : Handle<FieldType> new_field_type) {
4509 : Isolate* isolate = map->GetIsolate();
4510 :
4511 : // Check if we actually need to generalize the field type at all.
4512 : Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
4513 475511 : PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
4514 : PropertyConstness old_constness = old_details.constness();
4515 : Representation old_representation = old_details.representation();
4516 : Handle<FieldType> old_field_type(old_descriptors->GetFieldType(modify_index),
4517 475511 : isolate);
4518 :
4519 : // Return if the current map is general enough to hold requested contness and
4520 : // representation/field type.
4521 475511 : if (((FLAG_modify_map_inplace &&
4522 : IsGeneralizableTo(new_constness, old_constness)) ||
4523 475511 : (!FLAG_modify_map_inplace && (old_constness == new_constness))) &&
4524 197943 : old_representation.Equals(new_representation) &&
4525 673435 : !FieldTypeIsCleared(new_representation, *new_field_type) &&
4526 : // Checking old_field_type for being cleared is not necessary because
4527 : // the NowIs check below would fail anyway in that case.
4528 197924 : new_field_type->NowIs(old_field_type)) {
4529 : DCHECK(GeneralizeFieldType(old_representation, old_field_type,
4530 : new_representation, new_field_type, isolate)
4531 : ->NowIs(old_field_type));
4532 163538 : return;
4533 : }
4534 :
4535 : // Determine the field owner.
4536 311973 : Handle<Map> field_owner(map->FindFieldOwner(modify_index), isolate);
4537 : Handle<DescriptorArray> descriptors(field_owner->instance_descriptors(),
4538 : isolate);
4539 : DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index));
4540 :
4541 : new_field_type =
4542 : Map::GeneralizeFieldType(old_representation, old_field_type,
4543 311973 : new_representation, new_field_type, isolate);
4544 : if (FLAG_modify_map_inplace) {
4545 : new_constness = GeneralizeConstness(old_constness, new_constness);
4546 : }
4547 :
4548 311973 : PropertyDetails details = descriptors->GetDetails(modify_index);
4549 : Handle<Name> name(descriptors->GetKey(modify_index));
4550 :
4551 311973 : Handle<Object> wrapped_type(WrapFieldType(new_field_type));
4552 : field_owner->UpdateFieldType(modify_index, name, new_constness,
4553 311973 : new_representation, wrapped_type);
4554 : field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
4555 311973 : isolate, DependentCode::kFieldOwnerGroup);
4556 :
4557 311973 : if (FLAG_trace_generalization) {
4558 : map->PrintGeneralization(
4559 : stdout, "field type generalization", modify_index,
4560 : map->NumberOfOwnDescriptors(), map->NumberOfOwnDescriptors(), false,
4561 : details.representation(), details.representation(), old_field_type,
4562 0 : MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>());
4563 : }
4564 : }
4565 :
4566 : // TODO(ishell): remove.
4567 : // static
4568 497 : Handle<Map> Map::ReconfigureProperty(Handle<Map> map, int modify_index,
4569 : PropertyKind new_kind,
4570 : PropertyAttributes new_attributes,
4571 : Representation new_representation,
4572 : Handle<FieldType> new_field_type) {
4573 : DCHECK_EQ(kData, new_kind); // Only kData case is supported.
4574 497 : MapUpdater mu(map->GetIsolate(), map);
4575 : return mu.ReconfigureToDataField(modify_index, new_attributes, kConst,
4576 497 : new_representation, new_field_type);
4577 : }
4578 :
4579 : // TODO(ishell): remove.
4580 : // static
4581 427557 : Handle<Map> Map::ReconfigureElementsKind(Handle<Map> map,
4582 : ElementsKind new_elements_kind) {
4583 427557 : MapUpdater mu(map->GetIsolate(), map);
4584 427557 : return mu.ReconfigureElementsKind(new_elements_kind);
4585 : }
4586 :
4587 : // Generalize all fields and update the transition tree.
4588 35095 : Handle<Map> Map::GeneralizeAllFields(Handle<Map> map) {
4589 : Isolate* isolate = map->GetIsolate();
4590 35095 : Handle<FieldType> any_type = FieldType::Any(isolate);
4591 :
4592 : Handle<DescriptorArray> descriptors(map->instance_descriptors());
4593 97154 : for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) {
4594 13482 : PropertyDetails details = descriptors->GetDetails(i);
4595 13482 : if (details.location() == kField) {
4596 : DCHECK_EQ(kData, details.kind());
4597 1326 : MapUpdater mu(isolate, map);
4598 : map = mu.ReconfigureToDataField(i, details.attributes(), kMutable,
4599 1326 : Representation::Tagged(), any_type);
4600 : }
4601 : }
4602 35095 : return map;
4603 : }
4604 :
4605 :
4606 : // static
4607 160915 : MaybeHandle<Map> Map::TryUpdate(Handle<Map> old_map) {
4608 : DisallowHeapAllocation no_allocation;
4609 : DisallowDeoptimization no_deoptimization(old_map->GetIsolate());
4610 :
4611 160915 : if (!old_map->is_deprecated()) return old_map;
4612 :
4613 : // Check the state of the root map.
4614 4169 : Map* root_map = old_map->FindRootMap();
4615 4169 : if (root_map->is_deprecated()) {
4616 0 : JSFunction* constructor = JSFunction::cast(root_map->GetConstructor());
4617 : DCHECK(constructor->has_initial_map());
4618 : DCHECK(constructor->initial_map()->is_dictionary_map());
4619 0 : if (constructor->initial_map()->elements_kind() !=
4620 : old_map->elements_kind()) {
4621 0 : return MaybeHandle<Map>();
4622 : }
4623 0 : return handle(constructor->initial_map());
4624 : }
4625 4169 : if (!old_map->EquivalentToForTransition(root_map)) return MaybeHandle<Map>();
4626 :
4627 : ElementsKind from_kind = root_map->elements_kind();
4628 : ElementsKind to_kind = old_map->elements_kind();
4629 4099 : if (from_kind != to_kind) {
4630 : // Try to follow existing elements kind transitions.
4631 : root_map = root_map->LookupElementsTransitionMap(to_kind);
4632 8 : if (root_map == nullptr) return MaybeHandle<Map>();
4633 : // From here on, use the map with correct elements kind as root map.
4634 : }
4635 4099 : Map* new_map = root_map->TryReplayPropertyTransitions(*old_map);
4636 4099 : if (new_map == nullptr) return MaybeHandle<Map>();
4637 4081 : return handle(new_map);
4638 : }
4639 :
4640 100422 : Map* Map::TryReplayPropertyTransitions(Map* old_map) {
4641 : DisallowHeapAllocation no_allocation;
4642 : DisallowDeoptimization no_deoptimization(GetIsolate());
4643 :
4644 : int root_nof = NumberOfOwnDescriptors();
4645 :
4646 : int old_nof = old_map->NumberOfOwnDescriptors();
4647 : DescriptorArray* old_descriptors = old_map->instance_descriptors();
4648 :
4649 : Map* new_map = this;
4650 105748 : for (int i = root_nof; i < old_nof; ++i) {
4651 9576 : PropertyDetails old_details = old_descriptors->GetDetails(i);
4652 : Map* transition =
4653 : TransitionsAccessor(new_map, &no_allocation)
4654 : .SearchTransition(old_descriptors->GetKey(i), old_details.kind(),
4655 9576 : old_details.attributes());
4656 9576 : if (transition == nullptr) return nullptr;
4657 : new_map = transition;
4658 : DescriptorArray* new_descriptors = new_map->instance_descriptors();
4659 :
4660 5381 : PropertyDetails new_details = new_descriptors->GetDetails(i);
4661 : DCHECK_EQ(old_details.kind(), new_details.kind());
4662 : DCHECK_EQ(old_details.attributes(), new_details.attributes());
4663 5381 : if (!IsGeneralizableTo(old_details.constness(), new_details.constness())) {
4664 : return nullptr;
4665 : }
4666 : DCHECK(IsGeneralizableTo(old_details.location(), new_details.location()));
4667 16143 : if (!old_details.representation().fits_into(new_details.representation())) {
4668 : return nullptr;
4669 : }
4670 5336 : if (new_details.location() == kField) {
4671 5210 : if (new_details.kind() == kData) {
4672 5210 : FieldType* new_type = new_descriptors->GetFieldType(i);
4673 : // Cleared field types need special treatment. They represent lost
4674 : // knowledge, so we must first generalize the new_type to "Any".
4675 5210 : if (FieldTypeIsCleared(new_details.representation(), new_type)) {
4676 : return nullptr;
4677 : }
4678 : DCHECK_EQ(kData, old_details.kind());
4679 5210 : if (old_details.location() == kField) {
4680 5050 : FieldType* old_type = old_descriptors->GetFieldType(i);
4681 10100 : if (FieldTypeIsCleared(old_details.representation(), old_type) ||
4682 5050 : !old_type->NowIs(new_type)) {
4683 : return nullptr;
4684 : }
4685 : } else {
4686 : DCHECK_EQ(kDescriptor, old_details.location());
4687 : DCHECK(!FLAG_track_constant_fields);
4688 : Object* old_value = old_descriptors->GetValue(i);
4689 160 : if (!new_type->NowContains(old_value)) {
4690 : return nullptr;
4691 : }
4692 : }
4693 :
4694 : } else {
4695 : DCHECK_EQ(kAccessor, new_details.kind());
4696 : #ifdef DEBUG
4697 : FieldType* new_type = new_descriptors->GetFieldType(i);
4698 : DCHECK(new_type->IsAny());
4699 : #endif
4700 0 : UNREACHABLE();
4701 : }
4702 : } else {
4703 : DCHECK_EQ(kDescriptor, new_details.location());
4704 : Object* old_value = old_descriptors->GetValue(i);
4705 : Object* new_value = new_descriptors->GetValue(i);
4706 126 : if (old_details.location() == kField || old_value != new_value) {
4707 : return nullptr;
4708 : }
4709 : }
4710 : }
4711 96172 : if (new_map->NumberOfOwnDescriptors() != old_nof) return nullptr;
4712 96172 : return new_map;
4713 : }
4714 :
4715 :
4716 : // static
4717 26982874 : Handle<Map> Map::Update(Handle<Map> map) {
4718 26982874 : if (!map->is_deprecated()) return map;
4719 4167 : MapUpdater mu(map->GetIsolate(), map);
4720 4167 : return mu.Update();
4721 : }
4722 :
4723 193402 : Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
4724 : ShouldThrow should_throw,
4725 : Handle<Object> value) {
4726 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
4727 : return SetPropertyWithInterceptorInternal(it, it->GetInterceptor(),
4728 193402 : should_throw, value);
4729 : }
4730 :
4731 3152772 : MaybeHandle<Object> Object::SetProperty(Handle<Object> object,
4732 : Handle<Name> name, Handle<Object> value,
4733 : LanguageMode language_mode,
4734 : StoreFromKeyed store_mode) {
4735 3152772 : LookupIterator it(object, name);
4736 3152772 : MAYBE_RETURN_NULL(SetProperty(&it, value, language_mode, store_mode));
4737 3152680 : return value;
4738 : }
4739 :
4740 :
4741 20091656 : Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
4742 : Handle<Object> value,
4743 : LanguageMode language_mode,
4744 : StoreFromKeyed store_mode,
4745 : bool* found) {
4746 9841084 : it->UpdateProtector();
4747 : DCHECK(it->IsFound());
4748 : ShouldThrow should_throw =
4749 9841084 : is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4750 :
4751 : // Make sure that the top context does not change when doing callbacks or
4752 : // interceptor calls.
4753 : AssertNoContextChange ncc(it->isolate());
4754 :
4755 266180 : do {
4756 9984392 : switch (it->state()) {
4757 : case LookupIterator::NOT_FOUND:
4758 0 : UNREACHABLE();
4759 :
4760 : case LookupIterator::ACCESS_CHECK:
4761 73273 : if (it->HasAccess()) break;
4762 : // Check whether it makes sense to reuse the lookup iterator. Here it
4763 : // might still call into setters up the prototype chain.
4764 : return JSObject::SetPropertyWithFailedAccessCheck(it, value,
4765 105 : should_throw);
4766 :
4767 : case LookupIterator::JSPROXY:
4768 : return JSProxy::SetProperty(it->GetHolder<JSProxy>(), it->GetName(),
4769 41571 : value, it->GetReceiver(), language_mode);
4770 :
4771 : case LookupIterator::INTERCEPTOR: {
4772 202423 : if (it->HolderIsReceiverOrHiddenPrototype()) {
4773 : Maybe<bool> result =
4774 193182 : JSObject::SetPropertyWithInterceptor(it, should_throw, value);
4775 386364 : if (result.IsNothing() || result.FromJust()) return result;
4776 : } else {
4777 : Maybe<PropertyAttributes> maybe_attributes =
4778 9241 : JSObject::GetPropertyAttributesWithInterceptor(it);
4779 18384 : if (!maybe_attributes.IsJust()) return Nothing<bool>();
4780 9241 : if ((maybe_attributes.FromJust() & READ_ONLY) != 0) {
4781 0 : return WriteToReadOnlyProperty(it, value, should_throw);
4782 : }
4783 9241 : if (maybe_attributes.FromJust() == ABSENT) break;
4784 9143 : *found = false;
4785 : return Nothing<bool>();
4786 : }
4787 : break;
4788 : }
4789 :
4790 : case LookupIterator::ACCESSOR: {
4791 529489 : if (it->IsReadOnly()) {
4792 1585 : return WriteToReadOnlyProperty(it, value, should_throw);
4793 : }
4794 527904 : Handle<Object> accessors = it->GetAccessors();
4795 777782 : if (accessors->IsAccessorInfo() &&
4796 648640 : !it->HolderIsReceiverOrHiddenPrototype() &&
4797 : AccessorInfo::cast(*accessors)->is_special_data_property()) {
4798 498 : *found = false;
4799 : return Nothing<bool>();
4800 : }
4801 527406 : return SetPropertyWithAccessor(it, value, should_throw);
4802 : }
4803 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
4804 : // TODO(verwaest): We should throw an exception if holder is receiver.
4805 : return Just(true);
4806 :
4807 : case LookupIterator::DATA:
4808 8531821 : if (it->IsReadOnly()) {
4809 29553 : return WriteToReadOnlyProperty(it, value, should_throw);
4810 : }
4811 8502268 : if (it->HolderIsReceiverOrHiddenPrototype()) {
4812 8396852 : return SetDataProperty(it, value);
4813 : }
4814 : // Fall through.
4815 : case LookupIterator::TRANSITION:
4816 709033 : *found = false;
4817 : return Nothing<bool>();
4818 : }
4819 266180 : it->Next();
4820 : } while (it->IsFound());
4821 :
4822 122872 : *found = false;
4823 : return Nothing<bool>();
4824 : }
4825 :
4826 :
4827 20851320 : Maybe<bool> Object::SetProperty(LookupIterator* it, Handle<Object> value,
4828 : LanguageMode language_mode,
4829 : StoreFromKeyed store_mode) {
4830 20850084 : if (it->IsFound()) {
4831 9795993 : bool found = true;
4832 : Maybe<bool> result =
4833 9795993 : SetPropertyInternal(it, value, language_mode, store_mode, &found);
4834 9795993 : if (found) return result;
4835 : }
4836 :
4837 : // If the receiver is the JSGlobalObject, the store was contextual. In case
4838 : // the property did not exist yet on the global object itself, we have to
4839 : // throw a reference error in strict mode. In sloppy mode, we continue.
4840 19802574 : if (is_strict(language_mode) && it->GetReceiver()->IsJSGlobalObject()) {
4841 : it->isolate()->Throw(*it->isolate()->factory()->NewReferenceError(
4842 1236 : MessageTemplate::kNotDefined, it->name()));
4843 : return Nothing<bool>();
4844 : }
4845 :
4846 : ShouldThrow should_throw =
4847 11892817 : is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4848 11892817 : return AddDataProperty(it, value, NONE, should_throw, store_mode);
4849 : }
4850 :
4851 :
4852 54822 : Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
4853 : LanguageMode language_mode,
4854 : StoreFromKeyed store_mode) {
4855 : Isolate* isolate = it->isolate();
4856 :
4857 49220 : if (it->IsFound()) {
4858 45091 : bool found = true;
4859 : Maybe<bool> result =
4860 45091 : SetPropertyInternal(it, value, language_mode, store_mode, &found);
4861 45091 : if (found) return result;
4862 : }
4863 :
4864 6331 : it->UpdateProtector();
4865 :
4866 : // The property either doesn't exist on the holder or exists there as a data
4867 : // property.
4868 :
4869 : ShouldThrow should_throw =
4870 6331 : is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4871 :
4872 6331 : if (!it->GetReceiver()->IsJSReceiver()) {
4873 729 : return WriteToReadOnlyProperty(it, value, should_throw);
4874 : }
4875 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
4876 :
4877 : LookupIterator::Configuration c = LookupIterator::OWN;
4878 : LookupIterator own_lookup =
4879 : it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c)
4880 11204 : : LookupIterator(receiver, it->name(), c);
4881 :
4882 28 : for (; own_lookup.IsFound(); own_lookup.Next()) {
4883 4221 : switch (own_lookup.state()) {
4884 : case LookupIterator::ACCESS_CHECK:
4885 33 : if (!own_lookup.HasAccess()) {
4886 : return JSObject::SetPropertyWithFailedAccessCheck(&own_lookup, value,
4887 5 : should_throw);
4888 : }
4889 : break;
4890 :
4891 : case LookupIterator::ACCESSOR:
4892 1962 : if (own_lookup.GetAccessors()->IsAccessorInfo()) {
4893 9 : if (own_lookup.IsReadOnly()) {
4894 0 : return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
4895 : }
4896 : return JSObject::SetPropertyWithAccessor(&own_lookup, value,
4897 9 : should_throw);
4898 : }
4899 : // Fall through.
4900 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
4901 : return RedefineIncompatibleProperty(isolate, it->GetName(), value,
4902 1944 : should_throw);
4903 :
4904 : case LookupIterator::DATA: {
4905 981 : if (own_lookup.IsReadOnly()) {
4906 297 : return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
4907 : }
4908 684 : return SetDataProperty(&own_lookup, value);
4909 : }
4910 :
4911 : case LookupIterator::INTERCEPTOR:
4912 : case LookupIterator::JSPROXY: {
4913 : PropertyDescriptor desc;
4914 : Maybe<bool> owned =
4915 2226 : JSReceiver::GetOwnPropertyDescriptor(&own_lookup, &desc);
4916 2226 : MAYBE_RETURN(owned, Nothing<bool>());
4917 1776 : if (!owned.FromJust()) {
4918 : return JSReceiver::CreateDataProperty(&own_lookup, value,
4919 871 : should_throw);
4920 : }
4921 1810 : if (PropertyDescriptor::IsAccessorDescriptor(&desc) ||
4922 : !desc.writable()) {
4923 : return RedefineIncompatibleProperty(isolate, it->GetName(), value,
4924 0 : should_throw);
4925 : }
4926 :
4927 : PropertyDescriptor value_desc;
4928 : value_desc.set_value(value);
4929 : return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
4930 1810 : &value_desc, should_throw);
4931 : }
4932 :
4933 : case LookupIterator::NOT_FOUND:
4934 : case LookupIterator::TRANSITION:
4935 0 : UNREACHABLE();
4936 : }
4937 : }
4938 :
4939 1409 : return AddDataProperty(&own_lookup, value, NONE, should_throw, store_mode);
4940 : }
4941 :
4942 6223 : Maybe<bool> Object::CannotCreateProperty(Isolate* isolate,
4943 : Handle<Object> receiver,
4944 : Handle<Object> name,
4945 : Handle<Object> value,
4946 : ShouldThrow should_throw) {
4947 6469 : RETURN_FAILURE(
4948 : isolate, should_throw,
4949 : NewTypeError(MessageTemplate::kStrictCannotCreateProperty, name,
4950 : Object::TypeOf(isolate, receiver), receiver));
4951 : }
4952 :
4953 :
4954 64328 : Maybe<bool> Object::WriteToReadOnlyProperty(LookupIterator* it,
4955 : Handle<Object> value,
4956 : ShouldThrow should_throw) {
4957 : return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(),
4958 64328 : it->GetName(), value, should_throw);
4959 : }
4960 :
4961 :
4962 32164 : Maybe<bool> Object::WriteToReadOnlyProperty(Isolate* isolate,
4963 : Handle<Object> receiver,
4964 : Handle<Object> name,
4965 : Handle<Object> value,
4966 : ShouldThrow should_throw) {
4967 52532 : RETURN_FAILURE(isolate, should_throw,
4968 : NewTypeError(MessageTemplate::kStrictReadOnlyProperty, name,
4969 : Object::TypeOf(isolate, receiver), receiver));
4970 : }
4971 :
4972 :
4973 982 : Maybe<bool> Object::RedefineIncompatibleProperty(Isolate* isolate,
4974 : Handle<Object> name,
4975 : Handle<Object> value,
4976 : ShouldThrow should_throw) {
4977 1218 : RETURN_FAILURE(isolate, should_throw,
4978 : NewTypeError(MessageTemplate::kRedefineDisallowed, name));
4979 : }
4980 :
4981 :
4982 17469524 : Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) {
4983 : // Proxies are handled elsewhere. Other non-JSObjects cannot have own
4984 : // properties.
4985 : Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
4986 :
4987 : // Store on the holder which may be hidden behind the receiver.
4988 : DCHECK(it->HolderIsReceiverOrHiddenPrototype());
4989 :
4990 8733506 : Handle<Object> to_assign = value;
4991 : // Convert the incoming value to a number for storing into typed arrays.
4992 9613567 : if (it->IsElement() && receiver->HasFixedTypedArrayElements()) {
4993 745470 : if (!value->IsNumber() && !value->IsUndefined(it->isolate())) {
4994 3886 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4995 : it->isolate(), to_assign, Object::ToNumber(value), Nothing<bool>());
4996 : // We have to recheck the length. However, it can only change if the
4997 : // underlying buffer was neutered, so just check that.
4998 1943 : if (Handle<JSArrayBufferView>::cast(receiver)->WasNeutered()) {
4999 : return Just(true);
5000 : // TODO(neis): According to the spec, this should throw a TypeError.
5001 : }
5002 : }
5003 : }
5004 :
5005 : // Possibly migrate to the most up-to-date map that will be able to store
5006 : // |value| under it->name().
5007 8733506 : it->PrepareForDataProperty(to_assign);
5008 :
5009 : // Write the property value.
5010 8733506 : it->WriteDataValue(to_assign, false);
5011 :
5012 : #if VERIFY_HEAP
5013 : if (FLAG_verify_heap) {
5014 : receiver->JSObjectVerify();
5015 : }
5016 : #endif
5017 : return Just(true);
5018 : }
5019 :
5020 :
5021 134173622 : Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value,
5022 : PropertyAttributes attributes,
5023 : ShouldThrow should_throw,
5024 : StoreFromKeyed store_mode) {
5025 42223091 : if (!it->GetReceiver()->IsJSObject()) {
5026 6277 : if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate()) {
5027 45 : RETURN_FAILURE(it->isolate(), should_throw,
5028 : NewTypeError(MessageTemplate::kProxyPrivate));
5029 : }
5030 : return CannotCreateProperty(it->isolate(), it->GetReceiver(), it->GetName(),
5031 12446 : value, should_throw);
5032 : }
5033 :
5034 : DCHECK_NE(LookupIterator::INTEGER_INDEXED_EXOTIC, it->state());
5035 :
5036 42216841 : Handle<JSObject> receiver = it->GetStoreTarget();
5037 :
5038 : // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject)
5039 : // instead. If the prototype is Null, the proxy is detached.
5040 42216836 : if (receiver->IsJSGlobalProxy()) return Just(true);
5041 :
5042 : Isolate* isolate = it->isolate();
5043 :
5044 42216836 : if (it->ExtendingNonExtensible(receiver)) {
5045 404941 : RETURN_FAILURE(
5046 : isolate, should_throw,
5047 : NewTypeError(MessageTemplate::kObjectNotExtensible, it->GetName()));
5048 : }
5049 :
5050 42113418 : if (it->IsElement()) {
5051 5808117 : if (receiver->IsJSArray()) {
5052 : Handle<JSArray> array = Handle<JSArray>::cast(receiver);
5053 1806226 : if (JSArray::WouldChangeReadOnlyLength(array, it->index())) {
5054 1144 : RETURN_FAILURE(array->GetIsolate(), should_throw,
5055 : NewTypeError(MessageTemplate::kStrictReadOnlyProperty,
5056 : isolate->factory()->length_string(),
5057 : Object::TypeOf(isolate, array), array));
5058 : }
5059 :
5060 1805919 : if (FLAG_trace_external_array_abuse &&
5061 0 : array->HasFixedTypedArrayElements()) {
5062 0 : CheckArrayAbuse(array, "typed elements write", it->index(), true);
5063 : }
5064 :
5065 1805919 : if (FLAG_trace_js_array_abuse && !array->HasFixedTypedArrayElements()) {
5066 0 : CheckArrayAbuse(array, "elements write", it->index(), false);
5067 : }
5068 : }
5069 :
5070 : Maybe<bool> result = JSObject::AddDataElement(receiver, it->index(), value,
5071 5807810 : attributes, should_throw);
5072 : JSObject::ValidateElements(*receiver);
5073 5807810 : return result;
5074 : } else {
5075 36305301 : it->UpdateProtector();
5076 : // Migrate to the most up-to-date map that will be able to store |value|
5077 : // under it->name() with |attributes|.
5078 : it->PrepareTransitionToDataProperty(receiver, value, attributes,
5079 36305303 : store_mode);
5080 : DCHECK_EQ(LookupIterator::TRANSITION, it->state());
5081 36305303 : it->ApplyTransitionToDataProperty(receiver);
5082 :
5083 : // Write the property value.
5084 36305305 : it->WriteDataValue(value, true);
5085 :
5086 : #if VERIFY_HEAP
5087 : if (FLAG_verify_heap) {
5088 : receiver->JSObjectVerify();
5089 : }
5090 : #endif
5091 : }
5092 :
5093 : return Just(true);
5094 : }
5095 :
5096 :
5097 2416908 : void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
5098 : // Only supports adding slack to owned descriptors.
5099 : DCHECK(map->owns_descriptors());
5100 :
5101 : Handle<DescriptorArray> descriptors(map->instance_descriptors());
5102 : int old_size = map->NumberOfOwnDescriptors();
5103 2416908 : if (slack <= descriptors->NumberOfSlackDescriptors()) return;
5104 :
5105 : Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
5106 : descriptors, old_size, slack);
5107 :
5108 : DisallowHeapAllocation no_allocation;
5109 : // The descriptors are still the same, so keep the layout descriptor.
5110 : LayoutDescriptor* layout_descriptor = map->GetLayoutDescriptor();
5111 :
5112 2416908 : if (old_size == 0) {
5113 2385 : map->UpdateDescriptors(*new_descriptors, layout_descriptor);
5114 2385 : return;
5115 : }
5116 :
5117 : // If the source descriptors had an enum cache we copy it. This ensures
5118 : // that the maps to which we push the new descriptor array back can rely
5119 : // on a cache always being available once it is set. If the map has more
5120 : // enumerated descriptors than available in the original cache, the cache
5121 : // will be lazily replaced by the extended cache when needed.
5122 2414523 : new_descriptors->CopyEnumCacheFrom(*descriptors);
5123 :
5124 : Isolate* isolate = map->GetIsolate();
5125 : // Replace descriptors by new_descriptors in all maps that share it. The old
5126 : // descriptors will not be trimmed in the mark-compactor, we need to mark
5127 : // all its elements.
5128 2414523 : isolate->heap()->incremental_marking()->RecordWrites(*descriptors);
5129 :
5130 : Map* current = *map;
5131 24534985 : while (current->instance_descriptors() == *descriptors) {
5132 19706423 : Object* next = current->GetBackPointer();
5133 19706423 : if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map.
5134 19705939 : current->UpdateDescriptors(*new_descriptors, layout_descriptor);
5135 : current = Map::cast(next);
5136 : }
5137 2414523 : map->UpdateDescriptors(*new_descriptors, layout_descriptor);
5138 : }
5139 :
5140 : // static
5141 122721 : Handle<Map> Map::GetObjectCreateMap(Handle<HeapObject> prototype) {
5142 : Isolate* isolate = prototype->GetIsolate();
5143 : Handle<Map> map(isolate->native_context()->object_function()->initial_map(),
5144 245442 : isolate);
5145 122721 : if (map->prototype() == *prototype) return map;
5146 122702 : if (prototype->IsNull(isolate)) {
5147 368 : return isolate->slow_object_with_null_prototype_map();
5148 : }
5149 122334 : if (prototype->IsJSObject()) {
5150 : Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype);
5151 121603 : if (!js_prototype->map()->is_prototype_map()) {
5152 119045 : JSObject::OptimizeAsPrototype(js_prototype);
5153 : }
5154 : Handle<PrototypeInfo> info =
5155 121603 : Map::GetOrCreatePrototypeInfo(js_prototype, isolate);
5156 : // TODO(verwaest): Use inobject slack tracking for this map.
5157 121603 : if (info->HasObjectCreateMap()) {
5158 : map = handle(info->ObjectCreateMap(), isolate);
5159 : } else {
5160 121562 : map = Map::CopyInitialMap(map);
5161 121562 : Map::SetPrototype(map, prototype);
5162 121562 : PrototypeInfo::SetObjectCreateMap(info, map);
5163 : }
5164 121603 : return map;
5165 : }
5166 :
5167 731 : return Map::TransitionToPrototype(map, prototype);
5168 : }
5169 :
5170 : template <class T>
5171 46261 : static int AppendUniqueCallbacks(Handle<TemplateList> callbacks,
5172 : Handle<typename T::Array> array,
5173 : int valid_descriptors) {
5174 : int nof_callbacks = callbacks->length();
5175 :
5176 : Isolate* isolate = array->GetIsolate();
5177 : // Ensure the keys are unique names before writing them into the
5178 : // instance descriptor. Since it may cause a GC, it has to be done before we
5179 : // temporarily put the heap in an invalid state while appending descriptors.
5180 139066 : for (int i = 0; i < nof_callbacks; ++i) {
5181 : Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
5182 47053 : if (entry->name()->IsUniqueName()) continue;
5183 : Handle<String> key =
5184 : isolate->factory()->InternalizeString(
5185 46035 : Handle<String>(String::cast(entry->name())));
5186 46035 : entry->set_name(*key);
5187 : }
5188 :
5189 : // Fill in new callback descriptors. Process the callbacks from
5190 : // back to front so that the last callback with a given name takes
5191 : // precedence over previously added callbacks with that name.
5192 92805 : for (int i = nof_callbacks - 1; i >= 0; i--) {
5193 : Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
5194 : Handle<Name> key(Name::cast(entry->name()));
5195 : // Check if a descriptor with this name already exists before writing.
5196 46544 : if (!T::Contains(key, entry, valid_descriptors, array)) {
5197 0 : T::Insert(key, entry, valid_descriptors, array);
5198 46532 : valid_descriptors++;
5199 : }
5200 : }
5201 :
5202 46261 : return valid_descriptors;
5203 : }
5204 :
5205 : struct DescriptorArrayAppender {
5206 : typedef DescriptorArray Array;
5207 : static bool Contains(Handle<Name> key,
5208 : Handle<AccessorInfo> entry,
5209 : int valid_descriptors,
5210 : Handle<DescriptorArray> array) {
5211 : DisallowHeapAllocation no_gc;
5212 : return array->Search(*key, valid_descriptors) != DescriptorArray::kNotFound;
5213 : }
5214 0 : static void Insert(Handle<Name> key,
5215 : Handle<AccessorInfo> entry,
5216 : int valid_descriptors,
5217 : Handle<DescriptorArray> array) {
5218 : DisallowHeapAllocation no_gc;
5219 : Descriptor d =
5220 : Descriptor::AccessorConstant(key, entry, entry->property_attributes());
5221 0 : array->Append(&d);
5222 0 : }
5223 : };
5224 :
5225 :
5226 : struct FixedArrayAppender {
5227 : typedef FixedArray Array;
5228 46544 : static bool Contains(Handle<Name> key,
5229 : Handle<AccessorInfo> entry,
5230 : int valid_descriptors,
5231 : Handle<FixedArray> array) {
5232 523 : for (int i = 0; i < valid_descriptors; i++) {
5233 535 : if (*key == AccessorInfo::cast(array->get(i))->name()) return true;
5234 : }
5235 : return false;
5236 : }
5237 : static void Insert(Handle<Name> key,
5238 : Handle<AccessorInfo> entry,
5239 : int valid_descriptors,
5240 : Handle<FixedArray> array) {
5241 : DisallowHeapAllocation no_gc;
5242 46532 : array->set(valid_descriptors, *entry);
5243 : }
5244 : };
5245 :
5246 :
5247 0 : void Map::AppendCallbackDescriptors(Handle<Map> map,
5248 : Handle<Object> descriptors) {
5249 : int nof = map->NumberOfOwnDescriptors();
5250 : Handle<DescriptorArray> array(map->instance_descriptors());
5251 0 : Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors);
5252 : DCHECK_GE(array->NumberOfSlackDescriptors(), callbacks->length());
5253 0 : nof = AppendUniqueCallbacks<DescriptorArrayAppender>(callbacks, array, nof);
5254 : map->SetNumberOfOwnDescriptors(nof);
5255 0 : }
5256 :
5257 :
5258 46261 : int AccessorInfo::AppendUnique(Handle<Object> descriptors,
5259 : Handle<FixedArray> array,
5260 : int valid_descriptors) {
5261 46261 : Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors);
5262 : DCHECK_GE(array->length(), callbacks->length() + valid_descriptors);
5263 : return AppendUniqueCallbacks<FixedArrayAppender>(callbacks, array,
5264 46261 : valid_descriptors);
5265 : }
5266 :
5267 : static bool ContainsMap(MapHandles const& maps, Map* map) {
5268 : DCHECK_NOT_NULL(map);
5269 276348 : for (Handle<Map> current : maps) {
5270 212954 : if (!current.is_null() && *current == map) return true;
5271 : }
5272 : return false;
5273 : }
5274 :
5275 60196 : Map* Map::FindElementsKindTransitionedMap(MapHandles const& candidates) {
5276 : DisallowHeapAllocation no_allocation;
5277 : DisallowDeoptimization no_deoptimization(GetIsolate());
5278 :
5279 60196 : if (is_prototype_map()) return nullptr;
5280 :
5281 : ElementsKind kind = elements_kind();
5282 : bool packed = IsFastPackedElementsKind(kind);
5283 :
5284 : Map* transition = nullptr;
5285 59407 : if (IsTransitionableFastElementsKind(kind)) {
5286 : // Check the state of the root map.
5287 31825 : Map* root_map = FindRootMap();
5288 31825 : if (!EquivalentToForElementsKindTransition(root_map)) return nullptr;
5289 : root_map = root_map->LookupElementsTransitionMap(kind);
5290 : DCHECK_NOT_NULL(root_map);
5291 : // Starting from the next existing elements kind transition try to
5292 : // replay the property transitions that does not involve instance rewriting
5293 : // (ElementsTransitionAndStoreStub does not support that).
5294 256296 : for (root_map = root_map->ElementsTransitionMap();
5295 227070 : root_map != nullptr && root_map->has_fast_elements();
5296 : root_map = root_map->ElementsTransitionMap()) {
5297 96323 : Map* current = root_map->TryReplayPropertyTransitions(this);
5298 96323 : if (current == nullptr) continue;
5299 92091 : if (InstancesNeedRewriting(current)) continue;
5300 :
5301 184086 : if (ContainsMap(candidates, current) &&
5302 1672 : (packed || !IsFastPackedElementsKind(current->elements_kind()))) {
5303 : transition = current;
5304 26397 : packed = packed && IsFastPackedElementsKind(current->elements_kind());
5305 : }
5306 : }
5307 : }
5308 59407 : return transition;
5309 : }
5310 :
5311 :
5312 790810 : static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
5313 : // Ensure we are requested to search elements kind transition "near the root".
5314 : DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(),
5315 : map->NumberOfOwnDescriptors());
5316 : Map* current_map = map;
5317 :
5318 : ElementsKind kind = map->elements_kind();
5319 2762608 : while (kind != to_kind) {
5320 1350135 : Map* next_map = current_map->ElementsTransitionMap();
5321 1350135 : if (next_map == nullptr) return current_map;
5322 : kind = next_map->elements_kind();
5323 : current_map = next_map;
5324 : }
5325 :
5326 : DCHECK_EQ(to_kind, current_map->elements_kind());
5327 : return current_map;
5328 : }
5329 :
5330 :
5331 0 : Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) {
5332 31833 : Map* to_map = FindClosestElementsTransition(this, to_kind);
5333 31833 : if (to_map->elements_kind() == to_kind) return to_map;
5334 : return nullptr;
5335 : }
5336 :
5337 268142 : bool Map::IsMapInArrayPrototypeChain() const {
5338 : Isolate* isolate = GetIsolate();
5339 536284 : if (isolate->initial_array_prototype()->map() == this) {
5340 : return true;
5341 : }
5342 :
5343 535078 : if (isolate->initial_object_prototype()->map() == this) {
5344 : return true;
5345 : }
5346 :
5347 267355 : return false;
5348 : }
5349 :
5350 :
5351 10803078 : Handle<WeakCell> Map::WeakCellForMap(Handle<Map> map) {
5352 : Isolate* isolate = map->GetIsolate();
5353 10803078 : if (map->weak_cell_cache()->IsWeakCell()) {
5354 3456596 : return Handle<WeakCell>(WeakCell::cast(map->weak_cell_cache()));
5355 : }
5356 7346482 : Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(map);
5357 7346482 : map->set_weak_cell_cache(*weak_cell);
5358 7346483 : return weak_cell;
5359 : }
5360 :
5361 :
5362 169147 : static Handle<Map> AddMissingElementsTransitions(Handle<Map> map,
5363 : ElementsKind to_kind) {
5364 : DCHECK(IsTransitionElementsKind(map->elements_kind()));
5365 :
5366 : Handle<Map> current_map = map;
5367 :
5368 : ElementsKind kind = map->elements_kind();
5369 : TransitionFlag flag;
5370 169147 : if (map->is_prototype_map()) {
5371 : flag = OMIT_TRANSITION;
5372 : } else {
5373 : flag = INSERT_TRANSITION;
5374 167268 : if (IsFastElementsKind(kind)) {
5375 344821 : while (kind != to_kind && !IsTerminalElementsKind(kind)) {
5376 6088 : kind = GetNextTransitionElementsKind(kind);
5377 6088 : current_map = Map::CopyAsElementsKind(current_map, kind, flag);
5378 : }
5379 : }
5380 : }
5381 :
5382 : // In case we are exiting the fast elements kind system, just add the map in
5383 : // the end.
5384 169147 : if (kind != to_kind) {
5385 167442 : current_map = Map::CopyAsElementsKind(current_map, to_kind, flag);
5386 : }
5387 :
5388 : DCHECK(current_map->elements_kind() == to_kind);
5389 169147 : return current_map;
5390 : }
5391 :
5392 :
5393 1496774 : Handle<Map> Map::TransitionElementsTo(Handle<Map> map,
5394 : ElementsKind to_kind) {
5395 : ElementsKind from_kind = map->elements_kind();
5396 1496774 : if (from_kind == to_kind) return map;
5397 :
5398 803130 : Isolate* isolate = map->GetIsolate();
5399 : Context* native_context = isolate->context()->native_context();
5400 803130 : if (from_kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
5401 761 : if (*map == native_context->fast_aliased_arguments_map()) {
5402 : DCHECK_EQ(SLOW_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
5403 : return handle(native_context->slow_aliased_arguments_map());
5404 : }
5405 802369 : } else if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
5406 0 : if (*map == native_context->slow_aliased_arguments_map()) {
5407 : DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
5408 : return handle(native_context->fast_aliased_arguments_map());
5409 : }
5410 1603971 : } else if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) {
5411 : // Reuse map transitions for JSArrays.
5412 : DisallowHeapAllocation no_gc;
5413 1000306 : if (native_context->GetInitialJSArrayMap(from_kind) == *map) {
5414 : Object* maybe_transitioned_map =
5415 : native_context->get(Context::ArrayMapIndex(to_kind));
5416 374317 : if (maybe_transitioned_map->IsMap()) {
5417 : return handle(Map::cast(maybe_transitioned_map), isolate);
5418 : }
5419 : }
5420 : }
5421 :
5422 : DCHECK(!map->IsUndefined(isolate));
5423 : // Check if we can go back in the elements kind transition chain.
5424 835541 : if (IsHoleyOrDictionaryElementsKind(from_kind) &&
5425 0 : to_kind == GetPackedElementsKind(from_kind) &&
5426 428122 : map->GetBackPointer()->IsMap() &&
5427 0 : Map::cast(map->GetBackPointer())->elements_kind() == to_kind) {
5428 0 : return handle(Map::cast(map->GetBackPointer()));
5429 : }
5430 :
5431 : bool allow_store_transition = IsTransitionElementsKind(from_kind);
5432 : // Only store fast element maps in ascending generality.
5433 428122 : if (IsFastElementsKind(to_kind)) {
5434 : allow_store_transition =
5435 378133 : allow_store_transition && IsTransitionableFastElementsKind(from_kind) &&
5436 125836 : IsMoreGeneralElementsKindTransition(from_kind, to_kind);
5437 : }
5438 :
5439 428122 : if (!allow_store_transition) {
5440 635 : return Map::CopyAsElementsKind(map, to_kind, OMIT_TRANSITION);
5441 : }
5442 :
5443 427487 : return Map::ReconfigureElementsKind(map, to_kind);
5444 : }
5445 :
5446 :
5447 : // static
5448 758977 : Handle<Map> Map::AsElementsKind(Handle<Map> map, ElementsKind kind) {
5449 758977 : Handle<Map> closest_map(FindClosestElementsTransition(*map, kind));
5450 :
5451 758977 : if (closest_map->elements_kind() == kind) {
5452 589830 : return closest_map;
5453 : }
5454 :
5455 169147 : return AddMissingElementsTransitions(closest_map, kind);
5456 : }
5457 :
5458 :
5459 1474485 : Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
5460 : ElementsKind to_kind) {
5461 : Handle<Map> map(object->map());
5462 1474485 : return Map::TransitionElementsTo(map, to_kind);
5463 : }
5464 :
5465 :
5466 140 : void JSProxy::Revoke(Handle<JSProxy> proxy) {
5467 : Isolate* isolate = proxy->GetIsolate();
5468 271 : if (!proxy->IsRevoked()) proxy->set_handler(isolate->heap()->null_value());
5469 : DCHECK(proxy->IsRevoked());
5470 140 : }
5471 :
5472 : // static
5473 1079 : Maybe<bool> JSProxy::IsArray(Handle<JSProxy> proxy) {
5474 : Isolate* isolate = proxy->GetIsolate();
5475 : Handle<JSReceiver> object = Handle<JSReceiver>::cast(proxy);
5476 1025099 : for (int i = 0; i < JSProxy::kMaxIterationLimit; i++) {
5477 : Handle<JSProxy> proxy = Handle<JSProxy>::cast(object);
5478 1025089 : if (proxy->IsRevoked()) {
5479 : isolate->Throw(*isolate->factory()->NewTypeError(
5480 : MessageTemplate::kProxyRevoked,
5481 162 : isolate->factory()->NewStringFromAsciiChecked("IsArray")));
5482 : return Nothing<bool>();
5483 : }
5484 : object = handle(proxy->target(), isolate);
5485 1025035 : if (object->IsJSArray()) return Just(true);
5486 1024715 : if (!object->IsJSProxy()) return Just(false);
5487 : }
5488 :
5489 : // Too deep recursion, throw a RangeError.
5490 10 : isolate->StackOverflow();
5491 : return Nothing<bool>();
5492 : }
5493 :
5494 42595 : Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy,
5495 : Handle<Name> name) {
5496 : DCHECK(!name->IsPrivate());
5497 42595 : STACK_CHECK(isolate, Nothing<bool>());
5498 : // 1. (Assert)
5499 : // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
5500 : Handle<Object> handler(proxy->handler(), isolate);
5501 : // 3. If handler is null, throw a TypeError exception.
5502 : // 4. Assert: Type(handler) is Object.
5503 42586 : if (proxy->IsRevoked()) {
5504 : isolate->Throw(*isolate->factory()->NewTypeError(
5505 0 : MessageTemplate::kProxyRevoked, isolate->factory()->has_string()));
5506 : return Nothing<bool>();
5507 : }
5508 : // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
5509 : Handle<JSReceiver> target(proxy->target(), isolate);
5510 : // 6. Let trap be ? GetMethod(handler, "has").
5511 : Handle<Object> trap;
5512 85172 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5513 : isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
5514 : isolate->factory()->has_string()),
5515 : Nothing<bool>());
5516 : // 7. If trap is undefined, then
5517 42586 : if (trap->IsUndefined(isolate)) {
5518 : // 7a. Return target.[[HasProperty]](P).
5519 34212 : return JSReceiver::HasProperty(target, name);
5520 : }
5521 : // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, P»)).
5522 : Handle<Object> trap_result_obj;
5523 : Handle<Object> args[] = {target, name};
5524 16748 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5525 : isolate, trap_result_obj,
5526 : Execution::Call(isolate, trap, handler, arraysize(args), args),
5527 : Nothing<bool>());
5528 8328 : bool boolean_trap_result = trap_result_obj->BooleanValue();
5529 : // 9. If booleanTrapResult is false, then:
5530 8328 : if (!boolean_trap_result) {
5531 5447 : MAYBE_RETURN(JSProxy::CheckHasTrap(isolate, name, target), Nothing<bool>());
5532 : }
5533 : // 10. Return booleanTrapResult.
5534 : return Just(boolean_trap_result);
5535 : }
5536 :
5537 5457 : Maybe<bool> JSProxy::CheckHasTrap(Isolate* isolate, Handle<Name> name,
5538 : Handle<JSReceiver> target) {
5539 : // 9a. Let targetDesc be ? target.[[GetOwnProperty]](P).
5540 : PropertyDescriptor target_desc;
5541 : Maybe<bool> target_found =
5542 5457 : JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
5543 5457 : MAYBE_RETURN(target_found, Nothing<bool>());
5544 : // 9b. If targetDesc is not undefined, then:
5545 5457 : if (target_found.FromJust()) {
5546 : // 9b i. If targetDesc.[[Configurable]] is false, throw a TypeError
5547 : // exception.
5548 30 : if (!target_desc.configurable()) {
5549 : isolate->Throw(*isolate->factory()->NewTypeError(
5550 20 : MessageTemplate::kProxyHasNonConfigurable, name));
5551 10 : return Nothing<bool>();
5552 : }
5553 : // 9b ii. Let extensibleTarget be ? IsExtensible(target).
5554 20 : Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
5555 20 : MAYBE_RETURN(extensible_target, Nothing<bool>());
5556 : // 9b iii. If extensibleTarget is false, throw a TypeError exception.
5557 20 : if (!extensible_target.FromJust()) {
5558 : isolate->Throw(*isolate->factory()->NewTypeError(
5559 0 : MessageTemplate::kProxyHasNonExtensible, name));
5560 : return Nothing<bool>();
5561 : }
5562 : }
5563 : return Just(true);
5564 : }
5565 :
5566 41571 : Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name,
5567 : Handle<Object> value, Handle<Object> receiver,
5568 : LanguageMode language_mode) {
5569 : DCHECK(!name->IsPrivate());
5570 : Isolate* isolate = proxy->GetIsolate();
5571 41571 : STACK_CHECK(isolate, Nothing<bool>());
5572 : Factory* factory = isolate->factory();
5573 : Handle<String> trap_name = factory->set_string();
5574 : ShouldThrow should_throw =
5575 41553 : is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
5576 :
5577 41553 : if (proxy->IsRevoked()) {
5578 : isolate->Throw(
5579 36 : *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
5580 : return Nothing<bool>();
5581 : }
5582 : Handle<JSReceiver> target(proxy->target(), isolate);
5583 : Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
5584 :
5585 : Handle<Object> trap;
5586 83070 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5587 : isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
5588 41283 : if (trap->IsUndefined(isolate)) {
5589 : LookupIterator it =
5590 38266 : LookupIterator::PropertyOrElement(isolate, receiver, name, target);
5591 : return Object::SetSuperProperty(&it, value, language_mode,
5592 38266 : Object::MAY_BE_STORE_FROM_KEYED);
5593 : }
5594 :
5595 : Handle<Object> trap_result;
5596 3017 : Handle<Object> args[] = {target, name, value, receiver};
5597 6034 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5598 : isolate, trap_result,
5599 : Execution::Call(isolate, trap, handler, arraysize(args), args),
5600 : Nothing<bool>());
5601 2774 : if (!trap_result->BooleanValue()) {
5602 587 : RETURN_FAILURE(isolate, should_throw,
5603 : NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
5604 : trap_name, name));
5605 : }
5606 :
5607 : MaybeHandle<Object> result =
5608 2277 : JSProxy::CheckGetSetTrapResult(isolate, name, target, value, kSet);
5609 :
5610 2277 : if (result.is_null()) {
5611 : return Nothing<bool>();
5612 : }
5613 : return Just(true);
5614 : }
5615 :
5616 :
5617 3097 : Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy,
5618 : Handle<Name> name,
5619 : LanguageMode language_mode) {
5620 : DCHECK(!name->IsPrivate());
5621 : ShouldThrow should_throw =
5622 3097 : is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
5623 : Isolate* isolate = proxy->GetIsolate();
5624 3097 : STACK_CHECK(isolate, Nothing<bool>());
5625 : Factory* factory = isolate->factory();
5626 : Handle<String> trap_name = factory->deleteProperty_string();
5627 :
5628 3097 : if (proxy->IsRevoked()) {
5629 : isolate->Throw(
5630 36 : *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
5631 : return Nothing<bool>();
5632 : }
5633 : Handle<JSReceiver> target(proxy->target(), isolate);
5634 : Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
5635 :
5636 : Handle<Object> trap;
5637 6158 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5638 : isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
5639 2944 : if (trap->IsUndefined(isolate)) {
5640 811 : return JSReceiver::DeletePropertyOrElement(target, name, language_mode);
5641 : }
5642 :
5643 : Handle<Object> trap_result;
5644 : Handle<Object> args[] = {target, name};
5645 4266 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5646 : isolate, trap_result,
5647 : Execution::Call(isolate, trap, handler, arraysize(args), args),
5648 : Nothing<bool>());
5649 1809 : if (!trap_result->BooleanValue()) {
5650 1242 : RETURN_FAILURE(isolate, should_throw,
5651 : NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
5652 : trap_name, name));
5653 : }
5654 :
5655 : // Enforce the invariant.
5656 : PropertyDescriptor target_desc;
5657 : Maybe<bool> owned =
5658 1053 : JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
5659 1053 : MAYBE_RETURN(owned, Nothing<bool>());
5660 1593 : if (owned.FromJust() && !target_desc.configurable()) {
5661 : isolate->Throw(*factory->NewTypeError(
5662 720 : MessageTemplate::kProxyDeletePropertyNonConfigurable, name));
5663 : return Nothing<bool>();
5664 : }
5665 : return Just(true);
5666 : }
5667 :
5668 :
5669 : // static
5670 17 : MaybeHandle<JSProxy> JSProxy::New(Isolate* isolate, Handle<Object> target,
5671 : Handle<Object> handler) {
5672 17 : if (!target->IsJSReceiver()) {
5673 0 : THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5674 : JSProxy);
5675 : }
5676 17 : if (target->IsJSProxy() && JSProxy::cast(*target)->IsRevoked()) {
5677 0 : THROW_NEW_ERROR(isolate,
5678 : NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5679 : JSProxy);
5680 : }
5681 17 : if (!handler->IsJSReceiver()) {
5682 0 : THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5683 : JSProxy);
5684 : }
5685 17 : if (handler->IsJSProxy() && JSProxy::cast(*handler)->IsRevoked()) {
5686 0 : THROW_NEW_ERROR(isolate,
5687 : NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5688 : JSProxy);
5689 : }
5690 : return isolate->factory()->NewJSProxy(Handle<JSReceiver>::cast(target),
5691 17 : Handle<JSReceiver>::cast(handler));
5692 : }
5693 :
5694 :
5695 : // static
5696 19 : MaybeHandle<Context> JSProxy::GetFunctionRealm(Handle<JSProxy> proxy) {
5697 : DCHECK(proxy->map()->is_constructor());
5698 19 : if (proxy->IsRevoked()) {
5699 0 : THROW_NEW_ERROR(proxy->GetIsolate(),
5700 : NewTypeError(MessageTemplate::kProxyRevoked), Context);
5701 : }
5702 : Handle<JSReceiver> target(JSReceiver::cast(proxy->target()));
5703 19 : return JSReceiver::GetFunctionRealm(target);
5704 : }
5705 :
5706 :
5707 : // static
5708 0 : MaybeHandle<Context> JSBoundFunction::GetFunctionRealm(
5709 : Handle<JSBoundFunction> function) {
5710 : DCHECK(function->map()->is_constructor());
5711 : return JSReceiver::GetFunctionRealm(
5712 0 : handle(function->bound_target_function()));
5713 : }
5714 :
5715 : // static
5716 82 : MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate,
5717 : Handle<JSBoundFunction> function) {
5718 : Handle<String> prefix = isolate->factory()->bound__string();
5719 : Handle<String> target_name = prefix;
5720 : Factory* factory = isolate->factory();
5721 : // Concatenate the "bound " up to the last non-bound target.
5722 164 : while (function->bound_target_function()->IsJSBoundFunction()) {
5723 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, target_name,
5724 : factory->NewConsString(prefix, target_name),
5725 : String);
5726 : function = handle(JSBoundFunction::cast(function->bound_target_function()),
5727 : isolate);
5728 : }
5729 82 : if (function->bound_target_function()->IsJSFunction()) {
5730 : Handle<JSFunction> target(
5731 : JSFunction::cast(function->bound_target_function()), isolate);
5732 82 : Handle<Object> name = JSFunction::GetName(isolate, target);
5733 82 : if (!name->IsString()) return target_name;
5734 82 : return factory->NewConsString(target_name, Handle<String>::cast(name));
5735 : }
5736 : // This will omit the proper target name for bound JSProxies.
5737 0 : return target_name;
5738 : }
5739 :
5740 : // static
5741 342 : Maybe<int> JSBoundFunction::GetLength(Isolate* isolate,
5742 : Handle<JSBoundFunction> function) {
5743 : int nof_bound_arguments = function->bound_arguments()->length();
5744 1104 : while (function->bound_target_function()->IsJSBoundFunction()) {
5745 : function = handle(JSBoundFunction::cast(function->bound_target_function()),
5746 : isolate);
5747 : // Make sure we never overflow {nof_bound_arguments}, the number of
5748 : // arguments of a function is strictly limited by the max length of an
5749 : // JSAarray, Smi::kMaxValue is thus a reasonably good overestimate.
5750 : int length = function->bound_arguments()->length();
5751 420 : if (V8_LIKELY(Smi::kMaxValue - nof_bound_arguments > length)) {
5752 420 : nof_bound_arguments += length;
5753 : } else {
5754 : nof_bound_arguments = Smi::kMaxValue;
5755 : }
5756 : }
5757 : // All non JSFunction targets get a direct property and don't use this
5758 : // accessor.
5759 : Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()),
5760 : isolate);
5761 342 : Maybe<int> target_length = JSFunction::GetLength(isolate, target);
5762 342 : if (target_length.IsNothing()) return target_length;
5763 :
5764 342 : int length = Max(0, target_length.FromJust() - nof_bound_arguments);
5765 : return Just(length);
5766 : }
5767 :
5768 : // static
5769 88005 : Handle<Object> JSFunction::GetName(Isolate* isolate,
5770 : Handle<JSFunction> function) {
5771 88005 : if (function->shared()->name_should_print_as_anonymous()) {
5772 0 : return isolate->factory()->anonymous_string();
5773 : }
5774 88005 : return handle(function->shared()->name(), isolate);
5775 : }
5776 :
5777 : // static
5778 17576 : Maybe<int> JSFunction::GetLength(Isolate* isolate,
5779 : Handle<JSFunction> function) {
5780 : int length = 0;
5781 17576 : if (function->shared()->is_compiled()) {
5782 : length = function->shared()->GetLength();
5783 : } else {
5784 : // If the function isn't compiled yet, the length is not computed
5785 : // correctly yet. Compile it now and return the right length.
5786 1890 : if (Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) {
5787 : length = function->shared()->GetLength();
5788 : }
5789 1890 : if (isolate->has_pending_exception()) return Nothing<int>();
5790 : }
5791 : DCHECK_GE(length, 0);
5792 : return Just(length);
5793 : }
5794 :
5795 : // static
5796 2809 : Handle<Context> JSFunction::GetFunctionRealm(Handle<JSFunction> function) {
5797 : DCHECK(function->map()->is_constructor());
5798 2809 : return handle(function->context()->native_context());
5799 : }
5800 :
5801 :
5802 : // static
5803 0 : MaybeHandle<Context> JSObject::GetFunctionRealm(Handle<JSObject> object) {
5804 : DCHECK(object->map()->is_constructor());
5805 : DCHECK(!object->IsJSFunction());
5806 0 : return object->GetCreationContext();
5807 : }
5808 :
5809 :
5810 : // static
5811 2828 : MaybeHandle<Context> JSReceiver::GetFunctionRealm(Handle<JSReceiver> receiver) {
5812 2828 : if (receiver->IsJSProxy()) {
5813 19 : return JSProxy::GetFunctionRealm(Handle<JSProxy>::cast(receiver));
5814 : }
5815 :
5816 2809 : if (receiver->IsJSFunction()) {
5817 2809 : return JSFunction::GetFunctionRealm(Handle<JSFunction>::cast(receiver));
5818 : }
5819 :
5820 0 : if (receiver->IsJSBoundFunction()) {
5821 : return JSBoundFunction::GetFunctionRealm(
5822 0 : Handle<JSBoundFunction>::cast(receiver));
5823 : }
5824 :
5825 : return JSObject::GetFunctionRealm(Handle<JSObject>::cast(receiver));
5826 : }
5827 :
5828 :
5829 3180 : Maybe<PropertyAttributes> JSProxy::GetPropertyAttributes(LookupIterator* it) {
5830 : PropertyDescriptor desc;
5831 : Maybe<bool> found = JSProxy::GetOwnPropertyDescriptor(
5832 3180 : it->isolate(), it->GetHolder<JSProxy>(), it->GetName(), &desc);
5833 1590 : MAYBE_RETURN(found, Nothing<PropertyAttributes>());
5834 1290 : if (!found.FromJust()) return Just(ABSENT);
5835 1136 : return Just(desc.ToAttributes());
5836 : }
5837 :
5838 :
5839 6882840 : void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
5840 : DCHECK(object->map()->GetInObjectProperties() ==
5841 : map->GetInObjectProperties());
5842 : ElementsKind obj_kind = object->map()->elements_kind();
5843 : ElementsKind map_kind = map->elements_kind();
5844 6882840 : if (map_kind != obj_kind) {
5845 : ElementsKind to_kind = GetMoreGeneralElementsKind(map_kind, obj_kind);
5846 40 : if (IsDictionaryElementsKind(obj_kind)) {
5847 : to_kind = obj_kind;
5848 : }
5849 40 : if (IsDictionaryElementsKind(to_kind)) {
5850 30 : NormalizeElements(object);
5851 : } else {
5852 10 : TransitionElementsKind(object, to_kind);
5853 : }
5854 40 : map = Map::ReconfigureElementsKind(map, to_kind);
5855 : }
5856 6882840 : int number_of_fields = map->NumberOfFields();
5857 : int inobject = map->GetInObjectProperties();
5858 : int unused = map->UnusedPropertyFields();
5859 6882840 : int total_size = number_of_fields + unused;
5860 6882840 : int external = total_size - inobject;
5861 : // Allocate mutable double boxes if necessary. It is always necessary if we
5862 : // have external properties, but is also necessary if we only have inobject
5863 : // properties but don't unbox double fields.
5864 6882840 : if (!FLAG_unbox_double_fields || external > 0) {
5865 : Isolate* isolate = object->GetIsolate();
5866 :
5867 : Handle<DescriptorArray> descriptors(map->instance_descriptors());
5868 : Handle<FixedArray> storage;
5869 : if (!FLAG_unbox_double_fields) {
5870 : storage = isolate->factory()->NewFixedArray(inobject);
5871 : }
5872 :
5873 : Handle<PropertyArray> array;
5874 2663276 : if (external > 0) {
5875 2663276 : array = isolate->factory()->NewPropertyArray(external);
5876 : }
5877 :
5878 37598386 : for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
5879 16135917 : PropertyDetails details = descriptors->GetDetails(i);
5880 : Representation representation = details.representation();
5881 32271714 : if (!representation.IsDouble()) continue;
5882 6055 : FieldIndex index = FieldIndex::ForDescriptor(*map, i);
5883 6055 : if (map->IsUnboxedDoubleField(index)) continue;
5884 : Handle<HeapNumber> box = isolate->factory()->NewMutableHeapNumber();
5885 120 : if (index.is_inobject()) {
5886 0 : storage->set(index.property_index(), *box);
5887 : } else {
5888 120 : array->set(index.outobject_array_index(), *box);
5889 : }
5890 : }
5891 :
5892 2663276 : if (external > 0) {
5893 2663276 : object->SetProperties(*array);
5894 : }
5895 :
5896 : if (!FLAG_unbox_double_fields) {
5897 : for (int i = 0; i < inobject; i++) {
5898 : FieldIndex index = FieldIndex::ForPropertyIndex(*map, i);
5899 : Object* value = storage->get(i);
5900 : object->RawFastPropertyAtPut(index, value);
5901 : }
5902 : }
5903 : }
5904 6882840 : object->synchronized_set_map(*map);
5905 6882840 : }
5906 :
5907 :
5908 3707 : void JSObject::MigrateInstance(Handle<JSObject> object) {
5909 : Handle<Map> original_map(object->map());
5910 3707 : Handle<Map> map = Map::Update(original_map);
5911 : map->set_migration_target(true);
5912 3707 : MigrateToMap(object, map);
5913 3707 : if (FLAG_trace_migration) {
5914 0 : object->PrintInstanceMigration(stdout, *original_map, *map);
5915 : }
5916 : #if VERIFY_HEAP
5917 : if (FLAG_verify_heap) {
5918 : object->JSObjectVerify();
5919 : }
5920 : #endif
5921 3707 : }
5922 :
5923 :
5924 : // static
5925 5402 : bool JSObject::TryMigrateInstance(Handle<JSObject> object) {
5926 : Isolate* isolate = object->GetIsolate();
5927 : DisallowDeoptimization no_deoptimization(isolate);
5928 : Handle<Map> original_map(object->map(), isolate);
5929 : Handle<Map> new_map;
5930 10804 : if (!Map::TryUpdate(original_map).ToHandle(&new_map)) {
5931 : return false;
5932 : }
5933 5384 : JSObject::MigrateToMap(object, new_map);
5934 5384 : if (FLAG_trace_migration && *original_map != object->map()) {
5935 0 : object->PrintInstanceMigration(stdout, *original_map, object->map());
5936 : }
5937 : #if VERIFY_HEAP
5938 : if (FLAG_verify_heap) {
5939 : object->JSObjectVerify();
5940 : }
5941 : #endif
5942 : return true;
5943 : }
5944 :
5945 :
5946 12229355 : void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name,
5947 : Handle<Object> value,
5948 : PropertyAttributes attributes) {
5949 12229355 : LookupIterator it(object, name, object, LookupIterator::OWN_SKIP_INTERCEPTOR);
5950 12229358 : CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
5951 : #ifdef DEBUG
5952 : uint32_t index;
5953 : DCHECK(!object->IsJSProxy());
5954 : DCHECK(!name->AsArrayIndex(&index));
5955 : Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
5956 : DCHECK(maybe.IsJust());
5957 : DCHECK(!it.IsFound());
5958 : DCHECK(object->map()->is_extensible() || name->IsPrivate());
5959 : #endif
5960 12229358 : CHECK(AddDataProperty(&it, value, attributes, THROW_ON_ERROR,
5961 : CERTAINLY_NOT_STORE_FROM_KEYED)
5962 : .IsJust());
5963 12229358 : }
5964 :
5965 :
5966 : // Reconfigures a property to a data property with attributes, even if it is not
5967 : // reconfigurable.
5968 : // Requires a LookupIterator that does not look at the prototype chain beyond
5969 : // hidden prototypes.
5970 15411732 : MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes(
5971 : LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
5972 : AccessorInfoHandling handling) {
5973 15411732 : MAYBE_RETURN_NULL(DefineOwnPropertyIgnoreAttributes(
5974 : it, value, attributes, THROW_ON_ERROR, handling));
5975 15411707 : return value;
5976 : }
5977 :
5978 :
5979 16102207 : Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
5980 16126380 : LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
5981 : ShouldThrow should_throw, AccessorInfoHandling handling) {
5982 16102207 : it->UpdateProtector();
5983 : Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
5984 :
5985 32205950 : for (; it->IsFound(); it->Next()) {
5986 459899 : switch (it->state()) {
5987 : case LookupIterator::JSPROXY:
5988 : case LookupIterator::NOT_FOUND:
5989 : case LookupIterator::TRANSITION:
5990 0 : UNREACHABLE();
5991 :
5992 : case LookupIterator::ACCESS_CHECK:
5993 559 : if (!it->HasAccess()) {
5994 5 : it->isolate()->ReportFailedAccessCheck(it->GetHolder<JSObject>());
5995 5 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
5996 : return Just(true);
5997 : }
5998 : break;
5999 :
6000 : // If there's an interceptor, try to store the property with the
6001 : // interceptor.
6002 : // In case of success, the attributes will have been reset to the default
6003 : // attributes of the interceptor, rather than the incoming attributes.
6004 : //
6005 : // TODO(verwaest): JSProxy afterwards verify the attributes that the
6006 : // JSProxy claims it has, and verifies that they are compatible. If not,
6007 : // they throw. Here we should do the same.
6008 : case LookupIterator::INTERCEPTOR:
6009 220 : if (handling == DONT_FORCE_FIELD) {
6010 : Maybe<bool> result =
6011 220 : JSObject::SetPropertyWithInterceptor(it, should_throw, value);
6012 440 : if (result.IsNothing() || result.FromJust()) return result;
6013 : }
6014 : break;
6015 :
6016 : case LookupIterator::ACCESSOR: {
6017 99755 : Handle<Object> accessors = it->GetAccessors();
6018 :
6019 : // Special handling for AccessorInfo, which behaves like a data
6020 : // property.
6021 99755 : if (accessors->IsAccessorInfo() && handling == DONT_FORCE_FIELD) {
6022 : PropertyAttributes current_attributes = it->property_attributes();
6023 : // Ensure the context isn't changed after calling into accessors.
6024 : AssertNoContextChange ncc(it->isolate());
6025 :
6026 : // Update the attributes before calling the setter. The setter may
6027 : // later change the shape of the property.
6028 99245 : if (current_attributes != attributes) {
6029 95560 : it->TransitionToAccessorPair(accessors, attributes);
6030 : }
6031 :
6032 99245 : return JSObject::SetPropertyWithAccessor(it, value, should_throw);
6033 : }
6034 :
6035 510 : it->ReconfigureDataProperty(value, attributes);
6036 : return Just(true);
6037 : }
6038 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
6039 : return RedefineIncompatibleProperty(it->isolate(), it->GetName(), value,
6040 20 : should_throw);
6041 :
6042 : case LookupIterator::DATA: {
6043 : // Regular property update if the attributes match.
6044 359355 : if (it->property_attributes() == attributes) {
6045 335970 : return SetDataProperty(it, value);
6046 : }
6047 :
6048 : // Special case: properties of typed arrays cannot be reconfigured to
6049 : // non-writable nor to non-enumerable.
6050 44809 : if (it->IsElement() && object->HasFixedTypedArrayElements()) {
6051 : return RedefineIncompatibleProperty(it->isolate(), it->GetName(),
6052 0 : value, should_throw);
6053 : }
6054 :
6055 : // Reconfigure the data property if the attributes mismatch.
6056 23385 : it->ReconfigureDataProperty(value, attributes);
6057 :
6058 : return Just(true);
6059 : }
6060 : }
6061 : }
6062 :
6063 : return AddDataProperty(it, value, attributes, should_throw,
6064 15643076 : CERTAINLY_NOT_STORE_FROM_KEYED);
6065 : }
6066 :
6067 8835683 : MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
6068 : Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
6069 : PropertyAttributes attributes) {
6070 : DCHECK(!value->IsTheHole(object->GetIsolate()));
6071 8835683 : LookupIterator it(object, name, object, LookupIterator::OWN);
6072 8835683 : return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
6073 : }
6074 :
6075 2751039 : MaybeHandle<Object> JSObject::SetOwnElementIgnoreAttributes(
6076 : Handle<JSObject> object, uint32_t index, Handle<Object> value,
6077 : PropertyAttributes attributes) {
6078 : Isolate* isolate = object->GetIsolate();
6079 : LookupIterator it(isolate, object, index, object, LookupIterator::OWN);
6080 2751039 : return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
6081 : }
6082 :
6083 400829 : MaybeHandle<Object> JSObject::DefinePropertyOrElementIgnoreAttributes(
6084 : Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
6085 : PropertyAttributes attributes) {
6086 : Isolate* isolate = object->GetIsolate();
6087 : LookupIterator it = LookupIterator::PropertyOrElement(
6088 400829 : isolate, object, name, object, LookupIterator::OWN);
6089 400829 : return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
6090 : }
6091 :
6092 250419 : Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
6093 : LookupIterator* it) {
6094 250419 : return GetPropertyAttributesWithInterceptorInternal(it, it->GetInterceptor());
6095 : }
6096 :
6097 9859313 : Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
6098 12032816 : LookupIterator* it) {
6099 24065632 : for (; it->IsFound(); it->Next()) {
6100 6666402 : switch (it->state()) {
6101 : case LookupIterator::NOT_FOUND:
6102 : case LookupIterator::TRANSITION:
6103 0 : UNREACHABLE();
6104 : case LookupIterator::JSPROXY:
6105 839 : return JSProxy::GetPropertyAttributes(it);
6106 : case LookupIterator::INTERCEPTOR: {
6107 : Maybe<PropertyAttributes> result =
6108 716 : JSObject::GetPropertyAttributesWithInterceptor(it);
6109 1075 : if (!result.IsJust()) return result;
6110 716 : if (result.FromJust() != ABSENT) return result;
6111 357 : break;
6112 : }
6113 : case LookupIterator::ACCESS_CHECK:
6114 2173227 : if (it->HasAccess()) break;
6115 81 : return JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
6116 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
6117 : return Just(ABSENT);
6118 : case LookupIterator::ACCESSOR:
6119 : case LookupIterator::DATA:
6120 : return Just(it->property_attributes());
6121 : }
6122 : }
6123 : return Just(ABSENT);
6124 : }
6125 :
6126 :
6127 61 : Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) {
6128 : Handle<FixedArray> array(
6129 61 : isolate->factory()->NewFixedArray(kEntries, TENURED));
6130 61 : return Handle<NormalizedMapCache>::cast(array);
6131 : }
6132 :
6133 :
6134 755249 : MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map,
6135 : PropertyNormalizationMode mode) {
6136 : DisallowHeapAllocation no_gc;
6137 : Object* value = FixedArray::get(GetIndex(fast_map));
6138 1408287 : if (!value->IsWeakCell() || WeakCell::cast(value)->cleared()) {
6139 112260 : return MaybeHandle<Map>();
6140 : }
6141 :
6142 : Map* normalized_map = Map::cast(WeakCell::cast(value)->value());
6143 642989 : if (!normalized_map->EquivalentToForNormalization(*fast_map, mode)) {
6144 89992 : return MaybeHandle<Map>();
6145 : }
6146 552997 : return handle(normalized_map);
6147 : }
6148 :
6149 202252 : void NormalizedMapCache::Set(Handle<Map> fast_map, Handle<Map> normalized_map,
6150 : Handle<WeakCell> normalized_map_weak_cell) {
6151 : DisallowHeapAllocation no_gc;
6152 : DCHECK(normalized_map->is_dictionary_map());
6153 : DCHECK_EQ(normalized_map_weak_cell->value(), *normalized_map);
6154 202252 : FixedArray::set(GetIndex(fast_map), *normalized_map_weak_cell);
6155 202252 : }
6156 :
6157 :
6158 0 : void NormalizedMapCache::Clear() {
6159 : int entries = length();
6160 0 : for (int i = 0; i != entries; i++) {
6161 0 : set_undefined(i);
6162 : }
6163 0 : }
6164 :
6165 :
6166 992358 : void JSObject::NormalizeProperties(Handle<JSObject> object,
6167 : PropertyNormalizationMode mode,
6168 : int expected_additional_properties,
6169 : const char* reason) {
6170 1333807 : if (!object->HasFastProperties()) return;
6171 :
6172 : Handle<Map> map(object->map());
6173 650909 : Handle<Map> new_map = Map::Normalize(map, mode, reason);
6174 :
6175 650909 : MigrateToMap(object, new_map, expected_additional_properties);
6176 : }
6177 :
6178 :
6179 861475 : void JSObject::MigrateSlowToFast(Handle<JSObject> object,
6180 : int unused_property_fields,
6181 : const char* reason) {
6182 1350565 : if (object->HasFastProperties()) return;
6183 : DCHECK(!object->IsJSGlobalObject());
6184 : Isolate* isolate = object->GetIsolate();
6185 : Factory* factory = isolate->factory();
6186 : Handle<NameDictionary> dictionary(object->property_dictionary());
6187 :
6188 : // Make sure we preserve dictionary representation if there are too many
6189 : // descriptors.
6190 : int number_of_elements = dictionary->NumberOfElements();
6191 445067 : if (number_of_elements > kMaxNumberOfDescriptors) return;
6192 :
6193 : Handle<FixedArray> iteration_order =
6194 444668 : NameDictionary::IterationIndices(dictionary);
6195 :
6196 : int instance_descriptor_length = iteration_order->length();
6197 : int number_of_fields = 0;
6198 :
6199 : // Compute the length of the instance descriptor.
6200 2694457 : for (int i = 0; i < instance_descriptor_length; i++) {
6201 : int index = Smi::ToInt(iteration_order->get(i));
6202 : DCHECK(dictionary->IsKey(isolate, dictionary->KeyAt(index)));
6203 :
6204 : PropertyKind kind = dictionary->DetailsAt(index).kind();
6205 2249789 : if (kind == kData) {
6206 : if (FLAG_track_constant_fields) {
6207 : number_of_fields += 1;
6208 : } else {
6209 1588423 : Object* value = dictionary->ValueAt(index);
6210 1588423 : if (!value->IsJSFunction()) {
6211 438229 : number_of_fields += 1;
6212 : }
6213 : }
6214 : }
6215 : }
6216 :
6217 : Handle<Map> old_map(object->map(), isolate);
6218 :
6219 : int inobject_props = old_map->GetInObjectProperties();
6220 :
6221 : // Allocate new map.
6222 444668 : Handle<Map> new_map = Map::CopyDropDescriptors(old_map);
6223 889146 : new_map->set_may_have_interesting_symbols(new_map->has_named_interceptor() ||
6224 : new_map->is_access_check_needed());
6225 : new_map->set_dictionary_map(false);
6226 :
6227 444668 : NotifyMapChange(old_map, new_map, isolate);
6228 :
6229 : #if V8_TRACE_MAPS
6230 : if (FLAG_trace_maps) {
6231 : PrintF("[TraceMaps: SlowToFast from= %p to= %p reason= %s ]\n",
6232 : reinterpret_cast<void*>(*old_map), reinterpret_cast<void*>(*new_map),
6233 : reason);
6234 : }
6235 : #endif
6236 :
6237 444668 : if (instance_descriptor_length == 0) {
6238 : DisallowHeapAllocation no_gc;
6239 : DCHECK_LE(unused_property_fields, inobject_props);
6240 : // Transform the object.
6241 72283 : new_map->SetInObjectUnusedPropertyFields(inobject_props);
6242 72283 : object->synchronized_set_map(*new_map);
6243 144566 : object->SetProperties(isolate->heap()->empty_fixed_array());
6244 : // Check that it really works.
6245 : DCHECK(object->HasFastProperties());
6246 : return;
6247 : }
6248 :
6249 : // Allocate the instance descriptor.
6250 : Handle<DescriptorArray> descriptors = DescriptorArray::Allocate(
6251 372385 : isolate, instance_descriptor_length, 0, TENURED);
6252 :
6253 : int number_of_allocated_fields =
6254 372385 : number_of_fields + unused_property_fields - inobject_props;
6255 372385 : if (number_of_allocated_fields < 0) {
6256 : // There is enough inobject space for all fields (including unused).
6257 : number_of_allocated_fields = 0;
6258 60051 : unused_property_fields = inobject_props - number_of_fields;
6259 : }
6260 :
6261 : // Allocate the property array for the fields.
6262 : Handle<PropertyArray> fields =
6263 372385 : factory->NewPropertyArray(number_of_allocated_fields);
6264 :
6265 : // Fill in the instance descriptor and the fields.
6266 : int current_offset = 0;
6267 2622174 : for (int i = 0; i < instance_descriptor_length; i++) {
6268 : int index = Smi::ToInt(iteration_order->get(i));
6269 : Name* k = dictionary->NameAt(index);
6270 : // Dictionary keys are internalized upon insertion.
6271 : // TODO(jkummerow): Turn this into a DCHECK if it's not hit in the wild.
6272 2249789 : CHECK(k->IsUniqueName());
6273 : Handle<Name> key(k, isolate);
6274 :
6275 : // Properly mark the {new_map} if the {key} is an "interesting symbol".
6276 2249789 : if (key->IsInterestingSymbol()) {
6277 : new_map->set_may_have_interesting_symbols(true);
6278 : }
6279 :
6280 2249789 : Object* value = dictionary->ValueAt(index);
6281 :
6282 : PropertyDetails details = dictionary->DetailsAt(index);
6283 : DCHECK_EQ(kField, details.location());
6284 : DCHECK_EQ(kMutable, details.constness());
6285 :
6286 : Descriptor d;
6287 2249789 : if (details.kind() == kData) {
6288 1588423 : if (!FLAG_track_constant_fields && value->IsJSFunction()) {
6289 : d = Descriptor::DataConstant(key, handle(value, isolate),
6290 1150194 : details.attributes());
6291 : } else {
6292 : d = Descriptor::DataField(
6293 : key, current_offset, details.attributes(), kDefaultFieldConstness,
6294 : // TODO(verwaest): value->OptimalRepresentation();
6295 876458 : Representation::Tagged(), FieldType::Any(isolate));
6296 : }
6297 : } else {
6298 : DCHECK_EQ(kAccessor, details.kind());
6299 : d = Descriptor::AccessorConstant(key, handle(value, isolate),
6300 661366 : details.attributes());
6301 : }
6302 : details = d.GetDetails();
6303 2249789 : if (details.location() == kField) {
6304 438229 : if (current_offset < inobject_props) {
6305 : object->InObjectPropertyAtPut(current_offset, value,
6306 25181 : UPDATE_WRITE_BARRIER);
6307 : } else {
6308 413048 : int offset = current_offset - inobject_props;
6309 413048 : fields->set(offset, value);
6310 : }
6311 438229 : current_offset += details.field_width_in_words();
6312 : }
6313 2249789 : descriptors->Set(i, &d);
6314 : }
6315 : DCHECK(current_offset == number_of_fields);
6316 :
6317 372385 : descriptors->Sort();
6318 :
6319 : Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
6320 372385 : new_map, descriptors, descriptors->number_of_descriptors());
6321 :
6322 : DisallowHeapAllocation no_gc;
6323 372385 : new_map->InitializeDescriptors(*descriptors, *layout_descriptor);
6324 372385 : if (number_of_allocated_fields == 0) {
6325 258601 : new_map->SetInObjectUnusedPropertyFields(unused_property_fields);
6326 : } else {
6327 : new_map->SetOutOfObjectUnusedPropertyFields(unused_property_fields);
6328 : }
6329 :
6330 : // Transform the object.
6331 372385 : object->synchronized_set_map(*new_map);
6332 :
6333 372385 : object->SetProperties(*fields);
6334 : DCHECK(object->IsJSObject());
6335 :
6336 : // Check that it really works.
6337 : DCHECK(object->HasFastProperties());
6338 : }
6339 :
6340 86869 : void JSObject::RequireSlowElements(SeededNumberDictionary* dictionary) {
6341 173738 : if (dictionary->requires_slow_elements()) return;
6342 : dictionary->set_requires_slow_elements();
6343 53001 : if (map()->is_prototype_map()) {
6344 : // If this object is a prototype (the callee will check), invalidate any
6345 : // prototype chains involving it.
6346 : InvalidatePrototypeChains(map());
6347 : }
6348 : }
6349 :
6350 :
6351 304401 : Handle<SeededNumberDictionary> JSObject::NormalizeElements(
6352 : Handle<JSObject> object) {
6353 : DCHECK(!object->HasFixedTypedArrayElements());
6354 : Isolate* isolate = object->GetIsolate();
6355 304401 : bool is_sloppy_arguments = object->HasSloppyArgumentsElements();
6356 : {
6357 : DisallowHeapAllocation no_gc;
6358 : FixedArrayBase* elements = object->elements();
6359 :
6360 304401 : if (is_sloppy_arguments) {
6361 : elements = SloppyArgumentsElements::cast(elements)->arguments();
6362 : }
6363 :
6364 304401 : if (elements->IsDictionary()) {
6365 : return handle(SeededNumberDictionary::cast(elements), isolate);
6366 : }
6367 : }
6368 :
6369 : DCHECK(object->HasSmiOrObjectElements() || object->HasDoubleElements() ||
6370 : object->HasFastArgumentsElements() ||
6371 : object->HasFastStringWrapperElements());
6372 :
6373 : Handle<SeededNumberDictionary> dictionary =
6374 299028 : object->GetElementsAccessor()->Normalize(object);
6375 :
6376 : // Switch to using the dictionary as the backing storage for elements.
6377 : ElementsKind target_kind = is_sloppy_arguments
6378 : ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS
6379 298267 : : object->HasFastStringWrapperElements()
6380 : ? SLOW_STRING_WRAPPER_ELEMENTS
6381 597295 : : DICTIONARY_ELEMENTS;
6382 299028 : Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind);
6383 : // Set the new map first to satify the elements type assert in set_elements().
6384 299028 : JSObject::MigrateToMap(object, new_map);
6385 :
6386 299028 : if (is_sloppy_arguments) {
6387 : SloppyArgumentsElements::cast(object->elements())
6388 : ->set_arguments(*dictionary);
6389 : } else {
6390 298267 : object->set_elements(*dictionary);
6391 : }
6392 :
6393 299028 : isolate->counters()->elements_to_dictionary()->Increment();
6394 :
6395 : #ifdef DEBUG
6396 : if (FLAG_trace_normalization) {
6397 : OFStream os(stdout);
6398 : os << "Object elements have been normalized:\n";
6399 : object->Print(os);
6400 : }
6401 : #endif
6402 :
6403 : DCHECK(object->HasDictionaryElements() ||
6404 : object->HasSlowArgumentsElements() ||
6405 : object->HasSlowStringWrapperElements());
6406 299028 : return dictionary;
6407 : }
6408 :
6409 : namespace {
6410 :
6411 12001 : Object* SetHashAndUpdateProperties(HeapObject* properties, int hash) {
6412 : DCHECK_NE(PropertyArray::kNoHashSentinel, hash);
6413 : DCHECK(PropertyArray::HashField::is_valid(hash));
6414 :
6415 12199 : if (properties == properties->GetHeap()->empty_fixed_array() ||
6416 198 : properties == properties->GetHeap()->empty_property_dictionary()) {
6417 11803 : return Smi::FromInt(hash);
6418 : }
6419 :
6420 198 : if (properties->IsPropertyArray()) {
6421 85 : PropertyArray::cast(properties)->SetHash(hash);
6422 85 : return properties;
6423 : }
6424 :
6425 : DCHECK(properties->IsDictionary());
6426 : NameDictionary::cast(properties)->SetHash(hash);
6427 113 : return properties;
6428 : }
6429 :
6430 23869184 : int GetIdentityHashHelper(Isolate* isolate, JSReceiver* object) {
6431 : DisallowHeapAllocation no_gc;
6432 : Object* properties = object->raw_properties_or_hash();
6433 23869184 : if (properties->IsSmi()) {
6434 : return Smi::ToInt(properties);
6435 : }
6436 :
6437 23853363 : if (properties->IsPropertyArray()) {
6438 : return PropertyArray::cast(properties)->Hash();
6439 : }
6440 :
6441 21875803 : if (properties->IsDictionary()) {
6442 : return NameDictionary::cast(properties)->Hash();
6443 : }
6444 :
6445 : #ifdef DEBUG
6446 : FixedArray* empty_fixed_array = isolate->heap()->empty_fixed_array();
6447 : FixedArray* empty_property_dictionary =
6448 : isolate->heap()->empty_property_dictionary();
6449 : DCHECK(properties == empty_fixed_array ||
6450 : properties == empty_property_dictionary);
6451 : #endif
6452 :
6453 : return PropertyArray::kNoHashSentinel;
6454 : }
6455 : } // namespace
6456 :
6457 11853 : void JSReceiver::SetIdentityHash(int hash) {
6458 : DisallowHeapAllocation no_gc;
6459 : DCHECK_NE(PropertyArray::kNoHashSentinel, hash);
6460 : DCHECK(PropertyArray::HashField::is_valid(hash));
6461 :
6462 : HeapObject* existing_properties = HeapObject::cast(raw_properties_or_hash());
6463 : Object* new_properties =
6464 11853 : SetHashAndUpdateProperties(existing_properties, hash);
6465 11853 : set_raw_properties_or_hash(new_properties);
6466 11853 : }
6467 :
6468 23838196 : void JSReceiver::SetProperties(HeapObject* properties) {
6469 : DisallowHeapAllocation no_gc;
6470 : Isolate* isolate = properties->GetIsolate();
6471 23838196 : int hash = GetIdentityHashHelper(isolate, this);
6472 : Object* new_properties = properties;
6473 :
6474 : // TODO(cbruni): Make GetIdentityHashHelper return a bool so that we
6475 : // don't have to manually compare against kNoHashSentinel.
6476 23838196 : if (hash != PropertyArray::kNoHashSentinel) {
6477 148 : new_properties = SetHashAndUpdateProperties(properties, hash);
6478 : }
6479 :
6480 23838196 : set_raw_properties_or_hash(new_properties);
6481 23838196 : }
6482 :
6483 : template <typename ProxyType>
6484 388 : Smi* GetOrCreateIdentityHashHelper(Isolate* isolate, ProxyType* proxy) {
6485 : DisallowHeapAllocation no_gc;
6486 : Object* maybe_hash = proxy->hash();
6487 388 : if (maybe_hash->IsSmi()) return Smi::cast(maybe_hash);
6488 :
6489 364 : Smi* hash = Smi::FromInt(isolate->GenerateIdentityHash(Smi::kMaxValue));
6490 364 : proxy->set_hash(hash);
6491 364 : return hash;
6492 : }
6493 :
6494 31045 : Object* JSObject::GetIdentityHash(Isolate* isolate) {
6495 : DisallowHeapAllocation no_gc;
6496 31045 : if (IsJSGlobalProxy()) {
6497 56 : return JSGlobalProxy::cast(this)->hash();
6498 : }
6499 :
6500 30989 : int hash = GetIdentityHashHelper(isolate, this);
6501 30989 : if (hash == PropertyArray::kNoHashSentinel) {
6502 15109 : return isolate->heap()->undefined_value();
6503 : }
6504 :
6505 15880 : return Smi::FromInt(hash);
6506 : }
6507 :
6508 12457 : Smi* JSObject::GetOrCreateIdentityHash(Isolate* isolate) {
6509 : DisallowHeapAllocation no_gc;
6510 12457 : if (IsJSGlobalProxy()) {
6511 46 : return GetOrCreateIdentityHashHelper(isolate, JSGlobalProxy::cast(this));
6512 : }
6513 :
6514 12411 : Object* hash_obj = GetIdentityHash(isolate);
6515 12411 : if (!hash_obj->IsUndefined(isolate)) {
6516 : return Smi::cast(hash_obj);
6517 : }
6518 :
6519 11823 : int hash = isolate->GenerateIdentityHash(PropertyArray::HashField::kMax);
6520 : DCHECK_NE(PropertyArray::kNoHashSentinel, hash);
6521 :
6522 11823 : SetIdentityHash(hash);
6523 11823 : return Smi::FromInt(hash);
6524 : }
6525 :
6526 0 : Object* JSProxy::GetIdentityHash() { return hash(); }
6527 :
6528 0 : Smi* JSProxy::GetOrCreateIdentityHash(Isolate* isolate) {
6529 342 : return GetOrCreateIdentityHashHelper(isolate, this);
6530 : }
6531 :
6532 :
6533 158 : Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it,
6534 : ShouldThrow should_throw) {
6535 : Isolate* isolate = it->isolate();
6536 : // Make sure that the top context does not change when doing callbacks or
6537 : // interceptor calls.
6538 : AssertNoContextChange ncc(isolate);
6539 :
6540 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
6541 100 : Handle<InterceptorInfo> interceptor(it->GetInterceptor());
6542 100 : if (interceptor->deleter()->IsUndefined(isolate)) return Nothing<bool>();
6543 :
6544 : Handle<JSObject> holder = it->GetHolder<JSObject>();
6545 : Handle<Object> receiver = it->GetReceiver();
6546 58 : if (!receiver->IsJSReceiver()) {
6547 0 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
6548 : Object::ConvertReceiver(isolate, receiver),
6549 : Nothing<bool>());
6550 : }
6551 :
6552 : PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
6553 : *holder, should_throw);
6554 : Handle<Object> result;
6555 58 : if (it->IsElement()) {
6556 : uint32_t index = it->index();
6557 : v8::IndexedPropertyDeleterCallback deleter =
6558 : v8::ToCData<v8::IndexedPropertyDeleterCallback>(interceptor->deleter());
6559 23 : result = args.Call(deleter, index);
6560 : } else {
6561 : DCHECK_IMPLIES(it->name()->IsSymbol(),
6562 : interceptor->can_intercept_symbols());
6563 35 : Handle<Name> name = it->name();
6564 : DCHECK(!name->IsPrivate());
6565 : v8::GenericNamedPropertyDeleterCallback deleter =
6566 : v8::ToCData<v8::GenericNamedPropertyDeleterCallback>(
6567 : interceptor->deleter());
6568 35 : result = args.Call(deleter, name);
6569 : }
6570 :
6571 58 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6572 58 : if (result.is_null()) return Nothing<bool>();
6573 :
6574 : DCHECK(result->IsBoolean());
6575 : // Rebox CustomArguments::kReturnValueOffset before returning.
6576 : return Just(result->IsTrue(isolate));
6577 : }
6578 :
6579 89191 : void JSReceiver::DeleteNormalizedProperty(Handle<JSReceiver> object,
6580 : int entry) {
6581 : DCHECK(!object->HasFastProperties());
6582 : Isolate* isolate = object->GetIsolate();
6583 :
6584 89191 : if (object->IsJSGlobalObject()) {
6585 : // If we have a global object, invalidate the cell and swap in a new one.
6586 : Handle<GlobalDictionary> dictionary(
6587 : JSGlobalObject::cast(*object)->global_dictionary());
6588 : DCHECK_NE(GlobalDictionary::kNotFound, entry);
6589 :
6590 10784 : auto cell = PropertyCell::InvalidateEntry(dictionary, entry);
6591 21568 : cell->set_value(isolate->heap()->the_hole_value());
6592 : cell->set_property_details(
6593 : PropertyDetails::Empty(PropertyCellType::kUninitialized));
6594 : } else {
6595 : Handle<NameDictionary> dictionary(object->property_dictionary());
6596 : DCHECK_NE(NameDictionary::kNotFound, entry);
6597 :
6598 78407 : dictionary = NameDictionary::DeleteEntry(dictionary, entry);
6599 78407 : object->SetProperties(*dictionary);
6600 : }
6601 89191 : }
6602 :
6603 :
6604 3017171 : Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
6605 : LanguageMode language_mode) {
6606 1003500 : it->UpdateProtector();
6607 :
6608 : Isolate* isolate = it->isolate();
6609 :
6610 1003500 : if (it->state() == LookupIterator::JSPROXY) {
6611 : return JSProxy::DeletePropertyOrElement(it->GetHolder<JSProxy>(),
6612 3097 : it->GetName(), language_mode);
6613 : }
6614 :
6615 1000403 : if (it->GetReceiver()->IsJSProxy()) {
6616 39 : if (it->state() != LookupIterator::NOT_FOUND) {
6617 : DCHECK_EQ(LookupIterator::DATA, it->state());
6618 : DCHECK(it->name()->IsPrivate());
6619 6 : it->Delete();
6620 : }
6621 : return Just(true);
6622 : }
6623 : Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
6624 :
6625 2020264 : for (; it->IsFound(); it->Next()) {
6626 213018 : switch (it->state()) {
6627 : case LookupIterator::JSPROXY:
6628 : case LookupIterator::NOT_FOUND:
6629 : case LookupIterator::TRANSITION:
6630 0 : UNREACHABLE();
6631 : case LookupIterator::ACCESS_CHECK:
6632 9728 : if (it->HasAccess()) break;
6633 36 : isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
6634 36 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6635 : return Just(false);
6636 : case LookupIterator::INTERCEPTOR: {
6637 : ShouldThrow should_throw =
6638 100 : is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
6639 : Maybe<bool> result =
6640 100 : JSObject::DeletePropertyWithInterceptor(it, should_throw);
6641 : // An exception was thrown in the interceptor. Propagate.
6642 124 : if (isolate->has_pending_exception()) return Nothing<bool>();
6643 : // Delete with interceptor succeeded. Return result.
6644 : // TODO(neis): In strict mode, we should probably throw if the
6645 : // interceptor returns false.
6646 100 : if (result.IsJust()) return result;
6647 76 : break;
6648 : }
6649 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
6650 : return Just(true);
6651 : case LookupIterator::DATA:
6652 : case LookupIterator::ACCESSOR: {
6653 203145 : if (!it->IsConfigurable()) {
6654 : // Fail if the property is not configurable.
6655 2309 : if (is_strict(language_mode)) {
6656 : isolate->Throw(*isolate->factory()->NewTypeError(
6657 : MessageTemplate::kStrictDeleteProperty, it->GetName(),
6658 1671 : receiver));
6659 : return Nothing<bool>();
6660 : }
6661 : return Just(false);
6662 : }
6663 :
6664 200836 : it->Delete();
6665 :
6666 : return Just(true);
6667 : }
6668 : }
6669 : }
6670 :
6671 : return Just(true);
6672 : }
6673 :
6674 :
6675 10 : Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index,
6676 : LanguageMode language_mode) {
6677 : LookupIterator it(object->GetIsolate(), object, index, object,
6678 : LookupIterator::OWN);
6679 10 : return DeleteProperty(&it, language_mode);
6680 : }
6681 :
6682 :
6683 902 : Maybe<bool> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
6684 : Handle<Name> name,
6685 : LanguageMode language_mode) {
6686 902 : LookupIterator it(object, name, object, LookupIterator::OWN);
6687 902 : return DeleteProperty(&it, language_mode);
6688 : }
6689 :
6690 :
6691 3785 : Maybe<bool> JSReceiver::DeletePropertyOrElement(Handle<JSReceiver> object,
6692 : Handle<Name> name,
6693 : LanguageMode language_mode) {
6694 : LookupIterator it = LookupIterator::PropertyOrElement(
6695 3785 : name->GetIsolate(), object, name, object, LookupIterator::OWN);
6696 3785 : return DeleteProperty(&it, language_mode);
6697 : }
6698 :
6699 : // ES6 19.1.2.4
6700 : // static
6701 191234 : Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object,
6702 : Handle<Object> key,
6703 : Handle<Object> attributes) {
6704 : // 1. If Type(O) is not Object, throw a TypeError exception.
6705 191234 : if (!object->IsJSReceiver()) {
6706 : Handle<String> fun_name =
6707 67 : isolate->factory()->InternalizeUtf8String("Object.defineProperty");
6708 134 : THROW_NEW_ERROR_RETURN_FAILURE(
6709 : isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name));
6710 : }
6711 : // 2. Let key be ToPropertyKey(P).
6712 : // 3. ReturnIfAbrupt(key).
6713 382334 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key, ToPropertyKey(isolate, key));
6714 : // 4. Let desc be ToPropertyDescriptor(Attributes).
6715 : // 5. ReturnIfAbrupt(desc).
6716 : PropertyDescriptor desc;
6717 191167 : if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) {
6718 140 : return isolate->heap()->exception();
6719 : }
6720 : // 6. Let success be DefinePropertyOrThrow(O,key, desc).
6721 : Maybe<bool> success = DefineOwnProperty(
6722 191027 : isolate, Handle<JSReceiver>::cast(object), key, &desc, THROW_ON_ERROR);
6723 : // 7. ReturnIfAbrupt(success).
6724 191027 : MAYBE_RETURN(success, isolate->heap()->exception());
6725 189929 : CHECK(success.FromJust());
6726 : // 8. Return O.
6727 189929 : return *object;
6728 : }
6729 :
6730 :
6731 : // ES6 19.1.2.3.1
6732 : // static
6733 13173 : MaybeHandle<Object> JSReceiver::DefineProperties(Isolate* isolate,
6734 : Handle<Object> object,
6735 : Handle<Object> properties) {
6736 : // 1. If Type(O) is not Object, throw a TypeError exception.
6737 13173 : if (!object->IsJSReceiver()) {
6738 : Handle<String> fun_name =
6739 28 : isolate->factory()->InternalizeUtf8String("Object.defineProperties");
6740 56 : THROW_NEW_ERROR(isolate,
6741 : NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name),
6742 : Object);
6743 : }
6744 : // 2. Let props be ToObject(Properties).
6745 : // 3. ReturnIfAbrupt(props).
6746 : Handle<JSReceiver> props;
6747 26290 : ASSIGN_RETURN_ON_EXCEPTION(isolate, props,
6748 : Object::ToObject(isolate, properties), Object);
6749 :
6750 : // 4. Let keys be props.[[OwnPropertyKeys]]().
6751 : // 5. ReturnIfAbrupt(keys).
6752 : Handle<FixedArray> keys;
6753 26270 : ASSIGN_RETURN_ON_EXCEPTION(
6754 : isolate, keys, KeyAccumulator::GetKeys(props, KeyCollectionMode::kOwnOnly,
6755 : ALL_PROPERTIES),
6756 : Object);
6757 : // 6. Let descriptors be an empty List.
6758 : int capacity = keys->length();
6759 13135 : std::vector<PropertyDescriptor> descriptors(capacity);
6760 : size_t descriptors_index = 0;
6761 : // 7. Repeat for each element nextKey of keys in List order,
6762 251706 : for (int i = 0; i < keys->length(); ++i) {
6763 : Handle<Object> next_key(keys->get(i), isolate);
6764 : // 7a. Let propDesc be props.[[GetOwnProperty]](nextKey).
6765 : // 7b. ReturnIfAbrupt(propDesc).
6766 112952 : bool success = false;
6767 : LookupIterator it = LookupIterator::PropertyOrElement(
6768 112952 : isolate, props, next_key, &success, LookupIterator::OWN);
6769 : DCHECK(success);
6770 112952 : Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
6771 112952 : if (!maybe.IsJust()) return MaybeHandle<Object>();
6772 : PropertyAttributes attrs = maybe.FromJust();
6773 : // 7c. If propDesc is not undefined and propDesc.[[Enumerable]] is true:
6774 114098 : if (attrs == ABSENT) continue;
6775 112952 : if (attrs & DONT_ENUM) continue;
6776 : // 7c i. Let descObj be Get(props, nextKey).
6777 : // 7c ii. ReturnIfAbrupt(descObj).
6778 : Handle<Object> desc_obj;
6779 223612 : ASSIGN_RETURN_ON_EXCEPTION(isolate, desc_obj, Object::GetProperty(&it),
6780 : Object);
6781 : // 7c iii. Let desc be ToPropertyDescriptor(descObj).
6782 : success = PropertyDescriptor::ToPropertyDescriptor(
6783 223612 : isolate, desc_obj, &descriptors[descriptors_index]);
6784 : // 7c iv. ReturnIfAbrupt(desc).
6785 111806 : if (!success) return MaybeHandle<Object>();
6786 : // 7c v. Append the pair (a two element List) consisting of nextKey and
6787 : // desc to the end of descriptors.
6788 111572 : descriptors[descriptors_index].set_name(next_key);
6789 111572 : descriptors_index++;
6790 : }
6791 : // 8. For each pair from descriptors in list order,
6792 111163 : for (size_t i = 0; i < descriptors_index; ++i) {
6793 111163 : PropertyDescriptor* desc = &descriptors[i];
6794 : // 8a. Let P be the first element of pair.
6795 : // 8b. Let desc be the second element of pair.
6796 : // 8c. Let status be DefinePropertyOrThrow(O, P, desc).
6797 : Maybe<bool> status =
6798 : DefineOwnProperty(isolate, Handle<JSReceiver>::cast(object),
6799 111163 : desc->name(), desc, THROW_ON_ERROR);
6800 : // 8d. ReturnIfAbrupt(status).
6801 111163 : if (!status.IsJust()) return MaybeHandle<Object>();
6802 111163 : CHECK(status.FromJust());
6803 : }
6804 : // 9. Return o.
6805 12901 : return object;
6806 : }
6807 :
6808 :
6809 : // static
6810 697020 : Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate,
6811 : Handle<JSReceiver> object,
6812 : Handle<Object> key,
6813 : PropertyDescriptor* desc,
6814 : ShouldThrow should_throw) {
6815 697020 : if (object->IsJSArray()) {
6816 : return JSArray::DefineOwnProperty(isolate, Handle<JSArray>::cast(object),
6817 53697 : key, desc, should_throw);
6818 : }
6819 643323 : if (object->IsJSProxy()) {
6820 : return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object),
6821 4005 : key, desc, should_throw);
6822 : }
6823 639318 : if (object->IsJSTypedArray()) {
6824 : return JSTypedArray::DefineOwnProperty(
6825 3119 : isolate, Handle<JSTypedArray>::cast(object), key, desc, should_throw);
6826 : }
6827 : // TODO(neis): Special case for JSModuleNamespace?
6828 :
6829 : // OrdinaryDefineOwnProperty, by virtue of calling
6830 : // DefineOwnPropertyIgnoreAttributes, can handle arguments
6831 : // (ES#sec-arguments-exotic-objects-defineownproperty-p-desc).
6832 : return OrdinaryDefineOwnProperty(isolate, Handle<JSObject>::cast(object), key,
6833 636199 : desc, should_throw);
6834 : }
6835 :
6836 :
6837 : // static
6838 708304 : Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate,
6839 : Handle<JSObject> object,
6840 : Handle<Object> key,
6841 : PropertyDescriptor* desc,
6842 : ShouldThrow should_throw) {
6843 708304 : bool success = false;
6844 : DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
6845 : LookupIterator it = LookupIterator::PropertyOrElement(
6846 708304 : isolate, object, key, &success, LookupIterator::OWN);
6847 : DCHECK(success); // ...so creating a LookupIterator can't fail.
6848 :
6849 : // Deal with access checks first.
6850 708304 : if (it.state() == LookupIterator::ACCESS_CHECK) {
6851 2483 : if (!it.HasAccess()) {
6852 30 : isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>());
6853 30 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6854 : return Just(true);
6855 : }
6856 2453 : it.Next();
6857 : }
6858 :
6859 708274 : return OrdinaryDefineOwnProperty(&it, desc, should_throw);
6860 : }
6861 :
6862 :
6863 : // ES6 9.1.6.1
6864 : // static
6865 1642146 : Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
6866 : PropertyDescriptor* desc,
6867 : ShouldThrow should_throw) {
6868 : Isolate* isolate = it->isolate();
6869 : // 1. Let current be O.[[GetOwnProperty]](P).
6870 : // 2. ReturnIfAbrupt(current).
6871 : PropertyDescriptor current;
6872 708274 : MAYBE_RETURN(GetOwnPropertyDescriptor(it, ¤t), Nothing<bool>());
6873 :
6874 708274 : it->Restart();
6875 : // Handle interceptor
6876 1867744 : for (; it->IsFound(); it->Next()) {
6877 225652 : if (it->state() == LookupIterator::INTERCEPTOR) {
6878 178 : if (it->HolderIsReceiverOrHiddenPrototype()) {
6879 : Maybe<bool> result = DefinePropertyWithInterceptorInternal(
6880 178 : it, it->GetInterceptor(), should_throw, *desc);
6881 356 : if (result.IsNothing() || result.FromJust()) {
6882 54 : return result;
6883 : }
6884 : }
6885 : }
6886 : }
6887 :
6888 : // TODO(jkummerow/verwaest): It would be nice if we didn't have to reset
6889 : // the iterator every time. Currently, the reasons why we need it are:
6890 : // - handle interceptors correctly
6891 : // - handle accessors correctly (which might change the holder's map)
6892 708220 : it->Restart();
6893 : // 3. Let extensible be the value of the [[Extensible]] internal slot of O.
6894 708220 : Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
6895 708220 : bool extensible = JSObject::IsExtensible(object);
6896 :
6897 : return ValidateAndApplyPropertyDescriptor(
6898 708220 : isolate, it, extensible, desc, ¤t, should_throw, Handle<Name>());
6899 : }
6900 :
6901 :
6902 : // ES6 9.1.6.2
6903 : // static
6904 0 : Maybe<bool> JSReceiver::IsCompatiblePropertyDescriptor(
6905 : Isolate* isolate, bool extensible, PropertyDescriptor* desc,
6906 : PropertyDescriptor* current, Handle<Name> property_name,
6907 : ShouldThrow should_throw) {
6908 : // 1. Return ValidateAndApplyPropertyDescriptor(undefined, undefined,
6909 : // Extensible, Desc, Current).
6910 : return ValidateAndApplyPropertyDescriptor(
6911 4522 : isolate, nullptr, extensible, desc, current, should_throw, property_name);
6912 : }
6913 :
6914 :
6915 : // ES6 9.1.6.3
6916 : // static
6917 712742 : Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor(
6918 : Isolate* isolate, LookupIterator* it, bool extensible,
6919 : PropertyDescriptor* desc, PropertyDescriptor* current,
6920 : ShouldThrow should_throw, Handle<Name> property_name) {
6921 : // We either need a LookupIterator, or a property name.
6922 : DCHECK((it == nullptr) != property_name.is_null());
6923 : Handle<JSObject> object;
6924 : if (it != nullptr) object = Handle<JSObject>::cast(it->GetReceiver());
6925 : bool desc_is_data_descriptor = PropertyDescriptor::IsDataDescriptor(desc);
6926 : bool desc_is_accessor_descriptor =
6927 : PropertyDescriptor::IsAccessorDescriptor(desc);
6928 : bool desc_is_generic_descriptor =
6929 : PropertyDescriptor::IsGenericDescriptor(desc);
6930 : // 1. (Assert)
6931 : // 2. If current is undefined, then
6932 712742 : if (current->is_empty()) {
6933 : // 2a. If extensible is false, return false.
6934 487842 : if (!extensible) {
6935 325 : RETURN_FAILURE(
6936 : isolate, should_throw,
6937 : NewTypeError(MessageTemplate::kDefineDisallowed,
6938 : it != nullptr ? it->GetName() : property_name));
6939 : }
6940 : // 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then:
6941 : // (This is equivalent to !IsAccessorDescriptor(desc).)
6942 : DCHECK((desc_is_generic_descriptor || desc_is_data_descriptor) ==
6943 : !desc_is_accessor_descriptor);
6944 487724 : if (!desc_is_accessor_descriptor) {
6945 : // 2c i. If O is not undefined, create an own data property named P of
6946 : // object O whose [[Value]], [[Writable]], [[Enumerable]] and
6947 : // [[Configurable]] attribute values are described by Desc. If the value
6948 : // of an attribute field of Desc is absent, the attribute of the newly
6949 : // created property is set to its default value.
6950 419303 : if (it != nullptr) {
6951 416801 : if (!desc->has_writable()) desc->set_writable(false);
6952 416801 : if (!desc->has_enumerable()) desc->set_enumerable(false);
6953 416801 : if (!desc->has_configurable()) desc->set_configurable(false);
6954 : Handle<Object> value(
6955 : desc->has_value()
6956 : ? desc->value()
6957 502522 : : Handle<Object>::cast(isolate->factory()->undefined_value()));
6958 : MaybeHandle<Object> result =
6959 : JSObject::DefineOwnPropertyIgnoreAttributes(it, value,
6960 416801 : desc->ToAttributes());
6961 416801 : if (result.is_null()) return Nothing<bool>();
6962 : }
6963 : } else {
6964 : // 2d. Else Desc must be an accessor Property Descriptor,
6965 : DCHECK(desc_is_accessor_descriptor);
6966 : // 2d i. If O is not undefined, create an own accessor property named P
6967 : // of object O whose [[Get]], [[Set]], [[Enumerable]] and
6968 : // [[Configurable]] attribute values are described by Desc. If the value
6969 : // of an attribute field of Desc is absent, the attribute of the newly
6970 : // created property is set to its default value.
6971 68421 : if (it != nullptr) {
6972 68277 : if (!desc->has_enumerable()) desc->set_enumerable(false);
6973 68277 : if (!desc->has_configurable()) desc->set_configurable(false);
6974 : Handle<Object> getter(
6975 : desc->has_get()
6976 : ? desc->get()
6977 80797 : : Handle<Object>::cast(isolate->factory()->null_value()));
6978 : Handle<Object> setter(
6979 : desc->has_set()
6980 : ? desc->set()
6981 110229 : : Handle<Object>::cast(isolate->factory()->null_value()));
6982 : MaybeHandle<Object> result =
6983 68277 : JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes());
6984 68277 : if (result.is_null()) return Nothing<bool>();
6985 : }
6986 : }
6987 : // 2e. Return true.
6988 : return Just(true);
6989 : }
6990 : // 3. Return true, if every field in Desc is absent.
6991 : // 4. Return true, if every field in Desc also occurs in current and the
6992 : // value of every field in Desc is the same value as the corresponding field
6993 : // in current when compared using the SameValue algorithm.
6994 394229 : if ((!desc->has_enumerable() ||
6995 95891 : desc->enumerable() == current->enumerable()) &&
6996 58967 : (!desc->has_configurable() ||
6997 93437 : desc->configurable() == current->configurable()) &&
6998 76298 : (!desc->has_value() ||
6999 142825 : (current->has_value() && current->value()->SameValue(*desc->value()))) &&
7000 50461 : (!desc->has_writable() ||
7001 104519 : (current->has_writable() && current->writable() == desc->writable())) &&
7002 5503 : (!desc->has_get() ||
7003 277630 : (current->has_get() && current->get()->SameValue(*desc->get()))) &&
7004 7225 : (!desc->has_set() ||
7005 7030 : (current->has_set() && current->set()->SameValue(*desc->set())))) {
7006 : return Just(true);
7007 : }
7008 : // 5. If the [[Configurable]] field of current is false, then
7009 183258 : if (!current->configurable()) {
7010 : // 5a. Return false, if the [[Configurable]] field of Desc is true.
7011 19832 : if (desc->has_configurable() && desc->configurable()) {
7012 585 : RETURN_FAILURE(
7013 : isolate, should_throw,
7014 : NewTypeError(MessageTemplate::kRedefineDisallowed,
7015 : it != nullptr ? it->GetName() : property_name));
7016 : }
7017 : // 5b. Return false, if the [[Enumerable]] field of Desc is present and the
7018 : // [[Enumerable]] fields of current and Desc are the Boolean negation of
7019 : // each other.
7020 19160 : if (desc->has_enumerable() && desc->enumerable() != current->enumerable()) {
7021 296 : RETURN_FAILURE(
7022 : isolate, should_throw,
7023 : NewTypeError(MessageTemplate::kRedefineDisallowed,
7024 : it != nullptr ? it->GetName() : property_name));
7025 : }
7026 : }
7027 :
7028 : bool current_is_data_descriptor =
7029 : PropertyDescriptor::IsDataDescriptor(current);
7030 : // 6. If IsGenericDescriptor(Desc) is true, no further validation is required.
7031 182935 : if (desc_is_generic_descriptor) {
7032 : // Nothing to see here.
7033 :
7034 : // 7. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) have
7035 : // different results, then:
7036 181997 : } else if (current_is_data_descriptor != desc_is_data_descriptor) {
7037 : // 7a. Return false, if the [[Configurable]] field of current is false.
7038 130545 : if (!current->configurable()) {
7039 448 : RETURN_FAILURE(
7040 : isolate, should_throw,
7041 : NewTypeError(MessageTemplate::kRedefineDisallowed,
7042 : it != nullptr ? it->GetName() : property_name));
7043 : }
7044 : // 7b. If IsDataDescriptor(current) is true, then:
7045 : if (current_is_data_descriptor) {
7046 : // 7b i. If O is not undefined, convert the property named P of object O
7047 : // from a data property to an accessor property. Preserve the existing
7048 : // values of the converted property's [[Configurable]] and [[Enumerable]]
7049 : // attributes and set the rest of the property's attributes to their
7050 : // default values.
7051 : // --> Folded into step 10.
7052 : } else {
7053 : // 7c i. If O is not undefined, convert the property named P of object O
7054 : // from an accessor property to a data property. Preserve the existing
7055 : // values of the converted property’s [[Configurable]] and [[Enumerable]]
7056 : // attributes and set the rest of the property’s attributes to their
7057 : // default values.
7058 : // --> Folded into step 10.
7059 : }
7060 :
7061 : // 8. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both
7062 : // true, then:
7063 51452 : } else if (current_is_data_descriptor && desc_is_data_descriptor) {
7064 : // 8a. If the [[Configurable]] field of current is false, then:
7065 40427 : if (!current->configurable()) {
7066 : // 8a i. Return false, if the [[Writable]] field of current is false and
7067 : // the [[Writable]] field of Desc is true.
7068 16159 : if (!current->writable() && desc->has_writable() && desc->writable()) {
7069 193 : RETURN_FAILURE(
7070 : isolate, should_throw,
7071 : NewTypeError(MessageTemplate::kRedefineDisallowed,
7072 : it != nullptr ? it->GetName() : property_name));
7073 : }
7074 : // 8a ii. If the [[Writable]] field of current is false, then:
7075 15731 : if (!current->writable()) {
7076 : // 8a ii 1. Return false, if the [[Value]] field of Desc is present and
7077 : // SameValue(Desc.[[Value]], current.[[Value]]) is false.
7078 488 : if (desc->has_value() && !desc->value()->SameValue(*current->value())) {
7079 811 : RETURN_FAILURE(
7080 : isolate, should_throw,
7081 : NewTypeError(MessageTemplate::kRedefineDisallowed,
7082 : it != nullptr ? it->GetName() : property_name));
7083 : }
7084 : }
7085 : }
7086 : } else {
7087 : // 9. Else IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc)
7088 : // are both true,
7089 : DCHECK(PropertyDescriptor::IsAccessorDescriptor(current) &&
7090 : desc_is_accessor_descriptor);
7091 : // 9a. If the [[Configurable]] field of current is false, then:
7092 11025 : if (!current->configurable()) {
7093 : // 9a i. Return false, if the [[Set]] field of Desc is present and
7094 : // SameValue(Desc.[[Set]], current.[[Set]]) is false.
7095 147 : if (desc->has_set() && !desc->set()->SameValue(*current->set())) {
7096 121 : RETURN_FAILURE(
7097 : isolate, should_throw,
7098 : NewTypeError(MessageTemplate::kRedefineDisallowed,
7099 : it != nullptr ? it->GetName() : property_name));
7100 : }
7101 : // 9a ii. Return false, if the [[Get]] field of Desc is present and
7102 : // SameValue(Desc.[[Get]], current.[[Get]]) is false.
7103 108 : if (desc->has_get() && !desc->get()->SameValue(*current->get())) {
7104 174 : RETURN_FAILURE(
7105 : isolate, should_throw,
7106 : NewTypeError(MessageTemplate::kRedefineDisallowed,
7107 : it != nullptr ? it->GetName() : property_name));
7108 : }
7109 : }
7110 : }
7111 :
7112 : // 10. If O is not undefined, then:
7113 182412 : if (it != nullptr) {
7114 : // 10a. For each field of Desc that is present, set the corresponding
7115 : // attribute of the property named P of object O to the value of the field.
7116 : PropertyAttributes attrs = NONE;
7117 :
7118 182178 : if (desc->has_enumerable()) {
7119 : attrs = static_cast<PropertyAttributes>(
7120 134344 : attrs | (desc->enumerable() ? NONE : DONT_ENUM));
7121 : } else {
7122 : attrs = static_cast<PropertyAttributes>(
7123 47834 : attrs | (current->enumerable() ? NONE : DONT_ENUM));
7124 : }
7125 182178 : if (desc->has_configurable()) {
7126 : attrs = static_cast<PropertyAttributes>(
7127 146287 : attrs | (desc->configurable() ? NONE : DONT_DELETE));
7128 : } else {
7129 : attrs = static_cast<PropertyAttributes>(
7130 35891 : attrs | (current->configurable() ? NONE : DONT_DELETE));
7131 : }
7132 324011 : if (desc_is_data_descriptor ||
7133 141833 : (desc_is_generic_descriptor && current_is_data_descriptor)) {
7134 41178 : if (desc->has_writable()) {
7135 : attrs = static_cast<PropertyAttributes>(
7136 38267 : attrs | (desc->writable() ? NONE : READ_ONLY));
7137 : } else {
7138 : attrs = static_cast<PropertyAttributes>(
7139 2911 : attrs | (current->writable() ? NONE : READ_ONLY));
7140 : }
7141 : Handle<Object> value(
7142 : desc->has_value() ? desc->value()
7143 : : current->has_value()
7144 : ? current->value()
7145 : : Handle<Object>::cast(
7146 43971 : isolate->factory()->undefined_value()));
7147 : return JSObject::DefineOwnPropertyIgnoreAttributes(it, value, attrs,
7148 41178 : should_throw);
7149 : } else {
7150 : DCHECK(desc_is_accessor_descriptor ||
7151 : (desc_is_generic_descriptor &&
7152 : PropertyDescriptor::IsAccessorDescriptor(current)));
7153 : Handle<Object> getter(
7154 : desc->has_get()
7155 : ? desc->get()
7156 : : current->has_get()
7157 : ? current->get()
7158 148554 : : Handle<Object>::cast(isolate->factory()->null_value()));
7159 : Handle<Object> setter(
7160 : desc->has_set()
7161 : ? desc->set()
7162 : : current->has_set()
7163 : ? current->set()
7164 403565 : : Handle<Object>::cast(isolate->factory()->null_value()));
7165 : MaybeHandle<Object> result =
7166 141000 : JSObject::DefineAccessor(it, getter, setter, attrs);
7167 141000 : if (result.is_null()) return Nothing<bool>();
7168 : }
7169 : }
7170 :
7171 : // 11. Return true.
7172 : return Just(true);
7173 : }
7174 :
7175 :
7176 : // static
7177 1110623 : Maybe<bool> JSReceiver::CreateDataProperty(LookupIterator* it,
7178 : Handle<Object> value,
7179 : ShouldThrow should_throw) {
7180 : DCHECK(!it->check_prototype_chain());
7181 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
7182 : Isolate* isolate = receiver->GetIsolate();
7183 :
7184 1110623 : if (receiver->IsJSObject()) {
7185 1109722 : return JSObject::CreateDataProperty(it, value, should_throw); // Shortcut.
7186 : }
7187 :
7188 : PropertyDescriptor new_desc;
7189 : new_desc.set_value(value);
7190 : new_desc.set_writable(true);
7191 : new_desc.set_enumerable(true);
7192 : new_desc.set_configurable(true);
7193 :
7194 : return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
7195 1802 : &new_desc, should_throw);
7196 : }
7197 :
7198 2223907 : Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it,
7199 : Handle<Object> value,
7200 : ShouldThrow should_throw) {
7201 : DCHECK(it->GetReceiver()->IsJSObject());
7202 1111956 : MAYBE_RETURN(JSReceiver::GetPropertyAttributes(it), Nothing<bool>());
7203 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
7204 : Isolate* isolate = receiver->GetIsolate();
7205 :
7206 1111951 : if (it->IsFound()) {
7207 338 : Maybe<PropertyAttributes> attributes = GetPropertyAttributes(it);
7208 376 : MAYBE_RETURN(attributes, Nothing<bool>());
7209 338 : if ((attributes.FromJust() & DONT_DELETE) != 0) {
7210 122 : RETURN_FAILURE(
7211 : isolate, should_throw,
7212 : NewTypeError(MessageTemplate::kRedefineDisallowed, it->GetName()));
7213 : }
7214 : } else {
7215 1111613 : if (!JSObject::IsExtensible(Handle<JSObject>::cast(it->GetReceiver()))) {
7216 229 : RETURN_FAILURE(
7217 : isolate, should_throw,
7218 : NewTypeError(MessageTemplate::kDefineDisallowed, it->GetName()));
7219 : }
7220 : }
7221 :
7222 2223704 : RETURN_ON_EXCEPTION_VALUE(it->isolate(),
7223 : DefineOwnPropertyIgnoreAttributes(it, value, NONE),
7224 : Nothing<bool>());
7225 :
7226 : return Just(true);
7227 : }
7228 :
7229 :
7230 : // TODO(jkummerow): Consider unification with FastAsArrayLength() in
7231 : // accessors.cc.
7232 43230 : bool PropertyKeyToArrayLength(Handle<Object> value, uint32_t* length) {
7233 : DCHECK(value->IsNumber() || value->IsName());
7234 43230 : if (value->ToArrayLength(length)) return true;
7235 58293 : if (value->IsString()) return String::cast(*value)->AsArrayIndex(length);
7236 : return false;
7237 : }
7238 :
7239 0 : bool PropertyKeyToArrayIndex(Handle<Object> index_obj, uint32_t* output) {
7240 43230 : return PropertyKeyToArrayLength(index_obj, output) && *output != kMaxUInt32;
7241 : }
7242 :
7243 :
7244 : // ES6 9.4.2.1
7245 : // static
7246 55327 : Maybe<bool> JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o,
7247 : Handle<Object> name,
7248 : PropertyDescriptor* desc,
7249 : ShouldThrow should_throw) {
7250 : // 1. Assert: IsPropertyKey(P) is true. ("P" is |name|.)
7251 : // 2. If P is "length", then:
7252 : // TODO(jkummerow): Check if we need slow string comparison.
7253 55327 : if (*name == isolate->heap()->length_string()) {
7254 : // 2a. Return ArraySetLength(A, Desc).
7255 12097 : return ArraySetLength(isolate, o, desc, should_throw);
7256 : }
7257 : // 3. Else if P is an array index, then:
7258 43230 : uint32_t index = 0;
7259 43230 : if (PropertyKeyToArrayIndex(name, &index)) {
7260 : // 3a. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
7261 : PropertyDescriptor old_len_desc;
7262 : Maybe<bool> success = GetOwnPropertyDescriptor(
7263 38968 : isolate, o, isolate->factory()->length_string(), &old_len_desc);
7264 : // 3b. (Assert)
7265 : DCHECK(success.FromJust());
7266 : USE(success);
7267 : // 3c. Let oldLen be oldLenDesc.[[Value]].
7268 38968 : uint32_t old_len = 0;
7269 38968 : CHECK(old_len_desc.value()->ToArrayLength(&old_len));
7270 : // 3d. Let index be ToUint32(P).
7271 : // (Already done above.)
7272 : // 3e. (Assert)
7273 : // 3f. If index >= oldLen and oldLenDesc.[[Writable]] is false,
7274 : // return false.
7275 66760 : if (index >= old_len && old_len_desc.has_writable() &&
7276 : !old_len_desc.writable()) {
7277 0 : RETURN_FAILURE(isolate, should_throw,
7278 : NewTypeError(MessageTemplate::kDefineDisallowed, name));
7279 : }
7280 : // 3g. Let succeeded be OrdinaryDefineOwnProperty(A, P, Desc).
7281 : Maybe<bool> succeeded =
7282 38968 : OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
7283 : // 3h. Assert: succeeded is not an abrupt completion.
7284 : // In our case, if should_throw == THROW_ON_ERROR, it can be!
7285 : // 3i. If succeeded is false, return false.
7286 77849 : if (succeeded.IsNothing() || !succeeded.FromJust()) return succeeded;
7287 : // 3j. If index >= oldLen, then:
7288 38872 : if (index >= old_len) {
7289 : // 3j i. Set oldLenDesc.[[Value]] to index + 1.
7290 13896 : old_len_desc.set_value(isolate->factory()->NewNumberFromUint(index + 1));
7291 : // 3j ii. Let succeeded be
7292 : // OrdinaryDefineOwnProperty(A, "length", oldLenDesc).
7293 : succeeded = OrdinaryDefineOwnProperty(isolate, o,
7294 : isolate->factory()->length_string(),
7295 13896 : &old_len_desc, should_throw);
7296 : // 3j iii. Assert: succeeded is true.
7297 : DCHECK(succeeded.FromJust());
7298 : USE(succeeded);
7299 : }
7300 : // 3k. Return true.
7301 : return Just(true);
7302 : }
7303 :
7304 : // 4. Return OrdinaryDefineOwnProperty(A, P, Desc).
7305 4262 : return OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
7306 : }
7307 :
7308 :
7309 : // Part of ES6 9.4.2.4 ArraySetLength.
7310 : // static
7311 538625 : bool JSArray::AnythingToArrayLength(Isolate* isolate,
7312 : Handle<Object> length_object,
7313 : uint32_t* output) {
7314 : // Fast path: check numbers and strings that can be converted directly
7315 : // and unobservably.
7316 538625 : if (length_object->ToArrayLength(output)) return true;
7317 473825 : if (length_object->IsString() &&
7318 20 : Handle<String>::cast(length_object)->AsArrayIndex(output)) {
7319 : return true;
7320 : }
7321 : // Slow path: follow steps in ES6 9.4.2.4 "ArraySetLength".
7322 : // 3. Let newLen be ToUint32(Desc.[[Value]]).
7323 : Handle<Object> uint32_v;
7324 947590 : if (!Object::ToUint32(isolate, length_object).ToHandle(&uint32_v)) {
7325 : // 4. ReturnIfAbrupt(newLen).
7326 : return false;
7327 : }
7328 : // 5. Let numberLen be ToNumber(Desc.[[Value]]).
7329 : Handle<Object> number_v;
7330 947570 : if (!Object::ToNumber(length_object).ToHandle(&number_v)) {
7331 : // 6. ReturnIfAbrupt(newLen).
7332 : return false;
7333 : }
7334 : // 7. If newLen != numberLen, throw a RangeError exception.
7335 473785 : if (uint32_v->Number() != number_v->Number()) {
7336 : Handle<Object> exception =
7337 256 : isolate->factory()->NewRangeError(MessageTemplate::kInvalidArrayLength);
7338 256 : isolate->Throw(*exception);
7339 : return false;
7340 : }
7341 473529 : CHECK(uint32_v->ToArrayLength(output));
7342 : return true;
7343 : }
7344 :
7345 :
7346 : // ES6 9.4.2.4
7347 : // static
7348 12097 : Maybe<bool> JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a,
7349 : PropertyDescriptor* desc,
7350 : ShouldThrow should_throw) {
7351 : // 1. If the [[Value]] field of Desc is absent, then
7352 12097 : if (!desc->has_value()) {
7353 : // 1a. Return OrdinaryDefineOwnProperty(A, "length", Desc).
7354 : return OrdinaryDefineOwnProperty(
7355 264 : isolate, a, isolate->factory()->length_string(), desc, should_throw);
7356 : }
7357 : // 2. Let newLenDesc be a copy of Desc.
7358 : // (Actual copying is not necessary.)
7359 : PropertyDescriptor* new_len_desc = desc;
7360 : // 3. - 7. Convert Desc.[[Value]] to newLen.
7361 11833 : uint32_t new_len = 0;
7362 11833 : if (!AnythingToArrayLength(isolate, desc->value(), &new_len)) {
7363 : DCHECK(isolate->has_pending_exception());
7364 : return Nothing<bool>();
7365 : }
7366 : // 8. Set newLenDesc.[[Value]] to newLen.
7367 : // (Done below, if needed.)
7368 : // 9. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
7369 : PropertyDescriptor old_len_desc;
7370 : Maybe<bool> success = GetOwnPropertyDescriptor(
7371 11823 : isolate, a, isolate->factory()->length_string(), &old_len_desc);
7372 : // 10. (Assert)
7373 : DCHECK(success.FromJust());
7374 : USE(success);
7375 : // 11. Let oldLen be oldLenDesc.[[Value]].
7376 11823 : uint32_t old_len = 0;
7377 11823 : CHECK(old_len_desc.value()->ToArrayLength(&old_len));
7378 : // 12. If newLen >= oldLen, then
7379 11823 : if (new_len >= old_len) {
7380 : // 8. Set newLenDesc.[[Value]] to newLen.
7381 : // 12a. Return OrdinaryDefineOwnProperty(A, "length", newLenDesc).
7382 11814 : new_len_desc->set_value(isolate->factory()->NewNumberFromUint(new_len));
7383 : return OrdinaryDefineOwnProperty(isolate, a,
7384 : isolate->factory()->length_string(),
7385 11814 : new_len_desc, should_throw);
7386 : }
7387 : // 13. If oldLenDesc.[[Writable]] is false, return false.
7388 9 : if (!old_len_desc.writable()) {
7389 0 : RETURN_FAILURE(isolate, should_throw,
7390 : NewTypeError(MessageTemplate::kRedefineDisallowed,
7391 : isolate->factory()->length_string()));
7392 : }
7393 : // 14. If newLenDesc.[[Writable]] is absent or has the value true,
7394 : // let newWritable be true.
7395 : bool new_writable = false;
7396 9 : if (!new_len_desc->has_writable() || new_len_desc->writable()) {
7397 : new_writable = true;
7398 : } else {
7399 : // 15. Else,
7400 : // 15a. Need to defer setting the [[Writable]] attribute to false in case
7401 : // any elements cannot be deleted.
7402 : // 15b. Let newWritable be false. (It's initialized as "false" anyway.)
7403 : // 15c. Set newLenDesc.[[Writable]] to true.
7404 : // (Not needed.)
7405 : }
7406 : // Most of steps 16 through 19 is implemented by JSArray::SetLength.
7407 9 : JSArray::SetLength(a, new_len);
7408 : // Steps 19d-ii, 20.
7409 9 : if (!new_writable) {
7410 : PropertyDescriptor readonly;
7411 : readonly.set_writable(false);
7412 : Maybe<bool> success = OrdinaryDefineOwnProperty(
7413 : isolate, a, isolate->factory()->length_string(), &readonly,
7414 0 : should_throw);
7415 : DCHECK(success.FromJust());
7416 : USE(success);
7417 : }
7418 9 : uint32_t actual_new_len = 0;
7419 9 : CHECK(a->length()->ToArrayLength(&actual_new_len));
7420 : // Steps 19d-v, 21. Return false if there were non-deletable elements.
7421 9 : bool result = actual_new_len == new_len;
7422 9 : if (!result) {
7423 9 : RETURN_FAILURE(
7424 : isolate, should_throw,
7425 : NewTypeError(MessageTemplate::kStrictDeleteProperty,
7426 : isolate->factory()->NewNumberFromUint(actual_new_len - 1),
7427 : a));
7428 : }
7429 : return Just(result);
7430 : }
7431 :
7432 :
7433 : // ES6 9.5.6
7434 : // static
7435 4005 : Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy,
7436 : Handle<Object> key,
7437 : PropertyDescriptor* desc,
7438 : ShouldThrow should_throw) {
7439 4005 : STACK_CHECK(isolate, Nothing<bool>());
7440 4293 : if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) {
7441 : return SetPrivateProperty(isolate, proxy, Handle<Symbol>::cast(key), desc,
7442 18 : should_throw);
7443 : }
7444 : Handle<String> trap_name = isolate->factory()->defineProperty_string();
7445 : // 1. Assert: IsPropertyKey(P) is true.
7446 : DCHECK(key->IsName() || key->IsNumber());
7447 : // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
7448 : Handle<Object> handler(proxy->handler(), isolate);
7449 : // 3. If handler is null, throw a TypeError exception.
7450 : // 4. Assert: Type(handler) is Object.
7451 3987 : if (proxy->IsRevoked()) {
7452 : isolate->Throw(*isolate->factory()->NewTypeError(
7453 18 : MessageTemplate::kProxyRevoked, trap_name));
7454 : return Nothing<bool>();
7455 : }
7456 : // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
7457 : Handle<JSReceiver> target(proxy->target(), isolate);
7458 : // 6. Let trap be ? GetMethod(handler, "defineProperty").
7459 : Handle<Object> trap;
7460 7956 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7461 : isolate, trap,
7462 : Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
7463 : Nothing<bool>());
7464 : // 7. If trap is undefined, then:
7465 3888 : if (trap->IsUndefined(isolate)) {
7466 : // 7a. Return target.[[DefineOwnProperty]](P, Desc).
7467 : return JSReceiver::DefineOwnProperty(isolate, target, key, desc,
7468 2035 : should_throw);
7469 : }
7470 : // 8. Let descObj be FromPropertyDescriptor(Desc).
7471 1853 : Handle<Object> desc_obj = desc->ToObject(isolate);
7472 : // 9. Let booleanTrapResult be
7473 : // ToBoolean(? Call(trap, handler, «target, P, descObj»)).
7474 : Handle<Name> property_name =
7475 : key->IsName()
7476 : ? Handle<Name>::cast(key)
7477 1853 : : Handle<Name>::cast(isolate->factory()->NumberToString(key));
7478 : // Do not leak private property names.
7479 : DCHECK(!property_name->IsPrivate());
7480 : Handle<Object> trap_result_obj;
7481 1853 : Handle<Object> args[] = {target, property_name, desc_obj};
7482 3706 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7483 : isolate, trap_result_obj,
7484 : Execution::Call(isolate, trap, handler, arraysize(args), args),
7485 : Nothing<bool>());
7486 : // 10. If booleanTrapResult is false, return false.
7487 1327 : if (!trap_result_obj->BooleanValue()) {
7488 99 : RETURN_FAILURE(isolate, should_throw,
7489 : NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
7490 : trap_name, property_name));
7491 : }
7492 : // 11. Let targetDesc be ? target.[[GetOwnProperty]](P).
7493 : PropertyDescriptor target_desc;
7494 : Maybe<bool> target_found =
7495 1246 : JSReceiver::GetOwnPropertyDescriptor(isolate, target, key, &target_desc);
7496 1246 : MAYBE_RETURN(target_found, Nothing<bool>());
7497 : // 12. Let extensibleTarget be ? IsExtensible(target).
7498 1246 : Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
7499 1246 : MAYBE_RETURN(maybe_extensible, Nothing<bool>());
7500 : bool extensible_target = maybe_extensible.FromJust();
7501 : // 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]]
7502 : // is false, then:
7503 : // 13a. Let settingConfigFalse be true.
7504 : // 14. Else let settingConfigFalse be false.
7505 1941 : bool setting_config_false = desc->has_configurable() && !desc->configurable();
7506 : // 15. If targetDesc is undefined, then
7507 1246 : if (!target_found.FromJust()) {
7508 : // 15a. If extensibleTarget is false, throw a TypeError exception.
7509 621 : if (!extensible_target) {
7510 : isolate->Throw(*isolate->factory()->NewTypeError(
7511 18 : MessageTemplate::kProxyDefinePropertyNonExtensible, property_name));
7512 : return Nothing<bool>();
7513 : }
7514 : // 15b. If settingConfigFalse is true, throw a TypeError exception.
7515 612 : if (setting_config_false) {
7516 : isolate->Throw(*isolate->factory()->NewTypeError(
7517 18 : MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
7518 : return Nothing<bool>();
7519 : }
7520 : } else {
7521 : // 16. Else targetDesc is not undefined,
7522 : // 16a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc,
7523 : // targetDesc) is false, throw a TypeError exception.
7524 : Maybe<bool> valid =
7525 : IsCompatiblePropertyDescriptor(isolate, extensible_target, desc,
7526 : &target_desc, property_name, DONT_THROW);
7527 625 : MAYBE_RETURN(valid, Nothing<bool>());
7528 625 : if (!valid.FromJust()) {
7529 : isolate->Throw(*isolate->factory()->NewTypeError(
7530 18 : MessageTemplate::kProxyDefinePropertyIncompatible, property_name));
7531 : return Nothing<bool>();
7532 : }
7533 : // 16b. If settingConfigFalse is true and targetDesc.[[Configurable]] is
7534 : // true, throw a TypeError exception.
7535 706 : if (setting_config_false && target_desc.configurable()) {
7536 : isolate->Throw(*isolate->factory()->NewTypeError(
7537 18 : MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
7538 : return Nothing<bool>();
7539 : }
7540 : }
7541 : // 17. Return true.
7542 : return Just(true);
7543 : }
7544 :
7545 :
7546 : // static
7547 36 : Maybe<bool> JSProxy::SetPrivateProperty(Isolate* isolate, Handle<JSProxy> proxy,
7548 : Handle<Symbol> private_name,
7549 : PropertyDescriptor* desc,
7550 : ShouldThrow should_throw) {
7551 : // Despite the generic name, this can only add private data properties.
7552 54 : if (!PropertyDescriptor::IsDataDescriptor(desc) ||
7553 18 : desc->ToAttributes() != DONT_ENUM) {
7554 36 : RETURN_FAILURE(isolate, should_throw,
7555 : NewTypeError(MessageTemplate::kProxyPrivate));
7556 : }
7557 : DCHECK(proxy->map()->is_dictionary_map());
7558 : Handle<Object> value =
7559 : desc->has_value()
7560 : ? desc->value()
7561 18 : : Handle<Object>::cast(isolate->factory()->undefined_value());
7562 :
7563 18 : LookupIterator it(proxy, private_name, proxy);
7564 :
7565 18 : if (it.IsFound()) {
7566 : DCHECK_EQ(LookupIterator::DATA, it.state());
7567 : DCHECK_EQ(DONT_ENUM, it.property_attributes());
7568 6 : it.WriteDataValue(value, false);
7569 : return Just(true);
7570 : }
7571 :
7572 : Handle<NameDictionary> dict(proxy->property_dictionary());
7573 : PropertyDetails details(kData, DONT_ENUM, PropertyCellType::kNoCell);
7574 : Handle<NameDictionary> result =
7575 12 : NameDictionary::Add(dict, private_name, value, details);
7576 18 : if (!dict.is_identical_to(result)) proxy->SetProperties(*result);
7577 : return Just(true);
7578 : }
7579 :
7580 :
7581 : // static
7582 2279114 : Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate,
7583 : Handle<JSReceiver> object,
7584 : Handle<Object> key,
7585 : PropertyDescriptor* desc) {
7586 2279114 : bool success = false;
7587 : DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
7588 : LookupIterator it = LookupIterator::PropertyOrElement(
7589 2279114 : isolate, object, key, &success, LookupIterator::OWN);
7590 : DCHECK(success); // ...so creating a LookupIterator can't fail.
7591 2279114 : return GetOwnPropertyDescriptor(&it, desc);
7592 : }
7593 :
7594 : namespace {
7595 :
7596 5967247 : Maybe<bool> GetPropertyDescriptorWithInterceptor(LookupIterator* it,
7597 : PropertyDescriptor* desc) {
7598 : bool has_access = true;
7599 2983347 : if (it->state() == LookupIterator::ACCESS_CHECK) {
7600 2169299 : has_access = it->HasAccess() || JSObject::AllCanRead(it);
7601 2169299 : it->Next();
7602 : }
7603 :
7604 5966649 : if (has_access && it->state() == LookupIterator::INTERCEPTOR) {
7605 : Isolate* isolate = it->isolate();
7606 548 : Handle<InterceptorInfo> interceptor = it->GetInterceptor();
7607 548 : if (!interceptor->descriptor()->IsUndefined(isolate)) {
7608 : Handle<Object> result;
7609 : Handle<JSObject> holder = it->GetHolder<JSObject>();
7610 :
7611 : Handle<Object> receiver = it->GetReceiver();
7612 38 : if (!receiver->IsJSReceiver()) {
7613 12 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7614 : isolate, receiver, Object::ConvertReceiver(isolate, receiver),
7615 : Nothing<bool>());
7616 : }
7617 :
7618 : PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
7619 : *holder, Object::DONT_THROW);
7620 38 : if (it->IsElement()) {
7621 : uint32_t index = it->index();
7622 : v8::IndexedPropertyDescriptorCallback descriptorCallback =
7623 : v8::ToCData<v8::IndexedPropertyDescriptorCallback>(
7624 : interceptor->descriptor());
7625 :
7626 10 : result = args.Call(descriptorCallback, index);
7627 : } else {
7628 28 : Handle<Name> name = it->name();
7629 : DCHECK(!name->IsPrivate());
7630 : v8::GenericNamedPropertyDescriptorCallback descriptorCallback =
7631 : v8::ToCData<v8::GenericNamedPropertyDescriptorCallback>(
7632 : interceptor->descriptor());
7633 28 : result = args.Call(descriptorCallback, name);
7634 : }
7635 38 : if (!result.is_null()) {
7636 : // Request successfully intercepted, try to set the property
7637 : // descriptor.
7638 : Utils::ApiCheck(
7639 12 : PropertyDescriptor::ToPropertyDescriptor(isolate, result, desc),
7640 : it->IsElement() ? "v8::IndexedPropertyDescriptorCallback"
7641 : : "v8::NamedPropertyDescriptorCallback",
7642 12 : "Invalid property descriptor.");
7643 :
7644 : return Just(true);
7645 : }
7646 : }
7647 : }
7648 2983335 : it->Restart();
7649 : return Just(false);
7650 : }
7651 : } // namespace
7652 :
7653 : // ES6 9.1.5.1
7654 : // Returns true on success, false if the property didn't exist, nothing if
7655 : // an exception was thrown.
7656 : // static
7657 5455613 : Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it,
7658 : PropertyDescriptor* desc) {
7659 : Isolate* isolate = it->isolate();
7660 : // "Virtual" dispatch.
7661 5462270 : if (it->IsFound() && it->GetHolder<JSReceiver>()->IsJSProxy()) {
7662 : return JSProxy::GetOwnPropertyDescriptor(isolate, it->GetHolder<JSProxy>(),
7663 6267 : it->GetName(), desc);
7664 : }
7665 :
7666 2983347 : Maybe<bool> intercepted = GetPropertyDescriptorWithInterceptor(it, desc);
7667 2983347 : MAYBE_RETURN(intercepted, Nothing<bool>());
7668 2983347 : if (intercepted.FromJust()) {
7669 : return Just(true);
7670 : }
7671 :
7672 : // Request was not intercepted, continue as normal.
7673 : // 1. (Assert)
7674 : // 2. If O does not have an own property with key P, return undefined.
7675 2983335 : Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(it);
7676 2983335 : MAYBE_RETURN(maybe, Nothing<bool>());
7677 : PropertyAttributes attrs = maybe.FromJust();
7678 2983290 : if (attrs == ABSENT) return Just(false);
7679 : DCHECK(!isolate->has_pending_exception());
7680 :
7681 : // 3. Let D be a newly created Property Descriptor with no fields.
7682 : DCHECK(desc->is_empty());
7683 : // 4. Let X be O's own property whose key is P.
7684 : // 5. If X is a data property, then
7685 2571514 : bool is_accessor_pair = it->state() == LookupIterator::ACCESSOR &&
7686 2571514 : it->GetAccessors()->IsAccessorPair();
7687 2465999 : if (!is_accessor_pair) {
7688 : // 5a. Set D.[[Value]] to the value of X's [[Value]] attribute.
7689 : Handle<Object> value;
7690 4904228 : if (!Object::GetProperty(it).ToHandle(&value)) {
7691 : DCHECK(isolate->has_pending_exception());
7692 : return Nothing<bool>();
7693 : }
7694 : desc->set_value(value);
7695 : // 5b. Set D.[[Writable]] to the value of X's [[Writable]] attribute
7696 2452114 : desc->set_writable((attrs & READ_ONLY) == 0);
7697 : } else {
7698 : // 6. Else X is an accessor property, so
7699 : Handle<AccessorPair> accessors =
7700 13885 : Handle<AccessorPair>::cast(it->GetAccessors());
7701 : // 6a. Set D.[[Get]] to the value of X's [[Get]] attribute.
7702 13885 : desc->set_get(AccessorPair::GetComponent(accessors, ACCESSOR_GETTER));
7703 : // 6b. Set D.[[Set]] to the value of X's [[Set]] attribute.
7704 13885 : desc->set_set(AccessorPair::GetComponent(accessors, ACCESSOR_SETTER));
7705 : }
7706 :
7707 : // 7. Set D.[[Enumerable]] to the value of X's [[Enumerable]] attribute.
7708 2465999 : desc->set_enumerable((attrs & DONT_ENUM) == 0);
7709 : // 8. Set D.[[Configurable]] to the value of X's [[Configurable]] attribute.
7710 2465999 : desc->set_configurable((attrs & DONT_DELETE) == 0);
7711 : // 9. Return D.
7712 : DCHECK(PropertyDescriptor::IsAccessorDescriptor(desc) !=
7713 : PropertyDescriptor::IsDataDescriptor(desc));
7714 : return Just(true);
7715 : }
7716 :
7717 :
7718 : // ES6 9.5.5
7719 : // static
7720 9420 : Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate,
7721 : Handle<JSProxy> proxy,
7722 : Handle<Name> name,
7723 : PropertyDescriptor* desc) {
7724 : DCHECK(!name->IsPrivate());
7725 9420 : STACK_CHECK(isolate, Nothing<bool>());
7726 :
7727 : Handle<String> trap_name =
7728 : isolate->factory()->getOwnPropertyDescriptor_string();
7729 : // 1. (Assert)
7730 : // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
7731 : Handle<Object> handler(proxy->handler(), isolate);
7732 : // 3. If handler is null, throw a TypeError exception.
7733 : // 4. Assert: Type(handler) is Object.
7734 9420 : if (proxy->IsRevoked()) {
7735 : isolate->Throw(*isolate->factory()->NewTypeError(
7736 36 : MessageTemplate::kProxyRevoked, trap_name));
7737 : return Nothing<bool>();
7738 : }
7739 : // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
7740 : Handle<JSReceiver> target(proxy->target(), isolate);
7741 : // 6. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor").
7742 : Handle<Object> trap;
7743 18804 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7744 : isolate, trap,
7745 : Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
7746 : Nothing<bool>());
7747 : // 7. If trap is undefined, then
7748 9348 : if (trap->IsUndefined(isolate)) {
7749 : // 7a. Return target.[[GetOwnProperty]](P).
7750 3657 : return JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, desc);
7751 : }
7752 : // 8. Let trapResultObj be ? Call(trap, handler, «target, P»).
7753 : Handle<Object> trap_result_obj;
7754 : Handle<Object> args[] = {target, name};
7755 11382 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7756 : isolate, trap_result_obj,
7757 : Execution::Call(isolate, trap, handler, arraysize(args), args),
7758 : Nothing<bool>());
7759 : // 9. If Type(trapResultObj) is neither Object nor Undefined, throw a
7760 : // TypeError exception.
7761 5589 : if (!trap_result_obj->IsJSReceiver() &&
7762 : !trap_result_obj->IsUndefined(isolate)) {
7763 : isolate->Throw(*isolate->factory()->NewTypeError(
7764 36 : MessageTemplate::kProxyGetOwnPropertyDescriptorInvalid, name));
7765 : return Nothing<bool>();
7766 : }
7767 : // 10. Let targetDesc be ? target.[[GetOwnProperty]](P).
7768 : PropertyDescriptor target_desc;
7769 : Maybe<bool> found =
7770 4761 : JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
7771 4761 : MAYBE_RETURN(found, Nothing<bool>());
7772 : // 11. If trapResultObj is undefined, then
7773 4761 : if (trap_result_obj->IsUndefined(isolate)) {
7774 : // 11a. If targetDesc is undefined, return undefined.
7775 792 : if (!found.FromJust()) return Just(false);
7776 : // 11b. If targetDesc.[[Configurable]] is false, throw a TypeError
7777 : // exception.
7778 45 : if (!target_desc.configurable()) {
7779 : isolate->Throw(*isolate->factory()->NewTypeError(
7780 54 : MessageTemplate::kProxyGetOwnPropertyDescriptorUndefined, name));
7781 : return Nothing<bool>();
7782 : }
7783 : // 11c. Let extensibleTarget be ? IsExtensible(target).
7784 18 : Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
7785 18 : MAYBE_RETURN(extensible_target, Nothing<bool>());
7786 : // 11d. (Assert)
7787 : // 11e. If extensibleTarget is false, throw a TypeError exception.
7788 18 : if (!extensible_target.FromJust()) {
7789 : isolate->Throw(*isolate->factory()->NewTypeError(
7790 0 : MessageTemplate::kProxyGetOwnPropertyDescriptorNonExtensible, name));
7791 : return Nothing<bool>();
7792 : }
7793 : // 11f. Return undefined.
7794 : return Just(false);
7795 : }
7796 : // 12. Let extensibleTarget be ? IsExtensible(target).
7797 3969 : Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
7798 3969 : MAYBE_RETURN(extensible_target, Nothing<bool>());
7799 : // 13. Let resultDesc be ? ToPropertyDescriptor(trapResultObj).
7800 3969 : if (!PropertyDescriptor::ToPropertyDescriptor(isolate, trap_result_obj,
7801 3969 : desc)) {
7802 : DCHECK(isolate->has_pending_exception());
7803 : return Nothing<bool>();
7804 : }
7805 : // 14. Call CompletePropertyDescriptor(resultDesc).
7806 3897 : PropertyDescriptor::CompletePropertyDescriptor(isolate, desc);
7807 : // 15. Let valid be IsCompatiblePropertyDescriptor (extensibleTarget,
7808 : // resultDesc, targetDesc).
7809 : Maybe<bool> valid =
7810 : IsCompatiblePropertyDescriptor(isolate, extensible_target.FromJust(),
7811 : desc, &target_desc, name, DONT_THROW);
7812 3897 : MAYBE_RETURN(valid, Nothing<bool>());
7813 : // 16. If valid is false, throw a TypeError exception.
7814 3897 : if (!valid.FromJust()) {
7815 : isolate->Throw(*isolate->factory()->NewTypeError(
7816 36 : MessageTemplate::kProxyGetOwnPropertyDescriptorIncompatible, name));
7817 : return Nothing<bool>();
7818 : }
7819 : // 17. If resultDesc.[[Configurable]] is false, then
7820 3879 : if (!desc->configurable()) {
7821 : // 17a. If targetDesc is undefined or targetDesc.[[Configurable]] is true:
7822 477 : if (target_desc.is_empty() || target_desc.configurable()) {
7823 : // 17a i. Throw a TypeError exception.
7824 : isolate->Throw(*isolate->factory()->NewTypeError(
7825 : MessageTemplate::kProxyGetOwnPropertyDescriptorNonConfigurable,
7826 36 : name));
7827 : return Nothing<bool>();
7828 : }
7829 : }
7830 : // 18. Return resultDesc.
7831 : return Just(true);
7832 : }
7833 :
7834 :
7835 0 : bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
7836 : ElementsKind kind,
7837 : Object* object) {
7838 : Isolate* isolate = elements->GetIsolate();
7839 0 : if (IsObjectElementsKind(kind) || kind == FAST_STRING_WRAPPER_ELEMENTS) {
7840 : int length = IsJSArray() ? Smi::ToInt(JSArray::cast(this)->length())
7841 0 : : elements->length();
7842 0 : for (int i = 0; i < length; ++i) {
7843 : Object* element = elements->get(i);
7844 0 : if (!element->IsTheHole(isolate) && element == object) return true;
7845 : }
7846 : } else {
7847 : DCHECK(kind == DICTIONARY_ELEMENTS || kind == SLOW_STRING_WRAPPER_ELEMENTS);
7848 : Object* key =
7849 0 : SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
7850 0 : if (!key->IsUndefined(isolate)) return true;
7851 : }
7852 : return false;
7853 : }
7854 :
7855 :
7856 : // Check whether this object references another object.
7857 0 : bool JSObject::ReferencesObject(Object* obj) {
7858 : Map* map_of_this = map();
7859 : Heap* heap = GetHeap();
7860 : DisallowHeapAllocation no_allocation;
7861 :
7862 : // Is the object the constructor for this object?
7863 0 : if (map_of_this->GetConstructor() == obj) {
7864 : return true;
7865 : }
7866 :
7867 : // Is the object the prototype for this object?
7868 0 : if (map_of_this->prototype() == obj) {
7869 : return true;
7870 : }
7871 :
7872 : // Check if the object is among the named properties.
7873 0 : Object* key = SlowReverseLookup(obj);
7874 0 : if (!key->IsUndefined(heap->isolate())) {
7875 : return true;
7876 : }
7877 :
7878 : // Check if the object is among the indexed properties.
7879 : ElementsKind kind = GetElementsKind();
7880 0 : switch (kind) {
7881 : // Raw pixels and external arrays do not reference other
7882 : // objects.
7883 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
7884 : case TYPE##_ELEMENTS: \
7885 : break;
7886 :
7887 : TYPED_ARRAYS(TYPED_ARRAY_CASE)
7888 : #undef TYPED_ARRAY_CASE
7889 :
7890 : case PACKED_DOUBLE_ELEMENTS:
7891 : case HOLEY_DOUBLE_ELEMENTS:
7892 : break;
7893 : case PACKED_SMI_ELEMENTS:
7894 : case HOLEY_SMI_ELEMENTS:
7895 : break;
7896 : case PACKED_ELEMENTS:
7897 : case HOLEY_ELEMENTS:
7898 : case DICTIONARY_ELEMENTS:
7899 : case FAST_STRING_WRAPPER_ELEMENTS:
7900 : case SLOW_STRING_WRAPPER_ELEMENTS: {
7901 : FixedArray* elements = FixedArray::cast(this->elements());
7902 0 : if (ReferencesObjectFromElements(elements, kind, obj)) return true;
7903 : break;
7904 : }
7905 : case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
7906 : case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
7907 : SloppyArgumentsElements* elements =
7908 : SloppyArgumentsElements::cast(this->elements());
7909 : // Check the mapped parameters.
7910 0 : for (uint32_t i = 0; i < elements->parameter_map_length(); ++i) {
7911 : Object* value = elements->get_mapped_entry(i);
7912 0 : if (!value->IsTheHole(heap->isolate()) && value == obj) return true;
7913 : }
7914 : // Check the arguments.
7915 : FixedArray* arguments = elements->arguments();
7916 0 : kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : HOLEY_ELEMENTS;
7917 0 : if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
7918 : break;
7919 : }
7920 : case NO_ELEMENTS:
7921 : break;
7922 : }
7923 :
7924 : // For functions check the context.
7925 0 : if (IsJSFunction()) {
7926 : // Get the constructor function for arguments array.
7927 : Map* arguments_map =
7928 0 : heap->isolate()->context()->native_context()->sloppy_arguments_map();
7929 : JSFunction* arguments_function =
7930 0 : JSFunction::cast(arguments_map->GetConstructor());
7931 :
7932 : // Get the context and don't check if it is the native context.
7933 : JSFunction* f = JSFunction::cast(this);
7934 : Context* context = f->context();
7935 0 : if (context->IsNativeContext()) {
7936 : return false;
7937 : }
7938 :
7939 : // Check the non-special context slots.
7940 0 : for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
7941 : // Only check JS objects.
7942 0 : if (context->get(i)->IsJSObject()) {
7943 : JSObject* ctxobj = JSObject::cast(context->get(i));
7944 : // If it is an arguments array check the content.
7945 0 : if (ctxobj->map()->GetConstructor() == arguments_function) {
7946 0 : if (ctxobj->ReferencesObject(obj)) {
7947 : return true;
7948 : }
7949 0 : } else if (ctxobj == obj) {
7950 : return true;
7951 : }
7952 : }
7953 : }
7954 :
7955 : // Check the context extension (if any) if it can have references.
7956 0 : if (context->has_extension() && !context->IsCatchContext() &&
7957 0 : !context->IsModuleContext()) {
7958 : // With harmony scoping, a JSFunction may have a script context.
7959 : // TODO(mvstanton): walk into the ScopeInfo.
7960 0 : if (context->IsScriptContext()) {
7961 : return false;
7962 : }
7963 :
7964 0 : return context->extension_object()->ReferencesObject(obj);
7965 : }
7966 : }
7967 :
7968 : // No references to object.
7969 : return false;
7970 : }
7971 :
7972 :
7973 260371 : Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver,
7974 : IntegrityLevel level,
7975 : ShouldThrow should_throw) {
7976 : DCHECK(level == SEALED || level == FROZEN);
7977 :
7978 260371 : if (receiver->IsJSObject()) {
7979 : Handle<JSObject> object = Handle<JSObject>::cast(receiver);
7980 :
7981 259957 : if (!object->HasSloppyArgumentsElements()) { // Fast path.
7982 : // prevent memory leaks by not adding unnecessary transitions
7983 259905 : Maybe<bool> test = JSObject::TestIntegrityLevel(object, level);
7984 259905 : MAYBE_RETURN(test, Nothing<bool>());
7985 259905 : if (test.FromJust()) return test;
7986 :
7987 256764 : if (level == SEALED) {
7988 : return JSObject::PreventExtensionsWithTransition<SEALED>(object,
7989 477 : should_throw);
7990 : } else {
7991 : return JSObject::PreventExtensionsWithTransition<FROZEN>(object,
7992 256287 : should_throw);
7993 : }
7994 : }
7995 : }
7996 :
7997 : Isolate* isolate = receiver->GetIsolate();
7998 :
7999 466 : MAYBE_RETURN(JSReceiver::PreventExtensions(receiver, should_throw),
8000 : Nothing<bool>());
8001 :
8002 : Handle<FixedArray> keys;
8003 466 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8004 : isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>());
8005 :
8006 : PropertyDescriptor no_conf;
8007 : no_conf.set_configurable(false);
8008 :
8009 : PropertyDescriptor no_conf_no_write;
8010 : no_conf_no_write.set_configurable(false);
8011 : no_conf_no_write.set_writable(false);
8012 :
8013 466 : if (level == SEALED) {
8014 294 : for (int i = 0; i < keys->length(); ++i) {
8015 : Handle<Object> key(keys->get(i), isolate);
8016 96 : MAYBE_RETURN(
8017 : DefineOwnProperty(isolate, receiver, key, &no_conf, THROW_ON_ERROR),
8018 : Nothing<bool>());
8019 : }
8020 : return Just(true);
8021 : }
8022 :
8023 2908 : for (int i = 0; i < keys->length(); ++i) {
8024 : Handle<Object> key(keys->get(i), isolate);
8025 : PropertyDescriptor current_desc;
8026 : Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
8027 1272 : isolate, receiver, key, ¤t_desc);
8028 1272 : MAYBE_RETURN(owned, Nothing<bool>());
8029 1272 : if (owned.FromJust()) {
8030 : PropertyDescriptor desc =
8031 : PropertyDescriptor::IsAccessorDescriptor(¤t_desc)
8032 : ? no_conf
8033 1272 : : no_conf_no_write;
8034 1272 : MAYBE_RETURN(
8035 : DefineOwnProperty(isolate, receiver, key, &desc, THROW_ON_ERROR),
8036 : Nothing<bool>());
8037 : }
8038 : }
8039 : return Just(true);
8040 : }
8041 :
8042 : namespace {
8043 :
8044 : template <typename Dictionary>
8045 4375 : bool TestDictionaryPropertiesIntegrityLevel(Dictionary* dict, Isolate* isolate,
8046 : PropertyAttributes level) {
8047 : DCHECK(level == SEALED || level == FROZEN);
8048 :
8049 4375 : uint32_t capacity = dict->Capacity();
8050 13883 : for (uint32_t i = 0; i < capacity; i++) {
8051 : Object* key;
8052 16803 : if (!dict->ToKey(isolate, i, &key)) continue;
8053 2689 : if (key->FilterKey(ALL_PROPERTIES)) continue;
8054 : PropertyDetails details = dict->DetailsAt(i);
8055 2900 : if (details.IsConfigurable()) return false;
8056 5574 : if (level == FROZEN && details.kind() == kData && !details.IsReadOnly()) {
8057 : return false;
8058 : }
8059 : }
8060 : return true;
8061 : }
8062 :
8063 3991 : bool TestFastPropertiesIntegrityLevel(Map* map, PropertyAttributes level) {
8064 : DCHECK(level == SEALED || level == FROZEN);
8065 : DCHECK_LT(LAST_CUSTOM_ELEMENTS_RECEIVER, map->instance_type());
8066 : DCHECK(!map->is_dictionary_map());
8067 :
8068 : DescriptorArray* descriptors = map->instance_descriptors();
8069 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
8070 5745 : for (int i = 0; i < number_of_own_descriptors; i++) {
8071 1911 : if (descriptors->GetKey(i)->IsPrivate()) continue;
8072 1893 : PropertyDetails details = descriptors->GetDetails(i);
8073 1893 : if (details.IsConfigurable()) return false;
8074 4092 : if (level == FROZEN && details.kind() == kData && !details.IsReadOnly()) {
8075 : return false;
8076 : }
8077 : }
8078 : return true;
8079 : }
8080 :
8081 4085 : bool TestPropertiesIntegrityLevel(JSObject* object, PropertyAttributes level) {
8082 : DCHECK_LT(LAST_CUSTOM_ELEMENTS_RECEIVER, object->map()->instance_type());
8083 :
8084 4085 : if (object->HasFastProperties()) {
8085 3991 : return TestFastPropertiesIntegrityLevel(object->map(), level);
8086 : }
8087 :
8088 : return TestDictionaryPropertiesIntegrityLevel(object->property_dictionary(),
8089 94 : object->GetIsolate(), level);
8090 : }
8091 :
8092 4281 : bool TestElementsIntegrityLevel(JSObject* object, PropertyAttributes level) {
8093 : DCHECK(!object->HasSloppyArgumentsElements());
8094 :
8095 : ElementsKind kind = object->GetElementsKind();
8096 :
8097 4281 : if (IsDictionaryElementsKind(kind)) {
8098 : return TestDictionaryPropertiesIntegrityLevel(
8099 : SeededNumberDictionary::cast(object->elements()), object->GetIsolate(),
8100 4281 : level);
8101 : }
8102 :
8103 : ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
8104 : // Only DICTIONARY_ELEMENTS and SLOW_SLOPPY_ARGUMENTS_ELEMENTS have
8105 : // PropertyAttributes so just test if empty
8106 0 : return accessor->NumberOfElements(object) == 0;
8107 : }
8108 :
8109 270951 : bool FastTestIntegrityLevel(JSObject* object, PropertyAttributes level) {
8110 : DCHECK_LT(LAST_CUSTOM_ELEMENTS_RECEIVER, object->map()->instance_type());
8111 :
8112 4281 : return !object->map()->is_extensible() &&
8113 275036 : TestElementsIntegrityLevel(object, level) &&
8114 275036 : TestPropertiesIntegrityLevel(object, level);
8115 : }
8116 :
8117 246 : Maybe<bool> GenericTestIntegrityLevel(Handle<JSReceiver> receiver,
8118 : PropertyAttributes level) {
8119 : DCHECK(level == SEALED || level == FROZEN);
8120 :
8121 246 : Maybe<bool> extensible = JSReceiver::IsExtensible(receiver);
8122 246 : MAYBE_RETURN(extensible, Nothing<bool>());
8123 246 : if (extensible.FromJust()) return Just(false);
8124 :
8125 : Isolate* isolate = receiver->GetIsolate();
8126 :
8127 : Handle<FixedArray> keys;
8128 98 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8129 : isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>());
8130 :
8131 4802 : for (int i = 0; i < keys->length(); ++i) {
8132 : Handle<Object> key(keys->get(i), isolate);
8133 : PropertyDescriptor current_desc;
8134 : Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
8135 2380 : isolate, receiver, key, ¤t_desc);
8136 2408 : MAYBE_RETURN(owned, Nothing<bool>());
8137 2380 : if (owned.FromJust()) {
8138 2380 : if (current_desc.configurable()) return Just(false);
8139 3568 : if (level == FROZEN &&
8140 3559 : PropertyDescriptor::IsDataDescriptor(¤t_desc) &&
8141 : current_desc.writable()) {
8142 : return Just(false);
8143 : }
8144 : }
8145 : }
8146 : return Just(true);
8147 : }
8148 :
8149 : } // namespace
8150 :
8151 11292 : Maybe<bool> JSReceiver::TestIntegrityLevel(Handle<JSReceiver> receiver,
8152 : IntegrityLevel level) {
8153 11292 : if (receiver->map()->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER) {
8154 : return JSObject::TestIntegrityLevel(Handle<JSObject>::cast(receiver),
8155 11178 : level);
8156 : }
8157 114 : return GenericTestIntegrityLevel(receiver, level);
8158 : }
8159 :
8160 271083 : Maybe<bool> JSObject::TestIntegrityLevel(Handle<JSObject> object,
8161 : IntegrityLevel level) {
8162 542066 : if (object->map()->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER &&
8163 270983 : !object->HasSloppyArgumentsElements()) {
8164 270951 : return Just(FastTestIntegrityLevel(*object, level));
8165 : }
8166 132 : return GenericTestIntegrityLevel(Handle<JSReceiver>::cast(object), level);
8167 : }
8168 :
8169 4637 : Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object,
8170 : ShouldThrow should_throw) {
8171 4637 : if (object->IsJSProxy()) {
8172 : return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object),
8173 612 : should_throw);
8174 : }
8175 : DCHECK(object->IsJSObject());
8176 : return JSObject::PreventExtensions(Handle<JSObject>::cast(object),
8177 4025 : should_throw);
8178 : }
8179 :
8180 :
8181 612 : Maybe<bool> JSProxy::PreventExtensions(Handle<JSProxy> proxy,
8182 : ShouldThrow should_throw) {
8183 : Isolate* isolate = proxy->GetIsolate();
8184 612 : STACK_CHECK(isolate, Nothing<bool>());
8185 : Factory* factory = isolate->factory();
8186 : Handle<String> trap_name = factory->preventExtensions_string();
8187 :
8188 612 : if (proxy->IsRevoked()) {
8189 : isolate->Throw(
8190 36 : *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
8191 : return Nothing<bool>();
8192 : }
8193 : Handle<JSReceiver> target(proxy->target(), isolate);
8194 : Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
8195 :
8196 : Handle<Object> trap;
8197 1188 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8198 : isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
8199 576 : if (trap->IsUndefined(isolate)) {
8200 522 : return JSReceiver::PreventExtensions(target, should_throw);
8201 : }
8202 :
8203 : Handle<Object> trap_result;
8204 : Handle<Object> args[] = {target};
8205 108 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8206 : isolate, trap_result,
8207 : Execution::Call(isolate, trap, handler, arraysize(args), args),
8208 : Nothing<bool>());
8209 54 : if (!trap_result->BooleanValue()) {
8210 18 : RETURN_FAILURE(
8211 : isolate, should_throw,
8212 : NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
8213 : }
8214 :
8215 : // Enforce the invariant.
8216 36 : Maybe<bool> target_result = JSReceiver::IsExtensible(target);
8217 36 : MAYBE_RETURN(target_result, Nothing<bool>());
8218 36 : if (target_result.FromJust()) {
8219 : isolate->Throw(*factory->NewTypeError(
8220 18 : MessageTemplate::kProxyPreventExtensionsExtensible));
8221 : return Nothing<bool>();
8222 : }
8223 : return Just(true);
8224 : }
8225 :
8226 :
8227 4328 : Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object,
8228 : ShouldThrow should_throw) {
8229 0 : Isolate* isolate = object->GetIsolate();
8230 :
8231 4328 : if (!object->HasSloppyArgumentsElements()) {
8232 4266 : return PreventExtensionsWithTransition<NONE>(object, should_throw);
8233 : }
8234 :
8235 62 : if (object->IsAccessCheckNeeded() &&
8236 0 : !isolate->MayAccess(handle(isolate->context()), object)) {
8237 0 : isolate->ReportFailedAccessCheck(object);
8238 0 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
8239 0 : RETURN_FAILURE(isolate, should_throw,
8240 : NewTypeError(MessageTemplate::kNoAccess));
8241 : }
8242 :
8243 62 : if (!object->map()->is_extensible()) return Just(true);
8244 :
8245 62 : if (object->IsJSGlobalProxy()) {
8246 0 : PrototypeIterator iter(isolate, object);
8247 0 : if (iter.IsAtEnd()) return Just(true);
8248 : DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
8249 : return PreventExtensions(PrototypeIterator::GetCurrent<JSObject>(iter),
8250 0 : should_throw);
8251 : }
8252 :
8253 124 : if (object->map()->has_named_interceptor() ||
8254 : object->map()->has_indexed_interceptor()) {
8255 0 : RETURN_FAILURE(isolate, should_throw,
8256 : NewTypeError(MessageTemplate::kCannotPreventExt));
8257 : }
8258 :
8259 62 : if (!object->HasFixedTypedArrayElements()) {
8260 : // If there are fast elements we normalize.
8261 62 : Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
8262 : DCHECK(object->HasDictionaryElements() ||
8263 : object->HasSlowArgumentsElements());
8264 :
8265 : // Make sure that we never go back to fast case.
8266 62 : object->RequireSlowElements(*dictionary);
8267 : }
8268 :
8269 : // Do a map transition, other objects with this map may still
8270 : // be extensible.
8271 : // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
8272 62 : Handle<Map> new_map = Map::Copy(handle(object->map()), "PreventExtensions");
8273 :
8274 : new_map->set_is_extensible(false);
8275 62 : JSObject::MigrateToMap(object, new_map);
8276 : DCHECK(!object->map()->is_extensible());
8277 :
8278 : return Just(true);
8279 : }
8280 :
8281 :
8282 1032836 : Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) {
8283 1032836 : if (object->IsJSProxy()) {
8284 585 : return JSProxy::IsExtensible(Handle<JSProxy>::cast(object));
8285 : }
8286 1032251 : return Just(JSObject::IsExtensible(Handle<JSObject>::cast(object)));
8287 : }
8288 :
8289 :
8290 585 : Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) {
8291 : Isolate* isolate = proxy->GetIsolate();
8292 585 : STACK_CHECK(isolate, Nothing<bool>());
8293 : Factory* factory = isolate->factory();
8294 : Handle<String> trap_name = factory->isExtensible_string();
8295 :
8296 585 : if (proxy->IsRevoked()) {
8297 : isolate->Throw(
8298 36 : *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
8299 : return Nothing<bool>();
8300 : }
8301 : Handle<JSReceiver> target(proxy->target(), isolate);
8302 : Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
8303 :
8304 : Handle<Object> trap;
8305 1134 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8306 : isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
8307 549 : if (trap->IsUndefined(isolate)) {
8308 126 : return JSReceiver::IsExtensible(target);
8309 : }
8310 :
8311 : Handle<Object> trap_result;
8312 : Handle<Object> args[] = {target};
8313 846 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8314 : isolate, trap_result,
8315 : Execution::Call(isolate, trap, handler, arraysize(args), args),
8316 : Nothing<bool>());
8317 :
8318 : // Enforce the invariant.
8319 423 : Maybe<bool> target_result = JSReceiver::IsExtensible(target);
8320 423 : MAYBE_RETURN(target_result, Nothing<bool>());
8321 423 : if (target_result.FromJust() != trap_result->BooleanValue()) {
8322 : isolate->Throw(
8323 : *factory->NewTypeError(MessageTemplate::kProxyIsExtensibleInconsistent,
8324 54 : factory->ToBoolean(target_result.FromJust())));
8325 : return Nothing<bool>();
8326 : }
8327 396 : return target_result;
8328 : }
8329 :
8330 :
8331 2852264 : bool JSObject::IsExtensible(Handle<JSObject> object) {
8332 40 : Isolate* isolate = object->GetIsolate();
8333 2852304 : if (object->IsAccessCheckNeeded() &&
8334 40 : !isolate->MayAccess(handle(isolate->context()), object)) {
8335 : return true;
8336 : }
8337 2852234 : if (object->IsJSGlobalProxy()) {
8338 : PrototypeIterator iter(isolate, *object);
8339 2817 : if (iter.IsAtEnd()) return false;
8340 : DCHECK(iter.GetCurrent()->IsJSGlobalObject());
8341 5634 : return iter.GetCurrent<JSObject>()->map()->is_extensible();
8342 : }
8343 2849417 : return object->map()->is_extensible();
8344 : }
8345 :
8346 : namespace {
8347 :
8348 : template <typename Dictionary>
8349 4035 : void ApplyAttributesToDictionary(Isolate* isolate,
8350 : Handle<Dictionary> dictionary,
8351 : const PropertyAttributes attributes) {
8352 : int capacity = dictionary->Capacity();
8353 47491 : for (int i = 0; i < capacity; i++) {
8354 : Object* k;
8355 68556 : if (!dictionary->ToKey(isolate, i, &k)) continue;
8356 18374 : if (k->FilterKey(ALL_PROPERTIES)) continue;
8357 : PropertyDetails details = dictionary->DetailsAt(i);
8358 18356 : int attrs = attributes;
8359 : // READ_ONLY is an invalid attribute for JS setters/getters.
8360 34702 : if ((attributes & READ_ONLY) && details.kind() == kAccessor) {
8361 29 : Object* v = dictionary->ValueAt(i);
8362 39 : if (v->IsAccessorPair()) attrs &= ~READ_ONLY;
8363 : }
8364 : details = details.CopyAddAttributes(static_cast<PropertyAttributes>(attrs));
8365 : dictionary->DetailsAtPut(i, details);
8366 : }
8367 4035 : }
8368 :
8369 : } // namespace
8370 :
8371 : template <PropertyAttributes attrs>
8372 261128 : Maybe<bool> JSObject::PreventExtensionsWithTransition(
8373 : Handle<JSObject> object, ShouldThrow should_throw) {
8374 : STATIC_ASSERT(attrs == NONE || attrs == SEALED || attrs == FROZEN);
8375 :
8376 : // Sealing/freezing sloppy arguments should be handled elsewhere.
8377 : DCHECK(!object->HasSloppyArgumentsElements());
8378 :
8379 25 : Isolate* isolate = object->GetIsolate();
8380 261153 : if (object->IsAccessCheckNeeded() &&
8381 25 : !isolate->MayAccess(handle(isolate->context()), object)) {
8382 20 : isolate->ReportFailedAccessCheck(object);
8383 20 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
8384 0 : RETURN_FAILURE(isolate, should_throw,
8385 : NewTypeError(MessageTemplate::kNoAccess));
8386 : }
8387 :
8388 4265 : if (attrs == NONE && !object->map()->is_extensible()) return Just(true);
8389 :
8390 261098 : if (object->IsJSGlobalProxy()) {
8391 98 : PrototypeIterator iter(isolate, object);
8392 98 : if (iter.IsAtEnd()) return Just(true);
8393 : DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
8394 : return PreventExtensionsWithTransition<attrs>(
8395 98 : PrototypeIterator::GetCurrent<JSObject>(iter), should_throw);
8396 : }
8397 :
8398 521999 : if (object->map()->has_named_interceptor() ||
8399 : object->map()->has_indexed_interceptor()) {
8400 : MessageTemplate::Template message = MessageTemplate::kNone;
8401 : switch (attrs) {
8402 : case NONE:
8403 : message = MessageTemplate::kCannotPreventExt;
8404 : break;
8405 :
8406 : case SEALED:
8407 : message = MessageTemplate::kCannotSeal;
8408 : break;
8409 :
8410 : case FROZEN:
8411 : message = MessageTemplate::kCannotFreeze;
8412 : break;
8413 : }
8414 3 : RETURN_FAILURE(isolate, should_throw, NewTypeError(message));
8415 : }
8416 :
8417 : Handle<SeededNumberDictionary> new_element_dictionary;
8418 782695 : if (!object->HasFixedTypedArrayElements() &&
8419 260940 : !object->HasDictionaryElements() &&
8420 260756 : !object->HasSlowStringWrapperElements()) {
8421 : int length = object->IsJSArray()
8422 : ? Smi::ToInt(Handle<JSArray>::cast(object)->length())
8423 260756 : : object->elements()->length();
8424 264941 : new_element_dictionary =
8425 : length == 0 ? isolate->factory()->empty_slow_element_dictionary()
8426 4185 : : object->GetElementsAccessor()->Normalize(object);
8427 : }
8428 :
8429 : Handle<Symbol> transition_marker;
8430 : if (attrs == NONE) {
8431 : transition_marker = isolate->factory()->nonextensible_symbol();
8432 : } else if (attrs == SEALED) {
8433 : transition_marker = isolate->factory()->sealed_symbol();
8434 : } else {
8435 : DCHECK(attrs == FROZEN);
8436 : transition_marker = isolate->factory()->frozen_symbol();
8437 : }
8438 :
8439 : Handle<Map> old_map(object->map(), isolate);
8440 : TransitionsAccessor transitions(old_map);
8441 260999 : Map* transition = transitions.SearchSpecial(*transition_marker);
8442 260999 : if (transition != nullptr) {
8443 : Handle<Map> transition_map(transition, isolate);
8444 : DCHECK(transition_map->has_dictionary_elements() ||
8445 : transition_map->has_fixed_typed_array_elements() ||
8446 : transition_map->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
8447 : DCHECK(!transition_map->is_extensible());
8448 106794 : JSObject::MigrateToMap(object, transition_map);
8449 154205 : } else if (transitions.CanHaveMoreTransitions()) {
8450 : // Create a new descriptor array with the appropriate property attributes
8451 : Handle<Map> new_map = Map::CopyForPreventExtensions(
8452 153533 : old_map, attrs, transition_marker, "CopyForPreventExtensions");
8453 153533 : JSObject::MigrateToMap(object, new_map);
8454 : } else {
8455 : DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map());
8456 : // Slow path: need to normalize properties for safety
8457 672 : NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0,
8458 : "SlowPreventExtensions");
8459 :
8460 : // Create a new map, since other objects with this map may be extensible.
8461 : // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
8462 : Handle<Map> new_map =
8463 672 : Map::Copy(handle(object->map()), "SlowCopyForPreventExtensions");
8464 : new_map->set_is_extensible(false);
8465 672 : if (!new_element_dictionary.is_null()) {
8466 : ElementsKind new_kind =
8467 : IsStringWrapperElementsKind(old_map->elements_kind())
8468 : ? SLOW_STRING_WRAPPER_ELEMENTS
8469 672 : : DICTIONARY_ELEMENTS;
8470 : new_map->set_elements_kind(new_kind);
8471 : }
8472 672 : JSObject::MigrateToMap(object, new_map);
8473 :
8474 : if (attrs != NONE) {
8475 170 : if (object->IsJSGlobalObject()) {
8476 : Handle<GlobalDictionary> dictionary(
8477 : JSGlobalObject::cast(*object)->global_dictionary(), isolate);
8478 89 : ApplyAttributesToDictionary(isolate, dictionary, attrs);
8479 : } else {
8480 : Handle<NameDictionary> dictionary(object->property_dictionary(),
8481 : isolate);
8482 81 : ApplyAttributesToDictionary(isolate, dictionary, attrs);
8483 : }
8484 : }
8485 : }
8486 :
8487 : // Both seal and preventExtensions always go through without modifications to
8488 : // typed array elements. Freeze works only if there are no actual elements.
8489 260999 : if (object->HasFixedTypedArrayElements()) {
8490 39 : if (attrs == FROZEN &&
8491 : JSArrayBufferView::cast(*object)->byte_length()->Number() > 0) {
8492 29 : isolate->Throw(*isolate->factory()->NewTypeError(
8493 58 : MessageTemplate::kCannotFreezeArrayBufferView));
8494 : return Nothing<bool>();
8495 : }
8496 : return Just(true);
8497 : }
8498 :
8499 : DCHECK(object->map()->has_dictionary_elements() ||
8500 : object->map()->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
8501 260940 : if (!new_element_dictionary.is_null()) {
8502 260756 : object->set_elements(*new_element_dictionary);
8503 : }
8504 :
8505 260940 : if (object->elements() != isolate->heap()->empty_slow_element_dictionary()) {
8506 : Handle<SeededNumberDictionary> dictionary(object->element_dictionary(),
8507 : isolate);
8508 : // Make sure we never go back to the fast case
8509 4351 : object->RequireSlowElements(*dictionary);
8510 : if (attrs != NONE) {
8511 3865 : ApplyAttributesToDictionary(isolate, dictionary, attrs);
8512 : }
8513 : }
8514 :
8515 : return Just(true);
8516 : }
8517 :
8518 :
8519 35106458 : Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object,
8520 : Representation representation,
8521 : FieldIndex index) {
8522 : Isolate* isolate = object->GetIsolate();
8523 35106458 : if (object->IsUnboxedDoubleField(index)) {
8524 : double value = object->RawFastDoublePropertyAt(index);
8525 33752 : return isolate->factory()->NewHeapNumber(value);
8526 : }
8527 35072708 : Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate);
8528 35072708 : return Object::WrapForRead(isolate, raw_value, representation);
8529 : }
8530 :
8531 : // static
8532 6785896 : MaybeHandle<Object> JSReceiver::ToPrimitive(Handle<JSReceiver> receiver,
8533 : ToPrimitiveHint hint) {
8534 : Isolate* const isolate = receiver->GetIsolate();
8535 : Handle<Object> exotic_to_prim;
8536 13571792 : ASSIGN_RETURN_ON_EXCEPTION(
8537 : isolate, exotic_to_prim,
8538 : GetMethod(receiver, isolate->factory()->to_primitive_symbol()), Object);
8539 6785891 : if (!exotic_to_prim->IsUndefined(isolate)) {
8540 : Handle<Object> hint_string =
8541 3823 : isolate->factory()->ToPrimitiveHintString(hint);
8542 : Handle<Object> result;
8543 7646 : ASSIGN_RETURN_ON_EXCEPTION(
8544 : isolate, result,
8545 : Execution::Call(isolate, exotic_to_prim, receiver, 1, &hint_string),
8546 : Object);
8547 3692 : if (result->IsPrimitive()) return result;
8548 0 : THROW_NEW_ERROR(isolate,
8549 : NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8550 : Object);
8551 : }
8552 : return OrdinaryToPrimitive(receiver, (hint == ToPrimitiveHint::kString)
8553 : ? OrdinaryToPrimitiveHint::kString
8554 6782068 : : OrdinaryToPrimitiveHint::kNumber);
8555 : }
8556 :
8557 :
8558 : // static
8559 6782068 : MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive(
8560 : Handle<JSReceiver> receiver, OrdinaryToPrimitiveHint hint) {
8561 : Isolate* const isolate = receiver->GetIsolate();
8562 20346204 : Handle<String> method_names[2];
8563 6782068 : switch (hint) {
8564 : case OrdinaryToPrimitiveHint::kNumber:
8565 4499 : method_names[0] = isolate->factory()->valueOf_string();
8566 4499 : method_names[1] = isolate->factory()->toString_string();
8567 4499 : break;
8568 : case OrdinaryToPrimitiveHint::kString:
8569 6777569 : method_names[0] = isolate->factory()->toString_string();
8570 6777569 : method_names[1] = isolate->factory()->valueOf_string();
8571 6777569 : break;
8572 : }
8573 6785196 : for (Handle<String> name : method_names) {
8574 : Handle<Object> method;
8575 13567130 : ASSIGN_RETURN_ON_EXCEPTION(isolate, method,
8576 : JSReceiver::GetProperty(receiver, name), Object);
8577 6783547 : if (method->IsCallable()) {
8578 : Handle<Object> result;
8579 13566104 : ASSIGN_RETURN_ON_EXCEPTION(
8580 : isolate, result,
8581 : Execution::Call(isolate, method, receiver, 0, nullptr), Object);
8582 6769323 : if (result->IsPrimitive()) return result;
8583 : }
8584 : }
8585 268 : THROW_NEW_ERROR(isolate,
8586 : NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8587 : Object);
8588 : }
8589 :
8590 :
8591 : // TODO(cbruni/jkummerow): Consider moving this into elements.cc.
8592 152253 : bool JSObject::HasEnumerableElements() {
8593 : // TODO(cbruni): cleanup
8594 : JSObject* object = this;
8595 152253 : switch (object->GetElementsKind()) {
8596 : case PACKED_SMI_ELEMENTS:
8597 : case PACKED_ELEMENTS:
8598 : case PACKED_DOUBLE_ELEMENTS: {
8599 : int length = object->IsJSArray()
8600 : ? Smi::ToInt(JSArray::cast(object)->length())
8601 62531 : : object->elements()->length();
8602 62531 : return length > 0;
8603 : }
8604 : case HOLEY_SMI_ELEMENTS:
8605 : case HOLEY_ELEMENTS: {
8606 : FixedArray* elements = FixedArray::cast(object->elements());
8607 : int length = object->IsJSArray()
8608 : ? Smi::ToInt(JSArray::cast(object)->length())
8609 89437 : : elements->length();
8610 : Isolate* isolate = GetIsolate();
8611 2622242 : for (int i = 0; i < length; i++) {
8612 2558433 : if (!elements->is_the_hole(isolate, i)) return true;
8613 : }
8614 : return false;
8615 : }
8616 : case HOLEY_DOUBLE_ELEMENTS: {
8617 : int length = object->IsJSArray()
8618 : ? Smi::ToInt(JSArray::cast(object)->length())
8619 50 : : object->elements()->length();
8620 : // Zero-length arrays would use the empty FixedArray...
8621 50 : if (length == 0) return false;
8622 : // ...so only cast to FixedDoubleArray otherwise.
8623 : FixedDoubleArray* elements = FixedDoubleArray::cast(object->elements());
8624 50 : for (int i = 0; i < length; i++) {
8625 50 : if (!elements->is_the_hole(i)) return true;
8626 : }
8627 : return false;
8628 : }
8629 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
8630 : case TYPE##_ELEMENTS:
8631 :
8632 : TYPED_ARRAYS(TYPED_ARRAY_CASE)
8633 : #undef TYPED_ARRAY_CASE
8634 : {
8635 : int length = object->elements()->length();
8636 0 : return length > 0;
8637 : }
8638 : case DICTIONARY_ELEMENTS: {
8639 : SeededNumberDictionary* elements =
8640 : SeededNumberDictionary::cast(object->elements());
8641 175 : return elements->NumberOfEnumerableProperties() > 0;
8642 : }
8643 : case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
8644 : case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
8645 : // We're approximating non-empty arguments objects here.
8646 : return true;
8647 : case FAST_STRING_WRAPPER_ELEMENTS:
8648 : case SLOW_STRING_WRAPPER_ELEMENTS:
8649 0 : if (String::cast(JSValue::cast(object)->value())->length() > 0) {
8650 : return true;
8651 : }
8652 0 : return object->elements()->length() > 0;
8653 : case NO_ELEMENTS:
8654 0 : return false;
8655 : }
8656 0 : UNREACHABLE();
8657 : }
8658 :
8659 228779 : int Map::NumberOfEnumerableProperties() const {
8660 : int result = 0;
8661 : DescriptorArray* descs = instance_descriptors();
8662 : int limit = NumberOfOwnDescriptors();
8663 1211740 : for (int i = 0; i < limit; i++) {
8664 2801838 : if ((descs->GetDetails(i).attributes() & ONLY_ENUMERABLE) == 0 &&
8665 835916 : !descs->GetKey(i)->FilterKey(ENUMERABLE_STRINGS)) {
8666 834147 : result++;
8667 : }
8668 : }
8669 228779 : return result;
8670 : }
8671 :
8672 6747542 : int Map::NextFreePropertyIndex() const {
8673 : int free_index = 0;
8674 : int number_of_own_descriptors = NumberOfOwnDescriptors();
8675 : DescriptorArray* descs = instance_descriptors();
8676 211917722 : for (int i = 0; i < number_of_own_descriptors; i++) {
8677 205170176 : PropertyDetails details = descs->GetDetails(i);
8678 205170180 : if (details.location() == kField) {
8679 195403536 : int candidate = details.field_index() + details.field_width_in_words();
8680 195403536 : if (candidate > free_index) free_index = candidate;
8681 : }
8682 : }
8683 6747546 : return free_index;
8684 : }
8685 :
8686 228832 : bool Map::OnlyHasSimpleProperties() const {
8687 : // Wrapped string elements aren't explicitly stored in the elements backing
8688 : // store, but are loaded indirectly from the underlying string.
8689 225389 : return !IsStringWrapperElementsKind(elements_kind()) &&
8690 641848 : !IsSpecialReceiverMap() && !has_hidden_prototype() &&
8691 228832 : !is_dictionary_map();
8692 : }
8693 :
8694 1054 : MUST_USE_RESULT Maybe<bool> FastGetOwnValuesOrEntries(
8695 : Isolate* isolate, Handle<JSReceiver> receiver, bool get_entries,
8696 : Handle<FixedArray>* result) {
8697 : Handle<Map> map(JSReceiver::cast(*receiver)->map(), isolate);
8698 :
8699 1054 : if (!map->IsJSObjectMap()) return Just(false);
8700 766 : if (!map->OnlyHasSimpleProperties()) return Just(false);
8701 :
8702 : Handle<JSObject> object(JSObject::cast(*receiver));
8703 :
8704 : Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
8705 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
8706 : int number_of_own_elements =
8707 1172 : object->GetElementsAccessor()->GetCapacity(*object, object->elements());
8708 : Handle<FixedArray> values_or_entries = isolate->factory()->NewFixedArray(
8709 586 : number_of_own_descriptors + number_of_own_elements);
8710 586 : int count = 0;
8711 :
8712 586 : if (object->elements() != isolate->heap()->empty_fixed_array()) {
8713 496 : MAYBE_RETURN(object->GetElementsAccessor()->CollectValuesOrEntries(
8714 : isolate, object, values_or_entries, get_entries, &count,
8715 : ENUMERABLE_STRINGS),
8716 : Nothing<bool>());
8717 : }
8718 :
8719 586 : bool stable = object->map() == *map;
8720 :
8721 1592 : for (int index = 0; index < number_of_own_descriptors; index++) {
8722 : Handle<Name> next_key(descriptors->GetKey(index), isolate);
8723 1006 : if (!next_key->IsString()) continue;
8724 : Handle<Object> prop_value;
8725 :
8726 : // Directly decode from the descriptor array if |from| did not change shape.
8727 916 : if (stable) {
8728 898 : PropertyDetails details = descriptors->GetDetails(index);
8729 898 : if (!details.IsEnumerable()) continue;
8730 664 : if (details.kind() == kData) {
8731 628 : if (details.location() == kDescriptor) {
8732 : prop_value = handle(descriptors->GetValue(index), isolate);
8733 : } else {
8734 628 : Representation representation = details.representation();
8735 628 : FieldIndex field_index = FieldIndex::ForDescriptor(*map, index);
8736 : prop_value =
8737 628 : JSObject::FastPropertyAt(object, representation, field_index);
8738 : }
8739 : } else {
8740 72 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8741 : isolate, prop_value, JSReceiver::GetProperty(object, next_key),
8742 : Nothing<bool>());
8743 36 : stable = object->map() == *map;
8744 : }
8745 : } else {
8746 : // If the map did change, do a slower lookup. We are still guaranteed that
8747 : // the object has a simple shape, and that the key is a name.
8748 18 : LookupIterator it(object, next_key, LookupIterator::OWN_SKIP_INTERCEPTOR);
8749 18 : if (!it.IsFound()) continue;
8750 : DCHECK(it.state() == LookupIterator::DATA ||
8751 : it.state() == LookupIterator::ACCESSOR);
8752 18 : if (!it.IsEnumerable()) continue;
8753 36 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8754 : isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
8755 : }
8756 :
8757 682 : if (get_entries) {
8758 360 : prop_value = MakeEntryPair(isolate, next_key, prop_value);
8759 : }
8760 :
8761 1364 : values_or_entries->set(count, *prop_value);
8762 682 : count++;
8763 : }
8764 :
8765 586 : if (count < values_or_entries->length()) values_or_entries->Shrink(count);
8766 586 : *result = values_or_entries;
8767 : return Just(true);
8768 : }
8769 :
8770 1054 : MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate,
8771 : Handle<JSReceiver> object,
8772 : PropertyFilter filter,
8773 : bool get_entries) {
8774 : Handle<FixedArray> values_or_entries;
8775 1054 : if (filter == ENUMERABLE_STRINGS) {
8776 : Maybe<bool> fast_values_or_entries = FastGetOwnValuesOrEntries(
8777 1054 : isolate, object, get_entries, &values_or_entries);
8778 1054 : if (fast_values_or_entries.IsNothing()) return MaybeHandle<FixedArray>();
8779 1054 : if (fast_values_or_entries.FromJust()) return values_or_entries;
8780 : }
8781 :
8782 : PropertyFilter key_filter =
8783 468 : static_cast<PropertyFilter>(filter & ~ONLY_ENUMERABLE);
8784 :
8785 : Handle<FixedArray> keys;
8786 936 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8787 : isolate, keys,
8788 : KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, key_filter,
8789 : GetKeysConversion::kConvertToString),
8790 : MaybeHandle<FixedArray>());
8791 :
8792 468 : values_or_entries = isolate->factory()->NewFixedArray(keys->length());
8793 : int length = 0;
8794 :
8795 4092 : for (int i = 0; i < keys->length(); ++i) {
8796 : Handle<Name> key = Handle<Name>::cast(handle(keys->get(i), isolate));
8797 :
8798 1578 : if (filter & ONLY_ENUMERABLE) {
8799 : PropertyDescriptor descriptor;
8800 : Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor(
8801 1578 : isolate, object, key, &descriptor);
8802 1578 : MAYBE_RETURN(did_get_descriptor, MaybeHandle<FixedArray>());
8803 3108 : if (!did_get_descriptor.FromJust() || !descriptor.enumerable()) continue;
8804 : }
8805 :
8806 : Handle<Object> value;
8807 1944 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8808 : isolate, value, JSReceiver::GetPropertyOrElement(object, key),
8809 : MaybeHandle<FixedArray>());
8810 :
8811 972 : if (get_entries) {
8812 : Handle<FixedArray> entry_storage =
8813 495 : isolate->factory()->NewUninitializedFixedArray(2);
8814 495 : entry_storage->set(0, *key);
8815 495 : entry_storage->set(1, *value);
8816 : value = isolate->factory()->NewJSArrayWithElements(entry_storage,
8817 495 : PACKED_ELEMENTS, 2);
8818 : }
8819 :
8820 972 : values_or_entries->set(length, *value);
8821 972 : length++;
8822 : }
8823 468 : if (length < values_or_entries->length()) values_or_entries->Shrink(length);
8824 468 : return values_or_entries;
8825 : }
8826 :
8827 649 : MaybeHandle<FixedArray> JSReceiver::GetOwnValues(Handle<JSReceiver> object,
8828 : PropertyFilter filter) {
8829 649 : return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, false);
8830 : }
8831 :
8832 405 : MaybeHandle<FixedArray> JSReceiver::GetOwnEntries(Handle<JSReceiver> object,
8833 : PropertyFilter filter) {
8834 405 : return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, true);
8835 : }
8836 :
8837 174321 : bool Map::DictionaryElementsInPrototypeChainOnly() {
8838 174321 : if (IsDictionaryElementsKind(elements_kind())) {
8839 : return false;
8840 : }
8841 :
8842 506629 : for (PrototypeIterator iter(this); !iter.IsAtEnd(); iter.Advance()) {
8843 : // Be conservative, don't walk into proxies.
8844 685236 : if (iter.GetCurrent()->IsJSProxy()) return true;
8845 : // String wrappers have non-configurable, non-writable elements.
8846 685236 : if (iter.GetCurrent()->IsStringWrapper()) return true;
8847 342598 : JSObject* current = iter.GetCurrent<JSObject>();
8848 :
8849 350835 : if (current->HasDictionaryElements() &&
8850 8237 : current->element_dictionary()->requires_slow_elements()) {
8851 : return true;
8852 : }
8853 :
8854 334561 : if (current->HasSlowArgumentsElements()) {
8855 : FixedArray* parameter_map = FixedArray::cast(current->elements());
8856 : Object* arguments = parameter_map->get(1);
8857 0 : if (SeededNumberDictionary::cast(arguments)->requires_slow_elements()) {
8858 : return true;
8859 : }
8860 : }
8861 : }
8862 :
8863 164011 : return false;
8864 : }
8865 :
8866 :
8867 444764 : MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
8868 : Handle<Name> name,
8869 : Handle<Object> getter,
8870 : Handle<Object> setter,
8871 : PropertyAttributes attributes) {
8872 : Isolate* isolate = object->GetIsolate();
8873 :
8874 : LookupIterator it = LookupIterator::PropertyOrElement(
8875 444764 : isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
8876 444764 : return DefineAccessor(&it, getter, setter, attributes);
8877 : }
8878 :
8879 :
8880 1962118 : MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it,
8881 : Handle<Object> getter,
8882 : Handle<Object> setter,
8883 : PropertyAttributes attributes) {
8884 : Isolate* isolate = it->isolate();
8885 :
8886 654041 : it->UpdateProtector();
8887 :
8888 654041 : if (it->state() == LookupIterator::ACCESS_CHECK) {
8889 1759 : if (!it->HasAccess()) {
8890 5 : isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
8891 5 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
8892 0 : return isolate->factory()->undefined_value();
8893 : }
8894 1754 : it->Next();
8895 : }
8896 :
8897 : Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
8898 : // Ignore accessors on typed arrays.
8899 680197 : if (it->IsElement() && object->HasFixedTypedArrayElements()) {
8900 0 : return it->factory()->undefined_value();
8901 : }
8902 :
8903 : DCHECK(getter->IsCallable() || getter->IsUndefined(isolate) ||
8904 : getter->IsNull(isolate) || getter->IsFunctionTemplateInfo());
8905 : DCHECK(setter->IsCallable() || setter->IsUndefined(isolate) ||
8906 : setter->IsNull(isolate) || setter->IsFunctionTemplateInfo());
8907 654036 : it->TransitionToAccessorProperty(getter, setter, attributes);
8908 :
8909 654036 : return isolate->factory()->undefined_value();
8910 : }
8911 :
8912 :
8913 124136 : MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
8914 : Handle<AccessorInfo> info) {
8915 : Isolate* isolate = object->GetIsolate();
8916 : Handle<Name> name(Name::cast(info->name()), isolate);
8917 :
8918 : LookupIterator it = LookupIterator::PropertyOrElement(
8919 124136 : isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
8920 :
8921 : // Duplicate ACCESS_CHECK outside of GetPropertyAttributes for the case that
8922 : // the FailedAccessCheckCallbackFunction doesn't throw an exception.
8923 : //
8924 : // TODO(verwaest): Force throw an exception if the callback doesn't, so we can
8925 : // remove reliance on default return values.
8926 124136 : if (it.state() == LookupIterator::ACCESS_CHECK) {
8927 7356 : if (!it.HasAccess()) {
8928 5 : isolate->ReportFailedAccessCheck(object);
8929 5 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
8930 0 : return it.factory()->undefined_value();
8931 : }
8932 7351 : it.Next();
8933 : }
8934 :
8935 : // Ignore accessors on typed arrays.
8936 124143 : if (it.IsElement() && object->HasFixedTypedArrayElements()) {
8937 0 : return it.factory()->undefined_value();
8938 : }
8939 :
8940 124131 : CHECK(GetPropertyAttributes(&it).IsJust());
8941 :
8942 : // ES5 forbids turning a property into an accessor if it's not
8943 : // configurable. See 8.6.1 (Table 5).
8944 124178 : if (it.IsFound() && !it.IsConfigurable()) {
8945 50 : return it.factory()->undefined_value();
8946 : }
8947 :
8948 124106 : it.TransitionToAccessorPair(info, info->property_attributes());
8949 :
8950 124106 : return object;
8951 : }
8952 :
8953 50 : Object* JSObject::SlowReverseLookup(Object* value) {
8954 50 : if (HasFastProperties()) {
8955 : int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
8956 : DescriptorArray* descs = map()->instance_descriptors();
8957 : bool value_is_number = value->IsNumber();
8958 250 : for (int i = 0; i < number_of_own_descriptors; i++) {
8959 220 : PropertyDetails details = descs->GetDetails(i);
8960 220 : if (details.location() == kField) {
8961 : DCHECK_EQ(kData, details.kind());
8962 0 : FieldIndex field_index = FieldIndex::ForDescriptor(map(), i);
8963 0 : if (IsUnboxedDoubleField(field_index)) {
8964 0 : if (value_is_number) {
8965 : double property = RawFastDoublePropertyAt(field_index);
8966 0 : if (property == value->Number()) {
8967 0 : return descs->GetKey(i);
8968 : }
8969 : }
8970 : } else {
8971 0 : Object* property = RawFastPropertyAt(field_index);
8972 0 : if (field_index.is_double()) {
8973 : DCHECK(property->IsMutableHeapNumber());
8974 0 : if (value_is_number && property->Number() == value->Number()) {
8975 0 : return descs->GetKey(i);
8976 : }
8977 0 : } else if (property == value) {
8978 0 : return descs->GetKey(i);
8979 : }
8980 : }
8981 : } else {
8982 : DCHECK_EQ(kDescriptor, details.location());
8983 220 : if (details.kind() == kData) {
8984 210 : if (descs->GetValue(i) == value) {
8985 10 : return descs->GetKey(i);
8986 : }
8987 : }
8988 : }
8989 : }
8990 30 : return GetHeap()->undefined_value();
8991 10 : } else if (IsJSGlobalObject()) {
8992 : return JSGlobalObject::cast(this)->global_dictionary()->SlowReverseLookup(
8993 10 : value);
8994 : } else {
8995 0 : return property_dictionary()->SlowReverseLookup(value);
8996 : }
8997 : }
8998 :
8999 21708450 : Handle<Map> Map::RawCopy(Handle<Map> map, int instance_size,
9000 : int inobject_properties) {
9001 : Isolate* isolate = map->GetIsolate();
9002 : Handle<Map> result = isolate->factory()->NewMap(
9003 : map->instance_type(), instance_size, TERMINAL_FAST_ELEMENTS_KIND,
9004 21708450 : inobject_properties);
9005 : Handle<Object> prototype(map->prototype(), isolate);
9006 21708450 : Map::SetPrototype(result, prototype);
9007 43416901 : result->set_constructor_or_backpointer(map->GetConstructor());
9008 : result->set_bit_field(map->bit_field());
9009 : result->set_bit_field2(map->bit_field2());
9010 : int new_bit_field3 = map->bit_field3();
9011 : new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true);
9012 : new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0);
9013 : new_bit_field3 = EnumLengthBits::update(new_bit_field3,
9014 : kInvalidEnumCacheSentinel);
9015 21708449 : new_bit_field3 = Deprecated::update(new_bit_field3, false);
9016 21708449 : if (!map->is_dictionary_map()) {
9017 20595001 : new_bit_field3 = IsUnstable::update(new_bit_field3, false);
9018 : }
9019 21708449 : result->set_bit_field3(new_bit_field3);
9020 21708449 : return result;
9021 : }
9022 :
9023 :
9024 918333 : Handle<Map> Map::Normalize(Handle<Map> fast_map, PropertyNormalizationMode mode,
9025 : const char* reason) {
9026 : DCHECK(!fast_map->is_dictionary_map());
9027 :
9028 : Isolate* isolate = fast_map->GetIsolate();
9029 : Handle<Object> maybe_cache(isolate->native_context()->normalized_map_cache(),
9030 1836666 : isolate);
9031 : bool use_cache =
9032 1673643 : !fast_map->is_prototype_map() && !maybe_cache->IsUndefined(isolate);
9033 : Handle<NormalizedMapCache> cache;
9034 918333 : if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache);
9035 :
9036 : Handle<Map> new_map;
9037 2428831 : if (use_cache && cache->Get(fast_map, mode).ToHandle(&new_map)) {
9038 : #ifdef VERIFY_HEAP
9039 : if (FLAG_verify_heap) new_map->DictionaryMapVerify();
9040 : #endif
9041 : #ifdef ENABLE_SLOW_DCHECKS
9042 : if (FLAG_enable_slow_asserts) {
9043 : // The cached map should match newly created normalized map bit-by-bit,
9044 : // except for the code cache, which can contain some ics which can be
9045 : // applied to the shared map, dependent code and weak cell cache.
9046 : Handle<Map> fresh = Map::CopyNormalized(fast_map, mode);
9047 :
9048 : if (new_map->is_prototype_map()) {
9049 : // For prototype maps, the PrototypeInfo is not copied.
9050 : DCHECK_EQ(0, memcmp(fresh->address(), new_map->address(),
9051 : kTransitionsOrPrototypeInfoOffset));
9052 : DCHECK_EQ(fresh->raw_transitions(), Smi::kZero);
9053 : STATIC_ASSERT(kDescriptorsOffset ==
9054 : kTransitionsOrPrototypeInfoOffset + kPointerSize);
9055 : DCHECK_EQ(0, memcmp(HeapObject::RawField(*fresh, kDescriptorsOffset),
9056 : HeapObject::RawField(*new_map, kDescriptorsOffset),
9057 : kDependentCodeOffset - kDescriptorsOffset));
9058 : } else {
9059 : DCHECK_EQ(0, memcmp(fresh->address(), new_map->address(),
9060 : Map::kDependentCodeOffset));
9061 : }
9062 : STATIC_ASSERT(Map::kWeakCellCacheOffset ==
9063 : Map::kDependentCodeOffset + kPointerSize);
9064 : int offset = Map::kWeakCellCacheOffset + kPointerSize;
9065 : DCHECK_EQ(0, memcmp(fresh->address() + offset,
9066 : new_map->address() + offset, Map::kSize - offset));
9067 : }
9068 : #endif
9069 : } else {
9070 365336 : new_map = Map::CopyNormalized(fast_map, mode);
9071 365336 : if (use_cache) {
9072 202252 : Handle<WeakCell> cell = Map::WeakCellForMap(new_map);
9073 202252 : cache->Set(fast_map, new_map, cell);
9074 202252 : isolate->counters()->maps_normalized()->Increment();
9075 : }
9076 : #if V8_TRACE_MAPS
9077 : if (FLAG_trace_maps) {
9078 : PrintF("[TraceMaps: Normalize from= %p to= %p reason= %s ]\n",
9079 : reinterpret_cast<void*>(*fast_map),
9080 : reinterpret_cast<void*>(*new_map), reason);
9081 : }
9082 : #endif
9083 : }
9084 918333 : fast_map->NotifyLeafMapLayoutChange();
9085 918333 : return new_map;
9086 : }
9087 :
9088 :
9089 365397 : Handle<Map> Map::CopyNormalized(Handle<Map> map,
9090 : PropertyNormalizationMode mode) {
9091 : int new_instance_size = map->instance_size();
9092 365397 : if (mode == CLEAR_INOBJECT_PROPERTIES) {
9093 102307 : new_instance_size -= map->GetInObjectProperties() * kPointerSize;
9094 : }
9095 :
9096 : Handle<Map> result = RawCopy(
9097 : map, new_instance_size,
9098 730794 : mode == CLEAR_INOBJECT_PROPERTIES ? 0 : map->GetInObjectProperties());
9099 : // Clear the unused_property_fields explicitly as this field should not
9100 : // be accessed for normalized maps.
9101 365397 : result->SetInObjectUnusedPropertyFields(0);
9102 : result->set_dictionary_map(true);
9103 : result->set_migration_target(false);
9104 : result->set_may_have_interesting_symbols(true);
9105 : result->set_construction_counter(kNoSlackTracking);
9106 :
9107 : #ifdef VERIFY_HEAP
9108 : if (FLAG_verify_heap) result->DictionaryMapVerify();
9109 : #endif
9110 :
9111 365397 : return result;
9112 : }
9113 :
9114 : // Return an immutable prototype exotic object version of the input map.
9115 : // Never even try to cache it in the transition tree, as it is intended
9116 : // for the global object and its prototype chain, and excluding it saves
9117 : // memory on the map transition tree.
9118 :
9119 : // static
9120 6 : Handle<Map> Map::TransitionToImmutableProto(Handle<Map> map) {
9121 6 : Handle<Map> new_map = Map::Copy(map, "ImmutablePrototype");
9122 : new_map->set_immutable_proto(true);
9123 6 : return new_map;
9124 : }
9125 :
9126 : namespace {
9127 : void EnsureInitialMap(Handle<Map> map) {
9128 : #ifdef DEBUG
9129 : Isolate* isolate = map->GetIsolate();
9130 : // Strict function maps have Function as a constructor but the
9131 : // Function's initial map is a sloppy function map. Same holds for
9132 : // GeneratorFunction / AsyncFunction and its initial map.
9133 : Object* constructor = map->GetConstructor();
9134 : DCHECK(constructor->IsJSFunction());
9135 : DCHECK(*map == JSFunction::cast(constructor)->initial_map() ||
9136 : *map == *isolate->strict_function_map() ||
9137 : *map == *isolate->strict_function_with_name_map() ||
9138 : *map == *isolate->generator_function_map() ||
9139 : *map == *isolate->generator_function_with_name_map() ||
9140 : *map == *isolate->generator_function_with_home_object_map() ||
9141 : *map == *isolate->generator_function_with_name_and_home_object_map() ||
9142 : *map == *isolate->async_function_map() ||
9143 : *map == *isolate->async_function_with_name_map() ||
9144 : *map == *isolate->async_function_with_home_object_map() ||
9145 : *map == *isolate->async_function_with_name_and_home_object_map());
9146 : #endif
9147 : // Initial maps must always own their descriptors and it's descriptor array
9148 : // does not contain descriptors that do not belong to the map.
9149 : DCHECK(map->owns_descriptors());
9150 : DCHECK_EQ(map->NumberOfOwnDescriptors(),
9151 : map->instance_descriptors()->number_of_descriptors());
9152 : }
9153 : } // namespace
9154 :
9155 : // static
9156 61 : Handle<Map> Map::CopyInitialMapNormalized(Handle<Map> map,
9157 : PropertyNormalizationMode mode) {
9158 : EnsureInitialMap(map);
9159 61 : return CopyNormalized(map, mode);
9160 : }
9161 :
9162 : // static
9163 132881 : Handle<Map> Map::CopyInitialMap(Handle<Map> map, int instance_size,
9164 : int inobject_properties,
9165 : int unused_property_fields) {
9166 : EnsureInitialMap(map);
9167 132881 : Handle<Map> result = RawCopy(map, instance_size, inobject_properties);
9168 :
9169 : // Please note instance_type and instance_size are set when allocated.
9170 132881 : result->SetInObjectUnusedPropertyFields(unused_property_fields);
9171 :
9172 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9173 132881 : if (number_of_own_descriptors > 0) {
9174 : // The copy will use the same descriptors array.
9175 : result->UpdateDescriptors(map->instance_descriptors(),
9176 3034 : map->GetLayoutDescriptor());
9177 : result->SetNumberOfOwnDescriptors(number_of_own_descriptors);
9178 :
9179 : DCHECK_EQ(result->NumberOfFields(),
9180 : result->GetInObjectProperties() - result->UnusedPropertyFields());
9181 : }
9182 :
9183 132881 : return result;
9184 : }
9185 :
9186 :
9187 21210169 : Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) {
9188 : Handle<Map> result =
9189 : RawCopy(map, map->instance_size(),
9190 42420338 : map->IsJSObjectMap() ? map->GetInObjectProperties() : 0);
9191 :
9192 : // Please note instance_type and instance_size are set when allocated.
9193 21210172 : if (map->IsJSObjectMap()) {
9194 : result->CopyUnusedPropertyFields(*map);
9195 : }
9196 21210172 : map->NotifyLeafMapLayoutChange();
9197 21210172 : return result;
9198 : }
9199 :
9200 :
9201 4824044 : Handle<Map> Map::ShareDescriptor(Handle<Map> map,
9202 : Handle<DescriptorArray> descriptors,
9203 : Descriptor* descriptor) {
9204 : // Sanity check. This path is only to be taken if the map owns its descriptor
9205 : // array, implying that its NumberOfOwnDescriptors equals the number of
9206 : // descriptors in the descriptor array.
9207 : DCHECK_EQ(map->NumberOfOwnDescriptors(),
9208 : map->instance_descriptors()->number_of_descriptors());
9209 :
9210 4824044 : Handle<Map> result = CopyDropDescriptors(map);
9211 : Handle<Name> name = descriptor->GetKey();
9212 :
9213 : // Properly mark the {result} if the {name} is an "interesting symbol".
9214 4824044 : if (name->IsInterestingSymbol()) {
9215 : result->set_may_have_interesting_symbols(true);
9216 : }
9217 :
9218 : // Ensure there's space for the new descriptor in the shared descriptor array.
9219 4824044 : if (descriptors->NumberOfSlackDescriptors() == 0) {
9220 : int old_size = descriptors->number_of_descriptors();
9221 2414661 : if (old_size == 0) {
9222 382 : descriptors = DescriptorArray::Allocate(map->GetIsolate(), 0, 1);
9223 : } else {
9224 2414279 : int slack = SlackForArraySize(old_size, kMaxNumberOfDescriptors);
9225 2414279 : EnsureDescriptorSlack(map, slack);
9226 : descriptors = handle(map->instance_descriptors());
9227 : }
9228 : }
9229 :
9230 : Handle<LayoutDescriptor> layout_descriptor =
9231 : FLAG_unbox_double_fields
9232 : ? LayoutDescriptor::ShareAppend(map, descriptor->GetDetails())
9233 4824044 : : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
9234 :
9235 : {
9236 : DisallowHeapAllocation no_gc;
9237 4824044 : descriptors->Append(descriptor);
9238 4824043 : result->InitializeDescriptors(*descriptors, *layout_descriptor);
9239 : }
9240 :
9241 : DCHECK(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1);
9242 4824043 : ConnectTransition(map, result, name, SIMPLE_PROPERTY_TRANSITION);
9243 :
9244 4824044 : return result;
9245 : }
9246 :
9247 : #if V8_TRACE_MAPS
9248 :
9249 : // static
9250 : void Map::TraceTransition(const char* what, Map* from, Map* to, Name* name) {
9251 : if (FLAG_trace_maps) {
9252 : PrintF("[TraceMaps: %s from= %p to= %p name= ", what,
9253 : reinterpret_cast<void*>(from), reinterpret_cast<void*>(to));
9254 : name->NameShortPrint();
9255 : PrintF(" ]\n");
9256 : }
9257 : }
9258 :
9259 :
9260 : // static
9261 : void Map::TraceAllTransitions(Map* map) {
9262 : DisallowHeapAllocation no_gc;
9263 : TransitionsAccessor transitions(map, &no_gc);
9264 : int num_transitions = transitions.NumberOfTransitions();
9265 : for (int i = -0; i < num_transitions; ++i) {
9266 : Map* target = transitions.GetTarget(i);
9267 : Name* key = transitions.GetKey(i);
9268 : Map::TraceTransition("Transition", map, target, key);
9269 : Map::TraceAllTransitions(target);
9270 : }
9271 : }
9272 :
9273 : #endif // V8_TRACE_MAPS
9274 :
9275 12459974 : void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
9276 : Handle<Name> name, SimpleTransitionFlag flag) {
9277 12459974 : Isolate* isolate = parent->GetIsolate();
9278 : DCHECK_IMPLIES(name->IsInterestingSymbol(),
9279 : child->may_have_interesting_symbols());
9280 : DCHECK_IMPLIES(parent->may_have_interesting_symbols(),
9281 : child->may_have_interesting_symbols());
9282 : // Do not track transitions during bootstrap except for element transitions.
9283 18774906 : if (isolate->bootstrapper()->IsActive() &&
9284 : !name.is_identical_to(isolate->factory()->elements_transition_symbol())) {
9285 12459975 : return;
9286 : }
9287 12291426 : if (!parent->GetBackPointer()->IsUndefined(isolate)) {
9288 : parent->set_owns_descriptors(false);
9289 : } else {
9290 : // |parent| is initial map and it must keep the ownership, there must be no
9291 : // descriptors in the descriptors array that do not belong to the map.
9292 : DCHECK(parent->owns_descriptors());
9293 : DCHECK_EQ(parent->NumberOfOwnDescriptors(),
9294 : parent->instance_descriptors()->number_of_descriptors());
9295 : }
9296 6145713 : if (parent->is_prototype_map()) {
9297 : DCHECK(child->is_prototype_map());
9298 : #if V8_TRACE_MAPS
9299 : Map::TraceTransition("NoTransition", *parent, *child, *name);
9300 : #endif
9301 : } else {
9302 6145713 : TransitionsAccessor(parent).Insert(name, child, flag);
9303 : #if V8_TRACE_MAPS
9304 : Map::TraceTransition("Transition", *parent, *child, *name);
9305 : #endif
9306 : }
9307 : }
9308 :
9309 :
9310 15704120 : Handle<Map> Map::CopyReplaceDescriptors(
9311 : Handle<Map> map, Handle<DescriptorArray> descriptors,
9312 : Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag,
9313 : MaybeHandle<Name> maybe_name, const char* reason,
9314 : SimpleTransitionFlag simple_flag) {
9315 : DCHECK(descriptors->IsSortedNoDuplicates());
9316 :
9317 15704120 : Handle<Map> result = CopyDropDescriptors(map);
9318 :
9319 : // Properly mark the {result} if the {name} is an "interesting symbol".
9320 : Handle<Name> name;
9321 26530773 : if (maybe_name.ToHandle(&name) && name->IsInterestingSymbol()) {
9322 : result->set_may_have_interesting_symbols(true);
9323 : }
9324 :
9325 15704122 : if (!map->is_prototype_map()) {
9326 36875724 : if (flag == INSERT_TRANSITION &&
9327 27256008 : TransitionsAccessor(map).CanHaveMoreTransitions()) {
9328 7482050 : result->InitializeDescriptors(*descriptors, *layout_descriptor);
9329 :
9330 : DCHECK(!maybe_name.is_null());
9331 7482049 : ConnectTransition(map, result, name, simple_flag);
9332 : } else {
9333 4809858 : descriptors->GeneralizeAllFields();
9334 : result->InitializeDescriptors(*descriptors,
9335 4809859 : LayoutDescriptor::FastPointerLayout());
9336 : }
9337 : } else {
9338 3412214 : result->InitializeDescriptors(*descriptors, *layout_descriptor);
9339 : }
9340 : #if V8_TRACE_MAPS
9341 : if (FLAG_trace_maps &&
9342 : // Mirror conditions above that did not call ConnectTransition().
9343 : (map->is_prototype_map() ||
9344 : !(flag == INSERT_TRANSITION &&
9345 : TransitionsAccessor(map).CanHaveMoreTransitions()))) {
9346 : PrintF("[TraceMaps: ReplaceDescriptors from= %p to= %p reason= %s ]\n",
9347 : reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*result),
9348 : reason);
9349 : }
9350 : #endif
9351 :
9352 15704122 : return result;
9353 : }
9354 :
9355 :
9356 : // Creates transition tree starting from |split_map| and adding all descriptors
9357 : // starting from descriptor with index |split_map|.NumberOfOwnDescriptors().
9358 : // The way how it is done is tricky because of GC and special descriptors
9359 : // marking logic.
9360 24903 : Handle<Map> Map::AddMissingTransitions(
9361 : Handle<Map> split_map, Handle<DescriptorArray> descriptors,
9362 : Handle<LayoutDescriptor> full_layout_descriptor) {
9363 : DCHECK(descriptors->IsSortedNoDuplicates());
9364 : int split_nof = split_map->NumberOfOwnDescriptors();
9365 : int nof_descriptors = descriptors->number_of_descriptors();
9366 : DCHECK_LT(split_nof, nof_descriptors);
9367 :
9368 : // Start with creating last map which will own full descriptors array.
9369 : // This is necessary to guarantee that GC will mark the whole descriptor
9370 : // array if any of the allocations happening below fail.
9371 : // Number of unused properties is temporarily incorrect and the layout
9372 : // descriptor could unnecessarily be in slow mode but we will fix after
9373 : // all the other intermediate maps are created.
9374 24903 : Handle<Map> last_map = CopyDropDescriptors(split_map);
9375 24903 : last_map->InitializeDescriptors(*descriptors, *full_layout_descriptor);
9376 24903 : last_map->SetInObjectUnusedPropertyFields(0);
9377 :
9378 : // During creation of intermediate maps we violate descriptors sharing
9379 : // invariant since the last map is not yet connected to the transition tree
9380 : // we create here. But it is safe because GC never trims map's descriptors
9381 : // if there are no dead transitions from that map and this is exactly the
9382 : // case for all the intermediate maps we create here.
9383 : Handle<Map> map = split_map;
9384 62585 : for (int i = split_nof; i < nof_descriptors - 1; ++i) {
9385 37682 : Handle<Map> new_map = CopyDropDescriptors(map);
9386 37682 : InstallDescriptors(map, new_map, i, descriptors, full_layout_descriptor);
9387 37682 : map = new_map;
9388 : }
9389 24903 : map->NotifyLeafMapLayoutChange();
9390 : InstallDescriptors(map, last_map, nof_descriptors - 1, descriptors,
9391 24903 : full_layout_descriptor);
9392 24903 : return last_map;
9393 : }
9394 :
9395 :
9396 : // Since this method is used to rewrite an existing transition tree, it can
9397 : // always insert transitions without checking.
9398 62585 : void Map::InstallDescriptors(Handle<Map> parent, Handle<Map> child,
9399 : int new_descriptor,
9400 : Handle<DescriptorArray> descriptors,
9401 : Handle<LayoutDescriptor> full_layout_descriptor) {
9402 : DCHECK(descriptors->IsSortedNoDuplicates());
9403 :
9404 62585 : child->set_instance_descriptors(*descriptors);
9405 62585 : child->SetNumberOfOwnDescriptors(new_descriptor + 1);
9406 : child->CopyUnusedPropertyFields(*parent);
9407 62585 : PropertyDetails details = descriptors->GetDetails(new_descriptor);
9408 62585 : if (details.location() == kField) {
9409 60450 : child->AccountAddedPropertyField();
9410 : }
9411 :
9412 : if (FLAG_unbox_double_fields) {
9413 : Handle<LayoutDescriptor> layout_descriptor =
9414 : LayoutDescriptor::AppendIfFastOrUseFull(parent, details,
9415 62585 : full_layout_descriptor);
9416 62585 : child->set_layout_descriptor(*layout_descriptor);
9417 : #ifdef VERIFY_HEAP
9418 : // TODO(ishell): remove these checks from VERIFY_HEAP mode.
9419 : if (FLAG_verify_heap) {
9420 : CHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
9421 : }
9422 : #else
9423 : SLOW_DCHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
9424 : #endif
9425 62585 : child->set_visitor_id(Map::GetVisitorId(*child));
9426 : }
9427 :
9428 : Handle<Name> name = handle(descriptors->GetKey(new_descriptor));
9429 125099 : if (parent->may_have_interesting_symbols() || name->IsInterestingSymbol()) {
9430 : child->set_may_have_interesting_symbols(true);
9431 : }
9432 62585 : ConnectTransition(parent, child, name, SIMPLE_PROPERTY_TRANSITION);
9433 62585 : }
9434 :
9435 :
9436 174775 : Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind,
9437 : TransitionFlag flag) {
9438 : Map* maybe_elements_transition_map = nullptr;
9439 174775 : if (flag == INSERT_TRANSITION) {
9440 : // Ensure we are requested to add elements kind transition "near the root".
9441 : DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(),
9442 : map->NumberOfOwnDescriptors());
9443 :
9444 172261 : maybe_elements_transition_map = map->ElementsTransitionMap();
9445 : DCHECK(maybe_elements_transition_map == nullptr ||
9446 : (maybe_elements_transition_map->elements_kind() ==
9447 : DICTIONARY_ELEMENTS &&
9448 : kind == DICTIONARY_ELEMENTS));
9449 : DCHECK(!IsFastElementsKind(kind) ||
9450 : IsMoreGeneralElementsKindTransition(map->elements_kind(), kind));
9451 : DCHECK(kind != map->elements_kind());
9452 : }
9453 :
9454 172261 : bool insert_transition = flag == INSERT_TRANSITION &&
9455 610474 : TransitionsAccessor(map).CanHaveMoreTransitions() &&
9456 2514 : maybe_elements_transition_map == nullptr;
9457 :
9458 174775 : if (insert_transition) {
9459 91177 : Handle<Map> new_map = CopyForTransition(map, "CopyAsElementsKind");
9460 : new_map->set_elements_kind(kind);
9461 :
9462 : Isolate* isolate = map->GetIsolate();
9463 : Handle<Name> name = isolate->factory()->elements_transition_symbol();
9464 91177 : ConnectTransition(map, new_map, name, SPECIAL_TRANSITION);
9465 91177 : return new_map;
9466 : }
9467 :
9468 : // Create a new free-floating map only if we are not allowed to store it.
9469 83598 : Handle<Map> new_map = Copy(map, "CopyAsElementsKind");
9470 : new_map->set_elements_kind(kind);
9471 83598 : return new_map;
9472 : }
9473 :
9474 687 : Handle<Map> Map::AsLanguageMode(Handle<Map> initial_map,
9475 : Handle<SharedFunctionInfo> shared_info) {
9476 : DCHECK_EQ(JS_FUNCTION_TYPE, initial_map->instance_type());
9477 : // Initial map for sloppy mode function is stored in the function
9478 : // constructor. Initial maps for strict mode are cached as special transitions
9479 : // using |strict_function_transition_symbol| as a key.
9480 687 : if (is_sloppy(shared_info->language_mode())) return initial_map;
9481 : Isolate* isolate = initial_map->GetIsolate();
9482 :
9483 : Handle<Map> function_map(Map::cast(
9484 312 : isolate->native_context()->get(shared_info->function_map_index())));
9485 :
9486 : STATIC_ASSERT(LanguageModeSize == 2);
9487 : DCHECK_EQ(LanguageMode::kStrict, shared_info->language_mode());
9488 : Handle<Symbol> transition_symbol =
9489 : isolate->factory()->strict_function_transition_symbol();
9490 : Map* maybe_transition =
9491 156 : TransitionsAccessor(initial_map).SearchSpecial(*transition_symbol);
9492 156 : if (maybe_transition != nullptr) {
9493 : return handle(maybe_transition, isolate);
9494 : }
9495 120 : initial_map->NotifyLeafMapLayoutChange();
9496 :
9497 : // Create new map taking descriptors from the |function_map| and all
9498 : // the other details from the |initial_map|.
9499 : Handle<Map> map =
9500 : Map::CopyInitialMap(function_map, initial_map->instance_size(),
9501 : initial_map->GetInObjectProperties(),
9502 120 : initial_map->UnusedPropertyFields());
9503 120 : map->SetConstructor(initial_map->GetConstructor());
9504 120 : map->set_prototype(initial_map->prototype());
9505 : map->set_construction_counter(initial_map->construction_counter());
9506 :
9507 120 : if (TransitionsAccessor(initial_map).CanHaveMoreTransitions()) {
9508 : Map::ConnectTransition(initial_map, map, transition_symbol,
9509 120 : SPECIAL_TRANSITION);
9510 : }
9511 120 : return map;
9512 : }
9513 :
9514 :
9515 91177 : Handle<Map> Map::CopyForTransition(Handle<Map> map, const char* reason) {
9516 : DCHECK(!map->is_prototype_map());
9517 91177 : Handle<Map> new_map = CopyDropDescriptors(map);
9518 :
9519 91177 : if (map->owns_descriptors()) {
9520 : // In case the map owned its own descriptors, share the descriptors and
9521 : // transfer ownership to the new map.
9522 : // The properties did not change, so reuse descriptors.
9523 : new_map->InitializeDescriptors(map->instance_descriptors(),
9524 91175 : map->GetLayoutDescriptor());
9525 : } else {
9526 : // In case the map did not own its own descriptors, a split is forced by
9527 : // copying the map; creating a new descriptor array cell.
9528 : Handle<DescriptorArray> descriptors(map->instance_descriptors());
9529 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9530 : Handle<DescriptorArray> new_descriptors =
9531 : DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
9532 : Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9533 : map->GetIsolate());
9534 2 : new_map->InitializeDescriptors(*new_descriptors, *new_layout_descriptor);
9535 : }
9536 :
9537 : #if V8_TRACE_MAPS
9538 : if (FLAG_trace_maps) {
9539 : PrintF("[TraceMaps: CopyForTransition from= %p to= %p reason= %s ]\n",
9540 : reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*new_map),
9541 : reason);
9542 : }
9543 : #endif
9544 :
9545 91177 : return new_map;
9546 : }
9547 :
9548 :
9549 4859341 : Handle<Map> Map::Copy(Handle<Map> map, const char* reason) {
9550 : Handle<DescriptorArray> descriptors(map->instance_descriptors());
9551 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9552 : Handle<DescriptorArray> new_descriptors =
9553 4859343 : DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
9554 : Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9555 : map->GetIsolate());
9556 : return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9557 : OMIT_TRANSITION, MaybeHandle<Name>(), reason,
9558 4859341 : SPECIAL_TRANSITION);
9559 : }
9560 :
9561 :
9562 149919 : Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) {
9563 : Handle<Map> copy =
9564 299838 : Copy(handle(isolate->object_function()->initial_map()), "MapCreate");
9565 :
9566 : // Check that we do not overflow the instance size when adding the extra
9567 : // inobject properties. If the instance size overflows, we allocate as many
9568 : // properties as we can as inobject properties.
9569 149919 : if (inobject_properties > JSObject::kMaxInObjectProperties) {
9570 : inobject_properties = JSObject::kMaxInObjectProperties;
9571 : }
9572 :
9573 : int new_instance_size =
9574 149919 : JSObject::kHeaderSize + kPointerSize * inobject_properties;
9575 :
9576 : // Adjust the map with the extra inobject properties.
9577 : copy->set_instance_size(new_instance_size);
9578 : copy->SetInObjectProperties(inobject_properties);
9579 149919 : copy->SetInObjectUnusedPropertyFields(inobject_properties);
9580 149919 : copy->set_visitor_id(Map::GetVisitorId(*copy));
9581 149919 : return copy;
9582 : }
9583 :
9584 :
9585 153543 : Handle<Map> Map::CopyForPreventExtensions(Handle<Map> map,
9586 : PropertyAttributes attrs_to_add,
9587 : Handle<Symbol> transition_marker,
9588 : const char* reason) {
9589 : int num_descriptors = map->NumberOfOwnDescriptors();
9590 : Isolate* isolate = map->GetIsolate();
9591 : Handle<DescriptorArray> new_desc = DescriptorArray::CopyUpToAddAttributes(
9592 : handle(map->instance_descriptors(), isolate), num_descriptors,
9593 153543 : attrs_to_add);
9594 : Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9595 : isolate);
9596 : Handle<Map> new_map = CopyReplaceDescriptors(
9597 : map, new_desc, new_layout_descriptor, INSERT_TRANSITION,
9598 153543 : transition_marker, reason, SPECIAL_TRANSITION);
9599 : new_map->set_is_extensible(false);
9600 153543 : if (!IsFixedTypedArrayElementsKind(map->elements_kind())) {
9601 : ElementsKind new_kind = IsStringWrapperElementsKind(map->elements_kind())
9602 : ? SLOW_STRING_WRAPPER_ELEMENTS
9603 153494 : : DICTIONARY_ELEMENTS;
9604 : new_map->set_elements_kind(new_kind);
9605 : }
9606 153543 : return new_map;
9607 : }
9608 :
9609 : namespace {
9610 :
9611 11226062 : bool CanHoldValue(DescriptorArray* descriptors, int descriptor,
9612 : PropertyConstness constness, Object* value) {
9613 11226062 : PropertyDetails details = descriptors->GetDetails(descriptor);
9614 11226062 : if (details.location() == kField) {
9615 11209715 : if (details.kind() == kData) {
9616 11209715 : return IsGeneralizableTo(constness, details.constness()) &&
9617 33318983 : value->FitsRepresentation(details.representation()) &&
9618 22109268 : descriptors->GetFieldType(descriptor)->NowContains(value);
9619 : } else {
9620 : DCHECK_EQ(kAccessor, details.kind());
9621 : return false;
9622 : }
9623 :
9624 : } else {
9625 : DCHECK_EQ(kDescriptor, details.location());
9626 : DCHECK_EQ(kConst, details.constness());
9627 16347 : if (details.kind() == kData) {
9628 : DCHECK(!FLAG_track_constant_fields);
9629 : DCHECK(descriptors->GetValue(descriptor) != value ||
9630 : value->FitsRepresentation(details.representation()));
9631 16347 : return descriptors->GetValue(descriptor) == value;
9632 : } else {
9633 : DCHECK_EQ(kAccessor, details.kind());
9634 : return false;
9635 : }
9636 : }
9637 : UNREACHABLE();
9638 : }
9639 :
9640 11226062 : Handle<Map> UpdateDescriptorForValue(Handle<Map> map, int descriptor,
9641 : PropertyConstness constness,
9642 : Handle<Object> value) {
9643 11226062 : if (CanHoldValue(map->instance_descriptors(), descriptor, constness,
9644 : *value)) {
9645 10879951 : return map;
9646 : }
9647 :
9648 : Isolate* isolate = map->GetIsolate();
9649 : PropertyAttributes attributes =
9650 692222 : map->instance_descriptors()->GetDetails(descriptor).attributes();
9651 346111 : Representation representation = value->OptimalRepresentation();
9652 346111 : Handle<FieldType> type = value->OptimalType(isolate, representation);
9653 :
9654 346111 : MapUpdater mu(isolate, map);
9655 : return mu.ReconfigureToDataField(descriptor, attributes, constness,
9656 346111 : representation, type);
9657 : }
9658 :
9659 : } // namespace
9660 :
9661 : // static
9662 5669476 : Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor,
9663 : PropertyConstness constness,
9664 : Handle<Object> value) {
9665 : // Dictionaries can store any property value.
9666 : DCHECK(!map->is_dictionary_map());
9667 : // Update to the newest map before storing the property.
9668 5669476 : return UpdateDescriptorForValue(Update(map), descriptor, constness, value);
9669 : }
9670 :
9671 20702316 : Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
9672 : Handle<Object> value,
9673 : PropertyAttributes attributes,
9674 : PropertyConstness constness,
9675 : StoreFromKeyed store_mode,
9676 : bool* created_new_map) {
9677 : RuntimeCallTimerScope stats_scope(
9678 : *map, map->is_prototype_map()
9679 : ? &RuntimeCallStats::PrototypeMap_TransitionToDataProperty
9680 20702316 : : &RuntimeCallStats::Map_TransitionToDataProperty);
9681 :
9682 : DCHECK(name->IsUniqueName());
9683 : DCHECK(!map->is_dictionary_map());
9684 :
9685 : // Migrate to the newest map before storing the property.
9686 20702319 : map = Update(map);
9687 :
9688 : Map* maybe_transition =
9689 20702318 : TransitionsAccessor(map).SearchTransition(*name, kData, attributes);
9690 20702316 : if (maybe_transition != nullptr) {
9691 5556586 : *created_new_map = false;
9692 : Handle<Map> transition(maybe_transition);
9693 : int descriptor = transition->LastAdded();
9694 :
9695 : DCHECK_EQ(attributes, transition->instance_descriptors()
9696 : ->GetDetails(descriptor)
9697 : .attributes());
9698 :
9699 5556586 : return UpdateDescriptorForValue(transition, descriptor, constness, value);
9700 : }
9701 :
9702 15145730 : *created_new_map = true;
9703 : TransitionFlag flag = INSERT_TRANSITION;
9704 : MaybeHandle<Map> maybe_map;
9705 15145733 : if (!FLAG_track_constant_fields && value->IsJSFunction()) {
9706 8384952 : maybe_map = Map::CopyWithConstant(map, name, value, attributes, flag);
9707 6760781 : } else if (!map->TooManyFastProperties(store_mode)) {
9708 : Isolate* isolate = name->GetIsolate();
9709 6734774 : Representation representation = value->OptimalRepresentation();
9710 6734774 : Handle<FieldType> type = value->OptimalType(isolate, representation);
9711 : maybe_map = Map::CopyWithField(map, name, type, attributes, constness,
9712 6734773 : representation, flag);
9713 : }
9714 :
9715 : Handle<Map> result;
9716 15145731 : if (!maybe_map.ToHandle(&result)) {
9717 : Isolate* isolate = name->GetIsolate();
9718 : const char* reason = "TooManyFastProperties";
9719 : #if V8_TRACE_MAPS
9720 : std::unique_ptr<ScopedVector<char>> buffer;
9721 : if (FLAG_trace_maps) {
9722 : ScopedVector<char> name_buffer(100);
9723 : name->NameShortPrint(name_buffer);
9724 : buffer.reset(new ScopedVector<char>(128));
9725 : SNPrintF(*buffer, "TooManyFastProperties %s", name_buffer.start());
9726 : reason = buffer->start();
9727 : }
9728 : #endif
9729 26085 : Handle<Object> maybe_constructor(map->GetConstructor(), isolate);
9730 26085 : if (FLAG_feedback_normalization && map->new_target_is_base() &&
9731 26085 : maybe_constructor->IsJSFunction() &&
9732 : !JSFunction::cast(*maybe_constructor)->shared()->native()) {
9733 : Handle<JSFunction> constructor =
9734 : Handle<JSFunction>::cast(maybe_constructor);
9735 : DCHECK_NE(*constructor,
9736 : constructor->context()->native_context()->object_function());
9737 : Handle<Map> initial_map(constructor->initial_map(), isolate);
9738 0 : result = Map::Normalize(initial_map, CLEAR_INOBJECT_PROPERTIES, reason);
9739 0 : initial_map->DeprecateTransitionTree();
9740 : Handle<Object> prototype(result->prototype(), isolate);
9741 0 : JSFunction::SetInitialMap(constructor, result, prototype);
9742 :
9743 : // Deoptimize all code that embeds the previous initial map.
9744 : initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
9745 0 : isolate, DependentCode::kInitialMapChangedGroup);
9746 0 : if (!result->EquivalentToForNormalization(*map,
9747 0 : CLEAR_INOBJECT_PROPERTIES)) {
9748 0 : result = Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, reason);
9749 : }
9750 : } else {
9751 26085 : result = Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, reason);
9752 : }
9753 : }
9754 :
9755 15145731 : return result;
9756 : }
9757 :
9758 :
9759 13660 : Handle<Map> Map::ReconfigureExistingProperty(Handle<Map> map, int descriptor,
9760 : PropertyKind kind,
9761 : PropertyAttributes attributes) {
9762 : // Dictionaries have to be reconfigured in-place.
9763 : DCHECK(!map->is_dictionary_map());
9764 :
9765 27320 : if (!map->GetBackPointer()->IsMap()) {
9766 : // There is no benefit from reconstructing transition tree for maps without
9767 : // back pointers.
9768 : return CopyGeneralizeAllFields(map, map->elements_kind(), descriptor, kind,
9769 : attributes,
9770 1060 : "GenAll_AttributesMismatchProtoMap");
9771 : }
9772 :
9773 12600 : if (FLAG_trace_generalization) {
9774 0 : map->PrintReconfiguration(stdout, descriptor, kind, attributes);
9775 : }
9776 :
9777 : Isolate* isolate = map->GetIsolate();
9778 :
9779 12600 : MapUpdater mu(isolate, map);
9780 : DCHECK_EQ(kData, kind); // Only kData case is supported so far.
9781 : Handle<Map> new_map = mu.ReconfigureToDataField(
9782 : descriptor, attributes, kDefaultFieldConstness, Representation::None(),
9783 12600 : FieldType::None(isolate));
9784 12600 : return new_map;
9785 : }
9786 :
9787 606699 : Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map,
9788 : Handle<Name> name, int descriptor,
9789 : Handle<Object> getter,
9790 : Handle<Object> setter,
9791 : PropertyAttributes attributes) {
9792 : RuntimeCallTimerScope stats_scope(
9793 : isolate,
9794 : map->is_prototype_map()
9795 : ? &RuntimeCallStats::PrototypeMap_TransitionToAccessorProperty
9796 606699 : : &RuntimeCallStats::Map_TransitionToAccessorProperty);
9797 :
9798 : // At least one of the accessors needs to be a new value.
9799 : DCHECK(!getter->IsNull(isolate) || !setter->IsNull(isolate));
9800 : DCHECK(name->IsUniqueName());
9801 :
9802 : // Dictionary maps can always have additional data properties.
9803 606699 : if (map->is_dictionary_map()) return map;
9804 :
9805 : // Migrate to the newest map before transitioning to the new property.
9806 606699 : map = Update(map);
9807 :
9808 : PropertyNormalizationMode mode = map->is_prototype_map()
9809 : ? KEEP_INOBJECT_PROPERTIES
9810 606699 : : CLEAR_INOBJECT_PROPERTIES;
9811 :
9812 : Map* maybe_transition =
9813 606699 : TransitionsAccessor(map).SearchTransition(*name, kAccessor, attributes);
9814 606699 : if (maybe_transition != nullptr) {
9815 : Handle<Map> transition(maybe_transition, isolate);
9816 : DescriptorArray* descriptors = transition->instance_descriptors();
9817 : int descriptor = transition->LastAdded();
9818 : DCHECK(descriptors->GetKey(descriptor)->Equals(*name));
9819 :
9820 : DCHECK_EQ(kAccessor, descriptors->GetDetails(descriptor).kind());
9821 : DCHECK_EQ(attributes, descriptors->GetDetails(descriptor).attributes());
9822 :
9823 : Handle<Object> maybe_pair(descriptors->GetValue(descriptor), isolate);
9824 11881 : if (!maybe_pair->IsAccessorPair()) {
9825 0 : return Map::Normalize(map, mode, "TransitionToAccessorFromNonPair");
9826 : }
9827 :
9828 : Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair);
9829 11881 : if (!pair->Equals(*getter, *setter)) {
9830 11328 : return Map::Normalize(map, mode, "TransitionToDifferentAccessor");
9831 : }
9832 :
9833 553 : return transition;
9834 : }
9835 :
9836 : Handle<AccessorPair> pair;
9837 : DescriptorArray* old_descriptors = map->instance_descriptors();
9838 594818 : if (descriptor != DescriptorArray::kNotFound) {
9839 230195 : if (descriptor != map->LastAdded()) {
9840 129915 : return Map::Normalize(map, mode, "AccessorsOverwritingNonLast");
9841 : }
9842 100280 : PropertyDetails old_details = old_descriptors->GetDetails(descriptor);
9843 100280 : if (old_details.kind() != kAccessor) {
9844 98602 : return Map::Normalize(map, mode, "AccessorsOverwritingNonAccessors");
9845 : }
9846 :
9847 1678 : if (old_details.attributes() != attributes) {
9848 86 : return Map::Normalize(map, mode, "AccessorsWithAttributes");
9849 : }
9850 :
9851 : Handle<Object> maybe_pair(old_descriptors->GetValue(descriptor), isolate);
9852 1592 : if (!maybe_pair->IsAccessorPair()) {
9853 24 : return Map::Normalize(map, mode, "AccessorsOverwritingNonPair");
9854 : }
9855 :
9856 : Handle<AccessorPair> current_pair = Handle<AccessorPair>::cast(maybe_pair);
9857 1568 : if (current_pair->Equals(*getter, *setter)) return map;
9858 :
9859 : bool overwriting_accessor = false;
9860 3130 : if (!getter->IsNull(isolate) &&
9861 3036 : !current_pair->get(ACCESSOR_GETTER)->IsNull(isolate) &&
9862 : current_pair->get(ACCESSOR_GETTER) != *getter) {
9863 : overwriting_accessor = true;
9864 : }
9865 3127 : if (!setter->IsNull(isolate) &&
9866 2740 : !current_pair->get(ACCESSOR_SETTER)->IsNull(isolate) &&
9867 : current_pair->get(ACCESSOR_SETTER) != *setter) {
9868 : overwriting_accessor = true;
9869 : }
9870 1568 : if (overwriting_accessor) {
9871 1378 : return Map::Normalize(map, mode, "AccessorsOverwritingAccessors");
9872 : }
9873 :
9874 190 : pair = AccessorPair::Copy(Handle<AccessorPair>::cast(maybe_pair));
9875 729246 : } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors ||
9876 364623 : map->TooManyFastProperties(CERTAINLY_NOT_STORE_FROM_KEYED)) {
9877 0 : return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, "TooManyAccessors");
9878 : } else {
9879 364623 : pair = isolate->factory()->NewAccessorPair();
9880 : }
9881 :
9882 364813 : pair->SetComponents(*getter, *setter);
9883 :
9884 : TransitionFlag flag = INSERT_TRANSITION;
9885 : Descriptor d = Descriptor::AccessorConstant(name, pair, attributes);
9886 364813 : return Map::CopyInsertDescriptor(map, &d, flag);
9887 : }
9888 :
9889 :
9890 15496960 : Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
9891 : Descriptor* descriptor,
9892 : TransitionFlag flag) {
9893 : Handle<DescriptorArray> descriptors(map->instance_descriptors());
9894 :
9895 : // Share descriptors only if map owns descriptors and it not an initial map.
9896 57108460 : if (flag == INSERT_TRANSITION && map->owns_descriptors() &&
9897 35762870 : !map->GetBackPointer()->IsUndefined(map->GetIsolate()) &&
9898 25145050 : TransitionsAccessor(map).CanHaveMoreTransitions()) {
9899 4824044 : return ShareDescriptor(map, descriptors, descriptor);
9900 : }
9901 :
9902 : int nof = map->NumberOfOwnDescriptors();
9903 : Handle<DescriptorArray> new_descriptors =
9904 : DescriptorArray::CopyUpTo(descriptors, nof, 1);
9905 10672919 : new_descriptors->Append(descriptor);
9906 :
9907 : Handle<LayoutDescriptor> new_layout_descriptor =
9908 : FLAG_unbox_double_fields
9909 10672918 : ? LayoutDescriptor::New(map, new_descriptors, nof + 1)
9910 10672918 : : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
9911 :
9912 : return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9913 : flag, descriptor->GetKey(), "CopyAddDescriptor",
9914 10672918 : SIMPLE_PROPERTY_TRANSITION);
9915 : }
9916 :
9917 :
9918 364853 : Handle<Map> Map::CopyInsertDescriptor(Handle<Map> map,
9919 : Descriptor* descriptor,
9920 : TransitionFlag flag) {
9921 : Handle<DescriptorArray> old_descriptors(map->instance_descriptors());
9922 :
9923 : // We replace the key if it is already present.
9924 : int index = old_descriptors->SearchWithCache(map->GetIsolate(),
9925 : *descriptor->GetKey(), *map);
9926 364853 : if (index != DescriptorArray::kNotFound) {
9927 190 : return CopyReplaceDescriptor(map, old_descriptors, descriptor, index, flag);
9928 : }
9929 364663 : return CopyAddDescriptor(map, descriptor, flag);
9930 : }
9931 :
9932 :
9933 0 : Handle<DescriptorArray> DescriptorArray::CopyUpTo(
9934 : Handle<DescriptorArray> desc,
9935 : int enumeration_index,
9936 : int slack) {
9937 : return DescriptorArray::CopyUpToAddAttributes(
9938 17967490 : desc, enumeration_index, NONE, slack);
9939 : }
9940 :
9941 :
9942 18121034 : Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
9943 : Handle<DescriptorArray> desc,
9944 : int enumeration_index,
9945 : PropertyAttributes attributes,
9946 : int slack) {
9947 18121034 : if (enumeration_index + slack == 0) {
9948 : return desc->GetIsolate()->factory()->empty_descriptor_array();
9949 : }
9950 :
9951 : int size = enumeration_index;
9952 :
9953 : Handle<DescriptorArray> descriptors =
9954 16535188 : DescriptorArray::Allocate(desc->GetIsolate(), size, slack);
9955 :
9956 16535188 : if (attributes != NONE) {
9957 188391 : for (int i = 0; i < size; ++i) {
9958 : Object* value = desc->GetValue(i);
9959 : Name* key = desc->GetKey(i);
9960 188391 : PropertyDetails details = desc->GetDetails(i);
9961 : // Bulk attribute changes never affect private properties.
9962 188391 : if (!key->IsPrivate()) {
9963 : int mask = DONT_DELETE | DONT_ENUM;
9964 : // READ_ONLY is an invalid attribute for JS setters/getters.
9965 189326 : if (details.kind() != kAccessor || !value->IsAccessorPair()) {
9966 : mask |= READ_ONLY;
9967 : }
9968 : details = details.CopyAddAttributes(
9969 188373 : static_cast<PropertyAttributes>(attributes & mask));
9970 : }
9971 188391 : descriptors->Set(i, key, value, details);
9972 : }
9973 : } else {
9974 104562671 : for (int i = 0; i < size; ++i) {
9975 104562672 : descriptors->CopyFrom(i, *desc);
9976 : }
9977 : }
9978 :
9979 16594799 : if (desc->number_of_descriptors() != enumeration_index) descriptors->Sort();
9980 :
9981 16535189 : return descriptors;
9982 : }
9983 :
9984 :
9985 2303 : bool DescriptorArray::IsEqualUpTo(DescriptorArray* desc, int nof_descriptors) {
9986 27751 : for (int i = 0; i < nof_descriptors; i++) {
9987 50896 : if (GetKey(i) != desc->GetKey(i) || GetValue(i) != desc->GetValue(i)) {
9988 : return false;
9989 : }
9990 25448 : PropertyDetails details = GetDetails(i);
9991 25448 : PropertyDetails other_details = desc->GetDetails(i);
9992 50896 : if (details.kind() != other_details.kind() ||
9993 50896 : details.location() != other_details.location() ||
9994 : !details.representation().Equals(other_details.representation())) {
9995 : return false;
9996 : }
9997 : }
9998 : return true;
9999 : }
10000 :
10001 :
10002 190 : Handle<Map> Map::CopyReplaceDescriptor(Handle<Map> map,
10003 : Handle<DescriptorArray> descriptors,
10004 : Descriptor* descriptor,
10005 : int insertion_index,
10006 : TransitionFlag flag) {
10007 : Handle<Name> key = descriptor->GetKey();
10008 : DCHECK_EQ(*key, descriptors->GetKey(insertion_index));
10009 : // This function does not support replacing property fields as
10010 : // that would break property field counters.
10011 : DCHECK_NE(kField, descriptor->GetDetails().location());
10012 : DCHECK_NE(kField, descriptors->GetDetails(insertion_index).location());
10013 :
10014 : Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
10015 : descriptors, map->NumberOfOwnDescriptors());
10016 :
10017 190 : new_descriptors->Replace(insertion_index, descriptor);
10018 : Handle<LayoutDescriptor> new_layout_descriptor = LayoutDescriptor::New(
10019 190 : map, new_descriptors, new_descriptors->number_of_descriptors());
10020 :
10021 : SimpleTransitionFlag simple_flag =
10022 190 : (insertion_index == descriptors->number_of_descriptors() - 1)
10023 : ? SIMPLE_PROPERTY_TRANSITION
10024 190 : : PROPERTY_TRANSITION;
10025 : return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
10026 : flag, key, "CopyReplaceDescriptor",
10027 190 : simple_flag);
10028 : }
10029 :
10030 8437134 : Handle<FixedArray> FixedArray::SetAndGrow(Handle<FixedArray> array, int index,
10031 : Handle<Object> value) {
10032 8437134 : if (index < array->length()) {
10033 7973284 : array->set(index, *value);
10034 7973284 : return array;
10035 : }
10036 : int capacity = array->length();
10037 463850 : do {
10038 927700 : capacity = JSObject::NewElementsCapacity(capacity);
10039 : } while (capacity <= index);
10040 : Handle<FixedArray> new_array =
10041 463850 : array->GetIsolate()->factory()->NewUninitializedFixedArray(capacity);
10042 463850 : array->CopyTo(0, *new_array, 0, array->length());
10043 463850 : new_array->FillWithHoles(array->length(), new_array->length());
10044 463850 : new_array->set(index, *value);
10045 463850 : return new_array;
10046 : }
10047 :
10048 8033883 : void FixedArray::Shrink(int new_length) {
10049 : DCHECK(0 <= new_length && new_length <= length());
10050 8033883 : if (new_length < length()) {
10051 12601610 : GetHeap()->RightTrimFixedArray(this, length() - new_length);
10052 : }
10053 8033883 : }
10054 :
10055 525339 : void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos,
10056 : int len) const {
10057 : DisallowHeapAllocation no_gc;
10058 525339 : WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
10059 20999450 : for (int index = 0; index < len; index++) {
10060 40948222 : dest->set(dest_pos+index, get(pos+index), mode);
10061 : }
10062 525339 : }
10063 :
10064 : #ifdef DEBUG
10065 : bool FixedArray::IsEqualTo(FixedArray* other) {
10066 : if (length() != other->length()) return false;
10067 : for (int i = 0 ; i < length(); ++i) {
10068 : if (get(i) != other->get(i)) return false;
10069 : }
10070 : return true;
10071 : }
10072 : #endif
10073 :
10074 :
10075 : // static
10076 11560960 : void WeakFixedArray::Set(Handle<WeakFixedArray> array, int index,
10077 : Handle<HeapObject> value) {
10078 : DCHECK(array->IsEmptySlot(index)); // Don't overwrite anything.
10079 : Handle<WeakCell> cell =
10080 : value->IsMap() ? Map::WeakCellForMap(Handle<Map>::cast(value))
10081 22747214 : : array->GetIsolate()->factory()->NewWeakCell(value);
10082 23121922 : Handle<FixedArray>::cast(array)->set(index + kFirstIndex, *cell);
10083 11560961 : if (FLAG_trace_weak_arrays) {
10084 0 : PrintF("[WeakFixedArray: storing at index %d ]\n", index);
10085 : }
10086 : array->set_last_used_index(index);
10087 11560961 : }
10088 :
10089 :
10090 : // static
10091 11560959 : Handle<WeakFixedArray> WeakFixedArray::Add(Handle<Object> maybe_array,
10092 : Handle<HeapObject> value,
10093 : int* assigned_index) {
10094 : Handle<WeakFixedArray> array =
10095 11545918 : (maybe_array.is_null() || !maybe_array->IsWeakFixedArray())
10096 : ? Allocate(value->GetIsolate(), 1, Handle<WeakFixedArray>::null())
10097 11632247 : : Handle<WeakFixedArray>::cast(maybe_array);
10098 : // Try to store the new entry if there's room. Optimize for consecutive
10099 : // accesses.
10100 : int first_index = array->last_used_index();
10101 : int length = array->Length();
10102 11560961 : if (length > 0) {
10103 : for (int i = first_index;;) {
10104 54377260 : if (array->IsEmptySlot((i))) {
10105 11407519 : WeakFixedArray::Set(array, i, value);
10106 11407519 : if (assigned_index != nullptr) *assigned_index = i;
10107 11407519 : return array;
10108 : }
10109 42969741 : if (FLAG_trace_weak_arrays) {
10110 0 : PrintF("[WeakFixedArray: searching for free slot]\n");
10111 : }
10112 42969741 : i = (i + 1) % length;
10113 42969741 : if (i == first_index) break;
10114 : }
10115 : }
10116 :
10117 : // No usable slot found, grow the array.
10118 153442 : int new_length = length == 0 ? 1 : length + (length >> 1) + 4;
10119 : Handle<WeakFixedArray> new_array =
10120 153442 : Allocate(array->GetIsolate(), new_length, array);
10121 153442 : if (FLAG_trace_weak_arrays) {
10122 0 : PrintF("[WeakFixedArray: growing to size %d ]\n", new_length);
10123 : }
10124 153442 : WeakFixedArray::Set(new_array, length, value);
10125 153442 : if (assigned_index != nullptr) *assigned_index = length;
10126 153442 : return new_array;
10127 : }
10128 :
10129 :
10130 : template <class CompactionCallback>
10131 398 : void WeakFixedArray::Compact() {
10132 : FixedArray* array = FixedArray::cast(this);
10133 : int new_length = kFirstIndex;
10134 198084 : for (int i = kFirstIndex; i < array->length(); i++) {
10135 : Object* element = array->get(i);
10136 98644 : if (element->IsSmi()) continue;
10137 65881 : if (WeakCell::cast(element)->cleared()) continue;
10138 : Object* value = WeakCell::cast(element)->value();
10139 : CompactionCallback::Callback(value, i - kFirstIndex,
10140 171 : new_length - kFirstIndex);
10141 65639 : array->set(new_length++, element);
10142 : }
10143 398 : array->Shrink(new_length);
10144 : set_last_used_index(0);
10145 398 : }
10146 :
10147 :
10148 916247 : void WeakFixedArray::Iterator::Reset(Object* maybe_array) {
10149 916247 : if (maybe_array->IsWeakFixedArray()) {
10150 244196 : list_ = WeakFixedArray::cast(maybe_array);
10151 244196 : index_ = 0;
10152 : #ifdef DEBUG
10153 : last_used_index_ = list_->last_used_index();
10154 : #endif // DEBUG
10155 : }
10156 916247 : }
10157 :
10158 :
10159 0 : void JSObject::PrototypeRegistryCompactionCallback::Callback(Object* value,
10160 : int old_index,
10161 : int new_index) {
10162 : DCHECK(value->IsMap() && Map::cast(value)->is_prototype_map());
10163 : Map* map = Map::cast(value);
10164 : DCHECK(map->prototype_info()->IsPrototypeInfo());
10165 : PrototypeInfo* proto_info = PrototypeInfo::cast(map->prototype_info());
10166 : DCHECK_EQ(old_index, proto_info->registry_slot());
10167 : proto_info->set_registry_slot(new_index);
10168 0 : }
10169 :
10170 :
10171 : template void WeakFixedArray::Compact<WeakFixedArray::NullCallback>();
10172 : template void
10173 : WeakFixedArray::Compact<JSObject::PrototypeRegistryCompactionCallback>();
10174 :
10175 :
10176 5172755 : bool WeakFixedArray::Remove(Handle<HeapObject> value) {
10177 5172755 : if (Length() == 0) return false;
10178 : // Optimize for the most recently added element to be removed again.
10179 : int first_index = last_used_index();
10180 : for (int i = first_index;;) {
10181 11591232 : if (Get(i) == *value) {
10182 : Clear(i);
10183 : // Users of WeakFixedArray should make sure that there are no duplicates.
10184 5172755 : return true;
10185 : }
10186 1245722 : i = (i + 1) % Length();
10187 622861 : if (i == first_index) return false;
10188 : }
10189 : UNREACHABLE();
10190 : }
10191 :
10192 :
10193 : // static
10194 224732 : Handle<WeakFixedArray> WeakFixedArray::Allocate(
10195 : Isolate* isolate, int size, Handle<WeakFixedArray> initialize_from) {
10196 : DCHECK_LE(0, size);
10197 : Handle<FixedArray> result =
10198 224732 : isolate->factory()->NewUninitializedFixedArray(size + kFirstIndex);
10199 : int index = 0;
10200 224731 : if (!initialize_from.is_null()) {
10201 : DCHECK(initialize_from->Length() <= size);
10202 : Handle<FixedArray> raw_source = Handle<FixedArray>::cast(initialize_from);
10203 : // Copy the entries without compacting, since the PrototypeInfo relies on
10204 : // the index of the entries not to change.
10205 36725965 : while (index < raw_source->length()) {
10206 36572522 : result->set(index, raw_source->get(index));
10207 36572523 : index++;
10208 : }
10209 : }
10210 19167259 : while (index < result->length()) {
10211 : result->set(index, Smi::kZero);
10212 18942527 : index++;
10213 : }
10214 224732 : return Handle<WeakFixedArray>::cast(result);
10215 : }
10216 :
10217 : // static
10218 2199 : Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj,
10219 : AddMode mode) {
10220 2199 : int length = array->Length();
10221 2199 : array = EnsureSpace(array, length + 1);
10222 2199 : if (mode == kReloadLengthAfterAllocation) {
10223 : DCHECK(array->Length() <= length);
10224 0 : length = array->Length();
10225 : }
10226 : array->Set(length, *obj);
10227 : array->SetLength(length + 1);
10228 2199 : return array;
10229 : }
10230 :
10231 : // static
10232 391567 : Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj1,
10233 : Handle<Object> obj2, AddMode mode) {
10234 391567 : int length = array->Length();
10235 391567 : array = EnsureSpace(array, length + 2);
10236 391567 : if (mode == kReloadLengthAfterAllocation) {
10237 34675 : length = array->Length();
10238 : }
10239 : array->Set(length, *obj1);
10240 : array->Set(length + 1, *obj2);
10241 : array->SetLength(length + 2);
10242 391567 : return array;
10243 : }
10244 :
10245 : // static
10246 419 : Handle<ArrayList> ArrayList::New(Isolate* isolate, int size) {
10247 : Handle<ArrayList> result = Handle<ArrayList>::cast(
10248 419 : isolate->factory()->NewFixedArray(size + kFirstIndex));
10249 : result->SetLength(0);
10250 419 : return result;
10251 : }
10252 :
10253 0 : Handle<FixedArray> ArrayList::Elements(Handle<ArrayList> array) {
10254 0 : int length = array->Length();
10255 : Handle<FixedArray> result =
10256 0 : array->GetIsolate()->factory()->NewFixedArray(length);
10257 : // Do not copy the first entry, i.e., the length.
10258 0 : array->CopyTo(kFirstIndex, *result, 0, length);
10259 0 : return result;
10260 : }
10261 :
10262 34675 : bool ArrayList::IsFull() {
10263 : int capacity = length();
10264 34675 : return kFirstIndex + Length() == capacity;
10265 : }
10266 :
10267 : namespace {
10268 :
10269 5116809 : Handle<FixedArray> EnsureSpaceInFixedArray(Handle<FixedArray> array,
10270 : int length) {
10271 : int capacity = array->length();
10272 5116809 : if (capacity < length) {
10273 : Isolate* isolate = array->GetIsolate();
10274 : int new_capacity = length;
10275 66374 : new_capacity = new_capacity + Max(new_capacity / 2, 2);
10276 33187 : int grow_by = new_capacity - capacity;
10277 33187 : array = isolate->factory()->CopyFixedArrayAndGrow(array, grow_by);
10278 : }
10279 5116809 : return array;
10280 : }
10281 :
10282 : } // namespace
10283 :
10284 : // static
10285 393766 : Handle<ArrayList> ArrayList::EnsureSpace(Handle<ArrayList> array, int length) {
10286 : const bool empty = (array->length() == 0);
10287 : auto ret = Handle<ArrayList>::cast(
10288 787532 : EnsureSpaceInFixedArray(array, kFirstIndex + length));
10289 393766 : if (empty) ret->SetLength(0);
10290 393766 : return ret;
10291 : }
10292 :
10293 309058 : Handle<RegExpMatchInfo> RegExpMatchInfo::ReserveCaptures(
10294 : Handle<RegExpMatchInfo> match_info, int capture_count) {
10295 : DCHECK_GE(match_info->length(), kLastMatchOverhead);
10296 309058 : const int required_length = kFirstCaptureIndex + capture_count;
10297 : Handle<FixedArray> result =
10298 309058 : EnsureSpaceInFixedArray(match_info, required_length);
10299 309058 : return Handle<RegExpMatchInfo>::cast(result);
10300 : }
10301 :
10302 : // static
10303 4368901 : Handle<FrameArray> FrameArray::AppendJSFrame(Handle<FrameArray> in,
10304 : Handle<Object> receiver,
10305 : Handle<JSFunction> function,
10306 : Handle<AbstractCode> code,
10307 : int offset, int flags) {
10308 : const int frame_count = in->FrameCount();
10309 4368901 : const int new_length = LengthFor(frame_count + 1);
10310 : Handle<FrameArray> array = EnsureSpace(in, new_length);
10311 : array->SetReceiver(frame_count, *receiver);
10312 : array->SetFunction(frame_count, *function);
10313 : array->SetCode(frame_count, *code);
10314 : array->SetOffset(frame_count, Smi::FromInt(offset));
10315 4368901 : array->SetFlags(frame_count, Smi::FromInt(flags));
10316 : array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));
10317 4368901 : return array;
10318 : }
10319 :
10320 : // static
10321 45084 : Handle<FrameArray> FrameArray::AppendWasmFrame(
10322 : Handle<FrameArray> in, Handle<WasmInstanceObject> wasm_instance,
10323 : int wasm_function_index, Handle<AbstractCode> code, int offset, int flags) {
10324 : const int frame_count = in->FrameCount();
10325 45084 : const int new_length = LengthFor(frame_count + 1);
10326 : Handle<FrameArray> array = EnsureSpace(in, new_length);
10327 : array->SetWasmInstance(frame_count, *wasm_instance);
10328 : array->SetWasmFunctionIndex(frame_count, Smi::FromInt(wasm_function_index));
10329 : // code will be a null handle for interpreted wasm frames.
10330 45084 : if (!code.is_null()) array->SetCode(frame_count, *code);
10331 : array->SetOffset(frame_count, Smi::FromInt(offset));
10332 45084 : array->SetFlags(frame_count, Smi::FromInt(flags));
10333 : array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));
10334 45084 : return array;
10335 : }
10336 :
10337 2119966 : void FrameArray::ShrinkToFit() { Shrink(LengthFor(FrameCount())); }
10338 :
10339 : // static
10340 0 : Handle<FrameArray> FrameArray::EnsureSpace(Handle<FrameArray> array,
10341 : int length) {
10342 4413985 : return Handle<FrameArray>::cast(EnsureSpaceInFixedArray(array, length));
10343 : }
10344 :
10345 16932923 : Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate,
10346 : int number_of_descriptors,
10347 : int slack,
10348 : PretenureFlag pretenure) {
10349 : DCHECK_LE(0, number_of_descriptors);
10350 : Factory* factory = isolate->factory();
10351 : // Do not use DescriptorArray::cast on incomplete object.
10352 16932923 : int size = number_of_descriptors + slack;
10353 16932923 : if (size == 0) return factory->empty_descriptor_array();
10354 : // Allocate the array of keys.
10355 : Handle<FixedArray> result =
10356 16932923 : factory->NewFixedArray(LengthFor(size), pretenure);
10357 :
10358 : result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors));
10359 33865842 : result->set(kEnumCacheIndex, isolate->heap()->empty_enum_cache());
10360 : return Handle<DescriptorArray>::cast(result);
10361 : }
10362 :
10363 90 : void DescriptorArray::ClearEnumCache() {
10364 90 : set(kEnumCacheIndex, GetHeap()->empty_enum_cache());
10365 90 : }
10366 :
10367 329604 : void DescriptorArray::Replace(int index, Descriptor* descriptor) {
10368 : descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index));
10369 329604 : Set(index, descriptor);
10370 329604 : }
10371 :
10372 : // static
10373 189119 : void DescriptorArray::SetEnumCache(Handle<DescriptorArray> descriptors,
10374 : Isolate* isolate, Handle<FixedArray> keys,
10375 : Handle<FixedArray> indices) {
10376 : EnumCache* enum_cache = descriptors->GetEnumCache();
10377 189119 : if (enum_cache == isolate->heap()->empty_enum_cache()) {
10378 365540 : enum_cache = *isolate->factory()->NewEnumCache(keys, indices);
10379 182770 : descriptors->set(kEnumCacheIndex, enum_cache);
10380 : } else {
10381 6349 : enum_cache->set_keys(*keys);
10382 6349 : enum_cache->set_indices(*indices);
10383 : }
10384 189119 : }
10385 :
10386 104562670 : void DescriptorArray::CopyFrom(int index, DescriptorArray* src) {
10387 104562670 : PropertyDetails details = src->GetDetails(index);
10388 104562674 : Set(index, src->GetKey(index), src->GetValue(index), details);
10389 104562670 : }
10390 :
10391 13234543 : void DescriptorArray::Sort() {
10392 : // In-place heap sort.
10393 : int len = number_of_descriptors();
10394 : // Reset sorting since the descriptor array might contain invalid pointers.
10395 13234543 : for (int i = 0; i < len; ++i) SetSortedKey(i, i);
10396 : // Bottom-up max-heap construction.
10397 : // Index of the last node with children
10398 13234545 : const int max_parent_index = (len / 2) - 1;
10399 53043814 : for (int i = max_parent_index; i >= 0; --i) {
10400 : int parent_index = i;
10401 39809271 : const uint32_t parent_hash = GetSortedKey(i)->Hash();
10402 117652352 : while (parent_index <= max_parent_index) {
10403 57774525 : int child_index = 2 * parent_index + 1;
10404 57774525 : uint32_t child_hash = GetSortedKey(child_index)->Hash();
10405 57774518 : if (child_index + 1 < len) {
10406 46521631 : uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
10407 46521640 : if (right_child_hash > child_hash) {
10408 : child_index++;
10409 : child_hash = right_child_hash;
10410 : }
10411 : }
10412 57774527 : if (child_hash <= parent_hash) break;
10413 38033815 : SwapSortedKeys(parent_index, child_index);
10414 : // Now element at child_index could be < its children.
10415 : parent_index = child_index; // parent_hash remains correct.
10416 : }
10417 : }
10418 :
10419 : // Extract elements and create sorted array.
10420 85134509 : for (int i = len - 1; i > 0; --i) {
10421 : // Put max element at the back of the array.
10422 71899972 : SwapSortedKeys(0, i);
10423 : // Shift down the new top element.
10424 : int parent_index = 0;
10425 71899981 : const uint32_t parent_hash = GetSortedKey(parent_index)->Hash();
10426 71899973 : const int max_parent_index = (i / 2) - 1;
10427 260037727 : while (parent_index <= max_parent_index) {
10428 127164883 : int child_index = parent_index * 2 + 1;
10429 127164883 : uint32_t child_hash = GetSortedKey(child_index)->Hash();
10430 127164806 : if (child_index + 1 < i) {
10431 108706567 : uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
10432 108706570 : if (right_child_hash > child_hash) {
10433 : child_index++;
10434 : child_hash = right_child_hash;
10435 : }
10436 : }
10437 127164809 : if (child_hash <= parent_hash) break;
10438 116237714 : SwapSortedKeys(parent_index, child_index);
10439 : parent_index = child_index;
10440 : }
10441 : }
10442 : DCHECK(IsSortedNoDuplicates());
10443 13234537 : }
10444 :
10445 :
10446 11311 : Handle<AccessorPair> AccessorPair::Copy(Handle<AccessorPair> pair) {
10447 11311 : Handle<AccessorPair> copy = pair->GetIsolate()->factory()->NewAccessorPair();
10448 11311 : copy->set_getter(pair->getter());
10449 11311 : copy->set_setter(pair->setter());
10450 11311 : return copy;
10451 : }
10452 :
10453 27992 : Handle<Object> AccessorPair::GetComponent(Handle<AccessorPair> accessor_pair,
10454 : AccessorComponent component) {
10455 : Object* accessor = accessor_pair->get(component);
10456 27992 : if (accessor->IsFunctionTemplateInfo()) {
10457 : return ApiNatives::InstantiateFunction(
10458 79 : handle(FunctionTemplateInfo::cast(accessor)))
10459 158 : .ToHandleChecked();
10460 : }
10461 : Isolate* isolate = accessor_pair->GetIsolate();
10462 27913 : if (accessor->IsNull(isolate)) {
10463 3909 : return isolate->factory()->undefined_value();
10464 : }
10465 : return handle(accessor, isolate);
10466 : }
10467 :
10468 442526 : Handle<DeoptimizationData> DeoptimizationData::New(Isolate* isolate,
10469 : int deopt_entry_count,
10470 : PretenureFlag pretenure) {
10471 : return Handle<DeoptimizationData>::cast(isolate->factory()->NewFixedArray(
10472 442526 : LengthFor(deopt_entry_count), pretenure));
10473 : }
10474 :
10475 1226823 : Handle<DeoptimizationData> DeoptimizationData::Empty(Isolate* isolate) {
10476 : return Handle<DeoptimizationData>::cast(
10477 1226823 : isolate->factory()->empty_fixed_array());
10478 : }
10479 :
10480 36 : SharedFunctionInfo* DeoptimizationData::GetInlinedFunction(int index) {
10481 36 : if (index == -1) {
10482 0 : return SharedFunctionInfo::cast(SharedFunctionInfo());
10483 : } else {
10484 36 : return SharedFunctionInfo::cast(LiteralArray()->get(index));
10485 : }
10486 : }
10487 :
10488 22097306 : int HandlerTable::LookupRange(int pc_offset, int* data_out,
10489 : CatchPrediction* prediction_out) {
10490 : int innermost_handler = -1;
10491 : #ifdef DEBUG
10492 : // Assuming that ranges are well nested, we don't need to track the innermost
10493 : // offsets. This is just to verify that the table is actually well nested.
10494 : int innermost_start = std::numeric_limits<int>::min();
10495 : int innermost_end = std::numeric_limits<int>::max();
10496 : #endif
10497 64283428 : for (int i = 0; i < length(); i += kRangeEntrySize) {
10498 : int start_offset = Smi::ToInt(get(i + kRangeStartIndex));
10499 10044408 : int end_offset = Smi::ToInt(get(i + kRangeEndIndex));
10500 10044408 : int handler_field = Smi::ToInt(get(i + kRangeHandlerIndex));
10501 10044408 : int handler_offset = HandlerOffsetField::decode(handler_field);
10502 : CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
10503 10044408 : int handler_data = Smi::ToInt(get(i + kRangeDataIndex));
10504 10044408 : if (pc_offset >= start_offset && pc_offset < end_offset) {
10505 : DCHECK_GE(start_offset, innermost_start);
10506 : DCHECK_LT(end_offset, innermost_end);
10507 : innermost_handler = handler_offset;
10508 : #ifdef DEBUG
10509 : innermost_start = start_offset;
10510 : innermost_end = end_offset;
10511 : #endif
10512 1601161 : if (data_out) *data_out = handler_data;
10513 1601161 : if (prediction_out) *prediction_out = prediction;
10514 : }
10515 : }
10516 22097306 : return innermost_handler;
10517 : }
10518 :
10519 :
10520 : // TODO(turbofan): Make sure table is sorted and use binary search.
10521 2906054 : int HandlerTable::LookupReturn(int pc_offset) {
10522 6870130 : for (int i = 0; i < length(); i += kReturnEntrySize) {
10523 : int return_offset = Smi::ToInt(get(i + kReturnOffsetIndex));
10524 761777 : int handler_field = Smi::ToInt(get(i + kReturnHandlerIndex));
10525 761777 : if (pc_offset == return_offset) {
10526 465532 : return HandlerOffsetField::decode(handler_field);
10527 : }
10528 : }
10529 : return -1;
10530 : }
10531 :
10532 1669287 : Handle<HandlerTable> HandlerTable::Empty(Isolate* isolate) {
10533 1669287 : return Handle<HandlerTable>::cast(isolate->factory()->empty_fixed_array());
10534 : }
10535 :
10536 : #ifdef DEBUG
10537 : bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
10538 : if (length() != other->length()) return false;
10539 : for (int i = 0; i < length(); ++i) {
10540 : if (get(i) != other->get(i)) return false;
10541 : }
10542 : return true;
10543 : }
10544 : #endif
10545 :
10546 : // static
10547 36 : Handle<String> String::Trim(Handle<String> string, TrimMode mode) {
10548 36 : Isolate* const isolate = string->GetIsolate();
10549 36 : string = String::Flatten(string);
10550 : int const length = string->length();
10551 :
10552 : // Perform left trimming if requested.
10553 : int left = 0;
10554 : UnicodeCache* unicode_cache = isolate->unicode_cache();
10555 36 : if (mode == kTrim || mode == kTrimLeft) {
10556 1206 : while (left < length &&
10557 603 : unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) {
10558 567 : left++;
10559 : }
10560 : }
10561 :
10562 : // Perform right trimming if requested.
10563 : int right = length;
10564 36 : if (mode == kTrim || mode == kTrimRight) {
10565 36 : while (
10566 72 : right > left &&
10567 72 : unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) {
10568 0 : right--;
10569 : }
10570 : }
10571 :
10572 36 : return isolate->factory()->NewSubString(string, left, right);
10573 : }
10574 :
10575 2728329 : bool String::LooksValid() { return GetIsolate()->heap()->Contains(this); }
10576 :
10577 : // static
10578 291767 : MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) {
10579 291767 : if (name->IsString()) return Handle<String>::cast(name);
10580 : // ES6 section 9.2.11 SetFunctionName, step 4.
10581 : Isolate* const isolate = name->GetIsolate();
10582 : Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate);
10583 9959 : if (description->IsUndefined(isolate)) {
10584 81 : return isolate->factory()->empty_string();
10585 : }
10586 9878 : IncrementalStringBuilder builder(isolate);
10587 : builder.AppendCharacter('[');
10588 9878 : builder.AppendString(Handle<String>::cast(description));
10589 : builder.AppendCharacter(']');
10590 9878 : return builder.Finish();
10591 : }
10592 :
10593 : // static
10594 87483 : MaybeHandle<String> Name::ToFunctionName(Handle<Name> name,
10595 : Handle<String> prefix) {
10596 : Handle<String> name_string;
10597 : Isolate* const isolate = name->GetIsolate();
10598 174966 : ASSIGN_RETURN_ON_EXCEPTION(isolate, name_string, ToFunctionName(name),
10599 : String);
10600 87483 : IncrementalStringBuilder builder(isolate);
10601 87483 : builder.AppendString(prefix);
10602 : builder.AppendCharacter(' ');
10603 87483 : builder.AppendString(name_string);
10604 87483 : return builder.Finish();
10605 : }
10606 :
10607 : namespace {
10608 :
10609 : bool AreDigits(const uint8_t* s, int from, int to) {
10610 30918 : for (int i = from; i < to; i++) {
10611 50936 : if (s[i] < '0' || s[i] > '9') return false;
10612 : }
10613 :
10614 : return true;
10615 : }
10616 :
10617 :
10618 : int ParseDecimalInteger(const uint8_t* s, int from, int to) {
10619 : DCHECK_LT(to - from, 10); // Overflow is not possible.
10620 : DCHECK(from < to);
10621 1659 : int d = s[from] - '0';
10622 :
10623 2043 : for (int i = from + 1; i < to; i++) {
10624 384 : d = 10 * d + (s[i] - '0');
10625 : }
10626 :
10627 : return d;
10628 : }
10629 :
10630 : } // namespace
10631 :
10632 : // static
10633 4539635 : Handle<Object> String::ToNumber(Handle<String> subject) {
10634 1821993 : Isolate* const isolate = subject->GetIsolate();
10635 :
10636 : // Flatten {subject} string first.
10637 4539635 : subject = String::Flatten(subject);
10638 :
10639 : // Fast array index case.
10640 : uint32_t index;
10641 4539635 : if (subject->AsArrayIndex(&index)) {
10642 46689 : return isolate->factory()->NewNumberFromUint(index);
10643 : }
10644 :
10645 : // Fast case: short integer or some sorts of junk values.
10646 4492946 : if (subject->IsSeqOneByteString()) {
10647 : int len = subject->length();
10648 2826581 : if (len == 0) return handle(Smi::kZero, isolate);
10649 :
10650 : DisallowHeapAllocation no_gc;
10651 2782575 : uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars();
10652 2782575 : bool minus = (data[0] == '-');
10653 2782575 : int start_pos = (minus ? 1 : 0);
10654 :
10655 2782575 : if (start_pos == len) {
10656 0 : return isolate->factory()->nan_value();
10657 2782575 : } else if (data[start_pos] > '9') {
10658 : // Fast check for a junk value. A valid string may start from a
10659 : // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit
10660 : // or the 'I' character ('Infinity'). All of that have codes not greater
10661 : // than '9' except 'I' and .
10662 2652969 : if (data[start_pos] != 'I' && data[start_pos] != 0xa0) {
10663 2647291 : return isolate->factory()->nan_value();
10664 : }
10665 151283 : } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
10666 : // The maximal/minimal smi has 10 digits. If the string has less digits
10667 : // we know it will fit into the smi-data type.
10668 : int d = ParseDecimalInteger(data, start_pos, len);
10669 1659 : if (minus) {
10670 1864 : if (d == 0) return isolate->factory()->minus_zero_value();
10671 1334 : d = -d;
10672 120 : } else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize &&
10673 0 : (len == 1 || data[0] != '0')) {
10674 : // String hash is not calculated yet but all the data are present.
10675 : // Update the hash field to speed up sequential convertions.
10676 0 : uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
10677 : #ifdef DEBUG
10678 : subject->Hash(); // Force hash calculation.
10679 : DCHECK_EQ(static_cast<int>(subject->hash_field()),
10680 : static_cast<int>(hash));
10681 : #endif
10682 : subject->set_hash_field(hash);
10683 : }
10684 1394 : return handle(Smi::FromInt(d), isolate);
10685 : }
10686 : }
10687 :
10688 : // Slower case.
10689 : int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY;
10690 : return isolate->factory()->NewNumber(
10691 1821993 : StringToDouble(isolate->unicode_cache(), subject, flags));
10692 : }
10693 :
10694 :
10695 114207095 : String::FlatContent String::GetFlatContent() {
10696 : DCHECK(!AllowHeapAllocation::IsAllowed());
10697 : int length = this->length();
10698 : StringShape shape(this);
10699 : String* string = this;
10700 : int offset = 0;
10701 114207095 : if (shape.representation_tag() == kConsStringTag) {
10702 : ConsString* cons = ConsString::cast(string);
10703 0 : if (cons->second()->length() != 0) {
10704 0 : return FlatContent();
10705 : }
10706 : string = cons->first();
10707 : shape = StringShape(string);
10708 114207095 : } else if (shape.representation_tag() == kSlicedStringTag) {
10709 : SlicedString* slice = SlicedString::cast(string);
10710 : offset = slice->offset();
10711 : string = slice->parent();
10712 : shape = StringShape(string);
10713 : DCHECK(shape.representation_tag() != kConsStringTag &&
10714 : shape.representation_tag() != kSlicedStringTag);
10715 : }
10716 114207095 : if (shape.representation_tag() == kThinStringTag) {
10717 : ThinString* thin = ThinString::cast(string);
10718 : string = thin->actual();
10719 : shape = StringShape(string);
10720 : DCHECK(!shape.IsCons());
10721 : DCHECK(!shape.IsSliced());
10722 : }
10723 114207095 : if (shape.encoding_tag() == kOneByteStringTag) {
10724 : const uint8_t* start;
10725 106165841 : if (shape.representation_tag() == kSeqStringTag) {
10726 106163830 : start = SeqOneByteString::cast(string)->GetChars();
10727 : } else {
10728 : start = ExternalOneByteString::cast(string)->GetChars();
10729 : }
10730 106165845 : return FlatContent(start + offset, length);
10731 : } else {
10732 : DCHECK_EQ(shape.encoding_tag(), kTwoByteStringTag);
10733 : const uc16* start;
10734 8041254 : if (shape.representation_tag() == kSeqStringTag) {
10735 8039606 : start = SeqTwoByteString::cast(string)->GetChars();
10736 : } else {
10737 : start = ExternalTwoByteString::cast(string)->GetChars();
10738 : }
10739 8041254 : return FlatContent(start + offset, length);
10740 : }
10741 : }
10742 :
10743 3194585 : std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
10744 : RobustnessFlag robust_flag,
10745 : int offset, int length,
10746 : int* length_return) {
10747 5922850 : if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
10748 : return std::unique_ptr<char[]>();
10749 : }
10750 : // Negative length means the to the end of the string.
10751 3194585 : if (length < 0) length = kMaxInt - offset;
10752 :
10753 : // Compute the size of the UTF-8 string. Start at the specified offset.
10754 : StringCharacterStream stream(this, offset);
10755 : int character_position = offset;
10756 : int utf8_bytes = 0;
10757 : int last = unibrow::Utf16::kNoPreviousCharacter;
10758 33720284 : while (stream.HasMore() && character_position++ < offset + length) {
10759 27331116 : uint16_t character = stream.GetNext();
10760 27331116 : utf8_bytes += unibrow::Utf8::Length(character, last);
10761 27331116 : last = character;
10762 : }
10763 :
10764 3194584 : if (length_return) {
10765 2685533 : *length_return = utf8_bytes;
10766 : }
10767 :
10768 3194584 : char* result = NewArray<char>(utf8_bytes + 1);
10769 :
10770 : // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
10771 3194585 : stream.Reset(this, offset);
10772 : character_position = offset;
10773 : int utf8_byte_position = 0;
10774 : last = unibrow::Utf16::kNoPreviousCharacter;
10775 33720284 : while (stream.HasMore() && character_position++ < offset + length) {
10776 27331116 : uint16_t character = stream.GetNext();
10777 27331116 : if (allow_nulls == DISALLOW_NULLS && character == 0) {
10778 : character = ' ';
10779 : }
10780 : utf8_byte_position +=
10781 27331116 : unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
10782 27331114 : last = character;
10783 : }
10784 3194585 : result[utf8_byte_position] = 0;
10785 : return std::unique_ptr<char[]>(result);
10786 : }
10787 :
10788 509052 : std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
10789 : RobustnessFlag robust_flag,
10790 : int* length_return) {
10791 509052 : return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
10792 : }
10793 :
10794 :
10795 62 : const uc16* String::GetTwoByteData(unsigned start) {
10796 : DCHECK(!IsOneByteRepresentationUnderneath());
10797 62 : switch (StringShape(this).representation_tag()) {
10798 : case kSeqStringTag:
10799 0 : return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
10800 : case kExternalStringTag:
10801 : return ExternalTwoByteString::cast(this)->
10802 62 : ExternalTwoByteStringGetData(start);
10803 : case kSlicedStringTag: {
10804 : SlicedString* slice = SlicedString::cast(this);
10805 0 : return slice->parent()->GetTwoByteData(start + slice->offset());
10806 : }
10807 : case kConsStringTag:
10808 : case kThinStringTag:
10809 0 : UNREACHABLE();
10810 : }
10811 0 : UNREACHABLE();
10812 : }
10813 :
10814 :
10815 0 : const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
10816 : return reinterpret_cast<uc16*>(
10817 0 : reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
10818 : }
10819 :
10820 :
10821 86451 : void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) {
10822 : Relocatable* current = isolate->relocatable_top();
10823 194561 : while (current != nullptr) {
10824 21659 : current->PostGarbageCollection();
10825 21659 : current = current->prev_;
10826 : }
10827 86451 : }
10828 :
10829 :
10830 : // Reserve space for statics needing saving and restoring.
10831 1118 : int Relocatable::ArchiveSpacePerThread() {
10832 1118 : return sizeof(Relocatable*); // NOLINT
10833 : }
10834 :
10835 :
10836 : // Archive statics that are thread-local.
10837 24163 : char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
10838 24163 : *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
10839 : isolate->set_relocatable_top(nullptr);
10840 24163 : return to + ArchiveSpacePerThread();
10841 : }
10842 :
10843 :
10844 : // Restore statics that are thread-local.
10845 24163 : char* Relocatable::RestoreState(Isolate* isolate, char* from) {
10846 24163 : isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
10847 24163 : return from + ArchiveSpacePerThread();
10848 : }
10849 :
10850 5994 : char* Relocatable::Iterate(RootVisitor* v, char* thread_storage) {
10851 5994 : Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
10852 : Iterate(v, top);
10853 5994 : return thread_storage + ArchiveSpacePerThread();
10854 : }
10855 :
10856 232423 : void Relocatable::Iterate(Isolate* isolate, RootVisitor* v) {
10857 : Iterate(v, isolate->relocatable_top());
10858 232423 : }
10859 :
10860 0 : void Relocatable::Iterate(RootVisitor* v, Relocatable* top) {
10861 : Relocatable* current = top;
10862 286736 : while (current != nullptr) {
10863 48319 : current->IterateInstance(v);
10864 48319 : current = current->prev_;
10865 : }
10866 0 : }
10867 :
10868 :
10869 1524155 : FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
10870 : : Relocatable(isolate),
10871 : str_(str.location()),
10872 4572465 : length_(str->length()) {
10873 1524155 : PostGarbageCollection();
10874 1524155 : }
10875 :
10876 :
10877 3072 : FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
10878 : : Relocatable(isolate),
10879 : str_(0),
10880 : is_one_byte_(true),
10881 3072 : length_(input.length()),
10882 9216 : start_(input.start()) {}
10883 :
10884 :
10885 1524585 : void FlatStringReader::PostGarbageCollection() {
10886 1524585 : if (str_ == nullptr) return;
10887 : Handle<String> str(str_);
10888 : DCHECK(str->IsFlat());
10889 : DisallowHeapAllocation no_gc;
10890 : // This does not actually prevent the vector from being relocated later.
10891 1524585 : String::FlatContent content = str->GetFlatContent();
10892 : DCHECK(content.IsFlat());
10893 3049170 : is_one_byte_ = content.IsOneByte();
10894 1524585 : if (is_one_byte_) {
10895 1385341 : start_ = content.ToOneByteVector().start();
10896 : } else {
10897 139244 : start_ = content.ToUC16Vector().start();
10898 : }
10899 : }
10900 :
10901 :
10902 47184 : void ConsStringIterator::Initialize(ConsString* cons_string, int offset) {
10903 : DCHECK_NOT_NULL(cons_string);
10904 3660153 : root_ = cons_string;
10905 3660153 : consumed_ = offset;
10906 : // Force stack blown condition to trigger restart.
10907 3660153 : depth_ = 1;
10908 3660153 : maximum_depth_ = kStackSize + depth_;
10909 : DCHECK(StackBlown());
10910 47184 : }
10911 :
10912 :
10913 43511997 : String* ConsStringIterator::Continue(int* offset_out) {
10914 : DCHECK_NE(depth_, 0);
10915 : DCHECK_EQ(0, *offset_out);
10916 43511997 : bool blew_stack = StackBlown();
10917 : String* string = nullptr;
10918 : // Get the next leaf if there is one.
10919 43511997 : if (!blew_stack) string = NextLeaf(&blew_stack);
10920 : // Restart search from root.
10921 43511997 : if (blew_stack) {
10922 : DCHECK_NULL(string);
10923 4053378 : string = Search(offset_out);
10924 : }
10925 : // Ensure future calls return null immediately.
10926 43511997 : if (string == nullptr) Reset(nullptr);
10927 43511997 : return string;
10928 : }
10929 :
10930 :
10931 8106611 : String* ConsStringIterator::Search(int* offset_out) {
10932 4053378 : ConsString* cons_string = root_;
10933 : // Reset the stack, pushing the root string.
10934 4053378 : depth_ = 1;
10935 4053378 : maximum_depth_ = 1;
10936 4053378 : frames_[0] = cons_string;
10937 4053378 : const int consumed = consumed_;
10938 : int offset = 0;
10939 : while (true) {
10940 : // Loop until the string is found which contains the target offset.
10941 : String* string = cons_string->first();
10942 : int length = string->length();
10943 : int32_t type;
10944 9838866271 : if (consumed < offset + length) {
10945 : // Target offset is in the left branch.
10946 : // Keep going if we're still in a ConString.
10947 : type = string->map()->instance_type();
10948 9837169956 : if ((type & kStringRepresentationMask) == kConsStringTag) {
10949 : cons_string = ConsString::cast(string);
10950 : PushLeft(cons_string);
10951 : continue;
10952 : }
10953 : // Tell the stack we're done descending.
10954 : AdjustMaximumDepth();
10955 : } else {
10956 : // Descend right.
10957 : // Update progress through the string.
10958 : offset += length;
10959 : // Keep going if we're still in a ConString.
10960 : string = cons_string->second();
10961 : type = string->map()->instance_type();
10962 1696315 : if ((type & kStringRepresentationMask) == kConsStringTag) {
10963 : cons_string = ConsString::cast(string);
10964 : PushRight(cons_string);
10965 : continue;
10966 : }
10967 : // Need this to be updated for the current string.
10968 : length = string->length();
10969 : // Account for the possibility of an empty right leaf.
10970 : // This happens only if we have asked for an offset outside the string.
10971 398240 : if (length == 0) {
10972 : // Reset so future operations will return null immediately.
10973 : Reset(nullptr);
10974 145 : return nullptr;
10975 : }
10976 : // Tell the stack we're done descending.
10977 : AdjustMaximumDepth();
10978 : // Pop stack so next iteration is in correct place.
10979 : Pop();
10980 : }
10981 : DCHECK_NE(length, 0);
10982 : // Adjust return values and exit.
10983 4053233 : consumed_ = offset + length;
10984 4053233 : *offset_out = consumed - offset;
10985 4053233 : return string;
10986 : }
10987 : UNREACHABLE();
10988 : }
10989 :
10990 :
10991 88559491 : String* ConsStringIterator::NextLeaf(bool* blew_stack) {
10992 : while (true) {
10993 : // Tree traversal complete.
10994 39922496 : if (depth_ == 0) {
10995 6787 : *blew_stack = false;
10996 6787 : return nullptr;
10997 : }
10998 : // We've lost track of higher nodes.
10999 39915709 : if (StackBlown()) {
11000 695 : *blew_stack = true;
11001 695 : return nullptr;
11002 : }
11003 : // Go right.
11004 79830028 : ConsString* cons_string = frames_[OffsetForDepth(depth_ - 1)];
11005 : String* string = cons_string->second();
11006 : int32_t type = string->map()->instance_type();
11007 39915014 : if ((type & kStringRepresentationMask) != kConsStringTag) {
11008 : // Pop stack so next iteration is in correct place.
11009 : Pop();
11010 : int length = string->length();
11011 : // Could be a flattened ConsString.
11012 30730546 : if (length == 0) continue;
11013 30267364 : consumed_ += length;
11014 30267364 : return string;
11015 : }
11016 : cons_string = ConsString::cast(string);
11017 : PushRight(cons_string);
11018 : // Need to traverse all the way left.
11019 : while (true) {
11020 : // Continue left.
11021 : string = cons_string->first();
11022 : type = string->map()->instance_type();
11023 15414030 : if ((type & kStringRepresentationMask) != kConsStringTag) {
11024 : AdjustMaximumDepth();
11025 : int length = string->length();
11026 9184468 : if (length == 0) break; // Skip empty left-hand sides of ConsStrings.
11027 9184468 : consumed_ += length;
11028 9184468 : return string;
11029 : }
11030 : cons_string = ConsString::cast(string);
11031 : PushLeft(cons_string);
11032 : }
11033 : }
11034 : UNREACHABLE();
11035 : }
11036 :
11037 :
11038 2576397 : uint16_t ConsString::ConsStringGet(int index) {
11039 : DCHECK(index >= 0 && index < this->length());
11040 :
11041 : // Check for a flattened cons string
11042 2576397 : if (second()->length() == 0) {
11043 : String* left = first();
11044 300474 : return left->Get(index);
11045 : }
11046 :
11047 : String* string = String::cast(this);
11048 :
11049 : while (true) {
11050 22223504 : if (StringShape(string).IsCons()) {
11051 : ConsString* cons_string = ConsString::cast(string);
11052 : String* left = cons_string->first();
11053 19947581 : if (left->length() > index) {
11054 : string = left;
11055 : } else {
11056 407486 : index -= left->length();
11057 : string = cons_string->second();
11058 : }
11059 : } else {
11060 2275923 : return string->Get(index);
11061 : }
11062 : }
11063 :
11064 : UNREACHABLE();
11065 : }
11066 :
11067 4316 : uint16_t ThinString::ThinStringGet(int index) { return actual()->Get(index); }
11068 :
11069 1237991 : uint16_t SlicedString::SlicedStringGet(int index) {
11070 2475982 : return parent()->Get(offset() + index);
11071 : }
11072 :
11073 :
11074 : template <typename sinkchar>
11075 223877430 : void String::WriteToFlat(String* src,
11076 : sinkchar* sink,
11077 : int f,
11078 : int t) {
11079 : String* source = src;
11080 : int from = f;
11081 : int to = t;
11082 : while (true) {
11083 : DCHECK(0 <= from && from <= to && to <= source->length());
11084 296605740 : switch (StringShape(source).full_representation_tag()) {
11085 : case kOneByteStringTag | kExternalStringTag: {
11086 : CopyChars(sink, ExternalOneByteString::cast(source)->GetChars() + from,
11087 810978 : to - from);
11088 : return;
11089 : }
11090 : case kTwoByteStringTag | kExternalStringTag: {
11091 : const uc16* data =
11092 : ExternalTwoByteString::cast(source)->GetChars();
11093 : CopyChars(sink,
11094 : data + from,
11095 283084 : to - from);
11096 : return;
11097 : }
11098 : case kOneByteStringTag | kSeqStringTag: {
11099 : CopyChars(sink,
11100 172714349 : SeqOneByteString::cast(source)->GetChars() + from,
11101 345428698 : to - from);
11102 : return;
11103 : }
11104 : case kTwoByteStringTag | kSeqStringTag: {
11105 : CopyChars(sink,
11106 7901734 : SeqTwoByteString::cast(source)->GetChars() + from,
11107 15803468 : to - from);
11108 : return;
11109 : }
11110 : case kOneByteStringTag | kConsStringTag:
11111 : case kTwoByteStringTag | kConsStringTag: {
11112 : ConsString* cons_string = ConsString::cast(source);
11113 : String* first = cons_string->first();
11114 : int boundary = first->length();
11115 113696206 : if (to - boundary >= boundary - from) {
11116 : // Right hand side is longer. Recurse over left.
11117 49990012 : if (from < boundary) {
11118 49990012 : WriteToFlat(first, sink, from, boundary);
11119 99980024 : if (from == 0 && cons_string->second() == first) {
11120 41003981 : CopyChars(sink + boundary, sink, boundary);
11121 : return;
11122 : }
11123 8986031 : sink += boundary - from;
11124 : from = 0;
11125 : } else {
11126 0 : from -= boundary;
11127 : }
11128 : to -= boundary;
11129 : source = cons_string->second();
11130 : } else {
11131 : // Left hand side is longer. Recurse over right.
11132 63706194 : if (to > boundary) {
11133 : String* second = cons_string->second();
11134 : // When repeatedly appending to a string, we get a cons string that
11135 : // is unbalanced to the left, a list, essentially. We inline the
11136 : // common case of sequential one-byte right child.
11137 63443212 : if (to - boundary == 1) {
11138 49233914 : sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
11139 38826255 : } else if (second->IsSeqOneByteString()) {
11140 26980495 : CopyChars(sink + boundary - from,
11141 26980495 : SeqOneByteString::cast(second)->GetChars(),
11142 53960990 : to - boundary);
11143 : } else {
11144 11845760 : WriteToFlat(second,
11145 11845760 : sink + boundary - from,
11146 : 0,
11147 11845760 : to - boundary);
11148 : }
11149 : to = boundary;
11150 : }
11151 : source = first;
11152 : }
11153 : break;
11154 : }
11155 : case kOneByteStringTag | kSlicedStringTag:
11156 : case kTwoByteStringTag | kSlicedStringTag: {
11157 : SlicedString* slice = SlicedString::cast(source);
11158 1568792 : unsigned offset = slice->offset();
11159 3137584 : WriteToFlat(slice->parent(), sink, from + offset, to + offset);
11160 1568792 : return;
11161 : }
11162 : case kOneByteStringTag | kThinStringTag:
11163 : case kTwoByteStringTag | kThinStringTag:
11164 : source = ThinString::cast(source)->actual();
11165 36086 : break;
11166 : }
11167 : }
11168 : }
11169 :
11170 : template <typename SourceChar>
11171 45720 : static void CalculateLineEndsImpl(Isolate* isolate, std::vector<int>* line_ends,
11172 : Vector<const SourceChar> src,
11173 : bool include_ending_line) {
11174 91440 : const int src_len = src.length();
11175 : UnicodeCache* cache = isolate->unicode_cache();
11176 213205794 : for (int i = 0; i < src_len - 1; i++) {
11177 426320148 : SourceChar current = src[i];
11178 426320148 : SourceChar next = src[i + 1];
11179 426320148 : if (cache->IsLineTerminatorSequence(current, next)) line_ends->push_back(i);
11180 : }
11181 :
11182 136512 : if (src_len > 0 && cache->IsLineTerminatorSequence(src[src_len - 1], 0)) {
11183 34094 : line_ends->push_back(src_len - 1);
11184 : }
11185 45720 : if (include_ending_line) {
11186 : // Include one character beyond the end of script. The rewriter uses that
11187 : // position for the implicit return statement.
11188 44456 : line_ends->push_back(src_len);
11189 : }
11190 45720 : }
11191 :
11192 :
11193 45720 : Handle<FixedArray> String::CalculateLineEnds(Handle<String> src,
11194 : bool include_ending_line) {
11195 45720 : src = Flatten(src);
11196 : // Rough estimate of line count based on a roughly estimated average
11197 : // length of (unpacked) code.
11198 45720 : int line_count_estimate = src->length() >> 4;
11199 : std::vector<int> line_ends;
11200 45720 : line_ends.reserve(line_count_estimate);
11201 : Isolate* isolate = src->GetIsolate();
11202 : { DisallowHeapAllocation no_allocation; // ensure vectors stay valid.
11203 : // Dispatch on type of strings.
11204 45720 : String::FlatContent content = src->GetFlatContent();
11205 : DCHECK(content.IsFlat());
11206 45720 : if (content.IsOneByte()) {
11207 : CalculateLineEndsImpl(isolate,
11208 : &line_ends,
11209 : content.ToOneByteVector(),
11210 91404 : include_ending_line);
11211 : } else {
11212 : CalculateLineEndsImpl(isolate,
11213 : &line_ends,
11214 : content.ToUC16Vector(),
11215 36 : include_ending_line);
11216 : }
11217 : }
11218 91440 : int line_count = static_cast<int>(line_ends.size());
11219 45720 : Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count);
11220 11528329 : for (int i = 0; i < line_count; i++) {
11221 22965218 : array->set(i, Smi::FromInt(line_ends[i]));
11222 : }
11223 91440 : return array;
11224 : }
11225 :
11226 :
11227 : // Compares the contents of two strings by reading and comparing
11228 : // int-sized blocks of characters.
11229 : template <typename Char>
11230 : static inline bool CompareRawStringContents(const Char* const a,
11231 : const Char* const b,
11232 : int length) {
11233 51511944 : return CompareChars(a, b, length) == 0;
11234 : }
11235 :
11236 :
11237 : template<typename Chars1, typename Chars2>
11238 : class RawStringComparator : public AllStatic {
11239 : public:
11240 : static inline bool compare(const Chars1* a, const Chars2* b, int len) {
11241 : DCHECK(sizeof(Chars1) != sizeof(Chars2));
11242 2947468 : for (int i = 0; i < len; i++) {
11243 2947483 : if (a[i] != b[i]) {
11244 : return false;
11245 : }
11246 : }
11247 : return true;
11248 : }
11249 : };
11250 :
11251 :
11252 : template<>
11253 : class RawStringComparator<uint16_t, uint16_t> {
11254 : public:
11255 : static inline bool compare(const uint16_t* a, const uint16_t* b, int len) {
11256 : return CompareRawStringContents(a, b, len);
11257 : }
11258 : };
11259 :
11260 :
11261 : template<>
11262 : class RawStringComparator<uint8_t, uint8_t> {
11263 : public:
11264 : static inline bool compare(const uint8_t* a, const uint8_t* b, int len) {
11265 : return CompareRawStringContents(a, b, len);
11266 : }
11267 : };
11268 :
11269 :
11270 : class StringComparator {
11271 : class State {
11272 : public:
11273 2119394 : State() : is_one_byte_(true), length_(0), buffer8_(nullptr) {}
11274 :
11275 4238788 : void Init(String* string) {
11276 4238788 : ConsString* cons_string = String::VisitFlat(this, string);
11277 : iter_.Reset(cons_string);
11278 4238788 : if (cons_string != nullptr) {
11279 : int offset;
11280 2130716 : string = iter_.Next(&offset);
11281 2130716 : String::VisitFlat(this, string, offset);
11282 : }
11283 4238788 : }
11284 :
11285 : inline void VisitOneByteString(const uint8_t* chars, int length) {
11286 24958339 : is_one_byte_ = true;
11287 24958339 : buffer8_ = chars;
11288 24958339 : length_ = length;
11289 : }
11290 :
11291 : inline void VisitTwoByteString(const uint16_t* chars, int length) {
11292 1623878 : is_one_byte_ = false;
11293 1623878 : buffer16_ = chars;
11294 1623878 : length_ = length;
11295 : }
11296 :
11297 27824344 : void Advance(int consumed) {
11298 : DCHECK(consumed <= length_);
11299 : // Still in buffer.
11300 27824344 : if (length_ != consumed) {
11301 5480915 : if (is_one_byte_) {
11302 4757504 : buffer8_ += consumed;
11303 : } else {
11304 723411 : buffer16_ += consumed;
11305 : }
11306 5480915 : length_ -= consumed;
11307 33305259 : return;
11308 : }
11309 : // Advance state.
11310 : int offset;
11311 22343429 : String* next = iter_.Next(&offset);
11312 : DCHECK_EQ(0, offset);
11313 : DCHECK_NOT_NULL(next);
11314 22343429 : String::VisitFlat(this, next);
11315 : }
11316 :
11317 : ConsStringIterator iter_;
11318 : bool is_one_byte_;
11319 : int length_;
11320 : union {
11321 : const uint8_t* buffer8_;
11322 : const uint16_t* buffer16_;
11323 : };
11324 :
11325 : private:
11326 : DISALLOW_COPY_AND_ASSIGN(State);
11327 : };
11328 :
11329 : public:
11330 : inline StringComparator() {}
11331 :
11332 : template<typename Chars1, typename Chars2>
11333 : static inline bool Equals(State* state_1, State* state_2, int to_check) {
11334 : const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_);
11335 : const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_);
11336 : return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check);
11337 : }
11338 :
11339 2119394 : bool Equals(String* string_1, String* string_2) {
11340 : int length = string_1->length();
11341 18150960 : state_1_.Init(string_1);
11342 18150960 : state_2_.Init(string_2);
11343 : while (true) {
11344 16031566 : int to_check = Min(state_1_.length_, state_2_.length_);
11345 : DCHECK(to_check > 0 && to_check <= length);
11346 : bool is_equal;
11347 16031566 : if (state_1_.is_one_byte_) {
11348 14496921 : if (state_2_.is_one_byte_) {
11349 : is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check);
11350 : } else {
11351 : is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check);
11352 : }
11353 : } else {
11354 1534645 : if (state_2_.is_one_byte_) {
11355 : is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check);
11356 : } else {
11357 : is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check);
11358 : }
11359 : }
11360 : // Looping done.
11361 16031566 : if (!is_equal) return false;
11362 16024823 : length -= to_check;
11363 : // Exit condition. Strings are equal.
11364 16024823 : if (length == 0) return true;
11365 13912172 : state_1_.Advance(to_check);
11366 13912172 : state_2_.Advance(to_check);
11367 13912172 : }
11368 : }
11369 :
11370 : private:
11371 : State state_1_;
11372 : State state_2_;
11373 :
11374 : DISALLOW_COPY_AND_ASSIGN(StringComparator);
11375 : };
11376 :
11377 :
11378 16636501 : bool String::SlowEquals(String* other) {
11379 : DisallowHeapAllocation no_gc;
11380 : // Fast check: negative check with lengths.
11381 : int len = length();
11382 16636501 : if (len != other->length()) return false;
11383 12711256 : if (len == 0) return true;
11384 :
11385 : // Fast check: if at least one ThinString is involved, dereference it/them
11386 : // and restart.
11387 25420255 : if (this->IsThinString() || other->IsThinString()) {
11388 4543 : if (other->IsThinString()) other = ThinString::cast(other)->actual();
11389 4543 : if (this->IsThinString()) {
11390 2257 : return ThinString::cast(this)->actual()->Equals(other);
11391 : } else {
11392 2286 : return this->Equals(other);
11393 : }
11394 : }
11395 :
11396 : // Fast check: if hash code is computed for both strings
11397 : // a fast negative check can be performed.
11398 25208082 : if (HasHashCode() && other->HasHashCode()) {
11399 : #ifdef ENABLE_SLOW_DCHECKS
11400 : if (FLAG_enable_slow_asserts) {
11401 : if (Hash() != other->Hash()) {
11402 : bool found_difference = false;
11403 : for (int i = 0; i < len; i++) {
11404 : if (Get(i) != other->Get(i)) {
11405 : found_difference = true;
11406 : break;
11407 : }
11408 : }
11409 : DCHECK(found_difference);
11410 : }
11411 : }
11412 : #endif
11413 12500146 : if (Hash() != other->Hash()) return false;
11414 : }
11415 :
11416 : // We know the strings are both non-empty. Compare the first chars
11417 : // before we try to flatten the strings.
11418 11627037 : if (this->Get(0) != other->Get(0)) return false;
11419 :
11420 21519932 : if (IsSeqOneByteString() && other->IsSeqOneByteString()) {
11421 9506760 : const uint8_t* str1 = SeqOneByteString::cast(this)->GetChars();
11422 9506760 : const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars();
11423 9506760 : return CompareRawStringContents(str1, str2, len);
11424 : }
11425 :
11426 : StringComparator comparator;
11427 2119394 : return comparator.Equals(this, other);
11428 : }
11429 :
11430 :
11431 4313902 : bool String::SlowEquals(Handle<String> one, Handle<String> two) {
11432 : // Fast check: negative check with lengths.
11433 : int one_length = one->length();
11434 4313902 : if (one_length != two->length()) return false;
11435 4303375 : if (one_length == 0) return true;
11436 :
11437 : // Fast check: if at least one ThinString is involved, dereference it/them
11438 : // and restart.
11439 8606750 : if (one->IsThinString() || two->IsThinString()) {
11440 23 : if (one->IsThinString()) one = handle(ThinString::cast(*one)->actual());
11441 23 : if (two->IsThinString()) two = handle(ThinString::cast(*two)->actual());
11442 23 : return String::Equals(one, two);
11443 : }
11444 :
11445 : // Fast check: if hash code is computed for both strings
11446 : // a fast negative check can be performed.
11447 4319579 : if (one->HasHashCode() && two->HasHashCode()) {
11448 : #ifdef ENABLE_SLOW_DCHECKS
11449 : if (FLAG_enable_slow_asserts) {
11450 : if (one->Hash() != two->Hash()) {
11451 : bool found_difference = false;
11452 : for (int i = 0; i < one_length; i++) {
11453 : if (one->Get(i) != two->Get(i)) {
11454 : found_difference = true;
11455 : break;
11456 : }
11457 : }
11458 : DCHECK(found_difference);
11459 : }
11460 : }
11461 : #endif
11462 5635 : if (one->Hash() != two->Hash()) return false;
11463 : }
11464 :
11465 : // We know the strings are both non-empty. Compare the first chars
11466 : // before we try to flatten the strings.
11467 4303207 : if (one->Get(0) != two->Get(0)) return false;
11468 :
11469 2936423 : one = String::Flatten(one);
11470 2936423 : two = String::Flatten(two);
11471 :
11472 : DisallowHeapAllocation no_gc;
11473 2936423 : String::FlatContent flat1 = one->GetFlatContent();
11474 2936423 : String::FlatContent flat2 = two->GetFlatContent();
11475 :
11476 2936423 : if (flat1.IsOneByte() && flat2.IsOneByte()) {
11477 : return CompareRawStringContents(flat1.ToOneByteVector().start(),
11478 : flat2.ToOneByteVector().start(),
11479 : one_length);
11480 : } else {
11481 13652567 : for (int i = 0; i < one_length; i++) {
11482 13652567 : if (flat1.Get(i) != flat2.Get(i)) return false;
11483 : }
11484 : return true;
11485 : }
11486 : }
11487 :
11488 :
11489 : // static
11490 5120741 : ComparisonResult String::Compare(Handle<String> x, Handle<String> y) {
11491 : // A few fast case tests before we flatten.
11492 5120741 : if (x.is_identical_to(y)) {
11493 : return ComparisonResult::kEqual;
11494 5120735 : } else if (y->length() == 0) {
11495 : return x->length() == 0 ? ComparisonResult::kEqual
11496 0 : : ComparisonResult::kGreaterThan;
11497 5120735 : } else if (x->length() == 0) {
11498 : return ComparisonResult::kLessThan;
11499 : }
11500 :
11501 10241470 : int const d = x->Get(0) - y->Get(0);
11502 5120735 : if (d < 0) {
11503 : return ComparisonResult::kLessThan;
11504 3353726 : } else if (d > 0) {
11505 : return ComparisonResult::kGreaterThan;
11506 : }
11507 :
11508 : // Slow case.
11509 410957 : x = String::Flatten(x);
11510 410957 : y = String::Flatten(y);
11511 :
11512 : DisallowHeapAllocation no_gc;
11513 : ComparisonResult result = ComparisonResult::kEqual;
11514 : int prefix_length = x->length();
11515 410957 : if (y->length() < prefix_length) {
11516 : prefix_length = y->length();
11517 : result = ComparisonResult::kGreaterThan;
11518 370717 : } else if (y->length() > prefix_length) {
11519 : result = ComparisonResult::kLessThan;
11520 : }
11521 : int r;
11522 410957 : String::FlatContent x_content = x->GetFlatContent();
11523 410957 : String::FlatContent y_content = y->GetFlatContent();
11524 410957 : if (x_content.IsOneByte()) {
11525 : Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
11526 393577 : if (y_content.IsOneByte()) {
11527 : Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11528 391489 : r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11529 : } else {
11530 : Vector<const uc16> y_chars = y_content.ToUC16Vector();
11531 2088 : r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11532 : }
11533 : } else {
11534 : Vector<const uc16> x_chars = x_content.ToUC16Vector();
11535 17380 : if (y_content.IsOneByte()) {
11536 : Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11537 1044 : r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11538 : } else {
11539 : Vector<const uc16> y_chars = y_content.ToUC16Vector();
11540 16336 : r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11541 : }
11542 : }
11543 410957 : if (r < 0) {
11544 : result = ComparisonResult::kLessThan;
11545 162295 : } else if (r > 0) {
11546 : result = ComparisonResult::kGreaterThan;
11547 : }
11548 410957 : return result;
11549 : }
11550 :
11551 2439 : Object* String::IndexOf(Isolate* isolate, Handle<Object> receiver,
11552 : Handle<Object> search, Handle<Object> position) {
11553 2439 : if (receiver->IsNullOrUndefined(isolate)) {
11554 600 : THROW_NEW_ERROR_RETURN_FAILURE(
11555 : isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
11556 : isolate->factory()->NewStringFromAsciiChecked(
11557 : "String.prototype.indexOf")));
11558 : }
11559 : Handle<String> receiver_string;
11560 4478 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string,
11561 : Object::ToString(isolate, receiver));
11562 :
11563 : Handle<String> search_string;
11564 4478 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
11565 : Object::ToString(isolate, search));
11566 :
11567 2239 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11568 : Object::ToInteger(isolate, position));
11569 :
11570 : uint32_t index = receiver_string->ToValidIndex(*position);
11571 : return Smi::FromInt(
11572 4458 : String::IndexOf(isolate, receiver_string, search_string, index));
11573 : }
11574 :
11575 : namespace {
11576 :
11577 : template <typename T>
11578 117734 : int SearchString(Isolate* isolate, String::FlatContent receiver_content,
11579 : Vector<T> pat_vector, int start_index) {
11580 117734 : if (receiver_content.IsOneByte()) {
11581 : return SearchString(isolate, receiver_content.ToOneByteVector(), pat_vector,
11582 117508 : start_index);
11583 : }
11584 : return SearchString(isolate, receiver_content.ToUC16Vector(), pat_vector,
11585 226 : start_index);
11586 : }
11587 :
11588 : } // namespace
11589 :
11590 120555 : int String::IndexOf(Isolate* isolate, Handle<String> receiver,
11591 : Handle<String> search, int start_index) {
11592 : DCHECK_LE(0, start_index);
11593 : DCHECK(start_index <= receiver->length());
11594 :
11595 120555 : uint32_t search_length = search->length();
11596 120555 : if (search_length == 0) return start_index;
11597 :
11598 120508 : uint32_t receiver_length = receiver->length();
11599 120508 : if (start_index + search_length > receiver_length) return -1;
11600 :
11601 117734 : receiver = String::Flatten(receiver);
11602 117734 : search = String::Flatten(search);
11603 :
11604 : DisallowHeapAllocation no_gc; // ensure vectors stay valid
11605 : // Extract flattened substrings of cons strings before getting encoding.
11606 117734 : String::FlatContent receiver_content = receiver->GetFlatContent();
11607 117734 : String::FlatContent search_content = search->GetFlatContent();
11608 :
11609 : // dispatch on type of strings
11610 117734 : if (search_content.IsOneByte()) {
11611 115747 : Vector<const uint8_t> pat_vector = search_content.ToOneByteVector();
11612 : return SearchString<const uint8_t>(isolate, receiver_content, pat_vector,
11613 115747 : start_index);
11614 : }
11615 1987 : Vector<const uc16> pat_vector = search_content.ToUC16Vector();
11616 : return SearchString<const uc16>(isolate, receiver_content, pat_vector,
11617 1987 : start_index);
11618 : }
11619 :
11620 3976 : MaybeHandle<String> String::GetSubstitution(Isolate* isolate, Match* match,
11621 : Handle<String> replacement,
11622 : int start_index) {
11623 : DCHECK_IMPLIES(match->HasNamedCaptures(), FLAG_harmony_regexp_named_captures);
11624 : DCHECK_GE(start_index, 0);
11625 :
11626 : Factory* factory = isolate->factory();
11627 :
11628 : const int replacement_length = replacement->length();
11629 3976 : const int captures_length = match->CaptureCount();
11630 :
11631 3976 : replacement = String::Flatten(replacement);
11632 :
11633 : Handle<String> dollar_string =
11634 3976 : factory->LookupSingleCharacterStringFromCode('$');
11635 : int next_dollar_ix =
11636 3976 : String::IndexOf(isolate, replacement, dollar_string, start_index);
11637 3976 : if (next_dollar_ix < 0) {
11638 50 : return replacement;
11639 : }
11640 :
11641 3926 : IncrementalStringBuilder builder(isolate);
11642 :
11643 3926 : if (next_dollar_ix > 0) {
11644 310 : builder.AppendString(factory->NewSubString(replacement, 0, next_dollar_ix));
11645 : }
11646 :
11647 : while (true) {
11648 8599 : const int peek_ix = next_dollar_ix + 1;
11649 8599 : if (peek_ix >= replacement_length) {
11650 : builder.AppendCharacter('$');
11651 20 : return builder.Finish();
11652 : }
11653 :
11654 : int continue_from_ix = -1;
11655 : const uint16_t peek = replacement->Get(peek_ix);
11656 8579 : switch (peek) {
11657 : case '$': // $$
11658 : builder.AppendCharacter('$');
11659 60 : continue_from_ix = peek_ix + 1;
11660 60 : break;
11661 : case '&': // $& - match
11662 60 : builder.AppendString(match->GetMatch());
11663 60 : continue_from_ix = peek_ix + 1;
11664 60 : break;
11665 : case '`': // $` - prefix
11666 40 : builder.AppendString(match->GetPrefix());
11667 40 : continue_from_ix = peek_ix + 1;
11668 40 : break;
11669 : case '\'': // $' - suffix
11670 40 : builder.AppendString(match->GetSuffix());
11671 40 : continue_from_ix = peek_ix + 1;
11672 40 : break;
11673 : case '0':
11674 : case '1':
11675 : case '2':
11676 : case '3':
11677 : case '4':
11678 : case '5':
11679 : case '6':
11680 : case '7':
11681 : case '8':
11682 : case '9': {
11683 : // Valid indices are $1 .. $9, $01 .. $09 and $10 .. $99
11684 7998 : int scaled_index = (peek - '0');
11685 : int advance = 1;
11686 :
11687 7998 : if (peek_ix + 1 < replacement_length) {
11688 : const uint16_t next_peek = replacement->Get(peek_ix + 1);
11689 6661 : if (next_peek >= '0' && next_peek <= '9') {
11690 1490 : const int new_scaled_index = scaled_index * 10 + (next_peek - '0');
11691 1490 : if (new_scaled_index < captures_length) {
11692 : scaled_index = new_scaled_index;
11693 : advance = 2;
11694 : }
11695 : }
11696 : }
11697 :
11698 7998 : if (scaled_index == 0 || scaled_index >= captures_length) {
11699 : builder.AppendCharacter('$');
11700 : continue_from_ix = peek_ix;
11701 8098 : break;
11702 : }
11703 :
11704 : bool capture_exists;
11705 : Handle<String> capture;
11706 15796 : ASSIGN_RETURN_ON_EXCEPTION(
11707 : isolate, capture, match->GetCapture(scaled_index, &capture_exists),
11708 : String);
11709 7898 : if (capture_exists) builder.AppendString(capture);
11710 7898 : continue_from_ix = peek_ix + advance;
11711 7898 : break;
11712 : }
11713 : case '<': { // $<name> - named capture
11714 : typedef String::Match::CaptureState CaptureState;
11715 :
11716 351 : if (!match->HasNamedCaptures()) {
11717 : builder.AppendCharacter('$');
11718 : continue_from_ix = peek_ix;
11719 414 : break;
11720 : }
11721 :
11722 : Handle<String> bracket_string =
11723 288 : factory->LookupSingleCharacterStringFromCode('>');
11724 : const int closing_bracket_ix =
11725 288 : String::IndexOf(isolate, replacement, bracket_string, peek_ix + 1);
11726 :
11727 288 : if (closing_bracket_ix == -1) {
11728 : // No closing bracket was found, treat '$<' as a string literal.
11729 : builder.AppendCharacter('$');
11730 : continue_from_ix = peek_ix;
11731 72 : break;
11732 : }
11733 :
11734 : Handle<String> capture_name =
11735 216 : factory->NewSubString(replacement, peek_ix + 1, closing_bracket_ix);
11736 : Handle<String> capture;
11737 : CaptureState capture_state;
11738 432 : ASSIGN_RETURN_ON_EXCEPTION(
11739 : isolate, capture,
11740 : match->GetNamedCapture(capture_name, &capture_state), String);
11741 :
11742 216 : switch (capture_state) {
11743 : case CaptureState::INVALID:
11744 : case CaptureState::UNMATCHED:
11745 : break;
11746 : case CaptureState::MATCHED:
11747 72 : builder.AppendString(capture);
11748 72 : break;
11749 : }
11750 :
11751 216 : continue_from_ix = closing_bracket_ix + 1;
11752 216 : break;
11753 : }
11754 : default:
11755 : builder.AppendCharacter('$');
11756 : continue_from_ix = peek_ix;
11757 30 : break;
11758 : }
11759 :
11760 : // Go the the next $ in the replacement.
11761 : // TODO(jgruber): Single-char lookups could be much more efficient.
11762 : DCHECK_NE(continue_from_ix, -1);
11763 : next_dollar_ix =
11764 8579 : String::IndexOf(isolate, replacement, dollar_string, continue_from_ix);
11765 :
11766 : // Return if there are no more $ characters in the replacement. If we
11767 : // haven't reached the end, we need to append the suffix.
11768 8579 : if (next_dollar_ix < 0) {
11769 3906 : if (continue_from_ix < replacement_length) {
11770 : builder.AppendString(factory->NewSubString(
11771 1369 : replacement, continue_from_ix, replacement_length));
11772 : }
11773 3906 : return builder.Finish();
11774 : }
11775 :
11776 : // Append substring between the previous and the next $ character.
11777 4673 : if (next_dollar_ix > continue_from_ix) {
11778 : builder.AppendString(
11779 72 : factory->NewSubString(replacement, continue_from_ix, next_dollar_ix));
11780 : }
11781 : }
11782 :
11783 : UNREACHABLE();
11784 : }
11785 :
11786 : namespace { // for String.Prototype.lastIndexOf
11787 :
11788 : template <typename schar, typename pchar>
11789 1579 : int StringMatchBackwards(Vector<const schar> subject,
11790 : Vector<const pchar> pattern, int idx) {
11791 1579 : int pattern_length = pattern.length();
11792 : DCHECK_GE(pattern_length, 1);
11793 : DCHECK(idx + pattern_length <= subject.length());
11794 :
11795 : if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
11796 0 : for (int i = 0; i < pattern_length; i++) {
11797 0 : uc16 c = pattern[i];
11798 0 : if (c > String::kMaxOneByteCharCode) {
11799 : return -1;
11800 : }
11801 : }
11802 : }
11803 :
11804 1579 : pchar pattern_first_char = pattern[0];
11805 5704 : for (int i = idx; i >= 0; i--) {
11806 14198 : if (subject[i] != pattern_first_char) continue;
11807 : int j = 1;
11808 2159 : while (j < pattern_length) {
11809 2292 : if (pattern[j] != subject[i + j]) {
11810 : break;
11811 : }
11812 744 : j++;
11813 : }
11814 1415 : if (j == pattern_length) {
11815 : return i;
11816 : }
11817 : }
11818 : return -1;
11819 : }
11820 :
11821 : } // namespace
11822 :
11823 2039 : Object* String::LastIndexOf(Isolate* isolate, Handle<Object> receiver,
11824 : Handle<Object> search, Handle<Object> position) {
11825 2039 : if (receiver->IsNullOrUndefined(isolate)) {
11826 540 : THROW_NEW_ERROR_RETURN_FAILURE(
11827 : isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
11828 : isolate->factory()->NewStringFromAsciiChecked(
11829 : "String.prototype.lastIndexOf")));
11830 : }
11831 : Handle<String> receiver_string;
11832 3718 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string,
11833 : Object::ToString(isolate, receiver));
11834 :
11835 : Handle<String> search_string;
11836 3718 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
11837 : Object::ToString(isolate, search));
11838 :
11839 3718 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11840 : Object::ToNumber(position));
11841 :
11842 : uint32_t start_index;
11843 :
11844 1859 : if (position->IsNaN()) {
11845 1329 : start_index = receiver_string->length();
11846 : } else {
11847 530 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11848 : Object::ToInteger(isolate, position));
11849 : start_index = receiver_string->ToValidIndex(*position);
11850 : }
11851 :
11852 1859 : uint32_t pattern_length = search_string->length();
11853 1859 : uint32_t receiver_length = receiver_string->length();
11854 :
11855 1859 : if (start_index + pattern_length > receiver_length) {
11856 1409 : start_index = receiver_length - pattern_length;
11857 : }
11858 :
11859 1859 : if (pattern_length == 0) {
11860 560 : return Smi::FromInt(start_index);
11861 : }
11862 :
11863 1579 : receiver_string = String::Flatten(receiver_string);
11864 1579 : search_string = String::Flatten(search_string);
11865 :
11866 : int last_index = -1;
11867 : DisallowHeapAllocation no_gc; // ensure vectors stay valid
11868 :
11869 1579 : String::FlatContent receiver_content = receiver_string->GetFlatContent();
11870 1579 : String::FlatContent search_content = search_string->GetFlatContent();
11871 :
11872 1579 : if (search_content.IsOneByte()) {
11873 1579 : Vector<const uint8_t> pat_vector = search_content.ToOneByteVector();
11874 1579 : if (receiver_content.IsOneByte()) {
11875 : last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
11876 1573 : pat_vector, start_index);
11877 : } else {
11878 : last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
11879 6 : pat_vector, start_index);
11880 : }
11881 : } else {
11882 0 : Vector<const uc16> pat_vector = search_content.ToUC16Vector();
11883 0 : if (receiver_content.IsOneByte()) {
11884 : last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
11885 0 : pat_vector, start_index);
11886 : } else {
11887 : last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
11888 0 : pat_vector, start_index);
11889 : }
11890 : }
11891 1579 : return Smi::FromInt(last_index);
11892 : }
11893 :
11894 25823454 : bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
11895 : int slen = length();
11896 : // Can't check exact length equality, but we can check bounds.
11897 25823454 : int str_len = str.length();
11898 25823454 : if (!allow_prefix_match &&
11899 25020651 : (str_len < slen ||
11900 25020651 : str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) {
11901 : return false;
11902 : }
11903 : int i;
11904 24963901 : size_t remaining_in_str = static_cast<size_t>(str_len);
11905 24963901 : const uint8_t* utf8_data = reinterpret_cast<const uint8_t*>(str.start());
11906 697222780 : for (i = 0; i < slen && remaining_in_str > 0; i++) {
11907 332003234 : size_t cursor = 0;
11908 332003234 : uint32_t r = unibrow::Utf8::ValueOf(utf8_data, remaining_in_str, &cursor);
11909 : DCHECK(cursor > 0 && cursor <= remaining_in_str);
11910 332003234 : if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
11911 8355757 : if (i > slen - 1) return false;
11912 24 : if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false;
11913 12 : if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false;
11914 : } else {
11915 332003222 : if (Get(i) != r) return false;
11916 : }
11917 323647489 : utf8_data += cursor;
11918 323647489 : remaining_in_str -= cursor;
11919 : }
11920 16608156 : return (allow_prefix_match || i == slen) && remaining_in_str == 0;
11921 : }
11922 :
11923 : template <>
11924 135 : bool String::IsEqualTo(Vector<const uint8_t> str) {
11925 135 : return IsOneByteEqualTo(str);
11926 : }
11927 :
11928 : template <>
11929 0 : bool String::IsEqualTo(Vector<const uc16> str) {
11930 0 : return IsTwoByteEqualTo(str);
11931 : }
11932 :
11933 90244315 : bool String::IsOneByteEqualTo(Vector<const uint8_t> str) {
11934 : int slen = length();
11935 180488630 : if (str.length() != slen) return false;
11936 : DisallowHeapAllocation no_gc;
11937 75655719 : FlatContent content = GetFlatContent();
11938 75655722 : if (content.IsOneByte()) {
11939 75655663 : return CompareChars(content.ToOneByteVector().start(),
11940 151311326 : str.start(), slen) == 0;
11941 : }
11942 82 : for (int i = 0; i < slen; i++) {
11943 258 : if (Get(i) != static_cast<uint16_t>(str[i])) return false;
11944 : }
11945 : return true;
11946 : }
11947 :
11948 :
11949 25494 : bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
11950 : int slen = length();
11951 50988 : if (str.length() != slen) return false;
11952 : DisallowHeapAllocation no_gc;
11953 8193 : FlatContent content = GetFlatContent();
11954 8193 : if (content.IsTwoByte()) {
11955 14744 : return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
11956 : }
11957 0 : for (int i = 0; i < slen; i++) {
11958 1642 : if (Get(i) != str[i]) return false;
11959 : }
11960 : return true;
11961 : }
11962 :
11963 :
11964 63848349 : uint32_t String::ComputeAndSetHash() {
11965 : // Should only be called if hash code has not yet been computed.
11966 : DCHECK(!HasHashCode());
11967 :
11968 : // Store the hash code in the object.
11969 63848349 : uint32_t field = IteratingStringHasher::Hash(this, GetHeap()->HashSeed());
11970 : set_hash_field(field);
11971 :
11972 : // Check the hash code is there.
11973 : DCHECK(HasHashCode());
11974 63848510 : uint32_t result = field >> kHashShift;
11975 : DCHECK_NE(result, 0); // Ensure that the hash value of 0 is never computed.
11976 63848510 : return result;
11977 : }
11978 :
11979 :
11980 3429979 : bool String::ComputeArrayIndex(uint32_t* index) {
11981 : int length = this->length();
11982 3429979 : if (length == 0 || length > kMaxArrayIndexSize) return false;
11983 : StringCharacterStream stream(this);
11984 1760817 : return StringToArrayIndex(&stream, index);
11985 : }
11986 :
11987 :
11988 12573935 : bool String::SlowAsArrayIndex(uint32_t* index) {
11989 12573935 : if (length() <= kMaxCachedArrayIndexLength) {
11990 9143956 : Hash(); // force computation of hash code
11991 : uint32_t field = hash_field();
11992 9143956 : if ((field & kIsNotArrayIndexMask) != 0) return false;
11993 : // Isolate the array index form the full hash field.
11994 509908 : *index = ArrayIndexValueBits::decode(field);
11995 509908 : return true;
11996 : } else {
11997 3429979 : return ComputeArrayIndex(index);
11998 : }
11999 : }
12000 :
12001 :
12002 25817815 : Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
12003 : Heap* heap = string->GetHeap();
12004 25817815 : if (new_length == 0) return heap->isolate()->factory()->empty_string();
12005 :
12006 : int new_size, old_size;
12007 : int old_length = string->length();
12008 19250877 : if (old_length <= new_length) return string;
12009 :
12010 18214886 : if (string->IsSeqOneByteString()) {
12011 : old_size = SeqOneByteString::SizeFor(old_length);
12012 : new_size = SeqOneByteString::SizeFor(new_length);
12013 : } else {
12014 : DCHECK(string->IsSeqTwoByteString());
12015 : old_size = SeqTwoByteString::SizeFor(old_length);
12016 : new_size = SeqTwoByteString::SizeFor(new_length);
12017 : }
12018 :
12019 18214886 : int delta = old_size - new_size;
12020 :
12021 18214886 : Address start_of_string = string->address();
12022 : DCHECK_OBJECT_ALIGNED(start_of_string);
12023 : DCHECK_OBJECT_ALIGNED(start_of_string + new_size);
12024 :
12025 : // Sizes are pointer size aligned, so that we can use filler objects
12026 : // that are a multiple of pointer size.
12027 : heap->CreateFillerObjectAt(start_of_string + new_size, delta,
12028 18214886 : ClearRecordedSlots::kNo);
12029 : // We are storing the new length using release store after creating a filler
12030 : // for the left-over space to avoid races with the sweeper thread.
12031 : string->synchronized_set_length(new_length);
12032 :
12033 18214886 : return string;
12034 : }
12035 :
12036 177406 : void SeqOneByteString::clear_padding() {
12037 177406 : int data_size = SeqString::kHeaderSize + length() * kOneByteSize;
12038 177406 : memset(address() + data_size, 0, SizeFor(length()) - data_size);
12039 177406 : }
12040 :
12041 0 : void SeqTwoByteString::clear_padding() {
12042 0 : int data_size = SeqString::kHeaderSize + length() * kUC16Size;
12043 0 : memset(address() + data_size, 0, SizeFor(length()) - data_size);
12044 0 : }
12045 :
12046 1513200 : uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
12047 : // For array indexes mix the length into the hash as an array index could
12048 : // be zero.
12049 : DCHECK_GT(length, 0);
12050 : DCHECK_LE(length, String::kMaxArrayIndexSize);
12051 : DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
12052 : (1 << String::kArrayIndexValueBits));
12053 :
12054 5901124 : value <<= String::ArrayIndexValueBits::kShift;
12055 5901124 : value |= length << String::ArrayIndexLengthBits::kShift;
12056 :
12057 : DCHECK_EQ(value & String::kIsNotArrayIndexMask, 0);
12058 : DCHECK_EQ(length <= String::kMaxCachedArrayIndexLength,
12059 : Name::ContainsCachedArrayIndex(value));
12060 1513200 : return value;
12061 : }
12062 :
12063 :
12064 210939162 : uint32_t StringHasher::GetHashField() {
12065 210939162 : if (length_ <= String::kMaxHashCalcLength) {
12066 210894699 : if (is_array_index_) {
12067 8020144 : return MakeArrayIndexHash(array_index_, length_);
12068 : }
12069 413769254 : return (GetHashCore(raw_running_hash_) << String::kHashShift) |
12070 206884627 : String::kIsNotArrayIndexMask;
12071 : } else {
12072 44463 : return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
12073 : }
12074 : }
12075 :
12076 :
12077 16790285 : uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars,
12078 : uint32_t seed,
12079 : int* utf16_length_out) {
12080 16790285 : int vector_length = chars.length();
12081 : // Handle some edge cases
12082 16790285 : if (vector_length <= 1) {
12083 : DCHECK(vector_length == 0 ||
12084 : static_cast<uint8_t>(chars.start()[0]) <=
12085 : unibrow::Utf8::kMaxOneByteChar);
12086 2370 : *utf16_length_out = vector_length;
12087 2370 : return HashSequentialString(chars.start(), vector_length, seed);
12088 : }
12089 : // Start with a fake length which won't affect computation.
12090 : // It will be updated later.
12091 : StringHasher hasher(String::kMaxArrayIndexSize, seed);
12092 16787915 : size_t remaining = static_cast<size_t>(vector_length);
12093 : const uint8_t* stream = reinterpret_cast<const uint8_t*>(chars.start());
12094 : int utf16_length = 0;
12095 : bool is_index = true;
12096 : DCHECK(hasher.is_array_index_);
12097 358512549 : while (remaining > 0) {
12098 324936719 : size_t consumed = 0;
12099 324936719 : uint32_t c = unibrow::Utf8::ValueOf(stream, remaining, &consumed);
12100 : DCHECK(consumed > 0 && consumed <= remaining);
12101 324936719 : stream += consumed;
12102 324936719 : remaining -= consumed;
12103 324936719 : bool is_two_characters = c > unibrow::Utf16::kMaxNonSurrogateCharCode;
12104 324936719 : utf16_length += is_two_characters ? 2 : 1;
12105 : // No need to keep hashing. But we do need to calculate utf16_length.
12106 324936719 : if (utf16_length > String::kMaxHashCalcLength) continue;
12107 324936719 : if (is_two_characters) {
12108 : uint16_t c1 = unibrow::Utf16::LeadSurrogate(c);
12109 : uint16_t c2 = unibrow::Utf16::TrailSurrogate(c);
12110 : hasher.AddCharacter(c1);
12111 : hasher.AddCharacter(c2);
12112 12 : if (is_index) is_index = hasher.UpdateIndex(c1);
12113 12 : if (is_index) is_index = hasher.UpdateIndex(c2);
12114 : } else {
12115 : hasher.AddCharacter(c);
12116 324936707 : if (is_index) is_index = hasher.UpdateIndex(c);
12117 : }
12118 : }
12119 16787915 : *utf16_length_out = static_cast<int>(utf16_length);
12120 : // Must set length here so that hash computation is correct.
12121 16787915 : hasher.length_ = utf16_length;
12122 16787915 : return hasher.GetHashField();
12123 : }
12124 :
12125 :
12126 1664856 : void IteratingStringHasher::VisitConsString(ConsString* cons_string) {
12127 : // Run small ConsStrings through ConsStringIterator.
12128 1664856 : if (cons_string->length() < 64) {
12129 : ConsStringIterator iter(cons_string);
12130 : int offset;
12131 : String* string;
12132 9977429 : while (nullptr != (string = iter.Next(&offset))) {
12133 : DCHECK_EQ(0, offset);
12134 8516550 : String::VisitFlat(this, string, 0);
12135 : }
12136 1664856 : return;
12137 : }
12138 : // Slow case.
12139 203977 : const int max_length = String::kMaxHashCalcLength;
12140 407954 : int length = std::min(cons_string->length(), max_length);
12141 203977 : if (cons_string->HasOnlyOneByteChars()) {
12142 183180 : uint8_t* buffer = new uint8_t[length];
12143 183180 : String::WriteToFlat(cons_string, buffer, 0, length);
12144 183180 : AddCharacters(buffer, length);
12145 183180 : delete[] buffer;
12146 : } else {
12147 20797 : uint16_t* buffer = new uint16_t[length];
12148 20797 : String::WriteToFlat(cons_string, buffer, 0, length);
12149 20797 : AddCharacters(buffer, length);
12150 20797 : delete[] buffer;
12151 : }
12152 : }
12153 :
12154 :
12155 35009 : void String::PrintOn(FILE* file) {
12156 : int length = this->length();
12157 3217188 : for (int i = 0; i < length; i++) {
12158 3182179 : PrintF(file, "%c", Get(i));
12159 : }
12160 35009 : }
12161 :
12162 :
12163 957501 : int Map::Hash() {
12164 : // For performance reasons we only hash the 3 most variable fields of a map:
12165 : // constructor, prototype and bit_field2. For predictability reasons we
12166 : // use objects' offsets in respective pages for hashing instead of raw
12167 : // addresses.
12168 :
12169 : // Shift away the tag.
12170 1915002 : int hash = ObjectAddressForHashing(GetConstructor()) >> 2;
12171 :
12172 : // XOR-ing the prototype and constructor directly yields too many zero bits
12173 : // when the two pointers are close (which is fairly common).
12174 : // To avoid this we shift the prototype bits relatively to the constructor.
12175 957501 : hash ^= ObjectAddressForHashing(prototype()) << (32 - kPageSizeBits);
12176 :
12177 1915002 : return hash ^ (hash >> 16) ^ bit_field2();
12178 : }
12179 :
12180 :
12181 : namespace {
12182 :
12183 1193673 : bool CheckEquivalent(const Map* first, const Map* second) {
12184 2349987 : return first->GetConstructor() == second->GetConstructor() &&
12185 1146419 : first->prototype() == second->prototype() &&
12186 1146410 : first->instance_type() == second->instance_type() &&
12187 1146400 : first->bit_field() == second->bit_field() &&
12188 1146245 : first->is_extensible() == second->is_extensible() &&
12189 2339898 : first->new_target_is_base() == second->new_target_is_base() &&
12190 1193673 : first->has_hidden_prototype() == second->has_hidden_prototype();
12191 : }
12192 :
12193 : } // namespace
12194 :
12195 550684 : bool Map::EquivalentToForTransition(const Map* other) const {
12196 550684 : if (!CheckEquivalent(this, other)) return false;
12197 550519 : if (instance_type() == JS_FUNCTION_TYPE) {
12198 : // JSFunctions require more checks to ensure that sloppy function is
12199 : // not equivalent to strict function.
12200 : int nof = Min(NumberOfOwnDescriptors(), other->NumberOfOwnDescriptors());
12201 : return instance_descriptors()->IsEqualUpTo(other->instance_descriptors(),
12202 2303 : nof);
12203 : }
12204 : return true;
12205 : }
12206 :
12207 0 : bool Map::EquivalentToForElementsKindTransition(const Map* other) const {
12208 31825 : if (!EquivalentToForTransition(other)) return false;
12209 : #ifdef DEBUG
12210 : // Ensure that we don't try to generate elements kind transitions from maps
12211 : // with fields that may be generalized in-place. This must already be handled
12212 : // during addition of a new field.
12213 : DescriptorArray* descriptors = instance_descriptors();
12214 : int nof = NumberOfOwnDescriptors();
12215 : for (int i = 0; i < nof; i++) {
12216 : PropertyDetails details = descriptors->GetDetails(i);
12217 : if (details.location() == kField) {
12218 : DCHECK(!IsInplaceGeneralizableField(details.constness(),
12219 : details.representation(),
12220 : descriptors->GetFieldType(i)));
12221 : }
12222 : }
12223 : #endif
12224 0 : return true;
12225 : }
12226 :
12227 642989 : bool Map::EquivalentToForNormalization(const Map* other,
12228 : PropertyNormalizationMode mode) const {
12229 : int properties =
12230 642989 : mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other->GetInObjectProperties();
12231 1834401 : return CheckEquivalent(this, other) && bit_field2() == other->bit_field2() &&
12232 1195986 : GetInObjectProperties() == properties &&
12233 552997 : JSObject::GetEmbedderFieldCount(this) ==
12234 1195986 : JSObject::GetEmbedderFieldCount(other);
12235 : }
12236 :
12237 :
12238 352024 : void JSFunction::MarkForOptimization(ConcurrencyMode mode) {
12239 703596 : Isolate* isolate = GetIsolate();
12240 703596 : if (!isolate->concurrent_recompilation_enabled() ||
12241 351572 : isolate->bootstrapper()->IsActive()) {
12242 : mode = ConcurrencyMode::kNotConcurrent;
12243 : }
12244 :
12245 : DCHECK(!IsOptimized());
12246 : DCHECK(!HasOptimizedCode());
12247 : DCHECK(shared()->allows_lazy_compilation() ||
12248 : !shared()->optimization_disabled());
12249 :
12250 352024 : if (mode == ConcurrencyMode::kConcurrent) {
12251 13102 : if (IsInOptimizationQueue()) {
12252 0 : if (FLAG_trace_concurrent_recompilation) {
12253 0 : PrintF(" ** Not marking ");
12254 0 : ShortPrint();
12255 0 : PrintF(" -- already in optimization queue.\n");
12256 : }
12257 352024 : return;
12258 : }
12259 13102 : if (FLAG_trace_concurrent_recompilation) {
12260 0 : PrintF(" ** Marking ");
12261 0 : ShortPrint();
12262 0 : PrintF(" for concurrent recompilation.\n");
12263 : }
12264 : }
12265 :
12266 352024 : if (!IsInterpreted()) {
12267 : // For non I+TF path, install a shim which checks the optimization marker.
12268 : // No write barrier required, since the builtin is part of the root set.
12269 : set_code_no_write_barrier(
12270 : isolate->builtins()->builtin(Builtins::kCheckOptimizationMarker));
12271 : }
12272 : SetOptimizationMarker(mode == ConcurrencyMode::kConcurrent
12273 : ? OptimizationMarker::kCompileOptimizedConcurrent
12274 352024 : : OptimizationMarker::kCompileOptimized);
12275 : }
12276 :
12277 : // static
12278 12159295 : void JSFunction::EnsureLiterals(Handle<JSFunction> function) {
12279 : Handle<SharedFunctionInfo> shared(function->shared());
12280 : Isolate* isolate = shared->GetIsolate();
12281 :
12282 12159296 : FeedbackVectorState state = function->GetFeedbackVectorState(isolate);
12283 12159298 : switch (state) {
12284 : case TOP_LEVEL_SCRIPT_NEEDS_VECTOR: {
12285 : // A top level script didn't get it's literals installed.
12286 : Handle<FeedbackVector> feedback_vector =
12287 4601565 : FeedbackVector::New(isolate, shared);
12288 : Handle<Cell> new_cell =
12289 4601566 : isolate->factory()->NewOneClosureCell(feedback_vector);
12290 4601566 : function->set_feedback_vector_cell(*new_cell);
12291 : break;
12292 : }
12293 : case NEEDS_VECTOR: {
12294 : Handle<FeedbackVector> feedback_vector =
12295 1587642 : FeedbackVector::New(isolate, shared);
12296 1587640 : function->feedback_vector_cell()->set_value(*feedback_vector);
12297 : break;
12298 : }
12299 : case HAS_VECTOR:
12300 : case NO_VECTOR_NEEDED:
12301 : // Nothing to do.
12302 : break;
12303 : }
12304 12159299 : }
12305 :
12306 160969 : static void GetMinInobjectSlack(Map* map, void* data) {
12307 : int slack = map->UnusedPropertyFields();
12308 160969 : if (*reinterpret_cast<int*>(data) > slack) {
12309 41723 : *reinterpret_cast<int*>(data) = slack;
12310 : }
12311 160969 : }
12312 :
12313 :
12314 154706 : static void ShrinkInstanceSize(Map* map, void* data) {
12315 : #ifdef DEBUG
12316 : int old_visitor_id = Map::GetVisitorId(map);
12317 : #endif
12318 154706 : int slack = *reinterpret_cast<int*>(data);
12319 : DCHECK_GE(slack, 0);
12320 154706 : map->SetInObjectProperties(map->GetInObjectProperties() - slack);
12321 154706 : map->set_unused_property_fields(map->unused_property_fields() - slack);
12322 154706 : map->set_instance_size(map->instance_size() - slack * kPointerSize);
12323 : map->set_construction_counter(Map::kNoSlackTracking);
12324 : DCHECK_EQ(old_visitor_id, Map::GetVisitorId(map));
12325 154706 : }
12326 :
12327 6263 : static void StopSlackTracking(Map* map, void* data) {
12328 : map->set_construction_counter(Map::kNoSlackTracking);
12329 6263 : }
12330 :
12331 45806 : void Map::CompleteInobjectSlackTracking() {
12332 : // Has to be an initial map.
12333 : DCHECK(GetBackPointer()->IsUndefined(GetIsolate()));
12334 :
12335 45806 : int slack = UnusedPropertyFields();
12336 : DisallowHeapAllocation no_gc;
12337 : TransitionsAccessor transitions(this, &no_gc);
12338 : transitions.TraverseTransitionTree(&GetMinInobjectSlack, &slack);
12339 45806 : if (slack != 0) {
12340 : // Resize the initial map and all maps in its transition tree.
12341 : transitions.TraverseTransitionTree(&ShrinkInstanceSize, &slack);
12342 : } else {
12343 : transitions.TraverseTransitionTree(&StopSlackTracking, nullptr);
12344 : }
12345 45806 : }
12346 :
12347 :
12348 23211418 : static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) {
12349 : DisallowHeapAllocation no_gc;
12350 23211418 : if (!object->HasFastProperties()) return false;
12351 22063489 : if (object->IsJSGlobalProxy()) return false;
12352 22042374 : if (object->GetIsolate()->bootstrapper()->IsActive()) return false;
12353 8803438 : return !object->map()->is_prototype_map() ||
12354 8803438 : !object->map()->should_be_fast_prototype_map();
12355 : }
12356 :
12357 : // static
12358 2786137 : void JSObject::MakePrototypesFast(Handle<Object> receiver,
12359 : WhereToStart where_to_start,
12360 : Isolate* isolate) {
12361 2786137 : if (!receiver->IsJSReceiver()) return;
12362 7371988 : for (PrototypeIterator iter(isolate, Handle<JSReceiver>::cast(receiver),
12363 2739286 : where_to_start);
12364 6526120 : !iter.IsAtEnd(); iter.Advance()) {
12365 : Handle<Object> current = PrototypeIterator::GetCurrent(iter);
12366 4526605 : if (!current->IsJSObject()) return;
12367 : Handle<JSObject> current_obj = Handle<JSObject>::cast(current);
12368 : Map* current_map = current_obj->map();
12369 4521256 : if (current_map->is_prototype_map()) {
12370 : // If the map is already marked as should be fast, we're done. Its
12371 : // prototypes will have been marked already as well.
12372 5586509 : if (current_map->should_be_fast_prototype_map()) return;
12373 : Handle<Map> map(current_map);
12374 330830 : Map::SetShouldBeFastPrototypeMap(map, true, isolate);
12375 330830 : JSObject::OptimizeAsPrototype(current_obj);
12376 : }
12377 : }
12378 : }
12379 :
12380 : // static
12381 23301469 : void JSObject::OptimizeAsPrototype(Handle<JSObject> object) {
12382 46602926 : if (object->IsJSGlobalObject()) return;
12383 23211417 : if (PrototypeBenefitsFromNormalization(object)) {
12384 : // First normalize to ensure all JSFunctions are DATA_CONSTANT.
12385 : JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0,
12386 424963 : "NormalizeAsPrototype");
12387 : }
12388 : Handle<Map> previous_map(object->map());
12389 23211416 : if (object->map()->is_prototype_map()) {
12390 35665668 : if (object->map()->should_be_fast_prototype_map() &&
12391 16189351 : !object->HasFastProperties()) {
12392 313483 : JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype");
12393 : }
12394 : } else {
12395 3735099 : if (object->map() == *previous_map) {
12396 3735099 : Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype");
12397 3735099 : JSObject::MigrateToMap(object, new_map);
12398 : }
12399 : object->map()->set_is_prototype_map(true);
12400 :
12401 : // Replace the pointer to the exact constructor with the Object function
12402 : // from the same context if undetectable from JS. This is to avoid keeping
12403 : // memory alive unnecessarily.
12404 3735099 : Object* maybe_constructor = object->map()->GetConstructor();
12405 3735099 : if (maybe_constructor->IsJSFunction()) {
12406 : JSFunction* constructor = JSFunction::cast(maybe_constructor);
12407 : Isolate* isolate = object->GetIsolate();
12408 7420620 : if (!constructor->shared()->IsApiFunction() &&
12409 3686061 : object->class_name() == isolate->heap()->Object_string()) {
12410 : Context* context = constructor->context()->native_context();
12411 : JSFunction* object_function = context->object_function();
12412 : object->map()->SetConstructor(object_function);
12413 : }
12414 : }
12415 : }
12416 : }
12417 :
12418 :
12419 : // static
12420 571358 : void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) {
12421 571358 : if (!object->map()->is_prototype_map()) return;
12422 63228 : if (!object->map()->should_be_fast_prototype_map()) return;
12423 39146 : OptimizeAsPrototype(object);
12424 : }
12425 :
12426 :
12427 : // static
12428 1229283 : void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
12429 : // Contract: In line with InvalidatePrototypeChains()'s requirements,
12430 : // leaf maps don't need to register as users, only prototypes do.
12431 : DCHECK(user->is_prototype_map());
12432 :
12433 1229283 : Handle<Map> current_user = user;
12434 : Handle<PrototypeInfo> current_user_info =
12435 1229283 : Map::GetOrCreatePrototypeInfo(user, isolate);
12436 3207976 : for (PrototypeIterator iter(user); !iter.IsAtEnd(); iter.Advance()) {
12437 : // Walk up the prototype chain as far as links haven't been registered yet.
12438 1166997 : if (current_user_info->registry_slot() != PrototypeInfo::UNREGISTERED) {
12439 : break;
12440 : }
12441 : Handle<Object> maybe_proto = PrototypeIterator::GetCurrent(iter);
12442 : // Proxies on the prototype chain are not supported. They make it
12443 : // impossible to make any assumptions about the prototype chain anyway.
12444 1604318 : if (maybe_proto->IsJSProxy()) return;
12445 : Handle<JSObject> proto = Handle<JSObject>::cast(maybe_proto);
12446 : Handle<PrototypeInfo> proto_info =
12447 374706 : Map::GetOrCreatePrototypeInfo(proto, isolate);
12448 : Handle<Object> maybe_registry(proto_info->prototype_users(), isolate);
12449 374706 : int slot = 0;
12450 : Handle<WeakFixedArray> new_array =
12451 374706 : WeakFixedArray::Add(maybe_registry, current_user, &slot);
12452 374706 : current_user_info->set_registry_slot(slot);
12453 374706 : if (!maybe_registry.is_identical_to(new_array)) {
12454 90165 : proto_info->set_prototype_users(*new_array);
12455 : }
12456 374706 : if (FLAG_trace_prototype_users) {
12457 : PrintF("Registering %p as a user of prototype %p (map=%p).\n",
12458 : reinterpret_cast<void*>(*current_user),
12459 : reinterpret_cast<void*>(*proto),
12460 0 : reinterpret_cast<void*>(proto->map()));
12461 : }
12462 :
12463 : current_user = handle(proto->map(), isolate);
12464 : current_user_info = proto_info;
12465 : }
12466 : }
12467 :
12468 :
12469 : // Can be called regardless of whether |user| was actually registered with
12470 : // |prototype|. Returns true when there was a registration.
12471 : // static
12472 3888596 : bool JSObject::UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
12473 : DCHECK(user->is_prototype_map());
12474 : // If it doesn't have a PrototypeInfo, it was never registered.
12475 3888596 : if (!user->prototype_info()->IsPrototypeInfo()) return false;
12476 : // If it had no prototype before, see if it had users that might expect
12477 : // registration.
12478 642464 : if (!user->prototype()->IsJSObject()) {
12479 : Object* users =
12480 : PrototypeInfo::cast(user->prototype_info())->prototype_users();
12481 76680 : return users->IsWeakFixedArray();
12482 : }
12483 : Handle<JSObject> prototype(JSObject::cast(user->prototype()), isolate);
12484 : Handle<PrototypeInfo> user_info =
12485 565784 : Map::GetOrCreatePrototypeInfo(user, isolate);
12486 : int slot = user_info->registry_slot();
12487 565784 : if (slot == PrototypeInfo::UNREGISTERED) return false;
12488 : DCHECK(prototype->map()->is_prototype_map());
12489 : Object* maybe_proto_info = prototype->map()->prototype_info();
12490 : // User knows its registry slot, prototype info and user registry must exist.
12491 : DCHECK(maybe_proto_info->IsPrototypeInfo());
12492 : Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info),
12493 : isolate);
12494 : Object* maybe_registry = proto_info->prototype_users();
12495 : DCHECK(maybe_registry->IsWeakFixedArray());
12496 : DCHECK(WeakFixedArray::cast(maybe_registry)->Get(slot) == *user);
12497 : WeakFixedArray::cast(maybe_registry)->Clear(slot);
12498 81624 : if (FLAG_trace_prototype_users) {
12499 : PrintF("Unregistering %p as a user of prototype %p.\n",
12500 0 : reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype));
12501 : }
12502 : return true;
12503 : }
12504 :
12505 :
12506 3972722 : static void InvalidatePrototypeChainsInternal(Map* map) {
12507 : DCHECK(map->is_prototype_map());
12508 3972722 : if (FLAG_trace_prototype_users) {
12509 : PrintF("Invalidating prototype map %p 's cell\n",
12510 0 : reinterpret_cast<void*>(map));
12511 : }
12512 : Object* maybe_proto_info = map->prototype_info();
12513 7219221 : if (!maybe_proto_info->IsPrototypeInfo()) return;
12514 : PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info);
12515 : Object* maybe_cell = proto_info->validity_cell();
12516 726223 : if (maybe_cell->IsCell()) {
12517 : // Just set the value; the cell will be replaced lazily.
12518 : Cell* cell = Cell::cast(maybe_cell);
12519 151839 : cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid));
12520 : }
12521 :
12522 : WeakFixedArray::Iterator iterator(proto_info->prototype_users());
12523 : // For now, only maps register themselves as users.
12524 : Map* user;
12525 808985 : while ((user = iterator.Next<Map>()) != nullptr) {
12526 : // Walk the prototype chain (backwards, towards leaf objects) if necessary.
12527 82762 : InvalidatePrototypeChainsInternal(user);
12528 : }
12529 : }
12530 :
12531 :
12532 : // static
12533 0 : void JSObject::InvalidatePrototypeChains(Map* map) {
12534 : DisallowHeapAllocation no_gc;
12535 3889960 : InvalidatePrototypeChainsInternal(map);
12536 0 : }
12537 :
12538 :
12539 : // static
12540 2088105 : Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<JSObject> prototype,
12541 : Isolate* isolate) {
12542 : Object* maybe_proto_info = prototype->map()->prototype_info();
12543 2088105 : if (maybe_proto_info->IsPrototypeInfo()) {
12544 : return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
12545 : }
12546 128319 : Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
12547 128319 : prototype->map()->set_prototype_info(*proto_info);
12548 128319 : return proto_info;
12549 : }
12550 :
12551 :
12552 : // static
12553 2292811 : Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<Map> prototype_map,
12554 : Isolate* isolate) {
12555 : Object* maybe_proto_info = prototype_map->prototype_info();
12556 2292811 : if (maybe_proto_info->IsPrototypeInfo()) {
12557 : return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
12558 : }
12559 313577 : Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
12560 313577 : prototype_map->set_prototype_info(*proto_info);
12561 313577 : return proto_info;
12562 : }
12563 :
12564 : // static
12565 497744 : void Map::SetShouldBeFastPrototypeMap(Handle<Map> map, bool value,
12566 : Isolate* isolate) {
12567 497744 : if (value == false && !map->prototype_info()->IsPrototypeInfo()) {
12568 : // "False" is the implicit default value, so there's nothing to do.
12569 497744 : return;
12570 : }
12571 995488 : GetOrCreatePrototypeInfo(map, isolate)->set_should_be_fast_map(value);
12572 : }
12573 :
12574 : // static
12575 1094435 : Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
12576 : Isolate* isolate) {
12577 : Handle<Object> maybe_prototype;
12578 1094435 : if (map->IsJSGlobalObjectMap()) {
12579 : DCHECK(map->is_prototype_map());
12580 : // Global object is prototype of a global proxy and therefore we can
12581 : // use its validity cell for guarding global object's prototype change.
12582 2068 : maybe_prototype = isolate->global_object();
12583 : } else {
12584 : maybe_prototype =
12585 1092367 : handle(map->GetPrototypeChainRootMap(isolate)->prototype(), isolate);
12586 1092367 : if (!maybe_prototype->IsJSReceiver()) return Handle<Cell>::null();
12587 : }
12588 1075735 : if (maybe_prototype->IsJSProxy()) {
12589 : Handle<Cell> cell = isolate->factory()->NewCell(
12590 1251 : handle(Smi::FromInt(Map::kPrototypeChainValid), isolate));
12591 1251 : return cell;
12592 : }
12593 : Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype);
12594 : // Ensure the prototype is registered with its own prototypes so its cell
12595 : // will be invalidated when necessary.
12596 : JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate),
12597 1074484 : isolate);
12598 : Handle<PrototypeInfo> proto_info =
12599 1074483 : GetOrCreatePrototypeInfo(prototype, isolate);
12600 : Object* maybe_cell = proto_info->validity_cell();
12601 : // Return existing cell if it's still valid.
12602 1074483 : if (maybe_cell->IsCell()) {
12603 : Handle<Cell> cell(Cell::cast(maybe_cell), isolate);
12604 811922 : if (cell->value() == Smi::FromInt(Map::kPrototypeChainValid)) {
12605 795028 : return cell;
12606 : }
12607 : }
12608 : // Otherwise create a new cell.
12609 : Handle<Cell> cell = isolate->factory()->NewCell(
12610 279456 : handle(Smi::FromInt(Map::kPrototypeChainValid), isolate));
12611 279456 : proto_info->set_validity_cell(*cell);
12612 279456 : return cell;
12613 : }
12614 :
12615 : // static
12616 518483 : Handle<WeakCell> Map::GetOrCreatePrototypeWeakCell(Handle<JSReceiver> prototype,
12617 : Isolate* isolate) {
12618 : DCHECK(!prototype.is_null());
12619 518483 : if (prototype->IsJSProxy()) {
12620 1170 : Handle<WeakCell> cell = isolate->factory()->NewWeakCell(prototype);
12621 1170 : return cell;
12622 : }
12623 :
12624 : Handle<PrototypeInfo> proto_info =
12625 517313 : GetOrCreatePrototypeInfo(Handle<JSObject>::cast(prototype), isolate);
12626 : Object* maybe_cell = proto_info->weak_cell();
12627 : // Return existing cell if it's already created.
12628 517313 : if (maybe_cell->IsWeakCell()) {
12629 : Handle<WeakCell> cell(WeakCell::cast(maybe_cell), isolate);
12630 : DCHECK(!cell->cleared());
12631 441592 : return cell;
12632 : }
12633 : // Otherwise create a new cell.
12634 75721 : Handle<WeakCell> cell = isolate->factory()->NewWeakCell(prototype);
12635 75721 : proto_info->set_weak_cell(*cell);
12636 75721 : return cell;
12637 : }
12638 :
12639 : // static
12640 26621864 : void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype) {
12641 : RuntimeCallTimerScope stats_scope(*map, &RuntimeCallStats::Map_SetPrototype);
12642 :
12643 : bool is_hidden = false;
12644 26621867 : if (prototype->IsJSObject()) {
12645 : Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype);
12646 22156873 : JSObject::OptimizeAsPrototype(prototype_jsobj);
12647 :
12648 22156867 : Object* maybe_constructor = prototype_jsobj->map()->GetConstructor();
12649 22156865 : if (maybe_constructor->IsJSFunction()) {
12650 : JSFunction* constructor = JSFunction::cast(maybe_constructor);
12651 : Object* data = constructor->shared()->function_data();
12652 204764 : is_hidden = (data->IsFunctionTemplateInfo() &&
12653 42808539 : FunctionTemplateInfo::cast(data)->hidden_prototype()) ||
12654 : prototype->IsJSGlobalObject();
12655 752456 : } else if (maybe_constructor->IsFunctionTemplateInfo()) {
12656 : is_hidden =
12657 42 : FunctionTemplateInfo::cast(maybe_constructor)->hidden_prototype() ||
12658 : prototype->IsJSGlobalObject();
12659 : }
12660 : }
12661 : map->set_has_hidden_prototype(is_hidden);
12662 :
12663 : WriteBarrierMode wb_mode = prototype->IsNull(map->GetIsolate())
12664 : ? SKIP_WRITE_BARRIER
12665 26621860 : : UPDATE_WRITE_BARRIER;
12666 26621860 : map->set_prototype(*prototype, wb_mode);
12667 26621864 : }
12668 :
12669 :
12670 122 : Handle<Object> CacheInitialJSArrayMaps(
12671 : Handle<Context> native_context, Handle<Map> initial_map) {
12672 : // Replace all of the cached initial array maps in the native context with
12673 : // the appropriate transitioned elements kind maps.
12674 122 : Handle<Map> current_map = initial_map;
12675 : ElementsKind kind = current_map->elements_kind();
12676 : DCHECK_EQ(GetInitialFastElementsKind(), kind);
12677 122 : native_context->set(Context::ArrayMapIndex(kind), *current_map);
12678 732 : for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1;
12679 : i < kFastElementsKindCount; ++i) {
12680 : Handle<Map> new_map;
12681 610 : ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
12682 610 : if (Map* maybe_elements_transition = current_map->ElementsTransitionMap()) {
12683 : new_map = handle(maybe_elements_transition);
12684 : } else {
12685 : new_map = Map::CopyAsElementsKind(
12686 610 : current_map, next_kind, INSERT_TRANSITION);
12687 : }
12688 : DCHECK_EQ(next_kind, new_map->elements_kind());
12689 610 : native_context->set(Context::ArrayMapIndex(next_kind), *new_map);
12690 : current_map = new_map;
12691 : }
12692 122 : return initial_map;
12693 : }
12694 :
12695 : namespace {
12696 :
12697 589666 : void SetInstancePrototype(Isolate* isolate, Handle<JSFunction> function,
12698 : Handle<JSReceiver> value) {
12699 : // Now some logic for the maps of the objects that are created by using this
12700 : // function as a constructor.
12701 589666 : if (function->has_initial_map()) {
12702 : // If the function has allocated the initial map replace it with a
12703 : // copy containing the new prototype. Also complete any in-object
12704 : // slack tracking that is in progress at this point because it is
12705 : // still tracking the old copy.
12706 28069 : function->CompleteInobjectSlackTrackingIfActive();
12707 :
12708 : Handle<Map> initial_map(function->initial_map(), isolate);
12709 :
12710 55205 : if (!initial_map->GetIsolate()->bootstrapper()->IsActive() &&
12711 : initial_map->instance_type() == JS_OBJECT_TYPE) {
12712 : // Put the value in the initial map field until an initial map is needed.
12713 : // At that point, a new initial map is created and the prototype is put
12714 : // into the initial map where it belongs.
12715 26902 : function->set_prototype_or_initial_map(*value);
12716 : } else {
12717 1167 : Handle<Map> new_map = Map::Copy(initial_map, "SetInstancePrototype");
12718 1167 : JSFunction::SetInitialMap(function, new_map, value);
12719 :
12720 : // If the function is used as the global Array function, cache the
12721 : // updated initial maps (and transitioned versions) in the native context.
12722 : Handle<Context> native_context(function->context()->native_context(),
12723 : isolate);
12724 : Handle<Object> array_function(
12725 : native_context->get(Context::ARRAY_FUNCTION_INDEX), isolate);
12726 2273 : if (array_function->IsJSFunction() &&
12727 : *function == JSFunction::cast(*array_function)) {
12728 61 : CacheInitialJSArrayMaps(native_context, new_map);
12729 : }
12730 : }
12731 :
12732 : // Deoptimize all code that embeds the previous initial map.
12733 : initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
12734 28069 : isolate, DependentCode::kInitialMapChangedGroup);
12735 : } else {
12736 : // Put the value in the initial map field until an initial map is
12737 : // needed. At that point, a new initial map is created and the
12738 : // prototype is put into the initial map where it belongs.
12739 561597 : function->set_prototype_or_initial_map(*value);
12740 561597 : if (value->IsJSObject()) {
12741 : // Optimize as prototype to detach it from its transition tree.
12742 561534 : JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value));
12743 : }
12744 : }
12745 589666 : }
12746 :
12747 : } // anonymous namespace
12748 :
12749 589666 : void JSFunction::SetPrototype(Handle<JSFunction> function,
12750 : Handle<Object> value) {
12751 : DCHECK(function->IsConstructor() ||
12752 : IsGeneratorFunction(function->shared()->kind()));
12753 : Isolate* isolate = function->GetIsolate();
12754 : Handle<JSReceiver> construct_prototype;
12755 :
12756 : // If the value is not a JSReceiver, store the value in the map's
12757 : // constructor field so it can be accessed. Also, set the prototype
12758 : // used for constructing objects to the original object prototype.
12759 : // See ECMA-262 13.2.2.
12760 589666 : if (!value->IsJSReceiver()) {
12761 : // Copy the map so this does not affect unrelated functions.
12762 : // Remove map transitions because they point to maps with a
12763 : // different prototype.
12764 4324 : Handle<Map> new_map = Map::Copy(handle(function->map()), "SetPrototype");
12765 :
12766 4324 : JSObject::MigrateToMap(function, new_map);
12767 : new_map->SetConstructor(*value);
12768 : new_map->set_non_instance_prototype(true);
12769 :
12770 : FunctionKind kind = function->shared()->kind();
12771 : Handle<Context> native_context(function->context()->native_context());
12772 :
12773 : construct_prototype = Handle<JSReceiver>(
12774 : IsGeneratorFunction(kind)
12775 : ? IsAsyncFunction(kind)
12776 : ? native_context->initial_async_generator_prototype()
12777 : : native_context->initial_generator_prototype()
12778 : : native_context->initial_object_prototype(),
12779 8666 : isolate);
12780 : } else {
12781 585342 : construct_prototype = Handle<JSReceiver>::cast(value);
12782 : function->map()->set_non_instance_prototype(false);
12783 : }
12784 :
12785 589666 : SetInstancePrototype(isolate, function, construct_prototype);
12786 589666 : }
12787 :
12788 :
12789 3823516 : void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
12790 : Handle<Object> prototype) {
12791 3823516 : if (map->prototype() != *prototype) Map::SetPrototype(map, prototype);
12792 3823515 : function->set_prototype_or_initial_map(*map);
12793 : map->SetConstructor(*function);
12794 : #if V8_TRACE_MAPS
12795 : if (FLAG_trace_maps) {
12796 : PrintF("[TraceMaps: InitialMap map= %p SFI= %d_%s ]\n",
12797 : reinterpret_cast<void*>(*map), function->shared()->unique_id(),
12798 : function->shared()->DebugName()->ToCString().get());
12799 : }
12800 : #endif
12801 3823515 : }
12802 :
12803 :
12804 : #ifdef DEBUG
12805 : namespace {
12806 :
12807 : bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
12808 : switch (instance_type) {
12809 : case JS_API_OBJECT_TYPE:
12810 : case JS_ARRAY_BUFFER_TYPE:
12811 : case JS_ARRAY_TYPE:
12812 : case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
12813 : case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
12814 : case JS_DATA_VIEW_TYPE:
12815 : case JS_DATE_TYPE:
12816 : case JS_FUNCTION_TYPE:
12817 : case JS_GENERATOR_OBJECT_TYPE:
12818 : case JS_ASYNC_GENERATOR_OBJECT_TYPE:
12819 : case JS_MAP_TYPE:
12820 : case JS_MESSAGE_OBJECT_TYPE:
12821 : case JS_OBJECT_TYPE:
12822 : case JS_ERROR_TYPE:
12823 : case JS_ARGUMENTS_TYPE:
12824 : case JS_PROMISE_TYPE:
12825 : case JS_REGEXP_TYPE:
12826 : case JS_SET_TYPE:
12827 : case JS_SPECIAL_API_OBJECT_TYPE:
12828 : case JS_TYPED_ARRAY_TYPE:
12829 : case JS_VALUE_TYPE:
12830 : case JS_WEAK_MAP_TYPE:
12831 : case JS_WEAK_SET_TYPE:
12832 : return true;
12833 :
12834 : case BIGINT_TYPE:
12835 : case BYTECODE_ARRAY_TYPE:
12836 : case BYTE_ARRAY_TYPE:
12837 : case CELL_TYPE:
12838 : case CODE_TYPE:
12839 : case FILLER_TYPE:
12840 : case FIXED_ARRAY_TYPE:
12841 : case FIXED_DOUBLE_ARRAY_TYPE:
12842 : case FOREIGN_TYPE:
12843 : case FREE_SPACE_TYPE:
12844 : case HASH_TABLE_TYPE:
12845 : case HEAP_NUMBER_TYPE:
12846 : case JS_BOUND_FUNCTION_TYPE:
12847 : case JS_GLOBAL_OBJECT_TYPE:
12848 : case JS_GLOBAL_PROXY_TYPE:
12849 : case JS_PROXY_TYPE:
12850 : case MAP_TYPE:
12851 : case MUTABLE_HEAP_NUMBER_TYPE:
12852 : case ODDBALL_TYPE:
12853 : case PROPERTY_CELL_TYPE:
12854 : case SHARED_FUNCTION_INFO_TYPE:
12855 : case SYMBOL_TYPE:
12856 : case WEAK_CELL_TYPE:
12857 :
12858 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
12859 : case FIXED_##TYPE##_ARRAY_TYPE:
12860 : #undef TYPED_ARRAY_CASE
12861 :
12862 : #define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE:
12863 : STRUCT_LIST(MAKE_STRUCT_CASE)
12864 : #undef MAKE_STRUCT_CASE
12865 : // We must not end up here for these instance types at all.
12866 : UNREACHABLE();
12867 : // Fall through.
12868 : default:
12869 : return false;
12870 : }
12871 : }
12872 :
12873 : } // namespace
12874 : #endif
12875 :
12876 :
12877 14596365 : void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
12878 : DCHECK(function->has_prototype_slot());
12879 : DCHECK(function->IsConstructor() ||
12880 : IsResumableFunction(function->shared()->kind()));
12881 28867807 : if (function->has_initial_map()) return;
12882 : Isolate* isolate = function->GetIsolate();
12883 :
12884 : // First create a new map with the size and number of in-object properties
12885 : // suggested by the function.
12886 : InstanceType instance_type;
12887 324925 : if (IsResumableFunction(function->shared()->kind())) {
12888 : instance_type = IsAsyncGeneratorFunction(function->shared()->kind())
12889 : ? JS_ASYNC_GENERATOR_OBJECT_TYPE
12890 12374 : : JS_GENERATOR_OBJECT_TYPE;
12891 : } else {
12892 : instance_type = JS_OBJECT_TYPE;
12893 : }
12894 :
12895 : // The constructor should be compiled for the optimization hints to be
12896 : // available.
12897 : int expected_nof_properties = 0;
12898 365703 : if (function->shared()->is_compiled() ||
12899 40778 : Compiler::Compile(function, Compiler::CLEAR_EXCEPTION)) {
12900 : DCHECK(function->shared()->is_compiled());
12901 : expected_nof_properties = function->shared()->expected_nof_properties();
12902 : }
12903 :
12904 : int instance_size;
12905 : int inobject_properties;
12906 : CalculateInstanceSizeHelper(instance_type, false, 0, expected_nof_properties,
12907 324925 : &instance_size, &inobject_properties);
12908 :
12909 : Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size,
12910 : TERMINAL_FAST_ELEMENTS_KIND,
12911 324925 : inobject_properties);
12912 :
12913 : // Fetch or allocate prototype.
12914 : Handle<Object> prototype;
12915 324925 : if (function->has_instance_prototype()) {
12916 259799 : prototype = handle(function->instance_prototype(), isolate);
12917 : } else {
12918 65126 : prototype = isolate->factory()->NewFunctionPrototype(function);
12919 : }
12920 : DCHECK(map->has_fast_object_elements());
12921 :
12922 : // Finally link initial map and constructor function.
12923 : DCHECK(prototype->IsJSReceiver());
12924 324925 : JSFunction::SetInitialMap(function, map, prototype);
12925 : map->StartInobjectSlackTracking();
12926 : }
12927 :
12928 :
12929 : // static
12930 2639599 : MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
12931 : Handle<JSFunction> constructor,
12932 : Handle<JSReceiver> new_target) {
12933 2639599 : EnsureHasInitialMap(constructor);
12934 :
12935 : Handle<Map> constructor_initial_map(constructor->initial_map(), isolate);
12936 2639599 : if (*new_target == *constructor) return constructor_initial_map;
12937 :
12938 : // Fast case, new.target is a subclass of constructor. The map is cacheable
12939 : // (and may already have been cached). new.target.prototype is guaranteed to
12940 : // be a JSReceiver.
12941 99787 : if (new_target->IsJSFunction()) {
12942 : Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
12943 :
12944 : // Check that |function|'s initial map still in sync with the |constructor|,
12945 : // otherwise we must create a new initial map for |function|.
12946 185858 : if (function->has_initial_map() &&
12947 88667 : function->initial_map()->GetConstructor() == *constructor) {
12948 88538 : return handle(function->initial_map(), isolate);
12949 : }
12950 :
12951 : // Create a new map with the size and number of in-object properties
12952 : // suggested by |function|.
12953 :
12954 : // Link initial map and constructor function if the new.target is actually a
12955 : // subclass constructor.
12956 8653 : if (IsDerivedConstructor(function->shared()->kind())) {
12957 : Handle<Object> prototype(function->instance_prototype(), isolate);
12958 : InstanceType instance_type = constructor_initial_map->instance_type();
12959 : DCHECK(CanSubclassHaveInobjectProperties(instance_type));
12960 : int embedder_fields =
12961 7160 : JSObject::GetEmbedderFieldCount(*constructor_initial_map);
12962 : int pre_allocated = constructor_initial_map->GetInObjectProperties() -
12963 7160 : constructor_initial_map->UnusedPropertyFields();
12964 : int instance_size;
12965 : int in_object_properties;
12966 : CalculateInstanceSizeForDerivedClass(function, instance_type,
12967 : embedder_fields, &instance_size,
12968 7160 : &in_object_properties);
12969 :
12970 7160 : int unused_property_fields = in_object_properties - pre_allocated;
12971 : Handle<Map> map =
12972 : Map::CopyInitialMap(constructor_initial_map, instance_size,
12973 7160 : in_object_properties, unused_property_fields);
12974 : map->set_new_target_is_base(false);
12975 :
12976 7160 : JSFunction::SetInitialMap(function, map, prototype);
12977 : map->SetConstructor(*constructor);
12978 : map->set_construction_counter(Map::kNoSlackTracking);
12979 : map->StartInobjectSlackTracking();
12980 7160 : return map;
12981 : }
12982 : }
12983 :
12984 : // Slow path, new.target is either a proxy or can't cache the map.
12985 : // new.target.prototype is not guaranteed to be a JSReceiver, and may need to
12986 : // fall back to the intrinsicDefaultProto.
12987 : Handle<Object> prototype;
12988 4089 : if (new_target->IsJSFunction()) {
12989 : Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
12990 : // Make sure the new.target.prototype is cached.
12991 1493 : EnsureHasInitialMap(function);
12992 1493 : prototype = handle(function->prototype(), isolate);
12993 : } else {
12994 : Handle<String> prototype_string = isolate->factory()->prototype_string();
12995 5192 : ASSIGN_RETURN_ON_EXCEPTION(
12996 : isolate, prototype,
12997 : JSReceiver::GetProperty(new_target, prototype_string), Map);
12998 : // The above prototype lookup might change the constructor and its
12999 : // prototype, hence we have to reload the initial map.
13000 2536 : EnsureHasInitialMap(constructor);
13001 : constructor_initial_map = handle(constructor->initial_map(), isolate);
13002 : }
13003 :
13004 : // If prototype is not a JSReceiver, fetch the intrinsicDefaultProto from the
13005 : // correct realm. Rather than directly fetching the .prototype, we fetch the
13006 : // constructor that points to the .prototype. This relies on
13007 : // constructor.prototype being FROZEN for those constructors.
13008 4029 : if (!prototype->IsJSReceiver()) {
13009 : Handle<Context> context;
13010 2558 : ASSIGN_RETURN_ON_EXCEPTION(isolate, context,
13011 : JSReceiver::GetFunctionRealm(new_target), Map);
13012 : DCHECK(context->IsNativeContext());
13013 : Handle<Object> maybe_index = JSReceiver::GetDataProperty(
13014 1279 : constructor, isolate->factory()->native_context_index_symbol());
13015 : int index = maybe_index->IsSmi() ? Smi::ToInt(*maybe_index)
13016 1279 : : Context::OBJECT_FUNCTION_INDEX;
13017 : Handle<JSFunction> realm_constructor(JSFunction::cast(context->get(index)));
13018 1279 : prototype = handle(realm_constructor->prototype(), isolate);
13019 : }
13020 :
13021 4029 : Handle<Map> map = Map::CopyInitialMap(constructor_initial_map);
13022 : map->set_new_target_is_base(false);
13023 : DCHECK(prototype->IsJSReceiver());
13024 4029 : if (map->prototype() != *prototype) Map::SetPrototype(map, prototype);
13025 : map->SetConstructor(*constructor);
13026 4029 : return map;
13027 : }
13028 :
13029 :
13030 0 : void JSFunction::PrintName(FILE* out) {
13031 0 : std::unique_ptr<char[]> name = shared()->DebugName()->ToCString();
13032 0 : PrintF(out, "%s", name.get());
13033 0 : }
13034 :
13035 :
13036 453615 : Handle<String> JSFunction::GetName(Handle<JSFunction> function) {
13037 : Isolate* isolate = function->GetIsolate();
13038 : Handle<Object> name =
13039 453615 : JSReceiver::GetDataProperty(function, isolate->factory()->name_string());
13040 453615 : if (name->IsString()) return Handle<String>::cast(name);
13041 452894 : return handle(function->shared()->DebugName(), isolate);
13042 : }
13043 :
13044 :
13045 352788 : Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) {
13046 : Isolate* isolate = function->GetIsolate();
13047 : Handle<Object> name = JSReceiver::GetDataProperty(
13048 352788 : function, isolate->factory()->display_name_string());
13049 352788 : if (name->IsString()) return Handle<String>::cast(name);
13050 352749 : return JSFunction::GetName(function);
13051 : }
13052 :
13053 10755 : bool JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name,
13054 : Handle<String> prefix) {
13055 : Isolate* isolate = function->GetIsolate();
13056 : Handle<String> function_name;
13057 21510 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, function_name,
13058 : Name::ToFunctionName(name), false);
13059 10745 : if (prefix->length() > 0) {
13060 2461 : IncrementalStringBuilder builder(isolate);
13061 2461 : builder.AppendString(prefix);
13062 : builder.AppendCharacter(' ');
13063 2461 : builder.AppendString(function_name);
13064 4922 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, function_name, builder.Finish(),
13065 : false);
13066 : }
13067 21450 : RETURN_ON_EXCEPTION_VALUE(
13068 : isolate,
13069 : JSObject::DefinePropertyOrElementIgnoreAttributes(
13070 : function, isolate->factory()->name_string(), function_name,
13071 : static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY)),
13072 : false);
13073 10725 : return true;
13074 : }
13075 :
13076 : namespace {
13077 :
13078 : char const kNativeCodeSource[] = "function () { [native code] }";
13079 :
13080 :
13081 1023200 : Handle<String> NativeCodeFunctionSourceString(
13082 : Handle<SharedFunctionInfo> shared_info) {
13083 : Isolate* const isolate = shared_info->GetIsolate();
13084 1023200 : IncrementalStringBuilder builder(isolate);
13085 : builder.AppendCString("function ");
13086 1023200 : builder.AppendString(handle(shared_info->name(), isolate));
13087 : builder.AppendCString("() { [native code] }");
13088 2046400 : return builder.Finish().ToHandleChecked();
13089 : }
13090 :
13091 : } // namespace
13092 :
13093 :
13094 : // static
13095 55 : Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) {
13096 : Isolate* const isolate = function->GetIsolate();
13097 55 : return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource);
13098 : }
13099 :
13100 :
13101 : // static
13102 1767950 : Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
13103 : Isolate* const isolate = function->GetIsolate();
13104 : Handle<SharedFunctionInfo> shared_info(function->shared(), isolate);
13105 :
13106 : // Check if {function} should hide its source code.
13107 1767950 : if (!shared_info->IsUserJavaScript()) {
13108 1023200 : return NativeCodeFunctionSourceString(shared_info);
13109 : }
13110 :
13111 : // Check if we should print {function} as a class.
13112 : Handle<Object> class_start_position = JSReceiver::GetDataProperty(
13113 744750 : function, isolate->factory()->class_start_position_symbol());
13114 744750 : if (class_start_position->IsSmi()) {
13115 : Handle<Object> class_end_position = JSReceiver::GetDataProperty(
13116 21565 : function, isolate->factory()->class_end_position_symbol());
13117 : Handle<String> script_source(
13118 : String::cast(Script::cast(shared_info->script())->source()), isolate);
13119 : return isolate->factory()->NewSubString(
13120 : script_source, Handle<Smi>::cast(class_start_position)->value(),
13121 21565 : Handle<Smi>::cast(class_end_position)->value());
13122 : }
13123 :
13124 : // Check if we have source code for the {function}.
13125 723185 : if (!shared_info->HasSourceCode()) {
13126 0 : return NativeCodeFunctionSourceString(shared_info);
13127 : }
13128 :
13129 723185 : if (FLAG_harmony_function_tostring) {
13130 813 : return Handle<String>::cast(shared_info->GetSourceCodeHarmony());
13131 : }
13132 :
13133 722372 : IncrementalStringBuilder builder(isolate);
13134 : FunctionKind kind = shared_info->kind();
13135 722372 : if (!IsArrowFunction(kind)) {
13136 683271 : if (IsConciseMethod(kind)) {
13137 63 : if (IsAsyncGeneratorFunction(kind)) {
13138 : builder.AppendCString("async *");
13139 36 : } else if (IsGeneratorFunction(kind)) {
13140 : builder.AppendCharacter('*');
13141 27 : } else if (IsAsyncFunction(kind)) {
13142 : builder.AppendCString("async ");
13143 : }
13144 : } else {
13145 683208 : if (IsAsyncGeneratorFunction(kind)) {
13146 : builder.AppendCString("async function* ");
13147 683163 : } else if (IsGeneratorFunction(kind)) {
13148 : builder.AppendCString("function* ");
13149 683028 : } else if (IsAsyncFunction(kind)) {
13150 : builder.AppendCString("async function ");
13151 : } else {
13152 : builder.AppendCString("function ");
13153 : }
13154 : }
13155 683271 : if (shared_info->name_should_print_as_anonymous()) {
13156 : builder.AppendCString("anonymous");
13157 682909 : } else if (!shared_info->is_anonymous_expression()) {
13158 616810 : builder.AppendString(handle(shared_info->name(), isolate));
13159 : }
13160 : }
13161 722372 : builder.AppendString(Handle<String>::cast(shared_info->GetSourceCode()));
13162 1444744 : return builder.Finish().ToHandleChecked();
13163 : }
13164 :
13165 341 : void Oddball::Initialize(Isolate* isolate, Handle<Oddball> oddball,
13166 : const char* to_string, Handle<Object> to_number,
13167 : const char* type_of, byte kind) {
13168 : Handle<String> internalized_to_string =
13169 341 : isolate->factory()->InternalizeUtf8String(to_string);
13170 : Handle<String> internalized_type_of =
13171 341 : isolate->factory()->InternalizeUtf8String(type_of);
13172 341 : if (to_number->IsHeapNumber()) {
13173 : oddball->set_to_number_raw_as_bits(
13174 : Handle<HeapNumber>::cast(to_number)->value_as_bits());
13175 : } else {
13176 : oddball->set_to_number_raw(to_number->Number());
13177 : }
13178 341 : oddball->set_to_number(*to_number);
13179 341 : oddball->set_to_string(*internalized_to_string);
13180 341 : oddball->set_type_of(*internalized_type_of);
13181 : oddball->set_kind(kind);
13182 341 : }
13183 :
13184 2168 : int Script::GetEvalPosition() {
13185 : DisallowHeapAllocation no_gc;
13186 : DCHECK(compilation_type() == Script::COMPILATION_TYPE_EVAL);
13187 : int position = eval_from_position();
13188 2168 : if (position < 0) {
13189 : // Due to laziness, the position may not have been translated from code
13190 : // offset yet, which would be encoded as negative integer. In that case,
13191 : // translate and set the position.
13192 791 : if (eval_from_shared()->IsUndefined(GetIsolate())) {
13193 : position = 0;
13194 : } else {
13195 : SharedFunctionInfo* shared = SharedFunctionInfo::cast(eval_from_shared());
13196 1582 : position = shared->abstract_code()->SourcePosition(-position);
13197 : }
13198 : DCHECK_GE(position, 0);
13199 : set_eval_from_position(position);
13200 : }
13201 2168 : return position;
13202 : }
13203 :
13204 1142656 : void Script::InitLineEnds(Handle<Script> script) {
13205 : Isolate* isolate = script->GetIsolate();
13206 2285312 : if (!script->line_ends()->IsUndefined(isolate)) return;
13207 : DCHECK_NE(Script::TYPE_WASM, script->type());
13208 :
13209 : Object* src_obj = script->source();
13210 44462 : if (!src_obj->IsString()) {
13211 : DCHECK(src_obj->IsUndefined(isolate));
13212 12 : script->set_line_ends(isolate->heap()->empty_fixed_array());
13213 : } else {
13214 : DCHECK(src_obj->IsString());
13215 : Handle<String> src(String::cast(src_obj), isolate);
13216 44456 : Handle<FixedArray> array = String::CalculateLineEnds(src, true);
13217 44456 : script->set_line_ends(*array);
13218 : }
13219 :
13220 : DCHECK(script->line_ends()->IsFixedArray());
13221 : }
13222 :
13223 957936 : bool Script::GetPositionInfo(Handle<Script> script, int position,
13224 : PositionInfo* info, OffsetFlag offset_flag) {
13225 : // For wasm, we do not create an artificial line_ends array, but do the
13226 : // translation directly.
13227 957936 : if (script->type() != Script::TYPE_WASM) InitLineEnds(script);
13228 957936 : return script->GetPositionInfo(position, info, offset_flag);
13229 : }
13230 :
13231 17924358 : bool Script::IsUserJavaScript() { return type() == Script::TYPE_NORMAL; }
13232 :
13233 : namespace {
13234 1184 : bool GetPositionInfoSlow(const Script* script, int position,
13235 : Script::PositionInfo* info) {
13236 1184 : if (!script->source()->IsString()) return false;
13237 1184 : if (position < 0) position = 0;
13238 :
13239 : String* source_string = String::cast(script->source());
13240 : int line = 0;
13241 : int line_start = 0;
13242 : int len = source_string->length();
13243 363503 : for (int pos = 0; pos <= len; ++pos) {
13244 726946 : if (pos == len || source_string->Get(pos) == '\n') {
13245 14912 : if (position <= pos) {
13246 1174 : info->line = line;
13247 1174 : info->column = position - line_start;
13248 1174 : info->line_start = line_start;
13249 1174 : info->line_end = pos;
13250 1174 : return true;
13251 : }
13252 13738 : line++;
13253 13738 : line_start = pos + 1;
13254 : }
13255 : }
13256 : return false;
13257 : }
13258 : } // namespace
13259 :
13260 : #define SMI_VALUE(x) (Smi::ToInt(x))
13261 973603 : bool Script::GetPositionInfo(int position, PositionInfo* info,
13262 : OffsetFlag offset_flag) const {
13263 : DisallowHeapAllocation no_allocation;
13264 :
13265 : // For wasm, we do not rely on the line_ends array, but do the translation
13266 : // directly.
13267 973603 : if (type() == Script::TYPE_WASM) {
13268 : Handle<WasmCompiledModule> compiled_module(
13269 : WasmCompiledModule::cast(wasm_compiled_module()));
13270 : DCHECK_LE(0, position);
13271 : return compiled_module->GetPositionInfo(static_cast<uint32_t>(position),
13272 976 : info);
13273 : }
13274 :
13275 973115 : if (line_ends()->IsUndefined(GetIsolate())) {
13276 : // Slow mode: we do not have line_ends. We have to iterate through source.
13277 1184 : if (!GetPositionInfoSlow(this, position, info)) return false;
13278 : } else {
13279 : DCHECK(line_ends()->IsFixedArray());
13280 : FixedArray* ends = FixedArray::cast(line_ends());
13281 :
13282 : const int ends_len = ends->length();
13283 971931 : if (ends_len == 0) return false;
13284 :
13285 : // Return early on invalid positions. Negative positions behave as if 0 was
13286 : // passed, and positions beyond the end of the script return as failure.
13287 971913 : if (position < 0) {
13288 : position = 0;
13289 1942776 : } else if (position > SMI_VALUE(ends->get(ends_len - 1))) {
13290 : return false;
13291 : }
13292 :
13293 : // Determine line number by doing a binary search on the line ends array.
13294 971894 : if (SMI_VALUE(ends->get(0)) >= position) {
13295 187945 : info->line = 0;
13296 187945 : info->line_start = 0;
13297 187945 : info->column = position;
13298 : } else {
13299 : int left = 0;
13300 783949 : int right = ends_len - 1;
13301 :
13302 5378515 : while (right > 0) {
13303 : DCHECK_LE(left, right);
13304 4594566 : const int mid = (left + right) / 2;
13305 4594566 : if (position > SMI_VALUE(ends->get(mid))) {
13306 2331369 : left = mid + 1;
13307 4526394 : } else if (position <= SMI_VALUE(ends->get(mid - 1))) {
13308 : right = mid - 1;
13309 : } else {
13310 783949 : info->line = mid;
13311 783949 : break;
13312 : }
13313 : }
13314 : DCHECK(SMI_VALUE(ends->get(info->line)) >= position &&
13315 : SMI_VALUE(ends->get(info->line - 1)) < position);
13316 1567898 : info->line_start = SMI_VALUE(ends->get(info->line - 1)) + 1;
13317 783949 : info->column = position - info->line_start;
13318 : }
13319 :
13320 : // Line end is position of the linebreak character.
13321 1943788 : info->line_end = SMI_VALUE(ends->get(info->line));
13322 971894 : if (info->line_end > 0) {
13323 : DCHECK(source()->IsString());
13324 : String* src = String::cast(source());
13325 1942510 : if (src->length() >= info->line_end &&
13326 971255 : src->Get(info->line_end - 1) == '\r') {
13327 0 : info->line_end--;
13328 : }
13329 : }
13330 : }
13331 :
13332 : // Add offsets if requested.
13333 973068 : if (offset_flag == WITH_OFFSET) {
13334 838900 : if (info->line == 0) {
13335 165363 : info->column += column_offset();
13336 : }
13337 838900 : info->line += line_offset();
13338 : }
13339 :
13340 : return true;
13341 : }
13342 : #undef SMI_VALUE
13343 :
13344 219212 : int Script::GetColumnNumber(Handle<Script> script, int code_pos) {
13345 : PositionInfo info;
13346 219212 : GetPositionInfo(script, code_pos, &info, WITH_OFFSET);
13347 219212 : return info.column;
13348 : }
13349 :
13350 0 : int Script::GetColumnNumber(int code_pos) const {
13351 : PositionInfo info;
13352 0 : GetPositionInfo(code_pos, &info, WITH_OFFSET);
13353 0 : return info.column;
13354 : }
13355 :
13356 225395 : int Script::GetLineNumber(Handle<Script> script, int code_pos) {
13357 : PositionInfo info;
13358 225395 : GetPositionInfo(script, code_pos, &info, WITH_OFFSET);
13359 225395 : return info.line;
13360 : }
13361 :
13362 15567 : int Script::GetLineNumber(int code_pos) const {
13363 : PositionInfo info;
13364 15567 : GetPositionInfo(code_pos, &info, WITH_OFFSET);
13365 15567 : return info.line;
13366 : }
13367 :
13368 29652 : Object* Script::GetNameOrSourceURL() {
13369 : Isolate* isolate = GetIsolate();
13370 : // Keep in sync with ScriptNameOrSourceURL in messages.js.
13371 31740 : if (!source_url()->IsUndefined(isolate)) return source_url();
13372 27564 : return name();
13373 : }
13374 :
13375 :
13376 1224204 : Handle<JSObject> Script::GetWrapper(Handle<Script> script) {
13377 : Isolate* isolate = script->GetIsolate();
13378 1224204 : if (!script->wrapper()->IsUndefined(isolate)) {
13379 : DCHECK(script->wrapper()->IsWeakCell());
13380 : Handle<WeakCell> cell(WeakCell::cast(script->wrapper()));
13381 844390 : if (!cell->cleared()) {
13382 : // Return a handle for the existing script wrapper from the cache.
13383 : return handle(JSObject::cast(cell->value()));
13384 : }
13385 : // If we found an empty WeakCell, that means the script wrapper was
13386 : // GCed. We are not notified directly of that, so we decrement here
13387 : // so that we at least don't count double for any given script.
13388 6928 : isolate->counters()->script_wrappers()->Decrement();
13389 : }
13390 : // Construct a new script wrapper.
13391 386742 : isolate->counters()->script_wrappers()->Increment();
13392 386742 : Handle<JSFunction> constructor = isolate->script_function();
13393 : Handle<JSValue> result =
13394 386742 : Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
13395 386742 : result->set_value(*script);
13396 386742 : Handle<WeakCell> cell = isolate->factory()->NewWeakCell(result);
13397 386742 : script->set_wrapper(*cell);
13398 386742 : return result;
13399 : }
13400 :
13401 4708095 : MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
13402 4708095 : Isolate* isolate, const FunctionLiteral* fun) {
13403 : DCHECK_NE(fun->function_literal_id(), FunctionLiteral::kIdTypeInvalid);
13404 : DCHECK_LT(fun->function_literal_id(), shared_function_infos()->length());
13405 : Object* shared = shared_function_infos()->get(fun->function_literal_id());
13406 5260430 : if (shared->IsUndefined(isolate) || WeakCell::cast(shared)->cleared()) {
13407 4155760 : return MaybeHandle<SharedFunctionInfo>();
13408 : }
13409 552335 : return handle(SharedFunctionInfo::cast(WeakCell::cast(shared)->value()));
13410 : }
13411 :
13412 133214 : Script::Iterator::Iterator(Isolate* isolate)
13413 266433 : : iterator_(isolate->heap()->script_list()) {}
13414 :
13415 :
13416 2764834 : Script* Script::Iterator::Next() { return iterator_.Next<Script>(); }
13417 :
13418 :
13419 60106 : SharedFunctionInfo::ScriptIterator::ScriptIterator(Handle<Script> script)
13420 : : ScriptIterator(script->GetIsolate(),
13421 60106 : handle(script->shared_function_infos())) {}
13422 :
13423 460 : SharedFunctionInfo::ScriptIterator::ScriptIterator(
13424 : Isolate* isolate, Handle<FixedArray> shared_function_infos)
13425 : : isolate_(isolate),
13426 : shared_function_infos_(shared_function_infos),
13427 60566 : index_(0) {}
13428 :
13429 863188 : SharedFunctionInfo* SharedFunctionInfo::ScriptIterator::Next() {
13430 3266976 : while (index_ < shared_function_infos_->length()) {
13431 1141283 : Object* raw = shared_function_infos_->get(index_++);
13432 3104314 : if (raw->IsUndefined(isolate_) || WeakCell::cast(raw)->cleared()) continue;
13433 802577 : return SharedFunctionInfo::cast(WeakCell::cast(raw)->value());
13434 : }
13435 : return nullptr;
13436 : }
13437 :
13438 55 : void SharedFunctionInfo::ScriptIterator::Reset(Handle<Script> script) {
13439 55 : shared_function_infos_ = handle(script->shared_function_infos());
13440 55 : index_ = 0;
13441 55 : }
13442 :
13443 5 : SharedFunctionInfo::GlobalIterator::GlobalIterator(Isolate* isolate)
13444 : : script_iterator_(isolate),
13445 : noscript_sfi_iterator_(isolate->heap()->noscript_shared_function_infos()),
13446 10 : sfi_iterator_(handle(script_iterator_.Next(), isolate)) {}
13447 :
13448 4070 : SharedFunctionInfo* SharedFunctionInfo::GlobalIterator::Next() {
13449 4070 : SharedFunctionInfo* next = noscript_sfi_iterator_.Next<SharedFunctionInfo>();
13450 4070 : if (next != nullptr) return next;
13451 : for (;;) {
13452 1235 : next = sfi_iterator_.Next();
13453 1235 : if (next != nullptr) return next;
13454 : Script* next_script = script_iterator_.Next();
13455 60 : if (next_script == nullptr) return nullptr;
13456 55 : sfi_iterator_.Reset(handle(next_script));
13457 55 : }
13458 : }
13459 :
13460 5174202 : void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
13461 : Handle<Object> script_object,
13462 : bool reset_preparsed_scope_data) {
13463 : DCHECK_NE(shared->function_literal_id(), FunctionLiteral::kIdTypeInvalid);
13464 10348404 : if (shared->script() == *script_object) return;
13465 : Isolate* isolate = shared->GetIsolate();
13466 :
13467 5174202 : if (reset_preparsed_scope_data) {
13468 7211 : shared->set_preparsed_scope_data(isolate->heap()->null_value());
13469 : }
13470 :
13471 : // Add shared function info to new script's list. If a collection occurs,
13472 : // the shared function info may be temporarily in two lists.
13473 : // This is okay because the gc-time processing of these lists can tolerate
13474 : // duplicates.
13475 5174202 : if (script_object->IsScript()) {
13476 : Handle<Script> script = Handle<Script>::cast(script_object);
13477 : Handle<FixedArray> list = handle(script->shared_function_infos(), isolate);
13478 : #ifdef DEBUG
13479 : DCHECK_LT(shared->function_literal_id(), list->length());
13480 : if (list->get(shared->function_literal_id())->IsWeakCell() &&
13481 : !WeakCell::cast(list->get(shared->function_literal_id()))->cleared()) {
13482 : DCHECK(
13483 : WeakCell::cast(list->get(shared->function_literal_id()))->value() ==
13484 : *shared);
13485 : }
13486 : #endif
13487 5169631 : Handle<WeakCell> cell = isolate->factory()->NewWeakCell(shared);
13488 5169631 : list->set(shared->function_literal_id(), *cell);
13489 : } else {
13490 : Handle<Object> list = isolate->factory()->noscript_shared_function_infos();
13491 :
13492 : #ifdef DEBUG
13493 : if (FLAG_enable_slow_asserts) {
13494 : WeakFixedArray::Iterator iterator(*list);
13495 : SharedFunctionInfo* next;
13496 : while ((next = iterator.Next<SharedFunctionInfo>()) != nullptr) {
13497 : DCHECK_NE(next, *shared);
13498 : }
13499 : }
13500 : #endif // DEBUG
13501 :
13502 4571 : list = WeakFixedArray::Add(list, shared);
13503 :
13504 : isolate->heap()->SetRootNoScriptSharedFunctionInfos(*list);
13505 : }
13506 :
13507 5174202 : if (shared->script()->IsScript()) {
13508 : // Remove shared function info from old script's list.
13509 : Script* old_script = Script::cast(shared->script());
13510 :
13511 : // Due to liveedit, it might happen that the old_script doesn't know
13512 : // about the SharedFunctionInfo, so we have to guard against that.
13513 : Handle<FixedArray> infos(old_script->shared_function_infos(), isolate);
13514 4595 : if (shared->function_literal_id() < infos->length()) {
13515 : Object* raw = old_script->shared_function_infos()->get(
13516 : shared->function_literal_id());
13517 9149 : if (!raw->IsWeakCell() || WeakCell::cast(raw)->value() == *shared) {
13518 : old_script->shared_function_infos()->set(
13519 2168 : shared->function_literal_id(), isolate->heap()->undefined_value());
13520 : }
13521 : }
13522 : } else {
13523 : // Remove shared function info from root array.
13524 5169607 : Object* list = isolate->heap()->noscript_shared_function_infos();
13525 5169607 : CHECK(WeakFixedArray::cast(list)->Remove(shared));
13526 : }
13527 :
13528 : // Finally set new script.
13529 5174202 : shared->set_script(*script_object);
13530 : }
13531 :
13532 1161758 : bool SharedFunctionInfo::HasBreakInfo() const {
13533 1161758 : if (!HasDebugInfo()) return false;
13534 : DebugInfo* info = DebugInfo::cast(debug_info());
13535 308513 : bool has_break_info = info->HasBreakInfo();
13536 : DCHECK_IMPLIES(has_break_info, HasBytecodeArray());
13537 308513 : return has_break_info;
13538 : }
13539 :
13540 244286 : bool SharedFunctionInfo::HasCoverageInfo() const {
13541 244286 : if (!HasDebugInfo()) return false;
13542 : DebugInfo* info = DebugInfo::cast(debug_info());
13543 232585 : bool has_coverage_info = info->HasCoverageInfo();
13544 232585 : return has_coverage_info;
13545 : }
13546 :
13547 224645 : CoverageInfo* SharedFunctionInfo::GetCoverageInfo() const {
13548 : DCHECK(HasCoverageInfo());
13549 224645 : return CoverageInfo::cast(GetDebugInfo()->coverage_info());
13550 : }
13551 :
13552 395533 : DebugInfo* SharedFunctionInfo::GetDebugInfo() const {
13553 : DCHECK(HasDebugInfo());
13554 395533 : return DebugInfo::cast(debug_info());
13555 : }
13556 :
13557 2483201 : int SharedFunctionInfo::debugger_hints() const {
13558 9294185 : if (HasDebugInfo()) return GetDebugInfo()->debugger_hints();
13559 2329219 : return Smi::ToInt(debug_info());
13560 : }
13561 :
13562 7339701 : void SharedFunctionInfo::set_debugger_hints(int value) {
13563 7339701 : if (HasDebugInfo()) {
13564 : GetDebugInfo()->set_debugger_hints(value);
13565 : } else {
13566 7338271 : set_debug_info(Smi::FromInt(value));
13567 : }
13568 7339702 : }
13569 :
13570 1428497 : String* SharedFunctionInfo::DebugName() {
13571 : String* n = name();
13572 1428497 : if (String::cast(n)->length() == 0) return inferred_name();
13573 : return String::cast(n);
13574 : }
13575 :
13576 9732 : bool SharedFunctionInfo::HasNoSideEffect() {
13577 9732 : if (!computed_has_no_side_effect()) {
13578 : DisallowHeapAllocation not_handlified;
13579 : Handle<SharedFunctionInfo> info(this);
13580 8181 : set_has_no_side_effect(DebugEvaluate::FunctionHasNoSideEffect(info));
13581 8181 : set_computed_has_no_side_effect(true);
13582 : }
13583 9732 : return has_no_side_effect();
13584 : }
13585 :
13586 : // The filter is a pattern that matches function names in this way:
13587 : // "*" all; the default
13588 : // "-" all but the top-level function
13589 : // "-name" all but the function "name"
13590 : // "" only the top-level function
13591 : // "name" only the function "name"
13592 : // "name*" only functions starting with "name"
13593 : // "~" none; the tilde is not an identifier
13594 439182 : bool SharedFunctionInfo::PassesFilter(const char* raw_filter) {
13595 439182 : if (*raw_filter == '*') return true;
13596 207 : String* name = DebugName();
13597 : Vector<const char> filter = CStrVector(raw_filter);
13598 207 : if (filter.length() == 0) return name->length() == 0;
13599 207 : if (filter[0] == '-') {
13600 : // Negative filter.
13601 0 : if (filter.length() == 1) {
13602 0 : return (name->length() != 0);
13603 0 : } else if (name->IsUtf8EqualTo(filter.SubVector(1, filter.length()))) {
13604 : return false;
13605 : }
13606 0 : if (filter[filter.length() - 1] == '*' &&
13607 0 : name->IsUtf8EqualTo(filter.SubVector(1, filter.length() - 1), true)) {
13608 : return false;
13609 : }
13610 0 : return true;
13611 :
13612 207 : } else if (name->IsUtf8EqualTo(filter)) {
13613 : return true;
13614 : }
13615 284 : if (filter[filter.length() - 1] == '*' &&
13616 28 : name->IsUtf8EqualTo(filter.SubVector(0, filter.length() - 1), true)) {
13617 : return true;
13618 : }
13619 110 : return false;
13620 : }
13621 :
13622 6726046 : bool SharedFunctionInfo::HasSourceCode() const {
13623 : Isolate* isolate = GetIsolate();
13624 13452092 : return !script()->IsUndefined(isolate) &&
13625 6726046 : !reinterpret_cast<Script*>(script())->source()->IsUndefined(isolate);
13626 : }
13627 :
13628 :
13629 722624 : Handle<Object> SharedFunctionInfo::GetSourceCode() {
13630 722624 : if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value();
13631 : Handle<String> source(String::cast(Script::cast(script())->source()));
13632 : return GetIsolate()->factory()->NewSubString(
13633 722624 : source, start_position(), end_position());
13634 : }
13635 :
13636 813 : Handle<Object> SharedFunctionInfo::GetSourceCodeHarmony() {
13637 : Isolate* isolate = GetIsolate();
13638 813 : if (!HasSourceCode()) return isolate->factory()->undefined_value();
13639 : Handle<String> script_source(String::cast(Script::cast(script())->source()));
13640 : int start_pos = function_token_position();
13641 813 : if (start_pos == kNoSourcePosition) start_pos = start_position();
13642 : return isolate->factory()->NewSubString(script_source, start_pos,
13643 813 : end_position());
13644 : }
13645 :
13646 62272 : bool SharedFunctionInfo::IsInlineable() {
13647 : // Check that the function has a script associated with it.
13648 62272 : if (!script()->IsScript()) return false;
13649 62272 : if (GetIsolate()->is_precise_binary_code_coverage() &&
13650 : !has_reported_binary_coverage()) {
13651 : // We may miss invocations if this function is inlined.
13652 : return false;
13653 : }
13654 62272 : return !optimization_disabled();
13655 : }
13656 :
13657 0 : int SharedFunctionInfo::SourceSize() {
13658 0 : return end_position() - start_position();
13659 : }
13660 :
13661 332085 : void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type,
13662 : bool has_prototype_slot,
13663 : int requested_embedder_fields,
13664 : int requested_in_object_properties,
13665 : int* instance_size,
13666 : int* in_object_properties) {
13667 332085 : int header_size = JSObject::GetHeaderSize(instance_type, has_prototype_slot);
13668 : DCHECK_LE(requested_embedder_fields,
13669 : (JSObject::kMaxInstanceSize - header_size) >> kPointerSizeLog2);
13670 : *instance_size =
13671 : Min(header_size +
13672 332085 : ((requested_embedder_fields + requested_in_object_properties)
13673 332085 : << kPointerSizeLog2),
13674 664170 : JSObject::kMaxInstanceSize);
13675 332085 : *in_object_properties = ((*instance_size - header_size) >> kPointerSizeLog2) -
13676 332085 : requested_embedder_fields;
13677 332085 : }
13678 :
13679 7160 : void JSFunction::CalculateInstanceSizeForDerivedClass(
13680 : Handle<JSFunction> function, InstanceType instance_type,
13681 : int requested_embedder_fields, int* instance_size,
13682 : int* in_object_properties) {
13683 : Isolate* isolate = function->GetIsolate();
13684 : int expected_nof_properties = 0;
13685 30342 : for (PrototypeIterator iter(isolate, function, kStartAtReceiver);
13686 16022 : !iter.IsAtEnd(); iter.Advance()) {
13687 : Handle<JSReceiver> current =
13688 : PrototypeIterator::GetCurrent<JSReceiver>(iter);
13689 23182 : if (!current->IsJSFunction()) break;
13690 : Handle<JSFunction> func(Handle<JSFunction>::cast(current));
13691 : // The super constructor should be compiled for the number of expected
13692 : // properties to be available.
13693 : Handle<SharedFunctionInfo> shared(func->shared());
13694 23398 : if (shared->is_compiled() ||
13695 226 : Compiler::Compile(func, Compiler::CLEAR_EXCEPTION)) {
13696 : DCHECK(shared->is_compiled());
13697 23172 : expected_nof_properties += shared->expected_nof_properties();
13698 : }
13699 23172 : if (!IsDerivedConstructor(shared->kind())) {
13700 : break;
13701 : }
13702 : }
13703 : CalculateInstanceSizeHelper(instance_type, true, requested_embedder_fields,
13704 : expected_nof_properties, instance_size,
13705 7160 : in_object_properties);
13706 7160 : }
13707 :
13708 :
13709 : // Output the source code without any allocation in the heap.
13710 0 : std::ostream& operator<<(std::ostream& os, const SourceCodeOf& v) {
13711 0 : const SharedFunctionInfo* s = v.value;
13712 : // For some native functions there is no source.
13713 0 : if (!s->HasSourceCode()) return os << "<No Source>";
13714 :
13715 : // Get the source for the script which this function came from.
13716 : // Don't use String::cast because we don't want more assertion errors while
13717 : // we are already creating a stack dump.
13718 : String* script_source =
13719 : reinterpret_cast<String*>(Script::cast(s->script())->source());
13720 :
13721 0 : if (!script_source->LooksValid()) return os << "<Invalid Source>";
13722 :
13723 0 : if (!s->is_toplevel()) {
13724 0 : os << "function ";
13725 : String* name = s->name();
13726 0 : if (name->length() > 0) {
13727 0 : name->PrintUC16(os);
13728 : }
13729 : }
13730 :
13731 0 : int len = s->end_position() - s->start_position();
13732 0 : if (len <= v.max_length || v.max_length < 0) {
13733 0 : script_source->PrintUC16(os, s->start_position(), s->end_position());
13734 0 : return os;
13735 : } else {
13736 : script_source->PrintUC16(os, s->start_position(),
13737 0 : s->start_position() + v.max_length);
13738 0 : return os << "...\n";
13739 : }
13740 : }
13741 :
13742 :
13743 24667 : void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
13744 : DCHECK_NE(reason, kNoReason);
13745 :
13746 : set_compiler_hints(
13747 49334 : DisabledOptimizationReasonBits::update(compiler_hints(), reason));
13748 : // Code should be the lazy compilation stub or else interpreted.
13749 : DCHECK(abstract_code()->kind() == AbstractCode::INTERPRETED_FUNCTION ||
13750 : abstract_code()->kind() == AbstractCode::BUILTIN);
13751 24667 : PROFILE(GetIsolate(), CodeDisableOptEvent(abstract_code(), this));
13752 24667 : if (FLAG_trace_opt) {
13753 0 : PrintF("[disabled optimization for ");
13754 0 : ShortPrint();
13755 0 : PrintF(", reason: %s]\n", GetBailoutReason(reason));
13756 : }
13757 24667 : }
13758 :
13759 5166991 : void SharedFunctionInfo::InitFromFunctionLiteral(
13760 34313286 : Handle<SharedFunctionInfo> shared_info, FunctionLiteral* lit) {
13761 : // When adding fields here, make sure DeclarationScope::AnalyzePartially is
13762 : // updated accordingly.
13763 : shared_info->set_internal_formal_parameter_count(lit->parameter_count());
13764 : shared_info->set_function_token_position(lit->function_token_position());
13765 5166991 : shared_info->set_start_position(lit->start_position());
13766 5166991 : shared_info->set_end_position(lit->end_position());
13767 : shared_info->set_is_declaration(lit->is_declaration());
13768 : shared_info->set_is_named_expression(lit->is_named_expression());
13769 10333982 : shared_info->set_is_anonymous_expression(lit->is_anonymous_expression());
13770 10333981 : shared_info->set_inferred_name(*lit->inferred_name());
13771 5166990 : shared_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
13772 5166990 : shared_info->set_language_mode(lit->language_mode());
13773 : // shared_info->set_kind(lit->kind());
13774 : // FunctionKind must have already been set.
13775 : DCHECK(lit->kind() == shared_info->kind());
13776 5166990 : if (!IsConstructable(lit->kind())) {
13777 : shared_info->SetConstructStub(
13778 1335268 : *BUILTIN_CODE(shared_info->GetIsolate(), ConstructedNonConstructable));
13779 : }
13780 5166990 : shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
13781 : shared_info->set_function_literal_id(lit->function_literal_id());
13782 :
13783 : // For lazy parsed functions, the following flags will be inaccurate since we
13784 : // don't have the information yet. They're set later in
13785 : // SetSharedFunctionFlagsFromLiteral (compiler.cc), when the function is
13786 : // really parsed and compiled.
13787 5166991 : if (lit->body() != nullptr) {
13788 : shared_info->set_length(lit->function_length());
13789 : shared_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
13790 : shared_info->SetExpectedNofPropertiesFromEstimate(lit);
13791 : DCHECK_NULL(lit->produced_preparsed_scope_data());
13792 : } else {
13793 : // Set an invalid length for lazy functions. This way we can set the correct
13794 : // value after compiling, but avoid overwriting values set manually by the
13795 : // bootstrapper.
13796 : shared_info->set_length(SharedFunctionInfo::kInvalidLength);
13797 1855650 : if (FLAG_preparser_scope_analysis) {
13798 : ProducedPreParsedScopeData* scope_data =
13799 : lit->produced_preparsed_scope_data();
13800 1855650 : if (scope_data != nullptr) {
13801 : MaybeHandle<PreParsedScopeData> maybe_data =
13802 1818337 : scope_data->Serialize(shared_info->GetIsolate());
13803 1818337 : if (!maybe_data.is_null()) {
13804 : Handle<PreParsedScopeData> data = maybe_data.ToHandleChecked();
13805 52950 : shared_info->set_preparsed_scope_data(*data);
13806 : }
13807 : }
13808 : }
13809 : }
13810 5166991 : }
13811 :
13812 2134855 : void SharedFunctionInfo::SetExpectedNofPropertiesFromEstimate(
13813 5446196 : FunctionLiteral* literal) {
13814 : int estimate = literal->expected_property_count();
13815 :
13816 : // If no properties are added in the constructor, they are more likely
13817 : // to be added later.
13818 5446196 : if (estimate == 0) estimate = 2;
13819 :
13820 : // Inobject slack tracking will reclaim redundant inobject space later,
13821 : // so we can afford to adjust the estimate generously.
13822 5446196 : estimate += 8;
13823 :
13824 : set_expected_nof_properties(estimate);
13825 2134855 : }
13826 :
13827 13034551 : void SharedFunctionInfo::SetConstructStub(Code* code) {
13828 13034551 : if (code->kind() == Code::BUILTIN) code->set_is_construct_stub(true);
13829 : #ifdef DEBUG
13830 : if (code->is_builtin()) {
13831 : // See https://crbug.com/v8/6787. Lazy deserialization currently cannot
13832 : // handle lazy construct stubs that differ from the code object.
13833 : int builtin_id = code->builtin_index();
13834 : DCHECK_NE(Builtins::kDeserializeLazy, builtin_id);
13835 : DCHECK(builtin_id == Builtins::kJSBuiltinsConstructStub ||
13836 : this->code() == code || !Builtins::IsLazy(builtin_id));
13837 : }
13838 : #endif
13839 13034551 : set_construct_stub(code);
13840 13034552 : }
13841 :
13842 0 : void Map::StartInobjectSlackTracking() {
13843 : DCHECK(!IsInobjectSlackTrackingInProgress());
13844 332085 : if (UnusedPropertyFields() == 0) return;
13845 : set_construction_counter(Map::kSlackTrackingCounterStart);
13846 : }
13847 :
13848 5795310 : void ObjectVisitor::VisitCodeTarget(Code* host, RelocInfo* rinfo) {
13849 : DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode()));
13850 5795310 : Object* old_pointer = Code::GetCodeFromTargetAddress(rinfo->target_address());
13851 5795310 : Object* new_pointer = old_pointer;
13852 5795310 : VisitPointer(host, &new_pointer);
13853 : DCHECK_EQ(old_pointer, new_pointer);
13854 5795310 : }
13855 :
13856 313031 : void ObjectVisitor::VisitEmbeddedPointer(Code* host, RelocInfo* rinfo) {
13857 : DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
13858 : Object* old_pointer = rinfo->target_object();
13859 313031 : Object* new_pointer = old_pointer;
13860 313031 : VisitPointer(host, &new_pointer);
13861 : DCHECK_EQ(old_pointer, new_pointer);
13862 313031 : }
13863 :
13864 :
13865 0 : void Code::InvalidateRelocation() {
13866 0 : InvalidateEmbeddedObjects();
13867 0 : set_relocation_info(GetHeap()->empty_byte_array());
13868 0 : }
13869 :
13870 :
13871 255503 : void Code::InvalidateEmbeddedObjects() {
13872 255503 : HeapObject* undefined = GetHeap()->undefined_value();
13873 : int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
13874 3432520 : for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
13875 3177017 : RelocInfo::Mode mode = it.rinfo()->rmode();
13876 3177017 : if (mode == RelocInfo::EMBEDDED_OBJECT) {
13877 : it.rinfo()->set_target_object(undefined, SKIP_WRITE_BARRIER);
13878 : }
13879 : }
13880 255503 : }
13881 :
13882 :
13883 90109 : void Code::Relocate(intptr_t delta) {
13884 96839 : if (trap_handler::UseTrapHandler() && is_wasm_code()) {
13885 : const int index = trap_handler_index()->value();
13886 679 : if (index >= 0) {
13887 7 : trap_handler::UpdateHandlerDataCodePointer(index, instruction_start());
13888 : }
13889 : }
13890 265260 : for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
13891 175151 : it.rinfo()->apply(delta);
13892 : }
13893 180218 : Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size());
13894 90109 : }
13895 :
13896 :
13897 1669351 : void Code::CopyFrom(const CodeDesc& desc) {
13898 : // copy code
13899 : CopyBytes(instruction_start(), desc.buffer,
13900 1669351 : static_cast<size_t>(desc.instr_size));
13901 :
13902 : // copy unwinding info, if any
13903 1669351 : if (desc.unwinding_info) {
13904 : DCHECK_GT(desc.unwinding_info_size, 0);
13905 27 : set_unwinding_info_size(desc.unwinding_info_size);
13906 : CopyBytes(unwinding_info_start(), desc.unwinding_info,
13907 54 : static_cast<size_t>(desc.unwinding_info_size));
13908 : }
13909 :
13910 : // copy reloc info
13911 : CopyBytes(relocation_start(),
13912 1669351 : desc.buffer + desc.buffer_size - desc.reloc_size,
13913 5008053 : static_cast<size_t>(desc.reloc_size));
13914 :
13915 : // unbox handles and relocate
13916 : int mode_mask = RelocInfo::kCodeTargetMask |
13917 : RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
13918 1669351 : RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
13919 1669351 : RelocInfo::kApplyMask;
13920 : // Needed to find target_object and runtime_entry on X64
13921 1669351 : Assembler* origin = desc.origin;
13922 : AllowDeferredHandleDereference embedding_raw_address;
13923 16087600 : for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
13924 14418249 : RelocInfo::Mode mode = it.rinfo()->rmode();
13925 14418249 : if (mode == RelocInfo::EMBEDDED_OBJECT) {
13926 4989532 : Handle<HeapObject> p = it.rinfo()->target_object_handle(origin);
13927 : it.rinfo()->set_target_object(*p, UPDATE_WRITE_BARRIER,
13928 : SKIP_ICACHE_FLUSH);
13929 9428717 : } else if (RelocInfo::IsCodeTarget(mode)) {
13930 : // rewrite code handles to direct pointers to the first instruction in the
13931 : // code object
13932 6025821 : Handle<Object> p = it.rinfo()->target_object_handle(origin);
13933 : Code* code = Code::cast(*p);
13934 : it.rinfo()->set_target_address(GetIsolate(), code->instruction_start(),
13935 12051642 : UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
13936 3402896 : } else if (RelocInfo::IsRuntimeEntry(mode)) {
13937 3077632 : Address p = it.rinfo()->target_runtime_entry(origin);
13938 : it.rinfo()->set_target_runtime_entry(
13939 : GetIsolate(), p, UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
13940 : } else {
13941 325264 : intptr_t delta = instruction_start() - desc.buffer;
13942 325264 : it.rinfo()->apply(delta);
13943 : }
13944 : }
13945 3338702 : Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size());
13946 1669351 : }
13947 :
13948 :
13949 2758981 : SafepointEntry Code::GetSafepointEntry(Address pc) {
13950 2758981 : SafepointTable table(this);
13951 2758981 : return table.FindEntry(pc);
13952 : }
13953 :
13954 :
13955 : namespace {
13956 : template <typename Code>
13957 7432 : void SetStackFrameCacheCommon(Handle<Code> code,
13958 : Handle<UnseededNumberDictionary> cache) {
13959 : Handle<Object> maybe_table(code->source_position_table(), code->GetIsolate());
13960 7432 : if (maybe_table->IsSourcePositionTableWithFrameCache()) {
13961 561 : Handle<SourcePositionTableWithFrameCache>::cast(maybe_table)
13962 : ->set_stack_frame_cache(*cache);
13963 7993 : return;
13964 : }
13965 : DCHECK(maybe_table->IsByteArray());
13966 6871 : Handle<ByteArray> table(Handle<ByteArray>::cast(maybe_table));
13967 : Handle<SourcePositionTableWithFrameCache> table_with_cache =
13968 : code->GetIsolate()->factory()->NewSourcePositionTableWithFrameCache(
13969 6871 : table, cache);
13970 6871 : code->set_source_position_table(*table_with_cache);
13971 : }
13972 : } // namespace
13973 :
13974 : // static
13975 7432 : void AbstractCode::SetStackFrameCache(Handle<AbstractCode> abstract_code,
13976 : Handle<UnseededNumberDictionary> cache) {
13977 7432 : if (abstract_code->IsCode()) {
13978 0 : SetStackFrameCacheCommon(handle(abstract_code->GetCode()), cache);
13979 : } else {
13980 7432 : SetStackFrameCacheCommon(handle(abstract_code->GetBytecodeArray()), cache);
13981 : }
13982 7432 : }
13983 :
13984 : namespace {
13985 : template <typename Code>
13986 5765601 : void DropStackFrameCacheCommon(Code* code) {
13987 : i::Object* maybe_table = code->source_position_table();
13988 11531202 : if (maybe_table->IsByteArray()) return;
13989 : DCHECK(maybe_table->IsSourcePositionTableWithFrameCache());
13990 20 : code->set_source_position_table(
13991 : i::SourcePositionTableWithFrameCache::cast(maybe_table)
13992 : ->source_position_table());
13993 : }
13994 : } // namespace
13995 :
13996 5765601 : void AbstractCode::DropStackFrameCache() {
13997 5765601 : if (IsCode()) {
13998 5754701 : DropStackFrameCacheCommon(GetCode());
13999 : } else {
14000 10900 : DropStackFrameCacheCommon(GetBytecodeArray());
14001 : }
14002 5765600 : }
14003 :
14004 1396566 : int AbstractCode::SourcePosition(int offset) {
14005 : int position = 0;
14006 : // Subtract one because the current PC is one instruction after the call site.
14007 1396566 : if (IsCode()) offset--;
14008 32602042 : for (SourcePositionTableIterator iterator(source_position_table());
14009 31205476 : !iterator.done() && iterator.code_offset() <= offset;
14010 29808910 : iterator.Advance()) {
14011 29808910 : position = iterator.source_position().ScriptOffset();
14012 : }
14013 1396566 : return position;
14014 : }
14015 :
14016 98825 : int AbstractCode::SourceStatementPosition(int offset) {
14017 : // First find the closest position.
14018 98825 : int position = SourcePosition(offset);
14019 : // Now find the closest statement position before the position.
14020 : int statement_position = 0;
14021 11043366 : for (SourcePositionTableIterator it(source_position_table()); !it.done();
14022 10845716 : it.Advance()) {
14023 10845716 : if (it.is_statement()) {
14024 6905911 : int p = it.source_position().ScriptOffset();
14025 6905911 : if (statement_position < p && p <= position) {
14026 : statement_position = p;
14027 : }
14028 : }
14029 : }
14030 98825 : return statement_position;
14031 : }
14032 :
14033 57790 : void JSFunction::ClearTypeFeedbackInfo() {
14034 57790 : if (feedback_vector_cell()->value()->IsFeedbackVector()) {
14035 : FeedbackVector* vector = feedback_vector();
14036 : Isolate* isolate = GetIsolate();
14037 57761 : if (vector->ClearSlots(isolate)) {
14038 31961 : IC::OnFeedbackChanged(isolate, vector, this);
14039 : }
14040 : }
14041 57790 : }
14042 :
14043 0 : void Code::PrintDeoptLocation(FILE* out, Address pc) {
14044 0 : Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(this, pc);
14045 0 : class SourcePosition pos = info.position;
14046 0 : if (info.deopt_reason != DeoptimizeReason::kNoReason || pos.IsKnown()) {
14047 0 : PrintF(out, " ;;; deoptimize at ");
14048 0 : OFStream outstr(out);
14049 0 : pos.Print(outstr, this);
14050 0 : PrintF(out, ", %s\n", DeoptimizeReasonToString(info.deopt_reason));
14051 : }
14052 0 : }
14053 :
14054 :
14055 2543 : bool Code::CanDeoptAt(Address pc) {
14056 : DeoptimizationData* deopt_data =
14057 : DeoptimizationData::cast(deoptimization_data());
14058 2543 : Address code_start_address = instruction_start();
14059 60248 : for (int i = 0; i < deopt_data->DeoptCount(); i++) {
14060 59474 : if (deopt_data->Pc(i)->value() == -1) continue;
14061 52080 : Address address = code_start_address + deopt_data->Pc(i)->value();
14062 28196 : if (address == pc && deopt_data->BytecodeOffset(i) != BailoutId::None()) {
14063 : return true;
14064 : }
14065 : }
14066 : return false;
14067 : }
14068 :
14069 :
14070 : // Identify kind of code.
14071 22729 : const char* Code::Kind2String(Kind kind) {
14072 22729 : switch (kind) {
14073 : #define CASE(name) case name: return #name;
14074 0 : CODE_KIND_LIST(CASE)
14075 : #undef CASE
14076 : case NUMBER_OF_KINDS: break;
14077 : }
14078 0 : UNREACHABLE();
14079 : }
14080 :
14081 : // Identify kind of code.
14082 0 : const char* AbstractCode::Kind2String(Kind kind) {
14083 0 : if (kind < AbstractCode::INTERPRETED_FUNCTION)
14084 0 : return Code::Kind2String((Code::Kind)kind);
14085 0 : if (kind == AbstractCode::INTERPRETED_FUNCTION) return "INTERPRETED_FUNCTION";
14086 0 : UNREACHABLE();
14087 : }
14088 :
14089 1154451 : Handle<WeakCell> Code::WeakCellFor(Handle<Code> code) {
14090 : DCHECK(code->kind() == OPTIMIZED_FUNCTION);
14091 1154451 : WeakCell* raw_cell = code->CachedWeakCell();
14092 2076439 : if (raw_cell != nullptr) return Handle<WeakCell>(raw_cell);
14093 232463 : Handle<WeakCell> cell = code->GetIsolate()->factory()->NewWeakCell(code);
14094 : DeoptimizationData::cast(code->deoptimization_data())
14095 : ->SetWeakCellCache(*cell);
14096 232463 : return cell;
14097 : }
14098 :
14099 1154451 : WeakCell* Code::CachedWeakCell() {
14100 : DCHECK(kind() == OPTIMIZED_FUNCTION);
14101 : Object* weak_cell_cache =
14102 : DeoptimizationData::cast(deoptimization_data())->WeakCellCache();
14103 1154451 : if (weak_cell_cache->IsWeakCell()) {
14104 : DCHECK(this == WeakCell::cast(weak_cell_cache)->value());
14105 921988 : return WeakCell::cast(weak_cell_cache);
14106 : }
14107 : return nullptr;
14108 : }
14109 :
14110 48488 : bool Code::Inlines(SharedFunctionInfo* sfi) {
14111 : // We can only check for inlining for optimized code.
14112 : DCHECK(is_optimized_code());
14113 : DisallowHeapAllocation no_gc;
14114 : DeoptimizationData* const data =
14115 : DeoptimizationData::cast(deoptimization_data());
14116 48488 : if (data->length() == 0) return false;
14117 48485 : if (data->SharedFunctionInfo() == sfi) return true;
14118 : FixedArray* const literals = data->LiteralArray();
14119 : int const inlined_count = data->InlinedFunctionCount()->value();
14120 48336 : for (int i = 0; i < inlined_count; ++i) {
14121 198 : if (SharedFunctionInfo::cast(literals->get(i)) == sfi) return true;
14122 : }
14123 : return false;
14124 : }
14125 :
14126 9227 : Code::OptimizedCodeIterator::OptimizedCodeIterator(Isolate* isolate) {
14127 9227 : isolate_ = isolate;
14128 9227 : Object* list = isolate->heap()->native_contexts_list();
14129 9227 : next_context_ = list->IsUndefined(isolate_) ? nullptr : Context::cast(list);
14130 9227 : current_code_ = nullptr;
14131 9227 : }
14132 :
14133 57256 : Code* Code::OptimizedCodeIterator::Next() {
14134 66946 : do {
14135 : Object* next;
14136 76173 : if (current_code_ != nullptr) {
14137 : // Get next code in the linked list.
14138 : next = Code::cast(current_code_)->next_code_link();
14139 28144 : } else if (next_context_ != nullptr) {
14140 : // Linked list of code exhausted. Get list of next context.
14141 18917 : next = next_context_->OptimizedCodeListHead();
14142 18917 : Object* next_context = next_context_->next_context_link();
14143 18917 : next_context_ = next_context->IsUndefined(isolate_)
14144 : ? nullptr
14145 18917 : : Context::cast(next_context);
14146 : } else {
14147 : // Exhausted contexts.
14148 : return nullptr;
14149 : }
14150 133892 : current_code_ = next->IsUndefined(isolate_) ? nullptr : Code::cast(next);
14151 : } while (current_code_ == nullptr);
14152 : Code* code = Code::cast(current_code_);
14153 : DCHECK_EQ(Code::OPTIMIZED_FUNCTION, code->kind());
14154 : return code;
14155 : }
14156 :
14157 : #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
14158 :
14159 : const char* Code::ICState2String(InlineCacheState state) {
14160 : switch (state) {
14161 : case UNINITIALIZED:
14162 : return "UNINITIALIZED";
14163 : case PREMONOMORPHIC:
14164 : return "PREMONOMORPHIC";
14165 : case MONOMORPHIC:
14166 : return "MONOMORPHIC";
14167 : case RECOMPUTE_HANDLER:
14168 : return "RECOMPUTE_HANDLER";
14169 : case POLYMORPHIC:
14170 : return "POLYMORPHIC";
14171 : case MEGAMORPHIC:
14172 : return "MEGAMORPHIC";
14173 : case GENERIC:
14174 : return "GENERIC";
14175 : }
14176 : UNREACHABLE();
14177 : }
14178 :
14179 : #endif // defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
14180 :
14181 : #ifdef ENABLE_DISASSEMBLER
14182 :
14183 : namespace {
14184 : void print_pc(std::ostream& os, int pc) {
14185 : if (pc == -1) {
14186 : os << "NA";
14187 : } else {
14188 : os << std::hex << pc << std::dec;
14189 : }
14190 : }
14191 : } // anonymous namespace
14192 :
14193 : void DeoptimizationData::DeoptimizationDataPrint(std::ostream& os) { // NOLINT
14194 : if (length() == 0) {
14195 : os << "Deoptimization Input Data invalidated by lazy deoptimization\n";
14196 : return;
14197 : }
14198 :
14199 : disasm::NameConverter converter;
14200 : int const inlined_function_count = InlinedFunctionCount()->value();
14201 : os << "Inlined functions (count = " << inlined_function_count << ")\n";
14202 : for (int id = 0; id < inlined_function_count; ++id) {
14203 : Object* info = LiteralArray()->get(id);
14204 : os << " " << Brief(SharedFunctionInfo::cast(info)) << "\n";
14205 : }
14206 : os << "\n";
14207 : int deopt_count = DeoptCount();
14208 : os << "Deoptimization Input Data (deopt points = " << deopt_count << ")\n";
14209 : if (0 != deopt_count) {
14210 : os << " index bytecode-offset pc";
14211 : if (FLAG_print_code_verbose) os << " commands";
14212 : os << "\n";
14213 : }
14214 : for (int i = 0; i < deopt_count; i++) {
14215 : os << std::setw(6) << i << " " << std::setw(15)
14216 : << BytecodeOffset(i).ToInt() << " " << std::setw(4);
14217 : print_pc(os, Pc(i)->value());
14218 : os << std::setw(2);
14219 :
14220 : if (!FLAG_print_code_verbose) {
14221 : os << "\n";
14222 : continue;
14223 : }
14224 :
14225 : // Print details of the frame translation.
14226 : int translation_index = TranslationIndex(i)->value();
14227 : TranslationIterator iterator(TranslationByteArray(), translation_index);
14228 : Translation::Opcode opcode =
14229 : static_cast<Translation::Opcode>(iterator.Next());
14230 : DCHECK(Translation::BEGIN == opcode);
14231 : int frame_count = iterator.Next();
14232 : int jsframe_count = iterator.Next();
14233 : os << " " << Translation::StringFor(opcode)
14234 : << " {frame count=" << frame_count
14235 : << ", js frame count=" << jsframe_count << "}\n";
14236 :
14237 : while (iterator.HasNext() &&
14238 : Translation::BEGIN !=
14239 : (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
14240 : os << std::setw(31) << " " << Translation::StringFor(opcode) << " ";
14241 :
14242 : switch (opcode) {
14243 : case Translation::BEGIN:
14244 : UNREACHABLE();
14245 : break;
14246 :
14247 : case Translation::INTERPRETED_FRAME: {
14248 : int bytecode_offset = iterator.Next();
14249 : int shared_info_id = iterator.Next();
14250 : unsigned height = iterator.Next();
14251 : Object* shared_info = LiteralArray()->get(shared_info_id);
14252 : os << "{bytecode_offset=" << bytecode_offset << ", function="
14253 : << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14254 : << ", height=" << height << "}";
14255 : break;
14256 : }
14257 :
14258 : case Translation::CONSTRUCT_STUB_FRAME: {
14259 : int bailout_id = iterator.Next();
14260 : int shared_info_id = iterator.Next();
14261 : Object* shared_info = LiteralArray()->get(shared_info_id);
14262 : unsigned height = iterator.Next();
14263 : os << "{bailout_id=" << bailout_id << ", function="
14264 : << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14265 : << ", height=" << height << "}";
14266 : break;
14267 : }
14268 :
14269 : case Translation::BUILTIN_CONTINUATION_FRAME:
14270 : case Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME: {
14271 : int bailout_id = iterator.Next();
14272 : int shared_info_id = iterator.Next();
14273 : Object* shared_info = LiteralArray()->get(shared_info_id);
14274 : unsigned height = iterator.Next();
14275 : os << "{bailout_id=" << bailout_id << ", function="
14276 : << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14277 : << ", height=" << height << "}";
14278 : break;
14279 : }
14280 :
14281 : case Translation::ARGUMENTS_ADAPTOR_FRAME: {
14282 : int shared_info_id = iterator.Next();
14283 : Object* shared_info = LiteralArray()->get(shared_info_id);
14284 : unsigned height = iterator.Next();
14285 : os << "{function="
14286 : << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14287 : << ", height=" << height << "}";
14288 : break;
14289 : }
14290 :
14291 : case Translation::GETTER_STUB_FRAME:
14292 : case Translation::SETTER_STUB_FRAME: {
14293 : int shared_info_id = iterator.Next();
14294 : Object* shared_info = LiteralArray()->get(shared_info_id);
14295 : os << "{function=" << Brief(SharedFunctionInfo::cast(shared_info)
14296 : ->DebugName()) << "}";
14297 : break;
14298 : }
14299 :
14300 : case Translation::REGISTER: {
14301 : int reg_code = iterator.Next();
14302 : os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
14303 : break;
14304 : }
14305 :
14306 : case Translation::INT32_REGISTER: {
14307 : int reg_code = iterator.Next();
14308 : os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
14309 : break;
14310 : }
14311 :
14312 : case Translation::UINT32_REGISTER: {
14313 : int reg_code = iterator.Next();
14314 : os << "{input=" << converter.NameOfCPURegister(reg_code)
14315 : << " (unsigned)}";
14316 : break;
14317 : }
14318 :
14319 : case Translation::BOOL_REGISTER: {
14320 : int reg_code = iterator.Next();
14321 : os << "{input=" << converter.NameOfCPURegister(reg_code)
14322 : << " (bool)}";
14323 : break;
14324 : }
14325 :
14326 : case Translation::FLOAT_REGISTER: {
14327 : int reg_code = iterator.Next();
14328 : os << "{input="
14329 : << RegisterConfiguration::Default()->GetFloatRegisterName(reg_code)
14330 : << "}";
14331 : break;
14332 : }
14333 :
14334 : case Translation::DOUBLE_REGISTER: {
14335 : int reg_code = iterator.Next();
14336 : os << "{input="
14337 : << RegisterConfiguration::Default()->GetDoubleRegisterName(
14338 : reg_code)
14339 : << "}";
14340 : break;
14341 : }
14342 :
14343 : case Translation::STACK_SLOT: {
14344 : int input_slot_index = iterator.Next();
14345 : os << "{input=" << input_slot_index << "}";
14346 : break;
14347 : }
14348 :
14349 : case Translation::INT32_STACK_SLOT: {
14350 : int input_slot_index = iterator.Next();
14351 : os << "{input=" << input_slot_index << "}";
14352 : break;
14353 : }
14354 :
14355 : case Translation::UINT32_STACK_SLOT: {
14356 : int input_slot_index = iterator.Next();
14357 : os << "{input=" << input_slot_index << " (unsigned)}";
14358 : break;
14359 : }
14360 :
14361 : case Translation::BOOL_STACK_SLOT: {
14362 : int input_slot_index = iterator.Next();
14363 : os << "{input=" << input_slot_index << " (bool)}";
14364 : break;
14365 : }
14366 :
14367 : case Translation::FLOAT_STACK_SLOT:
14368 : case Translation::DOUBLE_STACK_SLOT: {
14369 : int input_slot_index = iterator.Next();
14370 : os << "{input=" << input_slot_index << "}";
14371 : break;
14372 : }
14373 :
14374 : case Translation::LITERAL: {
14375 : int literal_index = iterator.Next();
14376 : Object* literal_value = LiteralArray()->get(literal_index);
14377 : os << "{literal_id=" << literal_index << " (" << Brief(literal_value)
14378 : << ")}";
14379 : break;
14380 : }
14381 :
14382 : case Translation::DUPLICATED_OBJECT: {
14383 : int object_index = iterator.Next();
14384 : os << "{object_index=" << object_index << "}";
14385 : break;
14386 : }
14387 :
14388 : case Translation::ARGUMENTS_ELEMENTS:
14389 : case Translation::ARGUMENTS_LENGTH: {
14390 : CreateArgumentsType arguments_type =
14391 : static_cast<CreateArgumentsType>(iterator.Next());
14392 : os << "{arguments_type=" << arguments_type << "}";
14393 : break;
14394 : }
14395 :
14396 : case Translation::CAPTURED_OBJECT: {
14397 : int args_length = iterator.Next();
14398 : os << "{length=" << args_length << "}";
14399 : break;
14400 : }
14401 : }
14402 : os << "\n";
14403 : }
14404 : }
14405 : }
14406 :
14407 :
14408 : void HandlerTable::HandlerTableRangePrint(std::ostream& os) {
14409 : os << " from to hdlr\n";
14410 : for (int i = 0; i < length(); i += kRangeEntrySize) {
14411 : int pc_start = Smi::ToInt(get(i + kRangeStartIndex));
14412 : int pc_end = Smi::ToInt(get(i + kRangeEndIndex));
14413 : int handler_field = Smi::ToInt(get(i + kRangeHandlerIndex));
14414 : int handler_offset = HandlerOffsetField::decode(handler_field);
14415 : CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
14416 : int data = Smi::ToInt(get(i + kRangeDataIndex));
14417 : os << " (" << std::setw(4) << pc_start << "," << std::setw(4) << pc_end
14418 : << ") -> " << std::setw(4) << handler_offset
14419 : << " (prediction=" << prediction << ", data=" << data << ")\n";
14420 : }
14421 : }
14422 :
14423 :
14424 : void HandlerTable::HandlerTableReturnPrint(std::ostream& os) {
14425 : os << " off hdlr (c)\n";
14426 : for (int i = 0; i < length(); i += kReturnEntrySize) {
14427 : int pc_offset = Smi::ToInt(get(i + kReturnOffsetIndex));
14428 : int handler_field = Smi::ToInt(get(i + kReturnHandlerIndex));
14429 : int handler_offset = HandlerOffsetField::decode(handler_field);
14430 : CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
14431 : os << " " << std::setw(4) << pc_offset << " -> " << std::setw(4)
14432 : << handler_offset << " (prediction=" << prediction << ")\n";
14433 : }
14434 : }
14435 :
14436 :
14437 : void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT
14438 : os << "kind = " << Kind2String(kind()) << "\n";
14439 : if (is_stub()) {
14440 : const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this));
14441 : os << "major_key = " << (n == nullptr ? "null" : n) << "\n";
14442 : }
14443 : if ((name != nullptr) && (name[0] != '\0')) {
14444 : os << "name = " << name << "\n";
14445 : } else if (kind() == BYTECODE_HANDLER) {
14446 : name = GetIsolate()->interpreter()->LookupNameOfBytecodeHandler(this);
14447 : if (name != nullptr) {
14448 : os << "name = " << name << "\n";
14449 : }
14450 : } else {
14451 : // There are some handlers and ICs that we can also find names for with
14452 : // Builtins::Lookup.
14453 : name = GetIsolate()->builtins()->Lookup(instruction_start());
14454 : if (name != nullptr) {
14455 : os << "name = " << name << "\n";
14456 : }
14457 : }
14458 : if (kind() == OPTIMIZED_FUNCTION) {
14459 : os << "stack_slots = " << stack_slots() << "\n";
14460 : }
14461 : os << "compiler = " << (is_turbofanned() ? "turbofan" : "unknown") << "\n";
14462 :
14463 : os << "Instructions (size = " << instruction_size() << ")\n";
14464 : {
14465 : Isolate* isolate = GetIsolate();
14466 : int size = instruction_size();
14467 : int safepoint_offset =
14468 : is_turbofanned() ? static_cast<int>(safepoint_table_offset()) : size;
14469 : int constant_pool_offset = FLAG_enable_embedded_constant_pool
14470 : ? this->constant_pool_offset()
14471 : : size;
14472 :
14473 : // Stop before reaching any embedded tables
14474 : int code_size = Min(safepoint_offset, constant_pool_offset);
14475 : byte* begin = instruction_start();
14476 : byte* end = begin + code_size;
14477 : Disassembler::Decode(isolate, &os, begin, end, this);
14478 :
14479 : if (constant_pool_offset < size) {
14480 : int constant_pool_size = safepoint_offset - constant_pool_offset;
14481 : DCHECK_EQ(constant_pool_size & kPointerAlignmentMask, 0);
14482 : os << "\nConstant Pool (size = " << constant_pool_size << ")\n";
14483 : Vector<char> buf = Vector<char>::New(50);
14484 : intptr_t* ptr = reinterpret_cast<intptr_t*>(begin + constant_pool_offset);
14485 : for (int i = 0; i < constant_pool_size; i += kPointerSize, ptr++) {
14486 : SNPrintF(buf, "%4d %08" V8PRIxPTR, i, *ptr);
14487 : os << static_cast<const void*>(ptr) << " " << buf.start() << "\n";
14488 : }
14489 : }
14490 : }
14491 : os << "\n";
14492 :
14493 : SourcePositionTableIterator it(SourcePositionTable());
14494 : if (!it.done()) {
14495 : os << "Source positions:\n pc offset position\n";
14496 : for (; !it.done(); it.Advance()) {
14497 : os << std::setw(10) << std::hex << it.code_offset() << std::dec
14498 : << std::setw(10) << it.source_position().ScriptOffset()
14499 : << (it.is_statement() ? " statement" : "") << "\n";
14500 : }
14501 : os << "\n";
14502 : }
14503 :
14504 : if (kind() == OPTIMIZED_FUNCTION) {
14505 : DeoptimizationData* data =
14506 : DeoptimizationData::cast(this->deoptimization_data());
14507 : data->DeoptimizationDataPrint(os);
14508 : }
14509 : os << "\n";
14510 :
14511 : if (is_turbofanned()) {
14512 : SafepointTable table(this);
14513 : os << "Safepoints (size = " << table.size() << ")\n";
14514 : for (unsigned i = 0; i < table.length(); i++) {
14515 : unsigned pc_offset = table.GetPcOffset(i);
14516 : os << static_cast<const void*>(instruction_start() + pc_offset) << " ";
14517 : os << std::setw(6) << std::hex << pc_offset << " " << std::setw(4);
14518 : int trampoline_pc = table.GetTrampolinePcOffset(i);
14519 : print_pc(os, trampoline_pc);
14520 : os << std::dec << " ";
14521 : table.PrintEntry(i, os);
14522 : os << " (sp -> fp) ";
14523 : SafepointEntry entry = table.GetEntry(i);
14524 : if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
14525 : os << std::setw(6) << entry.deoptimization_index();
14526 : } else {
14527 : os << "<none>";
14528 : }
14529 : if (entry.argument_count() > 0) {
14530 : os << " argc: " << entry.argument_count();
14531 : }
14532 : os << "\n";
14533 : }
14534 : os << "\n";
14535 : }
14536 :
14537 : if (handler_table()->length() > 0) {
14538 : os << "Handler Table (size = " << handler_table()->Size() << ")\n";
14539 : if (kind() == OPTIMIZED_FUNCTION) {
14540 : HandlerTable::cast(handler_table())->HandlerTableReturnPrint(os);
14541 : }
14542 : os << "\n";
14543 : }
14544 :
14545 : os << "RelocInfo (size = " << relocation_size() << ")\n";
14546 : for (RelocIterator it(this); !it.done(); it.next()) {
14547 : it.rinfo()->Print(GetIsolate(), os);
14548 : }
14549 : os << "\n";
14550 :
14551 : if (has_unwinding_info()) {
14552 : os << "UnwindingInfo (size = " << unwinding_info_size() << ")\n";
14553 : EhFrameDisassembler eh_frame_disassembler(unwinding_info_start(),
14554 : unwinding_info_end());
14555 : eh_frame_disassembler.DisassembleToStream(os);
14556 : os << "\n";
14557 : }
14558 : }
14559 : #endif // ENABLE_DISASSEMBLER
14560 :
14561 :
14562 0 : void BytecodeArray::Disassemble(std::ostream& os) {
14563 0 : os << "Parameter count " << parameter_count() << "\n";
14564 0 : os << "Frame size " << frame_size() << "\n";
14565 :
14566 0 : const uint8_t* base_address = GetFirstBytecodeAddress();
14567 0 : SourcePositionTableIterator source_positions(SourcePositionTable());
14568 :
14569 0 : interpreter::BytecodeArrayIterator iterator(handle(this));
14570 0 : while (!iterator.done()) {
14571 0 : if (!source_positions.done() &&
14572 0 : iterator.current_offset() == source_positions.code_offset()) {
14573 0 : os << std::setw(5) << source_positions.source_position().ScriptOffset();
14574 0 : os << (source_positions.is_statement() ? " S> " : " E> ");
14575 0 : source_positions.Advance();
14576 : } else {
14577 0 : os << " ";
14578 : }
14579 0 : const uint8_t* current_address = base_address + iterator.current_offset();
14580 0 : os << reinterpret_cast<const void*>(current_address) << " @ "
14581 0 : << std::setw(4) << iterator.current_offset() << " : ";
14582 : interpreter::BytecodeDecoder::Decode(os, current_address,
14583 0 : parameter_count());
14584 0 : if (interpreter::Bytecodes::IsJump(iterator.current_bytecode())) {
14585 0 : const void* jump_target = base_address + iterator.GetJumpTargetOffset();
14586 0 : os << " (" << jump_target << " @ " << iterator.GetJumpTargetOffset()
14587 0 : << ")";
14588 : }
14589 0 : if (interpreter::Bytecodes::IsSwitch(iterator.current_bytecode())) {
14590 0 : os << " {";
14591 : bool first_entry = true;
14592 0 : for (const auto& entry : iterator.GetJumpTableTargetOffsets()) {
14593 0 : if (first_entry) {
14594 : first_entry = false;
14595 : } else {
14596 0 : os << ",";
14597 : }
14598 0 : os << " " << entry.case_value << ": @" << entry.target_offset;
14599 : }
14600 0 : os << " }";
14601 : }
14602 : os << std::endl;
14603 0 : iterator.Advance();
14604 : }
14605 :
14606 0 : os << "Constant pool (size = " << constant_pool()->length() << ")\n";
14607 : #ifdef OBJECT_PRINT
14608 : if (constant_pool()->length() > 0) {
14609 : constant_pool()->Print();
14610 : }
14611 : #endif
14612 :
14613 0 : os << "Handler Table (size = " << handler_table()->Size() << ")\n";
14614 : #ifdef ENABLE_DISASSEMBLER
14615 : if (handler_table()->length() > 0) {
14616 : HandlerTable::cast(handler_table())->HandlerTableRangePrint(os);
14617 : }
14618 : #endif
14619 0 : }
14620 :
14621 8341 : void BytecodeArray::CopyBytecodesTo(BytecodeArray* to) {
14622 : BytecodeArray* from = this;
14623 : DCHECK_EQ(from->length(), to->length());
14624 8341 : CopyBytes(to->GetFirstBytecodeAddress(), from->GetFirstBytecodeAddress(),
14625 16682 : from->length());
14626 8341 : }
14627 :
14628 1616788 : void BytecodeArray::MakeOlder() {
14629 : // BytecodeArray is aged in concurrent marker.
14630 : // The word must be completely within the byte code array.
14631 1616788 : Address age_addr = address() + kBytecodeAgeOffset;
14632 : DCHECK_LE((reinterpret_cast<uintptr_t>(age_addr) & ~kPointerAlignmentMask) +
14633 : kPointerSize,
14634 : reinterpret_cast<uintptr_t>(address() + Size()));
14635 : Age age = bytecode_age();
14636 1616788 : if (age < kLastBytecodeAge) {
14637 1158062 : base::AsAtomic8::Release_CompareAndSwap(age_addr, age, age + 1);
14638 : }
14639 :
14640 : DCHECK_GE(bytecode_age(), kFirstBytecodeAge);
14641 : DCHECK_LE(bytecode_age(), kLastBytecodeAge);
14642 1616788 : }
14643 :
14644 0 : bool BytecodeArray::IsOld() const {
14645 0 : return bytecode_age() >= kIsOldBytecodeAge;
14646 : }
14647 :
14648 : // static
14649 89745 : void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
14650 : DCHECK_GE(capacity, 0);
14651 : array->GetIsolate()->factory()->NewJSArrayStorage(
14652 89745 : array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
14653 89745 : }
14654 :
14655 919774 : void JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) {
14656 : // We should never end in here with a pixel or external array.
14657 : DCHECK(array->AllowsSetLength());
14658 919774 : if (array->SetLengthWouldNormalize(new_length)) {
14659 1020 : JSObject::NormalizeElements(array);
14660 : }
14661 919774 : array->GetElementsAccessor()->SetLength(array, new_length);
14662 919774 : }
14663 :
14664 :
14665 : // static
14666 125062 : void Map::AddDependentCode(Handle<Map> map,
14667 : DependentCode::DependencyGroup group,
14668 : Handle<Code> code) {
14669 125062 : Handle<WeakCell> cell = Code::WeakCellFor(code);
14670 : Handle<DependentCode> codes = DependentCode::InsertWeakCode(
14671 : Handle<DependentCode>(map->dependent_code()), group, cell);
14672 125062 : if (*codes != map->dependent_code()) map->set_dependent_code(*codes);
14673 125062 : }
14674 :
14675 :
14676 739697 : Handle<DependentCode> DependentCode::InsertCompilationDependencies(
14677 : Handle<DependentCode> entries, DependencyGroup group,
14678 : Handle<Foreign> info) {
14679 739697 : return Insert(entries, group, info);
14680 : }
14681 :
14682 :
14683 491672 : Handle<DependentCode> DependentCode::InsertWeakCode(
14684 : Handle<DependentCode> entries, DependencyGroup group,
14685 : Handle<WeakCell> code_cell) {
14686 616734 : return Insert(entries, group, code_cell);
14687 : }
14688 :
14689 :
14690 1366388 : Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
14691 : DependencyGroup group,
14692 : Handle<Object> object) {
14693 2434188 : if (entries->length() == 0 || entries->group() > group) {
14694 : // There is no such group.
14695 310518 : return DependentCode::New(group, object, entries);
14696 : }
14697 1055870 : if (entries->group() < group) {
14698 : // The group comes later in the list.
14699 : Handle<DependentCode> old_next(entries->next_link());
14700 9957 : Handle<DependentCode> new_next = Insert(old_next, group, object);
14701 9957 : if (!old_next.is_identical_to(new_next)) {
14702 : entries->set_next_link(*new_next);
14703 : }
14704 9957 : return entries;
14705 : }
14706 : DCHECK_EQ(group, entries->group());
14707 : int count = entries->count();
14708 : // Check for existing entry to avoid duplicates.
14709 249702259 : for (int i = 0; i < count; i++) {
14710 249161414 : if (entries->object_at(i) == *object) return entries;
14711 : }
14712 1081690 : if (entries->length() < kCodesStartIndex + count + 1) {
14713 156543 : entries = EnsureSpace(entries);
14714 : // Count could have changed, reload it.
14715 : count = entries->count();
14716 : }
14717 : entries->set_object_at(count, *object);
14718 1081690 : entries->set_count(count + 1);
14719 540845 : return entries;
14720 : }
14721 :
14722 :
14723 310518 : Handle<DependentCode> DependentCode::New(DependencyGroup group,
14724 : Handle<Object> object,
14725 : Handle<DependentCode> next) {
14726 : Isolate* isolate = next->GetIsolate();
14727 : Handle<DependentCode> result = Handle<DependentCode>::cast(
14728 310518 : isolate->factory()->NewFixedArray(kCodesStartIndex + 1, TENURED));
14729 : result->set_next_link(*next);
14730 310518 : result->set_flags(GroupField::encode(group) | CountField::encode(1));
14731 : result->set_object_at(0, *object);
14732 310518 : return result;
14733 : }
14734 :
14735 :
14736 156543 : Handle<DependentCode> DependentCode::EnsureSpace(
14737 : Handle<DependentCode> entries) {
14738 156543 : if (entries->Compact()) return entries;
14739 : Isolate* isolate = entries->GetIsolate();
14740 154498 : int capacity = kCodesStartIndex + DependentCode::Grow(entries->count());
14741 154498 : int grow_by = capacity - entries->length();
14742 : return Handle<DependentCode>::cast(
14743 154498 : isolate->factory()->CopyFixedArrayAndGrow(entries, grow_by, TENURED));
14744 : }
14745 :
14746 :
14747 156543 : bool DependentCode::Compact() {
14748 : int old_count = count();
14749 : int new_count = 0;
14750 2360853 : for (int i = 0; i < old_count; i++) {
14751 : Object* obj = object_at(i);
14752 4407974 : if (!obj->IsWeakCell() || !WeakCell::cast(obj)->cleared()) {
14753 2181978 : if (i != new_count) {
14754 24034 : copy(i, new_count);
14755 : }
14756 2181978 : new_count++;
14757 : }
14758 : }
14759 156543 : set_count(new_count);
14760 178875 : for (int i = new_count; i < old_count; i++) {
14761 : clear_at(i);
14762 : }
14763 156543 : return new_count < old_count;
14764 : }
14765 :
14766 :
14767 731056 : void DependentCode::UpdateToFinishedCode(DependencyGroup group, Foreign* info,
14768 : WeakCell* code_cell) {
14769 1486760 : if (this->length() == 0 || this->group() > group) {
14770 : // There is no such group.
14771 : return;
14772 : }
14773 743380 : if (this->group() < group) {
14774 : // The group comes later in the list.
14775 : next_link()->UpdateToFinishedCode(group, info, code_cell);
14776 12324 : return;
14777 : }
14778 : DCHECK_EQ(group, this->group());
14779 : DisallowHeapAllocation no_gc;
14780 : int count = this->count();
14781 112477938 : for (int i = 0; i < count; i++) {
14782 112189113 : if (object_at(i) == info) {
14783 : set_object_at(i, code_cell);
14784 : break;
14785 : }
14786 : }
14787 : #ifdef DEBUG
14788 : for (int i = 0; i < count; i++) {
14789 : DCHECK(object_at(i) != info);
14790 : }
14791 : #endif
14792 : }
14793 :
14794 :
14795 8625 : void DependentCode::RemoveCompilationDependencies(
14796 : DependentCode::DependencyGroup group, Foreign* info) {
14797 17700 : if (this->length() == 0 || this->group() > group) {
14798 : // There is no such group.
14799 : return;
14800 : }
14801 8850 : if (this->group() < group) {
14802 : // The group comes later in the list.
14803 : next_link()->RemoveCompilationDependencies(group, info);
14804 225 : return;
14805 : }
14806 : DCHECK_EQ(group, this->group());
14807 : DisallowHeapAllocation no_allocation;
14808 : int old_count = count();
14809 : // Find compilation info wrapper.
14810 : int info_pos = -1;
14811 11376 : for (int i = 0; i < old_count; i++) {
14812 5345 : if (object_at(i) == info) {
14813 : info_pos = i;
14814 : break;
14815 : }
14816 : }
14817 8625 : if (info_pos == -1) return; // Not found.
14818 : // Use the last code to fill the gap.
14819 2594 : if (info_pos < old_count - 1) {
14820 46 : copy(old_count - 1, info_pos);
14821 : }
14822 : clear_at(old_count - 1);
14823 2594 : set_count(old_count - 1);
14824 :
14825 : #ifdef DEBUG
14826 : for (int i = 0; i < old_count - 1; i++) {
14827 : DCHECK(object_at(i) != info);
14828 : }
14829 : #endif
14830 : }
14831 :
14832 :
14833 0 : bool DependentCode::Contains(DependencyGroup group, WeakCell* code_cell) {
14834 0 : if (this->length() == 0 || this->group() > group) {
14835 : // There is no such group.
14836 : return false;
14837 : }
14838 0 : if (this->group() < group) {
14839 : // The group comes later in the list.
14840 0 : return next_link()->Contains(group, code_cell);
14841 : }
14842 : DCHECK_EQ(group, this->group());
14843 : int count = this->count();
14844 0 : for (int i = 0; i < count; i++) {
14845 0 : if (object_at(i) == code_cell) return true;
14846 : }
14847 : return false;
14848 : }
14849 :
14850 :
14851 125062 : bool DependentCode::IsEmpty(DependencyGroup group) {
14852 225011 : if (this->length() == 0 || this->group() > group) {
14853 : // There is no such group.
14854 : return true;
14855 : }
14856 90462 : if (this->group() < group) {
14857 : // The group comes later in the list.
14858 0 : return next_link()->IsEmpty(group);
14859 : }
14860 : DCHECK_EQ(group, this->group());
14861 90462 : return count() == 0;
14862 : }
14863 :
14864 :
14865 17852761 : bool DependentCode::MarkCodeForDeoptimization(
14866 : Isolate* isolate,
14867 : DependentCode::DependencyGroup group) {
14868 17884470 : if (this->length() == 0 || this->group() > group) {
14869 : // There is no such group.
14870 : return false;
14871 : }
14872 27865 : if (this->group() < group) {
14873 : // The group comes later in the list.
14874 3379 : return next_link()->MarkCodeForDeoptimization(isolate, group);
14875 : }
14876 : DCHECK_EQ(group, this->group());
14877 : DisallowHeapAllocation no_allocation_scope;
14878 : // Mark all the code that needs to be deoptimized.
14879 : bool marked = false;
14880 : bool invalidate_embedded_objects = group == kWeakCodeGroup;
14881 : int count = this->count();
14882 72266 : for (int i = 0; i < count; i++) {
14883 : Object* obj = object_at(i);
14884 47780 : if (obj->IsWeakCell()) {
14885 : WeakCell* cell = WeakCell::cast(obj);
14886 47666 : if (cell->cleared()) continue;
14887 : Code* code = Code::cast(cell->value());
14888 14072 : if (!code->marked_for_deoptimization()) {
14889 5970 : SetMarkedForDeoptimization(code, group);
14890 5970 : if (invalidate_embedded_objects) {
14891 2063 : code->InvalidateEmbeddedObjects();
14892 : }
14893 : marked = true;
14894 : }
14895 : } else {
14896 : DCHECK(obj->IsForeign());
14897 : CompilationDependencies* info =
14898 : reinterpret_cast<CompilationDependencies*>(
14899 : Foreign::cast(obj)->foreign_address());
14900 : info->Abort();
14901 : }
14902 : }
14903 47780 : for (int i = 0; i < count; i++) {
14904 : clear_at(i);
14905 : }
14906 24486 : set_count(0);
14907 24486 : return marked;
14908 : }
14909 :
14910 :
14911 17832590 : void DependentCode::DeoptimizeDependentCodeGroup(
14912 : Isolate* isolate,
14913 : DependentCode::DependencyGroup group) {
14914 : DisallowHeapAllocation no_allocation_scope;
14915 17832590 : bool marked = MarkCodeForDeoptimization(isolate, group);
14916 17832590 : if (marked) {
14917 : DCHECK(AllowCodeDependencyChange::IsAllowed());
14918 2135 : Deoptimizer::DeoptimizeMarkedCode(isolate);
14919 : }
14920 17832590 : }
14921 :
14922 :
14923 5985 : void DependentCode::SetMarkedForDeoptimization(Code* code,
14924 : DependencyGroup group) {
14925 : code->set_marked_for_deoptimization(true);
14926 5985 : if (FLAG_trace_deopt &&
14927 0 : (code->deoptimization_data() != code->GetHeap()->empty_fixed_array())) {
14928 : DeoptimizationData* deopt_data =
14929 : DeoptimizationData::cast(code->deoptimization_data());
14930 0 : CodeTracer::Scope scope(code->GetHeap()->isolate()->GetCodeTracer());
14931 : PrintF(scope.file(), "[marking dependent code 0x%08" V8PRIxPTR
14932 : " (opt #%d) for deoptimization, reason: %s]\n",
14933 : reinterpret_cast<intptr_t>(code),
14934 0 : deopt_data->OptimizationId()->value(), DependencyGroupName(group));
14935 : }
14936 5985 : }
14937 :
14938 :
14939 0 : const char* DependentCode::DependencyGroupName(DependencyGroup group) {
14940 0 : switch (group) {
14941 : case kWeakCodeGroup:
14942 : return "weak-code";
14943 : case kTransitionGroup:
14944 0 : return "transition";
14945 : case kPrototypeCheckGroup:
14946 0 : return "prototype-check";
14947 : case kPropertyCellChangedGroup:
14948 0 : return "property-cell-changed";
14949 : case kFieldOwnerGroup:
14950 0 : return "field-owner";
14951 : case kInitialMapChangedGroup:
14952 0 : return "initial-map-changed";
14953 : case kAllocationSiteTenuringChangedGroup:
14954 0 : return "allocation-site-tenuring-changed";
14955 : case kAllocationSiteTransitionChangedGroup:
14956 0 : return "allocation-site-transition-changed";
14957 : }
14958 0 : UNREACHABLE();
14959 : }
14960 :
14961 2650252 : Handle<Map> Map::TransitionToPrototype(Handle<Map> map,
14962 : Handle<Object> prototype) {
14963 : Handle<Map> new_map =
14964 2650252 : TransitionsAccessor(map).GetPrototypeTransition(prototype);
14965 2650252 : if (new_map.is_null()) {
14966 202818 : new_map = Copy(map, "TransitionToPrototype");
14967 202818 : TransitionsAccessor(map).PutPrototypeTransition(prototype, new_map);
14968 202818 : Map::SetPrototype(new_map, prototype);
14969 : }
14970 2650252 : return new_map;
14971 : }
14972 :
14973 :
14974 2666813 : Maybe<bool> JSReceiver::SetPrototype(Handle<JSReceiver> object,
14975 : Handle<Object> value, bool from_javascript,
14976 : ShouldThrow should_throw) {
14977 2666813 : if (object->IsJSProxy()) {
14978 : return JSProxy::SetPrototype(Handle<JSProxy>::cast(object), value,
14979 342 : from_javascript, should_throw);
14980 : }
14981 : return JSObject::SetPrototype(Handle<JSObject>::cast(object), value,
14982 2666471 : from_javascript, should_throw);
14983 : }
14984 :
14985 :
14986 : // ES6: 9.5.2 [[SetPrototypeOf]] (V)
14987 : // static
14988 342 : Maybe<bool> JSProxy::SetPrototype(Handle<JSProxy> proxy, Handle<Object> value,
14989 : bool from_javascript,
14990 : ShouldThrow should_throw) {
14991 : Isolate* isolate = proxy->GetIsolate();
14992 342 : STACK_CHECK(isolate, Nothing<bool>());
14993 : Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string();
14994 : // 1. Assert: Either Type(V) is Object or Type(V) is Null.
14995 : DCHECK(value->IsJSReceiver() || value->IsNull(isolate));
14996 : // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
14997 : Handle<Object> handler(proxy->handler(), isolate);
14998 : // 3. If handler is null, throw a TypeError exception.
14999 : // 4. Assert: Type(handler) is Object.
15000 342 : if (proxy->IsRevoked()) {
15001 : isolate->Throw(*isolate->factory()->NewTypeError(
15002 18 : MessageTemplate::kProxyRevoked, trap_name));
15003 : return Nothing<bool>();
15004 : }
15005 : // 5. Let target be the value of the [[ProxyTarget]] internal slot.
15006 : Handle<JSReceiver> target(proxy->target(), isolate);
15007 : // 6. Let trap be ? GetMethod(handler, "getPrototypeOf").
15008 : Handle<Object> trap;
15009 666 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15010 : isolate, trap,
15011 : Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
15012 : Nothing<bool>());
15013 : // 7. If trap is undefined, then return target.[[SetPrototypeOf]]().
15014 333 : if (trap->IsUndefined(isolate)) {
15015 : return JSReceiver::SetPrototype(target, value, from_javascript,
15016 234 : should_throw);
15017 : }
15018 : // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, V»)).
15019 99 : Handle<Object> argv[] = {target, value};
15020 : Handle<Object> trap_result;
15021 198 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15022 : isolate, trap_result,
15023 : Execution::Call(isolate, trap, handler, arraysize(argv), argv),
15024 : Nothing<bool>());
15025 90 : bool bool_trap_result = trap_result->BooleanValue();
15026 : // 9. If booleanTrapResult is false, return false.
15027 90 : if (!bool_trap_result) {
15028 90 : RETURN_FAILURE(
15029 : isolate, should_throw,
15030 : NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15031 : }
15032 : // 10. Let extensibleTarget be ? IsExtensible(target).
15033 54 : Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
15034 54 : if (is_extensible.IsNothing()) return Nothing<bool>();
15035 : // 11. If extensibleTarget is true, return true.
15036 54 : if (is_extensible.FromJust()) {
15037 27 : if (bool_trap_result) return Just(true);
15038 0 : RETURN_FAILURE(
15039 : isolate, should_throw,
15040 : NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15041 : }
15042 : // 12. Let targetProto be ? target.[[GetPrototypeOf]]().
15043 : Handle<Object> target_proto;
15044 54 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_proto,
15045 : JSReceiver::GetPrototype(isolate, target),
15046 : Nothing<bool>());
15047 : // 13. If SameValue(V, targetProto) is false, throw a TypeError exception.
15048 36 : if (bool_trap_result && !value->SameValue(*target_proto)) {
15049 : isolate->Throw(*isolate->factory()->NewTypeError(
15050 18 : MessageTemplate::kProxySetPrototypeOfNonExtensible));
15051 : return Nothing<bool>();
15052 : }
15053 : // 14. Return true.
15054 : return Just(true);
15055 : }
15056 :
15057 :
15058 2676186 : Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object,
15059 : Handle<Object> value, bool from_javascript,
15060 : ShouldThrow should_throw) {
15061 35 : Isolate* isolate = object->GetIsolate();
15062 :
15063 : #ifdef DEBUG
15064 : int size = object->Size();
15065 : #endif
15066 :
15067 2676186 : if (from_javascript) {
15068 204764 : if (object->IsAccessCheckNeeded() &&
15069 35 : !isolate->MayAccess(handle(isolate->context()), object)) {
15070 0 : isolate->ReportFailedAccessCheck(object);
15071 0 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
15072 0 : RETURN_FAILURE(isolate, should_throw,
15073 : NewTypeError(MessageTemplate::kNoAccess));
15074 : }
15075 : } else {
15076 : DCHECK(!object->IsAccessCheckNeeded());
15077 : }
15078 :
15079 : // Silently ignore the change if value is not a JSObject or null.
15080 : // SpiderMonkey behaves this way.
15081 5132140 : if (!value->IsJSReceiver() && !value->IsNull(isolate)) return Just(true);
15082 :
15083 : bool all_extensible = object->map()->is_extensible();
15084 : Handle<JSObject> real_receiver = object;
15085 2676171 : if (from_javascript) {
15086 : // Find the first object in the chain whose prototype object is not
15087 : // hidden.
15088 : PrototypeIterator iter(isolate, real_receiver, kStartAtPrototype,
15089 204729 : PrototypeIterator::END_AT_NON_HIDDEN);
15090 412587 : while (!iter.IsAtEnd()) {
15091 : // Casting to JSObject is fine because hidden prototypes are never
15092 : // JSProxies.
15093 : real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter);
15094 3129 : iter.Advance();
15095 6258 : all_extensible = all_extensible && real_receiver->map()->is_extensible();
15096 : }
15097 : }
15098 : Handle<Map> map(real_receiver->map());
15099 :
15100 : // Nothing to do if prototype is already set.
15101 2676171 : if (map->prototype() == *value) return Just(true);
15102 :
15103 : bool immutable_proto = map->is_immutable_proto();
15104 2649787 : if (immutable_proto) {
15105 177 : RETURN_FAILURE(
15106 : isolate, should_throw,
15107 : NewTypeError(MessageTemplate::kImmutablePrototypeSet, object));
15108 : }
15109 :
15110 : // From 8.6.2 Object Internal Methods
15111 : // ...
15112 : // In addition, if [[Extensible]] is false the value of the [[Class]] and
15113 : // [[Prototype]] internal properties of the object may not be modified.
15114 : // ...
15115 : // Implementation specific extensions that modify [[Class]], [[Prototype]]
15116 : // or [[Extensible]] must not violate the invariants defined in the preceding
15117 : // paragraph.
15118 2649722 : if (!all_extensible) {
15119 532 : RETURN_FAILURE(isolate, should_throw,
15120 : NewTypeError(MessageTemplate::kNonExtensibleProto, object));
15121 : }
15122 :
15123 : // Before we can set the prototype we need to be sure prototype cycles are
15124 : // prevented. It is sufficient to validate that the receiver is not in the
15125 : // new prototype chain.
15126 2649466 : if (value->IsJSReceiver()) {
15127 632756 : for (PrototypeIterator iter(isolate, JSReceiver::cast(*value),
15128 : kStartAtReceiver);
15129 439112 : !iter.IsAtEnd(); iter.Advance()) {
15130 878386 : if (iter.GetCurrent<JSReceiver>() == *object) {
15131 : // Cycle detected.
15132 207 : RETURN_FAILURE(isolate, should_throw,
15133 : NewTypeError(MessageTemplate::kCyclicProto));
15134 : }
15135 : }
15136 : }
15137 :
15138 : // Set the new prototype of the object.
15139 :
15140 : isolate->UpdateArrayProtectorOnSetPrototype(real_receiver);
15141 :
15142 2649385 : Handle<Map> new_map = Map::TransitionToPrototype(map, value);
15143 : DCHECK(new_map->prototype() == *value);
15144 2649385 : JSObject::MigrateToMap(real_receiver, new_map);
15145 :
15146 : DCHECK(size == object->Size());
15147 : return Just(true);
15148 : }
15149 :
15150 : // static
15151 24 : void JSObject::SetImmutableProto(Handle<JSObject> object) {
15152 : DCHECK(!object->IsAccessCheckNeeded()); // Never called from JS
15153 : Handle<Map> map(object->map());
15154 :
15155 : // Nothing to do if prototype is already set.
15156 42 : if (map->is_immutable_proto()) return;
15157 :
15158 6 : Handle<Map> new_map = Map::TransitionToImmutableProto(map);
15159 6 : object->synchronized_set_map(*new_map);
15160 : }
15161 :
15162 412214 : void JSObject::EnsureCanContainElements(Handle<JSObject> object,
15163 412214 : Arguments* args,
15164 : uint32_t first_arg,
15165 : uint32_t arg_count,
15166 : EnsureElementsMode mode) {
15167 : // Elements in |Arguments| are ordered backwards (because they're on the
15168 : // stack), but the method that's called here iterates over them in forward
15169 : // direction.
15170 : return EnsureCanContainElements(
15171 412214 : object, args->arguments() - first_arg - (arg_count - 1), arg_count, mode);
15172 : }
15173 :
15174 :
15175 341063661 : ElementsAccessor* JSObject::GetElementsAccessor() {
15176 341063661 : return ElementsAccessor::ForKind(GetElementsKind());
15177 : }
15178 :
15179 8735840 : void JSObject::ValidateElements(JSObject* object) {
15180 : #ifdef ENABLE_SLOW_DCHECKS
15181 : if (FLAG_enable_slow_asserts) {
15182 : object->GetElementsAccessor()->Validate(object);
15183 : }
15184 : #endif
15185 8735840 : }
15186 :
15187 :
15188 4536357 : static bool ShouldConvertToSlowElements(JSObject* object, uint32_t capacity,
15189 : uint32_t index,
15190 : uint32_t* new_capacity) {
15191 : STATIC_ASSERT(JSObject::kMaxUncheckedOldFastElementsLength <=
15192 : JSObject::kMaxUncheckedFastElementsLength);
15193 4536357 : if (index < capacity) {
15194 3947791 : *new_capacity = capacity;
15195 3947791 : return false;
15196 : }
15197 588566 : if (index - capacity >= JSObject::kMaxGap) return true;
15198 672278 : *new_capacity = JSObject::NewElementsCapacity(index + 1);
15199 : DCHECK_LT(index, *new_capacity);
15200 672278 : if (*new_capacity <= JSObject::kMaxUncheckedOldFastElementsLength ||
15201 46568 : (*new_capacity <= JSObject::kMaxUncheckedFastElementsLength &&
15202 : object->GetHeap()->InNewSpace(object))) {
15203 : return false;
15204 : }
15205 : // If the fast-case backing storage takes up much more memory than a
15206 : // dictionary backing storage would, the object should have slow elements.
15207 1446 : int used_elements = object->GetFastElementsUsage();
15208 : uint32_t size_threshold =
15209 : SeededNumberDictionary::kPreferFastElementsSizeFactor *
15210 1446 : SeededNumberDictionary::ComputeCapacity(used_elements) *
15211 1446 : SeededNumberDictionary::kEntrySize;
15212 1446 : return size_threshold <= *new_capacity;
15213 : }
15214 :
15215 :
15216 117372 : bool JSObject::WouldConvertToSlowElements(uint32_t index) {
15217 117372 : if (HasFastElements()) {
15218 : Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements()));
15219 16900 : uint32_t capacity = static_cast<uint32_t>(backing_store->length());
15220 : uint32_t new_capacity;
15221 16900 : return ShouldConvertToSlowElements(this, capacity, index, &new_capacity);
15222 : }
15223 : return false;
15224 : }
15225 :
15226 :
15227 566 : static ElementsKind BestFittingFastElementsKind(JSObject* object) {
15228 566 : if (object->HasSloppyArgumentsElements()) {
15229 : return FAST_SLOPPY_ARGUMENTS_ELEMENTS;
15230 : }
15231 566 : if (object->HasStringWrapperElements()) {
15232 : return FAST_STRING_WRAPPER_ELEMENTS;
15233 : }
15234 : DCHECK(object->HasDictionaryElements());
15235 : SeededNumberDictionary* dictionary = object->element_dictionary();
15236 : ElementsKind kind = HOLEY_SMI_ELEMENTS;
15237 2802120 : for (int i = 0; i < dictionary->Capacity(); i++) {
15238 : Object* key = dictionary->KeyAt(i);
15239 1400561 : if (key->IsNumber()) {
15240 466315 : Object* value = dictionary->ValueAt(i);
15241 466315 : if (!value->IsNumber()) return HOLEY_ELEMENTS;
15242 466258 : if (!value->IsSmi()) {
15243 13410 : if (!FLAG_unbox_double_arrays) return HOLEY_ELEMENTS;
15244 : kind = HOLEY_DOUBLE_ELEMENTS;
15245 : }
15246 : }
15247 : }
15248 : return kind;
15249 : }
15250 :
15251 :
15252 1281153 : static bool ShouldConvertToFastElements(JSObject* object,
15253 : SeededNumberDictionary* dictionary,
15254 : uint32_t index,
15255 : uint32_t* new_capacity) {
15256 : // If properties with non-standard attributes or accessors were added, we
15257 : // cannot go back to fast elements.
15258 1281153 : if (dictionary->requires_slow_elements()) return false;
15259 :
15260 : // Adding a property with this index will require slow elements.
15261 1253957 : if (index >= static_cast<uint32_t>(Smi::kMaxValue)) return false;
15262 :
15263 1253614 : if (object->IsJSArray()) {
15264 : Object* length = JSArray::cast(object)->length();
15265 614992 : if (!length->IsSmi()) return false;
15266 614152 : *new_capacity = static_cast<uint32_t>(Smi::ToInt(length));
15267 638622 : } else if (object->IsJSSloppyArgumentsObject()) {
15268 : return false;
15269 : } else {
15270 528506 : *new_capacity = dictionary->max_number_key() + 1;
15271 : }
15272 2285316 : *new_capacity = Max(index + 1, *new_capacity);
15273 :
15274 1142658 : uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
15275 1142658 : SeededNumberDictionary::kEntrySize;
15276 :
15277 : // Turn fast if the dictionary only saves 50% space.
15278 1142658 : return 2 * dictionary_size >= *new_capacity;
15279 : }
15280 :
15281 :
15282 : // static
15283 22809 : MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> object,
15284 : uint32_t index,
15285 : Handle<Object> value,
15286 : PropertyAttributes attributes) {
15287 22809 : MAYBE_RETURN_NULL(
15288 : AddDataElement(object, index, value, attributes, THROW_ON_ERROR));
15289 22809 : return value;
15290 : }
15291 :
15292 :
15293 : // static
15294 5830619 : Maybe<bool> JSObject::AddDataElement(Handle<JSObject> object, uint32_t index,
15295 : Handle<Object> value,
15296 : PropertyAttributes attributes,
15297 : ShouldThrow should_throw) {
15298 : DCHECK(object->map()->is_extensible());
15299 :
15300 : Isolate* isolate = object->GetIsolate();
15301 :
15302 5830619 : uint32_t old_length = 0;
15303 5830619 : uint32_t new_capacity = 0;
15304 :
15305 5830619 : if (object->IsJSArray()) {
15306 1828716 : CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length));
15307 : }
15308 :
15309 : ElementsKind kind = object->GetElementsKind();
15310 : FixedArrayBase* elements = object->elements();
15311 : ElementsKind dictionary_kind = DICTIONARY_ELEMENTS;
15312 5830619 : if (IsSloppyArgumentsElementsKind(kind)) {
15313 : elements = SloppyArgumentsElements::cast(elements)->arguments();
15314 : dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
15315 5697905 : } else if (IsStringWrapperElementsKind(kind)) {
15316 : dictionary_kind = SLOW_STRING_WRAPPER_ELEMENTS;
15317 : }
15318 :
15319 5830619 : if (attributes != NONE) {
15320 : kind = dictionary_kind;
15321 5799590 : } else if (elements->IsSeededNumberDictionary()) {
15322 : kind = ShouldConvertToFastElements(*object,
15323 : SeededNumberDictionary::cast(elements),
15324 1281153 : index, &new_capacity)
15325 : ? BestFittingFastElementsKind(*object)
15326 1281719 : : dictionary_kind;
15327 4518437 : } else if (ShouldConvertToSlowElements(
15328 : *object, static_cast<uint32_t>(elements->length()), index,
15329 4518437 : &new_capacity)) {
15330 : kind = dictionary_kind;
15331 : }
15332 :
15333 5830619 : ElementsKind to = value->OptimalElementsKind();
15334 6207974 : if (IsHoleyOrDictionaryElementsKind(kind) || !object->IsJSArray() ||
15335 72057 : index > old_length) {
15336 : to = GetHoleyElementsKind(to);
15337 : kind = GetHoleyElementsKind(kind);
15338 : }
15339 : to = GetMoreGeneralElementsKind(kind, to);
15340 : ElementsAccessor* accessor = ElementsAccessor::ForKind(to);
15341 5830619 : accessor->Add(object, index, value, attributes, new_capacity);
15342 :
15343 5830619 : if (object->IsJSArray() && index >= old_length) {
15344 : Handle<Object> new_length =
15345 1695378 : isolate->factory()->NewNumberFromUint(index + 1);
15346 1695378 : JSArray::cast(*object)->set_length(*new_length);
15347 : }
15348 :
15349 5830619 : return Just(true);
15350 : }
15351 :
15352 :
15353 919774 : bool JSArray::SetLengthWouldNormalize(uint32_t new_length) {
15354 919774 : if (!HasFastElements()) return false;
15355 901654 : uint32_t capacity = static_cast<uint32_t>(elements()->length());
15356 : uint32_t new_capacity;
15357 902674 : return JSArray::SetLengthWouldNormalize(GetHeap(), new_length) &&
15358 : ShouldConvertToSlowElements(this, capacity, new_length - 1,
15359 902674 : &new_capacity);
15360 : }
15361 :
15362 :
15363 : const double AllocationSite::kPretenureRatio = 0.85;
15364 :
15365 :
15366 0 : void AllocationSite::ResetPretenureDecision() {
15367 0 : set_pretenure_decision(kUndecided);
15368 0 : set_memento_found_count(0);
15369 : set_memento_create_count(0);
15370 0 : }
15371 :
15372 8606 : PretenureFlag AllocationSite::GetPretenureMode() const {
15373 : PretenureDecision mode = pretenure_decision();
15374 : // Zombie objects "decide" to be untenured.
15375 8606 : return mode == kTenure ? TENURED : NOT_TENURED;
15376 : }
15377 :
15378 0 : bool AllocationSite::IsNested() {
15379 : DCHECK(FLAG_trace_track_allocation_sites);
15380 0 : Object* current = GetHeap()->allocation_sites_list();
15381 0 : while (current->IsAllocationSite()) {
15382 : AllocationSite* current_site = AllocationSite::cast(current);
15383 0 : if (current_site->nested_site() == this) {
15384 : return true;
15385 : }
15386 : current = current_site->weak_next();
15387 : }
15388 : return false;
15389 : }
15390 :
15391 : template <AllocationSiteUpdateMode update_or_check>
15392 546852 : bool AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
15393 : ElementsKind to_kind) {
15394 : Isolate* isolate = site->GetIsolate();
15395 : bool result = false;
15396 :
15397 573663 : if (site->PointsToLiteral() && site->boilerplate()->IsJSArray()) {
15398 : Handle<JSArray> boilerplate(JSArray::cast(site->boilerplate()), isolate);
15399 : ElementsKind kind = boilerplate->GetElementsKind();
15400 : // if kind is holey ensure that to_kind is as well.
15401 26811 : if (IsHoleyOrDictionaryElementsKind(kind)) {
15402 : to_kind = GetHoleyElementsKind(to_kind);
15403 : }
15404 26811 : if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
15405 : // If the array is huge, it's not likely to be defined in a local
15406 : // function, so we shouldn't make new instances of it very often.
15407 16512 : uint32_t length = 0;
15408 16512 : CHECK(boilerplate->length()->ToArrayLength(&length));
15409 16512 : if (length <= kMaximumArrayBytesToPretransition) {
15410 : if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) {
15411 0 : return true;
15412 : }
15413 16512 : if (FLAG_trace_track_allocation_sites) {
15414 0 : bool is_nested = site->IsNested();
15415 0 : PrintF("AllocationSite: JSArray %p boilerplate %supdated %s->%s\n",
15416 : reinterpret_cast<void*>(*site), is_nested ? "(nested)" : " ",
15417 0 : ElementsKindToString(kind), ElementsKindToString(to_kind));
15418 : }
15419 16512 : JSObject::TransitionElementsKind(boilerplate, to_kind);
15420 16512 : site->dependent_code()->DeoptimizeDependentCodeGroup(
15421 : isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
15422 : result = true;
15423 : }
15424 : }
15425 : } else {
15426 : // The AllocationSite is for a constructed Array.
15427 : ElementsKind kind = site->GetElementsKind();
15428 : // if kind is holey ensure that to_kind is as well.
15429 520041 : if (IsHoleyOrDictionaryElementsKind(kind)) {
15430 : to_kind = GetHoleyElementsKind(to_kind);
15431 : }
15432 520041 : if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
15433 : if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) return true;
15434 18838 : if (FLAG_trace_track_allocation_sites) {
15435 0 : PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
15436 : reinterpret_cast<void*>(*site),
15437 : ElementsKindToString(kind),
15438 0 : ElementsKindToString(to_kind));
15439 : }
15440 18838 : site->SetElementsKind(to_kind);
15441 18838 : site->dependent_code()->DeoptimizeDependentCodeGroup(
15442 : isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
15443 : result = true;
15444 : }
15445 : }
15446 : return result;
15447 : }
15448 :
15449 1314 : bool AllocationSite::ShouldTrack(ElementsKind from, ElementsKind to) {
15450 2292 : return IsSmiElementsKind(from) &&
15451 2292 : IsMoreGeneralElementsKindTransition(from, to);
15452 : }
15453 :
15454 0 : const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) {
15455 0 : switch (decision) {
15456 : case kUndecided: return "undecided";
15457 0 : case kDontTenure: return "don't tenure";
15458 0 : case kMaybeTenure: return "maybe tenure";
15459 0 : case kTenure: return "tenure";
15460 0 : case kZombie: return "zombie";
15461 0 : default: UNREACHABLE();
15462 : }
15463 : return nullptr;
15464 : }
15465 :
15466 : template <AllocationSiteUpdateMode update_or_check>
15467 951460 : bool JSObject::UpdateAllocationSite(Handle<JSObject> object,
15468 : ElementsKind to_kind) {
15469 951460 : if (!object->IsJSArray()) return false;
15470 :
15471 : Heap* heap = object->GetHeap();
15472 674715 : if (!heap->InNewSpace(*object)) return false;
15473 :
15474 : Handle<AllocationSite> site;
15475 : {
15476 : DisallowHeapAllocation no_allocation;
15477 :
15478 : AllocationMemento* memento =
15479 654211 : heap->FindAllocationMemento<Heap::kForRuntime>(object->map(), *object);
15480 654211 : if (memento == nullptr) return false;
15481 :
15482 : // Walk through to the Allocation Site
15483 546852 : site = handle(memento->GetAllocationSite());
15484 : }
15485 : return AllocationSite::DigestTransitionFeedback<update_or_check>(site,
15486 546852 : to_kind);
15487 : }
15488 :
15489 : template bool
15490 : JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kCheckOnly>(
15491 : Handle<JSObject> object, ElementsKind to_kind);
15492 :
15493 : template bool JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kUpdate>(
15494 : Handle<JSObject> object, ElementsKind to_kind);
15495 :
15496 149966 : void JSObject::TransitionElementsKind(Handle<JSObject> object,
15497 : ElementsKind to_kind) {
15498 : ElementsKind from_kind = object->GetElementsKind();
15499 :
15500 149966 : if (IsHoleyElementsKind(from_kind)) {
15501 : to_kind = GetHoleyElementsKind(to_kind);
15502 : }
15503 :
15504 299932 : if (from_kind == to_kind) return;
15505 :
15506 : // This method should never be called for any other case.
15507 : DCHECK(IsFastElementsKind(from_kind));
15508 : DCHECK(IsFastElementsKind(to_kind));
15509 : DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind);
15510 :
15511 149911 : UpdateAllocationSite(object, to_kind);
15512 297075 : if (object->elements() == object->GetHeap()->empty_fixed_array() ||
15513 : IsDoubleElementsKind(from_kind) == IsDoubleElementsKind(to_kind)) {
15514 : // No change is needed to the elements() buffer, the transition
15515 : // only requires a map change.
15516 143919 : Handle<Map> new_map = GetElementsTransitionMap(object, to_kind);
15517 143919 : MigrateToMap(object, new_map);
15518 : if (FLAG_trace_elements_transitions) {
15519 : Handle<FixedArrayBase> elms(object->elements());
15520 : PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms);
15521 : }
15522 : } else {
15523 : DCHECK((IsSmiElementsKind(from_kind) && IsDoubleElementsKind(to_kind)) ||
15524 : (IsDoubleElementsKind(from_kind) && IsObjectElementsKind(to_kind)));
15525 5992 : uint32_t c = static_cast<uint32_t>(object->elements()->length());
15526 5992 : ElementsAccessor::ForKind(to_kind)->GrowCapacityAndConvert(object, c);
15527 : }
15528 : }
15529 :
15530 :
15531 : // static
15532 0 : bool Map::IsValidElementsTransition(ElementsKind from_kind,
15533 : ElementsKind to_kind) {
15534 : // Transitions can't go backwards.
15535 0 : if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
15536 : return false;
15537 : }
15538 :
15539 : // Transitions from HOLEY -> PACKED are not allowed.
15540 0 : return !IsHoleyElementsKind(from_kind) || IsHoleyElementsKind(to_kind);
15541 : }
15542 :
15543 :
15544 9220908 : bool JSArray::HasReadOnlyLength(Handle<JSArray> array) {
15545 : Map* map = array->map();
15546 : // Fast path: "length" is the first fast property of arrays. Since it's not
15547 : // configurable, it's guaranteed to be the first in the descriptor array.
15548 9220908 : if (!map->is_dictionary_map()) {
15549 : DCHECK(map->instance_descriptors()->GetKey(0) ==
15550 : array->GetHeap()->length_string());
15551 18417054 : return map->instance_descriptors()->GetDetails(0).IsReadOnly();
15552 : }
15553 :
15554 : Isolate* isolate = array->GetIsolate();
15555 : LookupIterator it(array, isolate->factory()->length_string(), array,
15556 12381 : LookupIterator::OWN_SKIP_INTERCEPTOR);
15557 12381 : CHECK_EQ(LookupIterator::ACCESSOR, it.state());
15558 12381 : return it.IsReadOnly();
15559 : }
15560 :
15561 :
15562 1806226 : bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array,
15563 : uint32_t index) {
15564 1806226 : uint32_t length = 0;
15565 1806226 : CHECK(array->length()->ToArrayLength(&length));
15566 1806226 : if (length <= index) return HasReadOnlyLength(array);
15567 : return false;
15568 : }
15569 :
15570 : template <typename BackingStore>
15571 284670 : static int HoleyElementsUsage(JSObject* object, BackingStore* store) {
15572 : Isolate* isolate = store->GetIsolate();
15573 : int limit = object->IsJSArray() ? Smi::ToInt(JSArray::cast(object)->length())
15574 284670 : : store->length();
15575 : int used = 0;
15576 370638539 : for (int i = 0; i < limit; ++i) {
15577 370353869 : if (!store->is_the_hole(isolate, i)) ++used;
15578 : }
15579 284670 : return used;
15580 : }
15581 :
15582 304659 : int JSObject::GetFastElementsUsage() {
15583 : FixedArrayBase* store = elements();
15584 304659 : switch (GetElementsKind()) {
15585 : case PACKED_SMI_ELEMENTS:
15586 : case PACKED_DOUBLE_ELEMENTS:
15587 : case PACKED_ELEMENTS:
15588 : return IsJSArray() ? Smi::ToInt(JSArray::cast(this)->length())
15589 39918 : : store->length();
15590 : case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
15591 : store = SloppyArgumentsElements::cast(store)->arguments();
15592 : // Fall through.
15593 : case HOLEY_SMI_ELEMENTS:
15594 : case HOLEY_ELEMENTS:
15595 : case FAST_STRING_WRAPPER_ELEMENTS:
15596 284563 : return HoleyElementsUsage(this, FixedArray::cast(store));
15597 : case HOLEY_DOUBLE_ELEMENTS:
15598 137 : if (elements()->length() == 0) return 0;
15599 107 : return HoleyElementsUsage(this, FixedDoubleArray::cast(store));
15600 :
15601 : case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
15602 : case SLOW_STRING_WRAPPER_ELEMENTS:
15603 : case DICTIONARY_ELEMENTS:
15604 : case NO_ELEMENTS:
15605 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
15606 : case TYPE##_ELEMENTS: \
15607 :
15608 : TYPED_ARRAYS(TYPED_ARRAY_CASE)
15609 : #undef TYPED_ARRAY_CASE
15610 0 : UNREACHABLE();
15611 : }
15612 : return 0;
15613 : }
15614 :
15615 :
15616 : // Certain compilers request function template instantiation when they
15617 : // see the definition of the other template functions in the
15618 : // class. This requires us to have the template functions put
15619 : // together, so even though this function belongs in objects-debug.cc,
15620 : // we keep it here instead to satisfy certain compilers.
15621 : #ifdef OBJECT_PRINT
15622 : template <typename Derived, typename Shape>
15623 : void Dictionary<Derived, Shape>::Print(std::ostream& os) {
15624 : DisallowHeapAllocation no_gc;
15625 : Isolate* isolate = this->GetIsolate();
15626 : Derived* dictionary = Derived::cast(this);
15627 : int capacity = dictionary->Capacity();
15628 : for (int i = 0; i < capacity; i++) {
15629 : Object* k = dictionary->KeyAt(i);
15630 : if (!Shape::IsLive(isolate, k)) continue;
15631 : if (!dictionary->ToKey(isolate, i, &k)) continue;
15632 : os << "\n ";
15633 : if (k->IsString()) {
15634 : String::cast(k)->StringPrint(os);
15635 : } else {
15636 : os << Brief(k);
15637 : }
15638 : os << ": " << Brief(dictionary->ValueAt(i)) << " ";
15639 : dictionary->DetailsAt(i).PrintAsSlowTo(os);
15640 : }
15641 : }
15642 : template <typename Derived, typename Shape>
15643 : void Dictionary<Derived, Shape>::Print() {
15644 : OFStream os(stdout);
15645 : Print(os);
15646 : }
15647 : #endif
15648 :
15649 :
15650 13969 : MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it,
15651 : bool* done) {
15652 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
15653 13969 : return GetPropertyWithInterceptorInternal(it, it->GetInterceptor(), done);
15654 : }
15655 :
15656 42331931 : Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object,
15657 : Handle<Name> name) {
15658 : LookupIterator it = LookupIterator::PropertyOrElement(
15659 42331931 : name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
15660 42331931 : return HasProperty(&it);
15661 : }
15662 :
15663 :
15664 17 : Maybe<bool> JSObject::HasRealElementProperty(Handle<JSObject> object,
15665 : uint32_t index) {
15666 : Isolate* isolate = object->GetIsolate();
15667 : LookupIterator it(isolate, object, index, object,
15668 : LookupIterator::OWN_SKIP_INTERCEPTOR);
15669 17 : return HasProperty(&it);
15670 : }
15671 :
15672 :
15673 5 : Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
15674 : Handle<Name> name) {
15675 : LookupIterator it = LookupIterator::PropertyOrElement(
15676 5 : name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
15677 5 : Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
15678 5 : return maybe_result.IsJust() ? Just(it.state() == LookupIterator::ACCESSOR)
15679 10 : : Nothing<bool>();
15680 : }
15681 :
15682 2031 : int FixedArrayBase::GetMaxLengthForNewSpaceAllocation(ElementsKind kind) {
15683 : return ((kMaxRegularHeapObjectSize - FixedArrayBase::kHeaderSize) >>
15684 2031 : ElementsKindToShiftSize(kind));
15685 : }
15686 :
15687 1243 : bool FixedArrayBase::IsCowArray() const {
15688 1243 : return map() == GetHeap()->fixed_cow_array_map();
15689 : }
15690 :
15691 31702 : bool JSObject::WasConstructedFromApiFunction() {
15692 : auto instance_type = map()->instance_type();
15693 31702 : bool is_api_object = instance_type == JS_API_OBJECT_TYPE ||
15694 31702 : instance_type == JS_SPECIAL_API_OBJECT_TYPE;
15695 : bool is_wasm_object =
15696 : instance_type == WASM_MEMORY_TYPE || instance_type == WASM_MODULE_TYPE ||
15697 : instance_type == WASM_INSTANCE_TYPE || instance_type == WASM_TABLE_TYPE;
15698 : #ifdef ENABLE_SLOW_DCHECKS
15699 : if (FLAG_enable_slow_asserts) {
15700 : Object* maybe_constructor = map()->GetConstructor();
15701 : if (maybe_constructor->IsJSFunction()) {
15702 : JSFunction* constructor = JSFunction::cast(maybe_constructor);
15703 : DCHECK_EQ(constructor->shared()->IsApiFunction(),
15704 : is_api_object || is_wasm_object);
15705 : } else if (maybe_constructor->IsFunctionTemplateInfo()) {
15706 : DCHECK(is_api_object || is_wasm_object);
15707 : } else {
15708 : return false;
15709 : }
15710 : }
15711 : #endif
15712 : // TODO(titzer): Clean this up somehow. WebAssembly objects should not be
15713 : // considered "constructed from API functions" even though they have
15714 : // function template info, since that would make the V8 GC identify them to
15715 : // the embedder, e.g. the Oilpan GC.
15716 : USE(is_wasm_object);
15717 31702 : return is_api_object;
15718 : }
15719 :
15720 180 : const char* Symbol::PrivateSymbolToName() const {
15721 6840 : Heap* heap = GetIsolate()->heap();
15722 : #define SYMBOL_CHECK_AND_PRINT(name) \
15723 : if (this == heap->name()) return #name;
15724 6840 : PRIVATE_SYMBOL_LIST(SYMBOL_CHECK_AND_PRINT)
15725 : #undef SYMBOL_CHECK_AND_PRINT
15726 180 : return "UNKNOWN";
15727 : }
15728 :
15729 :
15730 192 : void Symbol::SymbolShortPrint(std::ostream& os) {
15731 192 : os << "<Symbol:";
15732 192 : if (!name()->IsUndefined(GetIsolate())) {
15733 12 : os << " ";
15734 : HeapStringAllocator allocator;
15735 : StringStream accumulator(&allocator);
15736 12 : String::cast(name())->StringShortPrint(&accumulator, false);
15737 36 : os << accumulator.ToCString().get();
15738 : } else {
15739 180 : os << " (" << PrivateSymbolToName() << ")";
15740 : }
15741 192 : os << ">";
15742 192 : }
15743 :
15744 :
15745 : // StringSharedKeys are used as keys in the eval cache.
15746 0 : class StringSharedKey : public HashTableKey {
15747 : public:
15748 : // This tuple unambiguously identifies calls to eval() or
15749 : // CreateDynamicFunction() (such as through the Function() constructor).
15750 : // * source is the string passed into eval(). For dynamic functions, this is
15751 : // the effective source for the function, some of which is implicitly
15752 : // generated.
15753 : // * shared is the shared function info for the function containing the call
15754 : // to eval(). for dynamic functions, shared is the native context closure.
15755 : // * When positive, position is the position in the source where eval is
15756 : // called. When negative, position is the negation of the position in the
15757 : // dynamic function's effective source where the ')' ends the parameters.
15758 5151455 : StringSharedKey(Handle<String> source, Handle<SharedFunctionInfo> shared,
15759 : LanguageMode language_mode, int position)
15760 : : HashTableKey(CompilationCacheShape::StringSharedHash(
15761 : *source, *shared, language_mode, position)),
15762 : source_(source),
15763 : shared_(shared),
15764 : language_mode_(language_mode),
15765 10302910 : position_(position) {}
15766 :
15767 6325764 : bool IsMatch(Object* other) override {
15768 : DisallowHeapAllocation no_allocation;
15769 6325764 : if (!other->IsFixedArray()) {
15770 : DCHECK(other->IsNumber());
15771 1994352 : uint32_t other_hash = static_cast<uint32_t>(other->Number());
15772 1994352 : return Hash() == other_hash;
15773 : }
15774 : FixedArray* other_array = FixedArray::cast(other);
15775 : SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
15776 4331412 : if (shared != *shared_) return false;
15777 : int language_unchecked = Smi::ToInt(other_array->get(2));
15778 : DCHECK(is_valid_language_mode(language_unchecked));
15779 4161951 : LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
15780 4161951 : if (language_mode != language_mode_) return false;
15781 : int position = Smi::ToInt(other_array->get(3));
15782 4149117 : if (position != position_) return false;
15783 : String* source = String::cast(other_array->get(1));
15784 4149100 : return source->Equals(*source_);
15785 : }
15786 :
15787 1319908 : Handle<Object> AsHandle(Isolate* isolate) {
15788 1319908 : Handle<FixedArray> array = isolate->factory()->NewFixedArray(4);
15789 1319908 : array->set(0, *shared_);
15790 1319908 : array->set(1, *source_);
15791 1319908 : array->set(2, Smi::FromEnum(language_mode_));
15792 1319908 : array->set(3, Smi::FromInt(position_));
15793 2639816 : array->set_map(isolate->heap()->fixed_cow_array_map());
15794 1319908 : return array;
15795 : }
15796 :
15797 : private:
15798 : Handle<String> source_;
15799 : Handle<SharedFunctionInfo> shared_;
15800 : LanguageMode language_mode_;
15801 : int position_;
15802 : };
15803 :
15804 290 : v8::Promise::PromiseState JSPromise::status() const {
15805 290 : int value = flags() & kStatusMask;
15806 : DCHECK(value == 0 || value == 1 || value == 2);
15807 290 : return static_cast<v8::Promise::PromiseState>(value);
15808 : }
15809 :
15810 : // static
15811 25 : const char* JSPromise::Status(v8::Promise::PromiseState status) {
15812 25 : switch (status) {
15813 : case v8::Promise::kFulfilled:
15814 : return "resolved";
15815 : case v8::Promise::kPending:
15816 10 : return "pending";
15817 : case v8::Promise::kRejected:
15818 0 : return "rejected";
15819 : }
15820 0 : UNREACHABLE();
15821 : }
15822 :
15823 : namespace {
15824 :
15825 418560 : JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags, bool* success) {
15826 : JSRegExp::Flags value = JSRegExp::kNone;
15827 : int length = flags->length();
15828 : // A longer flags string cannot be valid.
15829 418560 : if (length > JSRegExp::FlagCount()) return JSRegExp::Flags(0);
15830 87040 : for (int i = 0; i < length; i++) {
15831 : JSRegExp::Flag flag = JSRegExp::kNone;
15832 87198 : switch (flags->Get(i)) {
15833 : case 'g':
15834 : flag = JSRegExp::kGlobal;
15835 : break;
15836 : case 'i':
15837 : flag = JSRegExp::kIgnoreCase;
15838 73082 : break;
15839 : case 'm':
15840 : flag = JSRegExp::kMultiline;
15841 464 : break;
15842 : case 's':
15843 36 : if (FLAG_harmony_regexp_dotall) {
15844 : flag = JSRegExp::kDotAll;
15845 : } else {
15846 0 : return JSRegExp::Flags(0);
15847 : }
15848 : break;
15849 : case 'u':
15850 : flag = JSRegExp::kUnicode;
15851 1180 : break;
15852 : case 'y':
15853 : flag = JSRegExp::kSticky;
15854 125 : break;
15855 : default:
15856 19 : return JSRegExp::Flags(0);
15857 : }
15858 : // Duplicate flag.
15859 87179 : if (value & flag) return JSRegExp::Flags(0);
15860 : value |= flag;
15861 : }
15862 418402 : *success = true;
15863 418402 : return value;
15864 : }
15865 :
15866 : } // namespace
15867 :
15868 :
15869 : // static
15870 99965 : MaybeHandle<JSRegExp> JSRegExp::New(Handle<String> pattern, Flags flags) {
15871 : Isolate* isolate = pattern->GetIsolate();
15872 99965 : Handle<JSFunction> constructor = isolate->regexp_function();
15873 : Handle<JSRegExp> regexp =
15874 99965 : Handle<JSRegExp>::cast(isolate->factory()->NewJSObject(constructor));
15875 :
15876 99965 : return JSRegExp::Initialize(regexp, pattern, flags);
15877 : }
15878 :
15879 :
15880 : // static
15881 15754 : Handle<JSRegExp> JSRegExp::Copy(Handle<JSRegExp> regexp) {
15882 : Isolate* const isolate = regexp->GetIsolate();
15883 15754 : return Handle<JSRegExp>::cast(isolate->factory()->CopyJSObject(regexp));
15884 : }
15885 :
15886 :
15887 : template <typename Char>
15888 518367 : inline int CountRequiredEscapes(Handle<String> source) {
15889 : DisallowHeapAllocation no_gc;
15890 : int escapes = 0;
15891 : Vector<const Char> src = source->GetCharVector<Char>();
15892 21498062736 : for (int i = 0; i < src.length(); i++) {
15893 21497026002 : if (src[i] == '\\') {
15894 : // Escape. Skip next character;
15895 113730 : i++;
15896 10748399271 : } else if (src[i] == '/') {
15897 : // Not escaped forward-slash needs escape.
15898 1755 : escapes++;
15899 : }
15900 : }
15901 518367 : return escapes;
15902 : }
15903 :
15904 :
15905 : template <typename Char, typename StringType>
15906 637 : inline Handle<StringType> WriteEscapedRegExpSource(Handle<String> source,
15907 : Handle<StringType> result) {
15908 : DisallowHeapAllocation no_gc;
15909 : Vector<const Char> src = source->GetCharVector<Char>();
15910 637 : Vector<Char> dst(result->GetChars(), result->length());
15911 : int s = 0;
15912 : int d = 0;
15913 35076 : while (s < src.length()) {
15914 67604 : if (src[s] == '\\') {
15915 : // Escape. Copy this and next character.
15916 4126 : dst[d++] = src[s++];
15917 2063 : if (s == src.length()) break;
15918 31739 : } else if (src[s] == '/') {
15919 : // Not escaped forward-slash needs escape.
15920 3510 : dst[d++] = '\\';
15921 : }
15922 101406 : dst[d++] = src[s++];
15923 : }
15924 : DCHECK_EQ(result->length(), d);
15925 637 : return result;
15926 : }
15927 :
15928 :
15929 518367 : MaybeHandle<String> EscapeRegExpSource(Isolate* isolate,
15930 : Handle<String> source) {
15931 : DCHECK(source->IsFlat());
15932 518367 : if (source->length() == 0) return isolate->factory()->query_colon_string();
15933 518367 : bool one_byte = source->IsOneByteRepresentationUnderneath();
15934 : int escapes = one_byte ? CountRequiredEscapes<uint8_t>(source)
15935 518367 : : CountRequiredEscapes<uc16>(source);
15936 518367 : if (escapes == 0) return source;
15937 637 : int length = source->length() + escapes;
15938 637 : if (one_byte) {
15939 : Handle<SeqOneByteString> result;
15940 1258 : ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
15941 : isolate->factory()->NewRawOneByteString(length),
15942 : String);
15943 629 : return WriteEscapedRegExpSource<uint8_t>(source, result);
15944 : } else {
15945 : Handle<SeqTwoByteString> result;
15946 16 : ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
15947 : isolate->factory()->NewRawTwoByteString(length),
15948 : String);
15949 8 : return WriteEscapedRegExpSource<uc16>(source, result);
15950 : }
15951 : }
15952 :
15953 :
15954 : // static
15955 418560 : MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
15956 : Handle<String> source,
15957 : Handle<String> flags_string) {
15958 : Isolate* isolate = source->GetIsolate();
15959 418560 : bool success = false;
15960 418560 : Flags flags = RegExpFlagsFromString(flags_string, &success);
15961 418560 : if (!success) {
15962 316 : THROW_NEW_ERROR(
15963 : isolate,
15964 : NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string),
15965 : JSRegExp);
15966 : }
15967 418402 : return Initialize(regexp, source, flags);
15968 : }
15969 :
15970 :
15971 : // static
15972 518367 : MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
15973 : Handle<String> source, Flags flags) {
15974 : Isolate* isolate = regexp->GetIsolate();
15975 : Factory* factory = isolate->factory();
15976 : // If source is the empty string we set it to "(?:)" instead as
15977 : // suggested by ECMA-262, 5th, section 15.10.4.1.
15978 518367 : if (source->length() == 0) source = factory->query_colon_string();
15979 :
15980 518367 : source = String::Flatten(source);
15981 :
15982 : Handle<String> escaped_source;
15983 1036734 : ASSIGN_RETURN_ON_EXCEPTION(isolate, escaped_source,
15984 : EscapeRegExpSource(isolate, source), JSRegExp);
15985 :
15986 1036734 : RETURN_ON_EXCEPTION(isolate, RegExpImpl::Compile(regexp, source, flags),
15987 : JSRegExp);
15988 :
15989 515911 : regexp->set_source(*escaped_source);
15990 515911 : regexp->set_flags(Smi::FromInt(flags));
15991 :
15992 : Map* map = regexp->map();
15993 515911 : Object* constructor = map->GetConstructor();
15994 1031822 : if (constructor->IsJSFunction() &&
15995 : JSFunction::cast(constructor)->initial_map() == map) {
15996 : // If we still have the original map, set in-object properties directly.
15997 : regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, Smi::kZero,
15998 515702 : SKIP_WRITE_BARRIER);
15999 : } else {
16000 : // Map has changed, so use generic, but slower, method.
16001 418 : RETURN_ON_EXCEPTION(
16002 : isolate,
16003 : JSReceiver::SetProperty(regexp, factory->lastIndex_string(),
16004 : Handle<Smi>(Smi::kZero, isolate),
16005 : LanguageMode::kStrict),
16006 : JSRegExp);
16007 : }
16008 :
16009 515911 : return regexp;
16010 : }
16011 :
16012 :
16013 : // RegExpKey carries the source and flags of a regular expression as key.
16014 0 : class RegExpKey : public HashTableKey {
16015 : public:
16016 : RegExpKey(Handle<String> string, JSRegExp::Flags flags)
16017 : : HashTableKey(
16018 : CompilationCacheShape::RegExpHash(*string, Smi::FromInt(flags))),
16019 : string_(string),
16020 1909128 : flags_(Smi::FromInt(flags)) {}
16021 :
16022 : // Rather than storing the key in the hash table, a pointer to the
16023 : // stored value is stored where the key should be. IsMatch then
16024 : // compares the search key to the found object, rather than comparing
16025 : // a key to a key.
16026 652889 : bool IsMatch(Object* obj) override {
16027 : FixedArray* val = FixedArray::cast(obj);
16028 652889 : return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
16029 870465 : && (flags_ == val->get(JSRegExp::kFlagsIndex));
16030 : }
16031 :
16032 : Handle<String> string_;
16033 : Smi* flags_;
16034 : };
16035 :
16036 39153 : Handle<String> OneByteStringKey::AsHandle(Isolate* isolate) {
16037 39153 : return isolate->factory()->NewOneByteInternalizedString(string_, HashField());
16038 : }
16039 :
16040 0 : Handle<String> TwoByteStringKey::AsHandle(Isolate* isolate) {
16041 0 : return isolate->factory()->NewTwoByteInternalizedString(string_, HashField());
16042 : }
16043 :
16044 112004 : Handle<String> SeqOneByteSubStringKey::AsHandle(Isolate* isolate) {
16045 : return isolate->factory()->NewOneByteInternalizedSubString(
16046 112004 : string_, from_, length_, HashField());
16047 : }
16048 :
16049 :
16050 73858 : bool SeqOneByteSubStringKey::IsMatch(Object* string) {
16051 147716 : Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
16052 73858 : return String::cast(string)->IsOneByteEqualTo(chars);
16053 : }
16054 :
16055 :
16056 : // InternalizedStringKey carries a string/internalized-string object as key.
16057 0 : class InternalizedStringKey : public StringTableKey {
16058 : public:
16059 12002528 : explicit InternalizedStringKey(Handle<String> string)
16060 12002528 : : StringTableKey(0), string_(string) {
16061 : DCHECK(!string->IsInternalizedString());
16062 : DCHECK(string->IsFlat());
16063 : // Make sure hash_field is computed.
16064 12002528 : string->Hash();
16065 : set_hash_field(string->hash_field());
16066 12002528 : }
16067 :
16068 13705434 : bool IsMatch(Object* string) override {
16069 13705434 : return string_->SlowEquals(String::cast(string));
16070 : }
16071 :
16072 1924115 : Handle<String> AsHandle(Isolate* isolate) override {
16073 : // Internalize the string if possible.
16074 : MaybeHandle<Map> maybe_map =
16075 1924115 : isolate->factory()->InternalizedStringMapForString(string_);
16076 : Handle<Map> map;
16077 1924115 : if (maybe_map.ToHandle(&map)) {
16078 : string_->set_map_no_write_barrier(*map);
16079 : DCHECK(string_->IsInternalizedString());
16080 9589 : return string_;
16081 : }
16082 1914526 : if (FLAG_thin_strings) {
16083 : // External strings get special treatment, to avoid copying their
16084 : // contents.
16085 1914526 : if (string_->IsExternalOneByteString()) {
16086 : return isolate->factory()
16087 10 : ->InternalizeExternalString<ExternalOneByteString>(string_);
16088 1914516 : } else if (string_->IsExternalTwoByteString()) {
16089 : return isolate->factory()
16090 0 : ->InternalizeExternalString<ExternalTwoByteString>(string_);
16091 : }
16092 : }
16093 : // Otherwise allocate a new internalized string.
16094 : return isolate->factory()->NewInternalizedStringImpl(
16095 1914516 : string_, string_->length(), string_->hash_field());
16096 : }
16097 :
16098 : private:
16099 : Handle<String> string_;
16100 : };
16101 :
16102 : template <typename Derived, typename Shape>
16103 56758 : void HashTable<Derived, Shape>::IteratePrefix(ObjectVisitor* v) {
16104 : BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v);
16105 56758 : }
16106 :
16107 : template <typename Derived, typename Shape>
16108 56800 : void HashTable<Derived, Shape>::IterateElements(ObjectVisitor* v) {
16109 : BodyDescriptorBase::IteratePointers(this, kElementsStartOffset,
16110 56800 : kHeaderSize + length() * kPointerSize, v);
16111 56800 : }
16112 :
16113 : template <typename Derived, typename Shape>
16114 2126177 : Handle<Derived> HashTable<Derived, Shape>::New(
16115 : Isolate* isolate, int at_least_space_for, PretenureFlag pretenure,
16116 : MinimumCapacity capacity_option) {
16117 : DCHECK_LE(0, at_least_space_for);
16118 : DCHECK_IMPLIES(capacity_option == USE_CUSTOM_MINIMUM_CAPACITY,
16119 : base::bits::IsPowerOfTwo(at_least_space_for));
16120 :
16121 : int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
16122 : ? at_least_space_for
16123 2126177 : : ComputeCapacity(at_least_space_for);
16124 2126177 : if (capacity > HashTable::kMaxCapacity) {
16125 0 : v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
16126 : }
16127 2126177 : return NewInternal(isolate, capacity, pretenure);
16128 : }
16129 :
16130 : template <typename Derived, typename Shape>
16131 2126177 : Handle<Derived> HashTable<Derived, Shape>::NewInternal(
16132 : Isolate* isolate, int capacity, PretenureFlag pretenure) {
16133 : Factory* factory = isolate->factory();
16134 : int length = EntryToIndex(capacity);
16135 2126177 : Handle<FixedArray> array = factory->NewFixedArray(length, pretenure);
16136 : array->set_map_no_write_barrier(Shape::GetMap(isolate));
16137 : Handle<Derived> table = Handle<Derived>::cast(array);
16138 :
16139 : table->SetNumberOfElements(0);
16140 : table->SetNumberOfDeletedElements(0);
16141 : table->SetCapacity(capacity);
16142 2126177 : return table;
16143 : }
16144 :
16145 : template <typename Derived, typename Shape>
16146 503112 : void HashTable<Derived, Shape>::Rehash(Derived* new_table) {
16147 : DisallowHeapAllocation no_gc;
16148 503112 : WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
16149 :
16150 : DCHECK_LT(NumberOfElements(), new_table->Capacity());
16151 :
16152 : // Copy prefix to new array.
16153 1460027 : for (int i = kPrefixStartIndex; i < kElementsStartIndex; i++) {
16154 970311 : new_table->set(i, get(i), mode);
16155 : }
16156 :
16157 : // Rehash the elements.
16158 : int capacity = this->Capacity();
16159 : Isolate* isolate = new_table->GetIsolate();
16160 36457223 : for (int i = 0; i < capacity; i++) {
16161 35952100 : uint32_t from_index = EntryToIndex(i);
16162 : Object* k = this->get(from_index);
16163 35952100 : if (!Shape::IsLive(isolate, k)) continue;
16164 7844210 : uint32_t hash = Shape::HashForObject(isolate, k);
16165 : uint32_t insertion_index =
16166 46074352 : EntryToIndex(new_table->FindInsertionEntry(hash));
16167 71873513 : for (int j = 0; j < Shape::kEntrySize; j++) {
16168 97672674 : new_table->set(insertion_index + j, get(from_index + j), mode);
16169 : }
16170 : }
16171 : new_table->SetNumberOfElements(NumberOfElements());
16172 : new_table->SetNumberOfDeletedElements(0);
16173 503112 : }
16174 :
16175 : template <typename Derived, typename Shape>
16176 322618593 : uint32_t HashTable<Derived, Shape>::EntryForProbe(Object* k, int probe,
16177 : uint32_t expected) {
16178 46244265 : uint32_t hash = Shape::HashForObject(GetIsolate(), k);
16179 322617872 : uint32_t capacity = this->Capacity();
16180 : uint32_t entry = FirstProbe(hash, capacity);
16181 372778996 : for (int i = 1; i < probe; i++) {
16182 268910412 : if (entry == expected) return expected;
16183 50161124 : entry = NextProbe(entry, i, capacity);
16184 : }
16185 : return entry;
16186 : }
16187 :
16188 : template <typename Derived, typename Shape>
16189 51705677 : void HashTable<Derived, Shape>::Swap(uint32_t entry1, uint32_t entry2,
16190 : WriteBarrierMode mode) {
16191 51705677 : int index1 = EntryToIndex(entry1);
16192 51705677 : int index2 = EntryToIndex(entry2);
16193 : Object* temp[Shape::kEntrySize];
16194 103417456 : for (int j = 0; j < Shape::kEntrySize; j++) {
16195 51723995 : temp[j] = get(index1 + j);
16196 : }
16197 51711789 : for (int j = 0; j < Shape::kEntrySize; j++) {
16198 103423568 : set(index1 + j, get(index2 + j), mode);
16199 : }
16200 51711696 : for (int j = 0; j < Shape::kEntrySize; j++) {
16201 51711790 : set(index2 + j, temp[j], mode);
16202 : }
16203 51705588 : }
16204 :
16205 : template <typename Derived, typename Shape>
16206 250130 : void HashTable<Derived, Shape>::Rehash() {
16207 : DisallowHeapAllocation no_gc;
16208 250130 : WriteBarrierMode mode = GetWriteBarrierMode(no_gc);
16209 : Isolate* isolate = GetIsolate();
16210 250138 : uint32_t capacity = Capacity();
16211 : bool done = false;
16212 1411421 : for (int probe = 1; !done; probe++) {
16213 : // All elements at entries given by one of the first _probe_ probes
16214 : // are placed correctly. Other elements might need to be moved.
16215 : done = true;
16216 1276476811 : for (uint32_t current = 0; current < capacity; current++) {
16217 1276476811 : Object* current_key = KeyAt(current);
16218 1276476811 : if (!Shape::IsLive(isolate, current_key)) continue;
16219 306067845 : uint32_t target = EntryForProbe(current_key, probe, current);
16220 306067899 : if (current == target) continue;
16221 61829213 : Object* target_key = KeyAt(target);
16222 78379558 : if (!Shape::IsLive(isolate, target_key) ||
16223 16550346 : EntryForProbe(target_key, probe, target) != target) {
16224 : // Put the current element into the correct position.
16225 51705674 : Swap(current, target, mode);
16226 : // The other element will be processed on the next iteration.
16227 51705621 : current--;
16228 : } else {
16229 : // The place for the current element is occupied. Leave the element
16230 : // for the next probe.
16231 : done = false;
16232 : }
16233 : }
16234 : }
16235 : // Wipe deleted entries.
16236 250138 : Object* the_hole = isolate->heap()->the_hole_value();
16237 250138 : Object* undefined = isolate->heap()->undefined_value();
16238 239468042 : for (uint32_t current = 0; current < capacity; current++) {
16239 478435824 : if (KeyAt(current) == the_hole) {
16240 24622051 : set(EntryToIndex(current) + kEntryKeyIndex, undefined);
16241 : }
16242 : }
16243 : SetNumberOfDeletedElements(0);
16244 250130 : }
16245 :
16246 : template <typename Derived, typename Shape>
16247 37559137 : Handle<Derived> HashTable<Derived, Shape>::EnsureCapacity(
16248 : Handle<Derived> table, int n, PretenureFlag pretenure) {
16249 37559137 : if (table->HasSufficientCapacityToAdd(n)) return table;
16250 :
16251 : Isolate* isolate = table->GetIsolate();
16252 : int capacity = table->Capacity();
16253 502828 : int new_nof = table->NumberOfElements() + n;
16254 :
16255 : const int kMinCapacityForPretenure = 256;
16256 : bool should_pretenure = pretenure == TENURED ||
16257 : ((capacity > kMinCapacityForPretenure) &&
16258 506695 : !isolate->heap()->InNewSpace(*table));
16259 : Handle<Derived> new_table = HashTable::New(
16260 502828 : isolate, new_nof, should_pretenure ? TENURED : NOT_TENURED);
16261 :
16262 502828 : table->Rehash(*new_table);
16263 502828 : return new_table;
16264 : }
16265 :
16266 : template bool
16267 : HashTable<NameDictionary, NameDictionaryShape>::HasSufficientCapacityToAdd(int);
16268 :
16269 : template <typename Derived, typename Shape>
16270 37593177 : bool HashTable<Derived, Shape>::HasSufficientCapacityToAdd(
16271 : int number_of_additional_elements) {
16272 : int capacity = Capacity();
16273 37593177 : int nof = NumberOfElements() + number_of_additional_elements;
16274 : int nod = NumberOfDeletedElements();
16275 : // Return true if:
16276 : // 50% is still free after adding number_of_additional_elements elements and
16277 : // at most 50% of the free elements are deleted elements.
16278 37593177 : if ((nof < capacity) && ((nod <= (capacity - nof) >> 1))) {
16279 37432537 : int needed_free = nof >> 1;
16280 37432537 : if (nof + needed_free <= capacity) return true;
16281 : }
16282 503113 : return false;
16283 : }
16284 :
16285 : template <typename Derived, typename Shape>
16286 83208 : Handle<Derived> HashTable<Derived, Shape>::Shrink(Handle<Derived> table) {
16287 : int capacity = table->Capacity();
16288 : int nof = table->NumberOfElements();
16289 :
16290 : // Shrink to fit the number of elements if only a quarter of the
16291 : // capacity is filled with elements.
16292 83208 : if (nof > (capacity >> 2)) return table;
16293 : // Allocate a new dictionary with room for at least the current
16294 : // number of elements. The allocation method will make sure that
16295 : // there is extra room in the dictionary for additions. Don't go
16296 : // lower than room for 16 elements.
16297 : int at_least_room_for = nof;
16298 65093 : if (at_least_room_for < 16) return table;
16299 :
16300 : Isolate* isolate = table->GetIsolate();
16301 : const int kMinCapacityForPretenure = 256;
16302 : bool pretenure =
16303 : (at_least_room_for > kMinCapacityForPretenure) &&
16304 303 : !isolate->heap()->InNewSpace(*table);
16305 : Handle<Derived> new_table = HashTable::New(
16306 : isolate,
16307 : at_least_room_for,
16308 284 : pretenure ? TENURED : NOT_TENURED);
16309 :
16310 284 : table->Rehash(*new_table);
16311 284 : return new_table;
16312 : }
16313 :
16314 : template <typename Derived, typename Shape>
16315 60596012 : uint32_t HashTable<Derived, Shape>::FindInsertionEntry(uint32_t hash) {
16316 60596012 : uint32_t capacity = Capacity();
16317 : uint32_t entry = FirstProbe(hash, capacity);
16318 : uint32_t count = 1;
16319 : // EnsureCapacity will guarantee the hash table is never full.
16320 : Isolate* isolate = GetIsolate();
16321 : while (true) {
16322 311615418 : if (!Shape::IsLive(isolate, KeyAt(entry))) break;
16323 95211697 : entry = NextProbe(entry, count++, capacity);
16324 : }
16325 95211697 : return entry;
16326 : }
16327 :
16328 :
16329 : // Force instantiation of template instances class.
16330 : // Please note this list is compiler dependent.
16331 :
16332 : template class HashTable<StringTable, StringTableShape>;
16333 :
16334 : template class HashTable<CompilationCacheTable, CompilationCacheShape>;
16335 :
16336 : template class HashTable<ObjectHashTable, ObjectHashTableShape>;
16337 :
16338 : template class HashTable<WeakHashTable, WeakHashTableShape<2>>;
16339 :
16340 : template class HashTable<TemplateMap, TemplateMapShape>;
16341 :
16342 : template class Dictionary<NameDictionary, NameDictionaryShape>;
16343 :
16344 : template class Dictionary<GlobalDictionary, GlobalDictionaryShape>;
16345 :
16346 : template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
16347 : HashTable<SeededNumberDictionary, SeededNumberDictionaryShape>;
16348 :
16349 : template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
16350 : Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape>;
16351 :
16352 : template class Dictionary<UnseededNumberDictionary,
16353 : UnseededNumberDictionaryShape>;
16354 :
16355 : template Handle<NameDictionary>
16356 : BaseNameDictionary<NameDictionary, NameDictionaryShape>::New(
16357 : Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
16358 :
16359 : template Handle<GlobalDictionary>
16360 : BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::New(
16361 : Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
16362 :
16363 : template Handle<SeededNumberDictionary>
16364 : Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape>::AtPut(
16365 : Handle<SeededNumberDictionary>, uint32_t, Handle<Object>,
16366 : PropertyDetails);
16367 :
16368 : template Handle<UnseededNumberDictionary>
16369 : Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape>::AtPut(
16370 : Handle<UnseededNumberDictionary>, uint32_t, Handle<Object>,
16371 : PropertyDetails);
16372 :
16373 : template Object*
16374 : Dictionary<SeededNumberDictionary,
16375 : SeededNumberDictionaryShape>::SlowReverseLookup(Object* value);
16376 :
16377 : template Object* Dictionary<
16378 : NameDictionary, NameDictionaryShape>::SlowReverseLookup(Object* value);
16379 :
16380 : template Handle<NameDictionary>
16381 : Dictionary<NameDictionary, NameDictionaryShape>::DeleteEntry(
16382 : Handle<NameDictionary>, int);
16383 :
16384 : template Handle<SeededNumberDictionary>
16385 : Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape>::DeleteEntry(
16386 : Handle<SeededNumberDictionary>, int);
16387 :
16388 : template Handle<UnseededNumberDictionary>
16389 : Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape>::
16390 : DeleteEntry(Handle<UnseededNumberDictionary>, int);
16391 :
16392 : template Handle<UnseededNumberDictionary>
16393 : HashTable<UnseededNumberDictionary, UnseededNumberDictionaryShape>::New(
16394 : Isolate*, int, PretenureFlag, MinimumCapacity);
16395 :
16396 : template Handle<NameDictionary>
16397 : HashTable<NameDictionary, NameDictionaryShape>::New(Isolate*, int,
16398 : PretenureFlag,
16399 : MinimumCapacity);
16400 :
16401 : template Handle<ObjectHashSet>
16402 : HashTable<ObjectHashSet, ObjectHashSetShape>::New(Isolate*, int n,
16403 : PretenureFlag,
16404 : MinimumCapacity);
16405 :
16406 : template Handle<NameDictionary> HashTable<
16407 : NameDictionary, NameDictionaryShape>::Shrink(Handle<NameDictionary>);
16408 :
16409 : template Handle<UnseededNumberDictionary>
16410 : HashTable<UnseededNumberDictionary, UnseededNumberDictionaryShape>::Shrink(
16411 : Handle<UnseededNumberDictionary>);
16412 :
16413 : template Handle<NameDictionary>
16414 : BaseNameDictionary<NameDictionary, NameDictionaryShape>::Add(
16415 : Handle<NameDictionary>, Handle<Name>, Handle<Object>, PropertyDetails,
16416 : int*);
16417 :
16418 : template Handle<GlobalDictionary>
16419 : BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::Add(
16420 : Handle<GlobalDictionary>, Handle<Name>, Handle<Object>, PropertyDetails,
16421 : int*);
16422 :
16423 : template void HashTable<GlobalDictionary, GlobalDictionaryShape>::Rehash();
16424 :
16425 : template Handle<SeededNumberDictionary>
16426 : Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape>::Add(
16427 : Handle<SeededNumberDictionary>, uint32_t, Handle<Object>, PropertyDetails,
16428 : int*);
16429 :
16430 : template Handle<UnseededNumberDictionary>
16431 : Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape>::Add(
16432 : Handle<UnseededNumberDictionary>, uint32_t, Handle<Object>, PropertyDetails,
16433 : int*);
16434 :
16435 : template Handle<NameDictionary>
16436 : BaseNameDictionary<NameDictionary, NameDictionaryShape>::EnsureCapacity(
16437 : Handle<NameDictionary>, int);
16438 :
16439 : template int Dictionary<GlobalDictionary,
16440 : GlobalDictionaryShape>::NumberOfEnumerableProperties();
16441 :
16442 : template int
16443 : Dictionary<NameDictionary, NameDictionaryShape>::NumberOfEnumerableProperties();
16444 :
16445 : template void
16446 : BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::CopyEnumKeysTo(
16447 : Handle<GlobalDictionary> dictionary, Handle<FixedArray> storage,
16448 : KeyCollectionMode mode, KeyAccumulator* accumulator);
16449 :
16450 : template void
16451 : BaseNameDictionary<NameDictionary, NameDictionaryShape>::CopyEnumKeysTo(
16452 : Handle<NameDictionary> dictionary, Handle<FixedArray> storage,
16453 : KeyCollectionMode mode, KeyAccumulator* accumulator);
16454 :
16455 : template Handle<FixedArray>
16456 : BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::IterationIndices(
16457 : Handle<GlobalDictionary> dictionary);
16458 : template void
16459 : BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::CollectKeysTo(
16460 : Handle<GlobalDictionary> dictionary, KeyAccumulator* keys);
16461 :
16462 : template Handle<FixedArray>
16463 : BaseNameDictionary<NameDictionary, NameDictionaryShape>::IterationIndices(
16464 : Handle<NameDictionary> dictionary);
16465 : template void
16466 : BaseNameDictionary<NameDictionary, NameDictionaryShape>::CollectKeysTo(
16467 : Handle<NameDictionary> dictionary, KeyAccumulator* keys);
16468 :
16469 : template int
16470 : Dictionary<SeededNumberDictionary,
16471 : SeededNumberDictionaryShape>::NumberOfEnumerableProperties();
16472 :
16473 : namespace {
16474 :
16475 2930 : bool CanonicalNumericIndexString(Isolate* isolate, Handle<Object> s,
16476 : Handle<Object>* index) {
16477 : DCHECK(s->IsString() || s->IsSmi());
16478 :
16479 : Handle<Object> result;
16480 2930 : if (s->IsSmi()) {
16481 : result = s;
16482 : } else {
16483 2912 : result = String::ToNumber(Handle<String>::cast(s));
16484 2912 : if (!result->IsMinusZero()) {
16485 5806 : Handle<String> str = Object::ToString(isolate, result).ToHandleChecked();
16486 : // Avoid treating strings like "2E1" and "20" as the same key.
16487 2903 : if (!str->SameValue(*s)) return false;
16488 : }
16489 : }
16490 218 : *index = result;
16491 218 : return true;
16492 : }
16493 :
16494 : } // anonymous namespace
16495 :
16496 : // ES#sec-integer-indexed-exotic-objects-defineownproperty-p-desc
16497 : // static
16498 3119 : Maybe<bool> JSTypedArray::DefineOwnProperty(Isolate* isolate,
16499 : Handle<JSTypedArray> o,
16500 : Handle<Object> key,
16501 : PropertyDescriptor* desc,
16502 : ShouldThrow should_throw) {
16503 : // 1. Assert: IsPropertyKey(P) is true.
16504 : DCHECK(key->IsName() || key->IsNumber());
16505 : // 2. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot.
16506 : // 3. If Type(P) is String, then
16507 3326 : if (key->IsString() || key->IsSmi()) {
16508 : // 3a. Let numericIndex be ! CanonicalNumericIndexString(P)
16509 : // 3b. If numericIndex is not undefined, then
16510 : Handle<Object> numeric_index;
16511 2930 : if (CanonicalNumericIndexString(isolate, key, &numeric_index)) {
16512 : // 3b i. If IsInteger(numericIndex) is false, return false.
16513 : // 3b ii. If numericIndex = -0, return false.
16514 : // 3b iii. If numericIndex < 0, return false.
16515 : // FIXME: the standard allows up to 2^53 elements.
16516 : uint32_t index;
16517 427 : if (numeric_index->IsMinusZero() || !numeric_index->ToUint32(&index)) {
16518 81 : RETURN_FAILURE(isolate, should_throw,
16519 : NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
16520 : }
16521 : // 3b iv. Let length be O.[[ArrayLength]].
16522 191 : uint32_t length = o->length()->Number();
16523 : // 3b v. If numericIndex ≥ length, return false.
16524 191 : if (index >= length) {
16525 27 : RETURN_FAILURE(isolate, should_throw,
16526 : NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
16527 : }
16528 : // 3b vi. If IsAccessorDescriptor(Desc) is true, return false.
16529 182 : if (PropertyDescriptor::IsAccessorDescriptor(desc)) {
16530 516 : RETURN_FAILURE(isolate, should_throw,
16531 : NewTypeError(MessageTemplate::kRedefineDisallowed, key));
16532 : }
16533 : // 3b vii. If Desc has a [[Configurable]] field and if
16534 : // Desc.[[Configurable]] is true, return false.
16535 : // 3b viii. If Desc has an [[Enumerable]] field and if Desc.[[Enumerable]]
16536 : // is false, return false.
16537 : // 3b ix. If Desc has a [[Writable]] field and if Desc.[[Writable]] is
16538 : // false, return false.
16539 20 : if ((desc->has_configurable() && desc->configurable()) ||
16540 20 : (desc->has_enumerable() && !desc->enumerable()) ||
16541 10 : (desc->has_writable() && !desc->writable())) {
16542 30 : RETURN_FAILURE(isolate, should_throw,
16543 : NewTypeError(MessageTemplate::kRedefineDisallowed, key));
16544 : }
16545 : // 3b x. If Desc has a [[Value]] field, then
16546 : // 3b x 1. Let value be Desc.[[Value]].
16547 : // 3b x 2. Return ? IntegerIndexedElementSet(O, numericIndex, value).
16548 0 : if (desc->has_value()) {
16549 0 : if (!desc->has_configurable()) desc->set_configurable(false);
16550 0 : if (!desc->has_enumerable()) desc->set_enumerable(true);
16551 0 : if (!desc->has_writable()) desc->set_writable(true);
16552 0 : Handle<Object> value = desc->value();
16553 0 : RETURN_ON_EXCEPTION_VALUE(isolate,
16554 : SetOwnElementIgnoreAttributes(
16555 : o, index, value, desc->ToAttributes()),
16556 : Nothing<bool>());
16557 : }
16558 : // 3b xi. Return true.
16559 : return Just(true);
16560 : }
16561 : }
16562 : // 4. Return ! OrdinaryDefineOwnProperty(O, P, Desc).
16563 2901 : return OrdinaryDefineOwnProperty(isolate, o, key, desc, should_throw);
16564 : }
16565 :
16566 9877273 : ExternalArrayType JSTypedArray::type() {
16567 9877273 : switch (elements()->map()->instance_type()) {
16568 : #define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype, size) \
16569 : case FIXED_##TYPE##_ARRAY_TYPE: \
16570 : return kExternal##Type##Array;
16571 :
16572 3662 : TYPED_ARRAYS(INSTANCE_TYPE_TO_ARRAY_TYPE)
16573 : #undef INSTANCE_TYPE_TO_ARRAY_TYPE
16574 :
16575 : default:
16576 0 : UNREACHABLE();
16577 : }
16578 : }
16579 :
16580 :
16581 13481 : size_t JSTypedArray::element_size() {
16582 13481 : switch (elements()->map()->instance_type()) {
16583 : #define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype, size) \
16584 : case FIXED_##TYPE##_ARRAY_TYPE: \
16585 : return size;
16586 :
16587 911 : TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE)
16588 : #undef INSTANCE_TYPE_TO_ELEMENT_SIZE
16589 :
16590 : default:
16591 0 : UNREACHABLE();
16592 : }
16593 : }
16594 :
16595 : // static
16596 10748 : MaybeHandle<JSTypedArray> JSTypedArray::Create(Isolate* isolate,
16597 : Handle<Object> default_ctor,
16598 : int argc, Handle<Object>* argv,
16599 : const char* method_name) {
16600 : // 1. Let newTypedArray be ? Construct(constructor, argumentList).
16601 : Handle<Object> new_obj;
16602 21496 : ASSIGN_RETURN_ON_EXCEPTION(isolate, new_obj,
16603 : Execution::New(isolate, default_ctor, argc, argv),
16604 : JSTypedArray);
16605 :
16606 : // 2. Perform ? ValidateTypedArray(newTypedArray).
16607 : Handle<JSTypedArray> new_array;
16608 21496 : ASSIGN_RETURN_ON_EXCEPTION(
16609 : isolate, new_array, JSTypedArray::Validate(isolate, new_obj, method_name),
16610 : JSTypedArray);
16611 :
16612 : // 3. If argumentList is a List of a single Number, then
16613 : // If newTypedArray.[[ArrayLength]] < size, throw a TypeError exception.
16614 : DCHECK_IMPLIES(argc == 1, argv[0]->IsSmi());
16615 31515 : if (argc == 1 && new_array->length_value() < argv[0]->Number()) {
16616 : const MessageTemplate::Template message =
16617 : MessageTemplate::kTypedArrayTooShort;
16618 324 : THROW_NEW_ERROR(isolate, NewTypeError(message), JSTypedArray);
16619 : }
16620 :
16621 : // 4. Return newTypedArray.
16622 10343 : return new_array;
16623 : }
16624 :
16625 : // static
16626 10910 : MaybeHandle<JSTypedArray> JSTypedArray::SpeciesCreate(
16627 : Isolate* isolate, Handle<JSTypedArray> exemplar, int argc,
16628 : Handle<Object>* argv, const char* method_name) {
16629 : // 1. Assert: exemplar is an Object that has a [[TypedArrayName]] internal
16630 : // slot.
16631 : DCHECK(exemplar->IsJSTypedArray());
16632 :
16633 : // 2. Let defaultConstructor be the intrinsic object listed in column one of
16634 : // Table 51 for exemplar.[[TypedArrayName]].
16635 10910 : Handle<JSFunction> default_ctor = isolate->uint8_array_fun();
16636 10910 : switch (exemplar->type()) {
16637 : #define TYPED_ARRAY_CTOR(Type, type, TYPE, ctype, size) \
16638 : case kExternal##Type##Array: { \
16639 : default_ctor = isolate->type##_array_fun(); \
16640 : break; \
16641 : }
16642 :
16643 1682 : TYPED_ARRAYS(TYPED_ARRAY_CTOR)
16644 : #undef TYPED_ARRAY_CTOR
16645 : default:
16646 0 : UNREACHABLE();
16647 : }
16648 :
16649 : // 3. Let constructor be ? SpeciesConstructor(exemplar, defaultConstructor).
16650 : Handle<Object> ctor;
16651 21820 : ASSIGN_RETURN_ON_EXCEPTION(
16652 : isolate, ctor,
16653 : Object::SpeciesConstructor(isolate, exemplar, default_ctor),
16654 : JSTypedArray);
16655 :
16656 : // 4. Return ? TypedArrayCreate(constructor, argumentList).
16657 10748 : return Create(isolate, ctor, argc, argv, method_name);
16658 : }
16659 :
16660 379548 : void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global,
16661 : Handle<Name> name) {
16662 : DCHECK(!global->HasFastProperties());
16663 : auto dictionary = handle(global->global_dictionary());
16664 : int entry = dictionary->FindEntry(name);
16665 759096 : if (entry == GlobalDictionary::kNotFound) return;
16666 95 : PropertyCell::InvalidateEntry(dictionary, entry);
16667 : }
16668 :
16669 7168421 : Handle<PropertyCell> JSGlobalObject::EnsureEmptyPropertyCell(
16670 : Handle<JSGlobalObject> global, Handle<Name> name,
16671 : PropertyCellType cell_type, int* entry_out) {
16672 : Isolate* isolate = global->GetIsolate();
16673 : DCHECK(!global->HasFastProperties());
16674 : Handle<GlobalDictionary> dictionary(global->global_dictionary(), isolate);
16675 : int entry = dictionary->FindEntry(name);
16676 : Handle<PropertyCell> cell;
16677 7168421 : if (entry != GlobalDictionary::kNotFound) {
16678 3976 : if (entry_out) *entry_out = entry;
16679 : cell = handle(dictionary->CellAt(entry));
16680 : PropertyCellType original_cell_type = cell->property_details().cell_type();
16681 : DCHECK(original_cell_type == PropertyCellType::kInvalidated ||
16682 : original_cell_type == PropertyCellType::kUninitialized);
16683 : DCHECK(cell->value()->IsTheHole(isolate));
16684 3976 : if (original_cell_type == PropertyCellType::kInvalidated) {
16685 1319 : cell = PropertyCell::InvalidateEntry(dictionary, entry);
16686 : }
16687 : PropertyDetails details(kData, NONE, cell_type);
16688 : cell->set_property_details(details);
16689 3976 : return cell;
16690 : }
16691 7164445 : cell = isolate->factory()->NewPropertyCell(name);
16692 : PropertyDetails details(kData, NONE, cell_type);
16693 : dictionary =
16694 7164445 : GlobalDictionary::Add(dictionary, name, cell, details, entry_out);
16695 : // {*entry_out} is initialized inside GlobalDictionary::Add().
16696 7164445 : global->SetProperties(*dictionary);
16697 7164445 : return cell;
16698 : }
16699 :
16700 :
16701 : // This class is used for looking up two character strings in the string table.
16702 : // If we don't have a hit we don't want to waste much time so we unroll the
16703 : // string hash calculation loop here for speed. Doesn't work if the two
16704 : // characters form a decimal integer, since such strings have a different hash
16705 : // algorithm.
16706 0 : class TwoCharHashTableKey : public StringTableKey {
16707 : public:
16708 : TwoCharHashTableKey(uint16_t c1, uint16_t c2, uint32_t seed)
16709 10033972 : : StringTableKey(ComputeHashField(c1, c2, seed)), c1_(c1), c2_(c2) {}
16710 :
16711 944045 : bool IsMatch(Object* o) override {
16712 : String* other = String::cast(o);
16713 944045 : if (other->length() != 2) return false;
16714 240686 : if (other->Get(0) != c1_) return false;
16715 189608 : return other->Get(1) == c2_;
16716 : }
16717 :
16718 0 : Handle<String> AsHandle(Isolate* isolate) override {
16719 : // The TwoCharHashTableKey is only used for looking in the string
16720 : // table, not for adding to it.
16721 0 : UNREACHABLE();
16722 : }
16723 :
16724 : private:
16725 5016986 : uint32_t ComputeHashField(uint16_t c1, uint16_t c2, uint32_t seed) {
16726 : // Char 1.
16727 : uint32_t hash = seed;
16728 5016986 : hash += c1;
16729 5016986 : hash += hash << 10;
16730 5016986 : hash ^= hash >> 6;
16731 : // Char 2.
16732 5016986 : hash += c2;
16733 5016986 : hash += hash << 10;
16734 5016986 : hash ^= hash >> 6;
16735 : // GetHash.
16736 5016986 : hash += hash << 3;
16737 5016986 : hash ^= hash >> 11;
16738 5016986 : hash += hash << 15;
16739 5016986 : if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash;
16740 5016986 : hash = (hash << String::kHashShift) | String::kIsNotArrayIndexMask;
16741 : #ifdef DEBUG
16742 : // If this assert fails then we failed to reproduce the two-character
16743 : // version of the string hashing algorithm above. One reason could be
16744 : // that we were passed two digits as characters, since the hash
16745 : // algorithm is different in that case.
16746 : uint16_t chars[2] = {c1, c2};
16747 : uint32_t check_hash = StringHasher::HashSequentialString(chars, 2, seed);
16748 : DCHECK_EQ(hash, check_hash);
16749 : #endif
16750 5016986 : return hash;
16751 : }
16752 :
16753 : uint16_t c1_;
16754 : uint16_t c2_;
16755 : };
16756 :
16757 5016986 : MaybeHandle<String> StringTable::LookupTwoCharsStringIfExists(
16758 : Isolate* isolate,
16759 : uint16_t c1,
16760 : uint16_t c2) {
16761 : TwoCharHashTableKey key(c1, c2, isolate->heap()->HashSeed());
16762 : Handle<StringTable> string_table = isolate->factory()->string_table();
16763 : int entry = string_table->FindEntry(&key);
16764 5016986 : if (entry == kNotFound) return MaybeHandle<String>();
16765 :
16766 : Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
16767 : DCHECK(StringShape(*result).IsInternalized());
16768 : DCHECK_EQ(result->Hash(), key.Hash());
16769 188758 : return result;
16770 : }
16771 :
16772 300 : void StringTable::EnsureCapacityForDeserialization(Isolate* isolate,
16773 : int expected) {
16774 : Handle<StringTable> table = isolate->factory()->string_table();
16775 : // We need a key instance for the virtual hash function.
16776 300 : table = StringTable::EnsureCapacity(table, expected);
16777 : isolate->heap()->SetRootStringTable(*table);
16778 300 : }
16779 :
16780 : namespace {
16781 :
16782 : template <class StringClass>
16783 31 : void MigrateExternalStringResource(Isolate* isolate, String* from, String* to) {
16784 : StringClass* cast_from = StringClass::cast(from);
16785 : StringClass* cast_to = StringClass::cast(to);
16786 : const typename StringClass::Resource* to_resource = cast_to->resource();
16787 31 : if (to_resource == nullptr) {
16788 : // |to| is a just-created internalized copy of |from|. Migrate the resource.
16789 : cast_to->set_resource(cast_from->resource());
16790 : // Zap |from|'s resource pointer to reflect the fact that |from| has
16791 : // relinquished ownership of its resource.
16792 : cast_from->set_resource(nullptr);
16793 21 : } else if (to_resource != cast_from->resource()) {
16794 : // |to| already existed and has its own resource. Finalize |from|.
16795 : isolate->heap()->FinalizeExternalString(from);
16796 : }
16797 31 : }
16798 :
16799 12049350 : void MakeStringThin(String* string, String* internalized, Isolate* isolate) {
16800 12049350 : if (string->IsExternalString()) {
16801 31 : if (internalized->IsExternalOneByteString()) {
16802 : MigrateExternalStringResource<ExternalOneByteString>(isolate, string,
16803 20 : internalized);
16804 11 : } else if (internalized->IsExternalTwoByteString()) {
16805 : MigrateExternalStringResource<ExternalTwoByteString>(isolate, string,
16806 11 : internalized);
16807 : } else {
16808 : // If the external string is duped into an existing non-external
16809 : // internalized string, free its resource (it's about to be rewritten
16810 : // into a ThinString below).
16811 : isolate->heap()->FinalizeExternalString(string);
16812 : }
16813 : }
16814 :
16815 12049350 : if (!string->IsInternalizedString()) {
16816 : DisallowHeapAllocation no_gc;
16817 12039761 : int old_size = string->Size();
16818 12039761 : isolate->heap()->NotifyObjectLayoutChange(string, old_size, no_gc);
16819 : bool one_byte = internalized->IsOneByteRepresentation();
16820 : Handle<Map> map = one_byte ? isolate->factory()->thin_one_byte_string_map()
16821 12039761 : : isolate->factory()->thin_string_map();
16822 : DCHECK_GE(old_size, ThinString::kSize);
16823 12039761 : string->synchronized_set_map(*map);
16824 : ThinString* thin = ThinString::cast(string);
16825 12039761 : thin->set_actual(internalized);
16826 12039761 : Address thin_end = thin->address() + ThinString::kSize;
16827 12039761 : int size_delta = old_size - ThinString::kSize;
16828 12039761 : if (size_delta != 0) {
16829 : Heap* heap = isolate->heap();
16830 3360588 : heap->CreateFillerObjectAt(thin_end, size_delta, ClearRecordedSlots::kNo);
16831 : }
16832 : }
16833 12049350 : }
16834 :
16835 : } // namespace
16836 :
16837 12717887 : Handle<String> StringTable::LookupString(Isolate* isolate,
16838 : Handle<String> string) {
16839 12717887 : string = String::Flatten(string);
16840 12717887 : if (string->IsInternalizedString()) return string;
16841 :
16842 12002528 : InternalizedStringKey key(string);
16843 12002529 : Handle<String> result = LookupKey(isolate, &key);
16844 :
16845 12002529 : if (FLAG_thin_strings) {
16846 12002529 : MakeStringThin(*string, *result, isolate);
16847 : } else { // !FLAG_thin_strings
16848 0 : if (string->IsConsString()) {
16849 : Handle<ConsString> cons = Handle<ConsString>::cast(string);
16850 0 : cons->set_first(*result);
16851 0 : cons->set_second(isolate->heap()->empty_string());
16852 0 : } else if (string->IsSlicedString()) {
16853 : STATIC_ASSERT(ConsString::kSize == SlicedString::kSize);
16854 : DisallowHeapAllocation no_gc;
16855 : bool one_byte = result->IsOneByteRepresentation();
16856 : Handle<Map> map = one_byte
16857 : ? isolate->factory()->cons_one_byte_string_map()
16858 0 : : isolate->factory()->cons_string_map();
16859 0 : string->set_map(*map);
16860 : Handle<ConsString> cons = Handle<ConsString>::cast(string);
16861 0 : cons->set_first(*result);
16862 0 : cons->set_second(isolate->heap()->empty_string());
16863 : }
16864 : }
16865 12002529 : return result;
16866 : }
16867 :
16868 60220412 : Handle<String> StringTable::LookupKey(Isolate* isolate, StringTableKey* key) {
16869 : Handle<StringTable> table = isolate->factory()->string_table();
16870 : int entry = table->FindEntry(key);
16871 :
16872 : // String already in table.
16873 60220427 : if (entry != kNotFound) {
16874 : return handle(String::cast(table->KeyAt(entry)), isolate);
16875 : }
16876 :
16877 : // Adding new string. Grow table if needed.
16878 12898852 : table = StringTable::EnsureCapacity(table, 1);
16879 :
16880 : // Create string object.
16881 12898851 : Handle<String> string = key->AsHandle(isolate);
16882 : // There must be no attempts to internalize strings that could throw
16883 : // InvalidStringLength error.
16884 12898851 : CHECK(!string.is_null());
16885 : DCHECK(string->HasHashCode());
16886 :
16887 : // Add the new string and return it along with the string table.
16888 25797702 : entry = table->FindInsertionEntry(key->Hash());
16889 12898852 : table->set(EntryToIndex(entry), *string);
16890 12898852 : table->ElementAdded();
16891 :
16892 : isolate->heap()->SetRootStringTable(*table);
16893 : return Handle<String>::cast(string);
16894 : }
16895 :
16896 : namespace {
16897 :
16898 : class StringTableNoAllocateKey : public StringTableKey {
16899 : public:
16900 47085 : StringTableNoAllocateKey(String* string, uint32_t seed)
16901 47085 : : StringTableKey(0), string_(string) {
16902 : StringShape shape(string);
16903 47085 : one_byte_ = shape.HasOnlyOneByteChars();
16904 : DCHECK(!shape.IsInternalized());
16905 : DCHECK(!shape.IsThin());
16906 : int length = string->length();
16907 47085 : if (shape.IsCons() && length <= String::kMaxHashCalcLength) {
16908 266 : special_flattening_ = true;
16909 : uint32_t hash_field = 0;
16910 266 : if (one_byte_) {
16911 263 : one_byte_content_ = new uint8_t[length];
16912 263 : String::WriteToFlat(string, one_byte_content_, 0, length);
16913 : hash_field =
16914 263 : StringHasher::HashSequentialString(one_byte_content_, length, seed);
16915 : } else {
16916 3 : two_byte_content_ = new uint16_t[length];
16917 3 : String::WriteToFlat(string, two_byte_content_, 0, length);
16918 : hash_field =
16919 3 : StringHasher::HashSequentialString(two_byte_content_, length, seed);
16920 : }
16921 : string->set_hash_field(hash_field);
16922 : } else {
16923 46819 : special_flattening_ = false;
16924 46819 : one_byte_content_ = nullptr;
16925 46819 : string->Hash();
16926 : }
16927 :
16928 : DCHECK(string->HasHashCode());
16929 : set_hash_field(string->hash_field());
16930 47085 : }
16931 :
16932 47085 : ~StringTableNoAllocateKey() {
16933 47085 : if (one_byte_) {
16934 44402 : delete[] one_byte_content_;
16935 : } else {
16936 2683 : delete[] two_byte_content_;
16937 : }
16938 47085 : }
16939 :
16940 71200 : bool IsMatch(Object* otherstring) override {
16941 : String* other = String::cast(otherstring);
16942 : DCHECK(other->IsInternalizedString());
16943 : DCHECK(other->IsFlat());
16944 142400 : if (Hash() != other->Hash()) return false;
16945 46821 : int len = string_->length();
16946 46821 : if (len != other->length()) return false;
16947 :
16948 46821 : if (!special_flattening_) {
16949 46603 : if (string_->Get(0) != other->Get(0)) return false;
16950 46603 : if (string_->IsFlat()) {
16951 46603 : StringShape shape1(string_);
16952 : StringShape shape2(other);
16953 90538 : if (shape1.encoding_tag() == kOneByteStringTag &&
16954 : shape2.encoding_tag() == kOneByteStringTag) {
16955 43935 : String::FlatContent flat1 = string_->GetFlatContent();
16956 43935 : String::FlatContent flat2 = other->GetFlatContent();
16957 43935 : return CompareRawStringContents(flat1.ToOneByteVector().start(),
16958 43935 : flat2.ToOneByteVector().start(), len);
16959 : }
16960 5336 : if (shape1.encoding_tag() == kTwoByteStringTag &&
16961 : shape2.encoding_tag() == kTwoByteStringTag) {
16962 2668 : String::FlatContent flat1 = string_->GetFlatContent();
16963 2668 : String::FlatContent flat2 = other->GetFlatContent();
16964 2668 : return CompareRawStringContents(flat1.ToUC16Vector().start(),
16965 2668 : flat2.ToUC16Vector().start(), len);
16966 : }
16967 : }
16968 : StringComparator comparator;
16969 0 : return comparator.Equals(string_, other);
16970 : }
16971 :
16972 218 : String::FlatContent flat_content = other->GetFlatContent();
16973 218 : if (one_byte_) {
16974 215 : if (flat_content.IsOneByte()) {
16975 : return CompareRawStringContents(
16976 215 : one_byte_content_, flat_content.ToOneByteVector().start(), len);
16977 : } else {
16978 : DCHECK(flat_content.IsTwoByte());
16979 0 : for (int i = 0; i < len; i++) {
16980 0 : if (flat_content.Get(i) != one_byte_content_[i]) return false;
16981 : }
16982 : return true;
16983 : }
16984 : } else {
16985 3 : if (flat_content.IsTwoByte()) {
16986 : return CompareRawStringContents(
16987 0 : two_byte_content_, flat_content.ToUC16Vector().start(), len);
16988 : } else {
16989 : DCHECK(flat_content.IsOneByte());
16990 60 : for (int i = 0; i < len; i++) {
16991 60 : if (flat_content.Get(i) != two_byte_content_[i]) return false;
16992 : }
16993 : return true;
16994 : }
16995 : }
16996 : }
16997 :
16998 0 : MUST_USE_RESULT Handle<String> AsHandle(Isolate* isolate) override {
16999 0 : UNREACHABLE();
17000 : }
17001 :
17002 : private:
17003 : String* string_;
17004 : bool one_byte_;
17005 : bool special_flattening_;
17006 : union {
17007 : uint8_t* one_byte_content_;
17008 : uint16_t* two_byte_content_;
17009 : };
17010 : };
17011 :
17012 : } // namespace
17013 :
17014 : // static
17015 47085 : Object* StringTable::LookupStringIfExists_NoAllocate(String* string) {
17016 : DisallowHeapAllocation no_gc;
17017 47085 : Heap* heap = string->GetHeap();
17018 : Isolate* isolate = heap->isolate();
17019 : StringTable* table = heap->string_table();
17020 :
17021 47085 : StringTableNoAllocateKey key(string, heap->HashSeed());
17022 :
17023 : // String could be an array index.
17024 : uint32_t hash = string->hash_field();
17025 :
17026 : // Valid array indices are >= 0, so they cannot be mixed up with any of
17027 : // the result sentinels, which are negative.
17028 : STATIC_ASSERT(
17029 : !String::ArrayIndexValueBits::is_valid(ResultSentinel::kUnsupported));
17030 : STATIC_ASSERT(
17031 : !String::ArrayIndexValueBits::is_valid(ResultSentinel::kNotFound));
17032 :
17033 47085 : if (Name::ContainsCachedArrayIndex(hash)) {
17034 12 : return Smi::FromInt(String::ArrayIndexValueBits::decode(hash));
17035 : }
17036 47079 : if ((hash & Name::kIsNotArrayIndexMask) == 0) {
17037 : // It is an indexed, but it's not cached.
17038 : return Smi::FromInt(ResultSentinel::kUnsupported);
17039 : }
17040 :
17041 47062 : int entry = table->FindEntry(isolate, &key, key.Hash());
17042 47062 : if (entry != kNotFound) {
17043 : String* internalized = String::cast(table->KeyAt(entry));
17044 46821 : if (FLAG_thin_strings) {
17045 46821 : MakeStringThin(string, internalized, isolate);
17046 : }
17047 46821 : return internalized;
17048 : }
17049 : // A string that's not an array index, and not in the string table,
17050 : // cannot have been used as a property name before.
17051 47085 : return Smi::FromInt(ResultSentinel::kNotFound);
17052 : }
17053 :
17054 8735 : String* StringTable::LookupKeyIfExists(Isolate* isolate, StringTableKey* key) {
17055 : Handle<StringTable> table = isolate->factory()->string_table();
17056 8735 : int entry = table->FindEntry(isolate, key);
17057 11155 : if (entry != kNotFound) return String::cast(table->KeyAt(entry));
17058 : return nullptr;
17059 : }
17060 :
17061 130903 : Handle<StringSet> StringSet::New(Isolate* isolate) {
17062 130903 : return HashTable::New(isolate, 0);
17063 : }
17064 :
17065 1769226 : Handle<StringSet> StringSet::Add(Handle<StringSet> stringset,
17066 : Handle<String> name) {
17067 1769226 : if (!stringset->Has(name)) {
17068 119578 : stringset = EnsureCapacity(stringset, 1);
17069 : uint32_t hash = ShapeT::Hash(name->GetIsolate(), *name);
17070 119578 : int entry = stringset->FindInsertionEntry(hash);
17071 119578 : stringset->set(EntryToIndex(entry), *name);
17072 119578 : stringset->ElementAdded();
17073 : }
17074 1769226 : return stringset;
17075 : }
17076 :
17077 1782602 : bool StringSet::Has(Handle<String> name) {
17078 1782602 : return FindEntry(*name) != kNotFound;
17079 : }
17080 :
17081 59909 : Handle<ObjectHashSet> ObjectHashSet::Add(Handle<ObjectHashSet> set,
17082 : Handle<Object> key) {
17083 : Isolate* isolate = set->GetIsolate();
17084 59909 : int32_t hash = key->GetOrCreateHash(isolate)->value();
17085 59909 : if (!set->Has(isolate, key, hash)) {
17086 58240 : set = EnsureCapacity(set, 1);
17087 116480 : int entry = set->FindInsertionEntry(hash);
17088 58240 : set->set(EntryToIndex(entry), *key);
17089 58240 : set->ElementAdded();
17090 : }
17091 59909 : return set;
17092 : }
17093 :
17094 0 : Handle<Object> CompilationCacheTable::Lookup(Handle<String> src,
17095 : Handle<Context> context,
17096 : LanguageMode language_mode) {
17097 : Isolate* isolate = GetIsolate();
17098 : Handle<SharedFunctionInfo> shared(context->closure()->shared());
17099 0 : StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17100 : int entry = FindEntry(&key);
17101 0 : if (entry == kNotFound) return isolate->factory()->undefined_value();
17102 : int index = EntryToIndex(entry);
17103 0 : if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value();
17104 0 : return Handle<Object>(get(index + 1), isolate);
17105 : }
17106 :
17107 : namespace {
17108 :
17109 : const int kLiteralEntryLength = 2;
17110 : const int kLiteralInitialLength = 2;
17111 : const int kLiteralContextOffset = 0;
17112 : const int kLiteralLiteralsOffset = 1;
17113 :
17114 3139783 : int SearchLiteralsMapEntry(CompilationCacheTable* cache, int cache_entry,
17115 : Context* native_context) {
17116 : DisallowHeapAllocation no_gc;
17117 : DCHECK(native_context->IsNativeContext());
17118 : Object* obj = cache->get(cache_entry);
17119 :
17120 3139783 : if (obj->IsFixedArray()) {
17121 : FixedArray* literals_map = FixedArray::cast(obj);
17122 : int length = literals_map->length();
17123 6809295 : for (int i = 0; i < length; i += kLiteralEntryLength) {
17124 6025971 : if (WeakCell::cast(literals_map->get(i + kLiteralContextOffset))
17125 : ->value() == native_context) {
17126 : return i;
17127 : }
17128 : }
17129 : }
17130 : return -1;
17131 : }
17132 :
17133 666274 : void AddToLiteralsMap(Handle<CompilationCacheTable> cache, int cache_entry,
17134 : Handle<Context> native_context, Handle<Cell> literals) {
17135 : Isolate* isolate = native_context->GetIsolate();
17136 : DCHECK(native_context->IsNativeContext());
17137 : STATIC_ASSERT(kLiteralEntryLength == 2);
17138 : Handle<FixedArray> new_literals_map;
17139 : int entry;
17140 :
17141 : Object* obj = cache->get(cache_entry);
17142 :
17143 1037930 : if (!obj->IsFixedArray() || FixedArray::cast(obj)->length() == 0) {
17144 : new_literals_map =
17145 294618 : isolate->factory()->NewFixedArray(kLiteralInitialLength, TENURED);
17146 : entry = 0;
17147 : } else {
17148 : Handle<FixedArray> old_literals_map(FixedArray::cast(obj), isolate);
17149 371656 : entry = SearchLiteralsMapEntry(*cache, cache_entry, *native_context);
17150 371656 : if (entry >= 0) {
17151 : // Just set the code of the entry.
17152 : Handle<WeakCell> literals_cell =
17153 1968 : isolate->factory()->NewWeakCell(literals);
17154 3936 : old_literals_map->set(entry + kLiteralLiteralsOffset, *literals_cell);
17155 666274 : return;
17156 : }
17157 :
17158 : // Can we reuse an entry?
17159 : DCHECK_LT(entry, 0);
17160 : int length = old_literals_map->length();
17161 1014330 : for (int i = 0; i < length; i += kLiteralEntryLength) {
17162 682851 : if (WeakCell::cast(old_literals_map->get(i + kLiteralContextOffset))
17163 : ->cleared()) {
17164 : new_literals_map = old_literals_map;
17165 : entry = i;
17166 : break;
17167 : }
17168 : }
17169 :
17170 369688 : if (entry < 0) {
17171 : // Copy old optimized code map and append one new entry.
17172 : new_literals_map = isolate->factory()->CopyFixedArrayAndGrow(
17173 331479 : old_literals_map, kLiteralEntryLength, TENURED);
17174 : entry = old_literals_map->length();
17175 : }
17176 : }
17177 :
17178 664306 : Handle<WeakCell> literals_cell = isolate->factory()->NewWeakCell(literals);
17179 : WeakCell* context_cell = native_context->self_weak_cell();
17180 :
17181 664306 : new_literals_map->set(entry + kLiteralContextOffset, context_cell);
17182 1328612 : new_literals_map->set(entry + kLiteralLiteralsOffset, *literals_cell);
17183 :
17184 : #ifdef DEBUG
17185 : for (int i = 0; i < new_literals_map->length(); i += kLiteralEntryLength) {
17186 : WeakCell* cell =
17187 : WeakCell::cast(new_literals_map->get(i + kLiteralContextOffset));
17188 : DCHECK(cell->cleared() || cell->value()->IsNativeContext());
17189 : cell = WeakCell::cast(new_literals_map->get(i + kLiteralLiteralsOffset));
17190 : DCHECK(cell->cleared() || (cell->value()->IsCell()));
17191 : }
17192 : #endif
17193 :
17194 : Object* old_literals_map = cache->get(cache_entry);
17195 664306 : if (old_literals_map != *new_literals_map) {
17196 626097 : cache->set(cache_entry, *new_literals_map);
17197 : }
17198 : }
17199 :
17200 2768127 : Cell* SearchLiteralsMap(CompilationCacheTable* cache, int cache_entry,
17201 : Context* native_context) {
17202 : Cell* result = nullptr;
17203 2768127 : int entry = SearchLiteralsMapEntry(cache, cache_entry, native_context);
17204 2768127 : if (entry >= 0) {
17205 : FixedArray* literals_map = FixedArray::cast(cache->get(cache_entry));
17206 : DCHECK_LE(entry + kLiteralEntryLength, literals_map->length());
17207 : WeakCell* cell =
17208 2354491 : WeakCell::cast(literals_map->get(entry + kLiteralLiteralsOffset));
17209 :
17210 2354491 : result = cell->cleared() ? nullptr : Cell::cast(cell->value());
17211 : }
17212 : DCHECK(result == nullptr || result->IsCell());
17213 2768127 : return result;
17214 : }
17215 :
17216 : } // namespace
17217 :
17218 211326 : InfoVectorPair CompilationCacheTable::LookupScript(Handle<String> src,
17219 : Handle<Context> context,
17220 : LanguageMode language_mode) {
17221 : InfoVectorPair empty_result;
17222 : Handle<SharedFunctionInfo> shared(context->closure()->shared());
17223 211326 : StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17224 : int entry = FindEntry(&key);
17225 211326 : if (entry == kNotFound) return empty_result;
17226 : int index = EntryToIndex(entry);
17227 92034 : if (!get(index)->IsFixedArray()) return empty_result;
17228 92034 : Object* obj = get(index + 1);
17229 92034 : if (obj->IsSharedFunctionInfo()) {
17230 : Cell* literals =
17231 92034 : SearchLiteralsMap(this, index + 2, context->native_context());
17232 92034 : return InfoVectorPair(SharedFunctionInfo::cast(obj), literals);
17233 : }
17234 0 : return empty_result;
17235 : }
17236 :
17237 3620221 : InfoVectorPair CompilationCacheTable::LookupEval(
17238 : Handle<String> src, Handle<SharedFunctionInfo> outer_info,
17239 : Handle<Context> native_context, LanguageMode language_mode, int position) {
17240 : InfoVectorPair empty_result;
17241 3620221 : StringSharedKey key(src, outer_info, language_mode, position);
17242 : int entry = FindEntry(&key);
17243 3620221 : if (entry == kNotFound) return empty_result;
17244 : int index = EntryToIndex(entry);
17245 2849746 : if (!get(index)->IsFixedArray()) return empty_result;
17246 2676093 : Object* obj = get(EntryToIndex(entry) + 1);
17247 2676093 : if (obj->IsSharedFunctionInfo()) {
17248 : Cell* literals =
17249 2676093 : SearchLiteralsMap(this, EntryToIndex(entry) + 2, *native_context);
17250 2676093 : return InfoVectorPair(SharedFunctionInfo::cast(obj), literals);
17251 : }
17252 0 : return empty_result;
17253 : }
17254 :
17255 808106 : Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src,
17256 : JSRegExp::Flags flags) {
17257 : Isolate* isolate = GetIsolate();
17258 : DisallowHeapAllocation no_allocation;
17259 : RegExpKey key(src, flags);
17260 : int entry = FindEntry(&key);
17261 1398708 : if (entry == kNotFound) return isolate->factory()->undefined_value();
17262 435008 : return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
17263 : }
17264 :
17265 :
17266 0 : Handle<CompilationCacheTable> CompilationCacheTable::Put(
17267 : Handle<CompilationCacheTable> cache, Handle<String> src,
17268 : Handle<Context> context, LanguageMode language_mode, Handle<Object> value) {
17269 : Isolate* isolate = cache->GetIsolate();
17270 : Handle<SharedFunctionInfo> shared(context->closure()->shared());
17271 0 : StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17272 0 : Handle<Object> k = key.AsHandle(isolate);
17273 0 : cache = EnsureCapacity(cache, 1);
17274 0 : int entry = cache->FindInsertionEntry(key.Hash());
17275 0 : cache->set(EntryToIndex(entry), *k);
17276 0 : cache->set(EntryToIndex(entry) + 1, *value);
17277 0 : cache->ElementAdded();
17278 0 : return cache;
17279 : }
17280 :
17281 118424 : Handle<CompilationCacheTable> CompilationCacheTable::PutScript(
17282 : Handle<CompilationCacheTable> cache, Handle<String> src,
17283 : Handle<Context> context, LanguageMode language_mode,
17284 : Handle<SharedFunctionInfo> value, Handle<Cell> literals) {
17285 : Isolate* isolate = cache->GetIsolate();
17286 : Handle<SharedFunctionInfo> shared(context->closure()->shared());
17287 : Handle<Context> native_context(context->native_context());
17288 118424 : StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17289 118424 : Handle<Object> k = key.AsHandle(isolate);
17290 118424 : cache = EnsureCapacity(cache, 1);
17291 236848 : int entry = cache->FindInsertionEntry(key.Hash());
17292 118424 : cache->set(EntryToIndex(entry), *k);
17293 236848 : cache->set(EntryToIndex(entry) + 1, *value);
17294 118424 : AddToLiteralsMap(cache, EntryToIndex(entry) + 2, native_context, literals);
17295 118424 : cache->ElementAdded();
17296 118424 : return cache;
17297 : }
17298 :
17299 1201484 : Handle<CompilationCacheTable> CompilationCacheTable::PutEval(
17300 : Handle<CompilationCacheTable> cache, Handle<String> src,
17301 : Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value,
17302 : Handle<Context> native_context, Handle<Cell> literals, int position) {
17303 : Isolate* isolate = cache->GetIsolate();
17304 1201484 : StringSharedKey key(src, outer_info, value->language_mode(), position);
17305 : {
17306 1201484 : Handle<Object> k = key.AsHandle(isolate);
17307 : int entry = cache->FindEntry(&key);
17308 1201484 : if (entry != kNotFound) {
17309 547850 : cache->set(EntryToIndex(entry), *k);
17310 1095700 : cache->set(EntryToIndex(entry) + 1, *value);
17311 : // AddToLiteralsMap may allocate a new sub-array to live in the entry,
17312 : // but it won't change the cache array. Therefore EntryToIndex and
17313 : // entry remains correct.
17314 : AddToLiteralsMap(cache, EntryToIndex(entry) + 2, native_context,
17315 547850 : literals);
17316 547850 : return cache;
17317 : }
17318 : }
17319 :
17320 653634 : cache = EnsureCapacity(cache, 1);
17321 1307268 : int entry = cache->FindInsertionEntry(key.Hash());
17322 : Handle<Object> k =
17323 653634 : isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
17324 653634 : cache->set(EntryToIndex(entry), *k);
17325 : cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
17326 653634 : cache->ElementAdded();
17327 653634 : return cache;
17328 : }
17329 :
17330 :
17331 292916 : Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp(
17332 : Handle<CompilationCacheTable> cache, Handle<String> src,
17333 : JSRegExp::Flags flags, Handle<FixedArray> value) {
17334 : RegExpKey key(src, flags);
17335 292916 : cache = EnsureCapacity(cache, 1);
17336 292916 : int entry = cache->FindInsertionEntry(key.Hash());
17337 : // We store the value in the key slot, and compare the search key
17338 : // to the stored value with a custon IsMatch function during lookups.
17339 292916 : cache->set(EntryToIndex(entry), *value);
17340 585832 : cache->set(EntryToIndex(entry) + 1, *value);
17341 292916 : cache->ElementAdded();
17342 292916 : return cache;
17343 : }
17344 :
17345 :
17346 37857 : void CompilationCacheTable::Age() {
17347 : DisallowHeapAllocation no_allocation;
17348 37857 : Object* the_hole_value = GetHeap()->the_hole_value();
17349 7196718 : for (int entry = 0, size = Capacity(); entry < size; entry++) {
17350 : int entry_index = EntryToIndex(entry);
17351 7121004 : int value_index = entry_index + 1;
17352 :
17353 7121004 : if (get(entry_index)->IsNumber()) {
17354 : Smi* count = Smi::cast(get(value_index));
17355 735170 : count = Smi::FromInt(count->value() - 1);
17356 735170 : if (count->value() == 0) {
17357 : NoWriteBarrierSet(this, entry_index, the_hole_value);
17358 : NoWriteBarrierSet(this, value_index, the_hole_value);
17359 16767 : ElementRemoved();
17360 : } else {
17361 : NoWriteBarrierSet(this, value_index, count);
17362 : }
17363 6385834 : } else if (get(entry_index)->IsFixedArray()) {
17364 : SharedFunctionInfo* info = SharedFunctionInfo::cast(get(value_index));
17365 831478 : if (info->IsInterpreted() && info->bytecode_array()->IsOld()) {
17366 24222 : for (int i = 0; i < kEntrySize; i++) {
17367 24222 : NoWriteBarrierSet(this, entry_index + i, the_hole_value);
17368 : }
17369 8074 : ElementRemoved();
17370 : }
17371 : }
17372 : }
17373 37857 : }
17374 :
17375 :
17376 0 : void CompilationCacheTable::Remove(Object* value) {
17377 : DisallowHeapAllocation no_allocation;
17378 0 : Object* the_hole_value = GetHeap()->the_hole_value();
17379 0 : for (int entry = 0, size = Capacity(); entry < size; entry++) {
17380 : int entry_index = EntryToIndex(entry);
17381 0 : int value_index = entry_index + 1;
17382 0 : if (get(value_index) == value) {
17383 0 : for (int i = 0; i < kEntrySize; i++) {
17384 0 : NoWriteBarrierSet(this, entry_index + i, the_hole_value);
17385 : }
17386 0 : ElementRemoved();
17387 : }
17388 : }
17389 0 : return;
17390 : }
17391 :
17392 : template <typename Derived, typename Shape>
17393 1030413 : Handle<Derived> BaseNameDictionary<Derived, Shape>::New(
17394 : Isolate* isolate, int at_least_space_for, PretenureFlag pretenure,
17395 : MinimumCapacity capacity_option) {
17396 : DCHECK_LE(0, at_least_space_for);
17397 : Handle<Derived> dict = Dictionary<Derived, Shape>::New(
17398 1030413 : isolate, at_least_space_for, pretenure, capacity_option);
17399 : dict->SetHash(PropertyArray::kNoHashSentinel);
17400 : dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
17401 1030413 : return dict;
17402 : }
17403 :
17404 : template <typename Derived, typename Shape>
17405 18842142 : Handle<Derived> BaseNameDictionary<Derived, Shape>::EnsureCapacity(
17406 : Handle<Derived> dictionary, int n) {
17407 : // Check whether there are enough enumeration indices to add n elements.
17408 37684284 : if (!PropertyDetails::IsValidIndex(dictionary->NextEnumerationIndex() + n)) {
17409 : // If not, we generate new indices for the properties.
17410 : int length = dictionary->NumberOfElements();
17411 :
17412 0 : Handle<FixedArray> iteration_order = IterationIndices(dictionary);
17413 : DCHECK_EQ(length, iteration_order->length());
17414 :
17415 : // Iterate over the dictionary using the enumeration order and update
17416 : // the dictionary with new enumeration indices.
17417 0 : for (int i = 0; i < length; i++) {
17418 : int index = Smi::ToInt(iteration_order->get(i));
17419 : DCHECK(dictionary->IsKey(dictionary->GetIsolate(),
17420 : dictionary->KeyAt(index)));
17421 :
17422 0 : int enum_index = PropertyDetails::kInitialIndex + i;
17423 :
17424 : PropertyDetails details = dictionary->DetailsAt(index);
17425 : PropertyDetails new_details = details.set_index(enum_index);
17426 : dictionary->DetailsAtPut(index, new_details);
17427 : }
17428 :
17429 : // Set the next enumeration index.
17430 0 : dictionary->SetNextEnumerationIndex(PropertyDetails::kInitialIndex +
17431 : length);
17432 : }
17433 18842142 : return HashTable<Derived, Shape>::EnsureCapacity(dictionary, n);
17434 : }
17435 :
17436 : template <typename Derived, typename Shape>
17437 82841 : Handle<Derived> Dictionary<Derived, Shape>::DeleteEntry(
17438 : Handle<Derived> dictionary, int entry) {
17439 : DCHECK(Shape::kEntrySize != 3 ||
17440 : dictionary->DetailsAt(entry).IsConfigurable());
17441 82841 : dictionary->ClearEntry(entry);
17442 82841 : dictionary->ElementRemoved();
17443 82841 : return Shrink(dictionary);
17444 : }
17445 :
17446 : template <typename Derived, typename Shape>
17447 501034 : Handle<Derived> Dictionary<Derived, Shape>::AtPut(Handle<Derived> dictionary,
17448 : Key key, Handle<Object> value,
17449 : PropertyDetails details) {
17450 : int entry = dictionary->FindEntry(key);
17451 :
17452 : // If the entry is present set the value;
17453 501034 : if (entry == Dictionary::kNotFound) {
17454 499565 : return Derived::Add(dictionary, key, value, details);
17455 : }
17456 :
17457 : // We don't need to copy over the enumeration index.
17458 : dictionary->ValueAtPut(entry, *value);
17459 : if (Shape::kEntrySize == 3) dictionary->DetailsAtPut(entry, details);
17460 1469 : return dictionary;
17461 : }
17462 :
17463 : template <typename Derived, typename Shape>
17464 18842142 : Handle<Derived> BaseNameDictionary<Derived, Shape>::Add(
17465 : Handle<Derived> dictionary, Key key, Handle<Object> value,
17466 : PropertyDetails details, int* entry_out) {
17467 : // Insert element at empty or deleted entry
17468 : DCHECK_EQ(0, details.dictionary_index());
17469 : // Assign an enumeration index to the property and update
17470 : // SetNextEnumerationIndex.
17471 : int index = dictionary->NextEnumerationIndex();
17472 : details = details.set_index(index);
17473 18842142 : dictionary->SetNextEnumerationIndex(index + 1);
17474 : return Dictionary<Derived, Shape>::Add(dictionary, key, value, details,
17475 18842142 : entry_out);
17476 : }
17477 :
17478 : template <typename Derived, typename Shape>
17479 23270428 : Handle<Derived> Dictionary<Derived, Shape>::Add(Handle<Derived> dictionary,
17480 : Key key, Handle<Object> value,
17481 : PropertyDetails details,
17482 : int* entry_out) {
17483 : Isolate* isolate = dictionary->GetIsolate();
17484 23168086 : uint32_t hash = Shape::Hash(isolate, key);
17485 : // Valdate key is absent.
17486 : SLOW_DCHECK((dictionary->FindEntry(key) == Dictionary::kNotFound));
17487 : // Check whether the dictionary should be extended.
17488 23270428 : dictionary = Derived::EnsureCapacity(dictionary, 1);
17489 :
17490 : // Compute the key object.
17491 : Handle<Object> k = Shape::AsHandle(isolate, key);
17492 :
17493 23270428 : uint32_t entry = dictionary->FindInsertionEntry(hash);
17494 46540856 : dictionary->SetEntry(entry, *k, *value, details);
17495 : DCHECK(dictionary->KeyAt(entry)->IsNumber() ||
17496 : Shape::Unwrap(dictionary->KeyAt(entry))->IsUniqueName());
17497 23270428 : dictionary->ElementAdded();
17498 23270428 : if (entry_out) *entry_out = entry;
17499 23270428 : return dictionary;
17500 : }
17501 :
17502 6707 : bool SeededNumberDictionary::HasComplexElements() {
17503 6707 : if (!requires_slow_elements()) return false;
17504 : Isolate* isolate = this->GetIsolate();
17505 : int capacity = this->Capacity();
17506 27285 : for (int i = 0; i < capacity; i++) {
17507 : Object* k;
17508 37885 : if (!this->ToKey(isolate, i, &k)) continue;
17509 : PropertyDetails details = this->DetailsAt(i);
17510 9720 : if (details.kind() == kAccessor) return true;
17511 : PropertyAttributes attr = details.attributes();
17512 9620 : if (attr & ALL_ATTRIBUTES_MASK) return true;
17513 : }
17514 : return false;
17515 : }
17516 :
17517 1884295 : void SeededNumberDictionary::UpdateMaxNumberKey(
17518 : uint32_t key, Handle<JSObject> dictionary_holder) {
17519 : DisallowHeapAllocation no_allocation;
17520 : // If the dictionary requires slow elements an element has already
17521 : // been added at a high index.
17522 1884295 : if (requires_slow_elements()) return;
17523 : // Check if this index is high enough that we should require slow
17524 : // elements.
17525 1834256 : if (key > kRequiresSlowElementsLimit) {
17526 4097 : if (!dictionary_holder.is_null()) {
17527 3829 : dictionary_holder->RequireSlowElements(this);
17528 : }
17529 : set_requires_slow_elements();
17530 : return;
17531 : }
17532 : // Update max key value.
17533 : Object* max_index_object = get(kMaxNumberKeyIndex);
17534 1830159 : if (!max_index_object->IsSmi() || max_number_key() < key) {
17535 : FixedArray::set(kMaxNumberKeyIndex,
17536 1209660 : Smi::FromInt(key << kRequiresSlowElementsTagSize));
17537 : }
17538 : }
17539 :
17540 404612 : Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
17541 : Handle<SeededNumberDictionary> dictionary, uint32_t key,
17542 : Handle<Object> value, Handle<JSObject> dictionary_holder,
17543 : PropertyDetails details) {
17544 404612 : dictionary->UpdateMaxNumberKey(key, dictionary_holder);
17545 404612 : return AtPut(dictionary, key, value, details);
17546 : }
17547 :
17548 40 : void SeededNumberDictionary::CopyValuesTo(FixedArray* elements) {
17549 : Isolate* isolate = this->GetIsolate();
17550 : int pos = 0;
17551 : int capacity = this->Capacity();
17552 : DisallowHeapAllocation no_gc;
17553 40 : WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
17554 680 : for (int i = 0; i < capacity; i++) {
17555 : Object* k;
17556 640 : if (this->ToKey(isolate, i, &k)) {
17557 300 : elements->set(pos++, this->ValueAt(i), mode);
17558 : }
17559 : }
17560 : DCHECK_EQ(pos, elements->length());
17561 40 : }
17562 :
17563 96422 : Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
17564 : Handle<UnseededNumberDictionary> dictionary,
17565 : uint32_t key,
17566 : Handle<Object> value) {
17567 96422 : return AtPut(dictionary, key, value, PropertyDetails::Empty());
17568 : }
17569 :
17570 : template <typename Derived, typename Shape>
17571 87649 : int Dictionary<Derived, Shape>::NumberOfEnumerableProperties() {
17572 : Isolate* isolate = this->GetIsolate();
17573 : int capacity = this->Capacity();
17574 : int result = 0;
17575 8402185 : for (int i = 0; i < capacity; i++) {
17576 : Object* k;
17577 12531727 : if (!this->ToKey(isolate, i, &k)) continue;
17578 4115883 : if (k->FilterKey(ENUMERABLE_STRINGS)) continue;
17579 : PropertyDetails details = this->DetailsAt(i);
17580 : PropertyAttributes attr = details.attributes();
17581 4097345 : if ((attr & ONLY_ENUMERABLE) == 0) result++;
17582 : }
17583 87649 : return result;
17584 : }
17585 :
17586 :
17587 : template <typename Dictionary>
17588 : struct EnumIndexComparator {
17589 654657 : explicit EnumIndexComparator(Dictionary* dict) : dict(dict) {}
17590 88090467 : bool operator()(const base::AtomicElement<Smi*>& a,
17591 : const base::AtomicElement<Smi*>& b) {
17592 88090467 : PropertyDetails da(dict->DetailsAt(a.value()->value()));
17593 88090467 : PropertyDetails db(dict->DetailsAt(b.value()->value()));
17594 88090467 : return da.dictionary_index() < db.dictionary_index();
17595 : }
17596 : Dictionary* dict;
17597 : };
17598 :
17599 : template <typename Derived, typename Shape>
17600 86823 : void BaseNameDictionary<Derived, Shape>::CopyEnumKeysTo(
17601 : Handle<Derived> dictionary, Handle<FixedArray> storage,
17602 : KeyCollectionMode mode, KeyAccumulator* accumulator) {
17603 : DCHECK_IMPLIES(mode != KeyCollectionMode::kOwnOnly, accumulator != nullptr);
17604 : Isolate* isolate = dictionary->GetIsolate();
17605 : int length = storage->length();
17606 : int capacity = dictionary->Capacity();
17607 : int properties = 0;
17608 8355210 : for (int i = 0; i < capacity; i++) {
17609 : Object* key;
17610 13508466 : if (!dictionary->ToKey(isolate, i, &key)) continue;
17611 : bool is_shadowing_key = false;
17612 8227624 : if (key->IsSymbol()) continue;
17613 : PropertyDetails details = dictionary->DetailsAt(i);
17614 4095426 : if (details.IsDontEnum()) {
17615 1017638 : if (mode == KeyCollectionMode::kIncludePrototypes) {
17616 : is_shadowing_key = true;
17617 : } else {
17618 : continue;
17619 : }
17620 : }
17621 3090978 : if (is_shadowing_key) {
17622 13190 : accumulator->AddShadowingKey(key);
17623 13190 : continue;
17624 : } else {
17625 : storage->set(properties, Smi::FromInt(i));
17626 : }
17627 3077788 : properties++;
17628 3077788 : if (mode == KeyCollectionMode::kOwnOnly && properties == length) break;
17629 : }
17630 :
17631 86823 : CHECK_EQ(length, properties);
17632 : DisallowHeapAllocation no_gc;
17633 : Derived* raw_dictionary = *dictionary;
17634 : FixedArray* raw_storage = *storage;
17635 : EnumIndexComparator<Derived> cmp(raw_dictionary);
17636 : // Use AtomicElement wrapper to ensure that std::sort uses atomic load and
17637 : // store operations that are safe for concurrent marking.
17638 : base::AtomicElement<Smi*>* start =
17639 : reinterpret_cast<base::AtomicElement<Smi*>*>(
17640 86823 : storage->GetFirstElementAddress());
17641 86823 : std::sort(start, start + length, cmp);
17642 3164611 : for (int i = 0; i < length; i++) {
17643 : int index = Smi::ToInt(raw_storage->get(i));
17644 3077788 : raw_storage->set(i, raw_dictionary->NameAt(index));
17645 : }
17646 86823 : }
17647 :
17648 : template <typename Derived, typename Shape>
17649 528179 : Handle<FixedArray> BaseNameDictionary<Derived, Shape>::IterationIndices(
17650 : Handle<Derived> dictionary) {
17651 : Isolate* isolate = dictionary->GetIsolate();
17652 : int capacity = dictionary->Capacity();
17653 : int length = dictionary->NumberOfElements();
17654 528179 : Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
17655 : int array_size = 0;
17656 : {
17657 : DisallowHeapAllocation no_gc;
17658 : Derived* raw_dictionary = *dictionary;
17659 16440735 : for (int i = 0; i < capacity; i++) {
17660 : Object* k;
17661 25232531 : if (!raw_dictionary->ToKey(isolate, i, &k)) continue;
17662 6592581 : array->set(array_size++, Smi::FromInt(i));
17663 : }
17664 :
17665 : DCHECK_EQ(array_size, length);
17666 :
17667 : EnumIndexComparator<Derived> cmp(raw_dictionary);
17668 : // Use AtomicElement wrapper to ensure that std::sort uses atomic load and
17669 : // store operations that are safe for concurrent marking.
17670 : base::AtomicElement<Smi*>* start =
17671 : reinterpret_cast<base::AtomicElement<Smi*>*>(
17672 528179 : array->GetFirstElementAddress());
17673 528179 : std::sort(start, start + array_size, cmp);
17674 : }
17675 528179 : array->Shrink(array_size);
17676 528179 : return array;
17677 : }
17678 :
17679 : template <typename Derived, typename Shape>
17680 39655 : void BaseNameDictionary<Derived, Shape>::CollectKeysTo(
17681 : Handle<Derived> dictionary, KeyAccumulator* keys) {
17682 : Isolate* isolate = keys->isolate();
17683 : int capacity = dictionary->Capacity();
17684 : Handle<FixedArray> array =
17685 39655 : isolate->factory()->NewFixedArray(dictionary->NumberOfElements());
17686 : int array_size = 0;
17687 : PropertyFilter filter = keys->filter();
17688 : {
17689 : DisallowHeapAllocation no_gc;
17690 : Derived* raw_dictionary = *dictionary;
17691 10079431 : for (int i = 0; i < capacity; i++) {
17692 : Object* k;
17693 17569989 : if (!raw_dictionary->ToKey(isolate, i, &k)) continue;
17694 4681625 : if (k->FilterKey(filter)) continue;
17695 : PropertyDetails details = raw_dictionary->DetailsAt(i);
17696 2510459 : if ((details.attributes() & filter) != 0) {
17697 550 : keys->AddShadowingKey(k);
17698 550 : continue;
17699 : }
17700 2509909 : if (filter & ONLY_ALL_CAN_READ) {
17701 362 : if (details.kind() != kAccessor) continue;
17702 0 : Object* accessors = raw_dictionary->ValueAt(i);
17703 26 : if (!accessors->IsAccessorInfo()) continue;
17704 26 : if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
17705 : }
17706 2509563 : array->set(array_size++, Smi::FromInt(i));
17707 : }
17708 :
17709 : EnumIndexComparator<Derived> cmp(raw_dictionary);
17710 : // Use AtomicElement wrapper to ensure that std::sort uses atomic load and
17711 : // store operations that are safe for concurrent marking.
17712 : base::AtomicElement<Smi*>* start =
17713 : reinterpret_cast<base::AtomicElement<Smi*>*>(
17714 39655 : array->GetFirstElementAddress());
17715 39655 : std::sort(start, start + array_size, cmp);
17716 : }
17717 :
17718 : bool has_seen_symbol = false;
17719 2549218 : for (int i = 0; i < array_size; i++) {
17720 : int index = Smi::ToInt(array->get(i));
17721 : Object* key = dictionary->NameAt(index);
17722 2509563 : if (key->IsSymbol()) {
17723 : has_seen_symbol = true;
17724 : continue;
17725 : }
17726 2491357 : keys->AddKey(key, DO_NOT_CONVERT);
17727 : }
17728 39655 : if (has_seen_symbol) {
17729 23988 : for (int i = 0; i < array_size; i++) {
17730 : int index = Smi::ToInt(array->get(i));
17731 : Object* key = dictionary->NameAt(index);
17732 23988 : if (!key->IsSymbol()) continue;
17733 18206 : keys->AddKey(key, DO_NOT_CONVERT);
17734 : }
17735 : }
17736 39655 : }
17737 :
17738 : // Backwards lookup (slow).
17739 : template <typename Derived, typename Shape>
17740 10 : Object* Dictionary<Derived, Shape>::SlowReverseLookup(Object* value) {
17741 : Derived* dictionary = Derived::cast(this);
17742 : Isolate* isolate = dictionary->GetIsolate();
17743 : int capacity = dictionary->Capacity();
17744 2570 : for (int i = 0; i < capacity; i++) {
17745 : Object* k;
17746 4060 : if (!dictionary->ToKey(isolate, i, &k)) continue;
17747 0 : Object* e = dictionary->ValueAt(i);
17748 1060 : if (e == value) return k;
17749 : }
17750 10 : return isolate->heap()->undefined_value();
17751 : }
17752 :
17753 :
17754 35159 : Object* ObjectHashTable::Lookup(Isolate* isolate, Handle<Object> key,
17755 : int32_t hash) {
17756 : DisallowHeapAllocation no_gc;
17757 : DCHECK(IsKey(isolate, *key));
17758 :
17759 35159 : int entry = FindEntry(isolate, key, hash);
17760 35159 : if (entry == kNotFound) return isolate->heap()->the_hole_value();
17761 68574 : return get(EntryToIndex(entry) + 1);
17762 : }
17763 :
17764 :
17765 35781 : Object* ObjectHashTable::Lookup(Handle<Object> key) {
17766 : DisallowHeapAllocation no_gc;
17767 :
17768 : Isolate* isolate = GetIsolate();
17769 : DCHECK(IsKey(isolate, *key));
17770 :
17771 : // If the object does not have an identity hash, it was never used as a key.
17772 35781 : Object* hash = key->GetHash();
17773 35781 : if (hash->IsUndefined(isolate)) {
17774 622 : return isolate->heap()->the_hole_value();
17775 : }
17776 35159 : return Lookup(isolate, key, Smi::ToInt(hash));
17777 : }
17778 :
17779 148 : Object* ObjectHashTable::ValueAt(int entry) {
17780 148 : return get(EntryToValueIndex(entry));
17781 : }
17782 :
17783 0 : Object* ObjectHashTable::Lookup(Handle<Object> key, int32_t hash) {
17784 0 : return Lookup(GetIsolate(), key, hash);
17785 : }
17786 :
17787 :
17788 32341 : Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
17789 : Handle<Object> key,
17790 : Handle<Object> value) {
17791 : Isolate* isolate = table->GetIsolate();
17792 : DCHECK(table->IsKey(isolate, *key));
17793 : DCHECK(!value->IsTheHole(isolate));
17794 :
17795 : // Make sure the key object has an identity hash code.
17796 32341 : int32_t hash = key->GetOrCreateHash(isolate)->value();
17797 :
17798 32341 : return Put(table, key, value, hash);
17799 : }
17800 :
17801 :
17802 34558 : Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
17803 : Handle<Object> key,
17804 : Handle<Object> value,
17805 : int32_t hash) {
17806 : Isolate* isolate = table->GetIsolate();
17807 : DCHECK(table->IsKey(isolate, *key));
17808 : DCHECK(!value->IsTheHole(isolate));
17809 :
17810 34558 : int entry = table->FindEntry(isolate, key, hash);
17811 :
17812 : // Key is already in table, just overwrite value.
17813 34558 : if (entry != kNotFound) {
17814 1036 : table->set(EntryToIndex(entry) + 1, *value);
17815 518 : return table;
17816 : }
17817 :
17818 : // Rehash if more than 33% of the entries are deleted entries.
17819 : // TODO(jochen): Consider to shrink the fixed array in place.
17820 68080 : if ((table->NumberOfDeletedElements() << 1) > table->NumberOfElements()) {
17821 6 : table->Rehash();
17822 : }
17823 : // If we're out of luck, we didn't get a GC recently, and so rehashing
17824 : // isn't enough to avoid a crash.
17825 34040 : if (!table->HasSufficientCapacityToAdd(1)) {
17826 285 : int nof = table->NumberOfElements() + 1;
17827 285 : int capacity = ObjectHashTable::ComputeCapacity(nof * 2);
17828 285 : if (capacity > ObjectHashTable::kMaxCapacity) {
17829 0 : for (size_t i = 0; i < 2; ++i) {
17830 : isolate->heap()->CollectAllGarbage(
17831 : Heap::kFinalizeIncrementalMarkingMask,
17832 0 : GarbageCollectionReason::kFullHashtable);
17833 : }
17834 0 : table->Rehash();
17835 : }
17836 : }
17837 :
17838 : // Check whether the hash table should be extended.
17839 34040 : table = EnsureCapacity(table, 1);
17840 102120 : table->AddEntry(table->FindInsertionEntry(hash), *key, *value);
17841 34040 : return table;
17842 : }
17843 :
17844 :
17845 6 : Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
17846 : Handle<Object> key,
17847 : bool* was_present) {
17848 : DCHECK(table->IsKey(table->GetIsolate(), *key));
17849 :
17850 6 : Object* hash = key->GetHash();
17851 6 : if (hash->IsUndefined(table->GetIsolate())) {
17852 0 : *was_present = false;
17853 0 : return table;
17854 : }
17855 :
17856 6 : return Remove(table, key, was_present, Smi::ToInt(hash));
17857 : }
17858 :
17859 :
17860 83 : Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
17861 : Handle<Object> key,
17862 : bool* was_present,
17863 : int32_t hash) {
17864 : Isolate* isolate = table->GetIsolate();
17865 : DCHECK(table->IsKey(isolate, *key));
17866 :
17867 83 : int entry = table->FindEntry(isolate, key, hash);
17868 83 : if (entry == kNotFound) {
17869 0 : *was_present = false;
17870 0 : return table;
17871 : }
17872 :
17873 83 : *was_present = true;
17874 83 : table->RemoveEntry(entry);
17875 : return Shrink(table);
17876 : }
17877 :
17878 :
17879 34040 : void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
17880 34040 : set(EntryToIndex(entry), key);
17881 34040 : set(EntryToIndex(entry) + 1, value);
17882 34040 : ElementAdded();
17883 34040 : }
17884 :
17885 :
17886 173 : void ObjectHashTable::RemoveEntry(int entry) {
17887 173 : set_the_hole(EntryToIndex(entry));
17888 173 : set_the_hole(EntryToIndex(entry) + 1);
17889 173 : ElementRemoved();
17890 173 : }
17891 :
17892 :
17893 491672 : Object* WeakHashTable::Lookup(Handle<HeapObject> key) {
17894 : DisallowHeapAllocation no_gc;
17895 : Isolate* isolate = GetIsolate();
17896 : DCHECK(IsKey(isolate, *key));
17897 : int entry = FindEntry(key);
17898 491672 : if (entry == kNotFound) return isolate->heap()->the_hole_value();
17899 380578 : return get(EntryToValueIndex(entry));
17900 : }
17901 :
17902 :
17903 491672 : Handle<WeakHashTable> WeakHashTable::Put(Handle<WeakHashTable> table,
17904 : Handle<HeapObject> key,
17905 : Handle<HeapObject> value) {
17906 : Isolate* isolate = key->GetIsolate();
17907 : DCHECK(table->IsKey(isolate, *key));
17908 : int entry = table->FindEntry(key);
17909 : // Key is already in table, just overwrite value.
17910 491672 : if (entry != kNotFound) {
17911 380578 : table->set(EntryToValueIndex(entry), *value);
17912 380578 : return table;
17913 : }
17914 :
17915 111094 : Handle<WeakCell> key_cell = isolate->factory()->NewWeakCell(key);
17916 :
17917 : // Check whether the hash table should be extended.
17918 111094 : table = EnsureCapacity(table, 1, TENURED);
17919 :
17920 111094 : uint32_t hash = ShapeT::Hash(isolate, key);
17921 222188 : table->AddEntry(table->FindInsertionEntry(hash), key_cell, value);
17922 111094 : return table;
17923 : }
17924 :
17925 :
17926 111094 : void WeakHashTable::AddEntry(int entry, Handle<WeakCell> key_cell,
17927 : Handle<HeapObject> value) {
17928 : DisallowHeapAllocation no_allocation;
17929 111094 : set(EntryToIndex(entry), *key_cell);
17930 111094 : set(EntryToValueIndex(entry), *value);
17931 111094 : ElementAdded();
17932 111094 : }
17933 :
17934 : template <class Derived, int entrysize>
17935 5630890 : Handle<Derived> OrderedHashTable<Derived, entrysize>::Allocate(
17936 : Isolate* isolate, int capacity, PretenureFlag pretenure) {
17937 : // Capacity must be a power of two, since we depend on being able
17938 : // to divide and multiple by 2 (kLoadFactor) to derive capacity
17939 : // from number of buckets. If we decide to change kLoadFactor
17940 : // to something other than 2, capacity should be stored as another
17941 : // field of this object.
17942 5630890 : capacity = base::bits::RoundUpToPowerOfTwo32(Max(kMinCapacity, capacity));
17943 5630890 : if (capacity > kMaxCapacity) {
17944 0 : v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
17945 : }
17946 5630890 : int num_buckets = capacity / kLoadFactor;
17947 : Handle<FixedArray> backing_store = isolate->factory()->NewFixedArray(
17948 5630890 : kHashTableStartIndex + num_buckets + (capacity * kEntrySize), pretenure);
17949 : backing_store->set_map_no_write_barrier(
17950 5630890 : isolate->heap()->ordered_hash_table_map());
17951 : Handle<Derived> table = Handle<Derived>::cast(backing_store);
17952 53184620 : for (int i = 0; i < num_buckets; ++i) {
17953 : table->set(kHashTableStartIndex + i, Smi::FromInt(kNotFound));
17954 : }
17955 : table->SetNumberOfBuckets(num_buckets);
17956 : table->SetNumberOfElements(0);
17957 : table->SetNumberOfDeletedElements(0);
17958 5630890 : return table;
17959 : }
17960 :
17961 : template <class Derived, int entrysize>
17962 46792909 : Handle<Derived> OrderedHashTable<Derived, entrysize>::EnsureGrowable(
17963 : Handle<Derived> table) {
17964 : DCHECK(!table->IsObsolete());
17965 :
17966 : int nof = table->NumberOfElements();
17967 : int nod = table->NumberOfDeletedElements();
17968 : int capacity = table->Capacity();
17969 46792909 : if ((nof + nod) < capacity) return table;
17970 : // Don't need to grow if we can simply clear out deleted entries instead.
17971 : // Note that we can't compact in place, though, so we always allocate
17972 : // a new table.
17973 119313 : return Rehash(table, (nod < (capacity >> 1)) ? capacity << 1 : capacity);
17974 : }
17975 :
17976 : template <class Derived, int entrysize>
17977 135127 : Handle<Derived> OrderedHashTable<Derived, entrysize>::Shrink(
17978 : Handle<Derived> table) {
17979 : DCHECK(!table->IsObsolete());
17980 :
17981 : int nof = table->NumberOfElements();
17982 : int capacity = table->Capacity();
17983 135127 : if (nof >= (capacity >> 2)) return table;
17984 135127 : return Rehash(table, capacity / 2);
17985 : }
17986 :
17987 : template <class Derived, int entrysize>
17988 236 : Handle<Derived> OrderedHashTable<Derived, entrysize>::Clear(
17989 : Handle<Derived> table) {
17990 : DCHECK(!table->IsObsolete());
17991 :
17992 : Handle<Derived> new_table =
17993 : Allocate(table->GetIsolate(),
17994 : kMinCapacity,
17995 472 : table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
17996 :
17997 : table->SetNextTable(*new_table);
17998 : table->SetNumberOfDeletedElements(kClearedTableSentinel);
17999 :
18000 236 : return new_table;
18001 : }
18002 :
18003 : template <class Derived, int entrysize>
18004 534 : bool OrderedHashTable<Derived, entrysize>::HasKey(Isolate* isolate,
18005 : Derived* table, Object* key) {
18006 : DCHECK(table->IsOrderedHashTable());
18007 : DisallowHeapAllocation no_gc;
18008 534 : int entry = table->FindEntry(isolate, key);
18009 534 : return entry != kNotFound;
18010 : }
18011 :
18012 46781832 : Handle<OrderedHashSet> OrderedHashSet::Add(Handle<OrderedHashSet> table,
18013 : Handle<Object> key) {
18014 46781832 : int hash = key->GetOrCreateHash(table->GetIsolate())->value();
18015 46781832 : int entry = table->HashToEntry(hash);
18016 : // Walk the chain of the bucket and try finding the key.
18017 112731962 : while (entry != kNotFound) {
18018 19168857 : Object* candidate_key = table->KeyAt(entry);
18019 : // Do not add if we have the key already
18020 19168857 : if (candidate_key->SameValueZero(*key)) return table;
18021 19168298 : entry = table->NextChainEntry(entry);
18022 : }
18023 :
18024 46781273 : table = OrderedHashSet::EnsureGrowable(table);
18025 : // Read the existing bucket values.
18026 : int bucket = table->HashToBucket(hash);
18027 46781273 : int previous_entry = table->HashToEntry(hash);
18028 : int nof = table->NumberOfElements();
18029 : // Insert a new entry at the end,
18030 46781273 : int new_entry = nof + table->NumberOfDeletedElements();
18031 : int new_index = table->EntryToIndex(new_entry);
18032 46781273 : table->set(new_index, *key);
18033 : table->set(new_index + kChainOffset, Smi::FromInt(previous_entry));
18034 : // and point the bucket to the new entry.
18035 : table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
18036 46781273 : table->SetNumberOfElements(nof + 1);
18037 46781273 : return table;
18038 : }
18039 :
18040 5375650 : Handle<FixedArray> OrderedHashSet::ConvertToKeysArray(
18041 : Handle<OrderedHashSet> table, GetKeysConversion convert) {
18042 : Isolate* isolate = table->GetIsolate();
18043 : int length = table->NumberOfElements();
18044 : int nof_buckets = table->NumberOfBuckets();
18045 : // Convert the dictionary to a linear list.
18046 : Handle<FixedArray> result = Handle<FixedArray>::cast(table);
18047 : // From this point on table is no longer a valid OrderedHashSet.
18048 10751300 : result->set_map(isolate->heap()->fixed_array_map());
18049 52156773 : for (int i = 0; i < length; i++) {
18050 46781123 : int index = kHashTableStartIndex + nof_buckets + (i * kEntrySize);
18051 : Object* key = table->get(index);
18052 46781123 : if (convert == GetKeysConversion::kConvertToString) {
18053 : uint32_t index_value;
18054 4320215 : if (key->ToArrayIndex(&index_value)) {
18055 512810 : key = *isolate->factory()->Uint32ToString(index_value);
18056 : } else {
18057 4063810 : CHECK(key->IsName());
18058 : }
18059 : }
18060 46781123 : result->set(i, key);
18061 : }
18062 5375650 : result->Shrink(length);
18063 5375650 : return result;
18064 : }
18065 :
18066 : template <class Derived, int entrysize>
18067 254440 : Handle<Derived> OrderedHashTable<Derived, entrysize>::Rehash(
18068 : Handle<Derived> table, int new_capacity) {
18069 : Isolate* isolate = table->GetIsolate();
18070 : DCHECK(!table->IsObsolete());
18071 :
18072 : Handle<Derived> new_table =
18073 : Allocate(isolate, new_capacity,
18074 254440 : isolate->heap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
18075 : int nof = table->NumberOfElements();
18076 : int nod = table->NumberOfDeletedElements();
18077 : int new_buckets = new_table->NumberOfBuckets();
18078 : int new_entry = 0;
18079 : int removed_holes_index = 0;
18080 :
18081 : DisallowHeapAllocation no_gc;
18082 4744873 : for (int old_entry = 0; old_entry < (nof + nod); ++old_entry) {
18083 4490433 : Object* key = table->KeyAt(old_entry);
18084 4490433 : if (key->IsTheHole(isolate)) {
18085 213270 : table->SetRemovedIndexAt(removed_holes_index++, old_entry);
18086 : continue;
18087 : }
18088 :
18089 4277163 : Object* hash = key->GetHash();
18090 4277162 : int bucket = Smi::ToInt(hash) & (new_buckets - 1);
18091 4277162 : Object* chain_entry = new_table->get(kHashTableStartIndex + bucket);
18092 : new_table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
18093 : int new_index = new_table->EntryToIndex(new_entry);
18094 : int old_index = table->EntryToIndex(old_entry);
18095 8567800 : for (int i = 0; i < entrysize; ++i) {
18096 4290636 : Object* value = table->get(old_index + i);
18097 8581272 : new_table->set(new_index + i, value);
18098 : }
18099 8554328 : new_table->set(new_index + kChainOffset, chain_entry);
18100 4277163 : ++new_entry;
18101 : }
18102 :
18103 : DCHECK_EQ(nod, removed_holes_index);
18104 :
18105 : new_table->SetNumberOfElements(nof);
18106 : table->SetNextTable(*new_table);
18107 :
18108 254440 : return new_table;
18109 : }
18110 :
18111 : template <class Derived, int entrysize>
18112 96 : bool OrderedHashTable<Derived, entrysize>::Delete(Isolate* isolate,
18113 : Derived* table, Object* key) {
18114 : DisallowHeapAllocation no_gc;
18115 96 : int entry = table->FindEntry(isolate, key);
18116 96 : if (entry == kNotFound) return false;
18117 :
18118 : int nof = table->NumberOfElements();
18119 : int nod = table->NumberOfDeletedElements();
18120 : int index = table->EntryToIndex(entry);
18121 :
18122 48 : Object* hole = isolate->heap()->the_hole_value();
18123 120 : for (int i = 0; i < entrysize; ++i) {
18124 72 : table->set(index + i, hole);
18125 : }
18126 :
18127 48 : table->SetNumberOfElements(nof - 1);
18128 48 : table->SetNumberOfDeletedElements(nod + 1);
18129 :
18130 48 : return true;
18131 : }
18132 :
18133 78003 : Object* OrderedHashMap::GetHash(Isolate* isolate, Object* key) {
18134 : DisallowHeapAllocation no_gc;
18135 :
18136 78003 : Object* hash = key->GetHash();
18137 : // If the object does not have an identity hash, it was never used as a key
18138 78003 : if (hash->IsUndefined(isolate)) return Smi::FromInt(-1);
18139 : DCHECK(hash->IsSmi());
18140 : DCHECK_GE(Smi::cast(hash)->value(), 0);
18141 77652 : return hash;
18142 : }
18143 :
18144 96 : Handle<OrderedHashMap> OrderedHashMap::Add(Handle<OrderedHashMap> table,
18145 : Handle<Object> key,
18146 : Handle<Object> value) {
18147 96 : int hash = key->GetOrCreateHash(table->GetIsolate())->value();
18148 96 : int entry = table->HashToEntry(hash);
18149 : // Walk the chain of the bucket and try finding the key.
18150 : {
18151 : DisallowHeapAllocation no_gc;
18152 : Object* raw_key = *key;
18153 222 : while (entry != kNotFound) {
18154 54 : Object* candidate_key = table->KeyAt(entry);
18155 : // Do not add if we have the key already
18156 54 : if (candidate_key->SameValueZero(raw_key)) return table;
18157 30 : entry = table->NextChainEntry(entry);
18158 : }
18159 : }
18160 :
18161 72 : table = OrderedHashMap::EnsureGrowable(table);
18162 : // Read the existing bucket values.
18163 : int bucket = table->HashToBucket(hash);
18164 72 : int previous_entry = table->HashToEntry(hash);
18165 : int nof = table->NumberOfElements();
18166 : // Insert a new entry at the end,
18167 72 : int new_entry = nof + table->NumberOfDeletedElements();
18168 : int new_index = table->EntryToIndex(new_entry);
18169 72 : table->set(new_index, *key);
18170 144 : table->set(new_index + kValueOffset, *value);
18171 : table->set(new_index + kChainOffset, Smi::FromInt(previous_entry));
18172 : // and point the bucket to the new entry.
18173 : table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
18174 72 : table->SetNumberOfElements(nof + 1);
18175 72 : return table;
18176 : }
18177 :
18178 : template Handle<OrderedHashSet> OrderedHashTable<OrderedHashSet, 1>::Allocate(
18179 : Isolate* isolate, int capacity, PretenureFlag pretenure);
18180 :
18181 : template Handle<OrderedHashSet> OrderedHashTable<
18182 : OrderedHashSet, 1>::EnsureGrowable(Handle<OrderedHashSet> table);
18183 :
18184 : template Handle<OrderedHashSet> OrderedHashTable<OrderedHashSet, 1>::Shrink(
18185 : Handle<OrderedHashSet> table);
18186 :
18187 : template Handle<OrderedHashSet> OrderedHashTable<OrderedHashSet, 1>::Clear(
18188 : Handle<OrderedHashSet> table);
18189 :
18190 : template bool OrderedHashTable<OrderedHashSet, 1>::HasKey(Isolate* isolate,
18191 : OrderedHashSet* table,
18192 : Object* key);
18193 :
18194 : template bool OrderedHashTable<OrderedHashSet, 1>::Delete(Isolate* isolate,
18195 : OrderedHashSet* table,
18196 : Object* key);
18197 :
18198 : template Handle<OrderedHashMap> OrderedHashTable<OrderedHashMap, 2>::Allocate(
18199 : Isolate* isolate, int capacity, PretenureFlag pretenure);
18200 :
18201 : template Handle<OrderedHashMap> OrderedHashTable<
18202 : OrderedHashMap, 2>::EnsureGrowable(Handle<OrderedHashMap> table);
18203 :
18204 : template Handle<OrderedHashMap> OrderedHashTable<OrderedHashMap, 2>::Shrink(
18205 : Handle<OrderedHashMap> table);
18206 :
18207 : template Handle<OrderedHashMap> OrderedHashTable<OrderedHashMap, 2>::Clear(
18208 : Handle<OrderedHashMap> table);
18209 :
18210 : template bool OrderedHashTable<OrderedHashMap, 2>::HasKey(Isolate* isolate,
18211 : OrderedHashMap* table,
18212 : Object* key);
18213 :
18214 : template bool OrderedHashTable<OrderedHashMap, 2>::Delete(Isolate* isolate,
18215 : OrderedHashMap* table,
18216 : Object* key);
18217 :
18218 : template <>
18219 : Handle<SmallOrderedHashSet>
18220 0 : SmallOrderedHashTable<SmallOrderedHashSet>::Allocate(Isolate* isolate,
18221 : int capacity,
18222 : PretenureFlag pretenure) {
18223 36 : return isolate->factory()->NewSmallOrderedHashSet(capacity, pretenure);
18224 : }
18225 :
18226 : template <>
18227 : Handle<SmallOrderedHashMap>
18228 0 : SmallOrderedHashTable<SmallOrderedHashMap>::Allocate(Isolate* isolate,
18229 : int capacity,
18230 : PretenureFlag pretenure) {
18231 36 : return isolate->factory()->NewSmallOrderedHashMap(capacity, pretenure);
18232 : }
18233 :
18234 : template <class Derived>
18235 108 : void SmallOrderedHashTable<Derived>::Initialize(Isolate* isolate,
18236 : int capacity) {
18237 108 : int num_buckets = capacity / kLoadFactor;
18238 : int num_chains = capacity;
18239 :
18240 : SetNumberOfBuckets(num_buckets);
18241 : SetNumberOfElements(0);
18242 : SetNumberOfDeletedElements(0);
18243 :
18244 : byte* hashtable_start =
18245 108 : FIELD_ADDR(this, kHeaderSize + (kBucketsStartOffset * kOneByteSize));
18246 108 : memset(hashtable_start, kNotFound, num_buckets + num_chains);
18247 :
18248 108 : if (isolate->heap()->InNewSpace(this)) {
18249 : MemsetPointer(RawField(this, GetDataTableStartOffset()),
18250 : isolate->heap()->the_hole_value(),
18251 108 : capacity * Derived::kEntrySize);
18252 : } else {
18253 0 : for (int i = 0; i < capacity; i++) {
18254 0 : for (int j = 0; j < Derived::kEntrySize; i++) {
18255 0 : SetDataEntry(i, j, isolate->heap()->the_hole_value());
18256 : }
18257 : }
18258 : }
18259 :
18260 : #ifdef DEBUG
18261 : for (int i = 0; i < num_buckets; ++i) {
18262 : DCHECK_EQ(kNotFound, GetFirstEntry(i));
18263 : }
18264 :
18265 : for (int i = 0; i < num_chains; ++i) {
18266 : DCHECK_EQ(kNotFound, GetNextEntry(i));
18267 : }
18268 : #endif // DEBUG
18269 108 : }
18270 :
18271 1584 : Handle<SmallOrderedHashSet> SmallOrderedHashSet::Add(
18272 : Handle<SmallOrderedHashSet> table, Handle<Object> key) {
18273 : Isolate* isolate = table->GetIsolate();
18274 1584 : if (table->HasKey(isolate, key)) return table;
18275 :
18276 1560 : if (table->UsedCapacity() >= table->Capacity()) {
18277 36 : table = SmallOrderedHashSet::Grow(table);
18278 : }
18279 :
18280 1560 : int hash = key->GetOrCreateHash(table->GetIsolate())->value();
18281 : int nof = table->NumberOfElements();
18282 :
18283 : // Read the existing bucket values.
18284 : int bucket = table->HashToBucket(hash);
18285 : int previous_entry = table->HashToFirstEntry(hash);
18286 :
18287 : // Insert a new entry at the end,
18288 1560 : int new_entry = nof + table->NumberOfDeletedElements();
18289 :
18290 1560 : table->SetDataEntry(new_entry, SmallOrderedHashSet::kKeyIndex, *key);
18291 1560 : table->SetFirstEntry(bucket, new_entry);
18292 : table->SetNextEntry(new_entry, previous_entry);
18293 :
18294 : // and update book keeping.
18295 1560 : table->SetNumberOfElements(nof + 1);
18296 :
18297 1560 : return table;
18298 : }
18299 :
18300 1584 : Handle<SmallOrderedHashMap> SmallOrderedHashMap::Add(
18301 : Handle<SmallOrderedHashMap> table, Handle<Object> key,
18302 : Handle<Object> value) {
18303 : Isolate* isolate = table->GetIsolate();
18304 1584 : if (table->HasKey(isolate, key)) return table;
18305 :
18306 1560 : if (table->UsedCapacity() >= table->Capacity()) {
18307 36 : table = SmallOrderedHashMap::Grow(table);
18308 : }
18309 :
18310 1560 : int hash = key->GetOrCreateHash(table->GetIsolate())->value();
18311 : int nof = table->NumberOfElements();
18312 :
18313 : // Read the existing bucket values.
18314 : int bucket = table->HashToBucket(hash);
18315 : int previous_entry = table->HashToFirstEntry(hash);
18316 :
18317 : // Insert a new entry at the end,
18318 1560 : int new_entry = nof + table->NumberOfDeletedElements();
18319 :
18320 1560 : table->SetDataEntry(new_entry, SmallOrderedHashMap::kValueIndex, *value);
18321 1560 : table->SetDataEntry(new_entry, SmallOrderedHashMap::kKeyIndex, *key);
18322 1560 : table->SetFirstEntry(bucket, new_entry);
18323 : table->SetNextEntry(new_entry, previous_entry);
18324 :
18325 : // and update book keeping.
18326 1560 : table->SetNumberOfElements(nof + 1);
18327 :
18328 1560 : return table;
18329 : }
18330 :
18331 : template <class Derived>
18332 9564 : bool SmallOrderedHashTable<Derived>::HasKey(Isolate* isolate,
18333 : Handle<Object> key) {
18334 : DisallowHeapAllocation no_gc;
18335 : Object* raw_key = *key;
18336 9564 : Object* hash = key->GetHash();
18337 :
18338 9564 : if (hash->IsUndefined(isolate)) return false;
18339 : int entry = HashToFirstEntry(Smi::ToInt(hash));
18340 :
18341 : // Walk the chain in the bucket to find the key.
18342 34404 : while (entry != kNotFound) {
18343 : Object* candidate_key = KeyAt(entry);
18344 21696 : if (candidate_key->SameValueZero(raw_key)) return true;
18345 : entry = GetNextEntry(entry);
18346 : }
18347 : return false;
18348 : }
18349 :
18350 : template <class Derived>
18351 72 : Handle<Derived> SmallOrderedHashTable<Derived>::Rehash(Handle<Derived> table,
18352 : int new_capacity) {
18353 : DCHECK_GE(kMaxCapacity, new_capacity);
18354 : Isolate* isolate = table->GetIsolate();
18355 :
18356 : Handle<Derived> new_table = SmallOrderedHashTable<Derived>::Allocate(
18357 : isolate, new_capacity,
18358 72 : isolate->heap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
18359 : int nof = table->NumberOfElements();
18360 : int nod = table->NumberOfDeletedElements();
18361 : int new_entry = 0;
18362 :
18363 : {
18364 : DisallowHeapAllocation no_gc;
18365 3096 : for (int old_entry = 0; old_entry < (nof + nod); ++old_entry) {
18366 : Object* key = table->KeyAt(old_entry);
18367 3024 : if (key->IsTheHole(isolate)) continue;
18368 :
18369 3024 : int hash = Smi::ToInt(key->GetHash());
18370 : int bucket = new_table->HashToBucket(hash);
18371 : int chain = new_table->GetFirstEntry(bucket);
18372 :
18373 3024 : new_table->SetFirstEntry(bucket, new_entry);
18374 : new_table->SetNextEntry(new_entry, chain);
18375 :
18376 7560 : for (int i = 0; i < Derived::kEntrySize; ++i) {
18377 : Object* value = table->GetDataEntry(old_entry, i);
18378 4536 : new_table->SetDataEntry(new_entry, i, value);
18379 : }
18380 :
18381 3024 : ++new_entry;
18382 : }
18383 :
18384 : new_table->SetNumberOfElements(nof);
18385 : }
18386 72 : return new_table;
18387 : }
18388 :
18389 : template <class Derived>
18390 72 : Handle<Derived> SmallOrderedHashTable<Derived>::Grow(Handle<Derived> table) {
18391 : int capacity = table->Capacity();
18392 : int new_capacity = capacity;
18393 :
18394 : // Don't need to grow if we can simply clear out deleted entries instead.
18395 : // TODO(gsathya): Compact in place, instead of allocating a new table.
18396 72 : if (table->NumberOfDeletedElements() < (capacity >> 1)) {
18397 72 : new_capacity = capacity << 1;
18398 :
18399 : // The max capacity of our table is 254. We special case for 256 to
18400 : // account for our growth strategy, otherwise we would only fill up
18401 : // to 128 entries in our table.
18402 72 : if (new_capacity == kGrowthHack) {
18403 : new_capacity = kMaxCapacity;
18404 : }
18405 :
18406 : // TODO(gsathya): Transition to OrderedHashTable for size > kMaxCapacity.
18407 : }
18408 :
18409 72 : return Rehash(table, new_capacity);
18410 : }
18411 :
18412 : template bool SmallOrderedHashTable<SmallOrderedHashSet>::HasKey(
18413 : Isolate* isolate, Handle<Object> key);
18414 : template Handle<SmallOrderedHashSet>
18415 : SmallOrderedHashTable<SmallOrderedHashSet>::Rehash(
18416 : Handle<SmallOrderedHashSet> table, int new_capacity);
18417 : template Handle<SmallOrderedHashSet> SmallOrderedHashTable<
18418 : SmallOrderedHashSet>::Grow(Handle<SmallOrderedHashSet> table);
18419 : template void SmallOrderedHashTable<SmallOrderedHashSet>::Initialize(
18420 : Isolate* isolate, int capacity);
18421 :
18422 : template bool SmallOrderedHashTable<SmallOrderedHashMap>::HasKey(
18423 : Isolate* isolate, Handle<Object> key);
18424 : template Handle<SmallOrderedHashMap>
18425 : SmallOrderedHashTable<SmallOrderedHashMap>::Rehash(
18426 : Handle<SmallOrderedHashMap> table, int new_capacity);
18427 : template Handle<SmallOrderedHashMap> SmallOrderedHashTable<
18428 : SmallOrderedHashMap>::Grow(Handle<SmallOrderedHashMap> table);
18429 : template void SmallOrderedHashTable<SmallOrderedHashMap>::Initialize(
18430 : Isolate* isolate, int capacity);
18431 :
18432 : template<class Derived, class TableType>
18433 194 : void OrderedHashTableIterator<Derived, TableType>::Transition() {
18434 : DisallowHeapAllocation no_allocation;
18435 : TableType* table = TableType::cast(this->table());
18436 388 : if (!table->IsObsolete()) return;
18437 :
18438 : int index = Smi::ToInt(this->index());
18439 0 : while (table->IsObsolete()) {
18440 : TableType* next_table = table->NextTable();
18441 :
18442 0 : if (index > 0) {
18443 : int nod = table->NumberOfDeletedElements();
18444 :
18445 0 : if (nod == TableType::kClearedTableSentinel) {
18446 : index = 0;
18447 : } else {
18448 : int old_index = index;
18449 0 : for (int i = 0; i < nod; ++i) {
18450 : int removed_index = table->RemovedIndexAt(i);
18451 0 : if (removed_index >= old_index) break;
18452 0 : --index;
18453 : }
18454 : }
18455 : }
18456 :
18457 : table = next_table;
18458 : }
18459 :
18460 0 : set_table(table);
18461 0 : set_index(Smi::FromInt(index));
18462 : }
18463 :
18464 :
18465 : template<class Derived, class TableType>
18466 194 : bool OrderedHashTableIterator<Derived, TableType>::HasMore() {
18467 : DisallowHeapAllocation no_allocation;
18468 : Isolate* isolate = this->GetIsolate();
18469 :
18470 194 : Transition();
18471 :
18472 : TableType* table = TableType::cast(this->table());
18473 : int index = Smi::ToInt(this->index());
18474 194 : int used_capacity = table->UsedCapacity();
18475 :
18476 562 : while (index < used_capacity && table->KeyAt(index)->IsTheHole(isolate)) {
18477 0 : index++;
18478 : }
18479 :
18480 194 : set_index(Smi::FromInt(index));
18481 :
18482 194 : if (index < used_capacity) return true;
18483 :
18484 20 : set_table(isolate->heap()->empty_ordered_hash_table());
18485 20 : return false;
18486 : }
18487 :
18488 : template bool
18489 : OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::HasMore();
18490 :
18491 : template void
18492 : OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::MoveNext();
18493 :
18494 : template Object*
18495 : OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::CurrentKey();
18496 :
18497 : template void
18498 : OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Transition();
18499 :
18500 :
18501 : template bool
18502 : OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::HasMore();
18503 :
18504 : template void
18505 : OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::MoveNext();
18506 :
18507 : template Object*
18508 : OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::CurrentKey();
18509 :
18510 : template void
18511 : OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Transition();
18512 :
18513 :
18514 413 : void JSSet::Initialize(Handle<JSSet> set, Isolate* isolate) {
18515 413 : Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
18516 413 : set->set_table(*table);
18517 413 : }
18518 :
18519 :
18520 33 : void JSSet::Clear(Handle<JSSet> set) {
18521 : Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()));
18522 33 : table = OrderedHashSet::Clear(table);
18523 33 : set->set_table(*table);
18524 33 : }
18525 :
18526 :
18527 13 : void JSMap::Initialize(Handle<JSMap> map, Isolate* isolate) {
18528 13 : Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
18529 13 : map->set_table(*table);
18530 13 : }
18531 :
18532 :
18533 203 : void JSMap::Clear(Handle<JSMap> map) {
18534 : Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()));
18535 203 : table = OrderedHashMap::Clear(table);
18536 203 : map->set_table(*table);
18537 203 : }
18538 :
18539 :
18540 83169 : void JSWeakCollection::Initialize(Handle<JSWeakCollection> weak_collection,
18541 : Isolate* isolate) {
18542 83169 : Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0);
18543 83169 : weak_collection->set_table(*table);
18544 83169 : }
18545 :
18546 :
18547 2217 : void JSWeakCollection::Set(Handle<JSWeakCollection> weak_collection,
18548 : Handle<Object> key, Handle<Object> value,
18549 : int32_t hash) {
18550 : DCHECK(key->IsJSReceiver() || key->IsSymbol());
18551 : Handle<ObjectHashTable> table(
18552 : ObjectHashTable::cast(weak_collection->table()));
18553 : DCHECK(table->IsKey(table->GetIsolate(), *key));
18554 : Handle<ObjectHashTable> new_table =
18555 2217 : ObjectHashTable::Put(table, key, value, hash);
18556 2217 : weak_collection->set_table(*new_table);
18557 2217 : if (*table != *new_table) {
18558 : // Zap the old table since we didn't record slots for its elements.
18559 173 : table->FillWithHoles(0, table->length());
18560 : }
18561 2217 : }
18562 :
18563 :
18564 77 : bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection,
18565 : Handle<Object> key, int32_t hash) {
18566 : DCHECK(key->IsJSReceiver() || key->IsSymbol());
18567 : Handle<ObjectHashTable> table(
18568 : ObjectHashTable::cast(weak_collection->table()));
18569 : DCHECK(table->IsKey(table->GetIsolate(), *key));
18570 77 : bool was_present = false;
18571 : Handle<ObjectHashTable> new_table =
18572 77 : ObjectHashTable::Remove(table, key, &was_present, hash);
18573 77 : weak_collection->set_table(*new_table);
18574 77 : if (*table != *new_table) {
18575 : // Zap the old table since we didn't record slots for its elements.
18576 0 : table->FillWithHoles(0, table->length());
18577 : }
18578 77 : return was_present;
18579 : }
18580 :
18581 30 : Handle<JSArray> JSWeakCollection::GetEntries(Handle<JSWeakCollection> holder,
18582 : int max_entries) {
18583 : Isolate* isolate = holder->GetIsolate();
18584 : Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
18585 30 : if (max_entries == 0 || max_entries > table->NumberOfElements()) {
18586 : max_entries = table->NumberOfElements();
18587 : }
18588 30 : int values_per_entry = holder->IsJSWeakMap() ? 2 : 1;
18589 : Handle<FixedArray> entries =
18590 30 : isolate->factory()->NewFixedArray(max_entries * values_per_entry);
18591 : // Recompute max_values because GC could have removed elements from the table.
18592 30 : if (max_entries > table->NumberOfElements()) {
18593 : max_entries = table->NumberOfElements();
18594 : }
18595 :
18596 : {
18597 : DisallowHeapAllocation no_gc;
18598 : int count = 0;
18599 180 : for (int i = 0;
18600 150 : count / values_per_entry < max_entries && i < table->Capacity(); i++) {
18601 : Object* key;
18602 60 : if (table->ToKey(isolate, i, &key)) {
18603 40 : entries->set(count++, key);
18604 20 : if (values_per_entry > 1) {
18605 20 : Object* value = table->Lookup(handle(key, isolate));
18606 20 : entries->set(count++, value);
18607 : }
18608 : }
18609 : }
18610 : DCHECK_EQ(max_entries * values_per_entry, count);
18611 : }
18612 30 : return isolate->factory()->NewJSArrayWithElements(entries);
18613 : }
18614 :
18615 : // static
18616 156515 : MaybeHandle<JSDate> JSDate::New(Handle<JSFunction> constructor,
18617 : Handle<JSReceiver> new_target, double tv) {
18618 : Isolate* const isolate = constructor->GetIsolate();
18619 : Handle<JSObject> result;
18620 313030 : ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
18621 : JSObject::New(constructor, new_target), JSDate);
18622 156515 : if (-DateCache::kMaxTimeInMs <= tv && tv <= DateCache::kMaxTimeInMs) {
18623 156002 : tv = DoubleToInteger(tv) + 0.0;
18624 : } else {
18625 : tv = std::numeric_limits<double>::quiet_NaN();
18626 : }
18627 156515 : Handle<Object> value = isolate->factory()->NewNumber(tv);
18628 313030 : Handle<JSDate>::cast(result)->SetValue(*value, std::isnan(tv));
18629 156515 : return Handle<JSDate>::cast(result);
18630 : }
18631 :
18632 :
18633 : // static
18634 159235 : double JSDate::CurrentTimeValue(Isolate* isolate) {
18635 159235 : if (FLAG_log_internal_timer_events) LOG(isolate, CurrentTimeEvent());
18636 :
18637 : // According to ECMA-262, section 15.9.1, page 117, the precision of
18638 : // the number in a Date object representing a particular instant in
18639 : // time is milliseconds. Therefore, we floor the result of getting
18640 : // the OS time.
18641 318470 : return Floor(V8::GetCurrentPlatform()->CurrentClockTimeMillis());
18642 : }
18643 :
18644 :
18645 : // static
18646 11057 : Object* JSDate::GetField(Object* object, Smi* index) {
18647 : return JSDate::cast(object)->DoGetField(
18648 11057 : static_cast<FieldIndex>(index->value()));
18649 : }
18650 :
18651 :
18652 11057 : Object* JSDate::DoGetField(FieldIndex index) {
18653 : DCHECK_NE(index, kDateValue);
18654 :
18655 16490 : DateCache* date_cache = GetIsolate()->date_cache();
18656 :
18657 11057 : if (index < kFirstUncachedField) {
18658 : Object* stamp = cache_stamp();
18659 10866 : if (stamp != date_cache->stamp() && stamp->IsSmi()) {
18660 : // Since the stamp is not NaN, the value is also not NaN.
18661 : int64_t local_time_ms =
18662 378 : date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
18663 378 : SetCachedFields(local_time_ms, date_cache);
18664 : }
18665 5433 : switch (index) {
18666 895 : case kYear: return year();
18667 245 : case kMonth: return month();
18668 73 : case kDay: return day();
18669 0 : case kWeekday: return weekday();
18670 3142 : case kHour: return hour();
18671 852 : case kMinute: return min();
18672 226 : case kSecond: return sec();
18673 0 : default: UNREACHABLE();
18674 : }
18675 : }
18676 :
18677 5624 : if (index >= kFirstUTCField) {
18678 5460 : return GetUTCField(index, value()->Number(), date_cache);
18679 : }
18680 :
18681 : double time = value()->Number();
18682 164 : if (std::isnan(time)) return GetIsolate()->heap()->nan_value();
18683 :
18684 109 : int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
18685 : int days = DateCache::DaysFromTime(local_time_ms);
18686 :
18687 109 : if (index == kDays) return Smi::FromInt(days);
18688 :
18689 : int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
18690 218 : if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
18691 : DCHECK_EQ(index, kTimeInDay);
18692 0 : return Smi::FromInt(time_in_day_ms);
18693 : }
18694 :
18695 :
18696 5460 : Object* JSDate::GetUTCField(FieldIndex index,
18697 : double value,
18698 : DateCache* date_cache) {
18699 : DCHECK_GE(index, kFirstUTCField);
18700 :
18701 10570 : if (std::isnan(value)) return GetIsolate()->heap()->nan_value();
18702 :
18703 350 : int64_t time_ms = static_cast<int64_t>(value);
18704 :
18705 350 : if (index == kTimezoneOffset) {
18706 19 : return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
18707 : }
18708 :
18709 : int days = DateCache::DaysFromTime(time_ms);
18710 :
18711 340 : if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
18712 :
18713 322 : if (index <= kDayUTC) {
18714 : int year, month, day;
18715 120 : date_cache->YearMonthDayFromDays(days, &year, &month, &day);
18716 157 : if (index == kYearUTC) return Smi::FromInt(year);
18717 119 : if (index == kMonthUTC) return Smi::FromInt(month);
18718 : DCHECK_EQ(index, kDayUTC);
18719 94 : return Smi::FromInt(day);
18720 : }
18721 :
18722 : int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
18723 202 : switch (index) {
18724 188 : case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
18725 90 : case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
18726 72 : case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
18727 54 : case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
18728 0 : case kDaysUTC: return Smi::FromInt(days);
18729 0 : case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
18730 0 : default: UNREACHABLE();
18731 : }
18732 :
18733 : UNREACHABLE();
18734 : }
18735 :
18736 :
18737 : // static
18738 11201 : Handle<Object> JSDate::SetValue(Handle<JSDate> date, double v) {
18739 : Isolate* const isolate = date->GetIsolate();
18740 11201 : Handle<Object> value = isolate->factory()->NewNumber(v);
18741 : bool value_is_nan = std::isnan(v);
18742 22402 : date->SetValue(*value, value_is_nan);
18743 11201 : return value;
18744 : }
18745 :
18746 :
18747 167716 : void JSDate::SetValue(Object* value, bool is_value_nan) {
18748 167716 : set_value(value);
18749 167716 : if (is_value_nan) {
18750 11206 : HeapNumber* nan = GetIsolate()->heap()->nan_value();
18751 11206 : set_cache_stamp(nan, SKIP_WRITE_BARRIER);
18752 11206 : set_year(nan, SKIP_WRITE_BARRIER);
18753 11206 : set_month(nan, SKIP_WRITE_BARRIER);
18754 11206 : set_day(nan, SKIP_WRITE_BARRIER);
18755 11206 : set_hour(nan, SKIP_WRITE_BARRIER);
18756 11206 : set_min(nan, SKIP_WRITE_BARRIER);
18757 11206 : set_sec(nan, SKIP_WRITE_BARRIER);
18758 11206 : set_weekday(nan, SKIP_WRITE_BARRIER);
18759 : } else {
18760 156510 : set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
18761 : }
18762 167716 : }
18763 :
18764 :
18765 756 : void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) {
18766 : int days = DateCache::DaysFromTime(local_time_ms);
18767 : int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
18768 : int year, month, day;
18769 378 : date_cache->YearMonthDayFromDays(days, &year, &month, &day);
18770 : int weekday = date_cache->Weekday(days);
18771 378 : int hour = time_in_day_ms / (60 * 60 * 1000);
18772 378 : int min = (time_in_day_ms / (60 * 1000)) % 60;
18773 378 : int sec = (time_in_day_ms / 1000) % 60;
18774 378 : set_cache_stamp(date_cache->stamp());
18775 756 : set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
18776 756 : set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
18777 756 : set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
18778 378 : set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
18779 378 : set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
18780 378 : set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
18781 378 : set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
18782 378 : }
18783 :
18784 : namespace {
18785 :
18786 : Script* ScriptFromJSValue(Object* in) {
18787 : DCHECK(in->IsJSValue());
18788 : JSValue* jsvalue = JSValue::cast(in);
18789 : DCHECK(jsvalue->value()->IsScript());
18790 : return Script::cast(jsvalue->value());
18791 : }
18792 :
18793 : } // namespace
18794 :
18795 10681 : int JSMessageObject::GetLineNumber() const {
18796 10681 : if (start_position() == -1) return Message::kNoLineNumberInfo;
18797 :
18798 10606 : Handle<Script> the_script = handle(ScriptFromJSValue(script()));
18799 :
18800 : Script::PositionInfo info;
18801 : const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
18802 10606 : if (!Script::GetPositionInfo(the_script, start_position(), &info,
18803 10606 : offset_flag)) {
18804 : return Message::kNoLineNumberInfo;
18805 : }
18806 :
18807 10606 : return info.line + 1;
18808 : }
18809 :
18810 16928 : int JSMessageObject::GetColumnNumber() const {
18811 16928 : if (start_position() == -1) return -1;
18812 :
18813 16823 : Handle<Script> the_script = handle(ScriptFromJSValue(script()));
18814 :
18815 : Script::PositionInfo info;
18816 : const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
18817 16823 : if (!Script::GetPositionInfo(the_script, start_position(), &info,
18818 16823 : offset_flag)) {
18819 : return -1;
18820 : }
18821 :
18822 16823 : return info.column; // Note: No '+1' in contrast to GetLineNumber.
18823 : }
18824 :
18825 7666 : Handle<String> JSMessageObject::GetSourceLine() const {
18826 : Handle<Script> the_script = handle(ScriptFromJSValue(script()));
18827 :
18828 : Isolate* isolate = the_script->GetIsolate();
18829 7666 : if (the_script->type() == Script::TYPE_WASM) {
18830 : return isolate->factory()->empty_string();
18831 : }
18832 :
18833 : Script::PositionInfo info;
18834 : const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
18835 7666 : if (!Script::GetPositionInfo(the_script, start_position(), &info,
18836 7666 : offset_flag)) {
18837 : return isolate->factory()->empty_string();
18838 : }
18839 :
18840 7666 : Handle<String> src = handle(String::cast(the_script->source()), isolate);
18841 7666 : return isolate->factory()->NewSubString(src, info.line_start, info.line_end);
18842 : }
18843 :
18844 2334 : void JSArrayBuffer::Neuter() {
18845 2334 : CHECK(is_neuterable());
18846 2334 : CHECK(is_external());
18847 : set_backing_store(nullptr);
18848 2334 : set_byte_length(Smi::kZero);
18849 : set_allocation_base(nullptr);
18850 : set_allocation_length(0);
18851 : set_was_neutered(true);
18852 : // Invalidate the neutering protector.
18853 : Isolate* const isolate = GetIsolate();
18854 2334 : if (isolate->IsArrayBufferNeuteringIntact()) {
18855 236 : isolate->InvalidateArrayBufferNeuteringProtector();
18856 : }
18857 2334 : }
18858 :
18859 241350 : void JSArrayBuffer::FreeBackingStore() {
18860 241350 : if (allocation_base() == nullptr) {
18861 241385 : return;
18862 : }
18863 : using AllocationMode = ArrayBuffer::Allocator::AllocationMode;
18864 : const size_t length = allocation_length();
18865 : const AllocationMode mode = allocation_mode();
18866 241344 : GetIsolate()->array_buffer_allocator()->Free(allocation_base(), length, mode);
18867 :
18868 : // Zero out the backing store and allocation base to avoid dangling
18869 : // pointers.
18870 : set_backing_store(nullptr);
18871 : // TODO(eholk): set_byte_length(0) once we aren't using Smis for the
18872 : // byte_length. We can't do it now because the GC needs to call
18873 : // FreeBackingStore while it is collecting.
18874 : set_allocation_base(nullptr);
18875 : set_allocation_length(0);
18876 : }
18877 :
18878 784 : void JSArrayBuffer::Setup(Handle<JSArrayBuffer> array_buffer, Isolate* isolate,
18879 : bool is_external, void* data, size_t allocated_length,
18880 : SharedFlag shared) {
18881 : return Setup(array_buffer, isolate, is_external, data, allocated_length, data,
18882 229257 : allocated_length, shared);
18883 : }
18884 :
18885 248497 : void JSArrayBuffer::Setup(Handle<JSArrayBuffer> array_buffer, Isolate* isolate,
18886 : bool is_external, void* allocation_base,
18887 : size_t allocation_length, void* data,
18888 : size_t byte_length, SharedFlag shared) {
18889 : DCHECK_EQ(array_buffer->GetEmbedderFieldCount(),
18890 : v8::ArrayBuffer::kEmbedderFieldCount);
18891 745491 : for (int i = 0; i < v8::ArrayBuffer::kEmbedderFieldCount; i++) {
18892 496994 : array_buffer->SetEmbedderField(i, Smi::kZero);
18893 : }
18894 : array_buffer->set_bit_field(0);
18895 : array_buffer->set_is_external(is_external);
18896 248497 : array_buffer->set_is_neuterable(shared == SharedFlag::kNotShared);
18897 248497 : array_buffer->set_is_shared(shared == SharedFlag::kShared);
18898 :
18899 : Handle<Object> heap_byte_length =
18900 248497 : isolate->factory()->NewNumberFromSize(byte_length);
18901 248570 : CHECK(heap_byte_length->IsSmi() || heap_byte_length->IsHeapNumber());
18902 248497 : array_buffer->set_byte_length(*heap_byte_length);
18903 : // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
18904 : // are currently being constructed in the |ArrayBufferTracker|. The
18905 : // registration method below handles the case of registering a buffer that has
18906 : // already been promoted.
18907 : array_buffer->set_backing_store(data);
18908 :
18909 : array_buffer->set_allocation_base(data);
18910 : array_buffer->set_allocation_length(allocation_length);
18911 :
18912 248497 : if (data && !is_external) {
18913 231341 : isolate->heap()->RegisterNewArrayBuffer(*array_buffer);
18914 : }
18915 248497 : }
18916 :
18917 : namespace {
18918 :
18919 : inline int ConvertToMb(size_t size) {
18920 6294 : return static_cast<int>(size / static_cast<size_t>(MB));
18921 : }
18922 :
18923 : } // namespace
18924 :
18925 228474 : bool JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer> array_buffer,
18926 445858 : Isolate* isolate,
18927 : size_t allocated_length,
18928 : bool initialize, SharedFlag shared) {
18929 : void* data;
18930 228474 : CHECK_NOT_NULL(isolate->array_buffer_allocator());
18931 228474 : if (allocated_length != 0) {
18932 217384 : if (allocated_length >= MB)
18933 : isolate->counters()->array_buffer_big_allocations()->AddSample(
18934 296 : ConvertToMb(allocated_length));
18935 217384 : if (shared == SharedFlag::kShared)
18936 : isolate->counters()->shared_array_allocations()->AddSample(
18937 5997 : ConvertToMb(allocated_length));
18938 217384 : if (initialize) {
18939 216383 : data = isolate->array_buffer_allocator()->Allocate(allocated_length);
18940 : } else {
18941 : data = isolate->array_buffer_allocator()->AllocateUninitialized(
18942 1001 : allocated_length);
18943 : }
18944 217384 : if (data == nullptr) {
18945 : isolate->counters()->array_buffer_new_size_failures()->AddSample(
18946 1 : ConvertToMb(allocated_length));
18947 1 : return false;
18948 : }
18949 : } else {
18950 : data = nullptr;
18951 : }
18952 :
18953 : const bool is_external = false;
18954 : JSArrayBuffer::Setup(array_buffer, isolate, is_external, data,
18955 : allocated_length, shared);
18956 228473 : return true;
18957 : }
18958 :
18959 :
18960 12367 : Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
18961 : Handle<JSTypedArray> typed_array) {
18962 :
18963 : Handle<Map> map(typed_array->map());
18964 12367 : Isolate* isolate = typed_array->GetIsolate();
18965 :
18966 : DCHECK(IsFixedTypedArrayElementsKind(map->elements_kind()));
18967 :
18968 : Handle<FixedTypedArrayBase> fixed_typed_array(
18969 : FixedTypedArrayBase::cast(typed_array->elements()));
18970 :
18971 : Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(typed_array->buffer()),
18972 : isolate);
18973 : void* backing_store =
18974 : isolate->array_buffer_allocator()->AllocateUninitialized(
18975 24734 : fixed_typed_array->DataSize());
18976 : buffer->set_is_external(false);
18977 : DCHECK(buffer->byte_length()->IsSmi() ||
18978 : buffer->byte_length()->IsHeapNumber());
18979 : DCHECK(NumberToInt32(buffer->byte_length()) == fixed_typed_array->DataSize());
18980 : // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
18981 : // are currently being constructed in the |ArrayBufferTracker|. The
18982 : // registration method below handles the case of registering a buffer that has
18983 : // already been promoted.
18984 : buffer->set_backing_store(backing_store);
18985 : buffer->set_allocation_base(backing_store);
18986 12367 : buffer->set_allocation_length(NumberToSize(buffer->byte_length()));
18987 : // RegisterNewArrayBuffer expects a valid length for adjusting counters.
18988 12367 : isolate->heap()->RegisterNewArrayBuffer(*buffer);
18989 : memcpy(buffer->backing_store(),
18990 : fixed_typed_array->DataPtr(),
18991 12367 : fixed_typed_array->DataSize());
18992 : Handle<FixedTypedArrayBase> new_elements =
18993 : isolate->factory()->NewFixedTypedArrayWithExternalPointer(
18994 : fixed_typed_array->length(), typed_array->type(),
18995 24734 : static_cast<uint8_t*>(buffer->backing_store()));
18996 :
18997 12367 : typed_array->set_elements(*new_elements);
18998 :
18999 12367 : return buffer;
19000 : }
19001 :
19002 :
19003 19700823 : Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
19004 : Handle<JSArrayBuffer> array_buffer(JSArrayBuffer::cast(buffer()),
19005 : GetIsolate());
19006 39401607 : if (array_buffer->was_neutered() ||
19007 : array_buffer->backing_store() != nullptr) {
19008 19688457 : return array_buffer;
19009 : }
19010 : Handle<JSTypedArray> self(this);
19011 12367 : return MaterializeArrayBuffer(self);
19012 : }
19013 :
19014 19912 : Handle<PropertyCell> PropertyCell::InvalidateEntry(
19015 : Handle<GlobalDictionary> dictionary, int entry) {
19016 : Isolate* isolate = dictionary->GetIsolate();
19017 : // Swap with a copy.
19018 : Handle<PropertyCell> cell(dictionary->CellAt(entry));
19019 : Handle<Name> name(cell->name(), isolate);
19020 19912 : Handle<PropertyCell> new_cell = isolate->factory()->NewPropertyCell(name);
19021 19912 : new_cell->set_value(cell->value());
19022 : dictionary->ValueAtPut(entry, *new_cell);
19023 : bool is_the_hole = cell->value()->IsTheHole(isolate);
19024 : // Cell is officially mutable henceforth.
19025 : PropertyDetails details = cell->property_details();
19026 : details = details.set_cell_type(is_the_hole ? PropertyCellType::kUninitialized
19027 19912 : : PropertyCellType::kMutable);
19028 : new_cell->set_property_details(details);
19029 : // Old cell is ready for invalidation.
19030 19912 : if (is_the_hole) {
19031 17432 : cell->set_value(isolate->heap()->undefined_value());
19032 : } else {
19033 22392 : cell->set_value(isolate->heap()->the_hole_value());
19034 : }
19035 : details = details.set_cell_type(PropertyCellType::kInvalidated);
19036 : cell->set_property_details(details);
19037 : cell->dependent_code()->DeoptimizeDependentCodeGroup(
19038 19912 : isolate, DependentCode::kPropertyCellChangedGroup);
19039 19912 : return new_cell;
19040 : }
19041 :
19042 :
19043 0 : PropertyCellConstantType PropertyCell::GetConstantType() {
19044 0 : if (value()->IsSmi()) return PropertyCellConstantType::kSmi;
19045 0 : return PropertyCellConstantType::kStableMap;
19046 : }
19047 :
19048 :
19049 860231 : static bool RemainsConstantType(Handle<PropertyCell> cell,
19050 : Handle<Object> value) {
19051 : // TODO(dcarney): double->smi and smi->double transition from kConstant
19052 1654047 : if (cell->value()->IsSmi() && value->IsSmi()) {
19053 : return true;
19054 134536 : } else if (cell->value()->IsHeapObject() && value->IsHeapObject()) {
19055 : return HeapObject::cast(cell->value())->map() ==
19056 122095 : HeapObject::cast(*value)->map() &&
19057 65661 : HeapObject::cast(*value)->map()->is_stable();
19058 : }
19059 : return false;
19060 : }
19061 :
19062 :
19063 9471597 : PropertyCellType PropertyCell::UpdatedType(Handle<PropertyCell> cell,
19064 : Handle<Object> value,
19065 : PropertyDetails details) {
19066 : PropertyCellType type = details.cell_type();
19067 : Isolate* isolate = cell->GetIsolate();
19068 : DCHECK(!value->IsTheHole(isolate));
19069 9471597 : if (cell->value()->IsTheHole(isolate)) {
19070 7173698 : switch (type) {
19071 : // Only allow a cell to transition once into constant state.
19072 : case PropertyCellType::kUninitialized:
19073 7173698 : if (value->IsUndefined(isolate)) return PropertyCellType::kUndefined;
19074 5752462 : return PropertyCellType::kConstant;
19075 : case PropertyCellType::kInvalidated:
19076 : return PropertyCellType::kMutable;
19077 : default:
19078 0 : UNREACHABLE();
19079 : }
19080 : }
19081 2297899 : switch (type) {
19082 : case PropertyCellType::kUndefined:
19083 : return PropertyCellType::kConstant;
19084 : case PropertyCellType::kConstant:
19085 62907 : if (*value == cell->value()) return PropertyCellType::kConstant;
19086 : // Fall through.
19087 : case PropertyCellType::kConstantType:
19088 860231 : if (RemainsConstantType(cell, value)) {
19089 : return PropertyCellType::kConstantType;
19090 : }
19091 : // Fall through.
19092 : case PropertyCellType::kMutable:
19093 : return PropertyCellType::kMutable;
19094 : }
19095 0 : UNREACHABLE();
19096 : }
19097 :
19098 2305281 : Handle<PropertyCell> PropertyCell::PrepareForValue(
19099 : Handle<GlobalDictionary> dictionary, int entry, Handle<Object> value,
19100 : PropertyDetails details) {
19101 : Isolate* isolate = dictionary->GetIsolate();
19102 : DCHECK(!value->IsTheHole(isolate));
19103 : Handle<PropertyCell> cell(dictionary->CellAt(entry));
19104 : const PropertyDetails original_details = cell->property_details();
19105 : // Data accesses could be cached in ics or optimized code.
19106 : bool invalidate =
19107 6907569 : (original_details.kind() == kData && details.kind() == kAccessor) ||
19108 2297633 : (!original_details.IsReadOnly() && details.IsReadOnly());
19109 : int index;
19110 : PropertyCellType old_type = original_details.cell_type();
19111 : // Preserve the enumeration index unless the property was deleted or never
19112 : // initialized.
19113 2305281 : if (cell->value()->IsTheHole(isolate)) {
19114 : index = dictionary->NextEnumerationIndex();
19115 7382 : dictionary->SetNextEnumerationIndex(index + 1);
19116 : } else {
19117 : index = original_details.dictionary_index();
19118 : }
19119 : DCHECK_LT(0, index);
19120 : details = details.set_index(index);
19121 :
19122 2305281 : PropertyCellType new_type = UpdatedType(cell, value, original_details);
19123 2305281 : if (invalidate) cell = PropertyCell::InvalidateEntry(dictionary, entry);
19124 :
19125 : // Install new property details.
19126 : details = details.set_cell_type(new_type);
19127 : cell->set_property_details(details);
19128 :
19129 : // Deopt when transitioning from a constant type.
19130 3258323 : if (!invalidate && (old_type != new_type ||
19131 : original_details.IsReadOnly() != details.IsReadOnly())) {
19132 : cell->dependent_code()->DeoptimizeDependentCodeGroup(
19133 1344535 : isolate, DependentCode::kPropertyCellChangedGroup);
19134 : }
19135 2305281 : return cell;
19136 : }
19137 :
19138 :
19139 : // static
19140 856 : void PropertyCell::SetValueWithInvalidation(Handle<PropertyCell> cell,
19141 : Handle<Object> new_value) {
19142 856 : if (cell->value() != *new_value) {
19143 856 : cell->set_value(*new_value);
19144 : Isolate* isolate = cell->GetIsolate();
19145 : cell->dependent_code()->DeoptimizeDependentCodeGroup(
19146 856 : isolate, DependentCode::kPropertyCellChangedGroup);
19147 : }
19148 856 : }
19149 :
19150 1420 : int JSGeneratorObject::source_position() const {
19151 1420 : CHECK(is_suspended());
19152 : DCHECK(function()->shared()->HasBytecodeArray());
19153 :
19154 : int code_offset = Smi::ToInt(input_or_debug_pos());
19155 :
19156 : // The stored bytecode offset is relative to a different base than what
19157 : // is used in the source position table, hence the subtraction.
19158 1420 : code_offset -= BytecodeArray::kHeaderSize - kHeapObjectTag;
19159 : AbstractCode* code =
19160 : AbstractCode::cast(function()->shared()->bytecode_array());
19161 1420 : return code->SourcePosition(code_offset);
19162 : }
19163 :
19164 : // static
19165 6622 : AccessCheckInfo* AccessCheckInfo::Get(Isolate* isolate,
19166 : Handle<JSObject> receiver) {
19167 : DisallowHeapAllocation no_gc;
19168 : DCHECK(receiver->map()->is_access_check_needed());
19169 6622 : Object* maybe_constructor = receiver->map()->GetConstructor();
19170 6622 : if (maybe_constructor->IsFunctionTemplateInfo()) {
19171 : Object* data_obj =
19172 : FunctionTemplateInfo::cast(maybe_constructor)->access_check_info();
19173 174 : if (data_obj->IsUndefined(isolate)) return nullptr;
19174 174 : return AccessCheckInfo::cast(data_obj);
19175 : }
19176 : // Might happen for a detached context.
19177 6448 : if (!maybe_constructor->IsJSFunction()) return nullptr;
19178 : JSFunction* constructor = JSFunction::cast(maybe_constructor);
19179 : // Might happen for the debug context.
19180 6421 : if (!constructor->shared()->IsApiFunction()) return nullptr;
19181 :
19182 : Object* data_obj =
19183 : constructor->shared()->get_api_func_data()->access_check_info();
19184 4251 : if (data_obj->IsUndefined(isolate)) return nullptr;
19185 :
19186 3694 : return AccessCheckInfo::cast(data_obj);
19187 : }
19188 :
19189 4247 : bool JSReceiver::HasProxyInPrototype(Isolate* isolate) {
19190 17548 : for (PrototypeIterator iter(isolate, this, kStartAtReceiver,
19191 : PrototypeIterator::END_AT_NULL);
19192 13301 : !iter.IsAtEnd(); iter.AdvanceIgnoringProxies()) {
19193 26658 : if (iter.GetCurrent<Object>()->IsJSProxy()) return true;
19194 : }
19195 4219 : return false;
19196 : }
19197 :
19198 16583 : bool JSReceiver::HasComplexElements() {
19199 16583 : if (IsJSProxy()) return true;
19200 : JSObject* this_object = JSObject::cast(this);
19201 16583 : if (this_object->HasIndexedInterceptor()) {
19202 : return true;
19203 : }
19204 16583 : if (!this_object->HasDictionaryElements()) return false;
19205 6707 : return this_object->element_dictionary()->HasComplexElements();
19206 : }
19207 :
19208 6267008 : MaybeHandle<Name> FunctionTemplateInfo::TryGetCachedPropertyName(
19209 : Isolate* isolate, Handle<Object> getter) {
19210 6267008 : if (getter->IsFunctionTemplateInfo()) {
19211 : Handle<FunctionTemplateInfo> fti =
19212 : Handle<FunctionTemplateInfo>::cast(getter);
19213 : // Check if the accessor uses a cached property.
19214 1085 : if (!fti->cached_property_name()->IsTheHole(isolate)) {
19215 104 : return handle(Name::cast(fti->cached_property_name()));
19216 : }
19217 : }
19218 6266904 : return MaybeHandle<Name>();
19219 : }
19220 :
19221 : // static
19222 683 : ElementsKind JSArrayIterator::ElementsKindForInstanceType(InstanceType type) {
19223 : DCHECK_GE(type, FIRST_ARRAY_ITERATOR_TYPE);
19224 : DCHECK_LE(type, LAST_ARRAY_ITERATOR_TYPE);
19225 :
19226 683 : if (type <= LAST_ARRAY_KEY_ITERATOR_TYPE) {
19227 : // Should be ignored for key iterators.
19228 : return PACKED_ELEMENTS;
19229 : } else {
19230 : ElementsKind kind;
19231 675 : if (type < FIRST_ARRAY_VALUE_ITERATOR_TYPE) {
19232 : // Convert `type` to a value iterator from an entries iterator
19233 : type = static_cast<InstanceType>(type +
19234 : (FIRST_ARRAY_VALUE_ITERATOR_TYPE -
19235 14 : FIRST_ARRAY_KEY_VALUE_ITERATOR_TYPE));
19236 : DCHECK_GE(type, FIRST_ARRAY_VALUE_ITERATOR_TYPE);
19237 : DCHECK_LE(type, LAST_ARRAY_ITERATOR_TYPE);
19238 : }
19239 :
19240 675 : if (type <= JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE) {
19241 : kind =
19242 50 : static_cast<ElementsKind>(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND +
19243 50 : (type - FIRST_ARRAY_VALUE_ITERATOR_TYPE));
19244 : DCHECK_LE(kind, LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
19245 625 : } else if (type < JS_GENERIC_ARRAY_VALUE_ITERATOR_TYPE) {
19246 : kind = static_cast<ElementsKind>(
19247 625 : FIRST_FAST_ELEMENTS_KIND +
19248 625 : (type - JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE));
19249 : DCHECK_LE(kind, LAST_FAST_ELEMENTS_KIND);
19250 : } else {
19251 : // For any slow element cases, the actual elements kind is not known.
19252 : // Simply
19253 : // return a slow elements kind in this case. Users of this function must
19254 : // not
19255 : // depend on this.
19256 : return DICTIONARY_ELEMENTS;
19257 : }
19258 : DCHECK_LE(kind, LAST_ELEMENTS_KIND);
19259 675 : return kind;
19260 : }
19261 : }
19262 : } // namespace internal
19263 : } // namespace v8
|