• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/objects.h"
6 
7 #include <cmath>
8 #include <iomanip>
9 #include <memory>
10 #include <sstream>
11 #include <vector>
12 
13 #include "src/objects-inl.h"
14 
15 #include "src/accessors.h"
16 #include "src/allocation-site-scopes.h"
17 #include "src/api-arguments-inl.h"
18 #include "src/api-natives.h"
19 #include "src/api.h"
20 #include "src/arguments.h"
21 #include "src/ast/ast.h"
22 #include "src/ast/scopes.h"
23 #include "src/base/bits.h"
24 #include "src/base/utils/random-number-generator.h"
25 #include "src/bootstrapper.h"
26 #include "src/builtins/builtins.h"
27 #include "src/code-stubs.h"
28 #include "src/compiler.h"
29 #include "src/counters-inl.h"
30 #include "src/counters.h"
31 #include "src/date.h"
32 #include "src/debug/debug.h"
33 #include "src/deoptimizer.h"
34 #include "src/elements.h"
35 #include "src/execution.h"
36 #include "src/field-index-inl.h"
37 #include "src/field-index.h"
38 #include "src/field-type.h"
39 #include "src/frames-inl.h"
40 #include "src/globals.h"
41 #include "src/ic/ic.h"
42 #include "src/identity-map.h"
43 #include "src/interpreter/bytecode-array-iterator.h"
44 #include "src/interpreter/bytecode-decoder.h"
45 #include "src/interpreter/interpreter.h"
46 #include "src/isolate-inl.h"
47 #include "src/keys.h"
48 #include "src/log.h"
49 #include "src/lookup-inl.h"
50 #include "src/macro-assembler.h"
51 #include "src/map-updater.h"
52 #include "src/messages.h"
53 #include "src/objects-body-descriptors-inl.h"
54 #include "src/objects/api-callbacks.h"
55 #include "src/objects/arguments-inl.h"
56 #include "src/objects/bigint.h"
57 #include "src/objects/code-inl.h"
58 #include "src/objects/compilation-cache-inl.h"
59 #include "src/objects/debug-objects-inl.h"
60 #include "src/objects/frame-array-inl.h"
61 #include "src/objects/hash-table-inl.h"
62 #include "src/objects/js-array-inl.h"
63 #ifdef V8_INTL_SUPPORT
64 #include "src/objects/js-collator.h"
65 #endif  // V8_INTL_SUPPORT
66 #include "src/objects/js-collection-inl.h"
67 #include "src/objects/js-generator-inl.h"
68 #ifdef V8_INTL_SUPPORT
69 #include "src/objects/js-list-format.h"
70 #include "src/objects/js-locale.h"
71 #endif  // V8_INTL_SUPPORT
72 #include "src/objects/js-regexp-inl.h"
73 #include "src/objects/js-regexp-string-iterator.h"
74 #ifdef V8_INTL_SUPPORT
75 #include "src/objects/js-plural-rules.h"
76 #include "src/objects/js-relative-time-format.h"
77 #endif  // V8_INTL_SUPPORT
78 #include "src/objects/literal-objects-inl.h"
79 #include "src/objects/map.h"
80 #include "src/objects/microtask-inl.h"
81 #include "src/objects/module-inl.h"
82 #include "src/objects/promise-inl.h"
83 #include "src/parsing/preparsed-scope-data.h"
84 #include "src/property-descriptor.h"
85 #include "src/prototype.h"
86 #include "src/regexp/jsregexp.h"
87 #include "src/safepoint-table.h"
88 #include "src/snapshot/code-serializer.h"
89 #include "src/snapshot/snapshot.h"
90 #include "src/source-position-table.h"
91 #include "src/string-builder-inl.h"
92 #include "src/string-search.h"
93 #include "src/string-stream.h"
94 #include "src/unicode-cache-inl.h"
95 #include "src/unicode-decoder.h"
96 #include "src/utils-inl.h"
97 #include "src/wasm/wasm-engine.h"
98 #include "src/wasm/wasm-objects.h"
99 #include "src/zone/zone.h"
100 
101 #ifdef ENABLE_DISASSEMBLER
102 #include "src/disasm.h"
103 #include "src/disassembler.h"
104 #include "src/eh-frame.h"
105 #endif
106 
107 namespace v8 {
108 namespace internal {
109 
ComparisonResultToBool(Operation op,ComparisonResult result)110 bool ComparisonResultToBool(Operation op, ComparisonResult result) {
111   switch (op) {
112     case Operation::kLessThan:
113       return result == ComparisonResult::kLessThan;
114     case Operation::kLessThanOrEqual:
115       return result == ComparisonResult::kLessThan ||
116              result == ComparisonResult::kEqual;
117     case Operation::kGreaterThan:
118       return result == ComparisonResult::kGreaterThan;
119     case Operation::kGreaterThanOrEqual:
120       return result == ComparisonResult::kGreaterThan ||
121              result == ComparisonResult::kEqual;
122     default:
123       break;
124   }
125   UNREACHABLE();
126 }
127 
operator <<(std::ostream & os,InstanceType instance_type)128 std::ostream& operator<<(std::ostream& os, InstanceType instance_type) {
129   switch (instance_type) {
130 #define WRITE_TYPE(TYPE) \
131   case TYPE:             \
132     return os << #TYPE;
133     INSTANCE_TYPE_LIST(WRITE_TYPE)
134 #undef WRITE_TYPE
135   }
136   UNREACHABLE();
137 }
138 
OptimalType(Isolate * isolate,Representation representation)139 Handle<FieldType> Object::OptimalType(Isolate* isolate,
140                                       Representation representation) {
141   if (representation.IsNone()) return FieldType::None(isolate);
142   if (FLAG_track_field_types) {
143     if (representation.IsHeapObject() && IsHeapObject()) {
144       // We can track only JavaScript objects with stable maps.
145       Handle<Map> map(HeapObject::cast(this)->map(), isolate);
146       if (map->is_stable() && map->IsJSReceiverMap()) {
147         return FieldType::Class(map, isolate);
148       }
149     }
150   }
151   return FieldType::Any(isolate);
152 }
153 
ToObject(Isolate * isolate,Handle<Object> object,Handle<Context> native_context,const char * method_name)154 MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
155                                          Handle<Object> object,
156                                          Handle<Context> native_context,
157                                          const char* method_name) {
158   if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
159   Handle<JSFunction> constructor;
160   if (object->IsSmi()) {
161     constructor = handle(native_context->number_function(), isolate);
162   } else {
163     int constructor_function_index =
164         Handle<HeapObject>::cast(object)->map()->GetConstructorFunctionIndex();
165     if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
166       if (method_name != nullptr) {
167         THROW_NEW_ERROR(
168             isolate,
169             NewTypeError(
170                 MessageTemplate::kCalledOnNullOrUndefined,
171                 isolate->factory()->NewStringFromAsciiChecked(method_name)),
172             JSReceiver);
173       }
174       THROW_NEW_ERROR(isolate,
175                       NewTypeError(MessageTemplate::kUndefinedOrNullToObject),
176                       JSReceiver);
177     }
178     constructor = handle(
179         JSFunction::cast(native_context->get(constructor_function_index)),
180         isolate);
181   }
182   Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
183   Handle<JSValue>::cast(result)->set_value(*object);
184   return result;
185 }
186 
187 // ES6 section 9.2.1.2, OrdinaryCallBindThis for sloppy callee.
188 // static
ConvertReceiver(Isolate * isolate,Handle<Object> object)189 MaybeHandle<JSReceiver> Object::ConvertReceiver(Isolate* isolate,
190                                                 Handle<Object> object) {
191   if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
192   if (object->IsNullOrUndefined(isolate)) {
193     return isolate->global_proxy();
194   }
195   return Object::ToObject(isolate, object);
196 }
197 
198 // static
ConvertToNumberOrNumeric(Isolate * isolate,Handle<Object> input,Conversion mode)199 MaybeHandle<Object> Object::ConvertToNumberOrNumeric(Isolate* isolate,
200                                                      Handle<Object> input,
201                                                      Conversion mode) {
202   while (true) {
203     if (input->IsNumber()) {
204       return input;
205     }
206     if (input->IsString()) {
207       return String::ToNumber(isolate, Handle<String>::cast(input));
208     }
209     if (input->IsOddball()) {
210       return Oddball::ToNumber(isolate, Handle<Oddball>::cast(input));
211     }
212     if (input->IsSymbol()) {
213       THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber),
214                       Object);
215     }
216     if (input->IsBigInt()) {
217       if (mode == Conversion::kToNumeric) return input;
218       DCHECK_EQ(mode, Conversion::kToNumber);
219       THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kBigIntToNumber),
220                       Object);
221     }
222     ASSIGN_RETURN_ON_EXCEPTION(
223         isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
224                                                 ToPrimitiveHint::kNumber),
225         Object);
226   }
227 }
228 
229 // static
ConvertToInteger(Isolate * isolate,Handle<Object> input)230 MaybeHandle<Object> Object::ConvertToInteger(Isolate* isolate,
231                                              Handle<Object> input) {
232   ASSIGN_RETURN_ON_EXCEPTION(
233       isolate, input,
234       ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object);
235   if (input->IsSmi()) return input;
236   return isolate->factory()->NewNumber(DoubleToInteger(input->Number()));
237 }
238 
239 // static
ConvertToInt32(Isolate * isolate,Handle<Object> input)240 MaybeHandle<Object> Object::ConvertToInt32(Isolate* isolate,
241                                            Handle<Object> input) {
242   ASSIGN_RETURN_ON_EXCEPTION(
243       isolate, input,
244       ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object);
245   if (input->IsSmi()) return input;
246   return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number()));
247 }
248 
249 // static
ConvertToUint32(Isolate * isolate,Handle<Object> input)250 MaybeHandle<Object> Object::ConvertToUint32(Isolate* isolate,
251                                             Handle<Object> input) {
252   ASSIGN_RETURN_ON_EXCEPTION(
253       isolate, input,
254       ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object);
255   if (input->IsSmi()) return handle(Smi::cast(*input)->ToUint32Smi(), isolate);
256   return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number()));
257 }
258 
259 // static
ConvertToName(Isolate * isolate,Handle<Object> input)260 MaybeHandle<Name> Object::ConvertToName(Isolate* isolate,
261                                         Handle<Object> input) {
262   ASSIGN_RETURN_ON_EXCEPTION(
263       isolate, input, Object::ToPrimitive(input, ToPrimitiveHint::kString),
264       Name);
265   if (input->IsName()) return Handle<Name>::cast(input);
266   return ToString(isolate, input);
267 }
268 
269 // ES6 7.1.14
270 // static
ConvertToPropertyKey(Isolate * isolate,Handle<Object> value)271 MaybeHandle<Object> Object::ConvertToPropertyKey(Isolate* isolate,
272                                                  Handle<Object> value) {
273   // 1. Let key be ToPrimitive(argument, hint String).
274   MaybeHandle<Object> maybe_key =
275       Object::ToPrimitive(value, ToPrimitiveHint::kString);
276   // 2. ReturnIfAbrupt(key).
277   Handle<Object> key;
278   if (!maybe_key.ToHandle(&key)) return key;
279   // 3. If Type(key) is Symbol, then return key.
280   if (key->IsSymbol()) return key;
281   // 4. Return ToString(key).
282   // Extending spec'ed behavior, we'd be happy to return an element index.
283   if (key->IsSmi()) return key;
284   if (key->IsHeapNumber()) {
285     uint32_t uint_value;
286     if (value->ToArrayLength(&uint_value) &&
287         uint_value <= static_cast<uint32_t>(Smi::kMaxValue)) {
288       return handle(Smi::FromInt(static_cast<int>(uint_value)), isolate);
289     }
290   }
291   return Object::ToString(isolate, key);
292 }
293 
294 // static
ConvertToString(Isolate * isolate,Handle<Object> input)295 MaybeHandle<String> Object::ConvertToString(Isolate* isolate,
296                                             Handle<Object> input) {
297   while (true) {
298     if (input->IsOddball()) {
299       return handle(Handle<Oddball>::cast(input)->to_string(), isolate);
300     }
301     if (input->IsNumber()) {
302       return isolate->factory()->NumberToString(input);
303     }
304     if (input->IsSymbol()) {
305       THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToString),
306                       String);
307     }
308     if (input->IsBigInt()) {
309       return BigInt::ToString(isolate, Handle<BigInt>::cast(input));
310     }
311     ASSIGN_RETURN_ON_EXCEPTION(
312         isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
313                                                 ToPrimitiveHint::kString),
314         String);
315     // The previous isString() check happened in Object::ToString and thus we
316     // put it at the end of the loop in this helper.
317     if (input->IsString()) {
318       return Handle<String>::cast(input);
319     }
320   }
321 }
322 
323 namespace {
324 
IsErrorObject(Isolate * isolate,Handle<Object> object)325 bool IsErrorObject(Isolate* isolate, Handle<Object> object) {
326   if (!object->IsJSReceiver()) return false;
327   Handle<Symbol> symbol = isolate->factory()->stack_trace_symbol();
328   return JSReceiver::HasOwnProperty(Handle<JSReceiver>::cast(object), symbol)
329       .FromMaybe(false);
330 }
331 
AsStringOrEmpty(Isolate * isolate,Handle<Object> object)332 Handle<String> AsStringOrEmpty(Isolate* isolate, Handle<Object> object) {
333   return object->IsString() ? Handle<String>::cast(object)
334                             : isolate->factory()->empty_string();
335 }
336 
NoSideEffectsErrorToString(Isolate * isolate,Handle<Object> input)337 Handle<String> NoSideEffectsErrorToString(Isolate* isolate,
338                                           Handle<Object> input) {
339   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input);
340 
341   Handle<Name> name_key = isolate->factory()->name_string();
342   Handle<Object> name = JSReceiver::GetDataProperty(receiver, name_key);
343   Handle<String> name_str = AsStringOrEmpty(isolate, name);
344 
345   Handle<Name> msg_key = isolate->factory()->message_string();
346   Handle<Object> msg = JSReceiver::GetDataProperty(receiver, msg_key);
347   Handle<String> msg_str = AsStringOrEmpty(isolate, msg);
348 
349   if (name_str->length() == 0) return msg_str;
350   if (msg_str->length() == 0) return name_str;
351 
352   IncrementalStringBuilder builder(isolate);
353   builder.AppendString(name_str);
354   builder.AppendCString(": ");
355   builder.AppendString(msg_str);
356 
357   return builder.Finish().ToHandleChecked();
358 }
359 
360 }  // namespace
361 
362 // static
NoSideEffectsToString(Isolate * isolate,Handle<Object> input)363 Handle<String> Object::NoSideEffectsToString(Isolate* isolate,
364                                              Handle<Object> input) {
365   DisallowJavascriptExecution no_js(isolate);
366 
367   if (input->IsString() || input->IsNumeric() || input->IsOddball()) {
368     return Object::ToString(isolate, input).ToHandleChecked();
369   } else if (input->IsFunction()) {
370     // -- F u n c t i o n
371     Handle<String> fun_str;
372     if (input->IsJSBoundFunction()) {
373       fun_str = JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(input));
374     } else {
375       DCHECK(input->IsJSFunction());
376       fun_str = JSFunction::ToString(Handle<JSFunction>::cast(input));
377     }
378 
379     if (fun_str->length() > 128) {
380       IncrementalStringBuilder builder(isolate);
381       builder.AppendString(isolate->factory()->NewSubString(fun_str, 0, 111));
382       builder.AppendCString("...<omitted>...");
383       builder.AppendString(isolate->factory()->NewSubString(
384           fun_str, fun_str->length() - 2, fun_str->length()));
385 
386       return builder.Finish().ToHandleChecked();
387     }
388     return fun_str;
389   } else if (input->IsSymbol()) {
390     // -- S y m b o l
391     Handle<Symbol> symbol = Handle<Symbol>::cast(input);
392 
393     IncrementalStringBuilder builder(isolate);
394     builder.AppendCString("Symbol(");
395     if (symbol->name()->IsString()) {
396       builder.AppendString(handle(String::cast(symbol->name()), isolate));
397     }
398     builder.AppendCharacter(')');
399 
400     return builder.Finish().ToHandleChecked();
401   } else if (input->IsJSReceiver()) {
402     // -- J S R e c e i v e r
403     Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input);
404     Handle<Object> to_string = JSReceiver::GetDataProperty(
405         receiver, isolate->factory()->toString_string());
406 
407     if (IsErrorObject(isolate, input) ||
408         *to_string == *isolate->error_to_string()) {
409       // When internally formatting error objects, use a side-effects-free
410       // version of Error.prototype.toString independent of the actually
411       // installed toString method.
412       return NoSideEffectsErrorToString(isolate, input);
413     } else if (*to_string == *isolate->object_to_string()) {
414       Handle<Object> ctor = JSReceiver::GetDataProperty(
415           receiver, isolate->factory()->constructor_string());
416       if (ctor->IsFunction()) {
417         Handle<String> ctor_name;
418         if (ctor->IsJSBoundFunction()) {
419           ctor_name = JSBoundFunction::GetName(
420                           isolate, Handle<JSBoundFunction>::cast(ctor))
421                           .ToHandleChecked();
422         } else if (ctor->IsJSFunction()) {
423           Handle<Object> ctor_name_obj =
424               JSFunction::GetName(isolate, Handle<JSFunction>::cast(ctor));
425           ctor_name = AsStringOrEmpty(isolate, ctor_name_obj);
426         }
427 
428         if (ctor_name->length() != 0) {
429           IncrementalStringBuilder builder(isolate);
430           builder.AppendCString("#<");
431           builder.AppendString(ctor_name);
432           builder.AppendCString(">");
433 
434           return builder.Finish().ToHandleChecked();
435         }
436       }
437     }
438   }
439 
440   // At this point, input is either none of the above or a JSReceiver.
441 
442   Handle<JSReceiver> receiver;
443   if (input->IsJSReceiver()) {
444     receiver = Handle<JSReceiver>::cast(input);
445   } else {
446     // This is the only case where Object::ToObject throws.
447     DCHECK(!input->IsSmi());
448     int constructor_function_index =
449         Handle<HeapObject>::cast(input)->map()->GetConstructorFunctionIndex();
450     if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
451       return isolate->factory()->NewStringFromAsciiChecked("[object Unknown]");
452     }
453 
454     receiver = Object::ToObject(isolate, input, isolate->native_context())
455                    .ToHandleChecked();
456   }
457 
458   Handle<String> builtin_tag = handle(receiver->class_name(), isolate);
459   Handle<Object> tag_obj = JSReceiver::GetDataProperty(
460       receiver, isolate->factory()->to_string_tag_symbol());
461   Handle<String> tag =
462       tag_obj->IsString() ? Handle<String>::cast(tag_obj) : builtin_tag;
463 
464   IncrementalStringBuilder builder(isolate);
465   builder.AppendCString("[object ");
466   builder.AppendString(tag);
467   builder.AppendCString("]");
468 
469   return builder.Finish().ToHandleChecked();
470 }
471 
472 // static
ConvertToLength(Isolate * isolate,Handle<Object> input)473 MaybeHandle<Object> Object::ConvertToLength(Isolate* isolate,
474                                             Handle<Object> input) {
475   ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(isolate, input), Object);
476   if (input->IsSmi()) {
477     int value = std::max(Smi::ToInt(*input), 0);
478     return handle(Smi::FromInt(value), isolate);
479   }
480   double len = DoubleToInteger(input->Number());
481   if (len <= 0.0) {
482     return handle(Smi::kZero, isolate);
483   } else if (len >= kMaxSafeInteger) {
484     len = kMaxSafeInteger;
485   }
486   return isolate->factory()->NewNumber(len);
487 }
488 
489 // static
ConvertToIndex(Isolate * isolate,Handle<Object> input,MessageTemplate::Template error_index)490 MaybeHandle<Object> Object::ConvertToIndex(
491     Isolate* isolate, Handle<Object> input,
492     MessageTemplate::Template error_index) {
493   if (input->IsUndefined(isolate)) return handle(Smi::kZero, isolate);
494   ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(isolate, input), Object);
495   if (input->IsSmi() && Smi::ToInt(*input) >= 0) return input;
496   double len = DoubleToInteger(input->Number()) + 0.0;
497   auto js_len = isolate->factory()->NewNumber(len);
498   if (len < 0.0 || len > kMaxSafeInteger) {
499     THROW_NEW_ERROR(isolate, NewRangeError(error_index, js_len), Object);
500   }
501   return js_len;
502 }
503 
BooleanValue(Isolate * isolate)504 bool Object::BooleanValue(Isolate* isolate) {
505   if (IsSmi()) return Smi::ToInt(this) != 0;
506   DCHECK(IsHeapObject());
507   if (IsBoolean()) return IsTrue(isolate);
508   if (IsNullOrUndefined(isolate)) return false;
509   if (IsUndetectable()) return false;  // Undetectable object is false.
510   if (IsString()) return String::cast(this)->length() != 0;
511   if (IsHeapNumber()) return DoubleToBoolean(HeapNumber::cast(this)->value());
512   if (IsBigInt()) return BigInt::cast(this)->ToBoolean();
513   return true;
514 }
515 
516 
517 namespace {
518 
519 // TODO(bmeurer): Maybe we should introduce a marker interface Number,
520 // where we put all these methods at some point?
NumberCompare(double x,double y)521 ComparisonResult NumberCompare(double x, double y) {
522   if (std::isnan(x) || std::isnan(y)) {
523     return ComparisonResult::kUndefined;
524   } else if (x < y) {
525     return ComparisonResult::kLessThan;
526   } else if (x > y) {
527     return ComparisonResult::kGreaterThan;
528   } else {
529     return ComparisonResult::kEqual;
530   }
531 }
532 
NumberEquals(double x,double y)533 bool NumberEquals(double x, double y) {
534   // Must check explicitly for NaN's on Windows, but -0 works fine.
535   if (std::isnan(x)) return false;
536   if (std::isnan(y)) return false;
537   return x == y;
538 }
539 
NumberEquals(const Object * x,const Object * y)540 bool NumberEquals(const Object* x, const Object* y) {
541   return NumberEquals(x->Number(), y->Number());
542 }
543 
NumberEquals(Handle<Object> x,Handle<Object> y)544 bool NumberEquals(Handle<Object> x, Handle<Object> y) {
545   return NumberEquals(*x, *y);
546 }
547 
Reverse(ComparisonResult result)548 ComparisonResult Reverse(ComparisonResult result) {
549   if (result == ComparisonResult::kLessThan) {
550     return ComparisonResult::kGreaterThan;
551   }
552   if (result == ComparisonResult::kGreaterThan) {
553     return ComparisonResult::kLessThan;
554   }
555   return result;
556 }
557 
558 }  // anonymous namespace
559 
560 // static
Compare(Isolate * isolate,Handle<Object> x,Handle<Object> y)561 Maybe<ComparisonResult> Object::Compare(Isolate* isolate, Handle<Object> x,
562                                         Handle<Object> y) {
563   // ES6 section 7.2.11 Abstract Relational Comparison step 3 and 4.
564   if (!Object::ToPrimitive(x, ToPrimitiveHint::kNumber).ToHandle(&x) ||
565       !Object::ToPrimitive(y, ToPrimitiveHint::kNumber).ToHandle(&y)) {
566     return Nothing<ComparisonResult>();
567   }
568   if (x->IsString() && y->IsString()) {
569     // ES6 section 7.2.11 Abstract Relational Comparison step 5.
570     return Just(String::Compare(isolate, Handle<String>::cast(x),
571                                 Handle<String>::cast(y)));
572   }
573   if (x->IsBigInt() && y->IsString()) {
574     return Just(BigInt::CompareToString(isolate, Handle<BigInt>::cast(x),
575                                         Handle<String>::cast(y)));
576   }
577   if (x->IsString() && y->IsBigInt()) {
578     return Just(Reverse(BigInt::CompareToString(
579         isolate, Handle<BigInt>::cast(y), Handle<String>::cast(x))));
580   }
581   // ES6 section 7.2.11 Abstract Relational Comparison step 6.
582   if (!Object::ToNumeric(isolate, x).ToHandle(&x) ||
583       !Object::ToNumeric(isolate, y).ToHandle(&y)) {
584     return Nothing<ComparisonResult>();
585   }
586 
587   bool x_is_number = x->IsNumber();
588   bool y_is_number = y->IsNumber();
589   if (x_is_number && y_is_number) {
590     return Just(NumberCompare(x->Number(), y->Number()));
591   } else if (!x_is_number && !y_is_number) {
592     return Just(BigInt::CompareToBigInt(Handle<BigInt>::cast(x),
593                                         Handle<BigInt>::cast(y)));
594   } else if (x_is_number) {
595     return Just(Reverse(BigInt::CompareToNumber(Handle<BigInt>::cast(y), x)));
596   } else {
597     return Just(BigInt::CompareToNumber(Handle<BigInt>::cast(x), y));
598   }
599 }
600 
601 
602 // static
Equals(Isolate * isolate,Handle<Object> x,Handle<Object> y)603 Maybe<bool> Object::Equals(Isolate* isolate, Handle<Object> x,
604                            Handle<Object> y) {
605   // This is the generic version of Abstract Equality Comparison. Must be in
606   // sync with CodeStubAssembler::Equal.
607   while (true) {
608     if (x->IsNumber()) {
609       if (y->IsNumber()) {
610         return Just(NumberEquals(x, y));
611       } else if (y->IsBoolean()) {
612         return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
613       } else if (y->IsString()) {
614         return Just(NumberEquals(
615             x, String::ToNumber(isolate, Handle<String>::cast(y))));
616       } else if (y->IsBigInt()) {
617         return Just(BigInt::EqualToNumber(Handle<BigInt>::cast(y), x));
618       } else if (y->IsJSReceiver()) {
619         if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
620                  .ToHandle(&y)) {
621           return Nothing<bool>();
622         }
623       } else {
624         return Just(false);
625       }
626     } else if (x->IsString()) {
627       if (y->IsString()) {
628         return Just(String::Equals(isolate, Handle<String>::cast(x),
629                                    Handle<String>::cast(y)));
630       } else if (y->IsNumber()) {
631         x = String::ToNumber(isolate, Handle<String>::cast(x));
632         return Just(NumberEquals(x, y));
633       } else if (y->IsBoolean()) {
634         x = String::ToNumber(isolate, Handle<String>::cast(x));
635         return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
636       } else if (y->IsBigInt()) {
637         return Just(BigInt::EqualToString(isolate, Handle<BigInt>::cast(y),
638                                           Handle<String>::cast(x)));
639       } else if (y->IsJSReceiver()) {
640         if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
641                  .ToHandle(&y)) {
642           return Nothing<bool>();
643         }
644       } else {
645         return Just(false);
646       }
647     } else if (x->IsBoolean()) {
648       if (y->IsOddball()) {
649         return Just(x.is_identical_to(y));
650       } else if (y->IsNumber()) {
651         return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
652       } else if (y->IsString()) {
653         y = String::ToNumber(isolate, Handle<String>::cast(y));
654         return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
655       } else if (y->IsBigInt()) {
656         x = Oddball::ToNumber(isolate, Handle<Oddball>::cast(x));
657         return Just(BigInt::EqualToNumber(Handle<BigInt>::cast(y), x));
658       } else if (y->IsJSReceiver()) {
659         if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
660                  .ToHandle(&y)) {
661           return Nothing<bool>();
662         }
663         x = Oddball::ToNumber(isolate, Handle<Oddball>::cast(x));
664       } else {
665         return Just(false);
666       }
667     } else if (x->IsSymbol()) {
668       if (y->IsSymbol()) {
669         return Just(x.is_identical_to(y));
670       } else if (y->IsJSReceiver()) {
671         if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
672                  .ToHandle(&y)) {
673           return Nothing<bool>();
674         }
675       } else {
676         return Just(false);
677       }
678     } else if (x->IsBigInt()) {
679       if (y->IsBigInt()) {
680         return Just(BigInt::EqualToBigInt(BigInt::cast(*x), BigInt::cast(*y)));
681       }
682       return Equals(isolate, y, x);
683     } else if (x->IsJSReceiver()) {
684       if (y->IsJSReceiver()) {
685         return Just(x.is_identical_to(y));
686       } else if (y->IsUndetectable()) {
687         return Just(x->IsUndetectable());
688       } else if (y->IsBoolean()) {
689         y = Oddball::ToNumber(isolate, Handle<Oddball>::cast(y));
690       } else if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(x))
691                       .ToHandle(&x)) {
692         return Nothing<bool>();
693       }
694     } else {
695       return Just(x->IsUndetectable() && y->IsUndetectable());
696     }
697   }
698 }
699 
700 
StrictEquals(Object * that)701 bool Object::StrictEquals(Object* that) {
702   if (this->IsNumber()) {
703     if (!that->IsNumber()) return false;
704     return NumberEquals(this, that);
705   } else if (this->IsString()) {
706     if (!that->IsString()) return false;
707     return String::cast(this)->Equals(String::cast(that));
708   } else if (this->IsBigInt()) {
709     if (!that->IsBigInt()) return false;
710     return BigInt::EqualToBigInt(BigInt::cast(this), BigInt::cast(that));
711   }
712   return this == that;
713 }
714 
715 
716 // static
TypeOf(Isolate * isolate,Handle<Object> object)717 Handle<String> Object::TypeOf(Isolate* isolate, Handle<Object> object) {
718   if (object->IsNumber()) return isolate->factory()->number_string();
719   if (object->IsOddball())
720     return handle(Oddball::cast(*object)->type_of(), isolate);
721   if (object->IsUndetectable()) {
722     return isolate->factory()->undefined_string();
723   }
724   if (object->IsString()) return isolate->factory()->string_string();
725   if (object->IsSymbol()) return isolate->factory()->symbol_string();
726   if (object->IsBigInt()) return isolate->factory()->bigint_string();
727   if (object->IsCallable()) return isolate->factory()->function_string();
728   return isolate->factory()->object_string();
729 }
730 
731 
732 // static
Add(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)733 MaybeHandle<Object> Object::Add(Isolate* isolate, Handle<Object> lhs,
734                                 Handle<Object> rhs) {
735   if (lhs->IsNumber() && rhs->IsNumber()) {
736     return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
737   } else if (lhs->IsString() && rhs->IsString()) {
738     return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
739                                              Handle<String>::cast(rhs));
740   }
741   ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToPrimitive(lhs), Object);
742   ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToPrimitive(rhs), Object);
743   if (lhs->IsString() || rhs->IsString()) {
744     ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToString(isolate, rhs),
745                                Object);
746     ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToString(isolate, lhs),
747                                Object);
748     return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
749                                              Handle<String>::cast(rhs));
750   }
751   ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(isolate, rhs),
752                              Object);
753   ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(isolate, lhs),
754                              Object);
755   return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
756 }
757 
758 
759 // static
OrdinaryHasInstance(Isolate * isolate,Handle<Object> callable,Handle<Object> object)760 MaybeHandle<Object> Object::OrdinaryHasInstance(Isolate* isolate,
761                                                 Handle<Object> callable,
762                                                 Handle<Object> object) {
763   // The {callable} must have a [[Call]] internal method.
764   if (!callable->IsCallable()) return isolate->factory()->false_value();
765 
766   // Check if {callable} is a bound function, and if so retrieve its
767   // [[BoundTargetFunction]] and use that instead of {callable}.
768   if (callable->IsJSBoundFunction()) {
769     Handle<Object> bound_callable(
770         Handle<JSBoundFunction>::cast(callable)->bound_target_function(),
771         isolate);
772     return Object::InstanceOf(isolate, object, bound_callable);
773   }
774 
775   // If {object} is not a receiver, return false.
776   if (!object->IsJSReceiver()) return isolate->factory()->false_value();
777 
778   // Get the "prototype" of {callable}; raise an error if it's not a receiver.
779   Handle<Object> prototype;
780   ASSIGN_RETURN_ON_EXCEPTION(
781       isolate, prototype,
782       Object::GetProperty(isolate, callable,
783                           isolate->factory()->prototype_string()),
784       Object);
785   if (!prototype->IsJSReceiver()) {
786     THROW_NEW_ERROR(
787         isolate,
788         NewTypeError(MessageTemplate::kInstanceofNonobjectProto, prototype),
789         Object);
790   }
791 
792   // Return whether or not {prototype} is in the prototype chain of {object}.
793   Maybe<bool> result = JSReceiver::HasInPrototypeChain(
794       isolate, Handle<JSReceiver>::cast(object), prototype);
795   if (result.IsNothing()) return MaybeHandle<Object>();
796   return isolate->factory()->ToBoolean(result.FromJust());
797 }
798 
799 // static
InstanceOf(Isolate * isolate,Handle<Object> object,Handle<Object> callable)800 MaybeHandle<Object> Object::InstanceOf(Isolate* isolate, Handle<Object> object,
801                                        Handle<Object> callable) {
802   // The {callable} must be a receiver.
803   if (!callable->IsJSReceiver()) {
804     THROW_NEW_ERROR(isolate,
805                     NewTypeError(MessageTemplate::kNonObjectInInstanceOfCheck),
806                     Object);
807   }
808 
809   // Lookup the @@hasInstance method on {callable}.
810   Handle<Object> inst_of_handler;
811   ASSIGN_RETURN_ON_EXCEPTION(
812       isolate, inst_of_handler,
813       JSReceiver::GetMethod(Handle<JSReceiver>::cast(callable),
814                             isolate->factory()->has_instance_symbol()),
815       Object);
816   if (!inst_of_handler->IsUndefined(isolate)) {
817     // Call the {inst_of_handler} on the {callable}.
818     Handle<Object> result;
819     ASSIGN_RETURN_ON_EXCEPTION(
820         isolate, result,
821         Execution::Call(isolate, inst_of_handler, callable, 1, &object),
822         Object);
823     return isolate->factory()->ToBoolean(result->BooleanValue(isolate));
824   }
825 
826   // The {callable} must have a [[Call]] internal method.
827   if (!callable->IsCallable()) {
828     THROW_NEW_ERROR(
829         isolate, NewTypeError(MessageTemplate::kNonCallableInInstanceOfCheck),
830         Object);
831   }
832 
833   // Fall back to OrdinaryHasInstance with {callable} and {object}.
834   Handle<Object> result;
835   ASSIGN_RETURN_ON_EXCEPTION(
836       isolate, result,
837       JSReceiver::OrdinaryHasInstance(isolate, callable, object), Object);
838   return result;
839 }
840 
841 // static
GetMethod(Handle<JSReceiver> receiver,Handle<Name> name)842 MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
843                                       Handle<Name> name) {
844   Handle<Object> func;
845   Isolate* isolate = receiver->GetIsolate();
846   ASSIGN_RETURN_ON_EXCEPTION(
847       isolate, func, JSReceiver::GetProperty(isolate, receiver, name), Object);
848   if (func->IsNullOrUndefined(isolate)) {
849     return isolate->factory()->undefined_value();
850   }
851   if (!func->IsCallable()) {
852     THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kPropertyNotFunction,
853                                           func, name, receiver),
854                     Object);
855   }
856   return func;
857 }
858 
859 namespace {
860 
CreateListFromArrayLikeFastPath(Isolate * isolate,Handle<Object> object,ElementTypes element_types)861 MaybeHandle<FixedArray> CreateListFromArrayLikeFastPath(
862     Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
863   if (element_types == ElementTypes::kAll) {
864     if (object->IsJSArray()) {
865       Handle<JSArray> array = Handle<JSArray>::cast(object);
866       uint32_t length;
867       if (!array->HasArrayPrototype(isolate) ||
868           !array->length()->ToUint32(&length) || !array->HasFastElements() ||
869           !JSObject::PrototypeHasNoElements(isolate, *array)) {
870         return MaybeHandle<FixedArray>();
871       }
872       return array->GetElementsAccessor()->CreateListFromArrayLike(
873           isolate, array, length);
874     } else if (object->IsJSTypedArray()) {
875       Handle<JSTypedArray> array = Handle<JSTypedArray>::cast(object);
876       size_t length = array->length_value();
877       if (array->WasNeutered() ||
878           length > static_cast<size_t>(FixedArray::kMaxLength)) {
879         return MaybeHandle<FixedArray>();
880       }
881       return array->GetElementsAccessor()->CreateListFromArrayLike(
882           isolate, array, static_cast<uint32_t>(length));
883     }
884   }
885   return MaybeHandle<FixedArray>();
886 }
887 
888 }  // namespace
889 
890 // static
CreateListFromArrayLike(Isolate * isolate,Handle<Object> object,ElementTypes element_types)891 MaybeHandle<FixedArray> Object::CreateListFromArrayLike(
892     Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
893   // Fast-path for JSArray and JSTypedArray.
894   MaybeHandle<FixedArray> fast_result =
895       CreateListFromArrayLikeFastPath(isolate, object, element_types);
896   if (!fast_result.is_null()) return fast_result;
897   // 1. ReturnIfAbrupt(object).
898   // 2. (default elementTypes -- not applicable.)
899   // 3. If Type(obj) is not Object, throw a TypeError exception.
900   if (!object->IsJSReceiver()) {
901     THROW_NEW_ERROR(isolate,
902                     NewTypeError(MessageTemplate::kCalledOnNonObject,
903                                  isolate->factory()->NewStringFromAsciiChecked(
904                                      "CreateListFromArrayLike")),
905                     FixedArray);
906   }
907 
908   // 4. Let len be ? ToLength(? Get(obj, "length")).
909   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
910   Handle<Object> raw_length_number;
911   ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number,
912                              Object::GetLengthFromArrayLike(isolate, receiver),
913                              FixedArray);
914   uint32_t len;
915   if (!raw_length_number->ToUint32(&len) ||
916       len > static_cast<uint32_t>(FixedArray::kMaxLength)) {
917     THROW_NEW_ERROR(isolate,
918                     NewRangeError(MessageTemplate::kInvalidArrayLength),
919                     FixedArray);
920   }
921   // 5. Let list be an empty List.
922   Handle<FixedArray> list = isolate->factory()->NewFixedArray(len);
923   // 6. Let index be 0.
924   // 7. Repeat while index < len:
925   for (uint32_t index = 0; index < len; ++index) {
926     // 7a. Let indexName be ToString(index).
927     // 7b. Let next be ? Get(obj, indexName).
928     Handle<Object> next;
929     ASSIGN_RETURN_ON_EXCEPTION(isolate, next,
930                                JSReceiver::GetElement(isolate, receiver, index),
931                                FixedArray);
932     switch (element_types) {
933       case ElementTypes::kAll:
934         // Nothing to do.
935         break;
936       case ElementTypes::kStringAndSymbol: {
937         // 7c. If Type(next) is not an element of elementTypes, throw a
938         //     TypeError exception.
939         if (!next->IsName()) {
940           THROW_NEW_ERROR(isolate,
941                           NewTypeError(MessageTemplate::kNotPropertyName, next),
942                           FixedArray);
943         }
944         // 7d. Append next as the last element of list.
945         // Internalize on the fly so we can use pointer identity later.
946         next = isolate->factory()->InternalizeName(Handle<Name>::cast(next));
947         break;
948       }
949     }
950     list->set(index, *next);
951     // 7e. Set index to index + 1. (See loop header.)
952   }
953   // 8. Return list.
954   return list;
955 }
956 
957 
958 // static
GetLengthFromArrayLike(Isolate * isolate,Handle<JSReceiver> object)959 MaybeHandle<Object> Object::GetLengthFromArrayLike(Isolate* isolate,
960                                                    Handle<JSReceiver> object) {
961   Handle<Object> val;
962   Handle<Name> key = isolate->factory()->length_string();
963   ASSIGN_RETURN_ON_EXCEPTION(
964       isolate, val, JSReceiver::GetProperty(isolate, object, key), Object);
965   return Object::ToLength(isolate, val);
966 }
967 
968 // static
HasProperty(LookupIterator * it)969 Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) {
970   for (; it->IsFound(); it->Next()) {
971     switch (it->state()) {
972       case LookupIterator::NOT_FOUND:
973       case LookupIterator::TRANSITION:
974         UNREACHABLE();
975       case LookupIterator::JSPROXY:
976         return JSProxy::HasProperty(it->isolate(), it->GetHolder<JSProxy>(),
977                                     it->GetName());
978       case LookupIterator::INTERCEPTOR: {
979         Maybe<PropertyAttributes> result =
980             JSObject::GetPropertyAttributesWithInterceptor(it);
981         if (result.IsNothing()) return Nothing<bool>();
982         if (result.FromJust() != ABSENT) return Just(true);
983         break;
984       }
985       case LookupIterator::ACCESS_CHECK: {
986         if (it->HasAccess()) break;
987         Maybe<PropertyAttributes> result =
988             JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
989         if (result.IsNothing()) return Nothing<bool>();
990         return Just(result.FromJust() != ABSENT);
991       }
992       case LookupIterator::INTEGER_INDEXED_EXOTIC:
993         // TypedArray out-of-bounds access.
994         return Just(false);
995       case LookupIterator::ACCESSOR:
996       case LookupIterator::DATA:
997         return Just(true);
998     }
999   }
1000   return Just(false);
1001 }
1002 
1003 // static
HasOwnProperty(Handle<JSReceiver> object,Handle<Name> name)1004 Maybe<bool> JSReceiver::HasOwnProperty(Handle<JSReceiver> object,
1005                                        Handle<Name> name) {
1006   if (object->IsJSModuleNamespace()) {
1007     PropertyDescriptor desc;
1008     return JSReceiver::GetOwnPropertyDescriptor(object->GetIsolate(), object,
1009                                                 name, &desc);
1010   }
1011 
1012   if (object->IsJSObject()) {  // Shortcut.
1013     LookupIterator it = LookupIterator::PropertyOrElement(
1014         object->GetIsolate(), object, name, object, LookupIterator::OWN);
1015     return HasProperty(&it);
1016   }
1017 
1018   Maybe<PropertyAttributes> attributes =
1019       JSReceiver::GetOwnPropertyAttributes(object, name);
1020   MAYBE_RETURN(attributes, Nothing<bool>());
1021   return Just(attributes.FromJust() != ABSENT);
1022 }
1023 
1024 // static
GetProperty(LookupIterator * it,OnNonExistent on_non_existent)1025 MaybeHandle<Object> Object::GetProperty(LookupIterator* it,
1026                                         OnNonExistent on_non_existent) {
1027   for (; it->IsFound(); it->Next()) {
1028     switch (it->state()) {
1029       case LookupIterator::NOT_FOUND:
1030       case LookupIterator::TRANSITION:
1031         UNREACHABLE();
1032       case LookupIterator::JSPROXY: {
1033         bool was_found;
1034         MaybeHandle<Object> result =
1035             JSProxy::GetProperty(it->isolate(), it->GetHolder<JSProxy>(),
1036                                  it->GetName(), it->GetReceiver(), &was_found);
1037         if (!was_found) it->NotFound();
1038         return result;
1039       }
1040       case LookupIterator::INTERCEPTOR: {
1041         bool done;
1042         Handle<Object> result;
1043         ASSIGN_RETURN_ON_EXCEPTION(
1044             it->isolate(), result,
1045             JSObject::GetPropertyWithInterceptor(it, &done), Object);
1046         if (done) return result;
1047         break;
1048       }
1049       case LookupIterator::ACCESS_CHECK:
1050         if (it->HasAccess()) break;
1051         return JSObject::GetPropertyWithFailedAccessCheck(it);
1052       case LookupIterator::ACCESSOR:
1053         return GetPropertyWithAccessor(it);
1054       case LookupIterator::INTEGER_INDEXED_EXOTIC:
1055         return it->isolate()->factory()->undefined_value();
1056       case LookupIterator::DATA:
1057         return it->GetDataValue();
1058     }
1059   }
1060 
1061   if (on_non_existent == OnNonExistent::kThrowReferenceError) {
1062     THROW_NEW_ERROR(it->isolate(),
1063                     NewReferenceError(MessageTemplate::kNotDefined, it->name()),
1064                     Object);
1065   }
1066   return it->isolate()->factory()->undefined_value();
1067 }
1068 
1069 
1070 // static
GetProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Name> name,Handle<Object> receiver,bool * was_found)1071 MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
1072                                          Handle<JSProxy> proxy,
1073                                          Handle<Name> name,
1074                                          Handle<Object> receiver,
1075                                          bool* was_found) {
1076   *was_found = true;
1077 
1078   DCHECK(!name->IsPrivate());
1079   STACK_CHECK(isolate, MaybeHandle<Object>());
1080   Handle<Name> trap_name = isolate->factory()->get_string();
1081   // 1. Assert: IsPropertyKey(P) is true.
1082   // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
1083   Handle<Object> handler(proxy->handler(), isolate);
1084   // 3. If handler is null, throw a TypeError exception.
1085   // 4. Assert: Type(handler) is Object.
1086   if (proxy->IsRevoked()) {
1087     THROW_NEW_ERROR(isolate,
1088                     NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1089                     Object);
1090   }
1091   // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
1092   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
1093   // 6. Let trap be ? GetMethod(handler, "get").
1094   Handle<Object> trap;
1095   ASSIGN_RETURN_ON_EXCEPTION(
1096       isolate, trap,
1097       Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), Object);
1098   // 7. If trap is undefined, then
1099   if (trap->IsUndefined(isolate)) {
1100     // 7.a Return target.[[Get]](P, Receiver).
1101     LookupIterator it =
1102         LookupIterator::PropertyOrElement(isolate, receiver, name, target);
1103     MaybeHandle<Object> result = Object::GetProperty(&it);
1104     *was_found = it.IsFound();
1105     return result;
1106   }
1107   // 8. Let trapResult be ? Call(trap, handler, «target, P, Receiver»).
1108   Handle<Object> trap_result;
1109   Handle<Object> args[] = {target, name, receiver};
1110   ASSIGN_RETURN_ON_EXCEPTION(
1111       isolate, trap_result,
1112       Execution::Call(isolate, trap, handler, arraysize(args), args), Object);
1113 
1114   MaybeHandle<Object> result =
1115       JSProxy::CheckGetSetTrapResult(isolate, name, target, trap_result, kGet);
1116   if (result.is_null()) {
1117     return result;
1118   }
1119 
1120   // 11. Return trap_result
1121   return trap_result;
1122 }
1123 
1124 // static
CheckGetSetTrapResult(Isolate * isolate,Handle<Name> name,Handle<JSReceiver> target,Handle<Object> trap_result,AccessKind access_kind)1125 MaybeHandle<Object> JSProxy::CheckGetSetTrapResult(Isolate* isolate,
1126                                                    Handle<Name> name,
1127                                                    Handle<JSReceiver> target,
1128                                                    Handle<Object> trap_result,
1129                                                    AccessKind access_kind) {
1130   // 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
1131   PropertyDescriptor target_desc;
1132   Maybe<bool> target_found =
1133       JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
1134   MAYBE_RETURN_NULL(target_found);
1135   // 10. If targetDesc is not undefined, then
1136   if (target_found.FromJust()) {
1137     // 10.a. If IsDataDescriptor(targetDesc) and targetDesc.[[Configurable]] is
1138     //       false and targetDesc.[[Writable]] is false, then
1139     // 10.a.i. If SameValue(trapResult, targetDesc.[[Value]]) is false,
1140     //        throw a TypeError exception.
1141     bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
1142                         !target_desc.configurable() &&
1143                         !target_desc.writable() &&
1144                         !trap_result->SameValue(*target_desc.value());
1145     if (inconsistent) {
1146       if (access_kind == kGet) {
1147         THROW_NEW_ERROR(
1148             isolate,
1149             NewTypeError(MessageTemplate::kProxyGetNonConfigurableData, name,
1150                          target_desc.value(), trap_result),
1151             Object);
1152       } else {
1153         isolate->Throw(*isolate->factory()->NewTypeError(
1154             MessageTemplate::kProxySetFrozenData, name));
1155         return MaybeHandle<Object>();
1156       }
1157     }
1158     // 10.b. If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]]
1159     //       is false and targetDesc.[[Get]] is undefined, then
1160     // 10.b.i. If trapResult is not undefined, throw a TypeError exception.
1161     if (access_kind == kGet) {
1162       inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
1163                      !target_desc.configurable() &&
1164                      target_desc.get()->IsUndefined(isolate) &&
1165                      !trap_result->IsUndefined(isolate);
1166     } else {
1167       inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
1168                      !target_desc.configurable() &&
1169                      target_desc.set()->IsUndefined(isolate);
1170     }
1171     if (inconsistent) {
1172       if (access_kind == kGet) {
1173         THROW_NEW_ERROR(
1174             isolate,
1175             NewTypeError(MessageTemplate::kProxyGetNonConfigurableAccessor,
1176                          name, trap_result),
1177             Object);
1178       } else {
1179         isolate->Throw(*isolate->factory()->NewTypeError(
1180             MessageTemplate::kProxySetFrozenAccessor, name));
1181         return MaybeHandle<Object>();
1182       }
1183     }
1184   }
1185   return isolate->factory()->undefined_value();
1186 }
1187 
1188 
GetDataProperty(LookupIterator * it)1189 Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it) {
1190   for (; it->IsFound(); it->Next()) {
1191     switch (it->state()) {
1192       case LookupIterator::INTERCEPTOR:
1193       case LookupIterator::NOT_FOUND:
1194       case LookupIterator::TRANSITION:
1195         UNREACHABLE();
1196       case LookupIterator::ACCESS_CHECK:
1197         // Support calling this method without an active context, but refuse
1198         // access to access-checked objects in that case.
1199         if (it->isolate()->context() != nullptr && it->HasAccess()) continue;
1200         V8_FALLTHROUGH;
1201       case LookupIterator::JSPROXY:
1202         it->NotFound();
1203         return it->isolate()->factory()->undefined_value();
1204       case LookupIterator::ACCESSOR:
1205         // TODO(verwaest): For now this doesn't call into AccessorInfo, since
1206         // clients don't need it. Update once relevant.
1207         it->NotFound();
1208         return it->isolate()->factory()->undefined_value();
1209       case LookupIterator::INTEGER_INDEXED_EXOTIC:
1210         return it->isolate()->factory()->undefined_value();
1211       case LookupIterator::DATA:
1212         return it->GetDataValue();
1213     }
1214   }
1215   return it->isolate()->factory()->undefined_value();
1216 }
1217 
1218 
ToInt32(int32_t * value)1219 bool Object::ToInt32(int32_t* value) {
1220   if (IsSmi()) {
1221     *value = Smi::ToInt(this);
1222     return true;
1223   }
1224   if (IsHeapNumber()) {
1225     double num = HeapNumber::cast(this)->value();
1226     // Check range before conversion to avoid undefined behavior.
1227     if (num >= kMinInt && num <= kMaxInt && FastI2D(FastD2I(num)) == num) {
1228       *value = FastD2I(num);
1229       return true;
1230     }
1231   }
1232   return false;
1233 }
1234 
GetOrCreateSharedFunctionInfo(Isolate * isolate,Handle<FunctionTemplateInfo> info,MaybeHandle<Name> maybe_name)1235 Handle<SharedFunctionInfo> FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(
1236     Isolate* isolate, Handle<FunctionTemplateInfo> info,
1237     MaybeHandle<Name> maybe_name) {
1238   Object* current_info = info->shared_function_info();
1239   if (current_info->IsSharedFunctionInfo()) {
1240     return handle(SharedFunctionInfo::cast(current_info), isolate);
1241   }
1242   Handle<Name> name;
1243   Handle<String> name_string;
1244   if (maybe_name.ToHandle(&name) && name->IsString()) {
1245     name_string = Handle<String>::cast(name);
1246   } else if (info->class_name()->IsString()) {
1247     name_string = handle(String::cast(info->class_name()), isolate);
1248   } else {
1249     name_string = isolate->factory()->empty_string();
1250   }
1251   FunctionKind function_kind;
1252   if (info->remove_prototype()) {
1253     function_kind = kConciseMethod;
1254   } else {
1255     function_kind = kNormalFunction;
1256   }
1257   Handle<SharedFunctionInfo> result =
1258       isolate->factory()->NewSharedFunctionInfoForApiFunction(name_string, info,
1259                                                               function_kind);
1260 
1261   result->set_length(info->length());
1262   result->DontAdaptArguments();
1263   DCHECK(result->IsApiFunction());
1264 
1265   info->set_shared_function_info(*result);
1266   return result;
1267 }
1268 
IsTemplateFor(Map * map)1269 bool FunctionTemplateInfo::IsTemplateFor(Map* map) {
1270   // There is a constraint on the object; check.
1271   if (!map->IsJSObjectMap()) return false;
1272   // Fetch the constructor function of the object.
1273   Object* cons_obj = map->GetConstructor();
1274   Object* type;
1275   if (cons_obj->IsJSFunction()) {
1276     JSFunction* fun = JSFunction::cast(cons_obj);
1277     type = fun->shared()->function_data();
1278   } else if (cons_obj->IsFunctionTemplateInfo()) {
1279     type = FunctionTemplateInfo::cast(cons_obj);
1280   } else {
1281     return false;
1282   }
1283   // Iterate through the chain of inheriting function templates to
1284   // see if the required one occurs.
1285   while (type->IsFunctionTemplateInfo()) {
1286     if (type == this) return true;
1287     type = FunctionTemplateInfo::cast(type)->parent_template();
1288   }
1289   // Didn't find the required type in the inheritance chain.
1290   return false;
1291 }
1292 
1293 
1294 // static
New(Isolate * isolate,int size)1295 Handle<TemplateList> TemplateList::New(Isolate* isolate, int size) {
1296   Handle<FixedArray> list =
1297       isolate->factory()->NewFixedArray(kLengthIndex + size);
1298   list->set(kLengthIndex, Smi::kZero);
1299   return Handle<TemplateList>::cast(list);
1300 }
1301 
1302 // static
Add(Isolate * isolate,Handle<TemplateList> list,Handle<i::Object> value)1303 Handle<TemplateList> TemplateList::Add(Isolate* isolate,
1304                                        Handle<TemplateList> list,
1305                                        Handle<i::Object> value) {
1306   STATIC_ASSERT(kFirstElementIndex == 1);
1307   int index = list->length() + 1;
1308   Handle<i::FixedArray> fixed_array = Handle<FixedArray>::cast(list);
1309   fixed_array = FixedArray::SetAndGrow(isolate, fixed_array, index, value);
1310   fixed_array->set(kLengthIndex, Smi::FromInt(index));
1311   return Handle<TemplateList>::cast(fixed_array);
1312 }
1313 
1314 // static
New(Handle<JSFunction> constructor,Handle<JSReceiver> new_target,Handle<AllocationSite> site)1315 MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor,
1316                                     Handle<JSReceiver> new_target,
1317                                     Handle<AllocationSite> site) {
1318   // If called through new, new.target can be:
1319   // - a subclass of constructor,
1320   // - a proxy wrapper around constructor, or
1321   // - the constructor itself.
1322   // If called through Reflect.construct, it's guaranteed to be a constructor.
1323   Isolate* const isolate = constructor->GetIsolate();
1324   DCHECK(constructor->IsConstructor());
1325   DCHECK(new_target->IsConstructor());
1326   DCHECK(!constructor->has_initial_map() ||
1327          constructor->initial_map()->instance_type() != JS_FUNCTION_TYPE);
1328 
1329   Handle<Map> initial_map;
1330   ASSIGN_RETURN_ON_EXCEPTION(
1331       isolate, initial_map,
1332       JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject);
1333   Handle<JSObject> result =
1334       isolate->factory()->NewJSObjectFromMap(initial_map, NOT_TENURED, site);
1335   if (initial_map->is_dictionary_map()) {
1336     Handle<NameDictionary> dictionary =
1337         NameDictionary::New(isolate, NameDictionary::kInitialCapacity);
1338     result->SetProperties(*dictionary);
1339   }
1340   isolate->counters()->constructed_objects()->Increment();
1341   isolate->counters()->constructed_objects_runtime()->Increment();
1342   return result;
1343 }
1344 
1345 // 9.1.12 ObjectCreate ( proto [ , internalSlotsList ] )
1346 // Notice: This is NOT 19.1.2.2 Object.create ( O, Properties )
ObjectCreate(Isolate * isolate,Handle<Object> prototype)1347 MaybeHandle<JSObject> JSObject::ObjectCreate(Isolate* isolate,
1348                                              Handle<Object> prototype) {
1349   // Generate the map with the specified {prototype} based on the Object
1350   // function's initial map from the current native context.
1351   // TODO(bmeurer): Use a dedicated cache for Object.create; think about
1352   // slack tracking for Object.create.
1353   Handle<Map> map =
1354       Map::GetObjectCreateMap(isolate, Handle<HeapObject>::cast(prototype));
1355 
1356   // Actually allocate the object.
1357   Handle<JSObject> object;
1358   if (map->is_dictionary_map()) {
1359     object = isolate->factory()->NewSlowJSObjectFromMap(map);
1360   } else {
1361     object = isolate->factory()->NewJSObjectFromMap(map);
1362   }
1363   return object;
1364 }
1365 
EnsureWritableFastElements(Handle<JSObject> object)1366 void JSObject::EnsureWritableFastElements(Handle<JSObject> object) {
1367   DCHECK(object->HasSmiOrObjectElements() ||
1368          object->HasFastStringWrapperElements());
1369   FixedArray* raw_elems = FixedArray::cast(object->elements());
1370   Heap* heap = object->GetHeap();
1371   if (raw_elems->map() != ReadOnlyRoots(heap).fixed_cow_array_map()) return;
1372   Isolate* isolate = heap->isolate();
1373   Handle<FixedArray> elems(raw_elems, isolate);
1374   Handle<FixedArray> writable_elems = isolate->factory()->CopyFixedArrayWithMap(
1375       elems, isolate->factory()->fixed_array_map());
1376   object->set_elements(*writable_elems);
1377   isolate->counters()->cow_arrays_converted()->Increment();
1378 }
1379 
GetHeaderSize(InstanceType type,bool function_has_prototype_slot)1380 int JSObject::GetHeaderSize(InstanceType type,
1381                             bool function_has_prototype_slot) {
1382   switch (type) {
1383     case JS_OBJECT_TYPE:
1384     case JS_API_OBJECT_TYPE:
1385     case JS_SPECIAL_API_OBJECT_TYPE:
1386       return JSObject::kHeaderSize;
1387     case JS_GENERATOR_OBJECT_TYPE:
1388       return JSGeneratorObject::kSize;
1389     case JS_ASYNC_GENERATOR_OBJECT_TYPE:
1390       return JSAsyncGeneratorObject::kSize;
1391     case JS_GLOBAL_PROXY_TYPE:
1392       return JSGlobalProxy::kSize;
1393     case JS_GLOBAL_OBJECT_TYPE:
1394       return JSGlobalObject::kSize;
1395     case JS_BOUND_FUNCTION_TYPE:
1396       return JSBoundFunction::kSize;
1397     case JS_FUNCTION_TYPE:
1398       return JSFunction::GetHeaderSize(function_has_prototype_slot);
1399     case JS_VALUE_TYPE:
1400       return JSValue::kSize;
1401     case JS_DATE_TYPE:
1402       return JSDate::kSize;
1403     case JS_ARRAY_TYPE:
1404       return JSArray::kSize;
1405     case JS_ARRAY_BUFFER_TYPE:
1406       return JSArrayBuffer::kSize;
1407     case JS_ARRAY_ITERATOR_TYPE:
1408       return JSArrayIterator::kSize;
1409     case JS_TYPED_ARRAY_TYPE:
1410       return JSTypedArray::kSize;
1411     case JS_DATA_VIEW_TYPE:
1412       return JSDataView::kSize;
1413     case JS_SET_TYPE:
1414       return JSSet::kSize;
1415     case JS_MAP_TYPE:
1416       return JSMap::kSize;
1417     case JS_SET_KEY_VALUE_ITERATOR_TYPE:
1418     case JS_SET_VALUE_ITERATOR_TYPE:
1419       return JSSetIterator::kSize;
1420     case JS_MAP_KEY_ITERATOR_TYPE:
1421     case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
1422     case JS_MAP_VALUE_ITERATOR_TYPE:
1423       return JSMapIterator::kSize;
1424     case JS_WEAK_MAP_TYPE:
1425       return JSWeakMap::kSize;
1426     case JS_WEAK_SET_TYPE:
1427       return JSWeakSet::kSize;
1428     case JS_PROMISE_TYPE:
1429       return JSPromise::kSize;
1430     case JS_REGEXP_TYPE:
1431       return JSRegExp::kSize;
1432     case JS_REGEXP_STRING_ITERATOR_TYPE:
1433       return JSRegExpStringIterator::kSize;
1434     case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
1435       return JSObject::kHeaderSize;
1436     case JS_MESSAGE_OBJECT_TYPE:
1437       return JSMessageObject::kSize;
1438     case JS_ARGUMENTS_TYPE:
1439       return JSObject::kHeaderSize;
1440     case JS_ERROR_TYPE:
1441       return JSObject::kHeaderSize;
1442     case JS_STRING_ITERATOR_TYPE:
1443       return JSStringIterator::kSize;
1444     case JS_MODULE_NAMESPACE_TYPE:
1445       return JSModuleNamespace::kHeaderSize;
1446 #ifdef V8_INTL_SUPPORT
1447     case JS_INTL_COLLATOR_TYPE:
1448       return JSCollator::kSize;
1449     case JS_INTL_LIST_FORMAT_TYPE:
1450       return JSListFormat::kSize;
1451     case JS_INTL_LOCALE_TYPE:
1452       return JSLocale::kSize;
1453     case JS_INTL_PLURAL_RULES_TYPE:
1454       return JSPluralRules::kSize;
1455     case JS_INTL_RELATIVE_TIME_FORMAT_TYPE:
1456       return JSRelativeTimeFormat::kSize;
1457 #endif  // V8_INTL_SUPPORT
1458     case WASM_GLOBAL_TYPE:
1459       return WasmGlobalObject::kSize;
1460     case WASM_INSTANCE_TYPE:
1461       return WasmInstanceObject::kSize;
1462     case WASM_MEMORY_TYPE:
1463       return WasmMemoryObject::kSize;
1464     case WASM_MODULE_TYPE:
1465       return WasmModuleObject::kSize;
1466     case WASM_TABLE_TYPE:
1467       return WasmTableObject::kSize;
1468     default:
1469       UNREACHABLE();
1470   }
1471 }
1472 
1473 // ES6 9.5.1
1474 // static
GetPrototype(Handle<JSProxy> proxy)1475 MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
1476   Isolate* isolate = proxy->GetIsolate();
1477   Handle<String> trap_name = isolate->factory()->getPrototypeOf_string();
1478 
1479   STACK_CHECK(isolate, MaybeHandle<Object>());
1480 
1481   // 1. Let handler be the value of the [[ProxyHandler]] internal slot.
1482   // 2. If handler is null, throw a TypeError exception.
1483   // 3. Assert: Type(handler) is Object.
1484   // 4. Let target be the value of the [[ProxyTarget]] internal slot.
1485   if (proxy->IsRevoked()) {
1486     THROW_NEW_ERROR(isolate,
1487                     NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1488                     Object);
1489   }
1490   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
1491   Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
1492 
1493   // 5. Let trap be ? GetMethod(handler, "getPrototypeOf").
1494   Handle<Object> trap;
1495   ASSIGN_RETURN_ON_EXCEPTION(isolate, trap, GetMethod(handler, trap_name),
1496                              Object);
1497   // 6. If trap is undefined, then return target.[[GetPrototypeOf]]().
1498   if (trap->IsUndefined(isolate)) {
1499     return JSReceiver::GetPrototype(isolate, target);
1500   }
1501   // 7. Let handlerProto be ? Call(trap, handler, «target»).
1502   Handle<Object> argv[] = {target};
1503   Handle<Object> handler_proto;
1504   ASSIGN_RETURN_ON_EXCEPTION(
1505       isolate, handler_proto,
1506       Execution::Call(isolate, trap, handler, arraysize(argv), argv), Object);
1507   // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError.
1508   if (!(handler_proto->IsJSReceiver() || handler_proto->IsNull(isolate))) {
1509     THROW_NEW_ERROR(isolate,
1510                     NewTypeError(MessageTemplate::kProxyGetPrototypeOfInvalid),
1511                     Object);
1512   }
1513   // 9. Let extensibleTarget be ? IsExtensible(target).
1514   Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
1515   MAYBE_RETURN_NULL(is_extensible);
1516   // 10. If extensibleTarget is true, return handlerProto.
1517   if (is_extensible.FromJust()) return handler_proto;
1518   // 11. Let targetProto be ? target.[[GetPrototypeOf]]().
1519   Handle<Object> target_proto;
1520   ASSIGN_RETURN_ON_EXCEPTION(isolate, target_proto,
1521                              JSReceiver::GetPrototype(isolate, target), Object);
1522   // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError.
1523   if (!handler_proto->SameValue(*target_proto)) {
1524     THROW_NEW_ERROR(
1525         isolate,
1526         NewTypeError(MessageTemplate::kProxyGetPrototypeOfNonExtensible),
1527         Object);
1528   }
1529   // 13. Return handlerProto.
1530   return handler_proto;
1531 }
1532 
GetPropertyWithAccessor(LookupIterator * it)1533 MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) {
1534   Isolate* isolate = it->isolate();
1535   Handle<Object> structure = it->GetAccessors();
1536   Handle<Object> receiver = it->GetReceiver();
1537   // In case of global IC, the receiver is the global object. Replace by the
1538   // global proxy.
1539   if (receiver->IsJSGlobalObject()) {
1540     receiver = handle(JSGlobalObject::cast(*receiver)->global_proxy(), isolate);
1541   }
1542 
1543   // We should never get here to initialize a const with the hole value since a
1544   // const declaration would conflict with the getter.
1545   DCHECK(!structure->IsForeign());
1546 
1547   // API style callbacks.
1548   Handle<JSObject> holder = it->GetHolder<JSObject>();
1549   if (structure->IsAccessorInfo()) {
1550     Handle<Name> name = it->GetName();
1551     Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
1552     if (!info->IsCompatibleReceiver(*receiver)) {
1553       THROW_NEW_ERROR(isolate,
1554                       NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
1555                                    name, receiver),
1556                       Object);
1557     }
1558 
1559     if (!info->has_getter()) return isolate->factory()->undefined_value();
1560 
1561     if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1562       ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver,
1563                                  Object::ConvertReceiver(isolate, receiver),
1564                                  Object);
1565     }
1566 
1567     PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1568                                    kDontThrow);
1569     Handle<Object> result = args.CallAccessorGetter(info, name);
1570     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1571     if (result.is_null()) return isolate->factory()->undefined_value();
1572     Handle<Object> reboxed_result = handle(*result, isolate);
1573     if (info->replace_on_access() && receiver->IsJSReceiver()) {
1574       RETURN_ON_EXCEPTION(isolate,
1575                           Accessors::ReplaceAccessorWithDataProperty(
1576                               receiver, holder, name, result),
1577                           Object);
1578     }
1579     return reboxed_result;
1580   }
1581 
1582   // AccessorPair with 'cached' private property.
1583   if (it->TryLookupCachedProperty()) {
1584     return Object::GetProperty(it);
1585   }
1586 
1587   // Regular accessor.
1588   Handle<Object> getter(AccessorPair::cast(*structure)->getter(), isolate);
1589   if (getter->IsFunctionTemplateInfo()) {
1590     SaveContext save(isolate);
1591     isolate->set_context(*holder->GetCreationContext());
1592     return Builtins::InvokeApiFunction(
1593         isolate, false, Handle<FunctionTemplateInfo>::cast(getter), receiver, 0,
1594         nullptr, isolate->factory()->undefined_value());
1595   } else if (getter->IsCallable()) {
1596     // TODO(rossberg): nicer would be to cast to some JSCallable here...
1597     return Object::GetPropertyWithDefinedGetter(
1598         receiver, Handle<JSReceiver>::cast(getter));
1599   }
1600   // Getter is not a function.
1601   return isolate->factory()->undefined_value();
1602 }
1603 
1604 // static
redirect(Address address,AccessorComponent component)1605 Address AccessorInfo::redirect(Address address, AccessorComponent component) {
1606   ApiFunction fun(address);
1607   DCHECK_EQ(ACCESSOR_GETTER, component);
1608   ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
1609   return ExternalReference::Create(&fun, type).address();
1610 }
1611 
redirected_getter() const1612 Address AccessorInfo::redirected_getter() const {
1613   Address accessor = v8::ToCData<Address>(getter());
1614   if (accessor == kNullAddress) return kNullAddress;
1615   return redirect(accessor, ACCESSOR_GETTER);
1616 }
1617 
redirected_callback() const1618 Address CallHandlerInfo::redirected_callback() const {
1619   Address address = v8::ToCData<Address>(callback());
1620   ApiFunction fun(address);
1621   ExternalReference::Type type = ExternalReference::DIRECT_API_CALL;
1622   return ExternalReference::Create(&fun, type).address();
1623 }
1624 
IsCompatibleReceiverMap(Handle<AccessorInfo> info,Handle<Map> map)1625 bool AccessorInfo::IsCompatibleReceiverMap(Handle<AccessorInfo> info,
1626                                            Handle<Map> map) {
1627   if (!info->HasExpectedReceiverType()) return true;
1628   if (!map->IsJSObjectMap()) return false;
1629   return FunctionTemplateInfo::cast(info->expected_receiver_type())
1630       ->IsTemplateFor(*map);
1631 }
1632 
SetPropertyWithAccessor(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)1633 Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it,
1634                                             Handle<Object> value,
1635                                             ShouldThrow should_throw) {
1636   Isolate* isolate = it->isolate();
1637   Handle<Object> structure = it->GetAccessors();
1638   Handle<Object> receiver = it->GetReceiver();
1639   // In case of global IC, the receiver is the global object. Replace by the
1640   // global proxy.
1641   if (receiver->IsJSGlobalObject()) {
1642     receiver = handle(JSGlobalObject::cast(*receiver)->global_proxy(), isolate);
1643   }
1644 
1645   // We should never get here to initialize a const with the hole value since a
1646   // const declaration would conflict with the setter.
1647   DCHECK(!structure->IsForeign());
1648 
1649   // API style callbacks.
1650   Handle<JSObject> holder = it->GetHolder<JSObject>();
1651   if (structure->IsAccessorInfo()) {
1652     Handle<Name> name = it->GetName();
1653     Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
1654     if (!info->IsCompatibleReceiver(*receiver)) {
1655       isolate->Throw(*isolate->factory()->NewTypeError(
1656           MessageTemplate::kIncompatibleMethodReceiver, name, receiver));
1657       return Nothing<bool>();
1658     }
1659 
1660     if (!info->has_setter()) {
1661       // TODO(verwaest): We should not get here anymore once all AccessorInfos
1662       // are marked as special_data_property. They cannot both be writable and
1663       // not have a setter.
1664       return Just(true);
1665     }
1666 
1667     if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1668       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1669           isolate, receiver, Object::ConvertReceiver(isolate, receiver),
1670           Nothing<bool>());
1671     }
1672 
1673     // The actual type of setter callback is either
1674     // v8::AccessorNameSetterCallback or
1675     // i::Accesors::AccessorNameBooleanSetterCallback, depending on whether the
1676     // AccessorInfo was created by the API or internally (see accessors.cc).
1677     // Here we handle both cases using GenericNamedPropertySetterCallback and
1678     // its Call method.
1679     PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1680                                    should_throw);
1681     Handle<Object> result = args.CallAccessorSetter(info, name, value);
1682     // In the case of AccessorNameSetterCallback, we know that the result value
1683     // cannot have been set, so the result of Call will be null.  In the case of
1684     // AccessorNameBooleanSetterCallback, the result will either be null
1685     // (signalling an exception) or a boolean Oddball.
1686     RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1687     if (result.is_null()) return Just(true);
1688     DCHECK(result->BooleanValue(isolate) || should_throw == kDontThrow);
1689     return Just(result->BooleanValue(isolate));
1690   }
1691 
1692   // Regular accessor.
1693   Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
1694   if (setter->IsFunctionTemplateInfo()) {
1695     SaveContext save(isolate);
1696     isolate->set_context(*holder->GetCreationContext());
1697     Handle<Object> argv[] = {value};
1698     RETURN_ON_EXCEPTION_VALUE(
1699         isolate, Builtins::InvokeApiFunction(
1700                      isolate, false, Handle<FunctionTemplateInfo>::cast(setter),
1701                      receiver, arraysize(argv), argv,
1702                      isolate->factory()->undefined_value()),
1703         Nothing<bool>());
1704     return Just(true);
1705   } else if (setter->IsCallable()) {
1706     // TODO(rossberg): nicer would be to cast to some JSCallable here...
1707     return SetPropertyWithDefinedSetter(
1708         receiver, Handle<JSReceiver>::cast(setter), value, should_throw);
1709   }
1710 
1711   RETURN_FAILURE(isolate, should_throw,
1712                  NewTypeError(MessageTemplate::kNoSetterInCallback,
1713                               it->GetName(), it->GetHolder<JSObject>()));
1714 }
1715 
1716 
GetPropertyWithDefinedGetter(Handle<Object> receiver,Handle<JSReceiver> getter)1717 MaybeHandle<Object> Object::GetPropertyWithDefinedGetter(
1718     Handle<Object> receiver,
1719     Handle<JSReceiver> getter) {
1720   Isolate* isolate = getter->GetIsolate();
1721 
1722   // Platforms with simulators like arm/arm64 expose a funny issue. If the
1723   // simulator has a separate JS stack pointer from the C++ stack pointer, it
1724   // can miss C++ stack overflows in the stack guard at the start of JavaScript
1725   // functions. It would be very expensive to check the C++ stack pointer at
1726   // that location. The best solution seems to be to break the impasse by
1727   // adding checks at possible recursion points. What's more, we don't put
1728   // this stack check behind the USE_SIMULATOR define in order to keep
1729   // behavior the same between hardware and simulators.
1730   StackLimitCheck check(isolate);
1731   if (check.JsHasOverflowed()) {
1732     isolate->StackOverflow();
1733     return MaybeHandle<Object>();
1734   }
1735 
1736   return Execution::Call(isolate, getter, receiver, 0, nullptr);
1737 }
1738 
1739 
SetPropertyWithDefinedSetter(Handle<Object> receiver,Handle<JSReceiver> setter,Handle<Object> value,ShouldThrow should_throw)1740 Maybe<bool> Object::SetPropertyWithDefinedSetter(Handle<Object> receiver,
1741                                                  Handle<JSReceiver> setter,
1742                                                  Handle<Object> value,
1743                                                  ShouldThrow should_throw) {
1744   Isolate* isolate = setter->GetIsolate();
1745 
1746   Handle<Object> argv[] = { value };
1747   RETURN_ON_EXCEPTION_VALUE(isolate, Execution::Call(isolate, setter, receiver,
1748                                                      arraysize(argv), argv),
1749                             Nothing<bool>());
1750   return Just(true);
1751 }
1752 
1753 
1754 // static
AllCanRead(LookupIterator * it)1755 bool JSObject::AllCanRead(LookupIterator* it) {
1756   // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of
1757   // which have already been checked.
1758   DCHECK(it->state() == LookupIterator::ACCESS_CHECK ||
1759          it->state() == LookupIterator::INTERCEPTOR);
1760   for (it->Next(); it->IsFound(); it->Next()) {
1761     if (it->state() == LookupIterator::ACCESSOR) {
1762       auto accessors = it->GetAccessors();
1763       if (accessors->IsAccessorInfo()) {
1764         if (AccessorInfo::cast(*accessors)->all_can_read()) return true;
1765       }
1766     } else if (it->state() == LookupIterator::INTERCEPTOR) {
1767       if (it->GetInterceptor()->all_can_read()) return true;
1768     } else if (it->state() == LookupIterator::JSPROXY) {
1769       // Stop lookupiterating. And no, AllCanNotRead.
1770       return false;
1771     }
1772   }
1773   return false;
1774 }
1775 
1776 namespace {
1777 
GetPropertyWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor,bool * done)1778 MaybeHandle<Object> GetPropertyWithInterceptorInternal(
1779     LookupIterator* it, Handle<InterceptorInfo> interceptor, bool* done) {
1780   *done = false;
1781   Isolate* isolate = it->isolate();
1782   // Make sure that the top context does not change when doing callbacks or
1783   // interceptor calls.
1784   AssertNoContextChange ncc(isolate);
1785 
1786   if (interceptor->getter()->IsUndefined(isolate)) {
1787     return isolate->factory()->undefined_value();
1788   }
1789 
1790   Handle<JSObject> holder = it->GetHolder<JSObject>();
1791   Handle<Object> result;
1792   Handle<Object> receiver = it->GetReceiver();
1793   if (!receiver->IsJSReceiver()) {
1794     ASSIGN_RETURN_ON_EXCEPTION(
1795         isolate, receiver, Object::ConvertReceiver(isolate, receiver), Object);
1796   }
1797   PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1798                                  *holder, kDontThrow);
1799 
1800   if (it->IsElement()) {
1801     result = args.CallIndexedGetter(interceptor, it->index());
1802   } else {
1803     result = args.CallNamedGetter(interceptor, it->name());
1804   }
1805 
1806   RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1807   if (result.is_null()) return isolate->factory()->undefined_value();
1808   *done = true;
1809   // Rebox handle before return
1810   return handle(*result, isolate);
1811 }
1812 
GetPropertyAttributesWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor)1813 Maybe<PropertyAttributes> GetPropertyAttributesWithInterceptorInternal(
1814     LookupIterator* it, Handle<InterceptorInfo> interceptor) {
1815   Isolate* isolate = it->isolate();
1816   // Make sure that the top context does not change when doing
1817   // callbacks or interceptor calls.
1818   AssertNoContextChange ncc(isolate);
1819   HandleScope scope(isolate);
1820 
1821   Handle<JSObject> holder = it->GetHolder<JSObject>();
1822   DCHECK_IMPLIES(!it->IsElement() && it->name()->IsSymbol(),
1823                  interceptor->can_intercept_symbols());
1824   Handle<Object> receiver = it->GetReceiver();
1825   if (!receiver->IsJSReceiver()) {
1826     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1827                                      Object::ConvertReceiver(isolate, receiver),
1828                                      Nothing<PropertyAttributes>());
1829   }
1830   PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1831                                  *holder, kDontThrow);
1832   if (!interceptor->query()->IsUndefined(isolate)) {
1833     Handle<Object> result;
1834     if (it->IsElement()) {
1835       result = args.CallIndexedQuery(interceptor, it->index());
1836     } else {
1837       result = args.CallNamedQuery(interceptor, it->name());
1838     }
1839     if (!result.is_null()) {
1840       int32_t value;
1841       CHECK(result->ToInt32(&value));
1842       return Just(static_cast<PropertyAttributes>(value));
1843     }
1844   } else if (!interceptor->getter()->IsUndefined(isolate)) {
1845     // TODO(verwaest): Use GetPropertyWithInterceptor?
1846     Handle<Object> result;
1847     if (it->IsElement()) {
1848       result = args.CallIndexedGetter(interceptor, it->index());
1849     } else {
1850       result = args.CallNamedGetter(interceptor, it->name());
1851     }
1852     if (!result.is_null()) return Just(DONT_ENUM);
1853   }
1854 
1855   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
1856   return Just(ABSENT);
1857 }
1858 
SetPropertyWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor,ShouldThrow should_throw,Handle<Object> value)1859 Maybe<bool> SetPropertyWithInterceptorInternal(
1860     LookupIterator* it, Handle<InterceptorInfo> interceptor,
1861     ShouldThrow should_throw, Handle<Object> value) {
1862   Isolate* isolate = it->isolate();
1863   // Make sure that the top context does not change when doing callbacks or
1864   // interceptor calls.
1865   AssertNoContextChange ncc(isolate);
1866 
1867   if (interceptor->setter()->IsUndefined(isolate)) return Just(false);
1868 
1869   Handle<JSObject> holder = it->GetHolder<JSObject>();
1870   bool result;
1871   Handle<Object> receiver = it->GetReceiver();
1872   if (!receiver->IsJSReceiver()) {
1873     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1874                                      Object::ConvertReceiver(isolate, receiver),
1875                                      Nothing<bool>());
1876   }
1877   PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1878                                  *holder, should_throw);
1879 
1880   if (it->IsElement()) {
1881     // TODO(neis): In the future, we may want to actually return the
1882     // interceptor's result, which then should be a boolean.
1883     result = !args.CallIndexedSetter(interceptor, it->index(), value).is_null();
1884   } else {
1885     result = !args.CallNamedSetter(interceptor, it->name(), value).is_null();
1886   }
1887 
1888   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1889   return Just(result);
1890 }
1891 
DefinePropertyWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor,ShouldThrow should_throw,PropertyDescriptor & desc)1892 Maybe<bool> DefinePropertyWithInterceptorInternal(
1893     LookupIterator* it, Handle<InterceptorInfo> interceptor,
1894     ShouldThrow should_throw, PropertyDescriptor& desc) {
1895   Isolate* isolate = it->isolate();
1896   // Make sure that the top context does not change when doing callbacks or
1897   // interceptor calls.
1898   AssertNoContextChange ncc(isolate);
1899 
1900   if (interceptor->definer()->IsUndefined(isolate)) return Just(false);
1901 
1902   Handle<JSObject> holder = it->GetHolder<JSObject>();
1903   bool result;
1904   Handle<Object> receiver = it->GetReceiver();
1905   if (!receiver->IsJSReceiver()) {
1906     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1907                                      Object::ConvertReceiver(isolate, receiver),
1908                                      Nothing<bool>());
1909   }
1910   PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1911                                  *holder, should_throw);
1912 
1913   std::unique_ptr<v8::PropertyDescriptor> descriptor(
1914       new v8::PropertyDescriptor());
1915   if (PropertyDescriptor::IsAccessorDescriptor(&desc)) {
1916     descriptor.reset(new v8::PropertyDescriptor(
1917         v8::Utils::ToLocal(desc.get()), v8::Utils::ToLocal(desc.set())));
1918   } else if (PropertyDescriptor::IsDataDescriptor(&desc)) {
1919     if (desc.has_writable()) {
1920       descriptor.reset(new v8::PropertyDescriptor(
1921           v8::Utils::ToLocal(desc.value()), desc.writable()));
1922     } else {
1923       descriptor.reset(
1924           new v8::PropertyDescriptor(v8::Utils::ToLocal(desc.value())));
1925     }
1926   }
1927   if (desc.has_enumerable()) {
1928     descriptor->set_enumerable(desc.enumerable());
1929   }
1930   if (desc.has_configurable()) {
1931     descriptor->set_configurable(desc.configurable());
1932   }
1933 
1934   if (it->IsElement()) {
1935     result = !args.CallIndexedDefiner(interceptor, it->index(), *descriptor)
1936                   .is_null();
1937   } else {
1938     result =
1939         !args.CallNamedDefiner(interceptor, it->name(), *descriptor).is_null();
1940   }
1941 
1942   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1943   return Just(result);
1944 }
1945 
1946 }  // namespace
1947 
GetPropertyWithFailedAccessCheck(LookupIterator * it)1948 MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
1949     LookupIterator* it) {
1950   Isolate* isolate = it->isolate();
1951   Handle<JSObject> checked = it->GetHolder<JSObject>();
1952   Handle<InterceptorInfo> interceptor =
1953       it->GetInterceptorForFailedAccessCheck();
1954   if (interceptor.is_null()) {
1955     while (AllCanRead(it)) {
1956       if (it->state() == LookupIterator::ACCESSOR) {
1957         return GetPropertyWithAccessor(it);
1958       }
1959       DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
1960       bool done;
1961       Handle<Object> result;
1962       ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
1963                                  GetPropertyWithInterceptor(it, &done), Object);
1964       if (done) return result;
1965     }
1966 
1967   } else {
1968     Handle<Object> result;
1969     bool done;
1970     ASSIGN_RETURN_ON_EXCEPTION(
1971         isolate, result,
1972         GetPropertyWithInterceptorInternal(it, interceptor, &done), Object);
1973     if (done) return result;
1974   }
1975 
1976   // Cross-Origin [[Get]] of Well-Known Symbols does not throw, and returns
1977   // undefined.
1978   Handle<Name> name = it->GetName();
1979   if (name->IsSymbol() && Symbol::cast(*name)->is_well_known_symbol()) {
1980     return it->factory()->undefined_value();
1981   }
1982 
1983   isolate->ReportFailedAccessCheck(checked);
1984   RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1985   return it->factory()->undefined_value();
1986 }
1987 
1988 
GetPropertyAttributesWithFailedAccessCheck(LookupIterator * it)1989 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
1990     LookupIterator* it) {
1991   Isolate* isolate = it->isolate();
1992   Handle<JSObject> checked = it->GetHolder<JSObject>();
1993   Handle<InterceptorInfo> interceptor =
1994       it->GetInterceptorForFailedAccessCheck();
1995   if (interceptor.is_null()) {
1996     while (AllCanRead(it)) {
1997       if (it->state() == LookupIterator::ACCESSOR) {
1998         return Just(it->property_attributes());
1999       }
2000       DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
2001       auto result = GetPropertyAttributesWithInterceptor(it);
2002       if (isolate->has_scheduled_exception()) break;
2003       if (result.IsJust() && result.FromJust() != ABSENT) return result;
2004     }
2005   } else {
2006     Maybe<PropertyAttributes> result =
2007         GetPropertyAttributesWithInterceptorInternal(it, interceptor);
2008     if (isolate->has_pending_exception()) return Nothing<PropertyAttributes>();
2009     if (result.FromMaybe(ABSENT) != ABSENT) return result;
2010   }
2011   isolate->ReportFailedAccessCheck(checked);
2012   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
2013   return Just(ABSENT);
2014 }
2015 
2016 
2017 // static
AllCanWrite(LookupIterator * it)2018 bool JSObject::AllCanWrite(LookupIterator* it) {
2019   for (; it->IsFound() && it->state() != LookupIterator::JSPROXY; it->Next()) {
2020     if (it->state() == LookupIterator::ACCESSOR) {
2021       Handle<Object> accessors = it->GetAccessors();
2022       if (accessors->IsAccessorInfo()) {
2023         if (AccessorInfo::cast(*accessors)->all_can_write()) return true;
2024       }
2025     }
2026   }
2027   return false;
2028 }
2029 
2030 
SetPropertyWithFailedAccessCheck(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)2031 Maybe<bool> JSObject::SetPropertyWithFailedAccessCheck(
2032     LookupIterator* it, Handle<Object> value, ShouldThrow should_throw) {
2033   Isolate* isolate = it->isolate();
2034   Handle<JSObject> checked = it->GetHolder<JSObject>();
2035   Handle<InterceptorInfo> interceptor =
2036       it->GetInterceptorForFailedAccessCheck();
2037   if (interceptor.is_null()) {
2038     if (AllCanWrite(it)) {
2039       return SetPropertyWithAccessor(it, value, should_throw);
2040     }
2041   } else {
2042     Maybe<bool> result = SetPropertyWithInterceptorInternal(
2043         it, interceptor, should_throw, value);
2044     if (isolate->has_pending_exception()) return Nothing<bool>();
2045     if (result.IsJust()) return result;
2046   }
2047   isolate->ReportFailedAccessCheck(checked);
2048   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
2049   return Just(true);
2050 }
2051 
2052 
SetNormalizedProperty(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyDetails details)2053 void JSObject::SetNormalizedProperty(Handle<JSObject> object,
2054                                      Handle<Name> name,
2055                                      Handle<Object> value,
2056                                      PropertyDetails details) {
2057   DCHECK(!object->HasFastProperties());
2058   DCHECK(name->IsUniqueName());
2059   Isolate* isolate = object->GetIsolate();
2060 
2061   uint32_t hash = name->Hash();
2062 
2063   if (object->IsJSGlobalObject()) {
2064     Handle<JSGlobalObject> global_obj = Handle<JSGlobalObject>::cast(object);
2065     Handle<GlobalDictionary> dictionary(global_obj->global_dictionary(),
2066                                         isolate);
2067     int entry = dictionary->FindEntry(ReadOnlyRoots(isolate), name, hash);
2068 
2069     if (entry == GlobalDictionary::kNotFound) {
2070       DCHECK_IMPLIES(global_obj->map()->is_prototype_map(),
2071                      Map::IsPrototypeChainInvalidated(global_obj->map()));
2072       auto cell = isolate->factory()->NewPropertyCell(name);
2073       cell->set_value(*value);
2074       auto cell_type = value->IsUndefined(isolate)
2075                            ? PropertyCellType::kUndefined
2076                            : PropertyCellType::kConstant;
2077       details = details.set_cell_type(cell_type);
2078       value = cell;
2079       dictionary =
2080           GlobalDictionary::Add(isolate, dictionary, name, value, details);
2081       global_obj->set_global_dictionary(*dictionary);
2082     } else {
2083       Handle<PropertyCell> cell = PropertyCell::PrepareForValue(
2084           isolate, dictionary, entry, value, details);
2085       cell->set_value(*value);
2086     }
2087   } else {
2088     Handle<NameDictionary> dictionary(object->property_dictionary(), isolate);
2089 
2090     int entry = dictionary->FindEntry(isolate, name);
2091     if (entry == NameDictionary::kNotFound) {
2092       DCHECK_IMPLIES(object->map()->is_prototype_map(),
2093                      Map::IsPrototypeChainInvalidated(object->map()));
2094       dictionary =
2095           NameDictionary::Add(isolate, dictionary, name, value, details);
2096       object->SetProperties(*dictionary);
2097     } else {
2098       PropertyDetails original_details = dictionary->DetailsAt(entry);
2099       int enumeration_index = original_details.dictionary_index();
2100       DCHECK_GT(enumeration_index, 0);
2101       details = details.set_index(enumeration_index);
2102       dictionary->SetEntry(isolate, entry, *name, *value, details);
2103     }
2104   }
2105 }
2106 
2107 // static
HasInPrototypeChain(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> proto)2108 Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate,
2109                                             Handle<JSReceiver> object,
2110                                             Handle<Object> proto) {
2111   PrototypeIterator iter(isolate, object, kStartAtReceiver);
2112   while (true) {
2113     if (!iter.AdvanceFollowingProxies()) return Nothing<bool>();
2114     if (iter.IsAtEnd()) return Just(false);
2115     if (PrototypeIterator::GetCurrent(iter).is_identical_to(proto)) {
2116       return Just(true);
2117     }
2118   }
2119 }
2120 
2121 namespace {
2122 
HasExcludedProperty(const ScopedVector<Handle<Object>> * excluded_properties,Handle<Object> search_element)2123 bool HasExcludedProperty(
2124     const ScopedVector<Handle<Object>>* excluded_properties,
2125     Handle<Object> search_element) {
2126   // TODO(gsathya): Change this to be a hashtable.
2127   for (int i = 0; i < excluded_properties->length(); i++) {
2128     if (search_element->SameValue(*excluded_properties->at(i))) {
2129       return true;
2130     }
2131   }
2132 
2133   return false;
2134 }
2135 
FastAssign(Handle<JSReceiver> target,Handle<Object> source,const ScopedVector<Handle<Object>> * excluded_properties,bool use_set)2136 V8_WARN_UNUSED_RESULT Maybe<bool> FastAssign(
2137     Handle<JSReceiver> target, Handle<Object> source,
2138     const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) {
2139   // Non-empty strings are the only non-JSReceivers that need to be handled
2140   // explicitly by Object.assign.
2141   if (!source->IsJSReceiver()) {
2142     return Just(!source->IsString() || String::cast(*source)->length() == 0);
2143   }
2144 
2145   // If the target is deprecated, the object will be updated on first store. If
2146   // the source for that store equals the target, this will invalidate the
2147   // cached representation of the source. Preventively upgrade the target.
2148   // Do this on each iteration since any property load could cause deprecation.
2149   if (target->map()->is_deprecated()) {
2150     JSObject::MigrateInstance(Handle<JSObject>::cast(target));
2151   }
2152 
2153   Isolate* isolate = target->GetIsolate();
2154   Handle<Map> map(JSReceiver::cast(*source)->map(), isolate);
2155 
2156   if (!map->IsJSObjectMap()) return Just(false);
2157   if (!map->OnlyHasSimpleProperties()) return Just(false);
2158 
2159   Handle<JSObject> from = Handle<JSObject>::cast(source);
2160   if (from->elements() != ReadOnlyRoots(isolate).empty_fixed_array()) {
2161     return Just(false);
2162   }
2163 
2164   Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
2165   int length = map->NumberOfOwnDescriptors();
2166 
2167   bool stable = true;
2168 
2169   for (int i = 0; i < length; i++) {
2170     Handle<Name> next_key(descriptors->GetKey(i), isolate);
2171     Handle<Object> prop_value;
2172     // Directly decode from the descriptor array if |from| did not change shape.
2173     if (stable) {
2174       PropertyDetails details = descriptors->GetDetails(i);
2175       if (!details.IsEnumerable()) continue;
2176       if (details.kind() == kData) {
2177         if (details.location() == kDescriptor) {
2178           prop_value = handle(descriptors->GetStrongValue(i), isolate);
2179         } else {
2180           Representation representation = details.representation();
2181           FieldIndex index = FieldIndex::ForDescriptor(*map, i);
2182           prop_value = JSObject::FastPropertyAt(from, representation, index);
2183         }
2184       } else {
2185         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2186             isolate, prop_value,
2187             JSReceiver::GetProperty(isolate, from, next_key), Nothing<bool>());
2188         stable = from->map() == *map;
2189       }
2190     } else {
2191       // If the map did change, do a slower lookup. We are still guaranteed that
2192       // the object has a simple shape, and that the key is a name.
2193       LookupIterator it(from, next_key, from,
2194                         LookupIterator::OWN_SKIP_INTERCEPTOR);
2195       if (!it.IsFound()) continue;
2196       DCHECK(it.state() == LookupIterator::DATA ||
2197              it.state() == LookupIterator::ACCESSOR);
2198       if (!it.IsEnumerable()) continue;
2199       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2200           isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
2201     }
2202 
2203     if (use_set) {
2204       LookupIterator it(target, next_key, target);
2205       Maybe<bool> result =
2206           Object::SetProperty(&it, prop_value, LanguageMode::kStrict,
2207                               Object::CERTAINLY_NOT_STORE_FROM_KEYED);
2208       if (result.IsNothing()) return result;
2209       if (stable) stable = from->map() == *map;
2210     } else {
2211       if (excluded_properties != nullptr &&
2212           HasExcludedProperty(excluded_properties, next_key)) {
2213         continue;
2214       }
2215 
2216       // 4a ii 2. Perform ? CreateDataProperty(target, nextKey, propValue).
2217       bool success;
2218       LookupIterator it = LookupIterator::PropertyOrElement(
2219           isolate, target, next_key, &success, LookupIterator::OWN);
2220       CHECK(success);
2221       CHECK(JSObject::CreateDataProperty(&it, prop_value, kThrowOnError)
2222                 .FromJust());
2223     }
2224   }
2225 
2226   return Just(true);
2227 }
2228 }  // namespace
2229 
2230 // static
SetOrCopyDataProperties(Isolate * isolate,Handle<JSReceiver> target,Handle<Object> source,const ScopedVector<Handle<Object>> * excluded_properties,bool use_set)2231 Maybe<bool> JSReceiver::SetOrCopyDataProperties(
2232     Isolate* isolate, Handle<JSReceiver> target, Handle<Object> source,
2233     const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) {
2234   Maybe<bool> fast_assign =
2235       FastAssign(target, source, excluded_properties, use_set);
2236   if (fast_assign.IsNothing()) return Nothing<bool>();
2237   if (fast_assign.FromJust()) return Just(true);
2238 
2239   Handle<JSReceiver> from = Object::ToObject(isolate, source).ToHandleChecked();
2240   // 3b. Let keys be ? from.[[OwnPropertyKeys]]().
2241   Handle<FixedArray> keys;
2242   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2243       isolate, keys,
2244       KeyAccumulator::GetKeys(from, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES,
2245                               GetKeysConversion::kKeepNumbers),
2246       Nothing<bool>());
2247 
2248   // 4. Repeat for each element nextKey of keys in List order,
2249   for (int j = 0; j < keys->length(); ++j) {
2250     Handle<Object> next_key(keys->get(j), isolate);
2251     // 4a i. Let desc be ? from.[[GetOwnProperty]](nextKey).
2252     PropertyDescriptor desc;
2253     Maybe<bool> found =
2254         JSReceiver::GetOwnPropertyDescriptor(isolate, from, next_key, &desc);
2255     if (found.IsNothing()) return Nothing<bool>();
2256     // 4a ii. If desc is not undefined and desc.[[Enumerable]] is true, then
2257     if (found.FromJust() && desc.enumerable()) {
2258       // 4a ii 1. Let propValue be ? Get(from, nextKey).
2259       Handle<Object> prop_value;
2260       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2261           isolate, prop_value,
2262           Runtime::GetObjectProperty(isolate, from, next_key), Nothing<bool>());
2263 
2264       if (use_set) {
2265         // 4c ii 2. Let status be ? Set(to, nextKey, propValue, true).
2266         Handle<Object> status;
2267         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2268             isolate, status,
2269             Runtime::SetObjectProperty(isolate, target, next_key, prop_value,
2270                                        LanguageMode::kStrict),
2271             Nothing<bool>());
2272       } else {
2273         if (excluded_properties != nullptr &&
2274             HasExcludedProperty(excluded_properties, next_key)) {
2275           continue;
2276         }
2277 
2278         // 4a ii 2. Perform ! CreateDataProperty(target, nextKey, propValue).
2279         bool success;
2280         LookupIterator it = LookupIterator::PropertyOrElement(
2281             isolate, target, next_key, &success, LookupIterator::OWN);
2282         CHECK(success);
2283         CHECK(JSObject::CreateDataProperty(&it, prop_value, kThrowOnError)
2284                   .FromJust());
2285       }
2286     }
2287   }
2288 
2289   return Just(true);
2290 }
2291 
GetPrototypeChainRootMap(Isolate * isolate) const2292 Map* Object::GetPrototypeChainRootMap(Isolate* isolate) const {
2293   DisallowHeapAllocation no_alloc;
2294   if (IsSmi()) {
2295     Context* native_context = isolate->context()->native_context();
2296     return native_context->number_function()->initial_map();
2297   }
2298 
2299   const HeapObject* heap_object = HeapObject::cast(this);
2300   return heap_object->map()->GetPrototypeChainRootMap(isolate);
2301 }
2302 
GetPrototypeChainRootMap(Isolate * isolate) const2303 Map* Map::GetPrototypeChainRootMap(Isolate* isolate) const {
2304   DisallowHeapAllocation no_alloc;
2305   if (IsJSReceiverMap()) {
2306     return const_cast<Map*>(this);
2307   }
2308   int constructor_function_index = GetConstructorFunctionIndex();
2309   if (constructor_function_index != Map::kNoConstructorFunctionIndex) {
2310     Context* native_context = isolate->context()->native_context();
2311     JSFunction* constructor_function =
2312         JSFunction::cast(native_context->get(constructor_function_index));
2313     return constructor_function->initial_map();
2314   }
2315   return ReadOnlyRoots(isolate).null_value()->map();
2316 }
2317 
2318 // static
GetOrCreateHash(Isolate * isolate,Object * key)2319 Smi* Object::GetOrCreateHash(Isolate* isolate, Object* key) {
2320   DisallowHeapAllocation no_gc;
2321   return key->GetOrCreateHash(isolate);
2322 }
2323 
GetOrCreateHash(Isolate * isolate)2324 Smi* Object::GetOrCreateHash(Isolate* isolate) {
2325   DisallowHeapAllocation no_gc;
2326   Object* hash = Object::GetSimpleHash(this);
2327   if (hash->IsSmi()) return Smi::cast(hash);
2328 
2329   DCHECK(IsJSReceiver());
2330   return JSReceiver::cast(this)->GetOrCreateIdentityHash(isolate);
2331 }
2332 
2333 
SameValue(Object * other)2334 bool Object::SameValue(Object* other) {
2335   if (other == this) return true;
2336 
2337   if (IsNumber() && other->IsNumber()) {
2338     double this_value = Number();
2339     double other_value = other->Number();
2340     // SameValue(NaN, NaN) is true.
2341     if (this_value != other_value) {
2342       return std::isnan(this_value) && std::isnan(other_value);
2343     }
2344     // SameValue(0.0, -0.0) is false.
2345     return (std::signbit(this_value) == std::signbit(other_value));
2346   }
2347   if (IsString() && other->IsString()) {
2348     return String::cast(this)->Equals(String::cast(other));
2349   }
2350   if (IsBigInt() && other->IsBigInt()) {
2351     return BigInt::EqualToBigInt(BigInt::cast(this), BigInt::cast(other));
2352   }
2353   return false;
2354 }
2355 
2356 
SameValueZero(Object * other)2357 bool Object::SameValueZero(Object* other) {
2358   if (other == this) return true;
2359 
2360   if (IsNumber() && other->IsNumber()) {
2361     double this_value = Number();
2362     double other_value = other->Number();
2363     // +0 == -0 is true
2364     return this_value == other_value ||
2365            (std::isnan(this_value) && std::isnan(other_value));
2366   }
2367   if (IsString() && other->IsString()) {
2368     return String::cast(this)->Equals(String::cast(other));
2369   }
2370   if (IsBigInt() && other->IsBigInt()) {
2371     return BigInt::EqualToBigInt(BigInt::cast(this), BigInt::cast(other));
2372   }
2373   return false;
2374 }
2375 
2376 
ArraySpeciesConstructor(Isolate * isolate,Handle<Object> original_array)2377 MaybeHandle<Object> Object::ArraySpeciesConstructor(
2378     Isolate* isolate, Handle<Object> original_array) {
2379   Handle<Object> default_species = isolate->array_function();
2380   if (original_array->IsJSArray() &&
2381       Handle<JSArray>::cast(original_array)->HasArrayPrototype(isolate) &&
2382       isolate->IsArraySpeciesLookupChainIntact()) {
2383     return default_species;
2384   }
2385   Handle<Object> constructor = isolate->factory()->undefined_value();
2386   Maybe<bool> is_array = Object::IsArray(original_array);
2387   MAYBE_RETURN_NULL(is_array);
2388   if (is_array.FromJust()) {
2389     ASSIGN_RETURN_ON_EXCEPTION(
2390         isolate, constructor,
2391         Object::GetProperty(isolate, original_array,
2392                             isolate->factory()->constructor_string()),
2393         Object);
2394     if (constructor->IsConstructor()) {
2395       Handle<Context> constructor_context;
2396       ASSIGN_RETURN_ON_EXCEPTION(
2397           isolate, constructor_context,
2398           JSReceiver::GetFunctionRealm(Handle<JSReceiver>::cast(constructor)),
2399           Object);
2400       if (*constructor_context != *isolate->native_context() &&
2401           *constructor == constructor_context->array_function()) {
2402         constructor = isolate->factory()->undefined_value();
2403       }
2404     }
2405     if (constructor->IsJSReceiver()) {
2406       ASSIGN_RETURN_ON_EXCEPTION(
2407           isolate, constructor,
2408           JSReceiver::GetProperty(isolate,
2409                                   Handle<JSReceiver>::cast(constructor),
2410                                   isolate->factory()->species_symbol()),
2411           Object);
2412       if (constructor->IsNull(isolate)) {
2413         constructor = isolate->factory()->undefined_value();
2414       }
2415     }
2416   }
2417   if (constructor->IsUndefined(isolate)) {
2418     return default_species;
2419   } else {
2420     if (!constructor->IsConstructor()) {
2421       THROW_NEW_ERROR(isolate,
2422           NewTypeError(MessageTemplate::kSpeciesNotConstructor),
2423           Object);
2424     }
2425     return constructor;
2426   }
2427 }
2428 
2429 // ES6 section 7.3.20 SpeciesConstructor ( O, defaultConstructor )
SpeciesConstructor(Isolate * isolate,Handle<JSReceiver> recv,Handle<JSFunction> default_ctor)2430 V8_WARN_UNUSED_RESULT MaybeHandle<Object> Object::SpeciesConstructor(
2431     Isolate* isolate, Handle<JSReceiver> recv,
2432     Handle<JSFunction> default_ctor) {
2433   Handle<Object> ctor_obj;
2434   ASSIGN_RETURN_ON_EXCEPTION(
2435       isolate, ctor_obj,
2436       JSObject::GetProperty(isolate, recv,
2437                             isolate->factory()->constructor_string()),
2438       Object);
2439 
2440   if (ctor_obj->IsUndefined(isolate)) return default_ctor;
2441 
2442   if (!ctor_obj->IsJSReceiver()) {
2443     THROW_NEW_ERROR(isolate,
2444                     NewTypeError(MessageTemplate::kConstructorNotReceiver),
2445                     Object);
2446   }
2447 
2448   Handle<JSReceiver> ctor = Handle<JSReceiver>::cast(ctor_obj);
2449 
2450   Handle<Object> species;
2451   ASSIGN_RETURN_ON_EXCEPTION(
2452       isolate, species,
2453       JSObject::GetProperty(isolate, ctor,
2454                             isolate->factory()->species_symbol()),
2455       Object);
2456 
2457   if (species->IsNullOrUndefined(isolate)) {
2458     return default_ctor;
2459   }
2460 
2461   if (species->IsConstructor()) return species;
2462 
2463   THROW_NEW_ERROR(
2464       isolate, NewTypeError(MessageTemplate::kSpeciesNotConstructor), Object);
2465 }
2466 
IterationHasObservableEffects()2467 bool Object::IterationHasObservableEffects() {
2468   // Check that this object is an array.
2469   if (!IsJSArray()) return true;
2470   JSArray* array = JSArray::cast(this);
2471   Isolate* isolate = array->GetIsolate();
2472 
2473 #ifdef V8_ENABLE_FORCE_SLOW_PATH
2474   if (isolate->force_slow_path()) return true;
2475 #endif
2476 
2477   // Check that we have the original ArrayPrototype.
2478   if (!array->map()->prototype()->IsJSObject()) return true;
2479   JSObject* array_proto = JSObject::cast(array->map()->prototype());
2480   if (!isolate->is_initial_array_prototype(array_proto)) return true;
2481 
2482   // Check that the ArrayPrototype hasn't been modified in a way that would
2483   // affect iteration.
2484   if (!isolate->IsArrayIteratorLookupChainIntact()) return true;
2485 
2486   // For FastPacked kinds, iteration will have the same effect as simply
2487   // accessing each property in order.
2488   ElementsKind array_kind = array->GetElementsKind();
2489   if (IsFastPackedElementsKind(array_kind)) return false;
2490 
2491   // For FastHoley kinds, an element access on a hole would cause a lookup on
2492   // the prototype. This could have different results if the prototype has been
2493   // changed.
2494   if (IsHoleyElementsKind(array_kind) &&
2495       isolate->IsNoElementsProtectorIntact()) {
2496     return false;
2497   }
2498   return true;
2499 }
2500 
ShortPrint(FILE * out)2501 void Object::ShortPrint(FILE* out) {
2502   OFStream os(out);
2503   os << Brief(this);
2504 }
2505 
2506 
ShortPrint(StringStream * accumulator)2507 void Object::ShortPrint(StringStream* accumulator) {
2508   std::ostringstream os;
2509   os << Brief(this);
2510   accumulator->Add(os.str().c_str());
2511 }
2512 
2513 
ShortPrint(std::ostream & os)2514 void Object::ShortPrint(std::ostream& os) { os << Brief(this); }
2515 
ShortPrint(FILE * out)2516 void MaybeObject::ShortPrint(FILE* out) {
2517   OFStream os(out);
2518   os << Brief(this);
2519 }
2520 
ShortPrint(StringStream * accumulator)2521 void MaybeObject::ShortPrint(StringStream* accumulator) {
2522   std::ostringstream os;
2523   os << Brief(this);
2524   accumulator->Add(os.str().c_str());
2525 }
2526 
ShortPrint(std::ostream & os)2527 void MaybeObject::ShortPrint(std::ostream& os) { os << Brief(this); }
2528 
Brief(const Object * v)2529 Brief::Brief(const Object* v)
2530     : value(MaybeObject::FromObject(const_cast<Object*>(v))) {}
2531 
operator <<(std::ostream & os,const Brief & v)2532 std::ostream& operator<<(std::ostream& os, const Brief& v) {
2533   // TODO(marja): const-correct HeapObjectShortPrint.
2534   MaybeObject* maybe_object = const_cast<MaybeObject*>(v.value);
2535   Smi* smi;
2536   HeapObject* heap_object;
2537   if (maybe_object->ToSmi(&smi)) {
2538     smi->SmiPrint(os);
2539   } else if (maybe_object->IsClearedWeakHeapObject()) {
2540     os << "[cleared]";
2541   } else if (maybe_object->ToWeakHeapObject(&heap_object)) {
2542     os << "[weak] ";
2543     heap_object->HeapObjectShortPrint(os);
2544   } else if (maybe_object->ToStrongHeapObject(&heap_object)) {
2545     heap_object->HeapObjectShortPrint(os);
2546   } else {
2547     UNREACHABLE();
2548   }
2549   return os;
2550 }
2551 
SmiPrint(std::ostream & os) const2552 void Smi::SmiPrint(std::ostream& os) const {  // NOLINT
2553   os << value();
2554 }
2555 
SlowFlatten(Isolate * isolate,Handle<ConsString> cons,PretenureFlag pretenure)2556 Handle<String> String::SlowFlatten(Isolate* isolate, Handle<ConsString> cons,
2557                                    PretenureFlag pretenure) {
2558   DCHECK_NE(cons->second()->length(), 0);
2559 
2560   // TurboFan can create cons strings with empty first parts.
2561   while (cons->first()->length() == 0) {
2562     // We do not want to call this function recursively. Therefore we call
2563     // String::Flatten only in those cases where String::SlowFlatten is not
2564     // called again.
2565     if (cons->second()->IsConsString() && !cons->second()->IsFlat()) {
2566       cons = handle(ConsString::cast(cons->second()), isolate);
2567     } else {
2568       return String::Flatten(isolate, handle(cons->second(), isolate));
2569     }
2570   }
2571 
2572   DCHECK(AllowHeapAllocation::IsAllowed());
2573   int length = cons->length();
2574   PretenureFlag tenure = Heap::InNewSpace(*cons) ? pretenure : TENURED;
2575   Handle<SeqString> result;
2576   if (cons->IsOneByteRepresentation()) {
2577     Handle<SeqOneByteString> flat = isolate->factory()->NewRawOneByteString(
2578         length, tenure).ToHandleChecked();
2579     DisallowHeapAllocation no_gc;
2580     WriteToFlat(*cons, flat->GetChars(), 0, length);
2581     result = flat;
2582   } else {
2583     Handle<SeqTwoByteString> flat = isolate->factory()->NewRawTwoByteString(
2584         length, tenure).ToHandleChecked();
2585     DisallowHeapAllocation no_gc;
2586     WriteToFlat(*cons, flat->GetChars(), 0, length);
2587     result = flat;
2588   }
2589   cons->set_first(isolate, *result);
2590   cons->set_second(isolate, ReadOnlyRoots(isolate).empty_string());
2591   DCHECK(result->IsFlat());
2592   return result;
2593 }
2594 
2595 
2596 
MakeExternal(v8::String::ExternalStringResource * resource)2597 bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
2598   DisallowHeapAllocation no_allocation;
2599   // Externalizing twice leaks the external resource, so it's
2600   // prohibited by the API.
2601   DCHECK(this->SupportsExternalization());
2602   DCHECK(!resource->IsCompressible());
2603 #ifdef ENABLE_SLOW_DCHECKS
2604   if (FLAG_enable_slow_asserts) {
2605     // Assert that the resource and the string are equivalent.
2606     DCHECK(static_cast<size_t>(this->length()) == resource->length());
2607     ScopedVector<uc16> smart_chars(this->length());
2608     String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2609     DCHECK_EQ(0, memcmp(smart_chars.start(), resource->data(),
2610                         resource->length() * sizeof(smart_chars[0])));
2611   }
2612 #endif  // DEBUG
2613   int size = this->Size();  // Byte size of the original string.
2614   // Abort if size does not allow in-place conversion.
2615   if (size < ExternalString::kShortSize) return false;
2616   Isolate* isolate;
2617   // Read-only strings cannot be made external, since that would mutate the
2618   // string.
2619   if (!Isolate::FromWritableHeapObject(this, &isolate)) return false;
2620   Heap* heap = isolate->heap();
2621   bool is_one_byte = this->IsOneByteRepresentation();
2622   bool is_internalized = this->IsInternalizedString();
2623   bool has_pointers = StringShape(this).IsIndirect();
2624   if (has_pointers) {
2625     heap->NotifyObjectLayoutChange(this, size, no_allocation);
2626   }
2627   // Morph the string to an external string by replacing the map and
2628   // reinitializing the fields.  This won't work if the space the existing
2629   // string occupies is too small for a regular  external string.
2630   // Instead, we resort to a short external string instead, omitting
2631   // the field caching the address of the backing store.  When we encounter
2632   // short external strings in generated code, we need to bailout to runtime.
2633   Map* new_map;
2634   ReadOnlyRoots roots(heap);
2635   if (size < ExternalString::kSize) {
2636     if (is_internalized) {
2637       new_map =
2638           is_one_byte
2639               ? roots
2640                     .short_external_internalized_string_with_one_byte_data_map()
2641               : roots.short_external_internalized_string_map();
2642     } else {
2643       new_map = is_one_byte
2644                     ? roots.short_external_string_with_one_byte_data_map()
2645                     : roots.short_external_string_map();
2646     }
2647   } else {
2648     new_map =
2649         is_internalized
2650             ? (is_one_byte
2651                    ? roots.external_internalized_string_with_one_byte_data_map()
2652                    : roots.external_internalized_string_map())
2653             : (is_one_byte ? roots.external_string_with_one_byte_data_map()
2654                            : roots.external_string_map());
2655   }
2656 
2657   // Byte size of the external String object.
2658   int new_size = this->SizeFromMap(new_map);
2659   heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
2660                              ClearRecordedSlots::kNo);
2661   if (has_pointers) {
2662     heap->ClearRecordedSlotRange(this->address(), this->address() + new_size);
2663   }
2664 
2665   // We are storing the new map using release store after creating a filler for
2666   // the left-over space to avoid races with the sweeper thread.
2667   this->synchronized_set_map(new_map);
2668 
2669   ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
2670   self->SetResource(isolate, resource);
2671   heap->RegisterExternalString(this);
2672   if (is_internalized) self->Hash();  // Force regeneration of the hash value.
2673   return true;
2674 }
2675 
2676 
MakeExternal(v8::String::ExternalOneByteStringResource * resource)2677 bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
2678   DisallowHeapAllocation no_allocation;
2679   // Externalizing twice leaks the external resource, so it's
2680   // prohibited by the API.
2681   DCHECK(this->SupportsExternalization());
2682   DCHECK(!resource->IsCompressible());
2683 #ifdef ENABLE_SLOW_DCHECKS
2684   if (FLAG_enable_slow_asserts) {
2685     // Assert that the resource and the string are equivalent.
2686     DCHECK(static_cast<size_t>(this->length()) == resource->length());
2687     if (this->IsTwoByteRepresentation()) {
2688       ScopedVector<uint16_t> smart_chars(this->length());
2689       String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2690       DCHECK(String::IsOneByte(smart_chars.start(), this->length()));
2691     }
2692     ScopedVector<char> smart_chars(this->length());
2693     String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2694     DCHECK_EQ(0, memcmp(smart_chars.start(), resource->data(),
2695                         resource->length() * sizeof(smart_chars[0])));
2696   }
2697 #endif  // DEBUG
2698   int size = this->Size();  // Byte size of the original string.
2699   // Abort if size does not allow in-place conversion.
2700   if (size < ExternalString::kShortSize) return false;
2701   Isolate* isolate;
2702   // Read-only strings cannot be made external, since that would mutate the
2703   // string.
2704   if (!Isolate::FromWritableHeapObject(this, &isolate)) return false;
2705   Heap* heap = isolate->heap();
2706   bool is_internalized = this->IsInternalizedString();
2707   bool has_pointers = StringShape(this).IsIndirect();
2708 
2709   if (has_pointers) {
2710     heap->NotifyObjectLayoutChange(this, size, no_allocation);
2711   }
2712 
2713   // Morph the string to an external string by replacing the map and
2714   // reinitializing the fields.  This won't work if the space the existing
2715   // string occupies is too small for a regular  external string.
2716   // Instead, we resort to a short external string instead, omitting
2717   // the field caching the address of the backing store.  When we encounter
2718   // short external strings in generated code, we need to bailout to runtime.
2719   Map* new_map;
2720   ReadOnlyRoots roots(heap);
2721   if (size < ExternalString::kSize) {
2722     new_map = is_internalized
2723                   ? roots.short_external_one_byte_internalized_string_map()
2724                   : roots.short_external_one_byte_string_map();
2725   } else {
2726     new_map = is_internalized
2727                   ? roots.external_one_byte_internalized_string_map()
2728                   : roots.external_one_byte_string_map();
2729   }
2730 
2731   // Byte size of the external String object.
2732   int new_size = this->SizeFromMap(new_map);
2733   heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
2734                              ClearRecordedSlots::kNo);
2735   if (has_pointers) {
2736     heap->ClearRecordedSlotRange(this->address(), this->address() + new_size);
2737   }
2738 
2739   // We are storing the new map using release store after creating a filler for
2740   // the left-over space to avoid races with the sweeper thread.
2741   this->synchronized_set_map(new_map);
2742 
2743   ExternalOneByteString* self = ExternalOneByteString::cast(this);
2744   self->SetResource(isolate, resource);
2745   heap->RegisterExternalString(this);
2746   if (is_internalized) self->Hash();  // Force regeneration of the hash value.
2747   return true;
2748 }
2749 
SupportsExternalization()2750 bool String::SupportsExternalization() {
2751   if (this->IsThinString()) {
2752     return i::ThinString::cast(this)->actual()->SupportsExternalization();
2753   }
2754 
2755   Isolate* isolate;
2756   // RO_SPACE strings cannot be externalized.
2757   if (!Isolate::FromWritableHeapObject(this, &isolate)) {
2758     return false;
2759   }
2760 
2761   // Already an external string.
2762   if (StringShape(this).IsExternal()) {
2763     return false;
2764   }
2765 
2766   return !isolate->heap()->IsInGCPostProcessing();
2767 }
2768 
StringShortPrint(StringStream * accumulator,bool show_details)2769 void String::StringShortPrint(StringStream* accumulator, bool show_details) {
2770   int len = length();
2771   if (len > kMaxShortPrintLength) {
2772     accumulator->Add("<Very long string[%u]>", len);
2773     return;
2774   }
2775 
2776   if (!LooksValid()) {
2777     accumulator->Add("<Invalid String>");
2778     return;
2779   }
2780 
2781   StringCharacterStream stream(this);
2782 
2783   bool truncated = false;
2784   if (len > kMaxShortPrintLength) {
2785     len = kMaxShortPrintLength;
2786     truncated = true;
2787   }
2788   bool one_byte = true;
2789   for (int i = 0; i < len; i++) {
2790     uint16_t c = stream.GetNext();
2791 
2792     if (c < 32 || c >= 127) {
2793       one_byte = false;
2794     }
2795   }
2796   stream.Reset(this);
2797   if (one_byte) {
2798     if (show_details) accumulator->Add("<String[%u]: ", length());
2799     for (int i = 0; i < len; i++) {
2800       accumulator->Put(static_cast<char>(stream.GetNext()));
2801     }
2802     if (show_details) accumulator->Put('>');
2803   } else {
2804     // Backslash indicates that the string contains control
2805     // characters and that backslashes are therefore escaped.
2806     if (show_details) accumulator->Add("<String[%u]\\: ", length());
2807     for (int i = 0; i < len; i++) {
2808       uint16_t c = stream.GetNext();
2809       if (c == '\n') {
2810         accumulator->Add("\\n");
2811       } else if (c == '\r') {
2812         accumulator->Add("\\r");
2813       } else if (c == '\\') {
2814         accumulator->Add("\\\\");
2815       } else if (c < 32 || c > 126) {
2816         accumulator->Add("\\x%02x", c);
2817       } else {
2818         accumulator->Put(static_cast<char>(c));
2819       }
2820     }
2821     if (truncated) {
2822       accumulator->Put('.');
2823       accumulator->Put('.');
2824       accumulator->Put('.');
2825     }
2826     if (show_details) accumulator->Put('>');
2827   }
2828   return;
2829 }
2830 
2831 
PrintUC16(std::ostream & os,int start,int end)2832 void String::PrintUC16(std::ostream& os, int start, int end) {  // NOLINT
2833   if (end < 0) end = length();
2834   StringCharacterStream stream(this, start);
2835   for (int i = start; i < end && stream.HasMore(); i++) {
2836     os << AsUC16(stream.GetNext());
2837   }
2838 }
2839 
2840 
JSObjectShortPrint(StringStream * accumulator)2841 void JSObject::JSObjectShortPrint(StringStream* accumulator) {
2842   switch (map()->instance_type()) {
2843     case JS_ARRAY_TYPE: {
2844       double length = JSArray::cast(this)->length()->IsUndefined()
2845                           ? 0
2846                           : JSArray::cast(this)->length()->Number();
2847       accumulator->Add("<JSArray[%u]>", static_cast<uint32_t>(length));
2848       break;
2849     }
2850     case JS_BOUND_FUNCTION_TYPE: {
2851       JSBoundFunction* bound_function = JSBoundFunction::cast(this);
2852       accumulator->Add("<JSBoundFunction");
2853       accumulator->Add(
2854           " (BoundTargetFunction %p)>",
2855           reinterpret_cast<void*>(bound_function->bound_target_function()));
2856       break;
2857     }
2858     case JS_WEAK_MAP_TYPE: {
2859       accumulator->Add("<JSWeakMap>");
2860       break;
2861     }
2862     case JS_WEAK_SET_TYPE: {
2863       accumulator->Add("<JSWeakSet>");
2864       break;
2865     }
2866     case JS_REGEXP_TYPE: {
2867       accumulator->Add("<JSRegExp");
2868       JSRegExp* regexp = JSRegExp::cast(this);
2869       if (regexp->source()->IsString()) {
2870         accumulator->Add(" ");
2871         String::cast(regexp->source())->StringShortPrint(accumulator);
2872       }
2873       accumulator->Add(">");
2874 
2875       break;
2876     }
2877     case JS_FUNCTION_TYPE: {
2878       JSFunction* function = JSFunction::cast(this);
2879       Object* fun_name = function->shared()->DebugName();
2880       bool printed = false;
2881       if (fun_name->IsString()) {
2882         String* str = String::cast(fun_name);
2883         if (str->length() > 0) {
2884           accumulator->Add("<JSFunction ");
2885           accumulator->Put(str);
2886           printed = true;
2887         }
2888       }
2889       if (!printed) {
2890         accumulator->Add("<JSFunction");
2891       }
2892       if (FLAG_trace_file_names) {
2893         Object* source_name =
2894             Script::cast(function->shared()->script())->name();
2895         if (source_name->IsString()) {
2896           String* str = String::cast(source_name);
2897           if (str->length() > 0) {
2898             accumulator->Add(" <");
2899             accumulator->Put(str);
2900             accumulator->Add(">");
2901           }
2902         }
2903       }
2904       accumulator->Add(" (sfi = %p)",
2905                        reinterpret_cast<void*>(function->shared()));
2906       accumulator->Put('>');
2907       break;
2908     }
2909     case JS_GENERATOR_OBJECT_TYPE: {
2910       accumulator->Add("<JSGenerator>");
2911       break;
2912     }
2913     case JS_ASYNC_GENERATOR_OBJECT_TYPE: {
2914       accumulator->Add("<JS AsyncGenerator>");
2915       break;
2916     }
2917 
2918     // All other JSObjects are rather similar to each other (JSObject,
2919     // JSGlobalProxy, JSGlobalObject, JSUndetectable, JSValue).
2920     default: {
2921       Map* map_of_this = map();
2922       Heap* heap = GetHeap();
2923       Object* constructor = map_of_this->GetConstructor();
2924       bool printed = false;
2925       if (constructor->IsHeapObject() &&
2926           !heap->Contains(HeapObject::cast(constructor))) {
2927         accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
2928       } else {
2929         bool global_object = IsJSGlobalProxy();
2930         if (constructor->IsJSFunction()) {
2931           if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
2932             accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
2933           } else {
2934             String* constructor_name =
2935                 JSFunction::cast(constructor)->shared()->Name();
2936             if (constructor_name->length() > 0) {
2937               accumulator->Add(global_object ? "<GlobalObject " : "<");
2938               accumulator->Put(constructor_name);
2939               accumulator->Add(
2940                   " %smap = %p",
2941                   map_of_this->is_deprecated() ? "deprecated-" : "",
2942                   map_of_this);
2943               printed = true;
2944             }
2945           }
2946         } else if (constructor->IsFunctionTemplateInfo()) {
2947           accumulator->Add(global_object ? "<RemoteObject>" : "<RemoteObject>");
2948           printed = true;
2949         }
2950         if (!printed) {
2951           accumulator->Add("<JS%sObject", global_object ? "Global " : "");
2952         }
2953       }
2954       if (IsJSValue()) {
2955         accumulator->Add(" value = ");
2956         JSValue::cast(this)->value()->ShortPrint(accumulator);
2957       }
2958       accumulator->Put('>');
2959       break;
2960     }
2961   }
2962 }
2963 
2964 
PrintElementsTransition(FILE * file,Handle<JSObject> object,ElementsKind from_kind,Handle<FixedArrayBase> from_elements,ElementsKind to_kind,Handle<FixedArrayBase> to_elements)2965 void JSObject::PrintElementsTransition(
2966     FILE* file, Handle<JSObject> object,
2967     ElementsKind from_kind, Handle<FixedArrayBase> from_elements,
2968     ElementsKind to_kind, Handle<FixedArrayBase> to_elements) {
2969   if (from_kind != to_kind) {
2970     OFStream os(file);
2971     os << "elements transition [" << ElementsKindToString(from_kind) << " -> "
2972        << ElementsKindToString(to_kind) << "] in ";
2973     JavaScriptFrame::PrintTop(object->GetIsolate(), file, false, true);
2974     PrintF(file, " for ");
2975     object->ShortPrint(file);
2976     PrintF(file, " from ");
2977     from_elements->ShortPrint(file);
2978     PrintF(file, " to ");
2979     to_elements->ShortPrint(file);
2980     PrintF(file, "\n");
2981   }
2982 }
2983 
2984 
2985 // static
GetConstructorFunction(Handle<Map> map,Handle<Context> native_context)2986 MaybeHandle<JSFunction> Map::GetConstructorFunction(
2987     Handle<Map> map, Handle<Context> native_context) {
2988   if (map->IsPrimitiveMap()) {
2989     int const constructor_function_index = map->GetConstructorFunctionIndex();
2990     if (constructor_function_index != kNoConstructorFunctionIndex) {
2991       return handle(
2992           JSFunction::cast(native_context->get(constructor_function_index)),
2993           native_context->GetIsolate());
2994     }
2995   }
2996   return MaybeHandle<JSFunction>();
2997 }
2998 
PrintReconfiguration(Isolate * isolate,FILE * file,int modify_index,PropertyKind kind,PropertyAttributes attributes)2999 void Map::PrintReconfiguration(Isolate* isolate, FILE* file, int modify_index,
3000                                PropertyKind kind,
3001                                PropertyAttributes attributes) {
3002   OFStream os(file);
3003   os << "[reconfiguring]";
3004   Name* name = instance_descriptors()->GetKey(modify_index);
3005   if (name->IsString()) {
3006     String::cast(name)->PrintOn(file);
3007   } else {
3008     os << "{symbol " << static_cast<void*>(name) << "}";
3009   }
3010   os << ": " << (kind == kData ? "kData" : "ACCESSORS") << ", attrs: ";
3011   os << attributes << " [";
3012   JavaScriptFrame::PrintTop(isolate, file, false, true);
3013   os << "]\n";
3014 }
3015 
GetVisitorId(Map * map)3016 VisitorId Map::GetVisitorId(Map* map) {
3017   STATIC_ASSERT(kVisitorIdCount <= 256);
3018 
3019   const int instance_type = map->instance_type();
3020   const bool has_unboxed_fields =
3021       FLAG_unbox_double_fields && !map->HasFastPointerLayout();
3022   if (instance_type < FIRST_NONSTRING_TYPE) {
3023     switch (instance_type & kStringRepresentationMask) {
3024       case kSeqStringTag:
3025         if ((instance_type & kStringEncodingMask) == kOneByteStringTag) {
3026           return kVisitSeqOneByteString;
3027         } else {
3028           return kVisitSeqTwoByteString;
3029         }
3030 
3031       case kConsStringTag:
3032         if (IsShortcutCandidate(instance_type)) {
3033           return kVisitShortcutCandidate;
3034         } else {
3035           return kVisitConsString;
3036         }
3037 
3038       case kSlicedStringTag:
3039         return kVisitSlicedString;
3040 
3041       case kExternalStringTag:
3042         return kVisitDataObject;
3043 
3044       case kThinStringTag:
3045         return kVisitThinString;
3046     }
3047     UNREACHABLE();
3048   }
3049 
3050   switch (instance_type) {
3051     case BYTE_ARRAY_TYPE:
3052       return kVisitByteArray;
3053 
3054     case BYTECODE_ARRAY_TYPE:
3055       return kVisitBytecodeArray;
3056 
3057     case FREE_SPACE_TYPE:
3058       return kVisitFreeSpace;
3059 
3060     case FIXED_ARRAY_TYPE:
3061     case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
3062     case HASH_TABLE_TYPE:
3063     case ORDERED_HASH_MAP_TYPE:
3064     case ORDERED_HASH_SET_TYPE:
3065     case NAME_DICTIONARY_TYPE:
3066     case GLOBAL_DICTIONARY_TYPE:
3067     case NUMBER_DICTIONARY_TYPE:
3068     case SIMPLE_NUMBER_DICTIONARY_TYPE:
3069     case STRING_TABLE_TYPE:
3070     case SCOPE_INFO_TYPE:
3071     case SCRIPT_CONTEXT_TABLE_TYPE:
3072     case BLOCK_CONTEXT_TYPE:
3073     case CATCH_CONTEXT_TYPE:
3074     case DEBUG_EVALUATE_CONTEXT_TYPE:
3075     case EVAL_CONTEXT_TYPE:
3076     case FUNCTION_CONTEXT_TYPE:
3077     case MODULE_CONTEXT_TYPE:
3078     case NATIVE_CONTEXT_TYPE:
3079     case SCRIPT_CONTEXT_TYPE:
3080     case WITH_CONTEXT_TYPE:
3081       return kVisitFixedArray;
3082 
3083     case EPHEMERON_HASH_TABLE_TYPE:
3084       return kVisitEphemeronHashTable;
3085 
3086     case WEAK_FIXED_ARRAY_TYPE:
3087     case WEAK_ARRAY_LIST_TYPE:
3088     case DESCRIPTOR_ARRAY_TYPE:
3089       return kVisitWeakArray;
3090 
3091     case FIXED_DOUBLE_ARRAY_TYPE:
3092       return kVisitFixedDoubleArray;
3093 
3094     case PROPERTY_ARRAY_TYPE:
3095       return kVisitPropertyArray;
3096 
3097     case FEEDBACK_CELL_TYPE:
3098       return kVisitFeedbackCell;
3099 
3100     case FEEDBACK_VECTOR_TYPE:
3101       return kVisitFeedbackVector;
3102 
3103     case ODDBALL_TYPE:
3104       return kVisitOddball;
3105 
3106     case MAP_TYPE:
3107       return kVisitMap;
3108 
3109     case CODE_TYPE:
3110       return kVisitCode;
3111 
3112     case CELL_TYPE:
3113       return kVisitCell;
3114 
3115     case PROPERTY_CELL_TYPE:
3116       return kVisitPropertyCell;
3117 
3118     case TRANSITION_ARRAY_TYPE:
3119       return kVisitTransitionArray;
3120 
3121     case JS_WEAK_MAP_TYPE:
3122     case JS_WEAK_SET_TYPE:
3123       return kVisitJSWeakCollection;
3124 
3125     case CALL_HANDLER_INFO_TYPE:
3126       return kVisitStruct;
3127 
3128     case SHARED_FUNCTION_INFO_TYPE:
3129       return kVisitSharedFunctionInfo;
3130 
3131     case JS_PROXY_TYPE:
3132       return kVisitStruct;
3133 
3134     case SYMBOL_TYPE:
3135       return kVisitSymbol;
3136 
3137     case JS_ARRAY_BUFFER_TYPE:
3138       return kVisitJSArrayBuffer;
3139 
3140     case SMALL_ORDERED_HASH_MAP_TYPE:
3141       return kVisitSmallOrderedHashMap;
3142 
3143     case SMALL_ORDERED_HASH_SET_TYPE:
3144       return kVisitSmallOrderedHashSet;
3145 
3146     case CODE_DATA_CONTAINER_TYPE:
3147       return kVisitCodeDataContainer;
3148 
3149     case WASM_INSTANCE_TYPE:
3150       return kVisitWasmInstanceObject;
3151 
3152     case PRE_PARSED_SCOPE_DATA_TYPE:
3153       return kVisitPreParsedScopeData;
3154 
3155     case UNCOMPILED_DATA_WITHOUT_PRE_PARSED_SCOPE_TYPE:
3156       return kVisitUncompiledDataWithoutPreParsedScope;
3157 
3158     case UNCOMPILED_DATA_WITH_PRE_PARSED_SCOPE_TYPE:
3159       return kVisitUncompiledDataWithPreParsedScope;
3160 
3161     case JS_OBJECT_TYPE:
3162     case JS_ERROR_TYPE:
3163     case JS_ARGUMENTS_TYPE:
3164     case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
3165     case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
3166     case JS_GENERATOR_OBJECT_TYPE:
3167     case JS_ASYNC_GENERATOR_OBJECT_TYPE:
3168     case JS_MODULE_NAMESPACE_TYPE:
3169     case JS_VALUE_TYPE:
3170     case JS_DATE_TYPE:
3171     case JS_ARRAY_ITERATOR_TYPE:
3172     case JS_ARRAY_TYPE:
3173     case JS_GLOBAL_PROXY_TYPE:
3174     case JS_GLOBAL_OBJECT_TYPE:
3175     case JS_MESSAGE_OBJECT_TYPE:
3176     case JS_TYPED_ARRAY_TYPE:
3177     case JS_DATA_VIEW_TYPE:
3178     case JS_SET_TYPE:
3179     case JS_MAP_TYPE:
3180     case JS_SET_KEY_VALUE_ITERATOR_TYPE:
3181     case JS_SET_VALUE_ITERATOR_TYPE:
3182     case JS_MAP_KEY_ITERATOR_TYPE:
3183     case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
3184     case JS_MAP_VALUE_ITERATOR_TYPE:
3185     case JS_STRING_ITERATOR_TYPE:
3186     case JS_PROMISE_TYPE:
3187     case JS_REGEXP_TYPE:
3188     case JS_REGEXP_STRING_ITERATOR_TYPE:
3189 #ifdef V8_INTL_SUPPORT
3190     case JS_INTL_COLLATOR_TYPE:
3191     case JS_INTL_LIST_FORMAT_TYPE:
3192     case JS_INTL_LOCALE_TYPE:
3193     case JS_INTL_PLURAL_RULES_TYPE:
3194     case JS_INTL_RELATIVE_TIME_FORMAT_TYPE:
3195 #endif  // V8_INTL_SUPPORT
3196     case WASM_GLOBAL_TYPE:
3197     case WASM_MEMORY_TYPE:
3198     case WASM_MODULE_TYPE:
3199     case WASM_TABLE_TYPE:
3200     case JS_BOUND_FUNCTION_TYPE:
3201       return has_unboxed_fields ? kVisitJSObject : kVisitJSObjectFast;
3202     case JS_API_OBJECT_TYPE:
3203     case JS_SPECIAL_API_OBJECT_TYPE:
3204       return kVisitJSApiObject;
3205 
3206     case JS_FUNCTION_TYPE:
3207       return kVisitJSFunction;
3208 
3209     case FILLER_TYPE:
3210     case FOREIGN_TYPE:
3211     case HEAP_NUMBER_TYPE:
3212     case MUTABLE_HEAP_NUMBER_TYPE:
3213     case FEEDBACK_METADATA_TYPE:
3214       return kVisitDataObject;
3215 
3216     case BIGINT_TYPE:
3217       return kVisitBigInt;
3218 
3219     case FIXED_UINT8_ARRAY_TYPE:
3220     case FIXED_INT8_ARRAY_TYPE:
3221     case FIXED_UINT16_ARRAY_TYPE:
3222     case FIXED_INT16_ARRAY_TYPE:
3223     case FIXED_UINT32_ARRAY_TYPE:
3224     case FIXED_INT32_ARRAY_TYPE:
3225     case FIXED_FLOAT32_ARRAY_TYPE:
3226     case FIXED_UINT8_CLAMPED_ARRAY_TYPE:
3227     case FIXED_BIGUINT64_ARRAY_TYPE:
3228     case FIXED_BIGINT64_ARRAY_TYPE:
3229       return kVisitFixedTypedArrayBase;
3230 
3231     case FIXED_FLOAT64_ARRAY_TYPE:
3232       return kVisitFixedFloat64Array;
3233 
3234     case ALLOCATION_SITE_TYPE:
3235       return kVisitAllocationSite;
3236 
3237 #define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE:
3238       STRUCT_LIST(MAKE_STRUCT_CASE)
3239 #undef MAKE_STRUCT_CASE
3240       if (instance_type == PROTOTYPE_INFO_TYPE) {
3241         return kVisitPrototypeInfo;
3242       }
3243       return kVisitStruct;
3244 
3245     case LOAD_HANDLER_TYPE:
3246     case STORE_HANDLER_TYPE:
3247       return kVisitDataHandler;
3248 
3249     default:
3250       UNREACHABLE();
3251   }
3252 }
3253 
PrintGeneralization(Isolate * isolate,FILE * file,const char * reason,int modify_index,int split,int descriptors,bool descriptor_to_field,Representation old_representation,Representation new_representation,MaybeHandle<FieldType> old_field_type,MaybeHandle<Object> old_value,MaybeHandle<FieldType> new_field_type,MaybeHandle<Object> new_value)3254 void Map::PrintGeneralization(
3255     Isolate* isolate, FILE* file, const char* reason, int modify_index,
3256     int split, int descriptors, bool descriptor_to_field,
3257     Representation old_representation, Representation new_representation,
3258     MaybeHandle<FieldType> old_field_type, MaybeHandle<Object> old_value,
3259     MaybeHandle<FieldType> new_field_type, MaybeHandle<Object> new_value) {
3260   OFStream os(file);
3261   os << "[generalizing]";
3262   Name* name = instance_descriptors()->GetKey(modify_index);
3263   if (name->IsString()) {
3264     String::cast(name)->PrintOn(file);
3265   } else {
3266     os << "{symbol " << static_cast<void*>(name) << "}";
3267   }
3268   os << ":";
3269   if (descriptor_to_field) {
3270     os << "c";
3271   } else {
3272     os << old_representation.Mnemonic() << "{";
3273     if (old_field_type.is_null()) {
3274       os << Brief(*(old_value.ToHandleChecked()));
3275     } else {
3276       old_field_type.ToHandleChecked()->PrintTo(os);
3277     }
3278     os << "}";
3279   }
3280   os << "->" << new_representation.Mnemonic() << "{";
3281   if (new_field_type.is_null()) {
3282     os << Brief(*(new_value.ToHandleChecked()));
3283   } else {
3284     new_field_type.ToHandleChecked()->PrintTo(os);
3285   }
3286   os << "} (";
3287   if (strlen(reason) > 0) {
3288     os << reason;
3289   } else {
3290     os << "+" << (descriptors - split) << " maps";
3291   }
3292   os << ") [";
3293   JavaScriptFrame::PrintTop(isolate, file, false, true);
3294   os << "]\n";
3295 }
3296 
3297 
PrintInstanceMigration(FILE * file,Map * original_map,Map * new_map)3298 void JSObject::PrintInstanceMigration(FILE* file,
3299                                       Map* original_map,
3300                                       Map* new_map) {
3301   if (new_map->is_dictionary_map()) {
3302     PrintF(file, "[migrating to slow]\n");
3303     return;
3304   }
3305   PrintF(file, "[migrating]");
3306   DescriptorArray* o = original_map->instance_descriptors();
3307   DescriptorArray* n = new_map->instance_descriptors();
3308   for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) {
3309     Representation o_r = o->GetDetails(i).representation();
3310     Representation n_r = n->GetDetails(i).representation();
3311     if (!o_r.Equals(n_r)) {
3312       String::cast(o->GetKey(i))->PrintOn(file);
3313       PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic());
3314     } else if (o->GetDetails(i).location() == kDescriptor &&
3315                n->GetDetails(i).location() == kField) {
3316       Name* name = o->GetKey(i);
3317       if (name->IsString()) {
3318         String::cast(name)->PrintOn(file);
3319       } else {
3320         PrintF(file, "{symbol %p}", static_cast<void*>(name));
3321       }
3322       PrintF(file, " ");
3323     }
3324   }
3325   if (original_map->elements_kind() != new_map->elements_kind()) {
3326     PrintF(file, "elements_kind[%i->%i]", original_map->elements_kind(),
3327            new_map->elements_kind());
3328   }
3329   PrintF(file, "\n");
3330 }
3331 
IsUnmodifiedApiObject(Object ** o)3332 bool JSObject::IsUnmodifiedApiObject(Object** o) {
3333   Object* object = *o;
3334   if (object->IsSmi()) return false;
3335   HeapObject* heap_object = HeapObject::cast(object);
3336   if (!object->IsJSObject()) return false;
3337   JSObject* js_object = JSObject::cast(object);
3338   if (!js_object->IsApiWrapper()) return false;
3339   Object* maybe_constructor = js_object->map()->GetConstructor();
3340   if (!maybe_constructor->IsJSFunction()) return false;
3341   JSFunction* constructor = JSFunction::cast(maybe_constructor);
3342   if (js_object->elements()->length() != 0) return false;
3343 
3344   return constructor->initial_map() == heap_object->map();
3345 }
3346 
HeapObjectShortPrint(std::ostream & os)3347 void HeapObject::HeapObjectShortPrint(std::ostream& os) {  // NOLINT
3348   os << AsHex(reinterpret_cast<Address>(this), kPointerHexDigits, true) << " ";
3349 
3350   if (IsString()) {
3351     HeapStringAllocator allocator;
3352     StringStream accumulator(&allocator);
3353     String::cast(this)->StringShortPrint(&accumulator);
3354     os << accumulator.ToCString().get();
3355     return;
3356   }
3357   if (IsJSObject()) {
3358     HeapStringAllocator allocator;
3359     StringStream accumulator(&allocator);
3360     JSObject::cast(this)->JSObjectShortPrint(&accumulator);
3361     os << accumulator.ToCString().get();
3362     return;
3363   }
3364   switch (map()->instance_type()) {
3365     case MAP_TYPE: {
3366       os << "<Map";
3367       Map* mapInstance = Map::cast(this);
3368       if (mapInstance->IsJSObjectMap()) {
3369         os << "(" << ElementsKindToString(mapInstance->elements_kind()) << ")";
3370       } else if (mapInstance->instance_size() != kVariableSizeSentinel) {
3371         os << "[" << mapInstance->instance_size() << "]";
3372       }
3373       os << ">";
3374     } break;
3375     case BLOCK_CONTEXT_TYPE:
3376       os << "<BlockContext[" << FixedArray::cast(this)->length() << "]>";
3377       break;
3378     case CATCH_CONTEXT_TYPE:
3379       os << "<CatchContext[" << FixedArray::cast(this)->length() << "]>";
3380       break;
3381     case DEBUG_EVALUATE_CONTEXT_TYPE:
3382       os << "<DebugEvaluateContext[" << FixedArray::cast(this)->length()
3383          << "]>";
3384       break;
3385     case EVAL_CONTEXT_TYPE:
3386       os << "<EvalContext[" << FixedArray::cast(this)->length() << "]>";
3387       break;
3388     case FUNCTION_CONTEXT_TYPE:
3389       os << "<FunctionContext[" << FixedArray::cast(this)->length() << "]>";
3390       break;
3391     case MODULE_CONTEXT_TYPE:
3392       os << "<ModuleContext[" << FixedArray::cast(this)->length() << "]>";
3393       break;
3394     case NATIVE_CONTEXT_TYPE:
3395       os << "<NativeContext[" << FixedArray::cast(this)->length() << "]>";
3396       break;
3397     case SCRIPT_CONTEXT_TYPE:
3398       os << "<ScriptContext[" << FixedArray::cast(this)->length() << "]>";
3399       break;
3400     case WITH_CONTEXT_TYPE:
3401       os << "<WithContext[" << FixedArray::cast(this)->length() << "]>";
3402       break;
3403     case SCRIPT_CONTEXT_TABLE_TYPE:
3404       os << "<ScriptContextTable[" << FixedArray::cast(this)->length() << "]>";
3405       break;
3406     case HASH_TABLE_TYPE:
3407       os << "<HashTable[" << FixedArray::cast(this)->length() << "]>";
3408       break;
3409     case ORDERED_HASH_MAP_TYPE:
3410       os << "<OrderedHashMap[" << FixedArray::cast(this)->length() << "]>";
3411       break;
3412     case ORDERED_HASH_SET_TYPE:
3413       os << "<OrderedHashSet[" << FixedArray::cast(this)->length() << "]>";
3414       break;
3415     case NAME_DICTIONARY_TYPE:
3416       os << "<NameDictionary[" << FixedArray::cast(this)->length() << "]>";
3417       break;
3418     case GLOBAL_DICTIONARY_TYPE:
3419       os << "<GlobalDictionary[" << FixedArray::cast(this)->length() << "]>";
3420       break;
3421     case NUMBER_DICTIONARY_TYPE:
3422       os << "<NumberDictionary[" << FixedArray::cast(this)->length() << "]>";
3423       break;
3424     case SIMPLE_NUMBER_DICTIONARY_TYPE:
3425       os << "<SimpleNumberDictionary[" << FixedArray::cast(this)->length()
3426          << "]>";
3427       break;
3428     case STRING_TABLE_TYPE:
3429       os << "<StringTable[" << FixedArray::cast(this)->length() << "]>";
3430       break;
3431     case FIXED_ARRAY_TYPE:
3432       os << "<FixedArray[" << FixedArray::cast(this)->length() << "]>";
3433       break;
3434     case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
3435       os << "<ObjectBoilerplateDescription[" << FixedArray::cast(this)->length()
3436          << "]>";
3437       break;
3438     case FIXED_DOUBLE_ARRAY_TYPE:
3439       os << "<FixedDoubleArray[" << FixedDoubleArray::cast(this)->length()
3440          << "]>";
3441       break;
3442     case BYTE_ARRAY_TYPE:
3443       os << "<ByteArray[" << ByteArray::cast(this)->length() << "]>";
3444       break;
3445     case BYTECODE_ARRAY_TYPE:
3446       os << "<BytecodeArray[" << BytecodeArray::cast(this)->length() << "]>";
3447       break;
3448     case DESCRIPTOR_ARRAY_TYPE:
3449       os << "<DescriptorArray[" << DescriptorArray::cast(this)->length()
3450          << "]>";
3451       break;
3452     case TRANSITION_ARRAY_TYPE:
3453       os << "<TransitionArray[" << TransitionArray::cast(this)->length()
3454          << "]>";
3455       break;
3456     case PROPERTY_ARRAY_TYPE:
3457       os << "<PropertyArray[" << PropertyArray::cast(this)->length() << "]>";
3458       break;
3459     case FEEDBACK_CELL_TYPE: {
3460       {
3461         ReadOnlyRoots roots = GetReadOnlyRoots();
3462         os << "<FeedbackCell[";
3463         if (map() == roots.no_closures_cell_map()) {
3464           os << "no closures";
3465         } else if (map() == roots.one_closure_cell_map()) {
3466           os << "one closure";
3467         } else if (map() == roots.many_closures_cell_map()) {
3468           os << "many closures";
3469         } else {
3470           os << "!!!INVALID MAP!!!";
3471         }
3472         os << "]>";
3473       }
3474       break;
3475     }
3476     case FEEDBACK_VECTOR_TYPE:
3477       os << "<FeedbackVector[" << FeedbackVector::cast(this)->length() << "]>";
3478       break;
3479     case FREE_SPACE_TYPE:
3480       os << "<FreeSpace[" << FreeSpace::cast(this)->size() << "]>";
3481       break;
3482 #define TYPED_ARRAY_SHORT_PRINT(Type, type, TYPE, ctype)                      \
3483   case FIXED_##TYPE##_ARRAY_TYPE:                                             \
3484     os << "<Fixed" #Type "Array[" << Fixed##Type##Array::cast(this)->length() \
3485        << "]>";                                                               \
3486     break;
3487 
3488       TYPED_ARRAYS(TYPED_ARRAY_SHORT_PRINT)
3489 #undef TYPED_ARRAY_SHORT_PRINT
3490 
3491     case PRE_PARSED_SCOPE_DATA_TYPE: {
3492       PreParsedScopeData* data = PreParsedScopeData::cast(this);
3493       os << "<PreParsedScopeData[" << data->length() << "]>";
3494       break;
3495     }
3496 
3497     case UNCOMPILED_DATA_WITHOUT_PRE_PARSED_SCOPE_TYPE: {
3498       UncompiledDataWithoutPreParsedScope* data =
3499           UncompiledDataWithoutPreParsedScope::cast(this);
3500       os << "<UncompiledDataWithoutPreParsedScope (" << data->start_position()
3501          << ", " << data->end_position() << ")]>";
3502       break;
3503     }
3504 
3505     case UNCOMPILED_DATA_WITH_PRE_PARSED_SCOPE_TYPE: {
3506       UncompiledDataWithPreParsedScope* data =
3507           UncompiledDataWithPreParsedScope::cast(this);
3508       os << "<UncompiledDataWithPreParsedScope (" << data->start_position()
3509          << ", " << data->end_position()
3510          << ") preparsed=" << Brief(data->pre_parsed_scope_data()) << ">";
3511       break;
3512     }
3513 
3514     case SHARED_FUNCTION_INFO_TYPE: {
3515       SharedFunctionInfo* shared = SharedFunctionInfo::cast(this);
3516       std::unique_ptr<char[]> debug_name = shared->DebugName()->ToCString();
3517       if (debug_name[0] != 0) {
3518         os << "<SharedFunctionInfo " << debug_name.get() << ">";
3519       } else {
3520         os << "<SharedFunctionInfo>";
3521       }
3522       break;
3523     }
3524     case JS_MESSAGE_OBJECT_TYPE:
3525       os << "<JSMessageObject>";
3526       break;
3527 #define MAKE_STRUCT_CASE(NAME, Name, name)   \
3528   case NAME##_TYPE:                          \
3529     os << "<" #Name;                         \
3530     Name::cast(this)->BriefPrintDetails(os); \
3531     os << ">";                               \
3532     break;
3533       STRUCT_LIST(MAKE_STRUCT_CASE)
3534 #undef MAKE_STRUCT_CASE
3535     case ALLOCATION_SITE_TYPE: {
3536       os << "<AllocationSite";
3537       AllocationSite::cast(this)->BriefPrintDetails(os);
3538       os << ">";
3539       break;
3540     }
3541     case SCOPE_INFO_TYPE: {
3542       ScopeInfo* scope = ScopeInfo::cast(this);
3543       os << "<ScopeInfo";
3544       if (scope->length()) os << " " << scope->scope_type() << " ";
3545       os << "[" << scope->length() << "]>";
3546       break;
3547     }
3548     case CODE_TYPE: {
3549       Code* code = Code::cast(this);
3550       os << "<Code " << Code::Kind2String(code->kind());
3551       if (code->is_stub()) {
3552         os << " " << CodeStub::MajorName(CodeStub::GetMajorKey(code));
3553       } else if (code->is_builtin()) {
3554         os << " " << Builtins::name(code->builtin_index());
3555       }
3556       os << ">";
3557       break;
3558     }
3559     case ODDBALL_TYPE: {
3560       if (IsUndefined()) {
3561         os << "<undefined>";
3562       } else if (IsTheHole()) {
3563         os << "<the_hole>";
3564       } else if (IsNull()) {
3565         os << "<null>";
3566       } else if (IsTrue()) {
3567         os << "<true>";
3568       } else if (IsFalse()) {
3569         os << "<false>";
3570       } else {
3571         os << "<Odd Oddball: ";
3572         os << Oddball::cast(this)->to_string()->ToCString().get();
3573         os << ">";
3574       }
3575       break;
3576     }
3577     case SYMBOL_TYPE: {
3578       Symbol* symbol = Symbol::cast(this);
3579       symbol->SymbolShortPrint(os);
3580       break;
3581     }
3582     case HEAP_NUMBER_TYPE: {
3583       os << "<HeapNumber ";
3584       HeapNumber::cast(this)->HeapNumberPrint(os);
3585       os << ">";
3586       break;
3587     }
3588     case MUTABLE_HEAP_NUMBER_TYPE: {
3589       os << "<MutableHeapNumber ";
3590       MutableHeapNumber::cast(this)->MutableHeapNumberPrint(os);
3591       os << '>';
3592       break;
3593     }
3594     case BIGINT_TYPE: {
3595       os << "<BigInt ";
3596       BigInt::cast(this)->BigIntShortPrint(os);
3597       os << ">";
3598       break;
3599     }
3600     case JS_PROXY_TYPE:
3601       os << "<JSProxy>";
3602       break;
3603     case FOREIGN_TYPE:
3604       os << "<Foreign>";
3605       break;
3606     case CELL_TYPE: {
3607       os << "<Cell value= ";
3608       HeapStringAllocator allocator;
3609       StringStream accumulator(&allocator);
3610       Cell::cast(this)->value()->ShortPrint(&accumulator);
3611       os << accumulator.ToCString().get();
3612       os << '>';
3613       break;
3614     }
3615     case PROPERTY_CELL_TYPE: {
3616       PropertyCell* cell = PropertyCell::cast(this);
3617       os << "<PropertyCell name=";
3618       cell->name()->ShortPrint(os);
3619       os << " value=";
3620       HeapStringAllocator allocator;
3621       StringStream accumulator(&allocator);
3622       cell->value()->ShortPrint(&accumulator);
3623       os << accumulator.ToCString().get();
3624       os << '>';
3625       break;
3626     }
3627     case CALL_HANDLER_INFO_TYPE: {
3628       CallHandlerInfo* info = CallHandlerInfo::cast(this);
3629       os << "<CallHandlerInfo ";
3630       os << "callback= " << Brief(info->callback());
3631       os << ", js_callback= " << Brief(info->js_callback());
3632       os << ", data= " << Brief(info->data());
3633       if (info->IsSideEffectFreeCallHandlerInfo()) {
3634         os << ", side_effect_free= true>";
3635       } else {
3636         os << ", side_effect_free= false>";
3637       }
3638       break;
3639     }
3640     default:
3641       os << "<Other heap object (" << map()->instance_type() << ")>";
3642       break;
3643   }
3644 }
3645 
BriefPrintDetails(std::ostream & os)3646 void Struct::BriefPrintDetails(std::ostream& os) {}
3647 
BriefPrintDetails(std::ostream & os)3648 void Tuple2::BriefPrintDetails(std::ostream& os) {
3649   os << " " << Brief(value1()) << ", " << Brief(value2());
3650 }
3651 
BriefPrintDetails(std::ostream & os)3652 void Tuple3::BriefPrintDetails(std::ostream& os) {
3653   os << " " << Brief(value1()) << ", " << Brief(value2()) << ", "
3654      << Brief(value3());
3655 }
3656 
BriefPrintDetails(std::ostream & os)3657 void ArrayBoilerplateDescription::BriefPrintDetails(std::ostream& os) {
3658   os << " " << elements_kind() << ", " << Brief(constant_elements());
3659 }
3660 
BriefPrintDetails(std::ostream & os)3661 void CallableTask::BriefPrintDetails(std::ostream& os) {
3662   os << " callable=" << Brief(callable());
3663 }
3664 
Iterate(ObjectVisitor * v)3665 void HeapObject::Iterate(ObjectVisitor* v) { IterateFast<ObjectVisitor>(v); }
3666 
3667 
IterateBody(ObjectVisitor * v)3668 void HeapObject::IterateBody(ObjectVisitor* v) {
3669   Map* m = map();
3670   IterateBodyFast<ObjectVisitor>(m, SizeFromMap(m), v);
3671 }
3672 
IterateBody(Map * map,int object_size,ObjectVisitor * v)3673 void HeapObject::IterateBody(Map* map, int object_size, ObjectVisitor* v) {
3674   IterateBodyFast<ObjectVisitor>(map, object_size, v);
3675 }
3676 
3677 
3678 struct CallIsValidSlot {
3679   template <typename BodyDescriptor>
applyv8::internal::CallIsValidSlot3680   static bool apply(Map* map, HeapObject* obj, int offset, int) {
3681     return BodyDescriptor::IsValidSlot(map, obj, offset);
3682   }
3683 };
3684 
IsValidSlot(Map * map,int offset)3685 bool HeapObject::IsValidSlot(Map* map, int offset) {
3686   DCHECK_NE(0, offset);
3687   return BodyDescriptorApply<CallIsValidSlot, bool>(map->instance_type(), map,
3688                                                     this, offset, 0);
3689 }
3690 
class_name()3691 String* JSReceiver::class_name() {
3692   ReadOnlyRoots roots = GetReadOnlyRoots();
3693   if (IsFunction()) return roots.Function_string();
3694   if (IsJSArgumentsObject()) return roots.Arguments_string();
3695   if (IsJSArray()) return roots.Array_string();
3696   if (IsJSArrayBuffer()) {
3697     if (JSArrayBuffer::cast(this)->is_shared()) {
3698       return roots.SharedArrayBuffer_string();
3699     }
3700     return roots.ArrayBuffer_string();
3701   }
3702   if (IsJSArrayIterator()) return roots.ArrayIterator_string();
3703   if (IsJSDate()) return roots.Date_string();
3704   if (IsJSError()) return roots.Error_string();
3705   if (IsJSGeneratorObject()) return roots.Generator_string();
3706   if (IsJSMap()) return roots.Map_string();
3707   if (IsJSMapIterator()) return roots.MapIterator_string();
3708   if (IsJSProxy()) {
3709     return map()->is_callable() ? roots.Function_string()
3710                                 : roots.Object_string();
3711   }
3712   if (IsJSRegExp()) return roots.RegExp_string();
3713   if (IsJSSet()) return roots.Set_string();
3714   if (IsJSSetIterator()) return roots.SetIterator_string();
3715   if (IsJSTypedArray()) {
3716 #define SWITCH_KIND(Type, type, TYPE, ctype)       \
3717   if (map()->elements_kind() == TYPE##_ELEMENTS) { \
3718     return roots.Type##Array_string();             \
3719   }
3720     TYPED_ARRAYS(SWITCH_KIND)
3721 #undef SWITCH_KIND
3722   }
3723   if (IsJSValue()) {
3724     Object* value = JSValue::cast(this)->value();
3725     if (value->IsBoolean()) return roots.Boolean_string();
3726     if (value->IsString()) return roots.String_string();
3727     if (value->IsNumber()) return roots.Number_string();
3728     if (value->IsBigInt()) return roots.BigInt_string();
3729     if (value->IsSymbol()) return roots.Symbol_string();
3730     if (value->IsScript()) return roots.Script_string();
3731     UNREACHABLE();
3732   }
3733   if (IsJSWeakMap()) return roots.WeakMap_string();
3734   if (IsJSWeakSet()) return roots.WeakSet_string();
3735   if (IsJSGlobalProxy()) return roots.global_string();
3736 
3737   Object* maybe_constructor = map()->GetConstructor();
3738   if (maybe_constructor->IsJSFunction()) {
3739     JSFunction* constructor = JSFunction::cast(maybe_constructor);
3740     if (constructor->shared()->IsApiFunction()) {
3741       maybe_constructor = constructor->shared()->get_api_func_data();
3742     }
3743   }
3744 
3745   if (maybe_constructor->IsFunctionTemplateInfo()) {
3746     FunctionTemplateInfo* info = FunctionTemplateInfo::cast(maybe_constructor);
3747     if (info->class_name()->IsString()) return String::cast(info->class_name());
3748   }
3749 
3750   return roots.Object_string();
3751 }
3752 
CanBeRehashed() const3753 bool HeapObject::CanBeRehashed() const {
3754   DCHECK(NeedsRehashing());
3755   switch (map()->instance_type()) {
3756     case ORDERED_HASH_MAP_TYPE:
3757     case ORDERED_HASH_SET_TYPE:
3758       // TODO(yangguo): actually support rehashing OrderedHash{Map,Set}.
3759       return false;
3760     case NAME_DICTIONARY_TYPE:
3761     case GLOBAL_DICTIONARY_TYPE:
3762     case NUMBER_DICTIONARY_TYPE:
3763     case SIMPLE_NUMBER_DICTIONARY_TYPE:
3764     case STRING_TABLE_TYPE:
3765       return true;
3766     case DESCRIPTOR_ARRAY_TYPE:
3767       return true;
3768     case TRANSITION_ARRAY_TYPE:
3769       return true;
3770     case SMALL_ORDERED_HASH_MAP_TYPE:
3771       return SmallOrderedHashMap::cast(this)->NumberOfElements() == 0;
3772     case SMALL_ORDERED_HASH_SET_TYPE:
3773       return SmallOrderedHashMap::cast(this)->NumberOfElements() == 0;
3774     default:
3775       return false;
3776   }
3777   return false;
3778 }
3779 
RehashBasedOnMap(Isolate * isolate)3780 void HeapObject::RehashBasedOnMap(Isolate* isolate) {
3781   switch (map()->instance_type()) {
3782     case HASH_TABLE_TYPE:
3783       UNREACHABLE();
3784       break;
3785     case NAME_DICTIONARY_TYPE:
3786       NameDictionary::cast(this)->Rehash(isolate);
3787       break;
3788     case GLOBAL_DICTIONARY_TYPE:
3789       GlobalDictionary::cast(this)->Rehash(isolate);
3790       break;
3791     case NUMBER_DICTIONARY_TYPE:
3792       NumberDictionary::cast(this)->Rehash(isolate);
3793       break;
3794     case SIMPLE_NUMBER_DICTIONARY_TYPE:
3795       SimpleNumberDictionary::cast(this)->Rehash(isolate);
3796       break;
3797     case STRING_TABLE_TYPE:
3798       StringTable::cast(this)->Rehash(isolate);
3799       break;
3800     case DESCRIPTOR_ARRAY_TYPE:
3801       DCHECK_LE(1, DescriptorArray::cast(this)->number_of_descriptors());
3802       DescriptorArray::cast(this)->Sort();
3803       break;
3804     case TRANSITION_ARRAY_TYPE:
3805       TransitionArray::cast(this)->Sort();
3806       break;
3807     case SMALL_ORDERED_HASH_MAP_TYPE:
3808       DCHECK_EQ(0, SmallOrderedHashMap::cast(this)->NumberOfElements());
3809       break;
3810     case SMALL_ORDERED_HASH_SET_TYPE:
3811       DCHECK_EQ(0, SmallOrderedHashSet::cast(this)->NumberOfElements());
3812       break;
3813     default:
3814       break;
3815   }
3816 }
3817 
3818 namespace {
GetConstructorHelper(Handle<JSReceiver> receiver)3819 std::pair<MaybeHandle<JSFunction>, Handle<String>> GetConstructorHelper(
3820     Handle<JSReceiver> receiver) {
3821   Isolate* isolate = receiver->GetIsolate();
3822 
3823   // If the object was instantiated simply with base == new.target, the
3824   // constructor on the map provides the most accurate name.
3825   // Don't provide the info for prototypes, since their constructors are
3826   // reclaimed and replaced by Object in OptimizeAsPrototype.
3827   if (!receiver->IsJSProxy() && receiver->map()->new_target_is_base() &&
3828       !receiver->map()->is_prototype_map()) {
3829     Object* maybe_constructor = receiver->map()->GetConstructor();
3830     if (maybe_constructor->IsJSFunction()) {
3831       JSFunction* constructor = JSFunction::cast(maybe_constructor);
3832       String* name = constructor->shared()->DebugName();
3833       if (name->length() != 0 &&
3834           !name->Equals(ReadOnlyRoots(isolate).Object_string())) {
3835         return std::make_pair(handle(constructor, isolate),
3836                               handle(name, isolate));
3837       }
3838     } else if (maybe_constructor->IsFunctionTemplateInfo()) {
3839       FunctionTemplateInfo* info =
3840           FunctionTemplateInfo::cast(maybe_constructor);
3841       if (info->class_name()->IsString()) {
3842         return std::make_pair(
3843             MaybeHandle<JSFunction>(),
3844             handle(String::cast(info->class_name()), isolate));
3845       }
3846     }
3847   }
3848 
3849   Handle<Object> maybe_tag = JSReceiver::GetDataProperty(
3850       receiver, isolate->factory()->to_string_tag_symbol());
3851   if (maybe_tag->IsString())
3852     return std::make_pair(MaybeHandle<JSFunction>(),
3853                           Handle<String>::cast(maybe_tag));
3854 
3855   PrototypeIterator iter(isolate, receiver);
3856   if (iter.IsAtEnd()) {
3857     return std::make_pair(MaybeHandle<JSFunction>(),
3858                           handle(receiver->class_name(), isolate));
3859   }
3860 
3861   Handle<JSReceiver> start = PrototypeIterator::GetCurrent<JSReceiver>(iter);
3862   LookupIterator it(receiver, isolate->factory()->constructor_string(), start,
3863                     LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
3864   Handle<Object> maybe_constructor = JSReceiver::GetDataProperty(&it);
3865   if (maybe_constructor->IsJSFunction()) {
3866     JSFunction* constructor = JSFunction::cast(*maybe_constructor);
3867     String* name = constructor->shared()->DebugName();
3868 
3869     if (name->length() != 0 &&
3870         !name->Equals(ReadOnlyRoots(isolate).Object_string())) {
3871       return std::make_pair(handle(constructor, isolate),
3872                             handle(name, isolate));
3873     }
3874   }
3875 
3876   return std::make_pair(MaybeHandle<JSFunction>(),
3877                         handle(receiver->class_name(), isolate));
3878 }
3879 }  // anonymous namespace
3880 
3881 // static
GetConstructor(Handle<JSReceiver> receiver)3882 MaybeHandle<JSFunction> JSReceiver::GetConstructor(
3883     Handle<JSReceiver> receiver) {
3884   return GetConstructorHelper(receiver).first;
3885 }
3886 
3887 // static
GetConstructorName(Handle<JSReceiver> receiver)3888 Handle<String> JSReceiver::GetConstructorName(Handle<JSReceiver> receiver) {
3889   return GetConstructorHelper(receiver).second;
3890 }
3891 
GetCreationContext()3892 Handle<Context> JSReceiver::GetCreationContext() {
3893   JSReceiver* receiver = this;
3894   // Externals are JSObjects with null as a constructor.
3895   DCHECK(!receiver->IsExternal(GetIsolate()));
3896   Object* constructor = receiver->map()->GetConstructor();
3897   JSFunction* function;
3898   if (constructor->IsJSFunction()) {
3899     function = JSFunction::cast(constructor);
3900   } else if (constructor->IsFunctionTemplateInfo()) {
3901     // Remote objects don't have a creation context.
3902     return Handle<Context>::null();
3903   } else {
3904     // Functions have null as a constructor,
3905     // but any JSFunction knows its context immediately.
3906     CHECK(receiver->IsJSFunction());
3907     function = JSFunction::cast(receiver);
3908   }
3909 
3910   return function->has_context()
3911              ? Handle<Context>(function->context()->native_context(),
3912                                receiver->GetIsolate())
3913              : Handle<Context>::null();
3914 }
3915 
3916 // static
WrapFieldType(Isolate * isolate,Handle<FieldType> type)3917 MaybeObjectHandle Map::WrapFieldType(Isolate* isolate, Handle<FieldType> type) {
3918   if (type->IsClass()) {
3919     return MaybeObjectHandle::Weak(type->AsClass(), isolate);
3920   }
3921   return MaybeObjectHandle(type);
3922 }
3923 
3924 // static
UnwrapFieldType(MaybeObject * wrapped_type)3925 FieldType* Map::UnwrapFieldType(MaybeObject* wrapped_type) {
3926   if (wrapped_type->IsClearedWeakHeapObject()) {
3927     return FieldType::None();
3928   }
3929   HeapObject* heap_object;
3930   if (wrapped_type->ToWeakHeapObject(&heap_object)) {
3931     return FieldType::cast(heap_object);
3932   }
3933   return FieldType::cast(wrapped_type->ToObject());
3934 }
3935 
CopyWithField(Isolate * isolate,Handle<Map> map,Handle<Name> name,Handle<FieldType> type,PropertyAttributes attributes,PropertyConstness constness,Representation representation,TransitionFlag flag)3936 MaybeHandle<Map> Map::CopyWithField(Isolate* isolate, Handle<Map> map,
3937                                     Handle<Name> name, Handle<FieldType> type,
3938                                     PropertyAttributes attributes,
3939                                     PropertyConstness constness,
3940                                     Representation representation,
3941                                     TransitionFlag flag) {
3942   DCHECK(DescriptorArray::kNotFound ==
3943          map->instance_descriptors()->Search(
3944              *name, map->NumberOfOwnDescriptors()));
3945 
3946   // Ensure the descriptor array does not get too big.
3947   if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
3948     return MaybeHandle<Map>();
3949   }
3950 
3951   // Compute the new index for new field.
3952   int index = map->NextFreePropertyIndex();
3953 
3954   if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
3955     constness = PropertyConstness::kMutable;
3956     representation = Representation::Tagged();
3957     type = FieldType::Any(isolate);
3958   } else {
3959     Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
3960         isolate, map->instance_type(), &constness, &representation, &type);
3961   }
3962 
3963   MaybeObjectHandle wrapped_type = WrapFieldType(isolate, type);
3964 
3965   DCHECK_IMPLIES(!FLAG_track_constant_fields,
3966                  constness == PropertyConstness::kMutable);
3967   Descriptor d = Descriptor::DataField(name, index, attributes, constness,
3968                                        representation, wrapped_type);
3969   Handle<Map> new_map = Map::CopyAddDescriptor(isolate, map, &d, flag);
3970   new_map->AccountAddedPropertyField();
3971   return new_map;
3972 }
3973 
CopyWithConstant(Isolate * isolate,Handle<Map> map,Handle<Name> name,Handle<Object> constant,PropertyAttributes attributes,TransitionFlag flag)3974 MaybeHandle<Map> Map::CopyWithConstant(Isolate* isolate, Handle<Map> map,
3975                                        Handle<Name> name,
3976                                        Handle<Object> constant,
3977                                        PropertyAttributes attributes,
3978                                        TransitionFlag flag) {
3979   // Ensure the descriptor array does not get too big.
3980   if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
3981     return MaybeHandle<Map>();
3982   }
3983 
3984   if (FLAG_track_constant_fields) {
3985     Representation representation = constant->OptimalRepresentation();
3986     Handle<FieldType> type = constant->OptimalType(isolate, representation);
3987     return CopyWithField(isolate, map, name, type, attributes,
3988                          PropertyConstness::kConst, representation, flag);
3989   } else {
3990     // Allocate new instance descriptors with (name, constant) added.
3991     Descriptor d =
3992         Descriptor::DataConstant(isolate, name, 0, constant, attributes);
3993     Handle<Map> new_map = Map::CopyAddDescriptor(isolate, map, &d, flag);
3994     return new_map;
3995   }
3996 }
3997 
Mnemonic() const3998 const char* Representation::Mnemonic() const {
3999   switch (kind_) {
4000     case kNone: return "v";
4001     case kTagged: return "t";
4002     case kSmi: return "s";
4003     case kDouble: return "d";
4004     case kInteger32: return "i";
4005     case kHeapObject: return "h";
4006     case kExternal: return "x";
4007     default:
4008       UNREACHABLE();
4009   }
4010 }
4011 
TransitionRemovesTaggedField(Map * target) const4012 bool Map::TransitionRemovesTaggedField(Map* target) const {
4013   int inobject = NumberOfFields();
4014   int target_inobject = target->NumberOfFields();
4015   for (int i = target_inobject; i < inobject; i++) {
4016     FieldIndex index = FieldIndex::ForPropertyIndex(this, i);
4017     if (!IsUnboxedDoubleField(index)) return true;
4018   }
4019   return false;
4020 }
4021 
TransitionChangesTaggedFieldToUntaggedField(Map * target) const4022 bool Map::TransitionChangesTaggedFieldToUntaggedField(Map* target) const {
4023   int inobject = NumberOfFields();
4024   int target_inobject = target->NumberOfFields();
4025   int limit = Min(inobject, target_inobject);
4026   for (int i = 0; i < limit; i++) {
4027     FieldIndex index = FieldIndex::ForPropertyIndex(target, i);
4028     if (!IsUnboxedDoubleField(index) && target->IsUnboxedDoubleField(index)) {
4029       return true;
4030     }
4031   }
4032   return false;
4033 }
4034 
TransitionRequiresSynchronizationWithGC(Map * target) const4035 bool Map::TransitionRequiresSynchronizationWithGC(Map* target) const {
4036   return TransitionRemovesTaggedField(target) ||
4037          TransitionChangesTaggedFieldToUntaggedField(target);
4038 }
4039 
InstancesNeedRewriting(Map * target) const4040 bool Map::InstancesNeedRewriting(Map* target) const {
4041   int target_number_of_fields = target->NumberOfFields();
4042   int target_inobject = target->GetInObjectProperties();
4043   int target_unused = target->UnusedPropertyFields();
4044   int old_number_of_fields;
4045 
4046   return InstancesNeedRewriting(target, target_number_of_fields,
4047                                 target_inobject, target_unused,
4048                                 &old_number_of_fields);
4049 }
4050 
InstancesNeedRewriting(Map * target,int target_number_of_fields,int target_inobject,int target_unused,int * old_number_of_fields) const4051 bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields,
4052                                  int target_inobject, int target_unused,
4053                                  int* old_number_of_fields) const {
4054   // If fields were added (or removed), rewrite the instance.
4055   *old_number_of_fields = NumberOfFields();
4056   DCHECK(target_number_of_fields >= *old_number_of_fields);
4057   if (target_number_of_fields != *old_number_of_fields) return true;
4058 
4059   // If smi descriptors were replaced by double descriptors, rewrite.
4060   DescriptorArray* old_desc = instance_descriptors();
4061   DescriptorArray* new_desc = target->instance_descriptors();
4062   int limit = NumberOfOwnDescriptors();
4063   for (int i = 0; i < limit; i++) {
4064     if (new_desc->GetDetails(i).representation().IsDouble() !=
4065         old_desc->GetDetails(i).representation().IsDouble()) {
4066       return true;
4067     }
4068   }
4069 
4070   // If no fields were added, and no inobject properties were removed, setting
4071   // the map is sufficient.
4072   if (target_inobject == GetInObjectProperties()) return false;
4073   // In-object slack tracking may have reduced the object size of the new map.
4074   // In that case, succeed if all existing fields were inobject, and they still
4075   // fit within the new inobject size.
4076   DCHECK(target_inobject < GetInObjectProperties());
4077   if (target_number_of_fields <= target_inobject) {
4078     DCHECK(target_number_of_fields + target_unused == target_inobject);
4079     return false;
4080   }
4081   // Otherwise, properties will need to be moved to the backing store.
4082   return true;
4083 }
4084 
4085 
4086 // static
UpdatePrototypeUserRegistration(Handle<Map> old_map,Handle<Map> new_map,Isolate * isolate)4087 void JSObject::UpdatePrototypeUserRegistration(Handle<Map> old_map,
4088                                                Handle<Map> new_map,
4089                                                Isolate* isolate) {
4090   DCHECK(old_map->is_prototype_map());
4091   DCHECK(new_map->is_prototype_map());
4092   bool was_registered = JSObject::UnregisterPrototypeUser(old_map, isolate);
4093   new_map->set_prototype_info(old_map->prototype_info());
4094   old_map->set_prototype_info(Smi::kZero);
4095   if (FLAG_trace_prototype_users) {
4096     PrintF("Moving prototype_info %p from map %p to map %p.\n",
4097            reinterpret_cast<void*>(new_map->prototype_info()),
4098            reinterpret_cast<void*>(*old_map),
4099            reinterpret_cast<void*>(*new_map));
4100   }
4101   if (was_registered) {
4102     if (new_map->prototype_info()->IsPrototypeInfo()) {
4103       // The new map isn't registered with its prototype yet; reflect this fact
4104       // in the PrototypeInfo it just inherited from the old map.
4105       PrototypeInfo::cast(new_map->prototype_info())
4106           ->set_registry_slot(PrototypeInfo::UNREGISTERED);
4107     }
4108     JSObject::LazyRegisterPrototypeUser(new_map, isolate);
4109   }
4110 }
4111 
4112 namespace {
4113 // To migrate a fast instance to a fast map:
4114 // - First check whether the instance needs to be rewritten. If not, simply
4115 //   change the map.
4116 // - Otherwise, allocate a fixed array large enough to hold all fields, in
4117 //   addition to unused space.
4118 // - Copy all existing properties in, in the following order: backing store
4119 //   properties, unused fields, inobject properties.
4120 // - If all allocation succeeded, commit the state atomically:
4121 //   * Copy inobject properties from the backing store back into the object.
4122 //   * Trim the difference in instance size of the object. This also cleanly
4123 //     frees inobject properties that moved to the backing store.
4124 //   * If there are properties left in the backing store, trim of the space used
4125 //     to temporarily store the inobject properties.
4126 //   * If there are properties left in the backing store, install the backing
4127 //     store.
MigrateFastToFast(Handle<JSObject> object,Handle<Map> new_map)4128 void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
4129   Isolate* isolate = object->GetIsolate();
4130   Handle<Map> old_map(object->map(), isolate);
4131   // In case of a regular transition.
4132   if (new_map->GetBackPointer() == *old_map) {
4133     // If the map does not add named properties, simply set the map.
4134     if (old_map->NumberOfOwnDescriptors() ==
4135         new_map->NumberOfOwnDescriptors()) {
4136       object->synchronized_set_map(*new_map);
4137       return;
4138     }
4139 
4140     PropertyDetails details = new_map->GetLastDescriptorDetails();
4141     int target_index = details.field_index() - new_map->GetInObjectProperties();
4142     int property_array_length = object->property_array()->length();
4143     bool have_space = old_map->UnusedPropertyFields() > 0 ||
4144                       (details.location() == kField && target_index >= 0 &&
4145                        property_array_length > target_index);
4146     // Either new_map adds an kDescriptor property, or a kField property for
4147     // which there is still space, and which does not require a mutable double
4148     // box (an out-of-object double).
4149     if (details.location() == kDescriptor ||
4150         (have_space && ((FLAG_unbox_double_fields && target_index < 0) ||
4151                         !details.representation().IsDouble()))) {
4152       object->synchronized_set_map(*new_map);
4153       return;
4154     }
4155 
4156     // If there is still space in the object, we need to allocate a mutable
4157     // double box.
4158     if (have_space) {
4159       FieldIndex index =
4160           FieldIndex::ForDescriptor(*new_map, new_map->LastAdded());
4161       DCHECK(details.representation().IsDouble());
4162       DCHECK(!new_map->IsUnboxedDoubleField(index));
4163       auto value = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
4164       object->RawFastPropertyAtPut(index, *value);
4165       object->synchronized_set_map(*new_map);
4166       return;
4167     }
4168 
4169     // This migration is a transition from a map that has run out of property
4170     // space. Extend the backing store.
4171     int grow_by = new_map->UnusedPropertyFields() + 1;
4172     Handle<PropertyArray> old_storage(object->property_array(), isolate);
4173     Handle<PropertyArray> new_storage =
4174         isolate->factory()->CopyPropertyArrayAndGrow(old_storage, grow_by);
4175 
4176     // Properly initialize newly added property.
4177     Handle<Object> value;
4178     if (details.representation().IsDouble()) {
4179       value = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
4180     } else {
4181       value = isolate->factory()->uninitialized_value();
4182     }
4183     DCHECK_EQ(kField, details.location());
4184     DCHECK_EQ(kData, details.kind());
4185     DCHECK_GE(target_index, 0);  // Must be a backing store index.
4186     new_storage->set(target_index, *value);
4187 
4188     // From here on we cannot fail and we shouldn't GC anymore.
4189     DisallowHeapAllocation no_allocation;
4190 
4191     // Set the new property value and do the map transition.
4192     object->SetProperties(*new_storage);
4193     object->synchronized_set_map(*new_map);
4194     return;
4195   }
4196 
4197   int old_number_of_fields;
4198   int number_of_fields = new_map->NumberOfFields();
4199   int inobject = new_map->GetInObjectProperties();
4200   int unused = new_map->UnusedPropertyFields();
4201 
4202   // Nothing to do if no functions were converted to fields and no smis were
4203   // converted to doubles.
4204   if (!old_map->InstancesNeedRewriting(*new_map, number_of_fields, inobject,
4205                                        unused, &old_number_of_fields)) {
4206     object->synchronized_set_map(*new_map);
4207     return;
4208   }
4209 
4210   int total_size = number_of_fields + unused;
4211   int external = total_size - inobject;
4212   Handle<PropertyArray> array = isolate->factory()->NewPropertyArray(external);
4213 
4214   // We use this array to temporarily store the inobject properties.
4215   Handle<FixedArray> inobject_props =
4216       isolate->factory()->NewFixedArray(inobject);
4217 
4218   Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors(),
4219                                           isolate);
4220   Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors(),
4221                                           isolate);
4222   int old_nof = old_map->NumberOfOwnDescriptors();
4223   int new_nof = new_map->NumberOfOwnDescriptors();
4224 
4225   // This method only supports generalizing instances to at least the same
4226   // number of properties.
4227   DCHECK(old_nof <= new_nof);
4228 
4229   for (int i = 0; i < old_nof; i++) {
4230     PropertyDetails details = new_descriptors->GetDetails(i);
4231     if (details.location() != kField) continue;
4232     DCHECK_EQ(kData, details.kind());
4233     PropertyDetails old_details = old_descriptors->GetDetails(i);
4234     Representation old_representation = old_details.representation();
4235     Representation representation = details.representation();
4236     Handle<Object> value;
4237     if (old_details.location() == kDescriptor) {
4238       if (old_details.kind() == kAccessor) {
4239         // In case of kAccessor -> kData property reconfiguration, the property
4240         // must already be prepared for data of certain type.
4241         DCHECK(!details.representation().IsNone());
4242         if (details.representation().IsDouble()) {
4243           value = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
4244         } else {
4245           value = isolate->factory()->uninitialized_value();
4246         }
4247       } else {
4248         DCHECK_EQ(kData, old_details.kind());
4249         value = handle(old_descriptors->GetStrongValue(i), isolate);
4250         DCHECK(!old_representation.IsDouble() && !representation.IsDouble());
4251       }
4252     } else {
4253       DCHECK_EQ(kField, old_details.location());
4254       FieldIndex index = FieldIndex::ForDescriptor(*old_map, i);
4255       if (object->IsUnboxedDoubleField(index)) {
4256         uint64_t old_bits = object->RawFastDoublePropertyAsBitsAt(index);
4257         if (representation.IsDouble()) {
4258           value = isolate->factory()->NewMutableHeapNumberFromBits(old_bits);
4259         } else {
4260           value = isolate->factory()->NewHeapNumberFromBits(old_bits);
4261         }
4262       } else {
4263         value = handle(object->RawFastPropertyAt(index), isolate);
4264         if (!old_representation.IsDouble() && representation.IsDouble()) {
4265           DCHECK_IMPLIES(old_representation.IsNone(),
4266                          value->IsUninitialized(isolate));
4267           value = Object::NewStorageFor(isolate, value, representation);
4268         } else if (old_representation.IsDouble() &&
4269                    !representation.IsDouble()) {
4270           value = Object::WrapForRead(isolate, value, old_representation);
4271         }
4272       }
4273     }
4274     DCHECK(!(representation.IsDouble() && value->IsSmi()));
4275     int target_index = new_descriptors->GetFieldIndex(i);
4276     if (target_index < inobject) {
4277       inobject_props->set(target_index, *value);
4278     } else {
4279       array->set(target_index - inobject, *value);
4280     }
4281   }
4282 
4283   for (int i = old_nof; i < new_nof; i++) {
4284     PropertyDetails details = new_descriptors->GetDetails(i);
4285     if (details.location() != kField) continue;
4286     DCHECK_EQ(kData, details.kind());
4287     Handle<Object> value;
4288     if (details.representation().IsDouble()) {
4289       value = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
4290     } else {
4291       value = isolate->factory()->uninitialized_value();
4292     }
4293     int target_index = new_descriptors->GetFieldIndex(i);
4294     if (target_index < inobject) {
4295       inobject_props->set(target_index, *value);
4296     } else {
4297       array->set(target_index - inobject, *value);
4298     }
4299   }
4300 
4301   // From here on we cannot fail and we shouldn't GC anymore.
4302   DisallowHeapAllocation no_allocation;
4303 
4304   Heap* heap = isolate->heap();
4305 
4306   int old_instance_size = old_map->instance_size();
4307 
4308   heap->NotifyObjectLayoutChange(*object, old_instance_size, no_allocation);
4309 
4310   // Copy (real) inobject properties. If necessary, stop at number_of_fields to
4311   // avoid overwriting |one_pointer_filler_map|.
4312   int limit = Min(inobject, number_of_fields);
4313   for (int i = 0; i < limit; i++) {
4314     FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
4315     Object* value = inobject_props->get(i);
4316     // Can't use JSObject::FastPropertyAtPut() because proper map was not set
4317     // yet.
4318     if (new_map->IsUnboxedDoubleField(index)) {
4319       DCHECK(value->IsMutableHeapNumber());
4320       // Ensure that all bits of the double value are preserved.
4321       object->RawFastDoublePropertyAsBitsAtPut(
4322           index, MutableHeapNumber::cast(value)->value_as_bits());
4323       if (i < old_number_of_fields && !old_map->IsUnboxedDoubleField(index)) {
4324         // Transition from tagged to untagged slot.
4325         heap->ClearRecordedSlot(*object,
4326                                 HeapObject::RawField(*object, index.offset()));
4327       } else {
4328         DCHECK(!heap->HasRecordedSlot(
4329             *object, HeapObject::RawField(*object, index.offset())));
4330       }
4331     } else {
4332       object->RawFastPropertyAtPut(index, value);
4333     }
4334   }
4335 
4336   object->SetProperties(*array);
4337 
4338   // Create filler object past the new instance size.
4339   int new_instance_size = new_map->instance_size();
4340   int instance_size_delta = old_instance_size - new_instance_size;
4341   DCHECK_GE(instance_size_delta, 0);
4342 
4343   if (instance_size_delta > 0) {
4344     Address address = object->address();
4345     heap->CreateFillerObjectAt(address + new_instance_size, instance_size_delta,
4346                                ClearRecordedSlots::kYes);
4347   }
4348 
4349   // We are storing the new map using release store after creating a filler for
4350   // the left-over space to avoid races with the sweeper thread.
4351   object->synchronized_set_map(*new_map);
4352 }
4353 
MigrateFastToSlow(Handle<JSObject> object,Handle<Map> new_map,int expected_additional_properties)4354 void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map,
4355                        int expected_additional_properties) {
4356   // The global object is always normalized.
4357   DCHECK(!object->IsJSGlobalObject());
4358   // JSGlobalProxy must never be normalized
4359   DCHECK(!object->IsJSGlobalProxy());
4360 
4361   DCHECK_IMPLIES(new_map->is_prototype_map(),
4362                  Map::IsPrototypeChainInvalidated(*new_map));
4363 
4364   Isolate* isolate = object->GetIsolate();
4365   HandleScope scope(isolate);
4366   Handle<Map> map(object->map(), isolate);
4367 
4368   // Allocate new content.
4369   int real_size = map->NumberOfOwnDescriptors();
4370   int property_count = real_size;
4371   if (expected_additional_properties > 0) {
4372     property_count += expected_additional_properties;
4373   } else {
4374     // Make space for two more properties.
4375     property_count += NameDictionary::kInitialCapacity;
4376   }
4377   Handle<NameDictionary> dictionary =
4378       NameDictionary::New(isolate, property_count);
4379 
4380   Handle<DescriptorArray> descs(map->instance_descriptors(), isolate);
4381   for (int i = 0; i < real_size; i++) {
4382     PropertyDetails details = descs->GetDetails(i);
4383     Handle<Name> key(descs->GetKey(i), isolate);
4384     Handle<Object> value;
4385     if (details.location() == kField) {
4386       FieldIndex index = FieldIndex::ForDescriptor(*map, i);
4387       if (details.kind() == kData) {
4388         if (object->IsUnboxedDoubleField(index)) {
4389           double old_value = object->RawFastDoublePropertyAt(index);
4390           value = isolate->factory()->NewHeapNumber(old_value);
4391         } else {
4392           value = handle(object->RawFastPropertyAt(index), isolate);
4393           if (details.representation().IsDouble()) {
4394             DCHECK(value->IsMutableHeapNumber());
4395             double old_value = Handle<MutableHeapNumber>::cast(value)->value();
4396             value = isolate->factory()->NewHeapNumber(old_value);
4397           }
4398         }
4399       } else {
4400         DCHECK_EQ(kAccessor, details.kind());
4401         value = handle(object->RawFastPropertyAt(index), isolate);
4402       }
4403 
4404     } else {
4405       DCHECK_EQ(kDescriptor, details.location());
4406       value = handle(descs->GetStrongValue(i), isolate);
4407     }
4408     DCHECK(!value.is_null());
4409     PropertyDetails d(details.kind(), details.attributes(),
4410                       PropertyCellType::kNoCell);
4411     dictionary = NameDictionary::Add(isolate, dictionary, key, value, d);
4412   }
4413 
4414   // Copy the next enumeration index from instance descriptor.
4415   dictionary->SetNextEnumerationIndex(real_size + 1);
4416 
4417   // From here on we cannot fail and we shouldn't GC anymore.
4418   DisallowHeapAllocation no_allocation;
4419 
4420   Heap* heap = isolate->heap();
4421   int old_instance_size = map->instance_size();
4422   heap->NotifyObjectLayoutChange(*object, old_instance_size, no_allocation);
4423 
4424   // Resize the object in the heap if necessary.
4425   int new_instance_size = new_map->instance_size();
4426   int instance_size_delta = old_instance_size - new_instance_size;
4427   DCHECK_GE(instance_size_delta, 0);
4428 
4429   if (instance_size_delta > 0) {
4430     heap->CreateFillerObjectAt(object->address() + new_instance_size,
4431                                instance_size_delta, ClearRecordedSlots::kYes);
4432   }
4433 
4434   // We are storing the new map using release store after creating a filler for
4435   // the left-over space to avoid races with the sweeper thread.
4436   object->synchronized_set_map(*new_map);
4437 
4438   object->SetProperties(*dictionary);
4439 
4440   // Ensure that in-object space of slow-mode object does not contain random
4441   // garbage.
4442   int inobject_properties = new_map->GetInObjectProperties();
4443   if (inobject_properties) {
4444     Heap* heap = isolate->heap();
4445     heap->ClearRecordedSlotRange(
4446         object->address() + map->GetInObjectPropertyOffset(0),
4447         object->address() + new_instance_size);
4448 
4449     for (int i = 0; i < inobject_properties; i++) {
4450       FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
4451       object->RawFastPropertyAtPut(index, Smi::kZero);
4452     }
4453   }
4454 
4455   isolate->counters()->props_to_dictionary()->Increment();
4456 
4457 #ifdef DEBUG
4458   if (FLAG_trace_normalization) {
4459     StdoutStream os;
4460     os << "Object properties have been normalized:\n";
4461     object->Print(os);
4462   }
4463 #endif
4464 }
4465 
4466 }  // namespace
4467 
4468 // static
NotifyMapChange(Handle<Map> old_map,Handle<Map> new_map,Isolate * isolate)4469 void JSObject::NotifyMapChange(Handle<Map> old_map, Handle<Map> new_map,
4470                                Isolate* isolate) {
4471   if (!old_map->is_prototype_map()) return;
4472 
4473   InvalidatePrototypeChains(*old_map);
4474 
4475   // If the map was registered with its prototype before, ensure that it
4476   // registers with its new prototype now. This preserves the invariant that
4477   // when a map on a prototype chain is registered with its prototype, then
4478   // all prototypes further up the chain are also registered with their
4479   // respective prototypes.
4480   UpdatePrototypeUserRegistration(old_map, new_map, isolate);
4481 }
4482 
MigrateToMap(Handle<JSObject> object,Handle<Map> new_map,int expected_additional_properties)4483 void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
4484                             int expected_additional_properties) {
4485   if (object->map() == *new_map) return;
4486   Handle<Map> old_map(object->map(), object->GetIsolate());
4487   NotifyMapChange(old_map, new_map, object->GetIsolate());
4488 
4489   if (old_map->is_dictionary_map()) {
4490     // For slow-to-fast migrations JSObject::MigrateSlowToFast()
4491     // must be used instead.
4492     CHECK(new_map->is_dictionary_map());
4493 
4494     // Slow-to-slow migration is trivial.
4495     object->synchronized_set_map(*new_map);
4496   } else if (!new_map->is_dictionary_map()) {
4497     MigrateFastToFast(object, new_map);
4498     if (old_map->is_prototype_map()) {
4499       DCHECK(!old_map->is_stable());
4500       DCHECK(new_map->is_stable());
4501       DCHECK(new_map->owns_descriptors());
4502       DCHECK(old_map->owns_descriptors());
4503       // Transfer ownership to the new map. Keep the descriptor pointer of the
4504       // old map intact because the concurrent marker might be iterating the
4505       // object with the old map.
4506       old_map->set_owns_descriptors(false);
4507       DCHECK(old_map->is_abandoned_prototype_map());
4508       // Ensure that no transition was inserted for prototype migrations.
4509       DCHECK_EQ(0, TransitionsAccessor(object->GetIsolate(), old_map)
4510                        .NumberOfTransitions());
4511       DCHECK(new_map->GetBackPointer()->IsUndefined());
4512       DCHECK(object->map() != *old_map);
4513     }
4514   } else {
4515     MigrateFastToSlow(object, new_map, expected_additional_properties);
4516   }
4517 
4518   // Careful: Don't allocate here!
4519   // For some callers of this method, |object| might be in an inconsistent
4520   // state now: the new map might have a new elements_kind, but the object's
4521   // elements pointer hasn't been updated yet. Callers will fix this, but in
4522   // the meantime, (indirectly) calling JSObjectVerify() must be avoided.
4523   // When adding code here, add a DisallowHeapAllocation too.
4524 }
4525 
ForceSetPrototype(Handle<JSObject> object,Handle<Object> proto)4526 void JSObject::ForceSetPrototype(Handle<JSObject> object,
4527                                  Handle<Object> proto) {
4528   // object.__proto__ = proto;
4529   Handle<Map> old_map = Handle<Map>(object->map(), object->GetIsolate());
4530   Handle<Map> new_map =
4531       Map::Copy(object->GetIsolate(), old_map, "ForceSetPrototype");
4532   Map::SetPrototype(object->GetIsolate(), new_map, proto);
4533   JSObject::MigrateToMap(object, new_map);
4534 }
4535 
NumberOfFields() const4536 int Map::NumberOfFields() const {
4537   DescriptorArray* descriptors = instance_descriptors();
4538   int result = 0;
4539   for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
4540     if (descriptors->GetDetails(i).location() == kField) result++;
4541   }
4542   return result;
4543 }
4544 
HasOutOfObjectProperties() const4545 bool Map::HasOutOfObjectProperties() const {
4546   return GetInObjectProperties() < NumberOfFields();
4547 }
4548 
GeneralizeAllFields()4549 void DescriptorArray::GeneralizeAllFields() {
4550   int length = number_of_descriptors();
4551   for (int i = 0; i < length; i++) {
4552     PropertyDetails details = GetDetails(i);
4553     details = details.CopyWithRepresentation(Representation::Tagged());
4554     if (details.location() == kField) {
4555       DCHECK_EQ(kData, details.kind());
4556       details = details.CopyWithConstness(PropertyConstness::kMutable);
4557       SetValue(i, FieldType::Any());
4558     }
4559     set(ToDetailsIndex(i), MaybeObject::FromObject(details.AsSmi()));
4560   }
4561 }
4562 
CopyGeneralizeAllFields(Isolate * isolate,Handle<Map> map,ElementsKind elements_kind,int modify_index,PropertyKind kind,PropertyAttributes attributes,const char * reason)4563 Handle<Map> Map::CopyGeneralizeAllFields(Isolate* isolate, Handle<Map> map,
4564                                          ElementsKind elements_kind,
4565                                          int modify_index, PropertyKind kind,
4566                                          PropertyAttributes attributes,
4567                                          const char* reason) {
4568   Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
4569   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
4570   Handle<DescriptorArray> descriptors = DescriptorArray::CopyUpTo(
4571       isolate, old_descriptors, number_of_own_descriptors);
4572   descriptors->GeneralizeAllFields();
4573 
4574   Handle<LayoutDescriptor> new_layout_descriptor(
4575       LayoutDescriptor::FastPointerLayout(), isolate);
4576   Handle<Map> new_map = CopyReplaceDescriptors(
4577       isolate, map, descriptors, new_layout_descriptor, OMIT_TRANSITION,
4578       MaybeHandle<Name>(), reason, SPECIAL_TRANSITION);
4579 
4580   // Unless the instance is being migrated, ensure that modify_index is a field.
4581   if (modify_index >= 0) {
4582     PropertyDetails details = descriptors->GetDetails(modify_index);
4583     if (details.constness() != PropertyConstness::kMutable ||
4584         details.location() != kField || details.attributes() != attributes) {
4585       int field_index = details.location() == kField
4586                             ? details.field_index()
4587                             : new_map->NumberOfFields();
4588       Descriptor d = Descriptor::DataField(
4589           isolate, handle(descriptors->GetKey(modify_index), isolate),
4590           field_index, attributes, Representation::Tagged());
4591       descriptors->Replace(modify_index, &d);
4592       if (details.location() != kField) {
4593         new_map->AccountAddedPropertyField();
4594       }
4595     } else {
4596       DCHECK(details.attributes() == attributes);
4597     }
4598 
4599     if (FLAG_trace_generalization) {
4600       MaybeHandle<FieldType> field_type = FieldType::None(isolate);
4601       if (details.location() == kField) {
4602         field_type = handle(
4603             map->instance_descriptors()->GetFieldType(modify_index), isolate);
4604       }
4605       map->PrintGeneralization(
4606           isolate, stdout, reason, modify_index,
4607           new_map->NumberOfOwnDescriptors(), new_map->NumberOfOwnDescriptors(),
4608           details.location() == kDescriptor, details.representation(),
4609           Representation::Tagged(), field_type, MaybeHandle<Object>(),
4610           FieldType::Any(isolate), MaybeHandle<Object>());
4611     }
4612   }
4613   new_map->set_elements_kind(elements_kind);
4614   return new_map;
4615 }
4616 
DeprecateTransitionTree(Isolate * isolate)4617 void Map::DeprecateTransitionTree(Isolate* isolate) {
4618   if (is_deprecated()) return;
4619   DisallowHeapAllocation no_gc;
4620   TransitionsAccessor transitions(isolate, this, &no_gc);
4621   int num_transitions = transitions.NumberOfTransitions();
4622   for (int i = 0; i < num_transitions; ++i) {
4623     transitions.GetTarget(i)->DeprecateTransitionTree(isolate);
4624   }
4625   DCHECK(!constructor_or_backpointer()->IsFunctionTemplateInfo());
4626   set_is_deprecated(true);
4627   if (FLAG_trace_maps) {
4628     LOG(isolate, MapEvent("Deprecate", this, nullptr));
4629   }
4630   dependent_code()->DeoptimizeDependentCodeGroup(
4631       isolate, DependentCode::kTransitionGroup);
4632   NotifyLeafMapLayoutChange(isolate);
4633 }
4634 
4635 
4636 // Installs |new_descriptors| over the current instance_descriptors to ensure
4637 // proper sharing of descriptor arrays.
ReplaceDescriptors(Isolate * isolate,DescriptorArray * new_descriptors,LayoutDescriptor * new_layout_descriptor)4638 void Map::ReplaceDescriptors(Isolate* isolate, DescriptorArray* new_descriptors,
4639                              LayoutDescriptor* new_layout_descriptor) {
4640   // Don't overwrite the empty descriptor array or initial map's descriptors.
4641   if (NumberOfOwnDescriptors() == 0 || GetBackPointer()->IsUndefined(isolate)) {
4642     return;
4643   }
4644 
4645   DescriptorArray* to_replace = instance_descriptors();
4646   // Replace descriptors by new_descriptors in all maps that share it. The old
4647   // descriptors will not be trimmed in the mark-compactor, we need to mark
4648   // all its elements.
4649   MarkingBarrierForElements(isolate->heap(), to_replace);
4650   Map* current = this;
4651   while (current->instance_descriptors() == to_replace) {
4652     Object* next = current->GetBackPointer();
4653     if (next->IsUndefined(isolate)) break;  // Stop overwriting at initial map.
4654     current->SetEnumLength(kInvalidEnumCacheSentinel);
4655     current->UpdateDescriptors(new_descriptors, new_layout_descriptor);
4656     current = Map::cast(next);
4657   }
4658   set_owns_descriptors(false);
4659 }
4660 
FindRootMap(Isolate * isolate) const4661 Map* Map::FindRootMap(Isolate* isolate) const {
4662   const Map* result = this;
4663   while (true) {
4664     Object* back = result->GetBackPointer();
4665     if (back->IsUndefined(isolate)) {
4666       // Initial map always owns descriptors and doesn't have unused entries
4667       // in the descriptor array.
4668       DCHECK(result->owns_descriptors());
4669       DCHECK_EQ(result->NumberOfOwnDescriptors(),
4670                 result->instance_descriptors()->number_of_descriptors());
4671       return const_cast<Map*>(result);
4672     }
4673     result = Map::cast(back);
4674   }
4675 }
4676 
FindFieldOwner(Isolate * isolate,int descriptor) const4677 Map* Map::FindFieldOwner(Isolate* isolate, int descriptor) const {
4678   DisallowHeapAllocation no_allocation;
4679   DCHECK_EQ(kField, instance_descriptors()->GetDetails(descriptor).location());
4680   const Map* result = this;
4681   while (true) {
4682     Object* back = result->GetBackPointer();
4683     if (back->IsUndefined(isolate)) break;
4684     const Map* parent = Map::cast(back);
4685     if (parent->NumberOfOwnDescriptors() <= descriptor) break;
4686     result = parent;
4687   }
4688   return const_cast<Map*>(result);
4689 }
4690 
UpdateFieldType(Isolate * isolate,int descriptor,Handle<Name> name,PropertyConstness new_constness,Representation new_representation,MaybeObjectHandle new_wrapped_type)4691 void Map::UpdateFieldType(Isolate* isolate, int descriptor, Handle<Name> name,
4692                           PropertyConstness new_constness,
4693                           Representation new_representation,
4694                           MaybeObjectHandle new_wrapped_type) {
4695   DCHECK(new_wrapped_type->IsSmi() || new_wrapped_type->IsWeakHeapObject());
4696   // We store raw pointers in the queue, so no allocations are allowed.
4697   DisallowHeapAllocation no_allocation;
4698   PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
4699   if (details.location() != kField) return;
4700   DCHECK_EQ(kData, details.kind());
4701 
4702   Zone zone(isolate->allocator(), ZONE_NAME);
4703   ZoneQueue<Map*> backlog(&zone);
4704   backlog.push(this);
4705 
4706   while (!backlog.empty()) {
4707     Map* current = backlog.front();
4708     backlog.pop();
4709 
4710     TransitionsAccessor transitions(isolate, current, &no_allocation);
4711     int num_transitions = transitions.NumberOfTransitions();
4712     for (int i = 0; i < num_transitions; ++i) {
4713       Map* target = transitions.GetTarget(i);
4714       backlog.push(target);
4715     }
4716     DescriptorArray* descriptors = current->instance_descriptors();
4717     PropertyDetails details = descriptors->GetDetails(descriptor);
4718 
4719     // Currently constness change implies map change.
4720     DCHECK_IMPLIES(new_constness != details.constness(),
4721                    FLAG_modify_map_inplace);
4722 
4723     // It is allowed to change representation here only from None to something.
4724     DCHECK(details.representation().Equals(new_representation) ||
4725            details.representation().IsNone());
4726 
4727     // Skip if already updated the shared descriptor.
4728     if ((FLAG_modify_map_inplace && new_constness != details.constness()) ||
4729         descriptors->GetFieldType(descriptor) != *new_wrapped_type.object()) {
4730       DCHECK_IMPLIES(!FLAG_track_constant_fields,
4731                      new_constness == PropertyConstness::kMutable);
4732       Descriptor d = Descriptor::DataField(
4733           name, descriptors->GetFieldIndex(descriptor), details.attributes(),
4734           new_constness, new_representation, new_wrapped_type);
4735       descriptors->Replace(descriptor, &d);
4736     }
4737   }
4738 }
4739 
FieldTypeIsCleared(Representation rep,FieldType * type)4740 bool FieldTypeIsCleared(Representation rep, FieldType* type) {
4741   return type->IsNone() && rep.IsHeapObject();
4742 }
4743 
4744 
4745 // static
GeneralizeFieldType(Representation rep1,Handle<FieldType> type1,Representation rep2,Handle<FieldType> type2,Isolate * isolate)4746 Handle<FieldType> Map::GeneralizeFieldType(Representation rep1,
4747                                            Handle<FieldType> type1,
4748                                            Representation rep2,
4749                                            Handle<FieldType> type2,
4750                                            Isolate* isolate) {
4751   // Cleared field types need special treatment. They represent lost knowledge,
4752   // so we must be conservative, so their generalization with any other type
4753   // is "Any".
4754   if (FieldTypeIsCleared(rep1, *type1) || FieldTypeIsCleared(rep2, *type2)) {
4755     return FieldType::Any(isolate);
4756   }
4757   if (type1->NowIs(type2)) return type2;
4758   if (type2->NowIs(type1)) return type1;
4759   return FieldType::Any(isolate);
4760 }
4761 
4762 // static
GeneralizeField(Isolate * isolate,Handle<Map> map,int modify_index,PropertyConstness new_constness,Representation new_representation,Handle<FieldType> new_field_type)4763 void Map::GeneralizeField(Isolate* isolate, Handle<Map> map, int modify_index,
4764                           PropertyConstness new_constness,
4765                           Representation new_representation,
4766                           Handle<FieldType> new_field_type) {
4767   // Check if we actually need to generalize the field type at all.
4768   Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
4769   PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
4770   PropertyConstness old_constness = old_details.constness();
4771   Representation old_representation = old_details.representation();
4772   Handle<FieldType> old_field_type(old_descriptors->GetFieldType(modify_index),
4773                                    isolate);
4774 
4775   // Return if the current map is general enough to hold requested constness and
4776   // representation/field type.
4777   if (((FLAG_modify_map_inplace &&
4778         IsGeneralizableTo(new_constness, old_constness)) ||
4779        (!FLAG_modify_map_inplace && (old_constness == new_constness))) &&
4780       old_representation.Equals(new_representation) &&
4781       !FieldTypeIsCleared(new_representation, *new_field_type) &&
4782       // Checking old_field_type for being cleared is not necessary because
4783       // the NowIs check below would fail anyway in that case.
4784       new_field_type->NowIs(old_field_type)) {
4785     DCHECK(GeneralizeFieldType(old_representation, old_field_type,
4786                                new_representation, new_field_type, isolate)
4787                ->NowIs(old_field_type));
4788     return;
4789   }
4790 
4791   // Determine the field owner.
4792   Handle<Map> field_owner(map->FindFieldOwner(isolate, modify_index), isolate);
4793   Handle<DescriptorArray> descriptors(field_owner->instance_descriptors(),
4794                                       isolate);
4795   DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index));
4796 
4797   new_field_type =
4798       Map::GeneralizeFieldType(old_representation, old_field_type,
4799                                new_representation, new_field_type, isolate);
4800   if (FLAG_modify_map_inplace) {
4801     new_constness = GeneralizeConstness(old_constness, new_constness);
4802   }
4803 
4804   PropertyDetails details = descriptors->GetDetails(modify_index);
4805   Handle<Name> name(descriptors->GetKey(modify_index), isolate);
4806 
4807   MaybeObjectHandle wrapped_type(WrapFieldType(isolate, new_field_type));
4808   field_owner->UpdateFieldType(isolate, modify_index, name, new_constness,
4809                                new_representation, wrapped_type);
4810   field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
4811       isolate, DependentCode::kFieldOwnerGroup);
4812 
4813   if (FLAG_trace_generalization) {
4814     map->PrintGeneralization(
4815         isolate, stdout, "field type generalization", modify_index,
4816         map->NumberOfOwnDescriptors(), map->NumberOfOwnDescriptors(), false,
4817         details.representation(), details.representation(), old_field_type,
4818         MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>());
4819   }
4820 }
4821 
4822 // TODO(ishell): remove.
4823 // static
ReconfigureProperty(Isolate * isolate,Handle<Map> map,int modify_index,PropertyKind new_kind,PropertyAttributes new_attributes,Representation new_representation,Handle<FieldType> new_field_type)4824 Handle<Map> Map::ReconfigureProperty(Isolate* isolate, Handle<Map> map,
4825                                      int modify_index, PropertyKind new_kind,
4826                                      PropertyAttributes new_attributes,
4827                                      Representation new_representation,
4828                                      Handle<FieldType> new_field_type) {
4829   DCHECK_EQ(kData, new_kind);  // Only kData case is supported.
4830   MapUpdater mu(isolate, map);
4831   return mu.ReconfigureToDataField(modify_index, new_attributes,
4832                                    PropertyConstness::kConst,
4833                                    new_representation, new_field_type);
4834 }
4835 
4836 // TODO(ishell): remove.
4837 // static
ReconfigureElementsKind(Isolate * isolate,Handle<Map> map,ElementsKind new_elements_kind)4838 Handle<Map> Map::ReconfigureElementsKind(Isolate* isolate, Handle<Map> map,
4839                                          ElementsKind new_elements_kind) {
4840   MapUpdater mu(isolate, map);
4841   return mu.ReconfigureElementsKind(new_elements_kind);
4842 }
4843 
4844 // Generalize all fields and update the transition tree.
GeneralizeAllFields(Isolate * isolate,Handle<Map> map)4845 Handle<Map> Map::GeneralizeAllFields(Isolate* isolate, Handle<Map> map) {
4846   Handle<FieldType> any_type = FieldType::Any(isolate);
4847 
4848   Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
4849   for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) {
4850     PropertyDetails details = descriptors->GetDetails(i);
4851     if (details.location() == kField) {
4852       DCHECK_EQ(kData, details.kind());
4853       MapUpdater mu(isolate, map);
4854       map = mu.ReconfigureToDataField(i, details.attributes(),
4855                                       PropertyConstness::kMutable,
4856                                       Representation::Tagged(), any_type);
4857     }
4858   }
4859   return map;
4860 }
4861 
4862 
4863 // static
TryUpdate(Isolate * isolate,Handle<Map> old_map)4864 MaybeHandle<Map> Map::TryUpdate(Isolate* isolate, Handle<Map> old_map) {
4865   DisallowHeapAllocation no_allocation;
4866   DisallowDeoptimization no_deoptimization(isolate);
4867 
4868   if (!old_map->is_deprecated()) return old_map;
4869 
4870   // Check the state of the root map.
4871   Map* root_map = old_map->FindRootMap(isolate);
4872   if (root_map->is_deprecated()) {
4873     JSFunction* constructor = JSFunction::cast(root_map->GetConstructor());
4874     DCHECK(constructor->has_initial_map());
4875     DCHECK(constructor->initial_map()->is_dictionary_map());
4876     if (constructor->initial_map()->elements_kind() !=
4877         old_map->elements_kind()) {
4878       return MaybeHandle<Map>();
4879     }
4880     return handle(constructor->initial_map(), constructor->GetIsolate());
4881   }
4882   if (!old_map->EquivalentToForTransition(root_map)) return MaybeHandle<Map>();
4883 
4884   ElementsKind from_kind = root_map->elements_kind();
4885   ElementsKind to_kind = old_map->elements_kind();
4886   if (from_kind != to_kind) {
4887     // Try to follow existing elements kind transitions.
4888     root_map = root_map->LookupElementsTransitionMap(isolate, to_kind);
4889     if (root_map == nullptr) return MaybeHandle<Map>();
4890     // From here on, use the map with correct elements kind as root map.
4891   }
4892   Map* new_map = root_map->TryReplayPropertyTransitions(isolate, *old_map);
4893   if (new_map == nullptr) return MaybeHandle<Map>();
4894   return handle(new_map, isolate);
4895 }
4896 
TryReplayPropertyTransitions(Isolate * isolate,Map * old_map)4897 Map* Map::TryReplayPropertyTransitions(Isolate* isolate, Map* old_map) {
4898   DisallowHeapAllocation no_allocation;
4899   DisallowDeoptimization no_deoptimization(isolate);
4900 
4901   int root_nof = NumberOfOwnDescriptors();
4902 
4903   int old_nof = old_map->NumberOfOwnDescriptors();
4904   DescriptorArray* old_descriptors = old_map->instance_descriptors();
4905 
4906   Map* new_map = this;
4907   for (int i = root_nof; i < old_nof; ++i) {
4908     PropertyDetails old_details = old_descriptors->GetDetails(i);
4909     Map* transition =
4910         TransitionsAccessor(isolate, new_map, &no_allocation)
4911             .SearchTransition(old_descriptors->GetKey(i), old_details.kind(),
4912                               old_details.attributes());
4913     if (transition == nullptr) return nullptr;
4914     new_map = transition;
4915     DescriptorArray* new_descriptors = new_map->instance_descriptors();
4916 
4917     PropertyDetails new_details = new_descriptors->GetDetails(i);
4918     DCHECK_EQ(old_details.kind(), new_details.kind());
4919     DCHECK_EQ(old_details.attributes(), new_details.attributes());
4920     if (!IsGeneralizableTo(old_details.constness(), new_details.constness())) {
4921       return nullptr;
4922     }
4923     DCHECK(IsGeneralizableTo(old_details.location(), new_details.location()));
4924     if (!old_details.representation().fits_into(new_details.representation())) {
4925       return nullptr;
4926     }
4927     if (new_details.location() == kField) {
4928       if (new_details.kind() == kData) {
4929         FieldType* new_type = new_descriptors->GetFieldType(i);
4930         // Cleared field types need special treatment. They represent lost
4931         // knowledge, so we must first generalize the new_type to "Any".
4932         if (FieldTypeIsCleared(new_details.representation(), new_type)) {
4933           return nullptr;
4934         }
4935         DCHECK_EQ(kData, old_details.kind());
4936         if (old_details.location() == kField) {
4937           FieldType* old_type = old_descriptors->GetFieldType(i);
4938           if (FieldTypeIsCleared(old_details.representation(), old_type) ||
4939               !old_type->NowIs(new_type)) {
4940             return nullptr;
4941           }
4942         } else {
4943           DCHECK_EQ(kDescriptor, old_details.location());
4944           DCHECK(!FLAG_track_constant_fields);
4945           Object* old_value = old_descriptors->GetStrongValue(i);
4946           if (!new_type->NowContains(old_value)) {
4947             return nullptr;
4948           }
4949         }
4950 
4951       } else {
4952         DCHECK_EQ(kAccessor, new_details.kind());
4953 #ifdef DEBUG
4954         FieldType* new_type = new_descriptors->GetFieldType(i);
4955         DCHECK(new_type->IsAny());
4956 #endif
4957         UNREACHABLE();
4958       }
4959     } else {
4960       DCHECK_EQ(kDescriptor, new_details.location());
4961       if (old_details.location() == kField ||
4962           old_descriptors->GetStrongValue(i) !=
4963               new_descriptors->GetStrongValue(i)) {
4964         return nullptr;
4965       }
4966     }
4967   }
4968   if (new_map->NumberOfOwnDescriptors() != old_nof) return nullptr;
4969   return new_map;
4970 }
4971 
4972 
4973 // static
Update(Isolate * isolate,Handle<Map> map)4974 Handle<Map> Map::Update(Isolate* isolate, Handle<Map> map) {
4975   if (!map->is_deprecated()) return map;
4976   MapUpdater mu(isolate, map);
4977   return mu.Update();
4978 }
4979 
SetPropertyWithInterceptor(LookupIterator * it,ShouldThrow should_throw,Handle<Object> value)4980 Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
4981                                                  ShouldThrow should_throw,
4982                                                  Handle<Object> value) {
4983   DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
4984   return SetPropertyWithInterceptorInternal(it, it->GetInterceptor(),
4985                                             should_throw, value);
4986 }
4987 
SetProperty(Isolate * isolate,Handle<Object> object,Handle<Name> name,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode)4988 MaybeHandle<Object> Object::SetProperty(Isolate* isolate, Handle<Object> object,
4989                                         Handle<Name> name, Handle<Object> value,
4990                                         LanguageMode language_mode,
4991                                         StoreFromKeyed store_mode) {
4992   LookupIterator it(isolate, object, name);
4993   MAYBE_RETURN_NULL(SetProperty(&it, value, language_mode, store_mode));
4994   return value;
4995 }
4996 
4997 
SetPropertyInternal(LookupIterator * it,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode,bool * found)4998 Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
4999                                         Handle<Object> value,
5000                                         LanguageMode language_mode,
5001                                         StoreFromKeyed store_mode,
5002                                         bool* found) {
5003   it->UpdateProtector();
5004   DCHECK(it->IsFound());
5005   ShouldThrow should_throw =
5006       is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
5007 
5008   // Make sure that the top context does not change when doing callbacks or
5009   // interceptor calls.
5010   AssertNoContextChange ncc(it->isolate());
5011 
5012   do {
5013     switch (it->state()) {
5014       case LookupIterator::NOT_FOUND:
5015         UNREACHABLE();
5016 
5017       case LookupIterator::ACCESS_CHECK:
5018         if (it->HasAccess()) break;
5019         // Check whether it makes sense to reuse the lookup iterator. Here it
5020         // might still call into setters up the prototype chain.
5021         return JSObject::SetPropertyWithFailedAccessCheck(it, value,
5022                                                           should_throw);
5023 
5024       case LookupIterator::JSPROXY:
5025         return JSProxy::SetProperty(it->GetHolder<JSProxy>(), it->GetName(),
5026                                     value, it->GetReceiver(), language_mode);
5027 
5028       case LookupIterator::INTERCEPTOR: {
5029         if (it->HolderIsReceiverOrHiddenPrototype()) {
5030           Maybe<bool> result =
5031               JSObject::SetPropertyWithInterceptor(it, should_throw, value);
5032           if (result.IsNothing() || result.FromJust()) return result;
5033         } else {
5034           Maybe<PropertyAttributes> maybe_attributes =
5035               JSObject::GetPropertyAttributesWithInterceptor(it);
5036           if (maybe_attributes.IsNothing()) return Nothing<bool>();
5037           if ((maybe_attributes.FromJust() & READ_ONLY) != 0) {
5038             return WriteToReadOnlyProperty(it, value, should_throw);
5039           }
5040           if (maybe_attributes.FromJust() == ABSENT) break;
5041           *found = false;
5042           return Nothing<bool>();
5043         }
5044         break;
5045       }
5046 
5047       case LookupIterator::ACCESSOR: {
5048         if (it->IsReadOnly()) {
5049           return WriteToReadOnlyProperty(it, value, should_throw);
5050         }
5051         Handle<Object> accessors = it->GetAccessors();
5052         if (accessors->IsAccessorInfo() &&
5053             !it->HolderIsReceiverOrHiddenPrototype() &&
5054             AccessorInfo::cast(*accessors)->is_special_data_property()) {
5055           *found = false;
5056           return Nothing<bool>();
5057         }
5058         return SetPropertyWithAccessor(it, value, should_throw);
5059       }
5060       case LookupIterator::INTEGER_INDEXED_EXOTIC: {
5061         // IntegerIndexedElementSet converts value to a Number/BigInt prior to
5062         // the bounds check. The bounds check has already happened here, but
5063         // perform the possibly effectful ToNumber (or ToBigInt) operation
5064         // anyways.
5065         auto holder = it->GetHolder<JSTypedArray>();
5066         Handle<Object> throwaway_value;
5067         if (holder->type() == kExternalBigInt64Array ||
5068             holder->type() == kExternalBigUint64Array) {
5069           ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5070               it->isolate(), throwaway_value,
5071               BigInt::FromObject(it->isolate(), value), Nothing<bool>());
5072         } else {
5073           ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5074               it->isolate(), throwaway_value,
5075               Object::ToNumber(it->isolate(), value), Nothing<bool>());
5076         }
5077 
5078         // FIXME: Throw a TypeError if the holder is neutered here
5079         // (IntegerIndexedElementSpec step 5).
5080 
5081         // TODO(verwaest): Per spec, we should return false here (steps 6-9
5082         // in IntegerIndexedElementSpec), resulting in an exception being thrown
5083         // on OOB accesses in strict code. Historically, v8 has not done made
5084         // this change due to uncertainty about web compat. (v8:4901)
5085         return Just(true);
5086       }
5087 
5088       case LookupIterator::DATA:
5089         if (it->IsReadOnly()) {
5090           return WriteToReadOnlyProperty(it, value, should_throw);
5091         }
5092         if (it->HolderIsReceiverOrHiddenPrototype()) {
5093           return SetDataProperty(it, value);
5094         }
5095         V8_FALLTHROUGH;
5096       case LookupIterator::TRANSITION:
5097         *found = false;
5098         return Nothing<bool>();
5099     }
5100     it->Next();
5101   } while (it->IsFound());
5102 
5103   *found = false;
5104   return Nothing<bool>();
5105 }
5106 
5107 
SetProperty(LookupIterator * it,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode)5108 Maybe<bool> Object::SetProperty(LookupIterator* it, Handle<Object> value,
5109                                 LanguageMode language_mode,
5110                                 StoreFromKeyed store_mode) {
5111   if (it->IsFound()) {
5112     bool found = true;
5113     Maybe<bool> result =
5114         SetPropertyInternal(it, value, language_mode, store_mode, &found);
5115     if (found) return result;
5116   }
5117 
5118   // If the receiver is the JSGlobalObject, the store was contextual. In case
5119   // the property did not exist yet on the global object itself, we have to
5120   // throw a reference error in strict mode.  In sloppy mode, we continue.
5121   if (is_strict(language_mode) && it->GetReceiver()->IsJSGlobalObject()) {
5122     it->isolate()->Throw(*it->isolate()->factory()->NewReferenceError(
5123         MessageTemplate::kNotDefined, it->name()));
5124     return Nothing<bool>();
5125   }
5126 
5127   ShouldThrow should_throw =
5128       is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
5129   return AddDataProperty(it, value, NONE, should_throw, store_mode);
5130 }
5131 
5132 
SetSuperProperty(LookupIterator * it,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode)5133 Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
5134                                      LanguageMode language_mode,
5135                                      StoreFromKeyed store_mode) {
5136   Isolate* isolate = it->isolate();
5137 
5138   if (it->IsFound()) {
5139     bool found = true;
5140     Maybe<bool> result =
5141         SetPropertyInternal(it, value, language_mode, store_mode, &found);
5142     if (found) return result;
5143   }
5144 
5145   it->UpdateProtector();
5146 
5147   // The property either doesn't exist on the holder or exists there as a data
5148   // property.
5149 
5150   ShouldThrow should_throw =
5151       is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
5152 
5153   if (!it->GetReceiver()->IsJSReceiver()) {
5154     return WriteToReadOnlyProperty(it, value, should_throw);
5155   }
5156   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
5157 
5158   LookupIterator::Configuration c = LookupIterator::OWN;
5159   LookupIterator own_lookup =
5160       it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c)
5161                       : LookupIterator(isolate, receiver, it->name(), c);
5162 
5163   for (; own_lookup.IsFound(); own_lookup.Next()) {
5164     switch (own_lookup.state()) {
5165       case LookupIterator::ACCESS_CHECK:
5166         if (!own_lookup.HasAccess()) {
5167           return JSObject::SetPropertyWithFailedAccessCheck(&own_lookup, value,
5168                                                             should_throw);
5169         }
5170         break;
5171 
5172       case LookupIterator::ACCESSOR:
5173         if (own_lookup.GetAccessors()->IsAccessorInfo()) {
5174           if (own_lookup.IsReadOnly()) {
5175             return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
5176           }
5177           return JSObject::SetPropertyWithAccessor(&own_lookup, value,
5178                                                    should_throw);
5179         }
5180         V8_FALLTHROUGH;
5181       case LookupIterator::INTEGER_INDEXED_EXOTIC:
5182         return RedefineIncompatibleProperty(isolate, it->GetName(), value,
5183                                             should_throw);
5184 
5185       case LookupIterator::DATA: {
5186         if (own_lookup.IsReadOnly()) {
5187           return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
5188         }
5189         return SetDataProperty(&own_lookup, value);
5190       }
5191 
5192       case LookupIterator::INTERCEPTOR:
5193       case LookupIterator::JSPROXY: {
5194         PropertyDescriptor desc;
5195         Maybe<bool> owned =
5196             JSReceiver::GetOwnPropertyDescriptor(&own_lookup, &desc);
5197         MAYBE_RETURN(owned, Nothing<bool>());
5198         if (!owned.FromJust()) {
5199           return JSReceiver::CreateDataProperty(&own_lookup, value,
5200                                                 should_throw);
5201         }
5202         if (PropertyDescriptor::IsAccessorDescriptor(&desc) ||
5203             !desc.writable()) {
5204           return RedefineIncompatibleProperty(isolate, it->GetName(), value,
5205                                               should_throw);
5206         }
5207 
5208         PropertyDescriptor value_desc;
5209         value_desc.set_value(value);
5210         return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
5211                                              &value_desc, should_throw);
5212       }
5213 
5214       case LookupIterator::NOT_FOUND:
5215       case LookupIterator::TRANSITION:
5216         UNREACHABLE();
5217     }
5218   }
5219 
5220   return AddDataProperty(&own_lookup, value, NONE, should_throw, store_mode);
5221 }
5222 
CannotCreateProperty(Isolate * isolate,Handle<Object> receiver,Handle<Object> name,Handle<Object> value,ShouldThrow should_throw)5223 Maybe<bool> Object::CannotCreateProperty(Isolate* isolate,
5224                                          Handle<Object> receiver,
5225                                          Handle<Object> name,
5226                                          Handle<Object> value,
5227                                          ShouldThrow should_throw) {
5228   RETURN_FAILURE(
5229       isolate, should_throw,
5230       NewTypeError(MessageTemplate::kStrictCannotCreateProperty, name,
5231                    Object::TypeOf(isolate, receiver), receiver));
5232 }
5233 
5234 
WriteToReadOnlyProperty(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)5235 Maybe<bool> Object::WriteToReadOnlyProperty(LookupIterator* it,
5236                                             Handle<Object> value,
5237                                             ShouldThrow should_throw) {
5238   return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(),
5239                                  it->GetName(), value, should_throw);
5240 }
5241 
5242 
WriteToReadOnlyProperty(Isolate * isolate,Handle<Object> receiver,Handle<Object> name,Handle<Object> value,ShouldThrow should_throw)5243 Maybe<bool> Object::WriteToReadOnlyProperty(Isolate* isolate,
5244                                             Handle<Object> receiver,
5245                                             Handle<Object> name,
5246                                             Handle<Object> value,
5247                                             ShouldThrow should_throw) {
5248   RETURN_FAILURE(isolate, should_throw,
5249                  NewTypeError(MessageTemplate::kStrictReadOnlyProperty, name,
5250                               Object::TypeOf(isolate, receiver), receiver));
5251 }
5252 
5253 
RedefineIncompatibleProperty(Isolate * isolate,Handle<Object> name,Handle<Object> value,ShouldThrow should_throw)5254 Maybe<bool> Object::RedefineIncompatibleProperty(Isolate* isolate,
5255                                                  Handle<Object> name,
5256                                                  Handle<Object> value,
5257                                                  ShouldThrow should_throw) {
5258   RETURN_FAILURE(isolate, should_throw,
5259                  NewTypeError(MessageTemplate::kRedefineDisallowed, name));
5260 }
5261 
5262 
SetDataProperty(LookupIterator * it,Handle<Object> value)5263 Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) {
5264   DCHECK_IMPLIES(it->GetReceiver()->IsJSProxy(),
5265                  it->GetName()->IsPrivateField());
5266   DCHECK_IMPLIES(!it->IsElement() && it->GetName()->IsPrivateField(),
5267                  it->state() == LookupIterator::DATA);
5268   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
5269 
5270   // Store on the holder which may be hidden behind the receiver.
5271   DCHECK(it->HolderIsReceiverOrHiddenPrototype());
5272 
5273   Handle<Object> to_assign = value;
5274   // Convert the incoming value to a number for storing into typed arrays.
5275   if (it->IsElement() && receiver->IsJSObject() &&
5276       JSObject::cast(*receiver)->HasFixedTypedArrayElements()) {
5277     ElementsKind elements_kind = JSObject::cast(*receiver)->GetElementsKind();
5278     if (elements_kind == BIGINT64_ELEMENTS ||
5279         elements_kind == BIGUINT64_ELEMENTS) {
5280       ASSIGN_RETURN_ON_EXCEPTION_VALUE(it->isolate(), to_assign,
5281                                        BigInt::FromObject(it->isolate(), value),
5282                                        Nothing<bool>());
5283       // We have to recheck the length. However, it can only change if the
5284       // underlying buffer was neutered, so just check that.
5285       if (Handle<JSArrayBufferView>::cast(receiver)->WasNeutered()) {
5286         return Just(true);
5287         // TODO(neis): According to the spec, this should throw a TypeError.
5288       }
5289     } else if (!value->IsNumber() && !value->IsUndefined(it->isolate())) {
5290       ASSIGN_RETURN_ON_EXCEPTION_VALUE(it->isolate(), to_assign,
5291                                        Object::ToNumber(it->isolate(), value),
5292                                        Nothing<bool>());
5293       // We have to recheck the length. However, it can only change if the
5294       // underlying buffer was neutered, so just check that.
5295       if (Handle<JSArrayBufferView>::cast(receiver)->WasNeutered()) {
5296         return Just(true);
5297         // TODO(neis): According to the spec, this should throw a TypeError.
5298       }
5299     }
5300   }
5301 
5302   // Possibly migrate to the most up-to-date map that will be able to store
5303   // |value| under it->name().
5304   it->PrepareForDataProperty(to_assign);
5305 
5306   // Write the property value.
5307   it->WriteDataValue(to_assign, false);
5308 
5309 #if VERIFY_HEAP
5310   if (FLAG_verify_heap) {
5311     receiver->HeapObjectVerify(it->isolate());
5312   }
5313 #endif
5314   return Just(true);
5315 }
5316 
5317 
AddDataProperty(LookupIterator * it,Handle<Object> value,PropertyAttributes attributes,ShouldThrow should_throw,StoreFromKeyed store_mode)5318 Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value,
5319                                     PropertyAttributes attributes,
5320                                     ShouldThrow should_throw,
5321                                     StoreFromKeyed store_mode) {
5322   if (!it->GetReceiver()->IsJSReceiver()) {
5323     return CannotCreateProperty(it->isolate(), it->GetReceiver(), it->GetName(),
5324                                 value, should_throw);
5325   }
5326 
5327   // Private symbols should be installed on JSProxy using
5328   // JSProxy::SetPrivateSymbol.
5329   if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate() &&
5330       !it->GetName()->IsPrivateField()) {
5331     RETURN_FAILURE(it->isolate(), should_throw,
5332                    NewTypeError(MessageTemplate::kProxyPrivate));
5333   }
5334 
5335   DCHECK_NE(LookupIterator::INTEGER_INDEXED_EXOTIC, it->state());
5336 
5337   Handle<JSReceiver> receiver = it->GetStoreTarget<JSReceiver>();
5338   DCHECK_IMPLIES(receiver->IsJSProxy(), it->GetName()->IsPrivateField());
5339   DCHECK_IMPLIES(receiver->IsJSProxy(),
5340                  it->state() == LookupIterator::NOT_FOUND);
5341 
5342   // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject)
5343   // instead. If the prototype is Null, the proxy is detached.
5344   if (receiver->IsJSGlobalProxy()) return Just(true);
5345 
5346   Isolate* isolate = it->isolate();
5347 
5348   if (it->ExtendingNonExtensible(receiver)) {
5349     RETURN_FAILURE(
5350         isolate, should_throw,
5351         NewTypeError(MessageTemplate::kObjectNotExtensible, it->GetName()));
5352   }
5353 
5354   if (it->IsElement()) {
5355     if (receiver->IsJSArray()) {
5356       Handle<JSArray> array = Handle<JSArray>::cast(receiver);
5357       if (JSArray::WouldChangeReadOnlyLength(array, it->index())) {
5358         RETURN_FAILURE(isolate, should_throw,
5359                        NewTypeError(MessageTemplate::kStrictReadOnlyProperty,
5360                                     isolate->factory()->length_string(),
5361                                     Object::TypeOf(isolate, array), array));
5362       }
5363 
5364       if (FLAG_trace_external_array_abuse &&
5365           array->HasFixedTypedArrayElements()) {
5366         CheckArrayAbuse(array, "typed elements write", it->index(), true);
5367       }
5368 
5369       if (FLAG_trace_js_array_abuse && !array->HasFixedTypedArrayElements()) {
5370         CheckArrayAbuse(array, "elements write", it->index(), false);
5371       }
5372     }
5373 
5374     Handle<JSObject> receiver_obj = Handle<JSObject>::cast(receiver);
5375     JSObject::AddDataElement(receiver_obj, it->index(), value, attributes);
5376     JSObject::ValidateElements(*receiver_obj);
5377     return Just(true);
5378   } else {
5379     it->UpdateProtector();
5380     // Migrate to the most up-to-date map that will be able to store |value|
5381     // under it->name() with |attributes|.
5382     it->PrepareTransitionToDataProperty(receiver, value, attributes,
5383                                         store_mode);
5384     DCHECK_EQ(LookupIterator::TRANSITION, it->state());
5385     it->ApplyTransitionToDataProperty(receiver);
5386 
5387     // Write the property value.
5388     it->WriteDataValue(value, true);
5389 
5390 #if VERIFY_HEAP
5391     if (FLAG_verify_heap) {
5392       receiver->HeapObjectVerify(isolate);
5393     }
5394 #endif
5395   }
5396 
5397   return Just(true);
5398 }
5399 
EnsureDescriptorSlack(Isolate * isolate,Handle<Map> map,int slack)5400 void Map::EnsureDescriptorSlack(Isolate* isolate, Handle<Map> map, int slack) {
5401   // Only supports adding slack to owned descriptors.
5402   DCHECK(map->owns_descriptors());
5403 
5404   Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
5405   int old_size = map->NumberOfOwnDescriptors();
5406   if (slack <= descriptors->NumberOfSlackDescriptors()) return;
5407 
5408   Handle<DescriptorArray> new_descriptors =
5409       DescriptorArray::CopyUpTo(isolate, descriptors, old_size, slack);
5410 
5411   DisallowHeapAllocation no_allocation;
5412   // The descriptors are still the same, so keep the layout descriptor.
5413   LayoutDescriptor* layout_descriptor = map->GetLayoutDescriptor();
5414 
5415   if (old_size == 0) {
5416     map->UpdateDescriptors(*new_descriptors, layout_descriptor);
5417     return;
5418   }
5419 
5420   // If the source descriptors had an enum cache we copy it. This ensures
5421   // that the maps to which we push the new descriptor array back can rely
5422   // on a cache always being available once it is set. If the map has more
5423   // enumerated descriptors than available in the original cache, the cache
5424   // will be lazily replaced by the extended cache when needed.
5425   new_descriptors->CopyEnumCacheFrom(*descriptors);
5426 
5427   // Replace descriptors by new_descriptors in all maps that share it. The old
5428   // descriptors will not be trimmed in the mark-compactor, we need to mark
5429   // all its elements.
5430   MarkingBarrierForElements(isolate->heap(), *descriptors);
5431 
5432   Map* current = *map;
5433   while (current->instance_descriptors() == *descriptors) {
5434     Object* next = current->GetBackPointer();
5435     if (next->IsUndefined(isolate)) break;  // Stop overwriting at initial map.
5436     current->UpdateDescriptors(*new_descriptors, layout_descriptor);
5437     current = Map::cast(next);
5438   }
5439   map->UpdateDescriptors(*new_descriptors, layout_descriptor);
5440 }
5441 
5442 // static
GetObjectCreateMap(Isolate * isolate,Handle<HeapObject> prototype)5443 Handle<Map> Map::GetObjectCreateMap(Isolate* isolate,
5444                                     Handle<HeapObject> prototype) {
5445   Handle<Map> map(isolate->native_context()->object_function()->initial_map(),
5446                   isolate);
5447   if (map->prototype() == *prototype) return map;
5448   if (prototype->IsNull(isolate)) {
5449     return isolate->slow_object_with_null_prototype_map();
5450   }
5451   if (prototype->IsJSObject()) {
5452     Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype);
5453     if (!js_prototype->map()->is_prototype_map()) {
5454       JSObject::OptimizeAsPrototype(js_prototype);
5455     }
5456     Handle<PrototypeInfo> info =
5457         Map::GetOrCreatePrototypeInfo(js_prototype, isolate);
5458     // TODO(verwaest): Use inobject slack tracking for this map.
5459     if (info->HasObjectCreateMap()) {
5460       map = handle(info->ObjectCreateMap(), isolate);
5461     } else {
5462       map = Map::CopyInitialMap(isolate, map);
5463       Map::SetPrototype(isolate, map, prototype);
5464       PrototypeInfo::SetObjectCreateMap(info, map);
5465     }
5466     return map;
5467   }
5468 
5469   return Map::TransitionToPrototype(isolate, map, prototype);
5470 }
5471 
5472 // static
TryGetObjectCreateMap(Isolate * isolate,Handle<HeapObject> prototype)5473 MaybeHandle<Map> Map::TryGetObjectCreateMap(Isolate* isolate,
5474                                             Handle<HeapObject> prototype) {
5475   Handle<Map> map(isolate->native_context()->object_function()->initial_map(),
5476                   isolate);
5477   if (map->prototype() == *prototype) return map;
5478   if (prototype->IsNull(isolate)) {
5479     return isolate->slow_object_with_null_prototype_map();
5480   }
5481   if (!prototype->IsJSObject()) return MaybeHandle<Map>();
5482   Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype);
5483   if (!js_prototype->map()->is_prototype_map()) return MaybeHandle<Map>();
5484   Handle<PrototypeInfo> info =
5485       Map::GetOrCreatePrototypeInfo(js_prototype, isolate);
5486   if (!info->HasObjectCreateMap()) return MaybeHandle<Map>();
5487   return handle(info->ObjectCreateMap(), isolate);
5488 }
5489 
5490 template <class T>
AppendUniqueCallbacks(Isolate * isolate,Handle<TemplateList> callbacks,Handle<typename T::Array> array,int valid_descriptors)5491 static int AppendUniqueCallbacks(Isolate* isolate,
5492                                  Handle<TemplateList> callbacks,
5493                                  Handle<typename T::Array> array,
5494                                  int valid_descriptors) {
5495   int nof_callbacks = callbacks->length();
5496 
5497   // Fill in new callback descriptors.  Process the callbacks from
5498   // back to front so that the last callback with a given name takes
5499   // precedence over previously added callbacks with that name.
5500   for (int i = nof_callbacks - 1; i >= 0; i--) {
5501     Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)), isolate);
5502     Handle<Name> key(Name::cast(entry->name()), isolate);
5503     DCHECK(key->IsUniqueName());
5504     // Check if a descriptor with this name already exists before writing.
5505     if (!T::Contains(key, entry, valid_descriptors, array)) {
5506       T::Insert(key, entry, valid_descriptors, array);
5507       valid_descriptors++;
5508     }
5509   }
5510 
5511   return valid_descriptors;
5512 }
5513 
5514 struct FixedArrayAppender {
5515   typedef FixedArray Array;
Containsv8::internal::FixedArrayAppender5516   static bool Contains(Handle<Name> key,
5517                        Handle<AccessorInfo> entry,
5518                        int valid_descriptors,
5519                        Handle<FixedArray> array) {
5520     for (int i = 0; i < valid_descriptors; i++) {
5521       if (*key == AccessorInfo::cast(array->get(i))->name()) return true;
5522     }
5523     return false;
5524   }
Insertv8::internal::FixedArrayAppender5525   static void Insert(Handle<Name> key,
5526                      Handle<AccessorInfo> entry,
5527                      int valid_descriptors,
5528                      Handle<FixedArray> array) {
5529     DisallowHeapAllocation no_gc;
5530     array->set(valid_descriptors, *entry);
5531   }
5532 };
5533 
AppendUnique(Isolate * isolate,Handle<Object> descriptors,Handle<FixedArray> array,int valid_descriptors)5534 int AccessorInfo::AppendUnique(Isolate* isolate, Handle<Object> descriptors,
5535                                Handle<FixedArray> array,
5536                                int valid_descriptors) {
5537   Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors);
5538   DCHECK_GE(array->length(), callbacks->length() + valid_descriptors);
5539   return AppendUniqueCallbacks<FixedArrayAppender>(isolate, callbacks, array,
5540                                                    valid_descriptors);
5541 }
5542 
ContainsMap(MapHandles const & maps,Map * map)5543 static bool ContainsMap(MapHandles const& maps, Map* map) {
5544   DCHECK_NOT_NULL(map);
5545   for (Handle<Map> current : maps) {
5546     if (!current.is_null() && *current == map) return true;
5547   }
5548   return false;
5549 }
5550 
FindElementsKindTransitionedMap(Isolate * isolate,MapHandles const & candidates)5551 Map* Map::FindElementsKindTransitionedMap(Isolate* isolate,
5552                                           MapHandles const& candidates) {
5553   DisallowHeapAllocation no_allocation;
5554   DisallowDeoptimization no_deoptimization(isolate);
5555 
5556   if (is_prototype_map()) return nullptr;
5557 
5558   ElementsKind kind = elements_kind();
5559   bool packed = IsFastPackedElementsKind(kind);
5560 
5561   Map* transition = nullptr;
5562   if (IsTransitionableFastElementsKind(kind)) {
5563     // Check the state of the root map.
5564     Map* root_map = FindRootMap(isolate);
5565     if (!EquivalentToForElementsKindTransition(root_map)) return nullptr;
5566     root_map = root_map->LookupElementsTransitionMap(isolate, kind);
5567     DCHECK_NOT_NULL(root_map);
5568     // Starting from the next existing elements kind transition try to
5569     // replay the property transitions that does not involve instance rewriting
5570     // (ElementsTransitionAndStoreStub does not support that).
5571     for (root_map = root_map->ElementsTransitionMap();
5572          root_map != nullptr && root_map->has_fast_elements();
5573          root_map = root_map->ElementsTransitionMap()) {
5574       Map* current = root_map->TryReplayPropertyTransitions(isolate, this);
5575       if (current == nullptr) continue;
5576       if (InstancesNeedRewriting(current)) continue;
5577 
5578       if (ContainsMap(candidates, current) &&
5579           (packed || !IsFastPackedElementsKind(current->elements_kind()))) {
5580         transition = current;
5581         packed = packed && IsFastPackedElementsKind(current->elements_kind());
5582       }
5583     }
5584   }
5585   return transition;
5586 }
5587 
FindClosestElementsTransition(Isolate * isolate,Map * map,ElementsKind to_kind)5588 static Map* FindClosestElementsTransition(Isolate* isolate, Map* map,
5589                                           ElementsKind to_kind) {
5590   // Ensure we are requested to search elements kind transition "near the root".
5591   DCHECK_EQ(map->FindRootMap(isolate)->NumberOfOwnDescriptors(),
5592             map->NumberOfOwnDescriptors());
5593   Map* current_map = map;
5594 
5595   ElementsKind kind = map->elements_kind();
5596   while (kind != to_kind) {
5597     Map* next_map = current_map->ElementsTransitionMap();
5598     if (next_map == nullptr) return current_map;
5599     kind = next_map->elements_kind();
5600     current_map = next_map;
5601   }
5602 
5603   DCHECK_EQ(to_kind, current_map->elements_kind());
5604   return current_map;
5605 }
5606 
LookupElementsTransitionMap(Isolate * isolate,ElementsKind to_kind)5607 Map* Map::LookupElementsTransitionMap(Isolate* isolate, ElementsKind to_kind) {
5608   Map* to_map = FindClosestElementsTransition(isolate, this, to_kind);
5609   if (to_map->elements_kind() == to_kind) return to_map;
5610   return nullptr;
5611 }
5612 
IsMapInArrayPrototypeChain(Isolate * isolate) const5613 bool Map::IsMapInArrayPrototypeChain(Isolate* isolate) const {
5614   if (isolate->initial_array_prototype()->map() == this) {
5615     return true;
5616   }
5617 
5618   if (isolate->initial_object_prototype()->map() == this) {
5619     return true;
5620   }
5621 
5622   return false;
5623 }
5624 
AddMissingElementsTransitions(Isolate * isolate,Handle<Map> map,ElementsKind to_kind)5625 static Handle<Map> AddMissingElementsTransitions(Isolate* isolate,
5626                                                  Handle<Map> map,
5627                                                  ElementsKind to_kind) {
5628   DCHECK(IsTransitionElementsKind(map->elements_kind()));
5629 
5630   Handle<Map> current_map = map;
5631 
5632   ElementsKind kind = map->elements_kind();
5633   TransitionFlag flag;
5634   if (map->is_prototype_map()) {
5635     flag = OMIT_TRANSITION;
5636   } else {
5637     flag = INSERT_TRANSITION;
5638     if (IsFastElementsKind(kind)) {
5639       while (kind != to_kind && !IsTerminalElementsKind(kind)) {
5640         kind = GetNextTransitionElementsKind(kind);
5641         current_map = Map::CopyAsElementsKind(isolate, current_map, kind, flag);
5642       }
5643     }
5644   }
5645 
5646   // In case we are exiting the fast elements kind system, just add the map in
5647   // the end.
5648   if (kind != to_kind) {
5649     current_map = Map::CopyAsElementsKind(isolate, current_map, to_kind, flag);
5650   }
5651 
5652   DCHECK(current_map->elements_kind() == to_kind);
5653   return current_map;
5654 }
5655 
TransitionElementsTo(Isolate * isolate,Handle<Map> map,ElementsKind to_kind)5656 Handle<Map> Map::TransitionElementsTo(Isolate* isolate, Handle<Map> map,
5657                                       ElementsKind to_kind) {
5658   ElementsKind from_kind = map->elements_kind();
5659   if (from_kind == to_kind) return map;
5660 
5661   Context* native_context = isolate->context()->native_context();
5662   if (from_kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
5663     if (*map == native_context->fast_aliased_arguments_map()) {
5664       DCHECK_EQ(SLOW_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
5665       return handle(native_context->slow_aliased_arguments_map(), isolate);
5666     }
5667   } else if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
5668     if (*map == native_context->slow_aliased_arguments_map()) {
5669       DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
5670       return handle(native_context->fast_aliased_arguments_map(), isolate);
5671     }
5672   } else if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) {
5673     // Reuse map transitions for JSArrays.
5674     DisallowHeapAllocation no_gc;
5675     if (native_context->GetInitialJSArrayMap(from_kind) == *map) {
5676       Object* maybe_transitioned_map =
5677           native_context->get(Context::ArrayMapIndex(to_kind));
5678       if (maybe_transitioned_map->IsMap()) {
5679         return handle(Map::cast(maybe_transitioned_map), isolate);
5680       }
5681     }
5682   }
5683 
5684   DCHECK(!map->IsUndefined(isolate));
5685   // Check if we can go back in the elements kind transition chain.
5686   if (IsHoleyElementsKind(from_kind) &&
5687       to_kind == GetPackedElementsKind(from_kind) &&
5688       map->GetBackPointer()->IsMap() &&
5689       Map::cast(map->GetBackPointer())->elements_kind() == to_kind) {
5690     return handle(Map::cast(map->GetBackPointer()), isolate);
5691   }
5692 
5693   bool allow_store_transition = IsTransitionElementsKind(from_kind);
5694   // Only store fast element maps in ascending generality.
5695   if (IsFastElementsKind(to_kind)) {
5696     allow_store_transition =
5697         allow_store_transition && IsTransitionableFastElementsKind(from_kind) &&
5698         IsMoreGeneralElementsKindTransition(from_kind, to_kind);
5699   }
5700 
5701   if (!allow_store_transition) {
5702     return Map::CopyAsElementsKind(isolate, map, to_kind, OMIT_TRANSITION);
5703   }
5704 
5705   return Map::ReconfigureElementsKind(isolate, map, to_kind);
5706 }
5707 
5708 
5709 // static
AsElementsKind(Isolate * isolate,Handle<Map> map,ElementsKind kind)5710 Handle<Map> Map::AsElementsKind(Isolate* isolate, Handle<Map> map,
5711                                 ElementsKind kind) {
5712   Handle<Map> closest_map(FindClosestElementsTransition(isolate, *map, kind),
5713                           isolate);
5714 
5715   if (closest_map->elements_kind() == kind) {
5716     return closest_map;
5717   }
5718 
5719   return AddMissingElementsTransitions(isolate, closest_map, kind);
5720 }
5721 
5722 
GetElementsTransitionMap(Handle<JSObject> object,ElementsKind to_kind)5723 Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
5724                                                ElementsKind to_kind) {
5725   Handle<Map> map(object->map(), object->GetIsolate());
5726   return Map::TransitionElementsTo(object->GetIsolate(), map, to_kind);
5727 }
5728 
5729 
Revoke(Handle<JSProxy> proxy)5730 void JSProxy::Revoke(Handle<JSProxy> proxy) {
5731   Isolate* isolate = proxy->GetIsolate();
5732   // ES#sec-proxy-revocation-functions
5733   if (!proxy->IsRevoked()) {
5734     // 5. Set p.[[ProxyTarget]] to null.
5735     proxy->set_target(ReadOnlyRoots(isolate).null_value());
5736     // 6. Set p.[[ProxyHandler]] to null.
5737     proxy->set_handler(ReadOnlyRoots(isolate).null_value());
5738   }
5739   DCHECK(proxy->IsRevoked());
5740 }
5741 
5742 // static
IsArray(Handle<JSProxy> proxy)5743 Maybe<bool> JSProxy::IsArray(Handle<JSProxy> proxy) {
5744   Isolate* isolate = proxy->GetIsolate();
5745   Handle<JSReceiver> object = Handle<JSReceiver>::cast(proxy);
5746   for (int i = 0; i < JSProxy::kMaxIterationLimit; i++) {
5747     Handle<JSProxy> proxy = Handle<JSProxy>::cast(object);
5748     if (proxy->IsRevoked()) {
5749       isolate->Throw(*isolate->factory()->NewTypeError(
5750           MessageTemplate::kProxyRevoked,
5751           isolate->factory()->NewStringFromAsciiChecked("IsArray")));
5752       return Nothing<bool>();
5753     }
5754     object = handle(JSReceiver::cast(proxy->target()), isolate);
5755     if (object->IsJSArray()) return Just(true);
5756     if (!object->IsJSProxy()) return Just(false);
5757   }
5758 
5759   // Too deep recursion, throw a RangeError.
5760   isolate->StackOverflow();
5761   return Nothing<bool>();
5762 }
5763 
HasProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Name> name)5764 Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy,
5765                                  Handle<Name> name) {
5766   DCHECK(!name->IsPrivate());
5767   STACK_CHECK(isolate, Nothing<bool>());
5768   // 1. (Assert)
5769   // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
5770   Handle<Object> handler(proxy->handler(), isolate);
5771   // 3. If handler is null, throw a TypeError exception.
5772   // 4. Assert: Type(handler) is Object.
5773   if (proxy->IsRevoked()) {
5774     isolate->Throw(*isolate->factory()->NewTypeError(
5775         MessageTemplate::kProxyRevoked, isolate->factory()->has_string()));
5776     return Nothing<bool>();
5777   }
5778   // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
5779   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
5780   // 6. Let trap be ? GetMethod(handler, "has").
5781   Handle<Object> trap;
5782   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5783       isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
5784                                        isolate->factory()->has_string()),
5785       Nothing<bool>());
5786   // 7. If trap is undefined, then
5787   if (trap->IsUndefined(isolate)) {
5788     // 7a. Return target.[[HasProperty]](P).
5789     return JSReceiver::HasProperty(target, name);
5790   }
5791   // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, P»)).
5792   Handle<Object> trap_result_obj;
5793   Handle<Object> args[] = {target, name};
5794   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5795       isolate, trap_result_obj,
5796       Execution::Call(isolate, trap, handler, arraysize(args), args),
5797       Nothing<bool>());
5798   bool boolean_trap_result = trap_result_obj->BooleanValue(isolate);
5799   // 9. If booleanTrapResult is false, then:
5800   if (!boolean_trap_result) {
5801     MAYBE_RETURN(JSProxy::CheckHasTrap(isolate, name, target), Nothing<bool>());
5802   }
5803   // 10. Return booleanTrapResult.
5804   return Just(boolean_trap_result);
5805 }
5806 
CheckHasTrap(Isolate * isolate,Handle<Name> name,Handle<JSReceiver> target)5807 Maybe<bool> JSProxy::CheckHasTrap(Isolate* isolate, Handle<Name> name,
5808                                   Handle<JSReceiver> target) {
5809   // 9a. Let targetDesc be ? target.[[GetOwnProperty]](P).
5810   PropertyDescriptor target_desc;
5811   Maybe<bool> target_found =
5812       JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
5813   MAYBE_RETURN(target_found, Nothing<bool>());
5814   // 9b. If targetDesc is not undefined, then:
5815   if (target_found.FromJust()) {
5816     // 9b i. If targetDesc.[[Configurable]] is false, throw a TypeError
5817     //       exception.
5818     if (!target_desc.configurable()) {
5819       isolate->Throw(*isolate->factory()->NewTypeError(
5820           MessageTemplate::kProxyHasNonConfigurable, name));
5821       return Nothing<bool>();
5822     }
5823     // 9b ii. Let extensibleTarget be ? IsExtensible(target).
5824     Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
5825     MAYBE_RETURN(extensible_target, Nothing<bool>());
5826     // 9b iii. If extensibleTarget is false, throw a TypeError exception.
5827     if (!extensible_target.FromJust()) {
5828       isolate->Throw(*isolate->factory()->NewTypeError(
5829           MessageTemplate::kProxyHasNonExtensible, name));
5830       return Nothing<bool>();
5831     }
5832   }
5833   return Just(true);
5834 }
5835 
SetProperty(Handle<JSProxy> proxy,Handle<Name> name,Handle<Object> value,Handle<Object> receiver,LanguageMode language_mode)5836 Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name,
5837                                  Handle<Object> value, Handle<Object> receiver,
5838                                  LanguageMode language_mode) {
5839   DCHECK(!name->IsPrivate());
5840   Isolate* isolate = proxy->GetIsolate();
5841   STACK_CHECK(isolate, Nothing<bool>());
5842   Factory* factory = isolate->factory();
5843   Handle<String> trap_name = factory->set_string();
5844   ShouldThrow should_throw =
5845       is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
5846 
5847   if (proxy->IsRevoked()) {
5848     isolate->Throw(
5849         *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
5850     return Nothing<bool>();
5851   }
5852   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
5853   Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
5854 
5855   Handle<Object> trap;
5856   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5857       isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
5858   if (trap->IsUndefined(isolate)) {
5859     LookupIterator it =
5860         LookupIterator::PropertyOrElement(isolate, receiver, name, target);
5861     return Object::SetSuperProperty(&it, value, language_mode,
5862                                     Object::MAY_BE_STORE_FROM_KEYED);
5863   }
5864 
5865   Handle<Object> trap_result;
5866   Handle<Object> args[] = {target, name, value, receiver};
5867   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5868       isolate, trap_result,
5869       Execution::Call(isolate, trap, handler, arraysize(args), args),
5870       Nothing<bool>());
5871   if (!trap_result->BooleanValue(isolate)) {
5872     RETURN_FAILURE(isolate, should_throw,
5873                    NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
5874                                 trap_name, name));
5875   }
5876 
5877   MaybeHandle<Object> result =
5878       JSProxy::CheckGetSetTrapResult(isolate, name, target, value, kSet);
5879 
5880   if (result.is_null()) {
5881     return Nothing<bool>();
5882   }
5883   return Just(true);
5884 }
5885 
5886 
DeletePropertyOrElement(Handle<JSProxy> proxy,Handle<Name> name,LanguageMode language_mode)5887 Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy,
5888                                              Handle<Name> name,
5889                                              LanguageMode language_mode) {
5890   DCHECK(!name->IsPrivate());
5891   ShouldThrow should_throw =
5892       is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
5893   Isolate* isolate = proxy->GetIsolate();
5894   STACK_CHECK(isolate, Nothing<bool>());
5895   Factory* factory = isolate->factory();
5896   Handle<String> trap_name = factory->deleteProperty_string();
5897 
5898   if (proxy->IsRevoked()) {
5899     isolate->Throw(
5900         *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
5901     return Nothing<bool>();
5902   }
5903   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
5904   Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
5905 
5906   Handle<Object> trap;
5907   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5908       isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
5909   if (trap->IsUndefined(isolate)) {
5910     return JSReceiver::DeletePropertyOrElement(target, name, language_mode);
5911   }
5912 
5913   Handle<Object> trap_result;
5914   Handle<Object> args[] = {target, name};
5915   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5916       isolate, trap_result,
5917       Execution::Call(isolate, trap, handler, arraysize(args), args),
5918       Nothing<bool>());
5919   if (!trap_result->BooleanValue(isolate)) {
5920     RETURN_FAILURE(isolate, should_throw,
5921                    NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
5922                                 trap_name, name));
5923   }
5924 
5925   // Enforce the invariant.
5926   PropertyDescriptor target_desc;
5927   Maybe<bool> owned =
5928       JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
5929   MAYBE_RETURN(owned, Nothing<bool>());
5930   if (owned.FromJust() && !target_desc.configurable()) {
5931     isolate->Throw(*factory->NewTypeError(
5932         MessageTemplate::kProxyDeletePropertyNonConfigurable, name));
5933     return Nothing<bool>();
5934   }
5935   return Just(true);
5936 }
5937 
5938 
5939 // static
New(Isolate * isolate,Handle<Object> target,Handle<Object> handler)5940 MaybeHandle<JSProxy> JSProxy::New(Isolate* isolate, Handle<Object> target,
5941                                   Handle<Object> handler) {
5942   if (!target->IsJSReceiver()) {
5943     THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5944                     JSProxy);
5945   }
5946   if (target->IsJSProxy() && JSProxy::cast(*target)->IsRevoked()) {
5947     THROW_NEW_ERROR(isolate,
5948                     NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5949                     JSProxy);
5950   }
5951   if (!handler->IsJSReceiver()) {
5952     THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5953                     JSProxy);
5954   }
5955   if (handler->IsJSProxy() && JSProxy::cast(*handler)->IsRevoked()) {
5956     THROW_NEW_ERROR(isolate,
5957                     NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5958                     JSProxy);
5959   }
5960   return isolate->factory()->NewJSProxy(Handle<JSReceiver>::cast(target),
5961                                         Handle<JSReceiver>::cast(handler));
5962 }
5963 
5964 
5965 // static
GetFunctionRealm(Handle<JSProxy> proxy)5966 MaybeHandle<Context> JSProxy::GetFunctionRealm(Handle<JSProxy> proxy) {
5967   DCHECK(proxy->map()->is_constructor());
5968   if (proxy->IsRevoked()) {
5969     THROW_NEW_ERROR(proxy->GetIsolate(),
5970                     NewTypeError(MessageTemplate::kProxyRevoked), Context);
5971   }
5972   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()),
5973                             proxy->GetIsolate());
5974   return JSReceiver::GetFunctionRealm(target);
5975 }
5976 
5977 
5978 // static
GetFunctionRealm(Handle<JSBoundFunction> function)5979 MaybeHandle<Context> JSBoundFunction::GetFunctionRealm(
5980     Handle<JSBoundFunction> function) {
5981   DCHECK(function->map()->is_constructor());
5982   return JSReceiver::GetFunctionRealm(
5983       handle(function->bound_target_function(), function->GetIsolate()));
5984 }
5985 
5986 // static
GetName(Isolate * isolate,Handle<JSBoundFunction> function)5987 MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate,
5988                                              Handle<JSBoundFunction> function) {
5989   Handle<String> prefix = isolate->factory()->bound__string();
5990   Handle<String> target_name = prefix;
5991   Factory* factory = isolate->factory();
5992   // Concatenate the "bound " up to the last non-bound target.
5993   while (function->bound_target_function()->IsJSBoundFunction()) {
5994     ASSIGN_RETURN_ON_EXCEPTION(isolate, target_name,
5995                                factory->NewConsString(prefix, target_name),
5996                                String);
5997     function = handle(JSBoundFunction::cast(function->bound_target_function()),
5998                       isolate);
5999   }
6000   if (function->bound_target_function()->IsJSFunction()) {
6001     Handle<JSFunction> target(
6002         JSFunction::cast(function->bound_target_function()), isolate);
6003     Handle<Object> name = JSFunction::GetName(isolate, target);
6004     if (!name->IsString()) return target_name;
6005     return factory->NewConsString(target_name, Handle<String>::cast(name));
6006   }
6007   // This will omit the proper target name for bound JSProxies.
6008   return target_name;
6009 }
6010 
6011 // static
GetLength(Isolate * isolate,Handle<JSBoundFunction> function)6012 Maybe<int> JSBoundFunction::GetLength(Isolate* isolate,
6013                                       Handle<JSBoundFunction> function) {
6014   int nof_bound_arguments = function->bound_arguments()->length();
6015   while (function->bound_target_function()->IsJSBoundFunction()) {
6016     function = handle(JSBoundFunction::cast(function->bound_target_function()),
6017                       isolate);
6018     // Make sure we never overflow {nof_bound_arguments}, the number of
6019     // arguments of a function is strictly limited by the max length of an
6020     // JSAarray, Smi::kMaxValue is thus a reasonably good overestimate.
6021     int length = function->bound_arguments()->length();
6022     if (V8_LIKELY(Smi::kMaxValue - nof_bound_arguments > length)) {
6023       nof_bound_arguments += length;
6024     } else {
6025       nof_bound_arguments = Smi::kMaxValue;
6026     }
6027   }
6028   // All non JSFunction targets get a direct property and don't use this
6029   // accessor.
6030   Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()),
6031                             isolate);
6032   Maybe<int> target_length = JSFunction::GetLength(isolate, target);
6033   if (target_length.IsNothing()) return target_length;
6034 
6035   int length = Max(0, target_length.FromJust() - nof_bound_arguments);
6036   return Just(length);
6037 }
6038 
6039 // static
GetName(Isolate * isolate,Handle<JSFunction> function)6040 Handle<Object> JSFunction::GetName(Isolate* isolate,
6041                                    Handle<JSFunction> function) {
6042   if (function->shared()->name_should_print_as_anonymous()) {
6043     return isolate->factory()->anonymous_string();
6044   }
6045   return handle(function->shared()->Name(), isolate);
6046 }
6047 
6048 // static
GetLength(Isolate * isolate,Handle<JSFunction> function)6049 Maybe<int> JSFunction::GetLength(Isolate* isolate,
6050                                  Handle<JSFunction> function) {
6051   int length = 0;
6052   if (function->shared()->is_compiled()) {
6053     length = function->shared()->GetLength();
6054   } else {
6055     // If the function isn't compiled yet, the length is not computed
6056     // correctly yet. Compile it now and return the right length.
6057     if (Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) {
6058       length = function->shared()->GetLength();
6059     }
6060     if (isolate->has_pending_exception()) return Nothing<int>();
6061   }
6062   DCHECK_GE(length, 0);
6063   return Just(length);
6064 }
6065 
6066 // static
GetFunctionRealm(Handle<JSFunction> function)6067 Handle<Context> JSFunction::GetFunctionRealm(Handle<JSFunction> function) {
6068   DCHECK(function->map()->is_constructor());
6069   return handle(function->context()->native_context(), function->GetIsolate());
6070 }
6071 
6072 
6073 // static
GetFunctionRealm(Handle<JSObject> object)6074 MaybeHandle<Context> JSObject::GetFunctionRealm(Handle<JSObject> object) {
6075   DCHECK(object->map()->is_constructor());
6076   DCHECK(!object->IsJSFunction());
6077   return object->GetCreationContext();
6078 }
6079 
6080 
6081 // static
GetFunctionRealm(Handle<JSReceiver> receiver)6082 MaybeHandle<Context> JSReceiver::GetFunctionRealm(Handle<JSReceiver> receiver) {
6083   if (receiver->IsJSProxy()) {
6084     return JSProxy::GetFunctionRealm(Handle<JSProxy>::cast(receiver));
6085   }
6086 
6087   if (receiver->IsJSFunction()) {
6088     return JSFunction::GetFunctionRealm(Handle<JSFunction>::cast(receiver));
6089   }
6090 
6091   if (receiver->IsJSBoundFunction()) {
6092     return JSBoundFunction::GetFunctionRealm(
6093         Handle<JSBoundFunction>::cast(receiver));
6094   }
6095 
6096   return JSObject::GetFunctionRealm(Handle<JSObject>::cast(receiver));
6097 }
6098 
6099 
GetPropertyAttributes(LookupIterator * it)6100 Maybe<PropertyAttributes> JSProxy::GetPropertyAttributes(LookupIterator* it) {
6101   PropertyDescriptor desc;
6102   Maybe<bool> found = JSProxy::GetOwnPropertyDescriptor(
6103       it->isolate(), it->GetHolder<JSProxy>(), it->GetName(), &desc);
6104   MAYBE_RETURN(found, Nothing<PropertyAttributes>());
6105   if (!found.FromJust()) return Just(ABSENT);
6106   return Just(desc.ToAttributes());
6107 }
6108 
6109 
AllocateStorageForMap(Handle<JSObject> object,Handle<Map> map)6110 void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
6111   DCHECK(object->map()->GetInObjectProperties() ==
6112          map->GetInObjectProperties());
6113   ElementsKind obj_kind = object->map()->elements_kind();
6114   ElementsKind map_kind = map->elements_kind();
6115   if (map_kind != obj_kind) {
6116     ElementsKind to_kind = GetMoreGeneralElementsKind(map_kind, obj_kind);
6117     if (IsDictionaryElementsKind(obj_kind)) {
6118       to_kind = obj_kind;
6119     }
6120     if (IsDictionaryElementsKind(to_kind)) {
6121       NormalizeElements(object);
6122     } else {
6123       TransitionElementsKind(object, to_kind);
6124     }
6125     map = Map::ReconfigureElementsKind(object->GetIsolate(), map, to_kind);
6126   }
6127   int number_of_fields = map->NumberOfFields();
6128   int inobject = map->GetInObjectProperties();
6129   int unused = map->UnusedPropertyFields();
6130   int total_size = number_of_fields + unused;
6131   int external = total_size - inobject;
6132   // Allocate mutable double boxes if necessary. It is always necessary if we
6133   // have external properties, but is also necessary if we only have inobject
6134   // properties but don't unbox double fields.
6135   if (!FLAG_unbox_double_fields || external > 0) {
6136     Isolate* isolate = object->GetIsolate();
6137 
6138     Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
6139     Handle<FixedArray> storage;
6140     if (!FLAG_unbox_double_fields) {
6141       storage = isolate->factory()->NewFixedArray(inobject);
6142     }
6143 
6144     Handle<PropertyArray> array =
6145         isolate->factory()->NewPropertyArray(external);
6146 
6147     for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
6148       PropertyDetails details = descriptors->GetDetails(i);
6149       Representation representation = details.representation();
6150       if (!representation.IsDouble()) continue;
6151       FieldIndex index = FieldIndex::ForDescriptor(*map, i);
6152       if (map->IsUnboxedDoubleField(index)) continue;
6153       auto box = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
6154       if (index.is_inobject()) {
6155         storage->set(index.property_index(), *box);
6156       } else {
6157         array->set(index.outobject_array_index(), *box);
6158       }
6159     }
6160 
6161     object->SetProperties(*array);
6162 
6163     if (!FLAG_unbox_double_fields) {
6164       for (int i = 0; i < inobject; i++) {
6165         FieldIndex index = FieldIndex::ForPropertyIndex(*map, i);
6166         Object* value = storage->get(i);
6167         object->RawFastPropertyAtPut(index, value);
6168       }
6169     }
6170   }
6171   object->synchronized_set_map(*map);
6172 }
6173 
6174 
MigrateInstance(Handle<JSObject> object)6175 void JSObject::MigrateInstance(Handle<JSObject> object) {
6176   Handle<Map> original_map(object->map(), object->GetIsolate());
6177   Handle<Map> map = Map::Update(object->GetIsolate(), original_map);
6178   map->set_is_migration_target(true);
6179   MigrateToMap(object, map);
6180   if (FLAG_trace_migration) {
6181     object->PrintInstanceMigration(stdout, *original_map, *map);
6182   }
6183 #if VERIFY_HEAP
6184   if (FLAG_verify_heap) {
6185     object->JSObjectVerify(object->GetIsolate());
6186   }
6187 #endif
6188 }
6189 
6190 
6191 // static
TryMigrateInstance(Handle<JSObject> object)6192 bool JSObject::TryMigrateInstance(Handle<JSObject> object) {
6193   Isolate* isolate = object->GetIsolate();
6194   DisallowDeoptimization no_deoptimization(isolate);
6195   Handle<Map> original_map(object->map(), isolate);
6196   Handle<Map> new_map;
6197   if (!Map::TryUpdate(isolate, original_map).ToHandle(&new_map)) {
6198     return false;
6199   }
6200   JSObject::MigrateToMap(object, new_map);
6201   if (FLAG_trace_migration && *original_map != object->map()) {
6202     object->PrintInstanceMigration(stdout, *original_map, object->map());
6203   }
6204 #if VERIFY_HEAP
6205   if (FLAG_verify_heap) {
6206     object->JSObjectVerify(isolate);
6207   }
6208 #endif
6209   return true;
6210 }
6211 
AddProperty(Isolate * isolate,Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)6212 void JSObject::AddProperty(Isolate* isolate, Handle<JSObject> object,
6213                            Handle<Name> name, Handle<Object> value,
6214                            PropertyAttributes attributes) {
6215   LookupIterator it(isolate, object, name, object,
6216                     LookupIterator::OWN_SKIP_INTERCEPTOR);
6217   CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
6218 #ifdef DEBUG
6219   uint32_t index;
6220   DCHECK(!object->IsJSProxy());
6221   DCHECK(!name->AsArrayIndex(&index));
6222   Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
6223   DCHECK(maybe.IsJust());
6224   DCHECK(!it.IsFound());
6225   DCHECK(object->map()->is_extensible() || name->IsPrivate());
6226 #endif
6227   CHECK(AddDataProperty(&it, value, attributes, kThrowOnError,
6228                         CERTAINLY_NOT_STORE_FROM_KEYED)
6229             .IsJust());
6230 }
6231 
6232 
6233 // Reconfigures a property to a data property with attributes, even if it is not
6234 // reconfigurable.
6235 // Requires a LookupIterator that does not look at the prototype chain beyond
6236 // hidden prototypes.
DefineOwnPropertyIgnoreAttributes(LookupIterator * it,Handle<Object> value,PropertyAttributes attributes,AccessorInfoHandling handling)6237 MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes(
6238     LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
6239     AccessorInfoHandling handling) {
6240   MAYBE_RETURN_NULL(DefineOwnPropertyIgnoreAttributes(it, value, attributes,
6241                                                       kThrowOnError, handling));
6242   return value;
6243 }
6244 
6245 
DefineOwnPropertyIgnoreAttributes(LookupIterator * it,Handle<Object> value,PropertyAttributes attributes,ShouldThrow should_throw,AccessorInfoHandling handling)6246 Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
6247     LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
6248     ShouldThrow should_throw, AccessorInfoHandling handling) {
6249   it->UpdateProtector();
6250   Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
6251 
6252   for (; it->IsFound(); it->Next()) {
6253     switch (it->state()) {
6254       case LookupIterator::JSPROXY:
6255       case LookupIterator::NOT_FOUND:
6256       case LookupIterator::TRANSITION:
6257         UNREACHABLE();
6258 
6259       case LookupIterator::ACCESS_CHECK:
6260         if (!it->HasAccess()) {
6261           it->isolate()->ReportFailedAccessCheck(it->GetHolder<JSObject>());
6262           RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
6263           return Just(true);
6264         }
6265         break;
6266 
6267       // If there's an interceptor, try to store the property with the
6268       // interceptor.
6269       // In case of success, the attributes will have been reset to the default
6270       // attributes of the interceptor, rather than the incoming attributes.
6271       //
6272       // TODO(verwaest): JSProxy afterwards verify the attributes that the
6273       // JSProxy claims it has, and verifies that they are compatible. If not,
6274       // they throw. Here we should do the same.
6275       case LookupIterator::INTERCEPTOR:
6276         if (handling == DONT_FORCE_FIELD) {
6277           Maybe<bool> result =
6278               JSObject::SetPropertyWithInterceptor(it, should_throw, value);
6279           if (result.IsNothing() || result.FromJust()) return result;
6280         }
6281         break;
6282 
6283       case LookupIterator::ACCESSOR: {
6284         Handle<Object> accessors = it->GetAccessors();
6285 
6286         // Special handling for AccessorInfo, which behaves like a data
6287         // property.
6288         if (accessors->IsAccessorInfo() && handling == DONT_FORCE_FIELD) {
6289           PropertyAttributes current_attributes = it->property_attributes();
6290           // Ensure the context isn't changed after calling into accessors.
6291           AssertNoContextChange ncc(it->isolate());
6292 
6293           // Update the attributes before calling the setter. The setter may
6294           // later change the shape of the property.
6295           if (current_attributes != attributes) {
6296             it->TransitionToAccessorPair(accessors, attributes);
6297           }
6298 
6299           return JSObject::SetPropertyWithAccessor(it, value, should_throw);
6300         }
6301 
6302         it->ReconfigureDataProperty(value, attributes);
6303         return Just(true);
6304       }
6305       case LookupIterator::INTEGER_INDEXED_EXOTIC:
6306         return RedefineIncompatibleProperty(it->isolate(), it->GetName(), value,
6307                                             should_throw);
6308 
6309       case LookupIterator::DATA: {
6310         // Regular property update if the attributes match.
6311         if (it->property_attributes() == attributes) {
6312           return SetDataProperty(it, value);
6313         }
6314 
6315         // Special case: properties of typed arrays cannot be reconfigured to
6316         // non-writable nor to non-enumerable.
6317         if (it->IsElement() && object->HasFixedTypedArrayElements()) {
6318           return RedefineIncompatibleProperty(it->isolate(), it->GetName(),
6319                                               value, should_throw);
6320         }
6321 
6322         // Reconfigure the data property if the attributes mismatch.
6323         it->ReconfigureDataProperty(value, attributes);
6324 
6325         return Just(true);
6326       }
6327     }
6328   }
6329 
6330   return AddDataProperty(it, value, attributes, should_throw,
6331                          CERTAINLY_NOT_STORE_FROM_KEYED);
6332 }
6333 
SetOwnPropertyIgnoreAttributes(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)6334 MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
6335     Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
6336     PropertyAttributes attributes) {
6337   DCHECK(!value->IsTheHole());
6338   LookupIterator it(object, name, object, LookupIterator::OWN);
6339   return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
6340 }
6341 
SetOwnElementIgnoreAttributes(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes)6342 MaybeHandle<Object> JSObject::SetOwnElementIgnoreAttributes(
6343     Handle<JSObject> object, uint32_t index, Handle<Object> value,
6344     PropertyAttributes attributes) {
6345   Isolate* isolate = object->GetIsolate();
6346   LookupIterator it(isolate, object, index, object, LookupIterator::OWN);
6347   return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
6348 }
6349 
DefinePropertyOrElementIgnoreAttributes(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)6350 MaybeHandle<Object> JSObject::DefinePropertyOrElementIgnoreAttributes(
6351     Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
6352     PropertyAttributes attributes) {
6353   Isolate* isolate = object->GetIsolate();
6354   LookupIterator it = LookupIterator::PropertyOrElement(
6355       isolate, object, name, object, LookupIterator::OWN);
6356   return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
6357 }
6358 
GetPropertyAttributesWithInterceptor(LookupIterator * it)6359 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
6360     LookupIterator* it) {
6361   return GetPropertyAttributesWithInterceptorInternal(it, it->GetInterceptor());
6362 }
6363 
GetPropertyAttributes(LookupIterator * it)6364 Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
6365     LookupIterator* it) {
6366   for (; it->IsFound(); it->Next()) {
6367     switch (it->state()) {
6368       case LookupIterator::NOT_FOUND:
6369       case LookupIterator::TRANSITION:
6370         UNREACHABLE();
6371       case LookupIterator::JSPROXY:
6372         return JSProxy::GetPropertyAttributes(it);
6373       case LookupIterator::INTERCEPTOR: {
6374         Maybe<PropertyAttributes> result =
6375             JSObject::GetPropertyAttributesWithInterceptor(it);
6376         if (result.IsNothing()) return result;
6377         if (result.FromJust() != ABSENT) return result;
6378         break;
6379       }
6380       case LookupIterator::ACCESS_CHECK:
6381         if (it->HasAccess()) break;
6382         return JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
6383       case LookupIterator::INTEGER_INDEXED_EXOTIC:
6384         return Just(ABSENT);
6385       case LookupIterator::ACCESSOR:
6386         if (it->GetHolder<Object>()->IsJSModuleNamespace()) {
6387           return JSModuleNamespace::GetPropertyAttributes(it);
6388         } else {
6389           return Just(it->property_attributes());
6390         }
6391       case LookupIterator::DATA:
6392         return Just(it->property_attributes());
6393     }
6394   }
6395   return Just(ABSENT);
6396 }
6397 
6398 
New(Isolate * isolate)6399 Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) {
6400   Handle<WeakFixedArray> array(
6401       isolate->factory()->NewWeakFixedArray(kEntries, TENURED));
6402   return Handle<NormalizedMapCache>::cast(array);
6403 }
6404 
6405 
Get(Handle<Map> fast_map,PropertyNormalizationMode mode)6406 MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map,
6407                                          PropertyNormalizationMode mode) {
6408   DisallowHeapAllocation no_gc;
6409   MaybeObject* value = WeakFixedArray::Get(GetIndex(fast_map));
6410   HeapObject* heap_object;
6411   if (!value->ToWeakHeapObject(&heap_object)) {
6412     return MaybeHandle<Map>();
6413   }
6414 
6415   Map* normalized_map = Map::cast(heap_object);
6416   if (!normalized_map->EquivalentToForNormalization(*fast_map, mode)) {
6417     return MaybeHandle<Map>();
6418   }
6419   return handle(normalized_map, GetIsolate());
6420 }
6421 
Set(Handle<Map> fast_map,Handle<Map> normalized_map)6422 void NormalizedMapCache::Set(Handle<Map> fast_map, Handle<Map> normalized_map) {
6423   DisallowHeapAllocation no_gc;
6424   DCHECK(normalized_map->is_dictionary_map());
6425   WeakFixedArray::Set(GetIndex(fast_map),
6426                       HeapObjectReference::Weak(*normalized_map));
6427 }
6428 
NormalizeProperties(Handle<JSObject> object,PropertyNormalizationMode mode,int expected_additional_properties,const char * reason)6429 void JSObject::NormalizeProperties(Handle<JSObject> object,
6430                                    PropertyNormalizationMode mode,
6431                                    int expected_additional_properties,
6432                                    const char* reason) {
6433   if (!object->HasFastProperties()) return;
6434 
6435   Handle<Map> map(object->map(), object->GetIsolate());
6436   Handle<Map> new_map = Map::Normalize(object->GetIsolate(), map, mode, reason);
6437 
6438   MigrateToMap(object, new_map, expected_additional_properties);
6439 }
6440 
6441 
MigrateSlowToFast(Handle<JSObject> object,int unused_property_fields,const char * reason)6442 void JSObject::MigrateSlowToFast(Handle<JSObject> object,
6443                                  int unused_property_fields,
6444                                  const char* reason) {
6445   if (object->HasFastProperties()) return;
6446   DCHECK(!object->IsJSGlobalObject());
6447   Isolate* isolate = object->GetIsolate();
6448   Factory* factory = isolate->factory();
6449   Handle<NameDictionary> dictionary(object->property_dictionary(), isolate);
6450 
6451   // Make sure we preserve dictionary representation if there are too many
6452   // descriptors.
6453   int number_of_elements = dictionary->NumberOfElements();
6454   if (number_of_elements > kMaxNumberOfDescriptors) return;
6455 
6456   Handle<FixedArray> iteration_order =
6457       NameDictionary::IterationIndices(isolate, dictionary);
6458 
6459   int instance_descriptor_length = iteration_order->length();
6460   int number_of_fields = 0;
6461 
6462   // Compute the length of the instance descriptor.
6463   ReadOnlyRoots roots(isolate);
6464   for (int i = 0; i < instance_descriptor_length; i++) {
6465     int index = Smi::ToInt(iteration_order->get(i));
6466     DCHECK(dictionary->IsKey(roots, dictionary->KeyAt(index)));
6467 
6468     PropertyKind kind = dictionary->DetailsAt(index).kind();
6469     if (kind == kData) {
6470       if (FLAG_track_constant_fields) {
6471         number_of_fields += 1;
6472       } else {
6473         Object* value = dictionary->ValueAt(index);
6474         if (!value->IsJSFunction()) {
6475           number_of_fields += 1;
6476         }
6477       }
6478     }
6479   }
6480 
6481   Handle<Map> old_map(object->map(), isolate);
6482 
6483   int inobject_props = old_map->GetInObjectProperties();
6484 
6485   // Allocate new map.
6486   Handle<Map> new_map = Map::CopyDropDescriptors(isolate, old_map);
6487   if (new_map->has_named_interceptor() || new_map->is_access_check_needed()) {
6488     // Force certain slow paths when API interceptors are used, or if an access
6489     // check is required.
6490     new_map->set_may_have_interesting_symbols(true);
6491   }
6492   new_map->set_is_dictionary_map(false);
6493 
6494   NotifyMapChange(old_map, new_map, isolate);
6495 
6496   if (FLAG_trace_maps) {
6497     LOG(isolate, MapEvent("SlowToFast", *old_map, *new_map, reason));
6498   }
6499 
6500   if (instance_descriptor_length == 0) {
6501     DisallowHeapAllocation no_gc;
6502     DCHECK_LE(unused_property_fields, inobject_props);
6503     // Transform the object.
6504     new_map->SetInObjectUnusedPropertyFields(inobject_props);
6505     object->synchronized_set_map(*new_map);
6506     object->SetProperties(ReadOnlyRoots(isolate).empty_fixed_array());
6507     // Check that it really works.
6508     DCHECK(object->HasFastProperties());
6509     return;
6510   }
6511 
6512   // Allocate the instance descriptor.
6513   Handle<DescriptorArray> descriptors = DescriptorArray::Allocate(
6514       isolate, instance_descriptor_length, 0, TENURED);
6515 
6516   int number_of_allocated_fields =
6517       number_of_fields + unused_property_fields - inobject_props;
6518   if (number_of_allocated_fields < 0) {
6519     // There is enough inobject space for all fields (including unused).
6520     number_of_allocated_fields = 0;
6521     unused_property_fields = inobject_props - number_of_fields;
6522   }
6523 
6524   // Allocate the property array for the fields.
6525   Handle<PropertyArray> fields =
6526       factory->NewPropertyArray(number_of_allocated_fields);
6527 
6528   bool is_transitionable_elements_kind =
6529       IsTransitionableFastElementsKind(old_map->elements_kind());
6530 
6531   // Fill in the instance descriptor and the fields.
6532   int current_offset = 0;
6533   for (int i = 0; i < instance_descriptor_length; i++) {
6534     int index = Smi::ToInt(iteration_order->get(i));
6535     Name* k = dictionary->NameAt(index);
6536     // Dictionary keys are internalized upon insertion.
6537     // TODO(jkummerow): Turn this into a DCHECK if it's not hit in the wild.
6538     CHECK(k->IsUniqueName());
6539     Handle<Name> key(k, isolate);
6540 
6541     // Properly mark the {new_map} if the {key} is an "interesting symbol".
6542     if (key->IsInterestingSymbol()) {
6543       new_map->set_may_have_interesting_symbols(true);
6544     }
6545 
6546     Object* value = dictionary->ValueAt(index);
6547 
6548     PropertyDetails details = dictionary->DetailsAt(index);
6549     DCHECK_EQ(kField, details.location());
6550     DCHECK_EQ(PropertyConstness::kMutable, details.constness());
6551 
6552     Descriptor d;
6553     if (details.kind() == kData) {
6554       if (!FLAG_track_constant_fields && value->IsJSFunction()) {
6555         d = Descriptor::DataConstant(key, handle(value, isolate),
6556                                      details.attributes());
6557       } else {
6558         // Ensure that we make constant field only when elements kind is not
6559         // transitionable.
6560         PropertyConstness constness =
6561             FLAG_track_constant_fields && !is_transitionable_elements_kind
6562                 ? PropertyConstness::kConst
6563                 : PropertyConstness::kMutable;
6564         d = Descriptor::DataField(
6565             key, current_offset, details.attributes(), constness,
6566             // TODO(verwaest): value->OptimalRepresentation();
6567             Representation::Tagged(),
6568             MaybeObjectHandle(FieldType::Any(isolate)));
6569       }
6570     } else {
6571       DCHECK_EQ(kAccessor, details.kind());
6572       d = Descriptor::AccessorConstant(key, handle(value, isolate),
6573                                        details.attributes());
6574     }
6575     details = d.GetDetails();
6576     if (details.location() == kField) {
6577       if (current_offset < inobject_props) {
6578         object->InObjectPropertyAtPut(current_offset, value,
6579                                       UPDATE_WRITE_BARRIER);
6580       } else {
6581         int offset = current_offset - inobject_props;
6582         fields->set(offset, value);
6583       }
6584       current_offset += details.field_width_in_words();
6585     }
6586     descriptors->Set(i, &d);
6587   }
6588   DCHECK(current_offset == number_of_fields);
6589 
6590   descriptors->Sort();
6591 
6592   Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
6593       isolate, new_map, descriptors, descriptors->number_of_descriptors());
6594 
6595   DisallowHeapAllocation no_gc;
6596   new_map->InitializeDescriptors(*descriptors, *layout_descriptor);
6597   if (number_of_allocated_fields == 0) {
6598     new_map->SetInObjectUnusedPropertyFields(unused_property_fields);
6599   } else {
6600     new_map->SetOutOfObjectUnusedPropertyFields(unused_property_fields);
6601   }
6602 
6603   // Transform the object.
6604   object->synchronized_set_map(*new_map);
6605 
6606   object->SetProperties(*fields);
6607   DCHECK(object->IsJSObject());
6608 
6609   // Check that it really works.
6610   DCHECK(object->HasFastProperties());
6611 }
6612 
RequireSlowElements(NumberDictionary * dictionary)6613 void JSObject::RequireSlowElements(NumberDictionary* dictionary) {
6614   if (dictionary->requires_slow_elements()) return;
6615   dictionary->set_requires_slow_elements();
6616   if (map()->is_prototype_map()) {
6617     // If this object is a prototype (the callee will check), invalidate any
6618     // prototype chains involving it.
6619     InvalidatePrototypeChains(map());
6620   }
6621 }
6622 
NormalizeElements(Handle<JSObject> object)6623 Handle<NumberDictionary> JSObject::NormalizeElements(Handle<JSObject> object) {
6624   DCHECK(!object->HasFixedTypedArrayElements());
6625   Isolate* isolate = object->GetIsolate();
6626   bool is_sloppy_arguments = object->HasSloppyArgumentsElements();
6627   {
6628     DisallowHeapAllocation no_gc;
6629     FixedArrayBase* elements = object->elements();
6630 
6631     if (is_sloppy_arguments) {
6632       elements = SloppyArgumentsElements::cast(elements)->arguments();
6633     }
6634 
6635     if (elements->IsNumberDictionary()) {
6636       return handle(NumberDictionary::cast(elements), isolate);
6637     }
6638   }
6639 
6640   DCHECK(object->HasSmiOrObjectElements() || object->HasDoubleElements() ||
6641          object->HasFastArgumentsElements() ||
6642          object->HasFastStringWrapperElements());
6643 
6644   Handle<NumberDictionary> dictionary =
6645       object->GetElementsAccessor()->Normalize(object);
6646 
6647   // Switch to using the dictionary as the backing storage for elements.
6648   ElementsKind target_kind = is_sloppy_arguments
6649                                  ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS
6650                                  : object->HasFastStringWrapperElements()
6651                                        ? SLOW_STRING_WRAPPER_ELEMENTS
6652                                        : DICTIONARY_ELEMENTS;
6653   Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind);
6654   // Set the new map first to satify the elements type assert in set_elements().
6655   JSObject::MigrateToMap(object, new_map);
6656 
6657   if (is_sloppy_arguments) {
6658     SloppyArgumentsElements::cast(object->elements())
6659         ->set_arguments(*dictionary);
6660   } else {
6661     object->set_elements(*dictionary);
6662   }
6663 
6664   isolate->counters()->elements_to_dictionary()->Increment();
6665 
6666 #ifdef DEBUG
6667   if (FLAG_trace_normalization) {
6668     StdoutStream os;
6669     os << "Object elements have been normalized:\n";
6670     object->Print(os);
6671   }
6672 #endif
6673 
6674   DCHECK(object->HasDictionaryElements() ||
6675          object->HasSlowArgumentsElements() ||
6676          object->HasSlowStringWrapperElements());
6677   return dictionary;
6678 }
6679 
6680 namespace {
6681 
SetHashAndUpdateProperties(Isolate * isolate,HeapObject * properties,int hash)6682 Object* SetHashAndUpdateProperties(Isolate* isolate, HeapObject* properties,
6683                                    int hash) {
6684   DCHECK_NE(PropertyArray::kNoHashSentinel, hash);
6685   DCHECK(PropertyArray::HashField::is_valid(hash));
6686 
6687   Heap* heap = isolate->heap();
6688   ReadOnlyRoots roots(heap);
6689   if (properties == roots.empty_fixed_array() ||
6690       properties == roots.empty_property_array() ||
6691       properties == heap->empty_property_dictionary()) {
6692     return Smi::FromInt(hash);
6693   }
6694 
6695   if (properties->IsPropertyArray()) {
6696     PropertyArray::cast(properties)->SetHash(hash);
6697     DCHECK_LT(0, PropertyArray::cast(properties)->length());
6698     return properties;
6699   }
6700 
6701   DCHECK(properties->IsNameDictionary());
6702   NameDictionary::cast(properties)->SetHash(hash);
6703   return properties;
6704 }
6705 
GetIdentityHashHelper(Isolate * isolate,JSReceiver * object)6706 int GetIdentityHashHelper(Isolate* isolate, JSReceiver* object) {
6707   DisallowHeapAllocation no_gc;
6708   Object* properties = object->raw_properties_or_hash();
6709   if (properties->IsSmi()) {
6710     return Smi::ToInt(properties);
6711   }
6712 
6713   if (properties->IsPropertyArray()) {
6714     return PropertyArray::cast(properties)->Hash();
6715   }
6716 
6717   if (properties->IsNameDictionary()) {
6718     return NameDictionary::cast(properties)->Hash();
6719   }
6720 
6721   if (properties->IsGlobalDictionary()) {
6722     return GlobalDictionary::cast(properties)->Hash();
6723   }
6724 
6725 #ifdef DEBUG
6726   FixedArray* empty_fixed_array = ReadOnlyRoots(isolate).empty_fixed_array();
6727   FixedArray* empty_property_dictionary =
6728       isolate->heap()->empty_property_dictionary();
6729   DCHECK(properties == empty_fixed_array ||
6730          properties == empty_property_dictionary);
6731 #endif
6732 
6733   return PropertyArray::kNoHashSentinel;
6734 }
6735 }  // namespace
6736 
SetIdentityHash(int hash)6737 void JSReceiver::SetIdentityHash(int hash) {
6738   DisallowHeapAllocation no_gc;
6739   DCHECK_NE(PropertyArray::kNoHashSentinel, hash);
6740   DCHECK(PropertyArray::HashField::is_valid(hash));
6741 
6742   HeapObject* existing_properties = HeapObject::cast(raw_properties_or_hash());
6743   Object* new_properties =
6744       SetHashAndUpdateProperties(GetIsolate(), existing_properties, hash);
6745   set_raw_properties_or_hash(new_properties);
6746 }
6747 
SetProperties(HeapObject * properties)6748 void JSReceiver::SetProperties(HeapObject* properties) {
6749   DCHECK_IMPLIES(properties->IsPropertyArray() &&
6750                      PropertyArray::cast(properties)->length() == 0,
6751                  properties == GetReadOnlyRoots().empty_property_array());
6752   DisallowHeapAllocation no_gc;
6753   Isolate* isolate = GetIsolate();
6754   int hash = GetIdentityHashHelper(isolate, this);
6755   Object* new_properties = properties;
6756 
6757   // TODO(cbruni): Make GetIdentityHashHelper return a bool so that we
6758   // don't have to manually compare against kNoHashSentinel.
6759   if (hash != PropertyArray::kNoHashSentinel) {
6760     new_properties = SetHashAndUpdateProperties(isolate, properties, hash);
6761   }
6762 
6763   set_raw_properties_or_hash(new_properties);
6764 }
6765 
GetIdentityHash(Isolate * isolate)6766 Object* JSReceiver::GetIdentityHash(Isolate* isolate) {
6767   DisallowHeapAllocation no_gc;
6768 
6769   int hash = GetIdentityHashHelper(isolate, this);
6770   if (hash == PropertyArray::kNoHashSentinel) {
6771     return ReadOnlyRoots(isolate).undefined_value();
6772   }
6773 
6774   return Smi::FromInt(hash);
6775 }
6776 
6777 // static
CreateIdentityHash(Isolate * isolate,JSReceiver * key)6778 Smi* JSReceiver::CreateIdentityHash(Isolate* isolate, JSReceiver* key) {
6779   DisallowHeapAllocation no_gc;
6780   int hash = isolate->GenerateIdentityHash(PropertyArray::HashField::kMax);
6781   DCHECK_NE(PropertyArray::kNoHashSentinel, hash);
6782 
6783   key->SetIdentityHash(hash);
6784   return Smi::FromInt(hash);
6785 }
6786 
GetOrCreateIdentityHash(Isolate * isolate)6787 Smi* JSReceiver::GetOrCreateIdentityHash(Isolate* isolate) {
6788   DisallowHeapAllocation no_gc;
6789 
6790   Object* hash_obj = GetIdentityHash(isolate);
6791   if (!hash_obj->IsUndefined(isolate)) {
6792     return Smi::cast(hash_obj);
6793   }
6794 
6795   return JSReceiver::CreateIdentityHash(isolate, this);
6796 }
6797 
DeletePropertyWithInterceptor(LookupIterator * it,ShouldThrow should_throw)6798 Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it,
6799                                                     ShouldThrow should_throw) {
6800   Isolate* isolate = it->isolate();
6801   // Make sure that the top context does not change when doing callbacks or
6802   // interceptor calls.
6803   AssertNoContextChange ncc(isolate);
6804 
6805   DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
6806   Handle<InterceptorInfo> interceptor(it->GetInterceptor());
6807   if (interceptor->deleter()->IsUndefined(isolate)) return Nothing<bool>();
6808 
6809   Handle<JSObject> holder = it->GetHolder<JSObject>();
6810   Handle<Object> receiver = it->GetReceiver();
6811   if (!receiver->IsJSReceiver()) {
6812     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
6813                                      Object::ConvertReceiver(isolate, receiver),
6814                                      Nothing<bool>());
6815   }
6816 
6817   PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
6818                                  *holder, should_throw);
6819   Handle<Object> result;
6820   if (it->IsElement()) {
6821     result = args.CallIndexedDeleter(interceptor, it->index());
6822   } else {
6823     result = args.CallNamedDeleter(interceptor, it->name());
6824   }
6825 
6826   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6827   if (result.is_null()) return Nothing<bool>();
6828 
6829   DCHECK(result->IsBoolean());
6830   // Rebox CustomArguments::kReturnValueOffset before returning.
6831   return Just(result->IsTrue(isolate));
6832 }
6833 
DeleteNormalizedProperty(Handle<JSReceiver> object,int entry)6834 void JSReceiver::DeleteNormalizedProperty(Handle<JSReceiver> object,
6835                                           int entry) {
6836   DCHECK(!object->HasFastProperties());
6837   Isolate* isolate = object->GetIsolate();
6838 
6839   if (object->IsJSGlobalObject()) {
6840     // If we have a global object, invalidate the cell and swap in a new one.
6841     Handle<GlobalDictionary> dictionary(
6842         JSGlobalObject::cast(*object)->global_dictionary(), isolate);
6843     DCHECK_NE(GlobalDictionary::kNotFound, entry);
6844 
6845     auto cell = PropertyCell::InvalidateEntry(isolate, dictionary, entry);
6846     cell->set_value(ReadOnlyRoots(isolate).the_hole_value());
6847     cell->set_property_details(
6848         PropertyDetails::Empty(PropertyCellType::kUninitialized));
6849   } else {
6850     Handle<NameDictionary> dictionary(object->property_dictionary(), isolate);
6851     DCHECK_NE(NameDictionary::kNotFound, entry);
6852 
6853     dictionary = NameDictionary::DeleteEntry(isolate, dictionary, entry);
6854     object->SetProperties(*dictionary);
6855   }
6856   if (object->map()->is_prototype_map()) {
6857     // Invalidate prototype validity cell as this may invalidate transitioning
6858     // store IC handlers.
6859     JSObject::InvalidatePrototypeChains(object->map());
6860   }
6861 }
6862 
6863 
DeleteProperty(LookupIterator * it,LanguageMode language_mode)6864 Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
6865                                        LanguageMode language_mode) {
6866   it->UpdateProtector();
6867 
6868   Isolate* isolate = it->isolate();
6869 
6870   if (it->state() == LookupIterator::JSPROXY) {
6871     return JSProxy::DeletePropertyOrElement(it->GetHolder<JSProxy>(),
6872                                             it->GetName(), language_mode);
6873   }
6874 
6875   if (it->GetReceiver()->IsJSProxy()) {
6876     if (it->state() != LookupIterator::NOT_FOUND) {
6877       DCHECK_EQ(LookupIterator::DATA, it->state());
6878       DCHECK(it->name()->IsPrivate());
6879       it->Delete();
6880     }
6881     return Just(true);
6882   }
6883   Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
6884 
6885   for (; it->IsFound(); it->Next()) {
6886     switch (it->state()) {
6887       case LookupIterator::JSPROXY:
6888       case LookupIterator::NOT_FOUND:
6889       case LookupIterator::TRANSITION:
6890         UNREACHABLE();
6891       case LookupIterator::ACCESS_CHECK:
6892         if (it->HasAccess()) break;
6893         isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
6894         RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6895         return Just(false);
6896       case LookupIterator::INTERCEPTOR: {
6897         ShouldThrow should_throw =
6898             is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
6899         Maybe<bool> result =
6900             JSObject::DeletePropertyWithInterceptor(it, should_throw);
6901         // An exception was thrown in the interceptor. Propagate.
6902         if (isolate->has_pending_exception()) return Nothing<bool>();
6903         // Delete with interceptor succeeded. Return result.
6904         // TODO(neis): In strict mode, we should probably throw if the
6905         // interceptor returns false.
6906         if (result.IsJust()) return result;
6907         break;
6908       }
6909       case LookupIterator::INTEGER_INDEXED_EXOTIC:
6910         return Just(true);
6911       case LookupIterator::DATA:
6912       case LookupIterator::ACCESSOR: {
6913         if (!it->IsConfigurable()) {
6914           // Fail if the property is not configurable.
6915           if (is_strict(language_mode)) {
6916             isolate->Throw(*isolate->factory()->NewTypeError(
6917                 MessageTemplate::kStrictDeleteProperty, it->GetName(),
6918                 receiver));
6919             return Nothing<bool>();
6920           }
6921           return Just(false);
6922         }
6923 
6924         it->Delete();
6925 
6926         return Just(true);
6927       }
6928     }
6929   }
6930 
6931   return Just(true);
6932 }
6933 
6934 
DeleteElement(Handle<JSReceiver> object,uint32_t index,LanguageMode language_mode)6935 Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index,
6936                                       LanguageMode language_mode) {
6937   LookupIterator it(object->GetIsolate(), object, index, object,
6938                     LookupIterator::OWN);
6939   return DeleteProperty(&it, language_mode);
6940 }
6941 
6942 
DeleteProperty(Handle<JSReceiver> object,Handle<Name> name,LanguageMode language_mode)6943 Maybe<bool> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
6944                                        Handle<Name> name,
6945                                        LanguageMode language_mode) {
6946   LookupIterator it(object, name, object, LookupIterator::OWN);
6947   return DeleteProperty(&it, language_mode);
6948 }
6949 
6950 
DeletePropertyOrElement(Handle<JSReceiver> object,Handle<Name> name,LanguageMode language_mode)6951 Maybe<bool> JSReceiver::DeletePropertyOrElement(Handle<JSReceiver> object,
6952                                                 Handle<Name> name,
6953                                                 LanguageMode language_mode) {
6954   LookupIterator it = LookupIterator::PropertyOrElement(
6955       object->GetIsolate(), object, name, object, LookupIterator::OWN);
6956   return DeleteProperty(&it, language_mode);
6957 }
6958 
6959 // ES6 19.1.2.4
6960 // static
DefineProperty(Isolate * isolate,Handle<Object> object,Handle<Object> key,Handle<Object> attributes)6961 Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object,
6962                                    Handle<Object> key,
6963                                    Handle<Object> attributes) {
6964   // 1. If Type(O) is not Object, throw a TypeError exception.
6965   if (!object->IsJSReceiver()) {
6966     Handle<String> fun_name =
6967         isolate->factory()->InternalizeUtf8String("Object.defineProperty");
6968     THROW_NEW_ERROR_RETURN_FAILURE(
6969         isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name));
6970   }
6971   // 2. Let key be ToPropertyKey(P).
6972   // 3. ReturnIfAbrupt(key).
6973   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key, ToPropertyKey(isolate, key));
6974   // 4. Let desc be ToPropertyDescriptor(Attributes).
6975   // 5. ReturnIfAbrupt(desc).
6976   PropertyDescriptor desc;
6977   if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) {
6978     return ReadOnlyRoots(isolate).exception();
6979   }
6980   // 6. Let success be DefinePropertyOrThrow(O,key, desc).
6981   Maybe<bool> success = DefineOwnProperty(
6982       isolate, Handle<JSReceiver>::cast(object), key, &desc, kThrowOnError);
6983   // 7. ReturnIfAbrupt(success).
6984   MAYBE_RETURN(success, ReadOnlyRoots(isolate).exception());
6985   CHECK(success.FromJust());
6986   // 8. Return O.
6987   return *object;
6988 }
6989 
6990 
6991 // ES6 19.1.2.3.1
6992 // static
DefineProperties(Isolate * isolate,Handle<Object> object,Handle<Object> properties)6993 MaybeHandle<Object> JSReceiver::DefineProperties(Isolate* isolate,
6994                                                  Handle<Object> object,
6995                                                  Handle<Object> properties) {
6996   // 1. If Type(O) is not Object, throw a TypeError exception.
6997   if (!object->IsJSReceiver()) {
6998     Handle<String> fun_name =
6999         isolate->factory()->InternalizeUtf8String("Object.defineProperties");
7000     THROW_NEW_ERROR(isolate,
7001                     NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name),
7002                     Object);
7003   }
7004   // 2. Let props be ToObject(Properties).
7005   // 3. ReturnIfAbrupt(props).
7006   Handle<JSReceiver> props;
7007   ASSIGN_RETURN_ON_EXCEPTION(isolate, props,
7008                              Object::ToObject(isolate, properties), Object);
7009 
7010   // 4. Let keys be props.[[OwnPropertyKeys]]().
7011   // 5. ReturnIfAbrupt(keys).
7012   Handle<FixedArray> keys;
7013   ASSIGN_RETURN_ON_EXCEPTION(
7014       isolate, keys, KeyAccumulator::GetKeys(props, KeyCollectionMode::kOwnOnly,
7015                                              ALL_PROPERTIES),
7016       Object);
7017   // 6. Let descriptors be an empty List.
7018   int capacity = keys->length();
7019   std::vector<PropertyDescriptor> descriptors(capacity);
7020   size_t descriptors_index = 0;
7021   // 7. Repeat for each element nextKey of keys in List order,
7022   for (int i = 0; i < keys->length(); ++i) {
7023     Handle<Object> next_key(keys->get(i), isolate);
7024     // 7a. Let propDesc be props.[[GetOwnProperty]](nextKey).
7025     // 7b. ReturnIfAbrupt(propDesc).
7026     bool success = false;
7027     LookupIterator it = LookupIterator::PropertyOrElement(
7028         isolate, props, next_key, &success, LookupIterator::OWN);
7029     DCHECK(success);
7030     Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
7031     if (maybe.IsNothing()) return MaybeHandle<Object>();
7032     PropertyAttributes attrs = maybe.FromJust();
7033     // 7c. If propDesc is not undefined and propDesc.[[Enumerable]] is true:
7034     if (attrs == ABSENT) continue;
7035     if (attrs & DONT_ENUM) continue;
7036     // 7c i. Let descObj be Get(props, nextKey).
7037     // 7c ii. ReturnIfAbrupt(descObj).
7038     Handle<Object> desc_obj;
7039     ASSIGN_RETURN_ON_EXCEPTION(isolate, desc_obj, Object::GetProperty(&it),
7040                                Object);
7041     // 7c iii. Let desc be ToPropertyDescriptor(descObj).
7042     success = PropertyDescriptor::ToPropertyDescriptor(
7043         isolate, desc_obj, &descriptors[descriptors_index]);
7044     // 7c iv. ReturnIfAbrupt(desc).
7045     if (!success) return MaybeHandle<Object>();
7046     // 7c v. Append the pair (a two element List) consisting of nextKey and
7047     //       desc to the end of descriptors.
7048     descriptors[descriptors_index].set_name(next_key);
7049     descriptors_index++;
7050   }
7051   // 8. For each pair from descriptors in list order,
7052   for (size_t i = 0; i < descriptors_index; ++i) {
7053     PropertyDescriptor* desc = &descriptors[i];
7054     // 8a. Let P be the first element of pair.
7055     // 8b. Let desc be the second element of pair.
7056     // 8c. Let status be DefinePropertyOrThrow(O, P, desc).
7057     Maybe<bool> status =
7058         DefineOwnProperty(isolate, Handle<JSReceiver>::cast(object),
7059                           desc->name(), desc, kThrowOnError);
7060     // 8d. ReturnIfAbrupt(status).
7061     if (status.IsNothing()) return MaybeHandle<Object>();
7062     CHECK(status.FromJust());
7063   }
7064   // 9. Return o.
7065   return object;
7066 }
7067 
7068 // static
DefineOwnProperty(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> key,PropertyDescriptor * desc,ShouldThrow should_throw)7069 Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate,
7070                                           Handle<JSReceiver> object,
7071                                           Handle<Object> key,
7072                                           PropertyDescriptor* desc,
7073                                           ShouldThrow should_throw) {
7074   if (object->IsJSArray()) {
7075     return JSArray::DefineOwnProperty(isolate, Handle<JSArray>::cast(object),
7076                                       key, desc, should_throw);
7077   }
7078   if (object->IsJSProxy()) {
7079     return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object),
7080                                       key, desc, should_throw);
7081   }
7082   if (object->IsJSTypedArray()) {
7083     return JSTypedArray::DefineOwnProperty(
7084         isolate, Handle<JSTypedArray>::cast(object), key, desc, should_throw);
7085   }
7086 
7087   // OrdinaryDefineOwnProperty, by virtue of calling
7088   // DefineOwnPropertyIgnoreAttributes, can handle arguments
7089   // (ES#sec-arguments-exotic-objects-defineownproperty-p-desc).
7090   return OrdinaryDefineOwnProperty(isolate, Handle<JSObject>::cast(object), key,
7091                                    desc, should_throw);
7092 }
7093 
7094 
7095 // static
OrdinaryDefineOwnProperty(Isolate * isolate,Handle<JSObject> object,Handle<Object> key,PropertyDescriptor * desc,ShouldThrow should_throw)7096 Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate,
7097                                                   Handle<JSObject> object,
7098                                                   Handle<Object> key,
7099                                                   PropertyDescriptor* desc,
7100                                                   ShouldThrow should_throw) {
7101   bool success = false;
7102   DCHECK(key->IsName() || key->IsNumber());  // |key| is a PropertyKey...
7103   LookupIterator it = LookupIterator::PropertyOrElement(
7104       isolate, object, key, &success, LookupIterator::OWN);
7105   DCHECK(success);  // ...so creating a LookupIterator can't fail.
7106 
7107   // Deal with access checks first.
7108   if (it.state() == LookupIterator::ACCESS_CHECK) {
7109     if (!it.HasAccess()) {
7110       isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>());
7111       RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
7112       return Just(true);
7113     }
7114     it.Next();
7115   }
7116 
7117   return OrdinaryDefineOwnProperty(&it, desc, should_throw);
7118 }
7119 
7120 
7121 // ES6 9.1.6.1
7122 // static
OrdinaryDefineOwnProperty(LookupIterator * it,PropertyDescriptor * desc,ShouldThrow should_throw)7123 Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
7124                                                   PropertyDescriptor* desc,
7125                                                   ShouldThrow should_throw) {
7126   Isolate* isolate = it->isolate();
7127   // 1. Let current be O.[[GetOwnProperty]](P).
7128   // 2. ReturnIfAbrupt(current).
7129   PropertyDescriptor current;
7130   MAYBE_RETURN(GetOwnPropertyDescriptor(it, &current), Nothing<bool>());
7131 
7132   it->Restart();
7133   // Handle interceptor
7134   for (; it->IsFound(); it->Next()) {
7135     if (it->state() == LookupIterator::INTERCEPTOR) {
7136       if (it->HolderIsReceiverOrHiddenPrototype()) {
7137         Maybe<bool> result = DefinePropertyWithInterceptorInternal(
7138             it, it->GetInterceptor(), should_throw, *desc);
7139         if (result.IsNothing() || result.FromJust()) {
7140           return result;
7141         }
7142       }
7143     }
7144   }
7145 
7146   // TODO(jkummerow/verwaest): It would be nice if we didn't have to reset
7147   // the iterator every time. Currently, the reasons why we need it are:
7148   // - handle interceptors correctly
7149   // - handle accessors correctly (which might change the holder's map)
7150   it->Restart();
7151   // 3. Let extensible be the value of the [[Extensible]] internal slot of O.
7152   Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
7153   bool extensible = JSObject::IsExtensible(object);
7154 
7155   return ValidateAndApplyPropertyDescriptor(
7156       isolate, it, extensible, desc, &current, should_throw, Handle<Name>());
7157 }
7158 
7159 
7160 // ES6 9.1.6.2
7161 // static
IsCompatiblePropertyDescriptor(Isolate * isolate,bool extensible,PropertyDescriptor * desc,PropertyDescriptor * current,Handle<Name> property_name,ShouldThrow should_throw)7162 Maybe<bool> JSReceiver::IsCompatiblePropertyDescriptor(
7163     Isolate* isolate, bool extensible, PropertyDescriptor* desc,
7164     PropertyDescriptor* current, Handle<Name> property_name,
7165     ShouldThrow should_throw) {
7166   // 1. Return ValidateAndApplyPropertyDescriptor(undefined, undefined,
7167   //    Extensible, Desc, Current).
7168   return ValidateAndApplyPropertyDescriptor(
7169       isolate, nullptr, extensible, desc, current, should_throw, property_name);
7170 }
7171 
7172 
7173 // ES6 9.1.6.3
7174 // static
ValidateAndApplyPropertyDescriptor(Isolate * isolate,LookupIterator * it,bool extensible,PropertyDescriptor * desc,PropertyDescriptor * current,ShouldThrow should_throw,Handle<Name> property_name)7175 Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor(
7176     Isolate* isolate, LookupIterator* it, bool extensible,
7177     PropertyDescriptor* desc, PropertyDescriptor* current,
7178     ShouldThrow should_throw, Handle<Name> property_name) {
7179   // We either need a LookupIterator, or a property name.
7180   DCHECK((it == nullptr) != property_name.is_null());
7181   Handle<JSObject> object;
7182   if (it != nullptr) object = Handle<JSObject>::cast(it->GetReceiver());
7183   bool desc_is_data_descriptor = PropertyDescriptor::IsDataDescriptor(desc);
7184   bool desc_is_accessor_descriptor =
7185       PropertyDescriptor::IsAccessorDescriptor(desc);
7186   bool desc_is_generic_descriptor =
7187       PropertyDescriptor::IsGenericDescriptor(desc);
7188   // 1. (Assert)
7189   // 2. If current is undefined, then
7190   if (current->is_empty()) {
7191     // 2a. If extensible is false, return false.
7192     if (!extensible) {
7193       RETURN_FAILURE(
7194           isolate, should_throw,
7195           NewTypeError(MessageTemplate::kDefineDisallowed,
7196                        it != nullptr ? it->GetName() : property_name));
7197     }
7198     // 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then:
7199     // (This is equivalent to !IsAccessorDescriptor(desc).)
7200     DCHECK((desc_is_generic_descriptor || desc_is_data_descriptor) ==
7201            !desc_is_accessor_descriptor);
7202     if (!desc_is_accessor_descriptor) {
7203       // 2c i. If O is not undefined, create an own data property named P of
7204       // object O whose [[Value]], [[Writable]], [[Enumerable]] and
7205       // [[Configurable]] attribute values are described by Desc. If the value
7206       // of an attribute field of Desc is absent, the attribute of the newly
7207       // created property is set to its default value.
7208       if (it != nullptr) {
7209         if (!desc->has_writable()) desc->set_writable(false);
7210         if (!desc->has_enumerable()) desc->set_enumerable(false);
7211         if (!desc->has_configurable()) desc->set_configurable(false);
7212         Handle<Object> value(
7213             desc->has_value()
7214                 ? desc->value()
7215                 : Handle<Object>::cast(isolate->factory()->undefined_value()));
7216         MaybeHandle<Object> result =
7217             JSObject::DefineOwnPropertyIgnoreAttributes(it, value,
7218                                                         desc->ToAttributes());
7219         if (result.is_null()) return Nothing<bool>();
7220       }
7221     } else {
7222       // 2d. Else Desc must be an accessor Property Descriptor,
7223       DCHECK(desc_is_accessor_descriptor);
7224       // 2d i. If O is not undefined, create an own accessor property named P
7225       // of object O whose [[Get]], [[Set]], [[Enumerable]] and
7226       // [[Configurable]] attribute values are described by Desc. If the value
7227       // of an attribute field of Desc is absent, the attribute of the newly
7228       // created property is set to its default value.
7229       if (it != nullptr) {
7230         if (!desc->has_enumerable()) desc->set_enumerable(false);
7231         if (!desc->has_configurable()) desc->set_configurable(false);
7232         Handle<Object> getter(
7233             desc->has_get()
7234                 ? desc->get()
7235                 : Handle<Object>::cast(isolate->factory()->null_value()));
7236         Handle<Object> setter(
7237             desc->has_set()
7238                 ? desc->set()
7239                 : Handle<Object>::cast(isolate->factory()->null_value()));
7240         MaybeHandle<Object> result =
7241             JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes());
7242         if (result.is_null()) return Nothing<bool>();
7243       }
7244     }
7245     // 2e. Return true.
7246     return Just(true);
7247   }
7248   // 3. Return true, if every field in Desc is absent.
7249   // 4. Return true, if every field in Desc also occurs in current and the
7250   // value of every field in Desc is the same value as the corresponding field
7251   // in current when compared using the SameValue algorithm.
7252   if ((!desc->has_enumerable() ||
7253        desc->enumerable() == current->enumerable()) &&
7254       (!desc->has_configurable() ||
7255        desc->configurable() == current->configurable()) &&
7256       (!desc->has_value() ||
7257        (current->has_value() && current->value()->SameValue(*desc->value()))) &&
7258       (!desc->has_writable() ||
7259        (current->has_writable() && current->writable() == desc->writable())) &&
7260       (!desc->has_get() ||
7261        (current->has_get() && current->get()->SameValue(*desc->get()))) &&
7262       (!desc->has_set() ||
7263        (current->has_set() && current->set()->SameValue(*desc->set())))) {
7264     return Just(true);
7265   }
7266   // 5. If the [[Configurable]] field of current is false, then
7267   if (!current->configurable()) {
7268     // 5a. Return false, if the [[Configurable]] field of Desc is true.
7269     if (desc->has_configurable() && desc->configurable()) {
7270       RETURN_FAILURE(
7271           isolate, should_throw,
7272           NewTypeError(MessageTemplate::kRedefineDisallowed,
7273                        it != nullptr ? it->GetName() : property_name));
7274     }
7275     // 5b. Return false, if the [[Enumerable]] field of Desc is present and the
7276     // [[Enumerable]] fields of current and Desc are the Boolean negation of
7277     // each other.
7278     if (desc->has_enumerable() && desc->enumerable() != current->enumerable()) {
7279       RETURN_FAILURE(
7280           isolate, should_throw,
7281           NewTypeError(MessageTemplate::kRedefineDisallowed,
7282                        it != nullptr ? it->GetName() : property_name));
7283     }
7284   }
7285 
7286   bool current_is_data_descriptor =
7287       PropertyDescriptor::IsDataDescriptor(current);
7288   // 6. If IsGenericDescriptor(Desc) is true, no further validation is required.
7289   if (desc_is_generic_descriptor) {
7290     // Nothing to see here.
7291 
7292     // 7. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) have
7293     // different results, then:
7294   } else if (current_is_data_descriptor != desc_is_data_descriptor) {
7295     // 7a. Return false, if the [[Configurable]] field of current is false.
7296     if (!current->configurable()) {
7297       RETURN_FAILURE(
7298           isolate, should_throw,
7299           NewTypeError(MessageTemplate::kRedefineDisallowed,
7300                        it != nullptr ? it->GetName() : property_name));
7301     }
7302     // 7b. If IsDataDescriptor(current) is true, then:
7303     if (current_is_data_descriptor) {
7304       // 7b i. If O is not undefined, convert the property named P of object O
7305       // from a data property to an accessor property. Preserve the existing
7306       // values of the converted property's [[Configurable]] and [[Enumerable]]
7307       // attributes and set the rest of the property's attributes to their
7308       // default values.
7309       // --> Folded into step 10.
7310     } else {
7311       // 7c i. If O is not undefined, convert the property named P of object O
7312       // from an accessor property to a data property. Preserve the existing
7313       // values of the converted property’s [[Configurable]] and [[Enumerable]]
7314       // attributes and set the rest of the property’s attributes to their
7315       // default values.
7316       // --> Folded into step 10.
7317     }
7318 
7319     // 8. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both
7320     // true, then:
7321   } else if (current_is_data_descriptor && desc_is_data_descriptor) {
7322     // 8a. If the [[Configurable]] field of current is false, then:
7323     if (!current->configurable()) {
7324       // 8a i. Return false, if the [[Writable]] field of current is false and
7325       // the [[Writable]] field of Desc is true.
7326       if (!current->writable() && desc->has_writable() && desc->writable()) {
7327         RETURN_FAILURE(
7328             isolate, should_throw,
7329             NewTypeError(MessageTemplate::kRedefineDisallowed,
7330                          it != nullptr ? it->GetName() : property_name));
7331       }
7332       // 8a ii. If the [[Writable]] field of current is false, then:
7333       if (!current->writable()) {
7334         // 8a ii 1. Return false, if the [[Value]] field of Desc is present and
7335         // SameValue(Desc.[[Value]], current.[[Value]]) is false.
7336         if (desc->has_value() && !desc->value()->SameValue(*current->value())) {
7337           RETURN_FAILURE(
7338               isolate, should_throw,
7339               NewTypeError(MessageTemplate::kRedefineDisallowed,
7340                            it != nullptr ? it->GetName() : property_name));
7341         }
7342       }
7343     }
7344   } else {
7345     // 9. Else IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc)
7346     // are both true,
7347     DCHECK(PropertyDescriptor::IsAccessorDescriptor(current) &&
7348            desc_is_accessor_descriptor);
7349     // 9a. If the [[Configurable]] field of current is false, then:
7350     if (!current->configurable()) {
7351       // 9a i. Return false, if the [[Set]] field of Desc is present and
7352       // SameValue(Desc.[[Set]], current.[[Set]]) is false.
7353       if (desc->has_set() && !desc->set()->SameValue(*current->set())) {
7354         RETURN_FAILURE(
7355             isolate, should_throw,
7356             NewTypeError(MessageTemplate::kRedefineDisallowed,
7357                          it != nullptr ? it->GetName() : property_name));
7358       }
7359       // 9a ii. Return false, if the [[Get]] field of Desc is present and
7360       // SameValue(Desc.[[Get]], current.[[Get]]) is false.
7361       if (desc->has_get() && !desc->get()->SameValue(*current->get())) {
7362         RETURN_FAILURE(
7363             isolate, should_throw,
7364             NewTypeError(MessageTemplate::kRedefineDisallowed,
7365                          it != nullptr ? it->GetName() : property_name));
7366       }
7367     }
7368   }
7369 
7370   // 10. If O is not undefined, then:
7371   if (it != nullptr) {
7372     // 10a. For each field of Desc that is present, set the corresponding
7373     // attribute of the property named P of object O to the value of the field.
7374     PropertyAttributes attrs = NONE;
7375 
7376     if (desc->has_enumerable()) {
7377       attrs = static_cast<PropertyAttributes>(
7378           attrs | (desc->enumerable() ? NONE : DONT_ENUM));
7379     } else {
7380       attrs = static_cast<PropertyAttributes>(
7381           attrs | (current->enumerable() ? NONE : DONT_ENUM));
7382     }
7383     if (desc->has_configurable()) {
7384       attrs = static_cast<PropertyAttributes>(
7385           attrs | (desc->configurable() ? NONE : DONT_DELETE));
7386     } else {
7387       attrs = static_cast<PropertyAttributes>(
7388           attrs | (current->configurable() ? NONE : DONT_DELETE));
7389     }
7390     if (desc_is_data_descriptor ||
7391         (desc_is_generic_descriptor && current_is_data_descriptor)) {
7392       if (desc->has_writable()) {
7393         attrs = static_cast<PropertyAttributes>(
7394             attrs | (desc->writable() ? NONE : READ_ONLY));
7395       } else {
7396         attrs = static_cast<PropertyAttributes>(
7397             attrs | (current->writable() ? NONE : READ_ONLY));
7398       }
7399       Handle<Object> value(
7400           desc->has_value() ? desc->value()
7401                             : current->has_value()
7402                                   ? current->value()
7403                                   : Handle<Object>::cast(
7404                                         isolate->factory()->undefined_value()));
7405       return JSObject::DefineOwnPropertyIgnoreAttributes(it, value, attrs,
7406                                                          should_throw);
7407     } else {
7408       DCHECK(desc_is_accessor_descriptor ||
7409              (desc_is_generic_descriptor &&
7410               PropertyDescriptor::IsAccessorDescriptor(current)));
7411       Handle<Object> getter(
7412           desc->has_get()
7413               ? desc->get()
7414               : current->has_get()
7415                     ? current->get()
7416                     : Handle<Object>::cast(isolate->factory()->null_value()));
7417       Handle<Object> setter(
7418           desc->has_set()
7419               ? desc->set()
7420               : current->has_set()
7421                     ? current->set()
7422                     : Handle<Object>::cast(isolate->factory()->null_value()));
7423       MaybeHandle<Object> result =
7424           JSObject::DefineAccessor(it, getter, setter, attrs);
7425       if (result.is_null()) return Nothing<bool>();
7426     }
7427   }
7428 
7429   // 11. Return true.
7430   return Just(true);
7431 }
7432 
7433 // static
CreateDataProperty(Isolate * isolate,Handle<JSReceiver> object,Handle<Name> key,Handle<Object> value,ShouldThrow should_throw)7434 Maybe<bool> JSReceiver::CreateDataProperty(Isolate* isolate,
7435                                            Handle<JSReceiver> object,
7436                                            Handle<Name> key,
7437                                            Handle<Object> value,
7438                                            ShouldThrow should_throw) {
7439   LookupIterator it = LookupIterator::PropertyOrElement(isolate, object, key,
7440                                                         LookupIterator::OWN);
7441   return CreateDataProperty(&it, value, should_throw);
7442 }
7443 
7444 // static
CreateDataProperty(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)7445 Maybe<bool> JSReceiver::CreateDataProperty(LookupIterator* it,
7446                                            Handle<Object> value,
7447                                            ShouldThrow should_throw) {
7448   DCHECK(!it->check_prototype_chain());
7449   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
7450   Isolate* isolate = receiver->GetIsolate();
7451 
7452   if (receiver->IsJSObject()) {
7453     return JSObject::CreateDataProperty(it, value, should_throw);  // Shortcut.
7454   }
7455 
7456   PropertyDescriptor new_desc;
7457   new_desc.set_value(value);
7458   new_desc.set_writable(true);
7459   new_desc.set_enumerable(true);
7460   new_desc.set_configurable(true);
7461 
7462   return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
7463                                        &new_desc, should_throw);
7464 }
7465 
CreateDataProperty(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)7466 Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it,
7467                                          Handle<Object> value,
7468                                          ShouldThrow should_throw) {
7469   DCHECK(it->GetReceiver()->IsJSObject());
7470   MAYBE_RETURN(JSReceiver::GetPropertyAttributes(it), Nothing<bool>());
7471   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
7472   Isolate* isolate = receiver->GetIsolate();
7473 
7474   if (it->IsFound()) {
7475     Maybe<PropertyAttributes> attributes = GetPropertyAttributes(it);
7476     MAYBE_RETURN(attributes, Nothing<bool>());
7477     if ((attributes.FromJust() & DONT_DELETE) != 0) {
7478       RETURN_FAILURE(
7479           isolate, should_throw,
7480           NewTypeError(MessageTemplate::kRedefineDisallowed, it->GetName()));
7481     }
7482   } else {
7483     if (!JSObject::IsExtensible(Handle<JSObject>::cast(it->GetReceiver()))) {
7484       RETURN_FAILURE(
7485           isolate, should_throw,
7486           NewTypeError(MessageTemplate::kDefineDisallowed, it->GetName()));
7487     }
7488   }
7489 
7490   RETURN_ON_EXCEPTION_VALUE(it->isolate(),
7491                             DefineOwnPropertyIgnoreAttributes(it, value, NONE),
7492                             Nothing<bool>());
7493 
7494   return Just(true);
7495 }
7496 
7497 // TODO(jkummerow): Consider unification with FastAsArrayLength() in
7498 // accessors.cc.
PropertyKeyToArrayLength(Handle<Object> value,uint32_t * length)7499 bool PropertyKeyToArrayLength(Handle<Object> value, uint32_t* length) {
7500   DCHECK(value->IsNumber() || value->IsName());
7501   if (value->ToArrayLength(length)) return true;
7502   if (value->IsString()) return String::cast(*value)->AsArrayIndex(length);
7503   return false;
7504 }
7505 
PropertyKeyToArrayIndex(Handle<Object> index_obj,uint32_t * output)7506 bool PropertyKeyToArrayIndex(Handle<Object> index_obj, uint32_t* output) {
7507   return PropertyKeyToArrayLength(index_obj, output) && *output != kMaxUInt32;
7508 }
7509 
7510 
7511 // ES6 9.4.2.1
7512 // static
DefineOwnProperty(Isolate * isolate,Handle<JSArray> o,Handle<Object> name,PropertyDescriptor * desc,ShouldThrow should_throw)7513 Maybe<bool> JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o,
7514                                        Handle<Object> name,
7515                                        PropertyDescriptor* desc,
7516                                        ShouldThrow should_throw) {
7517   // 1. Assert: IsPropertyKey(P) is true. ("P" is |name|.)
7518   // 2. If P is "length", then:
7519   // TODO(jkummerow): Check if we need slow string comparison.
7520   if (*name == ReadOnlyRoots(isolate).length_string()) {
7521     // 2a. Return ArraySetLength(A, Desc).
7522     return ArraySetLength(isolate, o, desc, should_throw);
7523   }
7524   // 3. Else if P is an array index, then:
7525   uint32_t index = 0;
7526   if (PropertyKeyToArrayIndex(name, &index)) {
7527     // 3a. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
7528     PropertyDescriptor old_len_desc;
7529     Maybe<bool> success = GetOwnPropertyDescriptor(
7530         isolate, o, isolate->factory()->length_string(), &old_len_desc);
7531     // 3b. (Assert)
7532     DCHECK(success.FromJust());
7533     USE(success);
7534     // 3c. Let oldLen be oldLenDesc.[[Value]].
7535     uint32_t old_len = 0;
7536     CHECK(old_len_desc.value()->ToArrayLength(&old_len));
7537     // 3d. Let index be ToUint32(P).
7538     // (Already done above.)
7539     // 3e. (Assert)
7540     // 3f. If index >= oldLen and oldLenDesc.[[Writable]] is false,
7541     //     return false.
7542     if (index >= old_len && old_len_desc.has_writable() &&
7543         !old_len_desc.writable()) {
7544       RETURN_FAILURE(isolate, should_throw,
7545                      NewTypeError(MessageTemplate::kDefineDisallowed, name));
7546     }
7547     // 3g. Let succeeded be OrdinaryDefineOwnProperty(A, P, Desc).
7548     Maybe<bool> succeeded =
7549         OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
7550     // 3h. Assert: succeeded is not an abrupt completion.
7551     //     In our case, if should_throw == kThrowOnError, it can be!
7552     // 3i. If succeeded is false, return false.
7553     if (succeeded.IsNothing() || !succeeded.FromJust()) return succeeded;
7554     // 3j. If index >= oldLen, then:
7555     if (index >= old_len) {
7556       // 3j i. Set oldLenDesc.[[Value]] to index + 1.
7557       old_len_desc.set_value(isolate->factory()->NewNumberFromUint(index + 1));
7558       // 3j ii. Let succeeded be
7559       //        OrdinaryDefineOwnProperty(A, "length", oldLenDesc).
7560       succeeded = OrdinaryDefineOwnProperty(isolate, o,
7561                                             isolate->factory()->length_string(),
7562                                             &old_len_desc, should_throw);
7563       // 3j iii. Assert: succeeded is true.
7564       DCHECK(succeeded.FromJust());
7565       USE(succeeded);
7566     }
7567     // 3k. Return true.
7568     return Just(true);
7569   }
7570 
7571   // 4. Return OrdinaryDefineOwnProperty(A, P, Desc).
7572   return OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
7573 }
7574 
7575 
7576 // Part of ES6 9.4.2.4 ArraySetLength.
7577 // static
AnythingToArrayLength(Isolate * isolate,Handle<Object> length_object,uint32_t * output)7578 bool JSArray::AnythingToArrayLength(Isolate* isolate,
7579                                     Handle<Object> length_object,
7580                                     uint32_t* output) {
7581   // Fast path: check numbers and strings that can be converted directly
7582   // and unobservably.
7583   if (length_object->ToArrayLength(output)) return true;
7584   if (length_object->IsString() &&
7585       Handle<String>::cast(length_object)->AsArrayIndex(output)) {
7586     return true;
7587   }
7588   // Slow path: follow steps in ES6 9.4.2.4 "ArraySetLength".
7589   // 3. Let newLen be ToUint32(Desc.[[Value]]).
7590   Handle<Object> uint32_v;
7591   if (!Object::ToUint32(isolate, length_object).ToHandle(&uint32_v)) {
7592     // 4. ReturnIfAbrupt(newLen).
7593     return false;
7594   }
7595   // 5. Let numberLen be ToNumber(Desc.[[Value]]).
7596   Handle<Object> number_v;
7597   if (!Object::ToNumber(isolate, length_object).ToHandle(&number_v)) {
7598     // 6. ReturnIfAbrupt(newLen).
7599     return false;
7600   }
7601   // 7. If newLen != numberLen, throw a RangeError exception.
7602   if (uint32_v->Number() != number_v->Number()) {
7603     Handle<Object> exception =
7604         isolate->factory()->NewRangeError(MessageTemplate::kInvalidArrayLength);
7605     isolate->Throw(*exception);
7606     return false;
7607   }
7608   CHECK(uint32_v->ToArrayLength(output));
7609   return true;
7610 }
7611 
7612 
7613 // ES6 9.4.2.4
7614 // static
ArraySetLength(Isolate * isolate,Handle<JSArray> a,PropertyDescriptor * desc,ShouldThrow should_throw)7615 Maybe<bool> JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a,
7616                                     PropertyDescriptor* desc,
7617                                     ShouldThrow should_throw) {
7618   // 1. If the [[Value]] field of Desc is absent, then
7619   if (!desc->has_value()) {
7620     // 1a. Return OrdinaryDefineOwnProperty(A, "length", Desc).
7621     return OrdinaryDefineOwnProperty(
7622         isolate, a, isolate->factory()->length_string(), desc, should_throw);
7623   }
7624   // 2. Let newLenDesc be a copy of Desc.
7625   // (Actual copying is not necessary.)
7626   PropertyDescriptor* new_len_desc = desc;
7627   // 3. - 7. Convert Desc.[[Value]] to newLen.
7628   uint32_t new_len = 0;
7629   if (!AnythingToArrayLength(isolate, desc->value(), &new_len)) {
7630     DCHECK(isolate->has_pending_exception());
7631     return Nothing<bool>();
7632   }
7633   // 8. Set newLenDesc.[[Value]] to newLen.
7634   // (Done below, if needed.)
7635   // 9. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
7636   PropertyDescriptor old_len_desc;
7637   Maybe<bool> success = GetOwnPropertyDescriptor(
7638       isolate, a, isolate->factory()->length_string(), &old_len_desc);
7639   // 10. (Assert)
7640   DCHECK(success.FromJust());
7641   USE(success);
7642   // 11. Let oldLen be oldLenDesc.[[Value]].
7643   uint32_t old_len = 0;
7644   CHECK(old_len_desc.value()->ToArrayLength(&old_len));
7645   // 12. If newLen >= oldLen, then
7646   if (new_len >= old_len) {
7647     // 8. Set newLenDesc.[[Value]] to newLen.
7648     // 12a. Return OrdinaryDefineOwnProperty(A, "length", newLenDesc).
7649     new_len_desc->set_value(isolate->factory()->NewNumberFromUint(new_len));
7650     return OrdinaryDefineOwnProperty(isolate, a,
7651                                      isolate->factory()->length_string(),
7652                                      new_len_desc, should_throw);
7653   }
7654   // 13. If oldLenDesc.[[Writable]] is false, return false.
7655   if (!old_len_desc.writable()) {
7656     RETURN_FAILURE(isolate, should_throw,
7657                    NewTypeError(MessageTemplate::kRedefineDisallowed,
7658                                 isolate->factory()->length_string()));
7659   }
7660   // 14. If newLenDesc.[[Writable]] is absent or has the value true,
7661   // let newWritable be true.
7662   bool new_writable = false;
7663   if (!new_len_desc->has_writable() || new_len_desc->writable()) {
7664     new_writable = true;
7665   } else {
7666     // 15. Else,
7667     // 15a. Need to defer setting the [[Writable]] attribute to false in case
7668     //      any elements cannot be deleted.
7669     // 15b. Let newWritable be false. (It's initialized as "false" anyway.)
7670     // 15c. Set newLenDesc.[[Writable]] to true.
7671     // (Not needed.)
7672   }
7673   // Most of steps 16 through 19 is implemented by JSArray::SetLength.
7674   JSArray::SetLength(a, new_len);
7675   // Steps 19d-ii, 20.
7676   if (!new_writable) {
7677     PropertyDescriptor readonly;
7678     readonly.set_writable(false);
7679     Maybe<bool> success = OrdinaryDefineOwnProperty(
7680         isolate, a, isolate->factory()->length_string(), &readonly,
7681         should_throw);
7682     DCHECK(success.FromJust());
7683     USE(success);
7684   }
7685   uint32_t actual_new_len = 0;
7686   CHECK(a->length()->ToArrayLength(&actual_new_len));
7687   // Steps 19d-v, 21. Return false if there were non-deletable elements.
7688   bool result = actual_new_len == new_len;
7689   if (!result) {
7690     RETURN_FAILURE(
7691         isolate, should_throw,
7692         NewTypeError(MessageTemplate::kStrictDeleteProperty,
7693                      isolate->factory()->NewNumberFromUint(actual_new_len - 1),
7694                      a));
7695   }
7696   return Just(result);
7697 }
7698 
7699 
7700 // ES6 9.5.6
7701 // static
DefineOwnProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Object> key,PropertyDescriptor * desc,ShouldThrow should_throw)7702 Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy,
7703                                        Handle<Object> key,
7704                                        PropertyDescriptor* desc,
7705                                        ShouldThrow should_throw) {
7706   STACK_CHECK(isolate, Nothing<bool>());
7707   if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) {
7708     DCHECK(!Handle<Symbol>::cast(key)->IsPrivateField());
7709     return JSProxy::SetPrivateSymbol(isolate, proxy, Handle<Symbol>::cast(key),
7710                                      desc, should_throw);
7711   }
7712   Handle<String> trap_name = isolate->factory()->defineProperty_string();
7713   // 1. Assert: IsPropertyKey(P) is true.
7714   DCHECK(key->IsName() || key->IsNumber());
7715   // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
7716   Handle<Object> handler(proxy->handler(), isolate);
7717   // 3. If handler is null, throw a TypeError exception.
7718   // 4. Assert: Type(handler) is Object.
7719   if (proxy->IsRevoked()) {
7720     isolate->Throw(*isolate->factory()->NewTypeError(
7721         MessageTemplate::kProxyRevoked, trap_name));
7722     return Nothing<bool>();
7723   }
7724   // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
7725   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
7726   // 6. Let trap be ? GetMethod(handler, "defineProperty").
7727   Handle<Object> trap;
7728   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7729       isolate, trap,
7730       Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
7731       Nothing<bool>());
7732   // 7. If trap is undefined, then:
7733   if (trap->IsUndefined(isolate)) {
7734     // 7a. Return target.[[DefineOwnProperty]](P, Desc).
7735     return JSReceiver::DefineOwnProperty(isolate, target, key, desc,
7736                                          should_throw);
7737   }
7738   // 8. Let descObj be FromPropertyDescriptor(Desc).
7739   Handle<Object> desc_obj = desc->ToObject(isolate);
7740   // 9. Let booleanTrapResult be
7741   //    ToBoolean(? Call(trap, handler, «target, P, descObj»)).
7742   Handle<Name> property_name =
7743       key->IsName()
7744           ? Handle<Name>::cast(key)
7745           : Handle<Name>::cast(isolate->factory()->NumberToString(key));
7746   // Do not leak private property names.
7747   DCHECK(!property_name->IsPrivate());
7748   Handle<Object> trap_result_obj;
7749   Handle<Object> args[] = {target, property_name, desc_obj};
7750   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7751       isolate, trap_result_obj,
7752       Execution::Call(isolate, trap, handler, arraysize(args), args),
7753       Nothing<bool>());
7754   // 10. If booleanTrapResult is false, return false.
7755   if (!trap_result_obj->BooleanValue(isolate)) {
7756     RETURN_FAILURE(isolate, should_throw,
7757                    NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
7758                                 trap_name, property_name));
7759   }
7760   // 11. Let targetDesc be ? target.[[GetOwnProperty]](P).
7761   PropertyDescriptor target_desc;
7762   Maybe<bool> target_found =
7763       JSReceiver::GetOwnPropertyDescriptor(isolate, target, key, &target_desc);
7764   MAYBE_RETURN(target_found, Nothing<bool>());
7765   // 12. Let extensibleTarget be ? IsExtensible(target).
7766   Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
7767   MAYBE_RETURN(maybe_extensible, Nothing<bool>());
7768   bool extensible_target = maybe_extensible.FromJust();
7769   // 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]]
7770   //     is false, then:
7771   // 13a. Let settingConfigFalse be true.
7772   // 14. Else let settingConfigFalse be false.
7773   bool setting_config_false = desc->has_configurable() && !desc->configurable();
7774   // 15. If targetDesc is undefined, then
7775   if (!target_found.FromJust()) {
7776     // 15a. If extensibleTarget is false, throw a TypeError exception.
7777     if (!extensible_target) {
7778       isolate->Throw(*isolate->factory()->NewTypeError(
7779           MessageTemplate::kProxyDefinePropertyNonExtensible, property_name));
7780       return Nothing<bool>();
7781     }
7782     // 15b. If settingConfigFalse is true, throw a TypeError exception.
7783     if (setting_config_false) {
7784       isolate->Throw(*isolate->factory()->NewTypeError(
7785           MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
7786       return Nothing<bool>();
7787     }
7788   } else {
7789     // 16. Else targetDesc is not undefined,
7790     // 16a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc,
7791     //      targetDesc) is false, throw a TypeError exception.
7792     Maybe<bool> valid =
7793         IsCompatiblePropertyDescriptor(isolate, extensible_target, desc,
7794                                        &target_desc, property_name, kDontThrow);
7795     MAYBE_RETURN(valid, Nothing<bool>());
7796     if (!valid.FromJust()) {
7797       isolate->Throw(*isolate->factory()->NewTypeError(
7798           MessageTemplate::kProxyDefinePropertyIncompatible, property_name));
7799       return Nothing<bool>();
7800     }
7801     // 16b. If settingConfigFalse is true and targetDesc.[[Configurable]] is
7802     //      true, throw a TypeError exception.
7803     if (setting_config_false && target_desc.configurable()) {
7804       isolate->Throw(*isolate->factory()->NewTypeError(
7805           MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
7806       return Nothing<bool>();
7807     }
7808   }
7809   // 17. Return true.
7810   return Just(true);
7811 }
7812 
7813 // static
SetPrivateSymbol(Isolate * isolate,Handle<JSProxy> proxy,Handle<Symbol> private_name,PropertyDescriptor * desc,ShouldThrow should_throw)7814 Maybe<bool> JSProxy::SetPrivateSymbol(Isolate* isolate, Handle<JSProxy> proxy,
7815                                       Handle<Symbol> private_name,
7816                                       PropertyDescriptor* desc,
7817                                       ShouldThrow should_throw) {
7818   DCHECK(!private_name->IsPrivateField());
7819   // Despite the generic name, this can only add private data properties.
7820   if (!PropertyDescriptor::IsDataDescriptor(desc) ||
7821       desc->ToAttributes() != DONT_ENUM) {
7822     RETURN_FAILURE(isolate, should_throw,
7823                    NewTypeError(MessageTemplate::kProxyPrivate));
7824   }
7825   DCHECK(proxy->map()->is_dictionary_map());
7826   Handle<Object> value =
7827       desc->has_value()
7828           ? desc->value()
7829           : Handle<Object>::cast(isolate->factory()->undefined_value());
7830 
7831   LookupIterator it(proxy, private_name, proxy);
7832 
7833   if (it.IsFound()) {
7834     DCHECK_EQ(LookupIterator::DATA, it.state());
7835     DCHECK_EQ(DONT_ENUM, it.property_attributes());
7836     it.WriteDataValue(value, false);
7837     return Just(true);
7838   }
7839 
7840   Handle<NameDictionary> dict(proxy->property_dictionary(), isolate);
7841   PropertyDetails details(kData, DONT_ENUM, PropertyCellType::kNoCell);
7842   Handle<NameDictionary> result =
7843       NameDictionary::Add(isolate, dict, private_name, value, details);
7844   if (!dict.is_identical_to(result)) proxy->SetProperties(*result);
7845   return Just(true);
7846 }
7847 
7848 // static
GetOwnPropertyDescriptor(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> key,PropertyDescriptor * desc)7849 Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate,
7850                                                  Handle<JSReceiver> object,
7851                                                  Handle<Object> key,
7852                                                  PropertyDescriptor* desc) {
7853   bool success = false;
7854   DCHECK(key->IsName() || key->IsNumber());  // |key| is a PropertyKey...
7855   LookupIterator it = LookupIterator::PropertyOrElement(
7856       isolate, object, key, &success, LookupIterator::OWN);
7857   DCHECK(success);  // ...so creating a LookupIterator can't fail.
7858   return GetOwnPropertyDescriptor(&it, desc);
7859 }
7860 
7861 namespace {
7862 
GetPropertyDescriptorWithInterceptor(LookupIterator * it,PropertyDescriptor * desc)7863 Maybe<bool> GetPropertyDescriptorWithInterceptor(LookupIterator* it,
7864                                                  PropertyDescriptor* desc) {
7865   if (it->state() == LookupIterator::ACCESS_CHECK) {
7866     if (it->HasAccess()) {
7867       it->Next();
7868     } else if (!JSObject::AllCanRead(it) ||
7869                it->state() != LookupIterator::INTERCEPTOR) {
7870       it->Restart();
7871       return Just(false);
7872     }
7873   }
7874 
7875   if (it->state() != LookupIterator::INTERCEPTOR) return Just(false);
7876 
7877   Isolate* isolate = it->isolate();
7878   Handle<InterceptorInfo> interceptor = it->GetInterceptor();
7879   if (interceptor->descriptor()->IsUndefined(isolate)) return Just(false);
7880 
7881   Handle<Object> result;
7882   Handle<JSObject> holder = it->GetHolder<JSObject>();
7883 
7884   Handle<Object> receiver = it->GetReceiver();
7885   if (!receiver->IsJSReceiver()) {
7886     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
7887                                      Object::ConvertReceiver(isolate, receiver),
7888                                      Nothing<bool>());
7889   }
7890 
7891   PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
7892                                  *holder, kDontThrow);
7893   if (it->IsElement()) {
7894     result = args.CallIndexedDescriptor(interceptor, it->index());
7895   } else {
7896     result = args.CallNamedDescriptor(interceptor, it->name());
7897   }
7898   if (!result.is_null()) {
7899     // Request successfully intercepted, try to set the property
7900     // descriptor.
7901     Utils::ApiCheck(
7902         PropertyDescriptor::ToPropertyDescriptor(isolate, result, desc),
7903         it->IsElement() ? "v8::IndexedPropertyDescriptorCallback"
7904                         : "v8::NamedPropertyDescriptorCallback",
7905         "Invalid property descriptor.");
7906 
7907     return Just(true);
7908   }
7909 
7910   it->Next();
7911   return Just(false);
7912 }
7913 }  // namespace
7914 
7915 // ES6 9.1.5.1
7916 // Returns true on success, false if the property didn't exist, nothing if
7917 // an exception was thrown.
7918 // static
GetOwnPropertyDescriptor(LookupIterator * it,PropertyDescriptor * desc)7919 Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it,
7920                                                  PropertyDescriptor* desc) {
7921   Isolate* isolate = it->isolate();
7922   // "Virtual" dispatch.
7923   if (it->IsFound() && it->GetHolder<JSReceiver>()->IsJSProxy()) {
7924     return JSProxy::GetOwnPropertyDescriptor(isolate, it->GetHolder<JSProxy>(),
7925                                              it->GetName(), desc);
7926   }
7927 
7928   Maybe<bool> intercepted = GetPropertyDescriptorWithInterceptor(it, desc);
7929   MAYBE_RETURN(intercepted, Nothing<bool>());
7930   if (intercepted.FromJust()) {
7931     return Just(true);
7932   }
7933 
7934   // Request was not intercepted, continue as normal.
7935   // 1. (Assert)
7936   // 2. If O does not have an own property with key P, return undefined.
7937   Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(it);
7938   MAYBE_RETURN(maybe, Nothing<bool>());
7939   PropertyAttributes attrs = maybe.FromJust();
7940   if (attrs == ABSENT) return Just(false);
7941   DCHECK(!isolate->has_pending_exception());
7942 
7943   // 3. Let D be a newly created Property Descriptor with no fields.
7944   DCHECK(desc->is_empty());
7945   // 4. Let X be O's own property whose key is P.
7946   // 5. If X is a data property, then
7947   bool is_accessor_pair = it->state() == LookupIterator::ACCESSOR &&
7948                           it->GetAccessors()->IsAccessorPair();
7949   if (!is_accessor_pair) {
7950     // 5a. Set D.[[Value]] to the value of X's [[Value]] attribute.
7951     Handle<Object> value;
7952     if (!Object::GetProperty(it).ToHandle(&value)) {
7953       DCHECK(isolate->has_pending_exception());
7954       return Nothing<bool>();
7955     }
7956     desc->set_value(value);
7957     // 5b. Set D.[[Writable]] to the value of X's [[Writable]] attribute
7958     desc->set_writable((attrs & READ_ONLY) == 0);
7959   } else {
7960     // 6. Else X is an accessor property, so
7961     Handle<AccessorPair> accessors =
7962         Handle<AccessorPair>::cast(it->GetAccessors());
7963     // 6a. Set D.[[Get]] to the value of X's [[Get]] attribute.
7964     desc->set_get(
7965         AccessorPair::GetComponent(isolate, accessors, ACCESSOR_GETTER));
7966     // 6b. Set D.[[Set]] to the value of X's [[Set]] attribute.
7967     desc->set_set(
7968         AccessorPair::GetComponent(isolate, accessors, ACCESSOR_SETTER));
7969   }
7970 
7971   // 7. Set D.[[Enumerable]] to the value of X's [[Enumerable]] attribute.
7972   desc->set_enumerable((attrs & DONT_ENUM) == 0);
7973   // 8. Set D.[[Configurable]] to the value of X's [[Configurable]] attribute.
7974   desc->set_configurable((attrs & DONT_DELETE) == 0);
7975   // 9. Return D.
7976   DCHECK(PropertyDescriptor::IsAccessorDescriptor(desc) !=
7977          PropertyDescriptor::IsDataDescriptor(desc));
7978   return Just(true);
7979 }
7980 
7981 
7982 // ES6 9.5.5
7983 // static
GetOwnPropertyDescriptor(Isolate * isolate,Handle<JSProxy> proxy,Handle<Name> name,PropertyDescriptor * desc)7984 Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate,
7985                                               Handle<JSProxy> proxy,
7986                                               Handle<Name> name,
7987                                               PropertyDescriptor* desc) {
7988   DCHECK(!name->IsPrivate());
7989   STACK_CHECK(isolate, Nothing<bool>());
7990 
7991   Handle<String> trap_name =
7992       isolate->factory()->getOwnPropertyDescriptor_string();
7993   // 1. (Assert)
7994   // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
7995   Handle<Object> handler(proxy->handler(), isolate);
7996   // 3. If handler is null, throw a TypeError exception.
7997   // 4. Assert: Type(handler) is Object.
7998   if (proxy->IsRevoked()) {
7999     isolate->Throw(*isolate->factory()->NewTypeError(
8000         MessageTemplate::kProxyRevoked, trap_name));
8001     return Nothing<bool>();
8002   }
8003   // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
8004   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
8005   // 6. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor").
8006   Handle<Object> trap;
8007   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8008       isolate, trap,
8009       Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
8010       Nothing<bool>());
8011   // 7. If trap is undefined, then
8012   if (trap->IsUndefined(isolate)) {
8013     // 7a. Return target.[[GetOwnProperty]](P).
8014     return JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, desc);
8015   }
8016   // 8. Let trapResultObj be ? Call(trap, handler, «target, P»).
8017   Handle<Object> trap_result_obj;
8018   Handle<Object> args[] = {target, name};
8019   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8020       isolate, trap_result_obj,
8021       Execution::Call(isolate, trap, handler, arraysize(args), args),
8022       Nothing<bool>());
8023   // 9. If Type(trapResultObj) is neither Object nor Undefined, throw a
8024   //    TypeError exception.
8025   if (!trap_result_obj->IsJSReceiver() &&
8026       !trap_result_obj->IsUndefined(isolate)) {
8027     isolate->Throw(*isolate->factory()->NewTypeError(
8028         MessageTemplate::kProxyGetOwnPropertyDescriptorInvalid, name));
8029     return Nothing<bool>();
8030   }
8031   // 10. Let targetDesc be ? target.[[GetOwnProperty]](P).
8032   PropertyDescriptor target_desc;
8033   Maybe<bool> found =
8034       JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
8035   MAYBE_RETURN(found, Nothing<bool>());
8036   // 11. If trapResultObj is undefined, then
8037   if (trap_result_obj->IsUndefined(isolate)) {
8038     // 11a. If targetDesc is undefined, return undefined.
8039     if (!found.FromJust()) return Just(false);
8040     // 11b. If targetDesc.[[Configurable]] is false, throw a TypeError
8041     //      exception.
8042     if (!target_desc.configurable()) {
8043       isolate->Throw(*isolate->factory()->NewTypeError(
8044           MessageTemplate::kProxyGetOwnPropertyDescriptorUndefined, name));
8045       return Nothing<bool>();
8046     }
8047     // 11c. Let extensibleTarget be ? IsExtensible(target).
8048     Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
8049     MAYBE_RETURN(extensible_target, Nothing<bool>());
8050     // 11d. (Assert)
8051     // 11e. If extensibleTarget is false, throw a TypeError exception.
8052     if (!extensible_target.FromJust()) {
8053       isolate->Throw(*isolate->factory()->NewTypeError(
8054           MessageTemplate::kProxyGetOwnPropertyDescriptorNonExtensible, name));
8055       return Nothing<bool>();
8056     }
8057     // 11f. Return undefined.
8058     return Just(false);
8059   }
8060   // 12. Let extensibleTarget be ? IsExtensible(target).
8061   Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
8062   MAYBE_RETURN(extensible_target, Nothing<bool>());
8063   // 13. Let resultDesc be ? ToPropertyDescriptor(trapResultObj).
8064   if (!PropertyDescriptor::ToPropertyDescriptor(isolate, trap_result_obj,
8065                                                 desc)) {
8066     DCHECK(isolate->has_pending_exception());
8067     return Nothing<bool>();
8068   }
8069   // 14. Call CompletePropertyDescriptor(resultDesc).
8070   PropertyDescriptor::CompletePropertyDescriptor(isolate, desc);
8071   // 15. Let valid be IsCompatiblePropertyDescriptor (extensibleTarget,
8072   //     resultDesc, targetDesc).
8073   Maybe<bool> valid =
8074       IsCompatiblePropertyDescriptor(isolate, extensible_target.FromJust(),
8075                                      desc, &target_desc, name, kDontThrow);
8076   MAYBE_RETURN(valid, Nothing<bool>());
8077   // 16. If valid is false, throw a TypeError exception.
8078   if (!valid.FromJust()) {
8079     isolate->Throw(*isolate->factory()->NewTypeError(
8080         MessageTemplate::kProxyGetOwnPropertyDescriptorIncompatible, name));
8081     return Nothing<bool>();
8082   }
8083   // 17. If resultDesc.[[Configurable]] is false, then
8084   if (!desc->configurable()) {
8085     // 17a. If targetDesc is undefined or targetDesc.[[Configurable]] is true:
8086     if (target_desc.is_empty() || target_desc.configurable()) {
8087       // 17a i. Throw a TypeError exception.
8088       isolate->Throw(*isolate->factory()->NewTypeError(
8089           MessageTemplate::kProxyGetOwnPropertyDescriptorNonConfigurable,
8090           name));
8091       return Nothing<bool>();
8092     }
8093   }
8094   // 18. Return resultDesc.
8095   return Just(true);
8096 }
8097 
8098 
ReferencesObjectFromElements(FixedArray * elements,ElementsKind kind,Object * object)8099 bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
8100                                             ElementsKind kind,
8101                                             Object* object) {
8102   Isolate* isolate = GetIsolate();
8103   if (IsObjectElementsKind(kind) || kind == FAST_STRING_WRAPPER_ELEMENTS) {
8104     int length = IsJSArray() ? Smi::ToInt(JSArray::cast(this)->length())
8105                              : elements->length();
8106     for (int i = 0; i < length; ++i) {
8107       Object* element = elements->get(i);
8108       if (!element->IsTheHole(isolate) && element == object) return true;
8109     }
8110   } else {
8111     DCHECK(kind == DICTIONARY_ELEMENTS || kind == SLOW_STRING_WRAPPER_ELEMENTS);
8112     Object* key = NumberDictionary::cast(elements)->SlowReverseLookup(object);
8113     if (!key->IsUndefined(isolate)) return true;
8114   }
8115   return false;
8116 }
8117 
8118 
8119 // Check whether this object references another object.
ReferencesObject(Object * obj)8120 bool JSObject::ReferencesObject(Object* obj) {
8121   Map* map_of_this = map();
8122   Heap* heap = GetHeap();
8123   DisallowHeapAllocation no_allocation;
8124 
8125   // Is the object the constructor for this object?
8126   if (map_of_this->GetConstructor() == obj) {
8127     return true;
8128   }
8129 
8130   // Is the object the prototype for this object?
8131   if (map_of_this->prototype() == obj) {
8132     return true;
8133   }
8134 
8135   // Check if the object is among the named properties.
8136   Object* key = SlowReverseLookup(obj);
8137   if (!key->IsUndefined(heap->isolate())) {
8138     return true;
8139   }
8140 
8141   // Check if the object is among the indexed properties.
8142   ElementsKind kind = GetElementsKind();
8143   switch (kind) {
8144     // Raw pixels and external arrays do not reference other
8145     // objects.
8146 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
8147   case TYPE##_ELEMENTS:                           \
8148     break;
8149 
8150     TYPED_ARRAYS(TYPED_ARRAY_CASE)
8151 #undef TYPED_ARRAY_CASE
8152 
8153     case PACKED_DOUBLE_ELEMENTS:
8154     case HOLEY_DOUBLE_ELEMENTS:
8155       break;
8156     case PACKED_SMI_ELEMENTS:
8157     case HOLEY_SMI_ELEMENTS:
8158       break;
8159     case PACKED_ELEMENTS:
8160     case HOLEY_ELEMENTS:
8161     case DICTIONARY_ELEMENTS:
8162     case FAST_STRING_WRAPPER_ELEMENTS:
8163     case SLOW_STRING_WRAPPER_ELEMENTS: {
8164       FixedArray* elements = FixedArray::cast(this->elements());
8165       if (ReferencesObjectFromElements(elements, kind, obj)) return true;
8166       break;
8167     }
8168     case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
8169     case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
8170       SloppyArgumentsElements* elements =
8171           SloppyArgumentsElements::cast(this->elements());
8172       // Check the mapped parameters.
8173       for (uint32_t i = 0; i < elements->parameter_map_length(); ++i) {
8174         Object* value = elements->get_mapped_entry(i);
8175         if (!value->IsTheHole(heap->isolate()) && value == obj) return true;
8176       }
8177       // Check the arguments.
8178       FixedArray* arguments = elements->arguments();
8179       kind = arguments->IsNumberDictionary() ? DICTIONARY_ELEMENTS
8180                                              : HOLEY_ELEMENTS;
8181       if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
8182       break;
8183     }
8184     case NO_ELEMENTS:
8185       break;
8186   }
8187 
8188   // For functions check the context.
8189   if (IsJSFunction()) {
8190     // Get the constructor function for arguments array.
8191     Map* arguments_map =
8192         heap->isolate()->context()->native_context()->sloppy_arguments_map();
8193     JSFunction* arguments_function =
8194         JSFunction::cast(arguments_map->GetConstructor());
8195 
8196     // Get the context and don't check if it is the native context.
8197     JSFunction* f = JSFunction::cast(this);
8198     Context* context = f->context();
8199     if (context->IsNativeContext()) {
8200       return false;
8201     }
8202 
8203     // Check the non-special context slots.
8204     for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
8205       // Only check JS objects.
8206       if (context->get(i)->IsJSObject()) {
8207         JSObject* ctxobj = JSObject::cast(context->get(i));
8208         // If it is an arguments array check the content.
8209         if (ctxobj->map()->GetConstructor() == arguments_function) {
8210           if (ctxobj->ReferencesObject(obj)) {
8211             return true;
8212           }
8213         } else if (ctxobj == obj) {
8214           return true;
8215         }
8216       }
8217     }
8218 
8219     // Check the context extension (if any) if it can have references.
8220     if (context->has_extension() && !context->IsCatchContext() &&
8221         !context->IsModuleContext()) {
8222       // With harmony scoping, a JSFunction may have a script context.
8223       // TODO(mvstanton): walk into the ScopeInfo.
8224       if (context->IsScriptContext()) {
8225         return false;
8226       }
8227 
8228       return context->extension_object()->ReferencesObject(obj);
8229     }
8230   }
8231 
8232   // No references to object.
8233   return false;
8234 }
8235 
8236 
SetIntegrityLevel(Handle<JSReceiver> receiver,IntegrityLevel level,ShouldThrow should_throw)8237 Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver,
8238                                           IntegrityLevel level,
8239                                           ShouldThrow should_throw) {
8240   DCHECK(level == SEALED || level == FROZEN);
8241 
8242   if (receiver->IsJSObject()) {
8243     Handle<JSObject> object = Handle<JSObject>::cast(receiver);
8244 
8245     if (!object->HasSloppyArgumentsElements() &&
8246         !object->IsJSModuleNamespace()) {  // Fast path.
8247       // Prevent memory leaks by not adding unnecessary transitions.
8248       Maybe<bool> test = JSObject::TestIntegrityLevel(object, level);
8249       MAYBE_RETURN(test, Nothing<bool>());
8250       if (test.FromJust()) return test;
8251 
8252       if (level == SEALED) {
8253         return JSObject::PreventExtensionsWithTransition<SEALED>(object,
8254                                                                  should_throw);
8255       } else {
8256         return JSObject::PreventExtensionsWithTransition<FROZEN>(object,
8257                                                                  should_throw);
8258       }
8259     }
8260   }
8261 
8262   Isolate* isolate = receiver->GetIsolate();
8263 
8264   MAYBE_RETURN(JSReceiver::PreventExtensions(receiver, should_throw),
8265                Nothing<bool>());
8266 
8267   Handle<FixedArray> keys;
8268   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8269       isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>());
8270 
8271   PropertyDescriptor no_conf;
8272   no_conf.set_configurable(false);
8273 
8274   PropertyDescriptor no_conf_no_write;
8275   no_conf_no_write.set_configurable(false);
8276   no_conf_no_write.set_writable(false);
8277 
8278   if (level == SEALED) {
8279     for (int i = 0; i < keys->length(); ++i) {
8280       Handle<Object> key(keys->get(i), isolate);
8281       MAYBE_RETURN(
8282           DefineOwnProperty(isolate, receiver, key, &no_conf, kThrowOnError),
8283           Nothing<bool>());
8284     }
8285     return Just(true);
8286   }
8287 
8288   for (int i = 0; i < keys->length(); ++i) {
8289     Handle<Object> key(keys->get(i), isolate);
8290     PropertyDescriptor current_desc;
8291     Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
8292         isolate, receiver, key, &current_desc);
8293     MAYBE_RETURN(owned, Nothing<bool>());
8294     if (owned.FromJust()) {
8295       PropertyDescriptor desc =
8296           PropertyDescriptor::IsAccessorDescriptor(&current_desc)
8297               ? no_conf
8298               : no_conf_no_write;
8299       MAYBE_RETURN(
8300           DefineOwnProperty(isolate, receiver, key, &desc, kThrowOnError),
8301           Nothing<bool>());
8302     }
8303   }
8304   return Just(true);
8305 }
8306 
8307 namespace {
8308 
8309 template <typename Dictionary>
TestDictionaryPropertiesIntegrityLevel(Dictionary * dict,ReadOnlyRoots roots,PropertyAttributes level)8310 bool TestDictionaryPropertiesIntegrityLevel(Dictionary* dict,
8311                                             ReadOnlyRoots roots,
8312                                             PropertyAttributes level) {
8313   DCHECK(level == SEALED || level == FROZEN);
8314 
8315   uint32_t capacity = dict->Capacity();
8316   for (uint32_t i = 0; i < capacity; i++) {
8317     Object* key;
8318     if (!dict->ToKey(roots, i, &key)) continue;
8319     if (key->FilterKey(ALL_PROPERTIES)) continue;
8320     PropertyDetails details = dict->DetailsAt(i);
8321     if (details.IsConfigurable()) return false;
8322     if (level == FROZEN && details.kind() == kData && !details.IsReadOnly()) {
8323       return false;
8324     }
8325   }
8326   return true;
8327 }
8328 
TestFastPropertiesIntegrityLevel(Map * map,PropertyAttributes level)8329 bool TestFastPropertiesIntegrityLevel(Map* map, PropertyAttributes level) {
8330   DCHECK(level == SEALED || level == FROZEN);
8331   DCHECK(!map->IsCustomElementsReceiverMap());
8332   DCHECK(!map->is_dictionary_map());
8333 
8334   DescriptorArray* descriptors = map->instance_descriptors();
8335   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
8336   for (int i = 0; i < number_of_own_descriptors; i++) {
8337     if (descriptors->GetKey(i)->IsPrivate()) continue;
8338     PropertyDetails details = descriptors->GetDetails(i);
8339     if (details.IsConfigurable()) return false;
8340     if (level == FROZEN && details.kind() == kData && !details.IsReadOnly()) {
8341       return false;
8342     }
8343   }
8344   return true;
8345 }
8346 
TestPropertiesIntegrityLevel(JSObject * object,PropertyAttributes level)8347 bool TestPropertiesIntegrityLevel(JSObject* object, PropertyAttributes level) {
8348   DCHECK(!object->map()->IsCustomElementsReceiverMap());
8349 
8350   if (object->HasFastProperties()) {
8351     return TestFastPropertiesIntegrityLevel(object->map(), level);
8352   }
8353 
8354   return TestDictionaryPropertiesIntegrityLevel(
8355       object->property_dictionary(), object->GetReadOnlyRoots(), level);
8356 }
8357 
TestElementsIntegrityLevel(JSObject * object,PropertyAttributes level)8358 bool TestElementsIntegrityLevel(JSObject* object, PropertyAttributes level) {
8359   DCHECK(!object->HasSloppyArgumentsElements());
8360 
8361   ElementsKind kind = object->GetElementsKind();
8362 
8363   if (IsDictionaryElementsKind(kind)) {
8364     return TestDictionaryPropertiesIntegrityLevel(
8365         NumberDictionary::cast(object->elements()), object->GetReadOnlyRoots(),
8366         level);
8367   }
8368 
8369   ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
8370   // Only DICTIONARY_ELEMENTS and SLOW_SLOPPY_ARGUMENTS_ELEMENTS have
8371   // PropertyAttributes so just test if empty
8372   return accessor->NumberOfElements(object) == 0;
8373 }
8374 
FastTestIntegrityLevel(JSObject * object,PropertyAttributes level)8375 bool FastTestIntegrityLevel(JSObject* object, PropertyAttributes level) {
8376   DCHECK(!object->map()->IsCustomElementsReceiverMap());
8377 
8378   return !object->map()->is_extensible() &&
8379          TestElementsIntegrityLevel(object, level) &&
8380          TestPropertiesIntegrityLevel(object, level);
8381 }
8382 
GenericTestIntegrityLevel(Handle<JSReceiver> receiver,PropertyAttributes level)8383 Maybe<bool> GenericTestIntegrityLevel(Handle<JSReceiver> receiver,
8384                                       PropertyAttributes level) {
8385   DCHECK(level == SEALED || level == FROZEN);
8386 
8387   Maybe<bool> extensible = JSReceiver::IsExtensible(receiver);
8388   MAYBE_RETURN(extensible, Nothing<bool>());
8389   if (extensible.FromJust()) return Just(false);
8390 
8391   Isolate* isolate = receiver->GetIsolate();
8392 
8393   Handle<FixedArray> keys;
8394   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8395       isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>());
8396 
8397   for (int i = 0; i < keys->length(); ++i) {
8398     Handle<Object> key(keys->get(i), isolate);
8399     PropertyDescriptor current_desc;
8400     Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
8401         isolate, receiver, key, &current_desc);
8402     MAYBE_RETURN(owned, Nothing<bool>());
8403     if (owned.FromJust()) {
8404       if (current_desc.configurable()) return Just(false);
8405       if (level == FROZEN &&
8406           PropertyDescriptor::IsDataDescriptor(&current_desc) &&
8407           current_desc.writable()) {
8408         return Just(false);
8409       }
8410     }
8411   }
8412   return Just(true);
8413 }
8414 
8415 }  // namespace
8416 
TestIntegrityLevel(Handle<JSReceiver> receiver,IntegrityLevel level)8417 Maybe<bool> JSReceiver::TestIntegrityLevel(Handle<JSReceiver> receiver,
8418                                            IntegrityLevel level) {
8419   if (!receiver->map()->IsCustomElementsReceiverMap()) {
8420     return JSObject::TestIntegrityLevel(Handle<JSObject>::cast(receiver),
8421                                         level);
8422   }
8423   return GenericTestIntegrityLevel(receiver, level);
8424 }
8425 
TestIntegrityLevel(Handle<JSObject> object,IntegrityLevel level)8426 Maybe<bool> JSObject::TestIntegrityLevel(Handle<JSObject> object,
8427                                          IntegrityLevel level) {
8428   if (!object->map()->IsCustomElementsReceiverMap() &&
8429       !object->HasSloppyArgumentsElements()) {
8430     return Just(FastTestIntegrityLevel(*object, level));
8431   }
8432   return GenericTestIntegrityLevel(Handle<JSReceiver>::cast(object), level);
8433 }
8434 
PreventExtensions(Handle<JSReceiver> object,ShouldThrow should_throw)8435 Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object,
8436                                           ShouldThrow should_throw) {
8437   if (object->IsJSProxy()) {
8438     return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object),
8439                                       should_throw);
8440   }
8441   DCHECK(object->IsJSObject());
8442   return JSObject::PreventExtensions(Handle<JSObject>::cast(object),
8443                                      should_throw);
8444 }
8445 
8446 
PreventExtensions(Handle<JSProxy> proxy,ShouldThrow should_throw)8447 Maybe<bool> JSProxy::PreventExtensions(Handle<JSProxy> proxy,
8448                                        ShouldThrow should_throw) {
8449   Isolate* isolate = proxy->GetIsolate();
8450   STACK_CHECK(isolate, Nothing<bool>());
8451   Factory* factory = isolate->factory();
8452   Handle<String> trap_name = factory->preventExtensions_string();
8453 
8454   if (proxy->IsRevoked()) {
8455     isolate->Throw(
8456         *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
8457     return Nothing<bool>();
8458   }
8459   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
8460   Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
8461 
8462   Handle<Object> trap;
8463   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8464       isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
8465   if (trap->IsUndefined(isolate)) {
8466     return JSReceiver::PreventExtensions(target, should_throw);
8467   }
8468 
8469   Handle<Object> trap_result;
8470   Handle<Object> args[] = {target};
8471   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8472       isolate, trap_result,
8473       Execution::Call(isolate, trap, handler, arraysize(args), args),
8474       Nothing<bool>());
8475   if (!trap_result->BooleanValue(isolate)) {
8476     RETURN_FAILURE(
8477         isolate, should_throw,
8478         NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
8479   }
8480 
8481   // Enforce the invariant.
8482   Maybe<bool> target_result = JSReceiver::IsExtensible(target);
8483   MAYBE_RETURN(target_result, Nothing<bool>());
8484   if (target_result.FromJust()) {
8485     isolate->Throw(*factory->NewTypeError(
8486         MessageTemplate::kProxyPreventExtensionsExtensible));
8487     return Nothing<bool>();
8488   }
8489   return Just(true);
8490 }
8491 
8492 
PreventExtensions(Handle<JSObject> object,ShouldThrow should_throw)8493 Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object,
8494                                         ShouldThrow should_throw) {
8495   Isolate* isolate = object->GetIsolate();
8496 
8497   if (!object->HasSloppyArgumentsElements()) {
8498     return PreventExtensionsWithTransition<NONE>(object, should_throw);
8499   }
8500 
8501   if (object->IsAccessCheckNeeded() &&
8502       !isolate->MayAccess(handle(isolate->context(), isolate), object)) {
8503     isolate->ReportFailedAccessCheck(object);
8504     RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
8505     RETURN_FAILURE(isolate, should_throw,
8506                    NewTypeError(MessageTemplate::kNoAccess));
8507   }
8508 
8509   if (!object->map()->is_extensible()) return Just(true);
8510 
8511   if (object->IsJSGlobalProxy()) {
8512     PrototypeIterator iter(isolate, object);
8513     if (iter.IsAtEnd()) return Just(true);
8514     DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
8515     return PreventExtensions(PrototypeIterator::GetCurrent<JSObject>(iter),
8516                              should_throw);
8517   }
8518 
8519   if (object->map()->has_named_interceptor() ||
8520       object->map()->has_indexed_interceptor()) {
8521     RETURN_FAILURE(isolate, should_throw,
8522                    NewTypeError(MessageTemplate::kCannotPreventExt));
8523   }
8524 
8525   if (!object->HasFixedTypedArrayElements()) {
8526     // If there are fast elements we normalize.
8527     Handle<NumberDictionary> dictionary = NormalizeElements(object);
8528     DCHECK(object->HasDictionaryElements() ||
8529            object->HasSlowArgumentsElements());
8530 
8531     // Make sure that we never go back to fast case.
8532     object->RequireSlowElements(*dictionary);
8533   }
8534 
8535   // Do a map transition, other objects with this map may still
8536   // be extensible.
8537   // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
8538   Handle<Map> new_map =
8539       Map::Copy(isolate, handle(object->map(), isolate), "PreventExtensions");
8540 
8541   new_map->set_is_extensible(false);
8542   JSObject::MigrateToMap(object, new_map);
8543   DCHECK(!object->map()->is_extensible());
8544 
8545   return Just(true);
8546 }
8547 
8548 
IsExtensible(Handle<JSReceiver> object)8549 Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) {
8550   if (object->IsJSProxy()) {
8551     return JSProxy::IsExtensible(Handle<JSProxy>::cast(object));
8552   }
8553   return Just(JSObject::IsExtensible(Handle<JSObject>::cast(object)));
8554 }
8555 
8556 
IsExtensible(Handle<JSProxy> proxy)8557 Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) {
8558   Isolate* isolate = proxy->GetIsolate();
8559   STACK_CHECK(isolate, Nothing<bool>());
8560   Factory* factory = isolate->factory();
8561   Handle<String> trap_name = factory->isExtensible_string();
8562 
8563   if (proxy->IsRevoked()) {
8564     isolate->Throw(
8565         *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
8566     return Nothing<bool>();
8567   }
8568   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
8569   Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
8570 
8571   Handle<Object> trap;
8572   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8573       isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
8574   if (trap->IsUndefined(isolate)) {
8575     return JSReceiver::IsExtensible(target);
8576   }
8577 
8578   Handle<Object> trap_result;
8579   Handle<Object> args[] = {target};
8580   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8581       isolate, trap_result,
8582       Execution::Call(isolate, trap, handler, arraysize(args), args),
8583       Nothing<bool>());
8584 
8585   // Enforce the invariant.
8586   Maybe<bool> target_result = JSReceiver::IsExtensible(target);
8587   MAYBE_RETURN(target_result, Nothing<bool>());
8588   if (target_result.FromJust() != trap_result->BooleanValue(isolate)) {
8589     isolate->Throw(
8590         *factory->NewTypeError(MessageTemplate::kProxyIsExtensibleInconsistent,
8591                                factory->ToBoolean(target_result.FromJust())));
8592     return Nothing<bool>();
8593   }
8594   return target_result;
8595 }
8596 
8597 
IsExtensible(Handle<JSObject> object)8598 bool JSObject::IsExtensible(Handle<JSObject> object) {
8599   Isolate* isolate = object->GetIsolate();
8600   if (object->IsAccessCheckNeeded() &&
8601       !isolate->MayAccess(handle(isolate->context(), isolate), object)) {
8602     return true;
8603   }
8604   if (object->IsJSGlobalProxy()) {
8605     PrototypeIterator iter(isolate, *object);
8606     if (iter.IsAtEnd()) return false;
8607     DCHECK(iter.GetCurrent()->IsJSGlobalObject());
8608     return iter.GetCurrent<JSObject>()->map()->is_extensible();
8609   }
8610   return object->map()->is_extensible();
8611 }
8612 
8613 namespace {
8614 
8615 template <typename Dictionary>
ApplyAttributesToDictionary(Isolate * isolate,ReadOnlyRoots roots,Handle<Dictionary> dictionary,const PropertyAttributes attributes)8616 void ApplyAttributesToDictionary(Isolate* isolate, ReadOnlyRoots roots,
8617                                  Handle<Dictionary> dictionary,
8618                                  const PropertyAttributes attributes) {
8619   int capacity = dictionary->Capacity();
8620   for (int i = 0; i < capacity; i++) {
8621     Object* k;
8622     if (!dictionary->ToKey(roots, i, &k)) continue;
8623     if (k->FilterKey(ALL_PROPERTIES)) continue;
8624     PropertyDetails details = dictionary->DetailsAt(i);
8625     int attrs = attributes;
8626     // READ_ONLY is an invalid attribute for JS setters/getters.
8627     if ((attributes & READ_ONLY) && details.kind() == kAccessor) {
8628       Object* v = dictionary->ValueAt(i);
8629       if (v->IsAccessorPair()) attrs &= ~READ_ONLY;
8630     }
8631     details = details.CopyAddAttributes(static_cast<PropertyAttributes>(attrs));
8632     dictionary->DetailsAtPut(isolate, i, details);
8633   }
8634 }
8635 
8636 }  // namespace
8637 
8638 template <PropertyAttributes attrs>
PreventExtensionsWithTransition(Handle<JSObject> object,ShouldThrow should_throw)8639 Maybe<bool> JSObject::PreventExtensionsWithTransition(
8640     Handle<JSObject> object, ShouldThrow should_throw) {
8641   STATIC_ASSERT(attrs == NONE || attrs == SEALED || attrs == FROZEN);
8642 
8643   // Sealing/freezing sloppy arguments or namespace objects should be handled
8644   // elsewhere.
8645   DCHECK(!object->HasSloppyArgumentsElements());
8646   DCHECK_IMPLIES(object->IsJSModuleNamespace(), attrs == NONE);
8647 
8648   Isolate* isolate = object->GetIsolate();
8649   if (object->IsAccessCheckNeeded() &&
8650       !isolate->MayAccess(handle(isolate->context(), isolate), object)) {
8651     isolate->ReportFailedAccessCheck(object);
8652     RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
8653     RETURN_FAILURE(isolate, should_throw,
8654                    NewTypeError(MessageTemplate::kNoAccess));
8655   }
8656 
8657   if (attrs == NONE && !object->map()->is_extensible()) return Just(true);
8658 
8659   if (object->IsJSGlobalProxy()) {
8660     PrototypeIterator iter(isolate, object);
8661     if (iter.IsAtEnd()) return Just(true);
8662     DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
8663     return PreventExtensionsWithTransition<attrs>(
8664         PrototypeIterator::GetCurrent<JSObject>(iter), should_throw);
8665   }
8666 
8667   if (object->map()->has_named_interceptor() ||
8668       object->map()->has_indexed_interceptor()) {
8669     MessageTemplate::Template message = MessageTemplate::kNone;
8670     switch (attrs) {
8671       case NONE:
8672         message = MessageTemplate::kCannotPreventExt;
8673         break;
8674 
8675       case SEALED:
8676         message = MessageTemplate::kCannotSeal;
8677         break;
8678 
8679       case FROZEN:
8680         message = MessageTemplate::kCannotFreeze;
8681         break;
8682     }
8683     RETURN_FAILURE(isolate, should_throw, NewTypeError(message));
8684   }
8685 
8686   Handle<NumberDictionary> new_element_dictionary;
8687   if (!object->HasFixedTypedArrayElements() &&
8688       !object->HasDictionaryElements() &&
8689       !object->HasSlowStringWrapperElements()) {
8690     int length = object->IsJSArray()
8691                      ? Smi::ToInt(Handle<JSArray>::cast(object)->length())
8692                      : object->elements()->length();
8693     new_element_dictionary =
8694         length == 0 ? isolate->factory()->empty_slow_element_dictionary()
8695                     : object->GetElementsAccessor()->Normalize(object);
8696   }
8697 
8698   Handle<Symbol> transition_marker;
8699   if (attrs == NONE) {
8700     transition_marker = isolate->factory()->nonextensible_symbol();
8701   } else if (attrs == SEALED) {
8702     transition_marker = isolate->factory()->sealed_symbol();
8703   } else {
8704     DCHECK(attrs == FROZEN);
8705     transition_marker = isolate->factory()->frozen_symbol();
8706   }
8707 
8708   Handle<Map> old_map(object->map(), isolate);
8709   TransitionsAccessor transitions(isolate, old_map);
8710   Map* transition = transitions.SearchSpecial(*transition_marker);
8711   if (transition != nullptr) {
8712     Handle<Map> transition_map(transition, isolate);
8713     DCHECK(transition_map->has_dictionary_elements() ||
8714            transition_map->has_fixed_typed_array_elements() ||
8715            transition_map->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
8716     DCHECK(!transition_map->is_extensible());
8717     JSObject::MigrateToMap(object, transition_map);
8718   } else if (transitions.CanHaveMoreTransitions()) {
8719     // Create a new descriptor array with the appropriate property attributes
8720     Handle<Map> new_map = Map::CopyForPreventExtensions(
8721         isolate, old_map, attrs, transition_marker, "CopyForPreventExtensions");
8722     JSObject::MigrateToMap(object, new_map);
8723   } else {
8724     DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map());
8725     // Slow path: need to normalize properties for safety
8726     NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0,
8727                         "SlowPreventExtensions");
8728 
8729     // Create a new map, since other objects with this map may be extensible.
8730     // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
8731     Handle<Map> new_map = Map::Copy(isolate, handle(object->map(), isolate),
8732                                     "SlowCopyForPreventExtensions");
8733     new_map->set_is_extensible(false);
8734     if (!new_element_dictionary.is_null()) {
8735       ElementsKind new_kind =
8736           IsStringWrapperElementsKind(old_map->elements_kind())
8737               ? SLOW_STRING_WRAPPER_ELEMENTS
8738               : DICTIONARY_ELEMENTS;
8739       new_map->set_elements_kind(new_kind);
8740     }
8741     JSObject::MigrateToMap(object, new_map);
8742 
8743     if (attrs != NONE) {
8744       ReadOnlyRoots roots(isolate);
8745       if (object->IsJSGlobalObject()) {
8746         Handle<GlobalDictionary> dictionary(
8747             JSGlobalObject::cast(*object)->global_dictionary(), isolate);
8748         ApplyAttributesToDictionary(isolate, roots, dictionary, attrs);
8749       } else {
8750         Handle<NameDictionary> dictionary(object->property_dictionary(),
8751                                           isolate);
8752         ApplyAttributesToDictionary(isolate, roots, dictionary, attrs);
8753       }
8754     }
8755   }
8756 
8757   // Both seal and preventExtensions always go through without modifications to
8758   // typed array elements. Freeze works only if there are no actual elements.
8759   if (object->HasFixedTypedArrayElements()) {
8760     if (attrs == FROZEN &&
8761         JSArrayBufferView::cast(*object)->byte_length()->Number() > 0) {
8762       isolate->Throw(*isolate->factory()->NewTypeError(
8763           MessageTemplate::kCannotFreezeArrayBufferView));
8764       return Nothing<bool>();
8765     }
8766     return Just(true);
8767   }
8768 
8769   DCHECK(object->map()->has_dictionary_elements() ||
8770          object->map()->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
8771   if (!new_element_dictionary.is_null()) {
8772     object->set_elements(*new_element_dictionary);
8773   }
8774 
8775   if (object->elements() !=
8776       ReadOnlyRoots(isolate).empty_slow_element_dictionary()) {
8777     Handle<NumberDictionary> dictionary(object->element_dictionary(), isolate);
8778     // Make sure we never go back to the fast case
8779     object->RequireSlowElements(*dictionary);
8780     if (attrs != NONE) {
8781       ApplyAttributesToDictionary(isolate, ReadOnlyRoots(isolate), dictionary,
8782                                   attrs);
8783     }
8784   }
8785 
8786   return Just(true);
8787 }
8788 
8789 
FastPropertyAt(Handle<JSObject> object,Representation representation,FieldIndex index)8790 Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object,
8791                                         Representation representation,
8792                                         FieldIndex index) {
8793   Isolate* isolate = object->GetIsolate();
8794   if (object->IsUnboxedDoubleField(index)) {
8795     double value = object->RawFastDoublePropertyAt(index);
8796     return isolate->factory()->NewHeapNumber(value);
8797   }
8798   Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate);
8799   return Object::WrapForRead(isolate, raw_value, representation);
8800 }
8801 
8802 // static
ToPrimitive(Handle<JSReceiver> receiver,ToPrimitiveHint hint)8803 MaybeHandle<Object> JSReceiver::ToPrimitive(Handle<JSReceiver> receiver,
8804                                             ToPrimitiveHint hint) {
8805   Isolate* const isolate = receiver->GetIsolate();
8806   Handle<Object> exotic_to_prim;
8807   ASSIGN_RETURN_ON_EXCEPTION(
8808       isolate, exotic_to_prim,
8809       GetMethod(receiver, isolate->factory()->to_primitive_symbol()), Object);
8810   if (!exotic_to_prim->IsUndefined(isolate)) {
8811     Handle<Object> hint_string =
8812         isolate->factory()->ToPrimitiveHintString(hint);
8813     Handle<Object> result;
8814     ASSIGN_RETURN_ON_EXCEPTION(
8815         isolate, result,
8816         Execution::Call(isolate, exotic_to_prim, receiver, 1, &hint_string),
8817         Object);
8818     if (result->IsPrimitive()) return result;
8819     THROW_NEW_ERROR(isolate,
8820                     NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8821                     Object);
8822   }
8823   return OrdinaryToPrimitive(receiver, (hint == ToPrimitiveHint::kString)
8824                                            ? OrdinaryToPrimitiveHint::kString
8825                                            : OrdinaryToPrimitiveHint::kNumber);
8826 }
8827 
8828 
8829 // static
OrdinaryToPrimitive(Handle<JSReceiver> receiver,OrdinaryToPrimitiveHint hint)8830 MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive(
8831     Handle<JSReceiver> receiver, OrdinaryToPrimitiveHint hint) {
8832   Isolate* const isolate = receiver->GetIsolate();
8833   Handle<String> method_names[2];
8834   switch (hint) {
8835     case OrdinaryToPrimitiveHint::kNumber:
8836       method_names[0] = isolate->factory()->valueOf_string();
8837       method_names[1] = isolate->factory()->toString_string();
8838       break;
8839     case OrdinaryToPrimitiveHint::kString:
8840       method_names[0] = isolate->factory()->toString_string();
8841       method_names[1] = isolate->factory()->valueOf_string();
8842       break;
8843   }
8844   for (Handle<String> name : method_names) {
8845     Handle<Object> method;
8846     ASSIGN_RETURN_ON_EXCEPTION(isolate, method,
8847                                JSReceiver::GetProperty(isolate, receiver, name),
8848                                Object);
8849     if (method->IsCallable()) {
8850       Handle<Object> result;
8851       ASSIGN_RETURN_ON_EXCEPTION(
8852           isolate, result,
8853           Execution::Call(isolate, method, receiver, 0, nullptr), Object);
8854       if (result->IsPrimitive()) return result;
8855     }
8856   }
8857   THROW_NEW_ERROR(isolate,
8858                   NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8859                   Object);
8860 }
8861 
8862 
8863 // TODO(cbruni/jkummerow): Consider moving this into elements.cc.
HasEnumerableElements()8864 bool JSObject::HasEnumerableElements() {
8865   // TODO(cbruni): cleanup
8866   JSObject* object = this;
8867   switch (object->GetElementsKind()) {
8868     case PACKED_SMI_ELEMENTS:
8869     case PACKED_ELEMENTS:
8870     case PACKED_DOUBLE_ELEMENTS: {
8871       int length = object->IsJSArray()
8872                        ? Smi::ToInt(JSArray::cast(object)->length())
8873                        : object->elements()->length();
8874       return length > 0;
8875     }
8876     case HOLEY_SMI_ELEMENTS:
8877     case HOLEY_ELEMENTS: {
8878       FixedArray* elements = FixedArray::cast(object->elements());
8879       int length = object->IsJSArray()
8880                        ? Smi::ToInt(JSArray::cast(object)->length())
8881                        : elements->length();
8882       Isolate* isolate = GetIsolate();
8883       for (int i = 0; i < length; i++) {
8884         if (!elements->is_the_hole(isolate, i)) return true;
8885       }
8886       return false;
8887     }
8888     case HOLEY_DOUBLE_ELEMENTS: {
8889       int length = object->IsJSArray()
8890                        ? Smi::ToInt(JSArray::cast(object)->length())
8891                        : object->elements()->length();
8892       // Zero-length arrays would use the empty FixedArray...
8893       if (length == 0) return false;
8894       // ...so only cast to FixedDoubleArray otherwise.
8895       FixedDoubleArray* elements = FixedDoubleArray::cast(object->elements());
8896       for (int i = 0; i < length; i++) {
8897         if (!elements->is_the_hole(i)) return true;
8898       }
8899       return false;
8900     }
8901 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS:
8902 
8903       TYPED_ARRAYS(TYPED_ARRAY_CASE)
8904 #undef TYPED_ARRAY_CASE
8905       {
8906         int length = object->elements()->length();
8907         return length > 0;
8908       }
8909     case DICTIONARY_ELEMENTS: {
8910       NumberDictionary* elements = NumberDictionary::cast(object->elements());
8911       return elements->NumberOfEnumerableProperties() > 0;
8912     }
8913     case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
8914     case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
8915       // We're approximating non-empty arguments objects here.
8916       return true;
8917     case FAST_STRING_WRAPPER_ELEMENTS:
8918     case SLOW_STRING_WRAPPER_ELEMENTS:
8919       if (String::cast(JSValue::cast(object)->value())->length() > 0) {
8920         return true;
8921       }
8922       return object->elements()->length() > 0;
8923     case NO_ELEMENTS:
8924       return false;
8925   }
8926   UNREACHABLE();
8927 }
8928 
NumberOfEnumerableProperties() const8929 int Map::NumberOfEnumerableProperties() const {
8930   int result = 0;
8931   DescriptorArray* descs = instance_descriptors();
8932   int limit = NumberOfOwnDescriptors();
8933   for (int i = 0; i < limit; i++) {
8934     if ((descs->GetDetails(i).attributes() & ONLY_ENUMERABLE) == 0 &&
8935         !descs->GetKey(i)->FilterKey(ENUMERABLE_STRINGS)) {
8936       result++;
8937     }
8938   }
8939   return result;
8940 }
8941 
NextFreePropertyIndex() const8942 int Map::NextFreePropertyIndex() const {
8943   int free_index = 0;
8944   int number_of_own_descriptors = NumberOfOwnDescriptors();
8945   DescriptorArray* descs = instance_descriptors();
8946   for (int i = 0; i < number_of_own_descriptors; i++) {
8947     PropertyDetails details = descs->GetDetails(i);
8948     if (details.location() == kField) {
8949       int candidate = details.field_index() + details.field_width_in_words();
8950       if (candidate > free_index) free_index = candidate;
8951     }
8952   }
8953   return free_index;
8954 }
8955 
OnlyHasSimpleProperties() const8956 bool Map::OnlyHasSimpleProperties() const {
8957   // Wrapped string elements aren't explicitly stored in the elements backing
8958   // store, but are loaded indirectly from the underlying string.
8959   return !IsStringWrapperElementsKind(elements_kind()) &&
8960          !IsSpecialReceiverMap() && !has_hidden_prototype() &&
8961          !is_dictionary_map();
8962 }
8963 
FastGetOwnValuesOrEntries(Isolate * isolate,Handle<JSReceiver> receiver,bool get_entries,Handle<FixedArray> * result)8964 V8_WARN_UNUSED_RESULT Maybe<bool> FastGetOwnValuesOrEntries(
8965     Isolate* isolate, Handle<JSReceiver> receiver, bool get_entries,
8966     Handle<FixedArray>* result) {
8967   Handle<Map> map(JSReceiver::cast(*receiver)->map(), isolate);
8968 
8969   if (!map->IsJSObjectMap()) return Just(false);
8970   if (!map->OnlyHasSimpleProperties()) return Just(false);
8971 
8972   Handle<JSObject> object(JSObject::cast(*receiver), isolate);
8973 
8974   Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
8975   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
8976   int number_of_own_elements =
8977       object->GetElementsAccessor()->GetCapacity(*object, object->elements());
8978   Handle<FixedArray> values_or_entries = isolate->factory()->NewFixedArray(
8979       number_of_own_descriptors + number_of_own_elements);
8980   int count = 0;
8981 
8982   if (object->elements() != ReadOnlyRoots(isolate).empty_fixed_array()) {
8983     MAYBE_RETURN(object->GetElementsAccessor()->CollectValuesOrEntries(
8984                      isolate, object, values_or_entries, get_entries, &count,
8985                      ENUMERABLE_STRINGS),
8986                  Nothing<bool>());
8987   }
8988 
8989   bool stable = object->map() == *map;
8990 
8991   for (int index = 0; index < number_of_own_descriptors; index++) {
8992     Handle<Name> next_key(descriptors->GetKey(index), isolate);
8993     if (!next_key->IsString()) continue;
8994     Handle<Object> prop_value;
8995 
8996     // Directly decode from the descriptor array if |from| did not change shape.
8997     if (stable) {
8998       PropertyDetails details = descriptors->GetDetails(index);
8999       if (!details.IsEnumerable()) continue;
9000       if (details.kind() == kData) {
9001         if (details.location() == kDescriptor) {
9002           prop_value = handle(descriptors->GetStrongValue(index), isolate);
9003         } else {
9004           Representation representation = details.representation();
9005           FieldIndex field_index = FieldIndex::ForDescriptor(*map, index);
9006           prop_value =
9007               JSObject::FastPropertyAt(object, representation, field_index);
9008         }
9009       } else {
9010         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
9011             isolate, prop_value,
9012             JSReceiver::GetProperty(isolate, object, next_key),
9013             Nothing<bool>());
9014         stable = object->map() == *map;
9015       }
9016     } else {
9017       // If the map did change, do a slower lookup. We are still guaranteed that
9018       // the object has a simple shape, and that the key is a name.
9019       LookupIterator it(isolate, object, next_key,
9020                         LookupIterator::OWN_SKIP_INTERCEPTOR);
9021       if (!it.IsFound()) continue;
9022       DCHECK(it.state() == LookupIterator::DATA ||
9023              it.state() == LookupIterator::ACCESSOR);
9024       if (!it.IsEnumerable()) continue;
9025       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
9026           isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
9027     }
9028 
9029     if (get_entries) {
9030       prop_value = MakeEntryPair(isolate, next_key, prop_value);
9031     }
9032 
9033     values_or_entries->set(count, *prop_value);
9034     count++;
9035   }
9036 
9037   DCHECK_LE(count, values_or_entries->length());
9038   *result = FixedArray::ShrinkOrEmpty(isolate, values_or_entries, count);
9039   return Just(true);
9040 }
9041 
GetOwnValuesOrEntries(Isolate * isolate,Handle<JSReceiver> object,PropertyFilter filter,bool try_fast_path,bool get_entries)9042 MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate,
9043                                               Handle<JSReceiver> object,
9044                                               PropertyFilter filter,
9045                                               bool try_fast_path,
9046                                               bool get_entries) {
9047   Handle<FixedArray> values_or_entries;
9048   if (try_fast_path && filter == ENUMERABLE_STRINGS) {
9049     Maybe<bool> fast_values_or_entries = FastGetOwnValuesOrEntries(
9050         isolate, object, get_entries, &values_or_entries);
9051     if (fast_values_or_entries.IsNothing()) return MaybeHandle<FixedArray>();
9052     if (fast_values_or_entries.FromJust()) return values_or_entries;
9053   }
9054 
9055   PropertyFilter key_filter =
9056       static_cast<PropertyFilter>(filter & ~ONLY_ENUMERABLE);
9057 
9058   Handle<FixedArray> keys;
9059   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
9060       isolate, keys,
9061       KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, key_filter,
9062                               GetKeysConversion::kConvertToString),
9063       MaybeHandle<FixedArray>());
9064 
9065   values_or_entries = isolate->factory()->NewFixedArray(keys->length());
9066   int length = 0;
9067 
9068   for (int i = 0; i < keys->length(); ++i) {
9069     Handle<Name> key = Handle<Name>::cast(handle(keys->get(i), isolate));
9070 
9071     if (filter & ONLY_ENUMERABLE) {
9072       PropertyDescriptor descriptor;
9073       Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor(
9074           isolate, object, key, &descriptor);
9075       MAYBE_RETURN(did_get_descriptor, MaybeHandle<FixedArray>());
9076       if (!did_get_descriptor.FromJust() || !descriptor.enumerable()) continue;
9077     }
9078 
9079     Handle<Object> value;
9080     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
9081         isolate, value, JSReceiver::GetPropertyOrElement(isolate, object, key),
9082         MaybeHandle<FixedArray>());
9083 
9084     if (get_entries) {
9085       Handle<FixedArray> entry_storage =
9086           isolate->factory()->NewUninitializedFixedArray(2);
9087       entry_storage->set(0, *key);
9088       entry_storage->set(1, *value);
9089       value = isolate->factory()->NewJSArrayWithElements(entry_storage,
9090                                                          PACKED_ELEMENTS, 2);
9091     }
9092 
9093     values_or_entries->set(length, *value);
9094     length++;
9095   }
9096   DCHECK_LE(length, values_or_entries->length());
9097   return FixedArray::ShrinkOrEmpty(isolate, values_or_entries, length);
9098 }
9099 
GetOwnValues(Handle<JSReceiver> object,PropertyFilter filter,bool try_fast_path)9100 MaybeHandle<FixedArray> JSReceiver::GetOwnValues(Handle<JSReceiver> object,
9101                                                  PropertyFilter filter,
9102                                                  bool try_fast_path) {
9103   return GetOwnValuesOrEntries(object->GetIsolate(), object, filter,
9104                                try_fast_path, false);
9105 }
9106 
GetOwnEntries(Handle<JSReceiver> object,PropertyFilter filter,bool try_fast_path)9107 MaybeHandle<FixedArray> JSReceiver::GetOwnEntries(Handle<JSReceiver> object,
9108                                                   PropertyFilter filter,
9109                                                   bool try_fast_path) {
9110   return GetOwnValuesOrEntries(object->GetIsolate(), object, filter,
9111                                try_fast_path, true);
9112 }
9113 
GetOwnElementIndices(Isolate * isolate,Handle<JSReceiver> receiver,Handle<JSObject> object)9114 Handle<FixedArray> JSReceiver::GetOwnElementIndices(Isolate* isolate,
9115                                                     Handle<JSReceiver> receiver,
9116                                                     Handle<JSObject> object) {
9117   KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly,
9118                              ALL_PROPERTIES);
9119   accumulator.CollectOwnElementIndices(receiver, object);
9120   Handle<FixedArray> keys =
9121       accumulator.GetKeys(GetKeysConversion::kKeepNumbers);
9122   DCHECK(keys->ContainsSortedNumbers());
9123   return keys;
9124 }
9125 
DictionaryElementsInPrototypeChainOnly(Isolate * isolate)9126 bool Map::DictionaryElementsInPrototypeChainOnly(Isolate* isolate) {
9127   if (IsDictionaryElementsKind(elements_kind())) {
9128     return false;
9129   }
9130 
9131   for (PrototypeIterator iter(isolate, this); !iter.IsAtEnd(); iter.Advance()) {
9132     // Be conservative, don't walk into proxies.
9133     if (iter.GetCurrent()->IsJSProxy()) return true;
9134     // String wrappers have non-configurable, non-writable elements.
9135     if (iter.GetCurrent()->IsStringWrapper()) return true;
9136     JSObject* current = iter.GetCurrent<JSObject>();
9137 
9138     if (current->HasDictionaryElements() &&
9139         current->element_dictionary()->requires_slow_elements()) {
9140       return true;
9141     }
9142 
9143     if (current->HasSlowArgumentsElements()) {
9144       FixedArray* parameter_map = FixedArray::cast(current->elements());
9145       Object* arguments = parameter_map->get(1);
9146       if (NumberDictionary::cast(arguments)->requires_slow_elements()) {
9147         return true;
9148       }
9149     }
9150   }
9151 
9152   return false;
9153 }
9154 
9155 
DefineAccessor(Handle<JSObject> object,Handle<Name> name,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)9156 MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
9157                                              Handle<Name> name,
9158                                              Handle<Object> getter,
9159                                              Handle<Object> setter,
9160                                              PropertyAttributes attributes) {
9161   Isolate* isolate = object->GetIsolate();
9162 
9163   LookupIterator it = LookupIterator::PropertyOrElement(
9164       isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
9165   return DefineAccessor(&it, getter, setter, attributes);
9166 }
9167 
9168 
DefineAccessor(LookupIterator * it,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)9169 MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it,
9170                                              Handle<Object> getter,
9171                                              Handle<Object> setter,
9172                                              PropertyAttributes attributes) {
9173   Isolate* isolate = it->isolate();
9174 
9175   it->UpdateProtector();
9176 
9177   if (it->state() == LookupIterator::ACCESS_CHECK) {
9178     if (!it->HasAccess()) {
9179       isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
9180       RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
9181       return isolate->factory()->undefined_value();
9182     }
9183     it->Next();
9184   }
9185 
9186   Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
9187   // Ignore accessors on typed arrays.
9188   if (it->IsElement() && object->HasFixedTypedArrayElements()) {
9189     return it->factory()->undefined_value();
9190   }
9191 
9192   DCHECK(getter->IsCallable() || getter->IsUndefined(isolate) ||
9193          getter->IsNull(isolate) || getter->IsFunctionTemplateInfo());
9194   DCHECK(setter->IsCallable() || setter->IsUndefined(isolate) ||
9195          setter->IsNull(isolate) || setter->IsFunctionTemplateInfo());
9196   it->TransitionToAccessorProperty(getter, setter, attributes);
9197 
9198   return isolate->factory()->undefined_value();
9199 }
9200 
SetAccessor(Handle<JSObject> object,Handle<Name> name,Handle<AccessorInfo> info,PropertyAttributes attributes)9201 MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
9202                                           Handle<Name> name,
9203                                           Handle<AccessorInfo> info,
9204                                           PropertyAttributes attributes) {
9205   Isolate* isolate = object->GetIsolate();
9206 
9207   LookupIterator it = LookupIterator::PropertyOrElement(
9208       isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
9209 
9210   // Duplicate ACCESS_CHECK outside of GetPropertyAttributes for the case that
9211   // the FailedAccessCheckCallbackFunction doesn't throw an exception.
9212   //
9213   // TODO(verwaest): Force throw an exception if the callback doesn't, so we can
9214   // remove reliance on default return values.
9215   if (it.state() == LookupIterator::ACCESS_CHECK) {
9216     if (!it.HasAccess()) {
9217       isolate->ReportFailedAccessCheck(object);
9218       RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
9219       return it.factory()->undefined_value();
9220     }
9221     it.Next();
9222   }
9223 
9224   // Ignore accessors on typed arrays.
9225   if (it.IsElement() && object->HasFixedTypedArrayElements()) {
9226     return it.factory()->undefined_value();
9227   }
9228 
9229   CHECK(GetPropertyAttributes(&it).IsJust());
9230 
9231   // ES5 forbids turning a property into an accessor if it's not
9232   // configurable. See 8.6.1 (Table 5).
9233   if (it.IsFound() && !it.IsConfigurable()) {
9234     return it.factory()->undefined_value();
9235   }
9236 
9237   it.TransitionToAccessorPair(info, attributes);
9238 
9239   return object;
9240 }
9241 
SlowReverseLookup(Object * value)9242 Object* JSObject::SlowReverseLookup(Object* value) {
9243   if (HasFastProperties()) {
9244     int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
9245     DescriptorArray* descs = map()->instance_descriptors();
9246     bool value_is_number = value->IsNumber();
9247     for (int i = 0; i < number_of_own_descriptors; i++) {
9248       PropertyDetails details = descs->GetDetails(i);
9249       if (details.location() == kField) {
9250         DCHECK_EQ(kData, details.kind());
9251         FieldIndex field_index = FieldIndex::ForDescriptor(map(), i);
9252         if (IsUnboxedDoubleField(field_index)) {
9253           if (value_is_number) {
9254             double property = RawFastDoublePropertyAt(field_index);
9255             if (property == value->Number()) {
9256               return descs->GetKey(i);
9257             }
9258           }
9259         } else {
9260           Object* property = RawFastPropertyAt(field_index);
9261           if (field_index.is_double()) {
9262             DCHECK(property->IsMutableHeapNumber());
9263             if (value_is_number && property->Number() == value->Number()) {
9264               return descs->GetKey(i);
9265             }
9266           } else if (property == value) {
9267             return descs->GetKey(i);
9268           }
9269         }
9270       } else {
9271         DCHECK_EQ(kDescriptor, details.location());
9272         if (details.kind() == kData) {
9273           if (descs->GetStrongValue(i) == value) {
9274             return descs->GetKey(i);
9275           }
9276         }
9277       }
9278     }
9279     return GetReadOnlyRoots().undefined_value();
9280   } else if (IsJSGlobalObject()) {
9281     return JSGlobalObject::cast(this)->global_dictionary()->SlowReverseLookup(
9282         value);
9283   } else {
9284     return property_dictionary()->SlowReverseLookup(value);
9285   }
9286 }
9287 
RawCopy(Isolate * isolate,Handle<Map> map,int instance_size,int inobject_properties)9288 Handle<Map> Map::RawCopy(Isolate* isolate, Handle<Map> map, int instance_size,
9289                          int inobject_properties) {
9290   Handle<Map> result = isolate->factory()->NewMap(
9291       map->instance_type(), instance_size, TERMINAL_FAST_ELEMENTS_KIND,
9292       inobject_properties);
9293   Handle<Object> prototype(map->prototype(), isolate);
9294   Map::SetPrototype(isolate, result, prototype);
9295   result->set_constructor_or_backpointer(map->GetConstructor());
9296   result->set_bit_field(map->bit_field());
9297   result->set_bit_field2(map->bit_field2());
9298   int new_bit_field3 = map->bit_field3();
9299   new_bit_field3 = OwnsDescriptorsBit::update(new_bit_field3, true);
9300   new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0);
9301   new_bit_field3 = EnumLengthBits::update(new_bit_field3,
9302                                           kInvalidEnumCacheSentinel);
9303   new_bit_field3 = IsDeprecatedBit::update(new_bit_field3, false);
9304   if (!map->is_dictionary_map()) {
9305     new_bit_field3 = IsUnstableBit::update(new_bit_field3, false);
9306   }
9307   result->set_bit_field3(new_bit_field3);
9308   return result;
9309 }
9310 
Normalize(Isolate * isolate,Handle<Map> fast_map,PropertyNormalizationMode mode,const char * reason)9311 Handle<Map> Map::Normalize(Isolate* isolate, Handle<Map> fast_map,
9312                            PropertyNormalizationMode mode, const char* reason) {
9313   DCHECK(!fast_map->is_dictionary_map());
9314 
9315   Handle<Object> maybe_cache(isolate->native_context()->normalized_map_cache(),
9316                              isolate);
9317   bool use_cache =
9318       !fast_map->is_prototype_map() && !maybe_cache->IsUndefined(isolate);
9319   Handle<NormalizedMapCache> cache;
9320   if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache);
9321 
9322   Handle<Map> new_map;
9323   if (use_cache && cache->Get(fast_map, mode).ToHandle(&new_map)) {
9324 #ifdef VERIFY_HEAP
9325     if (FLAG_verify_heap) new_map->DictionaryMapVerify(isolate);
9326 #endif
9327 #ifdef ENABLE_SLOW_DCHECKS
9328     if (FLAG_enable_slow_asserts) {
9329       // The cached map should match newly created normalized map bit-by-bit,
9330       // except for the code cache, which can contain some ICs which can be
9331       // applied to the shared map, dependent code and weak cell cache.
9332       Handle<Map> fresh = Map::CopyNormalized(isolate, fast_map, mode);
9333 
9334       if (new_map->is_prototype_map()) {
9335         // For prototype maps, the PrototypeInfo is not copied.
9336         DCHECK_EQ(0, memcmp(reinterpret_cast<void*>(fresh->address()),
9337                             reinterpret_cast<void*>(new_map->address()),
9338                             kTransitionsOrPrototypeInfoOffset));
9339         DCHECK_EQ(fresh->raw_transitions(),
9340                   MaybeObject::FromObject(Smi::kZero));
9341         STATIC_ASSERT(kDescriptorsOffset ==
9342                       kTransitionsOrPrototypeInfoOffset + kPointerSize);
9343         DCHECK_EQ(0, memcmp(HeapObject::RawField(*fresh, kDescriptorsOffset),
9344                             HeapObject::RawField(*new_map, kDescriptorsOffset),
9345                             kDependentCodeOffset - kDescriptorsOffset));
9346       } else {
9347         DCHECK_EQ(0, memcmp(reinterpret_cast<void*>(fresh->address()),
9348                             reinterpret_cast<void*>(new_map->address()),
9349                             Map::kDependentCodeOffset));
9350       }
9351       STATIC_ASSERT(Map::kPrototypeValidityCellOffset ==
9352                     Map::kDependentCodeOffset + kPointerSize);
9353       int offset = Map::kPrototypeValidityCellOffset + kPointerSize;
9354       DCHECK_EQ(0, memcmp(reinterpret_cast<void*>(fresh->address() + offset),
9355                           reinterpret_cast<void*>(new_map->address() + offset),
9356                           Map::kSize - offset));
9357     }
9358 #endif
9359   } else {
9360     new_map = Map::CopyNormalized(isolate, fast_map, mode);
9361     if (use_cache) {
9362       cache->Set(fast_map, new_map);
9363       isolate->counters()->maps_normalized()->Increment();
9364     }
9365     if (FLAG_trace_maps) {
9366       LOG(isolate, MapEvent("Normalize", *fast_map, *new_map, reason));
9367     }
9368   }
9369   fast_map->NotifyLeafMapLayoutChange(isolate);
9370   return new_map;
9371 }
9372 
CopyNormalized(Isolate * isolate,Handle<Map> map,PropertyNormalizationMode mode)9373 Handle<Map> Map::CopyNormalized(Isolate* isolate, Handle<Map> map,
9374                                 PropertyNormalizationMode mode) {
9375   int new_instance_size = map->instance_size();
9376   if (mode == CLEAR_INOBJECT_PROPERTIES) {
9377     new_instance_size -= map->GetInObjectProperties() * kPointerSize;
9378   }
9379 
9380   Handle<Map> result = RawCopy(
9381       isolate, map, new_instance_size,
9382       mode == CLEAR_INOBJECT_PROPERTIES ? 0 : map->GetInObjectProperties());
9383   // Clear the unused_property_fields explicitly as this field should not
9384   // be accessed for normalized maps.
9385   result->SetInObjectUnusedPropertyFields(0);
9386   result->set_is_dictionary_map(true);
9387   result->set_is_migration_target(false);
9388   result->set_may_have_interesting_symbols(true);
9389   result->set_construction_counter(kNoSlackTracking);
9390 
9391 #ifdef VERIFY_HEAP
9392   if (FLAG_verify_heap) result->DictionaryMapVerify(isolate);
9393 #endif
9394 
9395   return result;
9396 }
9397 
9398 // Return an immutable prototype exotic object version of the input map.
9399 // Never even try to cache it in the transition tree, as it is intended
9400 // for the global object and its prototype chain, and excluding it saves
9401 // memory on the map transition tree.
9402 
9403 // static
TransitionToImmutableProto(Isolate * isolate,Handle<Map> map)9404 Handle<Map> Map::TransitionToImmutableProto(Isolate* isolate, Handle<Map> map) {
9405   Handle<Map> new_map = Map::Copy(isolate, map, "ImmutablePrototype");
9406   new_map->set_is_immutable_proto(true);
9407   return new_map;
9408 }
9409 
9410 namespace {
EnsureInitialMap(Isolate * isolate,Handle<Map> map)9411 void EnsureInitialMap(Isolate* isolate, Handle<Map> map) {
9412 #ifdef DEBUG
9413   // Strict function maps have Function as a constructor but the
9414   // Function's initial map is a sloppy function map. Same holds for
9415   // GeneratorFunction / AsyncFunction and its initial map.
9416   Object* constructor = map->GetConstructor();
9417   DCHECK(constructor->IsJSFunction());
9418   DCHECK(*map == JSFunction::cast(constructor)->initial_map() ||
9419          *map == *isolate->strict_function_map() ||
9420          *map == *isolate->strict_function_with_name_map() ||
9421          *map == *isolate->generator_function_map() ||
9422          *map == *isolate->generator_function_with_name_map() ||
9423          *map == *isolate->generator_function_with_home_object_map() ||
9424          *map == *isolate->generator_function_with_name_and_home_object_map() ||
9425          *map == *isolate->async_function_map() ||
9426          *map == *isolate->async_function_with_name_map() ||
9427          *map == *isolate->async_function_with_home_object_map() ||
9428          *map == *isolate->async_function_with_name_and_home_object_map());
9429 #endif
9430   // Initial maps must always own their descriptors and it's descriptor array
9431   // does not contain descriptors that do not belong to the map.
9432   DCHECK(map->owns_descriptors());
9433   DCHECK_EQ(map->NumberOfOwnDescriptors(),
9434             map->instance_descriptors()->number_of_descriptors());
9435 }
9436 }  // namespace
9437 
9438 // static
CopyInitialMapNormalized(Isolate * isolate,Handle<Map> map,PropertyNormalizationMode mode)9439 Handle<Map> Map::CopyInitialMapNormalized(Isolate* isolate, Handle<Map> map,
9440                                           PropertyNormalizationMode mode) {
9441   EnsureInitialMap(isolate, map);
9442   return CopyNormalized(isolate, map, mode);
9443 }
9444 
9445 // static
CopyInitialMap(Isolate * isolate,Handle<Map> map,int instance_size,int inobject_properties,int unused_property_fields)9446 Handle<Map> Map::CopyInitialMap(Isolate* isolate, Handle<Map> map,
9447                                 int instance_size, int inobject_properties,
9448                                 int unused_property_fields) {
9449   EnsureInitialMap(isolate, map);
9450   Handle<Map> result =
9451       RawCopy(isolate, map, instance_size, inobject_properties);
9452 
9453   // Please note instance_type and instance_size are set when allocated.
9454   result->SetInObjectUnusedPropertyFields(unused_property_fields);
9455 
9456   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9457   if (number_of_own_descriptors > 0) {
9458     // The copy will use the same descriptors array.
9459     result->UpdateDescriptors(map->instance_descriptors(),
9460                               map->GetLayoutDescriptor());
9461     result->SetNumberOfOwnDescriptors(number_of_own_descriptors);
9462 
9463     DCHECK_EQ(result->NumberOfFields(),
9464               result->GetInObjectProperties() - result->UnusedPropertyFields());
9465   }
9466 
9467   return result;
9468 }
9469 
CopyDropDescriptors(Isolate * isolate,Handle<Map> map)9470 Handle<Map> Map::CopyDropDescriptors(Isolate* isolate, Handle<Map> map) {
9471   Handle<Map> result =
9472       RawCopy(isolate, map, map->instance_size(),
9473               map->IsJSObjectMap() ? map->GetInObjectProperties() : 0);
9474 
9475   // Please note instance_type and instance_size are set when allocated.
9476   if (map->IsJSObjectMap()) {
9477     result->CopyUnusedPropertyFields(*map);
9478   }
9479   map->NotifyLeafMapLayoutChange(isolate);
9480   return result;
9481 }
9482 
ShareDescriptor(Isolate * isolate,Handle<Map> map,Handle<DescriptorArray> descriptors,Descriptor * descriptor)9483 Handle<Map> Map::ShareDescriptor(Isolate* isolate, Handle<Map> map,
9484                                  Handle<DescriptorArray> descriptors,
9485                                  Descriptor* descriptor) {
9486   // Sanity check. This path is only to be taken if the map owns its descriptor
9487   // array, implying that its NumberOfOwnDescriptors equals the number of
9488   // descriptors in the descriptor array.
9489   DCHECK_EQ(map->NumberOfOwnDescriptors(),
9490             map->instance_descriptors()->number_of_descriptors());
9491 
9492   Handle<Map> result = CopyDropDescriptors(isolate, map);
9493   Handle<Name> name = descriptor->GetKey();
9494 
9495   // Properly mark the {result} if the {name} is an "interesting symbol".
9496   if (name->IsInterestingSymbol()) {
9497     result->set_may_have_interesting_symbols(true);
9498   }
9499 
9500   // Ensure there's space for the new descriptor in the shared descriptor array.
9501   if (descriptors->NumberOfSlackDescriptors() == 0) {
9502     int old_size = descriptors->number_of_descriptors();
9503     if (old_size == 0) {
9504       descriptors = DescriptorArray::Allocate(isolate, 0, 1);
9505     } else {
9506       int slack = SlackForArraySize(old_size, kMaxNumberOfDescriptors);
9507       EnsureDescriptorSlack(isolate, map, slack);
9508       descriptors = handle(map->instance_descriptors(), isolate);
9509     }
9510   }
9511 
9512   Handle<LayoutDescriptor> layout_descriptor =
9513       FLAG_unbox_double_fields
9514           ? LayoutDescriptor::ShareAppend(isolate, map,
9515                                           descriptor->GetDetails())
9516           : handle(LayoutDescriptor::FastPointerLayout(), isolate);
9517 
9518   {
9519     DisallowHeapAllocation no_gc;
9520     descriptors->Append(descriptor);
9521     result->InitializeDescriptors(*descriptors, *layout_descriptor);
9522   }
9523 
9524   DCHECK(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1);
9525   ConnectTransition(isolate, map, result, name, SIMPLE_PROPERTY_TRANSITION);
9526 
9527   return result;
9528 }
9529 
ConnectTransition(Isolate * isolate,Handle<Map> parent,Handle<Map> child,Handle<Name> name,SimpleTransitionFlag flag)9530 void Map::ConnectTransition(Isolate* isolate, Handle<Map> parent,
9531                             Handle<Map> child, Handle<Name> name,
9532                             SimpleTransitionFlag flag) {
9533   DCHECK_IMPLIES(name->IsInterestingSymbol(),
9534                  child->may_have_interesting_symbols());
9535   DCHECK_IMPLIES(parent->may_have_interesting_symbols(),
9536                  child->may_have_interesting_symbols());
9537   // Do not track transitions during bootstrap except for element transitions.
9538   if (isolate->bootstrapper()->IsActive() &&
9539       !name.is_identical_to(isolate->factory()->elements_transition_symbol())) {
9540     if (FLAG_trace_maps) {
9541       LOG(isolate,
9542           MapEvent("Transition", *parent, *child,
9543                    child->is_prototype_map() ? "prototype" : "", *name));
9544     }
9545     return;
9546   }
9547   if (!parent->GetBackPointer()->IsUndefined(isolate)) {
9548     parent->set_owns_descriptors(false);
9549   } else {
9550     // |parent| is initial map and it must keep the ownership, there must be no
9551     // descriptors in the descriptors array that do not belong to the map.
9552     DCHECK(parent->owns_descriptors());
9553     DCHECK_EQ(parent->NumberOfOwnDescriptors(),
9554               parent->instance_descriptors()->number_of_descriptors());
9555   }
9556   if (parent->is_prototype_map()) {
9557     DCHECK(child->is_prototype_map());
9558     if (FLAG_trace_maps) {
9559       LOG(isolate, MapEvent("Transition", *parent, *child, "prototype", *name));
9560     }
9561   } else {
9562     TransitionsAccessor(isolate, parent).Insert(name, child, flag);
9563     if (FLAG_trace_maps) {
9564       LOG(isolate, MapEvent("Transition", *parent, *child, "", *name));
9565     }
9566   }
9567 }
9568 
CopyReplaceDescriptors(Isolate * isolate,Handle<Map> map,Handle<DescriptorArray> descriptors,Handle<LayoutDescriptor> layout_descriptor,TransitionFlag flag,MaybeHandle<Name> maybe_name,const char * reason,SimpleTransitionFlag simple_flag)9569 Handle<Map> Map::CopyReplaceDescriptors(
9570     Isolate* isolate, Handle<Map> map, Handle<DescriptorArray> descriptors,
9571     Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag,
9572     MaybeHandle<Name> maybe_name, const char* reason,
9573     SimpleTransitionFlag simple_flag) {
9574   DCHECK(descriptors->IsSortedNoDuplicates());
9575 
9576   Handle<Map> result = CopyDropDescriptors(isolate, map);
9577 
9578   // Properly mark the {result} if the {name} is an "interesting symbol".
9579   Handle<Name> name;
9580   if (maybe_name.ToHandle(&name) && name->IsInterestingSymbol()) {
9581     result->set_may_have_interesting_symbols(true);
9582   }
9583 
9584   if (!map->is_prototype_map()) {
9585     if (flag == INSERT_TRANSITION &&
9586         TransitionsAccessor(isolate, map).CanHaveMoreTransitions()) {
9587       result->InitializeDescriptors(*descriptors, *layout_descriptor);
9588 
9589       DCHECK(!maybe_name.is_null());
9590       ConnectTransition(isolate, map, result, name, simple_flag);
9591     } else {
9592       descriptors->GeneralizeAllFields();
9593       result->InitializeDescriptors(*descriptors,
9594                                     LayoutDescriptor::FastPointerLayout());
9595     }
9596   } else {
9597     result->InitializeDescriptors(*descriptors, *layout_descriptor);
9598   }
9599   if (FLAG_trace_maps &&
9600       // Mirror conditions above that did not call ConnectTransition().
9601       (map->is_prototype_map() ||
9602        !(flag == INSERT_TRANSITION &&
9603          TransitionsAccessor(isolate, map).CanHaveMoreTransitions()))) {
9604     LOG(isolate, MapEvent("ReplaceDescriptors", *map, *result, reason,
9605                           maybe_name.is_null() ? nullptr : *name));
9606   }
9607   return result;
9608 }
9609 
9610 
9611 // Creates transition tree starting from |split_map| and adding all descriptors
9612 // starting from descriptor with index |split_map|.NumberOfOwnDescriptors().
9613 // The way how it is done is tricky because of GC and special descriptors
9614 // marking logic.
AddMissingTransitions(Isolate * isolate,Handle<Map> split_map,Handle<DescriptorArray> descriptors,Handle<LayoutDescriptor> full_layout_descriptor)9615 Handle<Map> Map::AddMissingTransitions(
9616     Isolate* isolate, Handle<Map> split_map,
9617     Handle<DescriptorArray> descriptors,
9618     Handle<LayoutDescriptor> full_layout_descriptor) {
9619   DCHECK(descriptors->IsSortedNoDuplicates());
9620   int split_nof = split_map->NumberOfOwnDescriptors();
9621   int nof_descriptors = descriptors->number_of_descriptors();
9622   DCHECK_LT(split_nof, nof_descriptors);
9623 
9624   // Start with creating last map which will own full descriptors array.
9625   // This is necessary to guarantee that GC will mark the whole descriptor
9626   // array if any of the allocations happening below fail.
9627   // Number of unused properties is temporarily incorrect and the layout
9628   // descriptor could unnecessarily be in slow mode but we will fix after
9629   // all the other intermediate maps are created.
9630   // Also the last map might have interesting symbols, we temporarily set
9631   // the flag and clear it right before the descriptors are installed. This
9632   // makes heap verification happy and ensures the flag ends up accurate.
9633   Handle<Map> last_map = CopyDropDescriptors(isolate, split_map);
9634   last_map->InitializeDescriptors(*descriptors, *full_layout_descriptor);
9635   last_map->SetInObjectUnusedPropertyFields(0);
9636   last_map->set_may_have_interesting_symbols(true);
9637 
9638   // During creation of intermediate maps we violate descriptors sharing
9639   // invariant since the last map is not yet connected to the transition tree
9640   // we create here. But it is safe because GC never trims map's descriptors
9641   // if there are no dead transitions from that map and this is exactly the
9642   // case for all the intermediate maps we create here.
9643   Handle<Map> map = split_map;
9644   for (int i = split_nof; i < nof_descriptors - 1; ++i) {
9645     Handle<Map> new_map = CopyDropDescriptors(isolate, map);
9646     InstallDescriptors(isolate, map, new_map, i, descriptors,
9647                        full_layout_descriptor);
9648     map = new_map;
9649   }
9650   map->NotifyLeafMapLayoutChange(isolate);
9651   last_map->set_may_have_interesting_symbols(false);
9652   InstallDescriptors(isolate, map, last_map, nof_descriptors - 1, descriptors,
9653                      full_layout_descriptor);
9654   return last_map;
9655 }
9656 
9657 
9658 // Since this method is used to rewrite an existing transition tree, it can
9659 // always insert transitions without checking.
InstallDescriptors(Isolate * isolate,Handle<Map> parent,Handle<Map> child,int new_descriptor,Handle<DescriptorArray> descriptors,Handle<LayoutDescriptor> full_layout_descriptor)9660 void Map::InstallDescriptors(Isolate* isolate, Handle<Map> parent,
9661                              Handle<Map> child, int new_descriptor,
9662                              Handle<DescriptorArray> descriptors,
9663                              Handle<LayoutDescriptor> full_layout_descriptor) {
9664   DCHECK(descriptors->IsSortedNoDuplicates());
9665 
9666   child->set_instance_descriptors(*descriptors);
9667   child->SetNumberOfOwnDescriptors(new_descriptor + 1);
9668   child->CopyUnusedPropertyFields(*parent);
9669   PropertyDetails details = descriptors->GetDetails(new_descriptor);
9670   if (details.location() == kField) {
9671     child->AccountAddedPropertyField();
9672   }
9673 
9674   if (FLAG_unbox_double_fields) {
9675     Handle<LayoutDescriptor> layout_descriptor =
9676         LayoutDescriptor::AppendIfFastOrUseFull(isolate, parent, details,
9677                                                 full_layout_descriptor);
9678     child->set_layout_descriptor(*layout_descriptor);
9679 #ifdef VERIFY_HEAP
9680     // TODO(ishell): remove these checks from VERIFY_HEAP mode.
9681     if (FLAG_verify_heap) {
9682       CHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
9683     }
9684 #else
9685     SLOW_DCHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
9686 #endif
9687     child->set_visitor_id(Map::GetVisitorId(*child));
9688   }
9689 
9690   Handle<Name> name = handle(descriptors->GetKey(new_descriptor), isolate);
9691   if (parent->may_have_interesting_symbols() || name->IsInterestingSymbol()) {
9692     child->set_may_have_interesting_symbols(true);
9693   }
9694   ConnectTransition(isolate, parent, child, name, SIMPLE_PROPERTY_TRANSITION);
9695 }
9696 
CopyAsElementsKind(Isolate * isolate,Handle<Map> map,ElementsKind kind,TransitionFlag flag)9697 Handle<Map> Map::CopyAsElementsKind(Isolate* isolate, Handle<Map> map,
9698                                     ElementsKind kind, TransitionFlag flag) {
9699   // Only certain objects are allowed to have non-terminal fast transitional
9700   // elements kinds.
9701   DCHECK(map->IsJSObjectMap());
9702   DCHECK_IMPLIES(
9703       !map->CanHaveFastTransitionableElementsKind(),
9704       IsDictionaryElementsKind(kind) || IsTerminalElementsKind(kind));
9705 
9706   Map* maybe_elements_transition_map = nullptr;
9707   if (flag == INSERT_TRANSITION) {
9708     // Ensure we are requested to add elements kind transition "near the root".
9709     DCHECK_EQ(map->FindRootMap(isolate)->NumberOfOwnDescriptors(),
9710               map->NumberOfOwnDescriptors());
9711 
9712     maybe_elements_transition_map = map->ElementsTransitionMap();
9713     DCHECK(maybe_elements_transition_map == nullptr ||
9714            (maybe_elements_transition_map->elements_kind() ==
9715                 DICTIONARY_ELEMENTS &&
9716             kind == DICTIONARY_ELEMENTS));
9717     DCHECK(!IsFastElementsKind(kind) ||
9718            IsMoreGeneralElementsKindTransition(map->elements_kind(), kind));
9719     DCHECK(kind != map->elements_kind());
9720   }
9721 
9722   bool insert_transition =
9723       flag == INSERT_TRANSITION &&
9724       TransitionsAccessor(isolate, map).CanHaveMoreTransitions() &&
9725       maybe_elements_transition_map == nullptr;
9726 
9727   if (insert_transition) {
9728     Handle<Map> new_map = CopyForTransition(isolate, map, "CopyAsElementsKind");
9729     new_map->set_elements_kind(kind);
9730 
9731     Handle<Name> name = isolate->factory()->elements_transition_symbol();
9732     ConnectTransition(isolate, map, new_map, name, SPECIAL_TRANSITION);
9733     return new_map;
9734   }
9735 
9736   // Create a new free-floating map only if we are not allowed to store it.
9737   Handle<Map> new_map = Copy(isolate, map, "CopyAsElementsKind");
9738   new_map->set_elements_kind(kind);
9739   return new_map;
9740 }
9741 
AsLanguageMode(Isolate * isolate,Handle<Map> initial_map,Handle<SharedFunctionInfo> shared_info)9742 Handle<Map> Map::AsLanguageMode(Isolate* isolate, Handle<Map> initial_map,
9743                                 Handle<SharedFunctionInfo> shared_info) {
9744   DCHECK_EQ(JS_FUNCTION_TYPE, initial_map->instance_type());
9745   // Initial map for sloppy mode function is stored in the function
9746   // constructor. Initial maps for strict mode are cached as special transitions
9747   // using |strict_function_transition_symbol| as a key.
9748   if (is_sloppy(shared_info->language_mode())) return initial_map;
9749 
9750   Handle<Map> function_map(Map::cast(isolate->native_context()->get(
9751                                shared_info->function_map_index())),
9752                            isolate);
9753 
9754   STATIC_ASSERT(LanguageModeSize == 2);
9755   DCHECK_EQ(LanguageMode::kStrict, shared_info->language_mode());
9756   Handle<Symbol> transition_symbol =
9757       isolate->factory()->strict_function_transition_symbol();
9758   Map* maybe_transition = TransitionsAccessor(isolate, initial_map)
9759                               .SearchSpecial(*transition_symbol);
9760   if (maybe_transition != nullptr) {
9761     return handle(maybe_transition, isolate);
9762   }
9763   initial_map->NotifyLeafMapLayoutChange(isolate);
9764 
9765   // Create new map taking descriptors from the |function_map| and all
9766   // the other details from the |initial_map|.
9767   Handle<Map> map =
9768       Map::CopyInitialMap(isolate, function_map, initial_map->instance_size(),
9769                           initial_map->GetInObjectProperties(),
9770                           initial_map->UnusedPropertyFields());
9771   map->SetConstructor(initial_map->GetConstructor());
9772   map->set_prototype(initial_map->prototype());
9773   map->set_construction_counter(initial_map->construction_counter());
9774 
9775   if (TransitionsAccessor(isolate, initial_map).CanHaveMoreTransitions()) {
9776     Map::ConnectTransition(isolate, initial_map, map, transition_symbol,
9777                            SPECIAL_TRANSITION);
9778   }
9779   return map;
9780 }
9781 
CopyForTransition(Isolate * isolate,Handle<Map> map,const char * reason)9782 Handle<Map> Map::CopyForTransition(Isolate* isolate, Handle<Map> map,
9783                                    const char* reason) {
9784   DCHECK(!map->is_prototype_map());
9785   Handle<Map> new_map = CopyDropDescriptors(isolate, map);
9786 
9787   if (map->owns_descriptors()) {
9788     // In case the map owned its own descriptors, share the descriptors and
9789     // transfer ownership to the new map.
9790     // The properties did not change, so reuse descriptors.
9791     new_map->InitializeDescriptors(map->instance_descriptors(),
9792                                    map->GetLayoutDescriptor());
9793   } else {
9794     // In case the map did not own its own descriptors, a split is forced by
9795     // copying the map; creating a new descriptor array cell.
9796     Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
9797     int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9798     Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
9799         isolate, descriptors, number_of_own_descriptors);
9800     Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9801                                                    isolate);
9802     new_map->InitializeDescriptors(*new_descriptors, *new_layout_descriptor);
9803   }
9804 
9805   if (FLAG_trace_maps) {
9806     LOG(isolate, MapEvent("CopyForTransition", *map, *new_map, reason));
9807   }
9808   return new_map;
9809 }
9810 
Copy(Isolate * isolate,Handle<Map> map,const char * reason)9811 Handle<Map> Map::Copy(Isolate* isolate, Handle<Map> map, const char* reason) {
9812   Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
9813   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9814   Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
9815       isolate, descriptors, number_of_own_descriptors);
9816   Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9817                                                  isolate);
9818   return CopyReplaceDescriptors(
9819       isolate, map, new_descriptors, new_layout_descriptor, OMIT_TRANSITION,
9820       MaybeHandle<Name>(), reason, SPECIAL_TRANSITION);
9821 }
9822 
9823 
Create(Isolate * isolate,int inobject_properties)9824 Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) {
9825   Handle<Map> copy =
9826       Copy(isolate, handle(isolate->object_function()->initial_map(), isolate),
9827            "MapCreate");
9828 
9829   // Check that we do not overflow the instance size when adding the extra
9830   // inobject properties. If the instance size overflows, we allocate as many
9831   // properties as we can as inobject properties.
9832   if (inobject_properties > JSObject::kMaxInObjectProperties) {
9833     inobject_properties = JSObject::kMaxInObjectProperties;
9834   }
9835 
9836   int new_instance_size =
9837       JSObject::kHeaderSize + kPointerSize * inobject_properties;
9838 
9839   // Adjust the map with the extra inobject properties.
9840   copy->set_instance_size(new_instance_size);
9841   copy->SetInObjectPropertiesStartInWords(JSObject::kHeaderSize / kPointerSize);
9842   DCHECK_EQ(copy->GetInObjectProperties(), inobject_properties);
9843   copy->SetInObjectUnusedPropertyFields(inobject_properties);
9844   copy->set_visitor_id(Map::GetVisitorId(*copy));
9845   return copy;
9846 }
9847 
CopyForPreventExtensions(Isolate * isolate,Handle<Map> map,PropertyAttributes attrs_to_add,Handle<Symbol> transition_marker,const char * reason)9848 Handle<Map> Map::CopyForPreventExtensions(Isolate* isolate, Handle<Map> map,
9849                                           PropertyAttributes attrs_to_add,
9850                                           Handle<Symbol> transition_marker,
9851                                           const char* reason) {
9852   int num_descriptors = map->NumberOfOwnDescriptors();
9853   Handle<DescriptorArray> new_desc = DescriptorArray::CopyUpToAddAttributes(
9854       isolate, handle(map->instance_descriptors(), isolate), num_descriptors,
9855       attrs_to_add);
9856   Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9857                                                  isolate);
9858   Handle<Map> new_map = CopyReplaceDescriptors(
9859       isolate, map, new_desc, new_layout_descriptor, INSERT_TRANSITION,
9860       transition_marker, reason, SPECIAL_TRANSITION);
9861   new_map->set_is_extensible(false);
9862   if (!IsFixedTypedArrayElementsKind(map->elements_kind())) {
9863     ElementsKind new_kind = IsStringWrapperElementsKind(map->elements_kind())
9864                                 ? SLOW_STRING_WRAPPER_ELEMENTS
9865                                 : DICTIONARY_ELEMENTS;
9866     new_map->set_elements_kind(new_kind);
9867   }
9868   return new_map;
9869 }
9870 
9871 namespace {
9872 
CanHoldValue(DescriptorArray * descriptors,int descriptor,PropertyConstness constness,Object * value)9873 bool CanHoldValue(DescriptorArray* descriptors, int descriptor,
9874                   PropertyConstness constness, Object* value) {
9875   PropertyDetails details = descriptors->GetDetails(descriptor);
9876   if (details.location() == kField) {
9877     if (details.kind() == kData) {
9878       return IsGeneralizableTo(constness, details.constness()) &&
9879              value->FitsRepresentation(details.representation()) &&
9880              descriptors->GetFieldType(descriptor)->NowContains(value);
9881     } else {
9882       DCHECK_EQ(kAccessor, details.kind());
9883       return false;
9884     }
9885 
9886   } else {
9887     DCHECK_EQ(kDescriptor, details.location());
9888     DCHECK_EQ(PropertyConstness::kConst, details.constness());
9889     if (details.kind() == kData) {
9890       DCHECK(!FLAG_track_constant_fields);
9891       DCHECK(descriptors->GetStrongValue(descriptor) != value ||
9892              value->FitsRepresentation(details.representation()));
9893       return descriptors->GetStrongValue(descriptor) == value;
9894     } else {
9895       DCHECK_EQ(kAccessor, details.kind());
9896       return false;
9897     }
9898   }
9899   UNREACHABLE();
9900 }
9901 
UpdateDescriptorForValue(Isolate * isolate,Handle<Map> map,int descriptor,PropertyConstness constness,Handle<Object> value)9902 Handle<Map> UpdateDescriptorForValue(Isolate* isolate, Handle<Map> map,
9903                                      int descriptor,
9904                                      PropertyConstness constness,
9905                                      Handle<Object> value) {
9906   if (CanHoldValue(map->instance_descriptors(), descriptor, constness,
9907                    *value)) {
9908     return map;
9909   }
9910 
9911   PropertyAttributes attributes =
9912       map->instance_descriptors()->GetDetails(descriptor).attributes();
9913   Representation representation = value->OptimalRepresentation();
9914   Handle<FieldType> type = value->OptimalType(isolate, representation);
9915 
9916   MapUpdater mu(isolate, map);
9917   return mu.ReconfigureToDataField(descriptor, attributes, constness,
9918                                    representation, type);
9919 }
9920 
9921 }  // namespace
9922 
9923 // static
PrepareForDataProperty(Isolate * isolate,Handle<Map> map,int descriptor,PropertyConstness constness,Handle<Object> value)9924 Handle<Map> Map::PrepareForDataProperty(Isolate* isolate, Handle<Map> map,
9925                                         int descriptor,
9926                                         PropertyConstness constness,
9927                                         Handle<Object> value) {
9928   // Dictionaries can store any property value.
9929   DCHECK(!map->is_dictionary_map());
9930   // Update to the newest map before storing the property.
9931   return UpdateDescriptorForValue(isolate, Update(isolate, map), descriptor,
9932                                   constness, value);
9933 }
9934 
TransitionToDataProperty(Isolate * isolate,Handle<Map> map,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes,PropertyConstness constness,StoreFromKeyed store_mode)9935 Handle<Map> Map::TransitionToDataProperty(Isolate* isolate, Handle<Map> map,
9936                                           Handle<Name> name,
9937                                           Handle<Object> value,
9938                                           PropertyAttributes attributes,
9939                                           PropertyConstness constness,
9940                                           StoreFromKeyed store_mode) {
9941   RuntimeCallTimerScope stats_scope(
9942       isolate, *map,
9943       map->is_prototype_map()
9944           ? RuntimeCallCounterId::kPrototypeMap_TransitionToDataProperty
9945           : RuntimeCallCounterId::kMap_TransitionToDataProperty);
9946 
9947   DCHECK(name->IsUniqueName());
9948   DCHECK(!map->is_dictionary_map());
9949 
9950   // Migrate to the newest map before storing the property.
9951   map = Update(isolate, map);
9952 
9953   Map* maybe_transition = TransitionsAccessor(isolate, map)
9954                               .SearchTransition(*name, kData, attributes);
9955   if (maybe_transition != nullptr) {
9956     Handle<Map> transition(maybe_transition, isolate);
9957     int descriptor = transition->LastAdded();
9958 
9959     DCHECK_EQ(attributes, transition->instance_descriptors()
9960                               ->GetDetails(descriptor)
9961                               .attributes());
9962 
9963     return UpdateDescriptorForValue(isolate, transition, descriptor, constness,
9964                                     value);
9965   }
9966 
9967   TransitionFlag flag = INSERT_TRANSITION;
9968   MaybeHandle<Map> maybe_map;
9969   if (!map->TooManyFastProperties(store_mode)) {
9970     if (!FLAG_track_constant_fields && value->IsJSFunction()) {
9971       maybe_map =
9972           Map::CopyWithConstant(isolate, map, name, value, attributes, flag);
9973     } else {
9974       Representation representation = value->OptimalRepresentation();
9975       Handle<FieldType> type = value->OptimalType(isolate, representation);
9976       maybe_map = Map::CopyWithField(isolate, map, name, type, attributes,
9977                                      constness, representation, flag);
9978     }
9979   }
9980 
9981   Handle<Map> result;
9982   if (!maybe_map.ToHandle(&result)) {
9983     const char* reason = "TooManyFastProperties";
9984 #if V8_TRACE_MAPS
9985     std::unique_ptr<ScopedVector<char>> buffer;
9986     if (FLAG_trace_maps) {
9987       ScopedVector<char> name_buffer(100);
9988       name->NameShortPrint(name_buffer);
9989       buffer.reset(new ScopedVector<char>(128));
9990       SNPrintF(*buffer, "TooManyFastProperties %s", name_buffer.start());
9991       reason = buffer->start();
9992     }
9993 #endif
9994     Handle<Object> maybe_constructor(map->GetConstructor(), isolate);
9995     if (FLAG_feedback_normalization && map->new_target_is_base() &&
9996         maybe_constructor->IsJSFunction() &&
9997         !JSFunction::cast(*maybe_constructor)->shared()->native()) {
9998       Handle<JSFunction> constructor =
9999           Handle<JSFunction>::cast(maybe_constructor);
10000       DCHECK_NE(*constructor,
10001                 constructor->context()->native_context()->object_function());
10002       Handle<Map> initial_map(constructor->initial_map(), isolate);
10003       result = Map::Normalize(isolate, initial_map, CLEAR_INOBJECT_PROPERTIES,
10004                               reason);
10005       initial_map->DeprecateTransitionTree(isolate);
10006       Handle<Object> prototype(result->prototype(), isolate);
10007       JSFunction::SetInitialMap(constructor, result, prototype);
10008 
10009       // Deoptimize all code that embeds the previous initial map.
10010       initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
10011           isolate, DependentCode::kInitialMapChangedGroup);
10012       if (!result->EquivalentToForNormalization(*map,
10013                                                 CLEAR_INOBJECT_PROPERTIES)) {
10014         result =
10015             Map::Normalize(isolate, map, CLEAR_INOBJECT_PROPERTIES, reason);
10016       }
10017     } else {
10018       result = Map::Normalize(isolate, map, CLEAR_INOBJECT_PROPERTIES, reason);
10019     }
10020   }
10021 
10022   return result;
10023 }
10024 
ReconfigureExistingProperty(Isolate * isolate,Handle<Map> map,int descriptor,PropertyKind kind,PropertyAttributes attributes)10025 Handle<Map> Map::ReconfigureExistingProperty(Isolate* isolate, Handle<Map> map,
10026                                              int descriptor, PropertyKind kind,
10027                                              PropertyAttributes attributes) {
10028   // Dictionaries have to be reconfigured in-place.
10029   DCHECK(!map->is_dictionary_map());
10030 
10031   if (!map->GetBackPointer()->IsMap()) {
10032     // There is no benefit from reconstructing transition tree for maps without
10033     // back pointers.
10034     return CopyGeneralizeAllFields(isolate, map, map->elements_kind(),
10035                                    descriptor, kind, attributes,
10036                                    "GenAll_AttributesMismatchProtoMap");
10037   }
10038 
10039   if (FLAG_trace_generalization) {
10040     map->PrintReconfiguration(isolate, stdout, descriptor, kind, attributes);
10041   }
10042 
10043   MapUpdater mu(isolate, map);
10044   DCHECK_EQ(kData, kind);  // Only kData case is supported so far.
10045   Handle<Map> new_map = mu.ReconfigureToDataField(
10046       descriptor, attributes, kDefaultFieldConstness, Representation::None(),
10047       FieldType::None(isolate));
10048   return new_map;
10049 }
10050 
TransitionToAccessorProperty(Isolate * isolate,Handle<Map> map,Handle<Name> name,int descriptor,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)10051 Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map,
10052                                               Handle<Name> name, int descriptor,
10053                                               Handle<Object> getter,
10054                                               Handle<Object> setter,
10055                                               PropertyAttributes attributes) {
10056   RuntimeCallTimerScope stats_scope(
10057       isolate,
10058       map->is_prototype_map()
10059           ? RuntimeCallCounterId::kPrototypeMap_TransitionToAccessorProperty
10060           : RuntimeCallCounterId::kMap_TransitionToAccessorProperty);
10061 
10062   // At least one of the accessors needs to be a new value.
10063   DCHECK(!getter->IsNull(isolate) || !setter->IsNull(isolate));
10064   DCHECK(name->IsUniqueName());
10065 
10066   // Dictionary maps can always have additional data properties.
10067   if (map->is_dictionary_map()) return map;
10068 
10069   // Migrate to the newest map before transitioning to the new property.
10070   map = Update(isolate, map);
10071 
10072   PropertyNormalizationMode mode = map->is_prototype_map()
10073                                        ? KEEP_INOBJECT_PROPERTIES
10074                                        : CLEAR_INOBJECT_PROPERTIES;
10075 
10076   Map* maybe_transition = TransitionsAccessor(isolate, map)
10077                               .SearchTransition(*name, kAccessor, attributes);
10078   if (maybe_transition != nullptr) {
10079     Handle<Map> transition(maybe_transition, isolate);
10080     DescriptorArray* descriptors = transition->instance_descriptors();
10081     int descriptor = transition->LastAdded();
10082     DCHECK(descriptors->GetKey(descriptor)->Equals(*name));
10083 
10084     DCHECK_EQ(kAccessor, descriptors->GetDetails(descriptor).kind());
10085     DCHECK_EQ(attributes, descriptors->GetDetails(descriptor).attributes());
10086 
10087     Handle<Object> maybe_pair(descriptors->GetStrongValue(descriptor), isolate);
10088     if (!maybe_pair->IsAccessorPair()) {
10089       return Map::Normalize(isolate, map, mode,
10090                             "TransitionToAccessorFromNonPair");
10091     }
10092 
10093     Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair);
10094     if (!pair->Equals(*getter, *setter)) {
10095       return Map::Normalize(isolate, map, mode,
10096                             "TransitionToDifferentAccessor");
10097     }
10098 
10099     return transition;
10100   }
10101 
10102   Handle<AccessorPair> pair;
10103   DescriptorArray* old_descriptors = map->instance_descriptors();
10104   if (descriptor != DescriptorArray::kNotFound) {
10105     if (descriptor != map->LastAdded()) {
10106       return Map::Normalize(isolate, map, mode, "AccessorsOverwritingNonLast");
10107     }
10108     PropertyDetails old_details = old_descriptors->GetDetails(descriptor);
10109     if (old_details.kind() != kAccessor) {
10110       return Map::Normalize(isolate, map, mode,
10111                             "AccessorsOverwritingNonAccessors");
10112     }
10113 
10114     if (old_details.attributes() != attributes) {
10115       return Map::Normalize(isolate, map, mode, "AccessorsWithAttributes");
10116     }
10117 
10118     Handle<Object> maybe_pair(old_descriptors->GetStrongValue(descriptor),
10119                               isolate);
10120     if (!maybe_pair->IsAccessorPair()) {
10121       return Map::Normalize(isolate, map, mode, "AccessorsOverwritingNonPair");
10122     }
10123 
10124     Handle<AccessorPair> current_pair = Handle<AccessorPair>::cast(maybe_pair);
10125     if (current_pair->Equals(*getter, *setter)) return map;
10126 
10127     bool overwriting_accessor = false;
10128     if (!getter->IsNull(isolate) &&
10129         !current_pair->get(ACCESSOR_GETTER)->IsNull(isolate) &&
10130         current_pair->get(ACCESSOR_GETTER) != *getter) {
10131       overwriting_accessor = true;
10132     }
10133     if (!setter->IsNull(isolate) &&
10134         !current_pair->get(ACCESSOR_SETTER)->IsNull(isolate) &&
10135         current_pair->get(ACCESSOR_SETTER) != *setter) {
10136       overwriting_accessor = true;
10137     }
10138     if (overwriting_accessor) {
10139       return Map::Normalize(isolate, map, mode,
10140                             "AccessorsOverwritingAccessors");
10141     }
10142 
10143     pair = AccessorPair::Copy(isolate, Handle<AccessorPair>::cast(maybe_pair));
10144   } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors ||
10145              map->TooManyFastProperties(CERTAINLY_NOT_STORE_FROM_KEYED)) {
10146     return Map::Normalize(isolate, map, CLEAR_INOBJECT_PROPERTIES,
10147                           "TooManyAccessors");
10148   } else {
10149     pair = isolate->factory()->NewAccessorPair();
10150   }
10151 
10152   pair->SetComponents(*getter, *setter);
10153 
10154   TransitionFlag flag = INSERT_TRANSITION;
10155   Descriptor d = Descriptor::AccessorConstant(name, pair, attributes);
10156   return Map::CopyInsertDescriptor(isolate, map, &d, flag);
10157 }
10158 
CopyAddDescriptor(Isolate * isolate,Handle<Map> map,Descriptor * descriptor,TransitionFlag flag)10159 Handle<Map> Map::CopyAddDescriptor(Isolate* isolate, Handle<Map> map,
10160                                    Descriptor* descriptor,
10161                                    TransitionFlag flag) {
10162   Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
10163 
10164   // Share descriptors only if map owns descriptors and it not an initial map.
10165   if (flag == INSERT_TRANSITION && map->owns_descriptors() &&
10166       !map->GetBackPointer()->IsUndefined(isolate) &&
10167       TransitionsAccessor(isolate, map).CanHaveMoreTransitions()) {
10168     return ShareDescriptor(isolate, map, descriptors, descriptor);
10169   }
10170 
10171   int nof = map->NumberOfOwnDescriptors();
10172   Handle<DescriptorArray> new_descriptors =
10173       DescriptorArray::CopyUpTo(isolate, descriptors, nof, 1);
10174   new_descriptors->Append(descriptor);
10175 
10176   Handle<LayoutDescriptor> new_layout_descriptor =
10177       FLAG_unbox_double_fields
10178           ? LayoutDescriptor::New(isolate, map, new_descriptors, nof + 1)
10179           : handle(LayoutDescriptor::FastPointerLayout(), isolate);
10180 
10181   return CopyReplaceDescriptors(
10182       isolate, map, new_descriptors, new_layout_descriptor, flag,
10183       descriptor->GetKey(), "CopyAddDescriptor", SIMPLE_PROPERTY_TRANSITION);
10184 }
10185 
CopyInsertDescriptor(Isolate * isolate,Handle<Map> map,Descriptor * descriptor,TransitionFlag flag)10186 Handle<Map> Map::CopyInsertDescriptor(Isolate* isolate, Handle<Map> map,
10187                                       Descriptor* descriptor,
10188                                       TransitionFlag flag) {
10189   Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
10190 
10191   // We replace the key if it is already present.
10192   int index =
10193       old_descriptors->SearchWithCache(isolate, *descriptor->GetKey(), *map);
10194   if (index != DescriptorArray::kNotFound) {
10195     return CopyReplaceDescriptor(isolate, map, old_descriptors, descriptor,
10196                                  index, flag);
10197   }
10198   return CopyAddDescriptor(isolate, map, descriptor, flag);
10199 }
10200 
CopyUpTo(Isolate * isolate,Handle<DescriptorArray> desc,int enumeration_index,int slack)10201 Handle<DescriptorArray> DescriptorArray::CopyUpTo(Isolate* isolate,
10202                                                   Handle<DescriptorArray> desc,
10203                                                   int enumeration_index,
10204                                                   int slack) {
10205   return DescriptorArray::CopyUpToAddAttributes(isolate, desc,
10206                                                 enumeration_index, NONE, slack);
10207 }
10208 
CopyUpToAddAttributes(Isolate * isolate,Handle<DescriptorArray> desc,int enumeration_index,PropertyAttributes attributes,int slack)10209 Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
10210     Isolate* isolate, Handle<DescriptorArray> desc, int enumeration_index,
10211     PropertyAttributes attributes, int slack) {
10212   if (enumeration_index + slack == 0) {
10213     return isolate->factory()->empty_descriptor_array();
10214   }
10215 
10216   int size = enumeration_index;
10217 
10218   Handle<DescriptorArray> descriptors =
10219       DescriptorArray::Allocate(isolate, size, slack);
10220 
10221   if (attributes != NONE) {
10222     for (int i = 0; i < size; ++i) {
10223       MaybeObject* value_or_field_type = desc->GetValue(i);
10224       Name* key = desc->GetKey(i);
10225       PropertyDetails details = desc->GetDetails(i);
10226       // Bulk attribute changes never affect private properties.
10227       if (!key->IsPrivate()) {
10228         int mask = DONT_DELETE | DONT_ENUM;
10229         // READ_ONLY is an invalid attribute for JS setters/getters.
10230         HeapObject* heap_object;
10231         if (details.kind() != kAccessor ||
10232             !(value_or_field_type->ToStrongHeapObject(&heap_object) &&
10233               heap_object->IsAccessorPair())) {
10234           mask |= READ_ONLY;
10235         }
10236         details = details.CopyAddAttributes(
10237             static_cast<PropertyAttributes>(attributes & mask));
10238       }
10239       descriptors->Set(i, key, value_or_field_type, details);
10240     }
10241   } else {
10242     for (int i = 0; i < size; ++i) {
10243       descriptors->CopyFrom(i, *desc);
10244     }
10245   }
10246 
10247   if (desc->number_of_descriptors() != enumeration_index) descriptors->Sort();
10248 
10249   return descriptors;
10250 }
10251 
10252 // Create a new descriptor array with only enumerable, configurable, writeable
10253 // data properties, but identical field locations.
CopyForFastObjectClone(Isolate * isolate,Handle<DescriptorArray> src,int enumeration_index,int slack)10254 Handle<DescriptorArray> DescriptorArray::CopyForFastObjectClone(
10255     Isolate* isolate, Handle<DescriptorArray> src, int enumeration_index,
10256     int slack) {
10257   if (enumeration_index + slack == 0) {
10258     return isolate->factory()->empty_descriptor_array();
10259   }
10260 
10261   int size = enumeration_index;
10262   Handle<DescriptorArray> descriptors =
10263       DescriptorArray::Allocate(isolate, size, slack);
10264 
10265   for (int i = 0; i < size; ++i) {
10266     Name* key = src->GetKey(i);
10267     PropertyDetails details = src->GetDetails(i);
10268 
10269     DCHECK(!key->IsPrivateField());
10270     DCHECK(details.IsEnumerable());
10271     DCHECK_EQ(details.kind(), kData);
10272 
10273     // Ensure the ObjectClone property details are NONE, and that all source
10274     // details did not contain DONT_ENUM.
10275     PropertyDetails new_details(kData, NONE, details.location(),
10276                                 details.constness(), details.representation(),
10277                                 details.field_index());
10278     // Do not propagate the field type of normal object fields from the
10279     // original descriptors since FieldType changes don't create new maps.
10280     MaybeObject* type = src->GetValue(i);
10281     if (details.location() == PropertyLocation::kField) {
10282       type = MaybeObject::FromObject(FieldType::Any());
10283     }
10284     descriptors->Set(i, key, type, new_details);
10285   }
10286 
10287   descriptors->Sort();
10288 
10289   return descriptors;
10290 }
10291 
IsEqualUpTo(DescriptorArray * desc,int nof_descriptors)10292 bool DescriptorArray::IsEqualUpTo(DescriptorArray* desc, int nof_descriptors) {
10293   for (int i = 0; i < nof_descriptors; i++) {
10294     if (GetKey(i) != desc->GetKey(i) || GetValue(i) != desc->GetValue(i)) {
10295       return false;
10296     }
10297     PropertyDetails details = GetDetails(i);
10298     PropertyDetails other_details = desc->GetDetails(i);
10299     if (details.kind() != other_details.kind() ||
10300         details.location() != other_details.location() ||
10301         !details.representation().Equals(other_details.representation())) {
10302       return false;
10303     }
10304   }
10305   return true;
10306 }
10307 
CopyReplaceDescriptor(Isolate * isolate,Handle<Map> map,Handle<DescriptorArray> descriptors,Descriptor * descriptor,int insertion_index,TransitionFlag flag)10308 Handle<Map> Map::CopyReplaceDescriptor(Isolate* isolate, Handle<Map> map,
10309                                        Handle<DescriptorArray> descriptors,
10310                                        Descriptor* descriptor,
10311                                        int insertion_index,
10312                                        TransitionFlag flag) {
10313   Handle<Name> key = descriptor->GetKey();
10314   DCHECK_EQ(*key, descriptors->GetKey(insertion_index));
10315   // This function does not support replacing property fields as
10316   // that would break property field counters.
10317   DCHECK_NE(kField, descriptor->GetDetails().location());
10318   DCHECK_NE(kField, descriptors->GetDetails(insertion_index).location());
10319 
10320   Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
10321       isolate, descriptors, map->NumberOfOwnDescriptors());
10322 
10323   new_descriptors->Replace(insertion_index, descriptor);
10324   Handle<LayoutDescriptor> new_layout_descriptor = LayoutDescriptor::New(
10325       isolate, map, new_descriptors, new_descriptors->number_of_descriptors());
10326 
10327   SimpleTransitionFlag simple_flag =
10328       (insertion_index == descriptors->number_of_descriptors() - 1)
10329           ? SIMPLE_PROPERTY_TRANSITION
10330           : PROPERTY_TRANSITION;
10331   return CopyReplaceDescriptors(isolate, map, new_descriptors,
10332                                 new_layout_descriptor, flag, key,
10333                                 "CopyReplaceDescriptor", simple_flag);
10334 }
10335 
SetAndGrow(Isolate * isolate,Handle<FixedArray> array,int index,Handle<Object> value,PretenureFlag pretenure)10336 Handle<FixedArray> FixedArray::SetAndGrow(Isolate* isolate,
10337                                           Handle<FixedArray> array, int index,
10338                                           Handle<Object> value,
10339                                           PretenureFlag pretenure) {
10340   if (index < array->length()) {
10341     array->set(index, *value);
10342     return array;
10343   }
10344   int capacity = array->length();
10345   do {
10346     capacity = JSObject::NewElementsCapacity(capacity);
10347   } while (capacity <= index);
10348   Handle<FixedArray> new_array =
10349       isolate->factory()->NewUninitializedFixedArray(capacity, pretenure);
10350   array->CopyTo(0, *new_array, 0, array->length());
10351   new_array->FillWithHoles(array->length(), new_array->length());
10352   new_array->set(index, *value);
10353   return new_array;
10354 }
10355 
ContainsSortedNumbers()10356 bool FixedArray::ContainsSortedNumbers() {
10357   for (int i = 1; i < length(); ++i) {
10358     Object* a_obj = get(i - 1);
10359     Object* b_obj = get(i);
10360     if (!a_obj->IsNumber() || !b_obj->IsNumber()) return false;
10361 
10362     uint32_t a = NumberToUint32(a_obj);
10363     uint32_t b = NumberToUint32(b_obj);
10364 
10365     if (a > b) return false;
10366   }
10367   return true;
10368 }
10369 
ShrinkOrEmpty(Isolate * isolate,Handle<FixedArray> array,int new_length)10370 Handle<FixedArray> FixedArray::ShrinkOrEmpty(Isolate* isolate,
10371                                              Handle<FixedArray> array,
10372                                              int new_length) {
10373   if (new_length == 0) {
10374     return array->GetReadOnlyRoots().empty_fixed_array_handle();
10375   } else {
10376     array->Shrink(isolate, new_length);
10377     return array;
10378   }
10379 }
10380 
Shrink(Isolate * isolate,int new_length)10381 void FixedArray::Shrink(Isolate* isolate, int new_length) {
10382   DCHECK(0 < new_length && new_length <= length());
10383   if (new_length < length()) {
10384     isolate->heap()->RightTrimFixedArray(this, length() - new_length);
10385   }
10386 }
10387 
CopyTo(int pos,FixedArray * dest,int dest_pos,int len) const10388 void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos,
10389                         int len) const {
10390   DisallowHeapAllocation no_gc;
10391   // Return early if len == 0 so that we don't try to read the write barrier off
10392   // a canonical read-only empty fixed array.
10393   if (len == 0) return;
10394   WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
10395   for (int index = 0; index < len; index++) {
10396     dest->set(dest_pos+index, get(pos+index), mode);
10397   }
10398 }
10399 
10400 #ifdef DEBUG
IsEqualTo(FixedArray * other)10401 bool FixedArray::IsEqualTo(FixedArray* other) {
10402   if (length() != other->length()) return false;
10403   for (int i = 0 ; i < length(); ++i) {
10404     if (get(i) != other->get(i)) return false;
10405   }
10406   return true;
10407 }
10408 #endif
10409 
PrototypeRegistryCompactionCallback(HeapObject * value,int old_index,int new_index)10410 void JSObject::PrototypeRegistryCompactionCallback(HeapObject* value,
10411                                                    int old_index,
10412                                                    int new_index) {
10413   DCHECK(value->IsMap() && Map::cast(value)->is_prototype_map());
10414   Map* map = Map::cast(value);
10415   DCHECK(map->prototype_info()->IsPrototypeInfo());
10416   PrototypeInfo* proto_info = PrototypeInfo::cast(map->prototype_info());
10417   DCHECK_EQ(old_index, proto_info->registry_slot());
10418   proto_info->set_registry_slot(new_index);
10419 }
10420 
10421 // static
Add(Isolate * isolate,Handle<ArrayList> array,Handle<Object> obj)10422 Handle<ArrayList> ArrayList::Add(Isolate* isolate, Handle<ArrayList> array,
10423                                  Handle<Object> obj) {
10424   int length = array->Length();
10425   array = EnsureSpace(isolate, array, length + 1);
10426   // Check that GC didn't remove elements from the array.
10427   DCHECK_EQ(array->Length(), length);
10428   array->Set(length, *obj);
10429   array->SetLength(length + 1);
10430   return array;
10431 }
10432 
10433 // static
Add(Isolate * isolate,Handle<ArrayList> array,Handle<Object> obj1,Handle<Object> obj2)10434 Handle<ArrayList> ArrayList::Add(Isolate* isolate, Handle<ArrayList> array,
10435                                  Handle<Object> obj1, Handle<Object> obj2) {
10436   int length = array->Length();
10437   array = EnsureSpace(isolate, array, length + 2);
10438   // Check that GC didn't remove elements from the array.
10439   DCHECK_EQ(array->Length(), length);
10440   array->Set(length, *obj1);
10441   array->Set(length + 1, *obj2);
10442   array->SetLength(length + 2);
10443   return array;
10444 }
10445 
10446 // static
New(Isolate * isolate,int size)10447 Handle<ArrayList> ArrayList::New(Isolate* isolate, int size) {
10448   Handle<FixedArray> fixed_array =
10449       isolate->factory()->NewFixedArray(size + kFirstIndex);
10450   fixed_array->set_map_no_write_barrier(
10451       ReadOnlyRoots(isolate).array_list_map());
10452   Handle<ArrayList> result = Handle<ArrayList>::cast(fixed_array);
10453   result->SetLength(0);
10454   return result;
10455 }
10456 
Elements(Isolate * isolate,Handle<ArrayList> array)10457 Handle<FixedArray> ArrayList::Elements(Isolate* isolate,
10458                                        Handle<ArrayList> array) {
10459   int length = array->Length();
10460   Handle<FixedArray> result = isolate->factory()->NewFixedArray(length);
10461   // Do not copy the first entry, i.e., the length.
10462   array->CopyTo(kFirstIndex, *result, 0, length);
10463   return result;
10464 }
10465 
IsFull()10466 bool ArrayList::IsFull() {
10467   int capacity = length();
10468   return kFirstIndex + Length() == capacity;
10469 }
10470 
10471 namespace {
10472 
EnsureSpaceInFixedArray(Isolate * isolate,Handle<FixedArray> array,int length)10473 Handle<FixedArray> EnsureSpaceInFixedArray(Isolate* isolate,
10474                                            Handle<FixedArray> array,
10475                                            int length) {
10476   int capacity = array->length();
10477   if (capacity < length) {
10478     int new_capacity = length;
10479     new_capacity = new_capacity + Max(new_capacity / 2, 2);
10480     int grow_by = new_capacity - capacity;
10481     array = isolate->factory()->CopyFixedArrayAndGrow(array, grow_by);
10482   }
10483   return array;
10484 }
10485 
10486 }  // namespace
10487 
10488 // static
EnsureSpace(Isolate * isolate,Handle<ArrayList> array,int length)10489 Handle<ArrayList> ArrayList::EnsureSpace(Isolate* isolate,
10490                                          Handle<ArrayList> array, int length) {
10491   const bool empty = (array->length() == 0);
10492   auto ret = EnsureSpaceInFixedArray(isolate, array, kFirstIndex + length);
10493   if (empty) {
10494     ret->set_map_no_write_barrier(array->GetReadOnlyRoots().array_list_map());
10495 
10496     Handle<ArrayList>::cast(ret)->SetLength(0);
10497   }
10498   return Handle<ArrayList>::cast(ret);
10499 }
10500 
10501 // static
AddToEnd(Isolate * isolate,Handle<WeakArrayList> array,MaybeObjectHandle value)10502 Handle<WeakArrayList> WeakArrayList::AddToEnd(Isolate* isolate,
10503                                               Handle<WeakArrayList> array,
10504                                               MaybeObjectHandle value) {
10505   int length = array->length();
10506   array = EnsureSpace(isolate, array, length + 1);
10507   // Reload length; GC might have removed elements from the array.
10508   length = array->length();
10509   array->Set(length, *value);
10510   array->set_length(length + 1);
10511   return array;
10512 }
10513 
IsFull()10514 bool WeakArrayList::IsFull() { return length() == capacity(); }
10515 
10516 // static
EnsureSpace(Isolate * isolate,Handle<WeakArrayList> array,int length,PretenureFlag pretenure)10517 Handle<WeakArrayList> WeakArrayList::EnsureSpace(Isolate* isolate,
10518                                                  Handle<WeakArrayList> array,
10519                                                  int length,
10520                                                  PretenureFlag pretenure) {
10521   int capacity = array->capacity();
10522   if (capacity < length) {
10523     int new_capacity = length;
10524     new_capacity = new_capacity + Max(new_capacity / 2, 2);
10525     int grow_by = new_capacity - capacity;
10526     array =
10527         isolate->factory()->CopyWeakArrayListAndGrow(array, grow_by, pretenure);
10528   }
10529   return array;
10530 }
10531 
CountLiveWeakReferences() const10532 int WeakArrayList::CountLiveWeakReferences() const {
10533   int live_weak_references = 0;
10534   for (int i = 0; i < length(); i++) {
10535     if (Get(i)->IsWeakHeapObject()) {
10536       ++live_weak_references;
10537     }
10538   }
10539   return live_weak_references;
10540 }
10541 
RemoveOne(MaybeObjectHandle value)10542 bool WeakArrayList::RemoveOne(MaybeObjectHandle value) {
10543   if (length() == 0) return false;
10544   // Optimize for the most recently added element to be removed again.
10545   int last_index = length() - 1;
10546   for (int i = last_index; i >= 0; --i) {
10547     if (Get(i) == *value) {
10548       // Move the last element into the this slot (or no-op, if this is the
10549       // last slot).
10550       Set(i, Get(last_index));
10551       Set(last_index, HeapObjectReference::ClearedValue());
10552       set_length(last_index);
10553       return true;
10554     }
10555   }
10556   return false;
10557 }
10558 
10559 // static
Add(Isolate * isolate,Handle<WeakArrayList> array,Handle<Map> value,int * assigned_index)10560 Handle<WeakArrayList> PrototypeUsers::Add(Isolate* isolate,
10561                                           Handle<WeakArrayList> array,
10562                                           Handle<Map> value,
10563                                           int* assigned_index) {
10564   int length = array->length();
10565   if (length == 0) {
10566     // Uninitialized WeakArrayList; need to initialize empty_slot_index.
10567     array = WeakArrayList::EnsureSpace(isolate, array, kFirstIndex + 1);
10568     set_empty_slot_index(*array, kNoEmptySlotsMarker);
10569     array->Set(kFirstIndex, HeapObjectReference::Weak(*value));
10570     array->set_length(kFirstIndex + 1);
10571     if (assigned_index != nullptr) *assigned_index = kFirstIndex;
10572     return array;
10573   }
10574 
10575   // If the array has unfilled space at the end, use it.
10576   if (!array->IsFull()) {
10577     array->Set(length, HeapObjectReference::Weak(*value));
10578     array->set_length(length + 1);
10579     if (assigned_index != nullptr) *assigned_index = length;
10580     return array;
10581   }
10582 
10583   // If there are empty slots, use one of them.
10584   int empty_slot = Smi::ToInt(empty_slot_index(*array));
10585   if (empty_slot != kNoEmptySlotsMarker) {
10586     DCHECK_GE(empty_slot, kFirstIndex);
10587     CHECK_LT(empty_slot, array->length());
10588     int next_empty_slot = Smi::ToInt(array->Get(empty_slot)->ToSmi());
10589 
10590     array->Set(empty_slot, HeapObjectReference::Weak(*value));
10591     if (assigned_index != nullptr) *assigned_index = empty_slot;
10592 
10593     set_empty_slot_index(*array, next_empty_slot);
10594     return array;
10595   } else {
10596     DCHECK_EQ(empty_slot, kNoEmptySlotsMarker);
10597   }
10598 
10599   // Array full and no empty slots. Grow the array.
10600   array = WeakArrayList::EnsureSpace(isolate, array, length + 1);
10601   array->Set(length, HeapObjectReference::Weak(*value));
10602   array->set_length(length + 1);
10603   if (assigned_index != nullptr) *assigned_index = length;
10604   return array;
10605 }
10606 
Compact(Handle<WeakArrayList> array,Heap * heap,CompactionCallback callback,PretenureFlag pretenure)10607 WeakArrayList* PrototypeUsers::Compact(Handle<WeakArrayList> array, Heap* heap,
10608                                        CompactionCallback callback,
10609                                        PretenureFlag pretenure) {
10610   if (array->length() == 0) {
10611     return *array;
10612   }
10613   int new_length = kFirstIndex + array->CountLiveWeakReferences();
10614   if (new_length == array->length()) {
10615     return *array;
10616   }
10617 
10618   Handle<WeakArrayList> new_array = WeakArrayList::EnsureSpace(
10619       heap->isolate(),
10620       handle(ReadOnlyRoots(heap).empty_weak_array_list(), heap->isolate()),
10621       new_length, pretenure);
10622   // Allocation might have caused GC and turned some of the elements into
10623   // cleared weak heap objects. Count the number of live objects again.
10624   int copy_to = kFirstIndex;
10625   for (int i = kFirstIndex; i < array->length(); i++) {
10626     MaybeObject* element = array->Get(i);
10627     if (element->IsSmi()) continue;
10628     if (element->IsClearedWeakHeapObject()) continue;
10629     HeapObject* value = element->ToWeakHeapObject();
10630     callback(value, i, copy_to);
10631     new_array->Set(copy_to++, element);
10632   }
10633   new_array->set_length(copy_to);
10634   set_empty_slot_index(*new_array, kNoEmptySlotsMarker);
10635   return *new_array;
10636 }
10637 
ReserveCaptures(Isolate * isolate,Handle<RegExpMatchInfo> match_info,int capture_count)10638 Handle<RegExpMatchInfo> RegExpMatchInfo::ReserveCaptures(
10639     Isolate* isolate, Handle<RegExpMatchInfo> match_info, int capture_count) {
10640   DCHECK_GE(match_info->length(), kLastMatchOverhead);
10641   const int required_length = kFirstCaptureIndex + capture_count;
10642   Handle<FixedArray> result =
10643       EnsureSpaceInFixedArray(isolate, match_info, required_length);
10644   return Handle<RegExpMatchInfo>::cast(result);
10645 }
10646 
10647 // static
AppendJSFrame(Handle<FrameArray> in,Handle<Object> receiver,Handle<JSFunction> function,Handle<AbstractCode> code,int offset,int flags)10648 Handle<FrameArray> FrameArray::AppendJSFrame(Handle<FrameArray> in,
10649                                              Handle<Object> receiver,
10650                                              Handle<JSFunction> function,
10651                                              Handle<AbstractCode> code,
10652                                              int offset, int flags) {
10653   const int frame_count = in->FrameCount();
10654   const int new_length = LengthFor(frame_count + 1);
10655   Handle<FrameArray> array =
10656       EnsureSpace(function->GetIsolate(), in, new_length);
10657   array->SetReceiver(frame_count, *receiver);
10658   array->SetFunction(frame_count, *function);
10659   array->SetCode(frame_count, *code);
10660   array->SetOffset(frame_count, Smi::FromInt(offset));
10661   array->SetFlags(frame_count, Smi::FromInt(flags));
10662   array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));
10663   return array;
10664 }
10665 
10666 // static
AppendWasmFrame(Handle<FrameArray> in,Handle<WasmInstanceObject> wasm_instance,int wasm_function_index,wasm::WasmCode * code,int offset,int flags)10667 Handle<FrameArray> FrameArray::AppendWasmFrame(
10668     Handle<FrameArray> in, Handle<WasmInstanceObject> wasm_instance,
10669     int wasm_function_index, wasm::WasmCode* code, int offset, int flags) {
10670   Isolate* isolate = wasm_instance->GetIsolate();
10671   const int frame_count = in->FrameCount();
10672   const int new_length = LengthFor(frame_count + 1);
10673   Handle<FrameArray> array = EnsureSpace(isolate, in, new_length);
10674   // The {code} will be {nullptr} for interpreted wasm frames.
10675   Handle<Foreign> code_foreign =
10676       isolate->factory()->NewForeign(reinterpret_cast<Address>(code));
10677   array->SetWasmInstance(frame_count, *wasm_instance);
10678   array->SetWasmFunctionIndex(frame_count, Smi::FromInt(wasm_function_index));
10679   array->SetWasmCodeObject(frame_count, *code_foreign);
10680   array->SetOffset(frame_count, Smi::FromInt(offset));
10681   array->SetFlags(frame_count, Smi::FromInt(flags));
10682   array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));
10683   return array;
10684 }
10685 
ShrinkToFit(Isolate * isolate)10686 void FrameArray::ShrinkToFit(Isolate* isolate) {
10687   Shrink(isolate, LengthFor(FrameCount()));
10688 }
10689 
10690 // static
EnsureSpace(Isolate * isolate,Handle<FrameArray> array,int length)10691 Handle<FrameArray> FrameArray::EnsureSpace(Isolate* isolate,
10692                                            Handle<FrameArray> array,
10693                                            int length) {
10694   return Handle<FrameArray>::cast(
10695       EnsureSpaceInFixedArray(isolate, array, length));
10696 }
10697 
Allocate(Isolate * isolate,int number_of_descriptors,int slack,PretenureFlag pretenure)10698 Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate,
10699                                                   int number_of_descriptors,
10700                                                   int slack,
10701                                                   PretenureFlag pretenure) {
10702   DCHECK_LE(0, number_of_descriptors);
10703   Factory* factory = isolate->factory();
10704   // Do not use DescriptorArray::cast on incomplete object.
10705   int size = number_of_descriptors + slack;
10706   if (size == 0) return factory->empty_descriptor_array();
10707   // Allocate the array of keys.
10708   Handle<WeakFixedArray> result =
10709       factory->NewWeakFixedArrayWithMap<DescriptorArray>(
10710           Heap::kDescriptorArrayMapRootIndex, LengthFor(size), pretenure);
10711   result->Set(kDescriptorLengthIndex,
10712               MaybeObject::FromObject(Smi::FromInt(number_of_descriptors)));
10713   result->Set(kEnumCacheIndex, MaybeObject::FromObject(
10714                                    ReadOnlyRoots(isolate).empty_enum_cache()));
10715   return Handle<DescriptorArray>::cast(result);
10716 }
10717 
ClearEnumCache()10718 void DescriptorArray::ClearEnumCache() {
10719   set(kEnumCacheIndex,
10720       MaybeObject::FromObject(GetReadOnlyRoots().empty_enum_cache()));
10721 }
10722 
Replace(int index,Descriptor * descriptor)10723 void DescriptorArray::Replace(int index, Descriptor* descriptor) {
10724   descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index));
10725   Set(index, descriptor);
10726 }
10727 
10728 // static
SetEnumCache(Handle<DescriptorArray> descriptors,Isolate * isolate,Handle<FixedArray> keys,Handle<FixedArray> indices)10729 void DescriptorArray::SetEnumCache(Handle<DescriptorArray> descriptors,
10730                                    Isolate* isolate, Handle<FixedArray> keys,
10731                                    Handle<FixedArray> indices) {
10732   EnumCache* enum_cache = descriptors->GetEnumCache();
10733   if (enum_cache == ReadOnlyRoots(isolate).empty_enum_cache()) {
10734     enum_cache = *isolate->factory()->NewEnumCache(keys, indices);
10735     descriptors->set(kEnumCacheIndex, MaybeObject::FromObject(enum_cache));
10736   } else {
10737     enum_cache->set_keys(*keys);
10738     enum_cache->set_indices(*indices);
10739   }
10740 }
10741 
CopyFrom(int index,DescriptorArray * src)10742 void DescriptorArray::CopyFrom(int index, DescriptorArray* src) {
10743   PropertyDetails details = src->GetDetails(index);
10744   Set(index, src->GetKey(index), src->GetValue(index), details);
10745 }
10746 
Sort()10747 void DescriptorArray::Sort() {
10748   // In-place heap sort.
10749   int len = number_of_descriptors();
10750   // Reset sorting since the descriptor array might contain invalid pointers.
10751   for (int i = 0; i < len; ++i) SetSortedKey(i, i);
10752   // Bottom-up max-heap construction.
10753   // Index of the last node with children
10754   const int max_parent_index = (len / 2) - 1;
10755   for (int i = max_parent_index; i >= 0; --i) {
10756     int parent_index = i;
10757     const uint32_t parent_hash = GetSortedKey(i)->Hash();
10758     while (parent_index <= max_parent_index) {
10759       int child_index = 2 * parent_index + 1;
10760       uint32_t child_hash = GetSortedKey(child_index)->Hash();
10761       if (child_index + 1 < len) {
10762         uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
10763         if (right_child_hash > child_hash) {
10764           child_index++;
10765           child_hash = right_child_hash;
10766         }
10767       }
10768       if (child_hash <= parent_hash) break;
10769       SwapSortedKeys(parent_index, child_index);
10770       // Now element at child_index could be < its children.
10771       parent_index = child_index;  // parent_hash remains correct.
10772     }
10773   }
10774 
10775   // Extract elements and create sorted array.
10776   for (int i = len - 1; i > 0; --i) {
10777     // Put max element at the back of the array.
10778     SwapSortedKeys(0, i);
10779     // Shift down the new top element.
10780     int parent_index = 0;
10781     const uint32_t parent_hash = GetSortedKey(parent_index)->Hash();
10782     const int max_parent_index = (i / 2) - 1;
10783     while (parent_index <= max_parent_index) {
10784       int child_index = parent_index * 2 + 1;
10785       uint32_t child_hash = GetSortedKey(child_index)->Hash();
10786       if (child_index + 1 < i) {
10787         uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
10788         if (right_child_hash > child_hash) {
10789           child_index++;
10790           child_hash = right_child_hash;
10791         }
10792       }
10793       if (child_hash <= parent_hash) break;
10794       SwapSortedKeys(parent_index, child_index);
10795       parent_index = child_index;
10796     }
10797   }
10798   DCHECK(IsSortedNoDuplicates());
10799 }
10800 
Copy(Isolate * isolate,Handle<AccessorPair> pair)10801 Handle<AccessorPair> AccessorPair::Copy(Isolate* isolate,
10802                                         Handle<AccessorPair> pair) {
10803   Handle<AccessorPair> copy = isolate->factory()->NewAccessorPair();
10804   copy->set_getter(pair->getter());
10805   copy->set_setter(pair->setter());
10806   return copy;
10807 }
10808 
GetComponent(Isolate * isolate,Handle<AccessorPair> accessor_pair,AccessorComponent component)10809 Handle<Object> AccessorPair::GetComponent(Isolate* isolate,
10810                                           Handle<AccessorPair> accessor_pair,
10811                                           AccessorComponent component) {
10812   Object* accessor = accessor_pair->get(component);
10813   if (accessor->IsFunctionTemplateInfo()) {
10814     return ApiNatives::InstantiateFunction(
10815                handle(FunctionTemplateInfo::cast(accessor), isolate))
10816         .ToHandleChecked();
10817   }
10818   if (accessor->IsNull(isolate)) {
10819     return isolate->factory()->undefined_value();
10820   }
10821   return handle(accessor, isolate);
10822 }
10823 
New(Isolate * isolate,int deopt_entry_count,PretenureFlag pretenure)10824 Handle<DeoptimizationData> DeoptimizationData::New(Isolate* isolate,
10825                                                    int deopt_entry_count,
10826                                                    PretenureFlag pretenure) {
10827   return Handle<DeoptimizationData>::cast(isolate->factory()->NewFixedArray(
10828       LengthFor(deopt_entry_count), pretenure));
10829 }
10830 
Empty(Isolate * isolate)10831 Handle<DeoptimizationData> DeoptimizationData::Empty(Isolate* isolate) {
10832   return Handle<DeoptimizationData>::cast(
10833       isolate->factory()->empty_fixed_array());
10834 }
10835 
GetInlinedFunction(int index)10836 SharedFunctionInfo* DeoptimizationData::GetInlinedFunction(int index) {
10837   if (index == -1) {
10838     return SharedFunctionInfo::cast(SharedFunctionInfo());
10839   } else {
10840     return SharedFunctionInfo::cast(LiteralArray()->get(index));
10841   }
10842 }
10843 
10844 #ifdef DEBUG
IsEqualTo(DescriptorArray * other)10845 bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
10846   if (length() != other->length()) return false;
10847   for (int i = 0; i < length(); ++i) {
10848     if (get(i) != other->get(i)) return false;
10849   }
10850   return true;
10851 }
10852 #endif
10853 
10854 // static
Trim(Isolate * isolate,Handle<String> string,TrimMode mode)10855 Handle<String> String::Trim(Isolate* isolate, Handle<String> string,
10856                             TrimMode mode) {
10857   string = String::Flatten(isolate, string);
10858   int const length = string->length();
10859 
10860   // Perform left trimming if requested.
10861   int left = 0;
10862   UnicodeCache* unicode_cache = isolate->unicode_cache();
10863   if (mode == kTrim || mode == kTrimStart) {
10864     while (left < length &&
10865            unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) {
10866       left++;
10867     }
10868   }
10869 
10870   // Perform right trimming if requested.
10871   int right = length;
10872   if (mode == kTrim || mode == kTrimEnd) {
10873     while (
10874         right > left &&
10875         unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) {
10876       right--;
10877     }
10878   }
10879 
10880   return isolate->factory()->NewSubString(string, left, right);
10881 }
10882 
LooksValid()10883 bool String::LooksValid() {
10884   // TODO(leszeks): Maybe remove this check entirely, Heap::Contains uses
10885   // basically the same logic as the way we access the heap in the first place.
10886   MemoryChunk* chunk = MemoryChunk::FromHeapObject(this);
10887   // RO_SPACE objects should always be valid.
10888   if (chunk->owner()->identity() == RO_SPACE) return true;
10889   if (chunk->heap() == nullptr) return false;
10890   return chunk->heap()->Contains(this);
10891 }
10892 
10893 // static
ToFunctionName(Isolate * isolate,Handle<Name> name)10894 MaybeHandle<String> Name::ToFunctionName(Isolate* isolate, Handle<Name> name) {
10895   if (name->IsString()) return Handle<String>::cast(name);
10896   // ES6 section 9.2.11 SetFunctionName, step 4.
10897   Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate);
10898   if (description->IsUndefined(isolate)) {
10899     return isolate->factory()->empty_string();
10900   }
10901   IncrementalStringBuilder builder(isolate);
10902   builder.AppendCharacter('[');
10903   builder.AppendString(Handle<String>::cast(description));
10904   builder.AppendCharacter(']');
10905   return builder.Finish();
10906 }
10907 
10908 // static
ToFunctionName(Isolate * isolate,Handle<Name> name,Handle<String> prefix)10909 MaybeHandle<String> Name::ToFunctionName(Isolate* isolate, Handle<Name> name,
10910                                          Handle<String> prefix) {
10911   Handle<String> name_string;
10912   ASSIGN_RETURN_ON_EXCEPTION(isolate, name_string,
10913                              ToFunctionName(isolate, name), String);
10914   IncrementalStringBuilder builder(isolate);
10915   builder.AppendString(prefix);
10916   builder.AppendCharacter(' ');
10917   builder.AppendString(name_string);
10918   return builder.Finish();
10919 }
10920 
10921 namespace {
10922 
AreDigits(const uint8_t * s,int from,int to)10923 bool AreDigits(const uint8_t* s, int from, int to) {
10924   for (int i = from; i < to; i++) {
10925     if (s[i] < '0' || s[i] > '9') return false;
10926   }
10927 
10928   return true;
10929 }
10930 
10931 
ParseDecimalInteger(const uint8_t * s,int from,int to)10932 int ParseDecimalInteger(const uint8_t* s, int from, int to) {
10933   DCHECK_LT(to - from, 10);  // Overflow is not possible.
10934   DCHECK(from < to);
10935   int d = s[from] - '0';
10936 
10937   for (int i = from + 1; i < to; i++) {
10938     d = 10 * d + (s[i] - '0');
10939   }
10940 
10941   return d;
10942 }
10943 
10944 }  // namespace
10945 
10946 // static
ToNumber(Isolate * isolate,Handle<String> subject)10947 Handle<Object> String::ToNumber(Isolate* isolate, Handle<String> subject) {
10948   // Flatten {subject} string first.
10949   subject = String::Flatten(isolate, subject);
10950 
10951   // Fast array index case.
10952   uint32_t index;
10953   if (subject->AsArrayIndex(&index)) {
10954     return isolate->factory()->NewNumberFromUint(index);
10955   }
10956 
10957   // Fast case: short integer or some sorts of junk values.
10958   if (subject->IsSeqOneByteString()) {
10959     int len = subject->length();
10960     if (len == 0) return handle(Smi::kZero, isolate);
10961 
10962     DisallowHeapAllocation no_gc;
10963     uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars();
10964     bool minus = (data[0] == '-');
10965     int start_pos = (minus ? 1 : 0);
10966 
10967     if (start_pos == len) {
10968       return isolate->factory()->nan_value();
10969     } else if (data[start_pos] > '9') {
10970       // Fast check for a junk value. A valid string may start from a
10971       // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit
10972       // or the 'I' character ('Infinity'). All of that have codes not greater
10973       // than '9' except 'I' and &nbsp;.
10974       if (data[start_pos] != 'I' && data[start_pos] != 0xA0) {
10975         return isolate->factory()->nan_value();
10976       }
10977     } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
10978       // The maximal/minimal smi has 10 digits. If the string has less digits
10979       // we know it will fit into the smi-data type.
10980       int d = ParseDecimalInteger(data, start_pos, len);
10981       if (minus) {
10982         if (d == 0) return isolate->factory()->minus_zero_value();
10983         d = -d;
10984       } else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize &&
10985                  (len == 1 || data[0] != '0')) {
10986         // String hash is not calculated yet but all the data are present.
10987         // Update the hash field to speed up sequential convertions.
10988         uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
10989 #ifdef DEBUG
10990         subject->Hash();  // Force hash calculation.
10991         DCHECK_EQ(static_cast<int>(subject->hash_field()),
10992                   static_cast<int>(hash));
10993 #endif
10994         subject->set_hash_field(hash);
10995       }
10996       return handle(Smi::FromInt(d), isolate);
10997     }
10998   }
10999 
11000   // Slower case.
11001   int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY;
11002   return isolate->factory()->NewNumber(
11003       StringToDouble(isolate, isolate->unicode_cache(), subject, flags));
11004 }
11005 
11006 
GetFlatContent()11007 String::FlatContent String::GetFlatContent() {
11008   DCHECK(!AllowHeapAllocation::IsAllowed());
11009   int length = this->length();
11010   StringShape shape(this);
11011   String* string = this;
11012   int offset = 0;
11013   if (shape.representation_tag() == kConsStringTag) {
11014     ConsString* cons = ConsString::cast(string);
11015     if (cons->second()->length() != 0) {
11016       return FlatContent();
11017     }
11018     string = cons->first();
11019     shape = StringShape(string);
11020   } else if (shape.representation_tag() == kSlicedStringTag) {
11021     SlicedString* slice = SlicedString::cast(string);
11022     offset = slice->offset();
11023     string = slice->parent();
11024     shape = StringShape(string);
11025     DCHECK(shape.representation_tag() != kConsStringTag &&
11026            shape.representation_tag() != kSlicedStringTag);
11027   }
11028   if (shape.representation_tag() == kThinStringTag) {
11029     ThinString* thin = ThinString::cast(string);
11030     string = thin->actual();
11031     shape = StringShape(string);
11032     DCHECK(!shape.IsCons());
11033     DCHECK(!shape.IsSliced());
11034   }
11035   if (shape.encoding_tag() == kOneByteStringTag) {
11036     const uint8_t* start;
11037     if (shape.representation_tag() == kSeqStringTag) {
11038       start = SeqOneByteString::cast(string)->GetChars();
11039     } else {
11040       start = ExternalOneByteString::cast(string)->GetChars();
11041     }
11042     return FlatContent(start + offset, length);
11043   } else {
11044     DCHECK_EQ(shape.encoding_tag(), kTwoByteStringTag);
11045     const uc16* start;
11046     if (shape.representation_tag() == kSeqStringTag) {
11047       start = SeqTwoByteString::cast(string)->GetChars();
11048     } else {
11049       start = ExternalTwoByteString::cast(string)->GetChars();
11050     }
11051     return FlatContent(start + offset, length);
11052   }
11053 }
11054 
ToCString(AllowNullsFlag allow_nulls,RobustnessFlag robust_flag,int offset,int length,int * length_return)11055 std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
11056                                           RobustnessFlag robust_flag,
11057                                           int offset, int length,
11058                                           int* length_return) {
11059   if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
11060     return std::unique_ptr<char[]>();
11061   }
11062   // Negative length means the to the end of the string.
11063   if (length < 0) length = kMaxInt - offset;
11064 
11065   // Compute the size of the UTF-8 string. Start at the specified offset.
11066   StringCharacterStream stream(this, offset);
11067   int character_position = offset;
11068   int utf8_bytes = 0;
11069   int last = unibrow::Utf16::kNoPreviousCharacter;
11070   while (stream.HasMore() && character_position++ < offset + length) {
11071     uint16_t character = stream.GetNext();
11072     utf8_bytes += unibrow::Utf8::Length(character, last);
11073     last = character;
11074   }
11075 
11076   if (length_return) {
11077     *length_return = utf8_bytes;
11078   }
11079 
11080   char* result = NewArray<char>(utf8_bytes + 1);
11081 
11082   // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
11083   stream.Reset(this, offset);
11084   character_position = offset;
11085   int utf8_byte_position = 0;
11086   last = unibrow::Utf16::kNoPreviousCharacter;
11087   while (stream.HasMore() && character_position++ < offset + length) {
11088     uint16_t character = stream.GetNext();
11089     if (allow_nulls == DISALLOW_NULLS && character == 0) {
11090       character = ' ';
11091     }
11092     utf8_byte_position +=
11093         unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
11094     last = character;
11095   }
11096   result[utf8_byte_position] = 0;
11097   return std::unique_ptr<char[]>(result);
11098 }
11099 
ToCString(AllowNullsFlag allow_nulls,RobustnessFlag robust_flag,int * length_return)11100 std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
11101                                           RobustnessFlag robust_flag,
11102                                           int* length_return) {
11103   return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
11104 }
11105 
11106 
GetTwoByteData(unsigned start)11107 const uc16* String::GetTwoByteData(unsigned start) {
11108   DCHECK(!IsOneByteRepresentationUnderneath());
11109   switch (StringShape(this).representation_tag()) {
11110     case kSeqStringTag:
11111       return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
11112     case kExternalStringTag:
11113       return ExternalTwoByteString::cast(this)->
11114         ExternalTwoByteStringGetData(start);
11115     case kSlicedStringTag: {
11116       SlicedString* slice = SlicedString::cast(this);
11117       return slice->parent()->GetTwoByteData(start + slice->offset());
11118     }
11119     case kConsStringTag:
11120     case kThinStringTag:
11121       UNREACHABLE();
11122   }
11123   UNREACHABLE();
11124 }
11125 
11126 
SeqTwoByteStringGetData(unsigned start)11127 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
11128   return reinterpret_cast<uc16*>(
11129       reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
11130 }
11131 
11132 
PostGarbageCollectionProcessing(Isolate * isolate)11133 void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) {
11134   Relocatable* current = isolate->relocatable_top();
11135   while (current != nullptr) {
11136     current->PostGarbageCollection();
11137     current = current->prev_;
11138   }
11139 }
11140 
11141 
11142 // Reserve space for statics needing saving and restoring.
ArchiveSpacePerThread()11143 int Relocatable::ArchiveSpacePerThread() {
11144   return sizeof(Relocatable*);  // NOLINT
11145 }
11146 
11147 
11148 // Archive statics that are thread-local.
ArchiveState(Isolate * isolate,char * to)11149 char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
11150   *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
11151   isolate->set_relocatable_top(nullptr);
11152   return to + ArchiveSpacePerThread();
11153 }
11154 
11155 
11156 // Restore statics that are thread-local.
RestoreState(Isolate * isolate,char * from)11157 char* Relocatable::RestoreState(Isolate* isolate, char* from) {
11158   isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
11159   return from + ArchiveSpacePerThread();
11160 }
11161 
Iterate(RootVisitor * v,char * thread_storage)11162 char* Relocatable::Iterate(RootVisitor* v, char* thread_storage) {
11163   Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
11164   Iterate(v, top);
11165   return thread_storage + ArchiveSpacePerThread();
11166 }
11167 
Iterate(Isolate * isolate,RootVisitor * v)11168 void Relocatable::Iterate(Isolate* isolate, RootVisitor* v) {
11169   Iterate(v, isolate->relocatable_top());
11170 }
11171 
Iterate(RootVisitor * v,Relocatable * top)11172 void Relocatable::Iterate(RootVisitor* v, Relocatable* top) {
11173   Relocatable* current = top;
11174   while (current != nullptr) {
11175     current->IterateInstance(v);
11176     current = current->prev_;
11177   }
11178 }
11179 
11180 
FlatStringReader(Isolate * isolate,Handle<String> str)11181 FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
11182     : Relocatable(isolate),
11183       str_(str.location()),
11184       length_(str->length()) {
11185   PostGarbageCollection();
11186 }
11187 
11188 
FlatStringReader(Isolate * isolate,Vector<const char> input)11189 FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
11190     : Relocatable(isolate),
11191       str_(0),
11192       is_one_byte_(true),
11193       length_(input.length()),
11194       start_(input.start()) {}
11195 
11196 
PostGarbageCollection()11197 void FlatStringReader::PostGarbageCollection() {
11198   if (str_ == nullptr) return;
11199   Handle<String> str(str_);
11200   DCHECK(str->IsFlat());
11201   DisallowHeapAllocation no_gc;
11202   // This does not actually prevent the vector from being relocated later.
11203   String::FlatContent content = str->GetFlatContent();
11204   DCHECK(content.IsFlat());
11205   is_one_byte_ = content.IsOneByte();
11206   if (is_one_byte_) {
11207     start_ = content.ToOneByteVector().start();
11208   } else {
11209     start_ = content.ToUC16Vector().start();
11210   }
11211 }
11212 
11213 
Initialize(ConsString * cons_string,int offset)11214 void ConsStringIterator::Initialize(ConsString* cons_string, int offset) {
11215   DCHECK_NOT_NULL(cons_string);
11216   root_ = cons_string;
11217   consumed_ = offset;
11218   // Force stack blown condition to trigger restart.
11219   depth_ = 1;
11220   maximum_depth_ = kStackSize + depth_;
11221   DCHECK(StackBlown());
11222 }
11223 
11224 
Continue(int * offset_out)11225 String* ConsStringIterator::Continue(int* offset_out) {
11226   DCHECK_NE(depth_, 0);
11227   DCHECK_EQ(0, *offset_out);
11228   bool blew_stack = StackBlown();
11229   String* string = nullptr;
11230   // Get the next leaf if there is one.
11231   if (!blew_stack) string = NextLeaf(&blew_stack);
11232   // Restart search from root.
11233   if (blew_stack) {
11234     DCHECK_NULL(string);
11235     string = Search(offset_out);
11236   }
11237   // Ensure future calls return null immediately.
11238   if (string == nullptr) Reset(nullptr);
11239   return string;
11240 }
11241 
11242 
Search(int * offset_out)11243 String* ConsStringIterator::Search(int* offset_out) {
11244   ConsString* cons_string = root_;
11245   // Reset the stack, pushing the root string.
11246   depth_ = 1;
11247   maximum_depth_ = 1;
11248   frames_[0] = cons_string;
11249   const int consumed = consumed_;
11250   int offset = 0;
11251   while (true) {
11252     // Loop until the string is found which contains the target offset.
11253     String* string = cons_string->first();
11254     int length = string->length();
11255     int32_t type;
11256     if (consumed < offset + length) {
11257       // Target offset is in the left branch.
11258       // Keep going if we're still in a ConString.
11259       type = string->map()->instance_type();
11260       if ((type & kStringRepresentationMask) == kConsStringTag) {
11261         cons_string = ConsString::cast(string);
11262         PushLeft(cons_string);
11263         continue;
11264       }
11265       // Tell the stack we're done descending.
11266       AdjustMaximumDepth();
11267     } else {
11268       // Descend right.
11269       // Update progress through the string.
11270       offset += length;
11271       // Keep going if we're still in a ConString.
11272       string = cons_string->second();
11273       type = string->map()->instance_type();
11274       if ((type & kStringRepresentationMask) == kConsStringTag) {
11275         cons_string = ConsString::cast(string);
11276         PushRight(cons_string);
11277         continue;
11278       }
11279       // Need this to be updated for the current string.
11280       length = string->length();
11281       // Account for the possibility of an empty right leaf.
11282       // This happens only if we have asked for an offset outside the string.
11283       if (length == 0) {
11284         // Reset so future operations will return null immediately.
11285         Reset(nullptr);
11286         return nullptr;
11287       }
11288       // Tell the stack we're done descending.
11289       AdjustMaximumDepth();
11290       // Pop stack so next iteration is in correct place.
11291       Pop();
11292     }
11293     DCHECK_NE(length, 0);
11294     // Adjust return values and exit.
11295     consumed_ = offset + length;
11296     *offset_out = consumed - offset;
11297     return string;
11298   }
11299   UNREACHABLE();
11300 }
11301 
11302 
NextLeaf(bool * blew_stack)11303 String* ConsStringIterator::NextLeaf(bool* blew_stack) {
11304   while (true) {
11305     // Tree traversal complete.
11306     if (depth_ == 0) {
11307       *blew_stack = false;
11308       return nullptr;
11309     }
11310     // We've lost track of higher nodes.
11311     if (StackBlown()) {
11312       *blew_stack = true;
11313       return nullptr;
11314     }
11315     // Go right.
11316     ConsString* cons_string = frames_[OffsetForDepth(depth_ - 1)];
11317     String* string = cons_string->second();
11318     int32_t type = string->map()->instance_type();
11319     if ((type & kStringRepresentationMask) != kConsStringTag) {
11320       // Pop stack so next iteration is in correct place.
11321       Pop();
11322       int length = string->length();
11323       // Could be a flattened ConsString.
11324       if (length == 0) continue;
11325       consumed_ += length;
11326       return string;
11327     }
11328     cons_string = ConsString::cast(string);
11329     PushRight(cons_string);
11330     // Need to traverse all the way left.
11331     while (true) {
11332       // Continue left.
11333       string = cons_string->first();
11334       type = string->map()->instance_type();
11335       if ((type & kStringRepresentationMask) != kConsStringTag) {
11336         AdjustMaximumDepth();
11337         int length = string->length();
11338         if (length == 0) break;  // Skip empty left-hand sides of ConsStrings.
11339         consumed_ += length;
11340         return string;
11341       }
11342       cons_string = ConsString::cast(string);
11343       PushLeft(cons_string);
11344     }
11345   }
11346   UNREACHABLE();
11347 }
11348 
11349 
ConsStringGet(int index)11350 uint16_t ConsString::ConsStringGet(int index) {
11351   DCHECK(index >= 0 && index < this->length());
11352 
11353   // Check for a flattened cons string
11354   if (second()->length() == 0) {
11355     String* left = first();
11356     return left->Get(index);
11357   }
11358 
11359   String* string = String::cast(this);
11360 
11361   while (true) {
11362     if (StringShape(string).IsCons()) {
11363       ConsString* cons_string = ConsString::cast(string);
11364       String* left = cons_string->first();
11365       if (left->length() > index) {
11366         string = left;
11367       } else {
11368         index -= left->length();
11369         string = cons_string->second();
11370       }
11371     } else {
11372       return string->Get(index);
11373     }
11374   }
11375 
11376   UNREACHABLE();
11377 }
11378 
ThinStringGet(int index)11379 uint16_t ThinString::ThinStringGet(int index) { return actual()->Get(index); }
11380 
SlicedStringGet(int index)11381 uint16_t SlicedString::SlicedStringGet(int index) {
11382   return parent()->Get(offset() + index);
11383 }
11384 
11385 
11386 template <typename sinkchar>
WriteToFlat(String * src,sinkchar * sink,int f,int t)11387 void String::WriteToFlat(String* src,
11388                          sinkchar* sink,
11389                          int f,
11390                          int t) {
11391   String* source = src;
11392   int from = f;
11393   int to = t;
11394   while (true) {
11395     DCHECK(0 <= from && from <= to && to <= source->length());
11396     switch (StringShape(source).full_representation_tag()) {
11397       case kOneByteStringTag | kExternalStringTag: {
11398         CopyChars(sink, ExternalOneByteString::cast(source)->GetChars() + from,
11399                   to - from);
11400         return;
11401       }
11402       case kTwoByteStringTag | kExternalStringTag: {
11403         const uc16* data =
11404             ExternalTwoByteString::cast(source)->GetChars();
11405         CopyChars(sink,
11406                   data + from,
11407                   to - from);
11408         return;
11409       }
11410       case kOneByteStringTag | kSeqStringTag: {
11411         CopyChars(sink,
11412                   SeqOneByteString::cast(source)->GetChars() + from,
11413                   to - from);
11414         return;
11415       }
11416       case kTwoByteStringTag | kSeqStringTag: {
11417         CopyChars(sink,
11418                   SeqTwoByteString::cast(source)->GetChars() + from,
11419                   to - from);
11420         return;
11421       }
11422       case kOneByteStringTag | kConsStringTag:
11423       case kTwoByteStringTag | kConsStringTag: {
11424         ConsString* cons_string = ConsString::cast(source);
11425         String* first = cons_string->first();
11426         int boundary = first->length();
11427         if (to - boundary >= boundary - from) {
11428           // Right hand side is longer.  Recurse over left.
11429           if (from < boundary) {
11430             WriteToFlat(first, sink, from, boundary);
11431             if (from == 0 && cons_string->second() == first) {
11432               CopyChars(sink + boundary, sink, boundary);
11433               return;
11434             }
11435             sink += boundary - from;
11436             from = 0;
11437           } else {
11438             from -= boundary;
11439           }
11440           to -= boundary;
11441           source = cons_string->second();
11442         } else {
11443           // Left hand side is longer.  Recurse over right.
11444           if (to > boundary) {
11445             String* second = cons_string->second();
11446             // When repeatedly appending to a string, we get a cons string that
11447             // is unbalanced to the left, a list, essentially.  We inline the
11448             // common case of sequential one-byte right child.
11449             if (to - boundary == 1) {
11450               sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
11451             } else if (second->IsSeqOneByteString()) {
11452               CopyChars(sink + boundary - from,
11453                         SeqOneByteString::cast(second)->GetChars(),
11454                         to - boundary);
11455             } else {
11456               WriteToFlat(second,
11457                           sink + boundary - from,
11458                           0,
11459                           to - boundary);
11460             }
11461             to = boundary;
11462           }
11463           source = first;
11464         }
11465         break;
11466       }
11467       case kOneByteStringTag | kSlicedStringTag:
11468       case kTwoByteStringTag | kSlicedStringTag: {
11469         SlicedString* slice = SlicedString::cast(source);
11470         unsigned offset = slice->offset();
11471         WriteToFlat(slice->parent(), sink, from + offset, to + offset);
11472         return;
11473       }
11474       case kOneByteStringTag | kThinStringTag:
11475       case kTwoByteStringTag | kThinStringTag:
11476         source = ThinString::cast(source)->actual();
11477         break;
11478     }
11479   }
11480 }
11481 
11482 template <typename SourceChar>
CalculateLineEndsImpl(Isolate * isolate,std::vector<int> * line_ends,Vector<const SourceChar> src,bool include_ending_line)11483 static void CalculateLineEndsImpl(Isolate* isolate, std::vector<int>* line_ends,
11484                                   Vector<const SourceChar> src,
11485                                   bool include_ending_line) {
11486   const int src_len = src.length();
11487   UnicodeCache* cache = isolate->unicode_cache();
11488   for (int i = 0; i < src_len - 1; i++) {
11489     SourceChar current = src[i];
11490     SourceChar next = src[i + 1];
11491     if (cache->IsLineTerminatorSequence(current, next)) line_ends->push_back(i);
11492   }
11493 
11494   if (src_len > 0 && cache->IsLineTerminatorSequence(src[src_len - 1], 0)) {
11495     line_ends->push_back(src_len - 1);
11496   }
11497   if (include_ending_line) {
11498     // Include one character beyond the end of script. The rewriter uses that
11499     // position for the implicit return statement.
11500     line_ends->push_back(src_len);
11501   }
11502 }
11503 
CalculateLineEnds(Isolate * isolate,Handle<String> src,bool include_ending_line)11504 Handle<FixedArray> String::CalculateLineEnds(Isolate* isolate,
11505                                              Handle<String> src,
11506                                              bool include_ending_line) {
11507   src = Flatten(isolate, src);
11508   // Rough estimate of line count based on a roughly estimated average
11509   // length of (unpacked) code.
11510   int line_count_estimate = src->length() >> 4;
11511   std::vector<int> line_ends;
11512   line_ends.reserve(line_count_estimate);
11513   { DisallowHeapAllocation no_allocation;  // ensure vectors stay valid.
11514     // Dispatch on type of strings.
11515     String::FlatContent content = src->GetFlatContent();
11516     DCHECK(content.IsFlat());
11517     if (content.IsOneByte()) {
11518       CalculateLineEndsImpl(isolate,
11519                             &line_ends,
11520                             content.ToOneByteVector(),
11521                             include_ending_line);
11522     } else {
11523       CalculateLineEndsImpl(isolate,
11524                             &line_ends,
11525                             content.ToUC16Vector(),
11526                             include_ending_line);
11527     }
11528   }
11529   int line_count = static_cast<int>(line_ends.size());
11530   Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count);
11531   for (int i = 0; i < line_count; i++) {
11532     array->set(i, Smi::FromInt(line_ends[i]));
11533   }
11534   return array;
11535 }
11536 
11537 
11538 // Compares the contents of two strings by reading and comparing
11539 // int-sized blocks of characters.
11540 template <typename Char>
CompareRawStringContents(const Char * const a,const Char * const b,int length)11541 static inline bool CompareRawStringContents(const Char* const a,
11542                                             const Char* const b,
11543                                             int length) {
11544   return CompareChars(a, b, length) == 0;
11545 }
11546 
11547 
11548 template<typename Chars1, typename Chars2>
11549 class RawStringComparator : public AllStatic {
11550  public:
compare(const Chars1 * a,const Chars2 * b,int len)11551   static inline bool compare(const Chars1* a, const Chars2* b, int len) {
11552     DCHECK(sizeof(Chars1) != sizeof(Chars2));
11553     for (int i = 0; i < len; i++) {
11554       if (a[i] != b[i]) {
11555         return false;
11556       }
11557     }
11558     return true;
11559   }
11560 };
11561 
11562 
11563 template<>
11564 class RawStringComparator<uint16_t, uint16_t> {
11565  public:
compare(const uint16_t * a,const uint16_t * b,int len)11566   static inline bool compare(const uint16_t* a, const uint16_t* b, int len) {
11567     return CompareRawStringContents(a, b, len);
11568   }
11569 };
11570 
11571 
11572 template<>
11573 class RawStringComparator<uint8_t, uint8_t> {
11574  public:
compare(const uint8_t * a,const uint8_t * b,int len)11575   static inline bool compare(const uint8_t* a, const uint8_t* b, int len) {
11576     return CompareRawStringContents(a, b, len);
11577   }
11578 };
11579 
11580 
11581 class StringComparator {
11582   class State {
11583    public:
State()11584     State() : is_one_byte_(true), length_(0), buffer8_(nullptr) {}
11585 
Init(String * string)11586     void Init(String* string) {
11587       ConsString* cons_string = String::VisitFlat(this, string);
11588       iter_.Reset(cons_string);
11589       if (cons_string != nullptr) {
11590         int offset;
11591         string = iter_.Next(&offset);
11592         String::VisitFlat(this, string, offset);
11593       }
11594     }
11595 
VisitOneByteString(const uint8_t * chars,int length)11596     inline void VisitOneByteString(const uint8_t* chars, int length) {
11597       is_one_byte_ = true;
11598       buffer8_ = chars;
11599       length_ = length;
11600     }
11601 
VisitTwoByteString(const uint16_t * chars,int length)11602     inline void VisitTwoByteString(const uint16_t* chars, int length) {
11603       is_one_byte_ = false;
11604       buffer16_ = chars;
11605       length_ = length;
11606     }
11607 
Advance(int consumed)11608     void Advance(int consumed) {
11609       DCHECK(consumed <= length_);
11610       // Still in buffer.
11611       if (length_ != consumed) {
11612         if (is_one_byte_) {
11613           buffer8_ += consumed;
11614         } else {
11615           buffer16_ += consumed;
11616         }
11617         length_ -= consumed;
11618         return;
11619       }
11620       // Advance state.
11621       int offset;
11622       String* next = iter_.Next(&offset);
11623       DCHECK_EQ(0, offset);
11624       DCHECK_NOT_NULL(next);
11625       String::VisitFlat(this, next);
11626     }
11627 
11628     ConsStringIterator iter_;
11629     bool is_one_byte_;
11630     int length_;
11631     union {
11632       const uint8_t* buffer8_;
11633       const uint16_t* buffer16_;
11634     };
11635 
11636    private:
11637     DISALLOW_COPY_AND_ASSIGN(State);
11638   };
11639 
11640  public:
StringComparator()11641   inline StringComparator() {}
11642 
11643   template<typename Chars1, typename Chars2>
Equals(State * state_1,State * state_2,int to_check)11644   static inline bool Equals(State* state_1, State* state_2, int to_check) {
11645     const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_);
11646     const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_);
11647     return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check);
11648   }
11649 
Equals(String * string_1,String * string_2)11650   bool Equals(String* string_1, String* string_2) {
11651     int length = string_1->length();
11652     state_1_.Init(string_1);
11653     state_2_.Init(string_2);
11654     while (true) {
11655       int to_check = Min(state_1_.length_, state_2_.length_);
11656       DCHECK(to_check > 0 && to_check <= length);
11657       bool is_equal;
11658       if (state_1_.is_one_byte_) {
11659         if (state_2_.is_one_byte_) {
11660           is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check);
11661         } else {
11662           is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check);
11663         }
11664       } else {
11665         if (state_2_.is_one_byte_) {
11666           is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check);
11667         } else {
11668           is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check);
11669         }
11670       }
11671       // Looping done.
11672       if (!is_equal) return false;
11673       length -= to_check;
11674       // Exit condition. Strings are equal.
11675       if (length == 0) return true;
11676       state_1_.Advance(to_check);
11677       state_2_.Advance(to_check);
11678     }
11679   }
11680 
11681  private:
11682   State state_1_;
11683   State state_2_;
11684 
11685   DISALLOW_COPY_AND_ASSIGN(StringComparator);
11686 };
11687 
11688 
SlowEquals(String * other)11689 bool String::SlowEquals(String* other) {
11690   DisallowHeapAllocation no_gc;
11691   // Fast check: negative check with lengths.
11692   int len = length();
11693   if (len != other->length()) return false;
11694   if (len == 0) return true;
11695 
11696   // Fast check: if at least one ThinString is involved, dereference it/them
11697   // and restart.
11698   if (this->IsThinString() || other->IsThinString()) {
11699     if (other->IsThinString()) other = ThinString::cast(other)->actual();
11700     if (this->IsThinString()) {
11701       return ThinString::cast(this)->actual()->Equals(other);
11702     } else {
11703       return this->Equals(other);
11704     }
11705   }
11706 
11707   // Fast check: if hash code is computed for both strings
11708   // a fast negative check can be performed.
11709   if (HasHashCode() && other->HasHashCode()) {
11710 #ifdef ENABLE_SLOW_DCHECKS
11711     if (FLAG_enable_slow_asserts) {
11712       if (Hash() != other->Hash()) {
11713         bool found_difference = false;
11714         for (int i = 0; i < len; i++) {
11715           if (Get(i) != other->Get(i)) {
11716             found_difference = true;
11717             break;
11718           }
11719         }
11720         DCHECK(found_difference);
11721       }
11722     }
11723 #endif
11724     if (Hash() != other->Hash()) return false;
11725   }
11726 
11727   // We know the strings are both non-empty. Compare the first chars
11728   // before we try to flatten the strings.
11729   if (this->Get(0) != other->Get(0)) return false;
11730 
11731   if (IsSeqOneByteString() && other->IsSeqOneByteString()) {
11732     const uint8_t* str1 = SeqOneByteString::cast(this)->GetChars();
11733     const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars();
11734     return CompareRawStringContents(str1, str2, len);
11735   }
11736 
11737   StringComparator comparator;
11738   return comparator.Equals(this, other);
11739 }
11740 
SlowEquals(Isolate * isolate,Handle<String> one,Handle<String> two)11741 bool String::SlowEquals(Isolate* isolate, Handle<String> one,
11742                         Handle<String> two) {
11743   // Fast check: negative check with lengths.
11744   int one_length = one->length();
11745   if (one_length != two->length()) return false;
11746   if (one_length == 0) return true;
11747 
11748   // Fast check: if at least one ThinString is involved, dereference it/them
11749   // and restart.
11750   if (one->IsThinString() || two->IsThinString()) {
11751     if (one->IsThinString())
11752       one = handle(ThinString::cast(*one)->actual(), isolate);
11753     if (two->IsThinString())
11754       two = handle(ThinString::cast(*two)->actual(), isolate);
11755     return String::Equals(isolate, one, two);
11756   }
11757 
11758   // Fast check: if hash code is computed for both strings
11759   // a fast negative check can be performed.
11760   if (one->HasHashCode() && two->HasHashCode()) {
11761 #ifdef ENABLE_SLOW_DCHECKS
11762     if (FLAG_enable_slow_asserts) {
11763       if (one->Hash() != two->Hash()) {
11764         bool found_difference = false;
11765         for (int i = 0; i < one_length; i++) {
11766           if (one->Get(i) != two->Get(i)) {
11767             found_difference = true;
11768             break;
11769           }
11770         }
11771         DCHECK(found_difference);
11772       }
11773     }
11774 #endif
11775     if (one->Hash() != two->Hash()) return false;
11776   }
11777 
11778   // We know the strings are both non-empty. Compare the first chars
11779   // before we try to flatten the strings.
11780   if (one->Get(0) != two->Get(0)) return false;
11781 
11782   one = String::Flatten(isolate, one);
11783   two = String::Flatten(isolate, two);
11784 
11785   DisallowHeapAllocation no_gc;
11786   String::FlatContent flat1 = one->GetFlatContent();
11787   String::FlatContent flat2 = two->GetFlatContent();
11788 
11789   if (flat1.IsOneByte() && flat2.IsOneByte()) {
11790       return CompareRawStringContents(flat1.ToOneByteVector().start(),
11791                                       flat2.ToOneByteVector().start(),
11792                                       one_length);
11793   } else {
11794     for (int i = 0; i < one_length; i++) {
11795       if (flat1.Get(i) != flat2.Get(i)) return false;
11796     }
11797     return true;
11798   }
11799 }
11800 
11801 
11802 // static
Compare(Isolate * isolate,Handle<String> x,Handle<String> y)11803 ComparisonResult String::Compare(Isolate* isolate, Handle<String> x,
11804                                  Handle<String> y) {
11805   // A few fast case tests before we flatten.
11806   if (x.is_identical_to(y)) {
11807     return ComparisonResult::kEqual;
11808   } else if (y->length() == 0) {
11809     return x->length() == 0 ? ComparisonResult::kEqual
11810                             : ComparisonResult::kGreaterThan;
11811   } else if (x->length() == 0) {
11812     return ComparisonResult::kLessThan;
11813   }
11814 
11815   int const d = x->Get(0) - y->Get(0);
11816   if (d < 0) {
11817     return ComparisonResult::kLessThan;
11818   } else if (d > 0) {
11819     return ComparisonResult::kGreaterThan;
11820   }
11821 
11822   // Slow case.
11823   x = String::Flatten(isolate, x);
11824   y = String::Flatten(isolate, y);
11825 
11826   DisallowHeapAllocation no_gc;
11827   ComparisonResult result = ComparisonResult::kEqual;
11828   int prefix_length = x->length();
11829   if (y->length() < prefix_length) {
11830     prefix_length = y->length();
11831     result = ComparisonResult::kGreaterThan;
11832   } else if (y->length() > prefix_length) {
11833     result = ComparisonResult::kLessThan;
11834   }
11835   int r;
11836   String::FlatContent x_content = x->GetFlatContent();
11837   String::FlatContent y_content = y->GetFlatContent();
11838   if (x_content.IsOneByte()) {
11839     Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
11840     if (y_content.IsOneByte()) {
11841       Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11842       r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11843     } else {
11844       Vector<const uc16> y_chars = y_content.ToUC16Vector();
11845       r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11846     }
11847   } else {
11848     Vector<const uc16> x_chars = x_content.ToUC16Vector();
11849     if (y_content.IsOneByte()) {
11850       Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11851       r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11852     } else {
11853       Vector<const uc16> y_chars = y_content.ToUC16Vector();
11854       r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11855     }
11856   }
11857   if (r < 0) {
11858     result = ComparisonResult::kLessThan;
11859   } else if (r > 0) {
11860     result = ComparisonResult::kGreaterThan;
11861   }
11862   return result;
11863 }
11864 
IndexOf(Isolate * isolate,Handle<Object> receiver,Handle<Object> search,Handle<Object> position)11865 Object* String::IndexOf(Isolate* isolate, Handle<Object> receiver,
11866                         Handle<Object> search, Handle<Object> position) {
11867   if (receiver->IsNullOrUndefined(isolate)) {
11868     THROW_NEW_ERROR_RETURN_FAILURE(
11869         isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
11870                               isolate->factory()->NewStringFromAsciiChecked(
11871                                   "String.prototype.indexOf")));
11872   }
11873   Handle<String> receiver_string;
11874   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string,
11875                                      Object::ToString(isolate, receiver));
11876 
11877   Handle<String> search_string;
11878   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
11879                                      Object::ToString(isolate, search));
11880 
11881   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11882                                      Object::ToInteger(isolate, position));
11883 
11884   uint32_t index = receiver_string->ToValidIndex(*position);
11885   return Smi::FromInt(
11886       String::IndexOf(isolate, receiver_string, search_string, index));
11887 }
11888 
11889 namespace {
11890 
11891 template <typename T>
SearchString(Isolate * isolate,String::FlatContent receiver_content,Vector<T> pat_vector,int start_index)11892 int SearchString(Isolate* isolate, String::FlatContent receiver_content,
11893                  Vector<T> pat_vector, int start_index) {
11894   if (receiver_content.IsOneByte()) {
11895     return SearchString(isolate, receiver_content.ToOneByteVector(), pat_vector,
11896                         start_index);
11897   }
11898   return SearchString(isolate, receiver_content.ToUC16Vector(), pat_vector,
11899                       start_index);
11900 }
11901 
11902 }  // namespace
11903 
IndexOf(Isolate * isolate,Handle<String> receiver,Handle<String> search,int start_index)11904 int String::IndexOf(Isolate* isolate, Handle<String> receiver,
11905                     Handle<String> search, int start_index) {
11906   DCHECK_LE(0, start_index);
11907   DCHECK(start_index <= receiver->length());
11908 
11909   uint32_t search_length = search->length();
11910   if (search_length == 0) return start_index;
11911 
11912   uint32_t receiver_length = receiver->length();
11913   if (start_index + search_length > receiver_length) return -1;
11914 
11915   receiver = String::Flatten(isolate, receiver);
11916   search = String::Flatten(isolate, search);
11917 
11918   DisallowHeapAllocation no_gc;  // ensure vectors stay valid
11919   // Extract flattened substrings of cons strings before getting encoding.
11920   String::FlatContent receiver_content = receiver->GetFlatContent();
11921   String::FlatContent search_content = search->GetFlatContent();
11922 
11923   // dispatch on type of strings
11924   if (search_content.IsOneByte()) {
11925     Vector<const uint8_t> pat_vector = search_content.ToOneByteVector();
11926     return SearchString<const uint8_t>(isolate, receiver_content, pat_vector,
11927                                        start_index);
11928   }
11929   Vector<const uc16> pat_vector = search_content.ToUC16Vector();
11930   return SearchString<const uc16>(isolate, receiver_content, pat_vector,
11931                                   start_index);
11932 }
11933 
GetSubstitution(Isolate * isolate,Match * match,Handle<String> replacement,int start_index)11934 MaybeHandle<String> String::GetSubstitution(Isolate* isolate, Match* match,
11935                                             Handle<String> replacement,
11936                                             int start_index) {
11937   DCHECK_GE(start_index, 0);
11938 
11939   Factory* factory = isolate->factory();
11940 
11941   const int replacement_length = replacement->length();
11942   const int captures_length = match->CaptureCount();
11943 
11944   replacement = String::Flatten(isolate, replacement);
11945 
11946   Handle<String> dollar_string =
11947       factory->LookupSingleCharacterStringFromCode('$');
11948   int next_dollar_ix =
11949       String::IndexOf(isolate, replacement, dollar_string, start_index);
11950   if (next_dollar_ix < 0) {
11951     return replacement;
11952   }
11953 
11954   IncrementalStringBuilder builder(isolate);
11955 
11956   if (next_dollar_ix > 0) {
11957     builder.AppendString(factory->NewSubString(replacement, 0, next_dollar_ix));
11958   }
11959 
11960   while (true) {
11961     const int peek_ix = next_dollar_ix + 1;
11962     if (peek_ix >= replacement_length) {
11963       builder.AppendCharacter('$');
11964       return builder.Finish();
11965     }
11966 
11967     int continue_from_ix = -1;
11968     const uint16_t peek = replacement->Get(peek_ix);
11969     switch (peek) {
11970       case '$':  // $$
11971         builder.AppendCharacter('$');
11972         continue_from_ix = peek_ix + 1;
11973         break;
11974       case '&':  // $& - match
11975         builder.AppendString(match->GetMatch());
11976         continue_from_ix = peek_ix + 1;
11977         break;
11978       case '`':  // $` - prefix
11979         builder.AppendString(match->GetPrefix());
11980         continue_from_ix = peek_ix + 1;
11981         break;
11982       case '\'':  // $' - suffix
11983         builder.AppendString(match->GetSuffix());
11984         continue_from_ix = peek_ix + 1;
11985         break;
11986       case '0':
11987       case '1':
11988       case '2':
11989       case '3':
11990       case '4':
11991       case '5':
11992       case '6':
11993       case '7':
11994       case '8':
11995       case '9': {
11996         // Valid indices are $1 .. $9, $01 .. $09 and $10 .. $99
11997         int scaled_index = (peek - '0');
11998         int advance = 1;
11999 
12000         if (peek_ix + 1 < replacement_length) {
12001           const uint16_t next_peek = replacement->Get(peek_ix + 1);
12002           if (next_peek >= '0' && next_peek <= '9') {
12003             const int new_scaled_index = scaled_index * 10 + (next_peek - '0');
12004             if (new_scaled_index < captures_length) {
12005               scaled_index = new_scaled_index;
12006               advance = 2;
12007             }
12008           }
12009         }
12010 
12011         if (scaled_index == 0 || scaled_index >= captures_length) {
12012           builder.AppendCharacter('$');
12013           continue_from_ix = peek_ix;
12014           break;
12015         }
12016 
12017         bool capture_exists;
12018         Handle<String> capture;
12019         ASSIGN_RETURN_ON_EXCEPTION(
12020             isolate, capture, match->GetCapture(scaled_index, &capture_exists),
12021             String);
12022         if (capture_exists) builder.AppendString(capture);
12023         continue_from_ix = peek_ix + advance;
12024         break;
12025       }
12026       case '<': {  // $<name> - named capture
12027         typedef String::Match::CaptureState CaptureState;
12028 
12029         if (!match->HasNamedCaptures()) {
12030           builder.AppendCharacter('$');
12031           continue_from_ix = peek_ix;
12032           break;
12033         }
12034 
12035         Handle<String> bracket_string =
12036             factory->LookupSingleCharacterStringFromCode('>');
12037         const int closing_bracket_ix =
12038             String::IndexOf(isolate, replacement, bracket_string, peek_ix + 1);
12039 
12040         if (closing_bracket_ix == -1) {
12041           // No closing bracket was found, treat '$<' as a string literal.
12042           builder.AppendCharacter('$');
12043           continue_from_ix = peek_ix;
12044           break;
12045         }
12046 
12047         Handle<String> capture_name =
12048             factory->NewSubString(replacement, peek_ix + 1, closing_bracket_ix);
12049         Handle<String> capture;
12050         CaptureState capture_state;
12051         ASSIGN_RETURN_ON_EXCEPTION(
12052             isolate, capture,
12053             match->GetNamedCapture(capture_name, &capture_state), String);
12054 
12055         switch (capture_state) {
12056           case CaptureState::INVALID:
12057           case CaptureState::UNMATCHED:
12058             break;
12059           case CaptureState::MATCHED:
12060             builder.AppendString(capture);
12061             break;
12062         }
12063 
12064         continue_from_ix = closing_bracket_ix + 1;
12065         break;
12066       }
12067       default:
12068         builder.AppendCharacter('$');
12069         continue_from_ix = peek_ix;
12070         break;
12071     }
12072 
12073     // Go the the next $ in the replacement.
12074     // TODO(jgruber): Single-char lookups could be much more efficient.
12075     DCHECK_NE(continue_from_ix, -1);
12076     next_dollar_ix =
12077         String::IndexOf(isolate, replacement, dollar_string, continue_from_ix);
12078 
12079     // Return if there are no more $ characters in the replacement. If we
12080     // haven't reached the end, we need to append the suffix.
12081     if (next_dollar_ix < 0) {
12082       if (continue_from_ix < replacement_length) {
12083         builder.AppendString(factory->NewSubString(
12084             replacement, continue_from_ix, replacement_length));
12085       }
12086       return builder.Finish();
12087     }
12088 
12089     // Append substring between the previous and the next $ character.
12090     if (next_dollar_ix > continue_from_ix) {
12091       builder.AppendString(
12092           factory->NewSubString(replacement, continue_from_ix, next_dollar_ix));
12093     }
12094   }
12095 
12096   UNREACHABLE();
12097 }
12098 
12099 namespace {  // for String.Prototype.lastIndexOf
12100 
12101 template <typename schar, typename pchar>
StringMatchBackwards(Vector<const schar> subject,Vector<const pchar> pattern,int idx)12102 int StringMatchBackwards(Vector<const schar> subject,
12103                          Vector<const pchar> pattern, int idx) {
12104   int pattern_length = pattern.length();
12105   DCHECK_GE(pattern_length, 1);
12106   DCHECK(idx + pattern_length <= subject.length());
12107 
12108   if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
12109     for (int i = 0; i < pattern_length; i++) {
12110       uc16 c = pattern[i];
12111       if (c > String::kMaxOneByteCharCode) {
12112         return -1;
12113       }
12114     }
12115   }
12116 
12117   pchar pattern_first_char = pattern[0];
12118   for (int i = idx; i >= 0; i--) {
12119     if (subject[i] != pattern_first_char) continue;
12120     int j = 1;
12121     while (j < pattern_length) {
12122       if (pattern[j] != subject[i + j]) {
12123         break;
12124       }
12125       j++;
12126     }
12127     if (j == pattern_length) {
12128       return i;
12129     }
12130   }
12131   return -1;
12132 }
12133 
12134 }  // namespace
12135 
LastIndexOf(Isolate * isolate,Handle<Object> receiver,Handle<Object> search,Handle<Object> position)12136 Object* String::LastIndexOf(Isolate* isolate, Handle<Object> receiver,
12137                             Handle<Object> search, Handle<Object> position) {
12138   if (receiver->IsNullOrUndefined(isolate)) {
12139     THROW_NEW_ERROR_RETURN_FAILURE(
12140         isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
12141                               isolate->factory()->NewStringFromAsciiChecked(
12142                                   "String.prototype.lastIndexOf")));
12143   }
12144   Handle<String> receiver_string;
12145   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string,
12146                                      Object::ToString(isolate, receiver));
12147 
12148   Handle<String> search_string;
12149   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
12150                                      Object::ToString(isolate, search));
12151 
12152   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
12153                                      Object::ToNumber(isolate, position));
12154 
12155   uint32_t start_index;
12156 
12157   if (position->IsNaN()) {
12158     start_index = receiver_string->length();
12159   } else {
12160     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
12161                                        Object::ToInteger(isolate, position));
12162     start_index = receiver_string->ToValidIndex(*position);
12163   }
12164 
12165   uint32_t pattern_length = search_string->length();
12166   uint32_t receiver_length = receiver_string->length();
12167 
12168   if (start_index + pattern_length > receiver_length) {
12169     start_index = receiver_length - pattern_length;
12170   }
12171 
12172   if (pattern_length == 0) {
12173     return Smi::FromInt(start_index);
12174   }
12175 
12176   receiver_string = String::Flatten(isolate, receiver_string);
12177   search_string = String::Flatten(isolate, search_string);
12178 
12179   int last_index = -1;
12180   DisallowHeapAllocation no_gc;  // ensure vectors stay valid
12181 
12182   String::FlatContent receiver_content = receiver_string->GetFlatContent();
12183   String::FlatContent search_content = search_string->GetFlatContent();
12184 
12185   if (search_content.IsOneByte()) {
12186     Vector<const uint8_t> pat_vector = search_content.ToOneByteVector();
12187     if (receiver_content.IsOneByte()) {
12188       last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
12189                                         pat_vector, start_index);
12190     } else {
12191       last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
12192                                         pat_vector, start_index);
12193     }
12194   } else {
12195     Vector<const uc16> pat_vector = search_content.ToUC16Vector();
12196     if (receiver_content.IsOneByte()) {
12197       last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
12198                                         pat_vector, start_index);
12199     } else {
12200       last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
12201                                         pat_vector, start_index);
12202     }
12203   }
12204   return Smi::FromInt(last_index);
12205 }
12206 
IsUtf8EqualTo(Vector<const char> str,bool allow_prefix_match)12207 bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
12208   int slen = length();
12209   // Can't check exact length equality, but we can check bounds.
12210   int str_len = str.length();
12211   if (!allow_prefix_match &&
12212       (str_len < slen ||
12213           str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) {
12214     return false;
12215   }
12216 
12217   int i = 0;
12218   unibrow::Utf8Iterator it = unibrow::Utf8Iterator(str);
12219   while (i < slen && !it.Done()) {
12220     if (Get(i++) != *it) return false;
12221     ++it;
12222   }
12223 
12224   return (allow_prefix_match || i == slen) && it.Done();
12225 }
12226 
12227 template <>
IsEqualTo(Vector<const uint8_t> str)12228 bool String::IsEqualTo(Vector<const uint8_t> str) {
12229   return IsOneByteEqualTo(str);
12230 }
12231 
12232 template <>
IsEqualTo(Vector<const uc16> str)12233 bool String::IsEqualTo(Vector<const uc16> str) {
12234   return IsTwoByteEqualTo(str);
12235 }
12236 
IsOneByteEqualTo(Vector<const uint8_t> str)12237 bool String::IsOneByteEqualTo(Vector<const uint8_t> str) {
12238   int slen = length();
12239   if (str.length() != slen) return false;
12240   DisallowHeapAllocation no_gc;
12241   FlatContent content = GetFlatContent();
12242   if (content.IsOneByte()) {
12243     return CompareChars(content.ToOneByteVector().start(),
12244                         str.start(), slen) == 0;
12245   }
12246   for (int i = 0; i < slen; i++) {
12247     if (Get(i) != static_cast<uint16_t>(str[i])) return false;
12248   }
12249   return true;
12250 }
12251 
12252 
IsTwoByteEqualTo(Vector<const uc16> str)12253 bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
12254   int slen = length();
12255   if (str.length() != slen) return false;
12256   DisallowHeapAllocation no_gc;
12257   FlatContent content = GetFlatContent();
12258   if (content.IsTwoByte()) {
12259     return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
12260   }
12261   for (int i = 0; i < slen; i++) {
12262     if (Get(i) != str[i]) return false;
12263   }
12264   return true;
12265 }
12266 
ComputeAndSetHash(Isolate * isolate)12267 uint32_t String::ComputeAndSetHash(Isolate* isolate) {
12268   // Should only be called if hash code has not yet been computed.
12269   DCHECK(!HasHashCode());
12270 
12271   // Store the hash code in the object.
12272   uint32_t field =
12273       IteratingStringHasher::Hash(this, isolate->heap()->HashSeed());
12274   set_hash_field(field);
12275 
12276   // Check the hash code is there.
12277   DCHECK(HasHashCode());
12278   uint32_t result = field >> kHashShift;
12279   DCHECK_NE(result, 0);  // Ensure that the hash value of 0 is never computed.
12280   return result;
12281 }
12282 
12283 
ComputeArrayIndex(uint32_t * index)12284 bool String::ComputeArrayIndex(uint32_t* index) {
12285   int length = this->length();
12286   if (length == 0 || length > kMaxArrayIndexSize) return false;
12287   StringCharacterStream stream(this);
12288   return StringToArrayIndex(&stream, index);
12289 }
12290 
12291 
SlowAsArrayIndex(uint32_t * index)12292 bool String::SlowAsArrayIndex(uint32_t* index) {
12293   if (length() <= kMaxCachedArrayIndexLength) {
12294     Hash();  // force computation of hash code
12295     uint32_t field = hash_field();
12296     if ((field & kIsNotArrayIndexMask) != 0) return false;
12297     // Isolate the array index form the full hash field.
12298     *index = ArrayIndexValueBits::decode(field);
12299     return true;
12300   } else {
12301     return ComputeArrayIndex(index);
12302   }
12303 }
12304 
12305 
Truncate(Handle<SeqString> string,int new_length)12306 Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
12307   if (new_length == 0) return string->GetReadOnlyRoots().empty_string_handle();
12308 
12309   int new_size, old_size;
12310   int old_length = string->length();
12311   if (old_length <= new_length) return string;
12312 
12313   if (string->IsSeqOneByteString()) {
12314     old_size = SeqOneByteString::SizeFor(old_length);
12315     new_size = SeqOneByteString::SizeFor(new_length);
12316   } else {
12317     DCHECK(string->IsSeqTwoByteString());
12318     old_size = SeqTwoByteString::SizeFor(old_length);
12319     new_size = SeqTwoByteString::SizeFor(new_length);
12320   }
12321 
12322   int delta = old_size - new_size;
12323 
12324   Address start_of_string = string->address();
12325   DCHECK_OBJECT_ALIGNED(start_of_string);
12326   DCHECK_OBJECT_ALIGNED(start_of_string + new_size);
12327 
12328   Heap* heap = Heap::FromWritableHeapObject(*string);
12329   // Sizes are pointer size aligned, so that we can use filler objects
12330   // that are a multiple of pointer size.
12331   heap->CreateFillerObjectAt(start_of_string + new_size, delta,
12332                              ClearRecordedSlots::kNo);
12333   // We are storing the new length using release store after creating a filler
12334   // for the left-over space to avoid races with the sweeper thread.
12335   string->synchronized_set_length(new_length);
12336 
12337   return string;
12338 }
12339 
clear_padding()12340 void SeqOneByteString::clear_padding() {
12341   int data_size = SeqString::kHeaderSize + length() * kOneByteSize;
12342   memset(reinterpret_cast<void*>(address() + data_size), 0,
12343          SizeFor(length()) - data_size);
12344 }
12345 
clear_padding()12346 void SeqTwoByteString::clear_padding() {
12347   int data_size = SeqString::kHeaderSize + length() * kUC16Size;
12348   memset(reinterpret_cast<void*>(address() + data_size), 0,
12349          SizeFor(length()) - data_size);
12350 }
12351 
ExternalPayloadSize() const12352 int ExternalString::ExternalPayloadSize() const {
12353   int length_multiplier = IsTwoByteRepresentation() ? i::kShortSize : kCharSize;
12354   return length() * length_multiplier;
12355 }
12356 
MakeArrayIndexHash(uint32_t value,int length)12357 uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
12358   // For array indexes mix the length into the hash as an array index could
12359   // be zero.
12360   DCHECK_GT(length, 0);
12361   DCHECK_LE(length, String::kMaxArrayIndexSize);
12362   DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
12363          (1 << String::kArrayIndexValueBits));
12364 
12365   value <<= String::ArrayIndexValueBits::kShift;
12366   value |= length << String::ArrayIndexLengthBits::kShift;
12367 
12368   DCHECK_EQ(value & String::kIsNotArrayIndexMask, 0);
12369   DCHECK_EQ(length <= String::kMaxCachedArrayIndexLength,
12370             Name::ContainsCachedArrayIndex(value));
12371   return value;
12372 }
12373 
12374 
GetHashField()12375 uint32_t StringHasher::GetHashField() {
12376   if (length_ <= String::kMaxHashCalcLength) {
12377     if (is_array_index_) {
12378       return MakeArrayIndexHash(array_index_, length_);
12379     }
12380     return (GetHashCore(raw_running_hash_) << String::kHashShift) |
12381            String::kIsNotArrayIndexMask;
12382   } else {
12383     return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
12384   }
12385 }
12386 
ComputeUtf8Hash(Vector<const char> chars,uint64_t seed,int * utf16_length_out)12387 uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars, uint64_t seed,
12388                                        int* utf16_length_out) {
12389   int vector_length = chars.length();
12390   // Handle some edge cases
12391   if (vector_length <= 1) {
12392     DCHECK(vector_length == 0 ||
12393            static_cast<uint8_t>(chars.start()[0]) <=
12394                unibrow::Utf8::kMaxOneByteChar);
12395     *utf16_length_out = vector_length;
12396     return HashSequentialString(chars.start(), vector_length, seed);
12397   }
12398 
12399   // Start with a fake length which won't affect computation.
12400   // It will be updated later.
12401   StringHasher hasher(String::kMaxArrayIndexSize, seed);
12402   DCHECK(hasher.is_array_index_);
12403 
12404   unibrow::Utf8Iterator it = unibrow::Utf8Iterator(chars);
12405   int utf16_length = 0;
12406   bool is_index = true;
12407 
12408   while (utf16_length < String::kMaxHashCalcLength && !it.Done()) {
12409     utf16_length++;
12410     uint16_t c = *it;
12411     ++it;
12412     hasher.AddCharacter(c);
12413     if (is_index) is_index = hasher.UpdateIndex(c);
12414   }
12415 
12416   // Now that hashing is done, we just need to calculate utf16_length
12417   while (!it.Done()) {
12418     ++it;
12419     utf16_length++;
12420   }
12421 
12422   *utf16_length_out = utf16_length;
12423   // Must set length here so that hash computation is correct.
12424   hasher.length_ = utf16_length;
12425   return hasher.GetHashField();
12426 }
12427 
12428 
VisitConsString(ConsString * cons_string)12429 void IteratingStringHasher::VisitConsString(ConsString* cons_string) {
12430   // Run small ConsStrings through ConsStringIterator.
12431   if (cons_string->length() < 64) {
12432     ConsStringIterator iter(cons_string);
12433     int offset;
12434     String* string;
12435     while (nullptr != (string = iter.Next(&offset))) {
12436       DCHECK_EQ(0, offset);
12437       String::VisitFlat(this, string, 0);
12438     }
12439     return;
12440   }
12441   // Slow case.
12442   const int max_length = String::kMaxHashCalcLength;
12443   int length = std::min(cons_string->length(), max_length);
12444   if (cons_string->HasOnlyOneByteChars()) {
12445     uint8_t* buffer = new uint8_t[length];
12446     String::WriteToFlat(cons_string, buffer, 0, length);
12447     AddCharacters(buffer, length);
12448     delete[] buffer;
12449   } else {
12450     uint16_t* buffer = new uint16_t[length];
12451     String::WriteToFlat(cons_string, buffer, 0, length);
12452     AddCharacters(buffer, length);
12453     delete[] buffer;
12454   }
12455 }
12456 
12457 
PrintOn(FILE * file)12458 void String::PrintOn(FILE* file) {
12459   int length = this->length();
12460   for (int i = 0; i < length; i++) {
12461     PrintF(file, "%c", Get(i));
12462   }
12463 }
12464 
12465 
Hash()12466 int Map::Hash() {
12467   // For performance reasons we only hash the 3 most variable fields of a map:
12468   // constructor, prototype and bit_field2. For predictability reasons we
12469   // use objects' offsets in respective pages for hashing instead of raw
12470   // addresses.
12471 
12472   // Shift away the tag.
12473   int hash = ObjectAddressForHashing(GetConstructor()) >> 2;
12474 
12475   // XOR-ing the prototype and constructor directly yields too many zero bits
12476   // when the two pointers are close (which is fairly common).
12477   // To avoid this we shift the prototype bits relatively to the constructor.
12478   hash ^= ObjectAddressForHashing(prototype()) << (32 - kPageSizeBits);
12479 
12480   return hash ^ (hash >> 16) ^ bit_field2();
12481 }
12482 
12483 
12484 namespace {
12485 
CheckEquivalent(const Map * first,const Map * second)12486 bool CheckEquivalent(const Map* first, const Map* second) {
12487   return first->GetConstructor() == second->GetConstructor() &&
12488          first->prototype() == second->prototype() &&
12489          first->instance_type() == second->instance_type() &&
12490          first->bit_field() == second->bit_field() &&
12491          first->is_extensible() == second->is_extensible() &&
12492          first->new_target_is_base() == second->new_target_is_base() &&
12493          first->has_hidden_prototype() == second->has_hidden_prototype();
12494 }
12495 
12496 }  // namespace
12497 
EquivalentToForTransition(const Map * other) const12498 bool Map::EquivalentToForTransition(const Map* other) const {
12499   if (!CheckEquivalent(this, other)) return false;
12500   if (instance_type() == JS_FUNCTION_TYPE) {
12501     // JSFunctions require more checks to ensure that sloppy function is
12502     // not equivalent to strict function.
12503     int nof = Min(NumberOfOwnDescriptors(), other->NumberOfOwnDescriptors());
12504     return instance_descriptors()->IsEqualUpTo(other->instance_descriptors(),
12505                                                nof);
12506   }
12507   return true;
12508 }
12509 
EquivalentToForElementsKindTransition(const Map * other) const12510 bool Map::EquivalentToForElementsKindTransition(const Map* other) const {
12511   if (!EquivalentToForTransition(other)) return false;
12512 #ifdef DEBUG
12513   // Ensure that we don't try to generate elements kind transitions from maps
12514   // with fields that may be generalized in-place. This must already be handled
12515   // during addition of a new field.
12516   DescriptorArray* descriptors = instance_descriptors();
12517   int nof = NumberOfOwnDescriptors();
12518   for (int i = 0; i < nof; i++) {
12519     PropertyDetails details = descriptors->GetDetails(i);
12520     if (details.location() == kField) {
12521       DCHECK(!IsInplaceGeneralizableField(details.constness(),
12522                                           details.representation(),
12523                                           descriptors->GetFieldType(i)));
12524     }
12525   }
12526 #endif
12527   return true;
12528 }
12529 
EquivalentToForNormalization(const Map * other,PropertyNormalizationMode mode) const12530 bool Map::EquivalentToForNormalization(const Map* other,
12531                                        PropertyNormalizationMode mode) const {
12532   int properties =
12533       mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other->GetInObjectProperties();
12534   return CheckEquivalent(this, other) && bit_field2() == other->bit_field2() &&
12535          GetInObjectProperties() == properties &&
12536          JSObject::GetEmbedderFieldCount(this) ==
12537              JSObject::GetEmbedderFieldCount(other);
12538 }
12539 
12540 
MarkForOptimization(ConcurrencyMode mode)12541 void JSFunction::MarkForOptimization(ConcurrencyMode mode) {
12542   Isolate* isolate = GetIsolate();
12543   if (!isolate->concurrent_recompilation_enabled() ||
12544       isolate->bootstrapper()->IsActive()) {
12545     mode = ConcurrencyMode::kNotConcurrent;
12546   }
12547 
12548   DCHECK(!is_compiled() || IsInterpreted());
12549   DCHECK(shared()->IsInterpreted());
12550   DCHECK(!IsOptimized());
12551   DCHECK(!HasOptimizedCode());
12552   DCHECK(shared()->allows_lazy_compilation() ||
12553          !shared()->optimization_disabled());
12554 
12555   if (mode == ConcurrencyMode::kConcurrent) {
12556     if (IsInOptimizationQueue()) {
12557       if (FLAG_trace_concurrent_recompilation) {
12558         PrintF("  ** Not marking ");
12559         ShortPrint();
12560         PrintF(" -- already in optimization queue.\n");
12561       }
12562       return;
12563     }
12564     if (FLAG_trace_concurrent_recompilation) {
12565       PrintF("  ** Marking ");
12566       ShortPrint();
12567       PrintF(" for concurrent recompilation.\n");
12568     }
12569   }
12570 
12571   SetOptimizationMarker(mode == ConcurrencyMode::kConcurrent
12572                             ? OptimizationMarker::kCompileOptimizedConcurrent
12573                             : OptimizationMarker::kCompileOptimized);
12574 }
12575 
12576 // static
EnsureFeedbackVector(Handle<JSFunction> function)12577 void JSFunction::EnsureFeedbackVector(Handle<JSFunction> function) {
12578   Isolate* const isolate = function->GetIsolate();
12579   if (function->feedback_cell()->value()->IsUndefined(isolate)) {
12580     Handle<SharedFunctionInfo> shared(function->shared(), isolate);
12581     if (!shared->HasAsmWasmData()) {
12582       Handle<FeedbackVector> feedback_vector =
12583           FeedbackVector::New(isolate, shared);
12584       if (function->feedback_cell() == isolate->heap()->many_closures_cell()) {
12585         Handle<FeedbackCell> feedback_cell =
12586             isolate->factory()->NewOneClosureCell(feedback_vector);
12587         function->set_feedback_cell(*feedback_cell);
12588       } else {
12589         function->feedback_cell()->set_value(*feedback_vector);
12590       }
12591     }
12592   }
12593 }
12594 
GetMinInobjectSlack(Map * map,void * data)12595 static void GetMinInobjectSlack(Map* map, void* data) {
12596   int slack = map->UnusedPropertyFields();
12597   if (*reinterpret_cast<int*>(data) > slack) {
12598     *reinterpret_cast<int*>(data) = slack;
12599   }
12600 }
12601 
InstanceSizeFromSlack(int slack) const12602 int Map::InstanceSizeFromSlack(int slack) const {
12603   return instance_size() - slack * kPointerSize;
12604 }
12605 
ShrinkInstanceSize(Map * map,void * data)12606 static void ShrinkInstanceSize(Map* map, void* data) {
12607   int slack = *reinterpret_cast<int*>(data);
12608   DCHECK_GE(slack, 0);
12609 #ifdef DEBUG
12610   int old_visitor_id = Map::GetVisitorId(map);
12611   int new_unused = map->UnusedPropertyFields() - slack;
12612 #endif
12613   map->set_instance_size(map->InstanceSizeFromSlack(slack));
12614   map->set_construction_counter(Map::kNoSlackTracking);
12615   DCHECK_EQ(old_visitor_id, Map::GetVisitorId(map));
12616   DCHECK_EQ(new_unused, map->UnusedPropertyFields());
12617 }
12618 
StopSlackTracking(Map * map,void * data)12619 static void StopSlackTracking(Map* map, void* data) {
12620   map->set_construction_counter(Map::kNoSlackTracking);
12621 }
12622 
ComputeMinObjectSlack(Isolate * isolate)12623 int Map::ComputeMinObjectSlack(Isolate* isolate) {
12624   DisallowHeapAllocation no_gc;
12625   // Has to be an initial map.
12626   DCHECK(GetBackPointer()->IsUndefined(isolate));
12627 
12628   int slack = UnusedPropertyFields();
12629   TransitionsAccessor transitions(isolate, this, &no_gc);
12630   transitions.TraverseTransitionTree(&GetMinInobjectSlack, &slack);
12631   return slack;
12632 }
12633 
CompleteInobjectSlackTracking(Isolate * isolate)12634 void Map::CompleteInobjectSlackTracking(Isolate* isolate) {
12635   DisallowHeapAllocation no_gc;
12636   // Has to be an initial map.
12637   DCHECK(GetBackPointer()->IsUndefined(isolate));
12638 
12639   int slack = ComputeMinObjectSlack(isolate);
12640   TransitionsAccessor transitions(isolate, this, &no_gc);
12641   if (slack != 0) {
12642     // Resize the initial map and all maps in its transition tree.
12643     transitions.TraverseTransitionTree(&ShrinkInstanceSize, &slack);
12644   } else {
12645     transitions.TraverseTransitionTree(&StopSlackTracking, nullptr);
12646   }
12647 }
12648 
12649 
PrototypeBenefitsFromNormalization(Handle<JSObject> object)12650 static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) {
12651   DisallowHeapAllocation no_gc;
12652   if (!object->HasFastProperties()) return false;
12653   if (object->IsJSGlobalProxy()) return false;
12654   if (object->GetIsolate()->bootstrapper()->IsActive()) return false;
12655   return !object->map()->is_prototype_map() ||
12656          !object->map()->should_be_fast_prototype_map();
12657 }
12658 
12659 // static
MakePrototypesFast(Handle<Object> receiver,WhereToStart where_to_start,Isolate * isolate)12660 void JSObject::MakePrototypesFast(Handle<Object> receiver,
12661                                   WhereToStart where_to_start,
12662                                   Isolate* isolate) {
12663   if (!receiver->IsJSReceiver()) return;
12664   for (PrototypeIterator iter(isolate, Handle<JSReceiver>::cast(receiver),
12665                               where_to_start);
12666        !iter.IsAtEnd(); iter.Advance()) {
12667     Handle<Object> current = PrototypeIterator::GetCurrent(iter);
12668     if (!current->IsJSObject()) return;
12669     Handle<JSObject> current_obj = Handle<JSObject>::cast(current);
12670     Map* current_map = current_obj->map();
12671     if (current_map->is_prototype_map()) {
12672       // If the map is already marked as should be fast, we're done. Its
12673       // prototypes will have been marked already as well.
12674       if (current_map->should_be_fast_prototype_map()) return;
12675       Handle<Map> map(current_map, isolate);
12676       Map::SetShouldBeFastPrototypeMap(map, true, isolate);
12677       JSObject::OptimizeAsPrototype(current_obj);
12678     }
12679   }
12680 }
12681 
12682 // static
OptimizeAsPrototype(Handle<JSObject> object,bool enable_setup_mode)12683 void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
12684                                    bool enable_setup_mode) {
12685   if (object->IsJSGlobalObject()) return;
12686   if (enable_setup_mode && PrototypeBenefitsFromNormalization(object)) {
12687     // First normalize to ensure all JSFunctions are DATA_CONSTANT.
12688     JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0,
12689                                   "NormalizeAsPrototype");
12690   }
12691   if (object->map()->is_prototype_map()) {
12692     if (object->map()->should_be_fast_prototype_map() &&
12693         !object->HasFastProperties()) {
12694       JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype");
12695     }
12696   } else {
12697     Handle<Map> new_map = Map::Copy(object->GetIsolate(),
12698                                     handle(object->map(), object->GetIsolate()),
12699                                     "CopyAsPrototype");
12700     JSObject::MigrateToMap(object, new_map);
12701     object->map()->set_is_prototype_map(true);
12702 
12703     // Replace the pointer to the exact constructor with the Object function
12704     // from the same context if undetectable from JS. This is to avoid keeping
12705     // memory alive unnecessarily.
12706     Object* maybe_constructor = object->map()->GetConstructor();
12707     if (maybe_constructor->IsJSFunction()) {
12708       JSFunction* constructor = JSFunction::cast(maybe_constructor);
12709       if (!constructor->shared()->IsApiFunction()) {
12710         Context* context = constructor->context()->native_context();
12711         JSFunction* object_function = context->object_function();
12712         object->map()->SetConstructor(object_function);
12713       }
12714     }
12715   }
12716 }
12717 
12718 
12719 // static
ReoptimizeIfPrototype(Handle<JSObject> object)12720 void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) {
12721   if (!object->map()->is_prototype_map()) return;
12722   if (!object->map()->should_be_fast_prototype_map()) return;
12723   OptimizeAsPrototype(object);
12724 }
12725 
12726 
12727 // static
LazyRegisterPrototypeUser(Handle<Map> user,Isolate * isolate)12728 void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
12729   // Contract: In line with InvalidatePrototypeChains()'s requirements,
12730   // leaf maps don't need to register as users, only prototypes do.
12731   DCHECK(user->is_prototype_map());
12732 
12733   Handle<Map> current_user = user;
12734   Handle<PrototypeInfo> current_user_info =
12735       Map::GetOrCreatePrototypeInfo(user, isolate);
12736   for (PrototypeIterator iter(isolate, user); !iter.IsAtEnd(); iter.Advance()) {
12737     // Walk up the prototype chain as far as links haven't been registered yet.
12738     if (current_user_info->registry_slot() != PrototypeInfo::UNREGISTERED) {
12739       break;
12740     }
12741     Handle<Object> maybe_proto = PrototypeIterator::GetCurrent(iter);
12742     // Proxies on the prototype chain are not supported. They make it
12743     // impossible to make any assumptions about the prototype chain anyway.
12744     if (maybe_proto->IsJSProxy()) return;
12745     Handle<JSObject> proto = Handle<JSObject>::cast(maybe_proto);
12746     Handle<PrototypeInfo> proto_info =
12747         Map::GetOrCreatePrototypeInfo(proto, isolate);
12748     Handle<Object> maybe_registry(proto_info->prototype_users(), isolate);
12749     Handle<WeakArrayList> registry =
12750         maybe_registry->IsSmi()
12751             ? handle(ReadOnlyRoots(isolate->heap()).empty_weak_array_list(),
12752                      isolate)
12753             : Handle<WeakArrayList>::cast(maybe_registry);
12754     int slot = 0;
12755     Handle<WeakArrayList> new_array =
12756         PrototypeUsers::Add(isolate, registry, current_user, &slot);
12757     current_user_info->set_registry_slot(slot);
12758     if (!maybe_registry.is_identical_to(new_array)) {
12759       proto_info->set_prototype_users(*new_array);
12760     }
12761     if (FLAG_trace_prototype_users) {
12762       PrintF("Registering %p as a user of prototype %p (map=%p).\n",
12763              reinterpret_cast<void*>(*current_user),
12764              reinterpret_cast<void*>(*proto),
12765              reinterpret_cast<void*>(proto->map()));
12766     }
12767 
12768     current_user = handle(proto->map(), isolate);
12769     current_user_info = proto_info;
12770   }
12771 }
12772 
12773 
12774 // Can be called regardless of whether |user| was actually registered with
12775 // |prototype|. Returns true when there was a registration.
12776 // static
UnregisterPrototypeUser(Handle<Map> user,Isolate * isolate)12777 bool JSObject::UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
12778   DCHECK(user->is_prototype_map());
12779   // If it doesn't have a PrototypeInfo, it was never registered.
12780   if (!user->prototype_info()->IsPrototypeInfo()) return false;
12781   // If it had no prototype before, see if it had users that might expect
12782   // registration.
12783   if (!user->prototype()->IsJSObject()) {
12784     Object* users =
12785         PrototypeInfo::cast(user->prototype_info())->prototype_users();
12786     return users->IsWeakArrayList();
12787   }
12788   Handle<JSObject> prototype(JSObject::cast(user->prototype()), isolate);
12789   Handle<PrototypeInfo> user_info =
12790       Map::GetOrCreatePrototypeInfo(user, isolate);
12791   int slot = user_info->registry_slot();
12792   if (slot == PrototypeInfo::UNREGISTERED) return false;
12793   DCHECK(prototype->map()->is_prototype_map());
12794   Object* maybe_proto_info = prototype->map()->prototype_info();
12795   // User knows its registry slot, prototype info and user registry must exist.
12796   DCHECK(maybe_proto_info->IsPrototypeInfo());
12797   Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info),
12798                                    isolate);
12799   Handle<WeakArrayList> prototype_users(
12800       WeakArrayList::cast(proto_info->prototype_users()), isolate);
12801   DCHECK_EQ(prototype_users->Get(slot), HeapObjectReference::Weak(*user));
12802   PrototypeUsers::MarkSlotEmpty(*prototype_users, slot);
12803   if (FLAG_trace_prototype_users) {
12804     PrintF("Unregistering %p as a user of prototype %p.\n",
12805            reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype));
12806   }
12807   return true;
12808 }
12809 
12810 namespace {
12811 
12812 // This function must be kept in sync with
12813 // AccessorAssembler::InvalidateValidityCellIfPrototype() which does pre-checks
12814 // before jumping here.
InvalidateOnePrototypeValidityCellInternal(Map * map)12815 void InvalidateOnePrototypeValidityCellInternal(Map* map) {
12816   DCHECK(map->is_prototype_map());
12817   if (FLAG_trace_prototype_users) {
12818     PrintF("Invalidating prototype map %p 's cell\n",
12819            reinterpret_cast<void*>(map));
12820   }
12821   Object* maybe_cell = map->prototype_validity_cell();
12822   if (maybe_cell->IsCell()) {
12823     // Just set the value; the cell will be replaced lazily.
12824     Cell* cell = Cell::cast(maybe_cell);
12825     cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid));
12826   }
12827 }
12828 
InvalidatePrototypeChainsInternal(Map * map)12829 void InvalidatePrototypeChainsInternal(Map* map) {
12830   InvalidateOnePrototypeValidityCellInternal(map);
12831 
12832   Object* maybe_proto_info = map->prototype_info();
12833   if (!maybe_proto_info->IsPrototypeInfo()) return;
12834   PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info);
12835   WeakArrayList* prototype_users =
12836       WeakArrayList::cast(proto_info->prototype_users());
12837   // For now, only maps register themselves as users.
12838   for (int i = PrototypeUsers::kFirstIndex; i < prototype_users->length();
12839        ++i) {
12840     HeapObject* heap_object;
12841     if (prototype_users->Get(i)->ToWeakHeapObject(&heap_object) &&
12842         heap_object->IsMap()) {
12843       // Walk the prototype chain (backwards, towards leaf objects) if
12844       // necessary.
12845       InvalidatePrototypeChainsInternal(Map::cast(heap_object));
12846     }
12847   }
12848 }
12849 
12850 }  // namespace
12851 
12852 // static
InvalidatePrototypeChains(Map * map)12853 Map* JSObject::InvalidatePrototypeChains(Map* map) {
12854   DisallowHeapAllocation no_gc;
12855   InvalidatePrototypeChainsInternal(map);
12856   return map;
12857 }
12858 
12859 // We also invalidate global objects validity cell when a new lexical
12860 // environment variable is added. This is necessary to ensure that
12861 // Load/StoreGlobalIC handlers that load/store from global object's prototype
12862 // get properly invalidated.
12863 // Note, that the normal Load/StoreICs that load/store through the global object
12864 // in the prototype chain are not affected by appearance of a new lexical
12865 // variable and therefore we don't propagate invalidation down.
12866 // static
InvalidatePrototypeValidityCell(JSGlobalObject * global)12867 void JSObject::InvalidatePrototypeValidityCell(JSGlobalObject* global) {
12868   DisallowHeapAllocation no_gc;
12869   InvalidateOnePrototypeValidityCellInternal(global->map());
12870 }
12871 
12872 // static
GetOrCreatePrototypeInfo(Handle<JSObject> prototype,Isolate * isolate)12873 Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<JSObject> prototype,
12874                                                     Isolate* isolate) {
12875   Object* maybe_proto_info = prototype->map()->prototype_info();
12876   if (maybe_proto_info->IsPrototypeInfo()) {
12877     return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
12878   }
12879   Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
12880   prototype->map()->set_prototype_info(*proto_info);
12881   return proto_info;
12882 }
12883 
12884 
12885 // static
GetOrCreatePrototypeInfo(Handle<Map> prototype_map,Isolate * isolate)12886 Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<Map> prototype_map,
12887                                                     Isolate* isolate) {
12888   Object* maybe_proto_info = prototype_map->prototype_info();
12889   if (maybe_proto_info->IsPrototypeInfo()) {
12890     return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
12891   }
12892   Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
12893   prototype_map->set_prototype_info(*proto_info);
12894   return proto_info;
12895 }
12896 
12897 // static
SetShouldBeFastPrototypeMap(Handle<Map> map,bool value,Isolate * isolate)12898 void Map::SetShouldBeFastPrototypeMap(Handle<Map> map, bool value,
12899                                       Isolate* isolate) {
12900   if (value == false && !map->prototype_info()->IsPrototypeInfo()) {
12901     // "False" is the implicit default value, so there's nothing to do.
12902     return;
12903   }
12904   GetOrCreatePrototypeInfo(map, isolate)->set_should_be_fast_map(value);
12905 }
12906 
12907 // static
GetOrCreatePrototypeChainValidityCell(Handle<Map> map,Isolate * isolate)12908 Handle<Object> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
12909                                                           Isolate* isolate) {
12910   Handle<Object> maybe_prototype;
12911   if (map->IsJSGlobalObjectMap()) {
12912     DCHECK(map->is_prototype_map());
12913     // Global object is prototype of a global proxy and therefore we can
12914     // use its validity cell for guarding global object's prototype change.
12915     maybe_prototype = isolate->global_object();
12916   } else {
12917     maybe_prototype =
12918         handle(map->GetPrototypeChainRootMap(isolate)->prototype(), isolate);
12919   }
12920   if (!maybe_prototype->IsJSObject()) {
12921     return handle(Smi::FromInt(Map::kPrototypeChainValid), isolate);
12922   }
12923   Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype);
12924   // Ensure the prototype is registered with its own prototypes so its cell
12925   // will be invalidated when necessary.
12926   JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate),
12927                                       isolate);
12928 
12929   Object* maybe_cell = prototype->map()->prototype_validity_cell();
12930   // Return existing cell if it's still valid.
12931   if (maybe_cell->IsCell()) {
12932     Handle<Cell> cell(Cell::cast(maybe_cell), isolate);
12933     if (cell->value() == Smi::FromInt(Map::kPrototypeChainValid)) {
12934       return cell;
12935     }
12936   }
12937   // Otherwise create a new cell.
12938   Handle<Cell> cell = isolate->factory()->NewCell(
12939       handle(Smi::FromInt(Map::kPrototypeChainValid), isolate));
12940   prototype->map()->set_prototype_validity_cell(*cell);
12941   return cell;
12942 }
12943 
12944 // static
IsPrototypeChainInvalidated(Map * map)12945 bool Map::IsPrototypeChainInvalidated(Map* map) {
12946   DCHECK(map->is_prototype_map());
12947   Object* maybe_cell = map->prototype_validity_cell();
12948   if (maybe_cell->IsCell()) {
12949     Cell* cell = Cell::cast(maybe_cell);
12950     return cell->value() != Smi::FromInt(Map::kPrototypeChainValid);
12951   }
12952   return true;
12953 }
12954 
12955 // static
SetPrototype(Isolate * isolate,Handle<Map> map,Handle<Object> prototype,bool enable_prototype_setup_mode)12956 void Map::SetPrototype(Isolate* isolate, Handle<Map> map,
12957                        Handle<Object> prototype,
12958                        bool enable_prototype_setup_mode) {
12959   RuntimeCallTimerScope stats_scope(isolate, *map,
12960                                     RuntimeCallCounterId::kMap_SetPrototype);
12961 
12962   bool is_hidden = false;
12963   if (prototype->IsJSObject()) {
12964     Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype);
12965     JSObject::OptimizeAsPrototype(prototype_jsobj, enable_prototype_setup_mode);
12966 
12967     Object* maybe_constructor = prototype_jsobj->map()->GetConstructor();
12968     if (maybe_constructor->IsJSFunction()) {
12969       JSFunction* constructor = JSFunction::cast(maybe_constructor);
12970       Object* data = constructor->shared()->function_data();
12971       is_hidden = (data->IsFunctionTemplateInfo() &&
12972                    FunctionTemplateInfo::cast(data)->hidden_prototype()) ||
12973                   prototype->IsJSGlobalObject();
12974     } else if (maybe_constructor->IsFunctionTemplateInfo()) {
12975       is_hidden =
12976           FunctionTemplateInfo::cast(maybe_constructor)->hidden_prototype() ||
12977           prototype->IsJSGlobalObject();
12978     }
12979   }
12980   map->set_has_hidden_prototype(is_hidden);
12981 
12982   WriteBarrierMode wb_mode =
12983       prototype->IsNull(isolate) ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER;
12984   map->set_prototype(*prototype, wb_mode);
12985 }
12986 
CacheInitialJSArrayMaps(Handle<Context> native_context,Handle<Map> initial_map)12987 Handle<Object> CacheInitialJSArrayMaps(Handle<Context> native_context,
12988                                        Handle<Map> initial_map) {
12989   // Replace all of the cached initial array maps in the native context with
12990   // the appropriate transitioned elements kind maps.
12991   Handle<Map> current_map = initial_map;
12992   ElementsKind kind = current_map->elements_kind();
12993   DCHECK_EQ(GetInitialFastElementsKind(), kind);
12994   native_context->set(Context::ArrayMapIndex(kind), *current_map);
12995   for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1;
12996        i < kFastElementsKindCount; ++i) {
12997     Handle<Map> new_map;
12998     ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
12999     if (Map* maybe_elements_transition = current_map->ElementsTransitionMap()) {
13000       new_map = handle(maybe_elements_transition, native_context->GetIsolate());
13001     } else {
13002       new_map =
13003           Map::CopyAsElementsKind(native_context->GetIsolate(), current_map,
13004                                   next_kind, INSERT_TRANSITION);
13005     }
13006     DCHECK_EQ(next_kind, new_map->elements_kind());
13007     native_context->set(Context::ArrayMapIndex(next_kind), *new_map);
13008     current_map = new_map;
13009   }
13010   return initial_map;
13011 }
13012 
13013 namespace {
13014 
SetInstancePrototype(Isolate * isolate,Handle<JSFunction> function,Handle<JSReceiver> value)13015 void SetInstancePrototype(Isolate* isolate, Handle<JSFunction> function,
13016                           Handle<JSReceiver> value) {
13017   // Now some logic for the maps of the objects that are created by using this
13018   // function as a constructor.
13019   if (function->has_initial_map()) {
13020     // If the function has allocated the initial map replace it with a
13021     // copy containing the new prototype.  Also complete any in-object
13022     // slack tracking that is in progress at this point because it is
13023     // still tracking the old copy.
13024     function->CompleteInobjectSlackTrackingIfActive();
13025 
13026     Handle<Map> initial_map(function->initial_map(), isolate);
13027 
13028     if (!isolate->bootstrapper()->IsActive() &&
13029         initial_map->instance_type() == JS_OBJECT_TYPE) {
13030       // Put the value in the initial map field until an initial map is needed.
13031       // At that point, a new initial map is created and the prototype is put
13032       // into the initial map where it belongs.
13033       function->set_prototype_or_initial_map(*value);
13034     } else {
13035       Handle<Map> new_map =
13036           Map::Copy(isolate, initial_map, "SetInstancePrototype");
13037       JSFunction::SetInitialMap(function, new_map, value);
13038 
13039       // If the function is used as the global Array function, cache the
13040       // updated initial maps (and transitioned versions) in the native context.
13041       Handle<Context> native_context(function->context()->native_context(),
13042                                      isolate);
13043       Handle<Object> array_function(
13044           native_context->get(Context::ARRAY_FUNCTION_INDEX), isolate);
13045       if (array_function->IsJSFunction() &&
13046           *function == JSFunction::cast(*array_function)) {
13047         CacheInitialJSArrayMaps(native_context, new_map);
13048       }
13049     }
13050 
13051     // Deoptimize all code that embeds the previous initial map.
13052     initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
13053         isolate, DependentCode::kInitialMapChangedGroup);
13054   } else {
13055     // Put the value in the initial map field until an initial map is
13056     // needed.  At that point, a new initial map is created and the
13057     // prototype is put into the initial map where it belongs.
13058     function->set_prototype_or_initial_map(*value);
13059     if (value->IsJSObject()) {
13060       // Optimize as prototype to detach it from its transition tree.
13061       JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value));
13062     }
13063   }
13064 }
13065 
13066 }  // anonymous namespace
13067 
SetPrototype(Handle<JSFunction> function,Handle<Object> value)13068 void JSFunction::SetPrototype(Handle<JSFunction> function,
13069                               Handle<Object> value) {
13070   DCHECK(function->IsConstructor() ||
13071          IsGeneratorFunction(function->shared()->kind()));
13072   Isolate* isolate = function->GetIsolate();
13073   Handle<JSReceiver> construct_prototype;
13074 
13075   // If the value is not a JSReceiver, store the value in the map's
13076   // constructor field so it can be accessed.  Also, set the prototype
13077   // used for constructing objects to the original object prototype.
13078   // See ECMA-262 13.2.2.
13079   if (!value->IsJSReceiver()) {
13080     // Copy the map so this does not affect unrelated functions.
13081     // Remove map transitions because they point to maps with a
13082     // different prototype.
13083     Handle<Map> new_map =
13084         Map::Copy(isolate, handle(function->map(), isolate), "SetPrototype");
13085 
13086     JSObject::MigrateToMap(function, new_map);
13087     new_map->SetConstructor(*value);
13088     new_map->set_has_non_instance_prototype(true);
13089 
13090     FunctionKind kind = function->shared()->kind();
13091     Handle<Context> native_context(function->context()->native_context(),
13092                                    isolate);
13093 
13094     construct_prototype = Handle<JSReceiver>(
13095         IsGeneratorFunction(kind)
13096             ? IsAsyncFunction(kind)
13097                   ? native_context->initial_async_generator_prototype()
13098                   : native_context->initial_generator_prototype()
13099             : native_context->initial_object_prototype(),
13100         isolate);
13101   } else {
13102     construct_prototype = Handle<JSReceiver>::cast(value);
13103     function->map()->set_has_non_instance_prototype(false);
13104   }
13105 
13106   SetInstancePrototype(isolate, function, construct_prototype);
13107 }
13108 
SetInitialMap(Handle<JSFunction> function,Handle<Map> map,Handle<Object> prototype)13109 void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
13110                                Handle<Object> prototype) {
13111   if (map->prototype() != *prototype)
13112     Map::SetPrototype(function->GetIsolate(), map, prototype);
13113   function->set_prototype_or_initial_map(*map);
13114   map->SetConstructor(*function);
13115   if (FLAG_trace_maps) {
13116     LOG(function->GetIsolate(), MapEvent("InitialMap", nullptr, *map, "",
13117                                          function->shared()->DebugName()));
13118   }
13119 }
13120 
13121 
13122 #ifdef DEBUG
13123 namespace {
13124 
CanSubclassHaveInobjectProperties(InstanceType instance_type)13125 bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
13126   switch (instance_type) {
13127     case JS_API_OBJECT_TYPE:
13128     case JS_ARRAY_BUFFER_TYPE:
13129     case JS_ARRAY_TYPE:
13130     case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
13131     case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
13132     case JS_DATA_VIEW_TYPE:
13133     case JS_DATE_TYPE:
13134     case JS_FUNCTION_TYPE:
13135     case JS_GENERATOR_OBJECT_TYPE:
13136 #ifdef V8_INTL_SUPPORT
13137     case JS_INTL_COLLATOR_TYPE:
13138     case JS_INTL_LIST_FORMAT_TYPE:
13139     case JS_INTL_PLURAL_RULES_TYPE:
13140     case JS_INTL_RELATIVE_TIME_FORMAT_TYPE:
13141 #endif
13142     case JS_ASYNC_GENERATOR_OBJECT_TYPE:
13143     case JS_MAP_TYPE:
13144     case JS_MESSAGE_OBJECT_TYPE:
13145     case JS_OBJECT_TYPE:
13146     case JS_ERROR_TYPE:
13147     case JS_ARGUMENTS_TYPE:
13148     case JS_PROMISE_TYPE:
13149     case JS_REGEXP_TYPE:
13150     case JS_SET_TYPE:
13151     case JS_SPECIAL_API_OBJECT_TYPE:
13152     case JS_TYPED_ARRAY_TYPE:
13153     case JS_VALUE_TYPE:
13154     case JS_WEAK_MAP_TYPE:
13155     case JS_WEAK_SET_TYPE:
13156     case WASM_GLOBAL_TYPE:
13157     case WASM_INSTANCE_TYPE:
13158     case WASM_MEMORY_TYPE:
13159     case WASM_MODULE_TYPE:
13160     case WASM_TABLE_TYPE:
13161       return true;
13162 
13163     case BIGINT_TYPE:
13164     case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
13165     case BYTECODE_ARRAY_TYPE:
13166     case BYTE_ARRAY_TYPE:
13167     case CELL_TYPE:
13168     case CODE_TYPE:
13169     case FILLER_TYPE:
13170     case FIXED_ARRAY_TYPE:
13171     case SCRIPT_CONTEXT_TABLE_TYPE:
13172     case FIXED_DOUBLE_ARRAY_TYPE:
13173     case FEEDBACK_METADATA_TYPE:
13174     case FOREIGN_TYPE:
13175     case FREE_SPACE_TYPE:
13176     case HASH_TABLE_TYPE:
13177     case ORDERED_HASH_MAP_TYPE:
13178     case ORDERED_HASH_SET_TYPE:
13179     case NAME_DICTIONARY_TYPE:
13180     case GLOBAL_DICTIONARY_TYPE:
13181     case NUMBER_DICTIONARY_TYPE:
13182     case SIMPLE_NUMBER_DICTIONARY_TYPE:
13183     case STRING_TABLE_TYPE:
13184     case HEAP_NUMBER_TYPE:
13185     case JS_BOUND_FUNCTION_TYPE:
13186     case JS_GLOBAL_OBJECT_TYPE:
13187     case JS_GLOBAL_PROXY_TYPE:
13188     case JS_PROXY_TYPE:
13189     case MAP_TYPE:
13190     case MUTABLE_HEAP_NUMBER_TYPE:
13191     case ODDBALL_TYPE:
13192     case PROPERTY_CELL_TYPE:
13193     case SHARED_FUNCTION_INFO_TYPE:
13194     case SYMBOL_TYPE:
13195     case ALLOCATION_SITE_TYPE:
13196 
13197 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
13198   case FIXED_##TYPE##_ARRAY_TYPE:
13199 #undef TYPED_ARRAY_CASE
13200 
13201 #define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE:
13202       STRUCT_LIST(MAKE_STRUCT_CASE)
13203 #undef MAKE_STRUCT_CASE
13204       // We must not end up here for these instance types at all.
13205       UNREACHABLE();
13206     // Fall through.
13207     default:
13208       return false;
13209   }
13210 }
13211 
13212 }  // namespace
13213 #endif
13214 
13215 
EnsureHasInitialMap(Handle<JSFunction> function)13216 void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
13217   DCHECK(function->has_prototype_slot());
13218   DCHECK(function->IsConstructor() ||
13219          IsResumableFunction(function->shared()->kind()));
13220   if (function->has_initial_map()) return;
13221   Isolate* isolate = function->GetIsolate();
13222 
13223   // First create a new map with the size and number of in-object properties
13224   // suggested by the function.
13225   InstanceType instance_type;
13226   if (IsResumableFunction(function->shared()->kind())) {
13227     instance_type = IsAsyncGeneratorFunction(function->shared()->kind())
13228                         ? JS_ASYNC_GENERATOR_OBJECT_TYPE
13229                         : JS_GENERATOR_OBJECT_TYPE;
13230   } else {
13231     instance_type = JS_OBJECT_TYPE;
13232   }
13233 
13234   // The constructor should be compiled for the optimization hints to be
13235   // available.
13236   int expected_nof_properties = 0;
13237   if (function->shared()->is_compiled() ||
13238       Compiler::Compile(function, Compiler::CLEAR_EXCEPTION)) {
13239     DCHECK(function->shared()->is_compiled());
13240     expected_nof_properties = function->shared()->expected_nof_properties();
13241   }
13242 
13243   int instance_size;
13244   int inobject_properties;
13245   CalculateInstanceSizeHelper(instance_type, false, 0, expected_nof_properties,
13246                               &instance_size, &inobject_properties);
13247 
13248   Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size,
13249                                                TERMINAL_FAST_ELEMENTS_KIND,
13250                                                inobject_properties);
13251 
13252   // Fetch or allocate prototype.
13253   Handle<Object> prototype;
13254   if (function->has_instance_prototype()) {
13255     prototype = handle(function->instance_prototype(), isolate);
13256   } else {
13257     prototype = isolate->factory()->NewFunctionPrototype(function);
13258   }
13259   DCHECK(map->has_fast_object_elements());
13260 
13261   // Finally link initial map and constructor function.
13262   DCHECK(prototype->IsJSReceiver());
13263   JSFunction::SetInitialMap(function, map, prototype);
13264   map->StartInobjectSlackTracking();
13265 }
13266 
13267 namespace {
FastInitializeDerivedMap(Isolate * isolate,Handle<JSFunction> new_target,Handle<JSFunction> constructor,Handle<Map> constructor_initial_map)13268 bool FastInitializeDerivedMap(Isolate* isolate, Handle<JSFunction> new_target,
13269                               Handle<JSFunction> constructor,
13270                               Handle<Map> constructor_initial_map) {
13271   // Check that |function|'s initial map still in sync with the |constructor|,
13272   // otherwise we must create a new initial map for |function|.
13273   if (new_target->has_initial_map() &&
13274       new_target->initial_map()->GetConstructor() == *constructor) {
13275     DCHECK(new_target->instance_prototype()->IsJSReceiver());
13276     return true;
13277   }
13278   InstanceType instance_type = constructor_initial_map->instance_type();
13279   DCHECK(CanSubclassHaveInobjectProperties(instance_type));
13280   // Create a new map with the size and number of in-object properties
13281   // suggested by |function|.
13282 
13283   // Link initial map and constructor function if the new.target is actually a
13284   // subclass constructor.
13285   if (!IsDerivedConstructor(new_target->shared()->kind())) return false;
13286 
13287   int instance_size;
13288   int in_object_properties;
13289   int embedder_fields =
13290       JSObject::GetEmbedderFieldCount(*constructor_initial_map);
13291   bool success = JSFunction::CalculateInstanceSizeForDerivedClass(
13292       new_target, instance_type, embedder_fields, &instance_size,
13293       &in_object_properties);
13294 
13295   Handle<Map> map;
13296   if (success) {
13297     int pre_allocated = constructor_initial_map->GetInObjectProperties() -
13298                         constructor_initial_map->UnusedPropertyFields();
13299     CHECK_LE(constructor_initial_map->UsedInstanceSize(), instance_size);
13300     int unused_property_fields = in_object_properties - pre_allocated;
13301     map = Map::CopyInitialMap(isolate, constructor_initial_map, instance_size,
13302                               in_object_properties, unused_property_fields);
13303   } else {
13304     map = Map::CopyInitialMap(isolate, constructor_initial_map);
13305   }
13306   map->set_new_target_is_base(false);
13307   Handle<Object> prototype(new_target->instance_prototype(), isolate);
13308   JSFunction::SetInitialMap(new_target, map, prototype);
13309   DCHECK(new_target->instance_prototype()->IsJSReceiver());
13310   map->SetConstructor(*constructor);
13311   map->set_construction_counter(Map::kNoSlackTracking);
13312   map->StartInobjectSlackTracking();
13313   return true;
13314 }
13315 
13316 }  // namespace
13317 
13318 // static
GetDerivedMap(Isolate * isolate,Handle<JSFunction> constructor,Handle<JSReceiver> new_target)13319 MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
13320                                            Handle<JSFunction> constructor,
13321                                            Handle<JSReceiver> new_target) {
13322   EnsureHasInitialMap(constructor);
13323 
13324   Handle<Map> constructor_initial_map(constructor->initial_map(), isolate);
13325   if (*new_target == *constructor) return constructor_initial_map;
13326 
13327   Handle<Map> result_map;
13328   // Fast case, new.target is a subclass of constructor. The map is cacheable
13329   // (and may already have been cached). new.target.prototype is guaranteed to
13330   // be a JSReceiver.
13331   if (new_target->IsJSFunction()) {
13332     Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
13333     if (FastInitializeDerivedMap(isolate, function, constructor,
13334                                  constructor_initial_map)) {
13335       return handle(function->initial_map(), isolate);
13336     }
13337   }
13338 
13339   // Slow path, new.target is either a proxy or can't cache the map.
13340   // new.target.prototype is not guaranteed to be a JSReceiver, and may need to
13341   // fall back to the intrinsicDefaultProto.
13342   Handle<Object> prototype;
13343   if (new_target->IsJSFunction()) {
13344     Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
13345     // Make sure the new.target.prototype is cached.
13346     EnsureHasInitialMap(function);
13347     prototype = handle(function->prototype(), isolate);
13348   } else {
13349     Handle<String> prototype_string = isolate->factory()->prototype_string();
13350     ASSIGN_RETURN_ON_EXCEPTION(
13351         isolate, prototype,
13352         JSReceiver::GetProperty(isolate, new_target, prototype_string), Map);
13353     // The above prototype lookup might change the constructor and its
13354     // prototype, hence we have to reload the initial map.
13355     EnsureHasInitialMap(constructor);
13356     constructor_initial_map = handle(constructor->initial_map(), isolate);
13357   }
13358 
13359   // If prototype is not a JSReceiver, fetch the intrinsicDefaultProto from the
13360   // correct realm. Rather than directly fetching the .prototype, we fetch the
13361   // constructor that points to the .prototype. This relies on
13362   // constructor.prototype being FROZEN for those constructors.
13363   if (!prototype->IsJSReceiver()) {
13364     Handle<Context> context;
13365     ASSIGN_RETURN_ON_EXCEPTION(isolate, context,
13366                                JSReceiver::GetFunctionRealm(new_target), Map);
13367     DCHECK(context->IsNativeContext());
13368     Handle<Object> maybe_index = JSReceiver::GetDataProperty(
13369         constructor, isolate->factory()->native_context_index_symbol());
13370     int index = maybe_index->IsSmi() ? Smi::ToInt(*maybe_index)
13371                                      : Context::OBJECT_FUNCTION_INDEX;
13372     Handle<JSFunction> realm_constructor(JSFunction::cast(context->get(index)),
13373                                          isolate);
13374     prototype = handle(realm_constructor->prototype(), isolate);
13375   }
13376 
13377   Handle<Map> map = Map::CopyInitialMap(isolate, constructor_initial_map);
13378   map->set_new_target_is_base(false);
13379   CHECK(prototype->IsJSReceiver());
13380   if (map->prototype() != *prototype)
13381     Map::SetPrototype(isolate, map, prototype);
13382   map->SetConstructor(*constructor);
13383   return map;
13384 }
13385 
ComputeInstanceSizeWithMinSlack(Isolate * isolate)13386 int JSFunction::ComputeInstanceSizeWithMinSlack(Isolate* isolate) {
13387   if (has_prototype_slot() && has_initial_map() &&
13388       initial_map()->IsInobjectSlackTrackingInProgress()) {
13389     int slack = initial_map()->ComputeMinObjectSlack(isolate);
13390     return initial_map()->InstanceSizeFromSlack(slack);
13391   }
13392   return initial_map()->instance_size();
13393 }
13394 
PrintName(FILE * out)13395 void JSFunction::PrintName(FILE* out) {
13396   std::unique_ptr<char[]> name = shared()->DebugName()->ToCString();
13397   PrintF(out, "%s", name.get());
13398 }
13399 
13400 
GetName(Handle<JSFunction> function)13401 Handle<String> JSFunction::GetName(Handle<JSFunction> function) {
13402   Isolate* isolate = function->GetIsolate();
13403   Handle<Object> name =
13404       JSReceiver::GetDataProperty(function, isolate->factory()->name_string());
13405   if (name->IsString()) return Handle<String>::cast(name);
13406   return handle(function->shared()->DebugName(), isolate);
13407 }
13408 
13409 
GetDebugName(Handle<JSFunction> function)13410 Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) {
13411   Isolate* isolate = function->GetIsolate();
13412   Handle<Object> name = JSReceiver::GetDataProperty(
13413       function, isolate->factory()->display_name_string());
13414   if (name->IsString()) return Handle<String>::cast(name);
13415   return JSFunction::GetName(function);
13416 }
13417 
SetName(Handle<JSFunction> function,Handle<Name> name,Handle<String> prefix)13418 bool JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name,
13419                          Handle<String> prefix) {
13420   Isolate* isolate = function->GetIsolate();
13421   Handle<String> function_name;
13422   ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, function_name,
13423                                    Name::ToFunctionName(isolate, name), false);
13424   if (prefix->length() > 0) {
13425     IncrementalStringBuilder builder(isolate);
13426     builder.AppendString(prefix);
13427     builder.AppendCharacter(' ');
13428     builder.AppendString(function_name);
13429     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, function_name, builder.Finish(),
13430                                      false);
13431   }
13432   RETURN_ON_EXCEPTION_VALUE(
13433       isolate,
13434       JSObject::DefinePropertyOrElementIgnoreAttributes(
13435           function, isolate->factory()->name_string(), function_name,
13436           static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY)),
13437       false);
13438   return true;
13439 }
13440 
13441 namespace {
13442 
NativeCodeFunctionSourceString(Handle<SharedFunctionInfo> shared_info)13443 Handle<String> NativeCodeFunctionSourceString(
13444     Handle<SharedFunctionInfo> shared_info) {
13445   Isolate* const isolate = shared_info->GetIsolate();
13446   IncrementalStringBuilder builder(isolate);
13447   builder.AppendCString("function ");
13448   builder.AppendString(handle(shared_info->Name(), isolate));
13449   builder.AppendCString("() { [native code] }");
13450   return builder.Finish().ToHandleChecked();
13451 }
13452 
13453 }  // namespace
13454 
13455 
13456 // static
ToString(Handle<JSBoundFunction> function)13457 Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) {
13458   Isolate* const isolate = function->GetIsolate();
13459   return isolate->factory()->function_native_code_string();
13460 }
13461 
13462 
13463 // static
ToString(Handle<JSFunction> function)13464 Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
13465   Isolate* const isolate = function->GetIsolate();
13466   Handle<SharedFunctionInfo> shared_info(function->shared(), isolate);
13467 
13468   // Check if {function} should hide its source code.
13469   if (!shared_info->IsUserJavaScript()) {
13470     return NativeCodeFunctionSourceString(shared_info);
13471   }
13472 
13473   // Check if we should print {function} as a class.
13474   Handle<Object> maybe_class_positions = JSReceiver::GetDataProperty(
13475       function, isolate->factory()->class_positions_symbol());
13476   if (maybe_class_positions->IsTuple2()) {
13477     Tuple2* class_positions = Tuple2::cast(*maybe_class_positions);
13478     int start_position = Smi::ToInt(class_positions->value1());
13479     int end_position = Smi::ToInt(class_positions->value2());
13480     Handle<String> script_source(
13481         String::cast(Script::cast(shared_info->script())->source()), isolate);
13482     return isolate->factory()->NewSubString(script_source, start_position,
13483                                             end_position);
13484   }
13485 
13486   // Check if we have source code for the {function}.
13487   if (!shared_info->HasSourceCode()) {
13488     return NativeCodeFunctionSourceString(shared_info);
13489   }
13490 
13491   if (FLAG_harmony_function_tostring) {
13492     if (shared_info->function_token_position() == kNoSourcePosition) {
13493       // If the function token position isn't valid, return [native code] to
13494       // ensure calling eval on the returned source code throws rather than
13495       // giving inconsistent call behaviour.
13496       isolate->CountUsage(v8::Isolate::UseCounterFeature::
13497                               kFunctionTokenOffsetTooLongForToString);
13498       return NativeCodeFunctionSourceString(shared_info);
13499     }
13500     return Handle<String>::cast(
13501         SharedFunctionInfo::GetSourceCodeHarmony(shared_info));
13502   }
13503 
13504   IncrementalStringBuilder builder(isolate);
13505   FunctionKind kind = shared_info->kind();
13506   if (!IsArrowFunction(kind)) {
13507     if (IsConciseMethod(kind)) {
13508       if (IsAsyncGeneratorFunction(kind)) {
13509         builder.AppendCString("async *");
13510       } else if (IsGeneratorFunction(kind)) {
13511         builder.AppendCharacter('*');
13512       } else if (IsAsyncFunction(kind)) {
13513         builder.AppendCString("async ");
13514       }
13515     } else {
13516       if (IsAsyncGeneratorFunction(kind)) {
13517         builder.AppendCString("async function* ");
13518       } else if (IsGeneratorFunction(kind)) {
13519         builder.AppendCString("function* ");
13520       } else if (IsAsyncFunction(kind)) {
13521         builder.AppendCString("async function ");
13522       } else {
13523         builder.AppendCString("function ");
13524       }
13525     }
13526     if (shared_info->name_should_print_as_anonymous()) {
13527       builder.AppendCString("anonymous");
13528     } else if (!shared_info->is_anonymous_expression()) {
13529       builder.AppendString(handle(shared_info->Name(), isolate));
13530     }
13531   }
13532   if (shared_info->is_wrapped()) {
13533     builder.AppendCharacter('(');
13534     Handle<FixedArray> args(
13535         Script::cast(shared_info->script())->wrapped_arguments(), isolate);
13536     int argc = args->length();
13537     for (int i = 0; i < argc; i++) {
13538       if (i > 0) builder.AppendCString(", ");
13539       builder.AppendString(Handle<String>(String::cast(args->get(i)), isolate));
13540     }
13541     builder.AppendCString(") {\n");
13542   }
13543   builder.AppendString(
13544       Handle<String>::cast(SharedFunctionInfo::GetSourceCode(shared_info)));
13545   if (shared_info->is_wrapped()) {
13546     builder.AppendCString("\n}");
13547   }
13548   return builder.Finish().ToHandleChecked();
13549 }
13550 
Initialize(Isolate * isolate,Handle<Oddball> oddball,const char * to_string,Handle<Object> to_number,const char * type_of,byte kind)13551 void Oddball::Initialize(Isolate* isolate, Handle<Oddball> oddball,
13552                          const char* to_string, Handle<Object> to_number,
13553                          const char* type_of, byte kind) {
13554   Handle<String> internalized_to_string =
13555       isolate->factory()->InternalizeUtf8String(to_string);
13556   Handle<String> internalized_type_of =
13557       isolate->factory()->InternalizeUtf8String(type_of);
13558   if (to_number->IsHeapNumber()) {
13559     oddball->set_to_number_raw_as_bits(
13560         Handle<HeapNumber>::cast(to_number)->value_as_bits());
13561   } else {
13562     oddball->set_to_number_raw(to_number->Number());
13563   }
13564   oddball->set_to_number(*to_number);
13565   oddball->set_to_string(*internalized_to_string);
13566   oddball->set_type_of(*internalized_type_of);
13567   oddball->set_kind(kind);
13568 }
13569 
GetEvalPosition()13570 int Script::GetEvalPosition() {
13571   DisallowHeapAllocation no_gc;
13572   DCHECK(compilation_type() == Script::COMPILATION_TYPE_EVAL);
13573   int position = eval_from_position();
13574   if (position < 0) {
13575     // Due to laziness, the position may not have been translated from code
13576     // offset yet, which would be encoded as negative integer. In that case,
13577     // translate and set the position.
13578     if (!has_eval_from_shared()) {
13579       position = 0;
13580     } else {
13581       SharedFunctionInfo* shared = eval_from_shared();
13582       position = shared->abstract_code()->SourcePosition(-position);
13583     }
13584     DCHECK_GE(position, 0);
13585     set_eval_from_position(position);
13586   }
13587   return position;
13588 }
13589 
InitLineEnds(Handle<Script> script)13590 void Script::InitLineEnds(Handle<Script> script) {
13591   Isolate* isolate = script->GetIsolate();
13592   if (!script->line_ends()->IsUndefined(isolate)) return;
13593   DCHECK_NE(Script::TYPE_WASM, script->type());
13594 
13595   Object* src_obj = script->source();
13596   if (!src_obj->IsString()) {
13597     DCHECK(src_obj->IsUndefined(isolate));
13598     script->set_line_ends(ReadOnlyRoots(isolate).empty_fixed_array());
13599   } else {
13600     DCHECK(src_obj->IsString());
13601     Handle<String> src(String::cast(src_obj), isolate);
13602     Handle<FixedArray> array = String::CalculateLineEnds(isolate, src, true);
13603     script->set_line_ends(*array);
13604   }
13605 
13606   DCHECK(script->line_ends()->IsFixedArray());
13607 }
13608 
GetPositionInfo(Handle<Script> script,int position,PositionInfo * info,OffsetFlag offset_flag)13609 bool Script::GetPositionInfo(Handle<Script> script, int position,
13610                              PositionInfo* info, OffsetFlag offset_flag) {
13611   // For wasm, we do not create an artificial line_ends array, but do the
13612   // translation directly.
13613   if (script->type() != Script::TYPE_WASM) InitLineEnds(script);
13614   return script->GetPositionInfo(position, info, offset_flag);
13615 }
13616 
IsUserJavaScript()13617 bool Script::IsUserJavaScript() { return type() == Script::TYPE_NORMAL; }
13618 
ContainsAsmModule()13619 bool Script::ContainsAsmModule() {
13620   DisallowHeapAllocation no_gc;
13621   SharedFunctionInfo::ScriptIterator iter(this->GetIsolate(), this);
13622   while (SharedFunctionInfo* info = iter.Next()) {
13623     if (info->HasAsmWasmData()) return true;
13624   }
13625   return false;
13626 }
13627 
13628 namespace {
GetPositionInfoSlow(const Script * script,int position,Script::PositionInfo * info)13629 bool GetPositionInfoSlow(const Script* script, int position,
13630                          Script::PositionInfo* info) {
13631   if (!script->source()->IsString()) return false;
13632   if (position < 0) position = 0;
13633 
13634   String* source_string = String::cast(script->source());
13635   int line = 0;
13636   int line_start = 0;
13637   int len = source_string->length();
13638   for (int pos = 0; pos <= len; ++pos) {
13639     if (pos == len || source_string->Get(pos) == '\n') {
13640       if (position <= pos) {
13641         info->line = line;
13642         info->column = position - line_start;
13643         info->line_start = line_start;
13644         info->line_end = pos;
13645         return true;
13646       }
13647       line++;
13648       line_start = pos + 1;
13649     }
13650   }
13651   return false;
13652 }
13653 }  // namespace
13654 
13655 #define SMI_VALUE(x) (Smi::ToInt(x))
GetPositionInfo(int position,PositionInfo * info,OffsetFlag offset_flag) const13656 bool Script::GetPositionInfo(int position, PositionInfo* info,
13657                              OffsetFlag offset_flag) const {
13658   DisallowHeapAllocation no_allocation;
13659 
13660   // For wasm, we do not rely on the line_ends array, but do the translation
13661   // directly.
13662   if (type() == Script::TYPE_WASM) {
13663     DCHECK_LE(0, position);
13664     return WasmModuleObject::cast(wasm_module_object())
13665         ->GetPositionInfo(static_cast<uint32_t>(position), info);
13666   }
13667 
13668   if (line_ends()->IsUndefined()) {
13669     // Slow mode: we do not have line_ends. We have to iterate through source.
13670     if (!GetPositionInfoSlow(this, position, info)) return false;
13671   } else {
13672     DCHECK(line_ends()->IsFixedArray());
13673     FixedArray* ends = FixedArray::cast(line_ends());
13674 
13675     const int ends_len = ends->length();
13676     if (ends_len == 0) return false;
13677 
13678     // Return early on invalid positions. Negative positions behave as if 0 was
13679     // passed, and positions beyond the end of the script return as failure.
13680     if (position < 0) {
13681       position = 0;
13682     } else if (position > SMI_VALUE(ends->get(ends_len - 1))) {
13683       return false;
13684     }
13685 
13686     // Determine line number by doing a binary search on the line ends array.
13687     if (SMI_VALUE(ends->get(0)) >= position) {
13688       info->line = 0;
13689       info->line_start = 0;
13690       info->column = position;
13691     } else {
13692       int left = 0;
13693       int right = ends_len - 1;
13694 
13695       while (right > 0) {
13696         DCHECK_LE(left, right);
13697         const int mid = (left + right) / 2;
13698         if (position > SMI_VALUE(ends->get(mid))) {
13699           left = mid + 1;
13700         } else if (position <= SMI_VALUE(ends->get(mid - 1))) {
13701           right = mid - 1;
13702         } else {
13703           info->line = mid;
13704           break;
13705         }
13706       }
13707       DCHECK(SMI_VALUE(ends->get(info->line)) >= position &&
13708              SMI_VALUE(ends->get(info->line - 1)) < position);
13709       info->line_start = SMI_VALUE(ends->get(info->line - 1)) + 1;
13710       info->column = position - info->line_start;
13711     }
13712 
13713     // Line end is position of the linebreak character.
13714     info->line_end = SMI_VALUE(ends->get(info->line));
13715     if (info->line_end > 0) {
13716       DCHECK(source()->IsString());
13717       String* src = String::cast(source());
13718       if (src->length() >= info->line_end &&
13719           src->Get(info->line_end - 1) == '\r') {
13720         info->line_end--;
13721       }
13722     }
13723   }
13724 
13725   // Add offsets if requested.
13726   if (offset_flag == WITH_OFFSET) {
13727     if (info->line == 0) {
13728       info->column += column_offset();
13729     }
13730     info->line += line_offset();
13731   }
13732 
13733   return true;
13734 }
13735 #undef SMI_VALUE
13736 
GetColumnNumber(Handle<Script> script,int code_pos)13737 int Script::GetColumnNumber(Handle<Script> script, int code_pos) {
13738   PositionInfo info;
13739   GetPositionInfo(script, code_pos, &info, WITH_OFFSET);
13740   return info.column;
13741 }
13742 
GetColumnNumber(int code_pos) const13743 int Script::GetColumnNumber(int code_pos) const {
13744   PositionInfo info;
13745   GetPositionInfo(code_pos, &info, WITH_OFFSET);
13746   return info.column;
13747 }
13748 
GetLineNumber(Handle<Script> script,int code_pos)13749 int Script::GetLineNumber(Handle<Script> script, int code_pos) {
13750   PositionInfo info;
13751   GetPositionInfo(script, code_pos, &info, WITH_OFFSET);
13752   return info.line;
13753 }
13754 
GetLineNumber(int code_pos) const13755 int Script::GetLineNumber(int code_pos) const {
13756   PositionInfo info;
13757   GetPositionInfo(code_pos, &info, WITH_OFFSET);
13758   return info.line;
13759 }
13760 
GetNameOrSourceURL()13761 Object* Script::GetNameOrSourceURL() {
13762   // Keep in sync with ScriptNameOrSourceURL in messages.js.
13763   if (!source_url()->IsUndefined()) return source_url();
13764   return name();
13765 }
13766 
FindSharedFunctionInfo(Isolate * isolate,const FunctionLiteral * fun)13767 MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
13768     Isolate* isolate, const FunctionLiteral* fun) {
13769   CHECK_NE(fun->function_literal_id(), FunctionLiteral::kIdTypeInvalid);
13770   // If this check fails, the problem is most probably the function id
13771   // renumbering done by AstFunctionLiteralIdReindexer; in particular, that
13772   // AstTraversalVisitor doesn't recurse properly in the construct which
13773   // triggers the mismatch.
13774   CHECK_LT(fun->function_literal_id(), shared_function_infos()->length());
13775   MaybeObject* shared =
13776       shared_function_infos()->Get(fun->function_literal_id());
13777   HeapObject* heap_object;
13778   if (!shared->ToStrongOrWeakHeapObject(&heap_object) ||
13779       heap_object->IsUndefined(isolate)) {
13780     return MaybeHandle<SharedFunctionInfo>();
13781   }
13782   return handle(SharedFunctionInfo::cast(heap_object), isolate);
13783 }
13784 
Iterator(Isolate * isolate)13785 Script::Iterator::Iterator(Isolate* isolate)
13786     : iterator_(isolate->heap()->script_list()) {}
13787 
Next()13788 Script* Script::Iterator::Next() {
13789   Object* o = iterator_.Next();
13790   if (o != nullptr) {
13791     return Script::cast(o);
13792   }
13793   return nullptr;
13794 }
13795 
GetCode() const13796 Code* SharedFunctionInfo::GetCode() const {
13797   // ======
13798   // NOTE: This chain of checks MUST be kept in sync with the equivalent CSA
13799   // GetSharedFunctionInfoCode method in code-stub-assembler.cc.
13800   // ======
13801 
13802   Isolate* isolate = GetIsolate();
13803   Object* data = function_data();
13804   if (data->IsSmi()) {
13805     // Holding a Smi means we are a builtin.
13806     DCHECK(HasBuiltinId());
13807     return isolate->builtins()->builtin(builtin_id());
13808   } else if (data->IsBytecodeArray()) {
13809     // Having a bytecode array means we are a compiled, interpreted function.
13810     DCHECK(HasBytecodeArray());
13811     return isolate->builtins()->builtin(Builtins::kInterpreterEntryTrampoline);
13812   } else if (data->IsFixedArray()) {
13813     // Having a fixed array means we are an asm.js/wasm function.
13814     DCHECK(HasAsmWasmData());
13815     return isolate->builtins()->builtin(Builtins::kInstantiateAsmJs);
13816   } else if (data->IsUncompiledData()) {
13817     // Having uncompiled data (with or without scope) means we need to compile.
13818     DCHECK(HasUncompiledData());
13819     return isolate->builtins()->builtin(Builtins::kCompileLazy);
13820   } else if (data->IsFunctionTemplateInfo()) {
13821     // Having a function template info means we are an API function.
13822     DCHECK(IsApiFunction());
13823     return isolate->builtins()->builtin(Builtins::kHandleApiCall);
13824   } else if (data->IsWasmExportedFunctionData()) {
13825     // Having a WasmExportedFunctionData means the code is in there.
13826     DCHECK(HasWasmExportedFunctionData());
13827     return wasm_exported_function_data()->wrapper_code();
13828   } else if (data->IsInterpreterData()) {
13829     Code* code = InterpreterTrampoline();
13830     DCHECK(code->IsCode());
13831     DCHECK(code->is_interpreter_trampoline_builtin());
13832     return code;
13833   }
13834   UNREACHABLE();
13835 }
13836 
wasm_exported_function_data() const13837 WasmExportedFunctionData* SharedFunctionInfo::wasm_exported_function_data()
13838     const {
13839   DCHECK(HasWasmExportedFunctionData());
13840   return WasmExportedFunctionData::cast(function_data());
13841 }
13842 
ScriptIterator(Isolate * isolate,Script * script)13843 SharedFunctionInfo::ScriptIterator::ScriptIterator(Isolate* isolate,
13844                                                    Script* script)
13845     : ScriptIterator(isolate,
13846                      handle(script->shared_function_infos(), isolate)) {}
13847 
ScriptIterator(Isolate * isolate,Handle<WeakFixedArray> shared_function_infos)13848 SharedFunctionInfo::ScriptIterator::ScriptIterator(
13849     Isolate* isolate, Handle<WeakFixedArray> shared_function_infos)
13850     : isolate_(isolate),
13851       shared_function_infos_(shared_function_infos),
13852       index_(0) {}
13853 
Next()13854 SharedFunctionInfo* SharedFunctionInfo::ScriptIterator::Next() {
13855   while (index_ < shared_function_infos_->length()) {
13856     MaybeObject* raw = shared_function_infos_->Get(index_++);
13857     HeapObject* heap_object;
13858     if (!raw->ToStrongOrWeakHeapObject(&heap_object) ||
13859         heap_object->IsUndefined(isolate_)) {
13860       continue;
13861     }
13862     return SharedFunctionInfo::cast(heap_object);
13863   }
13864   return nullptr;
13865 }
13866 
Reset(Script * script)13867 void SharedFunctionInfo::ScriptIterator::Reset(Script* script) {
13868   shared_function_infos_ = handle(script->shared_function_infos(), isolate_);
13869   index_ = 0;
13870 }
13871 
GlobalIterator(Isolate * isolate)13872 SharedFunctionInfo::GlobalIterator::GlobalIterator(Isolate* isolate)
13873     : script_iterator_(isolate),
13874       noscript_sfi_iterator_(isolate->heap()->noscript_shared_function_infos()),
13875       sfi_iterator_(isolate, script_iterator_.Next()) {}
13876 
Next()13877 SharedFunctionInfo* SharedFunctionInfo::GlobalIterator::Next() {
13878   HeapObject* next = noscript_sfi_iterator_.Next();
13879   if (next != nullptr) return SharedFunctionInfo::cast(next);
13880   for (;;) {
13881     next = sfi_iterator_.Next();
13882     if (next != nullptr) return SharedFunctionInfo::cast(next);
13883     Script* next_script = script_iterator_.Next();
13884     if (next_script == nullptr) return nullptr;
13885     sfi_iterator_.Reset(next_script);
13886   }
13887 }
13888 
SetScript(Handle<SharedFunctionInfo> shared,Handle<Object> script_object,int function_literal_id,bool reset_preparsed_scope_data)13889 void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
13890                                    Handle<Object> script_object,
13891                                    int function_literal_id,
13892                                    bool reset_preparsed_scope_data) {
13893   if (shared->script() == *script_object) return;
13894   Isolate* isolate = shared->GetIsolate();
13895 
13896   if (reset_preparsed_scope_data &&
13897       shared->HasUncompiledDataWithPreParsedScope()) {
13898     shared->ClearPreParsedScopeData();
13899   }
13900 
13901   // Add shared function info to new script's list. If a collection occurs,
13902   // the shared function info may be temporarily in two lists.
13903   // This is okay because the gc-time processing of these lists can tolerate
13904   // duplicates.
13905   if (script_object->IsScript()) {
13906     DCHECK(!shared->script()->IsScript());
13907     Handle<Script> script = Handle<Script>::cast(script_object);
13908     Handle<WeakFixedArray> list =
13909         handle(script->shared_function_infos(), isolate);
13910 #ifdef DEBUG
13911     DCHECK_LT(function_literal_id, list->length());
13912     MaybeObject* maybe_object = list->Get(function_literal_id);
13913     HeapObject* heap_object;
13914     if (maybe_object->ToWeakHeapObject(&heap_object)) {
13915       DCHECK_EQ(heap_object, *shared);
13916     }
13917 #endif
13918     list->Set(function_literal_id, HeapObjectReference::Weak(*shared));
13919 
13920     // Remove shared function info from root array.
13921     WeakArrayList* noscript_list =
13922         isolate->heap()->noscript_shared_function_infos();
13923     CHECK(noscript_list->RemoveOne(MaybeObjectHandle::Weak(shared)));
13924   } else {
13925     DCHECK(shared->script()->IsScript());
13926     Handle<WeakArrayList> list =
13927         isolate->factory()->noscript_shared_function_infos();
13928 
13929 #ifdef DEBUG
13930     if (FLAG_enable_slow_asserts) {
13931       WeakArrayList::Iterator iterator(*list);
13932       HeapObject* next;
13933       while ((next = iterator.Next()) != nullptr) {
13934         DCHECK_NE(next, *shared);
13935       }
13936     }
13937 #endif  // DEBUG
13938 
13939     list =
13940         WeakArrayList::AddToEnd(isolate, list, MaybeObjectHandle::Weak(shared));
13941 
13942     isolate->heap()->SetRootNoScriptSharedFunctionInfos(*list);
13943 
13944     // Remove shared function info from old script's list.
13945     Script* old_script = Script::cast(shared->script());
13946 
13947     // Due to liveedit, it might happen that the old_script doesn't know
13948     // about the SharedFunctionInfo, so we have to guard against that.
13949     Handle<WeakFixedArray> infos(old_script->shared_function_infos(), isolate);
13950     if (function_literal_id < infos->length()) {
13951       MaybeObject* raw =
13952           old_script->shared_function_infos()->Get(function_literal_id);
13953       HeapObject* heap_object;
13954       if (raw->ToWeakHeapObject(&heap_object) && heap_object == *shared) {
13955         old_script->shared_function_infos()->Set(
13956             function_literal_id, HeapObjectReference::Strong(
13957                                      ReadOnlyRoots(isolate).undefined_value()));
13958       }
13959     }
13960   }
13961 
13962   // Finally set new script.
13963   shared->set_script(*script_object);
13964 }
13965 
HasBreakInfo() const13966 bool SharedFunctionInfo::HasBreakInfo() const {
13967   if (!HasDebugInfo()) return false;
13968   DebugInfo* info = DebugInfo::cast(GetDebugInfo());
13969   bool has_break_info = info->HasBreakInfo();
13970   return has_break_info;
13971 }
13972 
BreakAtEntry() const13973 bool SharedFunctionInfo::BreakAtEntry() const {
13974   if (!HasDebugInfo()) return false;
13975   DebugInfo* info = DebugInfo::cast(GetDebugInfo());
13976   bool break_at_entry = info->BreakAtEntry();
13977   return break_at_entry;
13978 }
13979 
HasCoverageInfo() const13980 bool SharedFunctionInfo::HasCoverageInfo() const {
13981   if (!HasDebugInfo()) return false;
13982   DebugInfo* info = DebugInfo::cast(GetDebugInfo());
13983   bool has_coverage_info = info->HasCoverageInfo();
13984   return has_coverage_info;
13985 }
13986 
GetCoverageInfo() const13987 CoverageInfo* SharedFunctionInfo::GetCoverageInfo() const {
13988   DCHECK(HasCoverageInfo());
13989   return CoverageInfo::cast(GetDebugInfo()->coverage_info());
13990 }
13991 
DebugName()13992 String* SharedFunctionInfo::DebugName() {
13993   DisallowHeapAllocation no_gc;
13994   String* function_name = Name();
13995   if (function_name->length() > 0) return function_name;
13996   return inferred_name();
13997 }
13998 
PassesFilter(const char * raw_filter)13999 bool SharedFunctionInfo::PassesFilter(const char* raw_filter) {
14000   Vector<const char> filter = CStrVector(raw_filter);
14001   std::unique_ptr<char[]> cstrname(DebugName()->ToCString());
14002   return v8::internal::PassesFilter(CStrVector(cstrname.get()), filter);
14003 }
14004 
HasSourceCode() const14005 bool SharedFunctionInfo::HasSourceCode() const {
14006   Isolate* isolate = GetIsolate();
14007   return !script()->IsUndefined(isolate) &&
14008          !reinterpret_cast<Script*>(script())->source()->IsUndefined(isolate);
14009 }
14010 
14011 // static
GetSourceCode(Handle<SharedFunctionInfo> shared)14012 Handle<Object> SharedFunctionInfo::GetSourceCode(
14013     Handle<SharedFunctionInfo> shared) {
14014   Isolate* isolate = shared->GetIsolate();
14015   if (!shared->HasSourceCode()) return isolate->factory()->undefined_value();
14016   Handle<String> source(String::cast(Script::cast(shared->script())->source()),
14017                         isolate);
14018   return isolate->factory()->NewSubString(source, shared->StartPosition(),
14019                                           shared->EndPosition());
14020 }
14021 
14022 // static
GetSourceCodeHarmony(Handle<SharedFunctionInfo> shared)14023 Handle<Object> SharedFunctionInfo::GetSourceCodeHarmony(
14024     Handle<SharedFunctionInfo> shared) {
14025   Isolate* isolate = shared->GetIsolate();
14026   if (!shared->HasSourceCode()) return isolate->factory()->undefined_value();
14027   Handle<String> script_source(
14028       String::cast(Script::cast(shared->script())->source()), isolate);
14029   int start_pos = shared->function_token_position();
14030   DCHECK_NE(start_pos, kNoSourcePosition);
14031   Handle<String> source = isolate->factory()->NewSubString(
14032       script_source, start_pos, shared->EndPosition());
14033   if (!shared->is_wrapped()) return source;
14034 
14035   DCHECK(!shared->name_should_print_as_anonymous());
14036   IncrementalStringBuilder builder(isolate);
14037   builder.AppendCString("function ");
14038   builder.AppendString(Handle<String>(shared->Name(), isolate));
14039   builder.AppendCString("(");
14040   Handle<FixedArray> args(Script::cast(shared->script())->wrapped_arguments(),
14041                           isolate);
14042   int argc = args->length();
14043   for (int i = 0; i < argc; i++) {
14044     if (i > 0) builder.AppendCString(", ");
14045     builder.AppendString(Handle<String>(String::cast(args->get(i)), isolate));
14046   }
14047   builder.AppendCString(") {\n");
14048   builder.AppendString(source);
14049   builder.AppendCString("\n}");
14050   return builder.Finish().ToHandleChecked();
14051 }
14052 
IsInlineable()14053 bool SharedFunctionInfo::IsInlineable() {
14054   // Check that the function has a script associated with it.
14055   if (!script()->IsScript()) return false;
14056   if (GetIsolate()->is_precise_binary_code_coverage() &&
14057       !has_reported_binary_coverage()) {
14058     // We may miss invocations if this function is inlined.
14059     return false;
14060   }
14061   return !optimization_disabled();
14062 }
14063 
SourceSize()14064 int SharedFunctionInfo::SourceSize() { return EndPosition() - StartPosition(); }
14065 
FindIndexInScript(Isolate * isolate) const14066 int SharedFunctionInfo::FindIndexInScript(Isolate* isolate) const {
14067   DisallowHeapAllocation no_gc;
14068 
14069   Object* script_obj = script();
14070   if (!script_obj->IsScript()) return FunctionLiteral::kIdTypeInvalid;
14071 
14072   WeakFixedArray* shared_info_list =
14073       Script::cast(script_obj)->shared_function_infos();
14074   SharedFunctionInfo::ScriptIterator iterator(
14075       isolate, Handle<WeakFixedArray>(&shared_info_list));
14076 
14077   for (SharedFunctionInfo* shared = iterator.Next(); shared != nullptr;
14078        shared = iterator.Next()) {
14079     if (shared == this) {
14080       return iterator.CurrentIndex();
14081     }
14082   }
14083 
14084   return FunctionLiteral::kIdTypeInvalid;
14085 }
14086 
CalculateInstanceSizeHelper(InstanceType instance_type,bool has_prototype_slot,int requested_embedder_fields,int requested_in_object_properties,int * instance_size,int * in_object_properties)14087 void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type,
14088                                              bool has_prototype_slot,
14089                                              int requested_embedder_fields,
14090                                              int requested_in_object_properties,
14091                                              int* instance_size,
14092                                              int* in_object_properties) {
14093   DCHECK_LE(static_cast<unsigned>(requested_embedder_fields),
14094             JSObject::kMaxEmbedderFields);
14095   int header_size = JSObject::GetHeaderSize(instance_type, has_prototype_slot);
14096   int max_nof_fields =
14097       (JSObject::kMaxInstanceSize - header_size) >> kPointerSizeLog2;
14098   CHECK_LE(max_nof_fields, JSObject::kMaxInObjectProperties);
14099   CHECK_LE(static_cast<unsigned>(requested_embedder_fields),
14100            static_cast<unsigned>(max_nof_fields));
14101   *in_object_properties = Min(requested_in_object_properties,
14102                               max_nof_fields - requested_embedder_fields);
14103   *instance_size =
14104       header_size +
14105       ((requested_embedder_fields + *in_object_properties) << kPointerSizeLog2);
14106   CHECK_EQ(*in_object_properties,
14107            ((*instance_size - header_size) >> kPointerSizeLog2) -
14108                requested_embedder_fields);
14109   CHECK_LE(static_cast<unsigned>(*instance_size),
14110            static_cast<unsigned>(JSObject::kMaxInstanceSize));
14111 }
14112 
14113 // static
CalculateInstanceSizeForDerivedClass(Handle<JSFunction> function,InstanceType instance_type,int requested_embedder_fields,int * instance_size,int * in_object_properties)14114 bool JSFunction::CalculateInstanceSizeForDerivedClass(
14115     Handle<JSFunction> function, InstanceType instance_type,
14116     int requested_embedder_fields, int* instance_size,
14117     int* in_object_properties) {
14118   Isolate* isolate = function->GetIsolate();
14119   int expected_nof_properties = 0;
14120   for (PrototypeIterator iter(isolate, function, kStartAtReceiver);
14121        !iter.IsAtEnd(); iter.Advance()) {
14122     Handle<JSReceiver> current =
14123         PrototypeIterator::GetCurrent<JSReceiver>(iter);
14124     if (!current->IsJSFunction()) break;
14125     Handle<JSFunction> func(Handle<JSFunction>::cast(current));
14126     // The super constructor should be compiled for the number of expected
14127     // properties to be available.
14128     Handle<SharedFunctionInfo> shared(func->shared(), isolate);
14129     if (shared->is_compiled() ||
14130         Compiler::Compile(func, Compiler::CLEAR_EXCEPTION)) {
14131       DCHECK(shared->is_compiled());
14132       int count = shared->expected_nof_properties();
14133       // Check that the estimate is sane.
14134       if (expected_nof_properties <= JSObject::kMaxInObjectProperties - count) {
14135         expected_nof_properties += count;
14136       } else {
14137         expected_nof_properties = JSObject::kMaxInObjectProperties;
14138       }
14139     } else if (!shared->is_compiled()) {
14140       // In case there was a compilation error for the constructor we will
14141       // throw an error during instantiation. Hence we directly return 0;
14142       return false;
14143     }
14144     if (!IsDerivedConstructor(shared->kind())) break;
14145   }
14146   CalculateInstanceSizeHelper(instance_type, true, requested_embedder_fields,
14147                               expected_nof_properties, instance_size,
14148                               in_object_properties);
14149   return true;
14150 }
14151 
14152 
14153 // Output the source code without any allocation in the heap.
operator <<(std::ostream & os,const SourceCodeOf & v)14154 std::ostream& operator<<(std::ostream& os, const SourceCodeOf& v) {
14155   const SharedFunctionInfo* s = v.value;
14156   // For some native functions there is no source.
14157   if (!s->HasSourceCode()) return os << "<No Source>";
14158 
14159   // Get the source for the script which this function came from.
14160   // Don't use String::cast because we don't want more assertion errors while
14161   // we are already creating a stack dump.
14162   String* script_source =
14163       reinterpret_cast<String*>(Script::cast(s->script())->source());
14164 
14165   if (!script_source->LooksValid()) return os << "<Invalid Source>";
14166 
14167   if (!s->is_toplevel()) {
14168     os << "function ";
14169     String* name = s->Name();
14170     if (name->length() > 0) {
14171       name->PrintUC16(os);
14172     }
14173   }
14174 
14175   int len = s->EndPosition() - s->StartPosition();
14176   if (len <= v.max_length || v.max_length < 0) {
14177     script_source->PrintUC16(os, s->StartPosition(), s->EndPosition());
14178     return os;
14179   } else {
14180     script_source->PrintUC16(os, s->StartPosition(),
14181                              s->StartPosition() + v.max_length);
14182     return os << "...\n";
14183   }
14184 }
14185 
14186 
DisableOptimization(BailoutReason reason)14187 void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
14188   DCHECK_NE(reason, BailoutReason::kNoReason);
14189 
14190   set_flags(DisabledOptimizationReasonBits::update(flags(), reason));
14191   // Code should be the lazy compilation stub or else interpreted.
14192   DCHECK(abstract_code()->kind() == AbstractCode::INTERPRETED_FUNCTION ||
14193          abstract_code()->kind() == AbstractCode::BUILTIN);
14194   PROFILE(GetIsolate(), CodeDisableOptEvent(abstract_code(), this));
14195   if (FLAG_trace_opt) {
14196     PrintF("[disabled optimization for ");
14197     ShortPrint();
14198     PrintF(", reason: %s]\n", GetBailoutReason(reason));
14199   }
14200 }
14201 
InitFromFunctionLiteral(Handle<SharedFunctionInfo> shared_info,FunctionLiteral * lit,bool is_toplevel)14202 void SharedFunctionInfo::InitFromFunctionLiteral(
14203     Handle<SharedFunctionInfo> shared_info, FunctionLiteral* lit,
14204     bool is_toplevel) {
14205   Isolate* isolate = shared_info->GetIsolate();
14206   bool needs_position_info = true;
14207 
14208   // When adding fields here, make sure DeclarationScope::AnalyzePartially is
14209   // updated accordingly.
14210   shared_info->set_internal_formal_parameter_count(lit->parameter_count());
14211   shared_info->SetFunctionTokenPosition(lit->function_token_position(),
14212                                         lit->start_position());
14213   if (shared_info->scope_info()->HasPositionInfo()) {
14214     shared_info->scope_info()->SetPositionInfo(lit->start_position(),
14215                                                lit->end_position());
14216     needs_position_info = false;
14217   }
14218   shared_info->set_is_declaration(lit->is_declaration());
14219   shared_info->set_is_named_expression(lit->is_named_expression());
14220   shared_info->set_is_anonymous_expression(lit->is_anonymous_expression());
14221   shared_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
14222   shared_info->set_language_mode(lit->language_mode());
14223   shared_info->set_is_wrapped(lit->is_wrapped());
14224   //  shared_info->set_kind(lit->kind());
14225   // FunctionKind must have already been set.
14226   DCHECK(lit->kind() == shared_info->kind());
14227   shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
14228   DCHECK_IMPLIES(lit->requires_instance_fields_initializer(),
14229                  IsClassConstructor(lit->kind()));
14230   shared_info->set_requires_instance_fields_initializer(
14231       lit->requires_instance_fields_initializer());
14232 
14233   shared_info->set_is_toplevel(is_toplevel);
14234   DCHECK(shared_info->outer_scope_info()->IsTheHole());
14235   if (!is_toplevel) {
14236     Scope* outer_scope = lit->scope()->GetOuterScopeWithContext();
14237     if (outer_scope) {
14238       shared_info->set_outer_scope_info(*outer_scope->scope_info());
14239     }
14240   }
14241 
14242   // For lazy parsed functions, the following flags will be inaccurate since we
14243   // don't have the information yet. They're set later in
14244   // SetSharedFunctionFlagsFromLiteral (compiler.cc), when the function is
14245   // really parsed and compiled.
14246   if (lit->body() != nullptr) {
14247     shared_info->set_length(lit->function_length());
14248     shared_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
14249     shared_info->SetExpectedNofPropertiesFromEstimate(lit);
14250     DCHECK_NULL(lit->produced_preparsed_scope_data());
14251     if (lit->ShouldEagerCompile()) {
14252       // If we're about to eager compile, we'll have the function literal
14253       // available, so there's no need to wastefully allocate an uncompiled
14254       // data.
14255       // TODO(leszeks): This should be explicitly passed as a parameter, rather
14256       // than relying on a property of the literal.
14257       needs_position_info = false;
14258     }
14259   } else {
14260     // Set an invalid length for lazy functions. This way we can set the correct
14261     // value after compiling, but avoid overwriting values set manually by the
14262     // bootstrapper.
14263     shared_info->set_length(SharedFunctionInfo::kInvalidLength);
14264     if (FLAG_preparser_scope_analysis) {
14265       ProducedPreParsedScopeData* scope_data =
14266           lit->produced_preparsed_scope_data();
14267       if (scope_data != nullptr) {
14268         Handle<PreParsedScopeData> pre_parsed_scope_data;
14269         if (scope_data->Serialize(shared_info->GetIsolate())
14270                 .ToHandle(&pre_parsed_scope_data)) {
14271           Handle<UncompiledData> data =
14272               isolate->factory()->NewUncompiledDataWithPreParsedScope(
14273                   lit->inferred_name(), lit->start_position(),
14274                   lit->end_position(), lit->function_literal_id(),
14275                   pre_parsed_scope_data);
14276           shared_info->set_uncompiled_data(*data);
14277           needs_position_info = false;
14278         }
14279       }
14280     }
14281   }
14282   if (needs_position_info) {
14283     Handle<UncompiledData> data =
14284         isolate->factory()->NewUncompiledDataWithoutPreParsedScope(
14285             lit->inferred_name(), lit->start_position(), lit->end_position(),
14286             lit->function_literal_id());
14287     shared_info->set_uncompiled_data(*data);
14288   }
14289 }
14290 
SetExpectedNofPropertiesFromEstimate(FunctionLiteral * literal)14291 void SharedFunctionInfo::SetExpectedNofPropertiesFromEstimate(
14292     FunctionLiteral* literal) {
14293   int estimate = literal->expected_property_count();
14294 
14295   // If no properties are added in the constructor, they are more likely
14296   // to be added later.
14297   if (estimate == 0) estimate = 2;
14298 
14299   // Inobject slack tracking will reclaim redundant inobject space later,
14300   // so we can afford to adjust the estimate generously.
14301   estimate += 8;
14302 
14303   // Limit actual estimate to fit in a 8 bit field, we will never allocate
14304   // more than this in any case.
14305   STATIC_ASSERT(JSObject::kMaxInObjectProperties <= kMaxUInt8);
14306   estimate = std::min(estimate, kMaxUInt8);
14307 
14308   set_expected_nof_properties(estimate);
14309 }
14310 
SetFunctionTokenPosition(int function_token_position,int start_position)14311 void SharedFunctionInfo::SetFunctionTokenPosition(int function_token_position,
14312                                                   int start_position) {
14313   int offset;
14314   if (function_token_position == kNoSourcePosition) {
14315     offset = 0;
14316   } else {
14317     offset = start_position - function_token_position;
14318   }
14319 
14320   if (offset > kMaximumFunctionTokenOffset) {
14321     offset = kFunctionTokenOutOfRange;
14322   }
14323   set_raw_function_token_offset(offset);
14324 }
14325 
StartInobjectSlackTracking()14326 void Map::StartInobjectSlackTracking() {
14327   DCHECK(!IsInobjectSlackTrackingInProgress());
14328   if (UnusedPropertyFields() == 0) return;
14329   set_construction_counter(Map::kSlackTrackingCounterStart);
14330 }
14331 
VisitCodeTarget(Code * host,RelocInfo * rinfo)14332 void ObjectVisitor::VisitCodeTarget(Code* host, RelocInfo* rinfo) {
14333   DCHECK(RelocInfo::IsCodeTargetMode(rinfo->rmode()));
14334   Object* old_pointer = Code::GetCodeFromTargetAddress(rinfo->target_address());
14335   Object* new_pointer = old_pointer;
14336   VisitPointer(host, &new_pointer);
14337   DCHECK_EQ(old_pointer, new_pointer);
14338 }
14339 
VisitEmbeddedPointer(Code * host,RelocInfo * rinfo)14340 void ObjectVisitor::VisitEmbeddedPointer(Code* host, RelocInfo* rinfo) {
14341   DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
14342   Object* old_pointer = rinfo->target_object();
14343   Object* new_pointer = old_pointer;
14344   VisitPointer(host, &new_pointer);
14345   DCHECK_EQ(old_pointer, new_pointer);
14346 }
14347 
VisitRelocInfo(RelocIterator * it)14348 void ObjectVisitor::VisitRelocInfo(RelocIterator* it) {
14349   for (; !it->done(); it->next()) {
14350     it->rinfo()->Visit(this);
14351   }
14352 }
14353 
InvalidateEmbeddedObjects(Heap * heap)14354 void Code::InvalidateEmbeddedObjects(Heap* heap) {
14355   HeapObject* undefined = ReadOnlyRoots(heap).undefined_value();
14356   int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
14357   for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
14358     RelocInfo::Mode mode = it.rinfo()->rmode();
14359     if (mode == RelocInfo::EMBEDDED_OBJECT) {
14360       it.rinfo()->set_target_object(heap, undefined, SKIP_WRITE_BARRIER);
14361     }
14362   }
14363 }
14364 
14365 
Relocate(intptr_t delta)14366 void Code::Relocate(intptr_t delta) {
14367   for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
14368     it.rinfo()->apply(delta);
14369   }
14370   Assembler::FlushICache(raw_instruction_start(), raw_instruction_size());
14371 }
14372 
FlushICache() const14373 void Code::FlushICache() const {
14374   Assembler::FlushICache(raw_instruction_start(), raw_instruction_size());
14375 }
14376 
CopyFrom(Heap * heap,const CodeDesc & desc)14377 void Code::CopyFrom(Heap* heap, const CodeDesc& desc) {
14378   CopyFromNoFlush(heap, desc);
14379   FlushICache();
14380 }
14381 
CopyFromNoFlush(Heap * heap,const CodeDesc & desc)14382 void Code::CopyFromNoFlush(Heap* heap, const CodeDesc& desc) {
14383   // Copy code.
14384   CopyBytes(reinterpret_cast<byte*>(raw_instruction_start()), desc.buffer,
14385             static_cast<size_t>(desc.instr_size));
14386 
14387   // Copy unwinding info, if any.
14388   if (desc.unwinding_info) {
14389     DCHECK_GT(desc.unwinding_info_size, 0);
14390     set_unwinding_info_size(desc.unwinding_info_size);
14391     CopyBytes(reinterpret_cast<byte*>(unwinding_info_start()),
14392               desc.unwinding_info,
14393               static_cast<size_t>(desc.unwinding_info_size));
14394   }
14395 
14396   // Copy reloc info.
14397   CopyBytes(relocation_start(),
14398             desc.buffer + desc.buffer_size - desc.reloc_size,
14399             static_cast<size_t>(desc.reloc_size));
14400 
14401   // Unbox handles and relocate.
14402   Assembler* origin = desc.origin;
14403   AllowDeferredHandleDereference embedding_raw_address;
14404   const int mode_mask = RelocInfo::PostCodegenRelocationMask();
14405   for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
14406     RelocInfo::Mode mode = it.rinfo()->rmode();
14407     if (mode == RelocInfo::EMBEDDED_OBJECT) {
14408       Handle<HeapObject> p = it.rinfo()->target_object_handle(origin);
14409       it.rinfo()->set_target_object(heap, *p, UPDATE_WRITE_BARRIER,
14410                                     SKIP_ICACHE_FLUSH);
14411     } else if (RelocInfo::IsCodeTargetMode(mode)) {
14412       // Rewrite code handles to direct pointers to the first instruction in the
14413       // code object.
14414       Handle<Object> p = it.rinfo()->target_object_handle(origin);
14415       Code* code = Code::cast(*p);
14416       it.rinfo()->set_target_address(code->raw_instruction_start(),
14417                                      UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
14418     } else if (RelocInfo::IsRuntimeEntry(mode)) {
14419       Address p = it.rinfo()->target_runtime_entry(origin);
14420       it.rinfo()->set_target_runtime_entry(p, UPDATE_WRITE_BARRIER,
14421                                            SKIP_ICACHE_FLUSH);
14422     } else {
14423       intptr_t delta =
14424           raw_instruction_start() - reinterpret_cast<Address>(desc.buffer);
14425       it.rinfo()->apply(delta);
14426     }
14427   }
14428 }
14429 
14430 
GetSafepointEntry(Address pc)14431 SafepointEntry Code::GetSafepointEntry(Address pc) {
14432   SafepointTable table(this);
14433   return table.FindEntry(pc);
14434 }
14435 
OffHeapInstructionSize() const14436 int Code::OffHeapInstructionSize() const {
14437   DCHECK(is_off_heap_trampoline());
14438   if (Isolate::CurrentEmbeddedBlob() == nullptr) return raw_instruction_size();
14439   EmbeddedData d = EmbeddedData::FromBlob();
14440   return d.InstructionSizeOfBuiltin(builtin_index());
14441 }
14442 
OffHeapInstructionStart() const14443 Address Code::OffHeapInstructionStart() const {
14444   DCHECK(is_off_heap_trampoline());
14445   if (Isolate::CurrentEmbeddedBlob() == nullptr) return raw_instruction_start();
14446   EmbeddedData d = EmbeddedData::FromBlob();
14447   return d.InstructionStartOfBuiltin(builtin_index());
14448 }
14449 
OffHeapInstructionEnd() const14450 Address Code::OffHeapInstructionEnd() const {
14451   DCHECK(is_off_heap_trampoline());
14452   if (Isolate::CurrentEmbeddedBlob() == nullptr) return raw_instruction_end();
14453   EmbeddedData d = EmbeddedData::FromBlob();
14454   return d.InstructionStartOfBuiltin(builtin_index()) +
14455          d.InstructionSizeOfBuiltin(builtin_index());
14456 }
14457 
14458 namespace {
14459 template <typename Code>
SetStackFrameCacheCommon(Isolate * isolate,Handle<Code> code,Handle<SimpleNumberDictionary> cache)14460 void SetStackFrameCacheCommon(Isolate* isolate, Handle<Code> code,
14461                               Handle<SimpleNumberDictionary> cache) {
14462   Handle<Object> maybe_table(code->source_position_table(), isolate);
14463   if (maybe_table->IsSourcePositionTableWithFrameCache()) {
14464     Handle<SourcePositionTableWithFrameCache>::cast(maybe_table)
14465         ->set_stack_frame_cache(*cache);
14466     return;
14467   }
14468   DCHECK(maybe_table->IsByteArray());
14469   Handle<ByteArray> table(Handle<ByteArray>::cast(maybe_table));
14470   Handle<SourcePositionTableWithFrameCache> table_with_cache =
14471       isolate->factory()->NewSourcePositionTableWithFrameCache(table, cache);
14472   code->set_source_position_table(*table_with_cache);
14473 }
14474 }  // namespace
14475 
14476 // static
SetStackFrameCache(Handle<AbstractCode> abstract_code,Handle<SimpleNumberDictionary> cache)14477 void AbstractCode::SetStackFrameCache(Handle<AbstractCode> abstract_code,
14478                                       Handle<SimpleNumberDictionary> cache) {
14479   if (abstract_code->IsCode()) {
14480     SetStackFrameCacheCommon(
14481         abstract_code->GetIsolate(),
14482         handle(abstract_code->GetCode(), abstract_code->GetIsolate()), cache);
14483   } else {
14484     SetStackFrameCacheCommon(
14485         abstract_code->GetIsolate(),
14486         handle(abstract_code->GetBytecodeArray(), abstract_code->GetIsolate()),
14487         cache);
14488   }
14489 }
14490 
14491 namespace {
14492 template <typename Code>
DropStackFrameCacheCommon(Code * code)14493 void DropStackFrameCacheCommon(Code* code) {
14494   i::Object* maybe_table = code->source_position_table();
14495   if (maybe_table->IsByteArray()) return;
14496   DCHECK(maybe_table->IsSourcePositionTableWithFrameCache());
14497   code->set_source_position_table(
14498       i::SourcePositionTableWithFrameCache::cast(maybe_table)
14499           ->source_position_table());
14500 }
14501 }  // namespace
14502 
DropStackFrameCache()14503 void AbstractCode::DropStackFrameCache() {
14504   if (IsCode()) {
14505     DropStackFrameCacheCommon(GetCode());
14506   } else {
14507     DropStackFrameCacheCommon(GetBytecodeArray());
14508   }
14509 }
14510 
SourcePosition(int offset)14511 int AbstractCode::SourcePosition(int offset) {
14512   int position = 0;
14513   // Subtract one because the current PC is one instruction after the call site.
14514   if (IsCode()) offset--;
14515   for (SourcePositionTableIterator iterator(source_position_table());
14516        !iterator.done() && iterator.code_offset() <= offset;
14517        iterator.Advance()) {
14518     position = iterator.source_position().ScriptOffset();
14519   }
14520   return position;
14521 }
14522 
SourceStatementPosition(int offset)14523 int AbstractCode::SourceStatementPosition(int offset) {
14524   // First find the closest position.
14525   int position = SourcePosition(offset);
14526   // Now find the closest statement position before the position.
14527   int statement_position = 0;
14528   for (SourcePositionTableIterator it(source_position_table()); !it.done();
14529        it.Advance()) {
14530     if (it.is_statement()) {
14531       int p = it.source_position().ScriptOffset();
14532       if (statement_position < p && p <= position) {
14533         statement_position = p;
14534       }
14535     }
14536   }
14537   return statement_position;
14538 }
14539 
ClearTypeFeedbackInfo()14540 void JSFunction::ClearTypeFeedbackInfo() {
14541   if (feedback_cell()->value()->IsFeedbackVector()) {
14542     FeedbackVector* vector = feedback_vector();
14543     Isolate* isolate = GetIsolate();
14544     if (vector->ClearSlots(isolate)) {
14545       IC::OnFeedbackChanged(isolate, vector, FeedbackSlot::Invalid(), this,
14546                             "ClearTypeFeedbackInfo");
14547     }
14548   }
14549 }
14550 
PrintDeoptLocation(FILE * out,const char * str,Address pc)14551 void Code::PrintDeoptLocation(FILE* out, const char* str, Address pc) {
14552   Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(this, pc);
14553   class SourcePosition pos = info.position;
14554   if (info.deopt_reason != DeoptimizeReason::kUnknown || pos.IsKnown()) {
14555     PrintF(out, "%s", str);
14556     OFStream outstr(out);
14557     pos.Print(outstr, this);
14558     PrintF(out, ", %s\n", DeoptimizeReasonToString(info.deopt_reason));
14559   }
14560 }
14561 
14562 
CanDeoptAt(Address pc)14563 bool Code::CanDeoptAt(Address pc) {
14564   DeoptimizationData* deopt_data =
14565       DeoptimizationData::cast(deoptimization_data());
14566   Address code_start_address = InstructionStart();
14567   for (int i = 0; i < deopt_data->DeoptCount(); i++) {
14568     if (deopt_data->Pc(i)->value() == -1) continue;
14569     Address address = code_start_address + deopt_data->Pc(i)->value();
14570     if (address == pc && deopt_data->BytecodeOffset(i) != BailoutId::None()) {
14571       return true;
14572     }
14573   }
14574   return false;
14575 }
14576 
14577 
14578 // Identify kind of code.
Kind2String(Kind kind)14579 const char* Code::Kind2String(Kind kind) {
14580   switch (kind) {
14581 #define CASE(name) case name: return #name;
14582     CODE_KIND_LIST(CASE)
14583 #undef CASE
14584     case NUMBER_OF_KINDS: break;
14585   }
14586   UNREACHABLE();
14587 }
14588 
14589 // Identify kind of code.
Kind2String(Kind kind)14590 const char* AbstractCode::Kind2String(Kind kind) {
14591   if (kind < AbstractCode::INTERPRETED_FUNCTION)
14592     return Code::Kind2String((Code::Kind)kind);
14593   if (kind == AbstractCode::INTERPRETED_FUNCTION) return "INTERPRETED_FUNCTION";
14594   UNREACHABLE();
14595 }
14596 
IsIsolateIndependent(Isolate * isolate)14597 bool Code::IsIsolateIndependent(Isolate* isolate) {
14598   constexpr int all_real_modes_mask =
14599       (1 << (RelocInfo::LAST_REAL_RELOC_MODE + 1)) - 1;
14600   constexpr int mode_mask = all_real_modes_mask &
14601                             ~RelocInfo::ModeMask(RelocInfo::COMMENT) &
14602                             ~RelocInfo::ModeMask(RelocInfo::CONST_POOL) &
14603                             ~RelocInfo::ModeMask(RelocInfo::OFF_HEAP_TARGET) &
14604                             ~RelocInfo::ModeMask(RelocInfo::VENEER_POOL);
14605   STATIC_ASSERT(RelocInfo::LAST_REAL_RELOC_MODE == RelocInfo::VENEER_POOL);
14606   STATIC_ASSERT(RelocInfo::ModeMask(RelocInfo::COMMENT) ==
14607                 (1 << RelocInfo::COMMENT));
14608   STATIC_ASSERT(mode_mask ==
14609                 (RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
14610                  RelocInfo::ModeMask(RelocInfo::RELATIVE_CODE_TARGET) |
14611                  RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
14612                  RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
14613                  RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
14614                  RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) |
14615                  RelocInfo::ModeMask(RelocInfo::JS_TO_WASM_CALL) |
14616                  RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
14617                  RelocInfo::ModeMask(RelocInfo::WASM_CALL) |
14618                  RelocInfo::ModeMask(RelocInfo::WASM_STUB_CALL)));
14619 
14620   bool is_process_independent = true;
14621   for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
14622 #if defined(V8_TARGET_ARCH_X64) || defined(V8_TARGET_ARCH_ARM64) || \
14623     defined(V8_TARGET_ARCH_ARM)
14624     // On X64, ARM, ARM64 we emit relative builtin-to-builtin jumps for isolate
14625     // independent builtins in the snapshot. They are later rewritten as
14626     // pc-relative jumps to the off-heap instruction stream and are thus
14627     // process-independent.
14628     // See also: FinalizeEmbeddedCodeTargets.
14629     if (RelocInfo::IsCodeTargetMode(it.rinfo()->rmode())) {
14630       Address target_address = it.rinfo()->target_address();
14631       if (InstructionStream::PcIsOffHeap(isolate, target_address)) continue;
14632 
14633       Code* target = Code::GetCodeFromTargetAddress(target_address);
14634       CHECK(target->IsCode());
14635       if (Builtins::IsIsolateIndependentBuiltin(target)) continue;
14636     }
14637 #endif
14638     is_process_independent = false;
14639   }
14640 
14641   return is_process_independent;
14642 }
14643 
Inlines(SharedFunctionInfo * sfi)14644 bool Code::Inlines(SharedFunctionInfo* sfi) {
14645   // We can only check for inlining for optimized code.
14646   DCHECK(is_optimized_code());
14647   DisallowHeapAllocation no_gc;
14648   DeoptimizationData* const data =
14649       DeoptimizationData::cast(deoptimization_data());
14650   if (data->length() == 0) return false;
14651   if (data->SharedFunctionInfo() == sfi) return true;
14652   FixedArray* const literals = data->LiteralArray();
14653   int const inlined_count = data->InlinedFunctionCount()->value();
14654   for (int i = 0; i < inlined_count; ++i) {
14655     if (SharedFunctionInfo::cast(literals->get(i)) == sfi) return true;
14656   }
14657   return false;
14658 }
14659 
OptimizedCodeIterator(Isolate * isolate)14660 Code::OptimizedCodeIterator::OptimizedCodeIterator(Isolate* isolate) {
14661   isolate_ = isolate;
14662   Object* list = isolate->heap()->native_contexts_list();
14663   next_context_ = list->IsUndefined(isolate_) ? nullptr : Context::cast(list);
14664   current_code_ = nullptr;
14665 }
14666 
Next()14667 Code* Code::OptimizedCodeIterator::Next() {
14668   do {
14669     Object* next;
14670     if (current_code_ != nullptr) {
14671       // Get next code in the linked list.
14672       next = Code::cast(current_code_)->next_code_link();
14673     } else if (next_context_ != nullptr) {
14674       // Linked list of code exhausted. Get list of next context.
14675       next = next_context_->OptimizedCodeListHead();
14676       Object* next_context = next_context_->next_context_link();
14677       next_context_ = next_context->IsUndefined(isolate_)
14678                           ? nullptr
14679                           : Context::cast(next_context);
14680     } else {
14681       // Exhausted contexts.
14682       return nullptr;
14683     }
14684     current_code_ = next->IsUndefined(isolate_) ? nullptr : Code::cast(next);
14685   } while (current_code_ == nullptr);
14686   Code* code = Code::cast(current_code_);
14687   DCHECK_EQ(Code::OPTIMIZED_FUNCTION, code->kind());
14688   return code;
14689 }
14690 
14691 #ifdef ENABLE_DISASSEMBLER
14692 
14693 namespace {
print_pc(std::ostream & os,int pc)14694 void print_pc(std::ostream& os, int pc) {
14695   if (pc == -1) {
14696     os << "NA";
14697   } else {
14698     os << std::hex << pc << std::dec;
14699   }
14700 }
14701 }  // anonymous namespace
14702 
DeoptimizationDataPrint(std::ostream & os)14703 void DeoptimizationData::DeoptimizationDataPrint(std::ostream& os) {  // NOLINT
14704   if (length() == 0) {
14705     os << "Deoptimization Input Data invalidated by lazy deoptimization\n";
14706     return;
14707   }
14708 
14709   disasm::NameConverter converter;
14710   int const inlined_function_count = InlinedFunctionCount()->value();
14711   os << "Inlined functions (count = " << inlined_function_count << ")\n";
14712   for (int id = 0; id < inlined_function_count; ++id) {
14713     Object* info = LiteralArray()->get(id);
14714     os << " " << Brief(SharedFunctionInfo::cast(info)) << "\n";
14715   }
14716   os << "\n";
14717   int deopt_count = DeoptCount();
14718   os << "Deoptimization Input Data (deopt points = " << deopt_count << ")\n";
14719   if (0 != deopt_count) {
14720     os << " index  bytecode-offset    pc";
14721     if (FLAG_print_code_verbose) os << "  commands";
14722     os << "\n";
14723   }
14724   for (int i = 0; i < deopt_count; i++) {
14725     os << std::setw(6) << i << "  " << std::setw(15)
14726        << BytecodeOffset(i).ToInt() << "  " << std::setw(4);
14727     print_pc(os, Pc(i)->value());
14728     os << std::setw(2);
14729 
14730     if (!FLAG_print_code_verbose) {
14731       os << "\n";
14732       continue;
14733     }
14734 
14735     // Print details of the frame translation.
14736     int translation_index = TranslationIndex(i)->value();
14737     TranslationIterator iterator(TranslationByteArray(), translation_index);
14738     Translation::Opcode opcode =
14739         static_cast<Translation::Opcode>(iterator.Next());
14740     DCHECK(Translation::BEGIN == opcode);
14741     int frame_count = iterator.Next();
14742     int jsframe_count = iterator.Next();
14743     int update_feedback_count = iterator.Next();
14744     os << "  " << Translation::StringFor(opcode)
14745        << " {frame count=" << frame_count
14746        << ", js frame count=" << jsframe_count
14747        << ", update_feedback_count=" << update_feedback_count << "}\n";
14748 
14749     while (iterator.HasNext() &&
14750            Translation::BEGIN !=
14751            (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
14752       os << std::setw(31) << "    " << Translation::StringFor(opcode) << " ";
14753 
14754       switch (opcode) {
14755         case Translation::BEGIN:
14756           UNREACHABLE();
14757           break;
14758 
14759         case Translation::INTERPRETED_FRAME: {
14760           int bytecode_offset = iterator.Next();
14761           int shared_info_id = iterator.Next();
14762           unsigned height = iterator.Next();
14763           Object* shared_info = LiteralArray()->get(shared_info_id);
14764           os << "{bytecode_offset=" << bytecode_offset << ", function="
14765              << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14766              << ", height=" << height << "}";
14767           break;
14768         }
14769 
14770         case Translation::CONSTRUCT_STUB_FRAME: {
14771           int bailout_id = iterator.Next();
14772           int shared_info_id = iterator.Next();
14773           Object* shared_info = LiteralArray()->get(shared_info_id);
14774           unsigned height = iterator.Next();
14775           os << "{bailout_id=" << bailout_id << ", function="
14776              << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14777              << ", height=" << height << "}";
14778           break;
14779         }
14780 
14781         case Translation::BUILTIN_CONTINUATION_FRAME:
14782         case Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME:
14783         case Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME: {
14784           int bailout_id = iterator.Next();
14785           int shared_info_id = iterator.Next();
14786           Object* shared_info = LiteralArray()->get(shared_info_id);
14787           unsigned height = iterator.Next();
14788           os << "{bailout_id=" << bailout_id << ", function="
14789              << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14790              << ", height=" << height << "}";
14791           break;
14792         }
14793 
14794         case Translation::ARGUMENTS_ADAPTOR_FRAME: {
14795           int shared_info_id = iterator.Next();
14796           Object* shared_info = LiteralArray()->get(shared_info_id);
14797           unsigned height = iterator.Next();
14798           os << "{function="
14799              << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14800              << ", height=" << height << "}";
14801           break;
14802         }
14803 
14804         case Translation::REGISTER: {
14805           int reg_code = iterator.Next();
14806           os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
14807           break;
14808         }
14809 
14810         case Translation::INT32_REGISTER: {
14811           int reg_code = iterator.Next();
14812           os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
14813           break;
14814         }
14815 
14816         case Translation::UINT32_REGISTER: {
14817           int reg_code = iterator.Next();
14818           os << "{input=" << converter.NameOfCPURegister(reg_code)
14819              << " (unsigned)}";
14820           break;
14821         }
14822 
14823         case Translation::BOOL_REGISTER: {
14824           int reg_code = iterator.Next();
14825           os << "{input=" << converter.NameOfCPURegister(reg_code)
14826              << " (bool)}";
14827           break;
14828         }
14829 
14830         case Translation::FLOAT_REGISTER: {
14831           int reg_code = iterator.Next();
14832           os << "{input="
14833              << RegisterConfiguration::Default()->GetFloatRegisterName(reg_code)
14834              << "}";
14835           break;
14836         }
14837 
14838         case Translation::DOUBLE_REGISTER: {
14839           int reg_code = iterator.Next();
14840           os << "{input="
14841              << RegisterConfiguration::Default()->GetDoubleRegisterName(
14842                     reg_code)
14843              << "}";
14844           break;
14845         }
14846 
14847         case Translation::STACK_SLOT: {
14848           int input_slot_index = iterator.Next();
14849           os << "{input=" << input_slot_index << "}";
14850           break;
14851         }
14852 
14853         case Translation::INT32_STACK_SLOT: {
14854           int input_slot_index = iterator.Next();
14855           os << "{input=" << input_slot_index << "}";
14856           break;
14857         }
14858 
14859         case Translation::UINT32_STACK_SLOT: {
14860           int input_slot_index = iterator.Next();
14861           os << "{input=" << input_slot_index << " (unsigned)}";
14862           break;
14863         }
14864 
14865         case Translation::BOOL_STACK_SLOT: {
14866           int input_slot_index = iterator.Next();
14867           os << "{input=" << input_slot_index << " (bool)}";
14868           break;
14869         }
14870 
14871         case Translation::FLOAT_STACK_SLOT:
14872         case Translation::DOUBLE_STACK_SLOT: {
14873           int input_slot_index = iterator.Next();
14874           os << "{input=" << input_slot_index << "}";
14875           break;
14876         }
14877 
14878         case Translation::LITERAL: {
14879           int literal_index = iterator.Next();
14880           Object* literal_value = LiteralArray()->get(literal_index);
14881           os << "{literal_id=" << literal_index << " (" << Brief(literal_value)
14882              << ")}";
14883           break;
14884         }
14885 
14886         case Translation::DUPLICATED_OBJECT: {
14887           int object_index = iterator.Next();
14888           os << "{object_index=" << object_index << "}";
14889           break;
14890         }
14891 
14892         case Translation::ARGUMENTS_ELEMENTS:
14893         case Translation::ARGUMENTS_LENGTH: {
14894           CreateArgumentsType arguments_type =
14895               static_cast<CreateArgumentsType>(iterator.Next());
14896           os << "{arguments_type=" << arguments_type << "}";
14897           break;
14898         }
14899 
14900         case Translation::CAPTURED_OBJECT: {
14901           int args_length = iterator.Next();
14902           os << "{length=" << args_length << "}";
14903           break;
14904         }
14905 
14906         case Translation::UPDATE_FEEDBACK: {
14907           int literal_index = iterator.Next();
14908           FeedbackSlot slot(iterator.Next());
14909           os << "{feedback={vector_index=" << literal_index << ", slot=" << slot
14910              << "}}";
14911           break;
14912         }
14913       }
14914       os << "\n";
14915     }
14916   }
14917 }
14918 
GetName(Isolate * isolate) const14919 const char* Code::GetName(Isolate* isolate) const {
14920   if (is_stub()) {
14921     return CodeStub::MajorName(CodeStub::GetMajorKey(this));
14922   } else if (kind() == BYTECODE_HANDLER) {
14923     return isolate->interpreter()->LookupNameOfBytecodeHandler(this);
14924   } else {
14925     // There are some handlers and ICs that we can also find names for with
14926     // Builtins::Lookup.
14927     return isolate->builtins()->Lookup(raw_instruction_start());
14928   }
14929 }
14930 
PrintBuiltinCode(Isolate * isolate,const char * name)14931 void Code::PrintBuiltinCode(Isolate* isolate, const char* name) {
14932   DCHECK(FLAG_print_builtin_code);
14933   if (name == nullptr) {
14934     name = GetName(isolate);
14935   }
14936   if (name != nullptr &&
14937       PassesFilter(CStrVector(name),
14938                    CStrVector(FLAG_print_builtin_code_filter))) {
14939     CodeTracer::Scope trace_scope(isolate->GetCodeTracer());
14940     OFStream os(trace_scope.file());
14941     Disassemble(name, os);
14942     os << "\n";
14943   }
14944 }
14945 
14946 namespace {
14947 
DisassembleCodeRange(Isolate * isolate,std::ostream & os,Code * code,Address begin,size_t size,Address current_pc)14948 inline void DisassembleCodeRange(Isolate* isolate, std::ostream& os, Code* code,
14949                                  Address begin, size_t size,
14950                                  Address current_pc) {
14951   Address end = begin + size;
14952   // TODO(mstarzinger): Refactor CodeReference to avoid the
14953   // unhandlified->handlified transition.
14954   AllowHandleAllocation allow_handles;
14955   DisallowHeapAllocation no_gc;
14956   HandleScope handle_scope(isolate);
14957   Disassembler::Decode(isolate, &os, reinterpret_cast<byte*>(begin),
14958                        reinterpret_cast<byte*>(end),
14959                        CodeReference(handle(code, isolate)), current_pc);
14960 }
14961 
14962 }  // namespace
14963 
Disassemble(const char * name,std::ostream & os,Address current_pc)14964 void Code::Disassemble(const char* name, std::ostream& os, Address current_pc) {
14965   Isolate* isolate = GetIsolate();
14966   os << "kind = " << Kind2String(kind()) << "\n";
14967   if (is_stub()) {
14968     const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this));
14969     os << "major_key = " << (n == nullptr ? "null" : n) << "\n";
14970     os << "minor_key = " << CodeStub::MinorKeyFromKey(this->stub_key()) << "\n";
14971   }
14972   if (name == nullptr) {
14973     name = GetName(isolate);
14974   }
14975   if ((name != nullptr) && (name[0] != '\0')) {
14976     os << "name = " << name << "\n";
14977   }
14978   if (kind() == OPTIMIZED_FUNCTION) {
14979     os << "stack_slots = " << stack_slots() << "\n";
14980   }
14981   os << "compiler = " << (is_turbofanned() ? "turbofan" : "unknown") << "\n";
14982   os << "address = " << static_cast<const void*>(this) << "\n\n";
14983 
14984   if (is_off_heap_trampoline()) {
14985     int trampoline_size = raw_instruction_size();
14986     os << "Trampoline (size = " << trampoline_size << ")\n";
14987     DisassembleCodeRange(isolate, os, this, raw_instruction_start(),
14988                          trampoline_size, current_pc);
14989     os << "\n";
14990   }
14991 
14992   {
14993     int size = InstructionSize();
14994     int safepoint_offset =
14995         has_safepoint_info() ? safepoint_table_offset() : size;
14996     int constant_pool_offset = this->constant_pool_offset();
14997     int handler_offset = handler_table_offset() ? handler_table_offset() : size;
14998 
14999     // Stop before reaching any embedded tables
15000     int code_size =
15001         Min(handler_offset, Min(safepoint_offset, constant_pool_offset));
15002     os << "Instructions (size = " << code_size << ")\n";
15003     DisassembleCodeRange(isolate, os, this, InstructionStart(), code_size,
15004                          current_pc);
15005 
15006     if (constant_pool_offset < size) {
15007       int constant_pool_size = safepoint_offset - constant_pool_offset;
15008       DCHECK_EQ(constant_pool_size & kPointerAlignmentMask, 0);
15009       os << "\nConstant Pool (size = " << constant_pool_size << ")\n";
15010       Vector<char> buf = Vector<char>::New(50);
15011       intptr_t* ptr = reinterpret_cast<intptr_t*>(InstructionStart() +
15012                                                   constant_pool_offset);
15013       for (int i = 0; i < constant_pool_size; i += kPointerSize, ptr++) {
15014         SNPrintF(buf, "%4d %08" V8PRIxPTR, i, *ptr);
15015         os << static_cast<const void*>(ptr) << "  " << buf.start() << "\n";
15016       }
15017     }
15018   }
15019   os << "\n";
15020 
15021   SourcePositionTableIterator it(SourcePositionTable());
15022   if (!it.done()) {
15023     os << "Source positions:\n pc offset  position\n";
15024     for (; !it.done(); it.Advance()) {
15025       os << std::setw(10) << std::hex << it.code_offset() << std::dec
15026          << std::setw(10) << it.source_position().ScriptOffset()
15027          << (it.is_statement() ? "  statement" : "") << "\n";
15028     }
15029     os << "\n";
15030   }
15031 
15032   if (kind() == OPTIMIZED_FUNCTION) {
15033     DeoptimizationData* data =
15034         DeoptimizationData::cast(this->deoptimization_data());
15035     data->DeoptimizationDataPrint(os);
15036   }
15037   os << "\n";
15038 
15039   if (has_safepoint_info()) {
15040     SafepointTable table(this);
15041     os << "Safepoints (size = " << table.size() << ")\n";
15042     for (unsigned i = 0; i < table.length(); i++) {
15043       unsigned pc_offset = table.GetPcOffset(i);
15044       os << reinterpret_cast<const void*>(InstructionStart() + pc_offset)
15045          << "  ";
15046       os << std::setw(6) << std::hex << pc_offset << "  " << std::setw(4);
15047       int trampoline_pc = table.GetTrampolinePcOffset(i);
15048       print_pc(os, trampoline_pc);
15049       os << std::dec << "  ";
15050       table.PrintEntry(i, os);
15051       os << " (sp -> fp)  ";
15052       SafepointEntry entry = table.GetEntry(i);
15053       if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
15054         os << std::setw(6) << entry.deoptimization_index();
15055       } else {
15056         os << "<none>";
15057       }
15058       if (entry.argument_count() > 0) {
15059         os << " argc: " << entry.argument_count();
15060       }
15061       os << "\n";
15062     }
15063     os << "\n";
15064   }
15065 
15066   if (handler_table_offset() > 0) {
15067     HandlerTable table(this);
15068     os << "Handler Table (size = " << table.NumberOfReturnEntries() << ")\n";
15069     if (kind() == OPTIMIZED_FUNCTION) {
15070       table.HandlerTableReturnPrint(os);
15071     }
15072     os << "\n";
15073   }
15074 
15075   os << "RelocInfo (size = " << relocation_size() << ")\n";
15076   for (RelocIterator it(this); !it.done(); it.next()) {
15077     it.rinfo()->Print(isolate, os);
15078   }
15079   os << "\n";
15080 
15081   if (has_unwinding_info()) {
15082     os << "UnwindingInfo (size = " << unwinding_info_size() << ")\n";
15083     EhFrameDisassembler eh_frame_disassembler(
15084         reinterpret_cast<byte*>(unwinding_info_start()),
15085         reinterpret_cast<byte*>(unwinding_info_end()));
15086     eh_frame_disassembler.DisassembleToStream(os);
15087     os << "\n";
15088   }
15089 }
15090 #endif  // ENABLE_DISASSEMBLER
15091 
Disassemble(std::ostream & os)15092 void BytecodeArray::Disassemble(std::ostream& os) {
15093   DisallowHeapAllocation no_gc;
15094 
15095   os << "Parameter count " << parameter_count() << "\n";
15096   os << "Frame size " << frame_size() << "\n";
15097 
15098   Address base_address = GetFirstBytecodeAddress();
15099   SourcePositionTableIterator source_positions(SourcePositionTable());
15100 
15101   // Storage for backing the handle passed to the iterator. This handle won't be
15102   // updated by the gc, but that's ok because we've disallowed GCs anyway.
15103   BytecodeArray* handle_storage = this;
15104   Handle<BytecodeArray> handle(&handle_storage);
15105   interpreter::BytecodeArrayIterator iterator(handle);
15106   while (!iterator.done()) {
15107     if (!source_positions.done() &&
15108         iterator.current_offset() == source_positions.code_offset()) {
15109       os << std::setw(5) << source_positions.source_position().ScriptOffset();
15110       os << (source_positions.is_statement() ? " S> " : " E> ");
15111       source_positions.Advance();
15112     } else {
15113       os << "         ";
15114     }
15115     Address current_address = base_address + iterator.current_offset();
15116     os << reinterpret_cast<const void*>(current_address) << " @ "
15117        << std::setw(4) << iterator.current_offset() << " : ";
15118     interpreter::BytecodeDecoder::Decode(
15119         os, reinterpret_cast<byte*>(current_address), parameter_count());
15120     if (interpreter::Bytecodes::IsJump(iterator.current_bytecode())) {
15121       Address jump_target = base_address + iterator.GetJumpTargetOffset();
15122       os << " (" << reinterpret_cast<void*>(jump_target) << " @ "
15123          << iterator.GetJumpTargetOffset() << ")";
15124     }
15125     if (interpreter::Bytecodes::IsSwitch(iterator.current_bytecode())) {
15126       os << " {";
15127       bool first_entry = true;
15128       for (const auto& entry : iterator.GetJumpTableTargetOffsets()) {
15129         if (first_entry) {
15130           first_entry = false;
15131         } else {
15132           os << ",";
15133         }
15134         os << " " << entry.case_value << ": @" << entry.target_offset;
15135       }
15136       os << " }";
15137     }
15138     os << std::endl;
15139     iterator.Advance();
15140   }
15141 
15142   os << "Constant pool (size = " << constant_pool()->length() << ")\n";
15143 #ifdef OBJECT_PRINT
15144   if (constant_pool()->length() > 0) {
15145     constant_pool()->Print();
15146   }
15147 #endif
15148 
15149   os << "Handler Table (size = " << handler_table()->length() << ")\n";
15150 #ifdef ENABLE_DISASSEMBLER
15151   if (handler_table()->length() > 0) {
15152     HandlerTable table(this);
15153     table.HandlerTableRangePrint(os);
15154   }
15155 #endif
15156 }
15157 
CopyBytecodesTo(BytecodeArray * to)15158 void BytecodeArray::CopyBytecodesTo(BytecodeArray* to) {
15159   BytecodeArray* from = this;
15160   DCHECK_EQ(from->length(), to->length());
15161   CopyBytes(reinterpret_cast<byte*>(to->GetFirstBytecodeAddress()),
15162             reinterpret_cast<byte*>(from->GetFirstBytecodeAddress()),
15163             from->length());
15164 }
15165 
MakeOlder()15166 void BytecodeArray::MakeOlder() {
15167   // BytecodeArray is aged in concurrent marker.
15168   // The word must be completely within the byte code array.
15169   Address age_addr = address() + kBytecodeAgeOffset;
15170   DCHECK_LE((age_addr & ~kPointerAlignmentMask) + kPointerSize,
15171             address() + Size());
15172   Age age = bytecode_age();
15173   if (age < kLastBytecodeAge) {
15174     base::AsAtomic8::Release_CompareAndSwap(reinterpret_cast<byte*>(age_addr),
15175                                             age, age + 1);
15176   }
15177 
15178   DCHECK_GE(bytecode_age(), kFirstBytecodeAge);
15179   DCHECK_LE(bytecode_age(), kLastBytecodeAge);
15180 }
15181 
IsOld() const15182 bool BytecodeArray::IsOld() const {
15183   return bytecode_age() >= kIsOldBytecodeAge;
15184 }
15185 
15186 // static
Initialize(Handle<JSArray> array,int capacity,int length)15187 void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
15188   DCHECK_GE(capacity, 0);
15189   array->GetIsolate()->factory()->NewJSArrayStorage(
15190       array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
15191 }
15192 
SetLength(Handle<JSArray> array,uint32_t new_length)15193 void JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) {
15194   // We should never end in here with a pixel or external array.
15195   DCHECK(array->AllowsSetLength());
15196   if (array->SetLengthWouldNormalize(new_length)) {
15197     JSObject::NormalizeElements(array);
15198   }
15199   array->GetElementsAccessor()->SetLength(array, new_length);
15200 }
15201 
GetDependentCode(Handle<HeapObject> object)15202 DependentCode* DependentCode::GetDependentCode(Handle<HeapObject> object) {
15203   if (object->IsMap()) {
15204     return Handle<Map>::cast(object)->dependent_code();
15205   } else if (object->IsPropertyCell()) {
15206     return Handle<PropertyCell>::cast(object)->dependent_code();
15207   } else if (object->IsAllocationSite()) {
15208     return Handle<AllocationSite>::cast(object)->dependent_code();
15209   }
15210   UNREACHABLE();
15211 }
15212 
SetDependentCode(Handle<HeapObject> object,Handle<DependentCode> dep)15213 void DependentCode::SetDependentCode(Handle<HeapObject> object,
15214                                      Handle<DependentCode> dep) {
15215   if (object->IsMap()) {
15216     Handle<Map>::cast(object)->set_dependent_code(*dep);
15217   } else if (object->IsPropertyCell()) {
15218     Handle<PropertyCell>::cast(object)->set_dependent_code(*dep);
15219   } else if (object->IsAllocationSite()) {
15220     Handle<AllocationSite>::cast(object)->set_dependent_code(*dep);
15221   } else {
15222     UNREACHABLE();
15223   }
15224 }
15225 
InstallDependency(Isolate * isolate,MaybeObjectHandle code,Handle<HeapObject> object,DependencyGroup group)15226 void DependentCode::InstallDependency(Isolate* isolate, MaybeObjectHandle code,
15227                                       Handle<HeapObject> object,
15228                                       DependencyGroup group) {
15229   Handle<DependentCode> old_deps(DependentCode::GetDependentCode(object),
15230                                  isolate);
15231   Handle<DependentCode> new_deps =
15232       InsertWeakCode(isolate, old_deps, group, code);
15233   // Update the list head if necessary.
15234   if (!new_deps.is_identical_to(old_deps))
15235     DependentCode::SetDependentCode(object, new_deps);
15236 }
15237 
InsertWeakCode(Isolate * isolate,Handle<DependentCode> entries,DependencyGroup group,MaybeObjectHandle code)15238 Handle<DependentCode> DependentCode::InsertWeakCode(
15239     Isolate* isolate, Handle<DependentCode> entries, DependencyGroup group,
15240     MaybeObjectHandle code) {
15241   if (entries->length() == 0 || entries->group() > group) {
15242     // There is no such group.
15243     return DependentCode::New(isolate, group, code, entries);
15244   }
15245   if (entries->group() < group) {
15246     // The group comes later in the list.
15247     Handle<DependentCode> old_next(entries->next_link(), isolate);
15248     Handle<DependentCode> new_next =
15249         InsertWeakCode(isolate, old_next, group, code);
15250     if (!old_next.is_identical_to(new_next)) {
15251       entries->set_next_link(*new_next);
15252     }
15253     return entries;
15254   }
15255   DCHECK_EQ(group, entries->group());
15256   int count = entries->count();
15257   // Check for existing entry to avoid duplicates.
15258   for (int i = 0; i < count; i++) {
15259     if (entries->object_at(i) == *code) return entries;
15260   }
15261   if (entries->length() < kCodesStartIndex + count + 1) {
15262     entries = EnsureSpace(isolate, entries);
15263     // Count could have changed, reload it.
15264     count = entries->count();
15265   }
15266   entries->set_object_at(count, *code);
15267   entries->set_count(count + 1);
15268   return entries;
15269 }
15270 
New(Isolate * isolate,DependencyGroup group,MaybeObjectHandle object,Handle<DependentCode> next)15271 Handle<DependentCode> DependentCode::New(Isolate* isolate,
15272                                          DependencyGroup group,
15273                                          MaybeObjectHandle object,
15274                                          Handle<DependentCode> next) {
15275   Handle<DependentCode> result = Handle<DependentCode>::cast(
15276       isolate->factory()->NewWeakFixedArray(kCodesStartIndex + 1, TENURED));
15277   result->set_next_link(*next);
15278   result->set_flags(GroupField::encode(group) | CountField::encode(1));
15279   result->set_object_at(0, *object);
15280   return result;
15281 }
15282 
EnsureSpace(Isolate * isolate,Handle<DependentCode> entries)15283 Handle<DependentCode> DependentCode::EnsureSpace(
15284     Isolate* isolate, Handle<DependentCode> entries) {
15285   if (entries->Compact()) return entries;
15286   int capacity = kCodesStartIndex + DependentCode::Grow(entries->count());
15287   int grow_by = capacity - entries->length();
15288   return Handle<DependentCode>::cast(
15289       isolate->factory()->CopyWeakFixedArrayAndGrow(entries, grow_by, TENURED));
15290 }
15291 
15292 
Compact()15293 bool DependentCode::Compact() {
15294   int old_count = count();
15295   int new_count = 0;
15296   for (int i = 0; i < old_count; i++) {
15297     MaybeObject* obj = object_at(i);
15298     if (!obj->IsClearedWeakHeapObject()) {
15299       if (i != new_count) {
15300         copy(i, new_count);
15301       }
15302       new_count++;
15303     }
15304   }
15305   set_count(new_count);
15306   for (int i = new_count; i < old_count; i++) {
15307     clear_at(i);
15308   }
15309   return new_count < old_count;
15310 }
15311 
Contains(DependencyGroup group,MaybeObject * code)15312 bool DependentCode::Contains(DependencyGroup group, MaybeObject* code) {
15313   if (this->length() == 0 || this->group() > group) {
15314     // There is no such group.
15315     return false;
15316   }
15317   if (this->group() < group) {
15318     // The group comes later in the list.
15319     return next_link()->Contains(group, code);
15320   }
15321   DCHECK_EQ(group, this->group());
15322   int count = this->count();
15323   for (int i = 0; i < count; i++) {
15324     if (object_at(i) == code) return true;
15325   }
15326   return false;
15327 }
15328 
15329 
IsEmpty(DependencyGroup group)15330 bool DependentCode::IsEmpty(DependencyGroup group) {
15331   if (this->length() == 0 || this->group() > group) {
15332     // There is no such group.
15333     return true;
15334   }
15335   if (this->group() < group) {
15336     // The group comes later in the list.
15337     return next_link()->IsEmpty(group);
15338   }
15339   DCHECK_EQ(group, this->group());
15340   return count() == 0;
15341 }
15342 
15343 
MarkCodeForDeoptimization(Isolate * isolate,DependentCode::DependencyGroup group)15344 bool DependentCode::MarkCodeForDeoptimization(
15345     Isolate* isolate,
15346     DependentCode::DependencyGroup group) {
15347   if (this->length() == 0 || this->group() > group) {
15348     // There is no such group.
15349     return false;
15350   }
15351   if (this->group() < group) {
15352     // The group comes later in the list.
15353     return next_link()->MarkCodeForDeoptimization(isolate, group);
15354   }
15355   DCHECK_EQ(group, this->group());
15356   DisallowHeapAllocation no_allocation_scope;
15357   // Mark all the code that needs to be deoptimized.
15358   bool marked = false;
15359   int count = this->count();
15360   for (int i = 0; i < count; i++) {
15361     MaybeObject* obj = object_at(i);
15362     if (obj->IsClearedWeakHeapObject()) continue;
15363     Code* code = Code::cast(obj->ToWeakHeapObject());
15364     if (!code->marked_for_deoptimization()) {
15365       code->SetMarkedForDeoptimization(DependencyGroupName(group));
15366       marked = true;
15367     }
15368   }
15369   for (int i = 0; i < count; i++) {
15370     clear_at(i);
15371   }
15372   set_count(0);
15373   return marked;
15374 }
15375 
15376 
DeoptimizeDependentCodeGroup(Isolate * isolate,DependentCode::DependencyGroup group)15377 void DependentCode::DeoptimizeDependentCodeGroup(
15378     Isolate* isolate,
15379     DependentCode::DependencyGroup group) {
15380   DisallowHeapAllocation no_allocation_scope;
15381   bool marked = MarkCodeForDeoptimization(isolate, group);
15382   if (marked) {
15383     DCHECK(AllowCodeDependencyChange::IsAllowed());
15384     Deoptimizer::DeoptimizeMarkedCode(isolate);
15385   }
15386 }
15387 
SetMarkedForDeoptimization(const char * reason)15388 void Code::SetMarkedForDeoptimization(const char* reason) {
15389   set_marked_for_deoptimization(true);
15390   if (FLAG_trace_deopt &&
15391       (deoptimization_data() != GetReadOnlyRoots().empty_fixed_array())) {
15392     DeoptimizationData* deopt_data =
15393         DeoptimizationData::cast(deoptimization_data());
15394     CodeTracer::Scope scope(GetHeap()->isolate()->GetCodeTracer());
15395     PrintF(scope.file(),
15396            "[marking dependent code " V8PRIxPTR_FMT
15397            " (opt #%d) for deoptimization, reason: %s]\n",
15398            reinterpret_cast<intptr_t>(this),
15399            deopt_data->OptimizationId()->value(), reason);
15400   }
15401 }
15402 
15403 
DependencyGroupName(DependencyGroup group)15404 const char* DependentCode::DependencyGroupName(DependencyGroup group) {
15405   switch (group) {
15406     case kTransitionGroup:
15407       return "transition";
15408     case kPrototypeCheckGroup:
15409       return "prototype-check";
15410     case kPropertyCellChangedGroup:
15411       return "property-cell-changed";
15412     case kFieldOwnerGroup:
15413       return "field-owner";
15414     case kInitialMapChangedGroup:
15415       return "initial-map-changed";
15416     case kAllocationSiteTenuringChangedGroup:
15417       return "allocation-site-tenuring-changed";
15418     case kAllocationSiteTransitionChangedGroup:
15419       return "allocation-site-transition-changed";
15420   }
15421   UNREACHABLE();
15422 }
15423 
TransitionToPrototype(Isolate * isolate,Handle<Map> map,Handle<Object> prototype)15424 Handle<Map> Map::TransitionToPrototype(Isolate* isolate, Handle<Map> map,
15425                                        Handle<Object> prototype) {
15426   Handle<Map> new_map =
15427       TransitionsAccessor(isolate, map).GetPrototypeTransition(prototype);
15428   if (new_map.is_null()) {
15429     new_map = Copy(isolate, map, "TransitionToPrototype");
15430     TransitionsAccessor(isolate, map)
15431         .PutPrototypeTransition(prototype, new_map);
15432     Map::SetPrototype(isolate, new_map, prototype);
15433   }
15434   return new_map;
15435 }
15436 
15437 
SetPrototype(Handle<JSReceiver> object,Handle<Object> value,bool from_javascript,ShouldThrow should_throw)15438 Maybe<bool> JSReceiver::SetPrototype(Handle<JSReceiver> object,
15439                                      Handle<Object> value, bool from_javascript,
15440                                      ShouldThrow should_throw) {
15441   if (object->IsJSProxy()) {
15442     return JSProxy::SetPrototype(Handle<JSProxy>::cast(object), value,
15443                                  from_javascript, should_throw);
15444   }
15445   return JSObject::SetPrototype(Handle<JSObject>::cast(object), value,
15446                                 from_javascript, should_throw);
15447 }
15448 
15449 
15450 // ES6: 9.5.2 [[SetPrototypeOf]] (V)
15451 // static
SetPrototype(Handle<JSProxy> proxy,Handle<Object> value,bool from_javascript,ShouldThrow should_throw)15452 Maybe<bool> JSProxy::SetPrototype(Handle<JSProxy> proxy, Handle<Object> value,
15453                                   bool from_javascript,
15454                                   ShouldThrow should_throw) {
15455   Isolate* isolate = proxy->GetIsolate();
15456   STACK_CHECK(isolate, Nothing<bool>());
15457   Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string();
15458   // 1. Assert: Either Type(V) is Object or Type(V) is Null.
15459   DCHECK(value->IsJSReceiver() || value->IsNull(isolate));
15460   // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
15461   Handle<Object> handler(proxy->handler(), isolate);
15462   // 3. If handler is null, throw a TypeError exception.
15463   // 4. Assert: Type(handler) is Object.
15464   if (proxy->IsRevoked()) {
15465     isolate->Throw(*isolate->factory()->NewTypeError(
15466         MessageTemplate::kProxyRevoked, trap_name));
15467     return Nothing<bool>();
15468   }
15469   // 5. Let target be the value of the [[ProxyTarget]] internal slot.
15470   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
15471   // 6. Let trap be ? GetMethod(handler, "getPrototypeOf").
15472   Handle<Object> trap;
15473   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15474       isolate, trap,
15475       Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
15476       Nothing<bool>());
15477   // 7. If trap is undefined, then return target.[[SetPrototypeOf]]().
15478   if (trap->IsUndefined(isolate)) {
15479     return JSReceiver::SetPrototype(target, value, from_javascript,
15480                                     should_throw);
15481   }
15482   // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, V»)).
15483   Handle<Object> argv[] = {target, value};
15484   Handle<Object> trap_result;
15485   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15486       isolate, trap_result,
15487       Execution::Call(isolate, trap, handler, arraysize(argv), argv),
15488       Nothing<bool>());
15489   bool bool_trap_result = trap_result->BooleanValue(isolate);
15490   // 9. If booleanTrapResult is false, return false.
15491   if (!bool_trap_result) {
15492     RETURN_FAILURE(
15493         isolate, should_throw,
15494         NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15495   }
15496   // 10. Let extensibleTarget be ? IsExtensible(target).
15497   Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
15498   if (is_extensible.IsNothing()) return Nothing<bool>();
15499   // 11. If extensibleTarget is true, return true.
15500   if (is_extensible.FromJust()) {
15501     if (bool_trap_result) return Just(true);
15502     RETURN_FAILURE(
15503         isolate, should_throw,
15504         NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15505   }
15506   // 12. Let targetProto be ? target.[[GetPrototypeOf]]().
15507   Handle<Object> target_proto;
15508   ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_proto,
15509                                    JSReceiver::GetPrototype(isolate, target),
15510                                    Nothing<bool>());
15511   // 13. If SameValue(V, targetProto) is false, throw a TypeError exception.
15512   if (bool_trap_result && !value->SameValue(*target_proto)) {
15513     isolate->Throw(*isolate->factory()->NewTypeError(
15514         MessageTemplate::kProxySetPrototypeOfNonExtensible));
15515     return Nothing<bool>();
15516   }
15517   // 14. Return true.
15518   return Just(true);
15519 }
15520 
15521 
SetPrototype(Handle<JSObject> object,Handle<Object> value,bool from_javascript,ShouldThrow should_throw)15522 Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object,
15523                                    Handle<Object> value, bool from_javascript,
15524                                    ShouldThrow should_throw) {
15525   Isolate* isolate = object->GetIsolate();
15526 
15527 #ifdef DEBUG
15528   int size = object->Size();
15529 #endif
15530 
15531   if (from_javascript) {
15532     if (object->IsAccessCheckNeeded() &&
15533         !isolate->MayAccess(handle(isolate->context(), isolate), object)) {
15534       isolate->ReportFailedAccessCheck(object);
15535       RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
15536       RETURN_FAILURE(isolate, should_throw,
15537                      NewTypeError(MessageTemplate::kNoAccess));
15538     }
15539   } else {
15540     DCHECK(!object->IsAccessCheckNeeded());
15541   }
15542 
15543   // Silently ignore the change if value is not a JSObject or null.
15544   // SpiderMonkey behaves this way.
15545   if (!value->IsJSReceiver() && !value->IsNull(isolate)) return Just(true);
15546 
15547   bool all_extensible = object->map()->is_extensible();
15548   Handle<JSObject> real_receiver = object;
15549   if (from_javascript) {
15550     // Find the first object in the chain whose prototype object is not
15551     // hidden.
15552     PrototypeIterator iter(isolate, real_receiver, kStartAtPrototype,
15553                            PrototypeIterator::END_AT_NON_HIDDEN);
15554     while (!iter.IsAtEnd()) {
15555       // Casting to JSObject is fine because hidden prototypes are never
15556       // JSProxies.
15557       real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter);
15558       iter.Advance();
15559       all_extensible = all_extensible && real_receiver->map()->is_extensible();
15560     }
15561   }
15562   Handle<Map> map(real_receiver->map(), isolate);
15563 
15564   // Nothing to do if prototype is already set.
15565   if (map->prototype() == *value) return Just(true);
15566 
15567   bool immutable_proto = map->is_immutable_proto();
15568   if (immutable_proto) {
15569     RETURN_FAILURE(
15570         isolate, should_throw,
15571         NewTypeError(MessageTemplate::kImmutablePrototypeSet, object));
15572   }
15573 
15574   // From 8.6.2 Object Internal Methods
15575   // ...
15576   // In addition, if [[Extensible]] is false the value of the [[Class]] and
15577   // [[Prototype]] internal properties of the object may not be modified.
15578   // ...
15579   // Implementation specific extensions that modify [[Class]], [[Prototype]]
15580   // or [[Extensible]] must not violate the invariants defined in the preceding
15581   // paragraph.
15582   if (!all_extensible) {
15583     RETURN_FAILURE(isolate, should_throw,
15584                    NewTypeError(MessageTemplate::kNonExtensibleProto, object));
15585   }
15586 
15587   // Before we can set the prototype we need to be sure prototype cycles are
15588   // prevented.  It is sufficient to validate that the receiver is not in the
15589   // new prototype chain.
15590   if (value->IsJSReceiver()) {
15591     for (PrototypeIterator iter(isolate, JSReceiver::cast(*value),
15592                                 kStartAtReceiver);
15593          !iter.IsAtEnd(); iter.Advance()) {
15594       if (iter.GetCurrent<JSReceiver>() == *object) {
15595         // Cycle detected.
15596         RETURN_FAILURE(isolate, should_throw,
15597                        NewTypeError(MessageTemplate::kCyclicProto));
15598       }
15599     }
15600   }
15601 
15602   // Set the new prototype of the object.
15603 
15604   isolate->UpdateNoElementsProtectorOnSetPrototype(real_receiver);
15605 
15606   Handle<Map> new_map = Map::TransitionToPrototype(isolate, map, value);
15607   DCHECK(new_map->prototype() == *value);
15608   JSObject::MigrateToMap(real_receiver, new_map);
15609 
15610   DCHECK(size == object->Size());
15611   return Just(true);
15612 }
15613 
15614 // static
SetImmutableProto(Handle<JSObject> object)15615 void JSObject::SetImmutableProto(Handle<JSObject> object) {
15616   DCHECK(!object->IsAccessCheckNeeded());  // Never called from JS
15617   Handle<Map> map(object->map(), object->GetIsolate());
15618 
15619   // Nothing to do if prototype is already set.
15620   if (map->is_immutable_proto()) return;
15621 
15622   Handle<Map> new_map =
15623       Map::TransitionToImmutableProto(object->GetIsolate(), map);
15624   object->synchronized_set_map(*new_map);
15625 }
15626 
EnsureCanContainElements(Handle<JSObject> object,Arguments * args,uint32_t first_arg,uint32_t arg_count,EnsureElementsMode mode)15627 void JSObject::EnsureCanContainElements(Handle<JSObject> object,
15628                                         Arguments* args,
15629                                         uint32_t first_arg,
15630                                         uint32_t arg_count,
15631                                         EnsureElementsMode mode) {
15632   // Elements in |Arguments| are ordered backwards (because they're on the
15633   // stack), but the method that's called here iterates over them in forward
15634   // direction.
15635   return EnsureCanContainElements(
15636       object, args->arguments() - first_arg - (arg_count - 1), arg_count, mode);
15637 }
15638 
15639 
GetElementsAccessor()15640 ElementsAccessor* JSObject::GetElementsAccessor() {
15641   return ElementsAccessor::ForKind(GetElementsKind());
15642 }
15643 
ValidateElements(JSObject * object)15644 void JSObject::ValidateElements(JSObject* object) {
15645 #ifdef ENABLE_SLOW_DCHECKS
15646   if (FLAG_enable_slow_asserts) {
15647     object->GetElementsAccessor()->Validate(object);
15648   }
15649 #endif
15650 }
15651 
15652 
ShouldConvertToSlowElements(JSObject * object,uint32_t capacity,uint32_t index,uint32_t * new_capacity)15653 static bool ShouldConvertToSlowElements(JSObject* object, uint32_t capacity,
15654                                         uint32_t index,
15655                                         uint32_t* new_capacity) {
15656   STATIC_ASSERT(JSObject::kMaxUncheckedOldFastElementsLength <=
15657                 JSObject::kMaxUncheckedFastElementsLength);
15658   if (index < capacity) {
15659     *new_capacity = capacity;
15660     return false;
15661   }
15662   if (index - capacity >= JSObject::kMaxGap) return true;
15663   *new_capacity = JSObject::NewElementsCapacity(index + 1);
15664   DCHECK_LT(index, *new_capacity);
15665   if (*new_capacity <= JSObject::kMaxUncheckedOldFastElementsLength ||
15666       (*new_capacity <= JSObject::kMaxUncheckedFastElementsLength &&
15667        Heap::InNewSpace(object))) {
15668     return false;
15669   }
15670   // If the fast-case backing storage takes up much more memory than a
15671   // dictionary backing storage would, the object should have slow elements.
15672   int used_elements = object->GetFastElementsUsage();
15673   uint32_t size_threshold = NumberDictionary::kPreferFastElementsSizeFactor *
15674                             NumberDictionary::ComputeCapacity(used_elements) *
15675                             NumberDictionary::kEntrySize;
15676   return size_threshold <= *new_capacity;
15677 }
15678 
15679 
WouldConvertToSlowElements(uint32_t index)15680 bool JSObject::WouldConvertToSlowElements(uint32_t index) {
15681   if (!HasFastElements()) return false;
15682   uint32_t capacity = static_cast<uint32_t>(elements()->length());
15683   uint32_t new_capacity;
15684   return ShouldConvertToSlowElements(this, capacity, index, &new_capacity);
15685 }
15686 
15687 
BestFittingFastElementsKind(JSObject * object)15688 static ElementsKind BestFittingFastElementsKind(JSObject* object) {
15689   if (!object->map()->CanHaveFastTransitionableElementsKind()) {
15690     return HOLEY_ELEMENTS;
15691   }
15692   if (object->HasSloppyArgumentsElements()) {
15693     return FAST_SLOPPY_ARGUMENTS_ELEMENTS;
15694   }
15695   if (object->HasStringWrapperElements()) {
15696     return FAST_STRING_WRAPPER_ELEMENTS;
15697   }
15698   DCHECK(object->HasDictionaryElements());
15699   NumberDictionary* dictionary = object->element_dictionary();
15700   ElementsKind kind = HOLEY_SMI_ELEMENTS;
15701   for (int i = 0; i < dictionary->Capacity(); i++) {
15702     Object* key = dictionary->KeyAt(i);
15703     if (key->IsNumber()) {
15704       Object* value = dictionary->ValueAt(i);
15705       if (!value->IsNumber()) return HOLEY_ELEMENTS;
15706       if (!value->IsSmi()) {
15707         if (!FLAG_unbox_double_arrays) return HOLEY_ELEMENTS;
15708         kind = HOLEY_DOUBLE_ELEMENTS;
15709       }
15710     }
15711   }
15712   return kind;
15713 }
15714 
ShouldConvertToFastElements(JSObject * object,NumberDictionary * dictionary,uint32_t index,uint32_t * new_capacity)15715 static bool ShouldConvertToFastElements(JSObject* object,
15716                                         NumberDictionary* dictionary,
15717                                         uint32_t index,
15718                                         uint32_t* new_capacity) {
15719   // If properties with non-standard attributes or accessors were added, we
15720   // cannot go back to fast elements.
15721   if (dictionary->requires_slow_elements()) return false;
15722 
15723   // Adding a property with this index will require slow elements.
15724   if (index >= static_cast<uint32_t>(Smi::kMaxValue)) return false;
15725 
15726   if (object->IsJSArray()) {
15727     Object* length = JSArray::cast(object)->length();
15728     if (!length->IsSmi()) return false;
15729     *new_capacity = static_cast<uint32_t>(Smi::ToInt(length));
15730   } else if (object->IsJSSloppyArgumentsObject()) {
15731     return false;
15732   } else {
15733     *new_capacity = dictionary->max_number_key() + 1;
15734   }
15735   *new_capacity = Max(index + 1, *new_capacity);
15736 
15737   uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
15738                              NumberDictionary::kEntrySize;
15739 
15740   // Turn fast if the dictionary only saves 50% space.
15741   return 2 * dictionary_size >= *new_capacity;
15742 }
15743 
15744 // static
AddDataElement(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes)15745 void JSObject::AddDataElement(Handle<JSObject> object, uint32_t index,
15746                               Handle<Object> value,
15747                               PropertyAttributes attributes) {
15748   DCHECK(object->map()->is_extensible());
15749 
15750   Isolate* isolate = object->GetIsolate();
15751 
15752   uint32_t old_length = 0;
15753   uint32_t new_capacity = 0;
15754 
15755   if (object->IsJSArray()) {
15756     CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length));
15757   }
15758 
15759   ElementsKind kind = object->GetElementsKind();
15760   FixedArrayBase* elements = object->elements();
15761   ElementsKind dictionary_kind = DICTIONARY_ELEMENTS;
15762   if (IsSloppyArgumentsElementsKind(kind)) {
15763     elements = SloppyArgumentsElements::cast(elements)->arguments();
15764     dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
15765   } else if (IsStringWrapperElementsKind(kind)) {
15766     dictionary_kind = SLOW_STRING_WRAPPER_ELEMENTS;
15767   }
15768 
15769   if (attributes != NONE) {
15770     kind = dictionary_kind;
15771   } else if (elements->IsNumberDictionary()) {
15772     kind = ShouldConvertToFastElements(
15773                *object, NumberDictionary::cast(elements), index, &new_capacity)
15774                ? BestFittingFastElementsKind(*object)
15775                : dictionary_kind;
15776   } else if (ShouldConvertToSlowElements(
15777                  *object, static_cast<uint32_t>(elements->length()), index,
15778                  &new_capacity)) {
15779     kind = dictionary_kind;
15780   }
15781 
15782   ElementsKind to = value->OptimalElementsKind();
15783   if (IsHoleyElementsKind(kind) || !object->IsJSArray() || index > old_length) {
15784     to = GetHoleyElementsKind(to);
15785     kind = GetHoleyElementsKind(kind);
15786   }
15787   to = GetMoreGeneralElementsKind(kind, to);
15788   ElementsAccessor* accessor = ElementsAccessor::ForKind(to);
15789   accessor->Add(object, index, value, attributes, new_capacity);
15790 
15791   if (object->IsJSArray() && index >= old_length) {
15792     Handle<Object> new_length =
15793         isolate->factory()->NewNumberFromUint(index + 1);
15794     JSArray::cast(*object)->set_length(*new_length);
15795   }
15796 }
15797 
15798 
SetLengthWouldNormalize(uint32_t new_length)15799 bool JSArray::SetLengthWouldNormalize(uint32_t new_length) {
15800   if (!HasFastElements()) return false;
15801   uint32_t capacity = static_cast<uint32_t>(elements()->length());
15802   uint32_t new_capacity;
15803   return JSArray::SetLengthWouldNormalize(GetHeap(), new_length) &&
15804          ShouldConvertToSlowElements(this, capacity, new_length - 1,
15805                                      &new_capacity);
15806 }
15807 
15808 
15809 const double AllocationSite::kPretenureRatio = 0.85;
15810 
15811 
ResetPretenureDecision()15812 void AllocationSite::ResetPretenureDecision() {
15813   set_pretenure_decision(kUndecided);
15814   set_memento_found_count(0);
15815   set_memento_create_count(0);
15816 }
15817 
GetPretenureMode() const15818 PretenureFlag AllocationSite::GetPretenureMode() const {
15819   PretenureDecision mode = pretenure_decision();
15820   // Zombie objects "decide" to be untenured.
15821   return mode == kTenure ? TENURED : NOT_TENURED;
15822 }
15823 
IsNested()15824 bool AllocationSite::IsNested() {
15825   DCHECK(FLAG_trace_track_allocation_sites);
15826   Object* current = boilerplate()->GetHeap()->allocation_sites_list();
15827   while (current->IsAllocationSite()) {
15828     AllocationSite* current_site = AllocationSite::cast(current);
15829     if (current_site->nested_site() == this) {
15830       return true;
15831     }
15832     current = current_site->weak_next();
15833   }
15834   return false;
15835 }
15836 
15837 template <AllocationSiteUpdateMode update_or_check>
DigestTransitionFeedback(Handle<AllocationSite> site,ElementsKind to_kind)15838 bool AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
15839                                               ElementsKind to_kind) {
15840   Isolate* isolate = site->GetIsolate();
15841   bool result = false;
15842 
15843   if (site->PointsToLiteral() && site->boilerplate()->IsJSArray()) {
15844     Handle<JSArray> boilerplate(JSArray::cast(site->boilerplate()), isolate);
15845     ElementsKind kind = boilerplate->GetElementsKind();
15846     // if kind is holey ensure that to_kind is as well.
15847     if (IsHoleyElementsKind(kind)) {
15848       to_kind = GetHoleyElementsKind(to_kind);
15849     }
15850     if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
15851       // If the array is huge, it's not likely to be defined in a local
15852       // function, so we shouldn't make new instances of it very often.
15853       uint32_t length = 0;
15854       CHECK(boilerplate->length()->ToArrayLength(&length));
15855       if (length <= kMaximumArrayBytesToPretransition) {
15856         if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) {
15857           return true;
15858         }
15859         if (FLAG_trace_track_allocation_sites) {
15860           bool is_nested = site->IsNested();
15861           PrintF("AllocationSite: JSArray %p boilerplate %supdated %s->%s\n",
15862                  reinterpret_cast<void*>(*site), is_nested ? "(nested)" : " ",
15863                  ElementsKindToString(kind), ElementsKindToString(to_kind));
15864         }
15865         JSObject::TransitionElementsKind(boilerplate, to_kind);
15866         site->dependent_code()->DeoptimizeDependentCodeGroup(
15867             isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
15868         result = true;
15869       }
15870     }
15871   } else {
15872     // The AllocationSite is for a constructed Array.
15873     ElementsKind kind = site->GetElementsKind();
15874     // if kind is holey ensure that to_kind is as well.
15875     if (IsHoleyElementsKind(kind)) {
15876       to_kind = GetHoleyElementsKind(to_kind);
15877     }
15878     if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
15879       if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) return true;
15880       if (FLAG_trace_track_allocation_sites) {
15881         PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
15882                reinterpret_cast<void*>(*site),
15883                ElementsKindToString(kind),
15884                ElementsKindToString(to_kind));
15885       }
15886       site->SetElementsKind(to_kind);
15887       site->dependent_code()->DeoptimizeDependentCodeGroup(
15888           isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
15889       result = true;
15890     }
15891   }
15892   return result;
15893 }
15894 
ShouldTrack(ElementsKind from,ElementsKind to)15895 bool AllocationSite::ShouldTrack(ElementsKind from, ElementsKind to) {
15896   return IsSmiElementsKind(from) &&
15897          IsMoreGeneralElementsKindTransition(from, to);
15898 }
15899 
PretenureDecisionName(PretenureDecision decision)15900 const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) {
15901   switch (decision) {
15902     case kUndecided: return "undecided";
15903     case kDontTenure: return "don't tenure";
15904     case kMaybeTenure: return "maybe tenure";
15905     case kTenure: return "tenure";
15906     case kZombie: return "zombie";
15907     default: UNREACHABLE();
15908   }
15909   return nullptr;
15910 }
15911 
15912 template <AllocationSiteUpdateMode update_or_check>
UpdateAllocationSite(Handle<JSObject> object,ElementsKind to_kind)15913 bool JSObject::UpdateAllocationSite(Handle<JSObject> object,
15914                                     ElementsKind to_kind) {
15915   if (!object->IsJSArray()) return false;
15916 
15917   if (!Heap::InNewSpace(*object)) return false;
15918 
15919   Handle<AllocationSite> site;
15920   {
15921     DisallowHeapAllocation no_allocation;
15922 
15923     Heap* heap = object->GetHeap();
15924     AllocationMemento* memento =
15925         heap->FindAllocationMemento<Heap::kForRuntime>(object->map(), *object);
15926     if (memento == nullptr) return false;
15927 
15928     // Walk through to the Allocation Site
15929     site = handle(memento->GetAllocationSite(), heap->isolate());
15930   }
15931   return AllocationSite::DigestTransitionFeedback<update_or_check>(site,
15932                                                                    to_kind);
15933 }
15934 
15935 template bool
15936 JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kCheckOnly>(
15937     Handle<JSObject> object, ElementsKind to_kind);
15938 
15939 template bool JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kUpdate>(
15940     Handle<JSObject> object, ElementsKind to_kind);
15941 
TransitionElementsKind(Handle<JSObject> object,ElementsKind to_kind)15942 void JSObject::TransitionElementsKind(Handle<JSObject> object,
15943                                       ElementsKind to_kind) {
15944   ElementsKind from_kind = object->GetElementsKind();
15945 
15946   if (IsHoleyElementsKind(from_kind)) {
15947     to_kind = GetHoleyElementsKind(to_kind);
15948   }
15949 
15950   if (from_kind == to_kind) return;
15951 
15952   // This method should never be called for any other case.
15953   DCHECK(IsFastElementsKind(from_kind));
15954   DCHECK(IsFastElementsKind(to_kind));
15955   DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind);
15956 
15957   UpdateAllocationSite(object, to_kind);
15958   if (object->elements() == object->GetReadOnlyRoots().empty_fixed_array() ||
15959       IsDoubleElementsKind(from_kind) == IsDoubleElementsKind(to_kind)) {
15960     // No change is needed to the elements() buffer, the transition
15961     // only requires a map change.
15962     Handle<Map> new_map = GetElementsTransitionMap(object, to_kind);
15963     MigrateToMap(object, new_map);
15964     if (FLAG_trace_elements_transitions) {
15965       Handle<FixedArrayBase> elms(object->elements(), object->GetIsolate());
15966       PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms);
15967     }
15968   } else {
15969     DCHECK((IsSmiElementsKind(from_kind) && IsDoubleElementsKind(to_kind)) ||
15970            (IsDoubleElementsKind(from_kind) && IsObjectElementsKind(to_kind)));
15971     uint32_t c = static_cast<uint32_t>(object->elements()->length());
15972     ElementsAccessor::ForKind(to_kind)->GrowCapacityAndConvert(object, c);
15973   }
15974 }
15975 
15976 
15977 // static
IsValidElementsTransition(ElementsKind from_kind,ElementsKind to_kind)15978 bool Map::IsValidElementsTransition(ElementsKind from_kind,
15979                                     ElementsKind to_kind) {
15980   // Transitions can't go backwards.
15981   if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
15982     return false;
15983   }
15984 
15985   // Transitions from HOLEY -> PACKED are not allowed.
15986   return !IsHoleyElementsKind(from_kind) || IsHoleyElementsKind(to_kind);
15987 }
15988 
15989 
HasReadOnlyLength(Handle<JSArray> array)15990 bool JSArray::HasReadOnlyLength(Handle<JSArray> array) {
15991   Map* map = array->map();
15992   // Fast path: "length" is the first fast property of arrays. Since it's not
15993   // configurable, it's guaranteed to be the first in the descriptor array.
15994   if (!map->is_dictionary_map()) {
15995     DCHECK(map->instance_descriptors()->GetKey(0) ==
15996            array->GetReadOnlyRoots().length_string());
15997     return map->instance_descriptors()->GetDetails(0).IsReadOnly();
15998   }
15999 
16000   Isolate* isolate = array->GetIsolate();
16001   LookupIterator it(array, isolate->factory()->length_string(), array,
16002                     LookupIterator::OWN_SKIP_INTERCEPTOR);
16003   CHECK_EQ(LookupIterator::ACCESSOR, it.state());
16004   return it.IsReadOnly();
16005 }
16006 
16007 
WouldChangeReadOnlyLength(Handle<JSArray> array,uint32_t index)16008 bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array,
16009                                         uint32_t index) {
16010   uint32_t length = 0;
16011   CHECK(array->length()->ToArrayLength(&length));
16012   if (length <= index) return HasReadOnlyLength(array);
16013   return false;
16014 }
16015 
16016 template <typename BackingStore>
HoleyElementsUsage(JSObject * object,BackingStore * store)16017 static int HoleyElementsUsage(JSObject* object, BackingStore* store) {
16018   Isolate* isolate = object->GetIsolate();
16019   int limit = object->IsJSArray() ? Smi::ToInt(JSArray::cast(object)->length())
16020                                   : store->length();
16021   int used = 0;
16022   for (int i = 0; i < limit; ++i) {
16023     if (!store->is_the_hole(isolate, i)) ++used;
16024   }
16025   return used;
16026 }
16027 
GetFastElementsUsage()16028 int JSObject::GetFastElementsUsage() {
16029   FixedArrayBase* store = elements();
16030   switch (GetElementsKind()) {
16031     case PACKED_SMI_ELEMENTS:
16032     case PACKED_DOUBLE_ELEMENTS:
16033     case PACKED_ELEMENTS:
16034       return IsJSArray() ? Smi::ToInt(JSArray::cast(this)->length())
16035                          : store->length();
16036     case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
16037       store = SloppyArgumentsElements::cast(store)->arguments();
16038       V8_FALLTHROUGH;
16039     case HOLEY_SMI_ELEMENTS:
16040     case HOLEY_ELEMENTS:
16041     case FAST_STRING_WRAPPER_ELEMENTS:
16042       return HoleyElementsUsage(this, FixedArray::cast(store));
16043     case HOLEY_DOUBLE_ELEMENTS:
16044       if (elements()->length() == 0) return 0;
16045       return HoleyElementsUsage(this, FixedDoubleArray::cast(store));
16046 
16047     case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
16048     case SLOW_STRING_WRAPPER_ELEMENTS:
16049     case DICTIONARY_ELEMENTS:
16050     case NO_ELEMENTS:
16051 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS:
16052 
16053       TYPED_ARRAYS(TYPED_ARRAY_CASE)
16054 #undef TYPED_ARRAY_CASE
16055     UNREACHABLE();
16056   }
16057   return 0;
16058 }
16059 
16060 
16061 // Certain compilers request function template instantiation when they
16062 // see the definition of the other template functions in the
16063 // class. This requires us to have the template functions put
16064 // together, so even though this function belongs in objects-debug.cc,
16065 // we keep it here instead to satisfy certain compilers.
16066 #ifdef OBJECT_PRINT
16067 template <typename Derived, typename Shape>
Print(std::ostream & os)16068 void Dictionary<Derived, Shape>::Print(std::ostream& os) {
16069   DisallowHeapAllocation no_gc;
16070   ReadOnlyRoots roots = this->GetReadOnlyRoots();
16071   Derived* dictionary = Derived::cast(this);
16072   int capacity = dictionary->Capacity();
16073   for (int i = 0; i < capacity; i++) {
16074     Object* k = dictionary->KeyAt(i);
16075     if (!dictionary->ToKey(roots, i, &k)) continue;
16076     os << "\n   ";
16077     if (k->IsString()) {
16078       String::cast(k)->StringPrint(os);
16079     } else {
16080       os << Brief(k);
16081     }
16082     os << ": " << Brief(dictionary->ValueAt(i)) << " ";
16083     dictionary->DetailsAt(i).PrintAsSlowTo(os);
16084   }
16085 }
16086 template <typename Derived, typename Shape>
Print()16087 void Dictionary<Derived, Shape>::Print() {
16088   StdoutStream os;
16089   Print(os);
16090   os << std::endl;
16091 }
16092 #endif
16093 
16094 
GetPropertyWithInterceptor(LookupIterator * it,bool * done)16095 MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it,
16096                                                          bool* done) {
16097   DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
16098   return GetPropertyWithInterceptorInternal(it, it->GetInterceptor(), done);
16099 }
16100 
HasRealNamedProperty(Handle<JSObject> object,Handle<Name> name)16101 Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object,
16102                                            Handle<Name> name) {
16103   LookupIterator it = LookupIterator::PropertyOrElement(
16104       object->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
16105   return HasProperty(&it);
16106 }
16107 
16108 
HasRealElementProperty(Handle<JSObject> object,uint32_t index)16109 Maybe<bool> JSObject::HasRealElementProperty(Handle<JSObject> object,
16110                                              uint32_t index) {
16111   Isolate* isolate = object->GetIsolate();
16112   LookupIterator it(isolate, object, index, object,
16113                     LookupIterator::OWN_SKIP_INTERCEPTOR);
16114   return HasProperty(&it);
16115 }
16116 
16117 
HasRealNamedCallbackProperty(Handle<JSObject> object,Handle<Name> name)16118 Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
16119                                                    Handle<Name> name) {
16120   LookupIterator it = LookupIterator::PropertyOrElement(
16121       object->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
16122   Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
16123   return maybe_result.IsJust() ? Just(it.state() == LookupIterator::ACCESSOR)
16124                                : Nothing<bool>();
16125 }
16126 
GetMaxLengthForNewSpaceAllocation(ElementsKind kind)16127 int FixedArrayBase::GetMaxLengthForNewSpaceAllocation(ElementsKind kind) {
16128   return ((kMaxRegularHeapObjectSize - FixedArrayBase::kHeaderSize) >>
16129           ElementsKindToShiftSize(kind));
16130 }
16131 
IsCowArray() const16132 bool FixedArrayBase::IsCowArray() const {
16133   return map() == GetReadOnlyRoots().fixed_cow_array_map();
16134 }
16135 
IsApiWrapper()16136 bool JSObject::IsApiWrapper() {
16137   auto instance_type = map()->instance_type();
16138   return instance_type == JS_API_OBJECT_TYPE ||
16139          instance_type == JS_SPECIAL_API_OBJECT_TYPE;
16140 }
16141 
PrivateSymbolToName() const16142 const char* Symbol::PrivateSymbolToName() const {
16143   ReadOnlyRoots roots = GetReadOnlyRoots();
16144 #define SYMBOL_CHECK_AND_PRINT(name) \
16145   if (this == roots.name()) return #name;
16146   PRIVATE_SYMBOL_LIST(SYMBOL_CHECK_AND_PRINT)
16147 #undef SYMBOL_CHECK_AND_PRINT
16148   return "UNKNOWN";
16149 }
16150 
16151 
SymbolShortPrint(std::ostream & os)16152 void Symbol::SymbolShortPrint(std::ostream& os) {
16153   os << "<Symbol:";
16154   if (!name()->IsUndefined()) {
16155     os << " ";
16156     HeapStringAllocator allocator;
16157     StringStream accumulator(&allocator);
16158     String::cast(name())->StringShortPrint(&accumulator, false);
16159     os << accumulator.ToCString().get();
16160   } else {
16161     os << " (" << PrivateSymbolToName() << ")";
16162   }
16163   os << ">";
16164 }
16165 
16166 
16167 // StringSharedKeys are used as keys in the eval cache.
16168 class StringSharedKey : public HashTableKey {
16169  public:
16170   // This tuple unambiguously identifies calls to eval() or
16171   // CreateDynamicFunction() (such as through the Function() constructor).
16172   // * source is the string passed into eval(). For dynamic functions, this is
16173   //   the effective source for the function, some of which is implicitly
16174   //   generated.
16175   // * shared is the shared function info for the function containing the call
16176   //   to eval(). for dynamic functions, shared is the native context closure.
16177   // * When positive, position is the position in the source where eval is
16178   //   called. When negative, position is the negation of the position in the
16179   //   dynamic function's effective source where the ')' ends the parameters.
StringSharedKey(Handle<String> source,Handle<SharedFunctionInfo> shared,LanguageMode language_mode,int position)16180   StringSharedKey(Handle<String> source, Handle<SharedFunctionInfo> shared,
16181                   LanguageMode language_mode, int position)
16182       : HashTableKey(CompilationCacheShape::StringSharedHash(
16183             *source, *shared, language_mode, position)),
16184         source_(source),
16185         shared_(shared),
16186         language_mode_(language_mode),
16187         position_(position) {}
16188 
IsMatch(Object * other)16189   bool IsMatch(Object* other) override {
16190     DisallowHeapAllocation no_allocation;
16191     if (!other->IsFixedArray()) {
16192       DCHECK(other->IsNumber());
16193       uint32_t other_hash = static_cast<uint32_t>(other->Number());
16194       return Hash() == other_hash;
16195     }
16196     FixedArray* other_array = FixedArray::cast(other);
16197     SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
16198     if (shared != *shared_) return false;
16199     int language_unchecked = Smi::ToInt(other_array->get(2));
16200     DCHECK(is_valid_language_mode(language_unchecked));
16201     LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
16202     if (language_mode != language_mode_) return false;
16203     int position = Smi::ToInt(other_array->get(3));
16204     if (position != position_) return false;
16205     String* source = String::cast(other_array->get(1));
16206     return source->Equals(*source_);
16207   }
16208 
AsHandle(Isolate * isolate)16209   Handle<Object> AsHandle(Isolate* isolate) {
16210     Handle<FixedArray> array = isolate->factory()->NewFixedArray(4);
16211     array->set(0, *shared_);
16212     array->set(1, *source_);
16213     array->set(2, Smi::FromEnum(language_mode_));
16214     array->set(3, Smi::FromInt(position_));
16215     array->set_map(ReadOnlyRoots(isolate).fixed_cow_array_map());
16216     return array;
16217   }
16218 
16219  private:
16220   Handle<String> source_;
16221   Handle<SharedFunctionInfo> shared_;
16222   LanguageMode language_mode_;
16223   int position_;
16224 };
16225 
status() const16226 v8::Promise::PromiseState JSPromise::status() const {
16227   int value = flags() & kStatusMask;
16228   DCHECK(value == 0 || value == 1 || value == 2);
16229   return static_cast<v8::Promise::PromiseState>(value);
16230 }
16231 
set_status(Promise::PromiseState status)16232 void JSPromise::set_status(Promise::PromiseState status) {
16233   int value = flags() & ~kStatusMask;
16234   set_flags(value | status);
16235 }
16236 
16237 // static
Status(v8::Promise::PromiseState status)16238 const char* JSPromise::Status(v8::Promise::PromiseState status) {
16239   switch (status) {
16240     case v8::Promise::kFulfilled:
16241       return "resolved";
16242     case v8::Promise::kPending:
16243       return "pending";
16244     case v8::Promise::kRejected:
16245       return "rejected";
16246   }
16247   UNREACHABLE();
16248 }
16249 
async_task_id() const16250 int JSPromise::async_task_id() const {
16251   return AsyncTaskIdField::decode(flags());
16252 }
16253 
set_async_task_id(int id)16254 void JSPromise::set_async_task_id(int id) {
16255   set_flags(AsyncTaskIdField::update(flags(), id));
16256 }
16257 
16258 // static
Fulfill(Handle<JSPromise> promise,Handle<Object> value)16259 Handle<Object> JSPromise::Fulfill(Handle<JSPromise> promise,
16260                                   Handle<Object> value) {
16261   Isolate* const isolate = promise->GetIsolate();
16262 
16263   // 1. Assert: The value of promise.[[PromiseState]] is "pending".
16264   DCHECK_EQ(Promise::kPending, promise->status());
16265 
16266   // 2. Let reactions be promise.[[PromiseFulfillReactions]].
16267   Handle<Object> reactions(promise->reactions(), isolate);
16268 
16269   // 3. Set promise.[[PromiseResult]] to value.
16270   // 4. Set promise.[[PromiseFulfillReactions]] to undefined.
16271   // 5. Set promise.[[PromiseRejectReactions]] to undefined.
16272   promise->set_reactions_or_result(*value);
16273 
16274   // 6. Set promise.[[PromiseState]] to "fulfilled".
16275   promise->set_status(Promise::kFulfilled);
16276 
16277   // 7. Return TriggerPromiseReactions(reactions, value).
16278   return TriggerPromiseReactions(isolate, reactions, value,
16279                                  PromiseReaction::kFulfill);
16280 }
16281 
16282 // static
Reject(Handle<JSPromise> promise,Handle<Object> reason,bool debug_event)16283 Handle<Object> JSPromise::Reject(Handle<JSPromise> promise,
16284                                  Handle<Object> reason, bool debug_event) {
16285   Isolate* const isolate = promise->GetIsolate();
16286 
16287   if (debug_event) isolate->debug()->OnPromiseReject(promise, reason);
16288   isolate->RunPromiseHook(PromiseHookType::kResolve, promise,
16289                           isolate->factory()->undefined_value());
16290 
16291   // 1. Assert: The value of promise.[[PromiseState]] is "pending".
16292   DCHECK_EQ(Promise::kPending, promise->status());
16293 
16294   // 2. Let reactions be promise.[[PromiseRejectReactions]].
16295   Handle<Object> reactions(promise->reactions(), isolate);
16296 
16297   // 3. Set promise.[[PromiseResult]] to reason.
16298   // 4. Set promise.[[PromiseFulfillReactions]] to undefined.
16299   // 5. Set promise.[[PromiseRejectReactions]] to undefined.
16300   promise->set_reactions_or_result(*reason);
16301 
16302   // 6. Set promise.[[PromiseState]] to "rejected".
16303   promise->set_status(Promise::kRejected);
16304 
16305   // 7. If promise.[[PromiseIsHandled]] is false, perform
16306   //    HostPromiseRejectionTracker(promise, "reject").
16307   if (!promise->has_handler()) {
16308     isolate->ReportPromiseReject(promise, reason, kPromiseRejectWithNoHandler);
16309   }
16310 
16311   // 8. Return TriggerPromiseReactions(reactions, reason).
16312   return TriggerPromiseReactions(isolate, reactions, reason,
16313                                  PromiseReaction::kReject);
16314 }
16315 
16316 // static
Resolve(Handle<JSPromise> promise,Handle<Object> resolution)16317 MaybeHandle<Object> JSPromise::Resolve(Handle<JSPromise> promise,
16318                                        Handle<Object> resolution) {
16319   Isolate* const isolate = promise->GetIsolate();
16320 
16321   isolate->RunPromiseHook(PromiseHookType::kResolve, promise,
16322                           isolate->factory()->undefined_value());
16323 
16324   // 6. If SameValue(resolution, promise) is true, then
16325   if (promise.is_identical_to(resolution)) {
16326     // a. Let selfResolutionError be a newly created TypeError object.
16327     Handle<Object> self_resolution_error = isolate->factory()->NewTypeError(
16328         MessageTemplate::kPromiseCyclic, resolution);
16329     // b. Return RejectPromise(promise, selfResolutionError).
16330     return Reject(promise, self_resolution_error);
16331   }
16332 
16333   // 7. If Type(resolution) is not Object, then
16334   if (!resolution->IsJSReceiver()) {
16335     // a. Return FulfillPromise(promise, resolution).
16336     return Fulfill(promise, resolution);
16337   }
16338 
16339   // 8. Let then be Get(resolution, "then").
16340   MaybeHandle<Object> then;
16341   if (isolate->IsPromiseThenLookupChainIntact(
16342           Handle<JSReceiver>::cast(resolution))) {
16343     // We can skip the "then" lookup on {resolution} if its [[Prototype]]
16344     // is the (initial) Promise.prototype and the Promise#then protector
16345     // is intact, as that guards the lookup path for the "then" property
16346     // on JSPromise instances which have the (initial) %PromisePrototype%.
16347     then = isolate->promise_then();
16348   } else {
16349     then =
16350         JSReceiver::GetProperty(isolate, Handle<JSReceiver>::cast(resolution),
16351                                 isolate->factory()->then_string());
16352   }
16353 
16354   // 9. If then is an abrupt completion, then
16355   Handle<Object> then_action;
16356   if (!then.ToHandle(&then_action)) {
16357     // a. Return RejectPromise(promise, then.[[Value]]).
16358     Handle<Object> reason(isolate->pending_exception(), isolate);
16359     isolate->clear_pending_exception();
16360     return Reject(promise, reason, false);
16361   }
16362 
16363   // 10. Let thenAction be then.[[Value]].
16364   // 11. If IsCallable(thenAction) is false, then
16365   if (!then_action->IsCallable()) {
16366     // a. Return FulfillPromise(promise, resolution).
16367     return Fulfill(promise, resolution);
16368   }
16369 
16370   // 12. Perform EnqueueJob("PromiseJobs", PromiseResolveThenableJob,
16371   //                        «promise, resolution, thenAction»).
16372   Handle<PromiseResolveThenableJobTask> task =
16373       isolate->factory()->NewPromiseResolveThenableJobTask(
16374           promise, Handle<JSReceiver>::cast(then_action),
16375           Handle<JSReceiver>::cast(resolution), isolate->native_context());
16376   if (isolate->debug()->is_active() && resolution->IsJSPromise()) {
16377     // Mark the dependency of the new {promise} on the {resolution}.
16378     Object::SetProperty(isolate, resolution,
16379                         isolate->factory()->promise_handled_by_symbol(),
16380                         promise, LanguageMode::kStrict)
16381         .Check();
16382   }
16383   isolate->EnqueueMicrotask(task);
16384 
16385   // 13. Return undefined.
16386   return isolate->factory()->undefined_value();
16387 }
16388 
16389 // static
TriggerPromiseReactions(Isolate * isolate,Handle<Object> reactions,Handle<Object> argument,PromiseReaction::Type type)16390 Handle<Object> JSPromise::TriggerPromiseReactions(Isolate* isolate,
16391                                                   Handle<Object> reactions,
16392                                                   Handle<Object> argument,
16393                                                   PromiseReaction::Type type) {
16394   DCHECK(reactions->IsSmi() || reactions->IsPromiseReaction());
16395 
16396   // We need to reverse the {reactions} here, since we record them
16397   // on the JSPromise in the reverse order.
16398   {
16399     DisallowHeapAllocation no_gc;
16400     Object* current = *reactions;
16401     Object* reversed = Smi::kZero;
16402     while (!current->IsSmi()) {
16403       Object* next = PromiseReaction::cast(current)->next();
16404       PromiseReaction::cast(current)->set_next(reversed);
16405       reversed = current;
16406       current = next;
16407     }
16408     reactions = handle(reversed, isolate);
16409   }
16410 
16411   // Morph the {reactions} into PromiseReactionJobTasks
16412   // and push them onto the microtask queue.
16413   while (!reactions->IsSmi()) {
16414     Handle<HeapObject> task = Handle<HeapObject>::cast(reactions);
16415     Handle<PromiseReaction> reaction = Handle<PromiseReaction>::cast(task);
16416     reactions = handle(reaction->next(), isolate);
16417 
16418     STATIC_ASSERT(PromiseReaction::kSize == PromiseReactionJobTask::kSize);
16419     if (type == PromiseReaction::kFulfill) {
16420       task->synchronized_set_map(
16421           ReadOnlyRoots(isolate).promise_fulfill_reaction_job_task_map());
16422       Handle<PromiseFulfillReactionJobTask>::cast(task)->set_argument(
16423           *argument);
16424       Handle<PromiseFulfillReactionJobTask>::cast(task)->set_context(
16425           *isolate->native_context());
16426       STATIC_ASSERT(PromiseReaction::kFulfillHandlerOffset ==
16427                     PromiseFulfillReactionJobTask::kHandlerOffset);
16428       STATIC_ASSERT(PromiseReaction::kPromiseOrCapabilityOffset ==
16429                     PromiseFulfillReactionJobTask::kPromiseOrCapabilityOffset);
16430     } else {
16431       DisallowHeapAllocation no_gc;
16432       HeapObject* handler = reaction->reject_handler();
16433       task->synchronized_set_map(
16434           ReadOnlyRoots(isolate).promise_reject_reaction_job_task_map());
16435       Handle<PromiseRejectReactionJobTask>::cast(task)->set_argument(*argument);
16436       Handle<PromiseRejectReactionJobTask>::cast(task)->set_context(
16437           *isolate->native_context());
16438       Handle<PromiseRejectReactionJobTask>::cast(task)->set_handler(handler);
16439       STATIC_ASSERT(PromiseReaction::kPromiseOrCapabilityOffset ==
16440                     PromiseRejectReactionJobTask::kPromiseOrCapabilityOffset);
16441     }
16442 
16443     isolate->EnqueueMicrotask(Handle<PromiseReactionJobTask>::cast(task));
16444   }
16445 
16446   return isolate->factory()->undefined_value();
16447 }
16448 
16449 namespace {
16450 
RegExpFlagsFromString(Handle<String> flags,bool * success)16451 JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags, bool* success) {
16452   JSRegExp::Flags value = JSRegExp::kNone;
16453   int length = flags->length();
16454   // A longer flags string cannot be valid.
16455   if (length > JSRegExp::FlagCount()) return JSRegExp::Flags(0);
16456   for (int i = 0; i < length; i++) {
16457     JSRegExp::Flag flag = JSRegExp::kNone;
16458     switch (flags->Get(i)) {
16459       case 'g':
16460         flag = JSRegExp::kGlobal;
16461         break;
16462       case 'i':
16463         flag = JSRegExp::kIgnoreCase;
16464         break;
16465       case 'm':
16466         flag = JSRegExp::kMultiline;
16467         break;
16468       case 's':
16469         flag = JSRegExp::kDotAll;
16470         break;
16471       case 'u':
16472         flag = JSRegExp::kUnicode;
16473         break;
16474       case 'y':
16475         flag = JSRegExp::kSticky;
16476         break;
16477       default:
16478         return JSRegExp::Flags(0);
16479     }
16480     // Duplicate flag.
16481     if (value & flag) return JSRegExp::Flags(0);
16482     value |= flag;
16483   }
16484   *success = true;
16485   return value;
16486 }
16487 
16488 }  // namespace
16489 
16490 
16491 // static
New(Isolate * isolate,Handle<String> pattern,Flags flags)16492 MaybeHandle<JSRegExp> JSRegExp::New(Isolate* isolate, Handle<String> pattern,
16493                                     Flags flags) {
16494   Handle<JSFunction> constructor = isolate->regexp_function();
16495   Handle<JSRegExp> regexp =
16496       Handle<JSRegExp>::cast(isolate->factory()->NewJSObject(constructor));
16497 
16498   return JSRegExp::Initialize(regexp, pattern, flags);
16499 }
16500 
16501 
16502 // static
Copy(Handle<JSRegExp> regexp)16503 Handle<JSRegExp> JSRegExp::Copy(Handle<JSRegExp> regexp) {
16504   Isolate* const isolate = regexp->GetIsolate();
16505   return Handle<JSRegExp>::cast(isolate->factory()->CopyJSObject(regexp));
16506 }
16507 
16508 
16509 template <typename Char>
CountRequiredEscapes(Handle<String> source)16510 inline int CountRequiredEscapes(Handle<String> source) {
16511   DisallowHeapAllocation no_gc;
16512   int escapes = 0;
16513   Vector<const Char> src = source->GetCharVector<Char>();
16514   for (int i = 0; i < src.length(); i++) {
16515     if (src[i] == '\\') {
16516       // Escape. Skip next character;
16517       i++;
16518     } else if (src[i] == '/') {
16519       // Not escaped forward-slash needs escape.
16520       escapes++;
16521     }
16522   }
16523   return escapes;
16524 }
16525 
16526 
16527 template <typename Char, typename StringType>
WriteEscapedRegExpSource(Handle<String> source,Handle<StringType> result)16528 inline Handle<StringType> WriteEscapedRegExpSource(Handle<String> source,
16529                                                    Handle<StringType> result) {
16530   DisallowHeapAllocation no_gc;
16531   Vector<const Char> src = source->GetCharVector<Char>();
16532   Vector<Char> dst(result->GetChars(), result->length());
16533   int s = 0;
16534   int d = 0;
16535   while (s < src.length()) {
16536     if (src[s] == '\\') {
16537       // Escape. Copy this and next character.
16538       dst[d++] = src[s++];
16539       if (s == src.length()) break;
16540     } else if (src[s] == '/') {
16541       // Not escaped forward-slash needs escape.
16542       dst[d++] = '\\';
16543     }
16544     dst[d++] = src[s++];
16545   }
16546   DCHECK_EQ(result->length(), d);
16547   return result;
16548 }
16549 
16550 
EscapeRegExpSource(Isolate * isolate,Handle<String> source)16551 MaybeHandle<String> EscapeRegExpSource(Isolate* isolate,
16552                                        Handle<String> source) {
16553   DCHECK(source->IsFlat());
16554   if (source->length() == 0) return isolate->factory()->query_colon_string();
16555   bool one_byte = source->IsOneByteRepresentationUnderneath();
16556   int escapes = one_byte ? CountRequiredEscapes<uint8_t>(source)
16557                          : CountRequiredEscapes<uc16>(source);
16558   if (escapes == 0) return source;
16559   int length = source->length() + escapes;
16560   if (one_byte) {
16561     Handle<SeqOneByteString> result;
16562     ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
16563                                isolate->factory()->NewRawOneByteString(length),
16564                                String);
16565     return WriteEscapedRegExpSource<uint8_t>(source, result);
16566   } else {
16567     Handle<SeqTwoByteString> result;
16568     ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
16569                                isolate->factory()->NewRawTwoByteString(length),
16570                                String);
16571     return WriteEscapedRegExpSource<uc16>(source, result);
16572   }
16573 }
16574 
16575 
16576 // static
Initialize(Handle<JSRegExp> regexp,Handle<String> source,Handle<String> flags_string)16577 MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
16578                                            Handle<String> source,
16579                                            Handle<String> flags_string) {
16580   Isolate* isolate = regexp->GetIsolate();
16581   bool success = false;
16582   Flags flags = RegExpFlagsFromString(flags_string, &success);
16583   if (!success) {
16584     THROW_NEW_ERROR(
16585         isolate,
16586         NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string),
16587         JSRegExp);
16588   }
16589   return Initialize(regexp, source, flags);
16590 }
16591 
16592 
16593 // static
Initialize(Handle<JSRegExp> regexp,Handle<String> source,Flags flags)16594 MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
16595                                            Handle<String> source, Flags flags) {
16596   Isolate* isolate = regexp->GetIsolate();
16597   Factory* factory = isolate->factory();
16598   // If source is the empty string we set it to "(?:)" instead as
16599   // suggested by ECMA-262, 5th, section 15.10.4.1.
16600   if (source->length() == 0) source = factory->query_colon_string();
16601 
16602   source = String::Flatten(isolate, source);
16603 
16604   Handle<String> escaped_source;
16605   ASSIGN_RETURN_ON_EXCEPTION(isolate, escaped_source,
16606                              EscapeRegExpSource(isolate, source), JSRegExp);
16607 
16608   RETURN_ON_EXCEPTION(
16609       isolate, RegExpImpl::Compile(isolate, regexp, source, flags), JSRegExp);
16610 
16611   regexp->set_source(*escaped_source);
16612   regexp->set_flags(Smi::FromInt(flags));
16613 
16614   Map* map = regexp->map();
16615   Object* constructor = map->GetConstructor();
16616   if (constructor->IsJSFunction() &&
16617       JSFunction::cast(constructor)->initial_map() == map) {
16618     // If we still have the original map, set in-object properties directly.
16619     regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, Smi::kZero,
16620                                   SKIP_WRITE_BARRIER);
16621   } else {
16622     // Map has changed, so use generic, but slower, method.
16623     RETURN_ON_EXCEPTION(
16624         isolate,
16625         JSReceiver::SetProperty(isolate, regexp, factory->lastIndex_string(),
16626                                 Handle<Smi>(Smi::kZero, isolate),
16627                                 LanguageMode::kStrict),
16628         JSRegExp);
16629   }
16630 
16631   return regexp;
16632 }
16633 
16634 
16635 // RegExpKey carries the source and flags of a regular expression as key.
16636 class RegExpKey : public HashTableKey {
16637  public:
RegExpKey(Handle<String> string,JSRegExp::Flags flags)16638   RegExpKey(Handle<String> string, JSRegExp::Flags flags)
16639       : HashTableKey(
16640             CompilationCacheShape::RegExpHash(*string, Smi::FromInt(flags))),
16641         string_(string),
16642         flags_(Smi::FromInt(flags)) {}
16643 
16644   // Rather than storing the key in the hash table, a pointer to the
16645   // stored value is stored where the key should be.  IsMatch then
16646   // compares the search key to the found object, rather than comparing
16647   // a key to a key.
IsMatch(Object * obj)16648   bool IsMatch(Object* obj) override {
16649     FixedArray* val = FixedArray::cast(obj);
16650     return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
16651         && (flags_ == val->get(JSRegExp::kFlagsIndex));
16652   }
16653 
16654   Handle<String> string_;
16655   Smi* flags_;
16656 };
16657 
AsHandle(Isolate * isolate)16658 Handle<String> OneByteStringKey::AsHandle(Isolate* isolate) {
16659   return isolate->factory()->NewOneByteInternalizedString(string_, HashField());
16660 }
16661 
AsHandle(Isolate * isolate)16662 Handle<String> TwoByteStringKey::AsHandle(Isolate* isolate) {
16663   return isolate->factory()->NewTwoByteInternalizedString(string_, HashField());
16664 }
16665 
AsHandle(Isolate * isolate)16666 Handle<String> SeqOneByteSubStringKey::AsHandle(Isolate* isolate) {
16667   return isolate->factory()->NewOneByteInternalizedSubString(
16668       string_, from_, length_, HashField());
16669 }
16670 
16671 
IsMatch(Object * string)16672 bool SeqOneByteSubStringKey::IsMatch(Object* string) {
16673   Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
16674   return String::cast(string)->IsOneByteEqualTo(chars);
16675 }
16676 
16677 
16678 // InternalizedStringKey carries a string/internalized-string object as key.
16679 class InternalizedStringKey : public StringTableKey {
16680  public:
InternalizedStringKey(Handle<String> string)16681   explicit InternalizedStringKey(Handle<String> string)
16682       : StringTableKey(0), string_(string) {
16683     DCHECK(!string->IsInternalizedString());
16684     DCHECK(string->IsFlat());
16685     // Make sure hash_field is computed.
16686     string->Hash();
16687     set_hash_field(string->hash_field());
16688   }
16689 
IsMatch(Object * string)16690   bool IsMatch(Object* string) override {
16691     return string_->SlowEquals(String::cast(string));
16692   }
16693 
AsHandle(Isolate * isolate)16694   Handle<String> AsHandle(Isolate* isolate) override {
16695     // Internalize the string if possible.
16696     MaybeHandle<Map> maybe_map =
16697         isolate->factory()->InternalizedStringMapForString(string_);
16698     Handle<Map> map;
16699     if (maybe_map.ToHandle(&map)) {
16700       string_->set_map_no_write_barrier(*map);
16701       DCHECK(string_->IsInternalizedString());
16702       return string_;
16703     }
16704     if (FLAG_thin_strings) {
16705       // External strings get special treatment, to avoid copying their
16706       // contents.
16707       if (string_->IsExternalOneByteString()) {
16708         return isolate->factory()
16709             ->InternalizeExternalString<ExternalOneByteString>(string_);
16710       } else if (string_->IsExternalTwoByteString()) {
16711         return isolate->factory()
16712             ->InternalizeExternalString<ExternalTwoByteString>(string_);
16713       }
16714     }
16715     // Otherwise allocate a new internalized string.
16716     return isolate->factory()->NewInternalizedStringImpl(
16717         string_, string_->length(), string_->hash_field());
16718   }
16719 
16720  private:
16721   Handle<String> string_;
16722 };
16723 
16724 template <typename Derived, typename Shape>
IteratePrefix(ObjectVisitor * v)16725 void HashTable<Derived, Shape>::IteratePrefix(ObjectVisitor* v) {
16726   BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v);
16727 }
16728 
16729 template <typename Derived, typename Shape>
IterateElements(ObjectVisitor * v)16730 void HashTable<Derived, Shape>::IterateElements(ObjectVisitor* v) {
16731   BodyDescriptorBase::IteratePointers(this, kElementsStartOffset,
16732                                       kHeaderSize + length() * kPointerSize, v);
16733 }
16734 
16735 template <typename Derived, typename Shape>
New(Isolate * isolate,int at_least_space_for,PretenureFlag pretenure,MinimumCapacity capacity_option)16736 Handle<Derived> HashTable<Derived, Shape>::New(
16737     Isolate* isolate, int at_least_space_for, PretenureFlag pretenure,
16738     MinimumCapacity capacity_option) {
16739   DCHECK_LE(0, at_least_space_for);
16740   DCHECK_IMPLIES(capacity_option == USE_CUSTOM_MINIMUM_CAPACITY,
16741                  base::bits::IsPowerOfTwo(at_least_space_for));
16742 
16743   int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
16744                      ? at_least_space_for
16745                      : ComputeCapacity(at_least_space_for);
16746   if (capacity > HashTable::kMaxCapacity) {
16747     isolate->heap()->FatalProcessOutOfMemory("invalid table size");
16748   }
16749   return NewInternal(isolate, capacity, pretenure);
16750 }
16751 
16752 template <typename Derived, typename Shape>
NewInternal(Isolate * isolate,int capacity,PretenureFlag pretenure)16753 Handle<Derived> HashTable<Derived, Shape>::NewInternal(
16754     Isolate* isolate, int capacity, PretenureFlag pretenure) {
16755   Factory* factory = isolate->factory();
16756   int length = EntryToIndex(capacity);
16757   Heap::RootListIndex map_root_index =
16758       static_cast<Heap::RootListIndex>(Shape::GetMapRootIndex());
16759   Handle<FixedArray> array =
16760       factory->NewFixedArrayWithMap(map_root_index, length, pretenure);
16761   Handle<Derived> table = Handle<Derived>::cast(array);
16762 
16763   table->SetNumberOfElements(0);
16764   table->SetNumberOfDeletedElements(0);
16765   table->SetCapacity(capacity);
16766   return table;
16767 }
16768 
16769 template <typename Derived, typename Shape>
Rehash(Isolate * isolate,Derived * new_table)16770 void HashTable<Derived, Shape>::Rehash(Isolate* isolate, Derived* new_table) {
16771   DisallowHeapAllocation no_gc;
16772   WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
16773 
16774   DCHECK_LT(NumberOfElements(), new_table->Capacity());
16775 
16776   // Copy prefix to new array.
16777   for (int i = kPrefixStartIndex; i < kElementsStartIndex; i++) {
16778     new_table->set(i, get(i), mode);
16779   }
16780 
16781   // Rehash the elements.
16782   int capacity = this->Capacity();
16783   ReadOnlyRoots roots(isolate);
16784   for (int i = 0; i < capacity; i++) {
16785     uint32_t from_index = EntryToIndex(i);
16786     Object* k = this->get(from_index);
16787     if (!Shape::IsLive(roots, k)) continue;
16788     uint32_t hash = Shape::HashForObject(isolate, k);
16789     uint32_t insertion_index =
16790         EntryToIndex(new_table->FindInsertionEntry(hash));
16791     for (int j = 0; j < Shape::kEntrySize; j++) {
16792       new_table->set(insertion_index + j, get(from_index + j), mode);
16793     }
16794   }
16795   new_table->SetNumberOfElements(NumberOfElements());
16796   new_table->SetNumberOfDeletedElements(0);
16797 }
16798 
16799 template <typename Derived, typename Shape>
EntryForProbe(Isolate * isolate,Object * k,int probe,uint32_t expected)16800 uint32_t HashTable<Derived, Shape>::EntryForProbe(Isolate* isolate, Object* k,
16801                                                   int probe,
16802                                                   uint32_t expected) {
16803   uint32_t hash = Shape::HashForObject(isolate, k);
16804   uint32_t capacity = this->Capacity();
16805   uint32_t entry = FirstProbe(hash, capacity);
16806   for (int i = 1; i < probe; i++) {
16807     if (entry == expected) return expected;
16808     entry = NextProbe(entry, i, capacity);
16809   }
16810   return entry;
16811 }
16812 
16813 template <typename Derived, typename Shape>
Swap(uint32_t entry1,uint32_t entry2,WriteBarrierMode mode)16814 void HashTable<Derived, Shape>::Swap(uint32_t entry1, uint32_t entry2,
16815                                      WriteBarrierMode mode) {
16816   int index1 = EntryToIndex(entry1);
16817   int index2 = EntryToIndex(entry2);
16818   Object* temp[Shape::kEntrySize];
16819   for (int j = 0; j < Shape::kEntrySize; j++) {
16820     temp[j] = get(index1 + j);
16821   }
16822   for (int j = 0; j < Shape::kEntrySize; j++) {
16823     set(index1 + j, get(index2 + j), mode);
16824   }
16825   for (int j = 0; j < Shape::kEntrySize; j++) {
16826     set(index2 + j, temp[j], mode);
16827   }
16828 }
16829 
16830 template <typename Derived, typename Shape>
Rehash(Isolate * isolate)16831 void HashTable<Derived, Shape>::Rehash(Isolate* isolate) {
16832   DisallowHeapAllocation no_gc;
16833   WriteBarrierMode mode = GetWriteBarrierMode(no_gc);
16834   ReadOnlyRoots roots(isolate);
16835   uint32_t capacity = Capacity();
16836   bool done = false;
16837   for (int probe = 1; !done; probe++) {
16838     // All elements at entries given by one of the first _probe_ probes
16839     // are placed correctly. Other elements might need to be moved.
16840     done = true;
16841     for (uint32_t current = 0; current < capacity; current++) {
16842       Object* current_key = KeyAt(current);
16843       if (!Shape::IsLive(roots, current_key)) continue;
16844       uint32_t target = EntryForProbe(isolate, current_key, probe, current);
16845       if (current == target) continue;
16846       Object* target_key = KeyAt(target);
16847       if (!Shape::IsLive(roots, target_key) ||
16848           EntryForProbe(isolate, target_key, probe, target) != target) {
16849         // Put the current element into the correct position.
16850         Swap(current, target, mode);
16851         // The other element will be processed on the next iteration.
16852         current--;
16853       } else {
16854         // The place for the current element is occupied. Leave the element
16855         // for the next probe.
16856         done = false;
16857       }
16858     }
16859   }
16860   // Wipe deleted entries.
16861   Object* the_hole = roots.the_hole_value();
16862   Object* undefined = roots.undefined_value();
16863   for (uint32_t current = 0; current < capacity; current++) {
16864     if (KeyAt(current) == the_hole) {
16865       set(EntryToIndex(current) + kEntryKeyIndex, undefined);
16866     }
16867   }
16868   SetNumberOfDeletedElements(0);
16869 }
16870 
16871 template <typename Derived, typename Shape>
EnsureCapacity(Isolate * isolate,Handle<Derived> table,int n,PretenureFlag pretenure)16872 Handle<Derived> HashTable<Derived, Shape>::EnsureCapacity(
16873     Isolate* isolate, Handle<Derived> table, int n, PretenureFlag pretenure) {
16874   if (table->HasSufficientCapacityToAdd(n)) return table;
16875 
16876   int capacity = table->Capacity();
16877   int new_nof = table->NumberOfElements() + n;
16878 
16879   const int kMinCapacityForPretenure = 256;
16880   bool should_pretenure =
16881       pretenure == TENURED ||
16882       ((capacity > kMinCapacityForPretenure) && !Heap::InNewSpace(*table));
16883   Handle<Derived> new_table = HashTable::New(
16884       isolate, new_nof, should_pretenure ? TENURED : NOT_TENURED);
16885 
16886   table->Rehash(isolate, *new_table);
16887   return new_table;
16888 }
16889 
16890 template bool
16891 HashTable<NameDictionary, NameDictionaryShape>::HasSufficientCapacityToAdd(int);
16892 
16893 template <typename Derived, typename Shape>
HasSufficientCapacityToAdd(int number_of_additional_elements)16894 bool HashTable<Derived, Shape>::HasSufficientCapacityToAdd(
16895     int number_of_additional_elements) {
16896   int capacity = Capacity();
16897   int nof = NumberOfElements() + number_of_additional_elements;
16898   int nod = NumberOfDeletedElements();
16899   // Return true if:
16900   //   50% is still free after adding number_of_additional_elements elements and
16901   //   at most 50% of the free elements are deleted elements.
16902   if ((nof < capacity) && ((nod <= (capacity - nof) >> 1))) {
16903     int needed_free = nof >> 1;
16904     if (nof + needed_free <= capacity) return true;
16905   }
16906   return false;
16907 }
16908 
16909 template <typename Derived, typename Shape>
Shrink(Isolate * isolate,Handle<Derived> table,int additionalCapacity)16910 Handle<Derived> HashTable<Derived, Shape>::Shrink(Isolate* isolate,
16911                                                   Handle<Derived> table,
16912                                                   int additionalCapacity) {
16913   int capacity = table->Capacity();
16914   int nof = table->NumberOfElements();
16915 
16916   // Shrink to fit the number of elements if only a quarter of the
16917   // capacity is filled with elements.
16918   if (nof > (capacity >> 2)) return table;
16919   // Allocate a new dictionary with room for at least the current number of
16920   // elements + {additionalCapacity}. The allocation method will make sure that
16921   // there is extra room in the dictionary for additions. Don't go lower than
16922   // room for {kMinShrinkCapacity} elements.
16923   int at_least_room_for = nof + additionalCapacity;
16924   int new_capacity = ComputeCapacity(at_least_room_for);
16925   if (new_capacity < Derived::kMinShrinkCapacity) return table;
16926   if (new_capacity == capacity) return table;
16927 
16928   const int kMinCapacityForPretenure = 256;
16929   bool pretenure = (at_least_room_for > kMinCapacityForPretenure) &&
16930                    !Heap::InNewSpace(*table);
16931   Handle<Derived> new_table =
16932       HashTable::New(isolate, new_capacity, pretenure ? TENURED : NOT_TENURED,
16933                      USE_CUSTOM_MINIMUM_CAPACITY);
16934 
16935   table->Rehash(isolate, *new_table);
16936   return new_table;
16937 }
16938 
16939 template <typename Derived, typename Shape>
FindInsertionEntry(uint32_t hash)16940 uint32_t HashTable<Derived, Shape>::FindInsertionEntry(uint32_t hash) {
16941   uint32_t capacity = Capacity();
16942   uint32_t entry = FirstProbe(hash, capacity);
16943   uint32_t count = 1;
16944   // EnsureCapacity will guarantee the hash table is never full.
16945   ReadOnlyRoots roots = GetReadOnlyRoots();
16946   while (true) {
16947     if (!Shape::IsLive(roots, KeyAt(entry))) break;
16948     entry = NextProbe(entry, count++, capacity);
16949   }
16950   return entry;
16951 }
16952 
InvalidatePropertyCell(Handle<JSGlobalObject> global,Handle<Name> name)16953 void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global,
16954                                             Handle<Name> name) {
16955   // Regardless of whether the property is there or not invalidate
16956   // Load/StoreGlobalICs that load/store through global object's prototype.
16957   JSObject::InvalidatePrototypeValidityCell(*global);
16958 
16959   DCHECK(!global->HasFastProperties());
16960   auto dictionary = handle(global->global_dictionary(), global->GetIsolate());
16961   int entry = dictionary->FindEntry(global->GetIsolate(), name);
16962   if (entry == GlobalDictionary::kNotFound) return;
16963   PropertyCell::InvalidateEntry(global->GetIsolate(), dictionary, entry);
16964 }
16965 
EnsureEmptyPropertyCell(Handle<JSGlobalObject> global,Handle<Name> name,PropertyCellType cell_type,int * entry_out)16966 Handle<PropertyCell> JSGlobalObject::EnsureEmptyPropertyCell(
16967     Handle<JSGlobalObject> global, Handle<Name> name,
16968     PropertyCellType cell_type, int* entry_out) {
16969   Isolate* isolate = global->GetIsolate();
16970   DCHECK(!global->HasFastProperties());
16971   Handle<GlobalDictionary> dictionary(global->global_dictionary(), isolate);
16972   int entry = dictionary->FindEntry(isolate, name);
16973   Handle<PropertyCell> cell;
16974   if (entry != GlobalDictionary::kNotFound) {
16975     if (entry_out) *entry_out = entry;
16976     cell = handle(dictionary->CellAt(entry), isolate);
16977     PropertyCellType original_cell_type = cell->property_details().cell_type();
16978     DCHECK(original_cell_type == PropertyCellType::kInvalidated ||
16979            original_cell_type == PropertyCellType::kUninitialized);
16980     DCHECK(cell->value()->IsTheHole(isolate));
16981     if (original_cell_type == PropertyCellType::kInvalidated) {
16982       cell = PropertyCell::InvalidateEntry(isolate, dictionary, entry);
16983     }
16984     PropertyDetails details(kData, NONE, cell_type);
16985     cell->set_property_details(details);
16986     return cell;
16987   }
16988   cell = isolate->factory()->NewPropertyCell(name);
16989   PropertyDetails details(kData, NONE, cell_type);
16990   dictionary = GlobalDictionary::Add(isolate, dictionary, name, cell, details,
16991                                      entry_out);
16992   // {*entry_out} is initialized inside GlobalDictionary::Add().
16993   global->SetProperties(*dictionary);
16994   return cell;
16995 }
16996 
16997 
16998 // This class is used for looking up two character strings in the string table.
16999 // If we don't have a hit we don't want to waste much time so we unroll the
17000 // string hash calculation loop here for speed.  Doesn't work if the two
17001 // characters form a decimal integer, since such strings have a different hash
17002 // algorithm.
17003 class TwoCharHashTableKey : public StringTableKey {
17004  public:
TwoCharHashTableKey(uint16_t c1,uint16_t c2,uint64_t seed)17005   TwoCharHashTableKey(uint16_t c1, uint16_t c2, uint64_t seed)
17006       : StringTableKey(ComputeHashField(c1, c2, seed)), c1_(c1), c2_(c2) {}
17007 
IsMatch(Object * o)17008   bool IsMatch(Object* o) override {
17009     String* other = String::cast(o);
17010     if (other->length() != 2) return false;
17011     if (other->Get(0) != c1_) return false;
17012     return other->Get(1) == c2_;
17013   }
17014 
AsHandle(Isolate * isolate)17015   Handle<String> AsHandle(Isolate* isolate) override {
17016     // The TwoCharHashTableKey is only used for looking in the string
17017     // table, not for adding to it.
17018     UNREACHABLE();
17019   }
17020 
17021  private:
ComputeHashField(uint16_t c1,uint16_t c2,uint64_t seed)17022   uint32_t ComputeHashField(uint16_t c1, uint16_t c2, uint64_t seed) {
17023     // Char 1.
17024     uint32_t hash = static_cast<uint32_t>(seed);
17025     hash += c1;
17026     hash += hash << 10;
17027     hash ^= hash >> 6;
17028     // Char 2.
17029     hash += c2;
17030     hash += hash << 10;
17031     hash ^= hash >> 6;
17032     // GetHash.
17033     hash += hash << 3;
17034     hash ^= hash >> 11;
17035     hash += hash << 15;
17036     if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash;
17037     hash = (hash << String::kHashShift) | String::kIsNotArrayIndexMask;
17038 #ifdef DEBUG
17039     // If this assert fails then we failed to reproduce the two-character
17040     // version of the string hashing algorithm above.  One reason could be
17041     // that we were passed two digits as characters, since the hash
17042     // algorithm is different in that case.
17043     uint16_t chars[2] = {c1, c2};
17044     uint32_t check_hash = StringHasher::HashSequentialString(chars, 2, seed);
17045     DCHECK_EQ(hash, check_hash);
17046 #endif
17047     return hash;
17048   }
17049 
17050   uint16_t c1_;
17051   uint16_t c2_;
17052 };
17053 
LookupTwoCharsStringIfExists(Isolate * isolate,uint16_t c1,uint16_t c2)17054 MaybeHandle<String> StringTable::LookupTwoCharsStringIfExists(
17055     Isolate* isolate,
17056     uint16_t c1,
17057     uint16_t c2) {
17058   TwoCharHashTableKey key(c1, c2, isolate->heap()->HashSeed());
17059   Handle<StringTable> string_table = isolate->factory()->string_table();
17060   int entry = string_table->FindEntry(isolate, &key);
17061   if (entry == kNotFound) return MaybeHandle<String>();
17062 
17063   Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
17064   DCHECK(StringShape(*result).IsInternalized());
17065   DCHECK_EQ(result->Hash(), key.Hash());
17066   return result;
17067 }
17068 
EnsureCapacityForDeserialization(Isolate * isolate,int expected)17069 void StringTable::EnsureCapacityForDeserialization(Isolate* isolate,
17070                                                    int expected) {
17071   Handle<StringTable> table = isolate->factory()->string_table();
17072   // We need a key instance for the virtual hash function.
17073   table = StringTable::EnsureCapacity(isolate, table, expected);
17074   isolate->heap()->SetRootStringTable(*table);
17075 }
17076 
17077 namespace {
17078 
17079 template <class StringClass>
MigrateExternalStringResource(Isolate * isolate,String * from,String * to)17080 void MigrateExternalStringResource(Isolate* isolate, String* from, String* to) {
17081   StringClass* cast_from = StringClass::cast(from);
17082   StringClass* cast_to = StringClass::cast(to);
17083   const typename StringClass::Resource* to_resource = cast_to->resource();
17084   if (to_resource == nullptr) {
17085     // |to| is a just-created internalized copy of |from|. Migrate the resource.
17086     cast_to->SetResource(isolate, cast_from->resource());
17087     // Zap |from|'s resource pointer to reflect the fact that |from| has
17088     // relinquished ownership of its resource.
17089     isolate->heap()->UpdateExternalString(
17090         from, ExternalString::cast(from)->ExternalPayloadSize(), 0);
17091     cast_from->SetResource(isolate, nullptr);
17092   } else if (to_resource != cast_from->resource()) {
17093     // |to| already existed and has its own resource. Finalize |from|.
17094     isolate->heap()->FinalizeExternalString(from);
17095   }
17096 }
17097 
MakeStringThin(String * string,String * internalized,Isolate * isolate)17098 void MakeStringThin(String* string, String* internalized, Isolate* isolate) {
17099   DCHECK_NE(string, internalized);
17100   DCHECK(internalized->IsInternalizedString());
17101 
17102   if (string->IsExternalString()) {
17103     if (internalized->IsExternalOneByteString()) {
17104       MigrateExternalStringResource<ExternalOneByteString>(isolate, string,
17105                                                            internalized);
17106     } else if (internalized->IsExternalTwoByteString()) {
17107       MigrateExternalStringResource<ExternalTwoByteString>(isolate, string,
17108                                                            internalized);
17109     } else {
17110       // If the external string is duped into an existing non-external
17111       // internalized string, free its resource (it's about to be rewritten
17112       // into a ThinString below).
17113       isolate->heap()->FinalizeExternalString(string);
17114     }
17115   }
17116 
17117   DisallowHeapAllocation no_gc;
17118   int old_size = string->Size();
17119   isolate->heap()->NotifyObjectLayoutChange(string, old_size, no_gc);
17120   bool one_byte = internalized->IsOneByteRepresentation();
17121   Handle<Map> map = one_byte ? isolate->factory()->thin_one_byte_string_map()
17122                              : isolate->factory()->thin_string_map();
17123   DCHECK_GE(old_size, ThinString::kSize);
17124   string->synchronized_set_map(*map);
17125   ThinString* thin = ThinString::cast(string);
17126   thin->set_actual(internalized);
17127   Address thin_end = thin->address() + ThinString::kSize;
17128   int size_delta = old_size - ThinString::kSize;
17129   if (size_delta != 0) {
17130     Heap* heap = isolate->heap();
17131     heap->CreateFillerObjectAt(thin_end, size_delta, ClearRecordedSlots::kNo);
17132   }
17133 }
17134 
17135 }  // namespace
17136 
17137 // static
LookupString(Isolate * isolate,Handle<String> string)17138 Handle<String> StringTable::LookupString(Isolate* isolate,
17139                                          Handle<String> string) {
17140   string = String::Flatten(isolate, string);
17141   if (string->IsInternalizedString()) return string;
17142 
17143   InternalizedStringKey key(string);
17144   Handle<String> result = LookupKey(isolate, &key);
17145 
17146   if (FLAG_thin_strings) {
17147     if (!string->IsInternalizedString()) {
17148       MakeStringThin(*string, *result, isolate);
17149     }
17150   } else {  // !FLAG_thin_strings
17151     if (string->IsConsString()) {
17152       Handle<ConsString> cons = Handle<ConsString>::cast(string);
17153       cons->set_first(isolate, *result);
17154       cons->set_second(isolate, ReadOnlyRoots(isolate).empty_string());
17155     } else if (string->IsSlicedString()) {
17156       STATIC_ASSERT(ConsString::kSize == SlicedString::kSize);
17157       DisallowHeapAllocation no_gc;
17158       bool one_byte = result->IsOneByteRepresentation();
17159       Handle<Map> map = one_byte
17160                             ? isolate->factory()->cons_one_byte_string_map()
17161                             : isolate->factory()->cons_string_map();
17162       string->set_map(*map);
17163       Handle<ConsString> cons = Handle<ConsString>::cast(string);
17164       cons->set_first(isolate, *result);
17165       cons->set_second(isolate, ReadOnlyRoots(isolate).empty_string());
17166     }
17167   }
17168   return result;
17169 }
17170 
17171 // static
LookupKey(Isolate * isolate,StringTableKey * key)17172 Handle<String> StringTable::LookupKey(Isolate* isolate, StringTableKey* key) {
17173   Handle<StringTable> table = isolate->factory()->string_table();
17174   int entry = table->FindEntry(isolate, key);
17175 
17176   // String already in table.
17177   if (entry != kNotFound) {
17178     return handle(String::cast(table->KeyAt(entry)), isolate);
17179   }
17180 
17181   table = StringTable::CautiousShrink(isolate, table);
17182   // Adding new string. Grow table if needed.
17183   table = StringTable::EnsureCapacity(isolate, table, 1);
17184   isolate->heap()->SetRootStringTable(*table);
17185 
17186   return AddKeyNoResize(isolate, key);
17187 }
17188 
AddKeyNoResize(Isolate * isolate,StringTableKey * key)17189 Handle<String> StringTable::AddKeyNoResize(Isolate* isolate,
17190                                            StringTableKey* key) {
17191   Handle<StringTable> table = isolate->factory()->string_table();
17192   DCHECK(table->HasSufficientCapacityToAdd(1));
17193   // Create string object.
17194   Handle<String> string = key->AsHandle(isolate);
17195   // There must be no attempts to internalize strings that could throw
17196   // InvalidStringLength error.
17197   CHECK(!string.is_null());
17198   DCHECK(string->HasHashCode());
17199   DCHECK_EQ(table->FindEntry(isolate, key), kNotFound);
17200 
17201   // Add the new string and return it along with the string table.
17202   int entry = table->FindInsertionEntry(key->Hash());
17203   table->set(EntryToIndex(entry), *string);
17204   table->ElementAdded();
17205 
17206   return Handle<String>::cast(string);
17207 }
17208 
CautiousShrink(Isolate * isolate,Handle<StringTable> table)17209 Handle<StringTable> StringTable::CautiousShrink(Isolate* isolate,
17210                                                 Handle<StringTable> table) {
17211   // Only shrink if the table is very empty to avoid performance penalty.
17212   int capacity = table->Capacity();
17213   int nof = table->NumberOfElements();
17214   if (capacity <= StringTable::kMinCapacity) return table;
17215   if (nof > (capacity / kMaxEmptyFactor)) return table;
17216   // Keep capacity for at least half of the current nof elements.
17217   int slack_capacity = nof >> 2;
17218   return Shrink(isolate, table, slack_capacity);
17219 }
17220 
17221 namespace {
17222 
17223 class StringTableNoAllocateKey : public StringTableKey {
17224  public:
StringTableNoAllocateKey(String * string,uint64_t seed)17225   StringTableNoAllocateKey(String* string, uint64_t seed)
17226       : StringTableKey(0), string_(string) {
17227     StringShape shape(string);
17228     one_byte_ = shape.HasOnlyOneByteChars();
17229     DCHECK(!shape.IsInternalized());
17230     DCHECK(!shape.IsThin());
17231     int length = string->length();
17232     if (shape.IsCons() && length <= String::kMaxHashCalcLength) {
17233       special_flattening_ = true;
17234       uint32_t hash_field = 0;
17235       if (one_byte_) {
17236         if (V8_LIKELY(length <=
17237                       static_cast<int>(arraysize(one_byte_buffer_)))) {
17238           one_byte_content_ = one_byte_buffer_;
17239         } else {
17240           one_byte_content_ = new uint8_t[length];
17241         }
17242         String::WriteToFlat(string, one_byte_content_, 0, length);
17243         hash_field =
17244             StringHasher::HashSequentialString(one_byte_content_, length, seed);
17245       } else {
17246         if (V8_LIKELY(length <=
17247                       static_cast<int>(arraysize(two_byte_buffer_)))) {
17248           two_byte_content_ = two_byte_buffer_;
17249         } else {
17250           two_byte_content_ = new uint16_t[length];
17251         }
17252         String::WriteToFlat(string, two_byte_content_, 0, length);
17253         hash_field =
17254             StringHasher::HashSequentialString(two_byte_content_, length, seed);
17255       }
17256       string->set_hash_field(hash_field);
17257     } else {
17258       special_flattening_ = false;
17259       one_byte_content_ = nullptr;
17260       string->Hash();
17261     }
17262 
17263     DCHECK(string->HasHashCode());
17264     set_hash_field(string->hash_field());
17265   }
17266 
~StringTableNoAllocateKey()17267   ~StringTableNoAllocateKey() {
17268     if (one_byte_) {
17269       if (one_byte_content_ != one_byte_buffer_) delete[] one_byte_content_;
17270     } else {
17271       if (two_byte_content_ != two_byte_buffer_) delete[] two_byte_content_;
17272     }
17273   }
17274 
IsMatch(Object * otherstring)17275   bool IsMatch(Object* otherstring) override {
17276     String* other = String::cast(otherstring);
17277     DCHECK(other->IsInternalizedString());
17278     DCHECK(other->IsFlat());
17279     if (Hash() != other->Hash()) return false;
17280     int len = string_->length();
17281     if (len != other->length()) return false;
17282 
17283     if (!special_flattening_) {
17284       if (string_->Get(0) != other->Get(0)) return false;
17285       if (string_->IsFlat()) {
17286         StringShape shape1(string_);
17287         StringShape shape2(other);
17288         if (shape1.encoding_tag() == kOneByteStringTag &&
17289             shape2.encoding_tag() == kOneByteStringTag) {
17290           String::FlatContent flat1 = string_->GetFlatContent();
17291           String::FlatContent flat2 = other->GetFlatContent();
17292           return CompareRawStringContents(flat1.ToOneByteVector().start(),
17293                                           flat2.ToOneByteVector().start(), len);
17294         }
17295         if (shape1.encoding_tag() == kTwoByteStringTag &&
17296             shape2.encoding_tag() == kTwoByteStringTag) {
17297           String::FlatContent flat1 = string_->GetFlatContent();
17298           String::FlatContent flat2 = other->GetFlatContent();
17299           return CompareRawStringContents(flat1.ToUC16Vector().start(),
17300                                           flat2.ToUC16Vector().start(), len);
17301         }
17302       }
17303       StringComparator comparator;
17304       return comparator.Equals(string_, other);
17305     }
17306 
17307     String::FlatContent flat_content = other->GetFlatContent();
17308     if (one_byte_) {
17309       if (flat_content.IsOneByte()) {
17310         return CompareRawStringContents(
17311             one_byte_content_, flat_content.ToOneByteVector().start(), len);
17312       } else {
17313         DCHECK(flat_content.IsTwoByte());
17314         for (int i = 0; i < len; i++) {
17315           if (flat_content.Get(i) != one_byte_content_[i]) return false;
17316         }
17317         return true;
17318       }
17319     } else {
17320       if (flat_content.IsTwoByte()) {
17321         return CompareRawStringContents(
17322             two_byte_content_, flat_content.ToUC16Vector().start(), len);
17323       } else {
17324         DCHECK(flat_content.IsOneByte());
17325         for (int i = 0; i < len; i++) {
17326           if (flat_content.Get(i) != two_byte_content_[i]) return false;
17327         }
17328         return true;
17329       }
17330     }
17331   }
17332 
AsHandle(Isolate * isolate)17333   V8_WARN_UNUSED_RESULT Handle<String> AsHandle(Isolate* isolate) override {
17334     UNREACHABLE();
17335   }
17336 
17337  private:
17338   String* string_;
17339   bool one_byte_;
17340   bool special_flattening_;
17341   union {
17342     uint8_t* one_byte_content_;
17343     uint16_t* two_byte_content_;
17344   };
17345   union {
17346     uint8_t one_byte_buffer_[256];
17347     uint16_t two_byte_buffer_[128];
17348   };
17349 };
17350 
17351 }  // namespace
17352 
17353 // static
LookupStringIfExists_NoAllocate(Isolate * isolate,String * string)17354 Object* StringTable::LookupStringIfExists_NoAllocate(Isolate* isolate,
17355                                                      String* string) {
17356   DisallowHeapAllocation no_gc;
17357   Heap* heap = isolate->heap();
17358   StringTable* table = heap->string_table();
17359 
17360   StringTableNoAllocateKey key(string, heap->HashSeed());
17361 
17362   // String could be an array index.
17363   uint32_t hash = string->hash_field();
17364 
17365   // Valid array indices are >= 0, so they cannot be mixed up with any of
17366   // the result sentinels, which are negative.
17367   STATIC_ASSERT(
17368       !String::ArrayIndexValueBits::is_valid(ResultSentinel::kUnsupported));
17369   STATIC_ASSERT(
17370       !String::ArrayIndexValueBits::is_valid(ResultSentinel::kNotFound));
17371 
17372   if (Name::ContainsCachedArrayIndex(hash)) {
17373     return Smi::FromInt(String::ArrayIndexValueBits::decode(hash));
17374   }
17375   if ((hash & Name::kIsNotArrayIndexMask) == 0) {
17376     // It is an indexed, but it's not cached.
17377     return Smi::FromInt(ResultSentinel::kUnsupported);
17378   }
17379 
17380   DCHECK(!string->IsInternalizedString());
17381   int entry = table->FindEntry(ReadOnlyRoots(isolate), &key, key.Hash());
17382   if (entry != kNotFound) {
17383     String* internalized = String::cast(table->KeyAt(entry));
17384     if (FLAG_thin_strings) {
17385       MakeStringThin(string, internalized, isolate);
17386     }
17387     return internalized;
17388   }
17389   // A string that's not an array index, and not in the string table,
17390   // cannot have been used as a property name before.
17391   return Smi::FromInt(ResultSentinel::kNotFound);
17392 }
17393 
ForwardStringIfExists(Isolate * isolate,StringTableKey * key,String * string)17394 String* StringTable::ForwardStringIfExists(Isolate* isolate,
17395                                            StringTableKey* key,
17396                                            String* string) {
17397   Handle<StringTable> table = isolate->factory()->string_table();
17398   int entry = table->FindEntry(isolate, key);
17399   if (entry == kNotFound) return nullptr;
17400 
17401   String* canonical = String::cast(table->KeyAt(entry));
17402   if (canonical != string) MakeStringThin(string, canonical, isolate);
17403   return canonical;
17404 }
17405 
New(Isolate * isolate)17406 Handle<StringSet> StringSet::New(Isolate* isolate) {
17407   return HashTable::New(isolate, 0);
17408 }
17409 
Add(Isolate * isolate,Handle<StringSet> stringset,Handle<String> name)17410 Handle<StringSet> StringSet::Add(Isolate* isolate, Handle<StringSet> stringset,
17411                                  Handle<String> name) {
17412   if (!stringset->Has(isolate, name)) {
17413     stringset = EnsureCapacity(isolate, stringset, 1);
17414     uint32_t hash = ShapeT::Hash(isolate, *name);
17415     int entry = stringset->FindInsertionEntry(hash);
17416     stringset->set(EntryToIndex(entry), *name);
17417     stringset->ElementAdded();
17418   }
17419   return stringset;
17420 }
17421 
Has(Isolate * isolate,Handle<String> name)17422 bool StringSet::Has(Isolate* isolate, Handle<String> name) {
17423   return FindEntry(isolate, *name) != kNotFound;
17424 }
17425 
Add(Isolate * isolate,Handle<ObjectHashSet> set,Handle<Object> key)17426 Handle<ObjectHashSet> ObjectHashSet::Add(Isolate* isolate,
17427                                          Handle<ObjectHashSet> set,
17428                                          Handle<Object> key) {
17429   int32_t hash = key->GetOrCreateHash(isolate)->value();
17430   if (!set->Has(isolate, key, hash)) {
17431     set = EnsureCapacity(isolate, set, 1);
17432     int entry = set->FindInsertionEntry(hash);
17433     set->set(EntryToIndex(entry), *key);
17434     set->ElementAdded();
17435   }
17436   return set;
17437 }
17438 
Lookup(Handle<String> src,Handle<SharedFunctionInfo> shared,LanguageMode language_mode)17439 Handle<Object> CompilationCacheTable::Lookup(Handle<String> src,
17440                                              Handle<SharedFunctionInfo> shared,
17441                                              LanguageMode language_mode) {
17442   Isolate* isolate = GetIsolate();
17443   StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17444   int entry = FindEntry(isolate, &key);
17445   if (entry == kNotFound) return isolate->factory()->undefined_value();
17446   int index = EntryToIndex(entry);
17447   if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value();
17448   return Handle<Object>(get(index + 1), isolate);
17449 }
17450 
17451 namespace {
17452 
17453 const int kLiteralEntryLength = 2;
17454 const int kLiteralInitialLength = 2;
17455 const int kLiteralContextOffset = 0;
17456 const int kLiteralLiteralsOffset = 1;
17457 
SearchLiteralsMapEntry(CompilationCacheTable * cache,int cache_entry,Context * native_context)17458 int SearchLiteralsMapEntry(CompilationCacheTable* cache, int cache_entry,
17459                            Context* native_context) {
17460   DisallowHeapAllocation no_gc;
17461   DCHECK(native_context->IsNativeContext());
17462   Object* obj = cache->get(cache_entry);
17463 
17464   // Check that there's no confusion between FixedArray and WeakFixedArray (the
17465   // object used to be a FixedArray here).
17466   DCHECK(!obj->IsFixedArray());
17467   if (obj->IsWeakFixedArray()) {
17468     WeakFixedArray* literals_map = WeakFixedArray::cast(obj);
17469     int length = literals_map->length();
17470     for (int i = 0; i < length; i += kLiteralEntryLength) {
17471       DCHECK(literals_map->Get(i + kLiteralContextOffset)
17472                  ->IsWeakOrClearedHeapObject());
17473       if (literals_map->Get(i + kLiteralContextOffset) ==
17474           HeapObjectReference::Weak(native_context)) {
17475         return i;
17476       }
17477     }
17478   }
17479   return -1;
17480 }
17481 
AddToFeedbackCellsMap(Handle<CompilationCacheTable> cache,int cache_entry,Handle<Context> native_context,Handle<FeedbackCell> feedback_cell)17482 void AddToFeedbackCellsMap(Handle<CompilationCacheTable> cache, int cache_entry,
17483                            Handle<Context> native_context,
17484                            Handle<FeedbackCell> feedback_cell) {
17485   Isolate* isolate = native_context->GetIsolate();
17486   DCHECK(native_context->IsNativeContext());
17487   STATIC_ASSERT(kLiteralEntryLength == 2);
17488   Handle<WeakFixedArray> new_literals_map;
17489   int entry;
17490 
17491   Object* obj = cache->get(cache_entry);
17492 
17493   // Check that there's no confusion between FixedArray and WeakFixedArray (the
17494   // object used to be a FixedArray here).
17495   DCHECK(!obj->IsFixedArray());
17496   if (!obj->IsWeakFixedArray() || WeakFixedArray::cast(obj)->length() == 0) {
17497     new_literals_map =
17498         isolate->factory()->NewWeakFixedArray(kLiteralInitialLength, TENURED);
17499     entry = 0;
17500   } else {
17501     Handle<WeakFixedArray> old_literals_map(WeakFixedArray::cast(obj), isolate);
17502     entry = SearchLiteralsMapEntry(*cache, cache_entry, *native_context);
17503     if (entry >= 0) {
17504       // Just set the code of the entry.
17505       old_literals_map->Set(entry + kLiteralLiteralsOffset,
17506                             HeapObjectReference::Weak(*feedback_cell));
17507       return;
17508     }
17509 
17510     // Can we reuse an entry?
17511     DCHECK_LT(entry, 0);
17512     int length = old_literals_map->length();
17513     for (int i = 0; i < length; i += kLiteralEntryLength) {
17514       if (old_literals_map->Get(i + kLiteralContextOffset)
17515               ->IsClearedWeakHeapObject()) {
17516         new_literals_map = old_literals_map;
17517         entry = i;
17518         break;
17519       }
17520     }
17521 
17522     if (entry < 0) {
17523       // Copy old optimized code map and append one new entry.
17524       new_literals_map = isolate->factory()->CopyWeakFixedArrayAndGrow(
17525           old_literals_map, kLiteralEntryLength, TENURED);
17526       entry = old_literals_map->length();
17527     }
17528   }
17529 
17530   new_literals_map->Set(entry + kLiteralContextOffset,
17531                         HeapObjectReference::Weak(*native_context));
17532   new_literals_map->Set(entry + kLiteralLiteralsOffset,
17533                         HeapObjectReference::Weak(*feedback_cell));
17534 
17535 #ifdef DEBUG
17536   for (int i = 0; i < new_literals_map->length(); i += kLiteralEntryLength) {
17537     MaybeObject* object = new_literals_map->Get(i + kLiteralContextOffset);
17538     DCHECK(object->IsClearedWeakHeapObject() ||
17539            object->ToWeakHeapObject()->IsNativeContext());
17540     object = new_literals_map->Get(i + kLiteralLiteralsOffset);
17541     DCHECK(object->IsClearedWeakHeapObject() ||
17542            object->ToWeakHeapObject()->IsFeedbackCell());
17543   }
17544 #endif
17545 
17546   Object* old_literals_map = cache->get(cache_entry);
17547   if (old_literals_map != *new_literals_map) {
17548     cache->set(cache_entry, *new_literals_map);
17549   }
17550 }
17551 
SearchLiteralsMap(CompilationCacheTable * cache,int cache_entry,Context * native_context)17552 FeedbackCell* SearchLiteralsMap(CompilationCacheTable* cache, int cache_entry,
17553                                 Context* native_context) {
17554   FeedbackCell* result = nullptr;
17555   int entry = SearchLiteralsMapEntry(cache, cache_entry, native_context);
17556   if (entry >= 0) {
17557     WeakFixedArray* literals_map =
17558         WeakFixedArray::cast(cache->get(cache_entry));
17559     DCHECK_LE(entry + kLiteralEntryLength, literals_map->length());
17560     MaybeObject* object = literals_map->Get(entry + kLiteralLiteralsOffset);
17561 
17562     result = object->IsClearedWeakHeapObject()
17563                  ? nullptr
17564                  : FeedbackCell::cast(object->ToWeakHeapObject());
17565   }
17566   DCHECK(result == nullptr || result->IsFeedbackCell());
17567   return result;
17568 }
17569 
17570 }  // namespace
17571 
LookupScript(Handle<String> src,Handle<Context> native_context,LanguageMode language_mode)17572 MaybeHandle<SharedFunctionInfo> CompilationCacheTable::LookupScript(
17573     Handle<String> src, Handle<Context> native_context,
17574     LanguageMode language_mode) {
17575   // We use the empty function SFI as part of the key. Although the
17576   // empty_function is native context dependent, the SFI is de-duped on
17577   // snapshot builds by the PartialSnapshotCache, and so this does not prevent
17578   // reuse of scripts in the compilation cache across native contexts.
17579   Handle<SharedFunctionInfo> shared(native_context->empty_function()->shared(),
17580                                     native_context->GetIsolate());
17581   StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17582   int entry = FindEntry(GetIsolate(), &key);
17583   if (entry == kNotFound) return MaybeHandle<SharedFunctionInfo>();
17584   int index = EntryToIndex(entry);
17585   if (!get(index)->IsFixedArray()) return MaybeHandle<SharedFunctionInfo>();
17586   Object* obj = get(index + 1);
17587   if (obj->IsSharedFunctionInfo()) {
17588     return handle(SharedFunctionInfo::cast(obj), native_context->GetIsolate());
17589   }
17590   return MaybeHandle<SharedFunctionInfo>();
17591 }
17592 
LookupEval(Handle<String> src,Handle<SharedFunctionInfo> outer_info,Handle<Context> native_context,LanguageMode language_mode,int position)17593 InfoCellPair CompilationCacheTable::LookupEval(
17594     Handle<String> src, Handle<SharedFunctionInfo> outer_info,
17595     Handle<Context> native_context, LanguageMode language_mode, int position) {
17596   InfoCellPair empty_result;
17597   StringSharedKey key(src, outer_info, language_mode, position);
17598   int entry = FindEntry(GetIsolate(), &key);
17599   if (entry == kNotFound) return empty_result;
17600   int index = EntryToIndex(entry);
17601   if (!get(index)->IsFixedArray()) return empty_result;
17602   Object* obj = get(EntryToIndex(entry) + 1);
17603   if (obj->IsSharedFunctionInfo()) {
17604     FeedbackCell* feedback_cell =
17605         SearchLiteralsMap(this, EntryToIndex(entry) + 2, *native_context);
17606     return InfoCellPair(SharedFunctionInfo::cast(obj), feedback_cell);
17607   }
17608   return empty_result;
17609 }
17610 
LookupRegExp(Handle<String> src,JSRegExp::Flags flags)17611 Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src,
17612                                                    JSRegExp::Flags flags) {
17613   Isolate* isolate = GetIsolate();
17614   DisallowHeapAllocation no_allocation;
17615   RegExpKey key(src, flags);
17616   int entry = FindEntry(isolate, &key);
17617   if (entry == kNotFound) return isolate->factory()->undefined_value();
17618   return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
17619 }
17620 
Put(Handle<CompilationCacheTable> cache,Handle<String> src,Handle<SharedFunctionInfo> shared,LanguageMode language_mode,Handle<Object> value)17621 Handle<CompilationCacheTable> CompilationCacheTable::Put(
17622     Handle<CompilationCacheTable> cache, Handle<String> src,
17623     Handle<SharedFunctionInfo> shared, LanguageMode language_mode,
17624     Handle<Object> value) {
17625   Isolate* isolate = cache->GetIsolate();
17626   StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17627   Handle<Object> k = key.AsHandle(isolate);
17628   cache = EnsureCapacity(isolate, cache, 1);
17629   int entry = cache->FindInsertionEntry(key.Hash());
17630   cache->set(EntryToIndex(entry), *k);
17631   cache->set(EntryToIndex(entry) + 1, *value);
17632   cache->ElementAdded();
17633   return cache;
17634 }
17635 
PutScript(Handle<CompilationCacheTable> cache,Handle<String> src,Handle<Context> native_context,LanguageMode language_mode,Handle<SharedFunctionInfo> value)17636 Handle<CompilationCacheTable> CompilationCacheTable::PutScript(
17637     Handle<CompilationCacheTable> cache, Handle<String> src,
17638     Handle<Context> native_context, LanguageMode language_mode,
17639     Handle<SharedFunctionInfo> value) {
17640   Isolate* isolate = native_context->GetIsolate();
17641   // We use the empty function SFI as part of the key. Although the
17642   // empty_function is native context dependent, the SFI is de-duped on
17643   // snapshot builds by the PartialSnapshotCache, and so this does not prevent
17644   // reuse of scripts in the compilation cache across native contexts.
17645   Handle<SharedFunctionInfo> shared(native_context->empty_function()->shared(),
17646                                     isolate);
17647   StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17648   Handle<Object> k = key.AsHandle(isolate);
17649   cache = EnsureCapacity(isolate, cache, 1);
17650   int entry = cache->FindInsertionEntry(key.Hash());
17651   cache->set(EntryToIndex(entry), *k);
17652   cache->set(EntryToIndex(entry) + 1, *value);
17653   cache->ElementAdded();
17654   return cache;
17655 }
17656 
PutEval(Handle<CompilationCacheTable> cache,Handle<String> src,Handle<SharedFunctionInfo> outer_info,Handle<SharedFunctionInfo> value,Handle<Context> native_context,Handle<FeedbackCell> feedback_cell,int position)17657 Handle<CompilationCacheTable> CompilationCacheTable::PutEval(
17658     Handle<CompilationCacheTable> cache, Handle<String> src,
17659     Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value,
17660     Handle<Context> native_context, Handle<FeedbackCell> feedback_cell,
17661     int position) {
17662   Isolate* isolate = native_context->GetIsolate();
17663   StringSharedKey key(src, outer_info, value->language_mode(), position);
17664   {
17665     Handle<Object> k = key.AsHandle(isolate);
17666     int entry = cache->FindEntry(isolate, &key);
17667     if (entry != kNotFound) {
17668       cache->set(EntryToIndex(entry), *k);
17669       cache->set(EntryToIndex(entry) + 1, *value);
17670       // AddToFeedbackCellsMap may allocate a new sub-array to live in the
17671       // entry, but it won't change the cache array. Therefore EntryToIndex
17672       // and entry remains correct.
17673       AddToFeedbackCellsMap(cache, EntryToIndex(entry) + 2, native_context,
17674                             feedback_cell);
17675       return cache;
17676     }
17677   }
17678 
17679   cache = EnsureCapacity(isolate, cache, 1);
17680   int entry = cache->FindInsertionEntry(key.Hash());
17681   Handle<Object> k =
17682       isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
17683   cache->set(EntryToIndex(entry), *k);
17684   cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
17685   cache->ElementAdded();
17686   return cache;
17687 }
17688 
PutRegExp(Isolate * isolate,Handle<CompilationCacheTable> cache,Handle<String> src,JSRegExp::Flags flags,Handle<FixedArray> value)17689 Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp(
17690     Isolate* isolate, Handle<CompilationCacheTable> cache, Handle<String> src,
17691     JSRegExp::Flags flags, Handle<FixedArray> value) {
17692   RegExpKey key(src, flags);
17693   cache = EnsureCapacity(isolate, cache, 1);
17694   int entry = cache->FindInsertionEntry(key.Hash());
17695   // We store the value in the key slot, and compare the search key
17696   // to the stored value with a custon IsMatch function during lookups.
17697   cache->set(EntryToIndex(entry), *value);
17698   cache->set(EntryToIndex(entry) + 1, *value);
17699   cache->ElementAdded();
17700   return cache;
17701 }
17702 
17703 
Age()17704 void CompilationCacheTable::Age() {
17705   DisallowHeapAllocation no_allocation;
17706   Object* the_hole_value = GetReadOnlyRoots().the_hole_value();
17707   for (int entry = 0, size = Capacity(); entry < size; entry++) {
17708     int entry_index = EntryToIndex(entry);
17709     int value_index = entry_index + 1;
17710 
17711     if (get(entry_index)->IsNumber()) {
17712       Smi* count = Smi::cast(get(value_index));
17713       count = Smi::FromInt(count->value() - 1);
17714       if (count->value() == 0) {
17715         NoWriteBarrierSet(this, entry_index, the_hole_value);
17716         NoWriteBarrierSet(this, value_index, the_hole_value);
17717         ElementRemoved();
17718       } else {
17719         NoWriteBarrierSet(this, value_index, count);
17720       }
17721     } else if (get(entry_index)->IsFixedArray()) {
17722       SharedFunctionInfo* info = SharedFunctionInfo::cast(get(value_index));
17723       if (info->IsInterpreted() && info->GetBytecodeArray()->IsOld()) {
17724         for (int i = 0; i < kEntrySize; i++) {
17725           NoWriteBarrierSet(this, entry_index + i, the_hole_value);
17726         }
17727         ElementRemoved();
17728       }
17729     }
17730   }
17731 }
17732 
17733 
Remove(Object * value)17734 void CompilationCacheTable::Remove(Object* value) {
17735   DisallowHeapAllocation no_allocation;
17736   Object* the_hole_value = GetReadOnlyRoots().the_hole_value();
17737   for (int entry = 0, size = Capacity(); entry < size; entry++) {
17738     int entry_index = EntryToIndex(entry);
17739     int value_index = entry_index + 1;
17740     if (get(value_index) == value) {
17741       for (int i = 0; i < kEntrySize; i++) {
17742         NoWriteBarrierSet(this, entry_index + i, the_hole_value);
17743       }
17744       ElementRemoved();
17745     }
17746   }
17747   return;
17748 }
17749 
17750 template <typename Derived, typename Shape>
New(Isolate * isolate,int at_least_space_for,PretenureFlag pretenure,MinimumCapacity capacity_option)17751 Handle<Derived> BaseNameDictionary<Derived, Shape>::New(
17752     Isolate* isolate, int at_least_space_for, PretenureFlag pretenure,
17753     MinimumCapacity capacity_option) {
17754   DCHECK_LE(0, at_least_space_for);
17755   Handle<Derived> dict = Dictionary<Derived, Shape>::New(
17756       isolate, at_least_space_for, pretenure, capacity_option);
17757   dict->SetHash(PropertyArray::kNoHashSentinel);
17758   dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
17759   return dict;
17760 }
17761 
17762 template <typename Derived, typename Shape>
EnsureCapacity(Isolate * isolate,Handle<Derived> dictionary,int n)17763 Handle<Derived> BaseNameDictionary<Derived, Shape>::EnsureCapacity(
17764     Isolate* isolate, Handle<Derived> dictionary, int n) {
17765   // Check whether there are enough enumeration indices to add n elements.
17766   if (!PropertyDetails::IsValidIndex(dictionary->NextEnumerationIndex() + n)) {
17767     // If not, we generate new indices for the properties.
17768     int length = dictionary->NumberOfElements();
17769 
17770     Handle<FixedArray> iteration_order = IterationIndices(isolate, dictionary);
17771     DCHECK_EQ(length, iteration_order->length());
17772 
17773     // Iterate over the dictionary using the enumeration order and update
17774     // the dictionary with new enumeration indices.
17775     for (int i = 0; i < length; i++) {
17776       int index = Smi::ToInt(iteration_order->get(i));
17777       DCHECK(dictionary->IsKey(dictionary->GetReadOnlyRoots(),
17778                                dictionary->KeyAt(index)));
17779 
17780       int enum_index = PropertyDetails::kInitialIndex + i;
17781 
17782       PropertyDetails details = dictionary->DetailsAt(index);
17783       PropertyDetails new_details = details.set_index(enum_index);
17784       dictionary->DetailsAtPut(isolate, index, new_details);
17785     }
17786 
17787     // Set the next enumeration index.
17788     dictionary->SetNextEnumerationIndex(PropertyDetails::kInitialIndex +
17789                                         length);
17790   }
17791   return HashTable<Derived, Shape>::EnsureCapacity(isolate, dictionary, n);
17792 }
17793 
17794 template <typename Derived, typename Shape>
DeleteEntry(Isolate * isolate,Handle<Derived> dictionary,int entry)17795 Handle<Derived> Dictionary<Derived, Shape>::DeleteEntry(
17796     Isolate* isolate, Handle<Derived> dictionary, int entry) {
17797   DCHECK(Shape::kEntrySize != 3 ||
17798          dictionary->DetailsAt(entry).IsConfigurable());
17799   dictionary->ClearEntry(isolate, entry);
17800   dictionary->ElementRemoved();
17801   return Shrink(isolate, dictionary);
17802 }
17803 
17804 template <typename Derived, typename Shape>
AtPut(Isolate * isolate,Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details)17805 Handle<Derived> Dictionary<Derived, Shape>::AtPut(Isolate* isolate,
17806                                                   Handle<Derived> dictionary,
17807                                                   Key key, Handle<Object> value,
17808                                                   PropertyDetails details) {
17809   int entry = dictionary->FindEntry(isolate, key);
17810 
17811   // If the entry is present set the value;
17812   if (entry == Dictionary::kNotFound) {
17813     return Derived::Add(isolate, dictionary, key, value, details);
17814   }
17815 
17816   // We don't need to copy over the enumeration index.
17817   dictionary->ValueAtPut(entry, *value);
17818   if (Shape::kEntrySize == 3) dictionary->DetailsAtPut(isolate, entry, details);
17819   return dictionary;
17820 }
17821 
17822 template <typename Derived, typename Shape>
17823 Handle<Derived>
AddNoUpdateNextEnumerationIndex(Isolate * isolate,Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details,int * entry_out)17824 BaseNameDictionary<Derived, Shape>::AddNoUpdateNextEnumerationIndex(
17825     Isolate* isolate, Handle<Derived> dictionary, Key key, Handle<Object> value,
17826     PropertyDetails details, int* entry_out) {
17827   // Insert element at empty or deleted entry
17828   return Dictionary<Derived, Shape>::Add(isolate, dictionary, key, value,
17829                                          details, entry_out);
17830 }
17831 
17832 // GCC workaround: Explicitly instantiate template method for NameDictionary
17833 // to avoid "undefined reference" issues during linking.
17834 template Handle<NameDictionary>
17835 BaseNameDictionary<NameDictionary, NameDictionaryShape>::
17836     AddNoUpdateNextEnumerationIndex(Isolate* isolate, Handle<NameDictionary>,
17837                                     Handle<Name>, Handle<Object>,
17838                                     PropertyDetails, int*);
17839 
17840 template <typename Derived, typename Shape>
Add(Isolate * isolate,Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details,int * entry_out)17841 Handle<Derived> BaseNameDictionary<Derived, Shape>::Add(
17842     Isolate* isolate, Handle<Derived> dictionary, Key key, Handle<Object> value,
17843     PropertyDetails details, int* entry_out) {
17844   // Insert element at empty or deleted entry
17845   DCHECK_EQ(0, details.dictionary_index());
17846   // Assign an enumeration index to the property and update
17847   // SetNextEnumerationIndex.
17848   int index = dictionary->NextEnumerationIndex();
17849   details = details.set_index(index);
17850   dictionary->SetNextEnumerationIndex(index + 1);
17851   return AddNoUpdateNextEnumerationIndex(isolate, dictionary, key, value,
17852                                          details, entry_out);
17853 }
17854 
17855 template <typename Derived, typename Shape>
Add(Isolate * isolate,Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details,int * entry_out)17856 Handle<Derived> Dictionary<Derived, Shape>::Add(Isolate* isolate,
17857                                                 Handle<Derived> dictionary,
17858                                                 Key key, Handle<Object> value,
17859                                                 PropertyDetails details,
17860                                                 int* entry_out) {
17861   uint32_t hash = Shape::Hash(isolate, key);
17862   // Valdate key is absent.
17863   SLOW_DCHECK((dictionary->FindEntry(isolate, key) == Dictionary::kNotFound));
17864   // Check whether the dictionary should be extended.
17865   dictionary = Derived::EnsureCapacity(isolate, dictionary, 1);
17866 
17867   // Compute the key object.
17868   Handle<Object> k = Shape::AsHandle(isolate, key);
17869 
17870   uint32_t entry = dictionary->FindInsertionEntry(hash);
17871   dictionary->SetEntry(isolate, entry, *k, *value, details);
17872   DCHECK(dictionary->KeyAt(entry)->IsNumber() ||
17873          Shape::Unwrap(dictionary->KeyAt(entry))->IsUniqueName());
17874   dictionary->ElementAdded();
17875   if (entry_out) *entry_out = entry;
17876   return dictionary;
17877 }
17878 
17879 // static
Set(Isolate * isolate,Handle<SimpleNumberDictionary> dictionary,uint32_t key,Handle<Object> value)17880 Handle<SimpleNumberDictionary> SimpleNumberDictionary::Set(
17881     Isolate* isolate, Handle<SimpleNumberDictionary> dictionary, uint32_t key,
17882     Handle<Object> value) {
17883   return AtPut(isolate, dictionary, key, value, PropertyDetails::Empty());
17884 }
17885 
HasComplexElements()17886 bool NumberDictionary::HasComplexElements() {
17887   if (!requires_slow_elements()) return false;
17888   ReadOnlyRoots roots = GetReadOnlyRoots();
17889   int capacity = this->Capacity();
17890   for (int i = 0; i < capacity; i++) {
17891     Object* k;
17892     if (!this->ToKey(roots, i, &k)) continue;
17893     PropertyDetails details = this->DetailsAt(i);
17894     if (details.kind() == kAccessor) return true;
17895     PropertyAttributes attr = details.attributes();
17896     if (attr & ALL_ATTRIBUTES_MASK) return true;
17897   }
17898   return false;
17899 }
17900 
UpdateMaxNumberKey(uint32_t key,Handle<JSObject> dictionary_holder)17901 void NumberDictionary::UpdateMaxNumberKey(uint32_t key,
17902                                           Handle<JSObject> dictionary_holder) {
17903   DisallowHeapAllocation no_allocation;
17904   // If the dictionary requires slow elements an element has already
17905   // been added at a high index.
17906   if (requires_slow_elements()) return;
17907   // Check if this index is high enough that we should require slow
17908   // elements.
17909   if (key > kRequiresSlowElementsLimit) {
17910     if (!dictionary_holder.is_null()) {
17911       dictionary_holder->RequireSlowElements(this);
17912     }
17913     set_requires_slow_elements();
17914     return;
17915   }
17916   // Update max key value.
17917   Object* max_index_object = get(kMaxNumberKeyIndex);
17918   if (!max_index_object->IsSmi() || max_number_key() < key) {
17919     FixedArray::set(kMaxNumberKeyIndex,
17920                     Smi::FromInt(key << kRequiresSlowElementsTagSize));
17921   }
17922 }
17923 
Set(Isolate * isolate,Handle<NumberDictionary> dictionary,uint32_t key,Handle<Object> value,Handle<JSObject> dictionary_holder,PropertyDetails details)17924 Handle<NumberDictionary> NumberDictionary::Set(
17925     Isolate* isolate, Handle<NumberDictionary> dictionary, uint32_t key,
17926     Handle<Object> value, Handle<JSObject> dictionary_holder,
17927     PropertyDetails details) {
17928   dictionary->UpdateMaxNumberKey(key, dictionary_holder);
17929   return AtPut(isolate, dictionary, key, value, details);
17930 }
17931 
CopyValuesTo(FixedArray * elements)17932 void NumberDictionary::CopyValuesTo(FixedArray* elements) {
17933   ReadOnlyRoots roots = GetReadOnlyRoots();
17934   int pos = 0;
17935   int capacity = this->Capacity();
17936   DisallowHeapAllocation no_gc;
17937   WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
17938   for (int i = 0; i < capacity; i++) {
17939     Object* k;
17940     if (this->ToKey(roots, i, &k)) {
17941       elements->set(pos++, this->ValueAt(i), mode);
17942     }
17943   }
17944   DCHECK_EQ(pos, elements->length());
17945 }
17946 
17947 template <typename Derived, typename Shape>
NumberOfEnumerableProperties()17948 int Dictionary<Derived, Shape>::NumberOfEnumerableProperties() {
17949   ReadOnlyRoots roots = this->GetReadOnlyRoots();
17950   int capacity = this->Capacity();
17951   int result = 0;
17952   for (int i = 0; i < capacity; i++) {
17953     Object* k;
17954     if (!this->ToKey(roots, i, &k)) continue;
17955     if (k->FilterKey(ENUMERABLE_STRINGS)) continue;
17956     PropertyDetails details = this->DetailsAt(i);
17957     PropertyAttributes attr = details.attributes();
17958     if ((attr & ONLY_ENUMERABLE) == 0) result++;
17959   }
17960   return result;
17961 }
17962 
17963 
17964 template <typename Dictionary>
17965 struct EnumIndexComparator {
EnumIndexComparatorv8::internal::EnumIndexComparator17966   explicit EnumIndexComparator(Dictionary* dict) : dict(dict) {}
operator ()v8::internal::EnumIndexComparator17967   bool operator()(const base::AtomicElement<Smi*>& a,
17968                   const base::AtomicElement<Smi*>& b) {
17969     PropertyDetails da(dict->DetailsAt(a.value()->value()));
17970     PropertyDetails db(dict->DetailsAt(b.value()->value()));
17971     return da.dictionary_index() < db.dictionary_index();
17972   }
17973   Dictionary* dict;
17974 };
17975 
17976 template <typename Derived, typename Shape>
CopyEnumKeysTo(Isolate * isolate,Handle<Derived> dictionary,Handle<FixedArray> storage,KeyCollectionMode mode,KeyAccumulator * accumulator)17977 void BaseNameDictionary<Derived, Shape>::CopyEnumKeysTo(
17978     Isolate* isolate, Handle<Derived> dictionary, Handle<FixedArray> storage,
17979     KeyCollectionMode mode, KeyAccumulator* accumulator) {
17980   DCHECK_IMPLIES(mode != KeyCollectionMode::kOwnOnly, accumulator != nullptr);
17981   int length = storage->length();
17982   int capacity = dictionary->Capacity();
17983   int properties = 0;
17984   ReadOnlyRoots roots(isolate);
17985   for (int i = 0; i < capacity; i++) {
17986     Object* key;
17987     if (!dictionary->ToKey(roots, i, &key)) continue;
17988     bool is_shadowing_key = false;
17989     if (key->IsSymbol()) continue;
17990     PropertyDetails details = dictionary->DetailsAt(i);
17991     if (details.IsDontEnum()) {
17992       if (mode == KeyCollectionMode::kIncludePrototypes) {
17993         is_shadowing_key = true;
17994       } else {
17995         continue;
17996       }
17997     }
17998     if (is_shadowing_key) {
17999       accumulator->AddShadowingKey(key);
18000       continue;
18001     } else {
18002       storage->set(properties, Smi::FromInt(i));
18003     }
18004     properties++;
18005     if (mode == KeyCollectionMode::kOwnOnly && properties == length) break;
18006   }
18007 
18008   CHECK_EQ(length, properties);
18009   DisallowHeapAllocation no_gc;
18010   Derived* raw_dictionary = *dictionary;
18011   FixedArray* raw_storage = *storage;
18012   EnumIndexComparator<Derived> cmp(raw_dictionary);
18013   // Use AtomicElement wrapper to ensure that std::sort uses atomic load and
18014   // store operations that are safe for concurrent marking.
18015   base::AtomicElement<Smi*>* start =
18016       reinterpret_cast<base::AtomicElement<Smi*>*>(
18017           storage->GetFirstElementAddress());
18018   std::sort(start, start + length, cmp);
18019   for (int i = 0; i < length; i++) {
18020     int index = Smi::ToInt(raw_storage->get(i));
18021     raw_storage->set(i, raw_dictionary->NameAt(index));
18022   }
18023 }
18024 
18025 template <typename Derived, typename Shape>
IterationIndices(Isolate * isolate,Handle<Derived> dictionary)18026 Handle<FixedArray> BaseNameDictionary<Derived, Shape>::IterationIndices(
18027     Isolate* isolate, Handle<Derived> dictionary) {
18028   int capacity = dictionary->Capacity();
18029   int length = dictionary->NumberOfElements();
18030   Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
18031   ReadOnlyRoots roots(isolate);
18032   int array_size = 0;
18033   {
18034     DisallowHeapAllocation no_gc;
18035     Derived* raw_dictionary = *dictionary;
18036     for (int i = 0; i < capacity; i++) {
18037       Object* k;
18038       if (!raw_dictionary->ToKey(roots, i, &k)) continue;
18039       array->set(array_size++, Smi::FromInt(i));
18040     }
18041 
18042     DCHECK_EQ(array_size, length);
18043 
18044     EnumIndexComparator<Derived> cmp(raw_dictionary);
18045     // Use AtomicElement wrapper to ensure that std::sort uses atomic load and
18046     // store operations that are safe for concurrent marking.
18047     base::AtomicElement<Smi*>* start =
18048         reinterpret_cast<base::AtomicElement<Smi*>*>(
18049             array->GetFirstElementAddress());
18050     std::sort(start, start + array_size, cmp);
18051   }
18052   return FixedArray::ShrinkOrEmpty(isolate, array, array_size);
18053 }
18054 
18055 template <typename Derived, typename Shape>
CollectKeysTo(Handle<Derived> dictionary,KeyAccumulator * keys)18056 void BaseNameDictionary<Derived, Shape>::CollectKeysTo(
18057     Handle<Derived> dictionary, KeyAccumulator* keys) {
18058   Isolate* isolate = keys->isolate();
18059   ReadOnlyRoots roots(isolate);
18060   int capacity = dictionary->Capacity();
18061   Handle<FixedArray> array =
18062       isolate->factory()->NewFixedArray(dictionary->NumberOfElements());
18063   int array_size = 0;
18064   PropertyFilter filter = keys->filter();
18065   {
18066     DisallowHeapAllocation no_gc;
18067     Derived* raw_dictionary = *dictionary;
18068     for (int i = 0; i < capacity; i++) {
18069       Object* k;
18070       if (!raw_dictionary->ToKey(roots, i, &k)) continue;
18071       if (k->FilterKey(filter)) continue;
18072       PropertyDetails details = raw_dictionary->DetailsAt(i);
18073       if ((details.attributes() & filter) != 0) {
18074         keys->AddShadowingKey(k);
18075         continue;
18076       }
18077       if (filter & ONLY_ALL_CAN_READ) {
18078         if (details.kind() != kAccessor) continue;
18079         Object* accessors = raw_dictionary->ValueAt(i);
18080         if (!accessors->IsAccessorInfo()) continue;
18081         if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
18082       }
18083       array->set(array_size++, Smi::FromInt(i));
18084     }
18085 
18086     EnumIndexComparator<Derived> cmp(raw_dictionary);
18087     // Use AtomicElement wrapper to ensure that std::sort uses atomic load and
18088     // store operations that are safe for concurrent marking.
18089     base::AtomicElement<Smi*>* start =
18090         reinterpret_cast<base::AtomicElement<Smi*>*>(
18091             array->GetFirstElementAddress());
18092     std::sort(start, start + array_size, cmp);
18093   }
18094 
18095   bool has_seen_symbol = false;
18096   for (int i = 0; i < array_size; i++) {
18097     int index = Smi::ToInt(array->get(i));
18098     Object* key = dictionary->NameAt(index);
18099     if (key->IsSymbol()) {
18100       has_seen_symbol = true;
18101       continue;
18102     }
18103     keys->AddKey(key, DO_NOT_CONVERT);
18104   }
18105   if (has_seen_symbol) {
18106     for (int i = 0; i < array_size; i++) {
18107       int index = Smi::ToInt(array->get(i));
18108       Object* key = dictionary->NameAt(index);
18109       if (!key->IsSymbol()) continue;
18110       keys->AddKey(key, DO_NOT_CONVERT);
18111     }
18112   }
18113 }
18114 
18115 // Backwards lookup (slow).
18116 template <typename Derived, typename Shape>
SlowReverseLookup(Object * value)18117 Object* Dictionary<Derived, Shape>::SlowReverseLookup(Object* value) {
18118   Derived* dictionary = Derived::cast(this);
18119   ReadOnlyRoots roots = dictionary->GetReadOnlyRoots();
18120   int capacity = dictionary->Capacity();
18121   for (int i = 0; i < capacity; i++) {
18122     Object* k;
18123     if (!dictionary->ToKey(roots, i, &k)) continue;
18124     Object* e = dictionary->ValueAt(i);
18125     if (e == value) return k;
18126   }
18127   return roots.undefined_value();
18128 }
18129 
18130 template <typename Derived, typename Shape>
FillEntriesWithHoles(Handle<Derived> table)18131 void ObjectHashTableBase<Derived, Shape>::FillEntriesWithHoles(
18132     Handle<Derived> table) {
18133   int length = table->length();
18134   for (int i = Derived::EntryToIndex(0); i < length; i++) {
18135     table->set_the_hole(i);
18136   }
18137 }
18138 
18139 template <typename Derived, typename Shape>
Lookup(ReadOnlyRoots roots,Handle<Object> key,int32_t hash)18140 Object* ObjectHashTableBase<Derived, Shape>::Lookup(ReadOnlyRoots roots,
18141                                                     Handle<Object> key,
18142                                                     int32_t hash) {
18143   DisallowHeapAllocation no_gc;
18144   DCHECK(this->IsKey(roots, *key));
18145 
18146   int entry = this->FindEntry(roots, key, hash);
18147   if (entry == kNotFound) return roots.the_hole_value();
18148   return this->get(Derived::EntryToIndex(entry) + 1);
18149 }
18150 
18151 template <typename Derived, typename Shape>
Lookup(Handle<Object> key)18152 Object* ObjectHashTableBase<Derived, Shape>::Lookup(Handle<Object> key) {
18153   DisallowHeapAllocation no_gc;
18154 
18155   ReadOnlyRoots roots = this->GetReadOnlyRoots();
18156   DCHECK(this->IsKey(roots, *key));
18157 
18158   // If the object does not have an identity hash, it was never used as a key.
18159   Object* hash = key->GetHash();
18160   if (hash->IsUndefined(roots)) {
18161     return roots.the_hole_value();
18162   }
18163   return Lookup(roots, key, Smi::ToInt(hash));
18164 }
18165 
18166 template <typename Derived, typename Shape>
Lookup(Handle<Object> key,int32_t hash)18167 Object* ObjectHashTableBase<Derived, Shape>::Lookup(Handle<Object> key,
18168                                                     int32_t hash) {
18169   return Lookup(this->GetReadOnlyRoots(), key, hash);
18170 }
18171 
18172 template <typename Derived, typename Shape>
ValueAt(int entry)18173 Object* ObjectHashTableBase<Derived, Shape>::ValueAt(int entry) {
18174   return this->get(EntryToValueIndex(entry));
18175 }
18176 
18177 template <typename Derived, typename Shape>
Put(Handle<Derived> table,Handle<Object> key,Handle<Object> value)18178 Handle<Derived> ObjectHashTableBase<Derived, Shape>::Put(Handle<Derived> table,
18179                                                          Handle<Object> key,
18180                                                          Handle<Object> value) {
18181   Isolate* isolate = Heap::FromWritableHeapObject(*table)->isolate();
18182   DCHECK(table->IsKey(ReadOnlyRoots(isolate), *key));
18183   DCHECK(!value->IsTheHole(ReadOnlyRoots(isolate)));
18184 
18185   // Make sure the key object has an identity hash code.
18186   int32_t hash = key->GetOrCreateHash(isolate)->value();
18187 
18188   return ObjectHashTableBase<Derived, Shape>::Put(isolate, table, key, value,
18189                                                   hash);
18190 }
18191 
18192 template <typename Derived, typename Shape>
Put(Isolate * isolate,Handle<Derived> table,Handle<Object> key,Handle<Object> value,int32_t hash)18193 Handle<Derived> ObjectHashTableBase<Derived, Shape>::Put(Isolate* isolate,
18194                                                          Handle<Derived> table,
18195                                                          Handle<Object> key,
18196                                                          Handle<Object> value,
18197                                                          int32_t hash) {
18198   ReadOnlyRoots roots(isolate);
18199   DCHECK(table->IsKey(roots, *key));
18200   DCHECK(!value->IsTheHole(roots));
18201 
18202   int entry = table->FindEntry(roots, key, hash);
18203 
18204   // Key is already in table, just overwrite value.
18205   if (entry != kNotFound) {
18206     table->set(Derived::EntryToIndex(entry) + 1, *value);
18207     return table;
18208   }
18209 
18210   // Rehash if more than 33% of the entries are deleted entries.
18211   // TODO(jochen): Consider to shrink the fixed array in place.
18212   if ((table->NumberOfDeletedElements() << 1) > table->NumberOfElements()) {
18213     table->Rehash(isolate);
18214   }
18215   // If we're out of luck, we didn't get a GC recently, and so rehashing
18216   // isn't enough to avoid a crash.
18217   if (!table->HasSufficientCapacityToAdd(1)) {
18218     int nof = table->NumberOfElements() + 1;
18219     int capacity = ObjectHashTable::ComputeCapacity(nof * 2);
18220     if (capacity > ObjectHashTable::kMaxCapacity) {
18221       for (size_t i = 0; i < 2; ++i) {
18222         isolate->heap()->CollectAllGarbage(
18223             Heap::kFinalizeIncrementalMarkingMask,
18224             GarbageCollectionReason::kFullHashtable);
18225       }
18226       table->Rehash(isolate);
18227     }
18228   }
18229 
18230   // Check whether the hash table should be extended.
18231   table = Derived::EnsureCapacity(isolate, table, 1);
18232   table->AddEntry(table->FindInsertionEntry(hash), *key, *value);
18233   return table;
18234 }
18235 
18236 template <typename Derived, typename Shape>
Remove(Isolate * isolate,Handle<Derived> table,Handle<Object> key,bool * was_present)18237 Handle<Derived> ObjectHashTableBase<Derived, Shape>::Remove(
18238     Isolate* isolate, Handle<Derived> table, Handle<Object> key,
18239     bool* was_present) {
18240   DCHECK(table->IsKey(table->GetReadOnlyRoots(), *key));
18241 
18242   Object* hash = key->GetHash();
18243   if (hash->IsUndefined()) {
18244     *was_present = false;
18245     return table;
18246   }
18247 
18248   return Remove(isolate, table, key, was_present, Smi::ToInt(hash));
18249 }
18250 
18251 template <typename Derived, typename Shape>
Remove(Isolate * isolate,Handle<Derived> table,Handle<Object> key,bool * was_present,int32_t hash)18252 Handle<Derived> ObjectHashTableBase<Derived, Shape>::Remove(
18253     Isolate* isolate, Handle<Derived> table, Handle<Object> key,
18254     bool* was_present, int32_t hash) {
18255   ReadOnlyRoots roots = table->GetReadOnlyRoots();
18256   DCHECK(table->IsKey(roots, *key));
18257 
18258   int entry = table->FindEntry(roots, key, hash);
18259   if (entry == kNotFound) {
18260     *was_present = false;
18261     return table;
18262   }
18263 
18264   *was_present = true;
18265   table->RemoveEntry(entry);
18266   return Derived::Shrink(isolate, table);
18267 }
18268 
18269 template <typename Derived, typename Shape>
AddEntry(int entry,Object * key,Object * value)18270 void ObjectHashTableBase<Derived, Shape>::AddEntry(int entry, Object* key,
18271                                                    Object* value) {
18272   this->set(Derived::EntryToIndex(entry), key);
18273   this->set(Derived::EntryToIndex(entry) + 1, value);
18274   this->ElementAdded();
18275 }
18276 
18277 template <typename Derived, typename Shape>
RemoveEntry(int entry)18278 void ObjectHashTableBase<Derived, Shape>::RemoveEntry(int entry) {
18279   this->set_the_hole(Derived::EntryToIndex(entry));
18280   this->set_the_hole(Derived::EntryToIndex(entry) + 1);
18281   this->ElementRemoved();
18282 }
18283 
18284 
Initialize(Handle<JSSet> set,Isolate * isolate)18285 void JSSet::Initialize(Handle<JSSet> set, Isolate* isolate) {
18286   Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
18287   set->set_table(*table);
18288 }
18289 
Clear(Isolate * isolate,Handle<JSSet> set)18290 void JSSet::Clear(Isolate* isolate, Handle<JSSet> set) {
18291   Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()), isolate);
18292   table = OrderedHashSet::Clear(isolate, table);
18293   set->set_table(*table);
18294 }
18295 
18296 
Initialize(Handle<JSMap> map,Isolate * isolate)18297 void JSMap::Initialize(Handle<JSMap> map, Isolate* isolate) {
18298   Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
18299   map->set_table(*table);
18300 }
18301 
Clear(Isolate * isolate,Handle<JSMap> map)18302 void JSMap::Clear(Isolate* isolate, Handle<JSMap> map) {
18303   Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()), isolate);
18304   table = OrderedHashMap::Clear(isolate, table);
18305   map->set_table(*table);
18306 }
18307 
18308 
Initialize(Handle<JSWeakCollection> weak_collection,Isolate * isolate)18309 void JSWeakCollection::Initialize(Handle<JSWeakCollection> weak_collection,
18310                                   Isolate* isolate) {
18311   Handle<EphemeronHashTable> table = EphemeronHashTable::New(isolate, 0);
18312   weak_collection->set_table(*table);
18313 }
18314 
18315 
Set(Handle<JSWeakCollection> weak_collection,Handle<Object> key,Handle<Object> value,int32_t hash)18316 void JSWeakCollection::Set(Handle<JSWeakCollection> weak_collection,
18317                            Handle<Object> key, Handle<Object> value,
18318                            int32_t hash) {
18319   DCHECK(key->IsJSReceiver() || key->IsSymbol());
18320   Handle<EphemeronHashTable> table(
18321       EphemeronHashTable::cast(weak_collection->table()),
18322       weak_collection->GetIsolate());
18323   DCHECK(table->IsKey(weak_collection->GetReadOnlyRoots(), *key));
18324   Handle<EphemeronHashTable> new_table = EphemeronHashTable::Put(
18325       weak_collection->GetIsolate(), table, key, value, hash);
18326   weak_collection->set_table(*new_table);
18327   if (*table != *new_table) {
18328     // Zap the old table since we didn't record slots for its elements.
18329     EphemeronHashTable::FillEntriesWithHoles(table);
18330   }
18331 }
18332 
18333 
Delete(Handle<JSWeakCollection> weak_collection,Handle<Object> key,int32_t hash)18334 bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection,
18335                               Handle<Object> key, int32_t hash) {
18336   DCHECK(key->IsJSReceiver() || key->IsSymbol());
18337   Handle<EphemeronHashTable> table(
18338       EphemeronHashTable::cast(weak_collection->table()),
18339       weak_collection->GetIsolate());
18340   DCHECK(table->IsKey(weak_collection->GetReadOnlyRoots(), *key));
18341   bool was_present = false;
18342   Handle<EphemeronHashTable> new_table = EphemeronHashTable::Remove(
18343       weak_collection->GetIsolate(), table, key, &was_present, hash);
18344   weak_collection->set_table(*new_table);
18345   if (*table != *new_table) {
18346     // Zap the old table since we didn't record slots for its elements.
18347     EphemeronHashTable::FillEntriesWithHoles(table);
18348   }
18349   return was_present;
18350 }
18351 
GetEntries(Handle<JSWeakCollection> holder,int max_entries)18352 Handle<JSArray> JSWeakCollection::GetEntries(Handle<JSWeakCollection> holder,
18353                                              int max_entries) {
18354   Isolate* isolate = holder->GetIsolate();
18355   Handle<EphemeronHashTable> table(EphemeronHashTable::cast(holder->table()),
18356                                    isolate);
18357   if (max_entries == 0 || max_entries > table->NumberOfElements()) {
18358     max_entries = table->NumberOfElements();
18359   }
18360   int values_per_entry = holder->IsJSWeakMap() ? 2 : 1;
18361   Handle<FixedArray> entries =
18362       isolate->factory()->NewFixedArray(max_entries * values_per_entry);
18363   // Recompute max_values because GC could have removed elements from the table.
18364   if (max_entries > table->NumberOfElements()) {
18365     max_entries = table->NumberOfElements();
18366   }
18367 
18368   {
18369     DisallowHeapAllocation no_gc;
18370     ReadOnlyRoots roots = ReadOnlyRoots(isolate);
18371     int count = 0;
18372     for (int i = 0;
18373          count / values_per_entry < max_entries && i < table->Capacity(); i++) {
18374       Object* key;
18375       if (table->ToKey(roots, i, &key)) {
18376         entries->set(count++, key);
18377         if (values_per_entry > 1) {
18378           Object* value = table->Lookup(handle(key, isolate));
18379           entries->set(count++, value);
18380         }
18381       }
18382     }
18383     DCHECK_EQ(max_entries * values_per_entry, count);
18384   }
18385   return isolate->factory()->NewJSArrayWithElements(entries);
18386 }
18387 
18388 // static
New(Handle<JSFunction> constructor,Handle<JSReceiver> new_target,double tv)18389 MaybeHandle<JSDate> JSDate::New(Handle<JSFunction> constructor,
18390                                 Handle<JSReceiver> new_target, double tv) {
18391   Isolate* const isolate = constructor->GetIsolate();
18392   Handle<JSObject> result;
18393   ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
18394                              JSObject::New(constructor, new_target), JSDate);
18395   if (-DateCache::kMaxTimeInMs <= tv && tv <= DateCache::kMaxTimeInMs) {
18396     tv = DoubleToInteger(tv) + 0.0;
18397   } else {
18398     tv = std::numeric_limits<double>::quiet_NaN();
18399   }
18400   Handle<Object> value = isolate->factory()->NewNumber(tv);
18401   Handle<JSDate>::cast(result)->SetValue(*value, std::isnan(tv));
18402   return Handle<JSDate>::cast(result);
18403 }
18404 
18405 
18406 // static
CurrentTimeValue(Isolate * isolate)18407 double JSDate::CurrentTimeValue(Isolate* isolate) {
18408   if (FLAG_log_internal_timer_events) LOG(isolate, CurrentTimeEvent());
18409 
18410   // According to ECMA-262, section 15.9.1, page 117, the precision of
18411   // the number in a Date object representing a particular instant in
18412   // time is milliseconds. Therefore, we floor the result of getting
18413   // the OS time.
18414   return Floor(V8::GetCurrentPlatform()->CurrentClockTimeMillis());
18415 }
18416 
18417 
18418 // static
GetField(Object * object,Smi * index)18419 Object* JSDate::GetField(Object* object, Smi* index) {
18420   return JSDate::cast(object)->DoGetField(
18421       static_cast<FieldIndex>(index->value()));
18422 }
18423 
18424 
DoGetField(FieldIndex index)18425 Object* JSDate::DoGetField(FieldIndex index) {
18426   DCHECK_NE(index, kDateValue);
18427 
18428   DateCache* date_cache = GetIsolate()->date_cache();
18429 
18430   if (index < kFirstUncachedField) {
18431     Object* stamp = cache_stamp();
18432     if (stamp != date_cache->stamp() && stamp->IsSmi()) {
18433       // Since the stamp is not NaN, the value is also not NaN.
18434       int64_t local_time_ms =
18435           date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
18436       SetCachedFields(local_time_ms, date_cache);
18437     }
18438     switch (index) {
18439       case kYear: return year();
18440       case kMonth: return month();
18441       case kDay: return day();
18442       case kWeekday: return weekday();
18443       case kHour: return hour();
18444       case kMinute: return min();
18445       case kSecond: return sec();
18446       default: UNREACHABLE();
18447     }
18448   }
18449 
18450   if (index >= kFirstUTCField) {
18451     return GetUTCField(index, value()->Number(), date_cache);
18452   }
18453 
18454   double time = value()->Number();
18455   if (std::isnan(time)) return GetReadOnlyRoots().nan_value();
18456 
18457   int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
18458   int days = DateCache::DaysFromTime(local_time_ms);
18459 
18460   if (index == kDays) return Smi::FromInt(days);
18461 
18462   int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
18463   if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
18464   DCHECK_EQ(index, kTimeInDay);
18465   return Smi::FromInt(time_in_day_ms);
18466 }
18467 
18468 
GetUTCField(FieldIndex index,double value,DateCache * date_cache)18469 Object* JSDate::GetUTCField(FieldIndex index,
18470                             double value,
18471                             DateCache* date_cache) {
18472   DCHECK_GE(index, kFirstUTCField);
18473 
18474   if (std::isnan(value)) return GetReadOnlyRoots().nan_value();
18475 
18476   int64_t time_ms = static_cast<int64_t>(value);
18477 
18478   if (index == kTimezoneOffset) {
18479     return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
18480   }
18481 
18482   int days = DateCache::DaysFromTime(time_ms);
18483 
18484   if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
18485 
18486   if (index <= kDayUTC) {
18487     int year, month, day;
18488     date_cache->YearMonthDayFromDays(days, &year, &month, &day);
18489     if (index == kYearUTC) return Smi::FromInt(year);
18490     if (index == kMonthUTC) return Smi::FromInt(month);
18491     DCHECK_EQ(index, kDayUTC);
18492     return Smi::FromInt(day);
18493   }
18494 
18495   int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
18496   switch (index) {
18497     case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
18498     case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
18499     case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
18500     case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
18501     case kDaysUTC: return Smi::FromInt(days);
18502     case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
18503     default: UNREACHABLE();
18504   }
18505 
18506   UNREACHABLE();
18507 }
18508 
18509 
18510 // static
SetValue(Handle<JSDate> date,double v)18511 Handle<Object> JSDate::SetValue(Handle<JSDate> date, double v) {
18512   Isolate* const isolate = date->GetIsolate();
18513   Handle<Object> value = isolate->factory()->NewNumber(v);
18514   bool value_is_nan = std::isnan(v);
18515   date->SetValue(*value, value_is_nan);
18516   return value;
18517 }
18518 
18519 
SetValue(Object * value,bool is_value_nan)18520 void JSDate::SetValue(Object* value, bool is_value_nan) {
18521   set_value(value);
18522   if (is_value_nan) {
18523     HeapNumber* nan = GetReadOnlyRoots().nan_value();
18524     set_cache_stamp(nan, SKIP_WRITE_BARRIER);
18525     set_year(nan, SKIP_WRITE_BARRIER);
18526     set_month(nan, SKIP_WRITE_BARRIER);
18527     set_day(nan, SKIP_WRITE_BARRIER);
18528     set_hour(nan, SKIP_WRITE_BARRIER);
18529     set_min(nan, SKIP_WRITE_BARRIER);
18530     set_sec(nan, SKIP_WRITE_BARRIER);
18531     set_weekday(nan, SKIP_WRITE_BARRIER);
18532   } else {
18533     set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
18534   }
18535 }
18536 
18537 
SetCachedFields(int64_t local_time_ms,DateCache * date_cache)18538 void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) {
18539   int days = DateCache::DaysFromTime(local_time_ms);
18540   int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
18541   int year, month, day;
18542   date_cache->YearMonthDayFromDays(days, &year, &month, &day);
18543   int weekday = date_cache->Weekday(days);
18544   int hour = time_in_day_ms / (60 * 60 * 1000);
18545   int min = (time_in_day_ms / (60 * 1000)) % 60;
18546   int sec = (time_in_day_ms / 1000) % 60;
18547   set_cache_stamp(date_cache->stamp());
18548   set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
18549   set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
18550   set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
18551   set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
18552   set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
18553   set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
18554   set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
18555 }
18556 
GetLineNumber() const18557 int JSMessageObject::GetLineNumber() const {
18558   if (start_position() == -1) return Message::kNoLineNumberInfo;
18559 
18560   Handle<Script> the_script(script(), GetIsolate());
18561 
18562   Script::PositionInfo info;
18563   const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
18564   if (!Script::GetPositionInfo(the_script, start_position(), &info,
18565                                offset_flag)) {
18566     return Message::kNoLineNumberInfo;
18567   }
18568 
18569   return info.line + 1;
18570 }
18571 
GetColumnNumber() const18572 int JSMessageObject::GetColumnNumber() const {
18573   if (start_position() == -1) return -1;
18574 
18575   Handle<Script> the_script(script(), GetIsolate());
18576 
18577   Script::PositionInfo info;
18578   const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
18579   if (!Script::GetPositionInfo(the_script, start_position(), &info,
18580                                offset_flag)) {
18581     return -1;
18582   }
18583 
18584   return info.column;  // Note: No '+1' in contrast to GetLineNumber.
18585 }
18586 
GetSourceLine() const18587 Handle<String> JSMessageObject::GetSourceLine() const {
18588   Isolate* isolate = GetIsolate();
18589   Handle<Script> the_script(script(), isolate);
18590 
18591   if (the_script->type() == Script::TYPE_WASM) {
18592     return isolate->factory()->empty_string();
18593   }
18594 
18595   Script::PositionInfo info;
18596   const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
18597   if (!Script::GetPositionInfo(the_script, start_position(), &info,
18598                                offset_flag)) {
18599     return isolate->factory()->empty_string();
18600   }
18601 
18602   Handle<String> src = handle(String::cast(the_script->source()), isolate);
18603   return isolate->factory()->NewSubString(src, info.line_start, info.line_end);
18604 }
18605 
InvalidateEntry(Isolate * isolate,Handle<GlobalDictionary> dictionary,int entry)18606 Handle<PropertyCell> PropertyCell::InvalidateEntry(
18607     Isolate* isolate, Handle<GlobalDictionary> dictionary, int entry) {
18608   // Swap with a copy.
18609   Handle<PropertyCell> cell(dictionary->CellAt(entry), isolate);
18610   Handle<Name> name(cell->name(), isolate);
18611   Handle<PropertyCell> new_cell = isolate->factory()->NewPropertyCell(name);
18612   new_cell->set_value(cell->value());
18613   dictionary->ValueAtPut(entry, *new_cell);
18614   bool is_the_hole = cell->value()->IsTheHole(isolate);
18615   // Cell is officially mutable henceforth.
18616   PropertyDetails details = cell->property_details();
18617   details = details.set_cell_type(is_the_hole ? PropertyCellType::kUninitialized
18618                                               : PropertyCellType::kMutable);
18619   new_cell->set_property_details(details);
18620   // Old cell is ready for invalidation.
18621   if (is_the_hole) {
18622     cell->set_value(ReadOnlyRoots(isolate).undefined_value());
18623   } else {
18624     cell->set_value(ReadOnlyRoots(isolate).the_hole_value());
18625   }
18626   details = details.set_cell_type(PropertyCellType::kInvalidated);
18627   cell->set_property_details(details);
18628   cell->dependent_code()->DeoptimizeDependentCodeGroup(
18629       isolate, DependentCode::kPropertyCellChangedGroup);
18630   return new_cell;
18631 }
18632 
18633 
GetConstantType()18634 PropertyCellConstantType PropertyCell::GetConstantType() {
18635   if (value()->IsSmi()) return PropertyCellConstantType::kSmi;
18636   return PropertyCellConstantType::kStableMap;
18637 }
18638 
18639 
RemainsConstantType(Handle<PropertyCell> cell,Handle<Object> value)18640 static bool RemainsConstantType(Handle<PropertyCell> cell,
18641                                 Handle<Object> value) {
18642   // TODO(dcarney): double->smi and smi->double transition from kConstant
18643   if (cell->value()->IsSmi() && value->IsSmi()) {
18644     return true;
18645   } else if (cell->value()->IsHeapObject() && value->IsHeapObject()) {
18646     return HeapObject::cast(cell->value())->map() ==
18647                HeapObject::cast(*value)->map() &&
18648            HeapObject::cast(*value)->map()->is_stable();
18649   }
18650   return false;
18651 }
18652 
UpdatedType(Isolate * isolate,Handle<PropertyCell> cell,Handle<Object> value,PropertyDetails details)18653 PropertyCellType PropertyCell::UpdatedType(Isolate* isolate,
18654                                            Handle<PropertyCell> cell,
18655                                            Handle<Object> value,
18656                                            PropertyDetails details) {
18657   PropertyCellType type = details.cell_type();
18658   DCHECK(!value->IsTheHole(isolate));
18659   if (cell->value()->IsTheHole(isolate)) {
18660     switch (type) {
18661       // Only allow a cell to transition once into constant state.
18662       case PropertyCellType::kUninitialized:
18663         if (value->IsUndefined(isolate)) return PropertyCellType::kUndefined;
18664         return PropertyCellType::kConstant;
18665       case PropertyCellType::kInvalidated:
18666         return PropertyCellType::kMutable;
18667       default:
18668         UNREACHABLE();
18669     }
18670   }
18671   switch (type) {
18672     case PropertyCellType::kUndefined:
18673       return PropertyCellType::kConstant;
18674     case PropertyCellType::kConstant:
18675       if (*value == cell->value()) return PropertyCellType::kConstant;
18676       V8_FALLTHROUGH;
18677     case PropertyCellType::kConstantType:
18678       if (RemainsConstantType(cell, value)) {
18679         return PropertyCellType::kConstantType;
18680       }
18681       V8_FALLTHROUGH;
18682     case PropertyCellType::kMutable:
18683       return PropertyCellType::kMutable;
18684   }
18685   UNREACHABLE();
18686 }
18687 
PrepareForValue(Isolate * isolate,Handle<GlobalDictionary> dictionary,int entry,Handle<Object> value,PropertyDetails details)18688 Handle<PropertyCell> PropertyCell::PrepareForValue(
18689     Isolate* isolate, Handle<GlobalDictionary> dictionary, int entry,
18690     Handle<Object> value, PropertyDetails details) {
18691   DCHECK(!value->IsTheHole(isolate));
18692   Handle<PropertyCell> cell(dictionary->CellAt(entry), isolate);
18693   const PropertyDetails original_details = cell->property_details();
18694   // Data accesses could be cached in ics or optimized code.
18695   bool invalidate =
18696       (original_details.kind() == kData && details.kind() == kAccessor) ||
18697       (!original_details.IsReadOnly() && details.IsReadOnly());
18698   int index;
18699   PropertyCellType old_type = original_details.cell_type();
18700   // Preserve the enumeration index unless the property was deleted or never
18701   // initialized.
18702   if (cell->value()->IsTheHole(isolate)) {
18703     index = dictionary->NextEnumerationIndex();
18704     dictionary->SetNextEnumerationIndex(index + 1);
18705   } else {
18706     index = original_details.dictionary_index();
18707   }
18708   DCHECK_LT(0, index);
18709   details = details.set_index(index);
18710 
18711   PropertyCellType new_type =
18712       UpdatedType(isolate, cell, value, original_details);
18713   if (invalidate) {
18714     cell = PropertyCell::InvalidateEntry(isolate, dictionary, entry);
18715   }
18716 
18717   // Install new property details.
18718   details = details.set_cell_type(new_type);
18719   cell->set_property_details(details);
18720 
18721   if (new_type == PropertyCellType::kConstant ||
18722       new_type == PropertyCellType::kConstantType) {
18723     // Store the value now to ensure that the cell contains the constant or
18724     // type information. Otherwise subsequent store operation will turn
18725     // the cell to mutable.
18726     cell->set_value(*value);
18727   }
18728 
18729   // Deopt when transitioning from a constant type.
18730   if (!invalidate && (old_type != new_type ||
18731                       original_details.IsReadOnly() != details.IsReadOnly())) {
18732     cell->dependent_code()->DeoptimizeDependentCodeGroup(
18733         isolate, DependentCode::kPropertyCellChangedGroup);
18734   }
18735   return cell;
18736 }
18737 
18738 
18739 // static
SetValueWithInvalidation(Isolate * isolate,Handle<PropertyCell> cell,Handle<Object> new_value)18740 void PropertyCell::SetValueWithInvalidation(Isolate* isolate,
18741                                             Handle<PropertyCell> cell,
18742                                             Handle<Object> new_value) {
18743   if (cell->value() != *new_value) {
18744     cell->set_value(*new_value);
18745     cell->dependent_code()->DeoptimizeDependentCodeGroup(
18746         isolate, DependentCode::kPropertyCellChangedGroup);
18747   }
18748 }
18749 
source_position() const18750 int JSGeneratorObject::source_position() const {
18751   CHECK(is_suspended());
18752   DCHECK(function()->shared()->HasBytecodeArray());
18753 
18754   int code_offset = Smi::ToInt(input_or_debug_pos());
18755 
18756   // The stored bytecode offset is relative to a different base than what
18757   // is used in the source position table, hence the subtraction.
18758   code_offset -= BytecodeArray::kHeaderSize - kHeapObjectTag;
18759   AbstractCode* code =
18760       AbstractCode::cast(function()->shared()->GetBytecodeArray());
18761   return code->SourcePosition(code_offset);
18762 }
18763 
18764 // static
Get(Isolate * isolate,Handle<JSObject> receiver)18765 AccessCheckInfo* AccessCheckInfo::Get(Isolate* isolate,
18766                                       Handle<JSObject> receiver) {
18767   DisallowHeapAllocation no_gc;
18768   DCHECK(receiver->map()->is_access_check_needed());
18769   Object* maybe_constructor = receiver->map()->GetConstructor();
18770   if (maybe_constructor->IsFunctionTemplateInfo()) {
18771     Object* data_obj =
18772         FunctionTemplateInfo::cast(maybe_constructor)->access_check_info();
18773     if (data_obj->IsUndefined(isolate)) return nullptr;
18774     return AccessCheckInfo::cast(data_obj);
18775   }
18776   // Might happen for a detached context.
18777   if (!maybe_constructor->IsJSFunction()) return nullptr;
18778   JSFunction* constructor = JSFunction::cast(maybe_constructor);
18779   // Might happen for the debug context.
18780   if (!constructor->shared()->IsApiFunction()) return nullptr;
18781 
18782   Object* data_obj =
18783       constructor->shared()->get_api_func_data()->access_check_info();
18784   if (data_obj->IsUndefined(isolate)) return nullptr;
18785 
18786   return AccessCheckInfo::cast(data_obj);
18787 }
18788 
HasProxyInPrototype(Isolate * isolate)18789 bool JSReceiver::HasProxyInPrototype(Isolate* isolate) {
18790   for (PrototypeIterator iter(isolate, this, kStartAtReceiver,
18791                               PrototypeIterator::END_AT_NULL);
18792        !iter.IsAtEnd(); iter.AdvanceIgnoringProxies()) {
18793     if (iter.GetCurrent<Object>()->IsJSProxy()) return true;
18794   }
18795   return false;
18796 }
18797 
HasComplexElements()18798 bool JSReceiver::HasComplexElements() {
18799   if (IsJSProxy()) return true;
18800   JSObject* this_object = JSObject::cast(this);
18801   if (this_object->HasIndexedInterceptor()) {
18802     return true;
18803   }
18804   if (!this_object->HasDictionaryElements()) return false;
18805   return this_object->element_dictionary()->HasComplexElements();
18806 }
18807 
TryGetCachedPropertyName(Isolate * isolate,Handle<Object> getter)18808 MaybeHandle<Name> FunctionTemplateInfo::TryGetCachedPropertyName(
18809     Isolate* isolate, Handle<Object> getter) {
18810   if (getter->IsFunctionTemplateInfo()) {
18811     Handle<FunctionTemplateInfo> fti =
18812         Handle<FunctionTemplateInfo>::cast(getter);
18813     // Check if the accessor uses a cached property.
18814     if (!fti->cached_property_name()->IsTheHole(isolate)) {
18815       return handle(Name::cast(fti->cached_property_name()), isolate);
18816     }
18817   }
18818   return MaybeHandle<Name>();
18819 }
18820 
18821 // Force instantiation of template instances class.
18822 // Please note this list is compiler dependent.
18823 // Keep this at the end of this file
18824 
18825 template class HashTable<StringTable, StringTableShape>;
18826 
18827 template class HashTable<CompilationCacheTable, CompilationCacheShape>;
18828 
18829 template class HashTable<ObjectHashTable, ObjectHashTableShape>;
18830 
18831 template class HashTable<EphemeronHashTable, EphemeronHashTableShape>;
18832 
18833 template class ObjectHashTableBase<ObjectHashTable, ObjectHashTableShape>;
18834 
18835 template class ObjectHashTableBase<EphemeronHashTable, EphemeronHashTableShape>;
18836 
18837 template class Dictionary<NameDictionary, NameDictionaryShape>;
18838 
18839 template class Dictionary<GlobalDictionary, GlobalDictionaryShape>;
18840 
18841 template class EXPORT_TEMPLATE_DEFINE(
18842     V8_EXPORT_PRIVATE) HashTable<NumberDictionary, NumberDictionaryShape>;
18843 
18844 template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
18845     Dictionary<NumberDictionary, NumberDictionaryShape>;
18846 
18847 template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
18848     HashTable<SimpleNumberDictionary, SimpleNumberDictionaryShape>;
18849 
18850 template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
18851     Dictionary<SimpleNumberDictionary, SimpleNumberDictionaryShape>;
18852 
18853 template Handle<NameDictionary>
18854 BaseNameDictionary<NameDictionary, NameDictionaryShape>::New(
18855     Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
18856 
18857 template Handle<GlobalDictionary>
18858 BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::New(
18859     Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
18860 
18861 template Handle<NameDictionary>
18862 HashTable<NameDictionary, NameDictionaryShape>::New(Isolate*, int,
18863                                                     PretenureFlag,
18864                                                     MinimumCapacity);
18865 
18866 template Handle<ObjectHashSet>
18867 HashTable<ObjectHashSet, ObjectHashSetShape>::New(Isolate*, int n,
18868                                                   PretenureFlag,
18869                                                   MinimumCapacity);
18870 
18871 template Handle<NameDictionary>
18872 HashTable<NameDictionary, NameDictionaryShape>::Shrink(Isolate* isolate,
18873                                                        Handle<NameDictionary>,
18874                                                        int additionalCapacity);
18875 
18876 template Handle<NameDictionary>
18877 BaseNameDictionary<NameDictionary, NameDictionaryShape>::Add(
18878     Isolate* isolate, Handle<NameDictionary>, Handle<Name>, Handle<Object>,
18879     PropertyDetails, int*);
18880 
18881 template Handle<GlobalDictionary>
18882 BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::Add(
18883     Isolate* isolate, Handle<GlobalDictionary>, Handle<Name>, Handle<Object>,
18884     PropertyDetails, int*);
18885 
18886 template void HashTable<GlobalDictionary, GlobalDictionaryShape>::Rehash(
18887     Isolate* isolate);
18888 
18889 template Handle<NameDictionary>
18890 BaseNameDictionary<NameDictionary, NameDictionaryShape>::EnsureCapacity(
18891     Isolate* isolate, Handle<NameDictionary>, int);
18892 
18893 template void
18894 BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::CopyEnumKeysTo(
18895     Isolate* isolate, Handle<GlobalDictionary> dictionary,
18896     Handle<FixedArray> storage, KeyCollectionMode mode,
18897     KeyAccumulator* accumulator);
18898 
18899 template void
18900 BaseNameDictionary<NameDictionary, NameDictionaryShape>::CopyEnumKeysTo(
18901     Isolate* isolate, Handle<NameDictionary> dictionary,
18902     Handle<FixedArray> storage, KeyCollectionMode mode,
18903     KeyAccumulator* accumulator);
18904 
18905 template Handle<FixedArray>
18906 BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::IterationIndices(
18907     Isolate* isolate, Handle<GlobalDictionary> dictionary);
18908 template void
18909 BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::CollectKeysTo(
18910     Handle<GlobalDictionary> dictionary, KeyAccumulator* keys);
18911 
18912 template Handle<FixedArray>
18913 BaseNameDictionary<NameDictionary, NameDictionaryShape>::IterationIndices(
18914     Isolate* isolate, Handle<NameDictionary> dictionary);
18915 template void
18916 BaseNameDictionary<NameDictionary, NameDictionaryShape>::CollectKeysTo(
18917     Handle<NameDictionary> dictionary, KeyAccumulator* keys);
18918 
18919 }  // namespace internal
18920 }  // namespace v8
18921