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 <unordered_map>
12 : #include <unordered_set>
13 :
14 : #include "src/objects-inl.h"
15 :
16 : #include "src/accessors.h"
17 : #include "src/allocation-site-scopes.h"
18 : #include "src/api-arguments-inl.h"
19 : #include "src/api-natives.h"
20 : #include "src/api.h"
21 : #include "src/arguments.h"
22 : #include "src/base/bits.h"
23 : #include "src/base/utils/random-number-generator.h"
24 : #include "src/bootstrapper.h"
25 : #include "src/builtins/builtins.h"
26 : #include "src/code-stubs.h"
27 : #include "src/codegen.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/full-codegen/full-codegen.h"
43 : #include "src/globals.h"
44 : #include "src/ic/ic.h"
45 : #include "src/identity-map.h"
46 : #include "src/interpreter/bytecode-array-iterator.h"
47 : #include "src/interpreter/bytecode-decoder.h"
48 : #include "src/interpreter/interpreter.h"
49 : #include "src/isolate-inl.h"
50 : #include "src/keys.h"
51 : #include "src/list.h"
52 : #include "src/log.h"
53 : #include "src/lookup.h"
54 : #include "src/macro-assembler.h"
55 : #include "src/map-updater.h"
56 : #include "src/messages.h"
57 : #include "src/objects-body-descriptors-inl.h"
58 : #include "src/objects/code-cache-inl.h"
59 : #include "src/objects/compilation-cache-inl.h"
60 : #include "src/objects/frame-array-inl.h"
61 : #include "src/property-descriptor.h"
62 : #include "src/prototype.h"
63 : #include "src/regexp/jsregexp.h"
64 : #include "src/safepoint-table.h"
65 : #include "src/snapshot/code-serializer.h"
66 : #include "src/source-position-table.h"
67 : #include "src/string-builder.h"
68 : #include "src/string-search.h"
69 : #include "src/string-stream.h"
70 : #include "src/utils.h"
71 : #include "src/wasm/wasm-module.h"
72 : #include "src/wasm/wasm-objects.h"
73 : #include "src/zone/zone.h"
74 :
75 : #ifdef ENABLE_DISASSEMBLER
76 : #include "src/disasm.h"
77 : #include "src/disassembler.h"
78 : #include "src/eh-frame.h"
79 : #endif
80 :
81 : namespace v8 {
82 : namespace internal {
83 :
84 20244 : std::ostream& operator<<(std::ostream& os, InstanceType instance_type) {
85 20244 : switch (instance_type) {
86 : #define WRITE_TYPE(TYPE) \
87 : case TYPE: \
88 : return os << #TYPE;
89 0 : INSTANCE_TYPE_LIST(WRITE_TYPE)
90 : #undef WRITE_TYPE
91 : }
92 0 : UNREACHABLE();
93 : return os << "UNKNOWN"; // Keep the compiler happy.
94 : }
95 :
96 10645108 : Handle<FieldType> Object::OptimalType(Isolate* isolate,
97 : Representation representation) {
98 10645108 : if (representation.IsNone()) return FieldType::None(isolate);
99 10205414 : if (FLAG_track_field_types) {
100 15187492 : if (representation.IsHeapObject() && IsHeapObject()) {
101 : // We can track only JavaScript objects with stable maps.
102 : Handle<Map> map(HeapObject::cast(this)->map(), isolate);
103 8977477 : if (map->is_stable() && map->IsJSReceiverMap()) {
104 1602713 : return FieldType::Class(map, isolate);
105 : }
106 : }
107 : }
108 8602704 : return FieldType::Any(isolate);
109 : }
110 :
111 :
112 8470 : MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
113 : Handle<Object> object,
114 : Handle<Context> native_context) {
115 8470 : if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
116 : Handle<JSFunction> constructor;
117 8470 : if (object->IsSmi()) {
118 623 : constructor = handle(native_context->number_function(), isolate);
119 : } else {
120 : int constructor_function_index =
121 : Handle<HeapObject>::cast(object)->map()->GetConstructorFunctionIndex();
122 7847 : if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
123 1956 : THROW_NEW_ERROR(isolate,
124 : NewTypeError(MessageTemplate::kUndefinedOrNullToObject),
125 : JSReceiver);
126 : }
127 : constructor = handle(
128 : JSFunction::cast(native_context->get(constructor_function_index)),
129 6869 : isolate);
130 : }
131 7492 : Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
132 7492 : Handle<JSValue>::cast(result)->set_value(*object);
133 : return result;
134 : }
135 :
136 : // ES6 section 9.2.1.2, OrdinaryCallBindThis for sloppy callee.
137 : // static
138 51901 : MaybeHandle<JSReceiver> Object::ConvertReceiver(Isolate* isolate,
139 : Handle<Object> object) {
140 51901 : if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
141 1124 : if (*object == isolate->heap()->null_value() ||
142 : object->IsUndefined(isolate)) {
143 313 : return isolate->global_proxy();
144 : }
145 249 : return Object::ToObject(isolate, object);
146 : }
147 :
148 : // static
149 3476001 : MaybeHandle<Object> Object::ConvertToNumber(Isolate* isolate,
150 : Handle<Object> input) {
151 : while (true) {
152 3481935 : if (input->IsNumber()) {
153 : return input;
154 : }
155 3458133 : if (input->IsString()) {
156 91713 : return String::ToNumber(Handle<String>::cast(input));
157 : }
158 3366420 : if (input->IsOddball()) {
159 3354337 : return Oddball::ToNumber(Handle<Oddball>::cast(input));
160 : }
161 12083 : if (input->IsSymbol()) {
162 10966 : THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber),
163 : Object);
164 : }
165 13200 : ASSIGN_RETURN_ON_EXCEPTION(
166 : isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
167 : ToPrimitiveHint::kNumber),
168 : Object);
169 : }
170 : }
171 :
172 : // static
173 29747 : MaybeHandle<Object> Object::ConvertToInteger(Isolate* isolate,
174 : Handle<Object> input) {
175 59494 : ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ConvertToNumber(isolate, input),
176 : Object);
177 29393 : if (input->IsSmi()) return input;
178 27129 : return isolate->factory()->NewNumber(DoubleToInteger(input->Number()));
179 : }
180 :
181 : // static
182 1232 : MaybeHandle<Object> Object::ConvertToInt32(Isolate* isolate,
183 : Handle<Object> input) {
184 2464 : ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ConvertToNumber(isolate, input),
185 : Object);
186 1143 : if (input->IsSmi()) return input;
187 401 : return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number()));
188 : }
189 :
190 : // static
191 533104 : MaybeHandle<Object> Object::ConvertToUint32(Isolate* isolate,
192 : Handle<Object> input) {
193 1066208 : ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ConvertToNumber(isolate, input),
194 : Object);
195 533075 : if (input->IsSmi()) return handle(Smi::cast(*input)->ToUint32Smi(), isolate);
196 363 : return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number()));
197 : }
198 :
199 : // static
200 4574649 : MaybeHandle<Name> Object::ConvertToName(Isolate* isolate,
201 : Handle<Object> input) {
202 9149298 : ASSIGN_RETURN_ON_EXCEPTION(
203 : isolate, input, Object::ToPrimitive(input, ToPrimitiveHint::kString),
204 : Name);
205 4574394 : if (input->IsName()) return Handle<Name>::cast(input);
206 136914 : return ToString(isolate, input);
207 : }
208 :
209 : // ES6 7.1.14
210 : // static
211 744 : MaybeHandle<Object> Object::ConvertToPropertyKey(Isolate* isolate,
212 : Handle<Object> value) {
213 : // 1. Let key be ToPrimitive(argument, hint String).
214 : MaybeHandle<Object> maybe_key =
215 744 : Object::ToPrimitive(value, ToPrimitiveHint::kString);
216 : // 2. ReturnIfAbrupt(key).
217 : Handle<Object> key;
218 744 : if (!maybe_key.ToHandle(&key)) return key;
219 : // 3. If Type(key) is Symbol, then return key.
220 744 : if (key->IsSymbol()) return key;
221 : // 4. Return ToString(key).
222 : // Extending spec'ed behavior, we'd be happy to return an element index.
223 744 : if (key->IsSmi()) return key;
224 744 : if (key->IsHeapNumber()) {
225 : uint32_t uint_value;
226 43 : if (value->ToArrayLength(&uint_value) &&
227 14 : uint_value <= static_cast<uint32_t>(Smi::kMaxValue)) {
228 0 : return handle(Smi::FromInt(static_cast<int>(uint_value)), isolate);
229 : }
230 : }
231 1488 : return Object::ToString(isolate, key);
232 : }
233 :
234 : // static
235 8540846 : MaybeHandle<String> Object::ConvertToString(Isolate* isolate,
236 : Handle<Object> input) {
237 : while (true) {
238 8822312 : if (input->IsOddball()) {
239 : return handle(Handle<Oddball>::cast(input)->to_string(), isolate);
240 : }
241 6260573 : if (input->IsNumber()) {
242 424498 : return isolate->factory()->NumberToString(input);
243 : }
244 5836075 : if (input->IsSymbol()) {
245 6428 : THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToString),
246 : String);
247 : }
248 11665722 : ASSIGN_RETURN_ON_EXCEPTION(
249 : isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
250 : ToPrimitiveHint::kString),
251 : String);
252 : // The previous isString() check happened in Object::ToString and thus we
253 : // put it at the end of the loop in this helper.
254 5815737 : if (input->IsString()) {
255 : return Handle<String>::cast(input);
256 : }
257 : }
258 : }
259 :
260 : namespace {
261 :
262 42082 : bool IsErrorObject(Isolate* isolate, Handle<Object> object) {
263 42082 : if (!object->IsJSReceiver()) return false;
264 : Handle<Symbol> symbol = isolate->factory()->stack_trace_symbol();
265 42082 : return JSReceiver::HasOwnProperty(Handle<JSReceiver>::cast(object), symbol)
266 84164 : .FromMaybe(false);
267 : }
268 :
269 37546 : Handle<String> AsStringOrEmpty(Isolate* isolate, Handle<Object> object) {
270 : return object->IsString() ? Handle<String>::cast(object)
271 75092 : : isolate->factory()->empty_string();
272 : }
273 :
274 5095 : Handle<String> NoSideEffectsErrorToString(Isolate* isolate,
275 : Handle<Object> input) {
276 5095 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input);
277 :
278 : Handle<Name> name_key = isolate->factory()->name_string();
279 5095 : Handle<Object> name = JSReceiver::GetDataProperty(receiver, name_key);
280 5095 : Handle<String> name_str = AsStringOrEmpty(isolate, name);
281 :
282 : Handle<Name> msg_key = isolate->factory()->message_string();
283 5095 : Handle<Object> msg = JSReceiver::GetDataProperty(receiver, msg_key);
284 5095 : Handle<String> msg_str = AsStringOrEmpty(isolate, msg);
285 :
286 5095 : if (name_str->length() == 0) return msg_str;
287 5065 : if (msg_str->length() == 0) return name_str;
288 :
289 4924 : IncrementalStringBuilder builder(isolate);
290 4924 : builder.AppendString(name_str);
291 : builder.AppendCString(": ");
292 4924 : builder.AppendString(msg_str);
293 :
294 9848 : return builder.Finish().ToHandleChecked();
295 : }
296 :
297 : } // namespace
298 :
299 : // static
300 3697596 : Handle<String> Object::NoSideEffectsToString(Isolate* isolate,
301 : Handle<Object> input) {
302 3697596 : DisallowJavascriptExecution no_js(isolate);
303 :
304 8919795 : if (input->IsString() || input->IsNumber() || input->IsOddball()) {
305 7306348 : return Object::ToString(isolate, input).ToHandleChecked();
306 44422 : } else if (input->IsFunction()) {
307 : // -- F u n c t i o n
308 : Handle<String> fun_str;
309 858 : if (input->IsJSBoundFunction()) {
310 0 : fun_str = JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(input));
311 : } else {
312 : DCHECK(input->IsJSFunction());
313 858 : fun_str = JSFunction::ToString(Handle<JSFunction>::cast(input));
314 : }
315 :
316 858 : if (fun_str->length() > 128) {
317 15 : IncrementalStringBuilder builder(isolate);
318 15 : builder.AppendString(isolate->factory()->NewSubString(fun_str, 0, 111));
319 : builder.AppendCString("...<omitted>...");
320 : builder.AppendString(isolate->factory()->NewSubString(
321 15 : fun_str, fun_str->length() - 2, fun_str->length()));
322 :
323 30 : return builder.Finish().ToHandleChecked();
324 : }
325 843 : return fun_str;
326 43564 : } else if (input->IsSymbol()) {
327 : // -- S y m b o l
328 : Handle<Symbol> symbol = Handle<Symbol>::cast(input);
329 :
330 1482 : IncrementalStringBuilder builder(isolate);
331 : builder.AppendCString("Symbol(");
332 1482 : if (symbol->name()->IsString()) {
333 838 : builder.AppendString(handle(String::cast(symbol->name()), isolate));
334 : }
335 : builder.AppendCharacter(')');
336 :
337 2964 : return builder.Finish().ToHandleChecked();
338 42082 : } else if (input->IsJSReceiver()) {
339 : // -- J S R e c e i v e r
340 42082 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input);
341 : Handle<Object> to_string = JSReceiver::GetDataProperty(
342 42082 : receiver, isolate->factory()->toString_string());
343 :
344 126246 : if (IsErrorObject(isolate, input) ||
345 116086 : *to_string == *isolate->error_to_string()) {
346 : // When internally formatting error objects, use a side-effects-free
347 : // version of Error.prototype.toString independent of the actually
348 : // installed toString method.
349 36835 : return NoSideEffectsErrorToString(isolate, input);
350 73974 : } else if (*to_string == *isolate->object_to_string()) {
351 : Handle<Object> ctor = JSReceiver::GetDataProperty(
352 27790 : receiver, isolate->factory()->constructor_string());
353 27790 : if (ctor->IsFunction()) {
354 : Handle<String> ctor_name;
355 27356 : if (ctor->IsJSBoundFunction()) {
356 : ctor_name = JSBoundFunction::GetName(
357 : isolate, Handle<JSBoundFunction>::cast(ctor))
358 0 : .ToHandleChecked();
359 27356 : } else if (ctor->IsJSFunction()) {
360 : Handle<Object> ctor_name_obj =
361 27356 : JSFunction::GetName(isolate, Handle<JSFunction>::cast(ctor));
362 27356 : ctor_name = AsStringOrEmpty(isolate, ctor_name_obj);
363 : }
364 :
365 27356 : if (ctor_name->length() != 0) {
366 26645 : IncrementalStringBuilder builder(isolate);
367 : builder.AppendCString("#<");
368 26645 : builder.AppendString(ctor_name);
369 : builder.AppendCString(">");
370 :
371 53290 : return builder.Finish().ToHandleChecked();
372 : }
373 : }
374 : }
375 : }
376 :
377 : // At this point, input is either none of the above or a JSReceiver.
378 :
379 : Handle<JSReceiver> receiver;
380 10342 : if (input->IsJSReceiver()) {
381 : receiver = Handle<JSReceiver>::cast(input);
382 : } else {
383 : // This is the only case where Object::ToObject throws.
384 : DCHECK(!input->IsSmi());
385 : int constructor_function_index =
386 : Handle<HeapObject>::cast(input)->map()->GetConstructorFunctionIndex();
387 0 : if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
388 0 : return isolate->factory()->NewStringFromAsciiChecked("[object Unknown]");
389 : }
390 :
391 : receiver = Object::ToObject(isolate, input, isolate->native_context())
392 0 : .ToHandleChecked();
393 : }
394 :
395 10342 : Handle<String> builtin_tag = handle(receiver->class_name(), isolate);
396 : Handle<Object> tag_obj = JSReceiver::GetDataProperty(
397 10342 : receiver, isolate->factory()->to_string_tag_symbol());
398 : Handle<String> tag =
399 10342 : tag_obj->IsString() ? Handle<String>::cast(tag_obj) : builtin_tag;
400 :
401 10342 : IncrementalStringBuilder builder(isolate);
402 : builder.AppendCString("[object ");
403 10342 : builder.AppendString(tag);
404 : builder.AppendCString("]");
405 :
406 20684 : return builder.Finish().ToHandleChecked();
407 : }
408 :
409 : // static
410 1058 : MaybeHandle<Object> Object::ConvertToLength(Isolate* isolate,
411 : Handle<Object> input) {
412 2116 : ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
413 918 : if (input->IsSmi()) {
414 672 : int value = std::max(Smi::cast(*input)->value(), 0);
415 : return handle(Smi::FromInt(value), isolate);
416 : }
417 694 : double len = DoubleToInteger(input->Number());
418 694 : if (len <= 0.0) {
419 : return handle(Smi::kZero, isolate);
420 212 : } else if (len >= kMaxSafeInteger) {
421 : len = kMaxSafeInteger;
422 : }
423 212 : return isolate->factory()->NewNumber(len);
424 : }
425 :
426 : // static
427 5303 : MaybeHandle<Object> Object::ConvertToIndex(
428 : Isolate* isolate, Handle<Object> input,
429 : MessageTemplate::Template error_index) {
430 5303 : if (input->IsUndefined(isolate)) return handle(Smi::kZero, isolate);
431 4932 : ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
432 3224 : if (input->IsSmi() && Smi::cast(*input)->value() >= 0) return input;
433 2408 : double len = DoubleToInteger(input->Number()) + 0.0;
434 2408 : auto js_len = isolate->factory()->NewNumber(len);
435 2408 : if (len < 0.0 || len > kMaxSafeInteger) {
436 1400 : THROW_NEW_ERROR(isolate, NewRangeError(error_index, js_len), Object);
437 : }
438 : return js_len;
439 : }
440 :
441 7187949 : bool Object::BooleanValue() {
442 7738043 : if (IsSmi()) return Smi::cast(this)->value() != 0;
443 : DCHECK(IsHeapObject());
444 : Isolate* isolate = HeapObject::cast(this)->GetIsolate();
445 9283753 : if (IsBoolean()) return IsTrue(isolate);
446 3991961 : if (IsNullOrUndefined(isolate)) return false;
447 3857836 : if (IsUndetectable()) return false; // Undetectable object is false.
448 4616538 : if (IsString()) return String::cast(this)->length() != 0;
449 3164224 : if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue();
450 : return true;
451 : }
452 :
453 :
454 : namespace {
455 :
456 : // TODO(bmeurer): Maybe we should introduce a marker interface Number,
457 : // where we put all these methods at some point?
458 : ComparisonResult NumberCompare(double x, double y) {
459 222904 : if (std::isnan(x) || std::isnan(y)) {
460 : return ComparisonResult::kUndefined;
461 89080 : } else if (x < y) {
462 : return ComparisonResult::kLessThan;
463 51564 : } else if (x > y) {
464 : return ComparisonResult::kGreaterThan;
465 : } else {
466 : return ComparisonResult::kEqual;
467 : }
468 : }
469 :
470 :
471 : bool NumberEquals(double x, double y) {
472 : // Must check explicitly for NaN's on Windows, but -0 works fine.
473 6795 : if (std::isnan(x)) return false;
474 6658 : if (std::isnan(y)) return false;
475 6557 : return x == y;
476 : }
477 :
478 :
479 6795 : bool NumberEquals(const Object* x, const Object* y) {
480 6795 : return NumberEquals(x->Number(), y->Number());
481 : }
482 :
483 :
484 : bool NumberEquals(Handle<Object> x, Handle<Object> y) {
485 5146 : return NumberEquals(*x, *y);
486 : }
487 :
488 : } // namespace
489 :
490 :
491 : // static
492 224238 : Maybe<ComparisonResult> Object::Compare(Handle<Object> x, Handle<Object> y) {
493 : // ES6 section 7.2.11 Abstract Relational Comparison step 3 and 4.
494 896736 : if (!Object::ToPrimitive(x, ToPrimitiveHint::kNumber).ToHandle(&x) ||
495 448260 : !Object::ToPrimitive(y, ToPrimitiveHint::kNumber).ToHandle(&y)) {
496 : return Nothing<ComparisonResult>();
497 : }
498 289120 : if (x->IsString() && y->IsString()) {
499 : // ES6 section 7.2.11 Abstract Relational Comparison step 5.
500 : return Just(
501 938 : String::Compare(Handle<String>::cast(x), Handle<String>::cast(y)));
502 : }
503 : // ES6 section 7.2.11 Abstract Relational Comparison step 6.
504 669048 : if (!Object::ToNumber(x).ToHandle(&x) || !Object::ToNumber(y).ToHandle(&y)) {
505 : return Nothing<ComparisonResult>();
506 : }
507 : return Just(NumberCompare(x->Number(), y->Number()));
508 : }
509 :
510 :
511 : // static
512 193235 : Maybe<bool> Object::Equals(Handle<Object> x, Handle<Object> y) {
513 : // This is the generic version of Abstract Equality Comparison; a version in
514 : // JavaScript land is available in the EqualStub and NotEqualStub. Whenever
515 : // you change something functionality wise in here, remember to update the
516 : // TurboFan code stubs as well.
517 : while (true) {
518 193242 : if (x->IsNumber()) {
519 5070 : if (y->IsNumber()) {
520 : return Just(NumberEquals(x, y));
521 112 : } else if (y->IsBoolean()) {
522 0 : return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
523 112 : } else if (y->IsString()) {
524 112 : return Just(NumberEquals(x, String::ToNumber(Handle<String>::cast(y))));
525 0 : } else if (y->IsJSReceiver()) {
526 0 : if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
527 0 : .ToHandle(&y)) {
528 : return Nothing<bool>();
529 : }
530 : } else {
531 : return Just(false);
532 : }
533 188172 : } else if (x->IsString()) {
534 168452 : if (y->IsString()) {
535 : return Just(
536 168376 : String::Equals(Handle<String>::cast(x), Handle<String>::cast(y)));
537 76 : } else if (y->IsNumber()) {
538 76 : x = String::ToNumber(Handle<String>::cast(x));
539 : return Just(NumberEquals(x, y));
540 0 : } else if (y->IsBoolean()) {
541 0 : x = String::ToNumber(Handle<String>::cast(x));
542 0 : return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
543 0 : } else if (y->IsJSReceiver()) {
544 0 : if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
545 0 : .ToHandle(&y)) {
546 : return Nothing<bool>();
547 : }
548 : } else {
549 : return Just(false);
550 : }
551 19720 : } else if (x->IsBoolean()) {
552 700 : if (y->IsOddball()) {
553 : return Just(x.is_identical_to(y));
554 0 : } else if (y->IsNumber()) {
555 0 : return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
556 0 : } else if (y->IsString()) {
557 0 : y = String::ToNumber(Handle<String>::cast(y));
558 0 : return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
559 0 : } else if (y->IsJSReceiver()) {
560 0 : if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
561 0 : .ToHandle(&y)) {
562 : return Nothing<bool>();
563 : }
564 0 : x = Oddball::ToNumber(Handle<Oddball>::cast(x));
565 : } else {
566 : return Just(false);
567 : }
568 19020 : } else if (x->IsSymbol()) {
569 63 : if (y->IsSymbol()) {
570 : return Just(x.is_identical_to(y));
571 0 : } else if (y->IsJSReceiver()) {
572 0 : if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
573 0 : .ToHandle(&y)) {
574 : return Nothing<bool>();
575 : }
576 : } else {
577 : return Just(false);
578 : }
579 18957 : } else if (x->IsJSReceiver()) {
580 18835 : if (y->IsJSReceiver()) {
581 : return Just(x.is_identical_to(y));
582 7 : } else if (y->IsUndetectable()) {
583 : return Just(x->IsUndetectable());
584 7 : } else if (y->IsBoolean()) {
585 0 : y = Oddball::ToNumber(Handle<Oddball>::cast(y));
586 7 : } else if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(x))
587 14 : .ToHandle(&x)) {
588 : return Nothing<bool>();
589 : }
590 : } else {
591 244 : return Just(x->IsUndetectable() && y->IsUndetectable());
592 : }
593 : }
594 : }
595 :
596 :
597 16129 : bool Object::StrictEquals(Object* that) {
598 16129 : if (this->IsNumber()) {
599 2466 : if (!that->IsNumber()) return false;
600 1649 : return NumberEquals(this, that);
601 13663 : } else if (this->IsString()) {
602 12013 : if (!that->IsString()) return false;
603 11922 : return String::cast(this)->Equals(String::cast(that));
604 : }
605 1650 : return this == that;
606 : }
607 :
608 :
609 : // static
610 22073 : Handle<String> Object::TypeOf(Isolate* isolate, Handle<Object> object) {
611 22073 : if (object->IsNumber()) return isolate->factory()->number_string();
612 21229 : if (object->IsOddball()) return handle(Oddball::cast(*object)->type_of());
613 19076 : if (object->IsUndetectable()) {
614 : return isolate->factory()->undefined_string();
615 : }
616 19076 : if (object->IsString()) return isolate->factory()->string_string();
617 17832 : if (object->IsSymbol()) return isolate->factory()->symbol_string();
618 17759 : if (object->IsString()) return isolate->factory()->string_string();
619 17759 : if (object->IsCallable()) return isolate->factory()->function_string();
620 : return isolate->factory()->object_string();
621 : }
622 :
623 :
624 : // static
625 43151 : MaybeHandle<Object> Object::Multiply(Isolate* isolate, Handle<Object> lhs,
626 : Handle<Object> rhs) {
627 83324 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
628 6054 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
629 5410 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
630 : }
631 42829 : return isolate->factory()->NewNumber(lhs->Number() * rhs->Number());
632 : }
633 :
634 :
635 : // static
636 11590 : MaybeHandle<Object> Object::Divide(Isolate* isolate, Handle<Object> lhs,
637 : Handle<Object> rhs) {
638 23121 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
639 172 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
640 160 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
641 : }
642 11584 : return isolate->factory()->NewNumber(lhs->Number() / rhs->Number());
643 : }
644 :
645 :
646 : // static
647 5190 : MaybeHandle<Object> Object::Modulus(Isolate* isolate, Handle<Object> lhs,
648 : Handle<Object> rhs) {
649 10314 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
650 162 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
651 150 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
652 : }
653 5184 : return isolate->factory()->NewNumber(modulo(lhs->Number(), rhs->Number()));
654 : }
655 :
656 :
657 : // static
658 225776 : MaybeHandle<Object> Object::Add(Isolate* isolate, Handle<Object> lhs,
659 : Handle<Object> rhs) {
660 403085 : if (lhs->IsNumber() && rhs->IsNumber()) {
661 172508 : return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
662 96724 : } else if (lhs->IsString() && rhs->IsString()) {
663 : return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
664 73770 : Handle<String>::cast(rhs));
665 : }
666 32766 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToPrimitive(lhs), Object);
667 27540 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToPrimitive(rhs), Object);
668 19863 : if (lhs->IsString() || rhs->IsString()) {
669 23550 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToString(isolate, rhs),
670 : Object);
671 23538 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToString(isolate, lhs),
672 : Object);
673 : return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
674 22578 : Handle<String>::cast(rhs));
675 : }
676 3978 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
677 3954 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
678 1497 : return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
679 : }
680 :
681 :
682 : // static
683 19304 : MaybeHandle<Object> Object::Subtract(Isolate* isolate, Handle<Object> lhs,
684 : Handle<Object> rhs) {
685 38483 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
686 388 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
687 376 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
688 : }
689 19298 : return isolate->factory()->NewNumber(lhs->Number() - rhs->Number());
690 : }
691 :
692 :
693 : // static
694 9158 : MaybeHandle<Object> Object::ShiftLeft(Isolate* isolate, Handle<Object> lhs,
695 : Handle<Object> rhs) {
696 18259 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
697 170 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
698 158 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
699 : }
700 9152 : return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs)
701 9152 : << (NumberToUint32(*rhs) & 0x1F));
702 : }
703 :
704 :
705 : // static
706 20865 : MaybeHandle<Object> Object::ShiftRight(Isolate* isolate, Handle<Object> lhs,
707 : Handle<Object> rhs) {
708 41658 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
709 238 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
710 226 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
711 : }
712 20859 : return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) >>
713 20859 : (NumberToUint32(*rhs) & 0x1F));
714 : }
715 :
716 :
717 : // static
718 10299 : MaybeHandle<Object> Object::ShiftRightLogical(Isolate* isolate,
719 : Handle<Object> lhs,
720 : Handle<Object> rhs) {
721 20473 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
722 320 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
723 308 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
724 : }
725 10293 : return isolate->factory()->NewNumberFromUint(NumberToUint32(*lhs) >>
726 10293 : (NumberToUint32(*rhs) & 0x1F));
727 : }
728 :
729 :
730 : // static
731 19582 : MaybeHandle<Object> Object::BitwiseAnd(Isolate* isolate, Handle<Object> lhs,
732 : Handle<Object> rhs) {
733 38175 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
734 3682 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
735 3670 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
736 : }
737 19576 : return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) &
738 19576 : NumberToInt32(*rhs));
739 : }
740 :
741 :
742 : // static
743 64022 : MaybeHandle<Object> Object::BitwiseOr(Isolate* isolate, Handle<Object> lhs,
744 : Handle<Object> rhs) {
745 126575 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
746 4616 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
747 4552 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
748 : }
749 63990 : return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) |
750 63990 : NumberToInt32(*rhs));
751 : }
752 :
753 :
754 : // static
755 8254 : MaybeHandle<Object> Object::BitwiseXor(Isolate* isolate, Handle<Object> lhs,
756 : Handle<Object> rhs) {
757 16352 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
758 398 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
759 386 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
760 : }
761 8248 : return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) ^
762 8248 : NumberToInt32(*rhs));
763 : }
764 :
765 : // static
766 178702 : MaybeHandle<Object> Object::OrdinaryHasInstance(Isolate* isolate,
767 : Handle<Object> callable,
768 : Handle<Object> object) {
769 : // The {callable} must have a [[Call]] internal method.
770 178702 : if (!callable->IsCallable()) return isolate->factory()->false_value();
771 :
772 : // Check if {callable} is a bound function, and if so retrieve its
773 : // [[BoundTargetFunction]] and use that instead of {callable}.
774 178642 : if (callable->IsJSBoundFunction()) {
775 : Handle<Object> bound_callable(
776 : Handle<JSBoundFunction>::cast(callable)->bound_target_function(),
777 : isolate);
778 409 : return Object::InstanceOf(isolate, object, bound_callable);
779 : }
780 :
781 : // If {object} is not a receiver, return false.
782 178233 : if (!object->IsJSReceiver()) return isolate->factory()->false_value();
783 :
784 : // Get the "prototype" of {callable}; raise an error if it's not a receiver.
785 : Handle<Object> prototype;
786 333460 : ASSIGN_RETURN_ON_EXCEPTION(
787 : isolate, prototype,
788 : Object::GetProperty(callable, isolate->factory()->prototype_string()),
789 : Object);
790 166730 : if (!prototype->IsJSReceiver()) {
791 331042 : THROW_NEW_ERROR(
792 : isolate,
793 : NewTypeError(MessageTemplate::kInstanceofNonobjectProto, prototype),
794 : Object);
795 : }
796 :
797 : // Return whether or not {prototype} is in the prototype chain of {object}.
798 : Maybe<bool> result = JSReceiver::HasInPrototypeChain(
799 1209 : isolate, Handle<JSReceiver>::cast(object), prototype);
800 1209 : if (result.IsNothing()) return MaybeHandle<Object>();
801 1159 : return isolate->factory()->ToBoolean(result.FromJust());
802 : }
803 :
804 : // static
805 493 : MaybeHandle<Object> Object::InstanceOf(Isolate* isolate, Handle<Object> object,
806 : Handle<Object> callable) {
807 : // The {callable} must be a receiver.
808 493 : if (!callable->IsJSReceiver()) {
809 0 : THROW_NEW_ERROR(isolate,
810 : NewTypeError(MessageTemplate::kNonObjectInInstanceOfCheck),
811 : Object);
812 : }
813 :
814 : // Lookup the @@hasInstance method on {callable}.
815 : Handle<Object> inst_of_handler;
816 986 : ASSIGN_RETURN_ON_EXCEPTION(
817 : isolate, inst_of_handler,
818 : JSReceiver::GetMethod(Handle<JSReceiver>::cast(callable),
819 : isolate->factory()->has_instance_symbol()),
820 : Object);
821 493 : if (!inst_of_handler->IsUndefined(isolate)) {
822 : // Call the {inst_of_handler} on the {callable}.
823 : Handle<Object> result;
824 972 : ASSIGN_RETURN_ON_EXCEPTION(
825 : isolate, result,
826 : Execution::Call(isolate, inst_of_handler, callable, 1, &object),
827 : Object);
828 479 : return isolate->factory()->ToBoolean(result->BooleanValue());
829 : }
830 :
831 : // The {callable} must have a [[Call]] internal method.
832 7 : if (!callable->IsCallable()) {
833 14 : THROW_NEW_ERROR(
834 : isolate, NewTypeError(MessageTemplate::kNonCallableInInstanceOfCheck),
835 : Object);
836 : }
837 :
838 : // Fall back to OrdinaryHasInstance with {callable} and {object}.
839 : Handle<Object> result;
840 0 : ASSIGN_RETURN_ON_EXCEPTION(
841 : isolate, result,
842 : JSReceiver::OrdinaryHasInstance(isolate, callable, object), Object);
843 : return result;
844 : }
845 :
846 1792529 : Maybe<bool> Object::IsArray(Handle<Object> object) {
847 1792529 : if (object->IsJSArray()) return Just(true);
848 1745587 : if (object->IsJSProxy()) {
849 : Handle<JSProxy> proxy = Handle<JSProxy>::cast(object);
850 : Isolate* isolate = proxy->GetIsolate();
851 1689 : if (proxy->IsRevoked()) {
852 : isolate->Throw(*isolate->factory()->NewTypeError(
853 : MessageTemplate::kProxyRevoked,
854 252 : isolate->factory()->NewStringFromAsciiChecked("IsArray")));
855 : return Nothing<bool>();
856 : }
857 1605 : return Object::IsArray(handle(proxy->target(), isolate));
858 : }
859 : return Just(false);
860 : }
861 :
862 :
863 : // static
864 17847067 : MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
865 : Handle<Name> name) {
866 : Handle<Object> func;
867 : Isolate* isolate = receiver->GetIsolate();
868 35694134 : ASSIGN_RETURN_ON_EXCEPTION(isolate, func,
869 : JSReceiver::GetProperty(receiver, name), Object);
870 17804002 : if (func->IsNullOrUndefined(isolate)) {
871 : return isolate->factory()->undefined_value();
872 : }
873 1628224 : if (!func->IsCallable()) {
874 728 : THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kPropertyNotFunction,
875 : func, name, receiver),
876 : Object);
877 : }
878 : return func;
879 : }
880 :
881 : namespace {
882 26935 : MaybeHandle<FixedArray> CreateListFromArrayLikeFastPath(
883 : Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
884 52159 : if (element_types != ElementTypes::kAll || !object->IsJSArray()) {
885 : return MaybeHandle<FixedArray>();
886 : }
887 : Handle<JSArray> array = Handle<JSArray>::cast(object);
888 : uint32_t length;
889 3166 : if (!array->HasArrayPrototype(isolate) ||
890 3113 : !array->length()->ToUint32(&length) || !array->HasFastElements() ||
891 444 : !JSObject::PrototypeHasNoElements(isolate, *array)) {
892 : return MaybeHandle<FixedArray>();
893 : }
894 360 : return array->GetElementsAccessor()->CreateListFromArray(isolate, array);
895 : }
896 : } // namespace
897 :
898 : // static
899 26935 : MaybeHandle<FixedArray> Object::CreateListFromArrayLike(
900 : Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
901 : // Fast-path for JS_ARRAY_TYPE.
902 : MaybeHandle<FixedArray> fast_result =
903 26935 : CreateListFromArrayLikeFastPath(isolate, object, element_types);
904 26935 : if (!fast_result.is_null()) return fast_result;
905 : // 1. ReturnIfAbrupt(object).
906 : // 2. (default elementTypes -- not applicable.)
907 : // 3. If Type(obj) is not Object, throw a TypeError exception.
908 26575 : if (!object->IsJSReceiver()) {
909 1773 : THROW_NEW_ERROR(isolate,
910 : NewTypeError(MessageTemplate::kCalledOnNonObject,
911 : isolate->factory()->NewStringFromAsciiChecked(
912 : "CreateListFromArrayLike")),
913 : FixedArray);
914 : }
915 :
916 : // 4. Let len be ? ToLength(? Get(obj, "length")).
917 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
918 : Handle<Object> raw_length_number;
919 51968 : ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number,
920 : Object::GetLengthFromArrayLike(isolate, receiver),
921 : FixedArray);
922 : uint32_t len;
923 51842 : if (!raw_length_number->ToUint32(&len) ||
924 25914 : len > static_cast<uint32_t>(FixedArray::kMaxLength)) {
925 84 : THROW_NEW_ERROR(isolate,
926 : NewRangeError(MessageTemplate::kInvalidArrayLength),
927 : FixedArray);
928 : }
929 : // 5. Let list be an empty List.
930 25886 : Handle<FixedArray> list = isolate->factory()->NewFixedArray(len);
931 : // 6. Let index be 0.
932 : // 7. Repeat while index < len:
933 62455423 : for (uint32_t index = 0; index < len; ++index) {
934 : // 7a. Let indexName be ToString(index).
935 : // 7b. Let next be ? Get(obj, indexName).
936 : Handle<Object> next;
937 124859298 : ASSIGN_RETURN_ON_EXCEPTION(isolate, next,
938 : JSReceiver::GetElement(isolate, receiver, index),
939 : FixedArray);
940 62429593 : switch (element_types) {
941 : case ElementTypes::kAll:
942 : // Nothing to do.
943 : break;
944 : case ElementTypes::kStringAndSymbol: {
945 : // 7c. If Type(next) is not an element of elementTypes, throw a
946 : // TypeError exception.
947 4247 : if (!next->IsName()) {
948 112 : THROW_NEW_ERROR(isolate,
949 : NewTypeError(MessageTemplate::kNotPropertyName, next),
950 : FixedArray);
951 : }
952 : // 7d. Append next as the last element of list.
953 : // Internalize on the fly so we can use pointer identity later.
954 4191 : next = isolate->factory()->InternalizeName(Handle<Name>::cast(next));
955 4191 : break;
956 : }
957 : }
958 124859074 : list->set(index, *next);
959 : // 7e. Set index to index + 1. (See loop header.)
960 : }
961 : // 8. Return list.
962 : return list;
963 : }
964 :
965 :
966 : // static
967 62056 : MaybeHandle<Object> Object::GetLengthFromArrayLike(Isolate* isolate,
968 : Handle<Object> object) {
969 : Handle<Object> val;
970 : Handle<Object> key = isolate->factory()->length_string();
971 124112 : ASSIGN_RETURN_ON_EXCEPTION(
972 : isolate, val, Runtime::GetObjectProperty(isolate, object, key), Object);
973 61942 : return Object::ToLength(isolate, val);
974 : }
975 :
976 : // static
977 167034504 : Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) {
978 167005766 : for (; it->IsFound(); it->Next()) {
979 43856563 : switch (it->state()) {
980 : case LookupIterator::NOT_FOUND:
981 : case LookupIterator::TRANSITION:
982 0 : UNREACHABLE();
983 : case LookupIterator::JSPROXY:
984 : return JSProxy::HasProperty(it->isolate(), it->GetHolder<JSProxy>(),
985 136398 : it->GetName());
986 : case LookupIterator::INTERCEPTOR: {
987 : Maybe<PropertyAttributes> result =
988 246 : JSObject::GetPropertyAttributesWithInterceptor(it);
989 321 : if (result.IsNothing()) return Nothing<bool>();
990 246 : if (result.FromJust() != ABSENT) return Just(true);
991 171 : break;
992 : }
993 : case LookupIterator::ACCESS_CHECK: {
994 39338 : if (it->HasAccess()) break;
995 : Maybe<PropertyAttributes> result =
996 48 : JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
997 96 : if (result.IsNothing()) return Nothing<bool>();
998 0 : return Just(result.FromJust() != ABSENT);
999 : }
1000 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
1001 : // TypedArray out-of-bounds access.
1002 : return Just(false);
1003 : case LookupIterator::ACCESSOR:
1004 : case LookupIterator::DATA:
1005 : return Just(true);
1006 : }
1007 : }
1008 : return Just(false);
1009 : }
1010 :
1011 :
1012 : // static
1013 418142626 : MaybeHandle<Object> Object::GetProperty(LookupIterator* it) {
1014 385462379 : for (; it->IsFound(); it->Next()) {
1015 159011712 : switch (it->state()) {
1016 : case LookupIterator::NOT_FOUND:
1017 : case LookupIterator::TRANSITION:
1018 0 : UNREACHABLE();
1019 : case LookupIterator::JSPROXY: {
1020 : bool was_found;
1021 : MaybeHandle<Object> result =
1022 : JSProxy::GetProperty(it->isolate(), it->GetHolder<JSProxy>(),
1023 436900 : it->GetName(), it->GetReceiver(), &was_found);
1024 218450 : if (!was_found) it->NotFound();
1025 218450 : return result;
1026 : }
1027 : case LookupIterator::INTERCEPTOR: {
1028 : bool done;
1029 : Handle<Object> result;
1030 13447 : ASSIGN_RETURN_ON_EXCEPTION(
1031 : it->isolate(), result,
1032 : JSObject::GetPropertyWithInterceptor(it, &done), Object);
1033 5102 : if (done) return result;
1034 1901 : break;
1035 : }
1036 : case LookupIterator::ACCESS_CHECK:
1037 1261949 : if (it->HasAccess()) break;
1038 1378 : return JSObject::GetPropertyWithFailedAccessCheck(it);
1039 : case LookupIterator::ACCESSOR:
1040 10149997 : return GetPropertyWithAccessor(it);
1041 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
1042 : return it->isolate()->factory()->undefined_value();
1043 : case LookupIterator::DATA:
1044 147371417 : return it->GetDataValue();
1045 : }
1046 : }
1047 : return it->isolate()->factory()->undefined_value();
1048 : }
1049 :
1050 :
1051 : // static
1052 218450 : MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
1053 : Handle<JSProxy> proxy,
1054 : Handle<Name> name,
1055 : Handle<Object> receiver,
1056 : bool* was_found) {
1057 218450 : *was_found = true;
1058 :
1059 : DCHECK(!name->IsPrivate());
1060 218450 : STACK_CHECK(isolate, MaybeHandle<Object>());
1061 : Handle<Name> trap_name = isolate->factory()->get_string();
1062 : // 1. Assert: IsPropertyKey(P) is true.
1063 : // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
1064 : Handle<Object> handler(proxy->handler(), isolate);
1065 : // 3. If handler is null, throw a TypeError exception.
1066 : // 4. Assert: Type(handler) is Object.
1067 218226 : if (proxy->IsRevoked()) {
1068 112 : THROW_NEW_ERROR(isolate,
1069 : NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1070 : Object);
1071 : }
1072 : // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
1073 : Handle<JSReceiver> target(proxy->target(), isolate);
1074 : // 6. Let trap be ? GetMethod(handler, "get").
1075 : Handle<Object> trap;
1076 436340 : ASSIGN_RETURN_ON_EXCEPTION(
1077 : isolate, trap,
1078 : Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), Object);
1079 : // 7. If trap is undefined, then
1080 176035 : if (trap->IsUndefined(isolate)) {
1081 : // 7.a Return target.[[Get]](P, Receiver).
1082 : LookupIterator it =
1083 99844 : LookupIterator::PropertyOrElement(isolate, receiver, name, target);
1084 99844 : MaybeHandle<Object> result = Object::GetProperty(&it);
1085 199688 : *was_found = it.IsFound();
1086 99844 : return result;
1087 : }
1088 : // 8. Let trapResult be ? Call(trap, handler, «target, P, Receiver»).
1089 : Handle<Object> trap_result;
1090 76191 : Handle<Object> args[] = {target, name, receiver};
1091 152382 : ASSIGN_RETURN_ON_EXCEPTION(
1092 : isolate, trap_result,
1093 : Execution::Call(isolate, trap, handler, arraysize(args), args), Object);
1094 : // 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
1095 : PropertyDescriptor target_desc;
1096 : Maybe<bool> target_found =
1097 73639 : JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
1098 73639 : MAYBE_RETURN_NULL(target_found);
1099 : // 10. If targetDesc is not undefined, then
1100 73639 : if (target_found.FromJust()) {
1101 : // 10.a. If IsDataDescriptor(targetDesc) and targetDesc.[[Configurable]] is
1102 : // false and targetDesc.[[Writable]] is false, then
1103 : // 10.a.i. If SameValue(trapResult, targetDesc.[[Value]]) is false,
1104 : // throw a TypeError exception.
1105 6800 : bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
1106 1043 : !target_desc.configurable() &&
1107 6988 : !target_desc.writable() &&
1108 132 : !trap_result->SameValue(*target_desc.value());
1109 6856 : if (inconsistent) {
1110 84 : THROW_NEW_ERROR(
1111 : isolate, NewTypeError(MessageTemplate::kProxyGetNonConfigurableData,
1112 : name, target_desc.value(), trap_result),
1113 : Object);
1114 : }
1115 : // 10.b. If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]]
1116 : // is false and targetDesc.[[Get]] is undefined, then
1117 : // 10.b.i. If trapResult is not undefined, throw a TypeError exception.
1118 56 : inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
1119 56 : !target_desc.configurable() &&
1120 6842 : target_desc.get()->IsUndefined(isolate) &&
1121 : !trap_result->IsUndefined(isolate);
1122 6814 : if (inconsistent) {
1123 28 : THROW_NEW_ERROR(
1124 : isolate,
1125 : NewTypeError(MessageTemplate::kProxyGetNonConfigurableAccessor, name,
1126 : trap_result),
1127 : Object);
1128 : }
1129 : }
1130 : // 11. Return trap_result
1131 : return trap_result;
1132 : }
1133 :
1134 :
1135 14865541 : Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it) {
1136 14193804 : for (; it->IsFound(); it->Next()) {
1137 7056468 : switch (it->state()) {
1138 : case LookupIterator::INTERCEPTOR:
1139 : case LookupIterator::NOT_FOUND:
1140 : case LookupIterator::TRANSITION:
1141 0 : UNREACHABLE();
1142 : case LookupIterator::ACCESS_CHECK:
1143 : // Support calling this method without an active context, but refuse
1144 : // access to access-checked objects in that case.
1145 890515 : if (it->isolate()->context() != nullptr && it->HasAccess()) continue;
1146 : // Fall through.
1147 : case LookupIterator::JSPROXY:
1148 : it->NotFound();
1149 3209 : return it->isolate()->factory()->undefined_value();
1150 : case LookupIterator::ACCESSOR:
1151 : // TODO(verwaest): For now this doesn't call into AccessorInfo, since
1152 : // clients don't need it. Update once relevant.
1153 : it->NotFound();
1154 627697 : return it->isolate()->factory()->undefined_value();
1155 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
1156 0 : return it->isolate()->factory()->undefined_value();
1157 : case LookupIterator::DATA:
1158 5535444 : return it->GetDataValue();
1159 : }
1160 : }
1161 40434 : return it->isolate()->factory()->undefined_value();
1162 : }
1163 :
1164 :
1165 62558874 : bool Object::ToInt32(int32_t* value) {
1166 62558874 : if (IsSmi()) {
1167 62557349 : *value = Smi::cast(this)->value();
1168 62557349 : return true;
1169 : }
1170 1525 : if (IsHeapNumber()) {
1171 : double num = HeapNumber::cast(this)->value();
1172 1476 : if (FastI2D(FastD2I(num)) == num) {
1173 77 : *value = FastD2I(num);
1174 77 : return true;
1175 : }
1176 : }
1177 : return false;
1178 : }
1179 :
1180 3888974 : Handle<SharedFunctionInfo> FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(
1181 : Isolate* isolate, Handle<FunctionTemplateInfo> info) {
1182 : Object* current_info = info->shared_function_info();
1183 3888974 : if (current_info->IsSharedFunctionInfo()) {
1184 : return handle(SharedFunctionInfo::cast(current_info), isolate);
1185 : }
1186 :
1187 : Handle<Object> class_name(info->class_name(), isolate);
1188 : Handle<String> name = class_name->IsString()
1189 : ? Handle<String>::cast(class_name)
1190 7456101 : : isolate->factory()->empty_string();
1191 3759365 : Handle<Code> code = isolate->builtins()->HandleApiCall();
1192 3759365 : bool is_constructor = !info->remove_prototype();
1193 : Handle<SharedFunctionInfo> result =
1194 7518730 : isolate->factory()->NewSharedFunctionInfo(name, code, is_constructor);
1195 3759364 : if (is_constructor) {
1196 7436484 : result->SetConstructStub(*isolate->builtins()->JSConstructStubApi());
1197 : }
1198 :
1199 : result->set_length(info->length());
1200 3821993 : if (class_name->IsString()) result->set_instance_class_name(*class_name);
1201 : result->set_api_func_data(*info);
1202 : result->DontAdaptArguments();
1203 : DCHECK(result->IsApiFunction());
1204 :
1205 3759364 : info->set_shared_function_info(*result);
1206 3759364 : return result;
1207 : }
1208 :
1209 18277 : bool FunctionTemplateInfo::IsTemplateFor(Map* map) {
1210 : // There is a constraint on the object; check.
1211 18277 : if (!map->IsJSObjectMap()) return false;
1212 : // Fetch the constructor function of the object.
1213 18277 : Object* cons_obj = map->GetConstructor();
1214 : Object* type;
1215 18277 : if (cons_obj->IsJSFunction()) {
1216 : JSFunction* fun = JSFunction::cast(cons_obj);
1217 : type = fun->shared()->function_data();
1218 18 : } else if (cons_obj->IsFunctionTemplateInfo()) {
1219 : type = FunctionTemplateInfo::cast(cons_obj);
1220 : } else {
1221 : return false;
1222 : }
1223 : // Iterate through the chain of inheriting function templates to
1224 : // see if the required one occurs.
1225 18878 : while (type->IsFunctionTemplateInfo()) {
1226 10914 : if (type == this) return true;
1227 : type = FunctionTemplateInfo::cast(type)->parent_template();
1228 : }
1229 : // Didn't find the required type in the inheritance chain.
1230 : return false;
1231 : }
1232 :
1233 :
1234 : // static
1235 379945 : Handle<TemplateList> TemplateList::New(Isolate* isolate, int size) {
1236 : Handle<FixedArray> list =
1237 379945 : isolate->factory()->NewFixedArray(kLengthIndex + size);
1238 : list->set(kLengthIndex, Smi::kZero);
1239 379945 : return Handle<TemplateList>::cast(list);
1240 : }
1241 :
1242 : // static
1243 6570929 : Handle<TemplateList> TemplateList::Add(Isolate* isolate,
1244 : Handle<TemplateList> list,
1245 : Handle<i::Object> value) {
1246 : STATIC_ASSERT(kFirstElementIndex == 1);
1247 6570929 : int index = list->length() + 1;
1248 : Handle<i::FixedArray> fixed_array = Handle<FixedArray>::cast(list);
1249 6570929 : fixed_array = FixedArray::SetAndGrow(fixed_array, index, value);
1250 : fixed_array->set(kLengthIndex, Smi::FromInt(index));
1251 6570929 : return Handle<TemplateList>::cast(fixed_array);
1252 : }
1253 :
1254 : // static
1255 2463601 : MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor,
1256 : Handle<JSReceiver> new_target,
1257 : Handle<AllocationSite> site) {
1258 : // If called through new, new.target can be:
1259 : // - a subclass of constructor,
1260 : // - a proxy wrapper around constructor, or
1261 : // - the constructor itself.
1262 : // If called through Reflect.construct, it's guaranteed to be a constructor.
1263 4927112 : Isolate* const isolate = constructor->GetIsolate();
1264 : DCHECK(constructor->IsConstructor());
1265 : DCHECK(new_target->IsConstructor());
1266 : DCHECK(!constructor->has_initial_map() ||
1267 : constructor->initial_map()->instance_type() != JS_FUNCTION_TYPE);
1268 :
1269 : Handle<Map> initial_map;
1270 4927202 : ASSIGN_RETURN_ON_EXCEPTION(
1271 : isolate, initial_map,
1272 : JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject);
1273 : Handle<JSObject> result =
1274 2463556 : isolate->factory()->NewJSObjectFromMap(initial_map, NOT_TENURED, site);
1275 2463556 : if (initial_map->is_dictionary_map()) {
1276 : Handle<NameDictionary> dictionary =
1277 0 : NameDictionary::New(isolate, NameDictionary::kInitialCapacity);
1278 0 : result->set_properties(*dictionary);
1279 : }
1280 2463556 : isolate->counters()->constructed_objects()->Increment();
1281 2463556 : isolate->counters()->constructed_objects_runtime()->Increment();
1282 : return result;
1283 : }
1284 :
1285 2495402 : void JSObject::EnsureWritableFastElements(Handle<JSObject> object) {
1286 : DCHECK(object->HasFastSmiOrObjectElements() ||
1287 : object->HasFastStringWrapperElements());
1288 : FixedArray* raw_elems = FixedArray::cast(object->elements());
1289 2495402 : Heap* heap = object->GetHeap();
1290 4965018 : if (raw_elems->map() != heap->fixed_cow_array_map()) return;
1291 25786 : Isolate* isolate = heap->isolate();
1292 : Handle<FixedArray> elems(raw_elems, isolate);
1293 : Handle<FixedArray> writable_elems = isolate->factory()->CopyFixedArrayWithMap(
1294 25786 : elems, isolate->factory()->fixed_array_map());
1295 25786 : object->set_elements(*writable_elems);
1296 25786 : isolate->counters()->cow_arrays_converted()->Increment();
1297 : }
1298 :
1299 :
1300 : // ES6 9.5.1
1301 : // static
1302 5702696 : MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
1303 : Isolate* isolate = proxy->GetIsolate();
1304 : Handle<String> trap_name = isolate->factory()->getPrototypeOf_string();
1305 :
1306 5702696 : STACK_CHECK(isolate, MaybeHandle<Object>());
1307 :
1308 : // 1. Let handler be the value of the [[ProxyHandler]] internal slot.
1309 : // 2. If handler is null, throw a TypeError exception.
1310 : // 3. Assert: Type(handler) is Object.
1311 : // 4. Let target be the value of the [[ProxyTarget]] internal slot.
1312 5702696 : if (proxy->IsRevoked()) {
1313 56 : THROW_NEW_ERROR(isolate,
1314 : NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1315 : Object);
1316 : }
1317 : Handle<JSReceiver> target(proxy->target(), isolate);
1318 : Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
1319 :
1320 : // 5. Let trap be ? GetMethod(handler, "getPrototypeOf").
1321 : Handle<Object> trap;
1322 11405336 : ASSIGN_RETURN_ON_EXCEPTION(isolate, trap, GetMethod(handler, trap_name),
1323 : Object);
1324 : // 6. If trap is undefined, then return target.[[GetPrototypeOf]]().
1325 5702668 : if (trap->IsUndefined(isolate)) {
1326 4202080 : return JSReceiver::GetPrototype(isolate, target);
1327 : }
1328 : // 7. Let handlerProto be ? Call(trap, handler, «target»).
1329 : Handle<Object> argv[] = {target};
1330 : Handle<Object> handler_proto;
1331 3001176 : ASSIGN_RETURN_ON_EXCEPTION(
1332 : isolate, handler_proto,
1333 : Execution::Call(isolate, trap, handler, arraysize(argv), argv), Object);
1334 : // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError.
1335 1500476 : if (!(handler_proto->IsJSReceiver() || handler_proto->IsNull(isolate))) {
1336 28 : THROW_NEW_ERROR(isolate,
1337 : NewTypeError(MessageTemplate::kProxyGetPrototypeOfInvalid),
1338 : Object);
1339 : }
1340 : // 9. Let extensibleTarget be ? IsExtensible(target).
1341 1500420 : Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
1342 1500420 : MAYBE_RETURN_NULL(is_extensible);
1343 : // 10. If extensibleTarget is true, return handlerProto.
1344 1500420 : if (is_extensible.FromJust()) return handler_proto;
1345 : // 11. Let targetProto be ? target.[[GetPrototypeOf]]().
1346 : Handle<Object> target_proto;
1347 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, target_proto,
1348 : JSReceiver::GetPrototype(isolate, target), Object);
1349 : // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError.
1350 0 : if (!handler_proto->SameValue(*target_proto)) {
1351 0 : THROW_NEW_ERROR(
1352 : isolate,
1353 : NewTypeError(MessageTemplate::kProxyGetPrototypeOfNonExtensible),
1354 : Object);
1355 : }
1356 : // 13. Return handlerProto.
1357 : return handler_proto;
1358 : }
1359 :
1360 10150548 : MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) {
1361 : Isolate* isolate = it->isolate();
1362 10150548 : Handle<Object> structure = it->GetAccessors();
1363 : Handle<Object> receiver = it->GetReceiver();
1364 :
1365 : // We should never get here to initialize a const with the hole value since a
1366 : // const declaration would conflict with the getter.
1367 : DCHECK(!structure->IsForeign());
1368 :
1369 : // API style callbacks.
1370 10150548 : if (structure->IsAccessorInfo()) {
1371 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1372 884886 : Handle<Name> name = it->GetName();
1373 : Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
1374 884886 : if (!info->IsCompatibleReceiver(*receiver)) {
1375 210 : THROW_NEW_ERROR(isolate,
1376 : NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
1377 : name, receiver),
1378 : Object);
1379 : }
1380 :
1381 : v8::AccessorNameGetterCallback call_fun =
1382 : v8::ToCData<v8::AccessorNameGetterCallback>(info->getter());
1383 884781 : if (call_fun == nullptr) return isolate->factory()->undefined_value();
1384 :
1385 898837 : if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1386 36 : ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver,
1387 : Object::ConvertReceiver(isolate, receiver),
1388 : Object);
1389 : }
1390 :
1391 : PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1392 : Object::DONT_THROW);
1393 884641 : Handle<Object> result = args.Call(call_fun, name);
1394 884641 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1395 884406 : if (result.is_null()) return isolate->factory()->undefined_value();
1396 : Handle<Object> reboxed_result = handle(*result, isolate);
1397 877302 : if (info->replace_on_access() && receiver->IsJSReceiver()) {
1398 : args.Call(reinterpret_cast<GenericNamedPropertySetterCallback>(
1399 : &Accessors::ReconfigureToDataProperty),
1400 0 : name, result);
1401 0 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1402 : }
1403 : return reboxed_result;
1404 : }
1405 :
1406 : // AccessorPair with 'cached' private property.
1407 9265662 : if (it->TryLookupCachedProperty()) {
1408 58 : return Object::GetProperty(it);
1409 : }
1410 :
1411 : // Regular accessor.
1412 : Handle<Object> getter(AccessorPair::cast(*structure)->getter(), isolate);
1413 9265604 : if (getter->IsFunctionTemplateInfo()) {
1414 : return Builtins::InvokeApiFunction(
1415 : isolate, false, Handle<FunctionTemplateInfo>::cast(getter), receiver, 0,
1416 313 : nullptr, isolate->factory()->undefined_value());
1417 9265291 : } else if (getter->IsCallable()) {
1418 : // TODO(rossberg): nicer would be to cast to some JSCallable here...
1419 : return Object::GetPropertyWithDefinedGetter(
1420 9256830 : receiver, Handle<JSReceiver>::cast(getter));
1421 : }
1422 : // Getter is not a function.
1423 : return isolate->factory()->undefined_value();
1424 : }
1425 :
1426 : // static
1427 0 : Address AccessorInfo::redirect(Isolate* isolate, Address address,
1428 : AccessorComponent component) {
1429 : ApiFunction fun(address);
1430 : DCHECK_EQ(ACCESSOR_GETTER, component);
1431 : ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
1432 245420 : return ExternalReference(&fun, type, isolate).address();
1433 : }
1434 :
1435 124109 : Address AccessorInfo::redirected_getter() const {
1436 : Address accessor = v8::ToCData<Address>(getter());
1437 124109 : if (accessor == nullptr) return nullptr;
1438 122710 : return redirect(GetIsolate(), accessor, ACCESSOR_GETTER);
1439 : }
1440 :
1441 39760 : bool AccessorInfo::IsCompatibleReceiverMap(Isolate* isolate,
1442 : Handle<AccessorInfo> info,
1443 : Handle<Map> map) {
1444 39760 : if (!info->HasExpectedReceiverType()) return true;
1445 72 : if (!map->IsJSObjectMap()) return false;
1446 : return FunctionTemplateInfo::cast(info->expected_receiver_type())
1447 72 : ->IsTemplateFor(*map);
1448 : }
1449 :
1450 1979712 : Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it,
1451 : Handle<Object> value,
1452 : ShouldThrow should_throw) {
1453 : Isolate* isolate = it->isolate();
1454 1979712 : Handle<Object> structure = it->GetAccessors();
1455 : Handle<Object> receiver = it->GetReceiver();
1456 :
1457 : // We should never get here to initialize a const with the hole value since a
1458 : // const declaration would conflict with the setter.
1459 : DCHECK(!structure->IsForeign());
1460 :
1461 : // API style callbacks.
1462 1979712 : if (structure->IsAccessorInfo()) {
1463 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1464 1781742 : Handle<Name> name = it->GetName();
1465 : Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
1466 1781743 : if (!info->IsCompatibleReceiver(*receiver)) {
1467 : isolate->Throw(*isolate->factory()->NewTypeError(
1468 210 : MessageTemplate::kIncompatibleMethodReceiver, name, receiver));
1469 : return Nothing<bool>();
1470 : }
1471 :
1472 : // The actual type of call_fun is either v8::AccessorNameSetterCallback or
1473 : // i::Accesors::AccessorNameBooleanSetterCallback, depending on whether the
1474 : // AccessorInfo was created by the API or internally (see accessors.cc).
1475 : // Here we handle both cases using GenericNamedPropertySetterCallback and
1476 : // its Call method.
1477 : GenericNamedPropertySetterCallback call_fun =
1478 : v8::ToCData<GenericNamedPropertySetterCallback>(info->setter());
1479 :
1480 1781637 : if (call_fun == nullptr) {
1481 : // TODO(verwaest): We should not get here anymore once all AccessorInfos
1482 : // are marked as special_data_property. They cannot both be writable and
1483 : // not have a setter.
1484 : return Just(true);
1485 : }
1486 :
1487 1922319 : if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1488 0 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1489 : isolate, receiver, Object::ConvertReceiver(isolate, receiver),
1490 : Nothing<bool>());
1491 : }
1492 :
1493 : PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1494 : should_throw);
1495 1781560 : Handle<Object> result = args.Call(call_fun, name, value);
1496 : // In the case of AccessorNameSetterCallback, we know that the result value
1497 : // cannot have been set, so the result of Call will be null. In the case of
1498 : // AccessorNameBooleanSetterCallback, the result will either be null
1499 : // (signalling an exception) or a boolean Oddball.
1500 1781560 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1501 1781295 : if (result.is_null()) return Just(true);
1502 : DCHECK(result->BooleanValue() || should_throw == DONT_THROW);
1503 1640606 : return Just(result->BooleanValue());
1504 : }
1505 :
1506 : // Regular accessor.
1507 : Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
1508 197970 : if (setter->IsFunctionTemplateInfo()) {
1509 159 : Handle<Object> argv[] = {value};
1510 318 : RETURN_ON_EXCEPTION_VALUE(
1511 : isolate, Builtins::InvokeApiFunction(
1512 : isolate, false, Handle<FunctionTemplateInfo>::cast(setter),
1513 : receiver, arraysize(argv), argv,
1514 : isolate->factory()->undefined_value()),
1515 : Nothing<bool>());
1516 : return Just(true);
1517 197811 : } else if (setter->IsCallable()) {
1518 : // TODO(rossberg): nicer would be to cast to some JSCallable here...
1519 : return SetPropertyWithDefinedSetter(
1520 179220 : receiver, Handle<JSReceiver>::cast(setter), value, should_throw);
1521 : }
1522 :
1523 45750 : RETURN_FAILURE(isolate, should_throw,
1524 : NewTypeError(MessageTemplate::kNoSetterInCallback,
1525 : it->GetName(), it->GetHolder<JSObject>()));
1526 : }
1527 :
1528 :
1529 9256830 : MaybeHandle<Object> Object::GetPropertyWithDefinedGetter(
1530 : Handle<Object> receiver,
1531 : Handle<JSReceiver> getter) {
1532 : Isolate* isolate = getter->GetIsolate();
1533 :
1534 : // Platforms with simulators like arm/arm64 expose a funny issue. If the
1535 : // simulator has a separate JS stack pointer from the C++ stack pointer, it
1536 : // can miss C++ stack overflows in the stack guard at the start of JavaScript
1537 : // functions. It would be very expensive to check the C++ stack pointer at
1538 : // that location. The best solution seems to be to break the impasse by
1539 : // adding checks at possible recursion points. What's more, we don't put
1540 : // this stack check behind the USE_SIMULATOR define in order to keep
1541 : // behavior the same between hardware and simulators.
1542 : StackLimitCheck check(isolate);
1543 9256830 : if (check.JsHasOverflowed()) {
1544 28 : isolate->StackOverflow();
1545 : return MaybeHandle<Object>();
1546 : }
1547 :
1548 9256802 : return Execution::Call(isolate, getter, receiver, 0, NULL);
1549 : }
1550 :
1551 :
1552 179220 : Maybe<bool> Object::SetPropertyWithDefinedSetter(Handle<Object> receiver,
1553 : Handle<JSReceiver> setter,
1554 : Handle<Object> value,
1555 : ShouldThrow should_throw) {
1556 : Isolate* isolate = setter->GetIsolate();
1557 :
1558 179220 : Handle<Object> argv[] = { value };
1559 358440 : RETURN_ON_EXCEPTION_VALUE(isolate, Execution::Call(isolate, setter, receiver,
1560 : arraysize(argv), argv),
1561 : Nothing<bool>());
1562 : return Just(true);
1563 : }
1564 :
1565 :
1566 : // static
1567 4210 : bool JSObject::AllCanRead(LookupIterator* it) {
1568 : // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of
1569 : // which have already been checked.
1570 : DCHECK(it->state() == LookupIterator::ACCESS_CHECK ||
1571 : it->state() == LookupIterator::INTERCEPTOR);
1572 5552 : for (it->Next(); it->IsFound(); it->Next()) {
1573 1429 : if (it->state() == LookupIterator::ACCESSOR) {
1574 146 : auto accessors = it->GetAccessors();
1575 146 : if (accessors->IsAccessorInfo()) {
1576 92 : if (AccessorInfo::cast(*accessors)->all_can_read()) return true;
1577 : }
1578 1283 : } else if (it->state() == LookupIterator::INTERCEPTOR) {
1579 1472 : if (it->GetInterceptor()->all_can_read()) return true;
1580 547 : } else if (it->state() == LookupIterator::JSPROXY) {
1581 : // Stop lookupiterating. And no, AllCanNotRead.
1582 : return false;
1583 : }
1584 : }
1585 : return false;
1586 : }
1587 :
1588 : namespace {
1589 :
1590 5313 : MaybeHandle<Object> GetPropertyWithInterceptorInternal(
1591 10598 : LookupIterator* it, Handle<InterceptorInfo> interceptor, bool* done) {
1592 5313 : *done = false;
1593 : Isolate* isolate = it->isolate();
1594 : // Make sure that the top context does not change when doing callbacks or
1595 : // interceptor calls.
1596 : AssertNoContextChange ncc(isolate);
1597 :
1598 5313 : if (interceptor->getter()->IsUndefined(isolate)) {
1599 : return isolate->factory()->undefined_value();
1600 : }
1601 :
1602 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1603 : Handle<Object> result;
1604 : Handle<Object> receiver = it->GetReceiver();
1605 5285 : if (!receiver->IsJSReceiver()) {
1606 38 : ASSIGN_RETURN_ON_EXCEPTION(
1607 : isolate, receiver, Object::ConvertReceiver(isolate, receiver), Object);
1608 : }
1609 : PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1610 : *holder, Object::DONT_THROW);
1611 :
1612 5285 : if (it->IsElement()) {
1613 : uint32_t index = it->index();
1614 : v8::IndexedPropertyGetterCallback getter =
1615 : v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
1616 2471 : result = args.Call(getter, index);
1617 : } else {
1618 2814 : Handle<Name> name = it->name();
1619 : DCHECK(!name->IsPrivate());
1620 :
1621 : DCHECK_IMPLIES(name->IsSymbol(), interceptor->can_intercept_symbols());
1622 :
1623 : v8::GenericNamedPropertyGetterCallback getter =
1624 : v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
1625 : interceptor->getter());
1626 2814 : result = args.Call(getter, name);
1627 : }
1628 :
1629 5285 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1630 5257 : if (result.is_null()) return isolate->factory()->undefined_value();
1631 3288 : *done = true;
1632 : // Rebox handle before return
1633 : return handle(*result, isolate);
1634 : }
1635 :
1636 281223 : Maybe<PropertyAttributes> GetPropertyAttributesWithInterceptorInternal(
1637 562338 : LookupIterator* it, Handle<InterceptorInfo> interceptor) {
1638 : Isolate* isolate = it->isolate();
1639 : // Make sure that the top context does not change when doing
1640 : // callbacks or interceptor calls.
1641 : AssertNoContextChange ncc(isolate);
1642 : HandleScope scope(isolate);
1643 :
1644 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1645 : DCHECK_IMPLIES(!it->IsElement() && it->name()->IsSymbol(),
1646 : interceptor->can_intercept_symbols());
1647 : Handle<Object> receiver = it->GetReceiver();
1648 281223 : if (!receiver->IsJSReceiver()) {
1649 28 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1650 : Object::ConvertReceiver(isolate, receiver),
1651 : Nothing<PropertyAttributes>());
1652 : }
1653 : PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1654 : *holder, Object::DONT_THROW);
1655 281223 : if (!interceptor->query()->IsUndefined(isolate)) {
1656 : Handle<Object> result;
1657 268 : if (it->IsElement()) {
1658 : uint32_t index = it->index();
1659 : v8::IndexedPropertyQueryCallback query =
1660 : v8::ToCData<v8::IndexedPropertyQueryCallback>(interceptor->query());
1661 102 : result = args.Call(query, index);
1662 : } else {
1663 166 : Handle<Name> name = it->name();
1664 : DCHECK(!name->IsPrivate());
1665 : v8::GenericNamedPropertyQueryCallback query =
1666 : v8::ToCData<v8::GenericNamedPropertyQueryCallback>(
1667 : interceptor->query());
1668 166 : result = args.Call(query, name);
1669 : }
1670 268 : if (!result.is_null()) {
1671 : int32_t value;
1672 62 : CHECK(result->ToInt32(&value));
1673 62 : return Just(static_cast<PropertyAttributes>(value));
1674 : }
1675 280955 : } else if (!interceptor->getter()->IsUndefined(isolate)) {
1676 : // TODO(verwaest): Use GetPropertyWithInterceptor?
1677 : Handle<Object> result;
1678 280847 : if (it->IsElement()) {
1679 : uint32_t index = it->index();
1680 : v8::IndexedPropertyGetterCallback getter =
1681 : v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
1682 280250 : result = args.Call(getter, index);
1683 : } else {
1684 597 : Handle<Name> name = it->name();
1685 : DCHECK(!name->IsPrivate());
1686 : v8::GenericNamedPropertyGetterCallback getter =
1687 : v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
1688 : interceptor->getter());
1689 597 : result = args.Call(getter, name);
1690 : }
1691 280847 : if (!result.is_null()) return Just(DONT_ENUM);
1692 : }
1693 :
1694 280682 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
1695 : return Just(ABSENT);
1696 : }
1697 :
1698 225683 : Maybe<bool> SetPropertyWithInterceptorInternal(
1699 660931 : LookupIterator* it, Handle<InterceptorInfo> interceptor,
1700 : Object::ShouldThrow should_throw, Handle<Object> value) {
1701 : Isolate* isolate = it->isolate();
1702 : // Make sure that the top context does not change when doing callbacks or
1703 : // interceptor calls.
1704 : AssertNoContextChange ncc(isolate);
1705 :
1706 225683 : if (interceptor->setter()->IsUndefined(isolate)) return Just(false);
1707 :
1708 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1709 : bool result;
1710 : Handle<Object> receiver = it->GetReceiver();
1711 217624 : if (!receiver->IsJSReceiver()) {
1712 0 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1713 : Object::ConvertReceiver(isolate, receiver),
1714 : Nothing<bool>());
1715 : }
1716 : PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1717 : *holder, should_throw);
1718 :
1719 217624 : if (it->IsElement()) {
1720 : uint32_t index = it->index();
1721 : v8::IndexedPropertySetterCallback setter =
1722 : v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter());
1723 : // TODO(neis): In the future, we may want to actually return the
1724 : // interceptor's result, which then should be a boolean.
1725 153226 : result = !args.Call(setter, index, value).is_null();
1726 : } else {
1727 141011 : Handle<Name> name = it->name();
1728 : DCHECK(!name->IsPrivate());
1729 :
1730 : DCHECK_IMPLIES(name->IsSymbol(), interceptor->can_intercept_symbols());
1731 :
1732 : v8::GenericNamedPropertySetterCallback setter =
1733 : v8::ToCData<v8::GenericNamedPropertySetterCallback>(
1734 : interceptor->setter());
1735 282022 : result = !args.Call(setter, name, value).is_null();
1736 : }
1737 :
1738 217624 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1739 : return Just(result);
1740 : }
1741 :
1742 208 : Maybe<bool> DefinePropertyWithInterceptorInternal(
1743 400 : LookupIterator* it, Handle<InterceptorInfo> interceptor,
1744 : Object::ShouldThrow should_throw, PropertyDescriptor& desc) {
1745 : Isolate* isolate = it->isolate();
1746 : // Make sure that the top context does not change when doing callbacks or
1747 : // interceptor calls.
1748 : AssertNoContextChange ncc(isolate);
1749 :
1750 208 : if (interceptor->definer()->IsUndefined(isolate)) return Just(false);
1751 :
1752 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1753 : bool result;
1754 : Handle<Object> receiver = it->GetReceiver();
1755 96 : if (!receiver->IsJSReceiver()) {
1756 0 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1757 : Object::ConvertReceiver(isolate, receiver),
1758 : Nothing<bool>());
1759 : }
1760 : PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1761 : *holder, should_throw);
1762 :
1763 : std::unique_ptr<v8::PropertyDescriptor> descriptor(
1764 96 : new v8::PropertyDescriptor());
1765 96 : if (PropertyDescriptor::IsAccessorDescriptor(&desc)) {
1766 : descriptor.reset(new v8::PropertyDescriptor(
1767 70 : v8::Utils::ToLocal(desc.get()), v8::Utils::ToLocal(desc.set())));
1768 61 : } else if (PropertyDescriptor::IsDataDescriptor(&desc)) {
1769 49 : if (desc.has_writable()) {
1770 : descriptor.reset(new v8::PropertyDescriptor(
1771 21 : v8::Utils::ToLocal(desc.value()), desc.writable()));
1772 : } else {
1773 : descriptor.reset(
1774 84 : new v8::PropertyDescriptor(v8::Utils::ToLocal(desc.value())));
1775 : }
1776 : }
1777 96 : if (desc.has_enumerable()) {
1778 14 : descriptor->set_enumerable(desc.enumerable());
1779 : }
1780 96 : if (desc.has_configurable()) {
1781 14 : descriptor->set_configurable(desc.configurable());
1782 : }
1783 :
1784 96 : if (it->IsElement()) {
1785 : uint32_t index = it->index();
1786 : v8::IndexedPropertyDefinerCallback definer =
1787 : v8::ToCData<v8::IndexedPropertyDefinerCallback>(interceptor->definer());
1788 54 : result = !args.Call(definer, index, *descriptor).is_null();
1789 : } else {
1790 69 : Handle<Name> name = it->name();
1791 : DCHECK(!name->IsPrivate());
1792 :
1793 : DCHECK_IMPLIES(name->IsSymbol(), interceptor->can_intercept_symbols());
1794 :
1795 : v8::GenericNamedPropertyDefinerCallback definer =
1796 : v8::ToCData<v8::GenericNamedPropertyDefinerCallback>(
1797 : interceptor->definer());
1798 138 : result = !args.Call(definer, name, *descriptor).is_null();
1799 : }
1800 :
1801 96 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1802 : return Just(result);
1803 : }
1804 :
1805 : } // namespace
1806 :
1807 1378 : MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
1808 1463 : LookupIterator* it) {
1809 : Isolate* isolate = it->isolate();
1810 1378 : Handle<JSObject> checked = it->GetHolder<JSObject>();
1811 : Handle<InterceptorInfo> interceptor =
1812 1378 : it->GetInterceptorForFailedAccessCheck();
1813 1378 : if (interceptor.is_null()) {
1814 1229 : while (AllCanRead(it)) {
1815 55 : if (it->state() == LookupIterator::ACCESSOR) {
1816 62 : return GetPropertyWithAccessor(it);
1817 : }
1818 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
1819 : bool done;
1820 : Handle<Object> result;
1821 72 : ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
1822 : GetPropertyWithInterceptor(it, &done), Object);
1823 36 : if (done) return result;
1824 : }
1825 :
1826 : } else {
1827 : Handle<Object> result;
1828 : bool done;
1829 399 : ASSIGN_RETURN_ON_EXCEPTION(
1830 : isolate, result,
1831 : GetPropertyWithInterceptorInternal(it, interceptor, &done), Object);
1832 147 : if (done) return result;
1833 : }
1834 :
1835 : // Cross-Origin [[Get]] of Well-Known Symbols does not throw, and returns
1836 : // undefined.
1837 1258 : Handle<Name> name = it->GetName();
1838 1294 : if (name->IsSymbol() && Symbol::cast(*name)->is_well_known_symbol()) {
1839 : return it->factory()->undefined_value();
1840 : }
1841 :
1842 1228 : isolate->ReportFailedAccessCheck(checked);
1843 1228 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1844 : return it->factory()->undefined_value();
1845 : }
1846 :
1847 :
1848 145 : Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
1849 157 : LookupIterator* it) {
1850 : Isolate* isolate = it->isolate();
1851 145 : Handle<JSObject> checked = it->GetHolder<JSObject>();
1852 : Handle<InterceptorInfo> interceptor =
1853 145 : it->GetInterceptorForFailedAccessCheck();
1854 145 : if (interceptor.is_null()) {
1855 145 : while (AllCanRead(it)) {
1856 12 : if (it->state() == LookupIterator::ACCESSOR) {
1857 : return Just(it->property_attributes());
1858 : }
1859 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
1860 0 : auto result = GetPropertyAttributesWithInterceptor(it);
1861 0 : if (isolate->has_scheduled_exception()) break;
1862 0 : if (result.IsJust() && result.FromJust() != ABSENT) return result;
1863 : }
1864 : } else {
1865 : Maybe<PropertyAttributes> result =
1866 0 : GetPropertyAttributesWithInterceptorInternal(it, interceptor);
1867 0 : if (isolate->has_pending_exception()) return Nothing<PropertyAttributes>();
1868 0 : if (result.FromMaybe(ABSENT) != ABSENT) return result;
1869 : }
1870 133 : isolate->ReportFailedAccessCheck(checked);
1871 133 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
1872 : return Just(ABSENT);
1873 : }
1874 :
1875 :
1876 : // static
1877 327 : bool JSObject::AllCanWrite(LookupIterator* it) {
1878 464 : for (; it->IsFound() && it->state() != LookupIterator::JSPROXY; it->Next()) {
1879 149 : if (it->state() == LookupIterator::ACCESSOR) {
1880 30 : Handle<Object> accessors = it->GetAccessors();
1881 30 : if (accessors->IsAccessorInfo()) {
1882 18 : if (AccessorInfo::cast(*accessors)->all_can_write()) return true;
1883 : }
1884 : }
1885 : }
1886 : return false;
1887 : }
1888 :
1889 :
1890 137 : Maybe<bool> JSObject::SetPropertyWithFailedAccessCheck(
1891 137 : LookupIterator* it, Handle<Object> value, ShouldThrow should_throw) {
1892 : Isolate* isolate = it->isolate();
1893 137 : Handle<JSObject> checked = it->GetHolder<JSObject>();
1894 : Handle<InterceptorInfo> interceptor =
1895 137 : it->GetInterceptorForFailedAccessCheck();
1896 137 : if (interceptor.is_null()) {
1897 95 : if (AllCanWrite(it)) {
1898 12 : return SetPropertyWithAccessor(it, value, should_throw);
1899 : }
1900 : } else {
1901 : Maybe<bool> result = SetPropertyWithInterceptorInternal(
1902 42 : it, interceptor, should_throw, value);
1903 84 : if (isolate->has_pending_exception()) return Nothing<bool>();
1904 28 : if (result.IsJust()) return result;
1905 : }
1906 83 : isolate->ReportFailedAccessCheck(checked);
1907 83 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1908 : return Just(true);
1909 : }
1910 :
1911 :
1912 406670 : void JSObject::SetNormalizedProperty(Handle<JSObject> object,
1913 : Handle<Name> name,
1914 : Handle<Object> value,
1915 : PropertyDetails details) {
1916 : DCHECK(!object->HasFastProperties());
1917 406670 : if (!name->IsUniqueName()) {
1918 : name = object->GetIsolate()->factory()->InternalizeString(
1919 0 : Handle<String>::cast(name));
1920 : }
1921 :
1922 406670 : if (object->IsJSGlobalObject()) {
1923 : Handle<GlobalDictionary> dictionary(object->global_dictionary());
1924 :
1925 9729 : int entry = dictionary->FindEntry(name);
1926 9729 : if (entry == GlobalDictionary::kNotFound) {
1927 : Isolate* isolate = object->GetIsolate();
1928 1150 : auto cell = isolate->factory()->NewPropertyCell();
1929 1150 : cell->set_value(*value);
1930 : auto cell_type = value->IsUndefined(isolate)
1931 : ? PropertyCellType::kUndefined
1932 1150 : : PropertyCellType::kConstant;
1933 : details = details.set_cell_type(cell_type);
1934 : value = cell;
1935 1150 : dictionary = GlobalDictionary::Add(dictionary, name, value, details);
1936 1150 : object->set_properties(*dictionary);
1937 : } else {
1938 : Handle<PropertyCell> cell =
1939 8579 : PropertyCell::PrepareForValue(dictionary, entry, value, details);
1940 8579 : cell->set_value(*value);
1941 : }
1942 : } else {
1943 : Handle<NameDictionary> dictionary(object->property_dictionary());
1944 :
1945 396941 : int entry = dictionary->FindEntry(name);
1946 396941 : if (entry == NameDictionary::kNotFound) {
1947 146262 : dictionary = NameDictionary::Add(dictionary, name, value, details);
1948 146262 : object->set_properties(*dictionary);
1949 : } else {
1950 : PropertyDetails original_details = dictionary->DetailsAt(entry);
1951 : int enumeration_index = original_details.dictionary_index();
1952 : DCHECK(enumeration_index > 0);
1953 : details = details.set_index(enumeration_index);
1954 : dictionary->SetEntry(entry, name, value, details);
1955 : }
1956 : }
1957 406670 : }
1958 :
1959 : // static
1960 2619 : Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate,
1961 : Handle<JSReceiver> object,
1962 : Handle<Object> proto) {
1963 2619 : PrototypeIterator iter(isolate, object, kStartAtReceiver);
1964 : while (true) {
1965 5804637 : if (!iter.AdvanceFollowingProxies()) return Nothing<bool>();
1966 5804468 : if (iter.IsAtEnd()) return Just(false);
1967 5803131 : if (PrototypeIterator::GetCurrent(iter).is_identical_to(proto)) {
1968 : return Just(true);
1969 : }
1970 : }
1971 : }
1972 :
1973 : namespace {
1974 :
1975 686 : bool HasExcludedProperty(
1976 : const ScopedVector<Handle<Object>>* excluded_properties,
1977 : Handle<Object> search_element) {
1978 : // TODO(gsathya): Change this to be a hashtable.
1979 2184 : for (int i = 0; i < excluded_properties->length(); i++) {
1980 1764 : if (search_element->SameValue(*excluded_properties->at(i))) {
1981 : return true;
1982 : }
1983 : }
1984 :
1985 : return false;
1986 : }
1987 :
1988 1306 : MUST_USE_RESULT Maybe<bool> FastAssign(
1989 : Handle<JSReceiver> target, Handle<Object> source,
1990 : const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) {
1991 : // Non-empty strings are the only non-JSReceivers that need to be handled
1992 : // explicitly by Object.assign.
1993 1306 : if (!source->IsJSReceiver()) {
1994 70 : return Just(!source->IsString() || String::cast(*source)->length() == 0);
1995 : }
1996 :
1997 : // If the target is deprecated, the object will be updated on first store. If
1998 : // the source for that store equals the target, this will invalidate the
1999 : // cached representation of the source. Preventively upgrade the target.
2000 : // Do this on each iteration since any property load could cause deprecation.
2001 1264 : if (target->map()->is_deprecated()) {
2002 30 : JSObject::MigrateInstance(Handle<JSObject>::cast(target));
2003 : }
2004 :
2005 : Isolate* isolate = target->GetIsolate();
2006 : Handle<Map> map(JSReceiver::cast(*source)->map(), isolate);
2007 :
2008 1264 : if (!map->IsJSObjectMap()) return Just(false);
2009 1124 : if (!map->OnlyHasSimpleProperties()) return Just(false);
2010 :
2011 : Handle<JSObject> from = Handle<JSObject>::cast(source);
2012 1011 : if (from->elements() != isolate->heap()->empty_fixed_array()) {
2013 : return Just(false);
2014 : }
2015 :
2016 : Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
2017 : int length = map->NumberOfOwnDescriptors();
2018 :
2019 : bool stable = true;
2020 :
2021 2071 : for (int i = 0; i < length; i++) {
2022 : Handle<Name> next_key(descriptors->GetKey(i), isolate);
2023 : Handle<Object> prop_value;
2024 : // Directly decode from the descriptor array if |from| did not change shape.
2025 1214 : if (stable) {
2026 1186 : PropertyDetails details = descriptors->GetDetails(i);
2027 1186 : if (!details.IsEnumerable()) continue;
2028 1068 : if (details.kind() == kData) {
2029 1068 : if (details.location() == kDescriptor) {
2030 0 : prop_value = handle(descriptors->GetValue(i), isolate);
2031 : } else {
2032 1068 : Representation representation = details.representation();
2033 1068 : FieldIndex index = FieldIndex::ForDescriptor(*map, i);
2034 1068 : prop_value = JSObject::FastPropertyAt(from, representation, index);
2035 : }
2036 : } else {
2037 0 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2038 : isolate, prop_value, JSReceiver::GetProperty(from, next_key),
2039 : Nothing<bool>());
2040 0 : stable = from->map() == *map;
2041 : }
2042 : } else {
2043 : // If the map did change, do a slower lookup. We are still guaranteed that
2044 : // the object has a simple shape, and that the key is a name.
2045 : LookupIterator it(from, next_key, from,
2046 28 : LookupIterator::OWN_SKIP_INTERCEPTOR);
2047 42 : if (!it.IsFound()) continue;
2048 : DCHECK(it.state() == LookupIterator::DATA ||
2049 : it.state() == LookupIterator::ACCESSOR);
2050 28 : if (!it.IsEnumerable()) continue;
2051 28 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2052 : isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
2053 : }
2054 :
2055 1082 : if (use_set) {
2056 284 : LookupIterator it(target, next_key, target);
2057 284 : bool call_to_js = it.IsFound() && it.state() != LookupIterator::DATA;
2058 : Maybe<bool> result = Object::SetProperty(
2059 284 : &it, prop_value, STRICT, Object::CERTAINLY_NOT_STORE_FROM_KEYED);
2060 284 : if (result.IsNothing()) return result;
2061 284 : if (stable && call_to_js) stable = from->map() == *map;
2062 : } else {
2063 2394 : if (excluded_properties != nullptr &&
2064 1694 : HasExcludedProperty(excluded_properties, next_key)) {
2065 154 : continue;
2066 : }
2067 :
2068 : // 4a ii 2. Perform ? CreateDataProperty(target, nextKey, propValue).
2069 : bool success;
2070 : LookupIterator it = LookupIterator::PropertyOrElement(
2071 644 : isolate, target, next_key, &success, LookupIterator::OWN);
2072 644 : CHECK(success);
2073 1288 : CHECK(
2074 : JSObject::CreateDataProperty(&it, prop_value, Object::THROW_ON_ERROR)
2075 : .FromJust());
2076 : }
2077 : }
2078 :
2079 : return Just(true);
2080 : }
2081 : } // namespace
2082 :
2083 : // static
2084 1306 : Maybe<bool> JSReceiver::SetOrCopyDataProperties(
2085 : Isolate* isolate, Handle<JSReceiver> target, Handle<Object> source,
2086 : const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) {
2087 : Maybe<bool> fast_assign =
2088 1306 : FastAssign(target, source, excluded_properties, use_set);
2089 1306 : if (fast_assign.IsNothing()) return Nothing<bool>();
2090 1264 : if (fast_assign.FromJust()) return Just(true);
2091 :
2092 786 : Handle<JSReceiver> from = Object::ToObject(isolate, source).ToHandleChecked();
2093 : // 3b. Let keys be ? from.[[OwnPropertyKeys]]().
2094 : Handle<FixedArray> keys;
2095 786 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2096 : isolate, keys,
2097 : KeyAccumulator::GetKeys(from, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES,
2098 : GetKeysConversion::kKeepNumbers),
2099 : Nothing<bool>());
2100 :
2101 : // 4. Repeat for each element nextKey of keys in List order,
2102 1403 : for (int j = 0; j < keys->length(); ++j) {
2103 : Handle<Object> next_key(keys->get(j), isolate);
2104 : // 4a i. Let desc be ? from.[[GetOwnProperty]](nextKey).
2105 : PropertyDescriptor desc;
2106 : Maybe<bool> found =
2107 589 : JSReceiver::GetOwnPropertyDescriptor(isolate, from, next_key, &desc);
2108 631 : if (found.IsNothing()) return Nothing<bool>();
2109 : // 4a ii. If desc is not undefined and desc.[[Enumerable]] is true, then
2110 1178 : if (found.FromJust() && desc.enumerable()) {
2111 : // 4a ii 1. Let propValue be ? Get(from, nextKey).
2112 : Handle<Object> prop_value;
2113 1108 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2114 : isolate, prop_value,
2115 : Runtime::GetObjectProperty(isolate, from, next_key), Nothing<bool>());
2116 :
2117 491 : if (use_set) {
2118 : // 4c ii 2. Let status be ? Set(to, nextKey, propValue, true).
2119 : Handle<Object> status;
2120 310 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2121 : isolate, status, Runtime::SetObjectProperty(
2122 : isolate, target, next_key, prop_value, STRICT),
2123 : Nothing<bool>());
2124 : } else {
2125 574 : if (excluded_properties != nullptr &&
2126 238 : HasExcludedProperty(excluded_properties, next_key)) {
2127 112 : continue;
2128 : }
2129 :
2130 : // 4a ii 2. Perform ! CreateDataProperty(target, nextKey, propValue).
2131 : bool success;
2132 : LookupIterator it = LookupIterator::PropertyOrElement(
2133 224 : isolate, target, next_key, &success, LookupIterator::OWN);
2134 224 : CHECK(success);
2135 448 : CHECK(JSObject::CreateDataProperty(&it, prop_value,
2136 : Object::THROW_ON_ERROR)
2137 : .FromJust());
2138 : }
2139 : }
2140 : }
2141 :
2142 : return Just(true);
2143 : }
2144 :
2145 280841 : Map* Object::GetPrototypeChainRootMap(Isolate* isolate) {
2146 : DisallowHeapAllocation no_alloc;
2147 250652 : if (IsSmi()) {
2148 : Context* native_context = isolate->context()->native_context();
2149 30189 : return native_context->number_function()->initial_map();
2150 : }
2151 :
2152 : // The object is either a number, a string, a symbol, a boolean, a real JS
2153 : // object, or a Harmony proxy.
2154 : HeapObject* heap_object = HeapObject::cast(this);
2155 220463 : return heap_object->map()->GetPrototypeChainRootMap(isolate);
2156 : }
2157 :
2158 9845703 : Map* Map::GetPrototypeChainRootMap(Isolate* isolate) {
2159 : DisallowHeapAllocation no_alloc;
2160 9471641 : if (IsJSReceiverMap()) {
2161 : return this;
2162 : }
2163 : int constructor_function_index = GetConstructorFunctionIndex();
2164 374076 : if (constructor_function_index != Map::kNoConstructorFunctionIndex) {
2165 : Context* native_context = isolate->context()->native_context();
2166 : JSFunction* constructor_function =
2167 : JSFunction::cast(native_context->get(constructor_function_index));
2168 374062 : return constructor_function->initial_map();
2169 : }
2170 28 : return isolate->heap()->null_value()->map();
2171 : }
2172 :
2173 : namespace {
2174 :
2175 : // Returns a non-SMI for JSObjects, but returns the hash code for simple
2176 : // objects. This avoids a double lookup in the cases where we know we will
2177 : // add the hash to the JSObject if it does not already exist.
2178 107529362 : Object* GetSimpleHash(Object* object) {
2179 : // The object is either a Smi, a HeapNumber, a name, an odd-ball, a real JS
2180 : // object, or a Harmony proxy.
2181 107529362 : if (object->IsSmi()) {
2182 : uint32_t hash =
2183 1079907 : ComputeIntegerHash(Smi::cast(object)->value(), kZeroHashSeed);
2184 2159814 : return Smi::FromInt(hash & Smi::kMaxValue);
2185 : }
2186 106449446 : if (object->IsHeapNumber()) {
2187 : double num = HeapNumber::cast(object)->value();
2188 8922 : if (std::isnan(num)) return Smi::FromInt(Smi::kMaxValue);
2189 8217 : if (i::IsMinusZero(num)) num = 0;
2190 8217 : if (IsSmiDouble(num)) {
2191 600 : return Smi::FromInt(FastD2I(num))->GetHash();
2192 : }
2193 : uint32_t hash = ComputeLongHash(double_to_uint64(num));
2194 15234 : return Smi::FromInt(hash & Smi::kMaxValue);
2195 : }
2196 106440497 : if (object->IsName()) {
2197 : uint32_t hash = Name::cast(object)->Hash();
2198 212831570 : return Smi::FromInt(hash);
2199 : }
2200 24711 : if (object->IsOddball()) {
2201 : uint32_t hash = Oddball::cast(object)->to_string()->Hash();
2202 4396 : return Smi::FromInt(hash);
2203 : }
2204 : DCHECK(object->IsJSReceiver());
2205 : // Simply return the receiver as it is guaranteed to not be a SMI.
2206 : return object;
2207 : }
2208 :
2209 : } // namespace
2210 :
2211 12997029 : Object* Object::GetHash() {
2212 12997029 : Object* hash = GetSimpleHash(this);
2213 12997029 : if (hash->IsSmi()) return hash;
2214 :
2215 : DisallowHeapAllocation no_gc;
2216 : DCHECK(IsJSReceiver());
2217 : JSReceiver* receiver = JSReceiver::cast(this);
2218 : Isolate* isolate = receiver->GetIsolate();
2219 16991 : return JSReceiver::GetIdentityHash(isolate, handle(receiver, isolate));
2220 : }
2221 :
2222 94532376 : Smi* Object::GetOrCreateHash(Isolate* isolate, Handle<Object> object) {
2223 94532376 : Object* hash = GetSimpleHash(*object);
2224 94532363 : if (hash->IsSmi()) return Smi::cast(hash);
2225 :
2226 : DCHECK(object->IsJSReceiver());
2227 : return JSReceiver::GetOrCreateIdentityHash(isolate,
2228 5522 : Handle<JSReceiver>::cast(object));
2229 : }
2230 :
2231 :
2232 1905731 : bool Object::SameValue(Object* other) {
2233 1905731 : if (other == this) return true;
2234 :
2235 : // The object is either a number, a name, an odd-ball,
2236 : // a real JS object, or a Harmony proxy.
2237 1582461 : if (IsNumber() && other->IsNumber()) {
2238 : double this_value = Number();
2239 : double other_value = other->Number();
2240 : // SameValue(NaN, NaN) is true.
2241 32466 : if (this_value != other_value) {
2242 29029 : return std::isnan(this_value) && std::isnan(other_value);
2243 : }
2244 : // SameValue(0.0, -0.0) is false.
2245 3437 : return (std::signbit(this_value) == std::signbit(other_value));
2246 : }
2247 2924237 : if (IsString() && other->IsString()) {
2248 1420101 : return String::cast(this)->Equals(String::cast(other));
2249 : }
2250 : return false;
2251 : }
2252 :
2253 :
2254 50532831 : bool Object::SameValueZero(Object* other) {
2255 50532831 : if (other == this) return true;
2256 :
2257 : // The object is either a number, a name, an odd-ball,
2258 : // a real JS object, or a Harmony proxy.
2259 50944557 : if (IsNumber() && other->IsNumber()) {
2260 : double this_value = Number();
2261 : double other_value = other->Number();
2262 : // +0 == -0 is true
2263 410323 : return this_value == other_value ||
2264 17 : (std::isnan(this_value) && std::isnan(other_value));
2265 : }
2266 100227673 : if (IsString() && other->IsString()) {
2267 50106467 : return String::cast(this)->Equals(String::cast(other));
2268 : }
2269 : return false;
2270 : }
2271 :
2272 :
2273 71717 : MaybeHandle<Object> Object::ArraySpeciesConstructor(
2274 : Isolate* isolate, Handle<Object> original_array) {
2275 71717 : Handle<Object> default_species = isolate->array_function();
2276 138366 : if (original_array->IsJSArray() &&
2277 203407 : Handle<JSArray>::cast(original_array)->HasArrayPrototype(isolate) &&
2278 : isolate->IsArraySpeciesLookupChainIntact()) {
2279 : return default_species;
2280 : }
2281 : Handle<Object> constructor = isolate->factory()->undefined_value();
2282 7541 : Maybe<bool> is_array = Object::IsArray(original_array);
2283 7541 : MAYBE_RETURN_NULL(is_array);
2284 7541 : if (is_array.FromJust()) {
2285 5088 : ASSIGN_RETURN_ON_EXCEPTION(
2286 : isolate, constructor,
2287 : Object::GetProperty(original_array,
2288 : isolate->factory()->constructor_string()),
2289 : Object);
2290 2530 : if (constructor->IsConstructor()) {
2291 : Handle<Context> constructor_context;
2292 4572 : ASSIGN_RETURN_ON_EXCEPTION(
2293 : isolate, constructor_context,
2294 : JSReceiver::GetFunctionRealm(Handle<JSReceiver>::cast(constructor)),
2295 : Object);
2296 4600 : if (*constructor_context != *isolate->native_context() &&
2297 : *constructor == constructor_context->array_function()) {
2298 : constructor = isolate->factory()->undefined_value();
2299 : }
2300 : }
2301 2530 : if (constructor->IsJSReceiver()) {
2302 4516 : ASSIGN_RETURN_ON_EXCEPTION(
2303 : isolate, constructor,
2304 : JSReceiver::GetProperty(Handle<JSReceiver>::cast(constructor),
2305 : isolate->factory()->species_symbol()),
2306 : Object);
2307 2244 : if (constructor->IsNull(isolate)) {
2308 : constructor = isolate->factory()->undefined_value();
2309 : }
2310 : }
2311 : }
2312 7513 : if (constructor->IsUndefined(isolate)) {
2313 : return default_species;
2314 : } else {
2315 2200 : if (!constructor->IsConstructor()) {
2316 0 : THROW_NEW_ERROR(isolate,
2317 : NewTypeError(MessageTemplate::kSpeciesNotConstructor),
2318 : Object);
2319 : }
2320 : return constructor;
2321 : }
2322 : }
2323 :
2324 : // ES6 section 7.3.20 SpeciesConstructor ( O, defaultConstructor )
2325 14360 : MUST_USE_RESULT MaybeHandle<Object> Object::SpeciesConstructor(
2326 : Isolate* isolate, Handle<JSReceiver> recv,
2327 : Handle<JSFunction> default_ctor) {
2328 : Handle<Object> ctor_obj;
2329 28720 : ASSIGN_RETURN_ON_EXCEPTION(
2330 : isolate, ctor_obj,
2331 : JSObject::GetProperty(recv, isolate->factory()->constructor_string()),
2332 : Object);
2333 :
2334 14360 : if (ctor_obj->IsUndefined(isolate)) return default_ctor;
2335 :
2336 14346 : if (!ctor_obj->IsJSReceiver()) {
2337 0 : THROW_NEW_ERROR(isolate,
2338 : NewTypeError(MessageTemplate::kConstructorNotReceiver),
2339 : Object);
2340 : }
2341 :
2342 14346 : Handle<JSReceiver> ctor = Handle<JSReceiver>::cast(ctor_obj);
2343 :
2344 : Handle<Object> species;
2345 28692 : ASSIGN_RETURN_ON_EXCEPTION(
2346 : isolate, species,
2347 : JSObject::GetProperty(ctor, isolate->factory()->species_symbol()),
2348 : Object);
2349 :
2350 14346 : if (species->IsNullOrUndefined(isolate)) {
2351 : return default_ctor;
2352 : }
2353 :
2354 14346 : if (species->IsConstructor()) return species;
2355 :
2356 0 : THROW_NEW_ERROR(
2357 : isolate, NewTypeError(MessageTemplate::kSpeciesNotConstructor), Object);
2358 : }
2359 :
2360 34034 : bool Object::IterationHasObservableEffects() {
2361 : // Check that this object is an array.
2362 34034 : if (!IsJSArray()) return true;
2363 : JSArray* array = JSArray::cast(this);
2364 : Isolate* isolate = array->GetIsolate();
2365 :
2366 : // Check that we have the original ArrayPrototype.
2367 34034 : if (!array->map()->prototype()->IsJSObject()) return true;
2368 : JSObject* array_proto = JSObject::cast(array->map()->prototype());
2369 34019 : if (!isolate->is_initial_array_prototype(array_proto)) return true;
2370 :
2371 : // Check that the ArrayPrototype hasn't been modified in a way that would
2372 : // affect iteration.
2373 34019 : if (!isolate->IsArrayIteratorLookupChainIntact()) return true;
2374 :
2375 : // Check that the map of the initial array iterator hasn't changed.
2376 65010 : Map* iterator_map = isolate->initial_array_iterator_prototype()->map();
2377 32505 : if (!isolate->is_initial_array_iterator_prototype_map(iterator_map)) {
2378 : return true;
2379 : }
2380 :
2381 : // For FastPacked kinds, iteration will have the same effect as simply
2382 : // accessing each property in order.
2383 : ElementsKind array_kind = array->GetElementsKind();
2384 32505 : if (IsFastPackedElementsKind(array_kind)) return false;
2385 :
2386 : // For FastHoley kinds, an element access on a hole would cause a lookup on
2387 : // the prototype. This could have different results if the prototype has been
2388 : // changed.
2389 11760 : if (IsFastHoleyElementsKind(array_kind) &&
2390 5880 : isolate->IsFastArrayConstructorPrototypeChainIntact()) {
2391 : return false;
2392 : }
2393 80 : return true;
2394 : }
2395 :
2396 14 : void Object::ShortPrint(FILE* out) {
2397 14 : OFStream os(out);
2398 14 : os << Brief(this);
2399 14 : }
2400 :
2401 :
2402 260 : void Object::ShortPrint(StringStream* accumulator) {
2403 260 : std::ostringstream os;
2404 260 : os << Brief(this);
2405 520 : accumulator->Add(os.str().c_str());
2406 260 : }
2407 :
2408 :
2409 0 : void Object::ShortPrint(std::ostream& os) { os << Brief(this); }
2410 :
2411 :
2412 1714 : std::ostream& operator<<(std::ostream& os, const Brief& v) {
2413 3428 : if (v.value->IsSmi()) {
2414 : Smi::cast(v.value)->SmiPrint(os);
2415 : } else {
2416 : // TODO(svenpanne) Const-correct HeapObjectShortPrint!
2417 : HeapObject* obj = const_cast<HeapObject*>(HeapObject::cast(v.value));
2418 1356 : obj->HeapObjectShortPrint(os);
2419 : }
2420 1714 : return os;
2421 : }
2422 :
2423 189 : void Smi::SmiPrint(std::ostream& os) const { // NOLINT
2424 547 : os << value();
2425 189 : }
2426 :
2427 6108049 : Handle<String> String::SlowFlatten(Handle<ConsString> cons,
2428 : PretenureFlag pretenure) {
2429 : DCHECK(cons->second()->length() != 0);
2430 :
2431 : // TurboFan can create cons strings with empty first parts.
2432 12216111 : while (cons->first()->length() == 0) {
2433 : // We do not want to call this function recursively. Therefore we call
2434 : // String::Flatten only in those cases where String::SlowFlatten is not
2435 : // called again.
2436 60 : if (cons->second()->IsConsString() && !cons->second()->IsFlat()) {
2437 : cons = handle(ConsString::cast(cons->second()));
2438 : } else {
2439 34 : return String::Flatten(handle(cons->second()));
2440 : }
2441 : }
2442 :
2443 : DCHECK(AllowHeapAllocation::IsAllowed());
2444 : Isolate* isolate = cons->GetIsolate();
2445 : int length = cons->length();
2446 : PretenureFlag tenure = isolate->heap()->InNewSpace(*cons) ? pretenure
2447 6108015 : : TENURED;
2448 : Handle<SeqString> result;
2449 6108015 : if (cons->IsOneByteRepresentation()) {
2450 : Handle<SeqOneByteString> flat = isolate->factory()->NewRawOneByteString(
2451 11743144 : length, tenure).ToHandleChecked();
2452 : DisallowHeapAllocation no_gc;
2453 11743144 : WriteToFlat(*cons, flat->GetChars(), 0, length);
2454 : result = flat;
2455 : } else {
2456 : Handle<SeqTwoByteString> flat = isolate->factory()->NewRawTwoByteString(
2457 472886 : length, tenure).ToHandleChecked();
2458 : DisallowHeapAllocation no_gc;
2459 472886 : WriteToFlat(*cons, flat->GetChars(), 0, length);
2460 : result = flat;
2461 : }
2462 6108015 : cons->set_first(*result);
2463 12216030 : cons->set_second(isolate->heap()->empty_string());
2464 : DCHECK(result->IsFlat());
2465 6108015 : return result;
2466 : }
2467 :
2468 :
2469 :
2470 468 : bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
2471 : // Externalizing twice leaks the external resource, so it's
2472 : // prohibited by the API.
2473 : DCHECK(!this->IsExternalString());
2474 : DCHECK(!resource->IsCompressible());
2475 : #ifdef ENABLE_SLOW_DCHECKS
2476 : if (FLAG_enable_slow_asserts) {
2477 : // Assert that the resource and the string are equivalent.
2478 : DCHECK(static_cast<size_t>(this->length()) == resource->length());
2479 : ScopedVector<uc16> smart_chars(this->length());
2480 : String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2481 : DCHECK(memcmp(smart_chars.start(),
2482 : resource->data(),
2483 : resource->length() * sizeof(smart_chars[0])) == 0);
2484 : }
2485 : #endif // DEBUG
2486 468 : int size = this->Size(); // Byte size of the original string.
2487 : // Abort if size does not allow in-place conversion.
2488 468 : if (size < ExternalString::kShortSize) return false;
2489 274 : Heap* heap = GetHeap();
2490 : bool is_one_byte = this->IsOneByteRepresentation();
2491 : bool is_internalized = this->IsInternalizedString();
2492 : bool has_pointers = StringShape(this).IsIndirect();
2493 :
2494 : // Morph the string to an external string by replacing the map and
2495 : // reinitializing the fields. This won't work if the space the existing
2496 : // string occupies is too small for a regular external string.
2497 : // Instead, we resort to a short external string instead, omitting
2498 : // the field caching the address of the backing store. When we encounter
2499 : // short external strings in generated code, we need to bailout to runtime.
2500 : Map* new_map;
2501 468 : if (size < ExternalString::kSize) {
2502 : new_map = is_internalized
2503 : ? (is_one_byte
2504 : ? heap->short_external_internalized_string_with_one_byte_data_map()
2505 : : heap->short_external_internalized_string_map())
2506 : : (is_one_byte ? heap->short_external_string_with_one_byte_data_map()
2507 327 : : heap->short_external_string_map());
2508 : } else {
2509 : new_map = is_internalized
2510 : ? (is_one_byte
2511 : ? heap->external_internalized_string_with_one_byte_data_map()
2512 : : heap->external_internalized_string_map())
2513 : : (is_one_byte ? heap->external_string_with_one_byte_data_map()
2514 543 : : heap->external_string_map());
2515 : }
2516 :
2517 : // Byte size of the external String object.
2518 468 : int new_size = this->SizeFromMap(new_map);
2519 468 : heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
2520 936 : ClearRecordedSlots::kNo);
2521 468 : if (has_pointers) {
2522 88 : heap->ClearRecordedSlotRange(this->address(), this->address() + new_size);
2523 : }
2524 :
2525 : // We are storing the new map using release store after creating a filler for
2526 : // the left-over space to avoid races with the sweeper thread.
2527 468 : this->synchronized_set_map(new_map);
2528 :
2529 : ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
2530 : self->set_resource(resource);
2531 468 : if (is_internalized) self->Hash(); // Force regeneration of the hash value.
2532 :
2533 468 : heap->AdjustLiveBytes(this, new_size - size);
2534 468 : return true;
2535 : }
2536 :
2537 :
2538 458 : bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
2539 : // Externalizing twice leaks the external resource, so it's
2540 : // prohibited by the API.
2541 : DCHECK(!this->IsExternalString());
2542 : DCHECK(!resource->IsCompressible());
2543 : #ifdef ENABLE_SLOW_DCHECKS
2544 : if (FLAG_enable_slow_asserts) {
2545 : // Assert that the resource and the string are equivalent.
2546 : DCHECK(static_cast<size_t>(this->length()) == resource->length());
2547 : if (this->IsTwoByteRepresentation()) {
2548 : ScopedVector<uint16_t> smart_chars(this->length());
2549 : String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2550 : DCHECK(String::IsOneByte(smart_chars.start(), this->length()));
2551 : }
2552 : ScopedVector<char> smart_chars(this->length());
2553 : String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2554 : DCHECK(memcmp(smart_chars.start(),
2555 : resource->data(),
2556 : resource->length() * sizeof(smart_chars[0])) == 0);
2557 : }
2558 : #endif // DEBUG
2559 458 : int size = this->Size(); // Byte size of the original string.
2560 : // Abort if size does not allow in-place conversion.
2561 458 : if (size < ExternalString::kShortSize) return false;
2562 52 : Heap* heap = GetHeap();
2563 : bool is_internalized = this->IsInternalizedString();
2564 : bool has_pointers = StringShape(this).IsIndirect();
2565 :
2566 : // Morph the string to an external string by replacing the map and
2567 : // reinitializing the fields. This won't work if the space the existing
2568 : // string occupies is too small for a regular external string.
2569 : // Instead, we resort to a short external string instead, omitting
2570 : // the field caching the address of the backing store. When we encounter
2571 : // short external strings in generated code, we need to bailout to runtime.
2572 : Map* new_map;
2573 458 : if (size < ExternalString::kSize) {
2574 : new_map = is_internalized
2575 : ? heap->short_external_one_byte_internalized_string_map()
2576 13 : : heap->short_external_one_byte_string_map();
2577 : } else {
2578 : new_map = is_internalized
2579 : ? heap->external_one_byte_internalized_string_map()
2580 445 : : heap->external_one_byte_string_map();
2581 : }
2582 :
2583 : // Byte size of the external String object.
2584 458 : int new_size = this->SizeFromMap(new_map);
2585 458 : heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
2586 916 : ClearRecordedSlots::kNo);
2587 458 : if (has_pointers) {
2588 396 : heap->ClearRecordedSlotRange(this->address(), this->address() + new_size);
2589 : }
2590 :
2591 : // We are storing the new map using release store after creating a filler for
2592 : // the left-over space to avoid races with the sweeper thread.
2593 458 : this->synchronized_set_map(new_map);
2594 :
2595 : ExternalOneByteString* self = ExternalOneByteString::cast(this);
2596 : self->set_resource(resource);
2597 458 : if (is_internalized) self->Hash(); // Force regeneration of the hash value.
2598 :
2599 458 : heap->AdjustLiveBytes(this, new_size - size);
2600 458 : return true;
2601 : }
2602 :
2603 94 : void String::StringShortPrint(StringStream* accumulator, bool show_details) {
2604 : int len = length();
2605 94 : if (len > kMaxShortPrintLength) {
2606 0 : accumulator->Add("<Very long string[%u]>", len);
2607 0 : return;
2608 : }
2609 :
2610 94 : if (!LooksValid()) {
2611 0 : accumulator->Add("<Invalid String>");
2612 0 : return;
2613 : }
2614 :
2615 : StringCharacterStream stream(this);
2616 :
2617 : bool truncated = false;
2618 94 : if (len > kMaxShortPrintLength) {
2619 : len = kMaxShortPrintLength;
2620 : truncated = true;
2621 : }
2622 : bool one_byte = true;
2623 782 : for (int i = 0; i < len; i++) {
2624 688 : uint16_t c = stream.GetNext();
2625 :
2626 688 : if (c < 32 || c >= 127) {
2627 : one_byte = false;
2628 : }
2629 : }
2630 94 : stream.Reset(this);
2631 94 : if (one_byte) {
2632 171 : if (show_details) accumulator->Add("<String[%u]: ", length());
2633 688 : for (int i = 0; i < len; i++) {
2634 688 : accumulator->Put(static_cast<char>(stream.GetNext()));
2635 : }
2636 94 : if (show_details) accumulator->Put('>');
2637 : } else {
2638 : // Backslash indicates that the string contains control
2639 : // characters and that backslashes are therefore escaped.
2640 0 : if (show_details) accumulator->Add("<String[%u]\\: ", length());
2641 0 : for (int i = 0; i < len; i++) {
2642 0 : uint16_t c = stream.GetNext();
2643 0 : if (c == '\n') {
2644 0 : accumulator->Add("\\n");
2645 0 : } else if (c == '\r') {
2646 0 : accumulator->Add("\\r");
2647 0 : } else if (c == '\\') {
2648 0 : accumulator->Add("\\\\");
2649 0 : } else if (c < 32 || c > 126) {
2650 0 : accumulator->Add("\\x%02x", c);
2651 : } else {
2652 0 : accumulator->Put(static_cast<char>(c));
2653 : }
2654 : }
2655 0 : if (truncated) {
2656 0 : accumulator->Put('.');
2657 0 : accumulator->Put('.');
2658 0 : accumulator->Put('.');
2659 : }
2660 0 : if (show_details) accumulator->Put('>');
2661 : }
2662 : return;
2663 : }
2664 :
2665 :
2666 28 : void String::PrintUC16(std::ostream& os, int start, int end) { // NOLINT
2667 28 : if (end < 0) end = length();
2668 : StringCharacterStream stream(this, start);
2669 560 : for (int i = start; i < end && stream.HasMore(); i++) {
2670 1064 : os << AsUC16(stream.GetNext());
2671 : }
2672 28 : }
2673 :
2674 :
2675 840 : void JSObject::JSObjectShortPrint(StringStream* accumulator) {
2676 840 : switch (map()->instance_type()) {
2677 : case JS_ARRAY_TYPE: {
2678 : double length = JSArray::cast(this)->length()->IsUndefined(GetIsolate())
2679 : ? 0
2680 201 : : JSArray::cast(this)->length()->Number();
2681 201 : accumulator->Add("<JSArray[%u]>", static_cast<uint32_t>(length));
2682 201 : break;
2683 : }
2684 : case JS_BOUND_FUNCTION_TYPE: {
2685 : JSBoundFunction* bound_function = JSBoundFunction::cast(this);
2686 0 : accumulator->Add("<JSBoundFunction");
2687 : accumulator->Add(
2688 : " (BoundTargetFunction %p)>",
2689 0 : reinterpret_cast<void*>(bound_function->bound_target_function()));
2690 0 : break;
2691 : }
2692 : case JS_WEAK_MAP_TYPE: {
2693 0 : accumulator->Add("<JSWeakMap>");
2694 0 : break;
2695 : }
2696 : case JS_WEAK_SET_TYPE: {
2697 0 : accumulator->Add("<JSWeakSet>");
2698 0 : break;
2699 : }
2700 : case JS_REGEXP_TYPE: {
2701 30 : accumulator->Add("<JSRegExp");
2702 : JSRegExp* regexp = JSRegExp::cast(this);
2703 30 : if (regexp->source()->IsString()) {
2704 30 : accumulator->Add(" ");
2705 30 : String::cast(regexp->source())->StringShortPrint(accumulator);
2706 : }
2707 30 : accumulator->Add(">");
2708 :
2709 30 : break;
2710 : }
2711 : case JS_FUNCTION_TYPE: {
2712 : JSFunction* function = JSFunction::cast(this);
2713 73 : Object* fun_name = function->shared()->DebugName();
2714 : bool printed = false;
2715 73 : if (fun_name->IsString()) {
2716 : String* str = String::cast(fun_name);
2717 73 : if (str->length() > 0) {
2718 73 : accumulator->Add("<JSFunction ");
2719 73 : accumulator->Put(str);
2720 : printed = true;
2721 : }
2722 : }
2723 73 : if (!printed) {
2724 0 : accumulator->Add("<JSFunction");
2725 : }
2726 73 : if (FLAG_trace_file_names) {
2727 : Object* source_name =
2728 : Script::cast(function->shared()->script())->name();
2729 0 : if (source_name->IsString()) {
2730 : String* str = String::cast(source_name);
2731 0 : if (str->length() > 0) {
2732 0 : accumulator->Add(" <");
2733 0 : accumulator->Put(str);
2734 0 : accumulator->Add(">");
2735 : }
2736 : }
2737 : }
2738 : accumulator->Add(" (sfi = %p)",
2739 73 : reinterpret_cast<void*>(function->shared()));
2740 73 : accumulator->Put('>');
2741 73 : break;
2742 : }
2743 : case JS_GENERATOR_OBJECT_TYPE: {
2744 0 : accumulator->Add("<JSGenerator>");
2745 0 : break;
2746 : }
2747 : case JS_ASYNC_GENERATOR_OBJECT_TYPE: {
2748 0 : accumulator->Add("<JS AsyncGenerator>");
2749 0 : break;
2750 : }
2751 :
2752 : // All other JSObjects are rather similar to each other (JSObject,
2753 : // JSGlobalProxy, JSGlobalObject, JSUndetectable, JSValue).
2754 : default: {
2755 : Map* map_of_this = map();
2756 : Heap* heap = GetHeap();
2757 536 : Object* constructor = map_of_this->GetConstructor();
2758 : bool printed = false;
2759 1072 : if (constructor->IsHeapObject() &&
2760 536 : !heap->Contains(HeapObject::cast(constructor))) {
2761 0 : accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
2762 : } else {
2763 : bool global_object = IsJSGlobalProxy();
2764 536 : if (constructor->IsJSFunction()) {
2765 536 : if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
2766 0 : accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
2767 : } else {
2768 : Object* constructor_name =
2769 : JSFunction::cast(constructor)->shared()->name();
2770 536 : if (constructor_name->IsString()) {
2771 : String* str = String::cast(constructor_name);
2772 536 : if (str->length() > 0) {
2773 472 : accumulator->Add(global_object ? "<GlobalObject " : "<");
2774 472 : accumulator->Put(str);
2775 : accumulator->Add(
2776 : " %smap = %p",
2777 : map_of_this->is_deprecated() ? "deprecated-" : "",
2778 472 : map_of_this);
2779 : printed = true;
2780 : }
2781 : }
2782 : }
2783 0 : } else if (constructor->IsFunctionTemplateInfo()) {
2784 0 : accumulator->Add(global_object ? "<RemoteObject>" : "<RemoteObject>");
2785 : printed = true;
2786 : }
2787 536 : if (!printed) {
2788 64 : accumulator->Add("<JS%sObject", global_object ? "Global " : "");
2789 : }
2790 : }
2791 536 : if (IsJSValue()) {
2792 15 : accumulator->Add(" value = ");
2793 15 : JSValue::cast(this)->value()->ShortPrint(accumulator);
2794 : }
2795 536 : accumulator->Put('>');
2796 536 : break;
2797 : }
2798 : }
2799 840 : }
2800 :
2801 :
2802 0 : void JSObject::PrintElementsTransition(
2803 : FILE* file, Handle<JSObject> object,
2804 : ElementsKind from_kind, Handle<FixedArrayBase> from_elements,
2805 : ElementsKind to_kind, Handle<FixedArrayBase> to_elements) {
2806 0 : if (from_kind != to_kind) {
2807 0 : OFStream os(file);
2808 0 : os << "elements transition [" << ElementsKindToString(from_kind) << " -> "
2809 0 : << ElementsKindToString(to_kind) << "] in ";
2810 0 : JavaScriptFrame::PrintTop(object->GetIsolate(), file, false, true);
2811 0 : PrintF(file, " for ");
2812 0 : object->ShortPrint(file);
2813 0 : PrintF(file, " from ");
2814 0 : from_elements->ShortPrint(file);
2815 0 : PrintF(file, " to ");
2816 0 : to_elements->ShortPrint(file);
2817 0 : PrintF(file, "\n");
2818 : }
2819 0 : }
2820 :
2821 :
2822 : // static
2823 213145 : MaybeHandle<JSFunction> Map::GetConstructorFunction(
2824 : Handle<Map> map, Handle<Context> native_context) {
2825 213145 : if (map->IsPrimitiveMap()) {
2826 : int const constructor_function_index = map->GetConstructorFunctionIndex();
2827 36003 : if (constructor_function_index != kNoConstructorFunctionIndex) {
2828 : return handle(
2829 : JSFunction::cast(native_context->get(constructor_function_index)));
2830 : }
2831 : }
2832 : return MaybeHandle<JSFunction>();
2833 : }
2834 :
2835 :
2836 0 : void Map::PrintReconfiguration(FILE* file, int modify_index, PropertyKind kind,
2837 : PropertyAttributes attributes) {
2838 0 : OFStream os(file);
2839 0 : os << "[reconfiguring]";
2840 : Name* name = instance_descriptors()->GetKey(modify_index);
2841 0 : if (name->IsString()) {
2842 0 : String::cast(name)->PrintOn(file);
2843 : } else {
2844 0 : os << "{symbol " << static_cast<void*>(name) << "}";
2845 : }
2846 0 : os << ": " << (kind == kData ? "kData" : "ACCESSORS") << ", attrs: ";
2847 0 : os << attributes << " [";
2848 0 : JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
2849 0 : os << "]\n";
2850 0 : }
2851 :
2852 0 : void Map::PrintGeneralization(
2853 : FILE* file, const char* reason, int modify_index, int split,
2854 : int descriptors, bool descriptor_to_field,
2855 : Representation old_representation, Representation new_representation,
2856 : MaybeHandle<FieldType> old_field_type, MaybeHandle<Object> old_value,
2857 : MaybeHandle<FieldType> new_field_type, MaybeHandle<Object> new_value) {
2858 0 : OFStream os(file);
2859 0 : os << "[generalizing]";
2860 : Name* name = instance_descriptors()->GetKey(modify_index);
2861 0 : if (name->IsString()) {
2862 0 : String::cast(name)->PrintOn(file);
2863 : } else {
2864 0 : os << "{symbol " << static_cast<void*>(name) << "}";
2865 : }
2866 0 : os << ":";
2867 0 : if (descriptor_to_field) {
2868 0 : os << "c";
2869 : } else {
2870 0 : os << old_representation.Mnemonic() << "{";
2871 0 : if (old_field_type.is_null()) {
2872 0 : os << Brief(*(old_value.ToHandleChecked()));
2873 : } else {
2874 0 : old_field_type.ToHandleChecked()->PrintTo(os);
2875 : }
2876 0 : os << "}";
2877 : }
2878 0 : os << "->" << new_representation.Mnemonic() << "{";
2879 0 : if (new_field_type.is_null()) {
2880 0 : os << Brief(*(new_value.ToHandleChecked()));
2881 : } else {
2882 0 : new_field_type.ToHandleChecked()->PrintTo(os);
2883 : }
2884 0 : os << "} (";
2885 0 : if (strlen(reason) > 0) {
2886 0 : os << reason;
2887 : } else {
2888 0 : os << "+" << (descriptors - split) << " maps";
2889 : }
2890 0 : os << ") [";
2891 0 : JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
2892 0 : os << "]\n";
2893 0 : }
2894 :
2895 :
2896 0 : void JSObject::PrintInstanceMigration(FILE* file,
2897 : Map* original_map,
2898 : Map* new_map) {
2899 0 : if (new_map->is_dictionary_map()) {
2900 0 : PrintF(file, "[migrating to slow]\n");
2901 0 : return;
2902 : }
2903 0 : PrintF(file, "[migrating]");
2904 : DescriptorArray* o = original_map->instance_descriptors();
2905 : DescriptorArray* n = new_map->instance_descriptors();
2906 0 : for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) {
2907 0 : Representation o_r = o->GetDetails(i).representation();
2908 0 : Representation n_r = n->GetDetails(i).representation();
2909 0 : if (!o_r.Equals(n_r)) {
2910 0 : String::cast(o->GetKey(i))->PrintOn(file);
2911 0 : PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic());
2912 0 : } else if (o->GetDetails(i).location() == kDescriptor &&
2913 0 : n->GetDetails(i).location() == kField) {
2914 : Name* name = o->GetKey(i);
2915 0 : if (name->IsString()) {
2916 0 : String::cast(name)->PrintOn(file);
2917 : } else {
2918 0 : PrintF(file, "{symbol %p}", static_cast<void*>(name));
2919 : }
2920 0 : PrintF(file, " ");
2921 : }
2922 : }
2923 0 : if (original_map->elements_kind() != new_map->elements_kind()) {
2924 : PrintF(file, "elements_kind[%i->%i]", original_map->elements_kind(),
2925 0 : new_map->elements_kind());
2926 : }
2927 0 : PrintF(file, "\n");
2928 : }
2929 :
2930 :
2931 1356 : void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
2932 : Heap* heap = GetHeap();
2933 : Isolate* isolate = heap->isolate();
2934 1356 : if (!heap->Contains(this)) {
2935 0 : os << "!!!INVALID POINTER!!!";
2936 0 : return;
2937 : }
2938 1356 : if (!heap->Contains(map())) {
2939 0 : os << "!!!INVALID MAP!!!";
2940 0 : return;
2941 : }
2942 :
2943 1356 : os << this << " ";
2944 :
2945 1356 : if (IsString()) {
2946 : HeapStringAllocator allocator;
2947 : StringStream accumulator(&allocator);
2948 47 : String::cast(this)->StringShortPrint(&accumulator);
2949 141 : os << accumulator.ToCString().get();
2950 : return;
2951 : }
2952 1309 : if (IsJSObject()) {
2953 : HeapStringAllocator allocator;
2954 : StringStream accumulator(&allocator);
2955 840 : JSObject::cast(this)->JSObjectShortPrint(&accumulator);
2956 2520 : os << accumulator.ToCString().get();
2957 : return;
2958 : }
2959 469 : switch (map()->instance_type()) {
2960 : case MAP_TYPE:
2961 0 : os << "<Map(" << ElementsKindToString(Map::cast(this)->elements_kind())
2962 0 : << ")>";
2963 0 : break;
2964 : case FIXED_ARRAY_TYPE:
2965 0 : os << "<FixedArray[" << FixedArray::cast(this)->length() << "]>";
2966 0 : break;
2967 : case FIXED_DOUBLE_ARRAY_TYPE:
2968 0 : os << "<FixedDoubleArray[" << FixedDoubleArray::cast(this)->length()
2969 0 : << "]>";
2970 0 : break;
2971 : case BYTE_ARRAY_TYPE:
2972 0 : os << "<ByteArray[" << ByteArray::cast(this)->length() << "]>";
2973 0 : break;
2974 : case BYTECODE_ARRAY_TYPE:
2975 0 : os << "<BytecodeArray[" << BytecodeArray::cast(this)->length() << "]>";
2976 0 : break;
2977 : case TRANSITION_ARRAY_TYPE:
2978 0 : os << "<TransitionArray[" << TransitionArray::cast(this)->length()
2979 0 : << "]>";
2980 0 : break;
2981 : case FREE_SPACE_TYPE:
2982 0 : os << "<FreeSpace[" << FreeSpace::cast(this)->size() << "]>";
2983 0 : break;
2984 : #define TYPED_ARRAY_SHORT_PRINT(Type, type, TYPE, ctype, size) \
2985 : case FIXED_##TYPE##_ARRAY_TYPE: \
2986 : os << "<Fixed" #Type "Array[" << Fixed##Type##Array::cast(this)->length() \
2987 : << "]>"; \
2988 : break;
2989 :
2990 0 : TYPED_ARRAYS(TYPED_ARRAY_SHORT_PRINT)
2991 : #undef TYPED_ARRAY_SHORT_PRINT
2992 :
2993 : case SHARED_FUNCTION_INFO_TYPE: {
2994 : SharedFunctionInfo* shared = SharedFunctionInfo::cast(this);
2995 0 : std::unique_ptr<char[]> debug_name = shared->DebugName()->ToCString();
2996 0 : if (debug_name[0] != 0) {
2997 0 : os << "<SharedFunctionInfo " << debug_name.get() << ">";
2998 : } else {
2999 0 : os << "<SharedFunctionInfo>";
3000 : }
3001 : break;
3002 : }
3003 : case JS_MESSAGE_OBJECT_TYPE:
3004 0 : os << "<JSMessageObject>";
3005 0 : break;
3006 : #define MAKE_STRUCT_CASE(NAME, Name, name) \
3007 : case NAME##_TYPE: \
3008 : os << "<" #Name ">"; \
3009 : break;
3010 0 : STRUCT_LIST(MAKE_STRUCT_CASE)
3011 : #undef MAKE_STRUCT_CASE
3012 : case CODE_TYPE: {
3013 : Code* code = Code::cast(this);
3014 0 : os << "<Code " << Code::Kind2String(code->kind()) << ">";
3015 0 : break;
3016 : }
3017 : case ODDBALL_TYPE: {
3018 122 : if (IsUndefined(isolate)) {
3019 75 : os << "<undefined>";
3020 47 : } else if (IsTheHole(isolate)) {
3021 0 : os << "<the_hole>";
3022 47 : } else if (IsNull(isolate)) {
3023 17 : os << "<null>";
3024 30 : } else if (IsTrue(isolate)) {
3025 15 : os << "<true>";
3026 15 : } else if (IsFalse(isolate)) {
3027 15 : os << "<false>";
3028 : } else {
3029 0 : os << "<Odd Oddball: ";
3030 0 : os << Oddball::cast(this)->to_string()->ToCString().get();
3031 0 : os << ">";
3032 : }
3033 : break;
3034 : }
3035 : case SYMBOL_TYPE: {
3036 : Symbol* symbol = Symbol::cast(this);
3037 227 : symbol->SymbolShortPrint(os);
3038 227 : break;
3039 : }
3040 : case HEAP_NUMBER_TYPE: {
3041 105 : os << "<Number ";
3042 : HeapNumber::cast(this)->HeapNumberPrint(os);
3043 105 : os << ">";
3044 105 : break;
3045 : }
3046 : case MUTABLE_HEAP_NUMBER_TYPE: {
3047 0 : os << "<MutableNumber ";
3048 : HeapNumber::cast(this)->HeapNumberPrint(os);
3049 : os << '>';
3050 : break;
3051 : }
3052 : case JS_PROXY_TYPE:
3053 15 : os << "<JSProxy>";
3054 15 : break;
3055 : case FOREIGN_TYPE:
3056 0 : os << "<Foreign>";
3057 0 : break;
3058 : case CELL_TYPE: {
3059 0 : os << "<Cell value= ";
3060 : HeapStringAllocator allocator;
3061 : StringStream accumulator(&allocator);
3062 0 : Cell::cast(this)->value()->ShortPrint(&accumulator);
3063 0 : os << accumulator.ToCString().get();
3064 : os << '>';
3065 : break;
3066 : }
3067 : case PROPERTY_CELL_TYPE: {
3068 0 : os << "<PropertyCell value=";
3069 : HeapStringAllocator allocator;
3070 : StringStream accumulator(&allocator);
3071 : PropertyCell* cell = PropertyCell::cast(this);
3072 0 : cell->value()->ShortPrint(&accumulator);
3073 0 : os << accumulator.ToCString().get();
3074 : os << '>';
3075 : break;
3076 : }
3077 : case WEAK_CELL_TYPE: {
3078 0 : os << "<WeakCell value= ";
3079 : HeapStringAllocator allocator;
3080 : StringStream accumulator(&allocator);
3081 0 : WeakCell::cast(this)->value()->ShortPrint(&accumulator);
3082 0 : os << accumulator.ToCString().get();
3083 : os << '>';
3084 : break;
3085 : }
3086 : default:
3087 0 : os << "<Other heap object (" << map()->instance_type() << ")>";
3088 0 : break;
3089 : }
3090 : }
3091 :
3092 :
3093 33403765 : void HeapObject::Iterate(ObjectVisitor* v) { IterateFast<ObjectVisitor>(v); }
3094 :
3095 :
3096 681 : void HeapObject::IterateBody(ObjectVisitor* v) {
3097 : Map* m = map();
3098 681 : IterateBodyFast<ObjectVisitor>(m->instance_type(), SizeFromMap(m), v);
3099 681 : }
3100 :
3101 :
3102 52411275 : void HeapObject::IterateBody(InstanceType type, int object_size,
3103 : ObjectVisitor* v) {
3104 : IterateBodyFast<ObjectVisitor>(type, object_size, v);
3105 52413359 : }
3106 :
3107 :
3108 : struct CallIsValidSlot {
3109 : template <typename BodyDescriptor>
3110 : static bool apply(HeapObject* obj, int offset, int) {
3111 : return BodyDescriptor::IsValidSlot(obj, offset);
3112 : }
3113 : };
3114 :
3115 :
3116 0 : bool HeapObject::IsValidSlot(int offset) {
3117 : DCHECK_NE(0, offset);
3118 : return BodyDescriptorApply<CallIsValidSlot, bool>(map()->instance_type(),
3119 0 : this, offset, 0);
3120 : }
3121 :
3122 :
3123 0 : bool HeapNumber::HeapNumberBooleanValue() {
3124 65455 : return DoubleToBoolean(value());
3125 : }
3126 :
3127 :
3128 16569 : void HeapNumber::HeapNumberPrint(std::ostream& os) { // NOLINT
3129 : os << value();
3130 16569 : }
3131 :
3132 :
3133 : #define FIELD_ADDR_CONST(p, offset) \
3134 : (reinterpret_cast<const byte*>(p) + offset - kHeapObjectTag)
3135 :
3136 : #define READ_INT32_FIELD(p, offset) \
3137 : (*reinterpret_cast<const int32_t*>(FIELD_ADDR_CONST(p, offset)))
3138 :
3139 : #define READ_INT64_FIELD(p, offset) \
3140 : (*reinterpret_cast<const int64_t*>(FIELD_ADDR_CONST(p, offset)))
3141 :
3142 : #define READ_BYTE_FIELD(p, offset) \
3143 : (*reinterpret_cast<const byte*>(FIELD_ADDR_CONST(p, offset)))
3144 :
3145 65530334 : String* JSReceiver::class_name() {
3146 65530334 : if (IsFunction()) {
3147 31014906 : return GetHeap()->Function_string();
3148 : }
3149 34515428 : Object* maybe_constructor = map()->GetConstructor();
3150 34515428 : if (maybe_constructor->IsJSFunction()) {
3151 : JSFunction* constructor = JSFunction::cast(maybe_constructor);
3152 34515361 : return String::cast(constructor->shared()->instance_class_name());
3153 67 : } else if (maybe_constructor->IsFunctionTemplateInfo()) {
3154 : FunctionTemplateInfo* info = FunctionTemplateInfo::cast(maybe_constructor);
3155 : return info->class_name()->IsString() ? String::cast(info->class_name())
3156 1 : : GetHeap()->empty_string();
3157 : }
3158 :
3159 : // If the constructor is not present, return "Object".
3160 66 : return GetHeap()->Object_string();
3161 : }
3162 :
3163 :
3164 : // static
3165 7689049 : Handle<String> JSReceiver::GetConstructorName(Handle<JSReceiver> receiver) {
3166 : Isolate* isolate = receiver->GetIsolate();
3167 :
3168 : // If the object was instantiated simply with base == new.target, the
3169 : // constructor on the map provides the most accurate name.
3170 : // Don't provide the info for prototypes, since their constructors are
3171 : // reclaimed and replaced by Object in OptimizeAsPrototype.
3172 23066402 : if (!receiver->IsJSProxy() && receiver->map()->new_target_is_base() &&
3173 : !receiver->map()->is_prototype_map()) {
3174 7470957 : Object* maybe_constructor = receiver->map()->GetConstructor();
3175 7470957 : if (maybe_constructor->IsJSFunction()) {
3176 : JSFunction* constructor = JSFunction::cast(maybe_constructor);
3177 : String* name = String::cast(constructor->shared()->name());
3178 5035420 : if (name->length() == 0) name = constructor->shared()->inferred_name();
3179 9333199 : if (name->length() != 0 &&
3180 4297779 : !name->Equals(isolate->heap()->Object_string())) {
3181 : return handle(name, isolate);
3182 : }
3183 2435537 : } else if (maybe_constructor->IsFunctionTemplateInfo()) {
3184 : FunctionTemplateInfo* info =
3185 : FunctionTemplateInfo::cast(maybe_constructor);
3186 0 : if (info->class_name()->IsString()) {
3187 : return handle(String::cast(info->class_name()), isolate);
3188 : }
3189 : }
3190 : }
3191 :
3192 : Handle<Object> maybe_tag = JSReceiver::GetDataProperty(
3193 4363353 : receiver, isolate->factory()->to_string_tag_symbol());
3194 4363353 : if (maybe_tag->IsString()) return Handle<String>::cast(maybe_tag);
3195 :
3196 3648871 : PrototypeIterator iter(isolate, receiver);
3197 4272896 : if (iter.IsAtEnd()) return handle(receiver->class_name());
3198 3024846 : Handle<JSReceiver> start = PrototypeIterator::GetCurrent<JSReceiver>(iter);
3199 : LookupIterator it(receiver, isolate->factory()->constructor_string(), start,
3200 3024846 : LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
3201 3024846 : Handle<Object> maybe_constructor = JSReceiver::GetDataProperty(&it);
3202 : Handle<String> result = isolate->factory()->Object_string();
3203 3024846 : if (maybe_constructor->IsJSFunction()) {
3204 : JSFunction* constructor = JSFunction::cast(*maybe_constructor);
3205 : String* name = String::cast(constructor->shared()->name());
3206 3024732 : if (name->length() == 0) name = constructor->shared()->inferred_name();
3207 3024732 : if (name->length() > 0) result = handle(name, isolate);
3208 : }
3209 :
3210 : return result.is_identical_to(isolate->factory()->Object_string())
3211 476079 : ? handle(receiver->class_name())
3212 5573613 : : result;
3213 : }
3214 :
3215 491 : Handle<Context> JSReceiver::GetCreationContext() {
3216 : JSReceiver* receiver = this;
3217 996 : while (receiver->IsJSBoundFunction()) {
3218 : receiver = JSBoundFunction::cast(receiver)->bound_target_function();
3219 : }
3220 491 : Object* constructor = receiver->map()->GetConstructor();
3221 : JSFunction* function;
3222 491 : if (constructor->IsJSFunction()) {
3223 : function = JSFunction::cast(constructor);
3224 14 : } else if (constructor->IsFunctionTemplateInfo()) {
3225 : // Remote objects don't have a creation context.
3226 2 : return Handle<Context>::null();
3227 : } else {
3228 : // Functions have null as a constructor,
3229 : // but any JSFunction knows its context immediately.
3230 12 : CHECK(receiver->IsJSFunction());
3231 : function = JSFunction::cast(receiver);
3232 : }
3233 :
3234 489 : return function->has_context()
3235 : ? Handle<Context>(function->context()->native_context())
3236 489 : : Handle<Context>::null();
3237 : }
3238 :
3239 9704147 : Handle<Object> Map::WrapFieldType(Handle<FieldType> type) {
3240 10964109 : if (type->IsClass()) return Map::WeakCellForMap(type->AsClass());
3241 8444186 : return type;
3242 : }
3243 :
3244 67458763 : FieldType* Map::UnwrapFieldType(Object* wrapped_type) {
3245 : Object* value = wrapped_type;
3246 67458763 : if (value->IsWeakCell()) {
3247 9716587 : if (WeakCell::cast(value)->cleared()) return FieldType::None();
3248 : value = WeakCell::cast(value)->value();
3249 : }
3250 67458649 : return FieldType::cast(value);
3251 : }
3252 :
3253 8779738 : MaybeHandle<Map> Map::CopyWithField(Handle<Map> map, Handle<Name> name,
3254 : Handle<FieldType> type,
3255 : PropertyAttributes attributes,
3256 : PropertyConstness constness,
3257 : Representation representation,
3258 : TransitionFlag flag) {
3259 : DCHECK(DescriptorArray::kNotFound ==
3260 : map->instance_descriptors()->Search(
3261 : *name, map->NumberOfOwnDescriptors()));
3262 :
3263 : // Ensure the descriptor array does not get too big.
3264 8779738 : if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
3265 : return MaybeHandle<Map>();
3266 : }
3267 :
3268 : Isolate* isolate = map->GetIsolate();
3269 :
3270 : // Compute the new index for new field.
3271 8779621 : int index = map->NextFreePropertyIndex();
3272 :
3273 8779623 : if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
3274 4197 : representation = Representation::Tagged();
3275 4197 : type = FieldType::Any(isolate);
3276 : }
3277 :
3278 8779623 : Handle<Object> wrapped_type(WrapFieldType(type));
3279 :
3280 : DCHECK_IMPLIES(!FLAG_track_constant_fields, constness == kMutable);
3281 : Descriptor d = Descriptor::DataField(name, index, attributes, constness,
3282 8779623 : representation, wrapped_type);
3283 8779623 : Handle<Map> new_map = Map::CopyAddDescriptor(map, &d, flag);
3284 8779625 : int unused_property_fields = new_map->unused_property_fields() - 1;
3285 8779625 : if (unused_property_fields < 0) {
3286 2328805 : unused_property_fields += JSObject::kFieldsAdded;
3287 : }
3288 : new_map->set_unused_property_fields(unused_property_fields);
3289 : return new_map;
3290 : }
3291 :
3292 :
3293 6717029 : MaybeHandle<Map> Map::CopyWithConstant(Handle<Map> map,
3294 : Handle<Name> name,
3295 : Handle<Object> constant,
3296 : PropertyAttributes attributes,
3297 : TransitionFlag flag) {
3298 : // Ensure the descriptor array does not get too big.
3299 6717029 : if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
3300 : return MaybeHandle<Map>();
3301 : }
3302 :
3303 : if (FLAG_track_constant_fields) {
3304 : Isolate* isolate = map->GetIsolate();
3305 : Representation representation = constant->OptimalRepresentation();
3306 : Handle<FieldType> type = constant->OptimalType(isolate, representation);
3307 : return CopyWithField(map, name, type, attributes, kConst, representation,
3308 : flag);
3309 : } else {
3310 : // Allocate new instance descriptors with (name, constant) added.
3311 6717029 : Descriptor d = Descriptor::DataConstant(name, 0, constant, attributes);
3312 6717029 : Handle<Map> new_map = Map::CopyAddDescriptor(map, &d, flag);
3313 : return new_map;
3314 : }
3315 : }
3316 :
3317 0 : const char* Representation::Mnemonic() const {
3318 0 : switch (kind_) {
3319 : case kNone: return "v";
3320 0 : case kTagged: return "t";
3321 0 : case kSmi: return "s";
3322 0 : case kDouble: return "d";
3323 0 : case kInteger32: return "i";
3324 0 : case kHeapObject: return "h";
3325 0 : case kExternal: return "x";
3326 : default:
3327 0 : UNREACHABLE();
3328 : return NULL;
3329 : }
3330 : }
3331 :
3332 0 : bool Map::TransitionRemovesTaggedField(Map* target) {
3333 : int inobject = GetInObjectProperties();
3334 : int target_inobject = target->GetInObjectProperties();
3335 0 : for (int i = target_inobject; i < inobject; i++) {
3336 0 : FieldIndex index = FieldIndex::ForPropertyIndex(this, i);
3337 0 : if (!IsUnboxedDoubleField(index)) return true;
3338 : }
3339 : return false;
3340 : }
3341 :
3342 0 : bool Map::TransitionChangesTaggedFieldToUntaggedField(Map* target) {
3343 : int inobject = GetInObjectProperties();
3344 : int target_inobject = target->GetInObjectProperties();
3345 : int limit = Min(inobject, target_inobject);
3346 0 : for (int i = 0; i < limit; i++) {
3347 0 : FieldIndex index = FieldIndex::ForPropertyIndex(target, i);
3348 0 : if (!IsUnboxedDoubleField(index) && target->IsUnboxedDoubleField(index)) {
3349 0 : return true;
3350 : }
3351 : }
3352 : return false;
3353 : }
3354 :
3355 0 : bool Map::TransitionRequiresSynchronizationWithGC(Map* target) {
3356 0 : return TransitionRemovesTaggedField(target) ||
3357 0 : TransitionChangesTaggedFieldToUntaggedField(target);
3358 : }
3359 :
3360 146633 : bool Map::InstancesNeedRewriting(Map* target) {
3361 146633 : int target_number_of_fields = target->NumberOfFields();
3362 : int target_inobject = target->GetInObjectProperties();
3363 : int target_unused = target->unused_property_fields();
3364 : int old_number_of_fields;
3365 :
3366 : return InstancesNeedRewriting(target, target_number_of_fields,
3367 : target_inobject, target_unused,
3368 146633 : &old_number_of_fields);
3369 : }
3370 :
3371 26131569 : bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields,
3372 : int target_inobject, int target_unused,
3373 : int* old_number_of_fields) {
3374 : // If fields were added (or removed), rewrite the instance.
3375 26131569 : *old_number_of_fields = NumberOfFields();
3376 : DCHECK(target_number_of_fields >= *old_number_of_fields);
3377 26131569 : if (target_number_of_fields != *old_number_of_fields) return true;
3378 :
3379 : // If smi descriptors were replaced by double descriptors, rewrite.
3380 : DescriptorArray* old_desc = instance_descriptors();
3381 : DescriptorArray* new_desc = target->instance_descriptors();
3382 : int limit = NumberOfOwnDescriptors();
3383 50132130 : for (int i = 0; i < limit; i++) {
3384 72750386 : if (new_desc->GetDetails(i).representation().IsDouble() !=
3385 72750386 : old_desc->GetDetails(i).representation().IsDouble()) {
3386 : return true;
3387 : }
3388 : }
3389 :
3390 : // If no fields were added, and no inobject properties were removed, setting
3391 : // the map is sufficient.
3392 13756937 : if (target_inobject == GetInObjectProperties()) return false;
3393 : // In-object slack tracking may have reduced the object size of the new map.
3394 : // In that case, succeed if all existing fields were inobject, and they still
3395 : // fit within the new inobject size.
3396 : DCHECK(target_inobject < GetInObjectProperties());
3397 509 : if (target_number_of_fields <= target_inobject) {
3398 : DCHECK(target_number_of_fields + target_unused == target_inobject);
3399 : return false;
3400 : }
3401 : // Otherwise, properties will need to be moved to the backing store.
3402 0 : return true;
3403 : }
3404 :
3405 :
3406 : // static
3407 5497297 : void JSObject::UpdatePrototypeUserRegistration(Handle<Map> old_map,
3408 : Handle<Map> new_map,
3409 : Isolate* isolate) {
3410 : DCHECK(old_map->is_prototype_map());
3411 : DCHECK(new_map->is_prototype_map());
3412 5497297 : bool was_registered = JSObject::UnregisterPrototypeUser(old_map, isolate);
3413 5497297 : new_map->set_prototype_info(old_map->prototype_info());
3414 5497297 : old_map->set_prototype_info(Smi::kZero);
3415 5497296 : if (FLAG_trace_prototype_users) {
3416 : PrintF("Moving prototype_info %p from map %p to map %p.\n",
3417 : reinterpret_cast<void*>(new_map->prototype_info()),
3418 : reinterpret_cast<void*>(*old_map),
3419 0 : reinterpret_cast<void*>(*new_map));
3420 : }
3421 5497296 : if (was_registered) {
3422 284402 : if (new_map->prototype_info()->IsPrototypeInfo()) {
3423 : // The new map isn't registered with its prototype yet; reflect this fact
3424 : // in the PrototypeInfo it just inherited from the old map.
3425 : PrototypeInfo::cast(new_map->prototype_info())
3426 : ->set_registry_slot(PrototypeInfo::UNREGISTERED);
3427 : }
3428 284402 : JSObject::LazyRegisterPrototypeUser(new_map, isolate);
3429 : }
3430 5497296 : }
3431 :
3432 : namespace {
3433 : // To migrate a fast instance to a fast map:
3434 : // - First check whether the instance needs to be rewritten. If not, simply
3435 : // change the map.
3436 : // - Otherwise, allocate a fixed array large enough to hold all fields, in
3437 : // addition to unused space.
3438 : // - Copy all existing properties in, in the following order: backing store
3439 : // properties, unused fields, inobject properties.
3440 : // - If all allocation succeeded, commit the state atomically:
3441 : // * Copy inobject properties from the backing store back into the object.
3442 : // * Trim the difference in instance size of the object. This also cleanly
3443 : // frees inobject properties that moved to the backing store.
3444 : // * If there are properties left in the backing store, trim of the space used
3445 : // to temporarily store the inobject properties.
3446 : // * If there are properties left in the backing store, install the backing
3447 : // store.
3448 52815815 : void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
3449 : Isolate* isolate = object->GetIsolate();
3450 : Handle<Map> old_map(object->map());
3451 : // In case of a regular transition.
3452 105631641 : if (new_map->GetBackPointer() == *old_map) {
3453 : // If the map does not add named properties, simply set the map.
3454 26830892 : if (old_map->NumberOfOwnDescriptors() ==
3455 : new_map->NumberOfOwnDescriptors()) {
3456 685894 : object->synchronized_set_map(*new_map);
3457 685880 : return;
3458 : }
3459 :
3460 : PropertyDetails details = new_map->GetLastDescriptorDetails();
3461 26145005 : int target_index = details.field_index() - new_map->GetInObjectProperties();
3462 31502586 : bool have_space = old_map->unused_property_fields() > 0 ||
3463 9287038 : (details.location() == kField && target_index >= 0 &&
3464 : object->properties()->length() > target_index);
3465 : // Either new_map adds an kDescriptor property, or a kField property for
3466 : // which there is still space, and which does not require a mutable double
3467 : // box (an out-of-object double).
3468 52290010 : if (details.location() == kDescriptor ||
3469 18031342 : (have_space &&
3470 5435992 : ((FLAG_unbox_double_fields && object->properties()->length() == 0) ||
3471 : !details.representation().IsDouble()))) {
3472 21495994 : object->synchronized_set_map(*new_map);
3473 21495992 : return;
3474 : }
3475 :
3476 : // If there is still space in the object, we need to allocate a mutable
3477 : // double box.
3478 4649011 : if (have_space) {
3479 : FieldIndex index =
3480 5492 : FieldIndex::ForDescriptor(*new_map, new_map->LastAdded());
3481 : DCHECK(details.representation().IsDouble());
3482 : DCHECK(!new_map->IsUnboxedDoubleField(index));
3483 : Handle<Object> value = isolate->factory()->NewMutableHeapNumber();
3484 5492 : object->RawFastPropertyAtPut(index, *value);
3485 5492 : object->synchronized_set_map(*new_map);
3486 : return;
3487 : }
3488 :
3489 : // This migration is a transition from a map that has run out of property
3490 : // space. Extend the backing store.
3491 4643519 : int grow_by = new_map->unused_property_fields() + 1;
3492 4643519 : Handle<FixedArray> old_storage = handle(object->properties(), isolate);
3493 : Handle<FixedArray> new_storage =
3494 4643519 : isolate->factory()->CopyFixedArrayAndGrow(old_storage, grow_by);
3495 :
3496 : // Properly initialize newly added property.
3497 : Handle<Object> value;
3498 4643519 : if (details.representation().IsDouble()) {
3499 : value = isolate->factory()->NewMutableHeapNumber();
3500 : } else {
3501 : value = isolate->factory()->uninitialized_value();
3502 : }
3503 : DCHECK_EQ(kField, details.location());
3504 : DCHECK_EQ(kData, details.kind());
3505 : DCHECK(target_index >= 0); // Must be a backing store index.
3506 4643519 : new_storage->set(target_index, *value);
3507 :
3508 : // From here on we cannot fail and we shouldn't GC anymore.
3509 : DisallowHeapAllocation no_allocation;
3510 :
3511 : // Set the new property value and do the map transition.
3512 4643519 : object->set_properties(*new_storage);
3513 4643519 : object->synchronized_set_map(*new_map);
3514 4643519 : return;
3515 : }
3516 :
3517 : int old_number_of_fields;
3518 25984937 : int number_of_fields = new_map->NumberOfFields();
3519 : int inobject = new_map->GetInObjectProperties();
3520 : int unused = new_map->unused_property_fields();
3521 :
3522 : // Nothing to do if no functions were converted to fields and no smis were
3523 : // converted to doubles.
3524 25984938 : if (!old_map->InstancesNeedRewriting(*new_map, number_of_fields, inobject,
3525 25984937 : unused, &old_number_of_fields)) {
3526 13610335 : object->synchronized_set_map(*new_map);
3527 13610335 : return;
3528 : }
3529 :
3530 12374603 : int total_size = number_of_fields + unused;
3531 12374603 : int external = total_size - inobject;
3532 :
3533 12374603 : Handle<FixedArray> array = isolate->factory()->NewFixedArray(total_size);
3534 :
3535 : Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors());
3536 : Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors());
3537 : int old_nof = old_map->NumberOfOwnDescriptors();
3538 : int new_nof = new_map->NumberOfOwnDescriptors();
3539 :
3540 : // This method only supports generalizing instances to at least the same
3541 : // number of properties.
3542 : DCHECK(old_nof <= new_nof);
3543 :
3544 105609214 : for (int i = 0; i < old_nof; i++) {
3545 93234613 : PropertyDetails details = new_descriptors->GetDetails(i);
3546 93234613 : if (details.location() != kField) continue;
3547 : DCHECK_EQ(kData, details.kind());
3548 63105038 : PropertyDetails old_details = old_descriptors->GetDetails(i);
3549 : Representation old_representation = old_details.representation();
3550 : Representation representation = details.representation();
3551 : Handle<Object> value;
3552 63105038 : if (old_details.location() == kDescriptor) {
3553 1949152 : if (old_details.kind() == kAccessor) {
3554 : // In case of kAccessor -> kData property reconfiguration, the property
3555 : // must already be prepared for data of certain type.
3556 : DCHECK(!details.representation().IsNone());
3557 1512695 : if (details.representation().IsDouble()) {
3558 : value = isolate->factory()->NewMutableHeapNumber();
3559 : } else {
3560 : value = isolate->factory()->uninitialized_value();
3561 : }
3562 : } else {
3563 : DCHECK_EQ(kData, old_details.kind());
3564 : value = handle(old_descriptors->GetValue(i), isolate);
3565 : DCHECK(!old_representation.IsDouble() && !representation.IsDouble());
3566 : }
3567 : } else {
3568 : DCHECK_EQ(kField, old_details.location());
3569 61155886 : FieldIndex index = FieldIndex::ForDescriptor(*old_map, i);
3570 61155886 : if (object->IsUnboxedDoubleField(index)) {
3571 : uint64_t old_bits = object->RawFastDoublePropertyAsBitsAt(index);
3572 : value = isolate->factory()->NewHeapNumberFromBits(
3573 4883 : old_bits, representation.IsDouble() ? MUTABLE : IMMUTABLE);
3574 :
3575 : } else {
3576 61151003 : value = handle(object->RawFastPropertyAt(index), isolate);
3577 61151003 : if (!old_representation.IsDouble() && representation.IsDouble()) {
3578 : DCHECK_IMPLIES(old_representation.IsNone(),
3579 : value->IsUninitialized(isolate));
3580 2821 : value = Object::NewStorageFor(isolate, value, representation);
3581 61148182 : } else if (old_representation.IsDouble() &&
3582 : !representation.IsDouble()) {
3583 19 : value = Object::WrapForRead(isolate, value, old_representation);
3584 : }
3585 : }
3586 : }
3587 : DCHECK(!(representation.IsDouble() && value->IsSmi()));
3588 63105037 : int target_index = new_descriptors->GetFieldIndex(i) - inobject;
3589 63105037 : if (target_index < 0) target_index += total_size;
3590 63105037 : array->set(target_index, *value);
3591 : }
3592 :
3593 43615080 : for (int i = old_nof; i < new_nof; i++) {
3594 43615080 : PropertyDetails details = new_descriptors->GetDetails(i);
3595 43615080 : if (details.location() != kField) continue;
3596 : DCHECK_EQ(kData, details.kind());
3597 : Handle<Object> value;
3598 43615080 : if (details.representation().IsDouble()) {
3599 : value = isolate->factory()->NewMutableHeapNumber();
3600 : } else {
3601 : value = isolate->factory()->uninitialized_value();
3602 : }
3603 43615080 : int target_index = new_descriptors->GetFieldIndex(i) - inobject;
3604 43615080 : if (target_index < 0) target_index += total_size;
3605 43615080 : array->set(target_index, *value);
3606 : }
3607 :
3608 : // From here on we cannot fail and we shouldn't GC anymore.
3609 : DisallowHeapAllocation no_allocation;
3610 :
3611 12374601 : Heap* heap = isolate->heap();
3612 :
3613 12374601 : heap->NotifyObjectLayoutChange(*object, no_allocation);
3614 :
3615 : // Copy (real) inobject properties. If necessary, stop at number_of_fields to
3616 : // avoid overwriting |one_pointer_filler_map|.
3617 : int limit = Min(inobject, number_of_fields);
3618 47765038 : for (int i = 0; i < limit; i++) {
3619 35390435 : FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
3620 35390435 : Object* value = array->get(external + i);
3621 : // Can't use JSObject::FastPropertyAtPut() because proper map was not set
3622 : // yet.
3623 35390435 : if (new_map->IsUnboxedDoubleField(index)) {
3624 : DCHECK(value->IsMutableHeapNumber());
3625 : // Ensure that all bits of the double value are preserved.
3626 : object->RawFastDoublePropertyAsBitsAtPut(
3627 : index, HeapNumber::cast(value)->value_as_bits());
3628 45506 : if (i < old_number_of_fields && !old_map->IsUnboxedDoubleField(index)) {
3629 : // Transition from tagged to untagged slot.
3630 : heap->ClearRecordedSlot(*object,
3631 1875 : HeapObject::RawField(*object, index.offset()));
3632 : } else {
3633 : DCHECK(!heap->HasRecordedSlot(
3634 : *object, HeapObject::RawField(*object, index.offset())));
3635 : }
3636 : } else {
3637 35350948 : object->RawFastPropertyAtPut(index, value);
3638 : }
3639 : }
3640 :
3641 :
3642 : // If there are properties in the new backing store, trim it to the correct
3643 : // size and install the backing store into the object.
3644 12374603 : if (external > 0) {
3645 6738517 : heap->RightTrimFixedArray(*array, inobject);
3646 6738516 : object->set_properties(*array);
3647 : }
3648 :
3649 : // Create filler object past the new instance size.
3650 : int new_instance_size = new_map->instance_size();
3651 12374602 : int instance_size_delta = old_map->instance_size() - new_instance_size;
3652 : DCHECK(instance_size_delta >= 0);
3653 :
3654 12374602 : if (instance_size_delta > 0) {
3655 17 : Address address = object->address();
3656 : heap->CreateFillerObjectAt(address + new_instance_size, instance_size_delta,
3657 17 : ClearRecordedSlots::kYes);
3658 34 : heap->AdjustLiveBytes(*object, -instance_size_delta);
3659 : }
3660 :
3661 : // We are storing the new map using release store after creating a filler for
3662 : // the left-over space to avoid races with the sweeper thread.
3663 12374602 : object->synchronized_set_map(*new_map);
3664 : }
3665 :
3666 1317738 : void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map,
3667 : int expected_additional_properties) {
3668 : // The global object is always normalized.
3669 : DCHECK(!object->IsJSGlobalObject());
3670 : // JSGlobalProxy must never be normalized
3671 : DCHECK(!object->IsJSGlobalProxy());
3672 :
3673 1317738 : Isolate* isolate = object->GetIsolate();
3674 : HandleScope scope(isolate);
3675 : Handle<Map> map(object->map());
3676 :
3677 : // Allocate new content.
3678 : int real_size = map->NumberOfOwnDescriptors();
3679 : int property_count = real_size;
3680 1317738 : if (expected_additional_properties > 0) {
3681 94767 : property_count += expected_additional_properties;
3682 : } else {
3683 : // Make space for two more properties.
3684 1222971 : property_count += NameDictionary::kInitialCapacity;
3685 : }
3686 : Handle<NameDictionary> dictionary =
3687 1317738 : NameDictionary::New(isolate, property_count);
3688 :
3689 : Handle<DescriptorArray> descs(map->instance_descriptors());
3690 8434361 : for (int i = 0; i < real_size; i++) {
3691 5798885 : PropertyDetails details = descs->GetDetails(i);
3692 : Handle<Name> key(descs->GetKey(i));
3693 : Handle<Object> value;
3694 5798885 : if (details.location() == kField) {
3695 4466689 : FieldIndex index = FieldIndex::ForDescriptor(*map, i);
3696 4466689 : if (details.kind() == kData) {
3697 4466689 : if (object->IsUnboxedDoubleField(index)) {
3698 : double old_value = object->RawFastDoublePropertyAt(index);
3699 : value = isolate->factory()->NewHeapNumber(old_value);
3700 : } else {
3701 4465793 : value = handle(object->RawFastPropertyAt(index), isolate);
3702 4465793 : if (details.representation().IsDouble()) {
3703 : DCHECK(value->IsMutableHeapNumber());
3704 : Handle<HeapNumber> old = Handle<HeapNumber>::cast(value);
3705 : value = isolate->factory()->NewHeapNumber(old->value());
3706 : }
3707 : }
3708 : } else {
3709 : DCHECK_EQ(kAccessor, details.kind());
3710 0 : value = handle(object->RawFastPropertyAt(index), isolate);
3711 : }
3712 :
3713 : } else {
3714 : DCHECK_EQ(kDescriptor, details.location());
3715 : value = handle(descs->GetValue(i), isolate);
3716 : }
3717 : DCHECK(!value.is_null());
3718 : PropertyDetails d(details.kind(), details.attributes(), i + 1,
3719 5798885 : PropertyCellType::kNoCell);
3720 5798885 : dictionary = NameDictionary::Add(dictionary, key, value, d);
3721 : }
3722 :
3723 : // Copy the next enumeration index from instance descriptor.
3724 1317738 : dictionary->SetNextEnumerationIndex(real_size + 1);
3725 :
3726 : // From here on we cannot fail and we shouldn't GC anymore.
3727 : DisallowHeapAllocation no_allocation;
3728 :
3729 1317738 : Heap* heap = isolate->heap();
3730 1317738 : heap->NotifyObjectLayoutChange(*object, no_allocation);
3731 :
3732 : // Resize the object in the heap if necessary.
3733 : int new_instance_size = new_map->instance_size();
3734 1317738 : int instance_size_delta = map->instance_size() - new_instance_size;
3735 : DCHECK(instance_size_delta >= 0);
3736 :
3737 1317738 : if (instance_size_delta > 0) {
3738 452727 : heap->CreateFillerObjectAt(object->address() + new_instance_size,
3739 452727 : instance_size_delta, ClearRecordedSlots::kYes);
3740 905454 : heap->AdjustLiveBytes(*object, -instance_size_delta);
3741 : }
3742 :
3743 : // We are storing the new map using release store after creating a filler for
3744 : // the left-over space to avoid races with the sweeper thread.
3745 1317738 : object->synchronized_set_map(*new_map);
3746 :
3747 1317738 : object->set_properties(*dictionary);
3748 :
3749 : // Ensure that in-object space of slow-mode object does not contain random
3750 : // garbage.
3751 : int inobject_properties = new_map->GetInObjectProperties();
3752 1317738 : if (inobject_properties) {
3753 : Heap* heap = isolate->heap();
3754 : heap->ClearRecordedSlotRange(
3755 588032 : object->address() + map->GetInObjectPropertyOffset(0),
3756 1176064 : object->address() + new_instance_size);
3757 :
3758 3467145 : for (int i = 0; i < inobject_properties; i++) {
3759 2879113 : FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
3760 2879113 : object->RawFastPropertyAtPut(index, Smi::kZero);
3761 : }
3762 : }
3763 :
3764 1317738 : isolate->counters()->props_to_dictionary()->Increment();
3765 :
3766 : #ifdef DEBUG
3767 : if (FLAG_trace_normalization) {
3768 : OFStream os(stdout);
3769 : os << "Object properties have been normalized:\n";
3770 : object->Print(os);
3771 : }
3772 : #endif
3773 1317738 : }
3774 :
3775 : } // namespace
3776 :
3777 : // static
3778 55413211 : void JSObject::NotifyMapChange(Handle<Map> old_map, Handle<Map> new_map,
3779 : Isolate* isolate) {
3780 110826421 : if (!old_map->is_prototype_map()) return;
3781 :
3782 : InvalidatePrototypeChains(*old_map);
3783 :
3784 : // If the map was registered with its prototype before, ensure that it
3785 : // registers with its new prototype now. This preserves the invariant that
3786 : // when a map on a prototype chain is registered with its prototype, then
3787 : // all prototypes further up the chain are also registered with their
3788 : // respective prototypes.
3789 5497297 : UpdatePrototypeUserRegistration(old_map, new_map, isolate);
3790 : }
3791 :
3792 69226741 : void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
3793 : int expected_additional_properties) {
3794 138453489 : if (object->map() == *new_map) return;
3795 : Handle<Map> old_map(object->map());
3796 54784093 : NotifyMapChange(old_map, new_map, new_map->GetIsolate());
3797 :
3798 54784094 : if (old_map->is_dictionary_map()) {
3799 : // For slow-to-fast migrations JSObject::MigrateSlowToFast()
3800 : // must be used instead.
3801 650540 : CHECK(new_map->is_dictionary_map());
3802 :
3803 : // Slow-to-slow migration is trivial.
3804 650540 : object->set_map(*new_map);
3805 54133554 : } else if (!new_map->is_dictionary_map()) {
3806 52815816 : MigrateFastToFast(object, new_map);
3807 52815815 : if (old_map->is_prototype_map()) {
3808 : DCHECK(!old_map->is_stable());
3809 : DCHECK(new_map->is_stable());
3810 : // Clear out the old descriptor array to avoid problems to sharing
3811 : // the descriptor array without using an explicit.
3812 : old_map->InitializeDescriptors(
3813 : old_map->GetHeap()->empty_descriptor_array(),
3814 4899217 : LayoutDescriptor::FastPointerLayout());
3815 : // Ensure that no transition was inserted for prototype migrations.
3816 : DCHECK_EQ(
3817 : 0, TransitionArray::NumberOfTransitions(old_map->raw_transitions()));
3818 : DCHECK(new_map->GetBackPointer()->IsUndefined(new_map->GetIsolate()));
3819 : }
3820 : } else {
3821 1317738 : MigrateFastToSlow(object, new_map, expected_additional_properties);
3822 : }
3823 :
3824 : // Careful: Don't allocate here!
3825 : // For some callers of this method, |object| might be in an inconsistent
3826 : // state now: the new map might have a new elements_kind, but the object's
3827 : // elements pointer hasn't been updated yet. Callers will fix this, but in
3828 : // the meantime, (indirectly) calling JSObjectVerify() must be avoided.
3829 : // When adding code here, add a DisallowHeapAllocation too.
3830 : }
3831 :
3832 237661 : void JSObject::ForceSetPrototype(Handle<JSObject> object,
3833 : Handle<Object> proto) {
3834 : // object.__proto__ = proto;
3835 : Handle<Map> old_map = Handle<Map>(object->map());
3836 237661 : Handle<Map> new_map = Map::Copy(old_map, "ForceSetPrototype");
3837 237661 : Map::SetPrototype(new_map, proto, FAST_PROTOTYPE);
3838 237661 : JSObject::MigrateToMap(object, new_map);
3839 237661 : }
3840 :
3841 56054235 : int Map::NumberOfFields() {
3842 : DescriptorArray* descriptors = instance_descriptors();
3843 : int result = 0;
3844 920050224 : for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
3845 807941752 : if (descriptors->GetDetails(i).location() == kField) result++;
3846 : }
3847 56054237 : return result;
3848 : }
3849 :
3850 9532631 : void DescriptorArray::GeneralizeAllFields() {
3851 9532631 : int length = number_of_descriptors();
3852 57908793 : for (int i = 0; i < length; i++) {
3853 38843529 : PropertyDetails details = GetDetails(i);
3854 : details = details.CopyWithRepresentation(Representation::Tagged());
3855 38843530 : if (details.location() == kField) {
3856 : DCHECK_EQ(kData, details.kind());
3857 : details = details.CopyWithConstness(kMutable);
3858 5111075 : SetValue(i, FieldType::Any());
3859 : }
3860 : set(ToDetailsIndex(i), details.AsSmi());
3861 : }
3862 9532632 : }
3863 :
3864 1946877 : Handle<Map> Map::CopyGeneralizeAllFields(Handle<Map> map,
3865 : ElementsKind elements_kind,
3866 : int modify_index, PropertyKind kind,
3867 : PropertyAttributes attributes,
3868 : const char* reason) {
3869 : Isolate* isolate = map->GetIsolate();
3870 : Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
3871 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
3872 : Handle<DescriptorArray> descriptors =
3873 : DescriptorArray::CopyUpTo(old_descriptors, number_of_own_descriptors);
3874 1946878 : descriptors->GeneralizeAllFields();
3875 :
3876 : Handle<LayoutDescriptor> new_layout_descriptor(
3877 : LayoutDescriptor::FastPointerLayout(), isolate);
3878 : Handle<Map> new_map = CopyReplaceDescriptors(
3879 : map, descriptors, new_layout_descriptor, OMIT_TRANSITION,
3880 1946878 : MaybeHandle<Name>(), reason, SPECIAL_TRANSITION);
3881 :
3882 : // Unless the instance is being migrated, ensure that modify_index is a field.
3883 1946878 : if (modify_index >= 0) {
3884 1946774 : PropertyDetails details = descriptors->GetDetails(modify_index);
3885 1950848 : if (details.constness() != kMutable || details.location() != kField ||
3886 : details.attributes() != attributes) {
3887 : int field_index = details.location() == kField
3888 : ? details.field_index()
3889 3889912 : : new_map->NumberOfFields();
3890 : Descriptor d = Descriptor::DataField(
3891 : handle(descriptors->GetKey(modify_index), isolate), field_index,
3892 1945174 : attributes, Representation::Tagged());
3893 1945174 : descriptors->Replace(modify_index, &d);
3894 1945175 : if (details.location() != kField) {
3895 1944737 : int unused_property_fields = new_map->unused_property_fields() - 1;
3896 1944737 : if (unused_property_fields < 0) {
3897 1597063 : unused_property_fields += JSObject::kFieldsAdded;
3898 : }
3899 : new_map->set_unused_property_fields(unused_property_fields);
3900 : }
3901 : } else {
3902 : DCHECK(details.attributes() == attributes);
3903 : }
3904 :
3905 1946774 : if (FLAG_trace_generalization) {
3906 0 : MaybeHandle<FieldType> field_type = FieldType::None(isolate);
3907 0 : if (details.location() == kField) {
3908 : field_type = handle(
3909 0 : map->instance_descriptors()->GetFieldType(modify_index), isolate);
3910 : }
3911 : map->PrintGeneralization(
3912 : stdout, reason, modify_index, new_map->NumberOfOwnDescriptors(),
3913 : new_map->NumberOfOwnDescriptors(), details.location() == kDescriptor,
3914 : details.representation(), Representation::Tagged(), field_type,
3915 : MaybeHandle<Object>(), FieldType::Any(isolate),
3916 0 : MaybeHandle<Object>());
3917 : }
3918 : }
3919 : new_map->set_elements_kind(elements_kind);
3920 1946878 : return new_map;
3921 : }
3922 :
3923 :
3924 323702 : void Map::DeprecateTransitionTree() {
3925 647404 : if (is_deprecated()) return;
3926 : Object* transitions = raw_transitions();
3927 323702 : int num_transitions = TransitionArray::NumberOfTransitions(transitions);
3928 482307 : for (int i = 0; i < num_transitions; ++i) {
3929 158605 : TransitionArray::GetTarget(transitions, i)->DeprecateTransitionTree();
3930 : }
3931 : DCHECK(!constructor_or_backpointer()->IsFunctionTemplateInfo());
3932 : deprecate();
3933 : dependent_code()->DeoptimizeDependentCodeGroup(
3934 323702 : GetIsolate(), DependentCode::kTransitionGroup);
3935 323702 : NotifyLeafMapLayoutChange();
3936 : }
3937 :
3938 :
3939 : // Installs |new_descriptors| over the current instance_descriptors to ensure
3940 : // proper sharing of descriptor arrays.
3941 167298 : void Map::ReplaceDescriptors(DescriptorArray* new_descriptors,
3942 : LayoutDescriptor* new_layout_descriptor) {
3943 : Isolate* isolate = GetIsolate();
3944 : // Don't overwrite the empty descriptor array or initial map's descriptors.
3945 216626 : if (NumberOfOwnDescriptors() == 0 || GetBackPointer()->IsUndefined(isolate)) {
3946 167298 : return;
3947 : }
3948 :
3949 : DescriptorArray* to_replace = instance_descriptors();
3950 48904 : isolate->heap()->incremental_marking()->IterateBlackObject(to_replace);
3951 : Map* current = this;
3952 254662 : while (current->instance_descriptors() == to_replace) {
3953 157251 : Object* next = current->GetBackPointer();
3954 157251 : if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map.
3955 : current->SetEnumLength(kInvalidEnumCacheSentinel);
3956 156854 : current->UpdateDescriptors(new_descriptors, new_layout_descriptor);
3957 : current = Map::cast(next);
3958 : }
3959 : set_owns_descriptors(false);
3960 : }
3961 :
3962 :
3963 2114910 : Map* Map::FindRootMap() {
3964 : Map* result = this;
3965 : Isolate* isolate = GetIsolate();
3966 : while (true) {
3967 9954574 : Object* back = result->GetBackPointer();
3968 9954574 : if (back->IsUndefined(isolate)) {
3969 : // Initial map always owns descriptors and doesn't have unused entries
3970 : // in the descriptor array.
3971 : DCHECK(result->owns_descriptors());
3972 : DCHECK_EQ(result->NumberOfOwnDescriptors(),
3973 : result->instance_descriptors()->number_of_descriptors());
3974 2114910 : return result;
3975 : }
3976 : result = Map::cast(back);
3977 : }
3978 : }
3979 :
3980 :
3981 966844 : Map* Map::FindFieldOwner(int descriptor) {
3982 : DisallowHeapAllocation no_allocation;
3983 : DCHECK_EQ(kField, instance_descriptors()->GetDetails(descriptor).location());
3984 : Map* result = this;
3985 : Isolate* isolate = GetIsolate();
3986 : while (true) {
3987 3423094 : Object* back = result->GetBackPointer();
3988 3423094 : if (back->IsUndefined(isolate)) break;
3989 : Map* parent = Map::cast(back);
3990 3423094 : if (parent->NumberOfOwnDescriptors() <= descriptor) break;
3991 : result = parent;
3992 : }
3993 966844 : return result;
3994 : }
3995 :
3996 550695 : void Map::UpdateFieldType(int descriptor, Handle<Name> name,
3997 : PropertyConstness new_constness,
3998 : Representation new_representation,
3999 : Handle<Object> new_wrapped_type) {
4000 : DCHECK(new_wrapped_type->IsSmi() || new_wrapped_type->IsWeakCell());
4001 : // We store raw pointers in the queue, so no allocations are allowed.
4002 : DisallowHeapAllocation no_allocation;
4003 550695 : PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
4004 550695 : if (details.location() != kField) return;
4005 : DCHECK_EQ(kData, details.kind());
4006 :
4007 550695 : Zone zone(GetIsolate()->allocator(), ZONE_NAME);
4008 550695 : ZoneQueue<Map*> backlog(&zone);
4009 1101390 : backlog.push(this);
4010 :
4011 4101506 : while (!backlog.empty()) {
4012 3000116 : Map* current = backlog.front();
4013 : backlog.pop();
4014 :
4015 : Object* transitions = current->raw_transitions();
4016 3000116 : int num_transitions = TransitionArray::NumberOfTransitions(transitions);
4017 5449537 : for (int i = 0; i < num_transitions; ++i) {
4018 2449421 : Map* target = TransitionArray::GetTarget(transitions, i);
4019 : backlog.push(target);
4020 : }
4021 : DescriptorArray* descriptors = current->instance_descriptors();
4022 3000116 : PropertyDetails details = descriptors->GetDetails(descriptor);
4023 :
4024 : // Currently constness change implies map change.
4025 : DCHECK_IMPLIES(new_constness != details.constness(),
4026 : FLAG_modify_map_inplace);
4027 :
4028 : // It is allowed to change representation here only from None to something.
4029 : DCHECK(details.representation().Equals(new_representation) ||
4030 : details.representation().IsNone());
4031 :
4032 : // Skip if already updated the shared descriptor.
4033 3000116 : if ((FLAG_modify_map_inplace && new_constness != details.constness()) ||
4034 : descriptors->GetValue(descriptor) != *new_wrapped_type) {
4035 : DCHECK_IMPLIES(!FLAG_track_constant_fields, new_constness == kMutable);
4036 : Descriptor d = Descriptor::DataField(
4037 : name, descriptors->GetFieldIndex(descriptor), details.attributes(),
4038 550747 : new_constness, new_representation, new_wrapped_type);
4039 550747 : descriptors->Replace(descriptor, &d);
4040 : }
4041 550695 : }
4042 : }
4043 :
4044 0 : bool FieldTypeIsCleared(Representation rep, FieldType* type) {
4045 4662342 : return type->IsNone() && rep.IsHeapObject();
4046 : }
4047 :
4048 :
4049 : // static
4050 2080752 : Handle<FieldType> Map::GeneralizeFieldType(Representation rep1,
4051 : Handle<FieldType> type1,
4052 : Representation rep2,
4053 : Handle<FieldType> type2,
4054 : Isolate* isolate) {
4055 : // Cleared field types need special treatment. They represent lost knowledge,
4056 : // so we must be conservative, so their generalization with any other type
4057 : // is "Any".
4058 4161442 : if (FieldTypeIsCleared(rep1, *type1) || FieldTypeIsCleared(rep2, *type2)) {
4059 9569 : return FieldType::Any(isolate);
4060 : }
4061 2071183 : if (type1->NowIs(type2)) return type2;
4062 176992 : if (type2->NowIs(type1)) return type1;
4063 99085 : return FieldType::Any(isolate);
4064 : }
4065 :
4066 :
4067 : // static
4068 885725 : void Map::GeneralizeField(Handle<Map> map, int modify_index,
4069 : PropertyConstness new_constness,
4070 : Representation new_representation,
4071 : Handle<FieldType> new_field_type) {
4072 : Isolate* isolate = map->GetIsolate();
4073 :
4074 : // Check if we actually need to generalize the field type at all.
4075 : Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
4076 885725 : PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
4077 : PropertyConstness old_constness = old_details.constness();
4078 : Representation old_representation = old_details.representation();
4079 : Handle<FieldType> old_field_type(old_descriptors->GetFieldType(modify_index),
4080 885725 : isolate);
4081 :
4082 : // Return if the current map is general enough to hold requested contness and
4083 : // representation/field type.
4084 885725 : if (((FLAG_modify_map_inplace &&
4085 : IsGeneralizableTo(new_constness, old_constness)) ||
4086 885725 : (!FLAG_modify_map_inplace && (old_constness == new_constness))) &&
4087 484705 : old_representation.Equals(new_representation) &&
4088 1370387 : !FieldTypeIsCleared(new_representation, *new_field_type) &&
4089 : // Checking old_field_type for being cleared is not necessary because
4090 : // the NowIs check below would fail anyway in that case.
4091 484662 : new_field_type->NowIs(old_field_type)) {
4092 : DCHECK(GeneralizeFieldType(old_representation, old_field_type,
4093 : new_representation, new_field_type, isolate)
4094 : ->NowIs(old_field_type));
4095 335030 : return;
4096 : }
4097 :
4098 : // Determine the field owner.
4099 550695 : Handle<Map> field_owner(map->FindFieldOwner(modify_index), isolate);
4100 : Handle<DescriptorArray> descriptors(
4101 : field_owner->instance_descriptors(), isolate);
4102 : DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index));
4103 :
4104 : new_field_type =
4105 : Map::GeneralizeFieldType(old_representation, old_field_type,
4106 550695 : new_representation, new_field_type, isolate);
4107 : if (FLAG_modify_map_inplace) {
4108 : new_constness = GeneralizeConstness(old_constness, new_constness);
4109 : }
4110 :
4111 550695 : PropertyDetails details = descriptors->GetDetails(modify_index);
4112 : Handle<Name> name(descriptors->GetKey(modify_index));
4113 :
4114 550695 : Handle<Object> wrapped_type(WrapFieldType(new_field_type));
4115 : field_owner->UpdateFieldType(modify_index, name, new_constness,
4116 550695 : new_representation, wrapped_type);
4117 : field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
4118 550695 : isolate, DependentCode::kFieldOwnerGroup);
4119 :
4120 550695 : if (FLAG_trace_generalization) {
4121 : map->PrintGeneralization(
4122 : stdout, "field type generalization", modify_index,
4123 : map->NumberOfOwnDescriptors(), map->NumberOfOwnDescriptors(), false,
4124 : details.representation(), details.representation(), old_field_type,
4125 0 : MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>());
4126 : }
4127 : }
4128 :
4129 : // TODO(ishell): remove.
4130 : // static
4131 596 : Handle<Map> Map::ReconfigureProperty(Handle<Map> map, int modify_index,
4132 : PropertyKind new_kind,
4133 : PropertyAttributes new_attributes,
4134 : Representation new_representation,
4135 : Handle<FieldType> new_field_type) {
4136 : DCHECK_EQ(kData, new_kind); // Only kData case is supported.
4137 596 : MapUpdater mu(map->GetIsolate(), map);
4138 : return mu.ReconfigureToDataField(modify_index, new_attributes, kConst,
4139 596 : new_representation, new_field_type);
4140 : }
4141 :
4142 : // TODO(ishell): remove.
4143 : // static
4144 652544 : Handle<Map> Map::ReconfigureElementsKind(Handle<Map> map,
4145 : ElementsKind new_elements_kind) {
4146 652544 : MapUpdater mu(map->GetIsolate(), map);
4147 652544 : return mu.ReconfigureElementsKind(new_elements_kind);
4148 : }
4149 :
4150 : // Generalize all fields and update the transition tree.
4151 1697 : Handle<Map> Map::GeneralizeAllFields(Handle<Map> map) {
4152 : Isolate* isolate = map->GetIsolate();
4153 1697 : Handle<FieldType> any_type = FieldType::Any(isolate);
4154 :
4155 : Handle<DescriptorArray> descriptors(map->instance_descriptors());
4156 7208 : for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) {
4157 1907 : PropertyDetails details = descriptors->GetDetails(i);
4158 1907 : if (details.location() == kField) {
4159 : DCHECK_EQ(kData, details.kind());
4160 1007 : MapUpdater mu(isolate, map);
4161 : map = mu.ReconfigureToDataField(i, details.attributes(), kMutable,
4162 1007 : Representation::Tagged(), any_type);
4163 : }
4164 : }
4165 1697 : return map;
4166 : }
4167 :
4168 :
4169 : // static
4170 355240 : MaybeHandle<Map> Map::TryUpdate(Handle<Map> old_map) {
4171 : DisallowHeapAllocation no_allocation;
4172 : DisallowDeoptimization no_deoptimization(old_map->GetIsolate());
4173 :
4174 355240 : if (!old_map->is_deprecated()) return old_map;
4175 :
4176 : // Check the state of the root map.
4177 2639 : Map* root_map = old_map->FindRootMap();
4178 2639 : if (root_map->is_deprecated()) {
4179 0 : JSFunction* constructor = JSFunction::cast(root_map->GetConstructor());
4180 : DCHECK(constructor->has_initial_map());
4181 : DCHECK(constructor->initial_map()->is_dictionary_map());
4182 0 : if (constructor->initial_map()->elements_kind() !=
4183 : old_map->elements_kind()) {
4184 : return MaybeHandle<Map>();
4185 : }
4186 : return handle(constructor->initial_map());
4187 : }
4188 2639 : if (!old_map->EquivalentToForTransition(root_map)) return MaybeHandle<Map>();
4189 :
4190 : ElementsKind from_kind = root_map->elements_kind();
4191 : ElementsKind to_kind = old_map->elements_kind();
4192 2555 : if (from_kind != to_kind) {
4193 : // Try to follow existing elements kind transitions.
4194 : root_map = root_map->LookupElementsTransitionMap(to_kind);
4195 18 : if (root_map == NULL) return MaybeHandle<Map>();
4196 : // From here on, use the map with correct elements kind as root map.
4197 : }
4198 2555 : Map* new_map = root_map->TryReplayPropertyTransitions(*old_map);
4199 2555 : if (new_map == nullptr) return MaybeHandle<Map>();
4200 : return handle(new_map);
4201 : }
4202 :
4203 153711 : Map* Map::TryReplayPropertyTransitions(Map* old_map) {
4204 : DisallowHeapAllocation no_allocation;
4205 : DisallowDeoptimization no_deoptimization(GetIsolate());
4206 :
4207 : int root_nof = NumberOfOwnDescriptors();
4208 :
4209 : int old_nof = old_map->NumberOfOwnDescriptors();
4210 : DescriptorArray* old_descriptors = old_map->instance_descriptors();
4211 :
4212 : Map* new_map = this;
4213 163037 : for (int i = root_nof; i < old_nof; ++i) {
4214 13890 : PropertyDetails old_details = old_descriptors->GetDetails(i);
4215 : Map* transition = TransitionArray::SearchTransition(
4216 : new_map, old_details.kind(), old_descriptors->GetKey(i),
4217 13890 : old_details.attributes());
4218 13890 : if (transition == NULL) return nullptr;
4219 : new_map = transition;
4220 : DescriptorArray* new_descriptors = new_map->instance_descriptors();
4221 :
4222 9406 : PropertyDetails new_details = new_descriptors->GetDetails(i);
4223 : DCHECK_EQ(old_details.kind(), new_details.kind());
4224 : DCHECK_EQ(old_details.attributes(), new_details.attributes());
4225 9406 : if (!IsGeneralizableTo(old_details.constness(), new_details.constness())) {
4226 : return nullptr;
4227 : }
4228 : DCHECK(IsGeneralizableTo(old_details.location(), new_details.location()));
4229 28218 : if (!old_details.representation().fits_into(new_details.representation())) {
4230 : return nullptr;
4231 : }
4232 9354 : if (new_details.location() == kField) {
4233 9175 : if (new_details.kind() == kData) {
4234 9175 : FieldType* new_type = new_descriptors->GetFieldType(i);
4235 : // Cleared field types need special treatment. They represent lost
4236 : // knowledge, so we must first generalize the new_type to "Any".
4237 9175 : if (FieldTypeIsCleared(new_details.representation(), new_type)) {
4238 : return nullptr;
4239 : }
4240 : DCHECK_EQ(kData, old_details.kind());
4241 9175 : if (old_details.location() == kField) {
4242 7020 : FieldType* old_type = old_descriptors->GetFieldType(i);
4243 14040 : if (FieldTypeIsCleared(old_details.representation(), old_type) ||
4244 7020 : !old_type->NowIs(new_type)) {
4245 : return nullptr;
4246 : }
4247 : } else {
4248 : DCHECK_EQ(kDescriptor, old_details.location());
4249 : DCHECK(!FLAG_track_constant_fields);
4250 : Object* old_value = old_descriptors->GetValue(i);
4251 2155 : if (!new_type->NowContains(old_value)) {
4252 : return nullptr;
4253 : }
4254 : }
4255 :
4256 : } else {
4257 : DCHECK_EQ(kAccessor, new_details.kind());
4258 : #ifdef DEBUG
4259 : FieldType* new_type = new_descriptors->GetFieldType(i);
4260 : DCHECK(new_type->IsAny());
4261 : #endif
4262 0 : UNREACHABLE();
4263 : }
4264 : } else {
4265 : DCHECK_EQ(kDescriptor, new_details.location());
4266 : Object* old_value = old_descriptors->GetValue(i);
4267 : Object* new_value = new_descriptors->GetValue(i);
4268 179 : if (old_details.location() == kField || old_value != new_value) {
4269 : return nullptr;
4270 : }
4271 : }
4272 : }
4273 149147 : if (new_map->NumberOfOwnDescriptors() != old_nof) return nullptr;
4274 149147 : return new_map;
4275 : }
4276 :
4277 :
4278 : // static
4279 41286527 : Handle<Map> Map::Update(Handle<Map> map) {
4280 41286527 : if (!map->is_deprecated()) return map;
4281 10322 : MapUpdater mu(map->GetIsolate(), map);
4282 10322 : return mu.Update();
4283 : }
4284 :
4285 225641 : Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
4286 : ShouldThrow should_throw,
4287 : Handle<Object> value) {
4288 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
4289 : return SetPropertyWithInterceptorInternal(it, it->GetInterceptor(),
4290 225641 : should_throw, value);
4291 : }
4292 :
4293 4261217 : MaybeHandle<Object> Object::SetProperty(Handle<Object> object,
4294 : Handle<Name> name, Handle<Object> value,
4295 : LanguageMode language_mode,
4296 : StoreFromKeyed store_mode) {
4297 4261217 : LookupIterator it(object, name);
4298 4261217 : MAYBE_RETURN_NULL(SetProperty(&it, value, language_mode, store_mode));
4299 : return value;
4300 : }
4301 :
4302 :
4303 33956756 : Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
4304 : Handle<Object> value,
4305 : LanguageMode language_mode,
4306 : StoreFromKeyed store_mode,
4307 : bool* found) {
4308 16742905 : it->UpdateProtector();
4309 : DCHECK(it->IsFound());
4310 : ShouldThrow should_throw =
4311 16742905 : is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4312 :
4313 : // Make sure that the top context does not change when doing callbacks or
4314 : // interceptor calls.
4315 : AssertNoContextChange ncc(it->isolate());
4316 :
4317 312937 : do {
4318 16900914 : switch (it->state()) {
4319 : case LookupIterator::NOT_FOUND:
4320 0 : UNREACHABLE();
4321 :
4322 : case LookupIterator::ACCESS_CHECK:
4323 87884 : if (it->HasAccess()) break;
4324 : // Check whether it makes sense to reuse the lookup iterator. Here it
4325 : // might still call into setters up the prototype chain.
4326 : return JSObject::SetPropertyWithFailedAccessCheck(it, value,
4327 131 : should_throw);
4328 :
4329 : case LookupIterator::JSPROXY:
4330 : return JSProxy::SetProperty(it->GetHolder<JSProxy>(), it->GetName(),
4331 63039 : value, it->GetReceiver(), language_mode);
4332 :
4333 : case LookupIterator::INTERCEPTOR: {
4334 225664 : if (it->HolderIsReceiverOrHiddenPrototype()) {
4335 : Maybe<bool> result =
4336 225382 : JSObject::SetPropertyWithInterceptor(it, should_throw, value);
4337 450764 : if (result.IsNothing() || result.FromJust()) return result;
4338 : } else {
4339 : Maybe<PropertyAttributes> maybe_attributes =
4340 282 : JSObject::GetPropertyAttributesWithInterceptor(it);
4341 449 : if (!maybe_attributes.IsJust()) return Nothing<bool>();
4342 282 : if ((maybe_attributes.FromJust() & READ_ONLY) != 0) {
4343 0 : return WriteToReadOnlyProperty(it, value, should_throw);
4344 : }
4345 282 : if (maybe_attributes.FromJust() == ABSENT) break;
4346 167 : *found = false;
4347 : return Nothing<bool>();
4348 : }
4349 : break;
4350 : }
4351 :
4352 : case LookupIterator::ACCESSOR: {
4353 411223 : if (it->IsReadOnly()) {
4354 2651 : return WriteToReadOnlyProperty(it, value, should_throw);
4355 : }
4356 408572 : Handle<Object> accessors = it->GetAccessors();
4357 619174 : if (accessors->IsAccessorInfo() &&
4358 549563 : !it->HolderIsReceiverOrHiddenPrototype() &&
4359 : AccessorInfo::cast(*accessors)->is_special_data_property()) {
4360 713 : *found = false;
4361 : return Nothing<bool>();
4362 : }
4363 407859 : return SetPropertyWithAccessor(it, value, should_throw);
4364 : }
4365 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
4366 : // TODO(verwaest): We should throw an exception if holder is receiver.
4367 : return Just(true);
4368 :
4369 : case LookupIterator::DATA:
4370 14669663 : if (it->IsReadOnly()) {
4371 44336 : return WriteToReadOnlyProperty(it, value, should_throw);
4372 : }
4373 14625327 : if (it->HolderIsReceiverOrHiddenPrototype()) {
4374 14479426 : return SetDataProperty(it, value);
4375 : }
4376 : // Fall through.
4377 : case LookupIterator::TRANSITION:
4378 1586531 : *found = false;
4379 : return Nothing<bool>();
4380 : }
4381 312937 : it->Next();
4382 : } while (it->IsFound());
4383 :
4384 154928 : *found = false;
4385 : return Nothing<bool>();
4386 : }
4387 :
4388 :
4389 35771073 : Maybe<bool> Object::SetProperty(LookupIterator* it, Handle<Object> value,
4390 : LanguageMode language_mode,
4391 : StoreFromKeyed store_mode) {
4392 35769223 : if (it->IsFound()) {
4393 16675299 : bool found = true;
4394 : Maybe<bool> result =
4395 16675299 : SetPropertyInternal(it, value, language_mode, store_mode, &found);
4396 16675299 : if (found) return result;
4397 : }
4398 :
4399 : // If the receiver is the JSGlobalObject, the store was contextual. In case
4400 : // the property did not exist yet on the global object itself, we have to
4401 : // throw a reference error in strict mode. In sloppy mode, we continue.
4402 35876037 : if (is_strict(language_mode) && it->GetReceiver()->IsJSGlobalObject()) {
4403 : it->isolate()->Throw(*it->isolate()->factory()->NewReferenceError(
4404 1850 : MessageTemplate::kNotDefined, it->name()));
4405 : return Nothing<bool>();
4406 : }
4407 :
4408 : ShouldThrow should_throw =
4409 20832002 : is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4410 20832002 : return AddDataProperty(it, value, NONE, should_throw, store_mode);
4411 : }
4412 :
4413 :
4414 81956 : Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
4415 : LanguageMode language_mode,
4416 : StoreFromKeyed store_mode) {
4417 : Isolate* isolate = it->isolate();
4418 :
4419 73680 : if (it->IsFound()) {
4420 67606 : bool found = true;
4421 : Maybe<bool> result =
4422 67606 : SetPropertyInternal(it, value, language_mode, store_mode, &found);
4423 67606 : if (found) return result;
4424 : }
4425 :
4426 9410 : it->UpdateProtector();
4427 :
4428 : // The property either doesn't exist on the holder or exists there as a data
4429 : // property.
4430 :
4431 : ShouldThrow should_throw =
4432 9410 : is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4433 :
4434 9410 : if (!it->GetReceiver()->IsJSReceiver()) {
4435 1134 : return WriteToReadOnlyProperty(it, value, should_throw);
4436 : }
4437 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
4438 :
4439 : LookupIterator::Configuration c = LookupIterator::OWN;
4440 : LookupIterator own_lookup =
4441 : it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c)
4442 16552 : : LookupIterator(receiver, it->name(), c);
4443 :
4444 28 : for (; own_lookup.IsFound(); own_lookup.Next()) {
4445 6162 : switch (own_lookup.state()) {
4446 : case LookupIterator::ACCESS_CHECK:
4447 34 : if (!own_lookup.HasAccess()) {
4448 : return JSObject::SetPropertyWithFailedAccessCheck(&own_lookup, value,
4449 6 : should_throw);
4450 : }
4451 : break;
4452 :
4453 : case LookupIterator::ACCESSOR:
4454 3052 : if (own_lookup.GetAccessors()->IsAccessorInfo()) {
4455 14 : if (own_lookup.IsReadOnly()) {
4456 0 : return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
4457 : }
4458 : return JSObject::SetPropertyWithAccessor(&own_lookup, value,
4459 14 : should_throw);
4460 : }
4461 : // Fall through.
4462 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
4463 : return RedefineIncompatibleProperty(isolate, it->GetName(), value,
4464 3024 : should_throw);
4465 :
4466 : case LookupIterator::DATA: {
4467 1526 : if (own_lookup.IsReadOnly()) {
4468 462 : return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
4469 : }
4470 1064 : return SetDataProperty(&own_lookup, value);
4471 : }
4472 :
4473 : case LookupIterator::INTERCEPTOR:
4474 : case LookupIterator::JSPROXY: {
4475 : PropertyDescriptor desc;
4476 : Maybe<bool> owned =
4477 3076 : JSReceiver::GetOwnPropertyDescriptor(&own_lookup, &desc);
4478 3076 : MAYBE_RETURN(owned, Nothing<bool>());
4479 2376 : if (!owned.FromJust()) {
4480 : return JSReceiver::CreateDataProperty(&own_lookup, value,
4481 1057 : should_throw);
4482 : }
4483 2638 : if (PropertyDescriptor::IsAccessorDescriptor(&desc) ||
4484 : !desc.writable()) {
4485 : return RedefineIncompatibleProperty(isolate, it->GetName(), value,
4486 0 : should_throw);
4487 : }
4488 :
4489 : PropertyDescriptor value_desc;
4490 : value_desc.set_value(value);
4491 : return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
4492 2638 : &value_desc, should_throw);
4493 : }
4494 :
4495 : case LookupIterator::NOT_FOUND:
4496 : case LookupIterator::TRANSITION:
4497 0 : UNREACHABLE();
4498 : }
4499 : }
4500 :
4501 2142 : return AddDataProperty(&own_lookup, value, NONE, should_throw, store_mode);
4502 : }
4503 :
4504 9541 : Maybe<bool> Object::CannotCreateProperty(Isolate* isolate,
4505 : Handle<Object> receiver,
4506 : Handle<Object> name,
4507 : Handle<Object> value,
4508 : ShouldThrow should_throw) {
4509 9917 : RETURN_FAILURE(
4510 : isolate, should_throw,
4511 : NewTypeError(MessageTemplate::kStrictCannotCreateProperty, name,
4512 : Object::TypeOf(isolate, receiver), receiver));
4513 : }
4514 :
4515 :
4516 97166 : Maybe<bool> Object::WriteToReadOnlyProperty(LookupIterator* it,
4517 : Handle<Object> value,
4518 : ShouldThrow should_throw) {
4519 : return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(),
4520 97166 : it->GetName(), value, should_throw);
4521 : }
4522 :
4523 :
4524 48583 : Maybe<bool> Object::WriteToReadOnlyProperty(Isolate* isolate,
4525 : Handle<Object> receiver,
4526 : Handle<Object> name,
4527 : Handle<Object> value,
4528 : ShouldThrow should_throw) {
4529 79245 : RETURN_FAILURE(isolate, should_throw,
4530 : NewTypeError(MessageTemplate::kStrictReadOnlyProperty, name,
4531 : Object::TypeOf(isolate, receiver), receiver));
4532 : }
4533 :
4534 :
4535 1527 : Maybe<bool> Object::RedefineIncompatibleProperty(Isolate* isolate,
4536 : Handle<Object> name,
4537 : Handle<Object> value,
4538 : ShouldThrow should_throw) {
4539 1893 : RETURN_FAILURE(isolate, should_throw,
4540 : NewTypeError(MessageTemplate::kRedefineDisallowed, name));
4541 : }
4542 :
4543 :
4544 30968522 : Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) {
4545 : // Proxies are handled elsewhere. Other non-JSObjects cannot have own
4546 : // properties.
4547 : Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
4548 :
4549 : // Store on the holder which may be hidden behind the receiver.
4550 : DCHECK(it->HolderIsReceiverOrHiddenPrototype());
4551 :
4552 15480531 : Handle<Object> to_assign = value;
4553 : // Convert the incoming value to a number for storing into typed arrays.
4554 16806606 : if (it->IsElement() && receiver->HasFixedTypedArrayElements()) {
4555 1152847 : if (!value->IsNumber() && !value->IsUndefined(it->isolate())) {
4556 5292 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4557 : it->isolate(), to_assign, Object::ToNumber(value), Nothing<bool>());
4558 : // We have to recheck the length. However, it can only change if the
4559 : // underlying buffer was neutered, so just check that.
4560 2646 : if (Handle<JSArrayBufferView>::cast(receiver)->WasNeutered()) {
4561 : return Just(true);
4562 : // TODO(neis): According to the spec, this should throw a TypeError.
4563 : }
4564 : }
4565 : }
4566 :
4567 : // Possibly migrate to the most up-to-date map that will be able to store
4568 : // |value| under it->name().
4569 15480531 : it->PrepareForDataProperty(to_assign);
4570 :
4571 : // Write the property value.
4572 15480531 : it->WriteDataValue(to_assign, false);
4573 :
4574 : #if VERIFY_HEAP
4575 : if (FLAG_verify_heap) {
4576 : receiver->JSObjectVerify();
4577 : }
4578 : #endif
4579 : return Just(true);
4580 : }
4581 :
4582 :
4583 172996110 : Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value,
4584 : PropertyAttributes attributes,
4585 : ShouldThrow should_throw,
4586 : StoreFromKeyed store_mode) {
4587 55988259 : if (!it->GetReceiver()->IsJSObject()) {
4588 9625 : if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate()) {
4589 70 : RETURN_FAILURE(it->isolate(), should_throw,
4590 : NewTypeError(MessageTemplate::kProxyPrivate));
4591 : }
4592 : return CannotCreateProperty(it->isolate(), it->GetReceiver(), it->GetName(),
4593 19082 : value, should_throw);
4594 : }
4595 :
4596 : DCHECK_NE(LookupIterator::INTEGER_INDEXED_EXOTIC, it->state());
4597 :
4598 55978676 : Handle<JSObject> receiver = it->GetStoreTarget();
4599 :
4600 : // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject)
4601 : // instead. If the prototype is Null, the proxy is detached.
4602 55978630 : if (receiver->IsJSGlobalProxy()) return Just(true);
4603 :
4604 : Isolate* isolate = it->isolate();
4605 :
4606 55978630 : if (it->ExtendingNonExtensible(receiver)) {
4607 607516 : RETURN_FAILURE(
4608 : isolate, should_throw,
4609 : NewTypeError(MessageTemplate::kObjectNotExtensible, it->GetName()));
4610 : }
4611 :
4612 55823389 : if (it->IsElement()) {
4613 3678050 : if (receiver->IsJSArray()) {
4614 : Handle<JSArray> array = Handle<JSArray>::cast(receiver);
4615 1518673 : if (JSArray::WouldChangeReadOnlyLength(array, it->index())) {
4616 1719 : RETURN_FAILURE(array->GetIsolate(), should_throw,
4617 : NewTypeError(MessageTemplate::kStrictReadOnlyProperty,
4618 : isolate->factory()->length_string(),
4619 : Object::TypeOf(isolate, array), array));
4620 : }
4621 :
4622 1518211 : if (FLAG_trace_external_array_abuse &&
4623 0 : array->HasFixedTypedArrayElements()) {
4624 0 : CheckArrayAbuse(array, "typed elements write", it->index(), true);
4625 : }
4626 :
4627 1518211 : if (FLAG_trace_js_array_abuse && !array->HasFixedTypedArrayElements()) {
4628 0 : CheckArrayAbuse(array, "elements write", it->index(), false);
4629 : }
4630 : }
4631 :
4632 : Maybe<bool> result = JSObject::AddDataElement(receiver, it->index(), value,
4633 3677588 : attributes, should_throw);
4634 : JSObject::ValidateElements(receiver);
4635 3677588 : return result;
4636 : } else {
4637 52145339 : it->UpdateProtector();
4638 : // Migrate to the most up-to-date map that will be able to store |value|
4639 : // under it->name() with |attributes|.
4640 : it->PrepareTransitionToDataProperty(receiver, value, attributes,
4641 52145351 : store_mode);
4642 : DCHECK_EQ(LookupIterator::TRANSITION, it->state());
4643 52145379 : it->ApplyTransitionToDataProperty(receiver);
4644 :
4645 : // Write the property value.
4646 52145354 : it->WriteDataValue(value, true);
4647 :
4648 : #if VERIFY_HEAP
4649 : if (FLAG_verify_heap) {
4650 : receiver->JSObjectVerify();
4651 : }
4652 : #endif
4653 : }
4654 :
4655 : return Just(true);
4656 : }
4657 :
4658 :
4659 5827916 : void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
4660 : // Only supports adding slack to owned descriptors.
4661 : DCHECK(map->owns_descriptors());
4662 :
4663 : Handle<DescriptorArray> descriptors(map->instance_descriptors());
4664 : int old_size = map->NumberOfOwnDescriptors();
4665 5827916 : if (slack <= descriptors->NumberOfSlackDescriptors()) return;
4666 :
4667 : Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
4668 : descriptors, old_size, slack);
4669 :
4670 : DisallowHeapAllocation no_allocation;
4671 : // The descriptors are still the same, so keep the layout descriptor.
4672 : LayoutDescriptor* layout_descriptor = map->GetLayoutDescriptor();
4673 :
4674 5827915 : if (old_size == 0) {
4675 2669 : map->UpdateDescriptors(*new_descriptors, layout_descriptor);
4676 2669 : return;
4677 : }
4678 :
4679 : // If the source descriptors had an enum cache we copy it. This ensures
4680 : // that the maps to which we push the new descriptor array back can rely
4681 : // on a cache always being available once it is set. If the map has more
4682 : // enumerated descriptors than available in the original cache, the cache
4683 : // will be lazily replaced by the extended cache when needed.
4684 5825246 : if (descriptors->HasEnumCache()) {
4685 36785 : new_descriptors->CopyEnumCacheFrom(*descriptors);
4686 : }
4687 :
4688 : Isolate* isolate = map->GetIsolate();
4689 : // Replace descriptors by new_descriptors in all maps that share it.
4690 5825246 : isolate->heap()->incremental_marking()->IterateBlackObject(*descriptors);
4691 :
4692 : Map* current = *map;
4693 49662079 : while (current->instance_descriptors() == *descriptors) {
4694 38012161 : Object* next = current->GetBackPointer();
4695 38012166 : if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map.
4696 38011591 : current->UpdateDescriptors(*new_descriptors, layout_descriptor);
4697 : current = Map::cast(next);
4698 : }
4699 5825246 : map->UpdateDescriptors(*new_descriptors, layout_descriptor);
4700 : }
4701 :
4702 : // static
4703 189387 : Handle<Map> Map::GetObjectCreateMap(Handle<HeapObject> prototype) {
4704 : Isolate* isolate = prototype->GetIsolate();
4705 : Handle<Map> map(isolate->native_context()->object_function()->initial_map(),
4706 378774 : isolate);
4707 189387 : if (map->prototype() == *prototype) return map;
4708 189358 : if (prototype->IsNull(isolate)) {
4709 559 : return isolate->slow_object_with_null_prototype_map();
4710 : }
4711 188799 : if (prototype->IsJSObject()) {
4712 : Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype);
4713 187691 : if (!js_prototype->map()->is_prototype_map()) {
4714 183660 : JSObject::OptimizeAsPrototype(js_prototype, FAST_PROTOTYPE);
4715 : }
4716 : Handle<PrototypeInfo> info =
4717 187691 : Map::GetOrCreatePrototypeInfo(js_prototype, isolate);
4718 : // TODO(verwaest): Use inobject slack tracking for this map.
4719 187691 : if (info->HasObjectCreateMap()) {
4720 : map = handle(info->ObjectCreateMap(), isolate);
4721 : } else {
4722 187630 : map = Map::CopyInitialMap(map);
4723 187630 : Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
4724 187630 : PrototypeInfo::SetObjectCreateMap(info, map);
4725 : }
4726 187691 : return map;
4727 : }
4728 :
4729 1108 : return Map::TransitionToPrototype(map, prototype, REGULAR_PROTOTYPE);
4730 : }
4731 :
4732 : template <class T>
4733 63263 : static int AppendUniqueCallbacks(Handle<TemplateList> callbacks,
4734 : Handle<typename T::Array> array,
4735 : int valid_descriptors) {
4736 : int nof_callbacks = callbacks->length();
4737 :
4738 : Isolate* isolate = array->GetIsolate();
4739 : // Ensure the keys are unique names before writing them into the
4740 : // instance descriptor. Since it may cause a GC, it has to be done before we
4741 : // temporarily put the heap in an invalid state while appending descriptors.
4742 190118 : for (int i = 0; i < nof_callbacks; ++i) {
4743 : Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
4744 64167 : if (entry->name()->IsUniqueName()) continue;
4745 : Handle<String> key =
4746 : isolate->factory()->InternalizeString(
4747 63017 : Handle<String>(String::cast(entry->name())));
4748 63017 : entry->set_name(*key);
4749 : }
4750 :
4751 : // Fill in new callback descriptors. Process the callbacks from
4752 : // back to front so that the last callback with a given name takes
4753 : // precedence over previously added callbacks with that name.
4754 126855 : for (int i = nof_callbacks - 1; i >= 0; i--) {
4755 : Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
4756 : Handle<Name> key(Name::cast(entry->name()));
4757 : // Check if a descriptor with this name already exists before writing.
4758 63592 : if (!T::Contains(key, entry, valid_descriptors, array)) {
4759 0 : T::Insert(key, entry, valid_descriptors, array);
4760 63578 : valid_descriptors++;
4761 : }
4762 : }
4763 :
4764 63263 : return valid_descriptors;
4765 : }
4766 :
4767 : struct DescriptorArrayAppender {
4768 : typedef DescriptorArray Array;
4769 : static bool Contains(Handle<Name> key,
4770 : Handle<AccessorInfo> entry,
4771 : int valid_descriptors,
4772 : Handle<DescriptorArray> array) {
4773 : DisallowHeapAllocation no_gc;
4774 : return array->Search(*key, valid_descriptors) != DescriptorArray::kNotFound;
4775 : }
4776 0 : static void Insert(Handle<Name> key,
4777 : Handle<AccessorInfo> entry,
4778 : int valid_descriptors,
4779 : Handle<DescriptorArray> array) {
4780 : DisallowHeapAllocation no_gc;
4781 : Descriptor d =
4782 : Descriptor::AccessorConstant(key, entry, entry->property_attributes());
4783 0 : array->Append(&d);
4784 0 : }
4785 : };
4786 :
4787 :
4788 : struct FixedArrayAppender {
4789 : typedef FixedArray Array;
4790 63592 : static bool Contains(Handle<Name> key,
4791 : Handle<AccessorInfo> entry,
4792 : int valid_descriptors,
4793 : Handle<FixedArray> array) {
4794 609 : for (int i = 0; i < valid_descriptors; i++) {
4795 623 : if (*key == AccessorInfo::cast(array->get(i))->name()) return true;
4796 : }
4797 : return false;
4798 : }
4799 : static void Insert(Handle<Name> key,
4800 : Handle<AccessorInfo> entry,
4801 : int valid_descriptors,
4802 : Handle<FixedArray> array) {
4803 : DisallowHeapAllocation no_gc;
4804 63578 : array->set(valid_descriptors, *entry);
4805 : }
4806 : };
4807 :
4808 :
4809 0 : void Map::AppendCallbackDescriptors(Handle<Map> map,
4810 : Handle<Object> descriptors) {
4811 : int nof = map->NumberOfOwnDescriptors();
4812 : Handle<DescriptorArray> array(map->instance_descriptors());
4813 0 : Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors);
4814 : DCHECK_GE(array->NumberOfSlackDescriptors(), callbacks->length());
4815 0 : nof = AppendUniqueCallbacks<DescriptorArrayAppender>(callbacks, array, nof);
4816 : map->SetNumberOfOwnDescriptors(nof);
4817 0 : }
4818 :
4819 :
4820 63263 : int AccessorInfo::AppendUnique(Handle<Object> descriptors,
4821 : Handle<FixedArray> array,
4822 : int valid_descriptors) {
4823 63263 : Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors);
4824 : DCHECK_GE(array->length(), callbacks->length() + valid_descriptors);
4825 : return AppendUniqueCallbacks<FixedArrayAppender>(callbacks, array,
4826 63263 : valid_descriptors);
4827 : }
4828 :
4829 :
4830 316343 : static bool ContainsMap(MapHandleList* maps, Map* map) {
4831 : DCHECK_NOT_NULL(map);
4832 486083 : for (int i = 0; i < maps->length(); ++i) {
4833 391740 : if (!maps->at(i).is_null() && *maps->at(i) == map) return true;
4834 : }
4835 : return false;
4836 : }
4837 :
4838 95612 : Map* Map::FindElementsKindTransitionedMap(MapHandleList* candidates) {
4839 : DisallowHeapAllocation no_allocation;
4840 : DisallowDeoptimization no_deoptimization(GetIsolate());
4841 :
4842 : ElementsKind kind = elements_kind();
4843 : bool packed = IsFastPackedElementsKind(kind);
4844 :
4845 : Map* transition = nullptr;
4846 95612 : if (IsTransitionableFastElementsKind(kind)) {
4847 : // Check the state of the root map.
4848 47616 : Map* root_map = FindRootMap();
4849 47616 : if (!EquivalentToForTransition(root_map)) return nullptr;
4850 : root_map = root_map->LookupElementsTransitionMap(kind);
4851 : DCHECK_NOT_NULL(root_map);
4852 : // Starting from the next existing elements kind transition try to
4853 : // replay the property transitions that does not involve instance rewriting
4854 : // (ElementsTransitionAndStoreStub does not support that).
4855 246388 : for (root_map = root_map->ElementsTransitionMap();
4856 352839 : root_map != nullptr && root_map->has_fast_elements();
4857 : root_map = root_map->ElementsTransitionMap()) {
4858 151156 : Map* current = root_map->TryReplayPropertyTransitions(this);
4859 151156 : if (current == nullptr) continue;
4860 146633 : if (InstancesNeedRewriting(current)) continue;
4861 :
4862 293206 : if (ContainsMap(candidates, current) &&
4863 5008 : (packed || !IsFastPackedElementsKind(current->elements_kind()))) {
4864 : transition = current;
4865 46837 : packed = packed && IsFastPackedElementsKind(current->elements_kind());
4866 : }
4867 : }
4868 : }
4869 95612 : return transition;
4870 : }
4871 :
4872 :
4873 1575926 : static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
4874 : // Ensure we are requested to search elements kind transition "near the root".
4875 : DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(),
4876 : map->NumberOfOwnDescriptors());
4877 : Map* current_map = map;
4878 :
4879 : ElementsKind kind = map->elements_kind();
4880 5510912 : while (kind != to_kind) {
4881 : Map* next_map = current_map->ElementsTransitionMap();
4882 2620972 : if (next_map == nullptr) return current_map;
4883 : kind = next_map->elements_kind();
4884 : current_map = next_map;
4885 : }
4886 :
4887 : DCHECK_EQ(to_kind, current_map->elements_kind());
4888 : return current_map;
4889 : }
4890 :
4891 :
4892 0 : Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) {
4893 47634 : Map* to_map = FindClosestElementsTransition(this, to_kind);
4894 47634 : if (to_map->elements_kind() == to_kind) return to_map;
4895 : return nullptr;
4896 : }
4897 :
4898 :
4899 416144 : bool Map::IsMapInArrayPrototypeChain() {
4900 : Isolate* isolate = GetIsolate();
4901 832288 : if (isolate->initial_array_prototype()->map() == this) {
4902 : return true;
4903 : }
4904 :
4905 830654 : if (isolate->initial_object_prototype()->map() == this) {
4906 : return true;
4907 : }
4908 :
4909 415083 : return false;
4910 : }
4911 :
4912 :
4913 20613736 : Handle<WeakCell> Map::WeakCellForMap(Handle<Map> map) {
4914 : Isolate* isolate = map->GetIsolate();
4915 20613735 : if (map->weak_cell_cache()->IsWeakCell()) {
4916 8402194 : return Handle<WeakCell>(WeakCell::cast(map->weak_cell_cache()));
4917 : }
4918 12211541 : Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(map);
4919 12211541 : map->set_weak_cell_cache(*weak_cell);
4920 12211542 : return weak_cell;
4921 : }
4922 :
4923 :
4924 261912 : static Handle<Map> AddMissingElementsTransitions(Handle<Map> map,
4925 : ElementsKind to_kind) {
4926 : DCHECK(IsTransitionElementsKind(map->elements_kind()));
4927 :
4928 : Handle<Map> current_map = map;
4929 :
4930 : ElementsKind kind = map->elements_kind();
4931 : TransitionFlag flag;
4932 261912 : if (map->is_prototype_map()) {
4933 : flag = OMIT_TRANSITION;
4934 : } else {
4935 : flag = INSERT_TRANSITION;
4936 259586 : if (IsFastElementsKind(kind)) {
4937 536774 : while (kind != to_kind && !IsTerminalElementsKind(kind)) {
4938 10207 : kind = GetNextTransitionElementsKind(kind);
4939 10207 : current_map = Map::CopyAsElementsKind(current_map, kind, flag);
4940 : }
4941 : }
4942 : }
4943 :
4944 : // In case we are exiting the fast elements kind system, just add the map in
4945 : // the end.
4946 261912 : if (kind != to_kind) {
4947 259378 : current_map = Map::CopyAsElementsKind(current_map, to_kind, flag);
4948 : }
4949 :
4950 : DCHECK(current_map->elements_kind() == to_kind);
4951 261912 : return current_map;
4952 : }
4953 :
4954 :
4955 2598719 : Handle<Map> Map::TransitionElementsTo(Handle<Map> map,
4956 : ElementsKind to_kind) {
4957 : ElementsKind from_kind = map->elements_kind();
4958 2598719 : if (from_kind == to_kind) return map;
4959 :
4960 1504183 : Isolate* isolate = map->GetIsolate();
4961 : Context* native_context = isolate->context()->native_context();
4962 1504183 : if (from_kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
4963 532 : if (*map == native_context->fast_aliased_arguments_map()) {
4964 : DCHECK_EQ(SLOW_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
4965 : return handle(native_context->slow_aliased_arguments_map());
4966 : }
4967 1503651 : } else if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
4968 30 : if (*map == native_context->slow_aliased_arguments_map()) {
4969 : DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
4970 : return handle(native_context->fast_aliased_arguments_map());
4971 : }
4972 3004009 : } else if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) {
4973 : // Reuse map transitions for JSArrays.
4974 : DisallowHeapAllocation no_gc;
4975 1037401 : if (native_context->get(Context::ArrayMapIndex(from_kind)) == *map) {
4976 : Object* maybe_transitioned_map =
4977 : native_context->get(Context::ArrayMapIndex(to_kind));
4978 848228 : if (maybe_transitioned_map->IsMap()) {
4979 : return handle(Map::cast(maybe_transitioned_map), isolate);
4980 : }
4981 : }
4982 : }
4983 :
4984 : DCHECK(!map->IsUndefined(isolate));
4985 : // Check if we can go back in the elements kind transition chain.
4986 1282172 : if (IsHoleyElementsKind(from_kind) &&
4987 0 : to_kind == GetPackedElementsKind(from_kind) &&
4988 655483 : map->GetBackPointer()->IsMap() &&
4989 0 : Map::cast(map->GetBackPointer())->elements_kind() == to_kind) {
4990 0 : return handle(Map::cast(map->GetBackPointer()));
4991 : }
4992 :
4993 : bool allow_store_transition = IsTransitionElementsKind(from_kind);
4994 : // Only store fast element maps in ascending generality.
4995 655483 : if (IsFastElementsKind(to_kind)) {
4996 : allow_store_transition =
4997 570539 : allow_store_transition && IsTransitionableFastElementsKind(from_kind) &&
4998 189173 : IsMoreGeneralElementsKindTransition(from_kind, to_kind);
4999 : }
5000 :
5001 655483 : if (!allow_store_transition) {
5002 3035 : return Map::CopyAsElementsKind(map, to_kind, OMIT_TRANSITION);
5003 : }
5004 :
5005 652448 : return Map::ReconfigureElementsKind(map, to_kind);
5006 : }
5007 :
5008 :
5009 : // static
5010 1528292 : Handle<Map> Map::AsElementsKind(Handle<Map> map, ElementsKind kind) {
5011 1528292 : Handle<Map> closest_map(FindClosestElementsTransition(*map, kind));
5012 :
5013 1528292 : if (closest_map->elements_kind() == kind) {
5014 1266380 : return closest_map;
5015 : }
5016 :
5017 261912 : return AddMissingElementsTransitions(closest_map, kind);
5018 : }
5019 :
5020 :
5021 2521477 : Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
5022 : ElementsKind to_kind) {
5023 : Handle<Map> map(object->map());
5024 2521477 : return Map::TransitionElementsTo(map, to_kind);
5025 : }
5026 :
5027 :
5028 188 : void JSProxy::Revoke(Handle<JSProxy> proxy) {
5029 : Isolate* isolate = proxy->GetIsolate();
5030 362 : if (!proxy->IsRevoked()) proxy->set_handler(isolate->heap()->null_value());
5031 : DCHECK(proxy->IsRevoked());
5032 188 : }
5033 :
5034 :
5035 68199 : Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy,
5036 : Handle<Name> name) {
5037 : DCHECK(!name->IsPrivate());
5038 68199 : STACK_CHECK(isolate, Nothing<bool>());
5039 : // 1. (Assert)
5040 : // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
5041 : Handle<Object> handler(proxy->handler(), isolate);
5042 : // 3. If handler is null, throw a TypeError exception.
5043 : // 4. Assert: Type(handler) is Object.
5044 68185 : if (proxy->IsRevoked()) {
5045 : isolate->Throw(*isolate->factory()->NewTypeError(
5046 56 : MessageTemplate::kProxyRevoked, isolate->factory()->has_string()));
5047 : return Nothing<bool>();
5048 : }
5049 : // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
5050 : Handle<JSReceiver> target(proxy->target(), isolate);
5051 : // 6. Let trap be ? GetMethod(handler, "has").
5052 : Handle<Object> trap;
5053 136314 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5054 : isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
5055 : isolate->factory()->has_string()),
5056 : Nothing<bool>());
5057 : // 7. If trap is undefined, then
5058 67947 : if (trap->IsUndefined(isolate)) {
5059 : // 7a. Return target.[[HasProperty]](P).
5060 53258 : return JSReceiver::HasProperty(target, name);
5061 : }
5062 : // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, P»)).
5063 : Handle<Object> trap_result_obj;
5064 : Handle<Object> args[] = {target, name};
5065 29378 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5066 : isolate, trap_result_obj,
5067 : Execution::Call(isolate, trap, handler, arraysize(args), args),
5068 : Nothing<bool>());
5069 14045 : bool boolean_trap_result = trap_result_obj->BooleanValue();
5070 : // 9. If booleanTrapResult is false, then:
5071 14045 : if (!boolean_trap_result) {
5072 : // 9a. Let targetDesc be ? target.[[GetOwnProperty]](P).
5073 : PropertyDescriptor target_desc;
5074 : Maybe<bool> target_found = JSReceiver::GetOwnPropertyDescriptor(
5075 8990 : isolate, target, name, &target_desc);
5076 9032 : MAYBE_RETURN(target_found, Nothing<bool>());
5077 : // 9b. If targetDesc is not undefined, then:
5078 8990 : if (target_found.FromJust()) {
5079 : // 9b i. If targetDesc.[[Configurable]] is false, throw a TypeError
5080 : // exception.
5081 72 : if (!target_desc.configurable()) {
5082 : isolate->Throw(*isolate->factory()->NewTypeError(
5083 56 : MessageTemplate::kProxyHasNonConfigurable, name));
5084 42 : return Nothing<bool>();
5085 : }
5086 : // 9b ii. Let extensibleTarget be ? IsExtensible(target).
5087 44 : Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
5088 44 : MAYBE_RETURN(extensible_target, Nothing<bool>());
5089 : // 9b iii. If extensibleTarget is false, throw a TypeError exception.
5090 44 : if (!extensible_target.FromJust()) {
5091 : isolate->Throw(*isolate->factory()->NewTypeError(
5092 28 : MessageTemplate::kProxyHasNonExtensible, name));
5093 : return Nothing<bool>();
5094 : }
5095 : }
5096 : }
5097 : // 10. Return booleanTrapResult.
5098 : return Just(boolean_trap_result);
5099 : }
5100 :
5101 :
5102 63039 : Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name,
5103 : Handle<Object> value, Handle<Object> receiver,
5104 : LanguageMode language_mode) {
5105 : DCHECK(!name->IsPrivate());
5106 : Isolate* isolate = proxy->GetIsolate();
5107 63039 : STACK_CHECK(isolate, Nothing<bool>());
5108 : Factory* factory = isolate->factory();
5109 : Handle<String> trap_name = factory->set_string();
5110 : ShouldThrow should_throw =
5111 63011 : is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
5112 :
5113 63011 : if (proxy->IsRevoked()) {
5114 : isolate->Throw(
5115 56 : *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
5116 : return Nothing<bool>();
5117 : }
5118 : Handle<JSReceiver> target(proxy->target(), isolate);
5119 : Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
5120 :
5121 : Handle<Object> trap;
5122 125966 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5123 : isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
5124 62507 : if (trap->IsUndefined(isolate)) {
5125 : LookupIterator it =
5126 57942 : LookupIterator::PropertyOrElement(isolate, receiver, name, target);
5127 : return Object::SetSuperProperty(&it, value, language_mode,
5128 57942 : Object::MAY_BE_STORE_FROM_KEYED);
5129 : }
5130 :
5131 : Handle<Object> trap_result;
5132 4565 : Handle<Object> args[] = {target, name, value, receiver};
5133 9130 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5134 : isolate, trap_result,
5135 : Execution::Call(isolate, trap, handler, arraysize(args), args),
5136 : Nothing<bool>());
5137 4061 : if (!trap_result->BooleanValue()) {
5138 869 : RETURN_FAILURE(isolate, should_throw,
5139 : NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
5140 : trap_name, name));
5141 : }
5142 :
5143 : // Enforce the invariant.
5144 : PropertyDescriptor target_desc;
5145 : Maybe<bool> owned =
5146 3332 : JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
5147 3332 : MAYBE_RETURN(owned, Nothing<bool>());
5148 3332 : if (owned.FromJust()) {
5149 1526 : bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
5150 840 : !target_desc.configurable() &&
5151 2646 : !target_desc.writable() &&
5152 560 : !value->SameValue(*target_desc.value());
5153 2086 : if (inconsistent) {
5154 : isolate->Throw(*isolate->factory()->NewTypeError(
5155 560 : MessageTemplate::kProxySetFrozenData, name));
5156 : return Nothing<bool>();
5157 : }
5158 560 : inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
5159 2086 : !target_desc.configurable() &&
5160 : target_desc.set()->IsUndefined(isolate);
5161 1806 : if (inconsistent) {
5162 : isolate->Throw(*isolate->factory()->NewTypeError(
5163 560 : MessageTemplate::kProxySetFrozenAccessor, name));
5164 : return Nothing<bool>();
5165 : }
5166 : }
5167 : return Just(true);
5168 : }
5169 :
5170 :
5171 4817 : Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy,
5172 : Handle<Name> name,
5173 : LanguageMode language_mode) {
5174 : DCHECK(!name->IsPrivate());
5175 : ShouldThrow should_throw =
5176 4817 : is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
5177 : Isolate* isolate = proxy->GetIsolate();
5178 4817 : STACK_CHECK(isolate, Nothing<bool>());
5179 : Factory* factory = isolate->factory();
5180 : Handle<String> trap_name = factory->deleteProperty_string();
5181 :
5182 4817 : if (proxy->IsRevoked()) {
5183 : isolate->Throw(
5184 56 : *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
5185 : return Nothing<bool>();
5186 : }
5187 : Handle<JSReceiver> target(proxy->target(), isolate);
5188 : Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
5189 :
5190 : Handle<Object> trap;
5191 9578 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5192 : isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
5193 4579 : if (trap->IsUndefined(isolate)) {
5194 1261 : return JSReceiver::DeletePropertyOrElement(target, name, language_mode);
5195 : }
5196 :
5197 : Handle<Object> trap_result;
5198 : Handle<Object> args[] = {target, name};
5199 6636 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5200 : isolate, trap_result,
5201 : Execution::Call(isolate, trap, handler, arraysize(args), args),
5202 : Nothing<bool>());
5203 2814 : if (!trap_result->BooleanValue()) {
5204 1932 : RETURN_FAILURE(isolate, should_throw,
5205 : NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
5206 : trap_name, name));
5207 : }
5208 :
5209 : // Enforce the invariant.
5210 : PropertyDescriptor target_desc;
5211 : Maybe<bool> owned =
5212 1638 : JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
5213 1638 : MAYBE_RETURN(owned, Nothing<bool>());
5214 2478 : if (owned.FromJust() && !target_desc.configurable()) {
5215 : isolate->Throw(*factory->NewTypeError(
5216 1120 : MessageTemplate::kProxyDeletePropertyNonConfigurable, name));
5217 : return Nothing<bool>();
5218 : }
5219 : return Just(true);
5220 : }
5221 :
5222 :
5223 : // static
5224 44734 : MaybeHandle<JSProxy> JSProxy::New(Isolate* isolate, Handle<Object> target,
5225 : Handle<Object> handler) {
5226 44734 : if (!target->IsJSReceiver()) {
5227 30 : THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5228 : JSProxy);
5229 : }
5230 49761 : if (target->IsJSProxy() && JSProxy::cast(*target)->IsRevoked()) {
5231 0 : THROW_NEW_ERROR(isolate,
5232 : NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5233 : JSProxy);
5234 : }
5235 44719 : if (!handler->IsJSReceiver()) {
5236 0 : THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5237 : JSProxy);
5238 : }
5239 52139 : if (handler->IsJSProxy() && JSProxy::cast(*handler)->IsRevoked()) {
5240 0 : THROW_NEW_ERROR(isolate,
5241 : NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5242 : JSProxy);
5243 : }
5244 : return isolate->factory()->NewJSProxy(Handle<JSReceiver>::cast(target),
5245 44719 : Handle<JSReceiver>::cast(handler));
5246 : }
5247 :
5248 :
5249 : // static
5250 29 : MaybeHandle<Context> JSProxy::GetFunctionRealm(Handle<JSProxy> proxy) {
5251 : DCHECK(proxy->map()->is_constructor());
5252 29 : if (proxy->IsRevoked()) {
5253 0 : THROW_NEW_ERROR(proxy->GetIsolate(),
5254 : NewTypeError(MessageTemplate::kProxyRevoked), Context);
5255 : }
5256 : Handle<JSReceiver> target(JSReceiver::cast(proxy->target()));
5257 29 : return JSReceiver::GetFunctionRealm(target);
5258 : }
5259 :
5260 :
5261 : // static
5262 0 : MaybeHandle<Context> JSBoundFunction::GetFunctionRealm(
5263 : Handle<JSBoundFunction> function) {
5264 : DCHECK(function->map()->is_constructor());
5265 : return JSReceiver::GetFunctionRealm(
5266 0 : handle(function->bound_target_function()));
5267 : }
5268 :
5269 : // static
5270 341 : MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate,
5271 : Handle<JSBoundFunction> function) {
5272 : Handle<String> prefix = isolate->factory()->bound__string();
5273 341 : if (!function->bound_target_function()->IsJSFunction()) return prefix;
5274 : Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()),
5275 : isolate);
5276 341 : Handle<Object> target_name = JSFunction::GetName(isolate, target);
5277 341 : if (!target_name->IsString()) return prefix;
5278 : Factory* factory = isolate->factory();
5279 341 : return factory->NewConsString(prefix, Handle<String>::cast(target_name));
5280 : }
5281 :
5282 : // static
5283 145679 : Handle<Object> JSFunction::GetName(Isolate* isolate,
5284 : Handle<JSFunction> function) {
5285 145679 : if (function->shared()->name_should_print_as_anonymous()) {
5286 0 : return isolate->factory()->anonymous_string();
5287 : }
5288 : return handle(function->shared()->name(), isolate);
5289 : }
5290 :
5291 : // static
5292 24391 : MaybeHandle<Smi> JSFunction::GetLength(Isolate* isolate,
5293 : Handle<JSFunction> function) {
5294 : int length = 0;
5295 24391 : if (function->shared()->is_compiled()) {
5296 : length = function->shared()->GetLength();
5297 : } else {
5298 : // If the function isn't compiled yet, the length is not computed
5299 : // correctly yet. Compile it now and return the right length.
5300 2141 : if (Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) {
5301 : length = function->shared()->GetLength();
5302 : }
5303 2141 : if (isolate->has_pending_exception()) return MaybeHandle<Smi>();
5304 : }
5305 : DCHECK_GE(length, 0);
5306 : return handle(Smi::FromInt(length), isolate);
5307 : }
5308 :
5309 : // static
5310 4331 : Handle<Context> JSFunction::GetFunctionRealm(Handle<JSFunction> function) {
5311 : DCHECK(function->map()->is_constructor());
5312 4331 : return handle(function->context()->native_context());
5313 : }
5314 :
5315 :
5316 : // static
5317 0 : MaybeHandle<Context> JSObject::GetFunctionRealm(Handle<JSObject> object) {
5318 : DCHECK(object->map()->is_constructor());
5319 : DCHECK(!object->IsJSFunction());
5320 0 : return object->GetCreationContext();
5321 : }
5322 :
5323 :
5324 : // static
5325 4360 : MaybeHandle<Context> JSReceiver::GetFunctionRealm(Handle<JSReceiver> receiver) {
5326 4360 : if (receiver->IsJSProxy()) {
5327 29 : return JSProxy::GetFunctionRealm(Handle<JSProxy>::cast(receiver));
5328 : }
5329 :
5330 4331 : if (receiver->IsJSFunction()) {
5331 4331 : return JSFunction::GetFunctionRealm(Handle<JSFunction>::cast(receiver));
5332 : }
5333 :
5334 0 : if (receiver->IsJSBoundFunction()) {
5335 : return JSBoundFunction::GetFunctionRealm(
5336 0 : Handle<JSBoundFunction>::cast(receiver));
5337 : }
5338 :
5339 : return JSObject::GetFunctionRealm(Handle<JSObject>::cast(receiver));
5340 : }
5341 :
5342 :
5343 4940 : Maybe<PropertyAttributes> JSProxy::GetPropertyAttributes(LookupIterator* it) {
5344 : PropertyDescriptor desc;
5345 : Maybe<bool> found = JSProxy::GetOwnPropertyDescriptor(
5346 4940 : it->isolate(), it->GetHolder<JSProxy>(), it->GetName(), &desc);
5347 2470 : MAYBE_RETURN(found, Nothing<PropertyAttributes>());
5348 2005 : if (!found.FromJust()) return Just(ABSENT);
5349 1766 : return Just(desc.ToAttributes());
5350 : }
5351 :
5352 :
5353 9945177 : void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
5354 : DCHECK(object->map()->GetInObjectProperties() ==
5355 : map->GetInObjectProperties());
5356 : ElementsKind obj_kind = object->map()->elements_kind();
5357 : ElementsKind map_kind = map->elements_kind();
5358 9945177 : if (map_kind != obj_kind) {
5359 : ElementsKind to_kind = GetMoreGeneralElementsKind(map_kind, obj_kind);
5360 60 : if (IsDictionaryElementsKind(obj_kind)) {
5361 : to_kind = obj_kind;
5362 : }
5363 60 : if (IsDictionaryElementsKind(to_kind)) {
5364 45 : NormalizeElements(object);
5365 : } else {
5366 15 : TransitionElementsKind(object, to_kind);
5367 : }
5368 60 : map = Map::ReconfigureElementsKind(map, to_kind);
5369 : }
5370 9945177 : JSObject::MigrateToMap(object, map);
5371 9945177 : }
5372 :
5373 :
5374 9760 : void JSObject::MigrateInstance(Handle<JSObject> object) {
5375 : Handle<Map> original_map(object->map());
5376 9760 : Handle<Map> map = Map::Update(original_map);
5377 : map->set_migration_target(true);
5378 9760 : MigrateToMap(object, map);
5379 9760 : if (FLAG_trace_migration) {
5380 0 : object->PrintInstanceMigration(stdout, *original_map, *map);
5381 : }
5382 : #if VERIFY_HEAP
5383 : if (FLAG_verify_heap) {
5384 : object->JSObjectVerify();
5385 : }
5386 : #endif
5387 9760 : }
5388 :
5389 :
5390 : // static
5391 8224 : bool JSObject::TryMigrateInstance(Handle<JSObject> object) {
5392 : Isolate* isolate = object->GetIsolate();
5393 : DisallowDeoptimization no_deoptimization(isolate);
5394 : Handle<Map> original_map(object->map(), isolate);
5395 : Handle<Map> new_map;
5396 16448 : if (!Map::TryUpdate(original_map).ToHandle(&new_map)) {
5397 : return false;
5398 : }
5399 8196 : JSObject::MigrateToMap(object, new_map);
5400 8196 : if (FLAG_trace_migration && *original_map != object->map()) {
5401 0 : object->PrintInstanceMigration(stdout, *original_map, object->map());
5402 : }
5403 : #if VERIFY_HEAP
5404 : if (FLAG_verify_heap) {
5405 : object->JSObjectVerify();
5406 : }
5407 : #endif
5408 : return true;
5409 : }
5410 :
5411 :
5412 17973289 : void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name,
5413 : Handle<Object> value,
5414 : PropertyAttributes attributes) {
5415 17973289 : LookupIterator it(object, name, object, LookupIterator::OWN_SKIP_INTERCEPTOR);
5416 17973293 : CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
5417 : #ifdef DEBUG
5418 : uint32_t index;
5419 : DCHECK(!object->IsJSProxy());
5420 : DCHECK(!name->AsArrayIndex(&index));
5421 : Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
5422 : DCHECK(maybe.IsJust());
5423 : DCHECK(!it.IsFound());
5424 : DCHECK(object->map()->is_extensible() || name->IsPrivate());
5425 : #endif
5426 17973293 : CHECK(AddDataProperty(&it, value, attributes, THROW_ON_ERROR,
5427 : CERTAINLY_NOT_STORE_FROM_KEYED)
5428 : .IsJust());
5429 17973282 : }
5430 :
5431 :
5432 : // Reconfigures a property to a data property with attributes, even if it is not
5433 : // reconfigurable.
5434 : // Requires a LookupIterator that does not look at the prototype chain beyond
5435 : // hidden prototypes.
5436 2305905 : MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes(
5437 : LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
5438 : AccessorInfoHandling handling) {
5439 16414810 : MAYBE_RETURN_NULL(DefineOwnPropertyIgnoreAttributes(
5440 : it, value, attributes, THROW_ON_ERROR, handling));
5441 : return value;
5442 : }
5443 :
5444 :
5445 16749027 : Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
5446 16785146 : LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
5447 : ShouldThrow should_throw, AccessorInfoHandling handling) {
5448 16749027 : it->UpdateProtector();
5449 : Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
5450 :
5451 33500089 : for (; it->IsFound(); it->Next()) {
5452 2608756 : switch (it->state()) {
5453 : case LookupIterator::JSPROXY:
5454 : case LookupIterator::NOT_FOUND:
5455 : case LookupIterator::TRANSITION:
5456 0 : UNREACHABLE();
5457 :
5458 : case LookupIterator::ACCESS_CHECK:
5459 771 : if (!it->HasAccess()) {
5460 6 : it->isolate()->ReportFailedAccessCheck(it->GetHolder<JSObject>());
5461 6 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
5462 : return Just(true);
5463 : }
5464 : break;
5465 :
5466 : // If there's an interceptor, try to store the property with the
5467 : // interceptor.
5468 : // In case of success, the attributes will have been reset to the default
5469 : // attributes of the interceptor, rather than the incoming attributes.
5470 : //
5471 : // TODO(verwaest): JSProxy afterwards verify the attributes that the
5472 : // JSProxy claims it has, and verifies that they are compatible. If not,
5473 : // they throw. Here we should do the same.
5474 : case LookupIterator::INTERCEPTOR:
5475 259 : if (handling == DONT_FORCE_FIELD) {
5476 : Maybe<bool> result =
5477 259 : JSObject::SetPropertyWithInterceptor(it, should_throw, value);
5478 518 : if (result.IsNothing() || result.FromJust()) return result;
5479 : }
5480 : break;
5481 :
5482 : case LookupIterator::ACCESSOR: {
5483 1572594 : Handle<Object> accessors = it->GetAccessors();
5484 :
5485 : // Special handling for AccessorInfo, which behaves like a data
5486 : // property.
5487 1572594 : if (accessors->IsAccessorInfo() && handling == DONT_FORCE_FIELD) {
5488 : PropertyAttributes current_attributes = it->property_attributes();
5489 : // Ensure the context isn't changed after calling into accessors.
5490 : AssertNoContextChange ncc(it->isolate());
5491 :
5492 : // Update the attributes before calling the setter. The setter may
5493 : // later change the shape of the property.
5494 1571828 : if (current_attributes != attributes) {
5495 78644 : it->TransitionToAccessorPair(accessors, attributes);
5496 : }
5497 :
5498 1571828 : return JSObject::SetPropertyWithAccessor(it, value, should_throw);
5499 : }
5500 :
5501 766 : it->ReconfigureDataProperty(value, attributes);
5502 : return Just(true);
5503 : }
5504 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
5505 : return RedefineIncompatibleProperty(it->isolate(), it->GetName(), value,
5506 30 : should_throw);
5507 :
5508 : case LookupIterator::DATA: {
5509 : // Regular property update if the attributes match.
5510 1035116 : if (it->property_attributes() == attributes) {
5511 1000041 : return SetDataProperty(it, value);
5512 : }
5513 :
5514 : // Special case: properties of typed arrays cannot be reconfigured to
5515 : // non-writable nor to non-enumerable.
5516 67243 : if (it->IsElement() && object->HasFixedTypedArrayElements()) {
5517 : return RedefineIncompatibleProperty(it->isolate(), it->GetName(),
5518 0 : value, should_throw);
5519 : }
5520 :
5521 : // Reconfigure the data property if the attributes mismatch.
5522 35075 : it->ReconfigureDataProperty(value, attributes);
5523 :
5524 : return Just(true);
5525 : }
5526 : }
5527 : }
5528 :
5529 : return AddDataProperty(it, value, attributes, should_throw,
5530 14141288 : CERTAINLY_NOT_STORE_FROM_KEYED);
5531 : }
5532 :
5533 10946720 : MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
5534 : Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
5535 : PropertyAttributes attributes) {
5536 : DCHECK(!value->IsTheHole(object->GetIsolate()));
5537 10946720 : LookupIterator it(object, name, object, LookupIterator::OWN);
5538 10946718 : return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
5539 : }
5540 :
5541 295008 : MaybeHandle<Object> JSObject::SetOwnElementIgnoreAttributes(
5542 : Handle<JSObject> object, uint32_t index, Handle<Object> value,
5543 : PropertyAttributes attributes) {
5544 : Isolate* isolate = object->GetIsolate();
5545 : LookupIterator it(isolate, object, index, object, LookupIterator::OWN);
5546 295008 : return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
5547 : }
5548 :
5549 2016815 : MaybeHandle<Object> JSObject::DefinePropertyOrElementIgnoreAttributes(
5550 : Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
5551 : PropertyAttributes attributes) {
5552 : Isolate* isolate = object->GetIsolate();
5553 : LookupIterator it = LookupIterator::PropertyOrElement(
5554 2016815 : isolate, object, name, object, LookupIterator::OWN);
5555 2016815 : return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
5556 : }
5557 :
5558 281223 : Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
5559 : LookupIterator* it) {
5560 281223 : return GetPropertyAttributesWithInterceptorInternal(it, it->GetInterceptor());
5561 : }
5562 :
5563 10832660 : Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
5564 13995614 : LookupIterator* it) {
5565 27991228 : for (; it->IsFound(); it->Next()) {
5566 10148160 : switch (it->state()) {
5567 : case LookupIterator::NOT_FOUND:
5568 : case LookupIterator::TRANSITION:
5569 0 : UNREACHABLE();
5570 : case LookupIterator::JSPROXY:
5571 1304 : return JSProxy::GetPropertyAttributes(it);
5572 : case LookupIterator::INTERCEPTOR: {
5573 : Maybe<PropertyAttributes> result =
5574 411 : JSObject::GetPropertyAttributesWithInterceptor(it);
5575 466 : if (!result.IsJust()) return result;
5576 411 : if (result.FromJust() != ABSENT) return result;
5577 356 : break;
5578 : }
5579 : case LookupIterator::ACCESS_CHECK:
5580 3162695 : if (it->HasAccess()) break;
5581 97 : return JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
5582 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
5583 : return Just(ABSENT);
5584 : case LookupIterator::ACCESSOR:
5585 : case LookupIterator::DATA:
5586 : return Just(it->property_attributes());
5587 : }
5588 : }
5589 : return Just(ABSENT);
5590 : }
5591 :
5592 :
5593 79 : Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) {
5594 : Handle<FixedArray> array(
5595 79 : isolate->factory()->NewFixedArray(kEntries, TENURED));
5596 79 : return Handle<NormalizedMapCache>::cast(array);
5597 : }
5598 :
5599 :
5600 1082763 : MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map,
5601 : PropertyNormalizationMode mode) {
5602 : DisallowHeapAllocation no_gc;
5603 : Object* value = FixedArray::get(GetIndex(fast_map));
5604 2049898 : if (!value->IsMap() ||
5605 967135 : !Map::cast(value)->EquivalentToForNormalization(*fast_map, mode)) {
5606 : return MaybeHandle<Map>();
5607 : }
5608 : return handle(Map::cast(value));
5609 : }
5610 :
5611 :
5612 329339 : void NormalizedMapCache::Set(Handle<Map> fast_map,
5613 : Handle<Map> normalized_map) {
5614 : DisallowHeapAllocation no_gc;
5615 : DCHECK(normalized_map->is_dictionary_map());
5616 329339 : FixedArray::set(GetIndex(fast_map), *normalized_map);
5617 329339 : }
5618 :
5619 :
5620 76392 : void NormalizedMapCache::Clear() {
5621 : int entries = length();
5622 4965480 : for (int i = 0; i != entries; i++) {
5623 4889088 : set_undefined(i);
5624 : }
5625 76392 : }
5626 :
5627 :
5628 0 : void HeapObject::UpdateMapCodeCache(Handle<HeapObject> object,
5629 : Handle<Name> name,
5630 : Handle<Code> code) {
5631 : Handle<Map> map(object->map());
5632 0 : Map::UpdateCodeCache(map, name, code);
5633 0 : }
5634 :
5635 :
5636 1306883 : void JSObject::NormalizeProperties(Handle<JSObject> object,
5637 : PropertyNormalizationMode mode,
5638 : int expected_additional_properties,
5639 : const char* reason) {
5640 1572995 : if (!object->HasFastProperties()) return;
5641 :
5642 : Handle<Map> map(object->map());
5643 1040771 : Handle<Map> new_map = Map::Normalize(map, mode, reason);
5644 :
5645 1040771 : MigrateToMap(object, new_map, expected_additional_properties);
5646 : }
5647 :
5648 :
5649 791176 : void JSObject::MigrateSlowToFast(Handle<JSObject> object,
5650 : int unused_property_fields,
5651 : const char* reason) {
5652 1188993 : if (object->HasFastProperties()) return;
5653 : DCHECK(!object->IsJSGlobalObject());
5654 : Isolate* isolate = object->GetIsolate();
5655 : Factory* factory = isolate->factory();
5656 : Handle<NameDictionary> dictionary(object->property_dictionary());
5657 :
5658 : // Make sure we preserve dictionary representation if there are too many
5659 : // descriptors.
5660 : int number_of_elements = dictionary->NumberOfElements();
5661 522846 : if (number_of_elements > kMaxNumberOfDescriptors) return;
5662 :
5663 : Handle<FixedArray> iteration_order =
5664 522263 : NameDictionary::IterationIndices(dictionary);
5665 :
5666 : int instance_descriptor_length = iteration_order->length();
5667 : int number_of_fields = 0;
5668 :
5669 : // Compute the length of the instance descriptor.
5670 3719095 : for (int i = 0; i < instance_descriptor_length; i++) {
5671 : int index = Smi::cast(iteration_order->get(i))->value();
5672 : DCHECK(dictionary->IsKey(isolate, dictionary->KeyAt(index)));
5673 :
5674 : PropertyKind kind = dictionary->DetailsAt(index).kind();
5675 3196832 : if (kind == kData) {
5676 : if (FLAG_track_constant_fields) {
5677 : number_of_fields += 1;
5678 : } else {
5679 2745428 : Object* value = dictionary->ValueAt(index);
5680 2745428 : if (!value->IsJSFunction()) {
5681 904111 : number_of_fields += 1;
5682 : }
5683 : }
5684 : }
5685 : }
5686 :
5687 : Handle<Map> old_map(object->map(), isolate);
5688 :
5689 : int inobject_props = old_map->GetInObjectProperties();
5690 :
5691 : // Allocate new map.
5692 522263 : Handle<Map> new_map = Map::CopyDropDescriptors(old_map);
5693 : new_map->set_dictionary_map(false);
5694 :
5695 522263 : NotifyMapChange(old_map, new_map, isolate);
5696 :
5697 : #if TRACE_MAPS
5698 : if (FLAG_trace_maps) {
5699 : PrintF("[TraceMaps: SlowToFast from= %p to= %p reason= %s ]\n",
5700 : reinterpret_cast<void*>(*old_map), reinterpret_cast<void*>(*new_map),
5701 : reason);
5702 : }
5703 : #endif
5704 :
5705 522263 : if (instance_descriptor_length == 0) {
5706 : DisallowHeapAllocation no_gc;
5707 : DCHECK_LE(unused_property_fields, inobject_props);
5708 : // Transform the object.
5709 : new_map->set_unused_property_fields(inobject_props);
5710 128904 : object->synchronized_set_map(*new_map);
5711 257808 : object->set_properties(isolate->heap()->empty_fixed_array());
5712 : // Check that it really works.
5713 : DCHECK(object->HasFastProperties());
5714 : return;
5715 : }
5716 :
5717 : // Allocate the instance descriptor.
5718 : Handle<DescriptorArray> descriptors = DescriptorArray::Allocate(
5719 393359 : isolate, instance_descriptor_length, 0, TENURED);
5720 :
5721 : int number_of_allocated_fields =
5722 393359 : number_of_fields + unused_property_fields - inobject_props;
5723 393359 : if (number_of_allocated_fields < 0) {
5724 : // There is enough inobject space for all fields (including unused).
5725 : number_of_allocated_fields = 0;
5726 121825 : unused_property_fields = inobject_props - number_of_fields;
5727 : }
5728 :
5729 : // Allocate the fixed array for the fields.
5730 : Handle<FixedArray> fields = factory->NewFixedArray(
5731 393359 : number_of_allocated_fields);
5732 :
5733 : // Fill in the instance descriptor and the fields.
5734 : int current_offset = 0;
5735 3590191 : for (int i = 0; i < instance_descriptor_length; i++) {
5736 : int index = Smi::cast(iteration_order->get(i))->value();
5737 : Object* k = dictionary->KeyAt(index);
5738 : DCHECK(dictionary->IsKey(isolate, k));
5739 : // Dictionary keys are internalized upon insertion.
5740 : // TODO(jkummerow): Turn this into a DCHECK if it's not hit in the wild.
5741 3196832 : CHECK(k->IsUniqueName());
5742 : Handle<Name> key(Name::cast(k), isolate);
5743 :
5744 3196832 : Object* value = dictionary->ValueAt(index);
5745 :
5746 : PropertyDetails details = dictionary->DetailsAt(index);
5747 : DCHECK_EQ(kField, details.location());
5748 : DCHECK_EQ(kMutable, details.constness());
5749 :
5750 : Descriptor d;
5751 3196832 : if (details.kind() == kData) {
5752 2745428 : if (!FLAG_track_constant_fields && value->IsJSFunction()) {
5753 : d = Descriptor::DataConstant(key, handle(value, isolate),
5754 1841317 : details.attributes());
5755 : } else {
5756 : d = Descriptor::DataField(
5757 : key, current_offset, details.attributes(), kDefaultFieldConstness,
5758 : // TODO(verwaest): value->OptimalRepresentation();
5759 1808222 : Representation::Tagged(), FieldType::Any(isolate));
5760 : }
5761 : } else {
5762 : DCHECK_EQ(kAccessor, details.kind());
5763 : d = Descriptor::AccessorConstant(key, handle(value, isolate),
5764 451404 : details.attributes());
5765 : }
5766 : details = d.GetDetails();
5767 3196832 : if (details.location() == kField) {
5768 904111 : if (current_offset < inobject_props) {
5769 : object->InObjectPropertyAtPut(current_offset, value,
5770 493645 : UPDATE_WRITE_BARRIER);
5771 : } else {
5772 410466 : int offset = current_offset - inobject_props;
5773 410466 : fields->set(offset, value);
5774 : }
5775 904111 : current_offset += details.field_width_in_words();
5776 : }
5777 3196832 : descriptors->Set(i, &d);
5778 : }
5779 : DCHECK(current_offset == number_of_fields);
5780 :
5781 393359 : descriptors->Sort();
5782 :
5783 : Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
5784 393359 : new_map, descriptors, descriptors->number_of_descriptors());
5785 :
5786 : DisallowHeapAllocation no_gc;
5787 393359 : new_map->InitializeDescriptors(*descriptors, *layout_descriptor);
5788 : new_map->set_unused_property_fields(unused_property_fields);
5789 :
5790 : // Transform the object.
5791 393359 : object->synchronized_set_map(*new_map);
5792 :
5793 393359 : object->set_properties(*fields);
5794 : DCHECK(object->IsJSObject());
5795 :
5796 : // Check that it really works.
5797 : DCHECK(object->HasFastProperties());
5798 : }
5799 :
5800 :
5801 5432 : void JSObject::ResetElements(Handle<JSObject> object) {
5802 : Isolate* isolate = object->GetIsolate();
5803 5432 : CHECK(object->map() != isolate->heap()->sloppy_arguments_elements_map());
5804 5432 : if (object->map()->has_dictionary_elements()) {
5805 : Handle<SeededNumberDictionary> new_elements =
5806 3444 : SeededNumberDictionary::New(isolate, 0);
5807 3444 : object->set_elements(*new_elements);
5808 : } else {
5809 3976 : object->set_elements(object->map()->GetInitialElements());
5810 : }
5811 5432 : }
5812 :
5813 :
5814 126525 : void JSObject::RequireSlowElements(SeededNumberDictionary* dictionary) {
5815 253050 : if (dictionary->requires_slow_elements()) return;
5816 : dictionary->set_requires_slow_elements();
5817 75374 : if (map()->is_prototype_map()) {
5818 : // If this object is a prototype (the callee will check), invalidate any
5819 : // prototype chains involving it.
5820 : InvalidatePrototypeChains(map());
5821 : }
5822 : }
5823 :
5824 :
5825 466454 : Handle<SeededNumberDictionary> JSObject::NormalizeElements(
5826 : Handle<JSObject> object) {
5827 : DCHECK(!object->HasFixedTypedArrayElements());
5828 458557 : Isolate* isolate = object->GetIsolate();
5829 466454 : bool is_arguments = object->HasSloppyArgumentsElements();
5830 : {
5831 : DisallowHeapAllocation no_gc;
5832 : FixedArrayBase* elements = object->elements();
5833 :
5834 466454 : if (is_arguments) {
5835 : FixedArray* parameter_map = FixedArray::cast(elements);
5836 : elements = FixedArrayBase::cast(parameter_map->get(1));
5837 : }
5838 :
5839 466454 : if (elements->IsDictionary()) {
5840 : return handle(SeededNumberDictionary::cast(elements), isolate);
5841 : }
5842 : }
5843 :
5844 : DCHECK(object->HasFastSmiOrObjectElements() ||
5845 : object->HasFastDoubleElements() ||
5846 : object->HasFastArgumentsElements() ||
5847 : object->HasFastStringWrapperElements());
5848 :
5849 : Handle<SeededNumberDictionary> dictionary =
5850 458557 : object->GetElementsAccessor()->Normalize(object);
5851 :
5852 : // Switch to using the dictionary as the backing storage for elements.
5853 : ElementsKind target_kind = is_arguments
5854 : ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS
5855 458025 : : object->HasFastStringWrapperElements()
5856 : ? SLOW_STRING_WRAPPER_ELEMENTS
5857 916582 : : DICTIONARY_ELEMENTS;
5858 458557 : Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind);
5859 : // Set the new map first to satify the elements type assert in set_elements().
5860 458557 : JSObject::MigrateToMap(object, new_map);
5861 :
5862 458557 : if (is_arguments) {
5863 532 : FixedArray::cast(object->elements())->set(1, *dictionary);
5864 : } else {
5865 458025 : object->set_elements(*dictionary);
5866 : }
5867 :
5868 458557 : isolate->counters()->elements_to_dictionary()->Increment();
5869 :
5870 : #ifdef DEBUG
5871 : if (FLAG_trace_normalization) {
5872 : OFStream os(stdout);
5873 : os << "Object elements have been normalized:\n";
5874 : object->Print(os);
5875 : }
5876 : #endif
5877 :
5878 : DCHECK(object->HasDictionaryElements() ||
5879 : object->HasSlowArgumentsElements() ||
5880 : object->HasSlowStringWrapperElements());
5881 458557 : return dictionary;
5882 : }
5883 :
5884 :
5885 : template <typename ProxyType>
5886 3181 : static Smi* GetOrCreateIdentityHashHelper(Isolate* isolate,
5887 : Handle<ProxyType> proxy) {
5888 : Object* maybe_hash = proxy->hash();
5889 3181 : if (maybe_hash->IsSmi()) return Smi::cast(maybe_hash);
5890 :
5891 687 : Smi* hash = Smi::FromInt(isolate->GenerateIdentityHash(Smi::kMaxValue));
5892 687 : proxy->set_hash(hash);
5893 687 : return hash;
5894 : }
5895 :
5896 : // static
5897 20925 : Object* JSObject::GetIdentityHash(Isolate* isolate, Handle<JSObject> object) {
5898 20925 : if (object->IsJSGlobalProxy()) {
5899 82 : return JSGlobalProxy::cast(*object)->hash();
5900 : }
5901 : Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol();
5902 41686 : return *JSReceiver::GetDataProperty(object, hash_code_symbol);
5903 : }
5904 :
5905 : // static
5906 3952 : Smi* JSObject::GetOrCreateIdentityHash(Isolate* isolate,
5907 : Handle<JSObject> object) {
5908 3952 : if (object->IsJSGlobalProxy()) {
5909 : return GetOrCreateIdentityHashHelper(isolate,
5910 87 : Handle<JSGlobalProxy>::cast(object));
5911 : }
5912 :
5913 : Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol();
5914 3865 : LookupIterator it(object, hash_code_symbol, object, LookupIterator::OWN);
5915 3865 : if (it.IsFound()) {
5916 : DCHECK_EQ(LookupIterator::DATA, it.state());
5917 962 : Object* maybe_hash = *it.GetDataValue();
5918 481 : if (maybe_hash->IsSmi()) return Smi::cast(maybe_hash);
5919 : }
5920 :
5921 3384 : Smi* hash = Smi::FromInt(isolate->GenerateIdentityHash(Smi::kMaxValue));
5922 3384 : CHECK(AddDataProperty(&it, handle(hash, isolate), NONE, THROW_ON_ERROR,
5923 : CERTAINLY_NOT_STORE_FROM_KEYED)
5924 : .IsJust());
5925 : return hash;
5926 : }
5927 :
5928 : // static
5929 0 : Object* JSProxy::GetIdentityHash(Handle<JSProxy> proxy) {
5930 0 : return proxy->hash();
5931 : }
5932 :
5933 0 : Smi* JSProxy::GetOrCreateIdentityHash(Isolate* isolate, Handle<JSProxy> proxy) {
5934 3094 : return GetOrCreateIdentityHashHelper(isolate, proxy);
5935 : }
5936 :
5937 :
5938 185 : Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it,
5939 : ShouldThrow should_throw) {
5940 : Isolate* isolate = it->isolate();
5941 : // Make sure that the top context does not change when doing callbacks or
5942 : // interceptor calls.
5943 : AssertNoContextChange ncc(isolate);
5944 :
5945 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
5946 117 : Handle<InterceptorInfo> interceptor(it->GetInterceptor());
5947 117 : if (interceptor->deleter()->IsUndefined(isolate)) return Nothing<bool>();
5948 :
5949 : Handle<JSObject> holder = it->GetHolder<JSObject>();
5950 : Handle<Object> receiver = it->GetReceiver();
5951 68 : if (!receiver->IsJSReceiver()) {
5952 0 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
5953 : Object::ConvertReceiver(isolate, receiver),
5954 : Nothing<bool>());
5955 : }
5956 :
5957 : PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
5958 : *holder, should_throw);
5959 : Handle<Object> result;
5960 68 : if (it->IsElement()) {
5961 : uint32_t index = it->index();
5962 : v8::IndexedPropertyDeleterCallback deleter =
5963 : v8::ToCData<v8::IndexedPropertyDeleterCallback>(interceptor->deleter());
5964 27 : result = args.Call(deleter, index);
5965 : } else {
5966 : DCHECK_IMPLIES(it->name()->IsSymbol(),
5967 : interceptor->can_intercept_symbols());
5968 41 : Handle<Name> name = it->name();
5969 : DCHECK(!name->IsPrivate());
5970 : v8::GenericNamedPropertyDeleterCallback deleter =
5971 : v8::ToCData<v8::GenericNamedPropertyDeleterCallback>(
5972 : interceptor->deleter());
5973 41 : result = args.Call(deleter, name);
5974 : }
5975 :
5976 68 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
5977 68 : if (result.is_null()) return Nothing<bool>();
5978 :
5979 : DCHECK(result->IsBoolean());
5980 : // Rebox CustomArguments::kReturnValueOffset before returning.
5981 : return Just(result->IsTrue(isolate));
5982 : }
5983 :
5984 :
5985 6177375 : void JSReceiver::DeleteNormalizedProperty(Handle<JSReceiver> object,
5986 : Handle<Name> name, int entry) {
5987 : DCHECK(!object->HasFastProperties());
5988 : Isolate* isolate = object->GetIsolate();
5989 :
5990 6177375 : if (object->IsJSGlobalObject()) {
5991 : // If we have a global object, invalidate the cell and swap in a new one.
5992 : Handle<GlobalDictionary> dictionary(
5993 : JSObject::cast(*object)->global_dictionary());
5994 : DCHECK_NE(GlobalDictionary::kNotFound, entry);
5995 :
5996 12243 : auto cell = PropertyCell::InvalidateEntry(dictionary, entry);
5997 24486 : cell->set_value(isolate->heap()->the_hole_value());
5998 : cell->set_property_details(
5999 : PropertyDetails::Empty(PropertyCellType::kUninitialized));
6000 : } else {
6001 : Handle<NameDictionary> dictionary(object->property_dictionary());
6002 : DCHECK_NE(NameDictionary::kNotFound, entry);
6003 :
6004 6165132 : NameDictionary::DeleteProperty(dictionary, entry);
6005 : Handle<NameDictionary> new_properties =
6006 : NameDictionary::Shrink(dictionary, name);
6007 6165132 : object->set_properties(*new_properties);
6008 : }
6009 6177375 : }
6010 :
6011 :
6012 27147935 : Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
6013 : LanguageMode language_mode) {
6014 9045871 : it->UpdateProtector();
6015 :
6016 : Isolate* isolate = it->isolate();
6017 :
6018 9045871 : if (it->state() == LookupIterator::JSPROXY) {
6019 : return JSProxy::DeletePropertyOrElement(it->GetHolder<JSProxy>(),
6020 4817 : it->GetName(), language_mode);
6021 : }
6022 :
6023 9041054 : if (it->GetReceiver()->IsJSProxy()) {
6024 56 : if (it->state() != LookupIterator::NOT_FOUND) {
6025 : DCHECK_EQ(LookupIterator::DATA, it->state());
6026 : DCHECK(it->name()->IsPrivate());
6027 7 : it->Delete();
6028 : }
6029 : return Just(true);
6030 : }
6031 : Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
6032 :
6033 18112274 : for (; it->IsFound(); it->Next()) {
6034 6360279 : switch (it->state()) {
6035 : case LookupIterator::JSPROXY:
6036 : case LookupIterator::NOT_FOUND:
6037 : case LookupIterator::TRANSITION:
6038 0 : UNREACHABLE();
6039 : case LookupIterator::ACCESS_CHECK:
6040 15093 : if (it->HasAccess()) break;
6041 43 : isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
6042 43 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6043 : return Just(false);
6044 : case LookupIterator::INTERCEPTOR: {
6045 : ShouldThrow should_throw =
6046 117 : is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
6047 : Maybe<bool> result =
6048 117 : JSObject::DeletePropertyWithInterceptor(it, should_throw);
6049 : // An exception was thrown in the interceptor. Propagate.
6050 145 : if (isolate->has_pending_exception()) return Nothing<bool>();
6051 : // Delete with interceptor succeeded. Return result.
6052 : // TODO(neis): In strict mode, we should probably throw if the
6053 : // interceptor returns false.
6054 117 : if (result.IsJust()) return result;
6055 89 : break;
6056 : }
6057 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
6058 : return Just(true);
6059 : case LookupIterator::DATA:
6060 : case LookupIterator::ACCESSOR: {
6061 6344999 : if (!it->IsConfigurable()) {
6062 : // Fail if the property is not configurable.
6063 3502 : if (is_strict(language_mode)) {
6064 : isolate->Throw(*isolate->factory()->NewTypeError(
6065 : MessageTemplate::kStrictDeleteProperty, it->GetName(),
6066 2517 : receiver));
6067 : return Nothing<bool>();
6068 : }
6069 : return Just(false);
6070 : }
6071 :
6072 6341497 : it->Delete();
6073 :
6074 : return Just(true);
6075 : }
6076 : }
6077 : }
6078 :
6079 : return Just(true);
6080 : }
6081 :
6082 :
6083 12 : Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index,
6084 : LanguageMode language_mode) {
6085 : LookupIterator it(object->GetIsolate(), object, index, object,
6086 : LookupIterator::OWN);
6087 12 : return DeleteProperty(&it, language_mode);
6088 : }
6089 :
6090 :
6091 468 : Maybe<bool> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
6092 : Handle<Name> name,
6093 : LanguageMode language_mode) {
6094 468 : LookupIterator it(object, name, object, LookupIterator::OWN);
6095 468 : return DeleteProperty(&it, language_mode);
6096 : }
6097 :
6098 :
6099 5843 : Maybe<bool> JSReceiver::DeletePropertyOrElement(Handle<JSReceiver> object,
6100 : Handle<Name> name,
6101 : LanguageMode language_mode) {
6102 : LookupIterator it = LookupIterator::PropertyOrElement(
6103 5843 : name->GetIsolate(), object, name, object, LookupIterator::OWN);
6104 5843 : return DeleteProperty(&it, language_mode);
6105 : }
6106 :
6107 : // ES6 19.1.2.4
6108 : // static
6109 285828 : Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object,
6110 : Handle<Object> key,
6111 : Handle<Object> attributes) {
6112 : // 1. If Type(O) is not Object, throw a TypeError exception.
6113 285828 : if (!object->IsJSReceiver()) {
6114 : Handle<String> fun_name =
6115 102 : isolate->factory()->InternalizeUtf8String("Object.defineProperty");
6116 204 : THROW_NEW_ERROR_RETURN_FAILURE(
6117 : isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name));
6118 : }
6119 : // 2. Let key be ToPropertyKey(P).
6120 : // 3. ReturnIfAbrupt(key).
6121 571452 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key, ToPropertyKey(isolate, key));
6122 : // 4. Let desc be ToPropertyDescriptor(Attributes).
6123 : // 5. ReturnIfAbrupt(desc).
6124 : PropertyDescriptor desc;
6125 285726 : if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) {
6126 215 : return isolate->heap()->exception();
6127 : }
6128 : // 6. Let success be DefinePropertyOrThrow(O,key, desc).
6129 : Maybe<bool> success = DefineOwnProperty(
6130 285511 : isolate, Handle<JSReceiver>::cast(object), key, &desc, THROW_ON_ERROR);
6131 : // 7. ReturnIfAbrupt(success).
6132 285511 : MAYBE_RETURN(success, isolate->heap()->exception());
6133 283836 : CHECK(success.FromJust());
6134 : // 8. Return O.
6135 283836 : return *object;
6136 : }
6137 :
6138 :
6139 : // ES6 19.1.2.3.1
6140 : // static
6141 19975 : MaybeHandle<Object> JSReceiver::DefineProperties(Isolate* isolate,
6142 : Handle<Object> object,
6143 : Handle<Object> properties) {
6144 : // 1. If Type(O) is not Object, throw a TypeError exception.
6145 19975 : if (!object->IsJSReceiver()) {
6146 : Handle<String> fun_name =
6147 43 : isolate->factory()->InternalizeUtf8String("Object.defineProperties");
6148 86 : THROW_NEW_ERROR(isolate,
6149 : NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name),
6150 : Object);
6151 : }
6152 : // 2. Let props be ToObject(Properties).
6153 : // 3. ReturnIfAbrupt(props).
6154 : Handle<JSReceiver> props;
6155 39864 : ASSIGN_RETURN_ON_EXCEPTION(isolate, props,
6156 : Object::ToObject(isolate, properties), Object);
6157 :
6158 : // 4. Let keys be props.[[OwnPropertyKeys]]().
6159 : // 5. ReturnIfAbrupt(keys).
6160 : Handle<FixedArray> keys;
6161 39834 : ASSIGN_RETURN_ON_EXCEPTION(
6162 : isolate, keys, KeyAccumulator::GetKeys(props, KeyCollectionMode::kOwnOnly,
6163 : ALL_PROPERTIES),
6164 : Object);
6165 : // 6. Let descriptors be an empty List.
6166 : int capacity = keys->length();
6167 19917 : std::vector<PropertyDescriptor> descriptors(capacity);
6168 : size_t descriptors_index = 0;
6169 : // 7. Repeat for each element nextKey of keys in List order,
6170 379204 : for (int i = 0; i < keys->length(); ++i) {
6171 : Handle<Object> next_key(keys->get(i), isolate);
6172 : // 7a. Let propDesc be props.[[GetOwnProperty]](nextKey).
6173 : // 7b. ReturnIfAbrupt(propDesc).
6174 170044 : bool success = false;
6175 : LookupIterator it = LookupIterator::PropertyOrElement(
6176 170044 : isolate, props, next_key, &success, LookupIterator::OWN);
6177 : DCHECK(success);
6178 170044 : Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
6179 170403 : if (!maybe.IsJust()) return MaybeHandle<Object>();
6180 : PropertyAttributes attrs = maybe.FromJust();
6181 : // 7c. If propDesc is not undefined and propDesc.[[Enumerable]] is true:
6182 171765 : if (attrs == ABSENT) continue;
6183 170044 : if (attrs & DONT_ENUM) continue;
6184 : // 7c i. Let descObj be Get(props, nextKey).
6185 : // 7c ii. ReturnIfAbrupt(descObj).
6186 : Handle<Object> desc_obj;
6187 336646 : ASSIGN_RETURN_ON_EXCEPTION(isolate, desc_obj, Object::GetProperty(&it),
6188 : Object);
6189 : // 7c iii. Let desc be ToPropertyDescriptor(descObj).
6190 : success = PropertyDescriptor::ToPropertyDescriptor(
6191 336646 : isolate, desc_obj, &descriptors[descriptors_index]);
6192 : // 7c iv. ReturnIfAbrupt(desc).
6193 168323 : if (!success) return MaybeHandle<Object>();
6194 : // 7c v. Append the pair (a two element List) consisting of nextKey and
6195 : // desc to the end of descriptors.
6196 167964 : descriptors[descriptors_index].set_name(next_key);
6197 167964 : descriptors_index++;
6198 : }
6199 : // 8. For each pair from descriptors in list order,
6200 167290 : for (size_t i = 0; i < descriptors_index; ++i) {
6201 167290 : PropertyDescriptor* desc = &descriptors[i];
6202 : // 8a. Let P be the first element of pair.
6203 : // 8b. Let desc be the second element of pair.
6204 : // 8c. Let status be DefinePropertyOrThrow(O, P, desc).
6205 : Maybe<bool> status =
6206 : DefineOwnProperty(isolate, Handle<JSReceiver>::cast(object),
6207 167290 : desc->name(), desc, THROW_ON_ERROR);
6208 : // 8d. ReturnIfAbrupt(status).
6209 167290 : if (!status.IsJust()) return MaybeHandle<Object>();
6210 167290 : CHECK(status.FromJust());
6211 : }
6212 : // 9. Return o.
6213 : return object;
6214 : }
6215 :
6216 :
6217 : // static
6218 647720 : Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate,
6219 : Handle<JSReceiver> object,
6220 : Handle<Object> key,
6221 : PropertyDescriptor* desc,
6222 : ShouldThrow should_throw) {
6223 647720 : if (object->IsJSArray()) {
6224 : return JSArray::DefineOwnProperty(isolate, Handle<JSArray>::cast(object),
6225 80543 : key, desc, should_throw);
6226 : }
6227 567177 : if (object->IsJSProxy()) {
6228 : return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object),
6229 5822 : key, desc, should_throw);
6230 : }
6231 561355 : if (object->IsJSTypedArray()) {
6232 : return JSTypedArray::DefineOwnProperty(
6233 4786 : isolate, Handle<JSTypedArray>::cast(object), key, desc, should_throw);
6234 : }
6235 : // TODO(neis): Special case for JSModuleNamespace?
6236 :
6237 : // OrdinaryDefineOwnProperty, by virtue of calling
6238 : // DefineOwnPropertyIgnoreAttributes, can handle arguments
6239 : // (ES#sec-arguments-exotic-objects-defineownproperty-p-desc).
6240 : return OrdinaryDefineOwnProperty(isolate, Handle<JSObject>::cast(object), key,
6241 556569 : desc, should_throw);
6242 : }
6243 :
6244 :
6245 : // static
6246 662084 : Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate,
6247 : Handle<JSObject> object,
6248 : Handle<Object> key,
6249 : PropertyDescriptor* desc,
6250 : ShouldThrow should_throw) {
6251 662084 : bool success = false;
6252 : DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
6253 : LookupIterator it = LookupIterator::PropertyOrElement(
6254 662084 : isolate, object, key, &success, LookupIterator::OWN);
6255 : DCHECK(success); // ...so creating a LookupIterator can't fail.
6256 :
6257 : // Deal with access checks first.
6258 662084 : if (it.state() == LookupIterator::ACCESS_CHECK) {
6259 3716 : if (!it.HasAccess()) {
6260 36 : isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>());
6261 36 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6262 : return Just(true);
6263 : }
6264 3680 : it.Next();
6265 : }
6266 :
6267 : // Handle interceptor
6268 662048 : if (it.state() == LookupIterator::INTERCEPTOR) {
6269 208 : if (it.HolderIsReceiverOrHiddenPrototype()) {
6270 : Maybe<bool> result = DefinePropertyWithInterceptorInternal(
6271 208 : &it, it.GetInterceptor(), should_throw, *desc);
6272 416 : if (result.IsNothing() || result.FromJust()) {
6273 63 : return result;
6274 : }
6275 : }
6276 : }
6277 :
6278 661985 : return OrdinaryDefineOwnProperty(&it, desc, should_throw);
6279 : }
6280 :
6281 :
6282 : // ES6 9.1.6.1
6283 : // static
6284 661985 : Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
6285 : PropertyDescriptor* desc,
6286 : ShouldThrow should_throw) {
6287 : Isolate* isolate = it->isolate();
6288 : // 1. Let current be O.[[GetOwnProperty]](P).
6289 : // 2. ReturnIfAbrupt(current).
6290 : PropertyDescriptor current;
6291 661985 : MAYBE_RETURN(GetOwnPropertyDescriptor(it, ¤t), Nothing<bool>());
6292 :
6293 : // TODO(jkummerow/verwaest): It would be nice if we didn't have to reset
6294 : // the iterator every time. Currently, the reasons why we need it are:
6295 : // - handle interceptors correctly
6296 : // - handle accessors correctly (which might change the holder's map)
6297 661985 : it->Restart();
6298 : // 3. Let extensible be the value of the [[Extensible]] internal slot of O.
6299 661985 : Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
6300 661985 : bool extensible = JSObject::IsExtensible(object);
6301 :
6302 : return ValidateAndApplyPropertyDescriptor(isolate, it, extensible, desc,
6303 661985 : ¤t, should_throw);
6304 : }
6305 :
6306 :
6307 : // ES6 9.1.6.2
6308 : // static
6309 0 : Maybe<bool> JSReceiver::IsCompatiblePropertyDescriptor(
6310 : Isolate* isolate, bool extensible, PropertyDescriptor* desc,
6311 : PropertyDescriptor* current, Handle<Name> property_name,
6312 : ShouldThrow should_throw) {
6313 : // 1. Return ValidateAndApplyPropertyDescriptor(undefined, undefined,
6314 : // Extensible, Desc, Current).
6315 : return ValidateAndApplyPropertyDescriptor(
6316 6987 : isolate, NULL, extensible, desc, current, should_throw, property_name);
6317 : }
6318 :
6319 :
6320 : // ES6 9.1.6.3
6321 : // static
6322 668972 : Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor(
6323 : Isolate* isolate, LookupIterator* it, bool extensible,
6324 : PropertyDescriptor* desc, PropertyDescriptor* current,
6325 : ShouldThrow should_throw, Handle<Name> property_name) {
6326 : // We either need a LookupIterator, or a property name.
6327 : DCHECK((it == NULL) != property_name.is_null());
6328 : Handle<JSObject> object;
6329 : if (it != NULL) object = Handle<JSObject>::cast(it->GetReceiver());
6330 : bool desc_is_data_descriptor = PropertyDescriptor::IsDataDescriptor(desc);
6331 : bool desc_is_accessor_descriptor =
6332 : PropertyDescriptor::IsAccessorDescriptor(desc);
6333 : bool desc_is_generic_descriptor =
6334 : PropertyDescriptor::IsGenericDescriptor(desc);
6335 : // 1. (Assert)
6336 : // 2. If current is undefined, then
6337 668972 : if (current->is_empty()) {
6338 : // 2a. If extensible is false, return false.
6339 522728 : if (!extensible) {
6340 667 : RETURN_FAILURE(isolate, should_throw,
6341 : NewTypeError(MessageTemplate::kDefineDisallowed,
6342 : it != NULL ? it->GetName() : property_name));
6343 : }
6344 : // 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then:
6345 : // (This is equivalent to !IsAccessorDescriptor(desc).)
6346 : DCHECK((desc_is_generic_descriptor || desc_is_data_descriptor) ==
6347 : !desc_is_accessor_descriptor);
6348 522508 : if (!desc_is_accessor_descriptor) {
6349 : // 2c i. If O is not undefined, create an own data property named P of
6350 : // object O whose [[Value]], [[Writable]], [[Enumerable]] and
6351 : // [[Configurable]] attribute values are described by Desc. If the value
6352 : // of an attribute field of Desc is absent, the attribute of the newly
6353 : // created property is set to its default value.
6354 420571 : if (it != NULL) {
6355 416679 : if (!desc->has_writable()) desc->set_writable(false);
6356 416679 : if (!desc->has_enumerable()) desc->set_enumerable(false);
6357 416679 : if (!desc->has_configurable()) desc->set_configurable(false);
6358 : Handle<Object> value(
6359 : desc->has_value()
6360 : ? desc->value()
6361 416679 : : Handle<Object>::cast(isolate->factory()->undefined_value()));
6362 : MaybeHandle<Object> result =
6363 : JSObject::DefineOwnPropertyIgnoreAttributes(it, value,
6364 416679 : desc->ToAttributes());
6365 416679 : if (result.is_null()) return Nothing<bool>();
6366 : }
6367 : } else {
6368 : // 2d. Else Desc must be an accessor Property Descriptor,
6369 : DCHECK(desc_is_accessor_descriptor);
6370 : // 2d i. If O is not undefined, create an own accessor property named P
6371 : // of object O whose [[Get]], [[Set]], [[Enumerable]] and
6372 : // [[Configurable]] attribute values are described by Desc. If the value
6373 : // of an attribute field of Desc is absent, the attribute of the newly
6374 : // created property is set to its default value.
6375 101937 : if (it != NULL) {
6376 101713 : if (!desc->has_enumerable()) desc->set_enumerable(false);
6377 101713 : if (!desc->has_configurable()) desc->set_configurable(false);
6378 : Handle<Object> getter(
6379 : desc->has_get()
6380 : ? desc->get()
6381 120469 : : Handle<Object>::cast(isolate->factory()->null_value()));
6382 : Handle<Object> setter(
6383 : desc->has_set()
6384 : ? desc->set()
6385 165985 : : Handle<Object>::cast(isolate->factory()->null_value()));
6386 : MaybeHandle<Object> result =
6387 101713 : JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes());
6388 101713 : if (result.is_null()) return Nothing<bool>();
6389 : }
6390 : }
6391 : // 2e. Return true.
6392 : return Just(true);
6393 : }
6394 : // 3. Return true, if every field in Desc is absent.
6395 : // 4. Return true, if every field in Desc also occurs in current and the
6396 : // value of every field in Desc is the same value as the corresponding field
6397 : // in current when compared using the SameValue algorithm.
6398 209039 : if ((!desc->has_enumerable() ||
6399 144781 : desc->enumerable() == current->enumerable()) &&
6400 90221 : (!desc->has_configurable() ||
6401 141031 : desc->configurable() == current->configurable()) &&
6402 114814 : (!desc->has_value() ||
6403 216686 : (current->has_value() && current->value()->SameValue(*desc->value()))) &&
6404 77568 : (!desc->has_writable() ||
6405 160599 : (current->has_writable() && current->writable() == desc->writable())) &&
6406 8224 : (!desc->has_get() ||
6407 227503 : (current->has_get() && current->get()->SameValue(*desc->get()))) &&
6408 11182 : (!desc->has_set() ||
6409 10889 : (current->has_set() && current->set()->SameValue(*desc->set())))) {
6410 : return Just(true);
6411 : }
6412 : // 5. If the [[Configurable]] field of current is false, then
6413 82141 : if (!current->configurable()) {
6414 : // 5a. Return false, if the [[Configurable]] field of Desc is true.
6415 28431 : if (desc->has_configurable() && desc->configurable()) {
6416 809 : RETURN_FAILURE(isolate, should_throw,
6417 : NewTypeError(MessageTemplate::kRedefineDisallowed,
6418 : it != NULL ? it->GetName() : property_name));
6419 : }
6420 : // 5b. Return false, if the [[Enumerable]] field of Desc is present and the
6421 : // [[Enumerable]] fields of current and Desc are the Boolean negation of
6422 : // each other.
6423 27434 : if (desc->has_enumerable() && desc->enumerable() != current->enumerable()) {
6424 452 : RETURN_FAILURE(isolate, should_throw,
6425 : NewTypeError(MessageTemplate::kRedefineDisallowed,
6426 : it != NULL ? it->GetName() : property_name));
6427 : }
6428 : }
6429 :
6430 : bool current_is_data_descriptor =
6431 : PropertyDescriptor::IsDataDescriptor(current);
6432 : // 6. If IsGenericDescriptor(Desc) is true, no further validation is required.
6433 81663 : if (desc_is_generic_descriptor) {
6434 : // Nothing to see here.
6435 :
6436 : // 7. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) have
6437 : // different results, then:
6438 80244 : } else if (current_is_data_descriptor != desc_is_data_descriptor) {
6439 : // 7a. Return false, if the [[Configurable]] field of current is false.
6440 3552 : if (!current->configurable()) {
6441 671 : RETURN_FAILURE(isolate, should_throw,
6442 : NewTypeError(MessageTemplate::kRedefineDisallowed,
6443 : it != NULL ? it->GetName() : property_name));
6444 : }
6445 : // 7b. If IsDataDescriptor(current) is true, then:
6446 : if (current_is_data_descriptor) {
6447 : // 7b i. If O is not undefined, convert the property named P of object O
6448 : // from a data property to an accessor property. Preserve the existing
6449 : // values of the converted property's [[Configurable]] and [[Enumerable]]
6450 : // attributes and set the rest of the property's attributes to their
6451 : // default values.
6452 : // --> Folded into step 10.
6453 : } else {
6454 : // 7c i. If O is not undefined, convert the property named P of object O
6455 : // from an accessor property to a data property. Preserve the existing
6456 : // values of the converted property’s [[Configurable]] and [[Enumerable]]
6457 : // attributes and set the rest of the property’s attributes to their
6458 : // default values.
6459 : // --> Folded into step 10.
6460 : }
6461 :
6462 : // 8. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both
6463 : // true, then:
6464 76692 : } else if (current_is_data_descriptor && desc_is_data_descriptor) {
6465 : // 8a. If the [[Configurable]] field of current is false, then:
6466 59626 : if (!current->configurable()) {
6467 : // 8a i. Return false, if the [[Writable]] field of current is false and
6468 : // the [[Writable]] field of Desc is true.
6469 23582 : if (!current->writable() && desc->has_writable() && desc->writable()) {
6470 298 : RETURN_FAILURE(
6471 : isolate, should_throw,
6472 : NewTypeError(MessageTemplate::kRedefineDisallowed,
6473 : it != NULL ? it->GetName() : property_name));
6474 : }
6475 : // 8a ii. If the [[Writable]] field of current is false, then:
6476 22941 : if (!current->writable()) {
6477 : // 8a ii 1. Return false, if the [[Value]] field of Desc is present and
6478 : // SameValue(Desc.[[Value]], current.[[Value]]) is false.
6479 714 : if (desc->has_value() && !desc->value()->SameValue(*current->value())) {
6480 1224 : RETURN_FAILURE(
6481 : isolate, should_throw,
6482 : NewTypeError(MessageTemplate::kRedefineDisallowed,
6483 : it != NULL ? it->GetName() : property_name));
6484 : }
6485 : }
6486 : }
6487 : } else {
6488 : // 9. Else IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc)
6489 : // are both true,
6490 : DCHECK(PropertyDescriptor::IsAccessorDescriptor(current) &&
6491 : desc_is_accessor_descriptor);
6492 : // 9a. If the [[Configurable]] field of current is false, then:
6493 17066 : if (!current->configurable()) {
6494 : // 9a i. Return false, if the [[Set]] field of Desc is present and
6495 : // SameValue(Desc.[[Set]], current.[[Set]]) is false.
6496 220 : if (desc->has_set() && !desc->set()->SameValue(*current->set())) {
6497 186 : RETURN_FAILURE(
6498 : isolate, should_throw,
6499 : NewTypeError(MessageTemplate::kRedefineDisallowed,
6500 : it != NULL ? it->GetName() : property_name));
6501 : }
6502 : // 9a ii. Return false, if the [[Get]] field of Desc is present and
6503 : // SameValue(Desc.[[Get]], current.[[Get]]) is false.
6504 154 : if (desc->has_get() && !desc->get()->SameValue(*current->get())) {
6505 248 : RETURN_FAILURE(
6506 : isolate, should_throw,
6507 : NewTypeError(MessageTemplate::kRedefineDisallowed,
6508 : it != NULL ? it->GetName() : property_name));
6509 : }
6510 : }
6511 : }
6512 :
6513 : // 10. If O is not undefined, then:
6514 80887 : if (it != NULL) {
6515 : // 10a. For each field of Desc that is present, set the corresponding
6516 : // attribute of the property named P of object O to the value of the field.
6517 : PropertyAttributes attrs = NONE;
6518 :
6519 80523 : if (desc->has_enumerable()) {
6520 : attrs = static_cast<PropertyAttributes>(
6521 8748 : attrs | (desc->enumerable() ? NONE : DONT_ENUM));
6522 : } else {
6523 : attrs = static_cast<PropertyAttributes>(
6524 71775 : attrs | (current->enumerable() ? NONE : DONT_ENUM));
6525 : }
6526 80523 : if (desc->has_configurable()) {
6527 : attrs = static_cast<PropertyAttributes>(
6528 27231 : attrs | (desc->configurable() ? NONE : DONT_DELETE));
6529 : } else {
6530 : attrs = static_cast<PropertyAttributes>(
6531 53292 : attrs | (current->configurable() ? NONE : DONT_DELETE));
6532 : }
6533 101550 : if (desc_is_data_descriptor ||
6534 21027 : (desc_is_generic_descriptor && current_is_data_descriptor)) {
6535 60755 : if (desc->has_writable()) {
6536 : attrs = static_cast<PropertyAttributes>(
6537 56375 : attrs | (desc->writable() ? NONE : READ_ONLY));
6538 : } else {
6539 : attrs = static_cast<PropertyAttributes>(
6540 4380 : attrs | (current->writable() ? NONE : READ_ONLY));
6541 : }
6542 : Handle<Object> value(
6543 : desc->has_value() ? desc->value()
6544 : : current->has_value()
6545 : ? current->value()
6546 : : Handle<Object>::cast(
6547 64918 : isolate->factory()->undefined_value()));
6548 : MaybeHandle<Object> result =
6549 : JSObject::DefineOwnPropertyIgnoreAttributes(it, value, attrs);
6550 60755 : if (result.is_null()) return Nothing<bool>();
6551 : } else {
6552 : DCHECK(desc_is_accessor_descriptor ||
6553 : (desc_is_generic_descriptor &&
6554 : PropertyDescriptor::IsAccessorDescriptor(current)));
6555 : Handle<Object> getter(
6556 : desc->has_get()
6557 : ? desc->get()
6558 : : current->has_get()
6559 : ? current->get()
6560 31444 : : Handle<Object>::cast(isolate->factory()->null_value()));
6561 : Handle<Object> setter(
6562 : desc->has_set()
6563 : ? desc->set()
6564 : : current->has_set()
6565 : ? current->set()
6566 29360 : : Handle<Object>::cast(isolate->factory()->null_value()));
6567 : MaybeHandle<Object> result =
6568 19768 : JSObject::DefineAccessor(it, getter, setter, attrs);
6569 19768 : if (result.is_null()) return Nothing<bool>();
6570 : }
6571 : }
6572 :
6573 : // 11. Return true.
6574 : return Just(true);
6575 : }
6576 :
6577 :
6578 : // static
6579 370734 : Maybe<bool> JSReceiver::CreateDataProperty(LookupIterator* it,
6580 : Handle<Object> value,
6581 : ShouldThrow should_throw) {
6582 : DCHECK(!it->check_prototype_chain());
6583 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
6584 : Isolate* isolate = receiver->GetIsolate();
6585 :
6586 370734 : if (receiver->IsJSObject()) {
6587 369647 : return JSObject::CreateDataProperty(it, value, should_throw); // Shortcut.
6588 : }
6589 :
6590 : PropertyDescriptor new_desc;
6591 : new_desc.set_value(value);
6592 : new_desc.set_writable(true);
6593 : new_desc.set_enumerable(true);
6594 : new_desc.set_configurable(true);
6595 :
6596 : return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
6597 2174 : &new_desc, should_throw);
6598 : }
6599 :
6600 746148 : Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it,
6601 : Handle<Object> value,
6602 : ShouldThrow should_throw) {
6603 : DCHECK(it->GetReceiver()->IsJSObject());
6604 373077 : MAYBE_RETURN(JSReceiver::GetPropertyAttributes(it), Nothing<bool>());
6605 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
6606 : Isolate* isolate = receiver->GetIsolate();
6607 :
6608 373071 : if (it->IsFound()) {
6609 200346 : Maybe<PropertyAttributes> attributes = GetPropertyAttributes(it);
6610 200401 : MAYBE_RETURN(attributes, Nothing<bool>());
6611 200346 : if ((attributes.FromJust() & DONT_DELETE) != 0) {
6612 184 : RETURN_FAILURE(
6613 : isolate, should_throw,
6614 : NewTypeError(MessageTemplate::kRedefineDisallowed, it->GetName()));
6615 : }
6616 : } else {
6617 172725 : if (!JSObject::IsExtensible(Handle<JSObject>::cast(it->GetReceiver()))) {
6618 350 : RETURN_FAILURE(
6619 : isolate, should_throw,
6620 : NewTypeError(MessageTemplate::kDefineDisallowed, it->GetName()));
6621 : }
6622 : }
6623 :
6624 372924 : RETURN_ON_EXCEPTION_VALUE(it->isolate(),
6625 : DefineOwnPropertyIgnoreAttributes(it, value, NONE),
6626 : Nothing<bool>());
6627 :
6628 : return Just(true);
6629 : }
6630 :
6631 :
6632 : // TODO(jkummerow): Consider unification with FastAsArrayLength() in
6633 : // accessors.cc.
6634 62305 : bool PropertyKeyToArrayLength(Handle<Object> value, uint32_t* length) {
6635 : DCHECK(value->IsNumber() || value->IsName());
6636 62305 : if (value->ToArrayLength(length)) return true;
6637 83258 : if (value->IsString()) return String::cast(*value)->AsArrayIndex(length);
6638 : return false;
6639 : }
6640 :
6641 0 : bool PropertyKeyToArrayIndex(Handle<Object> index_obj, uint32_t* output) {
6642 62305 : return PropertyKeyToArrayLength(index_obj, output) && *output != kMaxUInt32;
6643 : }
6644 :
6645 :
6646 : // ES6 9.4.2.1
6647 : // static
6648 80543 : Maybe<bool> JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o,
6649 : Handle<Object> name,
6650 : PropertyDescriptor* desc,
6651 : ShouldThrow should_throw) {
6652 : // 1. Assert: IsPropertyKey(P) is true. ("P" is |name|.)
6653 : // 2. If P is "length", then:
6654 : // TODO(jkummerow): Check if we need slow string comparison.
6655 80543 : if (*name == isolate->heap()->length_string()) {
6656 : // 2a. Return ArraySetLength(A, Desc).
6657 18238 : return ArraySetLength(isolate, o, desc, should_throw);
6658 : }
6659 : // 3. Else if P is an array index, then:
6660 62305 : uint32_t index = 0;
6661 62305 : if (PropertyKeyToArrayIndex(name, &index)) {
6662 : // 3a. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
6663 : PropertyDescriptor old_len_desc;
6664 : Maybe<bool> success = GetOwnPropertyDescriptor(
6665 59166 : isolate, o, isolate->factory()->length_string(), &old_len_desc);
6666 : // 3b. (Assert)
6667 : DCHECK(success.FromJust());
6668 : USE(success);
6669 : // 3c. Let oldLen be oldLenDesc.[[Value]].
6670 59166 : uint32_t old_len = 0;
6671 59166 : CHECK(old_len_desc.value()->ToArrayLength(&old_len));
6672 : // 3d. Let index be ToUint32(P).
6673 : // (Already done above.)
6674 : // 3e. (Assert)
6675 : // 3f. If index >= oldLen and oldLenDesc.[[Writable]] is false,
6676 : // return false.
6677 100146 : if (index >= old_len && old_len_desc.has_writable() &&
6678 : !old_len_desc.writable()) {
6679 0 : RETURN_FAILURE(isolate, should_throw,
6680 : NewTypeError(MessageTemplate::kDefineDisallowed, name));
6681 : }
6682 : // 3g. Let succeeded be OrdinaryDefineOwnProperty(A, P, Desc).
6683 : Maybe<bool> succeeded =
6684 59166 : OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
6685 : // 3h. Assert: succeeded is not an abrupt completion.
6686 : // In our case, if should_throw == THROW_ON_ERROR, it can be!
6687 : // 3i. If succeeded is false, return false.
6688 118205 : if (succeeded.IsNothing() || !succeeded.FromJust()) return succeeded;
6689 : // 3j. If index >= oldLen, then:
6690 59025 : if (index >= old_len) {
6691 : // 3j i. Set oldLenDesc.[[Value]] to index + 1.
6692 20490 : old_len_desc.set_value(isolate->factory()->NewNumberFromUint(index + 1));
6693 : // 3j ii. Let succeeded be
6694 : // OrdinaryDefineOwnProperty(A, "length", oldLenDesc).
6695 : succeeded = OrdinaryDefineOwnProperty(isolate, o,
6696 : isolate->factory()->length_string(),
6697 20490 : &old_len_desc, should_throw);
6698 : // 3j iii. Assert: succeeded is true.
6699 : DCHECK(succeeded.FromJust());
6700 : USE(succeeded);
6701 : }
6702 : // 3k. Return true.
6703 : return Just(true);
6704 : }
6705 :
6706 : // 4. Return OrdinaryDefineOwnProperty(A, P, Desc).
6707 3139 : return OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
6708 : }
6709 :
6710 :
6711 : // Part of ES6 9.4.2.4 ArraySetLength.
6712 : // static
6713 1020711 : bool JSArray::AnythingToArrayLength(Isolate* isolate,
6714 : Handle<Object> length_object,
6715 : uint32_t* output) {
6716 : // Fast path: check numbers and strings that can be converted directly
6717 : // and unobservably.
6718 1020711 : if (length_object->ToArrayLength(output)) return true;
6719 533158 : if (length_object->IsString() &&
6720 30 : Handle<String>::cast(length_object)->AsArrayIndex(output)) {
6721 : return true;
6722 : }
6723 : // Slow path: follow steps in ES6 9.4.2.4 "ArraySetLength".
6724 : // 3. Let newLen be ToUint32(Desc.[[Value]]).
6725 : Handle<Object> uint32_v;
6726 1066226 : if (!Object::ToUint32(isolate, length_object).ToHandle(&uint32_v)) {
6727 : // 4. ReturnIfAbrupt(newLen).
6728 : return false;
6729 : }
6730 : // 5. Let numberLen be ToNumber(Desc.[[Value]]).
6731 : Handle<Object> number_v;
6732 1066196 : if (!Object::ToNumber(length_object).ToHandle(&number_v)) {
6733 : // 6. ReturnIfAbrupt(newLen).
6734 : return false;
6735 : }
6736 : // 7. If newLen != numberLen, throw a RangeError exception.
6737 533098 : if (uint32_v->Number() != number_v->Number()) {
6738 : Handle<Object> exception =
6739 386 : isolate->factory()->NewRangeError(MessageTemplate::kInvalidArrayLength);
6740 386 : isolate->Throw(*exception);
6741 : return false;
6742 : }
6743 532712 : CHECK(uint32_v->ToArrayLength(output));
6744 : return true;
6745 : }
6746 :
6747 :
6748 : // ES6 9.4.2.4
6749 : // static
6750 18238 : Maybe<bool> JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a,
6751 : PropertyDescriptor* desc,
6752 : ShouldThrow should_throw) {
6753 : // 1. If the [[Value]] field of Desc is absent, then
6754 18238 : if (!desc->has_value()) {
6755 : // 1a. Return OrdinaryDefineOwnProperty(A, "length", Desc).
6756 : return OrdinaryDefineOwnProperty(
6757 400 : isolate, a, isolate->factory()->length_string(), desc, should_throw);
6758 : }
6759 : // 2. Let newLenDesc be a copy of Desc.
6760 : // (Actual copying is not necessary.)
6761 : PropertyDescriptor* new_len_desc = desc;
6762 : // 3. - 7. Convert Desc.[[Value]] to newLen.
6763 17838 : uint32_t new_len = 0;
6764 17838 : if (!AnythingToArrayLength(isolate, desc->value(), &new_len)) {
6765 : DCHECK(isolate->has_pending_exception());
6766 : return Nothing<bool>();
6767 : }
6768 : // 8. Set newLenDesc.[[Value]] to newLen.
6769 : // (Done below, if needed.)
6770 : // 9. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
6771 : PropertyDescriptor old_len_desc;
6772 : Maybe<bool> success = GetOwnPropertyDescriptor(
6773 17823 : isolate, a, isolate->factory()->length_string(), &old_len_desc);
6774 : // 10. (Assert)
6775 : DCHECK(success.FromJust());
6776 : USE(success);
6777 : // 11. Let oldLen be oldLenDesc.[[Value]].
6778 17823 : uint32_t old_len = 0;
6779 17823 : CHECK(old_len_desc.value()->ToArrayLength(&old_len));
6780 : // 12. If newLen >= oldLen, then
6781 17823 : if (new_len >= old_len) {
6782 : // 8. Set newLenDesc.[[Value]] to newLen.
6783 : // 12a. Return OrdinaryDefineOwnProperty(A, "length", newLenDesc).
6784 17809 : new_len_desc->set_value(isolate->factory()->NewNumberFromUint(new_len));
6785 : return OrdinaryDefineOwnProperty(isolate, a,
6786 : isolate->factory()->length_string(),
6787 17809 : new_len_desc, should_throw);
6788 : }
6789 : // 13. If oldLenDesc.[[Writable]] is false, return false.
6790 14 : if (!old_len_desc.writable()) {
6791 0 : RETURN_FAILURE(isolate, should_throw,
6792 : NewTypeError(MessageTemplate::kRedefineDisallowed,
6793 : isolate->factory()->length_string()));
6794 : }
6795 : // 14. If newLenDesc.[[Writable]] is absent or has the value true,
6796 : // let newWritable be true.
6797 : bool new_writable = false;
6798 14 : if (!new_len_desc->has_writable() || new_len_desc->writable()) {
6799 : new_writable = true;
6800 : } else {
6801 : // 15. Else,
6802 : // 15a. Need to defer setting the [[Writable]] attribute to false in case
6803 : // any elements cannot be deleted.
6804 : // 15b. Let newWritable be false. (It's initialized as "false" anyway.)
6805 : // 15c. Set newLenDesc.[[Writable]] to true.
6806 : // (Not needed.)
6807 : }
6808 : // Most of steps 16 through 19 is implemented by JSArray::SetLength.
6809 14 : JSArray::SetLength(a, new_len);
6810 : // Steps 19d-ii, 20.
6811 14 : if (!new_writable) {
6812 : PropertyDescriptor readonly;
6813 : readonly.set_writable(false);
6814 : Maybe<bool> success = OrdinaryDefineOwnProperty(
6815 : isolate, a, isolate->factory()->length_string(), &readonly,
6816 0 : should_throw);
6817 : DCHECK(success.FromJust());
6818 : USE(success);
6819 : }
6820 14 : uint32_t actual_new_len = 0;
6821 14 : CHECK(a->length()->ToArrayLength(&actual_new_len));
6822 : // Steps 19d-v, 21. Return false if there were non-deletable elements.
6823 14 : bool result = actual_new_len == new_len;
6824 14 : if (!result) {
6825 14 : RETURN_FAILURE(
6826 : isolate, should_throw,
6827 : NewTypeError(MessageTemplate::kStrictDeleteProperty,
6828 : isolate->factory()->NewNumberFromUint(actual_new_len - 1),
6829 : a));
6830 : }
6831 : return Just(result);
6832 : }
6833 :
6834 :
6835 : // ES6 9.5.6
6836 : // static
6837 5822 : Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy,
6838 : Handle<Object> key,
6839 : PropertyDescriptor* desc,
6840 : ShouldThrow should_throw) {
6841 5822 : STACK_CHECK(isolate, Nothing<bool>());
6842 6214 : if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) {
6843 : return SetPrivateProperty(isolate, proxy, Handle<Symbol>::cast(key), desc,
6844 28 : should_throw);
6845 : }
6846 : Handle<String> trap_name = isolate->factory()->defineProperty_string();
6847 : // 1. Assert: IsPropertyKey(P) is true.
6848 : DCHECK(key->IsName() || key->IsNumber());
6849 : // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
6850 : Handle<Object> handler(proxy->handler(), isolate);
6851 : // 3. If handler is null, throw a TypeError exception.
6852 : // 4. Assert: Type(handler) is Object.
6853 5794 : if (proxy->IsRevoked()) {
6854 : isolate->Throw(*isolate->factory()->NewTypeError(
6855 28 : MessageTemplate::kProxyRevoked, trap_name));
6856 : return Nothing<bool>();
6857 : }
6858 : // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
6859 : Handle<JSReceiver> target(proxy->target(), isolate);
6860 : // 6. Let trap be ? GetMethod(handler, "defineProperty").
6861 : Handle<Object> trap;
6862 11560 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
6863 : isolate, trap,
6864 : Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
6865 : Nothing<bool>());
6866 : // 7. If trap is undefined, then:
6867 5640 : if (trap->IsUndefined(isolate)) {
6868 : // 7a. Return target.[[DefineOwnProperty]](P, Desc).
6869 : return JSReceiver::DefineOwnProperty(isolate, target, key, desc,
6870 2810 : should_throw);
6871 : }
6872 : // 8. Let descObj be FromPropertyDescriptor(Desc).
6873 2830 : Handle<Object> desc_obj = desc->ToObject(isolate);
6874 : // 9. Let booleanTrapResult be
6875 : // ToBoolean(? Call(trap, handler, «target, P, descObj»)).
6876 : Handle<Name> property_name =
6877 : key->IsName()
6878 : ? Handle<Name>::cast(key)
6879 2830 : : Handle<Name>::cast(isolate->factory()->NumberToString(key));
6880 : // Do not leak private property names.
6881 : DCHECK(!property_name->IsPrivate());
6882 : Handle<Object> trap_result_obj;
6883 2830 : Handle<Object> args[] = {target, property_name, desc_obj};
6884 5660 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
6885 : isolate, trap_result_obj,
6886 : Execution::Call(isolate, trap, handler, arraysize(args), args),
6887 : Nothing<bool>());
6888 : // 10. If booleanTrapResult is false, return false.
6889 2017 : if (!trap_result_obj->BooleanValue()) {
6890 154 : RETURN_FAILURE(isolate, should_throw,
6891 : NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
6892 : trap_name, property_name));
6893 : }
6894 : // 11. Let targetDesc be ? target.[[GetOwnProperty]](P).
6895 : PropertyDescriptor target_desc;
6896 : Maybe<bool> target_found =
6897 1891 : JSReceiver::GetOwnPropertyDescriptor(isolate, target, key, &target_desc);
6898 1891 : MAYBE_RETURN(target_found, Nothing<bool>());
6899 : // 12. Let extensibleTarget be ? IsExtensible(target).
6900 1891 : Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
6901 1891 : MAYBE_RETURN(maybe_extensible, Nothing<bool>());
6902 : bool extensible_target = maybe_extensible.FromJust();
6903 : // 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]]
6904 : // is false, then:
6905 : // 13a. Let settingConfigFalse be true.
6906 : // 14. Else let settingConfigFalse be false.
6907 2956 : bool setting_config_false = desc->has_configurable() && !desc->configurable();
6908 : // 15. If targetDesc is undefined, then
6909 1891 : if (!target_found.FromJust()) {
6910 : // 15a. If extensibleTarget is false, throw a TypeError exception.
6911 966 : if (!extensible_target) {
6912 : isolate->Throw(*isolate->factory()->NewTypeError(
6913 28 : MessageTemplate::kProxyDefinePropertyNonExtensible, property_name));
6914 : return Nothing<bool>();
6915 : }
6916 : // 15b. If settingConfigFalse is true, throw a TypeError exception.
6917 952 : if (setting_config_false) {
6918 : isolate->Throw(*isolate->factory()->NewTypeError(
6919 28 : MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
6920 : return Nothing<bool>();
6921 : }
6922 : } else {
6923 : // 16. Else targetDesc is not undefined,
6924 : // 16a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc,
6925 : // targetDesc) is false, throw a TypeError exception.
6926 : Maybe<bool> valid =
6927 : IsCompatiblePropertyDescriptor(isolate, extensible_target, desc,
6928 : &target_desc, property_name, DONT_THROW);
6929 925 : MAYBE_RETURN(valid, Nothing<bool>());
6930 925 : if (!valid.FromJust()) {
6931 : isolate->Throw(*isolate->factory()->NewTypeError(
6932 28 : MessageTemplate::kProxyDefinePropertyIncompatible, property_name));
6933 : return Nothing<bool>();
6934 : }
6935 : // 16b. If settingConfigFalse is true and targetDesc.[[Configurable]] is
6936 : // true, throw a TypeError exception.
6937 1051 : if (setting_config_false && target_desc.configurable()) {
6938 : isolate->Throw(*isolate->factory()->NewTypeError(
6939 28 : MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
6940 : return Nothing<bool>();
6941 : }
6942 : }
6943 : // 17. Return true.
6944 : return Just(true);
6945 : }
6946 :
6947 :
6948 : // static
6949 49 : Maybe<bool> JSProxy::SetPrivateProperty(Isolate* isolate, Handle<JSProxy> proxy,
6950 : Handle<Symbol> private_name,
6951 : PropertyDescriptor* desc,
6952 : ShouldThrow should_throw) {
6953 : // Despite the generic name, this can only add private data properties.
6954 70 : if (!PropertyDescriptor::IsDataDescriptor(desc) ||
6955 21 : desc->ToAttributes() != DONT_ENUM) {
6956 56 : RETURN_FAILURE(isolate, should_throw,
6957 : NewTypeError(MessageTemplate::kProxyPrivate));
6958 : }
6959 : DCHECK(proxy->map()->is_dictionary_map());
6960 : Handle<Object> value =
6961 : desc->has_value()
6962 : ? desc->value()
6963 21 : : Handle<Object>::cast(isolate->factory()->undefined_value());
6964 :
6965 21 : LookupIterator it(proxy, private_name, proxy);
6966 :
6967 21 : if (it.IsFound()) {
6968 : DCHECK_EQ(LookupIterator::DATA, it.state());
6969 : DCHECK_EQ(DONT_ENUM, it.property_attributes());
6970 7 : it.WriteDataValue(value, false);
6971 : return Just(true);
6972 : }
6973 :
6974 : Handle<NameDictionary> dict(proxy->property_dictionary());
6975 : PropertyDetails details(kData, DONT_ENUM, 0, PropertyCellType::kNoCell);
6976 : Handle<NameDictionary> result =
6977 14 : NameDictionary::Add(dict, private_name, value, details);
6978 21 : if (!dict.is_identical_to(result)) proxy->set_properties(*result);
6979 : return Just(true);
6980 : }
6981 :
6982 :
6983 : // static
6984 3690215 : Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate,
6985 : Handle<JSReceiver> object,
6986 : Handle<Object> key,
6987 : PropertyDescriptor* desc) {
6988 3690215 : bool success = false;
6989 : DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
6990 : LookupIterator it = LookupIterator::PropertyOrElement(
6991 3690215 : isolate, object, key, &success, LookupIterator::OWN);
6992 : DCHECK(success); // ...so creating a LookupIterator can't fail.
6993 3690215 : return GetOwnPropertyDescriptor(&it, desc);
6994 : }
6995 :
6996 : namespace {
6997 :
6998 8692690 : Maybe<bool> GetPropertyDescriptorWithInterceptor(LookupIterator* it,
6999 : PropertyDescriptor* desc) {
7000 : bool has_access = true;
7001 4346236 : if (it->state() == LookupIterator::ACCESS_CHECK) {
7002 3156992 : has_access = it->HasAccess() || JSObject::AllCanRead(it);
7003 3156992 : it->Next();
7004 : }
7005 :
7006 8692418 : if (has_access && it->state() == LookupIterator::INTERCEPTOR) {
7007 : Isolate* isolate = it->isolate();
7008 213 : Handle<InterceptorInfo> interceptor = it->GetInterceptor();
7009 213 : if (!interceptor->descriptor()->IsUndefined(isolate)) {
7010 : Handle<Object> result;
7011 : Handle<JSObject> holder = it->GetHolder<JSObject>();
7012 :
7013 : Handle<Object> receiver = it->GetReceiver();
7014 45 : if (!receiver->IsJSReceiver()) {
7015 14 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7016 : isolate, receiver, Object::ConvertReceiver(isolate, receiver),
7017 : Nothing<bool>());
7018 : }
7019 :
7020 : PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
7021 : *holder, Object::DONT_THROW);
7022 45 : if (it->IsElement()) {
7023 : uint32_t index = it->index();
7024 : v8::IndexedPropertyDescriptorCallback descriptorCallback =
7025 : v8::ToCData<v8::IndexedPropertyDescriptorCallback>(
7026 : interceptor->descriptor());
7027 :
7028 12 : result = args.Call(descriptorCallback, index);
7029 : } else {
7030 33 : Handle<Name> name = it->name();
7031 : DCHECK(!name->IsPrivate());
7032 : v8::GenericNamedPropertyDescriptorCallback descriptorCallback =
7033 : v8::ToCData<v8::GenericNamedPropertyDescriptorCallback>(
7034 : interceptor->descriptor());
7035 33 : result = args.Call(descriptorCallback, name);
7036 : }
7037 45 : if (!result.is_null()) {
7038 : // Request successfully intercepted, try to set the property
7039 : // descriptor.
7040 : Utils::ApiCheck(
7041 14 : PropertyDescriptor::ToPropertyDescriptor(isolate, result, desc),
7042 : it->IsElement() ? "v8::IndexedPropertyDescriptorCallback"
7043 : : "v8::NamedPropertyDescriptorCallback",
7044 14 : "Invalid property descriptor.");
7045 :
7046 : return Just(true);
7047 : }
7048 : }
7049 : }
7050 4346222 : it->Restart();
7051 : return Just(false);
7052 : }
7053 : } // namespace
7054 :
7055 : // ES6 9.1.5.1
7056 : // Returns true on success, false if the property didn't exist, nothing if
7057 : // an exception was thrown.
7058 : // static
7059 8088101 : Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it,
7060 : PropertyDescriptor* desc) {
7061 : Isolate* isolate = it->isolate();
7062 : // "Virtual" dispatch.
7063 8097717 : if (it->IsFound() && it->GetHolder<JSReceiver>()->IsJSProxy()) {
7064 : return JSProxy::GetOwnPropertyDescriptor(isolate, it->GetHolder<JSProxy>(),
7065 9040 : it->GetName(), desc);
7066 : }
7067 :
7068 4346236 : Maybe<bool> intercepted = GetPropertyDescriptorWithInterceptor(it, desc);
7069 4346236 : MAYBE_RETURN(intercepted, Nothing<bool>());
7070 4346236 : if (intercepted.FromJust()) {
7071 : return Just(true);
7072 : }
7073 :
7074 : // Request was not intercepted, continue as normal.
7075 : // 1. (Assert)
7076 : // 2. If O does not have an own property with key P, return undefined.
7077 4346222 : Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(it);
7078 4346222 : MAYBE_RETURN(maybe, Nothing<bool>());
7079 : PropertyAttributes attrs = maybe.FromJust();
7080 4346168 : if (attrs == ABSENT) return Just(false);
7081 : DCHECK(!isolate->has_pending_exception());
7082 :
7083 : // 3. Let D be a newly created Property Descriptor with no fields.
7084 : DCHECK(desc->is_empty());
7085 : // 4. Let X be O's own property whose key is P.
7086 : // 5. If X is a data property, then
7087 3900922 : bool is_accessor_pair = it->state() == LookupIterator::ACCESSOR &&
7088 3900922 : it->GetAccessors()->IsAccessorPair();
7089 3732825 : if (!is_accessor_pair) {
7090 : // 5a. Set D.[[Value]] to the value of X's [[Value]] attribute.
7091 : Handle<Object> value;
7092 7394420 : if (!Object::GetProperty(it).ToHandle(&value)) {
7093 : DCHECK(isolate->has_pending_exception());
7094 : return Nothing<bool>();
7095 : }
7096 : desc->set_value(value);
7097 : // 5b. Set D.[[Writable]] to the value of X's [[Writable]] attribute
7098 3697210 : desc->set_writable((attrs & READ_ONLY) == 0);
7099 : } else {
7100 : // 6. Else X is an accessor property, so
7101 : Handle<AccessorPair> accessors =
7102 35615 : Handle<AccessorPair>::cast(it->GetAccessors());
7103 : // 6a. Set D.[[Get]] to the value of X's [[Get]] attribute.
7104 35615 : desc->set_get(AccessorPair::GetComponent(accessors, ACCESSOR_GETTER));
7105 : // 6b. Set D.[[Set]] to the value of X's [[Set]] attribute.
7106 35615 : desc->set_set(AccessorPair::GetComponent(accessors, ACCESSOR_SETTER));
7107 : }
7108 :
7109 : // 7. Set D.[[Enumerable]] to the value of X's [[Enumerable]] attribute.
7110 3732825 : desc->set_enumerable((attrs & DONT_ENUM) == 0);
7111 : // 8. Set D.[[Configurable]] to the value of X's [[Configurable]] attribute.
7112 3732825 : desc->set_configurable((attrs & DONT_DELETE) == 0);
7113 : // 9. Return D.
7114 : DCHECK(PropertyDescriptor::IsAccessorDescriptor(desc) !=
7115 : PropertyDescriptor::IsDataDescriptor(desc));
7116 : return Just(true);
7117 : }
7118 :
7119 :
7120 : // ES6 9.5.5
7121 : // static
7122 13932 : Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate,
7123 : Handle<JSProxy> proxy,
7124 : Handle<Name> name,
7125 : PropertyDescriptor* desc) {
7126 : DCHECK(!name->IsPrivate());
7127 13932 : STACK_CHECK(isolate, Nothing<bool>());
7128 :
7129 : Handle<String> trap_name =
7130 : isolate->factory()->getOwnPropertyDescriptor_string();
7131 : // 1. (Assert)
7132 : // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
7133 : Handle<Object> handler(proxy->handler(), isolate);
7134 : // 3. If handler is null, throw a TypeError exception.
7135 : // 4. Assert: Type(handler) is Object.
7136 13932 : if (proxy->IsRevoked()) {
7137 : isolate->Throw(*isolate->factory()->NewTypeError(
7138 56 : MessageTemplate::kProxyRevoked, trap_name));
7139 : return Nothing<bool>();
7140 : }
7141 : // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
7142 : Handle<JSReceiver> target(proxy->target(), isolate);
7143 : // 6. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor").
7144 : Handle<Object> trap;
7145 27808 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7146 : isolate, trap,
7147 : Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
7148 : Nothing<bool>());
7149 : // 7. If trap is undefined, then
7150 13820 : if (trap->IsUndefined(isolate)) {
7151 : // 7a. Return target.[[GetOwnProperty]](P).
7152 4983 : return JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, desc);
7153 : }
7154 : // 8. Let trapResultObj be ? Call(trap, handler, «target, P»).
7155 : Handle<Object> trap_result_obj;
7156 : Handle<Object> args[] = {target, name};
7157 17674 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7158 : isolate, trap_result_obj,
7159 : Execution::Call(isolate, trap, handler, arraysize(args), args),
7160 : Nothing<bool>());
7161 : // 9. If Type(trapResultObj) is neither Object nor Undefined, throw a
7162 : // TypeError exception.
7163 8694 : if (!trap_result_obj->IsJSReceiver() &&
7164 : !trap_result_obj->IsUndefined(isolate)) {
7165 : isolate->Throw(*isolate->factory()->NewTypeError(
7166 56 : MessageTemplate::kProxyGetOwnPropertyDescriptorInvalid, name));
7167 : return Nothing<bool>();
7168 : }
7169 : // 10. Let targetDesc be ? target.[[GetOwnProperty]](P).
7170 : PropertyDescriptor target_desc;
7171 : Maybe<bool> found =
7172 7406 : JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
7173 7406 : MAYBE_RETURN(found, Nothing<bool>());
7174 : // 11. If trapResultObj is undefined, then
7175 7406 : if (trap_result_obj->IsUndefined(isolate)) {
7176 : // 11a. If targetDesc is undefined, return undefined.
7177 1232 : if (!found.FromJust()) return Just(false);
7178 : // 11b. If targetDesc.[[Configurable]] is false, throw a TypeError
7179 : // exception.
7180 70 : if (!target_desc.configurable()) {
7181 : isolate->Throw(*isolate->factory()->NewTypeError(
7182 84 : MessageTemplate::kProxyGetOwnPropertyDescriptorUndefined, name));
7183 : return Nothing<bool>();
7184 : }
7185 : // 11c. Let extensibleTarget be ? IsExtensible(target).
7186 28 : Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
7187 28 : MAYBE_RETURN(extensible_target, Nothing<bool>());
7188 : // 11d. (Assert)
7189 : // 11e. If extensibleTarget is false, throw a TypeError exception.
7190 28 : if (!extensible_target.FromJust()) {
7191 : isolate->Throw(*isolate->factory()->NewTypeError(
7192 0 : MessageTemplate::kProxyGetOwnPropertyDescriptorNonExtensible, name));
7193 : return Nothing<bool>();
7194 : }
7195 : // 11f. Return undefined.
7196 : return Just(false);
7197 : }
7198 : // 12. Let extensibleTarget be ? IsExtensible(target).
7199 6174 : Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
7200 6174 : MAYBE_RETURN(extensible_target, Nothing<bool>());
7201 : // 13. Let resultDesc be ? ToPropertyDescriptor(trapResultObj).
7202 6174 : if (!PropertyDescriptor::ToPropertyDescriptor(isolate, trap_result_obj,
7203 6174 : desc)) {
7204 : DCHECK(isolate->has_pending_exception());
7205 : return Nothing<bool>();
7206 : }
7207 : // 14. Call CompletePropertyDescriptor(resultDesc).
7208 6062 : PropertyDescriptor::CompletePropertyDescriptor(isolate, desc);
7209 : // 15. Let valid be IsCompatiblePropertyDescriptor (extensibleTarget,
7210 : // resultDesc, targetDesc).
7211 : Maybe<bool> valid =
7212 : IsCompatiblePropertyDescriptor(isolate, extensible_target.FromJust(),
7213 : desc, &target_desc, name, DONT_THROW);
7214 6062 : MAYBE_RETURN(valid, Nothing<bool>());
7215 : // 16. If valid is false, throw a TypeError exception.
7216 6062 : if (!valid.FromJust()) {
7217 : isolate->Throw(*isolate->factory()->NewTypeError(
7218 56 : MessageTemplate::kProxyGetOwnPropertyDescriptorIncompatible, name));
7219 : return Nothing<bool>();
7220 : }
7221 : // 17. If resultDesc.[[Configurable]] is false, then
7222 6034 : if (!desc->configurable()) {
7223 : // 17a. If targetDesc is undefined or targetDesc.[[Configurable]] is true:
7224 742 : if (target_desc.is_empty() || target_desc.configurable()) {
7225 : // 17a i. Throw a TypeError exception.
7226 : isolate->Throw(*isolate->factory()->NewTypeError(
7227 : MessageTemplate::kProxyGetOwnPropertyDescriptorNonConfigurable,
7228 56 : name));
7229 : return Nothing<bool>();
7230 : }
7231 : }
7232 : // 18. Return resultDesc.
7233 : return Just(true);
7234 : }
7235 :
7236 :
7237 0 : bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
7238 : ElementsKind kind,
7239 : Object* object) {
7240 : Isolate* isolate = elements->GetIsolate();
7241 0 : if (IsFastObjectElementsKind(kind) || kind == FAST_STRING_WRAPPER_ELEMENTS) {
7242 : int length = IsJSArray()
7243 : ? Smi::cast(JSArray::cast(this)->length())->value()
7244 0 : : elements->length();
7245 0 : for (int i = 0; i < length; ++i) {
7246 : Object* element = elements->get(i);
7247 0 : if (!element->IsTheHole(isolate) && element == object) return true;
7248 : }
7249 : } else {
7250 : DCHECK(kind == DICTIONARY_ELEMENTS || kind == SLOW_STRING_WRAPPER_ELEMENTS);
7251 : Object* key =
7252 0 : SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
7253 0 : if (!key->IsUndefined(isolate)) return true;
7254 : }
7255 : return false;
7256 : }
7257 :
7258 :
7259 : // Check whether this object references another object.
7260 0 : bool JSObject::ReferencesObject(Object* obj) {
7261 : Map* map_of_this = map();
7262 : Heap* heap = GetHeap();
7263 : DisallowHeapAllocation no_allocation;
7264 :
7265 : // Is the object the constructor for this object?
7266 0 : if (map_of_this->GetConstructor() == obj) {
7267 : return true;
7268 : }
7269 :
7270 : // Is the object the prototype for this object?
7271 0 : if (map_of_this->prototype() == obj) {
7272 : return true;
7273 : }
7274 :
7275 : // Check if the object is among the named properties.
7276 0 : Object* key = SlowReverseLookup(obj);
7277 0 : if (!key->IsUndefined(heap->isolate())) {
7278 : return true;
7279 : }
7280 :
7281 : // Check if the object is among the indexed properties.
7282 : ElementsKind kind = GetElementsKind();
7283 0 : switch (kind) {
7284 : // Raw pixels and external arrays do not reference other
7285 : // objects.
7286 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
7287 : case TYPE##_ELEMENTS: \
7288 : break;
7289 :
7290 : TYPED_ARRAYS(TYPED_ARRAY_CASE)
7291 : #undef TYPED_ARRAY_CASE
7292 :
7293 : case FAST_DOUBLE_ELEMENTS:
7294 : case FAST_HOLEY_DOUBLE_ELEMENTS:
7295 : break;
7296 : case FAST_SMI_ELEMENTS:
7297 : case FAST_HOLEY_SMI_ELEMENTS:
7298 : break;
7299 : case FAST_ELEMENTS:
7300 : case FAST_HOLEY_ELEMENTS:
7301 : case DICTIONARY_ELEMENTS:
7302 : case FAST_STRING_WRAPPER_ELEMENTS:
7303 : case SLOW_STRING_WRAPPER_ELEMENTS: {
7304 : FixedArray* elements = FixedArray::cast(this->elements());
7305 0 : if (ReferencesObjectFromElements(elements, kind, obj)) return true;
7306 : break;
7307 : }
7308 : case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
7309 : case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
7310 : SloppyArgumentsElements* elements =
7311 : SloppyArgumentsElements::cast(this->elements());
7312 : // Check the mapped parameters.
7313 0 : for (uint32_t i = 0; i < elements->parameter_map_length(); ++i) {
7314 : Object* value = elements->get_mapped_entry(i);
7315 0 : if (!value->IsTheHole(heap->isolate()) && value == obj) return true;
7316 : }
7317 : // Check the arguments.
7318 : FixedArray* arguments = elements->arguments();
7319 : kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS :
7320 0 : FAST_HOLEY_ELEMENTS;
7321 0 : if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
7322 : break;
7323 : }
7324 : case NO_ELEMENTS:
7325 : break;
7326 : }
7327 :
7328 : // For functions check the context.
7329 0 : if (IsJSFunction()) {
7330 : // Get the constructor function for arguments array.
7331 : Map* arguments_map =
7332 0 : heap->isolate()->context()->native_context()->sloppy_arguments_map();
7333 : JSFunction* arguments_function =
7334 0 : JSFunction::cast(arguments_map->GetConstructor());
7335 :
7336 : // Get the context and don't check if it is the native context.
7337 : JSFunction* f = JSFunction::cast(this);
7338 : Context* context = f->context();
7339 0 : if (context->IsNativeContext()) {
7340 : return false;
7341 : }
7342 :
7343 : // Check the non-special context slots.
7344 0 : for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
7345 : // Only check JS objects.
7346 0 : if (context->get(i)->IsJSObject()) {
7347 : JSObject* ctxobj = JSObject::cast(context->get(i));
7348 : // If it is an arguments array check the content.
7349 0 : if (ctxobj->map()->GetConstructor() == arguments_function) {
7350 0 : if (ctxobj->ReferencesObject(obj)) {
7351 : return true;
7352 : }
7353 0 : } else if (ctxobj == obj) {
7354 : return true;
7355 : }
7356 : }
7357 : }
7358 :
7359 : // Check the context extension (if any) if it can have references.
7360 0 : if (context->has_extension() && !context->IsCatchContext()) {
7361 : // With harmony scoping, a JSFunction may have a script context.
7362 : // TODO(mvstanton): walk into the ScopeInfo.
7363 0 : if (context->IsScriptContext()) {
7364 : return false;
7365 : }
7366 :
7367 0 : return context->extension_object()->ReferencesObject(obj);
7368 : }
7369 : }
7370 :
7371 : // No references to object.
7372 : return false;
7373 : }
7374 :
7375 :
7376 206214 : Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver,
7377 : IntegrityLevel level,
7378 : ShouldThrow should_throw) {
7379 : DCHECK(level == SEALED || level == FROZEN);
7380 :
7381 206214 : if (receiver->IsJSObject()) {
7382 : Handle<JSObject> object = Handle<JSObject>::cast(receiver);
7383 205570 : if (!object->HasSloppyArgumentsElements()) { // Fast path.
7384 205496 : if (level == SEALED) {
7385 : return JSObject::PreventExtensionsWithTransition<SEALED>(object,
7386 409 : should_throw);
7387 : } else {
7388 : return JSObject::PreventExtensionsWithTransition<FROZEN>(object,
7389 205087 : should_throw);
7390 : }
7391 : }
7392 : }
7393 :
7394 : Isolate* isolate = receiver->GetIsolate();
7395 :
7396 718 : MAYBE_RETURN(JSReceiver::PreventExtensions(receiver, should_throw),
7397 : Nothing<bool>());
7398 :
7399 : Handle<FixedArray> keys;
7400 718 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7401 : isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>());
7402 :
7403 : PropertyDescriptor no_conf;
7404 : no_conf.set_configurable(false);
7405 :
7406 : PropertyDescriptor no_conf_no_write;
7407 : no_conf_no_write.set_configurable(false);
7408 : no_conf_no_write.set_writable(false);
7409 :
7410 718 : if (level == SEALED) {
7411 406 : for (int i = 0; i < keys->length(); ++i) {
7412 : Handle<Object> key(keys->get(i), isolate);
7413 126 : MAYBE_RETURN(
7414 : DefineOwnProperty(isolate, receiver, key, &no_conf, THROW_ON_ERROR),
7415 : Nothing<bool>());
7416 : }
7417 : return Just(true);
7418 : }
7419 :
7420 4498 : for (int i = 0; i < keys->length(); ++i) {
7421 : Handle<Object> key(keys->get(i), isolate);
7422 : PropertyDescriptor current_desc;
7423 : Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
7424 1967 : isolate, receiver, key, ¤t_desc);
7425 1967 : MAYBE_RETURN(owned, Nothing<bool>());
7426 1967 : if (owned.FromJust()) {
7427 : PropertyDescriptor desc =
7428 : PropertyDescriptor::IsAccessorDescriptor(¤t_desc)
7429 : ? no_conf
7430 1967 : : no_conf_no_write;
7431 1967 : MAYBE_RETURN(
7432 : DefineOwnProperty(isolate, receiver, key, &desc, THROW_ON_ERROR),
7433 : Nothing<bool>());
7434 : }
7435 : }
7436 : return Just(true);
7437 : }
7438 :
7439 :
7440 7712 : Maybe<bool> JSReceiver::TestIntegrityLevel(Handle<JSReceiver> object,
7441 : IntegrityLevel level) {
7442 : DCHECK(level == SEALED || level == FROZEN);
7443 : Isolate* isolate = object->GetIsolate();
7444 :
7445 7712 : Maybe<bool> extensible = JSReceiver::IsExtensible(object);
7446 7712 : MAYBE_RETURN(extensible, Nothing<bool>());
7447 7712 : if (extensible.FromJust()) return Just(false);
7448 :
7449 : Handle<FixedArray> keys;
7450 1585 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7451 : isolate, keys, JSReceiver::OwnPropertyKeys(object), Nothing<bool>());
7452 :
7453 19213 : for (int i = 0; i < keys->length(); ++i) {
7454 : Handle<Object> key(keys->get(i), isolate);
7455 : PropertyDescriptor current_desc;
7456 : Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
7457 9314 : isolate, object, key, ¤t_desc);
7458 9814 : MAYBE_RETURN(owned, Nothing<bool>());
7459 9314 : if (owned.FromJust()) {
7460 9314 : if (current_desc.configurable()) return Just(false);
7461 14809 : if (level == FROZEN &&
7462 14699 : PropertyDescriptor::IsDataDescriptor(¤t_desc) &&
7463 : current_desc.writable()) {
7464 : return Just(false);
7465 : }
7466 : }
7467 : }
7468 : return Just(true);
7469 : }
7470 :
7471 :
7472 7126 : Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object,
7473 : ShouldThrow should_throw) {
7474 7126 : if (object->IsJSProxy()) {
7475 : return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object),
7476 952 : should_throw);
7477 : }
7478 : DCHECK(object->IsJSObject());
7479 : return JSObject::PreventExtensions(Handle<JSObject>::cast(object),
7480 6174 : should_throw);
7481 : }
7482 :
7483 :
7484 952 : Maybe<bool> JSProxy::PreventExtensions(Handle<JSProxy> proxy,
7485 : ShouldThrow should_throw) {
7486 : Isolate* isolate = proxy->GetIsolate();
7487 952 : STACK_CHECK(isolate, Nothing<bool>());
7488 : Factory* factory = isolate->factory();
7489 : Handle<String> trap_name = factory->preventExtensions_string();
7490 :
7491 952 : if (proxy->IsRevoked()) {
7492 : isolate->Throw(
7493 56 : *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
7494 : return Nothing<bool>();
7495 : }
7496 : Handle<JSReceiver> target(proxy->target(), isolate);
7497 : Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
7498 :
7499 : Handle<Object> trap;
7500 1848 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7501 : isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
7502 896 : if (trap->IsUndefined(isolate)) {
7503 812 : return JSReceiver::PreventExtensions(target, should_throw);
7504 : }
7505 :
7506 : Handle<Object> trap_result;
7507 : Handle<Object> args[] = {target};
7508 168 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7509 : isolate, trap_result,
7510 : Execution::Call(isolate, trap, handler, arraysize(args), args),
7511 : Nothing<bool>());
7512 84 : if (!trap_result->BooleanValue()) {
7513 28 : RETURN_FAILURE(
7514 : isolate, should_throw,
7515 : NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
7516 : }
7517 :
7518 : // Enforce the invariant.
7519 56 : Maybe<bool> target_result = JSReceiver::IsExtensible(target);
7520 56 : MAYBE_RETURN(target_result, Nothing<bool>());
7521 56 : if (target_result.FromJust()) {
7522 : isolate->Throw(*factory->NewTypeError(
7523 28 : MessageTemplate::kProxyPreventExtensionsExtensible));
7524 : return Nothing<bool>();
7525 : }
7526 : return Just(true);
7527 : }
7528 :
7529 :
7530 6632 : Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object,
7531 : ShouldThrow should_throw) {
7532 0 : Isolate* isolate = object->GetIsolate();
7533 :
7534 6632 : if (!object->HasSloppyArgumentsElements()) {
7535 6543 : return PreventExtensionsWithTransition<NONE>(object, should_throw);
7536 : }
7537 :
7538 89 : if (object->IsAccessCheckNeeded() &&
7539 0 : !isolate->MayAccess(handle(isolate->context()), object)) {
7540 0 : isolate->ReportFailedAccessCheck(object);
7541 0 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
7542 0 : RETURN_FAILURE(isolate, should_throw,
7543 : NewTypeError(MessageTemplate::kNoAccess));
7544 : }
7545 :
7546 89 : if (!object->map()->is_extensible()) return Just(true);
7547 :
7548 89 : if (object->IsJSGlobalProxy()) {
7549 0 : PrototypeIterator iter(isolate, object);
7550 0 : if (iter.IsAtEnd()) return Just(true);
7551 : DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
7552 : return PreventExtensions(PrototypeIterator::GetCurrent<JSObject>(iter),
7553 0 : should_throw);
7554 : }
7555 :
7556 178 : if (object->map()->has_named_interceptor() ||
7557 : object->map()->has_indexed_interceptor()) {
7558 0 : RETURN_FAILURE(isolate, should_throw,
7559 : NewTypeError(MessageTemplate::kCannotPreventExt));
7560 : }
7561 :
7562 89 : if (!object->HasFixedTypedArrayElements()) {
7563 : // If there are fast elements we normalize.
7564 89 : Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
7565 : DCHECK(object->HasDictionaryElements() ||
7566 : object->HasSlowArgumentsElements());
7567 :
7568 : // Make sure that we never go back to fast case.
7569 89 : object->RequireSlowElements(*dictionary);
7570 : }
7571 :
7572 : // Do a map transition, other objects with this map may still
7573 : // be extensible.
7574 : // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
7575 89 : Handle<Map> new_map = Map::Copy(handle(object->map()), "PreventExtensions");
7576 :
7577 : new_map->set_is_extensible(false);
7578 89 : JSObject::MigrateToMap(object, new_map);
7579 : DCHECK(!object->map()->is_extensible());
7580 :
7581 : return Just(true);
7582 : }
7583 :
7584 :
7585 1520952 : Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) {
7586 1520952 : if (object->IsJSProxy()) {
7587 910 : return JSProxy::IsExtensible(Handle<JSProxy>::cast(object));
7588 : }
7589 1520042 : return Just(JSObject::IsExtensible(Handle<JSObject>::cast(object)));
7590 : }
7591 :
7592 :
7593 910 : Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) {
7594 : Isolate* isolate = proxy->GetIsolate();
7595 910 : STACK_CHECK(isolate, Nothing<bool>());
7596 : Factory* factory = isolate->factory();
7597 : Handle<String> trap_name = factory->isExtensible_string();
7598 :
7599 910 : if (proxy->IsRevoked()) {
7600 : isolate->Throw(
7601 56 : *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
7602 : return Nothing<bool>();
7603 : }
7604 : Handle<JSReceiver> target(proxy->target(), isolate);
7605 : Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
7606 :
7607 : Handle<Object> trap;
7608 1764 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7609 : isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
7610 854 : if (trap->IsUndefined(isolate)) {
7611 196 : return JSReceiver::IsExtensible(target);
7612 : }
7613 :
7614 : Handle<Object> trap_result;
7615 : Handle<Object> args[] = {target};
7616 1316 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7617 : isolate, trap_result,
7618 : Execution::Call(isolate, trap, handler, arraysize(args), args),
7619 : Nothing<bool>());
7620 :
7621 : // Enforce the invariant.
7622 658 : Maybe<bool> target_result = JSReceiver::IsExtensible(target);
7623 658 : MAYBE_RETURN(target_result, Nothing<bool>());
7624 658 : if (target_result.FromJust() != trap_result->BooleanValue()) {
7625 : isolate->Throw(
7626 : *factory->NewTypeError(MessageTemplate::kProxyIsExtensibleInconsistent,
7627 84 : factory->ToBoolean(target_result.FromJust())));
7628 : return Nothing<bool>();
7629 : }
7630 616 : return target_result;
7631 : }
7632 :
7633 :
7634 2354752 : bool JSObject::IsExtensible(Handle<JSObject> object) {
7635 36 : Isolate* isolate = object->GetIsolate();
7636 2354788 : if (object->IsAccessCheckNeeded() &&
7637 36 : !isolate->MayAccess(handle(isolate->context()), object)) {
7638 : return true;
7639 : }
7640 2354728 : if (object->IsJSGlobalProxy()) {
7641 : PrototypeIterator iter(isolate, *object);
7642 3969 : if (iter.IsAtEnd()) return false;
7643 : DCHECK(iter.GetCurrent()->IsJSGlobalObject());
7644 7938 : return iter.GetCurrent<JSObject>()->map()->is_extensible();
7645 : }
7646 2350759 : return object->map()->is_extensible();
7647 : }
7648 :
7649 : namespace {
7650 :
7651 : template <typename Dictionary>
7652 : void DictionaryDetailsAtPut(Isolate* isolate, Handle<Dictionary> dictionary,
7653 : int entry, PropertyDetails details) {
7654 : dictionary->DetailsAtPut(entry, details);
7655 : }
7656 :
7657 : template <>
7658 13229 : void DictionaryDetailsAtPut<GlobalDictionary>(
7659 : Isolate* isolate, Handle<GlobalDictionary> dictionary, int entry,
7660 : PropertyDetails details) {
7661 13229 : Object* value = dictionary->ValueAt(entry);
7662 : DCHECK(value->IsPropertyCell());
7663 : value = PropertyCell::cast(value)->value();
7664 26458 : if (value->IsTheHole(isolate)) return;
7665 : PropertyCell::PrepareForValue(dictionary, entry, handle(value, isolate),
7666 13214 : details);
7667 : }
7668 :
7669 : template <typename Dictionary>
7670 5991 : void ApplyAttributesToDictionary(Isolate* isolate,
7671 : Handle<Dictionary> dictionary,
7672 : const PropertyAttributes attributes) {
7673 : int capacity = dictionary->Capacity();
7674 70583 : for (int i = 0; i < capacity; i++) {
7675 : Object* k = dictionary->KeyAt(i);
7676 90851 : if (dictionary->IsKey(isolate, k) &&
7677 : !(k->IsSymbol() && Symbol::cast(k)->is_private())) {
7678 : PropertyDetails details = dictionary->DetailsAt(i);
7679 26125 : int attrs = attributes;
7680 : // READ_ONLY is an invalid attribute for JS setters/getters.
7681 49718 : if ((attributes & READ_ONLY) && details.kind() == kAccessor) {
7682 44 : Object* v = dictionary->ValueAt(i);
7683 44 : if (v->IsPropertyCell()) v = PropertyCell::cast(v)->value();
7684 44 : if (v->IsAccessorPair()) attrs &= ~READ_ONLY;
7685 : }
7686 : details = details.CopyAddAttributes(
7687 : static_cast<PropertyAttributes>(attrs));
7688 13229 : DictionaryDetailsAtPut<Dictionary>(isolate, dictionary, i, details);
7689 : }
7690 : }
7691 5991 : }
7692 :
7693 : } // namespace
7694 :
7695 : template <PropertyAttributes attrs>
7696 212187 : Maybe<bool> JSObject::PreventExtensionsWithTransition(
7697 : Handle<JSObject> object, ShouldThrow should_throw) {
7698 : STATIC_ASSERT(attrs == NONE || attrs == SEALED || attrs == FROZEN);
7699 :
7700 : // Sealing/freezing sloppy arguments should be handled elsewhere.
7701 : DCHECK(!object->HasSloppyArgumentsElements());
7702 :
7703 30 : Isolate* isolate = object->GetIsolate();
7704 212217 : if (object->IsAccessCheckNeeded() &&
7705 30 : !isolate->MayAccess(handle(isolate->context()), object)) {
7706 24 : isolate->ReportFailedAccessCheck(object);
7707 24 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
7708 0 : RETURN_FAILURE(isolate, should_throw,
7709 : NewTypeError(MessageTemplate::kNoAccess));
7710 : }
7711 :
7712 6545 : if (attrs == NONE && !object->map()->is_extensible()) return Just(true);
7713 :
7714 212148 : if (object->IsJSGlobalProxy()) {
7715 148 : PrototypeIterator iter(isolate, object);
7716 148 : if (iter.IsAtEnd()) return Just(true);
7717 : DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
7718 : return PreventExtensionsWithTransition<attrs>(
7719 148 : PrototypeIterator::GetCurrent<JSObject>(iter), should_throw);
7720 : }
7721 :
7722 423999 : if (object->map()->has_named_interceptor() ||
7723 : object->map()->has_indexed_interceptor()) {
7724 : MessageTemplate::Template message = MessageTemplate::kNone;
7725 : switch (attrs) {
7726 : case NONE:
7727 : message = MessageTemplate::kCannotPreventExt;
7728 : break;
7729 :
7730 : case SEALED:
7731 : message = MessageTemplate::kCannotSeal;
7732 : break;
7733 :
7734 : case FROZEN:
7735 : message = MessageTemplate::kCannotFreeze;
7736 : break;
7737 : }
7738 3 : RETURN_FAILURE(isolate, should_throw, NewTypeError(message));
7739 : }
7740 :
7741 : Handle<SeededNumberDictionary> new_element_dictionary;
7742 635500 : if (!object->HasFixedTypedArrayElements() &&
7743 211910 : !object->HasDictionaryElements() &&
7744 211591 : !object->HasSlowStringWrapperElements()) {
7745 : int length =
7746 : object->IsJSArray()
7747 : ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
7748 211591 : : object->elements()->length();
7749 217870 : new_element_dictionary =
7750 : length == 0 ? isolate->factory()->empty_slow_element_dictionary()
7751 6279 : : object->GetElementsAccessor()->Normalize(object);
7752 : }
7753 :
7754 : Handle<Symbol> transition_marker;
7755 : if (attrs == NONE) {
7756 : transition_marker = isolate->factory()->nonextensible_symbol();
7757 : } else if (attrs == SEALED) {
7758 : transition_marker = isolate->factory()->sealed_symbol();
7759 : } else {
7760 : DCHECK(attrs == FROZEN);
7761 : transition_marker = isolate->factory()->frozen_symbol();
7762 : }
7763 :
7764 : Handle<Map> old_map(object->map(), isolate);
7765 : Map* transition =
7766 211999 : TransitionArray::SearchSpecial(*old_map, *transition_marker);
7767 211999 : if (transition != NULL) {
7768 : Handle<Map> transition_map(transition, isolate);
7769 : DCHECK(transition_map->has_dictionary_elements() ||
7770 : transition_map->has_fixed_typed_array_elements() ||
7771 : transition_map->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
7772 : DCHECK(!transition_map->is_extensible());
7773 159859 : JSObject::MigrateToMap(object, transition_map);
7774 52140 : } else if (TransitionArray::CanHaveMoreTransitions(old_map)) {
7775 : // Create a new descriptor array with the appropriate property attributes
7776 : Handle<Map> new_map = Map::CopyForPreventExtensions(
7777 51203 : old_map, attrs, transition_marker, "CopyForPreventExtensions");
7778 51203 : JSObject::MigrateToMap(object, new_map);
7779 : } else {
7780 : DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map());
7781 : // Slow path: need to normalize properties for safety
7782 937 : NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0,
7783 : "SlowPreventExtensions");
7784 :
7785 : // Create a new map, since other objects with this map may be extensible.
7786 : // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
7787 : Handle<Map> new_map =
7788 937 : Map::Copy(handle(object->map()), "SlowCopyForPreventExtensions");
7789 : new_map->set_is_extensible(false);
7790 937 : if (!new_element_dictionary.is_null()) {
7791 : ElementsKind new_kind =
7792 : IsStringWrapperElementsKind(old_map->elements_kind())
7793 : ? SLOW_STRING_WRAPPER_ELEMENTS
7794 937 : : DICTIONARY_ELEMENTS;
7795 : new_map->set_elements_kind(new_kind);
7796 : }
7797 937 : JSObject::MigrateToMap(object, new_map);
7798 :
7799 : if (attrs != NONE) {
7800 213 : if (object->IsJSGlobalObject()) {
7801 : Handle<GlobalDictionary> dictionary(object->global_dictionary(),
7802 : isolate);
7803 134 : ApplyAttributesToDictionary(isolate, dictionary, attrs);
7804 : } else {
7805 : Handle<NameDictionary> dictionary(object->property_dictionary(),
7806 : isolate);
7807 79 : ApplyAttributesToDictionary(isolate, dictionary, attrs);
7808 : }
7809 : }
7810 : }
7811 :
7812 : // Both seal and preventExtensions always go through without modifications to
7813 : // typed array elements. Freeze works only if there are no actual elements.
7814 211999 : if (object->HasFixedTypedArrayElements()) {
7815 59 : if (attrs == FROZEN &&
7816 : JSArrayBufferView::cast(*object)->byte_length()->Number() > 0) {
7817 44 : isolate->Throw(*isolate->factory()->NewTypeError(
7818 88 : MessageTemplate::kCannotFreezeArrayBufferView));
7819 : return Nothing<bool>();
7820 : }
7821 : return Just(true);
7822 : }
7823 :
7824 : DCHECK(object->map()->has_dictionary_elements() ||
7825 : object->map()->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
7826 211910 : if (!new_element_dictionary.is_null()) {
7827 211591 : object->set_elements(*new_element_dictionary);
7828 : }
7829 :
7830 211910 : if (object->elements() != isolate->heap()->empty_slow_element_dictionary()) {
7831 : Handle<SeededNumberDictionary> dictionary(object->element_dictionary(),
7832 : isolate);
7833 : // Make sure we never go back to the fast case
7834 6510 : object->RequireSlowElements(*dictionary);
7835 : if (attrs != NONE) {
7836 5778 : ApplyAttributesToDictionary(isolate, dictionary, attrs);
7837 : }
7838 : }
7839 :
7840 : return Just(true);
7841 : }
7842 :
7843 :
7844 58218049 : Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object,
7845 : Representation representation,
7846 : FieldIndex index) {
7847 : Isolate* isolate = object->GetIsolate();
7848 58218049 : if (object->IsUnboxedDoubleField(index)) {
7849 : double value = object->RawFastDoublePropertyAt(index);
7850 78231 : return isolate->factory()->NewHeapNumber(value);
7851 : }
7852 58139818 : Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate);
7853 58139818 : return Object::WrapForRead(isolate, raw_value, representation);
7854 : }
7855 :
7856 : template <class ContextObject>
7857 : class JSObjectWalkVisitor {
7858 : public:
7859 : JSObjectWalkVisitor(ContextObject* site_context, bool copying,
7860 : JSObject::DeepCopyHints hints)
7861 : : site_context_(site_context),
7862 : copying_(copying),
7863 8247456 : hints_(hints) {}
7864 :
7865 : MUST_USE_RESULT MaybeHandle<JSObject> StructureWalk(Handle<JSObject> object);
7866 :
7867 : protected:
7868 1897610 : MUST_USE_RESULT inline MaybeHandle<JSObject> VisitElementOrProperty(
7869 : Handle<JSObject> object,
7870 2201171 : Handle<JSObject> value) {
7871 1897610 : Handle<AllocationSite> current_site = site_context()->EnterNewScope();
7872 1897610 : MaybeHandle<JSObject> copy_of_value = StructureWalk(value);
7873 303561 : site_context()->ExitScope(current_site, value);
7874 1897610 : return copy_of_value;
7875 : }
7876 :
7877 : inline ContextObject* site_context() { return site_context_; }
7878 10145062 : inline Isolate* isolate() { return site_context()->isolate(); }
7879 :
7880 : inline bool copying() const { return copying_; }
7881 :
7882 : private:
7883 : ContextObject* site_context_;
7884 : const bool copying_;
7885 : const JSObject::DeepCopyHints hints_;
7886 : };
7887 :
7888 : template <class ContextObject>
7889 10145062 : MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
7890 26183410 : Handle<JSObject> object) {
7891 641009 : Isolate* isolate = this->isolate();
7892 : bool copying = this->copying();
7893 10145062 : bool shallow = hints_ == JSObject::kObjectIsShallow;
7894 :
7895 10145062 : if (!shallow) {
7896 : StackLimitCheck check(isolate);
7897 :
7898 8796677 : if (check.HasOverflowed()) {
7899 165 : isolate->StackOverflow();
7900 : return MaybeHandle<JSObject>();
7901 : }
7902 : }
7903 :
7904 10144897 : if (object->map()->is_deprecated()) {
7905 2303 : JSObject::MigrateInstance(object);
7906 : }
7907 :
7908 : Handle<JSObject> copy;
7909 10144898 : if (copying) {
7910 : // JSFunction objects are not allowed to be in normal boilerplates at all.
7911 : DCHECK(!object->IsJSFunction());
7912 : Handle<AllocationSite> site_to_pass;
7913 8922587 : if (site_context()->ShouldCreateMemento(object)) {
7914 7115761 : site_to_pass = site_context()->current();
7915 : }
7916 8922588 : copy = isolate->factory()->CopyJSObjectWithAllocationSite(
7917 : object, site_to_pass);
7918 : } else {
7919 : copy = object;
7920 : }
7921 :
7922 : DCHECK(copying || copy.is_identical_to(object));
7923 :
7924 : ElementsKind kind = copy->GetElementsKind();
7925 18757388 : if (copying && IsFastSmiOrObjectElementsKind(kind) &&
7926 : FixedArray::cast(copy->elements())->map() ==
7927 8612488 : isolate->heap()->fixed_cow_array_map()) {
7928 641009 : isolate->counters()->cow_arrays_created_runtime()->Increment();
7929 : }
7930 :
7931 10144900 : if (!shallow) {
7932 : HandleScope scope(isolate);
7933 :
7934 : // Deep copy own properties.
7935 8796514 : if (copy->HasFastProperties()) {
7936 : Handle<DescriptorArray> descriptors(copy->map()->instance_descriptors());
7937 : int limit = copy->map()->NumberOfOwnDescriptors();
7938 29933368 : for (int i = 0; i < limit; i++) {
7939 21137049 : PropertyDetails details = descriptors->GetDetails(i);
7940 23106187 : if (details.location() != kField) continue;
7941 : DCHECK_EQ(kData, details.kind());
7942 19167911 : FieldIndex index = FieldIndex::ForDescriptor(copy->map(), i);
7943 19167909 : if (object->IsUnboxedDoubleField(index)) {
7944 160513 : if (copying) {
7945 : // Ensure that all bits of the double value are preserved.
7946 : uint64_t value = object->RawFastDoublePropertyAsBitsAt(index);
7947 : copy->RawFastDoublePropertyAsBitsAtPut(index, value);
7948 : }
7949 : } else {
7950 19007397 : Handle<Object> value(object->RawFastPropertyAt(index), isolate);
7951 19007402 : if (value->IsJSObject()) {
7952 1693952 : ASSIGN_RETURN_ON_EXCEPTION(
7953 : isolate, value,
7954 : VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
7955 : JSObject);
7956 846961 : if (copying) {
7957 645365 : copy->FastPropertyAtPut(index, *value);
7958 : }
7959 : } else {
7960 18160426 : if (copying) {
7961 15742937 : Representation representation = details.representation();
7962 15742937 : value = Object::NewStorageFor(isolate, value, representation);
7963 15742937 : copy->FastPropertyAtPut(index, *value);
7964 : }
7965 : }
7966 : }
7967 : }
7968 : } else {
7969 : // Only deep copy fields from the object literal expression.
7970 : // In particular, don't try to copy the length attribute of
7971 : // an array.
7972 : PropertyFilter filter = static_cast<PropertyFilter>(
7973 : ONLY_WRITABLE | ONLY_ENUMERABLE | ONLY_CONFIGURABLE);
7974 : KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly, filter);
7975 182 : accumulator.CollectOwnPropertyNames(copy, copy);
7976 182 : Handle<FixedArray> names = accumulator.GetKeys();
7977 593688 : for (int i = 0; i < names->length(); i++) {
7978 : DCHECK(names->get(i)->IsName());
7979 : Handle<Name> name(Name::cast(names->get(i)));
7980 : Handle<Object> value =
7981 593324 : JSObject::GetProperty(copy, name).ToHandleChecked();
7982 296662 : if (value->IsJSObject()) {
7983 : Handle<JSObject> result;
7984 0 : ASSIGN_RETURN_ON_EXCEPTION(
7985 : isolate, result,
7986 : VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
7987 : JSObject);
7988 0 : if (copying) {
7989 : // Creating object copy for literals. No strict mode needed.
7990 0 : JSObject::SetProperty(copy, name, result, SLOPPY).Assert();
7991 : }
7992 : }
7993 182 : }
7994 : }
7995 :
7996 : // Deep copy own elements.
7997 8796501 : switch (kind) {
7998 : case FAST_ELEMENTS:
7999 : case FAST_HOLEY_ELEMENTS: {
8000 : Handle<FixedArray> elements(FixedArray::cast(copy->elements()));
8001 7716301 : if (elements->map() == isolate->heap()->fixed_cow_array_map()) {
8002 : #ifdef DEBUG
8003 : for (int i = 0; i < elements->length(); i++) {
8004 : DCHECK(!elements->get(i)->IsJSObject());
8005 : }
8006 : #endif
8007 : } else {
8008 14127124 : for (int i = 0; i < elements->length(); i++) {
8009 : Handle<Object> value(elements->get(i), isolate);
8010 3252017 : if (value->IsJSObject()) {
8011 : Handle<JSObject> result;
8012 2100528 : ASSIGN_RETURN_ON_EXCEPTION(
8013 : isolate, result,
8014 : VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
8015 : JSObject);
8016 1050234 : if (copying) {
8017 948439 : elements->set(i, *result);
8018 : }
8019 : }
8020 : }
8021 : }
8022 : break;
8023 : }
8024 : case DICTIONARY_ELEMENTS: {
8025 : Handle<SeededNumberDictionary> element_dictionary(
8026 : copy->element_dictionary());
8027 : int capacity = element_dictionary->Capacity();
8028 28179 : for (int i = 0; i < capacity; i++) {
8029 : Object* k = element_dictionary->KeyAt(i);
8030 26276 : if (element_dictionary->IsKey(isolate, k)) {
8031 9826 : Handle<Object> value(element_dictionary->ValueAt(i), isolate);
8032 9826 : if (value->IsJSObject()) {
8033 : Handle<JSObject> result;
8034 740 : ASSIGN_RETURN_ON_EXCEPTION(
8035 : isolate, result,
8036 : VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
8037 : JSObject);
8038 370 : if (copying) {
8039 : element_dictionary->ValueAtPut(i, *result);
8040 : }
8041 : }
8042 : }
8043 : }
8044 : break;
8045 : }
8046 : case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
8047 : case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
8048 0 : UNIMPLEMENTED();
8049 : break;
8050 : case FAST_STRING_WRAPPER_ELEMENTS:
8051 : case SLOW_STRING_WRAPPER_ELEMENTS:
8052 0 : UNREACHABLE();
8053 : break;
8054 :
8055 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
8056 : case TYPE##_ELEMENTS: \
8057 :
8058 : TYPED_ARRAYS(TYPED_ARRAY_CASE)
8059 : #undef TYPED_ARRAY_CASE
8060 : // Typed elements cannot be created using an object literal.
8061 0 : UNREACHABLE();
8062 : break;
8063 :
8064 : case FAST_SMI_ELEMENTS:
8065 : case FAST_HOLEY_SMI_ELEMENTS:
8066 : case FAST_DOUBLE_ELEMENTS:
8067 : case FAST_HOLEY_DOUBLE_ELEMENTS:
8068 : case NO_ELEMENTS:
8069 : // No contained objects, nothing to do.
8070 : break;
8071 : }
8072 : }
8073 :
8074 : return copy;
8075 : }
8076 :
8077 :
8078 918881 : MaybeHandle<JSObject> JSObject::DeepWalk(
8079 : Handle<JSObject> object,
8080 : AllocationSiteCreationContext* site_context) {
8081 : JSObjectWalkVisitor<AllocationSiteCreationContext> v(site_context, false,
8082 : kNoHints);
8083 918881 : MaybeHandle<JSObject> result = v.StructureWalk(object);
8084 : Handle<JSObject> for_assert;
8085 : DCHECK(!result.ToHandle(&for_assert) || for_assert.is_identical_to(object));
8086 918881 : return result;
8087 : }
8088 :
8089 :
8090 7328575 : MaybeHandle<JSObject> JSObject::DeepCopy(
8091 : Handle<JSObject> object,
8092 : AllocationSiteUsageContext* site_context,
8093 : DeepCopyHints hints) {
8094 : JSObjectWalkVisitor<AllocationSiteUsageContext> v(site_context, true, hints);
8095 7328575 : MaybeHandle<JSObject> copy = v.StructureWalk(object);
8096 : Handle<JSObject> for_assert;
8097 : DCHECK(!copy.ToHandle(&for_assert) || !for_assert.is_identical_to(object));
8098 7328575 : return copy;
8099 : }
8100 :
8101 : // static
8102 10353260 : MaybeHandle<Object> JSReceiver::ToPrimitive(Handle<JSReceiver> receiver,
8103 : ToPrimitiveHint hint) {
8104 : Isolate* const isolate = receiver->GetIsolate();
8105 : Handle<Object> exotic_to_prim;
8106 20706520 : ASSIGN_RETURN_ON_EXCEPTION(
8107 : isolate, exotic_to_prim,
8108 : GetMethod(receiver, isolate->factory()->to_primitive_symbol()), Object);
8109 10353254 : if (!exotic_to_prim->IsUndefined(isolate)) {
8110 : Handle<Object> hint_string =
8111 6539 : isolate->factory()->ToPrimitiveHintString(hint);
8112 : Handle<Object> result;
8113 13078 : ASSIGN_RETURN_ON_EXCEPTION(
8114 : isolate, result,
8115 : Execution::Call(isolate, exotic_to_prim, receiver, 1, &hint_string),
8116 : Object);
8117 6410 : if (result->IsPrimitive()) return result;
8118 0 : THROW_NEW_ERROR(isolate,
8119 : NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8120 : Object);
8121 : }
8122 : return OrdinaryToPrimitive(receiver, (hint == ToPrimitiveHint::kString)
8123 : ? OrdinaryToPrimitiveHint::kString
8124 10346715 : : OrdinaryToPrimitiveHint::kNumber);
8125 : }
8126 :
8127 :
8128 : // static
8129 10346715 : MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive(
8130 : Handle<JSReceiver> receiver, OrdinaryToPrimitiveHint hint) {
8131 : Isolate* const isolate = receiver->GetIsolate();
8132 31040145 : Handle<String> method_names[2];
8133 10346715 : switch (hint) {
8134 : case OrdinaryToPrimitiveHint::kNumber:
8135 11879 : method_names[0] = isolate->factory()->valueOf_string();
8136 11879 : method_names[1] = isolate->factory()->toString_string();
8137 11879 : break;
8138 : case OrdinaryToPrimitiveHint::kString:
8139 10334836 : method_names[0] = isolate->factory()->toString_string();
8140 10334836 : method_names[1] = isolate->factory()->valueOf_string();
8141 10334836 : break;
8142 : }
8143 10363512 : for (Handle<String> name : method_names) {
8144 : Handle<Object> method;
8145 20710008 : ASSIGN_RETURN_ON_EXCEPTION(isolate, method,
8146 : JSReceiver::GetProperty(receiver, name), Object);
8147 10354976 : if (method->IsCallable()) {
8148 : Handle<Object> result;
8149 20708438 : ASSIGN_RETURN_ON_EXCEPTION(
8150 : isolate, result, Execution::Call(isolate, method, receiver, 0, NULL),
8151 : Object);
8152 10333679 : if (result->IsPrimitive()) return result;
8153 : }
8154 : }
8155 438 : THROW_NEW_ERROR(isolate,
8156 : NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8157 : Object);
8158 : }
8159 :
8160 :
8161 : // TODO(cbruni/jkummerow): Consider moving this into elements.cc.
8162 222954 : bool JSObject::HasEnumerableElements() {
8163 : // TODO(cbruni): cleanup
8164 : JSObject* object = this;
8165 222954 : switch (object->GetElementsKind()) {
8166 : case FAST_SMI_ELEMENTS:
8167 : case FAST_ELEMENTS:
8168 : case FAST_DOUBLE_ELEMENTS: {
8169 : int length = object->IsJSArray()
8170 : ? Smi::cast(JSArray::cast(object)->length())->value()
8171 89170 : : object->elements()->length();
8172 89170 : return length > 0;
8173 : }
8174 : case FAST_HOLEY_SMI_ELEMENTS:
8175 : case FAST_HOLEY_ELEMENTS: {
8176 : FixedArray* elements = FixedArray::cast(object->elements());
8177 : int length = object->IsJSArray()
8178 : ? Smi::cast(JSArray::cast(object)->length())->value()
8179 133339 : : elements->length();
8180 : Isolate* isolate = GetIsolate();
8181 4028504 : for (int i = 0; i < length; i++) {
8182 3934375 : if (!elements->is_the_hole(isolate, i)) return true;
8183 : }
8184 : return false;
8185 : }
8186 : case FAST_HOLEY_DOUBLE_ELEMENTS: {
8187 : int length = object->IsJSArray()
8188 : ? Smi::cast(JSArray::cast(object)->length())->value()
8189 75 : : object->elements()->length();
8190 : // Zero-length arrays would use the empty FixedArray...
8191 75 : if (length == 0) return false;
8192 : // ...so only cast to FixedDoubleArray otherwise.
8193 : FixedDoubleArray* elements = FixedDoubleArray::cast(object->elements());
8194 75 : for (int i = 0; i < length; i++) {
8195 75 : if (!elements->is_the_hole(i)) return true;
8196 : }
8197 : return false;
8198 : }
8199 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
8200 : case TYPE##_ELEMENTS:
8201 :
8202 : TYPED_ARRAYS(TYPED_ARRAY_CASE)
8203 : #undef TYPED_ARRAY_CASE
8204 : {
8205 : int length = object->elements()->length();
8206 0 : return length > 0;
8207 : }
8208 : case DICTIONARY_ELEMENTS: {
8209 : SeededNumberDictionary* elements =
8210 : SeededNumberDictionary::cast(object->elements());
8211 280 : return elements->NumberOfElementsFilterAttributes(ONLY_ENUMERABLE) > 0;
8212 : }
8213 : case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
8214 : case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
8215 : // We're approximating non-empty arguments objects here.
8216 : return true;
8217 : case FAST_STRING_WRAPPER_ELEMENTS:
8218 : case SLOW_STRING_WRAPPER_ELEMENTS:
8219 0 : if (String::cast(JSValue::cast(object)->value())->length() > 0) {
8220 : return true;
8221 : }
8222 0 : return object->elements()->length() > 0;
8223 : case NO_ELEMENTS:
8224 0 : return false;
8225 : }
8226 0 : UNREACHABLE();
8227 : return true;
8228 : }
8229 :
8230 :
8231 175278 : int Map::NumberOfDescribedProperties(DescriptorFlag which,
8232 : PropertyFilter filter) {
8233 : int result = 0;
8234 : DescriptorArray* descs = instance_descriptors();
8235 : int limit = which == ALL_DESCRIPTORS
8236 : ? descs->number_of_descriptors()
8237 175278 : : NumberOfOwnDescriptors();
8238 1120023 : for (int i = 0; i < limit; i++) {
8239 2603766 : if ((descs->GetDetails(i).attributes() & filter) == 0 &&
8240 714276 : !descs->GetKey(i)->FilterKey(filter)) {
8241 711549 : result++;
8242 : }
8243 : }
8244 175278 : return result;
8245 : }
8246 :
8247 :
8248 8779880 : int Map::NextFreePropertyIndex() {
8249 : int free_index = 0;
8250 : int number_of_own_descriptors = NumberOfOwnDescriptors();
8251 : DescriptorArray* descs = instance_descriptors();
8252 289287866 : for (int i = 0; i < number_of_own_descriptors; i++) {
8253 280507986 : PropertyDetails details = descs->GetDetails(i);
8254 280507986 : if (details.location() == kField) {
8255 271066829 : int candidate = details.field_index() + details.field_width_in_words();
8256 271066829 : if (candidate > free_index) free_index = candidate;
8257 : }
8258 : }
8259 8779880 : return free_index;
8260 : }
8261 :
8262 :
8263 16080831 : bool Map::OnlyHasSimpleProperties() {
8264 : // Wrapped string elements aren't explicitly stored in the elements backing
8265 : // store, but are loaded indirectly from the underlying string.
8266 16076322 : return !IsStringWrapperElementsKind(elements_kind()) &&
8267 48174479 : !IsSpecialReceiverMap() && !has_hidden_prototype() &&
8268 16080831 : !is_dictionary_map();
8269 : }
8270 :
8271 1064 : MUST_USE_RESULT Maybe<bool> FastGetOwnValuesOrEntries(
8272 : Isolate* isolate, Handle<JSReceiver> receiver, bool get_entries,
8273 : Handle<FixedArray>* result) {
8274 : Handle<Map> map(JSReceiver::cast(*receiver)->map(), isolate);
8275 :
8276 1064 : if (!map->IsJSObjectMap()) return Just(false);
8277 616 : if (!map->OnlyHasSimpleProperties()) return Just(false);
8278 :
8279 : Handle<JSObject> object(JSObject::cast(*receiver));
8280 :
8281 : Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
8282 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
8283 : int number_of_own_elements =
8284 952 : object->GetElementsAccessor()->GetCapacity(*object, object->elements());
8285 : Handle<FixedArray> values_or_entries = isolate->factory()->NewFixedArray(
8286 476 : number_of_own_descriptors + number_of_own_elements);
8287 476 : int count = 0;
8288 :
8289 476 : if (object->elements() != isolate->heap()->empty_fixed_array()) {
8290 336 : MAYBE_RETURN(object->GetElementsAccessor()->CollectValuesOrEntries(
8291 : isolate, object, values_or_entries, get_entries, &count,
8292 : ENUMERABLE_STRINGS),
8293 : Nothing<bool>());
8294 : }
8295 :
8296 476 : bool stable = object->map() == *map;
8297 :
8298 1792 : for (int index = 0; index < number_of_own_descriptors; index++) {
8299 : Handle<Name> next_key(descriptors->GetKey(index), isolate);
8300 1316 : if (!next_key->IsString()) continue;
8301 : Handle<Object> prop_value;
8302 :
8303 : // Directly decode from the descriptor array if |from| did not change shape.
8304 1176 : if (stable) {
8305 1148 : PropertyDetails details = descriptors->GetDetails(index);
8306 1148 : if (!details.IsEnumerable()) continue;
8307 784 : if (details.kind() == kData) {
8308 728 : if (details.location() == kDescriptor) {
8309 : prop_value = handle(descriptors->GetValue(index), isolate);
8310 : } else {
8311 728 : Representation representation = details.representation();
8312 728 : FieldIndex field_index = FieldIndex::ForDescriptor(*map, index);
8313 : prop_value =
8314 728 : JSObject::FastPropertyAt(object, representation, field_index);
8315 : }
8316 : } else {
8317 112 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8318 : isolate, prop_value, JSReceiver::GetProperty(object, next_key),
8319 : Nothing<bool>());
8320 56 : stable = object->map() == *map;
8321 : }
8322 : } else {
8323 : // If the map did change, do a slower lookup. We are still guaranteed that
8324 : // the object has a simple shape, and that the key is a name.
8325 28 : LookupIterator it(object, next_key, LookupIterator::OWN_SKIP_INTERCEPTOR);
8326 28 : if (!it.IsFound()) continue;
8327 : DCHECK(it.state() == LookupIterator::DATA ||
8328 : it.state() == LookupIterator::ACCESSOR);
8329 28 : if (!it.IsEnumerable()) continue;
8330 56 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8331 : isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
8332 : }
8333 :
8334 812 : if (get_entries) {
8335 560 : prop_value = MakeEntryPair(isolate, next_key, prop_value);
8336 : }
8337 :
8338 1624 : values_or_entries->set(count, *prop_value);
8339 812 : count++;
8340 : }
8341 :
8342 476 : if (count < values_or_entries->length()) values_or_entries->Shrink(count);
8343 476 : *result = values_or_entries;
8344 : return Just(true);
8345 : }
8346 :
8347 1064 : MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate,
8348 : Handle<JSReceiver> object,
8349 : PropertyFilter filter,
8350 : bool get_entries) {
8351 : Handle<FixedArray> values_or_entries;
8352 1064 : if (filter == ENUMERABLE_STRINGS) {
8353 : Maybe<bool> fast_values_or_entries = FastGetOwnValuesOrEntries(
8354 1064 : isolate, object, get_entries, &values_or_entries);
8355 1540 : if (fast_values_or_entries.IsNothing()) return MaybeHandle<FixedArray>();
8356 1064 : if (fast_values_or_entries.FromJust()) return values_or_entries;
8357 : }
8358 :
8359 : PropertyFilter key_filter =
8360 588 : static_cast<PropertyFilter>(filter & ~ONLY_ENUMERABLE);
8361 :
8362 : Handle<FixedArray> keys;
8363 1176 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8364 : isolate, keys,
8365 : KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, key_filter,
8366 : GetKeysConversion::kConvertToString),
8367 : MaybeHandle<FixedArray>());
8368 :
8369 588 : values_or_entries = isolate->factory()->NewFixedArray(keys->length());
8370 : int length = 0;
8371 :
8372 5152 : for (int i = 0; i < keys->length(); ++i) {
8373 : Handle<Name> key = Handle<Name>::cast(handle(keys->get(i), isolate));
8374 :
8375 1988 : if (filter & ONLY_ENUMERABLE) {
8376 : PropertyDescriptor descriptor;
8377 : Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor(
8378 1988 : isolate, object, key, &descriptor);
8379 1988 : MAYBE_RETURN(did_get_descriptor, MaybeHandle<FixedArray>());
8380 3948 : if (!did_get_descriptor.FromJust() || !descriptor.enumerable()) continue;
8381 : }
8382 :
8383 : Handle<Object> value;
8384 2744 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8385 : isolate, value, JSReceiver::GetPropertyOrElement(object, key),
8386 : MaybeHandle<FixedArray>());
8387 :
8388 1372 : if (get_entries) {
8389 : Handle<FixedArray> entry_storage =
8390 686 : isolate->factory()->NewUninitializedFixedArray(2);
8391 686 : entry_storage->set(0, *key);
8392 686 : entry_storage->set(1, *value);
8393 : value = isolate->factory()->NewJSArrayWithElements(entry_storage,
8394 686 : FAST_ELEMENTS, 2);
8395 : }
8396 :
8397 1372 : values_or_entries->set(length, *value);
8398 1372 : length++;
8399 : }
8400 588 : if (length < values_or_entries->length()) values_or_entries->Shrink(length);
8401 : return values_or_entries;
8402 : }
8403 :
8404 518 : MaybeHandle<FixedArray> JSReceiver::GetOwnValues(Handle<JSReceiver> object,
8405 : PropertyFilter filter) {
8406 518 : return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, false);
8407 : }
8408 :
8409 546 : MaybeHandle<FixedArray> JSReceiver::GetOwnEntries(Handle<JSReceiver> object,
8410 : PropertyFilter filter) {
8411 546 : return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, true);
8412 : }
8413 :
8414 301849 : bool Map::DictionaryElementsInPrototypeChainOnly() {
8415 301849 : if (IsDictionaryElementsKind(elements_kind())) {
8416 : return false;
8417 : }
8418 :
8419 887039 : for (PrototypeIterator iter(this); !iter.IsAtEnd(); iter.Advance()) {
8420 : // Be conservative, don't walk into proxies.
8421 1199116 : if (iter.GetCurrent()->IsJSProxy()) return true;
8422 : // String wrappers have non-configurable, non-writable elements.
8423 1199116 : if (iter.GetCurrent()->IsStringWrapper()) return true;
8424 599513 : JSObject* current = iter.GetCurrent<JSObject>();
8425 :
8426 610730 : if (current->HasDictionaryElements() &&
8427 11217 : current->element_dictionary()->requires_slow_elements()) {
8428 : return true;
8429 : }
8430 :
8431 588615 : if (current->HasSlowArgumentsElements()) {
8432 : FixedArray* parameter_map = FixedArray::cast(current->elements());
8433 : Object* arguments = parameter_map->get(1);
8434 0 : if (SeededNumberDictionary::cast(arguments)->requires_slow_elements()) {
8435 : return true;
8436 : }
8437 : }
8438 : }
8439 :
8440 287481 : return false;
8441 : }
8442 :
8443 :
8444 386449 : MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
8445 : Handle<Name> name,
8446 : Handle<Object> getter,
8447 : Handle<Object> setter,
8448 : PropertyAttributes attributes) {
8449 : Isolate* isolate = object->GetIsolate();
8450 :
8451 : LookupIterator it = LookupIterator::PropertyOrElement(
8452 386449 : isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
8453 386449 : return DefineAccessor(&it, getter, setter, attributes);
8454 : }
8455 :
8456 :
8457 1523784 : MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it,
8458 : Handle<Object> getter,
8459 : Handle<Object> setter,
8460 : PropertyAttributes attributes) {
8461 : Isolate* isolate = it->isolate();
8462 :
8463 507930 : it->UpdateProtector();
8464 :
8465 507930 : if (it->state() == LookupIterator::ACCESS_CHECK) {
8466 2657 : if (!it->HasAccess()) {
8467 6 : isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
8468 6 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
8469 : return isolate->factory()->undefined_value();
8470 : }
8471 2651 : it->Next();
8472 : }
8473 :
8474 : Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
8475 : // Ignore accessors on typed arrays.
8476 547112 : if (it->IsElement() && object->HasFixedTypedArrayElements()) {
8477 : return it->factory()->undefined_value();
8478 : }
8479 :
8480 : DCHECK(getter->IsCallable() || getter->IsUndefined(isolate) ||
8481 : getter->IsNull(isolate) || getter->IsFunctionTemplateInfo());
8482 : DCHECK(setter->IsCallable() || setter->IsUndefined(isolate) ||
8483 : setter->IsNull(isolate) || setter->IsFunctionTemplateInfo());
8484 507924 : it->TransitionToAccessorProperty(getter, setter, attributes);
8485 :
8486 : return isolate->factory()->undefined_value();
8487 : }
8488 :
8489 :
8490 118150 : MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
8491 : Handle<AccessorInfo> info) {
8492 : Isolate* isolate = object->GetIsolate();
8493 : Handle<Name> name(Name::cast(info->name()), isolate);
8494 :
8495 : LookupIterator it = LookupIterator::PropertyOrElement(
8496 118150 : isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
8497 :
8498 : // Duplicate ACCESS_CHECK outside of GetPropertyAttributes for the case that
8499 : // the FailedAccessCheckCallbackFunction doesn't throw an exception.
8500 : //
8501 : // TODO(verwaest): Force throw an exception if the callback doesn't, so we can
8502 : // remove reliance on default return values.
8503 118150 : if (it.state() == LookupIterator::ACCESS_CHECK) {
8504 6955 : if (!it.HasAccess()) {
8505 6 : isolate->ReportFailedAccessCheck(object);
8506 6 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
8507 0 : return it.factory()->undefined_value();
8508 : }
8509 6949 : it.Next();
8510 : }
8511 :
8512 : // Ignore accessors on typed arrays.
8513 118158 : if (it.IsElement() && object->HasFixedTypedArrayElements()) {
8514 0 : return it.factory()->undefined_value();
8515 : }
8516 :
8517 118144 : CHECK(GetPropertyAttributes(&it).IsJust());
8518 :
8519 : // ES5 forbids turning a property into an accessor if it's not
8520 : // configurable. See 8.6.1 (Table 5).
8521 118187 : if (it.IsFound() && !it.IsConfigurable()) {
8522 29 : return it.factory()->undefined_value();
8523 : }
8524 :
8525 118115 : it.TransitionToAccessorPair(info, info->property_attributes());
8526 :
8527 : return object;
8528 : }
8529 :
8530 84 : Object* JSObject::SlowReverseLookup(Object* value) {
8531 84 : if (HasFastProperties()) {
8532 : int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
8533 : DescriptorArray* descs = map()->instance_descriptors();
8534 : bool value_is_number = value->IsNumber();
8535 252 : for (int i = 0; i < number_of_own_descriptors; i++) {
8536 210 : PropertyDetails details = descs->GetDetails(i);
8537 210 : if (details.location() == kField) {
8538 : DCHECK_EQ(kData, details.kind());
8539 28 : FieldIndex field_index = FieldIndex::ForDescriptor(map(), i);
8540 28 : if (IsUnboxedDoubleField(field_index)) {
8541 0 : if (value_is_number) {
8542 : double property = RawFastDoublePropertyAt(field_index);
8543 0 : if (property == value->Number()) {
8544 28 : return descs->GetKey(i);
8545 : }
8546 : }
8547 : } else {
8548 28 : Object* property = RawFastPropertyAt(field_index);
8549 28 : if (field_index.is_double()) {
8550 : DCHECK(property->IsMutableHeapNumber());
8551 0 : if (value_is_number && property->Number() == value->Number()) {
8552 0 : return descs->GetKey(i);
8553 : }
8554 28 : } else if (property == value) {
8555 28 : return descs->GetKey(i);
8556 : }
8557 : }
8558 : } else {
8559 : DCHECK_EQ(kDescriptor, details.location());
8560 182 : if (details.kind() == kData) {
8561 168 : if (descs->GetValue(i) == value) {
8562 0 : return descs->GetKey(i);
8563 : }
8564 : }
8565 : }
8566 : }
8567 42 : return GetHeap()->undefined_value();
8568 14 : } else if (IsJSGlobalObject()) {
8569 14 : return global_dictionary()->SlowReverseLookup(value);
8570 : } else {
8571 0 : return property_dictionary()->SlowReverseLookup(value);
8572 : }
8573 : }
8574 :
8575 :
8576 25904759 : Handle<Map> Map::RawCopy(Handle<Map> map, int instance_size) {
8577 : Isolate* isolate = map->GetIsolate();
8578 : Handle<Map> result =
8579 25904759 : isolate->factory()->NewMap(map->instance_type(), instance_size);
8580 : Handle<Object> prototype(map->prototype(), isolate);
8581 25904748 : Map::SetPrototype(result, prototype);
8582 51809497 : result->set_constructor_or_backpointer(map->GetConstructor());
8583 : result->set_bit_field(map->bit_field());
8584 : result->set_bit_field2(map->bit_field2());
8585 : int new_bit_field3 = map->bit_field3();
8586 : new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true);
8587 : new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0);
8588 : new_bit_field3 = EnumLengthBits::update(new_bit_field3,
8589 : kInvalidEnumCacheSentinel);
8590 25904750 : new_bit_field3 = Deprecated::update(new_bit_field3, false);
8591 25904750 : if (!map->is_dictionary_map()) {
8592 24624742 : new_bit_field3 = IsUnstable::update(new_bit_field3, false);
8593 : }
8594 25904750 : result->set_bit_field3(new_bit_field3);
8595 25904750 : return result;
8596 : }
8597 :
8598 :
8599 1317738 : Handle<Map> Map::Normalize(Handle<Map> fast_map, PropertyNormalizationMode mode,
8600 : const char* reason) {
8601 : DCHECK(!fast_map->is_dictionary_map());
8602 :
8603 329339 : Isolate* isolate = fast_map->GetIsolate();
8604 : Handle<Object> maybe_cache(isolate->native_context()->normalized_map_cache(),
8605 2635476 : isolate);
8606 : bool use_cache =
8607 2400975 : !fast_map->is_prototype_map() && !maybe_cache->IsUndefined(isolate);
8608 : Handle<NormalizedMapCache> cache;
8609 1317738 : if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache);
8610 :
8611 : Handle<Map> new_map;
8612 3483264 : if (use_cache && cache->Get(fast_map, mode).ToHandle(&new_map)) {
8613 : #ifdef VERIFY_HEAP
8614 : if (FLAG_verify_heap) new_map->DictionaryMapVerify();
8615 : #endif
8616 : #ifdef ENABLE_SLOW_DCHECKS
8617 : if (FLAG_enable_slow_asserts) {
8618 : // The cached map should match newly created normalized map bit-by-bit,
8619 : // except for the code cache, which can contain some ics which can be
8620 : // applied to the shared map, dependent code and weak cell cache.
8621 : Handle<Map> fresh = Map::CopyNormalized(fast_map, mode);
8622 :
8623 : if (new_map->is_prototype_map()) {
8624 : // For prototype maps, the PrototypeInfo is not copied.
8625 : DCHECK(memcmp(fresh->address(), new_map->address(),
8626 : kTransitionsOrPrototypeInfoOffset) == 0);
8627 : DCHECK(fresh->raw_transitions() == Smi::kZero);
8628 : STATIC_ASSERT(kDescriptorsOffset ==
8629 : kTransitionsOrPrototypeInfoOffset + kPointerSize);
8630 : DCHECK(memcmp(HeapObject::RawField(*fresh, kDescriptorsOffset),
8631 : HeapObject::RawField(*new_map, kDescriptorsOffset),
8632 : kCodeCacheOffset - kDescriptorsOffset) == 0);
8633 : } else {
8634 : DCHECK(memcmp(fresh->address(), new_map->address(),
8635 : Map::kCodeCacheOffset) == 0);
8636 : }
8637 : STATIC_ASSERT(Map::kDependentCodeOffset ==
8638 : Map::kCodeCacheOffset + kPointerSize);
8639 : STATIC_ASSERT(Map::kWeakCellCacheOffset ==
8640 : Map::kDependentCodeOffset + kPointerSize);
8641 : int offset = Map::kWeakCellCacheOffset + kPointerSize;
8642 : DCHECK(memcmp(fresh->address() + offset,
8643 : new_map->address() + offset,
8644 : Map::kSize - offset) == 0);
8645 : }
8646 : #endif
8647 : } else {
8648 564314 : new_map = Map::CopyNormalized(fast_map, mode);
8649 564314 : if (use_cache) {
8650 329339 : cache->Set(fast_map, new_map);
8651 329339 : isolate->counters()->maps_normalized()->Increment();
8652 : }
8653 : #if TRACE_MAPS
8654 : if (FLAG_trace_maps) {
8655 : PrintF("[TraceMaps: Normalize from= %p to= %p reason= %s ]\n",
8656 : reinterpret_cast<void*>(*fast_map),
8657 : reinterpret_cast<void*>(*new_map), reason);
8658 : }
8659 : #endif
8660 : }
8661 1317738 : fast_map->NotifyLeafMapLayoutChange();
8662 1317738 : return new_map;
8663 : }
8664 :
8665 :
8666 564314 : Handle<Map> Map::CopyNormalized(Handle<Map> map,
8667 : PropertyNormalizationMode mode) {
8668 : int new_instance_size = map->instance_size();
8669 564314 : if (mode == CLEAR_INOBJECT_PROPERTIES) {
8670 109803 : new_instance_size -= map->GetInObjectProperties() * kPointerSize;
8671 : }
8672 :
8673 564314 : Handle<Map> result = RawCopy(map, new_instance_size);
8674 :
8675 564314 : if (mode != CLEAR_INOBJECT_PROPERTIES) {
8676 : result->SetInObjectProperties(map->GetInObjectProperties());
8677 : }
8678 :
8679 : result->set_dictionary_map(true);
8680 : result->set_migration_target(false);
8681 : result->set_construction_counter(kNoSlackTracking);
8682 :
8683 : #ifdef VERIFY_HEAP
8684 : if (FLAG_verify_heap) result->DictionaryMapVerify();
8685 : #endif
8686 :
8687 564314 : return result;
8688 : }
8689 :
8690 : // Return an immutable prototype exotic object version of the input map.
8691 : // Never even try to cache it in the transition tree, as it is intended
8692 : // for the global object and its prototype chain, and excluding it saves
8693 : // memory on the map transition tree.
8694 :
8695 : // static
8696 7 : Handle<Map> Map::TransitionToImmutableProto(Handle<Map> map) {
8697 7 : Handle<Map> new_map = Map::Copy(map, "ImmutablePrototype");
8698 : new_map->set_immutable_proto(true);
8699 7 : return new_map;
8700 : }
8701 :
8702 410220 : Handle<Map> Map::CopyInitialMap(Handle<Map> map, int instance_size,
8703 : int in_object_properties,
8704 : int unused_property_fields) {
8705 : #ifdef DEBUG
8706 : Isolate* isolate = map->GetIsolate();
8707 : // Strict function maps have Function as a constructor but the
8708 : // Function's initial map is a sloppy function map. Same holds for
8709 : // GeneratorFunction / AsyncFunction and its initial map.
8710 : Object* constructor = map->GetConstructor();
8711 : DCHECK(constructor->IsJSFunction());
8712 : DCHECK(*map == JSFunction::cast(constructor)->initial_map() ||
8713 : *map == *isolate->strict_function_map() ||
8714 : *map == *isolate->generator_function_map() ||
8715 : *map == *isolate->async_function_map());
8716 : #endif
8717 : // Initial maps must always own their descriptors and it's descriptor array
8718 : // does not contain descriptors that do not belong to the map.
8719 : DCHECK(map->owns_descriptors());
8720 : DCHECK_EQ(map->NumberOfOwnDescriptors(),
8721 : map->instance_descriptors()->number_of_descriptors());
8722 :
8723 410220 : Handle<Map> result = RawCopy(map, instance_size);
8724 :
8725 : // Please note instance_type and instance_size are set when allocated.
8726 : result->SetInObjectProperties(in_object_properties);
8727 : result->set_unused_property_fields(unused_property_fields);
8728 :
8729 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
8730 410220 : if (number_of_own_descriptors > 0) {
8731 : // The copy will use the same descriptors array.
8732 : result->UpdateDescriptors(map->instance_descriptors(),
8733 214003 : map->GetLayoutDescriptor());
8734 : result->SetNumberOfOwnDescriptors(number_of_own_descriptors);
8735 :
8736 : DCHECK_EQ(result->NumberOfFields(),
8737 : in_object_properties - unused_property_fields);
8738 : }
8739 :
8740 410220 : return result;
8741 : }
8742 :
8743 :
8744 24930225 : Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) {
8745 24930225 : Handle<Map> result = RawCopy(map, map->instance_size());
8746 :
8747 : // Please note instance_type and instance_size are set when allocated.
8748 24930219 : if (map->IsJSObjectMap()) {
8749 : result->SetInObjectProperties(map->GetInObjectProperties());
8750 : result->set_unused_property_fields(map->unused_property_fields());
8751 : }
8752 : result->ClearCodeCache(map->GetHeap());
8753 24930219 : map->NotifyLeafMapLayoutChange();
8754 24930225 : return result;
8755 : }
8756 :
8757 :
8758 9525533 : Handle<Map> Map::ShareDescriptor(Handle<Map> map,
8759 : Handle<DescriptorArray> descriptors,
8760 : Descriptor* descriptor) {
8761 : // Sanity check. This path is only to be taken if the map owns its descriptor
8762 : // array, implying that its NumberOfOwnDescriptors equals the number of
8763 : // descriptors in the descriptor array.
8764 : DCHECK_EQ(map->NumberOfOwnDescriptors(),
8765 : map->instance_descriptors()->number_of_descriptors());
8766 :
8767 9525533 : Handle<Map> result = CopyDropDescriptors(map);
8768 9525533 : Handle<Name> name = descriptor->GetKey();
8769 :
8770 : // Ensure there's space for the new descriptor in the shared descriptor array.
8771 9525533 : if (descriptors->NumberOfSlackDescriptors() == 0) {
8772 5825462 : int old_size = descriptors->number_of_descriptors();
8773 5825462 : if (old_size == 0) {
8774 531 : descriptors = DescriptorArray::Allocate(map->GetIsolate(), 0, 1);
8775 : } else {
8776 5824931 : int slack = SlackForArraySize(old_size, kMaxNumberOfDescriptors);
8777 5824931 : EnsureDescriptorSlack(map, slack);
8778 : descriptors = handle(map->instance_descriptors());
8779 : }
8780 : }
8781 :
8782 : Handle<LayoutDescriptor> layout_descriptor =
8783 : FLAG_unbox_double_fields
8784 : ? LayoutDescriptor::ShareAppend(map, descriptor->GetDetails())
8785 9525533 : : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
8786 :
8787 : {
8788 : DisallowHeapAllocation no_gc;
8789 9525532 : descriptors->Append(descriptor);
8790 9525533 : result->InitializeDescriptors(*descriptors, *layout_descriptor);
8791 : }
8792 :
8793 : DCHECK(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1);
8794 9525531 : ConnectTransition(map, result, name, SIMPLE_PROPERTY_TRANSITION);
8795 :
8796 9525533 : return result;
8797 : }
8798 :
8799 :
8800 : #if TRACE_MAPS
8801 :
8802 : // static
8803 : void Map::TraceTransition(const char* what, Map* from, Map* to, Name* name) {
8804 : if (FLAG_trace_maps) {
8805 : PrintF("[TraceMaps: %s from= %p to= %p name= ", what,
8806 : reinterpret_cast<void*>(from), reinterpret_cast<void*>(to));
8807 : name->NameShortPrint();
8808 : PrintF(" ]\n");
8809 : }
8810 : }
8811 :
8812 :
8813 : // static
8814 : void Map::TraceAllTransitions(Map* map) {
8815 : Object* transitions = map->raw_transitions();
8816 : int num_transitions = TransitionArray::NumberOfTransitions(transitions);
8817 : for (int i = -0; i < num_transitions; ++i) {
8818 : Map* target = TransitionArray::GetTarget(transitions, i);
8819 : Name* key = TransitionArray::GetKey(transitions, i);
8820 : Map::TraceTransition("Transition", map, target, key);
8821 : Map::TraceAllTransitions(target);
8822 : }
8823 : }
8824 :
8825 : #endif // TRACE_MAPS
8826 :
8827 :
8828 11747190 : void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
8829 : Handle<Name> name, SimpleTransitionFlag flag) {
8830 23494380 : if (!parent->GetBackPointer()->IsUndefined(parent->GetIsolate())) {
8831 : parent->set_owns_descriptors(false);
8832 : } else {
8833 : // |parent| is initial map and it must keep the ownership, there must be no
8834 : // descriptors in the descriptors array that do not belong to the map.
8835 : DCHECK(parent->owns_descriptors());
8836 : DCHECK_EQ(parent->NumberOfOwnDescriptors(),
8837 : parent->instance_descriptors()->number_of_descriptors());
8838 : }
8839 11747190 : if (parent->is_prototype_map()) {
8840 : DCHECK(child->is_prototype_map());
8841 : #if TRACE_MAPS
8842 : Map::TraceTransition("NoTransition", *parent, *child, *name);
8843 : #endif
8844 : } else {
8845 11747190 : TransitionArray::Insert(parent, name, child, flag);
8846 : #if TRACE_MAPS
8847 : Map::TraceTransition("Transition", *parent, *child, *name);
8848 : #endif
8849 : }
8850 11747192 : }
8851 :
8852 :
8853 14384997 : Handle<Map> Map::CopyReplaceDescriptors(
8854 : Handle<Map> map, Handle<DescriptorArray> descriptors,
8855 : Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag,
8856 : MaybeHandle<Name> maybe_name, const char* reason,
8857 : SimpleTransitionFlag simple_flag) {
8858 : DCHECK(descriptors->IsSortedNoDuplicates());
8859 :
8860 14384997 : Handle<Map> result = CopyDropDescriptors(map);
8861 :
8862 14384993 : if (!map->is_prototype_map()) {
8863 11247526 : if (flag == INSERT_TRANSITION &&
8864 1830886 : TransitionArray::CanHaveMoreTransitions(map)) {
8865 1830886 : result->InitializeDescriptors(*descriptors, *layout_descriptor);
8866 :
8867 : Handle<Name> name;
8868 1830886 : CHECK(maybe_name.ToHandle(&name));
8869 1830886 : ConnectTransition(map, result, name, simple_flag);
8870 : } else {
8871 7585754 : descriptors->GeneralizeAllFields();
8872 : result->InitializeDescriptors(*descriptors,
8873 7585755 : LayoutDescriptor::FastPointerLayout());
8874 : }
8875 : } else {
8876 4968353 : result->InitializeDescriptors(*descriptors, *layout_descriptor);
8877 : }
8878 : #if TRACE_MAPS
8879 : if (FLAG_trace_maps &&
8880 : // Mirror conditions above that did not call ConnectTransition().
8881 : (map->is_prototype_map() ||
8882 : !(flag == INSERT_TRANSITION &&
8883 : TransitionArray::CanHaveMoreTransitions(map)))) {
8884 : PrintF("[TraceMaps: ReplaceDescriptors from= %p to= %p reason= %s ]\n",
8885 : reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*result),
8886 : reason);
8887 : }
8888 : #endif
8889 :
8890 14384994 : return result;
8891 : }
8892 :
8893 :
8894 : // Creates transition tree starting from |split_map| and adding all descriptors
8895 : // starting from descriptor with index |split_map|.NumberOfOwnDescriptors().
8896 : // The way how it is done is tricky because of GC and special descriptors
8897 : // marking logic.
8898 167389 : Handle<Map> Map::AddMissingTransitions(
8899 : Handle<Map> split_map, Handle<DescriptorArray> descriptors,
8900 : Handle<LayoutDescriptor> full_layout_descriptor) {
8901 : DCHECK(descriptors->IsSortedNoDuplicates());
8902 : int split_nof = split_map->NumberOfOwnDescriptors();
8903 167389 : int nof_descriptors = descriptors->number_of_descriptors();
8904 : DCHECK_LT(split_nof, nof_descriptors);
8905 :
8906 : // Start with creating last map which will own full descriptors array.
8907 : // This is necessary to guarantee that GC will mark the whole descriptor
8908 : // array if any of the allocations happening below fail.
8909 : // Number of unused properties is temporarily incorrect and the layout
8910 : // descriptor could unnecessarily be in slow mode but we will fix after
8911 : // all the other intermediate maps are created.
8912 167389 : Handle<Map> last_map = CopyDropDescriptors(split_map);
8913 167389 : last_map->InitializeDescriptors(*descriptors, *full_layout_descriptor);
8914 : last_map->set_unused_property_fields(0);
8915 :
8916 : // During creation of intermediate maps we violate descriptors sharing
8917 : // invariant since the last map is not yet connected to the transition tree
8918 : // we create here. But it is safe because GC never trims map's descriptors
8919 : // if there are no dead transitions from that map and this is exactly the
8920 : // case for all the intermediate maps we create here.
8921 : Handle<Map> map = split_map;
8922 248739 : for (int i = split_nof; i < nof_descriptors - 1; ++i) {
8923 81350 : Handle<Map> new_map = CopyDropDescriptors(map);
8924 81350 : InstallDescriptors(map, new_map, i, descriptors, full_layout_descriptor);
8925 81350 : map = new_map;
8926 : }
8927 167389 : map->NotifyLeafMapLayoutChange();
8928 : InstallDescriptors(map, last_map, nof_descriptors - 1, descriptors,
8929 167389 : full_layout_descriptor);
8930 167389 : return last_map;
8931 : }
8932 :
8933 :
8934 : // Since this method is used to rewrite an existing transition tree, it can
8935 : // always insert transitions without checking.
8936 248739 : void Map::InstallDescriptors(Handle<Map> parent, Handle<Map> child,
8937 : int new_descriptor,
8938 : Handle<DescriptorArray> descriptors,
8939 : Handle<LayoutDescriptor> full_layout_descriptor) {
8940 : DCHECK(descriptors->IsSortedNoDuplicates());
8941 :
8942 248739 : child->set_instance_descriptors(*descriptors);
8943 248739 : child->SetNumberOfOwnDescriptors(new_descriptor + 1);
8944 :
8945 : int unused_property_fields = parent->unused_property_fields();
8946 248739 : PropertyDetails details = descriptors->GetDetails(new_descriptor);
8947 248739 : if (details.location() == kField) {
8948 231304 : unused_property_fields = parent->unused_property_fields() - 1;
8949 231304 : if (unused_property_fields < 0) {
8950 21507 : unused_property_fields += JSObject::kFieldsAdded;
8951 : }
8952 : }
8953 : child->set_unused_property_fields(unused_property_fields);
8954 :
8955 : if (FLAG_unbox_double_fields) {
8956 : Handle<LayoutDescriptor> layout_descriptor =
8957 : LayoutDescriptor::AppendIfFastOrUseFull(parent, details,
8958 248739 : full_layout_descriptor);
8959 248739 : child->set_layout_descriptor(*layout_descriptor);
8960 : #ifdef VERIFY_HEAP
8961 : // TODO(ishell): remove these checks from VERIFY_HEAP mode.
8962 : if (FLAG_verify_heap) {
8963 : CHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
8964 : }
8965 : #else
8966 : SLOW_DCHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
8967 : #endif
8968 248739 : child->set_visitor_id(Heap::GetStaticVisitorIdForMap(*child));
8969 : }
8970 :
8971 248739 : Handle<Name> name = handle(descriptors->GetKey(new_descriptor));
8972 248739 : ConnectTransition(parent, child, name, SIMPLE_PROPERTY_TRANSITION);
8973 248739 : }
8974 :
8975 :
8976 273410 : Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind,
8977 : TransitionFlag flag) {
8978 : Map* maybe_elements_transition_map = NULL;
8979 273410 : if (flag == INSERT_TRANSITION) {
8980 : // Ensure we are requested to add elements kind transition "near the root".
8981 : DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(),
8982 : map->NumberOfOwnDescriptors());
8983 :
8984 : maybe_elements_transition_map = map->ElementsTransitionMap();
8985 : DCHECK(maybe_elements_transition_map == NULL ||
8986 : (maybe_elements_transition_map->elements_kind() ==
8987 : DICTIONARY_ELEMENTS &&
8988 : kind == DICTIONARY_ELEMENTS));
8989 : DCHECK(!IsFastElementsKind(kind) ||
8990 : IsMoreGeneralElementsKindTransition(map->elements_kind(), kind));
8991 : DCHECK(kind != map->elements_kind());
8992 : }
8993 :
8994 268049 : bool insert_transition = flag == INSERT_TRANSITION &&
8995 415275 : TransitionArray::CanHaveMoreTransitions(map) &&
8996 : maybe_elements_transition_map == NULL;
8997 :
8998 273410 : if (insert_transition) {
8999 141865 : Handle<Map> new_map = CopyForTransition(map, "CopyAsElementsKind");
9000 : new_map->set_elements_kind(kind);
9001 :
9002 : Isolate* isolate = map->GetIsolate();
9003 : Handle<Name> name = isolate->factory()->elements_transition_symbol();
9004 141865 : ConnectTransition(map, new_map, name, SPECIAL_TRANSITION);
9005 141865 : return new_map;
9006 : }
9007 :
9008 : // Create a new free-floating map only if we are not allowed to store it.
9009 131545 : Handle<Map> new_map = Copy(map, "CopyAsElementsKind");
9010 : new_map->set_elements_kind(kind);
9011 131545 : return new_map;
9012 : }
9013 :
9014 :
9015 731 : Handle<Map> Map::AsLanguageMode(Handle<Map> initial_map,
9016 : LanguageMode language_mode, FunctionKind kind) {
9017 : DCHECK_EQ(JS_FUNCTION_TYPE, initial_map->instance_type());
9018 : // Initial map for sloppy mode function is stored in the function
9019 : // constructor. Initial maps for strict mode are cached as special transitions
9020 : // using |strict_function_transition_symbol| as a key.
9021 731 : if (language_mode == SLOPPY) return initial_map;
9022 : Isolate* isolate = initial_map->GetIsolate();
9023 :
9024 226 : int map_index = Context::FunctionMapIndex(language_mode, kind);
9025 : Handle<Map> function_map(
9026 452 : Map::cast(isolate->native_context()->get(map_index)));
9027 :
9028 : STATIC_ASSERT(LANGUAGE_END == 2);
9029 : DCHECK_EQ(STRICT, language_mode);
9030 : Handle<Symbol> transition_symbol =
9031 : isolate->factory()->strict_function_transition_symbol();
9032 : Map* maybe_transition =
9033 226 : TransitionArray::SearchSpecial(*initial_map, *transition_symbol);
9034 226 : if (maybe_transition != NULL) {
9035 : return handle(maybe_transition, isolate);
9036 : }
9037 170 : initial_map->NotifyLeafMapLayoutChange();
9038 :
9039 : // Create new map taking descriptors from the |function_map| and all
9040 : // the other details from the |initial_map|.
9041 : Handle<Map> map =
9042 : Map::CopyInitialMap(function_map, initial_map->instance_size(),
9043 : initial_map->GetInObjectProperties(),
9044 170 : initial_map->unused_property_fields());
9045 170 : map->SetConstructor(initial_map->GetConstructor());
9046 170 : map->set_prototype(initial_map->prototype());
9047 :
9048 170 : if (TransitionArray::CanHaveMoreTransitions(initial_map)) {
9049 : Map::ConnectTransition(initial_map, map, transition_symbol,
9050 170 : SPECIAL_TRANSITION);
9051 : }
9052 170 : return map;
9053 : }
9054 :
9055 :
9056 141865 : Handle<Map> Map::CopyForTransition(Handle<Map> map, const char* reason) {
9057 : DCHECK(!map->is_prototype_map());
9058 141865 : Handle<Map> new_map = CopyDropDescriptors(map);
9059 :
9060 141865 : if (map->owns_descriptors()) {
9061 : // In case the map owned its own descriptors, share the descriptors and
9062 : // transfer ownership to the new map.
9063 : // The properties did not change, so reuse descriptors.
9064 : new_map->InitializeDescriptors(map->instance_descriptors(),
9065 141863 : map->GetLayoutDescriptor());
9066 : } else {
9067 : // In case the map did not own its own descriptors, a split is forced by
9068 : // copying the map; creating a new descriptor array cell.
9069 : Handle<DescriptorArray> descriptors(map->instance_descriptors());
9070 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9071 : Handle<DescriptorArray> new_descriptors =
9072 : DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
9073 : Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9074 : map->GetIsolate());
9075 2 : new_map->InitializeDescriptors(*new_descriptors, *new_layout_descriptor);
9076 : }
9077 :
9078 : #if TRACE_MAPS
9079 : if (FLAG_trace_maps) {
9080 : PrintF("[TraceMaps: CopyForTransition from= %p to= %p reason= %s ]\n",
9081 : reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*new_map),
9082 : reason);
9083 : }
9084 : #endif
9085 :
9086 141865 : return new_map;
9087 : }
9088 :
9089 :
9090 6157609 : Handle<Map> Map::Copy(Handle<Map> map, const char* reason) {
9091 : Handle<DescriptorArray> descriptors(map->instance_descriptors());
9092 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9093 : Handle<DescriptorArray> new_descriptors =
9094 6157610 : DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
9095 : Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9096 : map->GetIsolate());
9097 : return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9098 : OMIT_TRANSITION, MaybeHandle<Name>(), reason,
9099 6157610 : SPECIAL_TRANSITION);
9100 : }
9101 :
9102 :
9103 250434 : Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) {
9104 : Handle<Map> copy =
9105 500868 : Copy(handle(isolate->object_function()->initial_map()), "MapCreate");
9106 :
9107 : // Check that we do not overflow the instance size when adding the extra
9108 : // inobject properties. If the instance size overflows, we allocate as many
9109 : // properties as we can as inobject properties.
9110 : int max_extra_properties =
9111 : (JSObject::kMaxInstanceSize - JSObject::kHeaderSize) >> kPointerSizeLog2;
9112 :
9113 250434 : if (inobject_properties > max_extra_properties) {
9114 : inobject_properties = max_extra_properties;
9115 : }
9116 :
9117 : int new_instance_size =
9118 250434 : JSObject::kHeaderSize + kPointerSize * inobject_properties;
9119 :
9120 : // Adjust the map with the extra inobject properties.
9121 : copy->SetInObjectProperties(inobject_properties);
9122 : copy->set_unused_property_fields(inobject_properties);
9123 : copy->set_instance_size(new_instance_size);
9124 250434 : copy->set_visitor_id(Heap::GetStaticVisitorIdForMap(*copy));
9125 250434 : return copy;
9126 : }
9127 :
9128 :
9129 51215 : Handle<Map> Map::CopyForPreventExtensions(Handle<Map> map,
9130 : PropertyAttributes attrs_to_add,
9131 : Handle<Symbol> transition_marker,
9132 : const char* reason) {
9133 : int num_descriptors = map->NumberOfOwnDescriptors();
9134 : Isolate* isolate = map->GetIsolate();
9135 : Handle<DescriptorArray> new_desc = DescriptorArray::CopyUpToAddAttributes(
9136 : handle(map->instance_descriptors(), isolate), num_descriptors,
9137 51215 : attrs_to_add);
9138 : Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9139 : isolate);
9140 : Handle<Map> new_map = CopyReplaceDescriptors(
9141 : map, new_desc, new_layout_descriptor, INSERT_TRANSITION,
9142 51215 : transition_marker, reason, SPECIAL_TRANSITION);
9143 : new_map->set_is_extensible(false);
9144 51215 : if (!IsFixedTypedArrayElementsKind(map->elements_kind())) {
9145 : ElementsKind new_kind = IsStringWrapperElementsKind(map->elements_kind())
9146 : ? SLOW_STRING_WRAPPER_ELEMENTS
9147 51141 : : DICTIONARY_ELEMENTS;
9148 : new_map->set_elements_kind(new_kind);
9149 : }
9150 51215 : return new_map;
9151 : }
9152 :
9153 : namespace {
9154 :
9155 25258440 : bool CanHoldValue(DescriptorArray* descriptors, int descriptor,
9156 : PropertyConstness constness, Object* value) {
9157 25258440 : PropertyDetails details = descriptors->GetDetails(descriptor);
9158 25258441 : if (details.location() == kField) {
9159 24683063 : if (details.kind() == kData) {
9160 24683062 : return IsGeneralizableTo(constness, details.constness()) &&
9161 73593902 : value->FitsRepresentation(details.representation()) &&
9162 48910836 : descriptors->GetFieldType(descriptor)->NowContains(value);
9163 : } else {
9164 : DCHECK_EQ(kAccessor, details.kind());
9165 : return false;
9166 : }
9167 :
9168 : } else {
9169 : DCHECK_EQ(kDescriptor, details.location());
9170 : DCHECK_EQ(kConst, details.constness());
9171 575378 : if (details.kind() == kData) {
9172 : DCHECK(!FLAG_track_constant_fields);
9173 : DCHECK(descriptors->GetValue(descriptor) != value ||
9174 : value->FitsRepresentation(details.representation()));
9175 575378 : return descriptors->GetValue(descriptor) == value;
9176 : } else {
9177 : DCHECK_EQ(kAccessor, details.kind());
9178 : return false;
9179 : }
9180 : }
9181 : UNREACHABLE();
9182 : return false;
9183 : }
9184 :
9185 25258439 : Handle<Map> UpdateDescriptorForValue(Handle<Map> map, int descriptor,
9186 : PropertyConstness constness,
9187 : Handle<Object> value) {
9188 25258439 : if (CanHoldValue(map->instance_descriptors(), descriptor, constness,
9189 : *value)) {
9190 24102815 : return map;
9191 : }
9192 :
9193 : Isolate* isolate = map->GetIsolate();
9194 : PropertyAttributes attributes =
9195 2311252 : map->instance_descriptors()->GetDetails(descriptor).attributes();
9196 1155626 : Representation representation = value->OptimalRepresentation();
9197 1155626 : Handle<FieldType> type = value->OptimalType(isolate, representation);
9198 :
9199 1155626 : MapUpdater mu(isolate, map);
9200 : return mu.ReconfigureToDataField(descriptor, attributes, constness,
9201 1155626 : representation, type);
9202 : }
9203 :
9204 : } // namespace
9205 :
9206 : // static
9207 10658805 : Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor,
9208 : PropertyConstness constness,
9209 : Handle<Object> value) {
9210 : // Dictionaries can store any property value.
9211 : DCHECK(!map->is_dictionary_map());
9212 : // Update to the newest map before storing the property.
9213 10658805 : return UpdateDescriptorForValue(Update(map), descriptor, constness, value);
9214 : }
9215 :
9216 30182367 : Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
9217 : Handle<Object> value,
9218 : PropertyAttributes attributes,
9219 : PropertyConstness constness,
9220 : StoreFromKeyed store_mode) {
9221 : RuntimeCallTimerScope stats_scope(
9222 : *map, map->is_prototype_map()
9223 : ? &RuntimeCallStats::PrototypeMap_TransitionToDataProperty
9224 30182367 : : &RuntimeCallStats::Map_TransitionToDataProperty);
9225 :
9226 : DCHECK(name->IsUniqueName());
9227 : DCHECK(!map->is_dictionary_map());
9228 :
9229 : // Migrate to the newest map before storing the property.
9230 30182382 : map = Update(map);
9231 :
9232 : Map* maybe_transition =
9233 30182378 : TransitionArray::SearchTransition(*map, kData, *name, attributes);
9234 30182370 : if (maybe_transition != NULL) {
9235 : Handle<Map> transition(maybe_transition);
9236 : int descriptor = transition->LastAdded();
9237 :
9238 : DCHECK_EQ(attributes, transition->instance_descriptors()
9239 : ->GetDetails(descriptor)
9240 : .attributes());
9241 :
9242 14599631 : return UpdateDescriptorForValue(transition, descriptor, constness, value);
9243 : }
9244 :
9245 : TransitionFlag flag = INSERT_TRANSITION;
9246 : MaybeHandle<Map> maybe_map;
9247 15582740 : if (!FLAG_track_constant_fields && value->IsJSFunction()) {
9248 6716985 : maybe_map = Map::CopyWithConstant(map, name, value, attributes, flag);
9249 8865755 : } else if (!map->TooManyFastProperties(store_mode)) {
9250 : Isolate* isolate = name->GetIsolate();
9251 8764661 : Representation representation = value->OptimalRepresentation();
9252 8764659 : Handle<FieldType> type = value->OptimalType(isolate, representation);
9253 : maybe_map = Map::CopyWithField(map, name, type, attributes, constness,
9254 8764661 : representation, flag);
9255 : }
9256 :
9257 : Handle<Map> result;
9258 15582741 : if (!maybe_map.ToHandle(&result)) {
9259 : Isolate* isolate = name->GetIsolate();
9260 : const char* reason = "TooManyFastProperties";
9261 : #if TRACE_MAPS
9262 : std::unique_ptr<ScopedVector<char>> buffer;
9263 : if (FLAG_trace_maps) {
9264 : ScopedVector<char> name_buffer(100);
9265 : name->NameShortPrint(name_buffer);
9266 : buffer.reset(new ScopedVector<char>(128));
9267 : SNPrintF(*buffer, "TooManyFastProperties %s", name_buffer.start());
9268 : reason = buffer->start();
9269 : }
9270 : #endif
9271 101209 : Handle<Object> maybe_constructor(map->GetConstructor(), isolate);
9272 101209 : if (FLAG_feedback_normalization && map->new_target_is_base() &&
9273 101209 : maybe_constructor->IsJSFunction() &&
9274 : !JSFunction::cast(*maybe_constructor)->shared()->native()) {
9275 : Handle<JSFunction> constructor =
9276 : Handle<JSFunction>::cast(maybe_constructor);
9277 : DCHECK_NE(*constructor,
9278 : constructor->context()->native_context()->object_function());
9279 : Handle<Map> initial_map(constructor->initial_map(), isolate);
9280 0 : result = Map::Normalize(initial_map, CLEAR_INOBJECT_PROPERTIES, reason);
9281 0 : initial_map->DeprecateTransitionTree();
9282 : Handle<Object> prototype(result->prototype(), isolate);
9283 0 : JSFunction::SetInitialMap(constructor, result, prototype);
9284 :
9285 : // Deoptimize all code that embeds the previous initial map.
9286 : initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
9287 0 : isolate, DependentCode::kInitialMapChangedGroup);
9288 0 : if (!result->EquivalentToForNormalization(*map,
9289 0 : CLEAR_INOBJECT_PROPERTIES)) {
9290 0 : result = Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, reason);
9291 : }
9292 : } else {
9293 101209 : result = Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, reason);
9294 : }
9295 : }
9296 :
9297 15582741 : return result;
9298 : }
9299 :
9300 :
9301 1515099 : Handle<Map> Map::ReconfigureExistingProperty(Handle<Map> map, int descriptor,
9302 : PropertyKind kind,
9303 : PropertyAttributes attributes) {
9304 : // Dictionaries have to be reconfigured in-place.
9305 : DCHECK(!map->is_dictionary_map());
9306 :
9307 3030199 : if (!map->GetBackPointer()->IsMap()) {
9308 : // There is no benefit from reconstructing transition tree for maps without
9309 : // back pointers.
9310 : return CopyGeneralizeAllFields(map, map->elements_kind(), descriptor, kind,
9311 : attributes,
9312 1489827 : "GenAll_AttributesMismatchProtoMap");
9313 : }
9314 :
9315 25273 : if (FLAG_trace_generalization) {
9316 0 : map->PrintReconfiguration(stdout, descriptor, kind, attributes);
9317 : }
9318 :
9319 : Isolate* isolate = map->GetIsolate();
9320 :
9321 25273 : MapUpdater mu(isolate, map);
9322 : DCHECK_EQ(kData, kind); // Only kData case is supported so far.
9323 : Handle<Map> new_map = mu.ReconfigureToDataField(
9324 : descriptor, attributes, kDefaultFieldConstness, Representation::None(),
9325 25273 : FieldType::None(isolate));
9326 25273 : return new_map;
9327 : }
9328 :
9329 434778 : Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map,
9330 : Handle<Name> name, int descriptor,
9331 : Handle<Object> getter,
9332 : Handle<Object> setter,
9333 : PropertyAttributes attributes) {
9334 : RuntimeCallTimerScope stats_scope(
9335 : isolate,
9336 : map->is_prototype_map()
9337 : ? &RuntimeCallStats::PrototypeMap_TransitionToAccessorProperty
9338 434778 : : &RuntimeCallStats::Map_TransitionToAccessorProperty);
9339 :
9340 : // At least one of the accessors needs to be a new value.
9341 : DCHECK(!getter->IsNull(isolate) || !setter->IsNull(isolate));
9342 : DCHECK(name->IsUniqueName());
9343 :
9344 : // Dictionary maps can always have additional data properties.
9345 434778 : if (map->is_dictionary_map()) return map;
9346 :
9347 : // Migrate to the newest map before transitioning to the new property.
9348 434778 : map = Update(map);
9349 :
9350 : PropertyNormalizationMode mode = map->is_prototype_map()
9351 : ? KEEP_INOBJECT_PROPERTIES
9352 434778 : : CLEAR_INOBJECT_PROPERTIES;
9353 :
9354 : Map* maybe_transition =
9355 434778 : TransitionArray::SearchTransition(*map, kAccessor, *name, attributes);
9356 434778 : if (maybe_transition != NULL) {
9357 : Handle<Map> transition(maybe_transition, isolate);
9358 : DescriptorArray* descriptors = transition->instance_descriptors();
9359 : int descriptor = transition->LastAdded();
9360 : DCHECK(descriptors->GetKey(descriptor)->Equals(*name));
9361 :
9362 : DCHECK_EQ(kAccessor, descriptors->GetDetails(descriptor).kind());
9363 : DCHECK_EQ(attributes, descriptors->GetDetails(descriptor).attributes());
9364 :
9365 : Handle<Object> maybe_pair(descriptors->GetValue(descriptor), isolate);
9366 18809 : if (!maybe_pair->IsAccessorPair()) {
9367 0 : return Map::Normalize(map, mode, "TransitionToAccessorFromNonPair");
9368 : }
9369 :
9370 : Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair);
9371 18809 : if (!pair->Equals(*getter, *setter)) {
9372 17908 : return Map::Normalize(map, mode, "TransitionToDifferentAccessor");
9373 : }
9374 :
9375 901 : return transition;
9376 : }
9377 :
9378 : Handle<AccessorPair> pair;
9379 : DescriptorArray* old_descriptors = map->instance_descriptors();
9380 415969 : if (descriptor != DescriptorArray::kNotFound) {
9381 158119 : if (descriptor != map->LastAdded()) {
9382 3251 : return Map::Normalize(map, mode, "AccessorsOverwritingNonLast");
9383 : }
9384 154868 : PropertyDetails old_details = old_descriptors->GetDetails(descriptor);
9385 154868 : if (old_details.kind() != kAccessor) {
9386 152339 : return Map::Normalize(map, mode, "AccessorsOverwritingNonAccessors");
9387 : }
9388 :
9389 2529 : if (old_details.attributes() != attributes) {
9390 131 : return Map::Normalize(map, mode, "AccessorsWithAttributes");
9391 : }
9392 :
9393 : Handle<Object> maybe_pair(old_descriptors->GetValue(descriptor), isolate);
9394 2398 : if (!maybe_pair->IsAccessorPair()) {
9395 28 : return Map::Normalize(map, mode, "AccessorsOverwritingNonPair");
9396 : }
9397 :
9398 : Handle<AccessorPair> current_pair = Handle<AccessorPair>::cast(maybe_pair);
9399 2370 : if (current_pair->Equals(*getter, *setter)) return map;
9400 :
9401 : bool overwriting_accessor = false;
9402 4733 : if (!getter->IsNull(isolate) &&
9403 4589 : !current_pair->get(ACCESSOR_GETTER)->IsNull(isolate) &&
9404 : current_pair->get(ACCESSOR_GETTER) != *getter) {
9405 : overwriting_accessor = true;
9406 : }
9407 4726 : if (!setter->IsNull(isolate) &&
9408 4185 : !current_pair->get(ACCESSOR_SETTER)->IsNull(isolate) &&
9409 : current_pair->get(ACCESSOR_SETTER) != *setter) {
9410 : overwriting_accessor = true;
9411 : }
9412 2370 : if (overwriting_accessor) {
9413 2094 : return Map::Normalize(map, mode, "AccessorsOverwritingAccessors");
9414 : }
9415 :
9416 276 : pair = AccessorPair::Copy(Handle<AccessorPair>::cast(maybe_pair));
9417 515700 : } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors ||
9418 257850 : map->TooManyFastProperties(CERTAINLY_NOT_STORE_FROM_KEYED)) {
9419 0 : return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, "TooManyAccessors");
9420 : } else {
9421 257850 : pair = isolate->factory()->NewAccessorPair();
9422 : }
9423 :
9424 258126 : pair->SetComponents(*getter, *setter);
9425 :
9426 : TransitionFlag flag = INSERT_TRANSITION;
9427 : Descriptor d = Descriptor::AccessorConstant(name, pair, attributes);
9428 258126 : return Map::CopyInsertDescriptor(map, &d, flag);
9429 : }
9430 :
9431 :
9432 15754549 : Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
9433 : Descriptor* descriptor,
9434 : TransitionFlag flag) {
9435 : Handle<DescriptorArray> descriptors(map->instance_descriptors());
9436 :
9437 : // Share descriptors only if map owns descriptors and it not an initial map.
9438 47178457 : if (flag == INSERT_TRANSITION && map->owns_descriptors() &&
9439 40949727 : !map->GetBackPointer()->IsUndefined(map->GetIsolate()) &&
9440 9525533 : TransitionArray::CanHaveMoreTransitions(map)) {
9441 9525533 : return ShareDescriptor(map, descriptors, descriptor);
9442 : }
9443 :
9444 : int nof = map->NumberOfOwnDescriptors();
9445 : Handle<DescriptorArray> new_descriptors =
9446 : DescriptorArray::CopyUpTo(descriptors, nof, 1);
9447 6229017 : new_descriptors->Append(descriptor);
9448 :
9449 : Handle<LayoutDescriptor> new_layout_descriptor =
9450 : FLAG_unbox_double_fields
9451 6229018 : ? LayoutDescriptor::New(map, new_descriptors, nof + 1)
9452 6229018 : : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
9453 :
9454 : return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9455 : flag, descriptor->GetKey(), "CopyAddDescriptor",
9456 6229018 : SIMPLE_PROPERTY_TRANSITION);
9457 : }
9458 :
9459 :
9460 258174 : Handle<Map> Map::CopyInsertDescriptor(Handle<Map> map,
9461 : Descriptor* descriptor,
9462 : TransitionFlag flag) {
9463 : Handle<DescriptorArray> old_descriptors(map->instance_descriptors());
9464 :
9465 : // We replace the key if it is already present.
9466 : int index = old_descriptors->SearchWithCache(map->GetIsolate(),
9467 : *descriptor->GetKey(), *map);
9468 258174 : if (index != DescriptorArray::kNotFound) {
9469 276 : return CopyReplaceDescriptor(map, old_descriptors, descriptor, index, flag);
9470 : }
9471 257898 : return CopyAddDescriptor(map, descriptor, flag);
9472 : }
9473 :
9474 :
9475 0 : Handle<DescriptorArray> DescriptorArray::CopyUpTo(
9476 : Handle<DescriptorArray> desc,
9477 : int enumeration_index,
9478 : int slack) {
9479 : return DescriptorArray::CopyUpToAddAttributes(
9480 20161700 : desc, enumeration_index, NONE, slack);
9481 : }
9482 :
9483 :
9484 20212910 : Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
9485 : Handle<DescriptorArray> desc,
9486 : int enumeration_index,
9487 : PropertyAttributes attributes,
9488 : int slack) {
9489 20212910 : if (enumeration_index + slack == 0) {
9490 : return desc->GetIsolate()->factory()->empty_descriptor_array();
9491 : }
9492 :
9493 : int size = enumeration_index;
9494 :
9495 : Handle<DescriptorArray> descriptors =
9496 18015316 : DescriptorArray::Allocate(desc->GetIsolate(), size, slack);
9497 :
9498 18015316 : if (attributes != NONE) {
9499 78469 : for (int i = 0; i < size; ++i) {
9500 : Object* value = desc->GetValue(i);
9501 : Name* key = desc->GetKey(i);
9502 78469 : PropertyDetails details = desc->GetDetails(i);
9503 : // Bulk attribute changes never affect private properties.
9504 78469 : if (!key->IsPrivate()) {
9505 : int mask = DONT_DELETE | DONT_ENUM;
9506 : // READ_ONLY is an invalid attribute for JS setters/getters.
9507 79854 : if (details.kind() != kAccessor || !value->IsAccessorPair()) {
9508 : mask |= READ_ONLY;
9509 : }
9510 : details = details.CopyAddAttributes(
9511 78413 : static_cast<PropertyAttributes>(attributes & mask));
9512 : }
9513 78469 : descriptors->Set(i, key, value, details);
9514 : }
9515 : } else {
9516 154691642 : for (int i = 0; i < size; ++i) {
9517 154691633 : descriptors->CopyFrom(i, *desc);
9518 : }
9519 : }
9520 :
9521 18113086 : if (desc->number_of_descriptors() != enumeration_index) descriptors->Sort();
9522 :
9523 18015317 : return descriptors;
9524 : }
9525 :
9526 :
9527 8607 : bool DescriptorArray::IsEqualUpTo(DescriptorArray* desc, int nof_descriptors) {
9528 56569 : for (int i = 0; i < nof_descriptors; i++) {
9529 95924 : if (GetKey(i) != desc->GetKey(i) || GetValue(i) != desc->GetValue(i)) {
9530 : return false;
9531 : }
9532 47962 : PropertyDetails details = GetDetails(i);
9533 47962 : PropertyDetails other_details = desc->GetDetails(i);
9534 95924 : if (details.kind() != other_details.kind() ||
9535 95924 : details.location() != other_details.location() ||
9536 : !details.representation().Equals(other_details.representation())) {
9537 : return false;
9538 : }
9539 : }
9540 : return true;
9541 : }
9542 :
9543 :
9544 276 : Handle<Map> Map::CopyReplaceDescriptor(Handle<Map> map,
9545 : Handle<DescriptorArray> descriptors,
9546 : Descriptor* descriptor,
9547 : int insertion_index,
9548 : TransitionFlag flag) {
9549 : Handle<Name> key = descriptor->GetKey();
9550 : DCHECK(*key == descriptors->GetKey(insertion_index));
9551 :
9552 : Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
9553 : descriptors, map->NumberOfOwnDescriptors());
9554 :
9555 276 : new_descriptors->Replace(insertion_index, descriptor);
9556 : Handle<LayoutDescriptor> new_layout_descriptor = LayoutDescriptor::New(
9557 276 : map, new_descriptors, new_descriptors->number_of_descriptors());
9558 :
9559 : SimpleTransitionFlag simple_flag =
9560 276 : (insertion_index == descriptors->number_of_descriptors() - 1)
9561 : ? SIMPLE_PROPERTY_TRANSITION
9562 276 : : PROPERTY_TRANSITION;
9563 : return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9564 : flag, key, "CopyReplaceDescriptor",
9565 276 : simple_flag);
9566 : }
9567 :
9568 : // Helper class to manage a Map's code cache. The layout depends on the number
9569 : // of entries; this is worthwhile because most code caches are very small,
9570 : // but some are huge (thousands of entries).
9571 : // For zero entries, the EmptyFixedArray is used.
9572 : // For one entry, we use a 2-element FixedArray containing [name, code].
9573 : // For 2..100 entries, we use a FixedArray with linear lookups, the layout is:
9574 : // [0] - number of slots that are currently in use
9575 : // [1] - first name
9576 : // [2] - first code
9577 : // [3] - second name
9578 : // [4] - second code
9579 : // etc.
9580 : // For more than 128 entries, we use a CodeCacheHashTable.
9581 : class CodeCache : public AllStatic {
9582 : public:
9583 : // Returns the new cache, to be stored on the map.
9584 39712 : static Handle<FixedArray> Put(Isolate* isolate, Handle<FixedArray> cache,
9585 : Handle<Name> name, Handle<Code> code) {
9586 : int length = cache->length();
9587 39712 : if (length == 0) return PutFirstElement(isolate, name, code);
9588 2387 : if (length == kEntrySize) {
9589 577 : return PutSecondElement(isolate, cache, name, code);
9590 : }
9591 1810 : if (length <= kLinearMaxSize) {
9592 1663 : Handle<FixedArray> result = PutLinearElement(isolate, cache, name, code);
9593 1663 : if (!result.is_null()) return result;
9594 : // Fall through if linear storage is getting too large.
9595 : }
9596 154 : return PutHashTableElement(isolate, cache, name, code);
9597 : }
9598 :
9599 43561 : static Code* Lookup(FixedArray* cache, Name* name, Code::Flags flags) {
9600 : int length = cache->length();
9601 43561 : if (length == 0) return nullptr;
9602 6243 : if (length == kEntrySize) return OneElementLookup(cache, name, flags);
9603 3701 : if (!cache->IsCodeCacheHashTable()) {
9604 2490 : return LinearLookup(cache, name, flags);
9605 : } else {
9606 1211 : return CodeCacheHashTable::cast(cache)->Lookup(name, flags);
9607 : }
9608 : }
9609 :
9610 : private:
9611 : static const int kNameIndex = 0;
9612 : static const int kCodeIndex = 1;
9613 : static const int kEntrySize = 2;
9614 :
9615 : static const int kLinearUsageIndex = 0;
9616 : static const int kLinearReservedSlots = 1;
9617 : static const int kLinearInitialCapacity = 2;
9618 : static const int kLinearMaxSize = 257; // == LinearSizeFor(128);
9619 :
9620 : static const int kHashTableInitialCapacity = 200; // Number of entries.
9621 :
9622 : static int LinearSizeFor(int entries) {
9623 164 : return kLinearReservedSlots + kEntrySize * entries;
9624 : }
9625 :
9626 : static int LinearNewSize(int old_size) {
9627 164 : int old_entries = (old_size - kLinearReservedSlots) / kEntrySize;
9628 164 : return LinearSizeFor(old_entries * 2);
9629 : }
9630 :
9631 2542 : static Code* OneElementLookup(FixedArray* cache, Name* name,
9632 : Code::Flags flags) {
9633 : DCHECK_EQ(cache->length(), kEntrySize);
9634 2542 : if (cache->get(kNameIndex) != name) return nullptr;
9635 : Code* maybe_code = Code::cast(cache->get(kCodeIndex));
9636 2239 : if (maybe_code->flags() != flags) return nullptr;
9637 2192 : return maybe_code;
9638 : }
9639 :
9640 2490 : static Code* LinearLookup(FixedArray* cache, Name* name, Code::Flags flags) {
9641 : DCHECK_GE(cache->length(), kEntrySize);
9642 : DCHECK(!cache->IsCodeCacheHashTable());
9643 : int usage = GetLinearUsage(cache);
9644 59584 : for (int i = kLinearReservedSlots; i < usage; i += kEntrySize) {
9645 59544 : if (cache->get(i + kNameIndex) != name) continue;
9646 2501 : Code* code = Code::cast(cache->get(i + kCodeIndex));
9647 2501 : if (code->flags() == flags) return code;
9648 : }
9649 : return nullptr;
9650 : }
9651 :
9652 37325 : static Handle<FixedArray> PutFirstElement(Isolate* isolate, Handle<Name> name,
9653 : Handle<Code> code) {
9654 37325 : Handle<FixedArray> cache = isolate->factory()->NewFixedArray(kEntrySize);
9655 37325 : cache->set(kNameIndex, *name);
9656 37325 : cache->set(kCodeIndex, *code);
9657 37325 : return cache;
9658 : }
9659 :
9660 577 : static Handle<FixedArray> PutSecondElement(Isolate* isolate,
9661 : Handle<FixedArray> cache,
9662 : Handle<Name> name,
9663 : Handle<Code> code) {
9664 : DCHECK_EQ(cache->length(), kEntrySize);
9665 : Handle<FixedArray> new_cache = isolate->factory()->NewFixedArray(
9666 577 : LinearSizeFor(kLinearInitialCapacity));
9667 577 : new_cache->set(kLinearReservedSlots + kNameIndex, cache->get(kNameIndex));
9668 577 : new_cache->set(kLinearReservedSlots + kCodeIndex, cache->get(kCodeIndex));
9669 577 : new_cache->set(LinearSizeFor(1) + kNameIndex, *name);
9670 577 : new_cache->set(LinearSizeFor(1) + kCodeIndex, *code);
9671 : new_cache->set(kLinearUsageIndex, Smi::FromInt(LinearSizeFor(2)));
9672 577 : return new_cache;
9673 : }
9674 :
9675 1663 : static Handle<FixedArray> PutLinearElement(Isolate* isolate,
9676 : Handle<FixedArray> cache,
9677 : Handle<Name> name,
9678 : Handle<Code> code) {
9679 : int length = cache->length();
9680 : int usage = GetLinearUsage(*cache);
9681 : DCHECK_LE(usage, length);
9682 : // Check if we need to grow.
9683 1663 : if (usage == length) {
9684 : int new_length = LinearNewSize(length);
9685 164 : if (new_length > kLinearMaxSize) return Handle<FixedArray>::null();
9686 : Handle<FixedArray> new_cache =
9687 157 : isolate->factory()->NewFixedArray(new_length);
9688 3841 : for (int i = kLinearReservedSlots; i < length; i++) {
9689 3684 : new_cache->set(i, cache->get(i));
9690 : }
9691 157 : cache = new_cache;
9692 : }
9693 : // Store new entry.
9694 : DCHECK_GE(cache->length(), usage + kEntrySize);
9695 1656 : cache->set(usage + kNameIndex, *name);
9696 3312 : cache->set(usage + kCodeIndex, *code);
9697 1656 : cache->set(kLinearUsageIndex, Smi::FromInt(usage + kEntrySize));
9698 1656 : return cache;
9699 : }
9700 :
9701 154 : static Handle<FixedArray> PutHashTableElement(Isolate* isolate,
9702 : Handle<FixedArray> cache,
9703 : Handle<Name> name,
9704 : Handle<Code> code) {
9705 : // Check if we need to transition from linear to hash table storage.
9706 154 : if (!cache->IsCodeCacheHashTable()) {
9707 : // Check that the initial hash table capacity is large enough.
9708 : DCHECK_EQ(kLinearMaxSize, LinearSizeFor(128));
9709 : STATIC_ASSERT(kHashTableInitialCapacity > 128);
9710 :
9711 : int length = cache->length();
9712 : // Only migrate from linear storage when it's full.
9713 : DCHECK_EQ(length, GetLinearUsage(*cache));
9714 : DCHECK_EQ(length, kLinearMaxSize);
9715 : Handle<CodeCacheHashTable> table =
9716 7 : CodeCacheHashTable::New(isolate, kHashTableInitialCapacity);
9717 : HandleScope scope(isolate);
9718 903 : for (int i = kLinearReservedSlots; i < length; i += kEntrySize) {
9719 : Handle<Name> old_name(Name::cast(cache->get(i + kNameIndex)), isolate);
9720 896 : Handle<Code> old_code(Code::cast(cache->get(i + kCodeIndex)), isolate);
9721 896 : CodeCacheHashTable::Put(table, old_name, old_code);
9722 : }
9723 : cache = table;
9724 : }
9725 : // Store new entry.
9726 : DCHECK(cache->IsCodeCacheHashTable());
9727 : return CodeCacheHashTable::Put(Handle<CodeCacheHashTable>::cast(cache),
9728 154 : name, code);
9729 : }
9730 :
9731 : static inline int GetLinearUsage(FixedArray* linear_cache) {
9732 : DCHECK_GT(linear_cache->length(), kEntrySize);
9733 : return Smi::cast(linear_cache->get(kLinearUsageIndex))->value();
9734 : }
9735 : };
9736 :
9737 39712 : void Map::UpdateCodeCache(Handle<Map> map,
9738 : Handle<Name> name,
9739 : Handle<Code> code) {
9740 : Isolate* isolate = map->GetIsolate();
9741 : Handle<FixedArray> cache(map->code_cache(), isolate);
9742 39712 : Handle<FixedArray> new_cache = CodeCache::Put(isolate, cache, name, code);
9743 39712 : map->set_code_cache(*new_cache);
9744 39712 : }
9745 :
9746 43561 : Code* Map::LookupInCodeCache(Name* name, Code::Flags flags) {
9747 43561 : return CodeCache::Lookup(code_cache(), name, flags);
9748 : }
9749 :
9750 :
9751 : // The key in the code cache hash table consists of the property name and the
9752 : // code object. The actual match is on the name and the code flags. If a key
9753 : // is created using the flags and not a code object it can only be used for
9754 : // lookup not to create a new entry.
9755 0 : class CodeCacheHashTableKey : public HashTableKey {
9756 : public:
9757 : CodeCacheHashTableKey(Handle<Name> name, Code::Flags flags)
9758 1211 : : name_(name), flags_(flags), code_() {
9759 : DCHECK(name_->IsUniqueName());
9760 : }
9761 :
9762 : CodeCacheHashTableKey(Handle<Name> name, Handle<Code> code)
9763 2100 : : name_(name), flags_(code->flags()), code_(code) {
9764 : DCHECK(name_->IsUniqueName());
9765 : }
9766 :
9767 1505 : bool IsMatch(Object* other) override {
9768 : DCHECK(other->IsFixedArray());
9769 : FixedArray* pair = FixedArray::cast(other);
9770 : Name* name = Name::cast(pair->get(0));
9771 : Code::Flags flags = Code::cast(pair->get(1))->flags();
9772 1505 : if (flags != flags_) return false;
9773 : DCHECK(name->IsUniqueName());
9774 1505 : return *name_ == name;
9775 : }
9776 :
9777 : static uint32_t NameFlagsHashHelper(Name* name, Code::Flags flags) {
9778 2261 : return name->Hash() ^ flags;
9779 : }
9780 :
9781 4522 : uint32_t Hash() override { return NameFlagsHashHelper(*name_, flags_); }
9782 :
9783 0 : uint32_t HashForObject(Object* obj) override {
9784 : FixedArray* pair = FixedArray::cast(obj);
9785 : Name* name = Name::cast(pair->get(0));
9786 : Code* code = Code::cast(pair->get(1));
9787 0 : return NameFlagsHashHelper(name, code->flags());
9788 : }
9789 :
9790 1050 : MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) override {
9791 : Handle<Code> code = code_.ToHandleChecked();
9792 1050 : Handle<FixedArray> pair = isolate->factory()->NewFixedArray(2);
9793 1050 : pair->set(0, *name_);
9794 1050 : pair->set(1, *code);
9795 1050 : return pair;
9796 : }
9797 :
9798 : private:
9799 : Handle<Name> name_;
9800 : Code::Flags flags_;
9801 : // TODO(jkummerow): We should be able to get by without this.
9802 : MaybeHandle<Code> code_;
9803 : };
9804 :
9805 :
9806 1050 : Handle<CodeCacheHashTable> CodeCacheHashTable::Put(
9807 : Handle<CodeCacheHashTable> cache, Handle<Name> name, Handle<Code> code) {
9808 : CodeCacheHashTableKey key(name, code);
9809 :
9810 1050 : Handle<CodeCacheHashTable> new_cache = EnsureCapacity(cache, 1, &key);
9811 :
9812 2100 : int entry = new_cache->FindInsertionEntry(key.Hash());
9813 1050 : Handle<Object> k = key.AsHandle(cache->GetIsolate());
9814 :
9815 1050 : new_cache->set(EntryToIndex(entry), *k);
9816 1050 : new_cache->ElementAdded();
9817 1050 : return new_cache;
9818 : }
9819 :
9820 1211 : Code* CodeCacheHashTable::Lookup(Name* name, Code::Flags flags) {
9821 : DisallowHeapAllocation no_alloc;
9822 : CodeCacheHashTableKey key(handle(name), flags);
9823 : int entry = FindEntry(&key);
9824 1211 : if (entry == kNotFound) return nullptr;
9825 1204 : return Code::cast(FixedArray::cast(get(EntryToIndex(entry)))->get(1));
9826 : }
9827 :
9828 10501010 : Handle<FixedArray> FixedArray::SetAndGrow(Handle<FixedArray> array, int index,
9829 : Handle<Object> value) {
9830 10501010 : if (index < array->length()) {
9831 9931652 : array->set(index, *value);
9832 9931652 : return array;
9833 : }
9834 : int capacity = array->length();
9835 569358 : do {
9836 1138716 : capacity = JSObject::NewElementsCapacity(capacity);
9837 : } while (capacity <= index);
9838 : Handle<FixedArray> new_array =
9839 569358 : array->GetIsolate()->factory()->NewUninitializedFixedArray(capacity);
9840 569358 : array->CopyTo(0, *new_array, 0, array->length());
9841 569358 : new_array->FillWithHoles(array->length(), new_array->length());
9842 569358 : new_array->set(index, *value);
9843 569358 : return new_array;
9844 : }
9845 :
9846 12880503 : void FixedArray::Shrink(int new_length) {
9847 : DCHECK(0 <= new_length && new_length <= length());
9848 12880503 : if (new_length < length()) {
9849 21159266 : GetHeap()->RightTrimFixedArray(this, length() - new_length);
9850 : }
9851 12880503 : }
9852 :
9853 618954 : void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos,
9854 : int len) const {
9855 : DisallowHeapAllocation no_gc;
9856 618954 : WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
9857 27218618 : for (int index = 0; index < len; index++) {
9858 53199326 : dest->set(dest_pos+index, get(pos+index), mode);
9859 : }
9860 618955 : }
9861 :
9862 : #ifdef DEBUG
9863 : bool FixedArray::IsEqualTo(FixedArray* other) {
9864 : if (length() != other->length()) return false;
9865 : for (int i = 0 ; i < length(); ++i) {
9866 : if (get(i) != other->get(i)) return false;
9867 : }
9868 : return true;
9869 : }
9870 : #endif
9871 :
9872 :
9873 : // static
9874 13248769 : void WeakFixedArray::Set(Handle<WeakFixedArray> array, int index,
9875 : Handle<HeapObject> value) {
9876 : DCHECK(array->IsEmptySlot(index)); // Don't overwrite anything.
9877 : Handle<WeakCell> cell =
9878 : value->IsMap() ? Map::WeakCellForMap(Handle<Map>::cast(value))
9879 25999395 : : array->GetIsolate()->factory()->NewWeakCell(value);
9880 26497534 : Handle<FixedArray>::cast(array)->set(index + kFirstIndex, *cell);
9881 13248768 : if (FLAG_trace_weak_arrays) {
9882 0 : PrintF("[WeakFixedArray: storing at index %d ]\n", index);
9883 : }
9884 : array->set_last_used_index(index);
9885 13248768 : }
9886 :
9887 :
9888 : // static
9889 13248762 : Handle<WeakFixedArray> WeakFixedArray::Add(Handle<Object> maybe_array,
9890 : Handle<HeapObject> value,
9891 : int* assigned_index) {
9892 : Handle<WeakFixedArray> array =
9893 13248766 : (maybe_array.is_null() || !maybe_array->IsWeakFixedArray())
9894 : ? Allocate(value->GetIsolate(), 1, Handle<WeakFixedArray>::null())
9895 13345052 : : Handle<WeakFixedArray>::cast(maybe_array);
9896 : // Try to store the new entry if there's room. Optimize for consecutive
9897 : // accesses.
9898 : int first_index = array->last_used_index();
9899 : int length = array->Length();
9900 13248770 : if (length > 0) {
9901 : for (int i = first_index;;) {
9902 57546249 : if (array->IsEmptySlot((i))) {
9903 13061489 : WeakFixedArray::Set(array, i, value);
9904 13061487 : if (assigned_index != NULL) *assigned_index = i;
9905 13061487 : return array;
9906 : }
9907 44484760 : if (FLAG_trace_weak_arrays) {
9908 0 : PrintF("[WeakFixedArray: searching for free slot]\n");
9909 : }
9910 44484761 : i = (i + 1) % length;
9911 44484761 : if (i == first_index) break;
9912 : }
9913 : }
9914 :
9915 : // No usable slot found, grow the array.
9916 187281 : int new_length = length == 0 ? 1 : length + (length >> 1) + 4;
9917 : Handle<WeakFixedArray> new_array =
9918 187281 : Allocate(array->GetIsolate(), new_length, array);
9919 187281 : if (FLAG_trace_weak_arrays) {
9920 0 : PrintF("[WeakFixedArray: growing to size %d ]\n", new_length);
9921 : }
9922 187281 : WeakFixedArray::Set(new_array, length, value);
9923 187281 : if (assigned_index != NULL) *assigned_index = length;
9924 187281 : return new_array;
9925 : }
9926 :
9927 :
9928 : template <class CompactionCallback>
9929 303 : void WeakFixedArray::Compact() {
9930 : FixedArray* array = FixedArray::cast(this);
9931 : int new_length = kFirstIndex;
9932 131248 : for (int i = kFirstIndex; i < array->length(); i++) {
9933 : Object* element = array->get(i);
9934 65321 : if (element->IsSmi()) continue;
9935 43807 : if (WeakCell::cast(element)->cleared()) continue;
9936 : Object* value = WeakCell::cast(element)->value();
9937 : CompactionCallback::Callback(value, i - kFirstIndex,
9938 230 : new_length - kFirstIndex);
9939 43688 : array->set(new_length++, element);
9940 : }
9941 303 : array->Shrink(new_length);
9942 : set_last_used_index(0);
9943 303 : }
9944 :
9945 :
9946 1068370 : void WeakFixedArray::Iterator::Reset(Object* maybe_array) {
9947 1068370 : if (maybe_array->IsWeakFixedArray()) {
9948 425549 : list_ = WeakFixedArray::cast(maybe_array);
9949 425549 : index_ = 0;
9950 : #ifdef DEBUG
9951 : last_used_index_ = list_->last_used_index();
9952 : #endif // DEBUG
9953 : }
9954 1068370 : }
9955 :
9956 :
9957 0 : void JSObject::PrototypeRegistryCompactionCallback::Callback(Object* value,
9958 : int old_index,
9959 : int new_index) {
9960 : DCHECK(value->IsMap() && Map::cast(value)->is_prototype_map());
9961 : Map* map = Map::cast(value);
9962 : DCHECK(map->prototype_info()->IsPrototypeInfo());
9963 : PrototypeInfo* proto_info = PrototypeInfo::cast(map->prototype_info());
9964 : DCHECK_EQ(old_index, proto_info->registry_slot());
9965 : proto_info->set_registry_slot(new_index);
9966 0 : }
9967 :
9968 :
9969 : template void WeakFixedArray::Compact<WeakFixedArray::NullCallback>();
9970 : template void
9971 : WeakFixedArray::Compact<JSObject::PrototypeRegistryCompactionCallback>();
9972 :
9973 :
9974 6234878 : bool WeakFixedArray::Remove(Handle<HeapObject> value) {
9975 6234878 : if (Length() == 0) return false;
9976 : // Optimize for the most recently added element to be removed again.
9977 : int first_index = last_used_index();
9978 : for (int i = first_index;;) {
9979 13662549 : if (Get(i) == *value) {
9980 : Clear(i);
9981 : // Users of WeakFixedArray should make sure that there are no duplicates.
9982 6234879 : return true;
9983 : }
9984 1192792 : i = (i + 1) % Length();
9985 596396 : if (i == first_index) return false;
9986 : }
9987 : UNREACHABLE();
9988 : }
9989 :
9990 :
9991 : // static
9992 283574 : Handle<WeakFixedArray> WeakFixedArray::Allocate(
9993 : Isolate* isolate, int size, Handle<WeakFixedArray> initialize_from) {
9994 : DCHECK(0 <= size);
9995 : Handle<FixedArray> result =
9996 283574 : isolate->factory()->NewUninitializedFixedArray(size + kFirstIndex);
9997 : int index = 0;
9998 283574 : if (!initialize_from.is_null()) {
9999 : DCHECK(initialize_from->Length() <= size);
10000 : Handle<FixedArray> raw_source = Handle<FixedArray>::cast(initialize_from);
10001 : // Copy the entries without compacting, since the PrototypeInfo relies on
10002 : // the index of the entries not to change.
10003 37610254 : while (index < raw_source->length()) {
10004 37422973 : result->set(index, raw_source->get(index));
10005 37422973 : index++;
10006 : }
10007 : }
10008 19826681 : while (index < result->length()) {
10009 : result->set(index, Smi::kZero);
10010 19543107 : index++;
10011 : }
10012 283574 : return Handle<WeakFixedArray>::cast(result);
10013 : }
10014 :
10015 : // static
10016 2215 : Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj,
10017 : AddMode mode) {
10018 2215 : int length = array->Length();
10019 2215 : array = EnsureSpace(array, length + 1);
10020 2215 : if (mode == kReloadLengthAfterAllocation) {
10021 : DCHECK(array->Length() <= length);
10022 0 : length = array->Length();
10023 : }
10024 : array->Set(length, *obj);
10025 : array->SetLength(length + 1);
10026 2215 : return array;
10027 : }
10028 :
10029 : // static
10030 962182 : Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj1,
10031 : Handle<Object> obj2, AddMode mode) {
10032 962182 : int length = array->Length();
10033 962182 : array = EnsureSpace(array, length + 2);
10034 962182 : if (mode == kReloadLengthAfterAllocation) {
10035 38125 : length = array->Length();
10036 : }
10037 : array->Set(length, *obj1);
10038 : array->Set(length + 1, *obj2);
10039 : array->SetLength(length + 2);
10040 962182 : return array;
10041 : }
10042 :
10043 : // static
10044 472 : Handle<ArrayList> ArrayList::New(Isolate* isolate, int size) {
10045 : Handle<ArrayList> result = Handle<ArrayList>::cast(
10046 472 : isolate->factory()->NewFixedArray(size + kFirstIndex));
10047 : result->SetLength(0);
10048 472 : return result;
10049 : }
10050 :
10051 210 : Handle<FixedArray> ArrayList::Elements() const {
10052 420 : Handle<FixedArray> result = GetIsolate()->factory()->NewFixedArray(Length());
10053 : // Do not copy the first entry, i.e., the length.
10054 420 : CopyTo(kFirstIndex, *result, 0, Length());
10055 210 : return result;
10056 : }
10057 :
10058 38125 : bool ArrayList::IsFull() {
10059 : int capacity = length();
10060 38125 : return kFirstIndex + Length() == capacity;
10061 : }
10062 :
10063 : namespace {
10064 :
10065 5988436 : Handle<FixedArray> EnsureSpaceInFixedArray(Handle<FixedArray> array,
10066 : int length) {
10067 : int capacity = array->length();
10068 5988436 : if (capacity < length) {
10069 : Isolate* isolate = array->GetIsolate();
10070 : int new_capacity = length;
10071 97822 : new_capacity = new_capacity + Max(new_capacity / 2, 2);
10072 48911 : int grow_by = new_capacity - capacity;
10073 48911 : array = isolate->factory()->CopyFixedArrayAndGrow(array, grow_by);
10074 : }
10075 5988436 : return array;
10076 : }
10077 :
10078 : } // namespace
10079 :
10080 : // static
10081 964397 : Handle<ArrayList> ArrayList::EnsureSpace(Handle<ArrayList> array, int length) {
10082 : const bool empty = (array->length() == 0);
10083 : auto ret = Handle<ArrayList>::cast(
10084 1928794 : EnsureSpaceInFixedArray(array, kFirstIndex + length));
10085 964397 : if (empty) ret->SetLength(0);
10086 964397 : return ret;
10087 : }
10088 :
10089 259822 : Handle<RegExpMatchInfo> RegExpMatchInfo::ReserveCaptures(
10090 : Handle<RegExpMatchInfo> match_info, int capture_count) {
10091 : DCHECK_GE(match_info->length(), kLastMatchOverhead);
10092 259822 : const int required_length = kFirstCaptureIndex + capture_count;
10093 : Handle<FixedArray> result =
10094 259822 : EnsureSpaceInFixedArray(match_info, required_length);
10095 259822 : return Handle<RegExpMatchInfo>::cast(result);
10096 : }
10097 :
10098 : // static
10099 4726137 : Handle<FrameArray> FrameArray::AppendJSFrame(Handle<FrameArray> in,
10100 : Handle<Object> receiver,
10101 : Handle<JSFunction> function,
10102 : Handle<AbstractCode> code,
10103 : int offset, int flags) {
10104 : const int frame_count = in->FrameCount();
10105 4726137 : const int new_length = LengthFor(frame_count + 1);
10106 : Handle<FrameArray> array = EnsureSpace(in, new_length);
10107 : array->SetReceiver(frame_count, *receiver);
10108 : array->SetFunction(frame_count, *function);
10109 : array->SetCode(frame_count, *code);
10110 : array->SetOffset(frame_count, Smi::FromInt(offset));
10111 4726137 : array->SetFlags(frame_count, Smi::FromInt(flags));
10112 : array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));
10113 4726137 : return array;
10114 : }
10115 :
10116 : // static
10117 38080 : Handle<FrameArray> FrameArray::AppendWasmFrame(Handle<FrameArray> in,
10118 : Handle<Object> wasm_instance,
10119 : int wasm_function_index,
10120 : Handle<AbstractCode> code,
10121 : int offset, int flags) {
10122 : const int frame_count = in->FrameCount();
10123 38080 : const int new_length = LengthFor(frame_count + 1);
10124 : Handle<FrameArray> array = EnsureSpace(in, new_length);
10125 : array->SetWasmInstance(frame_count, *wasm_instance);
10126 : array->SetWasmFunctionIndex(frame_count, Smi::FromInt(wasm_function_index));
10127 : // code will be a null handle for interpreted wasm frames.
10128 38080 : if (!code.is_null()) array->SetCode(frame_count, *code);
10129 : array->SetOffset(frame_count, Smi::FromInt(offset));
10130 38080 : array->SetFlags(frame_count, Smi::FromInt(flags));
10131 : array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));
10132 38080 : return array;
10133 : }
10134 :
10135 2419438 : void FrameArray::ShrinkToFit() { Shrink(LengthFor(FrameCount())); }
10136 :
10137 : // static
10138 0 : Handle<FrameArray> FrameArray::EnsureSpace(Handle<FrameArray> array,
10139 : int length) {
10140 4764217 : return Handle<FrameArray>::cast(EnsureSpaceInFixedArray(array, length));
10141 : }
10142 :
10143 18576670 : Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate,
10144 : int number_of_descriptors,
10145 : int slack,
10146 : PretenureFlag pretenure) {
10147 : DCHECK(0 <= number_of_descriptors);
10148 : Factory* factory = isolate->factory();
10149 : // Do not use DescriptorArray::cast on incomplete object.
10150 18576670 : int size = number_of_descriptors + slack;
10151 18576670 : if (size == 0) return factory->empty_descriptor_array();
10152 : // Allocate the array of keys.
10153 : Handle<FixedArray> result =
10154 18576670 : factory->NewFixedArray(LengthFor(size), pretenure);
10155 :
10156 : result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors));
10157 : result->set(kEnumCacheIndex, Smi::kZero);
10158 : return Handle<DescriptorArray>::cast(result);
10159 : }
10160 :
10161 12 : void DescriptorArray::ClearEnumCache() { set(kEnumCacheIndex, Smi::kZero); }
10162 :
10163 2496355 : void DescriptorArray::Replace(int index, Descriptor* descriptor) {
10164 : descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index));
10165 2496355 : Set(index, descriptor);
10166 2496356 : }
10167 :
10168 :
10169 : // static
10170 114863 : void DescriptorArray::SetEnumCache(Handle<DescriptorArray> descriptors,
10171 : Isolate* isolate,
10172 : Handle<FixedArray> new_cache,
10173 : Handle<FixedArray> new_index_cache) {
10174 : DCHECK(!descriptors->IsEmpty());
10175 : FixedArray* bridge_storage;
10176 114863 : bool needs_new_enum_cache = !descriptors->HasEnumCache();
10177 114863 : if (needs_new_enum_cache) {
10178 : bridge_storage = *isolate->factory()->NewFixedArray(
10179 189764 : DescriptorArray::kEnumCacheBridgeLength);
10180 : } else {
10181 : bridge_storage = FixedArray::cast(descriptors->get(kEnumCacheIndex));
10182 : }
10183 114863 : bridge_storage->set(kEnumCacheBridgeCacheIndex, *new_cache);
10184 : bridge_storage->set(
10185 : kEnumCacheBridgeIndicesCacheIndex,
10186 229726 : new_index_cache.is_null() ? Object::cast(Smi::kZero) : *new_index_cache);
10187 114863 : if (needs_new_enum_cache) {
10188 94882 : descriptors->set(kEnumCacheIndex, bridge_storage);
10189 : }
10190 114863 : }
10191 :
10192 154691632 : void DescriptorArray::CopyFrom(int index, DescriptorArray* src) {
10193 154691632 : PropertyDetails details = src->GetDetails(index);
10194 154691635 : Set(index, src->GetKey(index), src->GetValue(index), details);
10195 154691646 : }
10196 :
10197 672987 : void DescriptorArray::Sort() {
10198 : // In-place heap sort.
10199 672987 : int len = number_of_descriptors();
10200 : // Reset sorting since the descriptor array might contain invalid pointers.
10201 672987 : for (int i = 0; i < len; ++i) SetSortedKey(i, i);
10202 : // Bottom-up max-heap construction.
10203 : // Index of the last node with children
10204 672987 : const int max_parent_index = (len / 2) - 1;
10205 2377018 : for (int i = max_parent_index; i >= 0; --i) {
10206 : int parent_index = i;
10207 1704031 : const uint32_t parent_hash = GetSortedKey(i)->Hash();
10208 5030286 : while (parent_index <= max_parent_index) {
10209 2445606 : int child_index = 2 * parent_index + 1;
10210 2445606 : uint32_t child_hash = GetSortedKey(child_index)->Hash();
10211 2445606 : if (child_index + 1 < len) {
10212 2078141 : uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
10213 2078141 : if (right_child_hash > child_hash) {
10214 : child_index++;
10215 : child_hash = right_child_hash;
10216 : }
10217 : }
10218 2445606 : if (child_hash <= parent_hash) break;
10219 1622224 : SwapSortedKeys(parent_index, child_index);
10220 : // Now element at child_index could be < its children.
10221 : parent_index = child_index; // parent_hash remains correct.
10222 : }
10223 : }
10224 :
10225 : // Extract elements and create sorted array.
10226 3823641 : for (int i = len - 1; i > 0; --i) {
10227 : // Put max element at the back of the array.
10228 3150654 : SwapSortedKeys(0, i);
10229 : // Shift down the new top element.
10230 : int parent_index = 0;
10231 3150654 : const uint32_t parent_hash = GetSortedKey(parent_index)->Hash();
10232 3150654 : const int max_parent_index = (i / 2) - 1;
10233 12639607 : while (parent_index <= max_parent_index) {
10234 6810081 : int child_index = parent_index * 2 + 1;
10235 6810081 : uint32_t child_hash = GetSortedKey(child_index)->Hash();
10236 6810081 : if (child_index + 1 < i) {
10237 6147622 : uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
10238 6147622 : if (right_child_hash > child_hash) {
10239 : child_index++;
10240 : child_hash = right_child_hash;
10241 : }
10242 : }
10243 6810081 : if (child_hash <= parent_hash) break;
10244 6338299 : SwapSortedKeys(parent_index, child_index);
10245 : parent_index = child_index;
10246 : }
10247 : }
10248 : DCHECK(IsSortedNoDuplicates());
10249 672987 : }
10250 :
10251 :
10252 17523 : Handle<AccessorPair> AccessorPair::Copy(Handle<AccessorPair> pair) {
10253 17523 : Handle<AccessorPair> copy = pair->GetIsolate()->factory()->NewAccessorPair();
10254 17523 : copy->set_getter(pair->getter());
10255 17523 : copy->set_setter(pair->setter());
10256 17523 : return copy;
10257 : }
10258 :
10259 71561 : Handle<Object> AccessorPair::GetComponent(Handle<AccessorPair> accessor_pair,
10260 : AccessorComponent component) {
10261 : Object* accessor = accessor_pair->get(component);
10262 71561 : if (accessor->IsFunctionTemplateInfo()) {
10263 : return ApiNatives::InstantiateFunction(
10264 : handle(FunctionTemplateInfo::cast(accessor)))
10265 184 : .ToHandleChecked();
10266 : }
10267 : Isolate* isolate = accessor_pair->GetIsolate();
10268 71469 : if (accessor->IsNull(isolate)) {
10269 6815 : return isolate->factory()->undefined_value();
10270 : }
10271 : return handle(accessor, isolate);
10272 : }
10273 :
10274 670319 : Handle<DeoptimizationInputData> DeoptimizationInputData::New(
10275 : Isolate* isolate, int deopt_entry_count, PretenureFlag pretenure) {
10276 : return Handle<DeoptimizationInputData>::cast(
10277 : isolate->factory()->NewFixedArray(LengthFor(deopt_entry_count),
10278 670319 : pretenure));
10279 : }
10280 :
10281 :
10282 236326 : Handle<DeoptimizationOutputData> DeoptimizationOutputData::New(
10283 : Isolate* isolate,
10284 : int number_of_deopt_points,
10285 : PretenureFlag pretenure) {
10286 : Handle<FixedArray> result;
10287 236326 : if (number_of_deopt_points == 0) {
10288 : result = isolate->factory()->empty_fixed_array();
10289 : } else {
10290 : result = isolate->factory()->NewFixedArray(
10291 236326 : LengthOfFixedArray(number_of_deopt_points), pretenure);
10292 : }
10293 236326 : return Handle<DeoptimizationOutputData>::cast(result);
10294 : }
10295 :
10296 48 : SharedFunctionInfo* DeoptimizationInputData::GetInlinedFunction(int index) {
10297 48 : if (index == -1) {
10298 0 : return SharedFunctionInfo::cast(SharedFunctionInfo());
10299 : } else {
10300 48 : return SharedFunctionInfo::cast(LiteralArray()->get(index));
10301 : }
10302 : }
10303 :
10304 10643411 : int HandlerTable::LookupRange(int pc_offset, int* data_out,
10305 : CatchPrediction* prediction_out) {
10306 : int innermost_handler = -1;
10307 : #ifdef DEBUG
10308 : // Assuming that ranges are well nested, we don't need to track the innermost
10309 : // offsets. This is just to verify that the table is actually well nested.
10310 : int innermost_start = std::numeric_limits<int>::min();
10311 : int innermost_end = std::numeric_limits<int>::max();
10312 : #endif
10313 51034236 : for (int i = 0; i < length(); i += kRangeEntrySize) {
10314 : int start_offset = Smi::cast(get(i + kRangeStartIndex))->value();
10315 14873707 : int end_offset = Smi::cast(get(i + kRangeEndIndex))->value();
10316 14873707 : int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value();
10317 14873707 : int handler_offset = HandlerOffsetField::decode(handler_field);
10318 : CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
10319 14873707 : int handler_data = Smi::cast(get(i + kRangeDataIndex))->value();
10320 14873707 : if (pc_offset >= start_offset && pc_offset < end_offset) {
10321 : DCHECK_GE(start_offset, innermost_start);
10322 : DCHECK_LT(end_offset, innermost_end);
10323 : innermost_handler = handler_offset;
10324 : #ifdef DEBUG
10325 : innermost_start = start_offset;
10326 : innermost_end = end_offset;
10327 : #endif
10328 2174972 : if (data_out) *data_out = handler_data;
10329 2174972 : if (prediction_out) *prediction_out = prediction;
10330 : }
10331 : }
10332 10643411 : return innermost_handler;
10333 : }
10334 :
10335 :
10336 : // TODO(turbofan): Make sure table is sorted and use binary search.
10337 2088275 : int HandlerTable::LookupReturn(int pc_offset) {
10338 6636452 : for (int i = 0; i < length(); i += kReturnEntrySize) {
10339 : int return_offset = Smi::cast(get(i + kReturnOffsetIndex))->value();
10340 1555528 : int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value();
10341 1555528 : if (pc_offset == return_offset) {
10342 651154 : return HandlerOffsetField::decode(handler_field);
10343 : }
10344 : }
10345 : return -1;
10346 : }
10347 :
10348 :
10349 : #ifdef DEBUG
10350 : bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
10351 : if (IsEmpty()) return other->IsEmpty();
10352 : if (other->IsEmpty()) return false;
10353 : if (length() != other->length()) return false;
10354 : for (int i = 0; i < length(); ++i) {
10355 : if (get(i) != other->get(i)) return false;
10356 : }
10357 : return true;
10358 : }
10359 : #endif
10360 :
10361 : // static
10362 1838054 : Handle<String> String::Trim(Handle<String> string, TrimMode mode) {
10363 1838054 : Isolate* const isolate = string->GetIsolate();
10364 1838054 : string = String::Flatten(string);
10365 : int const length = string->length();
10366 :
10367 : // Perform left trimming if requested.
10368 : int left = 0;
10369 : UnicodeCache* unicode_cache = isolate->unicode_cache();
10370 1838054 : if (mode == kTrim || mode == kTrimLeft) {
10371 3693504 : while (left < length &&
10372 1846458 : unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) {
10373 9496 : left++;
10374 : }
10375 : }
10376 :
10377 : // Perform right trimming if requested.
10378 : int right = length;
10379 1838054 : if (mode == kTrim || mode == kTrimRight) {
10380 1838222 : while (
10381 3675856 : right > left &&
10382 3675268 : unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) {
10383 1050 : right--;
10384 : }
10385 : }
10386 :
10387 1838054 : return isolate->factory()->NewSubString(string, left, right);
10388 : }
10389 :
10390 3124575 : bool String::LooksValid() { return GetIsolate()->heap()->Contains(this); }
10391 :
10392 : // static
10393 1532984 : MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) {
10394 1532985 : if (name->IsString()) return Handle<String>::cast(name);
10395 : // ES6 section 9.2.11 SetFunctionName, step 4.
10396 : Isolate* const isolate = name->GetIsolate();
10397 : Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate);
10398 11319 : if (description->IsUndefined(isolate)) {
10399 : return isolate->factory()->empty_string();
10400 : }
10401 11193 : IncrementalStringBuilder builder(isolate);
10402 : builder.AppendCharacter('[');
10403 11193 : builder.AppendString(Handle<String>::cast(description));
10404 : builder.AppendCharacter(']');
10405 11193 : return builder.Finish();
10406 : }
10407 :
10408 : // static
10409 6814 : MaybeHandle<String> Name::ToFunctionName(Handle<Name> name,
10410 : Handle<String> prefix) {
10411 : Handle<String> name_string;
10412 : Isolate* const isolate = name->GetIsolate();
10413 13628 : ASSIGN_RETURN_ON_EXCEPTION(isolate, name_string, ToFunctionName(name),
10414 : String);
10415 6814 : IncrementalStringBuilder builder(isolate);
10416 6814 : builder.AppendString(prefix);
10417 : builder.AppendCharacter(' ');
10418 6814 : builder.AppendString(name_string);
10419 6814 : return builder.Finish();
10420 : }
10421 :
10422 : namespace {
10423 :
10424 : bool AreDigits(const uint8_t* s, int from, int to) {
10425 46568 : for (int i = from; i < to; i++) {
10426 108861 : if (s[i] < '0' || s[i] > '9') return false;
10427 : }
10428 :
10429 : return true;
10430 : }
10431 :
10432 :
10433 : int ParseDecimalInteger(const uint8_t* s, int from, int to) {
10434 : DCHECK(to - from < 10); // Overflow is not possible.
10435 : DCHECK(from < to);
10436 2619 : int d = s[from] - '0';
10437 :
10438 3198 : for (int i = from + 1; i < to; i++) {
10439 579 : d = 10 * d + (s[i] - '0');
10440 : }
10441 :
10442 : return d;
10443 : }
10444 :
10445 : } // namespace
10446 :
10447 :
10448 : // static
10449 12609845 : Handle<Object> String::ToNumber(Handle<String> subject) {
10450 2726891 : Isolate* const isolate = subject->GetIsolate();
10451 :
10452 : // Flatten {subject} string first.
10453 12609845 : subject = String::Flatten(subject);
10454 :
10455 : // Fast array index case.
10456 : uint32_t index;
10457 12609845 : if (subject->AsArrayIndex(&index)) {
10458 6002725 : return isolate->factory()->NewNumberFromUint(index);
10459 : }
10460 :
10461 : // Fast case: short integer or some sorts of junk values.
10462 6607120 : if (subject->IsSeqOneByteString()) {
10463 : int len = subject->length();
10464 4153631 : if (len == 0) return handle(Smi::kZero, isolate);
10465 :
10466 : DisallowHeapAllocation no_gc;
10467 4087193 : uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars();
10468 4087193 : bool minus = (data[0] == '-');
10469 4087193 : int start_pos = (minus ? 1 : 0);
10470 :
10471 4087193 : if (start_pos == len) {
10472 0 : return isolate->factory()->nan_value();
10473 4087193 : } else if (data[start_pos] > '9') {
10474 : // Fast check for a junk value. A valid string may start from a
10475 : // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit
10476 : // or the 'I' character ('Infinity'). All of that have codes not greater
10477 : // than '9' except 'I' and .
10478 3854314 : if (data[start_pos] != 'I' && data[start_pos] != 0xa0) {
10479 3844391 : return isolate->factory()->nan_value();
10480 : }
10481 297791 : } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
10482 : // The maximal/minimal smi has 10 digits. If the string has less digits
10483 : // we know it will fit into the smi-data type.
10484 : int d = ParseDecimalInteger(data, start_pos, len);
10485 2619 : if (minus) {
10486 2933 : if (d == 0) return isolate->factory()->minus_zero_value();
10487 2125 : d = -d;
10488 180 : } else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize &&
10489 0 : (len == 1 || data[0] != '0')) {
10490 : // String hash is not calculated yet but all the data are present.
10491 : // Update the hash field to speed up sequential convertions.
10492 0 : uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
10493 : #ifdef DEBUG
10494 : subject->Hash(); // Force hash calculation.
10495 : DCHECK_EQ(static_cast<int>(subject->hash_field()),
10496 : static_cast<int>(hash));
10497 : #endif
10498 : subject->set_hash_field(hash);
10499 : }
10500 2215 : return handle(Smi::FromInt(d), isolate);
10501 : }
10502 : }
10503 :
10504 : // Slower case.
10505 : int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY;
10506 : return isolate->factory()->NewNumber(
10507 2726891 : StringToDouble(isolate->unicode_cache(), subject, flags));
10508 : }
10509 :
10510 :
10511 125831565 : String::FlatContent String::GetFlatContent() {
10512 : DCHECK(!AllowHeapAllocation::IsAllowed());
10513 : int length = this->length();
10514 : StringShape shape(this);
10515 : String* string = this;
10516 : int offset = 0;
10517 125831565 : if (shape.representation_tag() == kConsStringTag) {
10518 : ConsString* cons = ConsString::cast(string);
10519 0 : if (cons->second()->length() != 0) {
10520 0 : return FlatContent();
10521 : }
10522 : string = cons->first();
10523 : shape = StringShape(string);
10524 125831565 : } else if (shape.representation_tag() == kSlicedStringTag) {
10525 : SlicedString* slice = SlicedString::cast(string);
10526 : offset = slice->offset();
10527 : string = slice->parent();
10528 : shape = StringShape(string);
10529 : DCHECK(shape.representation_tag() != kConsStringTag &&
10530 : shape.representation_tag() != kSlicedStringTag);
10531 : }
10532 125831565 : if (shape.representation_tag() == kThinStringTag) {
10533 : ThinString* thin = ThinString::cast(string);
10534 : string = thin->actual();
10535 : shape = StringShape(string);
10536 : DCHECK(!shape.IsCons());
10537 : DCHECK(!shape.IsSliced());
10538 : }
10539 125831565 : if (shape.encoding_tag() == kOneByteStringTag) {
10540 : const uint8_t* start;
10541 113713019 : if (shape.representation_tag() == kSeqStringTag) {
10542 113709868 : start = SeqOneByteString::cast(string)->GetChars();
10543 : } else {
10544 : start = ExternalOneByteString::cast(string)->GetChars();
10545 : }
10546 113713021 : return FlatContent(start + offset, length);
10547 : } else {
10548 : DCHECK(shape.encoding_tag() == kTwoByteStringTag);
10549 : const uc16* start;
10550 12118546 : if (shape.representation_tag() == kSeqStringTag) {
10551 12115756 : start = SeqTwoByteString::cast(string)->GetChars();
10552 : } else {
10553 : start = ExternalTwoByteString::cast(string)->GetChars();
10554 : }
10555 12118546 : return FlatContent(start + offset, length);
10556 : }
10557 : }
10558 :
10559 3734839 : std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
10560 : RobustnessFlag robust_flag,
10561 : int offset, int length,
10562 : int* length_return) {
10563 6859306 : if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
10564 : return std::unique_ptr<char[]>();
10565 : }
10566 : // Negative length means the to the end of the string.
10567 3734839 : if (length < 0) length = kMaxInt - offset;
10568 :
10569 : // Compute the size of the UTF-8 string. Start at the specified offset.
10570 : StringCharacterStream stream(this, offset);
10571 : int character_position = offset;
10572 : int utf8_bytes = 0;
10573 : int last = unibrow::Utf16::kNoPreviousCharacter;
10574 42635139 : while (stream.HasMore() && character_position++ < offset + length) {
10575 35165461 : uint16_t character = stream.GetNext();
10576 35165461 : utf8_bytes += unibrow::Utf8::Length(character, last);
10577 35165461 : last = character;
10578 : }
10579 :
10580 3734839 : if (length_return) {
10581 3085127 : *length_return = utf8_bytes;
10582 : }
10583 :
10584 3734839 : char* result = NewArray<char>(utf8_bytes + 1);
10585 :
10586 : // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
10587 3734839 : stream.Reset(this, offset);
10588 : character_position = offset;
10589 : int utf8_byte_position = 0;
10590 : last = unibrow::Utf16::kNoPreviousCharacter;
10591 42635139 : while (stream.HasMore() && character_position++ < offset + length) {
10592 35165461 : uint16_t character = stream.GetNext();
10593 35165461 : if (allow_nulls == DISALLOW_NULLS && character == 0) {
10594 : character = ' ';
10595 : }
10596 : utf8_byte_position +=
10597 35165461 : unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
10598 35165461 : last = character;
10599 : }
10600 3734839 : result[utf8_byte_position] = 0;
10601 : return std::unique_ptr<char[]>(result);
10602 : }
10603 :
10604 654070 : std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
10605 : RobustnessFlag robust_flag,
10606 : int* length_return) {
10607 654070 : return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
10608 : }
10609 :
10610 :
10611 82 : const uc16* String::GetTwoByteData(unsigned start) {
10612 : DCHECK(!IsOneByteRepresentationUnderneath());
10613 82 : switch (StringShape(this).representation_tag()) {
10614 : case kSeqStringTag:
10615 0 : return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
10616 : case kExternalStringTag:
10617 : return ExternalTwoByteString::cast(this)->
10618 82 : ExternalTwoByteStringGetData(start);
10619 : case kSlicedStringTag: {
10620 : SlicedString* slice = SlicedString::cast(this);
10621 0 : return slice->parent()->GetTwoByteData(start + slice->offset());
10622 : }
10623 : case kConsStringTag:
10624 : case kThinStringTag:
10625 0 : UNREACHABLE();
10626 : return NULL;
10627 : }
10628 0 : UNREACHABLE();
10629 : return NULL;
10630 : }
10631 :
10632 :
10633 0 : const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
10634 : return reinterpret_cast<uc16*>(
10635 0 : reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
10636 : }
10637 :
10638 :
10639 122039 : void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) {
10640 : Relocatable* current = isolate->relocatable_top();
10641 265715 : while (current != NULL) {
10642 21637 : current->PostGarbageCollection();
10643 21637 : current = current->prev_;
10644 : }
10645 122039 : }
10646 :
10647 :
10648 : // Reserve space for statics needing saving and restoring.
10649 1313 : int Relocatable::ArchiveSpacePerThread() {
10650 1313 : return sizeof(Relocatable*); // NOLINT
10651 : }
10652 :
10653 :
10654 : // Archive statics that are thread-local.
10655 22597 : char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
10656 22597 : *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
10657 : isolate->set_relocatable_top(NULL);
10658 22597 : return to + ArchiveSpacePerThread();
10659 : }
10660 :
10661 :
10662 : // Restore statics that are thread-local.
10663 22597 : char* Relocatable::RestoreState(Isolate* isolate, char* from) {
10664 22597 : isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
10665 22597 : return from + ArchiveSpacePerThread();
10666 : }
10667 :
10668 4066 : char* Relocatable::Iterate(RootVisitor* v, char* thread_storage) {
10669 4066 : Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
10670 : Iterate(v, top);
10671 4066 : return thread_storage + ArchiveSpacePerThread();
10672 : }
10673 :
10674 240983 : void Relocatable::Iterate(Isolate* isolate, RootVisitor* v) {
10675 : Iterate(v, isolate->relocatable_top());
10676 240983 : }
10677 :
10678 0 : void Relocatable::Iterate(RootVisitor* v, Relocatable* top) {
10679 : Relocatable* current = top;
10680 287038 : while (current != NULL) {
10681 41989 : current->IterateInstance(v);
10682 41989 : current = current->prev_;
10683 : }
10684 0 : }
10685 :
10686 :
10687 1491694 : FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
10688 : : Relocatable(isolate),
10689 : str_(str.location()),
10690 4475082 : length_(str->length()) {
10691 1491694 : PostGarbageCollection();
10692 1491694 : }
10693 :
10694 :
10695 3584 : FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
10696 : : Relocatable(isolate),
10697 : str_(0),
10698 : is_one_byte_(true),
10699 3584 : length_(input.length()),
10700 10752 : start_(input.start()) {}
10701 :
10702 :
10703 1491783 : void FlatStringReader::PostGarbageCollection() {
10704 1491783 : if (str_ == NULL) return;
10705 : Handle<String> str(str_);
10706 : DCHECK(str->IsFlat());
10707 : DisallowHeapAllocation no_gc;
10708 : // This does not actually prevent the vector from being relocated later.
10709 1491783 : String::FlatContent content = str->GetFlatContent();
10710 : DCHECK(content.IsFlat());
10711 2983566 : is_one_byte_ = content.IsOneByte();
10712 1491783 : if (is_one_byte_) {
10713 1352397 : start_ = content.ToOneByteVector().start();
10714 : } else {
10715 139386 : start_ = content.ToUC16Vector().start();
10716 : }
10717 : }
10718 :
10719 :
10720 60578 : void ConsStringIterator::Initialize(ConsString* cons_string, int offset) {
10721 : DCHECK(cons_string != NULL);
10722 6034467 : root_ = cons_string;
10723 6034467 : consumed_ = offset;
10724 : // Force stack blown condition to trigger restart.
10725 6034467 : depth_ = 1;
10726 6034467 : maximum_depth_ = kStackSize + depth_;
10727 : DCHECK(StackBlown());
10728 60578 : }
10729 :
10730 :
10731 75784580 : String* ConsStringIterator::Continue(int* offset_out) {
10732 : DCHECK(depth_ != 0);
10733 : DCHECK_EQ(0, *offset_out);
10734 75784580 : bool blew_stack = StackBlown();
10735 : String* string = NULL;
10736 : // Get the next leaf if there is one.
10737 75784580 : if (!blew_stack) string = NextLeaf(&blew_stack);
10738 : // Restart search from root.
10739 75784580 : if (blew_stack) {
10740 : DCHECK(string == NULL);
10741 6840741 : string = Search(offset_out);
10742 : }
10743 : // Ensure future calls return null immediately.
10744 75784580 : if (string == NULL) Reset(NULL);
10745 75784580 : return string;
10746 : }
10747 :
10748 :
10749 13681308 : String* ConsStringIterator::Search(int* offset_out) {
10750 6840741 : ConsString* cons_string = root_;
10751 : // Reset the stack, pushing the root string.
10752 6840741 : depth_ = 1;
10753 6840741 : maximum_depth_ = 1;
10754 6840741 : frames_[0] = cons_string;
10755 6840741 : const int consumed = consumed_;
10756 : int offset = 0;
10757 : while (true) {
10758 : // Loop until the string is found which contains the target offset.
10759 : String* string = cons_string->first();
10760 : int length = string->length();
10761 : int32_t type;
10762 23686761841 : if (consumed < offset + length) {
10763 : // Target offset is in the left branch.
10764 : // Keep going if we're still in a ConString.
10765 : type = string->map()->instance_type();
10766 23684386707 : if ((type & kStringRepresentationMask) == kConsStringTag) {
10767 : cons_string = ConsString::cast(string);
10768 : PushLeft(cons_string);
10769 : continue;
10770 : }
10771 : // Tell the stack we're done descending.
10772 : AdjustMaximumDepth();
10773 : } else {
10774 : // Descend right.
10775 : // Update progress through the string.
10776 : offset += length;
10777 : // Keep going if we're still in a ConString.
10778 : string = cons_string->second();
10779 : type = string->map()->instance_type();
10780 2375134 : if ((type & kStringRepresentationMask) == kConsStringTag) {
10781 : cons_string = ConsString::cast(string);
10782 : PushRight(cons_string);
10783 : continue;
10784 : }
10785 : // Need this to be updated for the current string.
10786 : length = string->length();
10787 : // Account for the possibility of an empty right leaf.
10788 : // This happens only if we have asked for an offset outside the string.
10789 770020 : if (length == 0) {
10790 : // Reset so future operations will return null immediately.
10791 : Reset(NULL);
10792 174 : return NULL;
10793 : }
10794 : // Tell the stack we're done descending.
10795 : AdjustMaximumDepth();
10796 : // Pop stack so next iteration is in correct place.
10797 : Pop();
10798 : }
10799 : DCHECK(length != 0);
10800 : // Adjust return values and exit.
10801 6840567 : consumed_ = offset + length;
10802 6840567 : *offset_out = consumed - offset;
10803 6840567 : return string;
10804 : }
10805 : UNREACHABLE();
10806 : return NULL;
10807 : }
10808 :
10809 :
10810 152826869 : String* ConsStringIterator::NextLeaf(bool* blew_stack) {
10811 : while (true) {
10812 : // Tree traversal complete.
10813 69537660 : if (depth_ == 0) {
10814 6995 : *blew_stack = false;
10815 6995 : return NULL;
10816 : }
10817 : // We've lost track of higher nodes.
10818 69530665 : if (StackBlown()) {
10819 834 : *blew_stack = true;
10820 834 : return NULL;
10821 : }
10822 : // Go right.
10823 139059662 : ConsString* cons_string = frames_[OffsetForDepth(depth_ - 1)];
10824 : String* string = cons_string->second();
10825 : int32_t type = string->map()->instance_type();
10826 69529831 : if ((type & kStringRepresentationMask) != kConsStringTag) {
10827 : // Pop stack so next iteration is in correct place.
10828 : Pop();
10829 : int length = string->length();
10830 : // Could be a flattened ConsString.
10831 55178300 : if (length == 0) continue;
10832 54585313 : consumed_ += length;
10833 54585313 : return string;
10834 : }
10835 : cons_string = ConsString::cast(string);
10836 : PushRight(cons_string);
10837 : // Need to traverse all the way left.
10838 : while (true) {
10839 : // Continue left.
10840 : string = cons_string->first();
10841 : type = string->map()->instance_type();
10842 23762821 : if ((type & kStringRepresentationMask) != kConsStringTag) {
10843 : AdjustMaximumDepth();
10844 : int length = string->length();
10845 14351531 : if (length == 0) break; // Skip empty left-hand sides of ConsStrings.
10846 14351531 : consumed_ += length;
10847 14351531 : return string;
10848 : }
10849 : cons_string = ConsString::cast(string);
10850 : PushLeft(cons_string);
10851 : }
10852 : }
10853 : UNREACHABLE();
10854 : return NULL;
10855 : }
10856 :
10857 :
10858 4320981 : uint16_t ConsString::ConsStringGet(int index) {
10859 : DCHECK(index >= 0 && index < this->length());
10860 :
10861 : // Check for a flattened cons string
10862 4320981 : if (second()->length() == 0) {
10863 : String* left = first();
10864 374002 : return left->Get(index);
10865 : }
10866 :
10867 : String* string = String::cast(this);
10868 :
10869 : while (true) {
10870 42982425 : if (StringShape(string).IsCons()) {
10871 : ConsString* cons_string = ConsString::cast(string);
10872 : String* left = cons_string->first();
10873 39035446 : if (left->length() > index) {
10874 : string = left;
10875 : } else {
10876 488981 : index -= left->length();
10877 : string = cons_string->second();
10878 : }
10879 : } else {
10880 3946979 : return string->Get(index);
10881 : }
10882 : }
10883 :
10884 : UNREACHABLE();
10885 : return 0;
10886 : }
10887 :
10888 516 : uint16_t ThinString::ThinStringGet(int index) { return actual()->Get(index); }
10889 :
10890 1816864 : uint16_t SlicedString::SlicedStringGet(int index) {
10891 3633728 : return parent()->Get(offset() + index);
10892 : }
10893 :
10894 :
10895 : template <typename sinkchar>
10896 277422127 : void String::WriteToFlat(String* src,
10897 : sinkchar* sink,
10898 : int f,
10899 : int t) {
10900 : String* source = src;
10901 : int from = f;
10902 : int to = t;
10903 : while (true) {
10904 : DCHECK(0 <= from && from <= to && to <= source->length());
10905 372456848 : switch (StringShape(source).full_representation_tag()) {
10906 : case kOneByteStringTag | kExternalStringTag: {
10907 : CopyChars(sink, ExternalOneByteString::cast(source)->GetChars() + from,
10908 996924 : to - from);
10909 : return;
10910 : }
10911 : case kTwoByteStringTag | kExternalStringTag: {
10912 : const uc16* data =
10913 : ExternalTwoByteString::cast(source)->GetChars();
10914 : CopyChars(sink,
10915 : data + from,
10916 340890 : to - from);
10917 : return;
10918 : }
10919 : case kOneByteStringTag | kSeqStringTag: {
10920 : CopyChars(sink,
10921 244915746 : SeqOneByteString::cast(source)->GetChars() + from,
10922 489831492 : to - from);
10923 : return;
10924 : }
10925 : case kTwoByteStringTag | kSeqStringTag: {
10926 : CopyChars(sink,
10927 12055638 : SeqTwoByteString::cast(source)->GetChars() + from,
10928 24111276 : to - from);
10929 : return;
10930 : }
10931 : case kOneByteStringTag | kConsStringTag:
10932 : case kTwoByteStringTag | kConsStringTag: {
10933 : ConsString* cons_string = ConsString::cast(source);
10934 : String* first = cons_string->first();
10935 : int boundary = first->length();
10936 112533580 : if (to - boundary >= boundary - from) {
10937 : // Right hand side is longer. Recurse over left.
10938 30928445 : if (from < boundary) {
10939 30928445 : WriteToFlat(first, sink, from, boundary);
10940 61856890 : if (from == 0 && cons_string->second() == first) {
10941 17531267 : CopyChars(sink + boundary, sink, boundary);
10942 : return;
10943 : }
10944 13397178 : sink += boundary - from;
10945 : from = 0;
10946 : } else {
10947 0 : from -= boundary;
10948 : }
10949 : to -= boundary;
10950 : source = cons_string->second();
10951 : } else {
10952 : // Left hand side is longer. Recurse over right.
10953 81605135 : if (to > boundary) {
10954 : String* second = cons_string->second();
10955 : // When repeatedly appending to a string, we get a cons string that
10956 : // is unbalanced to the left, a list, essentially. We inline the
10957 : // common case of sequential one-byte right child.
10958 81036711 : if (to - boundary == 1) {
10959 72450806 : sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
10960 44811308 : } else if (second->IsSeqOneByteString()) {
10961 38379751 : CopyChars(sink + boundary - from,
10962 38379751 : SeqOneByteString::cast(second)->GetChars(),
10963 76759502 : to - boundary);
10964 : } else {
10965 6431557 : WriteToFlat(second,
10966 6431557 : sink + boundary - from,
10967 : 0,
10968 6431557 : to - boundary);
10969 : }
10970 : to = boundary;
10971 : }
10972 : source = first;
10973 : }
10974 : break;
10975 : }
10976 : case kOneByteStringTag | kSlicedStringTag:
10977 : case kTwoByteStringTag | kSlicedStringTag: {
10978 : SlicedString* slice = SlicedString::cast(source);
10979 2080123 : unsigned offset = slice->offset();
10980 4160246 : WriteToFlat(slice->parent(), sink, from + offset, to + offset);
10981 2080123 : return;
10982 : }
10983 : case kOneByteStringTag | kThinStringTag:
10984 : case kTwoByteStringTag | kThinStringTag:
10985 : source = ThinString::cast(source)->actual();
10986 32409 : break;
10987 : }
10988 : }
10989 : }
10990 :
10991 :
10992 :
10993 : template <typename SourceChar>
10994 129928 : static void CalculateLineEndsImpl(Isolate* isolate,
10995 : List<int>* line_ends,
10996 : Vector<const SourceChar> src,
10997 : bool include_ending_line) {
10998 64964 : const int src_len = src.length();
10999 : UnicodeCache* cache = isolate->unicode_cache();
11000 330207931 : for (int i = 0; i < src_len - 1; i++) {
11001 330142967 : SourceChar current = src[i];
11002 660285934 : SourceChar next = src[i + 1];
11003 330142967 : if (cache->IsLineTerminatorSequence(current, next)) line_ends->Add(i);
11004 : }
11005 :
11006 129438 : if (src_len > 0 && cache->IsLineTerminatorSequence(src[src_len - 1], 0)) {
11007 23333 : line_ends->Add(src_len - 1);
11008 : }
11009 64964 : if (include_ending_line) {
11010 : // Include one character beyond the end of script. The rewriter uses that
11011 : // position for the implicit return statement.
11012 63124 : line_ends->Add(src_len);
11013 : }
11014 64964 : }
11015 :
11016 :
11017 64964 : Handle<FixedArray> String::CalculateLineEnds(Handle<String> src,
11018 : bool include_ending_line) {
11019 64964 : src = Flatten(src);
11020 : // Rough estimate of line count based on a roughly estimated average
11021 : // length of (unpacked) code.
11022 64964 : int line_count_estimate = src->length() >> 4;
11023 : List<int> line_ends(line_count_estimate);
11024 : Isolate* isolate = src->GetIsolate();
11025 : { DisallowHeapAllocation no_allocation; // ensure vectors stay valid.
11026 : // Dispatch on type of strings.
11027 64964 : String::FlatContent content = src->GetFlatContent();
11028 : DCHECK(content.IsFlat());
11029 64964 : if (content.IsOneByte()) {
11030 : CalculateLineEndsImpl(isolate,
11031 : &line_ends,
11032 : content.ToOneByteVector(),
11033 64358 : include_ending_line);
11034 : } else {
11035 : CalculateLineEndsImpl(isolate,
11036 : &line_ends,
11037 : content.ToUC16Vector(),
11038 606 : include_ending_line);
11039 : }
11040 : }
11041 64964 : int line_count = line_ends.length();
11042 64964 : Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count);
11043 14930848 : for (int i = 0; i < line_count; i++) {
11044 29731768 : array->set(i, Smi::FromInt(line_ends[i]));
11045 : }
11046 129928 : return array;
11047 : }
11048 :
11049 :
11050 : // Compares the contents of two strings by reading and comparing
11051 : // int-sized blocks of characters.
11052 : template <typename Char>
11053 : static inline bool CompareRawStringContents(const Char* const a,
11054 : const Char* const b,
11055 : int length) {
11056 106096322 : return CompareChars(a, b, length) == 0;
11057 : }
11058 :
11059 :
11060 : template<typename Chars1, typename Chars2>
11061 : class RawStringComparator : public AllStatic {
11062 : public:
11063 : static inline bool compare(const Chars1* a, const Chars2* b, int len) {
11064 : DCHECK(sizeof(Chars1) != sizeof(Chars2));
11065 1322694 : for (int i = 0; i < len; i++) {
11066 1322738 : if (a[i] != b[i]) {
11067 : return false;
11068 : }
11069 : }
11070 : return true;
11071 : }
11072 : };
11073 :
11074 :
11075 : template<>
11076 : class RawStringComparator<uint16_t, uint16_t> {
11077 : public:
11078 : static inline bool compare(const uint16_t* a, const uint16_t* b, int len) {
11079 : return CompareRawStringContents(a, b, len);
11080 : }
11081 : };
11082 :
11083 :
11084 : template<>
11085 : class RawStringComparator<uint8_t, uint8_t> {
11086 : public:
11087 : static inline bool compare(const uint8_t* a, const uint8_t* b, int len) {
11088 : return CompareRawStringContents(a, b, len);
11089 : }
11090 : };
11091 :
11092 :
11093 : class StringComparator {
11094 : class State {
11095 : public:
11096 6157820 : State() : is_one_byte_(true), length_(0), buffer8_(NULL) {}
11097 :
11098 12315640 : void Init(String* string) {
11099 12315640 : ConsString* cons_string = String::VisitFlat(this, string);
11100 : iter_.Reset(cons_string);
11101 12315640 : if (cons_string != NULL) {
11102 : int offset;
11103 3741594 : string = iter_.Next(&offset);
11104 3741594 : String::VisitFlat(this, string, offset);
11105 : }
11106 12315640 : }
11107 :
11108 : inline void VisitOneByteString(const uint8_t* chars, int length) {
11109 50970706 : is_one_byte_ = true;
11110 50970706 : buffer8_ = chars;
11111 50970706 : length_ = length;
11112 : }
11113 :
11114 : inline void VisitTwoByteString(const uint16_t* chars, int length) {
11115 7882781 : is_one_byte_ = false;
11116 7882781 : buffer16_ = chars;
11117 7882781 : length_ = length;
11118 : }
11119 :
11120 56481012 : void Advance(int consumed) {
11121 : DCHECK(consumed <= length_);
11122 : // Still in buffer.
11123 56481012 : if (length_ != consumed) {
11124 9943165 : if (is_one_byte_) {
11125 9858799 : buffer8_ += consumed;
11126 : } else {
11127 84366 : buffer16_ += consumed;
11128 : }
11129 9943165 : length_ -= consumed;
11130 66424177 : return;
11131 : }
11132 : // Advance state.
11133 : int offset;
11134 46537847 : String* next = iter_.Next(&offset);
11135 : DCHECK_EQ(0, offset);
11136 : DCHECK(next != NULL);
11137 46537847 : String::VisitFlat(this, next);
11138 : }
11139 :
11140 : ConsStringIterator iter_;
11141 : bool is_one_byte_;
11142 : int length_;
11143 : union {
11144 : const uint8_t* buffer8_;
11145 : const uint16_t* buffer16_;
11146 : };
11147 :
11148 : private:
11149 : DISALLOW_COPY_AND_ASSIGN(State);
11150 : };
11151 :
11152 : public:
11153 : inline StringComparator() {}
11154 :
11155 : template<typename Chars1, typename Chars2>
11156 : static inline bool Equals(State* state_1, State* state_2, int to_check) {
11157 : const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_);
11158 : const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_);
11159 : return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check);
11160 : }
11161 :
11162 6157820 : bool Equals(String* string_1, String* string_2) {
11163 : int length = string_1->length();
11164 40556146 : state_1_.Init(string_1);
11165 40556146 : state_2_.Init(string_2);
11166 : while (true) {
11167 34398326 : int to_check = Min(state_1_.length_, state_2_.length_);
11168 : DCHECK(to_check > 0 && to_check <= length);
11169 : bool is_equal;
11170 34398326 : if (state_1_.is_one_byte_) {
11171 30367390 : if (state_2_.is_one_byte_) {
11172 : is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check);
11173 : } else {
11174 : is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check);
11175 : }
11176 : } else {
11177 4030936 : if (state_2_.is_one_byte_) {
11178 : is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check);
11179 : } else {
11180 : is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check);
11181 : }
11182 : }
11183 : // Looping done.
11184 34398326 : if (!is_equal) return false;
11185 34385549 : length -= to_check;
11186 : // Exit condition. Strings are equal.
11187 34385549 : if (length == 0) return true;
11188 28240506 : state_1_.Advance(to_check);
11189 28240506 : state_2_.Advance(to_check);
11190 28240506 : }
11191 : }
11192 :
11193 : private:
11194 : State state_1_;
11195 : State state_2_;
11196 :
11197 : DISALLOW_COPY_AND_ASSIGN(StringComparator);
11198 : };
11199 :
11200 :
11201 35267732 : bool String::SlowEquals(String* other) {
11202 : DisallowHeapAllocation no_gc;
11203 : // Fast check: negative check with lengths.
11204 : int len = length();
11205 35267732 : if (len != other->length()) return false;
11206 26104648 : if (len == 0) return true;
11207 :
11208 : // Fast check: if at least one ThinString is involved, dereference it/them
11209 : // and restart.
11210 52208043 : if (this->IsThinString() || other->IsThinString()) {
11211 4960 : if (other->IsThinString()) other = ThinString::cast(other)->actual();
11212 4960 : if (this->IsThinString()) {
11213 1252 : return ThinString::cast(this)->actual()->Equals(other);
11214 : } else {
11215 3708 : return this->Equals(other);
11216 : }
11217 : }
11218 :
11219 : // Fast check: if hash code is computed for both strings
11220 : // a fast negative check can be performed.
11221 51851719 : if (HasHashCode() && other->HasHashCode()) {
11222 : #ifdef ENABLE_SLOW_DCHECKS
11223 : if (FLAG_enable_slow_asserts) {
11224 : if (Hash() != other->Hash()) {
11225 : bool found_difference = false;
11226 : for (int i = 0; i < len; i++) {
11227 : if (Get(i) != other->Get(i)) {
11228 : found_difference = true;
11229 : break;
11230 : }
11231 : }
11232 : DCHECK(found_difference);
11233 : }
11234 : }
11235 : #endif
11236 25750928 : if (Hash() != other->Hash()) return false;
11237 : }
11238 :
11239 : // We know the strings are both non-empty. Compare the first chars
11240 : // before we try to flatten the strings.
11241 23614123 : if (this->Get(0) != other->Get(0)) return false;
11242 :
11243 41722343 : if (IsSeqOneByteString() && other->IsSeqOneByteString()) {
11244 17454798 : const uint8_t* str1 = SeqOneByteString::cast(this)->GetChars();
11245 17454798 : const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars();
11246 17454798 : return CompareRawStringContents(str1, str2, len);
11247 : }
11248 :
11249 : StringComparator comparator;
11250 6157820 : return comparator.Equals(this, other);
11251 : }
11252 :
11253 :
11254 6451089 : bool String::SlowEquals(Handle<String> one, Handle<String> two) {
11255 : // Fast check: negative check with lengths.
11256 : int one_length = one->length();
11257 6451089 : if (one_length != two->length()) return false;
11258 6411202 : if (one_length == 0) return true;
11259 :
11260 : // Fast check: if at least one ThinString is involved, dereference it/them
11261 : // and restart.
11262 12822404 : if (one->IsThinString() || two->IsThinString()) {
11263 19 : if (one->IsThinString()) one = handle(ThinString::cast(*one)->actual());
11264 19 : if (two->IsThinString()) two = handle(ThinString::cast(*two)->actual());
11265 19 : return String::Equals(one, two);
11266 : }
11267 :
11268 : // Fast check: if hash code is computed for both strings
11269 : // a fast negative check can be performed.
11270 6427839 : if (one->HasHashCode() && two->HasHashCode()) {
11271 : #ifdef ENABLE_SLOW_DCHECKS
11272 : if (FLAG_enable_slow_asserts) {
11273 : if (one->Hash() != two->Hash()) {
11274 : bool found_difference = false;
11275 : for (int i = 0; i < one_length; i++) {
11276 : if (one->Get(i) != two->Get(i)) {
11277 : found_difference = true;
11278 : break;
11279 : }
11280 : }
11281 : DCHECK(found_difference);
11282 : }
11283 : }
11284 : #endif
11285 3656 : if (one->Hash() != two->Hash()) return false;
11286 : }
11287 :
11288 : // We know the strings are both non-empty. Compare the first chars
11289 : // before we try to flatten the strings.
11290 6411167 : if (one->Get(0) != two->Get(0)) return false;
11291 :
11292 4391484 : one = String::Flatten(one);
11293 4391484 : two = String::Flatten(two);
11294 :
11295 : DisallowHeapAllocation no_gc;
11296 4391484 : String::FlatContent flat1 = one->GetFlatContent();
11297 4391484 : String::FlatContent flat2 = two->GetFlatContent();
11298 :
11299 4391484 : if (flat1.IsOneByte() && flat2.IsOneByte()) {
11300 : return CompareRawStringContents(flat1.ToOneByteVector().start(),
11301 : flat2.ToOneByteVector().start(),
11302 : one_length);
11303 : } else {
11304 20597132 : for (int i = 0; i < one_length; i++) {
11305 20597132 : if (flat1.Get(i) != flat2.Get(i)) return false;
11306 : }
11307 : return true;
11308 : }
11309 : }
11310 :
11311 :
11312 : // static
11313 7363753 : ComparisonResult String::Compare(Handle<String> x, Handle<String> y) {
11314 : // A few fast case tests before we flatten.
11315 7363753 : if (x.is_identical_to(y)) {
11316 : return ComparisonResult::kEqual;
11317 7363238 : } else if (y->length() == 0) {
11318 : return x->length() == 0 ? ComparisonResult::kEqual
11319 0 : : ComparisonResult::kGreaterThan;
11320 7363238 : } else if (x->length() == 0) {
11321 : return ComparisonResult::kLessThan;
11322 : }
11323 :
11324 14726476 : int const d = x->Get(0) - y->Get(0);
11325 7363238 : if (d < 0) {
11326 : return ComparisonResult::kLessThan;
11327 5847955 : } else if (d > 0) {
11328 : return ComparisonResult::kGreaterThan;
11329 : }
11330 :
11331 : // Slow case.
11332 30338 : x = String::Flatten(x);
11333 30338 : y = String::Flatten(y);
11334 :
11335 : DisallowHeapAllocation no_gc;
11336 : ComparisonResult result = ComparisonResult::kEqual;
11337 : int prefix_length = x->length();
11338 30338 : if (y->length() < prefix_length) {
11339 : prefix_length = y->length();
11340 : result = ComparisonResult::kGreaterThan;
11341 30338 : } else if (y->length() > prefix_length) {
11342 : result = ComparisonResult::kLessThan;
11343 : }
11344 : int r;
11345 30338 : String::FlatContent x_content = x->GetFlatContent();
11346 30338 : String::FlatContent y_content = y->GetFlatContent();
11347 30338 : if (x_content.IsOneByte()) {
11348 : Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
11349 3303 : if (y_content.IsOneByte()) {
11350 : Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11351 55 : r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11352 : } else {
11353 : Vector<const uc16> y_chars = y_content.ToUC16Vector();
11354 3248 : r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11355 : }
11356 : } else {
11357 : Vector<const uc16> x_chars = x_content.ToUC16Vector();
11358 27035 : if (y_content.IsOneByte()) {
11359 : Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11360 1624 : r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11361 : } else {
11362 : Vector<const uc16> y_chars = y_content.ToUC16Vector();
11363 25411 : r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11364 : }
11365 : }
11366 30338 : if (r < 0) {
11367 : result = ComparisonResult::kLessThan;
11368 18299 : } else if (r > 0) {
11369 : result = ComparisonResult::kGreaterThan;
11370 : }
11371 30338 : return result;
11372 : }
11373 :
11374 3383 : Object* String::IndexOf(Isolate* isolate, Handle<Object> receiver,
11375 : Handle<Object> search, Handle<Object> position) {
11376 3383 : if (receiver->IsNullOrUndefined(isolate)) {
11377 900 : THROW_NEW_ERROR_RETURN_FAILURE(
11378 : isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
11379 : isolate->factory()->NewStringFromAsciiChecked(
11380 : "String.prototype.indexOf")));
11381 : }
11382 : Handle<String> receiver_string;
11383 6166 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string,
11384 : Object::ToString(isolate, receiver));
11385 :
11386 : Handle<String> search_string;
11387 6166 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
11388 : Object::ToString(isolate, search));
11389 :
11390 3083 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11391 : Object::ToInteger(isolate, position));
11392 :
11393 : uint32_t index = receiver_string->ToValidIndex(*position);
11394 : return Smi::FromInt(
11395 6166 : String::IndexOf(isolate, receiver_string, search_string, index));
11396 : }
11397 :
11398 : namespace {
11399 :
11400 : template <typename T>
11401 183143 : int SearchString(Isolate* isolate, String::FlatContent receiver_content,
11402 240 : Vector<T> pat_vector, int start_index) {
11403 183143 : if (receiver_content.IsOneByte()) {
11404 : return SearchString(isolate, receiver_content.ToOneByteVector(), pat_vector,
11405 182674 : start_index);
11406 : }
11407 : return SearchString(isolate, receiver_content.ToUC16Vector(), pat_vector,
11408 469 : start_index);
11409 : }
11410 :
11411 : } // namespace
11412 :
11413 187332 : int String::IndexOf(Isolate* isolate, Handle<String> receiver,
11414 : Handle<String> search, int start_index) {
11415 : DCHECK(0 <= start_index);
11416 : DCHECK(start_index <= receiver->length());
11417 :
11418 187332 : uint32_t search_length = search->length();
11419 187332 : if (search_length == 0) return start_index;
11420 :
11421 187218 : uint32_t receiver_length = receiver->length();
11422 187218 : if (start_index + search_length > receiver_length) return -1;
11423 :
11424 183143 : receiver = String::Flatten(receiver);
11425 183143 : search = String::Flatten(search);
11426 :
11427 : DisallowHeapAllocation no_gc; // ensure vectors stay valid
11428 : // Extract flattened substrings of cons strings before getting encoding.
11429 183143 : String::FlatContent receiver_content = receiver->GetFlatContent();
11430 183143 : String::FlatContent search_content = search->GetFlatContent();
11431 :
11432 : // dispatch on type of strings
11433 183143 : if (search_content.IsOneByte()) {
11434 : Vector<const uint8_t> pat_vector = search_content.ToOneByteVector();
11435 : return SearchString<const uint8_t>(isolate, receiver_content, pat_vector,
11436 179993 : start_index);
11437 : }
11438 3150 : Vector<const uc16> pat_vector = search_content.ToUC16Vector();
11439 : return SearchString<const uc16>(isolate, receiver_content, pat_vector,
11440 3150 : start_index);
11441 : }
11442 :
11443 5600 : MaybeHandle<String> String::GetSubstitution(Isolate* isolate, Match* match,
11444 : Handle<String> replacement,
11445 : int start_index) {
11446 : DCHECK_IMPLIES(match->HasNamedCaptures(), FLAG_harmony_regexp_named_captures);
11447 : DCHECK_GE(start_index, 0);
11448 :
11449 : Factory* factory = isolate->factory();
11450 :
11451 : const int replacement_length = replacement->length();
11452 5600 : const int captures_length = match->CaptureCount();
11453 :
11454 5600 : replacement = String::Flatten(replacement);
11455 :
11456 : Handle<String> dollar_string =
11457 5600 : factory->LookupSingleCharacterStringFromCode('$');
11458 : int next_dollar_ix =
11459 5600 : String::IndexOf(isolate, replacement, dollar_string, start_index);
11460 5600 : if (next_dollar_ix < 0) {
11461 : return replacement;
11462 : }
11463 :
11464 5525 : IncrementalStringBuilder builder(isolate);
11465 :
11466 5525 : if (next_dollar_ix > 0) {
11467 465 : builder.AppendString(factory->NewSubString(replacement, 0, next_dollar_ix));
11468 : }
11469 :
11470 : while (true) {
11471 12473 : const int peek_ix = next_dollar_ix + 1;
11472 12473 : if (peek_ix >= replacement_length) {
11473 : builder.AppendCharacter('$');
11474 30 : return builder.Finish();
11475 : }
11476 :
11477 : int continue_from_ix = -1;
11478 : const uint16_t peek = replacement->Get(peek_ix);
11479 12443 : switch (peek) {
11480 : case '$': // $$
11481 : builder.AppendCharacter('$');
11482 90 : continue_from_ix = peek_ix + 1;
11483 90 : break;
11484 : case '&': // $& - match
11485 90 : builder.AppendString(match->GetMatch());
11486 90 : continue_from_ix = peek_ix + 1;
11487 90 : break;
11488 : case '`': // $` - prefix
11489 60 : builder.AppendString(match->GetPrefix());
11490 60 : continue_from_ix = peek_ix + 1;
11491 60 : break;
11492 : case '\'': // $' - suffix
11493 60 : builder.AppendString(match->GetSuffix());
11494 60 : continue_from_ix = peek_ix + 1;
11495 60 : break;
11496 : case '0':
11497 : case '1':
11498 : case '2':
11499 : case '3':
11500 : case '4':
11501 : case '5':
11502 : case '6':
11503 : case '7':
11504 : case '8':
11505 : case '9': {
11506 : // Valid indices are $1 .. $9, $01 .. $09 and $10 .. $99
11507 11678 : int scaled_index = (peek - '0');
11508 : int advance = 1;
11509 :
11510 11678 : if (peek_ix + 1 < replacement_length) {
11511 : const uint16_t next_peek = replacement->Get(peek_ix + 1);
11512 9731 : if (next_peek >= '0' && next_peek <= '9') {
11513 2235 : const int new_scaled_index = scaled_index * 10 + (next_peek - '0');
11514 2235 : if (new_scaled_index < captures_length) {
11515 : scaled_index = new_scaled_index;
11516 : advance = 2;
11517 : }
11518 : }
11519 : }
11520 :
11521 11678 : if (scaled_index == 0 || scaled_index >= captures_length) {
11522 : builder.AppendCharacter('$');
11523 : continue_from_ix = peek_ix;
11524 11828 : break;
11525 : }
11526 :
11527 : bool capture_exists;
11528 : Handle<String> capture;
11529 23056 : ASSIGN_RETURN_ON_EXCEPTION(
11530 : isolate, capture, match->GetCapture(scaled_index, &capture_exists),
11531 : String);
11532 11528 : if (capture_exists) builder.AppendString(capture);
11533 11528 : continue_from_ix = peek_ix + advance;
11534 11528 : break;
11535 : }
11536 : case '<': { // $<name> - named capture
11537 : typedef String::Match::CaptureState CaptureState;
11538 :
11539 420 : if (!match->HasNamedCaptures()) {
11540 : builder.AppendCharacter('$');
11541 : continue_from_ix = peek_ix;
11542 336 : break;
11543 : }
11544 :
11545 : Handle<String> bracket_string =
11546 336 : factory->LookupSingleCharacterStringFromCode('>');
11547 : const int closing_bracket_ix =
11548 336 : String::IndexOf(isolate, replacement, bracket_string, peek_ix + 1);
11549 :
11550 336 : if (closing_bracket_ix == -1) {
11551 84 : THROW_NEW_ERROR(
11552 : isolate,
11553 : NewSyntaxError(MessageTemplate::kRegExpInvalidReplaceString,
11554 : replacement),
11555 : String);
11556 : }
11557 :
11558 : Handle<String> capture_name =
11559 294 : factory->NewSubString(replacement, peek_ix + 1, closing_bracket_ix);
11560 : Handle<String> capture;
11561 : CaptureState capture_state;
11562 588 : ASSIGN_RETURN_ON_EXCEPTION(
11563 : isolate, capture,
11564 : match->GetNamedCapture(capture_name, &capture_state), String);
11565 :
11566 294 : switch (capture_state) {
11567 : case CaptureState::INVALID:
11568 252 : THROW_NEW_ERROR(
11569 : isolate,
11570 : NewSyntaxError(MessageTemplate::kRegExpInvalidReplaceString,
11571 : replacement),
11572 : String);
11573 : break;
11574 : case CaptureState::UNMATCHED:
11575 : break;
11576 : case CaptureState::MATCHED:
11577 112 : builder.AppendString(capture);
11578 112 : break;
11579 : }
11580 :
11581 168 : continue_from_ix = closing_bracket_ix + 1;
11582 168 : break;
11583 : }
11584 : default:
11585 : builder.AppendCharacter('$');
11586 : continue_from_ix = peek_ix;
11587 45 : break;
11588 : }
11589 :
11590 : // Go the the next $ in the replacement.
11591 : // TODO(jgruber): Single-char lookups could be much more efficient.
11592 : DCHECK_NE(continue_from_ix, -1);
11593 : next_dollar_ix =
11594 12275 : String::IndexOf(isolate, replacement, dollar_string, continue_from_ix);
11595 :
11596 : // Return if there are no more $ characters in the replacement. If we
11597 : // haven't reached the end, we need to append the suffix.
11598 12275 : if (next_dollar_ix < 0) {
11599 5327 : if (continue_from_ix < replacement_length) {
11600 : builder.AppendString(factory->NewSubString(
11601 1738 : replacement, continue_from_ix, replacement_length));
11602 : }
11603 5327 : return builder.Finish();
11604 : }
11605 :
11606 : // Append substring between the previous and the next $ character.
11607 6948 : if (next_dollar_ix > continue_from_ix) {
11608 : builder.AppendString(
11609 42 : factory->NewSubString(replacement, continue_from_ix, next_dollar_ix));
11610 : }
11611 : }
11612 :
11613 : UNREACHABLE();
11614 : return MaybeHandle<String>();
11615 : }
11616 :
11617 : namespace { // for String.Prototype.lastIndexOf
11618 :
11619 : template <typename schar, typename pchar>
11620 2260 : int StringMatchBackwards(Vector<const schar> subject,
11621 : Vector<const pchar> pattern, int idx) {
11622 2260 : int pattern_length = pattern.length();
11623 : DCHECK(pattern_length >= 1);
11624 : DCHECK(idx + pattern_length <= subject.length());
11625 :
11626 : if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
11627 0 : for (int i = 0; i < pattern_length; i++) {
11628 0 : uc16 c = pattern[i];
11629 0 : if (c > String::kMaxOneByteCharCode) {
11630 : return -1;
11631 : }
11632 : }
11633 : }
11634 :
11635 2260 : pchar pattern_first_char = pattern[0];
11636 8229 : for (int i = idx; i >= 0; i--) {
11637 10210 : if (subject[i] != pattern_first_char) continue;
11638 : int j = 1;
11639 3116 : while (j < pattern_length) {
11640 2270 : if (pattern[j] != subject[i + j]) {
11641 : break;
11642 : }
11643 1105 : j++;
11644 : }
11645 2011 : if (j == pattern_length) {
11646 : return i;
11647 : }
11648 : }
11649 : return -1;
11650 : }
11651 :
11652 : } // namespace
11653 :
11654 2905 : Object* String::LastIndexOf(Isolate* isolate, Handle<Object> receiver,
11655 : Handle<Object> search, Handle<Object> position) {
11656 2905 : if (receiver->IsNullOrUndefined(isolate)) {
11657 810 : THROW_NEW_ERROR_RETURN_FAILURE(
11658 : isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
11659 : isolate->factory()->NewStringFromAsciiChecked(
11660 : "String.prototype.lastIndexOf")));
11661 : }
11662 : Handle<String> receiver_string;
11663 5270 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string,
11664 : Object::ToString(isolate, receiver));
11665 :
11666 : Handle<String> search_string;
11667 5270 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
11668 : Object::ToString(isolate, search));
11669 :
11670 5270 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11671 : Object::ToNumber(position));
11672 :
11673 : uint32_t start_index;
11674 :
11675 2635 : if (position->IsNaN()) {
11676 1885 : start_index = receiver_string->length();
11677 : } else {
11678 750 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11679 : Object::ToInteger(isolate, position));
11680 : start_index = receiver_string->ToValidIndex(*position);
11681 : }
11682 :
11683 2635 : uint32_t pattern_length = search_string->length();
11684 2635 : uint32_t receiver_length = receiver_string->length();
11685 :
11686 2635 : if (start_index + pattern_length > receiver_length) {
11687 2005 : start_index = receiver_length - pattern_length;
11688 : }
11689 :
11690 2635 : if (pattern_length == 0) {
11691 750 : return Smi::FromInt(start_index);
11692 : }
11693 :
11694 2260 : receiver_string = String::Flatten(receiver_string);
11695 2260 : search_string = String::Flatten(search_string);
11696 :
11697 : int last_index = -1;
11698 : DisallowHeapAllocation no_gc; // ensure vectors stay valid
11699 :
11700 2260 : String::FlatContent receiver_content = receiver_string->GetFlatContent();
11701 2260 : String::FlatContent search_content = search_string->GetFlatContent();
11702 :
11703 2260 : if (search_content.IsOneByte()) {
11704 : Vector<const uint8_t> pat_vector = search_content.ToOneByteVector();
11705 2260 : if (receiver_content.IsOneByte()) {
11706 : last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
11707 2253 : pat_vector, start_index);
11708 : } else {
11709 : last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
11710 7 : pat_vector, start_index);
11711 : }
11712 : } else {
11713 : Vector<const uc16> pat_vector = search_content.ToUC16Vector();
11714 0 : if (receiver_content.IsOneByte()) {
11715 : last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
11716 0 : pat_vector, start_index);
11717 : } else {
11718 : last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
11719 0 : pat_vector, start_index);
11720 : }
11721 : }
11722 2260 : return Smi::FromInt(last_index);
11723 : }
11724 :
11725 59350098 : bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
11726 : int slen = length();
11727 : // Can't check exact length equality, but we can check bounds.
11728 59350098 : int str_len = str.length();
11729 59350098 : if (!allow_prefix_match &&
11730 58021913 : (str_len < slen ||
11731 58021913 : str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) {
11732 : return false;
11733 : }
11734 : int i;
11735 56787065 : size_t remaining_in_str = static_cast<size_t>(str_len);
11736 56787065 : const uint8_t* utf8_data = reinterpret_cast<const uint8_t*>(str.start());
11737 1126077312 : for (i = 0; i < slen && remaining_in_str > 0; i++) {
11738 538666039 : size_t cursor = 0;
11739 538666039 : uint32_t r = unibrow::Utf8::ValueOf(utf8_data, remaining_in_str, &cursor);
11740 : DCHECK(cursor > 0 && cursor <= remaining_in_str);
11741 538666046 : if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
11742 32414463 : if (i > slen - 1) return false;
11743 28 : if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false;
11744 14 : if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false;
11745 : } else {
11746 538666026 : if (Get(i) != r) return false;
11747 : }
11748 506251591 : utf8_data += cursor;
11749 506251591 : remaining_in_str -= cursor;
11750 : }
11751 24372617 : return (allow_prefix_match || i == slen) && remaining_in_str == 0;
11752 : }
11753 :
11754 : template <>
11755 210 : bool String::IsEqualTo(Vector<const uint8_t> str) {
11756 210 : return IsOneByteEqualTo(str);
11757 : }
11758 :
11759 : template <>
11760 0 : bool String::IsEqualTo(Vector<const uc16> str) {
11761 0 : return IsTwoByteEqualTo(str);
11762 : }
11763 :
11764 96500761 : bool String::IsOneByteEqualTo(Vector<const uint8_t> str) {
11765 : int slen = length();
11766 96500761 : if (str.length() != slen) return false;
11767 : DisallowHeapAllocation no_gc;
11768 69353226 : FlatContent content = GetFlatContent();
11769 69353227 : if (content.IsOneByte()) {
11770 69353126 : return CompareChars(content.ToOneByteVector().start(),
11771 138706252 : str.start(), slen) == 0;
11772 : }
11773 170 : for (int i = 0; i < slen; i++) {
11774 254 : if (Get(i) != static_cast<uint16_t>(str[i])) return false;
11775 : }
11776 : return true;
11777 : }
11778 :
11779 :
11780 40734 : bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
11781 : int slen = length();
11782 40734 : if (str.length() != slen) return false;
11783 : DisallowHeapAllocation no_gc;
11784 12506 : FlatContent content = GetFlatContent();
11785 12506 : if (content.IsTwoByte()) {
11786 24162 : return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
11787 : }
11788 0 : for (int i = 0; i < slen; i++) {
11789 425 : if (Get(i) != str[i]) return false;
11790 : }
11791 : return true;
11792 : }
11793 :
11794 :
11795 29106397 : uint32_t String::ComputeAndSetHash() {
11796 : // Should only be called if hash code has not yet been computed.
11797 : DCHECK(!HasHashCode());
11798 :
11799 : // Store the hash code in the object.
11800 29106397 : uint32_t field = IteratingStringHasher::Hash(this, GetHeap()->HashSeed());
11801 : set_hash_field(field);
11802 :
11803 : // Check the hash code is there.
11804 : DCHECK(HasHashCode());
11805 29106399 : uint32_t result = field >> kHashShift;
11806 : DCHECK(result != 0); // Ensure that the hash value of 0 is never computed.
11807 29106399 : return result;
11808 : }
11809 :
11810 :
11811 4309301 : bool String::ComputeArrayIndex(uint32_t* index) {
11812 : int length = this->length();
11813 4309301 : if (length == 0 || length > kMaxArrayIndexSize) return false;
11814 : StringCharacterStream stream(this);
11815 1840269 : return StringToArrayIndex(&stream, index);
11816 : }
11817 :
11818 :
11819 23891694 : bool String::SlowAsArrayIndex(uint32_t* index) {
11820 23891694 : if (length() <= kMaxCachedArrayIndexLength) {
11821 19582393 : Hash(); // force computation of hash code
11822 : uint32_t field = hash_field();
11823 19582393 : if ((field & kIsNotArrayIndexMask) != 0) return false;
11824 : // Isolate the array index form the full hash field.
11825 6707712 : *index = ArrayIndexValueBits::decode(field);
11826 6707712 : return true;
11827 : } else {
11828 4309301 : return ComputeArrayIndex(index);
11829 : }
11830 : }
11831 :
11832 :
11833 38297426 : Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
11834 : Heap* heap = string->GetHeap();
11835 38297426 : if (new_length == 0) return heap->isolate()->factory()->empty_string();
11836 :
11837 : int new_size, old_size;
11838 : int old_length = string->length();
11839 28892863 : if (old_length <= new_length) return string;
11840 :
11841 27264198 : if (string->IsSeqOneByteString()) {
11842 : old_size = SeqOneByteString::SizeFor(old_length);
11843 : new_size = SeqOneByteString::SizeFor(new_length);
11844 : } else {
11845 : DCHECK(string->IsSeqTwoByteString());
11846 : old_size = SeqTwoByteString::SizeFor(old_length);
11847 : new_size = SeqTwoByteString::SizeFor(new_length);
11848 : }
11849 :
11850 27264198 : int delta = old_size - new_size;
11851 :
11852 27264198 : Address start_of_string = string->address();
11853 : DCHECK_OBJECT_ALIGNED(start_of_string);
11854 : DCHECK_OBJECT_ALIGNED(start_of_string + new_size);
11855 :
11856 : // Sizes are pointer size aligned, so that we can use filler objects
11857 : // that are a multiple of pointer size.
11858 : heap->CreateFillerObjectAt(start_of_string + new_size, delta,
11859 27264198 : ClearRecordedSlots::kNo);
11860 54528396 : heap->AdjustLiveBytes(*string, -delta);
11861 :
11862 : // We are storing the new length using release store after creating a filler
11863 : // for the left-over space to avoid races with the sweeper thread.
11864 : string->synchronized_set_length(new_length);
11865 :
11866 27264198 : return string;
11867 : }
11868 :
11869 :
11870 2303138 : uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
11871 : // For array indexes mix the length into the hash as an array index could
11872 : // be zero.
11873 : DCHECK(length > 0);
11874 : DCHECK(length <= String::kMaxArrayIndexSize);
11875 : DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
11876 : (1 << String::kArrayIndexValueBits));
11877 :
11878 13358700 : value <<= String::ArrayIndexValueBits::kShift;
11879 13358700 : value |= length << String::ArrayIndexLengthBits::kShift;
11880 :
11881 : DCHECK((value & String::kIsNotArrayIndexMask) == 0);
11882 : DCHECK_EQ(length <= String::kMaxCachedArrayIndexLength,
11883 : (value & String::kContainsCachedArrayIndexMask) == 0);
11884 2303138 : return value;
11885 : }
11886 :
11887 :
11888 212848599 : uint32_t StringHasher::GetHashField() {
11889 212848599 : if (length_ <= String::kMaxHashCalcLength) {
11890 212787594 : if (is_array_index_) {
11891 21145784 : return MakeArrayIndexHash(array_index_, length_);
11892 : }
11893 404429404 : return (GetHashCore(raw_running_hash_) << String::kHashShift) |
11894 202214702 : String::kIsNotArrayIndexMask;
11895 : } else {
11896 61005 : return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
11897 : }
11898 : }
11899 :
11900 :
11901 24519251 : uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars,
11902 : uint32_t seed,
11903 : int* utf16_length_out) {
11904 24519251 : int vector_length = chars.length();
11905 : // Handle some edge cases
11906 24519251 : if (vector_length <= 1) {
11907 : DCHECK(vector_length == 0 ||
11908 : static_cast<uint8_t>(chars.start()[0]) <=
11909 : unibrow::Utf8::kMaxOneByteChar);
11910 42218 : *utf16_length_out = vector_length;
11911 42218 : return HashSequentialString(chars.start(), vector_length, seed);
11912 : }
11913 : // Start with a fake length which won't affect computation.
11914 : // It will be updated later.
11915 : StringHasher hasher(String::kMaxArrayIndexSize, seed);
11916 24477033 : size_t remaining = static_cast<size_t>(vector_length);
11917 : const uint8_t* stream = reinterpret_cast<const uint8_t*>(chars.start());
11918 : int utf16_length = 0;
11919 : bool is_index = true;
11920 : DCHECK(hasher.is_array_index_);
11921 576423782 : while (remaining > 0) {
11922 527469716 : size_t consumed = 0;
11923 527469716 : uint32_t c = unibrow::Utf8::ValueOf(stream, remaining, &consumed);
11924 : DCHECK(consumed > 0 && consumed <= remaining);
11925 527469716 : stream += consumed;
11926 527469716 : remaining -= consumed;
11927 527469716 : bool is_two_characters = c > unibrow::Utf16::kMaxNonSurrogateCharCode;
11928 527469716 : utf16_length += is_two_characters ? 2 : 1;
11929 : // No need to keep hashing. But we do need to calculate utf16_length.
11930 527469716 : if (utf16_length > String::kMaxHashCalcLength) continue;
11931 527469716 : if (is_two_characters) {
11932 : uint16_t c1 = unibrow::Utf16::LeadSurrogate(c);
11933 : uint16_t c2 = unibrow::Utf16::TrailSurrogate(c);
11934 : hasher.AddCharacter(c1);
11935 : hasher.AddCharacter(c2);
11936 14 : if (is_index) is_index = hasher.UpdateIndex(c1);
11937 14 : if (is_index) is_index = hasher.UpdateIndex(c2);
11938 : } else {
11939 : hasher.AddCharacter(c);
11940 527469702 : if (is_index) is_index = hasher.UpdateIndex(c);
11941 : }
11942 : }
11943 24477033 : *utf16_length_out = static_cast<int>(utf16_length);
11944 : // Must set length here so that hash computation is correct.
11945 24477033 : hasher.length_ = utf16_length;
11946 24477033 : return hasher.GetHashField();
11947 : }
11948 :
11949 :
11950 2502457 : void IteratingStringHasher::VisitConsString(ConsString* cons_string) {
11951 : // Run small ConsStrings through ConsStringIterator.
11952 2502457 : if (cons_string->length() < 64) {
11953 : ConsStringIterator iter(cons_string);
11954 : int offset;
11955 : String* string;
11956 15012985 : while (nullptr != (string = iter.Next(&offset))) {
11957 : DCHECK_EQ(0, offset);
11958 12825446 : String::VisitFlat(this, string, 0);
11959 : }
11960 2502457 : return;
11961 : }
11962 : // Slow case.
11963 314918 : const int max_length = String::kMaxHashCalcLength;
11964 629836 : int length = std::min(cons_string->length(), max_length);
11965 314918 : if (cons_string->HasOnlyOneByteChars()) {
11966 279226 : uint8_t* buffer = new uint8_t[length];
11967 279226 : String::WriteToFlat(cons_string, buffer, 0, length);
11968 279226 : AddCharacters(buffer, length);
11969 279226 : delete[] buffer;
11970 : } else {
11971 35692 : uint16_t* buffer = new uint16_t[length];
11972 35692 : String::WriteToFlat(cons_string, buffer, 0, length);
11973 35692 : AddCharacters(buffer, length);
11974 35692 : delete[] buffer;
11975 : }
11976 : }
11977 :
11978 :
11979 51674 : void String::PrintOn(FILE* file) {
11980 : int length = this->length();
11981 4535154 : for (int i = 0; i < length; i++) {
11982 4483480 : PrintF(file, "%c", Get(i));
11983 : }
11984 51674 : }
11985 :
11986 :
11987 1412102 : int Map::Hash() {
11988 : // For performance reasons we only hash the 3 most variable fields of a map:
11989 : // constructor, prototype and bit_field2. For predictability reasons we
11990 : // use objects' offsets in respective pages for hashing instead of raw
11991 : // addresses.
11992 :
11993 : // Shift away the tag.
11994 2824204 : int hash = ObjectAddressForHashing(GetConstructor()) >> 2;
11995 :
11996 : // XOR-ing the prototype and constructor directly yields too many zero bits
11997 : // when the two pointers are close (which is fairly common).
11998 : // To avoid this we shift the prototype bits relatively to the constructor.
11999 1412102 : hash ^= ObjectAddressForHashing(prototype()) << (32 - kPageSizeBits);
12000 :
12001 2824204 : return hash ^ (hash >> 16) ^ bit_field2();
12002 : }
12003 :
12004 :
12005 : namespace {
12006 :
12007 2461738 : bool CheckEquivalent(Map* first, Map* second) {
12008 4868035 : return first->GetConstructor() == second->GetConstructor() &&
12009 2393126 : first->prototype() == second->prototype() &&
12010 2393098 : first->instance_type() == second->instance_type() &&
12011 2393098 : first->bit_field() == second->bit_field() &&
12012 2392909 : first->is_extensible() == second->is_extensible() &&
12013 4854617 : first->new_target_is_base() == second->new_target_is_base() &&
12014 2461738 : first->has_hidden_prototype() == second->has_hidden_prototype();
12015 : }
12016 :
12017 : } // namespace
12018 :
12019 :
12020 1494603 : bool Map::EquivalentToForTransition(Map* other) {
12021 1494603 : if (!CheckEquivalent(this, other)) return false;
12022 1494399 : if (instance_type() == JS_FUNCTION_TYPE) {
12023 : // JSFunctions require more checks to ensure that sloppy function is
12024 : // not equvalent to strict function.
12025 : int nof = Min(NumberOfOwnDescriptors(), other->NumberOfOwnDescriptors());
12026 : return instance_descriptors()->IsEqualUpTo(other->instance_descriptors(),
12027 8607 : nof);
12028 : }
12029 : return true;
12030 : }
12031 :
12032 :
12033 967135 : bool Map::EquivalentToForNormalization(Map* other,
12034 : PropertyNormalizationMode mode) {
12035 : int properties =
12036 967135 : mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other->GetInObjectProperties();
12037 2764095 : return CheckEquivalent(this, other) && bit_field2() == other->bit_field2() &&
12038 1720574 : GetInObjectProperties() == properties &&
12039 753439 : JSObject::GetEmbedderFieldCount(this) ==
12040 1720574 : JSObject::GetEmbedderFieldCount(other);
12041 : }
12042 :
12043 :
12044 24822240 : bool JSFunction::Inlines(SharedFunctionInfo* candidate) {
12045 : DisallowHeapAllocation no_gc;
12046 24822240 : if (shared() == candidate) return true;
12047 24807966 : if (code()->kind() != Code::OPTIMIZED_FUNCTION) return false;
12048 : DeoptimizationInputData* const data =
12049 : DeoptimizationInputData::cast(code()->deoptimization_data());
12050 230857 : if (data->length() == 0) return false;
12051 : FixedArray* const literals = data->LiteralArray();
12052 : int const inlined_count = data->InlinedFunctionCount()->value();
12053 253772 : for (int i = 0; i < inlined_count; ++i) {
12054 22973 : if (SharedFunctionInfo::cast(literals->get(i)) == candidate) {
12055 : return true;
12056 : }
12057 : }
12058 : return false;
12059 : }
12060 :
12061 1216485 : void JSFunction::MarkForOptimization() {
12062 : Isolate* isolate = GetIsolate();
12063 : DCHECK(!IsOptimized());
12064 : DCHECK(shared()->allows_lazy_compilation() ||
12065 : !shared()->optimization_disabled());
12066 : set_code_no_write_barrier(
12067 : isolate->builtins()->builtin(Builtins::kCompileOptimized));
12068 : // No write barrier required, since the builtin is part of the root set.
12069 1217243 : if (FLAG_mark_shared_functions_for_tier_up) {
12070 : shared()->set_marked_for_tier_up(true);
12071 : }
12072 1216485 : }
12073 :
12074 :
12075 141101 : void JSFunction::AttemptConcurrentOptimization() {
12076 281449 : Isolate* isolate = GetIsolate();
12077 281449 : if (!isolate->concurrent_recompilation_enabled() ||
12078 140348 : isolate->bootstrapper()->IsActive()) {
12079 : MarkForOptimization();
12080 141101 : return;
12081 : }
12082 : DCHECK(!IsInOptimizationQueue());
12083 : DCHECK(!IsOptimized());
12084 : DCHECK(shared()->allows_lazy_compilation() ||
12085 : !shared()->optimization_disabled());
12086 : DCHECK(isolate->concurrent_recompilation_enabled());
12087 140343 : if (FLAG_trace_concurrent_recompilation) {
12088 0 : PrintF(" ** Marking ");
12089 0 : ShortPrint();
12090 0 : PrintF(" for concurrent recompilation.\n");
12091 : }
12092 :
12093 : set_code_no_write_barrier(
12094 : isolate->builtins()->builtin(Builtins::kCompileOptimizedConcurrent));
12095 : // No write barrier required, since the builtin is part of the root set.
12096 140343 : if (FLAG_mark_shared_functions_for_tier_up) {
12097 : // TODO(leszeks): The compilation isn't concurrent if we trigger it using
12098 : // this bit.
12099 : shared()->set_marked_for_tier_up(true);
12100 : }
12101 : }
12102 :
12103 : // static
12104 277951 : void SharedFunctionInfo::AddToOptimizedCodeMap(
12105 : Handle<SharedFunctionInfo> shared, Handle<Context> native_context,
12106 : Handle<Code> code, BailoutId osr_ast_id) {
12107 277951 : Isolate* isolate = shared->GetIsolate();
12108 286293 : if (isolate->serializer_enabled()) return;
12109 : DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
12110 : DCHECK(native_context->IsNativeContext());
12111 : STATIC_ASSERT(kEntryLength == 2);
12112 : Handle<FixedArray> new_code_map;
12113 : int entry;
12114 :
12115 277951 : if (!osr_ast_id.IsNone()) {
12116 2547 : Context::AddToOptimizedCodeMap(native_context, shared, code, osr_ast_id);
12117 2547 : return;
12118 : }
12119 :
12120 : DCHECK(osr_ast_id.IsNone());
12121 275404 : if (shared->OptimizedCodeMapIsCleared()) {
12122 234093 : new_code_map = isolate->factory()->NewFixedArray(kInitialLength, TENURED);
12123 : entry = kEntriesStart;
12124 : } else {
12125 : Handle<FixedArray> old_code_map(shared->optimized_code_map(), isolate);
12126 41311 : entry = shared->SearchOptimizedCodeMapEntry(*native_context);
12127 41311 : if (entry >= kEntriesStart) {
12128 : // Just set the code of the entry.
12129 5795 : Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code);
12130 11590 : old_code_map->set(entry + kCachedCodeOffset, *code_cell);
12131 : return;
12132 : }
12133 :
12134 : // Can we reuse an entry?
12135 : DCHECK(entry < kEntriesStart);
12136 : int length = old_code_map->length();
12137 121996 : for (int i = kEntriesStart; i < length; i += kEntryLength) {
12138 90384 : if (WeakCell::cast(old_code_map->get(i + kContextOffset))->cleared()) {
12139 : new_code_map = old_code_map;
12140 : entry = i;
12141 : break;
12142 : }
12143 : }
12144 :
12145 35516 : if (entry < kEntriesStart) {
12146 : // Copy old optimized code map and append one new entry.
12147 : new_code_map = isolate->factory()->CopyFixedArrayAndGrow(
12148 31612 : old_code_map, kEntryLength, TENURED);
12149 : // TODO(mstarzinger): Temporary workaround. The allocation above might
12150 : // have flushed the optimized code map and the copy we created is full of
12151 : // holes. For now we just give up on adding the entry and pretend it got
12152 : // flushed.
12153 31612 : if (shared->OptimizedCodeMapIsCleared()) return;
12154 : entry = old_code_map->length();
12155 : }
12156 : }
12157 :
12158 269609 : Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code);
12159 : WeakCell* context_cell = native_context->self_weak_cell();
12160 :
12161 269608 : new_code_map->set(entry + kContextOffset, context_cell);
12162 539218 : new_code_map->set(entry + kCachedCodeOffset, *code_cell);
12163 :
12164 : #ifdef DEBUG
12165 : for (int i = kEntriesStart; i < new_code_map->length(); i += kEntryLength) {
12166 : WeakCell* cell = WeakCell::cast(new_code_map->get(i + kContextOffset));
12167 : DCHECK(cell->cleared() || cell->value()->IsNativeContext());
12168 : cell = WeakCell::cast(new_code_map->get(i + kCachedCodeOffset));
12169 : DCHECK(cell->cleared() ||
12170 : (cell->value()->IsCode() &&
12171 : Code::cast(cell->value())->kind() == Code::OPTIMIZED_FUNCTION));
12172 : }
12173 : #endif
12174 :
12175 : FixedArray* old_code_map = shared->optimized_code_map();
12176 269609 : if (old_code_map != *new_code_map) {
12177 265705 : shared->set_optimized_code_map(*new_code_map);
12178 : }
12179 : }
12180 :
12181 :
12182 296 : void SharedFunctionInfo::ClearOptimizedCodeMap() {
12183 296 : FixedArray* empty_fixed_array = GetHeap()->empty_fixed_array();
12184 296 : set_optimized_code_map(empty_fixed_array, SKIP_WRITE_BARRIER);
12185 296 : }
12186 :
12187 :
12188 438599 : void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
12189 : const char* reason) {
12190 : DisallowHeapAllocation no_gc;
12191 : Isolate* isolate = GetIsolate();
12192 : bool found = false;
12193 :
12194 438599 : if (!OptimizedCodeMapIsCleared()) {
12195 176696 : Heap* heap = isolate->heap();
12196 : FixedArray* code_map = optimized_code_map();
12197 : int length = code_map->length();
12198 536562 : for (int src = kEntriesStart; src < length; src += kEntryLength) {
12199 : DCHECK(WeakCell::cast(code_map->get(src))->cleared() ||
12200 : WeakCell::cast(code_map->get(src))->value()->IsNativeContext());
12201 325058 : found = WeakCell::cast(code_map->get(src + kCachedCodeOffset))->value() ==
12202 325058 : optimized_code;
12203 325058 : if (found) {
12204 176696 : if (FLAG_trace_opt) {
12205 0 : PrintF("[evicting entry from optimizing code map (%s) for ", reason);
12206 0 : ShortPrint();
12207 0 : PrintF("]\n");
12208 : }
12209 : // Just clear the code.
12210 : code_map->set(src + kCachedCodeOffset, heap->empty_weak_cell(),
12211 176696 : SKIP_WRITE_BARRIER);
12212 : }
12213 : }
12214 : }
12215 :
12216 438599 : if (!found) {
12217 : // We didn't find the code in here. It must be osr'd code.
12218 280169 : isolate->EvictOSROptimizedCode(optimized_code, reason);
12219 : }
12220 438599 : }
12221 :
12222 : // static
12223 18752916 : void JSFunction::EnsureLiterals(Handle<JSFunction> function) {
12224 : Handle<SharedFunctionInfo> shared(function->shared());
12225 : Isolate* isolate = shared->GetIsolate();
12226 :
12227 18752918 : FeedbackVectorState state = function->GetFeedbackVectorState(isolate);
12228 18752916 : switch (state) {
12229 : case TOP_LEVEL_SCRIPT_NEEDS_VECTOR: {
12230 : // A top level script didn't get it's literals installed.
12231 : Handle<FeedbackVector> feedback_vector =
12232 6121472 : FeedbackVector::New(isolate, shared);
12233 : Handle<Cell> new_cell =
12234 6121475 : isolate->factory()->NewOneClosureCell(feedback_vector);
12235 6121474 : function->set_feedback_vector_cell(*new_cell);
12236 : break;
12237 : }
12238 : case NEEDS_VECTOR: {
12239 : Handle<FeedbackVector> feedback_vector =
12240 2398992 : FeedbackVector::New(isolate, shared);
12241 2398991 : function->feedback_vector_cell()->set_value(*feedback_vector);
12242 : break;
12243 : }
12244 : case HAS_VECTOR:
12245 : // Nothing to do.
12246 : break;
12247 : }
12248 18752918 : }
12249 :
12250 344364 : static void GetMinInobjectSlack(Map* map, void* data) {
12251 : int slack = map->unused_property_fields();
12252 344364 : if (*reinterpret_cast<int*>(data) > slack) {
12253 88632 : *reinterpret_cast<int*>(data) = slack;
12254 : }
12255 344364 : }
12256 :
12257 :
12258 337007 : static void ShrinkInstanceSize(Map* map, void* data) {
12259 337007 : int slack = *reinterpret_cast<int*>(data);
12260 337007 : map->SetInObjectProperties(map->GetInObjectProperties() - slack);
12261 337007 : map->set_unused_property_fields(map->unused_property_fields() - slack);
12262 337007 : map->set_instance_size(map->instance_size() - slack * kPointerSize);
12263 : map->set_construction_counter(Map::kNoSlackTracking);
12264 :
12265 : // Visitor id might depend on the instance size, recalculate it.
12266 337007 : map->set_visitor_id(Heap::GetStaticVisitorIdForMap(map));
12267 337007 : }
12268 :
12269 7357 : static void StopSlackTracking(Map* map, void* data) {
12270 : map->set_construction_counter(Map::kNoSlackTracking);
12271 7357 : }
12272 :
12273 92937 : void Map::CompleteInobjectSlackTracking() {
12274 : // Has to be an initial map.
12275 : DCHECK(GetBackPointer()->IsUndefined(GetIsolate()));
12276 :
12277 92937 : int slack = unused_property_fields();
12278 : TransitionArray::TraverseTransitionTree(this, &GetMinInobjectSlack, &slack);
12279 92937 : if (slack != 0) {
12280 : // Resize the initial map and all maps in its transition tree.
12281 : TransitionArray::TraverseTransitionTree(this, &ShrinkInstanceSize, &slack);
12282 : } else {
12283 : TransitionArray::TraverseTransitionTree(this, &StopSlackTracking, nullptr);
12284 : }
12285 92937 : }
12286 :
12287 :
12288 27763918 : static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) {
12289 : DisallowHeapAllocation no_gc;
12290 27763918 : if (!object->HasFastProperties()) return false;
12291 26465674 : if (object->IsJSGlobalProxy()) return false;
12292 26433425 : if (object->GetIsolate()->bootstrapper()->IsActive()) return false;
12293 11493683 : return !object->map()->is_prototype_map() ||
12294 11493683 : !object->map()->should_be_fast_prototype_map();
12295 : }
12296 :
12297 : // static
12298 5943447 : void JSObject::MakePrototypesFast(Handle<Object> receiver,
12299 : WhereToStart where_to_start,
12300 : Isolate* isolate) {
12301 5943447 : if (!receiver->IsJSReceiver()) return;
12302 15962145 : for (PrototypeIterator iter(isolate, Handle<JSReceiver>::cast(receiver),
12303 5874236 : where_to_start);
12304 14301580 : !iter.IsAtEnd(); iter.Advance()) {
12305 : Handle<Object> current = PrototypeIterator::GetCurrent(iter);
12306 9609096 : if (!current->IsJSObject()) return;
12307 : Handle<JSObject> current_obj = Handle<JSObject>::cast(current);
12308 : Map* current_map = current_obj->map();
12309 9603622 : if (current_map->is_prototype_map()) {
12310 : // If the map is already marked as should be fast, we're done. Its
12311 : // prototypes will have been marked already as well.
12312 11109670 : if (current_map->should_be_fast_prototype_map()) return;
12313 : Handle<Map> map(current_map);
12314 329770 : Map::SetShouldBeFastPrototypeMap(map, true, isolate);
12315 329770 : JSObject::OptimizeAsPrototype(current_obj, FAST_PROTOTYPE);
12316 : }
12317 : }
12318 : }
12319 :
12320 : // static
12321 27949692 : void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
12322 : PrototypeOptimizationMode mode) {
12323 55899377 : if (object->IsJSGlobalObject()) return;
12324 27833451 : if (mode == FAST_PROTOTYPE && PrototypeBenefitsFromNormalization(object)) {
12325 : // First normalize to ensure all JSFunctions are DATA_CONSTANT.
12326 : JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0,
12327 594366 : "NormalizeAsPrototype");
12328 : }
12329 : Handle<Map> previous_map(object->map());
12330 27833449 : if (object->map()->is_prototype_map()) {
12331 39960318 : if (object->map()->should_be_fast_prototype_map() &&
12332 17129593 : !object->HasFastProperties()) {
12333 293328 : JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype");
12334 : }
12335 : } else {
12336 5002722 : if (object->map() == *previous_map) {
12337 5002721 : Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype");
12338 5002720 : JSObject::MigrateToMap(object, new_map);
12339 : }
12340 : object->map()->set_is_prototype_map(true);
12341 :
12342 : // Replace the pointer to the exact constructor with the Object function
12343 : // from the same context if undetectable from JS. This is to avoid keeping
12344 : // memory alive unnecessarily.
12345 5002721 : Object* maybe_constructor = object->map()->GetConstructor();
12346 5002721 : if (maybe_constructor->IsJSFunction()) {
12347 : JSFunction* constructor = JSFunction::cast(maybe_constructor);
12348 : Isolate* isolate = object->GetIsolate();
12349 9511091 : if (!constructor->shared()->IsApiFunction() &&
12350 4512207 : object->class_name() == isolate->heap()->Object_string()) {
12351 : Context* context = constructor->context()->native_context();
12352 : JSFunction* object_function = context->object_function();
12353 : object->map()->SetConstructor(object_function);
12354 : }
12355 : }
12356 : }
12357 : }
12358 :
12359 :
12360 : // static
12361 6583834 : void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) {
12362 6583834 : if (!object->map()->is_prototype_map()) return;
12363 90338 : if (!object->map()->should_be_fast_prototype_map()) return;
12364 60333 : OptimizeAsPrototype(object, FAST_PROTOTYPE);
12365 : }
12366 :
12367 :
12368 : // static
12369 3008331 : void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
12370 : // Contract: In line with InvalidatePrototypeChains()'s requirements,
12371 : // leaf maps don't need to register as users, only prototypes do.
12372 : DCHECK(user->is_prototype_map());
12373 :
12374 3008331 : Handle<Map> current_user = user;
12375 : Handle<PrototypeInfo> current_user_info =
12376 3008331 : Map::GetOrCreatePrototypeInfo(user, isolate);
12377 7012928 : for (PrototypeIterator iter(user); !iter.IsAtEnd(); iter.Advance()) {
12378 : // Walk up the prototype chain as far as links haven't been registered yet.
12379 2906167 : if (current_user_info->registry_slot() != PrototypeInfo::UNREGISTERED) {
12380 : break;
12381 : }
12382 : Handle<Object> maybe_proto = PrototypeIterator::GetCurrent(iter);
12383 : // Proxies on the prototype chain are not supported. They make it
12384 : // impossible to make any assumptions about the prototype chain anyway.
12385 3506548 : if (maybe_proto->IsJSProxy()) return;
12386 : Handle<JSObject> proto = Handle<JSObject>::cast(maybe_proto);
12387 : Handle<PrototypeInfo> proto_info =
12388 498133 : Map::GetOrCreatePrototypeInfo(proto, isolate);
12389 : Handle<Object> maybe_registry(proto_info->prototype_users(), isolate);
12390 498133 : int slot = 0;
12391 : Handle<WeakFixedArray> new_array =
12392 498133 : WeakFixedArray::Add(maybe_registry, current_user, &slot);
12393 498133 : current_user_info->set_registry_slot(slot);
12394 498133 : if (!maybe_registry.is_identical_to(new_array)) {
12395 151031 : proto_info->set_prototype_users(*new_array);
12396 : }
12397 498133 : if (FLAG_trace_prototype_users) {
12398 : PrintF("Registering %p as a user of prototype %p (map=%p).\n",
12399 : reinterpret_cast<void*>(*current_user),
12400 : reinterpret_cast<void*>(*proto),
12401 0 : reinterpret_cast<void*>(proto->map()));
12402 : }
12403 :
12404 : current_user = handle(proto->map(), isolate);
12405 : current_user_info = proto_info;
12406 : }
12407 : }
12408 :
12409 :
12410 : // Can be called regardless of whether |user| was actually registered with
12411 : // |prototype|. Returns true when there was a registration.
12412 : // static
12413 5497297 : bool JSObject::UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
12414 : DCHECK(user->is_prototype_map());
12415 : // If it doesn't have a PrototypeInfo, it was never registered.
12416 5497297 : if (!user->prototype_info()->IsPrototypeInfo()) return false;
12417 : // If it had no prototype before, see if it had users that might expect
12418 : // registration.
12419 540369 : if (!user->prototype()->IsJSObject()) {
12420 : Object* users =
12421 : PrototypeInfo::cast(user->prototype_info())->prototype_users();
12422 112473 : return users->IsWeakFixedArray();
12423 : }
12424 : Handle<JSObject> prototype(JSObject::cast(user->prototype()), isolate);
12425 : Handle<PrototypeInfo> user_info =
12426 427896 : Map::GetOrCreatePrototypeInfo(user, isolate);
12427 : int slot = user_info->registry_slot();
12428 427896 : if (slot == PrototypeInfo::UNREGISTERED) return false;
12429 : DCHECK(prototype->map()->is_prototype_map());
12430 : Object* maybe_proto_info = prototype->map()->prototype_info();
12431 : // User knows its registry slot, prototype info and user registry must exist.
12432 : DCHECK(maybe_proto_info->IsPrototypeInfo());
12433 : Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info),
12434 : isolate);
12435 : Object* maybe_registry = proto_info->prototype_users();
12436 : DCHECK(maybe_registry->IsWeakFixedArray());
12437 : DCHECK(WeakFixedArray::cast(maybe_registry)->Get(slot) == *user);
12438 : WeakFixedArray::cast(maybe_registry)->Clear(slot);
12439 176128 : if (FLAG_trace_prototype_users) {
12440 : PrintF("Unregistering %p as a user of prototype %p.\n",
12441 0 : reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype));
12442 : }
12443 : return true;
12444 : }
12445 :
12446 :
12447 5736684 : static void InvalidatePrototypeChainsInternal(Map* map) {
12448 : DCHECK(map->is_prototype_map());
12449 5736684 : if (FLAG_trace_prototype_users) {
12450 : PrintF("Invalidating prototype map %p 's cell\n",
12451 0 : reinterpret_cast<void*>(map));
12452 : }
12453 : Object* maybe_proto_info = map->prototype_info();
12454 10694143 : if (!maybe_proto_info->IsPrototypeInfo()) return;
12455 : PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info);
12456 : Object* maybe_cell = proto_info->validity_cell();
12457 779225 : if (maybe_cell->IsCell()) {
12458 : // Just set the value; the cell will be replaced lazily.
12459 : Cell* cell = Cell::cast(maybe_cell);
12460 503389 : cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid));
12461 : }
12462 :
12463 : WeakFixedArray::Iterator iterator(proto_info->prototype_users());
12464 : // For now, only maps register themselves as users.
12465 : Map* user;
12466 1017065 : while ((user = iterator.Next<Map>()) != nullptr) {
12467 : // Walk the prototype chain (backwards, towards leaf objects) if necessary.
12468 237840 : InvalidatePrototypeChainsInternal(user);
12469 : }
12470 : }
12471 :
12472 :
12473 : // static
12474 0 : void JSObject::InvalidatePrototypeChains(Map* map) {
12475 : DisallowHeapAllocation no_gc;
12476 5498844 : InvalidatePrototypeChainsInternal(map);
12477 0 : }
12478 :
12479 :
12480 : // static
12481 4614362 : Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<JSObject> prototype,
12482 : Isolate* isolate) {
12483 : Object* maybe_proto_info = prototype->map()->prototype_info();
12484 4614362 : if (maybe_proto_info->IsPrototypeInfo()) {
12485 : return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
12486 : }
12487 196849 : Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
12488 196849 : prototype->map()->set_prototype_info(*proto_info);
12489 196849 : return proto_info;
12490 : }
12491 :
12492 :
12493 : // static
12494 3766693 : Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<Map> prototype_map,
12495 : Isolate* isolate) {
12496 : Object* maybe_proto_info = prototype_map->prototype_info();
12497 3766693 : if (maybe_proto_info->IsPrototypeInfo()) {
12498 : return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
12499 : }
12500 302960 : Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
12501 302960 : prototype_map->set_prototype_info(*proto_info);
12502 302960 : return proto_info;
12503 : }
12504 :
12505 : // static
12506 330466 : void Map::SetShouldBeFastPrototypeMap(Handle<Map> map, bool value,
12507 : Isolate* isolate) {
12508 330466 : if (value == false && !map->prototype_info()->IsPrototypeInfo()) {
12509 : // "False" is the implicit default value, so there's nothing to do.
12510 330466 : return;
12511 : }
12512 660932 : GetOrCreatePrototypeInfo(map, isolate)->set_should_be_fast_map(value);
12513 : }
12514 :
12515 : // static
12516 3061911 : Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
12517 : Isolate* isolate) {
12518 : Handle<Object> maybe_prototype;
12519 3061911 : if (map->IsJSGlobalObjectMap()) {
12520 : DCHECK(map->is_prototype_map());
12521 : // Global object is prototype of a global proxy and therefore we can
12522 : // use its validity cell for guarding global object's prototype change.
12523 2869 : maybe_prototype = isolate->global_object();
12524 : } else {
12525 : maybe_prototype =
12526 3059042 : handle(map->GetPrototypeChainRootMap(isolate)->prototype(), isolate);
12527 3059042 : if (!maybe_prototype->IsJSObject()) return Handle<Cell>::null();
12528 : }
12529 : Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype);
12530 : // Ensure the prototype is registered with its own prototypes so its cell
12531 : // will be invalidated when necessary.
12532 : JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate),
12533 2723929 : isolate);
12534 : Handle<PrototypeInfo> proto_info =
12535 2723929 : GetOrCreatePrototypeInfo(prototype, isolate);
12536 : Object* maybe_cell = proto_info->validity_cell();
12537 : // Return existing cell if it's still valid.
12538 2723929 : if (maybe_cell->IsCell()) {
12539 : Handle<Cell> cell(Cell::cast(maybe_cell), isolate);
12540 2451838 : if (cell->value() == Smi::FromInt(Map::kPrototypeChainValid)) {
12541 2397911 : return cell;
12542 : }
12543 : }
12544 : // Otherwise create a new cell.
12545 : Handle<Cell> cell = isolate->factory()->NewCell(
12546 326018 : handle(Smi::FromInt(Map::kPrototypeChainValid), isolate));
12547 326018 : proto_info->set_validity_cell(*cell);
12548 326018 : return cell;
12549 : }
12550 :
12551 : // static
12552 1204609 : Handle<WeakCell> Map::GetOrCreatePrototypeWeakCell(Handle<JSObject> prototype,
12553 : Isolate* isolate) {
12554 : DCHECK(!prototype.is_null());
12555 : Handle<PrototypeInfo> proto_info =
12556 1204609 : GetOrCreatePrototypeInfo(prototype, isolate);
12557 : Object* maybe_cell = proto_info->weak_cell();
12558 : // Return existing cell if it's already created.
12559 1204609 : if (maybe_cell->IsWeakCell()) {
12560 : Handle<WeakCell> cell(WeakCell::cast(maybe_cell), isolate);
12561 : DCHECK(!cell->cleared());
12562 1048917 : return cell;
12563 : }
12564 : // Otherwise create a new cell.
12565 155692 : Handle<WeakCell> cell = isolate->factory()->NewWeakCell(prototype);
12566 155692 : proto_info->set_weak_cell(*cell);
12567 155692 : return cell;
12568 : }
12569 :
12570 : // static
12571 31773330 : void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype,
12572 : PrototypeOptimizationMode proto_mode) {
12573 31773330 : RuntimeCallTimerScope stats_scope(*map, &RuntimeCallStats::Map_SetPrototype);
12574 :
12575 : bool is_hidden = false;
12576 31773352 : if (prototype->IsJSObject()) {
12577 : Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype);
12578 26595847 : JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode);
12579 :
12580 26595836 : Object* maybe_constructor = prototype_jsobj->map()->GetConstructor();
12581 26595833 : if (maybe_constructor->IsJSFunction()) {
12582 : JSFunction* constructor = JSFunction::cast(maybe_constructor);
12583 : Object* data = constructor->shared()->function_data();
12584 714747 : is_hidden = (data->IsFunctionTemplateInfo() &&
12585 48530003 : FunctionTemplateInfo::cast(data)->hidden_prototype()) ||
12586 : prototype->IsJSGlobalObject();
12587 2330666 : } else if (maybe_constructor->IsFunctionTemplateInfo()) {
12588 : is_hidden =
12589 48 : FunctionTemplateInfo::cast(maybe_constructor)->hidden_prototype() ||
12590 : prototype->IsJSGlobalObject();
12591 : }
12592 : }
12593 : map->set_has_hidden_prototype(is_hidden);
12594 :
12595 : WriteBarrierMode wb_mode = prototype->IsNull(map->GetIsolate())
12596 : ? SKIP_WRITE_BARRIER
12597 31773328 : : UPDATE_WRITE_BARRIER;
12598 31773328 : map->set_prototype(*prototype, wb_mode);
12599 31773333 : }
12600 :
12601 :
12602 158 : Handle<Object> CacheInitialJSArrayMaps(
12603 : Handle<Context> native_context, Handle<Map> initial_map) {
12604 : // Replace all of the cached initial array maps in the native context with
12605 : // the appropriate transitioned elements kind maps.
12606 158 : Handle<Map> current_map = initial_map;
12607 : ElementsKind kind = current_map->elements_kind();
12608 : DCHECK_EQ(GetInitialFastElementsKind(), kind);
12609 158 : native_context->set(Context::ArrayMapIndex(kind), *current_map);
12610 948 : for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1;
12611 : i < kFastElementsKindCount; ++i) {
12612 : Handle<Map> new_map;
12613 790 : ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
12614 790 : if (Map* maybe_elements_transition = current_map->ElementsTransitionMap()) {
12615 : new_map = handle(maybe_elements_transition);
12616 : } else {
12617 : new_map = Map::CopyAsElementsKind(
12618 790 : current_map, next_kind, INSERT_TRANSITION);
12619 : }
12620 : DCHECK_EQ(next_kind, new_map->elements_kind());
12621 790 : native_context->set(Context::ArrayMapIndex(next_kind), *new_map);
12622 : current_map = new_map;
12623 : }
12624 158 : return initial_map;
12625 : }
12626 :
12627 : namespace {
12628 :
12629 695459 : void SetInstancePrototype(Isolate* isolate, Handle<JSFunction> function,
12630 : Handle<JSReceiver> value) {
12631 : // Now some logic for the maps of the objects that are created by using this
12632 : // function as a constructor.
12633 695459 : if (function->has_initial_map()) {
12634 : // If the function has allocated the initial map replace it with a
12635 : // copy containing the new prototype. Also complete any in-object
12636 : // slack tracking that is in progress at this point because it is
12637 : // still tracking the old copy.
12638 42801 : function->CompleteInobjectSlackTrackingIfActive();
12639 :
12640 : Handle<Map> initial_map(function->initial_map(), isolate);
12641 :
12642 83074 : if (!initial_map->GetIsolate()->bootstrapper()->IsActive() &&
12643 : initial_map->instance_type() == JS_OBJECT_TYPE) {
12644 : // Put the value in the initial map field until an initial map is needed.
12645 : // At that point, a new initial map is created and the prototype is put
12646 : // into the initial map where it belongs.
12647 39909 : function->set_prototype_or_initial_map(*value);
12648 : } else {
12649 2892 : Handle<Map> new_map = Map::Copy(initial_map, "SetInstancePrototype");
12650 2892 : JSFunction::SetInitialMap(function, new_map, value);
12651 :
12652 : // If the function is used as the global Array function, cache the
12653 : // updated initial maps (and transitioned versions) in the native context.
12654 : Handle<Context> native_context(function->context()->native_context(),
12655 : isolate);
12656 : Handle<Object> array_function(
12657 : native_context->get(Context::ARRAY_FUNCTION_INDEX), isolate);
12658 5705 : if (array_function->IsJSFunction() &&
12659 : *function == JSFunction::cast(*array_function)) {
12660 79 : CacheInitialJSArrayMaps(native_context, new_map);
12661 : }
12662 : }
12663 :
12664 : // Deoptimize all code that embeds the previous initial map.
12665 : initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
12666 42801 : isolate, DependentCode::kInitialMapChangedGroup);
12667 : } else {
12668 : // Put the value in the initial map field until an initial map is
12669 : // needed. At that point, a new initial map is created and the
12670 : // prototype is put into the initial map where it belongs.
12671 652658 : function->set_prototype_or_initial_map(*value);
12672 652658 : if (value->IsJSObject()) {
12673 : // Optimize as prototype to detach it from its transition tree.
12674 : JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value),
12675 652560 : FAST_PROTOTYPE);
12676 : }
12677 : }
12678 : isolate->heap()->ClearInstanceofCache();
12679 695459 : }
12680 :
12681 : } // anonymous namespace
12682 :
12683 695459 : void JSFunction::SetPrototype(Handle<JSFunction> function,
12684 : Handle<Object> value) {
12685 : DCHECK(function->IsConstructor() ||
12686 : IsGeneratorFunction(function->shared()->kind()));
12687 : Isolate* isolate = function->GetIsolate();
12688 : Handle<JSReceiver> construct_prototype;
12689 :
12690 : // If the value is not a JSReceiver, store the value in the map's
12691 : // constructor field so it can be accessed. Also, set the prototype
12692 : // used for constructing objects to the original object prototype.
12693 : // See ECMA-262 13.2.2.
12694 695459 : if (!value->IsJSReceiver()) {
12695 : // Copy the map so this does not affect unrelated functions.
12696 : // Remove map transitions because they point to maps with a
12697 : // different prototype.
12698 6597 : Handle<Map> new_map = Map::Copy(handle(function->map()), "SetPrototype");
12699 :
12700 6597 : JSObject::MigrateToMap(function, new_map);
12701 : new_map->SetConstructor(*value);
12702 : new_map->set_non_instance_prototype(true);
12703 :
12704 : FunctionKind kind = function->shared()->kind();
12705 : Handle<Context> native_context(function->context()->native_context());
12706 :
12707 : construct_prototype = Handle<JSReceiver>(
12708 : IsGeneratorFunction(kind)
12709 : ? IsAsyncFunction(kind)
12710 : ? native_context->initial_async_generator_prototype()
12711 : : native_context->initial_generator_prototype()
12712 : : native_context->initial_object_prototype(),
12713 13208 : isolate);
12714 : } else {
12715 688862 : construct_prototype = Handle<JSReceiver>::cast(value);
12716 688862 : if (function->map()->has_non_instance_prototype()) {
12717 : function->map()->set_non_instance_prototype(false);
12718 29 : function->map()->SetConstructor(isolate->heap()->null_value());
12719 : }
12720 : }
12721 :
12722 695459 : SetInstancePrototype(isolate, function, construct_prototype);
12723 695459 : }
12724 :
12725 :
12726 46949 : bool JSFunction::RemovePrototype() {
12727 : Context* native_context = context()->native_context();
12728 : Map* no_prototype_map =
12729 : is_strict(shared()->language_mode())
12730 : ? native_context->strict_function_without_prototype_map()
12731 46949 : : native_context->sloppy_function_without_prototype_map();
12732 :
12733 46949 : if (map() == no_prototype_map) return true;
12734 :
12735 : #ifdef DEBUG
12736 : if (map() != (is_strict(shared()->language_mode())
12737 : ? native_context->strict_function_map()
12738 : : native_context->sloppy_function_map())) {
12739 : return false;
12740 : }
12741 : #endif
12742 :
12743 46001 : set_map(no_prototype_map);
12744 46001 : set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value());
12745 46001 : return true;
12746 : }
12747 :
12748 :
12749 4861137 : void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
12750 : Handle<Object> prototype) {
12751 4861137 : if (map->prototype() != *prototype) {
12752 4860495 : Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
12753 : }
12754 4861138 : function->set_prototype_or_initial_map(*map);
12755 : map->SetConstructor(*function);
12756 : #if TRACE_MAPS
12757 : if (FLAG_trace_maps) {
12758 : PrintF("[TraceMaps: InitialMap map= %p SFI= %d_%s ]\n",
12759 : reinterpret_cast<void*>(*map), function->shared()->unique_id(),
12760 : function->shared()->DebugName()->ToCString().get());
12761 : }
12762 : #endif
12763 4861138 : }
12764 :
12765 :
12766 : #ifdef DEBUG
12767 : namespace {
12768 :
12769 : bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
12770 : switch (instance_type) {
12771 : case JS_API_OBJECT_TYPE:
12772 : case JS_ARRAY_BUFFER_TYPE:
12773 : case JS_ARRAY_TYPE:
12774 : case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
12775 : case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
12776 : case JS_DATA_VIEW_TYPE:
12777 : case JS_DATE_TYPE:
12778 : case JS_FUNCTION_TYPE:
12779 : case JS_GENERATOR_OBJECT_TYPE:
12780 : case JS_ASYNC_GENERATOR_OBJECT_TYPE:
12781 : case JS_MAP_ITERATOR_TYPE:
12782 : case JS_MAP_TYPE:
12783 : case JS_MESSAGE_OBJECT_TYPE:
12784 : case JS_OBJECT_TYPE:
12785 : case JS_ERROR_TYPE:
12786 : case JS_ARGUMENTS_TYPE:
12787 : case JS_PROMISE_TYPE:
12788 : case JS_REGEXP_TYPE:
12789 : case JS_SET_ITERATOR_TYPE:
12790 : case JS_SET_TYPE:
12791 : case JS_SPECIAL_API_OBJECT_TYPE:
12792 : case JS_TYPED_ARRAY_TYPE:
12793 : case JS_VALUE_TYPE:
12794 : case JS_WEAK_MAP_TYPE:
12795 : case JS_WEAK_SET_TYPE:
12796 : return true;
12797 :
12798 : case BYTECODE_ARRAY_TYPE:
12799 : case BYTE_ARRAY_TYPE:
12800 : case CELL_TYPE:
12801 : case CODE_TYPE:
12802 : case FILLER_TYPE:
12803 : case FIXED_ARRAY_TYPE:
12804 : case FIXED_DOUBLE_ARRAY_TYPE:
12805 : case FOREIGN_TYPE:
12806 : case FREE_SPACE_TYPE:
12807 : case HEAP_NUMBER_TYPE:
12808 : case JS_BOUND_FUNCTION_TYPE:
12809 : case JS_GLOBAL_OBJECT_TYPE:
12810 : case JS_GLOBAL_PROXY_TYPE:
12811 : case JS_PROXY_TYPE:
12812 : case MAP_TYPE:
12813 : case MUTABLE_HEAP_NUMBER_TYPE:
12814 : case ODDBALL_TYPE:
12815 : case PROPERTY_CELL_TYPE:
12816 : case SHARED_FUNCTION_INFO_TYPE:
12817 : case SYMBOL_TYPE:
12818 : case WEAK_CELL_TYPE:
12819 :
12820 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
12821 : case FIXED_##TYPE##_ARRAY_TYPE:
12822 : #undef TYPED_ARRAY_CASE
12823 :
12824 : #define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE:
12825 : STRUCT_LIST(MAKE_STRUCT_CASE)
12826 : #undef MAKE_STRUCT_CASE
12827 : // We must not end up here for these instance types at all.
12828 : UNREACHABLE();
12829 : // Fall through.
12830 : default:
12831 : return false;
12832 : }
12833 : }
12834 :
12835 : } // namespace
12836 : #endif
12837 :
12838 :
12839 20797261 : void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
12840 : DCHECK(function->IsConstructor() ||
12841 : IsResumableFunction(function->shared()->kind()));
12842 41104724 : if (function->has_initial_map()) return;
12843 : Isolate* isolate = function->GetIsolate();
12844 :
12845 : // First create a new map with the size and number of in-object properties
12846 : // suggested by the function.
12847 : InstanceType instance_type;
12848 489798 : if (IsResumableFunction(function->shared()->kind())) {
12849 : instance_type = IsAsyncGeneratorFunction(function->shared()->kind())
12850 : ? JS_ASYNC_GENERATOR_OBJECT_TYPE
12851 19742 : : JS_GENERATOR_OBJECT_TYPE;
12852 : } else {
12853 : instance_type = JS_OBJECT_TYPE;
12854 : }
12855 :
12856 : // The constructor should be compiled for the optimization hints to be
12857 : // available.
12858 : int expected_nof_properties = 0;
12859 584078 : if (function->shared()->is_compiled() ||
12860 94280 : Compiler::Compile(function, Compiler::CLEAR_EXCEPTION)) {
12861 : DCHECK(function->shared()->is_compiled());
12862 : expected_nof_properties = function->shared()->expected_nof_properties();
12863 : }
12864 :
12865 : int instance_size;
12866 : int in_object_properties;
12867 : CalculateInstanceSizeHelper(instance_type, 0, expected_nof_properties,
12868 489798 : &instance_size, &in_object_properties);
12869 :
12870 489798 : Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size);
12871 :
12872 : // Fetch or allocate prototype.
12873 : Handle<Object> prototype;
12874 489798 : if (function->has_instance_prototype()) {
12875 391306 : prototype = handle(function->instance_prototype(), isolate);
12876 : } else {
12877 98492 : prototype = isolate->factory()->NewFunctionPrototype(function);
12878 : }
12879 489798 : map->SetInObjectProperties(in_object_properties);
12880 : map->set_unused_property_fields(in_object_properties);
12881 : DCHECK(map->has_fast_object_elements());
12882 :
12883 : // Finally link initial map and constructor function.
12884 : DCHECK(prototype->IsJSReceiver());
12885 489798 : JSFunction::SetInitialMap(function, map, prototype);
12886 : map->StartInobjectSlackTracking();
12887 : }
12888 :
12889 :
12890 : // static
12891 3960606 : MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
12892 : Handle<JSFunction> constructor,
12893 : Handle<JSReceiver> new_target) {
12894 3960606 : EnsureHasInitialMap(constructor);
12895 :
12896 : Handle<Map> constructor_initial_map(constructor->initial_map(), isolate);
12897 3960606 : if (*new_target == *constructor) return constructor_initial_map;
12898 :
12899 : // Fast case, new.target is a subclass of constructor. The map is cacheable
12900 : // (and may already have been cached). new.target.prototype is guaranteed to
12901 : // be a JSReceiver.
12902 133401 : if (new_target->IsJSFunction()) {
12903 : Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
12904 :
12905 : // Check that |function|'s initial map still in sync with the |constructor|,
12906 : // otherwise we must create a new initial map for |function|.
12907 254918 : if (function->has_initial_map() &&
12908 121849 : function->initial_map()->GetConstructor() == *constructor) {
12909 : return handle(function->initial_map(), isolate);
12910 : }
12911 :
12912 : // Create a new map with the size and number of in-object properties
12913 : // suggested by |function|.
12914 :
12915 : // Link initial map and constructor function if the new.target is actually a
12916 : // subclass constructor.
12917 11412 : if (IsDerivedConstructor(function->shared()->kind())) {
12918 : Handle<Object> prototype(function->instance_prototype(), isolate);
12919 : InstanceType instance_type = constructor_initial_map->instance_type();
12920 : DCHECK(CanSubclassHaveInobjectProperties(instance_type));
12921 : int embedder_fields =
12922 9044 : JSObject::GetEmbedderFieldCount(*constructor_initial_map);
12923 : int pre_allocated = constructor_initial_map->GetInObjectProperties() -
12924 9044 : constructor_initial_map->unused_property_fields();
12925 : int instance_size;
12926 : int in_object_properties;
12927 : CalculateInstanceSizeForDerivedClass(function, instance_type,
12928 : embedder_fields, &instance_size,
12929 9044 : &in_object_properties);
12930 :
12931 9044 : int unused_property_fields = in_object_properties - pre_allocated;
12932 : Handle<Map> map =
12933 : Map::CopyInitialMap(constructor_initial_map, instance_size,
12934 9044 : in_object_properties, unused_property_fields);
12935 : map->set_new_target_is_base(false);
12936 :
12937 9044 : JSFunction::SetInitialMap(function, map, prototype);
12938 : map->SetConstructor(*constructor);
12939 : map->set_construction_counter(Map::kNoSlackTracking);
12940 : map->StartInobjectSlackTracking();
12941 : return map;
12942 : }
12943 : }
12944 :
12945 : // Slow path, new.target is either a proxy or can't cache the map.
12946 : // new.target.prototype is not guaranteed to be a JSReceiver, and may need to
12947 : // fall back to the intrinsicDefaultProto.
12948 : Handle<Object> prototype;
12949 2700 : if (new_target->IsJSFunction()) {
12950 : Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
12951 : // Make sure the new.target.prototype is cached.
12952 2368 : EnsureHasInitialMap(function);
12953 2368 : prototype = handle(function->prototype(), isolate);
12954 : } else {
12955 : Handle<String> prototype_string = isolate->factory()->prototype_string();
12956 664 : ASSIGN_RETURN_ON_EXCEPTION(
12957 : isolate, prototype,
12958 : JSReceiver::GetProperty(new_target, prototype_string), Map);
12959 : // The above prototype lookup might change the constructor and its
12960 : // prototype, hence we have to reload the initial map.
12961 287 : EnsureHasInitialMap(constructor);
12962 : constructor_initial_map = handle(constructor->initial_map(), isolate);
12963 : }
12964 :
12965 : // If prototype is not a JSReceiver, fetch the intrinsicDefaultProto from the
12966 : // correct realm. Rather than directly fetching the .prototype, we fetch the
12967 : // constructor that points to the .prototype. This relies on
12968 : // constructor.prototype being FROZEN for those constructors.
12969 2655 : if (!prototype->IsJSReceiver()) {
12970 : Handle<Context> context;
12971 4090 : ASSIGN_RETURN_ON_EXCEPTION(isolate, context,
12972 : JSReceiver::GetFunctionRealm(new_target), Map);
12973 : DCHECK(context->IsNativeContext());
12974 : Handle<Object> maybe_index = JSReceiver::GetDataProperty(
12975 2045 : constructor, isolate->factory()->native_context_index_symbol());
12976 : int index = maybe_index->IsSmi() ? Smi::cast(*maybe_index)->value()
12977 2045 : : Context::OBJECT_FUNCTION_INDEX;
12978 : Handle<JSFunction> realm_constructor(JSFunction::cast(context->get(index)));
12979 2045 : prototype = handle(realm_constructor->prototype(), isolate);
12980 : }
12981 :
12982 2655 : Handle<Map> map = Map::CopyInitialMap(constructor_initial_map);
12983 : map->set_new_target_is_base(false);
12984 : DCHECK(prototype->IsJSReceiver());
12985 2655 : if (map->prototype() != *prototype) {
12986 1489 : Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
12987 : }
12988 : map->SetConstructor(*constructor);
12989 : return map;
12990 : }
12991 :
12992 :
12993 0 : void JSFunction::PrintName(FILE* out) {
12994 0 : std::unique_ptr<char[]> name = shared()->DebugName()->ToCString();
12995 0 : PrintF(out, "%s", name.get());
12996 0 : }
12997 :
12998 :
12999 620671 : Handle<String> JSFunction::GetName(Handle<JSFunction> function) {
13000 : Isolate* isolate = function->GetIsolate();
13001 : Handle<Object> name =
13002 620671 : JSReceiver::GetDataProperty(function, isolate->factory()->name_string());
13003 620671 : if (name->IsString()) return Handle<String>::cast(name);
13004 619668 : return handle(function->shared()->DebugName(), isolate);
13005 : }
13006 :
13007 :
13008 374858 : Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) {
13009 : Isolate* isolate = function->GetIsolate();
13010 : Handle<Object> name = JSReceiver::GetDataProperty(
13011 374858 : function, isolate->factory()->display_name_string());
13012 374858 : if (name->IsString()) return Handle<String>::cast(name);
13013 374812 : return JSFunction::GetName(function);
13014 : }
13015 :
13016 1487332 : void JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name,
13017 : Handle<String> prefix) {
13018 : Isolate* isolate = function->GetIsolate();
13019 2974665 : Handle<String> function_name = Name::ToFunctionName(name).ToHandleChecked();
13020 1487333 : if (prefix->length() > 0) {
13021 3480 : IncrementalStringBuilder builder(isolate);
13022 3480 : builder.AppendString(prefix);
13023 : builder.AppendCharacter(' ');
13024 3480 : builder.AppendString(function_name);
13025 6960 : function_name = builder.Finish().ToHandleChecked();
13026 : }
13027 : JSObject::DefinePropertyOrElementIgnoreAttributes(
13028 : function, isolate->factory()->name_string(), function_name,
13029 : static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY))
13030 2974665 : .ToHandleChecked();
13031 1487332 : }
13032 :
13033 : namespace {
13034 :
13035 : char const kNativeCodeSource[] = "function () { [native code] }";
13036 :
13037 :
13038 1552727 : Handle<String> NativeCodeFunctionSourceString(
13039 : Handle<SharedFunctionInfo> shared_info) {
13040 : Isolate* const isolate = shared_info->GetIsolate();
13041 1552727 : if (shared_info->name()->IsString()) {
13042 1552727 : IncrementalStringBuilder builder(isolate);
13043 : builder.AppendCString("function ");
13044 1552727 : builder.AppendString(handle(String::cast(shared_info->name()), isolate));
13045 : builder.AppendCString("() { [native code] }");
13046 3105454 : return builder.Finish().ToHandleChecked();
13047 : }
13048 0 : return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource);
13049 : }
13050 :
13051 : } // namespace
13052 :
13053 :
13054 : // static
13055 81 : Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) {
13056 : Isolate* const isolate = function->GetIsolate();
13057 81 : return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource);
13058 : }
13059 :
13060 :
13061 : // static
13062 2636894 : Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
13063 : Isolate* const isolate = function->GetIsolate();
13064 : Handle<SharedFunctionInfo> shared_info(function->shared(), isolate);
13065 :
13066 : // Check if {function} should hide its source code.
13067 2636894 : if (!shared_info->IsUserJavaScript()) {
13068 1552727 : return NativeCodeFunctionSourceString(shared_info);
13069 : }
13070 :
13071 : // Check if we should print {function} as a class.
13072 : Handle<Object> class_start_position = JSReceiver::GetDataProperty(
13073 1084167 : function, isolate->factory()->class_start_position_symbol());
13074 1084167 : if (class_start_position->IsSmi()) {
13075 : Handle<Object> class_end_position = JSReceiver::GetDataProperty(
13076 33811 : function, isolate->factory()->class_end_position_symbol());
13077 : Handle<String> script_source(
13078 : String::cast(Script::cast(shared_info->script())->source()), isolate);
13079 : return isolate->factory()->NewSubString(
13080 : script_source, Handle<Smi>::cast(class_start_position)->value(),
13081 33811 : Handle<Smi>::cast(class_end_position)->value());
13082 : }
13083 :
13084 : // Check if we have source code for the {function}.
13085 1050356 : if (!shared_info->HasSourceCode()) {
13086 0 : return NativeCodeFunctionSourceString(shared_info);
13087 : }
13088 :
13089 1050356 : if (FLAG_harmony_function_tostring) {
13090 1260 : return Handle<String>::cast(shared_info->GetSourceCodeHarmony());
13091 : }
13092 :
13093 1049096 : IncrementalStringBuilder builder(isolate);
13094 : FunctionKind kind = shared_info->kind();
13095 1049096 : if (!IsArrowFunction(kind)) {
13096 1043685 : if (IsConciseMethod(kind)) {
13097 98 : if (IsAsyncGeneratorFunction(kind)) {
13098 : builder.AppendCString("async *");
13099 56 : } else if (IsGeneratorFunction(kind)) {
13100 : builder.AppendCharacter('*');
13101 42 : } else if (IsAsyncFunction(kind)) {
13102 : builder.AppendCString("async ");
13103 : }
13104 : } else {
13105 1043587 : if (IsAsyncGeneratorFunction(kind)) {
13106 : builder.AppendCString("async function* ");
13107 1043517 : } else if (IsGeneratorFunction(kind)) {
13108 : builder.AppendCString("function* ");
13109 1043323 : } else if (IsAsyncFunction(kind)) {
13110 : builder.AppendCString("async function ");
13111 : } else {
13112 : builder.AppendCString("function ");
13113 : }
13114 : }
13115 1043685 : if (shared_info->name_should_print_as_anonymous()) {
13116 : builder.AppendCString("anonymous");
13117 1043123 : } else if (!shared_info->is_anonymous_expression()) {
13118 939165 : builder.AppendString(handle(String::cast(shared_info->name()), isolate));
13119 : }
13120 : }
13121 1049096 : builder.AppendString(Handle<String>::cast(shared_info->GetSourceCode()));
13122 2098192 : return builder.Finish().ToHandleChecked();
13123 : }
13124 :
13125 473 : void Oddball::Initialize(Isolate* isolate, Handle<Oddball> oddball,
13126 : const char* to_string, Handle<Object> to_number,
13127 : const char* type_of, byte kind) {
13128 : Handle<String> internalized_to_string =
13129 473 : isolate->factory()->InternalizeUtf8String(to_string);
13130 : Handle<String> internalized_type_of =
13131 473 : isolate->factory()->InternalizeUtf8String(type_of);
13132 473 : if (to_number->IsHeapNumber()) {
13133 : oddball->set_to_number_raw_as_bits(
13134 : Handle<HeapNumber>::cast(to_number)->value_as_bits());
13135 : } else {
13136 : oddball->set_to_number_raw(to_number->Number());
13137 : }
13138 473 : oddball->set_to_number(*to_number);
13139 473 : oddball->set_to_string(*internalized_to_string);
13140 473 : oddball->set_type_of(*internalized_type_of);
13141 : oddball->set_kind(kind);
13142 473 : }
13143 :
13144 1294349 : void Script::SetEvalOrigin(Handle<Script> script,
13145 : Handle<SharedFunctionInfo> outer_info,
13146 : int eval_position) {
13147 1294349 : if (eval_position == kNoSourcePosition) {
13148 : // If the position is missing, attempt to get the code offset from the
13149 : // current activation. Do not translate the code offset into source
13150 : // position, but store it as negative value for lazy translation.
13151 477387 : StackTraceFrameIterator it(script->GetIsolate());
13152 954697 : if (!it.done() && it.is_javascript()) {
13153 477310 : FrameSummary summary = FrameSummary::GetTop(it.javascript_frame());
13154 477310 : script->set_eval_from_shared(summary.AsJavaScript().function()->shared());
13155 477310 : script->set_eval_from_position(-summary.code_offset());
13156 1771659 : return;
13157 : }
13158 : eval_position = 0;
13159 : }
13160 817039 : script->set_eval_from_shared(*outer_info);
13161 : script->set_eval_from_position(eval_position);
13162 : }
13163 :
13164 12476 : int Script::GetEvalPosition() {
13165 : DisallowHeapAllocation no_gc;
13166 : DCHECK(compilation_type() == Script::COMPILATION_TYPE_EVAL);
13167 : int position = eval_from_position();
13168 12476 : if (position < 0) {
13169 : // Due to laziness, the position may not have been translated from code
13170 : // offset yet, which would be encoded as negative integer. In that case,
13171 : // translate and set the position.
13172 1105 : if (eval_from_shared()->IsUndefined(GetIsolate())) {
13173 : position = 0;
13174 : } else {
13175 : SharedFunctionInfo* shared = SharedFunctionInfo::cast(eval_from_shared());
13176 2210 : position = shared->abstract_code()->SourcePosition(-position);
13177 : }
13178 : DCHECK(position >= 0);
13179 : set_eval_from_position(position);
13180 : }
13181 12476 : return position;
13182 : }
13183 :
13184 1672105 : void Script::InitLineEnds(Handle<Script> script) {
13185 : Isolate* isolate = script->GetIsolate();
13186 3344210 : if (!script->line_ends()->IsUndefined(isolate)) return;
13187 : DCHECK_NE(Script::TYPE_WASM, script->type());
13188 :
13189 : Object* src_obj = script->source();
13190 63131 : if (!src_obj->IsString()) {
13191 : DCHECK(src_obj->IsUndefined(isolate));
13192 14 : script->set_line_ends(isolate->heap()->empty_fixed_array());
13193 : } else {
13194 : DCHECK(src_obj->IsString());
13195 : Handle<String> src(String::cast(src_obj), isolate);
13196 63124 : Handle<FixedArray> array = String::CalculateLineEnds(src, true);
13197 63124 : script->set_line_ends(*array);
13198 : }
13199 :
13200 : DCHECK(script->line_ends()->IsFixedArray());
13201 : }
13202 :
13203 1385921 : bool Script::GetPositionInfo(Handle<Script> script, int position,
13204 : PositionInfo* info, OffsetFlag offset_flag) {
13205 : // For wasm, we do not create an artificial line_ends array, but do the
13206 : // translation directly.
13207 1385921 : if (script->type() != Script::TYPE_WASM) InitLineEnds(script);
13208 1385921 : return script->GetPositionInfo(position, info, offset_flag);
13209 : }
13210 :
13211 54620317 : bool Script::IsUserJavaScript() { return type() == Script::TYPE_NORMAL; }
13212 :
13213 : namespace {
13214 1791 : bool GetPositionInfoSlow(const Script* script, int position,
13215 : Script::PositionInfo* info) {
13216 1791 : if (!script->source()->IsString()) return false;
13217 1791 : if (position < 0) position = 0;
13218 :
13219 : String* source_string = String::cast(script->source());
13220 : int line = 0;
13221 : int line_start = 0;
13222 : int len = source_string->length();
13223 539845 : for (int pos = 0; pos <= len; ++pos) {
13224 1079590 : if (pos == len || source_string->Get(pos) == '\n') {
13225 22152 : if (position <= pos) {
13226 1779 : info->line = line;
13227 1779 : info->column = position - line_start;
13228 1779 : info->line_start = line_start;
13229 1779 : info->line_end = pos;
13230 1779 : return true;
13231 : }
13232 20373 : line++;
13233 20373 : line_start = pos + 1;
13234 : }
13235 : }
13236 : return false;
13237 : }
13238 : } // namespace
13239 :
13240 : #define SMI_VALUE(x) (Smi::cast(x)->value())
13241 1443019 : bool Script::GetPositionInfo(int position, PositionInfo* info,
13242 : OffsetFlag offset_flag) const {
13243 : DisallowHeapAllocation no_allocation;
13244 :
13245 : // For wasm, we do not rely on the line_ends array, but do the translation
13246 : // directly.
13247 1443019 : if (type() == Script::TYPE_WASM) {
13248 : Handle<WasmCompiledModule> compiled_module(
13249 : WasmCompiledModule::cast(wasm_compiled_module()));
13250 : DCHECK_LE(0, position);
13251 : return compiled_module->GetPositionInfo(static_cast<uint32_t>(position),
13252 1036 : info);
13253 : }
13254 :
13255 1442501 : if (line_ends()->IsUndefined(GetIsolate())) {
13256 : // Slow mode: we do not have line_ends. We have to iterate through source.
13257 1791 : if (!GetPositionInfoSlow(this, position, info)) return false;
13258 : } else {
13259 : DCHECK(line_ends()->IsFixedArray());
13260 : FixedArray* ends = FixedArray::cast(line_ends());
13261 :
13262 : const int ends_len = ends->length();
13263 1440710 : if (ends_len == 0) return false;
13264 :
13265 : // Return early on invalid positions. Negative positions behave as if 0 was
13266 : // passed, and positions beyond the end of the script return as failure.
13267 1440689 : if (position < 0) {
13268 : position = 0;
13269 2880374 : } else if (position > SMI_VALUE(ends->get(ends_len - 1))) {
13270 : return false;
13271 : }
13272 :
13273 : // Determine line number by doing a binary search on the line ends array.
13274 1440663 : if (SMI_VALUE(ends->get(0)) >= position) {
13275 199002 : info->line = 0;
13276 199002 : info->line_start = 0;
13277 199002 : info->column = position;
13278 : } else {
13279 : int left = 0;
13280 1241661 : int right = ends_len - 1;
13281 :
13282 8767256 : while (right > 0) {
13283 : DCHECK_LE(left, right);
13284 7525595 : const int mid = (left + right) / 2;
13285 7525595 : if (position > SMI_VALUE(ends->get(mid))) {
13286 3844270 : left = mid + 1;
13287 7362650 : } else if (position <= SMI_VALUE(ends->get(mid - 1))) {
13288 : right = mid - 1;
13289 : } else {
13290 1241661 : info->line = mid;
13291 1241661 : break;
13292 : }
13293 : }
13294 : DCHECK(SMI_VALUE(ends->get(info->line)) >= position &&
13295 : SMI_VALUE(ends->get(info->line - 1)) < position);
13296 2483322 : info->line_start = SMI_VALUE(ends->get(info->line - 1)) + 1;
13297 1241661 : info->column = position - info->line_start;
13298 : }
13299 :
13300 : // Line end is position of the linebreak character.
13301 2881326 : info->line_end = SMI_VALUE(ends->get(info->line));
13302 1440663 : if (info->line_end > 0) {
13303 : DCHECK(source()->IsString());
13304 : String* src = String::cast(source());
13305 2880850 : if (src->length() >= info->line_end &&
13306 1440425 : src->Get(info->line_end - 1) == '\r') {
13307 0 : info->line_end--;
13308 : }
13309 : }
13310 : }
13311 :
13312 : // Add offsets if requested.
13313 1442442 : if (offset_flag == WITH_OFFSET) {
13314 1218318 : if (info->line == 0) {
13315 163662 : info->column += column_offset();
13316 : }
13317 1218318 : info->line += line_offset();
13318 : }
13319 :
13320 : return true;
13321 : }
13322 : #undef SMI_VALUE
13323 :
13324 203270 : int Script::GetColumnNumber(Handle<Script> script, int code_pos) {
13325 : PositionInfo info;
13326 203270 : GetPositionInfo(script, code_pos, &info, WITH_OFFSET);
13327 203270 : return info.column;
13328 : }
13329 :
13330 0 : int Script::GetColumnNumber(int code_pos) const {
13331 : PositionInfo info;
13332 0 : GetPositionInfo(code_pos, &info, WITH_OFFSET);
13333 0 : return info.column;
13334 : }
13335 :
13336 210501 : int Script::GetLineNumber(Handle<Script> script, int code_pos) {
13337 : PositionInfo info;
13338 210501 : GetPositionInfo(script, code_pos, &info, WITH_OFFSET);
13339 210501 : return info.line;
13340 : }
13341 :
13342 56978 : int Script::GetLineNumber(int code_pos) const {
13343 : PositionInfo info;
13344 56978 : GetPositionInfo(code_pos, &info, WITH_OFFSET);
13345 56978 : return info.line;
13346 : }
13347 :
13348 49078 : Object* Script::GetNameOrSourceURL() {
13349 : Isolate* isolate = GetIsolate();
13350 : // Keep in sync with ScriptNameOrSourceURL in messages.js.
13351 51247 : if (!source_url()->IsUndefined(isolate)) return source_url();
13352 46909 : return name();
13353 : }
13354 :
13355 :
13356 2036127 : Handle<JSObject> Script::GetWrapper(Handle<Script> script) {
13357 629356 : Isolate* isolate = script->GetIsolate();
13358 2036127 : if (!script->wrapper()->IsUndefined(isolate)) {
13359 : DCHECK(script->wrapper()->IsWeakCell());
13360 : Handle<WeakCell> cell(WeakCell::cast(script->wrapper()));
13361 1545187 : if (!cell->cleared()) {
13362 : // Return a handle for the existing script wrapper from the cache.
13363 : return handle(JSObject::cast(cell->value()));
13364 : }
13365 : // If we found an empty WeakCell, that means the script wrapper was
13366 : // GCed. We are not notified directly of that, so we decrement here
13367 : // so that we at least don't count double for any given script.
13368 69208 : isolate->counters()->script_wrappers()->Decrement();
13369 : }
13370 : // Construct a new script wrapper.
13371 560148 : isolate->counters()->script_wrappers()->Increment();
13372 560148 : Handle<JSFunction> constructor = isolate->script_function();
13373 : Handle<JSValue> result =
13374 560148 : Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
13375 560148 : result->set_value(*script);
13376 560148 : Handle<WeakCell> cell = isolate->factory()->NewWeakCell(result);
13377 560148 : script->set_wrapper(*cell);
13378 560148 : return result;
13379 : }
13380 :
13381 5863424 : MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
13382 5863424 : Isolate* isolate, const FunctionLiteral* fun) {
13383 : DCHECK_NE(fun->function_literal_id(), FunctionLiteral::kIdTypeInvalid);
13384 : DCHECK_LT(fun->function_literal_id(), shared_function_infos()->length());
13385 : Object* shared = shared_function_infos()->get(fun->function_literal_id());
13386 6837322 : if (shared->IsUndefined(isolate) || WeakCell::cast(shared)->cleared()) {
13387 : return MaybeHandle<SharedFunctionInfo>();
13388 : }
13389 : return handle(SharedFunctionInfo::cast(WeakCell::cast(shared)->value()));
13390 : }
13391 :
13392 212457 : Script::Iterator::Iterator(Isolate* isolate)
13393 436611 : : iterator_(isolate->heap()->script_list()) {}
13394 :
13395 :
13396 6114413 : Script* Script::Iterator::Next() { return iterator_.Next<Script>(); }
13397 :
13398 42 : bool Script::HasPreparsedScopeData() const {
13399 42 : return preparsed_scope_data()->length() > 0;
13400 : }
13401 :
13402 90460 : SharedFunctionInfo::ScriptIterator::ScriptIterator(Handle<Script> script)
13403 : : ScriptIterator(script->GetIsolate(),
13404 90460 : handle(script->shared_function_infos())) {}
13405 :
13406 642 : SharedFunctionInfo::ScriptIterator::ScriptIterator(
13407 : Isolate* isolate, Handle<FixedArray> shared_function_infos)
13408 : : isolate_(isolate),
13409 : shared_function_infos_(shared_function_infos),
13410 91102 : index_(0) {}
13411 :
13412 11827619 : SharedFunctionInfo* SharedFunctionInfo::ScriptIterator::Next() {
13413 39415009 : while (index_ < shared_function_infos_->length()) {
13414 13344251 : Object* raw = shared_function_infos_->get(index_++);
13415 38419159 : if (raw->IsUndefined(isolate_) || WeakCell::cast(raw)->cleared()) continue;
13416 11378175 : return SharedFunctionInfo::cast(WeakCell::cast(raw)->value());
13417 : }
13418 : return nullptr;
13419 : }
13420 :
13421 358357 : void SharedFunctionInfo::ScriptIterator::Reset(Handle<Script> script) {
13422 358357 : shared_function_infos_ = handle(script->shared_function_infos());
13423 358357 : index_ = 0;
13424 358357 : }
13425 :
13426 11697 : SharedFunctionInfo::GlobalIterator::GlobalIterator(Isolate* isolate)
13427 : : script_iterator_(isolate),
13428 : noscript_sfi_iterator_(isolate->heap()->noscript_shared_function_infos()),
13429 23394 : sfi_iterator_(handle(script_iterator_.Next(), isolate)) {}
13430 :
13431 16574437 : SharedFunctionInfo* SharedFunctionInfo::GlobalIterator::Next() {
13432 16574437 : SharedFunctionInfo* next = noscript_sfi_iterator_.Next<SharedFunctionInfo>();
13433 16574437 : if (next != nullptr) return next;
13434 : for (;;) {
13435 10658592 : next = sfi_iterator_.Next();
13436 10658592 : if (next != nullptr) return next;
13437 : Script* next_script = script_iterator_.Next();
13438 370054 : if (next_script == nullptr) return nullptr;
13439 358357 : sfi_iterator_.Reset(handle(next_script));
13440 358357 : }
13441 : }
13442 :
13443 :
13444 6241439 : void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
13445 : Handle<Object> script_object) {
13446 : DCHECK_NE(shared->function_literal_id(), FunctionLiteral::kIdTypeInvalid);
13447 12482884 : if (shared->script() == *script_object) return;
13448 : Isolate* isolate = shared->GetIsolate();
13449 :
13450 : // Add shared function info to new script's list. If a collection occurs,
13451 : // the shared function info may be temporarily in two lists.
13452 : // This is okay because the gc-time processing of these lists can tolerate
13453 : // duplicates.
13454 6241445 : if (script_object->IsScript()) {
13455 : Handle<Script> script = Handle<Script>::cast(script_object);
13456 : Handle<FixedArray> list = handle(script->shared_function_infos(), isolate);
13457 : #ifdef DEBUG
13458 : DCHECK_LT(shared->function_literal_id(), list->length());
13459 : if (list->get(shared->function_literal_id())->IsWeakCell() &&
13460 : !WeakCell::cast(list->get(shared->function_literal_id()))->cleared()) {
13461 : DCHECK(
13462 : WeakCell::cast(list->get(shared->function_literal_id()))->value() ==
13463 : *shared);
13464 : }
13465 : #endif
13466 6234904 : Handle<WeakCell> cell = isolate->factory()->NewWeakCell(shared);
13467 6234906 : list->set(shared->function_literal_id(), *cell);
13468 : } else {
13469 : Handle<Object> list = isolate->factory()->noscript_shared_function_infos();
13470 :
13471 : #ifdef DEBUG
13472 : if (FLAG_enable_slow_asserts) {
13473 : WeakFixedArray::Iterator iterator(*list);
13474 : SharedFunctionInfo* next;
13475 : while ((next = iterator.Next<SharedFunctionInfo>()) != nullptr) {
13476 : DCHECK_NE(next, *shared);
13477 : }
13478 : }
13479 : #endif // DEBUG
13480 :
13481 6539 : list = WeakFixedArray::Add(list, shared);
13482 :
13483 : isolate->heap()->SetRootNoScriptSharedFunctionInfos(*list);
13484 : }
13485 :
13486 6241446 : if (shared->script()->IsScript()) {
13487 : // Remove shared function info from old script's list.
13488 : Script* old_script = Script::cast(shared->script());
13489 :
13490 : // Due to liveedit, it might happen that the old_script doesn't know
13491 : // about the SharedFunctionInfo, so we have to guard against that.
13492 : Handle<FixedArray> infos(old_script->shared_function_infos(), isolate);
13493 6571 : if (shared->function_literal_id() < infos->length()) {
13494 : Object* raw = old_script->shared_function_infos()->get(
13495 : shared->function_literal_id());
13496 13080 : if (!raw->IsWeakCell() || WeakCell::cast(raw)->value() == *shared) {
13497 : old_script->shared_function_infos()->set(
13498 3450 : shared->function_literal_id(), isolate->heap()->undefined_value());
13499 : }
13500 : }
13501 : } else {
13502 : // Remove shared function info from root array.
13503 6234875 : Object* list = isolate->heap()->noscript_shared_function_infos();
13504 6234875 : CHECK(WeakFixedArray::cast(list)->Remove(shared));
13505 : }
13506 :
13507 : // Finally set new script.
13508 6241445 : shared->set_script(*script_object);
13509 : }
13510 :
13511 :
13512 3096797 : String* SharedFunctionInfo::DebugName() {
13513 : Object* n = name();
13514 6193593 : if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
13515 : return String::cast(n);
13516 : }
13517 :
13518 14088 : bool SharedFunctionInfo::HasNoSideEffect() {
13519 14088 : if (!computed_has_no_side_effect()) {
13520 : DisallowHeapAllocation not_handlified;
13521 : Handle<SharedFunctionInfo> info(this);
13522 11074 : set_has_no_side_effect(DebugEvaluate::FunctionHasNoSideEffect(info));
13523 11074 : set_computed_has_no_side_effect(true);
13524 : }
13525 14088 : return has_no_side_effect();
13526 : }
13527 :
13528 : // The filter is a pattern that matches function names in this way:
13529 : // "*" all; the default
13530 : // "-" all but the top-level function
13531 : // "-name" all but the function "name"
13532 : // "" only the top-level function
13533 : // "name" only the function "name"
13534 : // "name*" only functions starting with "name"
13535 : // "~" none; the tilde is not an identifier
13536 4003381 : bool SharedFunctionInfo::PassesFilter(const char* raw_filter) {
13537 4003381 : if (*raw_filter == '*') return true;
13538 1507706 : String* name = DebugName();
13539 1507704 : Vector<const char> filter = CStrVector(raw_filter);
13540 1507704 : if (filter.length() == 0) return name->length() == 0;
13541 1507704 : if (filter[0] == '-') {
13542 : // Negative filter.
13543 0 : if (filter.length() == 1) {
13544 0 : return (name->length() != 0);
13545 0 : } else if (name->IsUtf8EqualTo(filter.SubVector(1, filter.length()))) {
13546 : return false;
13547 : }
13548 0 : if (filter[filter.length() - 1] == '*' &&
13549 0 : name->IsUtf8EqualTo(filter.SubVector(1, filter.length() - 1), true)) {
13550 : return false;
13551 : }
13552 0 : return true;
13553 :
13554 1507704 : } else if (name->IsUtf8EqualTo(filter)) {
13555 : return true;
13556 : }
13557 3014835 : if (filter[filter.length() - 1] == '*' &&
13558 125 : name->IsUtf8EqualTo(filter.SubVector(0, filter.length() - 1), true)) {
13559 : return true;
13560 : }
13561 1507282 : return false;
13562 : }
13563 :
13564 14230898 : bool SharedFunctionInfo::HasSourceCode() const {
13565 : Isolate* isolate = GetIsolate();
13566 28461789 : return !script()->IsUndefined(isolate) &&
13567 14230898 : !reinterpret_cast<Script*>(script())->source()->IsUndefined(isolate);
13568 : }
13569 :
13570 :
13571 1049488 : Handle<Object> SharedFunctionInfo::GetSourceCode() {
13572 1049488 : if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value();
13573 : Handle<String> source(String::cast(Script::cast(script())->source()));
13574 : return GetIsolate()->factory()->NewSubString(
13575 1049488 : source, start_position(), end_position());
13576 : }
13577 :
13578 1260 : Handle<Object> SharedFunctionInfo::GetSourceCodeHarmony() {
13579 : Isolate* isolate = GetIsolate();
13580 1260 : if (!HasSourceCode()) return isolate->factory()->undefined_value();
13581 : Handle<String> script_source(String::cast(Script::cast(script())->source()));
13582 : int start_pos = function_token_position();
13583 1260 : if (start_pos == kNoSourcePosition) start_pos = start_position();
13584 : return isolate->factory()->NewSubString(script_source, start_pos,
13585 1260 : end_position());
13586 : }
13587 :
13588 180256 : bool SharedFunctionInfo::IsInlineable() {
13589 : // Check that the function has a script associated with it.
13590 180256 : if (!script()->IsScript()) return false;
13591 180268 : if (GetIsolate()->is_precise_binary_code_coverage() &&
13592 : !has_reported_binary_coverage()) {
13593 : // We may miss invocations if this function is inlined.
13594 : return false;
13595 : }
13596 180256 : return !optimization_disabled();
13597 : }
13598 :
13599 151597 : int SharedFunctionInfo::SourceSize() {
13600 151597 : return end_position() - start_position();
13601 : }
13602 :
13603 709484 : void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type,
13604 : int requested_embedder_fields,
13605 : int requested_in_object_properties,
13606 : int* instance_size,
13607 : int* in_object_properties) {
13608 709484 : int header_size = JSObject::GetHeaderSize(instance_type);
13609 : DCHECK_LE(requested_embedder_fields,
13610 : (JSObject::kMaxInstanceSize - header_size) >> kPointerSizeLog2);
13611 : *instance_size =
13612 : Min(header_size +
13613 709484 : ((requested_embedder_fields + requested_in_object_properties)
13614 709484 : << kPointerSizeLog2),
13615 1418968 : JSObject::kMaxInstanceSize);
13616 709484 : *in_object_properties = ((*instance_size - header_size) >> kPointerSizeLog2) -
13617 709484 : requested_embedder_fields;
13618 709484 : }
13619 :
13620 9044 : void JSFunction::CalculateInstanceSizeForDerivedClass(
13621 : Handle<JSFunction> function, InstanceType instance_type,
13622 : int requested_embedder_fields, int* instance_size,
13623 : int* in_object_properties) {
13624 : Isolate* isolate = function->GetIsolate();
13625 : int expected_nof_properties = 0;
13626 37792 : for (PrototypeIterator iter(isolate, function, kStartAtReceiver);
13627 19704 : !iter.IsAtEnd(); iter.Advance()) {
13628 : Handle<JSReceiver> current =
13629 : PrototypeIterator::GetCurrent<JSReceiver>(iter);
13630 28748 : if (!current->IsJSFunction()) break;
13631 : Handle<JSFunction> func(Handle<JSFunction>::cast(current));
13632 : // The super constructor should be compiled for the number of expected
13633 : // properties to be available.
13634 : Handle<SharedFunctionInfo> shared(func->shared());
13635 29028 : if (shared->is_compiled() ||
13636 295 : Compiler::Compile(func, Compiler::CLEAR_EXCEPTION)) {
13637 : DCHECK(shared->is_compiled());
13638 28733 : expected_nof_properties += shared->expected_nof_properties();
13639 : }
13640 28733 : if (!IsDerivedConstructor(shared->kind())) {
13641 : break;
13642 : }
13643 : }
13644 : CalculateInstanceSizeHelper(instance_type, requested_embedder_fields,
13645 : expected_nof_properties, instance_size,
13646 9044 : in_object_properties);
13647 9044 : }
13648 :
13649 :
13650 : // Output the source code without any allocation in the heap.
13651 21 : std::ostream& operator<<(std::ostream& os, const SourceCodeOf& v) {
13652 21 : const SharedFunctionInfo* s = v.value;
13653 : // For some native functions there is no source.
13654 21 : if (!s->HasSourceCode()) return os << "<No Source>";
13655 :
13656 : // Get the source for the script which this function came from.
13657 : // Don't use String::cast because we don't want more assertion errors while
13658 : // we are already creating a stack dump.
13659 : String* script_source =
13660 : reinterpret_cast<String*>(Script::cast(s->script())->source());
13661 :
13662 14 : if (!script_source->LooksValid()) return os << "<Invalid Source>";
13663 :
13664 14 : if (!s->is_toplevel()) {
13665 14 : os << "function ";
13666 : Object* name = s->name();
13667 28 : if (name->IsString() && String::cast(name)->length() > 0) {
13668 14 : String::cast(name)->PrintUC16(os);
13669 : }
13670 : }
13671 :
13672 14 : int len = s->end_position() - s->start_position();
13673 14 : if (len <= v.max_length || v.max_length < 0) {
13674 14 : script_source->PrintUC16(os, s->start_position(), s->end_position());
13675 14 : return os;
13676 : } else {
13677 : script_source->PrintUC16(os, s->start_position(),
13678 0 : s->start_position() + v.max_length);
13679 0 : return os << "...\n";
13680 : }
13681 : }
13682 :
13683 :
13684 231562 : static bool IsCodeEquivalent(Code* code, Code* recompiled) {
13685 231562 : if (code->instruction_size() != recompiled->instruction_size()) return false;
13686 : ByteArray* code_relocation = code->relocation_info();
13687 : ByteArray* recompiled_relocation = recompiled->relocation_info();
13688 : int length = code_relocation->length();
13689 228494 : if (length != recompiled_relocation->length()) return false;
13690 228494 : int compare = memcmp(code_relocation->GetDataStartAddress(),
13691 228494 : recompiled_relocation->GetDataStartAddress(),
13692 456988 : length);
13693 228494 : return compare == 0;
13694 : }
13695 :
13696 :
13697 231562 : void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
13698 : DCHECK(!has_deoptimization_support());
13699 : DisallowHeapAllocation no_allocation;
13700 : Code* code = this->code();
13701 231562 : if (IsCodeEquivalent(code, recompiled)) {
13702 : // Copy the deoptimization data from the recompiled code.
13703 228494 : code->set_deoptimization_data(recompiled->deoptimization_data());
13704 : code->set_has_deoptimization_support(true);
13705 : } else {
13706 : // TODO(3025757): In case the recompiled isn't equivalent to the
13707 : // old code, we have to replace it. We should try to avoid this
13708 : // altogether because it flushes valuable type feedback by
13709 : // effectively resetting all IC state.
13710 3069 : ReplaceCode(recompiled);
13711 : }
13712 : DCHECK(has_deoptimization_support());
13713 231563 : }
13714 :
13715 :
13716 57082 : void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
13717 : // Disable optimization for the shared function info and mark the
13718 : // code as non-optimizable. The marker on the shared function info
13719 : // is there because we flush non-optimized code thereby loosing the
13720 : // non-optimizable information for the code. When the code is
13721 : // regenerated and set on the shared function info it is marked as
13722 : // non-optimizable if optimization is disabled for the shared
13723 : // function info.
13724 : DCHECK(reason != kNoReason);
13725 : set_optimization_disabled(true);
13726 : set_disable_optimization_reason(reason);
13727 : // Code should be the lazy compilation stub or else unoptimized.
13728 : DCHECK(abstract_code()->kind() == AbstractCode::FUNCTION ||
13729 : abstract_code()->kind() == AbstractCode::INTERPRETED_FUNCTION ||
13730 : abstract_code()->kind() == AbstractCode::BUILTIN);
13731 57082 : PROFILE(GetIsolate(), CodeDisableOptEvent(abstract_code(), this));
13732 57082 : if (FLAG_trace_opt) {
13733 0 : PrintF("[disabled optimization for ");
13734 0 : ShortPrint();
13735 0 : PrintF(", reason: %s]\n", GetBailoutReason(reason));
13736 : }
13737 57082 : }
13738 :
13739 6231069 : void SharedFunctionInfo::InitFromFunctionLiteral(
13740 54574301 : Handle<SharedFunctionInfo> shared_info, FunctionLiteral* lit) {
13741 : // When adding fields here, make sure DeclarationScope::AnalyzePartially is
13742 : // updated accordingly.
13743 : shared_info->set_internal_formal_parameter_count(lit->parameter_count());
13744 : shared_info->set_function_token_position(lit->function_token_position());
13745 6231069 : shared_info->set_start_position(lit->start_position());
13746 6231074 : shared_info->set_end_position(lit->end_position());
13747 : shared_info->set_is_declaration(lit->is_declaration());
13748 : shared_info->set_is_named_expression(lit->is_named_expression());
13749 6231074 : shared_info->set_is_anonymous_expression(lit->is_anonymous_expression());
13750 12462146 : shared_info->set_inferred_name(*lit->inferred_name());
13751 6231074 : shared_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
13752 6231072 : shared_info->set_language_mode(lit->language_mode());
13753 6231071 : shared_info->set_uses_arguments(lit->scope()->arguments() != NULL);
13754 6231071 : shared_info->set_kind(lit->kind());
13755 6231075 : if (!IsConstructable(lit->kind())) {
13756 : shared_info->SetConstructStub(
13757 934062 : *shared_info->GetIsolate()->builtins()->ConstructedNonConstructable());
13758 : }
13759 6231072 : shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
13760 : shared_info->set_asm_function(lit->scope()->asm_function());
13761 : shared_info->set_function_literal_id(lit->function_literal_id());
13762 :
13763 : // For lazy parsed functions, the following flags will be inaccurate since we
13764 : // don't have the information yet. They're set later in
13765 : // SetSharedFunctionFlagsFromLiteral (compiler.cc), when the function is
13766 : // really parsed and compiled.
13767 6231074 : if (lit->body() != nullptr) {
13768 : shared_info->set_length(lit->function_length());
13769 : shared_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
13770 : shared_info->SetExpectedNofPropertiesFromEstimate(lit);
13771 : } else {
13772 : // Set an invalid length for lazy functions. This way we can set the correct
13773 : // value after compiling, but avoid overwriting values set manually by the
13774 : // bootstrapper.
13775 : shared_info->set_length(SharedFunctionInfo::kInvalidLength);
13776 : }
13777 6231074 : }
13778 :
13779 3339060 : void SharedFunctionInfo::SetExpectedNofPropertiesFromEstimate(
13780 8817459 : FunctionLiteral* literal) {
13781 : int estimate = literal->expected_property_count();
13782 :
13783 : // If no properties are added in the constructor, they are more likely
13784 : // to be added later.
13785 8817459 : if (estimate == 0) estimate = 2;
13786 :
13787 : // Inobject slack tracking will reclaim redundant inobject space later,
13788 : // so we can afford to adjust the estimate generously.
13789 8817459 : estimate += 8;
13790 :
13791 : set_expected_nof_properties(estimate);
13792 3339060 : }
13793 :
13794 0 : bool SharedFunctionInfo::VerifyBailoutId(BailoutId id) {
13795 : DCHECK(!id.IsNone());
13796 : Code* unoptimized = code();
13797 : DeoptimizationOutputData* data =
13798 : DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
13799 0 : unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
13800 : USE(ignore);
13801 0 : return true; // Return true if there was no DCHECK.
13802 : }
13803 :
13804 14896380 : void SharedFunctionInfo::SetConstructStub(Code* code) {
13805 14896380 : if (code->kind() == Code::BUILTIN) code->set_is_construct_stub(true);
13806 14896380 : set_construct_stub(code);
13807 14896385 : }
13808 :
13809 0 : void Map::StartInobjectSlackTracking() {
13810 : DCHECK(!IsInobjectSlackTrackingInProgress());
13811 498842 : if (unused_property_fields() == 0) return;
13812 : set_construction_counter(Map::kSlackTrackingCounterStart);
13813 : }
13814 :
13815 :
13816 4501247 : void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
13817 4501247 : code()->ClearInlineCaches();
13818 : set_ic_age(new_ic_age);
13819 4501251 : if (code()->kind() == Code::FUNCTION) {
13820 : code()->set_profiler_ticks(0);
13821 9672 : if (optimization_disabled() && deopt_count() >= FLAG_max_deopt_count) {
13822 : // Re-enable optimizations if they were disabled due to deopt_count limit.
13823 : set_optimization_disabled(false);
13824 : }
13825 : set_opt_count(0);
13826 : set_deopt_count(0);
13827 4491675 : } else if (IsInterpreted()) {
13828 : set_profiler_ticks(0);
13829 28198 : if (optimization_disabled() && deopt_count() >= FLAG_max_deopt_count) {
13830 : // Re-enable optimizations if they were disabled due to deopt_count limit.
13831 : set_optimization_disabled(false);
13832 : }
13833 : set_opt_count(0);
13834 : set_deopt_count(0);
13835 : }
13836 4501243 : }
13837 :
13838 27975351 : int SharedFunctionInfo::SearchOptimizedCodeMapEntry(Context* native_context) {
13839 : DisallowHeapAllocation no_gc;
13840 : DCHECK(native_context->IsNativeContext());
13841 27975351 : if (!OptimizedCodeMapIsCleared()) {
13842 : FixedArray* optimized_code_map = this->optimized_code_map();
13843 : int length = optimized_code_map->length();
13844 1913256 : for (int i = kEntriesStart; i < length; i += kEntryLength) {
13845 1656207 : if (WeakCell::cast(optimized_code_map->get(i + kContextOffset))
13846 : ->value() == native_context) {
13847 : return i;
13848 : }
13849 : }
13850 : }
13851 : return -1;
13852 : }
13853 :
13854 16557760 : void SharedFunctionInfo::ClearCodeFromOptimizedCodeMap() {
13855 16557760 : if (!OptimizedCodeMapIsCleared()) {
13856 : FixedArray* optimized_code_map = this->optimized_code_map();
13857 : int length = optimized_code_map->length();
13858 126459 : WeakCell* empty_weak_cell = GetHeap()->empty_weak_cell();
13859 254079 : for (int i = kEntriesStart; i < length; i += kEntryLength) {
13860 : optimized_code_map->set(i + kCachedCodeOffset, empty_weak_cell,
13861 127620 : SKIP_WRITE_BARRIER);
13862 : }
13863 : }
13864 16557760 : }
13865 :
13866 27942515 : Code* SharedFunctionInfo::SearchOptimizedCodeMap(Context* native_context,
13867 : BailoutId osr_ast_id) {
13868 : Code* result = nullptr;
13869 27942515 : if (!osr_ast_id.IsNone()) {
13870 8475 : return native_context->SearchOptimizedCodeMap(this, osr_ast_id);
13871 : }
13872 :
13873 : DCHECK(osr_ast_id.IsNone());
13874 27934040 : int entry = SearchOptimizedCodeMapEntry(native_context);
13875 27934039 : if (entry != kNotFound) {
13876 : FixedArray* code_map = optimized_code_map();
13877 : DCHECK_LE(entry + kEntryLength, code_map->length());
13878 915837 : WeakCell* cell = WeakCell::cast(code_map->get(entry + kCachedCodeOffset));
13879 915837 : result = cell->cleared() ? nullptr : Code::cast(cell->value());
13880 : }
13881 27934039 : return result;
13882 : }
13883 :
13884 14306879 : void ObjectVisitor::VisitCodeTarget(Code* host, RelocInfo* rinfo) {
13885 : DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode()));
13886 14306879 : Object* old_pointer = Code::GetCodeFromTargetAddress(rinfo->target_address());
13887 14306879 : Object* new_pointer = old_pointer;
13888 14306879 : VisitPointer(host, &new_pointer);
13889 : DCHECK_EQ(old_pointer, new_pointer);
13890 14306879 : }
13891 :
13892 0 : void ObjectVisitor::VisitCodeAgeSequence(Code* host, RelocInfo* rinfo) {
13893 : DCHECK(RelocInfo::IsCodeAgeSequence(rinfo->rmode()));
13894 : Object* old_pointer = rinfo->code_age_stub();
13895 0 : Object* new_pointer = old_pointer;
13896 0 : if (old_pointer != nullptr) {
13897 0 : VisitPointer(host, &new_pointer);
13898 : DCHECK_EQ(old_pointer, new_pointer);
13899 : }
13900 0 : }
13901 :
13902 2925048 : void ObjectVisitor::VisitCodeEntry(JSFunction* host, Address entry_address) {
13903 2925048 : Object* old_pointer = Code::GetObjectFromEntryAddress(entry_address);
13904 2925048 : Object* new_pointer = old_pointer;
13905 2925048 : VisitPointer(host, &new_pointer);
13906 : DCHECK_EQ(old_pointer, new_pointer);
13907 2925048 : }
13908 :
13909 3364 : void ObjectVisitor::VisitCellPointer(Code* host, RelocInfo* rinfo) {
13910 : DCHECK(rinfo->rmode() == RelocInfo::CELL);
13911 : Object* old_pointer = rinfo->target_cell();
13912 3364 : Object* new_pointer = old_pointer;
13913 3364 : VisitPointer(host, &new_pointer);
13914 : DCHECK_EQ(old_pointer, new_pointer);
13915 3364 : }
13916 :
13917 12 : void ObjectVisitor::VisitDebugTarget(Code* host, RelocInfo* rinfo) {
13918 : DCHECK(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
13919 : rinfo->IsPatchedDebugBreakSlotSequence());
13920 : Object* old_pointer =
13921 12 : Code::GetCodeFromTargetAddress(rinfo->debug_call_address());
13922 12 : Object* new_pointer = old_pointer;
13923 12 : VisitPointer(host, &new_pointer);
13924 : DCHECK_EQ(old_pointer, new_pointer);
13925 12 : }
13926 :
13927 2082470 : void ObjectVisitor::VisitEmbeddedPointer(Code* host, RelocInfo* rinfo) {
13928 : DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
13929 : Object* old_pointer = rinfo->target_object();
13930 2082470 : Object* new_pointer = old_pointer;
13931 2082470 : VisitPointer(host, &new_pointer);
13932 : DCHECK_EQ(old_pointer, new_pointer);
13933 2082470 : }
13934 :
13935 :
13936 413300 : void Code::InvalidateRelocation() {
13937 413300 : InvalidateEmbeddedObjects();
13938 413300 : set_relocation_info(GetHeap()->empty_byte_array());
13939 413300 : }
13940 :
13941 :
13942 418597 : void Code::InvalidateEmbeddedObjects() {
13943 418597 : HeapObject* undefined = GetHeap()->undefined_value();
13944 418597 : Cell* undefined_cell = GetHeap()->undefined_cell();
13945 : int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
13946 : RelocInfo::ModeMask(RelocInfo::CELL);
13947 4910502 : for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
13948 4491905 : RelocInfo::Mode mode = it.rinfo()->rmode();
13949 4491905 : if (mode == RelocInfo::EMBEDDED_OBJECT) {
13950 : it.rinfo()->set_target_object(undefined, SKIP_WRITE_BARRIER);
13951 0 : } else if (mode == RelocInfo::CELL) {
13952 : it.rinfo()->set_target_cell(undefined_cell, SKIP_WRITE_BARRIER);
13953 : }
13954 : }
13955 418597 : }
13956 :
13957 :
13958 182981 : void Code::Relocate(intptr_t delta) {
13959 191358 : if (trap_handler::UseTrapHandler() && is_wasm_code()) {
13960 : const int index = trap_handler_index()->value();
13961 2299 : if (index >= 0) {
13962 42 : trap_handler::UpdateHandlerDataCodePointer(index, instruction_start());
13963 : }
13964 : }
13965 700767 : for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
13966 : it.rinfo()->apply(delta);
13967 : }
13968 365962 : Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size());
13969 182981 : }
13970 :
13971 :
13972 2554076 : void Code::CopyFrom(const CodeDesc& desc) {
13973 : // copy code
13974 : CopyBytes(instruction_start(), desc.buffer,
13975 2554076 : static_cast<size_t>(desc.instr_size));
13976 :
13977 : // copy unwinding info, if any
13978 2554070 : if (desc.unwinding_info) {
13979 : DCHECK_GT(desc.unwinding_info_size, 0);
13980 25 : set_unwinding_info_size(desc.unwinding_info_size);
13981 : CopyBytes(unwinding_info_start(), desc.unwinding_info,
13982 25 : static_cast<size_t>(desc.unwinding_info_size));
13983 : }
13984 :
13985 : // copy reloc info
13986 : CopyBytes(relocation_start(),
13987 2554070 : desc.buffer + desc.buffer_size - desc.reloc_size,
13988 7662210 : static_cast<size_t>(desc.reloc_size));
13989 :
13990 : // unbox handles and relocate
13991 2554076 : intptr_t delta = instruction_start() - desc.buffer;
13992 : int mode_mask = RelocInfo::kCodeTargetMask |
13993 : RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
13994 : RelocInfo::ModeMask(RelocInfo::CELL) |
13995 2554076 : RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
13996 2554076 : RelocInfo::kApplyMask;
13997 : // Needed to find target_object and runtime_entry on X64
13998 2554076 : Assembler* origin = desc.origin;
13999 : AllowDeferredHandleDereference embedding_raw_address;
14000 37638241 : for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
14001 35084122 : RelocInfo::Mode mode = it.rinfo()->rmode();
14002 35084122 : if (mode == RelocInfo::EMBEDDED_OBJECT) {
14003 16181444 : Handle<HeapObject> p = it.rinfo()->target_object_handle(origin);
14004 : it.rinfo()->set_target_object(*p, UPDATE_WRITE_BARRIER,
14005 : SKIP_ICACHE_FLUSH);
14006 18902678 : } else if (mode == RelocInfo::CELL) {
14007 38640 : Handle<Cell> cell = it.rinfo()->target_cell_handle();
14008 : it.rinfo()->set_target_cell(*cell, UPDATE_WRITE_BARRIER,
14009 : SKIP_ICACHE_FLUSH);
14010 18864038 : } else if (RelocInfo::IsCodeTarget(mode)) {
14011 : // rewrite code handles in inline cache targets to direct
14012 : // pointers to the first instruction in the code object
14013 17863285 : Handle<Object> p = it.rinfo()->target_object_handle(origin);
14014 : Code* code = Code::cast(*p);
14015 : it.rinfo()->set_target_address(GetIsolate(), code->instruction_start(),
14016 35726580 : UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
14017 1000753 : } else if (RelocInfo::IsRuntimeEntry(mode)) {
14018 887221 : Address p = it.rinfo()->target_runtime_entry(origin);
14019 : it.rinfo()->set_target_runtime_entry(
14020 : GetIsolate(), p, UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
14021 113532 : } else if (mode == RelocInfo::CODE_AGE_SEQUENCE) {
14022 14 : Handle<Object> p = it.rinfo()->code_age_stub_handle(origin);
14023 : Code* code = Code::cast(*p);
14024 14 : it.rinfo()->set_code_age_stub(code, SKIP_ICACHE_FLUSH);
14025 : } else {
14026 : it.rinfo()->apply(delta);
14027 : }
14028 : }
14029 5108172 : Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size());
14030 2554085 : }
14031 :
14032 :
14033 1736619 : SafepointEntry Code::GetSafepointEntry(Address pc) {
14034 1736619 : SafepointTable table(this);
14035 1736619 : return table.FindEntry(pc);
14036 : }
14037 :
14038 :
14039 833470 : Object* Code::FindNthObject(int n, Map* match_map) {
14040 : DCHECK(is_inline_cache_stub());
14041 : DisallowHeapAllocation no_allocation;
14042 : int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
14043 1329965 : for (RelocIterator it(this, mask); !it.done(); it.next()) {
14044 572114 : RelocInfo* info = it.rinfo();
14045 : Object* object = info->target_object();
14046 572114 : if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
14047 572114 : if (object->IsHeapObject()) {
14048 572114 : if (HeapObject::cast(object)->map() == match_map) {
14049 75619 : if (--n == 0) return object;
14050 : }
14051 : }
14052 : }
14053 757850 : return NULL;
14054 : }
14055 :
14056 :
14057 386655 : AllocationSite* Code::FindFirstAllocationSite() {
14058 386655 : Object* result = FindNthObject(1, GetHeap()->allocation_site_map());
14059 386655 : return (result != NULL) ? AllocationSite::cast(result) : NULL;
14060 : }
14061 :
14062 :
14063 446815 : Map* Code::FindFirstMap() {
14064 446815 : Object* result = FindNthObject(1, GetHeap()->meta_map());
14065 446814 : return (result != NULL) ? Map::cast(result) : NULL;
14066 : }
14067 :
14068 :
14069 46790 : void Code::FindAndReplace(const FindAndReplacePattern& pattern) {
14070 : DCHECK(is_inline_cache_stub() || is_handler());
14071 : DisallowHeapAllocation no_allocation;
14072 : int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
14073 : STATIC_ASSERT(FindAndReplacePattern::kMaxCount < 32);
14074 : int current_pattern = 0;
14075 46790 : for (RelocIterator it(this, mask); !it.done(); it.next()) {
14076 46790 : RelocInfo* info = it.rinfo();
14077 : HeapObject* object = info->target_object();
14078 46790 : if (object->IsWeakCell()) {
14079 : object = HeapObject::cast(WeakCell::cast(object)->value());
14080 : }
14081 : Map* map = object->map();
14082 93580 : if (map == *pattern.find_[current_pattern]) {
14083 46790 : info->set_target_object(*pattern.replace_[current_pattern]);
14084 93580 : if (++current_pattern == pattern.count_) return;
14085 : }
14086 : }
14087 0 : UNREACHABLE();
14088 : }
14089 :
14090 :
14091 4535327 : void Code::ClearInlineCaches() {
14092 : int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
14093 : RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
14094 19728284 : for (RelocIterator it(this, mask); !it.done(); it.next()) {
14095 15192936 : RelocInfo* info = it.rinfo();
14096 : Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
14097 15192957 : if (target->is_inline_cache_stub()) {
14098 : ICUtility::Clear(this->GetIsolate(), info->pc(),
14099 132284 : info->host()->constant_pool());
14100 : }
14101 : }
14102 4535332 : }
14103 :
14104 : namespace {
14105 : template <typename Code>
14106 9579 : void SetStackFrameCacheCommon(Handle<Code> code,
14107 : Handle<UnseededNumberDictionary> cache) {
14108 : Handle<Object> maybe_table(code->source_position_table(), code->GetIsolate());
14109 9579 : if (maybe_table->IsSourcePositionTableWithFrameCache()) {
14110 638 : Handle<SourcePositionTableWithFrameCache>::cast(maybe_table)
14111 : ->set_stack_frame_cache(*cache);
14112 10217 : return;
14113 : }
14114 : DCHECK(maybe_table->IsByteArray());
14115 8941 : Handle<ByteArray> table(Handle<ByteArray>::cast(maybe_table));
14116 : Handle<SourcePositionTableWithFrameCache> table_with_cache =
14117 : code->GetIsolate()->factory()->NewSourcePositionTableWithFrameCache(
14118 8941 : table, cache);
14119 8941 : code->set_source_position_table(*table_with_cache);
14120 : }
14121 : } // namespace
14122 :
14123 : // static
14124 9579 : void AbstractCode::SetStackFrameCache(Handle<AbstractCode> abstract_code,
14125 : Handle<UnseededNumberDictionary> cache) {
14126 9579 : if (abstract_code->IsCode()) {
14127 2902 : SetStackFrameCacheCommon(handle(abstract_code->GetCode()), cache);
14128 : } else {
14129 6677 : SetStackFrameCacheCommon(handle(abstract_code->GetBytecodeArray()), cache);
14130 : }
14131 9579 : }
14132 :
14133 : namespace {
14134 : template <typename Code>
14135 8945708 : void DropStackFrameCacheCommon(Code* code) {
14136 : i::Object* maybe_table = code->source_position_table();
14137 17891416 : if (maybe_table->IsByteArray()) return;
14138 : DCHECK(maybe_table->IsSourcePositionTableWithFrameCache());
14139 0 : code->set_source_position_table(
14140 : i::SourcePositionTableWithFrameCache::cast(maybe_table)
14141 : ->source_position_table());
14142 : }
14143 : } // namespace
14144 :
14145 8945708 : void AbstractCode::DropStackFrameCache() {
14146 8945708 : if (IsCode()) {
14147 8935385 : DropStackFrameCacheCommon(GetCode());
14148 : } else {
14149 10323 : DropStackFrameCacheCommon(GetBytecodeArray());
14150 : }
14151 8945708 : }
14152 :
14153 2060741 : int AbstractCode::SourcePosition(int offset) {
14154 : int position = 0;
14155 : // Subtract one because the current PC is one instruction after the call site.
14156 2060741 : if (IsCode()) offset--;
14157 68749268 : for (SourcePositionTableIterator iterator(source_position_table());
14158 66688527 : !iterator.done() && iterator.code_offset() <= offset;
14159 64627786 : iterator.Advance()) {
14160 64627786 : position = iterator.source_position().ScriptOffset();
14161 : }
14162 2060741 : return position;
14163 : }
14164 :
14165 155350 : int AbstractCode::SourceStatementPosition(int offset) {
14166 : // First find the closest position.
14167 155350 : int position = SourcePosition(offset);
14168 : // Now find the closest statement position before the position.
14169 : int statement_position = 0;
14170 25647559 : for (SourcePositionTableIterator it(source_position_table()); !it.done();
14171 25336859 : it.Advance()) {
14172 25336859 : if (it.is_statement()) {
14173 10861866 : int p = it.source_position().ScriptOffset();
14174 10861866 : if (statement_position < p && p <= position) {
14175 : statement_position = p;
14176 : }
14177 : }
14178 : }
14179 155350 : return statement_position;
14180 : }
14181 :
14182 240567 : void JSFunction::ClearTypeFeedbackInfo() {
14183 240567 : if (feedback_vector_cell()->value()->IsFeedbackVector()) {
14184 : FeedbackVector* vector = feedback_vector();
14185 91974 : vector->ClearSlots(this);
14186 : }
14187 240567 : }
14188 :
14189 2639 : BailoutId Code::TranslatePcOffsetToAstId(uint32_t pc_offset) {
14190 : DisallowHeapAllocation no_gc;
14191 : DCHECK(kind() == FUNCTION);
14192 : BackEdgeTable back_edges(this, &no_gc);
14193 3626 : for (uint32_t i = 0; i < back_edges.length(); i++) {
14194 3626 : if (back_edges.pc_offset(i) == pc_offset) return back_edges.ast_id(i);
14195 : }
14196 : return BailoutId::None();
14197 : }
14198 :
14199 :
14200 0 : uint32_t Code::TranslateAstIdToPcOffset(BailoutId ast_id) {
14201 : DisallowHeapAllocation no_gc;
14202 : DCHECK(kind() == FUNCTION);
14203 : BackEdgeTable back_edges(this, &no_gc);
14204 0 : for (uint32_t i = 0; i < back_edges.length(); i++) {
14205 0 : if (back_edges.ast_id(i) == ast_id) return back_edges.pc_offset(i);
14206 : }
14207 0 : UNREACHABLE(); // We expect to find the back edge.
14208 : return 0;
14209 : }
14210 :
14211 653325 : void Code::MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate) {
14212 653681 : PatchPlatformCodeAge(isolate, sequence, kNoAgeCodeAge);
14213 653325 : }
14214 :
14215 :
14216 15 : void Code::MarkCodeAsExecuted(byte* sequence, Isolate* isolate) {
14217 15 : PatchPlatformCodeAge(isolate, sequence, kExecutedOnceCodeAge);
14218 15 : }
14219 :
14220 :
14221 : // NextAge defines the Code::Age state transitions during a GC cycle.
14222 : static Code::Age NextAge(Code::Age age) {
14223 1181541 : switch (age) {
14224 : case Code::kNotExecutedCodeAge: // Keep, until we've been executed.
14225 : case Code::kToBeExecutedOnceCodeAge: // Keep, until we've been executed.
14226 : case Code::kLastCodeAge: // Clamp at last Code::Age value.
14227 : return age;
14228 : case Code::kExecutedOnceCodeAge:
14229 : // Pre-age code that has only been executed once.
14230 : return static_cast<Code::Age>(Code::kPreAgedCodeAge + 1);
14231 : default:
14232 1012993 : return static_cast<Code::Age>(age + 1); // Default case: Increase age.
14233 : }
14234 : }
14235 :
14236 :
14237 : // IsOldAge defines the collection criteria for a Code object.
14238 : static bool IsOldAge(Code::Age age) {
14239 14057727 : return age >= Code::kIsOldCodeAge || age == Code::kNotExecutedCodeAge;
14240 : }
14241 :
14242 :
14243 199319 : void Code::MakeYoung(Isolate* isolate) {
14244 199319 : byte* sequence = FindCodeAgeSequence();
14245 199319 : if (sequence != NULL) MakeCodeAgeSequenceYoung(sequence, isolate);
14246 199319 : }
14247 :
14248 6 : void Code::PreAge(Isolate* isolate) {
14249 6 : byte* sequence = FindCodeAgeSequence();
14250 6 : if (sequence != NULL) {
14251 6 : PatchPlatformCodeAge(isolate, sequence, kPreAgedCodeAge);
14252 : }
14253 6 : }
14254 :
14255 48 : void Code::MarkToBeExecutedOnce(Isolate* isolate) {
14256 48 : byte* sequence = FindCodeAgeSequence();
14257 48 : if (sequence != NULL) {
14258 12 : PatchPlatformCodeAge(isolate, sequence, kToBeExecutedOnceCodeAge);
14259 : }
14260 48 : }
14261 :
14262 74555257 : void Code::MakeOlder() {
14263 74555257 : byte* sequence = FindCodeAgeSequence();
14264 74555264 : if (sequence != NULL) {
14265 : Isolate* isolate = GetIsolate();
14266 1181541 : Age age = GetCodeAge(isolate, sequence);
14267 : Age next_age = NextAge(age);
14268 1181541 : if (age != next_age) {
14269 1013001 : PatchPlatformCodeAge(isolate, sequence, next_age);
14270 : }
14271 : }
14272 74555264 : }
14273 :
14274 :
14275 13874565 : bool Code::IsOld() {
14276 27932292 : return IsOldAge(GetAge());
14277 : }
14278 :
14279 :
14280 177649251 : byte* Code::FindCodeAgeSequence() {
14281 177649275 : return FLAG_age_code &&
14282 112941671 : prologue_offset() != Code::kPrologueOffsetNotSet &&
14283 110657856 : (kind() == OPTIMIZED_FUNCTION ||
14284 4530313 : (kind() == FUNCTION && !has_debug_break_slots()))
14285 6301183 : ? instruction_start() + prologue_offset()
14286 183950434 : : NULL;
14287 : }
14288 :
14289 :
14290 14057733 : Code::Age Code::GetAge() {
14291 14057733 : byte* sequence = FindCodeAgeSequence();
14292 14057733 : if (sequence == NULL) {
14293 : return kNoAgeCodeAge;
14294 : }
14295 640788 : return GetCodeAge(GetIsolate(), sequence);
14296 : }
14297 :
14298 625322 : Code::Age Code::GetAgeOfCodeAgeStub(Code* code) {
14299 : Isolate* isolate = code->GetIsolate();
14300 625322 : Builtins* builtins = isolate->builtins();
14301 : #define HANDLE_CODE_AGE(AGE) \
14302 : if (code == *builtins->Make##AGE##CodeYoungAgain()) { \
14303 : return k##AGE##CodeAge; \
14304 : }
14305 2288301 : CODE_AGE_LIST(HANDLE_CODE_AGE)
14306 : #undef HANDLE_CODE_AGE
14307 98 : if (code == *builtins->MarkCodeAsExecutedOnce()) {
14308 : return kNotExecutedCodeAge;
14309 : }
14310 74 : if (code == *builtins->MarkCodeAsExecutedTwice()) {
14311 : return kExecutedOnceCodeAge;
14312 : }
14313 52 : if (code == *builtins->MarkCodeAsToBeExecutedOnce()) {
14314 : return kToBeExecutedOnceCodeAge;
14315 : }
14316 0 : UNREACHABLE();
14317 : return kNoAgeCodeAge;
14318 : }
14319 :
14320 1013034 : Code* Code::GetCodeAgeStub(Isolate* isolate, Age age) {
14321 1013034 : Builtins* builtins = isolate->builtins();
14322 1013034 : switch (age) {
14323 : #define HANDLE_CODE_AGE(AGE) \
14324 : case k##AGE##CodeAge: { \
14325 : return *builtins->Make##AGE##CodeYoungAgain(); \
14326 : }
14327 1797379 : CODE_AGE_LIST(HANDLE_CODE_AGE)
14328 : #undef HANDLE_CODE_AGE
14329 : case kNotExecutedCodeAge: {
14330 0 : return *builtins->MarkCodeAsExecutedOnce();
14331 : }
14332 : case kExecutedOnceCodeAge: {
14333 30 : return *builtins->MarkCodeAsExecutedTwice();
14334 : }
14335 : case kToBeExecutedOnceCodeAge: {
14336 24 : return *builtins->MarkCodeAsToBeExecutedOnce();
14337 : }
14338 : default:
14339 0 : UNREACHABLE();
14340 : break;
14341 : }
14342 : return NULL;
14343 : }
14344 :
14345 :
14346 0 : void Code::PrintDeoptLocation(FILE* out, Address pc) {
14347 0 : Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(this, pc);
14348 0 : class SourcePosition pos = info.position;
14349 0 : if (info.deopt_reason != DeoptimizeReason::kNoReason || pos.IsKnown()) {
14350 0 : if (FLAG_hydrogen_track_positions) {
14351 : PrintF(out, " ;;; deoptimize at %d_%d: %s\n", pos.InliningId(),
14352 0 : pos.ScriptOffset(), DeoptimizeReasonToString(info.deopt_reason));
14353 : } else {
14354 0 : PrintF(out, " ;;; deoptimize at ");
14355 0 : OFStream outstr(out);
14356 0 : pos.Print(outstr, this);
14357 0 : PrintF(out, ", %s\n", DeoptimizeReasonToString(info.deopt_reason));
14358 : }
14359 : }
14360 0 : }
14361 :
14362 :
14363 5320 : bool Code::CanDeoptAt(Address pc) {
14364 : DeoptimizationInputData* deopt_data =
14365 : DeoptimizationInputData::cast(deoptimization_data());
14366 5320 : Address code_start_address = instruction_start();
14367 190192 : for (int i = 0; i < deopt_data->DeoptCount(); i++) {
14368 188306 : if (deopt_data->Pc(i)->value() == -1) continue;
14369 126452 : Address address = code_start_address + deopt_data->Pc(i)->value();
14370 67605 : if (address == pc && deopt_data->AstId(i) != BailoutId::None()) {
14371 : return true;
14372 : }
14373 : }
14374 : return false;
14375 : }
14376 :
14377 :
14378 : // Identify kind of code.
14379 29547 : const char* Code::Kind2String(Kind kind) {
14380 29547 : switch (kind) {
14381 : #define CASE(name) case name: return #name;
14382 0 : CODE_KIND_LIST(CASE)
14383 : #undef CASE
14384 : case NUMBER_OF_KINDS: break;
14385 : }
14386 0 : UNREACHABLE();
14387 : return NULL;
14388 : }
14389 :
14390 : // Identify kind of code.
14391 0 : const char* AbstractCode::Kind2String(Kind kind) {
14392 0 : if (kind < AbstractCode::INTERPRETED_FUNCTION)
14393 0 : return Code::Kind2String((Code::Kind)kind);
14394 0 : if (kind == AbstractCode::INTERPRETED_FUNCTION) return "INTERPRETED_FUNCTION";
14395 0 : UNREACHABLE();
14396 : return NULL;
14397 : }
14398 :
14399 2556480 : Handle<WeakCell> Code::WeakCellFor(Handle<Code> code) {
14400 : DCHECK(code->kind() == OPTIMIZED_FUNCTION);
14401 2556480 : WeakCell* raw_cell = code->CachedWeakCell();
14402 4779300 : if (raw_cell != NULL) return Handle<WeakCell>(raw_cell);
14403 333667 : Handle<WeakCell> cell = code->GetIsolate()->factory()->NewWeakCell(code);
14404 : DeoptimizationInputData::cast(code->deoptimization_data())
14405 : ->SetWeakCellCache(*cell);
14406 333667 : return cell;
14407 : }
14408 :
14409 :
14410 2556480 : WeakCell* Code::CachedWeakCell() {
14411 : DCHECK(kind() == OPTIMIZED_FUNCTION);
14412 : Object* weak_cell_cache =
14413 : DeoptimizationInputData::cast(deoptimization_data())->WeakCellCache();
14414 2556482 : if (weak_cell_cache->IsWeakCell()) {
14415 : DCHECK(this == WeakCell::cast(weak_cell_cache)->value());
14416 2222816 : return WeakCell::cast(weak_cell_cache);
14417 : }
14418 : return NULL;
14419 : }
14420 :
14421 : #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
14422 :
14423 : const char* Code::ICState2String(InlineCacheState state) {
14424 : switch (state) {
14425 : case UNINITIALIZED:
14426 : return "UNINITIALIZED";
14427 : case PREMONOMORPHIC:
14428 : return "PREMONOMORPHIC";
14429 : case MONOMORPHIC:
14430 : return "MONOMORPHIC";
14431 : case RECOMPUTE_HANDLER:
14432 : return "RECOMPUTE_HANDLER";
14433 : case POLYMORPHIC:
14434 : return "POLYMORPHIC";
14435 : case MEGAMORPHIC:
14436 : return "MEGAMORPHIC";
14437 : case GENERIC:
14438 : return "GENERIC";
14439 : }
14440 : UNREACHABLE();
14441 : return NULL;
14442 : }
14443 :
14444 : void Code::PrintExtraICState(std::ostream& os, // NOLINT
14445 : Kind kind, ExtraICState extra) {
14446 : os << "extra_ic_state = ";
14447 : if ((kind == STORE_IC || kind == KEYED_STORE_IC) &&
14448 : is_strict(static_cast<LanguageMode>(extra))) {
14449 : os << "STRICT\n";
14450 : } else {
14451 : os << extra << "\n";
14452 : }
14453 : }
14454 :
14455 : #endif // defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
14456 :
14457 : #ifdef ENABLE_DISASSEMBLER
14458 :
14459 : void DeoptimizationInputData::DeoptimizationInputDataPrint(
14460 : std::ostream& os) { // NOLINT
14461 : disasm::NameConverter converter;
14462 : int const inlined_function_count = InlinedFunctionCount()->value();
14463 : os << "Inlined functions (count = " << inlined_function_count << ")\n";
14464 : for (int id = 0; id < inlined_function_count; ++id) {
14465 : Object* info = LiteralArray()->get(id);
14466 : os << " " << Brief(SharedFunctionInfo::cast(info)) << "\n";
14467 : }
14468 : os << "\n";
14469 : int deopt_count = DeoptCount();
14470 : os << "Deoptimization Input Data (deopt points = " << deopt_count << ")\n";
14471 : if (0 != deopt_count) {
14472 : os << " index ast id argc pc";
14473 : if (FLAG_print_code_verbose) os << " commands";
14474 : os << "\n";
14475 : }
14476 : for (int i = 0; i < deopt_count; i++) {
14477 : os << std::setw(6) << i << " " << std::setw(6) << AstId(i).ToInt() << " "
14478 : << std::setw(6) << ArgumentsStackHeight(i)->value() << " "
14479 : << std::setw(6) << Pc(i)->value();
14480 :
14481 : if (!FLAG_print_code_verbose) {
14482 : os << "\n";
14483 : continue;
14484 : }
14485 : // Print details of the frame translation.
14486 : int translation_index = TranslationIndex(i)->value();
14487 : TranslationIterator iterator(TranslationByteArray(), translation_index);
14488 : Translation::Opcode opcode =
14489 : static_cast<Translation::Opcode>(iterator.Next());
14490 : DCHECK(Translation::BEGIN == opcode);
14491 : int frame_count = iterator.Next();
14492 : int jsframe_count = iterator.Next();
14493 : os << " " << Translation::StringFor(opcode)
14494 : << " {frame count=" << frame_count
14495 : << ", js frame count=" << jsframe_count << "}\n";
14496 :
14497 : while (iterator.HasNext() &&
14498 : Translation::BEGIN !=
14499 : (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
14500 : os << std::setw(31) << " " << Translation::StringFor(opcode) << " ";
14501 :
14502 : switch (opcode) {
14503 : case Translation::BEGIN:
14504 : UNREACHABLE();
14505 : break;
14506 :
14507 : case Translation::JS_FRAME: {
14508 : int ast_id = iterator.Next();
14509 : int shared_info_id = iterator.Next();
14510 : unsigned height = iterator.Next();
14511 : Object* shared_info = LiteralArray()->get(shared_info_id);
14512 : os << "{ast_id=" << ast_id << ", function="
14513 : << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14514 : << ", height=" << height << "}";
14515 : break;
14516 : }
14517 :
14518 : case Translation::INTERPRETED_FRAME: {
14519 : int bytecode_offset = iterator.Next();
14520 : int shared_info_id = iterator.Next();
14521 : unsigned height = iterator.Next();
14522 : Object* shared_info = LiteralArray()->get(shared_info_id);
14523 : os << "{bytecode_offset=" << bytecode_offset << ", function="
14524 : << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14525 : << ", height=" << height << "}";
14526 : break;
14527 : }
14528 :
14529 : case Translation::CONSTRUCT_STUB_FRAME: {
14530 : int bailout_id = iterator.Next();
14531 : int shared_info_id = iterator.Next();
14532 : Object* shared_info = LiteralArray()->get(shared_info_id);
14533 : unsigned height = iterator.Next();
14534 : os << "{bailout_id=" << bailout_id << ", function="
14535 : << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14536 : << ", height=" << height << "}";
14537 : break;
14538 : }
14539 :
14540 : case Translation::COMPILED_STUB_FRAME: {
14541 : Code::Kind stub_kind = static_cast<Code::Kind>(iterator.Next());
14542 : os << "{kind=" << stub_kind << "}";
14543 : break;
14544 : }
14545 :
14546 : case Translation::ARGUMENTS_ADAPTOR_FRAME: {
14547 : int shared_info_id = iterator.Next();
14548 : Object* shared_info = LiteralArray()->get(shared_info_id);
14549 : unsigned height = iterator.Next();
14550 : os << "{function="
14551 : << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14552 : << ", height=" << height << "}";
14553 : break;
14554 : }
14555 :
14556 : case Translation::TAIL_CALLER_FRAME: {
14557 : int shared_info_id = iterator.Next();
14558 : Object* shared_info = LiteralArray()->get(shared_info_id);
14559 : os << "{function="
14560 : << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14561 : << "}";
14562 : break;
14563 : }
14564 :
14565 : case Translation::GETTER_STUB_FRAME:
14566 : case Translation::SETTER_STUB_FRAME: {
14567 : int shared_info_id = iterator.Next();
14568 : Object* shared_info = LiteralArray()->get(shared_info_id);
14569 : os << "{function=" << Brief(SharedFunctionInfo::cast(shared_info)
14570 : ->DebugName()) << "}";
14571 : break;
14572 : }
14573 :
14574 : case Translation::REGISTER: {
14575 : int reg_code = iterator.Next();
14576 : os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
14577 : break;
14578 : }
14579 :
14580 : case Translation::INT32_REGISTER: {
14581 : int reg_code = iterator.Next();
14582 : os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
14583 : break;
14584 : }
14585 :
14586 : case Translation::UINT32_REGISTER: {
14587 : int reg_code = iterator.Next();
14588 : os << "{input=" << converter.NameOfCPURegister(reg_code)
14589 : << " (unsigned)}";
14590 : break;
14591 : }
14592 :
14593 : case Translation::BOOL_REGISTER: {
14594 : int reg_code = iterator.Next();
14595 : os << "{input=" << converter.NameOfCPURegister(reg_code)
14596 : << " (bool)}";
14597 : break;
14598 : }
14599 :
14600 : case Translation::FLOAT_REGISTER: {
14601 : int reg_code = iterator.Next();
14602 : os << "{input="
14603 : << RegisterConfiguration::Crankshaft()->GetFloatRegisterName(
14604 : reg_code)
14605 : << "}";
14606 : break;
14607 : }
14608 :
14609 : case Translation::DOUBLE_REGISTER: {
14610 : int reg_code = iterator.Next();
14611 : os << "{input="
14612 : << RegisterConfiguration::Crankshaft()->GetDoubleRegisterName(
14613 : reg_code)
14614 : << "}";
14615 : break;
14616 : }
14617 :
14618 : case Translation::STACK_SLOT: {
14619 : int input_slot_index = iterator.Next();
14620 : os << "{input=" << input_slot_index << "}";
14621 : break;
14622 : }
14623 :
14624 : case Translation::INT32_STACK_SLOT: {
14625 : int input_slot_index = iterator.Next();
14626 : os << "{input=" << input_slot_index << "}";
14627 : break;
14628 : }
14629 :
14630 : case Translation::UINT32_STACK_SLOT: {
14631 : int input_slot_index = iterator.Next();
14632 : os << "{input=" << input_slot_index << " (unsigned)}";
14633 : break;
14634 : }
14635 :
14636 : case Translation::BOOL_STACK_SLOT: {
14637 : int input_slot_index = iterator.Next();
14638 : os << "{input=" << input_slot_index << " (bool)}";
14639 : break;
14640 : }
14641 :
14642 : case Translation::FLOAT_STACK_SLOT:
14643 : case Translation::DOUBLE_STACK_SLOT: {
14644 : int input_slot_index = iterator.Next();
14645 : os << "{input=" << input_slot_index << "}";
14646 : break;
14647 : }
14648 :
14649 : case Translation::LITERAL: {
14650 : int literal_index = iterator.Next();
14651 : Object* literal_value = LiteralArray()->get(literal_index);
14652 : os << "{literal_id=" << literal_index << " (" << Brief(literal_value)
14653 : << ")}";
14654 : break;
14655 : }
14656 :
14657 : case Translation::DUPLICATED_OBJECT: {
14658 : int object_index = iterator.Next();
14659 : os << "{object_index=" << object_index << "}";
14660 : break;
14661 : }
14662 :
14663 : case Translation::ARGUMENTS_ELEMENTS:
14664 : case Translation::ARGUMENTS_LENGTH: {
14665 : bool is_rest = iterator.Next();
14666 : os << "{is_rest=" << (is_rest ? "true" : "false") << "}";
14667 : break;
14668 : }
14669 :
14670 : case Translation::ARGUMENTS_OBJECT:
14671 : case Translation::CAPTURED_OBJECT: {
14672 : int args_length = iterator.Next();
14673 : os << "{length=" << args_length << "}";
14674 : break;
14675 : }
14676 : }
14677 : os << "\n";
14678 : }
14679 : }
14680 : }
14681 :
14682 :
14683 : void DeoptimizationOutputData::DeoptimizationOutputDataPrint(
14684 : std::ostream& os) { // NOLINT
14685 : os << "Deoptimization Output Data (deopt points = " << this->DeoptPoints()
14686 : << ")\n";
14687 : if (this->DeoptPoints() == 0) return;
14688 :
14689 : os << "ast id pc state\n";
14690 : for (int i = 0; i < this->DeoptPoints(); i++) {
14691 : int pc_and_state = this->PcAndState(i)->value();
14692 : os << std::setw(6) << this->AstId(i).ToInt() << " " << std::setw(8)
14693 : << FullCodeGenerator::PcField::decode(pc_and_state) << " "
14694 : << Deoptimizer::BailoutStateToString(
14695 : FullCodeGenerator::BailoutStateField::decode(pc_and_state))
14696 : << "\n";
14697 : }
14698 : }
14699 :
14700 :
14701 : void HandlerTable::HandlerTableRangePrint(std::ostream& os) {
14702 : os << " from to hdlr\n";
14703 : for (int i = 0; i < length(); i += kRangeEntrySize) {
14704 : int pc_start = Smi::cast(get(i + kRangeStartIndex))->value();
14705 : int pc_end = Smi::cast(get(i + kRangeEndIndex))->value();
14706 : int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value();
14707 : int handler_offset = HandlerOffsetField::decode(handler_field);
14708 : CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
14709 : int data = Smi::cast(get(i + kRangeDataIndex))->value();
14710 : os << " (" << std::setw(4) << pc_start << "," << std::setw(4) << pc_end
14711 : << ") -> " << std::setw(4) << handler_offset
14712 : << " (prediction=" << prediction << ", data=" << data << ")\n";
14713 : }
14714 : }
14715 :
14716 :
14717 : void HandlerTable::HandlerTableReturnPrint(std::ostream& os) {
14718 : os << " off hdlr (c)\n";
14719 : for (int i = 0; i < length(); i += kReturnEntrySize) {
14720 : int pc_offset = Smi::cast(get(i + kReturnOffsetIndex))->value();
14721 : int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value();
14722 : int handler_offset = HandlerOffsetField::decode(handler_field);
14723 : CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
14724 : os << " " << std::setw(4) << pc_offset << " -> " << std::setw(4)
14725 : << handler_offset << " (prediction=" << prediction << ")\n";
14726 : }
14727 : }
14728 :
14729 :
14730 : void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT
14731 : os << "kind = " << Kind2String(kind()) << "\n";
14732 : if (IsCodeStubOrIC()) {
14733 : const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this));
14734 : os << "major_key = " << (n == NULL ? "null" : n) << "\n";
14735 : }
14736 : if (is_inline_cache_stub()) {
14737 : if (is_compare_ic_stub() || is_to_boolean_ic_stub() ||
14738 : is_binary_op_stub()) {
14739 : InlineCacheState ic_state = IC::StateFromCode(this);
14740 : os << "ic_state = " << ICState2String(ic_state) << "\n";
14741 : PrintExtraICState(os, kind(), extra_ic_state());
14742 : }
14743 : if (is_compare_ic_stub()) {
14744 : DCHECK(CodeStub::GetMajorKey(this) == CodeStub::CompareIC);
14745 : CompareICStub stub(stub_key(), GetIsolate());
14746 : os << "compare_state = " << CompareICState::GetStateName(stub.left())
14747 : << "*" << CompareICState::GetStateName(stub.right()) << " -> "
14748 : << CompareICState::GetStateName(stub.state()) << "\n";
14749 : os << "compare_operation = " << Token::Name(stub.op()) << "\n";
14750 : }
14751 : }
14752 : if ((name != nullptr) && (name[0] != '\0')) {
14753 : os << "name = " << name << "\n";
14754 : } else if (kind() == BUILTIN) {
14755 : name = GetIsolate()->builtins()->Lookup(instruction_start());
14756 : if (name != nullptr) {
14757 : os << "name = " << name << "\n";
14758 : }
14759 : } else if (kind() == BYTECODE_HANDLER) {
14760 : name = GetIsolate()->interpreter()->LookupNameOfBytecodeHandler(this);
14761 : if (name != nullptr) {
14762 : os << "name = " << name << "\n";
14763 : }
14764 : }
14765 : if (kind() == OPTIMIZED_FUNCTION) {
14766 : os << "stack_slots = " << stack_slots() << "\n";
14767 : }
14768 : os << "compiler = " << (is_turbofanned()
14769 : ? "turbofan"
14770 : : is_crankshafted() ? "crankshaft"
14771 : : kind() == Code::FUNCTION
14772 : ? "full-codegen"
14773 : : "unknown") << "\n";
14774 :
14775 : os << "Instructions (size = " << instruction_size() << ")\n";
14776 : {
14777 : Isolate* isolate = GetIsolate();
14778 : int size = instruction_size();
14779 : int safepoint_offset =
14780 : is_crankshafted() ? static_cast<int>(safepoint_table_offset()) : size;
14781 : int back_edge_offset = (kind() == Code::FUNCTION)
14782 : ? static_cast<int>(back_edge_table_offset())
14783 : : size;
14784 : int constant_pool_offset = FLAG_enable_embedded_constant_pool
14785 : ? this->constant_pool_offset()
14786 : : size;
14787 :
14788 : // Stop before reaching any embedded tables
14789 : int code_size = Min(safepoint_offset, back_edge_offset);
14790 : code_size = Min(code_size, constant_pool_offset);
14791 : byte* begin = instruction_start();
14792 : byte* end = begin + code_size;
14793 : Disassembler::Decode(isolate, &os, begin, end, this);
14794 :
14795 : if (constant_pool_offset < size) {
14796 : int constant_pool_size = size - constant_pool_offset;
14797 : DCHECK((constant_pool_size & kPointerAlignmentMask) == 0);
14798 : os << "\nConstant Pool (size = " << constant_pool_size << ")\n";
14799 : Vector<char> buf = Vector<char>::New(50);
14800 : intptr_t* ptr = reinterpret_cast<intptr_t*>(begin + constant_pool_offset);
14801 : for (int i = 0; i < constant_pool_size; i += kPointerSize, ptr++) {
14802 : SNPrintF(buf, "%4d %08" V8PRIxPTR, i, *ptr);
14803 : os << static_cast<const void*>(ptr) << " " << buf.start() << "\n";
14804 : }
14805 : }
14806 : }
14807 : os << "\n";
14808 :
14809 : SourcePositionTableIterator it(SourcePositionTable());
14810 : if (!it.done()) {
14811 : os << "Source positions:\n pc offset position\n";
14812 : for (; !it.done(); it.Advance()) {
14813 : os << std::setw(10) << std::hex << it.code_offset() << std::dec
14814 : << std::setw(10) << it.source_position().ScriptOffset()
14815 : << (it.is_statement() ? " statement" : "") << "\n";
14816 : }
14817 : os << "\n";
14818 : }
14819 :
14820 : if (kind() == FUNCTION) {
14821 : DeoptimizationOutputData* data =
14822 : DeoptimizationOutputData::cast(this->deoptimization_data());
14823 : data->DeoptimizationOutputDataPrint(os);
14824 : } else if (kind() == OPTIMIZED_FUNCTION) {
14825 : DeoptimizationInputData* data =
14826 : DeoptimizationInputData::cast(this->deoptimization_data());
14827 : data->DeoptimizationInputDataPrint(os);
14828 : }
14829 : os << "\n";
14830 :
14831 : if (is_crankshafted()) {
14832 : SafepointTable table(this);
14833 : os << "Safepoints (size = " << table.size() << ")\n";
14834 : for (unsigned i = 0; i < table.length(); i++) {
14835 : unsigned pc_offset = table.GetPcOffset(i);
14836 : os << static_cast<const void*>(instruction_start() + pc_offset) << " ";
14837 : os << std::setw(4) << std::hex << pc_offset << std::dec << " ";
14838 : table.PrintEntry(i, os);
14839 : os << " (sp -> fp) ";
14840 : SafepointEntry entry = table.GetEntry(i);
14841 : if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
14842 : os << std::setw(6) << entry.deoptimization_index();
14843 : } else {
14844 : os << "<none>";
14845 : }
14846 : if (entry.argument_count() > 0) {
14847 : os << " argc: " << entry.argument_count();
14848 : }
14849 : os << "\n";
14850 : }
14851 : os << "\n";
14852 : } else if (kind() == FUNCTION) {
14853 : unsigned offset = back_edge_table_offset();
14854 : // If there is no back edge table, the "table start" will be at or after
14855 : // (due to alignment) the end of the instruction stream.
14856 : if (static_cast<int>(offset) < instruction_size()) {
14857 : DisallowHeapAllocation no_gc;
14858 : BackEdgeTable back_edges(this, &no_gc);
14859 :
14860 : os << "Back edges (size = " << back_edges.length() << ")\n";
14861 : os << "ast_id pc_offset loop_depth\n";
14862 :
14863 : for (uint32_t i = 0; i < back_edges.length(); i++) {
14864 : os << std::setw(6) << back_edges.ast_id(i).ToInt() << " "
14865 : << std::setw(9) << std::hex << back_edges.pc_offset(i) << std::dec
14866 : << " " << std::setw(10) << back_edges.loop_depth(i) << "\n";
14867 : }
14868 :
14869 : os << "\n";
14870 : }
14871 : #ifdef OBJECT_PRINT
14872 : if (!type_feedback_info()->IsUndefined(GetIsolate())) {
14873 : TypeFeedbackInfo* info = TypeFeedbackInfo::cast(type_feedback_info());
14874 : HeapObject::PrintHeader(os, "TypeFeedbackInfo");
14875 : os << "\n - ic_total_count: " << info->ic_total_count()
14876 : << ", ic_with_type_info_count: " << info->ic_with_type_info_count()
14877 : << ", ic_generic_count: " << info->ic_generic_count() << "\n";
14878 : os << "\n";
14879 : }
14880 : #endif
14881 : }
14882 :
14883 : if (handler_table()->length() > 0) {
14884 : os << "Handler Table (size = " << handler_table()->Size() << ")\n";
14885 : if (kind() == FUNCTION) {
14886 : HandlerTable::cast(handler_table())->HandlerTableRangePrint(os);
14887 : } else if (kind() == OPTIMIZED_FUNCTION) {
14888 : HandlerTable::cast(handler_table())->HandlerTableReturnPrint(os);
14889 : }
14890 : os << "\n";
14891 : }
14892 :
14893 : os << "RelocInfo (size = " << relocation_size() << ")\n";
14894 : for (RelocIterator it(this); !it.done(); it.next()) {
14895 : it.rinfo()->Print(GetIsolate(), os);
14896 : }
14897 : os << "\n";
14898 :
14899 : if (has_unwinding_info()) {
14900 : os << "UnwindingInfo (size = " << unwinding_info_size() << ")\n";
14901 : EhFrameDisassembler eh_frame_disassembler(unwinding_info_start(),
14902 : unwinding_info_end());
14903 : eh_frame_disassembler.DisassembleToStream(os);
14904 : os << "\n";
14905 : }
14906 : }
14907 : #endif // ENABLE_DISASSEMBLER
14908 :
14909 :
14910 0 : void BytecodeArray::Disassemble(std::ostream& os) {
14911 0 : os << "Parameter count " << parameter_count() << "\n";
14912 0 : os << "Frame size " << frame_size() << "\n";
14913 :
14914 0 : const uint8_t* base_address = GetFirstBytecodeAddress();
14915 0 : SourcePositionTableIterator source_positions(SourcePositionTable());
14916 :
14917 0 : interpreter::BytecodeArrayIterator iterator(handle(this));
14918 0 : while (!iterator.done()) {
14919 0 : if (!source_positions.done() &&
14920 0 : iterator.current_offset() == source_positions.code_offset()) {
14921 0 : os << std::setw(5) << source_positions.source_position().ScriptOffset();
14922 0 : os << (source_positions.is_statement() ? " S> " : " E> ");
14923 0 : source_positions.Advance();
14924 : } else {
14925 0 : os << " ";
14926 : }
14927 0 : const uint8_t* current_address = base_address + iterator.current_offset();
14928 0 : os << reinterpret_cast<const void*>(current_address) << " @ "
14929 0 : << std::setw(4) << iterator.current_offset() << " : ";
14930 : interpreter::BytecodeDecoder::Decode(os, current_address,
14931 0 : parameter_count());
14932 0 : if (interpreter::Bytecodes::IsJump(iterator.current_bytecode())) {
14933 0 : const void* jump_target = base_address + iterator.GetJumpTargetOffset();
14934 0 : os << " (" << jump_target << " @ " << iterator.GetJumpTargetOffset()
14935 0 : << ")";
14936 : }
14937 : os << std::endl;
14938 0 : iterator.Advance();
14939 : }
14940 :
14941 0 : if (constant_pool()->length() > 0) {
14942 0 : os << "Constant pool (size = " << constant_pool()->length() << ")\n";
14943 : constant_pool()->Print();
14944 : }
14945 :
14946 : #ifdef ENABLE_DISASSEMBLER
14947 : if (handler_table()->length() > 0) {
14948 : os << "Handler Table (size = " << handler_table()->Size() << ")\n";
14949 : HandlerTable::cast(handler_table())->HandlerTableRangePrint(os);
14950 : }
14951 : #endif
14952 0 : }
14953 :
14954 9470 : void BytecodeArray::CopyBytecodesTo(BytecodeArray* to) {
14955 : BytecodeArray* from = this;
14956 : DCHECK_EQ(from->length(), to->length());
14957 9470 : CopyBytes(to->GetFirstBytecodeAddress(), from->GetFirstBytecodeAddress(),
14958 18940 : from->length());
14959 9470 : }
14960 :
14961 1946409 : void BytecodeArray::MakeOlder() {
14962 : Age age = bytecode_age();
14963 1946409 : if (age < kLastBytecodeAge) {
14964 1407165 : set_bytecode_age(static_cast<Age>(age + 1));
14965 : }
14966 : DCHECK_GE(bytecode_age(), kFirstBytecodeAge);
14967 : DCHECK_LE(bytecode_age(), kLastBytecodeAge);
14968 1946409 : }
14969 :
14970 0 : bool BytecodeArray::IsOld() const {
14971 249638 : return bytecode_age() >= kIsOldBytecodeAge;
14972 : }
14973 :
14974 : // static
14975 352164 : void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
14976 : DCHECK(capacity >= 0);
14977 : array->GetIsolate()->factory()->NewJSArrayStorage(
14978 352164 : array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
14979 352164 : }
14980 :
14981 1562026 : void JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) {
14982 : // We should never end in here with a pixel or external array.
14983 : DCHECK(array->AllowsSetLength());
14984 1562026 : if (array->SetLengthWouldNormalize(new_length)) {
14985 1515 : JSObject::NormalizeElements(array);
14986 : }
14987 1562026 : array->GetElementsAccessor()->SetLength(array, new_length);
14988 1562026 : }
14989 :
14990 :
14991 : // static
14992 321357 : void Map::AddDependentCode(Handle<Map> map,
14993 : DependentCode::DependencyGroup group,
14994 : Handle<Code> code) {
14995 321357 : Handle<WeakCell> cell = Code::WeakCellFor(code);
14996 : Handle<DependentCode> codes = DependentCode::InsertWeakCode(
14997 : Handle<DependentCode>(map->dependent_code()), group, cell);
14998 321357 : if (*codes != map->dependent_code()) map->set_dependent_code(*codes);
14999 321357 : }
15000 :
15001 :
15002 904414 : Handle<DependentCode> DependentCode::InsertCompilationDependencies(
15003 : Handle<DependentCode> entries, DependencyGroup group,
15004 : Handle<Foreign> info) {
15005 904414 : return Insert(entries, group, info);
15006 : }
15007 :
15008 :
15009 1051520 : Handle<DependentCode> DependentCode::InsertWeakCode(
15010 : Handle<DependentCode> entries, DependencyGroup group,
15011 : Handle<WeakCell> code_cell) {
15012 1372877 : return Insert(entries, group, code_cell);
15013 : }
15014 :
15015 :
15016 2297332 : Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
15017 : DependencyGroup group,
15018 : Handle<Object> object) {
15019 4218794 : if (entries->length() == 0 || entries->group() > group) {
15020 : // There is no such group.
15021 391164 : return DependentCode::New(group, object, entries);
15022 : }
15023 1906168 : if (entries->group() < group) {
15024 : // The group comes later in the list.
15025 : Handle<DependentCode> old_next(entries->next_link());
15026 20042 : Handle<DependentCode> new_next = Insert(old_next, group, object);
15027 20042 : if (!old_next.is_identical_to(new_next)) {
15028 : entries->set_next_link(*new_next);
15029 : }
15030 20042 : return entries;
15031 : }
15032 : DCHECK_EQ(group, entries->group());
15033 : int count = entries->count();
15034 : // Check for existing entry to avoid duplicates.
15035 168608393 : for (int i = 0; i < count; i++) {
15036 167911126 : if (entries->object_at(i) == *object) return entries;
15037 : }
15038 1394534 : if (entries->length() < kCodesStartIndex + count + 1) {
15039 269799 : entries = EnsureSpace(entries);
15040 : // Count could have changed, reload it.
15041 : count = entries->count();
15042 : }
15043 : entries->set_object_at(count, *object);
15044 1394534 : entries->set_count(count + 1);
15045 697267 : return entries;
15046 : }
15047 :
15048 :
15049 391164 : Handle<DependentCode> DependentCode::New(DependencyGroup group,
15050 : Handle<Object> object,
15051 : Handle<DependentCode> next) {
15052 : Isolate* isolate = next->GetIsolate();
15053 : Handle<DependentCode> result = Handle<DependentCode>::cast(
15054 391164 : isolate->factory()->NewFixedArray(kCodesStartIndex + 1, TENURED));
15055 : result->set_next_link(*next);
15056 391164 : result->set_flags(GroupField::encode(group) | CountField::encode(1));
15057 : result->set_object_at(0, *object);
15058 391164 : return result;
15059 : }
15060 :
15061 :
15062 269799 : Handle<DependentCode> DependentCode::EnsureSpace(
15063 : Handle<DependentCode> entries) {
15064 269799 : if (entries->Compact()) return entries;
15065 : Isolate* isolate = entries->GetIsolate();
15066 259735 : int capacity = kCodesStartIndex + DependentCode::Grow(entries->count());
15067 259735 : int grow_by = capacity - entries->length();
15068 : return Handle<DependentCode>::cast(
15069 259735 : isolate->factory()->CopyFixedArrayAndGrow(entries, grow_by, TENURED));
15070 : }
15071 :
15072 :
15073 269799 : bool DependentCode::Compact() {
15074 : int old_count = count();
15075 : int new_count = 0;
15076 2904687 : for (int i = 0; i < old_count; i++) {
15077 : Object* obj = object_at(i);
15078 5257521 : if (!obj->IsWeakCell() || !WeakCell::cast(obj)->cleared()) {
15079 2599659 : if (i != new_count) {
15080 9040 : copy(i, new_count);
15081 : }
15082 2599659 : new_count++;
15083 : }
15084 : }
15085 269799 : set_count(new_count);
15086 305028 : for (int i = new_count; i < old_count; i++) {
15087 : clear_at(i);
15088 : }
15089 269799 : return new_count < old_count;
15090 : }
15091 :
15092 :
15093 869947 : void DependentCode::UpdateToFinishedCode(DependencyGroup group, Foreign* info,
15094 : WeakCell* code_cell) {
15095 1768502 : if (this->length() == 0 || this->group() > group) {
15096 : // There is no such group.
15097 : return;
15098 : }
15099 884251 : if (this->group() < group) {
15100 : // The group comes later in the list.
15101 : next_link()->UpdateToFinishedCode(group, info, code_cell);
15102 14304 : return;
15103 : }
15104 : DCHECK_EQ(group, this->group());
15105 : DisallowHeapAllocation no_gc;
15106 : int count = this->count();
15107 87162232 : for (int i = 0; i < count; i++) {
15108 86781905 : if (object_at(i) == info) {
15109 : set_object_at(i, code_cell);
15110 : break;
15111 : }
15112 : }
15113 : #ifdef DEBUG
15114 : for (int i = 0; i < count; i++) {
15115 : DCHECK(object_at(i) != info);
15116 : }
15117 : #endif
15118 : }
15119 :
15120 :
15121 34453 : void DependentCode::RemoveCompilationDependencies(
15122 : DependentCode::DependencyGroup group, Foreign* info) {
15123 70100 : if (this->length() == 0 || this->group() > group) {
15124 : // There is no such group.
15125 : return;
15126 : }
15127 35050 : if (this->group() < group) {
15128 : // The group comes later in the list.
15129 : next_link()->RemoveCompilationDependencies(group, info);
15130 597 : return;
15131 : }
15132 : DCHECK_EQ(group, this->group());
15133 : DisallowHeapAllocation no_allocation;
15134 : int old_count = count();
15135 : // Find compilation info wrapper.
15136 : int info_pos = -1;
15137 1140147 : for (int i = 0; i < old_count; i++) {
15138 1126166 : if (object_at(i) == info) {
15139 : info_pos = i;
15140 : break;
15141 : }
15142 : }
15143 34453 : if (info_pos == -1) return; // Not found.
15144 : // Use the last code to fill the gap.
15145 20472 : if (info_pos < old_count - 1) {
15146 4603 : copy(old_count - 1, info_pos);
15147 : }
15148 : clear_at(old_count - 1);
15149 20472 : set_count(old_count - 1);
15150 :
15151 : #ifdef DEBUG
15152 : for (int i = 0; i < old_count - 1; i++) {
15153 : DCHECK(object_at(i) != info);
15154 : }
15155 : #endif
15156 : }
15157 :
15158 :
15159 0 : bool DependentCode::Contains(DependencyGroup group, WeakCell* code_cell) {
15160 0 : if (this->length() == 0 || this->group() > group) {
15161 : // There is no such group.
15162 : return false;
15163 : }
15164 0 : if (this->group() < group) {
15165 : // The group comes later in the list.
15166 0 : return next_link()->Contains(group, code_cell);
15167 : }
15168 : DCHECK_EQ(group, this->group());
15169 : int count = this->count();
15170 0 : for (int i = 0; i < count; i++) {
15171 0 : if (object_at(i) == code_cell) return true;
15172 : }
15173 : return false;
15174 : }
15175 :
15176 :
15177 202133 : bool DependentCode::IsEmpty(DependencyGroup group) {
15178 376973 : if (this->length() == 0 || this->group() > group) {
15179 : // There is no such group.
15180 : return true;
15181 : }
15182 164098 : if (this->group() < group) {
15183 : // The group comes later in the list.
15184 0 : return next_link()->IsEmpty(group);
15185 : }
15186 : DCHECK_EQ(group, this->group());
15187 164098 : return count() == 0;
15188 : }
15189 :
15190 :
15191 20072595 : bool DependentCode::MarkCodeForDeoptimization(
15192 : Isolate* isolate,
15193 : DependentCode::DependencyGroup group) {
15194 20116163 : if (this->length() == 0 || this->group() > group) {
15195 : // There is no such group.
15196 : return false;
15197 : }
15198 41008 : if (this->group() < group) {
15199 : // The group comes later in the list.
15200 1949 : return next_link()->MarkCodeForDeoptimization(isolate, group);
15201 : }
15202 : DCHECK_EQ(group, this->group());
15203 : DisallowHeapAllocation no_allocation_scope;
15204 : // Mark all the code that needs to be deoptimized.
15205 : bool marked = false;
15206 : bool invalidate_embedded_objects = group == kWeakCodeGroup;
15207 : int count = this->count();
15208 124319 : for (int i = 0; i < count; i++) {
15209 : Object* obj = object_at(i);
15210 85260 : if (obj->IsWeakCell()) {
15211 : WeakCell* cell = WeakCell::cast(obj);
15212 85055 : if (cell->cleared()) continue;
15213 : Code* code = Code::cast(cell->value());
15214 23273 : if (!code->marked_for_deoptimization()) {
15215 14390 : SetMarkedForDeoptimization(code, group);
15216 14390 : if (invalidate_embedded_objects) {
15217 5283 : code->InvalidateEmbeddedObjects();
15218 : }
15219 : marked = true;
15220 : }
15221 : } else {
15222 : DCHECK(obj->IsForeign());
15223 : CompilationDependencies* info =
15224 : reinterpret_cast<CompilationDependencies*>(
15225 : Foreign::cast(obj)->foreign_address());
15226 : info->Abort();
15227 : }
15228 : }
15229 85260 : for (int i = 0; i < count; i++) {
15230 : clear_at(i);
15231 : }
15232 39059 : set_count(0);
15233 39059 : return marked;
15234 : }
15235 :
15236 :
15237 20040468 : void DependentCode::DeoptimizeDependentCodeGroup(
15238 : Isolate* isolate,
15239 : DependentCode::DependencyGroup group) {
15240 : DisallowHeapAllocation no_allocation_scope;
15241 20040468 : bool marked = MarkCodeForDeoptimization(isolate, group);
15242 20040470 : if (marked) {
15243 : DCHECK(AllowCodeDependencyChange::IsAllowed());
15244 5935 : Deoptimizer::DeoptimizeMarkedCode(isolate);
15245 : }
15246 20040470 : }
15247 :
15248 :
15249 14404 : void DependentCode::SetMarkedForDeoptimization(Code* code,
15250 : DependencyGroup group) {
15251 : code->set_marked_for_deoptimization(true);
15252 14404 : if (FLAG_trace_deopt &&
15253 0 : (code->deoptimization_data() != code->GetHeap()->empty_fixed_array())) {
15254 : DeoptimizationInputData* deopt_data =
15255 : DeoptimizationInputData::cast(code->deoptimization_data());
15256 0 : CodeTracer::Scope scope(code->GetHeap()->isolate()->GetCodeTracer());
15257 : PrintF(scope.file(), "[marking dependent code 0x%08" V8PRIxPTR
15258 : " (opt #%d) for deoptimization, reason: %s]\n",
15259 : reinterpret_cast<intptr_t>(code),
15260 0 : deopt_data->OptimizationId()->value(), DependencyGroupName(group));
15261 : }
15262 14404 : }
15263 :
15264 :
15265 0 : const char* DependentCode::DependencyGroupName(DependencyGroup group) {
15266 0 : switch (group) {
15267 : case kWeakCodeGroup:
15268 : return "weak-code";
15269 : case kTransitionGroup:
15270 0 : return "transition";
15271 : case kPrototypeCheckGroup:
15272 0 : return "prototype-check";
15273 : case kPropertyCellChangedGroup:
15274 0 : return "property-cell-changed";
15275 : case kFieldOwnerGroup:
15276 0 : return "field-owner";
15277 : case kInitialMapChangedGroup:
15278 0 : return "initial-map-changed";
15279 : case kAllocationSiteTenuringChangedGroup:
15280 0 : return "allocation-site-tenuring-changed";
15281 : case kAllocationSiteTransitionChangedGroup:
15282 0 : return "allocation-site-transition-changed";
15283 : }
15284 0 : UNREACHABLE();
15285 : return "?";
15286 : }
15287 :
15288 :
15289 4154295 : Handle<Map> Map::TransitionToPrototype(Handle<Map> map,
15290 : Handle<Object> prototype,
15291 : PrototypeOptimizationMode mode) {
15292 4154295 : Handle<Map> new_map = TransitionArray::GetPrototypeTransition(map, prototype);
15293 4154295 : if (new_map.is_null()) {
15294 138924 : new_map = Copy(map, "TransitionToPrototype");
15295 138924 : TransitionArray::PutPrototypeTransition(map, prototype, new_map);
15296 138924 : Map::SetPrototype(new_map, prototype, mode);
15297 : }
15298 4154295 : return new_map;
15299 : }
15300 :
15301 :
15302 4182272 : Maybe<bool> JSReceiver::SetPrototype(Handle<JSReceiver> object,
15303 : Handle<Object> value, bool from_javascript,
15304 : ShouldThrow should_throw) {
15305 4182272 : if (object->IsJSProxy()) {
15306 : return JSProxy::SetPrototype(Handle<JSProxy>::cast(object), value,
15307 532 : from_javascript, should_throw);
15308 : }
15309 : return JSObject::SetPrototype(Handle<JSObject>::cast(object), value,
15310 4181740 : from_javascript, should_throw);
15311 : }
15312 :
15313 :
15314 : // ES6: 9.5.2 [[SetPrototypeOf]] (V)
15315 : // static
15316 532 : Maybe<bool> JSProxy::SetPrototype(Handle<JSProxy> proxy, Handle<Object> value,
15317 : bool from_javascript,
15318 : ShouldThrow should_throw) {
15319 : Isolate* isolate = proxy->GetIsolate();
15320 532 : STACK_CHECK(isolate, Nothing<bool>());
15321 : Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string();
15322 : // 1. Assert: Either Type(V) is Object or Type(V) is Null.
15323 : DCHECK(value->IsJSReceiver() || value->IsNull(isolate));
15324 : // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
15325 : Handle<Object> handler(proxy->handler(), isolate);
15326 : // 3. If handler is null, throw a TypeError exception.
15327 : // 4. Assert: Type(handler) is Object.
15328 532 : if (proxy->IsRevoked()) {
15329 : isolate->Throw(*isolate->factory()->NewTypeError(
15330 28 : MessageTemplate::kProxyRevoked, trap_name));
15331 : return Nothing<bool>();
15332 : }
15333 : // 5. Let target be the value of the [[ProxyTarget]] internal slot.
15334 : Handle<JSReceiver> target(proxy->target(), isolate);
15335 : // 6. Let trap be ? GetMethod(handler, "getPrototypeOf").
15336 : Handle<Object> trap;
15337 1036 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15338 : isolate, trap,
15339 : Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
15340 : Nothing<bool>());
15341 : // 7. If trap is undefined, then return target.[[SetPrototypeOf]]().
15342 518 : if (trap->IsUndefined(isolate)) {
15343 : return JSReceiver::SetPrototype(target, value, from_javascript,
15344 364 : should_throw);
15345 : }
15346 : // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, V»)).
15347 154 : Handle<Object> argv[] = {target, value};
15348 : Handle<Object> trap_result;
15349 308 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15350 : isolate, trap_result,
15351 : Execution::Call(isolate, trap, handler, arraysize(argv), argv),
15352 : Nothing<bool>());
15353 140 : bool bool_trap_result = trap_result->BooleanValue();
15354 : // 9. If booleanTrapResult is false, return false.
15355 140 : if (!bool_trap_result) {
15356 140 : RETURN_FAILURE(
15357 : isolate, should_throw,
15358 : NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15359 : }
15360 : // 10. Let extensibleTarget be ? IsExtensible(target).
15361 84 : Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
15362 84 : if (is_extensible.IsNothing()) return Nothing<bool>();
15363 : // 11. If extensibleTarget is true, return true.
15364 84 : if (is_extensible.FromJust()) {
15365 42 : if (bool_trap_result) return Just(true);
15366 0 : RETURN_FAILURE(
15367 : isolate, should_throw,
15368 : NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15369 : }
15370 : // 12. Let targetProto be ? target.[[GetPrototypeOf]]().
15371 : Handle<Object> target_proto;
15372 84 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_proto,
15373 : JSReceiver::GetPrototype(isolate, target),
15374 : Nothing<bool>());
15375 : // 13. If SameValue(V, targetProto) is false, throw a TypeError exception.
15376 56 : if (bool_trap_result && !value->SameValue(*target_proto)) {
15377 : isolate->Throw(*isolate->factory()->NewTypeError(
15378 28 : MessageTemplate::kProxySetPrototypeOfNonExtensible));
15379 : return Nothing<bool>();
15380 : }
15381 : // 14. Return true.
15382 : return Just(true);
15383 : }
15384 :
15385 :
15386 4194431 : Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object,
15387 : Handle<Object> value, bool from_javascript,
15388 : ShouldThrow should_throw) {
15389 42 : Isolate* isolate = object->GetIsolate();
15390 :
15391 : #ifdef DEBUG
15392 : int size = object->Size();
15393 : #endif
15394 :
15395 4194431 : if (from_javascript) {
15396 115644 : if (object->IsAccessCheckNeeded() &&
15397 42 : !isolate->MayAccess(handle(isolate->context()), object)) {
15398 0 : isolate->ReportFailedAccessCheck(object);
15399 0 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
15400 0 : RETURN_FAILURE(isolate, should_throw,
15401 : NewTypeError(MessageTemplate::kNoAccess));
15402 : }
15403 : } else {
15404 : DCHECK(!object->IsAccessCheckNeeded());
15405 : }
15406 :
15407 : Heap* heap = isolate->heap();
15408 : // Silently ignore the change if value is not a JSObject or null.
15409 : // SpiderMonkey behaves this way.
15410 8252454 : if (!value->IsJSReceiver() && !value->IsNull(isolate)) return Just(true);
15411 :
15412 : bool all_extensible = object->map()->is_extensible();
15413 : Handle<JSObject> real_receiver = object;
15414 4194413 : if (from_javascript) {
15415 : // Find the first object in the chain whose prototype object is not
15416 : // hidden.
15417 : PrototypeIterator iter(isolate, real_receiver, kStartAtPrototype,
15418 115602 : PrototypeIterator::END_AT_NON_HIDDEN);
15419 235849 : while (!iter.IsAtEnd()) {
15420 : // Casting to JSObject is fine because hidden prototypes are never
15421 : // JSProxies.
15422 : real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter);
15423 4645 : iter.Advance();
15424 9290 : all_extensible = all_extensible && real_receiver->map()->is_extensible();
15425 : }
15426 : }
15427 : Handle<Map> map(real_receiver->map());
15428 :
15429 : // Nothing to do if prototype is already set.
15430 4194413 : if (map->prototype() == *value) return Just(true);
15431 :
15432 : bool immutable_proto = map->is_immutable_proto();
15433 4153594 : if (immutable_proto) {
15434 251 : RETURN_FAILURE(
15435 : isolate, should_throw,
15436 : NewTypeError(MessageTemplate::kImmutablePrototypeSet, object));
15437 : }
15438 :
15439 : // From 8.6.2 Object Internal Methods
15440 : // ...
15441 : // In addition, if [[Extensible]] is false the value of the [[Class]] and
15442 : // [[Prototype]] internal properties of the object may not be modified.
15443 : // ...
15444 : // Implementation specific extensions that modify [[Class]], [[Prototype]]
15445 : // or [[Extensible]] must not violate the invariants defined in the preceding
15446 : // paragraph.
15447 4153501 : if (!all_extensible) {
15448 822 : RETURN_FAILURE(isolate, should_throw,
15449 : NewTypeError(MessageTemplate::kNonExtensibleProto, object));
15450 : }
15451 :
15452 : // Before we can set the prototype we need to be sure prototype cycles are
15453 : // prevented. It is sufficient to validate that the receiver is not in the
15454 : // new prototype chain.
15455 4153105 : if (value->IsJSReceiver()) {
15456 357631 : for (PrototypeIterator iter(isolate, JSReceiver::cast(*value),
15457 : kStartAtReceiver);
15458 262388 : !iter.IsAtEnd(); iter.Advance()) {
15459 525020 : if (iter.GetCurrent<JSReceiver>() == *object) {
15460 : // Cycle detected.
15461 310 : RETURN_FAILURE(isolate, should_throw,
15462 : NewTypeError(MessageTemplate::kCyclicProto));
15463 : }
15464 : }
15465 : }
15466 :
15467 : // Set the new prototype of the object.
15468 :
15469 : isolate->UpdateArrayProtectorOnSetPrototype(real_receiver);
15470 :
15471 : PrototypeOptimizationMode mode =
15472 4152983 : from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE;
15473 4152983 : Handle<Map> new_map = Map::TransitionToPrototype(map, value, mode);
15474 : DCHECK(new_map->prototype() == *value);
15475 4152983 : JSObject::MigrateToMap(real_receiver, new_map);
15476 :
15477 : heap->ClearInstanceofCache();
15478 : DCHECK(size == object->Size());
15479 : return Just(true);
15480 : }
15481 :
15482 : // static
15483 28 : void JSObject::SetImmutableProto(Handle<JSObject> object) {
15484 : DCHECK(!object->IsAccessCheckNeeded()); // Never called from JS
15485 : Handle<Map> map(object->map());
15486 :
15487 : // Nothing to do if prototype is already set.
15488 49 : if (map->is_immutable_proto()) return;
15489 :
15490 7 : Handle<Map> new_map = Map::TransitionToImmutableProto(map);
15491 7 : object->set_map(*new_map);
15492 : }
15493 :
15494 1144031 : void JSObject::EnsureCanContainElements(Handle<JSObject> object,
15495 1144031 : Arguments* args,
15496 : uint32_t first_arg,
15497 : uint32_t arg_count,
15498 : EnsureElementsMode mode) {
15499 : // Elements in |Arguments| are ordered backwards (because they're on the
15500 : // stack), but the method that's called here iterates over them in forward
15501 : // direction.
15502 : return EnsureCanContainElements(
15503 1144031 : object, args->arguments() - first_arg - (arg_count - 1), arg_count, mode);
15504 : }
15505 :
15506 :
15507 512760675 : ElementsAccessor* JSObject::GetElementsAccessor() {
15508 512760675 : return ElementsAccessor::ForKind(GetElementsKind());
15509 : }
15510 :
15511 :
15512 21511152 : void JSObject::ValidateElements(Handle<JSObject> object) {
15513 : #ifdef ENABLE_SLOW_DCHECKS
15514 : if (FLAG_enable_slow_asserts) {
15515 : ElementsAccessor* accessor = object->GetElementsAccessor();
15516 : accessor->Validate(object);
15517 : }
15518 : #endif
15519 21511152 : }
15520 :
15521 :
15522 1963873 : static bool ShouldConvertToSlowElements(JSObject* object, uint32_t capacity,
15523 : uint32_t index,
15524 : uint32_t* new_capacity) {
15525 : STATIC_ASSERT(JSObject::kMaxUncheckedOldFastElementsLength <=
15526 : JSObject::kMaxUncheckedFastElementsLength);
15527 1963873 : if (index < capacity) {
15528 963081 : *new_capacity = capacity;
15529 963081 : return false;
15530 : }
15531 1000792 : if (index - capacity >= JSObject::kMaxGap) return true;
15532 1223844 : *new_capacity = JSObject::NewElementsCapacity(index + 1);
15533 : DCHECK_LT(index, *new_capacity);
15534 1223844 : if (*new_capacity <= JSObject::kMaxUncheckedOldFastElementsLength ||
15535 69292 : (*new_capacity <= JSObject::kMaxUncheckedFastElementsLength &&
15536 : object->GetHeap()->InNewSpace(object))) {
15537 : return false;
15538 : }
15539 : // If the fast-case backing storage takes up roughly three times as
15540 : // much space (in machine words) as a dictionary backing storage
15541 : // would, the object should have slow elements.
15542 1776 : int used_elements = object->GetFastElementsUsage();
15543 : int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
15544 1776 : SeededNumberDictionary::kEntrySize;
15545 1776 : return 3 * static_cast<uint32_t>(dictionary_size) <= *new_capacity;
15546 : }
15547 :
15548 :
15549 186759 : bool JSObject::WouldConvertToSlowElements(uint32_t index) {
15550 186759 : if (HasFastElements()) {
15551 : Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements()));
15552 36043 : uint32_t capacity = static_cast<uint32_t>(backing_store->length());
15553 : uint32_t new_capacity;
15554 36043 : return ShouldConvertToSlowElements(this, capacity, index, &new_capacity);
15555 : }
15556 : return false;
15557 : }
15558 :
15559 :
15560 2961 : static ElementsKind BestFittingFastElementsKind(JSObject* object) {
15561 2961 : if (object->HasSloppyArgumentsElements()) {
15562 : return FAST_SLOPPY_ARGUMENTS_ELEMENTS;
15563 : }
15564 2931 : if (object->HasStringWrapperElements()) {
15565 : return FAST_STRING_WRAPPER_ELEMENTS;
15566 : }
15567 : DCHECK(object->HasDictionaryElements());
15568 : SeededNumberDictionary* dictionary = object->element_dictionary();
15569 : ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS;
15570 3957332 : for (int i = 0; i < dictionary->Capacity(); i++) {
15571 : Object* key = dictionary->KeyAt(i);
15572 1975837 : if (key->IsNumber()) {
15573 655163 : Object* value = dictionary->ValueAt(i);
15574 655163 : if (!value->IsNumber()) return FAST_HOLEY_ELEMENTS;
15575 655076 : if (!value->IsSmi()) {
15576 73635 : if (!FLAG_unbox_double_arrays) return FAST_HOLEY_ELEMENTS;
15577 : kind = FAST_HOLEY_DOUBLE_ELEMENTS;
15578 : }
15579 : }
15580 : }
15581 : return kind;
15582 : }
15583 :
15584 :
15585 1736825 : static bool ShouldConvertToFastElements(JSObject* object,
15586 : SeededNumberDictionary* dictionary,
15587 : uint32_t index,
15588 : uint32_t* new_capacity) {
15589 : // If properties with non-standard attributes or accessors were added, we
15590 : // cannot go back to fast elements.
15591 1736825 : if (dictionary->requires_slow_elements()) return false;
15592 :
15593 : // Adding a property with this index will require slow elements.
15594 1697738 : if (index >= static_cast<uint32_t>(Smi::kMaxValue)) return false;
15595 :
15596 1697224 : if (object->IsJSArray()) {
15597 : Object* length = JSArray::cast(object)->length();
15598 903797 : if (!length->IsSmi()) return false;
15599 902537 : *new_capacity = static_cast<uint32_t>(Smi::cast(length)->value());
15600 : } else {
15601 793427 : *new_capacity = dictionary->max_number_key() + 1;
15602 : }
15603 3391928 : *new_capacity = Max(index + 1, *new_capacity);
15604 :
15605 1695964 : uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
15606 1695964 : SeededNumberDictionary::kEntrySize;
15607 :
15608 : // Turn fast if the dictionary only saves 50% space.
15609 1695964 : return 2 * dictionary_size >= *new_capacity;
15610 : }
15611 :
15612 :
15613 : // static
15614 32929 : MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> object,
15615 : uint32_t index,
15616 : Handle<Object> value,
15617 : PropertyAttributes attributes) {
15618 32929 : MAYBE_RETURN_NULL(
15619 : AddDataElement(object, index, value, attributes, THROW_ON_ERROR));
15620 : return value;
15621 : }
15622 :
15623 :
15624 : // static
15625 3710517 : Maybe<bool> JSObject::AddDataElement(Handle<JSObject> object, uint32_t index,
15626 : Handle<Object> value,
15627 : PropertyAttributes attributes,
15628 : ShouldThrow should_throw) {
15629 : DCHECK(object->map()->is_extensible());
15630 :
15631 : Isolate* isolate = object->GetIsolate();
15632 :
15633 3710517 : uint32_t old_length = 0;
15634 3710517 : uint32_t new_capacity = 0;
15635 :
15636 3710517 : if (object->IsJSArray()) {
15637 1550916 : CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length));
15638 : }
15639 :
15640 : ElementsKind kind = object->GetElementsKind();
15641 : FixedArrayBase* elements = object->elements();
15642 : ElementsKind dictionary_kind = DICTIONARY_ELEMENTS;
15643 3710517 : if (IsSloppyArgumentsElementsKind(kind)) {
15644 : elements = FixedArrayBase::cast(FixedArray::cast(elements)->get(1));
15645 : dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
15646 3511441 : } else if (IsStringWrapperElementsKind(kind)) {
15647 : dictionary_kind = SLOW_STRING_WRAPPER_ELEMENTS;
15648 : }
15649 :
15650 3710517 : if (attributes != NONE) {
15651 : kind = dictionary_kind;
15652 3663140 : } else if (elements->IsSeededNumberDictionary()) {
15653 : kind = ShouldConvertToFastElements(*object,
15654 : SeededNumberDictionary::cast(elements),
15655 1736825 : index, &new_capacity)
15656 : ? BestFittingFastElementsKind(*object)
15657 1739786 : : dictionary_kind; // Overwrite in case of arguments.
15658 1926315 : } else if (ShouldConvertToSlowElements(
15659 : *object, static_cast<uint32_t>(elements->length()), index,
15660 1926315 : &new_capacity)) {
15661 : kind = dictionary_kind;
15662 : }
15663 :
15664 3710517 : ElementsKind to = value->OptimalElementsKind();
15665 4270869 : if (IsHoleyElementsKind(kind) || !object->IsJSArray() || index > old_length) {
15666 : to = GetHoleyElementsKind(to);
15667 : kind = GetHoleyElementsKind(kind);
15668 : }
15669 : to = GetMoreGeneralElementsKind(kind, to);
15670 : ElementsAccessor* accessor = ElementsAccessor::ForKind(to);
15671 3710517 : accessor->Add(object, index, value, attributes, new_capacity);
15672 :
15673 3710517 : if (object->IsJSArray() && index >= old_length) {
15674 : Handle<Object> new_length =
15675 1322180 : isolate->factory()->NewNumberFromUint(index + 1);
15676 1322180 : JSArray::cast(*object)->set_length(*new_length);
15677 : }
15678 :
15679 3710517 : return Just(true);
15680 : }
15681 :
15682 :
15683 1562026 : bool JSArray::SetLengthWouldNormalize(uint32_t new_length) {
15684 1562026 : if (!HasFastElements()) return false;
15685 1537137 : uint32_t capacity = static_cast<uint32_t>(elements()->length());
15686 : uint32_t new_capacity;
15687 1538652 : return JSArray::SetLengthWouldNormalize(GetHeap(), new_length) &&
15688 : ShouldConvertToSlowElements(this, capacity, new_length - 1,
15689 1538652 : &new_capacity);
15690 : }
15691 :
15692 :
15693 : const double AllocationSite::kPretenureRatio = 0.85;
15694 :
15695 :
15696 0 : void AllocationSite::ResetPretenureDecision() {
15697 : set_pretenure_decision(kUndecided);
15698 : set_memento_found_count(0);
15699 : set_memento_create_count(0);
15700 0 : }
15701 :
15702 :
15703 45053 : PretenureFlag AllocationSite::GetPretenureMode() {
15704 : PretenureDecision mode = pretenure_decision();
15705 : // Zombie objects "decide" to be untenured.
15706 45053 : return mode == kTenure ? TENURED : NOT_TENURED;
15707 : }
15708 :
15709 :
15710 0 : bool AllocationSite::IsNestedSite() {
15711 : DCHECK(FLAG_trace_track_allocation_sites);
15712 0 : Object* current = GetHeap()->allocation_sites_list();
15713 0 : while (current->IsAllocationSite()) {
15714 : AllocationSite* current_site = AllocationSite::cast(current);
15715 0 : if (current_site->nested_site() == this) {
15716 : return true;
15717 : }
15718 : current = current_site->weak_next();
15719 : }
15720 : return false;
15721 : }
15722 :
15723 : template <AllocationSiteUpdateMode update_or_check>
15724 634931 : bool AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
15725 : ElementsKind to_kind) {
15726 : Isolate* isolate = site->GetIsolate();
15727 : bool result = false;
15728 :
15729 1242724 : if (site->SitePointsToLiteral() && site->transition_info()->IsJSArray()) {
15730 : Handle<JSArray> transition_info =
15731 : handle(JSArray::cast(site->transition_info()));
15732 : ElementsKind kind = transition_info->GetElementsKind();
15733 : // if kind is holey ensure that to_kind is as well.
15734 607793 : if (IsHoleyElementsKind(kind)) {
15735 : to_kind = GetHoleyElementsKind(to_kind);
15736 : }
15737 607793 : if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
15738 : // If the array is huge, it's not likely to be defined in a local
15739 : // function, so we shouldn't make new instances of it very often.
15740 61454 : uint32_t length = 0;
15741 61454 : CHECK(transition_info->length()->ToArrayLength(&length));
15742 61454 : if (length <= kMaximumArrayBytesToPretransition) {
15743 : if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) {
15744 0 : return true;
15745 : }
15746 61454 : if (FLAG_trace_track_allocation_sites) {
15747 0 : bool is_nested = site->IsNestedSite();
15748 0 : PrintF(
15749 : "AllocationSite: JSArray %p boilerplate %s updated %s->%s\n",
15750 : reinterpret_cast<void*>(*site),
15751 : is_nested ? "(nested)" : "",
15752 : ElementsKindToString(kind),
15753 0 : ElementsKindToString(to_kind));
15754 : }
15755 61454 : JSObject::TransitionElementsKind(transition_info, to_kind);
15756 61454 : site->dependent_code()->DeoptimizeDependentCodeGroup(
15757 : isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
15758 : result = true;
15759 : }
15760 : }
15761 : } else {
15762 : ElementsKind kind = site->GetElementsKind();
15763 : // if kind is holey ensure that to_kind is as well.
15764 27138 : if (IsHoleyElementsKind(kind)) {
15765 : to_kind = GetHoleyElementsKind(to_kind);
15766 : }
15767 27138 : if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
15768 : if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) return true;
15769 23552 : if (FLAG_trace_track_allocation_sites) {
15770 0 : PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
15771 : reinterpret_cast<void*>(*site),
15772 : ElementsKindToString(kind),
15773 0 : ElementsKindToString(to_kind));
15774 : }
15775 23552 : site->SetElementsKind(to_kind);
15776 23552 : site->dependent_code()->DeoptimizeDependentCodeGroup(
15777 : isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
15778 : result = true;
15779 : }
15780 : }
15781 : return result;
15782 : }
15783 :
15784 3312 : AllocationSiteMode AllocationSite::GetMode(ElementsKind from, ElementsKind to) {
15785 5930 : if (IsFastSmiElementsKind(from) &&
15786 2618 : IsMoreGeneralElementsKindTransition(from, to)) {
15787 : return TRACK_ALLOCATION_SITE;
15788 : }
15789 :
15790 694 : return DONT_TRACK_ALLOCATION_SITE;
15791 : }
15792 :
15793 0 : const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) {
15794 0 : switch (decision) {
15795 : case kUndecided: return "undecided";
15796 0 : case kDontTenure: return "don't tenure";
15797 0 : case kMaybeTenure: return "maybe tenure";
15798 0 : case kTenure: return "tenure";
15799 0 : case kZombie: return "zombie";
15800 0 : default: UNREACHABLE();
15801 : }
15802 : return NULL;
15803 : }
15804 :
15805 : template <AllocationSiteUpdateMode update_or_check>
15806 1725146 : bool JSObject::UpdateAllocationSite(Handle<JSObject> object,
15807 : ElementsKind to_kind) {
15808 1725146 : if (!object->IsJSArray()) return false;
15809 :
15810 : Heap* heap = object->GetHeap();
15811 1307902 : if (!heap->InNewSpace(*object)) return false;
15812 :
15813 : Handle<AllocationSite> site;
15814 : {
15815 : DisallowHeapAllocation no_allocation;
15816 :
15817 : AllocationMemento* memento =
15818 1238942 : heap->FindAllocationMemento<Heap::kForRuntime>(*object);
15819 1238942 : if (memento == NULL) return false;
15820 :
15821 : // Walk through to the Allocation Site
15822 634931 : site = handle(memento->GetAllocationSite());
15823 : }
15824 : return AllocationSite::DigestTransitionFeedback<update_or_check>(site,
15825 634931 : to_kind);
15826 : }
15827 :
15828 : template bool
15829 : JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kCheckOnly>(
15830 : Handle<JSObject> object, ElementsKind to_kind);
15831 :
15832 : template bool JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kUpdate>(
15833 : Handle<JSObject> object, ElementsKind to_kind);
15834 :
15835 444557 : void JSObject::TransitionElementsKind(Handle<JSObject> object,
15836 : ElementsKind to_kind) {
15837 : ElementsKind from_kind = object->GetElementsKind();
15838 :
15839 444557 : if (IsFastHoleyElementsKind(from_kind)) {
15840 : to_kind = GetHoleyElementsKind(to_kind);
15841 : }
15842 :
15843 889114 : if (from_kind == to_kind) return;
15844 :
15845 : // This method should never be called for any other case.
15846 : DCHECK(IsFastElementsKind(from_kind));
15847 : DCHECK(IsFastElementsKind(to_kind));
15848 : DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind);
15849 :
15850 444468 : UpdateAllocationSite(object, to_kind);
15851 813503 : if (object->elements() == object->GetHeap()->empty_fixed_array() ||
15852 : IsFastDoubleElementsKind(from_kind) ==
15853 : IsFastDoubleElementsKind(to_kind)) {
15854 : // No change is needed to the elements() buffer, the transition
15855 : // only requires a map change.
15856 436765 : Handle<Map> new_map = GetElementsTransitionMap(object, to_kind);
15857 436765 : MigrateToMap(object, new_map);
15858 : if (FLAG_trace_elements_transitions) {
15859 : Handle<FixedArrayBase> elms(object->elements());
15860 : PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms);
15861 : }
15862 : } else {
15863 : DCHECK((IsFastSmiElementsKind(from_kind) &&
15864 : IsFastDoubleElementsKind(to_kind)) ||
15865 : (IsFastDoubleElementsKind(from_kind) &&
15866 : IsFastObjectElementsKind(to_kind)));
15867 7703 : uint32_t c = static_cast<uint32_t>(object->elements()->length());
15868 7703 : ElementsAccessor::ForKind(to_kind)->GrowCapacityAndConvert(object, c);
15869 : }
15870 : }
15871 :
15872 :
15873 : // static
15874 0 : bool Map::IsValidElementsTransition(ElementsKind from_kind,
15875 : ElementsKind to_kind) {
15876 : // Transitions can't go backwards.
15877 0 : if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
15878 : return false;
15879 : }
15880 :
15881 : // Transitions from HOLEY -> PACKED are not allowed.
15882 0 : return !IsFastHoleyElementsKind(from_kind) ||
15883 0 : IsFastHoleyElementsKind(to_kind);
15884 : }
15885 :
15886 :
15887 4364472 : bool JSArray::HasReadOnlyLength(Handle<JSArray> array) {
15888 : Map* map = array->map();
15889 : // Fast path: "length" is the first fast property of arrays. Since it's not
15890 : // configurable, it's guaranteed to be the first in the descriptor array.
15891 4364472 : if (!map->is_dictionary_map()) {
15892 : DCHECK(map->instance_descriptors()->GetKey(0) ==
15893 : array->GetHeap()->length_string());
15894 8691714 : return map->instance_descriptors()->GetDetails(0).IsReadOnly();
15895 : }
15896 :
15897 : Isolate* isolate = array->GetIsolate();
15898 : LookupIterator it(array, isolate->factory()->length_string(), array,
15899 18615 : LookupIterator::OWN_SKIP_INTERCEPTOR);
15900 18615 : CHECK_EQ(LookupIterator::ACCESSOR, it.state());
15901 18615 : return it.IsReadOnly();
15902 : }
15903 :
15904 :
15905 1518673 : bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array,
15906 : uint32_t index) {
15907 1518673 : uint32_t length = 0;
15908 1518673 : CHECK(array->length()->ToArrayLength(&length));
15909 1518673 : if (length <= index) return HasReadOnlyLength(array);
15910 : return false;
15911 : }
15912 :
15913 :
15914 : template <typename BackingStore>
15915 439690 : static int FastHoleyElementsUsage(JSObject* object, BackingStore* store) {
15916 : Isolate* isolate = store->GetIsolate();
15917 : int limit = object->IsJSArray()
15918 : ? Smi::cast(JSArray::cast(object)->length())->value()
15919 439690 : : store->length();
15920 : int used = 0;
15921 523603629 : for (int i = 0; i < limit; ++i) {
15922 523163939 : if (!store->is_the_hole(isolate, i)) ++used;
15923 : }
15924 439690 : return used;
15925 : }
15926 :
15927 :
15928 466612 : int JSObject::GetFastElementsUsage() {
15929 : FixedArrayBase* store = elements();
15930 466612 : switch (GetElementsKind()) {
15931 : case FAST_SMI_ELEMENTS:
15932 : case FAST_DOUBLE_ELEMENTS:
15933 : case FAST_ELEMENTS:
15934 : return IsJSArray() ? Smi::cast(JSArray::cast(this)->length())->value()
15935 53754 : : store->length();
15936 : case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
15937 : store = SloppyArgumentsElements::cast(store)->arguments();
15938 : // Fall through.
15939 : case FAST_HOLEY_SMI_ELEMENTS:
15940 : case FAST_HOLEY_ELEMENTS:
15941 : case FAST_STRING_WRAPPER_ELEMENTS:
15942 439542 : return FastHoleyElementsUsage(this, FixedArray::cast(store));
15943 : case FAST_HOLEY_DOUBLE_ELEMENTS:
15944 193 : if (elements()->length() == 0) return 0;
15945 148 : return FastHoleyElementsUsage(this, FixedDoubleArray::cast(store));
15946 :
15947 : case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
15948 : case SLOW_STRING_WRAPPER_ELEMENTS:
15949 : case DICTIONARY_ELEMENTS:
15950 : case NO_ELEMENTS:
15951 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
15952 : case TYPE##_ELEMENTS: \
15953 :
15954 : TYPED_ARRAYS(TYPED_ARRAY_CASE)
15955 : #undef TYPED_ARRAY_CASE
15956 0 : UNREACHABLE();
15957 : }
15958 : return 0;
15959 : }
15960 :
15961 :
15962 : // Certain compilers request function template instantiation when they
15963 : // see the definition of the other template functions in the
15964 : // class. This requires us to have the template functions put
15965 : // together, so even though this function belongs in objects-debug.cc,
15966 : // we keep it here instead to satisfy certain compilers.
15967 : #ifdef OBJECT_PRINT
15968 : template <typename Derived, typename Shape, typename Key>
15969 : void Dictionary<Derived, Shape, Key>::Print(std::ostream& os) { // NOLINT
15970 : Isolate* isolate = this->GetIsolate();
15971 : int capacity = this->Capacity();
15972 : for (int i = 0; i < capacity; i++) {
15973 : Object* k = this->KeyAt(i);
15974 : if (this->IsKey(isolate, k)) {
15975 : os << "\n ";
15976 : if (k->IsString()) {
15977 : String::cast(k)->StringPrint(os);
15978 : } else {
15979 : os << Brief(k);
15980 : }
15981 : os << ": " << Brief(this->ValueAt(i)) << " ";
15982 : this->DetailsAt(i).PrintAsSlowTo(os);
15983 : }
15984 : }
15985 : }
15986 : template <typename Derived, typename Shape, typename Key>
15987 : void Dictionary<Derived, Shape, Key>::Print() {
15988 : OFStream os(stdout);
15989 : Print(os);
15990 : }
15991 : #endif
15992 :
15993 :
15994 5152 : MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it,
15995 : bool* done) {
15996 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
15997 5152 : return GetPropertyWithInterceptorInternal(it, it->GetInterceptor(), done);
15998 : }
15999 :
16000 66895821 : Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object,
16001 : Handle<Name> name) {
16002 : LookupIterator it = LookupIterator::PropertyOrElement(
16003 66895821 : name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
16004 66895821 : return HasProperty(&it);
16005 : }
16006 :
16007 :
16008 20 : Maybe<bool> JSObject::HasRealElementProperty(Handle<JSObject> object,
16009 : uint32_t index) {
16010 : Isolate* isolate = object->GetIsolate();
16011 : LookupIterator it(isolate, object, index, object,
16012 : LookupIterator::OWN_SKIP_INTERCEPTOR);
16013 20 : return HasProperty(&it);
16014 : }
16015 :
16016 :
16017 6 : Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
16018 : Handle<Name> name) {
16019 : LookupIterator it = LookupIterator::PropertyOrElement(
16020 6 : name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
16021 6 : Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
16022 6 : return maybe_result.IsJust() ? Just(it.state() == LookupIterator::ACCESSOR)
16023 12 : : Nothing<bool>();
16024 : }
16025 :
16026 3449 : int FixedArrayBase::GetMaxLengthForNewSpaceAllocation(ElementsKind kind) {
16027 : return ((kMaxRegularHeapObjectSize - FixedArrayBase::kHeaderSize) >>
16028 3449 : ElementsKindToShiftSize(kind));
16029 : }
16030 :
16031 49010 : bool JSObject::WasConstructedFromApiFunction() {
16032 : auto instance_type = map()->instance_type();
16033 49010 : bool is_api_object = instance_type == JS_API_OBJECT_TYPE ||
16034 49010 : instance_type == JS_SPECIAL_API_OBJECT_TYPE;
16035 : #ifdef ENABLE_SLOW_DCHECKS
16036 : if (FLAG_enable_slow_asserts) {
16037 : Object* maybe_constructor = map()->GetConstructor();
16038 : if (maybe_constructor->IsJSFunction()) {
16039 : JSFunction* constructor = JSFunction::cast(maybe_constructor);
16040 : if (constructor->shared()->IsApiFunction()) {
16041 : DCHECK(is_api_object);
16042 : } else {
16043 : DCHECK(!is_api_object);
16044 : }
16045 : } else if (maybe_constructor->IsFunctionTemplateInfo()) {
16046 : DCHECK(is_api_object);
16047 : } else {
16048 : return false;
16049 : }
16050 : }
16051 : #endif
16052 49010 : return is_api_object;
16053 : }
16054 :
16055 210 : const char* Symbol::PrivateSymbolToName() const {
16056 7140 : Heap* heap = GetIsolate()->heap();
16057 : #define SYMBOL_CHECK_AND_PRINT(name) \
16058 : if (this == heap->name()) return #name;
16059 7140 : PRIVATE_SYMBOL_LIST(SYMBOL_CHECK_AND_PRINT)
16060 : #undef SYMBOL_CHECK_AND_PRINT
16061 210 : return "UNKNOWN";
16062 : }
16063 :
16064 :
16065 227 : void Symbol::SymbolShortPrint(std::ostream& os) {
16066 227 : os << "<Symbol:";
16067 227 : if (!name()->IsUndefined(GetIsolate())) {
16068 17 : os << " ";
16069 : HeapStringAllocator allocator;
16070 : StringStream accumulator(&allocator);
16071 17 : String::cast(name())->StringShortPrint(&accumulator, false);
16072 51 : os << accumulator.ToCString().get();
16073 : } else {
16074 210 : os << " (" << PrivateSymbolToName() << ")";
16075 : }
16076 227 : os << ">";
16077 227 : }
16078 :
16079 :
16080 : // StringSharedKeys are used as keys in the eval cache.
16081 0 : class StringSharedKey : public HashTableKey {
16082 : public:
16083 : // This tuple unambiguously identifies calls to eval() or
16084 : // CreateDynamicFunction() (such as through the Function() constructor).
16085 : // * source is the string passed into eval(). For dynamic functions, this is
16086 : // the effective source for the function, some of which is implicitly
16087 : // generated.
16088 : // * shared is the shared function info for the function containing the call
16089 : // to eval(). for dynamic functions, shared is the native context closure.
16090 : // * When positive, position is the position in the source where eval is
16091 : // called. When negative, position is the negation of the position in the
16092 : // dynamic function's effective source where the ')' ends the parameters.
16093 : StringSharedKey(Handle<String> source, Handle<SharedFunctionInfo> shared,
16094 : LanguageMode language_mode, int position)
16095 : : source_(source),
16096 : shared_(shared),
16097 : language_mode_(language_mode),
16098 7850993 : position_(position) {}
16099 :
16100 9649113 : bool IsMatch(Object* other) override {
16101 : DisallowHeapAllocation no_allocation;
16102 9649113 : if (!other->IsFixedArray()) {
16103 2549780 : if (!other->IsNumber()) return false;
16104 2549780 : uint32_t other_hash = static_cast<uint32_t>(other->Number());
16105 2549780 : return Hash() == other_hash;
16106 : }
16107 : FixedArray* other_array = FixedArray::cast(other);
16108 : SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
16109 7099333 : if (shared != *shared_) return false;
16110 : int language_unchecked = Smi::cast(other_array->get(2))->value();
16111 : DCHECK(is_valid_language_mode(language_unchecked));
16112 6776483 : LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
16113 6776483 : if (language_mode != language_mode_) return false;
16114 : int position = Smi::cast(other_array->get(3))->value();
16115 6750051 : if (position != position_) return false;
16116 : String* source = String::cast(other_array->get(1));
16117 6750021 : return source->Equals(*source_);
16118 : }
16119 :
16120 12129773 : static uint32_t StringSharedHashHelper(String* source,
16121 : SharedFunctionInfo* shared,
16122 : LanguageMode language_mode,
16123 : int position) {
16124 : uint32_t hash = source->Hash();
16125 12129773 : if (shared->HasSourceCode()) {
16126 : // Instead of using the SharedFunctionInfo pointer in the hash
16127 : // code computation, we use a combination of the hash of the
16128 : // script source code and the start position of the calling scope.
16129 : // We do this to ensure that the cache entries can survive garbage
16130 : // collection.
16131 : Script* script(Script::cast(shared->script()));
16132 12129773 : hash ^= String::cast(script->source())->Hash();
16133 : STATIC_ASSERT(LANGUAGE_END == 2);
16134 12129773 : if (is_strict(language_mode)) hash ^= 0x8000;
16135 12129773 : hash += position;
16136 : }
16137 12129773 : return hash;
16138 : }
16139 :
16140 11954739 : uint32_t Hash() override {
16141 : return StringSharedHashHelper(*source_, *shared_, language_mode_,
16142 23909478 : position_);
16143 : }
16144 :
16145 1019703 : uint32_t HashForObject(Object* obj) override {
16146 : DisallowHeapAllocation no_allocation;
16147 1019703 : if (obj->IsNumber()) {
16148 844669 : return static_cast<uint32_t>(obj->Number());
16149 : }
16150 : FixedArray* other_array = FixedArray::cast(obj);
16151 : SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
16152 : String* source = String::cast(other_array->get(1));
16153 : int language_unchecked = Smi::cast(other_array->get(2))->value();
16154 : DCHECK(is_valid_language_mode(language_unchecked));
16155 175034 : LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
16156 : int position = Smi::cast(other_array->get(3))->value();
16157 175034 : return StringSharedHashHelper(source, shared, language_mode, position);
16158 : }
16159 :
16160 :
16161 1985791 : Handle<Object> AsHandle(Isolate* isolate) override {
16162 1985791 : Handle<FixedArray> array = isolate->factory()->NewFixedArray(4);
16163 1985791 : array->set(0, *shared_);
16164 1985791 : array->set(1, *source_);
16165 1985791 : array->set(2, Smi::FromInt(language_mode_));
16166 1985791 : array->set(3, Smi::FromInt(position_));
16167 1985791 : return array;
16168 : }
16169 :
16170 : private:
16171 : Handle<String> source_;
16172 : Handle<SharedFunctionInfo> shared_;
16173 : LanguageMode language_mode_;
16174 : int position_;
16175 : };
16176 :
16177 : // static
16178 30 : const char* JSPromise::Status(int status) {
16179 30 : switch (status) {
16180 : case v8::Promise::kFulfilled:
16181 : return "resolved";
16182 : case v8::Promise::kPending:
16183 12 : return "pending";
16184 : case v8::Promise::kRejected:
16185 0 : return "rejected";
16186 : }
16187 0 : UNREACHABLE();
16188 : return NULL;
16189 : }
16190 :
16191 : namespace {
16192 :
16193 593209 : JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags, bool* success) {
16194 : JSRegExp::Flags value = JSRegExp::kNone;
16195 : int length = flags->length();
16196 : // A longer flags string cannot be valid.
16197 593209 : if (length > JSRegExp::FlagCount()) return JSRegExp::Flags(0);
16198 97165 : for (int i = 0; i < length; i++) {
16199 : JSRegExp::Flag flag = JSRegExp::kNone;
16200 97445 : switch (flags->Get(i)) {
16201 : case 'g':
16202 : flag = JSRegExp::kGlobal;
16203 : break;
16204 : case 'i':
16205 : flag = JSRegExp::kIgnoreCase;
16206 76841 : break;
16207 : case 'm':
16208 : flag = JSRegExp::kMultiline;
16209 719 : break;
16210 : case 's':
16211 84 : if (FLAG_harmony_regexp_dotall) {
16212 : flag = JSRegExp::kDotAll;
16213 : } else {
16214 28 : return JSRegExp::Flags(0);
16215 : }
16216 : break;
16217 : case 'u':
16218 : flag = JSRegExp::kUnicode;
16219 1835 : break;
16220 : case 'y':
16221 : flag = JSRegExp::kSticky;
16222 130 : break;
16223 : default:
16224 43 : return JSRegExp::Flags(0);
16225 : }
16226 : // Duplicate flag.
16227 97374 : if (value & flag) return JSRegExp::Flags(0);
16228 : value |= flag;
16229 : }
16230 592929 : *success = true;
16231 592929 : return value;
16232 : }
16233 :
16234 : } // namespace
16235 :
16236 :
16237 : // static
16238 125419 : MaybeHandle<JSRegExp> JSRegExp::New(Handle<String> pattern, Flags flags) {
16239 : Isolate* isolate = pattern->GetIsolate();
16240 125419 : Handle<JSFunction> constructor = isolate->regexp_function();
16241 : Handle<JSRegExp> regexp =
16242 125419 : Handle<JSRegExp>::cast(isolate->factory()->NewJSObject(constructor));
16243 :
16244 125419 : return JSRegExp::Initialize(regexp, pattern, flags);
16245 : }
16246 :
16247 :
16248 : // static
16249 122005 : Handle<JSRegExp> JSRegExp::Copy(Handle<JSRegExp> regexp) {
16250 : Isolate* const isolate = regexp->GetIsolate();
16251 122005 : return Handle<JSRegExp>::cast(isolate->factory()->CopyJSObject(regexp));
16252 : }
16253 :
16254 :
16255 : template <typename Char>
16256 719976 : inline int CountRequiredEscapes(Handle<String> source) {
16257 : DisallowHeapAllocation no_gc;
16258 : int escapes = 0;
16259 : Vector<const Char> src = source->GetCharVector<Char>();
16260 16857041 : for (int i = 0; i < src.length(); i++) {
16261 16137065 : if (src[i] == '\\') {
16262 : // Escape. Skip next character;
16263 152785 : i++;
16264 15984280 : } else if (src[i] == '/') {
16265 : // Not escaped forward-slash needs escape.
16266 2627 : escapes++;
16267 : }
16268 : }
16269 719976 : return escapes;
16270 : }
16271 :
16272 :
16273 : template <typename Char, typename StringType>
16274 958 : inline Handle<StringType> WriteEscapedRegExpSource(Handle<String> source,
16275 : Handle<StringType> result) {
16276 : DisallowHeapAllocation no_gc;
16277 : Vector<const Char> src = source->GetCharVector<Char>();
16278 958 : Vector<Char> dst(result->GetChars(), result->length());
16279 : int s = 0;
16280 : int d = 0;
16281 52745 : while (s < src.length()) {
16282 50829 : if (src[s] == '\\') {
16283 : // Escape. Copy this and next character.
16284 6196 : dst[d++] = src[s++];
16285 3098 : if (s == src.length()) break;
16286 47731 : } else if (src[s] == '/') {
16287 : // Not escaped forward-slash needs escape.
16288 5254 : dst[d++] = '\\';
16289 : }
16290 152487 : dst[d++] = src[s++];
16291 : }
16292 : DCHECK_EQ(result->length(), d);
16293 958 : return result;
16294 : }
16295 :
16296 :
16297 719976 : MaybeHandle<String> EscapeRegExpSource(Isolate* isolate,
16298 : Handle<String> source) {
16299 : DCHECK(source->IsFlat());
16300 719976 : if (source->length() == 0) return isolate->factory()->query_colon_string();
16301 719976 : bool one_byte = source->IsOneByteRepresentationUnderneath();
16302 : int escapes = one_byte ? CountRequiredEscapes<uint8_t>(source)
16303 719976 : : CountRequiredEscapes<uc16>(source);
16304 719976 : if (escapes == 0) return source;
16305 958 : int length = source->length() + escapes;
16306 958 : if (one_byte) {
16307 : Handle<SeqOneByteString> result;
16308 1916 : ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
16309 : isolate->factory()->NewRawOneByteString(length),
16310 : String);
16311 958 : return WriteEscapedRegExpSource<uint8_t>(source, result);
16312 : } else {
16313 : Handle<SeqTwoByteString> result;
16314 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
16315 : isolate->factory()->NewRawTwoByteString(length),
16316 : String);
16317 0 : return WriteEscapedRegExpSource<uc16>(source, result);
16318 : }
16319 : }
16320 :
16321 :
16322 : // static
16323 593209 : MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
16324 : Handle<String> source,
16325 : Handle<String> flags_string) {
16326 : Isolate* isolate = source->GetIsolate();
16327 593209 : bool success = false;
16328 593209 : Flags flags = RegExpFlagsFromString(flags_string, &success);
16329 593209 : if (!success) {
16330 560 : THROW_NEW_ERROR(
16331 : isolate,
16332 : NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string),
16333 : JSRegExp);
16334 : }
16335 592929 : return Initialize(regexp, source, flags);
16336 : }
16337 :
16338 :
16339 : // static
16340 719976 : MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
16341 : Handle<String> source, Flags flags) {
16342 : Isolate* isolate = regexp->GetIsolate();
16343 : Factory* factory = isolate->factory();
16344 : // If source is the empty string we set it to "(?:)" instead as
16345 : // suggested by ECMA-262, 5th, section 15.10.4.1.
16346 719976 : if (source->length() == 0) source = factory->query_colon_string();
16347 :
16348 719976 : source = String::Flatten(source);
16349 :
16350 : Handle<String> escaped_source;
16351 1439952 : ASSIGN_RETURN_ON_EXCEPTION(isolate, escaped_source,
16352 : EscapeRegExpSource(isolate, source), JSRegExp);
16353 :
16354 1439952 : RETURN_ON_EXCEPTION(isolate, RegExpImpl::Compile(regexp, source, flags),
16355 : JSRegExp);
16356 :
16357 716414 : regexp->set_source(*escaped_source);
16358 716414 : regexp->set_flags(Smi::FromInt(flags));
16359 :
16360 : Map* map = regexp->map();
16361 716414 : Object* constructor = map->GetConstructor();
16362 1432828 : if (constructor->IsJSFunction() &&
16363 : JSFunction::cast(constructor)->initial_map() == map) {
16364 : // If we still have the original map, set in-object properties directly.
16365 : regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, Smi::kZero,
16366 716116 : SKIP_WRITE_BARRIER);
16367 : } else {
16368 : // Map has changed, so use generic, but slower, method.
16369 596 : RETURN_ON_EXCEPTION(isolate, JSReceiver::SetProperty(
16370 : regexp, factory->lastIndex_string(),
16371 : Handle<Smi>(Smi::kZero, isolate), STRICT),
16372 : JSRegExp);
16373 : }
16374 :
16375 : return regexp;
16376 : }
16377 :
16378 :
16379 : // RegExpKey carries the source and flags of a regular expression as key.
16380 0 : class RegExpKey : public HashTableKey {
16381 : public:
16382 : RegExpKey(Handle<String> string, JSRegExp::Flags flags)
16383 2845342 : : string_(string), flags_(Smi::FromInt(flags)) {}
16384 :
16385 : // Rather than storing the key in the hash table, a pointer to the
16386 : // stored value is stored where the key should be. IsMatch then
16387 : // compares the search key to the found object, rather than comparing
16388 : // a key to a key.
16389 845391 : bool IsMatch(Object* obj) override {
16390 : FixedArray* val = FixedArray::cast(obj);
16391 845391 : return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
16392 1201848 : && (flags_ == val->get(JSRegExp::kFlagsIndex));
16393 : }
16394 :
16395 2845342 : uint32_t Hash() override { return RegExpHash(*string_, flags_); }
16396 :
16397 0 : Handle<Object> AsHandle(Isolate* isolate) override {
16398 : // Plain hash maps, which is where regexp keys are used, don't
16399 : // use this function.
16400 0 : UNREACHABLE();
16401 : return MaybeHandle<Object>().ToHandleChecked();
16402 : }
16403 :
16404 511813 : uint32_t HashForObject(Object* obj) override {
16405 : FixedArray* val = FixedArray::cast(obj);
16406 : return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
16407 511813 : Smi::cast(val->get(JSRegExp::kFlagsIndex)));
16408 : }
16409 :
16410 1934484 : static uint32_t RegExpHash(String* string, Smi* flags) {
16411 1934484 : return string->Hash() + flags->value();
16412 : }
16413 :
16414 : Handle<String> string_;
16415 : Smi* flags_;
16416 : };
16417 :
16418 :
16419 55683 : Handle<Object> OneByteStringKey::AsHandle(Isolate* isolate) {
16420 55683 : if (hash_field_ == 0) Hash();
16421 55683 : return isolate->factory()->NewOneByteInternalizedString(string_, hash_field_);
16422 : }
16423 :
16424 :
16425 0 : Handle<Object> TwoByteStringKey::AsHandle(Isolate* isolate) {
16426 0 : if (hash_field_ == 0) Hash();
16427 0 : return isolate->factory()->NewTwoByteInternalizedString(string_, hash_field_);
16428 : }
16429 :
16430 :
16431 115049 : Handle<Object> SeqOneByteSubStringKey::AsHandle(Isolate* isolate) {
16432 115049 : if (hash_field_ == 0) Hash();
16433 : return isolate->factory()->NewOneByteInternalizedSubString(
16434 115049 : string_, from_, length_, hash_field_);
16435 : }
16436 :
16437 :
16438 163661 : bool SeqOneByteSubStringKey::IsMatch(Object* string) {
16439 327322 : Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
16440 163661 : return String::cast(string)->IsOneByteEqualTo(chars);
16441 : }
16442 :
16443 :
16444 : // InternalizedStringKey carries a string/internalized-string object as key.
16445 0 : class InternalizedStringKey : public HashTableKey {
16446 : public:
16447 : explicit InternalizedStringKey(Handle<String> string)
16448 22837777 : : string_(String::Flatten(string)) {}
16449 :
16450 30602494 : bool IsMatch(Object* string) override {
16451 30602494 : return String::cast(string)->Equals(*string_);
16452 : }
16453 :
16454 49481464 : uint32_t Hash() override { return string_->Hash(); }
16455 :
16456 549938 : uint32_t HashForObject(Object* other) override {
16457 549938 : return String::cast(other)->Hash();
16458 : }
16459 :
16460 1903339 : Handle<Object> AsHandle(Isolate* isolate) override {
16461 : // Internalize the string if possible.
16462 : MaybeHandle<Map> maybe_map =
16463 1903339 : isolate->factory()->InternalizedStringMapForString(string_);
16464 : Handle<Map> map;
16465 1903339 : if (maybe_map.ToHandle(&map)) {
16466 : string_->set_map_no_write_barrier(*map);
16467 : DCHECK(string_->IsInternalizedString());
16468 10899 : return string_;
16469 : }
16470 1892440 : if (FLAG_thin_strings) {
16471 : // External strings get special treatment, to avoid copying their
16472 : // contents.
16473 1330761 : if (string_->IsExternalOneByteString()) {
16474 : return isolate->factory()
16475 6 : ->InternalizeExternalString<ExternalOneByteString>(string_);
16476 1330755 : } else if (string_->IsExternalTwoByteString()) {
16477 : return isolate->factory()
16478 0 : ->InternalizeExternalString<ExternalTwoByteString>(string_);
16479 : }
16480 : }
16481 : // Otherwise allocate a new internalized string.
16482 : return isolate->factory()->NewInternalizedStringImpl(
16483 1892434 : string_, string_->length(), string_->hash_field());
16484 : }
16485 :
16486 : static uint32_t StringHash(Object* obj) {
16487 : return String::cast(obj)->Hash();
16488 : }
16489 :
16490 : private:
16491 : Handle<String> string_;
16492 : };
16493 :
16494 :
16495 : template<typename Derived, typename Shape, typename Key>
16496 53294 : void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) {
16497 : BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v);
16498 53294 : }
16499 :
16500 :
16501 : template<typename Derived, typename Shape, typename Key>
16502 71384 : void HashTable<Derived, Shape, Key>::IterateElements(ObjectVisitor* v) {
16503 : BodyDescriptorBase::IteratePointers(this, kElementsStartOffset,
16504 71384 : kHeaderSize + length() * kPointerSize, v);
16505 71384 : }
16506 :
16507 :
16508 : template<typename Derived, typename Shape, typename Key>
16509 7430455 : Handle<Derived> HashTable<Derived, Shape, Key>::New(
16510 : Isolate* isolate,
16511 : int at_least_space_for,
16512 : MinimumCapacity capacity_option,
16513 : PretenureFlag pretenure) {
16514 : DCHECK(0 <= at_least_space_for);
16515 : DCHECK_IMPLIES(capacity_option == USE_CUSTOM_MINIMUM_CAPACITY,
16516 : base::bits::IsPowerOfTwo32(at_least_space_for));
16517 :
16518 : int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
16519 : ? at_least_space_for
16520 7430455 : : ComputeCapacity(at_least_space_for);
16521 7430455 : if (capacity > HashTable::kMaxCapacity) {
16522 0 : v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
16523 : }
16524 7430455 : return New(isolate, capacity, pretenure);
16525 : }
16526 :
16527 : template <typename Derived, typename Shape, typename Key>
16528 7430739 : Handle<Derived> HashTable<Derived, Shape, Key>::New(Isolate* isolate,
16529 : int capacity,
16530 : PretenureFlag pretenure) {
16531 : Factory* factory = isolate->factory();
16532 : int length = EntryToIndex(capacity);
16533 7430739 : Handle<FixedArray> array = factory->NewFixedArray(length, pretenure);
16534 : array->set_map_no_write_barrier(Shape::GetMap(isolate));
16535 : Handle<Derived> table = Handle<Derived>::cast(array);
16536 :
16537 : table->SetNumberOfElements(0);
16538 : table->SetNumberOfDeletedElements(0);
16539 : table->SetCapacity(capacity);
16540 7430737 : return table;
16541 : }
16542 :
16543 : // Find entry for key otherwise return kNotFound.
16544 : template <typename Derived, typename Shape>
16545 94076451 : int NameDictionaryBase<Derived, Shape>::FindEntry(Handle<Name> key) {
16546 94076451 : if (!key->IsUniqueName()) {
16547 0 : return DerivedDictionary::FindEntry(key);
16548 : }
16549 :
16550 : // Optimized for unique names. Knowledge of the key type allows:
16551 : // 1. Move the check if the key is unique out of the loop.
16552 : // 2. Avoid comparing hash codes in unique-to-unique comparison.
16553 : // 3. Detect a case when a dictionary key is not unique but the key is.
16554 : // In case of positive result the dictionary key may be replaced by the
16555 : // internalized string with minimal performance penalty. It gives a chance
16556 : // to perform further lookups in code stubs (and significant performance
16557 : // boost a certain style of code).
16558 :
16559 : // EnsureCapacity will guarantee the hash table is never full.
16560 94076451 : uint32_t capacity = this->Capacity();
16561 : uint32_t entry = Derived::FirstProbe(key->Hash(), capacity);
16562 : uint32_t count = 1;
16563 : Isolate* isolate = this->GetIsolate();
16564 : while (true) {
16565 151673521 : Object* element = this->KeyAt(entry);
16566 151673511 : if (element->IsUndefined(isolate)) break; // Empty entry.
16567 107072172 : if (*key == element) return entry;
16568 : DCHECK(element->IsTheHole(isolate) || element->IsUniqueName());
16569 57597070 : entry = Derived::NextProbe(entry, count++, capacity);
16570 : }
16571 57597070 : return Derived::kNotFound;
16572 : }
16573 :
16574 :
16575 : template<typename Derived, typename Shape, typename Key>
16576 3427166 : void HashTable<Derived, Shape, Key>::Rehash(
16577 : Handle<Derived> new_table,
16578 : Key key) {
16579 : DCHECK(NumberOfElements() < new_table->Capacity());
16580 :
16581 : DisallowHeapAllocation no_gc;
16582 3427166 : WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
16583 :
16584 : // Copy prefix to new array.
16585 10226247 : for (int i = kPrefixStartIndex;
16586 : i < kPrefixStartIndex + Shape::kPrefixSize;
16587 : i++) {
16588 6817498 : new_table->set(i, get(i), mode);
16589 : }
16590 :
16591 : // Rehash the elements.
16592 : int capacity = this->Capacity();
16593 3427166 : Heap* heap = new_table->GetHeap();
16594 : Object* the_hole = heap->the_hole_value();
16595 : Object* undefined = heap->undefined_value();
16596 73589081 : for (int i = 0; i < capacity; i++) {
16597 70159402 : uint32_t from_index = EntryToIndex(i);
16598 : Object* k = this->get(from_index);
16599 70159402 : if (k != the_hole && k != undefined) {
16600 : uint32_t hash = this->HashForObject(key, k);
16601 : uint32_t insertion_index =
16602 78329098 : EntryToIndex(new_table->FindInsertionEntry(hash));
16603 135876972 : for (int j = 0; j < Shape::kEntrySize; j++) {
16604 290137269 : new_table->set(insertion_index + j, get(from_index + j), mode);
16605 : }
16606 : }
16607 : }
16608 : new_table->SetNumberOfElements(NumberOfElements());
16609 : new_table->SetNumberOfDeletedElements(0);
16610 3427166 : }
16611 :
16612 :
16613 : template<typename Derived, typename Shape, typename Key>
16614 1428621 : uint32_t HashTable<Derived, Shape, Key>::EntryForProbe(
16615 : Key key,
16616 : Object* k,
16617 : int probe,
16618 : uint32_t expected) {
16619 : uint32_t hash = this->HashForObject(key, k);
16620 1428621 : uint32_t capacity = this->Capacity();
16621 : uint32_t entry = FirstProbe(hash, capacity);
16622 3498116 : for (int i = 1; i < probe; i++) {
16623 2838300 : if (entry == expected) return expected;
16624 2069495 : entry = NextProbe(entry, i, capacity);
16625 : }
16626 : return entry;
16627 : }
16628 :
16629 :
16630 : template<typename Derived, typename Shape, typename Key>
16631 9497 : void HashTable<Derived, Shape, Key>::Swap(uint32_t entry1,
16632 : uint32_t entry2,
16633 : WriteBarrierMode mode) {
16634 9497 : int index1 = EntryToIndex(entry1);
16635 9497 : int index2 = EntryToIndex(entry2);
16636 : Object* temp[Shape::kEntrySize];
16637 28491 : for (int j = 0; j < Shape::kEntrySize; j++) {
16638 37988 : temp[j] = get(index1 + j);
16639 : }
16640 18994 : for (int j = 0; j < Shape::kEntrySize; j++) {
16641 37988 : set(index1 + j, get(index2 + j), mode);
16642 : }
16643 18994 : for (int j = 0; j < Shape::kEntrySize; j++) {
16644 18994 : set(index2 + j, temp[j], mode);
16645 : }
16646 9497 : }
16647 :
16648 :
16649 : template<typename Derived, typename Shape, typename Key>
16650 53315 : void HashTable<Derived, Shape, Key>::Rehash(Key key) {
16651 : DisallowHeapAllocation no_gc;
16652 53315 : WriteBarrierMode mode = GetWriteBarrierMode(no_gc);
16653 : Isolate* isolate = GetIsolate();
16654 53315 : uint32_t capacity = Capacity();
16655 : bool done = false;
16656 141562 : for (int probe = 1; !done; probe++) {
16657 : // All elements at entries given by one of the first _probe_ probes
16658 : // are placed correctly. Other elements might need to be moved.
16659 : done = true;
16660 4180121 : for (uint32_t current = 0; current < capacity; current++) {
16661 4180121 : Object* current_key = KeyAt(current);
16662 4180121 : if (IsKey(isolate, current_key)) {
16663 1177775 : uint32_t target = EntryForProbe(key, current_key, probe, current);
16664 1177775 : if (current == target) continue;
16665 257264 : Object* target_key = KeyAt(target);
16666 508110 : if (!IsKey(isolate, target_key) ||
16667 250846 : EntryForProbe(key, target_key, probe, target) != target) {
16668 : // Put the current element into the correct position.
16669 9497 : Swap(current, target, mode);
16670 : // The other element will be processed on the next iteration.
16671 9497 : current--;
16672 : } else {
16673 : // The place for the current element is occupied. Leave the element
16674 : // for the next probe.
16675 : done = false;
16676 : }
16677 : }
16678 : }
16679 : }
16680 : // Wipe deleted entries.
16681 53315 : Object* the_hole = isolate->heap()->the_hole_value();
16682 53315 : Object* undefined = isolate->heap()->undefined_value();
16683 1977507 : for (uint32_t current = 0; current < capacity; current++) {
16684 3848384 : if (KeyAt(current) == the_hole) {
16685 15731 : set(EntryToIndex(current) + Derived::kEntryKeyIndex, undefined);
16686 : }
16687 : }
16688 : SetNumberOfDeletedElements(0);
16689 53315 : }
16690 :
16691 :
16692 : template<typename Derived, typename Shape, typename Key>
16693 69331169 : Handle<Derived> HashTable<Derived, Shape, Key>::EnsureCapacity(
16694 : Handle<Derived> table,
16695 : int n,
16696 : Key key,
16697 : PretenureFlag pretenure) {
16698 69331169 : if (table->HasSufficientCapacityToAdd(n)) return table;
16699 :
16700 : Isolate* isolate = table->GetIsolate();
16701 : int capacity = table->Capacity();
16702 3426737 : int new_nof = table->NumberOfElements() + n;
16703 :
16704 : const int kMinCapacityForPretenure = 256;
16705 : bool should_pretenure = pretenure == TENURED ||
16706 : ((capacity > kMinCapacityForPretenure) &&
16707 3433762 : !isolate->heap()->InNewSpace(*table));
16708 : Handle<Derived> new_table =
16709 : HashTable::New(isolate, new_nof, USE_DEFAULT_MINIMUM_CAPACITY,
16710 3426737 : should_pretenure ? TENURED : NOT_TENURED);
16711 :
16712 3426737 : table->Rehash(new_table, key);
16713 3426737 : return new_table;
16714 : }
16715 :
16716 : template <typename Derived, typename Shape, typename Key>
16717 69336984 : bool HashTable<Derived, Shape, Key>::HasSufficientCapacityToAdd(
16718 : int number_of_additional_elements) {
16719 : int capacity = Capacity();
16720 69336984 : int nof = NumberOfElements() + number_of_additional_elements;
16721 : int nod = NumberOfDeletedElements();
16722 : // Return true if:
16723 : // 50% is still free after adding number_of_additional_elements elements and
16724 : // at most 50% of the free elements are deleted elements.
16725 69336984 : if ((nof < capacity) && ((nod <= (capacity - nof) >> 1))) {
16726 66366858 : int needed_free = nof >> 1;
16727 66366858 : if (nof + needed_free <= capacity) return true;
16728 : }
16729 3427139 : return false;
16730 : }
16731 :
16732 :
16733 : template<typename Derived, typename Shape, typename Key>
16734 6170046 : Handle<Derived> HashTable<Derived, Shape, Key>::Shrink(Handle<Derived> table,
16735 : Key key) {
16736 : int capacity = table->Capacity();
16737 : int nof = table->NumberOfElements();
16738 :
16739 : // Shrink to fit the number of elements if only a quarter of the
16740 : // capacity is filled with elements.
16741 6170046 : if (nof > (capacity >> 2)) return table;
16742 : // Allocate a new dictionary with room for at least the current
16743 : // number of elements. The allocation method will make sure that
16744 : // there is extra room in the dictionary for additions. Don't go
16745 : // lower than room for 16 elements.
16746 : int at_least_room_for = nof;
16747 6119485 : if (at_least_room_for < 16) return table;
16748 :
16749 : Isolate* isolate = table->GetIsolate();
16750 : const int kMinCapacityForPretenure = 256;
16751 : bool pretenure =
16752 : (at_least_room_for > kMinCapacityForPretenure) &&
16753 458 : !isolate->heap()->InNewSpace(*table);
16754 : Handle<Derived> new_table = HashTable::New(
16755 : isolate,
16756 : at_least_room_for,
16757 : USE_DEFAULT_MINIMUM_CAPACITY,
16758 429 : pretenure ? TENURED : NOT_TENURED);
16759 :
16760 429 : table->Rehash(new_table, key);
16761 429 : return new_table;
16762 : }
16763 :
16764 :
16765 : template<typename Derived, typename Shape, typename Key>
16766 108495329 : uint32_t HashTable<Derived, Shape, Key>::FindInsertionEntry(uint32_t hash) {
16767 108495329 : uint32_t capacity = Capacity();
16768 : uint32_t entry = FirstProbe(hash, capacity);
16769 : uint32_t count = 1;
16770 : // EnsureCapacity will guarantee the hash table is never full.
16771 : Isolate* isolate = GetIsolate();
16772 : while (true) {
16773 180994568 : Object* element = KeyAt(entry);
16774 180994568 : if (!IsKey(isolate, element)) break;
16775 72499239 : entry = NextProbe(entry, count++, capacity);
16776 : }
16777 72499239 : return entry;
16778 : }
16779 :
16780 :
16781 : // Force instantiation of template instances class.
16782 : // Please note this list is compiler dependent.
16783 :
16784 : template class HashTable<StringTable, StringTableShape, HashTableKey*>;
16785 :
16786 : template class HashTable<CompilationCacheTable,
16787 : CompilationCacheShape,
16788 : HashTableKey*>;
16789 :
16790 : template class HashTable<ObjectHashTable,
16791 : ObjectHashTableShape,
16792 : Handle<Object> >;
16793 :
16794 : template class HashTable<WeakHashTable, WeakHashTableShape<2>, Handle<Object> >;
16795 :
16796 : template class Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >;
16797 :
16798 : template class Dictionary<GlobalDictionary, GlobalDictionaryShape,
16799 : Handle<Name> >;
16800 :
16801 : template class Dictionary<SeededNumberDictionary,
16802 : SeededNumberDictionaryShape,
16803 : uint32_t>;
16804 :
16805 : template class Dictionary<UnseededNumberDictionary,
16806 : UnseededNumberDictionaryShape,
16807 : uint32_t>;
16808 :
16809 : template Handle<SeededNumberDictionary>
16810 : Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::New(
16811 : Isolate*, int at_least_space_for, PretenureFlag pretenure,
16812 : MinimumCapacity capacity_option);
16813 :
16814 : template Handle<SeededNumberDictionary>
16815 : Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
16816 : uint32_t>::NewEmpty(Isolate*, PretenureFlag pretenure);
16817 :
16818 : template Handle<UnseededNumberDictionary>
16819 : Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
16820 : uint32_t>::NewEmpty(Isolate*, PretenureFlag pretenure);
16821 :
16822 : template Handle<UnseededNumberDictionary>
16823 : Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
16824 : uint32_t>::New(Isolate*, int at_least_space_for,
16825 : PretenureFlag pretenure,
16826 : MinimumCapacity capacity_option);
16827 :
16828 : template Handle<NameDictionary>
16829 : Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::New(
16830 : Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
16831 :
16832 : template Handle<NameDictionary>
16833 : Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::NewEmpty(
16834 : Isolate*, PretenureFlag pretenure);
16835 :
16836 : template Handle<GlobalDictionary>
16837 : Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::New(
16838 : Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
16839 :
16840 : template Handle<SeededNumberDictionary>
16841 : Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
16842 : AtPut(Handle<SeededNumberDictionary>, uint32_t, Handle<Object>);
16843 :
16844 : template Handle<UnseededNumberDictionary>
16845 : Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
16846 : AtPut(Handle<UnseededNumberDictionary>, uint32_t, Handle<Object>);
16847 :
16848 : template Object*
16849 : Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
16850 : SlowReverseLookup(Object* value);
16851 :
16852 : template Object*
16853 : Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
16854 : SlowReverseLookup(Object* value);
16855 :
16856 : template Handle<Object>
16857 : Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::DeleteProperty(
16858 : Handle<NameDictionary>, int);
16859 :
16860 : template Handle<Object>
16861 : Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
16862 : uint32_t>::DeleteProperty(Handle<SeededNumberDictionary>, int);
16863 :
16864 : template Handle<Object>
16865 : Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
16866 : uint32_t>::DeleteProperty(Handle<UnseededNumberDictionary>, int);
16867 :
16868 : template Handle<NameDictionary>
16869 : HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
16870 : New(Isolate*, int, MinimumCapacity, PretenureFlag);
16871 :
16872 : template Handle<ObjectHashSet> HashTable<ObjectHashSet, ObjectHashSetShape,
16873 : Handle<Object>>::New(Isolate*, int n,
16874 : MinimumCapacity,
16875 : PretenureFlag);
16876 :
16877 : template Handle<NameDictionary>
16878 : HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
16879 : Shrink(Handle<NameDictionary>, Handle<Name>);
16880 :
16881 : template Handle<SeededNumberDictionary>
16882 : HashTable<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
16883 : Shrink(Handle<SeededNumberDictionary>, uint32_t);
16884 :
16885 : template Handle<UnseededNumberDictionary>
16886 : HashTable<UnseededNumberDictionary, UnseededNumberDictionaryShape,
16887 : uint32_t>::Shrink(Handle<UnseededNumberDictionary>, uint32_t);
16888 :
16889 : template Handle<NameDictionary>
16890 : Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::Add(
16891 : Handle<NameDictionary>, Handle<Name>, Handle<Object>, PropertyDetails,
16892 : int*);
16893 :
16894 : template Handle<GlobalDictionary>
16895 : Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::Add(
16896 : Handle<GlobalDictionary>, Handle<Name>, Handle<Object>, PropertyDetails,
16897 : int*);
16898 :
16899 : template Handle<SeededNumberDictionary>
16900 : Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::Add(
16901 : Handle<SeededNumberDictionary>, uint32_t, Handle<Object>, PropertyDetails,
16902 : int*);
16903 :
16904 : template Handle<UnseededNumberDictionary>
16905 : Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
16906 : uint32_t>::Add(Handle<UnseededNumberDictionary>, uint32_t,
16907 : Handle<Object>, PropertyDetails, int*);
16908 :
16909 : template Handle<SeededNumberDictionary>
16910 : Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
16911 : EnsureCapacity(Handle<SeededNumberDictionary>, int, uint32_t);
16912 :
16913 : template Handle<UnseededNumberDictionary>
16914 : Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
16915 : EnsureCapacity(Handle<UnseededNumberDictionary>, int, uint32_t);
16916 :
16917 : template void Dictionary<NameDictionary, NameDictionaryShape,
16918 : Handle<Name> >::SetRequiresCopyOnCapacityChange();
16919 :
16920 : template Handle<NameDictionary>
16921 : Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
16922 : EnsureCapacity(Handle<NameDictionary>, int, Handle<Name>);
16923 :
16924 : template int HashTable<SeededNumberDictionary, SeededNumberDictionaryShape,
16925 : uint32_t>::FindEntry(uint32_t);
16926 :
16927 : template int NameDictionaryBase<NameDictionary, NameDictionaryShape>::FindEntry(
16928 : Handle<Name>);
16929 :
16930 : template int Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
16931 : NumberOfElementsFilterAttributes(PropertyFilter filter);
16932 :
16933 : template int Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::
16934 : NumberOfElementsFilterAttributes(PropertyFilter filter);
16935 :
16936 : template void
16937 : Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
16938 : CopyEnumKeysTo(Handle<Dictionary<GlobalDictionary, GlobalDictionaryShape,
16939 : Handle<Name>>>
16940 : dictionary,
16941 : Handle<FixedArray> storage, KeyCollectionMode mode,
16942 : KeyAccumulator* accumulator);
16943 :
16944 : template void
16945 : Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::CopyEnumKeysTo(
16946 : Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>>
16947 : dictionary,
16948 : Handle<FixedArray> storage, KeyCollectionMode mode,
16949 : KeyAccumulator* accumulator);
16950 :
16951 : template Handle<FixedArray>
16952 : Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
16953 : IterationIndices(
16954 : Handle<
16955 : Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>>
16956 : dictionary);
16957 : template void
16958 : Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
16959 : CollectKeysTo(Handle<Dictionary<GlobalDictionary, GlobalDictionaryShape,
16960 : Handle<Name>>>
16961 : dictionary,
16962 : KeyAccumulator* keys);
16963 :
16964 : template Handle<FixedArray>
16965 : Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::IterationIndices(
16966 : Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>>
16967 : dictionary);
16968 : template void
16969 : Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::CollectKeysTo(
16970 : Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>>
16971 : dictionary,
16972 : KeyAccumulator* keys);
16973 :
16974 103 : Handle<Object> JSObject::PrepareSlowElementsForSort(
16975 : Handle<JSObject> object, uint32_t limit) {
16976 : DCHECK(object->HasDictionaryElements());
16977 : Isolate* isolate = object->GetIsolate();
16978 : // Must stay in dictionary mode, either because of requires_slow_elements,
16979 : // or because we are not going to sort (and therefore compact) all of the
16980 : // elements.
16981 : Handle<SeededNumberDictionary> dict(object->element_dictionary(), isolate);
16982 : Handle<SeededNumberDictionary> new_dict =
16983 103 : SeededNumberDictionary::New(isolate, dict->NumberOfElements());
16984 :
16985 : uint32_t pos = 0;
16986 : uint32_t undefs = 0;
16987 : int capacity = dict->Capacity();
16988 : Handle<Smi> bailout(Smi::FromInt(-1), isolate);
16989 : // Entry to the new dictionary does not cause it to grow, as we have
16990 : // allocated one that is large enough for all entries.
16991 : DisallowHeapAllocation no_gc;
16992 429 : for (int i = 0; i < capacity; i++) {
16993 : Object* k = dict->KeyAt(i);
16994 385 : if (!dict->IsKey(isolate, k)) continue;
16995 :
16996 : DCHECK(k->IsNumber());
16997 : DCHECK(!k->IsSmi() || Smi::cast(k)->value() >= 0);
16998 : DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
16999 : DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
17000 :
17001 : HandleScope scope(isolate);
17002 238 : Handle<Object> value(dict->ValueAt(i), isolate);
17003 : PropertyDetails details = dict->DetailsAt(i);
17004 432 : if (details.kind() == kAccessor || details.IsReadOnly()) {
17005 : // Bail out and do the sorting of undefineds and array holes in JS.
17006 : // Also bail out if the element is not supposed to be moved.
17007 44 : return bailout;
17008 : }
17009 :
17010 194 : uint32_t key = NumberToUint32(k);
17011 194 : if (key < limit) {
17012 164 : if (value->IsUndefined(isolate)) {
17013 15 : undefs++;
17014 149 : } else if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
17015 : // Adding an entry with the key beyond smi-range requires
17016 : // allocation. Bailout.
17017 0 : return bailout;
17018 : } else {
17019 : Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
17020 149 : new_dict, pos, value, details, object);
17021 : DCHECK(result.is_identical_to(new_dict));
17022 : USE(result);
17023 149 : pos++;
17024 : }
17025 30 : } else if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
17026 : // Adding an entry with the key beyond smi-range requires
17027 : // allocation. Bailout.
17028 15 : return bailout;
17029 : } else {
17030 : Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
17031 15 : new_dict, key, value, details, object);
17032 : DCHECK(result.is_identical_to(new_dict));
17033 : USE(result);
17034 : }
17035 : }
17036 :
17037 : uint32_t result = pos;
17038 44 : PropertyDetails no_details = PropertyDetails::Empty();
17039 103 : while (undefs > 0) {
17040 15 : if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
17041 : // Adding an entry with the key beyond smi-range requires
17042 : // allocation. Bailout.
17043 0 : return bailout;
17044 : }
17045 : HandleScope scope(isolate);
17046 : Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
17047 : new_dict, pos, isolate->factory()->undefined_value(), no_details,
17048 15 : object);
17049 : DCHECK(result.is_identical_to(new_dict));
17050 : USE(result);
17051 15 : pos++;
17052 15 : undefs--;
17053 : }
17054 :
17055 44 : object->set_elements(*new_dict);
17056 :
17057 : AllowHeapAllocation allocate_return_value;
17058 44 : return isolate->factory()->NewNumberFromUint(result);
17059 : }
17060 :
17061 :
17062 : // Collects all defined (non-hole) and non-undefined (array) elements at
17063 : // the start of the elements array.
17064 : // If the object is in dictionary mode, it is converted to fast elements
17065 : // mode.
17066 126632 : Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object,
17067 : uint32_t limit) {
17068 : Isolate* isolate = object->GetIsolate();
17069 253234 : if (object->HasSloppyArgumentsElements() || !object->map()->is_extensible()) {
17070 105 : return handle(Smi::FromInt(-1), isolate);
17071 : }
17072 :
17073 126527 : if (object->HasStringWrapperElements()) {
17074 : int len = String::cast(Handle<JSValue>::cast(object)->value())->length();
17075 15 : return handle(Smi::FromInt(len), isolate);
17076 : }
17077 :
17078 126512 : if (object->HasDictionaryElements()) {
17079 : // Convert to fast elements containing only the existing properties.
17080 : // Ordering is irrelevant, since we are going to sort anyway.
17081 : Handle<SeededNumberDictionary> dict(object->element_dictionary());
17082 342 : if (object->IsJSArray() || dict->requires_slow_elements() ||
17083 60 : dict->max_number_key() >= limit) {
17084 103 : return JSObject::PrepareSlowElementsForSort(object, limit);
17085 : }
17086 : // Convert to fast elements.
17087 :
17088 : Handle<Map> new_map =
17089 60 : JSObject::GetElementsTransitionMap(object, FAST_HOLEY_ELEMENTS);
17090 :
17091 : PretenureFlag tenure = isolate->heap()->InNewSpace(*object) ?
17092 60 : NOT_TENURED: TENURED;
17093 : Handle<FixedArray> fast_elements =
17094 60 : isolate->factory()->NewFixedArray(dict->NumberOfElements(), tenure);
17095 60 : dict->CopyValuesTo(*fast_elements);
17096 : JSObject::ValidateElements(object);
17097 :
17098 60 : JSObject::SetMapAndElements(object, new_map, fast_elements);
17099 126349 : } else if (object->HasFixedTypedArrayElements()) {
17100 : // Typed arrays cannot have holes or undefined elements.
17101 : return handle(Smi::FromInt(
17102 141 : FixedArrayBase::cast(object->elements())->length()), isolate);
17103 126208 : } else if (!object->HasFastDoubleElements()) {
17104 126151 : EnsureWritableFastElements(object);
17105 : }
17106 : DCHECK(object->HasFastSmiOrObjectElements() ||
17107 : object->HasFastDoubleElements());
17108 :
17109 : // Collect holes at the end, undefined before that and the rest at the
17110 : // start, and return the number of non-hole, non-undefined values.
17111 :
17112 : Handle<FixedArrayBase> elements_base(object->elements());
17113 126268 : uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
17114 126268 : if (limit > elements_length) {
17115 : limit = elements_length;
17116 : }
17117 126268 : if (limit == 0) {
17118 15 : return handle(Smi::kZero, isolate);
17119 : }
17120 :
17121 : uint32_t result = 0;
17122 126253 : if (elements_base->map() == isolate->heap()->fixed_double_array_map()) {
17123 : FixedDoubleArray* elements = FixedDoubleArray::cast(*elements_base);
17124 : // Split elements into defined and the_hole, in that order.
17125 : unsigned int holes = limit;
17126 : // Assume most arrays contain no holes and undefined values, so minimize the
17127 : // number of stores of non-undefined, non-the-hole values.
17128 5915 : for (unsigned int i = 0; i < holes; i++) {
17129 11716 : if (elements->is_the_hole(i)) {
17130 0 : holes--;
17131 : } else {
17132 : continue;
17133 : }
17134 : // Position i needs to be filled.
17135 0 : while (holes > i) {
17136 0 : if (elements->is_the_hole(holes)) {
17137 0 : holes--;
17138 : } else {
17139 : elements->set(i, elements->get_scalar(holes));
17140 : break;
17141 : }
17142 : }
17143 : }
17144 : result = holes;
17145 57 : while (holes < limit) {
17146 0 : elements->set_the_hole(holes);
17147 0 : holes++;
17148 : }
17149 : } else {
17150 : FixedArray* elements = FixedArray::cast(*elements_base);
17151 : DisallowHeapAllocation no_gc;
17152 :
17153 : // Split elements into defined, undefined and the_hole, in that order. Only
17154 : // count locations for undefined and the hole, and fill them afterwards.
17155 126196 : WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_gc);
17156 : unsigned int undefs = limit;
17157 : unsigned int holes = limit;
17158 : // Assume most arrays contain no holes and undefined values, so minimize the
17159 : // number of stores of non-undefined, non-the-hole values.
17160 5889831 : for (unsigned int i = 0; i < undefs; i++) {
17161 5763635 : Object* current = elements->get(i);
17162 5763635 : if (current->IsTheHole(isolate)) {
17163 31206 : holes--;
17164 31206 : undefs--;
17165 5732429 : } else if (current->IsUndefined(isolate)) {
17166 1136 : undefs--;
17167 : } else {
17168 : continue;
17169 : }
17170 : // Position i needs to be filled.
17171 7706829 : while (undefs > i) {
17172 7706137 : current = elements->get(undefs);
17173 7706137 : if (current->IsTheHole(isolate)) {
17174 7673296 : holes--;
17175 7673296 : undefs--;
17176 32841 : } else if (current->IsUndefined(isolate)) {
17177 1191 : undefs--;
17178 : } else {
17179 31650 : elements->set(i, current, write_barrier);
17180 31650 : break;
17181 : }
17182 : }
17183 : }
17184 : result = undefs;
17185 128523 : while (undefs < holes) {
17186 2327 : elements->set_undefined(isolate, undefs);
17187 2327 : undefs++;
17188 : }
17189 7830698 : while (holes < limit) {
17190 7704502 : elements->set_the_hole(isolate, holes);
17191 7704502 : holes++;
17192 : }
17193 : }
17194 :
17195 126253 : return isolate->factory()->NewNumberFromUint(result);
17196 : }
17197 :
17198 : namespace {
17199 :
17200 4492 : bool CanonicalNumericIndexString(Isolate* isolate, Handle<Object> s,
17201 : Handle<Object>* index) {
17202 : DCHECK(s->IsString() || s->IsSmi());
17203 :
17204 : Handle<Object> result;
17205 4492 : if (s->IsSmi()) {
17206 : result = s;
17207 : } else {
17208 4464 : result = String::ToNumber(Handle<String>::cast(s));
17209 4464 : if (!result->IsMinusZero()) {
17210 8900 : Handle<String> str = Object::ToString(isolate, result).ToHandleChecked();
17211 : // Avoid treating strings like "2E1" and "20" as the same key.
17212 4450 : if (!str->SameValue(*s)) return false;
17213 : }
17214 : }
17215 275 : *index = result;
17216 275 : return true;
17217 : }
17218 :
17219 : } // anonymous namespace
17220 :
17221 : // ES#sec-integer-indexed-exotic-objects-defineownproperty-p-desc
17222 : // static
17223 4786 : Maybe<bool> JSTypedArray::DefineOwnProperty(Isolate* isolate,
17224 : Handle<JSTypedArray> o,
17225 : Handle<Object> key,
17226 : PropertyDescriptor* desc,
17227 : ShouldThrow should_throw) {
17228 : // 1. Assert: IsPropertyKey(P) is true.
17229 : DCHECK(key->IsName() || key->IsNumber());
17230 : // 2. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot.
17231 : // 3. If Type(P) is String, then
17232 5108 : if (key->IsString() || key->IsSmi()) {
17233 : // 3a. Let numericIndex be ! CanonicalNumericIndexString(P)
17234 : // 3b. If numericIndex is not undefined, then
17235 : Handle<Object> numeric_index;
17236 4492 : if (CanonicalNumericIndexString(isolate, key, &numeric_index)) {
17237 : // 3b i. If IsInteger(numericIndex) is false, return false.
17238 : // 3b ii. If numericIndex = -0, return false.
17239 : // 3b iii. If numericIndex < 0, return false.
17240 : // FIXME: the standard allows up to 2^53 elements.
17241 : uint32_t index;
17242 536 : if (numeric_index->IsMinusZero() || !numeric_index->ToUint32(&index)) {
17243 126 : RETURN_FAILURE(isolate, should_throw,
17244 : NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
17245 : }
17246 : // 3b iv. Let length be O.[[ArrayLength]].
17247 233 : uint32_t length = o->length()->Number();
17248 : // 3b v. If numericIndex ≥ length, return false.
17249 233 : if (index >= length) {
17250 42 : RETURN_FAILURE(isolate, should_throw,
17251 : NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
17252 : }
17253 : // 3b vi. If IsAccessorDescriptor(Desc) is true, return false.
17254 219 : if (PropertyDescriptor::IsAccessorDescriptor(desc)) {
17255 234 : RETURN_FAILURE(isolate, should_throw,
17256 : NewTypeError(MessageTemplate::kRedefineDisallowed, key));
17257 : }
17258 : // 3b vii. If Desc has a [[Configurable]] field and if
17259 : // Desc.[[Configurable]] is true, return false.
17260 : // 3b viii. If Desc has an [[Enumerable]] field and if Desc.[[Enumerable]]
17261 : // is false, return false.
17262 : // 3b ix. If Desc has a [[Writable]] field and if Desc.[[Writable]] is
17263 : // false, return false.
17264 30 : if ((desc->has_configurable() && desc->configurable()) ||
17265 30 : (desc->has_enumerable() && !desc->enumerable()) ||
17266 15 : (desc->has_writable() && !desc->writable())) {
17267 45 : RETURN_FAILURE(isolate, should_throw,
17268 : NewTypeError(MessageTemplate::kRedefineDisallowed, key));
17269 : }
17270 : // 3b x. If Desc has a [[Value]] field, then
17271 : // 3b x 1. Let value be Desc.[[Value]].
17272 : // 3b x 2. Return ? IntegerIndexedElementSet(O, numericIndex, value).
17273 0 : if (desc->has_value()) {
17274 0 : if (!desc->has_configurable()) desc->set_configurable(false);
17275 0 : if (!desc->has_enumerable()) desc->set_enumerable(true);
17276 0 : if (!desc->has_writable()) desc->set_writable(true);
17277 0 : Handle<Object> value = desc->value();
17278 0 : RETURN_ON_EXCEPTION_VALUE(isolate,
17279 : SetOwnElementIgnoreAttributes(
17280 : o, index, value, desc->ToAttributes()),
17281 : Nothing<bool>());
17282 : }
17283 : // 3b xi. Return true.
17284 : return Just(true);
17285 : }
17286 : }
17287 : // 4. Return ! OrdinaryDefineOwnProperty(O, P, Desc).
17288 4511 : return OrdinaryDefineOwnProperty(isolate, o, key, desc, should_throw);
17289 : }
17290 :
17291 18988096 : ExternalArrayType JSTypedArray::type() {
17292 18988096 : switch (elements()->map()->instance_type()) {
17293 : #define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype, size) \
17294 : case FIXED_##TYPE##_ARRAY_TYPE: \
17295 : return kExternal##Type##Array;
17296 :
17297 5939 : TYPED_ARRAYS(INSTANCE_TYPE_TO_ARRAY_TYPE)
17298 : #undef INSTANCE_TYPE_TO_ARRAY_TYPE
17299 :
17300 : default:
17301 0 : UNREACHABLE();
17302 : return static_cast<ExternalArrayType>(-1);
17303 : }
17304 : }
17305 :
17306 :
17307 15924 : size_t JSTypedArray::element_size() {
17308 15924 : switch (elements()->map()->instance_type()) {
17309 : #define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype, size) \
17310 : case FIXED_##TYPE##_ARRAY_TYPE: \
17311 : return size;
17312 :
17313 1013 : TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE)
17314 : #undef INSTANCE_TYPE_TO_ELEMENT_SIZE
17315 :
17316 : default:
17317 0 : UNREACHABLE();
17318 : return 0;
17319 : }
17320 : }
17321 :
17322 :
17323 326473 : void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global,
17324 : Handle<Name> name) {
17325 : DCHECK(!global->HasFastProperties());
17326 : auto dictionary = handle(global->global_dictionary());
17327 326473 : int entry = dictionary->FindEntry(name);
17328 652946 : if (entry == GlobalDictionary::kNotFound) return;
17329 90 : PropertyCell::InvalidateEntry(dictionary, entry);
17330 : }
17331 :
17332 8831220 : Handle<PropertyCell> JSGlobalObject::EnsureEmptyPropertyCell(
17333 : Handle<JSGlobalObject> global, Handle<Name> name,
17334 : PropertyCellType cell_type, int* entry_out) {
17335 : Isolate* isolate = global->GetIsolate();
17336 : DCHECK(!global->HasFastProperties());
17337 : Handle<GlobalDictionary> dictionary(global->global_dictionary(), isolate);
17338 8831220 : int entry = dictionary->FindEntry(name);
17339 : Handle<PropertyCell> cell;
17340 8831222 : if (entry != GlobalDictionary::kNotFound) {
17341 6491 : if (entry_out) *entry_out = entry;
17342 : // This call should be idempotent.
17343 : DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
17344 6491 : cell = handle(PropertyCell::cast(dictionary->ValueAt(entry)));
17345 : PropertyCellType original_cell_type = cell->property_details().cell_type();
17346 : DCHECK(original_cell_type == PropertyCellType::kInvalidated ||
17347 : original_cell_type == PropertyCellType::kUninitialized);
17348 : DCHECK(cell->value()->IsTheHole(isolate));
17349 6491 : if (original_cell_type == PropertyCellType::kInvalidated) {
17350 2427 : cell = PropertyCell::InvalidateEntry(dictionary, entry);
17351 : }
17352 : PropertyDetails details(kData, NONE, 0, cell_type);
17353 : cell->set_property_details(details);
17354 6491 : return cell;
17355 : }
17356 8824731 : cell = isolate->factory()->NewPropertyCell();
17357 : PropertyDetails details(kData, NONE, 0, cell_type);
17358 : dictionary =
17359 8824730 : GlobalDictionary::Add(dictionary, name, cell, details, entry_out);
17360 : // {*entry_out} is initialized inside GlobalDictionary::Add().
17361 8824729 : global->set_properties(*dictionary);
17362 8824731 : return cell;
17363 : }
17364 :
17365 :
17366 : // This class is used for looking up two character strings in the string table.
17367 : // If we don't have a hit we don't want to waste much time so we unroll the
17368 : // string hash calculation loop here for speed. Doesn't work if the two
17369 : // characters form a decimal integer, since such strings have a different hash
17370 : // algorithm.
17371 0 : class TwoCharHashTableKey : public HashTableKey {
17372 : public:
17373 7323327 : TwoCharHashTableKey(uint16_t c1, uint16_t c2, uint32_t seed)
17374 7323327 : : c1_(c1), c2_(c2) {
17375 : // Char 1.
17376 : uint32_t hash = seed;
17377 7323327 : hash += c1;
17378 7323327 : hash += hash << 10;
17379 7323327 : hash ^= hash >> 6;
17380 : // Char 2.
17381 7323327 : hash += c2;
17382 7323327 : hash += hash << 10;
17383 7323327 : hash ^= hash >> 6;
17384 : // GetHash.
17385 7323327 : hash += hash << 3;
17386 7323327 : hash ^= hash >> 11;
17387 7323327 : hash += hash << 15;
17388 7323327 : if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash;
17389 7323327 : hash_ = hash;
17390 : #ifdef DEBUG
17391 : // If this assert fails then we failed to reproduce the two-character
17392 : // version of the string hashing algorithm above. One reason could be
17393 : // that we were passed two digits as characters, since the hash
17394 : // algorithm is different in that case.
17395 : uint16_t chars[2] = {c1, c2};
17396 : uint32_t check_hash = StringHasher::HashSequentialString(chars, 2, seed);
17397 : hash = (hash << String::kHashShift) | String::kIsNotArrayIndexMask;
17398 : DCHECK_EQ(static_cast<int32_t>(hash), static_cast<int32_t>(check_hash));
17399 : #endif
17400 7323327 : }
17401 :
17402 2099647 : bool IsMatch(Object* o) override {
17403 2099647 : if (!o->IsString()) return false;
17404 : String* other = String::cast(o);
17405 2099647 : if (other->length() != 2) return false;
17406 472959 : if (other->Get(0) != c1_) return false;
17407 22121 : return other->Get(1) == c2_;
17408 : }
17409 :
17410 7323327 : uint32_t Hash() override { return hash_; }
17411 0 : uint32_t HashForObject(Object* key) override {
17412 0 : if (!key->IsString()) return 0;
17413 0 : return String::cast(key)->Hash();
17414 : }
17415 :
17416 0 : Handle<Object> AsHandle(Isolate* isolate) override {
17417 : // The TwoCharHashTableKey is only used for looking in the string
17418 : // table, not for adding to it.
17419 0 : UNREACHABLE();
17420 : return MaybeHandle<Object>().ToHandleChecked();
17421 : }
17422 :
17423 : private:
17424 : uint16_t c1_;
17425 : uint16_t c2_;
17426 : uint32_t hash_;
17427 : };
17428 :
17429 :
17430 4258708 : MaybeHandle<String> StringTable::InternalizeStringIfExists(
17431 : Isolate* isolate,
17432 : Handle<String> string) {
17433 4258709 : if (string->IsInternalizedString()) {
17434 : return string;
17435 : }
17436 0 : if (string->IsThinString()) {
17437 : return handle(Handle<ThinString>::cast(string)->actual(), isolate);
17438 : }
17439 0 : return LookupStringIfExists(isolate, string);
17440 : }
17441 :
17442 :
17443 0 : MaybeHandle<String> StringTable::LookupStringIfExists(
17444 : Isolate* isolate,
17445 : Handle<String> string) {
17446 : Handle<StringTable> string_table = isolate->factory()->string_table();
17447 : InternalizedStringKey key(string);
17448 : int entry = string_table->FindEntry(&key);
17449 0 : if (entry == kNotFound) {
17450 : return MaybeHandle<String>();
17451 : } else {
17452 : Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
17453 : DCHECK(StringShape(*result).IsInternalized());
17454 : return result;
17455 : }
17456 : }
17457 :
17458 :
17459 7323327 : MaybeHandle<String> StringTable::LookupTwoCharsStringIfExists(
17460 : Isolate* isolate,
17461 : uint16_t c1,
17462 : uint16_t c2) {
17463 : Handle<StringTable> string_table = isolate->factory()->string_table();
17464 7323327 : TwoCharHashTableKey key(c1, c2, isolate->heap()->HashSeed());
17465 : int entry = string_table->FindEntry(&key);
17466 7323327 : if (entry == kNotFound) {
17467 : return MaybeHandle<String>();
17468 : } else {
17469 : Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
17470 : DCHECK(StringShape(*result).IsInternalized());
17471 : return result;
17472 : }
17473 : }
17474 :
17475 :
17476 385 : void StringTable::EnsureCapacityForDeserialization(Isolate* isolate,
17477 : int expected) {
17478 : Handle<StringTable> table = isolate->factory()->string_table();
17479 : // We need a key instance for the virtual hash function.
17480 : InternalizedStringKey dummy_key(isolate->factory()->empty_string());
17481 385 : table = StringTable::EnsureCapacity(table, expected, &dummy_key);
17482 : isolate->heap()->SetRootStringTable(*table);
17483 385 : }
17484 :
17485 : namespace {
17486 :
17487 : template <class StringClass>
17488 20 : void MigrateExternalStringResource(Isolate* isolate, String* from, String* to) {
17489 : StringClass* cast_from = StringClass::cast(from);
17490 : StringClass* cast_to = StringClass::cast(to);
17491 : const typename StringClass::Resource* to_resource = cast_to->resource();
17492 20 : if (to_resource == nullptr) {
17493 : // |to| is a just-created internalized copy of |from|. Migrate the resource.
17494 : cast_to->set_resource(cast_from->resource());
17495 : // Zap |from|'s resource pointer to reflect the fact that |from| has
17496 : // relinquished ownership of its resource.
17497 : cast_from->set_resource(nullptr);
17498 14 : } else if (to_resource != cast_from->resource()) {
17499 : // |to| already existed and has its own resource. Finalize |from|.
17500 : isolate->heap()->FinalizeExternalString(from);
17501 : }
17502 20 : }
17503 :
17504 9701951 : void MakeStringThin(String* string, String* internalized, Isolate* isolate) {
17505 9701951 : if (string->IsExternalString()) {
17506 20 : if (internalized->IsExternalOneByteString()) {
17507 : MigrateExternalStringResource<ExternalOneByteString>(isolate, string,
17508 11 : internalized);
17509 9 : } else if (internalized->IsExternalTwoByteString()) {
17510 : MigrateExternalStringResource<ExternalTwoByteString>(isolate, string,
17511 9 : internalized);
17512 : } else {
17513 : // If the external string is duped into an existing non-external
17514 : // internalized string, free its resource (it's about to be rewritten
17515 : // into a ThinString below).
17516 : isolate->heap()->FinalizeExternalString(string);
17517 : }
17518 : }
17519 :
17520 9701951 : if (!string->IsInternalizedString()) {
17521 : DisallowHeapAllocation no_gc;
17522 : bool one_byte = internalized->IsOneByteRepresentation();
17523 : Handle<Map> map = one_byte ? isolate->factory()->thin_one_byte_string_map()
17524 9694333 : : isolate->factory()->thin_string_map();
17525 9694333 : int old_size = string->Size();
17526 : DCHECK(old_size >= ThinString::kSize);
17527 9694333 : string->synchronized_set_map(*map);
17528 : ThinString* thin = ThinString::cast(string);
17529 9694333 : thin->set_actual(internalized);
17530 9694333 : Address thin_end = thin->address() + ThinString::kSize;
17531 9694333 : int size_delta = old_size - ThinString::kSize;
17532 9694333 : if (size_delta != 0) {
17533 2394967 : Heap* heap = isolate->heap();
17534 2394967 : heap->CreateFillerObjectAt(thin_end, size_delta, ClearRecordedSlots::kNo);
17535 2394967 : heap->AdjustLiveBytes(thin, -size_delta);
17536 : }
17537 : }
17538 9701951 : }
17539 :
17540 : } // namespace
17541 :
17542 23395027 : Handle<String> StringTable::LookupString(Isolate* isolate,
17543 : Handle<String> string) {
17544 23395028 : if (string->IsThinString()) {
17545 : DCHECK(Handle<ThinString>::cast(string)->actual()->IsInternalizedString());
17546 : return handle(Handle<ThinString>::cast(string)->actual(), isolate);
17547 : }
17548 23339000 : if (string->IsConsString() && string->IsFlat()) {
17549 : string = handle(Handle<ConsString>::cast(string)->first(), isolate);
17550 24882 : if (string->IsInternalizedString()) return string;
17551 : }
17552 :
17553 : InternalizedStringKey key(string);
17554 22837392 : Handle<String> result = LookupKey(isolate, &key);
17555 :
17556 22837394 : if (FLAG_thin_strings) {
17557 9676445 : MakeStringThin(*string, *result, isolate);
17558 : } else { // !FLAG_thin_strings
17559 13160949 : if (string->IsConsString()) {
17560 : Handle<ConsString> cons = Handle<ConsString>::cast(string);
17561 193003 : cons->set_first(*result);
17562 386006 : cons->set_second(isolate->heap()->empty_string());
17563 12967946 : } else if (string->IsSlicedString()) {
17564 : STATIC_ASSERT(ConsString::kSize == SlicedString::kSize);
17565 : DisallowHeapAllocation no_gc;
17566 : bool one_byte = result->IsOneByteRepresentation();
17567 : Handle<Map> map = one_byte
17568 : ? isolate->factory()->cons_one_byte_string_map()
17569 24790 : : isolate->factory()->cons_string_map();
17570 24790 : string->set_map(*map);
17571 : Handle<ConsString> cons = Handle<ConsString>::cast(string);
17572 24790 : cons->set_first(*result);
17573 49580 : cons->set_second(isolate->heap()->empty_string());
17574 : }
17575 : }
17576 22837394 : return result;
17577 : }
17578 :
17579 :
17580 89018469 : Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) {
17581 : Handle<StringTable> table = isolate->factory()->string_table();
17582 : int entry = table->FindEntry(key);
17583 :
17584 : // String already in table.
17585 89018534 : if (entry != kNotFound) {
17586 : return handle(String::cast(table->KeyAt(entry)), isolate);
17587 : }
17588 :
17589 : // Adding new string. Grow table if needed.
17590 13100099 : table = StringTable::EnsureCapacity(table, 1, key);
17591 :
17592 : // Create string object.
17593 13100099 : Handle<Object> string = key->AsHandle(isolate);
17594 : // There must be no attempts to internalize strings that could throw
17595 : // InvalidStringLength error.
17596 13100095 : CHECK(!string.is_null());
17597 :
17598 : // Add the new string and return it along with the string table.
17599 26200192 : entry = table->FindInsertionEntry(key->Hash());
17600 13100096 : table->set(EntryToIndex(entry), *string);
17601 13100097 : table->ElementAdded();
17602 :
17603 : isolate->heap()->SetRootStringTable(*table);
17604 : return Handle<String>::cast(string);
17605 : }
17606 :
17607 : namespace {
17608 :
17609 : class StringTableNoAllocateKey : public HashTableKey {
17610 : public:
17611 25653 : StringTableNoAllocateKey(String* string, uint32_t seed)
17612 51306 : : string_(string), length_(string->length()) {
17613 : StringShape shape(string);
17614 25653 : one_byte_ = shape.HasOnlyOneByteChars();
17615 : DCHECK(!shape.IsInternalized());
17616 : DCHECK(!shape.IsThin());
17617 25653 : if (shape.IsCons() && length_ <= String::kMaxHashCalcLength) {
17618 0 : special_flattening_ = true;
17619 : uint32_t hash_field = 0;
17620 0 : if (one_byte_) {
17621 0 : one_byte_content_ = new uint8_t[length_];
17622 0 : String::WriteToFlat(string, one_byte_content_, 0, length_);
17623 : hash_field = StringHasher::HashSequentialString(one_byte_content_,
17624 0 : length_, seed);
17625 : } else {
17626 0 : two_byte_content_ = new uint16_t[length_];
17627 0 : String::WriteToFlat(string, two_byte_content_, 0, length_);
17628 : hash_field = StringHasher::HashSequentialString(two_byte_content_,
17629 0 : length_, seed);
17630 : }
17631 : string->set_hash_field(hash_field);
17632 : } else {
17633 25653 : special_flattening_ = false;
17634 25653 : one_byte_content_ = nullptr;
17635 : }
17636 25653 : hash_ = string->Hash();
17637 25653 : }
17638 :
17639 25653 : ~StringTableNoAllocateKey() {
17640 25653 : if (one_byte_) {
17641 23349 : delete[] one_byte_content_;
17642 : } else {
17643 2304 : delete[] two_byte_content_;
17644 : }
17645 25653 : }
17646 :
17647 45282 : bool IsMatch(Object* otherstring) override {
17648 : String* other = String::cast(otherstring);
17649 : DCHECK(other->IsInternalizedString());
17650 : DCHECK(other->IsFlat());
17651 90564 : if (hash_ != other->Hash()) return false;
17652 25542 : int len = length_;
17653 25542 : if (len != other->length()) return false;
17654 :
17655 25542 : if (!special_flattening_) {
17656 51084 : if (string_->Get(0) != other->Get(0)) return false;
17657 25542 : if (string_->IsFlat()) {
17658 25542 : StringShape shape1(string_);
17659 : StringShape shape2(other);
17660 48780 : if (shape1.encoding_tag() == kOneByteStringTag &&
17661 : shape2.encoding_tag() == kOneByteStringTag) {
17662 23238 : String::FlatContent flat1 = string_->GetFlatContent();
17663 23238 : String::FlatContent flat2 = other->GetFlatContent();
17664 23238 : return CompareRawStringContents(flat1.ToOneByteVector().start(),
17665 23238 : flat2.ToOneByteVector().start(), len);
17666 : }
17667 4608 : if (shape1.encoding_tag() == kTwoByteStringTag &&
17668 : shape2.encoding_tag() == kTwoByteStringTag) {
17669 2304 : String::FlatContent flat1 = string_->GetFlatContent();
17670 2304 : String::FlatContent flat2 = other->GetFlatContent();
17671 2304 : return CompareRawStringContents(flat1.ToUC16Vector().start(),
17672 2304 : flat2.ToUC16Vector().start(), len);
17673 : }
17674 : }
17675 : StringComparator comparator;
17676 0 : return comparator.Equals(string_, other);
17677 : }
17678 :
17679 0 : String::FlatContent flat_content = other->GetFlatContent();
17680 0 : if (one_byte_) {
17681 0 : if (flat_content.IsOneByte()) {
17682 : return CompareRawStringContents(
17683 0 : one_byte_content_, flat_content.ToOneByteVector().start(), len);
17684 : } else {
17685 : DCHECK(flat_content.IsTwoByte());
17686 0 : for (int i = 0; i < len; i++) {
17687 0 : if (flat_content.Get(i) != one_byte_content_[i]) return false;
17688 : }
17689 : return true;
17690 : }
17691 : } else {
17692 0 : if (flat_content.IsTwoByte()) {
17693 : return CompareRawStringContents(
17694 0 : two_byte_content_, flat_content.ToUC16Vector().start(), len);
17695 : } else {
17696 : DCHECK(flat_content.IsOneByte());
17697 0 : for (int i = 0; i < len; i++) {
17698 0 : if (flat_content.Get(i) != two_byte_content_[i]) return false;
17699 : }
17700 : return true;
17701 : }
17702 : }
17703 : }
17704 :
17705 25653 : uint32_t Hash() override { return hash_; }
17706 :
17707 0 : uint32_t HashForObject(Object* key) override {
17708 0 : return String::cast(key)->Hash();
17709 : }
17710 :
17711 0 : MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) override {
17712 0 : UNREACHABLE();
17713 : return Handle<String>();
17714 : }
17715 :
17716 : private:
17717 : String* string_;
17718 : int length_;
17719 : bool one_byte_;
17720 : bool special_flattening_;
17721 : uint32_t hash_ = 0;
17722 : union {
17723 : uint8_t* one_byte_content_;
17724 : uint16_t* two_byte_content_;
17725 : };
17726 : };
17727 :
17728 : } // namespace
17729 :
17730 : // static
17731 25653 : Object* StringTable::LookupStringIfExists_NoAllocate(String* string) {
17732 : DisallowHeapAllocation no_gc;
17733 25653 : Heap* heap = string->GetHeap();
17734 : Isolate* isolate = heap->isolate();
17735 : StringTable* table = heap->string_table();
17736 :
17737 25653 : StringTableNoAllocateKey key(string, heap->HashSeed());
17738 :
17739 : // String could be an array index.
17740 : DCHECK(string->HasHashCode());
17741 : uint32_t hash = string->hash_field();
17742 :
17743 : // Valid array indices are >= 0, so they cannot be mixed up with any of
17744 : // the result sentinels, which are negative.
17745 : STATIC_ASSERT(
17746 : !String::ArrayIndexValueBits::is_valid(ResultSentinel::kUnsupported));
17747 : STATIC_ASSERT(
17748 : !String::ArrayIndexValueBits::is_valid(ResultSentinel::kNotFound));
17749 :
17750 25653 : if ((hash & Name::kContainsCachedArrayIndexMask) == 0) {
17751 0 : return Smi::FromInt(String::ArrayIndexValueBits::decode(hash));
17752 : }
17753 25653 : if ((hash & Name::kIsNotArrayIndexMask) == 0) {
17754 : // It is an indexed, but it's not cached.
17755 : return Smi::FromInt(ResultSentinel::kUnsupported);
17756 : }
17757 :
17758 25653 : int entry = table->FindEntry(isolate, &key, key.Hash());
17759 25653 : if (entry != kNotFound) {
17760 : String* internalized = String::cast(table->KeyAt(entry));
17761 25542 : if (FLAG_thin_strings) {
17762 25506 : MakeStringThin(string, internalized, isolate);
17763 : }
17764 25542 : return internalized;
17765 : }
17766 : // A string that's not an array index, and not in the string table,
17767 : // cannot have been used as a property name before.
17768 25653 : return Smi::FromInt(ResultSentinel::kNotFound);
17769 : }
17770 :
17771 7460 : String* StringTable::LookupKeyIfExists(Isolate* isolate, HashTableKey* key) {
17772 : Handle<StringTable> table = isolate->factory()->string_table();
17773 7460 : int entry = table->FindEntry(isolate, key);
17774 10216 : if (entry != kNotFound) return String::cast(table->KeyAt(entry));
17775 : return NULL;
17776 : }
17777 :
17778 195518 : Handle<StringSet> StringSet::New(Isolate* isolate) {
17779 195518 : return HashTable::New(isolate, 0);
17780 : }
17781 :
17782 2616926 : Handle<StringSet> StringSet::Add(Handle<StringSet> stringset,
17783 : Handle<String> name) {
17784 2616926 : if (!stringset->Has(name)) {
17785 172174 : stringset = EnsureCapacity(stringset, 1, *name);
17786 : uint32_t hash = StringSetShape::Hash(*name);
17787 172174 : int entry = stringset->FindInsertionEntry(hash);
17788 172174 : stringset->set(EntryToIndex(entry), *name);
17789 172174 : stringset->ElementAdded();
17790 : }
17791 2616926 : return stringset;
17792 : }
17793 :
17794 2636824 : bool StringSet::Has(Handle<String> name) {
17795 2636824 : return FindEntry(*name) != kNotFound;
17796 : }
17797 :
17798 16025435 : Handle<ObjectHashSet> ObjectHashSet::Add(Handle<ObjectHashSet> set,
17799 : Handle<Object> key) {
17800 : Isolate* isolate = set->GetIsolate();
17801 16025435 : int32_t hash = Object::GetOrCreateHash(isolate, key)->value();
17802 :
17803 16025435 : if (!set->Has(isolate, key, hash)) {
17804 16023124 : set = EnsureCapacity(set, 1, key);
17805 32046248 : int entry = set->FindInsertionEntry(hash);
17806 16023124 : set->set(EntryToIndex(entry), *key);
17807 16023124 : set->ElementAdded();
17808 : }
17809 16025435 : return set;
17810 : }
17811 :
17812 0 : Handle<Object> CompilationCacheTable::Lookup(Handle<String> src,
17813 : Handle<Context> context,
17814 : LanguageMode language_mode) {
17815 : Isolate* isolate = GetIsolate();
17816 : Handle<SharedFunctionInfo> shared(context->closure()->shared());
17817 : StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17818 : int entry = FindEntry(&key);
17819 0 : if (entry == kNotFound) return isolate->factory()->undefined_value();
17820 : int index = EntryToIndex(entry);
17821 0 : if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value();
17822 0 : return Handle<Object>(get(index + 1), isolate);
17823 : }
17824 :
17825 : namespace {
17826 :
17827 : const int kLiteralEntryLength = 2;
17828 : const int kLiteralInitialLength = 2;
17829 : const int kLiteralContextOffset = 0;
17830 : const int kLiteralLiteralsOffset = 1;
17831 :
17832 5184432 : int SearchLiteralsMapEntry(CompilationCacheTable* cache, int cache_entry,
17833 : Context* native_context) {
17834 : DisallowHeapAllocation no_gc;
17835 : DCHECK(native_context->IsNativeContext());
17836 : Object* obj = cache->get(cache_entry);
17837 :
17838 5184432 : if (obj->IsFixedArray()) {
17839 : FixedArray* literals_map = FixedArray::cast(obj);
17840 : int length = literals_map->length();
17841 12446612 : for (int i = 0; i < length; i += kLiteralEntryLength) {
17842 10895568 : if (WeakCell::cast(literals_map->get(i + kLiteralContextOffset))
17843 : ->value() == native_context) {
17844 : return i;
17845 : }
17846 : }
17847 : }
17848 : return -1;
17849 : }
17850 :
17851 1208808 : void AddToLiteralsMap(Handle<CompilationCacheTable> cache, int cache_entry,
17852 : Handle<Context> native_context, Handle<Cell> literals) {
17853 : Isolate* isolate = native_context->GetIsolate();
17854 : DCHECK(native_context->IsNativeContext());
17855 : STATIC_ASSERT(kLiteralEntryLength == 2);
17856 : Handle<FixedArray> new_literals_map;
17857 : int entry;
17858 :
17859 : Object* obj = cache->get(cache_entry);
17860 :
17861 1949315 : if (!obj->IsFixedArray() || FixedArray::cast(obj)->length() == 0) {
17862 : new_literals_map =
17863 468301 : isolate->factory()->NewFixedArray(kLiteralInitialLength, TENURED);
17864 : entry = 0;
17865 : } else {
17866 : Handle<FixedArray> old_literals_map(FixedArray::cast(obj), isolate);
17867 740507 : entry = SearchLiteralsMapEntry(*cache, cache_entry, *native_context);
17868 740507 : if (entry >= 0) {
17869 : // Just set the code of the entry.
17870 : Handle<WeakCell> literals_cell =
17871 2109 : isolate->factory()->NewWeakCell(literals);
17872 4218 : old_literals_map->set(entry + kLiteralLiteralsOffset, *literals_cell);
17873 1208808 : return;
17874 : }
17875 :
17876 : // Can we reuse an entry?
17877 : DCHECK(entry < 0);
17878 : int length = old_literals_map->length();
17879 2012295 : for (int i = 0; i < length; i += kLiteralEntryLength) {
17880 1358622 : if (WeakCell::cast(old_literals_map->get(i + kLiteralContextOffset))
17881 : ->cleared()) {
17882 : new_literals_map = old_literals_map;
17883 : entry = i;
17884 : break;
17885 : }
17886 : }
17887 :
17888 738398 : if (entry < 0) {
17889 : // Copy old optimized code map and append one new entry.
17890 : new_literals_map = isolate->factory()->CopyFixedArrayAndGrow(
17891 653673 : old_literals_map, kLiteralEntryLength, TENURED);
17892 : entry = old_literals_map->length();
17893 : }
17894 : }
17895 :
17896 1206699 : Handle<WeakCell> literals_cell = isolate->factory()->NewWeakCell(literals);
17897 : WeakCell* context_cell = native_context->self_weak_cell();
17898 :
17899 1206699 : new_literals_map->set(entry + kLiteralContextOffset, context_cell);
17900 2413398 : new_literals_map->set(entry + kLiteralLiteralsOffset, *literals_cell);
17901 :
17902 : #ifdef DEBUG
17903 : for (int i = 0; i < new_literals_map->length(); i += kLiteralEntryLength) {
17904 : WeakCell* cell =
17905 : WeakCell::cast(new_literals_map->get(i + kLiteralContextOffset));
17906 : DCHECK(cell->cleared() || cell->value()->IsNativeContext());
17907 : cell = WeakCell::cast(new_literals_map->get(i + kLiteralLiteralsOffset));
17908 : DCHECK(cell->cleared() || (cell->value()->IsCell()));
17909 : }
17910 : #endif
17911 :
17912 : Object* old_literals_map = cache->get(cache_entry);
17913 1206699 : if (old_literals_map != *new_literals_map) {
17914 1121974 : cache->set(cache_entry, *new_literals_map);
17915 : }
17916 : }
17917 :
17918 4443925 : Cell* SearchLiteralsMap(CompilationCacheTable* cache, int cache_entry,
17919 : Context* native_context) {
17920 : Cell* result = nullptr;
17921 4443925 : int entry = SearchLiteralsMapEntry(cache, cache_entry, native_context);
17922 4443925 : if (entry >= 0) {
17923 : FixedArray* literals_map = FixedArray::cast(cache->get(cache_entry));
17924 : DCHECK_LE(entry + kLiteralEntryLength, literals_map->length());
17925 : WeakCell* cell =
17926 3631279 : WeakCell::cast(literals_map->get(entry + kLiteralLiteralsOffset));
17927 :
17928 3631279 : result = cell->cleared() ? nullptr : Cell::cast(cell->value());
17929 : }
17930 : DCHECK(result == nullptr || result->IsCell());
17931 4443925 : return result;
17932 : }
17933 :
17934 : } // namespace
17935 :
17936 310823 : InfoVectorPair CompilationCacheTable::LookupScript(Handle<String> src,
17937 : Handle<Context> context,
17938 : LanguageMode language_mode) {
17939 : InfoVectorPair empty_result;
17940 : Handle<SharedFunctionInfo> shared(context->closure()->shared());
17941 : StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17942 : int entry = FindEntry(&key);
17943 310823 : if (entry == kNotFound) return empty_result;
17944 : int index = EntryToIndex(entry);
17945 141713 : if (!get(index)->IsFixedArray()) return empty_result;
17946 141713 : Object* obj = get(index + 1);
17947 141713 : if (obj->IsSharedFunctionInfo()) {
17948 : Cell* literals =
17949 141713 : SearchLiteralsMap(this, index + 2, context->native_context());
17950 141713 : return InfoVectorPair(SharedFunctionInfo::cast(obj), literals);
17951 : }
17952 0 : return empty_result;
17953 : }
17954 :
17955 5554379 : InfoVectorPair CompilationCacheTable::LookupEval(
17956 : Handle<String> src, Handle<SharedFunctionInfo> outer_info,
17957 : Handle<Context> native_context, LanguageMode language_mode, int position) {
17958 : InfoVectorPair empty_result;
17959 : StringSharedKey key(src, outer_info, language_mode, position);
17960 : int entry = FindEntry(&key);
17961 5554379 : if (entry == kNotFound) return empty_result;
17962 : int index = EntryToIndex(entry);
17963 4597179 : if (!get(index)->IsFixedArray()) return empty_result;
17964 4302212 : Object* obj = get(EntryToIndex(entry) + 1);
17965 4302212 : if (obj->IsSharedFunctionInfo()) {
17966 : Cell* literals =
17967 4302212 : SearchLiteralsMap(this, EntryToIndex(entry) + 2, *native_context);
17968 4302212 : return InfoVectorPair(SharedFunctionInfo::cast(obj), literals);
17969 : }
17970 0 : return empty_result;
17971 : }
17972 :
17973 1069562 : Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src,
17974 : JSRegExp::Flags flags) {
17975 : Isolate* isolate = GetIsolate();
17976 : DisallowHeapAllocation no_allocation;
17977 : RegExpKey key(src, flags);
17978 : int entry = FindEntry(&key);
17979 1782712 : if (entry == kNotFound) return isolate->factory()->undefined_value();
17980 712824 : return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
17981 : }
17982 :
17983 :
17984 0 : Handle<CompilationCacheTable> CompilationCacheTable::Put(
17985 : Handle<CompilationCacheTable> cache, Handle<String> src,
17986 : Handle<Context> context, LanguageMode language_mode, Handle<Object> value) {
17987 : Isolate* isolate = cache->GetIsolate();
17988 : Handle<SharedFunctionInfo> shared(context->closure()->shared());
17989 : StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17990 0 : Handle<Object> k = key.AsHandle(isolate);
17991 0 : cache = EnsureCapacity(cache, 1, &key);
17992 0 : int entry = cache->FindInsertionEntry(key.Hash());
17993 0 : cache->set(EntryToIndex(entry), *k);
17994 0 : cache->set(EntryToIndex(entry) + 1, *value);
17995 0 : cache->ElementAdded();
17996 0 : return cache;
17997 : }
17998 :
17999 168303 : Handle<CompilationCacheTable> CompilationCacheTable::PutScript(
18000 : Handle<CompilationCacheTable> cache, Handle<String> src,
18001 : Handle<Context> context, LanguageMode language_mode,
18002 : Handle<SharedFunctionInfo> value, Handle<Cell> literals) {
18003 : Isolate* isolate = cache->GetIsolate();
18004 : Handle<SharedFunctionInfo> shared(context->closure()->shared());
18005 : Handle<Context> native_context(context->native_context());
18006 : StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
18007 168303 : Handle<Object> k = key.AsHandle(isolate);
18008 168303 : cache = EnsureCapacity(cache, 1, &key);
18009 336606 : int entry = cache->FindInsertionEntry(key.Hash());
18010 168303 : cache->set(EntryToIndex(entry), *k);
18011 336606 : cache->set(EntryToIndex(entry) + 1, *value);
18012 168303 : AddToLiteralsMap(cache, EntryToIndex(entry) + 2, native_context, literals);
18013 168303 : cache->ElementAdded();
18014 168303 : return cache;
18015 : }
18016 :
18017 1817488 : Handle<CompilationCacheTable> CompilationCacheTable::PutEval(
18018 : Handle<CompilationCacheTable> cache, Handle<String> src,
18019 : Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value,
18020 : Handle<Context> native_context, Handle<Cell> literals, int position) {
18021 : Isolate* isolate = cache->GetIsolate();
18022 : StringSharedKey key(src, outer_info, value->language_mode(), position);
18023 : {
18024 1817488 : Handle<Object> k = key.AsHandle(isolate);
18025 : int entry = cache->FindEntry(&key);
18026 1817488 : if (entry != kNotFound) {
18027 1040505 : cache->set(EntryToIndex(entry), *k);
18028 2081010 : cache->set(EntryToIndex(entry) + 1, *value);
18029 : // AddToLiteralsMap may allocate a new sub-array to live in the entry,
18030 : // but it won't change the cache array. Therefore EntryToIndex and
18031 : // entry remains correct.
18032 : AddToLiteralsMap(cache, EntryToIndex(entry) + 2, native_context,
18033 1040505 : literals);
18034 1040505 : return cache;
18035 : }
18036 : }
18037 :
18038 776983 : cache = EnsureCapacity(cache, 1, &key);
18039 1553966 : int entry = cache->FindInsertionEntry(key.Hash());
18040 : Handle<Object> k =
18041 776983 : isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
18042 776983 : cache->set(EntryToIndex(entry), *k);
18043 : cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
18044 776983 : cache->ElementAdded();
18045 776983 : return cache;
18046 : }
18047 :
18048 :
18049 353109 : Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp(
18050 : Handle<CompilationCacheTable> cache, Handle<String> src,
18051 : JSRegExp::Flags flags, Handle<FixedArray> value) {
18052 : RegExpKey key(src, flags);
18053 353109 : cache = EnsureCapacity(cache, 1, &key);
18054 353109 : int entry = cache->FindInsertionEntry(key.Hash());
18055 : // We store the value in the key slot, and compare the search key
18056 : // to the stored value with a custon IsMatch function during lookups.
18057 353109 : cache->set(EntryToIndex(entry), *value);
18058 706218 : cache->set(EntryToIndex(entry) + 1, *value);
18059 353109 : cache->ElementAdded();
18060 353109 : return cache;
18061 : }
18062 :
18063 :
18064 19083 : void CompilationCacheTable::Age() {
18065 : DisallowHeapAllocation no_allocation;
18066 19083 : Object* the_hole_value = GetHeap()->the_hole_value();
18067 3931014 : for (int entry = 0, size = Capacity(); entry < size; entry++) {
18068 : int entry_index = EntryToIndex(entry);
18069 3892848 : int value_index = entry_index + 1;
18070 :
18071 3892848 : if (get(entry_index)->IsNumber()) {
18072 : Smi* count = Smi::cast(get(value_index));
18073 298543 : count = Smi::FromInt(count->value() - 1);
18074 298543 : if (count->value() == 0) {
18075 : NoWriteBarrierSet(this, entry_index, the_hole_value);
18076 : NoWriteBarrierSet(this, value_index, the_hole_value);
18077 264 : ElementRemoved();
18078 : } else {
18079 : NoWriteBarrierSet(this, value_index, count);
18080 : }
18081 3594305 : } else if (get(entry_index)->IsFixedArray()) {
18082 : SharedFunctionInfo* info = SharedFunctionInfo::cast(get(value_index));
18083 : bool is_old =
18084 : info->IsInterpreted()
18085 : ? info->bytecode_array()->IsOld()
18086 799124 : : info->code()->kind() != Code::FUNCTION || info->code()->IsOld();
18087 432800 : if (is_old) {
18088 14022 : for (int i = 0; i < kEntrySize; i++) {
18089 14022 : NoWriteBarrierSet(this, entry_index + i, the_hole_value);
18090 : }
18091 4674 : ElementRemoved();
18092 : }
18093 : }
18094 : }
18095 19083 : }
18096 :
18097 :
18098 0 : void CompilationCacheTable::Remove(Object* value) {
18099 : DisallowHeapAllocation no_allocation;
18100 0 : Object* the_hole_value = GetHeap()->the_hole_value();
18101 0 : for (int entry = 0, size = Capacity(); entry < size; entry++) {
18102 : int entry_index = EntryToIndex(entry);
18103 0 : int value_index = entry_index + 1;
18104 0 : if (get(value_index) == value) {
18105 0 : for (int i = 0; i < kEntrySize; i++) {
18106 0 : NoWriteBarrierSet(this, entry_index + i, the_hole_value);
18107 : }
18108 0 : ElementRemoved();
18109 : }
18110 : }
18111 0 : return;
18112 : }
18113 :
18114 : template <typename Derived, typename Shape, typename Key>
18115 2279460 : Handle<Derived> Dictionary<Derived, Shape, Key>::New(
18116 : Isolate* isolate, int at_least_space_for, PretenureFlag pretenure,
18117 : MinimumCapacity capacity_option) {
18118 : DCHECK(0 <= at_least_space_for);
18119 : Handle<Derived> dict = DerivedHashTable::New(isolate, at_least_space_for,
18120 2279460 : capacity_option, pretenure);
18121 :
18122 : // Initialize the next enumeration index.
18123 : dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
18124 2279458 : return dict;
18125 : }
18126 :
18127 : template <typename Derived, typename Shape, typename Key>
18128 284 : Handle<Derived> Dictionary<Derived, Shape, Key>::NewEmpty(
18129 : Isolate* isolate, PretenureFlag pretenure) {
18130 284 : Handle<Derived> dict = DerivedHashTable::New(isolate, 1, pretenure);
18131 : // Attempt to add one element to the empty dictionary must cause reallocation.
18132 : DCHECK(!dict->HasSufficientCapacityToAdd(1));
18133 : // Initialize the next enumeration index.
18134 : dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
18135 284 : return dict;
18136 : }
18137 :
18138 : template <typename Derived, typename Shape, typename Key>
18139 50 : void Dictionary<Derived, Shape, Key>::SetRequiresCopyOnCapacityChange() {
18140 : DCHECK_EQ(0, DerivedHashTable::NumberOfElements());
18141 : DCHECK_EQ(0, DerivedHashTable::NumberOfDeletedElements());
18142 : // Make sure that HashTable::EnsureCapacity will create a copy.
18143 : DerivedHashTable::SetNumberOfDeletedElements(DerivedHashTable::Capacity());
18144 : DCHECK(!DerivedHashTable::HasSufficientCapacityToAdd(1));
18145 50 : }
18146 :
18147 :
18148 : template <typename Derived, typename Shape, typename Key>
18149 38582974 : Handle<Derived> Dictionary<Derived, Shape, Key>::EnsureCapacity(
18150 : Handle<Derived> dictionary, int n, Key key) {
18151 : // Check whether there are enough enumeration indices to add n elements.
18152 30893400 : if (Shape::kIsEnumerable &&
18153 30893400 : !PropertyDetails::IsValidIndex(dictionary->NextEnumerationIndex() + n)) {
18154 : // If not, we generate new indices for the properties.
18155 : int length = dictionary->NumberOfElements();
18156 :
18157 0 : Handle<FixedArray> iteration_order = IterationIndices(dictionary);
18158 : DCHECK_EQ(length, iteration_order->length());
18159 :
18160 : // Iterate over the dictionary using the enumeration order and update
18161 : // the dictionary with new enumeration indices.
18162 0 : for (int i = 0; i < length; i++) {
18163 : int index = Smi::cast(iteration_order->get(i))->value();
18164 : DCHECK(dictionary->IsKey(dictionary->GetIsolate(),
18165 : dictionary->KeyAt(index)));
18166 :
18167 0 : int enum_index = PropertyDetails::kInitialIndex + i;
18168 :
18169 : PropertyDetails details = dictionary->DetailsAt(index);
18170 : PropertyDetails new_details = details.set_index(enum_index);
18171 : dictionary->DetailsAtPut(index, new_details);
18172 : }
18173 :
18174 : // Set the next enumeration index.
18175 0 : dictionary->SetNextEnumerationIndex(PropertyDetails::kInitialIndex +
18176 : length);
18177 : }
18178 38582974 : return DerivedHashTable::EnsureCapacity(dictionary, n, key);
18179 : }
18180 :
18181 :
18182 : template <typename Derived, typename Shape, typename Key>
18183 6169666 : Handle<Object> Dictionary<Derived, Shape, Key>::DeleteProperty(
18184 : Handle<Derived> dictionary, int entry) {
18185 : Factory* factory = dictionary->GetIsolate()->factory();
18186 : PropertyDetails details = dictionary->DetailsAt(entry);
18187 6169666 : if (!details.IsConfigurable()) return factory->false_value();
18188 :
18189 6169666 : dictionary->SetEntry(
18190 : entry, factory->the_hole_value(), factory->the_hole_value());
18191 6169666 : dictionary->ElementRemoved();
18192 6169666 : return factory->true_value();
18193 : }
18194 :
18195 :
18196 : template<typename Derived, typename Shape, typename Key>
18197 1899407 : Handle<Derived> Dictionary<Derived, Shape, Key>::AtPut(
18198 : Handle<Derived> dictionary, Key key, Handle<Object> value) {
18199 : int entry = dictionary->FindEntry(key);
18200 :
18201 : // If the entry is present set the value;
18202 1899407 : if (entry != Dictionary::kNotFound) {
18203 : dictionary->ValueAtPut(entry, *value);
18204 24 : return dictionary;
18205 : }
18206 :
18207 : // Check whether the dictionary should be extended.
18208 1899383 : dictionary = EnsureCapacity(dictionary, 1, key);
18209 : #ifdef DEBUG
18210 : USE(Shape::AsHandle(dictionary->GetIsolate(), key));
18211 : #endif
18212 1899383 : PropertyDetails details = PropertyDetails::Empty();
18213 :
18214 1899383 : AddEntry(dictionary, key, value, details, dictionary->Hash(key));
18215 1899383 : return dictionary;
18216 : }
18217 :
18218 : template <typename Derived, typename Shape, typename Key>
18219 36683589 : Handle<Derived> Dictionary<Derived, Shape, Key>::Add(Handle<Derived> dictionary,
18220 : Key key,
18221 : Handle<Object> value,
18222 : PropertyDetails details,
18223 : int* entry_out) {
18224 : // Valdate key is absent.
18225 : SLOW_DCHECK((dictionary->FindEntry(key) == Dictionary::kNotFound));
18226 : // Check whether the dictionary should be extended.
18227 36683589 : dictionary = EnsureCapacity(dictionary, 1, key);
18228 :
18229 36683590 : int entry = AddEntry(dictionary, key, value, details, dictionary->Hash(key));
18230 36683588 : if (entry_out) *entry_out = entry;
18231 36683588 : return dictionary;
18232 : }
18233 :
18234 : // Add a key, value pair to the dictionary. Returns entry value.
18235 : template <typename Derived, typename Shape, typename Key>
18236 38582973 : int Dictionary<Derived, Shape, Key>::AddEntry(Handle<Derived> dictionary,
18237 : Key key, Handle<Object> value,
18238 : PropertyDetails details,
18239 : uint32_t hash) {
18240 : // Compute the key object.
18241 : Handle<Object> k = Shape::AsHandle(dictionary->GetIsolate(), key);
18242 :
18243 38582973 : uint32_t entry = dictionary->FindInsertionEntry(hash);
18244 : // Insert element at empty or deleted entry
18245 30893401 : if (details.dictionary_index() == 0 && Shape::kIsEnumerable) {
18246 : // Assign an enumeration index to the property and update
18247 : // SetNextEnumerationIndex.
18248 : int index = dictionary->NextEnumerationIndex();
18249 : details = details.set_index(index);
18250 25094311 : dictionary->SetNextEnumerationIndex(index + 1);
18251 : }
18252 38582973 : dictionary->SetEntry(entry, k, value, details);
18253 : DCHECK((dictionary->KeyAt(entry)->IsNumber() ||
18254 : dictionary->KeyAt(entry)->IsName()));
18255 38582971 : dictionary->ElementAdded();
18256 38582971 : return entry;
18257 : }
18258 :
18259 4562 : bool SeededNumberDictionary::HasComplexElements() {
18260 4562 : if (!requires_slow_elements()) return false;
18261 : Isolate* isolate = this->GetIsolate();
18262 : int capacity = this->Capacity();
18263 20595 : for (int i = 0; i < capacity; i++) {
18264 : Object* k = this->KeyAt(i);
18265 17970 : if (!this->IsKey(isolate, k)) continue;
18266 : DCHECK(!IsDeleted(i));
18267 : PropertyDetails details = this->DetailsAt(i);
18268 7290 : if (details.kind() == kAccessor) return true;
18269 : PropertyAttributes attr = details.attributes();
18270 7230 : if (attr & ALL_ATTRIBUTES_MASK) return true;
18271 : }
18272 : return false;
18273 : }
18274 :
18275 6362220 : void SeededNumberDictionary::UpdateMaxNumberKey(
18276 : uint32_t key, Handle<JSObject> dictionary_holder) {
18277 : DisallowHeapAllocation no_allocation;
18278 : // If the dictionary requires slow elements an element has already
18279 : // been added at a high index.
18280 6362220 : if (requires_slow_elements()) return;
18281 : // Check if this index is high enough that we should require slow
18282 : // elements.
18283 6288637 : if (key > kRequiresSlowElementsLimit) {
18284 1586 : if (!dictionary_holder.is_null()) {
18285 1178 : dictionary_holder->RequireSlowElements(this);
18286 : }
18287 : set_requires_slow_elements();
18288 : return;
18289 : }
18290 : // Update max key value.
18291 : Object* max_index_object = get(kMaxNumberKeyIndex);
18292 6287051 : if (!max_index_object->IsSmi() || max_number_key() < key) {
18293 : FixedArray::set(kMaxNumberKeyIndex,
18294 5378441 : Smi::FromInt(key << kRequiresSlowElementsTagSize));
18295 : }
18296 : }
18297 :
18298 5775746 : Handle<SeededNumberDictionary> SeededNumberDictionary::AddNumberEntry(
18299 : Handle<SeededNumberDictionary> dictionary, uint32_t key,
18300 : Handle<Object> value, PropertyDetails details,
18301 : Handle<JSObject> dictionary_holder) {
18302 5775746 : dictionary->UpdateMaxNumberKey(key, dictionary_holder);
18303 : SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
18304 5775746 : return Add(dictionary, key, value, details);
18305 : }
18306 :
18307 :
18308 0 : Handle<UnseededNumberDictionary> UnseededNumberDictionary::AddNumberEntry(
18309 : Handle<UnseededNumberDictionary> dictionary,
18310 : uint32_t key,
18311 : Handle<Object> value) {
18312 : SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
18313 393 : return Add(dictionary, key, value, PropertyDetails::Empty());
18314 : }
18315 :
18316 0 : Handle<UnseededNumberDictionary> UnseededNumberDictionary::DeleteKey(
18317 : Handle<UnseededNumberDictionary> dictionary, uint32_t key) {
18318 : int entry = dictionary->FindEntry(key);
18319 0 : if (entry == kNotFound) return dictionary;
18320 :
18321 : Factory* factory = dictionary->GetIsolate()->factory();
18322 : dictionary->SetEntry(entry, factory->the_hole_value(),
18323 : factory->the_hole_value());
18324 0 : dictionary->ElementRemoved();
18325 0 : return dictionary->Shrink(dictionary, key);
18326 : }
18327 :
18328 586474 : Handle<SeededNumberDictionary> SeededNumberDictionary::AtNumberPut(
18329 : Handle<SeededNumberDictionary> dictionary, uint32_t key,
18330 : Handle<Object> value, Handle<JSObject> dictionary_holder) {
18331 586474 : dictionary->UpdateMaxNumberKey(key, dictionary_holder);
18332 586474 : return AtPut(dictionary, key, value);
18333 : }
18334 :
18335 60 : void SeededNumberDictionary::CopyValuesTo(FixedArray* elements) {
18336 : Isolate* isolate = this->GetIsolate();
18337 : int pos = 0;
18338 : int capacity = this->Capacity();
18339 : DisallowHeapAllocation no_gc;
18340 60 : WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
18341 1020 : for (int i = 0; i < capacity; i++) {
18342 : Object* k = this->KeyAt(i);
18343 960 : if (this->IsKey(isolate, k)) {
18344 450 : elements->set(pos++, this->ValueAt(i), mode);
18345 : }
18346 : }
18347 : DCHECK(pos == elements->length());
18348 60 : }
18349 :
18350 1312933 : Handle<UnseededNumberDictionary> UnseededNumberDictionary::AtNumberPut(
18351 : Handle<UnseededNumberDictionary> dictionary,
18352 : uint32_t key,
18353 : Handle<Object> value) {
18354 1312933 : return AtPut(dictionary, key, value);
18355 : }
18356 :
18357 39202 : Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
18358 : Handle<SeededNumberDictionary> dictionary, uint32_t key,
18359 : Handle<Object> value, PropertyDetails details,
18360 : Handle<JSObject> dictionary_holder) {
18361 : int entry = dictionary->FindEntry(key);
18362 39202 : if (entry == kNotFound) {
18363 37558 : return AddNumberEntry(dictionary, key, value, details, dictionary_holder);
18364 : }
18365 : // Preserve enumeration index.
18366 : details = details.set_index(dictionary->DetailsAt(entry).dictionary_index());
18367 : Handle<Object> object_key =
18368 : SeededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
18369 : dictionary->SetEntry(entry, object_key, value, details);
18370 1644 : return dictionary;
18371 : }
18372 :
18373 :
18374 1818 : Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
18375 : Handle<UnseededNumberDictionary> dictionary,
18376 : uint32_t key,
18377 : Handle<Object> value) {
18378 : int entry = dictionary->FindEntry(key);
18379 1818 : if (entry == kNotFound) return AddNumberEntry(dictionary, key, value);
18380 : Handle<Object> object_key =
18381 : UnseededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
18382 : dictionary->SetEntry(entry, object_key, value);
18383 1425 : return dictionary;
18384 : }
18385 :
18386 :
18387 : template <typename Derived, typename Shape, typename Key>
18388 98702 : int Dictionary<Derived, Shape, Key>::NumberOfElementsFilterAttributes(
18389 : PropertyFilter filter) {
18390 : Isolate* isolate = this->GetIsolate();
18391 : int capacity = this->Capacity();
18392 : int result = 0;
18393 10286962 : for (int i = 0; i < capacity; i++) {
18394 : Object* k = this->KeyAt(i);
18395 10188260 : if (this->IsKey(isolate, k) && !k->FilterKey(filter)) {
18396 3211028 : if (this->IsDeleted(i)) continue;
18397 : PropertyDetails details = this->DetailsAt(i);
18398 : PropertyAttributes attr = details.attributes();
18399 4505899 : if ((attr & filter) == 0) result++;
18400 : }
18401 : }
18402 98702 : return result;
18403 : }
18404 :
18405 :
18406 : template <typename Dictionary>
18407 : struct EnumIndexComparator {
18408 792771 : explicit EnumIndexComparator(Dictionary* dict) : dict(dict) {}
18409 130709123 : bool operator() (Smi* a, Smi* b) {
18410 130709123 : PropertyDetails da(dict->DetailsAt(a->value()));
18411 130709123 : PropertyDetails db(dict->DetailsAt(b->value()));
18412 130709123 : return da.dictionary_index() < db.dictionary_index();
18413 : }
18414 : Dictionary* dict;
18415 : };
18416 :
18417 : template <typename Derived, typename Shape, typename Key>
18418 97481 : void Dictionary<Derived, Shape, Key>::CopyEnumKeysTo(
18419 : Handle<Dictionary<Derived, Shape, Key>> dictionary,
18420 : Handle<FixedArray> storage, KeyCollectionMode mode,
18421 : KeyAccumulator* accumulator) {
18422 : DCHECK_IMPLIES(mode != KeyCollectionMode::kOwnOnly, accumulator != nullptr);
18423 : Isolate* isolate = dictionary->GetIsolate();
18424 : int length = storage->length();
18425 : int capacity = dictionary->Capacity();
18426 : int properties = 0;
18427 10089303 : for (int i = 0; i < capacity; i++) {
18428 : Object* key = dictionary->KeyAt(i);
18429 : bool is_shadowing_key = false;
18430 10031781 : if (!dictionary->IsKey(isolate, key)) continue;
18431 4475088 : if (key->IsSymbol()) continue;
18432 : PropertyDetails details = dictionary->DetailsAt(i);
18433 4446080 : if (details.IsDontEnum()) {
18434 1490117 : if (mode == KeyCollectionMode::kIncludePrototypes) {
18435 : is_shadowing_key = true;
18436 : } else {
18437 : continue;
18438 : }
18439 : }
18440 1682708 : if (dictionary->IsDeleted(i)) continue;
18441 2975492 : if (is_shadowing_key) {
18442 19664 : accumulator->AddShadowingKey(key);
18443 19664 : continue;
18444 : } else {
18445 : storage->set(properties, Smi::FromInt(i));
18446 : }
18447 2955828 : properties++;
18448 2955828 : if (mode == KeyCollectionMode::kOwnOnly && properties == length) break;
18449 : }
18450 :
18451 97481 : CHECK_EQ(length, properties);
18452 : DisallowHeapAllocation no_gc;
18453 : Dictionary<Derived, Shape, Key>* raw_dictionary = *dictionary;
18454 : FixedArray* raw_storage = *storage;
18455 : EnumIndexComparator<Derived> cmp(static_cast<Derived*>(*dictionary));
18456 97481 : Smi** start = reinterpret_cast<Smi**>(storage->GetFirstElementAddress());
18457 97481 : std::sort(start, start + length, cmp);
18458 3053309 : for (int i = 0; i < length; i++) {
18459 : int index = Smi::cast(raw_storage->get(i))->value();
18460 2955828 : raw_storage->set(i, raw_dictionary->KeyAt(index));
18461 : }
18462 97481 : }
18463 :
18464 : template <typename Derived, typename Shape, typename Key>
18465 629013 : Handle<FixedArray> Dictionary<Derived, Shape, Key>::IterationIndices(
18466 : Handle<Dictionary<Derived, Shape, Key>> dictionary) {
18467 : Isolate* isolate = dictionary->GetIsolate();
18468 : int capacity = dictionary->Capacity();
18469 : int length = dictionary->NumberOfElements();
18470 629013 : Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
18471 : int array_size = 0;
18472 : {
18473 : DisallowHeapAllocation no_gc;
18474 : Dictionary<Derived, Shape, Key>* raw_dict = *dictionary;
18475 21453645 : for (int i = 0; i < capacity; i++) {
18476 : Object* k = raw_dict->KeyAt(i);
18477 20824632 : if (!raw_dict->IsKey(isolate, k)) continue;
18478 5551162 : if (raw_dict->IsDeleted(i)) continue;
18479 8747994 : array->set(array_size++, Smi::FromInt(i));
18480 : }
18481 :
18482 : DCHECK_EQ(array_size, length);
18483 :
18484 : EnumIndexComparator<Derived> cmp(static_cast<Derived*>(raw_dict));
18485 629013 : Smi** start = reinterpret_cast<Smi**>(array->GetFirstElementAddress());
18486 629013 : std::sort(start, start + array_size, cmp);
18487 : }
18488 629013 : array->Shrink(array_size);
18489 629013 : return array;
18490 : }
18491 :
18492 : template <typename Derived, typename Shape, typename Key>
18493 66277 : void Dictionary<Derived, Shape, Key>::CollectKeysTo(
18494 : Handle<Dictionary<Derived, Shape, Key>> dictionary, KeyAccumulator* keys) {
18495 : Isolate* isolate = keys->isolate();
18496 : int capacity = dictionary->Capacity();
18497 : Handle<FixedArray> array =
18498 66277 : isolate->factory()->NewFixedArray(dictionary->NumberOfElements());
18499 : int array_size = 0;
18500 : PropertyFilter filter = keys->filter();
18501 : {
18502 : DisallowHeapAllocation no_gc;
18503 : Dictionary<Derived, Shape, Key>* raw_dict = *dictionary;
18504 19381873 : for (int i = 0; i < capacity; i++) {
18505 : Object* k = raw_dict->KeyAt(i);
18506 19315596 : if (!raw_dict->IsKey(isolate, k) || k->FilterKey(filter)) continue;
18507 3174296 : if (raw_dict->IsDeleted(i)) continue;
18508 : PropertyDetails details = raw_dict->DetailsAt(i);
18509 5856902 : if ((details.attributes() & filter) != 0) {
18510 636 : keys->AddShadowingKey(k);
18511 636 : continue;
18512 : }
18513 5856266 : if (filter & ONLY_ALL_CAN_READ) {
18514 409 : if (details.kind() != kAccessor) continue;
18515 31 : Object* accessors = raw_dict->ValueAt(i);
18516 31 : if (accessors->IsPropertyCell()) {
18517 : accessors = PropertyCell::cast(accessors)->value();
18518 : }
18519 31 : if (!accessors->IsAccessorInfo()) continue;
18520 31 : if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
18521 : }
18522 5855876 : array->set(array_size++, Smi::FromInt(i));
18523 : }
18524 :
18525 : EnumIndexComparator<Derived> cmp(static_cast<Derived*>(raw_dict));
18526 66277 : Smi** start = reinterpret_cast<Smi**>(array->GetFirstElementAddress());
18527 66277 : std::sort(start, start + array_size, cmp);
18528 : }
18529 :
18530 : bool has_seen_symbol = false;
18531 5922153 : for (int i = 0; i < array_size; i++) {
18532 : int index = Smi::cast(array->get(i))->value();
18533 : Object* key = dictionary->KeyAt(index);
18534 5855876 : if (key->IsSymbol()) {
18535 : has_seen_symbol = true;
18536 : continue;
18537 : }
18538 5827222 : keys->AddKey(key, DO_NOT_CONVERT);
18539 : }
18540 66277 : if (has_seen_symbol) {
18541 35075 : for (int i = 0; i < array_size; i++) {
18542 : int index = Smi::cast(array->get(i))->value();
18543 : Object* key = dictionary->KeyAt(index);
18544 35075 : if (!key->IsSymbol()) continue;
18545 28654 : keys->AddKey(key, DO_NOT_CONVERT);
18546 : }
18547 : }
18548 66277 : }
18549 :
18550 :
18551 : // Backwards lookup (slow).
18552 : template<typename Derived, typename Shape, typename Key>
18553 14 : Object* Dictionary<Derived, Shape, Key>::SlowReverseLookup(Object* value) {
18554 : Isolate* isolate = this->GetIsolate();
18555 : int capacity = this->Capacity();
18556 1806 : for (int i = 0; i < capacity; i++) {
18557 : Object* k = this->KeyAt(i);
18558 1792 : if (!this->IsKey(isolate, k)) continue;
18559 756 : Object* e = this->ValueAt(i);
18560 : // TODO(dcarney): this should be templatized.
18561 756 : if (e->IsPropertyCell()) {
18562 : e = PropertyCell::cast(e)->value();
18563 : }
18564 756 : if (e == value) return k;
18565 : }
18566 14 : return isolate->heap()->undefined_value();
18567 : }
18568 :
18569 :
18570 9158 : Object* ObjectHashTable::Lookup(Isolate* isolate, Handle<Object> key,
18571 : int32_t hash) {
18572 : DisallowHeapAllocation no_gc;
18573 : DCHECK(IsKey(isolate, *key));
18574 :
18575 9158 : int entry = FindEntry(isolate, key, hash);
18576 9158 : if (entry == kNotFound) return isolate->heap()->the_hole_value();
18577 15462 : return get(EntryToIndex(entry) + 1);
18578 : }
18579 :
18580 :
18581 7462 : Object* ObjectHashTable::Lookup(Handle<Object> key) {
18582 : DisallowHeapAllocation no_gc;
18583 :
18584 : Isolate* isolate = GetIsolate();
18585 : DCHECK(IsKey(isolate, *key));
18586 :
18587 : // If the object does not have an identity hash, it was never used as a key.
18588 7462 : Object* hash = key->GetHash();
18589 7462 : if (hash->IsUndefined(isolate)) {
18590 726 : return isolate->heap()->the_hole_value();
18591 : }
18592 6736 : return Lookup(isolate, key, Smi::cast(hash)->value());
18593 : }
18594 :
18595 0 : Object* ObjectHashTable::ValueAt(int entry) {
18596 0 : return get(EntryToValueIndex(entry));
18597 : }
18598 :
18599 2422 : Object* ObjectHashTable::Lookup(Handle<Object> key, int32_t hash) {
18600 2422 : return Lookup(GetIsolate(), key, hash);
18601 : }
18602 :
18603 :
18604 3498 : Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
18605 : Handle<Object> key,
18606 : Handle<Object> value) {
18607 : Isolate* isolate = table->GetIsolate();
18608 : DCHECK(table->IsKey(isolate, *key));
18609 : DCHECK(!value->IsTheHole(isolate));
18610 :
18611 : // Make sure the key object has an identity hash code.
18612 3498 : int32_t hash = Object::GetOrCreateHash(isolate, key)->value();
18613 :
18614 3498 : return Put(table, key, value, hash);
18615 : }
18616 :
18617 :
18618 6436 : Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
18619 : Handle<Object> key,
18620 : Handle<Object> value,
18621 : int32_t hash) {
18622 : Isolate* isolate = table->GetIsolate();
18623 : DCHECK(table->IsKey(isolate, *key));
18624 : DCHECK(!value->IsTheHole(isolate));
18625 :
18626 6436 : int entry = table->FindEntry(isolate, key, hash);
18627 :
18628 : // Key is already in table, just overwrite value.
18629 6436 : if (entry != kNotFound) {
18630 1242 : table->set(EntryToIndex(entry) + 1, *value);
18631 621 : return table;
18632 : }
18633 :
18634 : // Rehash if more than 33% of the entries are deleted entries.
18635 : // TODO(jochen): Consider to shrink the fixed array in place.
18636 11630 : if ((table->NumberOfDeletedElements() << 1) > table->NumberOfElements()) {
18637 7 : table->Rehash(isolate->factory()->undefined_value());
18638 : }
18639 : // If we're out of luck, we didn't get a GC recently, and so rehashing
18640 : // isn't enough to avoid a crash.
18641 5815 : if (!table->HasSufficientCapacityToAdd(1)) {
18642 402 : int nof = table->NumberOfElements() + 1;
18643 402 : int capacity = ObjectHashTable::ComputeCapacity(nof * 2);
18644 402 : if (capacity > ObjectHashTable::kMaxCapacity) {
18645 0 : for (size_t i = 0; i < 2; ++i) {
18646 : isolate->heap()->CollectAllGarbage(
18647 : Heap::kFinalizeIncrementalMarkingMask,
18648 0 : GarbageCollectionReason::kFullHashtable);
18649 : }
18650 0 : table->Rehash(isolate->factory()->undefined_value());
18651 : }
18652 : }
18653 :
18654 : // Check whether the hash table should be extended.
18655 5815 : table = EnsureCapacity(table, 1, key);
18656 17445 : table->AddEntry(table->FindInsertionEntry(hash), *key, *value);
18657 5815 : return table;
18658 : }
18659 :
18660 :
18661 7 : Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
18662 : Handle<Object> key,
18663 : bool* was_present) {
18664 : DCHECK(table->IsKey(table->GetIsolate(), *key));
18665 :
18666 7 : Object* hash = key->GetHash();
18667 7 : if (hash->IsUndefined(table->GetIsolate())) {
18668 0 : *was_present = false;
18669 0 : return table;
18670 : }
18671 :
18672 7 : return Remove(table, key, was_present, Smi::cast(hash)->value());
18673 : }
18674 :
18675 :
18676 125 : Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
18677 : Handle<Object> key,
18678 : bool* was_present,
18679 : int32_t hash) {
18680 : Isolate* isolate = table->GetIsolate();
18681 : DCHECK(table->IsKey(isolate, *key));
18682 :
18683 125 : int entry = table->FindEntry(isolate, key, hash);
18684 125 : if (entry == kNotFound) {
18685 0 : *was_present = false;
18686 0 : return table;
18687 : }
18688 :
18689 125 : *was_present = true;
18690 125 : table->RemoveEntry(entry);
18691 : return Shrink(table, key);
18692 : }
18693 :
18694 :
18695 5815 : void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
18696 5815 : set(EntryToIndex(entry), key);
18697 5815 : set(EntryToIndex(entry) + 1, value);
18698 5815 : ElementAdded();
18699 5815 : }
18700 :
18701 :
18702 164 : void ObjectHashTable::RemoveEntry(int entry) {
18703 164 : set_the_hole(EntryToIndex(entry));
18704 164 : set_the_hole(EntryToIndex(entry) + 1);
18705 164 : ElementRemoved();
18706 164 : }
18707 :
18708 :
18709 1051520 : Object* WeakHashTable::Lookup(Handle<HeapObject> key) {
18710 : DisallowHeapAllocation no_gc;
18711 : Isolate* isolate = GetIsolate();
18712 : DCHECK(IsKey(isolate, *key));
18713 : int entry = FindEntry(key);
18714 1051520 : if (entry == kNotFound) return isolate->heap()->the_hole_value();
18715 904367 : return get(EntryToValueIndex(entry));
18716 : }
18717 :
18718 :
18719 1051520 : Handle<WeakHashTable> WeakHashTable::Put(Handle<WeakHashTable> table,
18720 : Handle<HeapObject> key,
18721 : Handle<HeapObject> value) {
18722 : Isolate* isolate = key->GetIsolate();
18723 : DCHECK(table->IsKey(isolate, *key));
18724 : int entry = table->FindEntry(key);
18725 : // Key is already in table, just overwrite value.
18726 1051519 : if (entry != kNotFound) {
18727 904366 : table->set(EntryToValueIndex(entry), *value);
18728 904366 : return table;
18729 : }
18730 :
18731 147153 : Handle<WeakCell> key_cell = isolate->factory()->NewWeakCell(key);
18732 :
18733 : // Check whether the hash table should be extended.
18734 147153 : table = EnsureCapacity(table, 1, key, TENURED);
18735 :
18736 294306 : table->AddEntry(table->FindInsertionEntry(table->Hash(key)), key_cell, value);
18737 147153 : return table;
18738 : }
18739 :
18740 :
18741 147153 : void WeakHashTable::AddEntry(int entry, Handle<WeakCell> key_cell,
18742 : Handle<HeapObject> value) {
18743 : DisallowHeapAllocation no_allocation;
18744 147153 : set(EntryToIndex(entry), *key_cell);
18745 147153 : set(EntryToValueIndex(entry), *value);
18746 147153 : ElementAdded();
18747 147153 : }
18748 :
18749 : template <class Derived, int entrysize>
18750 10161487 : Handle<Derived> OrderedHashTable<Derived, entrysize>::Allocate(
18751 : Isolate* isolate, int capacity, PretenureFlag pretenure) {
18752 : // Capacity must be a power of two, since we depend on being able
18753 : // to divide and multiple by 2 (kLoadFactor) to derive capacity
18754 : // from number of buckets. If we decide to change kLoadFactor
18755 : // to something other than 2, capacity should be stored as another
18756 : // field of this object.
18757 10161487 : capacity = base::bits::RoundUpToPowerOfTwo32(Max(kMinCapacity, capacity));
18758 10161487 : if (capacity > kMaxCapacity) {
18759 0 : v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
18760 : }
18761 10161487 : int num_buckets = capacity / kLoadFactor;
18762 : Handle<FixedArray> backing_store = isolate->factory()->NewFixedArray(
18763 10161487 : kHashTableStartIndex + num_buckets + (capacity * kEntrySize), pretenure);
18764 : backing_store->set_map_no_write_barrier(
18765 10161488 : isolate->heap()->ordered_hash_table_map());
18766 : Handle<Derived> table = Handle<Derived>::cast(backing_store);
18767 99705260 : for (int i = 0; i < num_buckets; ++i) {
18768 : table->set(kHashTableStartIndex + i, Smi::FromInt(kNotFound));
18769 : }
18770 : table->SetNumberOfBuckets(num_buckets);
18771 : table->SetNumberOfElements(0);
18772 : table->SetNumberOfDeletedElements(0);
18773 10161488 : return table;
18774 : }
18775 :
18776 : template <class Derived, int entrysize>
18777 78472341 : Handle<Derived> OrderedHashTable<Derived, entrysize>::EnsureGrowable(
18778 : Handle<Derived> table) {
18779 : DCHECK(!table->IsObsolete());
18780 :
18781 : int nof = table->NumberOfElements();
18782 : int nod = table->NumberOfDeletedElements();
18783 : int capacity = table->Capacity();
18784 78472341 : if ((nof + nod) < capacity) return table;
18785 : // Don't need to grow if we can simply clear out deleted entries instead.
18786 : // Note that we can't compact in place, though, so we always allocate
18787 : // a new table.
18788 279137 : return Rehash(table, (nod < (capacity >> 1)) ? capacity << 1 : capacity);
18789 : }
18790 :
18791 : template <class Derived, int entrysize>
18792 202070 : Handle<Derived> OrderedHashTable<Derived, entrysize>::Shrink(
18793 : Handle<Derived> table) {
18794 : DCHECK(!table->IsObsolete());
18795 :
18796 : int nof = table->NumberOfElements();
18797 : int capacity = table->Capacity();
18798 202070 : if (nof >= (capacity >> 2)) return table;
18799 202070 : return Rehash(table, capacity / 2);
18800 : }
18801 :
18802 : template <class Derived, int entrysize>
18803 359 : Handle<Derived> OrderedHashTable<Derived, entrysize>::Clear(
18804 : Handle<Derived> table) {
18805 : DCHECK(!table->IsObsolete());
18806 :
18807 : Handle<Derived> new_table =
18808 : Allocate(table->GetIsolate(),
18809 : kMinCapacity,
18810 718 : table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
18811 :
18812 : table->SetNextTable(*new_table);
18813 : table->SetNumberOfDeletedElements(kClearedTableSentinel);
18814 :
18815 359 : return new_table;
18816 : }
18817 :
18818 : template <class Derived, int entrysize>
18819 0 : bool OrderedHashTable<Derived, entrysize>::HasKey(Handle<Derived> table,
18820 : Handle<Object> key) {
18821 : DisallowHeapAllocation no_gc;
18822 : Isolate* isolate = table->GetIsolate();
18823 : Object* raw_key = *key;
18824 0 : int entry = table->KeyToFirstEntry(isolate, raw_key);
18825 : // Walk the chain in the bucket to find the key.
18826 0 : while (entry != kNotFound) {
18827 0 : Object* candidate_key = table->KeyAt(entry);
18828 0 : if (candidate_key->SameValueZero(raw_key)) return true;
18829 0 : entry = table->NextChainEntry(entry);
18830 : }
18831 : return false;
18832 : }
18833 :
18834 :
18835 78454862 : Handle<OrderedHashSet> OrderedHashSet::Add(Handle<OrderedHashSet> table,
18836 : Handle<Object> key) {
18837 78454862 : int hash = Object::GetOrCreateHash(table->GetIsolate(), key)->value();
18838 78454860 : int entry = table->HashToEntry(hash);
18839 : // Walk the chain of the bucket and try finding the key.
18840 207423050 : while (entry != kNotFound) {
18841 50514161 : Object* candidate_key = table->KeyAt(entry);
18842 : // Do not add if we have the key already
18843 50514161 : if (candidate_key->SameValueZero(*key)) return table;
18844 50513329 : entry = table->NextChainEntry(entry);
18845 : }
18846 :
18847 78454029 : table = OrderedHashSet::EnsureGrowable(table);
18848 : // Read the existing bucket values.
18849 : int bucket = table->HashToBucket(hash);
18850 78454028 : int previous_entry = table->HashToEntry(hash);
18851 : int nof = table->NumberOfElements();
18852 : // Insert a new entry at the end,
18853 78454028 : int new_entry = nof + table->NumberOfDeletedElements();
18854 : int new_index = table->EntryToIndex(new_entry);
18855 78454028 : table->set(new_index, *key);
18856 : table->set(new_index + kChainOffset, Smi::FromInt(previous_entry));
18857 : // and point the bucket to the new entry.
18858 : table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
18859 78454028 : table->SetNumberOfElements(nof + 1);
18860 78454028 : return table;
18861 : }
18862 :
18863 9520923 : Handle<FixedArray> OrderedHashSet::ConvertToKeysArray(
18864 : Handle<OrderedHashSet> table, GetKeysConversion convert) {
18865 : Isolate* isolate = table->GetIsolate();
18866 : int length = table->NumberOfElements();
18867 : int nof_buckets = table->NumberOfBuckets();
18868 : // Convert the dictionary to a linear list.
18869 : Handle<FixedArray> result = Handle<FixedArray>::cast(table);
18870 : // From this point on table is no longer a valid OrderedHashSet.
18871 19041846 : result->set_map(isolate->heap()->fixed_array_map());
18872 87974884 : for (int i = 0; i < length; i++) {
18873 78453961 : int index = kHashTableStartIndex + nof_buckets + (i * kEntrySize);
18874 : Object* key = table->get(index);
18875 78453961 : if (convert == GetKeysConversion::kConvertToString) {
18876 : uint32_t index_value;
18877 11071734 : if (key->ToArrayIndex(&index_value)) {
18878 603298 : key = *isolate->factory()->Uint32ToString(index_value);
18879 : } else {
18880 10770085 : CHECK(key->IsName());
18881 : }
18882 : }
18883 78453961 : result->set(i, key);
18884 : }
18885 9520923 : result->Shrink(length);
18886 9520923 : return result;
18887 : }
18888 :
18889 : template <class Derived, int entrysize>
18890 481207 : Handle<Derived> OrderedHashTable<Derived, entrysize>::Rehash(
18891 : Handle<Derived> table, int new_capacity) {
18892 : Isolate* isolate = table->GetIsolate();
18893 : DCHECK(!table->IsObsolete());
18894 :
18895 : Handle<Derived> new_table =
18896 : Allocate(isolate, new_capacity,
18897 481207 : isolate->heap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
18898 : int nof = table->NumberOfElements();
18899 : int nod = table->NumberOfDeletedElements();
18900 : int new_buckets = new_table->NumberOfBuckets();
18901 : int new_entry = 0;
18902 : int removed_holes_index = 0;
18903 :
18904 : DisallowHeapAllocation no_gc;
18905 13348710 : for (int old_entry = 0; old_entry < (nof + nod); ++old_entry) {
18906 12867503 : Object* key = table->KeyAt(old_entry);
18907 12867503 : if (key->IsTheHole(isolate)) {
18908 212755 : table->SetRemovedIndexAt(removed_holes_index++, old_entry);
18909 : continue;
18910 : }
18911 :
18912 12654748 : Object* hash = key->GetHash();
18913 12654748 : int bucket = Smi::cast(hash)->value() & (new_buckets - 1);
18914 12654748 : Object* chain_entry = new_table->get(kHashTableStartIndex + bucket);
18915 : new_table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
18916 : int new_index = new_table->EntryToIndex(new_entry);
18917 : int old_index = table->EntryToIndex(old_entry);
18918 25378848 : for (int i = 0; i < entrysize; ++i) {
18919 12724100 : Object* value = table->get(old_index + i);
18920 25448200 : new_table->set(new_index + i, value);
18921 : }
18922 25309496 : new_table->set(new_index + kChainOffset, chain_entry);
18923 12654748 : ++new_entry;
18924 : }
18925 :
18926 : DCHECK_EQ(nod, removed_holes_index);
18927 :
18928 : new_table->SetNumberOfElements(nof);
18929 : table->SetNextTable(*new_table);
18930 :
18931 481207 : return new_table;
18932 : }
18933 :
18934 : template Handle<OrderedHashSet> OrderedHashTable<OrderedHashSet, 1>::Allocate(
18935 : Isolate* isolate, int capacity, PretenureFlag pretenure);
18936 :
18937 : template Handle<OrderedHashSet> OrderedHashTable<
18938 : OrderedHashSet, 1>::EnsureGrowable(Handle<OrderedHashSet> table);
18939 :
18940 : template Handle<OrderedHashSet> OrderedHashTable<OrderedHashSet, 1>::Shrink(
18941 : Handle<OrderedHashSet> table);
18942 :
18943 : template Handle<OrderedHashSet> OrderedHashTable<OrderedHashSet, 1>::Clear(
18944 : Handle<OrderedHashSet> table);
18945 :
18946 : template bool OrderedHashTable<OrderedHashSet, 1>::HasKey(
18947 : Handle<OrderedHashSet> table, Handle<Object> key);
18948 :
18949 : template Handle<OrderedHashMap> OrderedHashTable<OrderedHashMap, 2>::Allocate(
18950 : Isolate* isolate, int capacity, PretenureFlag pretenure);
18951 :
18952 : template Handle<OrderedHashMap> OrderedHashTable<
18953 : OrderedHashMap, 2>::EnsureGrowable(Handle<OrderedHashMap> table);
18954 :
18955 : template Handle<OrderedHashMap> OrderedHashTable<OrderedHashMap, 2>::Shrink(
18956 : Handle<OrderedHashMap> table);
18957 :
18958 : template Handle<OrderedHashMap> OrderedHashTable<OrderedHashMap, 2>::Clear(
18959 : Handle<OrderedHashMap> table);
18960 :
18961 : template bool OrderedHashTable<OrderedHashMap, 2>::HasKey(
18962 : Handle<OrderedHashMap> table, Handle<Object> key);
18963 :
18964 : template<class Derived, class TableType>
18965 12187 : void OrderedHashTableIterator<Derived, TableType>::Transition() {
18966 : DisallowHeapAllocation no_allocation;
18967 : TableType* table = TableType::cast(this->table());
18968 24374 : if (!table->IsObsolete()) return;
18969 :
18970 : int index = Smi::cast(this->index())->value();
18971 882 : while (table->IsObsolete()) {
18972 : TableType* next_table = table->NextTable();
18973 :
18974 490 : if (index > 0) {
18975 : int nod = table->NumberOfDeletedElements();
18976 :
18977 252 : if (nod == TableType::kClearedTableSentinel) {
18978 : index = 0;
18979 : } else {
18980 : int old_index = index;
18981 168 : for (int i = 0; i < nod; ++i) {
18982 : int removed_index = table->RemovedIndexAt(i);
18983 224 : if (removed_index >= old_index) break;
18984 168 : --index;
18985 : }
18986 : }
18987 : }
18988 :
18989 : table = next_table;
18990 : }
18991 :
18992 196 : set_table(table);
18993 196 : set_index(Smi::FromInt(index));
18994 : }
18995 :
18996 :
18997 : template<class Derived, class TableType>
18998 12283 : bool OrderedHashTableIterator<Derived, TableType>::HasMore() {
18999 : DisallowHeapAllocation no_allocation;
19000 : Isolate* isolate = this->GetIsolate();
19001 12283 : if (this->table()->IsUndefined(isolate)) return false;
19002 :
19003 12187 : Transition();
19004 :
19005 : TableType* table = TableType::cast(this->table());
19006 : int index = Smi::cast(this->index())->value();
19007 12187 : int used_capacity = table->UsedCapacity();
19008 :
19009 35607 : while (index < used_capacity && table->KeyAt(index)->IsTheHole(isolate)) {
19010 406 : index++;
19011 : }
19012 :
19013 12187 : set_index(Smi::FromInt(index));
19014 :
19015 12187 : if (index < used_capacity) return true;
19016 :
19017 1766 : set_table(isolate->heap()->undefined_value());
19018 1766 : return false;
19019 : }
19020 :
19021 :
19022 : template<class Derived, class TableType>
19023 12031 : Smi* OrderedHashTableIterator<Derived, TableType>::Next(JSArray* value_array) {
19024 : DisallowHeapAllocation no_allocation;
19025 12031 : if (HasMore()) {
19026 : FixedArray* array = FixedArray::cast(value_array->elements());
19027 10193 : static_cast<Derived*>(this)->PopulateValueArray(array);
19028 10193 : MoveNext();
19029 10193 : return Smi::cast(kind());
19030 : }
19031 : return Smi::kZero;
19032 : }
19033 :
19034 :
19035 : template Smi*
19036 : OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Next(
19037 : JSArray* value_array);
19038 :
19039 : template bool
19040 : OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::HasMore();
19041 :
19042 : template void
19043 : OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::MoveNext();
19044 :
19045 : template Object*
19046 : OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::CurrentKey();
19047 :
19048 : template void
19049 : OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Transition();
19050 :
19051 :
19052 : template Smi*
19053 : OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Next(
19054 : JSArray* value_array);
19055 :
19056 : template bool
19057 : OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::HasMore();
19058 :
19059 : template void
19060 : OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::MoveNext();
19061 :
19062 : template Object*
19063 : OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::CurrentKey();
19064 :
19065 : template void
19066 : OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Transition();
19067 :
19068 :
19069 78935 : void JSSet::Initialize(Handle<JSSet> set, Isolate* isolate) {
19070 78935 : Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
19071 78935 : set->set_table(*table);
19072 78935 : }
19073 :
19074 :
19075 45 : void JSSet::Clear(Handle<JSSet> set) {
19076 : Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()));
19077 45 : table = OrderedHashSet::Clear(table);
19078 45 : set->set_table(*table);
19079 45 : }
19080 :
19081 :
19082 80008 : void JSMap::Initialize(Handle<JSMap> map, Isolate* isolate) {
19083 80008 : Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
19084 80008 : map->set_table(*table);
19085 80008 : }
19086 :
19087 :
19088 314 : void JSMap::Clear(Handle<JSMap> map) {
19089 : Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()));
19090 314 : table = OrderedHashMap::Clear(table);
19091 314 : map->set_table(*table);
19092 314 : }
19093 :
19094 :
19095 129288 : void JSWeakCollection::Initialize(Handle<JSWeakCollection> weak_collection,
19096 : Isolate* isolate) {
19097 129288 : Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0);
19098 129288 : weak_collection->set_table(*table);
19099 129288 : }
19100 :
19101 :
19102 2938 : void JSWeakCollection::Set(Handle<JSWeakCollection> weak_collection,
19103 : Handle<Object> key, Handle<Object> value,
19104 : int32_t hash) {
19105 : DCHECK(key->IsJSReceiver() || key->IsSymbol());
19106 : Handle<ObjectHashTable> table(
19107 : ObjectHashTable::cast(weak_collection->table()));
19108 : DCHECK(table->IsKey(table->GetIsolate(), *key));
19109 : Handle<ObjectHashTable> new_table =
19110 2938 : ObjectHashTable::Put(table, key, value, hash);
19111 2938 : weak_collection->set_table(*new_table);
19112 2938 : if (*table != *new_table) {
19113 : // Zap the old table since we didn't record slots for its elements.
19114 238 : table->FillWithHoles(0, table->length());
19115 : }
19116 2938 : }
19117 :
19118 :
19119 118 : bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection,
19120 : Handle<Object> key, int32_t hash) {
19121 : DCHECK(key->IsJSReceiver() || key->IsSymbol());
19122 : Handle<ObjectHashTable> table(
19123 : ObjectHashTable::cast(weak_collection->table()));
19124 : DCHECK(table->IsKey(table->GetIsolate(), *key));
19125 118 : bool was_present = false;
19126 : Handle<ObjectHashTable> new_table =
19127 118 : ObjectHashTable::Remove(table, key, &was_present, hash);
19128 118 : weak_collection->set_table(*new_table);
19129 118 : if (*table != *new_table) {
19130 : // Zap the old table since we didn't record slots for its elements.
19131 0 : table->FillWithHoles(0, table->length());
19132 : }
19133 118 : return was_present;
19134 : }
19135 :
19136 36 : Handle<JSArray> JSWeakCollection::GetEntries(Handle<JSWeakCollection> holder,
19137 : int max_entries) {
19138 : Isolate* isolate = holder->GetIsolate();
19139 : Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
19140 36 : if (max_entries == 0 || max_entries > table->NumberOfElements()) {
19141 : max_entries = table->NumberOfElements();
19142 : }
19143 36 : int values_per_entry = holder->IsJSWeakMap() ? 2 : 1;
19144 : Handle<FixedArray> entries =
19145 36 : isolate->factory()->NewFixedArray(max_entries * values_per_entry);
19146 : // Recompute max_values because GC could have removed elements from the table.
19147 36 : if (max_entries > table->NumberOfElements()) {
19148 : max_entries = table->NumberOfElements();
19149 : }
19150 :
19151 : {
19152 : DisallowHeapAllocation no_gc;
19153 : int count = 0;
19154 192 : for (int i = 0;
19155 156 : count / values_per_entry < max_entries && i < table->Capacity(); i++) {
19156 : Handle<Object> key(table->KeyAt(i), isolate);
19157 60 : if (table->IsKey(isolate, *key)) {
19158 48 : entries->set(count++, *key);
19159 24 : if (values_per_entry > 1) {
19160 12 : Object* value = table->Lookup(key);
19161 24 : entries->set(count++, value);
19162 : }
19163 : }
19164 : }
19165 : DCHECK_EQ(max_entries * values_per_entry, count);
19166 : }
19167 36 : return isolate->factory()->NewJSArrayWithElements(entries);
19168 : }
19169 :
19170 : // Check if there is a break point at this source position.
19171 94182 : bool DebugInfo::HasBreakPoint(int source_position) {
19172 : // Get the break point info object for this code offset.
19173 94182 : Object* break_point_info = GetBreakPointInfo(source_position);
19174 :
19175 : // If there is no break point info object or no break points in the break
19176 : // point info object there is no break point at this code offset.
19177 94182 : if (break_point_info->IsUndefined(GetIsolate())) return false;
19178 5201 : return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
19179 : }
19180 :
19181 : // Get the break point info object for this source position.
19182 102192 : Object* DebugInfo::GetBreakPointInfo(int source_position) {
19183 : Isolate* isolate = GetIsolate();
19184 102192 : if (!break_points()->IsUndefined(isolate)) {
19185 839660 : for (int i = 0; i < break_points()->length(); i++) {
19186 379117 : if (!break_points()->get(i)->IsUndefined(isolate)) {
19187 : BreakPointInfo* break_point_info =
19188 : BreakPointInfo::cast(break_points()->get(i));
19189 52425 : if (break_point_info->source_position() == source_position) {
19190 : return break_point_info;
19191 : }
19192 : }
19193 : }
19194 : }
19195 91809 : return isolate->heap()->undefined_value();
19196 : }
19197 :
19198 2600 : bool DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
19199 : Handle<Object> break_point_object) {
19200 : Isolate* isolate = debug_info->GetIsolate();
19201 2600 : if (debug_info->break_points()->IsUndefined(isolate)) return false;
19202 :
19203 4292 : for (int i = 0; i < debug_info->break_points()->length(); i++) {
19204 3446 : if (debug_info->break_points()->get(i)->IsUndefined(isolate)) continue;
19205 : Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
19206 : BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
19207 3446 : if (BreakPointInfo::HasBreakPointObject(break_point_info,
19208 : break_point_object)) {
19209 2600 : BreakPointInfo::ClearBreakPoint(break_point_info, break_point_object);
19210 2600 : return true;
19211 : }
19212 : }
19213 : return false;
19214 : }
19215 :
19216 2977 : void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info, int source_position,
19217 : Handle<Object> break_point_object) {
19218 : Isolate* isolate = debug_info->GetIsolate();
19219 : Handle<Object> break_point_info(
19220 2977 : debug_info->GetBreakPointInfo(source_position), isolate);
19221 2977 : if (!break_point_info->IsUndefined(isolate)) {
19222 : BreakPointInfo::SetBreakPoint(
19223 : Handle<BreakPointInfo>::cast(break_point_info),
19224 149 : break_point_object);
19225 3126 : return;
19226 : }
19227 :
19228 : // Adding a new break point for a code offset which did not have any
19229 : // break points before. Try to find a free slot.
19230 : static const int kNoBreakPointInfo = -1;
19231 : int index = kNoBreakPointInfo;
19232 4484 : for (int i = 0; i < debug_info->break_points()->length(); i++) {
19233 3638 : if (debug_info->break_points()->get(i)->IsUndefined(isolate)) {
19234 : index = i;
19235 : break;
19236 : }
19237 : }
19238 2828 : if (index == kNoBreakPointInfo) {
19239 : // No free slot - extend break point info array.
19240 : Handle<FixedArray> old_break_points = Handle<FixedArray>(
19241 : FixedArray::cast(debug_info->break_points()), isolate);
19242 : Handle<FixedArray> new_break_points =
19243 : isolate->factory()->NewFixedArray(
19244 : old_break_points->length() +
19245 18 : DebugInfo::kEstimatedNofBreakPointsInFunction);
19246 :
19247 18 : debug_info->set_break_points(*new_break_points);
19248 180 : for (int i = 0; i < old_break_points->length(); i++) {
19249 72 : new_break_points->set(i, old_break_points->get(i));
19250 : }
19251 : index = old_break_points->length();
19252 : }
19253 : DCHECK(index != kNoBreakPointInfo);
19254 :
19255 : // Allocate new BreakPointInfo object and set the break point.
19256 : Handle<BreakPointInfo> new_break_point_info =
19257 2828 : isolate->factory()->NewBreakPointInfo(source_position);
19258 2828 : BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
19259 2828 : debug_info->break_points()->set(index, *new_break_point_info);
19260 : }
19261 :
19262 : // Get the break point objects for a source position.
19263 5033 : Handle<Object> DebugInfo::GetBreakPointObjects(int source_position) {
19264 5033 : Object* break_point_info = GetBreakPointInfo(source_position);
19265 : Isolate* isolate = GetIsolate();
19266 5033 : if (break_point_info->IsUndefined(isolate)) {
19267 0 : return isolate->factory()->undefined_value();
19268 : }
19269 : return Handle<Object>(
19270 5033 : BreakPointInfo::cast(break_point_info)->break_point_objects(), isolate);
19271 : }
19272 :
19273 :
19274 : // Get the total number of break points.
19275 3272 : int DebugInfo::GetBreakPointCount() {
19276 : Isolate* isolate = GetIsolate();
19277 3272 : if (break_points()->IsUndefined(isolate)) return 0;
19278 : int count = 0;
19279 30744 : for (int i = 0; i < break_points()->length(); i++) {
19280 13736 : if (!break_points()->get(i)->IsUndefined(isolate)) {
19281 : BreakPointInfo* break_point_info =
19282 : BreakPointInfo::cast(break_points()->get(i));
19283 5952 : count += break_point_info->GetBreakPointCount();
19284 : }
19285 : }
19286 : return count;
19287 : }
19288 :
19289 :
19290 9614 : Handle<Object> DebugInfo::FindBreakPointInfo(
19291 : Handle<DebugInfo> debug_info, Handle<Object> break_point_object) {
19292 : Isolate* isolate = debug_info->GetIsolate();
19293 9614 : if (!debug_info->break_points()->IsUndefined(isolate)) {
19294 67850 : for (int i = 0; i < debug_info->break_points()->length(); i++) {
19295 31718 : if (!debug_info->break_points()->get(i)->IsUndefined(isolate)) {
19296 : Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
19297 : BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
19298 8716 : if (BreakPointInfo::HasBreakPointObject(break_point_info,
19299 : break_point_object)) {
19300 2600 : return break_point_info;
19301 : }
19302 : }
19303 : }
19304 : }
19305 7014 : return isolate->factory()->undefined_value();
19306 : }
19307 :
19308 : // Remove the specified break point object.
19309 2600 : void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
19310 : Handle<Object> break_point_object) {
19311 : Isolate* isolate = break_point_info->GetIsolate();
19312 : // If there are no break points just ignore.
19313 2600 : if (break_point_info->break_point_objects()->IsUndefined(isolate)) return;
19314 : // If there is a single break point clear it if it is the same.
19315 2600 : if (!break_point_info->break_point_objects()->IsFixedArray()) {
19316 2428 : if (break_point_info->break_point_objects() == *break_point_object) {
19317 : break_point_info->set_break_point_objects(
19318 2428 : isolate->heap()->undefined_value());
19319 : }
19320 : return;
19321 : }
19322 : // If there are multiple break points shrink the array
19323 : DCHECK(break_point_info->break_point_objects()->IsFixedArray());
19324 : Handle<FixedArray> old_array =
19325 : Handle<FixedArray>(
19326 : FixedArray::cast(break_point_info->break_point_objects()));
19327 : Handle<FixedArray> new_array =
19328 172 : isolate->factory()->NewFixedArray(old_array->length() - 1);
19329 : int found_count = 0;
19330 1652 : for (int i = 0; i < old_array->length(); i++) {
19331 654 : if (old_array->get(i) == *break_point_object) {
19332 : DCHECK(found_count == 0);
19333 172 : found_count++;
19334 : } else {
19335 964 : new_array->set(i - found_count, old_array->get(i));
19336 : }
19337 : }
19338 : // If the break point was found in the list change it.
19339 344 : if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
19340 : }
19341 :
19342 :
19343 : // Add the specified break point object.
19344 3083 : void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
19345 : Handle<Object> break_point_object) {
19346 : Isolate* isolate = break_point_info->GetIsolate();
19347 :
19348 : // If there was no break point objects before just set it.
19349 3083 : if (break_point_info->break_point_objects()->IsUndefined(isolate)) {
19350 2934 : break_point_info->set_break_point_objects(*break_point_object);
19351 2934 : return;
19352 : }
19353 : // If the break point object is the same as before just ignore.
19354 149 : if (break_point_info->break_point_objects() == *break_point_object) return;
19355 : // If there was one break point object before replace with array.
19356 149 : if (!break_point_info->break_point_objects()->IsFixedArray()) {
19357 65 : Handle<FixedArray> array = isolate->factory()->NewFixedArray(2);
19358 65 : array->set(0, break_point_info->break_point_objects());
19359 65 : array->set(1, *break_point_object);
19360 65 : break_point_info->set_break_point_objects(*array);
19361 : return;
19362 : }
19363 : // If there was more than one break point before extend array.
19364 : Handle<FixedArray> old_array =
19365 : Handle<FixedArray>(
19366 : FixedArray::cast(break_point_info->break_point_objects()));
19367 : Handle<FixedArray> new_array =
19368 84 : isolate->factory()->NewFixedArray(old_array->length() + 1);
19369 1044 : for (int i = 0; i < old_array->length(); i++) {
19370 : // If the break point was there before just ignore.
19371 438 : if (old_array->get(i) == *break_point_object) return;
19372 438 : new_array->set(i, old_array->get(i));
19373 : }
19374 : // Add the new break point.
19375 84 : new_array->set(old_array->length(), *break_point_object);
19376 84 : break_point_info->set_break_point_objects(*new_array);
19377 : }
19378 :
19379 :
19380 12162 : bool BreakPointInfo::HasBreakPointObject(
19381 : Handle<BreakPointInfo> break_point_info,
19382 : Handle<Object> break_point_object) {
19383 : // No break point.
19384 : Isolate* isolate = break_point_info->GetIsolate();
19385 12162 : if (break_point_info->break_point_objects()->IsUndefined(isolate)) {
19386 : return false;
19387 : }
19388 : // Single break point.
19389 10524 : if (!break_point_info->break_point_objects()->IsFixedArray()) {
19390 10018 : return break_point_info->break_point_objects() == *break_point_object;
19391 : }
19392 : // Multiple break points.
19393 : FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
19394 1468 : for (int i = 0; i < array->length(); i++) {
19395 572 : if (array->get(i) == *break_point_object) {
19396 : return true;
19397 : }
19398 : }
19399 : return false;
19400 : }
19401 :
19402 :
19403 : // Get the number of break points.
19404 99917 : int BreakPointInfo::GetBreakPointCount() {
19405 : // No break point.
19406 99917 : if (break_point_objects()->IsUndefined(GetIsolate())) return 0;
19407 : // Single break point.
19408 95473 : if (!break_point_objects()->IsFixedArray()) return 1;
19409 : // Multiple break points.
19410 1217 : return FixedArray::cast(break_point_objects())->length();
19411 : }
19412 :
19413 :
19414 : // static
19415 229130 : MaybeHandle<JSDate> JSDate::New(Handle<JSFunction> constructor,
19416 : Handle<JSReceiver> new_target, double tv) {
19417 : Isolate* const isolate = constructor->GetIsolate();
19418 : Handle<JSObject> result;
19419 458260 : ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
19420 : JSObject::New(constructor, new_target), JSDate);
19421 229130 : if (-DateCache::kMaxTimeInMs <= tv && tv <= DateCache::kMaxTimeInMs) {
19422 228372 : tv = DoubleToInteger(tv) + 0.0;
19423 : } else {
19424 : tv = std::numeric_limits<double>::quiet_NaN();
19425 : }
19426 229130 : Handle<Object> value = isolate->factory()->NewNumber(tv);
19427 458260 : Handle<JSDate>::cast(result)->SetValue(*value, std::isnan(tv));
19428 : return Handle<JSDate>::cast(result);
19429 : }
19430 :
19431 :
19432 : // static
19433 21999634 : double JSDate::CurrentTimeValue(Isolate* isolate) {
19434 21999634 : if (FLAG_log_timer_events || FLAG_prof_cpp) LOG(isolate, CurrentTimeEvent());
19435 :
19436 : // According to ECMA-262, section 15.9.1, page 117, the precision of
19437 : // the number in a Date object representing a particular instant in
19438 : // time is milliseconds. Therefore, we floor the result of getting
19439 : // the OS time.
19440 : return Floor(FLAG_verify_predictable
19441 : ? isolate->heap()->MonotonicallyIncreasingTimeInMs()
19442 43999268 : : base::OS::TimeCurrentMillis());
19443 : }
19444 :
19445 :
19446 : // static
19447 17182 : Object* JSDate::GetField(Object* object, Smi* index) {
19448 : return JSDate::cast(object)->DoGetField(
19449 17182 : static_cast<FieldIndex>(index->value()));
19450 : }
19451 :
19452 :
19453 17182 : Object* JSDate::DoGetField(FieldIndex index) {
19454 : DCHECK(index != kDateValue);
19455 :
19456 25625 : DateCache* date_cache = GetIsolate()->date_cache();
19457 :
19458 17182 : if (index < kFirstUncachedField) {
19459 : Object* stamp = cache_stamp();
19460 16886 : if (stamp != date_cache->stamp() && stamp->IsSmi()) {
19461 : // Since the stamp is not NaN, the value is also not NaN.
19462 : int64_t local_time_ms =
19463 583 : date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
19464 583 : SetCachedFields(local_time_ms, date_cache);
19465 : }
19466 8443 : switch (index) {
19467 1390 : case kYear: return year();
19468 380 : case kMonth: return month();
19469 113 : case kDay: return day();
19470 0 : case kWeekday: return weekday();
19471 4887 : case kHour: return hour();
19472 1322 : case kMinute: return min();
19473 351 : case kSecond: return sec();
19474 0 : default: UNREACHABLE();
19475 : }
19476 : }
19477 :
19478 8739 : if (index >= kFirstUTCField) {
19479 8485 : return GetUTCField(index, value()->Number(), date_cache);
19480 : }
19481 :
19482 : double time = value()->Number();
19483 254 : if (std::isnan(time)) return GetIsolate()->heap()->nan_value();
19484 :
19485 169 : int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
19486 : int days = DateCache::DaysFromTime(local_time_ms);
19487 :
19488 169 : if (index == kDays) return Smi::FromInt(days);
19489 :
19490 : int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
19491 338 : if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
19492 : DCHECK(index == kTimeInDay);
19493 0 : return Smi::FromInt(time_in_day_ms);
19494 : }
19495 :
19496 :
19497 8485 : Object* JSDate::GetUTCField(FieldIndex index,
19498 : double value,
19499 : DateCache* date_cache) {
19500 : DCHECK(index >= kFirstUTCField);
19501 :
19502 16430 : if (std::isnan(value)) return GetIsolate()->heap()->nan_value();
19503 :
19504 540 : int64_t time_ms = static_cast<int64_t>(value);
19505 :
19506 540 : if (index == kTimezoneOffset) {
19507 29 : return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
19508 : }
19509 :
19510 : int days = DateCache::DaysFromTime(time_ms);
19511 :
19512 525 : if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
19513 :
19514 497 : if (index <= kDayUTC) {
19515 : int year, month, day;
19516 185 : date_cache->YearMonthDayFromDays(days, &year, &month, &day);
19517 242 : if (index == kYearUTC) return Smi::FromInt(year);
19518 184 : if (index == kMonthUTC) return Smi::FromInt(month);
19519 : DCHECK(index == kDayUTC);
19520 144 : return Smi::FromInt(day);
19521 : }
19522 :
19523 : int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
19524 312 : switch (index) {
19525 288 : case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
19526 140 : case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
19527 112 : case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
19528 84 : case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
19529 0 : case kDaysUTC: return Smi::FromInt(days);
19530 0 : case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
19531 0 : default: UNREACHABLE();
19532 : }
19533 :
19534 : UNREACHABLE();
19535 : return NULL;
19536 : }
19537 :
19538 :
19539 : // static
19540 17391 : Handle<Object> JSDate::SetValue(Handle<JSDate> date, double v) {
19541 : Isolate* const isolate = date->GetIsolate();
19542 17391 : Handle<Object> value = isolate->factory()->NewNumber(v);
19543 : bool value_is_nan = std::isnan(v);
19544 34782 : date->SetValue(*value, value_is_nan);
19545 17391 : return value;
19546 : }
19547 :
19548 :
19549 246521 : void JSDate::SetValue(Object* value, bool is_value_nan) {
19550 246521 : set_value(value);
19551 246521 : if (is_value_nan) {
19552 17376 : HeapNumber* nan = GetIsolate()->heap()->nan_value();
19553 17376 : set_cache_stamp(nan, SKIP_WRITE_BARRIER);
19554 17376 : set_year(nan, SKIP_WRITE_BARRIER);
19555 17376 : set_month(nan, SKIP_WRITE_BARRIER);
19556 17376 : set_day(nan, SKIP_WRITE_BARRIER);
19557 17376 : set_hour(nan, SKIP_WRITE_BARRIER);
19558 17376 : set_min(nan, SKIP_WRITE_BARRIER);
19559 17376 : set_sec(nan, SKIP_WRITE_BARRIER);
19560 17376 : set_weekday(nan, SKIP_WRITE_BARRIER);
19561 : } else {
19562 229145 : set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
19563 : }
19564 246521 : }
19565 :
19566 :
19567 1166 : void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) {
19568 : int days = DateCache::DaysFromTime(local_time_ms);
19569 : int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
19570 : int year, month, day;
19571 583 : date_cache->YearMonthDayFromDays(days, &year, &month, &day);
19572 : int weekday = date_cache->Weekday(days);
19573 583 : int hour = time_in_day_ms / (60 * 60 * 1000);
19574 583 : int min = (time_in_day_ms / (60 * 1000)) % 60;
19575 583 : int sec = (time_in_day_ms / 1000) % 60;
19576 583 : set_cache_stamp(date_cache->stamp());
19577 1166 : set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
19578 1166 : set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
19579 1166 : set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
19580 583 : set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
19581 583 : set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
19582 583 : set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
19583 583 : set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
19584 583 : }
19585 :
19586 : namespace {
19587 :
19588 : Script* ScriptFromJSValue(Object* in) {
19589 : DCHECK(in->IsJSValue());
19590 : JSValue* jsvalue = JSValue::cast(in);
19591 : DCHECK(jsvalue->value()->IsScript());
19592 : return Script::cast(jsvalue->value());
19593 : }
19594 :
19595 : } // namespace
19596 :
19597 13971 : int JSMessageObject::GetLineNumber() const {
19598 13971 : if (start_position() == -1) return Message::kNoLineNumberInfo;
19599 :
19600 13917 : Handle<Script> the_script = handle(ScriptFromJSValue(script()));
19601 :
19602 : Script::PositionInfo info;
19603 : const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
19604 13917 : if (!Script::GetPositionInfo(the_script, start_position(), &info,
19605 13917 : offset_flag)) {
19606 : return Message::kNoLineNumberInfo;
19607 : }
19608 :
19609 13917 : return info.line + 1;
19610 : }
19611 :
19612 24943 : int JSMessageObject::GetColumnNumber() const {
19613 24943 : if (start_position() == -1) return -1;
19614 :
19615 24889 : Handle<Script> the_script = handle(ScriptFromJSValue(script()));
19616 :
19617 : Script::PositionInfo info;
19618 : const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
19619 24889 : if (!Script::GetPositionInfo(the_script, start_position(), &info,
19620 24889 : offset_flag)) {
19621 : return -1;
19622 : }
19623 :
19624 24889 : return info.column; // Note: No '+1' in contrast to GetLineNumber.
19625 : }
19626 :
19627 11538 : Handle<String> JSMessageObject::GetSourceLine() const {
19628 : Handle<Script> the_script = handle(ScriptFromJSValue(script()));
19629 :
19630 : Isolate* isolate = the_script->GetIsolate();
19631 11538 : if (the_script->type() == Script::TYPE_WASM) {
19632 : return isolate->factory()->empty_string();
19633 : }
19634 :
19635 : Script::PositionInfo info;
19636 : const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
19637 11538 : if (!Script::GetPositionInfo(the_script, start_position(), &info,
19638 11538 : offset_flag)) {
19639 : return isolate->factory()->empty_string();
19640 : }
19641 :
19642 11538 : Handle<String> src = handle(String::cast(the_script->source()), isolate);
19643 11538 : return isolate->factory()->NewSubString(src, info.line_start, info.line_end);
19644 : }
19645 :
19646 3268 : void JSArrayBuffer::Neuter() {
19647 3268 : CHECK(is_neuterable());
19648 3268 : CHECK(is_external());
19649 : set_backing_store(NULL);
19650 3268 : set_byte_length(Smi::kZero);
19651 : set_was_neutered(true);
19652 : // Invalidate the neutering protector.
19653 : Isolate* const isolate = GetIsolate();
19654 3268 : if (isolate->IsArrayBufferNeuteringIntact()) {
19655 228 : isolate->InvalidateArrayBufferNeuteringProtector();
19656 : }
19657 3268 : }
19658 :
19659 :
19660 132532 : void JSArrayBuffer::Setup(Handle<JSArrayBuffer> array_buffer, Isolate* isolate,
19661 : bool is_external, void* data, size_t allocated_length,
19662 : SharedFlag shared) {
19663 : DCHECK(array_buffer->GetEmbedderFieldCount() ==
19664 : v8::ArrayBuffer::kEmbedderFieldCount);
19665 397596 : for (int i = 0; i < v8::ArrayBuffer::kEmbedderFieldCount; i++) {
19666 : array_buffer->SetEmbedderField(i, Smi::kZero);
19667 : }
19668 : array_buffer->set_bit_field(0);
19669 : array_buffer->set_is_external(is_external);
19670 132532 : array_buffer->set_is_neuterable(shared == SharedFlag::kNotShared);
19671 132532 : array_buffer->set_is_shared(shared == SharedFlag::kShared);
19672 :
19673 : Handle<Object> byte_length =
19674 132532 : isolate->factory()->NewNumberFromSize(allocated_length);
19675 132626 : CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
19676 132532 : array_buffer->set_byte_length(*byte_length);
19677 : // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
19678 : // are currently being constructed in the |ArrayBufferTracker|. The
19679 : // registration method below handles the case of registering a buffer that has
19680 : // already been promoted.
19681 : array_buffer->set_backing_store(data);
19682 :
19683 132532 : if (data && !is_external) {
19684 114744 : isolate->heap()->RegisterNewArrayBuffer(*array_buffer);
19685 : }
19686 132532 : }
19687 :
19688 : namespace {
19689 :
19690 : inline int ConvertToMb(size_t size) {
19691 103542 : return static_cast<int>(size / static_cast<size_t>(MB));
19692 : }
19693 :
19694 : } // namespace
19695 :
19696 120119 : bool JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer> array_buffer,
19697 327204 : Isolate* isolate,
19698 : size_t allocated_length,
19699 : bool initialize, SharedFlag shared) {
19700 : void* data;
19701 120119 : CHECK(isolate->array_buffer_allocator() != NULL);
19702 : // Prevent creating array buffers when serializing.
19703 : DCHECK(!isolate->serializer_enabled());
19704 120119 : if (allocated_length != 0) {
19705 : isolate->counters()->array_buffer_big_allocations()->AddSample(
19706 103542 : ConvertToMb(allocated_length));
19707 103542 : if (initialize) {
19708 102408 : data = isolate->array_buffer_allocator()->Allocate(allocated_length);
19709 : } else {
19710 : data = isolate->array_buffer_allocator()->AllocateUninitialized(
19711 1134 : allocated_length);
19712 : }
19713 103542 : if (data == NULL) {
19714 : isolate->counters()->array_buffer_new_size_failures()->AddSample(
19715 1 : ConvertToMb(allocated_length));
19716 1 : return false;
19717 : }
19718 : } else {
19719 : data = NULL;
19720 : }
19721 :
19722 : JSArrayBuffer::Setup(array_buffer, isolate, false, data, allocated_length,
19723 120118 : shared);
19724 120118 : return true;
19725 : }
19726 :
19727 :
19728 15430 : Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
19729 : Handle<JSTypedArray> typed_array) {
19730 :
19731 : Handle<Map> map(typed_array->map());
19732 15430 : Isolate* isolate = typed_array->GetIsolate();
19733 :
19734 : DCHECK(IsFixedTypedArrayElementsKind(map->elements_kind()));
19735 :
19736 : Handle<FixedTypedArrayBase> fixed_typed_array(
19737 : FixedTypedArrayBase::cast(typed_array->elements()));
19738 :
19739 : Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(typed_array->buffer()),
19740 : isolate);
19741 : void* backing_store =
19742 : isolate->array_buffer_allocator()->AllocateUninitialized(
19743 30860 : fixed_typed_array->DataSize());
19744 : buffer->set_is_external(false);
19745 : DCHECK(buffer->byte_length()->IsSmi() ||
19746 : buffer->byte_length()->IsHeapNumber());
19747 : DCHECK(NumberToInt32(buffer->byte_length()) == fixed_typed_array->DataSize());
19748 : // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
19749 : // are currently being constructed in the |ArrayBufferTracker|. The
19750 : // registration method below handles the case of registering a buffer that has
19751 : // already been promoted.
19752 : buffer->set_backing_store(backing_store);
19753 15430 : isolate->heap()->RegisterNewArrayBuffer(*buffer);
19754 : memcpy(buffer->backing_store(),
19755 : fixed_typed_array->DataPtr(),
19756 15430 : fixed_typed_array->DataSize());
19757 : Handle<FixedTypedArrayBase> new_elements =
19758 : isolate->factory()->NewFixedTypedArrayWithExternalPointer(
19759 : fixed_typed_array->length(), typed_array->type(),
19760 30860 : static_cast<uint8_t*>(buffer->backing_store()));
19761 :
19762 15430 : typed_array->set_elements(*new_elements);
19763 :
19764 15430 : return buffer;
19765 : }
19766 :
19767 :
19768 37902625 : Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
19769 : Handle<JSArrayBuffer> array_buffer(JSArrayBuffer::cast(buffer()),
19770 : GetIsolate());
19771 75805228 : if (array_buffer->was_neutered() ||
19772 : array_buffer->backing_store() != nullptr) {
19773 37887204 : return array_buffer;
19774 : }
19775 : Handle<JSTypedArray> self(this);
19776 15430 : return MaterializeArrayBuffer(self);
19777 : }
19778 :
19779 22497 : Handle<PropertyCell> PropertyCell::InvalidateEntry(
19780 : Handle<GlobalDictionary> dictionary, int entry) {
19781 : Isolate* isolate = dictionary->GetIsolate();
19782 : // Swap with a copy.
19783 : DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
19784 22497 : Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
19785 22497 : Handle<PropertyCell> new_cell = isolate->factory()->NewPropertyCell();
19786 22497 : new_cell->set_value(cell->value());
19787 : dictionary->ValueAtPut(entry, *new_cell);
19788 : bool is_the_hole = cell->value()->IsTheHole(isolate);
19789 : // Cell is officially mutable henceforth.
19790 : PropertyDetails details = cell->property_details();
19791 : details = details.set_cell_type(is_the_hole ? PropertyCellType::kUninitialized
19792 22497 : : PropertyCellType::kMutable);
19793 : new_cell->set_property_details(details);
19794 : // Old cell is ready for invalidation.
19795 22497 : if (is_the_hole) {
19796 19590 : cell->set_value(isolate->heap()->undefined_value());
19797 : } else {
19798 25404 : cell->set_value(isolate->heap()->the_hole_value());
19799 : }
19800 : details = details.set_cell_type(PropertyCellType::kInvalidated);
19801 : cell->set_property_details(details);
19802 : cell->dependent_code()->DeoptimizeDependentCodeGroup(
19803 22497 : isolate, DependentCode::kPropertyCellChangedGroup);
19804 22497 : return new_cell;
19805 : }
19806 :
19807 :
19808 13011 : PropertyCellConstantType PropertyCell::GetConstantType() {
19809 13011 : if (value()->IsSmi()) return PropertyCellConstantType::kSmi;
19810 2763 : return PropertyCellConstantType::kStableMap;
19811 : }
19812 :
19813 :
19814 1272659 : static bool RemainsConstantType(Handle<PropertyCell> cell,
19815 : Handle<Object> value) {
19816 : // TODO(dcarney): double->smi and smi->double transition from kConstant
19817 2451524 : if (cell->value()->IsSmi() && value->IsSmi()) {
19818 : return true;
19819 190038 : } else if (cell->value()->IsHeapObject() && value->IsHeapObject()) {
19820 : return HeapObject::cast(cell->value())->map() ==
19821 172254 : HeapObject::cast(*value)->map() &&
19822 92754 : HeapObject::cast(*value)->map()->is_stable();
19823 : }
19824 : return false;
19825 : }
19826 :
19827 :
19828 11911784 : PropertyCellType PropertyCell::UpdatedType(Handle<PropertyCell> cell,
19829 : Handle<Object> value,
19830 : PropertyDetails details) {
19831 : PropertyCellType type = details.cell_type();
19832 : Isolate* isolate = cell->GetIsolate();
19833 : DCHECK(!value->IsTheHole(isolate));
19834 11911784 : if (cell->value()->IsTheHole(isolate)) {
19835 8835027 : switch (type) {
19836 : // Only allow a cell to transition once into constant state.
19837 : case PropertyCellType::kUninitialized:
19838 8835029 : if (value->IsUndefined(isolate)) return PropertyCellType::kUndefined;
19839 7133039 : return PropertyCellType::kConstant;
19840 : case PropertyCellType::kInvalidated:
19841 : return PropertyCellType::kMutable;
19842 : default:
19843 0 : UNREACHABLE();
19844 : return PropertyCellType::kMutable;
19845 : }
19846 : }
19847 3076757 : switch (type) {
19848 : case PropertyCellType::kUndefined:
19849 : return PropertyCellType::kConstant;
19850 : case PropertyCellType::kConstant:
19851 102558 : if (*value == cell->value()) return PropertyCellType::kConstant;
19852 : // Fall through.
19853 : case PropertyCellType::kConstantType:
19854 1272659 : if (RemainsConstantType(cell, value)) {
19855 : return PropertyCellType::kConstantType;
19856 : }
19857 : // Fall through.
19858 : case PropertyCellType::kMutable:
19859 : return PropertyCellType::kMutable;
19860 : }
19861 0 : UNREACHABLE();
19862 : return PropertyCellType::kMutable;
19863 : }
19864 :
19865 3084107 : Handle<PropertyCell> PropertyCell::PrepareForValue(
19866 : Handle<GlobalDictionary> dictionary, int entry, Handle<Object> value,
19867 : PropertyDetails details) {
19868 : Isolate* isolate = dictionary->GetIsolate();
19869 : DCHECK(!value->IsTheHole(isolate));
19870 : DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
19871 3084107 : Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
19872 : const PropertyDetails original_details = cell->property_details();
19873 : // Data accesses could be cached in ics or optimized code.
19874 : bool invalidate =
19875 6167237 : original_details.kind() == kData && details.kind() == kAccessor;
19876 : int index = original_details.dictionary_index();
19877 : PropertyCellType old_type = original_details.cell_type();
19878 : // Preserve the enumeration index unless the property was deleted or never
19879 : // initialized.
19880 3084107 : if (cell->value()->IsTheHole(isolate)) {
19881 : index = dictionary->NextEnumerationIndex();
19882 7350 : dictionary->SetNextEnumerationIndex(index + 1);
19883 : }
19884 : DCHECK(index > 0);
19885 : details = details.set_index(index);
19886 :
19887 3084107 : PropertyCellType new_type = UpdatedType(cell, value, original_details);
19888 3084107 : if (invalidate) cell = PropertyCell::InvalidateEntry(dictionary, entry);
19889 :
19890 : // Install new property details.
19891 : details = details.set_cell_type(new_type);
19892 : cell->set_property_details(details);
19893 :
19894 : // Deopt when transitioning from a constant type.
19895 4503113 : if (!invalidate && (old_type != new_type ||
19896 : original_details.IsReadOnly() != details.IsReadOnly())) {
19897 : cell->dependent_code()->DeoptimizeDependentCodeGroup(
19898 1668804 : isolate, DependentCode::kPropertyCellChangedGroup);
19899 : }
19900 3084107 : return cell;
19901 : }
19902 :
19903 :
19904 : // static
19905 1007 : void PropertyCell::SetValueWithInvalidation(Handle<PropertyCell> cell,
19906 : Handle<Object> new_value) {
19907 1007 : if (cell->value() != *new_value) {
19908 1007 : cell->set_value(*new_value);
19909 : Isolate* isolate = cell->GetIsolate();
19910 : cell->dependent_code()->DeoptimizeDependentCodeGroup(
19911 1007 : isolate, DependentCode::kPropertyCellChangedGroup);
19912 : }
19913 1007 : }
19914 :
19915 42 : int JSGeneratorObject::source_position() const {
19916 42 : CHECK(is_suspended());
19917 : DCHECK(function()->shared()->HasBytecodeArray());
19918 : DCHECK(!function()->shared()->HasBaselineCode());
19919 :
19920 : int code_offset;
19921 : const JSAsyncGeneratorObject* async =
19922 42 : IsJSAsyncGeneratorObject() ? JSAsyncGeneratorObject::cast(this) : nullptr;
19923 42 : if (async != nullptr && async->awaited_promise()->IsJSPromise()) {
19924 : code_offset = Smi::cast(async->await_input_or_debug_pos())->value();
19925 : } else {
19926 : code_offset = Smi::cast(input_or_debug_pos())->value();
19927 : }
19928 :
19929 : // The stored bytecode offset is relative to a different base than what
19930 : // is used in the source position table, hence the subtraction.
19931 42 : code_offset -= BytecodeArray::kHeaderSize - kHeapObjectTag;
19932 : AbstractCode* code =
19933 : AbstractCode::cast(function()->shared()->bytecode_array());
19934 42 : return code->SourcePosition(code_offset);
19935 : }
19936 :
19937 : // static
19938 5978 : AccessCheckInfo* AccessCheckInfo::Get(Isolate* isolate,
19939 : Handle<JSObject> receiver) {
19940 : DisallowHeapAllocation no_gc;
19941 : DCHECK(receiver->map()->is_access_check_needed());
19942 5978 : Object* maybe_constructor = receiver->map()->GetConstructor();
19943 5978 : if (maybe_constructor->IsFunctionTemplateInfo()) {
19944 : Object* data_obj =
19945 : FunctionTemplateInfo::cast(maybe_constructor)->access_check_info();
19946 203 : if (data_obj->IsUndefined(isolate)) return nullptr;
19947 203 : return AccessCheckInfo::cast(data_obj);
19948 : }
19949 : // Might happen for a detached context.
19950 5775 : if (!maybe_constructor->IsJSFunction()) return nullptr;
19951 : JSFunction* constructor = JSFunction::cast(maybe_constructor);
19952 : // Might happen for the debug context.
19953 5743 : if (!constructor->shared()->IsApiFunction()) return nullptr;
19954 :
19955 : Object* data_obj =
19956 : constructor->shared()->get_api_func_data()->access_check_info();
19957 5206 : if (data_obj->IsUndefined(isolate)) return nullptr;
19958 :
19959 4373 : return AccessCheckInfo::cast(data_obj);
19960 : }
19961 :
19962 6145 : bool JSReceiver::HasProxyInPrototype(Isolate* isolate) {
19963 25300 : for (PrototypeIterator iter(isolate, this, kStartAtReceiver,
19964 : PrototypeIterator::END_AT_NULL);
19965 19155 : !iter.IsAtEnd(); iter.AdvanceIgnoringProxies()) {
19966 38396 : if (iter.GetCurrent<Object>()->IsJSProxy()) return true;
19967 : }
19968 6102 : return false;
19969 : }
19970 :
19971 853 : MaybeHandle<Object> JSModuleNamespace::GetExport(Handle<String> name) {
19972 : Isolate* isolate = name->GetIsolate();
19973 :
19974 1706 : Handle<Object> object(module()->exports()->Lookup(name), isolate);
19975 853 : if (object->IsTheHole(isolate)) {
19976 : return isolate->factory()->undefined_value();
19977 : }
19978 :
19979 : Handle<Object> value(Handle<Cell>::cast(object)->value(), isolate);
19980 853 : if (value->IsTheHole(isolate)) {
19981 210 : THROW_NEW_ERROR(
19982 : isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object);
19983 : }
19984 :
19985 : return value;
19986 : }
19987 :
19988 : namespace {
19989 :
19990 : struct ModuleHandleHash {
19991 : V8_INLINE size_t operator()(Handle<Module> module) const {
19992 732 : return module->hash();
19993 : }
19994 : };
19995 :
19996 : struct ModuleHandleEqual {
19997 : V8_INLINE bool operator()(Handle<Module> lhs, Handle<Module> rhs) const {
19998 : return *lhs == *rhs;
19999 : }
20000 : };
20001 :
20002 : struct StringHandleHash {
20003 : V8_INLINE size_t operator()(Handle<String> string) const {
20004 552 : return string->Hash();
20005 : }
20006 : };
20007 :
20008 : struct StringHandleEqual {
20009 : V8_INLINE bool operator()(Handle<String> lhs, Handle<String> rhs) const {
20010 45 : return lhs->Equals(*rhs);
20011 : }
20012 : };
20013 :
20014 : class UnorderedStringSet
20015 : : public std::unordered_set<Handle<String>, StringHandleHash,
20016 : StringHandleEqual,
20017 : ZoneAllocator<Handle<String>>> {
20018 : public:
20019 314 : explicit UnorderedStringSet(Zone* zone)
20020 : : std::unordered_set<Handle<String>, StringHandleHash, StringHandleEqual,
20021 : ZoneAllocator<Handle<String>>>(
20022 : 2 /* bucket count */, StringHandleHash(), StringHandleEqual(),
20023 314 : ZoneAllocator<Handle<String>>(zone)) {}
20024 : };
20025 :
20026 : class UnorderedModuleSet
20027 : : public std::unordered_set<Handle<Module>, ModuleHandleHash,
20028 : ModuleHandleEqual,
20029 : ZoneAllocator<Handle<Module>>> {
20030 : public:
20031 300 : explicit UnorderedModuleSet(Zone* zone)
20032 : : std::unordered_set<Handle<Module>, ModuleHandleHash, ModuleHandleEqual,
20033 : ZoneAllocator<Handle<Module>>>(
20034 : 2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(),
20035 300 : ZoneAllocator<Handle<Module>>(zone)) {}
20036 : };
20037 :
20038 : class UnorderedStringMap
20039 : : public std::unordered_map<
20040 : Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual,
20041 : ZoneAllocator<std::pair<const Handle<String>, Handle<Object>>>> {
20042 : public:
20043 388 : explicit UnorderedStringMap(Zone* zone)
20044 : : std::unordered_map<
20045 : Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual,
20046 : ZoneAllocator<std::pair<const Handle<String>, Handle<Object>>>>(
20047 : 2 /* bucket count */, StringHandleHash(), StringHandleEqual(),
20048 : ZoneAllocator<std::pair<const Handle<String>, Handle<Object>>>(
20049 388 : zone)) {}
20050 : };
20051 :
20052 : } // anonymous namespace
20053 :
20054 : class Module::ResolveSet
20055 : : public std::unordered_map<
20056 : Handle<Module>, UnorderedStringSet*, ModuleHandleHash,
20057 : ModuleHandleEqual,
20058 : ZoneAllocator<std::pair<const Handle<Module>, UnorderedStringSet*>>> {
20059 : public:
20060 1077 : explicit ResolveSet(Zone* zone)
20061 : : std::unordered_map<Handle<Module>, UnorderedStringSet*,
20062 : ModuleHandleHash, ModuleHandleEqual,
20063 : ZoneAllocator<std::pair<const Handle<Module>,
20064 : UnorderedStringSet*>>>(
20065 : 2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(),
20066 : ZoneAllocator<std::pair<const Handle<Module>, UnorderedStringSet*>>(
20067 : zone)),
20068 1077 : zone_(zone) {}
20069 :
20070 : Zone* zone() const { return zone_; }
20071 :
20072 : private:
20073 : Zone* zone_;
20074 : };
20075 :
20076 : namespace {
20077 :
20078 : int ExportIndex(int cell_index) {
20079 : DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
20080 : ModuleDescriptor::kExport);
20081 2060 : return cell_index - 1;
20082 : }
20083 :
20084 : int ImportIndex(int cell_index) {
20085 : DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
20086 : ModuleDescriptor::kImport);
20087 991 : return -cell_index - 1;
20088 : }
20089 :
20090 : } // anonymous namespace
20091 :
20092 180 : void Module::CreateIndirectExport(Handle<Module> module, Handle<String> name,
20093 : Handle<ModuleInfoEntry> entry) {
20094 : Isolate* isolate = module->GetIsolate();
20095 : Handle<ObjectHashTable> exports(module->exports(), isolate);
20096 : DCHECK(exports->Lookup(name)->IsTheHole(isolate));
20097 180 : exports = ObjectHashTable::Put(exports, name, entry);
20098 180 : module->set_exports(*exports);
20099 180 : }
20100 :
20101 1976 : void Module::CreateExport(Handle<Module> module, int cell_index,
20102 : Handle<FixedArray> names) {
20103 : DCHECK_LT(0, names->length());
20104 : Isolate* isolate = module->GetIsolate();
20105 :
20106 : Handle<Cell> cell =
20107 1976 : isolate->factory()->NewCell(isolate->factory()->undefined_value());
20108 1976 : module->regular_exports()->set(ExportIndex(cell_index), *cell);
20109 :
20110 : Handle<ObjectHashTable> exports(module->exports(), isolate);
20111 4147 : for (int i = 0, n = names->length(); i < n; ++i) {
20112 : Handle<String> name(String::cast(names->get(i)), isolate);
20113 : DCHECK(exports->Lookup(name)->IsTheHole(isolate));
20114 2171 : exports = ObjectHashTable::Put(exports, name, cell);
20115 : }
20116 1976 : module->set_exports(*exports);
20117 1976 : }
20118 :
20119 192 : Handle<Object> Module::LoadVariable(Handle<Module> module, int cell_index) {
20120 : Isolate* isolate = module->GetIsolate();
20121 : Handle<Object> object;
20122 192 : switch (ModuleDescriptor::GetCellIndexKind(cell_index)) {
20123 : case ModuleDescriptor::kImport:
20124 : object = handle(module->regular_imports()->get(ImportIndex(cell_index)),
20125 : isolate);
20126 108 : break;
20127 : case ModuleDescriptor::kExport:
20128 : object = handle(module->regular_exports()->get(ExportIndex(cell_index)),
20129 : isolate);
20130 84 : break;
20131 : case ModuleDescriptor::kInvalid:
20132 0 : UNREACHABLE();
20133 : break;
20134 : }
20135 192 : return handle(Handle<Cell>::cast(object)->value(), isolate);
20136 : }
20137 :
20138 0 : void Module::StoreVariable(Handle<Module> module, int cell_index,
20139 : Handle<Object> value) {
20140 : Isolate* isolate = module->GetIsolate();
20141 : DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
20142 : ModuleDescriptor::kExport);
20143 : Handle<Object> object(module->regular_exports()->get(ExportIndex(cell_index)),
20144 : isolate);
20145 0 : Handle<Cell>::cast(object)->set_value(*value);
20146 0 : }
20147 :
20148 1227 : MaybeHandle<Cell> Module::ResolveImport(Handle<Module> module,
20149 : Handle<String> name, int module_request,
20150 : MessageLocation loc, bool must_resolve,
20151 : Module::ResolveSet* resolve_set) {
20152 : Isolate* isolate = module->GetIsolate();
20153 : Handle<Module> requested_module(
20154 : Module::cast(module->requested_modules()->get(module_request)), isolate);
20155 : return Module::ResolveExport(requested_module, name, loc, must_resolve,
20156 1227 : resolve_set);
20157 : }
20158 :
20159 1407 : MaybeHandle<Cell> Module::ResolveExport(Handle<Module> module,
20160 : Handle<String> name,
20161 : MessageLocation loc, bool must_resolve,
20162 314 : Module::ResolveSet* resolve_set) {
20163 : DCHECK_EQ(module->status(), kPrepared);
20164 : Isolate* isolate = module->GetIsolate();
20165 2814 : Handle<Object> object(module->exports()->Lookup(name), isolate);
20166 1407 : if (object->IsCell()) {
20167 : // Already resolved (e.g. because it's a local export).
20168 : return Handle<Cell>::cast(object);
20169 : }
20170 :
20171 : // Check for cycle before recursing.
20172 : {
20173 : // Attempt insertion with a null string set.
20174 329 : auto result = resolve_set->insert({module, nullptr});
20175 : UnorderedStringSet*& name_set = result.first->second;
20176 329 : if (result.second) {
20177 : // |module| wasn't in the map previously, so allocate a new name set.
20178 : Zone* zone = resolve_set->zone();
20179 : name_set =
20180 314 : new (zone->New(sizeof(UnorderedStringSet))) UnorderedStringSet(zone);
20181 30 : } else if (name_set->count(name)) {
20182 : // Cycle detected.
20183 15 : if (must_resolve) {
20184 : return isolate->Throw<Cell>(
20185 : isolate->factory()->NewSyntaxError(
20186 : MessageTemplate::kCyclicModuleDependency, name),
20187 0 : &loc);
20188 : }
20189 : return MaybeHandle<Cell>();
20190 : }
20191 314 : name_set->insert(name);
20192 : }
20193 :
20194 314 : if (object->IsModuleInfoEntry()) {
20195 : // Not yet resolved indirect export.
20196 : Handle<ModuleInfoEntry> entry = Handle<ModuleInfoEntry>::cast(object);
20197 : Handle<String> import_name(String::cast(entry->import_name()), isolate);
20198 : Handle<Script> script(
20199 : Script::cast(JSFunction::cast(module->code())->shared()->script()),
20200 : isolate);
20201 180 : MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos());
20202 :
20203 : Handle<Cell> cell;
20204 180 : if (!ResolveImport(module, import_name, entry->module_request(), new_loc,
20205 : true, resolve_set)
20206 360 : .ToHandle(&cell)) {
20207 : DCHECK(isolate->has_pending_exception());
20208 : return MaybeHandle<Cell>();
20209 : }
20210 :
20211 : // The export table may have changed but the entry in question should be
20212 : // unchanged.
20213 : Handle<ObjectHashTable> exports(module->exports(), isolate);
20214 : DCHECK(exports->Lookup(name)->IsModuleInfoEntry());
20215 :
20216 180 : exports = ObjectHashTable::Put(exports, name, cell);
20217 180 : module->set_exports(*exports);
20218 : return cell;
20219 : }
20220 :
20221 : DCHECK(object->IsTheHole(isolate));
20222 : return Module::ResolveExportUsingStarExports(module, name, loc, must_resolve,
20223 134 : resolve_set);
20224 : }
20225 :
20226 134 : MaybeHandle<Cell> Module::ResolveExportUsingStarExports(
20227 : Handle<Module> module, Handle<String> name, MessageLocation loc,
20228 : bool must_resolve, Module::ResolveSet* resolve_set) {
20229 : Isolate* isolate = module->GetIsolate();
20230 268 : if (!name->Equals(isolate->heap()->default_string())) {
20231 : // Go through all star exports looking for the given name. If multiple star
20232 : // exports provide the name, make sure they all map it to the same cell.
20233 : Handle<Cell> unique_cell;
20234 : Handle<FixedArray> special_exports(module->info()->special_exports(),
20235 120 : isolate);
20236 360 : for (int i = 0, n = special_exports->length(); i < n; ++i) {
20237 : i::Handle<i::ModuleInfoEntry> entry(
20238 : i::ModuleInfoEntry::cast(special_exports->get(i)), isolate);
20239 240 : if (!entry->export_name()->IsUndefined(isolate)) {
20240 90 : continue; // Indirect export.
20241 : }
20242 :
20243 : Handle<Script> script(
20244 : Script::cast(JSFunction::cast(module->code())->shared()->script()),
20245 : isolate);
20246 150 : MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos());
20247 :
20248 : Handle<Cell> cell;
20249 150 : if (ResolveImport(module, name, entry->module_request(), new_loc, false,
20250 : resolve_set)
20251 300 : .ToHandle(&cell)) {
20252 90 : if (unique_cell.is_null()) unique_cell = cell;
20253 90 : if (*unique_cell != *cell) {
20254 : return isolate->Throw<Cell>(
20255 : isolate->factory()->NewSyntaxError(
20256 : MessageTemplate::kAmbiguousExport, name),
20257 0 : &loc);
20258 : }
20259 60 : } else if (isolate->has_pending_exception()) {
20260 : return MaybeHandle<Cell>();
20261 : }
20262 : }
20263 :
20264 120 : if (!unique_cell.is_null()) {
20265 : // Found a unique star export for this name.
20266 : Handle<ObjectHashTable> exports(module->exports(), isolate);
20267 : DCHECK(exports->Lookup(name)->IsTheHole(isolate));
20268 75 : exports = ObjectHashTable::Put(exports, name, unique_cell);
20269 75 : module->set_exports(*exports);
20270 : return unique_cell;
20271 : }
20272 : }
20273 :
20274 : // Unresolvable.
20275 59 : if (must_resolve) {
20276 : return isolate->Throw<Cell>(isolate->factory()->NewSyntaxError(
20277 : MessageTemplate::kUnresolvableExport, name),
20278 28 : &loc);
20279 : }
20280 : return MaybeHandle<Cell>();
20281 : }
20282 :
20283 1216 : bool Module::Instantiate(Handle<Module> module, v8::Local<v8::Context> context,
20284 : v8::Module::ResolveCallback callback) {
20285 2418 : return PrepareInstantiate(module, context, callback) &&
20286 2418 : FinishInstantiate(module, context);
20287 : }
20288 :
20289 2362 : bool Module::PrepareInstantiate(Handle<Module> module,
20290 : v8::Local<v8::Context> context,
20291 : v8::Module::ResolveCallback callback) {
20292 2362 : if (module->status() == kPrepared) return true;
20293 :
20294 : // Obtain requested modules.
20295 : Isolate* isolate = module->GetIsolate();
20296 1917 : Handle<ModuleInfo> module_info(module->info(), isolate);
20297 : Handle<FixedArray> module_requests(module_info->module_requests(), isolate);
20298 : Handle<FixedArray> requested_modules(module->requested_modules(), isolate);
20299 3070 : for (int i = 0, length = module_requests->length(); i < length; ++i) {
20300 : Handle<String> specifier(String::cast(module_requests->get(i)), isolate);
20301 : v8::Local<v8::Module> api_requested_module;
20302 1167 : if (!callback(context, v8::Utils::ToLocal(specifier),
20303 : v8::Utils::ToLocal(module))
20304 2334 : .ToLocal(&api_requested_module)) {
20305 14 : isolate->PromoteScheduledException();
20306 : return false;
20307 : }
20308 : Handle<Module> requested_module = Utils::OpenHandle(*api_requested_module);
20309 1153 : requested_modules->set(i, *requested_module);
20310 : }
20311 :
20312 : // Recurse.
20313 : module->set_status(kPrepared);
20314 3049 : for (int i = 0, length = requested_modules->length(); i < length; ++i) {
20315 : Handle<Module> requested_module(Module::cast(requested_modules->get(i)),
20316 : isolate);
20317 1146 : if (!PrepareInstantiate(requested_module, context, callback)) return false;
20318 : }
20319 :
20320 : // Set up local exports.
20321 : // TODO(neis): Create regular_exports array here instead of in factory method?
20322 3879 : for (int i = 0, n = module_info->RegularExportCount(); i < n; ++i) {
20323 1976 : int cell_index = module_info->RegularExportCellIndex(i);
20324 : Handle<FixedArray> export_names(module_info->RegularExportExportNames(i),
20325 1976 : isolate);
20326 1976 : CreateExport(module, cell_index, export_names);
20327 : }
20328 :
20329 : // Partially set up indirect exports.
20330 : // For each indirect export, we create the appropriate slot in the export
20331 : // table and store its ModuleInfoEntry there. When we later find the correct
20332 : // Cell in the module that actually provides the value, we replace the
20333 : // ModuleInfoEntry by that Cell (see ResolveExport).
20334 : Handle<FixedArray> special_exports(module_info->special_exports(), isolate);
20335 2290 : for (int i = 0, n = special_exports->length(); i < n; ++i) {
20336 : Handle<ModuleInfoEntry> entry(
20337 : ModuleInfoEntry::cast(special_exports->get(i)), isolate);
20338 : Handle<Object> export_name(entry->export_name(), isolate);
20339 387 : if (export_name->IsUndefined(isolate)) continue; // Star export.
20340 180 : CreateIndirectExport(module, Handle<String>::cast(export_name), entry);
20341 : }
20342 :
20343 : DCHECK_EQ(module->status(), kPrepared);
20344 : DCHECK(!module->instantiated());
20345 : return true;
20346 : }
20347 :
20348 2348 : bool Module::FinishInstantiate(Handle<Module> module,
20349 : v8::Local<v8::Context> context) {
20350 : DCHECK_EQ(module->status(), kPrepared);
20351 2348 : if (module->instantiated()) return true;
20352 :
20353 : // Instantiate SharedFunctionInfo and mark module as instantiated for
20354 : // the recursion.
20355 1903 : Isolate* isolate = module->GetIsolate();
20356 : Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(module->code()),
20357 : isolate);
20358 : Handle<JSFunction> function =
20359 : isolate->factory()->NewFunctionFromSharedFunctionInfo(
20360 : shared,
20361 1903 : handle(Utils::OpenHandle(*context)->native_context(), isolate));
20362 1903 : module->set_code(*function);
20363 : DCHECK(module->instantiated());
20364 :
20365 : // Recurse.
20366 : Handle<FixedArray> requested_modules(module->requested_modules(), isolate);
20367 3049 : for (int i = 0, length = requested_modules->length(); i < length; ++i) {
20368 : Handle<Module> requested_module(Module::cast(requested_modules->get(i)),
20369 : isolate);
20370 1146 : if (!FinishInstantiate(requested_module, context)) return false;
20371 : }
20372 :
20373 1903 : Zone zone(isolate->allocator(), ZONE_NAME);
20374 :
20375 : // Resolve imports.
20376 : Handle<ModuleInfo> module_info(shared->scope_info()->ModuleDescriptorInfo(),
20377 1903 : isolate);
20378 : Handle<FixedArray> regular_imports(module_info->regular_imports(), isolate);
20379 2786 : for (int i = 0, n = regular_imports->length(); i < n; ++i) {
20380 : Handle<ModuleInfoEntry> entry(
20381 : ModuleInfoEntry::cast(regular_imports->get(i)), isolate);
20382 : Handle<String> name(String::cast(entry->import_name()), isolate);
20383 : Handle<Script> script(
20384 : Script::cast(JSFunction::cast(module->code())->shared()->script()),
20385 : isolate);
20386 897 : MessageLocation loc(script, entry->beg_pos(), entry->end_pos());
20387 897 : ResolveSet resolve_set(&zone);
20388 : Handle<Cell> cell;
20389 897 : if (!ResolveImport(module, name, entry->module_request(), loc, true,
20390 : &resolve_set)
20391 1794 : .ToHandle(&cell)) {
20392 : return false;
20393 : }
20394 883 : module->regular_imports()->set(ImportIndex(entry->cell_index()), *cell);
20395 : }
20396 :
20397 : // Resolve indirect exports.
20398 : Handle<FixedArray> special_exports(module_info->special_exports(), isolate);
20399 2276 : for (int i = 0, n = special_exports->length(); i < n; ++i) {
20400 : Handle<ModuleInfoEntry> entry(
20401 : ModuleInfoEntry::cast(special_exports->get(i)), isolate);
20402 : Handle<Object> name(entry->export_name(), isolate);
20403 594 : if (name->IsUndefined(isolate)) continue; // Star export.
20404 : Handle<Script> script(
20405 : Script::cast(JSFunction::cast(module->code())->shared()->script()),
20406 : isolate);
20407 180 : MessageLocation loc(script, entry->beg_pos(), entry->end_pos());
20408 180 : ResolveSet resolve_set(&zone);
20409 180 : if (ResolveExport(module, Handle<String>::cast(name), loc, true,
20410 : &resolve_set)
20411 360 : .is_null()) {
20412 : return false;
20413 : }
20414 : }
20415 :
20416 1903 : return true;
20417 : }
20418 :
20419 2320 : MaybeHandle<Object> Module::Evaluate(Handle<Module> module) {
20420 : DCHECK(module->instantiated());
20421 :
20422 : // Each module can only be evaluated once.
20423 : Isolate* isolate = module->GetIsolate();
20424 2320 : if (module->evaluated()) return isolate->factory()->undefined_value();
20425 : Handle<JSFunction> function(JSFunction::cast(module->code()), isolate);
20426 1875 : module->set_evaluated();
20427 :
20428 : // Initialization.
20429 : DCHECK_EQ(MODULE_SCOPE, function->shared()->scope_info()->scope_type());
20430 : Handle<Object> receiver = isolate->factory()->undefined_value();
20431 : Handle<Object> argv[] = {module};
20432 : Handle<Object> generator;
20433 3750 : ASSIGN_RETURN_ON_EXCEPTION(
20434 : isolate, generator,
20435 : Execution::Call(isolate, function, receiver, arraysize(argv), argv),
20436 : Object);
20437 :
20438 : // Recursion.
20439 : Handle<FixedArray> requested_modules(module->requested_modules(), isolate);
20440 3007 : for (int i = 0, length = requested_modules->length(); i < length; ++i) {
20441 : Handle<Module> import(Module::cast(requested_modules->get(i)), isolate);
20442 2264 : RETURN_ON_EXCEPTION(isolate, Evaluate(import), Object);
20443 : }
20444 :
20445 : // Evaluation of module body.
20446 : Handle<JSFunction> resume(
20447 3750 : isolate->native_context()->generator_next_internal(), isolate);
20448 : Handle<Object> result;
20449 3750 : ASSIGN_RETURN_ON_EXCEPTION(
20450 : isolate, result, Execution::Call(isolate, resume, generator, 0, nullptr),
20451 : Object);
20452 : DCHECK(static_cast<JSIteratorResult*>(JSObject::cast(*result))
20453 : ->done()
20454 : ->BooleanValue());
20455 : return handle(
20456 : static_cast<JSIteratorResult*>(JSObject::cast(*result))->value(),
20457 : isolate);
20458 : }
20459 :
20460 : namespace {
20461 :
20462 403 : void FetchStarExports(Handle<Module> module, Zone* zone,
20463 : UnorderedModuleSet* visited) {
20464 : DCHECK(module->instantiated());
20465 :
20466 403 : bool cycle = !visited->insert(module).second;
20467 418 : if (cycle) return;
20468 :
20469 : Isolate* isolate = module->GetIsolate();
20470 : Handle<ObjectHashTable> exports(module->exports(), isolate);
20471 388 : UnorderedStringMap more_exports(zone);
20472 :
20473 : // TODO(neis): Only allocate more_exports if there are star exports.
20474 : // Maybe split special_exports into indirect_exports and star_exports.
20475 :
20476 : Handle<FixedArray> special_exports(module->info()->special_exports(),
20477 388 : isolate);
20478 536 : for (int i = 0, n = special_exports->length(); i < n; ++i) {
20479 : Handle<ModuleInfoEntry> entry(
20480 : ModuleInfoEntry::cast(special_exports->get(i)), isolate);
20481 148 : if (!entry->export_name()->IsUndefined(isolate)) {
20482 : continue; // Indirect export.
20483 : }
20484 :
20485 : Handle<Module> requested_module(
20486 : Module::cast(module->requested_modules()->get(entry->module_request())),
20487 : isolate);
20488 :
20489 : // Recurse.
20490 103 : FetchStarExports(requested_module, zone, visited);
20491 :
20492 : // Collect all of [requested_module]'s exports that must be added to
20493 : // [module]'s exports (i.e. to [exports]). We record these in
20494 : // [more_exports]. Ambiguities (conflicting exports) are marked by mapping
20495 : // the name to undefined instead of a Cell.
20496 : Handle<ObjectHashTable> requested_exports(requested_module->exports(),
20497 : isolate);
20498 815 : for (int i = 0, n = requested_exports->Capacity(); i < n; ++i) {
20499 : Handle<Object> key(requested_exports->KeyAt(i), isolate);
20500 712 : if (!requested_exports->IsKey(isolate, *key)) continue;
20501 : Handle<String> name = Handle<String>::cast(key);
20502 :
20503 298 : if (name->Equals(isolate->heap()->default_string())) continue;
20504 506 : if (!exports->Lookup(name)->IsTheHole(isolate)) continue;
20505 :
20506 : Handle<Cell> cell(Cell::cast(requested_exports->ValueAt(i)), isolate);
20507 446 : auto insert_result = more_exports.insert(std::make_pair(name, cell));
20508 223 : if (!insert_result.second) {
20509 : auto it = insert_result.first;
20510 45 : if (*it->second == *cell || it->second->IsUndefined(isolate)) {
20511 : // We already recorded this mapping before, or the name is already
20512 : // known to be ambiguous. In either case, there's nothing to do.
20513 : } else {
20514 : DCHECK(it->second->IsCell());
20515 : // Different star exports provide different cells for this name, hence
20516 : // mark the name as ambiguous.
20517 15 : it->second = isolate->factory()->undefined_value();
20518 : }
20519 : }
20520 : }
20521 : }
20522 :
20523 : // Copy [more_exports] into [exports].
20524 969 : for (const auto& elem : more_exports) {
20525 193 : if (elem.second->IsUndefined(isolate)) continue; // Ambiguous export.
20526 : DCHECK(!elem.first->Equals(isolate->heap()->default_string()));
20527 : DCHECK(elem.second->IsCell());
20528 178 : exports = ObjectHashTable::Put(exports, elem.first, elem.second);
20529 : }
20530 388 : module->set_exports(*exports);
20531 : }
20532 :
20533 : } // anonymous namespace
20534 :
20535 161 : Handle<JSModuleNamespace> Module::GetModuleNamespace(Handle<Module> module,
20536 : int module_request) {
20537 : Isolate* isolate = module->GetIsolate();
20538 : Handle<Module> requested_module(
20539 : Module::cast(module->requested_modules()->get(module_request)), isolate);
20540 161 : return Module::GetModuleNamespace(requested_module);
20541 : }
20542 :
20543 413 : Handle<JSModuleNamespace> Module::GetModuleNamespace(Handle<Module> module) {
20544 300 : Isolate* isolate = module->GetIsolate();
20545 :
20546 : Handle<HeapObject> object(module->module_namespace(), isolate);
20547 413 : if (!object->IsUndefined(isolate)) {
20548 : // Namespace object already exists.
20549 : return Handle<JSModuleNamespace>::cast(object);
20550 : }
20551 :
20552 : // Create the namespace object (initially empty).
20553 300 : Handle<JSModuleNamespace> ns = isolate->factory()->NewJSModuleNamespace();
20554 300 : ns->set_module(*module);
20555 300 : module->set_module_namespace(*ns);
20556 :
20557 : // Collect the export names.
20558 300 : Zone zone(isolate->allocator(), ZONE_NAME);
20559 300 : UnorderedModuleSet visited(&zone);
20560 300 : FetchStarExports(module, &zone, &visited);
20561 : Handle<ObjectHashTable> exports(module->exports(), isolate);
20562 : ZoneVector<Handle<String>> names(&zone);
20563 300 : names.reserve(exports->NumberOfElements());
20564 1920 : for (int i = 0, n = exports->Capacity(); i < n; ++i) {
20565 : Handle<Object> key(exports->KeyAt(i), isolate);
20566 1620 : if (!exports->IsKey(isolate, *key)) continue;
20567 : DCHECK(exports->ValueAt(i)->IsCell());
20568 611 : names.push_back(Handle<String>::cast(key));
20569 : }
20570 : DCHECK_EQ(static_cast<int>(names.size()), exports->NumberOfElements());
20571 :
20572 : // Sort them alphabetically.
20573 : struct {
20574 : bool operator()(Handle<String> a, Handle<String> b) {
20575 712 : return String::Compare(a, b) == ComparisonResult::kLessThan;
20576 : }
20577 : } StringLess;
20578 300 : std::sort(names.begin(), names.end(), StringLess);
20579 :
20580 : // Create the corresponding properties in the namespace object.
20581 : PropertyAttributes attr = DONT_DELETE;
20582 1211 : for (const auto& name : names) {
20583 : JSObject::SetAccessor(
20584 : ns, Accessors::ModuleNamespaceEntryInfo(isolate, name, attr))
20585 1833 : .Check();
20586 : }
20587 600 : JSObject::PreventExtensions(ns, THROW_ON_ERROR).ToChecked();
20588 :
20589 600 : return ns;
20590 : }
20591 :
20592 9377435 : MaybeHandle<Name> FunctionTemplateInfo::TryGetCachedPropertyName(
20593 : Isolate* isolate, Handle<Object> getter) {
20594 9377435 : if (getter->IsFunctionTemplateInfo()) {
20595 : Handle<FunctionTemplateInfo> fti =
20596 : Handle<FunctionTemplateInfo>::cast(getter);
20597 : // Check if the accessor uses a cached property.
20598 535 : if (!fti->cached_property_name()->IsTheHole(isolate)) {
20599 : return handle(Name::cast(fti->cached_property_name()));
20600 : }
20601 : }
20602 : return MaybeHandle<Name>();
20603 : }
20604 :
20605 : // static
20606 1408 : ElementsKind JSArrayIterator::ElementsKindForInstanceType(InstanceType type) {
20607 : DCHECK_GE(type, FIRST_ARRAY_ITERATOR_TYPE);
20608 : DCHECK_LE(type, LAST_ARRAY_ITERATOR_TYPE);
20609 :
20610 1408 : if (type <= LAST_ARRAY_KEY_ITERATOR_TYPE) {
20611 : // Should be ignored for key iterators.
20612 : return FAST_ELEMENTS;
20613 : } else {
20614 : ElementsKind kind;
20615 1395 : if (type < FIRST_ARRAY_VALUE_ITERATOR_TYPE) {
20616 : // Convert `type` to a value iterator from an entries iterator
20617 14 : type = static_cast<InstanceType>(type +
20618 : (FIRST_ARRAY_VALUE_ITERATOR_TYPE -
20619 14 : FIRST_ARRAY_KEY_VALUE_ITERATOR_TYPE));
20620 : DCHECK_GE(type, FIRST_ARRAY_VALUE_ITERATOR_TYPE);
20621 : DCHECK_LE(type, LAST_ARRAY_ITERATOR_TYPE);
20622 : }
20623 :
20624 1395 : if (type <= JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE) {
20625 : kind =
20626 14 : static_cast<ElementsKind>(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND +
20627 14 : (type - FIRST_ARRAY_VALUE_ITERATOR_TYPE));
20628 : DCHECK_LE(kind, LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
20629 1381 : } else if (type < JS_GENERIC_ARRAY_VALUE_ITERATOR_TYPE) {
20630 : kind = static_cast<ElementsKind>(
20631 1381 : FIRST_FAST_ELEMENTS_KIND +
20632 1381 : (type - JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE));
20633 : DCHECK_LE(kind, LAST_FAST_ELEMENTS_KIND);
20634 : } else {
20635 : // For any slow element cases, the actual elements kind is not known.
20636 : // Simply
20637 : // return a slow elements kind in this case. Users of this function must
20638 : // not
20639 : // depend on this.
20640 : return DICTIONARY_ELEMENTS;
20641 : }
20642 : DCHECK_LE(kind, LAST_ELEMENTS_KIND);
20643 1395 : return kind;
20644 : }
20645 : }
20646 :
20647 : } // namespace internal
20648 : } // namespace v8
|