1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/objects.h"
6 
7 #include <cmath>
8 #include <iomanip>
9 #include <memory>
10 #include <sstream>
11 #include <vector>
12 
13 #include "src/objects-inl.h"
14 
15 #include "src/accessors.h"
16 #include "src/allocation-site-scopes.h"
17 #include "src/api-arguments-inl.h"
18 #include "src/api-natives.h"
19 #include "src/api.h"
20 #include "src/arguments.h"
21 #include "src/ast/ast.h"
22 #include "src/ast/scopes.h"
23 #include "src/base/bits.h"
24 #include "src/base/utils/random-number-generator.h"
25 #include "src/bootstrapper.h"
26 #include "src/builtins/builtins.h"
27 #include "src/code-stubs.h"
28 #include "src/compilation-dependencies.h"
29 #include "src/compiler.h"
30 #include "src/counters-inl.h"
31 #include "src/counters.h"
32 #include "src/date.h"
33 #include "src/debug/debug-evaluate.h"
34 #include "src/debug/debug.h"
35 #include "src/deoptimizer.h"
36 #include "src/elements.h"
37 #include "src/execution.h"
38 #include "src/field-index-inl.h"
39 #include "src/field-index.h"
40 #include "src/field-type.h"
41 #include "src/frames-inl.h"
42 #include "src/globals.h"
43 #include "src/ic/ic.h"
44 #include "src/identity-map.h"
45 #include "src/interpreter/bytecode-array-iterator.h"
46 #include "src/interpreter/bytecode-decoder.h"
47 #include "src/interpreter/interpreter.h"
48 #include "src/isolate-inl.h"
49 #include "src/keys.h"
50 #include "src/log.h"
51 #include "src/lookup.h"
52 #include "src/macro-assembler.h"
53 #include "src/map-updater.h"
54 #include "src/messages.h"
55 #include "src/objects-body-descriptors-inl.h"
56 #include "src/objects/api-callbacks.h"
57 #include "src/objects/bigint.h"
58 #include "src/objects/code-inl.h"
59 #include "src/objects/compilation-cache-inl.h"
60 #include "src/objects/debug-objects-inl.h"
61 #include "src/objects/frame-array-inl.h"
62 #include "src/objects/hash-table-inl.h"
63 #ifdef V8_INTL_SUPPORT
64 #include "src/objects/js-locale.h"
65 #endif  // V8_INTL_SUPPORT
66 #include "src/objects/js-regexp-string-iterator.h"
67 #include "src/objects/map.h"
68 #include "src/objects/microtask-inl.h"
69 #include "src/objects/promise-inl.h"
70 #include "src/parsing/preparsed-scope-data.h"
71 #include "src/property-descriptor.h"
72 #include "src/prototype.h"
73 #include "src/regexp/jsregexp.h"
74 #include "src/safepoint-table.h"
75 #include "src/snapshot/code-serializer.h"
76 #include "src/snapshot/snapshot.h"
77 #include "src/source-position-table.h"
78 #include "src/string-builder.h"
79 #include "src/string-search.h"
80 #include "src/string-stream.h"
81 #include "src/unicode-cache-inl.h"
82 #include "src/unicode-decoder.h"
83 #include "src/utils-inl.h"
84 #include "src/wasm/wasm-engine.h"
85 #include "src/wasm/wasm-objects.h"
86 #include "src/zone/zone.h"
87 
88 #ifdef ENABLE_DISASSEMBLER
89 #include "src/disasm.h"
90 #include "src/disassembler.h"
91 #include "src/eh-frame.h"
92 #endif
93 
94 namespace v8 {
95 namespace internal {
96 
ComparisonResultToBool(Operation op,ComparisonResult result)97 bool ComparisonResultToBool(Operation op, ComparisonResult result) {
98   switch (op) {
99     case Operation::kLessThan:
100       return result == ComparisonResult::kLessThan;
101     case Operation::kLessThanOrEqual:
102       return result == ComparisonResult::kLessThan ||
103              result == ComparisonResult::kEqual;
104     case Operation::kGreaterThan:
105       return result == ComparisonResult::kGreaterThan;
106     case Operation::kGreaterThanOrEqual:
107       return result == ComparisonResult::kGreaterThan ||
108              result == ComparisonResult::kEqual;
109     default:
110       break;
111   }
112   UNREACHABLE();
113 }
114 
operator <<(std::ostream & os,InstanceType instance_type)115 std::ostream& operator<<(std::ostream& os, InstanceType instance_type) {
116   switch (instance_type) {
117 #define WRITE_TYPE(TYPE) \
118   case TYPE:             \
119     return os << #TYPE;
120     INSTANCE_TYPE_LIST(WRITE_TYPE)
121 #undef WRITE_TYPE
122   }
123   UNREACHABLE();
124 }
125 
OptimalType(Isolate * isolate,Representation representation)126 Handle<FieldType> Object::OptimalType(Isolate* isolate,
127                                       Representation representation) {
128   if (representation.IsNone()) return FieldType::None(isolate);
129   if (FLAG_track_field_types) {
130     if (representation.IsHeapObject() && IsHeapObject()) {
131       // We can track only JavaScript objects with stable maps.
132       Handle<Map> map(HeapObject::cast(this)->map(), isolate);
133       if (map->is_stable() && map->IsJSReceiverMap()) {
134         return FieldType::Class(map, isolate);
135       }
136     }
137   }
138   return FieldType::Any(isolate);
139 }
140 
ToObject(Isolate * isolate,Handle<Object> object,Handle<Context> native_context,const char * method_name)141 MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
142                                          Handle<Object> object,
143                                          Handle<Context> native_context,
144                                          const char* method_name) {
145   if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
146   Handle<JSFunction> constructor;
147   if (object->IsSmi()) {
148     constructor = handle(native_context->number_function(), isolate);
149   } else {
150     int constructor_function_index =
151         Handle<HeapObject>::cast(object)->map()->GetConstructorFunctionIndex();
152     if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
153       if (method_name != nullptr) {
154         THROW_NEW_ERROR(
155             isolate,
156             NewTypeError(
157                 MessageTemplate::kCalledOnNullOrUndefined,
158                 isolate->factory()->NewStringFromAsciiChecked(method_name)),
159             JSReceiver);
160       }
161       THROW_NEW_ERROR(isolate,
162                       NewTypeError(MessageTemplate::kUndefinedOrNullToObject),
163                       JSReceiver);
164     }
165     constructor = handle(
166         JSFunction::cast(native_context->get(constructor_function_index)),
167         isolate);
168   }
169   Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
170   Handle<JSValue>::cast(result)->set_value(*object);
171   return result;
172 }
173 
174 // ES6 section 9.2.1.2, OrdinaryCallBindThis for sloppy callee.
175 // static
ConvertReceiver(Isolate * isolate,Handle<Object> object)176 MaybeHandle<JSReceiver> Object::ConvertReceiver(Isolate* isolate,
177                                                 Handle<Object> object) {
178   if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
179   if (*object == isolate->heap()->null_value() ||
180       object->IsUndefined(isolate)) {
181     return isolate->global_proxy();
182   }
183   return Object::ToObject(isolate, object);
184 }
185 
186 // static
ConvertToNumberOrNumeric(Isolate * isolate,Handle<Object> input,Conversion mode)187 MaybeHandle<Object> Object::ConvertToNumberOrNumeric(Isolate* isolate,
188                                                      Handle<Object> input,
189                                                      Conversion mode) {
190   while (true) {
191     if (input->IsNumber()) {
192       return input;
193     }
194     if (input->IsString()) {
195       return String::ToNumber(Handle<String>::cast(input));
196     }
197     if (input->IsOddball()) {
198       return Oddball::ToNumber(Handle<Oddball>::cast(input));
199     }
200     if (input->IsSymbol()) {
201       THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber),
202                       Object);
203     }
204     if (input->IsBigInt()) {
205       if (mode == Conversion::kToNumeric) return input;
206       DCHECK_EQ(mode, Conversion::kToNumber);
207       THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kBigIntToNumber),
208                       Object);
209     }
210     ASSIGN_RETURN_ON_EXCEPTION(
211         isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
212                                                 ToPrimitiveHint::kNumber),
213         Object);
214   }
215 }
216 
217 // static
ConvertToInteger(Isolate * isolate,Handle<Object> input)218 MaybeHandle<Object> Object::ConvertToInteger(Isolate* isolate,
219                                              Handle<Object> input) {
220   ASSIGN_RETURN_ON_EXCEPTION(
221       isolate, input,
222       ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object);
223   if (input->IsSmi()) return input;
224   return isolate->factory()->NewNumber(DoubleToInteger(input->Number()));
225 }
226 
227 // static
ConvertToInt32(Isolate * isolate,Handle<Object> input)228 MaybeHandle<Object> Object::ConvertToInt32(Isolate* isolate,
229                                            Handle<Object> input) {
230   ASSIGN_RETURN_ON_EXCEPTION(
231       isolate, input,
232       ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object);
233   if (input->IsSmi()) return input;
234   return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number()));
235 }
236 
237 // static
ConvertToUint32(Isolate * isolate,Handle<Object> input)238 MaybeHandle<Object> Object::ConvertToUint32(Isolate* isolate,
239                                             Handle<Object> input) {
240   ASSIGN_RETURN_ON_EXCEPTION(
241       isolate, input,
242       ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object);
243   if (input->IsSmi()) return handle(Smi::cast(*input)->ToUint32Smi(), isolate);
244   return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number()));
245 }
246 
247 // static
ConvertToName(Isolate * isolate,Handle<Object> input)248 MaybeHandle<Name> Object::ConvertToName(Isolate* isolate,
249                                         Handle<Object> input) {
250   ASSIGN_RETURN_ON_EXCEPTION(
251       isolate, input, Object::ToPrimitive(input, ToPrimitiveHint::kString),
252       Name);
253   if (input->IsName()) return Handle<Name>::cast(input);
254   return ToString(isolate, input);
255 }
256 
257 // ES6 7.1.14
258 // static
ConvertToPropertyKey(Isolate * isolate,Handle<Object> value)259 MaybeHandle<Object> Object::ConvertToPropertyKey(Isolate* isolate,
260                                                  Handle<Object> value) {
261   // 1. Let key be ToPrimitive(argument, hint String).
262   MaybeHandle<Object> maybe_key =
263       Object::ToPrimitive(value, ToPrimitiveHint::kString);
264   // 2. ReturnIfAbrupt(key).
265   Handle<Object> key;
266   if (!maybe_key.ToHandle(&key)) return key;
267   // 3. If Type(key) is Symbol, then return key.
268   if (key->IsSymbol()) return key;
269   // 4. Return ToString(key).
270   // Extending spec'ed behavior, we'd be happy to return an element index.
271   if (key->IsSmi()) return key;
272   if (key->IsHeapNumber()) {
273     uint32_t uint_value;
274     if (value->ToArrayLength(&uint_value) &&
275         uint_value <= static_cast<uint32_t>(Smi::kMaxValue)) {
276       return handle(Smi::FromInt(static_cast<int>(uint_value)), isolate);
277     }
278   }
279   return Object::ToString(isolate, key);
280 }
281 
282 // static
ConvertToString(Isolate * isolate,Handle<Object> input)283 MaybeHandle<String> Object::ConvertToString(Isolate* isolate,
284                                             Handle<Object> input) {
285   while (true) {
286     if (input->IsOddball()) {
287       return handle(Handle<Oddball>::cast(input)->to_string(), isolate);
288     }
289     if (input->IsNumber()) {
290       return isolate->factory()->NumberToString(input);
291     }
292     if (input->IsSymbol()) {
293       THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToString),
294                       String);
295     }
296     if (input->IsBigInt()) {
297       return BigInt::ToString(Handle<BigInt>::cast(input));
298     }
299     ASSIGN_RETURN_ON_EXCEPTION(
300         isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
301                                                 ToPrimitiveHint::kString),
302         String);
303     // The previous isString() check happened in Object::ToString and thus we
304     // put it at the end of the loop in this helper.
305     if (input->IsString()) {
306       return Handle<String>::cast(input);
307     }
308   }
309 }
310 
311 namespace {
312 
IsErrorObject(Isolate * isolate,Handle<Object> object)313 bool IsErrorObject(Isolate* isolate, Handle<Object> object) {
314   if (!object->IsJSReceiver()) return false;
315   Handle<Symbol> symbol = isolate->factory()->stack_trace_symbol();
316   return JSReceiver::HasOwnProperty(Handle<JSReceiver>::cast(object), symbol)
317       .FromMaybe(false);
318 }
319 
AsStringOrEmpty(Isolate * isolate,Handle<Object> object)320 Handle<String> AsStringOrEmpty(Isolate* isolate, Handle<Object> object) {
321   return object->IsString() ? Handle<String>::cast(object)
322                             : isolate->factory()->empty_string();
323 }
324 
NoSideEffectsErrorToString(Isolate * isolate,Handle<Object> input)325 Handle<String> NoSideEffectsErrorToString(Isolate* isolate,
326                                           Handle<Object> input) {
327   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input);
328 
329   Handle<Name> name_key = isolate->factory()->name_string();
330   Handle<Object> name = JSReceiver::GetDataProperty(receiver, name_key);
331   Handle<String> name_str = AsStringOrEmpty(isolate, name);
332 
333   Handle<Name> msg_key = isolate->factory()->message_string();
334   Handle<Object> msg = JSReceiver::GetDataProperty(receiver, msg_key);
335   Handle<String> msg_str = AsStringOrEmpty(isolate, msg);
336 
337   if (name_str->length() == 0) return msg_str;
338   if (msg_str->length() == 0) return name_str;
339 
340   IncrementalStringBuilder builder(isolate);
341   builder.AppendString(name_str);
342   builder.AppendCString(": ");
343   builder.AppendString(msg_str);
344 
345   return builder.Finish().ToHandleChecked();
346 }
347 
348 }  // namespace
349 
350 // static
NoSideEffectsToString(Isolate * isolate,Handle<Object> input)351 Handle<String> Object::NoSideEffectsToString(Isolate* isolate,
352                                              Handle<Object> input) {
353   DisallowJavascriptExecution no_js(isolate);
354 
355   if (input->IsString() || input->IsNumeric() || input->IsOddball()) {
356     return Object::ToString(isolate, input).ToHandleChecked();
357   } else if (input->IsFunction()) {
358     // -- F u n c t i o n
359     Handle<String> fun_str;
360     if (input->IsJSBoundFunction()) {
361       fun_str = JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(input));
362     } else {
363       DCHECK(input->IsJSFunction());
364       fun_str = JSFunction::ToString(Handle<JSFunction>::cast(input));
365     }
366 
367     if (fun_str->length() > 128) {
368       IncrementalStringBuilder builder(isolate);
369       builder.AppendString(isolate->factory()->NewSubString(fun_str, 0, 111));
370       builder.AppendCString("...<omitted>...");
371       builder.AppendString(isolate->factory()->NewSubString(
372           fun_str, fun_str->length() - 2, fun_str->length()));
373 
374       return builder.Finish().ToHandleChecked();
375     }
376     return fun_str;
377   } else if (input->IsSymbol()) {
378     // -- S y m b o l
379     Handle<Symbol> symbol = Handle<Symbol>::cast(input);
380 
381     IncrementalStringBuilder builder(isolate);
382     builder.AppendCString("Symbol(");
383     if (symbol->name()->IsString()) {
384       builder.AppendString(handle(String::cast(symbol->name()), isolate));
385     }
386     builder.AppendCharacter(')');
387 
388     return builder.Finish().ToHandleChecked();
389   } else if (input->IsJSReceiver()) {
390     // -- J S R e c e i v e r
391     Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input);
392     Handle<Object> to_string = JSReceiver::GetDataProperty(
393         receiver, isolate->factory()->toString_string());
394 
395     if (IsErrorObject(isolate, input) ||
396         *to_string == *isolate->error_to_string()) {
397       // When internally formatting error objects, use a side-effects-free
398       // version of Error.prototype.toString independent of the actually
399       // installed toString method.
400       return NoSideEffectsErrorToString(isolate, input);
401     } else if (*to_string == *isolate->object_to_string()) {
402       Handle<Object> ctor = JSReceiver::GetDataProperty(
403           receiver, isolate->factory()->constructor_string());
404       if (ctor->IsFunction()) {
405         Handle<String> ctor_name;
406         if (ctor->IsJSBoundFunction()) {
407           ctor_name = JSBoundFunction::GetName(
408                           isolate, Handle<JSBoundFunction>::cast(ctor))
409                           .ToHandleChecked();
410         } else if (ctor->IsJSFunction()) {
411           Handle<Object> ctor_name_obj =
412               JSFunction::GetName(isolate, Handle<JSFunction>::cast(ctor));
413           ctor_name = AsStringOrEmpty(isolate, ctor_name_obj);
414         }
415 
416         if (ctor_name->length() != 0) {
417           IncrementalStringBuilder builder(isolate);
418           builder.AppendCString("#<");
419           builder.AppendString(ctor_name);
420           builder.AppendCString(">");
421 
422           return builder.Finish().ToHandleChecked();
423         }
424       }
425     }
426   }
427 
428   // At this point, input is either none of the above or a JSReceiver.
429 
430   Handle<JSReceiver> receiver;
431   if (input->IsJSReceiver()) {
432     receiver = Handle<JSReceiver>::cast(input);
433   } else {
434     // This is the only case where Object::ToObject throws.
435     DCHECK(!input->IsSmi());
436     int constructor_function_index =
437         Handle<HeapObject>::cast(input)->map()->GetConstructorFunctionIndex();
438     if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
439       return isolate->factory()->NewStringFromAsciiChecked("[object Unknown]");
440     }
441 
442     receiver = Object::ToObject(isolate, input, isolate->native_context())
443                    .ToHandleChecked();
444   }
445 
446   Handle<String> builtin_tag = handle(receiver->class_name(), isolate);
447   Handle<Object> tag_obj = JSReceiver::GetDataProperty(
448       receiver, isolate->factory()->to_string_tag_symbol());
449   Handle<String> tag =
450       tag_obj->IsString() ? Handle<String>::cast(tag_obj) : builtin_tag;
451 
452   IncrementalStringBuilder builder(isolate);
453   builder.AppendCString("[object ");
454   builder.AppendString(tag);
455   builder.AppendCString("]");
456 
457   return builder.Finish().ToHandleChecked();
458 }
459 
460 // static
ConvertToLength(Isolate * isolate,Handle<Object> input)461 MaybeHandle<Object> Object::ConvertToLength(Isolate* isolate,
462                                             Handle<Object> input) {
463   ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
464   if (input->IsSmi()) {
465     int value = std::max(Smi::ToInt(*input), 0);
466     return handle(Smi::FromInt(value), isolate);
467   }
468   double len = DoubleToInteger(input->Number());
469   if (len <= 0.0) {
470     return handle(Smi::kZero, isolate);
471   } else if (len >= kMaxSafeInteger) {
472     len = kMaxSafeInteger;
473   }
474   return isolate->factory()->NewNumber(len);
475 }
476 
477 // static
ConvertToIndex(Isolate * isolate,Handle<Object> input,MessageTemplate::Template error_index)478 MaybeHandle<Object> Object::ConvertToIndex(
479     Isolate* isolate, Handle<Object> input,
480     MessageTemplate::Template error_index) {
481   if (input->IsUndefined(isolate)) return handle(Smi::kZero, isolate);
482   ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
483   if (input->IsSmi() && Smi::ToInt(*input) >= 0) return input;
484   double len = DoubleToInteger(input->Number()) + 0.0;
485   auto js_len = isolate->factory()->NewNumber(len);
486   if (len < 0.0 || len > kMaxSafeInteger) {
487     THROW_NEW_ERROR(isolate, NewRangeError(error_index, js_len), Object);
488   }
489   return js_len;
490 }
491 
BooleanValue()492 bool Object::BooleanValue() {
493   if (IsSmi()) return Smi::ToInt(this) != 0;
494   DCHECK(IsHeapObject());
495   Isolate* isolate = HeapObject::cast(this)->GetIsolate();
496   if (IsBoolean()) return IsTrue(isolate);
497   if (IsNullOrUndefined(isolate)) return false;
498   if (IsUndetectable()) return false;  // Undetectable object is false.
499   if (IsString()) return String::cast(this)->length() != 0;
500   if (IsHeapNumber()) return DoubleToBoolean(HeapNumber::cast(this)->value());
501   if (IsBigInt()) return BigInt::cast(this)->ToBoolean();
502   return true;
503 }
504 
505 
506 namespace {
507 
508 // TODO(bmeurer): Maybe we should introduce a marker interface Number,
509 // where we put all these methods at some point?
NumberCompare(double x,double y)510 ComparisonResult NumberCompare(double x, double y) {
511   if (std::isnan(x) || std::isnan(y)) {
512     return ComparisonResult::kUndefined;
513   } else if (x < y) {
514     return ComparisonResult::kLessThan;
515   } else if (x > y) {
516     return ComparisonResult::kGreaterThan;
517   } else {
518     return ComparisonResult::kEqual;
519   }
520 }
521 
NumberEquals(double x,double y)522 bool NumberEquals(double x, double y) {
523   // Must check explicitly for NaN's on Windows, but -0 works fine.
524   if (std::isnan(x)) return false;
525   if (std::isnan(y)) return false;
526   return x == y;
527 }
528 
NumberEquals(const Object * x,const Object * y)529 bool NumberEquals(const Object* x, const Object* y) {
530   return NumberEquals(x->Number(), y->Number());
531 }
532 
NumberEquals(Handle<Object> x,Handle<Object> y)533 bool NumberEquals(Handle<Object> x, Handle<Object> y) {
534   return NumberEquals(*x, *y);
535 }
536 
Reverse(ComparisonResult result)537 ComparisonResult Reverse(ComparisonResult result) {
538   if (result == ComparisonResult::kLessThan) {
539     return ComparisonResult::kGreaterThan;
540   }
541   if (result == ComparisonResult::kGreaterThan) {
542     return ComparisonResult::kLessThan;
543   }
544   return result;
545 }
546 
547 }  // anonymous namespace
548 
549 // static
Compare(Handle<Object> x,Handle<Object> y)550 Maybe<ComparisonResult> Object::Compare(Handle<Object> x, Handle<Object> y) {
551   // ES6 section 7.2.11 Abstract Relational Comparison step 3 and 4.
552   if (!Object::ToPrimitive(x, ToPrimitiveHint::kNumber).ToHandle(&x) ||
553       !Object::ToPrimitive(y, ToPrimitiveHint::kNumber).ToHandle(&y)) {
554     return Nothing<ComparisonResult>();
555   }
556   if (x->IsString() && y->IsString()) {
557     // ES6 section 7.2.11 Abstract Relational Comparison step 5.
558     return Just(
559         String::Compare(Handle<String>::cast(x), Handle<String>::cast(y)));
560   }
561   if (x->IsBigInt() && y->IsString()) {
562     return Just(BigInt::CompareToString(Handle<BigInt>::cast(x),
563                                         Handle<String>::cast(y)));
564   }
565   if (x->IsString() && y->IsBigInt()) {
566     return Just(Reverse(BigInt::CompareToString(Handle<BigInt>::cast(y),
567                                                 Handle<String>::cast(x))));
568   }
569   // ES6 section 7.2.11 Abstract Relational Comparison step 6.
570   if (!Object::ToNumeric(x).ToHandle(&x) ||
571       !Object::ToNumeric(y).ToHandle(&y)) {
572     return Nothing<ComparisonResult>();
573   }
574 
575   bool x_is_number = x->IsNumber();
576   bool y_is_number = y->IsNumber();
577   if (x_is_number && y_is_number) {
578     return Just(NumberCompare(x->Number(), y->Number()));
579   } else if (!x_is_number && !y_is_number) {
580     return Just(BigInt::CompareToBigInt(Handle<BigInt>::cast(x),
581                                         Handle<BigInt>::cast(y)));
582   } else if (x_is_number) {
583     return Just(Reverse(BigInt::CompareToNumber(Handle<BigInt>::cast(y), x)));
584   } else {
585     return Just(BigInt::CompareToNumber(Handle<BigInt>::cast(x), y));
586   }
587 }
588 
589 
590 // static
Equals(Handle<Object> x,Handle<Object> y)591 Maybe<bool> Object::Equals(Handle<Object> x, Handle<Object> y) {
592   // This is the generic version of Abstract Equality Comparison. Must be in
593   // sync with CodeStubAssembler::Equal.
594   while (true) {
595     if (x->IsNumber()) {
596       if (y->IsNumber()) {
597         return Just(NumberEquals(x, y));
598       } else if (y->IsBoolean()) {
599         return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
600       } else if (y->IsString()) {
601         return Just(NumberEquals(x, String::ToNumber(Handle<String>::cast(y))));
602       } else if (y->IsBigInt()) {
603         return Just(BigInt::EqualToNumber(Handle<BigInt>::cast(y), x));
604       } else if (y->IsJSReceiver()) {
605         if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
606                  .ToHandle(&y)) {
607           return Nothing<bool>();
608         }
609       } else {
610         return Just(false);
611       }
612     } else if (x->IsString()) {
613       if (y->IsString()) {
614         return Just(
615             String::Equals(Handle<String>::cast(x), Handle<String>::cast(y)));
616       } else if (y->IsNumber()) {
617         x = String::ToNumber(Handle<String>::cast(x));
618         return Just(NumberEquals(x, y));
619       } else if (y->IsBoolean()) {
620         x = String::ToNumber(Handle<String>::cast(x));
621         return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
622       } else if (y->IsBigInt()) {
623         return Just(BigInt::EqualToString(Handle<BigInt>::cast(y),
624                                           Handle<String>::cast(x)));
625       } else if (y->IsJSReceiver()) {
626         if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
627                  .ToHandle(&y)) {
628           return Nothing<bool>();
629         }
630       } else {
631         return Just(false);
632       }
633     } else if (x->IsBoolean()) {
634       if (y->IsOddball()) {
635         return Just(x.is_identical_to(y));
636       } else if (y->IsNumber()) {
637         return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
638       } else if (y->IsString()) {
639         y = String::ToNumber(Handle<String>::cast(y));
640         return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
641       } else if (y->IsBigInt()) {
642         x = Oddball::ToNumber(Handle<Oddball>::cast(x));
643         return Just(BigInt::EqualToNumber(Handle<BigInt>::cast(y), x));
644       } else if (y->IsJSReceiver()) {
645         if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
646                  .ToHandle(&y)) {
647           return Nothing<bool>();
648         }
649         x = Oddball::ToNumber(Handle<Oddball>::cast(x));
650       } else {
651         return Just(false);
652       }
653     } else if (x->IsSymbol()) {
654       if (y->IsSymbol()) {
655         return Just(x.is_identical_to(y));
656       } else if (y->IsJSReceiver()) {
657         if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
658                  .ToHandle(&y)) {
659           return Nothing<bool>();
660         }
661       } else {
662         return Just(false);
663       }
664     } else if (x->IsBigInt()) {
665       if (y->IsBigInt()) {
666         return Just(BigInt::EqualToBigInt(BigInt::cast(*x), BigInt::cast(*y)));
667       }
668       return Equals(y, x);
669     } else if (x->IsJSReceiver()) {
670       if (y->IsJSReceiver()) {
671         return Just(x.is_identical_to(y));
672       } else if (y->IsUndetectable()) {
673         return Just(x->IsUndetectable());
674       } else if (y->IsBoolean()) {
675         y = Oddball::ToNumber(Handle<Oddball>::cast(y));
676       } else if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(x))
677                       .ToHandle(&x)) {
678         return Nothing<bool>();
679       }
680     } else {
681       return Just(x->IsUndetectable() && y->IsUndetectable());
682     }
683   }
684 }
685 
686 
StrictEquals(Object * that)687 bool Object::StrictEquals(Object* that) {
688   if (this->IsNumber()) {
689     if (!that->IsNumber()) return false;
690     return NumberEquals(this, that);
691   } else if (this->IsString()) {
692     if (!that->IsString()) return false;
693     return String::cast(this)->Equals(String::cast(that));
694   } else if (this->IsBigInt()) {
695     if (!that->IsBigInt()) return false;
696     return BigInt::EqualToBigInt(BigInt::cast(this), BigInt::cast(that));
697   }
698   return this == that;
699 }
700 
701 
702 // static
TypeOf(Isolate * isolate,Handle<Object> object)703 Handle<String> Object::TypeOf(Isolate* isolate, Handle<Object> object) {
704   if (object->IsNumber()) return isolate->factory()->number_string();
705   if (object->IsOddball()) return handle(Oddball::cast(*object)->type_of());
706   if (object->IsUndetectable()) {
707     return isolate->factory()->undefined_string();
708   }
709   if (object->IsString()) return isolate->factory()->string_string();
710   if (object->IsSymbol()) return isolate->factory()->symbol_string();
711   if (object->IsBigInt()) return isolate->factory()->bigint_string();
712   if (object->IsCallable()) return isolate->factory()->function_string();
713   return isolate->factory()->object_string();
714 }
715 
716 
717 // static
Add(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)718 MaybeHandle<Object> Object::Add(Isolate* isolate, Handle<Object> lhs,
719                                 Handle<Object> rhs) {
720   if (lhs->IsNumber() && rhs->IsNumber()) {
721     return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
722   } else if (lhs->IsString() && rhs->IsString()) {
723     return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
724                                              Handle<String>::cast(rhs));
725   }
726   ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToPrimitive(lhs), Object);
727   ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToPrimitive(rhs), Object);
728   if (lhs->IsString() || rhs->IsString()) {
729     ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToString(isolate, rhs),
730                                Object);
731     ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToString(isolate, lhs),
732                                Object);
733     return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
734                                              Handle<String>::cast(rhs));
735   }
736   ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
737   ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
738   return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
739 }
740 
741 
742 // static
OrdinaryHasInstance(Isolate * isolate,Handle<Object> callable,Handle<Object> object)743 MaybeHandle<Object> Object::OrdinaryHasInstance(Isolate* isolate,
744                                                 Handle<Object> callable,
745                                                 Handle<Object> object) {
746   // The {callable} must have a [[Call]] internal method.
747   if (!callable->IsCallable()) return isolate->factory()->false_value();
748 
749   // Check if {callable} is a bound function, and if so retrieve its
750   // [[BoundTargetFunction]] and use that instead of {callable}.
751   if (callable->IsJSBoundFunction()) {
752     Handle<Object> bound_callable(
753         Handle<JSBoundFunction>::cast(callable)->bound_target_function(),
754         isolate);
755     return Object::InstanceOf(isolate, object, bound_callable);
756   }
757 
758   // If {object} is not a receiver, return false.
759   if (!object->IsJSReceiver()) return isolate->factory()->false_value();
760 
761   // Get the "prototype" of {callable}; raise an error if it's not a receiver.
762   Handle<Object> prototype;
763   ASSIGN_RETURN_ON_EXCEPTION(
764       isolate, prototype,
765       Object::GetProperty(callable, isolate->factory()->prototype_string()),
766       Object);
767   if (!prototype->IsJSReceiver()) {
768     THROW_NEW_ERROR(
769         isolate,
770         NewTypeError(MessageTemplate::kInstanceofNonobjectProto, prototype),
771         Object);
772   }
773 
774   // Return whether or not {prototype} is in the prototype chain of {object}.
775   Maybe<bool> result = JSReceiver::HasInPrototypeChain(
776       isolate, Handle<JSReceiver>::cast(object), prototype);
777   if (result.IsNothing()) return MaybeHandle<Object>();
778   return isolate->factory()->ToBoolean(result.FromJust());
779 }
780 
781 // static
InstanceOf(Isolate * isolate,Handle<Object> object,Handle<Object> callable)782 MaybeHandle<Object> Object::InstanceOf(Isolate* isolate, Handle<Object> object,
783                                        Handle<Object> callable) {
784   // The {callable} must be a receiver.
785   if (!callable->IsJSReceiver()) {
786     THROW_NEW_ERROR(isolate,
787                     NewTypeError(MessageTemplate::kNonObjectInInstanceOfCheck),
788                     Object);
789   }
790 
791   // Lookup the @@hasInstance method on {callable}.
792   Handle<Object> inst_of_handler;
793   ASSIGN_RETURN_ON_EXCEPTION(
794       isolate, inst_of_handler,
795       JSReceiver::GetMethod(Handle<JSReceiver>::cast(callable),
796                             isolate->factory()->has_instance_symbol()),
797       Object);
798   if (!inst_of_handler->IsUndefined(isolate)) {
799     // Call the {inst_of_handler} on the {callable}.
800     Handle<Object> result;
801     ASSIGN_RETURN_ON_EXCEPTION(
802         isolate, result,
803         Execution::Call(isolate, inst_of_handler, callable, 1, &object),
804         Object);
805     return isolate->factory()->ToBoolean(result->BooleanValue());
806   }
807 
808   // The {callable} must have a [[Call]] internal method.
809   if (!callable->IsCallable()) {
810     THROW_NEW_ERROR(
811         isolate, NewTypeError(MessageTemplate::kNonCallableInInstanceOfCheck),
812         Object);
813   }
814 
815   // Fall back to OrdinaryHasInstance with {callable} and {object}.
816   Handle<Object> result;
817   ASSIGN_RETURN_ON_EXCEPTION(
818       isolate, result,
819       JSReceiver::OrdinaryHasInstance(isolate, callable, object), Object);
820   return result;
821 }
822 
823 // static
GetMethod(Handle<JSReceiver> receiver,Handle<Name> name)824 MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
825                                       Handle<Name> name) {
826   Handle<Object> func;
827   Isolate* isolate = receiver->GetIsolate();
828   ASSIGN_RETURN_ON_EXCEPTION(isolate, func,
829                              JSReceiver::GetProperty(receiver, name), Object);
830   if (func->IsNullOrUndefined(isolate)) {
831     return isolate->factory()->undefined_value();
832   }
833   if (!func->IsCallable()) {
834     THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kPropertyNotFunction,
835                                           func, name, receiver),
836                     Object);
837   }
838   return func;
839 }
840 
841 namespace {
842 
CreateListFromArrayLikeFastPath(Isolate * isolate,Handle<Object> object,ElementTypes element_types)843 MaybeHandle<FixedArray> CreateListFromArrayLikeFastPath(
844     Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
845   if (element_types == ElementTypes::kAll) {
846     if (object->IsJSArray()) {
847       Handle<JSArray> array = Handle<JSArray>::cast(object);
848       uint32_t length;
849       if (!array->HasArrayPrototype(isolate) ||
850           !array->length()->ToUint32(&length) || !array->HasFastElements() ||
851           !JSObject::PrototypeHasNoElements(isolate, *array)) {
852         return MaybeHandle<FixedArray>();
853       }
854       return array->GetElementsAccessor()->CreateListFromArrayLike(
855           isolate, array, length);
856     } else if (object->IsJSTypedArray()) {
857       Handle<JSTypedArray> array = Handle<JSTypedArray>::cast(object);
858       uint32_t length = array->length_value();
859       if (array->WasNeutered() ||
860           length > static_cast<uint32_t>(FixedArray::kMaxLength)) {
861         return MaybeHandle<FixedArray>();
862       }
863       return array->GetElementsAccessor()->CreateListFromArrayLike(
864           isolate, array, length);
865     }
866   }
867   return MaybeHandle<FixedArray>();
868 }
869 
870 }  // namespace
871 
872 // static
CreateListFromArrayLike(Isolate * isolate,Handle<Object> object,ElementTypes element_types)873 MaybeHandle<FixedArray> Object::CreateListFromArrayLike(
874     Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
875   // Fast-path for JSArray and JSTypedArray.
876   MaybeHandle<FixedArray> fast_result =
877       CreateListFromArrayLikeFastPath(isolate, object, element_types);
878   if (!fast_result.is_null()) return fast_result;
879   // 1. ReturnIfAbrupt(object).
880   // 2. (default elementTypes -- not applicable.)
881   // 3. If Type(obj) is not Object, throw a TypeError exception.
882   if (!object->IsJSReceiver()) {
883     THROW_NEW_ERROR(isolate,
884                     NewTypeError(MessageTemplate::kCalledOnNonObject,
885                                  isolate->factory()->NewStringFromAsciiChecked(
886                                      "CreateListFromArrayLike")),
887                     FixedArray);
888   }
889 
890   // 4. Let len be ? ToLength(? Get(obj, "length")).
891   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
892   Handle<Object> raw_length_number;
893   ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number,
894                              Object::GetLengthFromArrayLike(isolate, receiver),
895                              FixedArray);
896   uint32_t len;
897   if (!raw_length_number->ToUint32(&len) ||
898       len > static_cast<uint32_t>(FixedArray::kMaxLength)) {
899     THROW_NEW_ERROR(isolate,
900                     NewRangeError(MessageTemplate::kInvalidArrayLength),
901                     FixedArray);
902   }
903   // 5. Let list be an empty List.
904   Handle<FixedArray> list = isolate->factory()->NewFixedArray(len);
905   // 6. Let index be 0.
906   // 7. Repeat while index < len:
907   for (uint32_t index = 0; index < len; ++index) {
908     // 7a. Let indexName be ToString(index).
909     // 7b. Let next be ? Get(obj, indexName).
910     Handle<Object> next;
911     ASSIGN_RETURN_ON_EXCEPTION(isolate, next,
912                                JSReceiver::GetElement(isolate, receiver, index),
913                                FixedArray);
914     switch (element_types) {
915       case ElementTypes::kAll:
916         // Nothing to do.
917         break;
918       case ElementTypes::kStringAndSymbol: {
919         // 7c. If Type(next) is not an element of elementTypes, throw a
920         //     TypeError exception.
921         if (!next->IsName()) {
922           THROW_NEW_ERROR(isolate,
923                           NewTypeError(MessageTemplate::kNotPropertyName, next),
924                           FixedArray);
925         }
926         // 7d. Append next as the last element of list.
927         // Internalize on the fly so we can use pointer identity later.
928         next = isolate->factory()->InternalizeName(Handle<Name>::cast(next));
929         break;
930       }
931     }
932     list->set(index, *next);
933     // 7e. Set index to index + 1. (See loop header.)
934   }
935   // 8. Return list.
936   return list;
937 }
938 
939 
940 // static
GetLengthFromArrayLike(Isolate * isolate,Handle<Object> object)941 MaybeHandle<Object> Object::GetLengthFromArrayLike(Isolate* isolate,
942                                                    Handle<Object> object) {
943   Handle<Object> val;
944   Handle<Object> key = isolate->factory()->length_string();
945   ASSIGN_RETURN_ON_EXCEPTION(
946       isolate, val, Runtime::GetObjectProperty(isolate, object, key), Object);
947   return Object::ToLength(isolate, val);
948 }
949 
950 // static
HasProperty(LookupIterator * it)951 Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) {
952   for (; it->IsFound(); it->Next()) {
953     switch (it->state()) {
954       case LookupIterator::NOT_FOUND:
955       case LookupIterator::TRANSITION:
956         UNREACHABLE();
957       case LookupIterator::JSPROXY:
958         return JSProxy::HasProperty(it->isolate(), it->GetHolder<JSProxy>(),
959                                     it->GetName());
960       case LookupIterator::INTERCEPTOR: {
961         Maybe<PropertyAttributes> result =
962             JSObject::GetPropertyAttributesWithInterceptor(it);
963         if (result.IsNothing()) return Nothing<bool>();
964         if (result.FromJust() != ABSENT) return Just(true);
965         break;
966       }
967       case LookupIterator::ACCESS_CHECK: {
968         if (it->HasAccess()) break;
969         Maybe<PropertyAttributes> result =
970             JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
971         if (result.IsNothing()) return Nothing<bool>();
972         return Just(result.FromJust() != ABSENT);
973       }
974       case LookupIterator::INTEGER_INDEXED_EXOTIC:
975         // TypedArray out-of-bounds access.
976         return Just(false);
977       case LookupIterator::ACCESSOR:
978       case LookupIterator::DATA:
979         return Just(true);
980     }
981   }
982   return Just(false);
983 }
984 
985 // static
HasOwnProperty(Handle<JSReceiver> object,Handle<Name> name)986 Maybe<bool> JSReceiver::HasOwnProperty(Handle<JSReceiver> object,
987                                        Handle<Name> name) {
988   if (object->IsJSModuleNamespace()) {
989     PropertyDescriptor desc;
990     return JSReceiver::GetOwnPropertyDescriptor(object->GetIsolate(), object,
991                                                 name, &desc);
992   }
993 
994   if (object->IsJSObject()) {  // Shortcut.
995     LookupIterator it = LookupIterator::PropertyOrElement(
996         object->GetIsolate(), object, name, object, LookupIterator::OWN);
997     return HasProperty(&it);
998   }
999 
1000   Maybe<PropertyAttributes> attributes =
1001       JSReceiver::GetOwnPropertyAttributes(object, name);
1002   MAYBE_RETURN(attributes, Nothing<bool>());
1003   return Just(attributes.FromJust() != ABSENT);
1004 }
1005 
1006 // static
GetProperty(LookupIterator * it)1007 MaybeHandle<Object> Object::GetProperty(LookupIterator* it) {
1008   for (; it->IsFound(); it->Next()) {
1009     switch (it->state()) {
1010       case LookupIterator::NOT_FOUND:
1011       case LookupIterator::TRANSITION:
1012         UNREACHABLE();
1013       case LookupIterator::JSPROXY: {
1014         bool was_found;
1015         MaybeHandle<Object> result =
1016             JSProxy::GetProperty(it->isolate(), it->GetHolder<JSProxy>(),
1017                                  it->GetName(), it->GetReceiver(), &was_found);
1018         if (!was_found) it->NotFound();
1019         return result;
1020       }
1021       case LookupIterator::INTERCEPTOR: {
1022         bool done;
1023         Handle<Object> result;
1024         ASSIGN_RETURN_ON_EXCEPTION(
1025             it->isolate(), result,
1026             JSObject::GetPropertyWithInterceptor(it, &done), Object);
1027         if (done) return result;
1028         break;
1029       }
1030       case LookupIterator::ACCESS_CHECK:
1031         if (it->HasAccess()) break;
1032         return JSObject::GetPropertyWithFailedAccessCheck(it);
1033       case LookupIterator::ACCESSOR:
1034         return GetPropertyWithAccessor(it);
1035       case LookupIterator::INTEGER_INDEXED_EXOTIC:
1036         return it->isolate()->factory()->undefined_value();
1037       case LookupIterator::DATA:
1038         return it->GetDataValue();
1039     }
1040   }
1041   return it->isolate()->factory()->undefined_value();
1042 }
1043 
1044 
1045 // static
GetProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Name> name,Handle<Object> receiver,bool * was_found)1046 MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
1047                                          Handle<JSProxy> proxy,
1048                                          Handle<Name> name,
1049                                          Handle<Object> receiver,
1050                                          bool* was_found) {
1051   *was_found = true;
1052 
1053   DCHECK(!name->IsPrivate());
1054   STACK_CHECK(isolate, MaybeHandle<Object>());
1055   Handle<Name> trap_name = isolate->factory()->get_string();
1056   // 1. Assert: IsPropertyKey(P) is true.
1057   // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
1058   Handle<Object> handler(proxy->handler(), isolate);
1059   // 3. If handler is null, throw a TypeError exception.
1060   // 4. Assert: Type(handler) is Object.
1061   if (proxy->IsRevoked()) {
1062     THROW_NEW_ERROR(isolate,
1063                     NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1064                     Object);
1065   }
1066   // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
1067   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
1068   // 6. Let trap be ? GetMethod(handler, "get").
1069   Handle<Object> trap;
1070   ASSIGN_RETURN_ON_EXCEPTION(
1071       isolate, trap,
1072       Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), Object);
1073   // 7. If trap is undefined, then
1074   if (trap->IsUndefined(isolate)) {
1075     // 7.a Return target.[[Get]](P, Receiver).
1076     LookupIterator it =
1077         LookupIterator::PropertyOrElement(isolate, receiver, name, target);
1078     MaybeHandle<Object> result = Object::GetProperty(&it);
1079     *was_found = it.IsFound();
1080     return result;
1081   }
1082   // 8. Let trapResult be ? Call(trap, handler, «target, P, Receiver»).
1083   Handle<Object> trap_result;
1084   Handle<Object> args[] = {target, name, receiver};
1085   ASSIGN_RETURN_ON_EXCEPTION(
1086       isolate, trap_result,
1087       Execution::Call(isolate, trap, handler, arraysize(args), args), Object);
1088 
1089   MaybeHandle<Object> result =
1090       JSProxy::CheckGetSetTrapResult(isolate, name, target, trap_result, kGet);
1091   if (result.is_null()) {
1092     return result;
1093   }
1094 
1095   // 11. Return trap_result
1096   return trap_result;
1097 }
1098 
1099 // static
CheckGetSetTrapResult(Isolate * isolate,Handle<Name> name,Handle<JSReceiver> target,Handle<Object> trap_result,AccessKind access_kind)1100 MaybeHandle<Object> JSProxy::CheckGetSetTrapResult(Isolate* isolate,
1101                                                    Handle<Name> name,
1102                                                    Handle<JSReceiver> target,
1103                                                    Handle<Object> trap_result,
1104                                                    AccessKind access_kind) {
1105   // 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
1106   PropertyDescriptor target_desc;
1107   Maybe<bool> target_found =
1108       JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
1109   MAYBE_RETURN_NULL(target_found);
1110   // 10. If targetDesc is not undefined, then
1111   if (target_found.FromJust()) {
1112     // 10.a. If IsDataDescriptor(targetDesc) and targetDesc.[[Configurable]] is
1113     //       false and targetDesc.[[Writable]] is false, then
1114     // 10.a.i. If SameValue(trapResult, targetDesc.[[Value]]) is false,
1115     //        throw a TypeError exception.
1116     bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
1117                         !target_desc.configurable() &&
1118                         !target_desc.writable() &&
1119                         !trap_result->SameValue(*target_desc.value());
1120     if (inconsistent) {
1121       if (access_kind == kGet) {
1122         THROW_NEW_ERROR(
1123             isolate,
1124             NewTypeError(MessageTemplate::kProxyGetNonConfigurableData, name,
1125                          target_desc.value(), trap_result),
1126             Object);
1127       } else {
1128         isolate->Throw(*isolate->factory()->NewTypeError(
1129             MessageTemplate::kProxySetFrozenData, name));
1130         return MaybeHandle<Object>();
1131       }
1132     }
1133     // 10.b. If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]]
1134     //       is false and targetDesc.[[Get]] is undefined, then
1135     // 10.b.i. If trapResult is not undefined, throw a TypeError exception.
1136     if (access_kind == kGet) {
1137       inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
1138                      !target_desc.configurable() &&
1139                      target_desc.get()->IsUndefined(isolate) &&
1140                      !trap_result->IsUndefined(isolate);
1141     } else {
1142       inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
1143                      !target_desc.configurable() &&
1144                      target_desc.set()->IsUndefined(isolate);
1145     }
1146     if (inconsistent) {
1147       if (access_kind == kGet) {
1148         THROW_NEW_ERROR(
1149             isolate,
1150             NewTypeError(MessageTemplate::kProxyGetNonConfigurableAccessor,
1151                          name, trap_result),
1152             Object);
1153       } else {
1154         isolate->Throw(*isolate->factory()->NewTypeError(
1155             MessageTemplate::kProxySetFrozenAccessor, name));
1156         return MaybeHandle<Object>();
1157       }
1158     }
1159   }
1160   return isolate->factory()->undefined_value();
1161 }
1162 
1163 
GetDataProperty(LookupIterator * it)1164 Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it) {
1165   for (; it->IsFound(); it->Next()) {
1166     switch (it->state()) {
1167       case LookupIterator::INTERCEPTOR:
1168       case LookupIterator::NOT_FOUND:
1169       case LookupIterator::TRANSITION:
1170         UNREACHABLE();
1171       case LookupIterator::ACCESS_CHECK:
1172         // Support calling this method without an active context, but refuse
1173         // access to access-checked objects in that case.
1174         if (it->isolate()->context() != nullptr && it->HasAccess()) continue;
1175         V8_FALLTHROUGH;
1176       case LookupIterator::JSPROXY:
1177         it->NotFound();
1178         return it->isolate()->factory()->undefined_value();
1179       case LookupIterator::ACCESSOR:
1180         // TODO(verwaest): For now this doesn't call into AccessorInfo, since
1181         // clients don't need it. Update once relevant.
1182         it->NotFound();
1183         return it->isolate()->factory()->undefined_value();
1184       case LookupIterator::INTEGER_INDEXED_EXOTIC:
1185         return it->isolate()->factory()->undefined_value();
1186       case LookupIterator::DATA:
1187         return it->GetDataValue();
1188     }
1189   }
1190   return it->isolate()->factory()->undefined_value();
1191 }
1192 
1193 
ToInt32(int32_t * value)1194 bool Object::ToInt32(int32_t* value) {
1195   if (IsSmi()) {
1196     *value = Smi::ToInt(this);
1197     return true;
1198   }
1199   if (IsHeapNumber()) {
1200     double num = HeapNumber::cast(this)->value();
1201     // Check range before conversion to avoid undefined behavior.
1202     if (num >= kMinInt && num <= kMaxInt && FastI2D(FastD2I(num)) == num) {
1203       *value = FastD2I(num);
1204       return true;
1205     }
1206   }
1207   return false;
1208 }
1209 
GetOrCreateSharedFunctionInfo(Isolate * isolate,Handle<FunctionTemplateInfo> info,MaybeHandle<Name> maybe_name)1210 Handle<SharedFunctionInfo> FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(
1211     Isolate* isolate, Handle<FunctionTemplateInfo> info,
1212     MaybeHandle<Name> maybe_name) {
1213   Object* current_info = info->shared_function_info();
1214   if (current_info->IsSharedFunctionInfo()) {
1215     return handle(SharedFunctionInfo::cast(current_info), isolate);
1216   }
1217   Handle<Name> name;
1218   Handle<String> name_string;
1219   if (maybe_name.ToHandle(&name) && name->IsString()) {
1220     name_string = Handle<String>::cast(name);
1221   } else if (info->class_name()->IsString()) {
1222     name_string = handle(String::cast(info->class_name()));
1223   } else {
1224     name_string = isolate->factory()->empty_string();
1225   }
1226   FunctionKind function_kind;
1227   if (info->remove_prototype()) {
1228     function_kind = kConciseMethod;
1229   } else {
1230     function_kind = kNormalFunction;
1231   }
1232   Handle<SharedFunctionInfo> result =
1233       isolate->factory()->NewSharedFunctionInfoForApiFunction(name_string, info,
1234                                                               function_kind);
1235 
1236   result->set_length(info->length());
1237   result->DontAdaptArguments();
1238   DCHECK(result->IsApiFunction());
1239 
1240   info->set_shared_function_info(*result);
1241   return result;
1242 }
1243 
IsTemplateFor(Map * map)1244 bool FunctionTemplateInfo::IsTemplateFor(Map* map) {
1245   // There is a constraint on the object; check.
1246   if (!map->IsJSObjectMap()) return false;
1247   // Fetch the constructor function of the object.
1248   Object* cons_obj = map->GetConstructor();
1249   Object* type;
1250   if (cons_obj->IsJSFunction()) {
1251     JSFunction* fun = JSFunction::cast(cons_obj);
1252     type = fun->shared()->function_data();
1253   } else if (cons_obj->IsFunctionTemplateInfo()) {
1254     type = FunctionTemplateInfo::cast(cons_obj);
1255   } else {
1256     return false;
1257   }
1258   // Iterate through the chain of inheriting function templates to
1259   // see if the required one occurs.
1260   while (type->IsFunctionTemplateInfo()) {
1261     if (type == this) return true;
1262     type = FunctionTemplateInfo::cast(type)->parent_template();
1263   }
1264   // Didn't find the required type in the inheritance chain.
1265   return false;
1266 }
1267 
1268 
1269 // static
New(Isolate * isolate,int size)1270 Handle<TemplateList> TemplateList::New(Isolate* isolate, int size) {
1271   Handle<FixedArray> list =
1272       isolate->factory()->NewFixedArray(kLengthIndex + size);
1273   list->set(kLengthIndex, Smi::kZero);
1274   return Handle<TemplateList>::cast(list);
1275 }
1276 
1277 // static
Add(Isolate * isolate,Handle<TemplateList> list,Handle<i::Object> value)1278 Handle<TemplateList> TemplateList::Add(Isolate* isolate,
1279                                        Handle<TemplateList> list,
1280                                        Handle<i::Object> value) {
1281   STATIC_ASSERT(kFirstElementIndex == 1);
1282   int index = list->length() + 1;
1283   Handle<i::FixedArray> fixed_array = Handle<FixedArray>::cast(list);
1284   fixed_array = FixedArray::SetAndGrow(fixed_array, index, value);
1285   fixed_array->set(kLengthIndex, Smi::FromInt(index));
1286   return Handle<TemplateList>::cast(fixed_array);
1287 }
1288 
1289 // static
New(Handle<JSFunction> constructor,Handle<JSReceiver> new_target,Handle<AllocationSite> site)1290 MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor,
1291                                     Handle<JSReceiver> new_target,
1292                                     Handle<AllocationSite> site) {
1293   // If called through new, new.target can be:
1294   // - a subclass of constructor,
1295   // - a proxy wrapper around constructor, or
1296   // - the constructor itself.
1297   // If called through Reflect.construct, it's guaranteed to be a constructor.
1298   Isolate* const isolate = constructor->GetIsolate();
1299   DCHECK(constructor->IsConstructor());
1300   DCHECK(new_target->IsConstructor());
1301   DCHECK(!constructor->has_initial_map() ||
1302          constructor->initial_map()->instance_type() != JS_FUNCTION_TYPE);
1303 
1304   Handle<Map> initial_map;
1305   ASSIGN_RETURN_ON_EXCEPTION(
1306       isolate, initial_map,
1307       JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject);
1308   Handle<JSObject> result =
1309       isolate->factory()->NewJSObjectFromMap(initial_map, NOT_TENURED, site);
1310   if (initial_map->is_dictionary_map()) {
1311     Handle<NameDictionary> dictionary =
1312         NameDictionary::New(isolate, NameDictionary::kInitialCapacity);
1313     result->SetProperties(*dictionary);
1314   }
1315   isolate->counters()->constructed_objects()->Increment();
1316   isolate->counters()->constructed_objects_runtime()->Increment();
1317   return result;
1318 }
1319 
EnsureWritableFastElements(Handle<JSObject> object)1320 void JSObject::EnsureWritableFastElements(Handle<JSObject> object) {
1321   DCHECK(object->HasSmiOrObjectElements() ||
1322          object->HasFastStringWrapperElements());
1323   FixedArray* raw_elems = FixedArray::cast(object->elements());
1324   Heap* heap = object->GetHeap();
1325   if (raw_elems->map() != heap->fixed_cow_array_map()) return;
1326   Isolate* isolate = heap->isolate();
1327   Handle<FixedArray> elems(raw_elems, isolate);
1328   Handle<FixedArray> writable_elems = isolate->factory()->CopyFixedArrayWithMap(
1329       elems, isolate->factory()->fixed_array_map());
1330   object->set_elements(*writable_elems);
1331   isolate->counters()->cow_arrays_converted()->Increment();
1332 }
1333 
GetHeaderSize(InstanceType type,bool function_has_prototype_slot)1334 int JSObject::GetHeaderSize(InstanceType type,
1335                             bool function_has_prototype_slot) {
1336   switch (type) {
1337     case JS_OBJECT_TYPE:
1338     case JS_API_OBJECT_TYPE:
1339     case JS_SPECIAL_API_OBJECT_TYPE:
1340       return JSObject::kHeaderSize;
1341     case JS_GENERATOR_OBJECT_TYPE:
1342       return JSGeneratorObject::kSize;
1343     case JS_ASYNC_GENERATOR_OBJECT_TYPE:
1344       return JSAsyncGeneratorObject::kSize;
1345     case JS_GLOBAL_PROXY_TYPE:
1346       return JSGlobalProxy::kSize;
1347     case JS_GLOBAL_OBJECT_TYPE:
1348       return JSGlobalObject::kSize;
1349     case JS_BOUND_FUNCTION_TYPE:
1350       return JSBoundFunction::kSize;
1351     case JS_FUNCTION_TYPE:
1352       return JSFunction::GetHeaderSize(function_has_prototype_slot);
1353     case JS_VALUE_TYPE:
1354       return JSValue::kSize;
1355     case JS_DATE_TYPE:
1356       return JSDate::kSize;
1357     case JS_ARRAY_TYPE:
1358       return JSArray::kSize;
1359     case JS_ARRAY_BUFFER_TYPE:
1360       return JSArrayBuffer::kSize;
1361     case JS_ARRAY_ITERATOR_TYPE:
1362       return JSArrayIterator::kSize;
1363     case JS_TYPED_ARRAY_TYPE:
1364       return JSTypedArray::kSize;
1365     case JS_DATA_VIEW_TYPE:
1366       return JSDataView::kSize;
1367     case JS_SET_TYPE:
1368       return JSSet::kSize;
1369     case JS_MAP_TYPE:
1370       return JSMap::kSize;
1371     case JS_SET_KEY_VALUE_ITERATOR_TYPE:
1372     case JS_SET_VALUE_ITERATOR_TYPE:
1373       return JSSetIterator::kSize;
1374     case JS_MAP_KEY_ITERATOR_TYPE:
1375     case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
1376     case JS_MAP_VALUE_ITERATOR_TYPE:
1377       return JSMapIterator::kSize;
1378     case JS_WEAK_MAP_TYPE:
1379       return JSWeakMap::kSize;
1380     case JS_WEAK_SET_TYPE:
1381       return JSWeakSet::kSize;
1382     case JS_PROMISE_TYPE:
1383       return JSPromise::kSize;
1384     case JS_REGEXP_TYPE:
1385       return JSRegExp::kSize;
1386     case JS_REGEXP_STRING_ITERATOR_TYPE:
1387       return JSRegExpStringIterator::kSize;
1388     case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
1389       return JSObject::kHeaderSize;
1390     case JS_MESSAGE_OBJECT_TYPE:
1391       return JSMessageObject::kSize;
1392     case JS_ARGUMENTS_TYPE:
1393       return JSObject::kHeaderSize;
1394     case JS_ERROR_TYPE:
1395       return JSObject::kHeaderSize;
1396     case JS_STRING_ITERATOR_TYPE:
1397       return JSStringIterator::kSize;
1398     case JS_MODULE_NAMESPACE_TYPE:
1399       return JSModuleNamespace::kHeaderSize;
1400 #ifdef V8_INTL_SUPPORT
1401     case JS_INTL_LOCALE_TYPE:
1402       return JSLocale::kSize;
1403 #endif  // V8_INTL_SUPPORT
1404     case WASM_GLOBAL_TYPE:
1405       return WasmGlobalObject::kSize;
1406     case WASM_INSTANCE_TYPE:
1407       return WasmInstanceObject::kSize;
1408     case WASM_MEMORY_TYPE:
1409       return WasmMemoryObject::kSize;
1410     case WASM_MODULE_TYPE:
1411       return WasmModuleObject::kSize;
1412     case WASM_TABLE_TYPE:
1413       return WasmTableObject::kSize;
1414     default:
1415       UNREACHABLE();
1416   }
1417 }
1418 
1419 // ES6 9.5.1
1420 // static
GetPrototype(Handle<JSProxy> proxy)1421 MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
1422   Isolate* isolate = proxy->GetIsolate();
1423   Handle<String> trap_name = isolate->factory()->getPrototypeOf_string();
1424 
1425   STACK_CHECK(isolate, MaybeHandle<Object>());
1426 
1427   // 1. Let handler be the value of the [[ProxyHandler]] internal slot.
1428   // 2. If handler is null, throw a TypeError exception.
1429   // 3. Assert: Type(handler) is Object.
1430   // 4. Let target be the value of the [[ProxyTarget]] internal slot.
1431   if (proxy->IsRevoked()) {
1432     THROW_NEW_ERROR(isolate,
1433                     NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1434                     Object);
1435   }
1436   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
1437   Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
1438 
1439   // 5. Let trap be ? GetMethod(handler, "getPrototypeOf").
1440   Handle<Object> trap;
1441   ASSIGN_RETURN_ON_EXCEPTION(isolate, trap, GetMethod(handler, trap_name),
1442                              Object);
1443   // 6. If trap is undefined, then return target.[[GetPrototypeOf]]().
1444   if (trap->IsUndefined(isolate)) {
1445     return JSReceiver::GetPrototype(isolate, target);
1446   }
1447   // 7. Let handlerProto be ? Call(trap, handler, «target»).
1448   Handle<Object> argv[] = {target};
1449   Handle<Object> handler_proto;
1450   ASSIGN_RETURN_ON_EXCEPTION(
1451       isolate, handler_proto,
1452       Execution::Call(isolate, trap, handler, arraysize(argv), argv), Object);
1453   // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError.
1454   if (!(handler_proto->IsJSReceiver() || handler_proto->IsNull(isolate))) {
1455     THROW_NEW_ERROR(isolate,
1456                     NewTypeError(MessageTemplate::kProxyGetPrototypeOfInvalid),
1457                     Object);
1458   }
1459   // 9. Let extensibleTarget be ? IsExtensible(target).
1460   Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
1461   MAYBE_RETURN_NULL(is_extensible);
1462   // 10. If extensibleTarget is true, return handlerProto.
1463   if (is_extensible.FromJust()) return handler_proto;
1464   // 11. Let targetProto be ? target.[[GetPrototypeOf]]().
1465   Handle<Object> target_proto;
1466   ASSIGN_RETURN_ON_EXCEPTION(isolate, target_proto,
1467                              JSReceiver::GetPrototype(isolate, target), Object);
1468   // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError.
1469   if (!handler_proto->SameValue(*target_proto)) {
1470     THROW_NEW_ERROR(
1471         isolate,
1472         NewTypeError(MessageTemplate::kProxyGetPrototypeOfNonExtensible),
1473         Object);
1474   }
1475   // 13. Return handlerProto.
1476   return handler_proto;
1477 }
1478 
GetPropertyWithAccessor(LookupIterator * it)1479 MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) {
1480   Isolate* isolate = it->isolate();
1481   Handle<Object> structure = it->GetAccessors();
1482   Handle<Object> receiver = it->GetReceiver();
1483   // In case of global IC, the receiver is the global object. Replace by the
1484   // global proxy.
1485   if (receiver->IsJSGlobalObject()) {
1486     receiver = handle(JSGlobalObject::cast(*receiver)->global_proxy(), isolate);
1487   }
1488 
1489   // We should never get here to initialize a const with the hole value since a
1490   // const declaration would conflict with the getter.
1491   DCHECK(!structure->IsForeign());
1492 
1493   // API style callbacks.
1494   Handle<JSObject> holder = it->GetHolder<JSObject>();
1495   if (structure->IsAccessorInfo()) {
1496     Handle<Name> name = it->GetName();
1497     Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
1498     if (!info->IsCompatibleReceiver(*receiver)) {
1499       THROW_NEW_ERROR(isolate,
1500                       NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
1501                                    name, receiver),
1502                       Object);
1503     }
1504 
1505     if (!info->has_getter()) return isolate->factory()->undefined_value();
1506 
1507     if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1508       ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver,
1509                                  Object::ConvertReceiver(isolate, receiver),
1510                                  Object);
1511     }
1512 
1513     PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1514                                    kDontThrow);
1515     Handle<Object> result = args.CallAccessorGetter(info, name);
1516     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1517     if (result.is_null()) return isolate->factory()->undefined_value();
1518     Handle<Object> reboxed_result = handle(*result, isolate);
1519     if (info->replace_on_access() && receiver->IsJSReceiver()) {
1520       RETURN_ON_EXCEPTION(isolate,
1521                           Accessors::ReplaceAccessorWithDataProperty(
1522                               isolate, receiver, holder, name, result),
1523                           Object);
1524     }
1525     return reboxed_result;
1526   }
1527 
1528   // AccessorPair with 'cached' private property.
1529   if (it->TryLookupCachedProperty()) {
1530     return Object::GetProperty(it);
1531   }
1532 
1533   // Regular accessor.
1534   Handle<Object> getter(AccessorPair::cast(*structure)->getter(), isolate);
1535   if (getter->IsFunctionTemplateInfo()) {
1536     SaveContext save(isolate);
1537     isolate->set_context(*holder->GetCreationContext());
1538     return Builtins::InvokeApiFunction(
1539         isolate, false, Handle<FunctionTemplateInfo>::cast(getter), receiver, 0,
1540         nullptr, isolate->factory()->undefined_value());
1541   } else if (getter->IsCallable()) {
1542     // TODO(rossberg): nicer would be to cast to some JSCallable here...
1543     return Object::GetPropertyWithDefinedGetter(
1544         receiver, Handle<JSReceiver>::cast(getter));
1545   }
1546   // Getter is not a function.
1547   return isolate->factory()->undefined_value();
1548 }
1549 
1550 // static
redirect(Isolate * isolate,Address address,AccessorComponent component)1551 Address AccessorInfo::redirect(Isolate* isolate, Address address,
1552                                AccessorComponent component) {
1553   ApiFunction fun(address);
1554   DCHECK_EQ(ACCESSOR_GETTER, component);
1555   ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
1556   return ExternalReference::Create(&fun, type).address();
1557 }
1558 
redirected_getter() const1559 Address AccessorInfo::redirected_getter() const {
1560   Address accessor = v8::ToCData<Address>(getter());
1561   if (accessor == kNullAddress) return kNullAddress;
1562   return redirect(GetIsolate(), accessor, ACCESSOR_GETTER);
1563 }
1564 
redirected_callback() const1565 Address CallHandlerInfo::redirected_callback() const {
1566   Address address = v8::ToCData<Address>(callback());
1567   ApiFunction fun(address);
1568   ExternalReference::Type type = ExternalReference::DIRECT_API_CALL;
1569   return ExternalReference::Create(&fun, type).address();
1570 }
1571 
IsCompatibleReceiverMap(Isolate * isolate,Handle<AccessorInfo> info,Handle<Map> map)1572 bool AccessorInfo::IsCompatibleReceiverMap(Isolate* isolate,
1573                                            Handle<AccessorInfo> info,
1574                                            Handle<Map> map) {
1575   if (!info->HasExpectedReceiverType()) return true;
1576   if (!map->IsJSObjectMap()) return false;
1577   return FunctionTemplateInfo::cast(info->expected_receiver_type())
1578       ->IsTemplateFor(*map);
1579 }
1580 
SetPropertyWithAccessor(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)1581 Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it,
1582                                             Handle<Object> value,
1583                                             ShouldThrow should_throw) {
1584   Isolate* isolate = it->isolate();
1585   Handle<Object> structure = it->GetAccessors();
1586   Handle<Object> receiver = it->GetReceiver();
1587   // In case of global IC, the receiver is the global object. Replace by the
1588   // global proxy.
1589   if (receiver->IsJSGlobalObject()) {
1590     receiver = handle(JSGlobalObject::cast(*receiver)->global_proxy(), isolate);
1591   }
1592 
1593   // We should never get here to initialize a const with the hole value since a
1594   // const declaration would conflict with the setter.
1595   DCHECK(!structure->IsForeign());
1596 
1597   // API style callbacks.
1598   Handle<JSObject> holder = it->GetHolder<JSObject>();
1599   if (structure->IsAccessorInfo()) {
1600     Handle<Name> name = it->GetName();
1601     Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
1602     if (!info->IsCompatibleReceiver(*receiver)) {
1603       isolate->Throw(*isolate->factory()->NewTypeError(
1604           MessageTemplate::kIncompatibleMethodReceiver, name, receiver));
1605       return Nothing<bool>();
1606     }
1607 
1608     if (!info->has_setter()) {
1609       // TODO(verwaest): We should not get here anymore once all AccessorInfos
1610       // are marked as special_data_property. They cannot both be writable and
1611       // not have a setter.
1612       return Just(true);
1613     }
1614 
1615     if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1616       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1617           isolate, receiver, Object::ConvertReceiver(isolate, receiver),
1618           Nothing<bool>());
1619     }
1620 
1621     // The actual type of setter callback is either
1622     // v8::AccessorNameSetterCallback or
1623     // i::Accesors::AccessorNameBooleanSetterCallback, depending on whether the
1624     // AccessorInfo was created by the API or internally (see accessors.cc).
1625     // Here we handle both cases using GenericNamedPropertySetterCallback and
1626     // its Call method.
1627     PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1628                                    should_throw);
1629     Handle<Object> result = args.CallAccessorSetter(info, name, value);
1630     // In the case of AccessorNameSetterCallback, we know that the result value
1631     // cannot have been set, so the result of Call will be null.  In the case of
1632     // AccessorNameBooleanSetterCallback, the result will either be null
1633     // (signalling an exception) or a boolean Oddball.
1634     RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1635     if (result.is_null()) return Just(true);
1636     DCHECK(result->BooleanValue() || should_throw == kDontThrow);
1637     return Just(result->BooleanValue());
1638   }
1639 
1640   // Regular accessor.
1641   Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
1642   if (setter->IsFunctionTemplateInfo()) {
1643     SaveContext save(isolate);
1644     isolate->set_context(*holder->GetCreationContext());
1645     Handle<Object> argv[] = {value};
1646     RETURN_ON_EXCEPTION_VALUE(
1647         isolate, Builtins::InvokeApiFunction(
1648                      isolate, false, Handle<FunctionTemplateInfo>::cast(setter),
1649                      receiver, arraysize(argv), argv,
1650                      isolate->factory()->undefined_value()),
1651         Nothing<bool>());
1652     return Just(true);
1653   } else if (setter->IsCallable()) {
1654     // TODO(rossberg): nicer would be to cast to some JSCallable here...
1655     return SetPropertyWithDefinedSetter(
1656         receiver, Handle<JSReceiver>::cast(setter), value, should_throw);
1657   }
1658 
1659   RETURN_FAILURE(isolate, should_throw,
1660                  NewTypeError(MessageTemplate::kNoSetterInCallback,
1661                               it->GetName(), it->GetHolder<JSObject>()));
1662 }
1663 
1664 
GetPropertyWithDefinedGetter(Handle<Object> receiver,Handle<JSReceiver> getter)1665 MaybeHandle<Object> Object::GetPropertyWithDefinedGetter(
1666     Handle<Object> receiver,
1667     Handle<JSReceiver> getter) {
1668   Isolate* isolate = getter->GetIsolate();
1669 
1670   // Platforms with simulators like arm/arm64 expose a funny issue. If the
1671   // simulator has a separate JS stack pointer from the C++ stack pointer, it
1672   // can miss C++ stack overflows in the stack guard at the start of JavaScript
1673   // functions. It would be very expensive to check the C++ stack pointer at
1674   // that location. The best solution seems to be to break the impasse by
1675   // adding checks at possible recursion points. What's more, we don't put
1676   // this stack check behind the USE_SIMULATOR define in order to keep
1677   // behavior the same between hardware and simulators.
1678   StackLimitCheck check(isolate);
1679   if (check.JsHasOverflowed()) {
1680     isolate->StackOverflow();
1681     return MaybeHandle<Object>();
1682   }
1683 
1684   return Execution::Call(isolate, getter, receiver, 0, nullptr);
1685 }
1686 
1687 
SetPropertyWithDefinedSetter(Handle<Object> receiver,Handle<JSReceiver> setter,Handle<Object> value,ShouldThrow should_throw)1688 Maybe<bool> Object::SetPropertyWithDefinedSetter(Handle<Object> receiver,
1689                                                  Handle<JSReceiver> setter,
1690                                                  Handle<Object> value,
1691                                                  ShouldThrow should_throw) {
1692   Isolate* isolate = setter->GetIsolate();
1693 
1694   Handle<Object> argv[] = { value };
1695   RETURN_ON_EXCEPTION_VALUE(isolate, Execution::Call(isolate, setter, receiver,
1696                                                      arraysize(argv), argv),
1697                             Nothing<bool>());
1698   return Just(true);
1699 }
1700 
1701 
1702 // static
AllCanRead(LookupIterator * it)1703 bool JSObject::AllCanRead(LookupIterator* it) {
1704   // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of
1705   // which have already been checked.
1706   DCHECK(it->state() == LookupIterator::ACCESS_CHECK ||
1707          it->state() == LookupIterator::INTERCEPTOR);
1708   for (it->Next(); it->IsFound(); it->Next()) {
1709     if (it->state() == LookupIterator::ACCESSOR) {
1710       auto accessors = it->GetAccessors();
1711       if (accessors->IsAccessorInfo()) {
1712         if (AccessorInfo::cast(*accessors)->all_can_read()) return true;
1713       }
1714     } else if (it->state() == LookupIterator::INTERCEPTOR) {
1715       if (it->GetInterceptor()->all_can_read()) return true;
1716     } else if (it->state() == LookupIterator::JSPROXY) {
1717       // Stop lookupiterating. And no, AllCanNotRead.
1718       return false;
1719     }
1720   }
1721   return false;
1722 }
1723 
1724 namespace {
1725 
GetPropertyWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor,bool * done)1726 MaybeHandle<Object> GetPropertyWithInterceptorInternal(
1727     LookupIterator* it, Handle<InterceptorInfo> interceptor, bool* done) {
1728   *done = false;
1729   Isolate* isolate = it->isolate();
1730   // Make sure that the top context does not change when doing callbacks or
1731   // interceptor calls.
1732   AssertNoContextChange ncc(isolate);
1733 
1734   if (interceptor->getter()->IsUndefined(isolate)) {
1735     return isolate->factory()->undefined_value();
1736   }
1737 
1738   Handle<JSObject> holder = it->GetHolder<JSObject>();
1739   Handle<Object> result;
1740   Handle<Object> receiver = it->GetReceiver();
1741   if (!receiver->IsJSReceiver()) {
1742     ASSIGN_RETURN_ON_EXCEPTION(
1743         isolate, receiver, Object::ConvertReceiver(isolate, receiver), Object);
1744   }
1745   PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1746                                  *holder, kDontThrow);
1747 
1748   if (it->IsElement()) {
1749     result = args.CallIndexedGetter(interceptor, it->index());
1750   } else {
1751     result = args.CallNamedGetter(interceptor, it->name());
1752   }
1753 
1754   RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1755   if (result.is_null()) return isolate->factory()->undefined_value();
1756   *done = true;
1757   // Rebox handle before return
1758   return handle(*result, isolate);
1759 }
1760 
GetPropertyAttributesWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor)1761 Maybe<PropertyAttributes> GetPropertyAttributesWithInterceptorInternal(
1762     LookupIterator* it, Handle<InterceptorInfo> interceptor) {
1763   Isolate* isolate = it->isolate();
1764   // Make sure that the top context does not change when doing
1765   // callbacks or interceptor calls.
1766   AssertNoContextChange ncc(isolate);
1767   HandleScope scope(isolate);
1768 
1769   Handle<JSObject> holder = it->GetHolder<JSObject>();
1770   DCHECK_IMPLIES(!it->IsElement() && it->name()->IsSymbol(),
1771                  interceptor->can_intercept_symbols());
1772   Handle<Object> receiver = it->GetReceiver();
1773   if (!receiver->IsJSReceiver()) {
1774     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1775                                      Object::ConvertReceiver(isolate, receiver),
1776                                      Nothing<PropertyAttributes>());
1777   }
1778   PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1779                                  *holder, kDontThrow);
1780   if (!interceptor->query()->IsUndefined(isolate)) {
1781     Handle<Object> result;
1782     if (it->IsElement()) {
1783       result = args.CallIndexedQuery(interceptor, it->index());
1784     } else {
1785       result = args.CallNamedQuery(interceptor, it->name());
1786     }
1787     if (!result.is_null()) {
1788       int32_t value;
1789       CHECK(result->ToInt32(&value));
1790       return Just(static_cast<PropertyAttributes>(value));
1791     }
1792   } else if (!interceptor->getter()->IsUndefined(isolate)) {
1793     // TODO(verwaest): Use GetPropertyWithInterceptor?
1794     Handle<Object> result;
1795     if (it->IsElement()) {
1796       result = args.CallIndexedGetter(interceptor, it->index());
1797     } else {
1798       result = args.CallNamedGetter(interceptor, it->name());
1799     }
1800     if (!result.is_null()) return Just(DONT_ENUM);
1801   }
1802 
1803   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
1804   return Just(ABSENT);
1805 }
1806 
SetPropertyWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor,ShouldThrow should_throw,Handle<Object> value)1807 Maybe<bool> SetPropertyWithInterceptorInternal(
1808     LookupIterator* it, Handle<InterceptorInfo> interceptor,
1809     ShouldThrow should_throw, Handle<Object> value) {
1810   Isolate* isolate = it->isolate();
1811   // Make sure that the top context does not change when doing callbacks or
1812   // interceptor calls.
1813   AssertNoContextChange ncc(isolate);
1814 
1815   if (interceptor->setter()->IsUndefined(isolate)) return Just(false);
1816 
1817   Handle<JSObject> holder = it->GetHolder<JSObject>();
1818   bool result;
1819   Handle<Object> receiver = it->GetReceiver();
1820   if (!receiver->IsJSReceiver()) {
1821     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1822                                      Object::ConvertReceiver(isolate, receiver),
1823                                      Nothing<bool>());
1824   }
1825   PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1826                                  *holder, should_throw);
1827 
1828   if (it->IsElement()) {
1829     // TODO(neis): In the future, we may want to actually return the
1830     // interceptor's result, which then should be a boolean.
1831     result = !args.CallIndexedSetter(interceptor, it->index(), value).is_null();
1832   } else {
1833     result = !args.CallNamedSetter(interceptor, it->name(), value).is_null();
1834   }
1835 
1836   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1837   return Just(result);
1838 }
1839 
DefinePropertyWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor,ShouldThrow should_throw,PropertyDescriptor & desc)1840 Maybe<bool> DefinePropertyWithInterceptorInternal(
1841     LookupIterator* it, Handle<InterceptorInfo> interceptor,
1842     ShouldThrow should_throw, PropertyDescriptor& desc) {
1843   Isolate* isolate = it->isolate();
1844   // Make sure that the top context does not change when doing callbacks or
1845   // interceptor calls.
1846   AssertNoContextChange ncc(isolate);
1847 
1848   if (interceptor->definer()->IsUndefined(isolate)) return Just(false);
1849 
1850   Handle<JSObject> holder = it->GetHolder<JSObject>();
1851   bool result;
1852   Handle<Object> receiver = it->GetReceiver();
1853   if (!receiver->IsJSReceiver()) {
1854     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1855                                      Object::ConvertReceiver(isolate, receiver),
1856                                      Nothing<bool>());
1857   }
1858   PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1859                                  *holder, should_throw);
1860 
1861   std::unique_ptr<v8::PropertyDescriptor> descriptor(
1862       new v8::PropertyDescriptor());
1863   if (PropertyDescriptor::IsAccessorDescriptor(&desc)) {
1864     descriptor.reset(new v8::PropertyDescriptor(
1865         v8::Utils::ToLocal(desc.get()), v8::Utils::ToLocal(desc.set())));
1866   } else if (PropertyDescriptor::IsDataDescriptor(&desc)) {
1867     if (desc.has_writable()) {
1868       descriptor.reset(new v8::PropertyDescriptor(
1869           v8::Utils::ToLocal(desc.value()), desc.writable()));
1870     } else {
1871       descriptor.reset(
1872           new v8::PropertyDescriptor(v8::Utils::ToLocal(desc.value())));
1873     }
1874   }
1875   if (desc.has_enumerable()) {
1876     descriptor->set_enumerable(desc.enumerable());
1877   }
1878   if (desc.has_configurable()) {
1879     descriptor->set_configurable(desc.configurable());
1880   }
1881 
1882   if (it->IsElement()) {
1883     result = !args.CallIndexedDefiner(interceptor, it->index(), *descriptor)
1884                   .is_null();
1885   } else {
1886     result =
1887         !args.CallNamedDefiner(interceptor, it->name(), *descriptor).is_null();
1888   }
1889 
1890   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1891   return Just(result);
1892 }
1893 
1894 }  // namespace
1895 
GetPropertyWithFailedAccessCheck(LookupIterator * it)1896 MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
1897     LookupIterator* it) {
1898   Isolate* isolate = it->isolate();
1899   Handle<JSObject> checked = it->GetHolder<JSObject>();
1900   Handle<InterceptorInfo> interceptor =
1901       it->GetInterceptorForFailedAccessCheck();
1902   if (interceptor.is_null()) {
1903     while (AllCanRead(it)) {
1904       if (it->state() == LookupIterator::ACCESSOR) {
1905         return GetPropertyWithAccessor(it);
1906       }
1907       DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
1908       bool done;
1909       Handle<Object> result;
1910       ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
1911                                  GetPropertyWithInterceptor(it, &done), Object);
1912       if (done) return result;
1913     }
1914 
1915   } else {
1916     Handle<Object> result;
1917     bool done;
1918     ASSIGN_RETURN_ON_EXCEPTION(
1919         isolate, result,
1920         GetPropertyWithInterceptorInternal(it, interceptor, &done), Object);
1921     if (done) return result;
1922   }
1923 
1924   // Cross-Origin [[Get]] of Well-Known Symbols does not throw, and returns
1925   // undefined.
1926   Handle<Name> name = it->GetName();
1927   if (name->IsSymbol() && Symbol::cast(*name)->is_well_known_symbol()) {
1928     return it->factory()->undefined_value();
1929   }
1930 
1931   isolate->ReportFailedAccessCheck(checked);
1932   RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1933   return it->factory()->undefined_value();
1934 }
1935 
1936 
GetPropertyAttributesWithFailedAccessCheck(LookupIterator * it)1937 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
1938     LookupIterator* it) {
1939   Isolate* isolate = it->isolate();
1940   Handle<JSObject> checked = it->GetHolder<JSObject>();
1941   Handle<InterceptorInfo> interceptor =
1942       it->GetInterceptorForFailedAccessCheck();
1943   if (interceptor.is_null()) {
1944     while (AllCanRead(it)) {
1945       if (it->state() == LookupIterator::ACCESSOR) {
1946         return Just(it->property_attributes());
1947       }
1948       DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
1949       auto result = GetPropertyAttributesWithInterceptor(it);
1950       if (isolate->has_scheduled_exception()) break;
1951       if (result.IsJust() && result.FromJust() != ABSENT) return result;
1952     }
1953   } else {
1954     Maybe<PropertyAttributes> result =
1955         GetPropertyAttributesWithInterceptorInternal(it, interceptor);
1956     if (isolate->has_pending_exception()) return Nothing<PropertyAttributes>();
1957     if (result.FromMaybe(ABSENT) != ABSENT) return result;
1958   }
1959   isolate->ReportFailedAccessCheck(checked);
1960   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
1961   return Just(ABSENT);
1962 }
1963 
1964 
1965 // static
AllCanWrite(LookupIterator * it)1966 bool JSObject::AllCanWrite(LookupIterator* it) {
1967   for (; it->IsFound() && it->state() != LookupIterator::JSPROXY; it->Next()) {
1968     if (it->state() == LookupIterator::ACCESSOR) {
1969       Handle<Object> accessors = it->GetAccessors();
1970       if (accessors->IsAccessorInfo()) {
1971         if (AccessorInfo::cast(*accessors)->all_can_write()) return true;
1972       }
1973     }
1974   }
1975   return false;
1976 }
1977 
1978 
SetPropertyWithFailedAccessCheck(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)1979 Maybe<bool> JSObject::SetPropertyWithFailedAccessCheck(
1980     LookupIterator* it, Handle<Object> value, ShouldThrow should_throw) {
1981   Isolate* isolate = it->isolate();
1982   Handle<JSObject> checked = it->GetHolder<JSObject>();
1983   Handle<InterceptorInfo> interceptor =
1984       it->GetInterceptorForFailedAccessCheck();
1985   if (interceptor.is_null()) {
1986     if (AllCanWrite(it)) {
1987       return SetPropertyWithAccessor(it, value, should_throw);
1988     }
1989   } else {
1990     Maybe<bool> result = SetPropertyWithInterceptorInternal(
1991         it, interceptor, should_throw, value);
1992     if (isolate->has_pending_exception()) return Nothing<bool>();
1993     if (result.IsJust()) return result;
1994   }
1995   isolate->ReportFailedAccessCheck(checked);
1996   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1997   return Just(true);
1998 }
1999 
2000 
SetNormalizedProperty(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyDetails details)2001 void JSObject::SetNormalizedProperty(Handle<JSObject> object,
2002                                      Handle<Name> name,
2003                                      Handle<Object> value,
2004                                      PropertyDetails details) {
2005   DCHECK(!object->HasFastProperties());
2006   DCHECK(name->IsUniqueName());
2007   Isolate* isolate = object->GetIsolate();
2008 
2009   uint32_t hash = name->Hash();
2010 
2011   if (object->IsJSGlobalObject()) {
2012     Handle<JSGlobalObject> global_obj = Handle<JSGlobalObject>::cast(object);
2013     Handle<GlobalDictionary> dictionary(global_obj->global_dictionary());
2014     int entry = dictionary->FindEntry(isolate, name, hash);
2015 
2016     if (entry == GlobalDictionary::kNotFound) {
2017       DCHECK_IMPLIES(global_obj->map()->is_prototype_map(),
2018                      Map::IsPrototypeChainInvalidated(global_obj->map()));
2019       auto cell = isolate->factory()->NewPropertyCell(name);
2020       cell->set_value(*value);
2021       auto cell_type = value->IsUndefined(isolate)
2022                            ? PropertyCellType::kUndefined
2023                            : PropertyCellType::kConstant;
2024       details = details.set_cell_type(cell_type);
2025       value = cell;
2026       dictionary = GlobalDictionary::Add(dictionary, name, value, details);
2027       global_obj->set_global_dictionary(*dictionary);
2028     } else {
2029       Handle<PropertyCell> cell =
2030           PropertyCell::PrepareForValue(dictionary, entry, value, details);
2031       cell->set_value(*value);
2032     }
2033   } else {
2034     Handle<NameDictionary> dictionary(object->property_dictionary());
2035 
2036     int entry = dictionary->FindEntry(name);
2037     if (entry == NameDictionary::kNotFound) {
2038       DCHECK_IMPLIES(object->map()->is_prototype_map(),
2039                      Map::IsPrototypeChainInvalidated(object->map()));
2040       dictionary = NameDictionary::Add(dictionary, name, value, details);
2041       object->SetProperties(*dictionary);
2042     } else {
2043       PropertyDetails original_details = dictionary->DetailsAt(entry);
2044       int enumeration_index = original_details.dictionary_index();
2045       DCHECK_GT(enumeration_index, 0);
2046       details = details.set_index(enumeration_index);
2047       dictionary->SetEntry(entry, *name, *value, details);
2048     }
2049   }
2050 }
2051 
2052 // static
HasInPrototypeChain(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> proto)2053 Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate,
2054                                             Handle<JSReceiver> object,
2055                                             Handle<Object> proto) {
2056   PrototypeIterator iter(isolate, object, kStartAtReceiver);
2057   while (true) {
2058     if (!iter.AdvanceFollowingProxies()) return Nothing<bool>();
2059     if (iter.IsAtEnd()) return Just(false);
2060     if (PrototypeIterator::GetCurrent(iter).is_identical_to(proto)) {
2061       return Just(true);
2062     }
2063   }
2064 }
2065 
2066 namespace {
2067 
HasExcludedProperty(const ScopedVector<Handle<Object>> * excluded_properties,Handle<Object> search_element)2068 bool HasExcludedProperty(
2069     const ScopedVector<Handle<Object>>* excluded_properties,
2070     Handle<Object> search_element) {
2071   // TODO(gsathya): Change this to be a hashtable.
2072   for (int i = 0; i < excluded_properties->length(); i++) {
2073     if (search_element->SameValue(*excluded_properties->at(i))) {
2074       return true;
2075     }
2076   }
2077 
2078   return false;
2079 }
2080 
FastAssign(Handle<JSReceiver> target,Handle<Object> source,const ScopedVector<Handle<Object>> * excluded_properties,bool use_set)2081 V8_WARN_UNUSED_RESULT Maybe<bool> FastAssign(
2082     Handle<JSReceiver> target, Handle<Object> source,
2083     const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) {
2084   // Non-empty strings are the only non-JSReceivers that need to be handled
2085   // explicitly by Object.assign.
2086   if (!source->IsJSReceiver()) {
2087     return Just(!source->IsString() || String::cast(*source)->length() == 0);
2088   }
2089 
2090   // If the target is deprecated, the object will be updated on first store. If
2091   // the source for that store equals the target, this will invalidate the
2092   // cached representation of the source. Preventively upgrade the target.
2093   // Do this on each iteration since any property load could cause deprecation.
2094   if (target->map()->is_deprecated()) {
2095     JSObject::MigrateInstance(Handle<JSObject>::cast(target));
2096   }
2097 
2098   Isolate* isolate = target->GetIsolate();
2099   Handle<Map> map(JSReceiver::cast(*source)->map(), isolate);
2100 
2101   if (!map->IsJSObjectMap()) return Just(false);
2102   if (!map->OnlyHasSimpleProperties()) return Just(false);
2103 
2104   Handle<JSObject> from = Handle<JSObject>::cast(source);
2105   if (from->elements() != isolate->heap()->empty_fixed_array()) {
2106     return Just(false);
2107   }
2108 
2109   Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
2110   int length = map->NumberOfOwnDescriptors();
2111 
2112   bool stable = true;
2113 
2114   for (int i = 0; i < length; i++) {
2115     Handle<Name> next_key(descriptors->GetKey(i), isolate);
2116     Handle<Object> prop_value;
2117     // Directly decode from the descriptor array if |from| did not change shape.
2118     if (stable) {
2119       PropertyDetails details = descriptors->GetDetails(i);
2120       if (!details.IsEnumerable()) continue;
2121       if (details.kind() == kData) {
2122         if (details.location() == kDescriptor) {
2123           prop_value = handle(descriptors->GetValue(i), isolate);
2124         } else {
2125           Representation representation = details.representation();
2126           FieldIndex index = FieldIndex::ForDescriptor(*map, i);
2127           prop_value = JSObject::FastPropertyAt(from, representation, index);
2128         }
2129       } else {
2130         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2131             isolate, prop_value, JSReceiver::GetProperty(from, next_key),
2132             Nothing<bool>());
2133         stable = from->map() == *map;
2134       }
2135     } else {
2136       // If the map did change, do a slower lookup. We are still guaranteed that
2137       // the object has a simple shape, and that the key is a name.
2138       LookupIterator it(from, next_key, from,
2139                         LookupIterator::OWN_SKIP_INTERCEPTOR);
2140       if (!it.IsFound()) continue;
2141       DCHECK(it.state() == LookupIterator::DATA ||
2142              it.state() == LookupIterator::ACCESSOR);
2143       if (!it.IsEnumerable()) continue;
2144       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2145           isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
2146     }
2147 
2148     if (use_set) {
2149       LookupIterator it(target, next_key, target);
2150       Maybe<bool> result =
2151           Object::SetProperty(&it, prop_value, LanguageMode::kStrict,
2152                               Object::CERTAINLY_NOT_STORE_FROM_KEYED);
2153       if (result.IsNothing()) return result;
2154       if (stable) stable = from->map() == *map;
2155     } else {
2156       if (excluded_properties != nullptr &&
2157           HasExcludedProperty(excluded_properties, next_key)) {
2158         continue;
2159       }
2160 
2161       // 4a ii 2. Perform ? CreateDataProperty(target, nextKey, propValue).
2162       bool success;
2163       LookupIterator it = LookupIterator::PropertyOrElement(
2164           isolate, target, next_key, &success, LookupIterator::OWN);
2165       CHECK(success);
2166       CHECK(JSObject::CreateDataProperty(&it, prop_value, kThrowOnError)
2167                 .FromJust());
2168     }
2169   }
2170 
2171   return Just(true);
2172 }
2173 }  // namespace
2174 
2175 // static
SetOrCopyDataProperties(Isolate * isolate,Handle<JSReceiver> target,Handle<Object> source,const ScopedVector<Handle<Object>> * excluded_properties,bool use_set)2176 Maybe<bool> JSReceiver::SetOrCopyDataProperties(
2177     Isolate* isolate, Handle<JSReceiver> target, Handle<Object> source,
2178     const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) {
2179   Maybe<bool> fast_assign =
2180       FastAssign(target, source, excluded_properties, use_set);
2181   if (fast_assign.IsNothing()) return Nothing<bool>();
2182   if (fast_assign.FromJust()) return Just(true);
2183 
2184   Handle<JSReceiver> from = Object::ToObject(isolate, source).ToHandleChecked();
2185   // 3b. Let keys be ? from.[[OwnPropertyKeys]]().
2186   Handle<FixedArray> keys;
2187   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2188       isolate, keys,
2189       KeyAccumulator::GetKeys(from, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES,
2190                               GetKeysConversion::kKeepNumbers),
2191       Nothing<bool>());
2192 
2193   // 4. Repeat for each element nextKey of keys in List order,
2194   for (int j = 0; j < keys->length(); ++j) {
2195     Handle<Object> next_key(keys->get(j), isolate);
2196     // 4a i. Let desc be ? from.[[GetOwnProperty]](nextKey).
2197     PropertyDescriptor desc;
2198     Maybe<bool> found =
2199         JSReceiver::GetOwnPropertyDescriptor(isolate, from, next_key, &desc);
2200     if (found.IsNothing()) return Nothing<bool>();
2201     // 4a ii. If desc is not undefined and desc.[[Enumerable]] is true, then
2202     if (found.FromJust() && desc.enumerable()) {
2203       // 4a ii 1. Let propValue be ? Get(from, nextKey).
2204       Handle<Object> prop_value;
2205       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2206           isolate, prop_value,
2207           Runtime::GetObjectProperty(isolate, from, next_key), Nothing<bool>());
2208 
2209       if (use_set) {
2210         // 4c ii 2. Let status be ? Set(to, nextKey, propValue, true).
2211         Handle<Object> status;
2212         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2213             isolate, status,
2214             Runtime::SetObjectProperty(isolate, target, next_key, prop_value,
2215                                        LanguageMode::kStrict),
2216             Nothing<bool>());
2217       } else {
2218         if (excluded_properties != nullptr &&
2219             HasExcludedProperty(excluded_properties, next_key)) {
2220           continue;
2221         }
2222 
2223         // 4a ii 2. Perform ! CreateDataProperty(target, nextKey, propValue).
2224         bool success;
2225         LookupIterator it = LookupIterator::PropertyOrElement(
2226             isolate, target, next_key, &success, LookupIterator::OWN);
2227         CHECK(success);
2228         CHECK(JSObject::CreateDataProperty(&it, prop_value, kThrowOnError)
2229                   .FromJust());
2230       }
2231     }
2232   }
2233 
2234   return Just(true);
2235 }
2236 
GetPrototypeChainRootMap(Isolate * isolate) const2237 Map* Object::GetPrototypeChainRootMap(Isolate* isolate) const {
2238   DisallowHeapAllocation no_alloc;
2239   if (IsSmi()) {
2240     Context* native_context = isolate->context()->native_context();
2241     return native_context->number_function()->initial_map();
2242   }
2243 
2244   const HeapObject* heap_object = HeapObject::cast(this);
2245   return heap_object->map()->GetPrototypeChainRootMap(isolate);
2246 }
2247 
GetPrototypeChainRootMap(Isolate * isolate) const2248 Map* Map::GetPrototypeChainRootMap(Isolate* isolate) const {
2249   DisallowHeapAllocation no_alloc;
2250   if (IsJSReceiverMap()) {
2251     return const_cast<Map*>(this);
2252   }
2253   int constructor_function_index = GetConstructorFunctionIndex();
2254   if (constructor_function_index != Map::kNoConstructorFunctionIndex) {
2255     Context* native_context = isolate->context()->native_context();
2256     JSFunction* constructor_function =
2257         JSFunction::cast(native_context->get(constructor_function_index));
2258     return constructor_function->initial_map();
2259   }
2260   return isolate->heap()->null_value()->map();
2261 }
2262 
2263 // static
GetOrCreateHash(Isolate * isolate,Object * key)2264 Smi* Object::GetOrCreateHash(Isolate* isolate, Object* key) {
2265   DisallowHeapAllocation no_gc;
2266   return key->GetOrCreateHash(isolate);
2267 }
2268 
GetOrCreateHash(Isolate * isolate)2269 Smi* Object::GetOrCreateHash(Isolate* isolate) {
2270   DisallowHeapAllocation no_gc;
2271   Object* hash = Object::GetSimpleHash(this);
2272   if (hash->IsSmi()) return Smi::cast(hash);
2273 
2274   DCHECK(IsJSReceiver());
2275   return JSReceiver::cast(this)->GetOrCreateIdentityHash(isolate);
2276 }
2277 
2278 
SameValue(Object * other)2279 bool Object::SameValue(Object* other) {
2280   if (other == this) return true;
2281 
2282   if (IsNumber() && other->IsNumber()) {
2283     double this_value = Number();
2284     double other_value = other->Number();
2285     // SameValue(NaN, NaN) is true.
2286     if (this_value != other_value) {
2287       return std::isnan(this_value) && std::isnan(other_value);
2288     }
2289     // SameValue(0.0, -0.0) is false.
2290     return (std::signbit(this_value) == std::signbit(other_value));
2291   }
2292   if (IsString() && other->IsString()) {
2293     return String::cast(this)->Equals(String::cast(other));
2294   }
2295   if (IsBigInt() && other->IsBigInt()) {
2296     return BigInt::EqualToBigInt(BigInt::cast(this), BigInt::cast(other));
2297   }
2298   return false;
2299 }
2300 
2301 
SameValueZero(Object * other)2302 bool Object::SameValueZero(Object* other) {
2303   if (other == this) return true;
2304 
2305   if (IsNumber() && other->IsNumber()) {
2306     double this_value = Number();
2307     double other_value = other->Number();
2308     // +0 == -0 is true
2309     return this_value == other_value ||
2310            (std::isnan(this_value) && std::isnan(other_value));
2311   }
2312   if (IsString() && other->IsString()) {
2313     return String::cast(this)->Equals(String::cast(other));
2314   }
2315   if (IsBigInt() && other->IsBigInt()) {
2316     return BigInt::EqualToBigInt(BigInt::cast(this), BigInt::cast(other));
2317   }
2318   return false;
2319 }
2320 
2321 
ArraySpeciesConstructor(Isolate * isolate,Handle<Object> original_array)2322 MaybeHandle<Object> Object::ArraySpeciesConstructor(
2323     Isolate* isolate, Handle<Object> original_array) {
2324   Handle<Object> default_species = isolate->array_function();
2325   if (original_array->IsJSArray() &&
2326       Handle<JSArray>::cast(original_array)->HasArrayPrototype(isolate) &&
2327       isolate->IsArraySpeciesLookupChainIntact()) {
2328     return default_species;
2329   }
2330   Handle<Object> constructor = isolate->factory()->undefined_value();
2331   Maybe<bool> is_array = Object::IsArray(original_array);
2332   MAYBE_RETURN_NULL(is_array);
2333   if (is_array.FromJust()) {
2334     ASSIGN_RETURN_ON_EXCEPTION(
2335         isolate, constructor,
2336         Object::GetProperty(original_array,
2337                             isolate->factory()->constructor_string()),
2338         Object);
2339     if (constructor->IsConstructor()) {
2340       Handle<Context> constructor_context;
2341       ASSIGN_RETURN_ON_EXCEPTION(
2342           isolate, constructor_context,
2343           JSReceiver::GetFunctionRealm(Handle<JSReceiver>::cast(constructor)),
2344           Object);
2345       if (*constructor_context != *isolate->native_context() &&
2346           *constructor == constructor_context->array_function()) {
2347         constructor = isolate->factory()->undefined_value();
2348       }
2349     }
2350     if (constructor->IsJSReceiver()) {
2351       ASSIGN_RETURN_ON_EXCEPTION(
2352           isolate, constructor,
2353           JSReceiver::GetProperty(Handle<JSReceiver>::cast(constructor),
2354                                   isolate->factory()->species_symbol()),
2355           Object);
2356       if (constructor->IsNull(isolate)) {
2357         constructor = isolate->factory()->undefined_value();
2358       }
2359     }
2360   }
2361   if (constructor->IsUndefined(isolate)) {
2362     return default_species;
2363   } else {
2364     if (!constructor->IsConstructor()) {
2365       THROW_NEW_ERROR(isolate,
2366           NewTypeError(MessageTemplate::kSpeciesNotConstructor),
2367           Object);
2368     }
2369     return constructor;
2370   }
2371 }
2372 
2373 // ES6 section 7.3.20 SpeciesConstructor ( O, defaultConstructor )
SpeciesConstructor(Isolate * isolate,Handle<JSReceiver> recv,Handle<JSFunction> default_ctor)2374 V8_WARN_UNUSED_RESULT MaybeHandle<Object> Object::SpeciesConstructor(
2375     Isolate* isolate, Handle<JSReceiver> recv,
2376     Handle<JSFunction> default_ctor) {
2377   Handle<Object> ctor_obj;
2378   ASSIGN_RETURN_ON_EXCEPTION(
2379       isolate, ctor_obj,
2380       JSObject::GetProperty(recv, isolate->factory()->constructor_string()),
2381       Object);
2382 
2383   if (ctor_obj->IsUndefined(isolate)) return default_ctor;
2384 
2385   if (!ctor_obj->IsJSReceiver()) {
2386     THROW_NEW_ERROR(isolate,
2387                     NewTypeError(MessageTemplate::kConstructorNotReceiver),
2388                     Object);
2389   }
2390 
2391   Handle<JSReceiver> ctor = Handle<JSReceiver>::cast(ctor_obj);
2392 
2393   Handle<Object> species;
2394   ASSIGN_RETURN_ON_EXCEPTION(
2395       isolate, species,
2396       JSObject::GetProperty(ctor, isolate->factory()->species_symbol()),
2397       Object);
2398 
2399   if (species->IsNullOrUndefined(isolate)) {
2400     return default_ctor;
2401   }
2402 
2403   if (species->IsConstructor()) return species;
2404 
2405   THROW_NEW_ERROR(
2406       isolate, NewTypeError(MessageTemplate::kSpeciesNotConstructor), Object);
2407 }
2408 
IterationHasObservableEffects()2409 bool Object::IterationHasObservableEffects() {
2410   // Check that this object is an array.
2411   if (!IsJSArray()) return true;
2412   JSArray* array = JSArray::cast(this);
2413   Isolate* isolate = array->GetIsolate();
2414 
2415 #ifdef V8_ENABLE_FORCE_SLOW_PATH
2416   if (isolate->force_slow_path()) return true;
2417 #endif
2418 
2419   // Check that we have the original ArrayPrototype.
2420   if (!array->map()->prototype()->IsJSObject()) return true;
2421   JSObject* array_proto = JSObject::cast(array->map()->prototype());
2422   if (!isolate->is_initial_array_prototype(array_proto)) return true;
2423 
2424   // Check that the ArrayPrototype hasn't been modified in a way that would
2425   // affect iteration.
2426   if (!isolate->IsArrayIteratorLookupChainIntact()) return true;
2427 
2428   // For FastPacked kinds, iteration will have the same effect as simply
2429   // accessing each property in order.
2430   ElementsKind array_kind = array->GetElementsKind();
2431   if (IsFastPackedElementsKind(array_kind)) return false;
2432 
2433   // For FastHoley kinds, an element access on a hole would cause a lookup on
2434   // the prototype. This could have different results if the prototype has been
2435   // changed.
2436   if (IsHoleyElementsKind(array_kind) &&
2437       isolate->IsNoElementsProtectorIntact()) {
2438     return false;
2439   }
2440   return true;
2441 }
2442 
ShortPrint(FILE * out)2443 void Object::ShortPrint(FILE* out) {
2444   OFStream os(out);
2445   os << Brief(this);
2446 }
2447 
2448 
ShortPrint(StringStream * accumulator)2449 void Object::ShortPrint(StringStream* accumulator) {
2450   std::ostringstream os;
2451   os << Brief(this);
2452   accumulator->Add(os.str().c_str());
2453 }
2454 
2455 
ShortPrint(std::ostream & os)2456 void Object::ShortPrint(std::ostream& os) { os << Brief(this); }
2457 
ShortPrint(FILE * out)2458 void MaybeObject::ShortPrint(FILE* out) {
2459   OFStream os(out);
2460   os << MaybeObjectBrief(this);
2461 }
2462 
ShortPrint(StringStream * accumulator)2463 void MaybeObject::ShortPrint(StringStream* accumulator) {
2464   std::ostringstream os;
2465   os << MaybeObjectBrief(this);
2466   accumulator->Add(os.str().c_str());
2467 }
2468 
ShortPrint(std::ostream & os)2469 void MaybeObject::ShortPrint(std::ostream& os) { os << MaybeObjectBrief(this); }
2470 
operator <<(std::ostream & os,const Brief & v)2471 std::ostream& operator<<(std::ostream& os, const Brief& v) {
2472   if (v.value->IsSmi()) {
2473     Smi::cast(v.value)->SmiPrint(os);
2474   } else {
2475     // TODO(svenpanne) Const-correct HeapObjectShortPrint!
2476     HeapObject* obj = const_cast<HeapObject*>(HeapObject::cast(v.value));
2477     obj->HeapObjectShortPrint(os);
2478   }
2479   return os;
2480 }
2481 
operator <<(std::ostream & os,const MaybeObjectBrief & v)2482 std::ostream& operator<<(std::ostream& os, const MaybeObjectBrief& v) {
2483   // TODO(marja): const-correct this the same way as the Object* version.
2484   MaybeObject* maybe_object = const_cast<MaybeObject*>(v.value);
2485   Smi* smi;
2486   HeapObject* heap_object;
2487   if (maybe_object->ToSmi(&smi)) {
2488     smi->SmiPrint(os);
2489   } else if (maybe_object->IsClearedWeakHeapObject()) {
2490     os << "[cleared]";
2491   } else if (maybe_object->ToWeakHeapObject(&heap_object)) {
2492     os << "[weak] ";
2493     heap_object->HeapObjectShortPrint(os);
2494   } else if (maybe_object->ToStrongHeapObject(&heap_object)) {
2495     heap_object->HeapObjectShortPrint(os);
2496   } else {
2497     UNREACHABLE();
2498   }
2499   return os;
2500 }
2501 
SmiPrint(std::ostream & os) const2502 void Smi::SmiPrint(std::ostream& os) const {  // NOLINT
2503   os << value();
2504 }
2505 
SlowFlatten(Handle<ConsString> cons,PretenureFlag pretenure)2506 Handle<String> String::SlowFlatten(Handle<ConsString> cons,
2507                                    PretenureFlag pretenure) {
2508   DCHECK_NE(cons->second()->length(), 0);
2509 
2510   // TurboFan can create cons strings with empty first parts.
2511   while (cons->first()->length() == 0) {
2512     // We do not want to call this function recursively. Therefore we call
2513     // String::Flatten only in those cases where String::SlowFlatten is not
2514     // called again.
2515     if (cons->second()->IsConsString() && !cons->second()->IsFlat()) {
2516       cons = handle(ConsString::cast(cons->second()));
2517     } else {
2518       return String::Flatten(handle(cons->second()));
2519     }
2520   }
2521 
2522   DCHECK(AllowHeapAllocation::IsAllowed());
2523   Isolate* isolate = cons->GetIsolate();
2524   int length = cons->length();
2525   PretenureFlag tenure = isolate->heap()->InNewSpace(*cons) ? pretenure
2526                                                             : TENURED;
2527   Handle<SeqString> result;
2528   if (cons->IsOneByteRepresentation()) {
2529     Handle<SeqOneByteString> flat = isolate->factory()->NewRawOneByteString(
2530         length, tenure).ToHandleChecked();
2531     DisallowHeapAllocation no_gc;
2532     WriteToFlat(*cons, flat->GetChars(), 0, length);
2533     result = flat;
2534   } else {
2535     Handle<SeqTwoByteString> flat = isolate->factory()->NewRawTwoByteString(
2536         length, tenure).ToHandleChecked();
2537     DisallowHeapAllocation no_gc;
2538     WriteToFlat(*cons, flat->GetChars(), 0, length);
2539     result = flat;
2540   }
2541   cons->set_first(*result);
2542   cons->set_second(isolate->heap()->empty_string());
2543   DCHECK(result->IsFlat());
2544   return result;
2545 }
2546 
2547 
2548 
MakeExternal(v8::String::ExternalStringResource * resource)2549 bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
2550   DisallowHeapAllocation no_allocation;
2551   // Externalizing twice leaks the external resource, so it's
2552   // prohibited by the API.
2553   DCHECK(!this->IsExternalString());
2554   DCHECK(!resource->IsCompressible());
2555 #ifdef ENABLE_SLOW_DCHECKS
2556   if (FLAG_enable_slow_asserts) {
2557     // Assert that the resource and the string are equivalent.
2558     DCHECK(static_cast<size_t>(this->length()) == resource->length());
2559     ScopedVector<uc16> smart_chars(this->length());
2560     String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2561     DCHECK_EQ(0, memcmp(smart_chars.start(), resource->data(),
2562                         resource->length() * sizeof(smart_chars[0])));
2563   }
2564 #endif  // DEBUG
2565   int size = this->Size();  // Byte size of the original string.
2566   // Abort if size does not allow in-place conversion.
2567   if (size < ExternalString::kShortSize) return false;
2568   Heap* heap = GetHeap();
2569   if (heap->read_only_space()->Contains(this)) return false;
2570   bool is_one_byte = this->IsOneByteRepresentation();
2571   bool is_internalized = this->IsInternalizedString();
2572   bool has_pointers = StringShape(this).IsIndirect();
2573   if (has_pointers) {
2574     heap->NotifyObjectLayoutChange(this, size, no_allocation);
2575   }
2576   // Morph the string to an external string by replacing the map and
2577   // reinitializing the fields.  This won't work if the space the existing
2578   // string occupies is too small for a regular  external string.
2579   // Instead, we resort to a short external string instead, omitting
2580   // the field caching the address of the backing store.  When we encounter
2581   // short external strings in generated code, we need to bailout to runtime.
2582   Map* new_map;
2583   if (size < ExternalString::kSize) {
2584     new_map = is_internalized
2585         ? (is_one_byte
2586            ? heap->short_external_internalized_string_with_one_byte_data_map()
2587            : heap->short_external_internalized_string_map())
2588         : (is_one_byte ? heap->short_external_string_with_one_byte_data_map()
2589                        : heap->short_external_string_map());
2590   } else {
2591     new_map = is_internalized
2592         ? (is_one_byte
2593            ? heap->external_internalized_string_with_one_byte_data_map()
2594            : heap->external_internalized_string_map())
2595         : (is_one_byte ? heap->external_string_with_one_byte_data_map()
2596                        : heap->external_string_map());
2597   }
2598 
2599   // Byte size of the external String object.
2600   int new_size = this->SizeFromMap(new_map);
2601   heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
2602                              ClearRecordedSlots::kNo);
2603   if (has_pointers) {
2604     heap->ClearRecordedSlotRange(this->address(), this->address() + new_size);
2605   }
2606 
2607   // We are storing the new map using release store after creating a filler for
2608   // the left-over space to avoid races with the sweeper thread.
2609   this->synchronized_set_map(new_map);
2610 
2611   ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
2612   self->set_resource(resource);
2613   if (is_internalized) self->Hash();  // Force regeneration of the hash value.
2614   return true;
2615 }
2616 
2617 
MakeExternal(v8::String::ExternalOneByteStringResource * resource)2618 bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
2619   DisallowHeapAllocation no_allocation;
2620   // Externalizing twice leaks the external resource, so it's
2621   // prohibited by the API.
2622   DCHECK(!this->IsExternalString());
2623   DCHECK(!resource->IsCompressible());
2624 #ifdef ENABLE_SLOW_DCHECKS
2625   if (FLAG_enable_slow_asserts) {
2626     // Assert that the resource and the string are equivalent.
2627     DCHECK(static_cast<size_t>(this->length()) == resource->length());
2628     if (this->IsTwoByteRepresentation()) {
2629       ScopedVector<uint16_t> smart_chars(this->length());
2630       String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2631       DCHECK(String::IsOneByte(smart_chars.start(), this->length()));
2632     }
2633     ScopedVector<char> smart_chars(this->length());
2634     String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2635     DCHECK_EQ(0, memcmp(smart_chars.start(), resource->data(),
2636                         resource->length() * sizeof(smart_chars[0])));
2637   }
2638 #endif  // DEBUG
2639   int size = this->Size();  // Byte size of the original string.
2640   // Abort if size does not allow in-place conversion.
2641   if (size < ExternalString::kShortSize) return false;
2642   Heap* heap = GetHeap();
2643   if (heap->read_only_space()->Contains(this)) return false;
2644   bool is_internalized = this->IsInternalizedString();
2645   bool has_pointers = StringShape(this).IsIndirect();
2646 
2647   if (has_pointers) {
2648     heap->NotifyObjectLayoutChange(this, size, no_allocation);
2649   }
2650 
2651   // Morph the string to an external string by replacing the map and
2652   // reinitializing the fields.  This won't work if the space the existing
2653   // string occupies is too small for a regular  external string.
2654   // Instead, we resort to a short external string instead, omitting
2655   // the field caching the address of the backing store.  When we encounter
2656   // short external strings in generated code, we need to bailout to runtime.
2657   Map* new_map;
2658   if (size < ExternalString::kSize) {
2659     new_map = is_internalized
2660                   ? heap->short_external_one_byte_internalized_string_map()
2661                   : heap->short_external_one_byte_string_map();
2662   } else {
2663     new_map = is_internalized
2664                   ? heap->external_one_byte_internalized_string_map()
2665                   : heap->external_one_byte_string_map();
2666   }
2667 
2668   // Byte size of the external String object.
2669   int new_size = this->SizeFromMap(new_map);
2670   heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
2671                              ClearRecordedSlots::kNo);
2672   if (has_pointers) {
2673     heap->ClearRecordedSlotRange(this->address(), this->address() + new_size);
2674   }
2675 
2676   // We are storing the new map using release store after creating a filler for
2677   // the left-over space to avoid races with the sweeper thread.
2678   this->synchronized_set_map(new_map);
2679 
2680   ExternalOneByteString* self = ExternalOneByteString::cast(this);
2681   self->set_resource(resource);
2682   if (is_internalized) self->Hash();  // Force regeneration of the hash value.
2683   return true;
2684 }
2685 
StringShortPrint(StringStream * accumulator,bool show_details)2686 void String::StringShortPrint(StringStream* accumulator, bool show_details) {
2687   int len = length();
2688   if (len > kMaxShortPrintLength) {
2689     accumulator->Add("<Very long string[%u]>", len);
2690     return;
2691   }
2692 
2693   if (!LooksValid()) {
2694     accumulator->Add("<Invalid String>");
2695     return;
2696   }
2697 
2698   StringCharacterStream stream(this);
2699 
2700   bool truncated = false;
2701   if (len > kMaxShortPrintLength) {
2702     len = kMaxShortPrintLength;
2703     truncated = true;
2704   }
2705   bool one_byte = true;
2706   for (int i = 0; i < len; i++) {
2707     uint16_t c = stream.GetNext();
2708 
2709     if (c < 32 || c >= 127) {
2710       one_byte = false;
2711     }
2712   }
2713   stream.Reset(this);
2714   if (one_byte) {
2715     if (show_details) accumulator->Add("<String[%u]: ", length());
2716     for (int i = 0; i < len; i++) {
2717       accumulator->Put(static_cast<char>(stream.GetNext()));
2718     }
2719     if (show_details) accumulator->Put('>');
2720   } else {
2721     // Backslash indicates that the string contains control
2722     // characters and that backslashes are therefore escaped.
2723     if (show_details) accumulator->Add("<String[%u]\\: ", length());
2724     for (int i = 0; i < len; i++) {
2725       uint16_t c = stream.GetNext();
2726       if (c == '\n') {
2727         accumulator->Add("\\n");
2728       } else if (c == '\r') {
2729         accumulator->Add("\\r");
2730       } else if (c == '\\') {
2731         accumulator->Add("\\\\");
2732       } else if (c < 32 || c > 126) {
2733         accumulator->Add("\\x%02x", c);
2734       } else {
2735         accumulator->Put(static_cast<char>(c));
2736       }
2737     }
2738     if (truncated) {
2739       accumulator->Put('.');
2740       accumulator->Put('.');
2741       accumulator->Put('.');
2742     }
2743     if (show_details) accumulator->Put('>');
2744   }
2745   return;
2746 }
2747 
2748 
PrintUC16(std::ostream & os,int start,int end)2749 void String::PrintUC16(std::ostream& os, int start, int end) {  // NOLINT
2750   if (end < 0) end = length();
2751   StringCharacterStream stream(this, start);
2752   for (int i = start; i < end && stream.HasMore(); i++) {
2753     os << AsUC16(stream.GetNext());
2754   }
2755 }
2756 
2757 
JSObjectShortPrint(StringStream * accumulator)2758 void JSObject::JSObjectShortPrint(StringStream* accumulator) {
2759   switch (map()->instance_type()) {
2760     case JS_ARRAY_TYPE: {
2761       double length = JSArray::cast(this)->length()->IsUndefined(GetIsolate())
2762                           ? 0
2763                           : JSArray::cast(this)->length()->Number();
2764       accumulator->Add("<JSArray[%u]>", static_cast<uint32_t>(length));
2765       break;
2766     }
2767     case JS_BOUND_FUNCTION_TYPE: {
2768       JSBoundFunction* bound_function = JSBoundFunction::cast(this);
2769       accumulator->Add("<JSBoundFunction");
2770       accumulator->Add(
2771           " (BoundTargetFunction %p)>",
2772           reinterpret_cast<void*>(bound_function->bound_target_function()));
2773       break;
2774     }
2775     case JS_WEAK_MAP_TYPE: {
2776       accumulator->Add("<JSWeakMap>");
2777       break;
2778     }
2779     case JS_WEAK_SET_TYPE: {
2780       accumulator->Add("<JSWeakSet>");
2781       break;
2782     }
2783     case JS_REGEXP_TYPE: {
2784       accumulator->Add("<JSRegExp");
2785       JSRegExp* regexp = JSRegExp::cast(this);
2786       if (regexp->source()->IsString()) {
2787         accumulator->Add(" ");
2788         String::cast(regexp->source())->StringShortPrint(accumulator);
2789       }
2790       accumulator->Add(">");
2791 
2792       break;
2793     }
2794     case JS_FUNCTION_TYPE: {
2795       JSFunction* function = JSFunction::cast(this);
2796       Object* fun_name = function->shared()->DebugName();
2797       bool printed = false;
2798       if (fun_name->IsString()) {
2799         String* str = String::cast(fun_name);
2800         if (str->length() > 0) {
2801           accumulator->Add("<JSFunction ");
2802           accumulator->Put(str);
2803           printed = true;
2804         }
2805       }
2806       if (!printed) {
2807         accumulator->Add("<JSFunction");
2808       }
2809       if (FLAG_trace_file_names) {
2810         Object* source_name =
2811             Script::cast(function->shared()->script())->name();
2812         if (source_name->IsString()) {
2813           String* str = String::cast(source_name);
2814           if (str->length() > 0) {
2815             accumulator->Add(" <");
2816             accumulator->Put(str);
2817             accumulator->Add(">");
2818           }
2819         }
2820       }
2821       accumulator->Add(" (sfi = %p)",
2822                        reinterpret_cast<void*>(function->shared()));
2823       accumulator->Put('>');
2824       break;
2825     }
2826     case JS_GENERATOR_OBJECT_TYPE: {
2827       accumulator->Add("<JSGenerator>");
2828       break;
2829     }
2830     case JS_ASYNC_GENERATOR_OBJECT_TYPE: {
2831       accumulator->Add("<JS AsyncGenerator>");
2832       break;
2833     }
2834 
2835     // All other JSObjects are rather similar to each other (JSObject,
2836     // JSGlobalProxy, JSGlobalObject, JSUndetectable, JSValue).
2837     default: {
2838       Map* map_of_this = map();
2839       Heap* heap = GetHeap();
2840       Object* constructor = map_of_this->GetConstructor();
2841       bool printed = false;
2842       if (constructor->IsHeapObject() &&
2843           !heap->Contains(HeapObject::cast(constructor))) {
2844         accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
2845       } else {
2846         bool global_object = IsJSGlobalProxy();
2847         if (constructor->IsJSFunction()) {
2848           if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
2849             accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
2850           } else {
2851             String* constructor_name =
2852                 JSFunction::cast(constructor)->shared()->Name();
2853             if (constructor_name->length() > 0) {
2854               accumulator->Add(global_object ? "<GlobalObject " : "<");
2855               accumulator->Put(constructor_name);
2856               accumulator->Add(
2857                   " %smap = %p",
2858                   map_of_this->is_deprecated() ? "deprecated-" : "",
2859                   map_of_this);
2860               printed = true;
2861             }
2862           }
2863         } else if (constructor->IsFunctionTemplateInfo()) {
2864           accumulator->Add(global_object ? "<RemoteObject>" : "<RemoteObject>");
2865           printed = true;
2866         }
2867         if (!printed) {
2868           accumulator->Add("<JS%sObject", global_object ? "Global " : "");
2869         }
2870       }
2871       if (IsJSValue()) {
2872         accumulator->Add(" value = ");
2873         JSValue::cast(this)->value()->ShortPrint(accumulator);
2874       }
2875       accumulator->Put('>');
2876       break;
2877     }
2878   }
2879 }
2880 
2881 
PrintElementsTransition(FILE * file,Handle<JSObject> object,ElementsKind from_kind,Handle<FixedArrayBase> from_elements,ElementsKind to_kind,Handle<FixedArrayBase> to_elements)2882 void JSObject::PrintElementsTransition(
2883     FILE* file, Handle<JSObject> object,
2884     ElementsKind from_kind, Handle<FixedArrayBase> from_elements,
2885     ElementsKind to_kind, Handle<FixedArrayBase> to_elements) {
2886   if (from_kind != to_kind) {
2887     OFStream os(file);
2888     os << "elements transition [" << ElementsKindToString(from_kind) << " -> "
2889        << ElementsKindToString(to_kind) << "] in ";
2890     JavaScriptFrame::PrintTop(object->GetIsolate(), file, false, true);
2891     PrintF(file, " for ");
2892     object->ShortPrint(file);
2893     PrintF(file, " from ");
2894     from_elements->ShortPrint(file);
2895     PrintF(file, " to ");
2896     to_elements->ShortPrint(file);
2897     PrintF(file, "\n");
2898   }
2899 }
2900 
2901 
2902 // static
GetConstructorFunction(Handle<Map> map,Handle<Context> native_context)2903 MaybeHandle<JSFunction> Map::GetConstructorFunction(
2904     Handle<Map> map, Handle<Context> native_context) {
2905   if (map->IsPrimitiveMap()) {
2906     int const constructor_function_index = map->GetConstructorFunctionIndex();
2907     if (constructor_function_index != kNoConstructorFunctionIndex) {
2908       return handle(
2909           JSFunction::cast(native_context->get(constructor_function_index)));
2910     }
2911   }
2912   return MaybeHandle<JSFunction>();
2913 }
2914 
2915 
PrintReconfiguration(FILE * file,int modify_index,PropertyKind kind,PropertyAttributes attributes)2916 void Map::PrintReconfiguration(FILE* file, int modify_index, PropertyKind kind,
2917                                PropertyAttributes attributes) {
2918   OFStream os(file);
2919   os << "[reconfiguring]";
2920   Name* name = instance_descriptors()->GetKey(modify_index);
2921   if (name->IsString()) {
2922     String::cast(name)->PrintOn(file);
2923   } else {
2924     os << "{symbol " << static_cast<void*>(name) << "}";
2925   }
2926   os << ": " << (kind == kData ? "kData" : "ACCESSORS") << ", attrs: ";
2927   os << attributes << " [";
2928   JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
2929   os << "]\n";
2930 }
2931 
GetVisitorId(Map * map)2932 VisitorId Map::GetVisitorId(Map* map) {
2933   STATIC_ASSERT(kVisitorIdCount <= 256);
2934 
2935   const int instance_type = map->instance_type();
2936   const bool has_unboxed_fields =
2937       FLAG_unbox_double_fields && !map->HasFastPointerLayout();
2938   if (instance_type < FIRST_NONSTRING_TYPE) {
2939     switch (instance_type & kStringRepresentationMask) {
2940       case kSeqStringTag:
2941         if ((instance_type & kStringEncodingMask) == kOneByteStringTag) {
2942           return kVisitSeqOneByteString;
2943         } else {
2944           return kVisitSeqTwoByteString;
2945         }
2946 
2947       case kConsStringTag:
2948         if (IsShortcutCandidate(instance_type)) {
2949           return kVisitShortcutCandidate;
2950         } else {
2951           return kVisitConsString;
2952         }
2953 
2954       case kSlicedStringTag:
2955         return kVisitSlicedString;
2956 
2957       case kExternalStringTag:
2958         return kVisitDataObject;
2959 
2960       case kThinStringTag:
2961         return kVisitThinString;
2962     }
2963     UNREACHABLE();
2964   }
2965 
2966   switch (instance_type) {
2967     case BYTE_ARRAY_TYPE:
2968       return kVisitByteArray;
2969 
2970     case BYTECODE_ARRAY_TYPE:
2971       return kVisitBytecodeArray;
2972 
2973     case FREE_SPACE_TYPE:
2974       return kVisitFreeSpace;
2975 
2976     case FIXED_ARRAY_TYPE:
2977     case BOILERPLATE_DESCRIPTION_TYPE:
2978     case HASH_TABLE_TYPE:
2979     case DESCRIPTOR_ARRAY_TYPE:
2980     case SCOPE_INFO_TYPE:
2981     case BLOCK_CONTEXT_TYPE:
2982     case CATCH_CONTEXT_TYPE:
2983     case DEBUG_EVALUATE_CONTEXT_TYPE:
2984     case EVAL_CONTEXT_TYPE:
2985     case FUNCTION_CONTEXT_TYPE:
2986     case MODULE_CONTEXT_TYPE:
2987     case NATIVE_CONTEXT_TYPE:
2988     case SCRIPT_CONTEXT_TYPE:
2989     case WITH_CONTEXT_TYPE:
2990       return kVisitFixedArray;
2991 
2992     case WEAK_FIXED_ARRAY_TYPE:
2993     case WEAK_ARRAY_LIST_TYPE:
2994       return kVisitWeakArray;
2995 
2996     case FIXED_DOUBLE_ARRAY_TYPE:
2997       return kVisitFixedDoubleArray;
2998 
2999     case PROPERTY_ARRAY_TYPE:
3000       return kVisitPropertyArray;
3001 
3002     case FEEDBACK_CELL_TYPE:
3003       return kVisitFeedbackCell;
3004 
3005     case FEEDBACK_VECTOR_TYPE:
3006       return kVisitFeedbackVector;
3007 
3008     case ODDBALL_TYPE:
3009       return kVisitOddball;
3010 
3011     case MAP_TYPE:
3012       return kVisitMap;
3013 
3014     case CODE_TYPE:
3015       return kVisitCode;
3016 
3017     case CELL_TYPE:
3018       return kVisitCell;
3019 
3020     case PROPERTY_CELL_TYPE:
3021       return kVisitPropertyCell;
3022 
3023     case WEAK_CELL_TYPE:
3024       return kVisitWeakCell;
3025 
3026     case TRANSITION_ARRAY_TYPE:
3027       return kVisitTransitionArray;
3028 
3029     case JS_WEAK_MAP_TYPE:
3030     case JS_WEAK_SET_TYPE:
3031       return kVisitJSWeakCollection;
3032 
3033     case CALL_HANDLER_INFO_TYPE:
3034       return kVisitStruct;
3035 
3036     case SHARED_FUNCTION_INFO_TYPE:
3037       return kVisitSharedFunctionInfo;
3038 
3039     case JS_PROXY_TYPE:
3040       return kVisitStruct;
3041 
3042     case SYMBOL_TYPE:
3043       return kVisitSymbol;
3044 
3045     case JS_ARRAY_BUFFER_TYPE:
3046       return kVisitJSArrayBuffer;
3047 
3048     case SMALL_ORDERED_HASH_MAP_TYPE:
3049       return kVisitSmallOrderedHashMap;
3050 
3051     case SMALL_ORDERED_HASH_SET_TYPE:
3052       return kVisitSmallOrderedHashSet;
3053 
3054     case CODE_DATA_CONTAINER_TYPE:
3055       return kVisitCodeDataContainer;
3056 
3057     case WASM_INSTANCE_TYPE:
3058       return kVisitWasmInstanceObject;
3059 
3060     case JS_OBJECT_TYPE:
3061     case JS_ERROR_TYPE:
3062     case JS_ARGUMENTS_TYPE:
3063     case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
3064     case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
3065     case JS_GENERATOR_OBJECT_TYPE:
3066     case JS_ASYNC_GENERATOR_OBJECT_TYPE:
3067     case JS_MODULE_NAMESPACE_TYPE:
3068     case JS_VALUE_TYPE:
3069     case JS_DATE_TYPE:
3070     case JS_ARRAY_ITERATOR_TYPE:
3071     case JS_ARRAY_TYPE:
3072     case JS_GLOBAL_PROXY_TYPE:
3073     case JS_GLOBAL_OBJECT_TYPE:
3074     case JS_MESSAGE_OBJECT_TYPE:
3075     case JS_TYPED_ARRAY_TYPE:
3076     case JS_DATA_VIEW_TYPE:
3077     case JS_SET_TYPE:
3078     case JS_MAP_TYPE:
3079     case JS_SET_KEY_VALUE_ITERATOR_TYPE:
3080     case JS_SET_VALUE_ITERATOR_TYPE:
3081     case JS_MAP_KEY_ITERATOR_TYPE:
3082     case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
3083     case JS_MAP_VALUE_ITERATOR_TYPE:
3084     case JS_STRING_ITERATOR_TYPE:
3085     case JS_PROMISE_TYPE:
3086     case JS_REGEXP_TYPE:
3087     case JS_REGEXP_STRING_ITERATOR_TYPE:
3088 #ifdef V8_INTL_SUPPORT
3089     case JS_INTL_LOCALE_TYPE:
3090 #endif  // V8_INTL_SUPPORT
3091     case WASM_GLOBAL_TYPE:
3092     case WASM_MEMORY_TYPE:
3093     case WASM_MODULE_TYPE:
3094     case WASM_TABLE_TYPE:
3095     case JS_BOUND_FUNCTION_TYPE:
3096       return has_unboxed_fields ? kVisitJSObject : kVisitJSObjectFast;
3097     case JS_API_OBJECT_TYPE:
3098     case JS_SPECIAL_API_OBJECT_TYPE:
3099       return kVisitJSApiObject;
3100 
3101     case JS_FUNCTION_TYPE:
3102       return kVisitJSFunction;
3103 
3104     case FILLER_TYPE:
3105     case FOREIGN_TYPE:
3106     case HEAP_NUMBER_TYPE:
3107     case MUTABLE_HEAP_NUMBER_TYPE:
3108     case FEEDBACK_METADATA_TYPE:
3109       return kVisitDataObject;
3110 
3111     case BIGINT_TYPE:
3112       return kVisitBigInt;
3113 
3114     case FIXED_UINT8_ARRAY_TYPE:
3115     case FIXED_INT8_ARRAY_TYPE:
3116     case FIXED_UINT16_ARRAY_TYPE:
3117     case FIXED_INT16_ARRAY_TYPE:
3118     case FIXED_UINT32_ARRAY_TYPE:
3119     case FIXED_INT32_ARRAY_TYPE:
3120     case FIXED_FLOAT32_ARRAY_TYPE:
3121     case FIXED_UINT8_CLAMPED_ARRAY_TYPE:
3122     case FIXED_BIGUINT64_ARRAY_TYPE:
3123     case FIXED_BIGINT64_ARRAY_TYPE:
3124       return kVisitFixedTypedArrayBase;
3125 
3126     case FIXED_FLOAT64_ARRAY_TYPE:
3127       return kVisitFixedFloat64Array;
3128 
3129 #define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE:
3130       STRUCT_LIST(MAKE_STRUCT_CASE)
3131 #undef MAKE_STRUCT_CASE
3132       if (instance_type == ALLOCATION_SITE_TYPE) {
3133         return kVisitAllocationSite;
3134       }
3135       return kVisitStruct;
3136 
3137     case LOAD_HANDLER_TYPE:
3138     case STORE_HANDLER_TYPE:
3139       return kVisitStruct;
3140 
3141     default:
3142       UNREACHABLE();
3143   }
3144 }
3145 
PrintGeneralization(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)3146 void Map::PrintGeneralization(
3147     FILE* file, const char* reason, int modify_index, int split,
3148     int descriptors, bool descriptor_to_field,
3149     Representation old_representation, Representation new_representation,
3150     MaybeHandle<FieldType> old_field_type, MaybeHandle<Object> old_value,
3151     MaybeHandle<FieldType> new_field_type, MaybeHandle<Object> new_value) {
3152   OFStream os(file);
3153   os << "[generalizing]";
3154   Name* name = instance_descriptors()->GetKey(modify_index);
3155   if (name->IsString()) {
3156     String::cast(name)->PrintOn(file);
3157   } else {
3158     os << "{symbol " << static_cast<void*>(name) << "}";
3159   }
3160   os << ":";
3161   if (descriptor_to_field) {
3162     os << "c";
3163   } else {
3164     os << old_representation.Mnemonic() << "{";
3165     if (old_field_type.is_null()) {
3166       os << Brief(*(old_value.ToHandleChecked()));
3167     } else {
3168       old_field_type.ToHandleChecked()->PrintTo(os);
3169     }
3170     os << "}";
3171   }
3172   os << "->" << new_representation.Mnemonic() << "{";
3173   if (new_field_type.is_null()) {
3174     os << Brief(*(new_value.ToHandleChecked()));
3175   } else {
3176     new_field_type.ToHandleChecked()->PrintTo(os);
3177   }
3178   os << "} (";
3179   if (strlen(reason) > 0) {
3180     os << reason;
3181   } else {
3182     os << "+" << (descriptors - split) << " maps";
3183   }
3184   os << ") [";
3185   JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
3186   os << "]\n";
3187 }
3188 
3189 
PrintInstanceMigration(FILE * file,Map * original_map,Map * new_map)3190 void JSObject::PrintInstanceMigration(FILE* file,
3191                                       Map* original_map,
3192                                       Map* new_map) {
3193   if (new_map->is_dictionary_map()) {
3194     PrintF(file, "[migrating to slow]\n");
3195     return;
3196   }
3197   PrintF(file, "[migrating]");
3198   DescriptorArray* o = original_map->instance_descriptors();
3199   DescriptorArray* n = new_map->instance_descriptors();
3200   for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) {
3201     Representation o_r = o->GetDetails(i).representation();
3202     Representation n_r = n->GetDetails(i).representation();
3203     if (!o_r.Equals(n_r)) {
3204       String::cast(o->GetKey(i))->PrintOn(file);
3205       PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic());
3206     } else if (o->GetDetails(i).location() == kDescriptor &&
3207                n->GetDetails(i).location() == kField) {
3208       Name* name = o->GetKey(i);
3209       if (name->IsString()) {
3210         String::cast(name)->PrintOn(file);
3211       } else {
3212         PrintF(file, "{symbol %p}", static_cast<void*>(name));
3213       }
3214       PrintF(file, " ");
3215     }
3216   }
3217   if (original_map->elements_kind() != new_map->elements_kind()) {
3218     PrintF(file, "elements_kind[%i->%i]", original_map->elements_kind(),
3219            new_map->elements_kind());
3220   }
3221   PrintF(file, "\n");
3222 }
3223 
IsUnmodifiedApiObject(Object ** o)3224 bool JSObject::IsUnmodifiedApiObject(Object** o) {
3225   Object* object = *o;
3226   if (object->IsSmi()) return false;
3227   HeapObject* heap_object = HeapObject::cast(object);
3228   if (!object->IsJSObject()) return false;
3229   JSObject* js_object = JSObject::cast(object);
3230   if (!js_object->WasConstructedFromApiFunction()) return false;
3231   Object* maybe_constructor = js_object->map()->GetConstructor();
3232   if (!maybe_constructor->IsJSFunction()) return false;
3233   JSFunction* constructor = JSFunction::cast(maybe_constructor);
3234   if (js_object->elements()->length() != 0) return false;
3235 
3236   return constructor->initial_map() == heap_object->map();
3237 }
3238 
HeapObjectShortPrint(std::ostream & os)3239 void HeapObject::HeapObjectShortPrint(std::ostream& os) {  // NOLINT
3240   Heap* heap = GetHeap();
3241   Isolate* isolate = heap->isolate();
3242   if (!heap->Contains(this)) {
3243     os << "!!!INVALID POINTER!!!";
3244     return;
3245   }
3246   if (!heap->Contains(map())) {
3247     os << "!!!INVALID MAP!!!";
3248     return;
3249   }
3250 
3251   os << AsHex(reinterpret_cast<Address>(this), kPointerHexDigits, true) << " ";
3252 
3253   if (IsString()) {
3254     HeapStringAllocator allocator;
3255     StringStream accumulator(&allocator);
3256     String::cast(this)->StringShortPrint(&accumulator);
3257     os << accumulator.ToCString().get();
3258     return;
3259   }
3260   if (IsJSObject()) {
3261     HeapStringAllocator allocator;
3262     StringStream accumulator(&allocator);
3263     JSObject::cast(this)->JSObjectShortPrint(&accumulator);
3264     os << accumulator.ToCString().get();
3265     return;
3266   }
3267   switch (map()->instance_type()) {
3268     case MAP_TYPE: {
3269       os << "<Map";
3270       Map* mapInstance = Map::cast(this);
3271       if (mapInstance->IsJSObjectMap()) {
3272         os << "(" << ElementsKindToString(mapInstance->elements_kind()) << ")";
3273       } else if (mapInstance->instance_size() != kVariableSizeSentinel) {
3274         os << "[" << mapInstance->instance_size() << "]";
3275       }
3276       os << ">";
3277     } break;
3278     case BLOCK_CONTEXT_TYPE:
3279       os << "<BlockContext[" << FixedArray::cast(this)->length() << "]>";
3280       break;
3281     case CATCH_CONTEXT_TYPE:
3282       os << "<CatchContext[" << FixedArray::cast(this)->length() << "]>";
3283       break;
3284     case DEBUG_EVALUATE_CONTEXT_TYPE:
3285       os << "<DebugEvaluateContext[" << FixedArray::cast(this)->length()
3286          << "]>";
3287       break;
3288     case EVAL_CONTEXT_TYPE:
3289       os << "<EvalContext[" << FixedArray::cast(this)->length() << "]>";
3290       break;
3291     case FUNCTION_CONTEXT_TYPE:
3292       os << "<FunctionContext[" << FixedArray::cast(this)->length() << "]>";
3293       break;
3294     case MODULE_CONTEXT_TYPE:
3295       os << "<ModuleContext[" << FixedArray::cast(this)->length() << "]>";
3296       break;
3297     case NATIVE_CONTEXT_TYPE:
3298       os << "<NativeContext[" << FixedArray::cast(this)->length() << "]>";
3299       break;
3300     case SCRIPT_CONTEXT_TYPE:
3301       os << "<ScriptContext[" << FixedArray::cast(this)->length() << "]>";
3302       break;
3303     case WITH_CONTEXT_TYPE:
3304       os << "<WithContext[" << FixedArray::cast(this)->length() << "]>";
3305       break;
3306     case HASH_TABLE_TYPE:
3307       os << "<HashTable[" << FixedArray::cast(this)->length() << "]>";
3308       break;
3309     case FIXED_ARRAY_TYPE:
3310       os << "<FixedArray[" << FixedArray::cast(this)->length() << "]>";
3311       break;
3312     case BOILERPLATE_DESCRIPTION_TYPE:
3313       os << "<BoilerplateDescription[" << FixedArray::cast(this)->length()
3314          << "]>";
3315       break;
3316     case FIXED_DOUBLE_ARRAY_TYPE:
3317       os << "<FixedDoubleArray[" << FixedDoubleArray::cast(this)->length()
3318          << "]>";
3319       break;
3320     case BYTE_ARRAY_TYPE:
3321       os << "<ByteArray[" << ByteArray::cast(this)->length() << "]>";
3322       break;
3323     case BYTECODE_ARRAY_TYPE:
3324       os << "<BytecodeArray[" << BytecodeArray::cast(this)->length() << "]>";
3325       break;
3326     case DESCRIPTOR_ARRAY_TYPE:
3327       os << "<DescriptorArray[" << DescriptorArray::cast(this)->length()
3328          << "]>";
3329       break;
3330     case TRANSITION_ARRAY_TYPE:
3331       os << "<TransitionArray[" << TransitionArray::cast(this)->length()
3332          << "]>";
3333       break;
3334     case PROPERTY_ARRAY_TYPE:
3335       os << "<PropertyArray[" << PropertyArray::cast(this)->length() << "]>";
3336       break;
3337     case FEEDBACK_CELL_TYPE: {
3338       os << "<FeedbackCell[";
3339       if (map() == heap->no_closures_cell_map()) {
3340         os << "no closures";
3341       } else if (map() == heap->one_closure_cell_map()) {
3342         os << "one closure";
3343       } else if (map() == heap->many_closures_cell_map()) {
3344         os << "many closures";
3345       } else {
3346         os << "!!!INVALID MAP!!!";
3347       }
3348       os << "]>";
3349       break;
3350     }
3351     case FEEDBACK_VECTOR_TYPE:
3352       os << "<FeedbackVector[" << FeedbackVector::cast(this)->length() << "]>";
3353       break;
3354     case FREE_SPACE_TYPE:
3355       os << "<FreeSpace[" << FreeSpace::cast(this)->size() << "]>";
3356       break;
3357 #define TYPED_ARRAY_SHORT_PRINT(Type, type, TYPE, ctype, size)                \
3358   case FIXED_##TYPE##_ARRAY_TYPE:                                             \
3359     os << "<Fixed" #Type "Array[" << Fixed##Type##Array::cast(this)->length() \
3360        << "]>";                                                               \
3361     break;
3362 
3363     TYPED_ARRAYS(TYPED_ARRAY_SHORT_PRINT)
3364 #undef TYPED_ARRAY_SHORT_PRINT
3365 
3366     case SHARED_FUNCTION_INFO_TYPE: {
3367       SharedFunctionInfo* shared = SharedFunctionInfo::cast(this);
3368       std::unique_ptr<char[]> debug_name = shared->DebugName()->ToCString();
3369       if (debug_name[0] != 0) {
3370         os << "<SharedFunctionInfo " << debug_name.get() << ">";
3371       } else {
3372         os << "<SharedFunctionInfo>";
3373       }
3374       break;
3375     }
3376     case JS_MESSAGE_OBJECT_TYPE:
3377       os << "<JSMessageObject>";
3378       break;
3379 #define MAKE_STRUCT_CASE(NAME, Name, name)   \
3380   case NAME##_TYPE:                          \
3381     os << "<" #Name;                         \
3382     Name::cast(this)->BriefPrintDetails(os); \
3383     os << ">";                               \
3384     break;
3385       STRUCT_LIST(MAKE_STRUCT_CASE)
3386 #undef MAKE_STRUCT_CASE
3387     case SCOPE_INFO_TYPE: {
3388       ScopeInfo* scope = ScopeInfo::cast(this);
3389       os << "<ScopeInfo";
3390       if (scope->length()) os << " " << scope->scope_type() << " ";
3391       os << "[" << scope->length() << "]>";
3392       break;
3393     }
3394     case CODE_TYPE: {
3395       Code* code = Code::cast(this);
3396       os << "<Code " << Code::Kind2String(code->kind());
3397       if (code->is_stub()) {
3398         os << " " << CodeStub::MajorName(CodeStub::GetMajorKey(code));
3399       } else if (code->is_builtin()) {
3400         os << " " << Builtins::name(code->builtin_index());
3401       }
3402       os << ">";
3403       break;
3404     }
3405     case ODDBALL_TYPE: {
3406       if (IsUndefined(isolate)) {
3407         os << "<undefined>";
3408       } else if (IsTheHole(isolate)) {
3409         os << "<the_hole>";
3410       } else if (IsNull(isolate)) {
3411         os << "<null>";
3412       } else if (IsTrue(isolate)) {
3413         os << "<true>";
3414       } else if (IsFalse(isolate)) {
3415         os << "<false>";
3416       } else {
3417         os << "<Odd Oddball: ";
3418         os << Oddball::cast(this)->to_string()->ToCString().get();
3419         os << ">";
3420       }
3421       break;
3422     }
3423     case SYMBOL_TYPE: {
3424       Symbol* symbol = Symbol::cast(this);
3425       symbol->SymbolShortPrint(os);
3426       break;
3427     }
3428     case HEAP_NUMBER_TYPE: {
3429       os << "<Number ";
3430       HeapNumber::cast(this)->HeapNumberPrint(os);
3431       os << ">";
3432       break;
3433     }
3434     case MUTABLE_HEAP_NUMBER_TYPE: {
3435       os << "<MutableNumber ";
3436       HeapNumber::cast(this)->HeapNumberPrint(os);
3437       os << '>';
3438       break;
3439     }
3440     case BIGINT_TYPE: {
3441       os << "<BigInt ";
3442       BigInt::cast(this)->BigIntShortPrint(os);
3443       os << ">";
3444       break;
3445     }
3446     case JS_PROXY_TYPE:
3447       os << "<JSProxy>";
3448       break;
3449     case FOREIGN_TYPE:
3450       os << "<Foreign>";
3451       break;
3452     case CELL_TYPE: {
3453       os << "<Cell value= ";
3454       HeapStringAllocator allocator;
3455       StringStream accumulator(&allocator);
3456       Cell::cast(this)->value()->ShortPrint(&accumulator);
3457       os << accumulator.ToCString().get();
3458       os << '>';
3459       break;
3460     }
3461     case PROPERTY_CELL_TYPE: {
3462       PropertyCell* cell = PropertyCell::cast(this);
3463       os << "<PropertyCell name=";
3464       cell->name()->ShortPrint(os);
3465       os << " value=";
3466       HeapStringAllocator allocator;
3467       StringStream accumulator(&allocator);
3468       cell->value()->ShortPrint(&accumulator);
3469       os << accumulator.ToCString().get();
3470       os << '>';
3471       break;
3472     }
3473     case WEAK_CELL_TYPE: {
3474       os << "<WeakCell value= ";
3475       HeapStringAllocator allocator;
3476       StringStream accumulator(&allocator);
3477       WeakCell::cast(this)->value()->ShortPrint(&accumulator);
3478       os << accumulator.ToCString().get();
3479       os << '>';
3480       break;
3481     }
3482     case CALL_HANDLER_INFO_TYPE: {
3483       CallHandlerInfo* info = CallHandlerInfo::cast(this);
3484       os << "<CallHandlerInfo ";
3485       os << "callback= " << Brief(info->callback());
3486       os << ", js_callback= " << Brief(info->js_callback());
3487       os << ", data= " << Brief(info->data());
3488       if (info->IsSideEffectFreeCallHandlerInfo()) {
3489         os << ", side_effect_free= true>";
3490       } else {
3491         os << ", side_effect_free= false>";
3492       }
3493       break;
3494     }
3495     default:
3496       os << "<Other heap object (" << map()->instance_type() << ")>";
3497       break;
3498   }
3499 }
3500 
BriefPrintDetails(std::ostream & os)3501 void Struct::BriefPrintDetails(std::ostream& os) {}
3502 
BriefPrintDetails(std::ostream & os)3503 void Tuple2::BriefPrintDetails(std::ostream& os) {
3504   os << " " << Brief(value1()) << ", " << Brief(value2());
3505 }
3506 
BriefPrintDetails(std::ostream & os)3507 void Tuple3::BriefPrintDetails(std::ostream& os) {
3508   os << " " << Brief(value1()) << ", " << Brief(value2()) << ", "
3509      << Brief(value3());
3510 }
3511 
BriefPrintDetails(std::ostream & os)3512 void CallableTask::BriefPrintDetails(std::ostream& os) {
3513   os << " callable=" << Brief(callable());
3514 }
3515 
Iterate(ObjectVisitor * v)3516 void HeapObject::Iterate(ObjectVisitor* v) { IterateFast<ObjectVisitor>(v); }
3517 
3518 
IterateBody(ObjectVisitor * v)3519 void HeapObject::IterateBody(ObjectVisitor* v) {
3520   Map* m = map();
3521   IterateBodyFast<ObjectVisitor>(m, SizeFromMap(m), v);
3522 }
3523 
IterateBody(Map * map,int object_size,ObjectVisitor * v)3524 void HeapObject::IterateBody(Map* map, int object_size, ObjectVisitor* v) {
3525   IterateBodyFast<ObjectVisitor>(map, object_size, v);
3526 }
3527 
3528 
3529 struct CallIsValidSlot {
3530   template <typename BodyDescriptor>
applyv8::internal::CallIsValidSlot3531   static bool apply(Map* map, HeapObject* obj, int offset, int) {
3532     return BodyDescriptor::IsValidSlot(map, obj, offset);
3533   }
3534 };
3535 
IsValidSlot(Map * map,int offset)3536 bool HeapObject::IsValidSlot(Map* map, int offset) {
3537   DCHECK_NE(0, offset);
3538   return BodyDescriptorApply<CallIsValidSlot, bool>(map->instance_type(), map,
3539                                                     this, offset, 0);
3540 }
3541 
HeapNumberPrint(std::ostream & os)3542 void HeapNumber::HeapNumberPrint(std::ostream& os) {  // NOLINT
3543   os << value();
3544 }
3545 
class_name()3546 String* JSReceiver::class_name() {
3547   if (IsFunction()) return GetHeap()->Function_string();
3548   if (IsJSArgumentsObject()) return GetHeap()->Arguments_string();
3549   if (IsJSArray()) return GetHeap()->Array_string();
3550   if (IsJSArrayBuffer()) {
3551     if (JSArrayBuffer::cast(this)->is_shared()) {
3552       return GetHeap()->SharedArrayBuffer_string();
3553     }
3554     return GetHeap()->ArrayBuffer_string();
3555   }
3556   if (IsJSArrayIterator()) return GetHeap()->ArrayIterator_string();
3557   if (IsJSDate()) return GetHeap()->Date_string();
3558   if (IsJSError()) return GetHeap()->Error_string();
3559   if (IsJSGeneratorObject()) return GetHeap()->Generator_string();
3560   if (IsJSMap()) return GetHeap()->Map_string();
3561   if (IsJSMapIterator()) return GetHeap()->MapIterator_string();
3562   if (IsJSProxy()) {
3563     return map()->is_callable() ? GetHeap()->Function_string()
3564                                 : GetHeap()->Object_string();
3565   }
3566   if (IsJSRegExp()) return GetHeap()->RegExp_string();
3567   if (IsJSSet()) return GetHeap()->Set_string();
3568   if (IsJSSetIterator()) return GetHeap()->SetIterator_string();
3569   if (IsJSTypedArray()) {
3570 #define SWITCH_KIND(Type, type, TYPE, ctype, size) \
3571   if (map()->elements_kind() == TYPE##_ELEMENTS) { \
3572     return GetHeap()->Type##Array_string();        \
3573   }
3574     TYPED_ARRAYS(SWITCH_KIND)
3575 #undef SWITCH_KIND
3576   }
3577   if (IsJSValue()) {
3578     Object* value = JSValue::cast(this)->value();
3579     if (value->IsBoolean()) return GetHeap()->Boolean_string();
3580     if (value->IsString()) return GetHeap()->String_string();
3581     if (value->IsNumber()) return GetHeap()->Number_string();
3582     if (value->IsBigInt()) return GetHeap()->BigInt_string();
3583     if (value->IsSymbol()) return GetHeap()->Symbol_string();
3584     if (value->IsScript()) return GetHeap()->Script_string();
3585     UNREACHABLE();
3586   }
3587   if (IsJSWeakMap()) return GetHeap()->WeakMap_string();
3588   if (IsJSWeakSet()) return GetHeap()->WeakSet_string();
3589   if (IsJSGlobalProxy()) return GetHeap()->global_string();
3590 
3591   Object* maybe_constructor = map()->GetConstructor();
3592   if (maybe_constructor->IsJSFunction()) {
3593     JSFunction* constructor = JSFunction::cast(maybe_constructor);
3594     if (constructor->shared()->IsApiFunction()) {
3595       maybe_constructor = constructor->shared()->get_api_func_data();
3596     }
3597   }
3598 
3599   if (maybe_constructor->IsFunctionTemplateInfo()) {
3600     FunctionTemplateInfo* info = FunctionTemplateInfo::cast(maybe_constructor);
3601     if (info->class_name()->IsString()) return String::cast(info->class_name());
3602   }
3603 
3604   return GetHeap()->Object_string();
3605 }
3606 
CanBeRehashed() const3607 bool HeapObject::CanBeRehashed() const {
3608   DCHECK(NeedsRehashing());
3609   switch (map()->instance_type()) {
3610     case HASH_TABLE_TYPE:
3611       // TODO(yangguo): actually support rehashing OrderedHash{Map,Set}.
3612       return IsNameDictionary() || IsGlobalDictionary() ||
3613              IsNumberDictionary() || IsSimpleNumberDictionary() ||
3614              IsStringTable();
3615     case DESCRIPTOR_ARRAY_TYPE:
3616       return true;
3617     case TRANSITION_ARRAY_TYPE:
3618       return true;
3619     case SMALL_ORDERED_HASH_MAP_TYPE:
3620       return SmallOrderedHashMap::cast(this)->NumberOfElements() == 0;
3621     case SMALL_ORDERED_HASH_SET_TYPE:
3622       return SmallOrderedHashMap::cast(this)->NumberOfElements() == 0;
3623     default:
3624       return false;
3625   }
3626   return false;
3627 }
3628 
RehashBasedOnMap()3629 void HeapObject::RehashBasedOnMap() {
3630   switch (map()->instance_type()) {
3631     case HASH_TABLE_TYPE:
3632       if (IsNameDictionary()) {
3633         NameDictionary::cast(this)->Rehash();
3634       } else if (IsNumberDictionary()) {
3635         NumberDictionary::cast(this)->Rehash();
3636       } else if (IsSimpleNumberDictionary()) {
3637         SimpleNumberDictionary::cast(this)->Rehash();
3638       } else if (IsGlobalDictionary()) {
3639         GlobalDictionary::cast(this)->Rehash();
3640       } else if (IsStringTable()) {
3641         StringTable::cast(this)->Rehash();
3642       } else {
3643         UNREACHABLE();
3644       }
3645       break;
3646     case DESCRIPTOR_ARRAY_TYPE:
3647       DCHECK_LE(1, DescriptorArray::cast(this)->number_of_descriptors());
3648       DescriptorArray::cast(this)->Sort();
3649       break;
3650     case TRANSITION_ARRAY_TYPE:
3651       TransitionArray::cast(this)->Sort();
3652       break;
3653     case SMALL_ORDERED_HASH_MAP_TYPE:
3654       DCHECK_EQ(0, SmallOrderedHashMap::cast(this)->NumberOfElements());
3655       break;
3656     case SMALL_ORDERED_HASH_SET_TYPE:
3657       DCHECK_EQ(0, SmallOrderedHashSet::cast(this)->NumberOfElements());
3658       break;
3659     default:
3660       break;
3661   }
3662 }
3663 
3664 // static
GetConstructorName(Handle<JSReceiver> receiver)3665 Handle<String> JSReceiver::GetConstructorName(Handle<JSReceiver> receiver) {
3666   Isolate* isolate = receiver->GetIsolate();
3667 
3668   // If the object was instantiated simply with base == new.target, the
3669   // constructor on the map provides the most accurate name.
3670   // Don't provide the info for prototypes, since their constructors are
3671   // reclaimed and replaced by Object in OptimizeAsPrototype.
3672   if (!receiver->IsJSProxy() && receiver->map()->new_target_is_base() &&
3673       !receiver->map()->is_prototype_map()) {
3674     Object* maybe_constructor = receiver->map()->GetConstructor();
3675     if (maybe_constructor->IsJSFunction()) {
3676       JSFunction* constructor = JSFunction::cast(maybe_constructor);
3677       String* name = constructor->shared()->DebugName();
3678       if (name->length() != 0 &&
3679           !name->Equals(isolate->heap()->Object_string())) {
3680         return handle(name, isolate);
3681       }
3682     } else if (maybe_constructor->IsFunctionTemplateInfo()) {
3683       FunctionTemplateInfo* info =
3684           FunctionTemplateInfo::cast(maybe_constructor);
3685       if (info->class_name()->IsString()) {
3686         return handle(String::cast(info->class_name()), isolate);
3687       }
3688     }
3689   }
3690 
3691   Handle<Object> maybe_tag = JSReceiver::GetDataProperty(
3692       receiver, isolate->factory()->to_string_tag_symbol());
3693   if (maybe_tag->IsString()) return Handle<String>::cast(maybe_tag);
3694 
3695   PrototypeIterator iter(isolate, receiver);
3696   if (iter.IsAtEnd()) return handle(receiver->class_name());
3697   Handle<JSReceiver> start = PrototypeIterator::GetCurrent<JSReceiver>(iter);
3698   LookupIterator it(receiver, isolate->factory()->constructor_string(), start,
3699                     LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
3700   Handle<Object> maybe_constructor = JSReceiver::GetDataProperty(&it);
3701   Handle<String> result = isolate->factory()->Object_string();
3702   if (maybe_constructor->IsJSFunction()) {
3703     JSFunction* constructor = JSFunction::cast(*maybe_constructor);
3704     String* name = constructor->shared()->DebugName();
3705     if (name->length() > 0) result = handle(name, isolate);
3706   }
3707 
3708   return result.is_identical_to(isolate->factory()->Object_string())
3709              ? handle(receiver->class_name())
3710              : result;
3711 }
3712 
GetCreationContext()3713 Handle<Context> JSReceiver::GetCreationContext() {
3714   JSReceiver* receiver = this;
3715   // Externals are JSObjects with null as a constructor.
3716   DCHECK(!receiver->IsExternal());
3717   Object* constructor = receiver->map()->GetConstructor();
3718   JSFunction* function;
3719   if (constructor->IsJSFunction()) {
3720     function = JSFunction::cast(constructor);
3721   } else if (constructor->IsFunctionTemplateInfo()) {
3722     // Remote objects don't have a creation context.
3723     return Handle<Context>::null();
3724   } else {
3725     // Functions have null as a constructor,
3726     // but any JSFunction knows its context immediately.
3727     CHECK(receiver->IsJSFunction());
3728     function = JSFunction::cast(receiver);
3729   }
3730 
3731   return function->has_context()
3732              ? Handle<Context>(function->context()->native_context())
3733              : Handle<Context>::null();
3734 }
3735 
3736 // static
WrapFieldType(Handle<FieldType> type)3737 Handle<Object> Map::WrapFieldType(Handle<FieldType> type) {
3738   if (type->IsClass()) return Map::WeakCellForMap(type->AsClass());
3739   return type;
3740 }
3741 
3742 // static
UnwrapFieldType(Object * wrapped_type)3743 FieldType* Map::UnwrapFieldType(Object* wrapped_type) {
3744   Object* value = wrapped_type;
3745   if (value->IsWeakCell()) {
3746     if (WeakCell::cast(value)->cleared()) return FieldType::None();
3747     value = WeakCell::cast(value)->value();
3748   }
3749   return FieldType::cast(value);
3750 }
3751 
CopyWithField(Handle<Map> map,Handle<Name> name,Handle<FieldType> type,PropertyAttributes attributes,PropertyConstness constness,Representation representation,TransitionFlag flag)3752 MaybeHandle<Map> Map::CopyWithField(Handle<Map> map, Handle<Name> name,
3753                                     Handle<FieldType> type,
3754                                     PropertyAttributes attributes,
3755                                     PropertyConstness constness,
3756                                     Representation representation,
3757                                     TransitionFlag flag) {
3758   DCHECK(DescriptorArray::kNotFound ==
3759          map->instance_descriptors()->Search(
3760              *name, map->NumberOfOwnDescriptors()));
3761 
3762   // Ensure the descriptor array does not get too big.
3763   if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
3764     return MaybeHandle<Map>();
3765   }
3766 
3767   Isolate* isolate = map->GetIsolate();
3768 
3769   // Compute the new index for new field.
3770   int index = map->NextFreePropertyIndex();
3771 
3772   if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
3773     constness = kMutable;
3774     representation = Representation::Tagged();
3775     type = FieldType::Any(isolate);
3776   } else {
3777     Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
3778         isolate, map->instance_type(), &constness, &representation, &type);
3779   }
3780 
3781   Handle<Object> wrapped_type(WrapFieldType(type));
3782 
3783   DCHECK_IMPLIES(!FLAG_track_constant_fields, constness == kMutable);
3784   Descriptor d = Descriptor::DataField(name, index, attributes, constness,
3785                                        representation, wrapped_type);
3786   Handle<Map> new_map = Map::CopyAddDescriptor(map, &d, flag);
3787   new_map->AccountAddedPropertyField();
3788   return new_map;
3789 }
3790 
3791 
CopyWithConstant(Handle<Map> map,Handle<Name> name,Handle<Object> constant,PropertyAttributes attributes,TransitionFlag flag)3792 MaybeHandle<Map> Map::CopyWithConstant(Handle<Map> map,
3793                                        Handle<Name> name,
3794                                        Handle<Object> constant,
3795                                        PropertyAttributes attributes,
3796                                        TransitionFlag flag) {
3797   // Ensure the descriptor array does not get too big.
3798   if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
3799     return MaybeHandle<Map>();
3800   }
3801 
3802   if (FLAG_track_constant_fields) {
3803     Isolate* isolate = map->GetIsolate();
3804     Representation representation = constant->OptimalRepresentation();
3805     Handle<FieldType> type = constant->OptimalType(isolate, representation);
3806     return CopyWithField(map, name, type, attributes, kConst, representation,
3807                          flag);
3808   } else {
3809     // Allocate new instance descriptors with (name, constant) added.
3810     Descriptor d = Descriptor::DataConstant(name, 0, constant, attributes);
3811     Handle<Map> new_map = Map::CopyAddDescriptor(map, &d, flag);
3812     return new_map;
3813   }
3814 }
3815 
Mnemonic() const3816 const char* Representation::Mnemonic() const {
3817   switch (kind_) {
3818     case kNone: return "v";
3819     case kTagged: return "t";
3820     case kSmi: return "s";
3821     case kDouble: return "d";
3822     case kInteger32: return "i";
3823     case kHeapObject: return "h";
3824     case kExternal: return "x";
3825     default:
3826       UNREACHABLE();
3827   }
3828 }
3829 
TransitionRemovesTaggedField(Map * target) const3830 bool Map::TransitionRemovesTaggedField(Map* target) const {
3831   int inobject = NumberOfFields();
3832   int target_inobject = target->NumberOfFields();
3833   for (int i = target_inobject; i < inobject; i++) {
3834     FieldIndex index = FieldIndex::ForPropertyIndex(this, i);
3835     if (!IsUnboxedDoubleField(index)) return true;
3836   }
3837   return false;
3838 }
3839 
TransitionChangesTaggedFieldToUntaggedField(Map * target) const3840 bool Map::TransitionChangesTaggedFieldToUntaggedField(Map* target) const {
3841   int inobject = NumberOfFields();
3842   int target_inobject = target->NumberOfFields();
3843   int limit = Min(inobject, target_inobject);
3844   for (int i = 0; i < limit; i++) {
3845     FieldIndex index = FieldIndex::ForPropertyIndex(target, i);
3846     if (!IsUnboxedDoubleField(index) && target->IsUnboxedDoubleField(index)) {
3847       return true;
3848     }
3849   }
3850   return false;
3851 }
3852 
TransitionRequiresSynchronizationWithGC(Map * target) const3853 bool Map::TransitionRequiresSynchronizationWithGC(Map* target) const {
3854   return TransitionRemovesTaggedField(target) ||
3855          TransitionChangesTaggedFieldToUntaggedField(target);
3856 }
3857 
InstancesNeedRewriting(Map * target) const3858 bool Map::InstancesNeedRewriting(Map* target) const {
3859   int target_number_of_fields = target->NumberOfFields();
3860   int target_inobject = target->GetInObjectProperties();
3861   int target_unused = target->UnusedPropertyFields();
3862   int old_number_of_fields;
3863 
3864   return InstancesNeedRewriting(target, target_number_of_fields,
3865                                 target_inobject, target_unused,
3866                                 &old_number_of_fields);
3867 }
3868 
InstancesNeedRewriting(Map * target,int target_number_of_fields,int target_inobject,int target_unused,int * old_number_of_fields) const3869 bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields,
3870                                  int target_inobject, int target_unused,
3871                                  int* old_number_of_fields) const {
3872   // If fields were added (or removed), rewrite the instance.
3873   *old_number_of_fields = NumberOfFields();
3874   DCHECK(target_number_of_fields >= *old_number_of_fields);
3875   if (target_number_of_fields != *old_number_of_fields) return true;
3876 
3877   // If smi descriptors were replaced by double descriptors, rewrite.
3878   DescriptorArray* old_desc = instance_descriptors();
3879   DescriptorArray* new_desc = target->instance_descriptors();
3880   int limit = NumberOfOwnDescriptors();
3881   for (int i = 0; i < limit; i++) {
3882     if (new_desc->GetDetails(i).representation().IsDouble() !=
3883         old_desc->GetDetails(i).representation().IsDouble()) {
3884       return true;
3885     }
3886   }
3887 
3888   // If no fields were added, and no inobject properties were removed, setting
3889   // the map is sufficient.
3890   if (target_inobject == GetInObjectProperties()) return false;
3891   // In-object slack tracking may have reduced the object size of the new map.
3892   // In that case, succeed if all existing fields were inobject, and they still
3893   // fit within the new inobject size.
3894   DCHECK(target_inobject < GetInObjectProperties());
3895   if (target_number_of_fields <= target_inobject) {
3896     DCHECK(target_number_of_fields + target_unused == target_inobject);
3897     return false;
3898   }
3899   // Otherwise, properties will need to be moved to the backing store.
3900   return true;
3901 }
3902 
3903 
3904 // static
UpdatePrototypeUserRegistration(Handle<Map> old_map,Handle<Map> new_map,Isolate * isolate)3905 void JSObject::UpdatePrototypeUserRegistration(Handle<Map> old_map,
3906                                                Handle<Map> new_map,
3907                                                Isolate* isolate) {
3908   DCHECK(old_map->is_prototype_map());
3909   DCHECK(new_map->is_prototype_map());
3910   bool was_registered = JSObject::UnregisterPrototypeUser(old_map, isolate);
3911   new_map->set_prototype_info(old_map->prototype_info());
3912   old_map->set_prototype_info(Smi::kZero);
3913   if (FLAG_trace_prototype_users) {
3914     PrintF("Moving prototype_info %p from map %p to map %p.\n",
3915            reinterpret_cast<void*>(new_map->prototype_info()),
3916            reinterpret_cast<void*>(*old_map),
3917            reinterpret_cast<void*>(*new_map));
3918   }
3919   if (was_registered) {
3920     if (new_map->prototype_info()->IsPrototypeInfo()) {
3921       // The new map isn't registered with its prototype yet; reflect this fact
3922       // in the PrototypeInfo it just inherited from the old map.
3923       PrototypeInfo::cast(new_map->prototype_info())
3924           ->set_registry_slot(PrototypeInfo::UNREGISTERED);
3925     }
3926     JSObject::LazyRegisterPrototypeUser(new_map, isolate);
3927   }
3928 }
3929 
3930 namespace {
3931 // To migrate a fast instance to a fast map:
3932 // - First check whether the instance needs to be rewritten. If not, simply
3933 //   change the map.
3934 // - Otherwise, allocate a fixed array large enough to hold all fields, in
3935 //   addition to unused space.
3936 // - Copy all existing properties in, in the following order: backing store
3937 //   properties, unused fields, inobject properties.
3938 // - If all allocation succeeded, commit the state atomically:
3939 //   * Copy inobject properties from the backing store back into the object.
3940 //   * Trim the difference in instance size of the object. This also cleanly
3941 //     frees inobject properties that moved to the backing store.
3942 //   * If there are properties left in the backing store, trim of the space used
3943 //     to temporarily store the inobject properties.
3944 //   * If there are properties left in the backing store, install the backing
3945 //     store.
MigrateFastToFast(Handle<JSObject> object,Handle<Map> new_map)3946 void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
3947   Isolate* isolate = object->GetIsolate();
3948   Handle<Map> old_map(object->map());
3949   // In case of a regular transition.
3950   if (new_map->GetBackPointer() == *old_map) {
3951     // If the map does not add named properties, simply set the map.
3952     if (old_map->NumberOfOwnDescriptors() ==
3953         new_map->NumberOfOwnDescriptors()) {
3954       object->synchronized_set_map(*new_map);
3955       return;
3956     }
3957 
3958     PropertyDetails details = new_map->GetLastDescriptorDetails();
3959     int target_index = details.field_index() - new_map->GetInObjectProperties();
3960     int property_array_length = object->property_array()->length();
3961     bool have_space = old_map->UnusedPropertyFields() > 0 ||
3962                       (details.location() == kField && target_index >= 0 &&
3963                        property_array_length > target_index);
3964     // Either new_map adds an kDescriptor property, or a kField property for
3965     // which there is still space, and which does not require a mutable double
3966     // box (an out-of-object double).
3967     if (details.location() == kDescriptor ||
3968         (have_space && ((FLAG_unbox_double_fields && target_index < 0) ||
3969                         !details.representation().IsDouble()))) {
3970       object->synchronized_set_map(*new_map);
3971       return;
3972     }
3973 
3974     // If there is still space in the object, we need to allocate a mutable
3975     // double box.
3976     if (have_space) {
3977       FieldIndex index =
3978           FieldIndex::ForDescriptor(*new_map, new_map->LastAdded());
3979       DCHECK(details.representation().IsDouble());
3980       DCHECK(!new_map->IsUnboxedDoubleField(index));
3981       Handle<Object> value = isolate->factory()->NewMutableHeapNumber();
3982       object->RawFastPropertyAtPut(index, *value);
3983       object->synchronized_set_map(*new_map);
3984       return;
3985     }
3986 
3987     // This migration is a transition from a map that has run out of property
3988     // space. Extend the backing store.
3989     int grow_by = new_map->UnusedPropertyFields() + 1;
3990     Handle<PropertyArray> old_storage(object->property_array());
3991     Handle<PropertyArray> new_storage =
3992         isolate->factory()->CopyPropertyArrayAndGrow(old_storage, grow_by);
3993 
3994     // Properly initialize newly added property.
3995     Handle<Object> value;
3996     if (details.representation().IsDouble()) {
3997       value = isolate->factory()->NewMutableHeapNumber();
3998     } else {
3999       value = isolate->factory()->uninitialized_value();
4000     }
4001     DCHECK_EQ(kField, details.location());
4002     DCHECK_EQ(kData, details.kind());
4003     DCHECK_GE(target_index, 0);  // Must be a backing store index.
4004     new_storage->set(target_index, *value);
4005 
4006     // From here on we cannot fail and we shouldn't GC anymore.
4007     DisallowHeapAllocation no_allocation;
4008 
4009     // Set the new property value and do the map transition.
4010     object->SetProperties(*new_storage);
4011     object->synchronized_set_map(*new_map);
4012     return;
4013   }
4014 
4015   int old_number_of_fields;
4016   int number_of_fields = new_map->NumberOfFields();
4017   int inobject = new_map->GetInObjectProperties();
4018   int unused = new_map->UnusedPropertyFields();
4019 
4020   // Nothing to do if no functions were converted to fields and no smis were
4021   // converted to doubles.
4022   if (!old_map->InstancesNeedRewriting(*new_map, number_of_fields, inobject,
4023                                        unused, &old_number_of_fields)) {
4024     object->synchronized_set_map(*new_map);
4025     return;
4026   }
4027 
4028   int total_size = number_of_fields + unused;
4029   int external = total_size - inobject;
4030   Handle<PropertyArray> array = isolate->factory()->NewPropertyArray(external);
4031 
4032   // We use this array to temporarily store the inobject properties.
4033   Handle<FixedArray> inobject_props =
4034       isolate->factory()->NewFixedArray(inobject);
4035 
4036   Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors());
4037   Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors());
4038   int old_nof = old_map->NumberOfOwnDescriptors();
4039   int new_nof = new_map->NumberOfOwnDescriptors();
4040 
4041   // This method only supports generalizing instances to at least the same
4042   // number of properties.
4043   DCHECK(old_nof <= new_nof);
4044 
4045   for (int i = 0; i < old_nof; i++) {
4046     PropertyDetails details = new_descriptors->GetDetails(i);
4047     if (details.location() != kField) continue;
4048     DCHECK_EQ(kData, details.kind());
4049     PropertyDetails old_details = old_descriptors->GetDetails(i);
4050     Representation old_representation = old_details.representation();
4051     Representation representation = details.representation();
4052     Handle<Object> value;
4053     if (old_details.location() == kDescriptor) {
4054       if (old_details.kind() == kAccessor) {
4055         // In case of kAccessor -> kData property reconfiguration, the property
4056         // must already be prepared for data of certain type.
4057         DCHECK(!details.representation().IsNone());
4058         if (details.representation().IsDouble()) {
4059           value = isolate->factory()->NewMutableHeapNumber();
4060         } else {
4061           value = isolate->factory()->uninitialized_value();
4062         }
4063       } else {
4064         DCHECK_EQ(kData, old_details.kind());
4065         value = handle(old_descriptors->GetValue(i), isolate);
4066         DCHECK(!old_representation.IsDouble() && !representation.IsDouble());
4067       }
4068     } else {
4069       DCHECK_EQ(kField, old_details.location());
4070       FieldIndex index = FieldIndex::ForDescriptor(*old_map, i);
4071       if (object->IsUnboxedDoubleField(index)) {
4072         uint64_t old_bits = object->RawFastDoublePropertyAsBitsAt(index);
4073         value = isolate->factory()->NewHeapNumberFromBits(
4074             old_bits, representation.IsDouble() ? MUTABLE : IMMUTABLE);
4075 
4076       } else {
4077         value = handle(object->RawFastPropertyAt(index), isolate);
4078         if (!old_representation.IsDouble() && representation.IsDouble()) {
4079           DCHECK_IMPLIES(old_representation.IsNone(),
4080                          value->IsUninitialized(isolate));
4081           value = Object::NewStorageFor(isolate, value, representation);
4082         } else if (old_representation.IsDouble() &&
4083                    !representation.IsDouble()) {
4084           value = Object::WrapForRead(isolate, value, old_representation);
4085         }
4086       }
4087     }
4088     DCHECK(!(representation.IsDouble() && value->IsSmi()));
4089     int target_index = new_descriptors->GetFieldIndex(i);
4090     if (target_index < inobject) {
4091       inobject_props->set(target_index, *value);
4092     } else {
4093       array->set(target_index - inobject, *value);
4094     }
4095   }
4096 
4097   for (int i = old_nof; i < new_nof; i++) {
4098     PropertyDetails details = new_descriptors->GetDetails(i);
4099     if (details.location() != kField) continue;
4100     DCHECK_EQ(kData, details.kind());
4101     Handle<Object> value;
4102     if (details.representation().IsDouble()) {
4103       value = isolate->factory()->NewMutableHeapNumber();
4104     } else {
4105       value = isolate->factory()->uninitialized_value();
4106     }
4107     int target_index = new_descriptors->GetFieldIndex(i);
4108     if (target_index < inobject) {
4109       inobject_props->set(target_index, *value);
4110     } else {
4111       array->set(target_index - inobject, *value);
4112     }
4113   }
4114 
4115   // From here on we cannot fail and we shouldn't GC anymore.
4116   DisallowHeapAllocation no_allocation;
4117 
4118   Heap* heap = isolate->heap();
4119 
4120   int old_instance_size = old_map->instance_size();
4121 
4122   heap->NotifyObjectLayoutChange(*object, old_instance_size, no_allocation);
4123 
4124   // Copy (real) inobject properties. If necessary, stop at number_of_fields to
4125   // avoid overwriting |one_pointer_filler_map|.
4126   int limit = Min(inobject, number_of_fields);
4127   for (int i = 0; i < limit; i++) {
4128     FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
4129     Object* value = inobject_props->get(i);
4130     // Can't use JSObject::FastPropertyAtPut() because proper map was not set
4131     // yet.
4132     if (new_map->IsUnboxedDoubleField(index)) {
4133       DCHECK(value->IsMutableHeapNumber());
4134       // Ensure that all bits of the double value are preserved.
4135       object->RawFastDoublePropertyAsBitsAtPut(
4136           index, HeapNumber::cast(value)->value_as_bits());
4137       if (i < old_number_of_fields && !old_map->IsUnboxedDoubleField(index)) {
4138         // Transition from tagged to untagged slot.
4139         heap->ClearRecordedSlot(*object,
4140                                 HeapObject::RawField(*object, index.offset()));
4141       } else {
4142         DCHECK(!heap->HasRecordedSlot(
4143             *object, HeapObject::RawField(*object, index.offset())));
4144       }
4145     } else {
4146       object->RawFastPropertyAtPut(index, value);
4147     }
4148   }
4149 
4150   object->SetProperties(*array);
4151 
4152   // Create filler object past the new instance size.
4153   int new_instance_size = new_map->instance_size();
4154   int instance_size_delta = old_instance_size - new_instance_size;
4155   DCHECK_GE(instance_size_delta, 0);
4156 
4157   if (instance_size_delta > 0) {
4158     Address address = object->address();
4159     heap->CreateFillerObjectAt(address + new_instance_size, instance_size_delta,
4160                                ClearRecordedSlots::kYes);
4161   }
4162 
4163   // We are storing the new map using release store after creating a filler for
4164   // the left-over space to avoid races with the sweeper thread.
4165   object->synchronized_set_map(*new_map);
4166 }
4167 
MigrateFastToSlow(Handle<JSObject> object,Handle<Map> new_map,int expected_additional_properties)4168 void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map,
4169                        int expected_additional_properties) {
4170   // The global object is always normalized.
4171   DCHECK(!object->IsJSGlobalObject());
4172   // JSGlobalProxy must never be normalized
4173   DCHECK(!object->IsJSGlobalProxy());
4174 
4175   DCHECK_IMPLIES(new_map->is_prototype_map(),
4176                  Map::IsPrototypeChainInvalidated(*new_map));
4177 
4178   Isolate* isolate = object->GetIsolate();
4179   HandleScope scope(isolate);
4180   Handle<Map> map(object->map());
4181 
4182   // Allocate new content.
4183   int real_size = map->NumberOfOwnDescriptors();
4184   int property_count = real_size;
4185   if (expected_additional_properties > 0) {
4186     property_count += expected_additional_properties;
4187   } else {
4188     // Make space for two more properties.
4189     property_count += NameDictionary::kInitialCapacity;
4190   }
4191   Handle<NameDictionary> dictionary =
4192       NameDictionary::New(isolate, property_count);
4193 
4194   Handle<DescriptorArray> descs(map->instance_descriptors());
4195   for (int i = 0; i < real_size; i++) {
4196     PropertyDetails details = descs->GetDetails(i);
4197     Handle<Name> key(descs->GetKey(i));
4198     Handle<Object> value;
4199     if (details.location() == kField) {
4200       FieldIndex index = FieldIndex::ForDescriptor(*map, i);
4201       if (details.kind() == kData) {
4202         if (object->IsUnboxedDoubleField(index)) {
4203           double old_value = object->RawFastDoublePropertyAt(index);
4204           value = isolate->factory()->NewHeapNumber(old_value);
4205         } else {
4206           value = handle(object->RawFastPropertyAt(index), isolate);
4207           if (details.representation().IsDouble()) {
4208             DCHECK(value->IsMutableHeapNumber());
4209             Handle<HeapNumber> old = Handle<HeapNumber>::cast(value);
4210             value = isolate->factory()->NewHeapNumber(old->value());
4211           }
4212         }
4213       } else {
4214         DCHECK_EQ(kAccessor, details.kind());
4215         value = handle(object->RawFastPropertyAt(index), isolate);
4216       }
4217 
4218     } else {
4219       DCHECK_EQ(kDescriptor, details.location());
4220       value = handle(descs->GetValue(i), isolate);
4221     }
4222     DCHECK(!value.is_null());
4223     PropertyDetails d(details.kind(), details.attributes(),
4224                       PropertyCellType::kNoCell);
4225     dictionary = NameDictionary::Add(dictionary, key, value, d);
4226   }
4227 
4228   // Copy the next enumeration index from instance descriptor.
4229   dictionary->SetNextEnumerationIndex(real_size + 1);
4230 
4231   // From here on we cannot fail and we shouldn't GC anymore.
4232   DisallowHeapAllocation no_allocation;
4233 
4234   Heap* heap = isolate->heap();
4235   int old_instance_size = map->instance_size();
4236   heap->NotifyObjectLayoutChange(*object, old_instance_size, no_allocation);
4237 
4238   // Resize the object in the heap if necessary.
4239   int new_instance_size = new_map->instance_size();
4240   int instance_size_delta = old_instance_size - new_instance_size;
4241   DCHECK_GE(instance_size_delta, 0);
4242 
4243   if (instance_size_delta > 0) {
4244     heap->CreateFillerObjectAt(object->address() + new_instance_size,
4245                                instance_size_delta, ClearRecordedSlots::kYes);
4246   }
4247 
4248   // We are storing the new map using release store after creating a filler for
4249   // the left-over space to avoid races with the sweeper thread.
4250   object->synchronized_set_map(*new_map);
4251 
4252   object->SetProperties(*dictionary);
4253 
4254   // Ensure that in-object space of slow-mode object does not contain random
4255   // garbage.
4256   int inobject_properties = new_map->GetInObjectProperties();
4257   if (inobject_properties) {
4258     Heap* heap = isolate->heap();
4259     heap->ClearRecordedSlotRange(
4260         object->address() + map->GetInObjectPropertyOffset(0),
4261         object->address() + new_instance_size);
4262 
4263     for (int i = 0; i < inobject_properties; i++) {
4264       FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
4265       object->RawFastPropertyAtPut(index, Smi::kZero);
4266     }
4267   }
4268 
4269   isolate->counters()->props_to_dictionary()->Increment();
4270 
4271 #ifdef DEBUG
4272   if (FLAG_trace_normalization) {
4273     OFStream os(stdout);
4274     os << "Object properties have been normalized:\n";
4275     object->Print(os);
4276   }
4277 #endif
4278 }
4279 
4280 }  // namespace
4281 
4282 // static
NotifyMapChange(Handle<Map> old_map,Handle<Map> new_map,Isolate * isolate)4283 void JSObject::NotifyMapChange(Handle<Map> old_map, Handle<Map> new_map,
4284                                Isolate* isolate) {
4285   if (!old_map->is_prototype_map()) return;
4286 
4287   InvalidatePrototypeChains(*old_map);
4288 
4289   // If the map was registered with its prototype before, ensure that it
4290   // registers with its new prototype now. This preserves the invariant that
4291   // when a map on a prototype chain is registered with its prototype, then
4292   // all prototypes further up the chain are also registered with their
4293   // respective prototypes.
4294   UpdatePrototypeUserRegistration(old_map, new_map, isolate);
4295 }
4296 
MigrateToMap(Handle<JSObject> object,Handle<Map> new_map,int expected_additional_properties)4297 void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
4298                             int expected_additional_properties) {
4299   if (object->map() == *new_map) return;
4300   Handle<Map> old_map(object->map());
4301   NotifyMapChange(old_map, new_map, new_map->GetIsolate());
4302 
4303   if (old_map->is_dictionary_map()) {
4304     // For slow-to-fast migrations JSObject::MigrateSlowToFast()
4305     // must be used instead.
4306     CHECK(new_map->is_dictionary_map());
4307 
4308     // Slow-to-slow migration is trivial.
4309     object->synchronized_set_map(*new_map);
4310   } else if (!new_map->is_dictionary_map()) {
4311     MigrateFastToFast(object, new_map);
4312     if (old_map->is_prototype_map()) {
4313       DCHECK(!old_map->is_stable());
4314       DCHECK(new_map->is_stable());
4315       DCHECK(new_map->owns_descriptors());
4316       DCHECK(old_map->owns_descriptors());
4317       // Transfer ownership to the new map. Keep the descriptor pointer of the
4318       // old map intact because the concurrent marker might be iterating the
4319       // object with the old map.
4320       old_map->set_owns_descriptors(false);
4321       DCHECK(old_map->is_abandoned_prototype_map());
4322       // Ensure that no transition was inserted for prototype migrations.
4323       DCHECK_EQ(0, TransitionsAccessor(old_map).NumberOfTransitions());
4324       DCHECK(new_map->GetBackPointer()->IsUndefined(new_map->GetIsolate()));
4325       DCHECK(object->map() != *old_map);
4326     }
4327   } else {
4328     MigrateFastToSlow(object, new_map, expected_additional_properties);
4329   }
4330 
4331   // Careful: Don't allocate here!
4332   // For some callers of this method, |object| might be in an inconsistent
4333   // state now: the new map might have a new elements_kind, but the object's
4334   // elements pointer hasn't been updated yet. Callers will fix this, but in
4335   // the meantime, (indirectly) calling JSObjectVerify() must be avoided.
4336   // When adding code here, add a DisallowHeapAllocation too.
4337 }
4338 
ForceSetPrototype(Handle<JSObject> object,Handle<Object> proto)4339 void JSObject::ForceSetPrototype(Handle<JSObject> object,
4340                                  Handle<Object> proto) {
4341   // object.__proto__ = proto;
4342   Handle<Map> old_map = Handle<Map>(object->map());
4343   Handle<Map> new_map = Map::Copy(old_map, "ForceSetPrototype");
4344   Map::SetPrototype(new_map, proto);
4345   JSObject::MigrateToMap(object, new_map);
4346 }
4347 
NumberOfFields() const4348 int Map::NumberOfFields() const {
4349   DescriptorArray* descriptors = instance_descriptors();
4350   int result = 0;
4351   for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
4352     if (descriptors->GetDetails(i).location() == kField) result++;
4353   }
4354   return result;
4355 }
4356 
HasOutOfObjectProperties() const4357 bool Map::HasOutOfObjectProperties() const {
4358   return GetInObjectProperties() < NumberOfFields();
4359 }
4360 
GeneralizeAllFields()4361 void DescriptorArray::GeneralizeAllFields() {
4362   int length = number_of_descriptors();
4363   for (int i = 0; i < length; i++) {
4364     PropertyDetails details = GetDetails(i);
4365     details = details.CopyWithRepresentation(Representation::Tagged());
4366     if (details.location() == kField) {
4367       DCHECK_EQ(kData, details.kind());
4368       details = details.CopyWithConstness(kMutable);
4369       SetValue(i, FieldType::Any());
4370     }
4371     set(ToDetailsIndex(i), details.AsSmi());
4372   }
4373 }
4374 
CopyGeneralizeAllFields(Handle<Map> map,ElementsKind elements_kind,int modify_index,PropertyKind kind,PropertyAttributes attributes,const char * reason)4375 Handle<Map> Map::CopyGeneralizeAllFields(Handle<Map> map,
4376                                          ElementsKind elements_kind,
4377                                          int modify_index, PropertyKind kind,
4378                                          PropertyAttributes attributes,
4379                                          const char* reason) {
4380   Isolate* isolate = map->GetIsolate();
4381   Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
4382   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
4383   Handle<DescriptorArray> descriptors =
4384       DescriptorArray::CopyUpTo(old_descriptors, number_of_own_descriptors);
4385   descriptors->GeneralizeAllFields();
4386 
4387   Handle<LayoutDescriptor> new_layout_descriptor(
4388       LayoutDescriptor::FastPointerLayout(), isolate);
4389   Handle<Map> new_map = CopyReplaceDescriptors(
4390       map, descriptors, new_layout_descriptor, OMIT_TRANSITION,
4391       MaybeHandle<Name>(), reason, SPECIAL_TRANSITION);
4392 
4393   // Unless the instance is being migrated, ensure that modify_index is a field.
4394   if (modify_index >= 0) {
4395     PropertyDetails details = descriptors->GetDetails(modify_index);
4396     if (details.constness() != kMutable || details.location() != kField ||
4397         details.attributes() != attributes) {
4398       int field_index = details.location() == kField
4399                             ? details.field_index()
4400                             : new_map->NumberOfFields();
4401       Descriptor d = Descriptor::DataField(
4402           handle(descriptors->GetKey(modify_index), isolate), field_index,
4403           attributes, Representation::Tagged());
4404       descriptors->Replace(modify_index, &d);
4405       if (details.location() != kField) {
4406         new_map->AccountAddedPropertyField();
4407       }
4408     } else {
4409       DCHECK(details.attributes() == attributes);
4410     }
4411 
4412     if (FLAG_trace_generalization) {
4413       MaybeHandle<FieldType> field_type = FieldType::None(isolate);
4414       if (details.location() == kField) {
4415         field_type = handle(
4416             map->instance_descriptors()->GetFieldType(modify_index), isolate);
4417       }
4418       map->PrintGeneralization(
4419           stdout, reason, modify_index, new_map->NumberOfOwnDescriptors(),
4420           new_map->NumberOfOwnDescriptors(), details.location() == kDescriptor,
4421           details.representation(), Representation::Tagged(), field_type,
4422           MaybeHandle<Object>(), FieldType::Any(isolate),
4423           MaybeHandle<Object>());
4424     }
4425   }
4426   new_map->set_elements_kind(elements_kind);
4427   return new_map;
4428 }
4429 
DeprecateTransitionTree()4430 void Map::DeprecateTransitionTree() {
4431   if (is_deprecated()) return;
4432   DisallowHeapAllocation no_gc;
4433   TransitionsAccessor transitions(this, &no_gc);
4434   int num_transitions = transitions.NumberOfTransitions();
4435   for (int i = 0; i < num_transitions; ++i) {
4436     transitions.GetTarget(i)->DeprecateTransitionTree();
4437   }
4438   DCHECK(!constructor_or_backpointer()->IsFunctionTemplateInfo());
4439   set_is_deprecated(true);
4440   if (FLAG_trace_maps) {
4441     LOG(GetIsolate(), MapEvent("Deprecate", this, nullptr));
4442   }
4443   dependent_code()->DeoptimizeDependentCodeGroup(
4444       GetIsolate(), DependentCode::kTransitionGroup);
4445   NotifyLeafMapLayoutChange();
4446 }
4447 
4448 
4449 // Installs |new_descriptors| over the current instance_descriptors to ensure
4450 // proper sharing of descriptor arrays.
ReplaceDescriptors(DescriptorArray * new_descriptors,LayoutDescriptor * new_layout_descriptor)4451 void Map::ReplaceDescriptors(DescriptorArray* new_descriptors,
4452                              LayoutDescriptor* new_layout_descriptor) {
4453   Isolate* isolate = GetIsolate();
4454   // Don't overwrite the empty descriptor array or initial map's descriptors.
4455   if (NumberOfOwnDescriptors() == 0 || GetBackPointer()->IsUndefined(isolate)) {
4456     return;
4457   }
4458 
4459   DescriptorArray* to_replace = instance_descriptors();
4460   // Replace descriptors by new_descriptors in all maps that share it. The old
4461   // descriptors will not be trimmed in the mark-compactor, we need to mark
4462   // all its elements.
4463   isolate->heap()->incremental_marking()->RecordWrites(to_replace);
4464   Map* current = this;
4465   while (current->instance_descriptors() == to_replace) {
4466     Object* next = current->GetBackPointer();
4467     if (next->IsUndefined(isolate)) break;  // Stop overwriting at initial map.
4468     current->SetEnumLength(kInvalidEnumCacheSentinel);
4469     current->UpdateDescriptors(new_descriptors, new_layout_descriptor);
4470     current = Map::cast(next);
4471   }
4472   set_owns_descriptors(false);
4473 }
4474 
FindRootMap() const4475 Map* Map::FindRootMap() const {
4476   const Map* result = this;
4477   Isolate* isolate = GetIsolate();
4478   while (true) {
4479     Object* back = result->GetBackPointer();
4480     if (back->IsUndefined(isolate)) {
4481       // Initial map always owns descriptors and doesn't have unused entries
4482       // in the descriptor array.
4483       DCHECK(result->owns_descriptors());
4484       DCHECK_EQ(result->NumberOfOwnDescriptors(),
4485                 result->instance_descriptors()->number_of_descriptors());
4486       return const_cast<Map*>(result);
4487     }
4488     result = Map::cast(back);
4489   }
4490 }
4491 
FindFieldOwner(int descriptor) const4492 Map* Map::FindFieldOwner(int descriptor) const {
4493   DisallowHeapAllocation no_allocation;
4494   DCHECK_EQ(kField, instance_descriptors()->GetDetails(descriptor).location());
4495   const Map* result = this;
4496   Isolate* isolate = GetIsolate();
4497   while (true) {
4498     Object* back = result->GetBackPointer();
4499     if (back->IsUndefined(isolate)) break;
4500     const Map* parent = Map::cast(back);
4501     if (parent->NumberOfOwnDescriptors() <= descriptor) break;
4502     result = parent;
4503   }
4504   return const_cast<Map*>(result);
4505 }
4506 
UpdateFieldType(int descriptor,Handle<Name> name,PropertyConstness new_constness,Representation new_representation,Handle<Object> new_wrapped_type)4507 void Map::UpdateFieldType(int descriptor, Handle<Name> name,
4508                           PropertyConstness new_constness,
4509                           Representation new_representation,
4510                           Handle<Object> new_wrapped_type) {
4511   DCHECK(new_wrapped_type->IsSmi() || new_wrapped_type->IsWeakCell());
4512   // We store raw pointers in the queue, so no allocations are allowed.
4513   DisallowHeapAllocation no_allocation;
4514   PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
4515   if (details.location() != kField) return;
4516   DCHECK_EQ(kData, details.kind());
4517 
4518   Zone zone(GetIsolate()->allocator(), ZONE_NAME);
4519   ZoneQueue<Map*> backlog(&zone);
4520   backlog.push(this);
4521 
4522   while (!backlog.empty()) {
4523     Map* current = backlog.front();
4524     backlog.pop();
4525 
4526     TransitionsAccessor transitions(current, &no_allocation);
4527     int num_transitions = transitions.NumberOfTransitions();
4528     for (int i = 0; i < num_transitions; ++i) {
4529       Map* target = transitions.GetTarget(i);
4530       backlog.push(target);
4531     }
4532     DescriptorArray* descriptors = current->instance_descriptors();
4533     PropertyDetails details = descriptors->GetDetails(descriptor);
4534 
4535     // Currently constness change implies map change.
4536     DCHECK_IMPLIES(new_constness != details.constness(),
4537                    FLAG_modify_map_inplace);
4538 
4539     // It is allowed to change representation here only from None to something.
4540     DCHECK(details.representation().Equals(new_representation) ||
4541            details.representation().IsNone());
4542 
4543     // Skip if already updated the shared descriptor.
4544     if ((FLAG_modify_map_inplace && new_constness != details.constness()) ||
4545         descriptors->GetValue(descriptor) != *new_wrapped_type) {
4546       DCHECK_IMPLIES(!FLAG_track_constant_fields, new_constness == kMutable);
4547       Descriptor d = Descriptor::DataField(
4548           name, descriptors->GetFieldIndex(descriptor), details.attributes(),
4549           new_constness, new_representation, new_wrapped_type);
4550       descriptors->Replace(descriptor, &d);
4551     }
4552   }
4553 }
4554 
FieldTypeIsCleared(Representation rep,FieldType * type)4555 bool FieldTypeIsCleared(Representation rep, FieldType* type) {
4556   return type->IsNone() && rep.IsHeapObject();
4557 }
4558 
4559 
4560 // static
GeneralizeFieldType(Representation rep1,Handle<FieldType> type1,Representation rep2,Handle<FieldType> type2,Isolate * isolate)4561 Handle<FieldType> Map::GeneralizeFieldType(Representation rep1,
4562                                            Handle<FieldType> type1,
4563                                            Representation rep2,
4564                                            Handle<FieldType> type2,
4565                                            Isolate* isolate) {
4566   // Cleared field types need special treatment. They represent lost knowledge,
4567   // so we must be conservative, so their generalization with any other type
4568   // is "Any".
4569   if (FieldTypeIsCleared(rep1, *type1) || FieldTypeIsCleared(rep2, *type2)) {
4570     return FieldType::Any(isolate);
4571   }
4572   if (type1->NowIs(type2)) return type2;
4573   if (type2->NowIs(type1)) return type1;
4574   return FieldType::Any(isolate);
4575 }
4576 
4577 // static
GeneralizeField(Handle<Map> map,int modify_index,PropertyConstness new_constness,Representation new_representation,Handle<FieldType> new_field_type)4578 void Map::GeneralizeField(Handle<Map> map, int modify_index,
4579                           PropertyConstness new_constness,
4580                           Representation new_representation,
4581                           Handle<FieldType> new_field_type) {
4582   Isolate* isolate = map->GetIsolate();
4583 
4584   // Check if we actually need to generalize the field type at all.
4585   Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
4586   PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
4587   PropertyConstness old_constness = old_details.constness();
4588   Representation old_representation = old_details.representation();
4589   Handle<FieldType> old_field_type(old_descriptors->GetFieldType(modify_index),
4590                                    isolate);
4591 
4592   // Return if the current map is general enough to hold requested contness and
4593   // representation/field type.
4594   if (((FLAG_modify_map_inplace &&
4595         IsGeneralizableTo(new_constness, old_constness)) ||
4596        (!FLAG_modify_map_inplace && (old_constness == new_constness))) &&
4597       old_representation.Equals(new_representation) &&
4598       !FieldTypeIsCleared(new_representation, *new_field_type) &&
4599       // Checking old_field_type for being cleared is not necessary because
4600       // the NowIs check below would fail anyway in that case.
4601       new_field_type->NowIs(old_field_type)) {
4602     DCHECK(GeneralizeFieldType(old_representation, old_field_type,
4603                                new_representation, new_field_type, isolate)
4604                ->NowIs(old_field_type));
4605     return;
4606   }
4607 
4608   // Determine the field owner.
4609   Handle<Map> field_owner(map->FindFieldOwner(modify_index), isolate);
4610   Handle<DescriptorArray> descriptors(field_owner->instance_descriptors(),
4611                                       isolate);
4612   DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index));
4613 
4614   new_field_type =
4615       Map::GeneralizeFieldType(old_representation, old_field_type,
4616                                new_representation, new_field_type, isolate);
4617   if (FLAG_modify_map_inplace) {
4618     new_constness = GeneralizeConstness(old_constness, new_constness);
4619   }
4620 
4621   PropertyDetails details = descriptors->GetDetails(modify_index);
4622   Handle<Name> name(descriptors->GetKey(modify_index));
4623 
4624   Handle<Object> wrapped_type(WrapFieldType(new_field_type));
4625   field_owner->UpdateFieldType(modify_index, name, new_constness,
4626                                new_representation, wrapped_type);
4627   field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
4628       isolate, DependentCode::kFieldOwnerGroup);
4629 
4630   if (FLAG_trace_generalization) {
4631     map->PrintGeneralization(
4632         stdout, "field type generalization", modify_index,
4633         map->NumberOfOwnDescriptors(), map->NumberOfOwnDescriptors(), false,
4634         details.representation(), details.representation(), old_field_type,
4635         MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>());
4636   }
4637 }
4638 
4639 // TODO(ishell): remove.
4640 // static
ReconfigureProperty(Handle<Map> map,int modify_index,PropertyKind new_kind,PropertyAttributes new_attributes,Representation new_representation,Handle<FieldType> new_field_type)4641 Handle<Map> Map::ReconfigureProperty(Handle<Map> map, int modify_index,
4642                                      PropertyKind new_kind,
4643                                      PropertyAttributes new_attributes,
4644                                      Representation new_representation,
4645                                      Handle<FieldType> new_field_type) {
4646   DCHECK_EQ(kData, new_kind);  // Only kData case is supported.
4647   MapUpdater mu(map->GetIsolate(), map);
4648   return mu.ReconfigureToDataField(modify_index, new_attributes, kConst,
4649                                    new_representation, new_field_type);
4650 }
4651 
4652 // TODO(ishell): remove.
4653 // static
ReconfigureElementsKind(Handle<Map> map,ElementsKind new_elements_kind)4654 Handle<Map> Map::ReconfigureElementsKind(Handle<Map> map,
4655                                          ElementsKind new_elements_kind) {
4656   MapUpdater mu(map->GetIsolate(), map);
4657   return mu.ReconfigureElementsKind(new_elements_kind);
4658 }
4659 
4660 // Generalize all fields and update the transition tree.
GeneralizeAllFields(Handle<Map> map)4661 Handle<Map> Map::GeneralizeAllFields(Handle<Map> map) {
4662   Isolate* isolate = map->GetIsolate();
4663   Handle<FieldType> any_type = FieldType::Any(isolate);
4664 
4665   Handle<DescriptorArray> descriptors(map->instance_descriptors());
4666   for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) {
4667     PropertyDetails details = descriptors->GetDetails(i);
4668     if (details.location() == kField) {
4669       DCHECK_EQ(kData, details.kind());
4670       MapUpdater mu(isolate, map);
4671       map = mu.ReconfigureToDataField(i, details.attributes(), kMutable,
4672                                       Representation::Tagged(), any_type);
4673     }
4674   }
4675   return map;
4676 }
4677 
4678 
4679 // static
TryUpdate(Handle<Map> old_map)4680 MaybeHandle<Map> Map::TryUpdate(Handle<Map> old_map) {
4681   DisallowHeapAllocation no_allocation;
4682   DisallowDeoptimization no_deoptimization(old_map->GetIsolate());
4683 
4684   if (!old_map->is_deprecated()) return old_map;
4685 
4686   // Check the state of the root map.
4687   Map* root_map = old_map->FindRootMap();
4688   if (root_map->is_deprecated()) {
4689     JSFunction* constructor = JSFunction::cast(root_map->GetConstructor());
4690     DCHECK(constructor->has_initial_map());
4691     DCHECK(constructor->initial_map()->is_dictionary_map());
4692     if (constructor->initial_map()->elements_kind() !=
4693         old_map->elements_kind()) {
4694       return MaybeHandle<Map>();
4695     }
4696     return handle(constructor->initial_map());
4697   }
4698   if (!old_map->EquivalentToForTransition(root_map)) return MaybeHandle<Map>();
4699 
4700   ElementsKind from_kind = root_map->elements_kind();
4701   ElementsKind to_kind = old_map->elements_kind();
4702   if (from_kind != to_kind) {
4703     // Try to follow existing elements kind transitions.
4704     root_map = root_map->LookupElementsTransitionMap(to_kind);
4705     if (root_map == nullptr) return MaybeHandle<Map>();
4706     // From here on, use the map with correct elements kind as root map.
4707   }
4708   Map* new_map = root_map->TryReplayPropertyTransitions(*old_map);
4709   if (new_map == nullptr) return MaybeHandle<Map>();
4710   return handle(new_map);
4711 }
4712 
TryReplayPropertyTransitions(Map * old_map)4713 Map* Map::TryReplayPropertyTransitions(Map* old_map) {
4714   DisallowHeapAllocation no_allocation;
4715   DisallowDeoptimization no_deoptimization(GetIsolate());
4716 
4717   int root_nof = NumberOfOwnDescriptors();
4718 
4719   int old_nof = old_map->NumberOfOwnDescriptors();
4720   DescriptorArray* old_descriptors = old_map->instance_descriptors();
4721 
4722   Map* new_map = this;
4723   for (int i = root_nof; i < old_nof; ++i) {
4724     PropertyDetails old_details = old_descriptors->GetDetails(i);
4725     Map* transition =
4726         TransitionsAccessor(new_map, &no_allocation)
4727             .SearchTransition(old_descriptors->GetKey(i), old_details.kind(),
4728                               old_details.attributes());
4729     if (transition == nullptr) return nullptr;
4730     new_map = transition;
4731     DescriptorArray* new_descriptors = new_map->instance_descriptors();
4732 
4733     PropertyDetails new_details = new_descriptors->GetDetails(i);
4734     DCHECK_EQ(old_details.kind(), new_details.kind());
4735     DCHECK_EQ(old_details.attributes(), new_details.attributes());
4736     if (!IsGeneralizableTo(old_details.constness(), new_details.constness())) {
4737       return nullptr;
4738     }
4739     DCHECK(IsGeneralizableTo(old_details.location(), new_details.location()));
4740     if (!old_details.representation().fits_into(new_details.representation())) {
4741       return nullptr;
4742     }
4743     if (new_details.location() == kField) {
4744       if (new_details.kind() == kData) {
4745         FieldType* new_type = new_descriptors->GetFieldType(i);
4746         // Cleared field types need special treatment. They represent lost
4747         // knowledge, so we must first generalize the new_type to "Any".
4748         if (FieldTypeIsCleared(new_details.representation(), new_type)) {
4749           return nullptr;
4750         }
4751         DCHECK_EQ(kData, old_details.kind());
4752         if (old_details.location() == kField) {
4753           FieldType* old_type = old_descriptors->GetFieldType(i);
4754           if (FieldTypeIsCleared(old_details.representation(), old_type) ||
4755               !old_type->NowIs(new_type)) {
4756             return nullptr;
4757           }
4758         } else {
4759           DCHECK_EQ(kDescriptor, old_details.location());
4760           DCHECK(!FLAG_track_constant_fields);
4761           Object* old_value = old_descriptors->GetValue(i);
4762           if (!new_type->NowContains(old_value)) {
4763             return nullptr;
4764           }
4765         }
4766 
4767       } else {
4768         DCHECK_EQ(kAccessor, new_details.kind());
4769 #ifdef DEBUG
4770         FieldType* new_type = new_descriptors->GetFieldType(i);
4771         DCHECK(new_type->IsAny());
4772 #endif
4773         UNREACHABLE();
4774       }
4775     } else {
4776       DCHECK_EQ(kDescriptor, new_details.location());
4777       Object* old_value = old_descriptors->GetValue(i);
4778       Object* new_value = new_descriptors->GetValue(i);
4779       if (old_details.location() == kField || old_value != new_value) {
4780         return nullptr;
4781       }
4782     }
4783   }
4784   if (new_map->NumberOfOwnDescriptors() != old_nof) return nullptr;
4785   return new_map;
4786 }
4787 
4788 
4789 // static
Update(Handle<Map> map)4790 Handle<Map> Map::Update(Handle<Map> map) {
4791   if (!map->is_deprecated()) return map;
4792   MapUpdater mu(map->GetIsolate(), map);
4793   return mu.Update();
4794 }
4795 
SetPropertyWithInterceptor(LookupIterator * it,ShouldThrow should_throw,Handle<Object> value)4796 Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
4797                                                  ShouldThrow should_throw,
4798                                                  Handle<Object> value) {
4799   DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
4800   return SetPropertyWithInterceptorInternal(it, it->GetInterceptor(),
4801                                             should_throw, value);
4802 }
4803 
SetProperty(Handle<Object> object,Handle<Name> name,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode)4804 MaybeHandle<Object> Object::SetProperty(Handle<Object> object,
4805                                         Handle<Name> name, Handle<Object> value,
4806                                         LanguageMode language_mode,
4807                                         StoreFromKeyed store_mode) {
4808   LookupIterator it(object, name);
4809   MAYBE_RETURN_NULL(SetProperty(&it, value, language_mode, store_mode));
4810   return value;
4811 }
4812 
4813 
SetPropertyInternal(LookupIterator * it,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode,bool * found)4814 Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
4815                                         Handle<Object> value,
4816                                         LanguageMode language_mode,
4817                                         StoreFromKeyed store_mode,
4818                                         bool* found) {
4819   it->UpdateProtector();
4820   DCHECK(it->IsFound());
4821   ShouldThrow should_throw =
4822       is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
4823 
4824   // Make sure that the top context does not change when doing callbacks or
4825   // interceptor calls.
4826   AssertNoContextChange ncc(it->isolate());
4827 
4828   do {
4829     switch (it->state()) {
4830       case LookupIterator::NOT_FOUND:
4831         UNREACHABLE();
4832 
4833       case LookupIterator::ACCESS_CHECK:
4834         if (it->HasAccess()) break;
4835         // Check whether it makes sense to reuse the lookup iterator. Here it
4836         // might still call into setters up the prototype chain.
4837         return JSObject::SetPropertyWithFailedAccessCheck(it, value,
4838                                                           should_throw);
4839 
4840       case LookupIterator::JSPROXY:
4841         return JSProxy::SetProperty(it->GetHolder<JSProxy>(), it->GetName(),
4842                                     value, it->GetReceiver(), language_mode);
4843 
4844       case LookupIterator::INTERCEPTOR: {
4845         if (it->HolderIsReceiverOrHiddenPrototype()) {
4846           Maybe<bool> result =
4847               JSObject::SetPropertyWithInterceptor(it, should_throw, value);
4848           if (result.IsNothing() || result.FromJust()) return result;
4849         } else {
4850           Maybe<PropertyAttributes> maybe_attributes =
4851               JSObject::GetPropertyAttributesWithInterceptor(it);
4852           if (maybe_attributes.IsNothing()) return Nothing<bool>();
4853           if ((maybe_attributes.FromJust() & READ_ONLY) != 0) {
4854             return WriteToReadOnlyProperty(it, value, should_throw);
4855           }
4856           if (maybe_attributes.FromJust() == ABSENT) break;
4857           *found = false;
4858           return Nothing<bool>();
4859         }
4860         break;
4861       }
4862 
4863       case LookupIterator::ACCESSOR: {
4864         if (it->IsReadOnly()) {
4865           return WriteToReadOnlyProperty(it, value, should_throw);
4866         }
4867         Handle<Object> accessors = it->GetAccessors();
4868         if (accessors->IsAccessorInfo() &&
4869             !it->HolderIsReceiverOrHiddenPrototype() &&
4870             AccessorInfo::cast(*accessors)->is_special_data_property()) {
4871           *found = false;
4872           return Nothing<bool>();
4873         }
4874         return SetPropertyWithAccessor(it, value, should_throw);
4875       }
4876       case LookupIterator::INTEGER_INDEXED_EXOTIC:
4877         // TODO(verwaest): We should throw an exception if holder is receiver.
4878         return Just(true);
4879 
4880       case LookupIterator::DATA:
4881         if (it->IsReadOnly()) {
4882           return WriteToReadOnlyProperty(it, value, should_throw);
4883         }
4884         if (it->HolderIsReceiverOrHiddenPrototype()) {
4885           return SetDataProperty(it, value);
4886         }
4887         V8_FALLTHROUGH;
4888       case LookupIterator::TRANSITION:
4889         *found = false;
4890         return Nothing<bool>();
4891     }
4892     it->Next();
4893   } while (it->IsFound());
4894 
4895   *found = false;
4896   return Nothing<bool>();
4897 }
4898 
4899 
SetProperty(LookupIterator * it,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode)4900 Maybe<bool> Object::SetProperty(LookupIterator* it, Handle<Object> value,
4901                                 LanguageMode language_mode,
4902                                 StoreFromKeyed store_mode) {
4903   if (it->IsFound()) {
4904     bool found = true;
4905     Maybe<bool> result =
4906         SetPropertyInternal(it, value, language_mode, store_mode, &found);
4907     if (found) return result;
4908   }
4909 
4910   // If the receiver is the JSGlobalObject, the store was contextual. In case
4911   // the property did not exist yet on the global object itself, we have to
4912   // throw a reference error in strict mode.  In sloppy mode, we continue.
4913   if (is_strict(language_mode) && it->GetReceiver()->IsJSGlobalObject()) {
4914     it->isolate()->Throw(*it->isolate()->factory()->NewReferenceError(
4915         MessageTemplate::kNotDefined, it->name()));
4916     return Nothing<bool>();
4917   }
4918 
4919   ShouldThrow should_throw =
4920       is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
4921   return AddDataProperty(it, value, NONE, should_throw, store_mode);
4922 }
4923 
4924 
SetSuperProperty(LookupIterator * it,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode)4925 Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
4926                                      LanguageMode language_mode,
4927                                      StoreFromKeyed store_mode) {
4928   Isolate* isolate = it->isolate();
4929 
4930   if (it->IsFound()) {
4931     bool found = true;
4932     Maybe<bool> result =
4933         SetPropertyInternal(it, value, language_mode, store_mode, &found);
4934     if (found) return result;
4935   }
4936 
4937   it->UpdateProtector();
4938 
4939   // The property either doesn't exist on the holder or exists there as a data
4940   // property.
4941 
4942   ShouldThrow should_throw =
4943       is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
4944 
4945   if (!it->GetReceiver()->IsJSReceiver()) {
4946     return WriteToReadOnlyProperty(it, value, should_throw);
4947   }
4948   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
4949 
4950   LookupIterator::Configuration c = LookupIterator::OWN;
4951   LookupIterator own_lookup =
4952       it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c)
4953                       : LookupIterator(receiver, it->name(), c);
4954 
4955   for (; own_lookup.IsFound(); own_lookup.Next()) {
4956     switch (own_lookup.state()) {
4957       case LookupIterator::ACCESS_CHECK:
4958         if (!own_lookup.HasAccess()) {
4959           return JSObject::SetPropertyWithFailedAccessCheck(&own_lookup, value,
4960                                                             should_throw);
4961         }
4962         break;
4963 
4964       case LookupIterator::ACCESSOR:
4965         if (own_lookup.GetAccessors()->IsAccessorInfo()) {
4966           if (own_lookup.IsReadOnly()) {
4967             return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
4968           }
4969           return JSObject::SetPropertyWithAccessor(&own_lookup, value,
4970                                                    should_throw);
4971         }
4972         V8_FALLTHROUGH;
4973       case LookupIterator::INTEGER_INDEXED_EXOTIC:
4974         return RedefineIncompatibleProperty(isolate, it->GetName(), value,
4975                                             should_throw);
4976 
4977       case LookupIterator::DATA: {
4978         if (own_lookup.IsReadOnly()) {
4979           return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
4980         }
4981         return SetDataProperty(&own_lookup, value);
4982       }
4983 
4984       case LookupIterator::INTERCEPTOR:
4985       case LookupIterator::JSPROXY: {
4986         PropertyDescriptor desc;
4987         Maybe<bool> owned =
4988             JSReceiver::GetOwnPropertyDescriptor(&own_lookup, &desc);
4989         MAYBE_RETURN(owned, Nothing<bool>());
4990         if (!owned.FromJust()) {
4991           return JSReceiver::CreateDataProperty(&own_lookup, value,
4992                                                 should_throw);
4993         }
4994         if (PropertyDescriptor::IsAccessorDescriptor(&desc) ||
4995             !desc.writable()) {
4996           return RedefineIncompatibleProperty(isolate, it->GetName(), value,
4997                                               should_throw);
4998         }
4999 
5000         PropertyDescriptor value_desc;
5001         value_desc.set_value(value);
5002         return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
5003                                              &value_desc, should_throw);
5004       }
5005 
5006       case LookupIterator::NOT_FOUND:
5007       case LookupIterator::TRANSITION:
5008         UNREACHABLE();
5009     }
5010   }
5011 
5012   return AddDataProperty(&own_lookup, value, NONE, should_throw, store_mode);
5013 }
5014 
CannotCreateProperty(Isolate * isolate,Handle<Object> receiver,Handle<Object> name,Handle<Object> value,ShouldThrow should_throw)5015 Maybe<bool> Object::CannotCreateProperty(Isolate* isolate,
5016                                          Handle<Object> receiver,
5017                                          Handle<Object> name,
5018                                          Handle<Object> value,
5019                                          ShouldThrow should_throw) {
5020   RETURN_FAILURE(
5021       isolate, should_throw,
5022       NewTypeError(MessageTemplate::kStrictCannotCreateProperty, name,
5023                    Object::TypeOf(isolate, receiver), receiver));
5024 }
5025 
5026 
WriteToReadOnlyProperty(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)5027 Maybe<bool> Object::WriteToReadOnlyProperty(LookupIterator* it,
5028                                             Handle<Object> value,
5029                                             ShouldThrow should_throw) {
5030   return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(),
5031                                  it->GetName(), value, should_throw);
5032 }
5033 
5034 
WriteToReadOnlyProperty(Isolate * isolate,Handle<Object> receiver,Handle<Object> name,Handle<Object> value,ShouldThrow should_throw)5035 Maybe<bool> Object::WriteToReadOnlyProperty(Isolate* isolate,
5036                                             Handle<Object> receiver,
5037                                             Handle<Object> name,
5038                                             Handle<Object> value,
5039                                             ShouldThrow should_throw) {
5040   RETURN_FAILURE(isolate, should_throw,
5041                  NewTypeError(MessageTemplate::kStrictReadOnlyProperty, name,
5042                               Object::TypeOf(isolate, receiver), receiver));
5043 }
5044 
5045 
RedefineIncompatibleProperty(Isolate * isolate,Handle<Object> name,Handle<Object> value,ShouldThrow should_throw)5046 Maybe<bool> Object::RedefineIncompatibleProperty(Isolate* isolate,
5047                                                  Handle<Object> name,
5048                                                  Handle<Object> value,
5049                                                  ShouldThrow should_throw) {
5050   RETURN_FAILURE(isolate, should_throw,
5051                  NewTypeError(MessageTemplate::kRedefineDisallowed, name));
5052 }
5053 
5054 
SetDataProperty(LookupIterator * it,Handle<Object> value)5055 Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) {
5056   DCHECK_IMPLIES(it->GetReceiver()->IsJSProxy(),
5057                  it->GetName()->IsPrivateField());
5058   DCHECK_IMPLIES(!it->IsElement() && it->GetName()->IsPrivateField(),
5059                  it->state() == LookupIterator::DATA);
5060   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
5061 
5062   // Store on the holder which may be hidden behind the receiver.
5063   DCHECK(it->HolderIsReceiverOrHiddenPrototype());
5064 
5065   Handle<Object> to_assign = value;
5066   // Convert the incoming value to a number for storing into typed arrays.
5067   if (it->IsElement() && receiver->IsJSObject() &&
5068       JSObject::cast(*receiver)->HasFixedTypedArrayElements()) {
5069     ElementsKind elements_kind = JSObject::cast(*receiver)->GetElementsKind();
5070     if (elements_kind == BIGINT64_ELEMENTS ||
5071         elements_kind == BIGUINT64_ELEMENTS) {
5072       ASSIGN_RETURN_ON_EXCEPTION_VALUE(it->isolate(), to_assign,
5073                                        BigInt::FromObject(it->isolate(), value),
5074                                        Nothing<bool>());
5075       // We have to recheck the length. However, it can only change if the
5076       // underlying buffer was neutered, so just check that.
5077       if (Handle<JSArrayBufferView>::cast(receiver)->WasNeutered()) {
5078         return Just(true);
5079         // TODO(neis): According to the spec, this should throw a TypeError.
5080       }
5081     } else if (!value->IsNumber() && !value->IsUndefined(it->isolate())) {
5082       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5083           it->isolate(), to_assign, Object::ToNumber(value), Nothing<bool>());
5084       // We have to recheck the length. However, it can only change if the
5085       // underlying buffer was neutered, so just check that.
5086       if (Handle<JSArrayBufferView>::cast(receiver)->WasNeutered()) {
5087         return Just(true);
5088         // TODO(neis): According to the spec, this should throw a TypeError.
5089       }
5090     }
5091   }
5092 
5093   // Possibly migrate to the most up-to-date map that will be able to store
5094   // |value| under it->name().
5095   it->PrepareForDataProperty(to_assign);
5096 
5097   // Write the property value.
5098   it->WriteDataValue(to_assign, false);
5099 
5100 #if VERIFY_HEAP
5101   if (FLAG_verify_heap) {
5102     receiver->HeapObjectVerify();
5103   }
5104 #endif
5105   return Just(true);
5106 }
5107 
5108 
AddDataProperty(LookupIterator * it,Handle<Object> value,PropertyAttributes attributes,ShouldThrow should_throw,StoreFromKeyed store_mode)5109 Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value,
5110                                     PropertyAttributes attributes,
5111                                     ShouldThrow should_throw,
5112                                     StoreFromKeyed store_mode) {
5113   if (!it->GetReceiver()->IsJSReceiver()) {
5114     return CannotCreateProperty(it->isolate(), it->GetReceiver(), it->GetName(),
5115                                 value, should_throw);
5116   }
5117 
5118   // Private symbols should be installed on JSProxy using
5119   // JSProxy::SetPrivateSymbol.
5120   if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate() &&
5121       !it->GetName()->IsPrivateField()) {
5122     RETURN_FAILURE(it->isolate(), should_throw,
5123                    NewTypeError(MessageTemplate::kProxyPrivate));
5124   }
5125 
5126   DCHECK_NE(LookupIterator::INTEGER_INDEXED_EXOTIC, it->state());
5127 
5128   Handle<JSReceiver> receiver = it->GetStoreTarget<JSReceiver>();
5129   DCHECK_IMPLIES(receiver->IsJSProxy(), it->GetName()->IsPrivateField());
5130   DCHECK_IMPLIES(receiver->IsJSProxy(),
5131                  it->state() == LookupIterator::NOT_FOUND);
5132 
5133   // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject)
5134   // instead. If the prototype is Null, the proxy is detached.
5135   if (receiver->IsJSGlobalProxy()) return Just(true);
5136 
5137   Isolate* isolate = it->isolate();
5138 
5139   if (it->ExtendingNonExtensible(receiver)) {
5140     RETURN_FAILURE(
5141         isolate, should_throw,
5142         NewTypeError(MessageTemplate::kObjectNotExtensible, it->GetName()));
5143   }
5144 
5145   if (it->IsElement()) {
5146     if (receiver->IsJSArray()) {
5147       Handle<JSArray> array = Handle<JSArray>::cast(receiver);
5148       if (JSArray::WouldChangeReadOnlyLength(array, it->index())) {
5149         RETURN_FAILURE(array->GetIsolate(), should_throw,
5150                        NewTypeError(MessageTemplate::kStrictReadOnlyProperty,
5151                                     isolate->factory()->length_string(),
5152                                     Object::TypeOf(isolate, array), array));
5153       }
5154 
5155       if (FLAG_trace_external_array_abuse &&
5156           array->HasFixedTypedArrayElements()) {
5157         CheckArrayAbuse(array, "typed elements write", it->index(), true);
5158       }
5159 
5160       if (FLAG_trace_js_array_abuse && !array->HasFixedTypedArrayElements()) {
5161         CheckArrayAbuse(array, "elements write", it->index(), false);
5162       }
5163     }
5164 
5165     Handle<JSObject> receiver_obj = Handle<JSObject>::cast(receiver);
5166     Maybe<bool> result = JSObject::AddDataElement(
5167         receiver_obj, it->index(), value, attributes, should_throw);
5168     JSObject::ValidateElements(*receiver_obj);
5169     return result;
5170   } else {
5171     it->UpdateProtector();
5172     // Migrate to the most up-to-date map that will be able to store |value|
5173     // under it->name() with |attributes|.
5174     it->PrepareTransitionToDataProperty(receiver, value, attributes,
5175                                         store_mode);
5176     DCHECK_EQ(LookupIterator::TRANSITION, it->state());
5177     it->ApplyTransitionToDataProperty(receiver);
5178 
5179     // Write the property value.
5180     it->WriteDataValue(value, true);
5181 
5182 #if VERIFY_HEAP
5183     if (FLAG_verify_heap) {
5184       receiver->HeapObjectVerify();
5185     }
5186 #endif
5187   }
5188 
5189   return Just(true);
5190 }
5191 
5192 
EnsureDescriptorSlack(Handle<Map> map,int slack)5193 void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
5194   // Only supports adding slack to owned descriptors.
5195   DCHECK(map->owns_descriptors());
5196 
5197   Handle<DescriptorArray> descriptors(map->instance_descriptors());
5198   int old_size = map->NumberOfOwnDescriptors();
5199   if (slack <= descriptors->NumberOfSlackDescriptors()) return;
5200 
5201   Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
5202       descriptors, old_size, slack);
5203 
5204   DisallowHeapAllocation no_allocation;
5205   // The descriptors are still the same, so keep the layout descriptor.
5206   LayoutDescriptor* layout_descriptor = map->GetLayoutDescriptor();
5207 
5208   if (old_size == 0) {
5209     map->UpdateDescriptors(*new_descriptors, layout_descriptor);
5210     return;
5211   }
5212 
5213   // If the source descriptors had an enum cache we copy it. This ensures
5214   // that the maps to which we push the new descriptor array back can rely
5215   // on a cache always being available once it is set. If the map has more
5216   // enumerated descriptors than available in the original cache, the cache
5217   // will be lazily replaced by the extended cache when needed.
5218   new_descriptors->CopyEnumCacheFrom(*descriptors);
5219 
5220   Isolate* isolate = map->GetIsolate();
5221   // Replace descriptors by new_descriptors in all maps that share it. The old
5222   // descriptors will not be trimmed in the mark-compactor, we need to mark
5223   // all its elements.
5224   isolate->heap()->incremental_marking()->RecordWrites(*descriptors);
5225 
5226   Map* current = *map;
5227   while (current->instance_descriptors() == *descriptors) {
5228     Object* next = current->GetBackPointer();
5229     if (next->IsUndefined(isolate)) break;  // Stop overwriting at initial map.
5230     current->UpdateDescriptors(*new_descriptors, layout_descriptor);
5231     current = Map::cast(next);
5232   }
5233   map->UpdateDescriptors(*new_descriptors, layout_descriptor);
5234 }
5235 
5236 // static
GetObjectCreateMap(Handle<HeapObject> prototype)5237 Handle<Map> Map::GetObjectCreateMap(Handle<HeapObject> prototype) {
5238   Isolate* isolate = prototype->GetIsolate();
5239   Handle<Map> map(isolate->native_context()->object_function()->initial_map(),
5240                   isolate);
5241   if (map->prototype() == *prototype) return map;
5242   if (prototype->IsNull(isolate)) {
5243     return isolate->slow_object_with_null_prototype_map();
5244   }
5245   if (prototype->IsJSObject()) {
5246     Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype);
5247     if (!js_prototype->map()->is_prototype_map()) {
5248       JSObject::OptimizeAsPrototype(js_prototype);
5249     }
5250     Handle<PrototypeInfo> info =
5251         Map::GetOrCreatePrototypeInfo(js_prototype, isolate);
5252     // TODO(verwaest): Use inobject slack tracking for this map.
5253     if (info->HasObjectCreateMap()) {
5254       map = handle(info->ObjectCreateMap(), isolate);
5255     } else {
5256       map = Map::CopyInitialMap(map);
5257       Map::SetPrototype(map, prototype);
5258       PrototypeInfo::SetObjectCreateMap(info, map);
5259     }
5260     return map;
5261   }
5262 
5263   return Map::TransitionToPrototype(map, prototype);
5264 }
5265 
5266 // static
TryGetObjectCreateMap(Handle<HeapObject> prototype)5267 MaybeHandle<Map> Map::TryGetObjectCreateMap(Handle<HeapObject> prototype) {
5268   Isolate* isolate = prototype->GetIsolate();
5269   Handle<Map> map(isolate->native_context()->object_function()->initial_map(),
5270                   isolate);
5271   if (map->prototype() == *prototype) return map;
5272   if (prototype->IsNull(isolate)) {
5273     return isolate->slow_object_with_null_prototype_map();
5274   }
5275   if (!prototype->IsJSObject()) return MaybeHandle<Map>();
5276   Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype);
5277   if (!js_prototype->map()->is_prototype_map()) return MaybeHandle<Map>();
5278   Handle<PrototypeInfo> info =
5279       Map::GetOrCreatePrototypeInfo(js_prototype, isolate);
5280   if (!info->HasObjectCreateMap()) return MaybeHandle<Map>();
5281   return handle(info->ObjectCreateMap(), isolate);
5282 }
5283 
5284 template <class T>
AppendUniqueCallbacks(Handle<TemplateList> callbacks,Handle<typename T::Array> array,int valid_descriptors)5285 static int AppendUniqueCallbacks(Handle<TemplateList> callbacks,
5286                                  Handle<typename T::Array> array,
5287                                  int valid_descriptors) {
5288   int nof_callbacks = callbacks->length();
5289 
5290   // Fill in new callback descriptors.  Process the callbacks from
5291   // back to front so that the last callback with a given name takes
5292   // precedence over previously added callbacks with that name.
5293   for (int i = nof_callbacks - 1; i >= 0; i--) {
5294     Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
5295     Handle<Name> key(Name::cast(entry->name()));
5296     DCHECK(key->IsUniqueName());
5297     // Check if a descriptor with this name already exists before writing.
5298     if (!T::Contains(key, entry, valid_descriptors, array)) {
5299       T::Insert(key, entry, valid_descriptors, array);
5300       valid_descriptors++;
5301     }
5302   }
5303 
5304   return valid_descriptors;
5305 }
5306 
5307 struct FixedArrayAppender {
5308   typedef FixedArray Array;
Containsv8::internal::FixedArrayAppender5309   static bool Contains(Handle<Name> key,
5310                        Handle<AccessorInfo> entry,
5311                        int valid_descriptors,
5312                        Handle<FixedArray> array) {
5313     for (int i = 0; i < valid_descriptors; i++) {
5314       if (*key == AccessorInfo::cast(array->get(i))->name()) return true;
5315     }
5316     return false;
5317   }
Insertv8::internal::FixedArrayAppender5318   static void Insert(Handle<Name> key,
5319                      Handle<AccessorInfo> entry,
5320                      int valid_descriptors,
5321                      Handle<FixedArray> array) {
5322     DisallowHeapAllocation no_gc;
5323     array->set(valid_descriptors, *entry);
5324   }
5325 };
5326 
5327 
AppendUnique(Handle<Object> descriptors,Handle<FixedArray> array,int valid_descriptors)5328 int AccessorInfo::AppendUnique(Handle<Object> descriptors,
5329                                Handle<FixedArray> array,
5330                                int valid_descriptors) {
5331   Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors);
5332   DCHECK_GE(array->length(), callbacks->length() + valid_descriptors);
5333   return AppendUniqueCallbacks<FixedArrayAppender>(callbacks, array,
5334                                                    valid_descriptors);
5335 }
5336 
ContainsMap(MapHandles const & maps,Map * map)5337 static bool ContainsMap(MapHandles const& maps, Map* map) {
5338   DCHECK_NOT_NULL(map);
5339   for (Handle<Map> current : maps) {
5340     if (!current.is_null() && *current == map) return true;
5341   }
5342   return false;
5343 }
5344 
FindElementsKindTransitionedMap(MapHandles const & candidates)5345 Map* Map::FindElementsKindTransitionedMap(MapHandles const& candidates) {
5346   DisallowHeapAllocation no_allocation;
5347   DisallowDeoptimization no_deoptimization(GetIsolate());
5348 
5349   if (is_prototype_map()) return nullptr;
5350 
5351   ElementsKind kind = elements_kind();
5352   bool packed = IsFastPackedElementsKind(kind);
5353 
5354   Map* transition = nullptr;
5355   if (IsTransitionableFastElementsKind(kind)) {
5356     // Check the state of the root map.
5357     Map* root_map = FindRootMap();
5358     if (!EquivalentToForElementsKindTransition(root_map)) return nullptr;
5359     root_map = root_map->LookupElementsTransitionMap(kind);
5360     DCHECK_NOT_NULL(root_map);
5361     // Starting from the next existing elements kind transition try to
5362     // replay the property transitions that does not involve instance rewriting
5363     // (ElementsTransitionAndStoreStub does not support that).
5364     for (root_map = root_map->ElementsTransitionMap();
5365          root_map != nullptr && root_map->has_fast_elements();
5366          root_map = root_map->ElementsTransitionMap()) {
5367       Map* current = root_map->TryReplayPropertyTransitions(this);
5368       if (current == nullptr) continue;
5369       if (InstancesNeedRewriting(current)) continue;
5370 
5371       if (ContainsMap(candidates, current) &&
5372           (packed || !IsFastPackedElementsKind(current->elements_kind()))) {
5373         transition = current;
5374         packed = packed && IsFastPackedElementsKind(current->elements_kind());
5375       }
5376     }
5377   }
5378   return transition;
5379 }
5380 
5381 
FindClosestElementsTransition(Map * map,ElementsKind to_kind)5382 static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
5383   // Ensure we are requested to search elements kind transition "near the root".
5384   DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(),
5385             map->NumberOfOwnDescriptors());
5386   Map* current_map = map;
5387 
5388   ElementsKind kind = map->elements_kind();
5389   while (kind != to_kind) {
5390     Map* next_map = current_map->ElementsTransitionMap();
5391     if (next_map == nullptr) return current_map;
5392     kind = next_map->elements_kind();
5393     current_map = next_map;
5394   }
5395 
5396   DCHECK_EQ(to_kind, current_map->elements_kind());
5397   return current_map;
5398 }
5399 
5400 
LookupElementsTransitionMap(ElementsKind to_kind)5401 Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) {
5402   Map* to_map = FindClosestElementsTransition(this, to_kind);
5403   if (to_map->elements_kind() == to_kind) return to_map;
5404   return nullptr;
5405 }
5406 
IsMapInArrayPrototypeChain() const5407 bool Map::IsMapInArrayPrototypeChain() const {
5408   Isolate* isolate = GetIsolate();
5409   if (isolate->initial_array_prototype()->map() == this) {
5410     return true;
5411   }
5412 
5413   if (isolate->initial_object_prototype()->map() == this) {
5414     return true;
5415   }
5416 
5417   return false;
5418 }
5419 
5420 
WeakCellForMap(Handle<Map> map)5421 Handle<WeakCell> Map::WeakCellForMap(Handle<Map> map) {
5422   Isolate* isolate = map->GetIsolate();
5423   if (map->weak_cell_cache()->IsWeakCell()) {
5424     return Handle<WeakCell>(WeakCell::cast(map->weak_cell_cache()));
5425   }
5426   Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(map);
5427   map->set_weak_cell_cache(*weak_cell);
5428   return weak_cell;
5429 }
5430 
5431 
AddMissingElementsTransitions(Handle<Map> map,ElementsKind to_kind)5432 static Handle<Map> AddMissingElementsTransitions(Handle<Map> map,
5433                                                  ElementsKind to_kind) {
5434   DCHECK(IsTransitionElementsKind(map->elements_kind()));
5435 
5436   Handle<Map> current_map = map;
5437 
5438   ElementsKind kind = map->elements_kind();
5439   TransitionFlag flag;
5440   if (map->is_prototype_map()) {
5441     flag = OMIT_TRANSITION;
5442   } else {
5443     flag = INSERT_TRANSITION;
5444     if (IsFastElementsKind(kind)) {
5445       while (kind != to_kind && !IsTerminalElementsKind(kind)) {
5446         kind = GetNextTransitionElementsKind(kind);
5447         current_map = Map::CopyAsElementsKind(current_map, kind, flag);
5448       }
5449     }
5450   }
5451 
5452   // In case we are exiting the fast elements kind system, just add the map in
5453   // the end.
5454   if (kind != to_kind) {
5455     current_map = Map::CopyAsElementsKind(current_map, to_kind, flag);
5456   }
5457 
5458   DCHECK(current_map->elements_kind() == to_kind);
5459   return current_map;
5460 }
5461 
5462 
TransitionElementsTo(Handle<Map> map,ElementsKind to_kind)5463 Handle<Map> Map::TransitionElementsTo(Handle<Map> map,
5464                                       ElementsKind to_kind) {
5465   ElementsKind from_kind = map->elements_kind();
5466   if (from_kind == to_kind) return map;
5467 
5468   Isolate* isolate = map->GetIsolate();
5469   Context* native_context = isolate->context()->native_context();
5470   if (from_kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
5471     if (*map == native_context->fast_aliased_arguments_map()) {
5472       DCHECK_EQ(SLOW_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
5473       return handle(native_context->slow_aliased_arguments_map());
5474     }
5475   } else if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
5476     if (*map == native_context->slow_aliased_arguments_map()) {
5477       DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
5478       return handle(native_context->fast_aliased_arguments_map());
5479     }
5480   } else if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) {
5481     // Reuse map transitions for JSArrays.
5482     DisallowHeapAllocation no_gc;
5483     if (native_context->GetInitialJSArrayMap(from_kind) == *map) {
5484       Object* maybe_transitioned_map =
5485           native_context->get(Context::ArrayMapIndex(to_kind));
5486       if (maybe_transitioned_map->IsMap()) {
5487         return handle(Map::cast(maybe_transitioned_map), isolate);
5488       }
5489     }
5490   }
5491 
5492   DCHECK(!map->IsUndefined(isolate));
5493   // Check if we can go back in the elements kind transition chain.
5494   if (IsHoleyOrDictionaryElementsKind(from_kind) &&
5495       to_kind == GetPackedElementsKind(from_kind) &&
5496       map->GetBackPointer()->IsMap() &&
5497       Map::cast(map->GetBackPointer())->elements_kind() == to_kind) {
5498     return handle(Map::cast(map->GetBackPointer()));
5499   }
5500 
5501   bool allow_store_transition = IsTransitionElementsKind(from_kind);
5502   // Only store fast element maps in ascending generality.
5503   if (IsFastElementsKind(to_kind)) {
5504     allow_store_transition =
5505         allow_store_transition && IsTransitionableFastElementsKind(from_kind) &&
5506         IsMoreGeneralElementsKindTransition(from_kind, to_kind);
5507   }
5508 
5509   if (!allow_store_transition) {
5510     return Map::CopyAsElementsKind(map, to_kind, OMIT_TRANSITION);
5511   }
5512 
5513   return Map::ReconfigureElementsKind(map, to_kind);
5514 }
5515 
5516 
5517 // static
AsElementsKind(Handle<Map> map,ElementsKind kind)5518 Handle<Map> Map::AsElementsKind(Handle<Map> map, ElementsKind kind) {
5519   Handle<Map> closest_map(FindClosestElementsTransition(*map, kind));
5520 
5521   if (closest_map->elements_kind() == kind) {
5522     return closest_map;
5523   }
5524 
5525   return AddMissingElementsTransitions(closest_map, kind);
5526 }
5527 
5528 
GetElementsTransitionMap(Handle<JSObject> object,ElementsKind to_kind)5529 Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
5530                                                ElementsKind to_kind) {
5531   Handle<Map> map(object->map());
5532   return Map::TransitionElementsTo(map, to_kind);
5533 }
5534 
5535 
Revoke(Handle<JSProxy> proxy)5536 void JSProxy::Revoke(Handle<JSProxy> proxy) {
5537   Isolate* isolate = proxy->GetIsolate();
5538   // ES#sec-proxy-revocation-functions
5539   if (!proxy->IsRevoked()) {
5540     // 5. Set p.[[ProxyTarget]] to null.
5541     proxy->set_target(isolate->heap()->null_value());
5542     // 6. Set p.[[ProxyHandler]] to null.
5543     proxy->set_handler(isolate->heap()->null_value());
5544   }
5545   DCHECK(proxy->IsRevoked());
5546 }
5547 
5548 // static
IsArray(Handle<JSProxy> proxy)5549 Maybe<bool> JSProxy::IsArray(Handle<JSProxy> proxy) {
5550   Isolate* isolate = proxy->GetIsolate();
5551   Handle<JSReceiver> object = Handle<JSReceiver>::cast(proxy);
5552   for (int i = 0; i < JSProxy::kMaxIterationLimit; i++) {
5553     Handle<JSProxy> proxy = Handle<JSProxy>::cast(object);
5554     if (proxy->IsRevoked()) {
5555       isolate->Throw(*isolate->factory()->NewTypeError(
5556           MessageTemplate::kProxyRevoked,
5557           isolate->factory()->NewStringFromAsciiChecked("IsArray")));
5558       return Nothing<bool>();
5559     }
5560     object = handle(JSReceiver::cast(proxy->target()), isolate);
5561     if (object->IsJSArray()) return Just(true);
5562     if (!object->IsJSProxy()) return Just(false);
5563   }
5564 
5565   // Too deep recursion, throw a RangeError.
5566   isolate->StackOverflow();
5567   return Nothing<bool>();
5568 }
5569 
HasProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Name> name)5570 Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy,
5571                                  Handle<Name> name) {
5572   DCHECK(!name->IsPrivate());
5573   STACK_CHECK(isolate, Nothing<bool>());
5574   // 1. (Assert)
5575   // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
5576   Handle<Object> handler(proxy->handler(), isolate);
5577   // 3. If handler is null, throw a TypeError exception.
5578   // 4. Assert: Type(handler) is Object.
5579   if (proxy->IsRevoked()) {
5580     isolate->Throw(*isolate->factory()->NewTypeError(
5581         MessageTemplate::kProxyRevoked, isolate->factory()->has_string()));
5582     return Nothing<bool>();
5583   }
5584   // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
5585   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
5586   // 6. Let trap be ? GetMethod(handler, "has").
5587   Handle<Object> trap;
5588   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5589       isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
5590                                        isolate->factory()->has_string()),
5591       Nothing<bool>());
5592   // 7. If trap is undefined, then
5593   if (trap->IsUndefined(isolate)) {
5594     // 7a. Return target.[[HasProperty]](P).
5595     return JSReceiver::HasProperty(target, name);
5596   }
5597   // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, P»)).
5598   Handle<Object> trap_result_obj;
5599   Handle<Object> args[] = {target, name};
5600   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5601       isolate, trap_result_obj,
5602       Execution::Call(isolate, trap, handler, arraysize(args), args),
5603       Nothing<bool>());
5604   bool boolean_trap_result = trap_result_obj->BooleanValue();
5605   // 9. If booleanTrapResult is false, then:
5606   if (!boolean_trap_result) {
5607     MAYBE_RETURN(JSProxy::CheckHasTrap(isolate, name, target), Nothing<bool>());
5608   }
5609   // 10. Return booleanTrapResult.
5610   return Just(boolean_trap_result);
5611 }
5612 
CheckHasTrap(Isolate * isolate,Handle<Name> name,Handle<JSReceiver> target)5613 Maybe<bool> JSProxy::CheckHasTrap(Isolate* isolate, Handle<Name> name,
5614                                   Handle<JSReceiver> target) {
5615   // 9a. Let targetDesc be ? target.[[GetOwnProperty]](P).
5616   PropertyDescriptor target_desc;
5617   Maybe<bool> target_found =
5618       JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
5619   MAYBE_RETURN(target_found, Nothing<bool>());
5620   // 9b. If targetDesc is not undefined, then:
5621   if (target_found.FromJust()) {
5622     // 9b i. If targetDesc.[[Configurable]] is false, throw a TypeError
5623     //       exception.
5624     if (!target_desc.configurable()) {
5625       isolate->Throw(*isolate->factory()->NewTypeError(
5626           MessageTemplate::kProxyHasNonConfigurable, name));
5627       return Nothing<bool>();
5628     }
5629     // 9b ii. Let extensibleTarget be ? IsExtensible(target).
5630     Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
5631     MAYBE_RETURN(extensible_target, Nothing<bool>());
5632     // 9b iii. If extensibleTarget is false, throw a TypeError exception.
5633     if (!extensible_target.FromJust()) {
5634       isolate->Throw(*isolate->factory()->NewTypeError(
5635           MessageTemplate::kProxyHasNonExtensible, name));
5636       return Nothing<bool>();
5637     }
5638   }
5639   return Just(true);
5640 }
5641 
SetProperty(Handle<JSProxy> proxy,Handle<Name> name,Handle<Object> value,Handle<Object> receiver,LanguageMode language_mode)5642 Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name,
5643                                  Handle<Object> value, Handle<Object> receiver,
5644                                  LanguageMode language_mode) {
5645   DCHECK(!name->IsPrivate());
5646   Isolate* isolate = proxy->GetIsolate();
5647   STACK_CHECK(isolate, Nothing<bool>());
5648   Factory* factory = isolate->factory();
5649   Handle<String> trap_name = factory->set_string();
5650   ShouldThrow should_throw =
5651       is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
5652 
5653   if (proxy->IsRevoked()) {
5654     isolate->Throw(
5655         *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
5656     return Nothing<bool>();
5657   }
5658   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
5659   Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
5660 
5661   Handle<Object> trap;
5662   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5663       isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
5664   if (trap->IsUndefined(isolate)) {
5665     LookupIterator it =
5666         LookupIterator::PropertyOrElement(isolate, receiver, name, target);
5667     return Object::SetSuperProperty(&it, value, language_mode,
5668                                     Object::MAY_BE_STORE_FROM_KEYED);
5669   }
5670 
5671   Handle<Object> trap_result;
5672   Handle<Object> args[] = {target, name, value, receiver};
5673   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5674       isolate, trap_result,
5675       Execution::Call(isolate, trap, handler, arraysize(args), args),
5676       Nothing<bool>());
5677   if (!trap_result->BooleanValue()) {
5678     RETURN_FAILURE(isolate, should_throw,
5679                    NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
5680                                 trap_name, name));
5681   }
5682 
5683   MaybeHandle<Object> result =
5684       JSProxy::CheckGetSetTrapResult(isolate, name, target, value, kSet);
5685 
5686   if (result.is_null()) {
5687     return Nothing<bool>();
5688   }
5689   return Just(true);
5690 }
5691 
5692 
DeletePropertyOrElement(Handle<JSProxy> proxy,Handle<Name> name,LanguageMode language_mode)5693 Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy,
5694                                              Handle<Name> name,
5695                                              LanguageMode language_mode) {
5696   DCHECK(!name->IsPrivate());
5697   ShouldThrow should_throw =
5698       is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
5699   Isolate* isolate = proxy->GetIsolate();
5700   STACK_CHECK(isolate, Nothing<bool>());
5701   Factory* factory = isolate->factory();
5702   Handle<String> trap_name = factory->deleteProperty_string();
5703 
5704   if (proxy->IsRevoked()) {
5705     isolate->Throw(
5706         *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
5707     return Nothing<bool>();
5708   }
5709   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
5710   Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
5711 
5712   Handle<Object> trap;
5713   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5714       isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
5715   if (trap->IsUndefined(isolate)) {
5716     return JSReceiver::DeletePropertyOrElement(target, name, language_mode);
5717   }
5718 
5719   Handle<Object> trap_result;
5720   Handle<Object> args[] = {target, name};
5721   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5722       isolate, trap_result,
5723       Execution::Call(isolate, trap, handler, arraysize(args), args),
5724       Nothing<bool>());
5725   if (!trap_result->BooleanValue()) {
5726     RETURN_FAILURE(isolate, should_throw,
5727                    NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
5728                                 trap_name, name));
5729   }
5730 
5731   // Enforce the invariant.
5732   PropertyDescriptor target_desc;
5733   Maybe<bool> owned =
5734       JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
5735   MAYBE_RETURN(owned, Nothing<bool>());
5736   if (owned.FromJust() && !target_desc.configurable()) {
5737     isolate->Throw(*factory->NewTypeError(
5738         MessageTemplate::kProxyDeletePropertyNonConfigurable, name));
5739     return Nothing<bool>();
5740   }
5741   return Just(true);
5742 }
5743 
5744 
5745 // static
New(Isolate * isolate,Handle<Object> target,Handle<Object> handler)5746 MaybeHandle<JSProxy> JSProxy::New(Isolate* isolate, Handle<Object> target,
5747                                   Handle<Object> handler) {
5748   if (!target->IsJSReceiver()) {
5749     THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5750                     JSProxy);
5751   }
5752   if (target->IsJSProxy() && JSProxy::cast(*target)->IsRevoked()) {
5753     THROW_NEW_ERROR(isolate,
5754                     NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5755                     JSProxy);
5756   }
5757   if (!handler->IsJSReceiver()) {
5758     THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5759                     JSProxy);
5760   }
5761   if (handler->IsJSProxy() && JSProxy::cast(*handler)->IsRevoked()) {
5762     THROW_NEW_ERROR(isolate,
5763                     NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5764                     JSProxy);
5765   }
5766   return isolate->factory()->NewJSProxy(Handle<JSReceiver>::cast(target),
5767                                         Handle<JSReceiver>::cast(handler));
5768 }
5769 
5770 
5771 // static
GetFunctionRealm(Handle<JSProxy> proxy)5772 MaybeHandle<Context> JSProxy::GetFunctionRealm(Handle<JSProxy> proxy) {
5773   DCHECK(proxy->map()->is_constructor());
5774   if (proxy->IsRevoked()) {
5775     THROW_NEW_ERROR(proxy->GetIsolate(),
5776                     NewTypeError(MessageTemplate::kProxyRevoked), Context);
5777   }
5778   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()));
5779   return JSReceiver::GetFunctionRealm(target);
5780 }
5781 
5782 
5783 // static
GetFunctionRealm(Handle<JSBoundFunction> function)5784 MaybeHandle<Context> JSBoundFunction::GetFunctionRealm(
5785     Handle<JSBoundFunction> function) {
5786   DCHECK(function->map()->is_constructor());
5787   return JSReceiver::GetFunctionRealm(
5788       handle(function->bound_target_function()));
5789 }
5790 
5791 // static
GetName(Isolate * isolate,Handle<JSBoundFunction> function)5792 MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate,
5793                                              Handle<JSBoundFunction> function) {
5794   Handle<String> prefix = isolate->factory()->bound__string();
5795   Handle<String> target_name = prefix;
5796   Factory* factory = isolate->factory();
5797   // Concatenate the "bound " up to the last non-bound target.
5798   while (function->bound_target_function()->IsJSBoundFunction()) {
5799     ASSIGN_RETURN_ON_EXCEPTION(isolate, target_name,
5800                                factory->NewConsString(prefix, target_name),
5801                                String);
5802     function = handle(JSBoundFunction::cast(function->bound_target_function()),
5803                       isolate);
5804   }
5805   if (function->bound_target_function()->IsJSFunction()) {
5806     Handle<JSFunction> target(
5807         JSFunction::cast(function->bound_target_function()), isolate);
5808     Handle<Object> name = JSFunction::GetName(isolate, target);
5809     if (!name->IsString()) return target_name;
5810     return factory->NewConsString(target_name, Handle<String>::cast(name));
5811   }
5812   // This will omit the proper target name for bound JSProxies.
5813   return target_name;
5814 }
5815 
5816 // static
GetLength(Isolate * isolate,Handle<JSBoundFunction> function)5817 Maybe<int> JSBoundFunction::GetLength(Isolate* isolate,
5818                                       Handle<JSBoundFunction> function) {
5819   int nof_bound_arguments = function->bound_arguments()->length();
5820   while (function->bound_target_function()->IsJSBoundFunction()) {
5821     function = handle(JSBoundFunction::cast(function->bound_target_function()),
5822                       isolate);
5823     // Make sure we never overflow {nof_bound_arguments}, the number of
5824     // arguments of a function is strictly limited by the max length of an
5825     // JSAarray, Smi::kMaxValue is thus a reasonably good overestimate.
5826     int length = function->bound_arguments()->length();
5827     if (V8_LIKELY(Smi::kMaxValue - nof_bound_arguments > length)) {
5828       nof_bound_arguments += length;
5829     } else {
5830       nof_bound_arguments = Smi::kMaxValue;
5831     }
5832   }
5833   // All non JSFunction targets get a direct property and don't use this
5834   // accessor.
5835   Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()),
5836                             isolate);
5837   Maybe<int> target_length = JSFunction::GetLength(isolate, target);
5838   if (target_length.IsNothing()) return target_length;
5839 
5840   int length = Max(0, target_length.FromJust() - nof_bound_arguments);
5841   return Just(length);
5842 }
5843 
5844 // static
GetName(Isolate * isolate,Handle<JSFunction> function)5845 Handle<Object> JSFunction::GetName(Isolate* isolate,
5846                                    Handle<JSFunction> function) {
5847   if (function->shared()->name_should_print_as_anonymous()) {
5848     return isolate->factory()->anonymous_string();
5849   }
5850   return handle(function->shared()->Name(), isolate);
5851 }
5852 
5853 // static
GetLength(Isolate * isolate,Handle<JSFunction> function)5854 Maybe<int> JSFunction::GetLength(Isolate* isolate,
5855                                  Handle<JSFunction> function) {
5856   int length = 0;
5857   if (function->shared()->is_compiled()) {
5858     length = function->shared()->GetLength();
5859   } else {
5860     // If the function isn't compiled yet, the length is not computed
5861     // correctly yet. Compile it now and return the right length.
5862     if (Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) {
5863       length = function->shared()->GetLength();
5864     }
5865     if (isolate->has_pending_exception()) return Nothing<int>();
5866   }
5867   DCHECK_GE(length, 0);
5868   return Just(length);
5869 }
5870 
5871 // static
GetFunctionRealm(Handle<JSFunction> function)5872 Handle<Context> JSFunction::GetFunctionRealm(Handle<JSFunction> function) {
5873   DCHECK(function->map()->is_constructor());
5874   return handle(function->context()->native_context());
5875 }
5876 
5877 
5878 // static
GetFunctionRealm(Handle<JSObject> object)5879 MaybeHandle<Context> JSObject::GetFunctionRealm(Handle<JSObject> object) {
5880   DCHECK(object->map()->is_constructor());
5881   DCHECK(!object->IsJSFunction());
5882   return object->GetCreationContext();
5883 }
5884 
5885 
5886 // static
GetFunctionRealm(Handle<JSReceiver> receiver)5887 MaybeHandle<Context> JSReceiver::GetFunctionRealm(Handle<JSReceiver> receiver) {
5888   if (receiver->IsJSProxy()) {
5889     return JSProxy::GetFunctionRealm(Handle<JSProxy>::cast(receiver));
5890   }
5891 
5892   if (receiver->IsJSFunction()) {
5893     return JSFunction::GetFunctionRealm(Handle<JSFunction>::cast(receiver));
5894   }
5895 
5896   if (receiver->IsJSBoundFunction()) {
5897     return JSBoundFunction::GetFunctionRealm(
5898         Handle<JSBoundFunction>::cast(receiver));
5899   }
5900 
5901   return JSObject::GetFunctionRealm(Handle<JSObject>::cast(receiver));
5902 }
5903 
5904 
GetPropertyAttributes(LookupIterator * it)5905 Maybe<PropertyAttributes> JSProxy::GetPropertyAttributes(LookupIterator* it) {
5906   PropertyDescriptor desc;
5907   Maybe<bool> found = JSProxy::GetOwnPropertyDescriptor(
5908       it->isolate(), it->GetHolder<JSProxy>(), it->GetName(), &desc);
5909   MAYBE_RETURN(found, Nothing<PropertyAttributes>());
5910   if (!found.FromJust()) return Just(ABSENT);
5911   return Just(desc.ToAttributes());
5912 }
5913 
5914 
AllocateStorageForMap(Handle<JSObject> object,Handle<Map> map)5915 void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
5916   DCHECK(object->map()->GetInObjectProperties() ==
5917          map->GetInObjectProperties());
5918   ElementsKind obj_kind = object->map()->elements_kind();
5919   ElementsKind map_kind = map->elements_kind();
5920   if (map_kind != obj_kind) {
5921     ElementsKind to_kind = GetMoreGeneralElementsKind(map_kind, obj_kind);
5922     if (IsDictionaryElementsKind(obj_kind)) {
5923       to_kind = obj_kind;
5924     }
5925     if (IsDictionaryElementsKind(to_kind)) {
5926       NormalizeElements(object);
5927     } else {
5928       TransitionElementsKind(object, to_kind);
5929     }
5930     map = Map::ReconfigureElementsKind(map, to_kind);
5931   }
5932   int number_of_fields = map->NumberOfFields();
5933   int inobject = map->GetInObjectProperties();
5934   int unused = map->UnusedPropertyFields();
5935   int total_size = number_of_fields + unused;
5936   int external = total_size - inobject;
5937   // Allocate mutable double boxes if necessary. It is always necessary if we
5938   // have external properties, but is also necessary if we only have inobject
5939   // properties but don't unbox double fields.
5940   if (!FLAG_unbox_double_fields || external > 0) {
5941     Isolate* isolate = object->GetIsolate();
5942 
5943     Handle<DescriptorArray> descriptors(map->instance_descriptors());
5944     Handle<FixedArray> storage;
5945     if (!FLAG_unbox_double_fields) {
5946       storage = isolate->factory()->NewFixedArray(inobject);
5947     }
5948 
5949     Handle<PropertyArray> array =
5950         isolate->factory()->NewPropertyArray(external);
5951 
5952     for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
5953       PropertyDetails details = descriptors->GetDetails(i);
5954       Representation representation = details.representation();
5955       if (!representation.IsDouble()) continue;
5956       FieldIndex index = FieldIndex::ForDescriptor(*map, i);
5957       if (map->IsUnboxedDoubleField(index)) continue;
5958       Handle<HeapNumber> box = isolate->factory()->NewMutableHeapNumber();
5959       if (index.is_inobject()) {
5960         storage->set(index.property_index(), *box);
5961       } else {
5962         array->set(index.outobject_array_index(), *box);
5963       }
5964     }
5965 
5966     object->SetProperties(*array);
5967 
5968     if (!FLAG_unbox_double_fields) {
5969       for (int i = 0; i < inobject; i++) {
5970         FieldIndex index = FieldIndex::ForPropertyIndex(*map, i);
5971         Object* value = storage->get(i);
5972         object->RawFastPropertyAtPut(index, value);
5973       }
5974     }
5975   }
5976   object->synchronized_set_map(*map);
5977 }
5978 
5979 
MigrateInstance(Handle<JSObject> object)5980 void JSObject::MigrateInstance(Handle<JSObject> object) {
5981   Handle<Map> original_map(object->map());
5982   Handle<Map> map = Map::Update(original_map);
5983   map->set_is_migration_target(true);
5984   MigrateToMap(object, map);
5985   if (FLAG_trace_migration) {
5986     object->PrintInstanceMigration(stdout, *original_map, *map);
5987   }
5988 #if VERIFY_HEAP
5989   if (FLAG_verify_heap) {
5990     object->JSObjectVerify();
5991   }
5992 #endif
5993 }
5994 
5995 
5996 // static
TryMigrateInstance(Handle<JSObject> object)5997 bool JSObject::TryMigrateInstance(Handle<JSObject> object) {
5998   Isolate* isolate = object->GetIsolate();
5999   DisallowDeoptimization no_deoptimization(isolate);
6000   Handle<Map> original_map(object->map(), isolate);
6001   Handle<Map> new_map;
6002   if (!Map::TryUpdate(original_map).ToHandle(&new_map)) {
6003     return false;
6004   }
6005   JSObject::MigrateToMap(object, new_map);
6006   if (FLAG_trace_migration && *original_map != object->map()) {
6007     object->PrintInstanceMigration(stdout, *original_map, object->map());
6008   }
6009 #if VERIFY_HEAP
6010   if (FLAG_verify_heap) {
6011     object->JSObjectVerify();
6012   }
6013 #endif
6014   return true;
6015 }
6016 
6017 
AddProperty(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)6018 void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name,
6019                            Handle<Object> value,
6020                            PropertyAttributes attributes) {
6021   LookupIterator it(object, name, object, LookupIterator::OWN_SKIP_INTERCEPTOR);
6022   CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
6023 #ifdef DEBUG
6024   uint32_t index;
6025   DCHECK(!object->IsJSProxy());
6026   DCHECK(!name->AsArrayIndex(&index));
6027   Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
6028   DCHECK(maybe.IsJust());
6029   DCHECK(!it.IsFound());
6030   DCHECK(object->map()->is_extensible() || name->IsPrivate());
6031 #endif
6032   CHECK(AddDataProperty(&it, value, attributes, kThrowOnError,
6033                         CERTAINLY_NOT_STORE_FROM_KEYED)
6034             .IsJust());
6035 }
6036 
6037 
6038 // Reconfigures a property to a data property with attributes, even if it is not
6039 // reconfigurable.
6040 // Requires a LookupIterator that does not look at the prototype chain beyond
6041 // hidden prototypes.
DefineOwnPropertyIgnoreAttributes(LookupIterator * it,Handle<Object> value,PropertyAttributes attributes,AccessorInfoHandling handling)6042 MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes(
6043     LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
6044     AccessorInfoHandling handling) {
6045   MAYBE_RETURN_NULL(DefineOwnPropertyIgnoreAttributes(it, value, attributes,
6046                                                       kThrowOnError, handling));
6047   return value;
6048 }
6049 
6050 
DefineOwnPropertyIgnoreAttributes(LookupIterator * it,Handle<Object> value,PropertyAttributes attributes,ShouldThrow should_throw,AccessorInfoHandling handling)6051 Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
6052     LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
6053     ShouldThrow should_throw, AccessorInfoHandling handling) {
6054   it->UpdateProtector();
6055   Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
6056 
6057   for (; it->IsFound(); it->Next()) {
6058     switch (it->state()) {
6059       case LookupIterator::JSPROXY:
6060       case LookupIterator::NOT_FOUND:
6061       case LookupIterator::TRANSITION:
6062         UNREACHABLE();
6063 
6064       case LookupIterator::ACCESS_CHECK:
6065         if (!it->HasAccess()) {
6066           it->isolate()->ReportFailedAccessCheck(it->GetHolder<JSObject>());
6067           RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
6068           return Just(true);
6069         }
6070         break;
6071 
6072       // If there's an interceptor, try to store the property with the
6073       // interceptor.
6074       // In case of success, the attributes will have been reset to the default
6075       // attributes of the interceptor, rather than the incoming attributes.
6076       //
6077       // TODO(verwaest): JSProxy afterwards verify the attributes that the
6078       // JSProxy claims it has, and verifies that they are compatible. If not,
6079       // they throw. Here we should do the same.
6080       case LookupIterator::INTERCEPTOR:
6081         if (handling == DONT_FORCE_FIELD) {
6082           Maybe<bool> result =
6083               JSObject::SetPropertyWithInterceptor(it, should_throw, value);
6084           if (result.IsNothing() || result.FromJust()) return result;
6085         }
6086         break;
6087 
6088       case LookupIterator::ACCESSOR: {
6089         Handle<Object> accessors = it->GetAccessors();
6090 
6091         // Special handling for AccessorInfo, which behaves like a data
6092         // property.
6093         if (accessors->IsAccessorInfo() && handling == DONT_FORCE_FIELD) {
6094           PropertyAttributes current_attributes = it->property_attributes();
6095           // Ensure the context isn't changed after calling into accessors.
6096           AssertNoContextChange ncc(it->isolate());
6097 
6098           // Update the attributes before calling the setter. The setter may
6099           // later change the shape of the property.
6100           if (current_attributes != attributes) {
6101             it->TransitionToAccessorPair(accessors, attributes);
6102           }
6103 
6104           return JSObject::SetPropertyWithAccessor(it, value, should_throw);
6105         }
6106 
6107         it->ReconfigureDataProperty(value, attributes);
6108         return Just(true);
6109       }
6110       case LookupIterator::INTEGER_INDEXED_EXOTIC:
6111         return RedefineIncompatibleProperty(it->isolate(), it->GetName(), value,
6112                                             should_throw);
6113 
6114       case LookupIterator::DATA: {
6115         // Regular property update if the attributes match.
6116         if (it->property_attributes() == attributes) {
6117           return SetDataProperty(it, value);
6118         }
6119 
6120         // Special case: properties of typed arrays cannot be reconfigured to
6121         // non-writable nor to non-enumerable.
6122         if (it->IsElement() && object->HasFixedTypedArrayElements()) {
6123           return RedefineIncompatibleProperty(it->isolate(), it->GetName(),
6124                                               value, should_throw);
6125         }
6126 
6127         // Reconfigure the data property if the attributes mismatch.
6128         it->ReconfigureDataProperty(value, attributes);
6129 
6130         return Just(true);
6131       }
6132     }
6133   }
6134 
6135   return AddDataProperty(it, value, attributes, should_throw,
6136                          CERTAINLY_NOT_STORE_FROM_KEYED);
6137 }
6138 
SetOwnPropertyIgnoreAttributes(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)6139 MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
6140     Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
6141     PropertyAttributes attributes) {
6142   DCHECK(!value->IsTheHole(object->GetIsolate()));
6143   LookupIterator it(object, name, object, LookupIterator::OWN);
6144   return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
6145 }
6146 
SetOwnElementIgnoreAttributes(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes)6147 MaybeHandle<Object> JSObject::SetOwnElementIgnoreAttributes(
6148     Handle<JSObject> object, uint32_t index, Handle<Object> value,
6149     PropertyAttributes attributes) {
6150   Isolate* isolate = object->GetIsolate();
6151   LookupIterator it(isolate, object, index, object, LookupIterator::OWN);
6152   return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
6153 }
6154 
DefinePropertyOrElementIgnoreAttributes(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)6155 MaybeHandle<Object> JSObject::DefinePropertyOrElementIgnoreAttributes(
6156     Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
6157     PropertyAttributes attributes) {
6158   Isolate* isolate = object->GetIsolate();
6159   LookupIterator it = LookupIterator::PropertyOrElement(
6160       isolate, object, name, object, LookupIterator::OWN);
6161   return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
6162 }
6163 
GetPropertyAttributesWithInterceptor(LookupIterator * it)6164 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
6165     LookupIterator* it) {
6166   return GetPropertyAttributesWithInterceptorInternal(it, it->GetInterceptor());
6167 }
6168 
GetPropertyAttributes(LookupIterator * it)6169 Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
6170     LookupIterator* it) {
6171   for (; it->IsFound(); it->Next()) {
6172     switch (it->state()) {
6173       case LookupIterator::NOT_FOUND:
6174       case LookupIterator::TRANSITION:
6175         UNREACHABLE();
6176       case LookupIterator::JSPROXY:
6177         return JSProxy::GetPropertyAttributes(it);
6178       case LookupIterator::INTERCEPTOR: {
6179         Maybe<PropertyAttributes> result =
6180             JSObject::GetPropertyAttributesWithInterceptor(it);
6181         if (result.IsNothing()) return result;
6182         if (result.FromJust() != ABSENT) return result;
6183         break;
6184       }
6185       case LookupIterator::ACCESS_CHECK:
6186         if (it->HasAccess()) break;
6187         return JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
6188       case LookupIterator::INTEGER_INDEXED_EXOTIC:
6189         return Just(ABSENT);
6190       case LookupIterator::ACCESSOR:
6191         if (it->GetHolder<Object>()->IsJSModuleNamespace()) {
6192           return JSModuleNamespace::GetPropertyAttributes(it);
6193         } else {
6194           return Just(it->property_attributes());
6195         }
6196       case LookupIterator::DATA:
6197         return Just(it->property_attributes());
6198     }
6199   }
6200   return Just(ABSENT);
6201 }
6202 
6203 
New(Isolate * isolate)6204 Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) {
6205   Handle<FixedArray> array(
6206       isolate->factory()->NewFixedArray(kEntries, TENURED));
6207   return Handle<NormalizedMapCache>::cast(array);
6208 }
6209 
6210 
Get(Handle<Map> fast_map,PropertyNormalizationMode mode)6211 MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map,
6212                                          PropertyNormalizationMode mode) {
6213   DisallowHeapAllocation no_gc;
6214   Object* value = FixedArray::get(GetIndex(fast_map));
6215   if (!value->IsWeakCell() || WeakCell::cast(value)->cleared()) {
6216     return MaybeHandle<Map>();
6217   }
6218 
6219   Map* normalized_map = Map::cast(WeakCell::cast(value)->value());
6220   if (!normalized_map->EquivalentToForNormalization(*fast_map, mode)) {
6221     return MaybeHandle<Map>();
6222   }
6223   return handle(normalized_map);
6224 }
6225 
Set(Handle<Map> fast_map,Handle<Map> normalized_map,Handle<WeakCell> normalized_map_weak_cell)6226 void NormalizedMapCache::Set(Handle<Map> fast_map, Handle<Map> normalized_map,
6227                              Handle<WeakCell> normalized_map_weak_cell) {
6228   DisallowHeapAllocation no_gc;
6229   DCHECK(normalized_map->is_dictionary_map());
6230   DCHECK_EQ(normalized_map_weak_cell->value(), *normalized_map);
6231   FixedArray::set(GetIndex(fast_map), *normalized_map_weak_cell);
6232 }
6233 
6234 
Clear()6235 void NormalizedMapCache::Clear() {
6236   int entries = length();
6237   for (int i = 0; i != entries; i++) {
6238     set_undefined(i);
6239   }
6240 }
6241 
6242 
NormalizeProperties(Handle<JSObject> object,PropertyNormalizationMode mode,int expected_additional_properties,const char * reason)6243 void JSObject::NormalizeProperties(Handle<JSObject> object,
6244                                    PropertyNormalizationMode mode,
6245                                    int expected_additional_properties,
6246                                    const char* reason) {
6247   if (!object->HasFastProperties()) return;
6248 
6249   Handle<Map> map(object->map());
6250   Handle<Map> new_map = Map::Normalize(map, mode, reason);
6251 
6252   MigrateToMap(object, new_map, expected_additional_properties);
6253 }
6254 
6255 
MigrateSlowToFast(Handle<JSObject> object,int unused_property_fields,const char * reason)6256 void JSObject::MigrateSlowToFast(Handle<JSObject> object,
6257                                  int unused_property_fields,
6258                                  const char* reason) {
6259   if (object->HasFastProperties()) return;
6260   DCHECK(!object->IsJSGlobalObject());
6261   Isolate* isolate = object->GetIsolate();
6262   Factory* factory = isolate->factory();
6263   Handle<NameDictionary> dictionary(object->property_dictionary());
6264 
6265   // Make sure we preserve dictionary representation if there are too many
6266   // descriptors.
6267   int number_of_elements = dictionary->NumberOfElements();
6268   if (number_of_elements > kMaxNumberOfDescriptors) return;
6269 
6270   Handle<FixedArray> iteration_order =
6271       NameDictionary::IterationIndices(dictionary);
6272 
6273   int instance_descriptor_length = iteration_order->length();
6274   int number_of_fields = 0;
6275 
6276   // Compute the length of the instance descriptor.
6277   for (int i = 0; i < instance_descriptor_length; i++) {
6278     int index = Smi::ToInt(iteration_order->get(i));
6279     DCHECK(dictionary->IsKey(isolate, dictionary->KeyAt(index)));
6280 
6281     PropertyKind kind = dictionary->DetailsAt(index).kind();
6282     if (kind == kData) {
6283       if (FLAG_track_constant_fields) {
6284         number_of_fields += 1;
6285       } else {
6286         Object* value = dictionary->ValueAt(index);
6287         if (!value->IsJSFunction()) {
6288           number_of_fields += 1;
6289         }
6290       }
6291     }
6292   }
6293 
6294   Handle<Map> old_map(object->map(), isolate);
6295 
6296   int inobject_props = old_map->GetInObjectProperties();
6297 
6298   // Allocate new map.
6299   Handle<Map> new_map = Map::CopyDropDescriptors(old_map);
6300   if (new_map->has_named_interceptor() || new_map->is_access_check_needed()) {
6301     // Force certain slow paths when API interceptors are used, or if an access
6302     // check is required.
6303     new_map->set_may_have_interesting_symbols(true);
6304   }
6305   new_map->set_is_dictionary_map(false);
6306 
6307   NotifyMapChange(old_map, new_map, isolate);
6308 
6309   if (FLAG_trace_maps) {
6310     LOG(isolate, MapEvent("SlowToFast", *old_map, *new_map, reason));
6311   }
6312 
6313   if (instance_descriptor_length == 0) {
6314     DisallowHeapAllocation no_gc;
6315     DCHECK_LE(unused_property_fields, inobject_props);
6316     // Transform the object.
6317     new_map->SetInObjectUnusedPropertyFields(inobject_props);
6318     object->synchronized_set_map(*new_map);
6319     object->SetProperties(isolate->heap()->empty_fixed_array());
6320     // Check that it really works.
6321     DCHECK(object->HasFastProperties());
6322     return;
6323   }
6324 
6325   // Allocate the instance descriptor.
6326   Handle<DescriptorArray> descriptors = DescriptorArray::Allocate(
6327       isolate, instance_descriptor_length, 0, TENURED);
6328 
6329   int number_of_allocated_fields =
6330       number_of_fields + unused_property_fields - inobject_props;
6331   if (number_of_allocated_fields < 0) {
6332     // There is enough inobject space for all fields (including unused).
6333     number_of_allocated_fields = 0;
6334     unused_property_fields = inobject_props - number_of_fields;
6335   }
6336 
6337   // Allocate the property array for the fields.
6338   Handle<PropertyArray> fields =
6339       factory->NewPropertyArray(number_of_allocated_fields);
6340 
6341   bool is_transitionable_elements_kind =
6342       IsTransitionableFastElementsKind(old_map->elements_kind());
6343 
6344   // Fill in the instance descriptor and the fields.
6345   int current_offset = 0;
6346   for (int i = 0; i < instance_descriptor_length; i++) {
6347     int index = Smi::ToInt(iteration_order->get(i));
6348     Name* k = dictionary->NameAt(index);
6349     // Dictionary keys are internalized upon insertion.
6350     // TODO(jkummerow): Turn this into a DCHECK if it's not hit in the wild.
6351     CHECK(k->IsUniqueName());
6352     Handle<Name> key(k, isolate);
6353 
6354     // Properly mark the {new_map} if the {key} is an "interesting symbol".
6355     if (key->IsInterestingSymbol()) {
6356       new_map->set_may_have_interesting_symbols(true);
6357     }
6358 
6359     Object* value = dictionary->ValueAt(index);
6360 
6361     PropertyDetails details = dictionary->DetailsAt(index);
6362     DCHECK_EQ(kField, details.location());
6363     DCHECK_EQ(kMutable, details.constness());
6364 
6365     Descriptor d;
6366     if (details.kind() == kData) {
6367       if (!FLAG_track_constant_fields && value->IsJSFunction()) {
6368         d = Descriptor::DataConstant(key, handle(value, isolate),
6369                                      details.attributes());
6370       } else {
6371         // Ensure that we make constant field only when elements kind is not
6372         // transitionable.
6373         PropertyConstness constness =
6374             FLAG_track_constant_fields && !is_transitionable_elements_kind
6375                 ? kConst
6376                 : kMutable;
6377         d = Descriptor::DataField(
6378             key, current_offset, details.attributes(), constness,
6379             // TODO(verwaest): value->OptimalRepresentation();
6380             Representation::Tagged(), FieldType::Any(isolate));
6381       }
6382     } else {
6383       DCHECK_EQ(kAccessor, details.kind());
6384       d = Descriptor::AccessorConstant(key, handle(value, isolate),
6385                                        details.attributes());
6386     }
6387     details = d.GetDetails();
6388     if (details.location() == kField) {
6389       if (current_offset < inobject_props) {
6390         object->InObjectPropertyAtPut(current_offset, value,
6391                                       UPDATE_WRITE_BARRIER);
6392       } else {
6393         int offset = current_offset - inobject_props;
6394         fields->set(offset, value);
6395       }
6396       current_offset += details.field_width_in_words();
6397     }
6398     descriptors->Set(i, &d);
6399   }
6400   DCHECK(current_offset == number_of_fields);
6401 
6402   descriptors->Sort();
6403 
6404   Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
6405       new_map, descriptors, descriptors->number_of_descriptors());
6406 
6407   DisallowHeapAllocation no_gc;
6408   new_map->InitializeDescriptors(*descriptors, *layout_descriptor);
6409   if (number_of_allocated_fields == 0) {
6410     new_map->SetInObjectUnusedPropertyFields(unused_property_fields);
6411   } else {
6412     new_map->SetOutOfObjectUnusedPropertyFields(unused_property_fields);
6413   }
6414 
6415   // Transform the object.
6416   object->synchronized_set_map(*new_map);
6417 
6418   object->SetProperties(*fields);
6419   DCHECK(object->IsJSObject());
6420 
6421   // Check that it really works.
6422   DCHECK(object->HasFastProperties());
6423 }
6424 
RequireSlowElements(NumberDictionary * dictionary)6425 void JSObject::RequireSlowElements(NumberDictionary* dictionary) {
6426   if (dictionary->requires_slow_elements()) return;
6427   dictionary->set_requires_slow_elements();
6428   if (map()->is_prototype_map()) {
6429     // If this object is a prototype (the callee will check), invalidate any
6430     // prototype chains involving it.
6431     InvalidatePrototypeChains(map());
6432   }
6433 }
6434 
NormalizeElements(Handle<JSObject> object)6435 Handle<NumberDictionary> JSObject::NormalizeElements(Handle<JSObject> object) {
6436   DCHECK(!object->HasFixedTypedArrayElements());
6437   Isolate* isolate = object->GetIsolate();
6438   bool is_sloppy_arguments = object->HasSloppyArgumentsElements();
6439   {
6440     DisallowHeapAllocation no_gc;
6441     FixedArrayBase* elements = object->elements();
6442 
6443     if (is_sloppy_arguments) {
6444       elements = SloppyArgumentsElements::cast(elements)->arguments();
6445     }
6446 
6447     if (elements->IsDictionary()) {
6448       return handle(NumberDictionary::cast(elements), isolate);
6449     }
6450   }
6451 
6452   DCHECK(object->HasSmiOrObjectElements() || object->HasDoubleElements() ||
6453          object->HasFastArgumentsElements() ||
6454          object->HasFastStringWrapperElements());
6455 
6456   Handle<NumberDictionary> dictionary =
6457       object->GetElementsAccessor()->Normalize(object);
6458 
6459   // Switch to using the dictionary as the backing storage for elements.
6460   ElementsKind target_kind = is_sloppy_arguments
6461                                  ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS
6462                                  : object->HasFastStringWrapperElements()
6463                                        ? SLOW_STRING_WRAPPER_ELEMENTS
6464                                        : DICTIONARY_ELEMENTS;
6465   Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind);
6466   // Set the new map first to satify the elements type assert in set_elements().
6467   JSObject::MigrateToMap(object, new_map);
6468 
6469   if (is_sloppy_arguments) {
6470     SloppyArgumentsElements::cast(object->elements())
6471         ->set_arguments(*dictionary);
6472   } else {
6473     object->set_elements(*dictionary);
6474   }
6475 
6476   isolate->counters()->elements_to_dictionary()->Increment();
6477 
6478 #ifdef DEBUG
6479   if (FLAG_trace_normalization) {
6480     OFStream os(stdout);
6481     os << "Object elements have been normalized:\n";
6482     object->Print(os);
6483   }
6484 #endif
6485 
6486   DCHECK(object->HasDictionaryElements() ||
6487          object->HasSlowArgumentsElements() ||
6488          object->HasSlowStringWrapperElements());
6489   return dictionary;
6490 }
6491 
6492 namespace {
6493 
SetHashAndUpdateProperties(HeapObject * properties,int hash)6494 Object* SetHashAndUpdateProperties(HeapObject* properties, int hash) {
6495   DCHECK_NE(PropertyArray::kNoHashSentinel, hash);
6496   DCHECK(PropertyArray::HashField::is_valid(hash));
6497 
6498   Heap* heap = properties->GetHeap();
6499   if (properties == heap->empty_fixed_array() ||
6500       properties == heap->empty_property_array() ||
6501       properties == heap->empty_property_dictionary()) {
6502     return Smi::FromInt(hash);
6503   }
6504 
6505   if (properties->IsPropertyArray()) {
6506     PropertyArray::cast(properties)->SetHash(hash);
6507     DCHECK_LT(0, PropertyArray::cast(properties)->length());
6508     return properties;
6509   }
6510 
6511   DCHECK(properties->IsDictionary());
6512   NameDictionary::cast(properties)->SetHash(hash);
6513   return properties;
6514 }
6515 
GetIdentityHashHelper(Isolate * isolate,JSReceiver * object)6516 int GetIdentityHashHelper(Isolate* isolate, JSReceiver* object) {
6517   DisallowHeapAllocation no_gc;
6518   Object* properties = object->raw_properties_or_hash();
6519   if (properties->IsSmi()) {
6520     return Smi::ToInt(properties);
6521   }
6522 
6523   if (properties->IsPropertyArray()) {
6524     return PropertyArray::cast(properties)->Hash();
6525   }
6526 
6527   if (properties->IsNameDictionary()) {
6528     return NameDictionary::cast(properties)->Hash();
6529   }
6530 
6531   if (properties->IsGlobalDictionary()) {
6532     return GlobalDictionary::cast(properties)->Hash();
6533   }
6534 
6535 #ifdef DEBUG
6536   FixedArray* empty_fixed_array = isolate->heap()->empty_fixed_array();
6537   FixedArray* empty_property_dictionary =
6538       isolate->heap()->empty_property_dictionary();
6539   DCHECK(properties == empty_fixed_array ||
6540          properties == empty_property_dictionary);
6541 #endif
6542 
6543   return PropertyArray::kNoHashSentinel;
6544 }
6545 }  // namespace
6546 
SetIdentityHash(int hash)6547 void JSReceiver::SetIdentityHash(int hash) {
6548   DisallowHeapAllocation no_gc;
6549   DCHECK_NE(PropertyArray::kNoHashSentinel, hash);
6550   DCHECK(PropertyArray::HashField::is_valid(hash));
6551 
6552   HeapObject* existing_properties = HeapObject::cast(raw_properties_or_hash());
6553   Object* new_properties =
6554       SetHashAndUpdateProperties(existing_properties, hash);
6555   set_raw_properties_or_hash(new_properties);
6556 }
6557 
SetProperties(HeapObject * properties)6558 void JSReceiver::SetProperties(HeapObject* properties) {
6559   DCHECK_IMPLIES(properties->IsPropertyArray() &&
6560                      PropertyArray::cast(properties)->length() == 0,
6561                  properties == properties->GetHeap()->empty_property_array());
6562   DisallowHeapAllocation no_gc;
6563   Isolate* isolate = properties->GetIsolate();
6564   int hash = GetIdentityHashHelper(isolate, this);
6565   Object* new_properties = properties;
6566 
6567   // TODO(cbruni): Make GetIdentityHashHelper return a bool so that we
6568   // don't have to manually compare against kNoHashSentinel.
6569   if (hash != PropertyArray::kNoHashSentinel) {
6570     new_properties = SetHashAndUpdateProperties(properties, hash);
6571   }
6572 
6573   set_raw_properties_or_hash(new_properties);
6574 }
6575 
GetIdentityHash(Isolate * isolate)6576 Object* JSReceiver::GetIdentityHash(Isolate* isolate) {
6577   DisallowHeapAllocation no_gc;
6578 
6579   int hash = GetIdentityHashHelper(isolate, this);
6580   if (hash == PropertyArray::kNoHashSentinel) {
6581     return isolate->heap()->undefined_value();
6582   }
6583 
6584   return Smi::FromInt(hash);
6585 }
6586 
6587 // static
CreateIdentityHash(Isolate * isolate,JSReceiver * key)6588 Smi* JSReceiver::CreateIdentityHash(Isolate* isolate, JSReceiver* key) {
6589   DisallowHeapAllocation no_gc;
6590   int hash = isolate->GenerateIdentityHash(PropertyArray::HashField::kMax);
6591   DCHECK_NE(PropertyArray::kNoHashSentinel, hash);
6592 
6593   key->SetIdentityHash(hash);
6594   return Smi::FromInt(hash);
6595 }
6596 
GetOrCreateIdentityHash(Isolate * isolate)6597 Smi* JSReceiver::GetOrCreateIdentityHash(Isolate* isolate) {
6598   DisallowHeapAllocation no_gc;
6599 
6600   Object* hash_obj = GetIdentityHash(isolate);
6601   if (!hash_obj->IsUndefined(isolate)) {
6602     return Smi::cast(hash_obj);
6603   }
6604 
6605   return JSReceiver::CreateIdentityHash(isolate, this);
6606 }
6607 
DeletePropertyWithInterceptor(LookupIterator * it,ShouldThrow should_throw)6608 Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it,
6609                                                     ShouldThrow should_throw) {
6610   Isolate* isolate = it->isolate();
6611   // Make sure that the top context does not change when doing callbacks or
6612   // interceptor calls.
6613   AssertNoContextChange ncc(isolate);
6614 
6615   DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
6616   Handle<InterceptorInfo> interceptor(it->GetInterceptor());
6617   if (interceptor->deleter()->IsUndefined(isolate)) return Nothing<bool>();
6618 
6619   Handle<JSObject> holder = it->GetHolder<JSObject>();
6620   Handle<Object> receiver = it->GetReceiver();
6621   if (!receiver->IsJSReceiver()) {
6622     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
6623                                      Object::ConvertReceiver(isolate, receiver),
6624                                      Nothing<bool>());
6625   }
6626 
6627   PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
6628                                  *holder, should_throw);
6629   Handle<Object> result;
6630   if (it->IsElement()) {
6631     result = args.CallIndexedDeleter(interceptor, it->index());
6632   } else {
6633     result = args.CallNamedDeleter(interceptor, it->name());
6634   }
6635 
6636   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6637   if (result.is_null()) return Nothing<bool>();
6638 
6639   DCHECK(result->IsBoolean());
6640   // Rebox CustomArguments::kReturnValueOffset before returning.
6641   return Just(result->IsTrue(isolate));
6642 }
6643 
DeleteNormalizedProperty(Handle<JSReceiver> object,int entry)6644 void JSReceiver::DeleteNormalizedProperty(Handle<JSReceiver> object,
6645                                           int entry) {
6646   DCHECK(!object->HasFastProperties());
6647   Isolate* isolate = object->GetIsolate();
6648 
6649   if (object->IsJSGlobalObject()) {
6650     // If we have a global object, invalidate the cell and swap in a new one.
6651     Handle<GlobalDictionary> dictionary(
6652         JSGlobalObject::cast(*object)->global_dictionary());
6653     DCHECK_NE(GlobalDictionary::kNotFound, entry);
6654 
6655     auto cell = PropertyCell::InvalidateEntry(dictionary, entry);
6656     cell->set_value(isolate->heap()->the_hole_value());
6657     cell->set_property_details(
6658         PropertyDetails::Empty(PropertyCellType::kUninitialized));
6659   } else {
6660     Handle<NameDictionary> dictionary(object->property_dictionary());
6661     DCHECK_NE(NameDictionary::kNotFound, entry);
6662 
6663     dictionary = NameDictionary::DeleteEntry(dictionary, entry);
6664     object->SetProperties(*dictionary);
6665   }
6666   if (object->map()->is_prototype_map()) {
6667     // Invalidate prototype validity cell as this may invalidate transitioning
6668     // store IC handlers.
6669     JSObject::InvalidatePrototypeChains(object->map());
6670   }
6671 }
6672 
6673 
DeleteProperty(LookupIterator * it,LanguageMode language_mode)6674 Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
6675                                        LanguageMode language_mode) {
6676   it->UpdateProtector();
6677 
6678   Isolate* isolate = it->isolate();
6679 
6680   if (it->state() == LookupIterator::JSPROXY) {
6681     return JSProxy::DeletePropertyOrElement(it->GetHolder<JSProxy>(),
6682                                             it->GetName(), language_mode);
6683   }
6684 
6685   if (it->GetReceiver()->IsJSProxy()) {
6686     if (it->state() != LookupIterator::NOT_FOUND) {
6687       DCHECK_EQ(LookupIterator::DATA, it->state());
6688       DCHECK(it->name()->IsPrivate());
6689       it->Delete();
6690     }
6691     return Just(true);
6692   }
6693   Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
6694 
6695   for (; it->IsFound(); it->Next()) {
6696     switch (it->state()) {
6697       case LookupIterator::JSPROXY:
6698       case LookupIterator::NOT_FOUND:
6699       case LookupIterator::TRANSITION:
6700         UNREACHABLE();
6701       case LookupIterator::ACCESS_CHECK:
6702         if (it->HasAccess()) break;
6703         isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
6704         RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6705         return Just(false);
6706       case LookupIterator::INTERCEPTOR: {
6707         ShouldThrow should_throw =
6708             is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
6709         Maybe<bool> result =
6710             JSObject::DeletePropertyWithInterceptor(it, should_throw);
6711         // An exception was thrown in the interceptor. Propagate.
6712         if (isolate->has_pending_exception()) return Nothing<bool>();
6713         // Delete with interceptor succeeded. Return result.
6714         // TODO(neis): In strict mode, we should probably throw if the
6715         // interceptor returns false.
6716         if (result.IsJust()) return result;
6717         break;
6718       }
6719       case LookupIterator::INTEGER_INDEXED_EXOTIC:
6720         return Just(true);
6721       case LookupIterator::DATA:
6722       case LookupIterator::ACCESSOR: {
6723         if (!it->IsConfigurable()) {
6724           // Fail if the property is not configurable.
6725           if (is_strict(language_mode)) {
6726             isolate->Throw(*isolate->factory()->NewTypeError(
6727                 MessageTemplate::kStrictDeleteProperty, it->GetName(),
6728                 receiver));
6729             return Nothing<bool>();
6730           }
6731           return Just(false);
6732         }
6733 
6734         it->Delete();
6735 
6736         return Just(true);
6737       }
6738     }
6739   }
6740 
6741   return Just(true);
6742 }
6743 
6744 
DeleteElement(Handle<JSReceiver> object,uint32_t index,LanguageMode language_mode)6745 Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index,
6746                                       LanguageMode language_mode) {
6747   LookupIterator it(object->GetIsolate(), object, index, object,
6748                     LookupIterator::OWN);
6749   return DeleteProperty(&it, language_mode);
6750 }
6751 
6752 
DeleteProperty(Handle<JSReceiver> object,Handle<Name> name,LanguageMode language_mode)6753 Maybe<bool> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
6754                                        Handle<Name> name,
6755                                        LanguageMode language_mode) {
6756   LookupIterator it(object, name, object, LookupIterator::OWN);
6757   return DeleteProperty(&it, language_mode);
6758 }
6759 
6760 
DeletePropertyOrElement(Handle<JSReceiver> object,Handle<Name> name,LanguageMode language_mode)6761 Maybe<bool> JSReceiver::DeletePropertyOrElement(Handle<JSReceiver> object,
6762                                                 Handle<Name> name,
6763                                                 LanguageMode language_mode) {
6764   LookupIterator it = LookupIterator::PropertyOrElement(
6765       name->GetIsolate(), object, name, object, LookupIterator::OWN);
6766   return DeleteProperty(&it, language_mode);
6767 }
6768 
6769 // ES6 19.1.2.4
6770 // static
DefineProperty(Isolate * isolate,Handle<Object> object,Handle<Object> key,Handle<Object> attributes)6771 Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object,
6772                                    Handle<Object> key,
6773                                    Handle<Object> attributes) {
6774   // 1. If Type(O) is not Object, throw a TypeError exception.
6775   if (!object->IsJSReceiver()) {
6776     Handle<String> fun_name =
6777         isolate->factory()->InternalizeUtf8String("Object.defineProperty");
6778     THROW_NEW_ERROR_RETURN_FAILURE(
6779         isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name));
6780   }
6781   // 2. Let key be ToPropertyKey(P).
6782   // 3. ReturnIfAbrupt(key).
6783   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key, ToPropertyKey(isolate, key));
6784   // 4. Let desc be ToPropertyDescriptor(Attributes).
6785   // 5. ReturnIfAbrupt(desc).
6786   PropertyDescriptor desc;
6787   if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) {
6788     return isolate->heap()->exception();
6789   }
6790   // 6. Let success be DefinePropertyOrThrow(O,key, desc).
6791   Maybe<bool> success = DefineOwnProperty(
6792       isolate, Handle<JSReceiver>::cast(object), key, &desc, kThrowOnError);
6793   // 7. ReturnIfAbrupt(success).
6794   MAYBE_RETURN(success, isolate->heap()->exception());
6795   CHECK(success.FromJust());
6796   // 8. Return O.
6797   return *object;
6798 }
6799 
6800 
6801 // ES6 19.1.2.3.1
6802 // static
DefineProperties(Isolate * isolate,Handle<Object> object,Handle<Object> properties)6803 MaybeHandle<Object> JSReceiver::DefineProperties(Isolate* isolate,
6804                                                  Handle<Object> object,
6805                                                  Handle<Object> properties) {
6806   // 1. If Type(O) is not Object, throw a TypeError exception.
6807   if (!object->IsJSReceiver()) {
6808     Handle<String> fun_name =
6809         isolate->factory()->InternalizeUtf8String("Object.defineProperties");
6810     THROW_NEW_ERROR(isolate,
6811                     NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name),
6812                     Object);
6813   }
6814   // 2. Let props be ToObject(Properties).
6815   // 3. ReturnIfAbrupt(props).
6816   Handle<JSReceiver> props;
6817   ASSIGN_RETURN_ON_EXCEPTION(isolate, props,
6818                              Object::ToObject(isolate, properties), Object);
6819 
6820   // 4. Let keys be props.[[OwnPropertyKeys]]().
6821   // 5. ReturnIfAbrupt(keys).
6822   Handle<FixedArray> keys;
6823   ASSIGN_RETURN_ON_EXCEPTION(
6824       isolate, keys, KeyAccumulator::GetKeys(props, KeyCollectionMode::kOwnOnly,
6825                                              ALL_PROPERTIES),
6826       Object);
6827   // 6. Let descriptors be an empty List.
6828   int capacity = keys->length();
6829   std::vector<PropertyDescriptor> descriptors(capacity);
6830   size_t descriptors_index = 0;
6831   // 7. Repeat for each element nextKey of keys in List order,
6832   for (int i = 0; i < keys->length(); ++i) {
6833     Handle<Object> next_key(keys->get(i), isolate);
6834     // 7a. Let propDesc be props.[[GetOwnProperty]](nextKey).
6835     // 7b. ReturnIfAbrupt(propDesc).
6836     bool success = false;
6837     LookupIterator it = LookupIterator::PropertyOrElement(
6838         isolate, props, next_key, &success, LookupIterator::OWN);
6839     DCHECK(success);
6840     Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
6841     if (maybe.IsNothing()) return MaybeHandle<Object>();
6842     PropertyAttributes attrs = maybe.FromJust();
6843     // 7c. If propDesc is not undefined and propDesc.[[Enumerable]] is true:
6844     if (attrs == ABSENT) continue;
6845     if (attrs & DONT_ENUM) continue;
6846     // 7c i. Let descObj be Get(props, nextKey).
6847     // 7c ii. ReturnIfAbrupt(descObj).
6848     Handle<Object> desc_obj;
6849     ASSIGN_RETURN_ON_EXCEPTION(isolate, desc_obj, Object::GetProperty(&it),
6850                                Object);
6851     // 7c iii. Let desc be ToPropertyDescriptor(descObj).
6852     success = PropertyDescriptor::ToPropertyDescriptor(
6853         isolate, desc_obj, &descriptors[descriptors_index]);
6854     // 7c iv. ReturnIfAbrupt(desc).
6855     if (!success) return MaybeHandle<Object>();
6856     // 7c v. Append the pair (a two element List) consisting of nextKey and
6857     //       desc to the end of descriptors.
6858     descriptors[descriptors_index].set_name(next_key);
6859     descriptors_index++;
6860   }
6861   // 8. For each pair from descriptors in list order,
6862   for (size_t i = 0; i < descriptors_index; ++i) {
6863     PropertyDescriptor* desc = &descriptors[i];
6864     // 8a. Let P be the first element of pair.
6865     // 8b. Let desc be the second element of pair.
6866     // 8c. Let status be DefinePropertyOrThrow(O, P, desc).
6867     Maybe<bool> status =
6868         DefineOwnProperty(isolate, Handle<JSReceiver>::cast(object),
6869                           desc->name(), desc, kThrowOnError);
6870     // 8d. ReturnIfAbrupt(status).
6871     if (status.IsNothing()) return MaybeHandle<Object>();
6872     CHECK(status.FromJust());
6873   }
6874   // 9. Return o.
6875   return object;
6876 }
6877 
6878 // static
DefineOwnProperty(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> key,PropertyDescriptor * desc,ShouldThrow should_throw)6879 Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate,
6880                                           Handle<JSReceiver> object,
6881                                           Handle<Object> key,
6882                                           PropertyDescriptor* desc,
6883                                           ShouldThrow should_throw) {
6884   if (object->IsJSArray()) {
6885     return JSArray::DefineOwnProperty(isolate, Handle<JSArray>::cast(object),
6886                                       key, desc, should_throw);
6887   }
6888   if (object->IsJSProxy()) {
6889     return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object),
6890                                       key, desc, should_throw);
6891   }
6892   if (object->IsJSTypedArray()) {
6893     return JSTypedArray::DefineOwnProperty(
6894         isolate, Handle<JSTypedArray>::cast(object), key, desc, should_throw);
6895   }
6896 
6897   // OrdinaryDefineOwnProperty, by virtue of calling
6898   // DefineOwnPropertyIgnoreAttributes, can handle arguments
6899   // (ES#sec-arguments-exotic-objects-defineownproperty-p-desc).
6900   return OrdinaryDefineOwnProperty(isolate, Handle<JSObject>::cast(object), key,
6901                                    desc, should_throw);
6902 }
6903 
6904 
6905 // static
OrdinaryDefineOwnProperty(Isolate * isolate,Handle<JSObject> object,Handle<Object> key,PropertyDescriptor * desc,ShouldThrow should_throw)6906 Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate,
6907                                                   Handle<JSObject> object,
6908                                                   Handle<Object> key,
6909                                                   PropertyDescriptor* desc,
6910                                                   ShouldThrow should_throw) {
6911   bool success = false;
6912   DCHECK(key->IsName() || key->IsNumber());  // |key| is a PropertyKey...
6913   LookupIterator it = LookupIterator::PropertyOrElement(
6914       isolate, object, key, &success, LookupIterator::OWN);
6915   DCHECK(success);  // ...so creating a LookupIterator can't fail.
6916 
6917   // Deal with access checks first.
6918   if (it.state() == LookupIterator::ACCESS_CHECK) {
6919     if (!it.HasAccess()) {
6920       isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>());
6921       RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6922       return Just(true);
6923     }
6924     it.Next();
6925   }
6926 
6927   return OrdinaryDefineOwnProperty(&it, desc, should_throw);
6928 }
6929 
6930 
6931 // ES6 9.1.6.1
6932 // static
OrdinaryDefineOwnProperty(LookupIterator * it,PropertyDescriptor * desc,ShouldThrow should_throw)6933 Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
6934                                                   PropertyDescriptor* desc,
6935                                                   ShouldThrow should_throw) {
6936   Isolate* isolate = it->isolate();
6937   // 1. Let current be O.[[GetOwnProperty]](P).
6938   // 2. ReturnIfAbrupt(current).
6939   PropertyDescriptor current;
6940   MAYBE_RETURN(GetOwnPropertyDescriptor(it, &current), Nothing<bool>());
6941 
6942   it->Restart();
6943   // Handle interceptor
6944   for (; it->IsFound(); it->Next()) {
6945     if (it->state() == LookupIterator::INTERCEPTOR) {
6946       if (it->HolderIsReceiverOrHiddenPrototype()) {
6947         Maybe<bool> result = DefinePropertyWithInterceptorInternal(
6948             it, it->GetInterceptor(), should_throw, *desc);
6949         if (result.IsNothing() || result.FromJust()) {
6950           return result;
6951         }
6952       }
6953     }
6954   }
6955 
6956   // TODO(jkummerow/verwaest): It would be nice if we didn't have to reset
6957   // the iterator every time. Currently, the reasons why we need it are:
6958   // - handle interceptors correctly
6959   // - handle accessors correctly (which might change the holder's map)
6960   it->Restart();
6961   // 3. Let extensible be the value of the [[Extensible]] internal slot of O.
6962   Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
6963   bool extensible = JSObject::IsExtensible(object);
6964 
6965   return ValidateAndApplyPropertyDescriptor(
6966       isolate, it, extensible, desc, &current, should_throw, Handle<Name>());
6967 }
6968 
6969 
6970 // ES6 9.1.6.2
6971 // static
IsCompatiblePropertyDescriptor(Isolate * isolate,bool extensible,PropertyDescriptor * desc,PropertyDescriptor * current,Handle<Name> property_name,ShouldThrow should_throw)6972 Maybe<bool> JSReceiver::IsCompatiblePropertyDescriptor(
6973     Isolate* isolate, bool extensible, PropertyDescriptor* desc,
6974     PropertyDescriptor* current, Handle<Name> property_name,
6975     ShouldThrow should_throw) {
6976   // 1. Return ValidateAndApplyPropertyDescriptor(undefined, undefined,
6977   //    Extensible, Desc, Current).
6978   return ValidateAndApplyPropertyDescriptor(
6979       isolate, nullptr, extensible, desc, current, should_throw, property_name);
6980 }
6981 
6982 
6983 // ES6 9.1.6.3
6984 // static
ValidateAndApplyPropertyDescriptor(Isolate * isolate,LookupIterator * it,bool extensible,PropertyDescriptor * desc,PropertyDescriptor * current,ShouldThrow should_throw,Handle<Name> property_name)6985 Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor(
6986     Isolate* isolate, LookupIterator* it, bool extensible,
6987     PropertyDescriptor* desc, PropertyDescriptor* current,
6988     ShouldThrow should_throw, Handle<Name> property_name) {
6989   // We either need a LookupIterator, or a property name.
6990   DCHECK((it == nullptr) != property_name.is_null());
6991   Handle<JSObject> object;
6992   if (it != nullptr) object = Handle<JSObject>::cast(it->GetReceiver());
6993   bool desc_is_data_descriptor = PropertyDescriptor::IsDataDescriptor(desc);
6994   bool desc_is_accessor_descriptor =
6995       PropertyDescriptor::IsAccessorDescriptor(desc);
6996   bool desc_is_generic_descriptor =
6997       PropertyDescriptor::IsGenericDescriptor(desc);
6998   // 1. (Assert)
6999   // 2. If current is undefined, then
7000   if (current->is_empty()) {
7001     // 2a. If extensible is false, return false.
7002     if (!extensible) {
7003       RETURN_FAILURE(
7004           isolate, should_throw,
7005           NewTypeError(MessageTemplate::kDefineDisallowed,
7006                        it != nullptr ? it->GetName() : property_name));
7007     }
7008     // 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then:
7009     // (This is equivalent to !IsAccessorDescriptor(desc).)
7010     DCHECK((desc_is_generic_descriptor || desc_is_data_descriptor) ==
7011            !desc_is_accessor_descriptor);
7012     if (!desc_is_accessor_descriptor) {
7013       // 2c i. If O is not undefined, create an own data property named P of
7014       // object O whose [[Value]], [[Writable]], [[Enumerable]] and
7015       // [[Configurable]] attribute values are described by Desc. If the value
7016       // of an attribute field of Desc is absent, the attribute of the newly
7017       // created property is set to its default value.
7018       if (it != nullptr) {
7019         if (!desc->has_writable()) desc->set_writable(false);
7020         if (!desc->has_enumerable()) desc->set_enumerable(false);
7021         if (!desc->has_configurable()) desc->set_configurable(false);
7022         Handle<Object> value(
7023             desc->has_value()
7024                 ? desc->value()
7025                 : Handle<Object>::cast(isolate->factory()->undefined_value()));
7026         MaybeHandle<Object> result =
7027             JSObject::DefineOwnPropertyIgnoreAttributes(it, value,
7028                                                         desc->ToAttributes());
7029         if (result.is_null()) return Nothing<bool>();
7030       }
7031     } else {
7032       // 2d. Else Desc must be an accessor Property Descriptor,
7033       DCHECK(desc_is_accessor_descriptor);
7034       // 2d i. If O is not undefined, create an own accessor property named P
7035       // of object O whose [[Get]], [[Set]], [[Enumerable]] and
7036       // [[Configurable]] attribute values are described by Desc. If the value
7037       // of an attribute field of Desc is absent, the attribute of the newly
7038       // created property is set to its default value.
7039       if (it != nullptr) {
7040         if (!desc->has_enumerable()) desc->set_enumerable(false);
7041         if (!desc->has_configurable()) desc->set_configurable(false);
7042         Handle<Object> getter(
7043             desc->has_get()
7044                 ? desc->get()
7045                 : Handle<Object>::cast(isolate->factory()->null_value()));
7046         Handle<Object> setter(
7047             desc->has_set()
7048                 ? desc->set()
7049                 : Handle<Object>::cast(isolate->factory()->null_value()));
7050         MaybeHandle<Object> result =
7051             JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes());
7052         if (result.is_null()) return Nothing<bool>();
7053       }
7054     }
7055     // 2e. Return true.
7056     return Just(true);
7057   }
7058   // 3. Return true, if every field in Desc is absent.
7059   // 4. Return true, if every field in Desc also occurs in current and the
7060   // value of every field in Desc is the same value as the corresponding field
7061   // in current when compared using the SameValue algorithm.
7062   if ((!desc->has_enumerable() ||
7063        desc->enumerable() == current->enumerable()) &&
7064       (!desc->has_configurable() ||
7065        desc->configurable() == current->configurable()) &&
7066       (!desc->has_value() ||
7067        (current->has_value() && current->value()->SameValue(*desc->value()))) &&
7068       (!desc->has_writable() ||
7069        (current->has_writable() && current->writable() == desc->writable())) &&
7070       (!desc->has_get() ||
7071        (current->has_get() && current->get()->SameValue(*desc->get()))) &&
7072       (!desc->has_set() ||
7073        (current->has_set() && current->set()->SameValue(*desc->set())))) {
7074     return Just(true);
7075   }
7076   // 5. If the [[Configurable]] field of current is false, then
7077   if (!current->configurable()) {
7078     // 5a. Return false, if the [[Configurable]] field of Desc is true.
7079     if (desc->has_configurable() && desc->configurable()) {
7080       RETURN_FAILURE(
7081           isolate, should_throw,
7082           NewTypeError(MessageTemplate::kRedefineDisallowed,
7083                        it != nullptr ? it->GetName() : property_name));
7084     }
7085     // 5b. Return false, if the [[Enumerable]] field of Desc is present and the
7086     // [[Enumerable]] fields of current and Desc are the Boolean negation of
7087     // each other.
7088     if (desc->has_enumerable() && desc->enumerable() != current->enumerable()) {
7089       RETURN_FAILURE(
7090           isolate, should_throw,
7091           NewTypeError(MessageTemplate::kRedefineDisallowed,
7092                        it != nullptr ? it->GetName() : property_name));
7093     }
7094   }
7095 
7096   bool current_is_data_descriptor =
7097       PropertyDescriptor::IsDataDescriptor(current);
7098   // 6. If IsGenericDescriptor(Desc) is true, no further validation is required.
7099   if (desc_is_generic_descriptor) {
7100     // Nothing to see here.
7101 
7102     // 7. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) have
7103     // different results, then:
7104   } else if (current_is_data_descriptor != desc_is_data_descriptor) {
7105     // 7a. Return false, if the [[Configurable]] field of current is false.
7106     if (!current->configurable()) {
7107       RETURN_FAILURE(
7108           isolate, should_throw,
7109           NewTypeError(MessageTemplate::kRedefineDisallowed,
7110                        it != nullptr ? it->GetName() : property_name));
7111     }
7112     // 7b. If IsDataDescriptor(current) is true, then:
7113     if (current_is_data_descriptor) {
7114       // 7b i. If O is not undefined, convert the property named P of object O
7115       // from a data property to an accessor property. Preserve the existing
7116       // values of the converted property's [[Configurable]] and [[Enumerable]]
7117       // attributes and set the rest of the property's attributes to their
7118       // default values.
7119       // --> Folded into step 10.
7120     } else {
7121       // 7c i. If O is not undefined, convert the property named P of object O
7122       // from an accessor property to a data property. Preserve the existing
7123       // values of the converted property’s [[Configurable]] and [[Enumerable]]
7124       // attributes and set the rest of the property’s attributes to their
7125       // default values.
7126       // --> Folded into step 10.
7127     }
7128 
7129     // 8. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both
7130     // true, then:
7131   } else if (current_is_data_descriptor && desc_is_data_descriptor) {
7132     // 8a. If the [[Configurable]] field of current is false, then:
7133     if (!current->configurable()) {
7134       // 8a i. Return false, if the [[Writable]] field of current is false and
7135       // the [[Writable]] field of Desc is true.
7136       if (!current->writable() && desc->has_writable() && desc->writable()) {
7137         RETURN_FAILURE(
7138             isolate, should_throw,
7139             NewTypeError(MessageTemplate::kRedefineDisallowed,
7140                          it != nullptr ? it->GetName() : property_name));
7141       }
7142       // 8a ii. If the [[Writable]] field of current is false, then:
7143       if (!current->writable()) {
7144         // 8a ii 1. Return false, if the [[Value]] field of Desc is present and
7145         // SameValue(Desc.[[Value]], current.[[Value]]) is false.
7146         if (desc->has_value() && !desc->value()->SameValue(*current->value())) {
7147           RETURN_FAILURE(
7148               isolate, should_throw,
7149               NewTypeError(MessageTemplate::kRedefineDisallowed,
7150                            it != nullptr ? it->GetName() : property_name));
7151         }
7152       }
7153     }
7154   } else {
7155     // 9. Else IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc)
7156     // are both true,
7157     DCHECK(PropertyDescriptor::IsAccessorDescriptor(current) &&
7158            desc_is_accessor_descriptor);
7159     // 9a. If the [[Configurable]] field of current is false, then:
7160     if (!current->configurable()) {
7161       // 9a i. Return false, if the [[Set]] field of Desc is present and
7162       // SameValue(Desc.[[Set]], current.[[Set]]) is false.
7163       if (desc->has_set() && !desc->set()->SameValue(*current->set())) {
7164         RETURN_FAILURE(
7165             isolate, should_throw,
7166             NewTypeError(MessageTemplate::kRedefineDisallowed,
7167                          it != nullptr ? it->GetName() : property_name));
7168       }
7169       // 9a ii. Return false, if the [[Get]] field of Desc is present and
7170       // SameValue(Desc.[[Get]], current.[[Get]]) is false.
7171       if (desc->has_get() && !desc->get()->SameValue(*current->get())) {
7172         RETURN_FAILURE(
7173             isolate, should_throw,
7174             NewTypeError(MessageTemplate::kRedefineDisallowed,
7175                          it != nullptr ? it->GetName() : property_name));
7176       }
7177     }
7178   }
7179 
7180   // 10. If O is not undefined, then:
7181   if (it != nullptr) {
7182     // 10a. For each field of Desc that is present, set the corresponding
7183     // attribute of the property named P of object O to the value of the field.
7184     PropertyAttributes attrs = NONE;
7185 
7186     if (desc->has_enumerable()) {
7187       attrs = static_cast<PropertyAttributes>(
7188           attrs | (desc->enumerable() ? NONE : DONT_ENUM));
7189     } else {
7190       attrs = static_cast<PropertyAttributes>(
7191           attrs | (current->enumerable() ? NONE : DONT_ENUM));
7192     }
7193     if (desc->has_configurable()) {
7194       attrs = static_cast<PropertyAttributes>(
7195           attrs | (desc->configurable() ? NONE : DONT_DELETE));
7196     } else {
7197       attrs = static_cast<PropertyAttributes>(
7198           attrs | (current->configurable() ? NONE : DONT_DELETE));
7199     }
7200     if (desc_is_data_descriptor ||
7201         (desc_is_generic_descriptor && current_is_data_descriptor)) {
7202       if (desc->has_writable()) {
7203         attrs = static_cast<PropertyAttributes>(
7204             attrs | (desc->writable() ? NONE : READ_ONLY));
7205       } else {
7206         attrs = static_cast<PropertyAttributes>(
7207             attrs | (current->writable() ? NONE : READ_ONLY));
7208       }
7209       Handle<Object> value(
7210           desc->has_value() ? desc->value()
7211                             : current->has_value()
7212                                   ? current->value()
7213                                   : Handle<Object>::cast(
7214                                         isolate->factory()->undefined_value()));
7215       return JSObject::DefineOwnPropertyIgnoreAttributes(it, value, attrs,
7216                                                          should_throw);
7217     } else {
7218       DCHECK(desc_is_accessor_descriptor ||
7219              (desc_is_generic_descriptor &&
7220               PropertyDescriptor::IsAccessorDescriptor(current)));
7221       Handle<Object> getter(
7222           desc->has_get()
7223               ? desc->get()
7224               : current->has_get()
7225                     ? current->get()
7226                     : Handle<Object>::cast(isolate->factory()->null_value()));
7227       Handle<Object> setter(
7228           desc->has_set()
7229               ? desc->set()
7230               : current->has_set()
7231                     ? current->set()
7232                     : Handle<Object>::cast(isolate->factory()->null_value()));
7233       MaybeHandle<Object> result =
7234           JSObject::DefineAccessor(it, getter, setter, attrs);
7235       if (result.is_null()) return Nothing<bool>();
7236     }
7237   }
7238 
7239   // 11. Return true.
7240   return Just(true);
7241 }
7242 
7243 
7244 // static
CreateDataProperty(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)7245 Maybe<bool> JSReceiver::CreateDataProperty(LookupIterator* it,
7246                                            Handle<Object> value,
7247                                            ShouldThrow should_throw) {
7248   DCHECK(!it->check_prototype_chain());
7249   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
7250   Isolate* isolate = receiver->GetIsolate();
7251 
7252   if (receiver->IsJSObject()) {
7253     return JSObject::CreateDataProperty(it, value, should_throw);  // Shortcut.
7254   }
7255 
7256   PropertyDescriptor new_desc;
7257   new_desc.set_value(value);
7258   new_desc.set_writable(true);
7259   new_desc.set_enumerable(true);
7260   new_desc.set_configurable(true);
7261 
7262   return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
7263                                        &new_desc, should_throw);
7264 }
7265 
CreateDataProperty(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)7266 Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it,
7267                                          Handle<Object> value,
7268                                          ShouldThrow should_throw) {
7269   DCHECK(it->GetReceiver()->IsJSObject());
7270   MAYBE_RETURN(JSReceiver::GetPropertyAttributes(it), Nothing<bool>());
7271   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
7272   Isolate* isolate = receiver->GetIsolate();
7273 
7274   if (it->IsFound()) {
7275     Maybe<PropertyAttributes> attributes = GetPropertyAttributes(it);
7276     MAYBE_RETURN(attributes, Nothing<bool>());
7277     if ((attributes.FromJust() & DONT_DELETE) != 0) {
7278       RETURN_FAILURE(
7279           isolate, should_throw,
7280           NewTypeError(MessageTemplate::kRedefineDisallowed, it->GetName()));
7281     }
7282   } else {
7283     if (!JSObject::IsExtensible(Handle<JSObject>::cast(it->GetReceiver()))) {
7284       RETURN_FAILURE(
7285           isolate, should_throw,
7286           NewTypeError(MessageTemplate::kDefineDisallowed, it->GetName()));
7287     }
7288   }
7289 
7290   RETURN_ON_EXCEPTION_VALUE(it->isolate(),
7291                             DefineOwnPropertyIgnoreAttributes(it, value, NONE),
7292                             Nothing<bool>());
7293 
7294   return Just(true);
7295 }
7296 
7297 // TODO(jkummerow): Consider unification with FastAsArrayLength() in
7298 // accessors.cc.
PropertyKeyToArrayLength(Handle<Object> value,uint32_t * length)7299 bool PropertyKeyToArrayLength(Handle<Object> value, uint32_t* length) {
7300   DCHECK(value->IsNumber() || value->IsName());
7301   if (value->ToArrayLength(length)) return true;
7302   if (value->IsString()) return String::cast(*value)->AsArrayIndex(length);
7303   return false;
7304 }
7305 
PropertyKeyToArrayIndex(Handle<Object> index_obj,uint32_t * output)7306 bool PropertyKeyToArrayIndex(Handle<Object> index_obj, uint32_t* output) {
7307   return PropertyKeyToArrayLength(index_obj, output) && *output != kMaxUInt32;
7308 }
7309 
7310 
7311 // ES6 9.4.2.1
7312 // static
DefineOwnProperty(Isolate * isolate,Handle<JSArray> o,Handle<Object> name,PropertyDescriptor * desc,ShouldThrow should_throw)7313 Maybe<bool> JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o,
7314                                        Handle<Object> name,
7315                                        PropertyDescriptor* desc,
7316                                        ShouldThrow should_throw) {
7317   // 1. Assert: IsPropertyKey(P) is true. ("P" is |name|.)
7318   // 2. If P is "length", then:
7319   // TODO(jkummerow): Check if we need slow string comparison.
7320   if (*name == isolate->heap()->length_string()) {
7321     // 2a. Return ArraySetLength(A, Desc).
7322     return ArraySetLength(isolate, o, desc, should_throw);
7323   }
7324   // 3. Else if P is an array index, then:
7325   uint32_t index = 0;
7326   if (PropertyKeyToArrayIndex(name, &index)) {
7327     // 3a. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
7328     PropertyDescriptor old_len_desc;
7329     Maybe<bool> success = GetOwnPropertyDescriptor(
7330         isolate, o, isolate->factory()->length_string(), &old_len_desc);
7331     // 3b. (Assert)
7332     DCHECK(success.FromJust());
7333     USE(success);
7334     // 3c. Let oldLen be oldLenDesc.[[Value]].
7335     uint32_t old_len = 0;
7336     CHECK(old_len_desc.value()->ToArrayLength(&old_len));
7337     // 3d. Let index be ToUint32(P).
7338     // (Already done above.)
7339     // 3e. (Assert)
7340     // 3f. If index >= oldLen and oldLenDesc.[[Writable]] is false,
7341     //     return false.
7342     if (index >= old_len && old_len_desc.has_writable() &&
7343         !old_len_desc.writable()) {
7344       RETURN_FAILURE(isolate, should_throw,
7345                      NewTypeError(MessageTemplate::kDefineDisallowed, name));
7346     }
7347     // 3g. Let succeeded be OrdinaryDefineOwnProperty(A, P, Desc).
7348     Maybe<bool> succeeded =
7349         OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
7350     // 3h. Assert: succeeded is not an abrupt completion.
7351     //     In our case, if should_throw == kThrowOnError, it can be!
7352     // 3i. If succeeded is false, return false.
7353     if (succeeded.IsNothing() || !succeeded.FromJust()) return succeeded;
7354     // 3j. If index >= oldLen, then:
7355     if (index >= old_len) {
7356       // 3j i. Set oldLenDesc.[[Value]] to index + 1.
7357       old_len_desc.set_value(isolate->factory()->NewNumberFromUint(index + 1));
7358       // 3j ii. Let succeeded be
7359       //        OrdinaryDefineOwnProperty(A, "length", oldLenDesc).
7360       succeeded = OrdinaryDefineOwnProperty(isolate, o,
7361                                             isolate->factory()->length_string(),
7362                                             &old_len_desc, should_throw);
7363       // 3j iii. Assert: succeeded is true.
7364       DCHECK(succeeded.FromJust());
7365       USE(succeeded);
7366     }
7367     // 3k. Return true.
7368     return Just(true);
7369   }
7370 
7371   // 4. Return OrdinaryDefineOwnProperty(A, P, Desc).
7372   return OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
7373 }
7374 
7375 
7376 // Part of ES6 9.4.2.4 ArraySetLength.
7377 // static
AnythingToArrayLength(Isolate * isolate,Handle<Object> length_object,uint32_t * output)7378 bool JSArray::AnythingToArrayLength(Isolate* isolate,
7379                                     Handle<Object> length_object,
7380                                     uint32_t* output) {
7381   // Fast path: check numbers and strings that can be converted directly
7382   // and unobservably.
7383   if (length_object->ToArrayLength(output)) return true;
7384   if (length_object->IsString() &&
7385       Handle<String>::cast(length_object)->AsArrayIndex(output)) {
7386     return true;
7387   }
7388   // Slow path: follow steps in ES6 9.4.2.4 "ArraySetLength".
7389   // 3. Let newLen be ToUint32(Desc.[[Value]]).
7390   Handle<Object> uint32_v;
7391   if (!Object::ToUint32(isolate, length_object).ToHandle(&uint32_v)) {
7392     // 4. ReturnIfAbrupt(newLen).
7393     return false;
7394   }
7395   // 5. Let numberLen be ToNumber(Desc.[[Value]]).
7396   Handle<Object> number_v;
7397   if (!Object::ToNumber(length_object).ToHandle(&number_v)) {
7398     // 6. ReturnIfAbrupt(newLen).
7399     return false;
7400   }
7401   // 7. If newLen != numberLen, throw a RangeError exception.
7402   if (uint32_v->Number() != number_v->Number()) {
7403     Handle<Object> exception =
7404         isolate->factory()->NewRangeError(MessageTemplate::kInvalidArrayLength);
7405     isolate->Throw(*exception);
7406     return false;
7407   }
7408   CHECK(uint32_v->ToArrayLength(output));
7409   return true;
7410 }
7411 
7412 
7413 // ES6 9.4.2.4
7414 // static
ArraySetLength(Isolate * isolate,Handle<JSArray> a,PropertyDescriptor * desc,ShouldThrow should_throw)7415 Maybe<bool> JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a,
7416                                     PropertyDescriptor* desc,
7417                                     ShouldThrow should_throw) {
7418   // 1. If the [[Value]] field of Desc is absent, then
7419   if (!desc->has_value()) {
7420     // 1a. Return OrdinaryDefineOwnProperty(A, "length", Desc).
7421     return OrdinaryDefineOwnProperty(
7422         isolate, a, isolate->factory()->length_string(), desc, should_throw);
7423   }
7424   // 2. Let newLenDesc be a copy of Desc.
7425   // (Actual copying is not necessary.)
7426   PropertyDescriptor* new_len_desc = desc;
7427   // 3. - 7. Convert Desc.[[Value]] to newLen.
7428   uint32_t new_len = 0;
7429   if (!AnythingToArrayLength(isolate, desc->value(), &new_len)) {
7430     DCHECK(isolate->has_pending_exception());
7431     return Nothing<bool>();
7432   }
7433   // 8. Set newLenDesc.[[Value]] to newLen.
7434   // (Done below, if needed.)
7435   // 9. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
7436   PropertyDescriptor old_len_desc;
7437   Maybe<bool> success = GetOwnPropertyDescriptor(
7438       isolate, a, isolate->factory()->length_string(), &old_len_desc);
7439   // 10. (Assert)
7440   DCHECK(success.FromJust());
7441   USE(success);
7442   // 11. Let oldLen be oldLenDesc.[[Value]].
7443   uint32_t old_len = 0;
7444   CHECK(old_len_desc.value()->ToArrayLength(&old_len));
7445   // 12. If newLen >= oldLen, then
7446   if (new_len >= old_len) {
7447     // 8. Set newLenDesc.[[Value]] to newLen.
7448     // 12a. Return OrdinaryDefineOwnProperty(A, "length", newLenDesc).
7449     new_len_desc->set_value(isolate->factory()->NewNumberFromUint(new_len));
7450     return OrdinaryDefineOwnProperty(isolate, a,
7451                                      isolate->factory()->length_string(),
7452                                      new_len_desc, should_throw);
7453   }
7454   // 13. If oldLenDesc.[[Writable]] is false, return false.
7455   if (!old_len_desc.writable()) {
7456     RETURN_FAILURE(isolate, should_throw,
7457                    NewTypeError(MessageTemplate::kRedefineDisallowed,
7458                                 isolate->factory()->length_string()));
7459   }
7460   // 14. If newLenDesc.[[Writable]] is absent or has the value true,
7461   // let newWritable be true.
7462   bool new_writable = false;
7463   if (!new_len_desc->has_writable() || new_len_desc->writable()) {
7464     new_writable = true;
7465   } else {
7466     // 15. Else,
7467     // 15a. Need to defer setting the [[Writable]] attribute to false in case
7468     //      any elements cannot be deleted.
7469     // 15b. Let newWritable be false. (It's initialized as "false" anyway.)
7470     // 15c. Set newLenDesc.[[Writable]] to true.
7471     // (Not needed.)
7472   }
7473   // Most of steps 16 through 19 is implemented by JSArray::SetLength.
7474   JSArray::SetLength(a, new_len);
7475   // Steps 19d-ii, 20.
7476   if (!new_writable) {
7477     PropertyDescriptor readonly;
7478     readonly.set_writable(false);
7479     Maybe<bool> success = OrdinaryDefineOwnProperty(
7480         isolate, a, isolate->factory()->length_string(), &readonly,
7481         should_throw);
7482     DCHECK(success.FromJust());
7483     USE(success);
7484   }
7485   uint32_t actual_new_len = 0;
7486   CHECK(a->length()->ToArrayLength(&actual_new_len));
7487   // Steps 19d-v, 21. Return false if there were non-deletable elements.
7488   bool result = actual_new_len == new_len;
7489   if (!result) {
7490     RETURN_FAILURE(
7491         isolate, should_throw,
7492         NewTypeError(MessageTemplate::kStrictDeleteProperty,
7493                      isolate->factory()->NewNumberFromUint(actual_new_len - 1),
7494                      a));
7495   }
7496   return Just(result);
7497 }
7498 
7499 
7500 // ES6 9.5.6
7501 // static
DefineOwnProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Object> key,PropertyDescriptor * desc,ShouldThrow should_throw)7502 Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy,
7503                                        Handle<Object> key,
7504                                        PropertyDescriptor* desc,
7505                                        ShouldThrow should_throw) {
7506   STACK_CHECK(isolate, Nothing<bool>());
7507   if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) {
7508     DCHECK(!Handle<Symbol>::cast(key)->IsPrivateField());
7509     return JSProxy::SetPrivateSymbol(isolate, proxy, Handle<Symbol>::cast(key),
7510                                      desc, should_throw);
7511   }
7512   Handle<String> trap_name = isolate->factory()->defineProperty_string();
7513   // 1. Assert: IsPropertyKey(P) is true.
7514   DCHECK(key->IsName() || key->IsNumber());
7515   // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
7516   Handle<Object> handler(proxy->handler(), isolate);
7517   // 3. If handler is null, throw a TypeError exception.
7518   // 4. Assert: Type(handler) is Object.
7519   if (proxy->IsRevoked()) {
7520     isolate->Throw(*isolate->factory()->NewTypeError(
7521         MessageTemplate::kProxyRevoked, trap_name));
7522     return Nothing<bool>();
7523   }
7524   // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
7525   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
7526   // 6. Let trap be ? GetMethod(handler, "defineProperty").
7527   Handle<Object> trap;
7528   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7529       isolate, trap,
7530       Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
7531       Nothing<bool>());
7532   // 7. If trap is undefined, then:
7533   if (trap->IsUndefined(isolate)) {
7534     // 7a. Return target.[[DefineOwnProperty]](P, Desc).
7535     return JSReceiver::DefineOwnProperty(isolate, target, key, desc,
7536                                          should_throw);
7537   }
7538   // 8. Let descObj be FromPropertyDescriptor(Desc).
7539   Handle<Object> desc_obj = desc->ToObject(isolate);
7540   // 9. Let booleanTrapResult be
7541   //    ToBoolean(? Call(trap, handler, «target, P, descObj»)).
7542   Handle<Name> property_name =
7543       key->IsName()
7544           ? Handle<Name>::cast(key)
7545           : Handle<Name>::cast(isolate->factory()->NumberToString(key));
7546   // Do not leak private property names.
7547   DCHECK(!property_name->IsPrivate());
7548   Handle<Object> trap_result_obj;
7549   Handle<Object> args[] = {target, property_name, desc_obj};
7550   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7551       isolate, trap_result_obj,
7552       Execution::Call(isolate, trap, handler, arraysize(args), args),
7553       Nothing<bool>());
7554   // 10. If booleanTrapResult is false, return false.
7555   if (!trap_result_obj->BooleanValue()) {
7556     RETURN_FAILURE(isolate, should_throw,
7557                    NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
7558                                 trap_name, property_name));
7559   }
7560   // 11. Let targetDesc be ? target.[[GetOwnProperty]](P).
7561   PropertyDescriptor target_desc;
7562   Maybe<bool> target_found =
7563       JSReceiver::GetOwnPropertyDescriptor(isolate, target, key, &target_desc);
7564   MAYBE_RETURN(target_found, Nothing<bool>());
7565   // 12. Let extensibleTarget be ? IsExtensible(target).
7566   Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
7567   MAYBE_RETURN(maybe_extensible, Nothing<bool>());
7568   bool extensible_target = maybe_extensible.FromJust();
7569   // 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]]
7570   //     is false, then:
7571   // 13a. Let settingConfigFalse be true.
7572   // 14. Else let settingConfigFalse be false.
7573   bool setting_config_false = desc->has_configurable() && !desc->configurable();
7574   // 15. If targetDesc is undefined, then
7575   if (!target_found.FromJust()) {
7576     // 15a. If extensibleTarget is false, throw a TypeError exception.
7577     if (!extensible_target) {
7578       isolate->Throw(*isolate->factory()->NewTypeError(
7579           MessageTemplate::kProxyDefinePropertyNonExtensible, property_name));
7580       return Nothing<bool>();
7581     }
7582     // 15b. If settingConfigFalse is true, throw a TypeError exception.
7583     if (setting_config_false) {
7584       isolate->Throw(*isolate->factory()->NewTypeError(
7585           MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
7586       return Nothing<bool>();
7587     }
7588   } else {
7589     // 16. Else targetDesc is not undefined,
7590     // 16a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc,
7591     //      targetDesc) is false, throw a TypeError exception.
7592     Maybe<bool> valid =
7593         IsCompatiblePropertyDescriptor(isolate, extensible_target, desc,
7594                                        &target_desc, property_name, kDontThrow);
7595     MAYBE_RETURN(valid, Nothing<bool>());
7596     if (!valid.FromJust()) {
7597       isolate->Throw(*isolate->factory()->NewTypeError(
7598           MessageTemplate::kProxyDefinePropertyIncompatible, property_name));
7599       return Nothing<bool>();
7600     }
7601     // 16b. If settingConfigFalse is true and targetDesc.[[Configurable]] is
7602     //      true, throw a TypeError exception.
7603     if (setting_config_false && target_desc.configurable()) {
7604       isolate->Throw(*isolate->factory()->NewTypeError(
7605           MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
7606       return Nothing<bool>();
7607     }
7608   }
7609   // 17. Return true.
7610   return Just(true);
7611 }
7612 
7613 // static
SetPrivateSymbol(Isolate * isolate,Handle<JSProxy> proxy,Handle<Symbol> private_name,PropertyDescriptor * desc,ShouldThrow should_throw)7614 Maybe<bool> JSProxy::SetPrivateSymbol(Isolate* isolate, Handle<JSProxy> proxy,
7615                                       Handle<Symbol> private_name,
7616                                       PropertyDescriptor* desc,
7617                                       ShouldThrow should_throw) {
7618   DCHECK(!private_name->IsPrivateField());
7619   // Despite the generic name, this can only add private data properties.
7620   if (!PropertyDescriptor::IsDataDescriptor(desc) ||
7621       desc->ToAttributes() != DONT_ENUM) {
7622     RETURN_FAILURE(isolate, should_throw,
7623                    NewTypeError(MessageTemplate::kProxyPrivate));
7624   }
7625   DCHECK(proxy->map()->is_dictionary_map());
7626   Handle<Object> value =
7627       desc->has_value()
7628           ? desc->value()
7629           : Handle<Object>::cast(isolate->factory()->undefined_value());
7630 
7631   LookupIterator it(proxy, private_name, proxy);
7632 
7633   if (it.IsFound()) {
7634     DCHECK_EQ(LookupIterator::DATA, it.state());
7635     DCHECK_EQ(DONT_ENUM, it.property_attributes());
7636     it.WriteDataValue(value, false);
7637     return Just(true);
7638   }
7639 
7640   Handle<NameDictionary> dict(proxy->property_dictionary());
7641   PropertyDetails details(kData, DONT_ENUM, PropertyCellType::kNoCell);
7642   Handle<NameDictionary> result =
7643       NameDictionary::Add(dict, private_name, value, details);
7644   if (!dict.is_identical_to(result)) proxy->SetProperties(*result);
7645   return Just(true);
7646 }
7647 
7648 // static
GetOwnPropertyDescriptor(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> key,PropertyDescriptor * desc)7649 Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate,
7650                                                  Handle<JSReceiver> object,
7651                                                  Handle<Object> key,
7652                                                  PropertyDescriptor* desc) {
7653   bool success = false;
7654   DCHECK(key->IsName() || key->IsNumber());  // |key| is a PropertyKey...
7655   LookupIterator it = LookupIterator::PropertyOrElement(
7656       isolate, object, key, &success, LookupIterator::OWN);
7657   DCHECK(success);  // ...so creating a LookupIterator can't fail.
7658   return GetOwnPropertyDescriptor(&it, desc);
7659 }
7660 
7661 namespace {
7662 
GetPropertyDescriptorWithInterceptor(LookupIterator * it,PropertyDescriptor * desc)7663 Maybe<bool> GetPropertyDescriptorWithInterceptor(LookupIterator* it,
7664                                                  PropertyDescriptor* desc) {
7665   bool has_access = true;
7666   if (it->state() == LookupIterator::ACCESS_CHECK) {
7667     has_access = it->HasAccess() || JSObject::AllCanRead(it);
7668     it->Next();
7669   }
7670 
7671   if (has_access && it->state() == LookupIterator::INTERCEPTOR) {
7672     Isolate* isolate = it->isolate();
7673     Handle<InterceptorInfo> interceptor = it->GetInterceptor();
7674     if (!interceptor->descriptor()->IsUndefined(isolate)) {
7675       Handle<Object> result;
7676       Handle<JSObject> holder = it->GetHolder<JSObject>();
7677 
7678       Handle<Object> receiver = it->GetReceiver();
7679       if (!receiver->IsJSReceiver()) {
7680         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7681             isolate, receiver, Object::ConvertReceiver(isolate, receiver),
7682             Nothing<bool>());
7683       }
7684 
7685       PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
7686                                      *holder, kDontThrow);
7687       if (it->IsElement()) {
7688         result = args.CallIndexedDescriptor(interceptor, it->index());
7689       } else {
7690         result = args.CallNamedDescriptor(interceptor, it->name());
7691       }
7692       if (!result.is_null()) {
7693         // Request successfully intercepted, try to set the property
7694         // descriptor.
7695         Utils::ApiCheck(
7696             PropertyDescriptor::ToPropertyDescriptor(isolate, result, desc),
7697             it->IsElement() ? "v8::IndexedPropertyDescriptorCallback"
7698                             : "v8::NamedPropertyDescriptorCallback",
7699             "Invalid property descriptor.");
7700 
7701         return Just(true);
7702       }
7703     }
7704   }
7705   it->Restart();
7706   return Just(false);
7707 }
7708 }  // namespace
7709 
7710 // ES6 9.1.5.1
7711 // Returns true on success, false if the property didn't exist, nothing if
7712 // an exception was thrown.
7713 // static
GetOwnPropertyDescriptor(LookupIterator * it,PropertyDescriptor * desc)7714 Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it,
7715                                                  PropertyDescriptor* desc) {
7716   Isolate* isolate = it->isolate();
7717   // "Virtual" dispatch.
7718   if (it->IsFound() && it->GetHolder<JSReceiver>()->IsJSProxy()) {
7719     return JSProxy::GetOwnPropertyDescriptor(isolate, it->GetHolder<JSProxy>(),
7720                                              it->GetName(), desc);
7721   }
7722 
7723   Maybe<bool> intercepted = GetPropertyDescriptorWithInterceptor(it, desc);
7724   MAYBE_RETURN(intercepted, Nothing<bool>());
7725   if (intercepted.FromJust()) {
7726     return Just(true);
7727   }
7728 
7729   // Request was not intercepted, continue as normal.
7730   // 1. (Assert)
7731   // 2. If O does not have an own property with key P, return undefined.
7732   Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(it);
7733   MAYBE_RETURN(maybe, Nothing<bool>());
7734   PropertyAttributes attrs = maybe.FromJust();
7735   if (attrs == ABSENT) return Just(false);
7736   DCHECK(!isolate->has_pending_exception());
7737 
7738   // 3. Let D be a newly created Property Descriptor with no fields.
7739   DCHECK(desc->is_empty());
7740   // 4. Let X be O's own property whose key is P.
7741   // 5. If X is a data property, then
7742   bool is_accessor_pair = it->state() == LookupIterator::ACCESSOR &&
7743                           it->GetAccessors()->IsAccessorPair();
7744   if (!is_accessor_pair) {
7745     // 5a. Set D.[[Value]] to the value of X's [[Value]] attribute.
7746     Handle<Object> value;
7747     if (!Object::GetProperty(it).ToHandle(&value)) {
7748       DCHECK(isolate->has_pending_exception());
7749       return Nothing<bool>();
7750     }
7751     desc->set_value(value);
7752     // 5b. Set D.[[Writable]] to the value of X's [[Writable]] attribute
7753     desc->set_writable((attrs & READ_ONLY) == 0);
7754   } else {
7755     // 6. Else X is an accessor property, so
7756     Handle<AccessorPair> accessors =
7757         Handle<AccessorPair>::cast(it->GetAccessors());
7758     // 6a. Set D.[[Get]] to the value of X's [[Get]] attribute.
7759     desc->set_get(AccessorPair::GetComponent(accessors, ACCESSOR_GETTER));
7760     // 6b. Set D.[[Set]] to the value of X's [[Set]] attribute.
7761     desc->set_set(AccessorPair::GetComponent(accessors, ACCESSOR_SETTER));
7762   }
7763 
7764   // 7. Set D.[[Enumerable]] to the value of X's [[Enumerable]] attribute.
7765   desc->set_enumerable((attrs & DONT_ENUM) == 0);
7766   // 8. Set D.[[Configurable]] to the value of X's [[Configurable]] attribute.
7767   desc->set_configurable((attrs & DONT_DELETE) == 0);
7768   // 9. Return D.
7769   DCHECK(PropertyDescriptor::IsAccessorDescriptor(desc) !=
7770          PropertyDescriptor::IsDataDescriptor(desc));
7771   return Just(true);
7772 }
7773 
7774 
7775 // ES6 9.5.5
7776 // static
GetOwnPropertyDescriptor(Isolate * isolate,Handle<JSProxy> proxy,Handle<Name> name,PropertyDescriptor * desc)7777 Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate,
7778                                               Handle<JSProxy> proxy,
7779                                               Handle<Name> name,
7780                                               PropertyDescriptor* desc) {
7781   DCHECK(!name->IsPrivate());
7782   STACK_CHECK(isolate, Nothing<bool>());
7783 
7784   Handle<String> trap_name =
7785       isolate->factory()->getOwnPropertyDescriptor_string();
7786   // 1. (Assert)
7787   // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
7788   Handle<Object> handler(proxy->handler(), isolate);
7789   // 3. If handler is null, throw a TypeError exception.
7790   // 4. Assert: Type(handler) is Object.
7791   if (proxy->IsRevoked()) {
7792     isolate->Throw(*isolate->factory()->NewTypeError(
7793         MessageTemplate::kProxyRevoked, trap_name));
7794     return Nothing<bool>();
7795   }
7796   // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
7797   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
7798   // 6. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor").
7799   Handle<Object> trap;
7800   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7801       isolate, trap,
7802       Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
7803       Nothing<bool>());
7804   // 7. If trap is undefined, then
7805   if (trap->IsUndefined(isolate)) {
7806     // 7a. Return target.[[GetOwnProperty]](P).
7807     return JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, desc);
7808   }
7809   // 8. Let trapResultObj be ? Call(trap, handler, «target, P»).
7810   Handle<Object> trap_result_obj;
7811   Handle<Object> args[] = {target, name};
7812   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7813       isolate, trap_result_obj,
7814       Execution::Call(isolate, trap, handler, arraysize(args), args),
7815       Nothing<bool>());
7816   // 9. If Type(trapResultObj) is neither Object nor Undefined, throw a
7817   //    TypeError exception.
7818   if (!trap_result_obj->IsJSReceiver() &&
7819       !trap_result_obj->IsUndefined(isolate)) {
7820     isolate->Throw(*isolate->factory()->NewTypeError(
7821         MessageTemplate::kProxyGetOwnPropertyDescriptorInvalid, name));
7822     return Nothing<bool>();
7823   }
7824   // 10. Let targetDesc be ? target.[[GetOwnProperty]](P).
7825   PropertyDescriptor target_desc;
7826   Maybe<bool> found =
7827       JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
7828   MAYBE_RETURN(found, Nothing<bool>());
7829   // 11. If trapResultObj is undefined, then
7830   if (trap_result_obj->IsUndefined(isolate)) {
7831     // 11a. If targetDesc is undefined, return undefined.
7832     if (!found.FromJust()) return Just(false);
7833     // 11b. If targetDesc.[[Configurable]] is false, throw a TypeError
7834     //      exception.
7835     if (!target_desc.configurable()) {
7836       isolate->Throw(*isolate->factory()->NewTypeError(
7837           MessageTemplate::kProxyGetOwnPropertyDescriptorUndefined, name));
7838       return Nothing<bool>();
7839     }
7840     // 11c. Let extensibleTarget be ? IsExtensible(target).
7841     Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
7842     MAYBE_RETURN(extensible_target, Nothing<bool>());
7843     // 11d. (Assert)
7844     // 11e. If extensibleTarget is false, throw a TypeError exception.
7845     if (!extensible_target.FromJust()) {
7846       isolate->Throw(*isolate->factory()->NewTypeError(
7847           MessageTemplate::kProxyGetOwnPropertyDescriptorNonExtensible, name));
7848       return Nothing<bool>();
7849     }
7850     // 11f. Return undefined.
7851     return Just(false);
7852   }
7853   // 12. Let extensibleTarget be ? IsExtensible(target).
7854   Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
7855   MAYBE_RETURN(extensible_target, Nothing<bool>());
7856   // 13. Let resultDesc be ? ToPropertyDescriptor(trapResultObj).
7857   if (!PropertyDescriptor::ToPropertyDescriptor(isolate, trap_result_obj,
7858                                                 desc)) {
7859     DCHECK(isolate->has_pending_exception());
7860     return Nothing<bool>();
7861   }
7862   // 14. Call CompletePropertyDescriptor(resultDesc).
7863   PropertyDescriptor::CompletePropertyDescriptor(isolate, desc);
7864   // 15. Let valid be IsCompatiblePropertyDescriptor (extensibleTarget,
7865   //     resultDesc, targetDesc).
7866   Maybe<bool> valid =
7867       IsCompatiblePropertyDescriptor(isolate, extensible_target.FromJust(),
7868                                      desc, &target_desc, name, kDontThrow);
7869   MAYBE_RETURN(valid, Nothing<bool>());
7870   // 16. If valid is false, throw a TypeError exception.
7871   if (!valid.FromJust()) {
7872     isolate->Throw(*isolate->factory()->NewTypeError(
7873         MessageTemplate::kProxyGetOwnPropertyDescriptorIncompatible, name));
7874     return Nothing<bool>();
7875   }
7876   // 17. If resultDesc.[[Configurable]] is false, then
7877   if (!desc->configurable()) {
7878     // 17a. If targetDesc is undefined or targetDesc.[[Configurable]] is true:
7879     if (target_desc.is_empty() || target_desc.configurable()) {
7880       // 17a i. Throw a TypeError exception.
7881       isolate->Throw(*isolate->factory()->NewTypeError(
7882           MessageTemplate::kProxyGetOwnPropertyDescriptorNonConfigurable,
7883           name));
7884       return Nothing<bool>();
7885     }
7886   }
7887   // 18. Return resultDesc.
7888   return Just(true);
7889 }
7890 
7891 
ReferencesObjectFromElements(FixedArray * elements,ElementsKind kind,Object * object)7892 bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
7893                                             ElementsKind kind,
7894                                             Object* object) {
7895   Isolate* isolate = elements->GetIsolate();
7896   if (IsObjectElementsKind(kind) || kind == FAST_STRING_WRAPPER_ELEMENTS) {
7897     int length = IsJSArray() ? Smi::ToInt(JSArray::cast(this)->length())
7898                              : elements->length();
7899     for (int i = 0; i < length; ++i) {
7900       Object* element = elements->get(i);
7901       if (!element->IsTheHole(isolate) && element == object) return true;
7902     }
7903   } else {
7904     DCHECK(kind == DICTIONARY_ELEMENTS || kind == SLOW_STRING_WRAPPER_ELEMENTS);
7905     Object* key = NumberDictionary::cast(elements)->SlowReverseLookup(object);
7906     if (!key->IsUndefined(isolate)) return true;
7907   }
7908   return false;
7909 }
7910 
7911 
7912 // Check whether this object references another object.
ReferencesObject(Object * obj)7913 bool JSObject::ReferencesObject(Object* obj) {
7914   Map* map_of_this = map();
7915   Heap* heap = GetHeap();
7916   DisallowHeapAllocation no_allocation;
7917 
7918   // Is the object the constructor for this object?
7919   if (map_of_this->GetConstructor() == obj) {
7920     return true;
7921   }
7922 
7923   // Is the object the prototype for this object?
7924   if (map_of_this->prototype() == obj) {
7925     return true;
7926   }
7927 
7928   // Check if the object is among the named properties.
7929   Object* key = SlowReverseLookup(obj);
7930   if (!key->IsUndefined(heap->isolate())) {
7931     return true;
7932   }
7933 
7934   // Check if the object is among the indexed properties.
7935   ElementsKind kind = GetElementsKind();
7936   switch (kind) {
7937     // Raw pixels and external arrays do not reference other
7938     // objects.
7939 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                        \
7940     case TYPE##_ELEMENTS:                                                      \
7941       break;
7942 
7943     TYPED_ARRAYS(TYPED_ARRAY_CASE)
7944 #undef TYPED_ARRAY_CASE
7945 
7946     case PACKED_DOUBLE_ELEMENTS:
7947     case HOLEY_DOUBLE_ELEMENTS:
7948       break;
7949     case PACKED_SMI_ELEMENTS:
7950     case HOLEY_SMI_ELEMENTS:
7951       break;
7952     case PACKED_ELEMENTS:
7953     case HOLEY_ELEMENTS:
7954     case DICTIONARY_ELEMENTS:
7955     case FAST_STRING_WRAPPER_ELEMENTS:
7956     case SLOW_STRING_WRAPPER_ELEMENTS: {
7957       FixedArray* elements = FixedArray::cast(this->elements());
7958       if (ReferencesObjectFromElements(elements, kind, obj)) return true;
7959       break;
7960     }
7961     case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
7962     case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
7963       SloppyArgumentsElements* elements =
7964           SloppyArgumentsElements::cast(this->elements());
7965       // Check the mapped parameters.
7966       for (uint32_t i = 0; i < elements->parameter_map_length(); ++i) {
7967         Object* value = elements->get_mapped_entry(i);
7968         if (!value->IsTheHole(heap->isolate()) && value == obj) return true;
7969       }
7970       // Check the arguments.
7971       FixedArray* arguments = elements->arguments();
7972       kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : HOLEY_ELEMENTS;
7973       if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
7974       break;
7975     }
7976     case NO_ELEMENTS:
7977       break;
7978   }
7979 
7980   // For functions check the context.
7981   if (IsJSFunction()) {
7982     // Get the constructor function for arguments array.
7983     Map* arguments_map =
7984         heap->isolate()->context()->native_context()->sloppy_arguments_map();
7985     JSFunction* arguments_function =
7986         JSFunction::cast(arguments_map->GetConstructor());
7987 
7988     // Get the context and don't check if it is the native context.
7989     JSFunction* f = JSFunction::cast(this);
7990     Context* context = f->context();
7991     if (context->IsNativeContext()) {
7992       return false;
7993     }
7994 
7995     // Check the non-special context slots.
7996     for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
7997       // Only check JS objects.
7998       if (context->get(i)->IsJSObject()) {
7999         JSObject* ctxobj = JSObject::cast(context->get(i));
8000         // If it is an arguments array check the content.
8001         if (ctxobj->map()->GetConstructor() == arguments_function) {
8002           if (ctxobj->ReferencesObject(obj)) {
8003             return true;
8004           }
8005         } else if (ctxobj == obj) {
8006           return true;
8007         }
8008       }
8009     }
8010 
8011     // Check the context extension (if any) if it can have references.
8012     if (context->has_extension() && !context->IsCatchContext() &&
8013         !context->IsModuleContext()) {
8014       // With harmony scoping, a JSFunction may have a script context.
8015       // TODO(mvstanton): walk into the ScopeInfo.
8016       if (context->IsScriptContext()) {
8017         return false;
8018       }
8019 
8020       return context->extension_object()->ReferencesObject(obj);
8021     }
8022   }
8023 
8024   // No references to object.
8025   return false;
8026 }
8027 
8028 
SetIntegrityLevel(Handle<JSReceiver> receiver,IntegrityLevel level,ShouldThrow should_throw)8029 Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver,
8030                                           IntegrityLevel level,
8031                                           ShouldThrow should_throw) {
8032   DCHECK(level == SEALED || level == FROZEN);
8033 
8034   if (receiver->IsJSObject()) {
8035     Handle<JSObject> object = Handle<JSObject>::cast(receiver);
8036 
8037     if (!object->HasSloppyArgumentsElements() &&
8038         !object->IsJSModuleNamespace()) {  // Fast path.
8039       // Prevent memory leaks by not adding unnecessary transitions.
8040       Maybe<bool> test = JSObject::TestIntegrityLevel(object, level);
8041       MAYBE_RETURN(test, Nothing<bool>());
8042       if (test.FromJust()) return test;
8043 
8044       if (level == SEALED) {
8045         return JSObject::PreventExtensionsWithTransition<SEALED>(object,
8046                                                                  should_throw);
8047       } else {
8048         return JSObject::PreventExtensionsWithTransition<FROZEN>(object,
8049                                                                  should_throw);
8050       }
8051     }
8052   }
8053 
8054   Isolate* isolate = receiver->GetIsolate();
8055 
8056   MAYBE_RETURN(JSReceiver::PreventExtensions(receiver, should_throw),
8057                Nothing<bool>());
8058 
8059   Handle<FixedArray> keys;
8060   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8061       isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>());
8062 
8063   PropertyDescriptor no_conf;
8064   no_conf.set_configurable(false);
8065 
8066   PropertyDescriptor no_conf_no_write;
8067   no_conf_no_write.set_configurable(false);
8068   no_conf_no_write.set_writable(false);
8069 
8070   if (level == SEALED) {
8071     for (int i = 0; i < keys->length(); ++i) {
8072       Handle<Object> key(keys->get(i), isolate);
8073       MAYBE_RETURN(
8074           DefineOwnProperty(isolate, receiver, key, &no_conf, kThrowOnError),
8075           Nothing<bool>());
8076     }
8077     return Just(true);
8078   }
8079 
8080   for (int i = 0; i < keys->length(); ++i) {
8081     Handle<Object> key(keys->get(i), isolate);
8082     PropertyDescriptor current_desc;
8083     Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
8084         isolate, receiver, key, &current_desc);
8085     MAYBE_RETURN(owned, Nothing<bool>());
8086     if (owned.FromJust()) {
8087       PropertyDescriptor desc =
8088           PropertyDescriptor::IsAccessorDescriptor(&current_desc)
8089               ? no_conf
8090               : no_conf_no_write;
8091       MAYBE_RETURN(
8092           DefineOwnProperty(isolate, receiver, key, &desc, kThrowOnError),
8093           Nothing<bool>());
8094     }
8095   }
8096   return Just(true);
8097 }
8098 
8099 namespace {
8100 
8101 template <typename Dictionary>
TestDictionaryPropertiesIntegrityLevel(Dictionary * dict,Isolate * isolate,PropertyAttributes level)8102 bool TestDictionaryPropertiesIntegrityLevel(Dictionary* dict, Isolate* isolate,
8103                                             PropertyAttributes level) {
8104   DCHECK(level == SEALED || level == FROZEN);
8105 
8106   uint32_t capacity = dict->Capacity();
8107   for (uint32_t i = 0; i < capacity; i++) {
8108     Object* key;
8109     if (!dict->ToKey(isolate, i, &key)) continue;
8110     if (key->FilterKey(ALL_PROPERTIES)) continue;
8111     PropertyDetails details = dict->DetailsAt(i);
8112     if (details.IsConfigurable()) return false;
8113     if (level == FROZEN && details.kind() == kData && !details.IsReadOnly()) {
8114       return false;
8115     }
8116   }
8117   return true;
8118 }
8119 
TestFastPropertiesIntegrityLevel(Map * map,PropertyAttributes level)8120 bool TestFastPropertiesIntegrityLevel(Map* map, PropertyAttributes level) {
8121   DCHECK(level == SEALED || level == FROZEN);
8122   DCHECK(!map->IsCustomElementsReceiverMap());
8123   DCHECK(!map->is_dictionary_map());
8124 
8125   DescriptorArray* descriptors = map->instance_descriptors();
8126   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
8127   for (int i = 0; i < number_of_own_descriptors; i++) {
8128     if (descriptors->GetKey(i)->IsPrivate()) continue;
8129     PropertyDetails details = descriptors->GetDetails(i);
8130     if (details.IsConfigurable()) return false;
8131     if (level == FROZEN && details.kind() == kData && !details.IsReadOnly()) {
8132       return false;
8133     }
8134   }
8135   return true;
8136 }
8137 
TestPropertiesIntegrityLevel(JSObject * object,PropertyAttributes level)8138 bool TestPropertiesIntegrityLevel(JSObject* object, PropertyAttributes level) {
8139   DCHECK(!object->map()->IsCustomElementsReceiverMap());
8140 
8141   if (object->HasFastProperties()) {
8142     return TestFastPropertiesIntegrityLevel(object->map(), level);
8143   }
8144 
8145   return TestDictionaryPropertiesIntegrityLevel(object->property_dictionary(),
8146                                                 object->GetIsolate(), level);
8147 }
8148 
TestElementsIntegrityLevel(JSObject * object,PropertyAttributes level)8149 bool TestElementsIntegrityLevel(JSObject* object, PropertyAttributes level) {
8150   DCHECK(!object->HasSloppyArgumentsElements());
8151 
8152   ElementsKind kind = object->GetElementsKind();
8153 
8154   if (IsDictionaryElementsKind(kind)) {
8155     return TestDictionaryPropertiesIntegrityLevel(
8156         NumberDictionary::cast(object->elements()), object->GetIsolate(),
8157         level);
8158   }
8159 
8160   ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
8161   // Only DICTIONARY_ELEMENTS and SLOW_SLOPPY_ARGUMENTS_ELEMENTS have
8162   // PropertyAttributes so just test if empty
8163   return accessor->NumberOfElements(object) == 0;
8164 }
8165 
FastTestIntegrityLevel(JSObject * object,PropertyAttributes level)8166 bool FastTestIntegrityLevel(JSObject* object, PropertyAttributes level) {
8167   DCHECK(!object->map()->IsCustomElementsReceiverMap());
8168 
8169   return !object->map()->is_extensible() &&
8170          TestElementsIntegrityLevel(object, level) &&
8171          TestPropertiesIntegrityLevel(object, level);
8172 }
8173 
GenericTestIntegrityLevel(Handle<JSReceiver> receiver,PropertyAttributes level)8174 Maybe<bool> GenericTestIntegrityLevel(Handle<JSReceiver> receiver,
8175                                       PropertyAttributes level) {
8176   DCHECK(level == SEALED || level == FROZEN);
8177 
8178   Maybe<bool> extensible = JSReceiver::IsExtensible(receiver);
8179   MAYBE_RETURN(extensible, Nothing<bool>());
8180   if (extensible.FromJust()) return Just(false);
8181 
8182   Isolate* isolate = receiver->GetIsolate();
8183 
8184   Handle<FixedArray> keys;
8185   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8186       isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>());
8187 
8188   for (int i = 0; i < keys->length(); ++i) {
8189     Handle<Object> key(keys->get(i), isolate);
8190     PropertyDescriptor current_desc;
8191     Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
8192         isolate, receiver, key, &current_desc);
8193     MAYBE_RETURN(owned, Nothing<bool>());
8194     if (owned.FromJust()) {
8195       if (current_desc.configurable()) return Just(false);
8196       if (level == FROZEN &&
8197           PropertyDescriptor::IsDataDescriptor(&current_desc) &&
8198           current_desc.writable()) {
8199         return Just(false);
8200       }
8201     }
8202   }
8203   return Just(true);
8204 }
8205 
8206 }  // namespace
8207 
TestIntegrityLevel(Handle<JSReceiver> receiver,IntegrityLevel level)8208 Maybe<bool> JSReceiver::TestIntegrityLevel(Handle<JSReceiver> receiver,
8209                                            IntegrityLevel level) {
8210   if (!receiver->map()->IsCustomElementsReceiverMap()) {
8211     return JSObject::TestIntegrityLevel(Handle<JSObject>::cast(receiver),
8212                                         level);
8213   }
8214   return GenericTestIntegrityLevel(receiver, level);
8215 }
8216 
TestIntegrityLevel(Handle<JSObject> object,IntegrityLevel level)8217 Maybe<bool> JSObject::TestIntegrityLevel(Handle<JSObject> object,
8218                                          IntegrityLevel level) {
8219   if (!object->map()->IsCustomElementsReceiverMap() &&
8220       !object->HasSloppyArgumentsElements()) {
8221     return Just(FastTestIntegrityLevel(*object, level));
8222   }
8223   return GenericTestIntegrityLevel(Handle<JSReceiver>::cast(object), level);
8224 }
8225 
PreventExtensions(Handle<JSReceiver> object,ShouldThrow should_throw)8226 Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object,
8227                                           ShouldThrow should_throw) {
8228   if (object->IsJSProxy()) {
8229     return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object),
8230                                       should_throw);
8231   }
8232   DCHECK(object->IsJSObject());
8233   return JSObject::PreventExtensions(Handle<JSObject>::cast(object),
8234                                      should_throw);
8235 }
8236 
8237 
PreventExtensions(Handle<JSProxy> proxy,ShouldThrow should_throw)8238 Maybe<bool> JSProxy::PreventExtensions(Handle<JSProxy> proxy,
8239                                        ShouldThrow should_throw) {
8240   Isolate* isolate = proxy->GetIsolate();
8241   STACK_CHECK(isolate, Nothing<bool>());
8242   Factory* factory = isolate->factory();
8243   Handle<String> trap_name = factory->preventExtensions_string();
8244 
8245   if (proxy->IsRevoked()) {
8246     isolate->Throw(
8247         *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
8248     return Nothing<bool>();
8249   }
8250   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
8251   Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
8252 
8253   Handle<Object> trap;
8254   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8255       isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
8256   if (trap->IsUndefined(isolate)) {
8257     return JSReceiver::PreventExtensions(target, should_throw);
8258   }
8259 
8260   Handle<Object> trap_result;
8261   Handle<Object> args[] = {target};
8262   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8263       isolate, trap_result,
8264       Execution::Call(isolate, trap, handler, arraysize(args), args),
8265       Nothing<bool>());
8266   if (!trap_result->BooleanValue()) {
8267     RETURN_FAILURE(
8268         isolate, should_throw,
8269         NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
8270   }
8271 
8272   // Enforce the invariant.
8273   Maybe<bool> target_result = JSReceiver::IsExtensible(target);
8274   MAYBE_RETURN(target_result, Nothing<bool>());
8275   if (target_result.FromJust()) {
8276     isolate->Throw(*factory->NewTypeError(
8277         MessageTemplate::kProxyPreventExtensionsExtensible));
8278     return Nothing<bool>();
8279   }
8280   return Just(true);
8281 }
8282 
8283 
PreventExtensions(Handle<JSObject> object,ShouldThrow should_throw)8284 Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object,
8285                                         ShouldThrow should_throw) {
8286   Isolate* isolate = object->GetIsolate();
8287 
8288   if (!object->HasSloppyArgumentsElements()) {
8289     return PreventExtensionsWithTransition<NONE>(object, should_throw);
8290   }
8291 
8292   if (object->IsAccessCheckNeeded() &&
8293       !isolate->MayAccess(handle(isolate->context()), object)) {
8294     isolate->ReportFailedAccessCheck(object);
8295     RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
8296     RETURN_FAILURE(isolate, should_throw,
8297                    NewTypeError(MessageTemplate::kNoAccess));
8298   }
8299 
8300   if (!object->map()->is_extensible()) return Just(true);
8301 
8302   if (object->IsJSGlobalProxy()) {
8303     PrototypeIterator iter(isolate, object);
8304     if (iter.IsAtEnd()) return Just(true);
8305     DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
8306     return PreventExtensions(PrototypeIterator::GetCurrent<JSObject>(iter),
8307                              should_throw);
8308   }
8309 
8310   if (object->map()->has_named_interceptor() ||
8311       object->map()->has_indexed_interceptor()) {
8312     RETURN_FAILURE(isolate, should_throw,
8313                    NewTypeError(MessageTemplate::kCannotPreventExt));
8314   }
8315 
8316   if (!object->HasFixedTypedArrayElements()) {
8317     // If there are fast elements we normalize.
8318     Handle<NumberDictionary> dictionary = NormalizeElements(object);
8319     DCHECK(object->HasDictionaryElements() ||
8320            object->HasSlowArgumentsElements());
8321 
8322     // Make sure that we never go back to fast case.
8323     object->RequireSlowElements(*dictionary);
8324   }
8325 
8326   // Do a map transition, other objects with this map may still
8327   // be extensible.
8328   // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
8329   Handle<Map> new_map = Map::Copy(handle(object->map()), "PreventExtensions");
8330 
8331   new_map->set_is_extensible(false);
8332   JSObject::MigrateToMap(object, new_map);
8333   DCHECK(!object->map()->is_extensible());
8334 
8335   return Just(true);
8336 }
8337 
8338 
IsExtensible(Handle<JSReceiver> object)8339 Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) {
8340   if (object->IsJSProxy()) {
8341     return JSProxy::IsExtensible(Handle<JSProxy>::cast(object));
8342   }
8343   return Just(JSObject::IsExtensible(Handle<JSObject>::cast(object)));
8344 }
8345 
8346 
IsExtensible(Handle<JSProxy> proxy)8347 Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) {
8348   Isolate* isolate = proxy->GetIsolate();
8349   STACK_CHECK(isolate, Nothing<bool>());
8350   Factory* factory = isolate->factory();
8351   Handle<String> trap_name = factory->isExtensible_string();
8352 
8353   if (proxy->IsRevoked()) {
8354     isolate->Throw(
8355         *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
8356     return Nothing<bool>();
8357   }
8358   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
8359   Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
8360 
8361   Handle<Object> trap;
8362   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8363       isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
8364   if (trap->IsUndefined(isolate)) {
8365     return JSReceiver::IsExtensible(target);
8366   }
8367 
8368   Handle<Object> trap_result;
8369   Handle<Object> args[] = {target};
8370   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8371       isolate, trap_result,
8372       Execution::Call(isolate, trap, handler, arraysize(args), args),
8373       Nothing<bool>());
8374 
8375   // Enforce the invariant.
8376   Maybe<bool> target_result = JSReceiver::IsExtensible(target);
8377   MAYBE_RETURN(target_result, Nothing<bool>());
8378   if (target_result.FromJust() != trap_result->BooleanValue()) {
8379     isolate->Throw(
8380         *factory->NewTypeError(MessageTemplate::kProxyIsExtensibleInconsistent,
8381                                factory->ToBoolean(target_result.FromJust())));
8382     return Nothing<bool>();
8383   }
8384   return target_result;
8385 }
8386 
8387 
IsExtensible(Handle<JSObject> object)8388 bool JSObject::IsExtensible(Handle<JSObject> object) {
8389   Isolate* isolate = object->GetIsolate();
8390   if (object->IsAccessCheckNeeded() &&
8391       !isolate->MayAccess(handle(isolate->context()), object)) {
8392     return true;
8393   }
8394   if (object->IsJSGlobalProxy()) {
8395     PrototypeIterator iter(isolate, *object);
8396     if (iter.IsAtEnd()) return false;
8397     DCHECK(iter.GetCurrent()->IsJSGlobalObject());
8398     return iter.GetCurrent<JSObject>()->map()->is_extensible();
8399   }
8400   return object->map()->is_extensible();
8401 }
8402 
8403 namespace {
8404 
8405 template <typename Dictionary>
ApplyAttributesToDictionary(Isolate * isolate,Handle<Dictionary> dictionary,const PropertyAttributes attributes)8406 void ApplyAttributesToDictionary(Isolate* isolate,
8407                                  Handle<Dictionary> dictionary,
8408                                  const PropertyAttributes attributes) {
8409   int capacity = dictionary->Capacity();
8410   for (int i = 0; i < capacity; i++) {
8411     Object* k;
8412     if (!dictionary->ToKey(isolate, i, &k)) continue;
8413     if (k->FilterKey(ALL_PROPERTIES)) continue;
8414     PropertyDetails details = dictionary->DetailsAt(i);
8415     int attrs = attributes;
8416     // READ_ONLY is an invalid attribute for JS setters/getters.
8417     if ((attributes & READ_ONLY) && details.kind() == kAccessor) {
8418       Object* v = dictionary->ValueAt(i);
8419       if (v->IsAccessorPair()) attrs &= ~READ_ONLY;
8420     }
8421     details = details.CopyAddAttributes(static_cast<PropertyAttributes>(attrs));
8422     dictionary->DetailsAtPut(i, details);
8423   }
8424 }
8425 
8426 }  // namespace
8427 
8428 template <PropertyAttributes attrs>
PreventExtensionsWithTransition(Handle<JSObject> object,ShouldThrow should_throw)8429 Maybe<bool> JSObject::PreventExtensionsWithTransition(
8430     Handle<JSObject> object, ShouldThrow should_throw) {
8431   STATIC_ASSERT(attrs == NONE || attrs == SEALED || attrs == FROZEN);
8432 
8433   // Sealing/freezing sloppy arguments or namespace objects should be handled
8434   // elsewhere.
8435   DCHECK(!object->HasSloppyArgumentsElements());
8436   DCHECK_IMPLIES(object->IsJSModuleNamespace(), attrs == NONE);
8437 
8438   Isolate* isolate = object->GetIsolate();
8439   if (object->IsAccessCheckNeeded() &&
8440       !isolate->MayAccess(handle(isolate->context()), object)) {
8441     isolate->ReportFailedAccessCheck(object);
8442     RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
8443     RETURN_FAILURE(isolate, should_throw,
8444                    NewTypeError(MessageTemplate::kNoAccess));
8445   }
8446 
8447   if (attrs == NONE && !object->map()->is_extensible()) return Just(true);
8448 
8449   if (object->IsJSGlobalProxy()) {
8450     PrototypeIterator iter(isolate, object);
8451     if (iter.IsAtEnd()) return Just(true);
8452     DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
8453     return PreventExtensionsWithTransition<attrs>(
8454         PrototypeIterator::GetCurrent<JSObject>(iter), should_throw);
8455   }
8456 
8457   if (object->map()->has_named_interceptor() ||
8458       object->map()->has_indexed_interceptor()) {
8459     MessageTemplate::Template message = MessageTemplate::kNone;
8460     switch (attrs) {
8461       case NONE:
8462         message = MessageTemplate::kCannotPreventExt;
8463         break;
8464 
8465       case SEALED:
8466         message = MessageTemplate::kCannotSeal;
8467         break;
8468 
8469       case FROZEN:
8470         message = MessageTemplate::kCannotFreeze;
8471         break;
8472     }
8473     RETURN_FAILURE(isolate, should_throw, NewTypeError(message));
8474   }
8475 
8476   Handle<NumberDictionary> new_element_dictionary;
8477   if (!object->HasFixedTypedArrayElements() &&
8478       !object->HasDictionaryElements() &&
8479       !object->HasSlowStringWrapperElements()) {
8480     int length = object->IsJSArray()
8481                      ? Smi::ToInt(Handle<JSArray>::cast(object)->length())
8482                      : object->elements()->length();
8483     new_element_dictionary =
8484         length == 0 ? isolate->factory()->empty_slow_element_dictionary()
8485                     : object->GetElementsAccessor()->Normalize(object);
8486   }
8487 
8488   Handle<Symbol> transition_marker;
8489   if (attrs == NONE) {
8490     transition_marker = isolate->factory()->nonextensible_symbol();
8491   } else if (attrs == SEALED) {
8492     transition_marker = isolate->factory()->sealed_symbol();
8493   } else {
8494     DCHECK(attrs == FROZEN);
8495     transition_marker = isolate->factory()->frozen_symbol();
8496   }
8497 
8498   Handle<Map> old_map(object->map(), isolate);
8499   TransitionsAccessor transitions(old_map);
8500   Map* transition = transitions.SearchSpecial(*transition_marker);
8501   if (transition != nullptr) {
8502     Handle<Map> transition_map(transition, isolate);
8503     DCHECK(transition_map->has_dictionary_elements() ||
8504            transition_map->has_fixed_typed_array_elements() ||
8505            transition_map->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
8506     DCHECK(!transition_map->is_extensible());
8507     JSObject::MigrateToMap(object, transition_map);
8508   } else if (transitions.CanHaveMoreTransitions()) {
8509     // Create a new descriptor array with the appropriate property attributes
8510     Handle<Map> new_map = Map::CopyForPreventExtensions(
8511         old_map, attrs, transition_marker, "CopyForPreventExtensions");
8512     JSObject::MigrateToMap(object, new_map);
8513   } else {
8514     DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map());
8515     // Slow path: need to normalize properties for safety
8516     NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0,
8517                         "SlowPreventExtensions");
8518 
8519     // Create a new map, since other objects with this map may be extensible.
8520     // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
8521     Handle<Map> new_map =
8522         Map::Copy(handle(object->map()), "SlowCopyForPreventExtensions");
8523     new_map->set_is_extensible(false);
8524     if (!new_element_dictionary.is_null()) {
8525       ElementsKind new_kind =
8526           IsStringWrapperElementsKind(old_map->elements_kind())
8527               ? SLOW_STRING_WRAPPER_ELEMENTS
8528               : DICTIONARY_ELEMENTS;
8529       new_map->set_elements_kind(new_kind);
8530     }
8531     JSObject::MigrateToMap(object, new_map);
8532 
8533     if (attrs != NONE) {
8534       if (object->IsJSGlobalObject()) {
8535         Handle<GlobalDictionary> dictionary(
8536             JSGlobalObject::cast(*object)->global_dictionary(), isolate);
8537         ApplyAttributesToDictionary(isolate, dictionary, attrs);
8538       } else {
8539         Handle<NameDictionary> dictionary(object->property_dictionary(),
8540                                           isolate);
8541         ApplyAttributesToDictionary(isolate, dictionary, attrs);
8542       }
8543     }
8544   }
8545 
8546   // Both seal and preventExtensions always go through without modifications to
8547   // typed array elements. Freeze works only if there are no actual elements.
8548   if (object->HasFixedTypedArrayElements()) {
8549     if (attrs == FROZEN &&
8550         JSArrayBufferView::cast(*object)->byte_length()->Number() > 0) {
8551       isolate->Throw(*isolate->factory()->NewTypeError(
8552           MessageTemplate::kCannotFreezeArrayBufferView));
8553       return Nothing<bool>();
8554     }
8555     return Just(true);
8556   }
8557 
8558   DCHECK(object->map()->has_dictionary_elements() ||
8559          object->map()->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
8560   if (!new_element_dictionary.is_null()) {
8561     object->set_elements(*new_element_dictionary);
8562   }
8563 
8564   if (object->elements() != isolate->heap()->empty_slow_element_dictionary()) {
8565     Handle<NumberDictionary> dictionary(object->element_dictionary(), isolate);
8566     // Make sure we never go back to the fast case
8567     object->RequireSlowElements(*dictionary);
8568     if (attrs != NONE) {
8569       ApplyAttributesToDictionary(isolate, dictionary, attrs);
8570     }
8571   }
8572 
8573   return Just(true);
8574 }
8575 
8576 
FastPropertyAt(Handle<JSObject> object,Representation representation,FieldIndex index)8577 Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object,
8578                                         Representation representation,
8579                                         FieldIndex index) {
8580   Isolate* isolate = object->GetIsolate();
8581   if (object->IsUnboxedDoubleField(index)) {
8582     double value = object->RawFastDoublePropertyAt(index);
8583     return isolate->factory()->NewHeapNumber(value);
8584   }
8585   Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate);
8586   return Object::WrapForRead(isolate, raw_value, representation);
8587 }
8588 
8589 // static
ToPrimitive(Handle<JSReceiver> receiver,ToPrimitiveHint hint)8590 MaybeHandle<Object> JSReceiver::ToPrimitive(Handle<JSReceiver> receiver,
8591                                             ToPrimitiveHint hint) {
8592   Isolate* const isolate = receiver->GetIsolate();
8593   Handle<Object> exotic_to_prim;
8594   ASSIGN_RETURN_ON_EXCEPTION(
8595       isolate, exotic_to_prim,
8596       GetMethod(receiver, isolate->factory()->to_primitive_symbol()), Object);
8597   if (!exotic_to_prim->IsUndefined(isolate)) {
8598     Handle<Object> hint_string =
8599         isolate->factory()->ToPrimitiveHintString(hint);
8600     Handle<Object> result;
8601     ASSIGN_RETURN_ON_EXCEPTION(
8602         isolate, result,
8603         Execution::Call(isolate, exotic_to_prim, receiver, 1, &hint_string),
8604         Object);
8605     if (result->IsPrimitive()) return result;
8606     THROW_NEW_ERROR(isolate,
8607                     NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8608                     Object);
8609   }
8610   return OrdinaryToPrimitive(receiver, (hint == ToPrimitiveHint::kString)
8611                                            ? OrdinaryToPrimitiveHint::kString
8612                                            : OrdinaryToPrimitiveHint::kNumber);
8613 }
8614 
8615 
8616 // static
OrdinaryToPrimitive(Handle<JSReceiver> receiver,OrdinaryToPrimitiveHint hint)8617 MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive(
8618     Handle<JSReceiver> receiver, OrdinaryToPrimitiveHint hint) {
8619   Isolate* const isolate = receiver->GetIsolate();
8620   Handle<String> method_names[2];
8621   switch (hint) {
8622     case OrdinaryToPrimitiveHint::kNumber:
8623       method_names[0] = isolate->factory()->valueOf_string();
8624       method_names[1] = isolate->factory()->toString_string();
8625       break;
8626     case OrdinaryToPrimitiveHint::kString:
8627       method_names[0] = isolate->factory()->toString_string();
8628       method_names[1] = isolate->factory()->valueOf_string();
8629       break;
8630   }
8631   for (Handle<String> name : method_names) {
8632     Handle<Object> method;
8633     ASSIGN_RETURN_ON_EXCEPTION(isolate, method,
8634                                JSReceiver::GetProperty(receiver, name), Object);
8635     if (method->IsCallable()) {
8636       Handle<Object> result;
8637       ASSIGN_RETURN_ON_EXCEPTION(
8638           isolate, result,
8639           Execution::Call(isolate, method, receiver, 0, nullptr), Object);
8640       if (result->IsPrimitive()) return result;
8641     }
8642   }
8643   THROW_NEW_ERROR(isolate,
8644                   NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8645                   Object);
8646 }
8647 
8648 
8649 // TODO(cbruni/jkummerow): Consider moving this into elements.cc.
HasEnumerableElements()8650 bool JSObject::HasEnumerableElements() {
8651   // TODO(cbruni): cleanup
8652   JSObject* object = this;
8653   switch (object->GetElementsKind()) {
8654     case PACKED_SMI_ELEMENTS:
8655     case PACKED_ELEMENTS:
8656     case PACKED_DOUBLE_ELEMENTS: {
8657       int length = object->IsJSArray()
8658                        ? Smi::ToInt(JSArray::cast(object)->length())
8659                        : object->elements()->length();
8660       return length > 0;
8661     }
8662     case HOLEY_SMI_ELEMENTS:
8663     case HOLEY_ELEMENTS: {
8664       FixedArray* elements = FixedArray::cast(object->elements());
8665       int length = object->IsJSArray()
8666                        ? Smi::ToInt(JSArray::cast(object)->length())
8667                        : elements->length();
8668       Isolate* isolate = GetIsolate();
8669       for (int i = 0; i < length; i++) {
8670         if (!elements->is_the_hole(isolate, i)) return true;
8671       }
8672       return false;
8673     }
8674     case HOLEY_DOUBLE_ELEMENTS: {
8675       int length = object->IsJSArray()
8676                        ? Smi::ToInt(JSArray::cast(object)->length())
8677                        : object->elements()->length();
8678       // Zero-length arrays would use the empty FixedArray...
8679       if (length == 0) return false;
8680       // ...so only cast to FixedDoubleArray otherwise.
8681       FixedDoubleArray* elements = FixedDoubleArray::cast(object->elements());
8682       for (int i = 0; i < length; i++) {
8683         if (!elements->is_the_hole(i)) return true;
8684       }
8685       return false;
8686     }
8687 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
8688     case TYPE##_ELEMENTS:
8689 
8690       TYPED_ARRAYS(TYPED_ARRAY_CASE)
8691 #undef TYPED_ARRAY_CASE
8692       {
8693         int length = object->elements()->length();
8694         return length > 0;
8695       }
8696     case DICTIONARY_ELEMENTS: {
8697       NumberDictionary* elements = NumberDictionary::cast(object->elements());
8698       return elements->NumberOfEnumerableProperties() > 0;
8699     }
8700     case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
8701     case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
8702       // We're approximating non-empty arguments objects here.
8703       return true;
8704     case FAST_STRING_WRAPPER_ELEMENTS:
8705     case SLOW_STRING_WRAPPER_ELEMENTS:
8706       if (String::cast(JSValue::cast(object)->value())->length() > 0) {
8707         return true;
8708       }
8709       return object->elements()->length() > 0;
8710     case NO_ELEMENTS:
8711       return false;
8712   }
8713   UNREACHABLE();
8714 }
8715 
NumberOfEnumerableProperties() const8716 int Map::NumberOfEnumerableProperties() const {
8717   int result = 0;
8718   DescriptorArray* descs = instance_descriptors();
8719   int limit = NumberOfOwnDescriptors();
8720   for (int i = 0; i < limit; i++) {
8721     if ((descs->GetDetails(i).attributes() & ONLY_ENUMERABLE) == 0 &&
8722         !descs->GetKey(i)->FilterKey(ENUMERABLE_STRINGS)) {
8723       result++;
8724     }
8725   }
8726   return result;
8727 }
8728 
NextFreePropertyIndex() const8729 int Map::NextFreePropertyIndex() const {
8730   int free_index = 0;
8731   int number_of_own_descriptors = NumberOfOwnDescriptors();
8732   DescriptorArray* descs = instance_descriptors();
8733   for (int i = 0; i < number_of_own_descriptors; i++) {
8734     PropertyDetails details = descs->GetDetails(i);
8735     if (details.location() == kField) {
8736       int candidate = details.field_index() + details.field_width_in_words();
8737       if (candidate > free_index) free_index = candidate;
8738     }
8739   }
8740   return free_index;
8741 }
8742 
OnlyHasSimpleProperties() const8743 bool Map::OnlyHasSimpleProperties() const {
8744   // Wrapped string elements aren't explicitly stored in the elements backing
8745   // store, but are loaded indirectly from the underlying string.
8746   return !IsStringWrapperElementsKind(elements_kind()) &&
8747          !IsSpecialReceiverMap() && !has_hidden_prototype() &&
8748          !is_dictionary_map();
8749 }
8750 
FastGetOwnValuesOrEntries(Isolate * isolate,Handle<JSReceiver> receiver,bool get_entries,Handle<FixedArray> * result)8751 V8_WARN_UNUSED_RESULT Maybe<bool> FastGetOwnValuesOrEntries(
8752     Isolate* isolate, Handle<JSReceiver> receiver, bool get_entries,
8753     Handle<FixedArray>* result) {
8754   Handle<Map> map(JSReceiver::cast(*receiver)->map(), isolate);
8755 
8756   if (!map->IsJSObjectMap()) return Just(false);
8757   if (!map->OnlyHasSimpleProperties()) return Just(false);
8758 
8759   Handle<JSObject> object(JSObject::cast(*receiver));
8760 
8761   Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
8762   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
8763   int number_of_own_elements =
8764       object->GetElementsAccessor()->GetCapacity(*object, object->elements());
8765   Handle<FixedArray> values_or_entries = isolate->factory()->NewFixedArray(
8766       number_of_own_descriptors + number_of_own_elements);
8767   int count = 0;
8768 
8769   if (object->elements() != isolate->heap()->empty_fixed_array()) {
8770     MAYBE_RETURN(object->GetElementsAccessor()->CollectValuesOrEntries(
8771                      isolate, object, values_or_entries, get_entries, &count,
8772                      ENUMERABLE_STRINGS),
8773                  Nothing<bool>());
8774   }
8775 
8776   bool stable = object->map() == *map;
8777 
8778   for (int index = 0; index < number_of_own_descriptors; index++) {
8779     Handle<Name> next_key(descriptors->GetKey(index), isolate);
8780     if (!next_key->IsString()) continue;
8781     Handle<Object> prop_value;
8782 
8783     // Directly decode from the descriptor array if |from| did not change shape.
8784     if (stable) {
8785       PropertyDetails details = descriptors->GetDetails(index);
8786       if (!details.IsEnumerable()) continue;
8787       if (details.kind() == kData) {
8788         if (details.location() == kDescriptor) {
8789           prop_value = handle(descriptors->GetValue(index), isolate);
8790         } else {
8791           Representation representation = details.representation();
8792           FieldIndex field_index = FieldIndex::ForDescriptor(*map, index);
8793           prop_value =
8794               JSObject::FastPropertyAt(object, representation, field_index);
8795         }
8796       } else {
8797         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8798             isolate, prop_value, JSReceiver::GetProperty(object, next_key),
8799             Nothing<bool>());
8800         stable = object->map() == *map;
8801       }
8802     } else {
8803       // If the map did change, do a slower lookup. We are still guaranteed that
8804       // the object has a simple shape, and that the key is a name.
8805       LookupIterator it(object, next_key, LookupIterator::OWN_SKIP_INTERCEPTOR);
8806       if (!it.IsFound()) continue;
8807       DCHECK(it.state() == LookupIterator::DATA ||
8808              it.state() == LookupIterator::ACCESSOR);
8809       if (!it.IsEnumerable()) continue;
8810       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8811           isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
8812     }
8813 
8814     if (get_entries) {
8815       prop_value = MakeEntryPair(isolate, next_key, prop_value);
8816     }
8817 
8818     values_or_entries->set(count, *prop_value);
8819     count++;
8820   }
8821 
8822   if (count < values_or_entries->length()) values_or_entries->Shrink(count);
8823   *result = values_or_entries;
8824   return Just(true);
8825 }
8826 
GetOwnValuesOrEntries(Isolate * isolate,Handle<JSReceiver> object,PropertyFilter filter,bool try_fast_path,bool get_entries)8827 MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate,
8828                                               Handle<JSReceiver> object,
8829                                               PropertyFilter filter,
8830                                               bool try_fast_path,
8831                                               bool get_entries) {
8832   Handle<FixedArray> values_or_entries;
8833   if (try_fast_path && filter == ENUMERABLE_STRINGS) {
8834     Maybe<bool> fast_values_or_entries = FastGetOwnValuesOrEntries(
8835         isolate, object, get_entries, &values_or_entries);
8836     if (fast_values_or_entries.IsNothing()) return MaybeHandle<FixedArray>();
8837     if (fast_values_or_entries.FromJust()) return values_or_entries;
8838   }
8839 
8840   PropertyFilter key_filter =
8841       static_cast<PropertyFilter>(filter & ~ONLY_ENUMERABLE);
8842 
8843   Handle<FixedArray> keys;
8844   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8845       isolate, keys,
8846       KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, key_filter,
8847                               GetKeysConversion::kConvertToString),
8848       MaybeHandle<FixedArray>());
8849 
8850   values_or_entries = isolate->factory()->NewFixedArray(keys->length());
8851   int length = 0;
8852 
8853   for (int i = 0; i < keys->length(); ++i) {
8854     Handle<Name> key = Handle<Name>::cast(handle(keys->get(i), isolate));
8855 
8856     if (filter & ONLY_ENUMERABLE) {
8857       PropertyDescriptor descriptor;
8858       Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor(
8859           isolate, object, key, &descriptor);
8860       MAYBE_RETURN(did_get_descriptor, MaybeHandle<FixedArray>());
8861       if (!did_get_descriptor.FromJust() || !descriptor.enumerable()) continue;
8862     }
8863 
8864     Handle<Object> value;
8865     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8866         isolate, value, JSReceiver::GetPropertyOrElement(object, key),
8867         MaybeHandle<FixedArray>());
8868 
8869     if (get_entries) {
8870       Handle<FixedArray> entry_storage =
8871           isolate->factory()->NewUninitializedFixedArray(2);
8872       entry_storage->set(0, *key);
8873       entry_storage->set(1, *value);
8874       value = isolate->factory()->NewJSArrayWithElements(entry_storage,
8875                                                          PACKED_ELEMENTS, 2);
8876     }
8877 
8878     values_or_entries->set(length, *value);
8879     length++;
8880   }
8881   if (length < values_or_entries->length()) values_or_entries->Shrink(length);
8882   return values_or_entries;
8883 }
8884 
GetOwnValues(Handle<JSReceiver> object,PropertyFilter filter,bool try_fast_path)8885 MaybeHandle<FixedArray> JSReceiver::GetOwnValues(Handle<JSReceiver> object,
8886                                                  PropertyFilter filter,
8887                                                  bool try_fast_path) {
8888   return GetOwnValuesOrEntries(object->GetIsolate(), object, filter,
8889                                try_fast_path, false);
8890 }
8891 
GetOwnEntries(Handle<JSReceiver> object,PropertyFilter filter,bool try_fast_path)8892 MaybeHandle<FixedArray> JSReceiver::GetOwnEntries(Handle<JSReceiver> object,
8893                                                   PropertyFilter filter,
8894                                                   bool try_fast_path) {
8895   return GetOwnValuesOrEntries(object->GetIsolate(), object, filter,
8896                                try_fast_path, true);
8897 }
8898 
GetOwnElementIndices(Isolate * isolate,Handle<JSReceiver> receiver,Handle<JSObject> object)8899 Handle<FixedArray> JSReceiver::GetOwnElementIndices(Isolate* isolate,
8900                                                     Handle<JSReceiver> receiver,
8901                                                     Handle<JSObject> object) {
8902   KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly,
8903                              ALL_PROPERTIES);
8904   accumulator.CollectOwnElementIndices(receiver, object);
8905   Handle<FixedArray> keys =
8906       accumulator.GetKeys(GetKeysConversion::kKeepNumbers);
8907   DCHECK(keys->ContainsSortedNumbers());
8908   return keys;
8909 }
8910 
DictionaryElementsInPrototypeChainOnly()8911 bool Map::DictionaryElementsInPrototypeChainOnly() {
8912   if (IsDictionaryElementsKind(elements_kind())) {
8913     return false;
8914   }
8915 
8916   for (PrototypeIterator iter(this); !iter.IsAtEnd(); iter.Advance()) {
8917     // Be conservative, don't walk into proxies.
8918     if (iter.GetCurrent()->IsJSProxy()) return true;
8919     // String wrappers have non-configurable, non-writable elements.
8920     if (iter.GetCurrent()->IsStringWrapper()) return true;
8921     JSObject* current = iter.GetCurrent<JSObject>();
8922 
8923     if (current->HasDictionaryElements() &&
8924         current->element_dictionary()->requires_slow_elements()) {
8925       return true;
8926     }
8927 
8928     if (current->HasSlowArgumentsElements()) {
8929       FixedArray* parameter_map = FixedArray::cast(current->elements());
8930       Object* arguments = parameter_map->get(1);
8931       if (NumberDictionary::cast(arguments)->requires_slow_elements()) {
8932         return true;
8933       }
8934     }
8935   }
8936 
8937   return false;
8938 }
8939 
8940 
DefineAccessor(Handle<JSObject> object,Handle<Name> name,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)8941 MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
8942                                              Handle<Name> name,
8943                                              Handle<Object> getter,
8944                                              Handle<Object> setter,
8945                                              PropertyAttributes attributes) {
8946   Isolate* isolate = object->GetIsolate();
8947 
8948   LookupIterator it = LookupIterator::PropertyOrElement(
8949       isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
8950   return DefineAccessor(&it, getter, setter, attributes);
8951 }
8952 
8953 
DefineAccessor(LookupIterator * it,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)8954 MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it,
8955                                              Handle<Object> getter,
8956                                              Handle<Object> setter,
8957                                              PropertyAttributes attributes) {
8958   Isolate* isolate = it->isolate();
8959 
8960   it->UpdateProtector();
8961 
8962   if (it->state() == LookupIterator::ACCESS_CHECK) {
8963     if (!it->HasAccess()) {
8964       isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
8965       RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
8966       return isolate->factory()->undefined_value();
8967     }
8968     it->Next();
8969   }
8970 
8971   Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
8972   // Ignore accessors on typed arrays.
8973   if (it->IsElement() && object->HasFixedTypedArrayElements()) {
8974     return it->factory()->undefined_value();
8975   }
8976 
8977   DCHECK(getter->IsCallable() || getter->IsUndefined(isolate) ||
8978          getter->IsNull(isolate) || getter->IsFunctionTemplateInfo());
8979   DCHECK(setter->IsCallable() || setter->IsUndefined(isolate) ||
8980          setter->IsNull(isolate) || setter->IsFunctionTemplateInfo());
8981   it->TransitionToAccessorProperty(getter, setter, attributes);
8982 
8983   return isolate->factory()->undefined_value();
8984 }
8985 
SetAccessor(Handle<JSObject> object,Handle<Name> name,Handle<AccessorInfo> info,PropertyAttributes attributes)8986 MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
8987                                           Handle<Name> name,
8988                                           Handle<AccessorInfo> info,
8989                                           PropertyAttributes attributes) {
8990   Isolate* isolate = object->GetIsolate();
8991 
8992   LookupIterator it = LookupIterator::PropertyOrElement(
8993       isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
8994 
8995   // Duplicate ACCESS_CHECK outside of GetPropertyAttributes for the case that
8996   // the FailedAccessCheckCallbackFunction doesn't throw an exception.
8997   //
8998   // TODO(verwaest): Force throw an exception if the callback doesn't, so we can
8999   // remove reliance on default return values.
9000   if (it.state() == LookupIterator::ACCESS_CHECK) {
9001     if (!it.HasAccess()) {
9002       isolate->ReportFailedAccessCheck(object);
9003       RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
9004       return it.factory()->undefined_value();
9005     }
9006     it.Next();
9007   }
9008 
9009   // Ignore accessors on typed arrays.
9010   if (it.IsElement() && object->HasFixedTypedArrayElements()) {
9011     return it.factory()->undefined_value();
9012   }
9013 
9014   CHECK(GetPropertyAttributes(&it).IsJust());
9015 
9016   // ES5 forbids turning a property into an accessor if it's not
9017   // configurable. See 8.6.1 (Table 5).
9018   if (it.IsFound() && !it.IsConfigurable()) {
9019     return it.factory()->undefined_value();
9020   }
9021 
9022   it.TransitionToAccessorPair(info, attributes);
9023 
9024   return object;
9025 }
9026 
SlowReverseLookup(Object * value)9027 Object* JSObject::SlowReverseLookup(Object* value) {
9028   if (HasFastProperties()) {
9029     int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
9030     DescriptorArray* descs = map()->instance_descriptors();
9031     bool value_is_number = value->IsNumber();
9032     for (int i = 0; i < number_of_own_descriptors; i++) {
9033       PropertyDetails details = descs->GetDetails(i);
9034       if (details.location() == kField) {
9035         DCHECK_EQ(kData, details.kind());
9036         FieldIndex field_index = FieldIndex::ForDescriptor(map(), i);
9037         if (IsUnboxedDoubleField(field_index)) {
9038           if (value_is_number) {
9039             double property = RawFastDoublePropertyAt(field_index);
9040             if (property == value->Number()) {
9041               return descs->GetKey(i);
9042             }
9043           }
9044         } else {
9045           Object* property = RawFastPropertyAt(field_index);
9046           if (field_index.is_double()) {
9047             DCHECK(property->IsMutableHeapNumber());
9048             if (value_is_number && property->Number() == value->Number()) {
9049               return descs->GetKey(i);
9050             }
9051           } else if (property == value) {
9052             return descs->GetKey(i);
9053           }
9054         }
9055       } else {
9056         DCHECK_EQ(kDescriptor, details.location());
9057         if (details.kind() == kData) {
9058           if (descs->GetValue(i) == value) {
9059             return descs->GetKey(i);
9060           }
9061         }
9062       }
9063     }
9064     return GetHeap()->undefined_value();
9065   } else if (IsJSGlobalObject()) {
9066     return JSGlobalObject::cast(this)->global_dictionary()->SlowReverseLookup(
9067         value);
9068   } else {
9069     return property_dictionary()->SlowReverseLookup(value);
9070   }
9071 }
9072 
RawCopy(Handle<Map> map,int instance_size,int inobject_properties)9073 Handle<Map> Map::RawCopy(Handle<Map> map, int instance_size,
9074                          int inobject_properties) {
9075   Isolate* isolate = map->GetIsolate();
9076   Handle<Map> result = isolate->factory()->NewMap(
9077       map->instance_type(), instance_size, TERMINAL_FAST_ELEMENTS_KIND,
9078       inobject_properties);
9079   Handle<Object> prototype(map->prototype(), isolate);
9080   Map::SetPrototype(result, prototype);
9081   result->set_constructor_or_backpointer(map->GetConstructor());
9082   result->set_bit_field(map->bit_field());
9083   result->set_bit_field2(map->bit_field2());
9084   int new_bit_field3 = map->bit_field3();
9085   new_bit_field3 = OwnsDescriptorsBit::update(new_bit_field3, true);
9086   new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0);
9087   new_bit_field3 = EnumLengthBits::update(new_bit_field3,
9088                                           kInvalidEnumCacheSentinel);
9089   new_bit_field3 = IsDeprecatedBit::update(new_bit_field3, false);
9090   if (!map->is_dictionary_map()) {
9091     new_bit_field3 = IsUnstableBit::update(new_bit_field3, false);
9092   }
9093   result->set_bit_field3(new_bit_field3);
9094   return result;
9095 }
9096 
9097 
Normalize(Handle<Map> fast_map,PropertyNormalizationMode mode,const char * reason)9098 Handle<Map> Map::Normalize(Handle<Map> fast_map, PropertyNormalizationMode mode,
9099                            const char* reason) {
9100   DCHECK(!fast_map->is_dictionary_map());
9101 
9102   Isolate* isolate = fast_map->GetIsolate();
9103   Handle<Object> maybe_cache(isolate->native_context()->normalized_map_cache(),
9104                              isolate);
9105   bool use_cache =
9106       !fast_map->is_prototype_map() && !maybe_cache->IsUndefined(isolate);
9107   Handle<NormalizedMapCache> cache;
9108   if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache);
9109 
9110   Handle<Map> new_map;
9111   if (use_cache && cache->Get(fast_map, mode).ToHandle(&new_map)) {
9112 #ifdef VERIFY_HEAP
9113     if (FLAG_verify_heap) new_map->DictionaryMapVerify();
9114 #endif
9115 #ifdef ENABLE_SLOW_DCHECKS
9116     if (FLAG_enable_slow_asserts) {
9117       // The cached map should match newly created normalized map bit-by-bit,
9118       // except for the code cache, which can contain some ICs which can be
9119       // applied to the shared map, dependent code and weak cell cache.
9120       Handle<Map> fresh = Map::CopyNormalized(fast_map, mode);
9121 
9122       if (new_map->is_prototype_map()) {
9123         // For prototype maps, the PrototypeInfo is not copied.
9124         DCHECK_EQ(0, memcmp(reinterpret_cast<void*>(fresh->address()),
9125                             reinterpret_cast<void*>(new_map->address()),
9126                             kTransitionsOrPrototypeInfoOffset));
9127         DCHECK_EQ(fresh->raw_transitions(),
9128                   MaybeObject::FromObject(Smi::kZero));
9129         STATIC_ASSERT(kDescriptorsOffset ==
9130                       kTransitionsOrPrototypeInfoOffset + kPointerSize);
9131         DCHECK_EQ(0, memcmp(HeapObject::RawField(*fresh, kDescriptorsOffset),
9132                             HeapObject::RawField(*new_map, kDescriptorsOffset),
9133                             kDependentCodeOffset - kDescriptorsOffset));
9134       } else {
9135         DCHECK_EQ(0, memcmp(reinterpret_cast<void*>(fresh->address()),
9136                             reinterpret_cast<void*>(new_map->address()),
9137                             Map::kDependentCodeOffset));
9138       }
9139       STATIC_ASSERT(Map::kWeakCellCacheOffset ==
9140                     Map::kDependentCodeOffset + kPointerSize);
9141       STATIC_ASSERT(Map::kPrototypeValidityCellOffset ==
9142                     Map::kWeakCellCacheOffset + kPointerSize);
9143       int offset = Map::kPrototypeValidityCellOffset + kPointerSize;
9144       DCHECK_EQ(0, memcmp(reinterpret_cast<void*>(fresh->address() + offset),
9145                           reinterpret_cast<void*>(new_map->address() + offset),
9146                           Map::kSize - offset));
9147     }
9148 #endif
9149   } else {
9150     new_map = Map::CopyNormalized(fast_map, mode);
9151     if (use_cache) {
9152       Handle<WeakCell> cell = Map::WeakCellForMap(new_map);
9153       cache->Set(fast_map, new_map, cell);
9154       isolate->counters()->maps_normalized()->Increment();
9155     }
9156     if (FLAG_trace_maps) {
9157       LOG(isolate, MapEvent("Normalize", *fast_map, *new_map, reason));
9158     }
9159   }
9160   fast_map->NotifyLeafMapLayoutChange();
9161   return new_map;
9162 }
9163 
9164 
CopyNormalized(Handle<Map> map,PropertyNormalizationMode mode)9165 Handle<Map> Map::CopyNormalized(Handle<Map> map,
9166                                 PropertyNormalizationMode mode) {
9167   int new_instance_size = map->instance_size();
9168   if (mode == CLEAR_INOBJECT_PROPERTIES) {
9169     new_instance_size -= map->GetInObjectProperties() * kPointerSize;
9170   }
9171 
9172   Handle<Map> result = RawCopy(
9173       map, new_instance_size,
9174       mode == CLEAR_INOBJECT_PROPERTIES ? 0 : map->GetInObjectProperties());
9175   // Clear the unused_property_fields explicitly as this field should not
9176   // be accessed for normalized maps.
9177   result->SetInObjectUnusedPropertyFields(0);
9178   result->set_is_dictionary_map(true);
9179   result->set_is_migration_target(false);
9180   result->set_may_have_interesting_symbols(true);
9181   result->set_construction_counter(kNoSlackTracking);
9182 
9183 #ifdef VERIFY_HEAP
9184   if (FLAG_verify_heap) result->DictionaryMapVerify();
9185 #endif
9186 
9187   return result;
9188 }
9189 
9190 // Return an immutable prototype exotic object version of the input map.
9191 // Never even try to cache it in the transition tree, as it is intended
9192 // for the global object and its prototype chain, and excluding it saves
9193 // memory on the map transition tree.
9194 
9195 // static
TransitionToImmutableProto(Handle<Map> map)9196 Handle<Map> Map::TransitionToImmutableProto(Handle<Map> map) {
9197   Handle<Map> new_map = Map::Copy(map, "ImmutablePrototype");
9198   new_map->set_is_immutable_proto(true);
9199   return new_map;
9200 }
9201 
9202 namespace {
EnsureInitialMap(Handle<Map> map)9203 void EnsureInitialMap(Handle<Map> map) {
9204 #ifdef DEBUG
9205   Isolate* isolate = map->GetIsolate();
9206   // Strict function maps have Function as a constructor but the
9207   // Function's initial map is a sloppy function map. Same holds for
9208   // GeneratorFunction / AsyncFunction and its initial map.
9209   Object* constructor = map->GetConstructor();
9210   DCHECK(constructor->IsJSFunction());
9211   DCHECK(*map == JSFunction::cast(constructor)->initial_map() ||
9212          *map == *isolate->strict_function_map() ||
9213          *map == *isolate->strict_function_with_name_map() ||
9214          *map == *isolate->generator_function_map() ||
9215          *map == *isolate->generator_function_with_name_map() ||
9216          *map == *isolate->generator_function_with_home_object_map() ||
9217          *map == *isolate->generator_function_with_name_and_home_object_map() ||
9218          *map == *isolate->async_function_map() ||
9219          *map == *isolate->async_function_with_name_map() ||
9220          *map == *isolate->async_function_with_home_object_map() ||
9221          *map == *isolate->async_function_with_name_and_home_object_map());
9222 #endif
9223   // Initial maps must always own their descriptors and it's descriptor array
9224   // does not contain descriptors that do not belong to the map.
9225   DCHECK(map->owns_descriptors());
9226   DCHECK_EQ(map->NumberOfOwnDescriptors(),
9227             map->instance_descriptors()->number_of_descriptors());
9228 }
9229 }  // namespace
9230 
9231 // static
CopyInitialMapNormalized(Handle<Map> map,PropertyNormalizationMode mode)9232 Handle<Map> Map::CopyInitialMapNormalized(Handle<Map> map,
9233                                           PropertyNormalizationMode mode) {
9234   EnsureInitialMap(map);
9235   return CopyNormalized(map, mode);
9236 }
9237 
9238 // static
CopyInitialMap(Handle<Map> map,int instance_size,int inobject_properties,int unused_property_fields)9239 Handle<Map> Map::CopyInitialMap(Handle<Map> map, int instance_size,
9240                                 int inobject_properties,
9241                                 int unused_property_fields) {
9242   EnsureInitialMap(map);
9243   Handle<Map> result = RawCopy(map, instance_size, inobject_properties);
9244 
9245   // Please note instance_type and instance_size are set when allocated.
9246   result->SetInObjectUnusedPropertyFields(unused_property_fields);
9247 
9248   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9249   if (number_of_own_descriptors > 0) {
9250     // The copy will use the same descriptors array.
9251     result->UpdateDescriptors(map->instance_descriptors(),
9252                               map->GetLayoutDescriptor());
9253     result->SetNumberOfOwnDescriptors(number_of_own_descriptors);
9254 
9255     DCHECK_EQ(result->NumberOfFields(),
9256               result->GetInObjectProperties() - result->UnusedPropertyFields());
9257   }
9258 
9259   return result;
9260 }
9261 
9262 
CopyDropDescriptors(Handle<Map> map)9263 Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) {
9264   Handle<Map> result =
9265       RawCopy(map, map->instance_size(),
9266               map->IsJSObjectMap() ? map->GetInObjectProperties() : 0);
9267 
9268   // Please note instance_type and instance_size are set when allocated.
9269   if (map->IsJSObjectMap()) {
9270     result->CopyUnusedPropertyFields(*map);
9271   }
9272   map->NotifyLeafMapLayoutChange();
9273   return result;
9274 }
9275 
9276 
ShareDescriptor(Handle<Map> map,Handle<DescriptorArray> descriptors,Descriptor * descriptor)9277 Handle<Map> Map::ShareDescriptor(Handle<Map> map,
9278                                  Handle<DescriptorArray> descriptors,
9279                                  Descriptor* descriptor) {
9280   // Sanity check. This path is only to be taken if the map owns its descriptor
9281   // array, implying that its NumberOfOwnDescriptors equals the number of
9282   // descriptors in the descriptor array.
9283   DCHECK_EQ(map->NumberOfOwnDescriptors(),
9284             map->instance_descriptors()->number_of_descriptors());
9285 
9286   Handle<Map> result = CopyDropDescriptors(map);
9287   Handle<Name> name = descriptor->GetKey();
9288 
9289   // Properly mark the {result} if the {name} is an "interesting symbol".
9290   if (name->IsInterestingSymbol()) {
9291     result->set_may_have_interesting_symbols(true);
9292   }
9293 
9294   // Ensure there's space for the new descriptor in the shared descriptor array.
9295   if (descriptors->NumberOfSlackDescriptors() == 0) {
9296     int old_size = descriptors->number_of_descriptors();
9297     if (old_size == 0) {
9298       descriptors = DescriptorArray::Allocate(map->GetIsolate(), 0, 1);
9299     } else {
9300       int slack = SlackForArraySize(old_size, kMaxNumberOfDescriptors);
9301       EnsureDescriptorSlack(map, slack);
9302       descriptors = handle(map->instance_descriptors());
9303     }
9304   }
9305 
9306   Handle<LayoutDescriptor> layout_descriptor =
9307       FLAG_unbox_double_fields
9308           ? LayoutDescriptor::ShareAppend(map, descriptor->GetDetails())
9309           : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
9310 
9311   {
9312     DisallowHeapAllocation no_gc;
9313     descriptors->Append(descriptor);
9314     result->InitializeDescriptors(*descriptors, *layout_descriptor);
9315   }
9316 
9317   DCHECK(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1);
9318   ConnectTransition(map, result, name, SIMPLE_PROPERTY_TRANSITION);
9319 
9320   return result;
9321 }
9322 
ConnectTransition(Handle<Map> parent,Handle<Map> child,Handle<Name> name,SimpleTransitionFlag flag)9323 void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
9324                             Handle<Name> name, SimpleTransitionFlag flag) {
9325   Isolate* isolate = parent->GetIsolate();
9326   DCHECK_IMPLIES(name->IsInterestingSymbol(),
9327                  child->may_have_interesting_symbols());
9328   DCHECK_IMPLIES(parent->may_have_interesting_symbols(),
9329                  child->may_have_interesting_symbols());
9330   // Do not track transitions during bootstrap except for element transitions.
9331   if (isolate->bootstrapper()->IsActive() &&
9332       !name.is_identical_to(isolate->factory()->elements_transition_symbol())) {
9333     if (FLAG_trace_maps) {
9334       LOG(isolate,
9335           MapEvent("Transition", *parent, *child,
9336                    child->is_prototype_map() ? "prototype" : "", *name));
9337     }
9338     return;
9339   }
9340   if (!parent->GetBackPointer()->IsUndefined(isolate)) {
9341     parent->set_owns_descriptors(false);
9342   } else {
9343     // |parent| is initial map and it must keep the ownership, there must be no
9344     // descriptors in the descriptors array that do not belong to the map.
9345     DCHECK(parent->owns_descriptors());
9346     DCHECK_EQ(parent->NumberOfOwnDescriptors(),
9347               parent->instance_descriptors()->number_of_descriptors());
9348   }
9349   if (parent->is_prototype_map()) {
9350     DCHECK(child->is_prototype_map());
9351     if (FLAG_trace_maps) {
9352       LOG(isolate, MapEvent("Transition", *parent, *child, "prototype", *name));
9353     }
9354   } else {
9355     TransitionsAccessor(parent).Insert(name, child, flag);
9356     if (FLAG_trace_maps) {
9357       LOG(isolate, MapEvent("Transition", *parent, *child, "", *name));
9358     }
9359   }
9360 }
9361 
9362 
CopyReplaceDescriptors(Handle<Map> map,Handle<DescriptorArray> descriptors,Handle<LayoutDescriptor> layout_descriptor,TransitionFlag flag,MaybeHandle<Name> maybe_name,const char * reason,SimpleTransitionFlag simple_flag)9363 Handle<Map> Map::CopyReplaceDescriptors(
9364     Handle<Map> map, Handle<DescriptorArray> descriptors,
9365     Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag,
9366     MaybeHandle<Name> maybe_name, const char* reason,
9367     SimpleTransitionFlag simple_flag) {
9368   DCHECK(descriptors->IsSortedNoDuplicates());
9369 
9370   Handle<Map> result = CopyDropDescriptors(map);
9371 
9372   // Properly mark the {result} if the {name} is an "interesting symbol".
9373   Handle<Name> name;
9374   if (maybe_name.ToHandle(&name) && name->IsInterestingSymbol()) {
9375     result->set_may_have_interesting_symbols(true);
9376   }
9377 
9378   if (!map->is_prototype_map()) {
9379     if (flag == INSERT_TRANSITION &&
9380         TransitionsAccessor(map).CanHaveMoreTransitions()) {
9381       result->InitializeDescriptors(*descriptors, *layout_descriptor);
9382 
9383       DCHECK(!maybe_name.is_null());
9384       ConnectTransition(map, result, name, simple_flag);
9385     } else {
9386       descriptors->GeneralizeAllFields();
9387       result->InitializeDescriptors(*descriptors,
9388                                     LayoutDescriptor::FastPointerLayout());
9389     }
9390   } else {
9391     result->InitializeDescriptors(*descriptors, *layout_descriptor);
9392   }
9393   if (FLAG_trace_maps &&
9394       // Mirror conditions above that did not call ConnectTransition().
9395       (map->is_prototype_map() ||
9396        !(flag == INSERT_TRANSITION &&
9397          TransitionsAccessor(map).CanHaveMoreTransitions()))) {
9398     LOG(map->GetIsolate(), MapEvent("ReplaceDescriptors", *map, *result, reason,
9399                                     maybe_name.is_null() ? nullptr : *name));
9400   }
9401   return result;
9402 }
9403 
9404 
9405 // Creates transition tree starting from |split_map| and adding all descriptors
9406 // starting from descriptor with index |split_map|.NumberOfOwnDescriptors().
9407 // The way how it is done is tricky because of GC and special descriptors
9408 // marking logic.
AddMissingTransitions(Handle<Map> split_map,Handle<DescriptorArray> descriptors,Handle<LayoutDescriptor> full_layout_descriptor)9409 Handle<Map> Map::AddMissingTransitions(
9410     Handle<Map> split_map, Handle<DescriptorArray> descriptors,
9411     Handle<LayoutDescriptor> full_layout_descriptor) {
9412   DCHECK(descriptors->IsSortedNoDuplicates());
9413   int split_nof = split_map->NumberOfOwnDescriptors();
9414   int nof_descriptors = descriptors->number_of_descriptors();
9415   DCHECK_LT(split_nof, nof_descriptors);
9416 
9417   // Start with creating last map which will own full descriptors array.
9418   // This is necessary to guarantee that GC will mark the whole descriptor
9419   // array if any of the allocations happening below fail.
9420   // Number of unused properties is temporarily incorrect and the layout
9421   // descriptor could unnecessarily be in slow mode but we will fix after
9422   // all the other intermediate maps are created.
9423   // Also the last map might have interesting symbols, we temporarily set
9424   // the flag and clear it right before the descriptors are installed. This
9425   // makes heap verification happy and ensures the flag ends up accurate.
9426   Handle<Map> last_map = CopyDropDescriptors(split_map);
9427   last_map->InitializeDescriptors(*descriptors, *full_layout_descriptor);
9428   last_map->SetInObjectUnusedPropertyFields(0);
9429   last_map->set_may_have_interesting_symbols(true);
9430 
9431   // During creation of intermediate maps we violate descriptors sharing
9432   // invariant since the last map is not yet connected to the transition tree
9433   // we create here. But it is safe because GC never trims map's descriptors
9434   // if there are no dead transitions from that map and this is exactly the
9435   // case for all the intermediate maps we create here.
9436   Handle<Map> map = split_map;
9437   for (int i = split_nof; i < nof_descriptors - 1; ++i) {
9438     Handle<Map> new_map = CopyDropDescriptors(map);
9439     InstallDescriptors(map, new_map, i, descriptors, full_layout_descriptor);
9440     map = new_map;
9441   }
9442   map->NotifyLeafMapLayoutChange();
9443   last_map->set_may_have_interesting_symbols(false);
9444   InstallDescriptors(map, last_map, nof_descriptors - 1, descriptors,
9445                      full_layout_descriptor);
9446   return last_map;
9447 }
9448 
9449 
9450 // Since this method is used to rewrite an existing transition tree, it can
9451 // always insert transitions without checking.
InstallDescriptors(Handle<Map> parent,Handle<Map> child,int new_descriptor,Handle<DescriptorArray> descriptors,Handle<LayoutDescriptor> full_layout_descriptor)9452 void Map::InstallDescriptors(Handle<Map> parent, Handle<Map> child,
9453                              int new_descriptor,
9454                              Handle<DescriptorArray> descriptors,
9455                              Handle<LayoutDescriptor> full_layout_descriptor) {
9456   DCHECK(descriptors->IsSortedNoDuplicates());
9457 
9458   child->set_instance_descriptors(*descriptors);
9459   child->SetNumberOfOwnDescriptors(new_descriptor + 1);
9460   child->CopyUnusedPropertyFields(*parent);
9461   PropertyDetails details = descriptors->GetDetails(new_descriptor);
9462   if (details.location() == kField) {
9463     child->AccountAddedPropertyField();
9464   }
9465 
9466   if (FLAG_unbox_double_fields) {
9467     Handle<LayoutDescriptor> layout_descriptor =
9468         LayoutDescriptor::AppendIfFastOrUseFull(parent, details,
9469                                                 full_layout_descriptor);
9470     child->set_layout_descriptor(*layout_descriptor);
9471 #ifdef VERIFY_HEAP
9472     // TODO(ishell): remove these checks from VERIFY_HEAP mode.
9473     if (FLAG_verify_heap) {
9474       CHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
9475     }
9476 #else
9477     SLOW_DCHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
9478 #endif
9479     child->set_visitor_id(Map::GetVisitorId(*child));
9480   }
9481 
9482   Handle<Name> name = handle(descriptors->GetKey(new_descriptor));
9483   if (parent->may_have_interesting_symbols() || name->IsInterestingSymbol()) {
9484     child->set_may_have_interesting_symbols(true);
9485   }
9486   ConnectTransition(parent, child, name, SIMPLE_PROPERTY_TRANSITION);
9487 }
9488 
9489 
CopyAsElementsKind(Handle<Map> map,ElementsKind kind,TransitionFlag flag)9490 Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind,
9491                                     TransitionFlag flag) {
9492   // Only certain objects are allowed to have non-terminal fast transitional
9493   // elements kinds.
9494   DCHECK(map->IsJSObjectMap());
9495   DCHECK_IMPLIES(
9496       !map->CanHaveFastTransitionableElementsKind(),
9497       IsDictionaryElementsKind(kind) || IsTerminalElementsKind(kind));
9498 
9499   Map* maybe_elements_transition_map = nullptr;
9500   if (flag == INSERT_TRANSITION) {
9501     // Ensure we are requested to add elements kind transition "near the root".
9502     DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(),
9503               map->NumberOfOwnDescriptors());
9504 
9505     maybe_elements_transition_map = map->ElementsTransitionMap();
9506     DCHECK(maybe_elements_transition_map == nullptr ||
9507            (maybe_elements_transition_map->elements_kind() ==
9508                 DICTIONARY_ELEMENTS &&
9509             kind == DICTIONARY_ELEMENTS));
9510     DCHECK(!IsFastElementsKind(kind) ||
9511            IsMoreGeneralElementsKindTransition(map->elements_kind(), kind));
9512     DCHECK(kind != map->elements_kind());
9513   }
9514 
9515   bool insert_transition = flag == INSERT_TRANSITION &&
9516                            TransitionsAccessor(map).CanHaveMoreTransitions() &&
9517                            maybe_elements_transition_map == nullptr;
9518 
9519   if (insert_transition) {
9520     Handle<Map> new_map = CopyForTransition(map, "CopyAsElementsKind");
9521     new_map->set_elements_kind(kind);
9522 
9523     Isolate* isolate = map->GetIsolate();
9524     Handle<Name> name = isolate->factory()->elements_transition_symbol();
9525     ConnectTransition(map, new_map, name, SPECIAL_TRANSITION);
9526     return new_map;
9527   }
9528 
9529   // Create a new free-floating map only if we are not allowed to store it.
9530   Handle<Map> new_map = Copy(map, "CopyAsElementsKind");
9531   new_map->set_elements_kind(kind);
9532   return new_map;
9533 }
9534 
AsLanguageMode(Handle<Map> initial_map,Handle<SharedFunctionInfo> shared_info)9535 Handle<Map> Map::AsLanguageMode(Handle<Map> initial_map,
9536                                 Handle<SharedFunctionInfo> shared_info) {
9537   DCHECK_EQ(JS_FUNCTION_TYPE, initial_map->instance_type());
9538   // Initial map for sloppy mode function is stored in the function
9539   // constructor. Initial maps for strict mode are cached as special transitions
9540   // using |strict_function_transition_symbol| as a key.
9541   if (is_sloppy(shared_info->language_mode())) return initial_map;
9542   Isolate* isolate = initial_map->GetIsolate();
9543 
9544   Handle<Map> function_map(Map::cast(
9545       isolate->native_context()->get(shared_info->function_map_index())));
9546 
9547   STATIC_ASSERT(LanguageModeSize == 2);
9548   DCHECK_EQ(LanguageMode::kStrict, shared_info->language_mode());
9549   Handle<Symbol> transition_symbol =
9550       isolate->factory()->strict_function_transition_symbol();
9551   Map* maybe_transition =
9552       TransitionsAccessor(initial_map).SearchSpecial(*transition_symbol);
9553   if (maybe_transition != nullptr) {
9554     return handle(maybe_transition, isolate);
9555   }
9556   initial_map->NotifyLeafMapLayoutChange();
9557 
9558   // Create new map taking descriptors from the |function_map| and all
9559   // the other details from the |initial_map|.
9560   Handle<Map> map =
9561       Map::CopyInitialMap(function_map, initial_map->instance_size(),
9562                           initial_map->GetInObjectProperties(),
9563                           initial_map->UnusedPropertyFields());
9564   map->SetConstructor(initial_map->GetConstructor());
9565   map->set_prototype(initial_map->prototype());
9566   map->set_construction_counter(initial_map->construction_counter());
9567 
9568   if (TransitionsAccessor(initial_map).CanHaveMoreTransitions()) {
9569     Map::ConnectTransition(initial_map, map, transition_symbol,
9570                            SPECIAL_TRANSITION);
9571   }
9572   return map;
9573 }
9574 
9575 
CopyForTransition(Handle<Map> map,const char * reason)9576 Handle<Map> Map::CopyForTransition(Handle<Map> map, const char* reason) {
9577   DCHECK(!map->is_prototype_map());
9578   Handle<Map> new_map = CopyDropDescriptors(map);
9579 
9580   if (map->owns_descriptors()) {
9581     // In case the map owned its own descriptors, share the descriptors and
9582     // transfer ownership to the new map.
9583     // The properties did not change, so reuse descriptors.
9584     new_map->InitializeDescriptors(map->instance_descriptors(),
9585                                    map->GetLayoutDescriptor());
9586   } else {
9587     // In case the map did not own its own descriptors, a split is forced by
9588     // copying the map; creating a new descriptor array cell.
9589     Handle<DescriptorArray> descriptors(map->instance_descriptors());
9590     int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9591     Handle<DescriptorArray> new_descriptors =
9592         DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
9593     Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9594                                                    map->GetIsolate());
9595     new_map->InitializeDescriptors(*new_descriptors, *new_layout_descriptor);
9596   }
9597 
9598   if (FLAG_trace_maps) {
9599     LOG(map->GetIsolate(),
9600         MapEvent("CopyForTransition", *map, *new_map, reason));
9601   }
9602   return new_map;
9603 }
9604 
9605 
Copy(Handle<Map> map,const char * reason)9606 Handle<Map> Map::Copy(Handle<Map> map, const char* reason) {
9607   Handle<DescriptorArray> descriptors(map->instance_descriptors());
9608   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9609   Handle<DescriptorArray> new_descriptors =
9610       DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
9611   Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9612                                                  map->GetIsolate());
9613   return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9614                                 OMIT_TRANSITION, MaybeHandle<Name>(), reason,
9615                                 SPECIAL_TRANSITION);
9616 }
9617 
9618 
Create(Isolate * isolate,int inobject_properties)9619 Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) {
9620   Handle<Map> copy =
9621       Copy(handle(isolate->object_function()->initial_map()), "MapCreate");
9622 
9623   // Check that we do not overflow the instance size when adding the extra
9624   // inobject properties. If the instance size overflows, we allocate as many
9625   // properties as we can as inobject properties.
9626   if (inobject_properties > JSObject::kMaxInObjectProperties) {
9627     inobject_properties = JSObject::kMaxInObjectProperties;
9628   }
9629 
9630   int new_instance_size =
9631       JSObject::kHeaderSize + kPointerSize * inobject_properties;
9632 
9633   // Adjust the map with the extra inobject properties.
9634   copy->set_instance_size(new_instance_size);
9635   copy->SetInObjectPropertiesStartInWords(JSObject::kHeaderSize / kPointerSize);
9636   DCHECK_EQ(copy->GetInObjectProperties(), inobject_properties);
9637   copy->SetInObjectUnusedPropertyFields(inobject_properties);
9638   copy->set_visitor_id(Map::GetVisitorId(*copy));
9639   return copy;
9640 }
9641 
9642 
CopyForPreventExtensions(Handle<Map> map,PropertyAttributes attrs_to_add,Handle<Symbol> transition_marker,const char * reason)9643 Handle<Map> Map::CopyForPreventExtensions(Handle<Map> map,
9644                                           PropertyAttributes attrs_to_add,
9645                                           Handle<Symbol> transition_marker,
9646                                           const char* reason) {
9647   int num_descriptors = map->NumberOfOwnDescriptors();
9648   Isolate* isolate = map->GetIsolate();
9649   Handle<DescriptorArray> new_desc = DescriptorArray::CopyUpToAddAttributes(
9650       handle(map->instance_descriptors(), isolate), num_descriptors,
9651       attrs_to_add);
9652   Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9653                                                  isolate);
9654   Handle<Map> new_map = CopyReplaceDescriptors(
9655       map, new_desc, new_layout_descriptor, INSERT_TRANSITION,
9656       transition_marker, reason, SPECIAL_TRANSITION);
9657   new_map->set_is_extensible(false);
9658   if (!IsFixedTypedArrayElementsKind(map->elements_kind())) {
9659     ElementsKind new_kind = IsStringWrapperElementsKind(map->elements_kind())
9660                                 ? SLOW_STRING_WRAPPER_ELEMENTS
9661                                 : DICTIONARY_ELEMENTS;
9662     new_map->set_elements_kind(new_kind);
9663   }
9664   return new_map;
9665 }
9666 
9667 namespace {
9668 
CanHoldValue(DescriptorArray * descriptors,int descriptor,PropertyConstness constness,Object * value)9669 bool CanHoldValue(DescriptorArray* descriptors, int descriptor,
9670                   PropertyConstness constness, Object* value) {
9671   PropertyDetails details = descriptors->GetDetails(descriptor);
9672   if (details.location() == kField) {
9673     if (details.kind() == kData) {
9674       return IsGeneralizableTo(constness, details.constness()) &&
9675              value->FitsRepresentation(details.representation()) &&
9676              descriptors->GetFieldType(descriptor)->NowContains(value);
9677     } else {
9678       DCHECK_EQ(kAccessor, details.kind());
9679       return false;
9680     }
9681 
9682   } else {
9683     DCHECK_EQ(kDescriptor, details.location());
9684     DCHECK_EQ(kConst, details.constness());
9685     if (details.kind() == kData) {
9686       DCHECK(!FLAG_track_constant_fields);
9687       DCHECK(descriptors->GetValue(descriptor) != value ||
9688              value->FitsRepresentation(details.representation()));
9689       return descriptors->GetValue(descriptor) == value;
9690     } else {
9691       DCHECK_EQ(kAccessor, details.kind());
9692       return false;
9693     }
9694   }
9695   UNREACHABLE();
9696 }
9697 
UpdateDescriptorForValue(Handle<Map> map,int descriptor,PropertyConstness constness,Handle<Object> value)9698 Handle<Map> UpdateDescriptorForValue(Handle<Map> map, int descriptor,
9699                                      PropertyConstness constness,
9700                                      Handle<Object> value) {
9701   if (CanHoldValue(map->instance_descriptors(), descriptor, constness,
9702                    *value)) {
9703     return map;
9704   }
9705 
9706   Isolate* isolate = map->GetIsolate();
9707   PropertyAttributes attributes =
9708       map->instance_descriptors()->GetDetails(descriptor).attributes();
9709   Representation representation = value->OptimalRepresentation();
9710   Handle<FieldType> type = value->OptimalType(isolate, representation);
9711 
9712   MapUpdater mu(isolate, map);
9713   return mu.ReconfigureToDataField(descriptor, attributes, constness,
9714                                    representation, type);
9715 }
9716 
9717 }  // namespace
9718 
9719 // static
PrepareForDataProperty(Handle<Map> map,int descriptor,PropertyConstness constness,Handle<Object> value)9720 Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor,
9721                                         PropertyConstness constness,
9722                                         Handle<Object> value) {
9723   // Dictionaries can store any property value.
9724   DCHECK(!map->is_dictionary_map());
9725   // Update to the newest map before storing the property.
9726   return UpdateDescriptorForValue(Update(map), descriptor, constness, value);
9727 }
9728 
TransitionToDataProperty(Handle<Map> map,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes,PropertyConstness constness,StoreFromKeyed store_mode)9729 Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
9730                                           Handle<Object> value,
9731                                           PropertyAttributes attributes,
9732                                           PropertyConstness constness,
9733                                           StoreFromKeyed store_mode) {
9734   RuntimeCallTimerScope stats_scope(
9735       *map, map->is_prototype_map()
9736                 ? RuntimeCallCounterId::kPrototypeMap_TransitionToDataProperty
9737                 : RuntimeCallCounterId::kMap_TransitionToDataProperty);
9738 
9739   DCHECK(name->IsUniqueName());
9740   DCHECK(!map->is_dictionary_map());
9741 
9742   // Migrate to the newest map before storing the property.
9743   map = Update(map);
9744 
9745   Map* maybe_transition =
9746       TransitionsAccessor(map).SearchTransition(*name, kData, attributes);
9747   if (maybe_transition != nullptr) {
9748     Handle<Map> transition(maybe_transition);
9749     int descriptor = transition->LastAdded();
9750 
9751     DCHECK_EQ(attributes, transition->instance_descriptors()
9752                               ->GetDetails(descriptor)
9753                               .attributes());
9754 
9755     return UpdateDescriptorForValue(transition, descriptor, constness, value);
9756   }
9757 
9758   TransitionFlag flag = INSERT_TRANSITION;
9759   MaybeHandle<Map> maybe_map;
9760   if (!map->TooManyFastProperties(store_mode)) {
9761     if (!FLAG_track_constant_fields && value->IsJSFunction()) {
9762       maybe_map = Map::CopyWithConstant(map, name, value, attributes, flag);
9763     } else {
9764       Isolate* isolate = name->GetIsolate();
9765       Representation representation = value->OptimalRepresentation();
9766       Handle<FieldType> type = value->OptimalType(isolate, representation);
9767       maybe_map = Map::CopyWithField(map, name, type, attributes, constness,
9768                                      representation, flag);
9769     }
9770   }
9771 
9772   Handle<Map> result;
9773   if (!maybe_map.ToHandle(&result)) {
9774     Isolate* isolate = name->GetIsolate();
9775     const char* reason = "TooManyFastProperties";
9776 #if V8_TRACE_MAPS
9777     std::unique_ptr<ScopedVector<char>> buffer;
9778     if (FLAG_trace_maps) {
9779       ScopedVector<char> name_buffer(100);
9780       name->NameShortPrint(name_buffer);
9781       buffer.reset(new ScopedVector<char>(128));
9782       SNPrintF(*buffer, "TooManyFastProperties %s", name_buffer.start());
9783       reason = buffer->start();
9784     }
9785 #endif
9786     Handle<Object> maybe_constructor(map->GetConstructor(), isolate);
9787     if (FLAG_feedback_normalization && map->new_target_is_base() &&
9788         maybe_constructor->IsJSFunction() &&
9789         !JSFunction::cast(*maybe_constructor)->shared()->native()) {
9790       Handle<JSFunction> constructor =
9791           Handle<JSFunction>::cast(maybe_constructor);
9792       DCHECK_NE(*constructor,
9793                 constructor->context()->native_context()->object_function());
9794       Handle<Map> initial_map(constructor->initial_map(), isolate);
9795       result = Map::Normalize(initial_map, CLEAR_INOBJECT_PROPERTIES, reason);
9796       initial_map->DeprecateTransitionTree();
9797       Handle<Object> prototype(result->prototype(), isolate);
9798       JSFunction::SetInitialMap(constructor, result, prototype);
9799 
9800       // Deoptimize all code that embeds the previous initial map.
9801       initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
9802           isolate, DependentCode::kInitialMapChangedGroup);
9803       if (!result->EquivalentToForNormalization(*map,
9804                                                 CLEAR_INOBJECT_PROPERTIES)) {
9805         result = Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, reason);
9806       }
9807     } else {
9808       result = Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, reason);
9809     }
9810   }
9811 
9812   return result;
9813 }
9814 
9815 
ReconfigureExistingProperty(Handle<Map> map,int descriptor,PropertyKind kind,PropertyAttributes attributes)9816 Handle<Map> Map::ReconfigureExistingProperty(Handle<Map> map, int descriptor,
9817                                              PropertyKind kind,
9818                                              PropertyAttributes attributes) {
9819   // Dictionaries have to be reconfigured in-place.
9820   DCHECK(!map->is_dictionary_map());
9821 
9822   if (!map->GetBackPointer()->IsMap()) {
9823     // There is no benefit from reconstructing transition tree for maps without
9824     // back pointers.
9825     return CopyGeneralizeAllFields(map, map->elements_kind(), descriptor, kind,
9826                                    attributes,
9827                                    "GenAll_AttributesMismatchProtoMap");
9828   }
9829 
9830   if (FLAG_trace_generalization) {
9831     map->PrintReconfiguration(stdout, descriptor, kind, attributes);
9832   }
9833 
9834   Isolate* isolate = map->GetIsolate();
9835 
9836   MapUpdater mu(isolate, map);
9837   DCHECK_EQ(kData, kind);  // Only kData case is supported so far.
9838   Handle<Map> new_map = mu.ReconfigureToDataField(
9839       descriptor, attributes, kDefaultFieldConstness, Representation::None(),
9840       FieldType::None(isolate));
9841   return new_map;
9842 }
9843 
TransitionToAccessorProperty(Isolate * isolate,Handle<Map> map,Handle<Name> name,int descriptor,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)9844 Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map,
9845                                               Handle<Name> name, int descriptor,
9846                                               Handle<Object> getter,
9847                                               Handle<Object> setter,
9848                                               PropertyAttributes attributes) {
9849   RuntimeCallTimerScope stats_scope(
9850       isolate,
9851       map->is_prototype_map()
9852           ? RuntimeCallCounterId::kPrototypeMap_TransitionToAccessorProperty
9853           : RuntimeCallCounterId::kMap_TransitionToAccessorProperty);
9854 
9855   // At least one of the accessors needs to be a new value.
9856   DCHECK(!getter->IsNull(isolate) || !setter->IsNull(isolate));
9857   DCHECK(name->IsUniqueName());
9858 
9859   // Dictionary maps can always have additional data properties.
9860   if (map->is_dictionary_map()) return map;
9861 
9862   // Migrate to the newest map before transitioning to the new property.
9863   map = Update(map);
9864 
9865   PropertyNormalizationMode mode = map->is_prototype_map()
9866                                        ? KEEP_INOBJECT_PROPERTIES
9867                                        : CLEAR_INOBJECT_PROPERTIES;
9868 
9869   Map* maybe_transition =
9870       TransitionsAccessor(map).SearchTransition(*name, kAccessor, attributes);
9871   if (maybe_transition != nullptr) {
9872     Handle<Map> transition(maybe_transition, isolate);
9873     DescriptorArray* descriptors = transition->instance_descriptors();
9874     int descriptor = transition->LastAdded();
9875     DCHECK(descriptors->GetKey(descriptor)->Equals(*name));
9876 
9877     DCHECK_EQ(kAccessor, descriptors->GetDetails(descriptor).kind());
9878     DCHECK_EQ(attributes, descriptors->GetDetails(descriptor).attributes());
9879 
9880     Handle<Object> maybe_pair(descriptors->GetValue(descriptor), isolate);
9881     if (!maybe_pair->IsAccessorPair()) {
9882       return Map::Normalize(map, mode, "TransitionToAccessorFromNonPair");
9883     }
9884 
9885     Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair);
9886     if (!pair->Equals(*getter, *setter)) {
9887       return Map::Normalize(map, mode, "TransitionToDifferentAccessor");
9888     }
9889 
9890     return transition;
9891   }
9892 
9893   Handle<AccessorPair> pair;
9894   DescriptorArray* old_descriptors = map->instance_descriptors();
9895   if (descriptor != DescriptorArray::kNotFound) {
9896     if (descriptor != map->LastAdded()) {
9897       return Map::Normalize(map, mode, "AccessorsOverwritingNonLast");
9898     }
9899     PropertyDetails old_details = old_descriptors->GetDetails(descriptor);
9900     if (old_details.kind() != kAccessor) {
9901       return Map::Normalize(map, mode, "AccessorsOverwritingNonAccessors");
9902     }
9903 
9904     if (old_details.attributes() != attributes) {
9905       return Map::Normalize(map, mode, "AccessorsWithAttributes");
9906     }
9907 
9908     Handle<Object> maybe_pair(old_descriptors->GetValue(descriptor), isolate);
9909     if (!maybe_pair->IsAccessorPair()) {
9910       return Map::Normalize(map, mode, "AccessorsOverwritingNonPair");
9911     }
9912 
9913     Handle<AccessorPair> current_pair = Handle<AccessorPair>::cast(maybe_pair);
9914     if (current_pair->Equals(*getter, *setter)) return map;
9915 
9916     bool overwriting_accessor = false;
9917     if (!getter->IsNull(isolate) &&
9918         !current_pair->get(ACCESSOR_GETTER)->IsNull(isolate) &&
9919         current_pair->get(ACCESSOR_GETTER) != *getter) {
9920       overwriting_accessor = true;
9921     }
9922     if (!setter->IsNull(isolate) &&
9923         !current_pair->get(ACCESSOR_SETTER)->IsNull(isolate) &&
9924         current_pair->get(ACCESSOR_SETTER) != *setter) {
9925       overwriting_accessor = true;
9926     }
9927     if (overwriting_accessor) {
9928       return Map::Normalize(map, mode, "AccessorsOverwritingAccessors");
9929     }
9930 
9931     pair = AccessorPair::Copy(Handle<AccessorPair>::cast(maybe_pair));
9932   } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors ||
9933              map->TooManyFastProperties(CERTAINLY_NOT_STORE_FROM_KEYED)) {
9934     return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, "TooManyAccessors");
9935   } else {
9936     pair = isolate->factory()->NewAccessorPair();
9937   }
9938 
9939   pair->SetComponents(*getter, *setter);
9940 
9941   TransitionFlag flag = INSERT_TRANSITION;
9942   Descriptor d = Descriptor::AccessorConstant(name, pair, attributes);
9943   return Map::CopyInsertDescriptor(map, &d, flag);
9944 }
9945 
9946 
CopyAddDescriptor(Handle<Map> map,Descriptor * descriptor,TransitionFlag flag)9947 Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
9948                                    Descriptor* descriptor,
9949                                    TransitionFlag flag) {
9950   Handle<DescriptorArray> descriptors(map->instance_descriptors());
9951 
9952   // Share descriptors only if map owns descriptors and it not an initial map.
9953   if (flag == INSERT_TRANSITION && map->owns_descriptors() &&
9954       !map->GetBackPointer()->IsUndefined(map->GetIsolate()) &&
9955       TransitionsAccessor(map).CanHaveMoreTransitions()) {
9956     return ShareDescriptor(map, descriptors, descriptor);
9957   }
9958 
9959   int nof = map->NumberOfOwnDescriptors();
9960   Handle<DescriptorArray> new_descriptors =
9961       DescriptorArray::CopyUpTo(descriptors, nof, 1);
9962   new_descriptors->Append(descriptor);
9963 
9964   Handle<LayoutDescriptor> new_layout_descriptor =
9965       FLAG_unbox_double_fields
9966           ? LayoutDescriptor::New(map, new_descriptors, nof + 1)
9967           : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
9968 
9969   return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9970                                 flag, descriptor->GetKey(), "CopyAddDescriptor",
9971                                 SIMPLE_PROPERTY_TRANSITION);
9972 }
9973 
9974 
CopyInsertDescriptor(Handle<Map> map,Descriptor * descriptor,TransitionFlag flag)9975 Handle<Map> Map::CopyInsertDescriptor(Handle<Map> map,
9976                                       Descriptor* descriptor,
9977                                       TransitionFlag flag) {
9978   Handle<DescriptorArray> old_descriptors(map->instance_descriptors());
9979 
9980   // We replace the key if it is already present.
9981   int index = old_descriptors->SearchWithCache(map->GetIsolate(),
9982                                                *descriptor->GetKey(), *map);
9983   if (index != DescriptorArray::kNotFound) {
9984     return CopyReplaceDescriptor(map, old_descriptors, descriptor, index, flag);
9985   }
9986   return CopyAddDescriptor(map, descriptor, flag);
9987 }
9988 
9989 
CopyUpTo(Handle<DescriptorArray> desc,int enumeration_index,int slack)9990 Handle<DescriptorArray> DescriptorArray::CopyUpTo(
9991     Handle<DescriptorArray> desc,
9992     int enumeration_index,
9993     int slack) {
9994   return DescriptorArray::CopyUpToAddAttributes(
9995       desc, enumeration_index, NONE, slack);
9996 }
9997 
9998 
CopyUpToAddAttributes(Handle<DescriptorArray> desc,int enumeration_index,PropertyAttributes attributes,int slack)9999 Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
10000     Handle<DescriptorArray> desc,
10001     int enumeration_index,
10002     PropertyAttributes attributes,
10003     int slack) {
10004   if (enumeration_index + slack == 0) {
10005     return desc->GetIsolate()->factory()->empty_descriptor_array();
10006   }
10007 
10008   int size = enumeration_index;
10009 
10010   Handle<DescriptorArray> descriptors =
10011       DescriptorArray::Allocate(desc->GetIsolate(), size, slack);
10012 
10013   if (attributes != NONE) {
10014     for (int i = 0; i < size; ++i) {
10015       Object* value = desc->GetValue(i);
10016       Name* key = desc->GetKey(i);
10017       PropertyDetails details = desc->GetDetails(i);
10018       // Bulk attribute changes never affect private properties.
10019       if (!key->IsPrivate()) {
10020         int mask = DONT_DELETE | DONT_ENUM;
10021         // READ_ONLY is an invalid attribute for JS setters/getters.
10022         if (details.kind() != kAccessor || !value->IsAccessorPair()) {
10023           mask |= READ_ONLY;
10024         }
10025         details = details.CopyAddAttributes(
10026             static_cast<PropertyAttributes>(attributes & mask));
10027       }
10028       descriptors->Set(i, key, value, details);
10029     }
10030   } else {
10031     for (int i = 0; i < size; ++i) {
10032       descriptors->CopyFrom(i, *desc);
10033     }
10034   }
10035 
10036   if (desc->number_of_descriptors() != enumeration_index) descriptors->Sort();
10037 
10038   return descriptors;
10039 }
10040 
10041 
IsEqualUpTo(DescriptorArray * desc,int nof_descriptors)10042 bool DescriptorArray::IsEqualUpTo(DescriptorArray* desc, int nof_descriptors) {
10043   for (int i = 0; i < nof_descriptors; i++) {
10044     if (GetKey(i) != desc->GetKey(i) || GetValue(i) != desc->GetValue(i)) {
10045       return false;
10046     }
10047     PropertyDetails details = GetDetails(i);
10048     PropertyDetails other_details = desc->GetDetails(i);
10049     if (details.kind() != other_details.kind() ||
10050         details.location() != other_details.location() ||
10051         !details.representation().Equals(other_details.representation())) {
10052       return false;
10053     }
10054   }
10055   return true;
10056 }
10057 
10058 
CopyReplaceDescriptor(Handle<Map> map,Handle<DescriptorArray> descriptors,Descriptor * descriptor,int insertion_index,TransitionFlag flag)10059 Handle<Map> Map::CopyReplaceDescriptor(Handle<Map> map,
10060                                        Handle<DescriptorArray> descriptors,
10061                                        Descriptor* descriptor,
10062                                        int insertion_index,
10063                                        TransitionFlag flag) {
10064   Handle<Name> key = descriptor->GetKey();
10065   DCHECK_EQ(*key, descriptors->GetKey(insertion_index));
10066   // This function does not support replacing property fields as
10067   // that would break property field counters.
10068   DCHECK_NE(kField, descriptor->GetDetails().location());
10069   DCHECK_NE(kField, descriptors->GetDetails(insertion_index).location());
10070 
10071   Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
10072       descriptors, map->NumberOfOwnDescriptors());
10073 
10074   new_descriptors->Replace(insertion_index, descriptor);
10075   Handle<LayoutDescriptor> new_layout_descriptor = LayoutDescriptor::New(
10076       map, new_descriptors, new_descriptors->number_of_descriptors());
10077 
10078   SimpleTransitionFlag simple_flag =
10079       (insertion_index == descriptors->number_of_descriptors() - 1)
10080           ? SIMPLE_PROPERTY_TRANSITION
10081           : PROPERTY_TRANSITION;
10082   return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
10083                                 flag, key, "CopyReplaceDescriptor",
10084                                 simple_flag);
10085 }
10086 
SetAndGrow(Handle<FixedArray> array,int index,Handle<Object> value,PretenureFlag pretenure)10087 Handle<FixedArray> FixedArray::SetAndGrow(Handle<FixedArray> array, int index,
10088                                           Handle<Object> value,
10089                                           PretenureFlag pretenure) {
10090   if (index < array->length()) {
10091     array->set(index, *value);
10092     return array;
10093   }
10094   int capacity = array->length();
10095   do {
10096     capacity = JSObject::NewElementsCapacity(capacity);
10097   } while (capacity <= index);
10098   Handle<FixedArray> new_array =
10099       array->GetIsolate()->factory()->NewUninitializedFixedArray(capacity,
10100                                                                  pretenure);
10101   array->CopyTo(0, *new_array, 0, array->length());
10102   new_array->FillWithHoles(array->length(), new_array->length());
10103   new_array->set(index, *value);
10104   return new_array;
10105 }
10106 
ContainsSortedNumbers()10107 bool FixedArray::ContainsSortedNumbers() {
10108   for (int i = 1; i < length(); ++i) {
10109     Object* a_obj = get(i - 1);
10110     Object* b_obj = get(i);
10111     if (!a_obj->IsNumber() || !b_obj->IsNumber()) return false;
10112 
10113     uint32_t a = NumberToUint32(a_obj);
10114     uint32_t b = NumberToUint32(b_obj);
10115 
10116     if (a > b) return false;
10117   }
10118   return true;
10119 }
10120 
Shrink(int new_length)10121 void FixedArray::Shrink(int new_length) {
10122   DCHECK(0 <= new_length && new_length <= length());
10123   if (new_length < length()) {
10124     GetHeap()->RightTrimFixedArray(this, length() - new_length);
10125   }
10126 }
10127 
CopyTo(int pos,FixedArray * dest,int dest_pos,int len) const10128 void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos,
10129                         int len) const {
10130   DisallowHeapAllocation no_gc;
10131   WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
10132   for (int index = 0; index < len; index++) {
10133     dest->set(dest_pos+index, get(pos+index), mode);
10134   }
10135 }
10136 
10137 #ifdef DEBUG
IsEqualTo(FixedArray * other)10138 bool FixedArray::IsEqualTo(FixedArray* other) {
10139   if (length() != other->length()) return false;
10140   for (int i = 0 ; i < length(); ++i) {
10141     if (get(i) != other->get(i)) return false;
10142   }
10143   return true;
10144 }
10145 #endif
10146 
Shrink(int new_length)10147 void WeakFixedArray::Shrink(int new_length) {
10148   DCHECK(0 <= new_length && new_length <= length());
10149   if (new_length < length()) {
10150     GetHeap()->RightTrimWeakFixedArray(this, length() - new_length);
10151   }
10152 }
10153 
10154 // static
Set(Handle<FixedArrayOfWeakCells> array,int index,Handle<HeapObject> value)10155 void FixedArrayOfWeakCells::Set(Handle<FixedArrayOfWeakCells> array, int index,
10156                                 Handle<HeapObject> value) {
10157   DCHECK(array->IsEmptySlot(index));  // Don't overwrite anything.
10158   Handle<WeakCell> cell =
10159       value->IsMap() ? Map::WeakCellForMap(Handle<Map>::cast(value))
10160                      : array->GetIsolate()->factory()->NewWeakCell(value);
10161   Handle<FixedArray>::cast(array)->set(index + kFirstIndex, *cell);
10162   array->set_last_used_index(index);
10163 }
10164 
10165 
10166 // static
Add(Handle<Object> maybe_array,Handle<HeapObject> value,int * assigned_index)10167 Handle<FixedArrayOfWeakCells> FixedArrayOfWeakCells::Add(
10168     Handle<Object> maybe_array, Handle<HeapObject> value, int* assigned_index) {
10169   Handle<FixedArrayOfWeakCells> array =
10170       (maybe_array.is_null() || !maybe_array->IsFixedArrayOfWeakCells())
10171           ? Allocate(value->GetIsolate(), 1,
10172                      Handle<FixedArrayOfWeakCells>::null())
10173           : Handle<FixedArrayOfWeakCells>::cast(maybe_array);
10174   // Try to store the new entry if there's room. Optimize for consecutive
10175   // accesses.
10176   int first_index = array->last_used_index();
10177   int length = array->Length();
10178   if (length > 0) {
10179     for (int i = first_index;;) {
10180       if (array->IsEmptySlot((i))) {
10181         FixedArrayOfWeakCells::Set(array, i, value);
10182         if (assigned_index != nullptr) *assigned_index = i;
10183         return array;
10184       }
10185       i = (i + 1) % length;
10186       if (i == first_index) break;
10187     }
10188   }
10189 
10190   // No usable slot found, grow the array.
10191   int new_length = length == 0 ? 1 : length + (length >> 1) + 4;
10192   Handle<FixedArrayOfWeakCells> new_array =
10193       Allocate(array->GetIsolate(), new_length, array);
10194   FixedArrayOfWeakCells::Set(new_array, length, value);
10195   if (assigned_index != nullptr) *assigned_index = length;
10196   return new_array;
10197 }
10198 
10199 template <class CompactionCallback>
Compact()10200 void FixedArrayOfWeakCells::Compact() {
10201   FixedArray* array = FixedArray::cast(this);
10202   int new_length = kFirstIndex;
10203   for (int i = kFirstIndex; i < array->length(); i++) {
10204     Object* element = array->get(i);
10205     if (element->IsSmi()) continue;
10206     if (WeakCell::cast(element)->cleared()) continue;
10207     Object* value = WeakCell::cast(element)->value();
10208     CompactionCallback::Callback(value, i - kFirstIndex,
10209                                  new_length - kFirstIndex);
10210     array->set(new_length++, element);
10211   }
10212   array->Shrink(new_length);
10213   set_last_used_index(0);
10214 }
10215 
Reset(Object * maybe_array)10216 void FixedArrayOfWeakCells::Iterator::Reset(Object* maybe_array) {
10217   if (maybe_array->IsFixedArrayOfWeakCells()) {
10218     list_ = FixedArrayOfWeakCells::cast(maybe_array);
10219     index_ = 0;
10220 #ifdef DEBUG
10221     last_used_index_ = list_->last_used_index();
10222 #endif  // DEBUG
10223   }
10224 }
10225 
10226 
Callback(Object * value,int old_index,int new_index)10227 void JSObject::PrototypeRegistryCompactionCallback::Callback(Object* value,
10228                                                              int old_index,
10229                                                              int new_index) {
10230   DCHECK(value->IsMap() && Map::cast(value)->is_prototype_map());
10231   Map* map = Map::cast(value);
10232   DCHECK(map->prototype_info()->IsPrototypeInfo());
10233   PrototypeInfo* proto_info = PrototypeInfo::cast(map->prototype_info());
10234   DCHECK_EQ(old_index, proto_info->registry_slot());
10235   proto_info->set_registry_slot(new_index);
10236 }
10237 
10238 template void
10239 FixedArrayOfWeakCells::Compact<FixedArrayOfWeakCells::NullCallback>();
10240 template void
10241 FixedArrayOfWeakCells::Compact<JSObject::PrototypeRegistryCompactionCallback>();
10242 
Remove(Handle<HeapObject> value)10243 bool FixedArrayOfWeakCells::Remove(Handle<HeapObject> value) {
10244   if (Length() == 0) return false;
10245   // Optimize for the most recently added element to be removed again.
10246   int first_index = last_used_index();
10247   for (int i = first_index;;) {
10248     if (Get(i) == *value) {
10249       Clear(i);
10250       // Users of FixedArrayOfWeakCells should make sure that there are no
10251       // duplicates.
10252       return true;
10253     }
10254     i = (i + 1) % Length();
10255     if (i == first_index) return false;
10256   }
10257   UNREACHABLE();
10258 }
10259 
10260 
10261 // static
Allocate(Isolate * isolate,int size,Handle<FixedArrayOfWeakCells> initialize_from)10262 Handle<FixedArrayOfWeakCells> FixedArrayOfWeakCells::Allocate(
10263     Isolate* isolate, int size, Handle<FixedArrayOfWeakCells> initialize_from) {
10264   DCHECK_LE(0, size);
10265   Handle<FixedArray> result =
10266       isolate->factory()->NewUninitializedFixedArray(size + kFirstIndex);
10267   int index = 0;
10268   if (!initialize_from.is_null()) {
10269     DCHECK(initialize_from->Length() <= size);
10270     Handle<FixedArray> raw_source = Handle<FixedArray>::cast(initialize_from);
10271     // Copy the entries without compacting, since the PrototypeInfo relies on
10272     // the index of the entries not to change.
10273     while (index < raw_source->length()) {
10274       result->set(index, raw_source->get(index));
10275       index++;
10276     }
10277   }
10278   while (index < result->length()) {
10279     result->set(index, Smi::kZero);
10280     index++;
10281   }
10282   return Handle<FixedArrayOfWeakCells>::cast(result);
10283 }
10284 
10285 // static
Add(Handle<ArrayList> array,Handle<Object> obj)10286 Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj) {
10287   int length = array->Length();
10288   array = EnsureSpace(array, length + 1);
10289   // Check that GC didn't remove elements from the array.
10290   DCHECK_EQ(array->Length(), length);
10291   array->Set(length, *obj);
10292   array->SetLength(length + 1);
10293   return array;
10294 }
10295 
10296 // static
Add(Handle<ArrayList> array,Handle<Object> obj1,Handle<Object> obj2)10297 Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj1,
10298                                  Handle<Object> obj2) {
10299   int length = array->Length();
10300   array = EnsureSpace(array, length + 2);
10301   // Check that GC didn't remove elements from the array.
10302   DCHECK_EQ(array->Length(), length);
10303   array->Set(length, *obj1);
10304   array->Set(length + 1, *obj2);
10305   array->SetLength(length + 2);
10306   return array;
10307 }
10308 
10309 // static
New(Isolate * isolate,int size)10310 Handle<ArrayList> ArrayList::New(Isolate* isolate, int size) {
10311   Handle<FixedArray> fixed_array =
10312       isolate->factory()->NewFixedArray(size + kFirstIndex);
10313   fixed_array->set_map_no_write_barrier(isolate->heap()->array_list_map());
10314   Handle<ArrayList> result = Handle<ArrayList>::cast(fixed_array);
10315   result->SetLength(0);
10316   return result;
10317 }
10318 
Elements(Handle<ArrayList> array)10319 Handle<FixedArray> ArrayList::Elements(Handle<ArrayList> array) {
10320   int length = array->Length();
10321   Handle<FixedArray> result =
10322       array->GetIsolate()->factory()->NewFixedArray(length);
10323   // Do not copy the first entry, i.e., the length.
10324   array->CopyTo(kFirstIndex, *result, 0, length);
10325   return result;
10326 }
10327 
IsFull()10328 bool ArrayList::IsFull() {
10329   int capacity = length();
10330   return kFirstIndex + Length() == capacity;
10331 }
10332 
10333 namespace {
10334 
EnsureSpaceInFixedArray(Handle<FixedArray> array,int length)10335 Handle<FixedArray> EnsureSpaceInFixedArray(Handle<FixedArray> array,
10336                                            int length) {
10337   int capacity = array->length();
10338   if (capacity < length) {
10339     Isolate* isolate = array->GetIsolate();
10340     int new_capacity = length;
10341     new_capacity = new_capacity + Max(new_capacity / 2, 2);
10342     int grow_by = new_capacity - capacity;
10343     array = isolate->factory()->CopyFixedArrayAndGrow(array, grow_by);
10344   }
10345   return array;
10346 }
10347 
10348 }  // namespace
10349 
10350 // static
EnsureSpace(Handle<ArrayList> array,int length)10351 Handle<ArrayList> ArrayList::EnsureSpace(Handle<ArrayList> array, int length) {
10352   const bool empty = (array->length() == 0);
10353   auto ret = EnsureSpaceInFixedArray(array, kFirstIndex + length);
10354   if (empty) {
10355     ret->set_map_no_write_barrier(array->GetHeap()->array_list_map());
10356 
10357     Handle<ArrayList>::cast(ret)->SetLength(0);
10358   }
10359   return Handle<ArrayList>::cast(ret);
10360 }
10361 
10362 // static
Add(Handle<WeakArrayList> array,Handle<HeapObject> obj1,Smi * obj2)10363 Handle<WeakArrayList> WeakArrayList::Add(Handle<WeakArrayList> array,
10364                                          Handle<HeapObject> obj1, Smi* obj2) {
10365   int length = array->length();
10366   array = EnsureSpace(array, length + 2);
10367   // Check that GC didn't remove elements from the array.
10368   DCHECK_EQ(array->length(), length);
10369   array->Set(length, HeapObjectReference::Weak(*obj1));
10370   array->Set(length + 1, MaybeObject::FromSmi(obj2));
10371   array->set_length(length + 2);
10372   return array;
10373 }
10374 
IsFull()10375 bool WeakArrayList::IsFull() { return length() == capacity(); }
10376 
10377 // static
EnsureSpace(Handle<WeakArrayList> array,int length)10378 Handle<WeakArrayList> WeakArrayList::EnsureSpace(Handle<WeakArrayList> array,
10379                                                  int length) {
10380   int capacity = array->capacity();
10381   if (capacity < length) {
10382     Isolate* isolate = array->GetIsolate();
10383     int new_capacity = length;
10384     new_capacity = new_capacity + Max(new_capacity / 2, 2);
10385     int grow_by = new_capacity - capacity;
10386     array = isolate->factory()->CopyWeakArrayListAndGrow(array, grow_by);
10387   }
10388   return array;
10389 }
10390 
ReserveCaptures(Handle<RegExpMatchInfo> match_info,int capture_count)10391 Handle<RegExpMatchInfo> RegExpMatchInfo::ReserveCaptures(
10392     Handle<RegExpMatchInfo> match_info, int capture_count) {
10393   DCHECK_GE(match_info->length(), kLastMatchOverhead);
10394   const int required_length = kFirstCaptureIndex + capture_count;
10395   Handle<FixedArray> result =
10396       EnsureSpaceInFixedArray(match_info, required_length);
10397   return Handle<RegExpMatchInfo>::cast(result);
10398 }
10399 
10400 // static
AppendJSFrame(Handle<FrameArray> in,Handle<Object> receiver,Handle<JSFunction> function,Handle<AbstractCode> code,int offset,int flags)10401 Handle<FrameArray> FrameArray::AppendJSFrame(Handle<FrameArray> in,
10402                                              Handle<Object> receiver,
10403                                              Handle<JSFunction> function,
10404                                              Handle<AbstractCode> code,
10405                                              int offset, int flags) {
10406   const int frame_count = in->FrameCount();
10407   const int new_length = LengthFor(frame_count + 1);
10408   Handle<FrameArray> array = EnsureSpace(in, new_length);
10409   array->SetReceiver(frame_count, *receiver);
10410   array->SetFunction(frame_count, *function);
10411   array->SetCode(frame_count, *code);
10412   array->SetOffset(frame_count, Smi::FromInt(offset));
10413   array->SetFlags(frame_count, Smi::FromInt(flags));
10414   array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));
10415   return array;
10416 }
10417 
10418 // static
AppendWasmFrame(Handle<FrameArray> in,Handle<WasmInstanceObject> wasm_instance,int wasm_function_index,wasm::WasmCode * code,int offset,int flags)10419 Handle<FrameArray> FrameArray::AppendWasmFrame(
10420     Handle<FrameArray> in, Handle<WasmInstanceObject> wasm_instance,
10421     int wasm_function_index, wasm::WasmCode* code, int offset, int flags) {
10422   const int frame_count = in->FrameCount();
10423   const int new_length = LengthFor(frame_count + 1);
10424   Handle<FrameArray> array = EnsureSpace(in, new_length);
10425   array->SetWasmInstance(frame_count, *wasm_instance);
10426   array->SetWasmFunctionIndex(frame_count, Smi::FromInt(wasm_function_index));
10427   // The {code} will be {nullptr} for interpreted wasm frames.
10428   array->SetIsWasmInterpreterFrame(frame_count, Smi::FromInt(code == nullptr));
10429   array->SetOffset(frame_count, Smi::FromInt(offset));
10430   array->SetFlags(frame_count, Smi::FromInt(flags));
10431   array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));
10432   return array;
10433 }
10434 
ShrinkToFit()10435 void FrameArray::ShrinkToFit() { Shrink(LengthFor(FrameCount())); }
10436 
10437 // static
EnsureSpace(Handle<FrameArray> array,int length)10438 Handle<FrameArray> FrameArray::EnsureSpace(Handle<FrameArray> array,
10439                                            int length) {
10440   return Handle<FrameArray>::cast(EnsureSpaceInFixedArray(array, length));
10441 }
10442 
Allocate(Isolate * isolate,int number_of_descriptors,int slack,PretenureFlag pretenure)10443 Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate,
10444                                                   int number_of_descriptors,
10445                                                   int slack,
10446                                                   PretenureFlag pretenure) {
10447   DCHECK_LE(0, number_of_descriptors);
10448   Factory* factory = isolate->factory();
10449   // Do not use DescriptorArray::cast on incomplete object.
10450   int size = number_of_descriptors + slack;
10451   if (size == 0) return factory->empty_descriptor_array();
10452   // Allocate the array of keys.
10453   Handle<FixedArray> result = factory->NewFixedArrayWithMap(
10454       Heap::kDescriptorArrayMapRootIndex, LengthFor(size), pretenure);
10455   result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors));
10456   result->set(kEnumCacheIndex, isolate->heap()->empty_enum_cache());
10457   return Handle<DescriptorArray>::cast(result);
10458 }
10459 
ClearEnumCache()10460 void DescriptorArray::ClearEnumCache() {
10461   set(kEnumCacheIndex, GetHeap()->empty_enum_cache());
10462 }
10463 
Replace(int index,Descriptor * descriptor)10464 void DescriptorArray::Replace(int index, Descriptor* descriptor) {
10465   descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index));
10466   Set(index, descriptor);
10467 }
10468 
10469 // static
SetEnumCache(Handle<DescriptorArray> descriptors,Isolate * isolate,Handle<FixedArray> keys,Handle<FixedArray> indices)10470 void DescriptorArray::SetEnumCache(Handle<DescriptorArray> descriptors,
10471                                    Isolate* isolate, Handle<FixedArray> keys,
10472                                    Handle<FixedArray> indices) {
10473   EnumCache* enum_cache = descriptors->GetEnumCache();
10474   if (enum_cache == isolate->heap()->empty_enum_cache()) {
10475     enum_cache = *isolate->factory()->NewEnumCache(keys, indices);
10476     descriptors->set(kEnumCacheIndex, enum_cache);
10477   } else {
10478     enum_cache->set_keys(*keys);
10479     enum_cache->set_indices(*indices);
10480   }
10481 }
10482 
CopyFrom(int index,DescriptorArray * src)10483 void DescriptorArray::CopyFrom(int index, DescriptorArray* src) {
10484   PropertyDetails details = src->GetDetails(index);
10485   Set(index, src->GetKey(index), src->GetValue(index), details);
10486 }
10487 
Sort()10488 void DescriptorArray::Sort() {
10489   // In-place heap sort.
10490   int len = number_of_descriptors();
10491   // Reset sorting since the descriptor array might contain invalid pointers.
10492   for (int i = 0; i < len; ++i) SetSortedKey(i, i);
10493   // Bottom-up max-heap construction.
10494   // Index of the last node with children
10495   const int max_parent_index = (len / 2) - 1;
10496   for (int i = max_parent_index; i >= 0; --i) {
10497     int parent_index = i;
10498     const uint32_t parent_hash = GetSortedKey(i)->Hash();
10499     while (parent_index <= max_parent_index) {
10500       int child_index = 2 * parent_index + 1;
10501       uint32_t child_hash = GetSortedKey(child_index)->Hash();
10502       if (child_index + 1 < len) {
10503         uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
10504         if (right_child_hash > child_hash) {
10505           child_index++;
10506           child_hash = right_child_hash;
10507         }
10508       }
10509       if (child_hash <= parent_hash) break;
10510       SwapSortedKeys(parent_index, child_index);
10511       // Now element at child_index could be < its children.
10512       parent_index = child_index;  // parent_hash remains correct.
10513     }
10514   }
10515 
10516   // Extract elements and create sorted array.
10517   for (int i = len - 1; i > 0; --i) {
10518     // Put max element at the back of the array.
10519     SwapSortedKeys(0, i);
10520     // Shift down the new top element.
10521     int parent_index = 0;
10522     const uint32_t parent_hash = GetSortedKey(parent_index)->Hash();
10523     const int max_parent_index = (i / 2) - 1;
10524     while (parent_index <= max_parent_index) {
10525       int child_index = parent_index * 2 + 1;
10526       uint32_t child_hash = GetSortedKey(child_index)->Hash();
10527       if (child_index + 1 < i) {
10528         uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
10529         if (right_child_hash > child_hash) {
10530           child_index++;
10531           child_hash = right_child_hash;
10532         }
10533       }
10534       if (child_hash <= parent_hash) break;
10535       SwapSortedKeys(parent_index, child_index);
10536       parent_index = child_index;
10537     }
10538   }
10539   DCHECK(IsSortedNoDuplicates());
10540 }
10541 
10542 
Copy(Handle<AccessorPair> pair)10543 Handle<AccessorPair> AccessorPair::Copy(Handle<AccessorPair> pair) {
10544   Handle<AccessorPair> copy = pair->GetIsolate()->factory()->NewAccessorPair();
10545   copy->set_getter(pair->getter());
10546   copy->set_setter(pair->setter());
10547   return copy;
10548 }
10549 
GetComponent(Handle<AccessorPair> accessor_pair,AccessorComponent component)10550 Handle<Object> AccessorPair::GetComponent(Handle<AccessorPair> accessor_pair,
10551                                           AccessorComponent component) {
10552   Object* accessor = accessor_pair->get(component);
10553   if (accessor->IsFunctionTemplateInfo()) {
10554     return ApiNatives::InstantiateFunction(
10555                handle(FunctionTemplateInfo::cast(accessor)))
10556         .ToHandleChecked();
10557   }
10558   Isolate* isolate = accessor_pair->GetIsolate();
10559   if (accessor->IsNull(isolate)) {
10560     return isolate->factory()->undefined_value();
10561   }
10562   return handle(accessor, isolate);
10563 }
10564 
New(Isolate * isolate,int deopt_entry_count,PretenureFlag pretenure)10565 Handle<DeoptimizationData> DeoptimizationData::New(Isolate* isolate,
10566                                                    int deopt_entry_count,
10567                                                    PretenureFlag pretenure) {
10568   return Handle<DeoptimizationData>::cast(isolate->factory()->NewFixedArray(
10569       LengthFor(deopt_entry_count), pretenure));
10570 }
10571 
Empty(Isolate * isolate)10572 Handle<DeoptimizationData> DeoptimizationData::Empty(Isolate* isolate) {
10573   return Handle<DeoptimizationData>::cast(
10574       isolate->factory()->empty_fixed_array());
10575 }
10576 
GetInlinedFunction(int index)10577 SharedFunctionInfo* DeoptimizationData::GetInlinedFunction(int index) {
10578   if (index == -1) {
10579     return SharedFunctionInfo::cast(SharedFunctionInfo());
10580   } else {
10581     return SharedFunctionInfo::cast(LiteralArray()->get(index));
10582   }
10583 }
10584 
10585 #ifdef DEBUG
IsEqualTo(DescriptorArray * other)10586 bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
10587   if (length() != other->length()) return false;
10588   for (int i = 0; i < length(); ++i) {
10589     if (get(i) != other->get(i)) return false;
10590   }
10591   return true;
10592 }
10593 #endif
10594 
10595 // static
Trim(Handle<String> string,TrimMode mode)10596 Handle<String> String::Trim(Handle<String> string, TrimMode mode) {
10597   Isolate* const isolate = string->GetIsolate();
10598   string = String::Flatten(string);
10599   int const length = string->length();
10600 
10601   // Perform left trimming if requested.
10602   int left = 0;
10603   UnicodeCache* unicode_cache = isolate->unicode_cache();
10604   if (mode == kTrim || mode == kTrimStart) {
10605     while (left < length &&
10606            unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) {
10607       left++;
10608     }
10609   }
10610 
10611   // Perform right trimming if requested.
10612   int right = length;
10613   if (mode == kTrim || mode == kTrimEnd) {
10614     while (
10615         right > left &&
10616         unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) {
10617       right--;
10618     }
10619   }
10620 
10621   return isolate->factory()->NewSubString(string, left, right);
10622 }
10623 
LooksValid()10624 bool String::LooksValid() { return GetIsolate()->heap()->Contains(this); }
10625 
10626 // static
ToFunctionName(Handle<Name> name)10627 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) {
10628   if (name->IsString()) return Handle<String>::cast(name);
10629   // ES6 section 9.2.11 SetFunctionName, step 4.
10630   Isolate* const isolate = name->GetIsolate();
10631   Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate);
10632   if (description->IsUndefined(isolate)) {
10633     return isolate->factory()->empty_string();
10634   }
10635   IncrementalStringBuilder builder(isolate);
10636   builder.AppendCharacter('[');
10637   builder.AppendString(Handle<String>::cast(description));
10638   builder.AppendCharacter(']');
10639   return builder.Finish();
10640 }
10641 
10642 // static
ToFunctionName(Handle<Name> name,Handle<String> prefix)10643 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name,
10644                                          Handle<String> prefix) {
10645   Handle<String> name_string;
10646   Isolate* const isolate = name->GetIsolate();
10647   ASSIGN_RETURN_ON_EXCEPTION(isolate, name_string, ToFunctionName(name),
10648                              String);
10649   IncrementalStringBuilder builder(isolate);
10650   builder.AppendString(prefix);
10651   builder.AppendCharacter(' ');
10652   builder.AppendString(name_string);
10653   return builder.Finish();
10654 }
10655 
10656 namespace {
10657 
AreDigits(const uint8_t * s,int from,int to)10658 bool AreDigits(const uint8_t* s, int from, int to) {
10659   for (int i = from; i < to; i++) {
10660     if (s[i] < '0' || s[i] > '9') return false;
10661   }
10662 
10663   return true;
10664 }
10665 
10666 
ParseDecimalInteger(const uint8_t * s,int from,int to)10667 int ParseDecimalInteger(const uint8_t* s, int from, int to) {
10668   DCHECK_LT(to - from, 10);  // Overflow is not possible.
10669   DCHECK(from < to);
10670   int d = s[from] - '0';
10671 
10672   for (int i = from + 1; i < to; i++) {
10673     d = 10 * d + (s[i] - '0');
10674   }
10675 
10676   return d;
10677 }
10678 
10679 }  // namespace
10680 
10681 // static
ToNumber(Handle<String> subject)10682 Handle<Object> String::ToNumber(Handle<String> subject) {
10683   Isolate* const isolate = subject->GetIsolate();
10684 
10685   // Flatten {subject} string first.
10686   subject = String::Flatten(subject);
10687 
10688   // Fast array index case.
10689   uint32_t index;
10690   if (subject->AsArrayIndex(&index)) {
10691     return isolate->factory()->NewNumberFromUint(index);
10692   }
10693 
10694   // Fast case: short integer or some sorts of junk values.
10695   if (subject->IsSeqOneByteString()) {
10696     int len = subject->length();
10697     if (len == 0) return handle(Smi::kZero, isolate);
10698 
10699     DisallowHeapAllocation no_gc;
10700     uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars();
10701     bool minus = (data[0] == '-');
10702     int start_pos = (minus ? 1 : 0);
10703 
10704     if (start_pos == len) {
10705       return isolate->factory()->nan_value();
10706     } else if (data[start_pos] > '9') {
10707       // Fast check for a junk value. A valid string may start from a
10708       // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit
10709       // or the 'I' character ('Infinity'). All of that have codes not greater
10710       // than '9' except 'I' and &nbsp;.
10711       if (data[start_pos] != 'I' && data[start_pos] != 0xA0) {
10712         return isolate->factory()->nan_value();
10713       }
10714     } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
10715       // The maximal/minimal smi has 10 digits. If the string has less digits
10716       // we know it will fit into the smi-data type.
10717       int d = ParseDecimalInteger(data, start_pos, len);
10718       if (minus) {
10719         if (d == 0) return isolate->factory()->minus_zero_value();
10720         d = -d;
10721       } else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize &&
10722                  (len == 1 || data[0] != '0')) {
10723         // String hash is not calculated yet but all the data are present.
10724         // Update the hash field to speed up sequential convertions.
10725         uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
10726 #ifdef DEBUG
10727         subject->Hash();  // Force hash calculation.
10728         DCHECK_EQ(static_cast<int>(subject->hash_field()),
10729                   static_cast<int>(hash));
10730 #endif
10731         subject->set_hash_field(hash);
10732       }
10733       return handle(Smi::FromInt(d), isolate);
10734     }
10735   }
10736 
10737   // Slower case.
10738   int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY;
10739   return isolate->factory()->NewNumber(
10740       StringToDouble(isolate->unicode_cache(), subject, flags));
10741 }
10742 
10743 
GetFlatContent()10744 String::FlatContent String::GetFlatContent() {
10745   DCHECK(!AllowHeapAllocation::IsAllowed());
10746   int length = this->length();
10747   StringShape shape(this);
10748   String* string = this;
10749   int offset = 0;
10750   if (shape.representation_tag() == kConsStringTag) {
10751     ConsString* cons = ConsString::cast(string);
10752     if (cons->second()->length() != 0) {
10753       return FlatContent();
10754     }
10755     string = cons->first();
10756     shape = StringShape(string);
10757   } else if (shape.representation_tag() == kSlicedStringTag) {
10758     SlicedString* slice = SlicedString::cast(string);
10759     offset = slice->offset();
10760     string = slice->parent();
10761     shape = StringShape(string);
10762     DCHECK(shape.representation_tag() != kConsStringTag &&
10763            shape.representation_tag() != kSlicedStringTag);
10764   }
10765   if (shape.representation_tag() == kThinStringTag) {
10766     ThinString* thin = ThinString::cast(string);
10767     string = thin->actual();
10768     shape = StringShape(string);
10769     DCHECK(!shape.IsCons());
10770     DCHECK(!shape.IsSliced());
10771   }
10772   if (shape.encoding_tag() == kOneByteStringTag) {
10773     const uint8_t* start;
10774     if (shape.representation_tag() == kSeqStringTag) {
10775       start = SeqOneByteString::cast(string)->GetChars();
10776     } else {
10777       start = ExternalOneByteString::cast(string)->GetChars();
10778     }
10779     return FlatContent(start + offset, length);
10780   } else {
10781     DCHECK_EQ(shape.encoding_tag(), kTwoByteStringTag);
10782     const uc16* start;
10783     if (shape.representation_tag() == kSeqStringTag) {
10784       start = SeqTwoByteString::cast(string)->GetChars();
10785     } else {
10786       start = ExternalTwoByteString::cast(string)->GetChars();
10787     }
10788     return FlatContent(start + offset, length);
10789   }
10790 }
10791 
ToCString(AllowNullsFlag allow_nulls,RobustnessFlag robust_flag,int offset,int length,int * length_return)10792 std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
10793                                           RobustnessFlag robust_flag,
10794                                           int offset, int length,
10795                                           int* length_return) {
10796   if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
10797     return std::unique_ptr<char[]>();
10798   }
10799   // Negative length means the to the end of the string.
10800   if (length < 0) length = kMaxInt - offset;
10801 
10802   // Compute the size of the UTF-8 string. Start at the specified offset.
10803   StringCharacterStream stream(this, offset);
10804   int character_position = offset;
10805   int utf8_bytes = 0;
10806   int last = unibrow::Utf16::kNoPreviousCharacter;
10807   while (stream.HasMore() && character_position++ < offset + length) {
10808     uint16_t character = stream.GetNext();
10809     utf8_bytes += unibrow::Utf8::Length(character, last);
10810     last = character;
10811   }
10812 
10813   if (length_return) {
10814     *length_return = utf8_bytes;
10815   }
10816 
10817   char* result = NewArray<char>(utf8_bytes + 1);
10818 
10819   // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
10820   stream.Reset(this, offset);
10821   character_position = offset;
10822   int utf8_byte_position = 0;
10823   last = unibrow::Utf16::kNoPreviousCharacter;
10824   while (stream.HasMore() && character_position++ < offset + length) {
10825     uint16_t character = stream.GetNext();
10826     if (allow_nulls == DISALLOW_NULLS && character == 0) {
10827       character = ' ';
10828     }
10829     utf8_byte_position +=
10830         unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
10831     last = character;
10832   }
10833   result[utf8_byte_position] = 0;
10834   return std::unique_ptr<char[]>(result);
10835 }
10836 
ToCString(AllowNullsFlag allow_nulls,RobustnessFlag robust_flag,int * length_return)10837 std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
10838                                           RobustnessFlag robust_flag,
10839                                           int* length_return) {
10840   return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
10841 }
10842 
10843 
GetTwoByteData(unsigned start)10844 const uc16* String::GetTwoByteData(unsigned start) {
10845   DCHECK(!IsOneByteRepresentationUnderneath());
10846   switch (StringShape(this).representation_tag()) {
10847     case kSeqStringTag:
10848       return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
10849     case kExternalStringTag:
10850       return ExternalTwoByteString::cast(this)->
10851         ExternalTwoByteStringGetData(start);
10852     case kSlicedStringTag: {
10853       SlicedString* slice = SlicedString::cast(this);
10854       return slice->parent()->GetTwoByteData(start + slice->offset());
10855     }
10856     case kConsStringTag:
10857     case kThinStringTag:
10858       UNREACHABLE();
10859   }
10860   UNREACHABLE();
10861 }
10862 
10863 
SeqTwoByteStringGetData(unsigned start)10864 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
10865   return reinterpret_cast<uc16*>(
10866       reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
10867 }
10868 
10869 
PostGarbageCollectionProcessing(Isolate * isolate)10870 void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) {
10871   Relocatable* current = isolate->relocatable_top();
10872   while (current != nullptr) {
10873     current->PostGarbageCollection();
10874     current = current->prev_;
10875   }
10876 }
10877 
10878 
10879 // Reserve space for statics needing saving and restoring.
ArchiveSpacePerThread()10880 int Relocatable::ArchiveSpacePerThread() {
10881   return sizeof(Relocatable*);  // NOLINT
10882 }
10883 
10884 
10885 // Archive statics that are thread-local.
ArchiveState(Isolate * isolate,char * to)10886 char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
10887   *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
10888   isolate->set_relocatable_top(nullptr);
10889   return to + ArchiveSpacePerThread();
10890 }
10891 
10892 
10893 // Restore statics that are thread-local.
RestoreState(Isolate * isolate,char * from)10894 char* Relocatable::RestoreState(Isolate* isolate, char* from) {
10895   isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
10896   return from + ArchiveSpacePerThread();
10897 }
10898 
Iterate(RootVisitor * v,char * thread_storage)10899 char* Relocatable::Iterate(RootVisitor* v, char* thread_storage) {
10900   Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
10901   Iterate(v, top);
10902   return thread_storage + ArchiveSpacePerThread();
10903 }
10904 
Iterate(Isolate * isolate,RootVisitor * v)10905 void Relocatable::Iterate(Isolate* isolate, RootVisitor* v) {
10906   Iterate(v, isolate->relocatable_top());
10907 }
10908 
Iterate(RootVisitor * v,Relocatable * top)10909 void Relocatable::Iterate(RootVisitor* v, Relocatable* top) {
10910   Relocatable* current = top;
10911   while (current != nullptr) {
10912     current->IterateInstance(v);
10913     current = current->prev_;
10914   }
10915 }
10916 
10917 
FlatStringReader(Isolate * isolate,Handle<String> str)10918 FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
10919     : Relocatable(isolate),
10920       str_(str.location()),
10921       length_(str->length()) {
10922   PostGarbageCollection();
10923 }
10924 
10925 
FlatStringReader(Isolate * isolate,Vector<const char> input)10926 FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
10927     : Relocatable(isolate),
10928       str_(0),
10929       is_one_byte_(true),
10930       length_(input.length()),
10931       start_(input.start()) {}
10932 
10933 
PostGarbageCollection()10934 void FlatStringReader::PostGarbageCollection() {
10935   if (str_ == nullptr) return;
10936   Handle<String> str(str_);
10937   DCHECK(str->IsFlat());
10938   DisallowHeapAllocation no_gc;
10939   // This does not actually prevent the vector from being relocated later.
10940   String::FlatContent content = str->GetFlatContent();
10941   DCHECK(content.IsFlat());
10942   is_one_byte_ = content.IsOneByte();
10943   if (is_one_byte_) {
10944     start_ = content.ToOneByteVector().start();
10945   } else {
10946     start_ = content.ToUC16Vector().start();
10947   }
10948 }
10949 
10950 
Initialize(ConsString * cons_string,int offset)10951 void ConsStringIterator::Initialize(ConsString* cons_string, int offset) {
10952   DCHECK_NOT_NULL(cons_string);
10953   root_ = cons_string;
10954   consumed_ = offset;
10955   // Force stack blown condition to trigger restart.
10956   depth_ = 1;
10957   maximum_depth_ = kStackSize + depth_;
10958   DCHECK(StackBlown());
10959 }
10960 
10961 
Continue(int * offset_out)10962 String* ConsStringIterator::Continue(int* offset_out) {
10963   DCHECK_NE(depth_, 0);
10964   DCHECK_EQ(0, *offset_out);
10965   bool blew_stack = StackBlown();
10966   String* string = nullptr;
10967   // Get the next leaf if there is one.
10968   if (!blew_stack) string = NextLeaf(&blew_stack);
10969   // Restart search from root.
10970   if (blew_stack) {
10971     DCHECK_NULL(string);
10972     string = Search(offset_out);
10973   }
10974   // Ensure future calls return null immediately.
10975   if (string == nullptr) Reset(nullptr);
10976   return string;
10977 }
10978 
10979 
Search(int * offset_out)10980 String* ConsStringIterator::Search(int* offset_out) {
10981   ConsString* cons_string = root_;
10982   // Reset the stack, pushing the root string.
10983   depth_ = 1;
10984   maximum_depth_ = 1;
10985   frames_[0] = cons_string;
10986   const int consumed = consumed_;
10987   int offset = 0;
10988   while (true) {
10989     // Loop until the string is found which contains the target offset.
10990     String* string = cons_string->first();
10991     int length = string->length();
10992     int32_t type;
10993     if (consumed < offset + length) {
10994       // Target offset is in the left branch.
10995       // Keep going if we're still in a ConString.
10996       type = string->map()->instance_type();
10997       if ((type & kStringRepresentationMask) == kConsStringTag) {
10998         cons_string = ConsString::cast(string);
10999         PushLeft(cons_string);
11000         continue;
11001       }
11002       // Tell the stack we're done descending.
11003       AdjustMaximumDepth();
11004     } else {
11005       // Descend right.
11006       // Update progress through the string.
11007       offset += length;
11008       // Keep going if we're still in a ConString.
11009       string = cons_string->second();
11010       type = string->map()->instance_type();
11011       if ((type & kStringRepresentationMask) == kConsStringTag) {
11012         cons_string = ConsString::cast(string);
11013         PushRight(cons_string);
11014         continue;
11015       }
11016       // Need this to be updated for the current string.
11017       length = string->length();
11018       // Account for the possibility of an empty right leaf.
11019       // This happens only if we have asked for an offset outside the string.
11020       if (length == 0) {
11021         // Reset so future operations will return null immediately.
11022         Reset(nullptr);
11023         return nullptr;
11024       }
11025       // Tell the stack we're done descending.
11026       AdjustMaximumDepth();
11027       // Pop stack so next iteration is in correct place.
11028       Pop();
11029     }
11030     DCHECK_NE(length, 0);
11031     // Adjust return values and exit.
11032     consumed_ = offset + length;
11033     *offset_out = consumed - offset;
11034     return string;
11035   }
11036   UNREACHABLE();
11037 }
11038 
11039 
NextLeaf(bool * blew_stack)11040 String* ConsStringIterator::NextLeaf(bool* blew_stack) {
11041   while (true) {
11042     // Tree traversal complete.
11043     if (depth_ == 0) {
11044       *blew_stack = false;
11045       return nullptr;
11046     }
11047     // We've lost track of higher nodes.
11048     if (StackBlown()) {
11049       *blew_stack = true;
11050       return nullptr;
11051     }
11052     // Go right.
11053     ConsString* cons_string = frames_[OffsetForDepth(depth_ - 1)];
11054     String* string = cons_string->second();
11055     int32_t type = string->map()->instance_type();
11056     if ((type & kStringRepresentationMask) != kConsStringTag) {
11057       // Pop stack so next iteration is in correct place.
11058       Pop();
11059       int length = string->length();
11060       // Could be a flattened ConsString.
11061       if (length == 0) continue;
11062       consumed_ += length;
11063       return string;
11064     }
11065     cons_string = ConsString::cast(string);
11066     PushRight(cons_string);
11067     // Need to traverse all the way left.
11068     while (true) {
11069       // Continue left.
11070       string = cons_string->first();
11071       type = string->map()->instance_type();
11072       if ((type & kStringRepresentationMask) != kConsStringTag) {
11073         AdjustMaximumDepth();
11074         int length = string->length();
11075         if (length == 0) break;  // Skip empty left-hand sides of ConsStrings.
11076         consumed_ += length;
11077         return string;
11078       }
11079       cons_string = ConsString::cast(string);
11080       PushLeft(cons_string);
11081     }
11082   }
11083   UNREACHABLE();
11084 }
11085 
11086 
ConsStringGet(int index)11087 uint16_t ConsString::ConsStringGet(int index) {
11088   DCHECK(index >= 0 && index < this->length());
11089 
11090   // Check for a flattened cons string
11091   if (second()->length() == 0) {
11092     String* left = first();
11093     return left->Get(index);
11094   }
11095 
11096   String* string = String::cast(this);
11097 
11098   while (true) {
11099     if (StringShape(string).IsCons()) {
11100       ConsString* cons_string = ConsString::cast(string);
11101       String* left = cons_string->first();
11102       if (left->length() > index) {
11103         string = left;
11104       } else {
11105         index -= left->length();
11106         string = cons_string->second();
11107       }
11108     } else {
11109       return string->Get(index);
11110     }
11111   }
11112 
11113   UNREACHABLE();
11114 }
11115 
ThinStringGet(int index)11116 uint16_t ThinString::ThinStringGet(int index) { return actual()->Get(index); }
11117 
SlicedStringGet(int index)11118 uint16_t SlicedString::SlicedStringGet(int index) {
11119   return parent()->Get(offset() + index);
11120 }
11121 
11122 
11123 template <typename sinkchar>
WriteToFlat(String * src,sinkchar * sink,int f,int t)11124 void String::WriteToFlat(String* src,
11125                          sinkchar* sink,
11126                          int f,
11127                          int t) {
11128   String* source = src;
11129   int from = f;
11130   int to = t;
11131   while (true) {
11132     DCHECK(0 <= from && from <= to && to <= source->length());
11133     switch (StringShape(source).full_representation_tag()) {
11134       case kOneByteStringTag | kExternalStringTag: {
11135         CopyChars(sink, ExternalOneByteString::cast(source)->GetChars() + from,
11136                   to - from);
11137         return;
11138       }
11139       case kTwoByteStringTag | kExternalStringTag: {
11140         const uc16* data =
11141             ExternalTwoByteString::cast(source)->GetChars();
11142         CopyChars(sink,
11143                   data + from,
11144                   to - from);
11145         return;
11146       }
11147       case kOneByteStringTag | kSeqStringTag: {
11148         CopyChars(sink,
11149                   SeqOneByteString::cast(source)->GetChars() + from,
11150                   to - from);
11151         return;
11152       }
11153       case kTwoByteStringTag | kSeqStringTag: {
11154         CopyChars(sink,
11155                   SeqTwoByteString::cast(source)->GetChars() + from,
11156                   to - from);
11157         return;
11158       }
11159       case kOneByteStringTag | kConsStringTag:
11160       case kTwoByteStringTag | kConsStringTag: {
11161         ConsString* cons_string = ConsString::cast(source);
11162         String* first = cons_string->first();
11163         int boundary = first->length();
11164         if (to - boundary >= boundary - from) {
11165           // Right hand side is longer.  Recurse over left.
11166           if (from < boundary) {
11167             WriteToFlat(first, sink, from, boundary);
11168             if (from == 0 && cons_string->second() == first) {
11169               CopyChars(sink + boundary, sink, boundary);
11170               return;
11171             }
11172             sink += boundary - from;
11173             from = 0;
11174           } else {
11175             from -= boundary;
11176           }
11177           to -= boundary;
11178           source = cons_string->second();
11179         } else {
11180           // Left hand side is longer.  Recurse over right.
11181           if (to > boundary) {
11182             String* second = cons_string->second();
11183             // When repeatedly appending to a string, we get a cons string that
11184             // is unbalanced to the left, a list, essentially.  We inline the
11185             // common case of sequential one-byte right child.
11186             if (to - boundary == 1) {
11187               sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
11188             } else if (second->IsSeqOneByteString()) {
11189               CopyChars(sink + boundary - from,
11190                         SeqOneByteString::cast(second)->GetChars(),
11191                         to - boundary);
11192             } else {
11193               WriteToFlat(second,
11194                           sink + boundary - from,
11195                           0,
11196                           to - boundary);
11197             }
11198             to = boundary;
11199           }
11200           source = first;
11201         }
11202         break;
11203       }
11204       case kOneByteStringTag | kSlicedStringTag:
11205       case kTwoByteStringTag | kSlicedStringTag: {
11206         SlicedString* slice = SlicedString::cast(source);
11207         unsigned offset = slice->offset();
11208         WriteToFlat(slice->parent(), sink, from + offset, to + offset);
11209         return;
11210       }
11211       case kOneByteStringTag | kThinStringTag:
11212       case kTwoByteStringTag | kThinStringTag:
11213         source = ThinString::cast(source)->actual();
11214         break;
11215     }
11216   }
11217 }
11218 
11219 template <typename SourceChar>
CalculateLineEndsImpl(Isolate * isolate,std::vector<int> * line_ends,Vector<const SourceChar> src,bool include_ending_line)11220 static void CalculateLineEndsImpl(Isolate* isolate, std::vector<int>* line_ends,
11221                                   Vector<const SourceChar> src,
11222                                   bool include_ending_line) {
11223   const int src_len = src.length();
11224   UnicodeCache* cache = isolate->unicode_cache();
11225   for (int i = 0; i < src_len - 1; i++) {
11226     SourceChar current = src[i];
11227     SourceChar next = src[i + 1];
11228     if (cache->IsLineTerminatorSequence(current, next)) line_ends->push_back(i);
11229   }
11230 
11231   if (src_len > 0 && cache->IsLineTerminatorSequence(src[src_len - 1], 0)) {
11232     line_ends->push_back(src_len - 1);
11233   }
11234   if (include_ending_line) {
11235     // Include one character beyond the end of script. The rewriter uses that
11236     // position for the implicit return statement.
11237     line_ends->push_back(src_len);
11238   }
11239 }
11240 
11241 
CalculateLineEnds(Handle<String> src,bool include_ending_line)11242 Handle<FixedArray> String::CalculateLineEnds(Handle<String> src,
11243                                              bool include_ending_line) {
11244   src = Flatten(src);
11245   // Rough estimate of line count based on a roughly estimated average
11246   // length of (unpacked) code.
11247   int line_count_estimate = src->length() >> 4;
11248   std::vector<int> line_ends;
11249   line_ends.reserve(line_count_estimate);
11250   Isolate* isolate = src->GetIsolate();
11251   { DisallowHeapAllocation no_allocation;  // ensure vectors stay valid.
11252     // Dispatch on type of strings.
11253     String::FlatContent content = src->GetFlatContent();
11254     DCHECK(content.IsFlat());
11255     if (content.IsOneByte()) {
11256       CalculateLineEndsImpl(isolate,
11257                             &line_ends,
11258                             content.ToOneByteVector(),
11259                             include_ending_line);
11260     } else {
11261       CalculateLineEndsImpl(isolate,
11262                             &line_ends,
11263                             content.ToUC16Vector(),
11264                             include_ending_line);
11265     }
11266   }
11267   int line_count = static_cast<int>(line_ends.size());
11268   Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count);
11269   for (int i = 0; i < line_count; i++) {
11270     array->set(i, Smi::FromInt(line_ends[i]));
11271   }
11272   return array;
11273 }
11274 
11275 
11276 // Compares the contents of two strings by reading and comparing
11277 // int-sized blocks of characters.
11278 template <typename Char>
CompareRawStringContents(const Char * const a,const Char * const b,int length)11279 static inline bool CompareRawStringContents(const Char* const a,
11280                                             const Char* const b,
11281                                             int length) {
11282   return CompareChars(a, b, length) == 0;
11283 }
11284 
11285 
11286 template<typename Chars1, typename Chars2>
11287 class RawStringComparator : public AllStatic {
11288  public:
compare(const Chars1 * a,const Chars2 * b,int len)11289   static inline bool compare(const Chars1* a, const Chars2* b, int len) {
11290     DCHECK(sizeof(Chars1) != sizeof(Chars2));
11291     for (int i = 0; i < len; i++) {
11292       if (a[i] != b[i]) {
11293         return false;
11294       }
11295     }
11296     return true;
11297   }
11298 };
11299 
11300 
11301 template<>
11302 class RawStringComparator<uint16_t, uint16_t> {
11303  public:
compare(const uint16_t * a,const uint16_t * b,int len)11304   static inline bool compare(const uint16_t* a, const uint16_t* b, int len) {
11305     return CompareRawStringContents(a, b, len);
11306   }
11307 };
11308 
11309 
11310 template<>
11311 class RawStringComparator<uint8_t, uint8_t> {
11312  public:
compare(const uint8_t * a,const uint8_t * b,int len)11313   static inline bool compare(const uint8_t* a, const uint8_t* b, int len) {
11314     return CompareRawStringContents(a, b, len);
11315   }
11316 };
11317 
11318 
11319 class StringComparator {
11320   class State {
11321    public:
State()11322     State() : is_one_byte_(true), length_(0), buffer8_(nullptr) {}
11323 
Init(String * string)11324     void Init(String* string) {
11325       ConsString* cons_string = String::VisitFlat(this, string);
11326       iter_.Reset(cons_string);
11327       if (cons_string != nullptr) {
11328         int offset;
11329         string = iter_.Next(&offset);
11330         String::VisitFlat(this, string, offset);
11331       }
11332     }
11333 
VisitOneByteString(const uint8_t * chars,int length)11334     inline void VisitOneByteString(const uint8_t* chars, int length) {
11335       is_one_byte_ = true;
11336       buffer8_ = chars;
11337       length_ = length;
11338     }
11339 
VisitTwoByteString(const uint16_t * chars,int length)11340     inline void VisitTwoByteString(const uint16_t* chars, int length) {
11341       is_one_byte_ = false;
11342       buffer16_ = chars;
11343       length_ = length;
11344     }
11345 
Advance(int consumed)11346     void Advance(int consumed) {
11347       DCHECK(consumed <= length_);
11348       // Still in buffer.
11349       if (length_ != consumed) {
11350         if (is_one_byte_) {
11351           buffer8_ += consumed;
11352         } else {
11353           buffer16_ += consumed;
11354         }
11355         length_ -= consumed;
11356         return;
11357       }
11358       // Advance state.
11359       int offset;
11360       String* next = iter_.Next(&offset);
11361       DCHECK_EQ(0, offset);
11362       DCHECK_NOT_NULL(next);
11363       String::VisitFlat(this, next);
11364     }
11365 
11366     ConsStringIterator iter_;
11367     bool is_one_byte_;
11368     int length_;
11369     union {
11370       const uint8_t* buffer8_;
11371       const uint16_t* buffer16_;
11372     };
11373 
11374    private:
11375     DISALLOW_COPY_AND_ASSIGN(State);
11376   };
11377 
11378  public:
StringComparator()11379   inline StringComparator() {}
11380 
11381   template<typename Chars1, typename Chars2>
Equals(State * state_1,State * state_2,int to_check)11382   static inline bool Equals(State* state_1, State* state_2, int to_check) {
11383     const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_);
11384     const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_);
11385     return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check);
11386   }
11387 
Equals(String * string_1,String * string_2)11388   bool Equals(String* string_1, String* string_2) {
11389     int length = string_1->length();
11390     state_1_.Init(string_1);
11391     state_2_.Init(string_2);
11392     while (true) {
11393       int to_check = Min(state_1_.length_, state_2_.length_);
11394       DCHECK(to_check > 0 && to_check <= length);
11395       bool is_equal;
11396       if (state_1_.is_one_byte_) {
11397         if (state_2_.is_one_byte_) {
11398           is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check);
11399         } else {
11400           is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check);
11401         }
11402       } else {
11403         if (state_2_.is_one_byte_) {
11404           is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check);
11405         } else {
11406           is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check);
11407         }
11408       }
11409       // Looping done.
11410       if (!is_equal) return false;
11411       length -= to_check;
11412       // Exit condition. Strings are equal.
11413       if (length == 0) return true;
11414       state_1_.Advance(to_check);
11415       state_2_.Advance(to_check);
11416     }
11417   }
11418 
11419  private:
11420   State state_1_;
11421   State state_2_;
11422 
11423   DISALLOW_COPY_AND_ASSIGN(StringComparator);
11424 };
11425 
11426 
SlowEquals(String * other)11427 bool String::SlowEquals(String* other) {
11428   DisallowHeapAllocation no_gc;
11429   // Fast check: negative check with lengths.
11430   int len = length();
11431   if (len != other->length()) return false;
11432   if (len == 0) return true;
11433 
11434   // Fast check: if at least one ThinString is involved, dereference it/them
11435   // and restart.
11436   if (this->IsThinString() || other->IsThinString()) {
11437     if (other->IsThinString()) other = ThinString::cast(other)->actual();
11438     if (this->IsThinString()) {
11439       return ThinString::cast(this)->actual()->Equals(other);
11440     } else {
11441       return this->Equals(other);
11442     }
11443   }
11444 
11445   // Fast check: if hash code is computed for both strings
11446   // a fast negative check can be performed.
11447   if (HasHashCode() && other->HasHashCode()) {
11448 #ifdef ENABLE_SLOW_DCHECKS
11449     if (FLAG_enable_slow_asserts) {
11450       if (Hash() != other->Hash()) {
11451         bool found_difference = false;
11452         for (int i = 0; i < len; i++) {
11453           if (Get(i) != other->Get(i)) {
11454             found_difference = true;
11455             break;
11456           }
11457         }
11458         DCHECK(found_difference);
11459       }
11460     }
11461 #endif
11462     if (Hash() != other->Hash()) return false;
11463   }
11464 
11465   // We know the strings are both non-empty. Compare the first chars
11466   // before we try to flatten the strings.
11467   if (this->Get(0) != other->Get(0)) return false;
11468 
11469   if (IsSeqOneByteString() && other->IsSeqOneByteString()) {
11470     const uint8_t* str1 = SeqOneByteString::cast(this)->GetChars();
11471     const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars();
11472     return CompareRawStringContents(str1, str2, len);
11473   }
11474 
11475   StringComparator comparator;
11476   return comparator.Equals(this, other);
11477 }
11478 
11479 
SlowEquals(Handle<String> one,Handle<String> two)11480 bool String::SlowEquals(Handle<String> one, Handle<String> two) {
11481   // Fast check: negative check with lengths.
11482   int one_length = one->length();
11483   if (one_length != two->length()) return false;
11484   if (one_length == 0) return true;
11485 
11486   // Fast check: if at least one ThinString is involved, dereference it/them
11487   // and restart.
11488   if (one->IsThinString() || two->IsThinString()) {
11489     if (one->IsThinString()) one = handle(ThinString::cast(*one)->actual());
11490     if (two->IsThinString()) two = handle(ThinString::cast(*two)->actual());
11491     return String::Equals(one, two);
11492   }
11493 
11494   // Fast check: if hash code is computed for both strings
11495   // a fast negative check can be performed.
11496   if (one->HasHashCode() && two->HasHashCode()) {
11497 #ifdef ENABLE_SLOW_DCHECKS
11498     if (FLAG_enable_slow_asserts) {
11499       if (one->Hash() != two->Hash()) {
11500         bool found_difference = false;
11501         for (int i = 0; i < one_length; i++) {
11502           if (one->Get(i) != two->Get(i)) {
11503             found_difference = true;
11504             break;
11505           }
11506         }
11507         DCHECK(found_difference);
11508       }
11509     }
11510 #endif
11511     if (one->Hash() != two->Hash()) return false;
11512   }
11513 
11514   // We know the strings are both non-empty. Compare the first chars
11515   // before we try to flatten the strings.
11516   if (one->Get(0) != two->Get(0)) return false;
11517 
11518   one = String::Flatten(one);
11519   two = String::Flatten(two);
11520 
11521   DisallowHeapAllocation no_gc;
11522   String::FlatContent flat1 = one->GetFlatContent();
11523   String::FlatContent flat2 = two->GetFlatContent();
11524 
11525   if (flat1.IsOneByte() && flat2.IsOneByte()) {
11526       return CompareRawStringContents(flat1.ToOneByteVector().start(),
11527                                       flat2.ToOneByteVector().start(),
11528                                       one_length);
11529   } else {
11530     for (int i = 0; i < one_length; i++) {
11531       if (flat1.Get(i) != flat2.Get(i)) return false;
11532     }
11533     return true;
11534   }
11535 }
11536 
11537 
11538 // static
Compare(Handle<String> x,Handle<String> y)11539 ComparisonResult String::Compare(Handle<String> x, Handle<String> y) {
11540   // A few fast case tests before we flatten.
11541   if (x.is_identical_to(y)) {
11542     return ComparisonResult::kEqual;
11543   } else if (y->length() == 0) {
11544     return x->length() == 0 ? ComparisonResult::kEqual
11545                             : ComparisonResult::kGreaterThan;
11546   } else if (x->length() == 0) {
11547     return ComparisonResult::kLessThan;
11548   }
11549 
11550   int const d = x->Get(0) - y->Get(0);
11551   if (d < 0) {
11552     return ComparisonResult::kLessThan;
11553   } else if (d > 0) {
11554     return ComparisonResult::kGreaterThan;
11555   }
11556 
11557   // Slow case.
11558   x = String::Flatten(x);
11559   y = String::Flatten(y);
11560 
11561   DisallowHeapAllocation no_gc;
11562   ComparisonResult result = ComparisonResult::kEqual;
11563   int prefix_length = x->length();
11564   if (y->length() < prefix_length) {
11565     prefix_length = y->length();
11566     result = ComparisonResult::kGreaterThan;
11567   } else if (y->length() > prefix_length) {
11568     result = ComparisonResult::kLessThan;
11569   }
11570   int r;
11571   String::FlatContent x_content = x->GetFlatContent();
11572   String::FlatContent y_content = y->GetFlatContent();
11573   if (x_content.IsOneByte()) {
11574     Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
11575     if (y_content.IsOneByte()) {
11576       Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11577       r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11578     } else {
11579       Vector<const uc16> y_chars = y_content.ToUC16Vector();
11580       r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11581     }
11582   } else {
11583     Vector<const uc16> x_chars = x_content.ToUC16Vector();
11584     if (y_content.IsOneByte()) {
11585       Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11586       r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11587     } else {
11588       Vector<const uc16> y_chars = y_content.ToUC16Vector();
11589       r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11590     }
11591   }
11592   if (r < 0) {
11593     result = ComparisonResult::kLessThan;
11594   } else if (r > 0) {
11595     result = ComparisonResult::kGreaterThan;
11596   }
11597   return result;
11598 }
11599 
IndexOf(Isolate * isolate,Handle<Object> receiver,Handle<Object> search,Handle<Object> position)11600 Object* String::IndexOf(Isolate* isolate, Handle<Object> receiver,
11601                         Handle<Object> search, Handle<Object> position) {
11602   if (receiver->IsNullOrUndefined(isolate)) {
11603     THROW_NEW_ERROR_RETURN_FAILURE(
11604         isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
11605                               isolate->factory()->NewStringFromAsciiChecked(
11606                                   "String.prototype.indexOf")));
11607   }
11608   Handle<String> receiver_string;
11609   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string,
11610                                      Object::ToString(isolate, receiver));
11611 
11612   Handle<String> search_string;
11613   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
11614                                      Object::ToString(isolate, search));
11615 
11616   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11617                                      Object::ToInteger(isolate, position));
11618 
11619   uint32_t index = receiver_string->ToValidIndex(*position);
11620   return Smi::FromInt(
11621       String::IndexOf(isolate, receiver_string, search_string, index));
11622 }
11623 
11624 namespace {
11625 
11626 template <typename T>
SearchString(Isolate * isolate,String::FlatContent receiver_content,Vector<T> pat_vector,int start_index)11627 int SearchString(Isolate* isolate, String::FlatContent receiver_content,
11628                  Vector<T> pat_vector, int start_index) {
11629   if (receiver_content.IsOneByte()) {
11630     return SearchString(isolate, receiver_content.ToOneByteVector(), pat_vector,
11631                         start_index);
11632   }
11633   return SearchString(isolate, receiver_content.ToUC16Vector(), pat_vector,
11634                       start_index);
11635 }
11636 
11637 }  // namespace
11638 
IndexOf(Isolate * isolate,Handle<String> receiver,Handle<String> search,int start_index)11639 int String::IndexOf(Isolate* isolate, Handle<String> receiver,
11640                     Handle<String> search, int start_index) {
11641   DCHECK_LE(0, start_index);
11642   DCHECK(start_index <= receiver->length());
11643 
11644   uint32_t search_length = search->length();
11645   if (search_length == 0) return start_index;
11646 
11647   uint32_t receiver_length = receiver->length();
11648   if (start_index + search_length > receiver_length) return -1;
11649 
11650   receiver = String::Flatten(receiver);
11651   search = String::Flatten(search);
11652 
11653   DisallowHeapAllocation no_gc;  // ensure vectors stay valid
11654   // Extract flattened substrings of cons strings before getting encoding.
11655   String::FlatContent receiver_content = receiver->GetFlatContent();
11656   String::FlatContent search_content = search->GetFlatContent();
11657 
11658   // dispatch on type of strings
11659   if (search_content.IsOneByte()) {
11660     Vector<const uint8_t> pat_vector = search_content.ToOneByteVector();
11661     return SearchString<const uint8_t>(isolate, receiver_content, pat_vector,
11662                                        start_index);
11663   }
11664   Vector<const uc16> pat_vector = search_content.ToUC16Vector();
11665   return SearchString<const uc16>(isolate, receiver_content, pat_vector,
11666                                   start_index);
11667 }
11668 
GetSubstitution(Isolate * isolate,Match * match,Handle<String> replacement,int start_index)11669 MaybeHandle<String> String::GetSubstitution(Isolate* isolate, Match* match,
11670                                             Handle<String> replacement,
11671                                             int start_index) {
11672   DCHECK_IMPLIES(match->HasNamedCaptures(), FLAG_harmony_regexp_named_captures);
11673   DCHECK_GE(start_index, 0);
11674 
11675   Factory* factory = isolate->factory();
11676 
11677   const int replacement_length = replacement->length();
11678   const int captures_length = match->CaptureCount();
11679 
11680   replacement = String::Flatten(replacement);
11681 
11682   Handle<String> dollar_string =
11683       factory->LookupSingleCharacterStringFromCode('$');
11684   int next_dollar_ix =
11685       String::IndexOf(isolate, replacement, dollar_string, start_index);
11686   if (next_dollar_ix < 0) {
11687     return replacement;
11688   }
11689 
11690   IncrementalStringBuilder builder(isolate);
11691 
11692   if (next_dollar_ix > 0) {
11693     builder.AppendString(factory->NewSubString(replacement, 0, next_dollar_ix));
11694   }
11695 
11696   while (true) {
11697     const int peek_ix = next_dollar_ix + 1;
11698     if (peek_ix >= replacement_length) {
11699       builder.AppendCharacter('$');
11700       return builder.Finish();
11701     }
11702 
11703     int continue_from_ix = -1;
11704     const uint16_t peek = replacement->Get(peek_ix);
11705     switch (peek) {
11706       case '$':  // $$
11707         builder.AppendCharacter('$');
11708         continue_from_ix = peek_ix + 1;
11709         break;
11710       case '&':  // $& - match
11711         builder.AppendString(match->GetMatch());
11712         continue_from_ix = peek_ix + 1;
11713         break;
11714       case '`':  // $` - prefix
11715         builder.AppendString(match->GetPrefix());
11716         continue_from_ix = peek_ix + 1;
11717         break;
11718       case '\'':  // $' - suffix
11719         builder.AppendString(match->GetSuffix());
11720         continue_from_ix = peek_ix + 1;
11721         break;
11722       case '0':
11723       case '1':
11724       case '2':
11725       case '3':
11726       case '4':
11727       case '5':
11728       case '6':
11729       case '7':
11730       case '8':
11731       case '9': {
11732         // Valid indices are $1 .. $9, $01 .. $09 and $10 .. $99
11733         int scaled_index = (peek - '0');
11734         int advance = 1;
11735 
11736         if (peek_ix + 1 < replacement_length) {
11737           const uint16_t next_peek = replacement->Get(peek_ix + 1);
11738           if (next_peek >= '0' && next_peek <= '9') {
11739             const int new_scaled_index = scaled_index * 10 + (next_peek - '0');
11740             if (new_scaled_index < captures_length) {
11741               scaled_index = new_scaled_index;
11742               advance = 2;
11743             }
11744           }
11745         }
11746 
11747         if (scaled_index == 0 || scaled_index >= captures_length) {
11748           builder.AppendCharacter('$');
11749           continue_from_ix = peek_ix;
11750           break;
11751         }
11752 
11753         bool capture_exists;
11754         Handle<String> capture;
11755         ASSIGN_RETURN_ON_EXCEPTION(
11756             isolate, capture, match->GetCapture(scaled_index, &capture_exists),
11757             String);
11758         if (capture_exists) builder.AppendString(capture);
11759         continue_from_ix = peek_ix + advance;
11760         break;
11761       }
11762       case '<': {  // $<name> - named capture
11763         typedef String::Match::CaptureState CaptureState;
11764 
11765         if (!match->HasNamedCaptures()) {
11766           builder.AppendCharacter('$');
11767           continue_from_ix = peek_ix;
11768           break;
11769         }
11770 
11771         Handle<String> bracket_string =
11772             factory->LookupSingleCharacterStringFromCode('>');
11773         const int closing_bracket_ix =
11774             String::IndexOf(isolate, replacement, bracket_string, peek_ix + 1);
11775 
11776         if (closing_bracket_ix == -1) {
11777           // No closing bracket was found, treat '$<' as a string literal.
11778           builder.AppendCharacter('$');
11779           continue_from_ix = peek_ix;
11780           break;
11781         }
11782 
11783         Handle<String> capture_name =
11784             factory->NewSubString(replacement, peek_ix + 1, closing_bracket_ix);
11785         Handle<String> capture;
11786         CaptureState capture_state;
11787         ASSIGN_RETURN_ON_EXCEPTION(
11788             isolate, capture,
11789             match->GetNamedCapture(capture_name, &capture_state), String);
11790 
11791         switch (capture_state) {
11792           case CaptureState::INVALID:
11793           case CaptureState::UNMATCHED:
11794             break;
11795           case CaptureState::MATCHED:
11796             builder.AppendString(capture);
11797             break;
11798         }
11799 
11800         continue_from_ix = closing_bracket_ix + 1;
11801         break;
11802       }
11803       default:
11804         builder.AppendCharacter('$');
11805         continue_from_ix = peek_ix;
11806         break;
11807     }
11808 
11809     // Go the the next $ in the replacement.
11810     // TODO(jgruber): Single-char lookups could be much more efficient.
11811     DCHECK_NE(continue_from_ix, -1);
11812     next_dollar_ix =
11813         String::IndexOf(isolate, replacement, dollar_string, continue_from_ix);
11814 
11815     // Return if there are no more $ characters in the replacement. If we
11816     // haven't reached the end, we need to append the suffix.
11817     if (next_dollar_ix < 0) {
11818       if (continue_from_ix < replacement_length) {
11819         builder.AppendString(factory->NewSubString(
11820             replacement, continue_from_ix, replacement_length));
11821       }
11822       return builder.Finish();
11823     }
11824 
11825     // Append substring between the previous and the next $ character.
11826     if (next_dollar_ix > continue_from_ix) {
11827       builder.AppendString(
11828           factory->NewSubString(replacement, continue_from_ix, next_dollar_ix));
11829     }
11830   }
11831 
11832   UNREACHABLE();
11833 }
11834 
11835 namespace {  // for String.Prototype.lastIndexOf
11836 
11837 template <typename schar, typename pchar>
StringMatchBackwards(Vector<const schar> subject,Vector<const pchar> pattern,int idx)11838 int StringMatchBackwards(Vector<const schar> subject,
11839                          Vector<const pchar> pattern, int idx) {
11840   int pattern_length = pattern.length();
11841   DCHECK_GE(pattern_length, 1);
11842   DCHECK(idx + pattern_length <= subject.length());
11843 
11844   if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
11845     for (int i = 0; i < pattern_length; i++) {
11846       uc16 c = pattern[i];
11847       if (c > String::kMaxOneByteCharCode) {
11848         return -1;
11849       }
11850     }
11851   }
11852 
11853   pchar pattern_first_char = pattern[0];
11854   for (int i = idx; i >= 0; i--) {
11855     if (subject[i] != pattern_first_char) continue;
11856     int j = 1;
11857     while (j < pattern_length) {
11858       if (pattern[j] != subject[i + j]) {
11859         break;
11860       }
11861       j++;
11862     }
11863     if (j == pattern_length) {
11864       return i;
11865     }
11866   }
11867   return -1;
11868 }
11869 
11870 }  // namespace
11871 
LastIndexOf(Isolate * isolate,Handle<Object> receiver,Handle<Object> search,Handle<Object> position)11872 Object* String::LastIndexOf(Isolate* isolate, Handle<Object> receiver,
11873                             Handle<Object> search, Handle<Object> position) {
11874   if (receiver->IsNullOrUndefined(isolate)) {
11875     THROW_NEW_ERROR_RETURN_FAILURE(
11876         isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
11877                               isolate->factory()->NewStringFromAsciiChecked(
11878                                   "String.prototype.lastIndexOf")));
11879   }
11880   Handle<String> receiver_string;
11881   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string,
11882                                      Object::ToString(isolate, receiver));
11883 
11884   Handle<String> search_string;
11885   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
11886                                      Object::ToString(isolate, search));
11887 
11888   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11889                                      Object::ToNumber(position));
11890 
11891   uint32_t start_index;
11892 
11893   if (position->IsNaN()) {
11894     start_index = receiver_string->length();
11895   } else {
11896     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11897                                        Object::ToInteger(isolate, position));
11898     start_index = receiver_string->ToValidIndex(*position);
11899   }
11900 
11901   uint32_t pattern_length = search_string->length();
11902   uint32_t receiver_length = receiver_string->length();
11903 
11904   if (start_index + pattern_length > receiver_length) {
11905     start_index = receiver_length - pattern_length;
11906   }
11907 
11908   if (pattern_length == 0) {
11909     return Smi::FromInt(start_index);
11910   }
11911 
11912   receiver_string = String::Flatten(receiver_string);
11913   search_string = String::Flatten(search_string);
11914 
11915   int last_index = -1;
11916   DisallowHeapAllocation no_gc;  // ensure vectors stay valid
11917 
11918   String::FlatContent receiver_content = receiver_string->GetFlatContent();
11919   String::FlatContent search_content = search_string->GetFlatContent();
11920 
11921   if (search_content.IsOneByte()) {
11922     Vector<const uint8_t> pat_vector = search_content.ToOneByteVector();
11923     if (receiver_content.IsOneByte()) {
11924       last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
11925                                         pat_vector, start_index);
11926     } else {
11927       last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
11928                                         pat_vector, start_index);
11929     }
11930   } else {
11931     Vector<const uc16> pat_vector = search_content.ToUC16Vector();
11932     if (receiver_content.IsOneByte()) {
11933       last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
11934                                         pat_vector, start_index);
11935     } else {
11936       last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
11937                                         pat_vector, start_index);
11938     }
11939   }
11940   return Smi::FromInt(last_index);
11941 }
11942 
IsUtf8EqualTo(Vector<const char> str,bool allow_prefix_match)11943 bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
11944   int slen = length();
11945   // Can't check exact length equality, but we can check bounds.
11946   int str_len = str.length();
11947   if (!allow_prefix_match &&
11948       (str_len < slen ||
11949           str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) {
11950     return false;
11951   }
11952 
11953   int i = 0;
11954   unibrow::Utf8Iterator it = unibrow::Utf8Iterator(str);
11955   while (i < slen && !it.Done()) {
11956     if (Get(i++) != *it) return false;
11957     ++it;
11958   }
11959 
11960   return (allow_prefix_match || i == slen) && it.Done();
11961 }
11962 
11963 template <>
IsEqualTo(Vector<const uint8_t> str)11964 bool String::IsEqualTo(Vector<const uint8_t> str) {
11965   return IsOneByteEqualTo(str);
11966 }
11967 
11968 template <>
IsEqualTo(Vector<const uc16> str)11969 bool String::IsEqualTo(Vector<const uc16> str) {
11970   return IsTwoByteEqualTo(str);
11971 }
11972 
IsOneByteEqualTo(Vector<const uint8_t> str)11973 bool String::IsOneByteEqualTo(Vector<const uint8_t> str) {
11974   int slen = length();
11975   if (str.length() != slen) return false;
11976   DisallowHeapAllocation no_gc;
11977   FlatContent content = GetFlatContent();
11978   if (content.IsOneByte()) {
11979     return CompareChars(content.ToOneByteVector().start(),
11980                         str.start(), slen) == 0;
11981   }
11982   for (int i = 0; i < slen; i++) {
11983     if (Get(i) != static_cast<uint16_t>(str[i])) return false;
11984   }
11985   return true;
11986 }
11987 
11988 
IsTwoByteEqualTo(Vector<const uc16> str)11989 bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
11990   int slen = length();
11991   if (str.length() != slen) return false;
11992   DisallowHeapAllocation no_gc;
11993   FlatContent content = GetFlatContent();
11994   if (content.IsTwoByte()) {
11995     return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
11996   }
11997   for (int i = 0; i < slen; i++) {
11998     if (Get(i) != str[i]) return false;
11999   }
12000   return true;
12001 }
12002 
12003 
ComputeAndSetHash()12004 uint32_t String::ComputeAndSetHash() {
12005   // Should only be called if hash code has not yet been computed.
12006   DCHECK(!HasHashCode());
12007 
12008   // Store the hash code in the object.
12009   uint32_t field = IteratingStringHasher::Hash(this, GetHeap()->HashSeed());
12010   set_hash_field(field);
12011 
12012   // Check the hash code is there.
12013   DCHECK(HasHashCode());
12014   uint32_t result = field >> kHashShift;
12015   DCHECK_NE(result, 0);  // Ensure that the hash value of 0 is never computed.
12016   return result;
12017 }
12018 
12019 
ComputeArrayIndex(uint32_t * index)12020 bool String::ComputeArrayIndex(uint32_t* index) {
12021   int length = this->length();
12022   if (length == 0 || length > kMaxArrayIndexSize) return false;
12023   StringCharacterStream stream(this);
12024   return StringToArrayIndex(&stream, index);
12025 }
12026 
12027 
SlowAsArrayIndex(uint32_t * index)12028 bool String::SlowAsArrayIndex(uint32_t* index) {
12029   if (length() <= kMaxCachedArrayIndexLength) {
12030     Hash();  // force computation of hash code
12031     uint32_t field = hash_field();
12032     if ((field & kIsNotArrayIndexMask) != 0) return false;
12033     // Isolate the array index form the full hash field.
12034     *index = ArrayIndexValueBits::decode(field);
12035     return true;
12036   } else {
12037     return ComputeArrayIndex(index);
12038   }
12039 }
12040 
12041 
Truncate(Handle<SeqString> string,int new_length)12042 Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
12043   Heap* heap = string->GetHeap();
12044   if (new_length == 0) return heap->isolate()->factory()->empty_string();
12045 
12046   int new_size, old_size;
12047   int old_length = string->length();
12048   if (old_length <= new_length) return string;
12049 
12050   if (string->IsSeqOneByteString()) {
12051     old_size = SeqOneByteString::SizeFor(old_length);
12052     new_size = SeqOneByteString::SizeFor(new_length);
12053   } else {
12054     DCHECK(string->IsSeqTwoByteString());
12055     old_size = SeqTwoByteString::SizeFor(old_length);
12056     new_size = SeqTwoByteString::SizeFor(new_length);
12057   }
12058 
12059   int delta = old_size - new_size;
12060 
12061   Address start_of_string = string->address();
12062   DCHECK_OBJECT_ALIGNED(start_of_string);
12063   DCHECK_OBJECT_ALIGNED(start_of_string + new_size);
12064 
12065   // Sizes are pointer size aligned, so that we can use filler objects
12066   // that are a multiple of pointer size.
12067   heap->CreateFillerObjectAt(start_of_string + new_size, delta,
12068                              ClearRecordedSlots::kNo);
12069   // We are storing the new length using release store after creating a filler
12070   // for the left-over space to avoid races with the sweeper thread.
12071   string->synchronized_set_length(new_length);
12072 
12073   return string;
12074 }
12075 
clear_padding()12076 void SeqOneByteString::clear_padding() {
12077   int data_size = SeqString::kHeaderSize + length() * kOneByteSize;
12078   memset(reinterpret_cast<void*>(address() + data_size), 0,
12079          SizeFor(length()) - data_size);
12080 }
12081 
clear_padding()12082 void SeqTwoByteString::clear_padding() {
12083   int data_size = SeqString::kHeaderSize + length() * kUC16Size;
12084   memset(reinterpret_cast<void*>(address() + data_size), 0,
12085          SizeFor(length()) - data_size);
12086 }
12087 
ExternalPayloadSize() const12088 int ExternalString::ExternalPayloadSize() const {
12089   int length_multiplier = IsTwoByteRepresentation() ? i::kShortSize : kCharSize;
12090   return length() * length_multiplier;
12091 }
12092 
MakeArrayIndexHash(uint32_t value,int length)12093 uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
12094   // For array indexes mix the length into the hash as an array index could
12095   // be zero.
12096   DCHECK_GT(length, 0);
12097   DCHECK_LE(length, String::kMaxArrayIndexSize);
12098   DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
12099          (1 << String::kArrayIndexValueBits));
12100 
12101   value <<= String::ArrayIndexValueBits::kShift;
12102   value |= length << String::ArrayIndexLengthBits::kShift;
12103 
12104   DCHECK_EQ(value & String::kIsNotArrayIndexMask, 0);
12105   DCHECK_EQ(length <= String::kMaxCachedArrayIndexLength,
12106             Name::ContainsCachedArrayIndex(value));
12107   return value;
12108 }
12109 
12110 
GetHashField()12111 uint32_t StringHasher::GetHashField() {
12112   if (length_ <= String::kMaxHashCalcLength) {
12113     if (is_array_index_) {
12114       return MakeArrayIndexHash(array_index_, length_);
12115     }
12116     return (GetHashCore(raw_running_hash_) << String::kHashShift) |
12117            String::kIsNotArrayIndexMask;
12118   } else {
12119     return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
12120   }
12121 }
12122 
ComputeUtf8Hash(Vector<const char> chars,uint64_t seed,int * utf16_length_out)12123 uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars, uint64_t seed,
12124                                        int* utf16_length_out) {
12125   int vector_length = chars.length();
12126   // Handle some edge cases
12127   if (vector_length <= 1) {
12128     DCHECK(vector_length == 0 ||
12129            static_cast<uint8_t>(chars.start()[0]) <=
12130                unibrow::Utf8::kMaxOneByteChar);
12131     *utf16_length_out = vector_length;
12132     return HashSequentialString(chars.start(), vector_length, seed);
12133   }
12134 
12135   // Start with a fake length which won't affect computation.
12136   // It will be updated later.
12137   StringHasher hasher(String::kMaxArrayIndexSize, seed);
12138   DCHECK(hasher.is_array_index_);
12139 
12140   unibrow::Utf8Iterator it = unibrow::Utf8Iterator(chars);
12141   int utf16_length = 0;
12142   bool is_index = true;
12143 
12144   while (utf16_length < String::kMaxHashCalcLength && !it.Done()) {
12145     utf16_length++;
12146     uint16_t c = *it;
12147     ++it;
12148     hasher.AddCharacter(c);
12149     if (is_index) is_index = hasher.UpdateIndex(c);
12150   }
12151 
12152   // Now that hashing is done, we just need to calculate utf16_length
12153   while (!it.Done()) {
12154     ++it;
12155     utf16_length++;
12156   }
12157 
12158   *utf16_length_out = utf16_length;
12159   // Must set length here so that hash computation is correct.
12160   hasher.length_ = utf16_length;
12161   return hasher.GetHashField();
12162 }
12163 
12164 
VisitConsString(ConsString * cons_string)12165 void IteratingStringHasher::VisitConsString(ConsString* cons_string) {
12166   // Run small ConsStrings through ConsStringIterator.
12167   if (cons_string->length() < 64) {
12168     ConsStringIterator iter(cons_string);
12169     int offset;
12170     String* string;
12171     while (nullptr != (string = iter.Next(&offset))) {
12172       DCHECK_EQ(0, offset);
12173       String::VisitFlat(this, string, 0);
12174     }
12175     return;
12176   }
12177   // Slow case.
12178   const int max_length = String::kMaxHashCalcLength;
12179   int length = std::min(cons_string->length(), max_length);
12180   if (cons_string->HasOnlyOneByteChars()) {
12181     uint8_t* buffer = new uint8_t[length];
12182     String::WriteToFlat(cons_string, buffer, 0, length);
12183     AddCharacters(buffer, length);
12184     delete[] buffer;
12185   } else {
12186     uint16_t* buffer = new uint16_t[length];
12187     String::WriteToFlat(cons_string, buffer, 0, length);
12188     AddCharacters(buffer, length);
12189     delete[] buffer;
12190   }
12191 }
12192 
12193 
PrintOn(FILE * file)12194 void String::PrintOn(FILE* file) {
12195   int length = this->length();
12196   for (int i = 0; i < length; i++) {
12197     PrintF(file, "%c", Get(i));
12198   }
12199 }
12200 
12201 
Hash()12202 int Map::Hash() {
12203   // For performance reasons we only hash the 3 most variable fields of a map:
12204   // constructor, prototype and bit_field2. For predictability reasons we
12205   // use objects' offsets in respective pages for hashing instead of raw
12206   // addresses.
12207 
12208   // Shift away the tag.
12209   int hash = ObjectAddressForHashing(GetConstructor()) >> 2;
12210 
12211   // XOR-ing the prototype and constructor directly yields too many zero bits
12212   // when the two pointers are close (which is fairly common).
12213   // To avoid this we shift the prototype bits relatively to the constructor.
12214   hash ^= ObjectAddressForHashing(prototype()) << (32 - kPageSizeBits);
12215 
12216   return hash ^ (hash >> 16) ^ bit_field2();
12217 }
12218 
12219 
12220 namespace {
12221 
CheckEquivalent(const Map * first,const Map * second)12222 bool CheckEquivalent(const Map* first, const Map* second) {
12223   return first->GetConstructor() == second->GetConstructor() &&
12224          first->prototype() == second->prototype() &&
12225          first->instance_type() == second->instance_type() &&
12226          first->bit_field() == second->bit_field() &&
12227          first->is_extensible() == second->is_extensible() &&
12228          first->new_target_is_base() == second->new_target_is_base() &&
12229          first->has_hidden_prototype() == second->has_hidden_prototype();
12230 }
12231 
12232 }  // namespace
12233 
EquivalentToForTransition(const Map * other) const12234 bool Map::EquivalentToForTransition(const Map* other) const {
12235   if (!CheckEquivalent(this, other)) return false;
12236   if (instance_type() == JS_FUNCTION_TYPE) {
12237     // JSFunctions require more checks to ensure that sloppy function is
12238     // not equivalent to strict function.
12239     int nof = Min(NumberOfOwnDescriptors(), other->NumberOfOwnDescriptors());
12240     return instance_descriptors()->IsEqualUpTo(other->instance_descriptors(),
12241                                                nof);
12242   }
12243   return true;
12244 }
12245 
EquivalentToForElementsKindTransition(const Map * other) const12246 bool Map::EquivalentToForElementsKindTransition(const Map* other) const {
12247   if (!EquivalentToForTransition(other)) return false;
12248 #ifdef DEBUG
12249   // Ensure that we don't try to generate elements kind transitions from maps
12250   // with fields that may be generalized in-place. This must already be handled
12251   // during addition of a new field.
12252   DescriptorArray* descriptors = instance_descriptors();
12253   int nof = NumberOfOwnDescriptors();
12254   for (int i = 0; i < nof; i++) {
12255     PropertyDetails details = descriptors->GetDetails(i);
12256     if (details.location() == kField) {
12257       DCHECK(!IsInplaceGeneralizableField(details.constness(),
12258                                           details.representation(),
12259                                           descriptors->GetFieldType(i)));
12260     }
12261   }
12262 #endif
12263   return true;
12264 }
12265 
EquivalentToForNormalization(const Map * other,PropertyNormalizationMode mode) const12266 bool Map::EquivalentToForNormalization(const Map* other,
12267                                        PropertyNormalizationMode mode) const {
12268   int properties =
12269       mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other->GetInObjectProperties();
12270   return CheckEquivalent(this, other) && bit_field2() == other->bit_field2() &&
12271          GetInObjectProperties() == properties &&
12272          JSObject::GetEmbedderFieldCount(this) ==
12273              JSObject::GetEmbedderFieldCount(other);
12274 }
12275 
12276 
MarkForOptimization(ConcurrencyMode mode)12277 void JSFunction::MarkForOptimization(ConcurrencyMode mode) {
12278   Isolate* isolate = GetIsolate();
12279   if (!isolate->concurrent_recompilation_enabled() ||
12280       isolate->bootstrapper()->IsActive()) {
12281     mode = ConcurrencyMode::kNotConcurrent;
12282   }
12283 
12284   DCHECK(!is_compiled() || IsInterpreted());
12285   DCHECK(shared()->IsInterpreted());
12286   DCHECK(!IsOptimized());
12287   DCHECK(!HasOptimizedCode());
12288   DCHECK(shared()->allows_lazy_compilation() ||
12289          !shared()->optimization_disabled());
12290 
12291   if (mode == ConcurrencyMode::kConcurrent) {
12292     if (IsInOptimizationQueue()) {
12293       if (FLAG_trace_concurrent_recompilation) {
12294         PrintF("  ** Not marking ");
12295         ShortPrint();
12296         PrintF(" -- already in optimization queue.\n");
12297       }
12298       return;
12299     }
12300     if (FLAG_trace_concurrent_recompilation) {
12301       PrintF("  ** Marking ");
12302       ShortPrint();
12303       PrintF(" for concurrent recompilation.\n");
12304     }
12305   }
12306 
12307   SetOptimizationMarker(mode == ConcurrencyMode::kConcurrent
12308                             ? OptimizationMarker::kCompileOptimizedConcurrent
12309                             : OptimizationMarker::kCompileOptimized);
12310 }
12311 
12312 // static
EnsureFeedbackVector(Handle<JSFunction> function)12313 void JSFunction::EnsureFeedbackVector(Handle<JSFunction> function) {
12314   Isolate* const isolate = function->GetIsolate();
12315   if (function->feedback_cell()->value()->IsUndefined(isolate)) {
12316     Handle<SharedFunctionInfo> shared(function->shared(), isolate);
12317     if (!shared->HasAsmWasmData()) {
12318       Handle<FeedbackVector> feedback_vector =
12319           FeedbackVector::New(isolate, shared);
12320       if (function->feedback_cell() == isolate->heap()->many_closures_cell()) {
12321         Handle<FeedbackCell> feedback_cell =
12322             isolate->factory()->NewOneClosureCell(feedback_vector);
12323         function->set_feedback_cell(*feedback_cell);
12324       } else {
12325         function->feedback_cell()->set_value(*feedback_vector);
12326       }
12327     }
12328   }
12329 }
12330 
GetMinInobjectSlack(Map * map,void * data)12331 static void GetMinInobjectSlack(Map* map, void* data) {
12332   int slack = map->UnusedPropertyFields();
12333   if (*reinterpret_cast<int*>(data) > slack) {
12334     *reinterpret_cast<int*>(data) = slack;
12335   }
12336 }
12337 
12338 
ShrinkInstanceSize(Map * map,void * data)12339 static void ShrinkInstanceSize(Map* map, void* data) {
12340   int slack = *reinterpret_cast<int*>(data);
12341   DCHECK_GE(slack, 0);
12342 #ifdef DEBUG
12343   int old_visitor_id = Map::GetVisitorId(map);
12344   int new_unused = map->UnusedPropertyFields() - slack;
12345 #endif
12346   map->set_instance_size(map->instance_size() - slack * kPointerSize);
12347   map->set_construction_counter(Map::kNoSlackTracking);
12348   DCHECK_EQ(old_visitor_id, Map::GetVisitorId(map));
12349   DCHECK_EQ(new_unused, map->UnusedPropertyFields());
12350 }
12351 
StopSlackTracking(Map * map,void * data)12352 static void StopSlackTracking(Map* map, void* data) {
12353   map->set_construction_counter(Map::kNoSlackTracking);
12354 }
12355 
CompleteInobjectSlackTracking()12356 void Map::CompleteInobjectSlackTracking() {
12357   DisallowHeapAllocation no_gc;
12358   // Has to be an initial map.
12359   DCHECK(GetBackPointer()->IsUndefined(GetIsolate()));
12360 
12361   int slack = UnusedPropertyFields();
12362   TransitionsAccessor transitions(this, &no_gc);
12363   transitions.TraverseTransitionTree(&GetMinInobjectSlack, &slack);
12364   if (slack != 0) {
12365     // Resize the initial map and all maps in its transition tree.
12366     transitions.TraverseTransitionTree(&ShrinkInstanceSize, &slack);
12367   } else {
12368     transitions.TraverseTransitionTree(&StopSlackTracking, nullptr);
12369   }
12370 }
12371 
12372 
PrototypeBenefitsFromNormalization(Handle<JSObject> object)12373 static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) {
12374   DisallowHeapAllocation no_gc;
12375   if (!object->HasFastProperties()) return false;
12376   if (object->IsJSGlobalProxy()) return false;
12377   if (object->GetIsolate()->bootstrapper()->IsActive()) return false;
12378   return !object->map()->is_prototype_map() ||
12379          !object->map()->should_be_fast_prototype_map();
12380 }
12381 
12382 // static
MakePrototypesFast(Handle<Object> receiver,WhereToStart where_to_start,Isolate * isolate)12383 void JSObject::MakePrototypesFast(Handle<Object> receiver,
12384                                   WhereToStart where_to_start,
12385                                   Isolate* isolate) {
12386   if (!receiver->IsJSReceiver()) return;
12387   for (PrototypeIterator iter(isolate, Handle<JSReceiver>::cast(receiver),
12388                               where_to_start);
12389        !iter.IsAtEnd(); iter.Advance()) {
12390     Handle<Object> current = PrototypeIterator::GetCurrent(iter);
12391     if (!current->IsJSObject()) return;
12392     Handle<JSObject> current_obj = Handle<JSObject>::cast(current);
12393     Map* current_map = current_obj->map();
12394     if (current_map->is_prototype_map()) {
12395       // If the map is already marked as should be fast, we're done. Its
12396       // prototypes will have been marked already as well.
12397       if (current_map->should_be_fast_prototype_map()) return;
12398       Handle<Map> map(current_map);
12399       Map::SetShouldBeFastPrototypeMap(map, true, isolate);
12400       JSObject::OptimizeAsPrototype(current_obj);
12401     }
12402   }
12403 }
12404 
12405 // static
OptimizeAsPrototype(Handle<JSObject> object,bool enable_setup_mode)12406 void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
12407                                    bool enable_setup_mode) {
12408   if (object->IsJSGlobalObject()) return;
12409   if (enable_setup_mode && PrototypeBenefitsFromNormalization(object)) {
12410     // First normalize to ensure all JSFunctions are DATA_CONSTANT.
12411     JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0,
12412                                   "NormalizeAsPrototype");
12413   }
12414   if (object->map()->is_prototype_map()) {
12415     if (object->map()->should_be_fast_prototype_map() &&
12416         !object->HasFastProperties()) {
12417       JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype");
12418     }
12419   } else {
12420     Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype");
12421     JSObject::MigrateToMap(object, new_map);
12422     object->map()->set_is_prototype_map(true);
12423 
12424     // Replace the pointer to the exact constructor with the Object function
12425     // from the same context if undetectable from JS. This is to avoid keeping
12426     // memory alive unnecessarily.
12427     Object* maybe_constructor = object->map()->GetConstructor();
12428     if (maybe_constructor->IsJSFunction()) {
12429       JSFunction* constructor = JSFunction::cast(maybe_constructor);
12430       if (!constructor->shared()->IsApiFunction()) {
12431         Context* context = constructor->context()->native_context();
12432         JSFunction* object_function = context->object_function();
12433         object->map()->SetConstructor(object_function);
12434       }
12435     }
12436   }
12437 }
12438 
12439 
12440 // static
ReoptimizeIfPrototype(Handle<JSObject> object)12441 void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) {
12442   if (!object->map()->is_prototype_map()) return;
12443   if (!object->map()->should_be_fast_prototype_map()) return;
12444   OptimizeAsPrototype(object);
12445 }
12446 
12447 
12448 // static
LazyRegisterPrototypeUser(Handle<Map> user,Isolate * isolate)12449 void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
12450   // Contract: In line with InvalidatePrototypeChains()'s requirements,
12451   // leaf maps don't need to register as users, only prototypes do.
12452   DCHECK(user->is_prototype_map());
12453 
12454   Handle<Map> current_user = user;
12455   Handle<PrototypeInfo> current_user_info =
12456       Map::GetOrCreatePrototypeInfo(user, isolate);
12457   for (PrototypeIterator iter(user); !iter.IsAtEnd(); iter.Advance()) {
12458     // Walk up the prototype chain as far as links haven't been registered yet.
12459     if (current_user_info->registry_slot() != PrototypeInfo::UNREGISTERED) {
12460       break;
12461     }
12462     Handle<Object> maybe_proto = PrototypeIterator::GetCurrent(iter);
12463     // Proxies on the prototype chain are not supported. They make it
12464     // impossible to make any assumptions about the prototype chain anyway.
12465     if (maybe_proto->IsJSProxy()) return;
12466     Handle<JSObject> proto = Handle<JSObject>::cast(maybe_proto);
12467     Handle<PrototypeInfo> proto_info =
12468         Map::GetOrCreatePrototypeInfo(proto, isolate);
12469     Handle<Object> maybe_registry(proto_info->prototype_users(), isolate);
12470     int slot = 0;
12471     Handle<FixedArrayOfWeakCells> new_array =
12472         FixedArrayOfWeakCells::Add(maybe_registry, current_user, &slot);
12473     current_user_info->set_registry_slot(slot);
12474     if (!maybe_registry.is_identical_to(new_array)) {
12475       proto_info->set_prototype_users(*new_array);
12476     }
12477     if (FLAG_trace_prototype_users) {
12478       PrintF("Registering %p as a user of prototype %p (map=%p).\n",
12479              reinterpret_cast<void*>(*current_user),
12480              reinterpret_cast<void*>(*proto),
12481              reinterpret_cast<void*>(proto->map()));
12482     }
12483 
12484     current_user = handle(proto->map(), isolate);
12485     current_user_info = proto_info;
12486   }
12487 }
12488 
12489 
12490 // Can be called regardless of whether |user| was actually registered with
12491 // |prototype|. Returns true when there was a registration.
12492 // static
UnregisterPrototypeUser(Handle<Map> user,Isolate * isolate)12493 bool JSObject::UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
12494   DCHECK(user->is_prototype_map());
12495   // If it doesn't have a PrototypeInfo, it was never registered.
12496   if (!user->prototype_info()->IsPrototypeInfo()) return false;
12497   // If it had no prototype before, see if it had users that might expect
12498   // registration.
12499   if (!user->prototype()->IsJSObject()) {
12500     Object* users =
12501         PrototypeInfo::cast(user->prototype_info())->prototype_users();
12502     return users->IsFixedArrayOfWeakCells();
12503   }
12504   Handle<JSObject> prototype(JSObject::cast(user->prototype()), isolate);
12505   Handle<PrototypeInfo> user_info =
12506       Map::GetOrCreatePrototypeInfo(user, isolate);
12507   int slot = user_info->registry_slot();
12508   if (slot == PrototypeInfo::UNREGISTERED) return false;
12509   DCHECK(prototype->map()->is_prototype_map());
12510   Object* maybe_proto_info = prototype->map()->prototype_info();
12511   // User knows its registry slot, prototype info and user registry must exist.
12512   DCHECK(maybe_proto_info->IsPrototypeInfo());
12513   Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info),
12514                                    isolate);
12515   Object* maybe_registry = proto_info->prototype_users();
12516   DCHECK(maybe_registry->IsFixedArrayOfWeakCells());
12517   DCHECK(FixedArrayOfWeakCells::cast(maybe_registry)->Get(slot) == *user);
12518   FixedArrayOfWeakCells::cast(maybe_registry)->Clear(slot);
12519   if (FLAG_trace_prototype_users) {
12520     PrintF("Unregistering %p as a user of prototype %p.\n",
12521            reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype));
12522   }
12523   return true;
12524 }
12525 
12526 namespace {
12527 
12528 // This function must be kept in sync with
12529 // AccessorAssembler::InvalidateValidityCellIfPrototype() which does pre-checks
12530 // before jumping here.
InvalidateOnePrototypeValidityCellInternal(Map * map)12531 void InvalidateOnePrototypeValidityCellInternal(Map* map) {
12532   DCHECK(map->is_prototype_map());
12533   if (FLAG_trace_prototype_users) {
12534     PrintF("Invalidating prototype map %p 's cell\n",
12535            reinterpret_cast<void*>(map));
12536   }
12537   Object* maybe_cell = map->prototype_validity_cell();
12538   if (maybe_cell->IsCell()) {
12539     // Just set the value; the cell will be replaced lazily.
12540     Cell* cell = Cell::cast(maybe_cell);
12541     cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid));
12542   }
12543 }
12544 
InvalidatePrototypeChainsInternal(Map * map)12545 void InvalidatePrototypeChainsInternal(Map* map) {
12546   InvalidateOnePrototypeValidityCellInternal(map);
12547 
12548   Object* maybe_proto_info = map->prototype_info();
12549   if (!maybe_proto_info->IsPrototypeInfo()) return;
12550   PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info);
12551   FixedArrayOfWeakCells::Iterator iterator(proto_info->prototype_users());
12552   // For now, only maps register themselves as users.
12553   Map* user;
12554   while ((user = iterator.Next<Map>()) != nullptr) {
12555     // Walk the prototype chain (backwards, towards leaf objects) if necessary.
12556     InvalidatePrototypeChainsInternal(user);
12557   }
12558 }
12559 
12560 }  // namespace
12561 
12562 // static
InvalidatePrototypeChains(Map * map)12563 Map* JSObject::InvalidatePrototypeChains(Map* map) {
12564   DisallowHeapAllocation no_gc;
12565   InvalidatePrototypeChainsInternal(map);
12566   return map;
12567 }
12568 
12569 // We also invalidate global objects validity cell when a new lexical
12570 // environment variable is added. This is necessary to ensure that
12571 // Load/StoreGlobalIC handlers that load/store from global object's prototype
12572 // get properly invalidated.
12573 // Note, that the normal Load/StoreICs that load/store through the global object
12574 // in the prototype chain are not affected by appearance of a new lexical
12575 // variable and therefore we don't propagate invalidation down.
12576 // static
InvalidatePrototypeValidityCell(JSGlobalObject * global)12577 void JSObject::InvalidatePrototypeValidityCell(JSGlobalObject* global) {
12578   DisallowHeapAllocation no_gc;
12579   InvalidateOnePrototypeValidityCellInternal(global->map());
12580 }
12581 
12582 // static
GetOrCreatePrototypeInfo(Handle<JSObject> prototype,Isolate * isolate)12583 Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<JSObject> prototype,
12584                                                     Isolate* isolate) {
12585   Object* maybe_proto_info = prototype->map()->prototype_info();
12586   if (maybe_proto_info->IsPrototypeInfo()) {
12587     return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
12588   }
12589   Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
12590   prototype->map()->set_prototype_info(*proto_info);
12591   return proto_info;
12592 }
12593 
12594 
12595 // static
GetOrCreatePrototypeInfo(Handle<Map> prototype_map,Isolate * isolate)12596 Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<Map> prototype_map,
12597                                                     Isolate* isolate) {
12598   Object* maybe_proto_info = prototype_map->prototype_info();
12599   if (maybe_proto_info->IsPrototypeInfo()) {
12600     return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
12601   }
12602   Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
12603   prototype_map->set_prototype_info(*proto_info);
12604   return proto_info;
12605 }
12606 
12607 // static
SetShouldBeFastPrototypeMap(Handle<Map> map,bool value,Isolate * isolate)12608 void Map::SetShouldBeFastPrototypeMap(Handle<Map> map, bool value,
12609                                       Isolate* isolate) {
12610   if (value == false && !map->prototype_info()->IsPrototypeInfo()) {
12611     // "False" is the implicit default value, so there's nothing to do.
12612     return;
12613   }
12614   GetOrCreatePrototypeInfo(map, isolate)->set_should_be_fast_map(value);
12615 }
12616 
12617 // static
GetOrCreatePrototypeChainValidityCell(Handle<Map> map,Isolate * isolate)12618 Handle<Object> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
12619                                                           Isolate* isolate) {
12620   Handle<Object> maybe_prototype;
12621   if (map->IsJSGlobalObjectMap()) {
12622     DCHECK(map->is_prototype_map());
12623     // Global object is prototype of a global proxy and therefore we can
12624     // use its validity cell for guarding global object's prototype change.
12625     maybe_prototype = isolate->global_object();
12626   } else {
12627     maybe_prototype =
12628         handle(map->GetPrototypeChainRootMap(isolate)->prototype(), isolate);
12629   }
12630   if (!maybe_prototype->IsJSObject()) {
12631     return handle(Smi::FromInt(Map::kPrototypeChainValid), isolate);
12632   }
12633   Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype);
12634   // Ensure the prototype is registered with its own prototypes so its cell
12635   // will be invalidated when necessary.
12636   JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate),
12637                                       isolate);
12638 
12639   Object* maybe_cell = prototype->map()->prototype_validity_cell();
12640   // Return existing cell if it's still valid.
12641   if (maybe_cell->IsCell()) {
12642     Handle<Cell> cell(Cell::cast(maybe_cell), isolate);
12643     if (cell->value() == Smi::FromInt(Map::kPrototypeChainValid)) {
12644       return cell;
12645     }
12646   }
12647   // Otherwise create a new cell.
12648   Handle<Cell> cell = isolate->factory()->NewCell(
12649       handle(Smi::FromInt(Map::kPrototypeChainValid), isolate));
12650   prototype->map()->set_prototype_validity_cell(*cell);
12651   return cell;
12652 }
12653 
12654 // static
IsPrototypeChainInvalidated(Map * map)12655 bool Map::IsPrototypeChainInvalidated(Map* map) {
12656   DCHECK(map->is_prototype_map());
12657   Object* maybe_cell = map->prototype_validity_cell();
12658   if (maybe_cell->IsCell()) {
12659     Cell* cell = Cell::cast(maybe_cell);
12660     return cell->value() != Smi::FromInt(Map::kPrototypeChainValid);
12661   }
12662   return true;
12663 }
12664 
12665 // static
GetOrCreatePrototypeWeakCell(Handle<JSReceiver> prototype,Isolate * isolate)12666 Handle<WeakCell> Map::GetOrCreatePrototypeWeakCell(Handle<JSReceiver> prototype,
12667                                                    Isolate* isolate) {
12668   DCHECK(!prototype.is_null());
12669   if (prototype->IsJSProxy()) {
12670     Handle<WeakCell> cell = isolate->factory()->NewWeakCell(prototype);
12671     return cell;
12672   }
12673 
12674   Handle<PrototypeInfo> proto_info =
12675       GetOrCreatePrototypeInfo(Handle<JSObject>::cast(prototype), isolate);
12676   Object* maybe_cell = proto_info->weak_cell();
12677   // Return existing cell if it's already created.
12678   if (maybe_cell->IsWeakCell()) {
12679     Handle<WeakCell> cell(WeakCell::cast(maybe_cell), isolate);
12680     DCHECK(!cell->cleared());
12681     return cell;
12682   }
12683   // Otherwise create a new cell.
12684   Handle<WeakCell> cell = isolate->factory()->NewWeakCell(prototype);
12685   proto_info->set_weak_cell(*cell);
12686   return cell;
12687 }
12688 
12689 // static
SetPrototype(Handle<Map> map,Handle<Object> prototype,bool enable_prototype_setup_mode)12690 void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype,
12691                        bool enable_prototype_setup_mode) {
12692   RuntimeCallTimerScope stats_scope(*map,
12693                                     RuntimeCallCounterId::kMap_SetPrototype);
12694 
12695   bool is_hidden = false;
12696   if (prototype->IsJSObject()) {
12697     Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype);
12698     JSObject::OptimizeAsPrototype(prototype_jsobj, enable_prototype_setup_mode);
12699 
12700     Object* maybe_constructor = prototype_jsobj->map()->GetConstructor();
12701     if (maybe_constructor->IsJSFunction()) {
12702       JSFunction* constructor = JSFunction::cast(maybe_constructor);
12703       Object* data = constructor->shared()->function_data();
12704       is_hidden = (data->IsFunctionTemplateInfo() &&
12705                    FunctionTemplateInfo::cast(data)->hidden_prototype()) ||
12706                   prototype->IsJSGlobalObject();
12707     } else if (maybe_constructor->IsFunctionTemplateInfo()) {
12708       is_hidden =
12709           FunctionTemplateInfo::cast(maybe_constructor)->hidden_prototype() ||
12710           prototype->IsJSGlobalObject();
12711     }
12712   }
12713   map->set_has_hidden_prototype(is_hidden);
12714 
12715   WriteBarrierMode wb_mode = prototype->IsNull(map->GetIsolate())
12716                                  ? SKIP_WRITE_BARRIER
12717                                  : UPDATE_WRITE_BARRIER;
12718   map->set_prototype(*prototype, wb_mode);
12719 }
12720 
12721 
CacheInitialJSArrayMaps(Handle<Context> native_context,Handle<Map> initial_map)12722 Handle<Object> CacheInitialJSArrayMaps(
12723     Handle<Context> native_context, Handle<Map> initial_map) {
12724   // Replace all of the cached initial array maps in the native context with
12725   // the appropriate transitioned elements kind maps.
12726   Handle<Map> current_map = initial_map;
12727   ElementsKind kind = current_map->elements_kind();
12728   DCHECK_EQ(GetInitialFastElementsKind(), kind);
12729   native_context->set(Context::ArrayMapIndex(kind), *current_map);
12730   for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1;
12731        i < kFastElementsKindCount; ++i) {
12732     Handle<Map> new_map;
12733     ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
12734     if (Map* maybe_elements_transition = current_map->ElementsTransitionMap()) {
12735       new_map = handle(maybe_elements_transition);
12736     } else {
12737       new_map = Map::CopyAsElementsKind(
12738           current_map, next_kind, INSERT_TRANSITION);
12739     }
12740     DCHECK_EQ(next_kind, new_map->elements_kind());
12741     native_context->set(Context::ArrayMapIndex(next_kind), *new_map);
12742     current_map = new_map;
12743   }
12744   return initial_map;
12745 }
12746 
12747 namespace {
12748 
SetInstancePrototype(Isolate * isolate,Handle<JSFunction> function,Handle<JSReceiver> value)12749 void SetInstancePrototype(Isolate* isolate, Handle<JSFunction> function,
12750                           Handle<JSReceiver> value) {
12751   // Now some logic for the maps of the objects that are created by using this
12752   // function as a constructor.
12753   if (function->has_initial_map()) {
12754     // If the function has allocated the initial map replace it with a
12755     // copy containing the new prototype.  Also complete any in-object
12756     // slack tracking that is in progress at this point because it is
12757     // still tracking the old copy.
12758     function->CompleteInobjectSlackTrackingIfActive();
12759 
12760     Handle<Map> initial_map(function->initial_map(), isolate);
12761 
12762     if (!initial_map->GetIsolate()->bootstrapper()->IsActive() &&
12763         initial_map->instance_type() == JS_OBJECT_TYPE) {
12764       // Put the value in the initial map field until an initial map is needed.
12765       // At that point, a new initial map is created and the prototype is put
12766       // into the initial map where it belongs.
12767       function->set_prototype_or_initial_map(*value);
12768     } else {
12769       Handle<Map> new_map = Map::Copy(initial_map, "SetInstancePrototype");
12770       JSFunction::SetInitialMap(function, new_map, value);
12771 
12772       // If the function is used as the global Array function, cache the
12773       // updated initial maps (and transitioned versions) in the native context.
12774       Handle<Context> native_context(function->context()->native_context(),
12775                                      isolate);
12776       Handle<Object> array_function(
12777           native_context->get(Context::ARRAY_FUNCTION_INDEX), isolate);
12778       if (array_function->IsJSFunction() &&
12779           *function == JSFunction::cast(*array_function)) {
12780         CacheInitialJSArrayMaps(native_context, new_map);
12781       }
12782     }
12783 
12784     // Deoptimize all code that embeds the previous initial map.
12785     initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
12786         isolate, DependentCode::kInitialMapChangedGroup);
12787   } else {
12788     // Put the value in the initial map field until an initial map is
12789     // needed.  At that point, a new initial map is created and the
12790     // prototype is put into the initial map where it belongs.
12791     function->set_prototype_or_initial_map(*value);
12792     if (value->IsJSObject()) {
12793       // Optimize as prototype to detach it from its transition tree.
12794       JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value));
12795     }
12796   }
12797 }
12798 
12799 }  // anonymous namespace
12800 
SetPrototype(Handle<JSFunction> function,Handle<Object> value)12801 void JSFunction::SetPrototype(Handle<JSFunction> function,
12802                               Handle<Object> value) {
12803   DCHECK(function->IsConstructor() ||
12804          IsGeneratorFunction(function->shared()->kind()));
12805   Isolate* isolate = function->GetIsolate();
12806   Handle<JSReceiver> construct_prototype;
12807 
12808   // If the value is not a JSReceiver, store the value in the map's
12809   // constructor field so it can be accessed.  Also, set the prototype
12810   // used for constructing objects to the original object prototype.
12811   // See ECMA-262 13.2.2.
12812   if (!value->IsJSReceiver()) {
12813     // Copy the map so this does not affect unrelated functions.
12814     // Remove map transitions because they point to maps with a
12815     // different prototype.
12816     Handle<Map> new_map = Map::Copy(handle(function->map()), "SetPrototype");
12817 
12818     JSObject::MigrateToMap(function, new_map);
12819     new_map->SetConstructor(*value);
12820     new_map->set_has_non_instance_prototype(true);
12821 
12822     FunctionKind kind = function->shared()->kind();
12823     Handle<Context> native_context(function->context()->native_context());
12824 
12825     construct_prototype = Handle<JSReceiver>(
12826         IsGeneratorFunction(kind)
12827             ? IsAsyncFunction(kind)
12828                   ? native_context->initial_async_generator_prototype()
12829                   : native_context->initial_generator_prototype()
12830             : native_context->initial_object_prototype(),
12831         isolate);
12832   } else {
12833     construct_prototype = Handle<JSReceiver>::cast(value);
12834     function->map()->set_has_non_instance_prototype(false);
12835   }
12836 
12837   SetInstancePrototype(isolate, function, construct_prototype);
12838 }
12839 
12840 
SetInitialMap(Handle<JSFunction> function,Handle<Map> map,Handle<Object> prototype)12841 void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
12842                                Handle<Object> prototype) {
12843   if (map->prototype() != *prototype) Map::SetPrototype(map, prototype);
12844   function->set_prototype_or_initial_map(*map);
12845   map->SetConstructor(*function);
12846   if (FLAG_trace_maps) {
12847     LOG(map->GetIsolate(), MapEvent("InitialMap", nullptr, *map, "",
12848                                     function->shared()->DebugName()));
12849   }
12850 }
12851 
12852 
12853 #ifdef DEBUG
12854 namespace {
12855 
CanSubclassHaveInobjectProperties(InstanceType instance_type)12856 bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
12857   switch (instance_type) {
12858     case JS_API_OBJECT_TYPE:
12859     case JS_ARRAY_BUFFER_TYPE:
12860     case JS_ARRAY_TYPE:
12861     case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
12862     case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
12863     case JS_DATA_VIEW_TYPE:
12864     case JS_DATE_TYPE:
12865     case JS_FUNCTION_TYPE:
12866     case JS_GENERATOR_OBJECT_TYPE:
12867     case JS_ASYNC_GENERATOR_OBJECT_TYPE:
12868     case JS_MAP_TYPE:
12869     case JS_MESSAGE_OBJECT_TYPE:
12870     case JS_OBJECT_TYPE:
12871     case JS_ERROR_TYPE:
12872     case JS_ARGUMENTS_TYPE:
12873     case JS_PROMISE_TYPE:
12874     case JS_REGEXP_TYPE:
12875     case JS_SET_TYPE:
12876     case JS_SPECIAL_API_OBJECT_TYPE:
12877     case JS_TYPED_ARRAY_TYPE:
12878     case JS_VALUE_TYPE:
12879     case JS_WEAK_MAP_TYPE:
12880     case JS_WEAK_SET_TYPE:
12881     case WASM_GLOBAL_TYPE:
12882     case WASM_INSTANCE_TYPE:
12883     case WASM_MEMORY_TYPE:
12884     case WASM_MODULE_TYPE:
12885     case WASM_TABLE_TYPE:
12886       return true;
12887 
12888     case BIGINT_TYPE:
12889     case BOILERPLATE_DESCRIPTION_TYPE:
12890     case BYTECODE_ARRAY_TYPE:
12891     case BYTE_ARRAY_TYPE:
12892     case CELL_TYPE:
12893     case CODE_TYPE:
12894     case FILLER_TYPE:
12895     case FIXED_ARRAY_TYPE:
12896     case FIXED_DOUBLE_ARRAY_TYPE:
12897     case FEEDBACK_METADATA_TYPE:
12898     case FOREIGN_TYPE:
12899     case FREE_SPACE_TYPE:
12900     case HASH_TABLE_TYPE:
12901     case HEAP_NUMBER_TYPE:
12902     case JS_BOUND_FUNCTION_TYPE:
12903     case JS_GLOBAL_OBJECT_TYPE:
12904     case JS_GLOBAL_PROXY_TYPE:
12905     case JS_PROXY_TYPE:
12906     case MAP_TYPE:
12907     case MUTABLE_HEAP_NUMBER_TYPE:
12908     case ODDBALL_TYPE:
12909     case PROPERTY_CELL_TYPE:
12910     case SHARED_FUNCTION_INFO_TYPE:
12911     case SYMBOL_TYPE:
12912     case WEAK_CELL_TYPE:
12913 
12914 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
12915   case FIXED_##TYPE##_ARRAY_TYPE:
12916 #undef TYPED_ARRAY_CASE
12917 
12918 #define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE:
12919       STRUCT_LIST(MAKE_STRUCT_CASE)
12920 #undef MAKE_STRUCT_CASE
12921       // We must not end up here for these instance types at all.
12922       UNREACHABLE();
12923     // Fall through.
12924     default:
12925       return false;
12926   }
12927 }
12928 
12929 }  // namespace
12930 #endif
12931 
12932 
EnsureHasInitialMap(Handle<JSFunction> function)12933 void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
12934   DCHECK(function->has_prototype_slot());
12935   DCHECK(function->IsConstructor() ||
12936          IsResumableFunction(function->shared()->kind()));
12937   if (function->has_initial_map()) return;
12938   Isolate* isolate = function->GetIsolate();
12939 
12940   // First create a new map with the size and number of in-object properties
12941   // suggested by the function.
12942   InstanceType instance_type;
12943   if (IsResumableFunction(function->shared()->kind())) {
12944     instance_type = IsAsyncGeneratorFunction(function->shared()->kind())
12945                         ? JS_ASYNC_GENERATOR_OBJECT_TYPE
12946                         : JS_GENERATOR_OBJECT_TYPE;
12947   } else {
12948     instance_type = JS_OBJECT_TYPE;
12949   }
12950 
12951   // The constructor should be compiled for the optimization hints to be
12952   // available.
12953   int expected_nof_properties = 0;
12954   if (function->shared()->is_compiled() ||
12955       Compiler::Compile(function, Compiler::CLEAR_EXCEPTION)) {
12956     DCHECK(function->shared()->is_compiled());
12957     expected_nof_properties = function->shared()->expected_nof_properties();
12958   }
12959 
12960   int instance_size;
12961   int inobject_properties;
12962   CalculateInstanceSizeHelper(instance_type, false, 0, expected_nof_properties,
12963                               &instance_size, &inobject_properties);
12964 
12965   Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size,
12966                                                TERMINAL_FAST_ELEMENTS_KIND,
12967                                                inobject_properties);
12968 
12969   // Fetch or allocate prototype.
12970   Handle<Object> prototype;
12971   if (function->has_instance_prototype()) {
12972     prototype = handle(function->instance_prototype(), isolate);
12973   } else {
12974     prototype = isolate->factory()->NewFunctionPrototype(function);
12975   }
12976   DCHECK(map->has_fast_object_elements());
12977 
12978   // Finally link initial map and constructor function.
12979   DCHECK(prototype->IsJSReceiver());
12980   JSFunction::SetInitialMap(function, map, prototype);
12981   map->StartInobjectSlackTracking();
12982 }
12983 
12984 namespace {
FastInitializeDerivedMap(Isolate * isolate,Handle<JSFunction> new_target,Handle<JSFunction> constructor,Handle<Map> constructor_initial_map)12985 bool FastInitializeDerivedMap(Isolate* isolate, Handle<JSFunction> new_target,
12986                               Handle<JSFunction> constructor,
12987                               Handle<Map> constructor_initial_map) {
12988   // Check that |function|'s initial map still in sync with the |constructor|,
12989   // otherwise we must create a new initial map for |function|.
12990   if (new_target->has_initial_map() &&
12991       new_target->initial_map()->GetConstructor() == *constructor) {
12992     DCHECK(new_target->instance_prototype()->IsJSReceiver());
12993     return true;
12994   }
12995   InstanceType instance_type = constructor_initial_map->instance_type();
12996   DCHECK(CanSubclassHaveInobjectProperties(instance_type));
12997   // Create a new map with the size and number of in-object properties
12998   // suggested by |function|.
12999 
13000   // Link initial map and constructor function if the new.target is actually a
13001   // subclass constructor.
13002   if (!IsDerivedConstructor(new_target->shared()->kind())) return false;
13003 
13004   int instance_size;
13005   int in_object_properties;
13006   int embedder_fields =
13007       JSObject::GetEmbedderFieldCount(*constructor_initial_map);
13008   bool success = JSFunction::CalculateInstanceSizeForDerivedClass(
13009       new_target, instance_type, embedder_fields, &instance_size,
13010       &in_object_properties);
13011 
13012   Handle<Map> map;
13013   if (success) {
13014     int pre_allocated = constructor_initial_map->GetInObjectProperties() -
13015                         constructor_initial_map->UnusedPropertyFields();
13016     CHECK_LE(constructor_initial_map->UsedInstanceSize(), instance_size);
13017     int unused_property_fields = in_object_properties - pre_allocated;
13018     map = Map::CopyInitialMap(constructor_initial_map, instance_size,
13019                               in_object_properties, unused_property_fields);
13020   } else {
13021     map = Map::CopyInitialMap(constructor_initial_map);
13022   }
13023   map->set_new_target_is_base(false);
13024   Handle<Object> prototype(new_target->instance_prototype(), isolate);
13025   JSFunction::SetInitialMap(new_target, map, prototype);
13026   DCHECK(new_target->instance_prototype()->IsJSReceiver());
13027   map->SetConstructor(*constructor);
13028   map->set_construction_counter(Map::kNoSlackTracking);
13029   map->StartInobjectSlackTracking();
13030   return true;
13031 }
13032 
13033 }  // namespace
13034 
13035 // static
GetDerivedMap(Isolate * isolate,Handle<JSFunction> constructor,Handle<JSReceiver> new_target)13036 MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
13037                                            Handle<JSFunction> constructor,
13038                                            Handle<JSReceiver> new_target) {
13039   EnsureHasInitialMap(constructor);
13040 
13041   Handle<Map> constructor_initial_map(constructor->initial_map(), isolate);
13042   if (*new_target == *constructor) return constructor_initial_map;
13043 
13044   Handle<Map> result_map;
13045   // Fast case, new.target is a subclass of constructor. The map is cacheable
13046   // (and may already have been cached). new.target.prototype is guaranteed to
13047   // be a JSReceiver.
13048   if (new_target->IsJSFunction()) {
13049     Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
13050     if (FastInitializeDerivedMap(isolate, function, constructor,
13051                                  constructor_initial_map)) {
13052       return handle(function->initial_map(), isolate);
13053     }
13054   }
13055 
13056   // Slow path, new.target is either a proxy or can't cache the map.
13057   // new.target.prototype is not guaranteed to be a JSReceiver, and may need to
13058   // fall back to the intrinsicDefaultProto.
13059   Handle<Object> prototype;
13060   if (new_target->IsJSFunction()) {
13061     Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
13062     // Make sure the new.target.prototype is cached.
13063     EnsureHasInitialMap(function);
13064     prototype = handle(function->prototype(), isolate);
13065   } else {
13066     Handle<String> prototype_string = isolate->factory()->prototype_string();
13067     ASSIGN_RETURN_ON_EXCEPTION(
13068         isolate, prototype,
13069         JSReceiver::GetProperty(new_target, prototype_string), Map);
13070     // The above prototype lookup might change the constructor and its
13071     // prototype, hence we have to reload the initial map.
13072     EnsureHasInitialMap(constructor);
13073     constructor_initial_map = handle(constructor->initial_map(), isolate);
13074   }
13075 
13076   // If prototype is not a JSReceiver, fetch the intrinsicDefaultProto from the
13077   // correct realm. Rather than directly fetching the .prototype, we fetch the
13078   // constructor that points to the .prototype. This relies on
13079   // constructor.prototype being FROZEN for those constructors.
13080   if (!prototype->IsJSReceiver()) {
13081     Handle<Context> context;
13082     ASSIGN_RETURN_ON_EXCEPTION(isolate, context,
13083                                JSReceiver::GetFunctionRealm(new_target), Map);
13084     DCHECK(context->IsNativeContext());
13085     Handle<Object> maybe_index = JSReceiver::GetDataProperty(
13086         constructor, isolate->factory()->native_context_index_symbol());
13087     int index = maybe_index->IsSmi() ? Smi::ToInt(*maybe_index)
13088                                      : Context::OBJECT_FUNCTION_INDEX;
13089     Handle<JSFunction> realm_constructor(JSFunction::cast(context->get(index)));
13090     prototype = handle(realm_constructor->prototype(), isolate);
13091   }
13092 
13093   Handle<Map> map = Map::CopyInitialMap(constructor_initial_map);
13094   map->set_new_target_is_base(false);
13095   CHECK(prototype->IsJSReceiver());
13096   if (map->prototype() != *prototype) Map::SetPrototype(map, prototype);
13097   map->SetConstructor(*constructor);
13098   return map;
13099 }
13100 
13101 
PrintName(FILE * out)13102 void JSFunction::PrintName(FILE* out) {
13103   std::unique_ptr<char[]> name = shared()->DebugName()->ToCString();
13104   PrintF(out, "%s", name.get());
13105 }
13106 
13107 
GetName(Handle<JSFunction> function)13108 Handle<String> JSFunction::GetName(Handle<JSFunction> function) {
13109   Isolate* isolate = function->GetIsolate();
13110   Handle<Object> name =
13111       JSReceiver::GetDataProperty(function, isolate->factory()->name_string());
13112   if (name->IsString()) return Handle<String>::cast(name);
13113   return handle(function->shared()->DebugName(), isolate);
13114 }
13115 
13116 
GetDebugName(Handle<JSFunction> function)13117 Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) {
13118   Isolate* isolate = function->GetIsolate();
13119   Handle<Object> name = JSReceiver::GetDataProperty(
13120       function, isolate->factory()->display_name_string());
13121   if (name->IsString()) return Handle<String>::cast(name);
13122   return JSFunction::GetName(function);
13123 }
13124 
SetName(Handle<JSFunction> function,Handle<Name> name,Handle<String> prefix)13125 bool JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name,
13126                          Handle<String> prefix) {
13127   Isolate* isolate = function->GetIsolate();
13128   Handle<String> function_name;
13129   ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, function_name,
13130                                    Name::ToFunctionName(name), false);
13131   if (prefix->length() > 0) {
13132     IncrementalStringBuilder builder(isolate);
13133     builder.AppendString(prefix);
13134     builder.AppendCharacter(' ');
13135     builder.AppendString(function_name);
13136     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, function_name, builder.Finish(),
13137                                      false);
13138   }
13139   RETURN_ON_EXCEPTION_VALUE(
13140       isolate,
13141       JSObject::DefinePropertyOrElementIgnoreAttributes(
13142           function, isolate->factory()->name_string(), function_name,
13143           static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY)),
13144       false);
13145   return true;
13146 }
13147 
13148 namespace {
13149 
NativeCodeFunctionSourceString(Handle<SharedFunctionInfo> shared_info)13150 Handle<String> NativeCodeFunctionSourceString(
13151     Handle<SharedFunctionInfo> shared_info) {
13152   Isolate* const isolate = shared_info->GetIsolate();
13153   IncrementalStringBuilder builder(isolate);
13154   builder.AppendCString("function ");
13155   builder.AppendString(handle(shared_info->Name(), isolate));
13156   builder.AppendCString("() { [native code] }");
13157   return builder.Finish().ToHandleChecked();
13158 }
13159 
13160 }  // namespace
13161 
13162 
13163 // static
ToString(Handle<JSBoundFunction> function)13164 Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) {
13165   Isolate* const isolate = function->GetIsolate();
13166   return isolate->factory()->function_native_code_string();
13167 }
13168 
13169 
13170 // static
ToString(Handle<JSFunction> function)13171 Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
13172   Isolate* const isolate = function->GetIsolate();
13173   Handle<SharedFunctionInfo> shared_info(function->shared(), isolate);
13174 
13175   // Check if {function} should hide its source code.
13176   if (!shared_info->IsUserJavaScript()) {
13177     return NativeCodeFunctionSourceString(shared_info);
13178   }
13179 
13180   // Check if we should print {function} as a class.
13181   Handle<Object> maybe_class_positions = JSReceiver::GetDataProperty(
13182       function, isolate->factory()->class_positions_symbol());
13183   if (maybe_class_positions->IsTuple2()) {
13184     Tuple2* class_positions = Tuple2::cast(*maybe_class_positions);
13185     int start_position = Smi::ToInt(class_positions->value1());
13186     int end_position = Smi::ToInt(class_positions->value2());
13187     Handle<String> script_source(
13188         String::cast(Script::cast(shared_info->script())->source()), isolate);
13189     return isolate->factory()->NewSubString(script_source, start_position,
13190                                             end_position);
13191   }
13192 
13193   // Check if we have source code for the {function}.
13194   if (!shared_info->HasSourceCode()) {
13195     return NativeCodeFunctionSourceString(shared_info);
13196   }
13197 
13198   if (FLAG_harmony_function_tostring) {
13199     return Handle<String>::cast(
13200         SharedFunctionInfo::GetSourceCodeHarmony(shared_info));
13201   }
13202 
13203   IncrementalStringBuilder builder(isolate);
13204   FunctionKind kind = shared_info->kind();
13205   if (!IsArrowFunction(kind)) {
13206     if (IsConciseMethod(kind)) {
13207       if (IsAsyncGeneratorFunction(kind)) {
13208         builder.AppendCString("async *");
13209       } else if (IsGeneratorFunction(kind)) {
13210         builder.AppendCharacter('*');
13211       } else if (IsAsyncFunction(kind)) {
13212         builder.AppendCString("async ");
13213       }
13214     } else {
13215       if (IsAsyncGeneratorFunction(kind)) {
13216         builder.AppendCString("async function* ");
13217       } else if (IsGeneratorFunction(kind)) {
13218         builder.AppendCString("function* ");
13219       } else if (IsAsyncFunction(kind)) {
13220         builder.AppendCString("async function ");
13221       } else {
13222         builder.AppendCString("function ");
13223       }
13224     }
13225     if (shared_info->name_should_print_as_anonymous()) {
13226       builder.AppendCString("anonymous");
13227     } else if (!shared_info->is_anonymous_expression()) {
13228       builder.AppendString(handle(shared_info->Name(), isolate));
13229     }
13230   }
13231   if (shared_info->is_wrapped()) {
13232     builder.AppendCharacter('(');
13233     Handle<FixedArray> args(
13234         Script::cast(shared_info->script())->wrapped_arguments());
13235     int argc = args->length();
13236     for (int i = 0; i < argc; i++) {
13237       if (i > 0) builder.AppendCString(", ");
13238       builder.AppendString(Handle<String>(String::cast(args->get(i))));
13239     }
13240     builder.AppendCString(") {\n");
13241   }
13242   builder.AppendString(
13243       Handle<String>::cast(SharedFunctionInfo::GetSourceCode(shared_info)));
13244   if (shared_info->is_wrapped()) {
13245     builder.AppendCString("\n}");
13246   }
13247   return builder.Finish().ToHandleChecked();
13248 }
13249 
Initialize(Isolate * isolate,Handle<Oddball> oddball,const char * to_string,Handle<Object> to_number,const char * type_of,byte kind)13250 void Oddball::Initialize(Isolate* isolate, Handle<Oddball> oddball,
13251                          const char* to_string, Handle<Object> to_number,
13252                          const char* type_of, byte kind) {
13253   Handle<String> internalized_to_string =
13254       isolate->factory()->InternalizeUtf8String(to_string);
13255   Handle<String> internalized_type_of =
13256       isolate->factory()->InternalizeUtf8String(type_of);
13257   if (to_number->IsHeapNumber()) {
13258     oddball->set_to_number_raw_as_bits(
13259         Handle<HeapNumber>::cast(to_number)->value_as_bits());
13260   } else {
13261     oddball->set_to_number_raw(to_number->Number());
13262   }
13263   oddball->set_to_number(*to_number);
13264   oddball->set_to_string(*internalized_to_string);
13265   oddball->set_type_of(*internalized_type_of);
13266   oddball->set_kind(kind);
13267 }
13268 
GetEvalPosition()13269 int Script::GetEvalPosition() {
13270   DisallowHeapAllocation no_gc;
13271   DCHECK(compilation_type() == Script::COMPILATION_TYPE_EVAL);
13272   int position = eval_from_position();
13273   if (position < 0) {
13274     // Due to laziness, the position may not have been translated from code
13275     // offset yet, which would be encoded as negative integer. In that case,
13276     // translate and set the position.
13277     if (!has_eval_from_shared()) {
13278       position = 0;
13279     } else {
13280       SharedFunctionInfo* shared = eval_from_shared();
13281       position = shared->abstract_code()->SourcePosition(-position);
13282     }
13283     DCHECK_GE(position, 0);
13284     set_eval_from_position(position);
13285   }
13286   return position;
13287 }
13288 
InitLineEnds(Handle<Script> script)13289 void Script::InitLineEnds(Handle<Script> script) {
13290   Isolate* isolate = script->GetIsolate();
13291   if (!script->line_ends()->IsUndefined(isolate)) return;
13292   DCHECK_NE(Script::TYPE_WASM, script->type());
13293 
13294   Object* src_obj = script->source();
13295   if (!src_obj->IsString()) {
13296     DCHECK(src_obj->IsUndefined(isolate));
13297     script->set_line_ends(isolate->heap()->empty_fixed_array());
13298   } else {
13299     DCHECK(src_obj->IsString());
13300     Handle<String> src(String::cast(src_obj), isolate);
13301     Handle<FixedArray> array = String::CalculateLineEnds(src, true);
13302     script->set_line_ends(*array);
13303   }
13304 
13305   DCHECK(script->line_ends()->IsFixedArray());
13306 }
13307 
GetPositionInfo(Handle<Script> script,int position,PositionInfo * info,OffsetFlag offset_flag)13308 bool Script::GetPositionInfo(Handle<Script> script, int position,
13309                              PositionInfo* info, OffsetFlag offset_flag) {
13310   // For wasm, we do not create an artificial line_ends array, but do the
13311   // translation directly.
13312   if (script->type() != Script::TYPE_WASM) InitLineEnds(script);
13313   return script->GetPositionInfo(position, info, offset_flag);
13314 }
13315 
IsUserJavaScript()13316 bool Script::IsUserJavaScript() { return type() == Script::TYPE_NORMAL; }
13317 
ContainsAsmModule()13318 bool Script::ContainsAsmModule() {
13319   DisallowHeapAllocation no_gc;
13320   SharedFunctionInfo::ScriptIterator iter(Handle<Script>(this));
13321   while (SharedFunctionInfo* info = iter.Next()) {
13322     if (info->HasAsmWasmData()) return true;
13323   }
13324   return false;
13325 }
13326 
13327 namespace {
GetPositionInfoSlow(const Script * script,int position,Script::PositionInfo * info)13328 bool GetPositionInfoSlow(const Script* script, int position,
13329                          Script::PositionInfo* info) {
13330   if (!script->source()->IsString()) return false;
13331   if (position < 0) position = 0;
13332 
13333   String* source_string = String::cast(script->source());
13334   int line = 0;
13335   int line_start = 0;
13336   int len = source_string->length();
13337   for (int pos = 0; pos <= len; ++pos) {
13338     if (pos == len || source_string->Get(pos) == '\n') {
13339       if (position <= pos) {
13340         info->line = line;
13341         info->column = position - line_start;
13342         info->line_start = line_start;
13343         info->line_end = pos;
13344         return true;
13345       }
13346       line++;
13347       line_start = pos + 1;
13348     }
13349   }
13350   return false;
13351 }
13352 }  // namespace
13353 
13354 #define SMI_VALUE(x) (Smi::ToInt(x))
GetPositionInfo(int position,PositionInfo * info,OffsetFlag offset_flag) const13355 bool Script::GetPositionInfo(int position, PositionInfo* info,
13356                              OffsetFlag offset_flag) const {
13357   DisallowHeapAllocation no_allocation;
13358 
13359   // For wasm, we do not rely on the line_ends array, but do the translation
13360   // directly.
13361   if (type() == Script::TYPE_WASM) {
13362     DCHECK_LE(0, position);
13363     return WasmModuleObject::cast(wasm_module_object())
13364         ->shared()
13365         ->GetPositionInfo(static_cast<uint32_t>(position), info);
13366   }
13367 
13368   if (line_ends()->IsUndefined(GetIsolate())) {
13369     // Slow mode: we do not have line_ends. We have to iterate through source.
13370     if (!GetPositionInfoSlow(this, position, info)) return false;
13371   } else {
13372     DCHECK(line_ends()->IsFixedArray());
13373     FixedArray* ends = FixedArray::cast(line_ends());
13374 
13375     const int ends_len = ends->length();
13376     if (ends_len == 0) return false;
13377 
13378     // Return early on invalid positions. Negative positions behave as if 0 was
13379     // passed, and positions beyond the end of the script return as failure.
13380     if (position < 0) {
13381       position = 0;
13382     } else if (position > SMI_VALUE(ends->get(ends_len - 1))) {
13383       return false;
13384     }
13385 
13386     // Determine line number by doing a binary search on the line ends array.
13387     if (SMI_VALUE(ends->get(0)) >= position) {
13388       info->line = 0;
13389       info->line_start = 0;
13390       info->column = position;
13391     } else {
13392       int left = 0;
13393       int right = ends_len - 1;
13394 
13395       while (right > 0) {
13396         DCHECK_LE(left, right);
13397         const int mid = (left + right) / 2;
13398         if (position > SMI_VALUE(ends->get(mid))) {
13399           left = mid + 1;
13400         } else if (position <= SMI_VALUE(ends->get(mid - 1))) {
13401           right = mid - 1;
13402         } else {
13403           info->line = mid;
13404           break;
13405         }
13406       }
13407       DCHECK(SMI_VALUE(ends->get(info->line)) >= position &&
13408              SMI_VALUE(ends->get(info->line - 1)) < position);
13409       info->line_start = SMI_VALUE(ends->get(info->line - 1)) + 1;
13410       info->column = position - info->line_start;
13411     }
13412 
13413     // Line end is position of the linebreak character.
13414     info->line_end = SMI_VALUE(ends->get(info->line));
13415     if (info->line_end > 0) {
13416       DCHECK(source()->IsString());
13417       String* src = String::cast(source());
13418       if (src->length() >= info->line_end &&
13419           src->Get(info->line_end - 1) == '\r') {
13420         info->line_end--;
13421       }
13422     }
13423   }
13424 
13425   // Add offsets if requested.
13426   if (offset_flag == WITH_OFFSET) {
13427     if (info->line == 0) {
13428       info->column += column_offset();
13429     }
13430     info->line += line_offset();
13431   }
13432 
13433   return true;
13434 }
13435 #undef SMI_VALUE
13436 
GetColumnNumber(Handle<Script> script,int code_pos)13437 int Script::GetColumnNumber(Handle<Script> script, int code_pos) {
13438   PositionInfo info;
13439   GetPositionInfo(script, code_pos, &info, WITH_OFFSET);
13440   return info.column;
13441 }
13442 
GetColumnNumber(int code_pos) const13443 int Script::GetColumnNumber(int code_pos) const {
13444   PositionInfo info;
13445   GetPositionInfo(code_pos, &info, WITH_OFFSET);
13446   return info.column;
13447 }
13448 
GetLineNumber(Handle<Script> script,int code_pos)13449 int Script::GetLineNumber(Handle<Script> script, int code_pos) {
13450   PositionInfo info;
13451   GetPositionInfo(script, code_pos, &info, WITH_OFFSET);
13452   return info.line;
13453 }
13454 
GetLineNumber(int code_pos) const13455 int Script::GetLineNumber(int code_pos) const {
13456   PositionInfo info;
13457   GetPositionInfo(code_pos, &info, WITH_OFFSET);
13458   return info.line;
13459 }
13460 
GetNameOrSourceURL()13461 Object* Script::GetNameOrSourceURL() {
13462   Isolate* isolate = GetIsolate();
13463   // Keep in sync with ScriptNameOrSourceURL in messages.js.
13464   if (!source_url()->IsUndefined(isolate)) return source_url();
13465   return name();
13466 }
13467 
13468 
GetWrapper(Handle<Script> script)13469 Handle<JSObject> Script::GetWrapper(Handle<Script> script) {
13470   Isolate* isolate = script->GetIsolate();
13471   if (!script->wrapper()->IsUndefined(isolate)) {
13472     DCHECK(script->wrapper()->IsWeakCell());
13473     Handle<WeakCell> cell(WeakCell::cast(script->wrapper()));
13474     if (!cell->cleared()) {
13475       // Return a handle for the existing script wrapper from the cache.
13476       return handle(JSObject::cast(cell->value()));
13477     }
13478     // If we found an empty WeakCell, that means the script wrapper was
13479     // GCed.  We are not notified directly of that, so we decrement here
13480     // so that we at least don't count double for any given script.
13481     isolate->counters()->script_wrappers()->Decrement();
13482   }
13483   // Construct a new script wrapper.
13484   isolate->counters()->script_wrappers()->Increment();
13485   Handle<JSFunction> constructor = isolate->script_function();
13486   Handle<JSValue> result =
13487       Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
13488   result->set_value(*script);
13489   Handle<WeakCell> cell = isolate->factory()->NewWeakCell(result);
13490   script->set_wrapper(*cell);
13491   return result;
13492 }
13493 
FindSharedFunctionInfo(Isolate * isolate,const FunctionLiteral * fun)13494 MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
13495     Isolate* isolate, const FunctionLiteral* fun) {
13496   CHECK_NE(fun->function_literal_id(), FunctionLiteral::kIdTypeInvalid);
13497   // If this check fails, the problem is most probably the function id
13498   // renumbering done by AstFunctionLiteralIdReindexer; in particular, that
13499   // AstTraversalVisitor doesn't recurse properly in the construct which
13500   // triggers the mismatch.
13501   CHECK_LT(fun->function_literal_id(), shared_function_infos()->length());
13502   MaybeObject* shared =
13503       shared_function_infos()->Get(fun->function_literal_id());
13504   HeapObject* heap_object;
13505   if (!shared->ToStrongOrWeakHeapObject(&heap_object) ||
13506       heap_object->IsUndefined(isolate)) {
13507     return MaybeHandle<SharedFunctionInfo>();
13508   }
13509   return handle(SharedFunctionInfo::cast(heap_object));
13510 }
13511 
Iterator(Isolate * isolate)13512 Script::Iterator::Iterator(Isolate* isolate)
13513     : iterator_(isolate->heap()->script_list()) {}
13514 
13515 
Next()13516 Script* Script::Iterator::Next() { return iterator_.Next<Script>(); }
13517 
13518 
ScriptIterator(Handle<Script> script)13519 SharedFunctionInfo::ScriptIterator::ScriptIterator(Handle<Script> script)
13520     : ScriptIterator(script->GetIsolate(),
13521                      handle(script->shared_function_infos())) {}
13522 
ScriptIterator(Isolate * isolate,Handle<WeakFixedArray> shared_function_infos)13523 SharedFunctionInfo::ScriptIterator::ScriptIterator(
13524     Isolate* isolate, Handle<WeakFixedArray> shared_function_infos)
13525     : isolate_(isolate),
13526       shared_function_infos_(shared_function_infos),
13527       index_(0) {}
13528 
Next()13529 SharedFunctionInfo* SharedFunctionInfo::ScriptIterator::Next() {
13530   while (index_ < shared_function_infos_->length()) {
13531     MaybeObject* raw = shared_function_infos_->Get(index_++);
13532     HeapObject* heap_object;
13533     if (!raw->ToStrongOrWeakHeapObject(&heap_object) ||
13534         heap_object->IsUndefined(isolate_)) {
13535       continue;
13536     }
13537     return SharedFunctionInfo::cast(heap_object);
13538   }
13539   return nullptr;
13540 }
13541 
Reset(Handle<Script> script)13542 void SharedFunctionInfo::ScriptIterator::Reset(Handle<Script> script) {
13543   shared_function_infos_ = handle(script->shared_function_infos());
13544   index_ = 0;
13545 }
13546 
GlobalIterator(Isolate * isolate)13547 SharedFunctionInfo::GlobalIterator::GlobalIterator(Isolate* isolate)
13548     : script_iterator_(isolate),
13549       noscript_sfi_iterator_(isolate->heap()->noscript_shared_function_infos()),
13550       sfi_iterator_(handle(script_iterator_.Next(), isolate)) {}
13551 
Next()13552 SharedFunctionInfo* SharedFunctionInfo::GlobalIterator::Next() {
13553   SharedFunctionInfo* next = noscript_sfi_iterator_.Next<SharedFunctionInfo>();
13554   if (next != nullptr) return next;
13555   for (;;) {
13556     next = sfi_iterator_.Next();
13557     if (next != nullptr) return next;
13558     Script* next_script = script_iterator_.Next();
13559     if (next_script == nullptr) return nullptr;
13560     sfi_iterator_.Reset(handle(next_script));
13561   }
13562 }
13563 
SetScript(Handle<SharedFunctionInfo> shared,Handle<Object> script_object,bool reset_preparsed_scope_data)13564 void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
13565                                    Handle<Object> script_object,
13566                                    bool reset_preparsed_scope_data) {
13567   DCHECK_NE(shared->function_literal_id(), FunctionLiteral::kIdTypeInvalid);
13568   if (shared->script() == *script_object) return;
13569   Isolate* isolate = shared->GetIsolate();
13570 
13571   if (reset_preparsed_scope_data && shared->HasPreParsedScopeData()) {
13572     shared->ClearPreParsedScopeData();
13573   }
13574 
13575   // Add shared function info to new script's list. If a collection occurs,
13576   // the shared function info may be temporarily in two lists.
13577   // This is okay because the gc-time processing of these lists can tolerate
13578   // duplicates.
13579   if (script_object->IsScript()) {
13580     Handle<Script> script = Handle<Script>::cast(script_object);
13581     Handle<WeakFixedArray> list =
13582         handle(script->shared_function_infos(), isolate);
13583 #ifdef DEBUG
13584     DCHECK_LT(shared->function_literal_id(), list->length());
13585     MaybeObject* maybe_object = list->Get(shared->function_literal_id());
13586     HeapObject* heap_object;
13587     if (maybe_object->ToWeakHeapObject(&heap_object)) {
13588       DCHECK_EQ(heap_object, *shared);
13589     }
13590 #endif
13591     list->Set(shared->function_literal_id(),
13592               HeapObjectReference::Weak(*shared));
13593   } else {
13594     Handle<Object> list = isolate->factory()->noscript_shared_function_infos();
13595 
13596 #ifdef DEBUG
13597     if (FLAG_enable_slow_asserts) {
13598       FixedArrayOfWeakCells::Iterator iterator(*list);
13599       SharedFunctionInfo* next;
13600       while ((next = iterator.Next<SharedFunctionInfo>()) != nullptr) {
13601         DCHECK_NE(next, *shared);
13602       }
13603     }
13604 #endif  // DEBUG
13605 
13606     list = FixedArrayOfWeakCells::Add(list, shared);
13607 
13608     isolate->heap()->SetRootNoScriptSharedFunctionInfos(*list);
13609   }
13610 
13611   if (shared->script()->IsScript()) {
13612     // Remove shared function info from old script's list.
13613     Script* old_script = Script::cast(shared->script());
13614 
13615     // Due to liveedit, it might happen that the old_script doesn't know
13616     // about the SharedFunctionInfo, so we have to guard against that.
13617     Handle<WeakFixedArray> infos(old_script->shared_function_infos(), isolate);
13618     if (shared->function_literal_id() < infos->length()) {
13619       MaybeObject* raw = old_script->shared_function_infos()->Get(
13620           shared->function_literal_id());
13621       HeapObject* heap_object;
13622       if (raw->ToWeakHeapObject(&heap_object) && heap_object == *shared) {
13623         old_script->shared_function_infos()->Set(
13624             shared->function_literal_id(),
13625             HeapObjectReference::Strong(isolate->heap()->undefined_value()));
13626       }
13627     }
13628   } else {
13629     // Remove shared function info from root array.
13630     Object* list = isolate->heap()->noscript_shared_function_infos();
13631     CHECK(FixedArrayOfWeakCells::cast(list)->Remove(shared));
13632   }
13633 
13634   // Finally set new script.
13635   shared->set_script(*script_object);
13636 }
13637 
HasBreakInfo() const13638 bool SharedFunctionInfo::HasBreakInfo() const {
13639   if (!HasDebugInfo()) return false;
13640   DebugInfo* info = DebugInfo::cast(debug_info());
13641   bool has_break_info = info->HasBreakInfo();
13642   return has_break_info;
13643 }
13644 
BreakAtEntry() const13645 bool SharedFunctionInfo::BreakAtEntry() const {
13646   if (!HasDebugInfo()) return false;
13647   DebugInfo* info = DebugInfo::cast(debug_info());
13648   bool break_at_entry = info->BreakAtEntry();
13649   return break_at_entry;
13650 }
13651 
HasCoverageInfo() const13652 bool SharedFunctionInfo::HasCoverageInfo() const {
13653   if (!HasDebugInfo()) return false;
13654   DebugInfo* info = DebugInfo::cast(debug_info());
13655   bool has_coverage_info = info->HasCoverageInfo();
13656   return has_coverage_info;
13657 }
13658 
GetCoverageInfo() const13659 CoverageInfo* SharedFunctionInfo::GetCoverageInfo() const {
13660   DCHECK(HasCoverageInfo());
13661   return CoverageInfo::cast(GetDebugInfo()->coverage_info());
13662 }
13663 
GetDebugInfo() const13664 DebugInfo* SharedFunctionInfo::GetDebugInfo() const {
13665   DCHECK(HasDebugInfo());
13666   return DebugInfo::cast(debug_info());
13667 }
13668 
debugger_hints() const13669 int SharedFunctionInfo::debugger_hints() const {
13670   if (HasDebugInfo()) return GetDebugInfo()->debugger_hints();
13671   return Smi::ToInt(debug_info());
13672 }
13673 
set_debugger_hints(int value)13674 void SharedFunctionInfo::set_debugger_hints(int value) {
13675   if (HasDebugInfo()) {
13676     GetDebugInfo()->set_debugger_hints(value);
13677   } else {
13678     set_debug_info(Smi::FromInt(value));
13679   }
13680 }
13681 
DebugName()13682 String* SharedFunctionInfo::DebugName() {
13683   DisallowHeapAllocation no_gc;
13684   String* function_name = Name();
13685   if (function_name->length() > 0) return function_name;
13686   return inferred_name();
13687 }
13688 
13689 // static
GetSideEffectState(Handle<SharedFunctionInfo> info)13690 SharedFunctionInfo::SideEffectState SharedFunctionInfo::GetSideEffectState(
13691     Handle<SharedFunctionInfo> info) {
13692   if (info->side_effect_state() == kNotComputed) {
13693     SharedFunctionInfo::SideEffectState has_no_side_effect =
13694         DebugEvaluate::FunctionGetSideEffectState(info);
13695     info->set_side_effect_state(has_no_side_effect);
13696   }
13697   return static_cast<SideEffectState>(info->side_effect_state());
13698 }
13699 
PassesFilter(const char * raw_filter)13700 bool SharedFunctionInfo::PassesFilter(const char* raw_filter) {
13701   Vector<const char> filter = CStrVector(raw_filter);
13702   std::unique_ptr<char[]> cstrname(DebugName()->ToCString());
13703   return v8::internal::PassesFilter(CStrVector(cstrname.get()), filter);
13704 }
13705 
HasSourceCode() const13706 bool SharedFunctionInfo::HasSourceCode() const {
13707   Isolate* isolate = GetIsolate();
13708   return !script()->IsUndefined(isolate) &&
13709          !reinterpret_cast<Script*>(script())->source()->IsUndefined(isolate);
13710 }
13711 
13712 // static
GetSourceCode(Handle<SharedFunctionInfo> shared)13713 Handle<Object> SharedFunctionInfo::GetSourceCode(
13714     Handle<SharedFunctionInfo> shared) {
13715   Isolate* isolate = shared->GetIsolate();
13716   if (!shared->HasSourceCode()) return isolate->factory()->undefined_value();
13717   Handle<String> source(String::cast(Script::cast(shared->script())->source()));
13718   return isolate->factory()->NewSubString(source, shared->StartPosition(),
13719                                           shared->EndPosition());
13720 }
13721 
13722 // static
GetSourceCodeHarmony(Handle<SharedFunctionInfo> shared)13723 Handle<Object> SharedFunctionInfo::GetSourceCodeHarmony(
13724     Handle<SharedFunctionInfo> shared) {
13725   Isolate* isolate = shared->GetIsolate();
13726   if (!shared->HasSourceCode()) return isolate->factory()->undefined_value();
13727   Handle<String> script_source(
13728       String::cast(Script::cast(shared->script())->source()));
13729   int start_pos = shared->function_token_position();
13730   if (start_pos == kNoSourcePosition) start_pos = shared->StartPosition();
13731   Handle<String> source = isolate->factory()->NewSubString(
13732       script_source, start_pos, shared->EndPosition());
13733   if (!shared->is_wrapped()) return source;
13734 
13735   DCHECK(!shared->name_should_print_as_anonymous());
13736   IncrementalStringBuilder builder(isolate);
13737   builder.AppendCString("function ");
13738   builder.AppendString(Handle<String>(shared->Name(), isolate));
13739   builder.AppendCString("(");
13740   Handle<FixedArray> args(Script::cast(shared->script())->wrapped_arguments());
13741   int argc = args->length();
13742   for (int i = 0; i < argc; i++) {
13743     if (i > 0) builder.AppendCString(", ");
13744     builder.AppendString(Handle<String>(String::cast(args->get(i))));
13745   }
13746   builder.AppendCString(") {\n");
13747   builder.AppendString(source);
13748   builder.AppendCString("\n}");
13749   return builder.Finish().ToHandleChecked();
13750 }
13751 
IsInlineable()13752 bool SharedFunctionInfo::IsInlineable() {
13753   // Check that the function has a script associated with it.
13754   if (!script()->IsScript()) return false;
13755   if (GetIsolate()->is_precise_binary_code_coverage() &&
13756       !has_reported_binary_coverage()) {
13757     // We may miss invocations if this function is inlined.
13758     return false;
13759   }
13760   return !optimization_disabled();
13761 }
13762 
SourceSize()13763 int SharedFunctionInfo::SourceSize() { return EndPosition() - StartPosition(); }
13764 
CalculateInstanceSizeHelper(InstanceType instance_type,bool has_prototype_slot,int requested_embedder_fields,int requested_in_object_properties,int * instance_size,int * in_object_properties)13765 void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type,
13766                                              bool has_prototype_slot,
13767                                              int requested_embedder_fields,
13768                                              int requested_in_object_properties,
13769                                              int* instance_size,
13770                                              int* in_object_properties) {
13771   DCHECK_LE(static_cast<unsigned>(requested_embedder_fields),
13772             JSObject::kMaxEmbedderFields);
13773   int header_size = JSObject::GetHeaderSize(instance_type, has_prototype_slot);
13774   int max_nof_fields =
13775       (JSObject::kMaxInstanceSize - header_size) >> kPointerSizeLog2;
13776   CHECK_LE(max_nof_fields, JSObject::kMaxInObjectProperties);
13777   CHECK_LE(static_cast<unsigned>(requested_embedder_fields),
13778            static_cast<unsigned>(max_nof_fields));
13779   *in_object_properties = Min(requested_in_object_properties,
13780                               max_nof_fields - requested_embedder_fields);
13781   *instance_size =
13782       header_size +
13783       ((requested_embedder_fields + *in_object_properties) << kPointerSizeLog2);
13784   CHECK_EQ(*in_object_properties,
13785            ((*instance_size - header_size) >> kPointerSizeLog2) -
13786                requested_embedder_fields);
13787   CHECK_LE(static_cast<unsigned>(*instance_size),
13788            static_cast<unsigned>(JSObject::kMaxInstanceSize));
13789 }
13790 
13791 // static
CalculateInstanceSizeForDerivedClass(Handle<JSFunction> function,InstanceType instance_type,int requested_embedder_fields,int * instance_size,int * in_object_properties)13792 bool JSFunction::CalculateInstanceSizeForDerivedClass(
13793     Handle<JSFunction> function, InstanceType instance_type,
13794     int requested_embedder_fields, int* instance_size,
13795     int* in_object_properties) {
13796   Isolate* isolate = function->GetIsolate();
13797   int expected_nof_properties = 0;
13798   for (PrototypeIterator iter(isolate, function, kStartAtReceiver);
13799        !iter.IsAtEnd(); iter.Advance()) {
13800     Handle<JSReceiver> current =
13801         PrototypeIterator::GetCurrent<JSReceiver>(iter);
13802     if (!current->IsJSFunction()) break;
13803     Handle<JSFunction> func(Handle<JSFunction>::cast(current));
13804     // The super constructor should be compiled for the number of expected
13805     // properties to be available.
13806     Handle<SharedFunctionInfo> shared(func->shared());
13807     if (shared->is_compiled() ||
13808         Compiler::Compile(func, Compiler::CLEAR_EXCEPTION)) {
13809       DCHECK(shared->is_compiled());
13810       int count = shared->expected_nof_properties();
13811       // Check that the estimate is sane.
13812       if (expected_nof_properties <= JSObject::kMaxInObjectProperties - count) {
13813         expected_nof_properties += count;
13814       } else {
13815         expected_nof_properties = JSObject::kMaxInObjectProperties;
13816       }
13817     } else if (!shared->is_compiled()) {
13818       // In case there was a compilation error for the constructor we will
13819       // throw an error during instantiation. Hence we directly return 0;
13820       return false;
13821     }
13822     if (!IsDerivedConstructor(shared->kind())) break;
13823   }
13824   CalculateInstanceSizeHelper(instance_type, true, requested_embedder_fields,
13825                               expected_nof_properties, instance_size,
13826                               in_object_properties);
13827   return true;
13828 }
13829 
13830 
13831 // Output the source code without any allocation in the heap.
operator <<(std::ostream & os,const SourceCodeOf & v)13832 std::ostream& operator<<(std::ostream& os, const SourceCodeOf& v) {
13833   const SharedFunctionInfo* s = v.value;
13834   // For some native functions there is no source.
13835   if (!s->HasSourceCode()) return os << "<No Source>";
13836 
13837   // Get the source for the script which this function came from.
13838   // Don't use String::cast because we don't want more assertion errors while
13839   // we are already creating a stack dump.
13840   String* script_source =
13841       reinterpret_cast<String*>(Script::cast(s->script())->source());
13842 
13843   if (!script_source->LooksValid()) return os << "<Invalid Source>";
13844 
13845   if (!s->is_toplevel()) {
13846     os << "function ";
13847     String* name = s->Name();
13848     if (name->length() > 0) {
13849       name->PrintUC16(os);
13850     }
13851   }
13852 
13853   int len = s->EndPosition() - s->StartPosition();
13854   if (len <= v.max_length || v.max_length < 0) {
13855     script_source->PrintUC16(os, s->StartPosition(), s->EndPosition());
13856     return os;
13857   } else {
13858     script_source->PrintUC16(os, s->StartPosition(),
13859                              s->StartPosition() + v.max_length);
13860     return os << "...\n";
13861   }
13862 }
13863 
13864 
DisableOptimization(BailoutReason reason)13865 void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
13866   DCHECK_NE(reason, BailoutReason::kNoReason);
13867 
13868   set_flags(DisabledOptimizationReasonBits::update(flags(), reason));
13869   // Code should be the lazy compilation stub or else interpreted.
13870   DCHECK(abstract_code()->kind() == AbstractCode::INTERPRETED_FUNCTION ||
13871          abstract_code()->kind() == AbstractCode::BUILTIN);
13872   PROFILE(GetIsolate(), CodeDisableOptEvent(abstract_code(), this));
13873   if (FLAG_trace_opt) {
13874     PrintF("[disabled optimization for ");
13875     ShortPrint();
13876     PrintF(", reason: %s]\n", GetBailoutReason(reason));
13877   }
13878 }
13879 
InitFromFunctionLiteral(Handle<SharedFunctionInfo> shared_info,FunctionLiteral * lit,bool is_toplevel)13880 void SharedFunctionInfo::InitFromFunctionLiteral(
13881     Handle<SharedFunctionInfo> shared_info, FunctionLiteral* lit,
13882     bool is_toplevel) {
13883   // When adding fields here, make sure DeclarationScope::AnalyzePartially is
13884   // updated accordingly.
13885   shared_info->set_internal_formal_parameter_count(lit->parameter_count());
13886   shared_info->set_function_token_position(lit->function_token_position());
13887   shared_info->set_raw_start_position(lit->start_position());
13888   shared_info->set_raw_end_position(lit->end_position());
13889   if (shared_info->scope_info()->HasPositionInfo()) {
13890     shared_info->scope_info()->SetPositionInfo(lit->start_position(),
13891                                                lit->end_position());
13892   }
13893   shared_info->set_is_declaration(lit->is_declaration());
13894   shared_info->set_is_named_expression(lit->is_named_expression());
13895   shared_info->set_is_anonymous_expression(lit->is_anonymous_expression());
13896   shared_info->set_inferred_name(*lit->inferred_name());
13897   shared_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
13898   shared_info->set_language_mode(lit->language_mode());
13899   shared_info->set_is_wrapped(lit->is_wrapped());
13900   //  shared_info->set_kind(lit->kind());
13901   // FunctionKind must have already been set.
13902   DCHECK(lit->kind() == shared_info->kind());
13903   shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
13904   shared_info->set_function_literal_id(lit->function_literal_id());
13905   DCHECK_IMPLIES(lit->requires_instance_fields_initializer(),
13906                  IsClassConstructor(lit->kind()));
13907   shared_info->set_requires_instance_fields_initializer(
13908       lit->requires_instance_fields_initializer());
13909 
13910   shared_info->set_is_toplevel(is_toplevel);
13911   DCHECK(shared_info->outer_scope_info()->IsTheHole(shared_info->GetIsolate()));
13912   if (!is_toplevel) {
13913     Scope* outer_scope = lit->scope()->GetOuterScopeWithContext();
13914     if (outer_scope) {
13915       shared_info->set_outer_scope_info(*outer_scope->scope_info());
13916     }
13917   }
13918 
13919   // For lazy parsed functions, the following flags will be inaccurate since we
13920   // don't have the information yet. They're set later in
13921   // SetSharedFunctionFlagsFromLiteral (compiler.cc), when the function is
13922   // really parsed and compiled.
13923   if (lit->body() != nullptr) {
13924     shared_info->set_length(lit->function_length());
13925     shared_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
13926     shared_info->SetExpectedNofPropertiesFromEstimate(lit);
13927     DCHECK_NULL(lit->produced_preparsed_scope_data());
13928   } else {
13929     // Set an invalid length for lazy functions. This way we can set the correct
13930     // value after compiling, but avoid overwriting values set manually by the
13931     // bootstrapper.
13932     shared_info->set_length(SharedFunctionInfo::kInvalidLength);
13933     if (FLAG_preparser_scope_analysis) {
13934       ProducedPreParsedScopeData* scope_data =
13935           lit->produced_preparsed_scope_data();
13936       if (scope_data != nullptr) {
13937         MaybeHandle<PreParsedScopeData> maybe_data =
13938             scope_data->Serialize(shared_info->GetIsolate());
13939         if (!maybe_data.is_null()) {
13940           Handle<PreParsedScopeData> data = maybe_data.ToHandleChecked();
13941           shared_info->set_preparsed_scope_data(*data);
13942         }
13943       }
13944     }
13945   }
13946 }
13947 
SetExpectedNofPropertiesFromEstimate(FunctionLiteral * literal)13948 void SharedFunctionInfo::SetExpectedNofPropertiesFromEstimate(
13949     FunctionLiteral* literal) {
13950   int estimate = literal->expected_property_count();
13951 
13952   // If no properties are added in the constructor, they are more likely
13953   // to be added later.
13954   if (estimate == 0) estimate = 2;
13955 
13956   // Inobject slack tracking will reclaim redundant inobject space later,
13957   // so we can afford to adjust the estimate generously.
13958   estimate += 8;
13959 
13960   set_expected_nof_properties(estimate);
13961 }
13962 
StartInobjectSlackTracking()13963 void Map::StartInobjectSlackTracking() {
13964   DCHECK(!IsInobjectSlackTrackingInProgress());
13965   if (UnusedPropertyFields() == 0) return;
13966   set_construction_counter(Map::kSlackTrackingCounterStart);
13967 }
13968 
VisitCodeTarget(Code * host,RelocInfo * rinfo)13969 void ObjectVisitor::VisitCodeTarget(Code* host, RelocInfo* rinfo) {
13970   DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode()));
13971   Object* old_pointer = Code::GetCodeFromTargetAddress(rinfo->target_address());
13972   Object* new_pointer = old_pointer;
13973   VisitPointer(host, &new_pointer);
13974   DCHECK_EQ(old_pointer, new_pointer);
13975 }
13976 
VisitEmbeddedPointer(Code * host,RelocInfo * rinfo)13977 void ObjectVisitor::VisitEmbeddedPointer(Code* host, RelocInfo* rinfo) {
13978   DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
13979   Object* old_pointer = rinfo->target_object();
13980   Object* new_pointer = old_pointer;
13981   VisitPointer(host, &new_pointer);
13982   DCHECK_EQ(old_pointer, new_pointer);
13983 }
13984 
VisitRelocInfo(RelocIterator * it)13985 void ObjectVisitor::VisitRelocInfo(RelocIterator* it) {
13986   for (; !it->done(); it->next()) {
13987     it->rinfo()->Visit(this);
13988   }
13989 }
13990 
InvalidateEmbeddedObjects()13991 void Code::InvalidateEmbeddedObjects() {
13992   HeapObject* undefined = GetHeap()->undefined_value();
13993   int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
13994   for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
13995     RelocInfo::Mode mode = it.rinfo()->rmode();
13996     if (mode == RelocInfo::EMBEDDED_OBJECT) {
13997       it.rinfo()->set_target_object(undefined, SKIP_WRITE_BARRIER);
13998     }
13999   }
14000 }
14001 
14002 
Relocate(intptr_t delta)14003 void Code::Relocate(intptr_t delta) {
14004   for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
14005     it.rinfo()->apply(delta);
14006   }
14007   Assembler::FlushICache(raw_instruction_start(), raw_instruction_size());
14008 }
14009 
FlushICache() const14010 void Code::FlushICache() const {
14011   Assembler::FlushICache(raw_instruction_start(), raw_instruction_size());
14012 }
14013 
CopyFrom(const CodeDesc & desc)14014 void Code::CopyFrom(const CodeDesc& desc) {
14015   CopyFromNoFlush(desc);
14016   FlushICache();
14017 }
14018 
CopyFromNoFlush(const CodeDesc & desc)14019 void Code::CopyFromNoFlush(const CodeDesc& desc) {
14020   // copy code
14021   CopyBytes(reinterpret_cast<byte*>(raw_instruction_start()), desc.buffer,
14022             static_cast<size_t>(desc.instr_size));
14023 
14024   // copy unwinding info, if any
14025   if (desc.unwinding_info) {
14026     DCHECK_GT(desc.unwinding_info_size, 0);
14027     set_unwinding_info_size(desc.unwinding_info_size);
14028     CopyBytes(reinterpret_cast<byte*>(unwinding_info_start()),
14029               desc.unwinding_info,
14030               static_cast<size_t>(desc.unwinding_info_size));
14031   }
14032 
14033   // copy reloc info
14034   CopyBytes(relocation_start(),
14035             desc.buffer + desc.buffer_size - desc.reloc_size,
14036             static_cast<size_t>(desc.reloc_size));
14037 
14038   // unbox handles and relocate
14039   int mode_mask = RelocInfo::kCodeTargetMask |
14040                   RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
14041                   RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
14042                   RelocInfo::kApplyMask;
14043   // Needed to find target_object and runtime_entry on X64
14044   Assembler* origin = desc.origin;
14045   AllowDeferredHandleDereference embedding_raw_address;
14046   for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
14047     RelocInfo::Mode mode = it.rinfo()->rmode();
14048     if (mode == RelocInfo::EMBEDDED_OBJECT) {
14049       Handle<HeapObject> p = it.rinfo()->target_object_handle(origin);
14050       it.rinfo()->set_target_object(*p, UPDATE_WRITE_BARRIER,
14051                                     SKIP_ICACHE_FLUSH);
14052     } else if (RelocInfo::IsCodeTarget(mode)) {
14053       // rewrite code handles to direct pointers to the first instruction in the
14054       // code object
14055       Handle<Object> p = it.rinfo()->target_object_handle(origin);
14056       Code* code = Code::cast(*p);
14057       it.rinfo()->set_target_address(code->raw_instruction_start(),
14058                                      UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
14059     } else if (RelocInfo::IsRuntimeEntry(mode)) {
14060       Address p = it.rinfo()->target_runtime_entry(origin);
14061       it.rinfo()->set_target_runtime_entry(p, UPDATE_WRITE_BARRIER,
14062                                            SKIP_ICACHE_FLUSH);
14063     } else {
14064       intptr_t delta =
14065           raw_instruction_start() - reinterpret_cast<Address>(desc.buffer);
14066       it.rinfo()->apply(delta);
14067     }
14068   }
14069 }
14070 
14071 
GetSafepointEntry(Address pc)14072 SafepointEntry Code::GetSafepointEntry(Address pc) {
14073   SafepointTable table(this);
14074   return table.FindEntry(pc);
14075 }
14076 
14077 #ifdef V8_EMBEDDED_BUILTINS
OffHeapInstructionSize() const14078 int Code::OffHeapInstructionSize() const {
14079   DCHECK(Builtins::IsEmbeddedBuiltin(this));
14080   if (Isolate::CurrentEmbeddedBlob() == nullptr) return raw_instruction_size();
14081   EmbeddedData d = EmbeddedData::FromBlob();
14082   return d.InstructionSizeOfBuiltin(builtin_index());
14083 }
14084 
OffHeapInstructionStart() const14085 Address Code::OffHeapInstructionStart() const {
14086   DCHECK(Builtins::IsEmbeddedBuiltin(this));
14087   if (Isolate::CurrentEmbeddedBlob() == nullptr) return raw_instruction_start();
14088   EmbeddedData d = EmbeddedData::FromBlob();
14089   return d.InstructionStartOfBuiltin(builtin_index());
14090 }
14091 
OffHeapInstructionEnd() const14092 Address Code::OffHeapInstructionEnd() const {
14093   DCHECK(Builtins::IsEmbeddedBuiltin(this));
14094   if (Isolate::CurrentEmbeddedBlob() == nullptr) return raw_instruction_end();
14095   EmbeddedData d = EmbeddedData::FromBlob();
14096   return d.InstructionStartOfBuiltin(builtin_index()) +
14097          d.InstructionSizeOfBuiltin(builtin_index());
14098 }
14099 #endif
14100 
14101 namespace {
14102 template <typename Code>
SetStackFrameCacheCommon(Handle<Code> code,Handle<SimpleNumberDictionary> cache)14103 void SetStackFrameCacheCommon(Handle<Code> code,
14104                               Handle<SimpleNumberDictionary> cache) {
14105   Handle<Object> maybe_table(code->source_position_table(), code->GetIsolate());
14106   if (maybe_table->IsSourcePositionTableWithFrameCache()) {
14107     Handle<SourcePositionTableWithFrameCache>::cast(maybe_table)
14108         ->set_stack_frame_cache(*cache);
14109     return;
14110   }
14111   DCHECK(maybe_table->IsByteArray());
14112   Handle<ByteArray> table(Handle<ByteArray>::cast(maybe_table));
14113   Handle<SourcePositionTableWithFrameCache> table_with_cache =
14114       code->GetIsolate()->factory()->NewSourcePositionTableWithFrameCache(
14115           table, cache);
14116   code->set_source_position_table(*table_with_cache);
14117 }
14118 }  // namespace
14119 
14120 // static
SetStackFrameCache(Handle<AbstractCode> abstract_code,Handle<SimpleNumberDictionary> cache)14121 void AbstractCode::SetStackFrameCache(Handle<AbstractCode> abstract_code,
14122                                       Handle<SimpleNumberDictionary> cache) {
14123   if (abstract_code->IsCode()) {
14124     SetStackFrameCacheCommon(handle(abstract_code->GetCode()), cache);
14125   } else {
14126     SetStackFrameCacheCommon(handle(abstract_code->GetBytecodeArray()), cache);
14127   }
14128 }
14129 
14130 namespace {
14131 template <typename Code>
DropStackFrameCacheCommon(Code * code)14132 void DropStackFrameCacheCommon(Code* code) {
14133   i::Object* maybe_table = code->source_position_table();
14134   if (maybe_table->IsByteArray()) return;
14135   DCHECK(maybe_table->IsSourcePositionTableWithFrameCache());
14136   code->set_source_position_table(
14137       i::SourcePositionTableWithFrameCache::cast(maybe_table)
14138           ->source_position_table());
14139 }
14140 }  // namespace
14141 
DropStackFrameCache()14142 void AbstractCode::DropStackFrameCache() {
14143   if (IsCode()) {
14144     DropStackFrameCacheCommon(GetCode());
14145   } else {
14146     DropStackFrameCacheCommon(GetBytecodeArray());
14147   }
14148 }
14149 
SourcePosition(int offset)14150 int AbstractCode::SourcePosition(int offset) {
14151   int position = 0;
14152   // Subtract one because the current PC is one instruction after the call site.
14153   if (IsCode()) offset--;
14154   for (SourcePositionTableIterator iterator(source_position_table());
14155        !iterator.done() && iterator.code_offset() <= offset;
14156        iterator.Advance()) {
14157     position = iterator.source_position().ScriptOffset();
14158   }
14159   return position;
14160 }
14161 
SourceStatementPosition(int offset)14162 int AbstractCode::SourceStatementPosition(int offset) {
14163   // First find the closest position.
14164   int position = SourcePosition(offset);
14165   // Now find the closest statement position before the position.
14166   int statement_position = 0;
14167   for (SourcePositionTableIterator it(source_position_table()); !it.done();
14168        it.Advance()) {
14169     if (it.is_statement()) {
14170       int p = it.source_position().ScriptOffset();
14171       if (statement_position < p && p <= position) {
14172         statement_position = p;
14173       }
14174     }
14175   }
14176   return statement_position;
14177 }
14178 
ClearTypeFeedbackInfo()14179 void JSFunction::ClearTypeFeedbackInfo() {
14180   if (feedback_cell()->value()->IsFeedbackVector()) {
14181     FeedbackVector* vector = feedback_vector();
14182     Isolate* isolate = GetIsolate();
14183     if (vector->ClearSlots(isolate)) {
14184       IC::OnFeedbackChanged(isolate, vector, FeedbackSlot::Invalid(), this,
14185                             "ClearTypeFeedbackInfo");
14186     }
14187   }
14188 }
14189 
PrintDeoptLocation(FILE * out,const char * str,Address pc)14190 void Code::PrintDeoptLocation(FILE* out, const char* str, Address pc) {
14191   Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(this, pc);
14192   class SourcePosition pos = info.position;
14193   if (info.deopt_reason != DeoptimizeReason::kUnknown || pos.IsKnown()) {
14194     PrintF(out, "%s", str);
14195     OFStream outstr(out);
14196     pos.Print(outstr, this);
14197     PrintF(out, ", %s\n", DeoptimizeReasonToString(info.deopt_reason));
14198   }
14199 }
14200 
14201 
CanDeoptAt(Address pc)14202 bool Code::CanDeoptAt(Address pc) {
14203   DeoptimizationData* deopt_data =
14204       DeoptimizationData::cast(deoptimization_data());
14205   Address code_start_address = InstructionStart();
14206   for (int i = 0; i < deopt_data->DeoptCount(); i++) {
14207     if (deopt_data->Pc(i)->value() == -1) continue;
14208     Address address = code_start_address + deopt_data->Pc(i)->value();
14209     if (address == pc && deopt_data->BytecodeOffset(i) != BailoutId::None()) {
14210       return true;
14211     }
14212   }
14213   return false;
14214 }
14215 
14216 
14217 // Identify kind of code.
Kind2String(Kind kind)14218 const char* Code::Kind2String(Kind kind) {
14219   switch (kind) {
14220 #define CASE(name) case name: return #name;
14221     CODE_KIND_LIST(CASE)
14222 #undef CASE
14223     case NUMBER_OF_KINDS: break;
14224   }
14225   UNREACHABLE();
14226 }
14227 
14228 // Identify kind of code.
Kind2String(Kind kind)14229 const char* AbstractCode::Kind2String(Kind kind) {
14230   if (kind < AbstractCode::INTERPRETED_FUNCTION)
14231     return Code::Kind2String((Code::Kind)kind);
14232   if (kind == AbstractCode::INTERPRETED_FUNCTION) return "INTERPRETED_FUNCTION";
14233   UNREACHABLE();
14234 }
14235 
14236 #ifdef V8_EMBEDDED_BUILTINS
IsProcessIndependent()14237 bool Code::IsProcessIndependent() {
14238   constexpr int all_real_modes_mask =
14239       (1 << (RelocInfo::LAST_REAL_RELOC_MODE + 1)) - 1;
14240   constexpr int mode_mask =
14241       all_real_modes_mask & ~RelocInfo::ModeMask(RelocInfo::COMMENT) &
14242       ~RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) &
14243       ~RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) &
14244       ~RelocInfo::ModeMask(RelocInfo::OFF_HEAP_TARGET) &
14245       ~RelocInfo::ModeMask(RelocInfo::CONST_POOL) &
14246       ~RelocInfo::ModeMask(RelocInfo::VENEER_POOL);
14247   STATIC_ASSERT(RelocInfo::LAST_REAL_RELOC_MODE == RelocInfo::VENEER_POOL);
14248   STATIC_ASSERT(RelocInfo::ModeMask(RelocInfo::COMMENT) ==
14249                 (1 << RelocInfo::COMMENT));
14250   STATIC_ASSERT(
14251       mode_mask ==
14252       (RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
14253        RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
14254        RelocInfo::ModeMask(RelocInfo::WASM_GLOBAL_HANDLE) |
14255        RelocInfo::ModeMask(RelocInfo::WASM_CALL) |
14256        RelocInfo::ModeMask(RelocInfo::JS_TO_WASM_CALL) |
14257        RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
14258        RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE)));
14259 
14260   RelocIterator it(this, mode_mask);
14261   return it.done();
14262 }
14263 #endif
14264 
WeakCellFor(Handle<Code> code)14265 Handle<WeakCell> Code::WeakCellFor(Handle<Code> code) {
14266   DCHECK(code->kind() == OPTIMIZED_FUNCTION);
14267   WeakCell* raw_cell = code->CachedWeakCell();
14268   if (raw_cell != nullptr) return Handle<WeakCell>(raw_cell);
14269   Handle<WeakCell> cell = code->GetIsolate()->factory()->NewWeakCell(code);
14270   DeoptimizationData::cast(code->deoptimization_data())
14271       ->SetWeakCellCache(*cell);
14272   return cell;
14273 }
14274 
CachedWeakCell()14275 WeakCell* Code::CachedWeakCell() {
14276   DCHECK(kind() == OPTIMIZED_FUNCTION);
14277   Object* weak_cell_cache =
14278       DeoptimizationData::cast(deoptimization_data())->WeakCellCache();
14279   if (weak_cell_cache->IsWeakCell()) {
14280     DCHECK(this == WeakCell::cast(weak_cell_cache)->value());
14281     return WeakCell::cast(weak_cell_cache);
14282   }
14283   return nullptr;
14284 }
14285 
Inlines(SharedFunctionInfo * sfi)14286 bool Code::Inlines(SharedFunctionInfo* sfi) {
14287   // We can only check for inlining for optimized code.
14288   DCHECK(is_optimized_code());
14289   DisallowHeapAllocation no_gc;
14290   DeoptimizationData* const data =
14291       DeoptimizationData::cast(deoptimization_data());
14292   if (data->length() == 0) return false;
14293   if (data->SharedFunctionInfo() == sfi) return true;
14294   FixedArray* const literals = data->LiteralArray();
14295   int const inlined_count = data->InlinedFunctionCount()->value();
14296   for (int i = 0; i < inlined_count; ++i) {
14297     if (SharedFunctionInfo::cast(literals->get(i)) == sfi) return true;
14298   }
14299   return false;
14300 }
14301 
OptimizedCodeIterator(Isolate * isolate)14302 Code::OptimizedCodeIterator::OptimizedCodeIterator(Isolate* isolate) {
14303   isolate_ = isolate;
14304   Object* list = isolate->heap()->native_contexts_list();
14305   next_context_ = list->IsUndefined(isolate_) ? nullptr : Context::cast(list);
14306   current_code_ = nullptr;
14307 }
14308 
Next()14309 Code* Code::OptimizedCodeIterator::Next() {
14310   do {
14311     Object* next;
14312     if (current_code_ != nullptr) {
14313       // Get next code in the linked list.
14314       next = Code::cast(current_code_)->next_code_link();
14315     } else if (next_context_ != nullptr) {
14316       // Linked list of code exhausted. Get list of next context.
14317       next = next_context_->OptimizedCodeListHead();
14318       Object* next_context = next_context_->next_context_link();
14319       next_context_ = next_context->IsUndefined(isolate_)
14320                           ? nullptr
14321                           : Context::cast(next_context);
14322     } else {
14323       // Exhausted contexts.
14324       return nullptr;
14325     }
14326     current_code_ = next->IsUndefined(isolate_) ? nullptr : Code::cast(next);
14327   } while (current_code_ == nullptr);
14328   Code* code = Code::cast(current_code_);
14329   DCHECK_EQ(Code::OPTIMIZED_FUNCTION, code->kind());
14330   return code;
14331 }
14332 
14333 #ifdef ENABLE_DISASSEMBLER
14334 
14335 namespace {
print_pc(std::ostream & os,int pc)14336 void print_pc(std::ostream& os, int pc) {
14337   if (pc == -1) {
14338     os << "NA";
14339   } else {
14340     os << std::hex << pc << std::dec;
14341   }
14342 }
14343 }  // anonymous namespace
14344 
DeoptimizationDataPrint(std::ostream & os)14345 void DeoptimizationData::DeoptimizationDataPrint(std::ostream& os) {  // NOLINT
14346   if (length() == 0) {
14347     os << "Deoptimization Input Data invalidated by lazy deoptimization\n";
14348     return;
14349   }
14350 
14351   disasm::NameConverter converter;
14352   int const inlined_function_count = InlinedFunctionCount()->value();
14353   os << "Inlined functions (count = " << inlined_function_count << ")\n";
14354   for (int id = 0; id < inlined_function_count; ++id) {
14355     Object* info = LiteralArray()->get(id);
14356     os << " " << Brief(SharedFunctionInfo::cast(info)) << "\n";
14357   }
14358   os << "\n";
14359   int deopt_count = DeoptCount();
14360   os << "Deoptimization Input Data (deopt points = " << deopt_count << ")\n";
14361   if (0 != deopt_count) {
14362     os << " index  bytecode-offset    pc";
14363     if (FLAG_print_code_verbose) os << "  commands";
14364     os << "\n";
14365   }
14366   for (int i = 0; i < deopt_count; i++) {
14367     os << std::setw(6) << i << "  " << std::setw(15)
14368        << BytecodeOffset(i).ToInt() << "  " << std::setw(4);
14369     print_pc(os, Pc(i)->value());
14370     os << std::setw(2);
14371 
14372     if (!FLAG_print_code_verbose) {
14373       os << "\n";
14374       continue;
14375     }
14376 
14377     // Print details of the frame translation.
14378     int translation_index = TranslationIndex(i)->value();
14379     TranslationIterator iterator(TranslationByteArray(), translation_index);
14380     Translation::Opcode opcode =
14381         static_cast<Translation::Opcode>(iterator.Next());
14382     DCHECK(Translation::BEGIN == opcode);
14383     int frame_count = iterator.Next();
14384     int jsframe_count = iterator.Next();
14385     int update_feedback_count = iterator.Next();
14386     os << "  " << Translation::StringFor(opcode)
14387        << " {frame count=" << frame_count
14388        << ", js frame count=" << jsframe_count
14389        << ", update_feedback_count=" << update_feedback_count << "}\n";
14390 
14391     while (iterator.HasNext() &&
14392            Translation::BEGIN !=
14393            (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
14394       os << std::setw(31) << "    " << Translation::StringFor(opcode) << " ";
14395 
14396       switch (opcode) {
14397         case Translation::BEGIN:
14398           UNREACHABLE();
14399           break;
14400 
14401         case Translation::INTERPRETED_FRAME: {
14402           int bytecode_offset = iterator.Next();
14403           int shared_info_id = iterator.Next();
14404           unsigned height = iterator.Next();
14405           Object* shared_info = LiteralArray()->get(shared_info_id);
14406           os << "{bytecode_offset=" << bytecode_offset << ", function="
14407              << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14408              << ", height=" << height << "}";
14409           break;
14410         }
14411 
14412         case Translation::CONSTRUCT_STUB_FRAME: {
14413           int bailout_id = iterator.Next();
14414           int shared_info_id = iterator.Next();
14415           Object* shared_info = LiteralArray()->get(shared_info_id);
14416           unsigned height = iterator.Next();
14417           os << "{bailout_id=" << bailout_id << ", function="
14418              << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14419              << ", height=" << height << "}";
14420           break;
14421         }
14422 
14423         case Translation::BUILTIN_CONTINUATION_FRAME:
14424         case Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME:
14425         case Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME: {
14426           int bailout_id = iterator.Next();
14427           int shared_info_id = iterator.Next();
14428           Object* shared_info = LiteralArray()->get(shared_info_id);
14429           unsigned height = iterator.Next();
14430           os << "{bailout_id=" << bailout_id << ", function="
14431              << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14432              << ", height=" << height << "}";
14433           break;
14434         }
14435 
14436         case Translation::ARGUMENTS_ADAPTOR_FRAME: {
14437           int shared_info_id = iterator.Next();
14438           Object* shared_info = LiteralArray()->get(shared_info_id);
14439           unsigned height = iterator.Next();
14440           os << "{function="
14441              << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14442              << ", height=" << height << "}";
14443           break;
14444         }
14445 
14446         case Translation::REGISTER: {
14447           int reg_code = iterator.Next();
14448           os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
14449           break;
14450         }
14451 
14452         case Translation::INT32_REGISTER: {
14453           int reg_code = iterator.Next();
14454           os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
14455           break;
14456         }
14457 
14458         case Translation::UINT32_REGISTER: {
14459           int reg_code = iterator.Next();
14460           os << "{input=" << converter.NameOfCPURegister(reg_code)
14461              << " (unsigned)}";
14462           break;
14463         }
14464 
14465         case Translation::BOOL_REGISTER: {
14466           int reg_code = iterator.Next();
14467           os << "{input=" << converter.NameOfCPURegister(reg_code)
14468              << " (bool)}";
14469           break;
14470         }
14471 
14472         case Translation::FLOAT_REGISTER: {
14473           int reg_code = iterator.Next();
14474           os << "{input="
14475              << RegisterConfiguration::Default()->GetFloatRegisterName(reg_code)
14476              << "}";
14477           break;
14478         }
14479 
14480         case Translation::DOUBLE_REGISTER: {
14481           int reg_code = iterator.Next();
14482           os << "{input="
14483              << RegisterConfiguration::Default()->GetDoubleRegisterName(
14484                     reg_code)
14485              << "}";
14486           break;
14487         }
14488 
14489         case Translation::STACK_SLOT: {
14490           int input_slot_index = iterator.Next();
14491           os << "{input=" << input_slot_index << "}";
14492           break;
14493         }
14494 
14495         case Translation::INT32_STACK_SLOT: {
14496           int input_slot_index = iterator.Next();
14497           os << "{input=" << input_slot_index << "}";
14498           break;
14499         }
14500 
14501         case Translation::UINT32_STACK_SLOT: {
14502           int input_slot_index = iterator.Next();
14503           os << "{input=" << input_slot_index << " (unsigned)}";
14504           break;
14505         }
14506 
14507         case Translation::BOOL_STACK_SLOT: {
14508           int input_slot_index = iterator.Next();
14509           os << "{input=" << input_slot_index << " (bool)}";
14510           break;
14511         }
14512 
14513         case Translation::FLOAT_STACK_SLOT:
14514         case Translation::DOUBLE_STACK_SLOT: {
14515           int input_slot_index = iterator.Next();
14516           os << "{input=" << input_slot_index << "}";
14517           break;
14518         }
14519 
14520         case Translation::LITERAL: {
14521           int literal_index = iterator.Next();
14522           Object* literal_value = LiteralArray()->get(literal_index);
14523           os << "{literal_id=" << literal_index << " (" << Brief(literal_value)
14524              << ")}";
14525           break;
14526         }
14527 
14528         case Translation::DUPLICATED_OBJECT: {
14529           int object_index = iterator.Next();
14530           os << "{object_index=" << object_index << "}";
14531           break;
14532         }
14533 
14534         case Translation::ARGUMENTS_ELEMENTS:
14535         case Translation::ARGUMENTS_LENGTH: {
14536           CreateArgumentsType arguments_type =
14537               static_cast<CreateArgumentsType>(iterator.Next());
14538           os << "{arguments_type=" << arguments_type << "}";
14539           break;
14540         }
14541 
14542         case Translation::CAPTURED_OBJECT: {
14543           int args_length = iterator.Next();
14544           os << "{length=" << args_length << "}";
14545           break;
14546         }
14547 
14548         case Translation::UPDATE_FEEDBACK: {
14549           int literal_index = iterator.Next();
14550           FeedbackSlot slot(iterator.Next());
14551           os << "{feedback={vector_index=" << literal_index << ", slot=" << slot
14552              << "}}";
14553           break;
14554         }
14555       }
14556       os << "\n";
14557     }
14558   }
14559 }
14560 
Disassemble(const char * name,std::ostream & os,Address current_pc)14561 void Code::Disassemble(const char* name, std::ostream& os, Address current_pc) {
14562   os << "kind = " << Kind2String(kind()) << "\n";
14563   if (is_stub()) {
14564     const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this));
14565     os << "major_key = " << (n == nullptr ? "null" : n) << "\n";
14566     os << "minor_key = " << CodeStub::MinorKeyFromKey(this->stub_key()) << "\n";
14567   }
14568   if ((name != nullptr) && (name[0] != '\0')) {
14569     os << "name = " << name << "\n";
14570   } else if (kind() == BYTECODE_HANDLER) {
14571     name = GetIsolate()->interpreter()->LookupNameOfBytecodeHandler(this);
14572     if (name != nullptr) {
14573       os << "name = " << name << "\n";
14574     }
14575   } else {
14576     // There are some handlers and ICs that we can also find names for with
14577     // Builtins::Lookup.
14578     name = GetIsolate()->builtins()->Lookup(raw_instruction_start());
14579     if (name != nullptr) {
14580       os << "name = " << name << "\n";
14581     }
14582   }
14583   if (kind() == OPTIMIZED_FUNCTION) {
14584     os << "stack_slots = " << stack_slots() << "\n";
14585   }
14586   os << "compiler = " << (is_turbofanned() ? "turbofan" : "unknown") << "\n";
14587   os << "address = " << static_cast<const void*>(this) << "\n";
14588 
14589   os << "Body (size = " << InstructionSize() << ")\n";
14590   {
14591     Isolate* isolate = GetIsolate();
14592     int size = InstructionSize();
14593     int safepoint_offset =
14594         has_safepoint_info() ? safepoint_table_offset() : size;
14595     int constant_pool_offset = this->constant_pool_offset();
14596     int handler_offset = handler_table_offset() ? handler_table_offset() : size;
14597 
14598     // Stop before reaching any embedded tables
14599     int code_size =
14600         Min(handler_offset, Min(safepoint_offset, constant_pool_offset));
14601     os << "Instructions (size = " << code_size << ")\n";
14602     Address begin = InstructionStart();
14603     Address end = begin + code_size;
14604     {
14605       // TODO(mstarzinger): Refactor CodeReference to avoid the
14606       // unhandlified->handlified transition.
14607       AllowHandleAllocation allow_handles;
14608       DisallowHeapAllocation no_gc;
14609       HandleScope handle_scope(isolate);
14610       Disassembler::Decode(isolate, &os, reinterpret_cast<byte*>(begin),
14611                            reinterpret_cast<byte*>(end),
14612                            CodeReference(handle(this, isolate)), current_pc);
14613     }
14614 
14615     if (constant_pool_offset < size) {
14616       int constant_pool_size = safepoint_offset - constant_pool_offset;
14617       DCHECK_EQ(constant_pool_size & kPointerAlignmentMask, 0);
14618       os << "\nConstant Pool (size = " << constant_pool_size << ")\n";
14619       Vector<char> buf = Vector<char>::New(50);
14620       intptr_t* ptr = reinterpret_cast<intptr_t*>(begin + constant_pool_offset);
14621       for (int i = 0; i < constant_pool_size; i += kPointerSize, ptr++) {
14622         SNPrintF(buf, "%4d %08" V8PRIxPTR, i, *ptr);
14623         os << static_cast<const void*>(ptr) << "  " << buf.start() << "\n";
14624       }
14625     }
14626   }
14627   os << "\n";
14628 
14629   SourcePositionTableIterator it(SourcePositionTable());
14630   if (!it.done()) {
14631     os << "Source positions:\n pc offset  position\n";
14632     for (; !it.done(); it.Advance()) {
14633       os << std::setw(10) << std::hex << it.code_offset() << std::dec
14634          << std::setw(10) << it.source_position().ScriptOffset()
14635          << (it.is_statement() ? "  statement" : "") << "\n";
14636     }
14637     os << "\n";
14638   }
14639 
14640   if (kind() == OPTIMIZED_FUNCTION) {
14641     DeoptimizationData* data =
14642         DeoptimizationData::cast(this->deoptimization_data());
14643     data->DeoptimizationDataPrint(os);
14644   }
14645   os << "\n";
14646 
14647   if (has_safepoint_info()) {
14648     SafepointTable table(this);
14649     os << "Safepoints (size = " << table.size() << ")\n";
14650     for (unsigned i = 0; i < table.length(); i++) {
14651       unsigned pc_offset = table.GetPcOffset(i);
14652       os << reinterpret_cast<const void*>(InstructionStart() + pc_offset)
14653          << "  ";
14654       os << std::setw(6) << std::hex << pc_offset << "  " << std::setw(4);
14655       int trampoline_pc = table.GetTrampolinePcOffset(i);
14656       print_pc(os, trampoline_pc);
14657       os << std::dec << "  ";
14658       table.PrintEntry(i, os);
14659       os << " (sp -> fp)  ";
14660       SafepointEntry entry = table.GetEntry(i);
14661       if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
14662         os << std::setw(6) << entry.deoptimization_index();
14663       } else {
14664         os << "<none>";
14665       }
14666       if (entry.argument_count() > 0) {
14667         os << " argc: " << entry.argument_count();
14668       }
14669       os << "\n";
14670     }
14671     os << "\n";
14672   }
14673 
14674   if (handler_table_offset() > 0) {
14675     HandlerTable table(this);
14676     os << "Handler Table (size = " << table.NumberOfReturnEntries() << ")\n";
14677     if (kind() == OPTIMIZED_FUNCTION) {
14678       table.HandlerTableReturnPrint(os);
14679     }
14680     os << "\n";
14681   }
14682 
14683   os << "RelocInfo (size = " << relocation_size() << ")\n";
14684   for (RelocIterator it(this); !it.done(); it.next()) {
14685     it.rinfo()->Print(GetIsolate(), os);
14686   }
14687   os << "\n";
14688 
14689   if (has_unwinding_info()) {
14690     os << "UnwindingInfo (size = " << unwinding_info_size() << ")\n";
14691     EhFrameDisassembler eh_frame_disassembler(
14692         reinterpret_cast<byte*>(unwinding_info_start()),
14693         reinterpret_cast<byte*>(unwinding_info_end()));
14694     eh_frame_disassembler.DisassembleToStream(os);
14695     os << "\n";
14696   }
14697 }
14698 #endif  // ENABLE_DISASSEMBLER
14699 
14700 
Disassemble(std::ostream & os)14701 void BytecodeArray::Disassemble(std::ostream& os) {
14702   os << "Parameter count " << parameter_count() << "\n";
14703   os << "Frame size " << frame_size() << "\n";
14704 
14705   Address base_address = GetFirstBytecodeAddress();
14706   SourcePositionTableIterator source_positions(SourcePositionTable());
14707 
14708   interpreter::BytecodeArrayIterator iterator(handle(this));
14709   while (!iterator.done()) {
14710     if (!source_positions.done() &&
14711         iterator.current_offset() == source_positions.code_offset()) {
14712       os << std::setw(5) << source_positions.source_position().ScriptOffset();
14713       os << (source_positions.is_statement() ? " S> " : " E> ");
14714       source_positions.Advance();
14715     } else {
14716       os << "         ";
14717     }
14718     Address current_address = base_address + iterator.current_offset();
14719     os << reinterpret_cast<const void*>(current_address) << " @ "
14720        << std::setw(4) << iterator.current_offset() << " : ";
14721     interpreter::BytecodeDecoder::Decode(
14722         os, reinterpret_cast<byte*>(current_address), parameter_count());
14723     if (interpreter::Bytecodes::IsJump(iterator.current_bytecode())) {
14724       Address jump_target = base_address + iterator.GetJumpTargetOffset();
14725       os << " (" << reinterpret_cast<void*>(jump_target) << " @ "
14726          << iterator.GetJumpTargetOffset() << ")";
14727     }
14728     if (interpreter::Bytecodes::IsSwitch(iterator.current_bytecode())) {
14729       os << " {";
14730       bool first_entry = true;
14731       for (const auto& entry : iterator.GetJumpTableTargetOffsets()) {
14732         if (first_entry) {
14733           first_entry = false;
14734         } else {
14735           os << ",";
14736         }
14737         os << " " << entry.case_value << ": @" << entry.target_offset;
14738       }
14739       os << " }";
14740     }
14741     os << std::endl;
14742     iterator.Advance();
14743   }
14744 
14745   os << "Constant pool (size = " << constant_pool()->length() << ")\n";
14746 #ifdef OBJECT_PRINT
14747   if (constant_pool()->length() > 0) {
14748     constant_pool()->Print();
14749   }
14750 #endif
14751 
14752   os << "Handler Table (size = " << handler_table()->length() << ")\n";
14753 #ifdef ENABLE_DISASSEMBLER
14754   if (handler_table()->length() > 0) {
14755     HandlerTable table(this);
14756     table.HandlerTableRangePrint(os);
14757   }
14758 #endif
14759 }
14760 
CopyBytecodesTo(BytecodeArray * to)14761 void BytecodeArray::CopyBytecodesTo(BytecodeArray* to) {
14762   BytecodeArray* from = this;
14763   DCHECK_EQ(from->length(), to->length());
14764   CopyBytes(reinterpret_cast<byte*>(to->GetFirstBytecodeAddress()),
14765             reinterpret_cast<byte*>(from->GetFirstBytecodeAddress()),
14766             from->length());
14767 }
14768 
MakeOlder()14769 void BytecodeArray::MakeOlder() {
14770   // BytecodeArray is aged in concurrent marker.
14771   // The word must be completely within the byte code array.
14772   Address age_addr = address() + kBytecodeAgeOffset;
14773   DCHECK_LE((age_addr & ~kPointerAlignmentMask) + kPointerSize,
14774             address() + Size());
14775   Age age = bytecode_age();
14776   if (age < kLastBytecodeAge) {
14777     base::AsAtomic8::Release_CompareAndSwap(reinterpret_cast<byte*>(age_addr),
14778                                             age, age + 1);
14779   }
14780 
14781   DCHECK_GE(bytecode_age(), kFirstBytecodeAge);
14782   DCHECK_LE(bytecode_age(), kLastBytecodeAge);
14783 }
14784 
IsOld() const14785 bool BytecodeArray::IsOld() const {
14786   return bytecode_age() >= kIsOldBytecodeAge;
14787 }
14788 
14789 // static
Initialize(Handle<JSArray> array,int capacity,int length)14790 void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
14791   DCHECK_GE(capacity, 0);
14792   array->GetIsolate()->factory()->NewJSArrayStorage(
14793       array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
14794 }
14795 
SetLength(Handle<JSArray> array,uint32_t new_length)14796 void JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) {
14797   // We should never end in here with a pixel or external array.
14798   DCHECK(array->AllowsSetLength());
14799   if (array->SetLengthWouldNormalize(new_length)) {
14800     JSObject::NormalizeElements(array);
14801   }
14802   array->GetElementsAccessor()->SetLength(array, new_length);
14803 }
14804 
14805 
14806 // static
AddDependentCode(Handle<Map> map,DependentCode::DependencyGroup group,Handle<Code> code)14807 void Map::AddDependentCode(Handle<Map> map,
14808                            DependentCode::DependencyGroup group,
14809                            Handle<Code> code) {
14810   Handle<WeakCell> cell = Code::WeakCellFor(code);
14811   Handle<DependentCode> codes = DependentCode::InsertWeakCode(
14812       Handle<DependentCode>(map->dependent_code()), group, cell);
14813   if (*codes != map->dependent_code()) map->set_dependent_code(*codes);
14814 }
14815 
14816 
InsertCompilationDependencies(Handle<DependentCode> entries,DependencyGroup group,Handle<Foreign> info)14817 Handle<DependentCode> DependentCode::InsertCompilationDependencies(
14818     Handle<DependentCode> entries, DependencyGroup group,
14819     Handle<Foreign> info) {
14820   return Insert(entries, group, info);
14821 }
14822 
14823 
InsertWeakCode(Handle<DependentCode> entries,DependencyGroup group,Handle<WeakCell> code_cell)14824 Handle<DependentCode> DependentCode::InsertWeakCode(
14825     Handle<DependentCode> entries, DependencyGroup group,
14826     Handle<WeakCell> code_cell) {
14827   return Insert(entries, group, code_cell);
14828 }
14829 
14830 
Insert(Handle<DependentCode> entries,DependencyGroup group,Handle<Object> object)14831 Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
14832                                             DependencyGroup group,
14833                                             Handle<Object> object) {
14834   if (entries->length() == 0 || entries->group() > group) {
14835     // There is no such group.
14836     return DependentCode::New(group, object, entries);
14837   }
14838   if (entries->group() < group) {
14839     // The group comes later in the list.
14840     Handle<DependentCode> old_next(entries->next_link());
14841     Handle<DependentCode> new_next = Insert(old_next, group, object);
14842     if (!old_next.is_identical_to(new_next)) {
14843       entries->set_next_link(*new_next);
14844     }
14845     return entries;
14846   }
14847   DCHECK_EQ(group, entries->group());
14848   int count = entries->count();
14849   // Check for existing entry to avoid duplicates.
14850   for (int i = 0; i < count; i++) {
14851     if (entries->object_at(i) == *object) return entries;
14852   }
14853   if (entries->length() < kCodesStartIndex + count + 1) {
14854     entries = EnsureSpace(entries);
14855     // Count could have changed, reload it.
14856     count = entries->count();
14857   }
14858   entries->set_object_at(count, *object);
14859   entries->set_count(count + 1);
14860   return entries;
14861 }
14862 
14863 
New(DependencyGroup group,Handle<Object> object,Handle<DependentCode> next)14864 Handle<DependentCode> DependentCode::New(DependencyGroup group,
14865                                          Handle<Object> object,
14866                                          Handle<DependentCode> next) {
14867   Isolate* isolate = next->GetIsolate();
14868   Handle<DependentCode> result = Handle<DependentCode>::cast(
14869       isolate->factory()->NewFixedArray(kCodesStartIndex + 1, TENURED));
14870   result->set_next_link(*next);
14871   result->set_flags(GroupField::encode(group) | CountField::encode(1));
14872   result->set_object_at(0, *object);
14873   return result;
14874 }
14875 
14876 
EnsureSpace(Handle<DependentCode> entries)14877 Handle<DependentCode> DependentCode::EnsureSpace(
14878     Handle<DependentCode> entries) {
14879   if (entries->Compact()) return entries;
14880   Isolate* isolate = entries->GetIsolate();
14881   int capacity = kCodesStartIndex + DependentCode::Grow(entries->count());
14882   int grow_by = capacity - entries->length();
14883   return Handle<DependentCode>::cast(
14884       isolate->factory()->CopyFixedArrayAndGrow(entries, grow_by, TENURED));
14885 }
14886 
14887 
Compact()14888 bool DependentCode::Compact() {
14889   int old_count = count();
14890   int new_count = 0;
14891   for (int i = 0; i < old_count; i++) {
14892     Object* obj = object_at(i);
14893     if (!obj->IsWeakCell() || !WeakCell::cast(obj)->cleared()) {
14894       if (i != new_count) {
14895         copy(i, new_count);
14896       }
14897       new_count++;
14898     }
14899   }
14900   set_count(new_count);
14901   for (int i = new_count; i < old_count; i++) {
14902     clear_at(i);
14903   }
14904   return new_count < old_count;
14905 }
14906 
14907 
UpdateToFinishedCode(DependencyGroup group,Foreign * info,WeakCell * code_cell)14908 void DependentCode::UpdateToFinishedCode(DependencyGroup group, Foreign* info,
14909                                          WeakCell* code_cell) {
14910   if (this->length() == 0 || this->group() > group) {
14911     // There is no such group.
14912     return;
14913   }
14914   if (this->group() < group) {
14915     // The group comes later in the list.
14916     next_link()->UpdateToFinishedCode(group, info, code_cell);
14917     return;
14918   }
14919   DCHECK_EQ(group, this->group());
14920   DisallowHeapAllocation no_gc;
14921   int count = this->count();
14922   for (int i = 0; i < count; i++) {
14923     if (object_at(i) == info) {
14924       set_object_at(i, code_cell);
14925       break;
14926     }
14927   }
14928 #ifdef DEBUG
14929   for (int i = 0; i < count; i++) {
14930     DCHECK(object_at(i) != info);
14931   }
14932 #endif
14933 }
14934 
14935 
RemoveCompilationDependencies(DependentCode::DependencyGroup group,Foreign * info)14936 void DependentCode::RemoveCompilationDependencies(
14937     DependentCode::DependencyGroup group, Foreign* info) {
14938   if (this->length() == 0 || this->group() > group) {
14939     // There is no such group.
14940     return;
14941   }
14942   if (this->group() < group) {
14943     // The group comes later in the list.
14944     next_link()->RemoveCompilationDependencies(group, info);
14945     return;
14946   }
14947   DCHECK_EQ(group, this->group());
14948   DisallowHeapAllocation no_allocation;
14949   int old_count = count();
14950   // Find compilation info wrapper.
14951   int info_pos = -1;
14952   for (int i = 0; i < old_count; i++) {
14953     if (object_at(i) == info) {
14954       info_pos = i;
14955       break;
14956     }
14957   }
14958   if (info_pos == -1) return;  // Not found.
14959   // Use the last code to fill the gap.
14960   if (info_pos < old_count - 1) {
14961     copy(old_count - 1, info_pos);
14962   }
14963   clear_at(old_count - 1);
14964   set_count(old_count - 1);
14965 
14966 #ifdef DEBUG
14967   for (int i = 0; i < old_count - 1; i++) {
14968     DCHECK(object_at(i) != info);
14969   }
14970 #endif
14971 }
14972 
14973 
Contains(DependencyGroup group,WeakCell * code_cell)14974 bool DependentCode::Contains(DependencyGroup group, WeakCell* code_cell) {
14975   if (this->length() == 0 || this->group() > group) {
14976     // There is no such group.
14977     return false;
14978   }
14979   if (this->group() < group) {
14980     // The group comes later in the list.
14981     return next_link()->Contains(group, code_cell);
14982   }
14983   DCHECK_EQ(group, this->group());
14984   int count = this->count();
14985   for (int i = 0; i < count; i++) {
14986     if (object_at(i) == code_cell) return true;
14987   }
14988   return false;
14989 }
14990 
14991 
IsEmpty(DependencyGroup group)14992 bool DependentCode::IsEmpty(DependencyGroup group) {
14993   if (this->length() == 0 || this->group() > group) {
14994     // There is no such group.
14995     return true;
14996   }
14997   if (this->group() < group) {
14998     // The group comes later in the list.
14999     return next_link()->IsEmpty(group);
15000   }
15001   DCHECK_EQ(group, this->group());
15002   return count() == 0;
15003 }
15004 
15005 
MarkCodeForDeoptimization(Isolate * isolate,DependentCode::DependencyGroup group)15006 bool DependentCode::MarkCodeForDeoptimization(
15007     Isolate* isolate,
15008     DependentCode::DependencyGroup group) {
15009   if (this->length() == 0 || this->group() > group) {
15010     // There is no such group.
15011     return false;
15012   }
15013   if (this->group() < group) {
15014     // The group comes later in the list.
15015     return next_link()->MarkCodeForDeoptimization(isolate, group);
15016   }
15017   DCHECK_EQ(group, this->group());
15018   DisallowHeapAllocation no_allocation_scope;
15019   // Mark all the code that needs to be deoptimized.
15020   bool marked = false;
15021   int count = this->count();
15022   for (int i = 0; i < count; i++) {
15023     Object* obj = object_at(i);
15024     if (obj->IsWeakCell()) {
15025       WeakCell* cell = WeakCell::cast(obj);
15026       if (cell->cleared()) continue;
15027       Code* code = Code::cast(cell->value());
15028       if (!code->marked_for_deoptimization()) {
15029         code->SetMarkedForDeoptimization(DependencyGroupName(group));
15030         marked = true;
15031       }
15032     } else {
15033       DCHECK(obj->IsForeign());
15034       CompilationDependencies* info =
15035           reinterpret_cast<CompilationDependencies*>(
15036               Foreign::cast(obj)->foreign_address());
15037       info->Abort();
15038     }
15039   }
15040   for (int i = 0; i < count; i++) {
15041     clear_at(i);
15042   }
15043   set_count(0);
15044   return marked;
15045 }
15046 
15047 
DeoptimizeDependentCodeGroup(Isolate * isolate,DependentCode::DependencyGroup group)15048 void DependentCode::DeoptimizeDependentCodeGroup(
15049     Isolate* isolate,
15050     DependentCode::DependencyGroup group) {
15051   DisallowHeapAllocation no_allocation_scope;
15052   bool marked = MarkCodeForDeoptimization(isolate, group);
15053   if (marked) {
15054     DCHECK(AllowCodeDependencyChange::IsAllowed());
15055     Deoptimizer::DeoptimizeMarkedCode(isolate);
15056   }
15057 }
15058 
SetMarkedForDeoptimization(const char * reason)15059 void Code::SetMarkedForDeoptimization(const char* reason) {
15060   set_marked_for_deoptimization(true);
15061   if (FLAG_trace_deopt &&
15062       (deoptimization_data() != GetHeap()->empty_fixed_array())) {
15063     DeoptimizationData* deopt_data =
15064         DeoptimizationData::cast(deoptimization_data());
15065     CodeTracer::Scope scope(GetHeap()->isolate()->GetCodeTracer());
15066     PrintF(scope.file(),
15067            "[marking dependent code " V8PRIxPTR_FMT
15068            " (opt #%d) for deoptimization, reason: %s]\n",
15069            reinterpret_cast<intptr_t>(this),
15070            deopt_data->OptimizationId()->value(), reason);
15071   }
15072 }
15073 
15074 
DependencyGroupName(DependencyGroup group)15075 const char* DependentCode::DependencyGroupName(DependencyGroup group) {
15076   switch (group) {
15077     case kTransitionGroup:
15078       return "transition";
15079     case kPrototypeCheckGroup:
15080       return "prototype-check";
15081     case kPropertyCellChangedGroup:
15082       return "property-cell-changed";
15083     case kFieldOwnerGroup:
15084       return "field-owner";
15085     case kInitialMapChangedGroup:
15086       return "initial-map-changed";
15087     case kAllocationSiteTenuringChangedGroup:
15088       return "allocation-site-tenuring-changed";
15089     case kAllocationSiteTransitionChangedGroup:
15090       return "allocation-site-transition-changed";
15091   }
15092   UNREACHABLE();
15093 }
15094 
TransitionToPrototype(Handle<Map> map,Handle<Object> prototype)15095 Handle<Map> Map::TransitionToPrototype(Handle<Map> map,
15096                                        Handle<Object> prototype) {
15097   Handle<Map> new_map =
15098       TransitionsAccessor(map).GetPrototypeTransition(prototype);
15099   if (new_map.is_null()) {
15100     new_map = Copy(map, "TransitionToPrototype");
15101     TransitionsAccessor(map).PutPrototypeTransition(prototype, new_map);
15102     Map::SetPrototype(new_map, prototype);
15103   }
15104   return new_map;
15105 }
15106 
15107 
SetPrototype(Handle<JSReceiver> object,Handle<Object> value,bool from_javascript,ShouldThrow should_throw)15108 Maybe<bool> JSReceiver::SetPrototype(Handle<JSReceiver> object,
15109                                      Handle<Object> value, bool from_javascript,
15110                                      ShouldThrow should_throw) {
15111   if (object->IsJSProxy()) {
15112     return JSProxy::SetPrototype(Handle<JSProxy>::cast(object), value,
15113                                  from_javascript, should_throw);
15114   }
15115   return JSObject::SetPrototype(Handle<JSObject>::cast(object), value,
15116                                 from_javascript, should_throw);
15117 }
15118 
15119 
15120 // ES6: 9.5.2 [[SetPrototypeOf]] (V)
15121 // static
SetPrototype(Handle<JSProxy> proxy,Handle<Object> value,bool from_javascript,ShouldThrow should_throw)15122 Maybe<bool> JSProxy::SetPrototype(Handle<JSProxy> proxy, Handle<Object> value,
15123                                   bool from_javascript,
15124                                   ShouldThrow should_throw) {
15125   Isolate* isolate = proxy->GetIsolate();
15126   STACK_CHECK(isolate, Nothing<bool>());
15127   Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string();
15128   // 1. Assert: Either Type(V) is Object or Type(V) is Null.
15129   DCHECK(value->IsJSReceiver() || value->IsNull(isolate));
15130   // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
15131   Handle<Object> handler(proxy->handler(), isolate);
15132   // 3. If handler is null, throw a TypeError exception.
15133   // 4. Assert: Type(handler) is Object.
15134   if (proxy->IsRevoked()) {
15135     isolate->Throw(*isolate->factory()->NewTypeError(
15136         MessageTemplate::kProxyRevoked, trap_name));
15137     return Nothing<bool>();
15138   }
15139   // 5. Let target be the value of the [[ProxyTarget]] internal slot.
15140   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
15141   // 6. Let trap be ? GetMethod(handler, "getPrototypeOf").
15142   Handle<Object> trap;
15143   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15144       isolate, trap,
15145       Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
15146       Nothing<bool>());
15147   // 7. If trap is undefined, then return target.[[SetPrototypeOf]]().
15148   if (trap->IsUndefined(isolate)) {
15149     return JSReceiver::SetPrototype(target, value, from_javascript,
15150                                     should_throw);
15151   }
15152   // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, V»)).
15153   Handle<Object> argv[] = {target, value};
15154   Handle<Object> trap_result;
15155   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15156       isolate, trap_result,
15157       Execution::Call(isolate, trap, handler, arraysize(argv), argv),
15158       Nothing<bool>());
15159   bool bool_trap_result = trap_result->BooleanValue();
15160   // 9. If booleanTrapResult is false, return false.
15161   if (!bool_trap_result) {
15162     RETURN_FAILURE(
15163         isolate, should_throw,
15164         NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15165   }
15166   // 10. Let extensibleTarget be ? IsExtensible(target).
15167   Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
15168   if (is_extensible.IsNothing()) return Nothing<bool>();
15169   // 11. If extensibleTarget is true, return true.
15170   if (is_extensible.FromJust()) {
15171     if (bool_trap_result) return Just(true);
15172     RETURN_FAILURE(
15173         isolate, should_throw,
15174         NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15175   }
15176   // 12. Let targetProto be ? target.[[GetPrototypeOf]]().
15177   Handle<Object> target_proto;
15178   ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_proto,
15179                                    JSReceiver::GetPrototype(isolate, target),
15180                                    Nothing<bool>());
15181   // 13. If SameValue(V, targetProto) is false, throw a TypeError exception.
15182   if (bool_trap_result && !value->SameValue(*target_proto)) {
15183     isolate->Throw(*isolate->factory()->NewTypeError(
15184         MessageTemplate::kProxySetPrototypeOfNonExtensible));
15185     return Nothing<bool>();
15186   }
15187   // 14. Return true.
15188   return Just(true);
15189 }
15190 
15191 
SetPrototype(Handle<JSObject> object,Handle<Object> value,bool from_javascript,ShouldThrow should_throw)15192 Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object,
15193                                    Handle<Object> value, bool from_javascript,
15194                                    ShouldThrow should_throw) {
15195   Isolate* isolate = object->GetIsolate();
15196 
15197 #ifdef DEBUG
15198   int size = object->Size();
15199 #endif
15200 
15201   if (from_javascript) {
15202     if (object->IsAccessCheckNeeded() &&
15203         !isolate->MayAccess(handle(isolate->context()), object)) {
15204       isolate->ReportFailedAccessCheck(object);
15205       RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
15206       RETURN_FAILURE(isolate, should_throw,
15207                      NewTypeError(MessageTemplate::kNoAccess));
15208     }
15209   } else {
15210     DCHECK(!object->IsAccessCheckNeeded());
15211   }
15212 
15213   // Silently ignore the change if value is not a JSObject or null.
15214   // SpiderMonkey behaves this way.
15215   if (!value->IsJSReceiver() && !value->IsNull(isolate)) return Just(true);
15216 
15217   bool all_extensible = object->map()->is_extensible();
15218   Handle<JSObject> real_receiver = object;
15219   if (from_javascript) {
15220     // Find the first object in the chain whose prototype object is not
15221     // hidden.
15222     PrototypeIterator iter(isolate, real_receiver, kStartAtPrototype,
15223                            PrototypeIterator::END_AT_NON_HIDDEN);
15224     while (!iter.IsAtEnd()) {
15225       // Casting to JSObject is fine because hidden prototypes are never
15226       // JSProxies.
15227       real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter);
15228       iter.Advance();
15229       all_extensible = all_extensible && real_receiver->map()->is_extensible();
15230     }
15231   }
15232   Handle<Map> map(real_receiver->map());
15233 
15234   // Nothing to do if prototype is already set.
15235   if (map->prototype() == *value) return Just(true);
15236 
15237   bool immutable_proto = map->is_immutable_proto();
15238   if (immutable_proto) {
15239     RETURN_FAILURE(
15240         isolate, should_throw,
15241         NewTypeError(MessageTemplate::kImmutablePrototypeSet, object));
15242   }
15243 
15244   // From 8.6.2 Object Internal Methods
15245   // ...
15246   // In addition, if [[Extensible]] is false the value of the [[Class]] and
15247   // [[Prototype]] internal properties of the object may not be modified.
15248   // ...
15249   // Implementation specific extensions that modify [[Class]], [[Prototype]]
15250   // or [[Extensible]] must not violate the invariants defined in the preceding
15251   // paragraph.
15252   if (!all_extensible) {
15253     RETURN_FAILURE(isolate, should_throw,
15254                    NewTypeError(MessageTemplate::kNonExtensibleProto, object));
15255   }
15256 
15257   // Before we can set the prototype we need to be sure prototype cycles are
15258   // prevented.  It is sufficient to validate that the receiver is not in the
15259   // new prototype chain.
15260   if (value->IsJSReceiver()) {
15261     for (PrototypeIterator iter(isolate, JSReceiver::cast(*value),
15262                                 kStartAtReceiver);
15263          !iter.IsAtEnd(); iter.Advance()) {
15264       if (iter.GetCurrent<JSReceiver>() == *object) {
15265         // Cycle detected.
15266         RETURN_FAILURE(isolate, should_throw,
15267                        NewTypeError(MessageTemplate::kCyclicProto));
15268       }
15269     }
15270   }
15271 
15272   // Set the new prototype of the object.
15273 
15274   isolate->UpdateNoElementsProtectorOnSetPrototype(real_receiver);
15275 
15276   Handle<Map> new_map = Map::TransitionToPrototype(map, value);
15277   DCHECK(new_map->prototype() == *value);
15278   JSObject::MigrateToMap(real_receiver, new_map);
15279 
15280   DCHECK(size == object->Size());
15281   return Just(true);
15282 }
15283 
15284 // static
SetImmutableProto(Handle<JSObject> object)15285 void JSObject::SetImmutableProto(Handle<JSObject> object) {
15286   DCHECK(!object->IsAccessCheckNeeded());  // Never called from JS
15287   Handle<Map> map(object->map());
15288 
15289   // Nothing to do if prototype is already set.
15290   if (map->is_immutable_proto()) return;
15291 
15292   Handle<Map> new_map = Map::TransitionToImmutableProto(map);
15293   object->synchronized_set_map(*new_map);
15294 }
15295 
EnsureCanContainElements(Handle<JSObject> object,Arguments * args,uint32_t first_arg,uint32_t arg_count,EnsureElementsMode mode)15296 void JSObject::EnsureCanContainElements(Handle<JSObject> object,
15297                                         Arguments* args,
15298                                         uint32_t first_arg,
15299                                         uint32_t arg_count,
15300                                         EnsureElementsMode mode) {
15301   // Elements in |Arguments| are ordered backwards (because they're on the
15302   // stack), but the method that's called here iterates over them in forward
15303   // direction.
15304   return EnsureCanContainElements(
15305       object, args->arguments() - first_arg - (arg_count - 1), arg_count, mode);
15306 }
15307 
15308 
GetElementsAccessor()15309 ElementsAccessor* JSObject::GetElementsAccessor() {
15310   return ElementsAccessor::ForKind(GetElementsKind());
15311 }
15312 
ValidateElements(JSObject * object)15313 void JSObject::ValidateElements(JSObject* object) {
15314 #ifdef ENABLE_SLOW_DCHECKS
15315   if (FLAG_enable_slow_asserts) {
15316     object->GetElementsAccessor()->Validate(object);
15317   }
15318 #endif
15319 }
15320 
15321 
ShouldConvertToSlowElements(JSObject * object,uint32_t capacity,uint32_t index,uint32_t * new_capacity)15322 static bool ShouldConvertToSlowElements(JSObject* object, uint32_t capacity,
15323                                         uint32_t index,
15324                                         uint32_t* new_capacity) {
15325   STATIC_ASSERT(JSObject::kMaxUncheckedOldFastElementsLength <=
15326                 JSObject::kMaxUncheckedFastElementsLength);
15327   if (index < capacity) {
15328     *new_capacity = capacity;
15329     return false;
15330   }
15331   if (index - capacity >= JSObject::kMaxGap) return true;
15332   *new_capacity = JSObject::NewElementsCapacity(index + 1);
15333   DCHECK_LT(index, *new_capacity);
15334   if (*new_capacity <= JSObject::kMaxUncheckedOldFastElementsLength ||
15335       (*new_capacity <= JSObject::kMaxUncheckedFastElementsLength &&
15336        object->GetHeap()->InNewSpace(object))) {
15337     return false;
15338   }
15339   // If the fast-case backing storage takes up much more memory than a
15340   // dictionary backing storage would, the object should have slow elements.
15341   int used_elements = object->GetFastElementsUsage();
15342   uint32_t size_threshold = NumberDictionary::kPreferFastElementsSizeFactor *
15343                             NumberDictionary::ComputeCapacity(used_elements) *
15344                             NumberDictionary::kEntrySize;
15345   return size_threshold <= *new_capacity;
15346 }
15347 
15348 
WouldConvertToSlowElements(uint32_t index)15349 bool JSObject::WouldConvertToSlowElements(uint32_t index) {
15350   if (!HasFastElements()) return false;
15351   uint32_t capacity = static_cast<uint32_t>(elements()->length());
15352   uint32_t new_capacity;
15353   return ShouldConvertToSlowElements(this, capacity, index, &new_capacity);
15354 }
15355 
15356 
BestFittingFastElementsKind(JSObject * object)15357 static ElementsKind BestFittingFastElementsKind(JSObject* object) {
15358   if (!object->map()->CanHaveFastTransitionableElementsKind()) {
15359     return HOLEY_ELEMENTS;
15360   }
15361   if (object->HasSloppyArgumentsElements()) {
15362     return FAST_SLOPPY_ARGUMENTS_ELEMENTS;
15363   }
15364   if (object->HasStringWrapperElements()) {
15365     return FAST_STRING_WRAPPER_ELEMENTS;
15366   }
15367   DCHECK(object->HasDictionaryElements());
15368   NumberDictionary* dictionary = object->element_dictionary();
15369   ElementsKind kind = HOLEY_SMI_ELEMENTS;
15370   for (int i = 0; i < dictionary->Capacity(); i++) {
15371     Object* key = dictionary->KeyAt(i);
15372     if (key->IsNumber()) {
15373       Object* value = dictionary->ValueAt(i);
15374       if (!value->IsNumber()) return HOLEY_ELEMENTS;
15375       if (!value->IsSmi()) {
15376         if (!FLAG_unbox_double_arrays) return HOLEY_ELEMENTS;
15377         kind = HOLEY_DOUBLE_ELEMENTS;
15378       }
15379     }
15380   }
15381   return kind;
15382 }
15383 
ShouldConvertToFastElements(JSObject * object,NumberDictionary * dictionary,uint32_t index,uint32_t * new_capacity)15384 static bool ShouldConvertToFastElements(JSObject* object,
15385                                         NumberDictionary* dictionary,
15386                                         uint32_t index,
15387                                         uint32_t* new_capacity) {
15388   // If properties with non-standard attributes or accessors were added, we
15389   // cannot go back to fast elements.
15390   if (dictionary->requires_slow_elements()) return false;
15391 
15392   // Adding a property with this index will require slow elements.
15393   if (index >= static_cast<uint32_t>(Smi::kMaxValue)) return false;
15394 
15395   if (object->IsJSArray()) {
15396     Object* length = JSArray::cast(object)->length();
15397     if (!length->IsSmi()) return false;
15398     *new_capacity = static_cast<uint32_t>(Smi::ToInt(length));
15399   } else if (object->IsJSSloppyArgumentsObject()) {
15400     return false;
15401   } else {
15402     *new_capacity = dictionary->max_number_key() + 1;
15403   }
15404   *new_capacity = Max(index + 1, *new_capacity);
15405 
15406   uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
15407                              NumberDictionary::kEntrySize;
15408 
15409   // Turn fast if the dictionary only saves 50% space.
15410   return 2 * dictionary_size >= *new_capacity;
15411 }
15412 
15413 
15414 // static
AddDataElement(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes)15415 MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> object,
15416                                              uint32_t index,
15417                                              Handle<Object> value,
15418                                              PropertyAttributes attributes) {
15419   MAYBE_RETURN_NULL(
15420       AddDataElement(object, index, value, attributes, kThrowOnError));
15421   return value;
15422 }
15423 
15424 
15425 // static
AddDataElement(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,ShouldThrow should_throw)15426 Maybe<bool> JSObject::AddDataElement(Handle<JSObject> object, uint32_t index,
15427                                      Handle<Object> value,
15428                                      PropertyAttributes attributes,
15429                                      ShouldThrow should_throw) {
15430   DCHECK(object->map()->is_extensible());
15431 
15432   Isolate* isolate = object->GetIsolate();
15433 
15434   uint32_t old_length = 0;
15435   uint32_t new_capacity = 0;
15436 
15437   if (object->IsJSArray()) {
15438     CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length));
15439   }
15440 
15441   ElementsKind kind = object->GetElementsKind();
15442   FixedArrayBase* elements = object->elements();
15443   ElementsKind dictionary_kind = DICTIONARY_ELEMENTS;
15444   if (IsSloppyArgumentsElementsKind(kind)) {
15445     elements = SloppyArgumentsElements::cast(elements)->arguments();
15446     dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
15447   } else if (IsStringWrapperElementsKind(kind)) {
15448     dictionary_kind = SLOW_STRING_WRAPPER_ELEMENTS;
15449   }
15450 
15451   if (attributes != NONE) {
15452     kind = dictionary_kind;
15453   } else if (elements->IsNumberDictionary()) {
15454     kind = ShouldConvertToFastElements(
15455                *object, NumberDictionary::cast(elements), index, &new_capacity)
15456                ? BestFittingFastElementsKind(*object)
15457                : dictionary_kind;
15458   } else if (ShouldConvertToSlowElements(
15459                  *object, static_cast<uint32_t>(elements->length()), index,
15460                  &new_capacity)) {
15461     kind = dictionary_kind;
15462   }
15463 
15464   ElementsKind to = value->OptimalElementsKind();
15465   if (IsHoleyOrDictionaryElementsKind(kind) || !object->IsJSArray() ||
15466       index > old_length) {
15467     to = GetHoleyElementsKind(to);
15468     kind = GetHoleyElementsKind(kind);
15469   }
15470   to = GetMoreGeneralElementsKind(kind, to);
15471   ElementsAccessor* accessor = ElementsAccessor::ForKind(to);
15472   accessor->Add(object, index, value, attributes, new_capacity);
15473 
15474   if (object->IsJSArray() && index >= old_length) {
15475     Handle<Object> new_length =
15476         isolate->factory()->NewNumberFromUint(index + 1);
15477     JSArray::cast(*object)->set_length(*new_length);
15478   }
15479 
15480   return Just(true);
15481 }
15482 
15483 
SetLengthWouldNormalize(uint32_t new_length)15484 bool JSArray::SetLengthWouldNormalize(uint32_t new_length) {
15485   if (!HasFastElements()) return false;
15486   uint32_t capacity = static_cast<uint32_t>(elements()->length());
15487   uint32_t new_capacity;
15488   return JSArray::SetLengthWouldNormalize(GetHeap(), new_length) &&
15489          ShouldConvertToSlowElements(this, capacity, new_length - 1,
15490                                      &new_capacity);
15491 }
15492 
15493 
15494 const double AllocationSite::kPretenureRatio = 0.85;
15495 
15496 
ResetPretenureDecision()15497 void AllocationSite::ResetPretenureDecision() {
15498   set_pretenure_decision(kUndecided);
15499   set_memento_found_count(0);
15500   set_memento_create_count(0);
15501 }
15502 
GetPretenureMode() const15503 PretenureFlag AllocationSite::GetPretenureMode() const {
15504   PretenureDecision mode = pretenure_decision();
15505   // Zombie objects "decide" to be untenured.
15506   return mode == kTenure ? TENURED : NOT_TENURED;
15507 }
15508 
IsNested()15509 bool AllocationSite::IsNested() {
15510   DCHECK(FLAG_trace_track_allocation_sites);
15511   Object* current = GetHeap()->allocation_sites_list();
15512   while (current->IsAllocationSite()) {
15513     AllocationSite* current_site = AllocationSite::cast(current);
15514     if (current_site->nested_site() == this) {
15515       return true;
15516     }
15517     current = current_site->weak_next();
15518   }
15519   return false;
15520 }
15521 
15522 template <AllocationSiteUpdateMode update_or_check>
DigestTransitionFeedback(Handle<AllocationSite> site,ElementsKind to_kind)15523 bool AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
15524                                               ElementsKind to_kind) {
15525   Isolate* isolate = site->GetIsolate();
15526   bool result = false;
15527 
15528   if (site->PointsToLiteral() && site->boilerplate()->IsJSArray()) {
15529     Handle<JSArray> boilerplate(JSArray::cast(site->boilerplate()), isolate);
15530     ElementsKind kind = boilerplate->GetElementsKind();
15531     // if kind is holey ensure that to_kind is as well.
15532     if (IsHoleyOrDictionaryElementsKind(kind)) {
15533       to_kind = GetHoleyElementsKind(to_kind);
15534     }
15535     if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
15536       // If the array is huge, it's not likely to be defined in a local
15537       // function, so we shouldn't make new instances of it very often.
15538       uint32_t length = 0;
15539       CHECK(boilerplate->length()->ToArrayLength(&length));
15540       if (length <= kMaximumArrayBytesToPretransition) {
15541         if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) {
15542           return true;
15543         }
15544         if (FLAG_trace_track_allocation_sites) {
15545           bool is_nested = site->IsNested();
15546           PrintF("AllocationSite: JSArray %p boilerplate %supdated %s->%s\n",
15547                  reinterpret_cast<void*>(*site), is_nested ? "(nested)" : " ",
15548                  ElementsKindToString(kind), ElementsKindToString(to_kind));
15549         }
15550         JSObject::TransitionElementsKind(boilerplate, to_kind);
15551         site->dependent_code()->DeoptimizeDependentCodeGroup(
15552             isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
15553         result = true;
15554       }
15555     }
15556   } else {
15557     // The AllocationSite is for a constructed Array.
15558     ElementsKind kind = site->GetElementsKind();
15559     // if kind is holey ensure that to_kind is as well.
15560     if (IsHoleyOrDictionaryElementsKind(kind)) {
15561       to_kind = GetHoleyElementsKind(to_kind);
15562     }
15563     if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
15564       if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) return true;
15565       if (FLAG_trace_track_allocation_sites) {
15566         PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
15567                reinterpret_cast<void*>(*site),
15568                ElementsKindToString(kind),
15569                ElementsKindToString(to_kind));
15570       }
15571       site->SetElementsKind(to_kind);
15572       site->dependent_code()->DeoptimizeDependentCodeGroup(
15573           isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
15574       result = true;
15575     }
15576   }
15577   return result;
15578 }
15579 
ShouldTrack(ElementsKind from,ElementsKind to)15580 bool AllocationSite::ShouldTrack(ElementsKind from, ElementsKind to) {
15581   return IsSmiElementsKind(from) &&
15582          IsMoreGeneralElementsKindTransition(from, to);
15583 }
15584 
PretenureDecisionName(PretenureDecision decision)15585 const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) {
15586   switch (decision) {
15587     case kUndecided: return "undecided";
15588     case kDontTenure: return "don't tenure";
15589     case kMaybeTenure: return "maybe tenure";
15590     case kTenure: return "tenure";
15591     case kZombie: return "zombie";
15592     default: UNREACHABLE();
15593   }
15594   return nullptr;
15595 }
15596 
15597 template <AllocationSiteUpdateMode update_or_check>
UpdateAllocationSite(Handle<JSObject> object,ElementsKind to_kind)15598 bool JSObject::UpdateAllocationSite(Handle<JSObject> object,
15599                                     ElementsKind to_kind) {
15600   if (!object->IsJSArray()) return false;
15601 
15602   Heap* heap = object->GetHeap();
15603   if (!heap->InNewSpace(*object)) return false;
15604 
15605   Handle<AllocationSite> site;
15606   {
15607     DisallowHeapAllocation no_allocation;
15608 
15609     AllocationMemento* memento =
15610         heap->FindAllocationMemento<Heap::kForRuntime>(object->map(), *object);
15611     if (memento == nullptr) return false;
15612 
15613     // Walk through to the Allocation Site
15614     site = handle(memento->GetAllocationSite());
15615   }
15616   return AllocationSite::DigestTransitionFeedback<update_or_check>(site,
15617                                                                    to_kind);
15618 }
15619 
15620 template bool
15621 JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kCheckOnly>(
15622     Handle<JSObject> object, ElementsKind to_kind);
15623 
15624 template bool JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kUpdate>(
15625     Handle<JSObject> object, ElementsKind to_kind);
15626 
TransitionElementsKind(Handle<JSObject> object,ElementsKind to_kind)15627 void JSObject::TransitionElementsKind(Handle<JSObject> object,
15628                                       ElementsKind to_kind) {
15629   ElementsKind from_kind = object->GetElementsKind();
15630 
15631   if (IsHoleyElementsKind(from_kind)) {
15632     to_kind = GetHoleyElementsKind(to_kind);
15633   }
15634 
15635   if (from_kind == to_kind) return;
15636 
15637   // This method should never be called for any other case.
15638   DCHECK(IsFastElementsKind(from_kind));
15639   DCHECK(IsFastElementsKind(to_kind));
15640   DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind);
15641 
15642   UpdateAllocationSite(object, to_kind);
15643   if (object->elements() == object->GetHeap()->empty_fixed_array() ||
15644       IsDoubleElementsKind(from_kind) == IsDoubleElementsKind(to_kind)) {
15645     // No change is needed to the elements() buffer, the transition
15646     // only requires a map change.
15647     Handle<Map> new_map = GetElementsTransitionMap(object, to_kind);
15648     MigrateToMap(object, new_map);
15649     if (FLAG_trace_elements_transitions) {
15650       Handle<FixedArrayBase> elms(object->elements());
15651       PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms);
15652     }
15653   } else {
15654     DCHECK((IsSmiElementsKind(from_kind) && IsDoubleElementsKind(to_kind)) ||
15655            (IsDoubleElementsKind(from_kind) && IsObjectElementsKind(to_kind)));
15656     uint32_t c = static_cast<uint32_t>(object->elements()->length());
15657     ElementsAccessor::ForKind(to_kind)->GrowCapacityAndConvert(object, c);
15658   }
15659 }
15660 
15661 
15662 // static
IsValidElementsTransition(ElementsKind from_kind,ElementsKind to_kind)15663 bool Map::IsValidElementsTransition(ElementsKind from_kind,
15664                                     ElementsKind to_kind) {
15665   // Transitions can't go backwards.
15666   if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
15667     return false;
15668   }
15669 
15670   // Transitions from HOLEY -> PACKED are not allowed.
15671   return !IsHoleyElementsKind(from_kind) || IsHoleyElementsKind(to_kind);
15672 }
15673 
15674 
HasReadOnlyLength(Handle<JSArray> array)15675 bool JSArray::HasReadOnlyLength(Handle<JSArray> array) {
15676   Map* map = array->map();
15677   // Fast path: "length" is the first fast property of arrays. Since it's not
15678   // configurable, it's guaranteed to be the first in the descriptor array.
15679   if (!map->is_dictionary_map()) {
15680     DCHECK(map->instance_descriptors()->GetKey(0) ==
15681            array->GetHeap()->length_string());
15682     return map->instance_descriptors()->GetDetails(0).IsReadOnly();
15683   }
15684 
15685   Isolate* isolate = array->GetIsolate();
15686   LookupIterator it(array, isolate->factory()->length_string(), array,
15687                     LookupIterator::OWN_SKIP_INTERCEPTOR);
15688   CHECK_EQ(LookupIterator::ACCESSOR, it.state());
15689   return it.IsReadOnly();
15690 }
15691 
15692 
WouldChangeReadOnlyLength(Handle<JSArray> array,uint32_t index)15693 bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array,
15694                                         uint32_t index) {
15695   uint32_t length = 0;
15696   CHECK(array->length()->ToArrayLength(&length));
15697   if (length <= index) return HasReadOnlyLength(array);
15698   return false;
15699 }
15700 
15701 template <typename BackingStore>
HoleyElementsUsage(JSObject * object,BackingStore * store)15702 static int HoleyElementsUsage(JSObject* object, BackingStore* store) {
15703   Isolate* isolate = store->GetIsolate();
15704   int limit = object->IsJSArray() ? Smi::ToInt(JSArray::cast(object)->length())
15705                                   : store->length();
15706   int used = 0;
15707   for (int i = 0; i < limit; ++i) {
15708     if (!store->is_the_hole(isolate, i)) ++used;
15709   }
15710   return used;
15711 }
15712 
GetFastElementsUsage()15713 int JSObject::GetFastElementsUsage() {
15714   FixedArrayBase* store = elements();
15715   switch (GetElementsKind()) {
15716     case PACKED_SMI_ELEMENTS:
15717     case PACKED_DOUBLE_ELEMENTS:
15718     case PACKED_ELEMENTS:
15719       return IsJSArray() ? Smi::ToInt(JSArray::cast(this)->length())
15720                          : store->length();
15721     case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
15722       store = SloppyArgumentsElements::cast(store)->arguments();
15723       V8_FALLTHROUGH;
15724     case HOLEY_SMI_ELEMENTS:
15725     case HOLEY_ELEMENTS:
15726     case FAST_STRING_WRAPPER_ELEMENTS:
15727       return HoleyElementsUsage(this, FixedArray::cast(store));
15728     case HOLEY_DOUBLE_ELEMENTS:
15729       if (elements()->length() == 0) return 0;
15730       return HoleyElementsUsage(this, FixedDoubleArray::cast(store));
15731 
15732     case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
15733     case SLOW_STRING_WRAPPER_ELEMENTS:
15734     case DICTIONARY_ELEMENTS:
15735     case NO_ELEMENTS:
15736 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                      \
15737     case TYPE##_ELEMENTS:                                                    \
15738 
15739     TYPED_ARRAYS(TYPED_ARRAY_CASE)
15740 #undef TYPED_ARRAY_CASE
15741     UNREACHABLE();
15742   }
15743   return 0;
15744 }
15745 
15746 
15747 // Certain compilers request function template instantiation when they
15748 // see the definition of the other template functions in the
15749 // class. This requires us to have the template functions put
15750 // together, so even though this function belongs in objects-debug.cc,
15751 // we keep it here instead to satisfy certain compilers.
15752 #ifdef OBJECT_PRINT
15753 template <typename Derived, typename Shape>
Print(std::ostream & os)15754 void Dictionary<Derived, Shape>::Print(std::ostream& os) {
15755   DisallowHeapAllocation no_gc;
15756   Isolate* isolate = this->GetIsolate();
15757   Derived* dictionary = Derived::cast(this);
15758   int capacity = dictionary->Capacity();
15759   for (int i = 0; i < capacity; i++) {
15760     Object* k = dictionary->KeyAt(i);
15761     if (!dictionary->ToKey(isolate, i, &k)) continue;
15762     os << "\n   ";
15763     if (k->IsString()) {
15764       String::cast(k)->StringPrint(os);
15765     } else {
15766       os << Brief(k);
15767     }
15768     os << ": " << Brief(dictionary->ValueAt(i)) << " ";
15769     dictionary->DetailsAt(i).PrintAsSlowTo(os);
15770   }
15771 }
15772 template <typename Derived, typename Shape>
Print()15773 void Dictionary<Derived, Shape>::Print() {
15774   OFStream os(stdout);
15775   Print(os);
15776   os << std::endl;
15777 }
15778 #endif
15779 
15780 
GetPropertyWithInterceptor(LookupIterator * it,bool * done)15781 MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it,
15782                                                          bool* done) {
15783   DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
15784   return GetPropertyWithInterceptorInternal(it, it->GetInterceptor(), done);
15785 }
15786 
HasRealNamedProperty(Handle<JSObject> object,Handle<Name> name)15787 Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object,
15788                                            Handle<Name> name) {
15789   LookupIterator it = LookupIterator::PropertyOrElement(
15790       name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
15791   return HasProperty(&it);
15792 }
15793 
15794 
HasRealElementProperty(Handle<JSObject> object,uint32_t index)15795 Maybe<bool> JSObject::HasRealElementProperty(Handle<JSObject> object,
15796                                              uint32_t index) {
15797   Isolate* isolate = object->GetIsolate();
15798   LookupIterator it(isolate, object, index, object,
15799                     LookupIterator::OWN_SKIP_INTERCEPTOR);
15800   return HasProperty(&it);
15801 }
15802 
15803 
HasRealNamedCallbackProperty(Handle<JSObject> object,Handle<Name> name)15804 Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
15805                                                    Handle<Name> name) {
15806   LookupIterator it = LookupIterator::PropertyOrElement(
15807       name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
15808   Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
15809   return maybe_result.IsJust() ? Just(it.state() == LookupIterator::ACCESSOR)
15810                                : Nothing<bool>();
15811 }
15812 
GetMaxLengthForNewSpaceAllocation(ElementsKind kind)15813 int FixedArrayBase::GetMaxLengthForNewSpaceAllocation(ElementsKind kind) {
15814   return ((kMaxRegularHeapObjectSize - FixedArrayBase::kHeaderSize) >>
15815           ElementsKindToShiftSize(kind));
15816 }
15817 
IsCowArray() const15818 bool FixedArrayBase::IsCowArray() const {
15819   return map() == GetHeap()->fixed_cow_array_map();
15820 }
15821 
WasConstructedFromApiFunction()15822 bool JSObject::WasConstructedFromApiFunction() {
15823   auto instance_type = map()->instance_type();
15824   bool is_api_object = instance_type == JS_API_OBJECT_TYPE ||
15825                        instance_type == JS_SPECIAL_API_OBJECT_TYPE;
15826   bool is_wasm_object =
15827       instance_type == WASM_GLOBAL_TYPE || instance_type == WASM_MEMORY_TYPE ||
15828       instance_type == WASM_MODULE_TYPE ||
15829       instance_type == WASM_INSTANCE_TYPE || instance_type == WASM_TABLE_TYPE;
15830 #ifdef ENABLE_SLOW_DCHECKS
15831   if (FLAG_enable_slow_asserts) {
15832     Object* maybe_constructor = map()->GetConstructor();
15833     if (maybe_constructor->IsJSFunction()) {
15834       JSFunction* constructor = JSFunction::cast(maybe_constructor);
15835       DCHECK_EQ(constructor->shared()->IsApiFunction(),
15836                 is_api_object || is_wasm_object);
15837     } else if (maybe_constructor->IsFunctionTemplateInfo()) {
15838       DCHECK(is_api_object || is_wasm_object);
15839     } else {
15840       return false;
15841     }
15842   }
15843 #endif
15844   // TODO(titzer): Clean this up somehow. WebAssembly objects should not be
15845   // considered "constructed from API functions" even though they have
15846   // function template info, since that would make the V8 GC identify them to
15847   // the embedder, e.g. the Oilpan GC.
15848   USE(is_wasm_object);
15849   return is_api_object;
15850 }
15851 
PrivateSymbolToName() const15852 const char* Symbol::PrivateSymbolToName() const {
15853   Heap* heap = GetIsolate()->heap();
15854 #define SYMBOL_CHECK_AND_PRINT(name) \
15855   if (this == heap->name()) return #name;
15856   PRIVATE_SYMBOL_LIST(SYMBOL_CHECK_AND_PRINT)
15857 #undef SYMBOL_CHECK_AND_PRINT
15858   return "UNKNOWN";
15859 }
15860 
15861 
SymbolShortPrint(std::ostream & os)15862 void Symbol::SymbolShortPrint(std::ostream& os) {
15863   os << "<Symbol:";
15864   if (!name()->IsUndefined(GetIsolate())) {
15865     os << " ";
15866     HeapStringAllocator allocator;
15867     StringStream accumulator(&allocator);
15868     String::cast(name())->StringShortPrint(&accumulator, false);
15869     os << accumulator.ToCString().get();
15870   } else {
15871     os << " (" << PrivateSymbolToName() << ")";
15872   }
15873   os << ">";
15874 }
15875 
15876 
15877 // StringSharedKeys are used as keys in the eval cache.
15878 class StringSharedKey : public HashTableKey {
15879  public:
15880   // This tuple unambiguously identifies calls to eval() or
15881   // CreateDynamicFunction() (such as through the Function() constructor).
15882   // * source is the string passed into eval(). For dynamic functions, this is
15883   //   the effective source for the function, some of which is implicitly
15884   //   generated.
15885   // * shared is the shared function info for the function containing the call
15886   //   to eval(). for dynamic functions, shared is the native context closure.
15887   // * When positive, position is the position in the source where eval is
15888   //   called. When negative, position is the negation of the position in the
15889   //   dynamic function's effective source where the ')' ends the parameters.
StringSharedKey(Handle<String> source,Handle<SharedFunctionInfo> shared,LanguageMode language_mode,int position)15890   StringSharedKey(Handle<String> source, Handle<SharedFunctionInfo> shared,
15891                   LanguageMode language_mode, int position)
15892       : HashTableKey(CompilationCacheShape::StringSharedHash(
15893             *source, *shared, language_mode, position)),
15894         source_(source),
15895         shared_(shared),
15896         language_mode_(language_mode),
15897         position_(position) {}
15898 
IsMatch(Object * other)15899   bool IsMatch(Object* other) override {
15900     DisallowHeapAllocation no_allocation;
15901     if (!other->IsFixedArray()) {
15902       DCHECK(other->IsNumber());
15903       uint32_t other_hash = static_cast<uint32_t>(other->Number());
15904       return Hash() == other_hash;
15905     }
15906     FixedArray* other_array = FixedArray::cast(other);
15907     SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
15908     if (shared != *shared_) return false;
15909     int language_unchecked = Smi::ToInt(other_array->get(2));
15910     DCHECK(is_valid_language_mode(language_unchecked));
15911     LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
15912     if (language_mode != language_mode_) return false;
15913     int position = Smi::ToInt(other_array->get(3));
15914     if (position != position_) return false;
15915     String* source = String::cast(other_array->get(1));
15916     return source->Equals(*source_);
15917   }
15918 
AsHandle(Isolate * isolate)15919   Handle<Object> AsHandle(Isolate* isolate) {
15920     Handle<FixedArray> array = isolate->factory()->NewFixedArray(4);
15921     array->set(0, *shared_);
15922     array->set(1, *source_);
15923     array->set(2, Smi::FromEnum(language_mode_));
15924     array->set(3, Smi::FromInt(position_));
15925     array->set_map(isolate->heap()->fixed_cow_array_map());
15926     return array;
15927   }
15928 
15929  private:
15930   Handle<String> source_;
15931   Handle<SharedFunctionInfo> shared_;
15932   LanguageMode language_mode_;
15933   int position_;
15934 };
15935 
status() const15936 v8::Promise::PromiseState JSPromise::status() const {
15937   int value = flags() & kStatusMask;
15938   DCHECK(value == 0 || value == 1 || value == 2);
15939   return static_cast<v8::Promise::PromiseState>(value);
15940 }
15941 
set_status(Promise::PromiseState status)15942 void JSPromise::set_status(Promise::PromiseState status) {
15943   int value = flags() & ~kStatusMask;
15944   set_flags(value | status);
15945 }
15946 
15947 // static
Status(v8::Promise::PromiseState status)15948 const char* JSPromise::Status(v8::Promise::PromiseState status) {
15949   switch (status) {
15950     case v8::Promise::kFulfilled:
15951       return "resolved";
15952     case v8::Promise::kPending:
15953       return "pending";
15954     case v8::Promise::kRejected:
15955       return "rejected";
15956   }
15957   UNREACHABLE();
15958 }
15959 
15960 // static
Fulfill(Handle<JSPromise> promise,Handle<Object> value)15961 Handle<Object> JSPromise::Fulfill(Handle<JSPromise> promise,
15962                                   Handle<Object> value) {
15963   Isolate* const isolate = promise->GetIsolate();
15964 
15965   // 1. Assert: The value of promise.[[PromiseState]] is "pending".
15966   DCHECK_EQ(Promise::kPending, promise->status());
15967 
15968   // 2. Let reactions be promise.[[PromiseFulfillReactions]].
15969   Handle<Object> reactions(promise->reactions(), isolate);
15970 
15971   // 3. Set promise.[[PromiseResult]] to value.
15972   // 4. Set promise.[[PromiseFulfillReactions]] to undefined.
15973   // 5. Set promise.[[PromiseRejectReactions]] to undefined.
15974   promise->set_reactions_or_result(*value);
15975 
15976   // 6. Set promise.[[PromiseState]] to "fulfilled".
15977   promise->set_status(Promise::kFulfilled);
15978 
15979   // 7. Return TriggerPromiseReactions(reactions, value).
15980   return TriggerPromiseReactions(isolate, reactions, value,
15981                                  PromiseReaction::kFulfill);
15982 }
15983 
15984 // static
Reject(Handle<JSPromise> promise,Handle<Object> reason,bool debug_event)15985 Handle<Object> JSPromise::Reject(Handle<JSPromise> promise,
15986                                  Handle<Object> reason, bool debug_event) {
15987   Isolate* const isolate = promise->GetIsolate();
15988 
15989   if (debug_event) isolate->debug()->OnPromiseReject(promise, reason);
15990   isolate->RunPromiseHook(PromiseHookType::kResolve, promise,
15991                           isolate->factory()->undefined_value());
15992 
15993   // 1. Assert: The value of promise.[[PromiseState]] is "pending".
15994   DCHECK_EQ(Promise::kPending, promise->status());
15995 
15996   // 2. Let reactions be promise.[[PromiseRejectReactions]].
15997   Handle<Object> reactions(promise->reactions(), isolate);
15998 
15999   // 3. Set promise.[[PromiseResult]] to reason.
16000   // 4. Set promise.[[PromiseFulfillReactions]] to undefined.
16001   // 5. Set promise.[[PromiseRejectReactions]] to undefined.
16002   promise->set_reactions_or_result(*reason);
16003 
16004   // 6. Set promise.[[PromiseState]] to "rejected".
16005   promise->set_status(Promise::kRejected);
16006 
16007   // 7. If promise.[[PromiseIsHandled]] is false, perform
16008   //    HostPromiseRejectionTracker(promise, "reject").
16009   if (!promise->has_handler()) {
16010     isolate->ReportPromiseReject(promise, reason, kPromiseRejectWithNoHandler);
16011   }
16012 
16013   // 8. Return TriggerPromiseReactions(reactions, reason).
16014   return TriggerPromiseReactions(isolate, reactions, reason,
16015                                  PromiseReaction::kReject);
16016 }
16017 
16018 // static
Resolve(Handle<JSPromise> promise,Handle<Object> resolution)16019 MaybeHandle<Object> JSPromise::Resolve(Handle<JSPromise> promise,
16020                                        Handle<Object> resolution) {
16021   Isolate* const isolate = promise->GetIsolate();
16022 
16023   isolate->RunPromiseHook(PromiseHookType::kResolve, promise,
16024                           isolate->factory()->undefined_value());
16025 
16026   // 6. If SameValue(resolution, promise) is true, then
16027   if (promise.is_identical_to(resolution)) {
16028     // a. Let selfResolutionError be a newly created TypeError object.
16029     Handle<Object> self_resolution_error = isolate->factory()->NewTypeError(
16030         MessageTemplate::kPromiseCyclic, resolution);
16031     // b. Return RejectPromise(promise, selfResolutionError).
16032     return Reject(promise, self_resolution_error);
16033   }
16034 
16035   // 7. If Type(resolution) is not Object, then
16036   if (!resolution->IsJSReceiver()) {
16037     // a. Return FulfillPromise(promise, resolution).
16038     return Fulfill(promise, resolution);
16039   }
16040 
16041   // 8. Let then be Get(resolution, "then").
16042   MaybeHandle<Object> then;
16043   if (isolate->IsPromiseThenLookupChainIntact(
16044           Handle<JSReceiver>::cast(resolution))) {
16045     // We can skip the "then" lookup on {resolution} if its [[Prototype]]
16046     // is the (initial) Promise.prototype and the Promise#then protector
16047     // is intact, as that guards the lookup path for the "then" property
16048     // on JSPromise instances which have the (initial) %PromisePrototype%.
16049     then = isolate->promise_then();
16050   } else {
16051     then = JSReceiver::GetProperty(Handle<JSReceiver>::cast(resolution),
16052                                    isolate->factory()->then_string());
16053   }
16054 
16055   // 9. If then is an abrupt completion, then
16056   Handle<Object> then_action;
16057   if (!then.ToHandle(&then_action)) {
16058     // a. Return RejectPromise(promise, then.[[Value]]).
16059     Handle<Object> reason(isolate->pending_exception(), isolate);
16060     isolate->clear_pending_exception();
16061     return Reject(promise, reason, false);
16062   }
16063 
16064   // 10. Let thenAction be then.[[Value]].
16065   // 11. If IsCallable(thenAction) is false, then
16066   if (!then_action->IsCallable()) {
16067     // a. Return FulfillPromise(promise, resolution).
16068     return Fulfill(promise, resolution);
16069   }
16070 
16071   // 12. Perform EnqueueJob("PromiseJobs", PromiseResolveThenableJob,
16072   //                        «promise, resolution, thenAction»).
16073   Handle<PromiseResolveThenableJobTask> task =
16074       isolate->factory()->NewPromiseResolveThenableJobTask(
16075           promise, Handle<JSReceiver>::cast(then_action),
16076           Handle<JSReceiver>::cast(resolution), isolate->native_context());
16077   if (isolate->debug()->is_active() && resolution->IsJSPromise()) {
16078     // Mark the dependency of the new {promise} on the {resolution}.
16079     Object::SetProperty(resolution,
16080                         isolate->factory()->promise_handled_by_symbol(),
16081                         promise, LanguageMode::kStrict)
16082         .Check();
16083   }
16084   isolate->EnqueueMicrotask(task);
16085 
16086   // 13. Return undefined.
16087   return isolate->factory()->undefined_value();
16088 }
16089 
16090 // static
TriggerPromiseReactions(Isolate * isolate,Handle<Object> reactions,Handle<Object> argument,PromiseReaction::Type type)16091 Handle<Object> JSPromise::TriggerPromiseReactions(Isolate* isolate,
16092                                                   Handle<Object> reactions,
16093                                                   Handle<Object> argument,
16094                                                   PromiseReaction::Type type) {
16095   DCHECK(reactions->IsSmi() || reactions->IsPromiseReaction());
16096 
16097   // We need to reverse the {reactions} here, since we record them
16098   // on the JSPromise in the reverse order.
16099   {
16100     DisallowHeapAllocation no_gc;
16101     Object* current = *reactions;
16102     Object* reversed = Smi::kZero;
16103     while (!current->IsSmi()) {
16104       Object* next = PromiseReaction::cast(current)->next();
16105       PromiseReaction::cast(current)->set_next(reversed);
16106       reversed = current;
16107       current = next;
16108     }
16109     reactions = handle(reversed, isolate);
16110   }
16111 
16112   // Morph the {reactions} into PromiseReactionJobTasks
16113   // and push them onto the microtask queue.
16114   while (!reactions->IsSmi()) {
16115     Handle<HeapObject> task = Handle<HeapObject>::cast(reactions);
16116     Handle<PromiseReaction> reaction = Handle<PromiseReaction>::cast(task);
16117     reactions = handle(reaction->next(), isolate);
16118 
16119     STATIC_ASSERT(PromiseReaction::kSize == PromiseReactionJobTask::kSize);
16120     if (type == PromiseReaction::kFulfill) {
16121       task->synchronized_set_map(
16122           isolate->heap()->promise_fulfill_reaction_job_task_map());
16123       Handle<PromiseFulfillReactionJobTask>::cast(task)->set_argument(
16124           *argument);
16125       Handle<PromiseFulfillReactionJobTask>::cast(task)->set_context(
16126           *isolate->native_context());
16127       STATIC_ASSERT(PromiseReaction::kFulfillHandlerOffset ==
16128                     PromiseFulfillReactionJobTask::kHandlerOffset);
16129       STATIC_ASSERT(PromiseReaction::kPromiseOrCapabilityOffset ==
16130                     PromiseFulfillReactionJobTask::kPromiseOrCapabilityOffset);
16131     } else {
16132       DisallowHeapAllocation no_gc;
16133       HeapObject* handler = reaction->reject_handler();
16134       task->synchronized_set_map(
16135           isolate->heap()->promise_reject_reaction_job_task_map());
16136       Handle<PromiseRejectReactionJobTask>::cast(task)->set_argument(*argument);
16137       Handle<PromiseRejectReactionJobTask>::cast(task)->set_context(
16138           *isolate->native_context());
16139       Handle<PromiseRejectReactionJobTask>::cast(task)->set_handler(handler);
16140       STATIC_ASSERT(PromiseReaction::kPromiseOrCapabilityOffset ==
16141                     PromiseRejectReactionJobTask::kPromiseOrCapabilityOffset);
16142     }
16143 
16144     isolate->EnqueueMicrotask(Handle<PromiseReactionJobTask>::cast(task));
16145   }
16146 
16147   return isolate->factory()->undefined_value();
16148 }
16149 
16150 namespace {
16151 
RegExpFlagsFromString(Handle<String> flags,bool * success)16152 JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags, bool* success) {
16153   JSRegExp::Flags value = JSRegExp::kNone;
16154   int length = flags->length();
16155   // A longer flags string cannot be valid.
16156   if (length > JSRegExp::FlagCount()) return JSRegExp::Flags(0);
16157   for (int i = 0; i < length; i++) {
16158     JSRegExp::Flag flag = JSRegExp::kNone;
16159     switch (flags->Get(i)) {
16160       case 'g':
16161         flag = JSRegExp::kGlobal;
16162         break;
16163       case 'i':
16164         flag = JSRegExp::kIgnoreCase;
16165         break;
16166       case 'm':
16167         flag = JSRegExp::kMultiline;
16168         break;
16169       case 's':
16170         flag = JSRegExp::kDotAll;
16171         break;
16172       case 'u':
16173         flag = JSRegExp::kUnicode;
16174         break;
16175       case 'y':
16176         flag = JSRegExp::kSticky;
16177         break;
16178       default:
16179         return JSRegExp::Flags(0);
16180     }
16181     // Duplicate flag.
16182     if (value & flag) return JSRegExp::Flags(0);
16183     value |= flag;
16184   }
16185   *success = true;
16186   return value;
16187 }
16188 
16189 }  // namespace
16190 
16191 
16192 // static
New(Handle<String> pattern,Flags flags)16193 MaybeHandle<JSRegExp> JSRegExp::New(Handle<String> pattern, Flags flags) {
16194   Isolate* isolate = pattern->GetIsolate();
16195   Handle<JSFunction> constructor = isolate->regexp_function();
16196   Handle<JSRegExp> regexp =
16197       Handle<JSRegExp>::cast(isolate->factory()->NewJSObject(constructor));
16198 
16199   return JSRegExp::Initialize(regexp, pattern, flags);
16200 }
16201 
16202 
16203 // static
Copy(Handle<JSRegExp> regexp)16204 Handle<JSRegExp> JSRegExp::Copy(Handle<JSRegExp> regexp) {
16205   Isolate* const isolate = regexp->GetIsolate();
16206   return Handle<JSRegExp>::cast(isolate->factory()->CopyJSObject(regexp));
16207 }
16208 
16209 
16210 template <typename Char>
CountRequiredEscapes(Handle<String> source)16211 inline int CountRequiredEscapes(Handle<String> source) {
16212   DisallowHeapAllocation no_gc;
16213   int escapes = 0;
16214   Vector<const Char> src = source->GetCharVector<Char>();
16215   for (int i = 0; i < src.length(); i++) {
16216     if (src[i] == '\\') {
16217       // Escape. Skip next character;
16218       i++;
16219     } else if (src[i] == '/') {
16220       // Not escaped forward-slash needs escape.
16221       escapes++;
16222     }
16223   }
16224   return escapes;
16225 }
16226 
16227 
16228 template <typename Char, typename StringType>
WriteEscapedRegExpSource(Handle<String> source,Handle<StringType> result)16229 inline Handle<StringType> WriteEscapedRegExpSource(Handle<String> source,
16230                                                    Handle<StringType> result) {
16231   DisallowHeapAllocation no_gc;
16232   Vector<const Char> src = source->GetCharVector<Char>();
16233   Vector<Char> dst(result->GetChars(), result->length());
16234   int s = 0;
16235   int d = 0;
16236   while (s < src.length()) {
16237     if (src[s] == '\\') {
16238       // Escape. Copy this and next character.
16239       dst[d++] = src[s++];
16240       if (s == src.length()) break;
16241     } else if (src[s] == '/') {
16242       // Not escaped forward-slash needs escape.
16243       dst[d++] = '\\';
16244     }
16245     dst[d++] = src[s++];
16246   }
16247   DCHECK_EQ(result->length(), d);
16248   return result;
16249 }
16250 
16251 
EscapeRegExpSource(Isolate * isolate,Handle<String> source)16252 MaybeHandle<String> EscapeRegExpSource(Isolate* isolate,
16253                                        Handle<String> source) {
16254   DCHECK(source->IsFlat());
16255   if (source->length() == 0) return isolate->factory()->query_colon_string();
16256   bool one_byte = source->IsOneByteRepresentationUnderneath();
16257   int escapes = one_byte ? CountRequiredEscapes<uint8_t>(source)
16258                          : CountRequiredEscapes<uc16>(source);
16259   if (escapes == 0) return source;
16260   int length = source->length() + escapes;
16261   if (one_byte) {
16262     Handle<SeqOneByteString> result;
16263     ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
16264                                isolate->factory()->NewRawOneByteString(length),
16265                                String);
16266     return WriteEscapedRegExpSource<uint8_t>(source, result);
16267   } else {
16268     Handle<SeqTwoByteString> result;
16269     ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
16270                                isolate->factory()->NewRawTwoByteString(length),
16271                                String);
16272     return WriteEscapedRegExpSource<uc16>(source, result);
16273   }
16274 }
16275 
16276 
16277 // static
Initialize(Handle<JSRegExp> regexp,Handle<String> source,Handle<String> flags_string)16278 MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
16279                                            Handle<String> source,
16280                                            Handle<String> flags_string) {
16281   Isolate* isolate = source->GetIsolate();
16282   bool success = false;
16283   Flags flags = RegExpFlagsFromString(flags_string, &success);
16284   if (!success) {
16285     THROW_NEW_ERROR(
16286         isolate,
16287         NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string),
16288         JSRegExp);
16289   }
16290   return Initialize(regexp, source, flags);
16291 }
16292 
16293 
16294 // static
Initialize(Handle<JSRegExp> regexp,Handle<String> source,Flags flags)16295 MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
16296                                            Handle<String> source, Flags flags) {
16297   Isolate* isolate = regexp->GetIsolate();
16298   Factory* factory = isolate->factory();
16299   // If source is the empty string we set it to "(?:)" instead as
16300   // suggested by ECMA-262, 5th, section 15.10.4.1.
16301   if (source->length() == 0) source = factory->query_colon_string();
16302 
16303   source = String::Flatten(source);
16304 
16305   Handle<String> escaped_source;
16306   ASSIGN_RETURN_ON_EXCEPTION(isolate, escaped_source,
16307                              EscapeRegExpSource(isolate, source), JSRegExp);
16308 
16309   RETURN_ON_EXCEPTION(isolate, RegExpImpl::Compile(regexp, source, flags),
16310                       JSRegExp);
16311 
16312   regexp->set_source(*escaped_source);
16313   regexp->set_flags(Smi::FromInt(flags));
16314 
16315   Map* map = regexp->map();
16316   Object* constructor = map->GetConstructor();
16317   if (constructor->IsJSFunction() &&
16318       JSFunction::cast(constructor)->initial_map() == map) {
16319     // If we still have the original map, set in-object properties directly.
16320     regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, Smi::kZero,
16321                                   SKIP_WRITE_BARRIER);
16322   } else {
16323     // Map has changed, so use generic, but slower, method.
16324     RETURN_ON_EXCEPTION(
16325         isolate,
16326         JSReceiver::SetProperty(regexp, factory->lastIndex_string(),
16327                                 Handle<Smi>(Smi::kZero, isolate),
16328                                 LanguageMode::kStrict),
16329         JSRegExp);
16330   }
16331 
16332   return regexp;
16333 }
16334 
16335 
16336 // RegExpKey carries the source and flags of a regular expression as key.
16337 class RegExpKey : public HashTableKey {
16338  public:
RegExpKey(Handle<String> string,JSRegExp::Flags flags)16339   RegExpKey(Handle<String> string, JSRegExp::Flags flags)
16340       : HashTableKey(
16341             CompilationCacheShape::RegExpHash(*string, Smi::FromInt(flags))),
16342         string_(string),
16343         flags_(Smi::FromInt(flags)) {}
16344 
16345   // Rather than storing the key in the hash table, a pointer to the
16346   // stored value is stored where the key should be.  IsMatch then
16347   // compares the search key to the found object, rather than comparing
16348   // a key to a key.
IsMatch(Object * obj)16349   bool IsMatch(Object* obj) override {
16350     FixedArray* val = FixedArray::cast(obj);
16351     return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
16352         && (flags_ == val->get(JSRegExp::kFlagsIndex));
16353   }
16354 
16355   Handle<String> string_;
16356   Smi* flags_;
16357 };
16358 
AsHandle(Isolate * isolate)16359 Handle<String> OneByteStringKey::AsHandle(Isolate* isolate) {
16360   return isolate->factory()->NewOneByteInternalizedString(string_, HashField());
16361 }
16362 
AsHandle(Isolate * isolate)16363 Handle<String> TwoByteStringKey::AsHandle(Isolate* isolate) {
16364   return isolate->factory()->NewTwoByteInternalizedString(string_, HashField());
16365 }
16366 
AsHandle(Isolate * isolate)16367 Handle<String> SeqOneByteSubStringKey::AsHandle(Isolate* isolate) {
16368   return isolate->factory()->NewOneByteInternalizedSubString(
16369       string_, from_, length_, HashField());
16370 }
16371 
16372 
IsMatch(Object * string)16373 bool SeqOneByteSubStringKey::IsMatch(Object* string) {
16374   Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
16375   return String::cast(string)->IsOneByteEqualTo(chars);
16376 }
16377 
16378 
16379 // InternalizedStringKey carries a string/internalized-string object as key.
16380 class InternalizedStringKey : public StringTableKey {
16381  public:
InternalizedStringKey(Handle<String> string)16382   explicit InternalizedStringKey(Handle<String> string)
16383       : StringTableKey(0), string_(string) {
16384     DCHECK(!string->IsInternalizedString());
16385     DCHECK(string->IsFlat());
16386     // Make sure hash_field is computed.
16387     string->Hash();
16388     set_hash_field(string->hash_field());
16389   }
16390 
IsMatch(Object * string)16391   bool IsMatch(Object* string) override {
16392     return string_->SlowEquals(String::cast(string));
16393   }
16394 
AsHandle(Isolate * isolate)16395   Handle<String> AsHandle(Isolate* isolate) override {
16396     // Internalize the string if possible.
16397     MaybeHandle<Map> maybe_map =
16398         isolate->factory()->InternalizedStringMapForString(string_);
16399     Handle<Map> map;
16400     if (maybe_map.ToHandle(&map)) {
16401       string_->set_map_no_write_barrier(*map);
16402       DCHECK(string_->IsInternalizedString());
16403       return string_;
16404     }
16405     if (FLAG_thin_strings) {
16406       // External strings get special treatment, to avoid copying their
16407       // contents.
16408       if (string_->IsExternalOneByteString()) {
16409         return isolate->factory()
16410             ->InternalizeExternalString<ExternalOneByteString>(string_);
16411       } else if (string_->IsExternalTwoByteString()) {
16412         return isolate->factory()
16413             ->InternalizeExternalString<ExternalTwoByteString>(string_);
16414       }
16415     }
16416     // Otherwise allocate a new internalized string.
16417     return isolate->factory()->NewInternalizedStringImpl(
16418         string_, string_->length(), string_->hash_field());
16419   }
16420 
16421  private:
16422   Handle<String> string_;
16423 };
16424 
16425 template <typename Derived, typename Shape>
IteratePrefix(ObjectVisitor * v)16426 void HashTable<Derived, Shape>::IteratePrefix(ObjectVisitor* v) {
16427   BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v);
16428 }
16429 
16430 template <typename Derived, typename Shape>
IterateElements(ObjectVisitor * v)16431 void HashTable<Derived, Shape>::IterateElements(ObjectVisitor* v) {
16432   BodyDescriptorBase::IteratePointers(this, kElementsStartOffset,
16433                                       kHeaderSize + length() * kPointerSize, v);
16434 }
16435 
16436 template <typename Derived, typename Shape>
New(Isolate * isolate,int at_least_space_for,PretenureFlag pretenure,MinimumCapacity capacity_option)16437 Handle<Derived> HashTable<Derived, Shape>::New(
16438     Isolate* isolate, int at_least_space_for, PretenureFlag pretenure,
16439     MinimumCapacity capacity_option) {
16440   DCHECK_LE(0, at_least_space_for);
16441   DCHECK_IMPLIES(capacity_option == USE_CUSTOM_MINIMUM_CAPACITY,
16442                  base::bits::IsPowerOfTwo(at_least_space_for));
16443 
16444   int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
16445                      ? at_least_space_for
16446                      : ComputeCapacity(at_least_space_for);
16447   if (capacity > HashTable::kMaxCapacity) {
16448     isolate->heap()->FatalProcessOutOfMemory("invalid table size");
16449   }
16450   return NewInternal(isolate, capacity, pretenure);
16451 }
16452 
16453 template <typename Derived, typename Shape>
NewInternal(Isolate * isolate,int capacity,PretenureFlag pretenure)16454 Handle<Derived> HashTable<Derived, Shape>::NewInternal(
16455     Isolate* isolate, int capacity, PretenureFlag pretenure) {
16456   Factory* factory = isolate->factory();
16457   int length = EntryToIndex(capacity);
16458   Heap::RootListIndex map_root_index =
16459       static_cast<Heap::RootListIndex>(Shape::GetMapRootIndex());
16460   Handle<FixedArray> array =
16461       factory->NewFixedArrayWithMap(map_root_index, length, pretenure);
16462   Handle<Derived> table = Handle<Derived>::cast(array);
16463 
16464   table->SetNumberOfElements(0);
16465   table->SetNumberOfDeletedElements(0);
16466   table->SetCapacity(capacity);
16467   return table;
16468 }
16469 
16470 template <typename Derived, typename Shape>
Rehash(Derived * new_table)16471 void HashTable<Derived, Shape>::Rehash(Derived* new_table) {
16472   DisallowHeapAllocation no_gc;
16473   WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
16474 
16475   DCHECK_LT(NumberOfElements(), new_table->Capacity());
16476 
16477   // Copy prefix to new array.
16478   for (int i = kPrefixStartIndex; i < kElementsStartIndex; i++) {
16479     new_table->set(i, get(i), mode);
16480   }
16481 
16482   // Rehash the elements.
16483   int capacity = this->Capacity();
16484   Isolate* isolate = new_table->GetIsolate();
16485   for (int i = 0; i < capacity; i++) {
16486     uint32_t from_index = EntryToIndex(i);
16487     Object* k = this->get(from_index);
16488     if (!Shape::IsLive(isolate, k)) continue;
16489     uint32_t hash = Shape::HashForObject(isolate, k);
16490     uint32_t insertion_index =
16491         EntryToIndex(new_table->FindInsertionEntry(hash));
16492     for (int j = 0; j < Shape::kEntrySize; j++) {
16493       new_table->set(insertion_index + j, get(from_index + j), mode);
16494     }
16495   }
16496   new_table->SetNumberOfElements(NumberOfElements());
16497   new_table->SetNumberOfDeletedElements(0);
16498 }
16499 
16500 template <typename Derived, typename Shape>
EntryForProbe(Object * k,int probe,uint32_t expected)16501 uint32_t HashTable<Derived, Shape>::EntryForProbe(Object* k, int probe,
16502                                                   uint32_t expected) {
16503   uint32_t hash = Shape::HashForObject(GetIsolate(), k);
16504   uint32_t capacity = this->Capacity();
16505   uint32_t entry = FirstProbe(hash, capacity);
16506   for (int i = 1; i < probe; i++) {
16507     if (entry == expected) return expected;
16508     entry = NextProbe(entry, i, capacity);
16509   }
16510   return entry;
16511 }
16512 
16513 template <typename Derived, typename Shape>
Swap(uint32_t entry1,uint32_t entry2,WriteBarrierMode mode)16514 void HashTable<Derived, Shape>::Swap(uint32_t entry1, uint32_t entry2,
16515                                      WriteBarrierMode mode) {
16516   int index1 = EntryToIndex(entry1);
16517   int index2 = EntryToIndex(entry2);
16518   Object* temp[Shape::kEntrySize];
16519   for (int j = 0; j < Shape::kEntrySize; j++) {
16520     temp[j] = get(index1 + j);
16521   }
16522   for (int j = 0; j < Shape::kEntrySize; j++) {
16523     set(index1 + j, get(index2 + j), mode);
16524   }
16525   for (int j = 0; j < Shape::kEntrySize; j++) {
16526     set(index2 + j, temp[j], mode);
16527   }
16528 }
16529 
16530 template <typename Derived, typename Shape>
Rehash()16531 void HashTable<Derived, Shape>::Rehash() {
16532   DisallowHeapAllocation no_gc;
16533   WriteBarrierMode mode = GetWriteBarrierMode(no_gc);
16534   Isolate* isolate = GetIsolate();
16535   uint32_t capacity = Capacity();
16536   bool done = false;
16537   for (int probe = 1; !done; probe++) {
16538     // All elements at entries given by one of the first _probe_ probes
16539     // are placed correctly. Other elements might need to be moved.
16540     done = true;
16541     for (uint32_t current = 0; current < capacity; current++) {
16542       Object* current_key = KeyAt(current);
16543       if (!Shape::IsLive(isolate, current_key)) continue;
16544       uint32_t target = EntryForProbe(current_key, probe, current);
16545       if (current == target) continue;
16546       Object* target_key = KeyAt(target);
16547       if (!Shape::IsLive(isolate, target_key) ||
16548           EntryForProbe(target_key, probe, target) != target) {
16549         // Put the current element into the correct position.
16550         Swap(current, target, mode);
16551         // The other element will be processed on the next iteration.
16552         current--;
16553       } else {
16554         // The place for the current element is occupied. Leave the element
16555         // for the next probe.
16556         done = false;
16557       }
16558     }
16559   }
16560   // Wipe deleted entries.
16561   Object* the_hole = isolate->heap()->the_hole_value();
16562   Object* undefined = isolate->heap()->undefined_value();
16563   for (uint32_t current = 0; current < capacity; current++) {
16564     if (KeyAt(current) == the_hole) {
16565       set(EntryToIndex(current) + kEntryKeyIndex, undefined);
16566     }
16567   }
16568   SetNumberOfDeletedElements(0);
16569 }
16570 
16571 template <typename Derived, typename Shape>
EnsureCapacity(Handle<Derived> table,int n,PretenureFlag pretenure)16572 Handle<Derived> HashTable<Derived, Shape>::EnsureCapacity(
16573     Handle<Derived> table, int n, PretenureFlag pretenure) {
16574   if (table->HasSufficientCapacityToAdd(n)) return table;
16575 
16576   Isolate* isolate = table->GetIsolate();
16577   int capacity = table->Capacity();
16578   int new_nof = table->NumberOfElements() + n;
16579 
16580   const int kMinCapacityForPretenure = 256;
16581   bool should_pretenure = pretenure == TENURED ||
16582       ((capacity > kMinCapacityForPretenure) &&
16583           !isolate->heap()->InNewSpace(*table));
16584   Handle<Derived> new_table = HashTable::New(
16585       isolate, new_nof, should_pretenure ? TENURED : NOT_TENURED);
16586 
16587   table->Rehash(*new_table);
16588   return new_table;
16589 }
16590 
16591 template bool
16592 HashTable<NameDictionary, NameDictionaryShape>::HasSufficientCapacityToAdd(int);
16593 
16594 template <typename Derived, typename Shape>
HasSufficientCapacityToAdd(int number_of_additional_elements)16595 bool HashTable<Derived, Shape>::HasSufficientCapacityToAdd(
16596     int number_of_additional_elements) {
16597   int capacity = Capacity();
16598   int nof = NumberOfElements() + number_of_additional_elements;
16599   int nod = NumberOfDeletedElements();
16600   // Return true if:
16601   //   50% is still free after adding number_of_additional_elements elements and
16602   //   at most 50% of the free elements are deleted elements.
16603   if ((nof < capacity) && ((nod <= (capacity - nof) >> 1))) {
16604     int needed_free = nof >> 1;
16605     if (nof + needed_free <= capacity) return true;
16606   }
16607   return false;
16608 }
16609 
16610 template <typename Derived, typename Shape>
Shrink(Handle<Derived> table,int additionalCapacity)16611 Handle<Derived> HashTable<Derived, Shape>::Shrink(Handle<Derived> table,
16612                                                   int additionalCapacity) {
16613   int capacity = table->Capacity();
16614   int nof = table->NumberOfElements();
16615 
16616   // Shrink to fit the number of elements if only a quarter of the
16617   // capacity is filled with elements.
16618   if (nof > (capacity >> 2)) return table;
16619   // Allocate a new dictionary with room for at least the current number of
16620   // elements + {additionalCapacity}. The allocation method will make sure that
16621   // there is extra room in the dictionary for additions. Don't go lower than
16622   // room for {kMinShrinkCapacity} elements.
16623   int at_least_room_for = nof + additionalCapacity;
16624   int new_capacity = ComputeCapacity(at_least_room_for);
16625   if (new_capacity < Derived::kMinShrinkCapacity) return table;
16626   if (new_capacity == capacity) return table;
16627 
16628   Isolate* isolate = table->GetIsolate();
16629   const int kMinCapacityForPretenure = 256;
16630   bool pretenure = (at_least_room_for > kMinCapacityForPretenure) &&
16631                    !isolate->heap()->InNewSpace(*table);
16632   Handle<Derived> new_table =
16633       HashTable::New(isolate, new_capacity, pretenure ? TENURED : NOT_TENURED,
16634                      USE_CUSTOM_MINIMUM_CAPACITY);
16635 
16636   table->Rehash(*new_table);
16637   return new_table;
16638 }
16639 
16640 template <typename Derived, typename Shape>
FindInsertionEntry(uint32_t hash)16641 uint32_t HashTable<Derived, Shape>::FindInsertionEntry(uint32_t hash) {
16642   uint32_t capacity = Capacity();
16643   uint32_t entry = FirstProbe(hash, capacity);
16644   uint32_t count = 1;
16645   // EnsureCapacity will guarantee the hash table is never full.
16646   Isolate* isolate = GetIsolate();
16647   while (true) {
16648     if (!Shape::IsLive(isolate, KeyAt(entry))) break;
16649     entry = NextProbe(entry, count++, capacity);
16650   }
16651   return entry;
16652 }
16653 
16654 
16655 // Force instantiation of template instances class.
16656 // Please note this list is compiler dependent.
16657 
16658 template class HashTable<StringTable, StringTableShape>;
16659 
16660 template class HashTable<CompilationCacheTable, CompilationCacheShape>;
16661 
16662 template class HashTable<ObjectHashTable, ObjectHashTableShape>;
16663 
16664 template class Dictionary<NameDictionary, NameDictionaryShape>;
16665 
16666 template class Dictionary<GlobalDictionary, GlobalDictionaryShape>;
16667 
16668 template class EXPORT_TEMPLATE_DEFINE(
16669     V8_EXPORT_PRIVATE) HashTable<NumberDictionary, NumberDictionaryShape>;
16670 
16671 template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
16672     Dictionary<NumberDictionary, NumberDictionaryShape>;
16673 
16674 template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
16675     HashTable<SimpleNumberDictionary, SimpleNumberDictionaryShape>;
16676 
16677 template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
16678     Dictionary<SimpleNumberDictionary, SimpleNumberDictionaryShape>;
16679 
16680 template Handle<NameDictionary>
16681 BaseNameDictionary<NameDictionary, NameDictionaryShape>::New(
16682     Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
16683 
16684 template Handle<GlobalDictionary>
16685 BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::New(
16686     Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
16687 
16688 template Handle<NumberDictionary>
16689     Dictionary<NumberDictionary, NumberDictionaryShape>::AtPut(
16690         Handle<NumberDictionary>, uint32_t, Handle<Object>, PropertyDetails);
16691 
16692 template Handle<SimpleNumberDictionary>
16693     Dictionary<SimpleNumberDictionary, SimpleNumberDictionaryShape>::AtPut(
16694         Handle<SimpleNumberDictionary>, uint32_t, Handle<Object>,
16695         PropertyDetails);
16696 
16697 template Object* Dictionary<
16698     NumberDictionary, NumberDictionaryShape>::SlowReverseLookup(Object* value);
16699 
16700 template Object* Dictionary<
16701     NameDictionary, NameDictionaryShape>::SlowReverseLookup(Object* value);
16702 
16703 template Handle<NameDictionary>
16704 Dictionary<NameDictionary, NameDictionaryShape>::DeleteEntry(
16705     Handle<NameDictionary>, int);
16706 
16707 template Handle<NumberDictionary>
16708 Dictionary<NumberDictionary, NumberDictionaryShape>::DeleteEntry(
16709     Handle<NumberDictionary>, int);
16710 
16711 template Handle<SimpleNumberDictionary>
16712 Dictionary<SimpleNumberDictionary, SimpleNumberDictionaryShape>::DeleteEntry(
16713     Handle<SimpleNumberDictionary>, int);
16714 
16715 template Handle<NameDictionary>
16716 HashTable<NameDictionary, NameDictionaryShape>::New(Isolate*, int,
16717                                                     PretenureFlag,
16718                                                     MinimumCapacity);
16719 
16720 template Handle<ObjectHashSet>
16721 HashTable<ObjectHashSet, ObjectHashSetShape>::New(Isolate*, int n,
16722                                                   PretenureFlag,
16723                                                   MinimumCapacity);
16724 
16725 template Handle<NameDictionary>
16726 HashTable<NameDictionary, NameDictionaryShape>::Shrink(Handle<NameDictionary>,
16727                                                        int additionalCapacity);
16728 
16729 template Handle<NameDictionary>
16730 BaseNameDictionary<NameDictionary, NameDictionaryShape>::Add(
16731     Handle<NameDictionary>, Handle<Name>, Handle<Object>, PropertyDetails,
16732     int*);
16733 
16734 template Handle<GlobalDictionary>
16735 BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::Add(
16736     Handle<GlobalDictionary>, Handle<Name>, Handle<Object>, PropertyDetails,
16737     int*);
16738 
16739 template void HashTable<GlobalDictionary, GlobalDictionaryShape>::Rehash();
16740 
16741 template Handle<NumberDictionary>
16742 Dictionary<NumberDictionary, NumberDictionaryShape>::Add(
16743     Handle<NumberDictionary>, uint32_t, Handle<Object>, PropertyDetails, int*);
16744 
16745 template Handle<NameDictionary>
16746 BaseNameDictionary<NameDictionary, NameDictionaryShape>::EnsureCapacity(
16747     Handle<NameDictionary>, int);
16748 
16749 template Handle<SimpleNumberDictionary>
16750 Dictionary<SimpleNumberDictionary, SimpleNumberDictionaryShape>::Add(
16751     Handle<SimpleNumberDictionary>, uint32_t, Handle<Object>, PropertyDetails,
16752     int*);
16753 
16754 template int Dictionary<GlobalDictionary,
16755                         GlobalDictionaryShape>::NumberOfEnumerableProperties();
16756 
16757 template int
16758 Dictionary<NameDictionary, NameDictionaryShape>::NumberOfEnumerableProperties();
16759 
16760 template void
16761 BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::CopyEnumKeysTo(
16762     Handle<GlobalDictionary> dictionary, Handle<FixedArray> storage,
16763     KeyCollectionMode mode, KeyAccumulator* accumulator);
16764 
16765 template void
16766 BaseNameDictionary<NameDictionary, NameDictionaryShape>::CopyEnumKeysTo(
16767     Handle<NameDictionary> dictionary, Handle<FixedArray> storage,
16768     KeyCollectionMode mode, KeyAccumulator* accumulator);
16769 
16770 template Handle<FixedArray>
16771 BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::IterationIndices(
16772     Handle<GlobalDictionary> dictionary);
16773 template void
16774 BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::CollectKeysTo(
16775     Handle<GlobalDictionary> dictionary, KeyAccumulator* keys);
16776 
16777 template Handle<FixedArray>
16778 BaseNameDictionary<NameDictionary, NameDictionaryShape>::IterationIndices(
16779     Handle<NameDictionary> dictionary);
16780 template void
16781 BaseNameDictionary<NameDictionary, NameDictionaryShape>::CollectKeysTo(
16782     Handle<NameDictionary> dictionary, KeyAccumulator* keys);
16783 
16784 template int Dictionary<NumberDictionary,
16785                         NumberDictionaryShape>::NumberOfEnumerableProperties();
16786 
16787 namespace {
16788 
CanonicalNumericIndexString(Isolate * isolate,Handle<Object> s,Handle<Object> * index)16789 bool CanonicalNumericIndexString(Isolate* isolate, Handle<Object> s,
16790                                  Handle<Object>* index) {
16791   DCHECK(s->IsString() || s->IsSmi());
16792 
16793   Handle<Object> result;
16794   if (s->IsSmi()) {
16795     result = s;
16796   } else {
16797     result = String::ToNumber(Handle<String>::cast(s));
16798     if (!result->IsMinusZero()) {
16799       Handle<String> str = Object::ToString(isolate, result).ToHandleChecked();
16800       // Avoid treating strings like "2E1" and "20" as the same key.
16801       if (!str->SameValue(*s)) return false;
16802     }
16803   }
16804   *index = result;
16805   return true;
16806 }
16807 
16808 }  // anonymous namespace
16809 
16810 // ES#sec-integer-indexed-exotic-objects-defineownproperty-p-desc
16811 // static
DefineOwnProperty(Isolate * isolate,Handle<JSTypedArray> o,Handle<Object> key,PropertyDescriptor * desc,ShouldThrow should_throw)16812 Maybe<bool> JSTypedArray::DefineOwnProperty(Isolate* isolate,
16813                                             Handle<JSTypedArray> o,
16814                                             Handle<Object> key,
16815                                             PropertyDescriptor* desc,
16816                                             ShouldThrow should_throw) {
16817   // 1. Assert: IsPropertyKey(P) is true.
16818   DCHECK(key->IsName() || key->IsNumber());
16819   // 2. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot.
16820   // 3. If Type(P) is String, then
16821   if (key->IsString() || key->IsSmi()) {
16822     // 3a. Let numericIndex be ! CanonicalNumericIndexString(P)
16823     // 3b. If numericIndex is not undefined, then
16824     Handle<Object> numeric_index;
16825     if (CanonicalNumericIndexString(isolate, key, &numeric_index)) {
16826       // 3b i. If IsInteger(numericIndex) is false, return false.
16827       // 3b ii. If numericIndex = -0, return false.
16828       // 3b iii. If numericIndex < 0, return false.
16829       // FIXME: the standard allows up to 2^53 elements.
16830       uint32_t index;
16831       if (numeric_index->IsMinusZero() || !numeric_index->ToUint32(&index)) {
16832         RETURN_FAILURE(isolate, should_throw,
16833                        NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
16834       }
16835       // 3b iv. Let length be O.[[ArrayLength]].
16836       uint32_t length = o->length()->Number();
16837       // 3b v. If numericIndex ≥ length, return false.
16838       if (index >= length) {
16839         RETURN_FAILURE(isolate, should_throw,
16840                        NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
16841       }
16842       // 3b vi. If IsAccessorDescriptor(Desc) is true, return false.
16843       if (PropertyDescriptor::IsAccessorDescriptor(desc)) {
16844         RETURN_FAILURE(isolate, should_throw,
16845                        NewTypeError(MessageTemplate::kRedefineDisallowed, key));
16846       }
16847       // 3b vii. If Desc has a [[Configurable]] field and if
16848       //         Desc.[[Configurable]] is true, return false.
16849       // 3b viii. If Desc has an [[Enumerable]] field and if Desc.[[Enumerable]]
16850       //          is false, return false.
16851       // 3b ix. If Desc has a [[Writable]] field and if Desc.[[Writable]] is
16852       //        false, return false.
16853       if ((desc->has_configurable() && desc->configurable()) ||
16854           (desc->has_enumerable() && !desc->enumerable()) ||
16855           (desc->has_writable() && !desc->writable())) {
16856         RETURN_FAILURE(isolate, should_throw,
16857                        NewTypeError(MessageTemplate::kRedefineDisallowed, key));
16858       }
16859       // 3b x. If Desc has a [[Value]] field, then
16860       //   3b x 1. Let value be Desc.[[Value]].
16861       //   3b x 2. Return ? IntegerIndexedElementSet(O, numericIndex, value).
16862       if (desc->has_value()) {
16863         if (!desc->has_configurable()) desc->set_configurable(false);
16864         if (!desc->has_enumerable()) desc->set_enumerable(true);
16865         if (!desc->has_writable()) desc->set_writable(true);
16866         Handle<Object> value = desc->value();
16867         RETURN_ON_EXCEPTION_VALUE(isolate,
16868                                   SetOwnElementIgnoreAttributes(
16869                                       o, index, value, desc->ToAttributes()),
16870                                   Nothing<bool>());
16871       }
16872       // 3b xi. Return true.
16873       return Just(true);
16874     }
16875   }
16876   // 4. Return ! OrdinaryDefineOwnProperty(O, P, Desc).
16877   return OrdinaryDefineOwnProperty(isolate, o, key, desc, should_throw);
16878 }
16879 
type()16880 ExternalArrayType JSTypedArray::type() {
16881   switch (elements()->map()->instance_type()) {
16882 #define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype, size)            \
16883     case FIXED_##TYPE##_ARRAY_TYPE:                                           \
16884       return kExternal##Type##Array;
16885 
16886     TYPED_ARRAYS(INSTANCE_TYPE_TO_ARRAY_TYPE)
16887 #undef INSTANCE_TYPE_TO_ARRAY_TYPE
16888 
16889     default:
16890       UNREACHABLE();
16891   }
16892 }
16893 
16894 
element_size()16895 size_t JSTypedArray::element_size() {
16896   switch (elements()->map()->instance_type()) {
16897 #define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype, size) \
16898   case FIXED_##TYPE##_ARRAY_TYPE:                                    \
16899     return size;
16900 
16901     TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE)
16902 #undef INSTANCE_TYPE_TO_ELEMENT_SIZE
16903 
16904     default:
16905       UNREACHABLE();
16906   }
16907 }
16908 
InvalidatePropertyCell(Handle<JSGlobalObject> global,Handle<Name> name)16909 void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global,
16910                                             Handle<Name> name) {
16911   // Regardless of whether the property is there or not invalidate
16912   // Load/StoreGlobalICs that load/store through global object's prototype.
16913   JSObject::InvalidatePrototypeValidityCell(*global);
16914 
16915   DCHECK(!global->HasFastProperties());
16916   auto dictionary = handle(global->global_dictionary());
16917   int entry = dictionary->FindEntry(name);
16918   if (entry == GlobalDictionary::kNotFound) return;
16919   PropertyCell::InvalidateEntry(dictionary, entry);
16920 }
16921 
EnsureEmptyPropertyCell(Handle<JSGlobalObject> global,Handle<Name> name,PropertyCellType cell_type,int * entry_out)16922 Handle<PropertyCell> JSGlobalObject::EnsureEmptyPropertyCell(
16923     Handle<JSGlobalObject> global, Handle<Name> name,
16924     PropertyCellType cell_type, int* entry_out) {
16925   Isolate* isolate = global->GetIsolate();
16926   DCHECK(!global->HasFastProperties());
16927   Handle<GlobalDictionary> dictionary(global->global_dictionary(), isolate);
16928   int entry = dictionary->FindEntry(name);
16929   Handle<PropertyCell> cell;
16930   if (entry != GlobalDictionary::kNotFound) {
16931     if (entry_out) *entry_out = entry;
16932     cell = handle(dictionary->CellAt(entry));
16933     PropertyCellType original_cell_type = cell->property_details().cell_type();
16934     DCHECK(original_cell_type == PropertyCellType::kInvalidated ||
16935            original_cell_type == PropertyCellType::kUninitialized);
16936     DCHECK(cell->value()->IsTheHole(isolate));
16937     if (original_cell_type == PropertyCellType::kInvalidated) {
16938       cell = PropertyCell::InvalidateEntry(dictionary, entry);
16939     }
16940     PropertyDetails details(kData, NONE, cell_type);
16941     cell->set_property_details(details);
16942     return cell;
16943   }
16944   cell = isolate->factory()->NewPropertyCell(name);
16945   PropertyDetails details(kData, NONE, cell_type);
16946   dictionary =
16947       GlobalDictionary::Add(dictionary, name, cell, details, entry_out);
16948   // {*entry_out} is initialized inside GlobalDictionary::Add().
16949   global->SetProperties(*dictionary);
16950   return cell;
16951 }
16952 
16953 
16954 // This class is used for looking up two character strings in the string table.
16955 // If we don't have a hit we don't want to waste much time so we unroll the
16956 // string hash calculation loop here for speed.  Doesn't work if the two
16957 // characters form a decimal integer, since such strings have a different hash
16958 // algorithm.
16959 class TwoCharHashTableKey : public StringTableKey {
16960  public:
TwoCharHashTableKey(uint16_t c1,uint16_t c2,uint64_t seed)16961   TwoCharHashTableKey(uint16_t c1, uint16_t c2, uint64_t seed)
16962       : StringTableKey(ComputeHashField(c1, c2, seed)), c1_(c1), c2_(c2) {}
16963 
IsMatch(Object * o)16964   bool IsMatch(Object* o) override {
16965     String* other = String::cast(o);
16966     if (other->length() != 2) return false;
16967     if (other->Get(0) != c1_) return false;
16968     return other->Get(1) == c2_;
16969   }
16970 
AsHandle(Isolate * isolate)16971   Handle<String> AsHandle(Isolate* isolate) override {
16972     // The TwoCharHashTableKey is only used for looking in the string
16973     // table, not for adding to it.
16974     UNREACHABLE();
16975   }
16976 
16977  private:
ComputeHashField(uint16_t c1,uint16_t c2,uint64_t seed)16978   uint32_t ComputeHashField(uint16_t c1, uint16_t c2, uint64_t seed) {
16979     // Char 1.
16980     uint32_t hash = static_cast<uint32_t>(seed);
16981     hash += c1;
16982     hash += hash << 10;
16983     hash ^= hash >> 6;
16984     // Char 2.
16985     hash += c2;
16986     hash += hash << 10;
16987     hash ^= hash >> 6;
16988     // GetHash.
16989     hash += hash << 3;
16990     hash ^= hash >> 11;
16991     hash += hash << 15;
16992     if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash;
16993     hash = (hash << String::kHashShift) | String::kIsNotArrayIndexMask;
16994 #ifdef DEBUG
16995     // If this assert fails then we failed to reproduce the two-character
16996     // version of the string hashing algorithm above.  One reason could be
16997     // that we were passed two digits as characters, since the hash
16998     // algorithm is different in that case.
16999     uint16_t chars[2] = {c1, c2};
17000     uint32_t check_hash = StringHasher::HashSequentialString(chars, 2, seed);
17001     DCHECK_EQ(hash, check_hash);
17002 #endif
17003     return hash;
17004   }
17005 
17006   uint16_t c1_;
17007   uint16_t c2_;
17008 };
17009 
LookupTwoCharsStringIfExists(Isolate * isolate,uint16_t c1,uint16_t c2)17010 MaybeHandle<String> StringTable::LookupTwoCharsStringIfExists(
17011     Isolate* isolate,
17012     uint16_t c1,
17013     uint16_t c2) {
17014   TwoCharHashTableKey key(c1, c2, isolate->heap()->HashSeed());
17015   Handle<StringTable> string_table = isolate->factory()->string_table();
17016   int entry = string_table->FindEntry(&key);
17017   if (entry == kNotFound) return MaybeHandle<String>();
17018 
17019   Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
17020   DCHECK(StringShape(*result).IsInternalized());
17021   DCHECK_EQ(result->Hash(), key.Hash());
17022   return result;
17023 }
17024 
EnsureCapacityForDeserialization(Isolate * isolate,int expected)17025 void StringTable::EnsureCapacityForDeserialization(Isolate* isolate,
17026                                                    int expected) {
17027   Handle<StringTable> table = isolate->factory()->string_table();
17028   // We need a key instance for the virtual hash function.
17029   table = StringTable::EnsureCapacity(table, expected);
17030   isolate->heap()->SetRootStringTable(*table);
17031 }
17032 
17033 namespace {
17034 
17035 template <class StringClass>
MigrateExternalStringResource(Isolate * isolate,String * from,String * to)17036 void MigrateExternalStringResource(Isolate* isolate, String* from, String* to) {
17037   StringClass* cast_from = StringClass::cast(from);
17038   StringClass* cast_to = StringClass::cast(to);
17039   const typename StringClass::Resource* to_resource = cast_to->resource();
17040   if (to_resource == nullptr) {
17041     // |to| is a just-created internalized copy of |from|. Migrate the resource.
17042     cast_to->set_resource(cast_from->resource());
17043     // Zap |from|'s resource pointer to reflect the fact that |from| has
17044     // relinquished ownership of its resource.
17045     cast_from->set_resource(nullptr);
17046   } else if (to_resource != cast_from->resource()) {
17047     // |to| already existed and has its own resource. Finalize |from|.
17048     isolate->heap()->FinalizeExternalString(from);
17049   }
17050 }
17051 
MakeStringThin(String * string,String * internalized,Isolate * isolate)17052 void MakeStringThin(String* string, String* internalized, Isolate* isolate) {
17053   DCHECK_NE(string, internalized);
17054   DCHECK(internalized->IsInternalizedString());
17055 
17056   if (string->IsExternalString()) {
17057     if (internalized->IsExternalOneByteString()) {
17058       MigrateExternalStringResource<ExternalOneByteString>(isolate, string,
17059                                                            internalized);
17060     } else if (internalized->IsExternalTwoByteString()) {
17061       MigrateExternalStringResource<ExternalTwoByteString>(isolate, string,
17062                                                            internalized);
17063     } else {
17064       // If the external string is duped into an existing non-external
17065       // internalized string, free its resource (it's about to be rewritten
17066       // into a ThinString below).
17067       isolate->heap()->FinalizeExternalString(string);
17068     }
17069   }
17070 
17071   DisallowHeapAllocation no_gc;
17072   int old_size = string->Size();
17073   isolate->heap()->NotifyObjectLayoutChange(string, old_size, no_gc);
17074   bool one_byte = internalized->IsOneByteRepresentation();
17075   Handle<Map> map = one_byte ? isolate->factory()->thin_one_byte_string_map()
17076                              : isolate->factory()->thin_string_map();
17077   DCHECK_GE(old_size, ThinString::kSize);
17078   string->synchronized_set_map(*map);
17079   ThinString* thin = ThinString::cast(string);
17080   thin->set_actual(internalized);
17081   Address thin_end = thin->address() + ThinString::kSize;
17082   int size_delta = old_size - ThinString::kSize;
17083   if (size_delta != 0) {
17084     Heap* heap = isolate->heap();
17085     heap->CreateFillerObjectAt(thin_end, size_delta, ClearRecordedSlots::kNo);
17086   }
17087 }
17088 
17089 }  // namespace
17090 
17091 // static
LookupString(Isolate * isolate,Handle<String> string)17092 Handle<String> StringTable::LookupString(Isolate* isolate,
17093                                          Handle<String> string) {
17094   string = String::Flatten(string);
17095   if (string->IsInternalizedString()) return string;
17096 
17097   InternalizedStringKey key(string);
17098   Handle<String> result = LookupKey(isolate, &key);
17099 
17100   if (FLAG_thin_strings) {
17101     if (!string->IsInternalizedString()) {
17102       MakeStringThin(*string, *result, isolate);
17103     }
17104   } else {  // !FLAG_thin_strings
17105     if (string->IsConsString()) {
17106       Handle<ConsString> cons = Handle<ConsString>::cast(string);
17107       cons->set_first(*result);
17108       cons->set_second(isolate->heap()->empty_string());
17109     } else if (string->IsSlicedString()) {
17110       STATIC_ASSERT(ConsString::kSize == SlicedString::kSize);
17111       DisallowHeapAllocation no_gc;
17112       bool one_byte = result->IsOneByteRepresentation();
17113       Handle<Map> map = one_byte
17114                             ? isolate->factory()->cons_one_byte_string_map()
17115                             : isolate->factory()->cons_string_map();
17116       string->set_map(*map);
17117       Handle<ConsString> cons = Handle<ConsString>::cast(string);
17118       cons->set_first(*result);
17119       cons->set_second(isolate->heap()->empty_string());
17120     }
17121   }
17122   return result;
17123 }
17124 
17125 // static
LookupKey(Isolate * isolate,StringTableKey * key)17126 Handle<String> StringTable::LookupKey(Isolate* isolate, StringTableKey* key) {
17127   Handle<StringTable> table = isolate->factory()->string_table();
17128   int entry = table->FindEntry(key);
17129 
17130   // String already in table.
17131   if (entry != kNotFound) {
17132     return handle(String::cast(table->KeyAt(entry)), isolate);
17133   }
17134 
17135   table = StringTable::CautiousShrink(table);
17136   // Adding new string. Grow table if needed.
17137   table = StringTable::EnsureCapacity(table, 1);
17138   isolate->heap()->SetRootStringTable(*table);
17139 
17140   return AddKeyNoResize(isolate, key);
17141 }
17142 
AddKeyNoResize(Isolate * isolate,StringTableKey * key)17143 Handle<String> StringTable::AddKeyNoResize(Isolate* isolate,
17144                                            StringTableKey* key) {
17145   Handle<StringTable> table = isolate->factory()->string_table();
17146   DCHECK(table->HasSufficientCapacityToAdd(1));
17147   // Create string object.
17148   Handle<String> string = key->AsHandle(isolate);
17149   // There must be no attempts to internalize strings that could throw
17150   // InvalidStringLength error.
17151   CHECK(!string.is_null());
17152   DCHECK(string->HasHashCode());
17153   DCHECK_EQ(table->FindEntry(key), kNotFound);
17154 
17155   // Add the new string and return it along with the string table.
17156   int entry = table->FindInsertionEntry(key->Hash());
17157   table->set(EntryToIndex(entry), *string);
17158   table->ElementAdded();
17159 
17160   return Handle<String>::cast(string);
17161 }
17162 
CautiousShrink(Handle<StringTable> table)17163 Handle<StringTable> StringTable::CautiousShrink(Handle<StringTable> table) {
17164   // Only shrink if the table is very empty to avoid performance penalty.
17165   int capacity = table->Capacity();
17166   int nof = table->NumberOfElements();
17167   if (capacity <= StringTable::kMinCapacity) return table;
17168   if (nof > (capacity / kMaxEmptyFactor)) return table;
17169   // Keep capacity for at least half of the current nof elements.
17170   int slack_capacity = nof >> 2;
17171   return Shrink(table, slack_capacity);
17172 }
17173 
17174 namespace {
17175 
17176 class StringTableNoAllocateKey : public StringTableKey {
17177  public:
StringTableNoAllocateKey(String * string,uint64_t seed)17178   StringTableNoAllocateKey(String* string, uint64_t seed)
17179       : StringTableKey(0), string_(string) {
17180     StringShape shape(string);
17181     one_byte_ = shape.HasOnlyOneByteChars();
17182     DCHECK(!shape.IsInternalized());
17183     DCHECK(!shape.IsThin());
17184     int length = string->length();
17185     if (shape.IsCons() && length <= String::kMaxHashCalcLength) {
17186       special_flattening_ = true;
17187       uint32_t hash_field = 0;
17188       if (one_byte_) {
17189         if (V8_LIKELY(length <=
17190                       static_cast<int>(arraysize(one_byte_buffer_)))) {
17191           one_byte_content_ = one_byte_buffer_;
17192         } else {
17193           one_byte_content_ = new uint8_t[length];
17194         }
17195         String::WriteToFlat(string, one_byte_content_, 0, length);
17196         hash_field =
17197             StringHasher::HashSequentialString(one_byte_content_, length, seed);
17198       } else {
17199         if (V8_LIKELY(length <=
17200                       static_cast<int>(arraysize(two_byte_buffer_)))) {
17201           two_byte_content_ = two_byte_buffer_;
17202         } else {
17203           two_byte_content_ = new uint16_t[length];
17204         }
17205         String::WriteToFlat(string, two_byte_content_, 0, length);
17206         hash_field =
17207             StringHasher::HashSequentialString(two_byte_content_, length, seed);
17208       }
17209       string->set_hash_field(hash_field);
17210     } else {
17211       special_flattening_ = false;
17212       one_byte_content_ = nullptr;
17213       string->Hash();
17214     }
17215 
17216     DCHECK(string->HasHashCode());
17217     set_hash_field(string->hash_field());
17218   }
17219 
~StringTableNoAllocateKey()17220   ~StringTableNoAllocateKey() {
17221     if (one_byte_) {
17222       if (one_byte_content_ != one_byte_buffer_) delete[] one_byte_content_;
17223     } else {
17224       if (two_byte_content_ != two_byte_buffer_) delete[] two_byte_content_;
17225     }
17226   }
17227 
IsMatch(Object * otherstring)17228   bool IsMatch(Object* otherstring) override {
17229     String* other = String::cast(otherstring);
17230     DCHECK(other->IsInternalizedString());
17231     DCHECK(other->IsFlat());
17232     if (Hash() != other->Hash()) return false;
17233     int len = string_->length();
17234     if (len != other->length()) return false;
17235 
17236     if (!special_flattening_) {
17237       if (string_->Get(0) != other->Get(0)) return false;
17238       if (string_->IsFlat()) {
17239         StringShape shape1(string_);
17240         StringShape shape2(other);
17241         if (shape1.encoding_tag() == kOneByteStringTag &&
17242             shape2.encoding_tag() == kOneByteStringTag) {
17243           String::FlatContent flat1 = string_->GetFlatContent();
17244           String::FlatContent flat2 = other->GetFlatContent();
17245           return CompareRawStringContents(flat1.ToOneByteVector().start(),
17246                                           flat2.ToOneByteVector().start(), len);
17247         }
17248         if (shape1.encoding_tag() == kTwoByteStringTag &&
17249             shape2.encoding_tag() == kTwoByteStringTag) {
17250           String::FlatContent flat1 = string_->GetFlatContent();
17251           String::FlatContent flat2 = other->GetFlatContent();
17252           return CompareRawStringContents(flat1.ToUC16Vector().start(),
17253                                           flat2.ToUC16Vector().start(), len);
17254         }
17255       }
17256       StringComparator comparator;
17257       return comparator.Equals(string_, other);
17258     }
17259 
17260     String::FlatContent flat_content = other->GetFlatContent();
17261     if (one_byte_) {
17262       if (flat_content.IsOneByte()) {
17263         return CompareRawStringContents(
17264             one_byte_content_, flat_content.ToOneByteVector().start(), len);
17265       } else {
17266         DCHECK(flat_content.IsTwoByte());
17267         for (int i = 0; i < len; i++) {
17268           if (flat_content.Get(i) != one_byte_content_[i]) return false;
17269         }
17270         return true;
17271       }
17272     } else {
17273       if (flat_content.IsTwoByte()) {
17274         return CompareRawStringContents(
17275             two_byte_content_, flat_content.ToUC16Vector().start(), len);
17276       } else {
17277         DCHECK(flat_content.IsOneByte());
17278         for (int i = 0; i < len; i++) {
17279           if (flat_content.Get(i) != two_byte_content_[i]) return false;
17280         }
17281         return true;
17282       }
17283     }
17284   }
17285 
AsHandle(Isolate * isolate)17286   V8_WARN_UNUSED_RESULT Handle<String> AsHandle(Isolate* isolate) override {
17287     UNREACHABLE();
17288   }
17289 
17290  private:
17291   String* string_;
17292   bool one_byte_;
17293   bool special_flattening_;
17294   union {
17295     uint8_t* one_byte_content_;
17296     uint16_t* two_byte_content_;
17297   };
17298   union {
17299     uint8_t one_byte_buffer_[256];
17300     uint16_t two_byte_buffer_[128];
17301   };
17302 };
17303 
17304 }  // namespace
17305 
17306 // static
LookupStringIfExists_NoAllocate(String * string)17307 Object* StringTable::LookupStringIfExists_NoAllocate(String* string) {
17308   DisallowHeapAllocation no_gc;
17309   Heap* heap = string->GetHeap();
17310   Isolate* isolate = heap->isolate();
17311   StringTable* table = heap->string_table();
17312 
17313   StringTableNoAllocateKey key(string, heap->HashSeed());
17314 
17315   // String could be an array index.
17316   uint32_t hash = string->hash_field();
17317 
17318   // Valid array indices are >= 0, so they cannot be mixed up with any of
17319   // the result sentinels, which are negative.
17320   STATIC_ASSERT(
17321       !String::ArrayIndexValueBits::is_valid(ResultSentinel::kUnsupported));
17322   STATIC_ASSERT(
17323       !String::ArrayIndexValueBits::is_valid(ResultSentinel::kNotFound));
17324 
17325   if (Name::ContainsCachedArrayIndex(hash)) {
17326     return Smi::FromInt(String::ArrayIndexValueBits::decode(hash));
17327   }
17328   if ((hash & Name::kIsNotArrayIndexMask) == 0) {
17329     // It is an indexed, but it's not cached.
17330     return Smi::FromInt(ResultSentinel::kUnsupported);
17331   }
17332 
17333   DCHECK(!string->IsInternalizedString());
17334   int entry = table->FindEntry(isolate, &key, key.Hash());
17335   if (entry != kNotFound) {
17336     String* internalized = String::cast(table->KeyAt(entry));
17337     if (FLAG_thin_strings) {
17338       MakeStringThin(string, internalized, isolate);
17339     }
17340     return internalized;
17341   }
17342   // A string that's not an array index, and not in the string table,
17343   // cannot have been used as a property name before.
17344   return Smi::FromInt(ResultSentinel::kNotFound);
17345 }
17346 
ForwardStringIfExists(Isolate * isolate,StringTableKey * key,String * string)17347 String* StringTable::ForwardStringIfExists(Isolate* isolate,
17348                                            StringTableKey* key,
17349                                            String* string) {
17350   Handle<StringTable> table = isolate->factory()->string_table();
17351   int entry = table->FindEntry(isolate, key);
17352   if (entry == kNotFound) return nullptr;
17353 
17354   String* canonical = String::cast(table->KeyAt(entry));
17355   if (canonical != string) MakeStringThin(string, canonical, isolate);
17356   return canonical;
17357 }
17358 
New(Isolate * isolate)17359 Handle<StringSet> StringSet::New(Isolate* isolate) {
17360   return HashTable::New(isolate, 0);
17361 }
17362 
Add(Handle<StringSet> stringset,Handle<String> name)17363 Handle<StringSet> StringSet::Add(Handle<StringSet> stringset,
17364                                  Handle<String> name) {
17365   if (!stringset->Has(name)) {
17366     stringset = EnsureCapacity(stringset, 1);
17367     uint32_t hash = ShapeT::Hash(name->GetIsolate(), *name);
17368     int entry = stringset->FindInsertionEntry(hash);
17369     stringset->set(EntryToIndex(entry), *name);
17370     stringset->ElementAdded();
17371   }
17372   return stringset;
17373 }
17374 
Has(Handle<String> name)17375 bool StringSet::Has(Handle<String> name) {
17376   return FindEntry(*name) != kNotFound;
17377 }
17378 
Add(Handle<ObjectHashSet> set,Handle<Object> key)17379 Handle<ObjectHashSet> ObjectHashSet::Add(Handle<ObjectHashSet> set,
17380                                          Handle<Object> key) {
17381   Isolate* isolate = set->GetIsolate();
17382   int32_t hash = key->GetOrCreateHash(isolate)->value();
17383   if (!set->Has(isolate, key, hash)) {
17384     set = EnsureCapacity(set, 1);
17385     int entry = set->FindInsertionEntry(hash);
17386     set->set(EntryToIndex(entry), *key);
17387     set->ElementAdded();
17388   }
17389   return set;
17390 }
17391 
Lookup(Handle<String> src,Handle<SharedFunctionInfo> shared,LanguageMode language_mode)17392 Handle<Object> CompilationCacheTable::Lookup(Handle<String> src,
17393                                              Handle<SharedFunctionInfo> shared,
17394                                              LanguageMode language_mode) {
17395   Isolate* isolate = GetIsolate();
17396   StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17397   int entry = FindEntry(&key);
17398   if (entry == kNotFound) return isolate->factory()->undefined_value();
17399   int index = EntryToIndex(entry);
17400   if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value();
17401   return Handle<Object>(get(index + 1), isolate);
17402 }
17403 
17404 namespace {
17405 
17406 const int kLiteralEntryLength = 2;
17407 const int kLiteralInitialLength = 2;
17408 const int kLiteralContextOffset = 0;
17409 const int kLiteralLiteralsOffset = 1;
17410 
SearchLiteralsMapEntry(CompilationCacheTable * cache,int cache_entry,Context * native_context)17411 int SearchLiteralsMapEntry(CompilationCacheTable* cache, int cache_entry,
17412                            Context* native_context) {
17413   DisallowHeapAllocation no_gc;
17414   DCHECK(native_context->IsNativeContext());
17415   Object* obj = cache->get(cache_entry);
17416 
17417   if (obj->IsFixedArray()) {
17418     FixedArray* literals_map = FixedArray::cast(obj);
17419     int length = literals_map->length();
17420     for (int i = 0; i < length; i += kLiteralEntryLength) {
17421       if (WeakCell::cast(literals_map->get(i + kLiteralContextOffset))
17422               ->value() == native_context) {
17423         return i;
17424       }
17425     }
17426   }
17427   return -1;
17428 }
17429 
AddToFeedbackCellsMap(Handle<CompilationCacheTable> cache,int cache_entry,Handle<Context> native_context,Handle<FeedbackCell> feedback_cell)17430 void AddToFeedbackCellsMap(Handle<CompilationCacheTable> cache, int cache_entry,
17431                            Handle<Context> native_context,
17432                            Handle<FeedbackCell> feedback_cell) {
17433   Isolate* isolate = native_context->GetIsolate();
17434   DCHECK(native_context->IsNativeContext());
17435   STATIC_ASSERT(kLiteralEntryLength == 2);
17436   Handle<FixedArray> new_literals_map;
17437   int entry;
17438 
17439   Object* obj = cache->get(cache_entry);
17440 
17441   if (!obj->IsFixedArray() || FixedArray::cast(obj)->length() == 0) {
17442     new_literals_map =
17443         isolate->factory()->NewFixedArray(kLiteralInitialLength, TENURED);
17444     entry = 0;
17445   } else {
17446     Handle<FixedArray> old_literals_map(FixedArray::cast(obj), isolate);
17447     entry = SearchLiteralsMapEntry(*cache, cache_entry, *native_context);
17448     if (entry >= 0) {
17449       // Just set the code of the entry.
17450       Handle<WeakCell> literals_cell =
17451           isolate->factory()->NewWeakCell(feedback_cell);
17452       old_literals_map->set(entry + kLiteralLiteralsOffset, *literals_cell);
17453       return;
17454     }
17455 
17456     // Can we reuse an entry?
17457     DCHECK_LT(entry, 0);
17458     int length = old_literals_map->length();
17459     for (int i = 0; i < length; i += kLiteralEntryLength) {
17460       if (WeakCell::cast(old_literals_map->get(i + kLiteralContextOffset))
17461               ->cleared()) {
17462         new_literals_map = old_literals_map;
17463         entry = i;
17464         break;
17465       }
17466     }
17467 
17468     if (entry < 0) {
17469       // Copy old optimized code map and append one new entry.
17470       new_literals_map = isolate->factory()->CopyFixedArrayAndGrow(
17471           old_literals_map, kLiteralEntryLength, TENURED);
17472       entry = old_literals_map->length();
17473     }
17474   }
17475 
17476   Handle<WeakCell> literals_cell =
17477       isolate->factory()->NewWeakCell(feedback_cell);
17478   WeakCell* context_cell = native_context->self_weak_cell();
17479 
17480   new_literals_map->set(entry + kLiteralContextOffset, context_cell);
17481   new_literals_map->set(entry + kLiteralLiteralsOffset, *literals_cell);
17482 
17483 #ifdef DEBUG
17484   for (int i = 0; i < new_literals_map->length(); i += kLiteralEntryLength) {
17485     WeakCell* cell =
17486         WeakCell::cast(new_literals_map->get(i + kLiteralContextOffset));
17487     DCHECK(cell->cleared() || cell->value()->IsNativeContext());
17488     cell = WeakCell::cast(new_literals_map->get(i + kLiteralLiteralsOffset));
17489     DCHECK(cell->cleared() || (cell->value()->IsFeedbackCell()));
17490   }
17491 #endif
17492 
17493   Object* old_literals_map = cache->get(cache_entry);
17494   if (old_literals_map != *new_literals_map) {
17495     cache->set(cache_entry, *new_literals_map);
17496   }
17497 }
17498 
SearchLiteralsMap(CompilationCacheTable * cache,int cache_entry,Context * native_context)17499 FeedbackCell* SearchLiteralsMap(CompilationCacheTable* cache, int cache_entry,
17500                                 Context* native_context) {
17501   FeedbackCell* result = nullptr;
17502   int entry = SearchLiteralsMapEntry(cache, cache_entry, native_context);
17503   if (entry >= 0) {
17504     FixedArray* literals_map = FixedArray::cast(cache->get(cache_entry));
17505     DCHECK_LE(entry + kLiteralEntryLength, literals_map->length());
17506     WeakCell* cell =
17507         WeakCell::cast(literals_map->get(entry + kLiteralLiteralsOffset));
17508 
17509     result = cell->cleared() ? nullptr : FeedbackCell::cast(cell->value());
17510   }
17511   DCHECK(result == nullptr || result->IsFeedbackCell());
17512   return result;
17513 }
17514 
17515 }  // namespace
17516 
LookupScript(Handle<String> src,Handle<Context> native_context,LanguageMode language_mode)17517 MaybeHandle<SharedFunctionInfo> CompilationCacheTable::LookupScript(
17518     Handle<String> src, Handle<Context> native_context,
17519     LanguageMode language_mode) {
17520   Handle<SharedFunctionInfo> shared(native_context->empty_function()->shared());
17521   StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17522   int entry = FindEntry(&key);
17523   if (entry == kNotFound) return MaybeHandle<SharedFunctionInfo>();
17524   int index = EntryToIndex(entry);
17525   if (!get(index)->IsFixedArray()) return MaybeHandle<SharedFunctionInfo>();
17526   Object* obj = get(index + 1);
17527   if (obj->IsSharedFunctionInfo()) {
17528     return handle(SharedFunctionInfo::cast(obj));
17529   }
17530   return MaybeHandle<SharedFunctionInfo>();
17531 }
17532 
LookupEval(Handle<String> src,Handle<SharedFunctionInfo> outer_info,Handle<Context> native_context,LanguageMode language_mode,int position)17533 InfoCellPair CompilationCacheTable::LookupEval(
17534     Handle<String> src, Handle<SharedFunctionInfo> outer_info,
17535     Handle<Context> native_context, LanguageMode language_mode, int position) {
17536   InfoCellPair empty_result;
17537   StringSharedKey key(src, outer_info, language_mode, position);
17538   int entry = FindEntry(&key);
17539   if (entry == kNotFound) return empty_result;
17540   int index = EntryToIndex(entry);
17541   if (!get(index)->IsFixedArray()) return empty_result;
17542   Object* obj = get(EntryToIndex(entry) + 1);
17543   if (obj->IsSharedFunctionInfo()) {
17544     FeedbackCell* feedback_cell =
17545         SearchLiteralsMap(this, EntryToIndex(entry) + 2, *native_context);
17546     return InfoCellPair(SharedFunctionInfo::cast(obj), feedback_cell);
17547   }
17548   return empty_result;
17549 }
17550 
LookupRegExp(Handle<String> src,JSRegExp::Flags flags)17551 Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src,
17552                                                    JSRegExp::Flags flags) {
17553   Isolate* isolate = GetIsolate();
17554   DisallowHeapAllocation no_allocation;
17555   RegExpKey key(src, flags);
17556   int entry = FindEntry(&key);
17557   if (entry == kNotFound) return isolate->factory()->undefined_value();
17558   return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
17559 }
17560 
Put(Handle<CompilationCacheTable> cache,Handle<String> src,Handle<SharedFunctionInfo> shared,LanguageMode language_mode,Handle<Object> value)17561 Handle<CompilationCacheTable> CompilationCacheTable::Put(
17562     Handle<CompilationCacheTable> cache, Handle<String> src,
17563     Handle<SharedFunctionInfo> shared, LanguageMode language_mode,
17564     Handle<Object> value) {
17565   Isolate* isolate = cache->GetIsolate();
17566   StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17567   Handle<Object> k = key.AsHandle(isolate);
17568   cache = EnsureCapacity(cache, 1);
17569   int entry = cache->FindInsertionEntry(key.Hash());
17570   cache->set(EntryToIndex(entry), *k);
17571   cache->set(EntryToIndex(entry) + 1, *value);
17572   cache->ElementAdded();
17573   return cache;
17574 }
17575 
PutScript(Handle<CompilationCacheTable> cache,Handle<String> src,Handle<Context> native_context,LanguageMode language_mode,Handle<SharedFunctionInfo> value)17576 Handle<CompilationCacheTable> CompilationCacheTable::PutScript(
17577     Handle<CompilationCacheTable> cache, Handle<String> src,
17578     Handle<Context> native_context, LanguageMode language_mode,
17579     Handle<SharedFunctionInfo> value) {
17580   Isolate* isolate = cache->GetIsolate();
17581   Handle<SharedFunctionInfo> shared(native_context->empty_function()->shared());
17582   StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17583   Handle<Object> k = key.AsHandle(isolate);
17584   cache = EnsureCapacity(cache, 1);
17585   int entry = cache->FindInsertionEntry(key.Hash());
17586   cache->set(EntryToIndex(entry), *k);
17587   cache->set(EntryToIndex(entry) + 1, *value);
17588   cache->ElementAdded();
17589   return cache;
17590 }
17591 
PutEval(Handle<CompilationCacheTable> cache,Handle<String> src,Handle<SharedFunctionInfo> outer_info,Handle<SharedFunctionInfo> value,Handle<Context> native_context,Handle<FeedbackCell> feedback_cell,int position)17592 Handle<CompilationCacheTable> CompilationCacheTable::PutEval(
17593     Handle<CompilationCacheTable> cache, Handle<String> src,
17594     Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value,
17595     Handle<Context> native_context, Handle<FeedbackCell> feedback_cell,
17596     int position) {
17597   Isolate* isolate = cache->GetIsolate();
17598   StringSharedKey key(src, outer_info, value->language_mode(), position);
17599   {
17600     Handle<Object> k = key.AsHandle(isolate);
17601     int entry = cache->FindEntry(&key);
17602     if (entry != kNotFound) {
17603       cache->set(EntryToIndex(entry), *k);
17604       cache->set(EntryToIndex(entry) + 1, *value);
17605       // AddToFeedbackCellsMap may allocate a new sub-array to live in the
17606       // entry, but it won't change the cache array. Therefore EntryToIndex
17607       // and entry remains correct.
17608       AddToFeedbackCellsMap(cache, EntryToIndex(entry) + 2, native_context,
17609                             feedback_cell);
17610       return cache;
17611     }
17612   }
17613 
17614   cache = EnsureCapacity(cache, 1);
17615   int entry = cache->FindInsertionEntry(key.Hash());
17616   Handle<Object> k =
17617       isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
17618   cache->set(EntryToIndex(entry), *k);
17619   cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
17620   cache->ElementAdded();
17621   return cache;
17622 }
17623 
17624 
PutRegExp(Handle<CompilationCacheTable> cache,Handle<String> src,JSRegExp::Flags flags,Handle<FixedArray> value)17625 Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp(
17626       Handle<CompilationCacheTable> cache, Handle<String> src,
17627       JSRegExp::Flags flags, Handle<FixedArray> value) {
17628   RegExpKey key(src, flags);
17629   cache = EnsureCapacity(cache, 1);
17630   int entry = cache->FindInsertionEntry(key.Hash());
17631   // We store the value in the key slot, and compare the search key
17632   // to the stored value with a custon IsMatch function during lookups.
17633   cache->set(EntryToIndex(entry), *value);
17634   cache->set(EntryToIndex(entry) + 1, *value);
17635   cache->ElementAdded();
17636   return cache;
17637 }
17638 
17639 
Age()17640 void CompilationCacheTable::Age() {
17641   DisallowHeapAllocation no_allocation;
17642   Object* the_hole_value = GetHeap()->the_hole_value();
17643   for (int entry = 0, size = Capacity(); entry < size; entry++) {
17644     int entry_index = EntryToIndex(entry);
17645     int value_index = entry_index + 1;
17646 
17647     if (get(entry_index)->IsNumber()) {
17648       Smi* count = Smi::cast(get(value_index));
17649       count = Smi::FromInt(count->value() - 1);
17650       if (count->value() == 0) {
17651         NoWriteBarrierSet(this, entry_index, the_hole_value);
17652         NoWriteBarrierSet(this, value_index, the_hole_value);
17653         ElementRemoved();
17654       } else {
17655         NoWriteBarrierSet(this, value_index, count);
17656       }
17657     } else if (get(entry_index)->IsFixedArray()) {
17658       SharedFunctionInfo* info = SharedFunctionInfo::cast(get(value_index));
17659       if (info->IsInterpreted() && info->GetBytecodeArray()->IsOld()) {
17660         for (int i = 0; i < kEntrySize; i++) {
17661           NoWriteBarrierSet(this, entry_index + i, the_hole_value);
17662         }
17663         ElementRemoved();
17664       }
17665     }
17666   }
17667 }
17668 
17669 
Remove(Object * value)17670 void CompilationCacheTable::Remove(Object* value) {
17671   DisallowHeapAllocation no_allocation;
17672   Object* the_hole_value = GetHeap()->the_hole_value();
17673   for (int entry = 0, size = Capacity(); entry < size; entry++) {
17674     int entry_index = EntryToIndex(entry);
17675     int value_index = entry_index + 1;
17676     if (get(value_index) == value) {
17677       for (int i = 0; i < kEntrySize; i++) {
17678         NoWriteBarrierSet(this, entry_index + i, the_hole_value);
17679       }
17680       ElementRemoved();
17681     }
17682   }
17683   return;
17684 }
17685 
17686 template <typename Derived, typename Shape>
New(Isolate * isolate,int at_least_space_for,PretenureFlag pretenure,MinimumCapacity capacity_option)17687 Handle<Derived> BaseNameDictionary<Derived, Shape>::New(
17688     Isolate* isolate, int at_least_space_for, PretenureFlag pretenure,
17689     MinimumCapacity capacity_option) {
17690   DCHECK_LE(0, at_least_space_for);
17691   Handle<Derived> dict = Dictionary<Derived, Shape>::New(
17692       isolate, at_least_space_for, pretenure, capacity_option);
17693   dict->SetHash(PropertyArray::kNoHashSentinel);
17694   dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
17695   return dict;
17696 }
17697 
17698 template <typename Derived, typename Shape>
EnsureCapacity(Handle<Derived> dictionary,int n)17699 Handle<Derived> BaseNameDictionary<Derived, Shape>::EnsureCapacity(
17700     Handle<Derived> dictionary, int n) {
17701   // Check whether there are enough enumeration indices to add n elements.
17702   if (!PropertyDetails::IsValidIndex(dictionary->NextEnumerationIndex() + n)) {
17703     // If not, we generate new indices for the properties.
17704     int length = dictionary->NumberOfElements();
17705 
17706     Handle<FixedArray> iteration_order = IterationIndices(dictionary);
17707     DCHECK_EQ(length, iteration_order->length());
17708 
17709     // Iterate over the dictionary using the enumeration order and update
17710     // the dictionary with new enumeration indices.
17711     for (int i = 0; i < length; i++) {
17712       int index = Smi::ToInt(iteration_order->get(i));
17713       DCHECK(dictionary->IsKey(dictionary->GetIsolate(),
17714                                dictionary->KeyAt(index)));
17715 
17716       int enum_index = PropertyDetails::kInitialIndex + i;
17717 
17718       PropertyDetails details = dictionary->DetailsAt(index);
17719       PropertyDetails new_details = details.set_index(enum_index);
17720       dictionary->DetailsAtPut(index, new_details);
17721     }
17722 
17723     // Set the next enumeration index.
17724     dictionary->SetNextEnumerationIndex(PropertyDetails::kInitialIndex +
17725                                         length);
17726   }
17727   return HashTable<Derived, Shape>::EnsureCapacity(dictionary, n);
17728 }
17729 
17730 template <typename Derived, typename Shape>
DeleteEntry(Handle<Derived> dictionary,int entry)17731 Handle<Derived> Dictionary<Derived, Shape>::DeleteEntry(
17732     Handle<Derived> dictionary, int entry) {
17733   DCHECK(Shape::kEntrySize != 3 ||
17734          dictionary->DetailsAt(entry).IsConfigurable());
17735   dictionary->ClearEntry(entry);
17736   dictionary->ElementRemoved();
17737   return Shrink(dictionary);
17738 }
17739 
17740 template <typename Derived, typename Shape>
AtPut(Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details)17741 Handle<Derived> Dictionary<Derived, Shape>::AtPut(Handle<Derived> dictionary,
17742                                                   Key key, Handle<Object> value,
17743                                                   PropertyDetails details) {
17744   int entry = dictionary->FindEntry(key);
17745 
17746   // If the entry is present set the value;
17747   if (entry == Dictionary::kNotFound) {
17748     return Derived::Add(dictionary, key, value, details);
17749   }
17750 
17751   // We don't need to copy over the enumeration index.
17752   dictionary->ValueAtPut(entry, *value);
17753   if (Shape::kEntrySize == 3) dictionary->DetailsAtPut(entry, details);
17754   return dictionary;
17755 }
17756 
17757 template <typename Derived, typename Shape>
17758 Handle<Derived>
AddNoUpdateNextEnumerationIndex(Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details,int * entry_out)17759 BaseNameDictionary<Derived, Shape>::AddNoUpdateNextEnumerationIndex(
17760     Handle<Derived> dictionary, Key key, Handle<Object> value,
17761     PropertyDetails details, int* entry_out) {
17762   // Insert element at empty or deleted entry
17763   return Dictionary<Derived, Shape>::Add(dictionary, key, value, details,
17764                                          entry_out);
17765 }
17766 
17767 // GCC workaround: Explicitly instantiate template method for NameDictionary
17768 // to avoid "undefined reference" issues during linking.
17769 template Handle<NameDictionary>
17770 BaseNameDictionary<NameDictionary, NameDictionaryShape>::
17771     AddNoUpdateNextEnumerationIndex(Handle<NameDictionary>, Handle<Name>,
17772                                     Handle<Object>, PropertyDetails, int*);
17773 
17774 template <typename Derived, typename Shape>
Add(Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details,int * entry_out)17775 Handle<Derived> BaseNameDictionary<Derived, Shape>::Add(
17776     Handle<Derived> dictionary, Key key, Handle<Object> value,
17777     PropertyDetails details, int* entry_out) {
17778   // Insert element at empty or deleted entry
17779   DCHECK_EQ(0, details.dictionary_index());
17780   // Assign an enumeration index to the property and update
17781   // SetNextEnumerationIndex.
17782   int index = dictionary->NextEnumerationIndex();
17783   details = details.set_index(index);
17784   dictionary->SetNextEnumerationIndex(index + 1);
17785   return AddNoUpdateNextEnumerationIndex(dictionary, key, value, details,
17786                                          entry_out);
17787 }
17788 
17789 template <typename Derived, typename Shape>
Add(Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details,int * entry_out)17790 Handle<Derived> Dictionary<Derived, Shape>::Add(Handle<Derived> dictionary,
17791                                                 Key key, Handle<Object> value,
17792                                                 PropertyDetails details,
17793                                                 int* entry_out) {
17794   Isolate* isolate = dictionary->GetIsolate();
17795   uint32_t hash = Shape::Hash(isolate, key);
17796   // Valdate key is absent.
17797   SLOW_DCHECK((dictionary->FindEntry(key) == Dictionary::kNotFound));
17798   // Check whether the dictionary should be extended.
17799   dictionary = Derived::EnsureCapacity(dictionary, 1);
17800 
17801   // Compute the key object.
17802   Handle<Object> k = Shape::AsHandle(isolate, key);
17803 
17804   uint32_t entry = dictionary->FindInsertionEntry(hash);
17805   dictionary->SetEntry(entry, *k, *value, details);
17806   DCHECK(dictionary->KeyAt(entry)->IsNumber() ||
17807          Shape::Unwrap(dictionary->KeyAt(entry))->IsUniqueName());
17808   dictionary->ElementAdded();
17809   if (entry_out) *entry_out = entry;
17810   return dictionary;
17811 }
17812 
17813 // static
Set(Handle<SimpleNumberDictionary> dictionary,uint32_t key,Handle<Object> value)17814 Handle<SimpleNumberDictionary> SimpleNumberDictionary::Set(
17815     Handle<SimpleNumberDictionary> dictionary, uint32_t key,
17816     Handle<Object> value) {
17817   return AtPut(dictionary, key, value, PropertyDetails::Empty());
17818 }
17819 
HasComplexElements()17820 bool NumberDictionary::HasComplexElements() {
17821   if (!requires_slow_elements()) return false;
17822   Isolate* isolate = this->GetIsolate();
17823   int capacity = this->Capacity();
17824   for (int i = 0; i < capacity; i++) {
17825     Object* k;
17826     if (!this->ToKey(isolate, i, &k)) continue;
17827     PropertyDetails details = this->DetailsAt(i);
17828     if (details.kind() == kAccessor) return true;
17829     PropertyAttributes attr = details.attributes();
17830     if (attr & ALL_ATTRIBUTES_MASK) return true;
17831   }
17832   return false;
17833 }
17834 
UpdateMaxNumberKey(uint32_t key,Handle<JSObject> dictionary_holder)17835 void NumberDictionary::UpdateMaxNumberKey(uint32_t key,
17836                                           Handle<JSObject> dictionary_holder) {
17837   DisallowHeapAllocation no_allocation;
17838   // If the dictionary requires slow elements an element has already
17839   // been added at a high index.
17840   if (requires_slow_elements()) return;
17841   // Check if this index is high enough that we should require slow
17842   // elements.
17843   if (key > kRequiresSlowElementsLimit) {
17844     if (!dictionary_holder.is_null()) {
17845       dictionary_holder->RequireSlowElements(this);
17846     }
17847     set_requires_slow_elements();
17848     return;
17849   }
17850   // Update max key value.
17851   Object* max_index_object = get(kMaxNumberKeyIndex);
17852   if (!max_index_object->IsSmi() || max_number_key() < key) {
17853     FixedArray::set(kMaxNumberKeyIndex,
17854                     Smi::FromInt(key << kRequiresSlowElementsTagSize));
17855   }
17856 }
17857 
Set(Handle<NumberDictionary> dictionary,uint32_t key,Handle<Object> value,Handle<JSObject> dictionary_holder,PropertyDetails details)17858 Handle<NumberDictionary> NumberDictionary::Set(
17859     Handle<NumberDictionary> dictionary, uint32_t key, Handle<Object> value,
17860     Handle<JSObject> dictionary_holder, PropertyDetails details) {
17861   dictionary->UpdateMaxNumberKey(key, dictionary_holder);
17862   return AtPut(dictionary, key, value, details);
17863 }
17864 
CopyValuesTo(FixedArray * elements)17865 void NumberDictionary::CopyValuesTo(FixedArray* elements) {
17866   Isolate* isolate = this->GetIsolate();
17867   int pos = 0;
17868   int capacity = this->Capacity();
17869   DisallowHeapAllocation no_gc;
17870   WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
17871   for (int i = 0; i < capacity; i++) {
17872     Object* k;
17873     if (this->ToKey(isolate, i, &k)) {
17874       elements->set(pos++, this->ValueAt(i), mode);
17875     }
17876   }
17877   DCHECK_EQ(pos, elements->length());
17878 }
17879 
17880 template <typename Derived, typename Shape>
NumberOfEnumerableProperties()17881 int Dictionary<Derived, Shape>::NumberOfEnumerableProperties() {
17882   Isolate* isolate = this->GetIsolate();
17883   int capacity = this->Capacity();
17884   int result = 0;
17885   for (int i = 0; i < capacity; i++) {
17886     Object* k;
17887     if (!this->ToKey(isolate, i, &k)) continue;
17888     if (k->FilterKey(ENUMERABLE_STRINGS)) continue;
17889     PropertyDetails details = this->DetailsAt(i);
17890     PropertyAttributes attr = details.attributes();
17891     if ((attr & ONLY_ENUMERABLE) == 0) result++;
17892   }
17893   return result;
17894 }
17895 
17896 
17897 template <typename Dictionary>
17898 struct EnumIndexComparator {
EnumIndexComparatorv8::internal::EnumIndexComparator17899   explicit EnumIndexComparator(Dictionary* dict) : dict(dict) {}
operator ()v8::internal::EnumIndexComparator17900   bool operator()(const base::AtomicElement<Smi*>& a,
17901                   const base::AtomicElement<Smi*>& b) {
17902     PropertyDetails da(dict->DetailsAt(a.value()->value()));
17903     PropertyDetails db(dict->DetailsAt(b.value()->value()));
17904     return da.dictionary_index() < db.dictionary_index();
17905   }
17906   Dictionary* dict;
17907 };
17908 
17909 template <typename Derived, typename Shape>
CopyEnumKeysTo(Handle<Derived> dictionary,Handle<FixedArray> storage,KeyCollectionMode mode,KeyAccumulator * accumulator)17910 void BaseNameDictionary<Derived, Shape>::CopyEnumKeysTo(
17911     Handle<Derived> dictionary, Handle<FixedArray> storage,
17912     KeyCollectionMode mode, KeyAccumulator* accumulator) {
17913   DCHECK_IMPLIES(mode != KeyCollectionMode::kOwnOnly, accumulator != nullptr);
17914   Isolate* isolate = dictionary->GetIsolate();
17915   int length = storage->length();
17916   int capacity = dictionary->Capacity();
17917   int properties = 0;
17918   for (int i = 0; i < capacity; i++) {
17919     Object* key;
17920     if (!dictionary->ToKey(isolate, i, &key)) continue;
17921     bool is_shadowing_key = false;
17922     if (key->IsSymbol()) continue;
17923     PropertyDetails details = dictionary->DetailsAt(i);
17924     if (details.IsDontEnum()) {
17925       if (mode == KeyCollectionMode::kIncludePrototypes) {
17926         is_shadowing_key = true;
17927       } else {
17928         continue;
17929       }
17930     }
17931     if (is_shadowing_key) {
17932       accumulator->AddShadowingKey(key);
17933       continue;
17934     } else {
17935       storage->set(properties, Smi::FromInt(i));
17936     }
17937     properties++;
17938     if (mode == KeyCollectionMode::kOwnOnly && properties == length) break;
17939   }
17940 
17941   CHECK_EQ(length, properties);
17942   DisallowHeapAllocation no_gc;
17943   Derived* raw_dictionary = *dictionary;
17944   FixedArray* raw_storage = *storage;
17945   EnumIndexComparator<Derived> cmp(raw_dictionary);
17946   // Use AtomicElement wrapper to ensure that std::sort uses atomic load and
17947   // store operations that are safe for concurrent marking.
17948   base::AtomicElement<Smi*>* start =
17949       reinterpret_cast<base::AtomicElement<Smi*>*>(
17950           storage->GetFirstElementAddress());
17951   std::sort(start, start + length, cmp);
17952   for (int i = 0; i < length; i++) {
17953     int index = Smi::ToInt(raw_storage->get(i));
17954     raw_storage->set(i, raw_dictionary->NameAt(index));
17955   }
17956 }
17957 
17958 template <typename Derived, typename Shape>
IterationIndices(Handle<Derived> dictionary)17959 Handle<FixedArray> BaseNameDictionary<Derived, Shape>::IterationIndices(
17960     Handle<Derived> dictionary) {
17961   Isolate* isolate = dictionary->GetIsolate();
17962   int capacity = dictionary->Capacity();
17963   int length = dictionary->NumberOfElements();
17964   Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
17965   int array_size = 0;
17966   {
17967     DisallowHeapAllocation no_gc;
17968     Derived* raw_dictionary = *dictionary;
17969     for (int i = 0; i < capacity; i++) {
17970       Object* k;
17971       if (!raw_dictionary->ToKey(isolate, i, &k)) continue;
17972       array->set(array_size++, Smi::FromInt(i));
17973     }
17974 
17975     DCHECK_EQ(array_size, length);
17976 
17977     EnumIndexComparator<Derived> cmp(raw_dictionary);
17978     // Use AtomicElement wrapper to ensure that std::sort uses atomic load and
17979     // store operations that are safe for concurrent marking.
17980     base::AtomicElement<Smi*>* start =
17981         reinterpret_cast<base::AtomicElement<Smi*>*>(
17982             array->GetFirstElementAddress());
17983     std::sort(start, start + array_size, cmp);
17984   }
17985   array->Shrink(array_size);
17986   return array;
17987 }
17988 
17989 template <typename Derived, typename Shape>
CollectKeysTo(Handle<Derived> dictionary,KeyAccumulator * keys)17990 void BaseNameDictionary<Derived, Shape>::CollectKeysTo(
17991     Handle<Derived> dictionary, KeyAccumulator* keys) {
17992   Isolate* isolate = keys->isolate();
17993   int capacity = dictionary->Capacity();
17994   Handle<FixedArray> array =
17995       isolate->factory()->NewFixedArray(dictionary->NumberOfElements());
17996   int array_size = 0;
17997   PropertyFilter filter = keys->filter();
17998   {
17999     DisallowHeapAllocation no_gc;
18000     Derived* raw_dictionary = *dictionary;
18001     for (int i = 0; i < capacity; i++) {
18002       Object* k;
18003       if (!raw_dictionary->ToKey(isolate, i, &k)) continue;
18004       if (k->FilterKey(filter)) continue;
18005       PropertyDetails details = raw_dictionary->DetailsAt(i);
18006       if ((details.attributes() & filter) != 0) {
18007         keys->AddShadowingKey(k);
18008         continue;
18009       }
18010       if (filter & ONLY_ALL_CAN_READ) {
18011         if (details.kind() != kAccessor) continue;
18012         Object* accessors = raw_dictionary->ValueAt(i);
18013         if (!accessors->IsAccessorInfo()) continue;
18014         if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
18015       }
18016       array->set(array_size++, Smi::FromInt(i));
18017     }
18018 
18019     EnumIndexComparator<Derived> cmp(raw_dictionary);
18020     // Use AtomicElement wrapper to ensure that std::sort uses atomic load and
18021     // store operations that are safe for concurrent marking.
18022     base::AtomicElement<Smi*>* start =
18023         reinterpret_cast<base::AtomicElement<Smi*>*>(
18024             array->GetFirstElementAddress());
18025     std::sort(start, start + array_size, cmp);
18026   }
18027 
18028   bool has_seen_symbol = false;
18029   for (int i = 0; i < array_size; i++) {
18030     int index = Smi::ToInt(array->get(i));
18031     Object* key = dictionary->NameAt(index);
18032     if (key->IsSymbol()) {
18033       has_seen_symbol = true;
18034       continue;
18035     }
18036     keys->AddKey(key, DO_NOT_CONVERT);
18037   }
18038   if (has_seen_symbol) {
18039     for (int i = 0; i < array_size; i++) {
18040       int index = Smi::ToInt(array->get(i));
18041       Object* key = dictionary->NameAt(index);
18042       if (!key->IsSymbol()) continue;
18043       keys->AddKey(key, DO_NOT_CONVERT);
18044     }
18045   }
18046 }
18047 
18048 // Backwards lookup (slow).
18049 template <typename Derived, typename Shape>
SlowReverseLookup(Object * value)18050 Object* Dictionary<Derived, Shape>::SlowReverseLookup(Object* value) {
18051   Derived* dictionary = Derived::cast(this);
18052   Isolate* isolate = dictionary->GetIsolate();
18053   int capacity = dictionary->Capacity();
18054   for (int i = 0; i < capacity; i++) {
18055     Object* k;
18056     if (!dictionary->ToKey(isolate, i, &k)) continue;
18057     Object* e = dictionary->ValueAt(i);
18058     if (e == value) return k;
18059   }
18060   return isolate->heap()->undefined_value();
18061 }
18062 
18063 
Lookup(Isolate * isolate,Handle<Object> key,int32_t hash)18064 Object* ObjectHashTable::Lookup(Isolate* isolate, Handle<Object> key,
18065                                 int32_t hash) {
18066   DisallowHeapAllocation no_gc;
18067   DCHECK(IsKey(isolate, *key));
18068 
18069   int entry = FindEntry(isolate, key, hash);
18070   if (entry == kNotFound) return isolate->heap()->the_hole_value();
18071   return get(EntryToIndex(entry) + 1);
18072 }
18073 
18074 
Lookup(Handle<Object> key)18075 Object* ObjectHashTable::Lookup(Handle<Object> key) {
18076   DisallowHeapAllocation no_gc;
18077 
18078   Isolate* isolate = GetIsolate();
18079   DCHECK(IsKey(isolate, *key));
18080 
18081   // If the object does not have an identity hash, it was never used as a key.
18082   Object* hash = key->GetHash();
18083   if (hash->IsUndefined(isolate)) {
18084     return isolate->heap()->the_hole_value();
18085   }
18086   return Lookup(isolate, key, Smi::ToInt(hash));
18087 }
18088 
ValueAt(int entry)18089 Object* ObjectHashTable::ValueAt(int entry) {
18090   return get(EntryToValueIndex(entry));
18091 }
18092 
Lookup(Handle<Object> key,int32_t hash)18093 Object* ObjectHashTable::Lookup(Handle<Object> key, int32_t hash) {
18094   return Lookup(GetIsolate(), key, hash);
18095 }
18096 
18097 
Put(Handle<ObjectHashTable> table,Handle<Object> key,Handle<Object> value)18098 Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
18099                                              Handle<Object> key,
18100                                              Handle<Object> value) {
18101   Isolate* isolate = table->GetIsolate();
18102   DCHECK(table->IsKey(isolate, *key));
18103   DCHECK(!value->IsTheHole(isolate));
18104 
18105   // Make sure the key object has an identity hash code.
18106   int32_t hash = key->GetOrCreateHash(isolate)->value();
18107 
18108   return Put(table, key, value, hash);
18109 }
18110 
18111 
Put(Handle<ObjectHashTable> table,Handle<Object> key,Handle<Object> value,int32_t hash)18112 Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
18113                                              Handle<Object> key,
18114                                              Handle<Object> value,
18115                                              int32_t hash) {
18116   Isolate* isolate = table->GetIsolate();
18117   DCHECK(table->IsKey(isolate, *key));
18118   DCHECK(!value->IsTheHole(isolate));
18119 
18120   int entry = table->FindEntry(isolate, key, hash);
18121 
18122   // Key is already in table, just overwrite value.
18123   if (entry != kNotFound) {
18124     table->set(EntryToIndex(entry) + 1, *value);
18125     return table;
18126   }
18127 
18128   // Rehash if more than 33% of the entries are deleted entries.
18129   // TODO(jochen): Consider to shrink the fixed array in place.
18130   if ((table->NumberOfDeletedElements() << 1) > table->NumberOfElements()) {
18131     table->Rehash();
18132   }
18133   // If we're out of luck, we didn't get a GC recently, and so rehashing
18134   // isn't enough to avoid a crash.
18135   if (!table->HasSufficientCapacityToAdd(1)) {
18136     int nof = table->NumberOfElements() + 1;
18137     int capacity = ObjectHashTable::ComputeCapacity(nof * 2);
18138     if (capacity > ObjectHashTable::kMaxCapacity) {
18139       for (size_t i = 0; i < 2; ++i) {
18140         isolate->heap()->CollectAllGarbage(
18141             Heap::kFinalizeIncrementalMarkingMask,
18142             GarbageCollectionReason::kFullHashtable);
18143       }
18144       table->Rehash();
18145     }
18146   }
18147 
18148   // Check whether the hash table should be extended.
18149   table = EnsureCapacity(table, 1);
18150   table->AddEntry(table->FindInsertionEntry(hash), *key, *value);
18151   return table;
18152 }
18153 
18154 
Remove(Handle<ObjectHashTable> table,Handle<Object> key,bool * was_present)18155 Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
18156                                                 Handle<Object> key,
18157                                                 bool* was_present) {
18158   DCHECK(table->IsKey(table->GetIsolate(), *key));
18159 
18160   Object* hash = key->GetHash();
18161   if (hash->IsUndefined(table->GetIsolate())) {
18162     *was_present = false;
18163     return table;
18164   }
18165 
18166   return Remove(table, key, was_present, Smi::ToInt(hash));
18167 }
18168 
18169 
Remove(Handle<ObjectHashTable> table,Handle<Object> key,bool * was_present,int32_t hash)18170 Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
18171                                                 Handle<Object> key,
18172                                                 bool* was_present,
18173                                                 int32_t hash) {
18174   Isolate* isolate = table->GetIsolate();
18175   DCHECK(table->IsKey(isolate, *key));
18176 
18177   int entry = table->FindEntry(isolate, key, hash);
18178   if (entry == kNotFound) {
18179     *was_present = false;
18180     return table;
18181   }
18182 
18183   *was_present = true;
18184   table->RemoveEntry(entry);
18185   return Shrink(table);
18186 }
18187 
18188 
AddEntry(int entry,Object * key,Object * value)18189 void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
18190   set(EntryToIndex(entry), key);
18191   set(EntryToIndex(entry) + 1, value);
18192   ElementAdded();
18193 }
18194 
18195 
RemoveEntry(int entry)18196 void ObjectHashTable::RemoveEntry(int entry) {
18197   set_the_hole(EntryToIndex(entry));
18198   set_the_hole(EntryToIndex(entry) + 1);
18199   ElementRemoved();
18200 }
18201 
18202 
Initialize(Handle<JSSet> set,Isolate * isolate)18203 void JSSet::Initialize(Handle<JSSet> set, Isolate* isolate) {
18204   Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
18205   set->set_table(*table);
18206 }
18207 
18208 
Clear(Handle<JSSet> set)18209 void JSSet::Clear(Handle<JSSet> set) {
18210   Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()));
18211   table = OrderedHashSet::Clear(table);
18212   set->set_table(*table);
18213 }
18214 
18215 
Initialize(Handle<JSMap> map,Isolate * isolate)18216 void JSMap::Initialize(Handle<JSMap> map, Isolate* isolate) {
18217   Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
18218   map->set_table(*table);
18219 }
18220 
18221 
Clear(Handle<JSMap> map)18222 void JSMap::Clear(Handle<JSMap> map) {
18223   Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()));
18224   table = OrderedHashMap::Clear(table);
18225   map->set_table(*table);
18226 }
18227 
18228 
Initialize(Handle<JSWeakCollection> weak_collection,Isolate * isolate)18229 void JSWeakCollection::Initialize(Handle<JSWeakCollection> weak_collection,
18230                                   Isolate* isolate) {
18231   Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0);
18232   weak_collection->set_table(*table);
18233 }
18234 
18235 
Set(Handle<JSWeakCollection> weak_collection,Handle<Object> key,Handle<Object> value,int32_t hash)18236 void JSWeakCollection::Set(Handle<JSWeakCollection> weak_collection,
18237                            Handle<Object> key, Handle<Object> value,
18238                            int32_t hash) {
18239   DCHECK(key->IsJSReceiver() || key->IsSymbol());
18240   Handle<ObjectHashTable> table(
18241       ObjectHashTable::cast(weak_collection->table()));
18242   DCHECK(table->IsKey(table->GetIsolate(), *key));
18243   Handle<ObjectHashTable> new_table =
18244       ObjectHashTable::Put(table, key, value, hash);
18245   weak_collection->set_table(*new_table);
18246   if (*table != *new_table) {
18247     // Zap the old table since we didn't record slots for its elements.
18248     table->FillWithHoles(0, table->length());
18249   }
18250 }
18251 
18252 
Delete(Handle<JSWeakCollection> weak_collection,Handle<Object> key,int32_t hash)18253 bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection,
18254                               Handle<Object> key, int32_t hash) {
18255   DCHECK(key->IsJSReceiver() || key->IsSymbol());
18256   Handle<ObjectHashTable> table(
18257       ObjectHashTable::cast(weak_collection->table()));
18258   DCHECK(table->IsKey(table->GetIsolate(), *key));
18259   bool was_present = false;
18260   Handle<ObjectHashTable> new_table =
18261       ObjectHashTable::Remove(table, key, &was_present, hash);
18262   weak_collection->set_table(*new_table);
18263   if (*table != *new_table) {
18264     // Zap the old table since we didn't record slots for its elements.
18265     table->FillWithHoles(0, table->length());
18266   }
18267   return was_present;
18268 }
18269 
GetEntries(Handle<JSWeakCollection> holder,int max_entries)18270 Handle<JSArray> JSWeakCollection::GetEntries(Handle<JSWeakCollection> holder,
18271                                              int max_entries) {
18272   Isolate* isolate = holder->GetIsolate();
18273   Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
18274   if (max_entries == 0 || max_entries > table->NumberOfElements()) {
18275     max_entries = table->NumberOfElements();
18276   }
18277   int values_per_entry = holder->IsJSWeakMap() ? 2 : 1;
18278   Handle<FixedArray> entries =
18279       isolate->factory()->NewFixedArray(max_entries * values_per_entry);
18280   // Recompute max_values because GC could have removed elements from the table.
18281   if (max_entries > table->NumberOfElements()) {
18282     max_entries = table->NumberOfElements();
18283   }
18284 
18285   {
18286     DisallowHeapAllocation no_gc;
18287     int count = 0;
18288     for (int i = 0;
18289          count / values_per_entry < max_entries && i < table->Capacity(); i++) {
18290       Object* key;
18291       if (table->ToKey(isolate, i, &key)) {
18292         entries->set(count++, key);
18293         if (values_per_entry > 1) {
18294           Object* value = table->Lookup(handle(key, isolate));
18295           entries->set(count++, value);
18296         }
18297       }
18298     }
18299     DCHECK_EQ(max_entries * values_per_entry, count);
18300   }
18301   return isolate->factory()->NewJSArrayWithElements(entries);
18302 }
18303 
18304 // static
New(Handle<JSFunction> constructor,Handle<JSReceiver> new_target,double tv)18305 MaybeHandle<JSDate> JSDate::New(Handle<JSFunction> constructor,
18306                                 Handle<JSReceiver> new_target, double tv) {
18307   Isolate* const isolate = constructor->GetIsolate();
18308   Handle<JSObject> result;
18309   ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
18310                              JSObject::New(constructor, new_target), JSDate);
18311   if (-DateCache::kMaxTimeInMs <= tv && tv <= DateCache::kMaxTimeInMs) {
18312     tv = DoubleToInteger(tv) + 0.0;
18313   } else {
18314     tv = std::numeric_limits<double>::quiet_NaN();
18315   }
18316   Handle<Object> value = isolate->factory()->NewNumber(tv);
18317   Handle<JSDate>::cast(result)->SetValue(*value, std::isnan(tv));
18318   return Handle<JSDate>::cast(result);
18319 }
18320 
18321 
18322 // static
CurrentTimeValue(Isolate * isolate)18323 double JSDate::CurrentTimeValue(Isolate* isolate) {
18324   if (FLAG_log_internal_timer_events) LOG(isolate, CurrentTimeEvent());
18325 
18326   // According to ECMA-262, section 15.9.1, page 117, the precision of
18327   // the number in a Date object representing a particular instant in
18328   // time is milliseconds. Therefore, we floor the result of getting
18329   // the OS time.
18330   return Floor(V8::GetCurrentPlatform()->CurrentClockTimeMillis());
18331 }
18332 
18333 
18334 // static
GetField(Object * object,Smi * index)18335 Object* JSDate::GetField(Object* object, Smi* index) {
18336   return JSDate::cast(object)->DoGetField(
18337       static_cast<FieldIndex>(index->value()));
18338 }
18339 
18340 
DoGetField(FieldIndex index)18341 Object* JSDate::DoGetField(FieldIndex index) {
18342   DCHECK_NE(index, kDateValue);
18343 
18344   DateCache* date_cache = GetIsolate()->date_cache();
18345 
18346   if (index < kFirstUncachedField) {
18347     Object* stamp = cache_stamp();
18348     if (stamp != date_cache->stamp() && stamp->IsSmi()) {
18349       // Since the stamp is not NaN, the value is also not NaN.
18350       int64_t local_time_ms =
18351           date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
18352       SetCachedFields(local_time_ms, date_cache);
18353     }
18354     switch (index) {
18355       case kYear: return year();
18356       case kMonth: return month();
18357       case kDay: return day();
18358       case kWeekday: return weekday();
18359       case kHour: return hour();
18360       case kMinute: return min();
18361       case kSecond: return sec();
18362       default: UNREACHABLE();
18363     }
18364   }
18365 
18366   if (index >= kFirstUTCField) {
18367     return GetUTCField(index, value()->Number(), date_cache);
18368   }
18369 
18370   double time = value()->Number();
18371   if (std::isnan(time)) return GetIsolate()->heap()->nan_value();
18372 
18373   int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
18374   int days = DateCache::DaysFromTime(local_time_ms);
18375 
18376   if (index == kDays) return Smi::FromInt(days);
18377 
18378   int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
18379   if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
18380   DCHECK_EQ(index, kTimeInDay);
18381   return Smi::FromInt(time_in_day_ms);
18382 }
18383 
18384 
GetUTCField(FieldIndex index,double value,DateCache * date_cache)18385 Object* JSDate::GetUTCField(FieldIndex index,
18386                             double value,
18387                             DateCache* date_cache) {
18388   DCHECK_GE(index, kFirstUTCField);
18389 
18390   if (std::isnan(value)) return GetIsolate()->heap()->nan_value();
18391 
18392   int64_t time_ms = static_cast<int64_t>(value);
18393 
18394   if (index == kTimezoneOffset) {
18395     return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
18396   }
18397 
18398   int days = DateCache::DaysFromTime(time_ms);
18399 
18400   if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
18401 
18402   if (index <= kDayUTC) {
18403     int year, month, day;
18404     date_cache->YearMonthDayFromDays(days, &year, &month, &day);
18405     if (index == kYearUTC) return Smi::FromInt(year);
18406     if (index == kMonthUTC) return Smi::FromInt(month);
18407     DCHECK_EQ(index, kDayUTC);
18408     return Smi::FromInt(day);
18409   }
18410 
18411   int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
18412   switch (index) {
18413     case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
18414     case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
18415     case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
18416     case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
18417     case kDaysUTC: return Smi::FromInt(days);
18418     case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
18419     default: UNREACHABLE();
18420   }
18421 
18422   UNREACHABLE();
18423 }
18424 
18425 
18426 // static
SetValue(Handle<JSDate> date,double v)18427 Handle<Object> JSDate::SetValue(Handle<JSDate> date, double v) {
18428   Isolate* const isolate = date->GetIsolate();
18429   Handle<Object> value = isolate->factory()->NewNumber(v);
18430   bool value_is_nan = std::isnan(v);
18431   date->SetValue(*value, value_is_nan);
18432   return value;
18433 }
18434 
18435 
SetValue(Object * value,bool is_value_nan)18436 void JSDate::SetValue(Object* value, bool is_value_nan) {
18437   set_value(value);
18438   if (is_value_nan) {
18439     HeapNumber* nan = GetIsolate()->heap()->nan_value();
18440     set_cache_stamp(nan, SKIP_WRITE_BARRIER);
18441     set_year(nan, SKIP_WRITE_BARRIER);
18442     set_month(nan, SKIP_WRITE_BARRIER);
18443     set_day(nan, SKIP_WRITE_BARRIER);
18444     set_hour(nan, SKIP_WRITE_BARRIER);
18445     set_min(nan, SKIP_WRITE_BARRIER);
18446     set_sec(nan, SKIP_WRITE_BARRIER);
18447     set_weekday(nan, SKIP_WRITE_BARRIER);
18448   } else {
18449     set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
18450   }
18451 }
18452 
18453 
SetCachedFields(int64_t local_time_ms,DateCache * date_cache)18454 void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) {
18455   int days = DateCache::DaysFromTime(local_time_ms);
18456   int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
18457   int year, month, day;
18458   date_cache->YearMonthDayFromDays(days, &year, &month, &day);
18459   int weekday = date_cache->Weekday(days);
18460   int hour = time_in_day_ms / (60 * 60 * 1000);
18461   int min = (time_in_day_ms / (60 * 1000)) % 60;
18462   int sec = (time_in_day_ms / 1000) % 60;
18463   set_cache_stamp(date_cache->stamp());
18464   set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
18465   set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
18466   set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
18467   set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
18468   set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
18469   set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
18470   set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
18471 }
18472 
18473 namespace {
18474 
ScriptFromJSValue(Object * in)18475 Script* ScriptFromJSValue(Object* in) {
18476   DCHECK(in->IsJSValue());
18477   JSValue* jsvalue = JSValue::cast(in);
18478   DCHECK(jsvalue->value()->IsScript());
18479   return Script::cast(jsvalue->value());
18480 }
18481 
18482 }  // namespace
18483 
GetLineNumber() const18484 int JSMessageObject::GetLineNumber() const {
18485   if (start_position() == -1) return Message::kNoLineNumberInfo;
18486 
18487   Handle<Script> the_script = handle(ScriptFromJSValue(script()));
18488 
18489   Script::PositionInfo info;
18490   const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
18491   if (!Script::GetPositionInfo(the_script, start_position(), &info,
18492                                offset_flag)) {
18493     return Message::kNoLineNumberInfo;
18494   }
18495 
18496   return info.line + 1;
18497 }
18498 
GetColumnNumber() const18499 int JSMessageObject::GetColumnNumber() const {
18500   if (start_position() == -1) return -1;
18501 
18502   Handle<Script> the_script = handle(ScriptFromJSValue(script()));
18503 
18504   Script::PositionInfo info;
18505   const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
18506   if (!Script::GetPositionInfo(the_script, start_position(), &info,
18507                                offset_flag)) {
18508     return -1;
18509   }
18510 
18511   return info.column;  // Note: No '+1' in contrast to GetLineNumber.
18512 }
18513 
GetSourceLine() const18514 Handle<String> JSMessageObject::GetSourceLine() const {
18515   Handle<Script> the_script = handle(ScriptFromJSValue(script()));
18516 
18517   Isolate* isolate = the_script->GetIsolate();
18518   if (the_script->type() == Script::TYPE_WASM) {
18519     return isolate->factory()->empty_string();
18520   }
18521 
18522   Script::PositionInfo info;
18523   const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
18524   if (!Script::GetPositionInfo(the_script, start_position(), &info,
18525                                offset_flag)) {
18526     return isolate->factory()->empty_string();
18527   }
18528 
18529   Handle<String> src = handle(String::cast(the_script->source()), isolate);
18530   return isolate->factory()->NewSubString(src, info.line_start, info.line_end);
18531 }
18532 
Neuter()18533 void JSArrayBuffer::Neuter() {
18534   CHECK(is_neuterable());
18535   CHECK(!was_neutered());
18536   CHECK(is_external());
18537   set_backing_store(nullptr);
18538   set_byte_length(Smi::kZero);
18539   set_was_neutered(true);
18540   set_is_neuterable(false);
18541   // Invalidate the neutering protector.
18542   Isolate* const isolate = GetIsolate();
18543   if (isolate->IsArrayBufferNeuteringIntact()) {
18544     isolate->InvalidateArrayBufferNeuteringProtector();
18545   }
18546 }
18547 
FreeBackingStoreFromMainThread()18548 void JSArrayBuffer::FreeBackingStoreFromMainThread() {
18549   if (allocation_base() == nullptr) {
18550     return;
18551   }
18552   FreeBackingStore(GetIsolate(),
18553                    {allocation_base(), allocation_length(), backing_store(),
18554                     allocation_mode(), is_wasm_memory()});
18555   // Zero out the backing store and allocation base to avoid dangling
18556   // pointers.
18557   set_backing_store(nullptr);
18558 }
18559 
18560 // static
FreeBackingStore(Isolate * isolate,Allocation allocation)18561 void JSArrayBuffer::FreeBackingStore(Isolate* isolate, Allocation allocation) {
18562   if (allocation.mode == ArrayBuffer::Allocator::AllocationMode::kReservation) {
18563     bool needs_free = true;
18564     if (allocation.is_wasm_memory) {
18565       wasm::WasmMemoryTracker* memory_tracker =
18566           isolate->wasm_engine()->memory_tracker();
18567       if (memory_tracker->FreeMemoryIfIsWasmMemory(allocation.backing_store)) {
18568         needs_free = false;
18569       }
18570     }
18571     if (needs_free) {
18572       CHECK(FreePages(allocation.allocation_base, allocation.length));
18573     }
18574   } else {
18575     isolate->array_buffer_allocator()->Free(allocation.allocation_base,
18576                                             allocation.length);
18577   }
18578 }
18579 
set_is_wasm_memory(bool is_wasm_memory)18580 void JSArrayBuffer::set_is_wasm_memory(bool is_wasm_memory) {
18581   set_bit_field(IsWasmMemory::update(bit_field(), is_wasm_memory));
18582 }
18583 
Setup(Handle<JSArrayBuffer> array_buffer,Isolate * isolate,bool is_external,void * data,size_t byte_length,SharedFlag shared,bool is_wasm_memory)18584 void JSArrayBuffer::Setup(Handle<JSArrayBuffer> array_buffer, Isolate* isolate,
18585                           bool is_external, void* data, size_t byte_length,
18586                           SharedFlag shared, bool is_wasm_memory) {
18587   DCHECK_EQ(array_buffer->GetEmbedderFieldCount(),
18588             v8::ArrayBuffer::kEmbedderFieldCount);
18589   for (int i = 0; i < v8::ArrayBuffer::kEmbedderFieldCount; i++) {
18590     array_buffer->SetEmbedderField(i, Smi::kZero);
18591   }
18592   array_buffer->set_bit_field(0);
18593   array_buffer->set_is_external(is_external);
18594   array_buffer->set_is_neuterable(shared == SharedFlag::kNotShared);
18595   array_buffer->set_is_shared(shared == SharedFlag::kShared);
18596   array_buffer->set_is_wasm_memory(is_wasm_memory);
18597 
18598   Handle<Object> heap_byte_length =
18599       isolate->factory()->NewNumberFromSize(byte_length);
18600   CHECK(heap_byte_length->IsSmi() || heap_byte_length->IsHeapNumber());
18601   array_buffer->set_byte_length(*heap_byte_length);
18602   // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
18603   // are currently being constructed in the |ArrayBufferTracker|. The
18604   // registration method below handles the case of registering a buffer that has
18605   // already been promoted.
18606   array_buffer->set_backing_store(data);
18607 
18608   if (data && !is_external) {
18609     isolate->heap()->RegisterNewArrayBuffer(*array_buffer);
18610   }
18611 }
18612 
18613 namespace {
18614 
ConvertToMb(size_t size)18615 inline int ConvertToMb(size_t size) {
18616   return static_cast<int>(size / static_cast<size_t>(MB));
18617 }
18618 
18619 }  // namespace
18620 
SetupAllocatingData(Handle<JSArrayBuffer> array_buffer,Isolate * isolate,size_t allocated_length,bool initialize,SharedFlag shared)18621 bool JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer> array_buffer,
18622                                         Isolate* isolate,
18623                                         size_t allocated_length,
18624                                         bool initialize, SharedFlag shared) {
18625   void* data;
18626   CHECK_NOT_NULL(isolate->array_buffer_allocator());
18627   if (allocated_length != 0) {
18628     if (allocated_length >= MB)
18629       isolate->counters()->array_buffer_big_allocations()->AddSample(
18630           ConvertToMb(allocated_length));
18631     if (shared == SharedFlag::kShared)
18632       isolate->counters()->shared_array_allocations()->AddSample(
18633           ConvertToMb(allocated_length));
18634     if (initialize) {
18635       data = isolate->array_buffer_allocator()->Allocate(allocated_length);
18636     } else {
18637       data = isolate->array_buffer_allocator()->AllocateUninitialized(
18638           allocated_length);
18639     }
18640     if (data == nullptr) {
18641       isolate->counters()->array_buffer_new_size_failures()->AddSample(
18642           ConvertToMb(allocated_length));
18643       return false;
18644     }
18645   } else {
18646     data = nullptr;
18647   }
18648 
18649   const bool is_external = false;
18650   JSArrayBuffer::Setup(array_buffer, isolate, is_external, data,
18651                        allocated_length, shared);
18652   return true;
18653 }
18654 
MaterializeArrayBuffer(Handle<JSTypedArray> typed_array)18655 Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
18656     Handle<JSTypedArray> typed_array) {
18657   DCHECK(typed_array->is_on_heap());
18658 
18659   Isolate* isolate = typed_array->GetIsolate();
18660 
18661   DCHECK(IsFixedTypedArrayElementsKind(typed_array->GetElementsKind()));
18662 
18663   Handle<FixedTypedArrayBase> fixed_typed_array(
18664       FixedTypedArrayBase::cast(typed_array->elements()));
18665 
18666   Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(typed_array->buffer()),
18667                                isolate);
18668   // This code does not know how to materialize from wasm buffers.
18669   DCHECK(!buffer->is_wasm_memory());
18670 
18671   void* backing_store =
18672       isolate->array_buffer_allocator()->AllocateUninitialized(
18673           fixed_typed_array->DataSize());
18674   buffer->set_is_external(false);
18675   DCHECK(buffer->byte_length()->IsSmi() ||
18676          buffer->byte_length()->IsHeapNumber());
18677   DCHECK(NumberToInt32(buffer->byte_length()) == fixed_typed_array->DataSize());
18678   // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
18679   // are currently being constructed in the |ArrayBufferTracker|. The
18680   // registration method below handles the case of registering a buffer that has
18681   // already been promoted.
18682   buffer->set_backing_store(backing_store);
18683   // RegisterNewArrayBuffer expects a valid length for adjusting counters.
18684   isolate->heap()->RegisterNewArrayBuffer(*buffer);
18685   memcpy(buffer->backing_store(),
18686          fixed_typed_array->DataPtr(),
18687          fixed_typed_array->DataSize());
18688   Handle<FixedTypedArrayBase> new_elements =
18689       isolate->factory()->NewFixedTypedArrayWithExternalPointer(
18690           fixed_typed_array->length(), typed_array->type(),
18691           static_cast<uint8_t*>(buffer->backing_store()));
18692 
18693   typed_array->set_elements(*new_elements);
18694   DCHECK(!typed_array->is_on_heap());
18695 
18696   return buffer;
18697 }
18698 
GetBuffer()18699 Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
18700   if (!is_on_heap()) {
18701     Handle<JSArrayBuffer> array_buffer(JSArrayBuffer::cast(buffer()));
18702     return array_buffer;
18703   }
18704   Handle<JSTypedArray> self(this);
18705   return MaterializeArrayBuffer(self);
18706 }
18707 
InvalidateEntry(Handle<GlobalDictionary> dictionary,int entry)18708 Handle<PropertyCell> PropertyCell::InvalidateEntry(
18709     Handle<GlobalDictionary> dictionary, int entry) {
18710   Isolate* isolate = dictionary->GetIsolate();
18711   // Swap with a copy.
18712   Handle<PropertyCell> cell(dictionary->CellAt(entry));
18713   Handle<Name> name(cell->name(), isolate);
18714   Handle<PropertyCell> new_cell = isolate->factory()->NewPropertyCell(name);
18715   new_cell->set_value(cell->value());
18716   dictionary->ValueAtPut(entry, *new_cell);
18717   bool is_the_hole = cell->value()->IsTheHole(isolate);
18718   // Cell is officially mutable henceforth.
18719   PropertyDetails details = cell->property_details();
18720   details = details.set_cell_type(is_the_hole ? PropertyCellType::kUninitialized
18721                                               : PropertyCellType::kMutable);
18722   new_cell->set_property_details(details);
18723   // Old cell is ready for invalidation.
18724   if (is_the_hole) {
18725     cell->set_value(isolate->heap()->undefined_value());
18726   } else {
18727     cell->set_value(isolate->heap()->the_hole_value());
18728   }
18729   details = details.set_cell_type(PropertyCellType::kInvalidated);
18730   cell->set_property_details(details);
18731   cell->dependent_code()->DeoptimizeDependentCodeGroup(
18732       isolate, DependentCode::kPropertyCellChangedGroup);
18733   return new_cell;
18734 }
18735 
18736 
GetConstantType()18737 PropertyCellConstantType PropertyCell::GetConstantType() {
18738   if (value()->IsSmi()) return PropertyCellConstantType::kSmi;
18739   return PropertyCellConstantType::kStableMap;
18740 }
18741 
18742 
RemainsConstantType(Handle<PropertyCell> cell,Handle<Object> value)18743 static bool RemainsConstantType(Handle<PropertyCell> cell,
18744                                 Handle<Object> value) {
18745   // TODO(dcarney): double->smi and smi->double transition from kConstant
18746   if (cell->value()->IsSmi() && value->IsSmi()) {
18747     return true;
18748   } else if (cell->value()->IsHeapObject() && value->IsHeapObject()) {
18749     return HeapObject::cast(cell->value())->map() ==
18750                HeapObject::cast(*value)->map() &&
18751            HeapObject::cast(*value)->map()->is_stable();
18752   }
18753   return false;
18754 }
18755 
18756 
UpdatedType(Handle<PropertyCell> cell,Handle<Object> value,PropertyDetails details)18757 PropertyCellType PropertyCell::UpdatedType(Handle<PropertyCell> cell,
18758                                            Handle<Object> value,
18759                                            PropertyDetails details) {
18760   PropertyCellType type = details.cell_type();
18761   Isolate* isolate = cell->GetIsolate();
18762   DCHECK(!value->IsTheHole(isolate));
18763   if (cell->value()->IsTheHole(isolate)) {
18764     switch (type) {
18765       // Only allow a cell to transition once into constant state.
18766       case PropertyCellType::kUninitialized:
18767         if (value->IsUndefined(isolate)) return PropertyCellType::kUndefined;
18768         return PropertyCellType::kConstant;
18769       case PropertyCellType::kInvalidated:
18770         return PropertyCellType::kMutable;
18771       default:
18772         UNREACHABLE();
18773     }
18774   }
18775   switch (type) {
18776     case PropertyCellType::kUndefined:
18777       return PropertyCellType::kConstant;
18778     case PropertyCellType::kConstant:
18779       if (*value == cell->value()) return PropertyCellType::kConstant;
18780       V8_FALLTHROUGH;
18781     case PropertyCellType::kConstantType:
18782       if (RemainsConstantType(cell, value)) {
18783         return PropertyCellType::kConstantType;
18784       }
18785       V8_FALLTHROUGH;
18786     case PropertyCellType::kMutable:
18787       return PropertyCellType::kMutable;
18788   }
18789   UNREACHABLE();
18790 }
18791 
PrepareForValue(Handle<GlobalDictionary> dictionary,int entry,Handle<Object> value,PropertyDetails details)18792 Handle<PropertyCell> PropertyCell::PrepareForValue(
18793     Handle<GlobalDictionary> dictionary, int entry, Handle<Object> value,
18794     PropertyDetails details) {
18795   Isolate* isolate = dictionary->GetIsolate();
18796   DCHECK(!value->IsTheHole(isolate));
18797   Handle<PropertyCell> cell(dictionary->CellAt(entry));
18798   const PropertyDetails original_details = cell->property_details();
18799   // Data accesses could be cached in ics or optimized code.
18800   bool invalidate =
18801       (original_details.kind() == kData && details.kind() == kAccessor) ||
18802       (!original_details.IsReadOnly() && details.IsReadOnly());
18803   int index;
18804   PropertyCellType old_type = original_details.cell_type();
18805   // Preserve the enumeration index unless the property was deleted or never
18806   // initialized.
18807   if (cell->value()->IsTheHole(isolate)) {
18808     index = dictionary->NextEnumerationIndex();
18809     dictionary->SetNextEnumerationIndex(index + 1);
18810   } else {
18811     index = original_details.dictionary_index();
18812   }
18813   DCHECK_LT(0, index);
18814   details = details.set_index(index);
18815 
18816   PropertyCellType new_type = UpdatedType(cell, value, original_details);
18817   if (invalidate) cell = PropertyCell::InvalidateEntry(dictionary, entry);
18818 
18819   // Install new property details.
18820   details = details.set_cell_type(new_type);
18821   cell->set_property_details(details);
18822 
18823   if (new_type == PropertyCellType::kConstant ||
18824       new_type == PropertyCellType::kConstantType) {
18825     // Store the value now to ensure that the cell contains the constant or
18826     // type information. Otherwise subsequent store operation will turn
18827     // the cell to mutable.
18828     cell->set_value(*value);
18829   }
18830 
18831   // Deopt when transitioning from a constant type.
18832   if (!invalidate && (old_type != new_type ||
18833                       original_details.IsReadOnly() != details.IsReadOnly())) {
18834     cell->dependent_code()->DeoptimizeDependentCodeGroup(
18835         isolate, DependentCode::kPropertyCellChangedGroup);
18836   }
18837   return cell;
18838 }
18839 
18840 
18841 // static
SetValueWithInvalidation(Handle<PropertyCell> cell,Handle<Object> new_value)18842 void PropertyCell::SetValueWithInvalidation(Handle<PropertyCell> cell,
18843                                             Handle<Object> new_value) {
18844   if (cell->value() != *new_value) {
18845     cell->set_value(*new_value);
18846     Isolate* isolate = cell->GetIsolate();
18847     cell->dependent_code()->DeoptimizeDependentCodeGroup(
18848         isolate, DependentCode::kPropertyCellChangedGroup);
18849   }
18850 }
18851 
source_position() const18852 int JSGeneratorObject::source_position() const {
18853   CHECK(is_suspended());
18854   DCHECK(function()->shared()->HasBytecodeArray());
18855 
18856   int code_offset = Smi::ToInt(input_or_debug_pos());
18857 
18858   // The stored bytecode offset is relative to a different base than what
18859   // is used in the source position table, hence the subtraction.
18860   code_offset -= BytecodeArray::kHeaderSize - kHeapObjectTag;
18861   AbstractCode* code =
18862       AbstractCode::cast(function()->shared()->GetBytecodeArray());
18863   return code->SourcePosition(code_offset);
18864 }
18865 
18866 // static
Get(Isolate * isolate,Handle<JSObject> receiver)18867 AccessCheckInfo* AccessCheckInfo::Get(Isolate* isolate,
18868                                       Handle<JSObject> receiver) {
18869   DisallowHeapAllocation no_gc;
18870   DCHECK(receiver->map()->is_access_check_needed());
18871   Object* maybe_constructor = receiver->map()->GetConstructor();
18872   if (maybe_constructor->IsFunctionTemplateInfo()) {
18873     Object* data_obj =
18874         FunctionTemplateInfo::cast(maybe_constructor)->access_check_info();
18875     if (data_obj->IsUndefined(isolate)) return nullptr;
18876     return AccessCheckInfo::cast(data_obj);
18877   }
18878   // Might happen for a detached context.
18879   if (!maybe_constructor->IsJSFunction()) return nullptr;
18880   JSFunction* constructor = JSFunction::cast(maybe_constructor);
18881   // Might happen for the debug context.
18882   if (!constructor->shared()->IsApiFunction()) return nullptr;
18883 
18884   Object* data_obj =
18885       constructor->shared()->get_api_func_data()->access_check_info();
18886   if (data_obj->IsUndefined(isolate)) return nullptr;
18887 
18888   return AccessCheckInfo::cast(data_obj);
18889 }
18890 
HasProxyInPrototype(Isolate * isolate)18891 bool JSReceiver::HasProxyInPrototype(Isolate* isolate) {
18892   for (PrototypeIterator iter(isolate, this, kStartAtReceiver,
18893                               PrototypeIterator::END_AT_NULL);
18894        !iter.IsAtEnd(); iter.AdvanceIgnoringProxies()) {
18895     if (iter.GetCurrent<Object>()->IsJSProxy()) return true;
18896   }
18897   return false;
18898 }
18899 
HasComplexElements()18900 bool JSReceiver::HasComplexElements() {
18901   if (IsJSProxy()) return true;
18902   JSObject* this_object = JSObject::cast(this);
18903   if (this_object->HasIndexedInterceptor()) {
18904     return true;
18905   }
18906   if (!this_object->HasDictionaryElements()) return false;
18907   return this_object->element_dictionary()->HasComplexElements();
18908 }
18909 
TryGetCachedPropertyName(Isolate * isolate,Handle<Object> getter)18910 MaybeHandle<Name> FunctionTemplateInfo::TryGetCachedPropertyName(
18911     Isolate* isolate, Handle<Object> getter) {
18912   if (getter->IsFunctionTemplateInfo()) {
18913     Handle<FunctionTemplateInfo> fti =
18914         Handle<FunctionTemplateInfo>::cast(getter);
18915     // Check if the accessor uses a cached property.
18916     if (!fti->cached_property_name()->IsTheHole(isolate)) {
18917       return handle(Name::cast(fti->cached_property_name()));
18918     }
18919   }
18920   return MaybeHandle<Name>();
18921 }
18922 
18923 }  // namespace internal
18924 }  // namespace v8
18925