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 10650139 : Handle<FieldType> Object::OptimalType(Isolate* isolate,
97 : Representation representation) {
98 10650139 : if (representation.IsNone()) return FieldType::None(isolate);
99 10210057 : if (FLAG_track_field_types) {
100 15195444 : if (representation.IsHeapObject() && IsHeapObject()) {
101 : // We can track only JavaScript objects with stable maps.
102 : Handle<Map> map(HeapObject::cast(this)->map(), isolate);
103 8983409 : if (map->is_stable() && map->IsJSReceiverMap()) {
104 1604105 : return FieldType::Class(map, isolate);
105 : }
106 : }
107 : }
108 8605953 : return FieldType::Any(isolate);
109 : }
110 :
111 9188 : MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
112 : Handle<Object> object,
113 : Handle<Context> native_context,
114 : const char* method_name) {
115 9188 : if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
116 : Handle<JSFunction> constructor;
117 9188 : 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 8565 : if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
123 1696 : if (method_name != nullptr) {
124 2154 : THROW_NEW_ERROR(
125 : isolate,
126 : NewTypeError(
127 : MessageTemplate::kCalledOnNullOrUndefined,
128 : isolate->factory()->NewStringFromAsciiChecked(method_name)),
129 : JSReceiver);
130 : }
131 1956 : THROW_NEW_ERROR(isolate,
132 : NewTypeError(MessageTemplate::kUndefinedOrNullToObject),
133 : JSReceiver);
134 : }
135 : constructor = handle(
136 : JSFunction::cast(native_context->get(constructor_function_index)),
137 6869 : isolate);
138 : }
139 7492 : Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
140 7492 : Handle<JSValue>::cast(result)->set_value(*object);
141 : return result;
142 : }
143 :
144 : // ES6 section 9.2.1.2, OrdinaryCallBindThis for sloppy callee.
145 : // static
146 51871 : MaybeHandle<JSReceiver> Object::ConvertReceiver(Isolate* isolate,
147 : Handle<Object> object) {
148 51871 : if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
149 1124 : if (*object == isolate->heap()->null_value() ||
150 : object->IsUndefined(isolate)) {
151 313 : return isolate->global_proxy();
152 : }
153 249 : return Object::ToObject(isolate, object);
154 : }
155 :
156 : // static
157 3454975 : MaybeHandle<Object> Object::ConvertToNumber(Isolate* isolate,
158 : Handle<Object> input) {
159 : while (true) {
160 3461161 : if (input->IsNumber()) {
161 : return input;
162 : }
163 3437107 : if (input->IsString()) {
164 91719 : return String::ToNumber(Handle<String>::cast(input));
165 : }
166 3345388 : if (input->IsOddball()) {
167 3332801 : return Oddball::ToNumber(Handle<Oddball>::cast(input));
168 : }
169 12587 : if (input->IsSymbol()) {
170 10966 : THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber),
171 : Object);
172 : }
173 14208 : ASSIGN_RETURN_ON_EXCEPTION(
174 : isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
175 : ToPrimitiveHint::kNumber),
176 : Object);
177 : }
178 : }
179 :
180 : // static
181 29747 : MaybeHandle<Object> Object::ConvertToInteger(Isolate* isolate,
182 : Handle<Object> input) {
183 59494 : ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ConvertToNumber(isolate, input),
184 : Object);
185 29393 : if (input->IsSmi()) return input;
186 27129 : return isolate->factory()->NewNumber(DoubleToInteger(input->Number()));
187 : }
188 :
189 : // static
190 1232 : MaybeHandle<Object> Object::ConvertToInt32(Isolate* isolate,
191 : Handle<Object> input) {
192 2464 : ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ConvertToNumber(isolate, input),
193 : Object);
194 1143 : if (input->IsSmi()) return input;
195 401 : return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number()));
196 : }
197 :
198 : // static
199 533104 : MaybeHandle<Object> Object::ConvertToUint32(Isolate* isolate,
200 : Handle<Object> input) {
201 1066208 : ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ConvertToNumber(isolate, input),
202 : Object);
203 533075 : if (input->IsSmi()) return handle(Smi::cast(*input)->ToUint32Smi(), isolate);
204 363 : return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number()));
205 : }
206 :
207 : // static
208 4574502 : MaybeHandle<Name> Object::ConvertToName(Isolate* isolate,
209 : Handle<Object> input) {
210 9149004 : ASSIGN_RETURN_ON_EXCEPTION(
211 : isolate, input, Object::ToPrimitive(input, ToPrimitiveHint::kString),
212 : Name);
213 4574247 : if (input->IsName()) return Handle<Name>::cast(input);
214 136620 : return ToString(isolate, input);
215 : }
216 :
217 : // ES6 7.1.14
218 : // static
219 744 : MaybeHandle<Object> Object::ConvertToPropertyKey(Isolate* isolate,
220 : Handle<Object> value) {
221 : // 1. Let key be ToPrimitive(argument, hint String).
222 : MaybeHandle<Object> maybe_key =
223 744 : Object::ToPrimitive(value, ToPrimitiveHint::kString);
224 : // 2. ReturnIfAbrupt(key).
225 : Handle<Object> key;
226 744 : if (!maybe_key.ToHandle(&key)) return key;
227 : // 3. If Type(key) is Symbol, then return key.
228 744 : if (key->IsSymbol()) return key;
229 : // 4. Return ToString(key).
230 : // Extending spec'ed behavior, we'd be happy to return an element index.
231 744 : if (key->IsSmi()) return key;
232 744 : if (key->IsHeapNumber()) {
233 : uint32_t uint_value;
234 43 : if (value->ToArrayLength(&uint_value) &&
235 14 : uint_value <= static_cast<uint32_t>(Smi::kMaxValue)) {
236 0 : return handle(Smi::FromInt(static_cast<int>(uint_value)), isolate);
237 : }
238 : }
239 1488 : return Object::ToString(isolate, key);
240 : }
241 :
242 : // static
243 8540016 : MaybeHandle<String> Object::ConvertToString(Isolate* isolate,
244 : Handle<Object> input) {
245 : while (true) {
246 8821482 : if (input->IsOddball()) {
247 : return handle(Handle<Oddball>::cast(input)->to_string(), isolate);
248 : }
249 6259494 : if (input->IsNumber()) {
250 424483 : return isolate->factory()->NumberToString(input);
251 : }
252 5835011 : if (input->IsSymbol()) {
253 6428 : THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToString),
254 : String);
255 : }
256 11663594 : ASSIGN_RETURN_ON_EXCEPTION(
257 : isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
258 : ToPrimitiveHint::kString),
259 : String);
260 : // The previous isString() check happened in Object::ToString and thus we
261 : // put it at the end of the loop in this helper.
262 5814673 : if (input->IsString()) {
263 : return Handle<String>::cast(input);
264 : }
265 : }
266 : }
267 :
268 : namespace {
269 :
270 42081 : bool IsErrorObject(Isolate* isolate, Handle<Object> object) {
271 42081 : if (!object->IsJSReceiver()) return false;
272 : Handle<Symbol> symbol = isolate->factory()->stack_trace_symbol();
273 42081 : return JSReceiver::HasOwnProperty(Handle<JSReceiver>::cast(object), symbol)
274 84162 : .FromMaybe(false);
275 : }
276 :
277 37544 : Handle<String> AsStringOrEmpty(Isolate* isolate, Handle<Object> object) {
278 : return object->IsString() ? Handle<String>::cast(object)
279 75088 : : isolate->factory()->empty_string();
280 : }
281 :
282 5094 : Handle<String> NoSideEffectsErrorToString(Isolate* isolate,
283 : Handle<Object> input) {
284 5094 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input);
285 :
286 : Handle<Name> name_key = isolate->factory()->name_string();
287 5094 : Handle<Object> name = JSReceiver::GetDataProperty(receiver, name_key);
288 5094 : Handle<String> name_str = AsStringOrEmpty(isolate, name);
289 :
290 : Handle<Name> msg_key = isolate->factory()->message_string();
291 5094 : Handle<Object> msg = JSReceiver::GetDataProperty(receiver, msg_key);
292 5094 : Handle<String> msg_str = AsStringOrEmpty(isolate, msg);
293 :
294 5094 : if (name_str->length() == 0) return msg_str;
295 5064 : if (msg_str->length() == 0) return name_str;
296 :
297 4923 : IncrementalStringBuilder builder(isolate);
298 4923 : builder.AppendString(name_str);
299 : builder.AppendCString(": ");
300 4923 : builder.AppendString(msg_str);
301 :
302 9846 : return builder.Finish().ToHandleChecked();
303 : }
304 :
305 : } // namespace
306 :
307 : // static
308 3697969 : Handle<String> Object::NoSideEffectsToString(Isolate* isolate,
309 : Handle<Object> input) {
310 3697969 : DisallowJavascriptExecution no_js(isolate);
311 :
312 8920790 : if (input->IsString() || input->IsNumber() || input->IsOddball()) {
313 7307096 : return Object::ToString(isolate, input).ToHandleChecked();
314 44421 : } else if (input->IsFunction()) {
315 : // -- F u n c t i o n
316 : Handle<String> fun_str;
317 858 : if (input->IsJSBoundFunction()) {
318 0 : fun_str = JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(input));
319 : } else {
320 : DCHECK(input->IsJSFunction());
321 858 : fun_str = JSFunction::ToString(Handle<JSFunction>::cast(input));
322 : }
323 :
324 858 : if (fun_str->length() > 128) {
325 15 : IncrementalStringBuilder builder(isolate);
326 15 : builder.AppendString(isolate->factory()->NewSubString(fun_str, 0, 111));
327 : builder.AppendCString("...<omitted>...");
328 : builder.AppendString(isolate->factory()->NewSubString(
329 15 : fun_str, fun_str->length() - 2, fun_str->length()));
330 :
331 30 : return builder.Finish().ToHandleChecked();
332 : }
333 843 : return fun_str;
334 43563 : } else if (input->IsSymbol()) {
335 : // -- S y m b o l
336 : Handle<Symbol> symbol = Handle<Symbol>::cast(input);
337 :
338 1482 : IncrementalStringBuilder builder(isolate);
339 : builder.AppendCString("Symbol(");
340 1482 : if (symbol->name()->IsString()) {
341 838 : builder.AppendString(handle(String::cast(symbol->name()), isolate));
342 : }
343 : builder.AppendCharacter(')');
344 :
345 2964 : return builder.Finish().ToHandleChecked();
346 42081 : } else if (input->IsJSReceiver()) {
347 : // -- J S R e c e i v e r
348 42081 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input);
349 : Handle<Object> to_string = JSReceiver::GetDataProperty(
350 42081 : receiver, isolate->factory()->toString_string());
351 :
352 126243 : if (IsErrorObject(isolate, input) ||
353 116085 : *to_string == *isolate->error_to_string()) {
354 : // When internally formatting error objects, use a side-effects-free
355 : // version of Error.prototype.toString independent of the actually
356 : // installed toString method.
357 36833 : return NoSideEffectsErrorToString(isolate, input);
358 73974 : } else if (*to_string == *isolate->object_to_string()) {
359 : Handle<Object> ctor = JSReceiver::GetDataProperty(
360 27790 : receiver, isolate->factory()->constructor_string());
361 27790 : if (ctor->IsFunction()) {
362 : Handle<String> ctor_name;
363 27356 : if (ctor->IsJSBoundFunction()) {
364 : ctor_name = JSBoundFunction::GetName(
365 : isolate, Handle<JSBoundFunction>::cast(ctor))
366 0 : .ToHandleChecked();
367 27356 : } else if (ctor->IsJSFunction()) {
368 : Handle<Object> ctor_name_obj =
369 27356 : JSFunction::GetName(isolate, Handle<JSFunction>::cast(ctor));
370 27356 : ctor_name = AsStringOrEmpty(isolate, ctor_name_obj);
371 : }
372 :
373 27356 : if (ctor_name->length() != 0) {
374 26645 : IncrementalStringBuilder builder(isolate);
375 : builder.AppendCString("#<");
376 26645 : builder.AppendString(ctor_name);
377 : builder.AppendCString(">");
378 :
379 53290 : return builder.Finish().ToHandleChecked();
380 : }
381 : }
382 : }
383 : }
384 :
385 : // At this point, input is either none of the above or a JSReceiver.
386 :
387 : Handle<JSReceiver> receiver;
388 10342 : if (input->IsJSReceiver()) {
389 : receiver = Handle<JSReceiver>::cast(input);
390 : } else {
391 : // This is the only case where Object::ToObject throws.
392 : DCHECK(!input->IsSmi());
393 : int constructor_function_index =
394 : Handle<HeapObject>::cast(input)->map()->GetConstructorFunctionIndex();
395 0 : if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
396 0 : return isolate->factory()->NewStringFromAsciiChecked("[object Unknown]");
397 : }
398 :
399 : receiver = Object::ToObject(isolate, input, isolate->native_context())
400 0 : .ToHandleChecked();
401 : }
402 :
403 10342 : Handle<String> builtin_tag = handle(receiver->class_name(), isolate);
404 : Handle<Object> tag_obj = JSReceiver::GetDataProperty(
405 10342 : receiver, isolate->factory()->to_string_tag_symbol());
406 : Handle<String> tag =
407 10342 : tag_obj->IsString() ? Handle<String>::cast(tag_obj) : builtin_tag;
408 :
409 10342 : IncrementalStringBuilder builder(isolate);
410 : builder.AppendCString("[object ");
411 10342 : builder.AppendString(tag);
412 : builder.AppendCString("]");
413 :
414 20684 : return builder.Finish().ToHandleChecked();
415 : }
416 :
417 : // static
418 1058 : MaybeHandle<Object> Object::ConvertToLength(Isolate* isolate,
419 : Handle<Object> input) {
420 2116 : ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
421 918 : if (input->IsSmi()) {
422 672 : int value = std::max(Smi::cast(*input)->value(), 0);
423 : return handle(Smi::FromInt(value), isolate);
424 : }
425 694 : double len = DoubleToInteger(input->Number());
426 694 : if (len <= 0.0) {
427 : return handle(Smi::kZero, isolate);
428 212 : } else if (len >= kMaxSafeInteger) {
429 : len = kMaxSafeInteger;
430 : }
431 212 : return isolate->factory()->NewNumber(len);
432 : }
433 :
434 : // static
435 5303 : MaybeHandle<Object> Object::ConvertToIndex(
436 : Isolate* isolate, Handle<Object> input,
437 : MessageTemplate::Template error_index) {
438 5303 : if (input->IsUndefined(isolate)) return handle(Smi::kZero, isolate);
439 4932 : ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
440 3224 : if (input->IsSmi() && Smi::cast(*input)->value() >= 0) return input;
441 2408 : double len = DoubleToInteger(input->Number()) + 0.0;
442 2408 : auto js_len = isolate->factory()->NewNumber(len);
443 2408 : if (len < 0.0 || len > kMaxSafeInteger) {
444 1400 : THROW_NEW_ERROR(isolate, NewRangeError(error_index, js_len), Object);
445 : }
446 : return js_len;
447 : }
448 :
449 7197291 : bool Object::BooleanValue() {
450 7746941 : if (IsSmi()) return Smi::cast(this)->value() != 0;
451 : DCHECK(IsHeapObject());
452 : Isolate* isolate = HeapObject::cast(this)->GetIsolate();
453 9295178 : if (IsBoolean()) return IsTrue(isolate);
454 4000108 : if (IsNullOrUndefined(isolate)) return false;
455 3865696 : if (IsUndetectable()) return false; // Undetectable object is false.
456 4626247 : if (IsString()) return String::cast(this)->length() != 0;
457 3169526 : if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue();
458 : return true;
459 : }
460 :
461 :
462 : namespace {
463 :
464 : // TODO(bmeurer): Maybe we should introduce a marker interface Number,
465 : // where we put all these methods at some point?
466 : ComparisonResult NumberCompare(double x, double y) {
467 222871 : if (std::isnan(x) || std::isnan(y)) {
468 : return ComparisonResult::kUndefined;
469 89080 : } else if (x < y) {
470 : return ComparisonResult::kLessThan;
471 51564 : } else if (x > y) {
472 : return ComparisonResult::kGreaterThan;
473 : } else {
474 : return ComparisonResult::kEqual;
475 : }
476 : }
477 :
478 :
479 : bool NumberEquals(double x, double y) {
480 : // Must check explicitly for NaN's on Windows, but -0 works fine.
481 6795 : if (std::isnan(x)) return false;
482 6658 : if (std::isnan(y)) return false;
483 6557 : return x == y;
484 : }
485 :
486 :
487 6795 : bool NumberEquals(const Object* x, const Object* y) {
488 6795 : return NumberEquals(x->Number(), y->Number());
489 : }
490 :
491 :
492 : bool NumberEquals(Handle<Object> x, Handle<Object> y) {
493 5146 : return NumberEquals(*x, *y);
494 : }
495 :
496 : } // namespace
497 :
498 :
499 : // static
500 224205 : Maybe<ComparisonResult> Object::Compare(Handle<Object> x, Handle<Object> y) {
501 : // ES6 section 7.2.11 Abstract Relational Comparison step 3 and 4.
502 896604 : if (!Object::ToPrimitive(x, ToPrimitiveHint::kNumber).ToHandle(&x) ||
503 448194 : !Object::ToPrimitive(y, ToPrimitiveHint::kNumber).ToHandle(&y)) {
504 : return Nothing<ComparisonResult>();
505 : }
506 289087 : if (x->IsString() && y->IsString()) {
507 : // ES6 section 7.2.11 Abstract Relational Comparison step 5.
508 : return Just(
509 938 : String::Compare(Handle<String>::cast(x), Handle<String>::cast(y)));
510 : }
511 : // ES6 section 7.2.11 Abstract Relational Comparison step 6.
512 668949 : if (!Object::ToNumber(x).ToHandle(&x) || !Object::ToNumber(y).ToHandle(&y)) {
513 : return Nothing<ComparisonResult>();
514 : }
515 : return Just(NumberCompare(x->Number(), y->Number()));
516 : }
517 :
518 :
519 : // static
520 193238 : Maybe<bool> Object::Equals(Handle<Object> x, Handle<Object> y) {
521 : // This is the generic version of Abstract Equality Comparison; a version in
522 : // JavaScript land is available in the EqualStub and NotEqualStub. Whenever
523 : // you change something functionality wise in here, remember to update the
524 : // TurboFan code stubs as well.
525 : while (true) {
526 193245 : if (x->IsNumber()) {
527 5070 : if (y->IsNumber()) {
528 : return Just(NumberEquals(x, y));
529 112 : } else if (y->IsBoolean()) {
530 0 : return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
531 112 : } else if (y->IsString()) {
532 112 : return Just(NumberEquals(x, String::ToNumber(Handle<String>::cast(y))));
533 0 : } else if (y->IsJSReceiver()) {
534 0 : if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
535 0 : .ToHandle(&y)) {
536 : return Nothing<bool>();
537 : }
538 : } else {
539 : return Just(false);
540 : }
541 188175 : } else if (x->IsString()) {
542 168455 : if (y->IsString()) {
543 : return Just(
544 168379 : String::Equals(Handle<String>::cast(x), Handle<String>::cast(y)));
545 76 : } else if (y->IsNumber()) {
546 76 : x = String::ToNumber(Handle<String>::cast(x));
547 : return Just(NumberEquals(x, y));
548 0 : } else if (y->IsBoolean()) {
549 0 : x = String::ToNumber(Handle<String>::cast(x));
550 0 : return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
551 0 : } else if (y->IsJSReceiver()) {
552 0 : if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
553 0 : .ToHandle(&y)) {
554 : return Nothing<bool>();
555 : }
556 : } else {
557 : return Just(false);
558 : }
559 19720 : } else if (x->IsBoolean()) {
560 700 : if (y->IsOddball()) {
561 : return Just(x.is_identical_to(y));
562 0 : } else if (y->IsNumber()) {
563 0 : return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
564 0 : } else if (y->IsString()) {
565 0 : y = String::ToNumber(Handle<String>::cast(y));
566 0 : return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
567 0 : } else if (y->IsJSReceiver()) {
568 0 : if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
569 0 : .ToHandle(&y)) {
570 : return Nothing<bool>();
571 : }
572 0 : x = Oddball::ToNumber(Handle<Oddball>::cast(x));
573 : } else {
574 : return Just(false);
575 : }
576 19020 : } else if (x->IsSymbol()) {
577 63 : if (y->IsSymbol()) {
578 : return Just(x.is_identical_to(y));
579 0 : } else if (y->IsJSReceiver()) {
580 0 : if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
581 0 : .ToHandle(&y)) {
582 : return Nothing<bool>();
583 : }
584 : } else {
585 : return Just(false);
586 : }
587 18957 : } else if (x->IsJSReceiver()) {
588 18835 : if (y->IsJSReceiver()) {
589 : return Just(x.is_identical_to(y));
590 7 : } else if (y->IsUndetectable()) {
591 : return Just(x->IsUndetectable());
592 7 : } else if (y->IsBoolean()) {
593 0 : y = Oddball::ToNumber(Handle<Oddball>::cast(y));
594 7 : } else if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(x))
595 14 : .ToHandle(&x)) {
596 : return Nothing<bool>();
597 : }
598 : } else {
599 244 : return Just(x->IsUndetectable() && y->IsUndetectable());
600 : }
601 : }
602 : }
603 :
604 :
605 16129 : bool Object::StrictEquals(Object* that) {
606 16129 : if (this->IsNumber()) {
607 2466 : if (!that->IsNumber()) return false;
608 1649 : return NumberEquals(this, that);
609 13663 : } else if (this->IsString()) {
610 12013 : if (!that->IsString()) return false;
611 11922 : return String::cast(this)->Equals(String::cast(that));
612 : }
613 1650 : return this == that;
614 : }
615 :
616 :
617 : // static
618 22073 : Handle<String> Object::TypeOf(Isolate* isolate, Handle<Object> object) {
619 22073 : if (object->IsNumber()) return isolate->factory()->number_string();
620 21229 : if (object->IsOddball()) return handle(Oddball::cast(*object)->type_of());
621 19076 : if (object->IsUndetectable()) {
622 : return isolate->factory()->undefined_string();
623 : }
624 19076 : if (object->IsString()) return isolate->factory()->string_string();
625 17832 : if (object->IsSymbol()) return isolate->factory()->symbol_string();
626 17759 : if (object->IsString()) return isolate->factory()->string_string();
627 17759 : if (object->IsCallable()) return isolate->factory()->function_string();
628 : return isolate->factory()->object_string();
629 : }
630 :
631 :
632 : // static
633 43229 : MaybeHandle<Object> Object::Multiply(Isolate* isolate, Handle<Object> lhs,
634 : Handle<Object> rhs) {
635 83480 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
636 6054 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
637 5410 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
638 : }
639 42907 : return isolate->factory()->NewNumber(lhs->Number() * rhs->Number());
640 : }
641 :
642 :
643 : // static
644 11601 : MaybeHandle<Object> Object::Divide(Isolate* isolate, Handle<Object> lhs,
645 : Handle<Object> rhs) {
646 23143 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
647 172 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
648 160 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
649 : }
650 11595 : return isolate->factory()->NewNumber(lhs->Number() / rhs->Number());
651 : }
652 :
653 :
654 : // static
655 5188 : MaybeHandle<Object> Object::Modulus(Isolate* isolate, Handle<Object> lhs,
656 : Handle<Object> rhs) {
657 10310 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
658 162 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
659 150 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
660 : }
661 5182 : return isolate->factory()->NewNumber(modulo(lhs->Number(), rhs->Number()));
662 : }
663 :
664 :
665 : // static
666 226109 : MaybeHandle<Object> Object::Add(Isolate* isolate, Handle<Object> lhs,
667 : Handle<Object> rhs) {
668 403720 : if (lhs->IsNumber() && rhs->IsNumber()) {
669 172810 : return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
670 96789 : } else if (lhs->IsString() && rhs->IsString()) {
671 : return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
672 73824 : Handle<String>::cast(rhs));
673 : }
674 32774 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToPrimitive(lhs), Object);
675 27548 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToPrimitive(rhs), Object);
676 19865 : if (lhs->IsString() || rhs->IsString()) {
677 23562 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToString(isolate, rhs),
678 : Object);
679 23550 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToString(isolate, lhs),
680 : Object);
681 : return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
682 22590 : Handle<String>::cast(rhs));
683 : }
684 3974 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
685 3950 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
686 1495 : return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
687 : }
688 :
689 :
690 : // static
691 19324 : MaybeHandle<Object> Object::Subtract(Isolate* isolate, Handle<Object> lhs,
692 : Handle<Object> rhs) {
693 38520 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
694 394 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
695 382 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
696 : }
697 19318 : return isolate->factory()->NewNumber(lhs->Number() - rhs->Number());
698 : }
699 :
700 :
701 : // static
702 9220 : MaybeHandle<Object> Object::ShiftLeft(Isolate* isolate, Handle<Object> lhs,
703 : Handle<Object> rhs) {
704 18383 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
705 170 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
706 158 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
707 : }
708 9214 : return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs)
709 9214 : << (NumberToUint32(*rhs) & 0x1F));
710 : }
711 :
712 :
713 : // static
714 20886 : MaybeHandle<Object> Object::ShiftRight(Isolate* isolate, Handle<Object> lhs,
715 : Handle<Object> rhs) {
716 41700 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
717 238 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
718 226 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
719 : }
720 20880 : return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) >>
721 20880 : (NumberToUint32(*rhs) & 0x1F));
722 : }
723 :
724 :
725 : // static
726 10307 : MaybeHandle<Object> Object::ShiftRightLogical(Isolate* isolate,
727 : Handle<Object> lhs,
728 : Handle<Object> rhs) {
729 20486 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
730 326 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
731 314 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
732 : }
733 10301 : return isolate->factory()->NewNumberFromUint(NumberToUint32(*lhs) >>
734 10301 : (NumberToUint32(*rhs) & 0x1F));
735 : }
736 :
737 :
738 : // static
739 19596 : MaybeHandle<Object> Object::BitwiseAnd(Isolate* isolate, Handle<Object> lhs,
740 : Handle<Object> rhs) {
741 38203 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
742 3682 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
743 3670 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
744 : }
745 19590 : return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) &
746 19590 : NumberToInt32(*rhs));
747 : }
748 :
749 :
750 : // static
751 64128 : MaybeHandle<Object> Object::BitwiseOr(Isolate* isolate, Handle<Object> lhs,
752 : Handle<Object> rhs) {
753 126788 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
754 4614 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
755 4550 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
756 : }
757 64096 : return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) |
758 64096 : NumberToInt32(*rhs));
759 : }
760 :
761 :
762 : // static
763 8276 : MaybeHandle<Object> Object::BitwiseXor(Isolate* isolate, Handle<Object> lhs,
764 : Handle<Object> rhs) {
765 16396 : if (!lhs->IsNumber() || !rhs->IsNumber()) {
766 398 : ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
767 386 : ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
768 : }
769 8270 : return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) ^
770 8270 : NumberToInt32(*rhs));
771 : }
772 :
773 : // static
774 178699 : MaybeHandle<Object> Object::OrdinaryHasInstance(Isolate* isolate,
775 : Handle<Object> callable,
776 : Handle<Object> object) {
777 : // The {callable} must have a [[Call]] internal method.
778 178699 : if (!callable->IsCallable()) return isolate->factory()->false_value();
779 :
780 : // Check if {callable} is a bound function, and if so retrieve its
781 : // [[BoundTargetFunction]] and use that instead of {callable}.
782 178639 : if (callable->IsJSBoundFunction()) {
783 : Handle<Object> bound_callable(
784 : Handle<JSBoundFunction>::cast(callable)->bound_target_function(),
785 : isolate);
786 409 : return Object::InstanceOf(isolate, object, bound_callable);
787 : }
788 :
789 : // If {object} is not a receiver, return false.
790 178230 : if (!object->IsJSReceiver()) return isolate->factory()->false_value();
791 :
792 : // Get the "prototype" of {callable}; raise an error if it's not a receiver.
793 : Handle<Object> prototype;
794 333454 : ASSIGN_RETURN_ON_EXCEPTION(
795 : isolate, prototype,
796 : Object::GetProperty(callable, isolate->factory()->prototype_string()),
797 : Object);
798 166727 : if (!prototype->IsJSReceiver()) {
799 331042 : THROW_NEW_ERROR(
800 : isolate,
801 : NewTypeError(MessageTemplate::kInstanceofNonobjectProto, prototype),
802 : Object);
803 : }
804 :
805 : // Return whether or not {prototype} is in the prototype chain of {object}.
806 : Maybe<bool> result = JSReceiver::HasInPrototypeChain(
807 1206 : isolate, Handle<JSReceiver>::cast(object), prototype);
808 1206 : if (result.IsNothing()) return MaybeHandle<Object>();
809 1156 : return isolate->factory()->ToBoolean(result.FromJust());
810 : }
811 :
812 : // static
813 493 : MaybeHandle<Object> Object::InstanceOf(Isolate* isolate, Handle<Object> object,
814 : Handle<Object> callable) {
815 : // The {callable} must be a receiver.
816 493 : if (!callable->IsJSReceiver()) {
817 0 : THROW_NEW_ERROR(isolate,
818 : NewTypeError(MessageTemplate::kNonObjectInInstanceOfCheck),
819 : Object);
820 : }
821 :
822 : // Lookup the @@hasInstance method on {callable}.
823 : Handle<Object> inst_of_handler;
824 986 : ASSIGN_RETURN_ON_EXCEPTION(
825 : isolate, inst_of_handler,
826 : JSReceiver::GetMethod(Handle<JSReceiver>::cast(callable),
827 : isolate->factory()->has_instance_symbol()),
828 : Object);
829 493 : if (!inst_of_handler->IsUndefined(isolate)) {
830 : // Call the {inst_of_handler} on the {callable}.
831 : Handle<Object> result;
832 972 : ASSIGN_RETURN_ON_EXCEPTION(
833 : isolate, result,
834 : Execution::Call(isolate, inst_of_handler, callable, 1, &object),
835 : Object);
836 479 : return isolate->factory()->ToBoolean(result->BooleanValue());
837 : }
838 :
839 : // The {callable} must have a [[Call]] internal method.
840 7 : if (!callable->IsCallable()) {
841 14 : THROW_NEW_ERROR(
842 : isolate, NewTypeError(MessageTemplate::kNonCallableInInstanceOfCheck),
843 : Object);
844 : }
845 :
846 : // Fall back to OrdinaryHasInstance with {callable} and {object}.
847 : Handle<Object> result;
848 0 : ASSIGN_RETURN_ON_EXCEPTION(
849 : isolate, result,
850 : JSReceiver::OrdinaryHasInstance(isolate, callable, object), Object);
851 : return result;
852 : }
853 :
854 1792631 : Maybe<bool> Object::IsArray(Handle<Object> object) {
855 1792631 : if (object->IsJSArray()) return Just(true);
856 1745689 : if (object->IsJSProxy()) {
857 : Handle<JSProxy> proxy = Handle<JSProxy>::cast(object);
858 : Isolate* isolate = proxy->GetIsolate();
859 1689 : if (proxy->IsRevoked()) {
860 : isolate->Throw(*isolate->factory()->NewTypeError(
861 : MessageTemplate::kProxyRevoked,
862 252 : isolate->factory()->NewStringFromAsciiChecked("IsArray")));
863 : return Nothing<bool>();
864 : }
865 1605 : return Object::IsArray(handle(proxy->target(), isolate));
866 : }
867 : return Just(false);
868 : }
869 :
870 :
871 : // static
872 17848324 : MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
873 : Handle<Name> name) {
874 : Handle<Object> func;
875 : Isolate* isolate = receiver->GetIsolate();
876 35696648 : ASSIGN_RETURN_ON_EXCEPTION(isolate, func,
877 : JSReceiver::GetProperty(receiver, name), Object);
878 17805259 : if (func->IsNullOrUndefined(isolate)) {
879 : return isolate->factory()->undefined_value();
880 : }
881 1628908 : if (!func->IsCallable()) {
882 728 : THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kPropertyNotFunction,
883 : func, name, receiver),
884 : Object);
885 : }
886 : return func;
887 : }
888 :
889 : namespace {
890 26820 : MaybeHandle<FixedArray> CreateListFromArrayLikeFastPath(
891 : Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
892 51929 : if (element_types != ElementTypes::kAll || !object->IsJSArray()) {
893 : return MaybeHandle<FixedArray>();
894 : }
895 : Handle<JSArray> array = Handle<JSArray>::cast(object);
896 : uint32_t length;
897 3166 : if (!array->HasArrayPrototype(isolate) ||
898 3113 : !array->length()->ToUint32(&length) || !array->HasFastElements() ||
899 444 : !JSObject::PrototypeHasNoElements(isolate, *array)) {
900 : return MaybeHandle<FixedArray>();
901 : }
902 360 : return array->GetElementsAccessor()->CreateListFromArray(isolate, array);
903 : }
904 : } // namespace
905 :
906 : // static
907 26820 : MaybeHandle<FixedArray> Object::CreateListFromArrayLike(
908 : Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
909 : // Fast-path for JS_ARRAY_TYPE.
910 : MaybeHandle<FixedArray> fast_result =
911 26820 : CreateListFromArrayLikeFastPath(isolate, object, element_types);
912 26820 : if (!fast_result.is_null()) return fast_result;
913 : // 1. ReturnIfAbrupt(object).
914 : // 2. (default elementTypes -- not applicable.)
915 : // 3. If Type(obj) is not Object, throw a TypeError exception.
916 26460 : if (!object->IsJSReceiver()) {
917 1773 : THROW_NEW_ERROR(isolate,
918 : NewTypeError(MessageTemplate::kCalledOnNonObject,
919 : isolate->factory()->NewStringFromAsciiChecked(
920 : "CreateListFromArrayLike")),
921 : FixedArray);
922 : }
923 :
924 : // 4. Let len be ? ToLength(? Get(obj, "length")).
925 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
926 : Handle<Object> raw_length_number;
927 51738 : ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number,
928 : Object::GetLengthFromArrayLike(isolate, receiver),
929 : FixedArray);
930 : uint32_t len;
931 51612 : if (!raw_length_number->ToUint32(&len) ||
932 25799 : len > static_cast<uint32_t>(FixedArray::kMaxLength)) {
933 84 : THROW_NEW_ERROR(isolate,
934 : NewRangeError(MessageTemplate::kInvalidArrayLength),
935 : FixedArray);
936 : }
937 : // 5. Let list be an empty List.
938 25771 : Handle<FixedArray> list = isolate->factory()->NewFixedArray(len);
939 : // 6. Let index be 0.
940 : // 7. Repeat while index < len:
941 62455083 : for (uint32_t index = 0; index < len; ++index) {
942 : // 7a. Let indexName be ToString(index).
943 : // 7b. Let next be ? Get(obj, indexName).
944 : Handle<Object> next;
945 124858848 : ASSIGN_RETURN_ON_EXCEPTION(isolate, next,
946 : JSReceiver::GetElement(isolate, receiver, index),
947 : FixedArray);
948 62429368 : switch (element_types) {
949 : case ElementTypes::kAll:
950 : // Nothing to do.
951 : break;
952 : case ElementTypes::kStringAndSymbol: {
953 : // 7c. If Type(next) is not an element of elementTypes, throw a
954 : // TypeError exception.
955 4247 : if (!next->IsName()) {
956 112 : THROW_NEW_ERROR(isolate,
957 : NewTypeError(MessageTemplate::kNotPropertyName, next),
958 : FixedArray);
959 : }
960 : // 7d. Append next as the last element of list.
961 : // Internalize on the fly so we can use pointer identity later.
962 4191 : next = isolate->factory()->InternalizeName(Handle<Name>::cast(next));
963 4191 : break;
964 : }
965 : }
966 124858624 : list->set(index, *next);
967 : // 7e. Set index to index + 1. (See loop header.)
968 : }
969 : // 8. Return list.
970 : return list;
971 : }
972 :
973 :
974 : // static
975 61941 : MaybeHandle<Object> Object::GetLengthFromArrayLike(Isolate* isolate,
976 : Handle<Object> object) {
977 : Handle<Object> val;
978 : Handle<Object> key = isolate->factory()->length_string();
979 123882 : ASSIGN_RETURN_ON_EXCEPTION(
980 : isolate, val, Runtime::GetObjectProperty(isolate, object, key), Object);
981 61827 : return Object::ToLength(isolate, val);
982 : }
983 :
984 : // static
985 167014786 : Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) {
986 166986048 : for (; it->IsFound(); it->Next()) {
987 43860599 : switch (it->state()) {
988 : case LookupIterator::NOT_FOUND:
989 : case LookupIterator::TRANSITION:
990 0 : UNREACHABLE();
991 : case LookupIterator::JSPROXY:
992 : return JSProxy::HasProperty(it->isolate(), it->GetHolder<JSProxy>(),
993 136398 : it->GetName());
994 : case LookupIterator::INTERCEPTOR: {
995 : Maybe<PropertyAttributes> result =
996 246 : JSObject::GetPropertyAttributesWithInterceptor(it);
997 321 : if (result.IsNothing()) return Nothing<bool>();
998 246 : if (result.FromJust() != ABSENT) return Just(true);
999 171 : break;
1000 : }
1001 : case LookupIterator::ACCESS_CHECK: {
1002 39338 : if (it->HasAccess()) break;
1003 : Maybe<PropertyAttributes> result =
1004 48 : JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
1005 96 : if (result.IsNothing()) return Nothing<bool>();
1006 0 : return Just(result.FromJust() != ABSENT);
1007 : }
1008 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
1009 : // TypedArray out-of-bounds access.
1010 : return Just(false);
1011 : case LookupIterator::ACCESSOR:
1012 : case LookupIterator::DATA:
1013 : return Just(true);
1014 : }
1015 : }
1016 : return Just(false);
1017 : }
1018 :
1019 :
1020 : // static
1021 416928103 : MaybeHandle<Object> Object::GetProperty(LookupIterator* it) {
1022 384267026 : for (; it->IsFound(); it->Next()) {
1023 158434512 : switch (it->state()) {
1024 : case LookupIterator::NOT_FOUND:
1025 : case LookupIterator::TRANSITION:
1026 0 : UNREACHABLE();
1027 : case LookupIterator::JSPROXY: {
1028 : bool was_found;
1029 : MaybeHandle<Object> result =
1030 : JSProxy::GetProperty(it->isolate(), it->GetHolder<JSProxy>(),
1031 440536 : it->GetName(), it->GetReceiver(), &was_found);
1032 220268 : if (!was_found) it->NotFound();
1033 220268 : return result;
1034 : }
1035 : case LookupIterator::INTERCEPTOR: {
1036 : bool done;
1037 : Handle<Object> result;
1038 13447 : ASSIGN_RETURN_ON_EXCEPTION(
1039 : it->isolate(), result,
1040 : JSObject::GetPropertyWithInterceptor(it, &done), Object);
1041 5102 : if (done) return result;
1042 1901 : break;
1043 : }
1044 : case LookupIterator::ACCESS_CHECK:
1045 1262459 : if (it->HasAccess()) break;
1046 1378 : return JSObject::GetPropertyWithFailedAccessCheck(it);
1047 : case LookupIterator::ACCESSOR:
1048 10153584 : return GetPropertyWithAccessor(it);
1049 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
1050 : return it->isolate()->factory()->undefined_value();
1051 : case LookupIterator::DATA:
1052 146788302 : return it->GetDataValue();
1053 : }
1054 : }
1055 : return it->isolate()->factory()->undefined_value();
1056 : }
1057 :
1058 :
1059 : // static
1060 220268 : MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
1061 : Handle<JSProxy> proxy,
1062 : Handle<Name> name,
1063 : Handle<Object> receiver,
1064 : bool* was_found) {
1065 220268 : *was_found = true;
1066 :
1067 : DCHECK(!name->IsPrivate());
1068 220268 : STACK_CHECK(isolate, MaybeHandle<Object>());
1069 : Handle<Name> trap_name = isolate->factory()->get_string();
1070 : // 1. Assert: IsPropertyKey(P) is true.
1071 : // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
1072 : Handle<Object> handler(proxy->handler(), isolate);
1073 : // 3. If handler is null, throw a TypeError exception.
1074 : // 4. Assert: Type(handler) is Object.
1075 220044 : if (proxy->IsRevoked()) {
1076 112 : THROW_NEW_ERROR(isolate,
1077 : NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1078 : Object);
1079 : }
1080 : // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
1081 : Handle<JSReceiver> target(proxy->target(), isolate);
1082 : // 6. Let trap be ? GetMethod(handler, "get").
1083 : Handle<Object> trap;
1084 439976 : ASSIGN_RETURN_ON_EXCEPTION(
1085 : isolate, trap,
1086 : Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), Object);
1087 : // 7. If trap is undefined, then
1088 177853 : if (trap->IsUndefined(isolate)) {
1089 : // 7.a Return target.[[Get]](P, Receiver).
1090 : LookupIterator it =
1091 100978 : LookupIterator::PropertyOrElement(isolate, receiver, name, target);
1092 100978 : MaybeHandle<Object> result = Object::GetProperty(&it);
1093 201956 : *was_found = it.IsFound();
1094 100978 : return result;
1095 : }
1096 : // 8. Let trapResult be ? Call(trap, handler, «target, P, Receiver»).
1097 : Handle<Object> trap_result;
1098 76875 : Handle<Object> args[] = {target, name, receiver};
1099 153750 : ASSIGN_RETURN_ON_EXCEPTION(
1100 : isolate, trap_result,
1101 : Execution::Call(isolate, trap, handler, arraysize(args), args), Object);
1102 : // 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
1103 : PropertyDescriptor target_desc;
1104 : Maybe<bool> target_found =
1105 74323 : JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
1106 74323 : MAYBE_RETURN_NULL(target_found);
1107 : // 10. If targetDesc is not undefined, then
1108 74323 : if (target_found.FromJust()) {
1109 : // 10.a. If IsDataDescriptor(targetDesc) and targetDesc.[[Configurable]] is
1110 : // false and targetDesc.[[Writable]] is false, then
1111 : // 10.a.i. If SameValue(trapResult, targetDesc.[[Value]]) is false,
1112 : // throw a TypeError exception.
1113 6800 : bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
1114 1043 : !target_desc.configurable() &&
1115 6988 : !target_desc.writable() &&
1116 132 : !trap_result->SameValue(*target_desc.value());
1117 6856 : if (inconsistent) {
1118 84 : THROW_NEW_ERROR(
1119 : isolate, NewTypeError(MessageTemplate::kProxyGetNonConfigurableData,
1120 : name, target_desc.value(), trap_result),
1121 : Object);
1122 : }
1123 : // 10.b. If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]]
1124 : // is false and targetDesc.[[Get]] is undefined, then
1125 : // 10.b.i. If trapResult is not undefined, throw a TypeError exception.
1126 56 : inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
1127 56 : !target_desc.configurable() &&
1128 6842 : target_desc.get()->IsUndefined(isolate) &&
1129 : !trap_result->IsUndefined(isolate);
1130 6814 : if (inconsistent) {
1131 28 : THROW_NEW_ERROR(
1132 : isolate,
1133 : NewTypeError(MessageTemplate::kProxyGetNonConfigurableAccessor, name,
1134 : trap_result),
1135 : Object);
1136 : }
1137 : }
1138 : // 11. Return trap_result
1139 : return trap_result;
1140 : }
1141 :
1142 :
1143 14870391 : Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it) {
1144 14197946 : for (; it->IsFound(); it->Next()) {
1145 7058035 : switch (it->state()) {
1146 : case LookupIterator::INTERCEPTOR:
1147 : case LookupIterator::NOT_FOUND:
1148 : case LookupIterator::TRANSITION:
1149 0 : UNREACHABLE();
1150 : case LookupIterator::ACCESS_CHECK:
1151 : // Support calling this method without an active context, but refuse
1152 : // access to access-checked objects in that case.
1153 891019 : if (it->isolate()->context() != nullptr && it->HasAccess()) continue;
1154 : // Fall through.
1155 : case LookupIterator::JSPROXY:
1156 : it->NotFound();
1157 3209 : return it->isolate()->factory()->undefined_value();
1158 : case LookupIterator::ACCESSOR:
1159 : // TODO(verwaest): For now this doesn't call into AccessorInfo, since
1160 : // clients don't need it. Update once relevant.
1161 : it->NotFound();
1162 627901 : return it->isolate()->factory()->undefined_value();
1163 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
1164 0 : return it->isolate()->factory()->undefined_value();
1165 : case LookupIterator::DATA:
1166 5536303 : return it->GetDataValue();
1167 : }
1168 : }
1169 40938 : return it->isolate()->factory()->undefined_value();
1170 : }
1171 :
1172 :
1173 62870206 : bool Object::ToInt32(int32_t* value) {
1174 62870206 : if (IsSmi()) {
1175 62868679 : *value = Smi::cast(this)->value();
1176 62868679 : return true;
1177 : }
1178 1527 : if (IsHeapNumber()) {
1179 : double num = HeapNumber::cast(this)->value();
1180 1478 : if (FastI2D(FastD2I(num)) == num) {
1181 77 : *value = FastD2I(num);
1182 77 : return true;
1183 : }
1184 : }
1185 : return false;
1186 : }
1187 :
1188 3891714 : Handle<SharedFunctionInfo> FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(
1189 : Isolate* isolate, Handle<FunctionTemplateInfo> info) {
1190 : Object* current_info = info->shared_function_info();
1191 3891717 : if (current_info->IsSharedFunctionInfo()) {
1192 : return handle(SharedFunctionInfo::cast(current_info), isolate);
1193 : }
1194 :
1195 : Handle<Object> class_name(info->class_name(), isolate);
1196 : Handle<String> name = class_name->IsString()
1197 : ? Handle<String>::cast(class_name)
1198 7461323 : : isolate->factory()->empty_string();
1199 3761998 : Handle<Code> code = isolate->builtins()->HandleApiCall();
1200 3761997 : bool is_constructor = !info->remove_prototype();
1201 : Handle<SharedFunctionInfo> result =
1202 7523994 : isolate->factory()->NewSharedFunctionInfo(name, code, is_constructor);
1203 3761995 : if (is_constructor) {
1204 7441614 : result->SetConstructStub(*isolate->builtins()->JSConstructStubApi());
1205 : }
1206 :
1207 : result->set_length(info->length());
1208 3824671 : if (class_name->IsString()) result->set_instance_class_name(*class_name);
1209 : result->set_api_func_data(*info);
1210 : result->DontAdaptArguments();
1211 : DCHECK(result->IsApiFunction());
1212 :
1213 3761998 : info->set_shared_function_info(*result);
1214 3761997 : return result;
1215 : }
1216 :
1217 18284 : bool FunctionTemplateInfo::IsTemplateFor(Map* map) {
1218 : // There is a constraint on the object; check.
1219 18284 : if (!map->IsJSObjectMap()) return false;
1220 : // Fetch the constructor function of the object.
1221 18284 : Object* cons_obj = map->GetConstructor();
1222 : Object* type;
1223 18284 : if (cons_obj->IsJSFunction()) {
1224 : JSFunction* fun = JSFunction::cast(cons_obj);
1225 : type = fun->shared()->function_data();
1226 18 : } else if (cons_obj->IsFunctionTemplateInfo()) {
1227 : type = FunctionTemplateInfo::cast(cons_obj);
1228 : } else {
1229 : return false;
1230 : }
1231 : // Iterate through the chain of inheriting function templates to
1232 : // see if the required one occurs.
1233 18885 : while (type->IsFunctionTemplateInfo()) {
1234 10921 : if (type == this) return true;
1235 : type = FunctionTemplateInfo::cast(type)->parent_template();
1236 : }
1237 : // Didn't find the required type in the inheritance chain.
1238 : return false;
1239 : }
1240 :
1241 :
1242 : // static
1243 380233 : Handle<TemplateList> TemplateList::New(Isolate* isolate, int size) {
1244 : Handle<FixedArray> list =
1245 380233 : isolate->factory()->NewFixedArray(kLengthIndex + size);
1246 : list->set(kLengthIndex, Smi::kZero);
1247 380233 : return Handle<TemplateList>::cast(list);
1248 : }
1249 :
1250 : // static
1251 6575955 : Handle<TemplateList> TemplateList::Add(Isolate* isolate,
1252 : Handle<TemplateList> list,
1253 : Handle<i::Object> value) {
1254 : STATIC_ASSERT(kFirstElementIndex == 1);
1255 6575955 : int index = list->length() + 1;
1256 : Handle<i::FixedArray> fixed_array = Handle<FixedArray>::cast(list);
1257 6575955 : fixed_array = FixedArray::SetAndGrow(fixed_array, index, value);
1258 : fixed_array->set(kLengthIndex, Smi::FromInt(index));
1259 6575955 : return Handle<TemplateList>::cast(fixed_array);
1260 : }
1261 :
1262 : // static
1263 2465542 : MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor,
1264 : Handle<JSReceiver> new_target,
1265 : Handle<AllocationSite> site) {
1266 : // If called through new, new.target can be:
1267 : // - a subclass of constructor,
1268 : // - a proxy wrapper around constructor, or
1269 : // - the constructor itself.
1270 : // If called through Reflect.construct, it's guaranteed to be a constructor.
1271 4930994 : Isolate* const isolate = constructor->GetIsolate();
1272 : DCHECK(constructor->IsConstructor());
1273 : DCHECK(new_target->IsConstructor());
1274 : DCHECK(!constructor->has_initial_map() ||
1275 : constructor->initial_map()->instance_type() != JS_FUNCTION_TYPE);
1276 :
1277 : Handle<Map> initial_map;
1278 4931084 : ASSIGN_RETURN_ON_EXCEPTION(
1279 : isolate, initial_map,
1280 : JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject);
1281 : Handle<JSObject> result =
1282 2465497 : isolate->factory()->NewJSObjectFromMap(initial_map, NOT_TENURED, site);
1283 2465497 : if (initial_map->is_dictionary_map()) {
1284 : Handle<NameDictionary> dictionary =
1285 0 : NameDictionary::New(isolate, NameDictionary::kInitialCapacity);
1286 0 : result->set_properties(*dictionary);
1287 : }
1288 2465497 : isolate->counters()->constructed_objects()->Increment();
1289 2465497 : isolate->counters()->constructed_objects_runtime()->Increment();
1290 : return result;
1291 : }
1292 :
1293 2496984 : void JSObject::EnsureWritableFastElements(Handle<JSObject> object) {
1294 : DCHECK(object->HasFastSmiOrObjectElements() ||
1295 : object->HasFastStringWrapperElements());
1296 : FixedArray* raw_elems = FixedArray::cast(object->elements());
1297 2496984 : Heap* heap = object->GetHeap();
1298 4968182 : if (raw_elems->map() != heap->fixed_cow_array_map()) return;
1299 25786 : Isolate* isolate = heap->isolate();
1300 : Handle<FixedArray> elems(raw_elems, isolate);
1301 : Handle<FixedArray> writable_elems = isolate->factory()->CopyFixedArrayWithMap(
1302 25786 : elems, isolate->factory()->fixed_array_map());
1303 25786 : object->set_elements(*writable_elems);
1304 25786 : isolate->counters()->cow_arrays_converted()->Increment();
1305 : }
1306 :
1307 :
1308 : // ES6 9.5.1
1309 : // static
1310 5702696 : MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
1311 : Isolate* isolate = proxy->GetIsolate();
1312 : Handle<String> trap_name = isolate->factory()->getPrototypeOf_string();
1313 :
1314 5702696 : STACK_CHECK(isolate, MaybeHandle<Object>());
1315 :
1316 : // 1. Let handler be the value of the [[ProxyHandler]] internal slot.
1317 : // 2. If handler is null, throw a TypeError exception.
1318 : // 3. Assert: Type(handler) is Object.
1319 : // 4. Let target be the value of the [[ProxyTarget]] internal slot.
1320 5702696 : if (proxy->IsRevoked()) {
1321 56 : THROW_NEW_ERROR(isolate,
1322 : NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1323 : Object);
1324 : }
1325 : Handle<JSReceiver> target(proxy->target(), isolate);
1326 : Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
1327 :
1328 : // 5. Let trap be ? GetMethod(handler, "getPrototypeOf").
1329 : Handle<Object> trap;
1330 11405336 : ASSIGN_RETURN_ON_EXCEPTION(isolate, trap, GetMethod(handler, trap_name),
1331 : Object);
1332 : // 6. If trap is undefined, then return target.[[GetPrototypeOf]]().
1333 5702668 : if (trap->IsUndefined(isolate)) {
1334 4202080 : return JSReceiver::GetPrototype(isolate, target);
1335 : }
1336 : // 7. Let handlerProto be ? Call(trap, handler, «target»).
1337 : Handle<Object> argv[] = {target};
1338 : Handle<Object> handler_proto;
1339 3001176 : ASSIGN_RETURN_ON_EXCEPTION(
1340 : isolate, handler_proto,
1341 : Execution::Call(isolate, trap, handler, arraysize(argv), argv), Object);
1342 : // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError.
1343 1500476 : if (!(handler_proto->IsJSReceiver() || handler_proto->IsNull(isolate))) {
1344 28 : THROW_NEW_ERROR(isolate,
1345 : NewTypeError(MessageTemplate::kProxyGetPrototypeOfInvalid),
1346 : Object);
1347 : }
1348 : // 9. Let extensibleTarget be ? IsExtensible(target).
1349 1500420 : Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
1350 1500420 : MAYBE_RETURN_NULL(is_extensible);
1351 : // 10. If extensibleTarget is true, return handlerProto.
1352 1500420 : if (is_extensible.FromJust()) return handler_proto;
1353 : // 11. Let targetProto be ? target.[[GetPrototypeOf]]().
1354 : Handle<Object> target_proto;
1355 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, target_proto,
1356 : JSReceiver::GetPrototype(isolate, target), Object);
1357 : // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError.
1358 0 : if (!handler_proto->SameValue(*target_proto)) {
1359 0 : THROW_NEW_ERROR(
1360 : isolate,
1361 : NewTypeError(MessageTemplate::kProxyGetPrototypeOfNonExtensible),
1362 : Object);
1363 : }
1364 : // 13. Return handlerProto.
1365 : return handler_proto;
1366 : }
1367 :
1368 10154135 : MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) {
1369 : Isolate* isolate = it->isolate();
1370 10154135 : Handle<Object> structure = it->GetAccessors();
1371 : Handle<Object> receiver = it->GetReceiver();
1372 :
1373 : // We should never get here to initialize a const with the hole value since a
1374 : // const declaration would conflict with the getter.
1375 : DCHECK(!structure->IsForeign());
1376 :
1377 : // API style callbacks.
1378 10154135 : if (structure->IsAccessorInfo()) {
1379 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1380 887279 : Handle<Name> name = it->GetName();
1381 : Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
1382 887279 : if (!info->IsCompatibleReceiver(*receiver)) {
1383 210 : THROW_NEW_ERROR(isolate,
1384 : NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
1385 : name, receiver),
1386 : Object);
1387 : }
1388 :
1389 : v8::AccessorNameGetterCallback call_fun =
1390 : v8::ToCData<v8::AccessorNameGetterCallback>(info->getter());
1391 887174 : if (call_fun == nullptr) return isolate->factory()->undefined_value();
1392 :
1393 901230 : if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1394 36 : ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver,
1395 : Object::ConvertReceiver(isolate, receiver),
1396 : Object);
1397 : }
1398 :
1399 : PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1400 : Object::DONT_THROW);
1401 887034 : Handle<Object> result = args.Call(call_fun, name);
1402 887034 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1403 886799 : if (result.is_null()) return isolate->factory()->undefined_value();
1404 : Handle<Object> reboxed_result = handle(*result, isolate);
1405 879695 : if (info->replace_on_access() && receiver->IsJSReceiver()) {
1406 : args.Call(reinterpret_cast<GenericNamedPropertySetterCallback>(
1407 : &Accessors::ReconfigureToDataProperty),
1408 0 : name, result);
1409 0 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1410 : }
1411 : return reboxed_result;
1412 : }
1413 :
1414 : // AccessorPair with 'cached' private property.
1415 9266856 : if (it->TryLookupCachedProperty()) {
1416 58 : return Object::GetProperty(it);
1417 : }
1418 :
1419 : // Regular accessor.
1420 : Handle<Object> getter(AccessorPair::cast(*structure)->getter(), isolate);
1421 9266798 : if (getter->IsFunctionTemplateInfo()) {
1422 : return Builtins::InvokeApiFunction(
1423 : isolate, false, Handle<FunctionTemplateInfo>::cast(getter), receiver, 0,
1424 313 : nullptr, isolate->factory()->undefined_value());
1425 9266485 : } else if (getter->IsCallable()) {
1426 : // TODO(rossberg): nicer would be to cast to some JSCallable here...
1427 : return Object::GetPropertyWithDefinedGetter(
1428 9258024 : receiver, Handle<JSReceiver>::cast(getter));
1429 : }
1430 : // Getter is not a function.
1431 : return isolate->factory()->undefined_value();
1432 : }
1433 :
1434 : // static
1435 0 : Address AccessorInfo::redirect(Isolate* isolate, Address address,
1436 : AccessorComponent component) {
1437 : ApiFunction fun(address);
1438 : DCHECK_EQ(ACCESSOR_GETTER, component);
1439 : ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
1440 246012 : return ExternalReference(&fun, type, isolate).address();
1441 : }
1442 :
1443 124405 : Address AccessorInfo::redirected_getter() const {
1444 : Address accessor = v8::ToCData<Address>(getter());
1445 124405 : if (accessor == nullptr) return nullptr;
1446 123006 : return redirect(GetIsolate(), accessor, ACCESSOR_GETTER);
1447 : }
1448 :
1449 39810 : bool AccessorInfo::IsCompatibleReceiverMap(Isolate* isolate,
1450 : Handle<AccessorInfo> info,
1451 : Handle<Map> map) {
1452 39810 : if (!info->HasExpectedReceiverType()) return true;
1453 72 : if (!map->IsJSObjectMap()) return false;
1454 : return FunctionTemplateInfo::cast(info->expected_receiver_type())
1455 72 : ->IsTemplateFor(*map);
1456 : }
1457 :
1458 1980949 : Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it,
1459 : Handle<Object> value,
1460 : ShouldThrow should_throw) {
1461 : Isolate* isolate = it->isolate();
1462 1980949 : Handle<Object> structure = it->GetAccessors();
1463 : Handle<Object> receiver = it->GetReceiver();
1464 :
1465 : // We should never get here to initialize a const with the hole value since a
1466 : // const declaration would conflict with the setter.
1467 : DCHECK(!structure->IsForeign());
1468 :
1469 : // API style callbacks.
1470 1980949 : if (structure->IsAccessorInfo()) {
1471 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1472 1782979 : Handle<Name> name = it->GetName();
1473 : Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
1474 1782978 : if (!info->IsCompatibleReceiver(*receiver)) {
1475 : isolate->Throw(*isolate->factory()->NewTypeError(
1476 210 : MessageTemplate::kIncompatibleMethodReceiver, name, receiver));
1477 : return Nothing<bool>();
1478 : }
1479 :
1480 : // The actual type of call_fun is either v8::AccessorNameSetterCallback or
1481 : // i::Accesors::AccessorNameBooleanSetterCallback, depending on whether the
1482 : // AccessorInfo was created by the API or internally (see accessors.cc).
1483 : // Here we handle both cases using GenericNamedPropertySetterCallback and
1484 : // its Call method.
1485 : GenericNamedPropertySetterCallback call_fun =
1486 : v8::ToCData<GenericNamedPropertySetterCallback>(info->setter());
1487 :
1488 1782873 : if (call_fun == nullptr) {
1489 : // TODO(verwaest): We should not get here anymore once all AccessorInfos
1490 : // are marked as special_data_property. They cannot both be writable and
1491 : // not have a setter.
1492 : return Just(true);
1493 : }
1494 :
1495 1923555 : if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1496 0 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1497 : isolate, receiver, Object::ConvertReceiver(isolate, receiver),
1498 : Nothing<bool>());
1499 : }
1500 :
1501 : PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1502 : should_throw);
1503 1782796 : Handle<Object> result = args.Call(call_fun, name, value);
1504 : // In the case of AccessorNameSetterCallback, we know that the result value
1505 : // cannot have been set, so the result of Call will be null. In the case of
1506 : // AccessorNameBooleanSetterCallback, the result will either be null
1507 : // (signalling an exception) or a boolean Oddball.
1508 1782795 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1509 1782530 : if (result.is_null()) return Just(true);
1510 : DCHECK(result->BooleanValue() || should_throw == DONT_THROW);
1511 1641841 : return Just(result->BooleanValue());
1512 : }
1513 :
1514 : // Regular accessor.
1515 : Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
1516 197970 : if (setter->IsFunctionTemplateInfo()) {
1517 159 : Handle<Object> argv[] = {value};
1518 318 : RETURN_ON_EXCEPTION_VALUE(
1519 : isolate, Builtins::InvokeApiFunction(
1520 : isolate, false, Handle<FunctionTemplateInfo>::cast(setter),
1521 : receiver, arraysize(argv), argv,
1522 : isolate->factory()->undefined_value()),
1523 : Nothing<bool>());
1524 : return Just(true);
1525 197811 : } else if (setter->IsCallable()) {
1526 : // TODO(rossberg): nicer would be to cast to some JSCallable here...
1527 : return SetPropertyWithDefinedSetter(
1528 179220 : receiver, Handle<JSReceiver>::cast(setter), value, should_throw);
1529 : }
1530 :
1531 45750 : RETURN_FAILURE(isolate, should_throw,
1532 : NewTypeError(MessageTemplate::kNoSetterInCallback,
1533 : it->GetName(), it->GetHolder<JSObject>()));
1534 : }
1535 :
1536 :
1537 9258024 : MaybeHandle<Object> Object::GetPropertyWithDefinedGetter(
1538 : Handle<Object> receiver,
1539 : Handle<JSReceiver> getter) {
1540 : Isolate* isolate = getter->GetIsolate();
1541 :
1542 : // Platforms with simulators like arm/arm64 expose a funny issue. If the
1543 : // simulator has a separate JS stack pointer from the C++ stack pointer, it
1544 : // can miss C++ stack overflows in the stack guard at the start of JavaScript
1545 : // functions. It would be very expensive to check the C++ stack pointer at
1546 : // that location. The best solution seems to be to break the impasse by
1547 : // adding checks at possible recursion points. What's more, we don't put
1548 : // this stack check behind the USE_SIMULATOR define in order to keep
1549 : // behavior the same between hardware and simulators.
1550 : StackLimitCheck check(isolate);
1551 9258024 : if (check.JsHasOverflowed()) {
1552 28 : isolate->StackOverflow();
1553 : return MaybeHandle<Object>();
1554 : }
1555 :
1556 9257996 : return Execution::Call(isolate, getter, receiver, 0, NULL);
1557 : }
1558 :
1559 :
1560 179220 : Maybe<bool> Object::SetPropertyWithDefinedSetter(Handle<Object> receiver,
1561 : Handle<JSReceiver> setter,
1562 : Handle<Object> value,
1563 : ShouldThrow should_throw) {
1564 : Isolate* isolate = setter->GetIsolate();
1565 :
1566 179220 : Handle<Object> argv[] = { value };
1567 358440 : RETURN_ON_EXCEPTION_VALUE(isolate, Execution::Call(isolate, setter, receiver,
1568 : arraysize(argv), argv),
1569 : Nothing<bool>());
1570 : return Just(true);
1571 : }
1572 :
1573 :
1574 : // static
1575 4210 : bool JSObject::AllCanRead(LookupIterator* it) {
1576 : // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of
1577 : // which have already been checked.
1578 : DCHECK(it->state() == LookupIterator::ACCESS_CHECK ||
1579 : it->state() == LookupIterator::INTERCEPTOR);
1580 5552 : for (it->Next(); it->IsFound(); it->Next()) {
1581 1429 : if (it->state() == LookupIterator::ACCESSOR) {
1582 146 : auto accessors = it->GetAccessors();
1583 146 : if (accessors->IsAccessorInfo()) {
1584 92 : if (AccessorInfo::cast(*accessors)->all_can_read()) return true;
1585 : }
1586 1283 : } else if (it->state() == LookupIterator::INTERCEPTOR) {
1587 1472 : if (it->GetInterceptor()->all_can_read()) return true;
1588 547 : } else if (it->state() == LookupIterator::JSPROXY) {
1589 : // Stop lookupiterating. And no, AllCanNotRead.
1590 : return false;
1591 : }
1592 : }
1593 : return false;
1594 : }
1595 :
1596 : namespace {
1597 :
1598 5313 : MaybeHandle<Object> GetPropertyWithInterceptorInternal(
1599 10598 : LookupIterator* it, Handle<InterceptorInfo> interceptor, bool* done) {
1600 5313 : *done = false;
1601 : Isolate* isolate = it->isolate();
1602 : // Make sure that the top context does not change when doing callbacks or
1603 : // interceptor calls.
1604 : AssertNoContextChange ncc(isolate);
1605 :
1606 5313 : if (interceptor->getter()->IsUndefined(isolate)) {
1607 : return isolate->factory()->undefined_value();
1608 : }
1609 :
1610 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1611 : Handle<Object> result;
1612 : Handle<Object> receiver = it->GetReceiver();
1613 5285 : if (!receiver->IsJSReceiver()) {
1614 38 : ASSIGN_RETURN_ON_EXCEPTION(
1615 : isolate, receiver, Object::ConvertReceiver(isolate, receiver), Object);
1616 : }
1617 : PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1618 : *holder, Object::DONT_THROW);
1619 :
1620 5285 : if (it->IsElement()) {
1621 : uint32_t index = it->index();
1622 : v8::IndexedPropertyGetterCallback getter =
1623 : v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
1624 2471 : result = args.Call(getter, index);
1625 : } else {
1626 2814 : Handle<Name> name = it->name();
1627 : DCHECK(!name->IsPrivate());
1628 :
1629 : DCHECK_IMPLIES(name->IsSymbol(), interceptor->can_intercept_symbols());
1630 :
1631 : v8::GenericNamedPropertyGetterCallback getter =
1632 : v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
1633 : interceptor->getter());
1634 2814 : result = args.Call(getter, name);
1635 : }
1636 :
1637 5285 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1638 5257 : if (result.is_null()) return isolate->factory()->undefined_value();
1639 3288 : *done = true;
1640 : // Rebox handle before return
1641 : return handle(*result, isolate);
1642 : }
1643 :
1644 281223 : Maybe<PropertyAttributes> GetPropertyAttributesWithInterceptorInternal(
1645 562338 : LookupIterator* it, Handle<InterceptorInfo> interceptor) {
1646 : Isolate* isolate = it->isolate();
1647 : // Make sure that the top context does not change when doing
1648 : // callbacks or interceptor calls.
1649 : AssertNoContextChange ncc(isolate);
1650 : HandleScope scope(isolate);
1651 :
1652 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1653 : DCHECK_IMPLIES(!it->IsElement() && it->name()->IsSymbol(),
1654 : interceptor->can_intercept_symbols());
1655 : Handle<Object> receiver = it->GetReceiver();
1656 281223 : if (!receiver->IsJSReceiver()) {
1657 28 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1658 : Object::ConvertReceiver(isolate, receiver),
1659 : Nothing<PropertyAttributes>());
1660 : }
1661 : PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1662 : *holder, Object::DONT_THROW);
1663 281223 : if (!interceptor->query()->IsUndefined(isolate)) {
1664 : Handle<Object> result;
1665 268 : if (it->IsElement()) {
1666 : uint32_t index = it->index();
1667 : v8::IndexedPropertyQueryCallback query =
1668 : v8::ToCData<v8::IndexedPropertyQueryCallback>(interceptor->query());
1669 102 : result = args.Call(query, index);
1670 : } else {
1671 166 : Handle<Name> name = it->name();
1672 : DCHECK(!name->IsPrivate());
1673 : v8::GenericNamedPropertyQueryCallback query =
1674 : v8::ToCData<v8::GenericNamedPropertyQueryCallback>(
1675 : interceptor->query());
1676 166 : result = args.Call(query, name);
1677 : }
1678 268 : if (!result.is_null()) {
1679 : int32_t value;
1680 62 : CHECK(result->ToInt32(&value));
1681 62 : return Just(static_cast<PropertyAttributes>(value));
1682 : }
1683 280955 : } else if (!interceptor->getter()->IsUndefined(isolate)) {
1684 : // TODO(verwaest): Use GetPropertyWithInterceptor?
1685 : Handle<Object> result;
1686 280847 : if (it->IsElement()) {
1687 : uint32_t index = it->index();
1688 : v8::IndexedPropertyGetterCallback getter =
1689 : v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
1690 280250 : result = args.Call(getter, index);
1691 : } else {
1692 597 : Handle<Name> name = it->name();
1693 : DCHECK(!name->IsPrivate());
1694 : v8::GenericNamedPropertyGetterCallback getter =
1695 : v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
1696 : interceptor->getter());
1697 597 : result = args.Call(getter, name);
1698 : }
1699 280847 : if (!result.is_null()) return Just(DONT_ENUM);
1700 : }
1701 :
1702 280682 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
1703 : return Just(ABSENT);
1704 : }
1705 :
1706 225683 : Maybe<bool> SetPropertyWithInterceptorInternal(
1707 660931 : LookupIterator* it, Handle<InterceptorInfo> interceptor,
1708 : Object::ShouldThrow should_throw, Handle<Object> value) {
1709 : Isolate* isolate = it->isolate();
1710 : // Make sure that the top context does not change when doing callbacks or
1711 : // interceptor calls.
1712 : AssertNoContextChange ncc(isolate);
1713 :
1714 225683 : if (interceptor->setter()->IsUndefined(isolate)) return Just(false);
1715 :
1716 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1717 : bool result;
1718 : Handle<Object> receiver = it->GetReceiver();
1719 217624 : if (!receiver->IsJSReceiver()) {
1720 0 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1721 : Object::ConvertReceiver(isolate, receiver),
1722 : Nothing<bool>());
1723 : }
1724 : PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1725 : *holder, should_throw);
1726 :
1727 217624 : if (it->IsElement()) {
1728 : uint32_t index = it->index();
1729 : v8::IndexedPropertySetterCallback setter =
1730 : v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter());
1731 : // TODO(neis): In the future, we may want to actually return the
1732 : // interceptor's result, which then should be a boolean.
1733 153226 : result = !args.Call(setter, index, value).is_null();
1734 : } else {
1735 141011 : Handle<Name> name = it->name();
1736 : DCHECK(!name->IsPrivate());
1737 :
1738 : DCHECK_IMPLIES(name->IsSymbol(), interceptor->can_intercept_symbols());
1739 :
1740 : v8::GenericNamedPropertySetterCallback setter =
1741 : v8::ToCData<v8::GenericNamedPropertySetterCallback>(
1742 : interceptor->setter());
1743 282022 : result = !args.Call(setter, name, value).is_null();
1744 : }
1745 :
1746 217624 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1747 : return Just(result);
1748 : }
1749 :
1750 208 : Maybe<bool> DefinePropertyWithInterceptorInternal(
1751 400 : LookupIterator* it, Handle<InterceptorInfo> interceptor,
1752 : Object::ShouldThrow should_throw, PropertyDescriptor& desc) {
1753 : Isolate* isolate = it->isolate();
1754 : // Make sure that the top context does not change when doing callbacks or
1755 : // interceptor calls.
1756 : AssertNoContextChange ncc(isolate);
1757 :
1758 208 : if (interceptor->definer()->IsUndefined(isolate)) return Just(false);
1759 :
1760 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1761 : bool result;
1762 : Handle<Object> receiver = it->GetReceiver();
1763 96 : if (!receiver->IsJSReceiver()) {
1764 0 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1765 : Object::ConvertReceiver(isolate, receiver),
1766 : Nothing<bool>());
1767 : }
1768 : PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1769 : *holder, should_throw);
1770 :
1771 : std::unique_ptr<v8::PropertyDescriptor> descriptor(
1772 96 : new v8::PropertyDescriptor());
1773 96 : if (PropertyDescriptor::IsAccessorDescriptor(&desc)) {
1774 : descriptor.reset(new v8::PropertyDescriptor(
1775 70 : v8::Utils::ToLocal(desc.get()), v8::Utils::ToLocal(desc.set())));
1776 61 : } else if (PropertyDescriptor::IsDataDescriptor(&desc)) {
1777 49 : if (desc.has_writable()) {
1778 : descriptor.reset(new v8::PropertyDescriptor(
1779 21 : v8::Utils::ToLocal(desc.value()), desc.writable()));
1780 : } else {
1781 : descriptor.reset(
1782 84 : new v8::PropertyDescriptor(v8::Utils::ToLocal(desc.value())));
1783 : }
1784 : }
1785 96 : if (desc.has_enumerable()) {
1786 14 : descriptor->set_enumerable(desc.enumerable());
1787 : }
1788 96 : if (desc.has_configurable()) {
1789 14 : descriptor->set_configurable(desc.configurable());
1790 : }
1791 :
1792 96 : if (it->IsElement()) {
1793 : uint32_t index = it->index();
1794 : v8::IndexedPropertyDefinerCallback definer =
1795 : v8::ToCData<v8::IndexedPropertyDefinerCallback>(interceptor->definer());
1796 54 : result = !args.Call(definer, index, *descriptor).is_null();
1797 : } else {
1798 69 : Handle<Name> name = it->name();
1799 : DCHECK(!name->IsPrivate());
1800 :
1801 : DCHECK_IMPLIES(name->IsSymbol(), interceptor->can_intercept_symbols());
1802 :
1803 : v8::GenericNamedPropertyDefinerCallback definer =
1804 : v8::ToCData<v8::GenericNamedPropertyDefinerCallback>(
1805 : interceptor->definer());
1806 138 : result = !args.Call(definer, name, *descriptor).is_null();
1807 : }
1808 :
1809 96 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1810 : return Just(result);
1811 : }
1812 :
1813 : } // namespace
1814 :
1815 1378 : MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
1816 1463 : LookupIterator* it) {
1817 : Isolate* isolate = it->isolate();
1818 1378 : Handle<JSObject> checked = it->GetHolder<JSObject>();
1819 : Handle<InterceptorInfo> interceptor =
1820 1378 : it->GetInterceptorForFailedAccessCheck();
1821 1378 : if (interceptor.is_null()) {
1822 1229 : while (AllCanRead(it)) {
1823 55 : if (it->state() == LookupIterator::ACCESSOR) {
1824 62 : return GetPropertyWithAccessor(it);
1825 : }
1826 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
1827 : bool done;
1828 : Handle<Object> result;
1829 72 : ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
1830 : GetPropertyWithInterceptor(it, &done), Object);
1831 36 : if (done) return result;
1832 : }
1833 :
1834 : } else {
1835 : Handle<Object> result;
1836 : bool done;
1837 399 : ASSIGN_RETURN_ON_EXCEPTION(
1838 : isolate, result,
1839 : GetPropertyWithInterceptorInternal(it, interceptor, &done), Object);
1840 147 : if (done) return result;
1841 : }
1842 :
1843 : // Cross-Origin [[Get]] of Well-Known Symbols does not throw, and returns
1844 : // undefined.
1845 1258 : Handle<Name> name = it->GetName();
1846 1294 : if (name->IsSymbol() && Symbol::cast(*name)->is_well_known_symbol()) {
1847 : return it->factory()->undefined_value();
1848 : }
1849 :
1850 1228 : isolate->ReportFailedAccessCheck(checked);
1851 1228 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1852 : return it->factory()->undefined_value();
1853 : }
1854 :
1855 :
1856 145 : Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
1857 157 : LookupIterator* it) {
1858 : Isolate* isolate = it->isolate();
1859 145 : Handle<JSObject> checked = it->GetHolder<JSObject>();
1860 : Handle<InterceptorInfo> interceptor =
1861 145 : it->GetInterceptorForFailedAccessCheck();
1862 145 : if (interceptor.is_null()) {
1863 145 : while (AllCanRead(it)) {
1864 12 : if (it->state() == LookupIterator::ACCESSOR) {
1865 : return Just(it->property_attributes());
1866 : }
1867 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
1868 0 : auto result = GetPropertyAttributesWithInterceptor(it);
1869 0 : if (isolate->has_scheduled_exception()) break;
1870 0 : if (result.IsJust() && result.FromJust() != ABSENT) return result;
1871 : }
1872 : } else {
1873 : Maybe<PropertyAttributes> result =
1874 0 : GetPropertyAttributesWithInterceptorInternal(it, interceptor);
1875 0 : if (isolate->has_pending_exception()) return Nothing<PropertyAttributes>();
1876 0 : if (result.FromMaybe(ABSENT) != ABSENT) return result;
1877 : }
1878 133 : isolate->ReportFailedAccessCheck(checked);
1879 133 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
1880 : return Just(ABSENT);
1881 : }
1882 :
1883 :
1884 : // static
1885 327 : bool JSObject::AllCanWrite(LookupIterator* it) {
1886 464 : for (; it->IsFound() && it->state() != LookupIterator::JSPROXY; it->Next()) {
1887 149 : if (it->state() == LookupIterator::ACCESSOR) {
1888 30 : Handle<Object> accessors = it->GetAccessors();
1889 30 : if (accessors->IsAccessorInfo()) {
1890 18 : if (AccessorInfo::cast(*accessors)->all_can_write()) return true;
1891 : }
1892 : }
1893 : }
1894 : return false;
1895 : }
1896 :
1897 :
1898 137 : Maybe<bool> JSObject::SetPropertyWithFailedAccessCheck(
1899 137 : LookupIterator* it, Handle<Object> value, ShouldThrow should_throw) {
1900 : Isolate* isolate = it->isolate();
1901 137 : Handle<JSObject> checked = it->GetHolder<JSObject>();
1902 : Handle<InterceptorInfo> interceptor =
1903 137 : it->GetInterceptorForFailedAccessCheck();
1904 137 : if (interceptor.is_null()) {
1905 95 : if (AllCanWrite(it)) {
1906 12 : return SetPropertyWithAccessor(it, value, should_throw);
1907 : }
1908 : } else {
1909 : Maybe<bool> result = SetPropertyWithInterceptorInternal(
1910 42 : it, interceptor, should_throw, value);
1911 84 : if (isolate->has_pending_exception()) return Nothing<bool>();
1912 28 : if (result.IsJust()) return result;
1913 : }
1914 83 : isolate->ReportFailedAccessCheck(checked);
1915 83 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1916 : return Just(true);
1917 : }
1918 :
1919 :
1920 407218 : void JSObject::SetNormalizedProperty(Handle<JSObject> object,
1921 : Handle<Name> name,
1922 : Handle<Object> value,
1923 : PropertyDetails details) {
1924 : DCHECK(!object->HasFastProperties());
1925 407218 : if (!name->IsUniqueName()) {
1926 : name = object->GetIsolate()->factory()->InternalizeString(
1927 0 : Handle<String>::cast(name));
1928 : }
1929 :
1930 407218 : if (object->IsJSGlobalObject()) {
1931 : Handle<GlobalDictionary> dictionary(object->global_dictionary());
1932 :
1933 9729 : int entry = dictionary->FindEntry(name);
1934 9729 : if (entry == GlobalDictionary::kNotFound) {
1935 : Isolate* isolate = object->GetIsolate();
1936 1150 : auto cell = isolate->factory()->NewPropertyCell();
1937 1150 : cell->set_value(*value);
1938 : auto cell_type = value->IsUndefined(isolate)
1939 : ? PropertyCellType::kUndefined
1940 1150 : : PropertyCellType::kConstant;
1941 : details = details.set_cell_type(cell_type);
1942 : value = cell;
1943 1150 : dictionary = GlobalDictionary::Add(dictionary, name, value, details);
1944 1150 : object->set_properties(*dictionary);
1945 : } else {
1946 : Handle<PropertyCell> cell =
1947 8579 : PropertyCell::PrepareForValue(dictionary, entry, value, details);
1948 8579 : cell->set_value(*value);
1949 : }
1950 : } else {
1951 : Handle<NameDictionary> dictionary(object->property_dictionary());
1952 :
1953 397489 : int entry = dictionary->FindEntry(name);
1954 397489 : if (entry == NameDictionary::kNotFound) {
1955 146558 : dictionary = NameDictionary::Add(dictionary, name, value, details);
1956 146558 : object->set_properties(*dictionary);
1957 : } else {
1958 : PropertyDetails original_details = dictionary->DetailsAt(entry);
1959 : int enumeration_index = original_details.dictionary_index();
1960 : DCHECK(enumeration_index > 0);
1961 : details = details.set_index(enumeration_index);
1962 : dictionary->SetEntry(entry, name, value, details);
1963 : }
1964 : }
1965 407218 : }
1966 :
1967 : // static
1968 2619 : Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate,
1969 : Handle<JSReceiver> object,
1970 : Handle<Object> proto) {
1971 2619 : PrototypeIterator iter(isolate, object, kStartAtReceiver);
1972 : while (true) {
1973 5804637 : if (!iter.AdvanceFollowingProxies()) return Nothing<bool>();
1974 5804468 : if (iter.IsAtEnd()) return Just(false);
1975 5803131 : if (PrototypeIterator::GetCurrent(iter).is_identical_to(proto)) {
1976 : return Just(true);
1977 : }
1978 : }
1979 : }
1980 :
1981 : namespace {
1982 :
1983 686 : bool HasExcludedProperty(
1984 : const ScopedVector<Handle<Object>>* excluded_properties,
1985 : Handle<Object> search_element) {
1986 : // TODO(gsathya): Change this to be a hashtable.
1987 2184 : for (int i = 0; i < excluded_properties->length(); i++) {
1988 1764 : if (search_element->SameValue(*excluded_properties->at(i))) {
1989 : return true;
1990 : }
1991 : }
1992 :
1993 : return false;
1994 : }
1995 :
1996 1306 : MUST_USE_RESULT Maybe<bool> FastAssign(
1997 : Handle<JSReceiver> target, Handle<Object> source,
1998 : const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) {
1999 : // Non-empty strings are the only non-JSReceivers that need to be handled
2000 : // explicitly by Object.assign.
2001 1306 : if (!source->IsJSReceiver()) {
2002 70 : return Just(!source->IsString() || String::cast(*source)->length() == 0);
2003 : }
2004 :
2005 : // If the target is deprecated, the object will be updated on first store. If
2006 : // the source for that store equals the target, this will invalidate the
2007 : // cached representation of the source. Preventively upgrade the target.
2008 : // Do this on each iteration since any property load could cause deprecation.
2009 1264 : if (target->map()->is_deprecated()) {
2010 30 : JSObject::MigrateInstance(Handle<JSObject>::cast(target));
2011 : }
2012 :
2013 : Isolate* isolate = target->GetIsolate();
2014 : Handle<Map> map(JSReceiver::cast(*source)->map(), isolate);
2015 :
2016 1264 : if (!map->IsJSObjectMap()) return Just(false);
2017 1124 : if (!map->OnlyHasSimpleProperties()) return Just(false);
2018 :
2019 : Handle<JSObject> from = Handle<JSObject>::cast(source);
2020 1011 : if (from->elements() != isolate->heap()->empty_fixed_array()) {
2021 : return Just(false);
2022 : }
2023 :
2024 : Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
2025 : int length = map->NumberOfOwnDescriptors();
2026 :
2027 : bool stable = true;
2028 :
2029 2071 : for (int i = 0; i < length; i++) {
2030 : Handle<Name> next_key(descriptors->GetKey(i), isolate);
2031 : Handle<Object> prop_value;
2032 : // Directly decode from the descriptor array if |from| did not change shape.
2033 1214 : if (stable) {
2034 1186 : PropertyDetails details = descriptors->GetDetails(i);
2035 1186 : if (!details.IsEnumerable()) continue;
2036 1068 : if (details.kind() == kData) {
2037 1068 : if (details.location() == kDescriptor) {
2038 0 : prop_value = handle(descriptors->GetValue(i), isolate);
2039 : } else {
2040 1068 : Representation representation = details.representation();
2041 1068 : FieldIndex index = FieldIndex::ForDescriptor(*map, i);
2042 1068 : prop_value = JSObject::FastPropertyAt(from, representation, index);
2043 : }
2044 : } else {
2045 0 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2046 : isolate, prop_value, JSReceiver::GetProperty(from, next_key),
2047 : Nothing<bool>());
2048 0 : stable = from->map() == *map;
2049 : }
2050 : } else {
2051 : // If the map did change, do a slower lookup. We are still guaranteed that
2052 : // the object has a simple shape, and that the key is a name.
2053 : LookupIterator it(from, next_key, from,
2054 28 : LookupIterator::OWN_SKIP_INTERCEPTOR);
2055 42 : if (!it.IsFound()) continue;
2056 : DCHECK(it.state() == LookupIterator::DATA ||
2057 : it.state() == LookupIterator::ACCESSOR);
2058 28 : if (!it.IsEnumerable()) continue;
2059 28 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2060 : isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
2061 : }
2062 :
2063 1082 : if (use_set) {
2064 284 : LookupIterator it(target, next_key, target);
2065 284 : bool call_to_js = it.IsFound() && it.state() != LookupIterator::DATA;
2066 : Maybe<bool> result = Object::SetProperty(
2067 284 : &it, prop_value, STRICT, Object::CERTAINLY_NOT_STORE_FROM_KEYED);
2068 284 : if (result.IsNothing()) return result;
2069 284 : if (stable && call_to_js) stable = from->map() == *map;
2070 : } else {
2071 2394 : if (excluded_properties != nullptr &&
2072 1694 : HasExcludedProperty(excluded_properties, next_key)) {
2073 154 : continue;
2074 : }
2075 :
2076 : // 4a ii 2. Perform ? CreateDataProperty(target, nextKey, propValue).
2077 : bool success;
2078 : LookupIterator it = LookupIterator::PropertyOrElement(
2079 644 : isolate, target, next_key, &success, LookupIterator::OWN);
2080 644 : CHECK(success);
2081 1288 : CHECK(
2082 : JSObject::CreateDataProperty(&it, prop_value, Object::THROW_ON_ERROR)
2083 : .FromJust());
2084 : }
2085 : }
2086 :
2087 : return Just(true);
2088 : }
2089 : } // namespace
2090 :
2091 : // static
2092 1306 : Maybe<bool> JSReceiver::SetOrCopyDataProperties(
2093 : Isolate* isolate, Handle<JSReceiver> target, Handle<Object> source,
2094 : const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) {
2095 : Maybe<bool> fast_assign =
2096 1306 : FastAssign(target, source, excluded_properties, use_set);
2097 1306 : if (fast_assign.IsNothing()) return Nothing<bool>();
2098 1264 : if (fast_assign.FromJust()) return Just(true);
2099 :
2100 786 : Handle<JSReceiver> from = Object::ToObject(isolate, source).ToHandleChecked();
2101 : // 3b. Let keys be ? from.[[OwnPropertyKeys]]().
2102 : Handle<FixedArray> keys;
2103 786 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2104 : isolate, keys,
2105 : KeyAccumulator::GetKeys(from, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES,
2106 : GetKeysConversion::kKeepNumbers),
2107 : Nothing<bool>());
2108 :
2109 : // 4. Repeat for each element nextKey of keys in List order,
2110 1403 : for (int j = 0; j < keys->length(); ++j) {
2111 : Handle<Object> next_key(keys->get(j), isolate);
2112 : // 4a i. Let desc be ? from.[[GetOwnProperty]](nextKey).
2113 : PropertyDescriptor desc;
2114 : Maybe<bool> found =
2115 589 : JSReceiver::GetOwnPropertyDescriptor(isolate, from, next_key, &desc);
2116 631 : if (found.IsNothing()) return Nothing<bool>();
2117 : // 4a ii. If desc is not undefined and desc.[[Enumerable]] is true, then
2118 1178 : if (found.FromJust() && desc.enumerable()) {
2119 : // 4a ii 1. Let propValue be ? Get(from, nextKey).
2120 : Handle<Object> prop_value;
2121 1108 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2122 : isolate, prop_value,
2123 : Runtime::GetObjectProperty(isolate, from, next_key), Nothing<bool>());
2124 :
2125 491 : if (use_set) {
2126 : // 4c ii 2. Let status be ? Set(to, nextKey, propValue, true).
2127 : Handle<Object> status;
2128 310 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2129 : isolate, status, Runtime::SetObjectProperty(
2130 : isolate, target, next_key, prop_value, STRICT),
2131 : Nothing<bool>());
2132 : } else {
2133 574 : if (excluded_properties != nullptr &&
2134 238 : HasExcludedProperty(excluded_properties, next_key)) {
2135 112 : continue;
2136 : }
2137 :
2138 : // 4a ii 2. Perform ! CreateDataProperty(target, nextKey, propValue).
2139 : bool success;
2140 : LookupIterator it = LookupIterator::PropertyOrElement(
2141 224 : isolate, target, next_key, &success, LookupIterator::OWN);
2142 224 : CHECK(success);
2143 448 : CHECK(JSObject::CreateDataProperty(&it, prop_value,
2144 : Object::THROW_ON_ERROR)
2145 : .FromJust());
2146 : }
2147 : }
2148 : }
2149 :
2150 : return Just(true);
2151 : }
2152 :
2153 281064 : Map* Object::GetPrototypeChainRootMap(Isolate* isolate) {
2154 : DisallowHeapAllocation no_alloc;
2155 250874 : if (IsSmi()) {
2156 : Context* native_context = isolate->context()->native_context();
2157 30190 : return native_context->number_function()->initial_map();
2158 : }
2159 :
2160 : // The object is either a number, a string, a symbol, a boolean, a real JS
2161 : // object, or a Harmony proxy.
2162 : HeapObject* heap_object = HeapObject::cast(this);
2163 220684 : return heap_object->map()->GetPrototypeChainRootMap(isolate);
2164 : }
2165 :
2166 9868298 : Map* Map::GetPrototypeChainRootMap(Isolate* isolate) {
2167 : DisallowHeapAllocation no_alloc;
2168 9493742 : if (IsJSReceiverMap()) {
2169 : return this;
2170 : }
2171 : int constructor_function_index = GetConstructorFunctionIndex();
2172 374570 : if (constructor_function_index != Map::kNoConstructorFunctionIndex) {
2173 : Context* native_context = isolate->context()->native_context();
2174 : JSFunction* constructor_function =
2175 : JSFunction::cast(native_context->get(constructor_function_index));
2176 374556 : return constructor_function->initial_map();
2177 : }
2178 28 : return isolate->heap()->null_value()->map();
2179 : }
2180 :
2181 : namespace {
2182 :
2183 : // Returns a non-SMI for JSObjects, but returns the hash code for simple
2184 : // objects. This avoids a double lookup in the cases where we know we will
2185 : // add the hash to the JSObject if it does not already exist.
2186 107544730 : Object* GetSimpleHash(Object* object) {
2187 : // The object is either a Smi, a HeapNumber, a name, an odd-ball, a real JS
2188 : // object, or a Harmony proxy.
2189 107544730 : if (object->IsSmi()) {
2190 : uint32_t hash =
2191 1079997 : ComputeIntegerHash(Smi::cast(object)->value(), kZeroHashSeed);
2192 2159994 : return Smi::FromInt(hash & Smi::kMaxValue);
2193 : }
2194 106464735 : if (object->IsHeapNumber()) {
2195 : double num = HeapNumber::cast(object)->value();
2196 8922 : if (std::isnan(num)) return Smi::FromInt(Smi::kMaxValue);
2197 8217 : if (i::IsMinusZero(num)) num = 0;
2198 8217 : if (IsSmiDouble(num)) {
2199 600 : return Smi::FromInt(FastD2I(num))->GetHash();
2200 : }
2201 : uint32_t hash = ComputeLongHash(double_to_uint64(num));
2202 15234 : return Smi::FromInt(hash & Smi::kMaxValue);
2203 : }
2204 106455805 : if (object->IsName()) {
2205 : uint32_t hash = Name::cast(object)->Hash();
2206 212862188 : return Smi::FromInt(hash);
2207 : }
2208 24711 : if (object->IsOddball()) {
2209 : uint32_t hash = Oddball::cast(object)->to_string()->Hash();
2210 4396 : return Smi::FromInt(hash);
2211 : }
2212 : DCHECK(object->IsJSReceiver());
2213 : // Simply return the receiver as it is guaranteed to not be a SMI.
2214 : return object;
2215 : }
2216 :
2217 : } // namespace
2218 :
2219 12997117 : Object* Object::GetHash() {
2220 12997117 : Object* hash = GetSimpleHash(this);
2221 12997118 : if (hash->IsSmi()) return hash;
2222 :
2223 : DisallowHeapAllocation no_gc;
2224 : DCHECK(IsJSReceiver());
2225 : JSReceiver* receiver = JSReceiver::cast(this);
2226 : Isolate* isolate = receiver->GetIsolate();
2227 16991 : return JSReceiver::GetIdentityHash(isolate, handle(receiver, isolate));
2228 : }
2229 :
2230 94547635 : Smi* Object::GetOrCreateHash(Isolate* isolate, Handle<Object> object) {
2231 94547635 : Object* hash = GetSimpleHash(*object);
2232 94547629 : if (hash->IsSmi()) return Smi::cast(hash);
2233 :
2234 : DCHECK(object->IsJSReceiver());
2235 : return JSReceiver::GetOrCreateIdentityHash(isolate,
2236 5522 : Handle<JSReceiver>::cast(object));
2237 : }
2238 :
2239 :
2240 1906031 : bool Object::SameValue(Object* other) {
2241 1906031 : if (other == this) return true;
2242 :
2243 : // The object is either a number, a name, an odd-ball,
2244 : // a real JS object, or a Harmony proxy.
2245 1582761 : if (IsNumber() && other->IsNumber()) {
2246 : double this_value = Number();
2247 : double other_value = other->Number();
2248 : // SameValue(NaN, NaN) is true.
2249 32466 : if (this_value != other_value) {
2250 29029 : return std::isnan(this_value) && std::isnan(other_value);
2251 : }
2252 : // SameValue(0.0, -0.0) is false.
2253 3437 : return (std::signbit(this_value) == std::signbit(other_value));
2254 : }
2255 2925314 : if (IsString() && other->IsString()) {
2256 1420853 : return String::cast(this)->Equals(String::cast(other));
2257 : }
2258 : return false;
2259 : }
2260 :
2261 :
2262 50536535 : bool Object::SameValueZero(Object* other) {
2263 50536535 : if (other == this) return true;
2264 :
2265 : // The object is either a number, a name, an odd-ball,
2266 : // a real JS object, or a Harmony proxy.
2267 50948206 : if (IsNumber() && other->IsNumber()) {
2268 : double this_value = Number();
2269 : double other_value = other->Number();
2270 : // +0 == -0 is true
2271 410323 : return this_value == other_value ||
2272 17 : (std::isnan(this_value) && std::isnan(other_value));
2273 : }
2274 100234702 : if (IsString() && other->IsString()) {
2275 50109739 : return String::cast(this)->Equals(String::cast(other));
2276 : }
2277 : return false;
2278 : }
2279 :
2280 :
2281 71765 : MaybeHandle<Object> Object::ArraySpeciesConstructor(
2282 : Isolate* isolate, Handle<Object> original_array) {
2283 71765 : Handle<Object> default_species = isolate->array_function();
2284 138462 : if (original_array->IsJSArray() &&
2285 203551 : Handle<JSArray>::cast(original_array)->HasArrayPrototype(isolate) &&
2286 : isolate->IsArraySpeciesLookupChainIntact()) {
2287 : return default_species;
2288 : }
2289 : Handle<Object> constructor = isolate->factory()->undefined_value();
2290 7541 : Maybe<bool> is_array = Object::IsArray(original_array);
2291 7541 : MAYBE_RETURN_NULL(is_array);
2292 7541 : if (is_array.FromJust()) {
2293 5088 : ASSIGN_RETURN_ON_EXCEPTION(
2294 : isolate, constructor,
2295 : Object::GetProperty(original_array,
2296 : isolate->factory()->constructor_string()),
2297 : Object);
2298 2530 : if (constructor->IsConstructor()) {
2299 : Handle<Context> constructor_context;
2300 4572 : ASSIGN_RETURN_ON_EXCEPTION(
2301 : isolate, constructor_context,
2302 : JSReceiver::GetFunctionRealm(Handle<JSReceiver>::cast(constructor)),
2303 : Object);
2304 4600 : if (*constructor_context != *isolate->native_context() &&
2305 : *constructor == constructor_context->array_function()) {
2306 : constructor = isolate->factory()->undefined_value();
2307 : }
2308 : }
2309 2530 : if (constructor->IsJSReceiver()) {
2310 4516 : ASSIGN_RETURN_ON_EXCEPTION(
2311 : isolate, constructor,
2312 : JSReceiver::GetProperty(Handle<JSReceiver>::cast(constructor),
2313 : isolate->factory()->species_symbol()),
2314 : Object);
2315 2244 : if (constructor->IsNull(isolate)) {
2316 : constructor = isolate->factory()->undefined_value();
2317 : }
2318 : }
2319 : }
2320 7513 : if (constructor->IsUndefined(isolate)) {
2321 : return default_species;
2322 : } else {
2323 2200 : if (!constructor->IsConstructor()) {
2324 0 : THROW_NEW_ERROR(isolate,
2325 : NewTypeError(MessageTemplate::kSpeciesNotConstructor),
2326 : Object);
2327 : }
2328 : return constructor;
2329 : }
2330 : }
2331 :
2332 : // ES6 section 7.3.20 SpeciesConstructor ( O, defaultConstructor )
2333 14360 : MUST_USE_RESULT MaybeHandle<Object> Object::SpeciesConstructor(
2334 : Isolate* isolate, Handle<JSReceiver> recv,
2335 : Handle<JSFunction> default_ctor) {
2336 : Handle<Object> ctor_obj;
2337 28720 : ASSIGN_RETURN_ON_EXCEPTION(
2338 : isolate, ctor_obj,
2339 : JSObject::GetProperty(recv, isolate->factory()->constructor_string()),
2340 : Object);
2341 :
2342 14360 : if (ctor_obj->IsUndefined(isolate)) return default_ctor;
2343 :
2344 14346 : if (!ctor_obj->IsJSReceiver()) {
2345 0 : THROW_NEW_ERROR(isolate,
2346 : NewTypeError(MessageTemplate::kConstructorNotReceiver),
2347 : Object);
2348 : }
2349 :
2350 14346 : Handle<JSReceiver> ctor = Handle<JSReceiver>::cast(ctor_obj);
2351 :
2352 : Handle<Object> species;
2353 28692 : ASSIGN_RETURN_ON_EXCEPTION(
2354 : isolate, species,
2355 : JSObject::GetProperty(ctor, isolate->factory()->species_symbol()),
2356 : Object);
2357 :
2358 14346 : if (species->IsNullOrUndefined(isolate)) {
2359 : return default_ctor;
2360 : }
2361 :
2362 14346 : if (species->IsConstructor()) return species;
2363 :
2364 0 : THROW_NEW_ERROR(
2365 : isolate, NewTypeError(MessageTemplate::kSpeciesNotConstructor), Object);
2366 : }
2367 :
2368 35238 : bool Object::IterationHasObservableEffects() {
2369 : // Check that this object is an array.
2370 35238 : if (!IsJSArray()) return true;
2371 : JSArray* array = JSArray::cast(this);
2372 : Isolate* isolate = array->GetIsolate();
2373 :
2374 : // Check that we have the original ArrayPrototype.
2375 35238 : if (!array->map()->prototype()->IsJSObject()) return true;
2376 : JSObject* array_proto = JSObject::cast(array->map()->prototype());
2377 35223 : if (!isolate->is_initial_array_prototype(array_proto)) return true;
2378 :
2379 : // Check that the ArrayPrototype hasn't been modified in a way that would
2380 : // affect iteration.
2381 34971 : if (!isolate->IsArrayIteratorLookupChainIntact()) return true;
2382 :
2383 : // Check that the map of the initial array iterator hasn't changed.
2384 65490 : Map* iterator_map = isolate->initial_array_iterator_prototype()->map();
2385 32745 : if (!isolate->is_initial_array_iterator_prototype_map(iterator_map)) {
2386 : return true;
2387 : }
2388 :
2389 : // For FastPacked kinds, iteration will have the same effect as simply
2390 : // accessing each property in order.
2391 : ElementsKind array_kind = array->GetElementsKind();
2392 32745 : if (IsFastPackedElementsKind(array_kind)) return false;
2393 :
2394 : // For FastHoley kinds, an element access on a hole would cause a lookup on
2395 : // the prototype. This could have different results if the prototype has been
2396 : // changed.
2397 12300 : if (IsFastHoleyElementsKind(array_kind) &&
2398 6150 : isolate->IsFastArrayConstructorPrototypeChainIntact()) {
2399 : return false;
2400 : }
2401 242 : return true;
2402 : }
2403 :
2404 14 : void Object::ShortPrint(FILE* out) {
2405 14 : OFStream os(out);
2406 14 : os << Brief(this);
2407 14 : }
2408 :
2409 :
2410 260 : void Object::ShortPrint(StringStream* accumulator) {
2411 260 : std::ostringstream os;
2412 260 : os << Brief(this);
2413 520 : accumulator->Add(os.str().c_str());
2414 260 : }
2415 :
2416 :
2417 0 : void Object::ShortPrint(std::ostream& os) { os << Brief(this); }
2418 :
2419 :
2420 1714 : std::ostream& operator<<(std::ostream& os, const Brief& v) {
2421 3428 : if (v.value->IsSmi()) {
2422 : Smi::cast(v.value)->SmiPrint(os);
2423 : } else {
2424 : // TODO(svenpanne) Const-correct HeapObjectShortPrint!
2425 : HeapObject* obj = const_cast<HeapObject*>(HeapObject::cast(v.value));
2426 1356 : obj->HeapObjectShortPrint(os);
2427 : }
2428 1714 : return os;
2429 : }
2430 :
2431 189 : void Smi::SmiPrint(std::ostream& os) const { // NOLINT
2432 547 : os << value();
2433 189 : }
2434 :
2435 6108158 : Handle<String> String::SlowFlatten(Handle<ConsString> cons,
2436 : PretenureFlag pretenure) {
2437 : DCHECK(cons->second()->length() != 0);
2438 :
2439 : // TurboFan can create cons strings with empty first parts.
2440 12216329 : while (cons->first()->length() == 0) {
2441 : // We do not want to call this function recursively. Therefore we call
2442 : // String::Flatten only in those cases where String::SlowFlatten is not
2443 : // called again.
2444 60 : if (cons->second()->IsConsString() && !cons->second()->IsFlat()) {
2445 : cons = handle(ConsString::cast(cons->second()));
2446 : } else {
2447 34 : return String::Flatten(handle(cons->second()));
2448 : }
2449 : }
2450 :
2451 : DCHECK(AllowHeapAllocation::IsAllowed());
2452 : Isolate* isolate = cons->GetIsolate();
2453 : int length = cons->length();
2454 : PretenureFlag tenure = isolate->heap()->InNewSpace(*cons) ? pretenure
2455 6108124 : : TENURED;
2456 : Handle<SeqString> result;
2457 6108124 : if (cons->IsOneByteRepresentation()) {
2458 : Handle<SeqOneByteString> flat = isolate->factory()->NewRawOneByteString(
2459 11746354 : length, tenure).ToHandleChecked();
2460 : DisallowHeapAllocation no_gc;
2461 11746354 : WriteToFlat(*cons, flat->GetChars(), 0, length);
2462 : result = flat;
2463 : } else {
2464 : Handle<SeqTwoByteString> flat = isolate->factory()->NewRawTwoByteString(
2465 469894 : length, tenure).ToHandleChecked();
2466 : DisallowHeapAllocation no_gc;
2467 469894 : WriteToFlat(*cons, flat->GetChars(), 0, length);
2468 : result = flat;
2469 : }
2470 6108124 : cons->set_first(*result);
2471 12216248 : cons->set_second(isolate->heap()->empty_string());
2472 : DCHECK(result->IsFlat());
2473 6108124 : return result;
2474 : }
2475 :
2476 :
2477 :
2478 468 : bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
2479 : // Externalizing twice leaks the external resource, so it's
2480 : // prohibited by the API.
2481 : DCHECK(!this->IsExternalString());
2482 : DCHECK(!resource->IsCompressible());
2483 : #ifdef ENABLE_SLOW_DCHECKS
2484 : if (FLAG_enable_slow_asserts) {
2485 : // Assert that the resource and the string are equivalent.
2486 : DCHECK(static_cast<size_t>(this->length()) == resource->length());
2487 : ScopedVector<uc16> smart_chars(this->length());
2488 : String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2489 : DCHECK(memcmp(smart_chars.start(),
2490 : resource->data(),
2491 : resource->length() * sizeof(smart_chars[0])) == 0);
2492 : }
2493 : #endif // DEBUG
2494 468 : int size = this->Size(); // Byte size of the original string.
2495 : // Abort if size does not allow in-place conversion.
2496 468 : if (size < ExternalString::kShortSize) return false;
2497 274 : Heap* heap = GetHeap();
2498 : bool is_one_byte = this->IsOneByteRepresentation();
2499 : bool is_internalized = this->IsInternalizedString();
2500 : bool has_pointers = StringShape(this).IsIndirect();
2501 :
2502 : // Morph the string to an external string by replacing the map and
2503 : // reinitializing the fields. This won't work if the space the existing
2504 : // string occupies is too small for a regular external string.
2505 : // Instead, we resort to a short external string instead, omitting
2506 : // the field caching the address of the backing store. When we encounter
2507 : // short external strings in generated code, we need to bailout to runtime.
2508 : Map* new_map;
2509 468 : if (size < ExternalString::kSize) {
2510 : new_map = is_internalized
2511 : ? (is_one_byte
2512 : ? heap->short_external_internalized_string_with_one_byte_data_map()
2513 : : heap->short_external_internalized_string_map())
2514 : : (is_one_byte ? heap->short_external_string_with_one_byte_data_map()
2515 327 : : heap->short_external_string_map());
2516 : } else {
2517 : new_map = is_internalized
2518 : ? (is_one_byte
2519 : ? heap->external_internalized_string_with_one_byte_data_map()
2520 : : heap->external_internalized_string_map())
2521 : : (is_one_byte ? heap->external_string_with_one_byte_data_map()
2522 543 : : heap->external_string_map());
2523 : }
2524 :
2525 : // Byte size of the external String object.
2526 468 : int new_size = this->SizeFromMap(new_map);
2527 468 : heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
2528 936 : ClearRecordedSlots::kNo);
2529 468 : if (has_pointers) {
2530 88 : heap->ClearRecordedSlotRange(this->address(), this->address() + new_size);
2531 : }
2532 :
2533 : // We are storing the new map using release store after creating a filler for
2534 : // the left-over space to avoid races with the sweeper thread.
2535 468 : this->synchronized_set_map(new_map);
2536 :
2537 : ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
2538 : self->set_resource(resource);
2539 468 : if (is_internalized) self->Hash(); // Force regeneration of the hash value.
2540 :
2541 468 : heap->AdjustLiveBytes(this, new_size - size);
2542 468 : return true;
2543 : }
2544 :
2545 :
2546 458 : bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
2547 : // Externalizing twice leaks the external resource, so it's
2548 : // prohibited by the API.
2549 : DCHECK(!this->IsExternalString());
2550 : DCHECK(!resource->IsCompressible());
2551 : #ifdef ENABLE_SLOW_DCHECKS
2552 : if (FLAG_enable_slow_asserts) {
2553 : // Assert that the resource and the string are equivalent.
2554 : DCHECK(static_cast<size_t>(this->length()) == resource->length());
2555 : if (this->IsTwoByteRepresentation()) {
2556 : ScopedVector<uint16_t> smart_chars(this->length());
2557 : String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2558 : DCHECK(String::IsOneByte(smart_chars.start(), this->length()));
2559 : }
2560 : ScopedVector<char> smart_chars(this->length());
2561 : String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2562 : DCHECK(memcmp(smart_chars.start(),
2563 : resource->data(),
2564 : resource->length() * sizeof(smart_chars[0])) == 0);
2565 : }
2566 : #endif // DEBUG
2567 458 : int size = this->Size(); // Byte size of the original string.
2568 : // Abort if size does not allow in-place conversion.
2569 458 : if (size < ExternalString::kShortSize) return false;
2570 52 : Heap* heap = GetHeap();
2571 : bool is_internalized = this->IsInternalizedString();
2572 : bool has_pointers = StringShape(this).IsIndirect();
2573 :
2574 : // Morph the string to an external string by replacing the map and
2575 : // reinitializing the fields. This won't work if the space the existing
2576 : // string occupies is too small for a regular external string.
2577 : // Instead, we resort to a short external string instead, omitting
2578 : // the field caching the address of the backing store. When we encounter
2579 : // short external strings in generated code, we need to bailout to runtime.
2580 : Map* new_map;
2581 458 : if (size < ExternalString::kSize) {
2582 : new_map = is_internalized
2583 : ? heap->short_external_one_byte_internalized_string_map()
2584 13 : : heap->short_external_one_byte_string_map();
2585 : } else {
2586 : new_map = is_internalized
2587 : ? heap->external_one_byte_internalized_string_map()
2588 445 : : heap->external_one_byte_string_map();
2589 : }
2590 :
2591 : // Byte size of the external String object.
2592 458 : int new_size = this->SizeFromMap(new_map);
2593 458 : heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
2594 916 : ClearRecordedSlots::kNo);
2595 458 : if (has_pointers) {
2596 394 : heap->ClearRecordedSlotRange(this->address(), this->address() + new_size);
2597 : }
2598 :
2599 : // We are storing the new map using release store after creating a filler for
2600 : // the left-over space to avoid races with the sweeper thread.
2601 458 : this->synchronized_set_map(new_map);
2602 :
2603 : ExternalOneByteString* self = ExternalOneByteString::cast(this);
2604 : self->set_resource(resource);
2605 458 : if (is_internalized) self->Hash(); // Force regeneration of the hash value.
2606 :
2607 458 : heap->AdjustLiveBytes(this, new_size - size);
2608 458 : return true;
2609 : }
2610 :
2611 94 : void String::StringShortPrint(StringStream* accumulator, bool show_details) {
2612 : int len = length();
2613 94 : if (len > kMaxShortPrintLength) {
2614 0 : accumulator->Add("<Very long string[%u]>", len);
2615 0 : return;
2616 : }
2617 :
2618 94 : if (!LooksValid()) {
2619 0 : accumulator->Add("<Invalid String>");
2620 0 : return;
2621 : }
2622 :
2623 : StringCharacterStream stream(this);
2624 :
2625 : bool truncated = false;
2626 94 : if (len > kMaxShortPrintLength) {
2627 : len = kMaxShortPrintLength;
2628 : truncated = true;
2629 : }
2630 : bool one_byte = true;
2631 782 : for (int i = 0; i < len; i++) {
2632 688 : uint16_t c = stream.GetNext();
2633 :
2634 688 : if (c < 32 || c >= 127) {
2635 : one_byte = false;
2636 : }
2637 : }
2638 94 : stream.Reset(this);
2639 94 : if (one_byte) {
2640 171 : if (show_details) accumulator->Add("<String[%u]: ", length());
2641 688 : for (int i = 0; i < len; i++) {
2642 688 : accumulator->Put(static_cast<char>(stream.GetNext()));
2643 : }
2644 94 : if (show_details) accumulator->Put('>');
2645 : } else {
2646 : // Backslash indicates that the string contains control
2647 : // characters and that backslashes are therefore escaped.
2648 0 : if (show_details) accumulator->Add("<String[%u]\\: ", length());
2649 0 : for (int i = 0; i < len; i++) {
2650 0 : uint16_t c = stream.GetNext();
2651 0 : if (c == '\n') {
2652 0 : accumulator->Add("\\n");
2653 0 : } else if (c == '\r') {
2654 0 : accumulator->Add("\\r");
2655 0 : } else if (c == '\\') {
2656 0 : accumulator->Add("\\\\");
2657 0 : } else if (c < 32 || c > 126) {
2658 0 : accumulator->Add("\\x%02x", c);
2659 : } else {
2660 0 : accumulator->Put(static_cast<char>(c));
2661 : }
2662 : }
2663 0 : if (truncated) {
2664 0 : accumulator->Put('.');
2665 0 : accumulator->Put('.');
2666 0 : accumulator->Put('.');
2667 : }
2668 0 : if (show_details) accumulator->Put('>');
2669 : }
2670 : return;
2671 : }
2672 :
2673 :
2674 28 : void String::PrintUC16(std::ostream& os, int start, int end) { // NOLINT
2675 28 : if (end < 0) end = length();
2676 : StringCharacterStream stream(this, start);
2677 560 : for (int i = start; i < end && stream.HasMore(); i++) {
2678 1064 : os << AsUC16(stream.GetNext());
2679 : }
2680 28 : }
2681 :
2682 :
2683 840 : void JSObject::JSObjectShortPrint(StringStream* accumulator) {
2684 840 : switch (map()->instance_type()) {
2685 : case JS_ARRAY_TYPE: {
2686 : double length = JSArray::cast(this)->length()->IsUndefined(GetIsolate())
2687 : ? 0
2688 201 : : JSArray::cast(this)->length()->Number();
2689 201 : accumulator->Add("<JSArray[%u]>", static_cast<uint32_t>(length));
2690 201 : break;
2691 : }
2692 : case JS_BOUND_FUNCTION_TYPE: {
2693 : JSBoundFunction* bound_function = JSBoundFunction::cast(this);
2694 0 : accumulator->Add("<JSBoundFunction");
2695 : accumulator->Add(
2696 : " (BoundTargetFunction %p)>",
2697 0 : reinterpret_cast<void*>(bound_function->bound_target_function()));
2698 0 : break;
2699 : }
2700 : case JS_WEAK_MAP_TYPE: {
2701 0 : accumulator->Add("<JSWeakMap>");
2702 0 : break;
2703 : }
2704 : case JS_WEAK_SET_TYPE: {
2705 0 : accumulator->Add("<JSWeakSet>");
2706 0 : break;
2707 : }
2708 : case JS_REGEXP_TYPE: {
2709 30 : accumulator->Add("<JSRegExp");
2710 : JSRegExp* regexp = JSRegExp::cast(this);
2711 30 : if (regexp->source()->IsString()) {
2712 30 : accumulator->Add(" ");
2713 30 : String::cast(regexp->source())->StringShortPrint(accumulator);
2714 : }
2715 30 : accumulator->Add(">");
2716 :
2717 30 : break;
2718 : }
2719 : case JS_FUNCTION_TYPE: {
2720 : JSFunction* function = JSFunction::cast(this);
2721 73 : Object* fun_name = function->shared()->DebugName();
2722 : bool printed = false;
2723 73 : if (fun_name->IsString()) {
2724 : String* str = String::cast(fun_name);
2725 73 : if (str->length() > 0) {
2726 73 : accumulator->Add("<JSFunction ");
2727 73 : accumulator->Put(str);
2728 : printed = true;
2729 : }
2730 : }
2731 73 : if (!printed) {
2732 0 : accumulator->Add("<JSFunction");
2733 : }
2734 73 : if (FLAG_trace_file_names) {
2735 : Object* source_name =
2736 : Script::cast(function->shared()->script())->name();
2737 0 : if (source_name->IsString()) {
2738 : String* str = String::cast(source_name);
2739 0 : if (str->length() > 0) {
2740 0 : accumulator->Add(" <");
2741 0 : accumulator->Put(str);
2742 0 : accumulator->Add(">");
2743 : }
2744 : }
2745 : }
2746 : accumulator->Add(" (sfi = %p)",
2747 73 : reinterpret_cast<void*>(function->shared()));
2748 73 : accumulator->Put('>');
2749 73 : break;
2750 : }
2751 : case JS_GENERATOR_OBJECT_TYPE: {
2752 0 : accumulator->Add("<JSGenerator>");
2753 0 : break;
2754 : }
2755 : case JS_ASYNC_GENERATOR_OBJECT_TYPE: {
2756 0 : accumulator->Add("<JS AsyncGenerator>");
2757 0 : break;
2758 : }
2759 :
2760 : // All other JSObjects are rather similar to each other (JSObject,
2761 : // JSGlobalProxy, JSGlobalObject, JSUndetectable, JSValue).
2762 : default: {
2763 : Map* map_of_this = map();
2764 : Heap* heap = GetHeap();
2765 536 : Object* constructor = map_of_this->GetConstructor();
2766 : bool printed = false;
2767 1072 : if (constructor->IsHeapObject() &&
2768 536 : !heap->Contains(HeapObject::cast(constructor))) {
2769 0 : accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
2770 : } else {
2771 : bool global_object = IsJSGlobalProxy();
2772 536 : if (constructor->IsJSFunction()) {
2773 536 : if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
2774 0 : accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
2775 : } else {
2776 : Object* constructor_name =
2777 : JSFunction::cast(constructor)->shared()->name();
2778 536 : if (constructor_name->IsString()) {
2779 : String* str = String::cast(constructor_name);
2780 536 : if (str->length() > 0) {
2781 472 : accumulator->Add(global_object ? "<GlobalObject " : "<");
2782 472 : accumulator->Put(str);
2783 : accumulator->Add(
2784 : " %smap = %p",
2785 : map_of_this->is_deprecated() ? "deprecated-" : "",
2786 472 : map_of_this);
2787 : printed = true;
2788 : }
2789 : }
2790 : }
2791 0 : } else if (constructor->IsFunctionTemplateInfo()) {
2792 0 : accumulator->Add(global_object ? "<RemoteObject>" : "<RemoteObject>");
2793 : printed = true;
2794 : }
2795 536 : if (!printed) {
2796 64 : accumulator->Add("<JS%sObject", global_object ? "Global " : "");
2797 : }
2798 : }
2799 536 : if (IsJSValue()) {
2800 15 : accumulator->Add(" value = ");
2801 15 : JSValue::cast(this)->value()->ShortPrint(accumulator);
2802 : }
2803 536 : accumulator->Put('>');
2804 536 : break;
2805 : }
2806 : }
2807 840 : }
2808 :
2809 :
2810 0 : void JSObject::PrintElementsTransition(
2811 : FILE* file, Handle<JSObject> object,
2812 : ElementsKind from_kind, Handle<FixedArrayBase> from_elements,
2813 : ElementsKind to_kind, Handle<FixedArrayBase> to_elements) {
2814 0 : if (from_kind != to_kind) {
2815 0 : OFStream os(file);
2816 0 : os << "elements transition [" << ElementsKindToString(from_kind) << " -> "
2817 0 : << ElementsKindToString(to_kind) << "] in ";
2818 0 : JavaScriptFrame::PrintTop(object->GetIsolate(), file, false, true);
2819 0 : PrintF(file, " for ");
2820 0 : object->ShortPrint(file);
2821 0 : PrintF(file, " from ");
2822 0 : from_elements->ShortPrint(file);
2823 0 : PrintF(file, " to ");
2824 0 : to_elements->ShortPrint(file);
2825 0 : PrintF(file, "\n");
2826 : }
2827 0 : }
2828 :
2829 :
2830 : // static
2831 217515 : MaybeHandle<JSFunction> Map::GetConstructorFunction(
2832 : Handle<Map> map, Handle<Context> native_context) {
2833 217515 : if (map->IsPrimitiveMap()) {
2834 : int const constructor_function_index = map->GetConstructorFunctionIndex();
2835 35986 : if (constructor_function_index != kNoConstructorFunctionIndex) {
2836 : return handle(
2837 : JSFunction::cast(native_context->get(constructor_function_index)));
2838 : }
2839 : }
2840 : return MaybeHandle<JSFunction>();
2841 : }
2842 :
2843 :
2844 0 : void Map::PrintReconfiguration(FILE* file, int modify_index, PropertyKind kind,
2845 : PropertyAttributes attributes) {
2846 0 : OFStream os(file);
2847 0 : os << "[reconfiguring]";
2848 : Name* name = instance_descriptors()->GetKey(modify_index);
2849 0 : if (name->IsString()) {
2850 0 : String::cast(name)->PrintOn(file);
2851 : } else {
2852 0 : os << "{symbol " << static_cast<void*>(name) << "}";
2853 : }
2854 0 : os << ": " << (kind == kData ? "kData" : "ACCESSORS") << ", attrs: ";
2855 0 : os << attributes << " [";
2856 0 : JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
2857 0 : os << "]\n";
2858 0 : }
2859 :
2860 0 : void Map::PrintGeneralization(
2861 : FILE* file, const char* reason, int modify_index, int split,
2862 : int descriptors, bool descriptor_to_field,
2863 : Representation old_representation, Representation new_representation,
2864 : MaybeHandle<FieldType> old_field_type, MaybeHandle<Object> old_value,
2865 : MaybeHandle<FieldType> new_field_type, MaybeHandle<Object> new_value) {
2866 0 : OFStream os(file);
2867 0 : os << "[generalizing]";
2868 : Name* name = instance_descriptors()->GetKey(modify_index);
2869 0 : if (name->IsString()) {
2870 0 : String::cast(name)->PrintOn(file);
2871 : } else {
2872 0 : os << "{symbol " << static_cast<void*>(name) << "}";
2873 : }
2874 0 : os << ":";
2875 0 : if (descriptor_to_field) {
2876 0 : os << "c";
2877 : } else {
2878 0 : os << old_representation.Mnemonic() << "{";
2879 0 : if (old_field_type.is_null()) {
2880 0 : os << Brief(*(old_value.ToHandleChecked()));
2881 : } else {
2882 0 : old_field_type.ToHandleChecked()->PrintTo(os);
2883 : }
2884 0 : os << "}";
2885 : }
2886 0 : os << "->" << new_representation.Mnemonic() << "{";
2887 0 : if (new_field_type.is_null()) {
2888 0 : os << Brief(*(new_value.ToHandleChecked()));
2889 : } else {
2890 0 : new_field_type.ToHandleChecked()->PrintTo(os);
2891 : }
2892 0 : os << "} (";
2893 0 : if (strlen(reason) > 0) {
2894 0 : os << reason;
2895 : } else {
2896 0 : os << "+" << (descriptors - split) << " maps";
2897 : }
2898 0 : os << ") [";
2899 0 : JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
2900 0 : os << "]\n";
2901 0 : }
2902 :
2903 :
2904 0 : void JSObject::PrintInstanceMigration(FILE* file,
2905 : Map* original_map,
2906 : Map* new_map) {
2907 0 : if (new_map->is_dictionary_map()) {
2908 0 : PrintF(file, "[migrating to slow]\n");
2909 0 : return;
2910 : }
2911 0 : PrintF(file, "[migrating]");
2912 : DescriptorArray* o = original_map->instance_descriptors();
2913 : DescriptorArray* n = new_map->instance_descriptors();
2914 0 : for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) {
2915 0 : Representation o_r = o->GetDetails(i).representation();
2916 0 : Representation n_r = n->GetDetails(i).representation();
2917 0 : if (!o_r.Equals(n_r)) {
2918 0 : String::cast(o->GetKey(i))->PrintOn(file);
2919 0 : PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic());
2920 0 : } else if (o->GetDetails(i).location() == kDescriptor &&
2921 0 : n->GetDetails(i).location() == kField) {
2922 : Name* name = o->GetKey(i);
2923 0 : if (name->IsString()) {
2924 0 : String::cast(name)->PrintOn(file);
2925 : } else {
2926 0 : PrintF(file, "{symbol %p}", static_cast<void*>(name));
2927 : }
2928 0 : PrintF(file, " ");
2929 : }
2930 : }
2931 0 : if (original_map->elements_kind() != new_map->elements_kind()) {
2932 : PrintF(file, "elements_kind[%i->%i]", original_map->elements_kind(),
2933 0 : new_map->elements_kind());
2934 : }
2935 0 : PrintF(file, "\n");
2936 : }
2937 :
2938 :
2939 1356 : void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
2940 : Heap* heap = GetHeap();
2941 : Isolate* isolate = heap->isolate();
2942 1356 : if (!heap->Contains(this)) {
2943 0 : os << "!!!INVALID POINTER!!!";
2944 0 : return;
2945 : }
2946 1356 : if (!heap->Contains(map())) {
2947 0 : os << "!!!INVALID MAP!!!";
2948 0 : return;
2949 : }
2950 :
2951 1356 : os << this << " ";
2952 :
2953 1356 : if (IsString()) {
2954 : HeapStringAllocator allocator;
2955 : StringStream accumulator(&allocator);
2956 47 : String::cast(this)->StringShortPrint(&accumulator);
2957 141 : os << accumulator.ToCString().get();
2958 : return;
2959 : }
2960 1309 : if (IsJSObject()) {
2961 : HeapStringAllocator allocator;
2962 : StringStream accumulator(&allocator);
2963 840 : JSObject::cast(this)->JSObjectShortPrint(&accumulator);
2964 2520 : os << accumulator.ToCString().get();
2965 : return;
2966 : }
2967 469 : switch (map()->instance_type()) {
2968 : case MAP_TYPE:
2969 0 : os << "<Map(" << ElementsKindToString(Map::cast(this)->elements_kind())
2970 0 : << ")>";
2971 0 : break;
2972 : case FIXED_ARRAY_TYPE:
2973 0 : os << "<FixedArray[" << FixedArray::cast(this)->length() << "]>";
2974 0 : break;
2975 : case FIXED_DOUBLE_ARRAY_TYPE:
2976 0 : os << "<FixedDoubleArray[" << FixedDoubleArray::cast(this)->length()
2977 0 : << "]>";
2978 0 : break;
2979 : case BYTE_ARRAY_TYPE:
2980 0 : os << "<ByteArray[" << ByteArray::cast(this)->length() << "]>";
2981 0 : break;
2982 : case BYTECODE_ARRAY_TYPE:
2983 0 : os << "<BytecodeArray[" << BytecodeArray::cast(this)->length() << "]>";
2984 0 : break;
2985 : case TRANSITION_ARRAY_TYPE:
2986 0 : os << "<TransitionArray[" << TransitionArray::cast(this)->length()
2987 0 : << "]>";
2988 0 : break;
2989 : case FREE_SPACE_TYPE:
2990 0 : os << "<FreeSpace[" << FreeSpace::cast(this)->size() << "]>";
2991 0 : break;
2992 : #define TYPED_ARRAY_SHORT_PRINT(Type, type, TYPE, ctype, size) \
2993 : case FIXED_##TYPE##_ARRAY_TYPE: \
2994 : os << "<Fixed" #Type "Array[" << Fixed##Type##Array::cast(this)->length() \
2995 : << "]>"; \
2996 : break;
2997 :
2998 0 : TYPED_ARRAYS(TYPED_ARRAY_SHORT_PRINT)
2999 : #undef TYPED_ARRAY_SHORT_PRINT
3000 :
3001 : case SHARED_FUNCTION_INFO_TYPE: {
3002 : SharedFunctionInfo* shared = SharedFunctionInfo::cast(this);
3003 0 : std::unique_ptr<char[]> debug_name = shared->DebugName()->ToCString();
3004 0 : if (debug_name[0] != 0) {
3005 0 : os << "<SharedFunctionInfo " << debug_name.get() << ">";
3006 : } else {
3007 0 : os << "<SharedFunctionInfo>";
3008 : }
3009 : break;
3010 : }
3011 : case JS_MESSAGE_OBJECT_TYPE:
3012 0 : os << "<JSMessageObject>";
3013 0 : break;
3014 : #define MAKE_STRUCT_CASE(NAME, Name, name) \
3015 : case NAME##_TYPE: \
3016 : os << "<" #Name ">"; \
3017 : break;
3018 0 : STRUCT_LIST(MAKE_STRUCT_CASE)
3019 : #undef MAKE_STRUCT_CASE
3020 : case CODE_TYPE: {
3021 : Code* code = Code::cast(this);
3022 0 : os << "<Code " << Code::Kind2String(code->kind()) << ">";
3023 0 : break;
3024 : }
3025 : case ODDBALL_TYPE: {
3026 122 : if (IsUndefined(isolate)) {
3027 75 : os << "<undefined>";
3028 47 : } else if (IsTheHole(isolate)) {
3029 0 : os << "<the_hole>";
3030 47 : } else if (IsNull(isolate)) {
3031 17 : os << "<null>";
3032 30 : } else if (IsTrue(isolate)) {
3033 15 : os << "<true>";
3034 15 : } else if (IsFalse(isolate)) {
3035 15 : os << "<false>";
3036 : } else {
3037 0 : os << "<Odd Oddball: ";
3038 0 : os << Oddball::cast(this)->to_string()->ToCString().get();
3039 0 : os << ">";
3040 : }
3041 : break;
3042 : }
3043 : case SYMBOL_TYPE: {
3044 : Symbol* symbol = Symbol::cast(this);
3045 227 : symbol->SymbolShortPrint(os);
3046 227 : break;
3047 : }
3048 : case HEAP_NUMBER_TYPE: {
3049 105 : os << "<Number ";
3050 : HeapNumber::cast(this)->HeapNumberPrint(os);
3051 105 : os << ">";
3052 105 : break;
3053 : }
3054 : case MUTABLE_HEAP_NUMBER_TYPE: {
3055 0 : os << "<MutableNumber ";
3056 : HeapNumber::cast(this)->HeapNumberPrint(os);
3057 : os << '>';
3058 : break;
3059 : }
3060 : case JS_PROXY_TYPE:
3061 15 : os << "<JSProxy>";
3062 15 : break;
3063 : case FOREIGN_TYPE:
3064 0 : os << "<Foreign>";
3065 0 : break;
3066 : case CELL_TYPE: {
3067 0 : os << "<Cell value= ";
3068 : HeapStringAllocator allocator;
3069 : StringStream accumulator(&allocator);
3070 0 : Cell::cast(this)->value()->ShortPrint(&accumulator);
3071 0 : os << accumulator.ToCString().get();
3072 : os << '>';
3073 : break;
3074 : }
3075 : case PROPERTY_CELL_TYPE: {
3076 0 : os << "<PropertyCell value=";
3077 : HeapStringAllocator allocator;
3078 : StringStream accumulator(&allocator);
3079 : PropertyCell* cell = PropertyCell::cast(this);
3080 0 : cell->value()->ShortPrint(&accumulator);
3081 0 : os << accumulator.ToCString().get();
3082 : os << '>';
3083 : break;
3084 : }
3085 : case WEAK_CELL_TYPE: {
3086 0 : os << "<WeakCell value= ";
3087 : HeapStringAllocator allocator;
3088 : StringStream accumulator(&allocator);
3089 0 : WeakCell::cast(this)->value()->ShortPrint(&accumulator);
3090 0 : os << accumulator.ToCString().get();
3091 : os << '>';
3092 : break;
3093 : }
3094 : default:
3095 0 : os << "<Other heap object (" << map()->instance_type() << ")>";
3096 0 : break;
3097 : }
3098 : }
3099 :
3100 :
3101 33403871 : void HeapObject::Iterate(ObjectVisitor* v) { IterateFast<ObjectVisitor>(v); }
3102 :
3103 :
3104 682 : void HeapObject::IterateBody(ObjectVisitor* v) {
3105 : Map* m = map();
3106 682 : IterateBodyFast<ObjectVisitor>(m->instance_type(), SizeFromMap(m), v);
3107 682 : }
3108 :
3109 :
3110 52843115 : void HeapObject::IterateBody(InstanceType type, int object_size,
3111 : ObjectVisitor* v) {
3112 : IterateBodyFast<ObjectVisitor>(type, object_size, v);
3113 52813816 : }
3114 :
3115 :
3116 : struct CallIsValidSlot {
3117 : template <typename BodyDescriptor>
3118 : static bool apply(HeapObject* obj, int offset, int) {
3119 : return BodyDescriptor::IsValidSlot(obj, offset);
3120 : }
3121 : };
3122 :
3123 :
3124 0 : bool HeapObject::IsValidSlot(int offset) {
3125 : DCHECK_NE(0, offset);
3126 : return BodyDescriptorApply<CallIsValidSlot, bool>(map()->instance_type(),
3127 0 : this, offset, 0);
3128 : }
3129 :
3130 :
3131 0 : bool HeapNumber::HeapNumberBooleanValue() {
3132 64743 : return DoubleToBoolean(value());
3133 : }
3134 :
3135 :
3136 16569 : void HeapNumber::HeapNumberPrint(std::ostream& os) { // NOLINT
3137 : os << value();
3138 16569 : }
3139 :
3140 :
3141 : #define FIELD_ADDR_CONST(p, offset) \
3142 : (reinterpret_cast<const byte*>(p) + offset - kHeapObjectTag)
3143 :
3144 : #define READ_INT32_FIELD(p, offset) \
3145 : (*reinterpret_cast<const int32_t*>(FIELD_ADDR_CONST(p, offset)))
3146 :
3147 : #define READ_INT64_FIELD(p, offset) \
3148 : (*reinterpret_cast<const int64_t*>(FIELD_ADDR_CONST(p, offset)))
3149 :
3150 : #define READ_BYTE_FIELD(p, offset) \
3151 : (*reinterpret_cast<const byte*>(FIELD_ADDR_CONST(p, offset)))
3152 :
3153 65542419 : String* JSReceiver::class_name() {
3154 65542420 : if (IsFunction()) {
3155 31014906 : return GetHeap()->Function_string();
3156 : }
3157 34527514 : Object* maybe_constructor = map()->GetConstructor();
3158 34527514 : if (maybe_constructor->IsJSFunction()) {
3159 : JSFunction* constructor = JSFunction::cast(maybe_constructor);
3160 34527447 : return String::cast(constructor->shared()->instance_class_name());
3161 67 : } else if (maybe_constructor->IsFunctionTemplateInfo()) {
3162 : FunctionTemplateInfo* info = FunctionTemplateInfo::cast(maybe_constructor);
3163 : return info->class_name()->IsString() ? String::cast(info->class_name())
3164 1 : : GetHeap()->empty_string();
3165 : }
3166 :
3167 : // If the constructor is not present, return "Object".
3168 66 : return GetHeap()->Object_string();
3169 : }
3170 :
3171 :
3172 : // static
3173 7689709 : Handle<String> JSReceiver::GetConstructorName(Handle<JSReceiver> receiver) {
3174 : Isolate* isolate = receiver->GetIsolate();
3175 :
3176 : // If the object was instantiated simply with base == new.target, the
3177 : // constructor on the map provides the most accurate name.
3178 : // Don't provide the info for prototypes, since their constructors are
3179 : // reclaimed and replaced by Object in OptimizeAsPrototype.
3180 23068382 : if (!receiver->IsJSProxy() && receiver->map()->new_target_is_base() &&
3181 : !receiver->map()->is_prototype_map()) {
3182 7471617 : Object* maybe_constructor = receiver->map()->GetConstructor();
3183 7471617 : if (maybe_constructor->IsJSFunction()) {
3184 : JSFunction* constructor = JSFunction::cast(maybe_constructor);
3185 : String* name = String::cast(constructor->shared()->name());
3186 5036080 : if (name->length() == 0) name = constructor->shared()->inferred_name();
3187 9334015 : if (name->length() != 0 &&
3188 4297935 : !name->Equals(isolate->heap()->Object_string())) {
3189 : return handle(name, isolate);
3190 : }
3191 2435537 : } else if (maybe_constructor->IsFunctionTemplateInfo()) {
3192 : FunctionTemplateInfo* info =
3193 : FunctionTemplateInfo::cast(maybe_constructor);
3194 0 : if (info->class_name()->IsString()) {
3195 : return handle(String::cast(info->class_name()), isolate);
3196 : }
3197 : }
3198 : }
3199 :
3200 : Handle<Object> maybe_tag = JSReceiver::GetDataProperty(
3201 4364013 : receiver, isolate->factory()->to_string_tag_symbol());
3202 4364013 : if (maybe_tag->IsString()) return Handle<String>::cast(maybe_tag);
3203 :
3204 3649531 : PrototypeIterator iter(isolate, receiver);
3205 4273712 : if (iter.IsAtEnd()) return handle(receiver->class_name());
3206 3025350 : Handle<JSReceiver> start = PrototypeIterator::GetCurrent<JSReceiver>(iter);
3207 : LookupIterator it(receiver, isolate->factory()->constructor_string(), start,
3208 3025350 : LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
3209 3025350 : Handle<Object> maybe_constructor = JSReceiver::GetDataProperty(&it);
3210 : Handle<String> result = isolate->factory()->Object_string();
3211 3025350 : if (maybe_constructor->IsJSFunction()) {
3212 : JSFunction* constructor = JSFunction::cast(*maybe_constructor);
3213 : String* name = String::cast(constructor->shared()->name());
3214 3025236 : if (name->length() == 0) name = constructor->shared()->inferred_name();
3215 3025236 : if (name->length() > 0) result = handle(name, isolate);
3216 : }
3217 :
3218 : return result.is_identical_to(isolate->factory()->Object_string())
3219 476583 : ? handle(receiver->class_name())
3220 5574117 : : result;
3221 : }
3222 :
3223 491 : Handle<Context> JSReceiver::GetCreationContext() {
3224 : JSReceiver* receiver = this;
3225 996 : while (receiver->IsJSBoundFunction()) {
3226 : receiver = JSBoundFunction::cast(receiver)->bound_target_function();
3227 : }
3228 491 : Object* constructor = receiver->map()->GetConstructor();
3229 : JSFunction* function;
3230 491 : if (constructor->IsJSFunction()) {
3231 : function = JSFunction::cast(constructor);
3232 14 : } else if (constructor->IsFunctionTemplateInfo()) {
3233 : // Remote objects don't have a creation context.
3234 2 : return Handle<Context>::null();
3235 : } else {
3236 : // Functions have null as a constructor,
3237 : // but any JSFunction knows its context immediately.
3238 12 : CHECK(receiver->IsJSFunction());
3239 : function = JSFunction::cast(receiver);
3240 : }
3241 :
3242 489 : return function->has_context()
3243 : ? Handle<Context>(function->context()->native_context())
3244 489 : : Handle<Context>::null();
3245 : }
3246 :
3247 9708462 : Handle<Object> Map::WrapFieldType(Handle<FieldType> type) {
3248 10969450 : if (type->IsClass()) return Map::WeakCellForMap(type->AsClass());
3249 8447477 : return type;
3250 : }
3251 :
3252 67479806 : FieldType* Map::UnwrapFieldType(Object* wrapped_type) {
3253 : Object* value = wrapped_type;
3254 67479806 : if (value->IsWeakCell()) {
3255 9719651 : if (WeakCell::cast(value)->cleared()) return FieldType::None();
3256 : value = WeakCell::cast(value)->value();
3257 : }
3258 67479691 : return FieldType::cast(value);
3259 : }
3260 :
3261 8783253 : MaybeHandle<Map> Map::CopyWithField(Handle<Map> map, Handle<Name> name,
3262 : Handle<FieldType> type,
3263 : PropertyAttributes attributes,
3264 : PropertyConstness constness,
3265 : Representation representation,
3266 : TransitionFlag flag) {
3267 : DCHECK(DescriptorArray::kNotFound ==
3268 : map->instance_descriptors()->Search(
3269 : *name, map->NumberOfOwnDescriptors()));
3270 :
3271 : // Ensure the descriptor array does not get too big.
3272 8783253 : if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
3273 : return MaybeHandle<Map>();
3274 : }
3275 :
3276 : Isolate* isolate = map->GetIsolate();
3277 :
3278 : // Compute the new index for new field.
3279 8783136 : int index = map->NextFreePropertyIndex();
3280 :
3281 8783134 : if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
3282 4195 : representation = Representation::Tagged();
3283 4195 : type = FieldType::Any(isolate);
3284 : }
3285 :
3286 8783134 : Handle<Object> wrapped_type(WrapFieldType(type));
3287 :
3288 : DCHECK_IMPLIES(!FLAG_track_constant_fields, constness == kMutable);
3289 : Descriptor d = Descriptor::DataField(name, index, attributes, constness,
3290 8783134 : representation, wrapped_type);
3291 8783134 : Handle<Map> new_map = Map::CopyAddDescriptor(map, &d, flag);
3292 8783138 : int unused_property_fields = new_map->unused_property_fields() - 1;
3293 8783138 : if (unused_property_fields < 0) {
3294 2329585 : unused_property_fields += JSObject::kFieldsAdded;
3295 : }
3296 : new_map->set_unused_property_fields(unused_property_fields);
3297 : return new_map;
3298 : }
3299 :
3300 :
3301 6722403 : MaybeHandle<Map> Map::CopyWithConstant(Handle<Map> map,
3302 : Handle<Name> name,
3303 : Handle<Object> constant,
3304 : PropertyAttributes attributes,
3305 : TransitionFlag flag) {
3306 : // Ensure the descriptor array does not get too big.
3307 6722403 : if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
3308 : return MaybeHandle<Map>();
3309 : }
3310 :
3311 : if (FLAG_track_constant_fields) {
3312 : Isolate* isolate = map->GetIsolate();
3313 : Representation representation = constant->OptimalRepresentation();
3314 : Handle<FieldType> type = constant->OptimalType(isolate, representation);
3315 : return CopyWithField(map, name, type, attributes, kConst, representation,
3316 : flag);
3317 : } else {
3318 : // Allocate new instance descriptors with (name, constant) added.
3319 6722403 : Descriptor d = Descriptor::DataConstant(name, 0, constant, attributes);
3320 6722405 : Handle<Map> new_map = Map::CopyAddDescriptor(map, &d, flag);
3321 : return new_map;
3322 : }
3323 : }
3324 :
3325 0 : const char* Representation::Mnemonic() const {
3326 0 : switch (kind_) {
3327 : case kNone: return "v";
3328 0 : case kTagged: return "t";
3329 0 : case kSmi: return "s";
3330 0 : case kDouble: return "d";
3331 0 : case kInteger32: return "i";
3332 0 : case kHeapObject: return "h";
3333 0 : case kExternal: return "x";
3334 : default:
3335 0 : UNREACHABLE();
3336 : return NULL;
3337 : }
3338 : }
3339 :
3340 0 : bool Map::TransitionRemovesTaggedField(Map* target) {
3341 : int inobject = GetInObjectProperties();
3342 : int target_inobject = target->GetInObjectProperties();
3343 0 : for (int i = target_inobject; i < inobject; i++) {
3344 0 : FieldIndex index = FieldIndex::ForPropertyIndex(this, i);
3345 0 : if (!IsUnboxedDoubleField(index)) return true;
3346 : }
3347 : return false;
3348 : }
3349 :
3350 0 : bool Map::TransitionChangesTaggedFieldToUntaggedField(Map* target) {
3351 : int inobject = GetInObjectProperties();
3352 : int target_inobject = target->GetInObjectProperties();
3353 : int limit = Min(inobject, target_inobject);
3354 0 : for (int i = 0; i < limit; i++) {
3355 0 : FieldIndex index = FieldIndex::ForPropertyIndex(target, i);
3356 0 : if (!IsUnboxedDoubleField(index) && target->IsUnboxedDoubleField(index)) {
3357 0 : return true;
3358 : }
3359 : }
3360 : return false;
3361 : }
3362 :
3363 0 : bool Map::TransitionRequiresSynchronizationWithGC(Map* target) {
3364 0 : return TransitionRemovesTaggedField(target) ||
3365 0 : TransitionChangesTaggedFieldToUntaggedField(target);
3366 : }
3367 :
3368 147124 : bool Map::InstancesNeedRewriting(Map* target) {
3369 147124 : int target_number_of_fields = target->NumberOfFields();
3370 : int target_inobject = target->GetInObjectProperties();
3371 : int target_unused = target->unused_property_fields();
3372 : int old_number_of_fields;
3373 :
3374 : return InstancesNeedRewriting(target, target_number_of_fields,
3375 : target_inobject, target_unused,
3376 147124 : &old_number_of_fields);
3377 : }
3378 :
3379 26143404 : bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields,
3380 : int target_inobject, int target_unused,
3381 : int* old_number_of_fields) {
3382 : // If fields were added (or removed), rewrite the instance.
3383 26143404 : *old_number_of_fields = NumberOfFields();
3384 : DCHECK(target_number_of_fields >= *old_number_of_fields);
3385 26143405 : if (target_number_of_fields != *old_number_of_fields) return true;
3386 :
3387 : // If smi descriptors were replaced by double descriptors, rewrite.
3388 : DescriptorArray* old_desc = instance_descriptors();
3389 : DescriptorArray* new_desc = target->instance_descriptors();
3390 : int limit = NumberOfOwnDescriptors();
3391 50164247 : for (int i = 0; i < limit; i++) {
3392 72794266 : if (new_desc->GetDetails(i).representation().IsDouble() !=
3393 72794268 : old_desc->GetDetails(i).representation().IsDouble()) {
3394 : return true;
3395 : }
3396 : }
3397 :
3398 : // If no fields were added, and no inobject properties were removed, setting
3399 : // the map is sufficient.
3400 13767115 : if (target_inobject == GetInObjectProperties()) return false;
3401 : // In-object slack tracking may have reduced the object size of the new map.
3402 : // In that case, succeed if all existing fields were inobject, and they still
3403 : // fit within the new inobject size.
3404 : DCHECK(target_inobject < GetInObjectProperties());
3405 509 : if (target_number_of_fields <= target_inobject) {
3406 : DCHECK(target_number_of_fields + target_unused == target_inobject);
3407 : return false;
3408 : }
3409 : // Otherwise, properties will need to be moved to the backing store.
3410 0 : return true;
3411 : }
3412 :
3413 :
3414 : // static
3415 5501812 : void JSObject::UpdatePrototypeUserRegistration(Handle<Map> old_map,
3416 : Handle<Map> new_map,
3417 : Isolate* isolate) {
3418 : DCHECK(old_map->is_prototype_map());
3419 : DCHECK(new_map->is_prototype_map());
3420 5501812 : bool was_registered = JSObject::UnregisterPrototypeUser(old_map, isolate);
3421 5501812 : new_map->set_prototype_info(old_map->prototype_info());
3422 5501813 : old_map->set_prototype_info(Smi::kZero);
3423 5501812 : if (FLAG_trace_prototype_users) {
3424 : PrintF("Moving prototype_info %p from map %p to map %p.\n",
3425 : reinterpret_cast<void*>(new_map->prototype_info()),
3426 : reinterpret_cast<void*>(*old_map),
3427 0 : reinterpret_cast<void*>(*new_map));
3428 : }
3429 5501812 : if (was_registered) {
3430 284542 : if (new_map->prototype_info()->IsPrototypeInfo()) {
3431 : // The new map isn't registered with its prototype yet; reflect this fact
3432 : // in the PrototypeInfo it just inherited from the old map.
3433 : PrototypeInfo::cast(new_map->prototype_info())
3434 : ->set_registry_slot(PrototypeInfo::UNREGISTERED);
3435 : }
3436 284542 : JSObject::LazyRegisterPrototypeUser(new_map, isolate);
3437 : }
3438 5501812 : }
3439 :
3440 : namespace {
3441 : // To migrate a fast instance to a fast map:
3442 : // - First check whether the instance needs to be rewritten. If not, simply
3443 : // change the map.
3444 : // - Otherwise, allocate a fixed array large enough to hold all fields, in
3445 : // addition to unused space.
3446 : // - Copy all existing properties in, in the following order: backing store
3447 : // properties, unused fields, inobject properties.
3448 : // - If all allocation succeeded, commit the state atomically:
3449 : // * Copy inobject properties from the backing store back into the object.
3450 : // * Trim the difference in instance size of the object. This also cleanly
3451 : // frees inobject properties that moved to the backing store.
3452 : // * If there are properties left in the backing store, trim of the space used
3453 : // to temporarily store the inobject properties.
3454 : // * If there are properties left in the backing store, install the backing
3455 : // store.
3456 52843403 : void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
3457 : Isolate* isolate = object->GetIsolate();
3458 : Handle<Map> old_map(object->map());
3459 : // In case of a regular transition.
3460 105686795 : if (new_map->GetBackPointer() == *old_map) {
3461 : // If the map does not add named properties, simply set the map.
3462 26847117 : if (old_map->NumberOfOwnDescriptors() ==
3463 : new_map->NumberOfOwnDescriptors()) {
3464 686146 : object->synchronized_set_map(*new_map);
3465 686135 : return;
3466 : }
3467 :
3468 : PropertyDetails details = new_map->GetLastDescriptorDetails();
3469 26160983 : int target_index = details.field_index() - new_map->GetInObjectProperties();
3470 31520180 : bool have_space = old_map->unused_property_fields() > 0 ||
3471 9289388 : (details.location() == kField && target_index >= 0 &&
3472 : object->properties()->length() > target_index);
3473 : // Either new_map adds an kDescriptor property, or a kField property for
3474 : // which there is still space, and which does not require a mutable double
3475 : // box (an out-of-object double).
3476 52321966 : if (details.location() == kDescriptor ||
3477 18043579 : (have_space &&
3478 5436580 : ((FLAG_unbox_double_fields && object->properties()->length() == 0) ||
3479 : !details.representation().IsDouble()))) {
3480 21510796 : object->synchronized_set_map(*new_map);
3481 21510795 : return;
3482 : }
3483 :
3484 : // If there is still space in the object, we need to allocate a mutable
3485 : // double box.
3486 4650187 : if (have_space) {
3487 : FieldIndex index =
3488 5492 : FieldIndex::ForDescriptor(*new_map, new_map->LastAdded());
3489 : DCHECK(details.representation().IsDouble());
3490 : DCHECK(!new_map->IsUnboxedDoubleField(index));
3491 : Handle<Object> value = isolate->factory()->NewMutableHeapNumber();
3492 5492 : object->RawFastPropertyAtPut(index, *value);
3493 5492 : object->synchronized_set_map(*new_map);
3494 : return;
3495 : }
3496 :
3497 : // This migration is a transition from a map that has run out of property
3498 : // space. Extend the backing store.
3499 4644695 : int grow_by = new_map->unused_property_fields() + 1;
3500 4644694 : Handle<FixedArray> old_storage = handle(object->properties(), isolate);
3501 : Handle<FixedArray> new_storage =
3502 4644694 : isolate->factory()->CopyFixedArrayAndGrow(old_storage, grow_by);
3503 :
3504 : // Properly initialize newly added property.
3505 : Handle<Object> value;
3506 4644694 : if (details.representation().IsDouble()) {
3507 : value = isolate->factory()->NewMutableHeapNumber();
3508 : } else {
3509 : value = isolate->factory()->uninitialized_value();
3510 : }
3511 : DCHECK_EQ(kField, details.location());
3512 : DCHECK_EQ(kData, details.kind());
3513 : DCHECK(target_index >= 0); // Must be a backing store index.
3514 4644694 : new_storage->set(target_index, *value);
3515 :
3516 : // From here on we cannot fail and we shouldn't GC anymore.
3517 : DisallowHeapAllocation no_allocation;
3518 :
3519 : // Set the new property value and do the map transition.
3520 4644694 : object->set_properties(*new_storage);
3521 4644695 : object->synchronized_set_map(*new_map);
3522 4644695 : return;
3523 : }
3524 :
3525 : int old_number_of_fields;
3526 25996282 : int number_of_fields = new_map->NumberOfFields();
3527 : int inobject = new_map->GetInObjectProperties();
3528 : int unused = new_map->unused_property_fields();
3529 :
3530 : // Nothing to do if no functions were converted to fields and no smis were
3531 : // converted to doubles.
3532 25996282 : if (!old_map->InstancesNeedRewriting(*new_map, number_of_fields, inobject,
3533 25996280 : unused, &old_number_of_fields)) {
3534 13620021 : object->synchronized_set_map(*new_map);
3535 13620023 : return;
3536 : }
3537 :
3538 12376261 : int total_size = number_of_fields + unused;
3539 12376261 : int external = total_size - inobject;
3540 :
3541 12376261 : Handle<FixedArray> array = isolate->factory()->NewFixedArray(total_size);
3542 :
3543 : Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors());
3544 : Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors());
3545 : int old_nof = old_map->NumberOfOwnDescriptors();
3546 : int new_nof = new_map->NumberOfOwnDescriptors();
3547 :
3548 : // This method only supports generalizing instances to at least the same
3549 : // number of properties.
3550 : DCHECK(old_nof <= new_nof);
3551 :
3552 105629574 : for (int i = 0; i < old_nof; i++) {
3553 93253311 : PropertyDetails details = new_descriptors->GetDetails(i);
3554 93253317 : if (details.location() != kField) continue;
3555 : DCHECK_EQ(kData, details.kind());
3556 63107157 : PropertyDetails old_details = old_descriptors->GetDetails(i);
3557 : Representation old_representation = old_details.representation();
3558 : Representation representation = details.representation();
3559 : Handle<Object> value;
3560 63107158 : if (old_details.location() == kDescriptor) {
3561 1950275 : if (old_details.kind() == kAccessor) {
3562 : // In case of kAccessor -> kData property reconfiguration, the property
3563 : // must already be prepared for data of certain type.
3564 : DCHECK(!details.representation().IsNone());
3565 1513561 : if (details.representation().IsDouble()) {
3566 : value = isolate->factory()->NewMutableHeapNumber();
3567 : } else {
3568 : value = isolate->factory()->uninitialized_value();
3569 : }
3570 : } else {
3571 : DCHECK_EQ(kData, old_details.kind());
3572 : value = handle(old_descriptors->GetValue(i), isolate);
3573 : DCHECK(!old_representation.IsDouble() && !representation.IsDouble());
3574 : }
3575 : } else {
3576 : DCHECK_EQ(kField, old_details.location());
3577 61156883 : FieldIndex index = FieldIndex::ForDescriptor(*old_map, i);
3578 61156882 : if (object->IsUnboxedDoubleField(index)) {
3579 : uint64_t old_bits = object->RawFastDoublePropertyAsBitsAt(index);
3580 : value = isolate->factory()->NewHeapNumberFromBits(
3581 4883 : old_bits, representation.IsDouble() ? MUTABLE : IMMUTABLE);
3582 :
3583 : } else {
3584 61152000 : value = handle(object->RawFastPropertyAt(index), isolate);
3585 61152000 : if (!old_representation.IsDouble() && representation.IsDouble()) {
3586 : DCHECK_IMPLIES(old_representation.IsNone(),
3587 : value->IsUninitialized(isolate));
3588 2849 : value = Object::NewStorageFor(isolate, value, representation);
3589 61149151 : } else if (old_representation.IsDouble() &&
3590 : !representation.IsDouble()) {
3591 19 : value = Object::WrapForRead(isolate, value, old_representation);
3592 : }
3593 : }
3594 : }
3595 : DCHECK(!(representation.IsDouble() && value->IsSmi()));
3596 63107157 : int target_index = new_descriptors->GetFieldIndex(i) - inobject;
3597 63107157 : if (target_index < 0) target_index += total_size;
3598 63107157 : array->set(target_index, *value);
3599 : }
3600 :
3601 43615733 : for (int i = old_nof; i < new_nof; i++) {
3602 43615733 : PropertyDetails details = new_descriptors->GetDetails(i);
3603 43615733 : if (details.location() != kField) continue;
3604 : DCHECK_EQ(kData, details.kind());
3605 : Handle<Object> value;
3606 43615733 : if (details.representation().IsDouble()) {
3607 : value = isolate->factory()->NewMutableHeapNumber();
3608 : } else {
3609 : value = isolate->factory()->uninitialized_value();
3610 : }
3611 43615733 : int target_index = new_descriptors->GetFieldIndex(i) - inobject;
3612 43615733 : if (target_index < 0) target_index += total_size;
3613 43615733 : array->set(target_index, *value);
3614 : }
3615 :
3616 : // From here on we cannot fail and we shouldn't GC anymore.
3617 : DisallowHeapAllocation no_allocation;
3618 :
3619 12376263 : Heap* heap = isolate->heap();
3620 :
3621 12376263 : heap->NotifyObjectLayoutChange(*object, no_allocation);
3622 :
3623 : // Copy (real) inobject properties. If necessary, stop at number_of_fields to
3624 : // avoid overwriting |one_pointer_filler_map|.
3625 : int limit = Min(inobject, number_of_fields);
3626 47766808 : for (int i = 0; i < limit; i++) {
3627 35390545 : FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
3628 35390545 : Object* value = array->get(external + i);
3629 : // Can't use JSObject::FastPropertyAtPut() because proper map was not set
3630 : // yet.
3631 35390545 : if (new_map->IsUnboxedDoubleField(index)) {
3632 : DCHECK(value->IsMutableHeapNumber());
3633 : // Ensure that all bits of the double value are preserved.
3634 : object->RawFastDoublePropertyAsBitsAtPut(
3635 : index, HeapNumber::cast(value)->value_as_bits());
3636 45562 : if (i < old_number_of_fields && !old_map->IsUnboxedDoubleField(index)) {
3637 : // Transition from tagged to untagged slot.
3638 : heap->ClearRecordedSlot(*object,
3639 1903 : HeapObject::RawField(*object, index.offset()));
3640 : } else {
3641 : DCHECK(!heap->HasRecordedSlot(
3642 : *object, HeapObject::RawField(*object, index.offset())));
3643 : }
3644 : } else {
3645 35351030 : object->RawFastPropertyAtPut(index, value);
3646 : }
3647 : }
3648 :
3649 :
3650 : // If there are properties in the new backing store, trim it to the correct
3651 : // size and install the backing store into the object.
3652 12376263 : if (external > 0) {
3653 6740143 : heap->RightTrimFixedArray(*array, inobject);
3654 6740143 : object->set_properties(*array);
3655 : }
3656 :
3657 : // Create filler object past the new instance size.
3658 : int new_instance_size = new_map->instance_size();
3659 12376260 : int instance_size_delta = old_map->instance_size() - new_instance_size;
3660 : DCHECK(instance_size_delta >= 0);
3661 :
3662 12376260 : if (instance_size_delta > 0) {
3663 17 : Address address = object->address();
3664 : heap->CreateFillerObjectAt(address + new_instance_size, instance_size_delta,
3665 17 : ClearRecordedSlots::kYes);
3666 34 : heap->AdjustLiveBytes(*object, -instance_size_delta);
3667 : }
3668 :
3669 : // We are storing the new map using release store after creating a filler for
3670 : // the left-over space to avoid races with the sweeper thread.
3671 12376260 : object->synchronized_set_map(*new_map);
3672 : }
3673 :
3674 1318662 : void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map,
3675 : int expected_additional_properties) {
3676 : // The global object is always normalized.
3677 : DCHECK(!object->IsJSGlobalObject());
3678 : // JSGlobalProxy must never be normalized
3679 : DCHECK(!object->IsJSGlobalProxy());
3680 :
3681 1318662 : Isolate* isolate = object->GetIsolate();
3682 : HandleScope scope(isolate);
3683 : Handle<Map> map(object->map());
3684 :
3685 : // Allocate new content.
3686 : int real_size = map->NumberOfOwnDescriptors();
3687 : int property_count = real_size;
3688 1318662 : if (expected_additional_properties > 0) {
3689 94869 : property_count += expected_additional_properties;
3690 : } else {
3691 : // Make space for two more properties.
3692 1223793 : property_count += NameDictionary::kInitialCapacity;
3693 : }
3694 : Handle<NameDictionary> dictionary =
3695 1318662 : NameDictionary::New(isolate, property_count);
3696 :
3697 : Handle<DescriptorArray> descs(map->instance_descriptors());
3698 8438109 : for (int i = 0; i < real_size; i++) {
3699 5800785 : PropertyDetails details = descs->GetDetails(i);
3700 : Handle<Name> key(descs->GetKey(i));
3701 : Handle<Object> value;
3702 5800785 : if (details.location() == kField) {
3703 4467019 : FieldIndex index = FieldIndex::ForDescriptor(*map, i);
3704 4467019 : if (details.kind() == kData) {
3705 4467019 : if (object->IsUnboxedDoubleField(index)) {
3706 : double old_value = object->RawFastDoublePropertyAt(index);
3707 : value = isolate->factory()->NewHeapNumber(old_value);
3708 : } else {
3709 4466123 : value = handle(object->RawFastPropertyAt(index), isolate);
3710 4466123 : if (details.representation().IsDouble()) {
3711 : DCHECK(value->IsMutableHeapNumber());
3712 : Handle<HeapNumber> old = Handle<HeapNumber>::cast(value);
3713 : value = isolate->factory()->NewHeapNumber(old->value());
3714 : }
3715 : }
3716 : } else {
3717 : DCHECK_EQ(kAccessor, details.kind());
3718 0 : value = handle(object->RawFastPropertyAt(index), isolate);
3719 : }
3720 :
3721 : } else {
3722 : DCHECK_EQ(kDescriptor, details.location());
3723 : value = handle(descs->GetValue(i), isolate);
3724 : }
3725 : DCHECK(!value.is_null());
3726 : PropertyDetails d(details.kind(), details.attributes(), i + 1,
3727 5800785 : PropertyCellType::kNoCell);
3728 5800785 : dictionary = NameDictionary::Add(dictionary, key, value, d);
3729 : }
3730 :
3731 : // Copy the next enumeration index from instance descriptor.
3732 1318662 : dictionary->SetNextEnumerationIndex(real_size + 1);
3733 :
3734 : // From here on we cannot fail and we shouldn't GC anymore.
3735 : DisallowHeapAllocation no_allocation;
3736 :
3737 1318662 : Heap* heap = isolate->heap();
3738 1318662 : heap->NotifyObjectLayoutChange(*object, no_allocation);
3739 :
3740 : // Resize the object in the heap if necessary.
3741 : int new_instance_size = new_map->instance_size();
3742 1318662 : int instance_size_delta = map->instance_size() - new_instance_size;
3743 : DCHECK(instance_size_delta >= 0);
3744 :
3745 1318662 : if (instance_size_delta > 0) {
3746 452771 : heap->CreateFillerObjectAt(object->address() + new_instance_size,
3747 452771 : instance_size_delta, ClearRecordedSlots::kYes);
3748 905542 : heap->AdjustLiveBytes(*object, -instance_size_delta);
3749 : }
3750 :
3751 : // We are storing the new map using release store after creating a filler for
3752 : // the left-over space to avoid races with the sweeper thread.
3753 1318662 : object->synchronized_set_map(*new_map);
3754 :
3755 1318662 : object->set_properties(*dictionary);
3756 :
3757 : // Ensure that in-object space of slow-mode object does not contain random
3758 : // garbage.
3759 : int inobject_properties = new_map->GetInObjectProperties();
3760 1318662 : if (inobject_properties) {
3761 : Heap* heap = isolate->heap();
3762 : heap->ClearRecordedSlotRange(
3763 588350 : object->address() + map->GetInObjectPropertyOffset(0),
3764 1176700 : object->address() + new_instance_size);
3765 :
3766 3469050 : for (int i = 0; i < inobject_properties; i++) {
3767 2880700 : FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
3768 2880700 : object->RawFastPropertyAtPut(index, Smi::kZero);
3769 : }
3770 : }
3771 :
3772 1318662 : isolate->counters()->props_to_dictionary()->Increment();
3773 :
3774 : #ifdef DEBUG
3775 : if (FLAG_trace_normalization) {
3776 : OFStream os(stdout);
3777 : os << "Object properties have been normalized:\n";
3778 : object->Print(os);
3779 : }
3780 : #endif
3781 1318662 : }
3782 :
3783 : } // namespace
3784 :
3785 : // static
3786 55443037 : void JSObject::NotifyMapChange(Handle<Map> old_map, Handle<Map> new_map,
3787 : Isolate* isolate) {
3788 110886074 : if (!old_map->is_prototype_map()) return;
3789 :
3790 : InvalidatePrototypeChains(*old_map);
3791 :
3792 : // If the map was registered with its prototype before, ensure that it
3793 : // registers with its new prototype now. This preserves the invariant that
3794 : // when a map on a prototype chain is registered with its prototype, then
3795 : // all prototypes further up the chain are also registered with their
3796 : // respective prototypes.
3797 5501812 : UpdatePrototypeUserRegistration(old_map, new_map, isolate);
3798 : }
3799 :
3800 69258317 : void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
3801 : int expected_additional_properties) {
3802 138516636 : if (object->map() == *new_map) return;
3803 : Handle<Map> old_map(object->map());
3804 54813056 : NotifyMapChange(old_map, new_map, new_map->GetIsolate());
3805 :
3806 54813057 : if (old_map->is_dictionary_map()) {
3807 : // For slow-to-fast migrations JSObject::MigrateSlowToFast()
3808 : // must be used instead.
3809 650992 : CHECK(new_map->is_dictionary_map());
3810 :
3811 : // Slow-to-slow migration is trivial.
3812 650992 : object->set_map(*new_map);
3813 54162065 : } else if (!new_map->is_dictionary_map()) {
3814 52843403 : MigrateFastToFast(object, new_map);
3815 52843400 : if (old_map->is_prototype_map()) {
3816 : DCHECK(!old_map->is_stable());
3817 : DCHECK(new_map->is_stable());
3818 : // Clear out the old descriptor array to avoid problems to sharing
3819 : // the descriptor array without using an explicit.
3820 : old_map->InitializeDescriptors(
3821 : old_map->GetHeap()->empty_descriptor_array(),
3822 4902951 : LayoutDescriptor::FastPointerLayout());
3823 : // Ensure that no transition was inserted for prototype migrations.
3824 : DCHECK_EQ(
3825 : 0, TransitionArray::NumberOfTransitions(old_map->raw_transitions()));
3826 : DCHECK(new_map->GetBackPointer()->IsUndefined(new_map->GetIsolate()));
3827 : }
3828 : } else {
3829 1318662 : MigrateFastToSlow(object, new_map, expected_additional_properties);
3830 : }
3831 :
3832 : // Careful: Don't allocate here!
3833 : // For some callers of this method, |object| might be in an inconsistent
3834 : // state now: the new map might have a new elements_kind, but the object's
3835 : // elements pointer hasn't been updated yet. Callers will fix this, but in
3836 : // the meantime, (indirectly) calling JSObjectVerify() must be avoided.
3837 : // When adding code here, add a DisallowHeapAllocation too.
3838 : }
3839 :
3840 237841 : void JSObject::ForceSetPrototype(Handle<JSObject> object,
3841 : Handle<Object> proto) {
3842 : // object.__proto__ = proto;
3843 : Handle<Map> old_map = Handle<Map>(object->map());
3844 237841 : Handle<Map> new_map = Map::Copy(old_map, "ForceSetPrototype");
3845 237841 : Map::SetPrototype(new_map, proto, FAST_PROTOTYPE);
3846 237841 : JSObject::MigrateToMap(object, new_map);
3847 237841 : }
3848 :
3849 56079468 : int Map::NumberOfFields() {
3850 : DescriptorArray* descriptors = instance_descriptors();
3851 : int result = 0;
3852 920305806 : for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
3853 808146863 : if (descriptors->GetDetails(i).location() == kField) result++;
3854 : }
3855 56079475 : return result;
3856 : }
3857 :
3858 9538819 : void DescriptorArray::GeneralizeAllFields() {
3859 9538819 : int length = number_of_descriptors();
3860 57942138 : for (int i = 0; i < length; i++) {
3861 38864494 : PropertyDetails details = GetDetails(i);
3862 : details = details.CopyWithRepresentation(Representation::Tagged());
3863 38864497 : if (details.location() == kField) {
3864 : DCHECK_EQ(kData, details.kind());
3865 : details = details.CopyWithConstness(kMutable);
3866 5113417 : SetValue(i, FieldType::Any());
3867 : }
3868 : set(ToDetailsIndex(i), details.AsSmi());
3869 : }
3870 9538823 : }
3871 :
3872 1947577 : Handle<Map> Map::CopyGeneralizeAllFields(Handle<Map> map,
3873 : ElementsKind elements_kind,
3874 : int modify_index, PropertyKind kind,
3875 : PropertyAttributes attributes,
3876 : const char* reason) {
3877 : Isolate* isolate = map->GetIsolate();
3878 : Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
3879 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
3880 : Handle<DescriptorArray> descriptors =
3881 : DescriptorArray::CopyUpTo(old_descriptors, number_of_own_descriptors);
3882 1947581 : descriptors->GeneralizeAllFields();
3883 :
3884 : Handle<LayoutDescriptor> new_layout_descriptor(
3885 : LayoutDescriptor::FastPointerLayout(), isolate);
3886 : Handle<Map> new_map = CopyReplaceDescriptors(
3887 : map, descriptors, new_layout_descriptor, OMIT_TRANSITION,
3888 1947579 : MaybeHandle<Name>(), reason, SPECIAL_TRANSITION);
3889 :
3890 : // Unless the instance is being migrated, ensure that modify_index is a field.
3891 1947579 : if (modify_index >= 0) {
3892 1947475 : PropertyDetails details = descriptors->GetDetails(modify_index);
3893 1950723 : if (details.constness() != kMutable || details.location() != kField ||
3894 : details.attributes() != attributes) {
3895 : int field_index = details.location() == kField
3896 : ? details.field_index()
3897 3892140 : : new_map->NumberOfFields();
3898 : Descriptor d = Descriptor::DataField(
3899 : handle(descriptors->GetKey(modify_index), isolate), field_index,
3900 1946288 : attributes, Representation::Tagged());
3901 1946289 : descriptors->Replace(modify_index, &d);
3902 1946288 : if (details.location() != kField) {
3903 1945850 : int unused_property_fields = new_map->unused_property_fields() - 1;
3904 1945850 : if (unused_property_fields < 0) {
3905 1597991 : unused_property_fields += JSObject::kFieldsAdded;
3906 : }
3907 : new_map->set_unused_property_fields(unused_property_fields);
3908 : }
3909 : } else {
3910 : DCHECK(details.attributes() == attributes);
3911 : }
3912 :
3913 1947474 : if (FLAG_trace_generalization) {
3914 0 : MaybeHandle<FieldType> field_type = FieldType::None(isolate);
3915 0 : if (details.location() == kField) {
3916 : field_type = handle(
3917 0 : map->instance_descriptors()->GetFieldType(modify_index), isolate);
3918 : }
3919 : map->PrintGeneralization(
3920 : stdout, reason, modify_index, new_map->NumberOfOwnDescriptors(),
3921 : new_map->NumberOfOwnDescriptors(), details.location() == kDescriptor,
3922 : details.representation(), Representation::Tagged(), field_type,
3923 : MaybeHandle<Object>(), FieldType::Any(isolate),
3924 0 : MaybeHandle<Object>());
3925 : }
3926 : }
3927 : new_map->set_elements_kind(elements_kind);
3928 1947578 : return new_map;
3929 : }
3930 :
3931 :
3932 324090 : void Map::DeprecateTransitionTree() {
3933 648180 : if (is_deprecated()) return;
3934 : Object* transitions = raw_transitions();
3935 324090 : int num_transitions = TransitionArray::NumberOfTransitions(transitions);
3936 482884 : for (int i = 0; i < num_transitions; ++i) {
3937 158794 : TransitionArray::GetTarget(transitions, i)->DeprecateTransitionTree();
3938 : }
3939 : DCHECK(!constructor_or_backpointer()->IsFunctionTemplateInfo());
3940 : deprecate();
3941 : dependent_code()->DeoptimizeDependentCodeGroup(
3942 324090 : GetIsolate(), DependentCode::kTransitionGroup);
3943 324090 : NotifyLeafMapLayoutChange();
3944 : }
3945 :
3946 :
3947 : // Installs |new_descriptors| over the current instance_descriptors to ensure
3948 : // proper sharing of descriptor arrays.
3949 167507 : void Map::ReplaceDescriptors(DescriptorArray* new_descriptors,
3950 : LayoutDescriptor* new_layout_descriptor) {
3951 : Isolate* isolate = GetIsolate();
3952 : // Don't overwrite the empty descriptor array or initial map's descriptors.
3953 216919 : if (NumberOfOwnDescriptors() == 0 || GetBackPointer()->IsUndefined(isolate)) {
3954 167507 : return;
3955 : }
3956 :
3957 : DescriptorArray* to_replace = instance_descriptors();
3958 48988 : isolate->heap()->incremental_marking()->IterateBlackObject(to_replace);
3959 : Map* current = this;
3960 255030 : while (current->instance_descriptors() == to_replace) {
3961 157465 : Object* next = current->GetBackPointer();
3962 157465 : if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map.
3963 : current->SetEnumLength(kInvalidEnumCacheSentinel);
3964 157054 : current->UpdateDescriptors(new_descriptors, new_layout_descriptor);
3965 : current = Map::cast(next);
3966 : }
3967 : set_owns_descriptors(false);
3968 : }
3969 :
3970 :
3971 2118690 : Map* Map::FindRootMap() {
3972 : Map* result = this;
3973 : Isolate* isolate = GetIsolate();
3974 : while (true) {
3975 9994548 : Object* back = result->GetBackPointer();
3976 9994548 : if (back->IsUndefined(isolate)) {
3977 : // Initial map always owns descriptors and doesn't have unused entries
3978 : // in the descriptor array.
3979 : DCHECK(result->owns_descriptors());
3980 : DCHECK_EQ(result->NumberOfOwnDescriptors(),
3981 : result->instance_descriptors()->number_of_descriptors());
3982 2118690 : return result;
3983 : }
3984 : result = Map::cast(back);
3985 : }
3986 : }
3987 :
3988 :
3989 967624 : Map* Map::FindFieldOwner(int descriptor) {
3990 : DisallowHeapAllocation no_allocation;
3991 : DCHECK_EQ(kField, instance_descriptors()->GetDetails(descriptor).location());
3992 : Map* result = this;
3993 : Isolate* isolate = GetIsolate();
3994 : while (true) {
3995 3425250 : Object* back = result->GetBackPointer();
3996 3425250 : if (back->IsUndefined(isolate)) break;
3997 : Map* parent = Map::cast(back);
3998 3425250 : if (parent->NumberOfOwnDescriptors() <= descriptor) break;
3999 : result = parent;
4000 : }
4001 967624 : return result;
4002 : }
4003 :
4004 551166 : void Map::UpdateFieldType(int descriptor, Handle<Name> name,
4005 : PropertyConstness new_constness,
4006 : Representation new_representation,
4007 : Handle<Object> new_wrapped_type) {
4008 : DCHECK(new_wrapped_type->IsSmi() || new_wrapped_type->IsWeakCell());
4009 : // We store raw pointers in the queue, so no allocations are allowed.
4010 : DisallowHeapAllocation no_allocation;
4011 551166 : PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
4012 551166 : if (details.location() != kField) return;
4013 : DCHECK_EQ(kData, details.kind());
4014 :
4015 551166 : Zone zone(GetIsolate()->allocator(), ZONE_NAME);
4016 551166 : ZoneQueue<Map*> backlog(&zone);
4017 1102332 : backlog.push(this);
4018 :
4019 4104071 : while (!backlog.empty()) {
4020 3001739 : Map* current = backlog.front();
4021 : backlog.pop();
4022 :
4023 : Object* transitions = current->raw_transitions();
4024 3001739 : int num_transitions = TransitionArray::NumberOfTransitions(transitions);
4025 5452312 : for (int i = 0; i < num_transitions; ++i) {
4026 2450573 : Map* target = TransitionArray::GetTarget(transitions, i);
4027 : backlog.push(target);
4028 : }
4029 : DescriptorArray* descriptors = current->instance_descriptors();
4030 3001739 : PropertyDetails details = descriptors->GetDetails(descriptor);
4031 :
4032 : // Currently constness change implies map change.
4033 : DCHECK_IMPLIES(new_constness != details.constness(),
4034 : FLAG_modify_map_inplace);
4035 :
4036 : // It is allowed to change representation here only from None to something.
4037 : DCHECK(details.representation().Equals(new_representation) ||
4038 : details.representation().IsNone());
4039 :
4040 : // Skip if already updated the shared descriptor.
4041 3001739 : if ((FLAG_modify_map_inplace && new_constness != details.constness()) ||
4042 : descriptors->GetValue(descriptor) != *new_wrapped_type) {
4043 : DCHECK_IMPLIES(!FLAG_track_constant_fields, new_constness == kMutable);
4044 : Descriptor d = Descriptor::DataField(
4045 : name, descriptors->GetFieldIndex(descriptor), details.attributes(),
4046 551218 : new_constness, new_representation, new_wrapped_type);
4047 551218 : descriptors->Replace(descriptor, &d);
4048 : }
4049 551166 : }
4050 : }
4051 :
4052 0 : bool FieldTypeIsCleared(Representation rep, FieldType* type) {
4053 4666473 : return type->IsNone() && rep.IsHeapObject();
4054 : }
4055 :
4056 :
4057 : // static
4058 2082491 : Handle<FieldType> Map::GeneralizeFieldType(Representation rep1,
4059 : Handle<FieldType> type1,
4060 : Representation rep2,
4061 : Handle<FieldType> type2,
4062 : Isolate* isolate) {
4063 : // Cleared field types need special treatment. They represent lost knowledge,
4064 : // so we must be conservative, so their generalization with any other type
4065 : // is "Any".
4066 4164920 : if (FieldTypeIsCleared(rep1, *type1) || FieldTypeIsCleared(rep2, *type2)) {
4067 9601 : return FieldType::Any(isolate);
4068 : }
4069 2072890 : if (type1->NowIs(type2)) return type2;
4070 177137 : if (type2->NowIs(type1)) return type1;
4071 99162 : return FieldType::Any(isolate);
4072 : }
4073 :
4074 :
4075 : // static
4076 886657 : void Map::GeneralizeField(Handle<Map> map, int modify_index,
4077 : PropertyConstness new_constness,
4078 : Representation new_representation,
4079 : Handle<FieldType> new_field_type) {
4080 : Isolate* isolate = map->GetIsolate();
4081 :
4082 : // Check if we actually need to generalize the field type at all.
4083 : Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
4084 886657 : PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
4085 : PropertyConstness old_constness = old_details.constness();
4086 : Representation old_representation = old_details.representation();
4087 : Handle<FieldType> old_field_type(old_descriptors->GetFieldType(modify_index),
4088 886657 : isolate);
4089 :
4090 : // Return if the current map is general enough to hold requested contness and
4091 : // representation/field type.
4092 886657 : if (((FLAG_modify_map_inplace &&
4093 : IsGeneralizableTo(new_constness, old_constness)) ||
4094 886657 : (!FLAG_modify_map_inplace && (old_constness == new_constness))) &&
4095 485319 : old_representation.Equals(new_representation) &&
4096 1371933 : !FieldTypeIsCleared(new_representation, *new_field_type) &&
4097 : // Checking old_field_type for being cleared is not necessary because
4098 : // the NowIs check below would fail anyway in that case.
4099 485276 : new_field_type->NowIs(old_field_type)) {
4100 : DCHECK(GeneralizeFieldType(old_representation, old_field_type,
4101 : new_representation, new_field_type, isolate)
4102 : ->NowIs(old_field_type));
4103 335491 : return;
4104 : }
4105 :
4106 : // Determine the field owner.
4107 551166 : Handle<Map> field_owner(map->FindFieldOwner(modify_index), isolate);
4108 : Handle<DescriptorArray> descriptors(
4109 : field_owner->instance_descriptors(), isolate);
4110 : DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index));
4111 :
4112 : new_field_type =
4113 : Map::GeneralizeFieldType(old_representation, old_field_type,
4114 551166 : new_representation, new_field_type, isolate);
4115 : if (FLAG_modify_map_inplace) {
4116 : new_constness = GeneralizeConstness(old_constness, new_constness);
4117 : }
4118 :
4119 551166 : PropertyDetails details = descriptors->GetDetails(modify_index);
4120 : Handle<Name> name(descriptors->GetKey(modify_index));
4121 :
4122 551166 : Handle<Object> wrapped_type(WrapFieldType(new_field_type));
4123 : field_owner->UpdateFieldType(modify_index, name, new_constness,
4124 551166 : new_representation, wrapped_type);
4125 : field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
4126 551166 : isolate, DependentCode::kFieldOwnerGroup);
4127 :
4128 551166 : if (FLAG_trace_generalization) {
4129 : map->PrintGeneralization(
4130 : stdout, "field type generalization", modify_index,
4131 : map->NumberOfOwnDescriptors(), map->NumberOfOwnDescriptors(), false,
4132 : details.representation(), details.representation(), old_field_type,
4133 0 : MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>());
4134 : }
4135 : }
4136 :
4137 : // TODO(ishell): remove.
4138 : // static
4139 596 : Handle<Map> Map::ReconfigureProperty(Handle<Map> map, int modify_index,
4140 : PropertyKind new_kind,
4141 : PropertyAttributes new_attributes,
4142 : Representation new_representation,
4143 : Handle<FieldType> new_field_type) {
4144 : DCHECK_EQ(kData, new_kind); // Only kData case is supported.
4145 596 : MapUpdater mu(map->GetIsolate(), map);
4146 : return mu.ReconfigureToDataField(modify_index, new_attributes, kConst,
4147 596 : new_representation, new_field_type);
4148 : }
4149 :
4150 : // TODO(ishell): remove.
4151 : // static
4152 652950 : Handle<Map> Map::ReconfigureElementsKind(Handle<Map> map,
4153 : ElementsKind new_elements_kind) {
4154 652950 : MapUpdater mu(map->GetIsolate(), map);
4155 652950 : return mu.ReconfigureElementsKind(new_elements_kind);
4156 : }
4157 :
4158 : // Generalize all fields and update the transition tree.
4159 1700 : Handle<Map> Map::GeneralizeAllFields(Handle<Map> map) {
4160 : Isolate* isolate = map->GetIsolate();
4161 1700 : Handle<FieldType> any_type = FieldType::Any(isolate);
4162 :
4163 : Handle<DescriptorArray> descriptors(map->instance_descriptors());
4164 7226 : for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) {
4165 1913 : PropertyDetails details = descriptors->GetDetails(i);
4166 1913 : if (details.location() == kField) {
4167 : DCHECK_EQ(kData, details.kind());
4168 1013 : MapUpdater mu(isolate, map);
4169 : map = mu.ReconfigureToDataField(i, details.attributes(), kMutable,
4170 1013 : Representation::Tagged(), any_type);
4171 : }
4172 : }
4173 1700 : return map;
4174 : }
4175 :
4176 :
4177 : // static
4178 359200 : MaybeHandle<Map> Map::TryUpdate(Handle<Map> old_map) {
4179 : DisallowHeapAllocation no_allocation;
4180 : DisallowDeoptimization no_deoptimization(old_map->GetIsolate());
4181 :
4182 359200 : if (!old_map->is_deprecated()) return old_map;
4183 :
4184 : // Check the state of the root map.
4185 2635 : Map* root_map = old_map->FindRootMap();
4186 2635 : if (root_map->is_deprecated()) {
4187 0 : JSFunction* constructor = JSFunction::cast(root_map->GetConstructor());
4188 : DCHECK(constructor->has_initial_map());
4189 : DCHECK(constructor->initial_map()->is_dictionary_map());
4190 0 : if (constructor->initial_map()->elements_kind() !=
4191 : old_map->elements_kind()) {
4192 : return MaybeHandle<Map>();
4193 : }
4194 : return handle(constructor->initial_map());
4195 : }
4196 2635 : if (!old_map->EquivalentToForTransition(root_map)) return MaybeHandle<Map>();
4197 :
4198 : ElementsKind from_kind = root_map->elements_kind();
4199 : ElementsKind to_kind = old_map->elements_kind();
4200 2551 : if (from_kind != to_kind) {
4201 : // Try to follow existing elements kind transitions.
4202 : root_map = root_map->LookupElementsTransitionMap(to_kind);
4203 18 : if (root_map == NULL) return MaybeHandle<Map>();
4204 : // From here on, use the map with correct elements kind as root map.
4205 : }
4206 2551 : Map* new_map = root_map->TryReplayPropertyTransitions(*old_map);
4207 2551 : if (new_map == nullptr) return MaybeHandle<Map>();
4208 : return handle(new_map);
4209 : }
4210 :
4211 154198 : Map* Map::TryReplayPropertyTransitions(Map* old_map) {
4212 : DisallowHeapAllocation no_allocation;
4213 : DisallowDeoptimization no_deoptimization(GetIsolate());
4214 :
4215 : int root_nof = NumberOfOwnDescriptors();
4216 :
4217 : int old_nof = old_map->NumberOfOwnDescriptors();
4218 : DescriptorArray* old_descriptors = old_map->instance_descriptors();
4219 :
4220 : Map* new_map = this;
4221 163534 : for (int i = root_nof; i < old_nof; ++i) {
4222 13900 : PropertyDetails old_details = old_descriptors->GetDetails(i);
4223 : Map* transition = TransitionArray::SearchTransition(
4224 : new_map, old_details.kind(), old_descriptors->GetKey(i),
4225 13900 : old_details.attributes());
4226 13900 : if (transition == NULL) return nullptr;
4227 : new_map = transition;
4228 : DescriptorArray* new_descriptors = new_map->instance_descriptors();
4229 :
4230 9416 : PropertyDetails new_details = new_descriptors->GetDetails(i);
4231 : DCHECK_EQ(old_details.kind(), new_details.kind());
4232 : DCHECK_EQ(old_details.attributes(), new_details.attributes());
4233 9416 : if (!IsGeneralizableTo(old_details.constness(), new_details.constness())) {
4234 : return nullptr;
4235 : }
4236 : DCHECK(IsGeneralizableTo(old_details.location(), new_details.location()));
4237 28248 : if (!old_details.representation().fits_into(new_details.representation())) {
4238 : return nullptr;
4239 : }
4240 9364 : if (new_details.location() == kField) {
4241 9185 : if (new_details.kind() == kData) {
4242 9185 : FieldType* new_type = new_descriptors->GetFieldType(i);
4243 : // Cleared field types need special treatment. They represent lost
4244 : // knowledge, so we must first generalize the new_type to "Any".
4245 9185 : if (FieldTypeIsCleared(new_details.representation(), new_type)) {
4246 : return nullptr;
4247 : }
4248 : DCHECK_EQ(kData, old_details.kind());
4249 9185 : if (old_details.location() == kField) {
4250 7049 : FieldType* old_type = old_descriptors->GetFieldType(i);
4251 14098 : if (FieldTypeIsCleared(old_details.representation(), old_type) ||
4252 7049 : !old_type->NowIs(new_type)) {
4253 : return nullptr;
4254 : }
4255 : } else {
4256 : DCHECK_EQ(kDescriptor, old_details.location());
4257 : DCHECK(!FLAG_track_constant_fields);
4258 : Object* old_value = old_descriptors->GetValue(i);
4259 2136 : if (!new_type->NowContains(old_value)) {
4260 : return nullptr;
4261 : }
4262 : }
4263 :
4264 : } else {
4265 : DCHECK_EQ(kAccessor, new_details.kind());
4266 : #ifdef DEBUG
4267 : FieldType* new_type = new_descriptors->GetFieldType(i);
4268 : DCHECK(new_type->IsAny());
4269 : #endif
4270 0 : UNREACHABLE();
4271 : }
4272 : } else {
4273 : DCHECK_EQ(kDescriptor, new_details.location());
4274 : Object* old_value = old_descriptors->GetValue(i);
4275 : Object* new_value = new_descriptors->GetValue(i);
4276 179 : if (old_details.location() == kField || old_value != new_value) {
4277 : return nullptr;
4278 : }
4279 : }
4280 : }
4281 149634 : if (new_map->NumberOfOwnDescriptors() != old_nof) return nullptr;
4282 149634 : return new_map;
4283 : }
4284 :
4285 :
4286 : // static
4287 41308178 : Handle<Map> Map::Update(Handle<Map> map) {
4288 41308178 : if (!map->is_deprecated()) return map;
4289 10342 : MapUpdater mu(map->GetIsolate(), map);
4290 10342 : return mu.Update();
4291 : }
4292 :
4293 225641 : Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
4294 : ShouldThrow should_throw,
4295 : Handle<Object> value) {
4296 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
4297 : return SetPropertyWithInterceptorInternal(it, it->GetInterceptor(),
4298 225641 : should_throw, value);
4299 : }
4300 :
4301 4262159 : MaybeHandle<Object> Object::SetProperty(Handle<Object> object,
4302 : Handle<Name> name, Handle<Object> value,
4303 : LanguageMode language_mode,
4304 : StoreFromKeyed store_mode) {
4305 4262159 : LookupIterator it(object, name);
4306 4262159 : MAYBE_RETURN_NULL(SetProperty(&it, value, language_mode, store_mode));
4307 : return value;
4308 : }
4309 :
4310 :
4311 34000822 : Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
4312 : Handle<Object> value,
4313 : LanguageMode language_mode,
4314 : StoreFromKeyed store_mode,
4315 : bool* found) {
4316 16764916 : it->UpdateProtector();
4317 : DCHECK(it->IsFound());
4318 : ShouldThrow should_throw =
4319 16764916 : is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4320 :
4321 : // Make sure that the top context does not change when doing callbacks or
4322 : // interceptor calls.
4323 : AssertNoContextChange ncc(it->isolate());
4324 :
4325 312981 : do {
4326 16922925 : switch (it->state()) {
4327 : case LookupIterator::NOT_FOUND:
4328 0 : UNREACHABLE();
4329 :
4330 : case LookupIterator::ACCESS_CHECK:
4331 87928 : if (it->HasAccess()) break;
4332 : // Check whether it makes sense to reuse the lookup iterator. Here it
4333 : // might still call into setters up the prototype chain.
4334 : return JSObject::SetPropertyWithFailedAccessCheck(it, value,
4335 131 : should_throw);
4336 :
4337 : case LookupIterator::JSPROXY:
4338 : return JSProxy::SetProperty(it->GetHolder<JSProxy>(), it->GetName(),
4339 63039 : value, it->GetReceiver(), language_mode);
4340 :
4341 : case LookupIterator::INTERCEPTOR: {
4342 225664 : if (it->HolderIsReceiverOrHiddenPrototype()) {
4343 : Maybe<bool> result =
4344 225382 : JSObject::SetPropertyWithInterceptor(it, should_throw, value);
4345 450764 : if (result.IsNothing() || result.FromJust()) return result;
4346 : } else {
4347 : Maybe<PropertyAttributes> maybe_attributes =
4348 282 : JSObject::GetPropertyAttributesWithInterceptor(it);
4349 449 : if (!maybe_attributes.IsJust()) return Nothing<bool>();
4350 282 : if ((maybe_attributes.FromJust() & READ_ONLY) != 0) {
4351 0 : return WriteToReadOnlyProperty(it, value, should_throw);
4352 : }
4353 282 : if (maybe_attributes.FromJust() == ABSENT) break;
4354 167 : *found = false;
4355 : return Nothing<bool>();
4356 : }
4357 : break;
4358 : }
4359 :
4360 : case LookupIterator::ACCESSOR: {
4361 411341 : if (it->IsReadOnly()) {
4362 2651 : return WriteToReadOnlyProperty(it, value, should_throw);
4363 : }
4364 408690 : Handle<Object> accessors = it->GetAccessors();
4365 619410 : if (accessors->IsAccessorInfo() &&
4366 549681 : !it->HolderIsReceiverOrHiddenPrototype() &&
4367 : AccessorInfo::cast(*accessors)->is_special_data_property()) {
4368 713 : *found = false;
4369 : return Nothing<bool>();
4370 : }
4371 407977 : return SetPropertyWithAccessor(it, value, should_throw);
4372 : }
4373 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
4374 : // TODO(verwaest): We should throw an exception if holder is receiver.
4375 : return Just(true);
4376 :
4377 : case LookupIterator::DATA:
4378 14689502 : if (it->IsReadOnly()) {
4379 44336 : return WriteToReadOnlyProperty(it, value, should_throw);
4380 : }
4381 14645166 : if (it->HolderIsReceiverOrHiddenPrototype()) {
4382 14499107 : return SetDataProperty(it, value);
4383 : }
4384 : // Fall through.
4385 : case LookupIterator::TRANSITION:
4386 1588699 : *found = false;
4387 : return Nothing<bool>();
4388 : }
4389 312981 : it->Next();
4390 : } while (it->IsFound());
4391 :
4392 154972 : *found = false;
4393 : return Nothing<bool>();
4394 : }
4395 :
4396 :
4397 35797626 : Maybe<bool> Object::SetProperty(LookupIterator* it, Handle<Object> value,
4398 : LanguageMode language_mode,
4399 : StoreFromKeyed store_mode) {
4400 35795776 : if (it->IsFound()) {
4401 16697310 : bool found = true;
4402 : Maybe<bool> result =
4403 16697310 : SetPropertyInternal(it, value, language_mode, store_mode, &found);
4404 16697310 : if (found) return result;
4405 : }
4406 :
4407 : // If the receiver is the JSGlobalObject, the store was contextual. In case
4408 : // the property did not exist yet on the global object itself, we have to
4409 : // throw a reference error in strict mode. In sloppy mode, we continue.
4410 35888256 : if (is_strict(language_mode) && it->GetReceiver()->IsJSGlobalObject()) {
4411 : it->isolate()->Throw(*it->isolate()->factory()->NewReferenceError(
4412 1850 : MessageTemplate::kNotDefined, it->name()));
4413 : return Nothing<bool>();
4414 : }
4415 :
4416 : ShouldThrow should_throw =
4417 20838756 : is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4418 20838756 : return AddDataProperty(it, value, NONE, should_throw, store_mode);
4419 : }
4420 :
4421 :
4422 81956 : Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
4423 : LanguageMode language_mode,
4424 : StoreFromKeyed store_mode) {
4425 : Isolate* isolate = it->isolate();
4426 :
4427 73680 : if (it->IsFound()) {
4428 67606 : bool found = true;
4429 : Maybe<bool> result =
4430 67606 : SetPropertyInternal(it, value, language_mode, store_mode, &found);
4431 67606 : if (found) return result;
4432 : }
4433 :
4434 9410 : it->UpdateProtector();
4435 :
4436 : // The property either doesn't exist on the holder or exists there as a data
4437 : // property.
4438 :
4439 : ShouldThrow should_throw =
4440 9410 : is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4441 :
4442 9410 : if (!it->GetReceiver()->IsJSReceiver()) {
4443 1134 : return WriteToReadOnlyProperty(it, value, should_throw);
4444 : }
4445 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
4446 :
4447 : LookupIterator::Configuration c = LookupIterator::OWN;
4448 : LookupIterator own_lookup =
4449 : it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c)
4450 16552 : : LookupIterator(receiver, it->name(), c);
4451 :
4452 28 : for (; own_lookup.IsFound(); own_lookup.Next()) {
4453 6162 : switch (own_lookup.state()) {
4454 : case LookupIterator::ACCESS_CHECK:
4455 34 : if (!own_lookup.HasAccess()) {
4456 : return JSObject::SetPropertyWithFailedAccessCheck(&own_lookup, value,
4457 6 : should_throw);
4458 : }
4459 : break;
4460 :
4461 : case LookupIterator::ACCESSOR:
4462 3052 : if (own_lookup.GetAccessors()->IsAccessorInfo()) {
4463 14 : if (own_lookup.IsReadOnly()) {
4464 0 : return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
4465 : }
4466 : return JSObject::SetPropertyWithAccessor(&own_lookup, value,
4467 14 : should_throw);
4468 : }
4469 : // Fall through.
4470 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
4471 : return RedefineIncompatibleProperty(isolate, it->GetName(), value,
4472 3024 : should_throw);
4473 :
4474 : case LookupIterator::DATA: {
4475 1526 : if (own_lookup.IsReadOnly()) {
4476 462 : return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
4477 : }
4478 1064 : return SetDataProperty(&own_lookup, value);
4479 : }
4480 :
4481 : case LookupIterator::INTERCEPTOR:
4482 : case LookupIterator::JSPROXY: {
4483 : PropertyDescriptor desc;
4484 : Maybe<bool> owned =
4485 3076 : JSReceiver::GetOwnPropertyDescriptor(&own_lookup, &desc);
4486 3076 : MAYBE_RETURN(owned, Nothing<bool>());
4487 2376 : if (!owned.FromJust()) {
4488 : return JSReceiver::CreateDataProperty(&own_lookup, value,
4489 1057 : should_throw);
4490 : }
4491 2638 : if (PropertyDescriptor::IsAccessorDescriptor(&desc) ||
4492 : !desc.writable()) {
4493 : return RedefineIncompatibleProperty(isolate, it->GetName(), value,
4494 0 : should_throw);
4495 : }
4496 :
4497 : PropertyDescriptor value_desc;
4498 : value_desc.set_value(value);
4499 : return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
4500 2638 : &value_desc, should_throw);
4501 : }
4502 :
4503 : case LookupIterator::NOT_FOUND:
4504 : case LookupIterator::TRANSITION:
4505 0 : UNREACHABLE();
4506 : }
4507 : }
4508 :
4509 2142 : return AddDataProperty(&own_lookup, value, NONE, should_throw, store_mode);
4510 : }
4511 :
4512 9541 : Maybe<bool> Object::CannotCreateProperty(Isolate* isolate,
4513 : Handle<Object> receiver,
4514 : Handle<Object> name,
4515 : Handle<Object> value,
4516 : ShouldThrow should_throw) {
4517 9917 : RETURN_FAILURE(
4518 : isolate, should_throw,
4519 : NewTypeError(MessageTemplate::kStrictCannotCreateProperty, name,
4520 : Object::TypeOf(isolate, receiver), receiver));
4521 : }
4522 :
4523 :
4524 97166 : Maybe<bool> Object::WriteToReadOnlyProperty(LookupIterator* it,
4525 : Handle<Object> value,
4526 : ShouldThrow should_throw) {
4527 : return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(),
4528 97166 : it->GetName(), value, should_throw);
4529 : }
4530 :
4531 :
4532 48583 : Maybe<bool> Object::WriteToReadOnlyProperty(Isolate* isolate,
4533 : Handle<Object> receiver,
4534 : Handle<Object> name,
4535 : Handle<Object> value,
4536 : ShouldThrow should_throw) {
4537 79245 : RETURN_FAILURE(isolate, should_throw,
4538 : NewTypeError(MessageTemplate::kStrictReadOnlyProperty, name,
4539 : Object::TypeOf(isolate, receiver), receiver));
4540 : }
4541 :
4542 :
4543 1527 : Maybe<bool> Object::RedefineIncompatibleProperty(Isolate* isolate,
4544 : Handle<Object> name,
4545 : Handle<Object> value,
4546 : ShouldThrow should_throw) {
4547 1893 : RETURN_FAILURE(isolate, should_throw,
4548 : NewTypeError(MessageTemplate::kRedefineDisallowed, name));
4549 : }
4550 :
4551 :
4552 31008692 : Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) {
4553 : // Proxies are handled elsewhere. Other non-JSObjects cannot have own
4554 : // properties.
4555 : Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
4556 :
4557 : // Store on the holder which may be hidden behind the receiver.
4558 : DCHECK(it->HolderIsReceiverOrHiddenPrototype());
4559 :
4560 15500616 : Handle<Object> to_assign = value;
4561 : // Convert the incoming value to a number for storing into typed arrays.
4562 16844465 : if (it->IsElement() && receiver->HasFixedTypedArrayElements()) {
4563 1170047 : if (!value->IsNumber() && !value->IsUndefined(it->isolate())) {
4564 5292 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4565 : it->isolate(), to_assign, Object::ToNumber(value), Nothing<bool>());
4566 : // We have to recheck the length. However, it can only change if the
4567 : // underlying buffer was neutered, so just check that.
4568 2646 : if (Handle<JSArrayBufferView>::cast(receiver)->WasNeutered()) {
4569 : return Just(true);
4570 : // TODO(neis): According to the spec, this should throw a TypeError.
4571 : }
4572 : }
4573 : }
4574 :
4575 : // Possibly migrate to the most up-to-date map that will be able to store
4576 : // |value| under it->name().
4577 15500616 : it->PrepareForDataProperty(to_assign);
4578 :
4579 : // Write the property value.
4580 15500616 : it->WriteDataValue(to_assign, false);
4581 :
4582 : #if VERIFY_HEAP
4583 : if (FLAG_verify_heap) {
4584 : receiver->JSObjectVerify();
4585 : }
4586 : #endif
4587 : return Just(true);
4588 : }
4589 :
4590 :
4591 173082748 : Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value,
4592 : PropertyAttributes attributes,
4593 : ShouldThrow should_throw,
4594 : StoreFromKeyed store_mode) {
4595 56016474 : if (!it->GetReceiver()->IsJSObject()) {
4596 9625 : if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate()) {
4597 70 : RETURN_FAILURE(it->isolate(), should_throw,
4598 : NewTypeError(MessageTemplate::kProxyPrivate));
4599 : }
4600 : return CannotCreateProperty(it->isolate(), it->GetReceiver(), it->GetName(),
4601 19082 : value, should_throw);
4602 : }
4603 :
4604 : DCHECK_NE(LookupIterator::INTEGER_INDEXED_EXOTIC, it->state());
4605 :
4606 56006891 : Handle<JSObject> receiver = it->GetStoreTarget();
4607 :
4608 : // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject)
4609 : // instead. If the prototype is Null, the proxy is detached.
4610 56006844 : if (receiver->IsJSGlobalProxy()) return Just(true);
4611 :
4612 : Isolate* isolate = it->isolate();
4613 :
4614 56006844 : if (it->ExtendingNonExtensible(receiver)) {
4615 607516 : RETURN_FAILURE(
4616 : isolate, should_throw,
4617 : NewTypeError(MessageTemplate::kObjectNotExtensible, it->GetName()));
4618 : }
4619 :
4620 55851604 : if (it->IsElement()) {
4621 3679372 : if (receiver->IsJSArray()) {
4622 : Handle<JSArray> array = Handle<JSArray>::cast(receiver);
4623 1519342 : if (JSArray::WouldChangeReadOnlyLength(array, it->index())) {
4624 1719 : RETURN_FAILURE(array->GetIsolate(), should_throw,
4625 : NewTypeError(MessageTemplate::kStrictReadOnlyProperty,
4626 : isolate->factory()->length_string(),
4627 : Object::TypeOf(isolate, array), array));
4628 : }
4629 :
4630 1518880 : if (FLAG_trace_external_array_abuse &&
4631 0 : array->HasFixedTypedArrayElements()) {
4632 0 : CheckArrayAbuse(array, "typed elements write", it->index(), true);
4633 : }
4634 :
4635 1518880 : if (FLAG_trace_js_array_abuse && !array->HasFixedTypedArrayElements()) {
4636 0 : CheckArrayAbuse(array, "elements write", it->index(), false);
4637 : }
4638 : }
4639 :
4640 : Maybe<bool> result = JSObject::AddDataElement(receiver, it->index(), value,
4641 3678910 : attributes, should_throw);
4642 : JSObject::ValidateElements(receiver);
4643 3678910 : return result;
4644 : } else {
4645 52172232 : it->UpdateProtector();
4646 : // Migrate to the most up-to-date map that will be able to store |value|
4647 : // under it->name() with |attributes|.
4648 : it->PrepareTransitionToDataProperty(receiver, value, attributes,
4649 52172236 : store_mode);
4650 : DCHECK_EQ(LookupIterator::TRANSITION, it->state());
4651 52172277 : it->ApplyTransitionToDataProperty(receiver);
4652 :
4653 : // Write the property value.
4654 52172261 : it->WriteDataValue(value, true);
4655 :
4656 : #if VERIFY_HEAP
4657 : if (FLAG_verify_heap) {
4658 : receiver->JSObjectVerify();
4659 : }
4660 : #endif
4661 : }
4662 :
4663 : return Just(true);
4664 : }
4665 :
4666 :
4667 5831580 : void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
4668 : // Only supports adding slack to owned descriptors.
4669 : DCHECK(map->owns_descriptors());
4670 :
4671 : Handle<DescriptorArray> descriptors(map->instance_descriptors());
4672 : int old_size = map->NumberOfOwnDescriptors();
4673 5831580 : if (slack <= descriptors->NumberOfSlackDescriptors()) return;
4674 :
4675 : Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
4676 : descriptors, old_size, slack);
4677 :
4678 : DisallowHeapAllocation no_allocation;
4679 : // The descriptors are still the same, so keep the layout descriptor.
4680 : LayoutDescriptor* layout_descriptor = map->GetLayoutDescriptor();
4681 :
4682 5831581 : if (old_size == 0) {
4683 2669 : map->UpdateDescriptors(*new_descriptors, layout_descriptor);
4684 2669 : return;
4685 : }
4686 :
4687 : // If the source descriptors had an enum cache we copy it. This ensures
4688 : // that the maps to which we push the new descriptor array back can rely
4689 : // on a cache always being available once it is set. If the map has more
4690 : // enumerated descriptors than available in the original cache, the cache
4691 : // will be lazily replaced by the extended cache when needed.
4692 5828912 : if (descriptors->HasEnumCache()) {
4693 36845 : new_descriptors->CopyEnumCacheFrom(*descriptors);
4694 : }
4695 :
4696 : Isolate* isolate = map->GetIsolate();
4697 : // Replace descriptors by new_descriptors in all maps that share it.
4698 5828911 : isolate->heap()->incremental_marking()->IterateBlackObject(*descriptors);
4699 :
4700 : Map* current = *map;
4701 49684512 : while (current->instance_descriptors() == *descriptors) {
4702 38027269 : Object* next = current->GetBackPointer();
4703 38027274 : if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map.
4704 38026698 : current->UpdateDescriptors(*new_descriptors, layout_descriptor);
4705 : current = Map::cast(next);
4706 : }
4707 5828908 : map->UpdateDescriptors(*new_descriptors, layout_descriptor);
4708 : }
4709 :
4710 : // static
4711 189312 : Handle<Map> Map::GetObjectCreateMap(Handle<HeapObject> prototype) {
4712 : Isolate* isolate = prototype->GetIsolate();
4713 : Handle<Map> map(isolate->native_context()->object_function()->initial_map(),
4714 378624 : isolate);
4715 189312 : if (map->prototype() == *prototype) return map;
4716 189283 : if (prototype->IsNull(isolate)) {
4717 559 : return isolate->slow_object_with_null_prototype_map();
4718 : }
4719 188724 : if (prototype->IsJSObject()) {
4720 : Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype);
4721 187616 : if (!js_prototype->map()->is_prototype_map()) {
4722 183690 : JSObject::OptimizeAsPrototype(js_prototype, FAST_PROTOTYPE);
4723 : }
4724 : Handle<PrototypeInfo> info =
4725 187616 : Map::GetOrCreatePrototypeInfo(js_prototype, isolate);
4726 : // TODO(verwaest): Use inobject slack tracking for this map.
4727 187616 : if (info->HasObjectCreateMap()) {
4728 : map = handle(info->ObjectCreateMap(), isolate);
4729 : } else {
4730 187555 : map = Map::CopyInitialMap(map);
4731 187555 : Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
4732 187555 : PrototypeInfo::SetObjectCreateMap(info, map);
4733 : }
4734 187616 : return map;
4735 : }
4736 :
4737 1108 : return Map::TransitionToPrototype(map, prototype, REGULAR_PROTOTYPE);
4738 : }
4739 :
4740 : template <class T>
4741 63307 : static int AppendUniqueCallbacks(Handle<TemplateList> callbacks,
4742 : Handle<typename T::Array> array,
4743 : int valid_descriptors) {
4744 : int nof_callbacks = callbacks->length();
4745 :
4746 : Isolate* isolate = array->GetIsolate();
4747 : // Ensure the keys are unique names before writing them into the
4748 : // instance descriptor. Since it may cause a GC, it has to be done before we
4749 : // temporarily put the heap in an invalid state while appending descriptors.
4750 190250 : for (int i = 0; i < nof_callbacks; ++i) {
4751 : Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
4752 64211 : if (entry->name()->IsUniqueName()) continue;
4753 : Handle<String> key =
4754 : isolate->factory()->InternalizeString(
4755 63061 : Handle<String>(String::cast(entry->name())));
4756 63061 : entry->set_name(*key);
4757 : }
4758 :
4759 : // Fill in new callback descriptors. Process the callbacks from
4760 : // back to front so that the last callback with a given name takes
4761 : // precedence over previously added callbacks with that name.
4762 126943 : for (int i = nof_callbacks - 1; i >= 0; i--) {
4763 : Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
4764 : Handle<Name> key(Name::cast(entry->name()));
4765 : // Check if a descriptor with this name already exists before writing.
4766 63636 : if (!T::Contains(key, entry, valid_descriptors, array)) {
4767 0 : T::Insert(key, entry, valid_descriptors, array);
4768 63622 : valid_descriptors++;
4769 : }
4770 : }
4771 :
4772 63307 : return valid_descriptors;
4773 : }
4774 :
4775 : struct DescriptorArrayAppender {
4776 : typedef DescriptorArray Array;
4777 : static bool Contains(Handle<Name> key,
4778 : Handle<AccessorInfo> entry,
4779 : int valid_descriptors,
4780 : Handle<DescriptorArray> array) {
4781 : DisallowHeapAllocation no_gc;
4782 : return array->Search(*key, valid_descriptors) != DescriptorArray::kNotFound;
4783 : }
4784 0 : static void Insert(Handle<Name> key,
4785 : Handle<AccessorInfo> entry,
4786 : int valid_descriptors,
4787 : Handle<DescriptorArray> array) {
4788 : DisallowHeapAllocation no_gc;
4789 : Descriptor d =
4790 : Descriptor::AccessorConstant(key, entry, entry->property_attributes());
4791 0 : array->Append(&d);
4792 0 : }
4793 : };
4794 :
4795 :
4796 : struct FixedArrayAppender {
4797 : typedef FixedArray Array;
4798 63636 : static bool Contains(Handle<Name> key,
4799 : Handle<AccessorInfo> entry,
4800 : int valid_descriptors,
4801 : Handle<FixedArray> array) {
4802 609 : for (int i = 0; i < valid_descriptors; i++) {
4803 623 : if (*key == AccessorInfo::cast(array->get(i))->name()) return true;
4804 : }
4805 : return false;
4806 : }
4807 : static void Insert(Handle<Name> key,
4808 : Handle<AccessorInfo> entry,
4809 : int valid_descriptors,
4810 : Handle<FixedArray> array) {
4811 : DisallowHeapAllocation no_gc;
4812 63622 : array->set(valid_descriptors, *entry);
4813 : }
4814 : };
4815 :
4816 :
4817 0 : void Map::AppendCallbackDescriptors(Handle<Map> map,
4818 : Handle<Object> descriptors) {
4819 : int nof = map->NumberOfOwnDescriptors();
4820 : Handle<DescriptorArray> array(map->instance_descriptors());
4821 0 : Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors);
4822 : DCHECK_GE(array->NumberOfSlackDescriptors(), callbacks->length());
4823 0 : nof = AppendUniqueCallbacks<DescriptorArrayAppender>(callbacks, array, nof);
4824 : map->SetNumberOfOwnDescriptors(nof);
4825 0 : }
4826 :
4827 :
4828 63307 : int AccessorInfo::AppendUnique(Handle<Object> descriptors,
4829 : Handle<FixedArray> array,
4830 : int valid_descriptors) {
4831 63307 : Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors);
4832 : DCHECK_GE(array->length(), callbacks->length() + valid_descriptors);
4833 : return AppendUniqueCallbacks<FixedArrayAppender>(callbacks, array,
4834 63307 : valid_descriptors);
4835 : }
4836 :
4837 :
4838 317859 : static bool ContainsMap(MapHandleList* maps, Map* map) {
4839 : DCHECK_NOT_NULL(map);
4840 488624 : for (int i = 0; i < maps->length(); ++i) {
4841 393930 : if (!maps->at(i).is_null() && *maps->at(i) == map) return true;
4842 : }
4843 : return false;
4844 : }
4845 :
4846 98675 : Map* Map::FindElementsKindTransitionedMap(MapHandleList* candidates) {
4847 : DisallowHeapAllocation no_allocation;
4848 : DisallowDeoptimization no_deoptimization(GetIsolate());
4849 :
4850 : ElementsKind kind = elements_kind();
4851 : bool packed = IsFastPackedElementsKind(kind);
4852 :
4853 : Map* transition = nullptr;
4854 98675 : if (IsTransitionableFastElementsKind(kind)) {
4855 : // Check the state of the root map.
4856 48921 : Map* root_map = FindRootMap();
4857 48921 : if (!EquivalentToForTransition(root_map)) return nullptr;
4858 : root_map = root_map->LookupElementsTransitionMap(kind);
4859 : DCHECK_NOT_NULL(root_map);
4860 : // Starting from the next existing elements kind transition try to
4861 : // replay the property transitions that does not involve instance rewriting
4862 : // (ElementsTransitionAndStoreStub does not support that).
4863 249489 : for (root_map = root_map->ElementsTransitionMap();
4864 355119 : root_map != nullptr && root_map->has_fast_elements();
4865 : root_map = root_map->ElementsTransitionMap()) {
4866 151647 : Map* current = root_map->TryReplayPropertyTransitions(this);
4867 151647 : if (current == nullptr) continue;
4868 147124 : if (InstancesNeedRewriting(current)) continue;
4869 :
4870 294188 : if (ContainsMap(candidates, current) &&
4871 5018 : (packed || !IsFastPackedElementsKind(current->elements_kind()))) {
4872 : transition = current;
4873 46969 : packed = packed && IsFastPackedElementsKind(current->elements_kind());
4874 : }
4875 : }
4876 : }
4877 98675 : return transition;
4878 : }
4879 :
4880 :
4881 1577782 : static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
4882 : // Ensure we are requested to search elements kind transition "near the root".
4883 : DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(),
4884 : map->NumberOfOwnDescriptors());
4885 : Map* current_map = map;
4886 :
4887 : ElementsKind kind = map->elements_kind();
4888 5515597 : while (kind != to_kind) {
4889 : Map* next_map = current_map->ElementsTransitionMap();
4890 2622239 : if (next_map == nullptr) return current_map;
4891 : kind = next_map->elements_kind();
4892 : current_map = next_map;
4893 : }
4894 :
4895 : DCHECK_EQ(to_kind, current_map->elements_kind());
4896 : return current_map;
4897 : }
4898 :
4899 :
4900 0 : Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) {
4901 48939 : Map* to_map = FindClosestElementsTransition(this, to_kind);
4902 48939 : if (to_map->elements_kind() == to_kind) return to_map;
4903 : return nullptr;
4904 : }
4905 :
4906 :
4907 416927 : bool Map::IsMapInArrayPrototypeChain() {
4908 : Isolate* isolate = GetIsolate();
4909 833854 : if (isolate->initial_array_prototype()->map() == this) {
4910 : return true;
4911 : }
4912 :
4913 832164 : if (isolate->initial_object_prototype()->map() == this) {
4914 : return true;
4915 : }
4916 :
4917 415838 : return false;
4918 : }
4919 :
4920 :
4921 20640027 : Handle<WeakCell> Map::WeakCellForMap(Handle<Map> map) {
4922 : Isolate* isolate = map->GetIsolate();
4923 20640026 : if (map->weak_cell_cache()->IsWeakCell()) {
4924 8420738 : return Handle<WeakCell>(WeakCell::cast(map->weak_cell_cache()));
4925 : }
4926 12219288 : Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(map);
4927 12219290 : map->set_weak_cell_cache(*weak_cell);
4928 12219291 : return weak_cell;
4929 : }
4930 :
4931 :
4932 262206 : static Handle<Map> AddMissingElementsTransitions(Handle<Map> map,
4933 : ElementsKind to_kind) {
4934 : DCHECK(IsTransitionElementsKind(map->elements_kind()));
4935 :
4936 : Handle<Map> current_map = map;
4937 :
4938 : ElementsKind kind = map->elements_kind();
4939 : TransitionFlag flag;
4940 262206 : if (map->is_prototype_map()) {
4941 : flag = OMIT_TRANSITION;
4942 : } else {
4943 : flag = INSERT_TRANSITION;
4944 259852 : if (IsFastElementsKind(kind)) {
4945 537558 : while (kind != to_kind && !IsTerminalElementsKind(kind)) {
4946 10459 : kind = GetNextTransitionElementsKind(kind);
4947 10459 : current_map = Map::CopyAsElementsKind(current_map, kind, flag);
4948 : }
4949 : }
4950 : }
4951 :
4952 : // In case we are exiting the fast elements kind system, just add the map in
4953 : // the end.
4954 262206 : if (kind != to_kind) {
4955 259420 : current_map = Map::CopyAsElementsKind(current_map, to_kind, flag);
4956 : }
4957 :
4958 : DCHECK(current_map->elements_kind() == to_kind);
4959 262206 : return current_map;
4960 : }
4961 :
4962 :
4963 2600915 : Handle<Map> Map::TransitionElementsTo(Handle<Map> map,
4964 : ElementsKind to_kind) {
4965 : ElementsKind from_kind = map->elements_kind();
4966 2600915 : if (from_kind == to_kind) return map;
4967 :
4968 1505623 : Isolate* isolate = map->GetIsolate();
4969 : Context* native_context = isolate->context()->native_context();
4970 1505623 : if (from_kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
4971 532 : if (*map == native_context->fast_aliased_arguments_map()) {
4972 : DCHECK_EQ(SLOW_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
4973 : return handle(native_context->slow_aliased_arguments_map());
4974 : }
4975 1505091 : } else if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
4976 30 : if (*map == native_context->slow_aliased_arguments_map()) {
4977 : DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
4978 : return handle(native_context->fast_aliased_arguments_map());
4979 : }
4980 3006889 : } else if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) {
4981 : // Reuse map transitions for JSArrays.
4982 : DisallowHeapAllocation no_gc;
4983 1038715 : if (native_context->get(Context::ArrayMapIndex(from_kind)) == *map) {
4984 : Object* maybe_transitioned_map =
4985 : native_context->get(Context::ArrayMapIndex(to_kind));
4986 849262 : if (maybe_transitioned_map->IsMap()) {
4987 : return handle(Map::cast(maybe_transitioned_map), isolate);
4988 : }
4989 : }
4990 : }
4991 :
4992 : DCHECK(!map->IsUndefined(isolate));
4993 : // Check if we can go back in the elements kind transition chain.
4994 1282592 : if (IsHoleyElementsKind(from_kind) &&
4995 0 : to_kind == GetPackedElementsKind(from_kind) &&
4996 655889 : map->GetBackPointer()->IsMap() &&
4997 0 : Map::cast(map->GetBackPointer())->elements_kind() == to_kind) {
4998 0 : return handle(Map::cast(map->GetBackPointer()));
4999 : }
5000 :
5001 : bool allow_store_transition = IsTransitionElementsKind(from_kind);
5002 : // Only store fast element maps in ascending generality.
5003 655889 : if (IsFastElementsKind(to_kind)) {
5004 : allow_store_transition =
5005 571379 : allow_store_transition && IsTransitionableFastElementsKind(from_kind) &&
5006 189453 : IsMoreGeneralElementsKindTransition(from_kind, to_kind);
5007 : }
5008 :
5009 655889 : if (!allow_store_transition) {
5010 3035 : return Map::CopyAsElementsKind(map, to_kind, OMIT_TRANSITION);
5011 : }
5012 :
5013 652854 : return Map::ReconfigureElementsKind(map, to_kind);
5014 : }
5015 :
5016 :
5017 : // static
5018 1528843 : Handle<Map> Map::AsElementsKind(Handle<Map> map, ElementsKind kind) {
5019 1528843 : Handle<Map> closest_map(FindClosestElementsTransition(*map, kind));
5020 :
5021 1528843 : if (closest_map->elements_kind() == kind) {
5022 1266637 : return closest_map;
5023 : }
5024 :
5025 262206 : return AddMissingElementsTransitions(closest_map, kind);
5026 : }
5027 :
5028 :
5029 2523439 : Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
5030 : ElementsKind to_kind) {
5031 : Handle<Map> map(object->map());
5032 2523439 : return Map::TransitionElementsTo(map, to_kind);
5033 : }
5034 :
5035 :
5036 188 : void JSProxy::Revoke(Handle<JSProxy> proxy) {
5037 : Isolate* isolate = proxy->GetIsolate();
5038 362 : if (!proxy->IsRevoked()) proxy->set_handler(isolate->heap()->null_value());
5039 : DCHECK(proxy->IsRevoked());
5040 188 : }
5041 :
5042 :
5043 68199 : Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy,
5044 : Handle<Name> name) {
5045 : DCHECK(!name->IsPrivate());
5046 68199 : STACK_CHECK(isolate, Nothing<bool>());
5047 : // 1. (Assert)
5048 : // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
5049 : Handle<Object> handler(proxy->handler(), isolate);
5050 : // 3. If handler is null, throw a TypeError exception.
5051 : // 4. Assert: Type(handler) is Object.
5052 68185 : if (proxy->IsRevoked()) {
5053 : isolate->Throw(*isolate->factory()->NewTypeError(
5054 56 : MessageTemplate::kProxyRevoked, isolate->factory()->has_string()));
5055 : return Nothing<bool>();
5056 : }
5057 : // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
5058 : Handle<JSReceiver> target(proxy->target(), isolate);
5059 : // 6. Let trap be ? GetMethod(handler, "has").
5060 : Handle<Object> trap;
5061 136314 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5062 : isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
5063 : isolate->factory()->has_string()),
5064 : Nothing<bool>());
5065 : // 7. If trap is undefined, then
5066 67947 : if (trap->IsUndefined(isolate)) {
5067 : // 7a. Return target.[[HasProperty]](P).
5068 53258 : return JSReceiver::HasProperty(target, name);
5069 : }
5070 : // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, P»)).
5071 : Handle<Object> trap_result_obj;
5072 : Handle<Object> args[] = {target, name};
5073 29378 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5074 : isolate, trap_result_obj,
5075 : Execution::Call(isolate, trap, handler, arraysize(args), args),
5076 : Nothing<bool>());
5077 14045 : bool boolean_trap_result = trap_result_obj->BooleanValue();
5078 : // 9. If booleanTrapResult is false, then:
5079 14045 : if (!boolean_trap_result) {
5080 : // 9a. Let targetDesc be ? target.[[GetOwnProperty]](P).
5081 : PropertyDescriptor target_desc;
5082 : Maybe<bool> target_found = JSReceiver::GetOwnPropertyDescriptor(
5083 8990 : isolate, target, name, &target_desc);
5084 9032 : MAYBE_RETURN(target_found, Nothing<bool>());
5085 : // 9b. If targetDesc is not undefined, then:
5086 8990 : if (target_found.FromJust()) {
5087 : // 9b i. If targetDesc.[[Configurable]] is false, throw a TypeError
5088 : // exception.
5089 72 : if (!target_desc.configurable()) {
5090 : isolate->Throw(*isolate->factory()->NewTypeError(
5091 56 : MessageTemplate::kProxyHasNonConfigurable, name));
5092 42 : return Nothing<bool>();
5093 : }
5094 : // 9b ii. Let extensibleTarget be ? IsExtensible(target).
5095 44 : Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
5096 44 : MAYBE_RETURN(extensible_target, Nothing<bool>());
5097 : // 9b iii. If extensibleTarget is false, throw a TypeError exception.
5098 44 : if (!extensible_target.FromJust()) {
5099 : isolate->Throw(*isolate->factory()->NewTypeError(
5100 28 : MessageTemplate::kProxyHasNonExtensible, name));
5101 : return Nothing<bool>();
5102 : }
5103 : }
5104 : }
5105 : // 10. Return booleanTrapResult.
5106 : return Just(boolean_trap_result);
5107 : }
5108 :
5109 :
5110 63039 : Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name,
5111 : Handle<Object> value, Handle<Object> receiver,
5112 : LanguageMode language_mode) {
5113 : DCHECK(!name->IsPrivate());
5114 : Isolate* isolate = proxy->GetIsolate();
5115 63039 : STACK_CHECK(isolate, Nothing<bool>());
5116 : Factory* factory = isolate->factory();
5117 : Handle<String> trap_name = factory->set_string();
5118 : ShouldThrow should_throw =
5119 63011 : is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
5120 :
5121 63011 : if (proxy->IsRevoked()) {
5122 : isolate->Throw(
5123 56 : *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
5124 : return Nothing<bool>();
5125 : }
5126 : Handle<JSReceiver> target(proxy->target(), isolate);
5127 : Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
5128 :
5129 : Handle<Object> trap;
5130 125966 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5131 : isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
5132 62507 : if (trap->IsUndefined(isolate)) {
5133 : LookupIterator it =
5134 57942 : LookupIterator::PropertyOrElement(isolate, receiver, name, target);
5135 : return Object::SetSuperProperty(&it, value, language_mode,
5136 57942 : Object::MAY_BE_STORE_FROM_KEYED);
5137 : }
5138 :
5139 : Handle<Object> trap_result;
5140 4565 : Handle<Object> args[] = {target, name, value, receiver};
5141 9130 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5142 : isolate, trap_result,
5143 : Execution::Call(isolate, trap, handler, arraysize(args), args),
5144 : Nothing<bool>());
5145 4061 : if (!trap_result->BooleanValue()) {
5146 869 : RETURN_FAILURE(isolate, should_throw,
5147 : NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
5148 : trap_name, name));
5149 : }
5150 :
5151 : // Enforce the invariant.
5152 : PropertyDescriptor target_desc;
5153 : Maybe<bool> owned =
5154 3332 : JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
5155 3332 : MAYBE_RETURN(owned, Nothing<bool>());
5156 3332 : if (owned.FromJust()) {
5157 1526 : bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
5158 840 : !target_desc.configurable() &&
5159 2646 : !target_desc.writable() &&
5160 560 : !value->SameValue(*target_desc.value());
5161 2086 : if (inconsistent) {
5162 : isolate->Throw(*isolate->factory()->NewTypeError(
5163 560 : MessageTemplate::kProxySetFrozenData, name));
5164 : return Nothing<bool>();
5165 : }
5166 560 : inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
5167 2086 : !target_desc.configurable() &&
5168 : target_desc.set()->IsUndefined(isolate);
5169 1806 : if (inconsistent) {
5170 : isolate->Throw(*isolate->factory()->NewTypeError(
5171 560 : MessageTemplate::kProxySetFrozenAccessor, name));
5172 : return Nothing<bool>();
5173 : }
5174 : }
5175 : return Just(true);
5176 : }
5177 :
5178 :
5179 4817 : Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy,
5180 : Handle<Name> name,
5181 : LanguageMode language_mode) {
5182 : DCHECK(!name->IsPrivate());
5183 : ShouldThrow should_throw =
5184 4817 : is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
5185 : Isolate* isolate = proxy->GetIsolate();
5186 4817 : STACK_CHECK(isolate, Nothing<bool>());
5187 : Factory* factory = isolate->factory();
5188 : Handle<String> trap_name = factory->deleteProperty_string();
5189 :
5190 4817 : if (proxy->IsRevoked()) {
5191 : isolate->Throw(
5192 56 : *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
5193 : return Nothing<bool>();
5194 : }
5195 : Handle<JSReceiver> target(proxy->target(), isolate);
5196 : Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
5197 :
5198 : Handle<Object> trap;
5199 9578 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5200 : isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
5201 4579 : if (trap->IsUndefined(isolate)) {
5202 1261 : return JSReceiver::DeletePropertyOrElement(target, name, language_mode);
5203 : }
5204 :
5205 : Handle<Object> trap_result;
5206 : Handle<Object> args[] = {target, name};
5207 6636 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5208 : isolate, trap_result,
5209 : Execution::Call(isolate, trap, handler, arraysize(args), args),
5210 : Nothing<bool>());
5211 2814 : if (!trap_result->BooleanValue()) {
5212 1932 : RETURN_FAILURE(isolate, should_throw,
5213 : NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
5214 : trap_name, name));
5215 : }
5216 :
5217 : // Enforce the invariant.
5218 : PropertyDescriptor target_desc;
5219 : Maybe<bool> owned =
5220 1638 : JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
5221 1638 : MAYBE_RETURN(owned, Nothing<bool>());
5222 2478 : if (owned.FromJust() && !target_desc.configurable()) {
5223 : isolate->Throw(*factory->NewTypeError(
5224 1120 : MessageTemplate::kProxyDeletePropertyNonConfigurable, name));
5225 : return Nothing<bool>();
5226 : }
5227 : return Just(true);
5228 : }
5229 :
5230 :
5231 : // static
5232 45334 : MaybeHandle<JSProxy> JSProxy::New(Isolate* isolate, Handle<Object> target,
5233 : Handle<Object> handler) {
5234 45334 : if (!target->IsJSReceiver()) {
5235 30 : THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5236 : JSProxy);
5237 : }
5238 50361 : if (target->IsJSProxy() && JSProxy::cast(*target)->IsRevoked()) {
5239 0 : THROW_NEW_ERROR(isolate,
5240 : NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5241 : JSProxy);
5242 : }
5243 45319 : if (!handler->IsJSReceiver()) {
5244 0 : THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5245 : JSProxy);
5246 : }
5247 52739 : if (handler->IsJSProxy() && JSProxy::cast(*handler)->IsRevoked()) {
5248 0 : THROW_NEW_ERROR(isolate,
5249 : NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5250 : JSProxy);
5251 : }
5252 : return isolate->factory()->NewJSProxy(Handle<JSReceiver>::cast(target),
5253 45319 : Handle<JSReceiver>::cast(handler));
5254 : }
5255 :
5256 :
5257 : // static
5258 29 : MaybeHandle<Context> JSProxy::GetFunctionRealm(Handle<JSProxy> proxy) {
5259 : DCHECK(proxy->map()->is_constructor());
5260 29 : if (proxy->IsRevoked()) {
5261 0 : THROW_NEW_ERROR(proxy->GetIsolate(),
5262 : NewTypeError(MessageTemplate::kProxyRevoked), Context);
5263 : }
5264 : Handle<JSReceiver> target(JSReceiver::cast(proxy->target()));
5265 29 : return JSReceiver::GetFunctionRealm(target);
5266 : }
5267 :
5268 :
5269 : // static
5270 0 : MaybeHandle<Context> JSBoundFunction::GetFunctionRealm(
5271 : Handle<JSBoundFunction> function) {
5272 : DCHECK(function->map()->is_constructor());
5273 : return JSReceiver::GetFunctionRealm(
5274 0 : handle(function->bound_target_function()));
5275 : }
5276 :
5277 : // static
5278 341 : MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate,
5279 : Handle<JSBoundFunction> function) {
5280 : Handle<String> prefix = isolate->factory()->bound__string();
5281 341 : if (!function->bound_target_function()->IsJSFunction()) return prefix;
5282 : Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()),
5283 : isolate);
5284 341 : Handle<Object> target_name = JSFunction::GetName(isolate, target);
5285 341 : if (!target_name->IsString()) return prefix;
5286 : Factory* factory = isolate->factory();
5287 341 : return factory->NewConsString(prefix, Handle<String>::cast(target_name));
5288 : }
5289 :
5290 : // static
5291 145679 : Handle<Object> JSFunction::GetName(Isolate* isolate,
5292 : Handle<JSFunction> function) {
5293 145679 : if (function->shared()->name_should_print_as_anonymous()) {
5294 0 : return isolate->factory()->anonymous_string();
5295 : }
5296 : return handle(function->shared()->name(), isolate);
5297 : }
5298 :
5299 : // static
5300 24391 : MaybeHandle<Smi> JSFunction::GetLength(Isolate* isolate,
5301 : Handle<JSFunction> function) {
5302 : int length = 0;
5303 24391 : if (function->shared()->is_compiled()) {
5304 : length = function->shared()->GetLength();
5305 : } else {
5306 : // If the function isn't compiled yet, the length is not computed
5307 : // correctly yet. Compile it now and return the right length.
5308 2141 : if (Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) {
5309 : length = function->shared()->GetLength();
5310 : }
5311 2141 : if (isolate->has_pending_exception()) return MaybeHandle<Smi>();
5312 : }
5313 : DCHECK_GE(length, 0);
5314 : return handle(Smi::FromInt(length), isolate);
5315 : }
5316 :
5317 : // static
5318 4331 : Handle<Context> JSFunction::GetFunctionRealm(Handle<JSFunction> function) {
5319 : DCHECK(function->map()->is_constructor());
5320 4331 : return handle(function->context()->native_context());
5321 : }
5322 :
5323 :
5324 : // static
5325 0 : MaybeHandle<Context> JSObject::GetFunctionRealm(Handle<JSObject> object) {
5326 : DCHECK(object->map()->is_constructor());
5327 : DCHECK(!object->IsJSFunction());
5328 0 : return object->GetCreationContext();
5329 : }
5330 :
5331 :
5332 : // static
5333 4360 : MaybeHandle<Context> JSReceiver::GetFunctionRealm(Handle<JSReceiver> receiver) {
5334 4360 : if (receiver->IsJSProxy()) {
5335 29 : return JSProxy::GetFunctionRealm(Handle<JSProxy>::cast(receiver));
5336 : }
5337 :
5338 4331 : if (receiver->IsJSFunction()) {
5339 4331 : return JSFunction::GetFunctionRealm(Handle<JSFunction>::cast(receiver));
5340 : }
5341 :
5342 0 : if (receiver->IsJSBoundFunction()) {
5343 : return JSBoundFunction::GetFunctionRealm(
5344 0 : Handle<JSBoundFunction>::cast(receiver));
5345 : }
5346 :
5347 : return JSObject::GetFunctionRealm(Handle<JSObject>::cast(receiver));
5348 : }
5349 :
5350 :
5351 4940 : Maybe<PropertyAttributes> JSProxy::GetPropertyAttributes(LookupIterator* it) {
5352 : PropertyDescriptor desc;
5353 : Maybe<bool> found = JSProxy::GetOwnPropertyDescriptor(
5354 4940 : it->isolate(), it->GetHolder<JSProxy>(), it->GetName(), &desc);
5355 2470 : MAYBE_RETURN(found, Nothing<PropertyAttributes>());
5356 2005 : if (!found.FromJust()) return Just(ABSENT);
5357 1766 : return Just(desc.ToAttributes());
5358 : }
5359 :
5360 :
5361 9945195 : void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
5362 : DCHECK(object->map()->GetInObjectProperties() ==
5363 : map->GetInObjectProperties());
5364 : ElementsKind obj_kind = object->map()->elements_kind();
5365 : ElementsKind map_kind = map->elements_kind();
5366 9945195 : if (map_kind != obj_kind) {
5367 : ElementsKind to_kind = GetMoreGeneralElementsKind(map_kind, obj_kind);
5368 60 : if (IsDictionaryElementsKind(obj_kind)) {
5369 : to_kind = obj_kind;
5370 : }
5371 60 : if (IsDictionaryElementsKind(to_kind)) {
5372 45 : NormalizeElements(object);
5373 : } else {
5374 15 : TransitionElementsKind(object, to_kind);
5375 : }
5376 60 : map = Map::ReconfigureElementsKind(map, to_kind);
5377 : }
5378 9945195 : JSObject::MigrateToMap(object, map);
5379 9945195 : }
5380 :
5381 :
5382 9782 : void JSObject::MigrateInstance(Handle<JSObject> object) {
5383 : Handle<Map> original_map(object->map());
5384 9782 : Handle<Map> map = Map::Update(original_map);
5385 : map->set_migration_target(true);
5386 9782 : MigrateToMap(object, map);
5387 9782 : if (FLAG_trace_migration) {
5388 0 : object->PrintInstanceMigration(stdout, *original_map, *map);
5389 : }
5390 : #if VERIFY_HEAP
5391 : if (FLAG_verify_heap) {
5392 : object->JSObjectVerify();
5393 : }
5394 : #endif
5395 9782 : }
5396 :
5397 :
5398 : // static
5399 8185 : bool JSObject::TryMigrateInstance(Handle<JSObject> object) {
5400 : Isolate* isolate = object->GetIsolate();
5401 : DisallowDeoptimization no_deoptimization(isolate);
5402 : Handle<Map> original_map(object->map(), isolate);
5403 : Handle<Map> new_map;
5404 16370 : if (!Map::TryUpdate(original_map).ToHandle(&new_map)) {
5405 : return false;
5406 : }
5407 8157 : JSObject::MigrateToMap(object, new_map);
5408 8157 : if (FLAG_trace_migration && *original_map != object->map()) {
5409 0 : object->PrintInstanceMigration(stdout, *original_map, object->map());
5410 : }
5411 : #if VERIFY_HEAP
5412 : if (FLAG_verify_heap) {
5413 : object->JSObjectVerify();
5414 : }
5415 : #endif
5416 : return true;
5417 : }
5418 :
5419 :
5420 17984358 : void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name,
5421 : Handle<Object> value,
5422 : PropertyAttributes attributes) {
5423 17984358 : LookupIterator it(object, name, object, LookupIterator::OWN_SKIP_INTERCEPTOR);
5424 17984366 : CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
5425 : #ifdef DEBUG
5426 : uint32_t index;
5427 : DCHECK(!object->IsJSProxy());
5428 : DCHECK(!name->AsArrayIndex(&index));
5429 : Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
5430 : DCHECK(maybe.IsJust());
5431 : DCHECK(!it.IsFound());
5432 : DCHECK(object->map()->is_extensible() || name->IsPrivate());
5433 : #endif
5434 17984366 : CHECK(AddDataProperty(&it, value, attributes, THROW_ON_ERROR,
5435 : CERTAINLY_NOT_STORE_FROM_KEYED)
5436 : .IsJust());
5437 17984360 : }
5438 :
5439 :
5440 : // Reconfigures a property to a data property with attributes, even if it is not
5441 : // reconfigurable.
5442 : // Requires a LookupIterator that does not look at the prototype chain beyond
5443 : // hidden prototypes.
5444 2307104 : MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes(
5445 : LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
5446 : AccessorInfoHandling handling) {
5447 16424432 : MAYBE_RETURN_NULL(DefineOwnPropertyIgnoreAttributes(
5448 : it, value, attributes, THROW_ON_ERROR, handling));
5449 : return value;
5450 : }
5451 :
5452 :
5453 16758648 : Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
5454 16794773 : LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
5455 : ShouldThrow should_throw, AccessorInfoHandling handling) {
5456 16758648 : it->UpdateProtector();
5457 : Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
5458 :
5459 33519342 : for (; it->IsFound(); it->Next()) {
5460 2610278 : switch (it->state()) {
5461 : case LookupIterator::JSPROXY:
5462 : case LookupIterator::NOT_FOUND:
5463 : case LookupIterator::TRANSITION:
5464 0 : UNREACHABLE();
5465 :
5466 : case LookupIterator::ACCESS_CHECK:
5467 771 : if (!it->HasAccess()) {
5468 6 : it->isolate()->ReportFailedAccessCheck(it->GetHolder<JSObject>());
5469 6 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
5470 : return Just(true);
5471 : }
5472 : break;
5473 :
5474 : // If there's an interceptor, try to store the property with the
5475 : // interceptor.
5476 : // In case of success, the attributes will have been reset to the default
5477 : // attributes of the interceptor, rather than the incoming attributes.
5478 : //
5479 : // TODO(verwaest): JSProxy afterwards verify the attributes that the
5480 : // JSProxy claims it has, and verifies that they are compatible. If not,
5481 : // they throw. Here we should do the same.
5482 : case LookupIterator::INTERCEPTOR:
5483 259 : if (handling == DONT_FORCE_FIELD) {
5484 : Maybe<bool> result =
5485 259 : JSObject::SetPropertyWithInterceptor(it, should_throw, value);
5486 518 : if (result.IsNothing() || result.FromJust()) return result;
5487 : }
5488 : break;
5489 :
5490 : case LookupIterator::ACCESSOR: {
5491 1573711 : Handle<Object> accessors = it->GetAccessors();
5492 :
5493 : // Special handling for AccessorInfo, which behaves like a data
5494 : // property.
5495 1573713 : if (accessors->IsAccessorInfo() && handling == DONT_FORCE_FIELD) {
5496 : PropertyAttributes current_attributes = it->property_attributes();
5497 : // Ensure the context isn't changed after calling into accessors.
5498 : AssertNoContextChange ncc(it->isolate());
5499 :
5500 : // Update the attributes before calling the setter. The setter may
5501 : // later change the shape of the property.
5502 1572947 : if (current_attributes != attributes) {
5503 78896 : it->TransitionToAccessorPair(accessors, attributes);
5504 : }
5505 :
5506 1572947 : return JSObject::SetPropertyWithAccessor(it, value, should_throw);
5507 : }
5508 :
5509 766 : it->ReconfigureDataProperty(value, attributes);
5510 : return Just(true);
5511 : }
5512 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
5513 : return RedefineIncompatibleProperty(it->isolate(), it->GetName(), value,
5514 30 : should_throw);
5515 :
5516 : case LookupIterator::DATA: {
5517 : // Regular property update if the attributes match.
5518 1035520 : if (it->property_attributes() == attributes) {
5519 1000445 : return SetDataProperty(it, value);
5520 : }
5521 :
5522 : // Special case: properties of typed arrays cannot be reconfigured to
5523 : // non-writable nor to non-enumerable.
5524 67243 : if (it->IsElement() && object->HasFixedTypedArrayElements()) {
5525 : return RedefineIncompatibleProperty(it->isolate(), it->GetName(),
5526 0 : value, should_throw);
5527 : }
5528 :
5529 : // Reconfigure the data property if the attributes mismatch.
5530 35075 : it->ReconfigureDataProperty(value, attributes);
5531 :
5532 : return Just(true);
5533 : }
5534 : }
5535 : }
5536 :
5537 : return AddDataProperty(it, value, attributes, should_throw,
5538 14149393 : CERTAINLY_NOT_STORE_FROM_KEYED);
5539 : }
5540 :
5541 10953707 : MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
5542 : Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
5543 : PropertyAttributes attributes) {
5544 : DCHECK(!value->IsTheHole(object->GetIsolate()));
5545 10953707 : LookupIterator it(object, name, object, LookupIterator::OWN);
5546 10953708 : return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
5547 : }
5548 :
5549 295176 : MaybeHandle<Object> JSObject::SetOwnElementIgnoreAttributes(
5550 : Handle<JSObject> object, uint32_t index, Handle<Object> value,
5551 : PropertyAttributes attributes) {
5552 : Isolate* isolate = object->GetIsolate();
5553 : LookupIterator it(isolate, object, index, object, LookupIterator::OWN);
5554 295176 : return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
5555 : }
5556 :
5557 2017759 : MaybeHandle<Object> JSObject::DefinePropertyOrElementIgnoreAttributes(
5558 : Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
5559 : PropertyAttributes attributes) {
5560 : Isolate* isolate = object->GetIsolate();
5561 : LookupIterator it = LookupIterator::PropertyOrElement(
5562 2017759 : isolate, object, name, object, LookupIterator::OWN);
5563 2017757 : return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
5564 : }
5565 :
5566 281223 : Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
5567 : LookupIterator* it) {
5568 281223 : return GetPropertyAttributesWithInterceptorInternal(it, it->GetInterceptor());
5569 : }
5570 :
5571 10835943 : Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
5572 13998897 : LookupIterator* it) {
5573 27997794 : for (; it->IsFound(); it->Next()) {
5574 10149097 : switch (it->state()) {
5575 : case LookupIterator::NOT_FOUND:
5576 : case LookupIterator::TRANSITION:
5577 0 : UNREACHABLE();
5578 : case LookupIterator::JSPROXY:
5579 1304 : return JSProxy::GetPropertyAttributes(it);
5580 : case LookupIterator::INTERCEPTOR: {
5581 : Maybe<PropertyAttributes> result =
5582 411 : JSObject::GetPropertyAttributesWithInterceptor(it);
5583 466 : if (!result.IsJust()) return result;
5584 411 : if (result.FromJust() != ABSENT) return result;
5585 356 : break;
5586 : }
5587 : case LookupIterator::ACCESS_CHECK:
5588 3162695 : if (it->HasAccess()) break;
5589 97 : return JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
5590 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
5591 : return Just(ABSENT);
5592 : case LookupIterator::ACCESSOR:
5593 : case LookupIterator::DATA:
5594 : return Just(it->property_attributes());
5595 : }
5596 : }
5597 : return Just(ABSENT);
5598 : }
5599 :
5600 :
5601 79 : Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) {
5602 : Handle<FixedArray> array(
5603 79 : isolate->factory()->NewFixedArray(kEntries, TENURED));
5604 79 : return Handle<NormalizedMapCache>::cast(array);
5605 : }
5606 :
5607 :
5608 1083329 : MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map,
5609 : PropertyNormalizationMode mode) {
5610 : DisallowHeapAllocation no_gc;
5611 : Object* value = FixedArray::get(GetIndex(fast_map));
5612 2050871 : if (!value->IsMap() ||
5613 967542 : !Map::cast(value)->EquivalentToForNormalization(*fast_map, mode)) {
5614 : return MaybeHandle<Map>();
5615 : }
5616 : return handle(Map::cast(value));
5617 : }
5618 :
5619 :
5620 329942 : void NormalizedMapCache::Set(Handle<Map> fast_map,
5621 : Handle<Map> normalized_map) {
5622 : DisallowHeapAllocation no_gc;
5623 : DCHECK(normalized_map->is_dictionary_map());
5624 329942 : FixedArray::set(GetIndex(fast_map), *normalized_map);
5625 329942 : }
5626 :
5627 :
5628 76477 : void NormalizedMapCache::Clear() {
5629 : int entries = length();
5630 4971005 : for (int i = 0; i != entries; i++) {
5631 4894528 : set_undefined(i);
5632 : }
5633 76477 : }
5634 :
5635 :
5636 0 : void HeapObject::UpdateMapCodeCache(Handle<HeapObject> object,
5637 : Handle<Name> name,
5638 : Handle<Code> code) {
5639 : Handle<Map> map(object->map());
5640 0 : Map::UpdateCodeCache(map, name, code);
5641 0 : }
5642 :
5643 :
5644 1308059 : void JSObject::NormalizeProperties(Handle<JSObject> object,
5645 : PropertyNormalizationMode mode,
5646 : int expected_additional_properties,
5647 : const char* reason) {
5648 1574423 : if (!object->HasFastProperties()) return;
5649 :
5650 : Handle<Map> map(object->map());
5651 1041695 : Handle<Map> new_map = Map::Normalize(map, mode, reason);
5652 :
5653 1041695 : MigrateToMap(object, new_map, expected_additional_properties);
5654 : }
5655 :
5656 :
5657 792179 : void JSObject::MigrateSlowToFast(Handle<JSObject> object,
5658 : int unused_property_fields,
5659 : const char* reason) {
5660 1190307 : if (object->HasFastProperties()) return;
5661 : DCHECK(!object->IsJSGlobalObject());
5662 : Isolate* isolate = object->GetIsolate();
5663 : Factory* factory = isolate->factory();
5664 : Handle<NameDictionary> dictionary(object->property_dictionary());
5665 :
5666 : // Make sure we preserve dictionary representation if there are too many
5667 : // descriptors.
5668 : int number_of_elements = dictionary->NumberOfElements();
5669 523637 : if (number_of_elements > kMaxNumberOfDescriptors) return;
5670 :
5671 : Handle<FixedArray> iteration_order =
5672 523054 : NameDictionary::IterationIndices(dictionary);
5673 :
5674 : int instance_descriptor_length = iteration_order->length();
5675 : int number_of_fields = 0;
5676 :
5677 : // Compute the length of the instance descriptor.
5678 3723248 : for (int i = 0; i < instance_descriptor_length; i++) {
5679 : int index = Smi::cast(iteration_order->get(i))->value();
5680 : DCHECK(dictionary->IsKey(isolate, dictionary->KeyAt(index)));
5681 :
5682 : PropertyKind kind = dictionary->DetailsAt(index).kind();
5683 3200194 : if (kind == kData) {
5684 : if (FLAG_track_constant_fields) {
5685 : number_of_fields += 1;
5686 : } else {
5687 2747990 : Object* value = dictionary->ValueAt(index);
5688 2747990 : if (!value->IsJSFunction()) {
5689 905026 : number_of_fields += 1;
5690 : }
5691 : }
5692 : }
5693 : }
5694 :
5695 : Handle<Map> old_map(object->map(), isolate);
5696 :
5697 : int inobject_props = old_map->GetInObjectProperties();
5698 :
5699 : // Allocate new map.
5700 523054 : Handle<Map> new_map = Map::CopyDropDescriptors(old_map);
5701 : new_map->set_dictionary_map(false);
5702 :
5703 523054 : NotifyMapChange(old_map, new_map, isolate);
5704 :
5705 : #if TRACE_MAPS
5706 : if (FLAG_trace_maps) {
5707 : PrintF("[TraceMaps: SlowToFast from= %p to= %p reason= %s ]\n",
5708 : reinterpret_cast<void*>(*old_map), reinterpret_cast<void*>(*new_map),
5709 : reason);
5710 : }
5711 : #endif
5712 :
5713 523054 : if (instance_descriptor_length == 0) {
5714 : DisallowHeapAllocation no_gc;
5715 : DCHECK_LE(unused_property_fields, inobject_props);
5716 : // Transform the object.
5717 : new_map->set_unused_property_fields(inobject_props);
5718 129003 : object->synchronized_set_map(*new_map);
5719 258006 : object->set_properties(isolate->heap()->empty_fixed_array());
5720 : // Check that it really works.
5721 : DCHECK(object->HasFastProperties());
5722 : return;
5723 : }
5724 :
5725 : // Allocate the instance descriptor.
5726 : Handle<DescriptorArray> descriptors = DescriptorArray::Allocate(
5727 394051 : isolate, instance_descriptor_length, 0, TENURED);
5728 :
5729 : int number_of_allocated_fields =
5730 394051 : number_of_fields + unused_property_fields - inobject_props;
5731 394051 : if (number_of_allocated_fields < 0) {
5732 : // There is enough inobject space for all fields (including unused).
5733 : number_of_allocated_fields = 0;
5734 121867 : unused_property_fields = inobject_props - number_of_fields;
5735 : }
5736 :
5737 : // Allocate the fixed array for the fields.
5738 : Handle<FixedArray> fields = factory->NewFixedArray(
5739 394051 : number_of_allocated_fields);
5740 :
5741 : // Fill in the instance descriptor and the fields.
5742 : int current_offset = 0;
5743 3594245 : for (int i = 0; i < instance_descriptor_length; i++) {
5744 : int index = Smi::cast(iteration_order->get(i))->value();
5745 : Object* k = dictionary->KeyAt(index);
5746 : DCHECK(dictionary->IsKey(isolate, k));
5747 : // Dictionary keys are internalized upon insertion.
5748 : // TODO(jkummerow): Turn this into a DCHECK if it's not hit in the wild.
5749 3200194 : CHECK(k->IsUniqueName());
5750 : Handle<Name> key(Name::cast(k), isolate);
5751 :
5752 3200194 : Object* value = dictionary->ValueAt(index);
5753 :
5754 : PropertyDetails details = dictionary->DetailsAt(index);
5755 : DCHECK_EQ(kField, details.location());
5756 : DCHECK_EQ(kMutable, details.constness());
5757 :
5758 : Descriptor d;
5759 3200194 : if (details.kind() == kData) {
5760 2747990 : if (!FLAG_track_constant_fields && value->IsJSFunction()) {
5761 : d = Descriptor::DataConstant(key, handle(value, isolate),
5762 1842964 : details.attributes());
5763 : } else {
5764 : d = Descriptor::DataField(
5765 : key, current_offset, details.attributes(), kDefaultFieldConstness,
5766 : // TODO(verwaest): value->OptimalRepresentation();
5767 1810052 : Representation::Tagged(), FieldType::Any(isolate));
5768 : }
5769 : } else {
5770 : DCHECK_EQ(kAccessor, details.kind());
5771 : d = Descriptor::AccessorConstant(key, handle(value, isolate),
5772 452204 : details.attributes());
5773 : }
5774 : details = d.GetDetails();
5775 3200194 : if (details.location() == kField) {
5776 905026 : if (current_offset < inobject_props) {
5777 : object->InObjectPropertyAtPut(current_offset, value,
5778 494032 : UPDATE_WRITE_BARRIER);
5779 : } else {
5780 410994 : int offset = current_offset - inobject_props;
5781 410994 : fields->set(offset, value);
5782 : }
5783 905026 : current_offset += details.field_width_in_words();
5784 : }
5785 3200194 : descriptors->Set(i, &d);
5786 : }
5787 : DCHECK(current_offset == number_of_fields);
5788 :
5789 394051 : descriptors->Sort();
5790 :
5791 : Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
5792 394051 : new_map, descriptors, descriptors->number_of_descriptors());
5793 :
5794 : DisallowHeapAllocation no_gc;
5795 394051 : new_map->InitializeDescriptors(*descriptors, *layout_descriptor);
5796 : new_map->set_unused_property_fields(unused_property_fields);
5797 :
5798 : // Transform the object.
5799 394051 : object->synchronized_set_map(*new_map);
5800 :
5801 394051 : object->set_properties(*fields);
5802 : DCHECK(object->IsJSObject());
5803 :
5804 : // Check that it really works.
5805 : DCHECK(object->HasFastProperties());
5806 : }
5807 :
5808 :
5809 5432 : void JSObject::ResetElements(Handle<JSObject> object) {
5810 : Isolate* isolate = object->GetIsolate();
5811 5432 : CHECK(object->map() != isolate->heap()->sloppy_arguments_elements_map());
5812 5432 : if (object->map()->has_dictionary_elements()) {
5813 : Handle<SeededNumberDictionary> new_elements =
5814 3444 : SeededNumberDictionary::New(isolate, 0);
5815 3444 : object->set_elements(*new_elements);
5816 : } else {
5817 3976 : object->set_elements(object->map()->GetInitialElements());
5818 : }
5819 5432 : }
5820 :
5821 :
5822 126651 : void JSObject::RequireSlowElements(SeededNumberDictionary* dictionary) {
5823 253302 : if (dictionary->requires_slow_elements()) return;
5824 : dictionary->set_requires_slow_elements();
5825 75500 : if (map()->is_prototype_map()) {
5826 : // If this object is a prototype (the callee will check), invalidate any
5827 : // prototype chains involving it.
5828 : InvalidatePrototypeChains(map());
5829 : }
5830 : }
5831 :
5832 :
5833 466580 : Handle<SeededNumberDictionary> JSObject::NormalizeElements(
5834 : Handle<JSObject> object) {
5835 : DCHECK(!object->HasFixedTypedArrayElements());
5836 458683 : Isolate* isolate = object->GetIsolate();
5837 466580 : bool is_arguments = object->HasSloppyArgumentsElements();
5838 : {
5839 : DisallowHeapAllocation no_gc;
5840 : FixedArrayBase* elements = object->elements();
5841 :
5842 466580 : if (is_arguments) {
5843 : FixedArray* parameter_map = FixedArray::cast(elements);
5844 : elements = FixedArrayBase::cast(parameter_map->get(1));
5845 : }
5846 :
5847 466580 : if (elements->IsDictionary()) {
5848 : return handle(SeededNumberDictionary::cast(elements), isolate);
5849 : }
5850 : }
5851 :
5852 : DCHECK(object->HasFastSmiOrObjectElements() ||
5853 : object->HasFastDoubleElements() ||
5854 : object->HasFastArgumentsElements() ||
5855 : object->HasFastStringWrapperElements());
5856 :
5857 : Handle<SeededNumberDictionary> dictionary =
5858 458683 : object->GetElementsAccessor()->Normalize(object);
5859 :
5860 : // Switch to using the dictionary as the backing storage for elements.
5861 : ElementsKind target_kind = is_arguments
5862 : ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS
5863 458151 : : object->HasFastStringWrapperElements()
5864 : ? SLOW_STRING_WRAPPER_ELEMENTS
5865 916834 : : DICTIONARY_ELEMENTS;
5866 458683 : Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind);
5867 : // Set the new map first to satify the elements type assert in set_elements().
5868 458683 : JSObject::MigrateToMap(object, new_map);
5869 :
5870 458683 : if (is_arguments) {
5871 532 : FixedArray::cast(object->elements())->set(1, *dictionary);
5872 : } else {
5873 458151 : object->set_elements(*dictionary);
5874 : }
5875 :
5876 458683 : isolate->counters()->elements_to_dictionary()->Increment();
5877 :
5878 : #ifdef DEBUG
5879 : if (FLAG_trace_normalization) {
5880 : OFStream os(stdout);
5881 : os << "Object elements have been normalized:\n";
5882 : object->Print(os);
5883 : }
5884 : #endif
5885 :
5886 : DCHECK(object->HasDictionaryElements() ||
5887 : object->HasSlowArgumentsElements() ||
5888 : object->HasSlowStringWrapperElements());
5889 458683 : return dictionary;
5890 : }
5891 :
5892 :
5893 : template <typename ProxyType>
5894 3181 : static Smi* GetOrCreateIdentityHashHelper(Isolate* isolate,
5895 : Handle<ProxyType> proxy) {
5896 : Object* maybe_hash = proxy->hash();
5897 3181 : if (maybe_hash->IsSmi()) return Smi::cast(maybe_hash);
5898 :
5899 687 : Smi* hash = Smi::FromInt(isolate->GenerateIdentityHash(Smi::kMaxValue));
5900 687 : proxy->set_hash(hash);
5901 687 : return hash;
5902 : }
5903 :
5904 : // static
5905 20925 : Object* JSObject::GetIdentityHash(Isolate* isolate, Handle<JSObject> object) {
5906 20925 : if (object->IsJSGlobalProxy()) {
5907 82 : return JSGlobalProxy::cast(*object)->hash();
5908 : }
5909 : Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol();
5910 41686 : return *JSReceiver::GetDataProperty(object, hash_code_symbol);
5911 : }
5912 :
5913 : // static
5914 3952 : Smi* JSObject::GetOrCreateIdentityHash(Isolate* isolate,
5915 : Handle<JSObject> object) {
5916 3952 : if (object->IsJSGlobalProxy()) {
5917 : return GetOrCreateIdentityHashHelper(isolate,
5918 87 : Handle<JSGlobalProxy>::cast(object));
5919 : }
5920 :
5921 : Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol();
5922 3865 : LookupIterator it(object, hash_code_symbol, object, LookupIterator::OWN);
5923 3865 : if (it.IsFound()) {
5924 : DCHECK_EQ(LookupIterator::DATA, it.state());
5925 962 : Object* maybe_hash = *it.GetDataValue();
5926 481 : if (maybe_hash->IsSmi()) return Smi::cast(maybe_hash);
5927 : }
5928 :
5929 3384 : Smi* hash = Smi::FromInt(isolate->GenerateIdentityHash(Smi::kMaxValue));
5930 3384 : CHECK(AddDataProperty(&it, handle(hash, isolate), NONE, THROW_ON_ERROR,
5931 : CERTAINLY_NOT_STORE_FROM_KEYED)
5932 : .IsJust());
5933 : return hash;
5934 : }
5935 :
5936 : // static
5937 0 : Object* JSProxy::GetIdentityHash(Handle<JSProxy> proxy) {
5938 0 : return proxy->hash();
5939 : }
5940 :
5941 0 : Smi* JSProxy::GetOrCreateIdentityHash(Isolate* isolate, Handle<JSProxy> proxy) {
5942 3094 : return GetOrCreateIdentityHashHelper(isolate, proxy);
5943 : }
5944 :
5945 :
5946 185 : Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it,
5947 : ShouldThrow should_throw) {
5948 : Isolate* isolate = it->isolate();
5949 : // Make sure that the top context does not change when doing callbacks or
5950 : // interceptor calls.
5951 : AssertNoContextChange ncc(isolate);
5952 :
5953 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
5954 117 : Handle<InterceptorInfo> interceptor(it->GetInterceptor());
5955 117 : if (interceptor->deleter()->IsUndefined(isolate)) return Nothing<bool>();
5956 :
5957 : Handle<JSObject> holder = it->GetHolder<JSObject>();
5958 : Handle<Object> receiver = it->GetReceiver();
5959 68 : if (!receiver->IsJSReceiver()) {
5960 0 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
5961 : Object::ConvertReceiver(isolate, receiver),
5962 : Nothing<bool>());
5963 : }
5964 :
5965 : PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
5966 : *holder, should_throw);
5967 : Handle<Object> result;
5968 68 : if (it->IsElement()) {
5969 : uint32_t index = it->index();
5970 : v8::IndexedPropertyDeleterCallback deleter =
5971 : v8::ToCData<v8::IndexedPropertyDeleterCallback>(interceptor->deleter());
5972 27 : result = args.Call(deleter, index);
5973 : } else {
5974 : DCHECK_IMPLIES(it->name()->IsSymbol(),
5975 : interceptor->can_intercept_symbols());
5976 41 : Handle<Name> name = it->name();
5977 : DCHECK(!name->IsPrivate());
5978 : v8::GenericNamedPropertyDeleterCallback deleter =
5979 : v8::ToCData<v8::GenericNamedPropertyDeleterCallback>(
5980 : interceptor->deleter());
5981 41 : result = args.Call(deleter, name);
5982 : }
5983 :
5984 68 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
5985 68 : if (result.is_null()) return Nothing<bool>();
5986 :
5987 : DCHECK(result->IsBoolean());
5988 : // Rebox CustomArguments::kReturnValueOffset before returning.
5989 : return Just(result->IsTrue(isolate));
5990 : }
5991 :
5992 :
5993 6177375 : void JSReceiver::DeleteNormalizedProperty(Handle<JSReceiver> object,
5994 : Handle<Name> name, int entry) {
5995 : DCHECK(!object->HasFastProperties());
5996 : Isolate* isolate = object->GetIsolate();
5997 :
5998 6177375 : if (object->IsJSGlobalObject()) {
5999 : // If we have a global object, invalidate the cell and swap in a new one.
6000 : Handle<GlobalDictionary> dictionary(
6001 : JSObject::cast(*object)->global_dictionary());
6002 : DCHECK_NE(GlobalDictionary::kNotFound, entry);
6003 :
6004 12243 : auto cell = PropertyCell::InvalidateEntry(dictionary, entry);
6005 24486 : cell->set_value(isolate->heap()->the_hole_value());
6006 : cell->set_property_details(
6007 : PropertyDetails::Empty(PropertyCellType::kUninitialized));
6008 : } else {
6009 : Handle<NameDictionary> dictionary(object->property_dictionary());
6010 : DCHECK_NE(NameDictionary::kNotFound, entry);
6011 :
6012 6165132 : NameDictionary::DeleteProperty(dictionary, entry);
6013 : Handle<NameDictionary> new_properties =
6014 : NameDictionary::Shrink(dictionary, name);
6015 6165132 : object->set_properties(*new_properties);
6016 : }
6017 6177375 : }
6018 :
6019 :
6020 27147935 : Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
6021 : LanguageMode language_mode) {
6022 9045871 : it->UpdateProtector();
6023 :
6024 : Isolate* isolate = it->isolate();
6025 :
6026 9045871 : if (it->state() == LookupIterator::JSPROXY) {
6027 : return JSProxy::DeletePropertyOrElement(it->GetHolder<JSProxy>(),
6028 4817 : it->GetName(), language_mode);
6029 : }
6030 :
6031 9041054 : if (it->GetReceiver()->IsJSProxy()) {
6032 56 : if (it->state() != LookupIterator::NOT_FOUND) {
6033 : DCHECK_EQ(LookupIterator::DATA, it->state());
6034 : DCHECK(it->name()->IsPrivate());
6035 7 : it->Delete();
6036 : }
6037 : return Just(true);
6038 : }
6039 : Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
6040 :
6041 18112274 : for (; it->IsFound(); it->Next()) {
6042 6360279 : switch (it->state()) {
6043 : case LookupIterator::JSPROXY:
6044 : case LookupIterator::NOT_FOUND:
6045 : case LookupIterator::TRANSITION:
6046 0 : UNREACHABLE();
6047 : case LookupIterator::ACCESS_CHECK:
6048 15093 : if (it->HasAccess()) break;
6049 43 : isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
6050 43 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6051 : return Just(false);
6052 : case LookupIterator::INTERCEPTOR: {
6053 : ShouldThrow should_throw =
6054 117 : is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
6055 : Maybe<bool> result =
6056 117 : JSObject::DeletePropertyWithInterceptor(it, should_throw);
6057 : // An exception was thrown in the interceptor. Propagate.
6058 145 : if (isolate->has_pending_exception()) return Nothing<bool>();
6059 : // Delete with interceptor succeeded. Return result.
6060 : // TODO(neis): In strict mode, we should probably throw if the
6061 : // interceptor returns false.
6062 117 : if (result.IsJust()) return result;
6063 89 : break;
6064 : }
6065 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
6066 : return Just(true);
6067 : case LookupIterator::DATA:
6068 : case LookupIterator::ACCESSOR: {
6069 6344999 : if (!it->IsConfigurable()) {
6070 : // Fail if the property is not configurable.
6071 3502 : if (is_strict(language_mode)) {
6072 : isolate->Throw(*isolate->factory()->NewTypeError(
6073 : MessageTemplate::kStrictDeleteProperty, it->GetName(),
6074 2517 : receiver));
6075 : return Nothing<bool>();
6076 : }
6077 : return Just(false);
6078 : }
6079 :
6080 6341497 : it->Delete();
6081 :
6082 : return Just(true);
6083 : }
6084 : }
6085 : }
6086 :
6087 : return Just(true);
6088 : }
6089 :
6090 :
6091 12 : Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index,
6092 : LanguageMode language_mode) {
6093 : LookupIterator it(object->GetIsolate(), object, index, object,
6094 : LookupIterator::OWN);
6095 12 : return DeleteProperty(&it, language_mode);
6096 : }
6097 :
6098 :
6099 468 : Maybe<bool> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
6100 : Handle<Name> name,
6101 : LanguageMode language_mode) {
6102 468 : LookupIterator it(object, name, object, LookupIterator::OWN);
6103 468 : return DeleteProperty(&it, language_mode);
6104 : }
6105 :
6106 :
6107 5843 : Maybe<bool> JSReceiver::DeletePropertyOrElement(Handle<JSReceiver> object,
6108 : Handle<Name> name,
6109 : LanguageMode language_mode) {
6110 : LookupIterator it = LookupIterator::PropertyOrElement(
6111 5843 : name->GetIsolate(), object, name, object, LookupIterator::OWN);
6112 5843 : return DeleteProperty(&it, language_mode);
6113 : }
6114 :
6115 : // ES6 19.1.2.4
6116 : // static
6117 285954 : Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object,
6118 : Handle<Object> key,
6119 : Handle<Object> attributes) {
6120 : // 1. If Type(O) is not Object, throw a TypeError exception.
6121 285954 : if (!object->IsJSReceiver()) {
6122 : Handle<String> fun_name =
6123 102 : isolate->factory()->InternalizeUtf8String("Object.defineProperty");
6124 204 : THROW_NEW_ERROR_RETURN_FAILURE(
6125 : isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name));
6126 : }
6127 : // 2. Let key be ToPropertyKey(P).
6128 : // 3. ReturnIfAbrupt(key).
6129 571704 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key, ToPropertyKey(isolate, key));
6130 : // 4. Let desc be ToPropertyDescriptor(Attributes).
6131 : // 5. ReturnIfAbrupt(desc).
6132 : PropertyDescriptor desc;
6133 285852 : if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) {
6134 215 : return isolate->heap()->exception();
6135 : }
6136 : // 6. Let success be DefinePropertyOrThrow(O,key, desc).
6137 : Maybe<bool> success = DefineOwnProperty(
6138 285637 : isolate, Handle<JSReceiver>::cast(object), key, &desc, THROW_ON_ERROR);
6139 : // 7. ReturnIfAbrupt(success).
6140 285637 : MAYBE_RETURN(success, isolate->heap()->exception());
6141 283962 : CHECK(success.FromJust());
6142 : // 8. Return O.
6143 283962 : return *object;
6144 : }
6145 :
6146 :
6147 : // ES6 19.1.2.3.1
6148 : // static
6149 19975 : MaybeHandle<Object> JSReceiver::DefineProperties(Isolate* isolate,
6150 : Handle<Object> object,
6151 : Handle<Object> properties) {
6152 : // 1. If Type(O) is not Object, throw a TypeError exception.
6153 19975 : if (!object->IsJSReceiver()) {
6154 : Handle<String> fun_name =
6155 43 : isolate->factory()->InternalizeUtf8String("Object.defineProperties");
6156 86 : THROW_NEW_ERROR(isolate,
6157 : NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name),
6158 : Object);
6159 : }
6160 : // 2. Let props be ToObject(Properties).
6161 : // 3. ReturnIfAbrupt(props).
6162 : Handle<JSReceiver> props;
6163 39864 : ASSIGN_RETURN_ON_EXCEPTION(isolate, props,
6164 : Object::ToObject(isolate, properties), Object);
6165 :
6166 : // 4. Let keys be props.[[OwnPropertyKeys]]().
6167 : // 5. ReturnIfAbrupt(keys).
6168 : Handle<FixedArray> keys;
6169 39834 : ASSIGN_RETURN_ON_EXCEPTION(
6170 : isolate, keys, KeyAccumulator::GetKeys(props, KeyCollectionMode::kOwnOnly,
6171 : ALL_PROPERTIES),
6172 : Object);
6173 : // 6. Let descriptors be an empty List.
6174 : int capacity = keys->length();
6175 19917 : std::vector<PropertyDescriptor> descriptors(capacity);
6176 : size_t descriptors_index = 0;
6177 : // 7. Repeat for each element nextKey of keys in List order,
6178 379204 : for (int i = 0; i < keys->length(); ++i) {
6179 : Handle<Object> next_key(keys->get(i), isolate);
6180 : // 7a. Let propDesc be props.[[GetOwnProperty]](nextKey).
6181 : // 7b. ReturnIfAbrupt(propDesc).
6182 170044 : bool success = false;
6183 : LookupIterator it = LookupIterator::PropertyOrElement(
6184 170044 : isolate, props, next_key, &success, LookupIterator::OWN);
6185 : DCHECK(success);
6186 170044 : Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
6187 170403 : if (!maybe.IsJust()) return MaybeHandle<Object>();
6188 : PropertyAttributes attrs = maybe.FromJust();
6189 : // 7c. If propDesc is not undefined and propDesc.[[Enumerable]] is true:
6190 171765 : if (attrs == ABSENT) continue;
6191 170044 : if (attrs & DONT_ENUM) continue;
6192 : // 7c i. Let descObj be Get(props, nextKey).
6193 : // 7c ii. ReturnIfAbrupt(descObj).
6194 : Handle<Object> desc_obj;
6195 336646 : ASSIGN_RETURN_ON_EXCEPTION(isolate, desc_obj, Object::GetProperty(&it),
6196 : Object);
6197 : // 7c iii. Let desc be ToPropertyDescriptor(descObj).
6198 : success = PropertyDescriptor::ToPropertyDescriptor(
6199 336646 : isolate, desc_obj, &descriptors[descriptors_index]);
6200 : // 7c iv. ReturnIfAbrupt(desc).
6201 168323 : if (!success) return MaybeHandle<Object>();
6202 : // 7c v. Append the pair (a two element List) consisting of nextKey and
6203 : // desc to the end of descriptors.
6204 167964 : descriptors[descriptors_index].set_name(next_key);
6205 167964 : descriptors_index++;
6206 : }
6207 : // 8. For each pair from descriptors in list order,
6208 167290 : for (size_t i = 0; i < descriptors_index; ++i) {
6209 167290 : PropertyDescriptor* desc = &descriptors[i];
6210 : // 8a. Let P be the first element of pair.
6211 : // 8b. Let desc be the second element of pair.
6212 : // 8c. Let status be DefinePropertyOrThrow(O, P, desc).
6213 : Maybe<bool> status =
6214 : DefineOwnProperty(isolate, Handle<JSReceiver>::cast(object),
6215 167290 : desc->name(), desc, THROW_ON_ERROR);
6216 : // 8d. ReturnIfAbrupt(status).
6217 167290 : if (!status.IsJust()) return MaybeHandle<Object>();
6218 167290 : CHECK(status.FromJust());
6219 : }
6220 : // 9. Return o.
6221 : return object;
6222 : }
6223 :
6224 :
6225 : // static
6226 647894 : Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate,
6227 : Handle<JSReceiver> object,
6228 : Handle<Object> key,
6229 : PropertyDescriptor* desc,
6230 : ShouldThrow should_throw) {
6231 647894 : if (object->IsJSArray()) {
6232 : return JSArray::DefineOwnProperty(isolate, Handle<JSArray>::cast(object),
6233 80669 : key, desc, should_throw);
6234 : }
6235 567225 : if (object->IsJSProxy()) {
6236 : return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object),
6237 5822 : key, desc, should_throw);
6238 : }
6239 561403 : if (object->IsJSTypedArray()) {
6240 : return JSTypedArray::DefineOwnProperty(
6241 4786 : isolate, Handle<JSTypedArray>::cast(object), key, desc, should_throw);
6242 : }
6243 : // TODO(neis): Special case for JSModuleNamespace?
6244 :
6245 : // OrdinaryDefineOwnProperty, by virtue of calling
6246 : // DefineOwnPropertyIgnoreAttributes, can handle arguments
6247 : // (ES#sec-arguments-exotic-objects-defineownproperty-p-desc).
6248 : return OrdinaryDefineOwnProperty(isolate, Handle<JSObject>::cast(object), key,
6249 556617 : desc, should_throw);
6250 : }
6251 :
6252 :
6253 : // static
6254 662258 : Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate,
6255 : Handle<JSObject> object,
6256 : Handle<Object> key,
6257 : PropertyDescriptor* desc,
6258 : ShouldThrow should_throw) {
6259 662258 : bool success = false;
6260 : DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
6261 : LookupIterator it = LookupIterator::PropertyOrElement(
6262 662258 : isolate, object, key, &success, LookupIterator::OWN);
6263 : DCHECK(success); // ...so creating a LookupIterator can't fail.
6264 :
6265 : // Deal with access checks first.
6266 662258 : if (it.state() == LookupIterator::ACCESS_CHECK) {
6267 3716 : if (!it.HasAccess()) {
6268 36 : isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>());
6269 36 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6270 : return Just(true);
6271 : }
6272 3680 : it.Next();
6273 : }
6274 :
6275 : // Handle interceptor
6276 662222 : if (it.state() == LookupIterator::INTERCEPTOR) {
6277 208 : if (it.HolderIsReceiverOrHiddenPrototype()) {
6278 : Maybe<bool> result = DefinePropertyWithInterceptorInternal(
6279 208 : &it, it.GetInterceptor(), should_throw, *desc);
6280 416 : if (result.IsNothing() || result.FromJust()) {
6281 63 : return result;
6282 : }
6283 : }
6284 : }
6285 :
6286 662159 : return OrdinaryDefineOwnProperty(&it, desc, should_throw);
6287 : }
6288 :
6289 :
6290 : // ES6 9.1.6.1
6291 : // static
6292 662159 : Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
6293 : PropertyDescriptor* desc,
6294 : ShouldThrow should_throw) {
6295 : Isolate* isolate = it->isolate();
6296 : // 1. Let current be O.[[GetOwnProperty]](P).
6297 : // 2. ReturnIfAbrupt(current).
6298 : PropertyDescriptor current;
6299 662159 : MAYBE_RETURN(GetOwnPropertyDescriptor(it, ¤t), Nothing<bool>());
6300 :
6301 : // TODO(jkummerow/verwaest): It would be nice if we didn't have to reset
6302 : // the iterator every time. Currently, the reasons why we need it are:
6303 : // - handle interceptors correctly
6304 : // - handle accessors correctly (which might change the holder's map)
6305 662159 : it->Restart();
6306 : // 3. Let extensible be the value of the [[Extensible]] internal slot of O.
6307 662159 : Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
6308 662159 : bool extensible = JSObject::IsExtensible(object);
6309 :
6310 : return ValidateAndApplyPropertyDescriptor(isolate, it, extensible, desc,
6311 662159 : ¤t, should_throw);
6312 : }
6313 :
6314 :
6315 : // ES6 9.1.6.2
6316 : // static
6317 0 : Maybe<bool> JSReceiver::IsCompatiblePropertyDescriptor(
6318 : Isolate* isolate, bool extensible, PropertyDescriptor* desc,
6319 : PropertyDescriptor* current, Handle<Name> property_name,
6320 : ShouldThrow should_throw) {
6321 : // 1. Return ValidateAndApplyPropertyDescriptor(undefined, undefined,
6322 : // Extensible, Desc, Current).
6323 : return ValidateAndApplyPropertyDescriptor(
6324 6987 : isolate, NULL, extensible, desc, current, should_throw, property_name);
6325 : }
6326 :
6327 :
6328 : // ES6 9.1.6.3
6329 : // static
6330 669146 : Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor(
6331 : Isolate* isolate, LookupIterator* it, bool extensible,
6332 : PropertyDescriptor* desc, PropertyDescriptor* current,
6333 : ShouldThrow should_throw, Handle<Name> property_name) {
6334 : // We either need a LookupIterator, or a property name.
6335 : DCHECK((it == NULL) != property_name.is_null());
6336 : Handle<JSObject> object;
6337 : if (it != NULL) object = Handle<JSObject>::cast(it->GetReceiver());
6338 : bool desc_is_data_descriptor = PropertyDescriptor::IsDataDescriptor(desc);
6339 : bool desc_is_accessor_descriptor =
6340 : PropertyDescriptor::IsAccessorDescriptor(desc);
6341 : bool desc_is_generic_descriptor =
6342 : PropertyDescriptor::IsGenericDescriptor(desc);
6343 : // 1. (Assert)
6344 : // 2. If current is undefined, then
6345 669146 : if (current->is_empty()) {
6346 : // 2a. If extensible is false, return false.
6347 522769 : if (!extensible) {
6348 667 : RETURN_FAILURE(isolate, should_throw,
6349 : NewTypeError(MessageTemplate::kDefineDisallowed,
6350 : it != NULL ? it->GetName() : property_name));
6351 : }
6352 : // 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then:
6353 : // (This is equivalent to !IsAccessorDescriptor(desc).)
6354 : DCHECK((desc_is_generic_descriptor || desc_is_data_descriptor) ==
6355 : !desc_is_accessor_descriptor);
6356 522549 : if (!desc_is_accessor_descriptor) {
6357 : // 2c i. If O is not undefined, create an own data property named P of
6358 : // object O whose [[Value]], [[Writable]], [[Enumerable]] and
6359 : // [[Configurable]] attribute values are described by Desc. If the value
6360 : // of an attribute field of Desc is absent, the attribute of the newly
6361 : // created property is set to its default value.
6362 420612 : if (it != NULL) {
6363 416720 : if (!desc->has_writable()) desc->set_writable(false);
6364 416720 : if (!desc->has_enumerable()) desc->set_enumerable(false);
6365 416720 : if (!desc->has_configurable()) desc->set_configurable(false);
6366 : Handle<Object> value(
6367 : desc->has_value()
6368 : ? desc->value()
6369 416720 : : Handle<Object>::cast(isolate->factory()->undefined_value()));
6370 : MaybeHandle<Object> result =
6371 : JSObject::DefineOwnPropertyIgnoreAttributes(it, value,
6372 416720 : desc->ToAttributes());
6373 416720 : if (result.is_null()) return Nothing<bool>();
6374 : }
6375 : } else {
6376 : // 2d. Else Desc must be an accessor Property Descriptor,
6377 : DCHECK(desc_is_accessor_descriptor);
6378 : // 2d i. If O is not undefined, create an own accessor property named P
6379 : // of object O whose [[Get]], [[Set]], [[Enumerable]] and
6380 : // [[Configurable]] attribute values are described by Desc. If the value
6381 : // of an attribute field of Desc is absent, the attribute of the newly
6382 : // created property is set to its default value.
6383 101937 : if (it != NULL) {
6384 101713 : if (!desc->has_enumerable()) desc->set_enumerable(false);
6385 101713 : if (!desc->has_configurable()) desc->set_configurable(false);
6386 : Handle<Object> getter(
6387 : desc->has_get()
6388 : ? desc->get()
6389 120469 : : Handle<Object>::cast(isolate->factory()->null_value()));
6390 : Handle<Object> setter(
6391 : desc->has_set()
6392 : ? desc->set()
6393 165985 : : Handle<Object>::cast(isolate->factory()->null_value()));
6394 : MaybeHandle<Object> result =
6395 101713 : JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes());
6396 101713 : if (result.is_null()) return Nothing<bool>();
6397 : }
6398 : }
6399 : // 2e. Return true.
6400 : return Just(true);
6401 : }
6402 : // 3. Return true, if every field in Desc is absent.
6403 : // 4. Return true, if every field in Desc also occurs in current and the
6404 : // value of every field in Desc is the same value as the corresponding field
6405 : // in current when compared using the SameValue algorithm.
6406 209179 : if ((!desc->has_enumerable() ||
6407 144914 : desc->enumerable() == current->enumerable()) &&
6408 90228 : (!desc->has_configurable() ||
6409 141164 : desc->configurable() == current->configurable()) &&
6410 114821 : (!desc->has_value() ||
6411 216819 : (current->has_value() && current->value()->SameValue(*desc->value()))) &&
6412 77568 : (!desc->has_writable() ||
6413 160725 : (current->has_writable() && current->writable() == desc->writable())) &&
6414 8350 : (!desc->has_get() ||
6415 227636 : (current->has_get() && current->get()->SameValue(*desc->get()))) &&
6416 11182 : (!desc->has_set() ||
6417 10889 : (current->has_set() && current->set()->SameValue(*desc->set())))) {
6418 : return Just(true);
6419 : }
6420 : // 5. If the [[Configurable]] field of current is false, then
6421 82274 : if (!current->configurable()) {
6422 : // 5a. Return false, if the [[Configurable]] field of Desc is true.
6423 28431 : if (desc->has_configurable() && desc->configurable()) {
6424 809 : RETURN_FAILURE(isolate, should_throw,
6425 : NewTypeError(MessageTemplate::kRedefineDisallowed,
6426 : it != NULL ? it->GetName() : property_name));
6427 : }
6428 : // 5b. Return false, if the [[Enumerable]] field of Desc is present and the
6429 : // [[Enumerable]] fields of current and Desc are the Boolean negation of
6430 : // each other.
6431 27434 : if (desc->has_enumerable() && desc->enumerable() != current->enumerable()) {
6432 452 : RETURN_FAILURE(isolate, should_throw,
6433 : NewTypeError(MessageTemplate::kRedefineDisallowed,
6434 : it != NULL ? it->GetName() : property_name));
6435 : }
6436 : }
6437 :
6438 : bool current_is_data_descriptor =
6439 : PropertyDescriptor::IsDataDescriptor(current);
6440 : // 6. If IsGenericDescriptor(Desc) is true, no further validation is required.
6441 81796 : if (desc_is_generic_descriptor) {
6442 : // Nothing to see here.
6443 :
6444 : // 7. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) have
6445 : // different results, then:
6446 80377 : } else if (current_is_data_descriptor != desc_is_data_descriptor) {
6447 : // 7a. Return false, if the [[Configurable]] field of current is false.
6448 3678 : if (!current->configurable()) {
6449 671 : RETURN_FAILURE(isolate, should_throw,
6450 : NewTypeError(MessageTemplate::kRedefineDisallowed,
6451 : it != NULL ? it->GetName() : property_name));
6452 : }
6453 : // 7b. If IsDataDescriptor(current) is true, then:
6454 : if (current_is_data_descriptor) {
6455 : // 7b i. If O is not undefined, convert the property named P of object O
6456 : // from a data property to an accessor property. Preserve the existing
6457 : // values of the converted property's [[Configurable]] and [[Enumerable]]
6458 : // attributes and set the rest of the property's attributes to their
6459 : // default values.
6460 : // --> Folded into step 10.
6461 : } else {
6462 : // 7c i. If O is not undefined, convert the property named P of object O
6463 : // from an accessor property to a data property. Preserve the existing
6464 : // values of the converted property’s [[Configurable]] and [[Enumerable]]
6465 : // attributes and set the rest of the property’s attributes to their
6466 : // default values.
6467 : // --> Folded into step 10.
6468 : }
6469 :
6470 : // 8. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both
6471 : // true, then:
6472 76699 : } else if (current_is_data_descriptor && desc_is_data_descriptor) {
6473 : // 8a. If the [[Configurable]] field of current is false, then:
6474 59633 : if (!current->configurable()) {
6475 : // 8a i. Return false, if the [[Writable]] field of current is false and
6476 : // the [[Writable]] field of Desc is true.
6477 23582 : if (!current->writable() && desc->has_writable() && desc->writable()) {
6478 298 : RETURN_FAILURE(
6479 : isolate, should_throw,
6480 : NewTypeError(MessageTemplate::kRedefineDisallowed,
6481 : it != NULL ? it->GetName() : property_name));
6482 : }
6483 : // 8a ii. If the [[Writable]] field of current is false, then:
6484 22941 : if (!current->writable()) {
6485 : // 8a ii 1. Return false, if the [[Value]] field of Desc is present and
6486 : // SameValue(Desc.[[Value]], current.[[Value]]) is false.
6487 714 : if (desc->has_value() && !desc->value()->SameValue(*current->value())) {
6488 1224 : RETURN_FAILURE(
6489 : isolate, should_throw,
6490 : NewTypeError(MessageTemplate::kRedefineDisallowed,
6491 : it != NULL ? it->GetName() : property_name));
6492 : }
6493 : }
6494 : }
6495 : } else {
6496 : // 9. Else IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc)
6497 : // are both true,
6498 : DCHECK(PropertyDescriptor::IsAccessorDescriptor(current) &&
6499 : desc_is_accessor_descriptor);
6500 : // 9a. If the [[Configurable]] field of current is false, then:
6501 17066 : if (!current->configurable()) {
6502 : // 9a i. Return false, if the [[Set]] field of Desc is present and
6503 : // SameValue(Desc.[[Set]], current.[[Set]]) is false.
6504 220 : if (desc->has_set() && !desc->set()->SameValue(*current->set())) {
6505 186 : RETURN_FAILURE(
6506 : isolate, should_throw,
6507 : NewTypeError(MessageTemplate::kRedefineDisallowed,
6508 : it != NULL ? it->GetName() : property_name));
6509 : }
6510 : // 9a ii. Return false, if the [[Get]] field of Desc is present and
6511 : // SameValue(Desc.[[Get]], current.[[Get]]) is false.
6512 154 : if (desc->has_get() && !desc->get()->SameValue(*current->get())) {
6513 248 : RETURN_FAILURE(
6514 : isolate, should_throw,
6515 : NewTypeError(MessageTemplate::kRedefineDisallowed,
6516 : it != NULL ? it->GetName() : property_name));
6517 : }
6518 : }
6519 : }
6520 :
6521 : // 10. If O is not undefined, then:
6522 81020 : if (it != NULL) {
6523 : // 10a. For each field of Desc that is present, set the corresponding
6524 : // attribute of the property named P of object O to the value of the field.
6525 : PropertyAttributes attrs = NONE;
6526 :
6527 80656 : if (desc->has_enumerable()) {
6528 : attrs = static_cast<PropertyAttributes>(
6529 8755 : attrs | (desc->enumerable() ? NONE : DONT_ENUM));
6530 : } else {
6531 : attrs = static_cast<PropertyAttributes>(
6532 71901 : attrs | (current->enumerable() ? NONE : DONT_ENUM));
6533 : }
6534 80656 : if (desc->has_configurable()) {
6535 : attrs = static_cast<PropertyAttributes>(
6536 27238 : attrs | (desc->configurable() ? NONE : DONT_DELETE));
6537 : } else {
6538 : attrs = static_cast<PropertyAttributes>(
6539 53418 : attrs | (current->configurable() ? NONE : DONT_DELETE));
6540 : }
6541 101809 : if (desc_is_data_descriptor ||
6542 21153 : (desc_is_generic_descriptor && current_is_data_descriptor)) {
6543 60762 : if (desc->has_writable()) {
6544 : attrs = static_cast<PropertyAttributes>(
6545 56382 : attrs | (desc->writable() ? NONE : READ_ONLY));
6546 : } else {
6547 : attrs = static_cast<PropertyAttributes>(
6548 4380 : attrs | (current->writable() ? NONE : READ_ONLY));
6549 : }
6550 : Handle<Object> value(
6551 : desc->has_value() ? desc->value()
6552 : : current->has_value()
6553 : ? current->value()
6554 : : Handle<Object>::cast(
6555 64925 : isolate->factory()->undefined_value()));
6556 : MaybeHandle<Object> result =
6557 : JSObject::DefineOwnPropertyIgnoreAttributes(it, value, attrs);
6558 60762 : if (result.is_null()) return Nothing<bool>();
6559 : } else {
6560 : DCHECK(desc_is_accessor_descriptor ||
6561 : (desc_is_generic_descriptor &&
6562 : PropertyDescriptor::IsAccessorDescriptor(current)));
6563 : Handle<Object> getter(
6564 : desc->has_get()
6565 : ? desc->get()
6566 : : current->has_get()
6567 : ? current->get()
6568 31570 : : Handle<Object>::cast(isolate->factory()->null_value()));
6569 : Handle<Object> setter(
6570 : desc->has_set()
6571 : ? desc->set()
6572 : : current->has_set()
6573 : ? current->set()
6574 29738 : : Handle<Object>::cast(isolate->factory()->null_value()));
6575 : MaybeHandle<Object> result =
6576 19894 : JSObject::DefineAccessor(it, getter, setter, attrs);
6577 19894 : if (result.is_null()) return Nothing<bool>();
6578 : }
6579 : }
6580 :
6581 : // 11. Return true.
6582 : return Just(true);
6583 : }
6584 :
6585 :
6586 : // static
6587 371016 : Maybe<bool> JSReceiver::CreateDataProperty(LookupIterator* it,
6588 : Handle<Object> value,
6589 : ShouldThrow should_throw) {
6590 : DCHECK(!it->check_prototype_chain());
6591 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
6592 : Isolate* isolate = receiver->GetIsolate();
6593 :
6594 371016 : if (receiver->IsJSObject()) {
6595 369929 : return JSObject::CreateDataProperty(it, value, should_throw); // Shortcut.
6596 : }
6597 :
6598 : PropertyDescriptor new_desc;
6599 : new_desc.set_value(value);
6600 : new_desc.set_writable(true);
6601 : new_desc.set_enumerable(true);
6602 : new_desc.set_configurable(true);
6603 :
6604 : return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
6605 2174 : &new_desc, should_throw);
6606 : }
6607 :
6608 746712 : Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it,
6609 : Handle<Object> value,
6610 : ShouldThrow should_throw) {
6611 : DCHECK(it->GetReceiver()->IsJSObject());
6612 373359 : MAYBE_RETURN(JSReceiver::GetPropertyAttributes(it), Nothing<bool>());
6613 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
6614 : Isolate* isolate = receiver->GetIsolate();
6615 :
6616 373353 : if (it->IsFound()) {
6617 200496 : Maybe<PropertyAttributes> attributes = GetPropertyAttributes(it);
6618 200551 : MAYBE_RETURN(attributes, Nothing<bool>());
6619 200496 : if ((attributes.FromJust() & DONT_DELETE) != 0) {
6620 184 : RETURN_FAILURE(
6621 : isolate, should_throw,
6622 : NewTypeError(MessageTemplate::kRedefineDisallowed, it->GetName()));
6623 : }
6624 : } else {
6625 172857 : if (!JSObject::IsExtensible(Handle<JSObject>::cast(it->GetReceiver()))) {
6626 350 : RETURN_FAILURE(
6627 : isolate, should_throw,
6628 : NewTypeError(MessageTemplate::kDefineDisallowed, it->GetName()));
6629 : }
6630 : }
6631 :
6632 373206 : RETURN_ON_EXCEPTION_VALUE(it->isolate(),
6633 : DefineOwnPropertyIgnoreAttributes(it, value, NONE),
6634 : Nothing<bool>());
6635 :
6636 : return Just(true);
6637 : }
6638 :
6639 :
6640 : // TODO(jkummerow): Consider unification with FastAsArrayLength() in
6641 : // accessors.cc.
6642 62431 : bool PropertyKeyToArrayLength(Handle<Object> value, uint32_t* length) {
6643 : DCHECK(value->IsNumber() || value->IsName());
6644 62431 : if (value->ToArrayLength(length)) return true;
6645 83510 : if (value->IsString()) return String::cast(*value)->AsArrayIndex(length);
6646 : return false;
6647 : }
6648 :
6649 0 : bool PropertyKeyToArrayIndex(Handle<Object> index_obj, uint32_t* output) {
6650 62431 : return PropertyKeyToArrayLength(index_obj, output) && *output != kMaxUInt32;
6651 : }
6652 :
6653 :
6654 : // ES6 9.4.2.1
6655 : // static
6656 80669 : Maybe<bool> JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o,
6657 : Handle<Object> name,
6658 : PropertyDescriptor* desc,
6659 : ShouldThrow should_throw) {
6660 : // 1. Assert: IsPropertyKey(P) is true. ("P" is |name|.)
6661 : // 2. If P is "length", then:
6662 : // TODO(jkummerow): Check if we need slow string comparison.
6663 80669 : if (*name == isolate->heap()->length_string()) {
6664 : // 2a. Return ArraySetLength(A, Desc).
6665 18238 : return ArraySetLength(isolate, o, desc, should_throw);
6666 : }
6667 : // 3. Else if P is an array index, then:
6668 62431 : uint32_t index = 0;
6669 62431 : if (PropertyKeyToArrayIndex(name, &index)) {
6670 : // 3a. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
6671 : PropertyDescriptor old_len_desc;
6672 : Maybe<bool> success = GetOwnPropertyDescriptor(
6673 59292 : isolate, o, isolate->factory()->length_string(), &old_len_desc);
6674 : // 3b. (Assert)
6675 : DCHECK(success.FromJust());
6676 : USE(success);
6677 : // 3c. Let oldLen be oldLenDesc.[[Value]].
6678 59292 : uint32_t old_len = 0;
6679 59292 : CHECK(old_len_desc.value()->ToArrayLength(&old_len));
6680 : // 3d. Let index be ToUint32(P).
6681 : // (Already done above.)
6682 : // 3e. (Assert)
6683 : // 3f. If index >= oldLen and oldLenDesc.[[Writable]] is false,
6684 : // return false.
6685 100272 : if (index >= old_len && old_len_desc.has_writable() &&
6686 : !old_len_desc.writable()) {
6687 0 : RETURN_FAILURE(isolate, should_throw,
6688 : NewTypeError(MessageTemplate::kDefineDisallowed, name));
6689 : }
6690 : // 3g. Let succeeded be OrdinaryDefineOwnProperty(A, P, Desc).
6691 : Maybe<bool> succeeded =
6692 59292 : OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
6693 : // 3h. Assert: succeeded is not an abrupt completion.
6694 : // In our case, if should_throw == THROW_ON_ERROR, it can be!
6695 : // 3i. If succeeded is false, return false.
6696 118457 : if (succeeded.IsNothing() || !succeeded.FromJust()) return succeeded;
6697 : // 3j. If index >= oldLen, then:
6698 59151 : if (index >= old_len) {
6699 : // 3j i. Set oldLenDesc.[[Value]] to index + 1.
6700 20490 : old_len_desc.set_value(isolate->factory()->NewNumberFromUint(index + 1));
6701 : // 3j ii. Let succeeded be
6702 : // OrdinaryDefineOwnProperty(A, "length", oldLenDesc).
6703 : succeeded = OrdinaryDefineOwnProperty(isolate, o,
6704 : isolate->factory()->length_string(),
6705 20490 : &old_len_desc, should_throw);
6706 : // 3j iii. Assert: succeeded is true.
6707 : DCHECK(succeeded.FromJust());
6708 : USE(succeeded);
6709 : }
6710 : // 3k. Return true.
6711 : return Just(true);
6712 : }
6713 :
6714 : // 4. Return OrdinaryDefineOwnProperty(A, P, Desc).
6715 3139 : return OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
6716 : }
6717 :
6718 :
6719 : // Part of ES6 9.4.2.4 ArraySetLength.
6720 : // static
6721 1021233 : bool JSArray::AnythingToArrayLength(Isolate* isolate,
6722 : Handle<Object> length_object,
6723 : uint32_t* output) {
6724 : // Fast path: check numbers and strings that can be converted directly
6725 : // and unobservably.
6726 1021233 : if (length_object->ToArrayLength(output)) return true;
6727 533158 : if (length_object->IsString() &&
6728 30 : Handle<String>::cast(length_object)->AsArrayIndex(output)) {
6729 : return true;
6730 : }
6731 : // Slow path: follow steps in ES6 9.4.2.4 "ArraySetLength".
6732 : // 3. Let newLen be ToUint32(Desc.[[Value]]).
6733 : Handle<Object> uint32_v;
6734 1066226 : if (!Object::ToUint32(isolate, length_object).ToHandle(&uint32_v)) {
6735 : // 4. ReturnIfAbrupt(newLen).
6736 : return false;
6737 : }
6738 : // 5. Let numberLen be ToNumber(Desc.[[Value]]).
6739 : Handle<Object> number_v;
6740 1066196 : if (!Object::ToNumber(length_object).ToHandle(&number_v)) {
6741 : // 6. ReturnIfAbrupt(newLen).
6742 : return false;
6743 : }
6744 : // 7. If newLen != numberLen, throw a RangeError exception.
6745 533098 : if (uint32_v->Number() != number_v->Number()) {
6746 : Handle<Object> exception =
6747 386 : isolate->factory()->NewRangeError(MessageTemplate::kInvalidArrayLength);
6748 386 : isolate->Throw(*exception);
6749 : return false;
6750 : }
6751 532712 : CHECK(uint32_v->ToArrayLength(output));
6752 : return true;
6753 : }
6754 :
6755 :
6756 : // ES6 9.4.2.4
6757 : // static
6758 18238 : Maybe<bool> JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a,
6759 : PropertyDescriptor* desc,
6760 : ShouldThrow should_throw) {
6761 : // 1. If the [[Value]] field of Desc is absent, then
6762 18238 : if (!desc->has_value()) {
6763 : // 1a. Return OrdinaryDefineOwnProperty(A, "length", Desc).
6764 : return OrdinaryDefineOwnProperty(
6765 400 : isolate, a, isolate->factory()->length_string(), desc, should_throw);
6766 : }
6767 : // 2. Let newLenDesc be a copy of Desc.
6768 : // (Actual copying is not necessary.)
6769 : PropertyDescriptor* new_len_desc = desc;
6770 : // 3. - 7. Convert Desc.[[Value]] to newLen.
6771 17838 : uint32_t new_len = 0;
6772 17838 : if (!AnythingToArrayLength(isolate, desc->value(), &new_len)) {
6773 : DCHECK(isolate->has_pending_exception());
6774 : return Nothing<bool>();
6775 : }
6776 : // 8. Set newLenDesc.[[Value]] to newLen.
6777 : // (Done below, if needed.)
6778 : // 9. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
6779 : PropertyDescriptor old_len_desc;
6780 : Maybe<bool> success = GetOwnPropertyDescriptor(
6781 17823 : isolate, a, isolate->factory()->length_string(), &old_len_desc);
6782 : // 10. (Assert)
6783 : DCHECK(success.FromJust());
6784 : USE(success);
6785 : // 11. Let oldLen be oldLenDesc.[[Value]].
6786 17823 : uint32_t old_len = 0;
6787 17823 : CHECK(old_len_desc.value()->ToArrayLength(&old_len));
6788 : // 12. If newLen >= oldLen, then
6789 17823 : if (new_len >= old_len) {
6790 : // 8. Set newLenDesc.[[Value]] to newLen.
6791 : // 12a. Return OrdinaryDefineOwnProperty(A, "length", newLenDesc).
6792 17809 : new_len_desc->set_value(isolate->factory()->NewNumberFromUint(new_len));
6793 : return OrdinaryDefineOwnProperty(isolate, a,
6794 : isolate->factory()->length_string(),
6795 17809 : new_len_desc, should_throw);
6796 : }
6797 : // 13. If oldLenDesc.[[Writable]] is false, return false.
6798 14 : if (!old_len_desc.writable()) {
6799 0 : RETURN_FAILURE(isolate, should_throw,
6800 : NewTypeError(MessageTemplate::kRedefineDisallowed,
6801 : isolate->factory()->length_string()));
6802 : }
6803 : // 14. If newLenDesc.[[Writable]] is absent or has the value true,
6804 : // let newWritable be true.
6805 : bool new_writable = false;
6806 14 : if (!new_len_desc->has_writable() || new_len_desc->writable()) {
6807 : new_writable = true;
6808 : } else {
6809 : // 15. Else,
6810 : // 15a. Need to defer setting the [[Writable]] attribute to false in case
6811 : // any elements cannot be deleted.
6812 : // 15b. Let newWritable be false. (It's initialized as "false" anyway.)
6813 : // 15c. Set newLenDesc.[[Writable]] to true.
6814 : // (Not needed.)
6815 : }
6816 : // Most of steps 16 through 19 is implemented by JSArray::SetLength.
6817 14 : JSArray::SetLength(a, new_len);
6818 : // Steps 19d-ii, 20.
6819 14 : if (!new_writable) {
6820 : PropertyDescriptor readonly;
6821 : readonly.set_writable(false);
6822 : Maybe<bool> success = OrdinaryDefineOwnProperty(
6823 : isolate, a, isolate->factory()->length_string(), &readonly,
6824 0 : should_throw);
6825 : DCHECK(success.FromJust());
6826 : USE(success);
6827 : }
6828 14 : uint32_t actual_new_len = 0;
6829 14 : CHECK(a->length()->ToArrayLength(&actual_new_len));
6830 : // Steps 19d-v, 21. Return false if there were non-deletable elements.
6831 14 : bool result = actual_new_len == new_len;
6832 14 : if (!result) {
6833 14 : RETURN_FAILURE(
6834 : isolate, should_throw,
6835 : NewTypeError(MessageTemplate::kStrictDeleteProperty,
6836 : isolate->factory()->NewNumberFromUint(actual_new_len - 1),
6837 : a));
6838 : }
6839 : return Just(result);
6840 : }
6841 :
6842 :
6843 : // ES6 9.5.6
6844 : // static
6845 5822 : Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy,
6846 : Handle<Object> key,
6847 : PropertyDescriptor* desc,
6848 : ShouldThrow should_throw) {
6849 5822 : STACK_CHECK(isolate, Nothing<bool>());
6850 6214 : if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) {
6851 : return SetPrivateProperty(isolate, proxy, Handle<Symbol>::cast(key), desc,
6852 28 : should_throw);
6853 : }
6854 : Handle<String> trap_name = isolate->factory()->defineProperty_string();
6855 : // 1. Assert: IsPropertyKey(P) is true.
6856 : DCHECK(key->IsName() || key->IsNumber());
6857 : // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
6858 : Handle<Object> handler(proxy->handler(), isolate);
6859 : // 3. If handler is null, throw a TypeError exception.
6860 : // 4. Assert: Type(handler) is Object.
6861 5794 : if (proxy->IsRevoked()) {
6862 : isolate->Throw(*isolate->factory()->NewTypeError(
6863 28 : MessageTemplate::kProxyRevoked, trap_name));
6864 : return Nothing<bool>();
6865 : }
6866 : // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
6867 : Handle<JSReceiver> target(proxy->target(), isolate);
6868 : // 6. Let trap be ? GetMethod(handler, "defineProperty").
6869 : Handle<Object> trap;
6870 11560 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
6871 : isolate, trap,
6872 : Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
6873 : Nothing<bool>());
6874 : // 7. If trap is undefined, then:
6875 5640 : if (trap->IsUndefined(isolate)) {
6876 : // 7a. Return target.[[DefineOwnProperty]](P, Desc).
6877 : return JSReceiver::DefineOwnProperty(isolate, target, key, desc,
6878 2810 : should_throw);
6879 : }
6880 : // 8. Let descObj be FromPropertyDescriptor(Desc).
6881 2830 : Handle<Object> desc_obj = desc->ToObject(isolate);
6882 : // 9. Let booleanTrapResult be
6883 : // ToBoolean(? Call(trap, handler, «target, P, descObj»)).
6884 : Handle<Name> property_name =
6885 : key->IsName()
6886 : ? Handle<Name>::cast(key)
6887 2830 : : Handle<Name>::cast(isolate->factory()->NumberToString(key));
6888 : // Do not leak private property names.
6889 : DCHECK(!property_name->IsPrivate());
6890 : Handle<Object> trap_result_obj;
6891 2830 : Handle<Object> args[] = {target, property_name, desc_obj};
6892 5660 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
6893 : isolate, trap_result_obj,
6894 : Execution::Call(isolate, trap, handler, arraysize(args), args),
6895 : Nothing<bool>());
6896 : // 10. If booleanTrapResult is false, return false.
6897 2017 : if (!trap_result_obj->BooleanValue()) {
6898 154 : RETURN_FAILURE(isolate, should_throw,
6899 : NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
6900 : trap_name, property_name));
6901 : }
6902 : // 11. Let targetDesc be ? target.[[GetOwnProperty]](P).
6903 : PropertyDescriptor target_desc;
6904 : Maybe<bool> target_found =
6905 1891 : JSReceiver::GetOwnPropertyDescriptor(isolate, target, key, &target_desc);
6906 1891 : MAYBE_RETURN(target_found, Nothing<bool>());
6907 : // 12. Let extensibleTarget be ? IsExtensible(target).
6908 1891 : Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
6909 1891 : MAYBE_RETURN(maybe_extensible, Nothing<bool>());
6910 : bool extensible_target = maybe_extensible.FromJust();
6911 : // 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]]
6912 : // is false, then:
6913 : // 13a. Let settingConfigFalse be true.
6914 : // 14. Else let settingConfigFalse be false.
6915 2956 : bool setting_config_false = desc->has_configurable() && !desc->configurable();
6916 : // 15. If targetDesc is undefined, then
6917 1891 : if (!target_found.FromJust()) {
6918 : // 15a. If extensibleTarget is false, throw a TypeError exception.
6919 966 : if (!extensible_target) {
6920 : isolate->Throw(*isolate->factory()->NewTypeError(
6921 28 : MessageTemplate::kProxyDefinePropertyNonExtensible, property_name));
6922 : return Nothing<bool>();
6923 : }
6924 : // 15b. If settingConfigFalse is true, throw a TypeError exception.
6925 952 : if (setting_config_false) {
6926 : isolate->Throw(*isolate->factory()->NewTypeError(
6927 28 : MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
6928 : return Nothing<bool>();
6929 : }
6930 : } else {
6931 : // 16. Else targetDesc is not undefined,
6932 : // 16a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc,
6933 : // targetDesc) is false, throw a TypeError exception.
6934 : Maybe<bool> valid =
6935 : IsCompatiblePropertyDescriptor(isolate, extensible_target, desc,
6936 : &target_desc, property_name, DONT_THROW);
6937 925 : MAYBE_RETURN(valid, Nothing<bool>());
6938 925 : if (!valid.FromJust()) {
6939 : isolate->Throw(*isolate->factory()->NewTypeError(
6940 28 : MessageTemplate::kProxyDefinePropertyIncompatible, property_name));
6941 : return Nothing<bool>();
6942 : }
6943 : // 16b. If settingConfigFalse is true and targetDesc.[[Configurable]] is
6944 : // true, throw a TypeError exception.
6945 1051 : if (setting_config_false && target_desc.configurable()) {
6946 : isolate->Throw(*isolate->factory()->NewTypeError(
6947 28 : MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
6948 : return Nothing<bool>();
6949 : }
6950 : }
6951 : // 17. Return true.
6952 : return Just(true);
6953 : }
6954 :
6955 :
6956 : // static
6957 49 : Maybe<bool> JSProxy::SetPrivateProperty(Isolate* isolate, Handle<JSProxy> proxy,
6958 : Handle<Symbol> private_name,
6959 : PropertyDescriptor* desc,
6960 : ShouldThrow should_throw) {
6961 : // Despite the generic name, this can only add private data properties.
6962 70 : if (!PropertyDescriptor::IsDataDescriptor(desc) ||
6963 21 : desc->ToAttributes() != DONT_ENUM) {
6964 56 : RETURN_FAILURE(isolate, should_throw,
6965 : NewTypeError(MessageTemplate::kProxyPrivate));
6966 : }
6967 : DCHECK(proxy->map()->is_dictionary_map());
6968 : Handle<Object> value =
6969 : desc->has_value()
6970 : ? desc->value()
6971 21 : : Handle<Object>::cast(isolate->factory()->undefined_value());
6972 :
6973 21 : LookupIterator it(proxy, private_name, proxy);
6974 :
6975 21 : if (it.IsFound()) {
6976 : DCHECK_EQ(LookupIterator::DATA, it.state());
6977 : DCHECK_EQ(DONT_ENUM, it.property_attributes());
6978 7 : it.WriteDataValue(value, false);
6979 : return Just(true);
6980 : }
6981 :
6982 : Handle<NameDictionary> dict(proxy->property_dictionary());
6983 : PropertyDetails details(kData, DONT_ENUM, 0, PropertyCellType::kNoCell);
6984 : Handle<NameDictionary> result =
6985 14 : NameDictionary::Add(dict, private_name, value, details);
6986 21 : if (!dict.is_identical_to(result)) proxy->set_properties(*result);
6987 : return Just(true);
6988 : }
6989 :
6990 :
6991 : // static
6992 3691025 : Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate,
6993 : Handle<JSReceiver> object,
6994 : Handle<Object> key,
6995 : PropertyDescriptor* desc) {
6996 3691025 : bool success = false;
6997 : DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
6998 : LookupIterator it = LookupIterator::PropertyOrElement(
6999 3691025 : isolate, object, key, &success, LookupIterator::OWN);
7000 : DCHECK(success); // ...so creating a LookupIterator can't fail.
7001 3691025 : return GetOwnPropertyDescriptor(&it, desc);
7002 : }
7003 :
7004 : namespace {
7005 :
7006 8694658 : Maybe<bool> GetPropertyDescriptorWithInterceptor(LookupIterator* it,
7007 : PropertyDescriptor* desc) {
7008 : bool has_access = true;
7009 4347220 : if (it->state() == LookupIterator::ACCESS_CHECK) {
7010 3156992 : has_access = it->HasAccess() || JSObject::AllCanRead(it);
7011 3156992 : it->Next();
7012 : }
7013 :
7014 8694386 : if (has_access && it->state() == LookupIterator::INTERCEPTOR) {
7015 : Isolate* isolate = it->isolate();
7016 213 : Handle<InterceptorInfo> interceptor = it->GetInterceptor();
7017 213 : if (!interceptor->descriptor()->IsUndefined(isolate)) {
7018 : Handle<Object> result;
7019 : Handle<JSObject> holder = it->GetHolder<JSObject>();
7020 :
7021 : Handle<Object> receiver = it->GetReceiver();
7022 45 : if (!receiver->IsJSReceiver()) {
7023 14 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7024 : isolate, receiver, Object::ConvertReceiver(isolate, receiver),
7025 : Nothing<bool>());
7026 : }
7027 :
7028 : PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
7029 : *holder, Object::DONT_THROW);
7030 45 : if (it->IsElement()) {
7031 : uint32_t index = it->index();
7032 : v8::IndexedPropertyDescriptorCallback descriptorCallback =
7033 : v8::ToCData<v8::IndexedPropertyDescriptorCallback>(
7034 : interceptor->descriptor());
7035 :
7036 12 : result = args.Call(descriptorCallback, index);
7037 : } else {
7038 33 : Handle<Name> name = it->name();
7039 : DCHECK(!name->IsPrivate());
7040 : v8::GenericNamedPropertyDescriptorCallback descriptorCallback =
7041 : v8::ToCData<v8::GenericNamedPropertyDescriptorCallback>(
7042 : interceptor->descriptor());
7043 33 : result = args.Call(descriptorCallback, name);
7044 : }
7045 45 : if (!result.is_null()) {
7046 : // Request successfully intercepted, try to set the property
7047 : // descriptor.
7048 : Utils::ApiCheck(
7049 14 : PropertyDescriptor::ToPropertyDescriptor(isolate, result, desc),
7050 : it->IsElement() ? "v8::IndexedPropertyDescriptorCallback"
7051 : : "v8::NamedPropertyDescriptorCallback",
7052 14 : "Invalid property descriptor.");
7053 :
7054 : return Just(true);
7055 : }
7056 : }
7057 : }
7058 4347206 : it->Restart();
7059 : return Just(false);
7060 : }
7061 : } // namespace
7062 :
7063 : // ES6 9.1.5.1
7064 : // Returns true on success, false if the property didn't exist, nothing if
7065 : // an exception was thrown.
7066 : // static
7067 8089344 : Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it,
7068 : PropertyDescriptor* desc) {
7069 : Isolate* isolate = it->isolate();
7070 : // "Virtual" dispatch.
7071 8098960 : if (it->IsFound() && it->GetHolder<JSReceiver>()->IsJSProxy()) {
7072 : return JSProxy::GetOwnPropertyDescriptor(isolate, it->GetHolder<JSProxy>(),
7073 9040 : it->GetName(), desc);
7074 : }
7075 :
7076 4347220 : Maybe<bool> intercepted = GetPropertyDescriptorWithInterceptor(it, desc);
7077 4347220 : MAYBE_RETURN(intercepted, Nothing<bool>());
7078 4347220 : if (intercepted.FromJust()) {
7079 : return Just(true);
7080 : }
7081 :
7082 : // Request was not intercepted, continue as normal.
7083 : // 1. (Assert)
7084 : // 2. If O does not have an own property with key P, return undefined.
7085 4347206 : Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(it);
7086 4347206 : MAYBE_RETURN(maybe, Nothing<bool>());
7087 : PropertyAttributes attrs = maybe.FromJust();
7088 4347152 : if (attrs == ABSENT) return Just(false);
7089 : DCHECK(!isolate->has_pending_exception());
7090 :
7091 : // 3. Let D be a newly created Property Descriptor with no fields.
7092 : DCHECK(desc->is_empty());
7093 : // 4. Let X be O's own property whose key is P.
7094 : // 5. If X is a data property, then
7095 3901307 : bool is_accessor_pair = it->state() == LookupIterator::ACCESSOR &&
7096 3901307 : it->GetAccessors()->IsAccessorPair();
7097 3733084 : if (!is_accessor_pair) {
7098 : // 5a. Set D.[[Value]] to the value of X's [[Value]] attribute.
7099 : Handle<Object> value;
7100 7394938 : if (!Object::GetProperty(it).ToHandle(&value)) {
7101 : DCHECK(isolate->has_pending_exception());
7102 : return Nothing<bool>();
7103 : }
7104 : desc->set_value(value);
7105 : // 5b. Set D.[[Writable]] to the value of X's [[Writable]] attribute
7106 3697469 : desc->set_writable((attrs & READ_ONLY) == 0);
7107 : } else {
7108 : // 6. Else X is an accessor property, so
7109 : Handle<AccessorPair> accessors =
7110 35615 : Handle<AccessorPair>::cast(it->GetAccessors());
7111 : // 6a. Set D.[[Get]] to the value of X's [[Get]] attribute.
7112 35615 : desc->set_get(AccessorPair::GetComponent(accessors, ACCESSOR_GETTER));
7113 : // 6b. Set D.[[Set]] to the value of X's [[Set]] attribute.
7114 35615 : desc->set_set(AccessorPair::GetComponent(accessors, ACCESSOR_SETTER));
7115 : }
7116 :
7117 : // 7. Set D.[[Enumerable]] to the value of X's [[Enumerable]] attribute.
7118 3733084 : desc->set_enumerable((attrs & DONT_ENUM) == 0);
7119 : // 8. Set D.[[Configurable]] to the value of X's [[Configurable]] attribute.
7120 3733084 : desc->set_configurable((attrs & DONT_DELETE) == 0);
7121 : // 9. Return D.
7122 : DCHECK(PropertyDescriptor::IsAccessorDescriptor(desc) !=
7123 : PropertyDescriptor::IsDataDescriptor(desc));
7124 : return Just(true);
7125 : }
7126 :
7127 :
7128 : // ES6 9.5.5
7129 : // static
7130 13932 : Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate,
7131 : Handle<JSProxy> proxy,
7132 : Handle<Name> name,
7133 : PropertyDescriptor* desc) {
7134 : DCHECK(!name->IsPrivate());
7135 13932 : STACK_CHECK(isolate, Nothing<bool>());
7136 :
7137 : Handle<String> trap_name =
7138 : isolate->factory()->getOwnPropertyDescriptor_string();
7139 : // 1. (Assert)
7140 : // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
7141 : Handle<Object> handler(proxy->handler(), isolate);
7142 : // 3. If handler is null, throw a TypeError exception.
7143 : // 4. Assert: Type(handler) is Object.
7144 13932 : if (proxy->IsRevoked()) {
7145 : isolate->Throw(*isolate->factory()->NewTypeError(
7146 56 : MessageTemplate::kProxyRevoked, trap_name));
7147 : return Nothing<bool>();
7148 : }
7149 : // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
7150 : Handle<JSReceiver> target(proxy->target(), isolate);
7151 : // 6. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor").
7152 : Handle<Object> trap;
7153 27808 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7154 : isolate, trap,
7155 : Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
7156 : Nothing<bool>());
7157 : // 7. If trap is undefined, then
7158 13820 : if (trap->IsUndefined(isolate)) {
7159 : // 7a. Return target.[[GetOwnProperty]](P).
7160 4983 : return JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, desc);
7161 : }
7162 : // 8. Let trapResultObj be ? Call(trap, handler, «target, P»).
7163 : Handle<Object> trap_result_obj;
7164 : Handle<Object> args[] = {target, name};
7165 17674 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7166 : isolate, trap_result_obj,
7167 : Execution::Call(isolate, trap, handler, arraysize(args), args),
7168 : Nothing<bool>());
7169 : // 9. If Type(trapResultObj) is neither Object nor Undefined, throw a
7170 : // TypeError exception.
7171 8694 : if (!trap_result_obj->IsJSReceiver() &&
7172 : !trap_result_obj->IsUndefined(isolate)) {
7173 : isolate->Throw(*isolate->factory()->NewTypeError(
7174 56 : MessageTemplate::kProxyGetOwnPropertyDescriptorInvalid, name));
7175 : return Nothing<bool>();
7176 : }
7177 : // 10. Let targetDesc be ? target.[[GetOwnProperty]](P).
7178 : PropertyDescriptor target_desc;
7179 : Maybe<bool> found =
7180 7406 : JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
7181 7406 : MAYBE_RETURN(found, Nothing<bool>());
7182 : // 11. If trapResultObj is undefined, then
7183 7406 : if (trap_result_obj->IsUndefined(isolate)) {
7184 : // 11a. If targetDesc is undefined, return undefined.
7185 1232 : if (!found.FromJust()) return Just(false);
7186 : // 11b. If targetDesc.[[Configurable]] is false, throw a TypeError
7187 : // exception.
7188 70 : if (!target_desc.configurable()) {
7189 : isolate->Throw(*isolate->factory()->NewTypeError(
7190 84 : MessageTemplate::kProxyGetOwnPropertyDescriptorUndefined, name));
7191 : return Nothing<bool>();
7192 : }
7193 : // 11c. Let extensibleTarget be ? IsExtensible(target).
7194 28 : Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
7195 28 : MAYBE_RETURN(extensible_target, Nothing<bool>());
7196 : // 11d. (Assert)
7197 : // 11e. If extensibleTarget is false, throw a TypeError exception.
7198 28 : if (!extensible_target.FromJust()) {
7199 : isolate->Throw(*isolate->factory()->NewTypeError(
7200 0 : MessageTemplate::kProxyGetOwnPropertyDescriptorNonExtensible, name));
7201 : return Nothing<bool>();
7202 : }
7203 : // 11f. Return undefined.
7204 : return Just(false);
7205 : }
7206 : // 12. Let extensibleTarget be ? IsExtensible(target).
7207 6174 : Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
7208 6174 : MAYBE_RETURN(extensible_target, Nothing<bool>());
7209 : // 13. Let resultDesc be ? ToPropertyDescriptor(trapResultObj).
7210 6174 : if (!PropertyDescriptor::ToPropertyDescriptor(isolate, trap_result_obj,
7211 6174 : desc)) {
7212 : DCHECK(isolate->has_pending_exception());
7213 : return Nothing<bool>();
7214 : }
7215 : // 14. Call CompletePropertyDescriptor(resultDesc).
7216 6062 : PropertyDescriptor::CompletePropertyDescriptor(isolate, desc);
7217 : // 15. Let valid be IsCompatiblePropertyDescriptor (extensibleTarget,
7218 : // resultDesc, targetDesc).
7219 : Maybe<bool> valid =
7220 : IsCompatiblePropertyDescriptor(isolate, extensible_target.FromJust(),
7221 : desc, &target_desc, name, DONT_THROW);
7222 6062 : MAYBE_RETURN(valid, Nothing<bool>());
7223 : // 16. If valid is false, throw a TypeError exception.
7224 6062 : if (!valid.FromJust()) {
7225 : isolate->Throw(*isolate->factory()->NewTypeError(
7226 56 : MessageTemplate::kProxyGetOwnPropertyDescriptorIncompatible, name));
7227 : return Nothing<bool>();
7228 : }
7229 : // 17. If resultDesc.[[Configurable]] is false, then
7230 6034 : if (!desc->configurable()) {
7231 : // 17a. If targetDesc is undefined or targetDesc.[[Configurable]] is true:
7232 742 : if (target_desc.is_empty() || target_desc.configurable()) {
7233 : // 17a i. Throw a TypeError exception.
7234 : isolate->Throw(*isolate->factory()->NewTypeError(
7235 : MessageTemplate::kProxyGetOwnPropertyDescriptorNonConfigurable,
7236 56 : name));
7237 : return Nothing<bool>();
7238 : }
7239 : }
7240 : // 18. Return resultDesc.
7241 : return Just(true);
7242 : }
7243 :
7244 :
7245 0 : bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
7246 : ElementsKind kind,
7247 : Object* object) {
7248 : Isolate* isolate = elements->GetIsolate();
7249 0 : if (IsFastObjectElementsKind(kind) || kind == FAST_STRING_WRAPPER_ELEMENTS) {
7250 : int length = IsJSArray()
7251 : ? Smi::cast(JSArray::cast(this)->length())->value()
7252 0 : : elements->length();
7253 0 : for (int i = 0; i < length; ++i) {
7254 : Object* element = elements->get(i);
7255 0 : if (!element->IsTheHole(isolate) && element == object) return true;
7256 : }
7257 : } else {
7258 : DCHECK(kind == DICTIONARY_ELEMENTS || kind == SLOW_STRING_WRAPPER_ELEMENTS);
7259 : Object* key =
7260 0 : SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
7261 0 : if (!key->IsUndefined(isolate)) return true;
7262 : }
7263 : return false;
7264 : }
7265 :
7266 :
7267 : // Check whether this object references another object.
7268 0 : bool JSObject::ReferencesObject(Object* obj) {
7269 : Map* map_of_this = map();
7270 : Heap* heap = GetHeap();
7271 : DisallowHeapAllocation no_allocation;
7272 :
7273 : // Is the object the constructor for this object?
7274 0 : if (map_of_this->GetConstructor() == obj) {
7275 : return true;
7276 : }
7277 :
7278 : // Is the object the prototype for this object?
7279 0 : if (map_of_this->prototype() == obj) {
7280 : return true;
7281 : }
7282 :
7283 : // Check if the object is among the named properties.
7284 0 : Object* key = SlowReverseLookup(obj);
7285 0 : if (!key->IsUndefined(heap->isolate())) {
7286 : return true;
7287 : }
7288 :
7289 : // Check if the object is among the indexed properties.
7290 : ElementsKind kind = GetElementsKind();
7291 0 : switch (kind) {
7292 : // Raw pixels and external arrays do not reference other
7293 : // objects.
7294 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
7295 : case TYPE##_ELEMENTS: \
7296 : break;
7297 :
7298 : TYPED_ARRAYS(TYPED_ARRAY_CASE)
7299 : #undef TYPED_ARRAY_CASE
7300 :
7301 : case FAST_DOUBLE_ELEMENTS:
7302 : case FAST_HOLEY_DOUBLE_ELEMENTS:
7303 : break;
7304 : case FAST_SMI_ELEMENTS:
7305 : case FAST_HOLEY_SMI_ELEMENTS:
7306 : break;
7307 : case FAST_ELEMENTS:
7308 : case FAST_HOLEY_ELEMENTS:
7309 : case DICTIONARY_ELEMENTS:
7310 : case FAST_STRING_WRAPPER_ELEMENTS:
7311 : case SLOW_STRING_WRAPPER_ELEMENTS: {
7312 : FixedArray* elements = FixedArray::cast(this->elements());
7313 0 : if (ReferencesObjectFromElements(elements, kind, obj)) return true;
7314 : break;
7315 : }
7316 : case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
7317 : case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
7318 : SloppyArgumentsElements* elements =
7319 : SloppyArgumentsElements::cast(this->elements());
7320 : // Check the mapped parameters.
7321 0 : for (uint32_t i = 0; i < elements->parameter_map_length(); ++i) {
7322 : Object* value = elements->get_mapped_entry(i);
7323 0 : if (!value->IsTheHole(heap->isolate()) && value == obj) return true;
7324 : }
7325 : // Check the arguments.
7326 : FixedArray* arguments = elements->arguments();
7327 : kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS :
7328 0 : FAST_HOLEY_ELEMENTS;
7329 0 : if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
7330 : break;
7331 : }
7332 : case NO_ELEMENTS:
7333 : break;
7334 : }
7335 :
7336 : // For functions check the context.
7337 0 : if (IsJSFunction()) {
7338 : // Get the constructor function for arguments array.
7339 : Map* arguments_map =
7340 0 : heap->isolate()->context()->native_context()->sloppy_arguments_map();
7341 : JSFunction* arguments_function =
7342 0 : JSFunction::cast(arguments_map->GetConstructor());
7343 :
7344 : // Get the context and don't check if it is the native context.
7345 : JSFunction* f = JSFunction::cast(this);
7346 : Context* context = f->context();
7347 0 : if (context->IsNativeContext()) {
7348 : return false;
7349 : }
7350 :
7351 : // Check the non-special context slots.
7352 0 : for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
7353 : // Only check JS objects.
7354 0 : if (context->get(i)->IsJSObject()) {
7355 : JSObject* ctxobj = JSObject::cast(context->get(i));
7356 : // If it is an arguments array check the content.
7357 0 : if (ctxobj->map()->GetConstructor() == arguments_function) {
7358 0 : if (ctxobj->ReferencesObject(obj)) {
7359 : return true;
7360 : }
7361 0 : } else if (ctxobj == obj) {
7362 : return true;
7363 : }
7364 : }
7365 : }
7366 :
7367 : // Check the context extension (if any) if it can have references.
7368 0 : if (context->has_extension() && !context->IsCatchContext()) {
7369 : // With harmony scoping, a JSFunction may have a script context.
7370 : // TODO(mvstanton): walk into the ScopeInfo.
7371 0 : if (context->IsScriptContext()) {
7372 : return false;
7373 : }
7374 :
7375 0 : return context->extension_object()->ReferencesObject(obj);
7376 : }
7377 : }
7378 :
7379 : // No references to object.
7380 : return false;
7381 : }
7382 :
7383 :
7384 206214 : Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver,
7385 : IntegrityLevel level,
7386 : ShouldThrow should_throw) {
7387 : DCHECK(level == SEALED || level == FROZEN);
7388 :
7389 206214 : if (receiver->IsJSObject()) {
7390 : Handle<JSObject> object = Handle<JSObject>::cast(receiver);
7391 205570 : if (!object->HasSloppyArgumentsElements()) { // Fast path.
7392 205496 : if (level == SEALED) {
7393 : return JSObject::PreventExtensionsWithTransition<SEALED>(object,
7394 409 : should_throw);
7395 : } else {
7396 : return JSObject::PreventExtensionsWithTransition<FROZEN>(object,
7397 205087 : should_throw);
7398 : }
7399 : }
7400 : }
7401 :
7402 : Isolate* isolate = receiver->GetIsolate();
7403 :
7404 718 : MAYBE_RETURN(JSReceiver::PreventExtensions(receiver, should_throw),
7405 : Nothing<bool>());
7406 :
7407 : Handle<FixedArray> keys;
7408 718 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7409 : isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>());
7410 :
7411 : PropertyDescriptor no_conf;
7412 : no_conf.set_configurable(false);
7413 :
7414 : PropertyDescriptor no_conf_no_write;
7415 : no_conf_no_write.set_configurable(false);
7416 : no_conf_no_write.set_writable(false);
7417 :
7418 718 : if (level == SEALED) {
7419 406 : for (int i = 0; i < keys->length(); ++i) {
7420 : Handle<Object> key(keys->get(i), isolate);
7421 126 : MAYBE_RETURN(
7422 : DefineOwnProperty(isolate, receiver, key, &no_conf, THROW_ON_ERROR),
7423 : Nothing<bool>());
7424 : }
7425 : return Just(true);
7426 : }
7427 :
7428 4498 : for (int i = 0; i < keys->length(); ++i) {
7429 : Handle<Object> key(keys->get(i), isolate);
7430 : PropertyDescriptor current_desc;
7431 : Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
7432 1967 : isolate, receiver, key, ¤t_desc);
7433 1967 : MAYBE_RETURN(owned, Nothing<bool>());
7434 1967 : if (owned.FromJust()) {
7435 : PropertyDescriptor desc =
7436 : PropertyDescriptor::IsAccessorDescriptor(¤t_desc)
7437 : ? no_conf
7438 1967 : : no_conf_no_write;
7439 1967 : MAYBE_RETURN(
7440 : DefineOwnProperty(isolate, receiver, key, &desc, THROW_ON_ERROR),
7441 : Nothing<bool>());
7442 : }
7443 : }
7444 : return Just(true);
7445 : }
7446 :
7447 :
7448 7712 : Maybe<bool> JSReceiver::TestIntegrityLevel(Handle<JSReceiver> object,
7449 : IntegrityLevel level) {
7450 : DCHECK(level == SEALED || level == FROZEN);
7451 : Isolate* isolate = object->GetIsolate();
7452 :
7453 7712 : Maybe<bool> extensible = JSReceiver::IsExtensible(object);
7454 7712 : MAYBE_RETURN(extensible, Nothing<bool>());
7455 7712 : if (extensible.FromJust()) return Just(false);
7456 :
7457 : Handle<FixedArray> keys;
7458 1585 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7459 : isolate, keys, JSReceiver::OwnPropertyKeys(object), Nothing<bool>());
7460 :
7461 19213 : for (int i = 0; i < keys->length(); ++i) {
7462 : Handle<Object> key(keys->get(i), isolate);
7463 : PropertyDescriptor current_desc;
7464 : Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
7465 9314 : isolate, object, key, ¤t_desc);
7466 9814 : MAYBE_RETURN(owned, Nothing<bool>());
7467 9314 : if (owned.FromJust()) {
7468 9314 : if (current_desc.configurable()) return Just(false);
7469 14809 : if (level == FROZEN &&
7470 14699 : PropertyDescriptor::IsDataDescriptor(¤t_desc) &&
7471 : current_desc.writable()) {
7472 : return Just(false);
7473 : }
7474 : }
7475 : }
7476 : return Just(true);
7477 : }
7478 :
7479 :
7480 7126 : Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object,
7481 : ShouldThrow should_throw) {
7482 7126 : if (object->IsJSProxy()) {
7483 : return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object),
7484 952 : should_throw);
7485 : }
7486 : DCHECK(object->IsJSObject());
7487 : return JSObject::PreventExtensions(Handle<JSObject>::cast(object),
7488 6174 : should_throw);
7489 : }
7490 :
7491 :
7492 952 : Maybe<bool> JSProxy::PreventExtensions(Handle<JSProxy> proxy,
7493 : ShouldThrow should_throw) {
7494 : Isolate* isolate = proxy->GetIsolate();
7495 952 : STACK_CHECK(isolate, Nothing<bool>());
7496 : Factory* factory = isolate->factory();
7497 : Handle<String> trap_name = factory->preventExtensions_string();
7498 :
7499 952 : if (proxy->IsRevoked()) {
7500 : isolate->Throw(
7501 56 : *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
7502 : return Nothing<bool>();
7503 : }
7504 : Handle<JSReceiver> target(proxy->target(), isolate);
7505 : Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
7506 :
7507 : Handle<Object> trap;
7508 1848 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7509 : isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
7510 896 : if (trap->IsUndefined(isolate)) {
7511 812 : return JSReceiver::PreventExtensions(target, should_throw);
7512 : }
7513 :
7514 : Handle<Object> trap_result;
7515 : Handle<Object> args[] = {target};
7516 168 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7517 : isolate, trap_result,
7518 : Execution::Call(isolate, trap, handler, arraysize(args), args),
7519 : Nothing<bool>());
7520 84 : if (!trap_result->BooleanValue()) {
7521 28 : RETURN_FAILURE(
7522 : isolate, should_throw,
7523 : NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
7524 : }
7525 :
7526 : // Enforce the invariant.
7527 56 : Maybe<bool> target_result = JSReceiver::IsExtensible(target);
7528 56 : MAYBE_RETURN(target_result, Nothing<bool>());
7529 56 : if (target_result.FromJust()) {
7530 : isolate->Throw(*factory->NewTypeError(
7531 28 : MessageTemplate::kProxyPreventExtensionsExtensible));
7532 : return Nothing<bool>();
7533 : }
7534 : return Just(true);
7535 : }
7536 :
7537 :
7538 6632 : Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object,
7539 : ShouldThrow should_throw) {
7540 0 : Isolate* isolate = object->GetIsolate();
7541 :
7542 6632 : if (!object->HasSloppyArgumentsElements()) {
7543 6543 : return PreventExtensionsWithTransition<NONE>(object, should_throw);
7544 : }
7545 :
7546 89 : if (object->IsAccessCheckNeeded() &&
7547 0 : !isolate->MayAccess(handle(isolate->context()), object)) {
7548 0 : isolate->ReportFailedAccessCheck(object);
7549 0 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
7550 0 : RETURN_FAILURE(isolate, should_throw,
7551 : NewTypeError(MessageTemplate::kNoAccess));
7552 : }
7553 :
7554 89 : if (!object->map()->is_extensible()) return Just(true);
7555 :
7556 89 : if (object->IsJSGlobalProxy()) {
7557 0 : PrototypeIterator iter(isolate, object);
7558 0 : if (iter.IsAtEnd()) return Just(true);
7559 : DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
7560 : return PreventExtensions(PrototypeIterator::GetCurrent<JSObject>(iter),
7561 0 : should_throw);
7562 : }
7563 :
7564 178 : if (object->map()->has_named_interceptor() ||
7565 : object->map()->has_indexed_interceptor()) {
7566 0 : RETURN_FAILURE(isolate, should_throw,
7567 : NewTypeError(MessageTemplate::kCannotPreventExt));
7568 : }
7569 :
7570 89 : if (!object->HasFixedTypedArrayElements()) {
7571 : // If there are fast elements we normalize.
7572 89 : Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
7573 : DCHECK(object->HasDictionaryElements() ||
7574 : object->HasSlowArgumentsElements());
7575 :
7576 : // Make sure that we never go back to fast case.
7577 89 : object->RequireSlowElements(*dictionary);
7578 : }
7579 :
7580 : // Do a map transition, other objects with this map may still
7581 : // be extensible.
7582 : // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
7583 89 : Handle<Map> new_map = Map::Copy(handle(object->map()), "PreventExtensions");
7584 :
7585 : new_map->set_is_extensible(false);
7586 89 : JSObject::MigrateToMap(object, new_map);
7587 : DCHECK(!object->map()->is_extensible());
7588 :
7589 : return Just(true);
7590 : }
7591 :
7592 :
7593 1520952 : Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) {
7594 1520952 : if (object->IsJSProxy()) {
7595 910 : return JSProxy::IsExtensible(Handle<JSProxy>::cast(object));
7596 : }
7597 1520042 : return Just(JSObject::IsExtensible(Handle<JSObject>::cast(object)));
7598 : }
7599 :
7600 :
7601 910 : Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) {
7602 : Isolate* isolate = proxy->GetIsolate();
7603 910 : STACK_CHECK(isolate, Nothing<bool>());
7604 : Factory* factory = isolate->factory();
7605 : Handle<String> trap_name = factory->isExtensible_string();
7606 :
7607 910 : if (proxy->IsRevoked()) {
7608 : isolate->Throw(
7609 56 : *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
7610 : return Nothing<bool>();
7611 : }
7612 : Handle<JSReceiver> target(proxy->target(), isolate);
7613 : Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
7614 :
7615 : Handle<Object> trap;
7616 1764 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7617 : isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
7618 854 : if (trap->IsUndefined(isolate)) {
7619 196 : return JSReceiver::IsExtensible(target);
7620 : }
7621 :
7622 : Handle<Object> trap_result;
7623 : Handle<Object> args[] = {target};
7624 1316 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7625 : isolate, trap_result,
7626 : Execution::Call(isolate, trap, handler, arraysize(args), args),
7627 : Nothing<bool>());
7628 :
7629 : // Enforce the invariant.
7630 658 : Maybe<bool> target_result = JSReceiver::IsExtensible(target);
7631 658 : MAYBE_RETURN(target_result, Nothing<bool>());
7632 658 : if (target_result.FromJust() != trap_result->BooleanValue()) {
7633 : isolate->Throw(
7634 : *factory->NewTypeError(MessageTemplate::kProxyIsExtensibleInconsistent,
7635 84 : factory->ToBoolean(target_result.FromJust())));
7636 : return Nothing<bool>();
7637 : }
7638 616 : return target_result;
7639 : }
7640 :
7641 :
7642 2355058 : bool JSObject::IsExtensible(Handle<JSObject> object) {
7643 36 : Isolate* isolate = object->GetIsolate();
7644 2355094 : if (object->IsAccessCheckNeeded() &&
7645 36 : !isolate->MayAccess(handle(isolate->context()), object)) {
7646 : return true;
7647 : }
7648 2355034 : if (object->IsJSGlobalProxy()) {
7649 : PrototypeIterator iter(isolate, *object);
7650 3969 : if (iter.IsAtEnd()) return false;
7651 : DCHECK(iter.GetCurrent()->IsJSGlobalObject());
7652 7938 : return iter.GetCurrent<JSObject>()->map()->is_extensible();
7653 : }
7654 2351065 : return object->map()->is_extensible();
7655 : }
7656 :
7657 : namespace {
7658 :
7659 : template <typename Dictionary>
7660 : void DictionaryDetailsAtPut(Isolate* isolate, Handle<Dictionary> dictionary,
7661 : int entry, PropertyDetails details) {
7662 : dictionary->DetailsAtPut(entry, details);
7663 : }
7664 :
7665 : template <>
7666 13229 : void DictionaryDetailsAtPut<GlobalDictionary>(
7667 : Isolate* isolate, Handle<GlobalDictionary> dictionary, int entry,
7668 : PropertyDetails details) {
7669 13229 : Object* value = dictionary->ValueAt(entry);
7670 : DCHECK(value->IsPropertyCell());
7671 : value = PropertyCell::cast(value)->value();
7672 26458 : if (value->IsTheHole(isolate)) return;
7673 : PropertyCell::PrepareForValue(dictionary, entry, handle(value, isolate),
7674 13214 : details);
7675 : }
7676 :
7677 : template <typename Dictionary>
7678 5991 : void ApplyAttributesToDictionary(Isolate* isolate,
7679 : Handle<Dictionary> dictionary,
7680 : const PropertyAttributes attributes) {
7681 : int capacity = dictionary->Capacity();
7682 70583 : for (int i = 0; i < capacity; i++) {
7683 : Object* k = dictionary->KeyAt(i);
7684 90851 : if (dictionary->IsKey(isolate, k) &&
7685 : !(k->IsSymbol() && Symbol::cast(k)->is_private())) {
7686 : PropertyDetails details = dictionary->DetailsAt(i);
7687 26125 : int attrs = attributes;
7688 : // READ_ONLY is an invalid attribute for JS setters/getters.
7689 49718 : if ((attributes & READ_ONLY) && details.kind() == kAccessor) {
7690 44 : Object* v = dictionary->ValueAt(i);
7691 44 : if (v->IsPropertyCell()) v = PropertyCell::cast(v)->value();
7692 44 : if (v->IsAccessorPair()) attrs &= ~READ_ONLY;
7693 : }
7694 : details = details.CopyAddAttributes(
7695 : static_cast<PropertyAttributes>(attrs));
7696 13229 : DictionaryDetailsAtPut<Dictionary>(isolate, dictionary, i, details);
7697 : }
7698 : }
7699 5991 : }
7700 :
7701 : } // namespace
7702 :
7703 : template <PropertyAttributes attrs>
7704 212187 : Maybe<bool> JSObject::PreventExtensionsWithTransition(
7705 : Handle<JSObject> object, ShouldThrow should_throw) {
7706 : STATIC_ASSERT(attrs == NONE || attrs == SEALED || attrs == FROZEN);
7707 :
7708 : // Sealing/freezing sloppy arguments should be handled elsewhere.
7709 : DCHECK(!object->HasSloppyArgumentsElements());
7710 :
7711 30 : Isolate* isolate = object->GetIsolate();
7712 212217 : if (object->IsAccessCheckNeeded() &&
7713 30 : !isolate->MayAccess(handle(isolate->context()), object)) {
7714 24 : isolate->ReportFailedAccessCheck(object);
7715 24 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
7716 0 : RETURN_FAILURE(isolate, should_throw,
7717 : NewTypeError(MessageTemplate::kNoAccess));
7718 : }
7719 :
7720 6545 : if (attrs == NONE && !object->map()->is_extensible()) return Just(true);
7721 :
7722 212148 : if (object->IsJSGlobalProxy()) {
7723 148 : PrototypeIterator iter(isolate, object);
7724 148 : if (iter.IsAtEnd()) return Just(true);
7725 : DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
7726 : return PreventExtensionsWithTransition<attrs>(
7727 148 : PrototypeIterator::GetCurrent<JSObject>(iter), should_throw);
7728 : }
7729 :
7730 423999 : if (object->map()->has_named_interceptor() ||
7731 : object->map()->has_indexed_interceptor()) {
7732 : MessageTemplate::Template message = MessageTemplate::kNone;
7733 : switch (attrs) {
7734 : case NONE:
7735 : message = MessageTemplate::kCannotPreventExt;
7736 : break;
7737 :
7738 : case SEALED:
7739 : message = MessageTemplate::kCannotSeal;
7740 : break;
7741 :
7742 : case FROZEN:
7743 : message = MessageTemplate::kCannotFreeze;
7744 : break;
7745 : }
7746 3 : RETURN_FAILURE(isolate, should_throw, NewTypeError(message));
7747 : }
7748 :
7749 : Handle<SeededNumberDictionary> new_element_dictionary;
7750 635500 : if (!object->HasFixedTypedArrayElements() &&
7751 211910 : !object->HasDictionaryElements() &&
7752 211591 : !object->HasSlowStringWrapperElements()) {
7753 : int length =
7754 : object->IsJSArray()
7755 : ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
7756 211591 : : object->elements()->length();
7757 217870 : new_element_dictionary =
7758 : length == 0 ? isolate->factory()->empty_slow_element_dictionary()
7759 6279 : : object->GetElementsAccessor()->Normalize(object);
7760 : }
7761 :
7762 : Handle<Symbol> transition_marker;
7763 : if (attrs == NONE) {
7764 : transition_marker = isolate->factory()->nonextensible_symbol();
7765 : } else if (attrs == SEALED) {
7766 : transition_marker = isolate->factory()->sealed_symbol();
7767 : } else {
7768 : DCHECK(attrs == FROZEN);
7769 : transition_marker = isolate->factory()->frozen_symbol();
7770 : }
7771 :
7772 : Handle<Map> old_map(object->map(), isolate);
7773 : Map* transition =
7774 211999 : TransitionArray::SearchSpecial(*old_map, *transition_marker);
7775 211999 : if (transition != NULL) {
7776 : Handle<Map> transition_map(transition, isolate);
7777 : DCHECK(transition_map->has_dictionary_elements() ||
7778 : transition_map->has_fixed_typed_array_elements() ||
7779 : transition_map->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
7780 : DCHECK(!transition_map->is_extensible());
7781 159859 : JSObject::MigrateToMap(object, transition_map);
7782 52140 : } else if (TransitionArray::CanHaveMoreTransitions(old_map)) {
7783 : // Create a new descriptor array with the appropriate property attributes
7784 : Handle<Map> new_map = Map::CopyForPreventExtensions(
7785 51203 : old_map, attrs, transition_marker, "CopyForPreventExtensions");
7786 51203 : JSObject::MigrateToMap(object, new_map);
7787 : } else {
7788 : DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map());
7789 : // Slow path: need to normalize properties for safety
7790 937 : NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0,
7791 : "SlowPreventExtensions");
7792 :
7793 : // Create a new map, since other objects with this map may be extensible.
7794 : // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
7795 : Handle<Map> new_map =
7796 937 : Map::Copy(handle(object->map()), "SlowCopyForPreventExtensions");
7797 : new_map->set_is_extensible(false);
7798 937 : if (!new_element_dictionary.is_null()) {
7799 : ElementsKind new_kind =
7800 : IsStringWrapperElementsKind(old_map->elements_kind())
7801 : ? SLOW_STRING_WRAPPER_ELEMENTS
7802 937 : : DICTIONARY_ELEMENTS;
7803 : new_map->set_elements_kind(new_kind);
7804 : }
7805 937 : JSObject::MigrateToMap(object, new_map);
7806 :
7807 : if (attrs != NONE) {
7808 213 : if (object->IsJSGlobalObject()) {
7809 : Handle<GlobalDictionary> dictionary(object->global_dictionary(),
7810 : isolate);
7811 134 : ApplyAttributesToDictionary(isolate, dictionary, attrs);
7812 : } else {
7813 : Handle<NameDictionary> dictionary(object->property_dictionary(),
7814 : isolate);
7815 79 : ApplyAttributesToDictionary(isolate, dictionary, attrs);
7816 : }
7817 : }
7818 : }
7819 :
7820 : // Both seal and preventExtensions always go through without modifications to
7821 : // typed array elements. Freeze works only if there are no actual elements.
7822 211999 : if (object->HasFixedTypedArrayElements()) {
7823 59 : if (attrs == FROZEN &&
7824 : JSArrayBufferView::cast(*object)->byte_length()->Number() > 0) {
7825 44 : isolate->Throw(*isolate->factory()->NewTypeError(
7826 88 : MessageTemplate::kCannotFreezeArrayBufferView));
7827 : return Nothing<bool>();
7828 : }
7829 : return Just(true);
7830 : }
7831 :
7832 : DCHECK(object->map()->has_dictionary_elements() ||
7833 : object->map()->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
7834 211910 : if (!new_element_dictionary.is_null()) {
7835 211591 : object->set_elements(*new_element_dictionary);
7836 : }
7837 :
7838 211910 : if (object->elements() != isolate->heap()->empty_slow_element_dictionary()) {
7839 : Handle<SeededNumberDictionary> dictionary(object->element_dictionary(),
7840 : isolate);
7841 : // Make sure we never go back to the fast case
7842 6510 : object->RequireSlowElements(*dictionary);
7843 : if (attrs != NONE) {
7844 5778 : ApplyAttributesToDictionary(isolate, dictionary, attrs);
7845 : }
7846 : }
7847 :
7848 : return Just(true);
7849 : }
7850 :
7851 :
7852 58226998 : Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object,
7853 : Representation representation,
7854 : FieldIndex index) {
7855 : Isolate* isolate = object->GetIsolate();
7856 58226998 : if (object->IsUnboxedDoubleField(index)) {
7857 : double value = object->RawFastDoublePropertyAt(index);
7858 78602 : return isolate->factory()->NewHeapNumber(value);
7859 : }
7860 58148396 : Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate);
7861 58148397 : return Object::WrapForRead(isolate, raw_value, representation);
7862 : }
7863 :
7864 : template <class ContextObject>
7865 : class JSObjectWalkVisitor {
7866 : public:
7867 : JSObjectWalkVisitor(ContextObject* site_context, bool copying,
7868 : JSObject::DeepCopyHints hints)
7869 : : site_context_(site_context),
7870 : copying_(copying),
7871 8266444 : hints_(hints) {}
7872 :
7873 : MUST_USE_RESULT MaybeHandle<JSObject> StructureWalk(Handle<JSObject> object);
7874 :
7875 : protected:
7876 1900263 : MUST_USE_RESULT inline MaybeHandle<JSObject> VisitElementOrProperty(
7877 : Handle<JSObject> object,
7878 2205317 : Handle<JSObject> value) {
7879 1900263 : Handle<AllocationSite> current_site = site_context()->EnterNewScope();
7880 1900263 : MaybeHandle<JSObject> copy_of_value = StructureWalk(value);
7881 305054 : site_context()->ExitScope(current_site, value);
7882 1900263 : return copy_of_value;
7883 : }
7884 :
7885 : inline ContextObject* site_context() { return site_context_; }
7886 10166706 : inline Isolate* isolate() { return site_context()->isolate(); }
7887 :
7888 : inline bool copying() const { return copying_; }
7889 :
7890 : private:
7891 : ContextObject* site_context_;
7892 : const bool copying_;
7893 : const JSObject::DeepCopyHints hints_;
7894 : };
7895 :
7896 : template <class ContextObject>
7897 10166706 : MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
7898 26230673 : Handle<JSObject> object) {
7899 641994 : Isolate* isolate = this->isolate();
7900 : bool copying = this->copying();
7901 10166706 : bool shallow = hints_ == JSObject::kObjectIsShallow;
7902 :
7903 10166706 : if (!shallow) {
7904 : StackLimitCheck check(isolate);
7905 :
7906 8816476 : if (check.HasOverflowed()) {
7907 165 : isolate->StackOverflow();
7908 : return MaybeHandle<JSObject>();
7909 : }
7910 : }
7911 :
7912 10166541 : if (object->map()->is_deprecated()) {
7913 2317 : JSObject::MigrateInstance(object);
7914 : }
7915 :
7916 : Handle<JSObject> copy;
7917 10166543 : if (copying) {
7918 : // JSFunction objects are not allowed to be in normal boilerplates at all.
7919 : DCHECK(!object->IsJSFunction());
7920 : Handle<AllocationSite> site_to_pass;
7921 8940784 : if (site_context()->ShouldCreateMemento(object)) {
7922 7123183 : site_to_pass = site_context()->current();
7923 : }
7924 8940785 : copy = isolate->factory()->CopyJSObjectWithAllocationSite(
7925 : object, site_to_pass);
7926 : } else {
7927 : copy = object;
7928 : }
7929 :
7930 : DCHECK(copying || copy.is_identical_to(object));
7931 :
7932 : ElementsKind kind = copy->GetElementsKind();
7933 18796869 : if (copying && IsFastSmiOrObjectElementsKind(kind) &&
7934 : FixedArray::cast(copy->elements())->map() ==
7935 8630330 : isolate->heap()->fixed_cow_array_map()) {
7936 641994 : isolate->counters()->cow_arrays_created_runtime()->Increment();
7937 : }
7938 :
7939 10166539 : if (!shallow) {
7940 : HandleScope scope(isolate);
7941 :
7942 : // Deep copy own properties.
7943 8816307 : if (copy->HasFastProperties()) {
7944 : Handle<DescriptorArray> descriptors(copy->map()->instance_descriptors());
7945 : int limit = copy->map()->NumberOfOwnDescriptors();
7946 29997254 : for (int i = 0; i < limit; i++) {
7947 21181137 : PropertyDetails details = descriptors->GetDetails(i);
7948 23151788 : if (details.location() != kField) continue;
7949 : DCHECK_EQ(kData, details.kind());
7950 19210488 : FieldIndex index = FieldIndex::ForDescriptor(copy->map(), i);
7951 19210483 : if (object->IsUnboxedDoubleField(index)) {
7952 161042 : if (copying) {
7953 : // Ensure that all bits of the double value are preserved.
7954 : uint64_t value = object->RawFastDoublePropertyAsBitsAt(index);
7955 : copy->RawFastDoublePropertyAsBitsAtPut(index, value);
7956 : }
7957 : } else {
7958 19049441 : Handle<Object> value(object->RawFastPropertyAt(index), isolate);
7959 19049449 : if (value->IsJSObject()) {
7960 1698378 : ASSIGN_RETURN_ON_EXCEPTION(
7961 : isolate, value,
7962 : VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
7963 : JSObject);
7964 849174 : if (copying) {
7965 646404 : copy->FastPropertyAtPut(index, *value);
7966 : }
7967 : } else {
7968 18200260 : if (copying) {
7969 15778022 : Representation representation = details.representation();
7970 15778022 : value = Object::NewStorageFor(isolate, value, representation);
7971 15778022 : copy->FastPropertyAtPut(index, *value);
7972 : }
7973 : }
7974 : }
7975 : }
7976 : } else {
7977 : // Only deep copy fields from the object literal expression.
7978 : // In particular, don't try to copy the length attribute of
7979 : // an array.
7980 : PropertyFilter filter = static_cast<PropertyFilter>(
7981 : ONLY_WRITABLE | ONLY_ENUMERABLE | ONLY_CONFIGURABLE);
7982 : KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly, filter);
7983 182 : accumulator.CollectOwnPropertyNames(copy, copy);
7984 182 : Handle<FixedArray> names = accumulator.GetKeys();
7985 593688 : for (int i = 0; i < names->length(); i++) {
7986 : DCHECK(names->get(i)->IsName());
7987 : Handle<Name> name(Name::cast(names->get(i)));
7988 : Handle<Object> value =
7989 593324 : JSObject::GetProperty(copy, name).ToHandleChecked();
7990 296662 : if (value->IsJSObject()) {
7991 : Handle<JSObject> result;
7992 0 : ASSIGN_RETURN_ON_EXCEPTION(
7993 : isolate, result,
7994 : VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
7995 : JSObject);
7996 0 : if (copying) {
7997 : // Creating object copy for literals. No strict mode needed.
7998 0 : JSObject::SetProperty(copy, name, result, SLOPPY).Assert();
7999 : }
8000 : }
8001 182 : }
8002 : }
8003 :
8004 : // Deep copy own elements.
8005 8816299 : switch (kind) {
8006 : case FAST_ELEMENTS:
8007 : case FAST_HOLEY_ELEMENTS: {
8008 : Handle<FixedArray> elements(FixedArray::cast(copy->elements()));
8009 7735331 : if (elements->map() == isolate->heap()->fixed_cow_array_map()) {
8010 : #ifdef DEBUG
8011 : for (int i = 0; i < elements->length(); i++) {
8012 : DCHECK(!elements->get(i)->IsJSObject());
8013 : }
8014 : #endif
8015 : } else {
8016 14179808 : for (int i = 0; i < elements->length(); i++) {
8017 : Handle<Object> value(elements->get(i), isolate);
8018 3268967 : if (value->IsJSObject()) {
8019 : Handle<JSObject> result;
8020 2101408 : ASSIGN_RETURN_ON_EXCEPTION(
8021 : isolate, result,
8022 : VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
8023 : JSObject);
8024 1050674 : if (copying) {
8025 948560 : elements->set(i, *result);
8026 : }
8027 : }
8028 : }
8029 : }
8030 : break;
8031 : }
8032 : case DICTIONARY_ELEMENTS: {
8033 : Handle<SeededNumberDictionary> element_dictionary(
8034 : copy->element_dictionary());
8035 : int capacity = element_dictionary->Capacity();
8036 28179 : for (int i = 0; i < capacity; i++) {
8037 : Object* k = element_dictionary->KeyAt(i);
8038 26276 : if (element_dictionary->IsKey(isolate, k)) {
8039 9826 : Handle<Object> value(element_dictionary->ValueAt(i), isolate);
8040 9826 : if (value->IsJSObject()) {
8041 : Handle<JSObject> result;
8042 740 : ASSIGN_RETURN_ON_EXCEPTION(
8043 : isolate, result,
8044 : VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
8045 : JSObject);
8046 370 : if (copying) {
8047 : element_dictionary->ValueAtPut(i, *result);
8048 : }
8049 : }
8050 : }
8051 : }
8052 : break;
8053 : }
8054 : case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
8055 : case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
8056 0 : UNIMPLEMENTED();
8057 : break;
8058 : case FAST_STRING_WRAPPER_ELEMENTS:
8059 : case SLOW_STRING_WRAPPER_ELEMENTS:
8060 0 : UNREACHABLE();
8061 : break;
8062 :
8063 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
8064 : case TYPE##_ELEMENTS: \
8065 :
8066 : TYPED_ARRAYS(TYPED_ARRAY_CASE)
8067 : #undef TYPED_ARRAY_CASE
8068 : // Typed elements cannot be created using an object literal.
8069 0 : UNREACHABLE();
8070 : break;
8071 :
8072 : case FAST_SMI_ELEMENTS:
8073 : case FAST_HOLEY_SMI_ELEMENTS:
8074 : case FAST_DOUBLE_ELEMENTS:
8075 : case FAST_HOLEY_DOUBLE_ELEMENTS:
8076 : case NO_ELEMENTS:
8077 : // No contained objects, nothing to do.
8078 : break;
8079 : }
8080 : }
8081 :
8082 : return copy;
8083 : }
8084 :
8085 :
8086 920835 : MaybeHandle<JSObject> JSObject::DeepWalk(
8087 : Handle<JSObject> object,
8088 : AllocationSiteCreationContext* site_context) {
8089 : JSObjectWalkVisitor<AllocationSiteCreationContext> v(site_context, false,
8090 : kNoHints);
8091 920835 : MaybeHandle<JSObject> result = v.StructureWalk(object);
8092 : Handle<JSObject> for_assert;
8093 : DCHECK(!result.ToHandle(&for_assert) || for_assert.is_identical_to(object));
8094 920835 : return result;
8095 : }
8096 :
8097 :
8098 7345609 : MaybeHandle<JSObject> JSObject::DeepCopy(
8099 : Handle<JSObject> object,
8100 : AllocationSiteUsageContext* site_context,
8101 : DeepCopyHints hints) {
8102 : JSObjectWalkVisitor<AllocationSiteUsageContext> v(site_context, true, hints);
8103 7345609 : MaybeHandle<JSObject> copy = v.StructureWalk(object);
8104 : Handle<JSObject> for_assert;
8105 : DCHECK(!copy.ToHandle(&for_assert) || !for_assert.is_identical_to(object));
8106 7345609 : return copy;
8107 : }
8108 :
8109 : // static
8110 10352699 : MaybeHandle<Object> JSReceiver::ToPrimitive(Handle<JSReceiver> receiver,
8111 : ToPrimitiveHint hint) {
8112 : Isolate* const isolate = receiver->GetIsolate();
8113 : Handle<Object> exotic_to_prim;
8114 20705398 : ASSIGN_RETURN_ON_EXCEPTION(
8115 : isolate, exotic_to_prim,
8116 : GetMethod(receiver, isolate->factory()->to_primitive_symbol()), Object);
8117 10352693 : if (!exotic_to_prim->IsUndefined(isolate)) {
8118 : Handle<Object> hint_string =
8119 6539 : isolate->factory()->ToPrimitiveHintString(hint);
8120 : Handle<Object> result;
8121 13078 : ASSIGN_RETURN_ON_EXCEPTION(
8122 : isolate, result,
8123 : Execution::Call(isolate, exotic_to_prim, receiver, 1, &hint_string),
8124 : Object);
8125 6410 : if (result->IsPrimitive()) return result;
8126 0 : THROW_NEW_ERROR(isolate,
8127 : NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8128 : Object);
8129 : }
8130 : return OrdinaryToPrimitive(receiver, (hint == ToPrimitiveHint::kString)
8131 : ? OrdinaryToPrimitiveHint::kString
8132 10346154 : : OrdinaryToPrimitiveHint::kNumber);
8133 : }
8134 :
8135 :
8136 : // static
8137 10346154 : MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive(
8138 : Handle<JSReceiver> receiver, OrdinaryToPrimitiveHint hint) {
8139 : Isolate* const isolate = receiver->GetIsolate();
8140 31038462 : Handle<String> method_names[2];
8141 10346154 : switch (hint) {
8142 : case OrdinaryToPrimitiveHint::kNumber:
8143 12382 : method_names[0] = isolate->factory()->valueOf_string();
8144 12382 : method_names[1] = isolate->factory()->toString_string();
8145 12382 : break;
8146 : case OrdinaryToPrimitiveHint::kString:
8147 10333772 : method_names[0] = isolate->factory()->toString_string();
8148 10333772 : method_names[1] = isolate->factory()->valueOf_string();
8149 10333772 : break;
8150 : }
8151 10362949 : for (Handle<String> name : method_names) {
8152 : Handle<Object> method;
8153 20708884 : ASSIGN_RETURN_ON_EXCEPTION(isolate, method,
8154 : JSReceiver::GetProperty(receiver, name), Object);
8155 10354414 : if (method->IsCallable()) {
8156 : Handle<Object> result;
8157 20707314 : ASSIGN_RETURN_ON_EXCEPTION(
8158 : isolate, result, Execution::Call(isolate, method, receiver, 0, NULL),
8159 : Object);
8160 10332865 : if (result->IsPrimitive()) return result;
8161 : }
8162 : }
8163 438 : THROW_NEW_ERROR(isolate,
8164 : NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8165 : Object);
8166 : }
8167 :
8168 :
8169 : // TODO(cbruni/jkummerow): Consider moving this into elements.cc.
8170 222954 : bool JSObject::HasEnumerableElements() {
8171 : // TODO(cbruni): cleanup
8172 : JSObject* object = this;
8173 222954 : switch (object->GetElementsKind()) {
8174 : case FAST_SMI_ELEMENTS:
8175 : case FAST_ELEMENTS:
8176 : case FAST_DOUBLE_ELEMENTS: {
8177 : int length = object->IsJSArray()
8178 : ? Smi::cast(JSArray::cast(object)->length())->value()
8179 89170 : : object->elements()->length();
8180 89170 : return length > 0;
8181 : }
8182 : case FAST_HOLEY_SMI_ELEMENTS:
8183 : case FAST_HOLEY_ELEMENTS: {
8184 : FixedArray* elements = FixedArray::cast(object->elements());
8185 : int length = object->IsJSArray()
8186 : ? Smi::cast(JSArray::cast(object)->length())->value()
8187 133339 : : elements->length();
8188 : Isolate* isolate = GetIsolate();
8189 4028504 : for (int i = 0; i < length; i++) {
8190 3934375 : if (!elements->is_the_hole(isolate, i)) return true;
8191 : }
8192 : return false;
8193 : }
8194 : case FAST_HOLEY_DOUBLE_ELEMENTS: {
8195 : int length = object->IsJSArray()
8196 : ? Smi::cast(JSArray::cast(object)->length())->value()
8197 75 : : object->elements()->length();
8198 : // Zero-length arrays would use the empty FixedArray...
8199 75 : if (length == 0) return false;
8200 : // ...so only cast to FixedDoubleArray otherwise.
8201 : FixedDoubleArray* elements = FixedDoubleArray::cast(object->elements());
8202 75 : for (int i = 0; i < length; i++) {
8203 75 : if (!elements->is_the_hole(i)) return true;
8204 : }
8205 : return false;
8206 : }
8207 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
8208 : case TYPE##_ELEMENTS:
8209 :
8210 : TYPED_ARRAYS(TYPED_ARRAY_CASE)
8211 : #undef TYPED_ARRAY_CASE
8212 : {
8213 : int length = object->elements()->length();
8214 0 : return length > 0;
8215 : }
8216 : case DICTIONARY_ELEMENTS: {
8217 : SeededNumberDictionary* elements =
8218 : SeededNumberDictionary::cast(object->elements());
8219 280 : return elements->NumberOfElementsFilterAttributes(ONLY_ENUMERABLE) > 0;
8220 : }
8221 : case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
8222 : case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
8223 : // We're approximating non-empty arguments objects here.
8224 : return true;
8225 : case FAST_STRING_WRAPPER_ELEMENTS:
8226 : case SLOW_STRING_WRAPPER_ELEMENTS:
8227 0 : if (String::cast(JSValue::cast(object)->value())->length() > 0) {
8228 : return true;
8229 : }
8230 0 : return object->elements()->length() > 0;
8231 : case NO_ELEMENTS:
8232 0 : return false;
8233 : }
8234 0 : UNREACHABLE();
8235 : return true;
8236 : }
8237 :
8238 :
8239 175387 : int Map::NumberOfDescribedProperties(DescriptorFlag which,
8240 : PropertyFilter filter) {
8241 : int result = 0;
8242 : DescriptorArray* descs = instance_descriptors();
8243 : int limit = which == ALL_DESCRIPTORS
8244 : ? descs->number_of_descriptors()
8245 175387 : : NumberOfOwnDescriptors();
8246 1120658 : for (int i = 0; i < limit; i++) {
8247 2605272 : if ((descs->GetDetails(i).attributes() & filter) == 0 &&
8248 714730 : !descs->GetKey(i)->FilterKey(filter)) {
8249 712003 : result++;
8250 : }
8251 : }
8252 175387 : return result;
8253 : }
8254 :
8255 :
8256 8783405 : int Map::NextFreePropertyIndex() {
8257 : int free_index = 0;
8258 : int number_of_own_descriptors = NumberOfOwnDescriptors();
8259 : DescriptorArray* descs = instance_descriptors();
8260 289323401 : for (int i = 0; i < number_of_own_descriptors; i++) {
8261 280540009 : PropertyDetails details = descs->GetDetails(i);
8262 280539996 : if (details.location() == kField) {
8263 271074062 : int candidate = details.field_index() + details.field_width_in_words();
8264 271074062 : if (candidate > free_index) free_index = candidate;
8265 : }
8266 : }
8267 8783392 : return free_index;
8268 : }
8269 :
8270 :
8271 16083027 : bool Map::OnlyHasSimpleProperties() {
8272 : // Wrapped string elements aren't explicitly stored in the elements backing
8273 : // store, but are loaded indirectly from the underlying string.
8274 16078518 : return !IsStringWrapperElementsKind(elements_kind()) &&
8275 48181067 : !IsSpecialReceiverMap() && !has_hidden_prototype() &&
8276 16083027 : !is_dictionary_map();
8277 : }
8278 :
8279 1064 : MUST_USE_RESULT Maybe<bool> FastGetOwnValuesOrEntries(
8280 : Isolate* isolate, Handle<JSReceiver> receiver, bool get_entries,
8281 : Handle<FixedArray>* result) {
8282 : Handle<Map> map(JSReceiver::cast(*receiver)->map(), isolate);
8283 :
8284 1064 : if (!map->IsJSObjectMap()) return Just(false);
8285 616 : if (!map->OnlyHasSimpleProperties()) return Just(false);
8286 :
8287 : Handle<JSObject> object(JSObject::cast(*receiver));
8288 :
8289 : Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
8290 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
8291 : int number_of_own_elements =
8292 952 : object->GetElementsAccessor()->GetCapacity(*object, object->elements());
8293 : Handle<FixedArray> values_or_entries = isolate->factory()->NewFixedArray(
8294 476 : number_of_own_descriptors + number_of_own_elements);
8295 476 : int count = 0;
8296 :
8297 476 : if (object->elements() != isolate->heap()->empty_fixed_array()) {
8298 336 : MAYBE_RETURN(object->GetElementsAccessor()->CollectValuesOrEntries(
8299 : isolate, object, values_or_entries, get_entries, &count,
8300 : ENUMERABLE_STRINGS),
8301 : Nothing<bool>());
8302 : }
8303 :
8304 476 : bool stable = object->map() == *map;
8305 :
8306 1792 : for (int index = 0; index < number_of_own_descriptors; index++) {
8307 : Handle<Name> next_key(descriptors->GetKey(index), isolate);
8308 1316 : if (!next_key->IsString()) continue;
8309 : Handle<Object> prop_value;
8310 :
8311 : // Directly decode from the descriptor array if |from| did not change shape.
8312 1176 : if (stable) {
8313 1148 : PropertyDetails details = descriptors->GetDetails(index);
8314 1148 : if (!details.IsEnumerable()) continue;
8315 784 : if (details.kind() == kData) {
8316 728 : if (details.location() == kDescriptor) {
8317 : prop_value = handle(descriptors->GetValue(index), isolate);
8318 : } else {
8319 728 : Representation representation = details.representation();
8320 728 : FieldIndex field_index = FieldIndex::ForDescriptor(*map, index);
8321 : prop_value =
8322 728 : JSObject::FastPropertyAt(object, representation, field_index);
8323 : }
8324 : } else {
8325 112 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8326 : isolate, prop_value, JSReceiver::GetProperty(object, next_key),
8327 : Nothing<bool>());
8328 56 : stable = object->map() == *map;
8329 : }
8330 : } else {
8331 : // If the map did change, do a slower lookup. We are still guaranteed that
8332 : // the object has a simple shape, and that the key is a name.
8333 28 : LookupIterator it(object, next_key, LookupIterator::OWN_SKIP_INTERCEPTOR);
8334 28 : if (!it.IsFound()) continue;
8335 : DCHECK(it.state() == LookupIterator::DATA ||
8336 : it.state() == LookupIterator::ACCESSOR);
8337 28 : if (!it.IsEnumerable()) continue;
8338 56 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8339 : isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
8340 : }
8341 :
8342 812 : if (get_entries) {
8343 560 : prop_value = MakeEntryPair(isolate, next_key, prop_value);
8344 : }
8345 :
8346 1624 : values_or_entries->set(count, *prop_value);
8347 812 : count++;
8348 : }
8349 :
8350 476 : if (count < values_or_entries->length()) values_or_entries->Shrink(count);
8351 476 : *result = values_or_entries;
8352 : return Just(true);
8353 : }
8354 :
8355 1064 : MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate,
8356 : Handle<JSReceiver> object,
8357 : PropertyFilter filter,
8358 : bool get_entries) {
8359 : Handle<FixedArray> values_or_entries;
8360 1064 : if (filter == ENUMERABLE_STRINGS) {
8361 : Maybe<bool> fast_values_or_entries = FastGetOwnValuesOrEntries(
8362 1064 : isolate, object, get_entries, &values_or_entries);
8363 1540 : if (fast_values_or_entries.IsNothing()) return MaybeHandle<FixedArray>();
8364 1064 : if (fast_values_or_entries.FromJust()) return values_or_entries;
8365 : }
8366 :
8367 : PropertyFilter key_filter =
8368 588 : static_cast<PropertyFilter>(filter & ~ONLY_ENUMERABLE);
8369 :
8370 : Handle<FixedArray> keys;
8371 1176 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8372 : isolate, keys,
8373 : KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, key_filter,
8374 : GetKeysConversion::kConvertToString),
8375 : MaybeHandle<FixedArray>());
8376 :
8377 588 : values_or_entries = isolate->factory()->NewFixedArray(keys->length());
8378 : int length = 0;
8379 :
8380 5152 : for (int i = 0; i < keys->length(); ++i) {
8381 : Handle<Name> key = Handle<Name>::cast(handle(keys->get(i), isolate));
8382 :
8383 1988 : if (filter & ONLY_ENUMERABLE) {
8384 : PropertyDescriptor descriptor;
8385 : Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor(
8386 1988 : isolate, object, key, &descriptor);
8387 1988 : MAYBE_RETURN(did_get_descriptor, MaybeHandle<FixedArray>());
8388 3948 : if (!did_get_descriptor.FromJust() || !descriptor.enumerable()) continue;
8389 : }
8390 :
8391 : Handle<Object> value;
8392 2744 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8393 : isolate, value, JSReceiver::GetPropertyOrElement(object, key),
8394 : MaybeHandle<FixedArray>());
8395 :
8396 1372 : if (get_entries) {
8397 : Handle<FixedArray> entry_storage =
8398 686 : isolate->factory()->NewUninitializedFixedArray(2);
8399 686 : entry_storage->set(0, *key);
8400 686 : entry_storage->set(1, *value);
8401 : value = isolate->factory()->NewJSArrayWithElements(entry_storage,
8402 686 : FAST_ELEMENTS, 2);
8403 : }
8404 :
8405 1372 : values_or_entries->set(length, *value);
8406 1372 : length++;
8407 : }
8408 588 : if (length < values_or_entries->length()) values_or_entries->Shrink(length);
8409 : return values_or_entries;
8410 : }
8411 :
8412 518 : MaybeHandle<FixedArray> JSReceiver::GetOwnValues(Handle<JSReceiver> object,
8413 : PropertyFilter filter) {
8414 518 : return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, false);
8415 : }
8416 :
8417 546 : MaybeHandle<FixedArray> JSReceiver::GetOwnEntries(Handle<JSReceiver> object,
8418 : PropertyFilter filter) {
8419 546 : return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, true);
8420 : }
8421 :
8422 303091 : bool Map::DictionaryElementsInPrototypeChainOnly() {
8423 303091 : if (IsDictionaryElementsKind(elements_kind())) {
8424 : return false;
8425 : }
8426 :
8427 891548 : for (PrototypeIterator iter(this); !iter.IsAtEnd(); iter.Advance()) {
8428 : // Be conservative, don't walk into proxies.
8429 1205650 : if (iter.GetCurrent()->IsJSProxy()) return true;
8430 : // String wrappers have non-configurable, non-writable elements.
8431 1205650 : if (iter.GetCurrent()->IsStringWrapper()) return true;
8432 602780 : JSObject* current = iter.GetCurrent<JSObject>();
8433 :
8434 613997 : if (current->HasDictionaryElements() &&
8435 11217 : current->element_dictionary()->requires_slow_elements()) {
8436 : return true;
8437 : }
8438 :
8439 591882 : if (current->HasSlowArgumentsElements()) {
8440 : FixedArray* parameter_map = FixedArray::cast(current->elements());
8441 : Object* arguments = parameter_map->get(1);
8442 0 : if (SeededNumberDictionary::cast(arguments)->requires_slow_elements()) {
8443 : return true;
8444 : }
8445 : }
8446 : }
8447 :
8448 288723 : return false;
8449 : }
8450 :
8451 :
8452 386592 : MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
8453 : Handle<Name> name,
8454 : Handle<Object> getter,
8455 : Handle<Object> setter,
8456 : PropertyAttributes attributes) {
8457 : Isolate* isolate = object->GetIsolate();
8458 :
8459 : LookupIterator it = LookupIterator::PropertyOrElement(
8460 386592 : isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
8461 386593 : return DefineAccessor(&it, getter, setter, attributes);
8462 : }
8463 :
8464 :
8465 1524592 : MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it,
8466 : Handle<Object> getter,
8467 : Handle<Object> setter,
8468 : PropertyAttributes attributes) {
8469 : Isolate* isolate = it->isolate();
8470 :
8471 508199 : it->UpdateProtector();
8472 :
8473 508200 : if (it->state() == LookupIterator::ACCESS_CHECK) {
8474 2657 : if (!it->HasAccess()) {
8475 6 : isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
8476 6 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
8477 : return isolate->factory()->undefined_value();
8478 : }
8479 2651 : it->Next();
8480 : }
8481 :
8482 : Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
8483 : // Ignore accessors on typed arrays.
8484 547507 : if (it->IsElement() && object->HasFixedTypedArrayElements()) {
8485 : return it->factory()->undefined_value();
8486 : }
8487 :
8488 : DCHECK(getter->IsCallable() || getter->IsUndefined(isolate) ||
8489 : getter->IsNull(isolate) || getter->IsFunctionTemplateInfo());
8490 : DCHECK(setter->IsCallable() || setter->IsUndefined(isolate) ||
8491 : setter->IsNull(isolate) || setter->IsFunctionTemplateInfo());
8492 508193 : it->TransitionToAccessorProperty(getter, setter, attributes);
8493 :
8494 : return isolate->factory()->undefined_value();
8495 : }
8496 :
8497 :
8498 118446 : MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
8499 : Handle<AccessorInfo> info) {
8500 : Isolate* isolate = object->GetIsolate();
8501 : Handle<Name> name(Name::cast(info->name()), isolate);
8502 :
8503 : LookupIterator it = LookupIterator::PropertyOrElement(
8504 118446 : isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
8505 :
8506 : // Duplicate ACCESS_CHECK outside of GetPropertyAttributes for the case that
8507 : // the FailedAccessCheckCallbackFunction doesn't throw an exception.
8508 : //
8509 : // TODO(verwaest): Force throw an exception if the callback doesn't, so we can
8510 : // remove reliance on default return values.
8511 118446 : if (it.state() == LookupIterator::ACCESS_CHECK) {
8512 6955 : if (!it.HasAccess()) {
8513 6 : isolate->ReportFailedAccessCheck(object);
8514 6 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
8515 0 : return it.factory()->undefined_value();
8516 : }
8517 6949 : it.Next();
8518 : }
8519 :
8520 : // Ignore accessors on typed arrays.
8521 118454 : if (it.IsElement() && object->HasFixedTypedArrayElements()) {
8522 0 : return it.factory()->undefined_value();
8523 : }
8524 :
8525 118440 : CHECK(GetPropertyAttributes(&it).IsJust());
8526 :
8527 : // ES5 forbids turning a property into an accessor if it's not
8528 : // configurable. See 8.6.1 (Table 5).
8529 118483 : if (it.IsFound() && !it.IsConfigurable()) {
8530 29 : return it.factory()->undefined_value();
8531 : }
8532 :
8533 118411 : it.TransitionToAccessorPair(info, info->property_attributes());
8534 :
8535 : return object;
8536 : }
8537 :
8538 84 : Object* JSObject::SlowReverseLookup(Object* value) {
8539 84 : if (HasFastProperties()) {
8540 : int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
8541 : DescriptorArray* descs = map()->instance_descriptors();
8542 : bool value_is_number = value->IsNumber();
8543 252 : for (int i = 0; i < number_of_own_descriptors; i++) {
8544 210 : PropertyDetails details = descs->GetDetails(i);
8545 210 : if (details.location() == kField) {
8546 : DCHECK_EQ(kData, details.kind());
8547 28 : FieldIndex field_index = FieldIndex::ForDescriptor(map(), i);
8548 28 : if (IsUnboxedDoubleField(field_index)) {
8549 0 : if (value_is_number) {
8550 : double property = RawFastDoublePropertyAt(field_index);
8551 0 : if (property == value->Number()) {
8552 28 : return descs->GetKey(i);
8553 : }
8554 : }
8555 : } else {
8556 28 : Object* property = RawFastPropertyAt(field_index);
8557 28 : if (field_index.is_double()) {
8558 : DCHECK(property->IsMutableHeapNumber());
8559 0 : if (value_is_number && property->Number() == value->Number()) {
8560 0 : return descs->GetKey(i);
8561 : }
8562 28 : } else if (property == value) {
8563 28 : return descs->GetKey(i);
8564 : }
8565 : }
8566 : } else {
8567 : DCHECK_EQ(kDescriptor, details.location());
8568 182 : if (details.kind() == kData) {
8569 168 : if (descs->GetValue(i) == value) {
8570 0 : return descs->GetKey(i);
8571 : }
8572 : }
8573 : }
8574 : }
8575 42 : return GetHeap()->undefined_value();
8576 14 : } else if (IsJSGlobalObject()) {
8577 14 : return global_dictionary()->SlowReverseLookup(value);
8578 : } else {
8579 0 : return property_dictionary()->SlowReverseLookup(value);
8580 : }
8581 : }
8582 :
8583 :
8584 25922194 : Handle<Map> Map::RawCopy(Handle<Map> map, int instance_size) {
8585 : Isolate* isolate = map->GetIsolate();
8586 : Handle<Map> result =
8587 25922194 : isolate->factory()->NewMap(map->instance_type(), instance_size);
8588 : Handle<Object> prototype(map->prototype(), isolate);
8589 25922198 : Map::SetPrototype(result, prototype);
8590 51844417 : result->set_constructor_or_backpointer(map->GetConstructor());
8591 : result->set_bit_field(map->bit_field());
8592 : result->set_bit_field2(map->bit_field2());
8593 : int new_bit_field3 = map->bit_field3();
8594 : new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true);
8595 : new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0);
8596 : new_bit_field3 = EnumLengthBits::update(new_bit_field3,
8597 : kInvalidEnumCacheSentinel);
8598 25922212 : new_bit_field3 = Deprecated::update(new_bit_field3, false);
8599 25922212 : if (!map->is_dictionary_map()) {
8600 24640893 : new_bit_field3 = IsUnstable::update(new_bit_field3, false);
8601 : }
8602 25922212 : result->set_bit_field3(new_bit_field3);
8603 25922212 : return result;
8604 : }
8605 :
8606 :
8607 1318662 : Handle<Map> Map::Normalize(Handle<Map> fast_map, PropertyNormalizationMode mode,
8608 : const char* reason) {
8609 : DCHECK(!fast_map->is_dictionary_map());
8610 :
8611 329942 : Isolate* isolate = fast_map->GetIsolate();
8612 : Handle<Object> maybe_cache(isolate->native_context()->normalized_map_cache(),
8613 2637324 : isolate);
8614 : bool use_cache =
8615 2402465 : !fast_map->is_prototype_map() && !maybe_cache->IsUndefined(isolate);
8616 : Handle<NormalizedMapCache> cache;
8617 1318662 : if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache);
8618 :
8619 : Handle<Map> new_map;
8620 3485320 : if (use_cache && cache->Get(fast_map, mode).ToHandle(&new_map)) {
8621 : #ifdef VERIFY_HEAP
8622 : if (FLAG_verify_heap) new_map->DictionaryMapVerify();
8623 : #endif
8624 : #ifdef ENABLE_SLOW_DCHECKS
8625 : if (FLAG_enable_slow_asserts) {
8626 : // The cached map should match newly created normalized map bit-by-bit,
8627 : // except for the code cache, which can contain some ics which can be
8628 : // applied to the shared map, dependent code and weak cell cache.
8629 : Handle<Map> fresh = Map::CopyNormalized(fast_map, mode);
8630 :
8631 : if (new_map->is_prototype_map()) {
8632 : // For prototype maps, the PrototypeInfo is not copied.
8633 : DCHECK(memcmp(fresh->address(), new_map->address(),
8634 : kTransitionsOrPrototypeInfoOffset) == 0);
8635 : DCHECK(fresh->raw_transitions() == Smi::kZero);
8636 : STATIC_ASSERT(kDescriptorsOffset ==
8637 : kTransitionsOrPrototypeInfoOffset + kPointerSize);
8638 : DCHECK(memcmp(HeapObject::RawField(*fresh, kDescriptorsOffset),
8639 : HeapObject::RawField(*new_map, kDescriptorsOffset),
8640 : kCodeCacheOffset - kDescriptorsOffset) == 0);
8641 : } else {
8642 : DCHECK(memcmp(fresh->address(), new_map->address(),
8643 : Map::kCodeCacheOffset) == 0);
8644 : }
8645 : STATIC_ASSERT(Map::kDependentCodeOffset ==
8646 : Map::kCodeCacheOffset + kPointerSize);
8647 : STATIC_ASSERT(Map::kWeakCellCacheOffset ==
8648 : Map::kDependentCodeOffset + kPointerSize);
8649 : int offset = Map::kWeakCellCacheOffset + kPointerSize;
8650 : DCHECK(memcmp(fresh->address() + offset,
8651 : new_map->address() + offset,
8652 : Map::kSize - offset) == 0);
8653 : }
8654 : #endif
8655 : } else {
8656 565275 : new_map = Map::CopyNormalized(fast_map, mode);
8657 565275 : if (use_cache) {
8658 329942 : cache->Set(fast_map, new_map);
8659 329942 : isolate->counters()->maps_normalized()->Increment();
8660 : }
8661 : #if TRACE_MAPS
8662 : if (FLAG_trace_maps) {
8663 : PrintF("[TraceMaps: Normalize from= %p to= %p reason= %s ]\n",
8664 : reinterpret_cast<void*>(*fast_map),
8665 : reinterpret_cast<void*>(*new_map), reason);
8666 : }
8667 : #endif
8668 : }
8669 1318662 : fast_map->NotifyLeafMapLayoutChange();
8670 1318662 : return new_map;
8671 : }
8672 :
8673 :
8674 565275 : Handle<Map> Map::CopyNormalized(Handle<Map> map,
8675 : PropertyNormalizationMode mode) {
8676 : int new_instance_size = map->instance_size();
8677 565275 : if (mode == CLEAR_INOBJECT_PROPERTIES) {
8678 110251 : new_instance_size -= map->GetInObjectProperties() * kPointerSize;
8679 : }
8680 :
8681 565275 : Handle<Map> result = RawCopy(map, new_instance_size);
8682 :
8683 565275 : if (mode != CLEAR_INOBJECT_PROPERTIES) {
8684 : result->SetInObjectProperties(map->GetInObjectProperties());
8685 : }
8686 :
8687 : result->set_dictionary_map(true);
8688 : result->set_migration_target(false);
8689 : result->set_construction_counter(kNoSlackTracking);
8690 :
8691 : #ifdef VERIFY_HEAP
8692 : if (FLAG_verify_heap) result->DictionaryMapVerify();
8693 : #endif
8694 :
8695 565275 : return result;
8696 : }
8697 :
8698 : // Return an immutable prototype exotic object version of the input map.
8699 : // Never even try to cache it in the transition tree, as it is intended
8700 : // for the global object and its prototype chain, and excluding it saves
8701 : // memory on the map transition tree.
8702 :
8703 : // static
8704 7 : Handle<Map> Map::TransitionToImmutableProto(Handle<Map> map) {
8705 7 : Handle<Map> new_map = Map::Copy(map, "ImmutablePrototype");
8706 : new_map->set_immutable_proto(true);
8707 7 : return new_map;
8708 : }
8709 :
8710 410519 : Handle<Map> Map::CopyInitialMap(Handle<Map> map, int instance_size,
8711 : int in_object_properties,
8712 : int unused_property_fields) {
8713 : #ifdef DEBUG
8714 : Isolate* isolate = map->GetIsolate();
8715 : // Strict function maps have Function as a constructor but the
8716 : // Function's initial map is a sloppy function map. Same holds for
8717 : // GeneratorFunction / AsyncFunction and its initial map.
8718 : Object* constructor = map->GetConstructor();
8719 : DCHECK(constructor->IsJSFunction());
8720 : DCHECK(*map == JSFunction::cast(constructor)->initial_map() ||
8721 : *map == *isolate->strict_function_map() ||
8722 : *map == *isolate->generator_function_map() ||
8723 : *map == *isolate->async_function_map());
8724 : #endif
8725 : // Initial maps must always own their descriptors and it's descriptor array
8726 : // does not contain descriptors that do not belong to the map.
8727 : DCHECK(map->owns_descriptors());
8728 : DCHECK_EQ(map->NumberOfOwnDescriptors(),
8729 : map->instance_descriptors()->number_of_descriptors());
8730 :
8731 410519 : Handle<Map> result = RawCopy(map, instance_size);
8732 :
8733 : // Please note instance_type and instance_size are set when allocated.
8734 : result->SetInObjectProperties(in_object_properties);
8735 : result->set_unused_property_fields(unused_property_fields);
8736 :
8737 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
8738 410521 : if (number_of_own_descriptors > 0) {
8739 : // The copy will use the same descriptors array.
8740 : result->UpdateDescriptors(map->instance_descriptors(),
8741 214379 : map->GetLayoutDescriptor());
8742 : result->SetNumberOfOwnDescriptors(number_of_own_descriptors);
8743 :
8744 : DCHECK_EQ(result->NumberOfFields(),
8745 : in_object_properties - unused_property_fields);
8746 : }
8747 :
8748 410521 : return result;
8749 : }
8750 :
8751 :
8752 24946405 : Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) {
8753 24946405 : Handle<Map> result = RawCopy(map, map->instance_size());
8754 :
8755 : // Please note instance_type and instance_size are set when allocated.
8756 24946418 : if (map->IsJSObjectMap()) {
8757 : result->SetInObjectProperties(map->GetInObjectProperties());
8758 : result->set_unused_property_fields(map->unused_property_fields());
8759 : }
8760 : result->ClearCodeCache(map->GetHeap());
8761 24946418 : map->NotifyLeafMapLayoutChange();
8762 24946414 : return result;
8763 : }
8764 :
8765 :
8766 9529929 : Handle<Map> Map::ShareDescriptor(Handle<Map> map,
8767 : Handle<DescriptorArray> descriptors,
8768 : Descriptor* descriptor) {
8769 : // Sanity check. This path is only to be taken if the map owns its descriptor
8770 : // array, implying that its NumberOfOwnDescriptors equals the number of
8771 : // descriptors in the descriptor array.
8772 : DCHECK_EQ(map->NumberOfOwnDescriptors(),
8773 : map->instance_descriptors()->number_of_descriptors());
8774 :
8775 9529929 : Handle<Map> result = CopyDropDescriptors(map);
8776 9529934 : Handle<Name> name = descriptor->GetKey();
8777 :
8778 : // Ensure there's space for the new descriptor in the shared descriptor array.
8779 9529934 : if (descriptors->NumberOfSlackDescriptors() == 0) {
8780 5829126 : int old_size = descriptors->number_of_descriptors();
8781 5829126 : if (old_size == 0) {
8782 531 : descriptors = DescriptorArray::Allocate(map->GetIsolate(), 0, 1);
8783 : } else {
8784 5828595 : int slack = SlackForArraySize(old_size, kMaxNumberOfDescriptors);
8785 5828595 : EnsureDescriptorSlack(map, slack);
8786 : descriptors = handle(map->instance_descriptors());
8787 : }
8788 : }
8789 :
8790 : Handle<LayoutDescriptor> layout_descriptor =
8791 : FLAG_unbox_double_fields
8792 : ? LayoutDescriptor::ShareAppend(map, descriptor->GetDetails())
8793 9529932 : : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
8794 :
8795 : {
8796 : DisallowHeapAllocation no_gc;
8797 9529930 : descriptors->Append(descriptor);
8798 9529933 : result->InitializeDescriptors(*descriptors, *layout_descriptor);
8799 : }
8800 :
8801 : DCHECK(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1);
8802 9529931 : ConnectTransition(map, result, name, SIMPLE_PROPERTY_TRANSITION);
8803 :
8804 9529934 : return result;
8805 : }
8806 :
8807 :
8808 : #if TRACE_MAPS
8809 :
8810 : // static
8811 : void Map::TraceTransition(const char* what, Map* from, Map* to, Name* name) {
8812 : if (FLAG_trace_maps) {
8813 : PrintF("[TraceMaps: %s from= %p to= %p name= ", what,
8814 : reinterpret_cast<void*>(from), reinterpret_cast<void*>(to));
8815 : name->NameShortPrint();
8816 : PrintF(" ]\n");
8817 : }
8818 : }
8819 :
8820 :
8821 : // static
8822 : void Map::TraceAllTransitions(Map* map) {
8823 : Object* transitions = map->raw_transitions();
8824 : int num_transitions = TransitionArray::NumberOfTransitions(transitions);
8825 : for (int i = -0; i < num_transitions; ++i) {
8826 : Map* target = TransitionArray::GetTarget(transitions, i);
8827 : Name* key = TransitionArray::GetKey(transitions, i);
8828 : Map::TraceTransition("Transition", map, target, key);
8829 : Map::TraceAllTransitions(target);
8830 : }
8831 : }
8832 :
8833 : #endif // TRACE_MAPS
8834 :
8835 :
8836 11753241 : void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
8837 : Handle<Name> name, SimpleTransitionFlag flag) {
8838 23506487 : if (!parent->GetBackPointer()->IsUndefined(parent->GetIsolate())) {
8839 : parent->set_owns_descriptors(false);
8840 : } else {
8841 : // |parent| is initial map and it must keep the ownership, there must be no
8842 : // descriptors in the descriptors array that do not belong to the map.
8843 : DCHECK(parent->owns_descriptors());
8844 : DCHECK_EQ(parent->NumberOfOwnDescriptors(),
8845 : parent->instance_descriptors()->number_of_descriptors());
8846 : }
8847 11753246 : if (parent->is_prototype_map()) {
8848 : DCHECK(child->is_prototype_map());
8849 : #if TRACE_MAPS
8850 : Map::TraceTransition("NoTransition", *parent, *child, *name);
8851 : #endif
8852 : } else {
8853 11753246 : TransitionArray::Insert(parent, name, child, flag);
8854 : #if TRACE_MAPS
8855 : Map::TraceTransition("Transition", *parent, *child, *name);
8856 : #endif
8857 : }
8858 11753246 : }
8859 :
8860 :
8861 14395438 : Handle<Map> Map::CopyReplaceDescriptors(
8862 : Handle<Map> map, Handle<DescriptorArray> descriptors,
8863 : Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag,
8864 : MaybeHandle<Name> maybe_name, const char* reason,
8865 : SimpleTransitionFlag simple_flag) {
8866 : DCHECK(descriptors->IsSortedNoDuplicates());
8867 :
8868 14395438 : Handle<Map> result = CopyDropDescriptors(map);
8869 :
8870 14395444 : if (!map->is_prototype_map()) {
8871 11255359 : if (flag == INSERT_TRANSITION &&
8872 1832059 : TransitionArray::CanHaveMoreTransitions(map)) {
8873 1832059 : result->InitializeDescriptors(*descriptors, *layout_descriptor);
8874 :
8875 : Handle<Name> name;
8876 1832060 : CHECK(maybe_name.ToHandle(&name));
8877 1832060 : ConnectTransition(map, result, name, simple_flag);
8878 : } else {
8879 7591241 : descriptors->GeneralizeAllFields();
8880 : result->InitializeDescriptors(*descriptors,
8881 7591243 : LayoutDescriptor::FastPointerLayout());
8882 : }
8883 : } else {
8884 4972144 : result->InitializeDescriptors(*descriptors, *layout_descriptor);
8885 : }
8886 : #if TRACE_MAPS
8887 : if (FLAG_trace_maps &&
8888 : // Mirror conditions above that did not call ConnectTransition().
8889 : (map->is_prototype_map() ||
8890 : !(flag == INSERT_TRANSITION &&
8891 : TransitionArray::CanHaveMoreTransitions(map)))) {
8892 : PrintF("[TraceMaps: ReplaceDescriptors from= %p to= %p reason= %s ]\n",
8893 : reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*result),
8894 : reason);
8895 : }
8896 : #endif
8897 :
8898 14395443 : return result;
8899 : }
8900 :
8901 :
8902 : // Creates transition tree starting from |split_map| and adding all descriptors
8903 : // starting from descriptor with index |split_map|.NumberOfOwnDescriptors().
8904 : // The way how it is done is tricky because of GC and special descriptors
8905 : // marking logic.
8906 167598 : Handle<Map> Map::AddMissingTransitions(
8907 : Handle<Map> split_map, Handle<DescriptorArray> descriptors,
8908 : Handle<LayoutDescriptor> full_layout_descriptor) {
8909 : DCHECK(descriptors->IsSortedNoDuplicates());
8910 : int split_nof = split_map->NumberOfOwnDescriptors();
8911 167598 : int nof_descriptors = descriptors->number_of_descriptors();
8912 : DCHECK_LT(split_nof, nof_descriptors);
8913 :
8914 : // Start with creating last map which will own full descriptors array.
8915 : // This is necessary to guarantee that GC will mark the whole descriptor
8916 : // array if any of the allocations happening below fail.
8917 : // Number of unused properties is temporarily incorrect and the layout
8918 : // descriptor could unnecessarily be in slow mode but we will fix after
8919 : // all the other intermediate maps are created.
8920 167598 : Handle<Map> last_map = CopyDropDescriptors(split_map);
8921 167598 : last_map->InitializeDescriptors(*descriptors, *full_layout_descriptor);
8922 : last_map->set_unused_property_fields(0);
8923 :
8924 : // During creation of intermediate maps we violate descriptors sharing
8925 : // invariant since the last map is not yet connected to the transition tree
8926 : // we create here. But it is safe because GC never trims map's descriptors
8927 : // if there are no dead transitions from that map and this is exactly the
8928 : // case for all the intermediate maps we create here.
8929 : Handle<Map> map = split_map;
8930 248953 : for (int i = split_nof; i < nof_descriptors - 1; ++i) {
8931 81355 : Handle<Map> new_map = CopyDropDescriptors(map);
8932 81355 : InstallDescriptors(map, new_map, i, descriptors, full_layout_descriptor);
8933 81355 : map = new_map;
8934 : }
8935 167598 : map->NotifyLeafMapLayoutChange();
8936 : InstallDescriptors(map, last_map, nof_descriptors - 1, descriptors,
8937 167598 : full_layout_descriptor);
8938 167598 : return last_map;
8939 : }
8940 :
8941 :
8942 : // Since this method is used to rewrite an existing transition tree, it can
8943 : // always insert transitions without checking.
8944 248953 : void Map::InstallDescriptors(Handle<Map> parent, Handle<Map> child,
8945 : int new_descriptor,
8946 : Handle<DescriptorArray> descriptors,
8947 : Handle<LayoutDescriptor> full_layout_descriptor) {
8948 : DCHECK(descriptors->IsSortedNoDuplicates());
8949 :
8950 248953 : child->set_instance_descriptors(*descriptors);
8951 248953 : child->SetNumberOfOwnDescriptors(new_descriptor + 1);
8952 :
8953 : int unused_property_fields = parent->unused_property_fields();
8954 248953 : PropertyDetails details = descriptors->GetDetails(new_descriptor);
8955 248953 : if (details.location() == kField) {
8956 231522 : unused_property_fields = parent->unused_property_fields() - 1;
8957 231522 : if (unused_property_fields < 0) {
8958 21521 : unused_property_fields += JSObject::kFieldsAdded;
8959 : }
8960 : }
8961 : child->set_unused_property_fields(unused_property_fields);
8962 :
8963 : if (FLAG_unbox_double_fields) {
8964 : Handle<LayoutDescriptor> layout_descriptor =
8965 : LayoutDescriptor::AppendIfFastOrUseFull(parent, details,
8966 248953 : full_layout_descriptor);
8967 248953 : child->set_layout_descriptor(*layout_descriptor);
8968 : #ifdef VERIFY_HEAP
8969 : // TODO(ishell): remove these checks from VERIFY_HEAP mode.
8970 : if (FLAG_verify_heap) {
8971 : CHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
8972 : }
8973 : #else
8974 : SLOW_DCHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
8975 : #endif
8976 248953 : child->set_visitor_id(Heap::GetStaticVisitorIdForMap(*child));
8977 : }
8978 :
8979 248953 : Handle<Name> name = handle(descriptors->GetKey(new_descriptor));
8980 248953 : ConnectTransition(parent, child, name, SIMPLE_PROPERTY_TRANSITION);
8981 248953 : }
8982 :
8983 :
8984 273704 : Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind,
8985 : TransitionFlag flag) {
8986 : Map* maybe_elements_transition_map = NULL;
8987 273704 : if (flag == INSERT_TRANSITION) {
8988 : // Ensure we are requested to add elements kind transition "near the root".
8989 : DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(),
8990 : map->NumberOfOwnDescriptors());
8991 :
8992 : maybe_elements_transition_map = map->ElementsTransitionMap();
8993 : DCHECK(maybe_elements_transition_map == NULL ||
8994 : (maybe_elements_transition_map->elements_kind() ==
8995 : DICTIONARY_ELEMENTS &&
8996 : kind == DICTIONARY_ELEMENTS));
8997 : DCHECK(!IsFastElementsKind(kind) ||
8998 : IsMoreGeneralElementsKindTransition(map->elements_kind(), kind));
8999 : DCHECK(kind != map->elements_kind());
9000 : }
9001 :
9002 268315 : bool insert_transition = flag == INSERT_TRANSITION &&
9003 415835 : TransitionArray::CanHaveMoreTransitions(map) &&
9004 : maybe_elements_transition_map == NULL;
9005 :
9006 273704 : if (insert_transition) {
9007 142131 : Handle<Map> new_map = CopyForTransition(map, "CopyAsElementsKind");
9008 : new_map->set_elements_kind(kind);
9009 :
9010 : Isolate* isolate = map->GetIsolate();
9011 : Handle<Name> name = isolate->factory()->elements_transition_symbol();
9012 142131 : ConnectTransition(map, new_map, name, SPECIAL_TRANSITION);
9013 142131 : return new_map;
9014 : }
9015 :
9016 : // Create a new free-floating map only if we are not allowed to store it.
9017 131573 : Handle<Map> new_map = Copy(map, "CopyAsElementsKind");
9018 : new_map->set_elements_kind(kind);
9019 131573 : return new_map;
9020 : }
9021 :
9022 :
9023 731 : Handle<Map> Map::AsLanguageMode(Handle<Map> initial_map,
9024 : LanguageMode language_mode, FunctionKind kind) {
9025 : DCHECK_EQ(JS_FUNCTION_TYPE, initial_map->instance_type());
9026 : // Initial map for sloppy mode function is stored in the function
9027 : // constructor. Initial maps for strict mode are cached as special transitions
9028 : // using |strict_function_transition_symbol| as a key.
9029 731 : if (language_mode == SLOPPY) return initial_map;
9030 : Isolate* isolate = initial_map->GetIsolate();
9031 :
9032 226 : int map_index = Context::FunctionMapIndex(language_mode, kind);
9033 : Handle<Map> function_map(
9034 452 : Map::cast(isolate->native_context()->get(map_index)));
9035 :
9036 : STATIC_ASSERT(LANGUAGE_END == 2);
9037 : DCHECK_EQ(STRICT, language_mode);
9038 : Handle<Symbol> transition_symbol =
9039 : isolate->factory()->strict_function_transition_symbol();
9040 : Map* maybe_transition =
9041 226 : TransitionArray::SearchSpecial(*initial_map, *transition_symbol);
9042 226 : if (maybe_transition != NULL) {
9043 : return handle(maybe_transition, isolate);
9044 : }
9045 170 : initial_map->NotifyLeafMapLayoutChange();
9046 :
9047 : // Create new map taking descriptors from the |function_map| and all
9048 : // the other details from the |initial_map|.
9049 : Handle<Map> map =
9050 : Map::CopyInitialMap(function_map, initial_map->instance_size(),
9051 : initial_map->GetInObjectProperties(),
9052 170 : initial_map->unused_property_fields());
9053 170 : map->SetConstructor(initial_map->GetConstructor());
9054 170 : map->set_prototype(initial_map->prototype());
9055 :
9056 170 : if (TransitionArray::CanHaveMoreTransitions(initial_map)) {
9057 : Map::ConnectTransition(initial_map, map, transition_symbol,
9058 170 : SPECIAL_TRANSITION);
9059 : }
9060 170 : return map;
9061 : }
9062 :
9063 :
9064 142131 : Handle<Map> Map::CopyForTransition(Handle<Map> map, const char* reason) {
9065 : DCHECK(!map->is_prototype_map());
9066 142131 : Handle<Map> new_map = CopyDropDescriptors(map);
9067 :
9068 142131 : if (map->owns_descriptors()) {
9069 : // In case the map owned its own descriptors, share the descriptors and
9070 : // transfer ownership to the new map.
9071 : // The properties did not change, so reuse descriptors.
9072 : new_map->InitializeDescriptors(map->instance_descriptors(),
9073 142129 : map->GetLayoutDescriptor());
9074 : } else {
9075 : // In case the map did not own its own descriptors, a split is forced by
9076 : // copying the map; creating a new descriptor array cell.
9077 : Handle<DescriptorArray> descriptors(map->instance_descriptors());
9078 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9079 : Handle<DescriptorArray> new_descriptors =
9080 : DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
9081 : Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9082 : map->GetIsolate());
9083 2 : new_map->InitializeDescriptors(*new_descriptors, *new_layout_descriptor);
9084 : }
9085 :
9086 : #if TRACE_MAPS
9087 : if (FLAG_trace_maps) {
9088 : PrintF("[TraceMaps: CopyForTransition from= %p to= %p reason= %s ]\n",
9089 : reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*new_map),
9090 : reason);
9091 : }
9092 : #endif
9093 :
9094 142131 : return new_map;
9095 : }
9096 :
9097 :
9098 6162719 : Handle<Map> Map::Copy(Handle<Map> map, const char* reason) {
9099 : Handle<DescriptorArray> descriptors(map->instance_descriptors());
9100 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9101 : Handle<DescriptorArray> new_descriptors =
9102 6162721 : DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
9103 : Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9104 : map->GetIsolate());
9105 : return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9106 : OMIT_TRANSITION, MaybeHandle<Name>(), reason,
9107 6162721 : SPECIAL_TRANSITION);
9108 : }
9109 :
9110 :
9111 250729 : Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) {
9112 : Handle<Map> copy =
9113 501458 : Copy(handle(isolate->object_function()->initial_map()), "MapCreate");
9114 :
9115 : // Check that we do not overflow the instance size when adding the extra
9116 : // inobject properties. If the instance size overflows, we allocate as many
9117 : // properties as we can as inobject properties.
9118 : int max_extra_properties =
9119 : (JSObject::kMaxInstanceSize - JSObject::kHeaderSize) >> kPointerSizeLog2;
9120 :
9121 250729 : if (inobject_properties > max_extra_properties) {
9122 : inobject_properties = max_extra_properties;
9123 : }
9124 :
9125 : int new_instance_size =
9126 250729 : JSObject::kHeaderSize + kPointerSize * inobject_properties;
9127 :
9128 : // Adjust the map with the extra inobject properties.
9129 : copy->SetInObjectProperties(inobject_properties);
9130 : copy->set_unused_property_fields(inobject_properties);
9131 : copy->set_instance_size(new_instance_size);
9132 250729 : copy->set_visitor_id(Heap::GetStaticVisitorIdForMap(*copy));
9133 250729 : return copy;
9134 : }
9135 :
9136 :
9137 51215 : Handle<Map> Map::CopyForPreventExtensions(Handle<Map> map,
9138 : PropertyAttributes attrs_to_add,
9139 : Handle<Symbol> transition_marker,
9140 : const char* reason) {
9141 : int num_descriptors = map->NumberOfOwnDescriptors();
9142 : Isolate* isolate = map->GetIsolate();
9143 : Handle<DescriptorArray> new_desc = DescriptorArray::CopyUpToAddAttributes(
9144 : handle(map->instance_descriptors(), isolate), num_descriptors,
9145 51215 : attrs_to_add);
9146 : Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9147 : isolate);
9148 : Handle<Map> new_map = CopyReplaceDescriptors(
9149 : map, new_desc, new_layout_descriptor, INSERT_TRANSITION,
9150 51215 : transition_marker, reason, SPECIAL_TRANSITION);
9151 : new_map->set_is_extensible(false);
9152 51215 : if (!IsFixedTypedArrayElementsKind(map->elements_kind())) {
9153 : ElementsKind new_kind = IsStringWrapperElementsKind(map->elements_kind())
9154 : ? SLOW_STRING_WRAPPER_ELEMENTS
9155 51141 : : DICTIONARY_ELEMENTS;
9156 : new_map->set_elements_kind(new_kind);
9157 : }
9158 51215 : return new_map;
9159 : }
9160 :
9161 : namespace {
9162 :
9163 25271041 : bool CanHoldValue(DescriptorArray* descriptors, int descriptor,
9164 : PropertyConstness constness, Object* value) {
9165 25271041 : PropertyDetails details = descriptors->GetDetails(descriptor);
9166 25271043 : if (details.location() == kField) {
9167 24695253 : if (details.kind() == kData) {
9168 24695251 : return IsGeneralizableTo(constness, details.constness()) &&
9169 73630093 : value->FitsRepresentation(details.representation()) &&
9170 48934838 : descriptors->GetFieldType(descriptor)->NowContains(value);
9171 : } else {
9172 : DCHECK_EQ(kAccessor, details.kind());
9173 : return false;
9174 : }
9175 :
9176 : } else {
9177 : DCHECK_EQ(kDescriptor, details.location());
9178 : DCHECK_EQ(kConst, details.constness());
9179 575790 : if (details.kind() == kData) {
9180 : DCHECK(!FLAG_track_constant_fields);
9181 : DCHECK(descriptors->GetValue(descriptor) != value ||
9182 : value->FitsRepresentation(details.representation()));
9183 575790 : return descriptors->GetValue(descriptor) == value;
9184 : } else {
9185 : DCHECK_EQ(kAccessor, details.kind());
9186 : return false;
9187 : }
9188 : }
9189 : UNREACHABLE();
9190 : return false;
9191 : }
9192 :
9193 25271041 : Handle<Map> UpdateDescriptorForValue(Handle<Map> map, int descriptor,
9194 : PropertyConstness constness,
9195 : Handle<Object> value) {
9196 25271041 : if (CanHoldValue(map->instance_descriptors(), descriptor, constness,
9197 : *value)) {
9198 24114477 : return map;
9199 : }
9200 :
9201 : Isolate* isolate = map->GetIsolate();
9202 : PropertyAttributes attributes =
9203 2313132 : map->instance_descriptors()->GetDetails(descriptor).attributes();
9204 1156566 : Representation representation = value->OptimalRepresentation();
9205 1156566 : Handle<FieldType> type = value->OptimalType(isolate, representation);
9206 :
9207 1156566 : MapUpdater mu(isolate, map);
9208 : return mu.ReconfigureToDataField(descriptor, attributes, constness,
9209 1156566 : representation, type);
9210 : }
9211 :
9212 : } // namespace
9213 :
9214 : // static
9215 10661007 : Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor,
9216 : PropertyConstness constness,
9217 : Handle<Object> value) {
9218 : // Dictionaries can store any property value.
9219 : DCHECK(!map->is_dictionary_map());
9220 : // Update to the newest map before storing the property.
9221 10661007 : return UpdateDescriptorForValue(Update(map), descriptor, constness, value);
9222 : }
9223 :
9224 30201648 : Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
9225 : Handle<Object> value,
9226 : PropertyAttributes attributes,
9227 : PropertyConstness constness,
9228 : StoreFromKeyed store_mode) {
9229 : RuntimeCallTimerScope stats_scope(
9230 : *map, map->is_prototype_map()
9231 : ? &RuntimeCallStats::PrototypeMap_TransitionToDataProperty
9232 30201648 : : &RuntimeCallStats::Map_TransitionToDataProperty);
9233 :
9234 : DCHECK(name->IsUniqueName());
9235 : DCHECK(!map->is_dictionary_map());
9236 :
9237 : // Migrate to the newest map before storing the property.
9238 30201664 : map = Update(map);
9239 :
9240 : Map* maybe_transition =
9241 30201663 : TransitionArray::SearchTransition(*map, kData, *name, attributes);
9242 30201661 : if (maybe_transition != NULL) {
9243 : Handle<Map> transition(maybe_transition);
9244 : int descriptor = transition->LastAdded();
9245 :
9246 : DCHECK_EQ(attributes, transition->instance_descriptors()
9247 : ->GetDetails(descriptor)
9248 : .attributes());
9249 :
9250 14610033 : return UpdateDescriptorForValue(transition, descriptor, constness, value);
9251 : }
9252 :
9253 : TransitionFlag flag = INSERT_TRANSITION;
9254 : MaybeHandle<Map> maybe_map;
9255 15591629 : if (!FLAG_track_constant_fields && value->IsJSFunction()) {
9256 6722361 : maybe_map = Map::CopyWithConstant(map, name, value, attributes, flag);
9257 8869268 : } else if (!map->TooManyFastProperties(store_mode)) {
9258 : Isolate* isolate = name->GetIsolate();
9259 8768176 : Representation representation = value->OptimalRepresentation();
9260 8768176 : Handle<FieldType> type = value->OptimalType(isolate, representation);
9261 : maybe_map = Map::CopyWithField(map, name, type, attributes, constness,
9262 8768176 : representation, flag);
9263 : }
9264 :
9265 : Handle<Map> result;
9266 15591626 : if (!maybe_map.ToHandle(&result)) {
9267 : Isolate* isolate = name->GetIsolate();
9268 : const char* reason = "TooManyFastProperties";
9269 : #if TRACE_MAPS
9270 : std::unique_ptr<ScopedVector<char>> buffer;
9271 : if (FLAG_trace_maps) {
9272 : ScopedVector<char> name_buffer(100);
9273 : name->NameShortPrint(name_buffer);
9274 : buffer.reset(new ScopedVector<char>(128));
9275 : SNPrintF(*buffer, "TooManyFastProperties %s", name_buffer.start());
9276 : reason = buffer->start();
9277 : }
9278 : #endif
9279 101209 : Handle<Object> maybe_constructor(map->GetConstructor(), isolate);
9280 101209 : if (FLAG_feedback_normalization && map->new_target_is_base() &&
9281 101209 : maybe_constructor->IsJSFunction() &&
9282 : !JSFunction::cast(*maybe_constructor)->shared()->native()) {
9283 : Handle<JSFunction> constructor =
9284 : Handle<JSFunction>::cast(maybe_constructor);
9285 : DCHECK_NE(*constructor,
9286 : constructor->context()->native_context()->object_function());
9287 : Handle<Map> initial_map(constructor->initial_map(), isolate);
9288 0 : result = Map::Normalize(initial_map, CLEAR_INOBJECT_PROPERTIES, reason);
9289 0 : initial_map->DeprecateTransitionTree();
9290 : Handle<Object> prototype(result->prototype(), isolate);
9291 0 : JSFunction::SetInitialMap(constructor, result, prototype);
9292 :
9293 : // Deoptimize all code that embeds the previous initial map.
9294 : initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
9295 0 : isolate, DependentCode::kInitialMapChangedGroup);
9296 0 : if (!result->EquivalentToForNormalization(*map,
9297 0 : CLEAR_INOBJECT_PROPERTIES)) {
9298 0 : result = Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, reason);
9299 : }
9300 : } else {
9301 101209 : result = Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, reason);
9302 : }
9303 : }
9304 :
9305 15591626 : return result;
9306 : }
9307 :
9308 :
9309 1515963 : Handle<Map> Map::ReconfigureExistingProperty(Handle<Map> map, int descriptor,
9310 : PropertyKind kind,
9311 : PropertyAttributes attributes) {
9312 : // Dictionaries have to be reconfigured in-place.
9313 : DCHECK(!map->is_dictionary_map());
9314 :
9315 3031927 : if (!map->GetBackPointer()->IsMap()) {
9316 : // There is no benefit from reconstructing transition tree for maps without
9317 : // back pointers.
9318 : return CopyGeneralizeAllFields(map, map->elements_kind(), descriptor, kind,
9319 : attributes,
9320 1490691 : "GenAll_AttributesMismatchProtoMap");
9321 : }
9322 :
9323 25273 : if (FLAG_trace_generalization) {
9324 0 : map->PrintReconfiguration(stdout, descriptor, kind, attributes);
9325 : }
9326 :
9327 : Isolate* isolate = map->GetIsolate();
9328 :
9329 25273 : MapUpdater mu(isolate, map);
9330 : DCHECK_EQ(kData, kind); // Only kData case is supported so far.
9331 : Handle<Map> new_map = mu.ReconfigureToDataField(
9332 : descriptor, attributes, kDefaultFieldConstness, Representation::None(),
9333 25273 : FieldType::None(isolate));
9334 25273 : return new_map;
9335 : }
9336 :
9337 434921 : Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map,
9338 : Handle<Name> name, int descriptor,
9339 : Handle<Object> getter,
9340 : Handle<Object> setter,
9341 : PropertyAttributes attributes) {
9342 : RuntimeCallTimerScope stats_scope(
9343 : isolate,
9344 : map->is_prototype_map()
9345 : ? &RuntimeCallStats::PrototypeMap_TransitionToAccessorProperty
9346 434921 : : &RuntimeCallStats::Map_TransitionToAccessorProperty);
9347 :
9348 : // At least one of the accessors needs to be a new value.
9349 : DCHECK(!getter->IsNull(isolate) || !setter->IsNull(isolate));
9350 : DCHECK(name->IsUniqueName());
9351 :
9352 : // Dictionary maps can always have additional data properties.
9353 434921 : if (map->is_dictionary_map()) return map;
9354 :
9355 : // Migrate to the newest map before transitioning to the new property.
9356 434921 : map = Update(map);
9357 :
9358 : PropertyNormalizationMode mode = map->is_prototype_map()
9359 : ? KEEP_INOBJECT_PROPERTIES
9360 434921 : : CLEAR_INOBJECT_PROPERTIES;
9361 :
9362 : Map* maybe_transition =
9363 434921 : TransitionArray::SearchTransition(*map, kAccessor, *name, attributes);
9364 434921 : if (maybe_transition != NULL) {
9365 : Handle<Map> transition(maybe_transition, isolate);
9366 : DescriptorArray* descriptors = transition->instance_descriptors();
9367 : int descriptor = transition->LastAdded();
9368 : DCHECK(descriptors->GetKey(descriptor)->Equals(*name));
9369 :
9370 : DCHECK_EQ(kAccessor, descriptors->GetDetails(descriptor).kind());
9371 : DCHECK_EQ(attributes, descriptors->GetDetails(descriptor).attributes());
9372 :
9373 : Handle<Object> maybe_pair(descriptors->GetValue(descriptor), isolate);
9374 18809 : if (!maybe_pair->IsAccessorPair()) {
9375 0 : return Map::Normalize(map, mode, "TransitionToAccessorFromNonPair");
9376 : }
9377 :
9378 : Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair);
9379 18809 : if (!pair->Equals(*getter, *setter)) {
9380 17908 : return Map::Normalize(map, mode, "TransitionToDifferentAccessor");
9381 : }
9382 :
9383 901 : return transition;
9384 : }
9385 :
9386 : Handle<AccessorPair> pair;
9387 : DescriptorArray* old_descriptors = map->instance_descriptors();
9388 416112 : if (descriptor != DescriptorArray::kNotFound) {
9389 158119 : if (descriptor != map->LastAdded()) {
9390 3251 : return Map::Normalize(map, mode, "AccessorsOverwritingNonLast");
9391 : }
9392 154868 : PropertyDetails old_details = old_descriptors->GetDetails(descriptor);
9393 154868 : if (old_details.kind() != kAccessor) {
9394 152339 : return Map::Normalize(map, mode, "AccessorsOverwritingNonAccessors");
9395 : }
9396 :
9397 2529 : if (old_details.attributes() != attributes) {
9398 131 : return Map::Normalize(map, mode, "AccessorsWithAttributes");
9399 : }
9400 :
9401 : Handle<Object> maybe_pair(old_descriptors->GetValue(descriptor), isolate);
9402 2398 : if (!maybe_pair->IsAccessorPair()) {
9403 28 : return Map::Normalize(map, mode, "AccessorsOverwritingNonPair");
9404 : }
9405 :
9406 : Handle<AccessorPair> current_pair = Handle<AccessorPair>::cast(maybe_pair);
9407 2370 : if (current_pair->Equals(*getter, *setter)) return map;
9408 :
9409 : bool overwriting_accessor = false;
9410 4733 : if (!getter->IsNull(isolate) &&
9411 4589 : !current_pair->get(ACCESSOR_GETTER)->IsNull(isolate) &&
9412 : current_pair->get(ACCESSOR_GETTER) != *getter) {
9413 : overwriting_accessor = true;
9414 : }
9415 4726 : if (!setter->IsNull(isolate) &&
9416 4185 : !current_pair->get(ACCESSOR_SETTER)->IsNull(isolate) &&
9417 : current_pair->get(ACCESSOR_SETTER) != *setter) {
9418 : overwriting_accessor = true;
9419 : }
9420 2370 : if (overwriting_accessor) {
9421 2094 : return Map::Normalize(map, mode, "AccessorsOverwritingAccessors");
9422 : }
9423 :
9424 276 : pair = AccessorPair::Copy(Handle<AccessorPair>::cast(maybe_pair));
9425 515987 : } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors ||
9426 257993 : map->TooManyFastProperties(CERTAINLY_NOT_STORE_FROM_KEYED)) {
9427 0 : return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, "TooManyAccessors");
9428 : } else {
9429 257994 : pair = isolate->factory()->NewAccessorPair();
9430 : }
9431 :
9432 258270 : pair->SetComponents(*getter, *setter);
9433 :
9434 : TransitionFlag flag = INSERT_TRANSITION;
9435 : Descriptor d = Descriptor::AccessorConstant(name, pair, attributes);
9436 258270 : return Map::CopyInsertDescriptor(map, &d, flag);
9437 : }
9438 :
9439 :
9440 15763576 : Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
9441 : Descriptor* descriptor,
9442 : TransitionFlag flag) {
9443 : Handle<DescriptorArray> descriptors(map->instance_descriptors());
9444 :
9445 : // Share descriptors only if map owns descriptors and it not an initial map.
9446 47205515 : if (flag == INSERT_TRANSITION && map->owns_descriptors() &&
9447 40972154 : !map->GetBackPointer()->IsUndefined(map->GetIsolate()) &&
9448 9529932 : TransitionArray::CanHaveMoreTransitions(map)) {
9449 9529932 : return ShareDescriptor(map, descriptors, descriptor);
9450 : }
9451 :
9452 : int nof = map->NumberOfOwnDescriptors();
9453 : Handle<DescriptorArray> new_descriptors =
9454 : DescriptorArray::CopyUpTo(descriptors, nof, 1);
9455 6233650 : new_descriptors->Append(descriptor);
9456 :
9457 : Handle<LayoutDescriptor> new_layout_descriptor =
9458 : FLAG_unbox_double_fields
9459 6233649 : ? LayoutDescriptor::New(map, new_descriptors, nof + 1)
9460 6233649 : : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
9461 :
9462 : return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9463 : flag, descriptor->GetKey(), "CopyAddDescriptor",
9464 6233649 : SIMPLE_PROPERTY_TRANSITION);
9465 : }
9466 :
9467 :
9468 258318 : Handle<Map> Map::CopyInsertDescriptor(Handle<Map> map,
9469 : Descriptor* descriptor,
9470 : TransitionFlag flag) {
9471 : Handle<DescriptorArray> old_descriptors(map->instance_descriptors());
9472 :
9473 : // We replace the key if it is already present.
9474 : int index = old_descriptors->SearchWithCache(map->GetIsolate(),
9475 : *descriptor->GetKey(), *map);
9476 258318 : if (index != DescriptorArray::kNotFound) {
9477 276 : return CopyReplaceDescriptor(map, old_descriptors, descriptor, index, flag);
9478 : }
9479 258042 : return CopyAddDescriptor(map, descriptor, flag);
9480 : }
9481 :
9482 :
9483 0 : Handle<DescriptorArray> DescriptorArray::CopyUpTo(
9484 : Handle<DescriptorArray> desc,
9485 : int enumeration_index,
9486 : int slack) {
9487 : return DescriptorArray::CopyUpToAddAttributes(
9488 20175803 : desc, enumeration_index, NONE, slack);
9489 : }
9490 :
9491 :
9492 20227008 : Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
9493 : Handle<DescriptorArray> desc,
9494 : int enumeration_index,
9495 : PropertyAttributes attributes,
9496 : int slack) {
9497 20227008 : if (enumeration_index + slack == 0) {
9498 : return desc->GetIsolate()->factory()->empty_descriptor_array();
9499 : }
9500 :
9501 : int size = enumeration_index;
9502 :
9503 : Handle<DescriptorArray> descriptors =
9504 18027552 : DescriptorArray::Allocate(desc->GetIsolate(), size, slack);
9505 :
9506 18027559 : if (attributes != NONE) {
9507 78469 : for (int i = 0; i < size; ++i) {
9508 : Object* value = desc->GetValue(i);
9509 : Name* key = desc->GetKey(i);
9510 78469 : PropertyDetails details = desc->GetDetails(i);
9511 : // Bulk attribute changes never affect private properties.
9512 78469 : if (!key->IsPrivate()) {
9513 : int mask = DONT_DELETE | DONT_ENUM;
9514 : // READ_ONLY is an invalid attribute for JS setters/getters.
9515 79854 : if (details.kind() != kAccessor || !value->IsAccessorPair()) {
9516 : mask |= READ_ONLY;
9517 : }
9518 : details = details.CopyAddAttributes(
9519 78413 : static_cast<PropertyAttributes>(attributes & mask));
9520 : }
9521 78469 : descriptors->Set(i, key, value, details);
9522 : }
9523 : } else {
9524 154745882 : for (int i = 0; i < size; ++i) {
9525 154745871 : descriptors->CopyFrom(i, *desc);
9526 : }
9527 : }
9528 :
9529 18125364 : if (desc->number_of_descriptors() != enumeration_index) descriptors->Sort();
9530 :
9531 18027570 : return descriptors;
9532 : }
9533 :
9534 :
9535 8613 : bool DescriptorArray::IsEqualUpTo(DescriptorArray* desc, int nof_descriptors) {
9536 56593 : for (int i = 0; i < nof_descriptors; i++) {
9537 95960 : if (GetKey(i) != desc->GetKey(i) || GetValue(i) != desc->GetValue(i)) {
9538 : return false;
9539 : }
9540 47980 : PropertyDetails details = GetDetails(i);
9541 47980 : PropertyDetails other_details = desc->GetDetails(i);
9542 95960 : if (details.kind() != other_details.kind() ||
9543 95960 : details.location() != other_details.location() ||
9544 : !details.representation().Equals(other_details.representation())) {
9545 : return false;
9546 : }
9547 : }
9548 : return true;
9549 : }
9550 :
9551 :
9552 276 : Handle<Map> Map::CopyReplaceDescriptor(Handle<Map> map,
9553 : Handle<DescriptorArray> descriptors,
9554 : Descriptor* descriptor,
9555 : int insertion_index,
9556 : TransitionFlag flag) {
9557 : Handle<Name> key = descriptor->GetKey();
9558 : DCHECK(*key == descriptors->GetKey(insertion_index));
9559 :
9560 : Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
9561 : descriptors, map->NumberOfOwnDescriptors());
9562 :
9563 276 : new_descriptors->Replace(insertion_index, descriptor);
9564 : Handle<LayoutDescriptor> new_layout_descriptor = LayoutDescriptor::New(
9565 276 : map, new_descriptors, new_descriptors->number_of_descriptors());
9566 :
9567 : SimpleTransitionFlag simple_flag =
9568 276 : (insertion_index == descriptors->number_of_descriptors() - 1)
9569 : ? SIMPLE_PROPERTY_TRANSITION
9570 276 : : PROPERTY_TRANSITION;
9571 : return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9572 : flag, key, "CopyReplaceDescriptor",
9573 276 : simple_flag);
9574 : }
9575 :
9576 : // Helper class to manage a Map's code cache. The layout depends on the number
9577 : // of entries; this is worthwhile because most code caches are very small,
9578 : // but some are huge (thousands of entries).
9579 : // For zero entries, the EmptyFixedArray is used.
9580 : // For one entry, we use a 2-element FixedArray containing [name, code].
9581 : // For 2..100 entries, we use a FixedArray with linear lookups, the layout is:
9582 : // [0] - number of slots that are currently in use
9583 : // [1] - first name
9584 : // [2] - first code
9585 : // [3] - second name
9586 : // [4] - second code
9587 : // etc.
9588 : // For more than 128 entries, we use a CodeCacheHashTable.
9589 : class CodeCache : public AllStatic {
9590 : public:
9591 : // Returns the new cache, to be stored on the map.
9592 39748 : static Handle<FixedArray> Put(Isolate* isolate, Handle<FixedArray> cache,
9593 : Handle<Name> name, Handle<Code> code) {
9594 : int length = cache->length();
9595 39748 : if (length == 0) return PutFirstElement(isolate, name, code);
9596 2387 : if (length == kEntrySize) {
9597 577 : return PutSecondElement(isolate, cache, name, code);
9598 : }
9599 1810 : if (length <= kLinearMaxSize) {
9600 1663 : Handle<FixedArray> result = PutLinearElement(isolate, cache, name, code);
9601 1663 : if (!result.is_null()) return result;
9602 : // Fall through if linear storage is getting too large.
9603 : }
9604 154 : return PutHashTableElement(isolate, cache, name, code);
9605 : }
9606 :
9607 43599 : static Code* Lookup(FixedArray* cache, Name* name, Code::Flags flags) {
9608 : int length = cache->length();
9609 43599 : if (length == 0) return nullptr;
9610 6245 : if (length == kEntrySize) return OneElementLookup(cache, name, flags);
9611 3701 : if (!cache->IsCodeCacheHashTable()) {
9612 2490 : return LinearLookup(cache, name, flags);
9613 : } else {
9614 1211 : return CodeCacheHashTable::cast(cache)->Lookup(name, flags);
9615 : }
9616 : }
9617 :
9618 : private:
9619 : static const int kNameIndex = 0;
9620 : static const int kCodeIndex = 1;
9621 : static const int kEntrySize = 2;
9622 :
9623 : static const int kLinearUsageIndex = 0;
9624 : static const int kLinearReservedSlots = 1;
9625 : static const int kLinearInitialCapacity = 2;
9626 : static const int kLinearMaxSize = 257; // == LinearSizeFor(128);
9627 :
9628 : static const int kHashTableInitialCapacity = 200; // Number of entries.
9629 :
9630 : static int LinearSizeFor(int entries) {
9631 164 : return kLinearReservedSlots + kEntrySize * entries;
9632 : }
9633 :
9634 : static int LinearNewSize(int old_size) {
9635 164 : int old_entries = (old_size - kLinearReservedSlots) / kEntrySize;
9636 164 : return LinearSizeFor(old_entries * 2);
9637 : }
9638 :
9639 2544 : static Code* OneElementLookup(FixedArray* cache, Name* name,
9640 : Code::Flags flags) {
9641 : DCHECK_EQ(cache->length(), kEntrySize);
9642 2544 : if (cache->get(kNameIndex) != name) return nullptr;
9643 : Code* maybe_code = Code::cast(cache->get(kCodeIndex));
9644 2241 : if (maybe_code->flags() != flags) return nullptr;
9645 2194 : return maybe_code;
9646 : }
9647 :
9648 2490 : static Code* LinearLookup(FixedArray* cache, Name* name, Code::Flags flags) {
9649 : DCHECK_GE(cache->length(), kEntrySize);
9650 : DCHECK(!cache->IsCodeCacheHashTable());
9651 : int usage = GetLinearUsage(cache);
9652 59584 : for (int i = kLinearReservedSlots; i < usage; i += kEntrySize) {
9653 59544 : if (cache->get(i + kNameIndex) != name) continue;
9654 2501 : Code* code = Code::cast(cache->get(i + kCodeIndex));
9655 2501 : if (code->flags() == flags) return code;
9656 : }
9657 : return nullptr;
9658 : }
9659 :
9660 37361 : static Handle<FixedArray> PutFirstElement(Isolate* isolate, Handle<Name> name,
9661 : Handle<Code> code) {
9662 37361 : Handle<FixedArray> cache = isolate->factory()->NewFixedArray(kEntrySize);
9663 37361 : cache->set(kNameIndex, *name);
9664 37361 : cache->set(kCodeIndex, *code);
9665 37361 : return cache;
9666 : }
9667 :
9668 577 : static Handle<FixedArray> PutSecondElement(Isolate* isolate,
9669 : Handle<FixedArray> cache,
9670 : Handle<Name> name,
9671 : Handle<Code> code) {
9672 : DCHECK_EQ(cache->length(), kEntrySize);
9673 : Handle<FixedArray> new_cache = isolate->factory()->NewFixedArray(
9674 577 : LinearSizeFor(kLinearInitialCapacity));
9675 577 : new_cache->set(kLinearReservedSlots + kNameIndex, cache->get(kNameIndex));
9676 577 : new_cache->set(kLinearReservedSlots + kCodeIndex, cache->get(kCodeIndex));
9677 577 : new_cache->set(LinearSizeFor(1) + kNameIndex, *name);
9678 577 : new_cache->set(LinearSizeFor(1) + kCodeIndex, *code);
9679 : new_cache->set(kLinearUsageIndex, Smi::FromInt(LinearSizeFor(2)));
9680 577 : return new_cache;
9681 : }
9682 :
9683 1663 : static Handle<FixedArray> PutLinearElement(Isolate* isolate,
9684 : Handle<FixedArray> cache,
9685 : Handle<Name> name,
9686 : Handle<Code> code) {
9687 : int length = cache->length();
9688 : int usage = GetLinearUsage(*cache);
9689 : DCHECK_LE(usage, length);
9690 : // Check if we need to grow.
9691 1663 : if (usage == length) {
9692 : int new_length = LinearNewSize(length);
9693 164 : if (new_length > kLinearMaxSize) return Handle<FixedArray>::null();
9694 : Handle<FixedArray> new_cache =
9695 157 : isolate->factory()->NewFixedArray(new_length);
9696 3841 : for (int i = kLinearReservedSlots; i < length; i++) {
9697 3684 : new_cache->set(i, cache->get(i));
9698 : }
9699 157 : cache = new_cache;
9700 : }
9701 : // Store new entry.
9702 : DCHECK_GE(cache->length(), usage + kEntrySize);
9703 1656 : cache->set(usage + kNameIndex, *name);
9704 3312 : cache->set(usage + kCodeIndex, *code);
9705 1656 : cache->set(kLinearUsageIndex, Smi::FromInt(usage + kEntrySize));
9706 1656 : return cache;
9707 : }
9708 :
9709 154 : static Handle<FixedArray> PutHashTableElement(Isolate* isolate,
9710 : Handle<FixedArray> cache,
9711 : Handle<Name> name,
9712 : Handle<Code> code) {
9713 : // Check if we need to transition from linear to hash table storage.
9714 154 : if (!cache->IsCodeCacheHashTable()) {
9715 : // Check that the initial hash table capacity is large enough.
9716 : DCHECK_EQ(kLinearMaxSize, LinearSizeFor(128));
9717 : STATIC_ASSERT(kHashTableInitialCapacity > 128);
9718 :
9719 : int length = cache->length();
9720 : // Only migrate from linear storage when it's full.
9721 : DCHECK_EQ(length, GetLinearUsage(*cache));
9722 : DCHECK_EQ(length, kLinearMaxSize);
9723 : Handle<CodeCacheHashTable> table =
9724 7 : CodeCacheHashTable::New(isolate, kHashTableInitialCapacity);
9725 : HandleScope scope(isolate);
9726 903 : for (int i = kLinearReservedSlots; i < length; i += kEntrySize) {
9727 : Handle<Name> old_name(Name::cast(cache->get(i + kNameIndex)), isolate);
9728 896 : Handle<Code> old_code(Code::cast(cache->get(i + kCodeIndex)), isolate);
9729 896 : CodeCacheHashTable::Put(table, old_name, old_code);
9730 : }
9731 : cache = table;
9732 : }
9733 : // Store new entry.
9734 : DCHECK(cache->IsCodeCacheHashTable());
9735 : return CodeCacheHashTable::Put(Handle<CodeCacheHashTable>::cast(cache),
9736 154 : name, code);
9737 : }
9738 :
9739 : static inline int GetLinearUsage(FixedArray* linear_cache) {
9740 : DCHECK_GT(linear_cache->length(), kEntrySize);
9741 : return Smi::cast(linear_cache->get(kLinearUsageIndex))->value();
9742 : }
9743 : };
9744 :
9745 39748 : void Map::UpdateCodeCache(Handle<Map> map,
9746 : Handle<Name> name,
9747 : Handle<Code> code) {
9748 : Isolate* isolate = map->GetIsolate();
9749 : Handle<FixedArray> cache(map->code_cache(), isolate);
9750 39748 : Handle<FixedArray> new_cache = CodeCache::Put(isolate, cache, name, code);
9751 39748 : map->set_code_cache(*new_cache);
9752 39748 : }
9753 :
9754 43599 : Code* Map::LookupInCodeCache(Name* name, Code::Flags flags) {
9755 43599 : return CodeCache::Lookup(code_cache(), name, flags);
9756 : }
9757 :
9758 :
9759 : // The key in the code cache hash table consists of the property name and the
9760 : // code object. The actual match is on the name and the code flags. If a key
9761 : // is created using the flags and not a code object it can only be used for
9762 : // lookup not to create a new entry.
9763 0 : class CodeCacheHashTableKey : public HashTableKey {
9764 : public:
9765 : CodeCacheHashTableKey(Handle<Name> name, Code::Flags flags)
9766 1211 : : name_(name), flags_(flags), code_() {
9767 : DCHECK(name_->IsUniqueName());
9768 : }
9769 :
9770 : CodeCacheHashTableKey(Handle<Name> name, Handle<Code> code)
9771 2100 : : name_(name), flags_(code->flags()), code_(code) {
9772 : DCHECK(name_->IsUniqueName());
9773 : }
9774 :
9775 1673 : bool IsMatch(Object* other) override {
9776 : DCHECK(other->IsFixedArray());
9777 : FixedArray* pair = FixedArray::cast(other);
9778 : Name* name = Name::cast(pair->get(0));
9779 : Code::Flags flags = Code::cast(pair->get(1))->flags();
9780 1673 : if (flags != flags_) return false;
9781 : DCHECK(name->IsUniqueName());
9782 1673 : return *name_ == name;
9783 : }
9784 :
9785 : static uint32_t NameFlagsHashHelper(Name* name, Code::Flags flags) {
9786 2261 : return name->Hash() ^ flags;
9787 : }
9788 :
9789 4522 : uint32_t Hash() override { return NameFlagsHashHelper(*name_, flags_); }
9790 :
9791 0 : uint32_t HashForObject(Object* obj) override {
9792 : FixedArray* pair = FixedArray::cast(obj);
9793 : Name* name = Name::cast(pair->get(0));
9794 : Code* code = Code::cast(pair->get(1));
9795 0 : return NameFlagsHashHelper(name, code->flags());
9796 : }
9797 :
9798 1050 : MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) override {
9799 : Handle<Code> code = code_.ToHandleChecked();
9800 1050 : Handle<FixedArray> pair = isolate->factory()->NewFixedArray(2);
9801 1050 : pair->set(0, *name_);
9802 1050 : pair->set(1, *code);
9803 1050 : return pair;
9804 : }
9805 :
9806 : private:
9807 : Handle<Name> name_;
9808 : Code::Flags flags_;
9809 : // TODO(jkummerow): We should be able to get by without this.
9810 : MaybeHandle<Code> code_;
9811 : };
9812 :
9813 :
9814 1050 : Handle<CodeCacheHashTable> CodeCacheHashTable::Put(
9815 : Handle<CodeCacheHashTable> cache, Handle<Name> name, Handle<Code> code) {
9816 : CodeCacheHashTableKey key(name, code);
9817 :
9818 1050 : Handle<CodeCacheHashTable> new_cache = EnsureCapacity(cache, 1, &key);
9819 :
9820 2100 : int entry = new_cache->FindInsertionEntry(key.Hash());
9821 1050 : Handle<Object> k = key.AsHandle(cache->GetIsolate());
9822 :
9823 1050 : new_cache->set(EntryToIndex(entry), *k);
9824 1050 : new_cache->ElementAdded();
9825 1050 : return new_cache;
9826 : }
9827 :
9828 1211 : Code* CodeCacheHashTable::Lookup(Name* name, Code::Flags flags) {
9829 : DisallowHeapAllocation no_alloc;
9830 : CodeCacheHashTableKey key(handle(name), flags);
9831 : int entry = FindEntry(&key);
9832 1211 : if (entry == kNotFound) return nullptr;
9833 1204 : return Code::cast(FixedArray::cast(get(EntryToIndex(entry)))->get(1));
9834 : }
9835 :
9836 10508796 : Handle<FixedArray> FixedArray::SetAndGrow(Handle<FixedArray> array, int index,
9837 : Handle<Object> value) {
9838 10508796 : if (index < array->length()) {
9839 9939006 : array->set(index, *value);
9840 9939011 : return array;
9841 : }
9842 : int capacity = array->length();
9843 569790 : do {
9844 1139580 : capacity = JSObject::NewElementsCapacity(capacity);
9845 : } while (capacity <= index);
9846 : Handle<FixedArray> new_array =
9847 569790 : array->GetIsolate()->factory()->NewUninitializedFixedArray(capacity);
9848 569790 : array->CopyTo(0, *new_array, 0, array->length());
9849 569790 : new_array->FillWithHoles(array->length(), new_array->length());
9850 569790 : new_array->set(index, *value);
9851 569790 : return new_array;
9852 : }
9853 :
9854 12882925 : void FixedArray::Shrink(int new_length) {
9855 : DCHECK(0 <= new_length && new_length <= length());
9856 12882925 : if (new_length < length()) {
9857 21161162 : GetHeap()->RightTrimFixedArray(this, length() - new_length);
9858 : }
9859 12882925 : }
9860 :
9861 619376 : void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos,
9862 : int len) const {
9863 : DisallowHeapAllocation no_gc;
9864 619376 : WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
9865 27222669 : for (int index = 0; index < len; index++) {
9866 53206564 : dest->set(dest_pos+index, get(pos+index), mode);
9867 : }
9868 619387 : }
9869 :
9870 : #ifdef DEBUG
9871 : bool FixedArray::IsEqualTo(FixedArray* other) {
9872 : if (length() != other->length()) return false;
9873 : for (int i = 0 ; i < length(); ++i) {
9874 : if (get(i) != other->get(i)) return false;
9875 : }
9876 : return true;
9877 : }
9878 : #endif
9879 :
9880 :
9881 : // static
9882 13257250 : void WeakFixedArray::Set(Handle<WeakFixedArray> array, int index,
9883 : Handle<HeapObject> value) {
9884 : DCHECK(array->IsEmptySlot(index)); // Don't overwrite anything.
9885 : Handle<WeakCell> cell =
9886 : value->IsMap() ? Map::WeakCellForMap(Handle<Map>::cast(value))
9887 26015352 : : array->GetIsolate()->factory()->NewWeakCell(value);
9888 26514496 : Handle<FixedArray>::cast(array)->set(index + kFirstIndex, *cell);
9889 13257244 : if (FLAG_trace_weak_arrays) {
9890 0 : PrintF("[WeakFixedArray: storing at index %d ]\n", index);
9891 : }
9892 : array->set_last_used_index(index);
9893 13257244 : }
9894 :
9895 :
9896 : // static
9897 13257234 : Handle<WeakFixedArray> WeakFixedArray::Add(Handle<Object> maybe_array,
9898 : Handle<HeapObject> value,
9899 : int* assigned_index) {
9900 : Handle<WeakFixedArray> array =
9901 13257243 : (maybe_array.is_null() || !maybe_array->IsWeakFixedArray())
9902 : ? Allocate(value->GetIsolate(), 1, Handle<WeakFixedArray>::null())
9903 13353593 : : Handle<WeakFixedArray>::cast(maybe_array);
9904 : // Try to store the new entry if there's room. Optimize for consecutive
9905 : // accesses.
9906 : int first_index = array->last_used_index();
9907 : int length = array->Length();
9908 13257253 : if (length > 0) {
9909 : for (int i = first_index;;) {
9910 57574811 : if (array->IsEmptySlot((i))) {
9911 13069700 : WeakFixedArray::Set(array, i, value);
9912 13069696 : if (assigned_index != NULL) *assigned_index = i;
9913 13069696 : return array;
9914 : }
9915 44505111 : if (FLAG_trace_weak_arrays) {
9916 0 : PrintF("[WeakFixedArray: searching for free slot]\n");
9917 : }
9918 44505110 : i = (i + 1) % length;
9919 44505110 : if (i == first_index) break;
9920 : }
9921 : }
9922 :
9923 : // No usable slot found, grow the array.
9924 187550 : int new_length = length == 0 ? 1 : length + (length >> 1) + 4;
9925 : Handle<WeakFixedArray> new_array =
9926 187550 : Allocate(array->GetIsolate(), new_length, array);
9927 187550 : if (FLAG_trace_weak_arrays) {
9928 0 : PrintF("[WeakFixedArray: growing to size %d ]\n", new_length);
9929 : }
9930 187550 : WeakFixedArray::Set(new_array, length, value);
9931 187550 : if (assigned_index != NULL) *assigned_index = length;
9932 187550 : return new_array;
9933 : }
9934 :
9935 :
9936 : template <class CompactionCallback>
9937 321 : void WeakFixedArray::Compact() {
9938 : FixedArray* array = FixedArray::cast(this);
9939 : int new_length = kFirstIndex;
9940 139936 : for (int i = kFirstIndex; i < array->length(); i++) {
9941 : Object* element = array->get(i);
9942 69647 : if (element->IsSmi()) continue;
9943 46681 : if (WeakCell::cast(element)->cleared()) continue;
9944 : Object* value = WeakCell::cast(element)->value();
9945 : CompactionCallback::Callback(value, i - kFirstIndex,
9946 242 : new_length - kFirstIndex);
9947 46562 : array->set(new_length++, element);
9948 : }
9949 321 : array->Shrink(new_length);
9950 : set_last_used_index(0);
9951 321 : }
9952 :
9953 :
9954 1068873 : void WeakFixedArray::Iterator::Reset(Object* maybe_array) {
9955 1068873 : if (maybe_array->IsWeakFixedArray()) {
9956 425603 : list_ = WeakFixedArray::cast(maybe_array);
9957 425603 : index_ = 0;
9958 : #ifdef DEBUG
9959 : last_used_index_ = list_->last_used_index();
9960 : #endif // DEBUG
9961 : }
9962 1068873 : }
9963 :
9964 :
9965 0 : void JSObject::PrototypeRegistryCompactionCallback::Callback(Object* value,
9966 : int old_index,
9967 : int new_index) {
9968 : DCHECK(value->IsMap() && Map::cast(value)->is_prototype_map());
9969 : Map* map = Map::cast(value);
9970 : DCHECK(map->prototype_info()->IsPrototypeInfo());
9971 : PrototypeInfo* proto_info = PrototypeInfo::cast(map->prototype_info());
9972 : DCHECK_EQ(old_index, proto_info->registry_slot());
9973 : proto_info->set_registry_slot(new_index);
9974 0 : }
9975 :
9976 :
9977 : template void WeakFixedArray::Compact<WeakFixedArray::NullCallback>();
9978 : template void
9979 : WeakFixedArray::Compact<JSObject::PrototypeRegistryCompactionCallback>();
9980 :
9981 :
9982 6239198 : bool WeakFixedArray::Remove(Handle<HeapObject> value) {
9983 6239198 : if (Length() == 0) return false;
9984 : // Optimize for the most recently added element to be removed again.
9985 : int first_index = last_used_index();
9986 : for (int i = first_index;;) {
9987 13671188 : if (Get(i) == *value) {
9988 : Clear(i);
9989 : // Users of WeakFixedArray should make sure that there are no duplicates.
9990 6239198 : return true;
9991 : }
9992 1192792 : i = (i + 1) % Length();
9993 596396 : if (i == first_index) return false;
9994 : }
9995 : UNREACHABLE();
9996 : }
9997 :
9998 :
9999 : // static
10000 283923 : Handle<WeakFixedArray> WeakFixedArray::Allocate(
10001 : Isolate* isolate, int size, Handle<WeakFixedArray> initialize_from) {
10002 : DCHECK(0 <= size);
10003 : Handle<FixedArray> result =
10004 283923 : isolate->factory()->NewUninitializedFixedArray(size + kFirstIndex);
10005 : int index = 0;
10006 283923 : if (!initialize_from.is_null()) {
10007 : DCHECK(initialize_from->Length() <= size);
10008 : Handle<FixedArray> raw_source = Handle<FixedArray>::cast(initialize_from);
10009 : // Copy the entries without compacting, since the PrototypeInfo relies on
10010 : // the index of the entries not to change.
10011 37626613 : while (index < raw_source->length()) {
10012 37439063 : result->set(index, raw_source->get(index));
10013 37439063 : index++;
10014 : }
10015 : }
10016 19836103 : while (index < result->length()) {
10017 : result->set(index, Smi::kZero);
10018 19552180 : index++;
10019 : }
10020 283923 : return Handle<WeakFixedArray>::cast(result);
10021 : }
10022 :
10023 : // static
10024 2215 : Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj,
10025 : AddMode mode) {
10026 2215 : int length = array->Length();
10027 2215 : array = EnsureSpace(array, length + 1);
10028 2215 : if (mode == kReloadLengthAfterAllocation) {
10029 : DCHECK(array->Length() <= length);
10030 0 : length = array->Length();
10031 : }
10032 : array->Set(length, *obj);
10033 : array->SetLength(length + 1);
10034 2215 : return array;
10035 : }
10036 :
10037 : // static
10038 964240 : Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj1,
10039 : Handle<Object> obj2, AddMode mode) {
10040 964240 : int length = array->Length();
10041 964240 : array = EnsureSpace(array, length + 2);
10042 964240 : if (mode == kReloadLengthAfterAllocation) {
10043 38231 : length = array->Length();
10044 : }
10045 : array->Set(length, *obj1);
10046 : array->Set(length + 1, *obj2);
10047 : array->SetLength(length + 2);
10048 964240 : return array;
10049 : }
10050 :
10051 : // static
10052 472 : Handle<ArrayList> ArrayList::New(Isolate* isolate, int size) {
10053 : Handle<ArrayList> result = Handle<ArrayList>::cast(
10054 472 : isolate->factory()->NewFixedArray(size + kFirstIndex));
10055 : result->SetLength(0);
10056 472 : return result;
10057 : }
10058 :
10059 210 : Handle<FixedArray> ArrayList::Elements() const {
10060 420 : Handle<FixedArray> result = GetIsolate()->factory()->NewFixedArray(Length());
10061 : // Do not copy the first entry, i.e., the length.
10062 420 : CopyTo(kFirstIndex, *result, 0, Length());
10063 210 : return result;
10064 : }
10065 :
10066 38231 : bool ArrayList::IsFull() {
10067 : int capacity = length();
10068 38231 : return kFirstIndex + Length() == capacity;
10069 : }
10070 :
10071 : namespace {
10072 :
10073 5994834 : Handle<FixedArray> EnsureSpaceInFixedArray(Handle<FixedArray> array,
10074 : int length) {
10075 : int capacity = array->length();
10076 5994834 : if (capacity < length) {
10077 : Isolate* isolate = array->GetIsolate();
10078 : int new_capacity = length;
10079 97978 : new_capacity = new_capacity + Max(new_capacity / 2, 2);
10080 48989 : int grow_by = new_capacity - capacity;
10081 48989 : array = isolate->factory()->CopyFixedArrayAndGrow(array, grow_by);
10082 : }
10083 5994834 : return array;
10084 : }
10085 :
10086 : } // namespace
10087 :
10088 : // static
10089 966455 : Handle<ArrayList> ArrayList::EnsureSpace(Handle<ArrayList> array, int length) {
10090 : const bool empty = (array->length() == 0);
10091 : auto ret = Handle<ArrayList>::cast(
10092 1932910 : EnsureSpaceInFixedArray(array, kFirstIndex + length));
10093 966455 : if (empty) ret->SetLength(0);
10094 966455 : return ret;
10095 : }
10096 :
10097 259838 : Handle<RegExpMatchInfo> RegExpMatchInfo::ReserveCaptures(
10098 : Handle<RegExpMatchInfo> match_info, int capture_count) {
10099 : DCHECK_GE(match_info->length(), kLastMatchOverhead);
10100 259838 : const int required_length = kFirstCaptureIndex + capture_count;
10101 : Handle<FixedArray> result =
10102 259838 : EnsureSpaceInFixedArray(match_info, required_length);
10103 259838 : return Handle<RegExpMatchInfo>::cast(result);
10104 : }
10105 :
10106 : // static
10107 4730461 : Handle<FrameArray> FrameArray::AppendJSFrame(Handle<FrameArray> in,
10108 : Handle<Object> receiver,
10109 : Handle<JSFunction> function,
10110 : Handle<AbstractCode> code,
10111 : int offset, int flags) {
10112 : const int frame_count = in->FrameCount();
10113 4730461 : const int new_length = LengthFor(frame_count + 1);
10114 : Handle<FrameArray> array = EnsureSpace(in, new_length);
10115 : array->SetReceiver(frame_count, *receiver);
10116 : array->SetFunction(frame_count, *function);
10117 : array->SetCode(frame_count, *code);
10118 : array->SetOffset(frame_count, Smi::FromInt(offset));
10119 4730461 : array->SetFlags(frame_count, Smi::FromInt(flags));
10120 : array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));
10121 4730461 : return array;
10122 : }
10123 :
10124 : // static
10125 38080 : Handle<FrameArray> FrameArray::AppendWasmFrame(Handle<FrameArray> in,
10126 : Handle<Object> wasm_instance,
10127 : int wasm_function_index,
10128 : Handle<AbstractCode> code,
10129 : int offset, int flags) {
10130 : const int frame_count = in->FrameCount();
10131 38080 : const int new_length = LengthFor(frame_count + 1);
10132 : Handle<FrameArray> array = EnsureSpace(in, new_length);
10133 : array->SetWasmInstance(frame_count, *wasm_instance);
10134 : array->SetWasmFunctionIndex(frame_count, Smi::FromInt(wasm_function_index));
10135 : // code will be a null handle for interpreted wasm frames.
10136 38080 : if (!code.is_null()) array->SetCode(frame_count, *code);
10137 : array->SetOffset(frame_count, Smi::FromInt(offset));
10138 38080 : array->SetFlags(frame_count, Smi::FromInt(flags));
10139 : array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));
10140 38080 : return array;
10141 : }
10142 :
10143 2420150 : void FrameArray::ShrinkToFit() { Shrink(LengthFor(FrameCount())); }
10144 :
10145 : // static
10146 0 : Handle<FrameArray> FrameArray::EnsureSpace(Handle<FrameArray> array,
10147 : int length) {
10148 4768541 : return Handle<FrameArray>::cast(EnsureSpaceInFixedArray(array, length));
10149 : }
10150 :
10151 18589809 : Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate,
10152 : int number_of_descriptors,
10153 : int slack,
10154 : PretenureFlag pretenure) {
10155 : DCHECK(0 <= number_of_descriptors);
10156 : Factory* factory = isolate->factory();
10157 : // Do not use DescriptorArray::cast on incomplete object.
10158 18589809 : int size = number_of_descriptors + slack;
10159 18589809 : if (size == 0) return factory->empty_descriptor_array();
10160 : // Allocate the array of keys.
10161 : Handle<FixedArray> result =
10162 18589809 : factory->NewFixedArray(LengthFor(size), pretenure);
10163 :
10164 : result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors));
10165 : result->set(kEnumCacheIndex, Smi::kZero);
10166 : return Handle<DescriptorArray>::cast(result);
10167 : }
10168 :
10169 12 : void DescriptorArray::ClearEnumCache() { set(kEnumCacheIndex, Smi::kZero); }
10170 :
10171 2497941 : void DescriptorArray::Replace(int index, Descriptor* descriptor) {
10172 : descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index));
10173 2497941 : Set(index, descriptor);
10174 2497941 : }
10175 :
10176 :
10177 : // static
10178 114947 : void DescriptorArray::SetEnumCache(Handle<DescriptorArray> descriptors,
10179 : Isolate* isolate,
10180 : Handle<FixedArray> new_cache,
10181 : Handle<FixedArray> new_index_cache) {
10182 : DCHECK(!descriptors->IsEmpty());
10183 : FixedArray* bridge_storage;
10184 114947 : bool needs_new_enum_cache = !descriptors->HasEnumCache();
10185 114947 : if (needs_new_enum_cache) {
10186 : bridge_storage = *isolate->factory()->NewFixedArray(
10187 189884 : DescriptorArray::kEnumCacheBridgeLength);
10188 : } else {
10189 : bridge_storage = FixedArray::cast(descriptors->get(kEnumCacheIndex));
10190 : }
10191 114947 : bridge_storage->set(kEnumCacheBridgeCacheIndex, *new_cache);
10192 : bridge_storage->set(
10193 : kEnumCacheBridgeIndicesCacheIndex,
10194 229894 : new_index_cache.is_null() ? Object::cast(Smi::kZero) : *new_index_cache);
10195 114947 : if (needs_new_enum_cache) {
10196 94942 : descriptors->set(kEnumCacheIndex, bridge_storage);
10197 : }
10198 114947 : }
10199 :
10200 154745872 : void DescriptorArray::CopyFrom(int index, DescriptorArray* src) {
10201 154745872 : PropertyDetails details = src->GetDetails(index);
10202 154745879 : Set(index, src->GetKey(index), src->GetValue(index), details);
10203 154745884 : }
10204 :
10205 673949 : void DescriptorArray::Sort() {
10206 : // In-place heap sort.
10207 673949 : int len = number_of_descriptors();
10208 : // Reset sorting since the descriptor array might contain invalid pointers.
10209 673949 : for (int i = 0; i < len; ++i) SetSortedKey(i, i);
10210 : // Bottom-up max-heap construction.
10211 : // Index of the last node with children
10212 673949 : const int max_parent_index = (len / 2) - 1;
10213 2379558 : for (int i = max_parent_index; i >= 0; --i) {
10214 : int parent_index = i;
10215 1705609 : const uint32_t parent_hash = GetSortedKey(i)->Hash();
10216 5025342 : while (parent_index <= max_parent_index) {
10217 2443304 : int child_index = 2 * parent_index + 1;
10218 2443304 : uint32_t child_hash = GetSortedKey(child_index)->Hash();
10219 2443304 : if (child_index + 1 < len) {
10220 2075621 : uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
10221 2075621 : if (right_child_hash > child_hash) {
10222 : child_index++;
10223 : child_hash = right_child_hash;
10224 : }
10225 : }
10226 2443304 : if (child_hash <= parent_hash) break;
10227 1614124 : SwapSortedKeys(parent_index, child_index);
10228 : // Now element at child_index could be < its children.
10229 : parent_index = child_index; // parent_hash remains correct.
10230 : }
10231 : }
10232 :
10233 : // Extract elements and create sorted array.
10234 3827504 : for (int i = len - 1; i > 0; --i) {
10235 : // Put max element at the back of the array.
10236 3153555 : SwapSortedKeys(0, i);
10237 : // Shift down the new top element.
10238 : int parent_index = 0;
10239 3153555 : const uint32_t parent_hash = GetSortedKey(parent_index)->Hash();
10240 3153555 : const int max_parent_index = (i / 2) - 1;
10241 12648488 : while (parent_index <= max_parent_index) {
10242 6813984 : int child_index = parent_index * 2 + 1;
10243 6813984 : uint32_t child_hash = GetSortedKey(child_index)->Hash();
10244 6813984 : if (child_index + 1 < i) {
10245 6150540 : uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
10246 6150540 : if (right_child_hash > child_hash) {
10247 : child_index++;
10248 : child_hash = right_child_hash;
10249 : }
10250 : }
10251 6813984 : if (child_hash <= parent_hash) break;
10252 6341378 : SwapSortedKeys(parent_index, child_index);
10253 : parent_index = child_index;
10254 : }
10255 : }
10256 : DCHECK(IsSortedNoDuplicates());
10257 673949 : }
10258 :
10259 :
10260 17523 : Handle<AccessorPair> AccessorPair::Copy(Handle<AccessorPair> pair) {
10261 17523 : Handle<AccessorPair> copy = pair->GetIsolate()->factory()->NewAccessorPair();
10262 17523 : copy->set_getter(pair->getter());
10263 17523 : copy->set_setter(pair->setter());
10264 17523 : return copy;
10265 : }
10266 :
10267 71561 : Handle<Object> AccessorPair::GetComponent(Handle<AccessorPair> accessor_pair,
10268 : AccessorComponent component) {
10269 : Object* accessor = accessor_pair->get(component);
10270 71561 : if (accessor->IsFunctionTemplateInfo()) {
10271 : return ApiNatives::InstantiateFunction(
10272 : handle(FunctionTemplateInfo::cast(accessor)))
10273 184 : .ToHandleChecked();
10274 : }
10275 : Isolate* isolate = accessor_pair->GetIsolate();
10276 71469 : if (accessor->IsNull(isolate)) {
10277 6815 : return isolate->factory()->undefined_value();
10278 : }
10279 : return handle(accessor, isolate);
10280 : }
10281 :
10282 670855 : Handle<DeoptimizationInputData> DeoptimizationInputData::New(
10283 : Isolate* isolate, int deopt_entry_count, PretenureFlag pretenure) {
10284 : return Handle<DeoptimizationInputData>::cast(
10285 : isolate->factory()->NewFixedArray(LengthFor(deopt_entry_count),
10286 670855 : pretenure));
10287 : }
10288 :
10289 :
10290 236544 : Handle<DeoptimizationOutputData> DeoptimizationOutputData::New(
10291 : Isolate* isolate,
10292 : int number_of_deopt_points,
10293 : PretenureFlag pretenure) {
10294 : Handle<FixedArray> result;
10295 236544 : if (number_of_deopt_points == 0) {
10296 : result = isolate->factory()->empty_fixed_array();
10297 : } else {
10298 : result = isolate->factory()->NewFixedArray(
10299 236544 : LengthOfFixedArray(number_of_deopt_points), pretenure);
10300 : }
10301 236544 : return Handle<DeoptimizationOutputData>::cast(result);
10302 : }
10303 :
10304 48 : SharedFunctionInfo* DeoptimizationInputData::GetInlinedFunction(int index) {
10305 48 : if (index == -1) {
10306 0 : return SharedFunctionInfo::cast(SharedFunctionInfo());
10307 : } else {
10308 48 : return SharedFunctionInfo::cast(LiteralArray()->get(index));
10309 : }
10310 : }
10311 :
10312 10643918 : int HandlerTable::LookupRange(int pc_offset, int* data_out,
10313 : CatchPrediction* prediction_out) {
10314 : int innermost_handler = -1;
10315 : #ifdef DEBUG
10316 : // Assuming that ranges are well nested, we don't need to track the innermost
10317 : // offsets. This is just to verify that the table is actually well nested.
10318 : int innermost_start = std::numeric_limits<int>::min();
10319 : int innermost_end = std::numeric_limits<int>::max();
10320 : #endif
10321 50999312 : for (int i = 0; i < length(); i += kRangeEntrySize) {
10322 : int start_offset = Smi::cast(get(i + kRangeStartIndex))->value();
10323 14855738 : int end_offset = Smi::cast(get(i + kRangeEndIndex))->value();
10324 14855738 : int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value();
10325 14855738 : int handler_offset = HandlerOffsetField::decode(handler_field);
10326 : CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
10327 14855738 : int handler_data = Smi::cast(get(i + kRangeDataIndex))->value();
10328 14855738 : if (pc_offset >= start_offset && pc_offset < end_offset) {
10329 : DCHECK_GE(start_offset, innermost_start);
10330 : DCHECK_LT(end_offset, innermost_end);
10331 : innermost_handler = handler_offset;
10332 : #ifdef DEBUG
10333 : innermost_start = start_offset;
10334 : innermost_end = end_offset;
10335 : #endif
10336 2167171 : if (data_out) *data_out = handler_data;
10337 2167171 : if (prediction_out) *prediction_out = prediction;
10338 : }
10339 : }
10340 10643918 : return innermost_handler;
10341 : }
10342 :
10343 :
10344 : // TODO(turbofan): Make sure table is sorted and use binary search.
10345 2090381 : int HandlerTable::LookupReturn(int pc_offset) {
10346 6623362 : for (int i = 0; i < length(); i += kReturnEntrySize) {
10347 : int return_offset = Smi::cast(get(i + kReturnOffsetIndex))->value();
10348 1546535 : int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value();
10349 1546535 : if (pc_offset == return_offset) {
10350 650470 : return HandlerOffsetField::decode(handler_field);
10351 : }
10352 : }
10353 : return -1;
10354 : }
10355 :
10356 :
10357 : #ifdef DEBUG
10358 : bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
10359 : if (IsEmpty()) return other->IsEmpty();
10360 : if (other->IsEmpty()) return false;
10361 : if (length() != other->length()) return false;
10362 : for (int i = 0; i < length(); ++i) {
10363 : if (get(i) != other->get(i)) return false;
10364 : }
10365 : return true;
10366 : }
10367 : #endif
10368 :
10369 : // static
10370 1838054 : Handle<String> String::Trim(Handle<String> string, TrimMode mode) {
10371 1838054 : Isolate* const isolate = string->GetIsolate();
10372 1838054 : string = String::Flatten(string);
10373 : int const length = string->length();
10374 :
10375 : // Perform left trimming if requested.
10376 : int left = 0;
10377 : UnicodeCache* unicode_cache = isolate->unicode_cache();
10378 1838054 : if (mode == kTrim || mode == kTrimLeft) {
10379 3693504 : while (left < length &&
10380 1846458 : unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) {
10381 9496 : left++;
10382 : }
10383 : }
10384 :
10385 : // Perform right trimming if requested.
10386 : int right = length;
10387 1838054 : if (mode == kTrim || mode == kTrimRight) {
10388 1838222 : while (
10389 3675856 : right > left &&
10390 3675268 : unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) {
10391 1050 : right--;
10392 : }
10393 : }
10394 :
10395 1838054 : return isolate->factory()->NewSubString(string, left, right);
10396 : }
10397 :
10398 3124610 : bool String::LooksValid() { return GetIsolate()->heap()->Contains(this); }
10399 :
10400 : // static
10401 1533845 : MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) {
10402 1533850 : if (name->IsString()) return Handle<String>::cast(name);
10403 : // ES6 section 9.2.11 SetFunctionName, step 4.
10404 : Isolate* const isolate = name->GetIsolate();
10405 : Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate);
10406 11319 : if (description->IsUndefined(isolate)) {
10407 : return isolate->factory()->empty_string();
10408 : }
10409 11193 : IncrementalStringBuilder builder(isolate);
10410 : builder.AppendCharacter('[');
10411 11193 : builder.AppendString(Handle<String>::cast(description));
10412 : builder.AppendCharacter(']');
10413 11193 : return builder.Finish();
10414 : }
10415 :
10416 : // static
10417 6814 : MaybeHandle<String> Name::ToFunctionName(Handle<Name> name,
10418 : Handle<String> prefix) {
10419 : Handle<String> name_string;
10420 : Isolate* const isolate = name->GetIsolate();
10421 13628 : ASSIGN_RETURN_ON_EXCEPTION(isolate, name_string, ToFunctionName(name),
10422 : String);
10423 6814 : IncrementalStringBuilder builder(isolate);
10424 6814 : builder.AppendString(prefix);
10425 : builder.AppendCharacter(' ');
10426 6814 : builder.AppendString(name_string);
10427 6814 : return builder.Finish();
10428 : }
10429 :
10430 : namespace {
10431 :
10432 : bool AreDigits(const uint8_t* s, int from, int to) {
10433 46568 : for (int i = from; i < to; i++) {
10434 108361 : if (s[i] < '0' || s[i] > '9') return false;
10435 : }
10436 :
10437 : return true;
10438 : }
10439 :
10440 :
10441 : int ParseDecimalInteger(const uint8_t* s, int from, int to) {
10442 : DCHECK(to - from < 10); // Overflow is not possible.
10443 : DCHECK(from < to);
10444 2619 : int d = s[from] - '0';
10445 :
10446 3198 : for (int i = from + 1; i < to; i++) {
10447 579 : d = 10 * d + (s[i] - '0');
10448 : }
10449 :
10450 : return d;
10451 : }
10452 :
10453 : } // namespace
10454 :
10455 :
10456 : // static
10457 12608721 : Handle<Object> String::ToNumber(Handle<String> subject) {
10458 2719702 : Isolate* const isolate = subject->GetIsolate();
10459 :
10460 : // Flatten {subject} string first.
10461 12608721 : subject = String::Flatten(subject);
10462 :
10463 : // Fast array index case.
10464 : uint32_t index;
10465 12608721 : if (subject->AsArrayIndex(&index)) {
10466 6002725 : return isolate->factory()->NewNumberFromUint(index);
10467 : }
10468 :
10469 : // Fast case: short integer or some sorts of junk values.
10470 6605996 : if (subject->IsSeqOneByteString()) {
10471 : int len = subject->length();
10472 4158674 : if (len == 0) return handle(Smi::kZero, isolate);
10473 :
10474 : DisallowHeapAllocation no_gc;
10475 4092236 : uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars();
10476 4092236 : bool minus = (data[0] == '-');
10477 4092236 : int start_pos = (minus ? 1 : 0);
10478 :
10479 4092236 : if (start_pos == len) {
10480 0 : return isolate->factory()->nan_value();
10481 4092236 : } else if (data[start_pos] > '9') {
10482 : // Fast check for a junk value. A valid string may start from a
10483 : // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit
10484 : // or the 'I' character ('Infinity'). All of that have codes not greater
10485 : // than '9' except 'I' and .
10486 3859879 : if (data[start_pos] != 'I' && data[start_pos] != 0xa0) {
10487 3850456 : return isolate->factory()->nan_value();
10488 : }
10489 296769 : } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
10490 : // The maximal/minimal smi has 10 digits. If the string has less digits
10491 : // we know it will fit into the smi-data type.
10492 : int d = ParseDecimalInteger(data, start_pos, len);
10493 2619 : if (minus) {
10494 2933 : if (d == 0) return isolate->factory()->minus_zero_value();
10495 2125 : d = -d;
10496 180 : } else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize &&
10497 0 : (len == 1 || data[0] != '0')) {
10498 : // String hash is not calculated yet but all the data are present.
10499 : // Update the hash field to speed up sequential convertions.
10500 0 : uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
10501 : #ifdef DEBUG
10502 : subject->Hash(); // Force hash calculation.
10503 : DCHECK_EQ(static_cast<int>(subject->hash_field()),
10504 : static_cast<int>(hash));
10505 : #endif
10506 : subject->set_hash_field(hash);
10507 : }
10508 2215 : return handle(Smi::FromInt(d), isolate);
10509 : }
10510 : }
10511 :
10512 : // Slower case.
10513 : int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY;
10514 : return isolate->factory()->NewNumber(
10515 2719702 : StringToDouble(isolate->unicode_cache(), subject, flags));
10516 : }
10517 :
10518 :
10519 125848762 : String::FlatContent String::GetFlatContent() {
10520 : DCHECK(!AllowHeapAllocation::IsAllowed());
10521 : int length = this->length();
10522 : StringShape shape(this);
10523 : String* string = this;
10524 : int offset = 0;
10525 125848762 : if (shape.representation_tag() == kConsStringTag) {
10526 : ConsString* cons = ConsString::cast(string);
10527 0 : if (cons->second()->length() != 0) {
10528 0 : return FlatContent();
10529 : }
10530 : string = cons->first();
10531 : shape = StringShape(string);
10532 125848762 : } else if (shape.representation_tag() == kSlicedStringTag) {
10533 : SlicedString* slice = SlicedString::cast(string);
10534 : offset = slice->offset();
10535 : string = slice->parent();
10536 : shape = StringShape(string);
10537 : DCHECK(shape.representation_tag() != kConsStringTag &&
10538 : shape.representation_tag() != kSlicedStringTag);
10539 : }
10540 125848762 : if (shape.representation_tag() == kThinStringTag) {
10541 : ThinString* thin = ThinString::cast(string);
10542 : string = thin->actual();
10543 : shape = StringShape(string);
10544 : DCHECK(!shape.IsCons());
10545 : DCHECK(!shape.IsSliced());
10546 : }
10547 125848762 : if (shape.encoding_tag() == kOneByteStringTag) {
10548 : const uint8_t* start;
10549 113737003 : if (shape.representation_tag() == kSeqStringTag) {
10550 113733852 : start = SeqOneByteString::cast(string)->GetChars();
10551 : } else {
10552 : start = ExternalOneByteString::cast(string)->GetChars();
10553 : }
10554 113737004 : return FlatContent(start + offset, length);
10555 : } else {
10556 : DCHECK(shape.encoding_tag() == kTwoByteStringTag);
10557 : const uc16* start;
10558 12111759 : if (shape.representation_tag() == kSeqStringTag) {
10559 12108969 : start = SeqTwoByteString::cast(string)->GetChars();
10560 : } else {
10561 : start = ExternalTwoByteString::cast(string)->GetChars();
10562 : }
10563 12111759 : return FlatContent(start + offset, length);
10564 : }
10565 : }
10566 :
10567 3735791 : std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
10568 : RobustnessFlag robust_flag,
10569 : int offset, int length,
10570 : int* length_return) {
10571 6860293 : if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
10572 : return std::unique_ptr<char[]>();
10573 : }
10574 : // Negative length means the to the end of the string.
10575 3735791 : if (length < 0) length = kMaxInt - offset;
10576 :
10577 : // Compute the size of the UTF-8 string. Start at the specified offset.
10578 : StringCharacterStream stream(this, offset);
10579 : int character_position = offset;
10580 : int utf8_bytes = 0;
10581 : int last = unibrow::Utf16::kNoPreviousCharacter;
10582 42641389 : while (stream.HasMore() && character_position++ < offset + length) {
10583 35169807 : uint16_t character = stream.GetNext();
10584 35169807 : utf8_bytes += unibrow::Utf8::Length(character, last);
10585 35169807 : last = character;
10586 : }
10587 :
10588 3735791 : if (length_return) {
10589 3085192 : *length_return = utf8_bytes;
10590 : }
10591 :
10592 3735791 : char* result = NewArray<char>(utf8_bytes + 1);
10593 :
10594 : // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
10595 3735792 : stream.Reset(this, offset);
10596 : character_position = offset;
10597 : int utf8_byte_position = 0;
10598 : last = unibrow::Utf16::kNoPreviousCharacter;
10599 42641391 : while (stream.HasMore() && character_position++ < offset + length) {
10600 35169807 : uint16_t character = stream.GetNext();
10601 35169807 : if (allow_nulls == DISALLOW_NULLS && character == 0) {
10602 : character = ' ';
10603 : }
10604 : utf8_byte_position +=
10605 35169807 : unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
10606 35169807 : last = character;
10607 : }
10608 3735791 : result[utf8_byte_position] = 0;
10609 : return std::unique_ptr<char[]>(result);
10610 : }
10611 :
10612 654987 : std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
10613 : RobustnessFlag robust_flag,
10614 : int* length_return) {
10615 654987 : return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
10616 : }
10617 :
10618 :
10619 82 : const uc16* String::GetTwoByteData(unsigned start) {
10620 : DCHECK(!IsOneByteRepresentationUnderneath());
10621 82 : switch (StringShape(this).representation_tag()) {
10622 : case kSeqStringTag:
10623 0 : return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
10624 : case kExternalStringTag:
10625 : return ExternalTwoByteString::cast(this)->
10626 82 : ExternalTwoByteStringGetData(start);
10627 : case kSlicedStringTag: {
10628 : SlicedString* slice = SlicedString::cast(this);
10629 0 : return slice->parent()->GetTwoByteData(start + slice->offset());
10630 : }
10631 : case kConsStringTag:
10632 : case kThinStringTag:
10633 0 : UNREACHABLE();
10634 : return NULL;
10635 : }
10636 0 : UNREACHABLE();
10637 : return NULL;
10638 : }
10639 :
10640 :
10641 0 : const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
10642 : return reinterpret_cast<uc16*>(
10643 0 : reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
10644 : }
10645 :
10646 :
10647 122535 : void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) {
10648 : Relocatable* current = isolate->relocatable_top();
10649 266691 : while (current != NULL) {
10650 21621 : current->PostGarbageCollection();
10651 21621 : current = current->prev_;
10652 : }
10653 122535 : }
10654 :
10655 :
10656 : // Reserve space for statics needing saving and restoring.
10657 1280 : int Relocatable::ArchiveSpacePerThread() {
10658 1280 : return sizeof(Relocatable*); // NOLINT
10659 : }
10660 :
10661 :
10662 : // Archive statics that are thread-local.
10663 22574 : char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
10664 22574 : *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
10665 : isolate->set_relocatable_top(NULL);
10666 22574 : return to + ArchiveSpacePerThread();
10667 : }
10668 :
10669 :
10670 : // Restore statics that are thread-local.
10671 22574 : char* Relocatable::RestoreState(Isolate* isolate, char* from) {
10672 22574 : isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
10673 22574 : return from + ArchiveSpacePerThread();
10674 : }
10675 :
10676 4049 : char* Relocatable::Iterate(RootVisitor* v, char* thread_storage) {
10677 4049 : Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
10678 : Iterate(v, top);
10679 4049 : return thread_storage + ArchiveSpacePerThread();
10680 : }
10681 :
10682 241585 : void Relocatable::Iterate(Isolate* isolate, RootVisitor* v) {
10683 : Iterate(v, isolate->relocatable_top());
10684 241585 : }
10685 :
10686 0 : void Relocatable::Iterate(RootVisitor* v, Relocatable* top) {
10687 : Relocatable* current = top;
10688 287607 : while (current != NULL) {
10689 41973 : current->IterateInstance(v);
10690 41973 : current = current->prev_;
10691 : }
10692 0 : }
10693 :
10694 :
10695 1492125 : FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
10696 : : Relocatable(isolate),
10697 : str_(str.location()),
10698 4476375 : length_(str->length()) {
10699 1492125 : PostGarbageCollection();
10700 1492125 : }
10701 :
10702 :
10703 3584 : FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
10704 : : Relocatable(isolate),
10705 : str_(0),
10706 : is_one_byte_(true),
10707 3584 : length_(input.length()),
10708 10752 : start_(input.start()) {}
10709 :
10710 :
10711 1492210 : void FlatStringReader::PostGarbageCollection() {
10712 1492210 : if (str_ == NULL) return;
10713 : Handle<String> str(str_);
10714 : DCHECK(str->IsFlat());
10715 : DisallowHeapAllocation no_gc;
10716 : // This does not actually prevent the vector from being relocated later.
10717 1492210 : String::FlatContent content = str->GetFlatContent();
10718 : DCHECK(content.IsFlat());
10719 2984420 : is_one_byte_ = content.IsOneByte();
10720 1492210 : if (is_one_byte_) {
10721 1352826 : start_ = content.ToOneByteVector().start();
10722 : } else {
10723 139384 : start_ = content.ToUC16Vector().start();
10724 : }
10725 : }
10726 :
10727 :
10728 60578 : void ConsStringIterator::Initialize(ConsString* cons_string, int offset) {
10729 : DCHECK(cons_string != NULL);
10730 6029272 : root_ = cons_string;
10731 6029272 : consumed_ = offset;
10732 : // Force stack blown condition to trigger restart.
10733 6029272 : depth_ = 1;
10734 6029272 : maximum_depth_ = kStackSize + depth_;
10735 : DCHECK(StackBlown());
10736 60578 : }
10737 :
10738 :
10739 75773602 : String* ConsStringIterator::Continue(int* offset_out) {
10740 : DCHECK(depth_ != 0);
10741 : DCHECK_EQ(0, *offset_out);
10742 75773602 : bool blew_stack = StackBlown();
10743 : String* string = NULL;
10744 : // Get the next leaf if there is one.
10745 75773602 : if (!blew_stack) string = NextLeaf(&blew_stack);
10746 : // Restart search from root.
10747 75773602 : if (blew_stack) {
10748 : DCHECK(string == NULL);
10749 6835546 : string = Search(offset_out);
10750 : }
10751 : // Ensure future calls return null immediately.
10752 75773602 : if (string == NULL) Reset(NULL);
10753 75773602 : return string;
10754 : }
10755 :
10756 :
10757 13670918 : String* ConsStringIterator::Search(int* offset_out) {
10758 6835546 : ConsString* cons_string = root_;
10759 : // Reset the stack, pushing the root string.
10760 6835546 : depth_ = 1;
10761 6835546 : maximum_depth_ = 1;
10762 6835546 : frames_[0] = cons_string;
10763 6835546 : const int consumed = consumed_;
10764 : int offset = 0;
10765 : while (true) {
10766 : // Loop until the string is found which contains the target offset.
10767 : String* string = cons_string->first();
10768 : int length = string->length();
10769 : int32_t type;
10770 23686754271 : if (consumed < offset + length) {
10771 : // Target offset is in the left branch.
10772 : // Keep going if we're still in a ConString.
10773 : type = string->map()->instance_type();
10774 23684379137 : if ((type & kStringRepresentationMask) == kConsStringTag) {
10775 : cons_string = ConsString::cast(string);
10776 : PushLeft(cons_string);
10777 : continue;
10778 : }
10779 : // Tell the stack we're done descending.
10780 : AdjustMaximumDepth();
10781 : } else {
10782 : // Descend right.
10783 : // Update progress through the string.
10784 : offset += length;
10785 : // Keep going if we're still in a ConString.
10786 : string = cons_string->second();
10787 : type = string->map()->instance_type();
10788 2375134 : if ((type & kStringRepresentationMask) == kConsStringTag) {
10789 : cons_string = ConsString::cast(string);
10790 : PushRight(cons_string);
10791 : continue;
10792 : }
10793 : // Need this to be updated for the current string.
10794 : length = string->length();
10795 : // Account for the possibility of an empty right leaf.
10796 : // This happens only if we have asked for an offset outside the string.
10797 770020 : if (length == 0) {
10798 : // Reset so future operations will return null immediately.
10799 : Reset(NULL);
10800 174 : return NULL;
10801 : }
10802 : // Tell the stack we're done descending.
10803 : AdjustMaximumDepth();
10804 : // Pop stack so next iteration is in correct place.
10805 : Pop();
10806 : }
10807 : DCHECK(length != 0);
10808 : // Adjust return values and exit.
10809 6835372 : consumed_ = offset + length;
10810 6835372 : *offset_out = consumed - offset;
10811 6835372 : return string;
10812 : }
10813 : UNREACHABLE();
10814 : return NULL;
10815 : }
10816 :
10817 :
10818 152813306 : String* ConsStringIterator::NextLeaf(bool* blew_stack) {
10819 : while (true) {
10820 : // Tree traversal complete.
10821 69531267 : if (depth_ == 0) {
10822 6995 : *blew_stack = false;
10823 6995 : return NULL;
10824 : }
10825 : // We've lost track of higher nodes.
10826 69524272 : if (StackBlown()) {
10827 834 : *blew_stack = true;
10828 834 : return NULL;
10829 : }
10830 : // Go right.
10831 139046876 : ConsString* cons_string = frames_[OffsetForDepth(depth_ - 1)];
10832 : String* string = cons_string->second();
10833 : int32_t type = string->map()->instance_type();
10834 69523438 : if ((type & kStringRepresentationMask) != kConsStringTag) {
10835 : // Pop stack so next iteration is in correct place.
10836 : Pop();
10837 : int length = string->length();
10838 : // Could be a flattened ConsString.
10839 55173294 : if (length == 0) continue;
10840 54580917 : consumed_ += length;
10841 54580917 : return string;
10842 : }
10843 : cons_string = ConsString::cast(string);
10844 : PushRight(cons_string);
10845 : // Need to traverse all the way left.
10846 : while (true) {
10847 : // Continue left.
10848 : string = cons_string->first();
10849 : type = string->map()->instance_type();
10850 23759740 : if ((type & kStringRepresentationMask) != kConsStringTag) {
10851 : AdjustMaximumDepth();
10852 : int length = string->length();
10853 14350144 : if (length == 0) break; // Skip empty left-hand sides of ConsStrings.
10854 14350144 : consumed_ += length;
10855 14350144 : return string;
10856 : }
10857 : cons_string = ConsString::cast(string);
10858 : PushLeft(cons_string);
10859 : }
10860 : }
10861 : UNREACHABLE();
10862 : return NULL;
10863 : }
10864 :
10865 :
10866 4314804 : uint16_t ConsString::ConsStringGet(int index) {
10867 : DCHECK(index >= 0 && index < this->length());
10868 :
10869 : // Check for a flattened cons string
10870 4314804 : if (second()->length() == 0) {
10871 : String* left = first();
10872 368913 : return left->Get(index);
10873 : }
10874 :
10875 : String* string = String::cast(this);
10876 :
10877 : while (true) {
10878 42977412 : if (StringShape(string).IsCons()) {
10879 : ConsString* cons_string = ConsString::cast(string);
10880 : String* left = cons_string->first();
10881 39031521 : if (left->length() > index) {
10882 : string = left;
10883 : } else {
10884 488981 : index -= left->length();
10885 : string = cons_string->second();
10886 : }
10887 : } else {
10888 3945891 : return string->Get(index);
10889 : }
10890 : }
10891 :
10892 : UNREACHABLE();
10893 : return 0;
10894 : }
10895 :
10896 516 : uint16_t ThinString::ThinStringGet(int index) { return actual()->Get(index); }
10897 :
10898 1816876 : uint16_t SlicedString::SlicedStringGet(int index) {
10899 3633752 : return parent()->Get(offset() + index);
10900 : }
10901 :
10902 :
10903 : template <typename sinkchar>
10904 277435848 : void String::WriteToFlat(String* src,
10905 : sinkchar* sink,
10906 : int f,
10907 : int t) {
10908 : String* source = src;
10909 : int from = f;
10910 : int to = t;
10911 : while (true) {
10912 : DCHECK(0 <= from && from <= to && to <= source->length());
10913 372472248 : switch (StringShape(source).full_representation_tag()) {
10914 : case kOneByteStringTag | kExternalStringTag: {
10915 : CopyChars(sink, ExternalOneByteString::cast(source)->GetChars() + from,
10916 996924 : to - from);
10917 : return;
10918 : }
10919 : case kTwoByteStringTag | kExternalStringTag: {
10920 : const uc16* data =
10921 : ExternalTwoByteString::cast(source)->GetChars();
10922 : CopyChars(sink,
10923 : data + from,
10924 340890 : to - from);
10925 : return;
10926 : }
10927 : case kOneByteStringTag | kSeqStringTag: {
10928 : CopyChars(sink,
10929 244929479 : SeqOneByteString::cast(source)->GetChars() + from,
10930 489858958 : to - from);
10931 : return;
10932 : }
10933 : case kTwoByteStringTag | kSeqStringTag: {
10934 : CopyChars(sink,
10935 12055590 : SeqTwoByteString::cast(source)->GetChars() + from,
10936 24111180 : to - from);
10937 : return;
10938 : }
10939 : case kOneByteStringTag | kConsStringTag:
10940 : case kTwoByteStringTag | kConsStringTag: {
10941 : ConsString* cons_string = ConsString::cast(source);
10942 : String* first = cons_string->first();
10943 : int boundary = first->length();
10944 112535277 : if (to - boundary >= boundary - from) {
10945 : // Right hand side is longer. Recurse over left.
10946 30928669 : if (from < boundary) {
10947 30928669 : WriteToFlat(first, sink, from, boundary);
10948 61857338 : if (from == 0 && cons_string->second() == first) {
10949 17531267 : CopyChars(sink + boundary, sink, boundary);
10950 : return;
10951 : }
10952 13397402 : sink += boundary - from;
10953 : from = 0;
10954 : } else {
10955 0 : from -= boundary;
10956 : }
10957 : to -= boundary;
10958 : source = cons_string->second();
10959 : } else {
10960 : // Left hand side is longer. Recurse over right.
10961 81606608 : if (to > boundary) {
10962 : String* second = cons_string->second();
10963 : // When repeatedly appending to a string, we get a cons string that
10964 : // is unbalanced to the left, a list, essentially. We inline the
10965 : // common case of sequential one-byte right child.
10966 81037951 : if (to - boundary == 1) {
10967 72452616 : sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
10968 44811643 : } else if (second->IsSeqOneByteString()) {
10969 38380080 : CopyChars(sink + boundary - from,
10970 38380080 : SeqOneByteString::cast(second)->GetChars(),
10971 76760160 : to - boundary);
10972 : } else {
10973 6431563 : WriteToFlat(second,
10974 6431563 : sink + boundary - from,
10975 : 0,
10976 6431563 : to - boundary);
10977 : }
10978 : to = boundary;
10979 : }
10980 : source = first;
10981 : }
10982 : break;
10983 : }
10984 : case kOneByteStringTag | kSlicedStringTag:
10985 : case kTwoByteStringTag | kSlicedStringTag: {
10986 : SlicedString* slice = SlicedString::cast(source);
10987 2080159 : unsigned offset = slice->offset();
10988 4160318 : WriteToFlat(slice->parent(), sink, from + offset, to + offset);
10989 2080159 : return;
10990 : }
10991 : case kOneByteStringTag | kThinStringTag:
10992 : case kTwoByteStringTag | kThinStringTag:
10993 : source = ThinString::cast(source)->actual();
10994 32393 : break;
10995 : }
10996 : }
10997 : }
10998 :
10999 :
11000 :
11001 : template <typename SourceChar>
11002 129988 : static void CalculateLineEndsImpl(Isolate* isolate,
11003 : List<int>* line_ends,
11004 : Vector<const SourceChar> src,
11005 : bool include_ending_line) {
11006 64994 : const int src_len = src.length();
11007 : UnicodeCache* cache = isolate->unicode_cache();
11008 330378325 : for (int i = 0; i < src_len - 1; i++) {
11009 330313331 : SourceChar current = src[i];
11010 660626662 : SourceChar next = src[i + 1];
11011 330313331 : if (cache->IsLineTerminatorSequence(current, next)) line_ends->Add(i);
11012 : }
11013 :
11014 129498 : if (src_len > 0 && cache->IsLineTerminatorSequence(src[src_len - 1], 0)) {
11015 23333 : line_ends->Add(src_len - 1);
11016 : }
11017 64994 : if (include_ending_line) {
11018 : // Include one character beyond the end of script. The rewriter uses that
11019 : // position for the implicit return statement.
11020 63154 : line_ends->Add(src_len);
11021 : }
11022 64994 : }
11023 :
11024 :
11025 64994 : Handle<FixedArray> String::CalculateLineEnds(Handle<String> src,
11026 : bool include_ending_line) {
11027 64994 : src = Flatten(src);
11028 : // Rough estimate of line count based on a roughly estimated average
11029 : // length of (unpacked) code.
11030 64994 : int line_count_estimate = src->length() >> 4;
11031 : List<int> line_ends(line_count_estimate);
11032 : Isolate* isolate = src->GetIsolate();
11033 : { DisallowHeapAllocation no_allocation; // ensure vectors stay valid.
11034 : // Dispatch on type of strings.
11035 64994 : String::FlatContent content = src->GetFlatContent();
11036 : DCHECK(content.IsFlat());
11037 64994 : if (content.IsOneByte()) {
11038 : CalculateLineEndsImpl(isolate,
11039 : &line_ends,
11040 : content.ToOneByteVector(),
11041 64388 : include_ending_line);
11042 : } else {
11043 : CalculateLineEndsImpl(isolate,
11044 : &line_ends,
11045 : content.ToUC16Vector(),
11046 606 : include_ending_line);
11047 : }
11048 : }
11049 64994 : int line_count = line_ends.length();
11050 64994 : Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count);
11051 14932606 : for (int i = 0; i < line_count; i++) {
11052 29735224 : array->set(i, Smi::FromInt(line_ends[i]));
11053 : }
11054 129988 : return array;
11055 : }
11056 :
11057 :
11058 : // Compares the contents of two strings by reading and comparing
11059 : // int-sized blocks of characters.
11060 : template <typename Char>
11061 : static inline bool CompareRawStringContents(const Char* const a,
11062 : const Char* const b,
11063 : int length) {
11064 106067174 : return CompareChars(a, b, length) == 0;
11065 : }
11066 :
11067 :
11068 : template<typename Chars1, typename Chars2>
11069 : class RawStringComparator : public AllStatic {
11070 : public:
11071 : static inline bool compare(const Chars1* a, const Chars2* b, int len) {
11072 : DCHECK(sizeof(Chars1) != sizeof(Chars2));
11073 1286580 : for (int i = 0; i < len; i++) {
11074 1286628 : if (a[i] != b[i]) {
11075 : return false;
11076 : }
11077 : }
11078 : return true;
11079 : }
11080 : };
11081 :
11082 :
11083 : template<>
11084 : class RawStringComparator<uint16_t, uint16_t> {
11085 : public:
11086 : static inline bool compare(const uint16_t* a, const uint16_t* b, int len) {
11087 : return CompareRawStringContents(a, b, len);
11088 : }
11089 : };
11090 :
11091 :
11092 : template<>
11093 : class RawStringComparator<uint8_t, uint8_t> {
11094 : public:
11095 : static inline bool compare(const uint8_t* a, const uint8_t* b, int len) {
11096 : return CompareRawStringContents(a, b, len);
11097 : }
11098 : };
11099 :
11100 :
11101 : class StringComparator {
11102 : class State {
11103 : public:
11104 6157423 : State() : is_one_byte_(true), length_(0), buffer8_(NULL) {}
11105 :
11106 12314846 : void Init(String* string) {
11107 12314846 : ConsString* cons_string = String::VisitFlat(this, string);
11108 : iter_.Reset(cons_string);
11109 12314846 : if (cons_string != NULL) {
11110 : int offset;
11111 3736066 : string = iter_.Next(&offset);
11112 3736066 : String::VisitFlat(this, string, offset);
11113 : }
11114 12314846 : }
11115 :
11116 : inline void VisitOneByteString(const uint8_t* chars, int length) {
11117 50963988 : is_one_byte_ = true;
11118 50963988 : buffer8_ = chars;
11119 50963988 : length_ = length;
11120 : }
11121 :
11122 : inline void VisitTwoByteString(const uint16_t* chars, int length) {
11123 7882395 : is_one_byte_ = false;
11124 7882395 : buffer16_ = chars;
11125 7882395 : length_ = length;
11126 : }
11127 :
11128 56474780 : void Advance(int consumed) {
11129 : DCHECK(consumed <= length_);
11130 : // Still in buffer.
11131 56474780 : if (length_ != consumed) {
11132 9943243 : if (is_one_byte_) {
11133 9849533 : buffer8_ += consumed;
11134 : } else {
11135 93710 : buffer16_ += consumed;
11136 : }
11137 9943243 : length_ -= consumed;
11138 66418023 : return;
11139 : }
11140 : // Advance state.
11141 : int offset;
11142 46531537 : String* next = iter_.Next(&offset);
11143 : DCHECK_EQ(0, offset);
11144 : DCHECK(next != NULL);
11145 46531537 : String::VisitFlat(this, next);
11146 : }
11147 :
11148 : ConsStringIterator iter_;
11149 : bool is_one_byte_;
11150 : int length_;
11151 : union {
11152 : const uint8_t* buffer8_;
11153 : const uint16_t* buffer16_;
11154 : };
11155 :
11156 : private:
11157 : DISALLOW_COPY_AND_ASSIGN(State);
11158 : };
11159 :
11160 : public:
11161 : inline StringComparator() {}
11162 :
11163 : template<typename Chars1, typename Chars2>
11164 : static inline bool Equals(State* state_1, State* state_2, int to_check) {
11165 : const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_);
11166 : const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_);
11167 : return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check);
11168 : }
11169 :
11170 6157423 : bool Equals(String* string_1, String* string_2) {
11171 : int length = string_1->length();
11172 40552236 : state_1_.Init(string_1);
11173 40552236 : state_2_.Init(string_2);
11174 : while (true) {
11175 34394813 : int to_check = Min(state_1_.length_, state_2_.length_);
11176 : DCHECK(to_check > 0 && to_check <= length);
11177 : bool is_equal;
11178 34394813 : if (state_1_.is_one_byte_) {
11179 30354128 : if (state_2_.is_one_byte_) {
11180 : is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check);
11181 : } else {
11182 : is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check);
11183 : }
11184 : } else {
11185 4040685 : if (state_2_.is_one_byte_) {
11186 : is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check);
11187 : } else {
11188 : is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check);
11189 : }
11190 : }
11191 : // Looping done.
11192 34394813 : if (!is_equal) return false;
11193 34381984 : length -= to_check;
11194 : // Exit condition. Strings are equal.
11195 34381984 : if (length == 0) return true;
11196 28237390 : state_1_.Advance(to_check);
11197 28237390 : state_2_.Advance(to_check);
11198 28237390 : }
11199 : }
11200 :
11201 : private:
11202 : State state_1_;
11203 : State state_2_;
11204 :
11205 : DISALLOW_COPY_AND_ASSIGN(StringComparator);
11206 : };
11207 :
11208 :
11209 35263083 : bool String::SlowEquals(String* other) {
11210 : DisallowHeapAllocation no_gc;
11211 : // Fast check: negative check with lengths.
11212 : int len = length();
11213 35263083 : if (len != other->length()) return false;
11214 26100958 : if (len == 0) return true;
11215 :
11216 : // Fast check: if at least one ThinString is involved, dereference it/them
11217 : // and restart.
11218 52200660 : if (this->IsThinString() || other->IsThinString()) {
11219 4960 : if (other->IsThinString()) other = ThinString::cast(other)->actual();
11220 4960 : if (this->IsThinString()) {
11221 1252 : return ThinString::cast(this)->actual()->Equals(other);
11222 : } else {
11223 3708 : return this->Equals(other);
11224 : }
11225 : }
11226 :
11227 : // Fast check: if hash code is computed for both strings
11228 : // a fast negative check can be performed.
11229 51839502 : if (HasHashCode() && other->HasHashCode()) {
11230 : #ifdef ENABLE_SLOW_DCHECKS
11231 : if (FLAG_enable_slow_asserts) {
11232 : if (Hash() != other->Hash()) {
11233 : bool found_difference = false;
11234 : for (int i = 0; i < len; i++) {
11235 : if (Get(i) != other->Get(i)) {
11236 : found_difference = true;
11237 : break;
11238 : }
11239 : }
11240 : DCHECK(found_difference);
11241 : }
11242 : }
11243 : #endif
11244 25742399 : if (Hash() != other->Hash()) return false;
11245 : }
11246 :
11247 : // We know the strings are both non-empty. Compare the first chars
11248 : // before we try to flatten the strings.
11249 23611585 : if (this->Get(0) != other->Get(0)) return false;
11250 :
11251 41721061 : if (IsSeqOneByteString() && other->IsSeqOneByteString()) {
11252 17452655 : const uint8_t* str1 = SeqOneByteString::cast(this)->GetChars();
11253 17452655 : const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars();
11254 17452655 : return CompareRawStringContents(str1, str2, len);
11255 : }
11256 :
11257 : StringComparator comparator;
11258 6157423 : return comparator.Equals(this, other);
11259 : }
11260 :
11261 :
11262 6450995 : bool String::SlowEquals(Handle<String> one, Handle<String> two) {
11263 : // Fast check: negative check with lengths.
11264 : int one_length = one->length();
11265 6450995 : if (one_length != two->length()) return false;
11266 6411118 : if (one_length == 0) return true;
11267 :
11268 : // Fast check: if at least one ThinString is involved, dereference it/them
11269 : // and restart.
11270 12822236 : if (one->IsThinString() || two->IsThinString()) {
11271 19 : if (one->IsThinString()) one = handle(ThinString::cast(*one)->actual());
11272 19 : if (two->IsThinString()) two = handle(ThinString::cast(*two)->actual());
11273 19 : return String::Equals(one, two);
11274 : }
11275 :
11276 : // Fast check: if hash code is computed for both strings
11277 : // a fast negative check can be performed.
11278 6427755 : if (one->HasHashCode() && two->HasHashCode()) {
11279 : #ifdef ENABLE_SLOW_DCHECKS
11280 : if (FLAG_enable_slow_asserts) {
11281 : if (one->Hash() != two->Hash()) {
11282 : bool found_difference = false;
11283 : for (int i = 0; i < one_length; i++) {
11284 : if (one->Get(i) != two->Get(i)) {
11285 : found_difference = true;
11286 : break;
11287 : }
11288 : }
11289 : DCHECK(found_difference);
11290 : }
11291 : }
11292 : #endif
11293 3656 : if (one->Hash() != two->Hash()) return false;
11294 : }
11295 :
11296 : // We know the strings are both non-empty. Compare the first chars
11297 : // before we try to flatten the strings.
11298 6411083 : if (one->Get(0) != two->Get(0)) return false;
11299 :
11300 4391400 : one = String::Flatten(one);
11301 4391400 : two = String::Flatten(two);
11302 :
11303 : DisallowHeapAllocation no_gc;
11304 4391400 : String::FlatContent flat1 = one->GetFlatContent();
11305 4391400 : String::FlatContent flat2 = two->GetFlatContent();
11306 :
11307 4391400 : if (flat1.IsOneByte() && flat2.IsOneByte()) {
11308 : return CompareRawStringContents(flat1.ToOneByteVector().start(),
11309 : flat2.ToOneByteVector().start(),
11310 : one_length);
11311 : } else {
11312 20597174 : for (int i = 0; i < one_length; i++) {
11313 20597174 : if (flat1.Get(i) != flat2.Get(i)) return false;
11314 : }
11315 : return true;
11316 : }
11317 : }
11318 :
11319 :
11320 : // static
11321 7363753 : ComparisonResult String::Compare(Handle<String> x, Handle<String> y) {
11322 : // A few fast case tests before we flatten.
11323 7363753 : if (x.is_identical_to(y)) {
11324 : return ComparisonResult::kEqual;
11325 7363238 : } else if (y->length() == 0) {
11326 : return x->length() == 0 ? ComparisonResult::kEqual
11327 0 : : ComparisonResult::kGreaterThan;
11328 7363238 : } else if (x->length() == 0) {
11329 : return ComparisonResult::kLessThan;
11330 : }
11331 :
11332 14726476 : int const d = x->Get(0) - y->Get(0);
11333 7363238 : if (d < 0) {
11334 : return ComparisonResult::kLessThan;
11335 5842647 : } else if (d > 0) {
11336 : return ComparisonResult::kGreaterThan;
11337 : }
11338 :
11339 : // Slow case.
11340 30338 : x = String::Flatten(x);
11341 30338 : y = String::Flatten(y);
11342 :
11343 : DisallowHeapAllocation no_gc;
11344 : ComparisonResult result = ComparisonResult::kEqual;
11345 : int prefix_length = x->length();
11346 30338 : if (y->length() < prefix_length) {
11347 : prefix_length = y->length();
11348 : result = ComparisonResult::kGreaterThan;
11349 30338 : } else if (y->length() > prefix_length) {
11350 : result = ComparisonResult::kLessThan;
11351 : }
11352 : int r;
11353 30338 : String::FlatContent x_content = x->GetFlatContent();
11354 30338 : String::FlatContent y_content = y->GetFlatContent();
11355 30338 : if (x_content.IsOneByte()) {
11356 : Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
11357 3303 : if (y_content.IsOneByte()) {
11358 : Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11359 55 : r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11360 : } else {
11361 : Vector<const uc16> y_chars = y_content.ToUC16Vector();
11362 3248 : r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11363 : }
11364 : } else {
11365 : Vector<const uc16> x_chars = x_content.ToUC16Vector();
11366 27035 : if (y_content.IsOneByte()) {
11367 : Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11368 1624 : r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11369 : } else {
11370 : Vector<const uc16> y_chars = y_content.ToUC16Vector();
11371 25411 : r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11372 : }
11373 : }
11374 30338 : if (r < 0) {
11375 : result = ComparisonResult::kLessThan;
11376 18299 : } else if (r > 0) {
11377 : result = ComparisonResult::kGreaterThan;
11378 : }
11379 30338 : return result;
11380 : }
11381 :
11382 3383 : Object* String::IndexOf(Isolate* isolate, Handle<Object> receiver,
11383 : Handle<Object> search, Handle<Object> position) {
11384 3383 : if (receiver->IsNullOrUndefined(isolate)) {
11385 900 : THROW_NEW_ERROR_RETURN_FAILURE(
11386 : isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
11387 : isolate->factory()->NewStringFromAsciiChecked(
11388 : "String.prototype.indexOf")));
11389 : }
11390 : Handle<String> receiver_string;
11391 6166 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string,
11392 : Object::ToString(isolate, receiver));
11393 :
11394 : Handle<String> search_string;
11395 6166 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
11396 : Object::ToString(isolate, search));
11397 :
11398 3083 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11399 : Object::ToInteger(isolate, position));
11400 :
11401 : uint32_t index = receiver_string->ToValidIndex(*position);
11402 : return Smi::FromInt(
11403 6166 : String::IndexOf(isolate, receiver_string, search_string, index));
11404 : }
11405 :
11406 : namespace {
11407 :
11408 : template <typename T>
11409 183161 : int SearchString(Isolate* isolate, String::FlatContent receiver_content,
11410 240 : Vector<T> pat_vector, int start_index) {
11411 183161 : if (receiver_content.IsOneByte()) {
11412 : return SearchString(isolate, receiver_content.ToOneByteVector(), pat_vector,
11413 182692 : start_index);
11414 : }
11415 : return SearchString(isolate, receiver_content.ToUC16Vector(), pat_vector,
11416 469 : start_index);
11417 : }
11418 :
11419 : } // namespace
11420 :
11421 187350 : int String::IndexOf(Isolate* isolate, Handle<String> receiver,
11422 : Handle<String> search, int start_index) {
11423 : DCHECK(0 <= start_index);
11424 : DCHECK(start_index <= receiver->length());
11425 :
11426 187350 : uint32_t search_length = search->length();
11427 187350 : if (search_length == 0) return start_index;
11428 :
11429 187236 : uint32_t receiver_length = receiver->length();
11430 187236 : if (start_index + search_length > receiver_length) return -1;
11431 :
11432 183161 : receiver = String::Flatten(receiver);
11433 183161 : search = String::Flatten(search);
11434 :
11435 : DisallowHeapAllocation no_gc; // ensure vectors stay valid
11436 : // Extract flattened substrings of cons strings before getting encoding.
11437 183161 : String::FlatContent receiver_content = receiver->GetFlatContent();
11438 183161 : String::FlatContent search_content = search->GetFlatContent();
11439 :
11440 : // dispatch on type of strings
11441 183161 : if (search_content.IsOneByte()) {
11442 : Vector<const uint8_t> pat_vector = search_content.ToOneByteVector();
11443 : return SearchString<const uint8_t>(isolate, receiver_content, pat_vector,
11444 180011 : start_index);
11445 : }
11446 3150 : Vector<const uc16> pat_vector = search_content.ToUC16Vector();
11447 : return SearchString<const uc16>(isolate, receiver_content, pat_vector,
11448 3150 : start_index);
11449 : }
11450 :
11451 5600 : MaybeHandle<String> String::GetSubstitution(Isolate* isolate, Match* match,
11452 : Handle<String> replacement,
11453 : int start_index) {
11454 : DCHECK_IMPLIES(match->HasNamedCaptures(), FLAG_harmony_regexp_named_captures);
11455 : DCHECK_GE(start_index, 0);
11456 :
11457 : Factory* factory = isolate->factory();
11458 :
11459 : const int replacement_length = replacement->length();
11460 5600 : const int captures_length = match->CaptureCount();
11461 :
11462 5600 : replacement = String::Flatten(replacement);
11463 :
11464 : Handle<String> dollar_string =
11465 5600 : factory->LookupSingleCharacterStringFromCode('$');
11466 : int next_dollar_ix =
11467 5600 : String::IndexOf(isolate, replacement, dollar_string, start_index);
11468 5600 : if (next_dollar_ix < 0) {
11469 : return replacement;
11470 : }
11471 :
11472 5525 : IncrementalStringBuilder builder(isolate);
11473 :
11474 5525 : if (next_dollar_ix > 0) {
11475 465 : builder.AppendString(factory->NewSubString(replacement, 0, next_dollar_ix));
11476 : }
11477 :
11478 : while (true) {
11479 12473 : const int peek_ix = next_dollar_ix + 1;
11480 12473 : if (peek_ix >= replacement_length) {
11481 : builder.AppendCharacter('$');
11482 30 : return builder.Finish();
11483 : }
11484 :
11485 : int continue_from_ix = -1;
11486 : const uint16_t peek = replacement->Get(peek_ix);
11487 12443 : switch (peek) {
11488 : case '$': // $$
11489 : builder.AppendCharacter('$');
11490 90 : continue_from_ix = peek_ix + 1;
11491 90 : break;
11492 : case '&': // $& - match
11493 90 : builder.AppendString(match->GetMatch());
11494 90 : continue_from_ix = peek_ix + 1;
11495 90 : break;
11496 : case '`': // $` - prefix
11497 60 : builder.AppendString(match->GetPrefix());
11498 60 : continue_from_ix = peek_ix + 1;
11499 60 : break;
11500 : case '\'': // $' - suffix
11501 60 : builder.AppendString(match->GetSuffix());
11502 60 : continue_from_ix = peek_ix + 1;
11503 60 : break;
11504 : case '0':
11505 : case '1':
11506 : case '2':
11507 : case '3':
11508 : case '4':
11509 : case '5':
11510 : case '6':
11511 : case '7':
11512 : case '8':
11513 : case '9': {
11514 : // Valid indices are $1 .. $9, $01 .. $09 and $10 .. $99
11515 11678 : int scaled_index = (peek - '0');
11516 : int advance = 1;
11517 :
11518 11678 : if (peek_ix + 1 < replacement_length) {
11519 : const uint16_t next_peek = replacement->Get(peek_ix + 1);
11520 9731 : if (next_peek >= '0' && next_peek <= '9') {
11521 2235 : const int new_scaled_index = scaled_index * 10 + (next_peek - '0');
11522 2235 : if (new_scaled_index < captures_length) {
11523 : scaled_index = new_scaled_index;
11524 : advance = 2;
11525 : }
11526 : }
11527 : }
11528 :
11529 11678 : if (scaled_index == 0 || scaled_index >= captures_length) {
11530 : builder.AppendCharacter('$');
11531 : continue_from_ix = peek_ix;
11532 11828 : break;
11533 : }
11534 :
11535 : bool capture_exists;
11536 : Handle<String> capture;
11537 23056 : ASSIGN_RETURN_ON_EXCEPTION(
11538 : isolate, capture, match->GetCapture(scaled_index, &capture_exists),
11539 : String);
11540 11528 : if (capture_exists) builder.AppendString(capture);
11541 11528 : continue_from_ix = peek_ix + advance;
11542 11528 : break;
11543 : }
11544 : case '<': { // $<name> - named capture
11545 : typedef String::Match::CaptureState CaptureState;
11546 :
11547 420 : if (!match->HasNamedCaptures()) {
11548 : builder.AppendCharacter('$');
11549 : continue_from_ix = peek_ix;
11550 336 : break;
11551 : }
11552 :
11553 : Handle<String> bracket_string =
11554 336 : factory->LookupSingleCharacterStringFromCode('>');
11555 : const int closing_bracket_ix =
11556 336 : String::IndexOf(isolate, replacement, bracket_string, peek_ix + 1);
11557 :
11558 336 : if (closing_bracket_ix == -1) {
11559 84 : THROW_NEW_ERROR(
11560 : isolate,
11561 : NewSyntaxError(MessageTemplate::kRegExpInvalidReplaceString,
11562 : replacement),
11563 : String);
11564 : }
11565 :
11566 : Handle<String> capture_name =
11567 294 : factory->NewSubString(replacement, peek_ix + 1, closing_bracket_ix);
11568 : Handle<String> capture;
11569 : CaptureState capture_state;
11570 588 : ASSIGN_RETURN_ON_EXCEPTION(
11571 : isolate, capture,
11572 : match->GetNamedCapture(capture_name, &capture_state), String);
11573 :
11574 294 : switch (capture_state) {
11575 : case CaptureState::INVALID:
11576 252 : THROW_NEW_ERROR(
11577 : isolate,
11578 : NewSyntaxError(MessageTemplate::kRegExpInvalidReplaceString,
11579 : replacement),
11580 : String);
11581 : break;
11582 : case CaptureState::UNMATCHED:
11583 : break;
11584 : case CaptureState::MATCHED:
11585 112 : builder.AppendString(capture);
11586 112 : break;
11587 : }
11588 :
11589 168 : continue_from_ix = closing_bracket_ix + 1;
11590 168 : break;
11591 : }
11592 : default:
11593 : builder.AppendCharacter('$');
11594 : continue_from_ix = peek_ix;
11595 45 : break;
11596 : }
11597 :
11598 : // Go the the next $ in the replacement.
11599 : // TODO(jgruber): Single-char lookups could be much more efficient.
11600 : DCHECK_NE(continue_from_ix, -1);
11601 : next_dollar_ix =
11602 12275 : String::IndexOf(isolate, replacement, dollar_string, continue_from_ix);
11603 :
11604 : // Return if there are no more $ characters in the replacement. If we
11605 : // haven't reached the end, we need to append the suffix.
11606 12275 : if (next_dollar_ix < 0) {
11607 5327 : if (continue_from_ix < replacement_length) {
11608 : builder.AppendString(factory->NewSubString(
11609 1738 : replacement, continue_from_ix, replacement_length));
11610 : }
11611 5327 : return builder.Finish();
11612 : }
11613 :
11614 : // Append substring between the previous and the next $ character.
11615 6948 : if (next_dollar_ix > continue_from_ix) {
11616 : builder.AppendString(
11617 42 : factory->NewSubString(replacement, continue_from_ix, next_dollar_ix));
11618 : }
11619 : }
11620 :
11621 : UNREACHABLE();
11622 : return MaybeHandle<String>();
11623 : }
11624 :
11625 : namespace { // for String.Prototype.lastIndexOf
11626 :
11627 : template <typename schar, typename pchar>
11628 2260 : int StringMatchBackwards(Vector<const schar> subject,
11629 : Vector<const pchar> pattern, int idx) {
11630 2260 : int pattern_length = pattern.length();
11631 : DCHECK(pattern_length >= 1);
11632 : DCHECK(idx + pattern_length <= subject.length());
11633 :
11634 : if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
11635 0 : for (int i = 0; i < pattern_length; i++) {
11636 0 : uc16 c = pattern[i];
11637 0 : if (c > String::kMaxOneByteCharCode) {
11638 : return -1;
11639 : }
11640 : }
11641 : }
11642 :
11643 2260 : pchar pattern_first_char = pattern[0];
11644 8229 : for (int i = idx; i >= 0; i--) {
11645 10210 : if (subject[i] != pattern_first_char) continue;
11646 : int j = 1;
11647 3116 : while (j < pattern_length) {
11648 2270 : if (pattern[j] != subject[i + j]) {
11649 : break;
11650 : }
11651 1105 : j++;
11652 : }
11653 2011 : if (j == pattern_length) {
11654 : return i;
11655 : }
11656 : }
11657 : return -1;
11658 : }
11659 :
11660 : } // namespace
11661 :
11662 2905 : Object* String::LastIndexOf(Isolate* isolate, Handle<Object> receiver,
11663 : Handle<Object> search, Handle<Object> position) {
11664 2905 : if (receiver->IsNullOrUndefined(isolate)) {
11665 810 : THROW_NEW_ERROR_RETURN_FAILURE(
11666 : isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
11667 : isolate->factory()->NewStringFromAsciiChecked(
11668 : "String.prototype.lastIndexOf")));
11669 : }
11670 : Handle<String> receiver_string;
11671 5270 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string,
11672 : Object::ToString(isolate, receiver));
11673 :
11674 : Handle<String> search_string;
11675 5270 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
11676 : Object::ToString(isolate, search));
11677 :
11678 5270 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11679 : Object::ToNumber(position));
11680 :
11681 : uint32_t start_index;
11682 :
11683 2635 : if (position->IsNaN()) {
11684 1885 : start_index = receiver_string->length();
11685 : } else {
11686 750 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11687 : Object::ToInteger(isolate, position));
11688 : start_index = receiver_string->ToValidIndex(*position);
11689 : }
11690 :
11691 2635 : uint32_t pattern_length = search_string->length();
11692 2635 : uint32_t receiver_length = receiver_string->length();
11693 :
11694 2635 : if (start_index + pattern_length > receiver_length) {
11695 2005 : start_index = receiver_length - pattern_length;
11696 : }
11697 :
11698 2635 : if (pattern_length == 0) {
11699 750 : return Smi::FromInt(start_index);
11700 : }
11701 :
11702 2260 : receiver_string = String::Flatten(receiver_string);
11703 2260 : search_string = String::Flatten(search_string);
11704 :
11705 : int last_index = -1;
11706 : DisallowHeapAllocation no_gc; // ensure vectors stay valid
11707 :
11708 2260 : String::FlatContent receiver_content = receiver_string->GetFlatContent();
11709 2260 : String::FlatContent search_content = search_string->GetFlatContent();
11710 :
11711 2260 : if (search_content.IsOneByte()) {
11712 : Vector<const uint8_t> pat_vector = search_content.ToOneByteVector();
11713 2260 : if (receiver_content.IsOneByte()) {
11714 : last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
11715 2253 : pat_vector, start_index);
11716 : } else {
11717 : last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
11718 7 : pat_vector, start_index);
11719 : }
11720 : } else {
11721 : Vector<const uc16> pat_vector = search_content.ToUC16Vector();
11722 0 : if (receiver_content.IsOneByte()) {
11723 : last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
11724 0 : pat_vector, start_index);
11725 : } else {
11726 : last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
11727 0 : pat_vector, start_index);
11728 : }
11729 : }
11730 2260 : return Smi::FromInt(last_index);
11731 : }
11732 :
11733 59356243 : bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
11734 : int slen = length();
11735 : // Can't check exact length equality, but we can check bounds.
11736 59356243 : int str_len = str.length();
11737 59356243 : if (!allow_prefix_match &&
11738 58028164 : (str_len < slen ||
11739 58028164 : str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) {
11740 : return false;
11741 : }
11742 : int i;
11743 56792688 : size_t remaining_in_str = static_cast<size_t>(str_len);
11744 56792688 : const uint8_t* utf8_data = reinterpret_cast<const uint8_t*>(str.start());
11745 1126237230 : for (i = 0; i < slen && remaining_in_str > 0; i++) {
11746 538742462 : size_t cursor = 0;
11747 538742462 : uint32_t r = unibrow::Utf8::ValueOf(utf8_data, remaining_in_str, &cursor);
11748 : DCHECK(cursor > 0 && cursor <= remaining_in_str);
11749 538742467 : if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
11750 32416569 : if (i > slen - 1) return false;
11751 28 : if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false;
11752 21 : if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false;
11753 : } else {
11754 538742461 : if (Get(i) != r) return false;
11755 : }
11756 506325927 : utf8_data += cursor;
11757 506325927 : remaining_in_str -= cursor;
11758 : }
11759 24376153 : return (allow_prefix_match || i == slen) && remaining_in_str == 0;
11760 : }
11761 :
11762 : template <>
11763 210 : bool String::IsEqualTo(Vector<const uint8_t> str) {
11764 210 : return IsOneByteEqualTo(str);
11765 : }
11766 :
11767 : template <>
11768 0 : bool String::IsEqualTo(Vector<const uc16> str) {
11769 0 : return IsTwoByteEqualTo(str);
11770 : }
11771 :
11772 96515560 : bool String::IsOneByteEqualTo(Vector<const uint8_t> str) {
11773 : int slen = length();
11774 96515560 : if (str.length() != slen) return false;
11775 : DisallowHeapAllocation no_gc;
11776 69374799 : FlatContent content = GetFlatContent();
11777 69374787 : if (content.IsOneByte()) {
11778 69374686 : return CompareChars(content.ToOneByteVector().start(),
11779 138749372 : str.start(), slen) == 0;
11780 : }
11781 170 : for (int i = 0; i < slen; i++) {
11782 254 : if (Get(i) != static_cast<uint16_t>(str[i])) return false;
11783 : }
11784 : return true;
11785 : }
11786 :
11787 :
11788 40747 : bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
11789 : int slen = length();
11790 40747 : if (str.length() != slen) return false;
11791 : DisallowHeapAllocation no_gc;
11792 12511 : FlatContent content = GetFlatContent();
11793 12511 : if (content.IsTwoByte()) {
11794 24172 : return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
11795 : }
11796 0 : for (int i = 0; i < slen; i++) {
11797 425 : if (Get(i) != str[i]) return false;
11798 : }
11799 : return true;
11800 : }
11801 :
11802 :
11803 29115815 : uint32_t String::ComputeAndSetHash() {
11804 : // Should only be called if hash code has not yet been computed.
11805 : DCHECK(!HasHashCode());
11806 :
11807 : // Store the hash code in the object.
11808 29115815 : uint32_t field = IteratingStringHasher::Hash(this, GetHeap()->HashSeed());
11809 : set_hash_field(field);
11810 :
11811 : // Check the hash code is there.
11812 : DCHECK(HasHashCode());
11813 29115820 : uint32_t result = field >> kHashShift;
11814 : DCHECK(result != 0); // Ensure that the hash value of 0 is never computed.
11815 29115820 : return result;
11816 : }
11817 :
11818 :
11819 4310076 : bool String::ComputeArrayIndex(uint32_t* index) {
11820 : int length = this->length();
11821 4310076 : if (length == 0 || length > kMaxArrayIndexSize) return false;
11822 : StringCharacterStream stream(this);
11823 1840747 : return StringToArrayIndex(&stream, index);
11824 : }
11825 :
11826 :
11827 23899348 : bool String::SlowAsArrayIndex(uint32_t* index) {
11828 23899348 : if (length() <= kMaxCachedArrayIndexLength) {
11829 19589272 : Hash(); // force computation of hash code
11830 : uint32_t field = hash_field();
11831 19589273 : if ((field & kIsNotArrayIndexMask) != 0) return false;
11832 : // Isolate the array index form the full hash field.
11833 6708846 : *index = ArrayIndexValueBits::decode(field);
11834 6708846 : return true;
11835 : } else {
11836 4310076 : return ComputeArrayIndex(index);
11837 : }
11838 : }
11839 :
11840 :
11841 38297751 : Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
11842 : Heap* heap = string->GetHeap();
11843 38297751 : if (new_length == 0) return heap->isolate()->factory()->empty_string();
11844 :
11845 : int new_size, old_size;
11846 : int old_length = string->length();
11847 28893065 : if (old_length <= new_length) return string;
11848 :
11849 27264400 : if (string->IsSeqOneByteString()) {
11850 : old_size = SeqOneByteString::SizeFor(old_length);
11851 : new_size = SeqOneByteString::SizeFor(new_length);
11852 : } else {
11853 : DCHECK(string->IsSeqTwoByteString());
11854 : old_size = SeqTwoByteString::SizeFor(old_length);
11855 : new_size = SeqTwoByteString::SizeFor(new_length);
11856 : }
11857 :
11858 27264400 : int delta = old_size - new_size;
11859 :
11860 27264400 : Address start_of_string = string->address();
11861 : DCHECK_OBJECT_ALIGNED(start_of_string);
11862 : DCHECK_OBJECT_ALIGNED(start_of_string + new_size);
11863 :
11864 : // Sizes are pointer size aligned, so that we can use filler objects
11865 : // that are a multiple of pointer size.
11866 : heap->CreateFillerObjectAt(start_of_string + new_size, delta,
11867 27264400 : ClearRecordedSlots::kNo);
11868 54528800 : heap->AdjustLiveBytes(*string, -delta);
11869 :
11870 : // We are storing the new length using release store after creating a filler
11871 : // for the left-over space to avoid races with the sweeper thread.
11872 : string->synchronized_set_length(new_length);
11873 :
11874 27264400 : return string;
11875 : }
11876 :
11877 :
11878 2303138 : uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
11879 : // For array indexes mix the length into the hash as an array index could
11880 : // be zero.
11881 : DCHECK(length > 0);
11882 : DCHECK(length <= String::kMaxArrayIndexSize);
11883 : DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
11884 : (1 << String::kArrayIndexValueBits));
11885 :
11886 13360334 : value <<= String::ArrayIndexValueBits::kShift;
11887 13360334 : value |= length << String::ArrayIndexLengthBits::kShift;
11888 :
11889 : DCHECK((value & String::kIsNotArrayIndexMask) == 0);
11890 : DCHECK_EQ(length <= String::kMaxCachedArrayIndexLength,
11891 : (value & String::kContainsCachedArrayIndexMask) == 0);
11892 2303138 : return value;
11893 : }
11894 :
11895 :
11896 213005237 : uint32_t StringHasher::GetHashField() {
11897 213005237 : if (length_ <= String::kMaxHashCalcLength) {
11898 212944188 : if (is_array_index_) {
11899 21147288 : return MakeArrayIndexHash(array_index_, length_);
11900 : }
11901 404741088 : return (GetHashCore(raw_running_hash_) << String::kHashShift) |
11902 202370544 : String::kIsNotArrayIndexMask;
11903 : } else {
11904 61049 : return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
11905 : }
11906 : }
11907 :
11908 :
11909 24522790 : uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars,
11910 : uint32_t seed,
11911 : int* utf16_length_out) {
11912 24522790 : int vector_length = chars.length();
11913 : // Handle some edge cases
11914 24522790 : if (vector_length <= 1) {
11915 : DCHECK(vector_length == 0 ||
11916 : static_cast<uint8_t>(chars.start()[0]) <=
11917 : unibrow::Utf8::kMaxOneByteChar);
11918 42417 : *utf16_length_out = vector_length;
11919 42417 : return HashSequentialString(chars.start(), vector_length, seed);
11920 : }
11921 : // Start with a fake length which won't affect computation.
11922 : // It will be updated later.
11923 : StringHasher hasher(String::kMaxArrayIndexSize, seed);
11924 24480373 : size_t remaining = static_cast<size_t>(vector_length);
11925 : const uint8_t* stream = reinterpret_cast<const uint8_t*>(chars.start());
11926 : int utf16_length = 0;
11927 : bool is_index = true;
11928 : DCHECK(hasher.is_array_index_);
11929 576556721 : while (remaining > 0) {
11930 527595976 : size_t consumed = 0;
11931 527595976 : uint32_t c = unibrow::Utf8::ValueOf(stream, remaining, &consumed);
11932 : DCHECK(consumed > 0 && consumed <= remaining);
11933 527595976 : stream += consumed;
11934 527595976 : remaining -= consumed;
11935 527595976 : bool is_two_characters = c > unibrow::Utf16::kMaxNonSurrogateCharCode;
11936 527595976 : utf16_length += is_two_characters ? 2 : 1;
11937 : // No need to keep hashing. But we do need to calculate utf16_length.
11938 527595976 : if (utf16_length > String::kMaxHashCalcLength) continue;
11939 527595976 : if (is_two_characters) {
11940 : uint16_t c1 = unibrow::Utf16::LeadSurrogate(c);
11941 : uint16_t c2 = unibrow::Utf16::TrailSurrogate(c);
11942 : hasher.AddCharacter(c1);
11943 : hasher.AddCharacter(c2);
11944 14 : if (is_index) is_index = hasher.UpdateIndex(c1);
11945 13 : if (is_index) is_index = hasher.UpdateIndex(c2);
11946 : } else {
11947 : hasher.AddCharacter(c);
11948 527595962 : if (is_index) is_index = hasher.UpdateIndex(c);
11949 : }
11950 : }
11951 24480372 : *utf16_length_out = static_cast<int>(utf16_length);
11952 : // Must set length here so that hash computation is correct.
11953 24480372 : hasher.length_ = utf16_length;
11954 24480372 : return hasher.GetHashField();
11955 : }
11956 :
11957 :
11958 2502618 : void IteratingStringHasher::VisitConsString(ConsString* cons_string) {
11959 : // Run small ConsStrings through ConsStringIterator.
11960 2502618 : if (cons_string->length() < 64) {
11961 : ConsStringIterator iter(cons_string);
11962 : int offset;
11963 : String* string;
11964 15013468 : while (nullptr != (string = iter.Next(&offset))) {
11965 : DCHECK_EQ(0, offset);
11966 12825768 : String::VisitFlat(this, string, 0);
11967 : }
11968 2502618 : return;
11969 : }
11970 : // Slow case.
11971 314918 : const int max_length = String::kMaxHashCalcLength;
11972 629836 : int length = std::min(cons_string->length(), max_length);
11973 314918 : if (cons_string->HasOnlyOneByteChars()) {
11974 280285 : uint8_t* buffer = new uint8_t[length];
11975 280285 : String::WriteToFlat(cons_string, buffer, 0, length);
11976 280285 : AddCharacters(buffer, length);
11977 280285 : delete[] buffer;
11978 : } else {
11979 34633 : uint16_t* buffer = new uint16_t[length];
11980 34633 : String::WriteToFlat(cons_string, buffer, 0, length);
11981 34633 : AddCharacters(buffer, length);
11982 34633 : delete[] buffer;
11983 : }
11984 : }
11985 :
11986 :
11987 51674 : void String::PrintOn(FILE* file) {
11988 : int length = this->length();
11989 4535154 : for (int i = 0; i < length; i++) {
11990 4483480 : PrintF(file, "%c", Get(i));
11991 : }
11992 51674 : }
11993 :
11994 :
11995 1413271 : int Map::Hash() {
11996 : // For performance reasons we only hash the 3 most variable fields of a map:
11997 : // constructor, prototype and bit_field2. For predictability reasons we
11998 : // use objects' offsets in respective pages for hashing instead of raw
11999 : // addresses.
12000 :
12001 : // Shift away the tag.
12002 2826542 : int hash = ObjectAddressForHashing(GetConstructor()) >> 2;
12003 :
12004 : // XOR-ing the prototype and constructor directly yields too many zero bits
12005 : // when the two pointers are close (which is fairly common).
12006 : // To avoid this we shift the prototype bits relatively to the constructor.
12007 1413271 : hash ^= ObjectAddressForHashing(prototype()) << (32 - kPageSizeBits);
12008 :
12009 2826542 : return hash ^ (hash >> 16) ^ bit_field2();
12010 : }
12011 :
12012 :
12013 : namespace {
12014 :
12015 2464500 : bool CheckEquivalent(Map* first, Map* second) {
12016 4873092 : return first->GetConstructor() == second->GetConstructor() &&
12017 2395584 : first->prototype() == second->prototype() &&
12018 2395556 : first->instance_type() == second->instance_type() &&
12019 2395556 : first->bit_field() == second->bit_field() &&
12020 2395367 : first->is_extensible() == second->is_extensible() &&
12021 4859837 : first->new_target_is_base() == second->new_target_is_base() &&
12022 2464500 : first->has_hidden_prototype() == second->has_hidden_prototype();
12023 : }
12024 :
12025 : } // namespace
12026 :
12027 :
12028 1496958 : bool Map::EquivalentToForTransition(Map* other) {
12029 1496958 : if (!CheckEquivalent(this, other)) return false;
12030 1496754 : if (instance_type() == JS_FUNCTION_TYPE) {
12031 : // JSFunctions require more checks to ensure that sloppy function is
12032 : // not equvalent to strict function.
12033 : int nof = Min(NumberOfOwnDescriptors(), other->NumberOfOwnDescriptors());
12034 : return instance_descriptors()->IsEqualUpTo(other->instance_descriptors(),
12035 8613 : nof);
12036 : }
12037 : return true;
12038 : }
12039 :
12040 :
12041 967542 : bool Map::EquivalentToForNormalization(Map* other,
12042 : PropertyNormalizationMode mode) {
12043 : int properties =
12044 967542 : mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other->GetInObjectProperties();
12045 2764708 : return CheckEquivalent(this, other) && bit_field2() == other->bit_field2() &&
12046 1720944 : GetInObjectProperties() == properties &&
12047 753402 : JSObject::GetEmbedderFieldCount(this) ==
12048 1720944 : JSObject::GetEmbedderFieldCount(other);
12049 : }
12050 :
12051 :
12052 24869981 : bool JSFunction::Inlines(SharedFunctionInfo* candidate) {
12053 : DisallowHeapAllocation no_gc;
12054 24869981 : if (shared() == candidate) return true;
12055 24855668 : if (code()->kind() != Code::OPTIMIZED_FUNCTION) return false;
12056 : DeoptimizationInputData* const data =
12057 : DeoptimizationInputData::cast(code()->deoptimization_data());
12058 231508 : if (data->length() == 0) return false;
12059 : FixedArray* const literals = data->LiteralArray();
12060 : int const inlined_count = data->InlinedFunctionCount()->value();
12061 254422 : for (int i = 0; i < inlined_count; ++i) {
12062 22971 : if (SharedFunctionInfo::cast(literals->get(i)) == candidate) {
12063 : return true;
12064 : }
12065 : }
12066 : return false;
12067 : }
12068 :
12069 1216932 : void JSFunction::MarkForOptimization() {
12070 : Isolate* isolate = GetIsolate();
12071 : DCHECK(!IsOptimized());
12072 : DCHECK(shared()->allows_lazy_compilation() ||
12073 : !shared()->optimization_disabled());
12074 : set_code_no_write_barrier(
12075 : isolate->builtins()->builtin(Builtins::kCompileOptimized));
12076 : // No write barrier required, since the builtin is part of the root set.
12077 1217690 : if (FLAG_mark_shared_functions_for_tier_up) {
12078 : shared()->set_marked_for_tier_up(true);
12079 : }
12080 1216932 : }
12081 :
12082 :
12083 141136 : void JSFunction::AttemptConcurrentOptimization() {
12084 281519 : Isolate* isolate = GetIsolate();
12085 281519 : if (!isolate->concurrent_recompilation_enabled() ||
12086 140383 : isolate->bootstrapper()->IsActive()) {
12087 : MarkForOptimization();
12088 141136 : return;
12089 : }
12090 : DCHECK(!IsInOptimizationQueue());
12091 : DCHECK(!IsOptimized());
12092 : DCHECK(shared()->allows_lazy_compilation() ||
12093 : !shared()->optimization_disabled());
12094 : DCHECK(isolate->concurrent_recompilation_enabled());
12095 140378 : if (FLAG_trace_concurrent_recompilation) {
12096 0 : PrintF(" ** Marking ");
12097 0 : ShortPrint();
12098 0 : PrintF(" for concurrent recompilation.\n");
12099 : }
12100 :
12101 : set_code_no_write_barrier(
12102 : isolate->builtins()->builtin(Builtins::kCompileOptimizedConcurrent));
12103 : // No write barrier required, since the builtin is part of the root set.
12104 140378 : if (FLAG_mark_shared_functions_for_tier_up) {
12105 : // TODO(leszeks): The compilation isn't concurrent if we trigger it using
12106 : // this bit.
12107 : shared()->set_marked_for_tier_up(true);
12108 : }
12109 : }
12110 :
12111 : // static
12112 278210 : void SharedFunctionInfo::AddToOptimizedCodeMap(
12113 : Handle<SharedFunctionInfo> shared, Handle<Context> native_context,
12114 : Handle<Code> code, BailoutId osr_ast_id) {
12115 278210 : Isolate* isolate = shared->GetIsolate();
12116 286599 : if (isolate->serializer_enabled()) return;
12117 : DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
12118 : DCHECK(native_context->IsNativeContext());
12119 : STATIC_ASSERT(kEntryLength == 2);
12120 : Handle<FixedArray> new_code_map;
12121 : int entry;
12122 :
12123 278210 : if (!osr_ast_id.IsNone()) {
12124 2546 : Context::AddToOptimizedCodeMap(native_context, shared, code, osr_ast_id);
12125 2546 : return;
12126 : }
12127 :
12128 : DCHECK(osr_ast_id.IsNone());
12129 275664 : if (shared->OptimizedCodeMapIsCleared()) {
12130 234368 : new_code_map = isolate->factory()->NewFixedArray(kInitialLength, TENURED);
12131 : entry = kEntriesStart;
12132 : } else {
12133 : Handle<FixedArray> old_code_map(shared->optimized_code_map(), isolate);
12134 41296 : entry = shared->SearchOptimizedCodeMapEntry(*native_context);
12135 41296 : if (entry >= kEntriesStart) {
12136 : // Just set the code of the entry.
12137 5843 : Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code);
12138 11686 : old_code_map->set(entry + kCachedCodeOffset, *code_cell);
12139 : return;
12140 : }
12141 :
12142 : // Can we reuse an entry?
12143 : DCHECK(entry < kEntriesStart);
12144 : int length = old_code_map->length();
12145 121555 : for (int i = kEntriesStart; i < length; i += kEntryLength) {
12146 90031 : if (WeakCell::cast(old_code_map->get(i + kContextOffset))->cleared()) {
12147 : new_code_map = old_code_map;
12148 : entry = i;
12149 : break;
12150 : }
12151 : }
12152 :
12153 35453 : if (entry < kEntriesStart) {
12154 : // Copy old optimized code map and append one new entry.
12155 : new_code_map = isolate->factory()->CopyFixedArrayAndGrow(
12156 31524 : old_code_map, kEntryLength, TENURED);
12157 : // TODO(mstarzinger): Temporary workaround. The allocation above might
12158 : // have flushed the optimized code map and the copy we created is full of
12159 : // holes. For now we just give up on adding the entry and pretend it got
12160 : // flushed.
12161 31524 : if (shared->OptimizedCodeMapIsCleared()) return;
12162 : entry = old_code_map->length();
12163 : }
12164 : }
12165 :
12166 269823 : Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code);
12167 : WeakCell* context_cell = native_context->self_weak_cell();
12168 :
12169 269822 : new_code_map->set(entry + kContextOffset, context_cell);
12170 539646 : new_code_map->set(entry + kCachedCodeOffset, *code_cell);
12171 :
12172 : #ifdef DEBUG
12173 : for (int i = kEntriesStart; i < new_code_map->length(); i += kEntryLength) {
12174 : WeakCell* cell = WeakCell::cast(new_code_map->get(i + kContextOffset));
12175 : DCHECK(cell->cleared() || cell->value()->IsNativeContext());
12176 : cell = WeakCell::cast(new_code_map->get(i + kCachedCodeOffset));
12177 : DCHECK(cell->cleared() ||
12178 : (cell->value()->IsCode() &&
12179 : Code::cast(cell->value())->kind() == Code::OPTIMIZED_FUNCTION));
12180 : }
12181 : #endif
12182 :
12183 : FixedArray* old_code_map = shared->optimized_code_map();
12184 269823 : if (old_code_map != *new_code_map) {
12185 265894 : shared->set_optimized_code_map(*new_code_map);
12186 : }
12187 : }
12188 :
12189 :
12190 295 : void SharedFunctionInfo::ClearOptimizedCodeMap() {
12191 295 : FixedArray* empty_fixed_array = GetHeap()->empty_fixed_array();
12192 295 : set_optimized_code_map(empty_fixed_array, SKIP_WRITE_BARRIER);
12193 295 : }
12194 :
12195 :
12196 447512 : void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
12197 : const char* reason) {
12198 : DisallowHeapAllocation no_gc;
12199 : Isolate* isolate = GetIsolate();
12200 : bool found = false;
12201 :
12202 447512 : if (!OptimizedCodeMapIsCleared()) {
12203 182186 : Heap* heap = isolate->heap();
12204 : FixedArray* code_map = optimized_code_map();
12205 : int length = code_map->length();
12206 548746 : for (int src = kEntriesStart; src < length; src += kEntryLength) {
12207 : DCHECK(WeakCell::cast(code_map->get(src))->cleared() ||
12208 : WeakCell::cast(code_map->get(src))->value()->IsNativeContext());
12209 331066 : found = WeakCell::cast(code_map->get(src + kCachedCodeOffset))->value() ==
12210 331066 : optimized_code;
12211 331066 : if (found) {
12212 182186 : if (FLAG_trace_opt) {
12213 0 : PrintF("[evicting entry from optimizing code map (%s) for ", reason);
12214 0 : ShortPrint();
12215 0 : PrintF("]\n");
12216 : }
12217 : // Just clear the code.
12218 : code_map->set(src + kCachedCodeOffset, heap->empty_weak_cell(),
12219 182186 : SKIP_WRITE_BARRIER);
12220 : }
12221 : }
12222 : }
12223 :
12224 447512 : if (!found) {
12225 : // We didn't find the code in here. It must be osr'd code.
12226 283556 : isolate->EvictOSROptimizedCode(optimized_code, reason);
12227 : }
12228 447512 : }
12229 :
12230 : // static
12231 18762118 : void JSFunction::EnsureLiterals(Handle<JSFunction> function) {
12232 : Handle<SharedFunctionInfo> shared(function->shared());
12233 : Isolate* isolate = shared->GetIsolate();
12234 :
12235 18762135 : FeedbackVectorState state = function->GetFeedbackVectorState(isolate);
12236 18762133 : switch (state) {
12237 : case TOP_LEVEL_SCRIPT_NEEDS_VECTOR: {
12238 : // A top level script didn't get it's literals installed.
12239 : Handle<FeedbackVector> feedback_vector =
12240 6123928 : FeedbackVector::New(isolate, shared);
12241 : Handle<Cell> new_cell =
12242 6123935 : isolate->factory()->NewOneClosureCell(feedback_vector);
12243 6123931 : function->set_feedback_vector_cell(*new_cell);
12244 : break;
12245 : }
12246 : case NEEDS_VECTOR: {
12247 : Handle<FeedbackVector> feedback_vector =
12248 2401017 : FeedbackVector::New(isolate, shared);
12249 2401017 : function->feedback_vector_cell()->set_value(*feedback_vector);
12250 : break;
12251 : }
12252 : case HAS_VECTOR:
12253 : // Nothing to do.
12254 : break;
12255 : }
12256 18762135 : }
12257 :
12258 344769 : static void GetMinInobjectSlack(Map* map, void* data) {
12259 : int slack = map->unused_property_fields();
12260 344769 : if (*reinterpret_cast<int*>(data) > slack) {
12261 88744 : *reinterpret_cast<int*>(data) = slack;
12262 : }
12263 344769 : }
12264 :
12265 :
12266 337412 : static void ShrinkInstanceSize(Map* map, void* data) {
12267 337412 : int slack = *reinterpret_cast<int*>(data);
12268 337412 : map->SetInObjectProperties(map->GetInObjectProperties() - slack);
12269 337412 : map->set_unused_property_fields(map->unused_property_fields() - slack);
12270 337412 : map->set_instance_size(map->instance_size() - slack * kPointerSize);
12271 : map->set_construction_counter(Map::kNoSlackTracking);
12272 :
12273 : // Visitor id might depend on the instance size, recalculate it.
12274 337412 : map->set_visitor_id(Heap::GetStaticVisitorIdForMap(map));
12275 337412 : }
12276 :
12277 7357 : static void StopSlackTracking(Map* map, void* data) {
12278 : map->set_construction_counter(Map::kNoSlackTracking);
12279 7357 : }
12280 :
12281 93061 : void Map::CompleteInobjectSlackTracking() {
12282 : // Has to be an initial map.
12283 : DCHECK(GetBackPointer()->IsUndefined(GetIsolate()));
12284 :
12285 93061 : int slack = unused_property_fields();
12286 : TransitionArray::TraverseTransitionTree(this, &GetMinInobjectSlack, &slack);
12287 93061 : if (slack != 0) {
12288 : // Resize the initial map and all maps in its transition tree.
12289 : TransitionArray::TraverseTransitionTree(this, &ShrinkInstanceSize, &slack);
12290 : } else {
12291 : TransitionArray::TraverseTransitionTree(this, &StopSlackTracking, nullptr);
12292 : }
12293 93061 : }
12294 :
12295 :
12296 27787179 : static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) {
12297 : DisallowHeapAllocation no_gc;
12298 27787179 : if (!object->HasFastProperties()) return false;
12299 26487005 : if (object->IsJSGlobalProxy()) return false;
12300 26454752 : if (object->GetIsolate()->bootstrapper()->IsActive()) return false;
12301 11506444 : return !object->map()->is_prototype_map() ||
12302 11506444 : !object->map()->should_be_fast_prototype_map();
12303 : }
12304 :
12305 : // static
12306 5955150 : void JSObject::MakePrototypesFast(Handle<Object> receiver,
12307 : WhereToStart where_to_start,
12308 : Isolate* isolate) {
12309 5955150 : if (!receiver->IsJSReceiver()) return;
12310 15995450 : for (PrototypeIterator iter(isolate, Handle<JSReceiver>::cast(receiver),
12311 5885809 : where_to_start);
12312 14333473 : !iter.IsAtEnd(); iter.Advance()) {
12313 : Handle<Object> current = PrototypeIterator::GetCurrent(iter);
12314 9630426 : if (!current->IsJSObject()) return;
12315 : Handle<JSObject> current_obj = Handle<JSObject>::cast(current);
12316 : Map* current_map = current_obj->map();
12317 9624522 : if (current_map->is_prototype_map()) {
12318 : // If the map is already marked as should be fast, we're done. Its
12319 : // prototypes will have been marked already as well.
12320 11132049 : if (current_map->should_be_fast_prototype_map()) return;
12321 : Handle<Map> map(current_map);
12322 330669 : Map::SetShouldBeFastPrototypeMap(map, true, isolate);
12323 330669 : JSObject::OptimizeAsPrototype(current_obj, FAST_PROTOTYPE);
12324 : }
12325 : }
12326 : }
12327 :
12328 : // static
12329 27973272 : void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
12330 : PrototypeOptimizationMode mode) {
12331 55946542 : if (object->IsJSGlobalObject()) return;
12332 27856965 : if (mode == FAST_PROTOTYPE && PrototypeBenefitsFromNormalization(object)) {
12333 : // First normalize to ensure all JSFunctions are DATA_CONSTANT.
12334 : JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0,
12335 594868 : "NormalizeAsPrototype");
12336 : }
12337 : Handle<Map> previous_map(object->map());
12338 27856956 : if (object->map()->is_prototype_map()) {
12339 39995226 : if (object->map()->should_be_fast_prototype_map() &&
12340 17144557 : !object->HasFastProperties()) {
12341 293697 : JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype");
12342 : }
12343 : } else {
12344 5006289 : if (object->map() == *previous_map) {
12345 5006286 : Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype");
12346 5006288 : JSObject::MigrateToMap(object, new_map);
12347 : }
12348 : object->map()->set_is_prototype_map(true);
12349 :
12350 : // Replace the pointer to the exact constructor with the Object function
12351 : // from the same context if undetectable from JS. This is to avoid keeping
12352 : // memory alive unnecessarily.
12353 5006294 : Object* maybe_constructor = object->map()->GetConstructor();
12354 5006290 : if (maybe_constructor->IsJSFunction()) {
12355 : JSFunction* constructor = JSFunction::cast(maybe_constructor);
12356 : Isolate* isolate = object->GetIsolate();
12357 9517870 : if (!constructor->shared()->IsApiFunction() &&
12358 4515444 : object->class_name() == isolate->heap()->Object_string()) {
12359 : Context* context = constructor->context()->native_context();
12360 : JSFunction* object_function = context->object_function();
12361 : object->map()->SetConstructor(object_function);
12362 : }
12363 : }
12364 : }
12365 : }
12366 :
12367 :
12368 : // static
12369 6584382 : void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) {
12370 6584382 : if (!object->map()->is_prototype_map()) return;
12371 90338 : if (!object->map()->should_be_fast_prototype_map()) return;
12372 60333 : OptimizeAsPrototype(object, FAST_PROTOTYPE);
12373 : }
12374 :
12375 :
12376 : // static
12377 3015481 : void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
12378 : // Contract: In line with InvalidatePrototypeChains()'s requirements,
12379 : // leaf maps don't need to register as users, only prototypes do.
12380 : DCHECK(user->is_prototype_map());
12381 :
12382 3015481 : Handle<Map> current_user = user;
12383 : Handle<PrototypeInfo> current_user_info =
12384 3015481 : Map::GetOrCreatePrototypeInfo(user, isolate);
12385 7029262 : for (PrototypeIterator iter(user); !iter.IsAtEnd(); iter.Advance()) {
12386 : // Walk up the prototype chain as far as links haven't been registered yet.
12387 2912961 : if (current_user_info->registry_slot() != PrototypeInfo::UNREGISTERED) {
12388 : break;
12389 : }
12390 : Handle<Object> maybe_proto = PrototypeIterator::GetCurrent(iter);
12391 : // Proxies on the prototype chain are not supported. They make it
12392 : // impossible to make any assumptions about the prototype chain anyway.
12393 3514715 : if (maybe_proto->IsJSProxy()) return;
12394 : Handle<JSObject> proto = Handle<JSObject>::cast(maybe_proto);
12395 : Handle<PrototypeInfo> proto_info =
12396 499150 : Map::GetOrCreatePrototypeInfo(proto, isolate);
12397 : Handle<Object> maybe_registry(proto_info->prototype_users(), isolate);
12398 499150 : int slot = 0;
12399 : Handle<WeakFixedArray> new_array =
12400 499150 : WeakFixedArray::Add(maybe_registry, current_user, &slot);
12401 499150 : current_user_info->set_registry_slot(slot);
12402 499150 : if (!maybe_registry.is_identical_to(new_array)) {
12403 151293 : proto_info->set_prototype_users(*new_array);
12404 : }
12405 499150 : if (FLAG_trace_prototype_users) {
12406 : PrintF("Registering %p as a user of prototype %p (map=%p).\n",
12407 : reinterpret_cast<void*>(*current_user),
12408 : reinterpret_cast<void*>(*proto),
12409 0 : reinterpret_cast<void*>(proto->map()));
12410 : }
12411 :
12412 : current_user = handle(proto->map(), isolate);
12413 : current_user_info = proto_info;
12414 : }
12415 : }
12416 :
12417 :
12418 : // Can be called regardless of whether |user| was actually registered with
12419 : // |prototype|. Returns true when there was a registration.
12420 : // static
12421 5501812 : bool JSObject::UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
12422 : DCHECK(user->is_prototype_map());
12423 : // If it doesn't have a PrototypeInfo, it was never registered.
12424 5501812 : if (!user->prototype_info()->IsPrototypeInfo()) return false;
12425 : // If it had no prototype before, see if it had users that might expect
12426 : // registration.
12427 540766 : if (!user->prototype()->IsJSObject()) {
12428 : Object* users =
12429 : PrototypeInfo::cast(user->prototype_info())->prototype_users();
12430 112479 : return users->IsWeakFixedArray();
12431 : }
12432 : Handle<JSObject> prototype(JSObject::cast(user->prototype()), isolate);
12433 : Handle<PrototypeInfo> user_info =
12434 428287 : Map::GetOrCreatePrototypeInfo(user, isolate);
12435 : int slot = user_info->registry_slot();
12436 428287 : if (slot == PrototypeInfo::UNREGISTERED) return false;
12437 : DCHECK(prototype->map()->is_prototype_map());
12438 : Object* maybe_proto_info = prototype->map()->prototype_info();
12439 : // User knows its registry slot, prototype info and user registry must exist.
12440 : DCHECK(maybe_proto_info->IsPrototypeInfo());
12441 : Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info),
12442 : isolate);
12443 : Object* maybe_registry = proto_info->prototype_users();
12444 : DCHECK(maybe_registry->IsWeakFixedArray());
12445 : DCHECK(WeakFixedArray::cast(maybe_registry)->Get(slot) == *user);
12446 : WeakFixedArray::cast(maybe_registry)->Clear(slot);
12447 176268 : if (FLAG_trace_prototype_users) {
12448 : PrintF("Unregistering %p as a user of prototype %p.\n",
12449 0 : reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype));
12450 : }
12451 : return true;
12452 : }
12453 :
12454 :
12455 5741199 : static void InvalidatePrototypeChainsInternal(Map* map) {
12456 : DCHECK(map->is_prototype_map());
12457 5741199 : if (FLAG_trace_prototype_users) {
12458 : PrintF("Invalidating prototype map %p 's cell\n",
12459 0 : reinterpret_cast<void*>(map));
12460 : }
12461 : Object* maybe_proto_info = map->prototype_info();
12462 10702776 : if (!maybe_proto_info->IsPrototypeInfo()) return;
12463 : PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info);
12464 : Object* maybe_cell = proto_info->validity_cell();
12465 779622 : if (maybe_cell->IsCell()) {
12466 : // Just set the value; the cell will be replaced lazily.
12467 : Cell* cell = Cell::cast(maybe_cell);
12468 503529 : cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid));
12469 : }
12470 :
12471 : WeakFixedArray::Iterator iterator(proto_info->prototype_users());
12472 : // For now, only maps register themselves as users.
12473 : Map* user;
12474 1017462 : while ((user = iterator.Next<Map>()) != nullptr) {
12475 : // Walk the prototype chain (backwards, towards leaf objects) if necessary.
12476 237840 : InvalidatePrototypeChainsInternal(user);
12477 : }
12478 : }
12479 :
12480 :
12481 : // static
12482 0 : void JSObject::InvalidatePrototypeChains(Map* map) {
12483 : DisallowHeapAllocation no_gc;
12484 5503359 : InvalidatePrototypeChainsInternal(map);
12485 0 : }
12486 :
12487 :
12488 : // static
12489 4626005 : Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<JSObject> prototype,
12490 : Isolate* isolate) {
12491 : Object* maybe_proto_info = prototype->map()->prototype_info();
12492 4626005 : if (maybe_proto_info->IsPrototypeInfo()) {
12493 : return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
12494 : }
12495 196879 : Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
12496 196879 : prototype->map()->set_prototype_info(*proto_info);
12497 196879 : return proto_info;
12498 : }
12499 :
12500 :
12501 : // static
12502 3775133 : Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<Map> prototype_map,
12503 : Isolate* isolate) {
12504 : Object* maybe_proto_info = prototype_map->prototype_info();
12505 3775133 : if (maybe_proto_info->IsPrototypeInfo()) {
12506 : return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
12507 : }
12508 303861 : Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
12509 303861 : prototype_map->set_prototype_info(*proto_info);
12510 303861 : return proto_info;
12511 : }
12512 :
12513 : // static
12514 331365 : void Map::SetShouldBeFastPrototypeMap(Handle<Map> map, bool value,
12515 : Isolate* isolate) {
12516 331365 : if (value == false && !map->prototype_info()->IsPrototypeInfo()) {
12517 : // "False" is the implicit default value, so there's nothing to do.
12518 331365 : return;
12519 : }
12520 662730 : GetOrCreatePrototypeInfo(map, isolate)->set_should_be_fast_map(value);
12521 : }
12522 :
12523 : // static
12524 3069102 : Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
12525 : Isolate* isolate) {
12526 : Handle<Object> maybe_prototype;
12527 3069102 : if (map->IsJSGlobalObjectMap()) {
12528 : DCHECK(map->is_prototype_map());
12529 : // Global object is prototype of a global proxy and therefore we can
12530 : // use its validity cell for guarding global object's prototype change.
12531 2869 : maybe_prototype = isolate->global_object();
12532 : } else {
12533 : maybe_prototype =
12534 3066233 : handle(map->GetPrototypeChainRootMap(isolate)->prototype(), isolate);
12535 3066234 : if (!maybe_prototype->IsJSObject()) return Handle<Cell>::null();
12536 : }
12537 : Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype);
12538 : // Ensure the prototype is registered with its own prototypes so its cell
12539 : // will be invalidated when necessary.
12540 : JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate),
12541 2730939 : isolate);
12542 : Handle<PrototypeInfo> proto_info =
12543 2730939 : GetOrCreatePrototypeInfo(prototype, isolate);
12544 : Object* maybe_cell = proto_info->validity_cell();
12545 : // Return existing cell if it's still valid.
12546 2730939 : if (maybe_cell->IsCell()) {
12547 : Handle<Cell> cell(Cell::cast(maybe_cell), isolate);
12548 2458054 : if (cell->value() == Smi::FromInt(Map::kPrototypeChainValid)) {
12549 2403976 : return cell;
12550 : }
12551 : }
12552 : // Otherwise create a new cell.
12553 : Handle<Cell> cell = isolate->factory()->NewCell(
12554 326963 : handle(Smi::FromInt(Map::kPrototypeChainValid), isolate));
12555 326963 : proto_info->set_validity_cell(*cell);
12556 326963 : return cell;
12557 : }
12558 :
12559 : // static
12560 1208300 : Handle<WeakCell> Map::GetOrCreatePrototypeWeakCell(Handle<JSObject> prototype,
12561 : Isolate* isolate) {
12562 : DCHECK(!prototype.is_null());
12563 : Handle<PrototypeInfo> proto_info =
12564 1208300 : GetOrCreatePrototypeInfo(prototype, isolate);
12565 : Object* maybe_cell = proto_info->weak_cell();
12566 : // Return existing cell if it's already created.
12567 1208300 : if (maybe_cell->IsWeakCell()) {
12568 : Handle<WeakCell> cell(WeakCell::cast(maybe_cell), isolate);
12569 : DCHECK(!cell->cleared());
12570 1052375 : return cell;
12571 : }
12572 : // Otherwise create a new cell.
12573 155925 : Handle<WeakCell> cell = isolate->factory()->NewWeakCell(prototype);
12574 155925 : proto_info->set_weak_cell(*cell);
12575 155925 : return cell;
12576 : }
12577 :
12578 : // static
12579 31795677 : void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype,
12580 : PrototypeOptimizationMode proto_mode) {
12581 31795677 : RuntimeCallTimerScope stats_scope(*map, &RuntimeCallStats::Map_SetPrototype);
12582 :
12583 : bool is_hidden = false;
12584 31795696 : if (prototype->IsJSObject()) {
12585 : Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype);
12586 26617447 : JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode);
12587 :
12588 26617444 : Object* maybe_constructor = prototype_jsobj->map()->GetConstructor();
12589 26617446 : if (maybe_constructor->IsJSFunction()) {
12590 : JSFunction* constructor = JSFunction::cast(maybe_constructor);
12591 : Object* data = constructor->shared()->function_data();
12592 715242 : is_hidden = (data->IsFunctionTemplateInfo() &&
12593 48569129 : FunctionTemplateInfo::cast(data)->hidden_prototype()) ||
12594 : prototype->IsJSGlobalObject();
12595 2332717 : } else if (maybe_constructor->IsFunctionTemplateInfo()) {
12596 : is_hidden =
12597 48 : FunctionTemplateInfo::cast(maybe_constructor)->hidden_prototype() ||
12598 : prototype->IsJSGlobalObject();
12599 : }
12600 : }
12601 : map->set_has_hidden_prototype(is_hidden);
12602 :
12603 : WriteBarrierMode wb_mode = prototype->IsNull(map->GetIsolate())
12604 : ? SKIP_WRITE_BARRIER
12605 31795691 : : UPDATE_WRITE_BARRIER;
12606 31795691 : map->set_prototype(*prototype, wb_mode);
12607 31795689 : }
12608 :
12609 :
12610 158 : Handle<Object> CacheInitialJSArrayMaps(
12611 : Handle<Context> native_context, Handle<Map> initial_map) {
12612 : // Replace all of the cached initial array maps in the native context with
12613 : // the appropriate transitioned elements kind maps.
12614 158 : Handle<Map> current_map = initial_map;
12615 : ElementsKind kind = current_map->elements_kind();
12616 : DCHECK_EQ(GetInitialFastElementsKind(), kind);
12617 158 : native_context->set(Context::ArrayMapIndex(kind), *current_map);
12618 948 : for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1;
12619 : i < kFastElementsKindCount; ++i) {
12620 : Handle<Map> new_map;
12621 790 : ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
12622 790 : if (Map* maybe_elements_transition = current_map->ElementsTransitionMap()) {
12623 : new_map = handle(maybe_elements_transition);
12624 : } else {
12625 : new_map = Map::CopyAsElementsKind(
12626 790 : current_map, next_kind, INSERT_TRANSITION);
12627 : }
12628 : DCHECK_EQ(next_kind, new_map->elements_kind());
12629 790 : native_context->set(Context::ArrayMapIndex(next_kind), *new_map);
12630 : current_map = new_map;
12631 : }
12632 158 : return initial_map;
12633 : }
12634 :
12635 : namespace {
12636 :
12637 696453 : void SetInstancePrototype(Isolate* isolate, Handle<JSFunction> function,
12638 : Handle<JSReceiver> value) {
12639 : // Now some logic for the maps of the objects that are created by using this
12640 : // function as a constructor.
12641 696453 : if (function->has_initial_map()) {
12642 : // If the function has allocated the initial map replace it with a
12643 : // copy containing the new prototype. Also complete any in-object
12644 : // slack tracking that is in progress at this point because it is
12645 : // still tracking the old copy.
12646 42846 : function->CompleteInobjectSlackTrackingIfActive();
12647 :
12648 : Handle<Map> initial_map(function->initial_map(), isolate);
12649 :
12650 83164 : if (!initial_map->GetIsolate()->bootstrapper()->IsActive() &&
12651 : initial_map->instance_type() == JS_OBJECT_TYPE) {
12652 : // Put the value in the initial map field until an initial map is needed.
12653 : // At that point, a new initial map is created and the prototype is put
12654 : // into the initial map where it belongs.
12655 39954 : function->set_prototype_or_initial_map(*value);
12656 : } else {
12657 2892 : Handle<Map> new_map = Map::Copy(initial_map, "SetInstancePrototype");
12658 2892 : JSFunction::SetInitialMap(function, new_map, value);
12659 :
12660 : // If the function is used as the global Array function, cache the
12661 : // updated initial maps (and transitioned versions) in the native context.
12662 : Handle<Context> native_context(function->context()->native_context(),
12663 : isolate);
12664 : Handle<Object> array_function(
12665 : native_context->get(Context::ARRAY_FUNCTION_INDEX), isolate);
12666 5705 : if (array_function->IsJSFunction() &&
12667 : *function == JSFunction::cast(*array_function)) {
12668 79 : CacheInitialJSArrayMaps(native_context, new_map);
12669 : }
12670 : }
12671 :
12672 : // Deoptimize all code that embeds the previous initial map.
12673 : initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
12674 42846 : isolate, DependentCode::kInitialMapChangedGroup);
12675 : } else {
12676 : // Put the value in the initial map field until an initial map is
12677 : // needed. At that point, a new initial map is created and the
12678 : // prototype is put into the initial map where it belongs.
12679 653607 : function->set_prototype_or_initial_map(*value);
12680 653607 : if (value->IsJSObject()) {
12681 : // Optimize as prototype to detach it from its transition tree.
12682 : JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value),
12683 653509 : FAST_PROTOTYPE);
12684 : }
12685 : }
12686 : isolate->heap()->ClearInstanceofCache();
12687 696453 : }
12688 :
12689 : } // anonymous namespace
12690 :
12691 696452 : void JSFunction::SetPrototype(Handle<JSFunction> function,
12692 : Handle<Object> value) {
12693 : DCHECK(function->IsConstructor() ||
12694 : IsGeneratorFunction(function->shared()->kind()));
12695 : Isolate* isolate = function->GetIsolate();
12696 : Handle<JSReceiver> construct_prototype;
12697 :
12698 : // If the value is not a JSReceiver, store the value in the map's
12699 : // constructor field so it can be accessed. Also, set the prototype
12700 : // used for constructing objects to the original object prototype.
12701 : // See ECMA-262 13.2.2.
12702 696453 : if (!value->IsJSReceiver()) {
12703 : // Copy the map so this does not affect unrelated functions.
12704 : // Remove map transitions because they point to maps with a
12705 : // different prototype.
12706 6612 : Handle<Map> new_map = Map::Copy(handle(function->map()), "SetPrototype");
12707 :
12708 6612 : JSObject::MigrateToMap(function, new_map);
12709 : new_map->SetConstructor(*value);
12710 : new_map->set_non_instance_prototype(true);
12711 :
12712 : FunctionKind kind = function->shared()->kind();
12713 : Handle<Context> native_context(function->context()->native_context());
12714 :
12715 : construct_prototype = Handle<JSReceiver>(
12716 : IsGeneratorFunction(kind)
12717 : ? IsAsyncFunction(kind)
12718 : ? native_context->initial_async_generator_prototype()
12719 : : native_context->initial_generator_prototype()
12720 : : native_context->initial_object_prototype(),
12721 13238 : isolate);
12722 : } else {
12723 689841 : construct_prototype = Handle<JSReceiver>::cast(value);
12724 : function->map()->set_non_instance_prototype(false);
12725 : }
12726 :
12727 696453 : SetInstancePrototype(isolate, function, construct_prototype);
12728 696452 : }
12729 :
12730 :
12731 46991 : bool JSFunction::RemovePrototype() {
12732 : Context* native_context = context()->native_context();
12733 : Map* no_prototype_map =
12734 : is_strict(shared()->language_mode())
12735 : ? native_context->strict_function_without_prototype_map()
12736 46991 : : native_context->sloppy_function_without_prototype_map();
12737 :
12738 46991 : if (map() == no_prototype_map) return true;
12739 :
12740 : #ifdef DEBUG
12741 : if (map() != (is_strict(shared()->language_mode())
12742 : ? native_context->strict_function_map()
12743 : : native_context->sloppy_function_map())) {
12744 : return false;
12745 : }
12746 : #endif
12747 :
12748 46043 : set_map(no_prototype_map);
12749 46043 : set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value());
12750 46043 : return true;
12751 : }
12752 :
12753 :
12754 4864647 : void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
12755 : Handle<Object> prototype) {
12756 4864647 : if (map->prototype() != *prototype) {
12757 4864006 : Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
12758 : }
12759 4864649 : function->set_prototype_or_initial_map(*map);
12760 : map->SetConstructor(*function);
12761 : #if TRACE_MAPS
12762 : if (FLAG_trace_maps) {
12763 : PrintF("[TraceMaps: InitialMap map= %p SFI= %d_%s ]\n",
12764 : reinterpret_cast<void*>(*map), function->shared()->unique_id(),
12765 : function->shared()->DebugName()->ToCString().get());
12766 : }
12767 : #endif
12768 4864653 : }
12769 :
12770 :
12771 : #ifdef DEBUG
12772 : namespace {
12773 :
12774 : bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
12775 : switch (instance_type) {
12776 : case JS_API_OBJECT_TYPE:
12777 : case JS_ARRAY_BUFFER_TYPE:
12778 : case JS_ARRAY_TYPE:
12779 : case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
12780 : case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
12781 : case JS_DATA_VIEW_TYPE:
12782 : case JS_DATE_TYPE:
12783 : case JS_FUNCTION_TYPE:
12784 : case JS_GENERATOR_OBJECT_TYPE:
12785 : case JS_ASYNC_GENERATOR_OBJECT_TYPE:
12786 : case JS_MAP_ITERATOR_TYPE:
12787 : case JS_MAP_TYPE:
12788 : case JS_MESSAGE_OBJECT_TYPE:
12789 : case JS_OBJECT_TYPE:
12790 : case JS_ERROR_TYPE:
12791 : case JS_ARGUMENTS_TYPE:
12792 : case JS_PROMISE_TYPE:
12793 : case JS_REGEXP_TYPE:
12794 : case JS_SET_ITERATOR_TYPE:
12795 : case JS_SET_TYPE:
12796 : case JS_SPECIAL_API_OBJECT_TYPE:
12797 : case JS_TYPED_ARRAY_TYPE:
12798 : case JS_VALUE_TYPE:
12799 : case JS_WEAK_MAP_TYPE:
12800 : case JS_WEAK_SET_TYPE:
12801 : return true;
12802 :
12803 : case BYTECODE_ARRAY_TYPE:
12804 : case BYTE_ARRAY_TYPE:
12805 : case CELL_TYPE:
12806 : case CODE_TYPE:
12807 : case FILLER_TYPE:
12808 : case FIXED_ARRAY_TYPE:
12809 : case FIXED_DOUBLE_ARRAY_TYPE:
12810 : case FOREIGN_TYPE:
12811 : case FREE_SPACE_TYPE:
12812 : case HEAP_NUMBER_TYPE:
12813 : case JS_BOUND_FUNCTION_TYPE:
12814 : case JS_GLOBAL_OBJECT_TYPE:
12815 : case JS_GLOBAL_PROXY_TYPE:
12816 : case JS_PROXY_TYPE:
12817 : case MAP_TYPE:
12818 : case MUTABLE_HEAP_NUMBER_TYPE:
12819 : case ODDBALL_TYPE:
12820 : case PROPERTY_CELL_TYPE:
12821 : case SHARED_FUNCTION_INFO_TYPE:
12822 : case SYMBOL_TYPE:
12823 : case WEAK_CELL_TYPE:
12824 :
12825 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
12826 : case FIXED_##TYPE##_ARRAY_TYPE:
12827 : #undef TYPED_ARRAY_CASE
12828 :
12829 : #define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE:
12830 : STRUCT_LIST(MAKE_STRUCT_CASE)
12831 : #undef MAKE_STRUCT_CASE
12832 : // We must not end up here for these instance types at all.
12833 : UNREACHABLE();
12834 : // Fall through.
12835 : default:
12836 : return false;
12837 : }
12838 : }
12839 :
12840 : } // namespace
12841 : #endif
12842 :
12843 :
12844 20823967 : void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
12845 : DCHECK(function->IsConstructor() ||
12846 : IsResumableFunction(function->shared()->kind()));
12847 41157828 : if (function->has_initial_map()) return;
12848 : Isolate* isolate = function->GetIsolate();
12849 :
12850 : // First create a new map with the size and number of in-object properties
12851 : // suggested by the function.
12852 : InstanceType instance_type;
12853 490109 : if (IsResumableFunction(function->shared()->kind())) {
12854 : instance_type = IsAsyncGeneratorFunction(function->shared()->kind())
12855 : ? JS_ASYNC_GENERATOR_OBJECT_TYPE
12856 19742 : : JS_GENERATOR_OBJECT_TYPE;
12857 : } else {
12858 : instance_type = JS_OBJECT_TYPE;
12859 : }
12860 :
12861 : // The constructor should be compiled for the optimization hints to be
12862 : // available.
12863 : int expected_nof_properties = 0;
12864 584479 : if (function->shared()->is_compiled() ||
12865 94370 : Compiler::Compile(function, Compiler::CLEAR_EXCEPTION)) {
12866 : DCHECK(function->shared()->is_compiled());
12867 : expected_nof_properties = function->shared()->expected_nof_properties();
12868 : }
12869 :
12870 : int instance_size;
12871 : int in_object_properties;
12872 : CalculateInstanceSizeHelper(instance_type, 0, expected_nof_properties,
12873 490109 : &instance_size, &in_object_properties);
12874 :
12875 490109 : Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size);
12876 :
12877 : // Fetch or allocate prototype.
12878 : Handle<Object> prototype;
12879 490109 : if (function->has_instance_prototype()) {
12880 391572 : prototype = handle(function->instance_prototype(), isolate);
12881 : } else {
12882 98537 : prototype = isolate->factory()->NewFunctionPrototype(function);
12883 : }
12884 490109 : map->SetInObjectProperties(in_object_properties);
12885 : map->set_unused_property_fields(in_object_properties);
12886 : DCHECK(map->has_fast_object_elements());
12887 :
12888 : // Finally link initial map and constructor function.
12889 : DCHECK(prototype->IsJSReceiver());
12890 490109 : JSFunction::SetInitialMap(function, map, prototype);
12891 : map->StartInobjectSlackTracking();
12892 : }
12893 :
12894 :
12895 : // static
12896 3982599 : MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
12897 : Handle<JSFunction> constructor,
12898 : Handle<JSReceiver> new_target) {
12899 3982599 : EnsureHasInitialMap(constructor);
12900 :
12901 : Handle<Map> constructor_initial_map(constructor->initial_map(), isolate);
12902 3982599 : if (*new_target == *constructor) return constructor_initial_map;
12903 :
12904 : // Fast case, new.target is a subclass of constructor. The map is cacheable
12905 : // (and may already have been cached). new.target.prototype is guaranteed to
12906 : // be a JSReceiver.
12907 133653 : if (new_target->IsJSFunction()) {
12908 : Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
12909 :
12910 : // Check that |function|'s initial map still in sync with the |constructor|,
12911 : // otherwise we must create a new initial map for |function|.
12912 255170 : if (function->has_initial_map() &&
12913 121849 : function->initial_map()->GetConstructor() == *constructor) {
12914 : return handle(function->initial_map(), isolate);
12915 : }
12916 :
12917 : // Create a new map with the size and number of in-object properties
12918 : // suggested by |function|.
12919 :
12920 : // Link initial map and constructor function if the new.target is actually a
12921 : // subclass constructor.
12922 11664 : if (IsDerivedConstructor(function->shared()->kind())) {
12923 : Handle<Object> prototype(function->instance_prototype(), isolate);
12924 : InstanceType instance_type = constructor_initial_map->instance_type();
12925 : DCHECK(CanSubclassHaveInobjectProperties(instance_type));
12926 : int embedder_fields =
12927 9296 : JSObject::GetEmbedderFieldCount(*constructor_initial_map);
12928 : int pre_allocated = constructor_initial_map->GetInObjectProperties() -
12929 9296 : constructor_initial_map->unused_property_fields();
12930 : int instance_size;
12931 : int in_object_properties;
12932 : CalculateInstanceSizeForDerivedClass(function, instance_type,
12933 : embedder_fields, &instance_size,
12934 9296 : &in_object_properties);
12935 :
12936 9296 : int unused_property_fields = in_object_properties - pre_allocated;
12937 : Handle<Map> map =
12938 : Map::CopyInitialMap(constructor_initial_map, instance_size,
12939 9296 : in_object_properties, unused_property_fields);
12940 : map->set_new_target_is_base(false);
12941 :
12942 9296 : JSFunction::SetInitialMap(function, map, prototype);
12943 : map->SetConstructor(*constructor);
12944 : map->set_construction_counter(Map::kNoSlackTracking);
12945 : map->StartInobjectSlackTracking();
12946 : return map;
12947 : }
12948 : }
12949 :
12950 : // Slow path, new.target is either a proxy or can't cache the map.
12951 : // new.target.prototype is not guaranteed to be a JSReceiver, and may need to
12952 : // fall back to the intrinsicDefaultProto.
12953 : Handle<Object> prototype;
12954 2700 : if (new_target->IsJSFunction()) {
12955 : Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
12956 : // Make sure the new.target.prototype is cached.
12957 2368 : EnsureHasInitialMap(function);
12958 2368 : prototype = handle(function->prototype(), isolate);
12959 : } else {
12960 : Handle<String> prototype_string = isolate->factory()->prototype_string();
12961 664 : ASSIGN_RETURN_ON_EXCEPTION(
12962 : isolate, prototype,
12963 : JSReceiver::GetProperty(new_target, prototype_string), Map);
12964 : // The above prototype lookup might change the constructor and its
12965 : // prototype, hence we have to reload the initial map.
12966 287 : EnsureHasInitialMap(constructor);
12967 : constructor_initial_map = handle(constructor->initial_map(), isolate);
12968 : }
12969 :
12970 : // If prototype is not a JSReceiver, fetch the intrinsicDefaultProto from the
12971 : // correct realm. Rather than directly fetching the .prototype, we fetch the
12972 : // constructor that points to the .prototype. This relies on
12973 : // constructor.prototype being FROZEN for those constructors.
12974 2655 : if (!prototype->IsJSReceiver()) {
12975 : Handle<Context> context;
12976 4090 : ASSIGN_RETURN_ON_EXCEPTION(isolate, context,
12977 : JSReceiver::GetFunctionRealm(new_target), Map);
12978 : DCHECK(context->IsNativeContext());
12979 : Handle<Object> maybe_index = JSReceiver::GetDataProperty(
12980 2045 : constructor, isolate->factory()->native_context_index_symbol());
12981 : int index = maybe_index->IsSmi() ? Smi::cast(*maybe_index)->value()
12982 2045 : : Context::OBJECT_FUNCTION_INDEX;
12983 : Handle<JSFunction> realm_constructor(JSFunction::cast(context->get(index)));
12984 2045 : prototype = handle(realm_constructor->prototype(), isolate);
12985 : }
12986 :
12987 2655 : Handle<Map> map = Map::CopyInitialMap(constructor_initial_map);
12988 : map->set_new_target_is_base(false);
12989 : DCHECK(prototype->IsJSReceiver());
12990 2655 : if (map->prototype() != *prototype) {
12991 1489 : Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
12992 : }
12993 : map->SetConstructor(*constructor);
12994 : return map;
12995 : }
12996 :
12997 :
12998 0 : void JSFunction::PrintName(FILE* out) {
12999 0 : std::unique_ptr<char[]> name = shared()->DebugName()->ToCString();
13000 0 : PrintF(out, "%s", name.get());
13001 0 : }
13002 :
13003 :
13004 620875 : Handle<String> JSFunction::GetName(Handle<JSFunction> function) {
13005 : Isolate* isolate = function->GetIsolate();
13006 : Handle<Object> name =
13007 620875 : JSReceiver::GetDataProperty(function, isolate->factory()->name_string());
13008 620875 : if (name->IsString()) return Handle<String>::cast(name);
13009 619872 : return handle(function->shared()->DebugName(), isolate);
13010 : }
13011 :
13012 :
13013 375062 : Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) {
13014 : Isolate* isolate = function->GetIsolate();
13015 : Handle<Object> name = JSReceiver::GetDataProperty(
13016 375062 : function, isolate->factory()->display_name_string());
13017 375062 : if (name->IsString()) return Handle<String>::cast(name);
13018 375016 : return JSFunction::GetName(function);
13019 : }
13020 :
13021 1488194 : void JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name,
13022 : Handle<String> prefix) {
13023 : Isolate* isolate = function->GetIsolate();
13024 2976393 : Handle<String> function_name = Name::ToFunctionName(name).ToHandleChecked();
13025 1488199 : if (prefix->length() > 0) {
13026 3480 : IncrementalStringBuilder builder(isolate);
13027 3480 : builder.AppendString(prefix);
13028 : builder.AppendCharacter(' ');
13029 3480 : builder.AppendString(function_name);
13030 6960 : function_name = builder.Finish().ToHandleChecked();
13031 : }
13032 : JSObject::DefinePropertyOrElementIgnoreAttributes(
13033 : function, isolate->factory()->name_string(), function_name,
13034 : static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY))
13035 2976397 : .ToHandleChecked();
13036 1488198 : }
13037 :
13038 : namespace {
13039 :
13040 : char const kNativeCodeSource[] = "function () { [native code] }";
13041 :
13042 :
13043 1552727 : Handle<String> NativeCodeFunctionSourceString(
13044 : Handle<SharedFunctionInfo> shared_info) {
13045 : Isolate* const isolate = shared_info->GetIsolate();
13046 1552727 : if (shared_info->name()->IsString()) {
13047 1552727 : IncrementalStringBuilder builder(isolate);
13048 : builder.AppendCString("function ");
13049 1552727 : builder.AppendString(handle(String::cast(shared_info->name()), isolate));
13050 : builder.AppendCString("() { [native code] }");
13051 3105454 : return builder.Finish().ToHandleChecked();
13052 : }
13053 0 : return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource);
13054 : }
13055 :
13056 : } // namespace
13057 :
13058 :
13059 : // static
13060 81 : Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) {
13061 : Isolate* const isolate = function->GetIsolate();
13062 81 : return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource);
13063 : }
13064 :
13065 :
13066 : // static
13067 2636894 : Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
13068 : Isolate* const isolate = function->GetIsolate();
13069 : Handle<SharedFunctionInfo> shared_info(function->shared(), isolate);
13070 :
13071 : // Check if {function} should hide its source code.
13072 2636894 : if (!shared_info->IsUserJavaScript()) {
13073 1552727 : return NativeCodeFunctionSourceString(shared_info);
13074 : }
13075 :
13076 : // Check if we should print {function} as a class.
13077 : Handle<Object> class_start_position = JSReceiver::GetDataProperty(
13078 1084167 : function, isolate->factory()->class_start_position_symbol());
13079 1084167 : if (class_start_position->IsSmi()) {
13080 : Handle<Object> class_end_position = JSReceiver::GetDataProperty(
13081 33811 : function, isolate->factory()->class_end_position_symbol());
13082 : Handle<String> script_source(
13083 : String::cast(Script::cast(shared_info->script())->source()), isolate);
13084 : return isolate->factory()->NewSubString(
13085 : script_source, Handle<Smi>::cast(class_start_position)->value(),
13086 33811 : Handle<Smi>::cast(class_end_position)->value());
13087 : }
13088 :
13089 : // Check if we have source code for the {function}.
13090 1050356 : if (!shared_info->HasSourceCode()) {
13091 0 : return NativeCodeFunctionSourceString(shared_info);
13092 : }
13093 :
13094 1050356 : if (FLAG_harmony_function_tostring) {
13095 1260 : return Handle<String>::cast(shared_info->GetSourceCodeHarmony());
13096 : }
13097 :
13098 1049096 : IncrementalStringBuilder builder(isolate);
13099 : FunctionKind kind = shared_info->kind();
13100 1049096 : if (!IsArrowFunction(kind)) {
13101 1043685 : if (IsConciseMethod(kind)) {
13102 98 : if (IsAsyncGeneratorFunction(kind)) {
13103 : builder.AppendCString("async *");
13104 56 : } else if (IsGeneratorFunction(kind)) {
13105 : builder.AppendCharacter('*');
13106 42 : } else if (IsAsyncFunction(kind)) {
13107 : builder.AppendCString("async ");
13108 : }
13109 : } else {
13110 1043587 : if (IsAsyncGeneratorFunction(kind)) {
13111 : builder.AppendCString("async function* ");
13112 1043517 : } else if (IsGeneratorFunction(kind)) {
13113 : builder.AppendCString("function* ");
13114 1043323 : } else if (IsAsyncFunction(kind)) {
13115 : builder.AppendCString("async function ");
13116 : } else {
13117 : builder.AppendCString("function ");
13118 : }
13119 : }
13120 1043685 : if (shared_info->name_should_print_as_anonymous()) {
13121 : builder.AppendCString("anonymous");
13122 1043123 : } else if (!shared_info->is_anonymous_expression()) {
13123 939165 : builder.AppendString(handle(String::cast(shared_info->name()), isolate));
13124 : }
13125 : }
13126 1049096 : builder.AppendString(Handle<String>::cast(shared_info->GetSourceCode()));
13127 2098192 : return builder.Finish().ToHandleChecked();
13128 : }
13129 :
13130 473 : void Oddball::Initialize(Isolate* isolate, Handle<Oddball> oddball,
13131 : const char* to_string, Handle<Object> to_number,
13132 : const char* type_of, byte kind) {
13133 : Handle<String> internalized_to_string =
13134 473 : isolate->factory()->InternalizeUtf8String(to_string);
13135 : Handle<String> internalized_type_of =
13136 473 : isolate->factory()->InternalizeUtf8String(type_of);
13137 473 : if (to_number->IsHeapNumber()) {
13138 : oddball->set_to_number_raw_as_bits(
13139 : Handle<HeapNumber>::cast(to_number)->value_as_bits());
13140 : } else {
13141 : oddball->set_to_number_raw(to_number->Number());
13142 : }
13143 473 : oddball->set_to_number(*to_number);
13144 473 : oddball->set_to_string(*internalized_to_string);
13145 473 : oddball->set_type_of(*internalized_type_of);
13146 : oddball->set_kind(kind);
13147 473 : }
13148 :
13149 1294323 : void Script::SetEvalOrigin(Handle<Script> script,
13150 : Handle<SharedFunctionInfo> outer_info,
13151 : int eval_position) {
13152 1294323 : if (eval_position == kNoSourcePosition) {
13153 : // If the position is missing, attempt to get the code offset from the
13154 : // current activation. Do not translate the code offset into source
13155 : // position, but store it as negative value for lazy translation.
13156 477363 : StackTraceFrameIterator it(script->GetIsolate());
13157 954649 : if (!it.done() && it.is_javascript()) {
13158 477286 : FrameSummary summary = FrameSummary::GetTop(it.javascript_frame());
13159 477286 : script->set_eval_from_shared(summary.AsJavaScript().function()->shared());
13160 477286 : script->set_eval_from_position(-summary.code_offset());
13161 1771609 : return;
13162 : }
13163 : eval_position = 0;
13164 : }
13165 817037 : script->set_eval_from_shared(*outer_info);
13166 : script->set_eval_from_position(eval_position);
13167 : }
13168 :
13169 12476 : int Script::GetEvalPosition() {
13170 : DisallowHeapAllocation no_gc;
13171 : DCHECK(compilation_type() == Script::COMPILATION_TYPE_EVAL);
13172 : int position = eval_from_position();
13173 12476 : if (position < 0) {
13174 : // Due to laziness, the position may not have been translated from code
13175 : // offset yet, which would be encoded as negative integer. In that case,
13176 : // translate and set the position.
13177 1105 : if (eval_from_shared()->IsUndefined(GetIsolate())) {
13178 : position = 0;
13179 : } else {
13180 : SharedFunctionInfo* shared = SharedFunctionInfo::cast(eval_from_shared());
13181 2210 : position = shared->abstract_code()->SourcePosition(-position);
13182 : }
13183 : DCHECK(position >= 0);
13184 : set_eval_from_position(position);
13185 : }
13186 12476 : return position;
13187 : }
13188 :
13189 1672519 : void Script::InitLineEnds(Handle<Script> script) {
13190 : Isolate* isolate = script->GetIsolate();
13191 3345038 : if (!script->line_ends()->IsUndefined(isolate)) return;
13192 : DCHECK_NE(Script::TYPE_WASM, script->type());
13193 :
13194 : Object* src_obj = script->source();
13195 63161 : if (!src_obj->IsString()) {
13196 : DCHECK(src_obj->IsUndefined(isolate));
13197 14 : script->set_line_ends(isolate->heap()->empty_fixed_array());
13198 : } else {
13199 : DCHECK(src_obj->IsString());
13200 : Handle<String> src(String::cast(src_obj), isolate);
13201 63154 : Handle<FixedArray> array = String::CalculateLineEnds(src, true);
13202 63154 : script->set_line_ends(*array);
13203 : }
13204 :
13205 : DCHECK(script->line_ends()->IsFixedArray());
13206 : }
13207 :
13208 1386299 : bool Script::GetPositionInfo(Handle<Script> script, int position,
13209 : PositionInfo* info, OffsetFlag offset_flag) {
13210 : // For wasm, we do not create an artificial line_ends array, but do the
13211 : // translation directly.
13212 1386299 : if (script->type() != Script::TYPE_WASM) InitLineEnds(script);
13213 1386299 : return script->GetPositionInfo(position, info, offset_flag);
13214 : }
13215 :
13216 54644495 : bool Script::IsUserJavaScript() { return type() == Script::TYPE_NORMAL; }
13217 :
13218 : namespace {
13219 1791 : bool GetPositionInfoSlow(const Script* script, int position,
13220 : Script::PositionInfo* info) {
13221 1791 : if (!script->source()->IsString()) return false;
13222 1791 : if (position < 0) position = 0;
13223 :
13224 : String* source_string = String::cast(script->source());
13225 : int line = 0;
13226 : int line_start = 0;
13227 : int len = source_string->length();
13228 539845 : for (int pos = 0; pos <= len; ++pos) {
13229 1079590 : if (pos == len || source_string->Get(pos) == '\n') {
13230 22152 : if (position <= pos) {
13231 1779 : info->line = line;
13232 1779 : info->column = position - line_start;
13233 1779 : info->line_start = line_start;
13234 1779 : info->line_end = pos;
13235 1779 : return true;
13236 : }
13237 20373 : line++;
13238 20373 : line_start = pos + 1;
13239 : }
13240 : }
13241 : return false;
13242 : }
13243 : } // namespace
13244 :
13245 : #define SMI_VALUE(x) (Smi::cast(x)->value())
13246 1443397 : bool Script::GetPositionInfo(int position, PositionInfo* info,
13247 : OffsetFlag offset_flag) const {
13248 : DisallowHeapAllocation no_allocation;
13249 :
13250 : // For wasm, we do not rely on the line_ends array, but do the translation
13251 : // directly.
13252 1443397 : if (type() == Script::TYPE_WASM) {
13253 : Handle<WasmCompiledModule> compiled_module(
13254 : WasmCompiledModule::cast(wasm_compiled_module()));
13255 : DCHECK_LE(0, position);
13256 : return compiled_module->GetPositionInfo(static_cast<uint32_t>(position),
13257 1036 : info);
13258 : }
13259 :
13260 1442879 : if (line_ends()->IsUndefined(GetIsolate())) {
13261 : // Slow mode: we do not have line_ends. We have to iterate through source.
13262 1791 : if (!GetPositionInfoSlow(this, position, info)) return false;
13263 : } else {
13264 : DCHECK(line_ends()->IsFixedArray());
13265 : FixedArray* ends = FixedArray::cast(line_ends());
13266 :
13267 : const int ends_len = ends->length();
13268 1441088 : if (ends_len == 0) return false;
13269 :
13270 : // Return early on invalid positions. Negative positions behave as if 0 was
13271 : // passed, and positions beyond the end of the script return as failure.
13272 1441067 : if (position < 0) {
13273 : position = 0;
13274 2881130 : } else if (position > SMI_VALUE(ends->get(ends_len - 1))) {
13275 : return false;
13276 : }
13277 :
13278 : // Determine line number by doing a binary search on the line ends array.
13279 1441041 : if (SMI_VALUE(ends->get(0)) >= position) {
13280 199218 : info->line = 0;
13281 199218 : info->line_start = 0;
13282 199218 : info->column = position;
13283 : } else {
13284 : int left = 0;
13285 1241823 : int right = ends_len - 1;
13286 :
13287 8767386 : while (right > 0) {
13288 : DCHECK_LE(left, right);
13289 7525563 : const int mid = (left + right) / 2;
13290 7525563 : if (position > SMI_VALUE(ends->get(mid))) {
13291 3844216 : left = mid + 1;
13292 7362694 : } else if (position <= SMI_VALUE(ends->get(mid - 1))) {
13293 : right = mid - 1;
13294 : } else {
13295 1241823 : info->line = mid;
13296 1241823 : break;
13297 : }
13298 : }
13299 : DCHECK(SMI_VALUE(ends->get(info->line)) >= position &&
13300 : SMI_VALUE(ends->get(info->line - 1)) < position);
13301 2483646 : info->line_start = SMI_VALUE(ends->get(info->line - 1)) + 1;
13302 1241823 : info->column = position - info->line_start;
13303 : }
13304 :
13305 : // Line end is position of the linebreak character.
13306 2882082 : info->line_end = SMI_VALUE(ends->get(info->line));
13307 1441041 : if (info->line_end > 0) {
13308 : DCHECK(source()->IsString());
13309 : String* src = String::cast(source());
13310 2881606 : if (src->length() >= info->line_end &&
13311 1440803 : src->Get(info->line_end - 1) == '\r') {
13312 0 : info->line_end--;
13313 : }
13314 : }
13315 : }
13316 :
13317 : // Add offsets if requested.
13318 1442820 : if (offset_flag == WITH_OFFSET) {
13319 1218696 : if (info->line == 0) {
13320 163878 : info->column += column_offset();
13321 : }
13322 1218696 : info->line += line_offset();
13323 : }
13324 :
13325 : return true;
13326 : }
13327 : #undef SMI_VALUE
13328 :
13329 203268 : int Script::GetColumnNumber(Handle<Script> script, int code_pos) {
13330 : PositionInfo info;
13331 203268 : GetPositionInfo(script, code_pos, &info, WITH_OFFSET);
13332 203268 : return info.column;
13333 : }
13334 :
13335 0 : int Script::GetColumnNumber(int code_pos) const {
13336 : PositionInfo info;
13337 0 : GetPositionInfo(code_pos, &info, WITH_OFFSET);
13338 0 : return info.column;
13339 : }
13340 :
13341 210499 : int Script::GetLineNumber(Handle<Script> script, int code_pos) {
13342 : PositionInfo info;
13343 210499 : GetPositionInfo(script, code_pos, &info, WITH_OFFSET);
13344 210499 : return info.line;
13345 : }
13346 :
13347 56978 : int Script::GetLineNumber(int code_pos) const {
13348 : PositionInfo info;
13349 56978 : GetPositionInfo(code_pos, &info, WITH_OFFSET);
13350 56978 : return info.line;
13351 : }
13352 :
13353 49078 : Object* Script::GetNameOrSourceURL() {
13354 : Isolate* isolate = GetIsolate();
13355 : // Keep in sync with ScriptNameOrSourceURL in messages.js.
13356 51247 : if (!source_url()->IsUndefined(isolate)) return source_url();
13357 46909 : return name();
13358 : }
13359 :
13360 :
13361 2036828 : Handle<JSObject> Script::GetWrapper(Handle<Script> script) {
13362 629346 : Isolate* isolate = script->GetIsolate();
13363 2036828 : if (!script->wrapper()->IsUndefined(isolate)) {
13364 : DCHECK(script->wrapper()->IsWeakCell());
13365 : Handle<WeakCell> cell(WeakCell::cast(script->wrapper()));
13366 1545864 : if (!cell->cleared()) {
13367 : // Return a handle for the existing script wrapper from the cache.
13368 : return handle(JSObject::cast(cell->value()));
13369 : }
13370 : // If we found an empty WeakCell, that means the script wrapper was
13371 : // GCed. We are not notified directly of that, so we decrement here
13372 : // so that we at least don't count double for any given script.
13373 69191 : isolate->counters()->script_wrappers()->Decrement();
13374 : }
13375 : // Construct a new script wrapper.
13376 560155 : isolate->counters()->script_wrappers()->Increment();
13377 560155 : Handle<JSFunction> constructor = isolate->script_function();
13378 : Handle<JSValue> result =
13379 560155 : Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
13380 560155 : result->set_value(*script);
13381 560155 : Handle<WeakCell> cell = isolate->factory()->NewWeakCell(result);
13382 560155 : script->set_wrapper(*cell);
13383 560155 : return result;
13384 : }
13385 :
13386 5867748 : MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
13387 5867748 : Isolate* isolate, const FunctionLiteral* fun) {
13388 : DCHECK_NE(fun->function_literal_id(), FunctionLiteral::kIdTypeInvalid);
13389 : DCHECK_LT(fun->function_literal_id(), shared_function_infos()->length());
13390 : Object* shared = shared_function_infos()->get(fun->function_literal_id());
13391 6841929 : if (shared->IsUndefined(isolate) || WeakCell::cast(shared)->cleared()) {
13392 : return MaybeHandle<SharedFunctionInfo>();
13393 : }
13394 : return handle(SharedFunctionInfo::cast(WeakCell::cast(shared)->value()));
13395 : }
13396 :
13397 212463 : Script::Iterator::Iterator(Isolate* isolate)
13398 436647 : : iterator_(isolate->heap()->script_list()) {}
13399 :
13400 :
13401 6115211 : Script* Script::Iterator::Next() { return iterator_.Next<Script>(); }
13402 :
13403 42 : bool Script::HasPreparsedScopeData() const {
13404 42 : return preparsed_scope_data()->length() > 0;
13405 : }
13406 :
13407 90520 : SharedFunctionInfo::ScriptIterator::ScriptIterator(Handle<Script> script)
13408 : : ScriptIterator(script->GetIsolate(),
13409 90520 : handle(script->shared_function_infos())) {}
13410 :
13411 642 : SharedFunctionInfo::ScriptIterator::ScriptIterator(
13412 : Isolate* isolate, Handle<FixedArray> shared_function_infos)
13413 : : isolate_(isolate),
13414 : shared_function_infos_(shared_function_infos),
13415 91162 : index_(0) {}
13416 :
13417 11846730 : SharedFunctionInfo* SharedFunctionInfo::ScriptIterator::Next() {
13418 39476960 : while (index_ < shared_function_infos_->length()) {
13419 13365011 : Object* raw = shared_function_infos_->get(index_++);
13420 38479849 : if (raw->IsUndefined(isolate_) || WeakCell::cast(raw)->cleared()) continue;
13421 11396626 : return SharedFunctionInfo::cast(WeakCell::cast(raw)->value());
13422 : }
13423 : return nullptr;
13424 : }
13425 :
13426 358957 : void SharedFunctionInfo::ScriptIterator::Reset(Handle<Script> script) {
13427 358957 : shared_function_infos_ = handle(script->shared_function_infos());
13428 358957 : index_ = 0;
13429 358957 : }
13430 :
13431 11721 : SharedFunctionInfo::GlobalIterator::GlobalIterator(Isolate* isolate)
13432 : : script_iterator_(isolate),
13433 : noscript_sfi_iterator_(isolate->heap()->noscript_shared_function_infos()),
13434 23442 : sfi_iterator_(handle(script_iterator_.Next(), isolate)) {}
13435 :
13436 16605451 : SharedFunctionInfo* SharedFunctionInfo::GlobalIterator::Next() {
13437 16605451 : SharedFunctionInfo* next = noscript_sfi_iterator_.Next<SharedFunctionInfo>();
13438 16605451 : if (next != nullptr) return next;
13439 : for (;;) {
13440 10677654 : next = sfi_iterator_.Next();
13441 10677654 : if (next != nullptr) return next;
13442 : Script* next_script = script_iterator_.Next();
13443 370678 : if (next_script == nullptr) return nullptr;
13444 358957 : sfi_iterator_.Reset(handle(next_script));
13445 358957 : }
13446 : }
13447 :
13448 :
13449 6245756 : void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
13450 : Handle<Object> script_object) {
13451 : DCHECK_NE(shared->function_literal_id(), FunctionLiteral::kIdTypeInvalid);
13452 12491506 : if (shared->script() == *script_object) return;
13453 : Isolate* isolate = shared->GetIsolate();
13454 :
13455 : // Add shared function info to new script's list. If a collection occurs,
13456 : // the shared function info may be temporarily in two lists.
13457 : // This is okay because the gc-time processing of these lists can tolerate
13458 : // duplicates.
13459 6245762 : if (script_object->IsScript()) {
13460 : Handle<Script> script = Handle<Script>::cast(script_object);
13461 : Handle<FixedArray> list = handle(script->shared_function_infos(), isolate);
13462 : #ifdef DEBUG
13463 : DCHECK_LT(shared->function_literal_id(), list->length());
13464 : if (list->get(shared->function_literal_id())->IsWeakCell() &&
13465 : !WeakCell::cast(list->get(shared->function_literal_id()))->cleared()) {
13466 : DCHECK(
13467 : WeakCell::cast(list->get(shared->function_literal_id()))->value() ==
13468 : *shared);
13469 : }
13470 : #endif
13471 6239219 : Handle<WeakCell> cell = isolate->factory()->NewWeakCell(shared);
13472 6239225 : list->set(shared->function_literal_id(), *cell);
13473 : } else {
13474 : Handle<Object> list = isolate->factory()->noscript_shared_function_infos();
13475 :
13476 : #ifdef DEBUG
13477 : if (FLAG_enable_slow_asserts) {
13478 : WeakFixedArray::Iterator iterator(*list);
13479 : SharedFunctionInfo* next;
13480 : while ((next = iterator.Next<SharedFunctionInfo>()) != nullptr) {
13481 : DCHECK_NE(next, *shared);
13482 : }
13483 : }
13484 : #endif // DEBUG
13485 :
13486 6539 : list = WeakFixedArray::Add(list, shared);
13487 :
13488 : isolate->heap()->SetRootNoScriptSharedFunctionInfos(*list);
13489 : }
13490 :
13491 6245764 : if (shared->script()->IsScript()) {
13492 : // Remove shared function info from old script's list.
13493 : Script* old_script = Script::cast(shared->script());
13494 :
13495 : // Due to liveedit, it might happen that the old_script doesn't know
13496 : // about the SharedFunctionInfo, so we have to guard against that.
13497 : Handle<FixedArray> infos(old_script->shared_function_infos(), isolate);
13498 6571 : if (shared->function_literal_id() < infos->length()) {
13499 : Object* raw = old_script->shared_function_infos()->get(
13500 : shared->function_literal_id());
13501 13080 : if (!raw->IsWeakCell() || WeakCell::cast(raw)->value() == *shared) {
13502 : old_script->shared_function_infos()->set(
13503 3450 : shared->function_literal_id(), isolate->heap()->undefined_value());
13504 : }
13505 : }
13506 : } else {
13507 : // Remove shared function info from root array.
13508 6239193 : Object* list = isolate->heap()->noscript_shared_function_infos();
13509 6239193 : CHECK(WeakFixedArray::cast(list)->Remove(shared));
13510 : }
13511 :
13512 : // Finally set new script.
13513 6245763 : shared->set_script(*script_object);
13514 : }
13515 :
13516 :
13517 3098969 : String* SharedFunctionInfo::DebugName() {
13518 : Object* n = name();
13519 6197945 : if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
13520 : return String::cast(n);
13521 : }
13522 :
13523 14088 : bool SharedFunctionInfo::HasNoSideEffect() {
13524 14088 : if (!computed_has_no_side_effect()) {
13525 : DisallowHeapAllocation not_handlified;
13526 : Handle<SharedFunctionInfo> info(this);
13527 11074 : set_has_no_side_effect(DebugEvaluate::FunctionHasNoSideEffect(info));
13528 11074 : set_computed_has_no_side_effect(true);
13529 : }
13530 14088 : return has_no_side_effect();
13531 : }
13532 :
13533 : // The filter is a pattern that matches function names in this way:
13534 : // "*" all; the default
13535 : // "-" all but the top-level function
13536 : // "-name" all but the function "name"
13537 : // "" only the top-level function
13538 : // "name" only the function "name"
13539 : // "name*" only functions starting with "name"
13540 : // "~" none; the tilde is not an identifier
13541 4007662 : bool SharedFunctionInfo::PassesFilter(const char* raw_filter) {
13542 4007662 : if (*raw_filter == '*') return true;
13543 1508807 : String* name = DebugName();
13544 1508812 : Vector<const char> filter = CStrVector(raw_filter);
13545 1508812 : if (filter.length() == 0) return name->length() == 0;
13546 1508812 : if (filter[0] == '-') {
13547 : // Negative filter.
13548 0 : if (filter.length() == 1) {
13549 0 : return (name->length() != 0);
13550 0 : } else if (name->IsUtf8EqualTo(filter.SubVector(1, filter.length()))) {
13551 : return false;
13552 : }
13553 0 : if (filter[filter.length() - 1] == '*' &&
13554 0 : name->IsUtf8EqualTo(filter.SubVector(1, filter.length() - 1), true)) {
13555 : return false;
13556 : }
13557 0 : return true;
13558 :
13559 1508812 : } else if (name->IsUtf8EqualTo(filter)) {
13560 : return true;
13561 : }
13562 3017053 : if (filter[filter.length() - 1] == '*' &&
13563 125 : name->IsUtf8EqualTo(filter.SubVector(0, filter.length() - 1), true)) {
13564 : return true;
13565 : }
13566 1508388 : return false;
13567 : }
13568 :
13569 14230772 : bool SharedFunctionInfo::HasSourceCode() const {
13570 : Isolate* isolate = GetIsolate();
13571 28461537 : return !script()->IsUndefined(isolate) &&
13572 14230772 : !reinterpret_cast<Script*>(script())->source()->IsUndefined(isolate);
13573 : }
13574 :
13575 :
13576 1049488 : Handle<Object> SharedFunctionInfo::GetSourceCode() {
13577 1049488 : if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value();
13578 : Handle<String> source(String::cast(Script::cast(script())->source()));
13579 : return GetIsolate()->factory()->NewSubString(
13580 1049488 : source, start_position(), end_position());
13581 : }
13582 :
13583 1260 : Handle<Object> SharedFunctionInfo::GetSourceCodeHarmony() {
13584 : Isolate* isolate = GetIsolate();
13585 1260 : if (!HasSourceCode()) return isolate->factory()->undefined_value();
13586 : Handle<String> script_source(String::cast(Script::cast(script())->source()));
13587 : int start_pos = function_token_position();
13588 1260 : if (start_pos == kNoSourcePosition) start_pos = start_position();
13589 : return isolate->factory()->NewSubString(script_source, start_pos,
13590 1260 : end_position());
13591 : }
13592 :
13593 180640 : bool SharedFunctionInfo::IsInlineable() {
13594 : // Check that the function has a script associated with it.
13595 180640 : if (!script()->IsScript()) return false;
13596 180652 : if (GetIsolate()->is_precise_binary_code_coverage() &&
13597 : !has_reported_binary_coverage()) {
13598 : // We may miss invocations if this function is inlined.
13599 : return false;
13600 : }
13601 180640 : return !optimization_disabled();
13602 : }
13603 :
13604 151655 : int SharedFunctionInfo::SourceSize() {
13605 151655 : return end_position() - start_position();
13606 : }
13607 :
13608 710169 : void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type,
13609 : int requested_embedder_fields,
13610 : int requested_in_object_properties,
13611 : int* instance_size,
13612 : int* in_object_properties) {
13613 710169 : int header_size = JSObject::GetHeaderSize(instance_type);
13614 : DCHECK_LE(requested_embedder_fields,
13615 : (JSObject::kMaxInstanceSize - header_size) >> kPointerSizeLog2);
13616 : *instance_size =
13617 : Min(header_size +
13618 710169 : ((requested_embedder_fields + requested_in_object_properties)
13619 710169 : << kPointerSizeLog2),
13620 1420338 : JSObject::kMaxInstanceSize);
13621 710169 : *in_object_properties = ((*instance_size - header_size) >> kPointerSizeLog2) -
13622 710169 : requested_embedder_fields;
13623 710169 : }
13624 :
13625 9296 : void JSFunction::CalculateInstanceSizeForDerivedClass(
13626 : Handle<JSFunction> function, InstanceType instance_type,
13627 : int requested_embedder_fields, int* instance_size,
13628 : int* in_object_properties) {
13629 : Isolate* isolate = function->GetIsolate();
13630 : int expected_nof_properties = 0;
13631 38548 : for (PrototypeIterator iter(isolate, function, kStartAtReceiver);
13632 19956 : !iter.IsAtEnd(); iter.Advance()) {
13633 : Handle<JSReceiver> current =
13634 : PrototypeIterator::GetCurrent<JSReceiver>(iter);
13635 29252 : if (!current->IsJSFunction()) break;
13636 : Handle<JSFunction> func(Handle<JSFunction>::cast(current));
13637 : // The super constructor should be compiled for the number of expected
13638 : // properties to be available.
13639 : Handle<SharedFunctionInfo> shared(func->shared());
13640 29532 : if (shared->is_compiled() ||
13641 295 : Compiler::Compile(func, Compiler::CLEAR_EXCEPTION)) {
13642 : DCHECK(shared->is_compiled());
13643 29237 : expected_nof_properties += shared->expected_nof_properties();
13644 : }
13645 29237 : if (!IsDerivedConstructor(shared->kind())) {
13646 : break;
13647 : }
13648 : }
13649 : CalculateInstanceSizeHelper(instance_type, requested_embedder_fields,
13650 : expected_nof_properties, instance_size,
13651 9296 : in_object_properties);
13652 9296 : }
13653 :
13654 :
13655 : // Output the source code without any allocation in the heap.
13656 21 : std::ostream& operator<<(std::ostream& os, const SourceCodeOf& v) {
13657 21 : const SharedFunctionInfo* s = v.value;
13658 : // For some native functions there is no source.
13659 21 : if (!s->HasSourceCode()) return os << "<No Source>";
13660 :
13661 : // Get the source for the script which this function came from.
13662 : // Don't use String::cast because we don't want more assertion errors while
13663 : // we are already creating a stack dump.
13664 : String* script_source =
13665 : reinterpret_cast<String*>(Script::cast(s->script())->source());
13666 :
13667 14 : if (!script_source->LooksValid()) return os << "<Invalid Source>";
13668 :
13669 14 : if (!s->is_toplevel()) {
13670 14 : os << "function ";
13671 : Object* name = s->name();
13672 28 : if (name->IsString() && String::cast(name)->length() > 0) {
13673 14 : String::cast(name)->PrintUC16(os);
13674 : }
13675 : }
13676 :
13677 14 : int len = s->end_position() - s->start_position();
13678 14 : if (len <= v.max_length || v.max_length < 0) {
13679 14 : script_source->PrintUC16(os, s->start_position(), s->end_position());
13680 14 : return os;
13681 : } else {
13682 : script_source->PrintUC16(os, s->start_position(),
13683 0 : s->start_position() + v.max_length);
13684 0 : return os << "...\n";
13685 : }
13686 : }
13687 :
13688 :
13689 231775 : static bool IsCodeEquivalent(Code* code, Code* recompiled) {
13690 231775 : if (code->instruction_size() != recompiled->instruction_size()) return false;
13691 : ByteArray* code_relocation = code->relocation_info();
13692 : ByteArray* recompiled_relocation = recompiled->relocation_info();
13693 : int length = code_relocation->length();
13694 228705 : if (length != recompiled_relocation->length()) return false;
13695 228705 : int compare = memcmp(code_relocation->GetDataStartAddress(),
13696 228705 : recompiled_relocation->GetDataStartAddress(),
13697 457410 : length);
13698 228705 : return compare == 0;
13699 : }
13700 :
13701 :
13702 231775 : void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
13703 : DCHECK(!has_deoptimization_support());
13704 : DisallowHeapAllocation no_allocation;
13705 : Code* code = this->code();
13706 231775 : if (IsCodeEquivalent(code, recompiled)) {
13707 : // Copy the deoptimization data from the recompiled code.
13708 228705 : code->set_deoptimization_data(recompiled->deoptimization_data());
13709 : code->set_has_deoptimization_support(true);
13710 : } else {
13711 : // TODO(3025757): In case the recompiled isn't equivalent to the
13712 : // old code, we have to replace it. We should try to avoid this
13713 : // altogether because it flushes valuable type feedback by
13714 : // effectively resetting all IC state.
13715 3070 : ReplaceCode(recompiled);
13716 : }
13717 : DCHECK(has_deoptimization_support());
13718 231775 : }
13719 :
13720 :
13721 57075 : void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
13722 : // Disable optimization for the shared function info and mark the
13723 : // code as non-optimizable. The marker on the shared function info
13724 : // is there because we flush non-optimized code thereby loosing the
13725 : // non-optimizable information for the code. When the code is
13726 : // regenerated and set on the shared function info it is marked as
13727 : // non-optimizable if optimization is disabled for the shared
13728 : // function info.
13729 : DCHECK(reason != kNoReason);
13730 : set_optimization_disabled(true);
13731 : set_disable_optimization_reason(reason);
13732 : // Code should be the lazy compilation stub or else unoptimized.
13733 : DCHECK(abstract_code()->kind() == AbstractCode::FUNCTION ||
13734 : abstract_code()->kind() == AbstractCode::INTERPRETED_FUNCTION ||
13735 : abstract_code()->kind() == AbstractCode::BUILTIN);
13736 57075 : PROFILE(GetIsolate(), CodeDisableOptEvent(abstract_code(), this));
13737 57075 : if (FLAG_trace_opt) {
13738 0 : PrintF("[disabled optimization for ");
13739 0 : ShortPrint();
13740 0 : PrintF(", reason: %s]\n", GetBailoutReason(reason));
13741 : }
13742 57075 : }
13743 :
13744 6235385 : void SharedFunctionInfo::InitFromFunctionLiteral(
13745 54611820 : Handle<SharedFunctionInfo> shared_info, FunctionLiteral* lit) {
13746 : // When adding fields here, make sure DeclarationScope::AnalyzePartially is
13747 : // updated accordingly.
13748 : shared_info->set_internal_formal_parameter_count(lit->parameter_count());
13749 : shared_info->set_function_token_position(lit->function_token_position());
13750 6235385 : shared_info->set_start_position(lit->start_position());
13751 6235387 : shared_info->set_end_position(lit->end_position());
13752 : shared_info->set_is_declaration(lit->is_declaration());
13753 : shared_info->set_is_named_expression(lit->is_named_expression());
13754 6235390 : shared_info->set_is_anonymous_expression(lit->is_anonymous_expression());
13755 12470779 : shared_info->set_inferred_name(*lit->inferred_name());
13756 6235391 : shared_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
13757 6235386 : shared_info->set_language_mode(lit->language_mode());
13758 6235391 : shared_info->set_uses_arguments(lit->scope()->arguments() != NULL);
13759 6235391 : shared_info->set_kind(lit->kind());
13760 6235394 : if (!IsConstructable(lit->kind())) {
13761 : shared_info->SetConstructStub(
13762 934422 : *shared_info->GetIsolate()->builtins()->ConstructedNonConstructable());
13763 : }
13764 6235393 : shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
13765 : shared_info->set_asm_function(lit->scope()->asm_function());
13766 : shared_info->set_function_literal_id(lit->function_literal_id());
13767 :
13768 : // For lazy parsed functions, the following flags will be inaccurate since we
13769 : // don't have the information yet. They're set later in
13770 : // SetSharedFunctionFlagsFromLiteral (compiler.cc), when the function is
13771 : // really parsed and compiled.
13772 6235394 : if (lit->body() != nullptr) {
13773 : shared_info->set_length(lit->function_length());
13774 : shared_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
13775 : shared_info->SetExpectedNofPropertiesFromEstimate(lit);
13776 : } else {
13777 : // Set an invalid length for lazy functions. This way we can set the correct
13778 : // value after compiling, but avoid overwriting values set manually by the
13779 : // bootstrapper.
13780 : shared_info->set_length(SharedFunctionInfo::kInvalidLength);
13781 : }
13782 6235394 : }
13783 :
13784 3341373 : void SharedFunctionInfo::SetExpectedNofPropertiesFromEstimate(
13785 8823415 : FunctionLiteral* literal) {
13786 : int estimate = literal->expected_property_count();
13787 :
13788 : // If no properties are added in the constructor, they are more likely
13789 : // to be added later.
13790 8823415 : if (estimate == 0) estimate = 2;
13791 :
13792 : // Inobject slack tracking will reclaim redundant inobject space later,
13793 : // so we can afford to adjust the estimate generously.
13794 8823415 : estimate += 8;
13795 :
13796 : set_expected_nof_properties(estimate);
13797 3341373 : }
13798 :
13799 0 : bool SharedFunctionInfo::VerifyBailoutId(BailoutId id) {
13800 : DCHECK(!id.IsNone());
13801 : Code* unoptimized = code();
13802 : DeoptimizationOutputData* data =
13803 : DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
13804 0 : unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
13805 : USE(ignore);
13806 0 : return true; // Return true if there was no DCHECK.
13807 : }
13808 :
13809 14906648 : void SharedFunctionInfo::SetConstructStub(Code* code) {
13810 14906648 : if (code->kind() == Code::BUILTIN) code->set_is_construct_stub(true);
13811 14906648 : set_construct_stub(code);
13812 14906655 : }
13813 :
13814 0 : void Map::StartInobjectSlackTracking() {
13815 : DCHECK(!IsInobjectSlackTrackingInProgress());
13816 499405 : if (unused_property_fields() == 0) return;
13817 : set_construction_counter(Map::kSlackTrackingCounterStart);
13818 : }
13819 :
13820 :
13821 4504657 : void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
13822 4504657 : code()->ClearInlineCaches();
13823 : set_ic_age(new_ic_age);
13824 4504677 : if (code()->kind() == Code::FUNCTION) {
13825 : code()->set_profiler_ticks(0);
13826 9714 : if (optimization_disabled() && deopt_count() >= FLAG_max_deopt_count) {
13827 : // Re-enable optimizations if they were disabled due to deopt_count limit.
13828 : set_optimization_disabled(false);
13829 : }
13830 : set_opt_count(0);
13831 : set_deopt_count(0);
13832 4495068 : } else if (IsInterpreted()) {
13833 : set_profiler_ticks(0);
13834 28230 : if (optimization_disabled() && deopt_count() >= FLAG_max_deopt_count) {
13835 : // Re-enable optimizations if they were disabled due to deopt_count limit.
13836 : set_optimization_disabled(false);
13837 : }
13838 : set_opt_count(0);
13839 : set_deopt_count(0);
13840 : }
13841 4504678 : }
13842 :
13843 27990209 : int SharedFunctionInfo::SearchOptimizedCodeMapEntry(Context* native_context) {
13844 : DisallowHeapAllocation no_gc;
13845 : DCHECK(native_context->IsNativeContext());
13846 27990209 : if (!OptimizedCodeMapIsCleared()) {
13847 : FixedArray* optimized_code_map = this->optimized_code_map();
13848 : int length = optimized_code_map->length();
13849 1902474 : for (int i = kEntriesStart; i < length; i += kEntryLength) {
13850 1647429 : if (WeakCell::cast(optimized_code_map->get(i + kContextOffset))
13851 : ->value() == native_context) {
13852 : return i;
13853 : }
13854 : }
13855 : }
13856 : return -1;
13857 : }
13858 :
13859 16588750 : void SharedFunctionInfo::ClearCodeFromOptimizedCodeMap() {
13860 16588750 : if (!OptimizedCodeMapIsCleared()) {
13861 : FixedArray* optimized_code_map = this->optimized_code_map();
13862 : int length = optimized_code_map->length();
13863 126857 : WeakCell* empty_weak_cell = GetHeap()->empty_weak_cell();
13864 254875 : for (int i = kEntriesStart; i < length; i += kEntryLength) {
13865 : optimized_code_map->set(i + kCachedCodeOffset, empty_weak_cell,
13866 128018 : SKIP_WRITE_BARRIER);
13867 : }
13868 : }
13869 16588750 : }
13870 :
13871 27957392 : Code* SharedFunctionInfo::SearchOptimizedCodeMap(Context* native_context,
13872 : BailoutId osr_ast_id) {
13873 : Code* result = nullptr;
13874 27957392 : if (!osr_ast_id.IsNone()) {
13875 8477 : return native_context->SearchOptimizedCodeMap(this, osr_ast_id);
13876 : }
13877 :
13878 : DCHECK(osr_ast_id.IsNone());
13879 27948915 : int entry = SearchOptimizedCodeMapEntry(native_context);
13880 27948919 : if (entry != kNotFound) {
13881 : FixedArray* code_map = optimized_code_map();
13882 : DCHECK_LE(entry + kEntryLength, code_map->length());
13883 916935 : WeakCell* cell = WeakCell::cast(code_map->get(entry + kCachedCodeOffset));
13884 916935 : result = cell->cleared() ? nullptr : Code::cast(cell->value());
13885 : }
13886 27948919 : return result;
13887 : }
13888 :
13889 14306693 : void ObjectVisitor::VisitCodeTarget(Code* host, RelocInfo* rinfo) {
13890 : DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode()));
13891 14306693 : Object* old_pointer = Code::GetCodeFromTargetAddress(rinfo->target_address());
13892 14306693 : Object* new_pointer = old_pointer;
13893 14306693 : VisitPointer(host, &new_pointer);
13894 : DCHECK_EQ(old_pointer, new_pointer);
13895 14306693 : }
13896 :
13897 0 : void ObjectVisitor::VisitCodeAgeSequence(Code* host, RelocInfo* rinfo) {
13898 : DCHECK(RelocInfo::IsCodeAgeSequence(rinfo->rmode()));
13899 : Object* old_pointer = rinfo->code_age_stub();
13900 0 : Object* new_pointer = old_pointer;
13901 0 : if (old_pointer != nullptr) {
13902 0 : VisitPointer(host, &new_pointer);
13903 : DCHECK_EQ(old_pointer, new_pointer);
13904 : }
13905 0 : }
13906 :
13907 2925048 : void ObjectVisitor::VisitCodeEntry(JSFunction* host, Address entry_address) {
13908 2925048 : Object* old_pointer = Code::GetObjectFromEntryAddress(entry_address);
13909 2925048 : Object* new_pointer = old_pointer;
13910 2925048 : VisitPointer(host, &new_pointer);
13911 : DCHECK_EQ(old_pointer, new_pointer);
13912 2925048 : }
13913 :
13914 3364 : void ObjectVisitor::VisitCellPointer(Code* host, RelocInfo* rinfo) {
13915 : DCHECK(rinfo->rmode() == RelocInfo::CELL);
13916 : Object* old_pointer = rinfo->target_cell();
13917 3364 : Object* new_pointer = old_pointer;
13918 3364 : VisitPointer(host, &new_pointer);
13919 : DCHECK_EQ(old_pointer, new_pointer);
13920 3364 : }
13921 :
13922 12 : void ObjectVisitor::VisitDebugTarget(Code* host, RelocInfo* rinfo) {
13923 : DCHECK(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
13924 : rinfo->IsPatchedDebugBreakSlotSequence());
13925 : Object* old_pointer =
13926 12 : Code::GetCodeFromTargetAddress(rinfo->debug_call_address());
13927 12 : Object* new_pointer = old_pointer;
13928 12 : VisitPointer(host, &new_pointer);
13929 : DCHECK_EQ(old_pointer, new_pointer);
13930 12 : }
13931 :
13932 2081999 : void ObjectVisitor::VisitEmbeddedPointer(Code* host, RelocInfo* rinfo) {
13933 : DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
13934 : Object* old_pointer = rinfo->target_object();
13935 2081999 : Object* new_pointer = old_pointer;
13936 2081999 : VisitPointer(host, &new_pointer);
13937 : DCHECK_EQ(old_pointer, new_pointer);
13938 2081999 : }
13939 :
13940 :
13941 422165 : void Code::InvalidateRelocation() {
13942 422165 : InvalidateEmbeddedObjects();
13943 422165 : set_relocation_info(GetHeap()->empty_byte_array());
13944 422165 : }
13945 :
13946 :
13947 427482 : void Code::InvalidateEmbeddedObjects() {
13948 427482 : HeapObject* undefined = GetHeap()->undefined_value();
13949 427482 : Cell* undefined_cell = GetHeap()->undefined_cell();
13950 : int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
13951 : RelocInfo::ModeMask(RelocInfo::CELL);
13952 4934406 : for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
13953 4506924 : RelocInfo::Mode mode = it.rinfo()->rmode();
13954 4506924 : if (mode == RelocInfo::EMBEDDED_OBJECT) {
13955 : it.rinfo()->set_target_object(undefined, SKIP_WRITE_BARRIER);
13956 0 : } else if (mode == RelocInfo::CELL) {
13957 : it.rinfo()->set_target_cell(undefined_cell, SKIP_WRITE_BARRIER);
13958 : }
13959 : }
13960 427482 : }
13961 :
13962 :
13963 183290 : void Code::Relocate(intptr_t delta) {
13964 191645 : if (trap_handler::UseTrapHandler() && is_wasm_code()) {
13965 : const int index = trap_handler_index()->value();
13966 2299 : if (index >= 0) {
13967 42 : trap_handler::UpdateHandlerDataCodePointer(index, instruction_start());
13968 : }
13969 : }
13970 706338 : for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
13971 : it.rinfo()->apply(delta);
13972 : }
13973 366578 : Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size());
13974 183290 : }
13975 :
13976 :
13977 2555735 : void Code::CopyFrom(const CodeDesc& desc) {
13978 : // copy code
13979 : CopyBytes(instruction_start(), desc.buffer,
13980 2555735 : static_cast<size_t>(desc.instr_size));
13981 :
13982 : // copy unwinding info, if any
13983 2555721 : if (desc.unwinding_info) {
13984 : DCHECK_GT(desc.unwinding_info_size, 0);
13985 25 : set_unwinding_info_size(desc.unwinding_info_size);
13986 : CopyBytes(unwinding_info_start(), desc.unwinding_info,
13987 25 : static_cast<size_t>(desc.unwinding_info_size));
13988 : }
13989 :
13990 : // copy reloc info
13991 : CopyBytes(relocation_start(),
13992 2555721 : desc.buffer + desc.buffer_size - desc.reloc_size,
13993 7667163 : static_cast<size_t>(desc.reloc_size));
13994 :
13995 : // unbox handles and relocate
13996 : int mode_mask = RelocInfo::kCodeTargetMask |
13997 : RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
13998 : RelocInfo::ModeMask(RelocInfo::CELL) |
13999 2555735 : RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
14000 2555735 : RelocInfo::kApplyMask;
14001 : // Needed to find target_object and runtime_entry on X64
14002 2555735 : Assembler* origin = desc.origin;
14003 : AllowDeferredHandleDereference embedding_raw_address;
14004 37669396 : for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
14005 35113628 : RelocInfo::Mode mode = it.rinfo()->rmode();
14006 35113628 : if (mode == RelocInfo::EMBEDDED_OBJECT) {
14007 16196461 : Handle<HeapObject> p = it.rinfo()->target_object_handle(origin);
14008 : it.rinfo()->set_target_object(*p, UPDATE_WRITE_BARRIER,
14009 : SKIP_ICACHE_FLUSH);
14010 18917167 : } else if (mode == RelocInfo::CELL) {
14011 38676 : Handle<Cell> cell = it.rinfo()->target_cell_handle();
14012 : it.rinfo()->set_target_cell(*cell, UPDATE_WRITE_BARRIER,
14013 : SKIP_ICACHE_FLUSH);
14014 18878491 : } else if (RelocInfo::IsCodeTarget(mode)) {
14015 : // rewrite code handles to direct pointers to the first instruction in the
14016 : // code object
14017 17875870 : Handle<Object> p = it.rinfo()->target_object_handle(origin);
14018 : Code* code = Code::cast(*p);
14019 : it.rinfo()->set_target_address(GetIsolate(), code->instruction_start(),
14020 35751748 : UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
14021 1002621 : } else if (RelocInfo::IsRuntimeEntry(mode)) {
14022 889879 : Address p = it.rinfo()->target_runtime_entry(origin);
14023 : it.rinfo()->set_target_runtime_entry(
14024 : GetIsolate(), p, UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
14025 112742 : } else if (mode == RelocInfo::CODE_AGE_SEQUENCE) {
14026 14 : Handle<Object> p = it.rinfo()->code_age_stub_handle(origin);
14027 : Code* code = Code::cast(*p);
14028 14 : it.rinfo()->set_code_age_stub(code, SKIP_ICACHE_FLUSH);
14029 : } else {
14030 112728 : intptr_t delta = instruction_start() - desc.buffer;
14031 : it.rinfo()->apply(delta);
14032 : }
14033 : }
14034 5111498 : Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size());
14035 2555741 : }
14036 :
14037 :
14038 1732479 : SafepointEntry Code::GetSafepointEntry(Address pc) {
14039 1732479 : SafepointTable table(this);
14040 1732479 : return table.FindEntry(pc);
14041 : }
14042 :
14043 :
14044 830620 : Object* Code::FindNthObject(int n, Map* match_map) {
14045 : DCHECK(is_inline_cache_stub());
14046 : DisallowHeapAllocation no_allocation;
14047 : int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
14048 1328530 : for (RelocIterator it(this, mask); !it.done(); it.next()) {
14049 573900 : RelocInfo* info = it.rinfo();
14050 : Object* object = info->target_object();
14051 573900 : if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
14052 573900 : if (object->IsHeapObject()) {
14053 573900 : if (HeapObject::cast(object)->map() == match_map) {
14054 75990 : if (--n == 0) return object;
14055 : }
14056 : }
14057 : }
14058 754630 : return NULL;
14059 : }
14060 :
14061 :
14062 382406 : AllocationSite* Code::FindFirstAllocationSite() {
14063 382406 : Object* result = FindNthObject(1, GetHeap()->allocation_site_map());
14064 382406 : return (result != NULL) ? AllocationSite::cast(result) : NULL;
14065 : }
14066 :
14067 :
14068 448214 : Map* Code::FindFirstMap() {
14069 448214 : Object* result = FindNthObject(1, GetHeap()->meta_map());
14070 448214 : return (result != NULL) ? Map::cast(result) : NULL;
14071 : }
14072 :
14073 :
14074 46824 : void Code::FindAndReplace(const FindAndReplacePattern& pattern) {
14075 : DCHECK(is_inline_cache_stub() || is_handler());
14076 : DisallowHeapAllocation no_allocation;
14077 : int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
14078 : STATIC_ASSERT(FindAndReplacePattern::kMaxCount < 32);
14079 : int current_pattern = 0;
14080 46824 : for (RelocIterator it(this, mask); !it.done(); it.next()) {
14081 46824 : RelocInfo* info = it.rinfo();
14082 : HeapObject* object = info->target_object();
14083 46824 : if (object->IsWeakCell()) {
14084 : object = HeapObject::cast(WeakCell::cast(object)->value());
14085 : }
14086 : Map* map = object->map();
14087 93648 : if (map == *pattern.find_[current_pattern]) {
14088 46824 : info->set_target_object(*pattern.replace_[current_pattern]);
14089 93648 : if (++current_pattern == pattern.count_) return;
14090 : }
14091 : }
14092 0 : UNREACHABLE();
14093 : }
14094 :
14095 :
14096 4538737 : void Code::ClearInlineCaches() {
14097 : int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
14098 : RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
14099 19743720 : for (RelocIterator it(this, mask); !it.done(); it.next()) {
14100 15204984 : RelocInfo* info = it.rinfo();
14101 : Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
14102 15204983 : if (target->is_inline_cache_stub()) {
14103 : ICUtility::Clear(this->GetIsolate(), info->pc(),
14104 132634 : info->host()->constant_pool());
14105 : }
14106 : }
14107 4538756 : }
14108 :
14109 : namespace {
14110 : template <typename Code>
14111 9579 : void SetStackFrameCacheCommon(Handle<Code> code,
14112 : Handle<UnseededNumberDictionary> cache) {
14113 : Handle<Object> maybe_table(code->source_position_table(), code->GetIsolate());
14114 9579 : if (maybe_table->IsSourcePositionTableWithFrameCache()) {
14115 638 : Handle<SourcePositionTableWithFrameCache>::cast(maybe_table)
14116 : ->set_stack_frame_cache(*cache);
14117 10217 : return;
14118 : }
14119 : DCHECK(maybe_table->IsByteArray());
14120 8941 : Handle<ByteArray> table(Handle<ByteArray>::cast(maybe_table));
14121 : Handle<SourcePositionTableWithFrameCache> table_with_cache =
14122 : code->GetIsolate()->factory()->NewSourcePositionTableWithFrameCache(
14123 8941 : table, cache);
14124 8941 : code->set_source_position_table(*table_with_cache);
14125 : }
14126 : } // namespace
14127 :
14128 : // static
14129 9579 : void AbstractCode::SetStackFrameCache(Handle<AbstractCode> abstract_code,
14130 : Handle<UnseededNumberDictionary> cache) {
14131 9579 : if (abstract_code->IsCode()) {
14132 2902 : SetStackFrameCacheCommon(handle(abstract_code->GetCode()), cache);
14133 : } else {
14134 6677 : SetStackFrameCacheCommon(handle(abstract_code->GetBytecodeArray()), cache);
14135 : }
14136 9579 : }
14137 :
14138 : namespace {
14139 : template <typename Code>
14140 8951201 : void DropStackFrameCacheCommon(Code* code) {
14141 : i::Object* maybe_table = code->source_position_table();
14142 17902402 : if (maybe_table->IsByteArray()) return;
14143 : DCHECK(maybe_table->IsSourcePositionTableWithFrameCache());
14144 0 : code->set_source_position_table(
14145 : i::SourcePositionTableWithFrameCache::cast(maybe_table)
14146 : ->source_position_table());
14147 : }
14148 : } // namespace
14149 :
14150 8951201 : void AbstractCode::DropStackFrameCache() {
14151 8951201 : if (IsCode()) {
14152 8940848 : DropStackFrameCacheCommon(GetCode());
14153 : } else {
14154 10353 : DropStackFrameCacheCommon(GetBytecodeArray());
14155 : }
14156 8951201 : }
14157 :
14158 2061453 : int AbstractCode::SourcePosition(int offset) {
14159 : int position = 0;
14160 : // Subtract one because the current PC is one instruction after the call site.
14161 2061453 : if (IsCode()) offset--;
14162 68753637 : for (SourcePositionTableIterator iterator(source_position_table());
14163 66692184 : !iterator.done() && iterator.code_offset() <= offset;
14164 64630731 : iterator.Advance()) {
14165 64630731 : position = iterator.source_position().ScriptOffset();
14166 : }
14167 2061453 : return position;
14168 : }
14169 :
14170 155428 : int AbstractCode::SourceStatementPosition(int offset) {
14171 : // First find the closest position.
14172 155428 : int position = SourcePosition(offset);
14173 : // Now find the closest statement position before the position.
14174 : int statement_position = 0;
14175 25648069 : for (SourcePositionTableIterator it(source_position_table()); !it.done();
14176 25337213 : it.Advance()) {
14177 25337213 : if (it.is_statement()) {
14178 10862058 : int p = it.source_position().ScriptOffset();
14179 10862058 : if (statement_position < p && p <= position) {
14180 : statement_position = p;
14181 : }
14182 : }
14183 : }
14184 155428 : return statement_position;
14185 : }
14186 :
14187 245079 : void JSFunction::ClearTypeFeedbackInfo() {
14188 245079 : if (feedback_vector_cell()->value()->IsFeedbackVector()) {
14189 : FeedbackVector* vector = feedback_vector();
14190 92298 : vector->ClearSlots(this);
14191 : }
14192 245079 : }
14193 :
14194 2641 : BailoutId Code::TranslatePcOffsetToAstId(uint32_t pc_offset) {
14195 : DisallowHeapAllocation no_gc;
14196 : DCHECK(kind() == FUNCTION);
14197 : BackEdgeTable back_edges(this, &no_gc);
14198 3625 : for (uint32_t i = 0; i < back_edges.length(); i++) {
14199 3625 : if (back_edges.pc_offset(i) == pc_offset) return back_edges.ast_id(i);
14200 : }
14201 : return BailoutId::None();
14202 : }
14203 :
14204 :
14205 0 : uint32_t Code::TranslateAstIdToPcOffset(BailoutId ast_id) {
14206 : DisallowHeapAllocation no_gc;
14207 : DCHECK(kind() == FUNCTION);
14208 : BackEdgeTable back_edges(this, &no_gc);
14209 0 : for (uint32_t i = 0; i < back_edges.length(); i++) {
14210 0 : if (back_edges.ast_id(i) == ast_id) return back_edges.pc_offset(i);
14211 : }
14212 0 : UNREACHABLE(); // We expect to find the back edge.
14213 : return 0;
14214 : }
14215 :
14216 656095 : void Code::MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate) {
14217 656451 : PatchPlatformCodeAge(isolate, sequence, kNoAgeCodeAge);
14218 656095 : }
14219 :
14220 :
14221 15 : void Code::MarkCodeAsExecuted(byte* sequence, Isolate* isolate) {
14222 15 : PatchPlatformCodeAge(isolate, sequence, kExecutedOnceCodeAge);
14223 15 : }
14224 :
14225 :
14226 : // NextAge defines the Code::Age state transitions during a GC cycle.
14227 : static Code::Age NextAge(Code::Age age) {
14228 1179528 : switch (age) {
14229 : case Code::kNotExecutedCodeAge: // Keep, until we've been executed.
14230 : case Code::kToBeExecutedOnceCodeAge: // Keep, until we've been executed.
14231 : case Code::kLastCodeAge: // Clamp at last Code::Age value.
14232 : return age;
14233 : case Code::kExecutedOnceCodeAge:
14234 : // Pre-age code that has only been executed once.
14235 : return static_cast<Code::Age>(Code::kPreAgedCodeAge + 1);
14236 : default:
14237 1010995 : return static_cast<Code::Age>(age + 1); // Default case: Increase age.
14238 : }
14239 : }
14240 :
14241 :
14242 : // IsOldAge defines the collection criteria for a Code object.
14243 : static bool IsOldAge(Code::Age age) {
14244 14061002 : return age >= Code::kIsOldCodeAge || age == Code::kNotExecutedCodeAge;
14245 : }
14246 :
14247 :
14248 207516 : void Code::MakeYoung(Isolate* isolate) {
14249 207516 : byte* sequence = FindCodeAgeSequence();
14250 207516 : if (sequence != NULL) MakeCodeAgeSequenceYoung(sequence, isolate);
14251 207516 : }
14252 :
14253 6 : void Code::PreAge(Isolate* isolate) {
14254 6 : byte* sequence = FindCodeAgeSequence();
14255 6 : if (sequence != NULL) {
14256 6 : PatchPlatformCodeAge(isolate, sequence, kPreAgedCodeAge);
14257 : }
14258 6 : }
14259 :
14260 48 : void Code::MarkToBeExecutedOnce(Isolate* isolate) {
14261 48 : byte* sequence = FindCodeAgeSequence();
14262 48 : if (sequence != NULL) {
14263 12 : PatchPlatformCodeAge(isolate, sequence, kToBeExecutedOnceCodeAge);
14264 : }
14265 48 : }
14266 :
14267 74612653 : void Code::MakeOlder() {
14268 74612653 : byte* sequence = FindCodeAgeSequence();
14269 74612666 : if (sequence != NULL) {
14270 : Isolate* isolate = GetIsolate();
14271 1179528 : Age age = GetCodeAge(isolate, sequence);
14272 : Age next_age = NextAge(age);
14273 1179528 : if (age != next_age) {
14274 1011003 : PatchPlatformCodeAge(isolate, sequence, next_age);
14275 : }
14276 : }
14277 74612666 : }
14278 :
14279 :
14280 13882333 : bool Code::IsOld() {
14281 27943335 : return IsOldAge(GetAge());
14282 : }
14283 :
14284 :
14285 177813255 : byte* Code::FindCodeAgeSequence() {
14286 177813290 : return FLAG_age_code &&
14287 113043475 : prologue_offset() != Code::kPrologueOffsetNotSet &&
14288 110748328 : (kind() == OPTIMIZED_FUNCTION ||
14289 4521432 : (kind() == FUNCTION && !has_debug_break_slots()))
14290 6303546 : ? instruction_start() + prologue_offset()
14291 184116801 : : NULL;
14292 : }
14293 :
14294 :
14295 14061008 : Code::Age Code::GetAge() {
14296 14061008 : byte* sequence = FindCodeAgeSequence();
14297 14061008 : if (sequence == NULL) {
14298 : return kNoAgeCodeAge;
14299 : }
14300 635994 : return GetCodeAge(GetIsolate(), sequence);
14301 : }
14302 :
14303 623965 : Code::Age Code::GetAgeOfCodeAgeStub(Code* code) {
14304 : Isolate* isolate = code->GetIsolate();
14305 623965 : Builtins* builtins = isolate->builtins();
14306 : #define HANDLE_CODE_AGE(AGE) \
14307 : if (code == *builtins->Make##AGE##CodeYoungAgain()) { \
14308 : return k##AGE##CodeAge; \
14309 : }
14310 2286519 : CODE_AGE_LIST(HANDLE_CODE_AGE)
14311 : #undef HANDLE_CODE_AGE
14312 98 : if (code == *builtins->MarkCodeAsExecutedOnce()) {
14313 : return kNotExecutedCodeAge;
14314 : }
14315 74 : if (code == *builtins->MarkCodeAsExecutedTwice()) {
14316 : return kExecutedOnceCodeAge;
14317 : }
14318 52 : if (code == *builtins->MarkCodeAsToBeExecutedOnce()) {
14319 : return kToBeExecutedOnceCodeAge;
14320 : }
14321 0 : UNREACHABLE();
14322 : return kNoAgeCodeAge;
14323 : }
14324 :
14325 1011036 : Code* Code::GetCodeAgeStub(Isolate* isolate, Age age) {
14326 1011036 : Builtins* builtins = isolate->builtins();
14327 1011036 : switch (age) {
14328 : #define HANDLE_CODE_AGE(AGE) \
14329 : case k##AGE##CodeAge: { \
14330 : return *builtins->Make##AGE##CodeYoungAgain(); \
14331 : }
14332 1792441 : CODE_AGE_LIST(HANDLE_CODE_AGE)
14333 : #undef HANDLE_CODE_AGE
14334 : case kNotExecutedCodeAge: {
14335 0 : return *builtins->MarkCodeAsExecutedOnce();
14336 : }
14337 : case kExecutedOnceCodeAge: {
14338 30 : return *builtins->MarkCodeAsExecutedTwice();
14339 : }
14340 : case kToBeExecutedOnceCodeAge: {
14341 24 : return *builtins->MarkCodeAsToBeExecutedOnce();
14342 : }
14343 : default:
14344 0 : UNREACHABLE();
14345 : break;
14346 : }
14347 : return NULL;
14348 : }
14349 :
14350 :
14351 0 : void Code::PrintDeoptLocation(FILE* out, Address pc) {
14352 0 : Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(this, pc);
14353 0 : class SourcePosition pos = info.position;
14354 0 : if (info.deopt_reason != DeoptimizeReason::kNoReason || pos.IsKnown()) {
14355 0 : if (FLAG_hydrogen_track_positions) {
14356 : PrintF(out, " ;;; deoptimize at %d_%d: %s\n", pos.InliningId(),
14357 0 : pos.ScriptOffset(), DeoptimizeReasonToString(info.deopt_reason));
14358 : } else {
14359 0 : PrintF(out, " ;;; deoptimize at ");
14360 0 : OFStream outstr(out);
14361 0 : pos.Print(outstr, this);
14362 0 : PrintF(out, ", %s\n", DeoptimizeReasonToString(info.deopt_reason));
14363 : }
14364 : }
14365 0 : }
14366 :
14367 :
14368 5320 : bool Code::CanDeoptAt(Address pc) {
14369 : DeoptimizationInputData* deopt_data =
14370 : DeoptimizationInputData::cast(deoptimization_data());
14371 5320 : Address code_start_address = instruction_start();
14372 186920 : for (int i = 0; i < deopt_data->DeoptCount(); i++) {
14373 185032 : if (deopt_data->Pc(i)->value() == -1) continue;
14374 124414 : Address address = code_start_address + deopt_data->Pc(i)->value();
14375 66584 : if (address == pc && deopt_data->AstId(i) != BailoutId::None()) {
14376 : return true;
14377 : }
14378 : }
14379 : return false;
14380 : }
14381 :
14382 :
14383 : // Identify kind of code.
14384 29547 : const char* Code::Kind2String(Kind kind) {
14385 29547 : switch (kind) {
14386 : #define CASE(name) case name: return #name;
14387 0 : CODE_KIND_LIST(CASE)
14388 : #undef CASE
14389 : case NUMBER_OF_KINDS: break;
14390 : }
14391 0 : UNREACHABLE();
14392 : return NULL;
14393 : }
14394 :
14395 : // Identify kind of code.
14396 0 : const char* AbstractCode::Kind2String(Kind kind) {
14397 0 : if (kind < AbstractCode::INTERPRETED_FUNCTION)
14398 0 : return Code::Kind2String((Code::Kind)kind);
14399 0 : if (kind == AbstractCode::INTERPRETED_FUNCTION) return "INTERPRETED_FUNCTION";
14400 0 : UNREACHABLE();
14401 : return NULL;
14402 : }
14403 :
14404 2560818 : Handle<WeakCell> Code::WeakCellFor(Handle<Code> code) {
14405 : DCHECK(code->kind() == OPTIMIZED_FUNCTION);
14406 2560818 : WeakCell* raw_cell = code->CachedWeakCell();
14407 4787618 : if (raw_cell != NULL) return Handle<WeakCell>(raw_cell);
14408 334024 : Handle<WeakCell> cell = code->GetIsolate()->factory()->NewWeakCell(code);
14409 : DeoptimizationInputData::cast(code->deoptimization_data())
14410 : ->SetWeakCellCache(*cell);
14411 334024 : return cell;
14412 : }
14413 :
14414 :
14415 2560818 : WeakCell* Code::CachedWeakCell() {
14416 : DCHECK(kind() == OPTIMIZED_FUNCTION);
14417 : Object* weak_cell_cache =
14418 : DeoptimizationInputData::cast(deoptimization_data())->WeakCellCache();
14419 2560818 : if (weak_cell_cache->IsWeakCell()) {
14420 : DCHECK(this == WeakCell::cast(weak_cell_cache)->value());
14421 2226797 : return WeakCell::cast(weak_cell_cache);
14422 : }
14423 : return NULL;
14424 : }
14425 :
14426 : #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
14427 :
14428 : const char* Code::ICState2String(InlineCacheState state) {
14429 : switch (state) {
14430 : case UNINITIALIZED:
14431 : return "UNINITIALIZED";
14432 : case PREMONOMORPHIC:
14433 : return "PREMONOMORPHIC";
14434 : case MONOMORPHIC:
14435 : return "MONOMORPHIC";
14436 : case RECOMPUTE_HANDLER:
14437 : return "RECOMPUTE_HANDLER";
14438 : case POLYMORPHIC:
14439 : return "POLYMORPHIC";
14440 : case MEGAMORPHIC:
14441 : return "MEGAMORPHIC";
14442 : case GENERIC:
14443 : return "GENERIC";
14444 : }
14445 : UNREACHABLE();
14446 : return NULL;
14447 : }
14448 :
14449 : void Code::PrintExtraICState(std::ostream& os, // NOLINT
14450 : Kind kind, ExtraICState extra) {
14451 : os << "extra_ic_state = ";
14452 : if ((kind == STORE_IC || kind == KEYED_STORE_IC) &&
14453 : is_strict(static_cast<LanguageMode>(extra))) {
14454 : os << "STRICT\n";
14455 : } else {
14456 : os << extra << "\n";
14457 : }
14458 : }
14459 :
14460 : #endif // defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
14461 :
14462 : #ifdef ENABLE_DISASSEMBLER
14463 :
14464 : void DeoptimizationInputData::DeoptimizationInputDataPrint(
14465 : std::ostream& os) { // NOLINT
14466 : disasm::NameConverter converter;
14467 : int const inlined_function_count = InlinedFunctionCount()->value();
14468 : os << "Inlined functions (count = " << inlined_function_count << ")\n";
14469 : for (int id = 0; id < inlined_function_count; ++id) {
14470 : Object* info = LiteralArray()->get(id);
14471 : os << " " << Brief(SharedFunctionInfo::cast(info)) << "\n";
14472 : }
14473 : os << "\n";
14474 : int deopt_count = DeoptCount();
14475 : os << "Deoptimization Input Data (deopt points = " << deopt_count << ")\n";
14476 : if (0 != deopt_count) {
14477 : os << " index ast id argc pc";
14478 : if (FLAG_print_code_verbose) os << " commands";
14479 : os << "\n";
14480 : }
14481 : for (int i = 0; i < deopt_count; i++) {
14482 : os << std::setw(6) << i << " " << std::setw(6) << AstId(i).ToInt() << " "
14483 : << std::setw(6) << ArgumentsStackHeight(i)->value() << " "
14484 : << std::setw(6) << Pc(i)->value();
14485 :
14486 : if (!FLAG_print_code_verbose) {
14487 : os << "\n";
14488 : continue;
14489 : }
14490 : // Print details of the frame translation.
14491 : int translation_index = TranslationIndex(i)->value();
14492 : TranslationIterator iterator(TranslationByteArray(), translation_index);
14493 : Translation::Opcode opcode =
14494 : static_cast<Translation::Opcode>(iterator.Next());
14495 : DCHECK(Translation::BEGIN == opcode);
14496 : int frame_count = iterator.Next();
14497 : int jsframe_count = iterator.Next();
14498 : os << " " << Translation::StringFor(opcode)
14499 : << " {frame count=" << frame_count
14500 : << ", js frame count=" << jsframe_count << "}\n";
14501 :
14502 : while (iterator.HasNext() &&
14503 : Translation::BEGIN !=
14504 : (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
14505 : os << std::setw(31) << " " << Translation::StringFor(opcode) << " ";
14506 :
14507 : switch (opcode) {
14508 : case Translation::BEGIN:
14509 : UNREACHABLE();
14510 : break;
14511 :
14512 : case Translation::JS_FRAME: {
14513 : int ast_id = iterator.Next();
14514 : int shared_info_id = iterator.Next();
14515 : unsigned height = iterator.Next();
14516 : Object* shared_info = LiteralArray()->get(shared_info_id);
14517 : os << "{ast_id=" << ast_id << ", function="
14518 : << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14519 : << ", height=" << height << "}";
14520 : break;
14521 : }
14522 :
14523 : case Translation::INTERPRETED_FRAME: {
14524 : int bytecode_offset = iterator.Next();
14525 : int shared_info_id = iterator.Next();
14526 : unsigned height = iterator.Next();
14527 : Object* shared_info = LiteralArray()->get(shared_info_id);
14528 : os << "{bytecode_offset=" << bytecode_offset << ", function="
14529 : << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14530 : << ", height=" << height << "}";
14531 : break;
14532 : }
14533 :
14534 : case Translation::CONSTRUCT_STUB_FRAME: {
14535 : int bailout_id = iterator.Next();
14536 : int shared_info_id = iterator.Next();
14537 : Object* shared_info = LiteralArray()->get(shared_info_id);
14538 : unsigned height = iterator.Next();
14539 : os << "{bailout_id=" << bailout_id << ", function="
14540 : << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14541 : << ", height=" << height << "}";
14542 : break;
14543 : }
14544 :
14545 : case Translation::COMPILED_STUB_FRAME: {
14546 : Code::Kind stub_kind = static_cast<Code::Kind>(iterator.Next());
14547 : os << "{kind=" << stub_kind << "}";
14548 : break;
14549 : }
14550 :
14551 : case Translation::ARGUMENTS_ADAPTOR_FRAME: {
14552 : int shared_info_id = iterator.Next();
14553 : Object* shared_info = LiteralArray()->get(shared_info_id);
14554 : unsigned height = iterator.Next();
14555 : os << "{function="
14556 : << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14557 : << ", height=" << height << "}";
14558 : break;
14559 : }
14560 :
14561 : case Translation::TAIL_CALLER_FRAME: {
14562 : int shared_info_id = iterator.Next();
14563 : Object* shared_info = LiteralArray()->get(shared_info_id);
14564 : os << "{function="
14565 : << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14566 : << "}";
14567 : break;
14568 : }
14569 :
14570 : case Translation::GETTER_STUB_FRAME:
14571 : case Translation::SETTER_STUB_FRAME: {
14572 : int shared_info_id = iterator.Next();
14573 : Object* shared_info = LiteralArray()->get(shared_info_id);
14574 : os << "{function=" << Brief(SharedFunctionInfo::cast(shared_info)
14575 : ->DebugName()) << "}";
14576 : break;
14577 : }
14578 :
14579 : case Translation::REGISTER: {
14580 : int reg_code = iterator.Next();
14581 : os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
14582 : break;
14583 : }
14584 :
14585 : case Translation::INT32_REGISTER: {
14586 : int reg_code = iterator.Next();
14587 : os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
14588 : break;
14589 : }
14590 :
14591 : case Translation::UINT32_REGISTER: {
14592 : int reg_code = iterator.Next();
14593 : os << "{input=" << converter.NameOfCPURegister(reg_code)
14594 : << " (unsigned)}";
14595 : break;
14596 : }
14597 :
14598 : case Translation::BOOL_REGISTER: {
14599 : int reg_code = iterator.Next();
14600 : os << "{input=" << converter.NameOfCPURegister(reg_code)
14601 : << " (bool)}";
14602 : break;
14603 : }
14604 :
14605 : case Translation::FLOAT_REGISTER: {
14606 : int reg_code = iterator.Next();
14607 : os << "{input="
14608 : << RegisterConfiguration::Crankshaft()->GetFloatRegisterName(
14609 : reg_code)
14610 : << "}";
14611 : break;
14612 : }
14613 :
14614 : case Translation::DOUBLE_REGISTER: {
14615 : int reg_code = iterator.Next();
14616 : os << "{input="
14617 : << RegisterConfiguration::Crankshaft()->GetDoubleRegisterName(
14618 : reg_code)
14619 : << "}";
14620 : break;
14621 : }
14622 :
14623 : case Translation::STACK_SLOT: {
14624 : int input_slot_index = iterator.Next();
14625 : os << "{input=" << input_slot_index << "}";
14626 : break;
14627 : }
14628 :
14629 : case Translation::INT32_STACK_SLOT: {
14630 : int input_slot_index = iterator.Next();
14631 : os << "{input=" << input_slot_index << "}";
14632 : break;
14633 : }
14634 :
14635 : case Translation::UINT32_STACK_SLOT: {
14636 : int input_slot_index = iterator.Next();
14637 : os << "{input=" << input_slot_index << " (unsigned)}";
14638 : break;
14639 : }
14640 :
14641 : case Translation::BOOL_STACK_SLOT: {
14642 : int input_slot_index = iterator.Next();
14643 : os << "{input=" << input_slot_index << " (bool)}";
14644 : break;
14645 : }
14646 :
14647 : case Translation::FLOAT_STACK_SLOT:
14648 : case Translation::DOUBLE_STACK_SLOT: {
14649 : int input_slot_index = iterator.Next();
14650 : os << "{input=" << input_slot_index << "}";
14651 : break;
14652 : }
14653 :
14654 : case Translation::LITERAL: {
14655 : int literal_index = iterator.Next();
14656 : Object* literal_value = LiteralArray()->get(literal_index);
14657 : os << "{literal_id=" << literal_index << " (" << Brief(literal_value)
14658 : << ")}";
14659 : break;
14660 : }
14661 :
14662 : case Translation::DUPLICATED_OBJECT: {
14663 : int object_index = iterator.Next();
14664 : os << "{object_index=" << object_index << "}";
14665 : break;
14666 : }
14667 :
14668 : case Translation::ARGUMENTS_ELEMENTS:
14669 : case Translation::ARGUMENTS_LENGTH: {
14670 : bool is_rest = iterator.Next();
14671 : os << "{is_rest=" << (is_rest ? "true" : "false") << "}";
14672 : break;
14673 : }
14674 :
14675 : case Translation::ARGUMENTS_OBJECT:
14676 : case Translation::CAPTURED_OBJECT: {
14677 : int args_length = iterator.Next();
14678 : os << "{length=" << args_length << "}";
14679 : break;
14680 : }
14681 : }
14682 : os << "\n";
14683 : }
14684 : }
14685 : }
14686 :
14687 :
14688 : void DeoptimizationOutputData::DeoptimizationOutputDataPrint(
14689 : std::ostream& os) { // NOLINT
14690 : os << "Deoptimization Output Data (deopt points = " << this->DeoptPoints()
14691 : << ")\n";
14692 : if (this->DeoptPoints() == 0) return;
14693 :
14694 : os << "ast id pc state\n";
14695 : for (int i = 0; i < this->DeoptPoints(); i++) {
14696 : int pc_and_state = this->PcAndState(i)->value();
14697 : os << std::setw(6) << this->AstId(i).ToInt() << " " << std::setw(8)
14698 : << FullCodeGenerator::PcField::decode(pc_and_state) << " "
14699 : << Deoptimizer::BailoutStateToString(
14700 : FullCodeGenerator::BailoutStateField::decode(pc_and_state))
14701 : << "\n";
14702 : }
14703 : }
14704 :
14705 :
14706 : void HandlerTable::HandlerTableRangePrint(std::ostream& os) {
14707 : os << " from to hdlr\n";
14708 : for (int i = 0; i < length(); i += kRangeEntrySize) {
14709 : int pc_start = Smi::cast(get(i + kRangeStartIndex))->value();
14710 : int pc_end = Smi::cast(get(i + kRangeEndIndex))->value();
14711 : int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value();
14712 : int handler_offset = HandlerOffsetField::decode(handler_field);
14713 : CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
14714 : int data = Smi::cast(get(i + kRangeDataIndex))->value();
14715 : os << " (" << std::setw(4) << pc_start << "," << std::setw(4) << pc_end
14716 : << ") -> " << std::setw(4) << handler_offset
14717 : << " (prediction=" << prediction << ", data=" << data << ")\n";
14718 : }
14719 : }
14720 :
14721 :
14722 : void HandlerTable::HandlerTableReturnPrint(std::ostream& os) {
14723 : os << " off hdlr (c)\n";
14724 : for (int i = 0; i < length(); i += kReturnEntrySize) {
14725 : int pc_offset = Smi::cast(get(i + kReturnOffsetIndex))->value();
14726 : int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value();
14727 : int handler_offset = HandlerOffsetField::decode(handler_field);
14728 : CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
14729 : os << " " << std::setw(4) << pc_offset << " -> " << std::setw(4)
14730 : << handler_offset << " (prediction=" << prediction << ")\n";
14731 : }
14732 : }
14733 :
14734 :
14735 : void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT
14736 : os << "kind = " << Kind2String(kind()) << "\n";
14737 : if (IsCodeStubOrIC()) {
14738 : const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this));
14739 : os << "major_key = " << (n == NULL ? "null" : n) << "\n";
14740 : }
14741 : if (is_inline_cache_stub()) {
14742 : if (is_compare_ic_stub() || is_to_boolean_ic_stub() ||
14743 : is_binary_op_stub()) {
14744 : InlineCacheState ic_state = IC::StateFromCode(this);
14745 : os << "ic_state = " << ICState2String(ic_state) << "\n";
14746 : PrintExtraICState(os, kind(), extra_ic_state());
14747 : }
14748 : if (is_compare_ic_stub()) {
14749 : DCHECK(CodeStub::GetMajorKey(this) == CodeStub::CompareIC);
14750 : CompareICStub stub(stub_key(), GetIsolate());
14751 : os << "compare_state = " << CompareICState::GetStateName(stub.left())
14752 : << "*" << CompareICState::GetStateName(stub.right()) << " -> "
14753 : << CompareICState::GetStateName(stub.state()) << "\n";
14754 : os << "compare_operation = " << Token::Name(stub.op()) << "\n";
14755 : }
14756 : }
14757 : if ((name != nullptr) && (name[0] != '\0')) {
14758 : os << "name = " << name << "\n";
14759 : } else if (kind() == BUILTIN) {
14760 : name = GetIsolate()->builtins()->Lookup(instruction_start());
14761 : if (name != nullptr) {
14762 : os << "name = " << name << "\n";
14763 : }
14764 : } else if (kind() == BYTECODE_HANDLER) {
14765 : name = GetIsolate()->interpreter()->LookupNameOfBytecodeHandler(this);
14766 : if (name != nullptr) {
14767 : os << "name = " << name << "\n";
14768 : }
14769 : }
14770 : if (kind() == OPTIMIZED_FUNCTION) {
14771 : os << "stack_slots = " << stack_slots() << "\n";
14772 : }
14773 : os << "compiler = " << (is_turbofanned()
14774 : ? "turbofan"
14775 : : is_crankshafted() ? "crankshaft"
14776 : : kind() == Code::FUNCTION
14777 : ? "full-codegen"
14778 : : "unknown") << "\n";
14779 :
14780 : os << "Instructions (size = " << instruction_size() << ")\n";
14781 : {
14782 : Isolate* isolate = GetIsolate();
14783 : int size = instruction_size();
14784 : int safepoint_offset =
14785 : is_crankshafted() ? static_cast<int>(safepoint_table_offset()) : size;
14786 : int back_edge_offset = (kind() == Code::FUNCTION)
14787 : ? static_cast<int>(back_edge_table_offset())
14788 : : size;
14789 : int constant_pool_offset = FLAG_enable_embedded_constant_pool
14790 : ? this->constant_pool_offset()
14791 : : size;
14792 :
14793 : // Stop before reaching any embedded tables
14794 : int code_size = Min(safepoint_offset, back_edge_offset);
14795 : code_size = Min(code_size, constant_pool_offset);
14796 : byte* begin = instruction_start();
14797 : byte* end = begin + code_size;
14798 : Disassembler::Decode(isolate, &os, begin, end, this);
14799 :
14800 : if (constant_pool_offset < size) {
14801 : int constant_pool_size = size - constant_pool_offset;
14802 : DCHECK((constant_pool_size & kPointerAlignmentMask) == 0);
14803 : os << "\nConstant Pool (size = " << constant_pool_size << ")\n";
14804 : Vector<char> buf = Vector<char>::New(50);
14805 : intptr_t* ptr = reinterpret_cast<intptr_t*>(begin + constant_pool_offset);
14806 : for (int i = 0; i < constant_pool_size; i += kPointerSize, ptr++) {
14807 : SNPrintF(buf, "%4d %08" V8PRIxPTR, i, *ptr);
14808 : os << static_cast<const void*>(ptr) << " " << buf.start() << "\n";
14809 : }
14810 : }
14811 : }
14812 : os << "\n";
14813 :
14814 : SourcePositionTableIterator it(SourcePositionTable());
14815 : if (!it.done()) {
14816 : os << "Source positions:\n pc offset position\n";
14817 : for (; !it.done(); it.Advance()) {
14818 : os << std::setw(10) << std::hex << it.code_offset() << std::dec
14819 : << std::setw(10) << it.source_position().ScriptOffset()
14820 : << (it.is_statement() ? " statement" : "") << "\n";
14821 : }
14822 : os << "\n";
14823 : }
14824 :
14825 : if (kind() == FUNCTION) {
14826 : DeoptimizationOutputData* data =
14827 : DeoptimizationOutputData::cast(this->deoptimization_data());
14828 : data->DeoptimizationOutputDataPrint(os);
14829 : } else if (kind() == OPTIMIZED_FUNCTION) {
14830 : DeoptimizationInputData* data =
14831 : DeoptimizationInputData::cast(this->deoptimization_data());
14832 : data->DeoptimizationInputDataPrint(os);
14833 : }
14834 : os << "\n";
14835 :
14836 : if (is_crankshafted()) {
14837 : SafepointTable table(this);
14838 : os << "Safepoints (size = " << table.size() << ")\n";
14839 : for (unsigned i = 0; i < table.length(); i++) {
14840 : unsigned pc_offset = table.GetPcOffset(i);
14841 : os << static_cast<const void*>(instruction_start() + pc_offset) << " ";
14842 : os << std::setw(4) << std::hex << pc_offset << std::dec << " ";
14843 : table.PrintEntry(i, os);
14844 : os << " (sp -> fp) ";
14845 : SafepointEntry entry = table.GetEntry(i);
14846 : if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
14847 : os << std::setw(6) << entry.deoptimization_index();
14848 : } else {
14849 : os << "<none>";
14850 : }
14851 : if (entry.argument_count() > 0) {
14852 : os << " argc: " << entry.argument_count();
14853 : }
14854 : os << "\n";
14855 : }
14856 : os << "\n";
14857 : } else if (kind() == FUNCTION) {
14858 : unsigned offset = back_edge_table_offset();
14859 : // If there is no back edge table, the "table start" will be at or after
14860 : // (due to alignment) the end of the instruction stream.
14861 : if (static_cast<int>(offset) < instruction_size()) {
14862 : DisallowHeapAllocation no_gc;
14863 : BackEdgeTable back_edges(this, &no_gc);
14864 :
14865 : os << "Back edges (size = " << back_edges.length() << ")\n";
14866 : os << "ast_id pc_offset loop_depth\n";
14867 :
14868 : for (uint32_t i = 0; i < back_edges.length(); i++) {
14869 : os << std::setw(6) << back_edges.ast_id(i).ToInt() << " "
14870 : << std::setw(9) << std::hex << back_edges.pc_offset(i) << std::dec
14871 : << " " << std::setw(10) << back_edges.loop_depth(i) << "\n";
14872 : }
14873 :
14874 : os << "\n";
14875 : }
14876 : #ifdef OBJECT_PRINT
14877 : if (!type_feedback_info()->IsUndefined(GetIsolate())) {
14878 : TypeFeedbackInfo* info = TypeFeedbackInfo::cast(type_feedback_info());
14879 : HeapObject::PrintHeader(os, "TypeFeedbackInfo");
14880 : os << "\n - ic_total_count: " << info->ic_total_count()
14881 : << ", ic_with_type_info_count: " << info->ic_with_type_info_count()
14882 : << ", ic_generic_count: " << info->ic_generic_count() << "\n";
14883 : os << "\n";
14884 : }
14885 : #endif
14886 : }
14887 :
14888 : if (handler_table()->length() > 0) {
14889 : os << "Handler Table (size = " << handler_table()->Size() << ")\n";
14890 : if (kind() == FUNCTION) {
14891 : HandlerTable::cast(handler_table())->HandlerTableRangePrint(os);
14892 : } else if (kind() == OPTIMIZED_FUNCTION) {
14893 : HandlerTable::cast(handler_table())->HandlerTableReturnPrint(os);
14894 : }
14895 : os << "\n";
14896 : }
14897 :
14898 : os << "RelocInfo (size = " << relocation_size() << ")\n";
14899 : for (RelocIterator it(this); !it.done(); it.next()) {
14900 : it.rinfo()->Print(GetIsolate(), os);
14901 : }
14902 : os << "\n";
14903 :
14904 : if (has_unwinding_info()) {
14905 : os << "UnwindingInfo (size = " << unwinding_info_size() << ")\n";
14906 : EhFrameDisassembler eh_frame_disassembler(unwinding_info_start(),
14907 : unwinding_info_end());
14908 : eh_frame_disassembler.DisassembleToStream(os);
14909 : os << "\n";
14910 : }
14911 : }
14912 : #endif // ENABLE_DISASSEMBLER
14913 :
14914 :
14915 0 : void BytecodeArray::Disassemble(std::ostream& os) {
14916 0 : os << "Parameter count " << parameter_count() << "\n";
14917 0 : os << "Frame size " << frame_size() << "\n";
14918 :
14919 0 : const uint8_t* base_address = GetFirstBytecodeAddress();
14920 0 : SourcePositionTableIterator source_positions(SourcePositionTable());
14921 :
14922 0 : interpreter::BytecodeArrayIterator iterator(handle(this));
14923 0 : while (!iterator.done()) {
14924 0 : if (!source_positions.done() &&
14925 0 : iterator.current_offset() == source_positions.code_offset()) {
14926 0 : os << std::setw(5) << source_positions.source_position().ScriptOffset();
14927 0 : os << (source_positions.is_statement() ? " S> " : " E> ");
14928 0 : source_positions.Advance();
14929 : } else {
14930 0 : os << " ";
14931 : }
14932 0 : const uint8_t* current_address = base_address + iterator.current_offset();
14933 0 : os << reinterpret_cast<const void*>(current_address) << " @ "
14934 0 : << std::setw(4) << iterator.current_offset() << " : ";
14935 : interpreter::BytecodeDecoder::Decode(os, current_address,
14936 0 : parameter_count());
14937 0 : if (interpreter::Bytecodes::IsJump(iterator.current_bytecode())) {
14938 0 : const void* jump_target = base_address + iterator.GetJumpTargetOffset();
14939 0 : os << " (" << jump_target << " @ " << iterator.GetJumpTargetOffset()
14940 0 : << ")";
14941 : }
14942 : os << std::endl;
14943 0 : iterator.Advance();
14944 : }
14945 :
14946 0 : if (constant_pool()->length() > 0) {
14947 0 : os << "Constant pool (size = " << constant_pool()->length() << ")\n";
14948 : constant_pool()->Print();
14949 : }
14950 :
14951 : #ifdef ENABLE_DISASSEMBLER
14952 : if (handler_table()->length() > 0) {
14953 : os << "Handler Table (size = " << handler_table()->Size() << ")\n";
14954 : HandlerTable::cast(handler_table())->HandlerTableRangePrint(os);
14955 : }
14956 : #endif
14957 0 : }
14958 :
14959 9490 : void BytecodeArray::CopyBytecodesTo(BytecodeArray* to) {
14960 : BytecodeArray* from = this;
14961 : DCHECK_EQ(from->length(), to->length());
14962 9490 : CopyBytes(to->GetFirstBytecodeAddress(), from->GetFirstBytecodeAddress(),
14963 18980 : from->length());
14964 9490 : }
14965 :
14966 1944461 : void BytecodeArray::MakeOlder() {
14967 : Age age = bytecode_age();
14968 1944461 : if (age < kLastBytecodeAge) {
14969 1405208 : set_bytecode_age(static_cast<Age>(age + 1));
14970 : }
14971 : DCHECK_GE(bytecode_age(), kFirstBytecodeAge);
14972 : DCHECK_LE(bytecode_age(), kLastBytecodeAge);
14973 1944461 : }
14974 :
14975 0 : bool BytecodeArray::IsOld() const {
14976 246687 : return bytecode_age() >= kIsOldBytecodeAge;
14977 : }
14978 :
14979 : // static
14980 352330 : void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
14981 : DCHECK(capacity >= 0);
14982 : array->GetIsolate()->factory()->NewJSArrayStorage(
14983 352330 : array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
14984 352330 : }
14985 :
14986 1562733 : void JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) {
14987 : // We should never end in here with a pixel or external array.
14988 : DCHECK(array->AllowsSetLength());
14989 1562733 : if (array->SetLengthWouldNormalize(new_length)) {
14990 1515 : JSObject::NormalizeElements(array);
14991 : }
14992 1562733 : array->GetElementsAccessor()->SetLength(array, new_length);
14993 1562733 : }
14994 :
14995 :
14996 : // static
14997 324603 : void Map::AddDependentCode(Handle<Map> map,
14998 : DependentCode::DependencyGroup group,
14999 : Handle<Code> code) {
15000 324603 : Handle<WeakCell> cell = Code::WeakCellFor(code);
15001 : Handle<DependentCode> codes = DependentCode::InsertWeakCode(
15002 : Handle<DependentCode>(map->dependent_code()), group, cell);
15003 324603 : if (*codes != map->dependent_code()) map->set_dependent_code(*codes);
15004 324603 : }
15005 :
15006 :
15007 905458 : Handle<DependentCode> DependentCode::InsertCompilationDependencies(
15008 : Handle<DependentCode> entries, DependencyGroup group,
15009 : Handle<Foreign> info) {
15010 905458 : return Insert(entries, group, info);
15011 : }
15012 :
15013 :
15014 1050332 : Handle<DependentCode> DependentCode::InsertWeakCode(
15015 : Handle<DependentCode> entries, DependencyGroup group,
15016 : Handle<WeakCell> code_cell) {
15017 1374935 : return Insert(entries, group, code_cell);
15018 : }
15019 :
15020 :
15021 2301002 : Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
15022 : DependencyGroup group,
15023 : Handle<Object> object) {
15024 4225772 : if (entries->length() == 0 || entries->group() > group) {
15025 : // There is no such group.
15026 391634 : return DependentCode::New(group, object, entries);
15027 : }
15028 1909368 : if (entries->group() < group) {
15029 : // The group comes later in the list.
15030 : Handle<DependentCode> old_next(entries->next_link());
15031 20608 : Handle<DependentCode> new_next = Insert(old_next, group, object);
15032 20608 : if (!old_next.is_identical_to(new_next)) {
15033 : entries->set_next_link(*new_next);
15034 : }
15035 20608 : return entries;
15036 : }
15037 : DCHECK_EQ(group, entries->group());
15038 : int count = entries->count();
15039 : // Check for existing entry to avoid duplicates.
15040 168781175 : for (int i = 0; i < count; i++) {
15041 168082326 : if (entries->object_at(i) == *object) return entries;
15042 : }
15043 1397698 : if (entries->length() < kCodesStartIndex + count + 1) {
15044 271033 : entries = EnsureSpace(entries);
15045 : // Count could have changed, reload it.
15046 : count = entries->count();
15047 : }
15048 : entries->set_object_at(count, *object);
15049 1397698 : entries->set_count(count + 1);
15050 698849 : return entries;
15051 : }
15052 :
15053 :
15054 391633 : Handle<DependentCode> DependentCode::New(DependencyGroup group,
15055 : Handle<Object> object,
15056 : Handle<DependentCode> next) {
15057 : Isolate* isolate = next->GetIsolate();
15058 : Handle<DependentCode> result = Handle<DependentCode>::cast(
15059 391633 : isolate->factory()->NewFixedArray(kCodesStartIndex + 1, TENURED));
15060 : result->set_next_link(*next);
15061 391634 : result->set_flags(GroupField::encode(group) | CountField::encode(1));
15062 : result->set_object_at(0, *object);
15063 391634 : return result;
15064 : }
15065 :
15066 :
15067 271033 : Handle<DependentCode> DependentCode::EnsureSpace(
15068 : Handle<DependentCode> entries) {
15069 271033 : if (entries->Compact()) return entries;
15070 : Isolate* isolate = entries->GetIsolate();
15071 260886 : int capacity = kCodesStartIndex + DependentCode::Grow(entries->count());
15072 260886 : int grow_by = capacity - entries->length();
15073 : return Handle<DependentCode>::cast(
15074 260886 : isolate->factory()->CopyFixedArrayAndGrow(entries, grow_by, TENURED));
15075 : }
15076 :
15077 :
15078 271033 : bool DependentCode::Compact() {
15079 : int old_count = count();
15080 : int new_count = 0;
15081 2911822 : for (int i = 0; i < old_count; i++) {
15082 : Object* obj = object_at(i);
15083 5269032 : if (!obj->IsWeakCell() || !WeakCell::cast(obj)->cleared()) {
15084 2605292 : if (i != new_count) {
15085 8726 : copy(i, new_count);
15086 : }
15087 2605292 : new_count++;
15088 : }
15089 : }
15090 271033 : set_count(new_count);
15091 306530 : for (int i = new_count; i < old_count; i++) {
15092 : clear_at(i);
15093 : }
15094 271033 : return new_count < old_count;
15095 : }
15096 :
15097 :
15098 870948 : void DependentCode::UpdateToFinishedCode(DependencyGroup group, Foreign* info,
15099 : WeakCell* code_cell) {
15100 1770684 : if (this->length() == 0 || this->group() > group) {
15101 : // There is no such group.
15102 : return;
15103 : }
15104 885342 : if (this->group() < group) {
15105 : // The group comes later in the list.
15106 : next_link()->UpdateToFinishedCode(group, info, code_cell);
15107 14394 : return;
15108 : }
15109 : DCHECK_EQ(group, this->group());
15110 : DisallowHeapAllocation no_gc;
15111 : int count = this->count();
15112 87267598 : for (int i = 0; i < count; i++) {
15113 86887107 : if (object_at(i) == info) {
15114 : set_object_at(i, code_cell);
15115 : break;
15116 : }
15117 : }
15118 : #ifdef DEBUG
15119 : for (int i = 0; i < count; i++) {
15120 : DCHECK(object_at(i) != info);
15121 : }
15122 : #endif
15123 : }
15124 :
15125 :
15126 34502 : void DependentCode::RemoveCompilationDependencies(
15127 : DependentCode::DependencyGroup group, Foreign* info) {
15128 70188 : if (this->length() == 0 || this->group() > group) {
15129 : // There is no such group.
15130 : return;
15131 : }
15132 35094 : if (this->group() < group) {
15133 : // The group comes later in the list.
15134 : next_link()->RemoveCompilationDependencies(group, info);
15135 592 : return;
15136 : }
15137 : DCHECK_EQ(group, this->group());
15138 : DisallowHeapAllocation no_allocation;
15139 : int old_count = count();
15140 : // Find compilation info wrapper.
15141 : int info_pos = -1;
15142 1385671 : for (int i = 0; i < old_count; i++) {
15143 1371800 : if (object_at(i) == info) {
15144 : info_pos = i;
15145 : break;
15146 : }
15147 : }
15148 34502 : if (info_pos == -1) return; // Not found.
15149 : // Use the last code to fill the gap.
15150 20631 : if (info_pos < old_count - 1) {
15151 4795 : copy(old_count - 1, info_pos);
15152 : }
15153 : clear_at(old_count - 1);
15154 20631 : set_count(old_count - 1);
15155 :
15156 : #ifdef DEBUG
15157 : for (int i = 0; i < old_count - 1; i++) {
15158 : DCHECK(object_at(i) != info);
15159 : }
15160 : #endif
15161 : }
15162 :
15163 :
15164 0 : bool DependentCode::Contains(DependencyGroup group, WeakCell* code_cell) {
15165 0 : if (this->length() == 0 || this->group() > group) {
15166 : // There is no such group.
15167 : return false;
15168 : }
15169 0 : if (this->group() < group) {
15170 : // The group comes later in the list.
15171 0 : return next_link()->Contains(group, code_cell);
15172 : }
15173 : DCHECK_EQ(group, this->group());
15174 : int count = this->count();
15175 0 : for (int i = 0; i < count; i++) {
15176 0 : if (object_at(i) == code_cell) return true;
15177 : }
15178 : return false;
15179 : }
15180 :
15181 :
15182 204592 : bool DependentCode::IsEmpty(DependencyGroup group) {
15183 381890 : if (this->length() == 0 || this->group() > group) {
15184 : // There is no such group.
15185 : return true;
15186 : }
15187 166451 : if (this->group() < group) {
15188 : // The group comes later in the list.
15189 0 : return next_link()->IsEmpty(group);
15190 : }
15191 : DCHECK_EQ(group, this->group());
15192 166451 : return count() == 0;
15193 : }
15194 :
15195 :
15196 20085440 : bool DependentCode::MarkCodeForDeoptimization(
15197 : Isolate* isolate,
15198 : DependentCode::DependencyGroup group) {
15199 20129087 : if (this->length() == 0 || this->group() > group) {
15200 : // There is no such group.
15201 : return false;
15202 : }
15203 41104 : if (this->group() < group) {
15204 : // The group comes later in the list.
15205 1931 : return next_link()->MarkCodeForDeoptimization(isolate, group);
15206 : }
15207 : DCHECK_EQ(group, this->group());
15208 : DisallowHeapAllocation no_allocation_scope;
15209 : // Mark all the code that needs to be deoptimized.
15210 : bool marked = false;
15211 : bool invalidate_embedded_objects = group == kWeakCodeGroup;
15212 : int count = this->count();
15213 124661 : for (int i = 0; i < count; i++) {
15214 : Object* obj = object_at(i);
15215 85488 : if (obj->IsWeakCell()) {
15216 : WeakCell* cell = WeakCell::cast(obj);
15217 85260 : if (cell->cleared()) continue;
15218 : Code* code = Code::cast(cell->value());
15219 23344 : if (!code->marked_for_deoptimization()) {
15220 14377 : SetMarkedForDeoptimization(code, group);
15221 14377 : if (invalidate_embedded_objects) {
15222 5302 : code->InvalidateEmbeddedObjects();
15223 : }
15224 : marked = true;
15225 : }
15226 : } else {
15227 : DCHECK(obj->IsForeign());
15228 : CompilationDependencies* info =
15229 : reinterpret_cast<CompilationDependencies*>(
15230 : Foreign::cast(obj)->foreign_address());
15231 : info->Abort();
15232 : }
15233 : }
15234 85488 : for (int i = 0; i < count; i++) {
15235 : clear_at(i);
15236 : }
15237 39173 : set_count(0);
15238 39173 : return marked;
15239 : }
15240 :
15241 :
15242 20053205 : void DependentCode::DeoptimizeDependentCodeGroup(
15243 : Isolate* isolate,
15244 : DependentCode::DependencyGroup group) {
15245 : DisallowHeapAllocation no_allocation_scope;
15246 20053205 : bool marked = MarkCodeForDeoptimization(isolate, group);
15247 20053205 : if (marked) {
15248 : DCHECK(AllowCodeDependencyChange::IsAllowed());
15249 5907 : Deoptimizer::DeoptimizeMarkedCode(isolate);
15250 : }
15251 20053205 : }
15252 :
15253 :
15254 14392 : void DependentCode::SetMarkedForDeoptimization(Code* code,
15255 : DependencyGroup group) {
15256 : code->set_marked_for_deoptimization(true);
15257 14392 : if (FLAG_trace_deopt &&
15258 0 : (code->deoptimization_data() != code->GetHeap()->empty_fixed_array())) {
15259 : DeoptimizationInputData* deopt_data =
15260 : DeoptimizationInputData::cast(code->deoptimization_data());
15261 0 : CodeTracer::Scope scope(code->GetHeap()->isolate()->GetCodeTracer());
15262 : PrintF(scope.file(), "[marking dependent code 0x%08" V8PRIxPTR
15263 : " (opt #%d) for deoptimization, reason: %s]\n",
15264 : reinterpret_cast<intptr_t>(code),
15265 0 : deopt_data->OptimizationId()->value(), DependencyGroupName(group));
15266 : }
15267 14392 : }
15268 :
15269 :
15270 0 : const char* DependentCode::DependencyGroupName(DependencyGroup group) {
15271 0 : switch (group) {
15272 : case kWeakCodeGroup:
15273 : return "weak-code";
15274 : case kTransitionGroup:
15275 0 : return "transition";
15276 : case kPrototypeCheckGroup:
15277 0 : return "prototype-check";
15278 : case kPropertyCellChangedGroup:
15279 0 : return "property-cell-changed";
15280 : case kFieldOwnerGroup:
15281 0 : return "field-owner";
15282 : case kInitialMapChangedGroup:
15283 0 : return "initial-map-changed";
15284 : case kAllocationSiteTenuringChangedGroup:
15285 0 : return "allocation-site-tenuring-changed";
15286 : case kAllocationSiteTransitionChangedGroup:
15287 0 : return "allocation-site-transition-changed";
15288 : }
15289 0 : UNREACHABLE();
15290 : return "?";
15291 : }
15292 :
15293 :
15294 4156555 : Handle<Map> Map::TransitionToPrototype(Handle<Map> map,
15295 : Handle<Object> prototype,
15296 : PrototypeOptimizationMode mode) {
15297 4156555 : Handle<Map> new_map = TransitionArray::GetPrototypeTransition(map, prototype);
15298 4156555 : if (new_map.is_null()) {
15299 139748 : new_map = Copy(map, "TransitionToPrototype");
15300 139748 : TransitionArray::PutPrototypeTransition(map, prototype, new_map);
15301 139748 : Map::SetPrototype(new_map, prototype, mode);
15302 : }
15303 4156555 : return new_map;
15304 : }
15305 :
15306 :
15307 4184280 : Maybe<bool> JSReceiver::SetPrototype(Handle<JSReceiver> object,
15308 : Handle<Object> value, bool from_javascript,
15309 : ShouldThrow should_throw) {
15310 4184280 : if (object->IsJSProxy()) {
15311 : return JSProxy::SetPrototype(Handle<JSProxy>::cast(object), value,
15312 532 : from_javascript, should_throw);
15313 : }
15314 : return JSObject::SetPrototype(Handle<JSObject>::cast(object), value,
15315 4183748 : from_javascript, should_throw);
15316 : }
15317 :
15318 :
15319 : // ES6: 9.5.2 [[SetPrototypeOf]] (V)
15320 : // static
15321 532 : Maybe<bool> JSProxy::SetPrototype(Handle<JSProxy> proxy, Handle<Object> value,
15322 : bool from_javascript,
15323 : ShouldThrow should_throw) {
15324 : Isolate* isolate = proxy->GetIsolate();
15325 532 : STACK_CHECK(isolate, Nothing<bool>());
15326 : Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string();
15327 : // 1. Assert: Either Type(V) is Object or Type(V) is Null.
15328 : DCHECK(value->IsJSReceiver() || value->IsNull(isolate));
15329 : // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
15330 : Handle<Object> handler(proxy->handler(), isolate);
15331 : // 3. If handler is null, throw a TypeError exception.
15332 : // 4. Assert: Type(handler) is Object.
15333 532 : if (proxy->IsRevoked()) {
15334 : isolate->Throw(*isolate->factory()->NewTypeError(
15335 28 : MessageTemplate::kProxyRevoked, trap_name));
15336 : return Nothing<bool>();
15337 : }
15338 : // 5. Let target be the value of the [[ProxyTarget]] internal slot.
15339 : Handle<JSReceiver> target(proxy->target(), isolate);
15340 : // 6. Let trap be ? GetMethod(handler, "getPrototypeOf").
15341 : Handle<Object> trap;
15342 1036 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15343 : isolate, trap,
15344 : Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
15345 : Nothing<bool>());
15346 : // 7. If trap is undefined, then return target.[[SetPrototypeOf]]().
15347 518 : if (trap->IsUndefined(isolate)) {
15348 : return JSReceiver::SetPrototype(target, value, from_javascript,
15349 364 : should_throw);
15350 : }
15351 : // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, V»)).
15352 154 : Handle<Object> argv[] = {target, value};
15353 : Handle<Object> trap_result;
15354 308 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15355 : isolate, trap_result,
15356 : Execution::Call(isolate, trap, handler, arraysize(argv), argv),
15357 : Nothing<bool>());
15358 140 : bool bool_trap_result = trap_result->BooleanValue();
15359 : // 9. If booleanTrapResult is false, return false.
15360 140 : if (!bool_trap_result) {
15361 140 : RETURN_FAILURE(
15362 : isolate, should_throw,
15363 : NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15364 : }
15365 : // 10. Let extensibleTarget be ? IsExtensible(target).
15366 84 : Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
15367 84 : if (is_extensible.IsNothing()) return Nothing<bool>();
15368 : // 11. If extensibleTarget is true, return true.
15369 84 : if (is_extensible.FromJust()) {
15370 42 : if (bool_trap_result) return Just(true);
15371 0 : RETURN_FAILURE(
15372 : isolate, should_throw,
15373 : NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15374 : }
15375 : // 12. Let targetProto be ? target.[[GetPrototypeOf]]().
15376 : Handle<Object> target_proto;
15377 84 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_proto,
15378 : JSReceiver::GetPrototype(isolate, target),
15379 : Nothing<bool>());
15380 : // 13. If SameValue(V, targetProto) is false, throw a TypeError exception.
15381 56 : if (bool_trap_result && !value->SameValue(*target_proto)) {
15382 : isolate->Throw(*isolate->factory()->NewTypeError(
15383 28 : MessageTemplate::kProxySetPrototypeOfNonExtensible));
15384 : return Nothing<bool>();
15385 : }
15386 : // 14. Return true.
15387 : return Just(true);
15388 : }
15389 :
15390 :
15391 4196691 : Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object,
15392 : Handle<Object> value, bool from_javascript,
15393 : ShouldThrow should_throw) {
15394 42 : Isolate* isolate = object->GetIsolate();
15395 :
15396 : #ifdef DEBUG
15397 : int size = object->Size();
15398 : #endif
15399 :
15400 4196691 : if (from_javascript) {
15401 116148 : if (object->IsAccessCheckNeeded() &&
15402 42 : !isolate->MayAccess(handle(isolate->context()), object)) {
15403 0 : isolate->ReportFailedAccessCheck(object);
15404 0 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
15405 0 : RETURN_FAILURE(isolate, should_throw,
15406 : NewTypeError(MessageTemplate::kNoAccess));
15407 : }
15408 : } else {
15409 : DCHECK(!object->IsAccessCheckNeeded());
15410 : }
15411 :
15412 : Heap* heap = isolate->heap();
15413 : // Silently ignore the change if value is not a JSObject or null.
15414 : // SpiderMonkey behaves this way.
15415 8256218 : if (!value->IsJSReceiver() && !value->IsNull(isolate)) return Just(true);
15416 :
15417 : bool all_extensible = object->map()->is_extensible();
15418 : Handle<JSObject> real_receiver = object;
15419 4196673 : if (from_javascript) {
15420 : // Find the first object in the chain whose prototype object is not
15421 : // hidden.
15422 : PrototypeIterator iter(isolate, real_receiver, kStartAtPrototype,
15423 116106 : PrototypeIterator::END_AT_NON_HIDDEN);
15424 236857 : while (!iter.IsAtEnd()) {
15425 : // Casting to JSObject is fine because hidden prototypes are never
15426 : // JSProxies.
15427 : real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter);
15428 4645 : iter.Advance();
15429 9290 : all_extensible = all_extensible && real_receiver->map()->is_extensible();
15430 : }
15431 : }
15432 : Handle<Map> map(real_receiver->map());
15433 :
15434 : // Nothing to do if prototype is already set.
15435 4196673 : if (map->prototype() == *value) return Just(true);
15436 :
15437 : bool immutable_proto = map->is_immutable_proto();
15438 4155854 : if (immutable_proto) {
15439 251 : RETURN_FAILURE(
15440 : isolate, should_throw,
15441 : NewTypeError(MessageTemplate::kImmutablePrototypeSet, object));
15442 : }
15443 :
15444 : // From 8.6.2 Object Internal Methods
15445 : // ...
15446 : // In addition, if [[Extensible]] is false the value of the [[Class]] and
15447 : // [[Prototype]] internal properties of the object may not be modified.
15448 : // ...
15449 : // Implementation specific extensions that modify [[Class]], [[Prototype]]
15450 : // or [[Extensible]] must not violate the invariants defined in the preceding
15451 : // paragraph.
15452 4155761 : if (!all_extensible) {
15453 822 : RETURN_FAILURE(isolate, should_throw,
15454 : NewTypeError(MessageTemplate::kNonExtensibleProto, object));
15455 : }
15456 :
15457 : // Before we can set the prototype we need to be sure prototype cycles are
15458 : // prevented. It is sufficient to validate that the receiver is not in the
15459 : // new prototype chain.
15460 4155365 : if (value->IsJSReceiver()) {
15461 359899 : for (PrototypeIterator iter(isolate, JSReceiver::cast(*value),
15462 : kStartAtReceiver);
15463 263900 : !iter.IsAtEnd(); iter.Advance()) {
15464 528044 : if (iter.GetCurrent<JSReceiver>() == *object) {
15465 : // Cycle detected.
15466 310 : RETURN_FAILURE(isolate, should_throw,
15467 : NewTypeError(MessageTemplate::kCyclicProto));
15468 : }
15469 : }
15470 : }
15471 :
15472 : // Set the new prototype of the object.
15473 :
15474 : isolate->UpdateArrayProtectorOnSetPrototype(real_receiver);
15475 :
15476 : PrototypeOptimizationMode mode =
15477 4155243 : from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE;
15478 4155243 : Handle<Map> new_map = Map::TransitionToPrototype(map, value, mode);
15479 : DCHECK(new_map->prototype() == *value);
15480 4155243 : JSObject::MigrateToMap(real_receiver, new_map);
15481 :
15482 : heap->ClearInstanceofCache();
15483 : DCHECK(size == object->Size());
15484 : return Just(true);
15485 : }
15486 :
15487 : // static
15488 28 : void JSObject::SetImmutableProto(Handle<JSObject> object) {
15489 : DCHECK(!object->IsAccessCheckNeeded()); // Never called from JS
15490 : Handle<Map> map(object->map());
15491 :
15492 : // Nothing to do if prototype is already set.
15493 49 : if (map->is_immutable_proto()) return;
15494 :
15495 7 : Handle<Map> new_map = Map::TransitionToImmutableProto(map);
15496 7 : object->set_map(*new_map);
15497 : }
15498 :
15499 1163917 : void JSObject::EnsureCanContainElements(Handle<JSObject> object,
15500 1163917 : Arguments* args,
15501 : uint32_t first_arg,
15502 : uint32_t arg_count,
15503 : EnsureElementsMode mode) {
15504 : // Elements in |Arguments| are ordered backwards (because they're on the
15505 : // stack), but the method that's called here iterates over them in forward
15506 : // direction.
15507 : return EnsureCanContainElements(
15508 1163917 : object, args->arguments() - first_arg - (arg_count - 1), arg_count, mode);
15509 : }
15510 :
15511 :
15512 511513831 : ElementsAccessor* JSObject::GetElementsAccessor() {
15513 511513831 : return ElementsAccessor::ForKind(GetElementsKind());
15514 : }
15515 :
15516 :
15517 21514742 : void JSObject::ValidateElements(Handle<JSObject> object) {
15518 : #ifdef ENABLE_SLOW_DCHECKS
15519 : if (FLAG_enable_slow_asserts) {
15520 : ElementsAccessor* accessor = object->GetElementsAccessor();
15521 : accessor->Validate(object);
15522 : }
15523 : #endif
15524 21514742 : }
15525 :
15526 :
15527 1965412 : static bool ShouldConvertToSlowElements(JSObject* object, uint32_t capacity,
15528 : uint32_t index,
15529 : uint32_t* new_capacity) {
15530 : STATIC_ASSERT(JSObject::kMaxUncheckedOldFastElementsLength <=
15531 : JSObject::kMaxUncheckedFastElementsLength);
15532 1965412 : if (index < capacity) {
15533 963452 : *new_capacity = capacity;
15534 963452 : return false;
15535 : }
15536 1001960 : if (index - capacity >= JSObject::kMaxGap) return true;
15537 1226180 : *new_capacity = JSObject::NewElementsCapacity(index + 1);
15538 : DCHECK_LT(index, *new_capacity);
15539 1226180 : if (*new_capacity <= JSObject::kMaxUncheckedOldFastElementsLength ||
15540 69292 : (*new_capacity <= JSObject::kMaxUncheckedFastElementsLength &&
15541 : object->GetHeap()->InNewSpace(object))) {
15542 : return false;
15543 : }
15544 : // If the fast-case backing storage takes up roughly three times as
15545 : // much space (in machine words) as a dictionary backing storage
15546 : // would, the object should have slow elements.
15547 1776 : int used_elements = object->GetFastElementsUsage();
15548 : int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
15549 1776 : SeededNumberDictionary::kEntrySize;
15550 1776 : return 3 * static_cast<uint32_t>(dictionary_size) <= *new_capacity;
15551 : }
15552 :
15553 :
15554 186957 : bool JSObject::WouldConvertToSlowElements(uint32_t index) {
15555 186957 : if (HasFastElements()) {
15556 : Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements()));
15557 36241 : uint32_t capacity = static_cast<uint32_t>(backing_store->length());
15558 : uint32_t new_capacity;
15559 36241 : return ShouldConvertToSlowElements(this, capacity, index, &new_capacity);
15560 : }
15561 : return false;
15562 : }
15563 :
15564 :
15565 2961 : static ElementsKind BestFittingFastElementsKind(JSObject* object) {
15566 2961 : if (object->HasSloppyArgumentsElements()) {
15567 : return FAST_SLOPPY_ARGUMENTS_ELEMENTS;
15568 : }
15569 2931 : if (object->HasStringWrapperElements()) {
15570 : return FAST_STRING_WRAPPER_ELEMENTS;
15571 : }
15572 : DCHECK(object->HasDictionaryElements());
15573 : SeededNumberDictionary* dictionary = object->element_dictionary();
15574 : ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS;
15575 3957332 : for (int i = 0; i < dictionary->Capacity(); i++) {
15576 : Object* key = dictionary->KeyAt(i);
15577 1975837 : if (key->IsNumber()) {
15578 655163 : Object* value = dictionary->ValueAt(i);
15579 655163 : if (!value->IsNumber()) return FAST_HOLEY_ELEMENTS;
15580 655076 : if (!value->IsSmi()) {
15581 73635 : if (!FLAG_unbox_double_arrays) return FAST_HOLEY_ELEMENTS;
15582 : kind = FAST_HOLEY_DOUBLE_ELEMENTS;
15583 : }
15584 : }
15585 : }
15586 : return kind;
15587 : }
15588 :
15589 :
15590 1736806 : static bool ShouldConvertToFastElements(JSObject* object,
15591 : SeededNumberDictionary* dictionary,
15592 : uint32_t index,
15593 : uint32_t* new_capacity) {
15594 : // If properties with non-standard attributes or accessors were added, we
15595 : // cannot go back to fast elements.
15596 1736806 : if (dictionary->requires_slow_elements()) return false;
15597 :
15598 : // Adding a property with this index will require slow elements.
15599 1697738 : if (index >= static_cast<uint32_t>(Smi::kMaxValue)) return false;
15600 :
15601 1697224 : if (object->IsJSArray()) {
15602 : Object* length = JSArray::cast(object)->length();
15603 903797 : if (!length->IsSmi()) return false;
15604 902537 : *new_capacity = static_cast<uint32_t>(Smi::cast(length)->value());
15605 : } else {
15606 793427 : *new_capacity = dictionary->max_number_key() + 1;
15607 : }
15608 3391928 : *new_capacity = Max(index + 1, *new_capacity);
15609 :
15610 1695964 : uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
15611 1695964 : SeededNumberDictionary::kEntrySize;
15612 :
15613 : // Turn fast if the dictionary only saves 50% space.
15614 1695964 : return 2 * dictionary_size >= *new_capacity;
15615 : }
15616 :
15617 :
15618 : // static
15619 32929 : MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> object,
15620 : uint32_t index,
15621 : Handle<Object> value,
15622 : PropertyAttributes attributes) {
15623 32929 : MAYBE_RETURN_NULL(
15624 : AddDataElement(object, index, value, attributes, THROW_ON_ERROR));
15625 : return value;
15626 : }
15627 :
15628 :
15629 : // static
15630 3711839 : Maybe<bool> JSObject::AddDataElement(Handle<JSObject> object, uint32_t index,
15631 : Handle<Object> value,
15632 : PropertyAttributes attributes,
15633 : ShouldThrow should_throw) {
15634 : DCHECK(object->map()->is_extensible());
15635 :
15636 : Isolate* isolate = object->GetIsolate();
15637 :
15638 3711839 : uint32_t old_length = 0;
15639 3711839 : uint32_t new_capacity = 0;
15640 :
15641 3711839 : if (object->IsJSArray()) {
15642 1551585 : CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length));
15643 : }
15644 :
15645 : ElementsKind kind = object->GetElementsKind();
15646 : FixedArrayBase* elements = object->elements();
15647 : ElementsKind dictionary_kind = DICTIONARY_ELEMENTS;
15648 3711839 : if (IsSloppyArgumentsElementsKind(kind)) {
15649 : elements = FixedArrayBase::cast(FixedArray::cast(elements)->get(1));
15650 : dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
15651 3512763 : } else if (IsStringWrapperElementsKind(kind)) {
15652 : dictionary_kind = SLOW_STRING_WRAPPER_ELEMENTS;
15653 : }
15654 :
15655 3711839 : if (attributes != NONE) {
15656 : kind = dictionary_kind;
15657 3664462 : } else if (elements->IsSeededNumberDictionary()) {
15658 : kind = ShouldConvertToFastElements(*object,
15659 : SeededNumberDictionary::cast(elements),
15660 1736806 : index, &new_capacity)
15661 : ? BestFittingFastElementsKind(*object)
15662 1739767 : : dictionary_kind; // Overwrite in case of arguments.
15663 1927656 : } else if (ShouldConvertToSlowElements(
15664 : *object, static_cast<uint32_t>(elements->length()), index,
15665 1927656 : &new_capacity)) {
15666 : kind = dictionary_kind;
15667 : }
15668 :
15669 3711839 : ElementsKind to = value->OptimalElementsKind();
15670 4272655 : if (IsHoleyElementsKind(kind) || !object->IsJSArray() || index > old_length) {
15671 : to = GetHoleyElementsKind(to);
15672 : kind = GetHoleyElementsKind(kind);
15673 : }
15674 : to = GetMoreGeneralElementsKind(kind, to);
15675 : ElementsAccessor* accessor = ElementsAccessor::ForKind(to);
15676 3711839 : accessor->Add(object, index, value, attributes, new_capacity);
15677 :
15678 3711839 : if (object->IsJSArray() && index >= old_length) {
15679 : Handle<Object> new_length =
15680 1322776 : isolate->factory()->NewNumberFromUint(index + 1);
15681 1322776 : JSArray::cast(*object)->set_length(*new_length);
15682 : }
15683 :
15684 3711839 : return Just(true);
15685 : }
15686 :
15687 :
15688 1562733 : bool JSArray::SetLengthWouldNormalize(uint32_t new_length) {
15689 1562733 : if (!HasFastElements()) return false;
15690 1537844 : uint32_t capacity = static_cast<uint32_t>(elements()->length());
15691 : uint32_t new_capacity;
15692 1539359 : return JSArray::SetLengthWouldNormalize(GetHeap(), new_length) &&
15693 : ShouldConvertToSlowElements(this, capacity, new_length - 1,
15694 1539359 : &new_capacity);
15695 : }
15696 :
15697 :
15698 : const double AllocationSite::kPretenureRatio = 0.85;
15699 :
15700 :
15701 0 : void AllocationSite::ResetPretenureDecision() {
15702 : set_pretenure_decision(kUndecided);
15703 : set_memento_found_count(0);
15704 : set_memento_create_count(0);
15705 0 : }
15706 :
15707 :
15708 44968 : PretenureFlag AllocationSite::GetPretenureMode() {
15709 : PretenureDecision mode = pretenure_decision();
15710 : // Zombie objects "decide" to be untenured.
15711 44968 : return mode == kTenure ? TENURED : NOT_TENURED;
15712 : }
15713 :
15714 :
15715 0 : bool AllocationSite::IsNestedSite() {
15716 : DCHECK(FLAG_trace_track_allocation_sites);
15717 0 : Object* current = GetHeap()->allocation_sites_list();
15718 0 : while (current->IsAllocationSite()) {
15719 : AllocationSite* current_site = AllocationSite::cast(current);
15720 0 : if (current_site->nested_site() == this) {
15721 : return true;
15722 : }
15723 : current = current_site->weak_next();
15724 : }
15725 : return false;
15726 : }
15727 :
15728 : template <AllocationSiteUpdateMode update_or_check>
15729 635739 : bool AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
15730 : ElementsKind to_kind) {
15731 : Isolate* isolate = site->GetIsolate();
15732 : bool result = false;
15733 :
15734 1244154 : if (site->SitePointsToLiteral() && site->transition_info()->IsJSArray()) {
15735 : Handle<JSArray> transition_info =
15736 : handle(JSArray::cast(site->transition_info()));
15737 : ElementsKind kind = transition_info->GetElementsKind();
15738 : // if kind is holey ensure that to_kind is as well.
15739 608415 : if (IsHoleyElementsKind(kind)) {
15740 : to_kind = GetHoleyElementsKind(to_kind);
15741 : }
15742 608415 : if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
15743 : // If the array is huge, it's not likely to be defined in a local
15744 : // function, so we shouldn't make new instances of it very often.
15745 61665 : uint32_t length = 0;
15746 61665 : CHECK(transition_info->length()->ToArrayLength(&length));
15747 61665 : if (length <= kMaximumArrayBytesToPretransition) {
15748 : if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) {
15749 0 : return true;
15750 : }
15751 61665 : if (FLAG_trace_track_allocation_sites) {
15752 0 : bool is_nested = site->IsNestedSite();
15753 0 : PrintF(
15754 : "AllocationSite: JSArray %p boilerplate %s updated %s->%s\n",
15755 : reinterpret_cast<void*>(*site),
15756 : is_nested ? "(nested)" : "",
15757 : ElementsKindToString(kind),
15758 0 : ElementsKindToString(to_kind));
15759 : }
15760 61665 : JSObject::TransitionElementsKind(transition_info, to_kind);
15761 61665 : site->dependent_code()->DeoptimizeDependentCodeGroup(
15762 : isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
15763 : result = true;
15764 : }
15765 : }
15766 : } else {
15767 : ElementsKind kind = site->GetElementsKind();
15768 : // if kind is holey ensure that to_kind is as well.
15769 27324 : if (IsHoleyElementsKind(kind)) {
15770 : to_kind = GetHoleyElementsKind(to_kind);
15771 : }
15772 27324 : if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
15773 : if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) return true;
15774 23619 : if (FLAG_trace_track_allocation_sites) {
15775 0 : PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
15776 : reinterpret_cast<void*>(*site),
15777 : ElementsKindToString(kind),
15778 0 : ElementsKindToString(to_kind));
15779 : }
15780 23619 : site->SetElementsKind(to_kind);
15781 23619 : site->dependent_code()->DeoptimizeDependentCodeGroup(
15782 : isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
15783 : result = true;
15784 : }
15785 : }
15786 : return result;
15787 : }
15788 :
15789 3310 : AllocationSiteMode AllocationSite::GetMode(ElementsKind from, ElementsKind to) {
15790 5926 : if (IsFastSmiElementsKind(from) &&
15791 2616 : IsMoreGeneralElementsKindTransition(from, to)) {
15792 : return TRACK_ALLOCATION_SITE;
15793 : }
15794 :
15795 694 : return DONT_TRACK_ALLOCATION_SITE;
15796 : }
15797 :
15798 0 : const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) {
15799 0 : switch (decision) {
15800 : case kUndecided: return "undecided";
15801 0 : case kDontTenure: return "don't tenure";
15802 0 : case kMaybeTenure: return "maybe tenure";
15803 0 : case kTenure: return "tenure";
15804 0 : case kZombie: return "zombie";
15805 0 : default: UNREACHABLE();
15806 : }
15807 : return NULL;
15808 : }
15809 :
15810 : template <AllocationSiteUpdateMode update_or_check>
15811 1727178 : bool JSObject::UpdateAllocationSite(Handle<JSObject> object,
15812 : ElementsKind to_kind) {
15813 1727178 : if (!object->IsJSArray()) return false;
15814 :
15815 : Heap* heap = object->GetHeap();
15816 1309332 : if (!heap->InNewSpace(*object)) return false;
15817 :
15818 : Handle<AllocationSite> site;
15819 : {
15820 : DisallowHeapAllocation no_allocation;
15821 :
15822 : AllocationMemento* memento =
15823 1240030 : heap->FindAllocationMemento<Heap::kForRuntime>(*object);
15824 1240030 : if (memento == NULL) return false;
15825 :
15826 : // Walk through to the Allocation Site
15827 635739 : site = handle(memento->GetAllocationSite());
15828 : }
15829 : return AllocationSite::DigestTransitionFeedback<update_or_check>(site,
15830 635739 : to_kind);
15831 : }
15832 :
15833 : template bool
15834 : JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kCheckOnly>(
15835 : Handle<JSObject> object, ElementsKind to_kind);
15836 :
15837 : template bool JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kUpdate>(
15838 : Handle<JSObject> object, ElementsKind to_kind);
15839 :
15840 445332 : void JSObject::TransitionElementsKind(Handle<JSObject> object,
15841 : ElementsKind to_kind) {
15842 : ElementsKind from_kind = object->GetElementsKind();
15843 :
15844 445332 : if (IsFastHoleyElementsKind(from_kind)) {
15845 : to_kind = GetHoleyElementsKind(to_kind);
15846 : }
15847 :
15848 890664 : if (from_kind == to_kind) return;
15849 :
15850 : // This method should never be called for any other case.
15851 : DCHECK(IsFastElementsKind(from_kind));
15852 : DCHECK(IsFastElementsKind(to_kind));
15853 : DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind);
15854 :
15855 445243 : UpdateAllocationSite(object, to_kind);
15856 814759 : if (object->elements() == object->GetHeap()->empty_fixed_array() ||
15857 : IsFastDoubleElementsKind(from_kind) ==
15858 : IsFastDoubleElementsKind(to_kind)) {
15859 : // No change is needed to the elements() buffer, the transition
15860 : // only requires a map change.
15861 437344 : Handle<Map> new_map = GetElementsTransitionMap(object, to_kind);
15862 437344 : MigrateToMap(object, new_map);
15863 : if (FLAG_trace_elements_transitions) {
15864 : Handle<FixedArrayBase> elms(object->elements());
15865 : PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms);
15866 : }
15867 : } else {
15868 : DCHECK((IsFastSmiElementsKind(from_kind) &&
15869 : IsFastDoubleElementsKind(to_kind)) ||
15870 : (IsFastDoubleElementsKind(from_kind) &&
15871 : IsFastObjectElementsKind(to_kind)));
15872 7899 : uint32_t c = static_cast<uint32_t>(object->elements()->length());
15873 7899 : ElementsAccessor::ForKind(to_kind)->GrowCapacityAndConvert(object, c);
15874 : }
15875 : }
15876 :
15877 :
15878 : // static
15879 0 : bool Map::IsValidElementsTransition(ElementsKind from_kind,
15880 : ElementsKind to_kind) {
15881 : // Transitions can't go backwards.
15882 0 : if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
15883 : return false;
15884 : }
15885 :
15886 : // Transitions from HOLEY -> PACKED are not allowed.
15887 0 : return !IsFastHoleyElementsKind(from_kind) ||
15888 0 : IsFastHoleyElementsKind(to_kind);
15889 : }
15890 :
15891 :
15892 4365334 : bool JSArray::HasReadOnlyLength(Handle<JSArray> array) {
15893 : Map* map = array->map();
15894 : // Fast path: "length" is the first fast property of arrays. Since it's not
15895 : // configurable, it's guaranteed to be the first in the descriptor array.
15896 4365334 : if (!map->is_dictionary_map()) {
15897 : DCHECK(map->instance_descriptors()->GetKey(0) ==
15898 : array->GetHeap()->length_string());
15899 8693438 : return map->instance_descriptors()->GetDetails(0).IsReadOnly();
15900 : }
15901 :
15902 : Isolate* isolate = array->GetIsolate();
15903 : LookupIterator it(array, isolate->factory()->length_string(), array,
15904 18615 : LookupIterator::OWN_SKIP_INTERCEPTOR);
15905 18615 : CHECK_EQ(LookupIterator::ACCESSOR, it.state());
15906 18615 : return it.IsReadOnly();
15907 : }
15908 :
15909 :
15910 1519342 : bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array,
15911 : uint32_t index) {
15912 1519342 : uint32_t length = 0;
15913 1519342 : CHECK(array->length()->ToArrayLength(&length));
15914 1519342 : if (length <= index) return HasReadOnlyLength(array);
15915 : return false;
15916 : }
15917 :
15918 :
15919 : template <typename BackingStore>
15920 439690 : static int FastHoleyElementsUsage(JSObject* object, BackingStore* store) {
15921 : Isolate* isolate = store->GetIsolate();
15922 : int limit = object->IsJSArray()
15923 : ? Smi::cast(JSArray::cast(object)->length())->value()
15924 439690 : : store->length();
15925 : int used = 0;
15926 523603629 : for (int i = 0; i < limit; ++i) {
15927 523163939 : if (!store->is_the_hole(isolate, i)) ++used;
15928 : }
15929 439690 : return used;
15930 : }
15931 :
15932 :
15933 466738 : int JSObject::GetFastElementsUsage() {
15934 : FixedArrayBase* store = elements();
15935 466738 : switch (GetElementsKind()) {
15936 : case FAST_SMI_ELEMENTS:
15937 : case FAST_DOUBLE_ELEMENTS:
15938 : case FAST_ELEMENTS:
15939 : return IsJSArray() ? Smi::cast(JSArray::cast(this)->length())->value()
15940 54006 : : store->length();
15941 : case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
15942 : store = SloppyArgumentsElements::cast(store)->arguments();
15943 : // Fall through.
15944 : case FAST_HOLEY_SMI_ELEMENTS:
15945 : case FAST_HOLEY_ELEMENTS:
15946 : case FAST_STRING_WRAPPER_ELEMENTS:
15947 439542 : return FastHoleyElementsUsage(this, FixedArray::cast(store));
15948 : case FAST_HOLEY_DOUBLE_ELEMENTS:
15949 193 : if (elements()->length() == 0) return 0;
15950 148 : return FastHoleyElementsUsage(this, FixedDoubleArray::cast(store));
15951 :
15952 : case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
15953 : case SLOW_STRING_WRAPPER_ELEMENTS:
15954 : case DICTIONARY_ELEMENTS:
15955 : case NO_ELEMENTS:
15956 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
15957 : case TYPE##_ELEMENTS: \
15958 :
15959 : TYPED_ARRAYS(TYPED_ARRAY_CASE)
15960 : #undef TYPED_ARRAY_CASE
15961 0 : UNREACHABLE();
15962 : }
15963 : return 0;
15964 : }
15965 :
15966 :
15967 : // Certain compilers request function template instantiation when they
15968 : // see the definition of the other template functions in the
15969 : // class. This requires us to have the template functions put
15970 : // together, so even though this function belongs in objects-debug.cc,
15971 : // we keep it here instead to satisfy certain compilers.
15972 : #ifdef OBJECT_PRINT
15973 : template <typename Derived, typename Shape, typename Key>
15974 : void Dictionary<Derived, Shape, Key>::Print(std::ostream& os) { // NOLINT
15975 : Isolate* isolate = this->GetIsolate();
15976 : int capacity = this->Capacity();
15977 : for (int i = 0; i < capacity; i++) {
15978 : Object* k = this->KeyAt(i);
15979 : if (this->IsKey(isolate, k)) {
15980 : os << "\n ";
15981 : if (k->IsString()) {
15982 : String::cast(k)->StringPrint(os);
15983 : } else {
15984 : os << Brief(k);
15985 : }
15986 : os << ": " << Brief(this->ValueAt(i)) << " ";
15987 : this->DetailsAt(i).PrintAsSlowTo(os);
15988 : }
15989 : }
15990 : }
15991 : template <typename Derived, typename Shape, typename Key>
15992 : void Dictionary<Derived, Shape, Key>::Print() {
15993 : OFStream os(stdout);
15994 : Print(os);
15995 : }
15996 : #endif
15997 :
15998 :
15999 5152 : MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it,
16000 : bool* done) {
16001 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
16002 5152 : return GetPropertyWithInterceptorInternal(it, it->GetInterceptor(), done);
16003 : }
16004 :
16005 66902001 : Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object,
16006 : Handle<Name> name) {
16007 : LookupIterator it = LookupIterator::PropertyOrElement(
16008 66902001 : name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
16009 66902001 : return HasProperty(&it);
16010 : }
16011 :
16012 :
16013 20 : Maybe<bool> JSObject::HasRealElementProperty(Handle<JSObject> object,
16014 : uint32_t index) {
16015 : Isolate* isolate = object->GetIsolate();
16016 : LookupIterator it(isolate, object, index, object,
16017 : LookupIterator::OWN_SKIP_INTERCEPTOR);
16018 20 : return HasProperty(&it);
16019 : }
16020 :
16021 :
16022 6 : Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
16023 : Handle<Name> name) {
16024 : LookupIterator it = LookupIterator::PropertyOrElement(
16025 6 : name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
16026 6 : Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
16027 6 : return maybe_result.IsJust() ? Just(it.state() == LookupIterator::ACCESSOR)
16028 12 : : Nothing<bool>();
16029 : }
16030 :
16031 3448 : int FixedArrayBase::GetMaxLengthForNewSpaceAllocation(ElementsKind kind) {
16032 : return ((kMaxRegularHeapObjectSize - FixedArrayBase::kHeaderSize) >>
16033 3448 : ElementsKindToShiftSize(kind));
16034 : }
16035 :
16036 49011 : bool JSObject::WasConstructedFromApiFunction() {
16037 : auto instance_type = map()->instance_type();
16038 49011 : bool is_api_object = instance_type == JS_API_OBJECT_TYPE ||
16039 49011 : instance_type == JS_SPECIAL_API_OBJECT_TYPE;
16040 : #ifdef ENABLE_SLOW_DCHECKS
16041 : if (FLAG_enable_slow_asserts) {
16042 : Object* maybe_constructor = map()->GetConstructor();
16043 : if (maybe_constructor->IsJSFunction()) {
16044 : JSFunction* constructor = JSFunction::cast(maybe_constructor);
16045 : if (constructor->shared()->IsApiFunction()) {
16046 : DCHECK(is_api_object);
16047 : } else {
16048 : DCHECK(!is_api_object);
16049 : }
16050 : } else if (maybe_constructor->IsFunctionTemplateInfo()) {
16051 : DCHECK(is_api_object);
16052 : } else {
16053 : return false;
16054 : }
16055 : }
16056 : #endif
16057 49011 : return is_api_object;
16058 : }
16059 :
16060 210 : const char* Symbol::PrivateSymbolToName() const {
16061 7140 : Heap* heap = GetIsolate()->heap();
16062 : #define SYMBOL_CHECK_AND_PRINT(name) \
16063 : if (this == heap->name()) return #name;
16064 7140 : PRIVATE_SYMBOL_LIST(SYMBOL_CHECK_AND_PRINT)
16065 : #undef SYMBOL_CHECK_AND_PRINT
16066 210 : return "UNKNOWN";
16067 : }
16068 :
16069 :
16070 227 : void Symbol::SymbolShortPrint(std::ostream& os) {
16071 227 : os << "<Symbol:";
16072 227 : if (!name()->IsUndefined(GetIsolate())) {
16073 17 : os << " ";
16074 : HeapStringAllocator allocator;
16075 : StringStream accumulator(&allocator);
16076 17 : String::cast(name())->StringShortPrint(&accumulator, false);
16077 51 : os << accumulator.ToCString().get();
16078 : } else {
16079 210 : os << " (" << PrivateSymbolToName() << ")";
16080 : }
16081 227 : os << ">";
16082 227 : }
16083 :
16084 :
16085 : // StringSharedKeys are used as keys in the eval cache.
16086 0 : class StringSharedKey : public HashTableKey {
16087 : public:
16088 : // This tuple unambiguously identifies calls to eval() or
16089 : // CreateDynamicFunction() (such as through the Function() constructor).
16090 : // * source is the string passed into eval(). For dynamic functions, this is
16091 : // the effective source for the function, some of which is implicitly
16092 : // generated.
16093 : // * shared is the shared function info for the function containing the call
16094 : // to eval(). for dynamic functions, shared is the native context closure.
16095 : // * When positive, position is the position in the source where eval is
16096 : // called. When negative, position is the negation of the position in the
16097 : // dynamic function's effective source where the ')' ends the parameters.
16098 : StringSharedKey(Handle<String> source, Handle<SharedFunctionInfo> shared,
16099 : LanguageMode language_mode, int position)
16100 : : source_(source),
16101 : shared_(shared),
16102 : language_mode_(language_mode),
16103 7850873 : position_(position) {}
16104 :
16105 9648723 : bool IsMatch(Object* other) override {
16106 : DisallowHeapAllocation no_allocation;
16107 9648723 : if (!other->IsFixedArray()) {
16108 2549774 : if (!other->IsNumber()) return false;
16109 2549774 : uint32_t other_hash = static_cast<uint32_t>(other->Number());
16110 2549774 : return Hash() == other_hash;
16111 : }
16112 : FixedArray* other_array = FixedArray::cast(other);
16113 : SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
16114 7098949 : if (shared != *shared_) return false;
16115 : int language_unchecked = Smi::cast(other_array->get(2))->value();
16116 : DCHECK(is_valid_language_mode(language_unchecked));
16117 6776263 : LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
16118 6776263 : if (language_mode != language_mode_) return false;
16119 : int position = Smi::cast(other_array->get(3))->value();
16120 6749831 : if (position != position_) return false;
16121 : String* source = String::cast(other_array->get(1));
16122 6749801 : return source->Equals(*source_);
16123 : }
16124 :
16125 12129647 : static uint32_t StringSharedHashHelper(String* source,
16126 : SharedFunctionInfo* shared,
16127 : LanguageMode language_mode,
16128 : int position) {
16129 : uint32_t hash = source->Hash();
16130 12129647 : if (shared->HasSourceCode()) {
16131 : // Instead of using the SharedFunctionInfo pointer in the hash
16132 : // code computation, we use a combination of the hash of the
16133 : // script source code and the start position of the calling scope.
16134 : // We do this to ensure that the cache entries can survive garbage
16135 : // collection.
16136 : Script* script(Script::cast(shared->script()));
16137 12129647 : hash ^= String::cast(script->source())->Hash();
16138 : STATIC_ASSERT(LANGUAGE_END == 2);
16139 12129647 : if (is_strict(language_mode)) hash ^= 0x8000;
16140 12129647 : hash += position;
16141 : }
16142 12129647 : return hash;
16143 : }
16144 :
16145 11954613 : uint32_t Hash() override {
16146 : return StringSharedHashHelper(*source_, *shared_, language_mode_,
16147 23909226 : position_);
16148 : }
16149 :
16150 1019703 : uint32_t HashForObject(Object* obj) override {
16151 : DisallowHeapAllocation no_allocation;
16152 1019703 : if (obj->IsNumber()) {
16153 844669 : return static_cast<uint32_t>(obj->Number());
16154 : }
16155 : FixedArray* other_array = FixedArray::cast(obj);
16156 : SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
16157 : String* source = String::cast(other_array->get(1));
16158 : int language_unchecked = Smi::cast(other_array->get(2))->value();
16159 : DCHECK(is_valid_language_mode(language_unchecked));
16160 175034 : LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
16161 : int position = Smi::cast(other_array->get(3))->value();
16162 175034 : return StringSharedHashHelper(source, shared, language_mode, position);
16163 : }
16164 :
16165 :
16166 1985370 : Handle<Object> AsHandle(Isolate* isolate) override {
16167 1985370 : Handle<FixedArray> array = isolate->factory()->NewFixedArray(4);
16168 1985370 : array->set(0, *shared_);
16169 1985370 : array->set(1, *source_);
16170 1985370 : array->set(2, Smi::FromInt(language_mode_));
16171 1985370 : array->set(3, Smi::FromInt(position_));
16172 1985370 : return array;
16173 : }
16174 :
16175 : private:
16176 : Handle<String> source_;
16177 : Handle<SharedFunctionInfo> shared_;
16178 : LanguageMode language_mode_;
16179 : int position_;
16180 : };
16181 :
16182 : // static
16183 30 : const char* JSPromise::Status(int status) {
16184 30 : switch (status) {
16185 : case v8::Promise::kFulfilled:
16186 : return "resolved";
16187 : case v8::Promise::kPending:
16188 12 : return "pending";
16189 : case v8::Promise::kRejected:
16190 0 : return "rejected";
16191 : }
16192 0 : UNREACHABLE();
16193 : return NULL;
16194 : }
16195 :
16196 : namespace {
16197 :
16198 593209 : JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags, bool* success) {
16199 : JSRegExp::Flags value = JSRegExp::kNone;
16200 : int length = flags->length();
16201 : // A longer flags string cannot be valid.
16202 593209 : if (length > JSRegExp::FlagCount()) return JSRegExp::Flags(0);
16203 97165 : for (int i = 0; i < length; i++) {
16204 : JSRegExp::Flag flag = JSRegExp::kNone;
16205 97445 : switch (flags->Get(i)) {
16206 : case 'g':
16207 : flag = JSRegExp::kGlobal;
16208 : break;
16209 : case 'i':
16210 : flag = JSRegExp::kIgnoreCase;
16211 76841 : break;
16212 : case 'm':
16213 : flag = JSRegExp::kMultiline;
16214 719 : break;
16215 : case 's':
16216 84 : if (FLAG_harmony_regexp_dotall) {
16217 : flag = JSRegExp::kDotAll;
16218 : } else {
16219 28 : return JSRegExp::Flags(0);
16220 : }
16221 : break;
16222 : case 'u':
16223 : flag = JSRegExp::kUnicode;
16224 1835 : break;
16225 : case 'y':
16226 : flag = JSRegExp::kSticky;
16227 130 : break;
16228 : default:
16229 43 : return JSRegExp::Flags(0);
16230 : }
16231 : // Duplicate flag.
16232 97374 : if (value & flag) return JSRegExp::Flags(0);
16233 : value |= flag;
16234 : }
16235 592929 : *success = true;
16236 592929 : return value;
16237 : }
16238 :
16239 : } // namespace
16240 :
16241 :
16242 : // static
16243 125431 : MaybeHandle<JSRegExp> JSRegExp::New(Handle<String> pattern, Flags flags) {
16244 : Isolate* isolate = pattern->GetIsolate();
16245 125431 : Handle<JSFunction> constructor = isolate->regexp_function();
16246 : Handle<JSRegExp> regexp =
16247 125431 : Handle<JSRegExp>::cast(isolate->factory()->NewJSObject(constructor));
16248 :
16249 125431 : return JSRegExp::Initialize(regexp, pattern, flags);
16250 : }
16251 :
16252 :
16253 : // static
16254 122017 : Handle<JSRegExp> JSRegExp::Copy(Handle<JSRegExp> regexp) {
16255 : Isolate* const isolate = regexp->GetIsolate();
16256 122017 : return Handle<JSRegExp>::cast(isolate->factory()->CopyJSObject(regexp));
16257 : }
16258 :
16259 :
16260 : template <typename Char>
16261 719988 : inline int CountRequiredEscapes(Handle<String> source) {
16262 : DisallowHeapAllocation no_gc;
16263 : int escapes = 0;
16264 : Vector<const Char> src = source->GetCharVector<Char>();
16265 16857335 : for (int i = 0; i < src.length(); i++) {
16266 16137347 : if (src[i] == '\\') {
16267 : // Escape. Skip next character;
16268 152815 : i++;
16269 15984532 : } else if (src[i] == '/') {
16270 : // Not escaped forward-slash needs escape.
16271 2627 : escapes++;
16272 : }
16273 : }
16274 719988 : return escapes;
16275 : }
16276 :
16277 :
16278 : template <typename Char, typename StringType>
16279 958 : inline Handle<StringType> WriteEscapedRegExpSource(Handle<String> source,
16280 : Handle<StringType> result) {
16281 : DisallowHeapAllocation no_gc;
16282 : Vector<const Char> src = source->GetCharVector<Char>();
16283 958 : Vector<Char> dst(result->GetChars(), result->length());
16284 : int s = 0;
16285 : int d = 0;
16286 52745 : while (s < src.length()) {
16287 50829 : if (src[s] == '\\') {
16288 : // Escape. Copy this and next character.
16289 6196 : dst[d++] = src[s++];
16290 3098 : if (s == src.length()) break;
16291 47731 : } else if (src[s] == '/') {
16292 : // Not escaped forward-slash needs escape.
16293 5254 : dst[d++] = '\\';
16294 : }
16295 152487 : dst[d++] = src[s++];
16296 : }
16297 : DCHECK_EQ(result->length(), d);
16298 958 : return result;
16299 : }
16300 :
16301 :
16302 719988 : MaybeHandle<String> EscapeRegExpSource(Isolate* isolate,
16303 : Handle<String> source) {
16304 : DCHECK(source->IsFlat());
16305 719988 : if (source->length() == 0) return isolate->factory()->query_colon_string();
16306 719988 : bool one_byte = source->IsOneByteRepresentationUnderneath();
16307 : int escapes = one_byte ? CountRequiredEscapes<uint8_t>(source)
16308 719988 : : CountRequiredEscapes<uc16>(source);
16309 719988 : if (escapes == 0) return source;
16310 958 : int length = source->length() + escapes;
16311 958 : if (one_byte) {
16312 : Handle<SeqOneByteString> result;
16313 1916 : ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
16314 : isolate->factory()->NewRawOneByteString(length),
16315 : String);
16316 958 : return WriteEscapedRegExpSource<uint8_t>(source, result);
16317 : } else {
16318 : Handle<SeqTwoByteString> result;
16319 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
16320 : isolate->factory()->NewRawTwoByteString(length),
16321 : String);
16322 0 : return WriteEscapedRegExpSource<uc16>(source, result);
16323 : }
16324 : }
16325 :
16326 :
16327 : // static
16328 593209 : MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
16329 : Handle<String> source,
16330 : Handle<String> flags_string) {
16331 : Isolate* isolate = source->GetIsolate();
16332 593209 : bool success = false;
16333 593209 : Flags flags = RegExpFlagsFromString(flags_string, &success);
16334 593209 : if (!success) {
16335 560 : THROW_NEW_ERROR(
16336 : isolate,
16337 : NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string),
16338 : JSRegExp);
16339 : }
16340 592929 : return Initialize(regexp, source, flags);
16341 : }
16342 :
16343 :
16344 : // static
16345 719988 : MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
16346 : Handle<String> source, Flags flags) {
16347 : Isolate* isolate = regexp->GetIsolate();
16348 : Factory* factory = isolate->factory();
16349 : // If source is the empty string we set it to "(?:)" instead as
16350 : // suggested by ECMA-262, 5th, section 15.10.4.1.
16351 719988 : if (source->length() == 0) source = factory->query_colon_string();
16352 :
16353 719988 : source = String::Flatten(source);
16354 :
16355 : Handle<String> escaped_source;
16356 1439976 : ASSIGN_RETURN_ON_EXCEPTION(isolate, escaped_source,
16357 : EscapeRegExpSource(isolate, source), JSRegExp);
16358 :
16359 1439976 : RETURN_ON_EXCEPTION(isolate, RegExpImpl::Compile(regexp, source, flags),
16360 : JSRegExp);
16361 :
16362 716426 : regexp->set_source(*escaped_source);
16363 716426 : regexp->set_flags(Smi::FromInt(flags));
16364 :
16365 : Map* map = regexp->map();
16366 716426 : Object* constructor = map->GetConstructor();
16367 1432852 : if (constructor->IsJSFunction() &&
16368 : JSFunction::cast(constructor)->initial_map() == map) {
16369 : // If we still have the original map, set in-object properties directly.
16370 : regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, Smi::kZero,
16371 716128 : SKIP_WRITE_BARRIER);
16372 : } else {
16373 : // Map has changed, so use generic, but slower, method.
16374 596 : RETURN_ON_EXCEPTION(isolate, JSReceiver::SetProperty(
16375 : regexp, factory->lastIndex_string(),
16376 : Handle<Smi>(Smi::kZero, isolate), STRICT),
16377 : JSRegExp);
16378 : }
16379 :
16380 : return regexp;
16381 : }
16382 :
16383 :
16384 : // RegExpKey carries the source and flags of a regular expression as key.
16385 0 : class RegExpKey : public HashTableKey {
16386 : public:
16387 : RegExpKey(Handle<String> string, JSRegExp::Flags flags)
16388 2845370 : : string_(string), flags_(Smi::FromInt(flags)) {}
16389 :
16390 : // Rather than storing the key in the hash table, a pointer to the
16391 : // stored value is stored where the key should be. IsMatch then
16392 : // compares the search key to the found object, rather than comparing
16393 : // a key to a key.
16394 845523 : bool IsMatch(Object* obj) override {
16395 : FixedArray* val = FixedArray::cast(obj);
16396 845523 : return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
16397 1201983 : && (flags_ == val->get(JSRegExp::kFlagsIndex));
16398 : }
16399 :
16400 2845370 : uint32_t Hash() override { return RegExpHash(*string_, flags_); }
16401 :
16402 0 : Handle<Object> AsHandle(Isolate* isolate) override {
16403 : // Plain hash maps, which is where regexp keys are used, don't
16404 : // use this function.
16405 0 : UNREACHABLE();
16406 : return MaybeHandle<Object>().ToHandleChecked();
16407 : }
16408 :
16409 511813 : uint32_t HashForObject(Object* obj) override {
16410 : FixedArray* val = FixedArray::cast(obj);
16411 : return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
16412 511813 : Smi::cast(val->get(JSRegExp::kFlagsIndex)));
16413 : }
16414 :
16415 1934498 : static uint32_t RegExpHash(String* string, Smi* flags) {
16416 1934498 : return string->Hash() + flags->value();
16417 : }
16418 :
16419 : Handle<String> string_;
16420 : Smi* flags_;
16421 : };
16422 :
16423 :
16424 55774 : Handle<Object> OneByteStringKey::AsHandle(Isolate* isolate) {
16425 55774 : if (hash_field_ == 0) Hash();
16426 55774 : return isolate->factory()->NewOneByteInternalizedString(string_, hash_field_);
16427 : }
16428 :
16429 :
16430 0 : Handle<Object> TwoByteStringKey::AsHandle(Isolate* isolate) {
16431 0 : if (hash_field_ == 0) Hash();
16432 0 : return isolate->factory()->NewTwoByteInternalizedString(string_, hash_field_);
16433 : }
16434 :
16435 :
16436 115049 : Handle<Object> SeqOneByteSubStringKey::AsHandle(Isolate* isolate) {
16437 115049 : if (hash_field_ == 0) Hash();
16438 : return isolate->factory()->NewOneByteInternalizedSubString(
16439 115049 : string_, from_, length_, hash_field_);
16440 : }
16441 :
16442 :
16443 163654 : bool SeqOneByteSubStringKey::IsMatch(Object* string) {
16444 327308 : Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
16445 163654 : return String::cast(string)->IsOneByteEqualTo(chars);
16446 : }
16447 :
16448 :
16449 : // InternalizedStringKey carries a string/internalized-string object as key.
16450 0 : class InternalizedStringKey : public HashTableKey {
16451 : public:
16452 : explicit InternalizedStringKey(Handle<String> string)
16453 22836612 : : string_(String::Flatten(string)) {}
16454 :
16455 30597821 : bool IsMatch(Object* string) override {
16456 30597821 : return String::cast(string)->Equals(*string_);
16457 : }
16458 :
16459 49481142 : uint32_t Hash() override { return string_->Hash(); }
16460 :
16461 551700 : uint32_t HashForObject(Object* other) override {
16462 551700 : return String::cast(other)->Hash();
16463 : }
16464 :
16465 1904345 : Handle<Object> AsHandle(Isolate* isolate) override {
16466 : // Internalize the string if possible.
16467 : MaybeHandle<Map> maybe_map =
16468 1904345 : isolate->factory()->InternalizedStringMapForString(string_);
16469 : Handle<Map> map;
16470 1904346 : if (maybe_map.ToHandle(&map)) {
16471 : string_->set_map_no_write_barrier(*map);
16472 : DCHECK(string_->IsInternalizedString());
16473 10904 : return string_;
16474 : }
16475 1893442 : if (FLAG_thin_strings) {
16476 : // External strings get special treatment, to avoid copying their
16477 : // contents.
16478 1331495 : if (string_->IsExternalOneByteString()) {
16479 : return isolate->factory()
16480 6 : ->InternalizeExternalString<ExternalOneByteString>(string_);
16481 1331490 : } else if (string_->IsExternalTwoByteString()) {
16482 : return isolate->factory()
16483 0 : ->InternalizeExternalString<ExternalTwoByteString>(string_);
16484 : }
16485 : }
16486 : // Otherwise allocate a new internalized string.
16487 : return isolate->factory()->NewInternalizedStringImpl(
16488 1893439 : string_, string_->length(), string_->hash_field());
16489 : }
16490 :
16491 : static uint32_t StringHash(Object* obj) {
16492 : return String::cast(obj)->Hash();
16493 : }
16494 :
16495 : private:
16496 : Handle<String> string_;
16497 : };
16498 :
16499 :
16500 : template<typename Derived, typename Shape, typename Key>
16501 53346 : void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) {
16502 : BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v);
16503 53346 : }
16504 :
16505 :
16506 : template<typename Derived, typename Shape, typename Key>
16507 71432 : void HashTable<Derived, Shape, Key>::IterateElements(ObjectVisitor* v) {
16508 : BodyDescriptorBase::IteratePointers(this, kElementsStartOffset,
16509 71432 : kHeaderSize + length() * kPointerSize, v);
16510 71432 : }
16511 :
16512 :
16513 : template<typename Derived, typename Shape, typename Key>
16514 7433054 : Handle<Derived> HashTable<Derived, Shape, Key>::New(
16515 : Isolate* isolate,
16516 : int at_least_space_for,
16517 : MinimumCapacity capacity_option,
16518 : PretenureFlag pretenure) {
16519 : DCHECK(0 <= at_least_space_for);
16520 : DCHECK_IMPLIES(capacity_option == USE_CUSTOM_MINIMUM_CAPACITY,
16521 : base::bits::IsPowerOfTwo32(at_least_space_for));
16522 :
16523 : int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
16524 : ? at_least_space_for
16525 7433054 : : ComputeCapacity(at_least_space_for);
16526 7433054 : if (capacity > HashTable::kMaxCapacity) {
16527 0 : v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
16528 : }
16529 7433054 : return New(isolate, capacity, pretenure);
16530 : }
16531 :
16532 : template <typename Derived, typename Shape, typename Key>
16533 7433338 : Handle<Derived> HashTable<Derived, Shape, Key>::New(Isolate* isolate,
16534 : int capacity,
16535 : PretenureFlag pretenure) {
16536 : Factory* factory = isolate->factory();
16537 : int length = EntryToIndex(capacity);
16538 7433338 : Handle<FixedArray> array = factory->NewFixedArray(length, pretenure);
16539 : array->set_map_no_write_barrier(Shape::GetMap(isolate));
16540 : Handle<Derived> table = Handle<Derived>::cast(array);
16541 :
16542 : table->SetNumberOfElements(0);
16543 : table->SetNumberOfDeletedElements(0);
16544 : table->SetCapacity(capacity);
16545 7433338 : return table;
16546 : }
16547 :
16548 : // Find entry for key otherwise return kNotFound.
16549 : template <typename Derived, typename Shape>
16550 94104490 : int NameDictionaryBase<Derived, Shape>::FindEntry(Handle<Name> key) {
16551 94104490 : if (!key->IsUniqueName()) {
16552 0 : return DerivedDictionary::FindEntry(key);
16553 : }
16554 :
16555 : // Optimized for unique names. Knowledge of the key type allows:
16556 : // 1. Move the check if the key is unique out of the loop.
16557 : // 2. Avoid comparing hash codes in unique-to-unique comparison.
16558 : // 3. Detect a case when a dictionary key is not unique but the key is.
16559 : // In case of positive result the dictionary key may be replaced by the
16560 : // internalized string with minimal performance penalty. It gives a chance
16561 : // to perform further lookups in code stubs (and significant performance
16562 : // boost a certain style of code).
16563 :
16564 : // EnsureCapacity will guarantee the hash table is never full.
16565 94104490 : uint32_t capacity = this->Capacity();
16566 : uint32_t entry = Derived::FirstProbe(key->Hash(), capacity);
16567 : uint32_t count = 1;
16568 : Isolate* isolate = this->GetIsolate();
16569 : while (true) {
16570 153144225 : Object* element = this->KeyAt(entry);
16571 153144201 : if (element->IsUndefined(isolate)) break; // Empty entry.
16572 108522855 : if (*key == element) return entry;
16573 : DCHECK(element->IsTheHole(isolate) || element->IsUniqueName());
16574 59039736 : entry = Derived::NextProbe(entry, count++, capacity);
16575 : }
16576 59039736 : return Derived::kNotFound;
16577 : }
16578 :
16579 :
16580 : template<typename Derived, typename Shape, typename Key>
16581 3427317 : void HashTable<Derived, Shape, Key>::Rehash(
16582 : Handle<Derived> new_table,
16583 : Key key) {
16584 : DCHECK(NumberOfElements() < new_table->Capacity());
16585 :
16586 : DisallowHeapAllocation no_gc;
16587 3427317 : WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
16588 :
16589 : // Copy prefix to new array.
16590 10226682 : for (int i = kPrefixStartIndex;
16591 : i < kPrefixStartIndex + Shape::kPrefixSize;
16592 : i++) {
16593 6817788 : new_table->set(i, get(i), mode);
16594 : }
16595 :
16596 : // Rehash the elements.
16597 : int capacity = this->Capacity();
16598 3427317 : Heap* heap = new_table->GetHeap();
16599 : Object* the_hole = heap->the_hole_value();
16600 : Object* undefined = heap->undefined_value();
16601 73606726 : for (int i = 0; i < capacity; i++) {
16602 70176896 : uint32_t from_index = EntryToIndex(i);
16603 : Object* k = this->get(from_index);
16604 70176896 : if (k != the_hole && k != undefined) {
16605 : uint32_t hash = this->HashForObject(key, k);
16606 : uint32_t insertion_index =
16607 78348964 : EntryToIndex(new_table->FindInsertionEntry(hash));
16608 135902091 : for (int j = 0; j < Shape::kEntrySize; j++) {
16609 290182827 : new_table->set(insertion_index + j, get(from_index + j), mode);
16610 : }
16611 : }
16612 : }
16613 : new_table->SetNumberOfElements(NumberOfElements());
16614 : new_table->SetNumberOfDeletedElements(0);
16615 3427317 : }
16616 :
16617 :
16618 : template<typename Derived, typename Shape, typename Key>
16619 1434830 : uint32_t HashTable<Derived, Shape, Key>::EntryForProbe(
16620 : Key key,
16621 : Object* k,
16622 : int probe,
16623 : uint32_t expected) {
16624 : uint32_t hash = this->HashForObject(key, k);
16625 1434830 : uint32_t capacity = this->Capacity();
16626 : uint32_t entry = FirstProbe(hash, capacity);
16627 3514261 : for (int i = 1; i < probe; i++) {
16628 2853171 : if (entry == expected) return expected;
16629 2079431 : entry = NextProbe(entry, i, capacity);
16630 : }
16631 : return entry;
16632 : }
16633 :
16634 :
16635 : template<typename Derived, typename Shape, typename Key>
16636 9340 : void HashTable<Derived, Shape, Key>::Swap(uint32_t entry1,
16637 : uint32_t entry2,
16638 : WriteBarrierMode mode) {
16639 9340 : int index1 = EntryToIndex(entry1);
16640 9340 : int index2 = EntryToIndex(entry2);
16641 : Object* temp[Shape::kEntrySize];
16642 28020 : for (int j = 0; j < Shape::kEntrySize; j++) {
16643 37360 : temp[j] = get(index1 + j);
16644 : }
16645 18680 : for (int j = 0; j < Shape::kEntrySize; j++) {
16646 37360 : set(index1 + j, get(index2 + j), mode);
16647 : }
16648 18680 : for (int j = 0; j < Shape::kEntrySize; j++) {
16649 18680 : set(index2 + j, temp[j], mode);
16650 : }
16651 9340 : }
16652 :
16653 :
16654 : template<typename Derived, typename Shape, typename Key>
16655 53367 : void HashTable<Derived, Shape, Key>::Rehash(Key key) {
16656 : DisallowHeapAllocation no_gc;
16657 53367 : WriteBarrierMode mode = GetWriteBarrierMode(no_gc);
16658 : Isolate* isolate = GetIsolate();
16659 53367 : uint32_t capacity = Capacity();
16660 : bool done = false;
16661 141776 : for (int probe = 1; !done; probe++) {
16662 : // All elements at entries given by one of the first _probe_ probes
16663 : // are placed correctly. Other elements might need to be moved.
16664 : done = true;
16665 4198172 : for (uint32_t current = 0; current < capacity; current++) {
16666 4198172 : Object* current_key = KeyAt(current);
16667 4198172 : if (IsKey(isolate, current_key)) {
16668 1183496 : uint32_t target = EntryForProbe(key, current_key, probe, current);
16669 1183496 : if (current == target) continue;
16670 257744 : Object* target_key = KeyAt(target);
16671 509078 : if (!IsKey(isolate, target_key) ||
16672 251334 : EntryForProbe(key, target_key, probe, target) != target) {
16673 : // Put the current element into the correct position.
16674 9340 : Swap(current, target, mode);
16675 : // The other element will be processed on the next iteration.
16676 9340 : current--;
16677 : } else {
16678 : // The place for the current element is occupied. Leave the element
16679 : // for the next probe.
16680 : done = false;
16681 : }
16682 : }
16683 : }
16684 : }
16685 : // Wipe deleted entries.
16686 53367 : Object* the_hole = isolate->heap()->the_hole_value();
16687 53367 : Object* undefined = isolate->heap()->undefined_value();
16688 1979767 : for (uint32_t current = 0; current < capacity; current++) {
16689 3852800 : if (KeyAt(current) == the_hole) {
16690 15761 : set(EntryToIndex(current) + Derived::kEntryKeyIndex, undefined);
16691 : }
16692 : }
16693 : SetNumberOfDeletedElements(0);
16694 53367 : }
16695 :
16696 :
16697 : template<typename Derived, typename Shape, typename Key>
16698 69360565 : Handle<Derived> HashTable<Derived, Shape, Key>::EnsureCapacity(
16699 : Handle<Derived> table,
16700 : int n,
16701 : Key key,
16702 : PretenureFlag pretenure) {
16703 69360565 : if (table->HasSufficientCapacityToAdd(n)) return table;
16704 :
16705 : Isolate* isolate = table->GetIsolate();
16706 : int capacity = table->Capacity();
16707 3426888 : int new_nof = table->NumberOfElements() + n;
16708 :
16709 : const int kMinCapacityForPretenure = 256;
16710 : bool should_pretenure = pretenure == TENURED ||
16711 : ((capacity > kMinCapacityForPretenure) &&
16712 3433916 : !isolate->heap()->InNewSpace(*table));
16713 : Handle<Derived> new_table =
16714 : HashTable::New(isolate, new_nof, USE_DEFAULT_MINIMUM_CAPACITY,
16715 3426888 : should_pretenure ? TENURED : NOT_TENURED);
16716 :
16717 3426888 : table->Rehash(new_table, key);
16718 3426888 : return new_table;
16719 : }
16720 :
16721 : template <typename Derived, typename Shape, typename Key>
16722 69366378 : bool HashTable<Derived, Shape, Key>::HasSufficientCapacityToAdd(
16723 : int number_of_additional_elements) {
16724 : int capacity = Capacity();
16725 69366378 : int nof = NumberOfElements() + number_of_additional_elements;
16726 : int nod = NumberOfDeletedElements();
16727 : // Return true if:
16728 : // 50% is still free after adding number_of_additional_elements elements and
16729 : // at most 50% of the free elements are deleted elements.
16730 69366378 : if ((nof < capacity) && ((nod <= (capacity - nof) >> 1))) {
16731 66396204 : int needed_free = nof >> 1;
16732 66396204 : if (nof + needed_free <= capacity) return true;
16733 : }
16734 3427290 : return false;
16735 : }
16736 :
16737 :
16738 : template<typename Derived, typename Shape, typename Key>
16739 6170046 : Handle<Derived> HashTable<Derived, Shape, Key>::Shrink(Handle<Derived> table,
16740 : Key key) {
16741 : int capacity = table->Capacity();
16742 : int nof = table->NumberOfElements();
16743 :
16744 : // Shrink to fit the number of elements if only a quarter of the
16745 : // capacity is filled with elements.
16746 6170046 : if (nof > (capacity >> 2)) return table;
16747 : // Allocate a new dictionary with room for at least the current
16748 : // number of elements. The allocation method will make sure that
16749 : // there is extra room in the dictionary for additions. Don't go
16750 : // lower than room for 16 elements.
16751 : int at_least_room_for = nof;
16752 6119485 : if (at_least_room_for < 16) return table;
16753 :
16754 : Isolate* isolate = table->GetIsolate();
16755 : const int kMinCapacityForPretenure = 256;
16756 : bool pretenure =
16757 : (at_least_room_for > kMinCapacityForPretenure) &&
16758 458 : !isolate->heap()->InNewSpace(*table);
16759 : Handle<Derived> new_table = HashTable::New(
16760 : isolate,
16761 : at_least_room_for,
16762 : USE_DEFAULT_MINIMUM_CAPACITY,
16763 429 : pretenure ? TENURED : NOT_TENURED);
16764 :
16765 429 : table->Rehash(new_table, key);
16766 429 : return new_table;
16767 : }
16768 :
16769 :
16770 : template<typename Derived, typename Shape, typename Key>
16771 108534663 : uint32_t HashTable<Derived, Shape, Key>::FindInsertionEntry(uint32_t hash) {
16772 108534663 : uint32_t capacity = Capacity();
16773 : uint32_t entry = FirstProbe(hash, capacity);
16774 : uint32_t count = 1;
16775 : // EnsureCapacity will guarantee the hash table is never full.
16776 : Isolate* isolate = GetIsolate();
16777 : while (true) {
16778 181056264 : Object* element = KeyAt(entry);
16779 181056264 : if (!IsKey(isolate, element)) break;
16780 72521601 : entry = NextProbe(entry, count++, capacity);
16781 : }
16782 72521601 : return entry;
16783 : }
16784 :
16785 :
16786 : // Force instantiation of template instances class.
16787 : // Please note this list is compiler dependent.
16788 :
16789 : template class HashTable<StringTable, StringTableShape, HashTableKey*>;
16790 :
16791 : template class HashTable<CompilationCacheTable,
16792 : CompilationCacheShape,
16793 : HashTableKey*>;
16794 :
16795 : template class HashTable<ObjectHashTable,
16796 : ObjectHashTableShape,
16797 : Handle<Object> >;
16798 :
16799 : template class HashTable<WeakHashTable, WeakHashTableShape<2>, Handle<Object> >;
16800 :
16801 : template class Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >;
16802 :
16803 : template class Dictionary<GlobalDictionary, GlobalDictionaryShape,
16804 : Handle<Name> >;
16805 :
16806 : template class Dictionary<SeededNumberDictionary,
16807 : SeededNumberDictionaryShape,
16808 : uint32_t>;
16809 :
16810 : template class Dictionary<UnseededNumberDictionary,
16811 : UnseededNumberDictionaryShape,
16812 : uint32_t>;
16813 :
16814 : template Handle<SeededNumberDictionary>
16815 : Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::New(
16816 : Isolate*, int at_least_space_for, PretenureFlag pretenure,
16817 : MinimumCapacity capacity_option);
16818 :
16819 : template Handle<SeededNumberDictionary>
16820 : Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
16821 : uint32_t>::NewEmpty(Isolate*, PretenureFlag pretenure);
16822 :
16823 : template Handle<UnseededNumberDictionary>
16824 : Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
16825 : uint32_t>::NewEmpty(Isolate*, PretenureFlag pretenure);
16826 :
16827 : template Handle<UnseededNumberDictionary>
16828 : Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
16829 : uint32_t>::New(Isolate*, int at_least_space_for,
16830 : PretenureFlag pretenure,
16831 : MinimumCapacity capacity_option);
16832 :
16833 : template Handle<NameDictionary>
16834 : Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::New(
16835 : Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
16836 :
16837 : template Handle<NameDictionary>
16838 : Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::NewEmpty(
16839 : Isolate*, PretenureFlag pretenure);
16840 :
16841 : template Handle<GlobalDictionary>
16842 : Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::New(
16843 : Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
16844 :
16845 : template Handle<SeededNumberDictionary>
16846 : Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
16847 : AtPut(Handle<SeededNumberDictionary>, uint32_t, Handle<Object>);
16848 :
16849 : template Handle<UnseededNumberDictionary>
16850 : Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
16851 : AtPut(Handle<UnseededNumberDictionary>, uint32_t, Handle<Object>);
16852 :
16853 : template Object*
16854 : Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
16855 : SlowReverseLookup(Object* value);
16856 :
16857 : template Object*
16858 : Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
16859 : SlowReverseLookup(Object* value);
16860 :
16861 : template Handle<Object>
16862 : Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::DeleteProperty(
16863 : Handle<NameDictionary>, int);
16864 :
16865 : template Handle<Object>
16866 : Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
16867 : uint32_t>::DeleteProperty(Handle<SeededNumberDictionary>, int);
16868 :
16869 : template Handle<Object>
16870 : Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
16871 : uint32_t>::DeleteProperty(Handle<UnseededNumberDictionary>, int);
16872 :
16873 : template Handle<NameDictionary>
16874 : HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
16875 : New(Isolate*, int, MinimumCapacity, PretenureFlag);
16876 :
16877 : template Handle<ObjectHashSet> HashTable<ObjectHashSet, ObjectHashSetShape,
16878 : Handle<Object>>::New(Isolate*, int n,
16879 : MinimumCapacity,
16880 : PretenureFlag);
16881 :
16882 : template Handle<NameDictionary>
16883 : HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
16884 : Shrink(Handle<NameDictionary>, Handle<Name>);
16885 :
16886 : template Handle<SeededNumberDictionary>
16887 : HashTable<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
16888 : Shrink(Handle<SeededNumberDictionary>, uint32_t);
16889 :
16890 : template Handle<UnseededNumberDictionary>
16891 : HashTable<UnseededNumberDictionary, UnseededNumberDictionaryShape,
16892 : uint32_t>::Shrink(Handle<UnseededNumberDictionary>, uint32_t);
16893 :
16894 : template Handle<NameDictionary>
16895 : Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::Add(
16896 : Handle<NameDictionary>, Handle<Name>, Handle<Object>, PropertyDetails,
16897 : int*);
16898 :
16899 : template Handle<GlobalDictionary>
16900 : Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::Add(
16901 : Handle<GlobalDictionary>, Handle<Name>, Handle<Object>, PropertyDetails,
16902 : int*);
16903 :
16904 : template Handle<SeededNumberDictionary>
16905 : Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::Add(
16906 : Handle<SeededNumberDictionary>, uint32_t, Handle<Object>, PropertyDetails,
16907 : int*);
16908 :
16909 : template Handle<UnseededNumberDictionary>
16910 : Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
16911 : uint32_t>::Add(Handle<UnseededNumberDictionary>, uint32_t,
16912 : Handle<Object>, PropertyDetails, int*);
16913 :
16914 : template Handle<SeededNumberDictionary>
16915 : Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
16916 : EnsureCapacity(Handle<SeededNumberDictionary>, int, uint32_t);
16917 :
16918 : template Handle<UnseededNumberDictionary>
16919 : Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
16920 : EnsureCapacity(Handle<UnseededNumberDictionary>, int, uint32_t);
16921 :
16922 : template void Dictionary<NameDictionary, NameDictionaryShape,
16923 : Handle<Name> >::SetRequiresCopyOnCapacityChange();
16924 :
16925 : template Handle<NameDictionary>
16926 : Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
16927 : EnsureCapacity(Handle<NameDictionary>, int, Handle<Name>);
16928 :
16929 : template int HashTable<SeededNumberDictionary, SeededNumberDictionaryShape,
16930 : uint32_t>::FindEntry(uint32_t);
16931 :
16932 : template int NameDictionaryBase<NameDictionary, NameDictionaryShape>::FindEntry(
16933 : Handle<Name>);
16934 :
16935 : template int Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
16936 : NumberOfElementsFilterAttributes(PropertyFilter filter);
16937 :
16938 : template int Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::
16939 : NumberOfElementsFilterAttributes(PropertyFilter filter);
16940 :
16941 : template void
16942 : Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
16943 : CopyEnumKeysTo(Handle<Dictionary<GlobalDictionary, GlobalDictionaryShape,
16944 : Handle<Name>>>
16945 : dictionary,
16946 : Handle<FixedArray> storage, KeyCollectionMode mode,
16947 : KeyAccumulator* accumulator);
16948 :
16949 : template void
16950 : Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::CopyEnumKeysTo(
16951 : Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>>
16952 : dictionary,
16953 : Handle<FixedArray> storage, KeyCollectionMode mode,
16954 : KeyAccumulator* accumulator);
16955 :
16956 : template Handle<FixedArray>
16957 : Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
16958 : IterationIndices(
16959 : Handle<
16960 : Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>>
16961 : dictionary);
16962 : template void
16963 : Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
16964 : CollectKeysTo(Handle<Dictionary<GlobalDictionary, GlobalDictionaryShape,
16965 : Handle<Name>>>
16966 : dictionary,
16967 : KeyAccumulator* keys);
16968 :
16969 : template Handle<FixedArray>
16970 : Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::IterationIndices(
16971 : Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>>
16972 : dictionary);
16973 : template void
16974 : Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::CollectKeysTo(
16975 : Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>>
16976 : dictionary,
16977 : KeyAccumulator* keys);
16978 :
16979 103 : Handle<Object> JSObject::PrepareSlowElementsForSort(
16980 : Handle<JSObject> object, uint32_t limit) {
16981 : DCHECK(object->HasDictionaryElements());
16982 : Isolate* isolate = object->GetIsolate();
16983 : // Must stay in dictionary mode, either because of requires_slow_elements,
16984 : // or because we are not going to sort (and therefore compact) all of the
16985 : // elements.
16986 : Handle<SeededNumberDictionary> dict(object->element_dictionary(), isolate);
16987 : Handle<SeededNumberDictionary> new_dict =
16988 103 : SeededNumberDictionary::New(isolate, dict->NumberOfElements());
16989 :
16990 : uint32_t pos = 0;
16991 : uint32_t undefs = 0;
16992 : int capacity = dict->Capacity();
16993 : Handle<Smi> bailout(Smi::FromInt(-1), isolate);
16994 : // Entry to the new dictionary does not cause it to grow, as we have
16995 : // allocated one that is large enough for all entries.
16996 : DisallowHeapAllocation no_gc;
16997 429 : for (int i = 0; i < capacity; i++) {
16998 : Object* k = dict->KeyAt(i);
16999 385 : if (!dict->IsKey(isolate, k)) continue;
17000 :
17001 : DCHECK(k->IsNumber());
17002 : DCHECK(!k->IsSmi() || Smi::cast(k)->value() >= 0);
17003 : DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
17004 : DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
17005 :
17006 : HandleScope scope(isolate);
17007 238 : Handle<Object> value(dict->ValueAt(i), isolate);
17008 : PropertyDetails details = dict->DetailsAt(i);
17009 432 : if (details.kind() == kAccessor || details.IsReadOnly()) {
17010 : // Bail out and do the sorting of undefineds and array holes in JS.
17011 : // Also bail out if the element is not supposed to be moved.
17012 44 : return bailout;
17013 : }
17014 :
17015 194 : uint32_t key = NumberToUint32(k);
17016 194 : if (key < limit) {
17017 164 : if (value->IsUndefined(isolate)) {
17018 15 : undefs++;
17019 149 : } else if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
17020 : // Adding an entry with the key beyond smi-range requires
17021 : // allocation. Bailout.
17022 0 : return bailout;
17023 : } else {
17024 : Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
17025 149 : new_dict, pos, value, details, object);
17026 : DCHECK(result.is_identical_to(new_dict));
17027 : USE(result);
17028 149 : pos++;
17029 : }
17030 30 : } else if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
17031 : // Adding an entry with the key beyond smi-range requires
17032 : // allocation. Bailout.
17033 15 : return bailout;
17034 : } else {
17035 : Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
17036 15 : new_dict, key, value, details, object);
17037 : DCHECK(result.is_identical_to(new_dict));
17038 : USE(result);
17039 : }
17040 : }
17041 :
17042 : uint32_t result = pos;
17043 44 : PropertyDetails no_details = PropertyDetails::Empty();
17044 103 : while (undefs > 0) {
17045 15 : if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
17046 : // Adding an entry with the key beyond smi-range requires
17047 : // allocation. Bailout.
17048 0 : return bailout;
17049 : }
17050 : HandleScope scope(isolate);
17051 : Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
17052 : new_dict, pos, isolate->factory()->undefined_value(), no_details,
17053 15 : object);
17054 : DCHECK(result.is_identical_to(new_dict));
17055 : USE(result);
17056 15 : pos++;
17057 15 : undefs--;
17058 : }
17059 :
17060 44 : object->set_elements(*new_dict);
17061 :
17062 : AllowHeapAllocation allocate_return_value;
17063 44 : return isolate->factory()->NewNumberFromUint(result);
17064 : }
17065 :
17066 :
17067 : // Collects all defined (non-hole) and non-undefined (array) elements at
17068 : // the start of the elements array.
17069 : // If the object is in dictionary mode, it is converted to fast elements
17070 : // mode.
17071 126632 : Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object,
17072 : uint32_t limit) {
17073 : Isolate* isolate = object->GetIsolate();
17074 253234 : if (object->HasSloppyArgumentsElements() || !object->map()->is_extensible()) {
17075 105 : return handle(Smi::FromInt(-1), isolate);
17076 : }
17077 :
17078 126527 : if (object->HasStringWrapperElements()) {
17079 : int len = String::cast(Handle<JSValue>::cast(object)->value())->length();
17080 15 : return handle(Smi::FromInt(len), isolate);
17081 : }
17082 :
17083 126512 : if (object->HasDictionaryElements()) {
17084 : // Convert to fast elements containing only the existing properties.
17085 : // Ordering is irrelevant, since we are going to sort anyway.
17086 : Handle<SeededNumberDictionary> dict(object->element_dictionary());
17087 342 : if (object->IsJSArray() || dict->requires_slow_elements() ||
17088 60 : dict->max_number_key() >= limit) {
17089 103 : return JSObject::PrepareSlowElementsForSort(object, limit);
17090 : }
17091 : // Convert to fast elements.
17092 :
17093 : Handle<Map> new_map =
17094 60 : JSObject::GetElementsTransitionMap(object, FAST_HOLEY_ELEMENTS);
17095 :
17096 : PretenureFlag tenure = isolate->heap()->InNewSpace(*object) ?
17097 60 : NOT_TENURED: TENURED;
17098 : Handle<FixedArray> fast_elements =
17099 60 : isolate->factory()->NewFixedArray(dict->NumberOfElements(), tenure);
17100 60 : dict->CopyValuesTo(*fast_elements);
17101 : JSObject::ValidateElements(object);
17102 :
17103 60 : JSObject::SetMapAndElements(object, new_map, fast_elements);
17104 126349 : } else if (object->HasFixedTypedArrayElements()) {
17105 : // Typed arrays cannot have holes or undefined elements.
17106 : return handle(Smi::FromInt(
17107 141 : FixedArrayBase::cast(object->elements())->length()), isolate);
17108 126208 : } else if (!object->HasFastDoubleElements()) {
17109 126151 : EnsureWritableFastElements(object);
17110 : }
17111 : DCHECK(object->HasFastSmiOrObjectElements() ||
17112 : object->HasFastDoubleElements());
17113 :
17114 : // Collect holes at the end, undefined before that and the rest at the
17115 : // start, and return the number of non-hole, non-undefined values.
17116 :
17117 : Handle<FixedArrayBase> elements_base(object->elements());
17118 126268 : uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
17119 126268 : if (limit > elements_length) {
17120 : limit = elements_length;
17121 : }
17122 126268 : if (limit == 0) {
17123 15 : return handle(Smi::kZero, isolate);
17124 : }
17125 :
17126 : uint32_t result = 0;
17127 126253 : if (elements_base->map() == isolate->heap()->fixed_double_array_map()) {
17128 : FixedDoubleArray* elements = FixedDoubleArray::cast(*elements_base);
17129 : // Split elements into defined and the_hole, in that order.
17130 : unsigned int holes = limit;
17131 : // Assume most arrays contain no holes and undefined values, so minimize the
17132 : // number of stores of non-undefined, non-the-hole values.
17133 5915 : for (unsigned int i = 0; i < holes; i++) {
17134 11716 : if (elements->is_the_hole(i)) {
17135 0 : holes--;
17136 : } else {
17137 : continue;
17138 : }
17139 : // Position i needs to be filled.
17140 0 : while (holes > i) {
17141 0 : if (elements->is_the_hole(holes)) {
17142 0 : holes--;
17143 : } else {
17144 : elements->set(i, elements->get_scalar(holes));
17145 : break;
17146 : }
17147 : }
17148 : }
17149 : result = holes;
17150 57 : while (holes < limit) {
17151 0 : elements->set_the_hole(holes);
17152 0 : holes++;
17153 : }
17154 : } else {
17155 : FixedArray* elements = FixedArray::cast(*elements_base);
17156 : DisallowHeapAllocation no_gc;
17157 :
17158 : // Split elements into defined, undefined and the_hole, in that order. Only
17159 : // count locations for undefined and the hole, and fill them afterwards.
17160 126196 : WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_gc);
17161 : unsigned int undefs = limit;
17162 : unsigned int holes = limit;
17163 : // Assume most arrays contain no holes and undefined values, so minimize the
17164 : // number of stores of non-undefined, non-the-hole values.
17165 5889807 : for (unsigned int i = 0; i < undefs; i++) {
17166 5763611 : Object* current = elements->get(i);
17167 5763611 : if (current->IsTheHole(isolate)) {
17168 31206 : holes--;
17169 31206 : undefs--;
17170 5732405 : } else if (current->IsUndefined(isolate)) {
17171 1136 : undefs--;
17172 : } else {
17173 : continue;
17174 : }
17175 : // Position i needs to be filled.
17176 7706829 : while (undefs > i) {
17177 7706137 : current = elements->get(undefs);
17178 7706137 : if (current->IsTheHole(isolate)) {
17179 7673296 : holes--;
17180 7673296 : undefs--;
17181 32841 : } else if (current->IsUndefined(isolate)) {
17182 1191 : undefs--;
17183 : } else {
17184 31650 : elements->set(i, current, write_barrier);
17185 31650 : break;
17186 : }
17187 : }
17188 : }
17189 : result = undefs;
17190 128523 : while (undefs < holes) {
17191 2327 : elements->set_undefined(isolate, undefs);
17192 2327 : undefs++;
17193 : }
17194 7830698 : while (holes < limit) {
17195 7704502 : elements->set_the_hole(isolate, holes);
17196 7704502 : holes++;
17197 : }
17198 : }
17199 :
17200 126253 : return isolate->factory()->NewNumberFromUint(result);
17201 : }
17202 :
17203 : namespace {
17204 :
17205 4492 : bool CanonicalNumericIndexString(Isolate* isolate, Handle<Object> s,
17206 : Handle<Object>* index) {
17207 : DCHECK(s->IsString() || s->IsSmi());
17208 :
17209 : Handle<Object> result;
17210 4492 : if (s->IsSmi()) {
17211 : result = s;
17212 : } else {
17213 4464 : result = String::ToNumber(Handle<String>::cast(s));
17214 4464 : if (!result->IsMinusZero()) {
17215 8900 : Handle<String> str = Object::ToString(isolate, result).ToHandleChecked();
17216 : // Avoid treating strings like "2E1" and "20" as the same key.
17217 4450 : if (!str->SameValue(*s)) return false;
17218 : }
17219 : }
17220 275 : *index = result;
17221 275 : return true;
17222 : }
17223 :
17224 : } // anonymous namespace
17225 :
17226 : // ES#sec-integer-indexed-exotic-objects-defineownproperty-p-desc
17227 : // static
17228 4786 : Maybe<bool> JSTypedArray::DefineOwnProperty(Isolate* isolate,
17229 : Handle<JSTypedArray> o,
17230 : Handle<Object> key,
17231 : PropertyDescriptor* desc,
17232 : ShouldThrow should_throw) {
17233 : // 1. Assert: IsPropertyKey(P) is true.
17234 : DCHECK(key->IsName() || key->IsNumber());
17235 : // 2. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot.
17236 : // 3. If Type(P) is String, then
17237 5108 : if (key->IsString() || key->IsSmi()) {
17238 : // 3a. Let numericIndex be ! CanonicalNumericIndexString(P)
17239 : // 3b. If numericIndex is not undefined, then
17240 : Handle<Object> numeric_index;
17241 4492 : if (CanonicalNumericIndexString(isolate, key, &numeric_index)) {
17242 : // 3b i. If IsInteger(numericIndex) is false, return false.
17243 : // 3b ii. If numericIndex = -0, return false.
17244 : // 3b iii. If numericIndex < 0, return false.
17245 : // FIXME: the standard allows up to 2^53 elements.
17246 : uint32_t index;
17247 536 : if (numeric_index->IsMinusZero() || !numeric_index->ToUint32(&index)) {
17248 126 : RETURN_FAILURE(isolate, should_throw,
17249 : NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
17250 : }
17251 : // 3b iv. Let length be O.[[ArrayLength]].
17252 233 : uint32_t length = o->length()->Number();
17253 : // 3b v. If numericIndex ≥ length, return false.
17254 233 : if (index >= length) {
17255 42 : RETURN_FAILURE(isolate, should_throw,
17256 : NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
17257 : }
17258 : // 3b vi. If IsAccessorDescriptor(Desc) is true, return false.
17259 219 : if (PropertyDescriptor::IsAccessorDescriptor(desc)) {
17260 234 : RETURN_FAILURE(isolate, should_throw,
17261 : NewTypeError(MessageTemplate::kRedefineDisallowed, key));
17262 : }
17263 : // 3b vii. If Desc has a [[Configurable]] field and if
17264 : // Desc.[[Configurable]] is true, return false.
17265 : // 3b viii. If Desc has an [[Enumerable]] field and if Desc.[[Enumerable]]
17266 : // is false, return false.
17267 : // 3b ix. If Desc has a [[Writable]] field and if Desc.[[Writable]] is
17268 : // false, return false.
17269 30 : if ((desc->has_configurable() && desc->configurable()) ||
17270 30 : (desc->has_enumerable() && !desc->enumerable()) ||
17271 15 : (desc->has_writable() && !desc->writable())) {
17272 45 : RETURN_FAILURE(isolate, should_throw,
17273 : NewTypeError(MessageTemplate::kRedefineDisallowed, key));
17274 : }
17275 : // 3b x. If Desc has a [[Value]] field, then
17276 : // 3b x 1. Let value be Desc.[[Value]].
17277 : // 3b x 2. Return ? IntegerIndexedElementSet(O, numericIndex, value).
17278 0 : if (desc->has_value()) {
17279 0 : if (!desc->has_configurable()) desc->set_configurable(false);
17280 0 : if (!desc->has_enumerable()) desc->set_enumerable(true);
17281 0 : if (!desc->has_writable()) desc->set_writable(true);
17282 0 : Handle<Object> value = desc->value();
17283 0 : RETURN_ON_EXCEPTION_VALUE(isolate,
17284 : SetOwnElementIgnoreAttributes(
17285 : o, index, value, desc->ToAttributes()),
17286 : Nothing<bool>());
17287 : }
17288 : // 3b xi. Return true.
17289 : return Just(true);
17290 : }
17291 : }
17292 : // 4. Return ! OrdinaryDefineOwnProperty(O, P, Desc).
17293 4511 : return OrdinaryDefineOwnProperty(isolate, o, key, desc, should_throw);
17294 : }
17295 :
17296 18768174 : ExternalArrayType JSTypedArray::type() {
17297 18768174 : switch (elements()->map()->instance_type()) {
17298 : #define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype, size) \
17299 : case FIXED_##TYPE##_ARRAY_TYPE: \
17300 : return kExternal##Type##Array;
17301 :
17302 5939 : TYPED_ARRAYS(INSTANCE_TYPE_TO_ARRAY_TYPE)
17303 : #undef INSTANCE_TYPE_TO_ARRAY_TYPE
17304 :
17305 : default:
17306 0 : UNREACHABLE();
17307 : return static_cast<ExternalArrayType>(-1);
17308 : }
17309 : }
17310 :
17311 :
17312 15924 : size_t JSTypedArray::element_size() {
17313 15924 : switch (elements()->map()->instance_type()) {
17314 : #define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype, size) \
17315 : case FIXED_##TYPE##_ARRAY_TYPE: \
17316 : return size;
17317 :
17318 1013 : TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE)
17319 : #undef INSTANCE_TYPE_TO_ELEMENT_SIZE
17320 :
17321 : default:
17322 0 : UNREACHABLE();
17323 : return 0;
17324 : }
17325 : }
17326 :
17327 :
17328 326473 : void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global,
17329 : Handle<Name> name) {
17330 : DCHECK(!global->HasFastProperties());
17331 : auto dictionary = handle(global->global_dictionary());
17332 326473 : int entry = dictionary->FindEntry(name);
17333 652946 : if (entry == GlobalDictionary::kNotFound) return;
17334 90 : PropertyCell::InvalidateEntry(dictionary, entry);
17335 : }
17336 :
17337 8836940 : Handle<PropertyCell> JSGlobalObject::EnsureEmptyPropertyCell(
17338 : Handle<JSGlobalObject> global, Handle<Name> name,
17339 : PropertyCellType cell_type, int* entry_out) {
17340 : Isolate* isolate = global->GetIsolate();
17341 : DCHECK(!global->HasFastProperties());
17342 : Handle<GlobalDictionary> dictionary(global->global_dictionary(), isolate);
17343 8836939 : int entry = dictionary->FindEntry(name);
17344 : Handle<PropertyCell> cell;
17345 8836938 : if (entry != GlobalDictionary::kNotFound) {
17346 6491 : if (entry_out) *entry_out = entry;
17347 : // This call should be idempotent.
17348 : DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
17349 6491 : cell = handle(PropertyCell::cast(dictionary->ValueAt(entry)));
17350 : PropertyCellType original_cell_type = cell->property_details().cell_type();
17351 : DCHECK(original_cell_type == PropertyCellType::kInvalidated ||
17352 : original_cell_type == PropertyCellType::kUninitialized);
17353 : DCHECK(cell->value()->IsTheHole(isolate));
17354 6491 : if (original_cell_type == PropertyCellType::kInvalidated) {
17355 2427 : cell = PropertyCell::InvalidateEntry(dictionary, entry);
17356 : }
17357 : PropertyDetails details(kData, NONE, 0, cell_type);
17358 : cell->set_property_details(details);
17359 6491 : return cell;
17360 : }
17361 8830447 : cell = isolate->factory()->NewPropertyCell();
17362 : PropertyDetails details(kData, NONE, 0, cell_type);
17363 : dictionary =
17364 8830445 : GlobalDictionary::Add(dictionary, name, cell, details, entry_out);
17365 : // {*entry_out} is initialized inside GlobalDictionary::Add().
17366 8830450 : global->set_properties(*dictionary);
17367 8830450 : return cell;
17368 : }
17369 :
17370 :
17371 : // This class is used for looking up two character strings in the string table.
17372 : // If we don't have a hit we don't want to waste much time so we unroll the
17373 : // string hash calculation loop here for speed. Doesn't work if the two
17374 : // characters form a decimal integer, since such strings have a different hash
17375 : // algorithm.
17376 0 : class TwoCharHashTableKey : public HashTableKey {
17377 : public:
17378 7323341 : TwoCharHashTableKey(uint16_t c1, uint16_t c2, uint32_t seed)
17379 7323341 : : c1_(c1), c2_(c2) {
17380 : // Char 1.
17381 : uint32_t hash = seed;
17382 7323341 : hash += c1;
17383 7323341 : hash += hash << 10;
17384 7323341 : hash ^= hash >> 6;
17385 : // Char 2.
17386 7323341 : hash += c2;
17387 7323341 : hash += hash << 10;
17388 7323341 : hash ^= hash >> 6;
17389 : // GetHash.
17390 7323341 : hash += hash << 3;
17391 7323341 : hash ^= hash >> 11;
17392 7323341 : hash += hash << 15;
17393 7323341 : if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash;
17394 7323341 : hash_ = hash;
17395 : #ifdef DEBUG
17396 : // If this assert fails then we failed to reproduce the two-character
17397 : // version of the string hashing algorithm above. One reason could be
17398 : // that we were passed two digits as characters, since the hash
17399 : // algorithm is different in that case.
17400 : uint16_t chars[2] = {c1, c2};
17401 : uint32_t check_hash = StringHasher::HashSequentialString(chars, 2, seed);
17402 : hash = (hash << String::kHashShift) | String::kIsNotArrayIndexMask;
17403 : DCHECK_EQ(static_cast<int32_t>(hash), static_cast<int32_t>(check_hash));
17404 : #endif
17405 7323341 : }
17406 :
17407 1729827 : bool IsMatch(Object* o) override {
17408 1729827 : if (!o->IsString()) return false;
17409 : String* other = String::cast(o);
17410 1729827 : if (other->length() != 2) return false;
17411 106029 : if (other->Get(0) != c1_) return false;
17412 22301 : return other->Get(1) == c2_;
17413 : }
17414 :
17415 7323341 : uint32_t Hash() override { return hash_; }
17416 0 : uint32_t HashForObject(Object* key) override {
17417 0 : if (!key->IsString()) return 0;
17418 0 : return String::cast(key)->Hash();
17419 : }
17420 :
17421 0 : Handle<Object> AsHandle(Isolate* isolate) override {
17422 : // The TwoCharHashTableKey is only used for looking in the string
17423 : // table, not for adding to it.
17424 0 : UNREACHABLE();
17425 : return MaybeHandle<Object>().ToHandleChecked();
17426 : }
17427 :
17428 : private:
17429 : uint16_t c1_;
17430 : uint16_t c2_;
17431 : uint32_t hash_;
17432 : };
17433 :
17434 :
17435 4262819 : MaybeHandle<String> StringTable::InternalizeStringIfExists(
17436 : Isolate* isolate,
17437 : Handle<String> string) {
17438 4262819 : if (string->IsInternalizedString()) {
17439 : return string;
17440 : }
17441 0 : if (string->IsThinString()) {
17442 : return handle(Handle<ThinString>::cast(string)->actual(), isolate);
17443 : }
17444 0 : return LookupStringIfExists(isolate, string);
17445 : }
17446 :
17447 :
17448 0 : MaybeHandle<String> StringTable::LookupStringIfExists(
17449 : Isolate* isolate,
17450 : Handle<String> string) {
17451 : Handle<StringTable> string_table = isolate->factory()->string_table();
17452 : InternalizedStringKey key(string);
17453 : int entry = string_table->FindEntry(&key);
17454 0 : if (entry == kNotFound) {
17455 : return MaybeHandle<String>();
17456 : } else {
17457 : Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
17458 : DCHECK(StringShape(*result).IsInternalized());
17459 : return result;
17460 : }
17461 : }
17462 :
17463 :
17464 7323341 : MaybeHandle<String> StringTable::LookupTwoCharsStringIfExists(
17465 : Isolate* isolate,
17466 : uint16_t c1,
17467 : uint16_t c2) {
17468 : Handle<StringTable> string_table = isolate->factory()->string_table();
17469 7323341 : TwoCharHashTableKey key(c1, c2, isolate->heap()->HashSeed());
17470 : int entry = string_table->FindEntry(&key);
17471 7323341 : if (entry == kNotFound) {
17472 : return MaybeHandle<String>();
17473 : } else {
17474 : Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
17475 : DCHECK(StringShape(*result).IsInternalized());
17476 : return result;
17477 : }
17478 : }
17479 :
17480 :
17481 385 : void StringTable::EnsureCapacityForDeserialization(Isolate* isolate,
17482 : int expected) {
17483 : Handle<StringTable> table = isolate->factory()->string_table();
17484 : // We need a key instance for the virtual hash function.
17485 : InternalizedStringKey dummy_key(isolate->factory()->empty_string());
17486 385 : table = StringTable::EnsureCapacity(table, expected, &dummy_key);
17487 : isolate->heap()->SetRootStringTable(*table);
17488 385 : }
17489 :
17490 : namespace {
17491 :
17492 : template <class StringClass>
17493 20 : void MigrateExternalStringResource(Isolate* isolate, String* from, String* to) {
17494 : StringClass* cast_from = StringClass::cast(from);
17495 : StringClass* cast_to = StringClass::cast(to);
17496 : const typename StringClass::Resource* to_resource = cast_to->resource();
17497 20 : if (to_resource == nullptr) {
17498 : // |to| is a just-created internalized copy of |from|. Migrate the resource.
17499 : cast_to->set_resource(cast_from->resource());
17500 : // Zap |from|'s resource pointer to reflect the fact that |from| has
17501 : // relinquished ownership of its resource.
17502 : cast_from->set_resource(nullptr);
17503 14 : } else if (to_resource != cast_from->resource()) {
17504 : // |to| already existed and has its own resource. Finalize |from|.
17505 : isolate->heap()->FinalizeExternalString(from);
17506 : }
17507 20 : }
17508 :
17509 9703806 : void MakeStringThin(String* string, String* internalized, Isolate* isolate) {
17510 9703812 : if (string->IsExternalString()) {
17511 20 : if (internalized->IsExternalOneByteString()) {
17512 : MigrateExternalStringResource<ExternalOneByteString>(isolate, string,
17513 11 : internalized);
17514 9 : } else if (internalized->IsExternalTwoByteString()) {
17515 : MigrateExternalStringResource<ExternalTwoByteString>(isolate, string,
17516 9 : internalized);
17517 : } else {
17518 : // If the external string is duped into an existing non-external
17519 : // internalized string, free its resource (it's about to be rewritten
17520 : // into a ThinString below).
17521 : isolate->heap()->FinalizeExternalString(string);
17522 : }
17523 : }
17524 :
17525 9703810 : if (!string->IsInternalizedString()) {
17526 : DisallowHeapAllocation no_gc;
17527 : bool one_byte = internalized->IsOneByteRepresentation();
17528 : Handle<Map> map = one_byte ? isolate->factory()->thin_one_byte_string_map()
17529 9696193 : : isolate->factory()->thin_string_map();
17530 9696193 : int old_size = string->Size();
17531 : DCHECK(old_size >= ThinString::kSize);
17532 9696193 : string->synchronized_set_map(*map);
17533 : ThinString* thin = ThinString::cast(string);
17534 9696193 : thin->set_actual(internalized);
17535 9696192 : Address thin_end = thin->address() + ThinString::kSize;
17536 9696192 : int size_delta = old_size - ThinString::kSize;
17537 9696192 : if (size_delta != 0) {
17538 2395543 : Heap* heap = isolate->heap();
17539 2395543 : heap->CreateFillerObjectAt(thin_end, size_delta, ClearRecordedSlots::kNo);
17540 2395542 : heap->AdjustLiveBytes(thin, -size_delta);
17541 : }
17542 : }
17543 9703809 : }
17544 :
17545 : } // namespace
17546 :
17547 23381586 : Handle<String> StringTable::LookupString(Isolate* isolate,
17548 : Handle<String> string) {
17549 23381588 : if (string->IsThinString()) {
17550 : DCHECK(Handle<ThinString>::cast(string)->actual()->IsInternalizedString());
17551 : return handle(Handle<ThinString>::cast(string)->actual(), isolate);
17552 : }
17553 23332717 : if (string->IsConsString() && string->IsFlat()) {
17554 : string = handle(Handle<ConsString>::cast(string)->first(), isolate);
17555 22320 : if (string->IsInternalizedString()) return string;
17556 : }
17557 :
17558 : InternalizedStringKey key(string);
17559 22836227 : Handle<String> result = LookupKey(isolate, &key);
17560 :
17561 22836230 : if (FLAG_thin_strings) {
17562 9678304 : MakeStringThin(*string, *result, isolate);
17563 : } else { // !FLAG_thin_strings
17564 13157926 : if (string->IsConsString()) {
17565 : Handle<ConsString> cons = Handle<ConsString>::cast(string);
17566 193005 : cons->set_first(*result);
17567 386010 : cons->set_second(isolate->heap()->empty_string());
17568 12964921 : } else if (string->IsSlicedString()) {
17569 : STATIC_ASSERT(ConsString::kSize == SlicedString::kSize);
17570 : DisallowHeapAllocation no_gc;
17571 : bool one_byte = result->IsOneByteRepresentation();
17572 : Handle<Map> map = one_byte
17573 : ? isolate->factory()->cons_one_byte_string_map()
17574 24792 : : isolate->factory()->cons_string_map();
17575 24792 : string->set_map(*map);
17576 : Handle<ConsString> cons = Handle<ConsString>::cast(string);
17577 24792 : cons->set_first(*result);
17578 49584 : cons->set_second(isolate->heap()->empty_string());
17579 : }
17580 : }
17581 22836231 : return result;
17582 : }
17583 :
17584 :
17585 89053511 : Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) {
17586 : Handle<StringTable> table = isolate->factory()->string_table();
17587 : int entry = table->FindEntry(key);
17588 :
17589 : // String already in table.
17590 89053558 : if (entry != kNotFound) {
17591 : return handle(String::cast(table->KeyAt(entry)), isolate);
17592 : }
17593 :
17594 : // Adding new string. Grow table if needed.
17595 13111844 : table = StringTable::EnsureCapacity(table, 1, key);
17596 :
17597 : // Create string object.
17598 13111843 : Handle<Object> string = key->AsHandle(isolate);
17599 : // There must be no attempts to internalize strings that could throw
17600 : // InvalidStringLength error.
17601 13111846 : CHECK(!string.is_null());
17602 :
17603 : // Add the new string and return it along with the string table.
17604 26223692 : entry = table->FindInsertionEntry(key->Hash());
17605 13111845 : table->set(EntryToIndex(entry), *string);
17606 13111843 : table->ElementAdded();
17607 :
17608 : isolate->heap()->SetRootStringTable(*table);
17609 : return Handle<String>::cast(string);
17610 : }
17611 :
17612 : namespace {
17613 :
17614 : class StringTableNoAllocateKey : public HashTableKey {
17615 : public:
17616 25653 : StringTableNoAllocateKey(String* string, uint32_t seed)
17617 51306 : : string_(string), length_(string->length()) {
17618 : StringShape shape(string);
17619 25653 : one_byte_ = shape.HasOnlyOneByteChars();
17620 : DCHECK(!shape.IsInternalized());
17621 : DCHECK(!shape.IsThin());
17622 25653 : if (shape.IsCons() && length_ <= String::kMaxHashCalcLength) {
17623 0 : special_flattening_ = true;
17624 : uint32_t hash_field = 0;
17625 0 : if (one_byte_) {
17626 0 : one_byte_content_ = new uint8_t[length_];
17627 0 : String::WriteToFlat(string, one_byte_content_, 0, length_);
17628 : hash_field = StringHasher::HashSequentialString(one_byte_content_,
17629 0 : length_, seed);
17630 : } else {
17631 0 : two_byte_content_ = new uint16_t[length_];
17632 0 : String::WriteToFlat(string, two_byte_content_, 0, length_);
17633 : hash_field = StringHasher::HashSequentialString(two_byte_content_,
17634 0 : length_, seed);
17635 : }
17636 : string->set_hash_field(hash_field);
17637 : } else {
17638 25653 : special_flattening_ = false;
17639 25653 : one_byte_content_ = nullptr;
17640 : }
17641 25653 : hash_ = string->Hash();
17642 25653 : }
17643 :
17644 25653 : ~StringTableNoAllocateKey() {
17645 25653 : if (one_byte_) {
17646 23349 : delete[] one_byte_content_;
17647 : } else {
17648 2304 : delete[] two_byte_content_;
17649 : }
17650 25653 : }
17651 :
17652 45282 : bool IsMatch(Object* otherstring) override {
17653 : String* other = String::cast(otherstring);
17654 : DCHECK(other->IsInternalizedString());
17655 : DCHECK(other->IsFlat());
17656 90564 : if (hash_ != other->Hash()) return false;
17657 25542 : int len = length_;
17658 25542 : if (len != other->length()) return false;
17659 :
17660 25542 : if (!special_flattening_) {
17661 51084 : if (string_->Get(0) != other->Get(0)) return false;
17662 25542 : if (string_->IsFlat()) {
17663 25542 : StringShape shape1(string_);
17664 : StringShape shape2(other);
17665 48780 : if (shape1.encoding_tag() == kOneByteStringTag &&
17666 : shape2.encoding_tag() == kOneByteStringTag) {
17667 23238 : String::FlatContent flat1 = string_->GetFlatContent();
17668 23238 : String::FlatContent flat2 = other->GetFlatContent();
17669 23238 : return CompareRawStringContents(flat1.ToOneByteVector().start(),
17670 23238 : flat2.ToOneByteVector().start(), len);
17671 : }
17672 4608 : if (shape1.encoding_tag() == kTwoByteStringTag &&
17673 : shape2.encoding_tag() == kTwoByteStringTag) {
17674 2304 : String::FlatContent flat1 = string_->GetFlatContent();
17675 2304 : String::FlatContent flat2 = other->GetFlatContent();
17676 2304 : return CompareRawStringContents(flat1.ToUC16Vector().start(),
17677 2304 : flat2.ToUC16Vector().start(), len);
17678 : }
17679 : }
17680 : StringComparator comparator;
17681 0 : return comparator.Equals(string_, other);
17682 : }
17683 :
17684 0 : String::FlatContent flat_content = other->GetFlatContent();
17685 0 : if (one_byte_) {
17686 0 : if (flat_content.IsOneByte()) {
17687 : return CompareRawStringContents(
17688 0 : one_byte_content_, flat_content.ToOneByteVector().start(), len);
17689 : } else {
17690 : DCHECK(flat_content.IsTwoByte());
17691 0 : for (int i = 0; i < len; i++) {
17692 0 : if (flat_content.Get(i) != one_byte_content_[i]) return false;
17693 : }
17694 : return true;
17695 : }
17696 : } else {
17697 0 : if (flat_content.IsTwoByte()) {
17698 : return CompareRawStringContents(
17699 0 : two_byte_content_, flat_content.ToUC16Vector().start(), len);
17700 : } else {
17701 : DCHECK(flat_content.IsOneByte());
17702 0 : for (int i = 0; i < len; i++) {
17703 0 : if (flat_content.Get(i) != two_byte_content_[i]) return false;
17704 : }
17705 : return true;
17706 : }
17707 : }
17708 : }
17709 :
17710 25653 : uint32_t Hash() override { return hash_; }
17711 :
17712 0 : uint32_t HashForObject(Object* key) override {
17713 0 : return String::cast(key)->Hash();
17714 : }
17715 :
17716 0 : MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) override {
17717 0 : UNREACHABLE();
17718 : return Handle<String>();
17719 : }
17720 :
17721 : private:
17722 : String* string_;
17723 : int length_;
17724 : bool one_byte_;
17725 : bool special_flattening_;
17726 : uint32_t hash_ = 0;
17727 : union {
17728 : uint8_t* one_byte_content_;
17729 : uint16_t* two_byte_content_;
17730 : };
17731 : };
17732 :
17733 : } // namespace
17734 :
17735 : // static
17736 25653 : Object* StringTable::LookupStringIfExists_NoAllocate(String* string) {
17737 : DisallowHeapAllocation no_gc;
17738 25653 : Heap* heap = string->GetHeap();
17739 : Isolate* isolate = heap->isolate();
17740 : StringTable* table = heap->string_table();
17741 :
17742 25653 : StringTableNoAllocateKey key(string, heap->HashSeed());
17743 :
17744 : // String could be an array index.
17745 : DCHECK(string->HasHashCode());
17746 : uint32_t hash = string->hash_field();
17747 :
17748 : // Valid array indices are >= 0, so they cannot be mixed up with any of
17749 : // the result sentinels, which are negative.
17750 : STATIC_ASSERT(
17751 : !String::ArrayIndexValueBits::is_valid(ResultSentinel::kUnsupported));
17752 : STATIC_ASSERT(
17753 : !String::ArrayIndexValueBits::is_valid(ResultSentinel::kNotFound));
17754 :
17755 25653 : if ((hash & Name::kContainsCachedArrayIndexMask) == 0) {
17756 0 : return Smi::FromInt(String::ArrayIndexValueBits::decode(hash));
17757 : }
17758 25653 : if ((hash & Name::kIsNotArrayIndexMask) == 0) {
17759 : // It is an indexed, but it's not cached.
17760 : return Smi::FromInt(ResultSentinel::kUnsupported);
17761 : }
17762 :
17763 25653 : int entry = table->FindEntry(isolate, &key, key.Hash());
17764 25653 : if (entry != kNotFound) {
17765 : String* internalized = String::cast(table->KeyAt(entry));
17766 25542 : if (FLAG_thin_strings) {
17767 25506 : MakeStringThin(string, internalized, isolate);
17768 : }
17769 25542 : return internalized;
17770 : }
17771 : // A string that's not an array index, and not in the string table,
17772 : // cannot have been used as a property name before.
17773 25653 : return Smi::FromInt(ResultSentinel::kNotFound);
17774 : }
17775 :
17776 7460 : String* StringTable::LookupKeyIfExists(Isolate* isolate, HashTableKey* key) {
17777 : Handle<StringTable> table = isolate->factory()->string_table();
17778 7460 : int entry = table->FindEntry(isolate, key);
17779 10216 : if (entry != kNotFound) return String::cast(table->KeyAt(entry));
17780 : return NULL;
17781 : }
17782 :
17783 195620 : Handle<StringSet> StringSet::New(Isolate* isolate) {
17784 195620 : return HashTable::New(isolate, 0);
17785 : }
17786 :
17787 2616962 : Handle<StringSet> StringSet::Add(Handle<StringSet> stringset,
17788 : Handle<String> name) {
17789 2616962 : if (!stringset->Has(name)) {
17790 172210 : stringset = EnsureCapacity(stringset, 1, *name);
17791 : uint32_t hash = StringSetShape::Hash(*name);
17792 172210 : int entry = stringset->FindInsertionEntry(hash);
17793 172210 : stringset->set(EntryToIndex(entry), *name);
17794 172210 : stringset->ElementAdded();
17795 : }
17796 2616962 : return stringset;
17797 : }
17798 :
17799 2636860 : bool StringSet::Has(Handle<String> name) {
17800 2636860 : return FindEntry(*name) != kNotFound;
17801 : }
17802 :
17803 16034291 : Handle<ObjectHashSet> ObjectHashSet::Add(Handle<ObjectHashSet> set,
17804 : Handle<Object> key) {
17805 : Isolate* isolate = set->GetIsolate();
17806 16034291 : int32_t hash = Object::GetOrCreateHash(isolate, key)->value();
17807 :
17808 16034291 : if (!set->Has(isolate, key, hash)) {
17809 16031980 : set = EnsureCapacity(set, 1, key);
17810 32063960 : int entry = set->FindInsertionEntry(hash);
17811 16031980 : set->set(EntryToIndex(entry), *key);
17812 16031980 : set->ElementAdded();
17813 : }
17814 16034291 : return set;
17815 : }
17816 :
17817 0 : Handle<Object> CompilationCacheTable::Lookup(Handle<String> src,
17818 : Handle<Context> context,
17819 : LanguageMode language_mode) {
17820 : Isolate* isolate = GetIsolate();
17821 : Handle<SharedFunctionInfo> shared(context->closure()->shared());
17822 : StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17823 : int entry = FindEntry(&key);
17824 0 : if (entry == kNotFound) return isolate->factory()->undefined_value();
17825 : int index = EntryToIndex(entry);
17826 0 : if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value();
17827 0 : return Handle<Object>(get(index + 1), isolate);
17828 : }
17829 :
17830 : namespace {
17831 :
17832 : const int kLiteralEntryLength = 2;
17833 : const int kLiteralInitialLength = 2;
17834 : const int kLiteralContextOffset = 0;
17835 : const int kLiteralLiteralsOffset = 1;
17836 :
17837 5183889 : int SearchLiteralsMapEntry(CompilationCacheTable* cache, int cache_entry,
17838 : Context* native_context) {
17839 : DisallowHeapAllocation no_gc;
17840 : DCHECK(native_context->IsNativeContext());
17841 : Object* obj = cache->get(cache_entry);
17842 :
17843 5183889 : if (obj->IsFixedArray()) {
17844 : FixedArray* literals_map = FixedArray::cast(obj);
17845 : int length = literals_map->length();
17846 12442549 : for (int i = 0; i < length; i += kLiteralEntryLength) {
17847 10891447 : if (WeakCell::cast(literals_map->get(i + kLiteralContextOffset))
17848 : ->value() == native_context) {
17849 : return i;
17850 : }
17851 : }
17852 : }
17853 : return -1;
17854 : }
17855 :
17856 1208386 : void AddToLiteralsMap(Handle<CompilationCacheTable> cache, int cache_entry,
17857 : Handle<Context> native_context, Handle<Cell> literals) {
17858 : Isolate* isolate = native_context->GetIsolate();
17859 : DCHECK(native_context->IsNativeContext());
17860 : STATIC_ASSERT(kLiteralEntryLength == 2);
17861 : Handle<FixedArray> new_literals_map;
17862 : int entry;
17863 :
17864 : Object* obj = cache->get(cache_entry);
17865 :
17866 1948250 : if (!obj->IsFixedArray() || FixedArray::cast(obj)->length() == 0) {
17867 : new_literals_map =
17868 468524 : isolate->factory()->NewFixedArray(kLiteralInitialLength, TENURED);
17869 : entry = 0;
17870 : } else {
17871 : Handle<FixedArray> old_literals_map(FixedArray::cast(obj), isolate);
17872 739863 : entry = SearchLiteralsMapEntry(*cache, cache_entry, *native_context);
17873 739863 : if (entry >= 0) {
17874 : // Just set the code of the entry.
17875 : Handle<WeakCell> literals_cell =
17876 1464 : isolate->factory()->NewWeakCell(literals);
17877 2928 : old_literals_map->set(entry + kLiteralLiteralsOffset, *literals_cell);
17878 1208387 : return;
17879 : }
17880 :
17881 : // Can we reuse an entry?
17882 : DCHECK(entry < 0);
17883 : int length = old_literals_map->length();
17884 2014368 : for (int i = 0; i < length; i += kLiteralEntryLength) {
17885 1359347 : if (WeakCell::cast(old_literals_map->get(i + kLiteralContextOffset))
17886 : ->cleared()) {
17887 : new_literals_map = old_literals_map;
17888 : entry = i;
17889 : break;
17890 : }
17891 : }
17892 :
17893 738399 : if (entry < 0) {
17894 : // Copy old optimized code map and append one new entry.
17895 : new_literals_map = isolate->factory()->CopyFixedArrayAndGrow(
17896 655021 : old_literals_map, kLiteralEntryLength, TENURED);
17897 : entry = old_literals_map->length();
17898 : }
17899 : }
17900 :
17901 1206923 : Handle<WeakCell> literals_cell = isolate->factory()->NewWeakCell(literals);
17902 : WeakCell* context_cell = native_context->self_weak_cell();
17903 :
17904 1206923 : new_literals_map->set(entry + kLiteralContextOffset, context_cell);
17905 2413846 : new_literals_map->set(entry + kLiteralLiteralsOffset, *literals_cell);
17906 :
17907 : #ifdef DEBUG
17908 : for (int i = 0; i < new_literals_map->length(); i += kLiteralEntryLength) {
17909 : WeakCell* cell =
17910 : WeakCell::cast(new_literals_map->get(i + kLiteralContextOffset));
17911 : DCHECK(cell->cleared() || cell->value()->IsNativeContext());
17912 : cell = WeakCell::cast(new_literals_map->get(i + kLiteralLiteralsOffset));
17913 : DCHECK(cell->cleared() || (cell->value()->IsCell()));
17914 : }
17915 : #endif
17916 :
17917 : Object* old_literals_map = cache->get(cache_entry);
17918 1206923 : if (old_literals_map != *new_literals_map) {
17919 1123545 : cache->set(cache_entry, *new_literals_map);
17920 : }
17921 : }
17922 :
17923 4444026 : Cell* SearchLiteralsMap(CompilationCacheTable* cache, int cache_entry,
17924 : Context* native_context) {
17925 : Cell* result = nullptr;
17926 4444026 : int entry = SearchLiteralsMapEntry(cache, cache_entry, native_context);
17927 4444026 : if (entry >= 0) {
17928 : FixedArray* literals_map = FixedArray::cast(cache->get(cache_entry));
17929 : DCHECK_LE(entry + kLiteralEntryLength, literals_map->length());
17930 : WeakCell* cell =
17931 3631323 : WeakCell::cast(literals_map->get(entry + kLiteralLiteralsOffset));
17932 :
17933 3631323 : result = cell->cleared() ? nullptr : Cell::cast(cell->value());
17934 : }
17935 : DCHECK(result == nullptr || result->IsCell());
17936 4444026 : return result;
17937 : }
17938 :
17939 : } // namespace
17940 :
17941 311147 : InfoVectorPair CompilationCacheTable::LookupScript(Handle<String> src,
17942 : Handle<Context> context,
17943 : LanguageMode language_mode) {
17944 : InfoVectorPair empty_result;
17945 : Handle<SharedFunctionInfo> shared(context->closure()->shared());
17946 : StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17947 : int entry = FindEntry(&key);
17948 311147 : if (entry == kNotFound) return empty_result;
17949 : int index = EntryToIndex(entry);
17950 141811 : if (!get(index)->IsFixedArray()) return empty_result;
17951 141811 : Object* obj = get(index + 1);
17952 141811 : if (obj->IsSharedFunctionInfo()) {
17953 : Cell* literals =
17954 141811 : SearchLiteralsMap(this, index + 2, context->native_context());
17955 141811 : return InfoVectorPair(SharedFunctionInfo::cast(obj), literals);
17956 : }
17957 0 : return empty_result;
17958 : }
17959 :
17960 5554356 : InfoVectorPair CompilationCacheTable::LookupEval(
17961 : Handle<String> src, Handle<SharedFunctionInfo> outer_info,
17962 : Handle<Context> native_context, LanguageMode language_mode, int position) {
17963 : InfoVectorPair empty_result;
17964 : StringSharedKey key(src, outer_info, language_mode, position);
17965 : int entry = FindEntry(&key);
17966 5554356 : if (entry == kNotFound) return empty_result;
17967 : int index = EntryToIndex(entry);
17968 4597179 : if (!get(index)->IsFixedArray()) return empty_result;
17969 4302215 : Object* obj = get(EntryToIndex(entry) + 1);
17970 4302215 : if (obj->IsSharedFunctionInfo()) {
17971 : Cell* literals =
17972 4302215 : SearchLiteralsMap(this, EntryToIndex(entry) + 2, *native_context);
17973 4302215 : return InfoVectorPair(SharedFunctionInfo::cast(obj), literals);
17974 : }
17975 0 : return empty_result;
17976 : }
17977 :
17978 1069572 : Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src,
17979 : JSRegExp::Flags flags) {
17980 : Isolate* isolate = GetIsolate();
17981 : DisallowHeapAllocation no_allocation;
17982 : RegExpKey key(src, flags);
17983 : int entry = FindEntry(&key);
17984 1782729 : if (entry == kNotFound) return isolate->factory()->undefined_value();
17985 712830 : return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
17986 : }
17987 :
17988 :
17989 0 : Handle<CompilationCacheTable> CompilationCacheTable::Put(
17990 : Handle<CompilationCacheTable> cache, Handle<String> src,
17991 : Handle<Context> context, LanguageMode language_mode, Handle<Object> value) {
17992 : Isolate* isolate = cache->GetIsolate();
17993 : Handle<SharedFunctionInfo> shared(context->closure()->shared());
17994 : StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17995 0 : Handle<Object> k = key.AsHandle(isolate);
17996 0 : cache = EnsureCapacity(cache, 1, &key);
17997 0 : int entry = cache->FindInsertionEntry(key.Hash());
17998 0 : cache->set(EntryToIndex(entry), *k);
17999 0 : cache->set(EntryToIndex(entry) + 1, *value);
18000 0 : cache->ElementAdded();
18001 0 : return cache;
18002 : }
18003 :
18004 168528 : Handle<CompilationCacheTable> CompilationCacheTable::PutScript(
18005 : Handle<CompilationCacheTable> cache, Handle<String> src,
18006 : Handle<Context> context, LanguageMode language_mode,
18007 : Handle<SharedFunctionInfo> value, Handle<Cell> literals) {
18008 : Isolate* isolate = cache->GetIsolate();
18009 : Handle<SharedFunctionInfo> shared(context->closure()->shared());
18010 : Handle<Context> native_context(context->native_context());
18011 : StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
18012 168529 : Handle<Object> k = key.AsHandle(isolate);
18013 168529 : cache = EnsureCapacity(cache, 1, &key);
18014 337058 : int entry = cache->FindInsertionEntry(key.Hash());
18015 168529 : cache->set(EntryToIndex(entry), *k);
18016 337058 : cache->set(EntryToIndex(entry) + 1, *value);
18017 168529 : AddToLiteralsMap(cache, EntryToIndex(entry) + 2, native_context, literals);
18018 168529 : cache->ElementAdded();
18019 168529 : return cache;
18020 : }
18021 :
18022 1816841 : Handle<CompilationCacheTable> CompilationCacheTable::PutEval(
18023 : Handle<CompilationCacheTable> cache, Handle<String> src,
18024 : Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value,
18025 : Handle<Context> native_context, Handle<Cell> literals, int position) {
18026 : Isolate* isolate = cache->GetIsolate();
18027 : StringSharedKey key(src, outer_info, value->language_mode(), position);
18028 : {
18029 1816841 : Handle<Object> k = key.AsHandle(isolate);
18030 : int entry = cache->FindEntry(&key);
18031 1816841 : if (entry != kNotFound) {
18032 1039858 : cache->set(EntryToIndex(entry), *k);
18033 2079716 : cache->set(EntryToIndex(entry) + 1, *value);
18034 : // AddToLiteralsMap may allocate a new sub-array to live in the entry,
18035 : // but it won't change the cache array. Therefore EntryToIndex and
18036 : // entry remains correct.
18037 : AddToLiteralsMap(cache, EntryToIndex(entry) + 2, native_context,
18038 1039858 : literals);
18039 1039858 : return cache;
18040 : }
18041 : }
18042 :
18043 776983 : cache = EnsureCapacity(cache, 1, &key);
18044 1553966 : int entry = cache->FindInsertionEntry(key.Hash());
18045 : Handle<Object> k =
18046 776983 : isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
18047 776983 : cache->set(EntryToIndex(entry), *k);
18048 : cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
18049 776983 : cache->ElementAdded();
18050 776983 : return cache;
18051 : }
18052 :
18053 :
18054 353113 : Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp(
18055 : Handle<CompilationCacheTable> cache, Handle<String> src,
18056 : JSRegExp::Flags flags, Handle<FixedArray> value) {
18057 : RegExpKey key(src, flags);
18058 353113 : cache = EnsureCapacity(cache, 1, &key);
18059 353113 : int entry = cache->FindInsertionEntry(key.Hash());
18060 : // We store the value in the key slot, and compare the search key
18061 : // to the stored value with a custon IsMatch function during lookups.
18062 353113 : cache->set(EntryToIndex(entry), *value);
18063 706226 : cache->set(EntryToIndex(entry) + 1, *value);
18064 353113 : cache->ElementAdded();
18065 353113 : return cache;
18066 : }
18067 :
18068 :
18069 19088 : void CompilationCacheTable::Age() {
18070 : DisallowHeapAllocation no_allocation;
18071 19088 : Object* the_hole_value = GetHeap()->the_hole_value();
18072 3931728 : for (int entry = 0, size = Capacity(); entry < size; entry++) {
18073 : int entry_index = EntryToIndex(entry);
18074 3893552 : int value_index = entry_index + 1;
18075 :
18076 3893552 : if (get(entry_index)->IsNumber()) {
18077 : Smi* count = Smi::cast(get(value_index));
18078 305932 : count = Smi::FromInt(count->value() - 1);
18079 305932 : if (count->value() == 0) {
18080 : NoWriteBarrierSet(this, entry_index, the_hole_value);
18081 : NoWriteBarrierSet(this, value_index, the_hole_value);
18082 264 : ElementRemoved();
18083 : } else {
18084 : NoWriteBarrierSet(this, value_index, count);
18085 : }
18086 3587620 : } else if (get(entry_index)->IsFixedArray()) {
18087 : SharedFunctionInfo* info = SharedFunctionInfo::cast(get(value_index));
18088 : bool is_old =
18089 : info->IsInterpreted()
18090 : ? info->bytecode_array()->IsOld()
18091 782694 : : info->code()->kind() != Code::FUNCTION || info->code()->IsOld();
18092 425356 : if (is_old) {
18093 14049 : for (int i = 0; i < kEntrySize; i++) {
18094 14049 : NoWriteBarrierSet(this, entry_index + i, the_hole_value);
18095 : }
18096 4683 : ElementRemoved();
18097 : }
18098 : }
18099 : }
18100 19088 : }
18101 :
18102 :
18103 0 : void CompilationCacheTable::Remove(Object* value) {
18104 : DisallowHeapAllocation no_allocation;
18105 0 : Object* the_hole_value = GetHeap()->the_hole_value();
18106 0 : for (int entry = 0, size = Capacity(); entry < size; entry++) {
18107 : int entry_index = EntryToIndex(entry);
18108 0 : int value_index = entry_index + 1;
18109 0 : if (get(value_index) == value) {
18110 0 : for (int i = 0; i < kEntrySize; i++) {
18111 0 : NoWriteBarrierSet(this, entry_index + i, the_hole_value);
18112 : }
18113 0 : ElementRemoved();
18114 : }
18115 : }
18116 0 : return;
18117 : }
18118 :
18119 : template <typename Derived, typename Shape, typename Key>
18120 2281020 : Handle<Derived> Dictionary<Derived, Shape, Key>::New(
18121 : Isolate* isolate, int at_least_space_for, PretenureFlag pretenure,
18122 : MinimumCapacity capacity_option) {
18123 : DCHECK(0 <= at_least_space_for);
18124 : Handle<Derived> dict = DerivedHashTable::New(isolate, at_least_space_for,
18125 2281020 : capacity_option, pretenure);
18126 :
18127 : // Initialize the next enumeration index.
18128 : dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
18129 2281020 : return dict;
18130 : }
18131 :
18132 : template <typename Derived, typename Shape, typename Key>
18133 284 : Handle<Derived> Dictionary<Derived, Shape, Key>::NewEmpty(
18134 : Isolate* isolate, PretenureFlag pretenure) {
18135 284 : Handle<Derived> dict = DerivedHashTable::New(isolate, 1, pretenure);
18136 : // Attempt to add one element to the empty dictionary must cause reallocation.
18137 : DCHECK(!dict->HasSufficientCapacityToAdd(1));
18138 : // Initialize the next enumeration index.
18139 : dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
18140 284 : return dict;
18141 : }
18142 :
18143 : template <typename Derived, typename Shape, typename Key>
18144 50 : void Dictionary<Derived, Shape, Key>::SetRequiresCopyOnCapacityChange() {
18145 : DCHECK_EQ(0, DerivedHashTable::NumberOfElements());
18146 : DCHECK_EQ(0, DerivedHashTable::NumberOfDeletedElements());
18147 : // Make sure that HashTable::EnsureCapacity will create a copy.
18148 : DerivedHashTable::SetNumberOfDeletedElements(DerivedHashTable::Capacity());
18149 : DCHECK(!DerivedHashTable::HasSufficientCapacityToAdd(1));
18150 50 : }
18151 :
18152 :
18153 : template <typename Derived, typename Shape, typename Key>
18154 38591409 : Handle<Derived> Dictionary<Derived, Shape, Key>::EnsureCapacity(
18155 : Handle<Derived> dictionary, int n, Key key) {
18156 : // Check whether there are enough enumeration indices to add n elements.
18157 30903219 : if (Shape::kIsEnumerable &&
18158 30903219 : !PropertyDetails::IsValidIndex(dictionary->NextEnumerationIndex() + n)) {
18159 : // If not, we generate new indices for the properties.
18160 : int length = dictionary->NumberOfElements();
18161 :
18162 0 : Handle<FixedArray> iteration_order = IterationIndices(dictionary);
18163 : DCHECK_EQ(length, iteration_order->length());
18164 :
18165 : // Iterate over the dictionary using the enumeration order and update
18166 : // the dictionary with new enumeration indices.
18167 0 : for (int i = 0; i < length; i++) {
18168 : int index = Smi::cast(iteration_order->get(i))->value();
18169 : DCHECK(dictionary->IsKey(dictionary->GetIsolate(),
18170 : dictionary->KeyAt(index)));
18171 :
18172 0 : int enum_index = PropertyDetails::kInitialIndex + i;
18173 :
18174 : PropertyDetails details = dictionary->DetailsAt(index);
18175 : PropertyDetails new_details = details.set_index(enum_index);
18176 : dictionary->DetailsAtPut(index, new_details);
18177 : }
18178 :
18179 : // Set the next enumeration index.
18180 0 : dictionary->SetNextEnumerationIndex(PropertyDetails::kInitialIndex +
18181 : length);
18182 : }
18183 38591409 : return DerivedHashTable::EnsureCapacity(dictionary, n, key);
18184 : }
18185 :
18186 :
18187 : template <typename Derived, typename Shape, typename Key>
18188 6169666 : Handle<Object> Dictionary<Derived, Shape, Key>::DeleteProperty(
18189 : Handle<Derived> dictionary, int entry) {
18190 : Factory* factory = dictionary->GetIsolate()->factory();
18191 : PropertyDetails details = dictionary->DetailsAt(entry);
18192 6169666 : if (!details.IsConfigurable()) return factory->false_value();
18193 :
18194 6169666 : dictionary->SetEntry(
18195 : entry, factory->the_hole_value(), factory->the_hole_value());
18196 6169666 : dictionary->ElementRemoved();
18197 6169666 : return factory->true_value();
18198 : }
18199 :
18200 :
18201 : template<typename Derived, typename Shape, typename Key>
18202 1897664 : Handle<Derived> Dictionary<Derived, Shape, Key>::AtPut(
18203 : Handle<Derived> dictionary, Key key, Handle<Object> value) {
18204 : int entry = dictionary->FindEntry(key);
18205 :
18206 : // If the entry is present set the value;
18207 1897664 : if (entry != Dictionary::kNotFound) {
18208 : dictionary->ValueAtPut(entry, *value);
18209 24 : return dictionary;
18210 : }
18211 :
18212 : // Check whether the dictionary should be extended.
18213 1897640 : dictionary = EnsureCapacity(dictionary, 1, key);
18214 : #ifdef DEBUG
18215 : USE(Shape::AsHandle(dictionary->GetIsolate(), key));
18216 : #endif
18217 1897640 : PropertyDetails details = PropertyDetails::Empty();
18218 :
18219 1897640 : AddEntry(dictionary, key, value, details, dictionary->Hash(key));
18220 1897640 : return dictionary;
18221 : }
18222 :
18223 : template <typename Derived, typename Shape, typename Key>
18224 36693767 : Handle<Derived> Dictionary<Derived, Shape, Key>::Add(Handle<Derived> dictionary,
18225 : Key key,
18226 : Handle<Object> value,
18227 : PropertyDetails details,
18228 : int* entry_out) {
18229 : // Valdate key is absent.
18230 : SLOW_DCHECK((dictionary->FindEntry(key) == Dictionary::kNotFound));
18231 : // Check whether the dictionary should be extended.
18232 36693767 : dictionary = EnsureCapacity(dictionary, 1, key);
18233 :
18234 36693769 : int entry = AddEntry(dictionary, key, value, details, dictionary->Hash(key));
18235 36693771 : if (entry_out) *entry_out = entry;
18236 36693771 : return dictionary;
18237 : }
18238 :
18239 : // Add a key, value pair to the dictionary. Returns entry value.
18240 : template <typename Derived, typename Shape, typename Key>
18241 38591409 : int Dictionary<Derived, Shape, Key>::AddEntry(Handle<Derived> dictionary,
18242 : Key key, Handle<Object> value,
18243 : PropertyDetails details,
18244 : uint32_t hash) {
18245 : // Compute the key object.
18246 : Handle<Object> k = Shape::AsHandle(dictionary->GetIsolate(), key);
18247 :
18248 38591409 : uint32_t entry = dictionary->FindInsertionEntry(hash);
18249 : // Insert element at empty or deleted entry
18250 30903220 : if (details.dictionary_index() == 0 && Shape::kIsEnumerable) {
18251 : // Assign an enumeration index to the property and update
18252 : // SetNextEnumerationIndex.
18253 : int index = dictionary->NextEnumerationIndex();
18254 : details = details.set_index(index);
18255 25102231 : dictionary->SetNextEnumerationIndex(index + 1);
18256 : }
18257 38591408 : dictionary->SetEntry(entry, k, value, details);
18258 : DCHECK((dictionary->KeyAt(entry)->IsNumber() ||
18259 : dictionary->KeyAt(entry)->IsName()));
18260 38591411 : dictionary->ElementAdded();
18261 38591411 : return entry;
18262 : }
18263 :
18264 4562 : bool SeededNumberDictionary::HasComplexElements() {
18265 4562 : if (!requires_slow_elements()) return false;
18266 : Isolate* isolate = this->GetIsolate();
18267 : int capacity = this->Capacity();
18268 20595 : for (int i = 0; i < capacity; i++) {
18269 : Object* k = this->KeyAt(i);
18270 17970 : if (!this->IsKey(isolate, k)) continue;
18271 : DCHECK(!IsDeleted(i));
18272 : PropertyDetails details = this->DetailsAt(i);
18273 7290 : if (details.kind() == kAccessor) return true;
18274 : PropertyAttributes attr = details.attributes();
18275 7230 : if (attr & ALL_ATTRIBUTES_MASK) return true;
18276 : }
18277 : return false;
18278 : }
18279 :
18280 6362579 : void SeededNumberDictionary::UpdateMaxNumberKey(
18281 : uint32_t key, Handle<JSObject> dictionary_holder) {
18282 : DisallowHeapAllocation no_allocation;
18283 : // If the dictionary requires slow elements an element has already
18284 : // been added at a high index.
18285 6362579 : if (requires_slow_elements()) return;
18286 : // Check if this index is high enough that we should require slow
18287 : // elements.
18288 6289015 : if (key > kRequiresSlowElementsLimit) {
18289 1586 : if (!dictionary_holder.is_null()) {
18290 1178 : dictionary_holder->RequireSlowElements(this);
18291 : }
18292 : set_requires_slow_elements();
18293 : return;
18294 : }
18295 : // Update max key value.
18296 : Object* max_index_object = get(kMaxNumberKeyIndex);
18297 6287429 : if (!max_index_object->IsSmi() || max_number_key() < key) {
18298 : FixedArray::set(kMaxNumberKeyIndex,
18299 5378819 : Smi::FromInt(key << kRequiresSlowElementsTagSize));
18300 : }
18301 : }
18302 :
18303 5776105 : Handle<SeededNumberDictionary> SeededNumberDictionary::AddNumberEntry(
18304 : Handle<SeededNumberDictionary> dictionary, uint32_t key,
18305 : Handle<Object> value, PropertyDetails details,
18306 : Handle<JSObject> dictionary_holder) {
18307 5776105 : dictionary->UpdateMaxNumberKey(key, dictionary_holder);
18308 : SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
18309 5776105 : return Add(dictionary, key, value, details);
18310 : }
18311 :
18312 :
18313 0 : Handle<UnseededNumberDictionary> UnseededNumberDictionary::AddNumberEntry(
18314 : Handle<UnseededNumberDictionary> dictionary,
18315 : uint32_t key,
18316 : Handle<Object> value) {
18317 : SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
18318 393 : return Add(dictionary, key, value, PropertyDetails::Empty());
18319 : }
18320 :
18321 0 : Handle<UnseededNumberDictionary> UnseededNumberDictionary::DeleteKey(
18322 : Handle<UnseededNumberDictionary> dictionary, uint32_t key) {
18323 : int entry = dictionary->FindEntry(key);
18324 0 : if (entry == kNotFound) return dictionary;
18325 :
18326 : Factory* factory = dictionary->GetIsolate()->factory();
18327 : dictionary->SetEntry(entry, factory->the_hole_value(),
18328 : factory->the_hole_value());
18329 0 : dictionary->ElementRemoved();
18330 0 : return dictionary->Shrink(dictionary, key);
18331 : }
18332 :
18333 586474 : Handle<SeededNumberDictionary> SeededNumberDictionary::AtNumberPut(
18334 : Handle<SeededNumberDictionary> dictionary, uint32_t key,
18335 : Handle<Object> value, Handle<JSObject> dictionary_holder) {
18336 586474 : dictionary->UpdateMaxNumberKey(key, dictionary_holder);
18337 586474 : return AtPut(dictionary, key, value);
18338 : }
18339 :
18340 60 : void SeededNumberDictionary::CopyValuesTo(FixedArray* elements) {
18341 : Isolate* isolate = this->GetIsolate();
18342 : int pos = 0;
18343 : int capacity = this->Capacity();
18344 : DisallowHeapAllocation no_gc;
18345 60 : WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
18346 1020 : for (int i = 0; i < capacity; i++) {
18347 : Object* k = this->KeyAt(i);
18348 960 : if (this->IsKey(isolate, k)) {
18349 450 : elements->set(pos++, this->ValueAt(i), mode);
18350 : }
18351 : }
18352 : DCHECK(pos == elements->length());
18353 60 : }
18354 :
18355 1311190 : Handle<UnseededNumberDictionary> UnseededNumberDictionary::AtNumberPut(
18356 : Handle<UnseededNumberDictionary> dictionary,
18357 : uint32_t key,
18358 : Handle<Object> value) {
18359 1311190 : return AtPut(dictionary, key, value);
18360 : }
18361 :
18362 39328 : Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
18363 : Handle<SeededNumberDictionary> dictionary, uint32_t key,
18364 : Handle<Object> value, PropertyDetails details,
18365 : Handle<JSObject> dictionary_holder) {
18366 : int entry = dictionary->FindEntry(key);
18367 39328 : if (entry == kNotFound) {
18368 37558 : return AddNumberEntry(dictionary, key, value, details, dictionary_holder);
18369 : }
18370 : // Preserve enumeration index.
18371 : details = details.set_index(dictionary->DetailsAt(entry).dictionary_index());
18372 : Handle<Object> object_key =
18373 : SeededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
18374 : dictionary->SetEntry(entry, object_key, value, details);
18375 1770 : return dictionary;
18376 : }
18377 :
18378 :
18379 1818 : Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
18380 : Handle<UnseededNumberDictionary> dictionary,
18381 : uint32_t key,
18382 : Handle<Object> value) {
18383 : int entry = dictionary->FindEntry(key);
18384 1818 : if (entry == kNotFound) return AddNumberEntry(dictionary, key, value);
18385 : Handle<Object> object_key =
18386 : UnseededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
18387 : dictionary->SetEntry(entry, object_key, value);
18388 1425 : return dictionary;
18389 : }
18390 :
18391 :
18392 : template <typename Derived, typename Shape, typename Key>
18393 98702 : int Dictionary<Derived, Shape, Key>::NumberOfElementsFilterAttributes(
18394 : PropertyFilter filter) {
18395 : Isolate* isolate = this->GetIsolate();
18396 : int capacity = this->Capacity();
18397 : int result = 0;
18398 10286962 : for (int i = 0; i < capacity; i++) {
18399 : Object* k = this->KeyAt(i);
18400 10188260 : if (this->IsKey(isolate, k) && !k->FilterKey(filter)) {
18401 3211028 : if (this->IsDeleted(i)) continue;
18402 : PropertyDetails details = this->DetailsAt(i);
18403 : PropertyAttributes attr = details.attributes();
18404 4505899 : if ((attr & filter) == 0) result++;
18405 : }
18406 : }
18407 98702 : return result;
18408 : }
18409 :
18410 :
18411 : template <typename Dictionary>
18412 : struct EnumIndexComparator {
18413 793630 : explicit EnumIndexComparator(Dictionary* dict) : dict(dict) {}
18414 130759320 : bool operator() (Smi* a, Smi* b) {
18415 130759320 : PropertyDetails da(dict->DetailsAt(a->value()));
18416 130759320 : PropertyDetails db(dict->DetailsAt(b->value()));
18417 130759320 : return da.dictionary_index() < db.dictionary_index();
18418 : }
18419 : Dictionary* dict;
18420 : };
18421 :
18422 : template <typename Derived, typename Shape, typename Key>
18423 97481 : void Dictionary<Derived, Shape, Key>::CopyEnumKeysTo(
18424 : Handle<Dictionary<Derived, Shape, Key>> dictionary,
18425 : Handle<FixedArray> storage, KeyCollectionMode mode,
18426 : KeyAccumulator* accumulator) {
18427 : DCHECK_IMPLIES(mode != KeyCollectionMode::kOwnOnly, accumulator != nullptr);
18428 : Isolate* isolate = dictionary->GetIsolate();
18429 : int length = storage->length();
18430 : int capacity = dictionary->Capacity();
18431 : int properties = 0;
18432 10089303 : for (int i = 0; i < capacity; i++) {
18433 : Object* key = dictionary->KeyAt(i);
18434 : bool is_shadowing_key = false;
18435 10031781 : if (!dictionary->IsKey(isolate, key)) continue;
18436 4475091 : if (key->IsSymbol()) continue;
18437 : PropertyDetails details = dictionary->DetailsAt(i);
18438 4446080 : if (details.IsDontEnum()) {
18439 1490117 : if (mode == KeyCollectionMode::kIncludePrototypes) {
18440 : is_shadowing_key = true;
18441 : } else {
18442 : continue;
18443 : }
18444 : }
18445 1682708 : if (dictionary->IsDeleted(i)) continue;
18446 2975492 : if (is_shadowing_key) {
18447 19664 : accumulator->AddShadowingKey(key);
18448 19664 : continue;
18449 : } else {
18450 : storage->set(properties, Smi::FromInt(i));
18451 : }
18452 2955828 : properties++;
18453 2955828 : if (mode == KeyCollectionMode::kOwnOnly && properties == length) break;
18454 : }
18455 :
18456 97481 : CHECK_EQ(length, properties);
18457 : DisallowHeapAllocation no_gc;
18458 : Dictionary<Derived, Shape, Key>* raw_dictionary = *dictionary;
18459 : FixedArray* raw_storage = *storage;
18460 : EnumIndexComparator<Derived> cmp(static_cast<Derived*>(*dictionary));
18461 97481 : Smi** start = reinterpret_cast<Smi**>(storage->GetFirstElementAddress());
18462 97481 : std::sort(start, start + length, cmp);
18463 3053309 : for (int i = 0; i < length; i++) {
18464 : int index = Smi::cast(raw_storage->get(i))->value();
18465 2955828 : raw_storage->set(i, raw_dictionary->KeyAt(index));
18466 : }
18467 97481 : }
18468 :
18469 : template <typename Derived, typename Shape, typename Key>
18470 629872 : Handle<FixedArray> Dictionary<Derived, Shape, Key>::IterationIndices(
18471 : Handle<Dictionary<Derived, Shape, Key>> dictionary) {
18472 : Isolate* isolate = dictionary->GetIsolate();
18473 : int capacity = dictionary->Capacity();
18474 : int length = dictionary->NumberOfElements();
18475 629872 : Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
18476 : int array_size = 0;
18477 : {
18478 : DisallowHeapAllocation no_gc;
18479 : Dictionary<Derived, Shape, Key>* raw_dict = *dictionary;
18480 21470092 : for (int i = 0; i < capacity; i++) {
18481 : Object* k = raw_dict->KeyAt(i);
18482 20840220 : if (!raw_dict->IsKey(isolate, k)) continue;
18483 5554710 : if (raw_dict->IsDeleted(i)) continue;
18484 8754904 : array->set(array_size++, Smi::FromInt(i));
18485 : }
18486 :
18487 : DCHECK_EQ(array_size, length);
18488 :
18489 : EnumIndexComparator<Derived> cmp(static_cast<Derived*>(raw_dict));
18490 629872 : Smi** start = reinterpret_cast<Smi**>(array->GetFirstElementAddress());
18491 629872 : std::sort(start, start + array_size, cmp);
18492 : }
18493 629872 : array->Shrink(array_size);
18494 629872 : return array;
18495 : }
18496 :
18497 : template <typename Derived, typename Shape, typename Key>
18498 66277 : void Dictionary<Derived, Shape, Key>::CollectKeysTo(
18499 : Handle<Dictionary<Derived, Shape, Key>> dictionary, KeyAccumulator* keys) {
18500 : Isolate* isolate = keys->isolate();
18501 : int capacity = dictionary->Capacity();
18502 : Handle<FixedArray> array =
18503 66277 : isolate->factory()->NewFixedArray(dictionary->NumberOfElements());
18504 : int array_size = 0;
18505 : PropertyFilter filter = keys->filter();
18506 : {
18507 : DisallowHeapAllocation no_gc;
18508 : Dictionary<Derived, Shape, Key>* raw_dict = *dictionary;
18509 19381873 : for (int i = 0; i < capacity; i++) {
18510 : Object* k = raw_dict->KeyAt(i);
18511 19315596 : if (!raw_dict->IsKey(isolate, k) || k->FilterKey(filter)) continue;
18512 3174296 : if (raw_dict->IsDeleted(i)) continue;
18513 : PropertyDetails details = raw_dict->DetailsAt(i);
18514 5856902 : if ((details.attributes() & filter) != 0) {
18515 636 : keys->AddShadowingKey(k);
18516 636 : continue;
18517 : }
18518 5856266 : if (filter & ONLY_ALL_CAN_READ) {
18519 409 : if (details.kind() != kAccessor) continue;
18520 31 : Object* accessors = raw_dict->ValueAt(i);
18521 31 : if (accessors->IsPropertyCell()) {
18522 : accessors = PropertyCell::cast(accessors)->value();
18523 : }
18524 31 : if (!accessors->IsAccessorInfo()) continue;
18525 31 : if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
18526 : }
18527 5855876 : array->set(array_size++, Smi::FromInt(i));
18528 : }
18529 :
18530 : EnumIndexComparator<Derived> cmp(static_cast<Derived*>(raw_dict));
18531 66277 : Smi** start = reinterpret_cast<Smi**>(array->GetFirstElementAddress());
18532 66277 : std::sort(start, start + array_size, cmp);
18533 : }
18534 :
18535 : bool has_seen_symbol = false;
18536 5922153 : for (int i = 0; i < array_size; i++) {
18537 : int index = Smi::cast(array->get(i))->value();
18538 : Object* key = dictionary->KeyAt(index);
18539 5855876 : if (key->IsSymbol()) {
18540 : has_seen_symbol = true;
18541 : continue;
18542 : }
18543 5827222 : keys->AddKey(key, DO_NOT_CONVERT);
18544 : }
18545 66277 : if (has_seen_symbol) {
18546 35075 : for (int i = 0; i < array_size; i++) {
18547 : int index = Smi::cast(array->get(i))->value();
18548 : Object* key = dictionary->KeyAt(index);
18549 35075 : if (!key->IsSymbol()) continue;
18550 28654 : keys->AddKey(key, DO_NOT_CONVERT);
18551 : }
18552 : }
18553 66277 : }
18554 :
18555 :
18556 : // Backwards lookup (slow).
18557 : template<typename Derived, typename Shape, typename Key>
18558 14 : Object* Dictionary<Derived, Shape, Key>::SlowReverseLookup(Object* value) {
18559 : Isolate* isolate = this->GetIsolate();
18560 : int capacity = this->Capacity();
18561 1806 : for (int i = 0; i < capacity; i++) {
18562 : Object* k = this->KeyAt(i);
18563 1792 : if (!this->IsKey(isolate, k)) continue;
18564 756 : Object* e = this->ValueAt(i);
18565 : // TODO(dcarney): this should be templatized.
18566 756 : if (e->IsPropertyCell()) {
18567 : e = PropertyCell::cast(e)->value();
18568 : }
18569 756 : if (e == value) return k;
18570 : }
18571 14 : return isolate->heap()->undefined_value();
18572 : }
18573 :
18574 :
18575 9158 : Object* ObjectHashTable::Lookup(Isolate* isolate, Handle<Object> key,
18576 : int32_t hash) {
18577 : DisallowHeapAllocation no_gc;
18578 : DCHECK(IsKey(isolate, *key));
18579 :
18580 9158 : int entry = FindEntry(isolate, key, hash);
18581 9158 : if (entry == kNotFound) return isolate->heap()->the_hole_value();
18582 15462 : return get(EntryToIndex(entry) + 1);
18583 : }
18584 :
18585 :
18586 7462 : Object* ObjectHashTable::Lookup(Handle<Object> key) {
18587 : DisallowHeapAllocation no_gc;
18588 :
18589 : Isolate* isolate = GetIsolate();
18590 : DCHECK(IsKey(isolate, *key));
18591 :
18592 : // If the object does not have an identity hash, it was never used as a key.
18593 7462 : Object* hash = key->GetHash();
18594 7462 : if (hash->IsUndefined(isolate)) {
18595 726 : return isolate->heap()->the_hole_value();
18596 : }
18597 6736 : return Lookup(isolate, key, Smi::cast(hash)->value());
18598 : }
18599 :
18600 0 : Object* ObjectHashTable::ValueAt(int entry) {
18601 0 : return get(EntryToValueIndex(entry));
18602 : }
18603 :
18604 2422 : Object* ObjectHashTable::Lookup(Handle<Object> key, int32_t hash) {
18605 2422 : return Lookup(GetIsolate(), key, hash);
18606 : }
18607 :
18608 :
18609 3498 : Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
18610 : Handle<Object> key,
18611 : Handle<Object> value) {
18612 : Isolate* isolate = table->GetIsolate();
18613 : DCHECK(table->IsKey(isolate, *key));
18614 : DCHECK(!value->IsTheHole(isolate));
18615 :
18616 : // Make sure the key object has an identity hash code.
18617 3498 : int32_t hash = Object::GetOrCreateHash(isolate, key)->value();
18618 :
18619 3498 : return Put(table, key, value, hash);
18620 : }
18621 :
18622 :
18623 6436 : Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
18624 : Handle<Object> key,
18625 : Handle<Object> value,
18626 : int32_t hash) {
18627 : Isolate* isolate = table->GetIsolate();
18628 : DCHECK(table->IsKey(isolate, *key));
18629 : DCHECK(!value->IsTheHole(isolate));
18630 :
18631 6436 : int entry = table->FindEntry(isolate, key, hash);
18632 :
18633 : // Key is already in table, just overwrite value.
18634 6436 : if (entry != kNotFound) {
18635 1242 : table->set(EntryToIndex(entry) + 1, *value);
18636 621 : return table;
18637 : }
18638 :
18639 : // Rehash if more than 33% of the entries are deleted entries.
18640 : // TODO(jochen): Consider to shrink the fixed array in place.
18641 11630 : if ((table->NumberOfDeletedElements() << 1) > table->NumberOfElements()) {
18642 7 : table->Rehash(isolate->factory()->undefined_value());
18643 : }
18644 : // If we're out of luck, we didn't get a GC recently, and so rehashing
18645 : // isn't enough to avoid a crash.
18646 5815 : if (!table->HasSufficientCapacityToAdd(1)) {
18647 402 : int nof = table->NumberOfElements() + 1;
18648 402 : int capacity = ObjectHashTable::ComputeCapacity(nof * 2);
18649 402 : if (capacity > ObjectHashTable::kMaxCapacity) {
18650 0 : for (size_t i = 0; i < 2; ++i) {
18651 : isolate->heap()->CollectAllGarbage(
18652 : Heap::kFinalizeIncrementalMarkingMask,
18653 0 : GarbageCollectionReason::kFullHashtable);
18654 : }
18655 0 : table->Rehash(isolate->factory()->undefined_value());
18656 : }
18657 : }
18658 :
18659 : // Check whether the hash table should be extended.
18660 5815 : table = EnsureCapacity(table, 1, key);
18661 17445 : table->AddEntry(table->FindInsertionEntry(hash), *key, *value);
18662 5815 : return table;
18663 : }
18664 :
18665 :
18666 7 : Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
18667 : Handle<Object> key,
18668 : bool* was_present) {
18669 : DCHECK(table->IsKey(table->GetIsolate(), *key));
18670 :
18671 7 : Object* hash = key->GetHash();
18672 7 : if (hash->IsUndefined(table->GetIsolate())) {
18673 0 : *was_present = false;
18674 0 : return table;
18675 : }
18676 :
18677 7 : return Remove(table, key, was_present, Smi::cast(hash)->value());
18678 : }
18679 :
18680 :
18681 125 : Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
18682 : Handle<Object> key,
18683 : bool* was_present,
18684 : int32_t hash) {
18685 : Isolate* isolate = table->GetIsolate();
18686 : DCHECK(table->IsKey(isolate, *key));
18687 :
18688 125 : int entry = table->FindEntry(isolate, key, hash);
18689 125 : if (entry == kNotFound) {
18690 0 : *was_present = false;
18691 0 : return table;
18692 : }
18693 :
18694 125 : *was_present = true;
18695 125 : table->RemoveEntry(entry);
18696 : return Shrink(table, key);
18697 : }
18698 :
18699 :
18700 5815 : void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
18701 5815 : set(EntryToIndex(entry), key);
18702 5815 : set(EntryToIndex(entry) + 1, value);
18703 5815 : ElementAdded();
18704 5815 : }
18705 :
18706 :
18707 164 : void ObjectHashTable::RemoveEntry(int entry) {
18708 164 : set_the_hole(EntryToIndex(entry));
18709 164 : set_the_hole(EntryToIndex(entry) + 1);
18710 164 : ElementRemoved();
18711 164 : }
18712 :
18713 :
18714 1050331 : Object* WeakHashTable::Lookup(Handle<HeapObject> key) {
18715 : DisallowHeapAllocation no_gc;
18716 : Isolate* isolate = GetIsolate();
18717 : DCHECK(IsKey(isolate, *key));
18718 : int entry = FindEntry(key);
18719 1050332 : if (entry == kNotFound) return isolate->heap()->the_hole_value();
18720 903083 : return get(EntryToValueIndex(entry));
18721 : }
18722 :
18723 :
18724 1050332 : Handle<WeakHashTable> WeakHashTable::Put(Handle<WeakHashTable> table,
18725 : Handle<HeapObject> key,
18726 : Handle<HeapObject> value) {
18727 : Isolate* isolate = key->GetIsolate();
18728 : DCHECK(table->IsKey(isolate, *key));
18729 : int entry = table->FindEntry(key);
18730 : // Key is already in table, just overwrite value.
18731 1050332 : if (entry != kNotFound) {
18732 903083 : table->set(EntryToValueIndex(entry), *value);
18733 903083 : return table;
18734 : }
18735 :
18736 147249 : Handle<WeakCell> key_cell = isolate->factory()->NewWeakCell(key);
18737 :
18738 : // Check whether the hash table should be extended.
18739 147249 : table = EnsureCapacity(table, 1, key, TENURED);
18740 :
18741 294498 : table->AddEntry(table->FindInsertionEntry(table->Hash(key)), key_cell, value);
18742 147249 : return table;
18743 : }
18744 :
18745 :
18746 147248 : void WeakHashTable::AddEntry(int entry, Handle<WeakCell> key_cell,
18747 : Handle<HeapObject> value) {
18748 : DisallowHeapAllocation no_allocation;
18749 147248 : set(EntryToIndex(entry), *key_cell);
18750 147249 : set(EntryToValueIndex(entry), *value);
18751 147249 : ElementAdded();
18752 147249 : }
18753 :
18754 : template <class Derived, int entrysize>
18755 10162754 : Handle<Derived> OrderedHashTable<Derived, entrysize>::Allocate(
18756 : Isolate* isolate, int capacity, PretenureFlag pretenure) {
18757 : // Capacity must be a power of two, since we depend on being able
18758 : // to divide and multiple by 2 (kLoadFactor) to derive capacity
18759 : // from number of buckets. If we decide to change kLoadFactor
18760 : // to something other than 2, capacity should be stored as another
18761 : // field of this object.
18762 10162754 : capacity = base::bits::RoundUpToPowerOfTwo32(Max(kMinCapacity, capacity));
18763 10162754 : if (capacity > kMaxCapacity) {
18764 0 : v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
18765 : }
18766 10162754 : int num_buckets = capacity / kLoadFactor;
18767 : Handle<FixedArray> backing_store = isolate->factory()->NewFixedArray(
18768 10162754 : kHashTableStartIndex + num_buckets + (capacity * kEntrySize), pretenure);
18769 : backing_store->set_map_no_write_barrier(
18770 10162755 : isolate->heap()->ordered_hash_table_map());
18771 : Handle<Derived> table = Handle<Derived>::cast(backing_store);
18772 99716207 : for (int i = 0; i < num_buckets; ++i) {
18773 : table->set(kHashTableStartIndex + i, Smi::FromInt(kNotFound));
18774 : }
18775 : table->SetNumberOfBuckets(num_buckets);
18776 : table->SetNumberOfElements(0);
18777 : table->SetNumberOfDeletedElements(0);
18778 10162755 : return table;
18779 : }
18780 :
18781 : template <class Derived, int entrysize>
18782 78478684 : Handle<Derived> OrderedHashTable<Derived, entrysize>::EnsureGrowable(
18783 : Handle<Derived> table) {
18784 : DCHECK(!table->IsObsolete());
18785 :
18786 : int nof = table->NumberOfElements();
18787 : int nod = table->NumberOfDeletedElements();
18788 : int capacity = table->Capacity();
18789 78478684 : if ((nof + nod) < capacity) return table;
18790 : // Don't need to grow if we can simply clear out deleted entries instead.
18791 : // Note that we can't compact in place, though, so we always allocate
18792 : // a new table.
18793 279167 : return Rehash(table, (nod < (capacity >> 1)) ? capacity << 1 : capacity);
18794 : }
18795 :
18796 : template <class Derived, int entrysize>
18797 202088 : Handle<Derived> OrderedHashTable<Derived, entrysize>::Shrink(
18798 : Handle<Derived> table) {
18799 : DCHECK(!table->IsObsolete());
18800 :
18801 : int nof = table->NumberOfElements();
18802 : int capacity = table->Capacity();
18803 202088 : if (nof >= (capacity >> 2)) return table;
18804 202088 : return Rehash(table, capacity / 2);
18805 : }
18806 :
18807 : template <class Derived, int entrysize>
18808 359 : Handle<Derived> OrderedHashTable<Derived, entrysize>::Clear(
18809 : Handle<Derived> table) {
18810 : DCHECK(!table->IsObsolete());
18811 :
18812 : Handle<Derived> new_table =
18813 : Allocate(table->GetIsolate(),
18814 : kMinCapacity,
18815 718 : table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
18816 :
18817 : table->SetNextTable(*new_table);
18818 : table->SetNumberOfDeletedElements(kClearedTableSentinel);
18819 :
18820 359 : return new_table;
18821 : }
18822 :
18823 : template <class Derived, int entrysize>
18824 0 : bool OrderedHashTable<Derived, entrysize>::HasKey(Handle<Derived> table,
18825 : Handle<Object> key) {
18826 : DisallowHeapAllocation no_gc;
18827 : Isolate* isolate = table->GetIsolate();
18828 : Object* raw_key = *key;
18829 0 : int entry = table->KeyToFirstEntry(isolate, raw_key);
18830 : // Walk the chain in the bucket to find the key.
18831 0 : while (entry != kNotFound) {
18832 0 : Object* candidate_key = table->KeyAt(entry);
18833 0 : if (candidate_key->SameValueZero(raw_key)) return true;
18834 0 : entry = table->NextChainEntry(entry);
18835 : }
18836 : return false;
18837 : }
18838 :
18839 :
18840 78461179 : Handle<OrderedHashSet> OrderedHashSet::Add(Handle<OrderedHashSet> table,
18841 : Handle<Object> key) {
18842 78461179 : int hash = Object::GetOrCreateHash(table->GetIsolate(), key)->value();
18843 78461175 : int entry = table->HashToEntry(hash);
18844 : // Walk the chain of the bucket and try finding the key.
18845 207439382 : while (entry != kNotFound) {
18846 50517865 : Object* candidate_key = table->KeyAt(entry);
18847 : // Do not add if we have the key already
18848 50517865 : if (candidate_key->SameValueZero(*key)) return table;
18849 50517032 : entry = table->NextChainEntry(entry);
18850 : }
18851 :
18852 78460341 : table = OrderedHashSet::EnsureGrowable(table);
18853 : // Read the existing bucket values.
18854 : int bucket = table->HashToBucket(hash);
18855 78460341 : int previous_entry = table->HashToEntry(hash);
18856 : int nof = table->NumberOfElements();
18857 : // Insert a new entry at the end,
18858 78460341 : int new_entry = nof + table->NumberOfDeletedElements();
18859 : int new_index = table->EntryToIndex(new_entry);
18860 78460341 : table->set(new_index, *key);
18861 : table->set(new_index + kChainOffset, Smi::FromInt(previous_entry));
18862 : // and point the bucket to the new entry.
18863 : table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
18864 78460341 : table->SetNumberOfElements(nof + 1);
18865 78460341 : return table;
18866 : }
18867 :
18868 9522106 : Handle<FixedArray> OrderedHashSet::ConvertToKeysArray(
18869 : Handle<OrderedHashSet> table, GetKeysConversion convert) {
18870 : Isolate* isolate = table->GetIsolate();
18871 : int length = table->NumberOfElements();
18872 : int nof_buckets = table->NumberOfBuckets();
18873 : // Convert the dictionary to a linear list.
18874 : Handle<FixedArray> result = Handle<FixedArray>::cast(table);
18875 : // From this point on table is no longer a valid OrderedHashSet.
18876 19044212 : result->set_map(isolate->heap()->fixed_array_map());
18877 87982384 : for (int i = 0; i < length; i++) {
18878 78460278 : int index = kHashTableStartIndex + nof_buckets + (i * kEntrySize);
18879 : Object* key = table->get(index);
18880 78460278 : if (convert == GetKeysConversion::kConvertToString) {
18881 : uint32_t index_value;
18882 11071871 : if (key->ToArrayIndex(&index_value)) {
18883 603298 : key = *isolate->factory()->Uint32ToString(index_value);
18884 : } else {
18885 10770222 : CHECK(key->IsName());
18886 : }
18887 : }
18888 78460278 : result->set(i, key);
18889 : }
18890 9522106 : result->Shrink(length);
18891 9522106 : return result;
18892 : }
18893 :
18894 : template <class Derived, int entrysize>
18895 481255 : Handle<Derived> OrderedHashTable<Derived, entrysize>::Rehash(
18896 : Handle<Derived> table, int new_capacity) {
18897 : Isolate* isolate = table->GetIsolate();
18898 : DCHECK(!table->IsObsolete());
18899 :
18900 : Handle<Derived> new_table =
18901 : Allocate(isolate, new_capacity,
18902 481255 : isolate->heap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
18903 : int nof = table->NumberOfElements();
18904 : int nod = table->NumberOfDeletedElements();
18905 : int new_buckets = new_table->NumberOfBuckets();
18906 : int new_entry = 0;
18907 : int removed_holes_index = 0;
18908 :
18909 : DisallowHeapAllocation no_gc;
18910 13348930 : for (int old_entry = 0; old_entry < (nof + nod); ++old_entry) {
18911 12867675 : Object* key = table->KeyAt(old_entry);
18912 12867675 : if (key->IsTheHole(isolate)) {
18913 212839 : table->SetRemovedIndexAt(removed_holes_index++, old_entry);
18914 : continue;
18915 : }
18916 :
18917 12654836 : Object* hash = key->GetHash();
18918 12654837 : int bucket = Smi::cast(hash)->value() & (new_buckets - 1);
18919 12654837 : Object* chain_entry = new_table->get(kHashTableStartIndex + bucket);
18920 : new_table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
18921 : int new_index = new_table->EntryToIndex(new_entry);
18922 : int old_index = table->EntryToIndex(old_entry);
18923 25379116 : for (int i = 0; i < entrysize; ++i) {
18924 12724279 : Object* value = table->get(old_index + i);
18925 25448558 : new_table->set(new_index + i, value);
18926 : }
18927 25309674 : new_table->set(new_index + kChainOffset, chain_entry);
18928 12654837 : ++new_entry;
18929 : }
18930 :
18931 : DCHECK_EQ(nod, removed_holes_index);
18932 :
18933 : new_table->SetNumberOfElements(nof);
18934 : table->SetNextTable(*new_table);
18935 :
18936 481255 : return new_table;
18937 : }
18938 :
18939 : template Handle<OrderedHashSet> OrderedHashTable<OrderedHashSet, 1>::Allocate(
18940 : Isolate* isolate, int capacity, PretenureFlag pretenure);
18941 :
18942 : template Handle<OrderedHashSet> OrderedHashTable<
18943 : OrderedHashSet, 1>::EnsureGrowable(Handle<OrderedHashSet> table);
18944 :
18945 : template Handle<OrderedHashSet> OrderedHashTable<OrderedHashSet, 1>::Shrink(
18946 : Handle<OrderedHashSet> table);
18947 :
18948 : template Handle<OrderedHashSet> OrderedHashTable<OrderedHashSet, 1>::Clear(
18949 : Handle<OrderedHashSet> table);
18950 :
18951 : template bool OrderedHashTable<OrderedHashSet, 1>::HasKey(
18952 : Handle<OrderedHashSet> table, Handle<Object> key);
18953 :
18954 : template Handle<OrderedHashMap> OrderedHashTable<OrderedHashMap, 2>::Allocate(
18955 : Isolate* isolate, int capacity, PretenureFlag pretenure);
18956 :
18957 : template Handle<OrderedHashMap> OrderedHashTable<
18958 : OrderedHashMap, 2>::EnsureGrowable(Handle<OrderedHashMap> table);
18959 :
18960 : template Handle<OrderedHashMap> OrderedHashTable<OrderedHashMap, 2>::Shrink(
18961 : Handle<OrderedHashMap> table);
18962 :
18963 : template Handle<OrderedHashMap> OrderedHashTable<OrderedHashMap, 2>::Clear(
18964 : Handle<OrderedHashMap> table);
18965 :
18966 : template bool OrderedHashTable<OrderedHashMap, 2>::HasKey(
18967 : Handle<OrderedHashMap> table, Handle<Object> key);
18968 :
18969 : template<class Derived, class TableType>
18970 12187 : void OrderedHashTableIterator<Derived, TableType>::Transition() {
18971 : DisallowHeapAllocation no_allocation;
18972 : TableType* table = TableType::cast(this->table());
18973 24374 : if (!table->IsObsolete()) return;
18974 :
18975 : int index = Smi::cast(this->index())->value();
18976 882 : while (table->IsObsolete()) {
18977 : TableType* next_table = table->NextTable();
18978 :
18979 490 : if (index > 0) {
18980 : int nod = table->NumberOfDeletedElements();
18981 :
18982 252 : if (nod == TableType::kClearedTableSentinel) {
18983 : index = 0;
18984 : } else {
18985 : int old_index = index;
18986 168 : for (int i = 0; i < nod; ++i) {
18987 : int removed_index = table->RemovedIndexAt(i);
18988 224 : if (removed_index >= old_index) break;
18989 168 : --index;
18990 : }
18991 : }
18992 : }
18993 :
18994 : table = next_table;
18995 : }
18996 :
18997 196 : set_table(table);
18998 196 : set_index(Smi::FromInt(index));
18999 : }
19000 :
19001 :
19002 : template<class Derived, class TableType>
19003 12283 : bool OrderedHashTableIterator<Derived, TableType>::HasMore() {
19004 : DisallowHeapAllocation no_allocation;
19005 : Isolate* isolate = this->GetIsolate();
19006 12283 : if (this->table()->IsUndefined(isolate)) return false;
19007 :
19008 12187 : Transition();
19009 :
19010 : TableType* table = TableType::cast(this->table());
19011 : int index = Smi::cast(this->index())->value();
19012 12187 : int used_capacity = table->UsedCapacity();
19013 :
19014 35607 : while (index < used_capacity && table->KeyAt(index)->IsTheHole(isolate)) {
19015 406 : index++;
19016 : }
19017 :
19018 12187 : set_index(Smi::FromInt(index));
19019 :
19020 12187 : if (index < used_capacity) return true;
19021 :
19022 1766 : set_table(isolate->heap()->undefined_value());
19023 1766 : return false;
19024 : }
19025 :
19026 :
19027 : template<class Derived, class TableType>
19028 12031 : Smi* OrderedHashTableIterator<Derived, TableType>::Next(JSArray* value_array) {
19029 : DisallowHeapAllocation no_allocation;
19030 12031 : if (HasMore()) {
19031 : FixedArray* array = FixedArray::cast(value_array->elements());
19032 10193 : static_cast<Derived*>(this)->PopulateValueArray(array);
19033 10193 : MoveNext();
19034 10193 : return Smi::cast(kind());
19035 : }
19036 : return Smi::kZero;
19037 : }
19038 :
19039 :
19040 : template Smi*
19041 : OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Next(
19042 : JSArray* value_array);
19043 :
19044 : template bool
19045 : OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::HasMore();
19046 :
19047 : template void
19048 : OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::MoveNext();
19049 :
19050 : template Object*
19051 : OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::CurrentKey();
19052 :
19053 : template void
19054 : OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Transition();
19055 :
19056 :
19057 : template Smi*
19058 : OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Next(
19059 : JSArray* value_array);
19060 :
19061 : template bool
19062 : OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::HasMore();
19063 :
19064 : template void
19065 : OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::MoveNext();
19066 :
19067 : template Object*
19068 : OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::CurrentKey();
19069 :
19070 : template void
19071 : OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Transition();
19072 :
19073 :
19074 78947 : void JSSet::Initialize(Handle<JSSet> set, Isolate* isolate) {
19075 78947 : Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
19076 78947 : set->set_table(*table);
19077 78947 : }
19078 :
19079 :
19080 45 : void JSSet::Clear(Handle<JSSet> set) {
19081 : Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()));
19082 45 : table = OrderedHashSet::Clear(table);
19083 45 : set->set_table(*table);
19084 45 : }
19085 :
19086 :
19087 80032 : void JSMap::Initialize(Handle<JSMap> map, Isolate* isolate) {
19088 80032 : Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
19089 80032 : map->set_table(*table);
19090 80032 : }
19091 :
19092 :
19093 314 : void JSMap::Clear(Handle<JSMap> map) {
19094 : Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()));
19095 314 : table = OrderedHashMap::Clear(table);
19096 314 : map->set_table(*table);
19097 314 : }
19098 :
19099 :
19100 129288 : void JSWeakCollection::Initialize(Handle<JSWeakCollection> weak_collection,
19101 : Isolate* isolate) {
19102 129288 : Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0);
19103 129288 : weak_collection->set_table(*table);
19104 129288 : }
19105 :
19106 :
19107 2938 : void JSWeakCollection::Set(Handle<JSWeakCollection> weak_collection,
19108 : Handle<Object> key, Handle<Object> value,
19109 : int32_t hash) {
19110 : DCHECK(key->IsJSReceiver() || key->IsSymbol());
19111 : Handle<ObjectHashTable> table(
19112 : ObjectHashTable::cast(weak_collection->table()));
19113 : DCHECK(table->IsKey(table->GetIsolate(), *key));
19114 : Handle<ObjectHashTable> new_table =
19115 2938 : ObjectHashTable::Put(table, key, value, hash);
19116 2938 : weak_collection->set_table(*new_table);
19117 2938 : if (*table != *new_table) {
19118 : // Zap the old table since we didn't record slots for its elements.
19119 238 : table->FillWithHoles(0, table->length());
19120 : }
19121 2938 : }
19122 :
19123 :
19124 118 : bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection,
19125 : Handle<Object> key, int32_t hash) {
19126 : DCHECK(key->IsJSReceiver() || key->IsSymbol());
19127 : Handle<ObjectHashTable> table(
19128 : ObjectHashTable::cast(weak_collection->table()));
19129 : DCHECK(table->IsKey(table->GetIsolate(), *key));
19130 118 : bool was_present = false;
19131 : Handle<ObjectHashTable> new_table =
19132 118 : ObjectHashTable::Remove(table, key, &was_present, hash);
19133 118 : weak_collection->set_table(*new_table);
19134 118 : if (*table != *new_table) {
19135 : // Zap the old table since we didn't record slots for its elements.
19136 0 : table->FillWithHoles(0, table->length());
19137 : }
19138 118 : return was_present;
19139 : }
19140 :
19141 36 : Handle<JSArray> JSWeakCollection::GetEntries(Handle<JSWeakCollection> holder,
19142 : int max_entries) {
19143 : Isolate* isolate = holder->GetIsolate();
19144 : Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
19145 36 : if (max_entries == 0 || max_entries > table->NumberOfElements()) {
19146 : max_entries = table->NumberOfElements();
19147 : }
19148 36 : int values_per_entry = holder->IsJSWeakMap() ? 2 : 1;
19149 : Handle<FixedArray> entries =
19150 36 : isolate->factory()->NewFixedArray(max_entries * values_per_entry);
19151 : // Recompute max_values because GC could have removed elements from the table.
19152 36 : if (max_entries > table->NumberOfElements()) {
19153 : max_entries = table->NumberOfElements();
19154 : }
19155 :
19156 : {
19157 : DisallowHeapAllocation no_gc;
19158 : int count = 0;
19159 120 : for (int i = 0;
19160 84 : count / values_per_entry < max_entries && i < table->Capacity(); i++) {
19161 : Handle<Object> key(table->KeyAt(i), isolate);
19162 24 : if (table->IsKey(isolate, *key)) {
19163 48 : entries->set(count++, *key);
19164 24 : if (values_per_entry > 1) {
19165 12 : Object* value = table->Lookup(key);
19166 24 : entries->set(count++, value);
19167 : }
19168 : }
19169 : }
19170 : DCHECK_EQ(max_entries * values_per_entry, count);
19171 : }
19172 36 : return isolate->factory()->NewJSArrayWithElements(entries);
19173 : }
19174 :
19175 : // Check if there is a break point at this source position.
19176 94236 : bool DebugInfo::HasBreakPoint(int source_position) {
19177 : // Get the break point info object for this code offset.
19178 94236 : Object* break_point_info = GetBreakPointInfo(source_position);
19179 :
19180 : // If there is no break point info object or no break points in the break
19181 : // point info object there is no break point at this code offset.
19182 94236 : if (break_point_info->IsUndefined(GetIsolate())) return false;
19183 5201 : return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
19184 : }
19185 :
19186 : // Get the break point info object for this source position.
19187 102246 : Object* DebugInfo::GetBreakPointInfo(int source_position) {
19188 : Isolate* isolate = GetIsolate();
19189 102246 : if (!break_points()->IsUndefined(isolate)) {
19190 840146 : for (int i = 0; i < break_points()->length(); i++) {
19191 379333 : if (!break_points()->get(i)->IsUndefined(isolate)) {
19192 : BreakPointInfo* break_point_info =
19193 : BreakPointInfo::cast(break_points()->get(i));
19194 52425 : if (break_point_info->source_position() == source_position) {
19195 : return break_point_info;
19196 : }
19197 : }
19198 : }
19199 : }
19200 91863 : return isolate->heap()->undefined_value();
19201 : }
19202 :
19203 2600 : bool DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
19204 : Handle<Object> break_point_object) {
19205 : Isolate* isolate = debug_info->GetIsolate();
19206 2600 : if (debug_info->break_points()->IsUndefined(isolate)) return false;
19207 :
19208 4292 : for (int i = 0; i < debug_info->break_points()->length(); i++) {
19209 3446 : if (debug_info->break_points()->get(i)->IsUndefined(isolate)) continue;
19210 : Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
19211 : BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
19212 3446 : if (BreakPointInfo::HasBreakPointObject(break_point_info,
19213 : break_point_object)) {
19214 2600 : BreakPointInfo::ClearBreakPoint(break_point_info, break_point_object);
19215 2600 : return true;
19216 : }
19217 : }
19218 : return false;
19219 : }
19220 :
19221 2977 : void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info, int source_position,
19222 : Handle<Object> break_point_object) {
19223 : Isolate* isolate = debug_info->GetIsolate();
19224 : Handle<Object> break_point_info(
19225 2977 : debug_info->GetBreakPointInfo(source_position), isolate);
19226 2977 : if (!break_point_info->IsUndefined(isolate)) {
19227 : BreakPointInfo::SetBreakPoint(
19228 : Handle<BreakPointInfo>::cast(break_point_info),
19229 149 : break_point_object);
19230 3126 : return;
19231 : }
19232 :
19233 : // Adding a new break point for a code offset which did not have any
19234 : // break points before. Try to find a free slot.
19235 : static const int kNoBreakPointInfo = -1;
19236 : int index = kNoBreakPointInfo;
19237 4484 : for (int i = 0; i < debug_info->break_points()->length(); i++) {
19238 3638 : if (debug_info->break_points()->get(i)->IsUndefined(isolate)) {
19239 : index = i;
19240 : break;
19241 : }
19242 : }
19243 2828 : if (index == kNoBreakPointInfo) {
19244 : // No free slot - extend break point info array.
19245 : Handle<FixedArray> old_break_points = Handle<FixedArray>(
19246 : FixedArray::cast(debug_info->break_points()), isolate);
19247 : Handle<FixedArray> new_break_points =
19248 : isolate->factory()->NewFixedArray(
19249 : old_break_points->length() +
19250 18 : DebugInfo::kEstimatedNofBreakPointsInFunction);
19251 :
19252 18 : debug_info->set_break_points(*new_break_points);
19253 180 : for (int i = 0; i < old_break_points->length(); i++) {
19254 72 : new_break_points->set(i, old_break_points->get(i));
19255 : }
19256 : index = old_break_points->length();
19257 : }
19258 : DCHECK(index != kNoBreakPointInfo);
19259 :
19260 : // Allocate new BreakPointInfo object and set the break point.
19261 : Handle<BreakPointInfo> new_break_point_info =
19262 2828 : isolate->factory()->NewBreakPointInfo(source_position);
19263 2828 : BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
19264 2828 : debug_info->break_points()->set(index, *new_break_point_info);
19265 : }
19266 :
19267 : // Get the break point objects for a source position.
19268 5033 : Handle<Object> DebugInfo::GetBreakPointObjects(int source_position) {
19269 5033 : Object* break_point_info = GetBreakPointInfo(source_position);
19270 : Isolate* isolate = GetIsolate();
19271 5033 : if (break_point_info->IsUndefined(isolate)) {
19272 0 : return isolate->factory()->undefined_value();
19273 : }
19274 : return Handle<Object>(
19275 5033 : BreakPointInfo::cast(break_point_info)->break_point_objects(), isolate);
19276 : }
19277 :
19278 :
19279 : // Get the total number of break points.
19280 3272 : int DebugInfo::GetBreakPointCount() {
19281 : Isolate* isolate = GetIsolate();
19282 3272 : if (break_points()->IsUndefined(isolate)) return 0;
19283 : int count = 0;
19284 30744 : for (int i = 0; i < break_points()->length(); i++) {
19285 13736 : if (!break_points()->get(i)->IsUndefined(isolate)) {
19286 : BreakPointInfo* break_point_info =
19287 : BreakPointInfo::cast(break_points()->get(i));
19288 5952 : count += break_point_info->GetBreakPointCount();
19289 : }
19290 : }
19291 : return count;
19292 : }
19293 :
19294 :
19295 9614 : Handle<Object> DebugInfo::FindBreakPointInfo(
19296 : Handle<DebugInfo> debug_info, Handle<Object> break_point_object) {
19297 : Isolate* isolate = debug_info->GetIsolate();
19298 9614 : if (!debug_info->break_points()->IsUndefined(isolate)) {
19299 67850 : for (int i = 0; i < debug_info->break_points()->length(); i++) {
19300 31718 : if (!debug_info->break_points()->get(i)->IsUndefined(isolate)) {
19301 : Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
19302 : BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
19303 8716 : if (BreakPointInfo::HasBreakPointObject(break_point_info,
19304 : break_point_object)) {
19305 2600 : return break_point_info;
19306 : }
19307 : }
19308 : }
19309 : }
19310 7014 : return isolate->factory()->undefined_value();
19311 : }
19312 :
19313 : // Remove the specified break point object.
19314 2600 : void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
19315 : Handle<Object> break_point_object) {
19316 : Isolate* isolate = break_point_info->GetIsolate();
19317 : // If there are no break points just ignore.
19318 2600 : if (break_point_info->break_point_objects()->IsUndefined(isolate)) return;
19319 : // If there is a single break point clear it if it is the same.
19320 2600 : if (!break_point_info->break_point_objects()->IsFixedArray()) {
19321 2428 : if (break_point_info->break_point_objects() == *break_point_object) {
19322 : break_point_info->set_break_point_objects(
19323 2428 : isolate->heap()->undefined_value());
19324 : }
19325 : return;
19326 : }
19327 : // If there are multiple break points shrink the array
19328 : DCHECK(break_point_info->break_point_objects()->IsFixedArray());
19329 : Handle<FixedArray> old_array =
19330 : Handle<FixedArray>(
19331 : FixedArray::cast(break_point_info->break_point_objects()));
19332 : Handle<FixedArray> new_array =
19333 172 : isolate->factory()->NewFixedArray(old_array->length() - 1);
19334 : int found_count = 0;
19335 1652 : for (int i = 0; i < old_array->length(); i++) {
19336 654 : if (old_array->get(i) == *break_point_object) {
19337 : DCHECK(found_count == 0);
19338 172 : found_count++;
19339 : } else {
19340 964 : new_array->set(i - found_count, old_array->get(i));
19341 : }
19342 : }
19343 : // If the break point was found in the list change it.
19344 344 : if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
19345 : }
19346 :
19347 :
19348 : // Add the specified break point object.
19349 3083 : void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
19350 : Handle<Object> break_point_object) {
19351 : Isolate* isolate = break_point_info->GetIsolate();
19352 :
19353 : // If there was no break point objects before just set it.
19354 3083 : if (break_point_info->break_point_objects()->IsUndefined(isolate)) {
19355 2934 : break_point_info->set_break_point_objects(*break_point_object);
19356 2934 : return;
19357 : }
19358 : // If the break point object is the same as before just ignore.
19359 149 : if (break_point_info->break_point_objects() == *break_point_object) return;
19360 : // If there was one break point object before replace with array.
19361 149 : if (!break_point_info->break_point_objects()->IsFixedArray()) {
19362 65 : Handle<FixedArray> array = isolate->factory()->NewFixedArray(2);
19363 65 : array->set(0, break_point_info->break_point_objects());
19364 65 : array->set(1, *break_point_object);
19365 65 : break_point_info->set_break_point_objects(*array);
19366 : return;
19367 : }
19368 : // If there was more than one break point before extend array.
19369 : Handle<FixedArray> old_array =
19370 : Handle<FixedArray>(
19371 : FixedArray::cast(break_point_info->break_point_objects()));
19372 : Handle<FixedArray> new_array =
19373 84 : isolate->factory()->NewFixedArray(old_array->length() + 1);
19374 1044 : for (int i = 0; i < old_array->length(); i++) {
19375 : // If the break point was there before just ignore.
19376 438 : if (old_array->get(i) == *break_point_object) return;
19377 438 : new_array->set(i, old_array->get(i));
19378 : }
19379 : // Add the new break point.
19380 84 : new_array->set(old_array->length(), *break_point_object);
19381 84 : break_point_info->set_break_point_objects(*new_array);
19382 : }
19383 :
19384 :
19385 12162 : bool BreakPointInfo::HasBreakPointObject(
19386 : Handle<BreakPointInfo> break_point_info,
19387 : Handle<Object> break_point_object) {
19388 : // No break point.
19389 : Isolate* isolate = break_point_info->GetIsolate();
19390 12162 : if (break_point_info->break_point_objects()->IsUndefined(isolate)) {
19391 : return false;
19392 : }
19393 : // Single break point.
19394 10524 : if (!break_point_info->break_point_objects()->IsFixedArray()) {
19395 10018 : return break_point_info->break_point_objects() == *break_point_object;
19396 : }
19397 : // Multiple break points.
19398 : FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
19399 1468 : for (int i = 0; i < array->length(); i++) {
19400 572 : if (array->get(i) == *break_point_object) {
19401 : return true;
19402 : }
19403 : }
19404 : return false;
19405 : }
19406 :
19407 :
19408 : // Get the number of break points.
19409 99917 : int BreakPointInfo::GetBreakPointCount() {
19410 : // No break point.
19411 99917 : if (break_point_objects()->IsUndefined(GetIsolate())) return 0;
19412 : // Single break point.
19413 95473 : if (!break_point_objects()->IsFixedArray()) return 1;
19414 : // Multiple break points.
19415 1217 : return FixedArray::cast(break_point_objects())->length();
19416 : }
19417 :
19418 :
19419 : // static
19420 229130 : MaybeHandle<JSDate> JSDate::New(Handle<JSFunction> constructor,
19421 : Handle<JSReceiver> new_target, double tv) {
19422 : Isolate* const isolate = constructor->GetIsolate();
19423 : Handle<JSObject> result;
19424 458260 : ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
19425 : JSObject::New(constructor, new_target), JSDate);
19426 229130 : if (-DateCache::kMaxTimeInMs <= tv && tv <= DateCache::kMaxTimeInMs) {
19427 228372 : tv = DoubleToInteger(tv) + 0.0;
19428 : } else {
19429 : tv = std::numeric_limits<double>::quiet_NaN();
19430 : }
19431 229130 : Handle<Object> value = isolate->factory()->NewNumber(tv);
19432 458260 : Handle<JSDate>::cast(result)->SetValue(*value, std::isnan(tv));
19433 : return Handle<JSDate>::cast(result);
19434 : }
19435 :
19436 :
19437 : // static
19438 28102331 : double JSDate::CurrentTimeValue(Isolate* isolate) {
19439 28102331 : if (FLAG_log_timer_events || FLAG_prof_cpp) LOG(isolate, CurrentTimeEvent());
19440 :
19441 : // According to ECMA-262, section 15.9.1, page 117, the precision of
19442 : // the number in a Date object representing a particular instant in
19443 : // time is milliseconds. Therefore, we floor the result of getting
19444 : // the OS time.
19445 : return Floor(FLAG_verify_predictable
19446 : ? isolate->heap()->MonotonicallyIncreasingTimeInMs()
19447 56204662 : : base::OS::TimeCurrentMillis());
19448 : }
19449 :
19450 :
19451 : // static
19452 17182 : Object* JSDate::GetField(Object* object, Smi* index) {
19453 : return JSDate::cast(object)->DoGetField(
19454 17182 : static_cast<FieldIndex>(index->value()));
19455 : }
19456 :
19457 :
19458 17182 : Object* JSDate::DoGetField(FieldIndex index) {
19459 : DCHECK(index != kDateValue);
19460 :
19461 25625 : DateCache* date_cache = GetIsolate()->date_cache();
19462 :
19463 17182 : if (index < kFirstUncachedField) {
19464 : Object* stamp = cache_stamp();
19465 16886 : if (stamp != date_cache->stamp() && stamp->IsSmi()) {
19466 : // Since the stamp is not NaN, the value is also not NaN.
19467 : int64_t local_time_ms =
19468 583 : date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
19469 583 : SetCachedFields(local_time_ms, date_cache);
19470 : }
19471 8443 : switch (index) {
19472 1390 : case kYear: return year();
19473 380 : case kMonth: return month();
19474 113 : case kDay: return day();
19475 0 : case kWeekday: return weekday();
19476 4887 : case kHour: return hour();
19477 1322 : case kMinute: return min();
19478 351 : case kSecond: return sec();
19479 0 : default: UNREACHABLE();
19480 : }
19481 : }
19482 :
19483 8739 : if (index >= kFirstUTCField) {
19484 8485 : return GetUTCField(index, value()->Number(), date_cache);
19485 : }
19486 :
19487 : double time = value()->Number();
19488 254 : if (std::isnan(time)) return GetIsolate()->heap()->nan_value();
19489 :
19490 169 : int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
19491 : int days = DateCache::DaysFromTime(local_time_ms);
19492 :
19493 169 : if (index == kDays) return Smi::FromInt(days);
19494 :
19495 : int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
19496 338 : if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
19497 : DCHECK(index == kTimeInDay);
19498 0 : return Smi::FromInt(time_in_day_ms);
19499 : }
19500 :
19501 :
19502 8485 : Object* JSDate::GetUTCField(FieldIndex index,
19503 : double value,
19504 : DateCache* date_cache) {
19505 : DCHECK(index >= kFirstUTCField);
19506 :
19507 16430 : if (std::isnan(value)) return GetIsolate()->heap()->nan_value();
19508 :
19509 540 : int64_t time_ms = static_cast<int64_t>(value);
19510 :
19511 540 : if (index == kTimezoneOffset) {
19512 29 : return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
19513 : }
19514 :
19515 : int days = DateCache::DaysFromTime(time_ms);
19516 :
19517 525 : if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
19518 :
19519 497 : if (index <= kDayUTC) {
19520 : int year, month, day;
19521 185 : date_cache->YearMonthDayFromDays(days, &year, &month, &day);
19522 242 : if (index == kYearUTC) return Smi::FromInt(year);
19523 184 : if (index == kMonthUTC) return Smi::FromInt(month);
19524 : DCHECK(index == kDayUTC);
19525 144 : return Smi::FromInt(day);
19526 : }
19527 :
19528 : int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
19529 312 : switch (index) {
19530 288 : case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
19531 140 : case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
19532 112 : case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
19533 84 : case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
19534 0 : case kDaysUTC: return Smi::FromInt(days);
19535 0 : case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
19536 0 : default: UNREACHABLE();
19537 : }
19538 :
19539 : UNREACHABLE();
19540 : return NULL;
19541 : }
19542 :
19543 :
19544 : // static
19545 17391 : Handle<Object> JSDate::SetValue(Handle<JSDate> date, double v) {
19546 : Isolate* const isolate = date->GetIsolate();
19547 17391 : Handle<Object> value = isolate->factory()->NewNumber(v);
19548 : bool value_is_nan = std::isnan(v);
19549 34782 : date->SetValue(*value, value_is_nan);
19550 17391 : return value;
19551 : }
19552 :
19553 :
19554 246521 : void JSDate::SetValue(Object* value, bool is_value_nan) {
19555 246521 : set_value(value);
19556 246521 : if (is_value_nan) {
19557 17376 : HeapNumber* nan = GetIsolate()->heap()->nan_value();
19558 17376 : set_cache_stamp(nan, SKIP_WRITE_BARRIER);
19559 17376 : set_year(nan, SKIP_WRITE_BARRIER);
19560 17376 : set_month(nan, SKIP_WRITE_BARRIER);
19561 17376 : set_day(nan, SKIP_WRITE_BARRIER);
19562 17376 : set_hour(nan, SKIP_WRITE_BARRIER);
19563 17376 : set_min(nan, SKIP_WRITE_BARRIER);
19564 17376 : set_sec(nan, SKIP_WRITE_BARRIER);
19565 17376 : set_weekday(nan, SKIP_WRITE_BARRIER);
19566 : } else {
19567 229145 : set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
19568 : }
19569 246521 : }
19570 :
19571 :
19572 1166 : void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) {
19573 : int days = DateCache::DaysFromTime(local_time_ms);
19574 : int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
19575 : int year, month, day;
19576 583 : date_cache->YearMonthDayFromDays(days, &year, &month, &day);
19577 : int weekday = date_cache->Weekday(days);
19578 583 : int hour = time_in_day_ms / (60 * 60 * 1000);
19579 583 : int min = (time_in_day_ms / (60 * 1000)) % 60;
19580 583 : int sec = (time_in_day_ms / 1000) % 60;
19581 583 : set_cache_stamp(date_cache->stamp());
19582 1166 : set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
19583 1166 : set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
19584 1166 : set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
19585 583 : set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
19586 583 : set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
19587 583 : set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
19588 583 : set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
19589 583 : }
19590 :
19591 : namespace {
19592 :
19593 : Script* ScriptFromJSValue(Object* in) {
19594 : DCHECK(in->IsJSValue());
19595 : JSValue* jsvalue = JSValue::cast(in);
19596 : DCHECK(jsvalue->value()->IsScript());
19597 : return Script::cast(jsvalue->value());
19598 : }
19599 :
19600 : } // namespace
19601 :
19602 13971 : int JSMessageObject::GetLineNumber() const {
19603 13971 : if (start_position() == -1) return Message::kNoLineNumberInfo;
19604 :
19605 13917 : Handle<Script> the_script = handle(ScriptFromJSValue(script()));
19606 :
19607 : Script::PositionInfo info;
19608 : const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
19609 13917 : if (!Script::GetPositionInfo(the_script, start_position(), &info,
19610 13917 : offset_flag)) {
19611 : return Message::kNoLineNumberInfo;
19612 : }
19613 :
19614 13917 : return info.line + 1;
19615 : }
19616 :
19617 24943 : int JSMessageObject::GetColumnNumber() const {
19618 24943 : if (start_position() == -1) return -1;
19619 :
19620 24889 : Handle<Script> the_script = handle(ScriptFromJSValue(script()));
19621 :
19622 : Script::PositionInfo info;
19623 : const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
19624 24889 : if (!Script::GetPositionInfo(the_script, start_position(), &info,
19625 24889 : offset_flag)) {
19626 : return -1;
19627 : }
19628 :
19629 24889 : return info.column; // Note: No '+1' in contrast to GetLineNumber.
19630 : }
19631 :
19632 11538 : Handle<String> JSMessageObject::GetSourceLine() const {
19633 : Handle<Script> the_script = handle(ScriptFromJSValue(script()));
19634 :
19635 : Isolate* isolate = the_script->GetIsolate();
19636 11538 : if (the_script->type() == Script::TYPE_WASM) {
19637 : return isolate->factory()->empty_string();
19638 : }
19639 :
19640 : Script::PositionInfo info;
19641 : const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
19642 11538 : if (!Script::GetPositionInfo(the_script, start_position(), &info,
19643 11538 : offset_flag)) {
19644 : return isolate->factory()->empty_string();
19645 : }
19646 :
19647 11538 : Handle<String> src = handle(String::cast(the_script->source()), isolate);
19648 11538 : return isolate->factory()->NewSubString(src, info.line_start, info.line_end);
19649 : }
19650 :
19651 3268 : void JSArrayBuffer::Neuter() {
19652 3268 : CHECK(is_neuterable());
19653 3268 : CHECK(is_external());
19654 : set_backing_store(NULL);
19655 3268 : set_byte_length(Smi::kZero);
19656 : set_was_neutered(true);
19657 : // Invalidate the neutering protector.
19658 : Isolate* const isolate = GetIsolate();
19659 3268 : if (isolate->IsArrayBufferNeuteringIntact()) {
19660 228 : isolate->InvalidateArrayBufferNeuteringProtector();
19661 : }
19662 3268 : }
19663 :
19664 :
19665 133519 : void JSArrayBuffer::Setup(Handle<JSArrayBuffer> array_buffer, Isolate* isolate,
19666 : bool is_external, void* data, size_t allocated_length,
19667 : SharedFlag shared) {
19668 : DCHECK(array_buffer->GetEmbedderFieldCount() ==
19669 : v8::ArrayBuffer::kEmbedderFieldCount);
19670 400557 : for (int i = 0; i < v8::ArrayBuffer::kEmbedderFieldCount; i++) {
19671 : array_buffer->SetEmbedderField(i, Smi::kZero);
19672 : }
19673 : array_buffer->set_bit_field(0);
19674 : array_buffer->set_is_external(is_external);
19675 133519 : array_buffer->set_is_neuterable(shared == SharedFlag::kNotShared);
19676 133519 : array_buffer->set_is_shared(shared == SharedFlag::kShared);
19677 :
19678 : Handle<Object> byte_length =
19679 133519 : isolate->factory()->NewNumberFromSize(allocated_length);
19680 133613 : CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
19681 133519 : array_buffer->set_byte_length(*byte_length);
19682 : // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
19683 : // are currently being constructed in the |ArrayBufferTracker|. The
19684 : // registration method below handles the case of registering a buffer that has
19685 : // already been promoted.
19686 : array_buffer->set_backing_store(data);
19687 :
19688 133519 : if (data && !is_external) {
19689 115730 : isolate->heap()->RegisterNewArrayBuffer(*array_buffer);
19690 : }
19691 133519 : }
19692 :
19693 : namespace {
19694 :
19695 : inline int ConvertToMb(size_t size) {
19696 104522 : return static_cast<int>(size / static_cast<size_t>(MB));
19697 : }
19698 :
19699 : } // namespace
19700 :
19701 121099 : bool JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer> array_buffer,
19702 330144 : Isolate* isolate,
19703 : size_t allocated_length,
19704 : bool initialize, SharedFlag shared) {
19705 : void* data;
19706 121099 : CHECK(isolate->array_buffer_allocator() != NULL);
19707 : // Prevent creating array buffers when serializing.
19708 : DCHECK(!isolate->serializer_enabled());
19709 121099 : if (allocated_length != 0) {
19710 : isolate->counters()->array_buffer_big_allocations()->AddSample(
19711 104522 : ConvertToMb(allocated_length));
19712 104522 : if (initialize) {
19713 102996 : data = isolate->array_buffer_allocator()->Allocate(allocated_length);
19714 : } else {
19715 : data = isolate->array_buffer_allocator()->AllocateUninitialized(
19716 1526 : allocated_length);
19717 : }
19718 104522 : if (data == NULL) {
19719 : isolate->counters()->array_buffer_new_size_failures()->AddSample(
19720 1 : ConvertToMb(allocated_length));
19721 1 : return false;
19722 : }
19723 : } else {
19724 : data = NULL;
19725 : }
19726 :
19727 : JSArrayBuffer::Setup(array_buffer, isolate, false, data, allocated_length,
19728 121098 : shared);
19729 121098 : return true;
19730 : }
19731 :
19732 :
19733 15528 : Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
19734 : Handle<JSTypedArray> typed_array) {
19735 :
19736 : Handle<Map> map(typed_array->map());
19737 15528 : Isolate* isolate = typed_array->GetIsolate();
19738 :
19739 : DCHECK(IsFixedTypedArrayElementsKind(map->elements_kind()));
19740 :
19741 : Handle<FixedTypedArrayBase> fixed_typed_array(
19742 : FixedTypedArrayBase::cast(typed_array->elements()));
19743 :
19744 : Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(typed_array->buffer()),
19745 : isolate);
19746 : void* backing_store =
19747 : isolate->array_buffer_allocator()->AllocateUninitialized(
19748 31056 : fixed_typed_array->DataSize());
19749 : buffer->set_is_external(false);
19750 : DCHECK(buffer->byte_length()->IsSmi() ||
19751 : buffer->byte_length()->IsHeapNumber());
19752 : DCHECK(NumberToInt32(buffer->byte_length()) == fixed_typed_array->DataSize());
19753 : // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
19754 : // are currently being constructed in the |ArrayBufferTracker|. The
19755 : // registration method below handles the case of registering a buffer that has
19756 : // already been promoted.
19757 : buffer->set_backing_store(backing_store);
19758 15528 : isolate->heap()->RegisterNewArrayBuffer(*buffer);
19759 : memcpy(buffer->backing_store(),
19760 : fixed_typed_array->DataPtr(),
19761 15528 : fixed_typed_array->DataSize());
19762 : Handle<FixedTypedArrayBase> new_elements =
19763 : isolate->factory()->NewFixedTypedArrayWithExternalPointer(
19764 : fixed_typed_array->length(), typed_array->type(),
19765 31056 : static_cast<uint8_t*>(buffer->backing_store()));
19766 :
19767 15528 : typed_array->set_elements(*new_elements);
19768 :
19769 15528 : return buffer;
19770 : }
19771 :
19772 :
19773 37463298 : Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
19774 : Handle<JSArrayBuffer> array_buffer(JSArrayBuffer::cast(buffer()),
19775 : GetIsolate());
19776 74926563 : if (array_buffer->was_neutered() ||
19777 : array_buffer->backing_store() != nullptr) {
19778 37447776 : return array_buffer;
19779 : }
19780 : Handle<JSTypedArray> self(this);
19781 15528 : return MaterializeArrayBuffer(self);
19782 : }
19783 :
19784 22497 : Handle<PropertyCell> PropertyCell::InvalidateEntry(
19785 : Handle<GlobalDictionary> dictionary, int entry) {
19786 : Isolate* isolate = dictionary->GetIsolate();
19787 : // Swap with a copy.
19788 : DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
19789 22497 : Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
19790 22497 : Handle<PropertyCell> new_cell = isolate->factory()->NewPropertyCell();
19791 22497 : new_cell->set_value(cell->value());
19792 : dictionary->ValueAtPut(entry, *new_cell);
19793 : bool is_the_hole = cell->value()->IsTheHole(isolate);
19794 : // Cell is officially mutable henceforth.
19795 : PropertyDetails details = cell->property_details();
19796 : details = details.set_cell_type(is_the_hole ? PropertyCellType::kUninitialized
19797 22497 : : PropertyCellType::kMutable);
19798 : new_cell->set_property_details(details);
19799 : // Old cell is ready for invalidation.
19800 22497 : if (is_the_hole) {
19801 19590 : cell->set_value(isolate->heap()->undefined_value());
19802 : } else {
19803 25404 : cell->set_value(isolate->heap()->the_hole_value());
19804 : }
19805 : details = details.set_cell_type(PropertyCellType::kInvalidated);
19806 : cell->set_property_details(details);
19807 : cell->dependent_code()->DeoptimizeDependentCodeGroup(
19808 22497 : isolate, DependentCode::kPropertyCellChangedGroup);
19809 22497 : return new_cell;
19810 : }
19811 :
19812 :
19813 12921 : PropertyCellConstantType PropertyCell::GetConstantType() {
19814 12921 : if (value()->IsSmi()) return PropertyCellConstantType::kSmi;
19815 2748 : return PropertyCellConstantType::kStableMap;
19816 : }
19817 :
19818 :
19819 1272645 : static bool RemainsConstantType(Handle<PropertyCell> cell,
19820 : Handle<Object> value) {
19821 : // TODO(dcarney): double->smi and smi->double transition from kConstant
19822 2451510 : if (cell->value()->IsSmi() && value->IsSmi()) {
19823 : return true;
19824 190010 : } else if (cell->value()->IsHeapObject() && value->IsHeapObject()) {
19825 : return HeapObject::cast(cell->value())->map() ==
19826 172240 : HeapObject::cast(*value)->map() &&
19827 92754 : HeapObject::cast(*value)->map()->is_stable();
19828 : }
19829 : return false;
19830 : }
19831 :
19832 :
19833 11918808 : PropertyCellType PropertyCell::UpdatedType(Handle<PropertyCell> cell,
19834 : Handle<Object> value,
19835 : PropertyDetails details) {
19836 : PropertyCellType type = details.cell_type();
19837 : Isolate* isolate = cell->GetIsolate();
19838 : DCHECK(!value->IsTheHole(isolate));
19839 11918808 : if (cell->value()->IsTheHole(isolate)) {
19840 8840745 : switch (type) {
19841 : // Only allow a cell to transition once into constant state.
19842 : case PropertyCellType::kUninitialized:
19843 8840745 : if (value->IsUndefined(isolate)) return PropertyCellType::kUndefined;
19844 7137426 : return PropertyCellType::kConstant;
19845 : case PropertyCellType::kInvalidated:
19846 : return PropertyCellType::kMutable;
19847 : default:
19848 0 : UNREACHABLE();
19849 : return PropertyCellType::kMutable;
19850 : }
19851 : }
19852 3078063 : switch (type) {
19853 : case PropertyCellType::kUndefined:
19854 : return PropertyCellType::kConstant;
19855 : case PropertyCellType::kConstant:
19856 102558 : if (*value == cell->value()) return PropertyCellType::kConstant;
19857 : // Fall through.
19858 : case PropertyCellType::kConstantType:
19859 1272645 : if (RemainsConstantType(cell, value)) {
19860 : return PropertyCellType::kConstantType;
19861 : }
19862 : // Fall through.
19863 : case PropertyCellType::kMutable:
19864 : return PropertyCellType::kMutable;
19865 : }
19866 0 : UNREACHABLE();
19867 : return PropertyCellType::kMutable;
19868 : }
19869 :
19870 3085413 : Handle<PropertyCell> PropertyCell::PrepareForValue(
19871 : Handle<GlobalDictionary> dictionary, int entry, Handle<Object> value,
19872 : PropertyDetails details) {
19873 : Isolate* isolate = dictionary->GetIsolate();
19874 : DCHECK(!value->IsTheHole(isolate));
19875 : DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
19876 3085413 : Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
19877 : const PropertyDetails original_details = cell->property_details();
19878 : // Data accesses could be cached in ics or optimized code.
19879 : bool invalidate =
19880 6169849 : original_details.kind() == kData && details.kind() == kAccessor;
19881 : int index = original_details.dictionary_index();
19882 : PropertyCellType old_type = original_details.cell_type();
19883 : // Preserve the enumeration index unless the property was deleted or never
19884 : // initialized.
19885 3085413 : if (cell->value()->IsTheHole(isolate)) {
19886 : index = dictionary->NextEnumerationIndex();
19887 7350 : dictionary->SetNextEnumerationIndex(index + 1);
19888 : }
19889 : DCHECK(index > 0);
19890 : details = details.set_index(index);
19891 :
19892 3085413 : PropertyCellType new_type = UpdatedType(cell, value, original_details);
19893 3085413 : if (invalidate) cell = PropertyCell::InvalidateEntry(dictionary, entry);
19894 :
19895 : // Install new property details.
19896 : details = details.set_cell_type(new_type);
19897 : cell->set_property_details(details);
19898 :
19899 : // Deopt when transitioning from a constant type.
19900 4504478 : if (!invalidate && (old_type != new_type ||
19901 : original_details.IsReadOnly() != details.IsReadOnly())) {
19902 : cell->dependent_code()->DeoptimizeDependentCodeGroup(
19903 1670051 : isolate, DependentCode::kPropertyCellChangedGroup);
19904 : }
19905 3085413 : return cell;
19906 : }
19907 :
19908 :
19909 : // static
19910 1018 : void PropertyCell::SetValueWithInvalidation(Handle<PropertyCell> cell,
19911 : Handle<Object> new_value) {
19912 1018 : if (cell->value() != *new_value) {
19913 1018 : cell->set_value(*new_value);
19914 : Isolate* isolate = cell->GetIsolate();
19915 : cell->dependent_code()->DeoptimizeDependentCodeGroup(
19916 1018 : isolate, DependentCode::kPropertyCellChangedGroup);
19917 : }
19918 1018 : }
19919 :
19920 42 : int JSGeneratorObject::source_position() const {
19921 42 : CHECK(is_suspended());
19922 : DCHECK(function()->shared()->HasBytecodeArray());
19923 : DCHECK(!function()->shared()->HasBaselineCode());
19924 :
19925 : int code_offset;
19926 : const JSAsyncGeneratorObject* async =
19927 42 : IsJSAsyncGeneratorObject() ? JSAsyncGeneratorObject::cast(this) : nullptr;
19928 42 : if (async != nullptr && async->awaited_promise()->IsJSPromise()) {
19929 : code_offset = Smi::cast(async->await_input_or_debug_pos())->value();
19930 : } else {
19931 : code_offset = Smi::cast(input_or_debug_pos())->value();
19932 : }
19933 :
19934 : // The stored bytecode offset is relative to a different base than what
19935 : // is used in the source position table, hence the subtraction.
19936 42 : code_offset -= BytecodeArray::kHeaderSize - kHeapObjectTag;
19937 : AbstractCode* code =
19938 : AbstractCode::cast(function()->shared()->bytecode_array());
19939 42 : return code->SourcePosition(code_offset);
19940 : }
19941 :
19942 : // static
19943 5978 : AccessCheckInfo* AccessCheckInfo::Get(Isolate* isolate,
19944 : Handle<JSObject> receiver) {
19945 : DisallowHeapAllocation no_gc;
19946 : DCHECK(receiver->map()->is_access_check_needed());
19947 5978 : Object* maybe_constructor = receiver->map()->GetConstructor();
19948 5978 : if (maybe_constructor->IsFunctionTemplateInfo()) {
19949 : Object* data_obj =
19950 : FunctionTemplateInfo::cast(maybe_constructor)->access_check_info();
19951 203 : if (data_obj->IsUndefined(isolate)) return nullptr;
19952 203 : return AccessCheckInfo::cast(data_obj);
19953 : }
19954 : // Might happen for a detached context.
19955 5775 : if (!maybe_constructor->IsJSFunction()) return nullptr;
19956 : JSFunction* constructor = JSFunction::cast(maybe_constructor);
19957 : // Might happen for the debug context.
19958 5743 : if (!constructor->shared()->IsApiFunction()) return nullptr;
19959 :
19960 : Object* data_obj =
19961 : constructor->shared()->get_api_func_data()->access_check_info();
19962 5206 : if (data_obj->IsUndefined(isolate)) return nullptr;
19963 :
19964 4373 : return AccessCheckInfo::cast(data_obj);
19965 : }
19966 :
19967 6145 : bool JSReceiver::HasProxyInPrototype(Isolate* isolate) {
19968 25300 : for (PrototypeIterator iter(isolate, this, kStartAtReceiver,
19969 : PrototypeIterator::END_AT_NULL);
19970 19155 : !iter.IsAtEnd(); iter.AdvanceIgnoringProxies()) {
19971 38396 : if (iter.GetCurrent<Object>()->IsJSProxy()) return true;
19972 : }
19973 6102 : return false;
19974 : }
19975 :
19976 853 : MaybeHandle<Object> JSModuleNamespace::GetExport(Handle<String> name) {
19977 : Isolate* isolate = name->GetIsolate();
19978 :
19979 1706 : Handle<Object> object(module()->exports()->Lookup(name), isolate);
19980 853 : if (object->IsTheHole(isolate)) {
19981 : return isolate->factory()->undefined_value();
19982 : }
19983 :
19984 : Handle<Object> value(Handle<Cell>::cast(object)->value(), isolate);
19985 853 : if (value->IsTheHole(isolate)) {
19986 210 : THROW_NEW_ERROR(
19987 : isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object);
19988 : }
19989 :
19990 : return value;
19991 : }
19992 :
19993 : namespace {
19994 :
19995 : struct ModuleHandleHash {
19996 : V8_INLINE size_t operator()(Handle<Module> module) const {
19997 732 : return module->hash();
19998 : }
19999 : };
20000 :
20001 : struct ModuleHandleEqual {
20002 : V8_INLINE bool operator()(Handle<Module> lhs, Handle<Module> rhs) const {
20003 : return *lhs == *rhs;
20004 : }
20005 : };
20006 :
20007 : struct StringHandleHash {
20008 : V8_INLINE size_t operator()(Handle<String> string) const {
20009 552 : return string->Hash();
20010 : }
20011 : };
20012 :
20013 : struct StringHandleEqual {
20014 : V8_INLINE bool operator()(Handle<String> lhs, Handle<String> rhs) const {
20015 45 : return lhs->Equals(*rhs);
20016 : }
20017 : };
20018 :
20019 : class UnorderedStringSet
20020 : : public std::unordered_set<Handle<String>, StringHandleHash,
20021 : StringHandleEqual,
20022 : ZoneAllocator<Handle<String>>> {
20023 : public:
20024 314 : explicit UnorderedStringSet(Zone* zone)
20025 : : std::unordered_set<Handle<String>, StringHandleHash, StringHandleEqual,
20026 : ZoneAllocator<Handle<String>>>(
20027 : 2 /* bucket count */, StringHandleHash(), StringHandleEqual(),
20028 314 : ZoneAllocator<Handle<String>>(zone)) {}
20029 : };
20030 :
20031 : class UnorderedModuleSet
20032 : : public std::unordered_set<Handle<Module>, ModuleHandleHash,
20033 : ModuleHandleEqual,
20034 : ZoneAllocator<Handle<Module>>> {
20035 : public:
20036 300 : explicit UnorderedModuleSet(Zone* zone)
20037 : : std::unordered_set<Handle<Module>, ModuleHandleHash, ModuleHandleEqual,
20038 : ZoneAllocator<Handle<Module>>>(
20039 : 2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(),
20040 300 : ZoneAllocator<Handle<Module>>(zone)) {}
20041 : };
20042 :
20043 : class UnorderedStringMap
20044 : : public std::unordered_map<
20045 : Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual,
20046 : ZoneAllocator<std::pair<const Handle<String>, Handle<Object>>>> {
20047 : public:
20048 388 : explicit UnorderedStringMap(Zone* zone)
20049 : : std::unordered_map<
20050 : Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual,
20051 : ZoneAllocator<std::pair<const Handle<String>, Handle<Object>>>>(
20052 : 2 /* bucket count */, StringHandleHash(), StringHandleEqual(),
20053 : ZoneAllocator<std::pair<const Handle<String>, Handle<Object>>>(
20054 388 : zone)) {}
20055 : };
20056 :
20057 : } // anonymous namespace
20058 :
20059 : class Module::ResolveSet
20060 : : public std::unordered_map<
20061 : Handle<Module>, UnorderedStringSet*, ModuleHandleHash,
20062 : ModuleHandleEqual,
20063 : ZoneAllocator<std::pair<const Handle<Module>, UnorderedStringSet*>>> {
20064 : public:
20065 1077 : explicit ResolveSet(Zone* zone)
20066 : : std::unordered_map<Handle<Module>, UnorderedStringSet*,
20067 : ModuleHandleHash, ModuleHandleEqual,
20068 : ZoneAllocator<std::pair<const Handle<Module>,
20069 : UnorderedStringSet*>>>(
20070 : 2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(),
20071 : ZoneAllocator<std::pair<const Handle<Module>, UnorderedStringSet*>>(
20072 : zone)),
20073 1077 : zone_(zone) {}
20074 :
20075 : Zone* zone() const { return zone_; }
20076 :
20077 : private:
20078 : Zone* zone_;
20079 : };
20080 :
20081 : namespace {
20082 :
20083 : int ExportIndex(int cell_index) {
20084 : DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
20085 : ModuleDescriptor::kExport);
20086 2060 : return cell_index - 1;
20087 : }
20088 :
20089 : int ImportIndex(int cell_index) {
20090 : DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
20091 : ModuleDescriptor::kImport);
20092 991 : return -cell_index - 1;
20093 : }
20094 :
20095 : } // anonymous namespace
20096 :
20097 180 : void Module::CreateIndirectExport(Handle<Module> module, Handle<String> name,
20098 : Handle<ModuleInfoEntry> entry) {
20099 : Isolate* isolate = module->GetIsolate();
20100 : Handle<ObjectHashTable> exports(module->exports(), isolate);
20101 : DCHECK(exports->Lookup(name)->IsTheHole(isolate));
20102 180 : exports = ObjectHashTable::Put(exports, name, entry);
20103 180 : module->set_exports(*exports);
20104 180 : }
20105 :
20106 1976 : void Module::CreateExport(Handle<Module> module, int cell_index,
20107 : Handle<FixedArray> names) {
20108 : DCHECK_LT(0, names->length());
20109 : Isolate* isolate = module->GetIsolate();
20110 :
20111 : Handle<Cell> cell =
20112 1976 : isolate->factory()->NewCell(isolate->factory()->undefined_value());
20113 1976 : module->regular_exports()->set(ExportIndex(cell_index), *cell);
20114 :
20115 : Handle<ObjectHashTable> exports(module->exports(), isolate);
20116 4147 : for (int i = 0, n = names->length(); i < n; ++i) {
20117 : Handle<String> name(String::cast(names->get(i)), isolate);
20118 : DCHECK(exports->Lookup(name)->IsTheHole(isolate));
20119 2171 : exports = ObjectHashTable::Put(exports, name, cell);
20120 : }
20121 1976 : module->set_exports(*exports);
20122 1976 : }
20123 :
20124 192 : Handle<Object> Module::LoadVariable(Handle<Module> module, int cell_index) {
20125 : Isolate* isolate = module->GetIsolate();
20126 : Handle<Object> object;
20127 192 : switch (ModuleDescriptor::GetCellIndexKind(cell_index)) {
20128 : case ModuleDescriptor::kImport:
20129 : object = handle(module->regular_imports()->get(ImportIndex(cell_index)),
20130 : isolate);
20131 108 : break;
20132 : case ModuleDescriptor::kExport:
20133 : object = handle(module->regular_exports()->get(ExportIndex(cell_index)),
20134 : isolate);
20135 84 : break;
20136 : case ModuleDescriptor::kInvalid:
20137 0 : UNREACHABLE();
20138 : break;
20139 : }
20140 192 : return handle(Handle<Cell>::cast(object)->value(), isolate);
20141 : }
20142 :
20143 0 : void Module::StoreVariable(Handle<Module> module, int cell_index,
20144 : Handle<Object> value) {
20145 : Isolate* isolate = module->GetIsolate();
20146 : DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
20147 : ModuleDescriptor::kExport);
20148 : Handle<Object> object(module->regular_exports()->get(ExportIndex(cell_index)),
20149 : isolate);
20150 0 : Handle<Cell>::cast(object)->set_value(*value);
20151 0 : }
20152 :
20153 1227 : MaybeHandle<Cell> Module::ResolveImport(Handle<Module> module,
20154 : Handle<String> name, int module_request,
20155 : MessageLocation loc, bool must_resolve,
20156 : Module::ResolveSet* resolve_set) {
20157 : Isolate* isolate = module->GetIsolate();
20158 : Handle<Module> requested_module(
20159 : Module::cast(module->requested_modules()->get(module_request)), isolate);
20160 : return Module::ResolveExport(requested_module, name, loc, must_resolve,
20161 1227 : resolve_set);
20162 : }
20163 :
20164 1407 : MaybeHandle<Cell> Module::ResolveExport(Handle<Module> module,
20165 : Handle<String> name,
20166 : MessageLocation loc, bool must_resolve,
20167 314 : Module::ResolveSet* resolve_set) {
20168 : DCHECK_EQ(module->status(), kPrepared);
20169 : Isolate* isolate = module->GetIsolate();
20170 2814 : Handle<Object> object(module->exports()->Lookup(name), isolate);
20171 1407 : if (object->IsCell()) {
20172 : // Already resolved (e.g. because it's a local export).
20173 : return Handle<Cell>::cast(object);
20174 : }
20175 :
20176 : // Check for cycle before recursing.
20177 : {
20178 : // Attempt insertion with a null string set.
20179 329 : auto result = resolve_set->insert({module, nullptr});
20180 : UnorderedStringSet*& name_set = result.first->second;
20181 329 : if (result.second) {
20182 : // |module| wasn't in the map previously, so allocate a new name set.
20183 : Zone* zone = resolve_set->zone();
20184 : name_set =
20185 314 : new (zone->New(sizeof(UnorderedStringSet))) UnorderedStringSet(zone);
20186 30 : } else if (name_set->count(name)) {
20187 : // Cycle detected.
20188 15 : if (must_resolve) {
20189 : return isolate->Throw<Cell>(
20190 : isolate->factory()->NewSyntaxError(
20191 : MessageTemplate::kCyclicModuleDependency, name),
20192 0 : &loc);
20193 : }
20194 : return MaybeHandle<Cell>();
20195 : }
20196 314 : name_set->insert(name);
20197 : }
20198 :
20199 314 : if (object->IsModuleInfoEntry()) {
20200 : // Not yet resolved indirect export.
20201 : Handle<ModuleInfoEntry> entry = Handle<ModuleInfoEntry>::cast(object);
20202 : Handle<String> import_name(String::cast(entry->import_name()), isolate);
20203 : Handle<Script> script(
20204 : Script::cast(JSFunction::cast(module->code())->shared()->script()),
20205 : isolate);
20206 180 : MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos());
20207 :
20208 : Handle<Cell> cell;
20209 180 : if (!ResolveImport(module, import_name, entry->module_request(), new_loc,
20210 : true, resolve_set)
20211 360 : .ToHandle(&cell)) {
20212 : DCHECK(isolate->has_pending_exception());
20213 : return MaybeHandle<Cell>();
20214 : }
20215 :
20216 : // The export table may have changed but the entry in question should be
20217 : // unchanged.
20218 : Handle<ObjectHashTable> exports(module->exports(), isolate);
20219 : DCHECK(exports->Lookup(name)->IsModuleInfoEntry());
20220 :
20221 180 : exports = ObjectHashTable::Put(exports, name, cell);
20222 180 : module->set_exports(*exports);
20223 : return cell;
20224 : }
20225 :
20226 : DCHECK(object->IsTheHole(isolate));
20227 : return Module::ResolveExportUsingStarExports(module, name, loc, must_resolve,
20228 134 : resolve_set);
20229 : }
20230 :
20231 134 : MaybeHandle<Cell> Module::ResolveExportUsingStarExports(
20232 : Handle<Module> module, Handle<String> name, MessageLocation loc,
20233 : bool must_resolve, Module::ResolveSet* resolve_set) {
20234 : Isolate* isolate = module->GetIsolate();
20235 268 : if (!name->Equals(isolate->heap()->default_string())) {
20236 : // Go through all star exports looking for the given name. If multiple star
20237 : // exports provide the name, make sure they all map it to the same cell.
20238 : Handle<Cell> unique_cell;
20239 : Handle<FixedArray> special_exports(module->info()->special_exports(),
20240 120 : isolate);
20241 360 : for (int i = 0, n = special_exports->length(); i < n; ++i) {
20242 : i::Handle<i::ModuleInfoEntry> entry(
20243 : i::ModuleInfoEntry::cast(special_exports->get(i)), isolate);
20244 240 : if (!entry->export_name()->IsUndefined(isolate)) {
20245 90 : continue; // Indirect export.
20246 : }
20247 :
20248 : Handle<Script> script(
20249 : Script::cast(JSFunction::cast(module->code())->shared()->script()),
20250 : isolate);
20251 150 : MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos());
20252 :
20253 : Handle<Cell> cell;
20254 150 : if (ResolveImport(module, name, entry->module_request(), new_loc, false,
20255 : resolve_set)
20256 300 : .ToHandle(&cell)) {
20257 90 : if (unique_cell.is_null()) unique_cell = cell;
20258 90 : if (*unique_cell != *cell) {
20259 : return isolate->Throw<Cell>(
20260 : isolate->factory()->NewSyntaxError(
20261 : MessageTemplate::kAmbiguousExport, name),
20262 0 : &loc);
20263 : }
20264 60 : } else if (isolate->has_pending_exception()) {
20265 : return MaybeHandle<Cell>();
20266 : }
20267 : }
20268 :
20269 120 : if (!unique_cell.is_null()) {
20270 : // Found a unique star export for this name.
20271 : Handle<ObjectHashTable> exports(module->exports(), isolate);
20272 : DCHECK(exports->Lookup(name)->IsTheHole(isolate));
20273 75 : exports = ObjectHashTable::Put(exports, name, unique_cell);
20274 75 : module->set_exports(*exports);
20275 : return unique_cell;
20276 : }
20277 : }
20278 :
20279 : // Unresolvable.
20280 59 : if (must_resolve) {
20281 : return isolate->Throw<Cell>(isolate->factory()->NewSyntaxError(
20282 : MessageTemplate::kUnresolvableExport, name),
20283 28 : &loc);
20284 : }
20285 : return MaybeHandle<Cell>();
20286 : }
20287 :
20288 1216 : bool Module::Instantiate(Handle<Module> module, v8::Local<v8::Context> context,
20289 : v8::Module::ResolveCallback callback) {
20290 2418 : return PrepareInstantiate(module, context, callback) &&
20291 2418 : FinishInstantiate(module, context);
20292 : }
20293 :
20294 2362 : bool Module::PrepareInstantiate(Handle<Module> module,
20295 : v8::Local<v8::Context> context,
20296 : v8::Module::ResolveCallback callback) {
20297 2362 : if (module->status() == kPrepared) return true;
20298 :
20299 : // Obtain requested modules.
20300 : Isolate* isolate = module->GetIsolate();
20301 1917 : Handle<ModuleInfo> module_info(module->info(), isolate);
20302 : Handle<FixedArray> module_requests(module_info->module_requests(), isolate);
20303 : Handle<FixedArray> requested_modules(module->requested_modules(), isolate);
20304 3070 : for (int i = 0, length = module_requests->length(); i < length; ++i) {
20305 : Handle<String> specifier(String::cast(module_requests->get(i)), isolate);
20306 : v8::Local<v8::Module> api_requested_module;
20307 1167 : if (!callback(context, v8::Utils::ToLocal(specifier),
20308 : v8::Utils::ToLocal(module))
20309 2334 : .ToLocal(&api_requested_module)) {
20310 14 : isolate->PromoteScheduledException();
20311 : return false;
20312 : }
20313 : Handle<Module> requested_module = Utils::OpenHandle(*api_requested_module);
20314 1153 : requested_modules->set(i, *requested_module);
20315 : }
20316 :
20317 : // Recurse.
20318 : module->set_status(kPrepared);
20319 3049 : for (int i = 0, length = requested_modules->length(); i < length; ++i) {
20320 : Handle<Module> requested_module(Module::cast(requested_modules->get(i)),
20321 : isolate);
20322 1146 : if (!PrepareInstantiate(requested_module, context, callback)) return false;
20323 : }
20324 :
20325 : // Set up local exports.
20326 : // TODO(neis): Create regular_exports array here instead of in factory method?
20327 3879 : for (int i = 0, n = module_info->RegularExportCount(); i < n; ++i) {
20328 1976 : int cell_index = module_info->RegularExportCellIndex(i);
20329 : Handle<FixedArray> export_names(module_info->RegularExportExportNames(i),
20330 1976 : isolate);
20331 1976 : CreateExport(module, cell_index, export_names);
20332 : }
20333 :
20334 : // Partially set up indirect exports.
20335 : // For each indirect export, we create the appropriate slot in the export
20336 : // table and store its ModuleInfoEntry there. When we later find the correct
20337 : // Cell in the module that actually provides the value, we replace the
20338 : // ModuleInfoEntry by that Cell (see ResolveExport).
20339 : Handle<FixedArray> special_exports(module_info->special_exports(), isolate);
20340 2290 : for (int i = 0, n = special_exports->length(); i < n; ++i) {
20341 : Handle<ModuleInfoEntry> entry(
20342 : ModuleInfoEntry::cast(special_exports->get(i)), isolate);
20343 : Handle<Object> export_name(entry->export_name(), isolate);
20344 387 : if (export_name->IsUndefined(isolate)) continue; // Star export.
20345 180 : CreateIndirectExport(module, Handle<String>::cast(export_name), entry);
20346 : }
20347 :
20348 : DCHECK_EQ(module->status(), kPrepared);
20349 : DCHECK(!module->instantiated());
20350 : return true;
20351 : }
20352 :
20353 2348 : bool Module::FinishInstantiate(Handle<Module> module,
20354 : v8::Local<v8::Context> context) {
20355 : DCHECK_EQ(module->status(), kPrepared);
20356 2348 : if (module->instantiated()) return true;
20357 :
20358 : // Instantiate SharedFunctionInfo and mark module as instantiated for
20359 : // the recursion.
20360 1903 : Isolate* isolate = module->GetIsolate();
20361 : Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(module->code()),
20362 : isolate);
20363 : Handle<JSFunction> function =
20364 : isolate->factory()->NewFunctionFromSharedFunctionInfo(
20365 : shared,
20366 1903 : handle(Utils::OpenHandle(*context)->native_context(), isolate));
20367 1903 : module->set_code(*function);
20368 : DCHECK(module->instantiated());
20369 :
20370 : // Recurse.
20371 : Handle<FixedArray> requested_modules(module->requested_modules(), isolate);
20372 3049 : for (int i = 0, length = requested_modules->length(); i < length; ++i) {
20373 : Handle<Module> requested_module(Module::cast(requested_modules->get(i)),
20374 : isolate);
20375 1146 : if (!FinishInstantiate(requested_module, context)) return false;
20376 : }
20377 :
20378 1903 : Zone zone(isolate->allocator(), ZONE_NAME);
20379 :
20380 : // Resolve imports.
20381 : Handle<ModuleInfo> module_info(shared->scope_info()->ModuleDescriptorInfo(),
20382 1903 : isolate);
20383 : Handle<FixedArray> regular_imports(module_info->regular_imports(), isolate);
20384 2786 : for (int i = 0, n = regular_imports->length(); i < n; ++i) {
20385 : Handle<ModuleInfoEntry> entry(
20386 : ModuleInfoEntry::cast(regular_imports->get(i)), isolate);
20387 : Handle<String> name(String::cast(entry->import_name()), isolate);
20388 : Handle<Script> script(
20389 : Script::cast(JSFunction::cast(module->code())->shared()->script()),
20390 : isolate);
20391 897 : MessageLocation loc(script, entry->beg_pos(), entry->end_pos());
20392 897 : ResolveSet resolve_set(&zone);
20393 : Handle<Cell> cell;
20394 897 : if (!ResolveImport(module, name, entry->module_request(), loc, true,
20395 : &resolve_set)
20396 1794 : .ToHandle(&cell)) {
20397 : return false;
20398 : }
20399 883 : module->regular_imports()->set(ImportIndex(entry->cell_index()), *cell);
20400 : }
20401 :
20402 : // Resolve indirect exports.
20403 : Handle<FixedArray> special_exports(module_info->special_exports(), isolate);
20404 2276 : for (int i = 0, n = special_exports->length(); i < n; ++i) {
20405 : Handle<ModuleInfoEntry> entry(
20406 : ModuleInfoEntry::cast(special_exports->get(i)), isolate);
20407 : Handle<Object> name(entry->export_name(), isolate);
20408 594 : if (name->IsUndefined(isolate)) continue; // Star export.
20409 : Handle<Script> script(
20410 : Script::cast(JSFunction::cast(module->code())->shared()->script()),
20411 : isolate);
20412 180 : MessageLocation loc(script, entry->beg_pos(), entry->end_pos());
20413 180 : ResolveSet resolve_set(&zone);
20414 180 : if (ResolveExport(module, Handle<String>::cast(name), loc, true,
20415 : &resolve_set)
20416 360 : .is_null()) {
20417 : return false;
20418 : }
20419 : }
20420 :
20421 1903 : return true;
20422 : }
20423 :
20424 2320 : MaybeHandle<Object> Module::Evaluate(Handle<Module> module) {
20425 : DCHECK(module->instantiated());
20426 :
20427 : // Each module can only be evaluated once.
20428 : Isolate* isolate = module->GetIsolate();
20429 2320 : if (module->evaluated()) return isolate->factory()->undefined_value();
20430 : Handle<JSFunction> function(JSFunction::cast(module->code()), isolate);
20431 1875 : module->set_evaluated();
20432 :
20433 : // Initialization.
20434 : DCHECK_EQ(MODULE_SCOPE, function->shared()->scope_info()->scope_type());
20435 : Handle<Object> receiver = isolate->factory()->undefined_value();
20436 : Handle<Object> argv[] = {module};
20437 : Handle<Object> generator;
20438 3750 : ASSIGN_RETURN_ON_EXCEPTION(
20439 : isolate, generator,
20440 : Execution::Call(isolate, function, receiver, arraysize(argv), argv),
20441 : Object);
20442 :
20443 : // Recursion.
20444 : Handle<FixedArray> requested_modules(module->requested_modules(), isolate);
20445 3007 : for (int i = 0, length = requested_modules->length(); i < length; ++i) {
20446 : Handle<Module> import(Module::cast(requested_modules->get(i)), isolate);
20447 2264 : RETURN_ON_EXCEPTION(isolate, Evaluate(import), Object);
20448 : }
20449 :
20450 : // Evaluation of module body.
20451 : Handle<JSFunction> resume(
20452 3750 : isolate->native_context()->generator_next_internal(), isolate);
20453 : Handle<Object> result;
20454 3750 : ASSIGN_RETURN_ON_EXCEPTION(
20455 : isolate, result, Execution::Call(isolate, resume, generator, 0, nullptr),
20456 : Object);
20457 : DCHECK(static_cast<JSIteratorResult*>(JSObject::cast(*result))
20458 : ->done()
20459 : ->BooleanValue());
20460 : return handle(
20461 : static_cast<JSIteratorResult*>(JSObject::cast(*result))->value(),
20462 : isolate);
20463 : }
20464 :
20465 : namespace {
20466 :
20467 403 : void FetchStarExports(Handle<Module> module, Zone* zone,
20468 : UnorderedModuleSet* visited) {
20469 : DCHECK(module->instantiated());
20470 :
20471 403 : bool cycle = !visited->insert(module).second;
20472 418 : if (cycle) return;
20473 :
20474 : Isolate* isolate = module->GetIsolate();
20475 : Handle<ObjectHashTable> exports(module->exports(), isolate);
20476 388 : UnorderedStringMap more_exports(zone);
20477 :
20478 : // TODO(neis): Only allocate more_exports if there are star exports.
20479 : // Maybe split special_exports into indirect_exports and star_exports.
20480 :
20481 : Handle<FixedArray> special_exports(module->info()->special_exports(),
20482 388 : isolate);
20483 536 : for (int i = 0, n = special_exports->length(); i < n; ++i) {
20484 : Handle<ModuleInfoEntry> entry(
20485 : ModuleInfoEntry::cast(special_exports->get(i)), isolate);
20486 148 : if (!entry->export_name()->IsUndefined(isolate)) {
20487 : continue; // Indirect export.
20488 : }
20489 :
20490 : Handle<Module> requested_module(
20491 : Module::cast(module->requested_modules()->get(entry->module_request())),
20492 : isolate);
20493 :
20494 : // Recurse.
20495 103 : FetchStarExports(requested_module, zone, visited);
20496 :
20497 : // Collect all of [requested_module]'s exports that must be added to
20498 : // [module]'s exports (i.e. to [exports]). We record these in
20499 : // [more_exports]. Ambiguities (conflicting exports) are marked by mapping
20500 : // the name to undefined instead of a Cell.
20501 : Handle<ObjectHashTable> requested_exports(requested_module->exports(),
20502 : isolate);
20503 815 : for (int i = 0, n = requested_exports->Capacity(); i < n; ++i) {
20504 : Handle<Object> key(requested_exports->KeyAt(i), isolate);
20505 712 : if (!requested_exports->IsKey(isolate, *key)) continue;
20506 : Handle<String> name = Handle<String>::cast(key);
20507 :
20508 298 : if (name->Equals(isolate->heap()->default_string())) continue;
20509 506 : if (!exports->Lookup(name)->IsTheHole(isolate)) continue;
20510 :
20511 : Handle<Cell> cell(Cell::cast(requested_exports->ValueAt(i)), isolate);
20512 446 : auto insert_result = more_exports.insert(std::make_pair(name, cell));
20513 223 : if (!insert_result.second) {
20514 : auto it = insert_result.first;
20515 45 : if (*it->second == *cell || it->second->IsUndefined(isolate)) {
20516 : // We already recorded this mapping before, or the name is already
20517 : // known to be ambiguous. In either case, there's nothing to do.
20518 : } else {
20519 : DCHECK(it->second->IsCell());
20520 : // Different star exports provide different cells for this name, hence
20521 : // mark the name as ambiguous.
20522 15 : it->second = isolate->factory()->undefined_value();
20523 : }
20524 : }
20525 : }
20526 : }
20527 :
20528 : // Copy [more_exports] into [exports].
20529 969 : for (const auto& elem : more_exports) {
20530 193 : if (elem.second->IsUndefined(isolate)) continue; // Ambiguous export.
20531 : DCHECK(!elem.first->Equals(isolate->heap()->default_string()));
20532 : DCHECK(elem.second->IsCell());
20533 178 : exports = ObjectHashTable::Put(exports, elem.first, elem.second);
20534 : }
20535 388 : module->set_exports(*exports);
20536 : }
20537 :
20538 : } // anonymous namespace
20539 :
20540 161 : Handle<JSModuleNamespace> Module::GetModuleNamespace(Handle<Module> module,
20541 : int module_request) {
20542 : Isolate* isolate = module->GetIsolate();
20543 : Handle<Module> requested_module(
20544 : Module::cast(module->requested_modules()->get(module_request)), isolate);
20545 161 : return Module::GetModuleNamespace(requested_module);
20546 : }
20547 :
20548 413 : Handle<JSModuleNamespace> Module::GetModuleNamespace(Handle<Module> module) {
20549 300 : Isolate* isolate = module->GetIsolate();
20550 :
20551 : Handle<HeapObject> object(module->module_namespace(), isolate);
20552 413 : if (!object->IsUndefined(isolate)) {
20553 : // Namespace object already exists.
20554 : return Handle<JSModuleNamespace>::cast(object);
20555 : }
20556 :
20557 : // Create the namespace object (initially empty).
20558 300 : Handle<JSModuleNamespace> ns = isolate->factory()->NewJSModuleNamespace();
20559 300 : ns->set_module(*module);
20560 300 : module->set_module_namespace(*ns);
20561 :
20562 : // Collect the export names.
20563 300 : Zone zone(isolate->allocator(), ZONE_NAME);
20564 300 : UnorderedModuleSet visited(&zone);
20565 300 : FetchStarExports(module, &zone, &visited);
20566 : Handle<ObjectHashTable> exports(module->exports(), isolate);
20567 : ZoneVector<Handle<String>> names(&zone);
20568 300 : names.reserve(exports->NumberOfElements());
20569 1920 : for (int i = 0, n = exports->Capacity(); i < n; ++i) {
20570 : Handle<Object> key(exports->KeyAt(i), isolate);
20571 1620 : if (!exports->IsKey(isolate, *key)) continue;
20572 : DCHECK(exports->ValueAt(i)->IsCell());
20573 611 : names.push_back(Handle<String>::cast(key));
20574 : }
20575 : DCHECK_EQ(static_cast<int>(names.size()), exports->NumberOfElements());
20576 :
20577 : // Sort them alphabetically.
20578 : struct {
20579 : bool operator()(Handle<String> a, Handle<String> b) {
20580 712 : return String::Compare(a, b) == ComparisonResult::kLessThan;
20581 : }
20582 : } StringLess;
20583 300 : std::sort(names.begin(), names.end(), StringLess);
20584 :
20585 : // Create the corresponding properties in the namespace object.
20586 : PropertyAttributes attr = DONT_DELETE;
20587 1211 : for (const auto& name : names) {
20588 : JSObject::SetAccessor(
20589 : ns, Accessors::ModuleNamespaceEntryInfo(isolate, name, attr))
20590 1833 : .Check();
20591 : }
20592 600 : JSObject::PreventExtensions(ns, THROW_ON_ERROR).ToChecked();
20593 :
20594 600 : return ns;
20595 : }
20596 :
20597 9379494 : MaybeHandle<Name> FunctionTemplateInfo::TryGetCachedPropertyName(
20598 : Isolate* isolate, Handle<Object> getter) {
20599 9379494 : if (getter->IsFunctionTemplateInfo()) {
20600 : Handle<FunctionTemplateInfo> fti =
20601 : Handle<FunctionTemplateInfo>::cast(getter);
20602 : // Check if the accessor uses a cached property.
20603 536 : if (!fti->cached_property_name()->IsTheHole(isolate)) {
20604 : return handle(Name::cast(fti->cached_property_name()));
20605 : }
20606 : }
20607 : return MaybeHandle<Name>();
20608 : }
20609 :
20610 : // static
20611 1397 : ElementsKind JSArrayIterator::ElementsKindForInstanceType(InstanceType type) {
20612 : DCHECK_GE(type, FIRST_ARRAY_ITERATOR_TYPE);
20613 : DCHECK_LE(type, LAST_ARRAY_ITERATOR_TYPE);
20614 :
20615 1397 : if (type <= LAST_ARRAY_KEY_ITERATOR_TYPE) {
20616 : // Should be ignored for key iterators.
20617 : return FAST_ELEMENTS;
20618 : } else {
20619 : ElementsKind kind;
20620 1384 : if (type < FIRST_ARRAY_VALUE_ITERATOR_TYPE) {
20621 : // Convert `type` to a value iterator from an entries iterator
20622 14 : type = static_cast<InstanceType>(type +
20623 : (FIRST_ARRAY_VALUE_ITERATOR_TYPE -
20624 14 : FIRST_ARRAY_KEY_VALUE_ITERATOR_TYPE));
20625 : DCHECK_GE(type, FIRST_ARRAY_VALUE_ITERATOR_TYPE);
20626 : DCHECK_LE(type, LAST_ARRAY_ITERATOR_TYPE);
20627 : }
20628 :
20629 1384 : if (type <= JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE) {
20630 : kind =
20631 14 : static_cast<ElementsKind>(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND +
20632 14 : (type - FIRST_ARRAY_VALUE_ITERATOR_TYPE));
20633 : DCHECK_LE(kind, LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
20634 1370 : } else if (type < JS_GENERIC_ARRAY_VALUE_ITERATOR_TYPE) {
20635 : kind = static_cast<ElementsKind>(
20636 1370 : FIRST_FAST_ELEMENTS_KIND +
20637 1370 : (type - JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE));
20638 : DCHECK_LE(kind, LAST_FAST_ELEMENTS_KIND);
20639 : } else {
20640 : // For any slow element cases, the actual elements kind is not known.
20641 : // Simply
20642 : // return a slow elements kind in this case. Users of this function must
20643 : // not
20644 : // depend on this.
20645 : return DICTIONARY_ELEMENTS;
20646 : }
20647 : DCHECK_LE(kind, LAST_ELEMENTS_KIND);
20648 1384 : return kind;
20649 : }
20650 : }
20651 :
20652 : } // namespace internal
20653 : } // namespace v8
|