• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/objects.h"
6 
7 #include <cmath>
8 #include <iomanip>
9 #include <memory>
10 #include <sstream>
11 #include <unordered_map>
12 #include <unordered_set>
13 
14 #include "src/objects-inl.h"
15 
16 #include "src/accessors.h"
17 #include "src/allocation-site-scopes.h"
18 #include "src/api-arguments-inl.h"
19 #include "src/api-natives.h"
20 #include "src/api.h"
21 #include "src/arguments.h"
22 #include "src/base/bits.h"
23 #include "src/base/utils/random-number-generator.h"
24 #include "src/bootstrapper.h"
25 #include "src/code-stubs.h"
26 #include "src/codegen.h"
27 #include "src/compilation-dependencies.h"
28 #include "src/compiler.h"
29 #include "src/counters-inl.h"
30 #include "src/counters.h"
31 #include "src/date.h"
32 #include "src/debug/debug-evaluate.h"
33 #include "src/debug/debug.h"
34 #include "src/deoptimizer.h"
35 #include "src/elements.h"
36 #include "src/execution.h"
37 #include "src/field-index-inl.h"
38 #include "src/field-index.h"
39 #include "src/field-type.h"
40 #include "src/frames-inl.h"
41 #include "src/full-codegen/full-codegen.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/list.h"
51 #include "src/log.h"
52 #include "src/lookup.h"
53 #include "src/macro-assembler.h"
54 #include "src/map-updater.h"
55 #include "src/messages.h"
56 #include "src/objects-body-descriptors-inl.h"
57 #include "src/property-descriptor.h"
58 #include "src/prototype.h"
59 #include "src/regexp/jsregexp.h"
60 #include "src/safepoint-table.h"
61 #include "src/snapshot/code-serializer.h"
62 #include "src/source-position-table.h"
63 #include "src/string-builder.h"
64 #include "src/string-search.h"
65 #include "src/string-stream.h"
66 #include "src/utils.h"
67 #include "src/wasm/wasm-module.h"
68 #include "src/wasm/wasm-objects.h"
69 #include "src/zone/zone.h"
70 
71 #ifdef ENABLE_DISASSEMBLER
72 #include "src/disasm.h"
73 #include "src/disassembler.h"
74 #include "src/eh-frame.h"
75 #endif
76 
77 namespace v8 {
78 namespace internal {
79 
operator <<(std::ostream & os,InstanceType instance_type)80 std::ostream& operator<<(std::ostream& os, InstanceType instance_type) {
81   switch (instance_type) {
82 #define WRITE_TYPE(TYPE) \
83   case TYPE:             \
84     return os << #TYPE;
85     INSTANCE_TYPE_LIST(WRITE_TYPE)
86 #undef WRITE_TYPE
87   }
88   UNREACHABLE();
89   return os << "UNKNOWN";  // Keep the compiler happy.
90 }
91 
OptimalType(Isolate * isolate,Representation representation)92 Handle<FieldType> Object::OptimalType(Isolate* isolate,
93                                       Representation representation) {
94   if (representation.IsNone()) return FieldType::None(isolate);
95   if (FLAG_track_field_types) {
96     if (representation.IsHeapObject() && IsHeapObject()) {
97       // We can track only JavaScript objects with stable maps.
98       Handle<Map> map(HeapObject::cast(this)->map(), isolate);
99       if (map->is_stable() && map->IsJSReceiverMap()) {
100         return FieldType::Class(map, isolate);
101       }
102     }
103   }
104   return FieldType::Any(isolate);
105 }
106 
107 
ToObject(Isolate * isolate,Handle<Object> object,Handle<Context> native_context)108 MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
109                                          Handle<Object> object,
110                                          Handle<Context> native_context) {
111   if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
112   Handle<JSFunction> constructor;
113   if (object->IsSmi()) {
114     constructor = handle(native_context->number_function(), isolate);
115   } else {
116     int constructor_function_index =
117         Handle<HeapObject>::cast(object)->map()->GetConstructorFunctionIndex();
118     if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
119       THROW_NEW_ERROR(isolate,
120                       NewTypeError(MessageTemplate::kUndefinedOrNullToObject),
121                       JSReceiver);
122     }
123     constructor = handle(
124         JSFunction::cast(native_context->get(constructor_function_index)),
125         isolate);
126   }
127   Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
128   Handle<JSValue>::cast(result)->set_value(*object);
129   return result;
130 }
131 
132 // ES6 section 9.2.1.2, OrdinaryCallBindThis for sloppy callee.
133 // static
ConvertReceiver(Isolate * isolate,Handle<Object> object)134 MaybeHandle<JSReceiver> Object::ConvertReceiver(Isolate* isolate,
135                                                 Handle<Object> object) {
136   if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
137   if (*object == isolate->heap()->null_value() ||
138       object->IsUndefined(isolate)) {
139     return isolate->global_proxy();
140   }
141   return Object::ToObject(isolate, object);
142 }
143 
144 // static
ConvertToNumber(Isolate * isolate,Handle<Object> input)145 MaybeHandle<Object> Object::ConvertToNumber(Isolate* isolate,
146                                             Handle<Object> input) {
147   while (true) {
148     if (input->IsNumber()) {
149       return input;
150     }
151     if (input->IsString()) {
152       return String::ToNumber(Handle<String>::cast(input));
153     }
154     if (input->IsOddball()) {
155       return Oddball::ToNumber(Handle<Oddball>::cast(input));
156     }
157     if (input->IsSymbol()) {
158       THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber),
159                       Object);
160     }
161     ASSIGN_RETURN_ON_EXCEPTION(
162         isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
163                                                 ToPrimitiveHint::kNumber),
164         Object);
165   }
166 }
167 
168 // static
ConvertToInteger(Isolate * isolate,Handle<Object> input)169 MaybeHandle<Object> Object::ConvertToInteger(Isolate* isolate,
170                                              Handle<Object> input) {
171   ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ConvertToNumber(isolate, input),
172                              Object);
173   if (input->IsSmi()) return input;
174   return isolate->factory()->NewNumber(DoubleToInteger(input->Number()));
175 }
176 
177 // static
ConvertToInt32(Isolate * isolate,Handle<Object> input)178 MaybeHandle<Object> Object::ConvertToInt32(Isolate* isolate,
179                                            Handle<Object> input) {
180   ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ConvertToNumber(isolate, input),
181                              Object);
182   if (input->IsSmi()) return input;
183   return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number()));
184 }
185 
186 // static
ConvertToUint32(Isolate * isolate,Handle<Object> input)187 MaybeHandle<Object> Object::ConvertToUint32(Isolate* isolate,
188                                             Handle<Object> input) {
189   ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ConvertToNumber(isolate, input),
190                              Object);
191   if (input->IsSmi()) return handle(Smi::cast(*input)->ToUint32Smi(), isolate);
192   return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number()));
193 }
194 
195 // static
ConvertToName(Isolate * isolate,Handle<Object> input)196 MaybeHandle<Name> Object::ConvertToName(Isolate* isolate,
197                                         Handle<Object> input) {
198   ASSIGN_RETURN_ON_EXCEPTION(
199       isolate, input, Object::ToPrimitive(input, ToPrimitiveHint::kString),
200       Name);
201   if (input->IsName()) return Handle<Name>::cast(input);
202   return ToString(isolate, input);
203 }
204 
205 // ES6 7.1.14
206 // static
ConvertToPropertyKey(Isolate * isolate,Handle<Object> value)207 MaybeHandle<Object> Object::ConvertToPropertyKey(Isolate* isolate,
208                                                  Handle<Object> value) {
209   // 1. Let key be ToPrimitive(argument, hint String).
210   MaybeHandle<Object> maybe_key =
211       Object::ToPrimitive(value, ToPrimitiveHint::kString);
212   // 2. ReturnIfAbrupt(key).
213   Handle<Object> key;
214   if (!maybe_key.ToHandle(&key)) return key;
215   // 3. If Type(key) is Symbol, then return key.
216   if (key->IsSymbol()) return key;
217   // 4. Return ToString(key).
218   // Extending spec'ed behavior, we'd be happy to return an element index.
219   if (key->IsSmi()) return key;
220   if (key->IsHeapNumber()) {
221     uint32_t uint_value;
222     if (value->ToArrayLength(&uint_value) &&
223         uint_value <= static_cast<uint32_t>(Smi::kMaxValue)) {
224       return handle(Smi::FromInt(static_cast<int>(uint_value)), isolate);
225     }
226   }
227   return Object::ToString(isolate, key);
228 }
229 
230 // static
ConvertToString(Isolate * isolate,Handle<Object> input)231 MaybeHandle<String> Object::ConvertToString(Isolate* isolate,
232                                             Handle<Object> input) {
233   while (true) {
234     if (input->IsOddball()) {
235       return handle(Handle<Oddball>::cast(input)->to_string(), isolate);
236     }
237     if (input->IsNumber()) {
238       return isolate->factory()->NumberToString(input);
239     }
240     if (input->IsSymbol()) {
241       THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToString),
242                       String);
243     }
244     ASSIGN_RETURN_ON_EXCEPTION(
245         isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
246                                                 ToPrimitiveHint::kString),
247         String);
248     // The previous isString() check happened in Object::ToString and thus we
249     // put it at the end of the loop in this helper.
250     if (input->IsString()) {
251       return Handle<String>::cast(input);
252     }
253   }
254 }
255 
256 namespace {
257 
IsErrorObject(Isolate * isolate,Handle<Object> object)258 bool IsErrorObject(Isolate* isolate, Handle<Object> object) {
259   if (!object->IsJSReceiver()) return false;
260   Handle<Symbol> symbol = isolate->factory()->stack_trace_symbol();
261   return JSReceiver::HasOwnProperty(Handle<JSReceiver>::cast(object), symbol)
262       .FromMaybe(false);
263 }
264 
AsStringOrEmpty(Isolate * isolate,Handle<Object> object)265 Handle<String> AsStringOrEmpty(Isolate* isolate, Handle<Object> object) {
266   return object->IsString() ? Handle<String>::cast(object)
267                             : isolate->factory()->empty_string();
268 }
269 
NoSideEffectsErrorToString(Isolate * isolate,Handle<Object> input)270 Handle<String> NoSideEffectsErrorToString(Isolate* isolate,
271                                           Handle<Object> input) {
272   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input);
273 
274   Handle<Name> name_key = isolate->factory()->name_string();
275   Handle<Object> name = JSReceiver::GetDataProperty(receiver, name_key);
276   Handle<String> name_str = AsStringOrEmpty(isolate, name);
277 
278   Handle<Name> msg_key = isolate->factory()->message_string();
279   Handle<Object> msg = JSReceiver::GetDataProperty(receiver, msg_key);
280   Handle<String> msg_str = AsStringOrEmpty(isolate, msg);
281 
282   if (name_str->length() == 0) return msg_str;
283   if (msg_str->length() == 0) return name_str;
284 
285   IncrementalStringBuilder builder(isolate);
286   builder.AppendString(name_str);
287   builder.AppendCString(": ");
288   builder.AppendString(msg_str);
289 
290   return builder.Finish().ToHandleChecked();
291 }
292 
293 }  // namespace
294 
295 // static
NoSideEffectsToString(Isolate * isolate,Handle<Object> input)296 Handle<String> Object::NoSideEffectsToString(Isolate* isolate,
297                                              Handle<Object> input) {
298   DisallowJavascriptExecution no_js(isolate);
299 
300   if (input->IsString() || input->IsNumber() || input->IsOddball()) {
301     return Object::ToString(isolate, input).ToHandleChecked();
302   } else if (input->IsFunction()) {
303     // -- F u n c t i o n
304     Handle<String> fun_str;
305     if (input->IsJSBoundFunction()) {
306       fun_str = JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(input));
307     } else {
308       DCHECK(input->IsJSFunction());
309       fun_str = JSFunction::ToString(Handle<JSFunction>::cast(input));
310     }
311 
312     if (fun_str->length() > 128) {
313       IncrementalStringBuilder builder(isolate);
314       builder.AppendString(isolate->factory()->NewSubString(fun_str, 0, 111));
315       builder.AppendCString("...<omitted>...");
316       builder.AppendString(isolate->factory()->NewSubString(
317           fun_str, fun_str->length() - 2, fun_str->length()));
318 
319       return builder.Finish().ToHandleChecked();
320     }
321     return fun_str;
322   } else if (input->IsSymbol()) {
323     // -- S y m b o l
324     Handle<Symbol> symbol = Handle<Symbol>::cast(input);
325 
326     IncrementalStringBuilder builder(isolate);
327     builder.AppendCString("Symbol(");
328     if (symbol->name()->IsString()) {
329       builder.AppendString(handle(String::cast(symbol->name()), isolate));
330     }
331     builder.AppendCharacter(')');
332 
333     return builder.Finish().ToHandleChecked();
334   } else if (input->IsJSReceiver()) {
335     // -- J S R e c e i v e r
336     Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input);
337     Handle<Object> to_string = JSReceiver::GetDataProperty(
338         receiver, isolate->factory()->toString_string());
339 
340     if (IsErrorObject(isolate, input) ||
341         *to_string == *isolate->error_to_string()) {
342       // When internally formatting error objects, use a side-effects-free
343       // version of Error.prototype.toString independent of the actually
344       // installed toString method.
345       return NoSideEffectsErrorToString(isolate, input);
346     } else if (*to_string == *isolate->object_to_string()) {
347       Handle<Object> ctor = JSReceiver::GetDataProperty(
348           receiver, isolate->factory()->constructor_string());
349       if (ctor->IsFunction()) {
350         Handle<String> ctor_name;
351         if (ctor->IsJSBoundFunction()) {
352           ctor_name = JSBoundFunction::GetName(
353                           isolate, Handle<JSBoundFunction>::cast(ctor))
354                           .ToHandleChecked();
355         } else if (ctor->IsJSFunction()) {
356           Handle<Object> ctor_name_obj =
357               JSFunction::GetName(isolate, Handle<JSFunction>::cast(ctor));
358           ctor_name = AsStringOrEmpty(isolate, ctor_name_obj);
359         }
360 
361         if (ctor_name->length() != 0) {
362           IncrementalStringBuilder builder(isolate);
363           builder.AppendCString("#<");
364           builder.AppendString(ctor_name);
365           builder.AppendCString(">");
366 
367           return builder.Finish().ToHandleChecked();
368         }
369       }
370     }
371   }
372 
373   // At this point, input is either none of the above or a JSReceiver.
374 
375   Handle<JSReceiver> receiver;
376   if (input->IsJSReceiver()) {
377     receiver = Handle<JSReceiver>::cast(input);
378   } else {
379     // This is the only case where Object::ToObject throws.
380     DCHECK(!input->IsSmi());
381     int constructor_function_index =
382         Handle<HeapObject>::cast(input)->map()->GetConstructorFunctionIndex();
383     if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
384       return isolate->factory()->NewStringFromAsciiChecked("[object Unknown]");
385     }
386 
387     receiver = Object::ToObject(isolate, input, isolate->native_context())
388                    .ToHandleChecked();
389   }
390 
391   Handle<String> builtin_tag = handle(receiver->class_name(), isolate);
392   Handle<Object> tag_obj = JSReceiver::GetDataProperty(
393       receiver, isolate->factory()->to_string_tag_symbol());
394   Handle<String> tag =
395       tag_obj->IsString() ? Handle<String>::cast(tag_obj) : builtin_tag;
396 
397   IncrementalStringBuilder builder(isolate);
398   builder.AppendCString("[object ");
399   builder.AppendString(tag);
400   builder.AppendCString("]");
401 
402   return builder.Finish().ToHandleChecked();
403 }
404 
405 // static
ConvertToLength(Isolate * isolate,Handle<Object> input)406 MaybeHandle<Object> Object::ConvertToLength(Isolate* isolate,
407                                             Handle<Object> input) {
408   ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
409   if (input->IsSmi()) {
410     int value = std::max(Smi::cast(*input)->value(), 0);
411     return handle(Smi::FromInt(value), isolate);
412   }
413   double len = DoubleToInteger(input->Number());
414   if (len <= 0.0) {
415     return handle(Smi::kZero, isolate);
416   } else if (len >= kMaxSafeInteger) {
417     len = kMaxSafeInteger;
418   }
419   return isolate->factory()->NewNumber(len);
420 }
421 
422 // static
ConvertToIndex(Isolate * isolate,Handle<Object> input,MessageTemplate::Template error_index)423 MaybeHandle<Object> Object::ConvertToIndex(
424     Isolate* isolate, Handle<Object> input,
425     MessageTemplate::Template error_index) {
426   if (input->IsUndefined(isolate)) return handle(Smi::kZero, isolate);
427   ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
428   if (input->IsSmi() && Smi::cast(*input)->value() >= 0) return input;
429   double len = DoubleToInteger(input->Number()) + 0.0;
430   auto js_len = isolate->factory()->NewNumber(len);
431   if (len < 0.0 || len > kMaxSafeInteger) {
432     THROW_NEW_ERROR(isolate, NewRangeError(error_index, js_len), Object);
433   }
434   return js_len;
435 }
436 
BooleanValue()437 bool Object::BooleanValue() {
438   if (IsSmi()) return Smi::cast(this)->value() != 0;
439   DCHECK(IsHeapObject());
440   Isolate* isolate = HeapObject::cast(this)->GetIsolate();
441   if (IsBoolean()) return IsTrue(isolate);
442   if (IsNullOrUndefined(isolate)) return false;
443   if (IsUndetectable()) return false;  // Undetectable object is false.
444   if (IsString()) return String::cast(this)->length() != 0;
445   if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue();
446   return true;
447 }
448 
449 
450 namespace {
451 
452 // TODO(bmeurer): Maybe we should introduce a marker interface Number,
453 // where we put all these methods at some point?
NumberCompare(double x,double y)454 ComparisonResult NumberCompare(double x, double y) {
455   if (std::isnan(x) || std::isnan(y)) {
456     return ComparisonResult::kUndefined;
457   } else if (x < y) {
458     return ComparisonResult::kLessThan;
459   } else if (x > y) {
460     return ComparisonResult::kGreaterThan;
461   } else {
462     return ComparisonResult::kEqual;
463   }
464 }
465 
466 
NumberEquals(double x,double y)467 bool NumberEquals(double x, double y) {
468   // Must check explicitly for NaN's on Windows, but -0 works fine.
469   if (std::isnan(x)) return false;
470   if (std::isnan(y)) return false;
471   return x == y;
472 }
473 
474 
NumberEquals(const Object * x,const Object * y)475 bool NumberEquals(const Object* x, const Object* y) {
476   return NumberEquals(x->Number(), y->Number());
477 }
478 
479 
NumberEquals(Handle<Object> x,Handle<Object> y)480 bool NumberEquals(Handle<Object> x, Handle<Object> y) {
481   return NumberEquals(*x, *y);
482 }
483 
484 }  // namespace
485 
486 
487 // static
Compare(Handle<Object> x,Handle<Object> y)488 Maybe<ComparisonResult> Object::Compare(Handle<Object> x, Handle<Object> y) {
489   // ES6 section 7.2.11 Abstract Relational Comparison step 3 and 4.
490   if (!Object::ToPrimitive(x, ToPrimitiveHint::kNumber).ToHandle(&x) ||
491       !Object::ToPrimitive(y, ToPrimitiveHint::kNumber).ToHandle(&y)) {
492     return Nothing<ComparisonResult>();
493   }
494   if (x->IsString() && y->IsString()) {
495     // ES6 section 7.2.11 Abstract Relational Comparison step 5.
496     return Just(
497         String::Compare(Handle<String>::cast(x), Handle<String>::cast(y)));
498   }
499   // ES6 section 7.2.11 Abstract Relational Comparison step 6.
500   if (!Object::ToNumber(x).ToHandle(&x) || !Object::ToNumber(y).ToHandle(&y)) {
501     return Nothing<ComparisonResult>();
502   }
503   return Just(NumberCompare(x->Number(), y->Number()));
504 }
505 
506 
507 // static
Equals(Handle<Object> x,Handle<Object> y)508 Maybe<bool> Object::Equals(Handle<Object> x, Handle<Object> y) {
509   // This is the generic version of Abstract Equality Comparison; a version in
510   // JavaScript land is available in the EqualStub and NotEqualStub. Whenever
511   // you change something functionality wise in here, remember to update the
512   // TurboFan code stubs as well.
513   while (true) {
514     if (x->IsNumber()) {
515       if (y->IsNumber()) {
516         return Just(NumberEquals(x, y));
517       } else if (y->IsBoolean()) {
518         return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
519       } else if (y->IsString()) {
520         return Just(NumberEquals(x, String::ToNumber(Handle<String>::cast(y))));
521       } else if (y->IsJSReceiver()) {
522         if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
523                  .ToHandle(&y)) {
524           return Nothing<bool>();
525         }
526       } else {
527         return Just(false);
528       }
529     } else if (x->IsString()) {
530       if (y->IsString()) {
531         return Just(
532             String::Equals(Handle<String>::cast(x), Handle<String>::cast(y)));
533       } else if (y->IsNumber()) {
534         x = String::ToNumber(Handle<String>::cast(x));
535         return Just(NumberEquals(x, y));
536       } else if (y->IsBoolean()) {
537         x = String::ToNumber(Handle<String>::cast(x));
538         return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
539       } else if (y->IsJSReceiver()) {
540         if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
541                  .ToHandle(&y)) {
542           return Nothing<bool>();
543         }
544       } else {
545         return Just(false);
546       }
547     } else if (x->IsBoolean()) {
548       if (y->IsOddball()) {
549         return Just(x.is_identical_to(y));
550       } else if (y->IsNumber()) {
551         return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
552       } else if (y->IsString()) {
553         y = String::ToNumber(Handle<String>::cast(y));
554         return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
555       } else if (y->IsJSReceiver()) {
556         if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
557                  .ToHandle(&y)) {
558           return Nothing<bool>();
559         }
560         x = Oddball::ToNumber(Handle<Oddball>::cast(x));
561       } else {
562         return Just(false);
563       }
564     } else if (x->IsSymbol()) {
565       if (y->IsSymbol()) {
566         return Just(x.is_identical_to(y));
567       } else if (y->IsJSReceiver()) {
568         if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
569                  .ToHandle(&y)) {
570           return Nothing<bool>();
571         }
572       } else {
573         return Just(false);
574       }
575     } else if (x->IsJSReceiver()) {
576       if (y->IsJSReceiver()) {
577         return Just(x.is_identical_to(y));
578       } else if (y->IsUndetectable()) {
579         return Just(x->IsUndetectable());
580       } else if (y->IsBoolean()) {
581         y = Oddball::ToNumber(Handle<Oddball>::cast(y));
582       } else if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(x))
583                       .ToHandle(&x)) {
584         return Nothing<bool>();
585       }
586     } else {
587       return Just(x->IsUndetectable() && y->IsUndetectable());
588     }
589   }
590 }
591 
592 
StrictEquals(Object * that)593 bool Object::StrictEquals(Object* that) {
594   if (this->IsNumber()) {
595     if (!that->IsNumber()) return false;
596     return NumberEquals(this, that);
597   } else if (this->IsString()) {
598     if (!that->IsString()) return false;
599     return String::cast(this)->Equals(String::cast(that));
600   }
601   return this == that;
602 }
603 
604 
605 // static
TypeOf(Isolate * isolate,Handle<Object> object)606 Handle<String> Object::TypeOf(Isolate* isolate, Handle<Object> object) {
607   if (object->IsNumber()) return isolate->factory()->number_string();
608   if (object->IsOddball()) return handle(Oddball::cast(*object)->type_of());
609   if (object->IsUndetectable()) {
610     return isolate->factory()->undefined_string();
611   }
612   if (object->IsString()) return isolate->factory()->string_string();
613   if (object->IsSymbol()) return isolate->factory()->symbol_string();
614   if (object->IsString()) return isolate->factory()->string_string();
615   if (object->IsCallable()) return isolate->factory()->function_string();
616   return isolate->factory()->object_string();
617 }
618 
619 
620 // static
Multiply(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)621 MaybeHandle<Object> Object::Multiply(Isolate* isolate, Handle<Object> lhs,
622                                      Handle<Object> rhs) {
623   if (!lhs->IsNumber() || !rhs->IsNumber()) {
624     ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
625     ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
626   }
627   return isolate->factory()->NewNumber(lhs->Number() * rhs->Number());
628 }
629 
630 
631 // static
Divide(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)632 MaybeHandle<Object> Object::Divide(Isolate* isolate, Handle<Object> lhs,
633                                    Handle<Object> rhs) {
634   if (!lhs->IsNumber() || !rhs->IsNumber()) {
635     ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
636     ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
637   }
638   return isolate->factory()->NewNumber(lhs->Number() / rhs->Number());
639 }
640 
641 
642 // static
Modulus(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)643 MaybeHandle<Object> Object::Modulus(Isolate* isolate, Handle<Object> lhs,
644                                     Handle<Object> rhs) {
645   if (!lhs->IsNumber() || !rhs->IsNumber()) {
646     ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
647     ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
648   }
649   return isolate->factory()->NewNumber(modulo(lhs->Number(), rhs->Number()));
650 }
651 
652 
653 // static
Add(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)654 MaybeHandle<Object> Object::Add(Isolate* isolate, Handle<Object> lhs,
655                                 Handle<Object> rhs) {
656   if (lhs->IsNumber() && rhs->IsNumber()) {
657     return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
658   } else if (lhs->IsString() && rhs->IsString()) {
659     return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
660                                              Handle<String>::cast(rhs));
661   }
662   ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToPrimitive(lhs), Object);
663   ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToPrimitive(rhs), Object);
664   if (lhs->IsString() || rhs->IsString()) {
665     ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToString(isolate, rhs),
666                                Object);
667     ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToString(isolate, lhs),
668                                Object);
669     return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
670                                              Handle<String>::cast(rhs));
671   }
672   ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
673   ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
674   return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
675 }
676 
677 
678 // static
Subtract(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)679 MaybeHandle<Object> Object::Subtract(Isolate* isolate, Handle<Object> lhs,
680                                      Handle<Object> rhs) {
681   if (!lhs->IsNumber() || !rhs->IsNumber()) {
682     ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
683     ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
684   }
685   return isolate->factory()->NewNumber(lhs->Number() - rhs->Number());
686 }
687 
688 
689 // static
ShiftLeft(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)690 MaybeHandle<Object> Object::ShiftLeft(Isolate* isolate, Handle<Object> lhs,
691                                       Handle<Object> rhs) {
692   if (!lhs->IsNumber() || !rhs->IsNumber()) {
693     ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
694     ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
695   }
696   return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs)
697                                               << (NumberToUint32(*rhs) & 0x1F));
698 }
699 
700 
701 // static
ShiftRight(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)702 MaybeHandle<Object> Object::ShiftRight(Isolate* isolate, Handle<Object> lhs,
703                                        Handle<Object> rhs) {
704   if (!lhs->IsNumber() || !rhs->IsNumber()) {
705     ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
706     ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
707   }
708   return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) >>
709                                               (NumberToUint32(*rhs) & 0x1F));
710 }
711 
712 
713 // static
ShiftRightLogical(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)714 MaybeHandle<Object> Object::ShiftRightLogical(Isolate* isolate,
715                                               Handle<Object> lhs,
716                                               Handle<Object> rhs) {
717   if (!lhs->IsNumber() || !rhs->IsNumber()) {
718     ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
719     ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
720   }
721   return isolate->factory()->NewNumberFromUint(NumberToUint32(*lhs) >>
722                                                (NumberToUint32(*rhs) & 0x1F));
723 }
724 
725 
726 // static
BitwiseAnd(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)727 MaybeHandle<Object> Object::BitwiseAnd(Isolate* isolate, Handle<Object> lhs,
728                                        Handle<Object> rhs) {
729   if (!lhs->IsNumber() || !rhs->IsNumber()) {
730     ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
731     ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
732   }
733   return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) &
734                                               NumberToInt32(*rhs));
735 }
736 
737 
738 // static
BitwiseOr(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)739 MaybeHandle<Object> Object::BitwiseOr(Isolate* isolate, Handle<Object> lhs,
740                                       Handle<Object> rhs) {
741   if (!lhs->IsNumber() || !rhs->IsNumber()) {
742     ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
743     ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
744   }
745   return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) |
746                                               NumberToInt32(*rhs));
747 }
748 
749 
750 // static
BitwiseXor(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)751 MaybeHandle<Object> Object::BitwiseXor(Isolate* isolate, Handle<Object> lhs,
752                                        Handle<Object> rhs) {
753   if (!lhs->IsNumber() || !rhs->IsNumber()) {
754     ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
755     ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
756   }
757   return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) ^
758                                               NumberToInt32(*rhs));
759 }
760 
761 // static
OrdinaryHasInstance(Isolate * isolate,Handle<Object> callable,Handle<Object> object)762 MaybeHandle<Object> Object::OrdinaryHasInstance(Isolate* isolate,
763                                                 Handle<Object> callable,
764                                                 Handle<Object> object) {
765   // The {callable} must have a [[Call]] internal method.
766   if (!callable->IsCallable()) return isolate->factory()->false_value();
767 
768   // Check if {callable} is a bound function, and if so retrieve its
769   // [[BoundTargetFunction]] and use that instead of {callable}.
770   if (callable->IsJSBoundFunction()) {
771     Handle<Object> bound_callable(
772         Handle<JSBoundFunction>::cast(callable)->bound_target_function(),
773         isolate);
774     return Object::InstanceOf(isolate, object, bound_callable);
775   }
776 
777   // If {object} is not a receiver, return false.
778   if (!object->IsJSReceiver()) return isolate->factory()->false_value();
779 
780   // Get the "prototype" of {callable}; raise an error if it's not a receiver.
781   Handle<Object> prototype;
782   ASSIGN_RETURN_ON_EXCEPTION(
783       isolate, prototype,
784       Object::GetProperty(callable, isolate->factory()->prototype_string()),
785       Object);
786   if (!prototype->IsJSReceiver()) {
787     THROW_NEW_ERROR(
788         isolate,
789         NewTypeError(MessageTemplate::kInstanceofNonobjectProto, prototype),
790         Object);
791   }
792 
793   // Return whether or not {prototype} is in the prototype chain of {object}.
794   Maybe<bool> result = JSReceiver::HasInPrototypeChain(
795       isolate, Handle<JSReceiver>::cast(object), prototype);
796   if (result.IsNothing()) return MaybeHandle<Object>();
797   return isolate->factory()->ToBoolean(result.FromJust());
798 }
799 
800 // static
InstanceOf(Isolate * isolate,Handle<Object> object,Handle<Object> callable)801 MaybeHandle<Object> Object::InstanceOf(Isolate* isolate, Handle<Object> object,
802                                        Handle<Object> callable) {
803   // The {callable} must be a receiver.
804   if (!callable->IsJSReceiver()) {
805     THROW_NEW_ERROR(isolate,
806                     NewTypeError(MessageTemplate::kNonObjectInInstanceOfCheck),
807                     Object);
808   }
809 
810   // Lookup the @@hasInstance method on {callable}.
811   Handle<Object> inst_of_handler;
812   ASSIGN_RETURN_ON_EXCEPTION(
813       isolate, inst_of_handler,
814       JSReceiver::GetMethod(Handle<JSReceiver>::cast(callable),
815                             isolate->factory()->has_instance_symbol()),
816       Object);
817   if (!inst_of_handler->IsUndefined(isolate)) {
818     // Call the {inst_of_handler} on the {callable}.
819     Handle<Object> result;
820     ASSIGN_RETURN_ON_EXCEPTION(
821         isolate, result,
822         Execution::Call(isolate, inst_of_handler, callable, 1, &object),
823         Object);
824     return isolate->factory()->ToBoolean(result->BooleanValue());
825   }
826 
827   // The {callable} must have a [[Call]] internal method.
828   if (!callable->IsCallable()) {
829     THROW_NEW_ERROR(
830         isolate, NewTypeError(MessageTemplate::kNonCallableInInstanceOfCheck),
831         Object);
832   }
833 
834   // Fall back to OrdinaryHasInstance with {callable} and {object}.
835   Handle<Object> result;
836   ASSIGN_RETURN_ON_EXCEPTION(
837       isolate, result,
838       JSReceiver::OrdinaryHasInstance(isolate, callable, object), Object);
839   return result;
840 }
841 
IsArray(Handle<Object> object)842 Maybe<bool> Object::IsArray(Handle<Object> object) {
843   if (object->IsJSArray()) return Just(true);
844   if (object->IsJSProxy()) {
845     Handle<JSProxy> proxy = Handle<JSProxy>::cast(object);
846     Isolate* isolate = proxy->GetIsolate();
847     if (proxy->IsRevoked()) {
848       isolate->Throw(*isolate->factory()->NewTypeError(
849           MessageTemplate::kProxyRevoked,
850           isolate->factory()->NewStringFromAsciiChecked("IsArray")));
851       return Nothing<bool>();
852     }
853     return Object::IsArray(handle(proxy->target(), isolate));
854   }
855   return Just(false);
856 }
857 
858 
859 // static
GetMethod(Handle<JSReceiver> receiver,Handle<Name> name)860 MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
861                                       Handle<Name> name) {
862   Handle<Object> func;
863   Isolate* isolate = receiver->GetIsolate();
864   ASSIGN_RETURN_ON_EXCEPTION(isolate, func,
865                              JSReceiver::GetProperty(receiver, name), Object);
866   if (func->IsNullOrUndefined(isolate)) {
867     return isolate->factory()->undefined_value();
868   }
869   if (!func->IsCallable()) {
870     THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kPropertyNotFunction,
871                                           func, name, receiver),
872                     Object);
873   }
874   return func;
875 }
876 
877 namespace {
CreateListFromArrayLikeFastPath(Isolate * isolate,Handle<Object> object,ElementTypes element_types)878 MaybeHandle<FixedArray> CreateListFromArrayLikeFastPath(
879     Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
880   if (element_types != ElementTypes::kAll || !object->IsJSArray()) {
881     return MaybeHandle<FixedArray>();
882   }
883   Handle<JSArray> array = Handle<JSArray>::cast(object);
884   uint32_t length;
885   if (!array->HasArrayPrototype(isolate) ||
886       !array->length()->ToUint32(&length) || !array->HasFastElements() ||
887       !JSObject::PrototypeHasNoElements(isolate, *array)) {
888     return MaybeHandle<FixedArray>();
889   }
890   return array->GetElementsAccessor()->CreateListFromArray(isolate, array);
891 }
892 }  // namespace
893 
894 // static
CreateListFromArrayLike(Isolate * isolate,Handle<Object> object,ElementTypes element_types)895 MaybeHandle<FixedArray> Object::CreateListFromArrayLike(
896     Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
897   // Fast-path for JS_ARRAY_TYPE.
898   MaybeHandle<FixedArray> fast_result =
899       CreateListFromArrayLikeFastPath(isolate, object, element_types);
900   if (!fast_result.is_null()) return fast_result;
901   // 1. ReturnIfAbrupt(object).
902   // 2. (default elementTypes -- not applicable.)
903   // 3. If Type(obj) is not Object, throw a TypeError exception.
904   if (!object->IsJSReceiver()) {
905     THROW_NEW_ERROR(isolate,
906                     NewTypeError(MessageTemplate::kCalledOnNonObject,
907                                  isolate->factory()->NewStringFromAsciiChecked(
908                                      "CreateListFromArrayLike")),
909                     FixedArray);
910   }
911 
912   // 4. Let len be ? ToLength(? Get(obj, "length")).
913   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
914   Handle<Object> raw_length_number;
915   ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number,
916                              Object::GetLengthFromArrayLike(isolate, receiver),
917                              FixedArray);
918   uint32_t len;
919   if (!raw_length_number->ToUint32(&len) ||
920       len > static_cast<uint32_t>(FixedArray::kMaxLength)) {
921     THROW_NEW_ERROR(isolate,
922                     NewRangeError(MessageTemplate::kInvalidArrayLength),
923                     FixedArray);
924   }
925   // 5. Let list be an empty List.
926   Handle<FixedArray> list = isolate->factory()->NewFixedArray(len);
927   // 6. Let index be 0.
928   // 7. Repeat while index < len:
929   for (uint32_t index = 0; index < len; ++index) {
930     // 7a. Let indexName be ToString(index).
931     // 7b. Let next be ? Get(obj, indexName).
932     Handle<Object> next;
933     ASSIGN_RETURN_ON_EXCEPTION(isolate, next,
934                                JSReceiver::GetElement(isolate, receiver, index),
935                                FixedArray);
936     switch (element_types) {
937       case ElementTypes::kAll:
938         // Nothing to do.
939         break;
940       case ElementTypes::kStringAndSymbol: {
941         // 7c. If Type(next) is not an element of elementTypes, throw a
942         //     TypeError exception.
943         if (!next->IsName()) {
944           THROW_NEW_ERROR(isolate,
945                           NewTypeError(MessageTemplate::kNotPropertyName, next),
946                           FixedArray);
947         }
948         // 7d. Append next as the last element of list.
949         // Internalize on the fly so we can use pointer identity later.
950         next = isolate->factory()->InternalizeName(Handle<Name>::cast(next));
951         break;
952       }
953     }
954     list->set(index, *next);
955     // 7e. Set index to index + 1. (See loop header.)
956   }
957   // 8. Return list.
958   return list;
959 }
960 
961 
962 // static
GetLengthFromArrayLike(Isolate * isolate,Handle<Object> object)963 MaybeHandle<Object> Object::GetLengthFromArrayLike(Isolate* isolate,
964                                                    Handle<Object> object) {
965   Handle<Object> val;
966   Handle<Object> key = isolate->factory()->length_string();
967   ASSIGN_RETURN_ON_EXCEPTION(
968       isolate, val, Runtime::GetObjectProperty(isolate, object, key), Object);
969   return Object::ToLength(isolate, val);
970 }
971 
972 // static
HasProperty(LookupIterator * it)973 Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) {
974   for (; it->IsFound(); it->Next()) {
975     switch (it->state()) {
976       case LookupIterator::NOT_FOUND:
977       case LookupIterator::TRANSITION:
978         UNREACHABLE();
979       case LookupIterator::JSPROXY:
980         return JSProxy::HasProperty(it->isolate(), it->GetHolder<JSProxy>(),
981                                     it->GetName());
982       case LookupIterator::INTERCEPTOR: {
983         Maybe<PropertyAttributes> result =
984             JSObject::GetPropertyAttributesWithInterceptor(it);
985         if (result.IsNothing()) return Nothing<bool>();
986         if (result.FromJust() != ABSENT) return Just(true);
987         break;
988       }
989       case LookupIterator::ACCESS_CHECK: {
990         if (it->HasAccess()) break;
991         Maybe<PropertyAttributes> result =
992             JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
993         if (result.IsNothing()) return Nothing<bool>();
994         return Just(result.FromJust() != ABSENT);
995       }
996       case LookupIterator::INTEGER_INDEXED_EXOTIC:
997         // TypedArray out-of-bounds access.
998         return Just(false);
999       case LookupIterator::ACCESSOR:
1000       case LookupIterator::DATA:
1001         return Just(true);
1002     }
1003   }
1004   return Just(false);
1005 }
1006 
1007 
1008 // static
GetProperty(LookupIterator * it)1009 MaybeHandle<Object> Object::GetProperty(LookupIterator* it) {
1010   for (; it->IsFound(); it->Next()) {
1011     switch (it->state()) {
1012       case LookupIterator::NOT_FOUND:
1013       case LookupIterator::TRANSITION:
1014         UNREACHABLE();
1015       case LookupIterator::JSPROXY: {
1016         bool was_found;
1017         MaybeHandle<Object> result =
1018             JSProxy::GetProperty(it->isolate(), it->GetHolder<JSProxy>(),
1019                                  it->GetName(), it->GetReceiver(), &was_found);
1020         if (!was_found) it->NotFound();
1021         return result;
1022       }
1023       case LookupIterator::INTERCEPTOR: {
1024         bool done;
1025         Handle<Object> result;
1026         ASSIGN_RETURN_ON_EXCEPTION(
1027             it->isolate(), result,
1028             JSObject::GetPropertyWithInterceptor(it, &done), Object);
1029         if (done) return result;
1030         break;
1031       }
1032       case LookupIterator::ACCESS_CHECK:
1033         if (it->HasAccess()) break;
1034         return JSObject::GetPropertyWithFailedAccessCheck(it);
1035       case LookupIterator::ACCESSOR:
1036         return GetPropertyWithAccessor(it);
1037       case LookupIterator::INTEGER_INDEXED_EXOTIC:
1038         return it->isolate()->factory()->undefined_value();
1039       case LookupIterator::DATA:
1040         return it->GetDataValue();
1041     }
1042   }
1043   return it->isolate()->factory()->undefined_value();
1044 }
1045 
1046 
1047 // static
GetProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Name> name,Handle<Object> receiver,bool * was_found)1048 MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
1049                                          Handle<JSProxy> proxy,
1050                                          Handle<Name> name,
1051                                          Handle<Object> receiver,
1052                                          bool* was_found) {
1053   *was_found = true;
1054   if (receiver->IsJSGlobalObject()) {
1055     THROW_NEW_ERROR(
1056         isolate,
1057         NewTypeError(MessageTemplate::kReadGlobalReferenceThroughProxy, name),
1058         Object);
1059   }
1060 
1061   DCHECK(!name->IsPrivate());
1062   STACK_CHECK(isolate, MaybeHandle<Object>());
1063   Handle<Name> trap_name = isolate->factory()->get_string();
1064   // 1. Assert: IsPropertyKey(P) is true.
1065   // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
1066   Handle<Object> handler(proxy->handler(), isolate);
1067   // 3. If handler is null, throw a TypeError exception.
1068   // 4. Assert: Type(handler) is Object.
1069   if (proxy->IsRevoked()) {
1070     THROW_NEW_ERROR(isolate,
1071                     NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1072                     Object);
1073   }
1074   // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
1075   Handle<JSReceiver> target(proxy->target(), isolate);
1076   // 6. Let trap be ? GetMethod(handler, "get").
1077   Handle<Object> trap;
1078   ASSIGN_RETURN_ON_EXCEPTION(
1079       isolate, trap,
1080       Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), Object);
1081   // 7. If trap is undefined, then
1082   if (trap->IsUndefined(isolate)) {
1083     // 7.a Return target.[[Get]](P, Receiver).
1084     LookupIterator it =
1085         LookupIterator::PropertyOrElement(isolate, receiver, name, target);
1086     MaybeHandle<Object> result = Object::GetProperty(&it);
1087     *was_found = it.IsFound();
1088     return result;
1089   }
1090   // 8. Let trapResult be ? Call(trap, handler, «target, P, Receiver»).
1091   Handle<Object> trap_result;
1092   Handle<Object> args[] = {target, name, receiver};
1093   ASSIGN_RETURN_ON_EXCEPTION(
1094       isolate, trap_result,
1095       Execution::Call(isolate, trap, handler, arraysize(args), args), Object);
1096   // 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
1097   PropertyDescriptor target_desc;
1098   Maybe<bool> target_found =
1099       JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
1100   MAYBE_RETURN_NULL(target_found);
1101   // 10. If targetDesc is not undefined, then
1102   if (target_found.FromJust()) {
1103     // 10.a. If IsDataDescriptor(targetDesc) and targetDesc.[[Configurable]] is
1104     //       false and targetDesc.[[Writable]] is false, then
1105     // 10.a.i. If SameValue(trapResult, targetDesc.[[Value]]) is false,
1106     //        throw a TypeError exception.
1107     bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
1108                         !target_desc.configurable() &&
1109                         !target_desc.writable() &&
1110                         !trap_result->SameValue(*target_desc.value());
1111     if (inconsistent) {
1112       THROW_NEW_ERROR(
1113           isolate, NewTypeError(MessageTemplate::kProxyGetNonConfigurableData,
1114                                 name, target_desc.value(), trap_result),
1115           Object);
1116     }
1117     // 10.b. If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]]
1118     //       is false and targetDesc.[[Get]] is undefined, then
1119     // 10.b.i. If trapResult is not undefined, throw a TypeError exception.
1120     inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
1121                    !target_desc.configurable() &&
1122                    target_desc.get()->IsUndefined(isolate) &&
1123                    !trap_result->IsUndefined(isolate);
1124     if (inconsistent) {
1125       THROW_NEW_ERROR(
1126           isolate,
1127           NewTypeError(MessageTemplate::kProxyGetNonConfigurableAccessor, name,
1128                        trap_result),
1129           Object);
1130     }
1131   }
1132   // 11. Return trap_result
1133   return trap_result;
1134 }
1135 
1136 
GetDataProperty(LookupIterator * it)1137 Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it) {
1138   for (; it->IsFound(); it->Next()) {
1139     switch (it->state()) {
1140       case LookupIterator::INTERCEPTOR:
1141       case LookupIterator::NOT_FOUND:
1142       case LookupIterator::TRANSITION:
1143         UNREACHABLE();
1144       case LookupIterator::ACCESS_CHECK:
1145         // Support calling this method without an active context, but refuse
1146         // access to access-checked objects in that case.
1147         if (it->isolate()->context() != nullptr && it->HasAccess()) continue;
1148       // Fall through.
1149       case LookupIterator::JSPROXY:
1150         it->NotFound();
1151         return it->isolate()->factory()->undefined_value();
1152       case LookupIterator::ACCESSOR:
1153         // TODO(verwaest): For now this doesn't call into AccessorInfo, since
1154         // clients don't need it. Update once relevant.
1155         it->NotFound();
1156         return it->isolate()->factory()->undefined_value();
1157       case LookupIterator::INTEGER_INDEXED_EXOTIC:
1158         return it->isolate()->factory()->undefined_value();
1159       case LookupIterator::DATA:
1160         return it->GetDataValue();
1161     }
1162   }
1163   return it->isolate()->factory()->undefined_value();
1164 }
1165 
1166 
ToInt32(int32_t * value)1167 bool Object::ToInt32(int32_t* value) {
1168   if (IsSmi()) {
1169     *value = Smi::cast(this)->value();
1170     return true;
1171   }
1172   if (IsHeapNumber()) {
1173     double num = HeapNumber::cast(this)->value();
1174     if (FastI2D(FastD2I(num)) == num) {
1175       *value = FastD2I(num);
1176       return true;
1177     }
1178   }
1179   return false;
1180 }
1181 
GetOrCreateSharedFunctionInfo(Isolate * isolate,Handle<FunctionTemplateInfo> info)1182 Handle<SharedFunctionInfo> FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(
1183     Isolate* isolate, Handle<FunctionTemplateInfo> info) {
1184   Object* current_info = info->shared_function_info();
1185   if (current_info->IsSharedFunctionInfo()) {
1186     return handle(SharedFunctionInfo::cast(current_info), isolate);
1187   }
1188 
1189   Handle<Object> class_name(info->class_name(), isolate);
1190   Handle<String> name = class_name->IsString()
1191                             ? Handle<String>::cast(class_name)
1192                             : isolate->factory()->empty_string();
1193   Handle<Code> code;
1194   if (info->call_code()->IsCallHandlerInfo() &&
1195       CallHandlerInfo::cast(info->call_code())->fast_handler()->IsCode()) {
1196     code = isolate->builtins()->HandleFastApiCall();
1197   } else {
1198     code = isolate->builtins()->HandleApiCall();
1199   }
1200   bool is_constructor = !info->remove_prototype();
1201   Handle<SharedFunctionInfo> result =
1202       isolate->factory()->NewSharedFunctionInfo(name, code, is_constructor);
1203   if (is_constructor) {
1204     result->SetConstructStub(*isolate->builtins()->JSConstructStubApi());
1205   }
1206 
1207   result->set_length(info->length());
1208   if (class_name->IsString()) result->set_instance_class_name(*class_name);
1209   result->set_api_func_data(*info);
1210   result->DontAdaptArguments();
1211   DCHECK(result->IsApiFunction());
1212 
1213   info->set_shared_function_info(*result);
1214   return result;
1215 }
1216 
IsTemplateFor(Map * map)1217 bool FunctionTemplateInfo::IsTemplateFor(Map* map) {
1218   // There is a constraint on the object; check.
1219   if (!map->IsJSObjectMap()) return false;
1220   // Fetch the constructor function of the object.
1221   Object* cons_obj = map->GetConstructor();
1222   if (!cons_obj->IsJSFunction()) return false;
1223   JSFunction* fun = JSFunction::cast(cons_obj);
1224   // Iterate through the chain of inheriting function templates to
1225   // see if the required one occurs.
1226   for (Object* type = fun->shared()->function_data();
1227        type->IsFunctionTemplateInfo();
1228        type = FunctionTemplateInfo::cast(type)->parent_template()) {
1229     if (type == this) return true;
1230   }
1231   // Didn't find the required type in the inheritance chain.
1232   return false;
1233 }
1234 
1235 
1236 // static
New(Isolate * isolate,int size)1237 Handle<TemplateList> TemplateList::New(Isolate* isolate, int size) {
1238   Handle<FixedArray> list =
1239       isolate->factory()->NewFixedArray(kLengthIndex + size);
1240   list->set(kLengthIndex, Smi::kZero);
1241   return Handle<TemplateList>::cast(list);
1242 }
1243 
1244 // static
Add(Isolate * isolate,Handle<TemplateList> list,Handle<i::Object> value)1245 Handle<TemplateList> TemplateList::Add(Isolate* isolate,
1246                                        Handle<TemplateList> list,
1247                                        Handle<i::Object> value) {
1248   STATIC_ASSERT(kFirstElementIndex == 1);
1249   int index = list->length() + 1;
1250   Handle<i::FixedArray> fixed_array = Handle<FixedArray>::cast(list);
1251   fixed_array = FixedArray::SetAndGrow(fixed_array, index, value);
1252   fixed_array->set(kLengthIndex, Smi::FromInt(index));
1253   return Handle<TemplateList>::cast(fixed_array);
1254 }
1255 
1256 // static
New(Handle<JSFunction> constructor,Handle<JSReceiver> new_target,Handle<AllocationSite> site)1257 MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor,
1258                                     Handle<JSReceiver> new_target,
1259                                     Handle<AllocationSite> site) {
1260   // If called through new, new.target can be:
1261   // - a subclass of constructor,
1262   // - a proxy wrapper around constructor, or
1263   // - the constructor itself.
1264   // If called through Reflect.construct, it's guaranteed to be a constructor.
1265   Isolate* const isolate = constructor->GetIsolate();
1266   DCHECK(constructor->IsConstructor());
1267   DCHECK(new_target->IsConstructor());
1268   DCHECK(!constructor->has_initial_map() ||
1269          constructor->initial_map()->instance_type() != JS_FUNCTION_TYPE);
1270 
1271   Handle<Map> initial_map;
1272   ASSIGN_RETURN_ON_EXCEPTION(
1273       isolate, initial_map,
1274       JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject);
1275   Handle<JSObject> result =
1276       isolate->factory()->NewJSObjectFromMap(initial_map, NOT_TENURED, site);
1277   isolate->counters()->constructed_objects()->Increment();
1278   isolate->counters()->constructed_objects_runtime()->Increment();
1279   return result;
1280 }
1281 
EnsureWritableFastElements(Handle<JSObject> object)1282 void JSObject::EnsureWritableFastElements(Handle<JSObject> object) {
1283   DCHECK(object->HasFastSmiOrObjectElements() ||
1284          object->HasFastStringWrapperElements());
1285   FixedArray* raw_elems = FixedArray::cast(object->elements());
1286   Heap* heap = object->GetHeap();
1287   if (raw_elems->map() != heap->fixed_cow_array_map()) return;
1288   Isolate* isolate = heap->isolate();
1289   Handle<FixedArray> elems(raw_elems, isolate);
1290   Handle<FixedArray> writable_elems = isolate->factory()->CopyFixedArrayWithMap(
1291       elems, isolate->factory()->fixed_array_map());
1292   object->set_elements(*writable_elems);
1293   isolate->counters()->cow_arrays_converted()->Increment();
1294 }
1295 
1296 
1297 // ES6 9.5.1
1298 // static
GetPrototype(Handle<JSProxy> proxy)1299 MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
1300   Isolate* isolate = proxy->GetIsolate();
1301   Handle<String> trap_name = isolate->factory()->getPrototypeOf_string();
1302 
1303   STACK_CHECK(isolate, MaybeHandle<Object>());
1304 
1305   // 1. Let handler be the value of the [[ProxyHandler]] internal slot.
1306   // 2. If handler is null, throw a TypeError exception.
1307   // 3. Assert: Type(handler) is Object.
1308   // 4. Let target be the value of the [[ProxyTarget]] internal slot.
1309   if (proxy->IsRevoked()) {
1310     THROW_NEW_ERROR(isolate,
1311                     NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1312                     Object);
1313   }
1314   Handle<JSReceiver> target(proxy->target(), isolate);
1315   Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
1316 
1317   // 5. Let trap be ? GetMethod(handler, "getPrototypeOf").
1318   Handle<Object> trap;
1319   ASSIGN_RETURN_ON_EXCEPTION(isolate, trap, GetMethod(handler, trap_name),
1320                              Object);
1321   // 6. If trap is undefined, then return target.[[GetPrototypeOf]]().
1322   if (trap->IsUndefined(isolate)) {
1323     return JSReceiver::GetPrototype(isolate, target);
1324   }
1325   // 7. Let handlerProto be ? Call(trap, handler, «target»).
1326   Handle<Object> argv[] = {target};
1327   Handle<Object> handler_proto;
1328   ASSIGN_RETURN_ON_EXCEPTION(
1329       isolate, handler_proto,
1330       Execution::Call(isolate, trap, handler, arraysize(argv), argv), Object);
1331   // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError.
1332   if (!(handler_proto->IsJSReceiver() || handler_proto->IsNull(isolate))) {
1333     THROW_NEW_ERROR(isolate,
1334                     NewTypeError(MessageTemplate::kProxyGetPrototypeOfInvalid),
1335                     Object);
1336   }
1337   // 9. Let extensibleTarget be ? IsExtensible(target).
1338   Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
1339   MAYBE_RETURN_NULL(is_extensible);
1340   // 10. If extensibleTarget is true, return handlerProto.
1341   if (is_extensible.FromJust()) return handler_proto;
1342   // 11. Let targetProto be ? target.[[GetPrototypeOf]]().
1343   Handle<Object> target_proto;
1344   ASSIGN_RETURN_ON_EXCEPTION(isolate, target_proto,
1345                              JSReceiver::GetPrototype(isolate, target), Object);
1346   // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError.
1347   if (!handler_proto->SameValue(*target_proto)) {
1348     THROW_NEW_ERROR(
1349         isolate,
1350         NewTypeError(MessageTemplate::kProxyGetPrototypeOfNonExtensible),
1351         Object);
1352   }
1353   // 13. Return handlerProto.
1354   return handler_proto;
1355 }
1356 
GetPropertyWithAccessor(LookupIterator * it)1357 MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) {
1358   Isolate* isolate = it->isolate();
1359   Handle<Object> structure = it->GetAccessors();
1360   Handle<Object> receiver = it->GetReceiver();
1361 
1362   // We should never get here to initialize a const with the hole value since a
1363   // const declaration would conflict with the getter.
1364   DCHECK(!structure->IsForeign());
1365 
1366   // API style callbacks.
1367   if (structure->IsAccessorInfo()) {
1368     Handle<JSObject> holder = it->GetHolder<JSObject>();
1369     Handle<Name> name = it->GetName();
1370     Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
1371     if (!info->IsCompatibleReceiver(*receiver)) {
1372       THROW_NEW_ERROR(isolate,
1373                       NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
1374                                    name, receiver),
1375                       Object);
1376     }
1377 
1378     v8::AccessorNameGetterCallback call_fun =
1379         v8::ToCData<v8::AccessorNameGetterCallback>(info->getter());
1380     if (call_fun == nullptr) return isolate->factory()->undefined_value();
1381 
1382     if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1383       ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver,
1384                                  Object::ConvertReceiver(isolate, receiver),
1385                                  Object);
1386     }
1387 
1388     PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1389                                    Object::DONT_THROW);
1390     Handle<Object> result = args.Call(call_fun, name);
1391     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1392     if (result.is_null()) return isolate->factory()->undefined_value();
1393     Handle<Object> reboxed_result = handle(*result, isolate);
1394     if (info->replace_on_access() && receiver->IsJSReceiver()) {
1395       args.Call(reinterpret_cast<GenericNamedPropertySetterCallback>(
1396                     &Accessors::ReconfigureToDataProperty),
1397                 name, result);
1398       RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1399     }
1400     return reboxed_result;
1401   }
1402 
1403   // AccessorPair with 'cached' private property.
1404   if (it->TryLookupCachedProperty()) {
1405     return Object::GetProperty(it);
1406   }
1407 
1408   // Regular accessor.
1409   Handle<Object> getter(AccessorPair::cast(*structure)->getter(), isolate);
1410   if (getter->IsFunctionTemplateInfo()) {
1411     return Builtins::InvokeApiFunction(
1412         isolate, false, Handle<FunctionTemplateInfo>::cast(getter), receiver, 0,
1413         nullptr, isolate->factory()->undefined_value());
1414   } else if (getter->IsCallable()) {
1415     // TODO(rossberg): nicer would be to cast to some JSCallable here...
1416     return Object::GetPropertyWithDefinedGetter(
1417         receiver, Handle<JSReceiver>::cast(getter));
1418   }
1419   // Getter is not a function.
1420   return isolate->factory()->undefined_value();
1421 }
1422 
1423 // static
redirect(Isolate * isolate,Address address,AccessorComponent component)1424 Address AccessorInfo::redirect(Isolate* isolate, Address address,
1425                                AccessorComponent component) {
1426   ApiFunction fun(address);
1427   DCHECK_EQ(ACCESSOR_GETTER, component);
1428   ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
1429   return ExternalReference(&fun, type, isolate).address();
1430 }
1431 
redirected_getter() const1432 Address AccessorInfo::redirected_getter() const {
1433   Address accessor = v8::ToCData<Address>(getter());
1434   if (accessor == nullptr) return nullptr;
1435   return redirect(GetIsolate(), accessor, ACCESSOR_GETTER);
1436 }
1437 
IsCompatibleReceiverMap(Isolate * isolate,Handle<AccessorInfo> info,Handle<Map> map)1438 bool AccessorInfo::IsCompatibleReceiverMap(Isolate* isolate,
1439                                            Handle<AccessorInfo> info,
1440                                            Handle<Map> map) {
1441   if (!info->HasExpectedReceiverType()) return true;
1442   if (!map->IsJSObjectMap()) return false;
1443   return FunctionTemplateInfo::cast(info->expected_receiver_type())
1444       ->IsTemplateFor(*map);
1445 }
1446 
SetPropertyWithAccessor(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)1447 Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it,
1448                                             Handle<Object> value,
1449                                             ShouldThrow should_throw) {
1450   Isolate* isolate = it->isolate();
1451   Handle<Object> structure = it->GetAccessors();
1452   Handle<Object> receiver = it->GetReceiver();
1453 
1454   // We should never get here to initialize a const with the hole value since a
1455   // const declaration would conflict with the setter.
1456   DCHECK(!structure->IsForeign());
1457 
1458   // API style callbacks.
1459   if (structure->IsAccessorInfo()) {
1460     Handle<JSObject> holder = it->GetHolder<JSObject>();
1461     Handle<Name> name = it->GetName();
1462     Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
1463     if (!info->IsCompatibleReceiver(*receiver)) {
1464       isolate->Throw(*isolate->factory()->NewTypeError(
1465           MessageTemplate::kIncompatibleMethodReceiver, name, receiver));
1466       return Nothing<bool>();
1467     }
1468 
1469     // The actual type of call_fun is either v8::AccessorNameSetterCallback or
1470     // i::Accesors::AccessorNameBooleanSetterCallback, depending on whether the
1471     // AccessorInfo was created by the API or internally (see accessors.cc).
1472     // Here we handle both cases using GenericNamedPropertySetterCallback and
1473     // its Call method.
1474     GenericNamedPropertySetterCallback call_fun =
1475         v8::ToCData<GenericNamedPropertySetterCallback>(info->setter());
1476 
1477     if (call_fun == nullptr) {
1478       // TODO(verwaest): We should not get here anymore once all AccessorInfos
1479       // are marked as special_data_property. They cannot both be writable and
1480       // not have a setter.
1481       return Just(true);
1482     }
1483 
1484     if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1485       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1486           isolate, receiver, Object::ConvertReceiver(isolate, receiver),
1487           Nothing<bool>());
1488     }
1489 
1490     PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1491                                    should_throw);
1492     Handle<Object> result = args.Call(call_fun, name, value);
1493     // In the case of AccessorNameSetterCallback, we know that the result value
1494     // cannot have been set, so the result of Call will be null.  In the case of
1495     // AccessorNameBooleanSetterCallback, the result will either be null
1496     // (signalling an exception) or a boolean Oddball.
1497     RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1498     if (result.is_null()) return Just(true);
1499     DCHECK(result->BooleanValue() || should_throw == DONT_THROW);
1500     return Just(result->BooleanValue());
1501   }
1502 
1503   // Regular accessor.
1504   Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
1505   if (setter->IsFunctionTemplateInfo()) {
1506     Handle<Object> argv[] = {value};
1507     RETURN_ON_EXCEPTION_VALUE(
1508         isolate, Builtins::InvokeApiFunction(
1509                      isolate, false, Handle<FunctionTemplateInfo>::cast(setter),
1510                      receiver, arraysize(argv), argv,
1511                      isolate->factory()->undefined_value()),
1512         Nothing<bool>());
1513     return Just(true);
1514   } else if (setter->IsCallable()) {
1515     // TODO(rossberg): nicer would be to cast to some JSCallable here...
1516     return SetPropertyWithDefinedSetter(
1517         receiver, Handle<JSReceiver>::cast(setter), value, should_throw);
1518   }
1519 
1520   RETURN_FAILURE(isolate, should_throw,
1521                  NewTypeError(MessageTemplate::kNoSetterInCallback,
1522                               it->GetName(), it->GetHolder<JSObject>()));
1523 }
1524 
1525 
GetPropertyWithDefinedGetter(Handle<Object> receiver,Handle<JSReceiver> getter)1526 MaybeHandle<Object> Object::GetPropertyWithDefinedGetter(
1527     Handle<Object> receiver,
1528     Handle<JSReceiver> getter) {
1529   Isolate* isolate = getter->GetIsolate();
1530 
1531   // Platforms with simulators like arm/arm64 expose a funny issue. If the
1532   // simulator has a separate JS stack pointer from the C++ stack pointer, it
1533   // can miss C++ stack overflows in the stack guard at the start of JavaScript
1534   // functions. It would be very expensive to check the C++ stack pointer at
1535   // that location. The best solution seems to be to break the impasse by
1536   // adding checks at possible recursion points. What's more, we don't put
1537   // this stack check behind the USE_SIMULATOR define in order to keep
1538   // behavior the same between hardware and simulators.
1539   StackLimitCheck check(isolate);
1540   if (check.JsHasOverflowed()) {
1541     isolate->StackOverflow();
1542     return MaybeHandle<Object>();
1543   }
1544 
1545   return Execution::Call(isolate, getter, receiver, 0, NULL);
1546 }
1547 
1548 
SetPropertyWithDefinedSetter(Handle<Object> receiver,Handle<JSReceiver> setter,Handle<Object> value,ShouldThrow should_throw)1549 Maybe<bool> Object::SetPropertyWithDefinedSetter(Handle<Object> receiver,
1550                                                  Handle<JSReceiver> setter,
1551                                                  Handle<Object> value,
1552                                                  ShouldThrow should_throw) {
1553   Isolate* isolate = setter->GetIsolate();
1554 
1555   Handle<Object> argv[] = { value };
1556   RETURN_ON_EXCEPTION_VALUE(isolate, Execution::Call(isolate, setter, receiver,
1557                                                      arraysize(argv), argv),
1558                             Nothing<bool>());
1559   return Just(true);
1560 }
1561 
1562 
1563 // static
AllCanRead(LookupIterator * it)1564 bool JSObject::AllCanRead(LookupIterator* it) {
1565   // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of
1566   // which have already been checked.
1567   DCHECK(it->state() == LookupIterator::ACCESS_CHECK ||
1568          it->state() == LookupIterator::INTERCEPTOR);
1569   for (it->Next(); it->IsFound(); it->Next()) {
1570     if (it->state() == LookupIterator::ACCESSOR) {
1571       auto accessors = it->GetAccessors();
1572       if (accessors->IsAccessorInfo()) {
1573         if (AccessorInfo::cast(*accessors)->all_can_read()) return true;
1574       }
1575     } else if (it->state() == LookupIterator::INTERCEPTOR) {
1576       if (it->GetInterceptor()->all_can_read()) return true;
1577     } else if (it->state() == LookupIterator::JSPROXY) {
1578       // Stop lookupiterating. And no, AllCanNotRead.
1579       return false;
1580     }
1581   }
1582   return false;
1583 }
1584 
1585 namespace {
1586 
GetPropertyWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor,bool * done)1587 MaybeHandle<Object> GetPropertyWithInterceptorInternal(
1588     LookupIterator* it, Handle<InterceptorInfo> interceptor, bool* done) {
1589   *done = false;
1590   Isolate* isolate = it->isolate();
1591   // Make sure that the top context does not change when doing callbacks or
1592   // interceptor calls.
1593   AssertNoContextChange ncc(isolate);
1594 
1595   if (interceptor->getter()->IsUndefined(isolate)) {
1596     return isolate->factory()->undefined_value();
1597   }
1598 
1599   Handle<JSObject> holder = it->GetHolder<JSObject>();
1600   Handle<Object> result;
1601   Handle<Object> receiver = it->GetReceiver();
1602   if (!receiver->IsJSReceiver()) {
1603     ASSIGN_RETURN_ON_EXCEPTION(
1604         isolate, receiver, Object::ConvertReceiver(isolate, receiver), Object);
1605   }
1606   PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1607                                  *holder, Object::DONT_THROW);
1608 
1609   if (it->IsElement()) {
1610     uint32_t index = it->index();
1611     v8::IndexedPropertyGetterCallback getter =
1612         v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
1613     result = args.Call(getter, index);
1614   } else {
1615     Handle<Name> name = it->name();
1616     DCHECK(!name->IsPrivate());
1617 
1618     if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
1619       return isolate->factory()->undefined_value();
1620     }
1621 
1622     v8::GenericNamedPropertyGetterCallback getter =
1623         v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
1624             interceptor->getter());
1625     result = args.Call(getter, name);
1626   }
1627 
1628   RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1629   if (result.is_null()) return isolate->factory()->undefined_value();
1630   *done = true;
1631   // Rebox handle before return
1632   return handle(*result, isolate);
1633 }
1634 
GetPropertyAttributesWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor)1635 Maybe<PropertyAttributes> GetPropertyAttributesWithInterceptorInternal(
1636     LookupIterator* it, Handle<InterceptorInfo> interceptor) {
1637   Isolate* isolate = it->isolate();
1638   // Make sure that the top context does not change when doing
1639   // callbacks or interceptor calls.
1640   AssertNoContextChange ncc(isolate);
1641   HandleScope scope(isolate);
1642 
1643   Handle<JSObject> holder = it->GetHolder<JSObject>();
1644   if (!it->IsElement() && it->name()->IsSymbol() &&
1645       !interceptor->can_intercept_symbols()) {
1646     return Just(ABSENT);
1647   }
1648   Handle<Object> receiver = it->GetReceiver();
1649   if (!receiver->IsJSReceiver()) {
1650     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1651                                      Object::ConvertReceiver(isolate, receiver),
1652                                      Nothing<PropertyAttributes>());
1653   }
1654   PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1655                                  *holder, Object::DONT_THROW);
1656   if (!interceptor->query()->IsUndefined(isolate)) {
1657     Handle<Object> result;
1658     if (it->IsElement()) {
1659       uint32_t index = it->index();
1660       v8::IndexedPropertyQueryCallback query =
1661           v8::ToCData<v8::IndexedPropertyQueryCallback>(interceptor->query());
1662       result = args.Call(query, index);
1663     } else {
1664       Handle<Name> name = it->name();
1665       DCHECK(!name->IsPrivate());
1666       v8::GenericNamedPropertyQueryCallback query =
1667           v8::ToCData<v8::GenericNamedPropertyQueryCallback>(
1668               interceptor->query());
1669       result = args.Call(query, name);
1670     }
1671     if (!result.is_null()) {
1672       int32_t value;
1673       CHECK(result->ToInt32(&value));
1674       return Just(static_cast<PropertyAttributes>(value));
1675     }
1676   } else if (!interceptor->getter()->IsUndefined(isolate)) {
1677     // TODO(verwaest): Use GetPropertyWithInterceptor?
1678     Handle<Object> result;
1679     if (it->IsElement()) {
1680       uint32_t index = it->index();
1681       v8::IndexedPropertyGetterCallback getter =
1682           v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
1683       result = args.Call(getter, index);
1684     } else {
1685       Handle<Name> name = it->name();
1686       DCHECK(!name->IsPrivate());
1687       v8::GenericNamedPropertyGetterCallback getter =
1688           v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
1689               interceptor->getter());
1690       result = args.Call(getter, name);
1691     }
1692     if (!result.is_null()) return Just(DONT_ENUM);
1693   }
1694 
1695   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
1696   return Just(ABSENT);
1697 }
1698 
SetPropertyWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor,Object::ShouldThrow should_throw,Handle<Object> value)1699 Maybe<bool> SetPropertyWithInterceptorInternal(
1700     LookupIterator* it, Handle<InterceptorInfo> interceptor,
1701     Object::ShouldThrow should_throw, Handle<Object> value) {
1702   Isolate* isolate = it->isolate();
1703   // Make sure that the top context does not change when doing callbacks or
1704   // interceptor calls.
1705   AssertNoContextChange ncc(isolate);
1706 
1707   if (interceptor->setter()->IsUndefined(isolate)) return Just(false);
1708 
1709   Handle<JSObject> holder = it->GetHolder<JSObject>();
1710   bool result;
1711   Handle<Object> receiver = it->GetReceiver();
1712   if (!receiver->IsJSReceiver()) {
1713     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1714                                      Object::ConvertReceiver(isolate, receiver),
1715                                      Nothing<bool>());
1716   }
1717   PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1718                                  *holder, should_throw);
1719 
1720   if (it->IsElement()) {
1721     uint32_t index = it->index();
1722     v8::IndexedPropertySetterCallback setter =
1723         v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter());
1724     // TODO(neis): In the future, we may want to actually return the
1725     // interceptor's result, which then should be a boolean.
1726     result = !args.Call(setter, index, value).is_null();
1727   } else {
1728     Handle<Name> name = it->name();
1729     DCHECK(!name->IsPrivate());
1730 
1731     if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
1732       return Just(false);
1733     }
1734 
1735     v8::GenericNamedPropertySetterCallback setter =
1736         v8::ToCData<v8::GenericNamedPropertySetterCallback>(
1737             interceptor->setter());
1738     result = !args.Call(setter, name, value).is_null();
1739   }
1740 
1741   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1742   return Just(result);
1743 }
1744 
DefinePropertyWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor,Object::ShouldThrow should_throw,PropertyDescriptor & desc)1745 Maybe<bool> DefinePropertyWithInterceptorInternal(
1746     LookupIterator* it, Handle<InterceptorInfo> interceptor,
1747     Object::ShouldThrow should_throw, PropertyDescriptor& desc) {
1748   Isolate* isolate = it->isolate();
1749   // Make sure that the top context does not change when doing callbacks or
1750   // interceptor calls.
1751   AssertNoContextChange ncc(isolate);
1752 
1753   if (interceptor->definer()->IsUndefined(isolate)) return Just(false);
1754 
1755   Handle<JSObject> holder = it->GetHolder<JSObject>();
1756   bool result;
1757   Handle<Object> receiver = it->GetReceiver();
1758   if (!receiver->IsJSReceiver()) {
1759     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1760                                      Object::ConvertReceiver(isolate, receiver),
1761                                      Nothing<bool>());
1762   }
1763   PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1764                                  *holder, should_throw);
1765 
1766   std::unique_ptr<v8::PropertyDescriptor> descriptor(
1767       new v8::PropertyDescriptor());
1768   if (PropertyDescriptor::IsAccessorDescriptor(&desc)) {
1769     descriptor.reset(new v8::PropertyDescriptor(
1770         v8::Utils::ToLocal(desc.get()), v8::Utils::ToLocal(desc.set())));
1771   } else if (PropertyDescriptor::IsDataDescriptor(&desc)) {
1772     if (desc.has_writable()) {
1773       descriptor.reset(new v8::PropertyDescriptor(
1774           v8::Utils::ToLocal(desc.value()), desc.writable()));
1775     } else {
1776       descriptor.reset(
1777           new v8::PropertyDescriptor(v8::Utils::ToLocal(desc.value())));
1778     }
1779   }
1780   if (desc.has_enumerable()) {
1781     descriptor->set_enumerable(desc.enumerable());
1782   }
1783   if (desc.has_configurable()) {
1784     descriptor->set_configurable(desc.configurable());
1785   }
1786 
1787   if (it->IsElement()) {
1788     uint32_t index = it->index();
1789     v8::IndexedPropertyDefinerCallback definer =
1790         v8::ToCData<v8::IndexedPropertyDefinerCallback>(interceptor->definer());
1791     result = !args.Call(definer, index, *descriptor).is_null();
1792   } else {
1793     Handle<Name> name = it->name();
1794     DCHECK(!name->IsPrivate());
1795 
1796     if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
1797       return Just(false);
1798     }
1799 
1800     v8::GenericNamedPropertyDefinerCallback definer =
1801         v8::ToCData<v8::GenericNamedPropertyDefinerCallback>(
1802             interceptor->definer());
1803     result = !args.Call(definer, name, *descriptor).is_null();
1804   }
1805 
1806   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1807   return Just(result);
1808 }
1809 
1810 }  // namespace
1811 
GetPropertyWithFailedAccessCheck(LookupIterator * it)1812 MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
1813     LookupIterator* it) {
1814   Isolate* isolate = it->isolate();
1815   Handle<JSObject> checked = it->GetHolder<JSObject>();
1816   Handle<InterceptorInfo> interceptor =
1817       it->GetInterceptorForFailedAccessCheck();
1818   if (interceptor.is_null()) {
1819     while (AllCanRead(it)) {
1820       if (it->state() == LookupIterator::ACCESSOR) {
1821         return GetPropertyWithAccessor(it);
1822       }
1823       DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
1824       bool done;
1825       Handle<Object> result;
1826       ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
1827                                  GetPropertyWithInterceptor(it, &done), Object);
1828       if (done) return result;
1829     }
1830 
1831   } else {
1832     Handle<Object> result;
1833     bool done;
1834     ASSIGN_RETURN_ON_EXCEPTION(
1835         isolate, result,
1836         GetPropertyWithInterceptorInternal(it, interceptor, &done), Object);
1837     if (done) return result;
1838   }
1839 
1840   // Cross-Origin [[Get]] of Well-Known Symbols does not throw, and returns
1841   // undefined.
1842   Handle<Name> name = it->GetName();
1843   if (name->IsSymbol() && Symbol::cast(*name)->is_well_known_symbol()) {
1844     return it->factory()->undefined_value();
1845   }
1846 
1847   isolate->ReportFailedAccessCheck(checked);
1848   RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1849   return it->factory()->undefined_value();
1850 }
1851 
1852 
GetPropertyAttributesWithFailedAccessCheck(LookupIterator * it)1853 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
1854     LookupIterator* it) {
1855   Isolate* isolate = it->isolate();
1856   Handle<JSObject> checked = it->GetHolder<JSObject>();
1857   Handle<InterceptorInfo> interceptor =
1858       it->GetInterceptorForFailedAccessCheck();
1859   if (interceptor.is_null()) {
1860     while (AllCanRead(it)) {
1861       if (it->state() == LookupIterator::ACCESSOR) {
1862         return Just(it->property_attributes());
1863       }
1864       DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
1865       auto result = GetPropertyAttributesWithInterceptor(it);
1866       if (isolate->has_scheduled_exception()) break;
1867       if (result.IsJust() && result.FromJust() != ABSENT) return result;
1868     }
1869   } else {
1870     Maybe<PropertyAttributes> result =
1871         GetPropertyAttributesWithInterceptorInternal(it, interceptor);
1872     if (isolate->has_pending_exception()) return Nothing<PropertyAttributes>();
1873     if (result.FromMaybe(ABSENT) != ABSENT) return result;
1874   }
1875   isolate->ReportFailedAccessCheck(checked);
1876   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
1877   return Just(ABSENT);
1878 }
1879 
1880 
1881 // static
AllCanWrite(LookupIterator * it)1882 bool JSObject::AllCanWrite(LookupIterator* it) {
1883   for (; it->IsFound() && it->state() != LookupIterator::JSPROXY; it->Next()) {
1884     if (it->state() == LookupIterator::ACCESSOR) {
1885       Handle<Object> accessors = it->GetAccessors();
1886       if (accessors->IsAccessorInfo()) {
1887         if (AccessorInfo::cast(*accessors)->all_can_write()) return true;
1888       }
1889     }
1890   }
1891   return false;
1892 }
1893 
1894 
SetPropertyWithFailedAccessCheck(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)1895 Maybe<bool> JSObject::SetPropertyWithFailedAccessCheck(
1896     LookupIterator* it, Handle<Object> value, ShouldThrow should_throw) {
1897   Isolate* isolate = it->isolate();
1898   Handle<JSObject> checked = it->GetHolder<JSObject>();
1899   Handle<InterceptorInfo> interceptor =
1900       it->GetInterceptorForFailedAccessCheck();
1901   if (interceptor.is_null()) {
1902     if (AllCanWrite(it)) {
1903       return SetPropertyWithAccessor(it, value, should_throw);
1904     }
1905   } else {
1906     Maybe<bool> result = SetPropertyWithInterceptorInternal(
1907         it, interceptor, should_throw, value);
1908     if (isolate->has_pending_exception()) return Nothing<bool>();
1909     if (result.IsJust()) return result;
1910   }
1911   isolate->ReportFailedAccessCheck(checked);
1912   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1913   return Just(true);
1914 }
1915 
1916 
SetNormalizedProperty(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyDetails details)1917 void JSObject::SetNormalizedProperty(Handle<JSObject> object,
1918                                      Handle<Name> name,
1919                                      Handle<Object> value,
1920                                      PropertyDetails details) {
1921   DCHECK(!object->HasFastProperties());
1922   if (!name->IsUniqueName()) {
1923     name = object->GetIsolate()->factory()->InternalizeString(
1924         Handle<String>::cast(name));
1925   }
1926 
1927   if (object->IsJSGlobalObject()) {
1928     Handle<GlobalDictionary> dictionary(object->global_dictionary());
1929 
1930     int entry = dictionary->FindEntry(name);
1931     if (entry == GlobalDictionary::kNotFound) {
1932       Isolate* isolate = object->GetIsolate();
1933       auto cell = isolate->factory()->NewPropertyCell();
1934       cell->set_value(*value);
1935       auto cell_type = value->IsUndefined(isolate)
1936                            ? PropertyCellType::kUndefined
1937                            : PropertyCellType::kConstant;
1938       details = details.set_cell_type(cell_type);
1939       value = cell;
1940       dictionary = GlobalDictionary::Add(dictionary, name, value, details);
1941       object->set_properties(*dictionary);
1942     } else {
1943       Handle<PropertyCell> cell =
1944           PropertyCell::PrepareForValue(dictionary, entry, value, details);
1945       cell->set_value(*value);
1946     }
1947   } else {
1948     Handle<NameDictionary> dictionary(object->property_dictionary());
1949 
1950     int entry = dictionary->FindEntry(name);
1951     if (entry == NameDictionary::kNotFound) {
1952       dictionary = NameDictionary::Add(dictionary, name, value, details);
1953       object->set_properties(*dictionary);
1954     } else {
1955       PropertyDetails original_details = dictionary->DetailsAt(entry);
1956       int enumeration_index = original_details.dictionary_index();
1957       DCHECK(enumeration_index > 0);
1958       details = details.set_index(enumeration_index);
1959       dictionary->SetEntry(entry, name, value, details);
1960     }
1961   }
1962 }
1963 
1964 // static
HasInPrototypeChain(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> proto)1965 Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate,
1966                                             Handle<JSReceiver> object,
1967                                             Handle<Object> proto) {
1968   PrototypeIterator iter(isolate, object, kStartAtReceiver);
1969   while (true) {
1970     if (!iter.AdvanceFollowingProxies()) return Nothing<bool>();
1971     if (iter.IsAtEnd()) return Just(false);
1972     if (PrototypeIterator::GetCurrent(iter).is_identical_to(proto)) {
1973       return Just(true);
1974     }
1975   }
1976 }
1977 
1978 namespace {
1979 
HasExcludedProperty(const ScopedVector<Handle<Object>> * excluded_properties,Handle<Object> search_element)1980 bool HasExcludedProperty(
1981     const ScopedVector<Handle<Object>>* excluded_properties,
1982     Handle<Object> search_element) {
1983   // TODO(gsathya): Change this to be a hashtable.
1984   for (int i = 0; i < excluded_properties->length(); i++) {
1985     if (search_element->SameValue(*excluded_properties->at(i))) {
1986       return true;
1987     }
1988   }
1989 
1990   return false;
1991 }
1992 
FastAssign(Handle<JSReceiver> target,Handle<Object> source,const ScopedVector<Handle<Object>> * excluded_properties,bool use_set)1993 MUST_USE_RESULT Maybe<bool> FastAssign(
1994     Handle<JSReceiver> target, Handle<Object> source,
1995     const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) {
1996   // Non-empty strings are the only non-JSReceivers that need to be handled
1997   // explicitly by Object.assign.
1998   if (!source->IsJSReceiver()) {
1999     return Just(!source->IsString() || String::cast(*source)->length() == 0);
2000   }
2001 
2002   // If the target is deprecated, the object will be updated on first store. If
2003   // the source for that store equals the target, this will invalidate the
2004   // cached representation of the source. Preventively upgrade the target.
2005   // Do this on each iteration since any property load could cause deprecation.
2006   if (target->map()->is_deprecated()) {
2007     JSObject::MigrateInstance(Handle<JSObject>::cast(target));
2008   }
2009 
2010   Isolate* isolate = target->GetIsolate();
2011   Handle<Map> map(JSReceiver::cast(*source)->map(), isolate);
2012 
2013   if (!map->IsJSObjectMap()) return Just(false);
2014   if (!map->OnlyHasSimpleProperties()) return Just(false);
2015 
2016   Handle<JSObject> from = Handle<JSObject>::cast(source);
2017   if (from->elements() != isolate->heap()->empty_fixed_array()) {
2018     return Just(false);
2019   }
2020 
2021   Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
2022   int length = map->NumberOfOwnDescriptors();
2023 
2024   bool stable = true;
2025 
2026   for (int i = 0; i < length; i++) {
2027     Handle<Name> next_key(descriptors->GetKey(i), isolate);
2028     Handle<Object> prop_value;
2029     // Directly decode from the descriptor array if |from| did not change shape.
2030     if (stable) {
2031       PropertyDetails details = descriptors->GetDetails(i);
2032       if (!details.IsEnumerable()) continue;
2033       if (details.kind() == kData) {
2034         if (details.location() == kDescriptor) {
2035           prop_value = handle(descriptors->GetValue(i), isolate);
2036         } else {
2037           Representation representation = details.representation();
2038           FieldIndex index = FieldIndex::ForDescriptor(*map, i);
2039           prop_value = JSObject::FastPropertyAt(from, representation, index);
2040         }
2041       } else {
2042         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2043             isolate, prop_value, JSReceiver::GetProperty(from, next_key),
2044             Nothing<bool>());
2045         stable = from->map() == *map;
2046       }
2047     } else {
2048       // If the map did change, do a slower lookup. We are still guaranteed that
2049       // the object has a simple shape, and that the key is a name.
2050       LookupIterator it(from, next_key, from,
2051                         LookupIterator::OWN_SKIP_INTERCEPTOR);
2052       if (!it.IsFound()) continue;
2053       DCHECK(it.state() == LookupIterator::DATA ||
2054              it.state() == LookupIterator::ACCESSOR);
2055       if (!it.IsEnumerable()) continue;
2056       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2057           isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
2058     }
2059 
2060     if (use_set) {
2061       LookupIterator it(target, next_key, target);
2062       bool call_to_js = it.IsFound() && it.state() != LookupIterator::DATA;
2063       Maybe<bool> result = Object::SetProperty(
2064           &it, prop_value, STRICT, Object::CERTAINLY_NOT_STORE_FROM_KEYED);
2065       if (result.IsNothing()) return result;
2066       if (stable && call_to_js) stable = from->map() == *map;
2067     } else {
2068       if (excluded_properties != nullptr &&
2069           HasExcludedProperty(excluded_properties, next_key)) {
2070         continue;
2071       }
2072 
2073       // 4a ii 2. Perform ? CreateDataProperty(target, nextKey, propValue).
2074       bool success;
2075       LookupIterator it = LookupIterator::PropertyOrElement(
2076           isolate, target, next_key, &success, LookupIterator::OWN);
2077       CHECK(success);
2078       CHECK(
2079           JSObject::CreateDataProperty(&it, prop_value, Object::THROW_ON_ERROR)
2080               .FromJust());
2081     }
2082   }
2083 
2084   return Just(true);
2085 }
2086 }  // namespace
2087 
2088 // static
SetOrCopyDataProperties(Isolate * isolate,Handle<JSReceiver> target,Handle<Object> source,const ScopedVector<Handle<Object>> * excluded_properties,bool use_set)2089 Maybe<bool> JSReceiver::SetOrCopyDataProperties(
2090     Isolate* isolate, Handle<JSReceiver> target, Handle<Object> source,
2091     const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) {
2092   Maybe<bool> fast_assign =
2093       FastAssign(target, source, excluded_properties, use_set);
2094   if (fast_assign.IsNothing()) return Nothing<bool>();
2095   if (fast_assign.FromJust()) return Just(true);
2096 
2097   Handle<JSReceiver> from = Object::ToObject(isolate, source).ToHandleChecked();
2098   // 3b. Let keys be ? from.[[OwnPropertyKeys]]().
2099   Handle<FixedArray> keys;
2100   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2101       isolate, keys,
2102       KeyAccumulator::GetKeys(from, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES,
2103                               GetKeysConversion::kKeepNumbers),
2104       Nothing<bool>());
2105 
2106   // 4. Repeat for each element nextKey of keys in List order,
2107   for (int j = 0; j < keys->length(); ++j) {
2108     Handle<Object> next_key(keys->get(j), isolate);
2109     // 4a i. Let desc be ? from.[[GetOwnProperty]](nextKey).
2110     PropertyDescriptor desc;
2111     Maybe<bool> found =
2112         JSReceiver::GetOwnPropertyDescriptor(isolate, from, next_key, &desc);
2113     if (found.IsNothing()) return Nothing<bool>();
2114     // 4a ii. If desc is not undefined and desc.[[Enumerable]] is true, then
2115     if (found.FromJust() && desc.enumerable()) {
2116       // 4a ii 1. Let propValue be ? Get(from, nextKey).
2117       Handle<Object> prop_value;
2118       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2119           isolate, prop_value,
2120           Runtime::GetObjectProperty(isolate, from, next_key), Nothing<bool>());
2121 
2122       if (use_set) {
2123         // 4c ii 2. Let status be ? Set(to, nextKey, propValue, true).
2124         Handle<Object> status;
2125         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2126             isolate, status, Runtime::SetObjectProperty(
2127                                  isolate, target, next_key, prop_value, STRICT),
2128             Nothing<bool>());
2129       } else {
2130         if (excluded_properties != nullptr &&
2131             HasExcludedProperty(excluded_properties, next_key)) {
2132           continue;
2133         }
2134 
2135         // 4a ii 2. Perform ! CreateDataProperty(target, nextKey, propValue).
2136         bool success;
2137         LookupIterator it = LookupIterator::PropertyOrElement(
2138             isolate, target, next_key, &success, LookupIterator::OWN);
2139         CHECK(success);
2140         CHECK(JSObject::CreateDataProperty(&it, prop_value,
2141                                            Object::THROW_ON_ERROR)
2142                   .FromJust());
2143       }
2144     }
2145   }
2146 
2147   return Just(true);
2148 }
2149 
GetPrototypeChainRootMap(Isolate * isolate)2150 Map* Object::GetPrototypeChainRootMap(Isolate* isolate) {
2151   DisallowHeapAllocation no_alloc;
2152   if (IsSmi()) {
2153     Context* native_context = isolate->context()->native_context();
2154     return native_context->number_function()->initial_map();
2155   }
2156 
2157   // The object is either a number, a string, a symbol, a boolean, a real JS
2158   // object, or a Harmony proxy.
2159   HeapObject* heap_object = HeapObject::cast(this);
2160   return heap_object->map()->GetPrototypeChainRootMap(isolate);
2161 }
2162 
GetPrototypeChainRootMap(Isolate * isolate)2163 Map* Map::GetPrototypeChainRootMap(Isolate* isolate) {
2164   DisallowHeapAllocation no_alloc;
2165   if (IsJSReceiverMap()) {
2166     return this;
2167   }
2168   int constructor_function_index = GetConstructorFunctionIndex();
2169   if (constructor_function_index != Map::kNoConstructorFunctionIndex) {
2170     Context* native_context = isolate->context()->native_context();
2171     JSFunction* constructor_function =
2172         JSFunction::cast(native_context->get(constructor_function_index));
2173     return constructor_function->initial_map();
2174   }
2175   return isolate->heap()->null_value()->map();
2176 }
2177 
2178 namespace {
2179 
2180 // Returns a non-SMI for JSObjects, but returns the hash code for simple
2181 // objects.  This avoids a double lookup in the cases where we know we will
2182 // add the hash to the JSObject if it does not already exist.
GetSimpleHash(Object * object)2183 Object* GetSimpleHash(Object* object) {
2184   // The object is either a Smi, a HeapNumber, a name, an odd-ball, a real JS
2185   // object, or a Harmony proxy.
2186   if (object->IsSmi()) {
2187     uint32_t hash =
2188         ComputeIntegerHash(Smi::cast(object)->value(), kZeroHashSeed);
2189     return Smi::FromInt(hash & Smi::kMaxValue);
2190   }
2191   if (object->IsHeapNumber()) {
2192     double num = HeapNumber::cast(object)->value();
2193     if (std::isnan(num)) return Smi::FromInt(Smi::kMaxValue);
2194     if (i::IsMinusZero(num)) num = 0;
2195     if (IsSmiDouble(num)) {
2196       return Smi::FromInt(FastD2I(num))->GetHash();
2197     }
2198     uint32_t hash = ComputeLongHash(double_to_uint64(num));
2199     return Smi::FromInt(hash & Smi::kMaxValue);
2200   }
2201   if (object->IsName()) {
2202     uint32_t hash = Name::cast(object)->Hash();
2203     return Smi::FromInt(hash);
2204   }
2205   if (object->IsOddball()) {
2206     uint32_t hash = Oddball::cast(object)->to_string()->Hash();
2207     return Smi::FromInt(hash);
2208   }
2209   DCHECK(object->IsJSReceiver());
2210   // Simply return the receiver as it is guaranteed to not be a SMI.
2211   return object;
2212 }
2213 
2214 }  // namespace
2215 
GetHash()2216 Object* Object::GetHash() {
2217   Object* hash = GetSimpleHash(this);
2218   if (hash->IsSmi()) return hash;
2219 
2220   DisallowHeapAllocation no_gc;
2221   DCHECK(IsJSReceiver());
2222   JSReceiver* receiver = JSReceiver::cast(this);
2223   Isolate* isolate = receiver->GetIsolate();
2224   return JSReceiver::GetIdentityHash(isolate, handle(receiver, isolate));
2225 }
2226 
GetOrCreateHash(Isolate * isolate,Handle<Object> object)2227 Smi* Object::GetOrCreateHash(Isolate* isolate, Handle<Object> object) {
2228   Object* hash = GetSimpleHash(*object);
2229   if (hash->IsSmi()) return Smi::cast(hash);
2230 
2231   DCHECK(object->IsJSReceiver());
2232   return JSReceiver::GetOrCreateIdentityHash(isolate,
2233                                              Handle<JSReceiver>::cast(object));
2234 }
2235 
2236 
SameValue(Object * other)2237 bool Object::SameValue(Object* other) {
2238   if (other == this) return true;
2239 
2240   // The object is either a number, a name, an odd-ball,
2241   // a real JS object, or a Harmony proxy.
2242   if (IsNumber() && other->IsNumber()) {
2243     double this_value = Number();
2244     double other_value = other->Number();
2245     // SameValue(NaN, NaN) is true.
2246     if (this_value != other_value) {
2247       return std::isnan(this_value) && std::isnan(other_value);
2248     }
2249     // SameValue(0.0, -0.0) is false.
2250     return (std::signbit(this_value) == std::signbit(other_value));
2251   }
2252   if (IsString() && other->IsString()) {
2253     return String::cast(this)->Equals(String::cast(other));
2254   }
2255   return false;
2256 }
2257 
2258 
SameValueZero(Object * other)2259 bool Object::SameValueZero(Object* other) {
2260   if (other == this) return true;
2261 
2262   // The object is either a number, a name, an odd-ball,
2263   // a real JS object, or a Harmony proxy.
2264   if (IsNumber() && other->IsNumber()) {
2265     double this_value = Number();
2266     double other_value = other->Number();
2267     // +0 == -0 is true
2268     return this_value == other_value ||
2269            (std::isnan(this_value) && std::isnan(other_value));
2270   }
2271   if (IsString() && other->IsString()) {
2272     return String::cast(this)->Equals(String::cast(other));
2273   }
2274   return false;
2275 }
2276 
2277 
ArraySpeciesConstructor(Isolate * isolate,Handle<Object> original_array)2278 MaybeHandle<Object> Object::ArraySpeciesConstructor(
2279     Isolate* isolate, Handle<Object> original_array) {
2280   Handle<Object> default_species = isolate->array_function();
2281   if (original_array->IsJSArray() &&
2282       Handle<JSArray>::cast(original_array)->HasArrayPrototype(isolate) &&
2283       isolate->IsArraySpeciesLookupChainIntact()) {
2284     return default_species;
2285   }
2286   Handle<Object> constructor = isolate->factory()->undefined_value();
2287   Maybe<bool> is_array = Object::IsArray(original_array);
2288   MAYBE_RETURN_NULL(is_array);
2289   if (is_array.FromJust()) {
2290     ASSIGN_RETURN_ON_EXCEPTION(
2291         isolate, constructor,
2292         Object::GetProperty(original_array,
2293                             isolate->factory()->constructor_string()),
2294         Object);
2295     if (constructor->IsConstructor()) {
2296       Handle<Context> constructor_context;
2297       ASSIGN_RETURN_ON_EXCEPTION(
2298           isolate, constructor_context,
2299           JSReceiver::GetFunctionRealm(Handle<JSReceiver>::cast(constructor)),
2300           Object);
2301       if (*constructor_context != *isolate->native_context() &&
2302           *constructor == constructor_context->array_function()) {
2303         constructor = isolate->factory()->undefined_value();
2304       }
2305     }
2306     if (constructor->IsJSReceiver()) {
2307       ASSIGN_RETURN_ON_EXCEPTION(
2308           isolate, constructor,
2309           JSReceiver::GetProperty(Handle<JSReceiver>::cast(constructor),
2310                                   isolate->factory()->species_symbol()),
2311           Object);
2312       if (constructor->IsNull(isolate)) {
2313         constructor = isolate->factory()->undefined_value();
2314       }
2315     }
2316   }
2317   if (constructor->IsUndefined(isolate)) {
2318     return default_species;
2319   } else {
2320     if (!constructor->IsConstructor()) {
2321       THROW_NEW_ERROR(isolate,
2322           NewTypeError(MessageTemplate::kSpeciesNotConstructor),
2323           Object);
2324     }
2325     return constructor;
2326   }
2327 }
2328 
IterationHasObservableEffects()2329 bool Object::IterationHasObservableEffects() {
2330   // Check that this object is an array.
2331   if (!IsJSArray()) return true;
2332   JSArray* spread_array = JSArray::cast(this);
2333   Isolate* isolate = spread_array->GetIsolate();
2334 
2335   // Check that we have the original ArrayPrototype.
2336   JSObject* array_proto = JSObject::cast(spread_array->map()->prototype());
2337   if (!isolate->is_initial_array_prototype(array_proto)) return true;
2338 
2339   // Check that the ArrayPrototype hasn't been modified in a way that would
2340   // affect iteration.
2341   if (!isolate->IsArrayIteratorLookupChainIntact()) return true;
2342 
2343   // Check that the map of the initial array iterator hasn't changed.
2344   Map* iterator_map = isolate->initial_array_iterator_prototype()->map();
2345   if (!isolate->is_initial_array_iterator_prototype_map(iterator_map)) {
2346     return true;
2347   }
2348 
2349   // For FastPacked kinds, iteration will have the same effect as simply
2350   // accessing each property in order.
2351   ElementsKind array_kind = spread_array->GetElementsKind();
2352   if (IsFastPackedElementsKind(array_kind)) return false;
2353 
2354   // For FastHoley kinds, an element access on a hole would cause a lookup on
2355   // the prototype. This could have different results if the prototype has been
2356   // changed.
2357   if (IsFastHoleyElementsKind(array_kind) &&
2358       isolate->IsFastArrayConstructorPrototypeChainIntact()) {
2359     return false;
2360   }
2361   return true;
2362 }
2363 
ShortPrint(FILE * out)2364 void Object::ShortPrint(FILE* out) {
2365   OFStream os(out);
2366   os << Brief(this);
2367 }
2368 
2369 
ShortPrint(StringStream * accumulator)2370 void Object::ShortPrint(StringStream* accumulator) {
2371   std::ostringstream os;
2372   os << Brief(this);
2373   accumulator->Add(os.str().c_str());
2374 }
2375 
2376 
ShortPrint(std::ostream & os)2377 void Object::ShortPrint(std::ostream& os) { os << Brief(this); }
2378 
2379 
operator <<(std::ostream & os,const Brief & v)2380 std::ostream& operator<<(std::ostream& os, const Brief& v) {
2381   if (v.value->IsSmi()) {
2382     Smi::cast(v.value)->SmiPrint(os);
2383   } else {
2384     // TODO(svenpanne) Const-correct HeapObjectShortPrint!
2385     HeapObject* obj = const_cast<HeapObject*>(HeapObject::cast(v.value));
2386     obj->HeapObjectShortPrint(os);
2387   }
2388   return os;
2389 }
2390 
SmiPrint(std::ostream & os) const2391 void Smi::SmiPrint(std::ostream& os) const {  // NOLINT
2392   os << value();
2393 }
2394 
2395 
2396 // Should a word be prefixed by 'a' or 'an' in order to read naturally in
2397 // English?  Returns false for non-ASCII or words that don't start with
2398 // a capital letter.  The a/an rule follows pronunciation in English.
2399 // We don't use the BBC's overcorrect "an historic occasion" though if
2400 // you speak a dialect you may well say "an 'istoric occasion".
AnWord(String * str)2401 static bool AnWord(String* str) {
2402   if (str->length() == 0) return false;  // A nothing.
2403   int c0 = str->Get(0);
2404   int c1 = str->length() > 1 ? str->Get(1) : 0;
2405   if (c0 == 'U') {
2406     if (c1 > 'Z') {
2407       return true;  // An Umpire, but a UTF8String, a U.
2408     }
2409   } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
2410     return true;    // An Ape, an ABCBook.
2411   } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
2412            (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
2413             c0 == 'S' || c0 == 'X')) {
2414     return true;    // An MP3File, an M.
2415   }
2416   return false;
2417 }
2418 
2419 
SlowFlatten(Handle<ConsString> cons,PretenureFlag pretenure)2420 Handle<String> String::SlowFlatten(Handle<ConsString> cons,
2421                                    PretenureFlag pretenure) {
2422   DCHECK(cons->second()->length() != 0);
2423 
2424   // TurboFan can create cons strings with empty first parts.
2425   while (cons->first()->length() == 0) {
2426     // We do not want to call this function recursively. Therefore we call
2427     // String::Flatten only in those cases where String::SlowFlatten is not
2428     // called again.
2429     if (cons->second()->IsConsString() && !cons->second()->IsFlat()) {
2430       cons = handle(ConsString::cast(cons->second()));
2431     } else {
2432       return String::Flatten(handle(cons->second()));
2433     }
2434   }
2435 
2436   DCHECK(AllowHeapAllocation::IsAllowed());
2437   Isolate* isolate = cons->GetIsolate();
2438   int length = cons->length();
2439   PretenureFlag tenure = isolate->heap()->InNewSpace(*cons) ? pretenure
2440                                                             : TENURED;
2441   Handle<SeqString> result;
2442   if (cons->IsOneByteRepresentation()) {
2443     Handle<SeqOneByteString> flat = isolate->factory()->NewRawOneByteString(
2444         length, tenure).ToHandleChecked();
2445     DisallowHeapAllocation no_gc;
2446     WriteToFlat(*cons, flat->GetChars(), 0, length);
2447     result = flat;
2448   } else {
2449     Handle<SeqTwoByteString> flat = isolate->factory()->NewRawTwoByteString(
2450         length, tenure).ToHandleChecked();
2451     DisallowHeapAllocation no_gc;
2452     WriteToFlat(*cons, flat->GetChars(), 0, length);
2453     result = flat;
2454   }
2455   cons->set_first(*result);
2456   cons->set_second(isolate->heap()->empty_string());
2457   DCHECK(result->IsFlat());
2458   return result;
2459 }
2460 
2461 
2462 
MakeExternal(v8::String::ExternalStringResource * resource)2463 bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
2464   // Externalizing twice leaks the external resource, so it's
2465   // prohibited by the API.
2466   DCHECK(!this->IsExternalString());
2467   DCHECK(!resource->IsCompressible());
2468 #ifdef ENABLE_SLOW_DCHECKS
2469   if (FLAG_enable_slow_asserts) {
2470     // Assert that the resource and the string are equivalent.
2471     DCHECK(static_cast<size_t>(this->length()) == resource->length());
2472     ScopedVector<uc16> smart_chars(this->length());
2473     String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2474     DCHECK(memcmp(smart_chars.start(),
2475                   resource->data(),
2476                   resource->length() * sizeof(smart_chars[0])) == 0);
2477   }
2478 #endif  // DEBUG
2479   int size = this->Size();  // Byte size of the original string.
2480   // Abort if size does not allow in-place conversion.
2481   if (size < ExternalString::kShortSize) return false;
2482   Heap* heap = GetHeap();
2483   bool is_one_byte = this->IsOneByteRepresentation();
2484   bool is_internalized = this->IsInternalizedString();
2485   bool has_pointers = StringShape(this).IsIndirect();
2486 
2487   // Morph the string to an external string by replacing the map and
2488   // reinitializing the fields.  This won't work if the space the existing
2489   // string occupies is too small for a regular  external string.
2490   // Instead, we resort to a short external string instead, omitting
2491   // the field caching the address of the backing store.  When we encounter
2492   // short external strings in generated code, we need to bailout to runtime.
2493   Map* new_map;
2494   if (size < ExternalString::kSize) {
2495     new_map = is_internalized
2496         ? (is_one_byte
2497            ? heap->short_external_internalized_string_with_one_byte_data_map()
2498            : heap->short_external_internalized_string_map())
2499         : (is_one_byte ? heap->short_external_string_with_one_byte_data_map()
2500                        : heap->short_external_string_map());
2501   } else {
2502     new_map = is_internalized
2503         ? (is_one_byte
2504            ? heap->external_internalized_string_with_one_byte_data_map()
2505            : heap->external_internalized_string_map())
2506         : (is_one_byte ? heap->external_string_with_one_byte_data_map()
2507                        : heap->external_string_map());
2508   }
2509 
2510   // Byte size of the external String object.
2511   int new_size = this->SizeFromMap(new_map);
2512   heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
2513                              ClearRecordedSlots::kNo);
2514   if (has_pointers) {
2515     heap->ClearRecordedSlotRange(this->address(), this->address() + new_size);
2516   }
2517 
2518   // We are storing the new map using release store after creating a filler for
2519   // the left-over space to avoid races with the sweeper thread.
2520   this->synchronized_set_map(new_map);
2521 
2522   ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
2523   self->set_resource(resource);
2524   if (is_internalized) self->Hash();  // Force regeneration of the hash value.
2525 
2526   heap->AdjustLiveBytes(this, new_size - size);
2527   return true;
2528 }
2529 
2530 
MakeExternal(v8::String::ExternalOneByteStringResource * resource)2531 bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
2532   // Externalizing twice leaks the external resource, so it's
2533   // prohibited by the API.
2534   DCHECK(!this->IsExternalString());
2535   DCHECK(!resource->IsCompressible());
2536 #ifdef ENABLE_SLOW_DCHECKS
2537   if (FLAG_enable_slow_asserts) {
2538     // Assert that the resource and the string are equivalent.
2539     DCHECK(static_cast<size_t>(this->length()) == resource->length());
2540     if (this->IsTwoByteRepresentation()) {
2541       ScopedVector<uint16_t> smart_chars(this->length());
2542       String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2543       DCHECK(String::IsOneByte(smart_chars.start(), this->length()));
2544     }
2545     ScopedVector<char> smart_chars(this->length());
2546     String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2547     DCHECK(memcmp(smart_chars.start(),
2548                   resource->data(),
2549                   resource->length() * sizeof(smart_chars[0])) == 0);
2550   }
2551 #endif  // DEBUG
2552   int size = this->Size();  // Byte size of the original string.
2553   // Abort if size does not allow in-place conversion.
2554   if (size < ExternalString::kShortSize) return false;
2555   Heap* heap = GetHeap();
2556   bool is_internalized = this->IsInternalizedString();
2557   bool has_pointers = StringShape(this).IsIndirect();
2558 
2559   // Morph the string to an external string by replacing the map and
2560   // reinitializing the fields.  This won't work if the space the existing
2561   // string occupies is too small for a regular  external string.
2562   // Instead, we resort to a short external string instead, omitting
2563   // the field caching the address of the backing store.  When we encounter
2564   // short external strings in generated code, we need to bailout to runtime.
2565   Map* new_map;
2566   if (size < ExternalString::kSize) {
2567     new_map = is_internalized
2568                   ? heap->short_external_one_byte_internalized_string_map()
2569                   : heap->short_external_one_byte_string_map();
2570   } else {
2571     new_map = is_internalized
2572                   ? heap->external_one_byte_internalized_string_map()
2573                   : heap->external_one_byte_string_map();
2574   }
2575 
2576   // Byte size of the external String object.
2577   int new_size = this->SizeFromMap(new_map);
2578   heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
2579                              ClearRecordedSlots::kNo);
2580   if (has_pointers) {
2581     heap->ClearRecordedSlotRange(this->address(), this->address() + new_size);
2582   }
2583 
2584   // We are storing the new map using release store after creating a filler for
2585   // the left-over space to avoid races with the sweeper thread.
2586   this->synchronized_set_map(new_map);
2587 
2588   ExternalOneByteString* self = ExternalOneByteString::cast(this);
2589   self->set_resource(resource);
2590   if (is_internalized) self->Hash();  // Force regeneration of the hash value.
2591 
2592   heap->AdjustLiveBytes(this, new_size - size);
2593   return true;
2594 }
2595 
StringShortPrint(StringStream * accumulator,bool show_details)2596 void String::StringShortPrint(StringStream* accumulator, bool show_details) {
2597   int len = length();
2598   if (len > kMaxShortPrintLength) {
2599     accumulator->Add("<Very long string[%u]>", len);
2600     return;
2601   }
2602 
2603   if (!LooksValid()) {
2604     accumulator->Add("<Invalid String>");
2605     return;
2606   }
2607 
2608   StringCharacterStream stream(this);
2609 
2610   bool truncated = false;
2611   if (len > kMaxShortPrintLength) {
2612     len = kMaxShortPrintLength;
2613     truncated = true;
2614   }
2615   bool one_byte = true;
2616   for (int i = 0; i < len; i++) {
2617     uint16_t c = stream.GetNext();
2618 
2619     if (c < 32 || c >= 127) {
2620       one_byte = false;
2621     }
2622   }
2623   stream.Reset(this);
2624   if (one_byte) {
2625     if (show_details) accumulator->Add("<String[%u]: ", length());
2626     for (int i = 0; i < len; i++) {
2627       accumulator->Put(static_cast<char>(stream.GetNext()));
2628     }
2629     if (show_details) accumulator->Put('>');
2630   } else {
2631     // Backslash indicates that the string contains control
2632     // characters and that backslashes are therefore escaped.
2633     if (show_details) accumulator->Add("<String[%u]\\: ", length());
2634     for (int i = 0; i < len; i++) {
2635       uint16_t c = stream.GetNext();
2636       if (c == '\n') {
2637         accumulator->Add("\\n");
2638       } else if (c == '\r') {
2639         accumulator->Add("\\r");
2640       } else if (c == '\\') {
2641         accumulator->Add("\\\\");
2642       } else if (c < 32 || c > 126) {
2643         accumulator->Add("\\x%02x", c);
2644       } else {
2645         accumulator->Put(static_cast<char>(c));
2646       }
2647     }
2648     if (truncated) {
2649       accumulator->Put('.');
2650       accumulator->Put('.');
2651       accumulator->Put('.');
2652     }
2653     if (show_details) accumulator->Put('>');
2654   }
2655   return;
2656 }
2657 
2658 
PrintUC16(std::ostream & os,int start,int end)2659 void String::PrintUC16(std::ostream& os, int start, int end) {  // NOLINT
2660   if (end < 0) end = length();
2661   StringCharacterStream stream(this, start);
2662   for (int i = start; i < end && stream.HasMore(); i++) {
2663     os << AsUC16(stream.GetNext());
2664   }
2665 }
2666 
2667 
JSObjectShortPrint(StringStream * accumulator)2668 void JSObject::JSObjectShortPrint(StringStream* accumulator) {
2669   switch (map()->instance_type()) {
2670     case JS_ARRAY_TYPE: {
2671       double length = JSArray::cast(this)->length()->IsUndefined(GetIsolate())
2672                           ? 0
2673                           : JSArray::cast(this)->length()->Number();
2674       accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length));
2675       break;
2676     }
2677     case JS_BOUND_FUNCTION_TYPE: {
2678       JSBoundFunction* bound_function = JSBoundFunction::cast(this);
2679       accumulator->Add("<JS BoundFunction");
2680       accumulator->Add(
2681           " (BoundTargetFunction %p)>",
2682           reinterpret_cast<void*>(bound_function->bound_target_function()));
2683       break;
2684     }
2685     case JS_WEAK_MAP_TYPE: {
2686       accumulator->Add("<JS WeakMap>");
2687       break;
2688     }
2689     case JS_WEAK_SET_TYPE: {
2690       accumulator->Add("<JS WeakSet>");
2691       break;
2692     }
2693     case JS_REGEXP_TYPE: {
2694       accumulator->Add("<JS RegExp>");
2695       break;
2696     }
2697     case JS_FUNCTION_TYPE: {
2698       JSFunction* function = JSFunction::cast(this);
2699       Object* fun_name = function->shared()->DebugName();
2700       bool printed = false;
2701       if (fun_name->IsString()) {
2702         String* str = String::cast(fun_name);
2703         if (str->length() > 0) {
2704           accumulator->Add("<JS Function ");
2705           accumulator->Put(str);
2706           printed = true;
2707         }
2708       }
2709       if (!printed) {
2710         accumulator->Add("<JS Function");
2711       }
2712       if (FLAG_trace_file_names) {
2713         Object* source_name =
2714             Script::cast(function->shared()->script())->name();
2715         if (source_name->IsString()) {
2716           String* str = String::cast(source_name);
2717           if (str->length() > 0) {
2718             accumulator->Add(" <");
2719             accumulator->Put(str);
2720             accumulator->Add(">");
2721           }
2722         }
2723       }
2724       accumulator->Add(" (SharedFunctionInfo %p)",
2725                        reinterpret_cast<void*>(function->shared()));
2726       accumulator->Put('>');
2727       break;
2728     }
2729     case JS_GENERATOR_OBJECT_TYPE: {
2730       accumulator->Add("<JS Generator>");
2731       break;
2732     }
2733     // All other JSObjects are rather similar to each other (JSObject,
2734     // JSGlobalProxy, JSGlobalObject, JSUndetectable, JSValue).
2735     default: {
2736       Map* map_of_this = map();
2737       Heap* heap = GetHeap();
2738       Object* constructor = map_of_this->GetConstructor();
2739       bool printed = false;
2740       if (constructor->IsHeapObject() &&
2741           !heap->Contains(HeapObject::cast(constructor))) {
2742         accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
2743       } else {
2744         bool global_object = IsJSGlobalProxy();
2745         if (constructor->IsJSFunction()) {
2746           if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
2747             accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
2748           } else {
2749             Object* constructor_name =
2750                 JSFunction::cast(constructor)->shared()->name();
2751             if (constructor_name->IsString()) {
2752               String* str = String::cast(constructor_name);
2753               if (str->length() > 0) {
2754                 bool vowel = AnWord(str);
2755                 accumulator->Add("<%sa%s ",
2756                        global_object ? "Global Object: " : "",
2757                        vowel ? "n" : "");
2758                 accumulator->Put(str);
2759                 accumulator->Add(" with %smap %p",
2760                     map_of_this->is_deprecated() ? "deprecated " : "",
2761                     map_of_this);
2762                 printed = true;
2763               }
2764             }
2765           }
2766         }
2767         if (!printed) {
2768           accumulator->Add("<JS %sObject", global_object ? "Global " : "");
2769         }
2770       }
2771       if (IsJSValue()) {
2772         accumulator->Add(" value = ");
2773         JSValue::cast(this)->value()->ShortPrint(accumulator);
2774       }
2775       accumulator->Put('>');
2776       break;
2777     }
2778   }
2779 }
2780 
2781 
PrintElementsTransition(FILE * file,Handle<JSObject> object,ElementsKind from_kind,Handle<FixedArrayBase> from_elements,ElementsKind to_kind,Handle<FixedArrayBase> to_elements)2782 void JSObject::PrintElementsTransition(
2783     FILE* file, Handle<JSObject> object,
2784     ElementsKind from_kind, Handle<FixedArrayBase> from_elements,
2785     ElementsKind to_kind, Handle<FixedArrayBase> to_elements) {
2786   if (from_kind != to_kind) {
2787     OFStream os(file);
2788     os << "elements transition [" << ElementsKindToString(from_kind) << " -> "
2789        << ElementsKindToString(to_kind) << "] in ";
2790     JavaScriptFrame::PrintTop(object->GetIsolate(), file, false, true);
2791     PrintF(file, " for ");
2792     object->ShortPrint(file);
2793     PrintF(file, " from ");
2794     from_elements->ShortPrint(file);
2795     PrintF(file, " to ");
2796     to_elements->ShortPrint(file);
2797     PrintF(file, "\n");
2798   }
2799 }
2800 
2801 
2802 // static
GetConstructorFunction(Handle<Map> map,Handle<Context> native_context)2803 MaybeHandle<JSFunction> Map::GetConstructorFunction(
2804     Handle<Map> map, Handle<Context> native_context) {
2805   if (map->IsPrimitiveMap()) {
2806     int const constructor_function_index = map->GetConstructorFunctionIndex();
2807     if (constructor_function_index != kNoConstructorFunctionIndex) {
2808       return handle(
2809           JSFunction::cast(native_context->get(constructor_function_index)));
2810     }
2811   }
2812   return MaybeHandle<JSFunction>();
2813 }
2814 
2815 
PrintReconfiguration(FILE * file,int modify_index,PropertyKind kind,PropertyAttributes attributes)2816 void Map::PrintReconfiguration(FILE* file, int modify_index, PropertyKind kind,
2817                                PropertyAttributes attributes) {
2818   OFStream os(file);
2819   os << "[reconfiguring]";
2820   Name* name = instance_descriptors()->GetKey(modify_index);
2821   if (name->IsString()) {
2822     String::cast(name)->PrintOn(file);
2823   } else {
2824     os << "{symbol " << static_cast<void*>(name) << "}";
2825   }
2826   os << ": " << (kind == kData ? "kData" : "ACCESSORS") << ", attrs: ";
2827   os << attributes << " [";
2828   JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
2829   os << "]\n";
2830 }
2831 
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)2832 void Map::PrintGeneralization(
2833     FILE* file, const char* reason, int modify_index, int split,
2834     int descriptors, bool descriptor_to_field,
2835     Representation old_representation, Representation new_representation,
2836     MaybeHandle<FieldType> old_field_type, MaybeHandle<Object> old_value,
2837     MaybeHandle<FieldType> new_field_type, MaybeHandle<Object> new_value) {
2838   OFStream os(file);
2839   os << "[generalizing]";
2840   Name* name = instance_descriptors()->GetKey(modify_index);
2841   if (name->IsString()) {
2842     String::cast(name)->PrintOn(file);
2843   } else {
2844     os << "{symbol " << static_cast<void*>(name) << "}";
2845   }
2846   os << ":";
2847   if (descriptor_to_field) {
2848     os << "c";
2849   } else {
2850     os << old_representation.Mnemonic() << "{";
2851     if (old_field_type.is_null()) {
2852       os << Brief(*(old_value.ToHandleChecked()));
2853     } else {
2854       old_field_type.ToHandleChecked()->PrintTo(os);
2855     }
2856     os << "}";
2857   }
2858   os << "->" << new_representation.Mnemonic() << "{";
2859   if (new_field_type.is_null()) {
2860     os << Brief(*(new_value.ToHandleChecked()));
2861   } else {
2862     new_field_type.ToHandleChecked()->PrintTo(os);
2863   }
2864   os << "} (";
2865   if (strlen(reason) > 0) {
2866     os << reason;
2867   } else {
2868     os << "+" << (descriptors - split) << " maps";
2869   }
2870   os << ") [";
2871   JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
2872   os << "]\n";
2873 }
2874 
2875 
PrintInstanceMigration(FILE * file,Map * original_map,Map * new_map)2876 void JSObject::PrintInstanceMigration(FILE* file,
2877                                       Map* original_map,
2878                                       Map* new_map) {
2879   PrintF(file, "[migrating]");
2880   DescriptorArray* o = original_map->instance_descriptors();
2881   DescriptorArray* n = new_map->instance_descriptors();
2882   for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) {
2883     Representation o_r = o->GetDetails(i).representation();
2884     Representation n_r = n->GetDetails(i).representation();
2885     if (!o_r.Equals(n_r)) {
2886       String::cast(o->GetKey(i))->PrintOn(file);
2887       PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic());
2888     } else if (o->GetDetails(i).location() == kDescriptor &&
2889                n->GetDetails(i).location() == kField) {
2890       Name* name = o->GetKey(i);
2891       if (name->IsString()) {
2892         String::cast(name)->PrintOn(file);
2893       } else {
2894         PrintF(file, "{symbol %p}", static_cast<void*>(name));
2895       }
2896       PrintF(file, " ");
2897     }
2898   }
2899   PrintF(file, "\n");
2900 }
2901 
2902 
HeapObjectShortPrint(std::ostream & os)2903 void HeapObject::HeapObjectShortPrint(std::ostream& os) {  // NOLINT
2904   Heap* heap = GetHeap();
2905   Isolate* isolate = heap->isolate();
2906   if (!heap->Contains(this)) {
2907     os << "!!!INVALID POINTER!!!";
2908     return;
2909   }
2910   if (!heap->Contains(map())) {
2911     os << "!!!INVALID MAP!!!";
2912     return;
2913   }
2914 
2915   os << this << " ";
2916 
2917   if (IsString()) {
2918     HeapStringAllocator allocator;
2919     StringStream accumulator(&allocator);
2920     String::cast(this)->StringShortPrint(&accumulator);
2921     os << accumulator.ToCString().get();
2922     return;
2923   }
2924   if (IsJSObject()) {
2925     HeapStringAllocator allocator;
2926     StringStream accumulator(&allocator);
2927     JSObject::cast(this)->JSObjectShortPrint(&accumulator);
2928     os << accumulator.ToCString().get();
2929     return;
2930   }
2931   switch (map()->instance_type()) {
2932     case MAP_TYPE:
2933       os << "<Map(" << ElementsKindToString(Map::cast(this)->elements_kind())
2934          << ")>";
2935       break;
2936     case FIXED_ARRAY_TYPE:
2937       os << "<FixedArray[" << FixedArray::cast(this)->length() << "]>";
2938       break;
2939     case FIXED_DOUBLE_ARRAY_TYPE:
2940       os << "<FixedDoubleArray[" << FixedDoubleArray::cast(this)->length()
2941          << "]>";
2942       break;
2943     case BYTE_ARRAY_TYPE:
2944       os << "<ByteArray[" << ByteArray::cast(this)->length() << "]>";
2945       break;
2946     case BYTECODE_ARRAY_TYPE:
2947       os << "<BytecodeArray[" << BytecodeArray::cast(this)->length() << "]>";
2948       break;
2949     case TRANSITION_ARRAY_TYPE:
2950       os << "<TransitionArray[" << TransitionArray::cast(this)->length()
2951          << "]>";
2952       break;
2953     case FREE_SPACE_TYPE:
2954       os << "<FreeSpace[" << FreeSpace::cast(this)->size() << "]>";
2955       break;
2956 #define TYPED_ARRAY_SHORT_PRINT(Type, type, TYPE, ctype, size)                \
2957   case FIXED_##TYPE##_ARRAY_TYPE:                                             \
2958     os << "<Fixed" #Type "Array[" << Fixed##Type##Array::cast(this)->length() \
2959        << "]>";                                                               \
2960     break;
2961 
2962     TYPED_ARRAYS(TYPED_ARRAY_SHORT_PRINT)
2963 #undef TYPED_ARRAY_SHORT_PRINT
2964 
2965     case SHARED_FUNCTION_INFO_TYPE: {
2966       SharedFunctionInfo* shared = SharedFunctionInfo::cast(this);
2967       std::unique_ptr<char[]> debug_name = shared->DebugName()->ToCString();
2968       if (debug_name[0] != 0) {
2969         os << "<SharedFunctionInfo " << debug_name.get() << ">";
2970       } else {
2971         os << "<SharedFunctionInfo>";
2972       }
2973       break;
2974     }
2975     case JS_MESSAGE_OBJECT_TYPE:
2976       os << "<JSMessageObject>";
2977       break;
2978 #define MAKE_STRUCT_CASE(NAME, Name, name) \
2979   case NAME##_TYPE:                        \
2980     os << "<" #Name ">";                   \
2981     break;
2982   STRUCT_LIST(MAKE_STRUCT_CASE)
2983 #undef MAKE_STRUCT_CASE
2984     case CODE_TYPE: {
2985       Code* code = Code::cast(this);
2986       os << "<Code: " << Code::Kind2String(code->kind()) << ">";
2987       break;
2988     }
2989     case ODDBALL_TYPE: {
2990       if (IsUndefined(isolate)) {
2991         os << "<undefined>";
2992       } else if (IsTheHole(isolate)) {
2993         os << "<the hole>";
2994       } else if (IsNull(isolate)) {
2995         os << "<null>";
2996       } else if (IsTrue(isolate)) {
2997         os << "<true>";
2998       } else if (IsFalse(isolate)) {
2999         os << "<false>";
3000       } else {
3001         os << "<Odd Oddball: ";
3002         os << Oddball::cast(this)->to_string()->ToCString().get();
3003         os << ">";
3004       }
3005       break;
3006     }
3007     case SYMBOL_TYPE: {
3008       Symbol* symbol = Symbol::cast(this);
3009       symbol->SymbolShortPrint(os);
3010       break;
3011     }
3012     case HEAP_NUMBER_TYPE: {
3013       os << "<Number: ";
3014       HeapNumber::cast(this)->HeapNumberPrint(os);
3015       os << ">";
3016       break;
3017     }
3018     case MUTABLE_HEAP_NUMBER_TYPE: {
3019       os << "<MutableNumber: ";
3020       HeapNumber::cast(this)->HeapNumberPrint(os);
3021       os << '>';
3022       break;
3023     }
3024     case JS_PROXY_TYPE:
3025       os << "<JSProxy>";
3026       break;
3027     case FOREIGN_TYPE:
3028       os << "<Foreign>";
3029       break;
3030     case CELL_TYPE: {
3031       os << "Cell for ";
3032       HeapStringAllocator allocator;
3033       StringStream accumulator(&allocator);
3034       Cell::cast(this)->value()->ShortPrint(&accumulator);
3035       os << accumulator.ToCString().get();
3036       break;
3037     }
3038     case PROPERTY_CELL_TYPE: {
3039       os << "PropertyCell for ";
3040       HeapStringAllocator allocator;
3041       StringStream accumulator(&allocator);
3042       PropertyCell* cell = PropertyCell::cast(this);
3043       cell->value()->ShortPrint(&accumulator);
3044       os << accumulator.ToCString().get();
3045       break;
3046     }
3047     case WEAK_CELL_TYPE: {
3048       os << "WeakCell for ";
3049       HeapStringAllocator allocator;
3050       StringStream accumulator(&allocator);
3051       WeakCell::cast(this)->value()->ShortPrint(&accumulator);
3052       os << accumulator.ToCString().get();
3053       break;
3054     }
3055     default:
3056       os << "<Other heap object (" << map()->instance_type() << ")>";
3057       break;
3058   }
3059 }
3060 
3061 
Iterate(ObjectVisitor * v)3062 void HeapObject::Iterate(ObjectVisitor* v) { IterateFast<ObjectVisitor>(v); }
3063 
3064 
IterateBody(ObjectVisitor * v)3065 void HeapObject::IterateBody(ObjectVisitor* v) {
3066   Map* m = map();
3067   IterateBodyFast<ObjectVisitor>(m->instance_type(), SizeFromMap(m), v);
3068 }
3069 
3070 
IterateBody(InstanceType type,int object_size,ObjectVisitor * v)3071 void HeapObject::IterateBody(InstanceType type, int object_size,
3072                              ObjectVisitor* v) {
3073   IterateBodyFast<ObjectVisitor>(type, object_size, v);
3074 }
3075 
3076 
3077 struct CallIsValidSlot {
3078   template <typename BodyDescriptor>
applyv8::internal::CallIsValidSlot3079   static bool apply(HeapObject* obj, int offset, int) {
3080     return BodyDescriptor::IsValidSlot(obj, offset);
3081   }
3082 };
3083 
3084 
IsValidSlot(int offset)3085 bool HeapObject::IsValidSlot(int offset) {
3086   DCHECK_NE(0, offset);
3087   return BodyDescriptorApply<CallIsValidSlot, bool>(map()->instance_type(),
3088                                                     this, offset, 0);
3089 }
3090 
3091 
HeapNumberBooleanValue()3092 bool HeapNumber::HeapNumberBooleanValue() {
3093   return DoubleToBoolean(value());
3094 }
3095 
3096 
HeapNumberPrint(std::ostream & os)3097 void HeapNumber::HeapNumberPrint(std::ostream& os) {  // NOLINT
3098   os << value();
3099 }
3100 
3101 
3102 #define FIELD_ADDR_CONST(p, offset) \
3103   (reinterpret_cast<const byte*>(p) + offset - kHeapObjectTag)
3104 
3105 #define READ_INT32_FIELD(p, offset) \
3106   (*reinterpret_cast<const int32_t*>(FIELD_ADDR_CONST(p, offset)))
3107 
3108 #define READ_INT64_FIELD(p, offset) \
3109   (*reinterpret_cast<const int64_t*>(FIELD_ADDR_CONST(p, offset)))
3110 
3111 #define READ_BYTE_FIELD(p, offset) \
3112   (*reinterpret_cast<const byte*>(FIELD_ADDR_CONST(p, offset)))
3113 
class_name()3114 String* JSReceiver::class_name() {
3115   if (IsFunction()) {
3116     return GetHeap()->Function_string();
3117   }
3118   Object* maybe_constructor = map()->GetConstructor();
3119   if (maybe_constructor->IsJSFunction()) {
3120     JSFunction* constructor = JSFunction::cast(maybe_constructor);
3121     return String::cast(constructor->shared()->instance_class_name());
3122   }
3123   // If the constructor is not present, return "Object".
3124   return GetHeap()->Object_string();
3125 }
3126 
3127 
3128 // static
GetConstructorName(Handle<JSReceiver> receiver)3129 Handle<String> JSReceiver::GetConstructorName(Handle<JSReceiver> receiver) {
3130   Isolate* isolate = receiver->GetIsolate();
3131 
3132   // If the object was instantiated simply with base == new.target, the
3133   // constructor on the map provides the most accurate name.
3134   // Don't provide the info for prototypes, since their constructors are
3135   // reclaimed and replaced by Object in OptimizeAsPrototype.
3136   if (!receiver->IsJSProxy() && receiver->map()->new_target_is_base() &&
3137       !receiver->map()->is_prototype_map()) {
3138     Object* maybe_constructor = receiver->map()->GetConstructor();
3139     if (maybe_constructor->IsJSFunction()) {
3140       JSFunction* constructor = JSFunction::cast(maybe_constructor);
3141       String* name = String::cast(constructor->shared()->name());
3142       if (name->length() == 0) name = constructor->shared()->inferred_name();
3143       if (name->length() != 0 &&
3144           !name->Equals(isolate->heap()->Object_string())) {
3145         return handle(name, isolate);
3146       }
3147     }
3148   }
3149 
3150   Handle<Object> maybe_tag = JSReceiver::GetDataProperty(
3151       receiver, isolate->factory()->to_string_tag_symbol());
3152   if (maybe_tag->IsString()) return Handle<String>::cast(maybe_tag);
3153 
3154   PrototypeIterator iter(isolate, receiver);
3155   if (iter.IsAtEnd()) return handle(receiver->class_name());
3156   Handle<JSReceiver> start = PrototypeIterator::GetCurrent<JSReceiver>(iter);
3157   LookupIterator it(receiver, isolate->factory()->constructor_string(), start,
3158                     LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
3159   Handle<Object> maybe_constructor = JSReceiver::GetDataProperty(&it);
3160   Handle<String> result = isolate->factory()->Object_string();
3161   if (maybe_constructor->IsJSFunction()) {
3162     JSFunction* constructor = JSFunction::cast(*maybe_constructor);
3163     String* name = String::cast(constructor->shared()->name());
3164     if (name->length() == 0) name = constructor->shared()->inferred_name();
3165     if (name->length() > 0) result = handle(name, isolate);
3166   }
3167 
3168   return result.is_identical_to(isolate->factory()->Object_string())
3169              ? handle(receiver->class_name())
3170              : result;
3171 }
3172 
GetCreationContext()3173 Handle<Context> JSReceiver::GetCreationContext() {
3174   JSReceiver* receiver = this;
3175   while (receiver->IsJSBoundFunction()) {
3176     receiver = JSBoundFunction::cast(receiver)->bound_target_function();
3177   }
3178   Object* constructor = receiver->map()->GetConstructor();
3179   JSFunction* function;
3180   if (constructor->IsJSFunction()) {
3181     function = JSFunction::cast(constructor);
3182   } else {
3183     // Functions have null as a constructor,
3184     // but any JSFunction knows its context immediately.
3185     CHECK(receiver->IsJSFunction());
3186     function = JSFunction::cast(receiver);
3187   }
3188 
3189   return function->has_context()
3190              ? Handle<Context>(function->context()->native_context())
3191              : Handle<Context>::null();
3192 }
3193 
WrapFieldType(Handle<FieldType> type)3194 Handle<Object> Map::WrapFieldType(Handle<FieldType> type) {
3195   if (type->IsClass()) return Map::WeakCellForMap(type->AsClass());
3196   return type;
3197 }
3198 
UnwrapFieldType(Object * wrapped_type)3199 FieldType* Map::UnwrapFieldType(Object* wrapped_type) {
3200   Object* value = wrapped_type;
3201   if (value->IsWeakCell()) {
3202     if (WeakCell::cast(value)->cleared()) return FieldType::None();
3203     value = WeakCell::cast(value)->value();
3204   }
3205   return FieldType::cast(value);
3206 }
3207 
CopyWithField(Handle<Map> map,Handle<Name> name,Handle<FieldType> type,PropertyAttributes attributes,PropertyConstness constness,Representation representation,TransitionFlag flag)3208 MaybeHandle<Map> Map::CopyWithField(Handle<Map> map, Handle<Name> name,
3209                                     Handle<FieldType> type,
3210                                     PropertyAttributes attributes,
3211                                     PropertyConstness constness,
3212                                     Representation representation,
3213                                     TransitionFlag flag) {
3214   DCHECK(DescriptorArray::kNotFound ==
3215          map->instance_descriptors()->Search(
3216              *name, map->NumberOfOwnDescriptors()));
3217 
3218   // Ensure the descriptor array does not get too big.
3219   if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
3220     return MaybeHandle<Map>();
3221   }
3222 
3223   Isolate* isolate = map->GetIsolate();
3224 
3225   // Compute the new index for new field.
3226   int index = map->NextFreePropertyIndex();
3227 
3228   if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
3229     representation = Representation::Tagged();
3230     type = FieldType::Any(isolate);
3231   }
3232 
3233   Handle<Object> wrapped_type(WrapFieldType(type));
3234 
3235   DCHECK_IMPLIES(!FLAG_track_constant_fields, constness == kMutable);
3236   Descriptor d = Descriptor::DataField(name, index, attributes, constness,
3237                                        representation, wrapped_type);
3238   Handle<Map> new_map = Map::CopyAddDescriptor(map, &d, flag);
3239   int unused_property_fields = new_map->unused_property_fields() - 1;
3240   if (unused_property_fields < 0) {
3241     unused_property_fields += JSObject::kFieldsAdded;
3242   }
3243   new_map->set_unused_property_fields(unused_property_fields);
3244   return new_map;
3245 }
3246 
3247 
CopyWithConstant(Handle<Map> map,Handle<Name> name,Handle<Object> constant,PropertyAttributes attributes,TransitionFlag flag)3248 MaybeHandle<Map> Map::CopyWithConstant(Handle<Map> map,
3249                                        Handle<Name> name,
3250                                        Handle<Object> constant,
3251                                        PropertyAttributes attributes,
3252                                        TransitionFlag flag) {
3253   // Ensure the descriptor array does not get too big.
3254   if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
3255     return MaybeHandle<Map>();
3256   }
3257 
3258   if (FLAG_track_constant_fields) {
3259     Isolate* isolate = map->GetIsolate();
3260     Representation representation = constant->OptimalRepresentation();
3261     Handle<FieldType> type = constant->OptimalType(isolate, representation);
3262     return CopyWithField(map, name, type, attributes, kConst, representation,
3263                          flag);
3264   } else {
3265     // Allocate new instance descriptors with (name, constant) added.
3266     Descriptor d = Descriptor::DataConstant(name, 0, constant, attributes);
3267     Handle<Map> new_map = Map::CopyAddDescriptor(map, &d, flag);
3268     return new_map;
3269   }
3270 }
3271 
Mnemonic() const3272 const char* Representation::Mnemonic() const {
3273   switch (kind_) {
3274     case kNone: return "v";
3275     case kTagged: return "t";
3276     case kSmi: return "s";
3277     case kDouble: return "d";
3278     case kInteger32: return "i";
3279     case kHeapObject: return "h";
3280     case kExternal: return "x";
3281     default:
3282       UNREACHABLE();
3283       return NULL;
3284   }
3285 }
3286 
TransitionRemovesTaggedField(Map * target)3287 bool Map::TransitionRemovesTaggedField(Map* target) {
3288   int inobject = GetInObjectProperties();
3289   int target_inobject = target->GetInObjectProperties();
3290   for (int i = target_inobject; i < inobject; i++) {
3291     FieldIndex index = FieldIndex::ForPropertyIndex(this, i);
3292     if (!IsUnboxedDoubleField(index)) return true;
3293   }
3294   return false;
3295 }
3296 
TransitionChangesTaggedFieldToUntaggedField(Map * target)3297 bool Map::TransitionChangesTaggedFieldToUntaggedField(Map* target) {
3298   int inobject = GetInObjectProperties();
3299   int target_inobject = target->GetInObjectProperties();
3300   int limit = Min(inobject, target_inobject);
3301   for (int i = 0; i < limit; i++) {
3302     FieldIndex index = FieldIndex::ForPropertyIndex(target, i);
3303     if (!IsUnboxedDoubleField(index) && target->IsUnboxedDoubleField(index)) {
3304       return true;
3305     }
3306   }
3307   return false;
3308 }
3309 
TransitionRequiresSynchronizationWithGC(Map * target)3310 bool Map::TransitionRequiresSynchronizationWithGC(Map* target) {
3311   return TransitionRemovesTaggedField(target) ||
3312          TransitionChangesTaggedFieldToUntaggedField(target);
3313 }
3314 
InstancesNeedRewriting(Map * target)3315 bool Map::InstancesNeedRewriting(Map* target) {
3316   int target_number_of_fields = target->NumberOfFields();
3317   int target_inobject = target->GetInObjectProperties();
3318   int target_unused = target->unused_property_fields();
3319   int old_number_of_fields;
3320 
3321   return InstancesNeedRewriting(target, target_number_of_fields,
3322                                 target_inobject, target_unused,
3323                                 &old_number_of_fields);
3324 }
3325 
InstancesNeedRewriting(Map * target,int target_number_of_fields,int target_inobject,int target_unused,int * old_number_of_fields)3326 bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields,
3327                                  int target_inobject, int target_unused,
3328                                  int* old_number_of_fields) {
3329   // If fields were added (or removed), rewrite the instance.
3330   *old_number_of_fields = NumberOfFields();
3331   DCHECK(target_number_of_fields >= *old_number_of_fields);
3332   if (target_number_of_fields != *old_number_of_fields) return true;
3333 
3334   // If smi descriptors were replaced by double descriptors, rewrite.
3335   DescriptorArray* old_desc = instance_descriptors();
3336   DescriptorArray* new_desc = target->instance_descriptors();
3337   int limit = NumberOfOwnDescriptors();
3338   for (int i = 0; i < limit; i++) {
3339     if (new_desc->GetDetails(i).representation().IsDouble() !=
3340         old_desc->GetDetails(i).representation().IsDouble()) {
3341       return true;
3342     }
3343   }
3344 
3345   // If no fields were added, and no inobject properties were removed, setting
3346   // the map is sufficient.
3347   if (target_inobject == GetInObjectProperties()) return false;
3348   // In-object slack tracking may have reduced the object size of the new map.
3349   // In that case, succeed if all existing fields were inobject, and they still
3350   // fit within the new inobject size.
3351   DCHECK(target_inobject < GetInObjectProperties());
3352   if (target_number_of_fields <= target_inobject) {
3353     DCHECK(target_number_of_fields + target_unused == target_inobject);
3354     return false;
3355   }
3356   // Otherwise, properties will need to be moved to the backing store.
3357   return true;
3358 }
3359 
3360 
3361 // static
UpdatePrototypeUserRegistration(Handle<Map> old_map,Handle<Map> new_map,Isolate * isolate)3362 void JSObject::UpdatePrototypeUserRegistration(Handle<Map> old_map,
3363                                                Handle<Map> new_map,
3364                                                Isolate* isolate) {
3365   DCHECK(old_map->is_prototype_map());
3366   DCHECK(new_map->is_prototype_map());
3367   bool was_registered = JSObject::UnregisterPrototypeUser(old_map, isolate);
3368   new_map->set_prototype_info(old_map->prototype_info());
3369   old_map->set_prototype_info(Smi::kZero);
3370   if (FLAG_trace_prototype_users) {
3371     PrintF("Moving prototype_info %p from map %p to map %p.\n",
3372            reinterpret_cast<void*>(new_map->prototype_info()),
3373            reinterpret_cast<void*>(*old_map),
3374            reinterpret_cast<void*>(*new_map));
3375   }
3376   if (was_registered) {
3377     if (new_map->prototype_info()->IsPrototypeInfo()) {
3378       // The new map isn't registered with its prototype yet; reflect this fact
3379       // in the PrototypeInfo it just inherited from the old map.
3380       PrototypeInfo::cast(new_map->prototype_info())
3381           ->set_registry_slot(PrototypeInfo::UNREGISTERED);
3382     }
3383     JSObject::LazyRegisterPrototypeUser(new_map, isolate);
3384   }
3385 }
3386 
3387 namespace {
3388 // To migrate a fast instance to a fast map:
3389 // - First check whether the instance needs to be rewritten. If not, simply
3390 //   change the map.
3391 // - Otherwise, allocate a fixed array large enough to hold all fields, in
3392 //   addition to unused space.
3393 // - Copy all existing properties in, in the following order: backing store
3394 //   properties, unused fields, inobject properties.
3395 // - If all allocation succeeded, commit the state atomically:
3396 //   * Copy inobject properties from the backing store back into the object.
3397 //   * Trim the difference in instance size of the object. This also cleanly
3398 //     frees inobject properties that moved to the backing store.
3399 //   * If there are properties left in the backing store, trim of the space used
3400 //     to temporarily store the inobject properties.
3401 //   * If there are properties left in the backing store, install the backing
3402 //     store.
MigrateFastToFast(Handle<JSObject> object,Handle<Map> new_map)3403 void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
3404   Isolate* isolate = object->GetIsolate();
3405   Handle<Map> old_map(object->map());
3406   // In case of a regular transition.
3407   if (new_map->GetBackPointer() == *old_map) {
3408     // If the map does not add named properties, simply set the map.
3409     if (old_map->NumberOfOwnDescriptors() ==
3410         new_map->NumberOfOwnDescriptors()) {
3411       object->synchronized_set_map(*new_map);
3412       return;
3413     }
3414 
3415     PropertyDetails details = new_map->GetLastDescriptorDetails();
3416     // Either new_map adds an kDescriptor property, or a kField property for
3417     // which there is still space, and which does not require a mutable double
3418     // box (an out-of-object double).
3419     if (details.location() == kDescriptor ||
3420         (old_map->unused_property_fields() > 0 &&
3421          ((FLAG_unbox_double_fields && object->properties()->length() == 0) ||
3422           !details.representation().IsDouble()))) {
3423       object->synchronized_set_map(*new_map);
3424       return;
3425     }
3426 
3427     // If there is still space in the object, we need to allocate a mutable
3428     // double box.
3429     if (old_map->unused_property_fields() > 0) {
3430       FieldIndex index =
3431           FieldIndex::ForDescriptor(*new_map, new_map->LastAdded());
3432       DCHECK(details.representation().IsDouble());
3433       DCHECK(!new_map->IsUnboxedDoubleField(index));
3434       Handle<Object> value = isolate->factory()->NewMutableHeapNumber();
3435       object->RawFastPropertyAtPut(index, *value);
3436       object->synchronized_set_map(*new_map);
3437       return;
3438     }
3439 
3440     // This migration is a transition from a map that has run out of property
3441     // space. Extend the backing store.
3442     int grow_by = new_map->unused_property_fields() + 1;
3443     Handle<FixedArray> old_storage = handle(object->properties(), isolate);
3444     Handle<FixedArray> new_storage =
3445         isolate->factory()->CopyFixedArrayAndGrow(old_storage, grow_by);
3446 
3447     // Properly initialize newly added property.
3448     Handle<Object> value;
3449     if (details.representation().IsDouble()) {
3450       value = isolate->factory()->NewMutableHeapNumber();
3451     } else {
3452       value = isolate->factory()->uninitialized_value();
3453     }
3454     DCHECK_EQ(kField, details.location());
3455     DCHECK_EQ(kData, details.kind());
3456     int target_index = details.field_index() - new_map->GetInObjectProperties();
3457     DCHECK(target_index >= 0);  // Must be a backing store index.
3458     new_storage->set(target_index, *value);
3459 
3460     // From here on we cannot fail and we shouldn't GC anymore.
3461     DisallowHeapAllocation no_allocation;
3462 
3463     // Set the new property value and do the map transition.
3464     object->set_properties(*new_storage);
3465     object->synchronized_set_map(*new_map);
3466     return;
3467   }
3468 
3469   int old_number_of_fields;
3470   int number_of_fields = new_map->NumberOfFields();
3471   int inobject = new_map->GetInObjectProperties();
3472   int unused = new_map->unused_property_fields();
3473 
3474   // Nothing to do if no functions were converted to fields and no smis were
3475   // converted to doubles.
3476   if (!old_map->InstancesNeedRewriting(*new_map, number_of_fields, inobject,
3477                                        unused, &old_number_of_fields)) {
3478     object->synchronized_set_map(*new_map);
3479     return;
3480   }
3481 
3482   int total_size = number_of_fields + unused;
3483   int external = total_size - inobject;
3484 
3485   Handle<FixedArray> array = isolate->factory()->NewFixedArray(total_size);
3486 
3487   Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors());
3488   Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors());
3489   int old_nof = old_map->NumberOfOwnDescriptors();
3490   int new_nof = new_map->NumberOfOwnDescriptors();
3491 
3492   // This method only supports generalizing instances to at least the same
3493   // number of properties.
3494   DCHECK(old_nof <= new_nof);
3495 
3496   for (int i = 0; i < old_nof; i++) {
3497     PropertyDetails details = new_descriptors->GetDetails(i);
3498     if (details.location() != kField) continue;
3499     DCHECK_EQ(kData, details.kind());
3500     PropertyDetails old_details = old_descriptors->GetDetails(i);
3501     Representation old_representation = old_details.representation();
3502     Representation representation = details.representation();
3503     Handle<Object> value;
3504     if (old_details.location() == kDescriptor) {
3505       if (old_details.kind() == kAccessor) {
3506         // In case of kAccessor -> kData property reconfiguration, the property
3507         // must already be prepared for data of certain type.
3508         DCHECK(!details.representation().IsNone());
3509         if (details.representation().IsDouble()) {
3510           value = isolate->factory()->NewMutableHeapNumber();
3511         } else {
3512           value = isolate->factory()->uninitialized_value();
3513         }
3514       } else {
3515         DCHECK_EQ(kData, old_details.kind());
3516         value = handle(old_descriptors->GetValue(i), isolate);
3517         DCHECK(!old_representation.IsDouble() && !representation.IsDouble());
3518       }
3519     } else {
3520       DCHECK_EQ(kField, old_details.location());
3521       FieldIndex index = FieldIndex::ForDescriptor(*old_map, i);
3522       if (object->IsUnboxedDoubleField(index)) {
3523         uint64_t old_bits = object->RawFastDoublePropertyAsBitsAt(index);
3524         value = isolate->factory()->NewHeapNumberFromBits(
3525             old_bits, representation.IsDouble() ? MUTABLE : IMMUTABLE);
3526 
3527       } else {
3528         value = handle(object->RawFastPropertyAt(index), isolate);
3529         if (!old_representation.IsDouble() && representation.IsDouble()) {
3530           DCHECK_IMPLIES(old_representation.IsNone(),
3531                          value->IsUninitialized(isolate));
3532           value = Object::NewStorageFor(isolate, value, representation);
3533         } else if (old_representation.IsDouble() &&
3534                    !representation.IsDouble()) {
3535           value = Object::WrapForRead(isolate, value, old_representation);
3536         }
3537       }
3538     }
3539     DCHECK(!(representation.IsDouble() && value->IsSmi()));
3540     int target_index = new_descriptors->GetFieldIndex(i) - inobject;
3541     if (target_index < 0) target_index += total_size;
3542     array->set(target_index, *value);
3543   }
3544 
3545   for (int i = old_nof; i < new_nof; i++) {
3546     PropertyDetails details = new_descriptors->GetDetails(i);
3547     if (details.location() != kField) continue;
3548     DCHECK_EQ(kData, details.kind());
3549     Handle<Object> value;
3550     if (details.representation().IsDouble()) {
3551       value = isolate->factory()->NewMutableHeapNumber();
3552     } else {
3553       value = isolate->factory()->uninitialized_value();
3554     }
3555     int target_index = new_descriptors->GetFieldIndex(i) - inobject;
3556     if (target_index < 0) target_index += total_size;
3557     array->set(target_index, *value);
3558   }
3559 
3560   // From here on we cannot fail and we shouldn't GC anymore.
3561   DisallowHeapAllocation no_allocation;
3562 
3563   Heap* heap = isolate->heap();
3564 
3565   heap->NotifyObjectLayoutChange(*object, no_allocation);
3566 
3567   // Copy (real) inobject properties. If necessary, stop at number_of_fields to
3568   // avoid overwriting |one_pointer_filler_map|.
3569   int limit = Min(inobject, number_of_fields);
3570   for (int i = 0; i < limit; i++) {
3571     FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
3572     Object* value = array->get(external + i);
3573     // Can't use JSObject::FastPropertyAtPut() because proper map was not set
3574     // yet.
3575     if (new_map->IsUnboxedDoubleField(index)) {
3576       DCHECK(value->IsMutableHeapNumber());
3577       // Ensure that all bits of the double value are preserved.
3578       object->RawFastDoublePropertyAsBitsAtPut(
3579           index, HeapNumber::cast(value)->value_as_bits());
3580       if (i < old_number_of_fields && !old_map->IsUnboxedDoubleField(index)) {
3581         // Transition from tagged to untagged slot.
3582         heap->ClearRecordedSlot(*object,
3583                                 HeapObject::RawField(*object, index.offset()));
3584       } else {
3585         DCHECK(!heap->HasRecordedSlot(
3586             *object, HeapObject::RawField(*object, index.offset())));
3587       }
3588     } else {
3589       object->RawFastPropertyAtPut(index, value);
3590     }
3591   }
3592 
3593 
3594   // If there are properties in the new backing store, trim it to the correct
3595   // size and install the backing store into the object.
3596   if (external > 0) {
3597     heap->RightTrimFixedArray(*array, inobject);
3598     object->set_properties(*array);
3599   }
3600 
3601   // Create filler object past the new instance size.
3602   int new_instance_size = new_map->instance_size();
3603   int instance_size_delta = old_map->instance_size() - new_instance_size;
3604   DCHECK(instance_size_delta >= 0);
3605 
3606   if (instance_size_delta > 0) {
3607     Address address = object->address();
3608     heap->CreateFillerObjectAt(address + new_instance_size, instance_size_delta,
3609                                ClearRecordedSlots::kYes);
3610     heap->AdjustLiveBytes(*object, -instance_size_delta);
3611   }
3612 
3613   // We are storing the new map using release store after creating a filler for
3614   // the left-over space to avoid races with the sweeper thread.
3615   object->synchronized_set_map(*new_map);
3616 }
3617 
MigrateFastToSlow(Handle<JSObject> object,Handle<Map> new_map,int expected_additional_properties)3618 void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map,
3619                        int expected_additional_properties) {
3620   // The global object is always normalized.
3621   DCHECK(!object->IsJSGlobalObject());
3622   // JSGlobalProxy must never be normalized
3623   DCHECK(!object->IsJSGlobalProxy());
3624 
3625   Isolate* isolate = object->GetIsolate();
3626   HandleScope scope(isolate);
3627   Handle<Map> map(object->map());
3628 
3629   // Allocate new content.
3630   int real_size = map->NumberOfOwnDescriptors();
3631   int property_count = real_size;
3632   if (expected_additional_properties > 0) {
3633     property_count += expected_additional_properties;
3634   } else {
3635     // Make space for two more properties.
3636     property_count += NameDictionary::kInitialCapacity;
3637   }
3638   Handle<NameDictionary> dictionary =
3639       NameDictionary::New(isolate, property_count);
3640 
3641   Handle<DescriptorArray> descs(map->instance_descriptors());
3642   for (int i = 0; i < real_size; i++) {
3643     PropertyDetails details = descs->GetDetails(i);
3644     Handle<Name> key(descs->GetKey(i));
3645     Handle<Object> value;
3646     if (details.location() == kField) {
3647       FieldIndex index = FieldIndex::ForDescriptor(*map, i);
3648       if (details.kind() == kData) {
3649         if (object->IsUnboxedDoubleField(index)) {
3650           double old_value = object->RawFastDoublePropertyAt(index);
3651           value = isolate->factory()->NewHeapNumber(old_value);
3652         } else {
3653           value = handle(object->RawFastPropertyAt(index), isolate);
3654           if (details.representation().IsDouble()) {
3655             DCHECK(value->IsMutableHeapNumber());
3656             Handle<HeapNumber> old = Handle<HeapNumber>::cast(value);
3657             value = isolate->factory()->NewHeapNumber(old->value());
3658           }
3659         }
3660       } else {
3661         DCHECK_EQ(kAccessor, details.kind());
3662         value = handle(object->RawFastPropertyAt(index), isolate);
3663       }
3664 
3665     } else {
3666       DCHECK_EQ(kDescriptor, details.location());
3667       value = handle(descs->GetValue(i), isolate);
3668     }
3669     DCHECK(!value.is_null());
3670     PropertyDetails d(details.kind(), details.attributes(), i + 1,
3671                       PropertyCellType::kNoCell);
3672     dictionary = NameDictionary::Add(dictionary, key, value, d);
3673   }
3674 
3675   // Copy the next enumeration index from instance descriptor.
3676   dictionary->SetNextEnumerationIndex(real_size + 1);
3677 
3678   // From here on we cannot fail and we shouldn't GC anymore.
3679   DisallowHeapAllocation no_allocation;
3680 
3681   Heap* heap = isolate->heap();
3682   heap->NotifyObjectLayoutChange(*object, no_allocation);
3683 
3684   // Resize the object in the heap if necessary.
3685   int new_instance_size = new_map->instance_size();
3686   int instance_size_delta = map->instance_size() - new_instance_size;
3687   DCHECK(instance_size_delta >= 0);
3688 
3689   if (instance_size_delta > 0) {
3690     heap->CreateFillerObjectAt(object->address() + new_instance_size,
3691                                instance_size_delta, ClearRecordedSlots::kYes);
3692     heap->AdjustLiveBytes(*object, -instance_size_delta);
3693   }
3694 
3695   // We are storing the new map using release store after creating a filler for
3696   // the left-over space to avoid races with the sweeper thread.
3697   object->synchronized_set_map(*new_map);
3698 
3699   object->set_properties(*dictionary);
3700 
3701   // Ensure that in-object space of slow-mode object does not contain random
3702   // garbage.
3703   int inobject_properties = new_map->GetInObjectProperties();
3704   if (inobject_properties) {
3705     Heap* heap = isolate->heap();
3706     heap->ClearRecordedSlotRange(
3707         object->address() + map->GetInObjectPropertyOffset(0),
3708         object->address() + new_instance_size);
3709 
3710     for (int i = 0; i < inobject_properties; i++) {
3711       FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
3712       object->RawFastPropertyAtPut(index, Smi::kZero);
3713     }
3714   }
3715 
3716   isolate->counters()->props_to_dictionary()->Increment();
3717 
3718 #ifdef DEBUG
3719   if (FLAG_trace_normalization) {
3720     OFStream os(stdout);
3721     os << "Object properties have been normalized:\n";
3722     object->Print(os);
3723   }
3724 #endif
3725 }
3726 
3727 }  // namespace
3728 
3729 // static
NotifyMapChange(Handle<Map> old_map,Handle<Map> new_map,Isolate * isolate)3730 void JSObject::NotifyMapChange(Handle<Map> old_map, Handle<Map> new_map,
3731                                Isolate* isolate) {
3732   if (!old_map->is_prototype_map()) return;
3733 
3734   InvalidatePrototypeChains(*old_map);
3735 
3736   // If the map was registered with its prototype before, ensure that it
3737   // registers with its new prototype now. This preserves the invariant that
3738   // when a map on a prototype chain is registered with its prototype, then
3739   // all prototypes further up the chain are also registered with their
3740   // respective prototypes.
3741   UpdatePrototypeUserRegistration(old_map, new_map, isolate);
3742 }
3743 
MigrateToMap(Handle<JSObject> object,Handle<Map> new_map,int expected_additional_properties)3744 void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
3745                             int expected_additional_properties) {
3746   if (object->map() == *new_map) return;
3747   Handle<Map> old_map(object->map());
3748   NotifyMapChange(old_map, new_map, new_map->GetIsolate());
3749 
3750   if (old_map->is_dictionary_map()) {
3751     // For slow-to-fast migrations JSObject::MigrateSlowToFast()
3752     // must be used instead.
3753     CHECK(new_map->is_dictionary_map());
3754 
3755     // Slow-to-slow migration is trivial.
3756     object->set_map(*new_map);
3757   } else if (!new_map->is_dictionary_map()) {
3758     MigrateFastToFast(object, new_map);
3759     if (old_map->is_prototype_map()) {
3760       DCHECK(!old_map->is_stable());
3761       DCHECK(new_map->is_stable());
3762       // Clear out the old descriptor array to avoid problems to sharing
3763       // the descriptor array without using an explicit.
3764       old_map->InitializeDescriptors(
3765           old_map->GetHeap()->empty_descriptor_array(),
3766           LayoutDescriptor::FastPointerLayout());
3767       // Ensure that no transition was inserted for prototype migrations.
3768       DCHECK_EQ(
3769           0, TransitionArray::NumberOfTransitions(old_map->raw_transitions()));
3770       DCHECK(new_map->GetBackPointer()->IsUndefined(new_map->GetIsolate()));
3771     }
3772   } else {
3773     MigrateFastToSlow(object, new_map, expected_additional_properties);
3774   }
3775 
3776   // Careful: Don't allocate here!
3777   // For some callers of this method, |object| might be in an inconsistent
3778   // state now: the new map might have a new elements_kind, but the object's
3779   // elements pointer hasn't been updated yet. Callers will fix this, but in
3780   // the meantime, (indirectly) calling JSObjectVerify() must be avoided.
3781   // When adding code here, add a DisallowHeapAllocation too.
3782 }
3783 
ForceSetPrototype(Handle<JSObject> object,Handle<Object> proto)3784 void JSObject::ForceSetPrototype(Handle<JSObject> object,
3785                                  Handle<Object> proto) {
3786   // object.__proto__ = proto;
3787   Handle<Map> old_map = Handle<Map>(object->map());
3788   Handle<Map> new_map = Map::Copy(old_map, "ForceSetPrototype");
3789   Map::SetPrototype(new_map, proto, FAST_PROTOTYPE);
3790   JSObject::MigrateToMap(object, new_map);
3791 }
3792 
NumberOfFields()3793 int Map::NumberOfFields() {
3794   DescriptorArray* descriptors = instance_descriptors();
3795   int result = 0;
3796   for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
3797     if (descriptors->GetDetails(i).location() == kField) result++;
3798   }
3799   return result;
3800 }
3801 
GeneralizeAllFields()3802 void DescriptorArray::GeneralizeAllFields() {
3803   int length = number_of_descriptors();
3804   for (int i = 0; i < length; i++) {
3805     PropertyDetails details = GetDetails(i);
3806     details = details.CopyWithRepresentation(Representation::Tagged());
3807     if (details.location() == kField) {
3808       DCHECK_EQ(kData, details.kind());
3809       details = details.CopyWithConstness(kMutable);
3810       SetValue(i, FieldType::Any());
3811     }
3812     set(ToDetailsIndex(i), details.AsSmi());
3813   }
3814 }
3815 
CopyGeneralizeAllFields(Handle<Map> map,ElementsKind elements_kind,int modify_index,PropertyKind kind,PropertyAttributes attributes,const char * reason)3816 Handle<Map> Map::CopyGeneralizeAllFields(Handle<Map> map,
3817                                          ElementsKind elements_kind,
3818                                          int modify_index, PropertyKind kind,
3819                                          PropertyAttributes attributes,
3820                                          const char* reason) {
3821   Isolate* isolate = map->GetIsolate();
3822   Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
3823   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
3824   Handle<DescriptorArray> descriptors =
3825       DescriptorArray::CopyUpTo(old_descriptors, number_of_own_descriptors);
3826   descriptors->GeneralizeAllFields();
3827 
3828   Handle<LayoutDescriptor> new_layout_descriptor(
3829       LayoutDescriptor::FastPointerLayout(), isolate);
3830   Handle<Map> new_map = CopyReplaceDescriptors(
3831       map, descriptors, new_layout_descriptor, OMIT_TRANSITION,
3832       MaybeHandle<Name>(), reason, SPECIAL_TRANSITION);
3833 
3834   // Unless the instance is being migrated, ensure that modify_index is a field.
3835   if (modify_index >= 0) {
3836     PropertyDetails details = descriptors->GetDetails(modify_index);
3837     if (details.constness() != kMutable || details.location() != kField ||
3838         details.attributes() != attributes) {
3839       int field_index = details.location() == kField
3840                             ? details.field_index()
3841                             : new_map->NumberOfFields();
3842       Descriptor d = Descriptor::DataField(
3843           handle(descriptors->GetKey(modify_index), isolate), field_index,
3844           attributes, Representation::Tagged());
3845       descriptors->Replace(modify_index, &d);
3846       if (details.location() != kField) {
3847         int unused_property_fields = new_map->unused_property_fields() - 1;
3848         if (unused_property_fields < 0) {
3849           unused_property_fields += JSObject::kFieldsAdded;
3850         }
3851         new_map->set_unused_property_fields(unused_property_fields);
3852       }
3853     } else {
3854       DCHECK(details.attributes() == attributes);
3855     }
3856 
3857     if (FLAG_trace_generalization) {
3858       MaybeHandle<FieldType> field_type = FieldType::None(isolate);
3859       if (details.location() == kField) {
3860         field_type = handle(
3861             map->instance_descriptors()->GetFieldType(modify_index), isolate);
3862       }
3863       map->PrintGeneralization(
3864           stdout, reason, modify_index, new_map->NumberOfOwnDescriptors(),
3865           new_map->NumberOfOwnDescriptors(), details.location() == kDescriptor,
3866           details.representation(), Representation::Tagged(), field_type,
3867           MaybeHandle<Object>(), FieldType::Any(isolate),
3868           MaybeHandle<Object>());
3869     }
3870   }
3871   new_map->set_elements_kind(elements_kind);
3872   return new_map;
3873 }
3874 
3875 
DeprecateTransitionTree()3876 void Map::DeprecateTransitionTree() {
3877   if (is_deprecated()) return;
3878   Object* transitions = raw_transitions();
3879   int num_transitions = TransitionArray::NumberOfTransitions(transitions);
3880   for (int i = 0; i < num_transitions; ++i) {
3881     TransitionArray::GetTarget(transitions, i)->DeprecateTransitionTree();
3882   }
3883   deprecate();
3884   dependent_code()->DeoptimizeDependentCodeGroup(
3885       GetIsolate(), DependentCode::kTransitionGroup);
3886   NotifyLeafMapLayoutChange();
3887 }
3888 
3889 
3890 // Installs |new_descriptors| over the current instance_descriptors to ensure
3891 // proper sharing of descriptor arrays.
ReplaceDescriptors(DescriptorArray * new_descriptors,LayoutDescriptor * new_layout_descriptor)3892 void Map::ReplaceDescriptors(DescriptorArray* new_descriptors,
3893                              LayoutDescriptor* new_layout_descriptor) {
3894   Isolate* isolate = GetIsolate();
3895   // Don't overwrite the empty descriptor array or initial map's descriptors.
3896   if (NumberOfOwnDescriptors() == 0 || GetBackPointer()->IsUndefined(isolate)) {
3897     return;
3898   }
3899 
3900   DescriptorArray* to_replace = instance_descriptors();
3901   isolate->heap()->incremental_marking()->IterateBlackObject(to_replace);
3902   Map* current = this;
3903   while (current->instance_descriptors() == to_replace) {
3904     Object* next = current->GetBackPointer();
3905     if (next->IsUndefined(isolate)) break;  // Stop overwriting at initial map.
3906     current->SetEnumLength(kInvalidEnumCacheSentinel);
3907     current->UpdateDescriptors(new_descriptors, new_layout_descriptor);
3908     current = Map::cast(next);
3909   }
3910   set_owns_descriptors(false);
3911 }
3912 
3913 
FindRootMap()3914 Map* Map::FindRootMap() {
3915   Map* result = this;
3916   Isolate* isolate = GetIsolate();
3917   while (true) {
3918     Object* back = result->GetBackPointer();
3919     if (back->IsUndefined(isolate)) {
3920       // Initial map always owns descriptors and doesn't have unused entries
3921       // in the descriptor array.
3922       DCHECK(result->owns_descriptors());
3923       DCHECK_EQ(result->NumberOfOwnDescriptors(),
3924                 result->instance_descriptors()->number_of_descriptors());
3925       return result;
3926     }
3927     result = Map::cast(back);
3928   }
3929 }
3930 
3931 
FindFieldOwner(int descriptor)3932 Map* Map::FindFieldOwner(int descriptor) {
3933   DisallowHeapAllocation no_allocation;
3934   DCHECK_EQ(kField, instance_descriptors()->GetDetails(descriptor).location());
3935   Map* result = this;
3936   Isolate* isolate = GetIsolate();
3937   while (true) {
3938     Object* back = result->GetBackPointer();
3939     if (back->IsUndefined(isolate)) break;
3940     Map* parent = Map::cast(back);
3941     if (parent->NumberOfOwnDescriptors() <= descriptor) break;
3942     result = parent;
3943   }
3944   return result;
3945 }
3946 
UpdateFieldType(int descriptor,Handle<Name> name,PropertyConstness new_constness,Representation new_representation,Handle<Object> new_wrapped_type)3947 void Map::UpdateFieldType(int descriptor, Handle<Name> name,
3948                           PropertyConstness new_constness,
3949                           Representation new_representation,
3950                           Handle<Object> new_wrapped_type) {
3951   DCHECK(new_wrapped_type->IsSmi() || new_wrapped_type->IsWeakCell());
3952   // We store raw pointers in the queue, so no allocations are allowed.
3953   DisallowHeapAllocation no_allocation;
3954   PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
3955   if (details.location() != kField) return;
3956   DCHECK_EQ(kData, details.kind());
3957 
3958   Zone zone(GetIsolate()->allocator(), ZONE_NAME);
3959   ZoneQueue<Map*> backlog(&zone);
3960   backlog.push(this);
3961 
3962   while (!backlog.empty()) {
3963     Map* current = backlog.front();
3964     backlog.pop();
3965 
3966     Object* transitions = current->raw_transitions();
3967     int num_transitions = TransitionArray::NumberOfTransitions(transitions);
3968     for (int i = 0; i < num_transitions; ++i) {
3969       Map* target = TransitionArray::GetTarget(transitions, i);
3970       backlog.push(target);
3971     }
3972     DescriptorArray* descriptors = current->instance_descriptors();
3973     PropertyDetails details = descriptors->GetDetails(descriptor);
3974 
3975     // Currently constness change implies map change.
3976     DCHECK_EQ(new_constness, details.constness());
3977 
3978     // It is allowed to change representation here only from None to something.
3979     DCHECK(details.representation().Equals(new_representation) ||
3980            details.representation().IsNone());
3981 
3982     // Skip if already updated the shared descriptor.
3983     if (descriptors->GetValue(descriptor) != *new_wrapped_type) {
3984       DCHECK_IMPLIES(!FLAG_track_constant_fields, new_constness == kMutable);
3985       Descriptor d = Descriptor::DataField(
3986           name, descriptors->GetFieldIndex(descriptor), details.attributes(),
3987           new_constness, new_representation, new_wrapped_type);
3988       descriptors->Replace(descriptor, &d);
3989     }
3990   }
3991 }
3992 
FieldTypeIsCleared(Representation rep,FieldType * type)3993 bool FieldTypeIsCleared(Representation rep, FieldType* type) {
3994   return type->IsNone() && rep.IsHeapObject();
3995 }
3996 
3997 
3998 // static
GeneralizeFieldType(Representation rep1,Handle<FieldType> type1,Representation rep2,Handle<FieldType> type2,Isolate * isolate)3999 Handle<FieldType> Map::GeneralizeFieldType(Representation rep1,
4000                                            Handle<FieldType> type1,
4001                                            Representation rep2,
4002                                            Handle<FieldType> type2,
4003                                            Isolate* isolate) {
4004   // Cleared field types need special treatment. They represent lost knowledge,
4005   // so we must be conservative, so their generalization with any other type
4006   // is "Any".
4007   if (FieldTypeIsCleared(rep1, *type1) || FieldTypeIsCleared(rep2, *type2)) {
4008     return FieldType::Any(isolate);
4009   }
4010   if (type1->NowIs(type2)) return type2;
4011   if (type2->NowIs(type1)) return type1;
4012   return FieldType::Any(isolate);
4013 }
4014 
4015 
4016 // static
GeneralizeField(Handle<Map> map,int modify_index,PropertyConstness new_constness,Representation new_representation,Handle<FieldType> new_field_type)4017 void Map::GeneralizeField(Handle<Map> map, int modify_index,
4018                           PropertyConstness new_constness,
4019                           Representation new_representation,
4020                           Handle<FieldType> new_field_type) {
4021   Isolate* isolate = map->GetIsolate();
4022 
4023   // Check if we actually need to generalize the field type at all.
4024   Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
4025   PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
4026   PropertyConstness old_constness = old_details.constness();
4027   Representation old_representation = old_details.representation();
4028   Handle<FieldType> old_field_type(old_descriptors->GetFieldType(modify_index),
4029                                    isolate);
4030 
4031   if (old_constness == new_constness &&
4032       old_representation.Equals(new_representation) &&
4033       !FieldTypeIsCleared(new_representation, *new_field_type) &&
4034       // Checking old_field_type for being cleared is not necessary because
4035       // the NowIs check below would fail anyway in that case.
4036       new_field_type->NowIs(old_field_type)) {
4037     DCHECK(GeneralizeFieldType(old_representation, old_field_type,
4038                                new_representation, new_field_type, isolate)
4039                ->NowIs(old_field_type));
4040     return;
4041   }
4042 
4043   // Determine the field owner.
4044   Handle<Map> field_owner(map->FindFieldOwner(modify_index), isolate);
4045   Handle<DescriptorArray> descriptors(
4046       field_owner->instance_descriptors(), isolate);
4047   DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index));
4048 
4049   new_field_type =
4050       Map::GeneralizeFieldType(old_representation, old_field_type,
4051                                new_representation, new_field_type, isolate);
4052 
4053   PropertyDetails details = descriptors->GetDetails(modify_index);
4054   Handle<Name> name(descriptors->GetKey(modify_index));
4055 
4056   Handle<Object> wrapped_type(WrapFieldType(new_field_type));
4057   field_owner->UpdateFieldType(modify_index, name, new_constness,
4058                                new_representation, wrapped_type);
4059   field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
4060       isolate, DependentCode::kFieldOwnerGroup);
4061 
4062   if (FLAG_trace_generalization) {
4063     map->PrintGeneralization(
4064         stdout, "field type generalization", modify_index,
4065         map->NumberOfOwnDescriptors(), map->NumberOfOwnDescriptors(), false,
4066         details.representation(), details.representation(), old_field_type,
4067         MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>());
4068   }
4069 }
4070 
4071 // TODO(ishell): remove.
4072 // static
ReconfigureProperty(Handle<Map> map,int modify_index,PropertyKind new_kind,PropertyAttributes new_attributes,Representation new_representation,Handle<FieldType> new_field_type)4073 Handle<Map> Map::ReconfigureProperty(Handle<Map> map, int modify_index,
4074                                      PropertyKind new_kind,
4075                                      PropertyAttributes new_attributes,
4076                                      Representation new_representation,
4077                                      Handle<FieldType> new_field_type) {
4078   DCHECK_EQ(kData, new_kind);  // Only kData case is supported.
4079   MapUpdater mu(map->GetIsolate(), map);
4080   return mu.ReconfigureToDataField(modify_index, new_attributes, kConst,
4081                                    new_representation, new_field_type);
4082 }
4083 
4084 // TODO(ishell): remove.
4085 // static
ReconfigureElementsKind(Handle<Map> map,ElementsKind new_elements_kind)4086 Handle<Map> Map::ReconfigureElementsKind(Handle<Map> map,
4087                                          ElementsKind new_elements_kind) {
4088   MapUpdater mu(map->GetIsolate(), map);
4089   return mu.ReconfigureElementsKind(new_elements_kind);
4090 }
4091 
4092 // Generalize all fields and update the transition tree.
GeneralizeAllFields(Handle<Map> map)4093 Handle<Map> Map::GeneralizeAllFields(Handle<Map> map) {
4094   Isolate* isolate = map->GetIsolate();
4095   Handle<FieldType> any_type = FieldType::Any(isolate);
4096 
4097   Handle<DescriptorArray> descriptors(map->instance_descriptors());
4098   for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) {
4099     PropertyDetails details = descriptors->GetDetails(i);
4100     if (details.location() == kField) {
4101       DCHECK_EQ(kData, details.kind());
4102       MapUpdater mu(isolate, map);
4103       map = mu.ReconfigureToDataField(i, details.attributes(), kMutable,
4104                                       Representation::Tagged(), any_type);
4105     }
4106   }
4107   return map;
4108 }
4109 
4110 
4111 // static
TryUpdate(Handle<Map> old_map)4112 MaybeHandle<Map> Map::TryUpdate(Handle<Map> old_map) {
4113   DisallowHeapAllocation no_allocation;
4114   DisallowDeoptimization no_deoptimization(old_map->GetIsolate());
4115 
4116   if (!old_map->is_deprecated()) return old_map;
4117 
4118   // Check the state of the root map.
4119   Map* root_map = old_map->FindRootMap();
4120   if (!old_map->EquivalentToForTransition(root_map)) return MaybeHandle<Map>();
4121 
4122   ElementsKind from_kind = root_map->elements_kind();
4123   ElementsKind to_kind = old_map->elements_kind();
4124   if (from_kind != to_kind) {
4125     // Try to follow existing elements kind transitions.
4126     root_map = root_map->LookupElementsTransitionMap(to_kind);
4127     if (root_map == NULL) return MaybeHandle<Map>();
4128     // From here on, use the map with correct elements kind as root map.
4129   }
4130   Map* new_map = root_map->TryReplayPropertyTransitions(*old_map);
4131   if (new_map == nullptr) return MaybeHandle<Map>();
4132   return handle(new_map);
4133 }
4134 
TryReplayPropertyTransitions(Map * old_map)4135 Map* Map::TryReplayPropertyTransitions(Map* old_map) {
4136   DisallowHeapAllocation no_allocation;
4137   DisallowDeoptimization no_deoptimization(GetIsolate());
4138 
4139   int root_nof = NumberOfOwnDescriptors();
4140 
4141   int old_nof = old_map->NumberOfOwnDescriptors();
4142   DescriptorArray* old_descriptors = old_map->instance_descriptors();
4143 
4144   Map* new_map = this;
4145   for (int i = root_nof; i < old_nof; ++i) {
4146     PropertyDetails old_details = old_descriptors->GetDetails(i);
4147     Map* transition = TransitionArray::SearchTransition(
4148         new_map, old_details.kind(), old_descriptors->GetKey(i),
4149         old_details.attributes());
4150     if (transition == NULL) return nullptr;
4151     new_map = transition;
4152     DescriptorArray* new_descriptors = new_map->instance_descriptors();
4153 
4154     PropertyDetails new_details = new_descriptors->GetDetails(i);
4155     DCHECK_EQ(old_details.kind(), new_details.kind());
4156     DCHECK_EQ(old_details.attributes(), new_details.attributes());
4157     if (!IsGeneralizableTo(old_details.constness(), new_details.constness())) {
4158       return nullptr;
4159     }
4160     DCHECK(IsGeneralizableTo(old_details.location(), new_details.location()));
4161     if (!old_details.representation().fits_into(new_details.representation())) {
4162       return nullptr;
4163     }
4164     if (new_details.location() == kField) {
4165       if (new_details.kind() == kData) {
4166         FieldType* new_type = new_descriptors->GetFieldType(i);
4167         // Cleared field types need special treatment. They represent lost
4168         // knowledge, so we must first generalize the new_type to "Any".
4169         if (FieldTypeIsCleared(new_details.representation(), new_type)) {
4170           return nullptr;
4171         }
4172         DCHECK_EQ(kData, old_details.kind());
4173         if (old_details.location() == kField) {
4174           FieldType* old_type = old_descriptors->GetFieldType(i);
4175           if (FieldTypeIsCleared(old_details.representation(), old_type) ||
4176               !old_type->NowIs(new_type)) {
4177             return nullptr;
4178           }
4179         } else {
4180           DCHECK_EQ(kDescriptor, old_details.location());
4181           DCHECK(!FLAG_track_constant_fields);
4182           Object* old_value = old_descriptors->GetValue(i);
4183           if (!new_type->NowContains(old_value)) {
4184             return nullptr;
4185           }
4186         }
4187 
4188       } else {
4189         DCHECK_EQ(kAccessor, new_details.kind());
4190 #ifdef DEBUG
4191         FieldType* new_type = new_descriptors->GetFieldType(i);
4192         DCHECK(new_type->IsAny());
4193 #endif
4194         UNREACHABLE();
4195       }
4196     } else {
4197       DCHECK_EQ(kDescriptor, new_details.location());
4198       Object* old_value = old_descriptors->GetValue(i);
4199       Object* new_value = new_descriptors->GetValue(i);
4200       if (old_details.location() == kField || old_value != new_value) {
4201         return nullptr;
4202       }
4203     }
4204   }
4205   if (new_map->NumberOfOwnDescriptors() != old_nof) return nullptr;
4206   return new_map;
4207 }
4208 
4209 
4210 // static
Update(Handle<Map> map)4211 Handle<Map> Map::Update(Handle<Map> map) {
4212   if (!map->is_deprecated()) return map;
4213   MapUpdater mu(map->GetIsolate(), map);
4214   return mu.Update();
4215 }
4216 
SetPropertyWithInterceptor(LookupIterator * it,ShouldThrow should_throw,Handle<Object> value)4217 Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
4218                                                  ShouldThrow should_throw,
4219                                                  Handle<Object> value) {
4220   DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
4221   return SetPropertyWithInterceptorInternal(it, it->GetInterceptor(),
4222                                             should_throw, value);
4223 }
4224 
SetProperty(Handle<Object> object,Handle<Name> name,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode)4225 MaybeHandle<Object> Object::SetProperty(Handle<Object> object,
4226                                         Handle<Name> name, Handle<Object> value,
4227                                         LanguageMode language_mode,
4228                                         StoreFromKeyed store_mode) {
4229   LookupIterator it(object, name);
4230   MAYBE_RETURN_NULL(SetProperty(&it, value, language_mode, store_mode));
4231   return value;
4232 }
4233 
4234 
SetPropertyInternal(LookupIterator * it,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode,bool * found)4235 Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
4236                                         Handle<Object> value,
4237                                         LanguageMode language_mode,
4238                                         StoreFromKeyed store_mode,
4239                                         bool* found) {
4240   it->UpdateProtector();
4241   DCHECK(it->IsFound());
4242   ShouldThrow should_throw =
4243       is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4244 
4245   // Make sure that the top context does not change when doing callbacks or
4246   // interceptor calls.
4247   AssertNoContextChange ncc(it->isolate());
4248 
4249   do {
4250     switch (it->state()) {
4251       case LookupIterator::NOT_FOUND:
4252         UNREACHABLE();
4253 
4254       case LookupIterator::ACCESS_CHECK:
4255         if (it->HasAccess()) break;
4256         // Check whether it makes sense to reuse the lookup iterator. Here it
4257         // might still call into setters up the prototype chain.
4258         return JSObject::SetPropertyWithFailedAccessCheck(it, value,
4259                                                           should_throw);
4260 
4261       case LookupIterator::JSPROXY:
4262         return JSProxy::SetProperty(it->GetHolder<JSProxy>(), it->GetName(),
4263                                     value, it->GetReceiver(), language_mode);
4264 
4265       case LookupIterator::INTERCEPTOR: {
4266         if (it->HolderIsReceiverOrHiddenPrototype()) {
4267           Maybe<bool> result =
4268               JSObject::SetPropertyWithInterceptor(it, should_throw, value);
4269           if (result.IsNothing() || result.FromJust()) return result;
4270         } else {
4271           Maybe<PropertyAttributes> maybe_attributes =
4272               JSObject::GetPropertyAttributesWithInterceptor(it);
4273           if (!maybe_attributes.IsJust()) return Nothing<bool>();
4274           if ((maybe_attributes.FromJust() & READ_ONLY) != 0) {
4275             return WriteToReadOnlyProperty(it, value, should_throw);
4276           }
4277           if (maybe_attributes.FromJust() == ABSENT) break;
4278           *found = false;
4279           return Nothing<bool>();
4280         }
4281         break;
4282       }
4283 
4284       case LookupIterator::ACCESSOR: {
4285         if (it->IsReadOnly()) {
4286           return WriteToReadOnlyProperty(it, value, should_throw);
4287         }
4288         Handle<Object> accessors = it->GetAccessors();
4289         if (accessors->IsAccessorInfo() &&
4290             !it->HolderIsReceiverOrHiddenPrototype() &&
4291             AccessorInfo::cast(*accessors)->is_special_data_property()) {
4292           *found = false;
4293           return Nothing<bool>();
4294         }
4295         return SetPropertyWithAccessor(it, value, should_throw);
4296       }
4297       case LookupIterator::INTEGER_INDEXED_EXOTIC:
4298         // TODO(verwaest): We should throw an exception if holder is receiver.
4299         return Just(true);
4300 
4301       case LookupIterator::DATA:
4302         if (it->IsReadOnly()) {
4303           return WriteToReadOnlyProperty(it, value, should_throw);
4304         }
4305         if (it->HolderIsReceiverOrHiddenPrototype()) {
4306           return SetDataProperty(it, value);
4307         }
4308       // Fall through.
4309       case LookupIterator::TRANSITION:
4310         *found = false;
4311         return Nothing<bool>();
4312     }
4313     it->Next();
4314   } while (it->IsFound());
4315 
4316   *found = false;
4317   return Nothing<bool>();
4318 }
4319 
4320 
SetProperty(LookupIterator * it,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode)4321 Maybe<bool> Object::SetProperty(LookupIterator* it, Handle<Object> value,
4322                                 LanguageMode language_mode,
4323                                 StoreFromKeyed store_mode) {
4324   if (it->IsFound()) {
4325     bool found = true;
4326     Maybe<bool> result =
4327         SetPropertyInternal(it, value, language_mode, store_mode, &found);
4328     if (found) return result;
4329   }
4330 
4331   // If the receiver is the JSGlobalObject, the store was contextual. In case
4332   // the property did not exist yet on the global object itself, we have to
4333   // throw a reference error in strict mode.  In sloppy mode, we continue.
4334   if (is_strict(language_mode) && it->GetReceiver()->IsJSGlobalObject()) {
4335     it->isolate()->Throw(*it->isolate()->factory()->NewReferenceError(
4336         MessageTemplate::kNotDefined, it->name()));
4337     return Nothing<bool>();
4338   }
4339 
4340   ShouldThrow should_throw =
4341       is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4342   return AddDataProperty(it, value, NONE, should_throw, store_mode);
4343 }
4344 
4345 
SetSuperProperty(LookupIterator * it,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode)4346 Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
4347                                      LanguageMode language_mode,
4348                                      StoreFromKeyed store_mode) {
4349   Isolate* isolate = it->isolate();
4350 
4351   if (it->IsFound()) {
4352     bool found = true;
4353     Maybe<bool> result =
4354         SetPropertyInternal(it, value, language_mode, store_mode, &found);
4355     if (found) return result;
4356   }
4357 
4358   it->UpdateProtector();
4359 
4360   // The property either doesn't exist on the holder or exists there as a data
4361   // property.
4362 
4363   ShouldThrow should_throw =
4364       is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4365 
4366   if (!it->GetReceiver()->IsJSReceiver()) {
4367     return WriteToReadOnlyProperty(it, value, should_throw);
4368   }
4369   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
4370 
4371   LookupIterator::Configuration c = LookupIterator::OWN;
4372   LookupIterator own_lookup =
4373       it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c)
4374                       : LookupIterator(receiver, it->name(), c);
4375 
4376   for (; own_lookup.IsFound(); own_lookup.Next()) {
4377     switch (own_lookup.state()) {
4378       case LookupIterator::ACCESS_CHECK:
4379         if (!own_lookup.HasAccess()) {
4380           return JSObject::SetPropertyWithFailedAccessCheck(&own_lookup, value,
4381                                                             should_throw);
4382         }
4383         break;
4384 
4385       case LookupIterator::ACCESSOR:
4386         if (own_lookup.GetAccessors()->IsAccessorInfo()) {
4387           if (own_lookup.IsReadOnly()) {
4388             return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
4389           }
4390           return JSObject::SetPropertyWithAccessor(&own_lookup, value,
4391                                                    should_throw);
4392         }
4393       // Fall through.
4394       case LookupIterator::INTEGER_INDEXED_EXOTIC:
4395         return RedefineIncompatibleProperty(isolate, it->GetName(), value,
4396                                             should_throw);
4397 
4398       case LookupIterator::DATA: {
4399         if (own_lookup.IsReadOnly()) {
4400           return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
4401         }
4402         return SetDataProperty(&own_lookup, value);
4403       }
4404 
4405       case LookupIterator::INTERCEPTOR:
4406       case LookupIterator::JSPROXY: {
4407         PropertyDescriptor desc;
4408         Maybe<bool> owned =
4409             JSReceiver::GetOwnPropertyDescriptor(&own_lookup, &desc);
4410         MAYBE_RETURN(owned, Nothing<bool>());
4411         if (!owned.FromJust()) {
4412           return JSReceiver::CreateDataProperty(&own_lookup, value,
4413                                                 should_throw);
4414         }
4415         if (PropertyDescriptor::IsAccessorDescriptor(&desc) ||
4416             !desc.writable()) {
4417           return RedefineIncompatibleProperty(isolate, it->GetName(), value,
4418                                               should_throw);
4419         }
4420 
4421         PropertyDescriptor value_desc;
4422         value_desc.set_value(value);
4423         return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
4424                                              &value_desc, should_throw);
4425       }
4426 
4427       case LookupIterator::NOT_FOUND:
4428       case LookupIterator::TRANSITION:
4429         UNREACHABLE();
4430     }
4431   }
4432 
4433   return AddDataProperty(&own_lookup, value, NONE, should_throw, store_mode);
4434 }
4435 
CannotCreateProperty(Isolate * isolate,Handle<Object> receiver,Handle<Object> name,Handle<Object> value,ShouldThrow should_throw)4436 Maybe<bool> Object::CannotCreateProperty(Isolate* isolate,
4437                                          Handle<Object> receiver,
4438                                          Handle<Object> name,
4439                                          Handle<Object> value,
4440                                          ShouldThrow should_throw) {
4441   RETURN_FAILURE(
4442       isolate, should_throw,
4443       NewTypeError(MessageTemplate::kStrictCannotCreateProperty, name,
4444                    Object::TypeOf(isolate, receiver), receiver));
4445 }
4446 
4447 
WriteToReadOnlyProperty(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)4448 Maybe<bool> Object::WriteToReadOnlyProperty(LookupIterator* it,
4449                                             Handle<Object> value,
4450                                             ShouldThrow should_throw) {
4451   return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(),
4452                                  it->GetName(), value, should_throw);
4453 }
4454 
4455 
WriteToReadOnlyProperty(Isolate * isolate,Handle<Object> receiver,Handle<Object> name,Handle<Object> value,ShouldThrow should_throw)4456 Maybe<bool> Object::WriteToReadOnlyProperty(Isolate* isolate,
4457                                             Handle<Object> receiver,
4458                                             Handle<Object> name,
4459                                             Handle<Object> value,
4460                                             ShouldThrow should_throw) {
4461   RETURN_FAILURE(isolate, should_throw,
4462                  NewTypeError(MessageTemplate::kStrictReadOnlyProperty, name,
4463                               Object::TypeOf(isolate, receiver), receiver));
4464 }
4465 
4466 
RedefineIncompatibleProperty(Isolate * isolate,Handle<Object> name,Handle<Object> value,ShouldThrow should_throw)4467 Maybe<bool> Object::RedefineIncompatibleProperty(Isolate* isolate,
4468                                                  Handle<Object> name,
4469                                                  Handle<Object> value,
4470                                                  ShouldThrow should_throw) {
4471   RETURN_FAILURE(isolate, should_throw,
4472                  NewTypeError(MessageTemplate::kRedefineDisallowed, name));
4473 }
4474 
4475 
SetDataProperty(LookupIterator * it,Handle<Object> value)4476 Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) {
4477   // Proxies are handled elsewhere. Other non-JSObjects cannot have own
4478   // properties.
4479   Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
4480 
4481   // Store on the holder which may be hidden behind the receiver.
4482   DCHECK(it->HolderIsReceiverOrHiddenPrototype());
4483 
4484   Handle<Object> to_assign = value;
4485   // Convert the incoming value to a number for storing into typed arrays.
4486   if (it->IsElement() && receiver->HasFixedTypedArrayElements()) {
4487     if (!value->IsNumber() && !value->IsUndefined(it->isolate())) {
4488       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4489           it->isolate(), to_assign, Object::ToNumber(value), Nothing<bool>());
4490       // We have to recheck the length. However, it can only change if the
4491       // underlying buffer was neutered, so just check that.
4492       if (Handle<JSArrayBufferView>::cast(receiver)->WasNeutered()) {
4493         return Just(true);
4494         // TODO(neis): According to the spec, this should throw a TypeError.
4495       }
4496     }
4497   }
4498 
4499   // Possibly migrate to the most up-to-date map that will be able to store
4500   // |value| under it->name().
4501   it->PrepareForDataProperty(to_assign);
4502 
4503   // Write the property value.
4504   it->WriteDataValue(to_assign, false);
4505 
4506 #if VERIFY_HEAP
4507   if (FLAG_verify_heap) {
4508     receiver->JSObjectVerify();
4509   }
4510 #endif
4511   return Just(true);
4512 }
4513 
4514 
AddDataProperty(LookupIterator * it,Handle<Object> value,PropertyAttributes attributes,ShouldThrow should_throw,StoreFromKeyed store_mode)4515 Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value,
4516                                     PropertyAttributes attributes,
4517                                     ShouldThrow should_throw,
4518                                     StoreFromKeyed store_mode) {
4519   if (!it->GetReceiver()->IsJSObject()) {
4520     if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate()) {
4521       RETURN_FAILURE(it->isolate(), should_throw,
4522                      NewTypeError(MessageTemplate::kProxyPrivate));
4523     }
4524     return CannotCreateProperty(it->isolate(), it->GetReceiver(), it->GetName(),
4525                                 value, should_throw);
4526   }
4527 
4528   DCHECK_NE(LookupIterator::INTEGER_INDEXED_EXOTIC, it->state());
4529 
4530   Handle<JSObject> receiver = it->GetStoreTarget();
4531 
4532   // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject)
4533   // instead. If the prototype is Null, the proxy is detached.
4534   if (receiver->IsJSGlobalProxy()) return Just(true);
4535 
4536   Isolate* isolate = it->isolate();
4537 
4538   if (it->ExtendingNonExtensible(receiver)) {
4539     RETURN_FAILURE(
4540         isolate, should_throw,
4541         NewTypeError(MessageTemplate::kObjectNotExtensible, it->GetName()));
4542   }
4543 
4544   if (it->IsElement()) {
4545     if (receiver->IsJSArray()) {
4546       Handle<JSArray> array = Handle<JSArray>::cast(receiver);
4547       if (JSArray::WouldChangeReadOnlyLength(array, it->index())) {
4548         RETURN_FAILURE(array->GetIsolate(), should_throw,
4549                        NewTypeError(MessageTemplate::kStrictReadOnlyProperty,
4550                                     isolate->factory()->length_string(),
4551                                     Object::TypeOf(isolate, array), array));
4552       }
4553 
4554       if (FLAG_trace_external_array_abuse &&
4555           array->HasFixedTypedArrayElements()) {
4556         CheckArrayAbuse(array, "typed elements write", it->index(), true);
4557       }
4558 
4559       if (FLAG_trace_js_array_abuse && !array->HasFixedTypedArrayElements()) {
4560         CheckArrayAbuse(array, "elements write", it->index(), false);
4561       }
4562     }
4563 
4564     Maybe<bool> result = JSObject::AddDataElement(receiver, it->index(), value,
4565                                                   attributes, should_throw);
4566     JSObject::ValidateElements(receiver);
4567     return result;
4568   } else {
4569     it->UpdateProtector();
4570     // Migrate to the most up-to-date map that will be able to store |value|
4571     // under it->name() with |attributes|.
4572     it->PrepareTransitionToDataProperty(receiver, value, attributes,
4573                                         store_mode);
4574     DCHECK_EQ(LookupIterator::TRANSITION, it->state());
4575     it->ApplyTransitionToDataProperty(receiver);
4576 
4577     // Write the property value.
4578     it->WriteDataValue(value, true);
4579 
4580 #if VERIFY_HEAP
4581     if (FLAG_verify_heap) {
4582       receiver->JSObjectVerify();
4583     }
4584 #endif
4585   }
4586 
4587   return Just(true);
4588 }
4589 
4590 
EnsureDescriptorSlack(Handle<Map> map,int slack)4591 void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
4592   // Only supports adding slack to owned descriptors.
4593   DCHECK(map->owns_descriptors());
4594 
4595   Handle<DescriptorArray> descriptors(map->instance_descriptors());
4596   int old_size = map->NumberOfOwnDescriptors();
4597   if (slack <= descriptors->NumberOfSlackDescriptors()) return;
4598 
4599   Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
4600       descriptors, old_size, slack);
4601 
4602   DisallowHeapAllocation no_allocation;
4603   // The descriptors are still the same, so keep the layout descriptor.
4604   LayoutDescriptor* layout_descriptor = map->GetLayoutDescriptor();
4605 
4606   if (old_size == 0) {
4607     map->UpdateDescriptors(*new_descriptors, layout_descriptor);
4608     return;
4609   }
4610 
4611   // If the source descriptors had an enum cache we copy it. This ensures
4612   // that the maps to which we push the new descriptor array back can rely
4613   // on a cache always being available once it is set. If the map has more
4614   // enumerated descriptors than available in the original cache, the cache
4615   // will be lazily replaced by the extended cache when needed.
4616   if (descriptors->HasEnumCache()) {
4617     new_descriptors->CopyEnumCacheFrom(*descriptors);
4618   }
4619 
4620   Isolate* isolate = map->GetIsolate();
4621   // Replace descriptors by new_descriptors in all maps that share it.
4622   isolate->heap()->incremental_marking()->IterateBlackObject(*descriptors);
4623 
4624   Map* current = *map;
4625   while (current->instance_descriptors() == *descriptors) {
4626     Object* next = current->GetBackPointer();
4627     if (next->IsUndefined(isolate)) break;  // Stop overwriting at initial map.
4628     current->UpdateDescriptors(*new_descriptors, layout_descriptor);
4629     current = Map::cast(next);
4630   }
4631   map->UpdateDescriptors(*new_descriptors, layout_descriptor);
4632 }
4633 
4634 // static
GetObjectCreateMap(Handle<HeapObject> prototype)4635 Handle<Map> Map::GetObjectCreateMap(Handle<HeapObject> prototype) {
4636   Isolate* isolate = prototype->GetIsolate();
4637   Handle<Map> map(isolate->native_context()->object_function()->initial_map(),
4638                   isolate);
4639   if (map->prototype() == *prototype) return map;
4640   if (prototype->IsNull(isolate)) {
4641     return isolate->slow_object_with_null_prototype_map();
4642   }
4643   if (prototype->IsJSObject()) {
4644     Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype);
4645     if (!js_prototype->map()->is_prototype_map()) {
4646       JSObject::OptimizeAsPrototype(js_prototype, FAST_PROTOTYPE);
4647     }
4648     Handle<PrototypeInfo> info =
4649         Map::GetOrCreatePrototypeInfo(js_prototype, isolate);
4650     // TODO(verwaest): Use inobject slack tracking for this map.
4651     if (info->HasObjectCreateMap()) {
4652       map = handle(info->ObjectCreateMap(), isolate);
4653     } else {
4654       map = Map::CopyInitialMap(map);
4655       Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
4656       PrototypeInfo::SetObjectCreateMap(info, map);
4657     }
4658     return map;
4659   }
4660 
4661   return Map::TransitionToPrototype(map, prototype, REGULAR_PROTOTYPE);
4662 }
4663 
4664 template <class T>
AppendUniqueCallbacks(Handle<TemplateList> callbacks,Handle<typename T::Array> array,int valid_descriptors)4665 static int AppendUniqueCallbacks(Handle<TemplateList> callbacks,
4666                                  Handle<typename T::Array> array,
4667                                  int valid_descriptors) {
4668   int nof_callbacks = callbacks->length();
4669 
4670   Isolate* isolate = array->GetIsolate();
4671   // Ensure the keys are unique names before writing them into the
4672   // instance descriptor. Since it may cause a GC, it has to be done before we
4673   // temporarily put the heap in an invalid state while appending descriptors.
4674   for (int i = 0; i < nof_callbacks; ++i) {
4675     Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
4676     if (entry->name()->IsUniqueName()) continue;
4677     Handle<String> key =
4678         isolate->factory()->InternalizeString(
4679             Handle<String>(String::cast(entry->name())));
4680     entry->set_name(*key);
4681   }
4682 
4683   // Fill in new callback descriptors.  Process the callbacks from
4684   // back to front so that the last callback with a given name takes
4685   // precedence over previously added callbacks with that name.
4686   for (int i = nof_callbacks - 1; i >= 0; i--) {
4687     Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
4688     Handle<Name> key(Name::cast(entry->name()));
4689     // Check if a descriptor with this name already exists before writing.
4690     if (!T::Contains(key, entry, valid_descriptors, array)) {
4691       T::Insert(key, entry, valid_descriptors, array);
4692       valid_descriptors++;
4693     }
4694   }
4695 
4696   return valid_descriptors;
4697 }
4698 
4699 struct DescriptorArrayAppender {
4700   typedef DescriptorArray Array;
Containsv8::internal::DescriptorArrayAppender4701   static bool Contains(Handle<Name> key,
4702                        Handle<AccessorInfo> entry,
4703                        int valid_descriptors,
4704                        Handle<DescriptorArray> array) {
4705     DisallowHeapAllocation no_gc;
4706     return array->Search(*key, valid_descriptors) != DescriptorArray::kNotFound;
4707   }
Insertv8::internal::DescriptorArrayAppender4708   static void Insert(Handle<Name> key,
4709                      Handle<AccessorInfo> entry,
4710                      int valid_descriptors,
4711                      Handle<DescriptorArray> array) {
4712     DisallowHeapAllocation no_gc;
4713     Descriptor d =
4714         Descriptor::AccessorConstant(key, entry, entry->property_attributes());
4715     array->Append(&d);
4716   }
4717 };
4718 
4719 
4720 struct FixedArrayAppender {
4721   typedef FixedArray Array;
Containsv8::internal::FixedArrayAppender4722   static bool Contains(Handle<Name> key,
4723                        Handle<AccessorInfo> entry,
4724                        int valid_descriptors,
4725                        Handle<FixedArray> array) {
4726     for (int i = 0; i < valid_descriptors; i++) {
4727       if (*key == AccessorInfo::cast(array->get(i))->name()) return true;
4728     }
4729     return false;
4730   }
Insertv8::internal::FixedArrayAppender4731   static void Insert(Handle<Name> key,
4732                      Handle<AccessorInfo> entry,
4733                      int valid_descriptors,
4734                      Handle<FixedArray> array) {
4735     DisallowHeapAllocation no_gc;
4736     array->set(valid_descriptors, *entry);
4737   }
4738 };
4739 
4740 
AppendCallbackDescriptors(Handle<Map> map,Handle<Object> descriptors)4741 void Map::AppendCallbackDescriptors(Handle<Map> map,
4742                                     Handle<Object> descriptors) {
4743   int nof = map->NumberOfOwnDescriptors();
4744   Handle<DescriptorArray> array(map->instance_descriptors());
4745   Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors);
4746   DCHECK_GE(array->NumberOfSlackDescriptors(), callbacks->length());
4747   nof = AppendUniqueCallbacks<DescriptorArrayAppender>(callbacks, array, nof);
4748   map->SetNumberOfOwnDescriptors(nof);
4749 }
4750 
4751 
AppendUnique(Handle<Object> descriptors,Handle<FixedArray> array,int valid_descriptors)4752 int AccessorInfo::AppendUnique(Handle<Object> descriptors,
4753                                Handle<FixedArray> array,
4754                                int valid_descriptors) {
4755   Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors);
4756   DCHECK_GE(array->length(), callbacks->length() + valid_descriptors);
4757   return AppendUniqueCallbacks<FixedArrayAppender>(callbacks, array,
4758                                                    valid_descriptors);
4759 }
4760 
4761 
ContainsMap(MapHandleList * maps,Map * map)4762 static bool ContainsMap(MapHandleList* maps, Map* map) {
4763   DCHECK_NOT_NULL(map);
4764   for (int i = 0; i < maps->length(); ++i) {
4765     if (!maps->at(i).is_null() && *maps->at(i) == map) return true;
4766   }
4767   return false;
4768 }
4769 
FindElementsKindTransitionedMap(MapHandleList * candidates)4770 Map* Map::FindElementsKindTransitionedMap(MapHandleList* candidates) {
4771   DisallowHeapAllocation no_allocation;
4772   DisallowDeoptimization no_deoptimization(GetIsolate());
4773 
4774   ElementsKind kind = elements_kind();
4775   bool packed = IsFastPackedElementsKind(kind);
4776 
4777   Map* transition = nullptr;
4778   if (IsTransitionableFastElementsKind(kind)) {
4779     // Check the state of the root map.
4780     Map* root_map = FindRootMap();
4781     if (!EquivalentToForTransition(root_map)) return nullptr;
4782     root_map = root_map->LookupElementsTransitionMap(kind);
4783     DCHECK_NOT_NULL(root_map);
4784     // Starting from the next existing elements kind transition try to
4785     // replay the property transitions that does not involve instance rewriting
4786     // (ElementsTransitionAndStoreStub does not support that).
4787     for (root_map = root_map->ElementsTransitionMap();
4788          root_map != nullptr && root_map->has_fast_elements();
4789          root_map = root_map->ElementsTransitionMap()) {
4790       Map* current = root_map->TryReplayPropertyTransitions(this);
4791       if (current == nullptr) continue;
4792       if (InstancesNeedRewriting(current)) continue;
4793 
4794       if (ContainsMap(candidates, current) &&
4795           (packed || !IsFastPackedElementsKind(current->elements_kind()))) {
4796         transition = current;
4797         packed = packed && IsFastPackedElementsKind(current->elements_kind());
4798       }
4799     }
4800   }
4801   return transition;
4802 }
4803 
4804 
FindClosestElementsTransition(Map * map,ElementsKind to_kind)4805 static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
4806   // Ensure we are requested to search elements kind transition "near the root".
4807   DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(),
4808             map->NumberOfOwnDescriptors());
4809   Map* current_map = map;
4810 
4811   ElementsKind kind = map->elements_kind();
4812   while (kind != to_kind) {
4813     Map* next_map = current_map->ElementsTransitionMap();
4814     if (next_map == nullptr) return current_map;
4815     kind = next_map->elements_kind();
4816     current_map = next_map;
4817   }
4818 
4819   DCHECK_EQ(to_kind, current_map->elements_kind());
4820   return current_map;
4821 }
4822 
4823 
LookupElementsTransitionMap(ElementsKind to_kind)4824 Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) {
4825   Map* to_map = FindClosestElementsTransition(this, to_kind);
4826   if (to_map->elements_kind() == to_kind) return to_map;
4827   return nullptr;
4828 }
4829 
4830 
IsMapInArrayPrototypeChain()4831 bool Map::IsMapInArrayPrototypeChain() {
4832   Isolate* isolate = GetIsolate();
4833   if (isolate->initial_array_prototype()->map() == this) {
4834     return true;
4835   }
4836 
4837   if (isolate->initial_object_prototype()->map() == this) {
4838     return true;
4839   }
4840 
4841   return false;
4842 }
4843 
4844 
WeakCellForMap(Handle<Map> map)4845 Handle<WeakCell> Map::WeakCellForMap(Handle<Map> map) {
4846   Isolate* isolate = map->GetIsolate();
4847   if (map->weak_cell_cache()->IsWeakCell()) {
4848     return Handle<WeakCell>(WeakCell::cast(map->weak_cell_cache()));
4849   }
4850   Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(map);
4851   map->set_weak_cell_cache(*weak_cell);
4852   return weak_cell;
4853 }
4854 
4855 
AddMissingElementsTransitions(Handle<Map> map,ElementsKind to_kind)4856 static Handle<Map> AddMissingElementsTransitions(Handle<Map> map,
4857                                                  ElementsKind to_kind) {
4858   DCHECK(IsTransitionElementsKind(map->elements_kind()));
4859 
4860   Handle<Map> current_map = map;
4861 
4862   ElementsKind kind = map->elements_kind();
4863   TransitionFlag flag;
4864   if (map->is_prototype_map()) {
4865     flag = OMIT_TRANSITION;
4866   } else {
4867     flag = INSERT_TRANSITION;
4868     if (IsFastElementsKind(kind)) {
4869       while (kind != to_kind && !IsTerminalElementsKind(kind)) {
4870         kind = GetNextTransitionElementsKind(kind);
4871         current_map = Map::CopyAsElementsKind(current_map, kind, flag);
4872       }
4873     }
4874   }
4875 
4876   // In case we are exiting the fast elements kind system, just add the map in
4877   // the end.
4878   if (kind != to_kind) {
4879     current_map = Map::CopyAsElementsKind(current_map, to_kind, flag);
4880   }
4881 
4882   DCHECK(current_map->elements_kind() == to_kind);
4883   return current_map;
4884 }
4885 
4886 
TransitionElementsTo(Handle<Map> map,ElementsKind to_kind)4887 Handle<Map> Map::TransitionElementsTo(Handle<Map> map,
4888                                       ElementsKind to_kind) {
4889   ElementsKind from_kind = map->elements_kind();
4890   if (from_kind == to_kind) return map;
4891 
4892   Isolate* isolate = map->GetIsolate();
4893   Context* native_context = isolate->context()->native_context();
4894   if (from_kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
4895     if (*map == native_context->fast_aliased_arguments_map()) {
4896       DCHECK_EQ(SLOW_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
4897       return handle(native_context->slow_aliased_arguments_map());
4898     }
4899   } else if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
4900     if (*map == native_context->slow_aliased_arguments_map()) {
4901       DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
4902       return handle(native_context->fast_aliased_arguments_map());
4903     }
4904   } else if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) {
4905     // Reuse map transitions for JSArrays.
4906     DisallowHeapAllocation no_gc;
4907     if (native_context->get(Context::ArrayMapIndex(from_kind)) == *map) {
4908       Object* maybe_transitioned_map =
4909           native_context->get(Context::ArrayMapIndex(to_kind));
4910       if (maybe_transitioned_map->IsMap()) {
4911         return handle(Map::cast(maybe_transitioned_map), isolate);
4912       }
4913     }
4914   }
4915 
4916   DCHECK(!map->IsUndefined(isolate));
4917   // Check if we can go back in the elements kind transition chain.
4918   if (IsHoleyElementsKind(from_kind) &&
4919       to_kind == GetPackedElementsKind(from_kind) &&
4920       map->GetBackPointer()->IsMap() &&
4921       Map::cast(map->GetBackPointer())->elements_kind() == to_kind) {
4922     return handle(Map::cast(map->GetBackPointer()));
4923   }
4924 
4925   bool allow_store_transition = IsTransitionElementsKind(from_kind);
4926   // Only store fast element maps in ascending generality.
4927   if (IsFastElementsKind(to_kind)) {
4928     allow_store_transition =
4929         allow_store_transition && IsTransitionableFastElementsKind(from_kind) &&
4930         IsMoreGeneralElementsKindTransition(from_kind, to_kind);
4931   }
4932 
4933   if (!allow_store_transition) {
4934     return Map::CopyAsElementsKind(map, to_kind, OMIT_TRANSITION);
4935   }
4936 
4937   return Map::ReconfigureElementsKind(map, to_kind);
4938 }
4939 
4940 
4941 // static
AsElementsKind(Handle<Map> map,ElementsKind kind)4942 Handle<Map> Map::AsElementsKind(Handle<Map> map, ElementsKind kind) {
4943   Handle<Map> closest_map(FindClosestElementsTransition(*map, kind));
4944 
4945   if (closest_map->elements_kind() == kind) {
4946     return closest_map;
4947   }
4948 
4949   return AddMissingElementsTransitions(closest_map, kind);
4950 }
4951 
4952 
GetElementsTransitionMap(Handle<JSObject> object,ElementsKind to_kind)4953 Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
4954                                                ElementsKind to_kind) {
4955   Handle<Map> map(object->map());
4956   return Map::TransitionElementsTo(map, to_kind);
4957 }
4958 
4959 
Revoke(Handle<JSProxy> proxy)4960 void JSProxy::Revoke(Handle<JSProxy> proxy) {
4961   Isolate* isolate = proxy->GetIsolate();
4962   if (!proxy->IsRevoked()) proxy->set_handler(isolate->heap()->null_value());
4963   DCHECK(proxy->IsRevoked());
4964 }
4965 
4966 
HasProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Name> name)4967 Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy,
4968                                  Handle<Name> name) {
4969   DCHECK(!name->IsPrivate());
4970   STACK_CHECK(isolate, Nothing<bool>());
4971   // 1. (Assert)
4972   // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
4973   Handle<Object> handler(proxy->handler(), isolate);
4974   // 3. If handler is null, throw a TypeError exception.
4975   // 4. Assert: Type(handler) is Object.
4976   if (proxy->IsRevoked()) {
4977     isolate->Throw(*isolate->factory()->NewTypeError(
4978         MessageTemplate::kProxyRevoked, isolate->factory()->has_string()));
4979     return Nothing<bool>();
4980   }
4981   // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
4982   Handle<JSReceiver> target(proxy->target(), isolate);
4983   // 6. Let trap be ? GetMethod(handler, "has").
4984   Handle<Object> trap;
4985   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4986       isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
4987                                        isolate->factory()->has_string()),
4988       Nothing<bool>());
4989   // 7. If trap is undefined, then
4990   if (trap->IsUndefined(isolate)) {
4991     // 7a. Return target.[[HasProperty]](P).
4992     return JSReceiver::HasProperty(target, name);
4993   }
4994   // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, P»)).
4995   Handle<Object> trap_result_obj;
4996   Handle<Object> args[] = {target, name};
4997   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4998       isolate, trap_result_obj,
4999       Execution::Call(isolate, trap, handler, arraysize(args), args),
5000       Nothing<bool>());
5001   bool boolean_trap_result = trap_result_obj->BooleanValue();
5002   // 9. If booleanTrapResult is false, then:
5003   if (!boolean_trap_result) {
5004     // 9a. Let targetDesc be ? target.[[GetOwnProperty]](P).
5005     PropertyDescriptor target_desc;
5006     Maybe<bool> target_found = JSReceiver::GetOwnPropertyDescriptor(
5007         isolate, target, name, &target_desc);
5008     MAYBE_RETURN(target_found, Nothing<bool>());
5009     // 9b. If targetDesc is not undefined, then:
5010     if (target_found.FromJust()) {
5011       // 9b i. If targetDesc.[[Configurable]] is false, throw a TypeError
5012       //       exception.
5013       if (!target_desc.configurable()) {
5014         isolate->Throw(*isolate->factory()->NewTypeError(
5015             MessageTemplate::kProxyHasNonConfigurable, name));
5016         return Nothing<bool>();
5017       }
5018       // 9b ii. Let extensibleTarget be ? IsExtensible(target).
5019       Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
5020       MAYBE_RETURN(extensible_target, Nothing<bool>());
5021       // 9b iii. If extensibleTarget is false, throw a TypeError exception.
5022       if (!extensible_target.FromJust()) {
5023         isolate->Throw(*isolate->factory()->NewTypeError(
5024             MessageTemplate::kProxyHasNonExtensible, name));
5025         return Nothing<bool>();
5026       }
5027     }
5028   }
5029   // 10. Return booleanTrapResult.
5030   return Just(boolean_trap_result);
5031 }
5032 
5033 
SetProperty(Handle<JSProxy> proxy,Handle<Name> name,Handle<Object> value,Handle<Object> receiver,LanguageMode language_mode)5034 Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name,
5035                                  Handle<Object> value, Handle<Object> receiver,
5036                                  LanguageMode language_mode) {
5037   DCHECK(!name->IsPrivate());
5038   Isolate* isolate = proxy->GetIsolate();
5039   STACK_CHECK(isolate, Nothing<bool>());
5040   Factory* factory = isolate->factory();
5041   Handle<String> trap_name = factory->set_string();
5042   ShouldThrow should_throw =
5043       is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
5044 
5045   if (proxy->IsRevoked()) {
5046     isolate->Throw(
5047         *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
5048     return Nothing<bool>();
5049   }
5050   Handle<JSReceiver> target(proxy->target(), isolate);
5051   Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
5052 
5053   Handle<Object> trap;
5054   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5055       isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
5056   if (trap->IsUndefined(isolate)) {
5057     LookupIterator it =
5058         LookupIterator::PropertyOrElement(isolate, receiver, name, target);
5059     return Object::SetSuperProperty(&it, value, language_mode,
5060                                     Object::MAY_BE_STORE_FROM_KEYED);
5061   }
5062 
5063   Handle<Object> trap_result;
5064   Handle<Object> args[] = {target, name, value, receiver};
5065   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5066       isolate, trap_result,
5067       Execution::Call(isolate, trap, handler, arraysize(args), args),
5068       Nothing<bool>());
5069   if (!trap_result->BooleanValue()) {
5070     RETURN_FAILURE(isolate, should_throw,
5071                    NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
5072                                 trap_name, name));
5073   }
5074 
5075   // Enforce the invariant.
5076   PropertyDescriptor target_desc;
5077   Maybe<bool> owned =
5078       JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
5079   MAYBE_RETURN(owned, Nothing<bool>());
5080   if (owned.FromJust()) {
5081     bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
5082                         !target_desc.configurable() &&
5083                         !target_desc.writable() &&
5084                         !value->SameValue(*target_desc.value());
5085     if (inconsistent) {
5086       isolate->Throw(*isolate->factory()->NewTypeError(
5087           MessageTemplate::kProxySetFrozenData, name));
5088       return Nothing<bool>();
5089     }
5090     inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
5091                    !target_desc.configurable() &&
5092                    target_desc.set()->IsUndefined(isolate);
5093     if (inconsistent) {
5094       isolate->Throw(*isolate->factory()->NewTypeError(
5095           MessageTemplate::kProxySetFrozenAccessor, name));
5096       return Nothing<bool>();
5097     }
5098   }
5099   return Just(true);
5100 }
5101 
5102 
DeletePropertyOrElement(Handle<JSProxy> proxy,Handle<Name> name,LanguageMode language_mode)5103 Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy,
5104                                              Handle<Name> name,
5105                                              LanguageMode language_mode) {
5106   DCHECK(!name->IsPrivate());
5107   ShouldThrow should_throw =
5108       is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
5109   Isolate* isolate = proxy->GetIsolate();
5110   STACK_CHECK(isolate, Nothing<bool>());
5111   Factory* factory = isolate->factory();
5112   Handle<String> trap_name = factory->deleteProperty_string();
5113 
5114   if (proxy->IsRevoked()) {
5115     isolate->Throw(
5116         *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
5117     return Nothing<bool>();
5118   }
5119   Handle<JSReceiver> target(proxy->target(), isolate);
5120   Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
5121 
5122   Handle<Object> trap;
5123   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5124       isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
5125   if (trap->IsUndefined(isolate)) {
5126     return JSReceiver::DeletePropertyOrElement(target, name, language_mode);
5127   }
5128 
5129   Handle<Object> trap_result;
5130   Handle<Object> args[] = {target, name};
5131   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5132       isolate, trap_result,
5133       Execution::Call(isolate, trap, handler, arraysize(args), args),
5134       Nothing<bool>());
5135   if (!trap_result->BooleanValue()) {
5136     RETURN_FAILURE(isolate, should_throw,
5137                    NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
5138                                 trap_name, name));
5139   }
5140 
5141   // Enforce the invariant.
5142   PropertyDescriptor target_desc;
5143   Maybe<bool> owned =
5144       JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
5145   MAYBE_RETURN(owned, Nothing<bool>());
5146   if (owned.FromJust() && !target_desc.configurable()) {
5147     isolate->Throw(*factory->NewTypeError(
5148         MessageTemplate::kProxyDeletePropertyNonConfigurable, name));
5149     return Nothing<bool>();
5150   }
5151   return Just(true);
5152 }
5153 
5154 
5155 // static
New(Isolate * isolate,Handle<Object> target,Handle<Object> handler)5156 MaybeHandle<JSProxy> JSProxy::New(Isolate* isolate, Handle<Object> target,
5157                                   Handle<Object> handler) {
5158   if (!target->IsJSReceiver()) {
5159     THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5160                     JSProxy);
5161   }
5162   if (target->IsJSProxy() && JSProxy::cast(*target)->IsRevoked()) {
5163     THROW_NEW_ERROR(isolate,
5164                     NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5165                     JSProxy);
5166   }
5167   if (!handler->IsJSReceiver()) {
5168     THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5169                     JSProxy);
5170   }
5171   if (handler->IsJSProxy() && JSProxy::cast(*handler)->IsRevoked()) {
5172     THROW_NEW_ERROR(isolate,
5173                     NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5174                     JSProxy);
5175   }
5176   return isolate->factory()->NewJSProxy(Handle<JSReceiver>::cast(target),
5177                                         Handle<JSReceiver>::cast(handler));
5178 }
5179 
5180 
5181 // static
GetFunctionRealm(Handle<JSProxy> proxy)5182 MaybeHandle<Context> JSProxy::GetFunctionRealm(Handle<JSProxy> proxy) {
5183   DCHECK(proxy->map()->is_constructor());
5184   if (proxy->IsRevoked()) {
5185     THROW_NEW_ERROR(proxy->GetIsolate(),
5186                     NewTypeError(MessageTemplate::kProxyRevoked), Context);
5187   }
5188   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()));
5189   return JSReceiver::GetFunctionRealm(target);
5190 }
5191 
5192 
5193 // static
GetFunctionRealm(Handle<JSBoundFunction> function)5194 MaybeHandle<Context> JSBoundFunction::GetFunctionRealm(
5195     Handle<JSBoundFunction> function) {
5196   DCHECK(function->map()->is_constructor());
5197   return JSReceiver::GetFunctionRealm(
5198       handle(function->bound_target_function()));
5199 }
5200 
5201 // static
GetName(Isolate * isolate,Handle<JSBoundFunction> function)5202 MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate,
5203                                              Handle<JSBoundFunction> function) {
5204   Handle<String> prefix = isolate->factory()->bound__string();
5205   if (!function->bound_target_function()->IsJSFunction()) return prefix;
5206   Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()),
5207                             isolate);
5208   Handle<Object> target_name = JSFunction::GetName(isolate, target);
5209   if (!target_name->IsString()) return prefix;
5210   Factory* factory = isolate->factory();
5211   return factory->NewConsString(prefix, Handle<String>::cast(target_name));
5212 }
5213 
5214 // static
GetName(Isolate * isolate,Handle<JSFunction> function)5215 Handle<Object> JSFunction::GetName(Isolate* isolate,
5216                                    Handle<JSFunction> function) {
5217   if (function->shared()->name_should_print_as_anonymous()) {
5218     return isolate->factory()->anonymous_string();
5219   }
5220   return handle(function->shared()->name(), isolate);
5221 }
5222 
5223 // static
GetLength(Isolate * isolate,Handle<JSFunction> function)5224 MaybeHandle<Smi> JSFunction::GetLength(Isolate* isolate,
5225                                        Handle<JSFunction> function) {
5226   int length = 0;
5227   if (function->shared()->is_compiled()) {
5228     length = function->shared()->length();
5229   } else {
5230     // If the function isn't compiled yet, the length is not computed
5231     // correctly yet. Compile it now and return the right length.
5232     if (Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) {
5233       length = function->shared()->length();
5234     }
5235     if (isolate->has_pending_exception()) return MaybeHandle<Smi>();
5236   }
5237   return handle(Smi::FromInt(length), isolate);
5238 }
5239 
5240 // static
GetFunctionRealm(Handle<JSFunction> function)5241 Handle<Context> JSFunction::GetFunctionRealm(Handle<JSFunction> function) {
5242   DCHECK(function->map()->is_constructor());
5243   return handle(function->context()->native_context());
5244 }
5245 
5246 
5247 // static
GetFunctionRealm(Handle<JSObject> object)5248 MaybeHandle<Context> JSObject::GetFunctionRealm(Handle<JSObject> object) {
5249   DCHECK(object->map()->is_constructor());
5250   DCHECK(!object->IsJSFunction());
5251   return object->GetCreationContext();
5252 }
5253 
5254 
5255 // static
GetFunctionRealm(Handle<JSReceiver> receiver)5256 MaybeHandle<Context> JSReceiver::GetFunctionRealm(Handle<JSReceiver> receiver) {
5257   if (receiver->IsJSProxy()) {
5258     return JSProxy::GetFunctionRealm(Handle<JSProxy>::cast(receiver));
5259   }
5260 
5261   if (receiver->IsJSFunction()) {
5262     return JSFunction::GetFunctionRealm(Handle<JSFunction>::cast(receiver));
5263   }
5264 
5265   if (receiver->IsJSBoundFunction()) {
5266     return JSBoundFunction::GetFunctionRealm(
5267         Handle<JSBoundFunction>::cast(receiver));
5268   }
5269 
5270   return JSObject::GetFunctionRealm(Handle<JSObject>::cast(receiver));
5271 }
5272 
5273 
GetPropertyAttributes(LookupIterator * it)5274 Maybe<PropertyAttributes> JSProxy::GetPropertyAttributes(LookupIterator* it) {
5275   PropertyDescriptor desc;
5276   Maybe<bool> found = JSProxy::GetOwnPropertyDescriptor(
5277       it->isolate(), it->GetHolder<JSProxy>(), it->GetName(), &desc);
5278   MAYBE_RETURN(found, Nothing<PropertyAttributes>());
5279   if (!found.FromJust()) return Just(ABSENT);
5280   return Just(desc.ToAttributes());
5281 }
5282 
5283 
AllocateStorageForMap(Handle<JSObject> object,Handle<Map> map)5284 void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
5285   DCHECK(object->map()->GetInObjectProperties() ==
5286          map->GetInObjectProperties());
5287   ElementsKind obj_kind = object->map()->elements_kind();
5288   ElementsKind map_kind = map->elements_kind();
5289   if (map_kind != obj_kind) {
5290     ElementsKind to_kind = GetMoreGeneralElementsKind(map_kind, obj_kind);
5291     if (IsDictionaryElementsKind(obj_kind)) {
5292       to_kind = obj_kind;
5293     }
5294     if (IsDictionaryElementsKind(to_kind)) {
5295       NormalizeElements(object);
5296     } else {
5297       TransitionElementsKind(object, to_kind);
5298     }
5299     map = Map::ReconfigureElementsKind(map, to_kind);
5300   }
5301   JSObject::MigrateToMap(object, map);
5302 }
5303 
5304 
MigrateInstance(Handle<JSObject> object)5305 void JSObject::MigrateInstance(Handle<JSObject> object) {
5306   Handle<Map> original_map(object->map());
5307   Handle<Map> map = Map::Update(original_map);
5308   map->set_migration_target(true);
5309   MigrateToMap(object, map);
5310   if (FLAG_trace_migration) {
5311     object->PrintInstanceMigration(stdout, *original_map, *map);
5312   }
5313 #if VERIFY_HEAP
5314   if (FLAG_verify_heap) {
5315     object->JSObjectVerify();
5316   }
5317 #endif
5318 }
5319 
5320 
5321 // static
TryMigrateInstance(Handle<JSObject> object)5322 bool JSObject::TryMigrateInstance(Handle<JSObject> object) {
5323   Isolate* isolate = object->GetIsolate();
5324   DisallowDeoptimization no_deoptimization(isolate);
5325   Handle<Map> original_map(object->map(), isolate);
5326   Handle<Map> new_map;
5327   if (!Map::TryUpdate(original_map).ToHandle(&new_map)) {
5328     return false;
5329   }
5330   JSObject::MigrateToMap(object, new_map);
5331   if (FLAG_trace_migration) {
5332     object->PrintInstanceMigration(stdout, *original_map, object->map());
5333   }
5334 #if VERIFY_HEAP
5335   if (FLAG_verify_heap) {
5336     object->JSObjectVerify();
5337   }
5338 #endif
5339   return true;
5340 }
5341 
5342 
AddProperty(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)5343 void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name,
5344                            Handle<Object> value,
5345                            PropertyAttributes attributes) {
5346   LookupIterator it(object, name, object, LookupIterator::OWN_SKIP_INTERCEPTOR);
5347   CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
5348 #ifdef DEBUG
5349   uint32_t index;
5350   DCHECK(!object->IsJSProxy());
5351   DCHECK(!name->AsArrayIndex(&index));
5352   Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
5353   DCHECK(maybe.IsJust());
5354   DCHECK(!it.IsFound());
5355   DCHECK(object->map()->is_extensible() || name->IsPrivate());
5356 #endif
5357   CHECK(AddDataProperty(&it, value, attributes, THROW_ON_ERROR,
5358                         CERTAINLY_NOT_STORE_FROM_KEYED)
5359             .IsJust());
5360 }
5361 
5362 
5363 // Reconfigures a property to a data property with attributes, even if it is not
5364 // reconfigurable.
5365 // Requires a LookupIterator that does not look at the prototype chain beyond
5366 // hidden prototypes.
DefineOwnPropertyIgnoreAttributes(LookupIterator * it,Handle<Object> value,PropertyAttributes attributes,AccessorInfoHandling handling)5367 MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes(
5368     LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
5369     AccessorInfoHandling handling) {
5370   MAYBE_RETURN_NULL(DefineOwnPropertyIgnoreAttributes(
5371       it, value, attributes, THROW_ON_ERROR, handling));
5372   return value;
5373 }
5374 
5375 
DefineOwnPropertyIgnoreAttributes(LookupIterator * it,Handle<Object> value,PropertyAttributes attributes,ShouldThrow should_throw,AccessorInfoHandling handling)5376 Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
5377     LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
5378     ShouldThrow should_throw, AccessorInfoHandling handling) {
5379   it->UpdateProtector();
5380   Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
5381 
5382   for (; it->IsFound(); it->Next()) {
5383     switch (it->state()) {
5384       case LookupIterator::JSPROXY:
5385       case LookupIterator::NOT_FOUND:
5386       case LookupIterator::TRANSITION:
5387         UNREACHABLE();
5388 
5389       case LookupIterator::ACCESS_CHECK:
5390         if (!it->HasAccess()) {
5391           it->isolate()->ReportFailedAccessCheck(it->GetHolder<JSObject>());
5392           RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
5393           return Just(true);
5394         }
5395         break;
5396 
5397       // If there's an interceptor, try to store the property with the
5398       // interceptor.
5399       // In case of success, the attributes will have been reset to the default
5400       // attributes of the interceptor, rather than the incoming attributes.
5401       //
5402       // TODO(verwaest): JSProxy afterwards verify the attributes that the
5403       // JSProxy claims it has, and verifies that they are compatible. If not,
5404       // they throw. Here we should do the same.
5405       case LookupIterator::INTERCEPTOR:
5406         if (handling == DONT_FORCE_FIELD) {
5407           Maybe<bool> result =
5408               JSObject::SetPropertyWithInterceptor(it, should_throw, value);
5409           if (result.IsNothing() || result.FromJust()) return result;
5410         }
5411         break;
5412 
5413       case LookupIterator::ACCESSOR: {
5414         Handle<Object> accessors = it->GetAccessors();
5415 
5416         // Special handling for AccessorInfo, which behaves like a data
5417         // property.
5418         if (accessors->IsAccessorInfo() && handling == DONT_FORCE_FIELD) {
5419           PropertyAttributes current_attributes = it->property_attributes();
5420           // Ensure the context isn't changed after calling into accessors.
5421           AssertNoContextChange ncc(it->isolate());
5422 
5423           // Update the attributes before calling the setter. The setter may
5424           // later change the shape of the property.
5425           if (current_attributes != attributes) {
5426             it->TransitionToAccessorPair(accessors, attributes);
5427           }
5428 
5429           return JSObject::SetPropertyWithAccessor(it, value, should_throw);
5430         }
5431 
5432         it->ReconfigureDataProperty(value, attributes);
5433         return Just(true);
5434       }
5435       case LookupIterator::INTEGER_INDEXED_EXOTIC:
5436         return RedefineIncompatibleProperty(it->isolate(), it->GetName(), value,
5437                                             should_throw);
5438 
5439       case LookupIterator::DATA: {
5440         // Regular property update if the attributes match.
5441         if (it->property_attributes() == attributes) {
5442           return SetDataProperty(it, value);
5443         }
5444 
5445         // Special case: properties of typed arrays cannot be reconfigured to
5446         // non-writable nor to non-enumerable.
5447         if (it->IsElement() && object->HasFixedTypedArrayElements()) {
5448           return RedefineIncompatibleProperty(it->isolate(), it->GetName(),
5449                                               value, should_throw);
5450         }
5451 
5452         // Reconfigure the data property if the attributes mismatch.
5453         it->ReconfigureDataProperty(value, attributes);
5454 
5455         return Just(true);
5456       }
5457     }
5458   }
5459 
5460   return AddDataProperty(it, value, attributes, should_throw,
5461                          CERTAINLY_NOT_STORE_FROM_KEYED);
5462 }
5463 
SetOwnPropertyIgnoreAttributes(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)5464 MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
5465     Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
5466     PropertyAttributes attributes) {
5467   DCHECK(!value->IsTheHole(object->GetIsolate()));
5468   LookupIterator it(object, name, object, LookupIterator::OWN);
5469   return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
5470 }
5471 
SetOwnElementIgnoreAttributes(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes)5472 MaybeHandle<Object> JSObject::SetOwnElementIgnoreAttributes(
5473     Handle<JSObject> object, uint32_t index, Handle<Object> value,
5474     PropertyAttributes attributes) {
5475   Isolate* isolate = object->GetIsolate();
5476   LookupIterator it(isolate, object, index, object, LookupIterator::OWN);
5477   return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
5478 }
5479 
DefinePropertyOrElementIgnoreAttributes(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)5480 MaybeHandle<Object> JSObject::DefinePropertyOrElementIgnoreAttributes(
5481     Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
5482     PropertyAttributes attributes) {
5483   Isolate* isolate = object->GetIsolate();
5484   LookupIterator it = LookupIterator::PropertyOrElement(
5485       isolate, object, name, object, LookupIterator::OWN);
5486   return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
5487 }
5488 
GetPropertyAttributesWithInterceptor(LookupIterator * it)5489 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
5490     LookupIterator* it) {
5491   return GetPropertyAttributesWithInterceptorInternal(it, it->GetInterceptor());
5492 }
5493 
GetPropertyAttributes(LookupIterator * it)5494 Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
5495     LookupIterator* it) {
5496   for (; it->IsFound(); it->Next()) {
5497     switch (it->state()) {
5498       case LookupIterator::NOT_FOUND:
5499       case LookupIterator::TRANSITION:
5500         UNREACHABLE();
5501       case LookupIterator::JSPROXY:
5502         return JSProxy::GetPropertyAttributes(it);
5503       case LookupIterator::INTERCEPTOR: {
5504         Maybe<PropertyAttributes> result =
5505             JSObject::GetPropertyAttributesWithInterceptor(it);
5506         if (!result.IsJust()) return result;
5507         if (result.FromJust() != ABSENT) return result;
5508         break;
5509       }
5510       case LookupIterator::ACCESS_CHECK:
5511         if (it->HasAccess()) break;
5512         return JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
5513       case LookupIterator::INTEGER_INDEXED_EXOTIC:
5514         return Just(ABSENT);
5515       case LookupIterator::ACCESSOR:
5516       case LookupIterator::DATA:
5517         return Just(it->property_attributes());
5518     }
5519   }
5520   return Just(ABSENT);
5521 }
5522 
5523 
New(Isolate * isolate)5524 Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) {
5525   Handle<FixedArray> array(
5526       isolate->factory()->NewFixedArray(kEntries, TENURED));
5527   return Handle<NormalizedMapCache>::cast(array);
5528 }
5529 
5530 
Get(Handle<Map> fast_map,PropertyNormalizationMode mode)5531 MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map,
5532                                          PropertyNormalizationMode mode) {
5533   DisallowHeapAllocation no_gc;
5534   Object* value = FixedArray::get(GetIndex(fast_map));
5535   if (!value->IsMap() ||
5536       !Map::cast(value)->EquivalentToForNormalization(*fast_map, mode)) {
5537     return MaybeHandle<Map>();
5538   }
5539   return handle(Map::cast(value));
5540 }
5541 
5542 
Set(Handle<Map> fast_map,Handle<Map> normalized_map)5543 void NormalizedMapCache::Set(Handle<Map> fast_map,
5544                              Handle<Map> normalized_map) {
5545   DisallowHeapAllocation no_gc;
5546   DCHECK(normalized_map->is_dictionary_map());
5547   FixedArray::set(GetIndex(fast_map), *normalized_map);
5548 }
5549 
5550 
Clear()5551 void NormalizedMapCache::Clear() {
5552   int entries = length();
5553   for (int i = 0; i != entries; i++) {
5554     set_undefined(i);
5555   }
5556 }
5557 
5558 
UpdateMapCodeCache(Handle<HeapObject> object,Handle<Name> name,Handle<Code> code)5559 void HeapObject::UpdateMapCodeCache(Handle<HeapObject> object,
5560                                     Handle<Name> name,
5561                                     Handle<Code> code) {
5562   Handle<Map> map(object->map());
5563   Map::UpdateCodeCache(map, name, code);
5564 }
5565 
5566 
NormalizeProperties(Handle<JSObject> object,PropertyNormalizationMode mode,int expected_additional_properties,const char * reason)5567 void JSObject::NormalizeProperties(Handle<JSObject> object,
5568                                    PropertyNormalizationMode mode,
5569                                    int expected_additional_properties,
5570                                    const char* reason) {
5571   if (!object->HasFastProperties()) return;
5572 
5573   Handle<Map> map(object->map());
5574   Handle<Map> new_map = Map::Normalize(map, mode, reason);
5575 
5576   MigrateToMap(object, new_map, expected_additional_properties);
5577 }
5578 
5579 
MigrateSlowToFast(Handle<JSObject> object,int unused_property_fields,const char * reason)5580 void JSObject::MigrateSlowToFast(Handle<JSObject> object,
5581                                  int unused_property_fields,
5582                                  const char* reason) {
5583   if (object->HasFastProperties()) return;
5584   DCHECK(!object->IsJSGlobalObject());
5585   Isolate* isolate = object->GetIsolate();
5586   Factory* factory = isolate->factory();
5587   Handle<NameDictionary> dictionary(object->property_dictionary());
5588 
5589   // Make sure we preserve dictionary representation if there are too many
5590   // descriptors.
5591   int number_of_elements = dictionary->NumberOfElements();
5592   if (number_of_elements > kMaxNumberOfDescriptors) return;
5593 
5594   Handle<FixedArray> iteration_order;
5595   if (number_of_elements != dictionary->NextEnumerationIndex()) {
5596     iteration_order =
5597         NameDictionary::DoGenerateNewEnumerationIndices(dictionary);
5598   } else {
5599     iteration_order = NameDictionary::IterationIndices(dictionary);
5600   }
5601 
5602   int instance_descriptor_length = iteration_order->length();
5603   int number_of_fields = 0;
5604 
5605   // Compute the length of the instance descriptor.
5606   for (int i = 0; i < instance_descriptor_length; i++) {
5607     int index = Smi::cast(iteration_order->get(i))->value();
5608     DCHECK(dictionary->IsKey(isolate, dictionary->KeyAt(index)));
5609 
5610     PropertyKind kind = dictionary->DetailsAt(index).kind();
5611     if (kind == kData) {
5612       if (FLAG_track_constant_fields) {
5613         number_of_fields += 1;
5614       } else {
5615         Object* value = dictionary->ValueAt(index);
5616         if (!value->IsJSFunction()) {
5617           number_of_fields += 1;
5618         }
5619       }
5620     }
5621   }
5622 
5623   Handle<Map> old_map(object->map(), isolate);
5624 
5625   int inobject_props = old_map->GetInObjectProperties();
5626 
5627   // Allocate new map.
5628   Handle<Map> new_map = Map::CopyDropDescriptors(old_map);
5629   new_map->set_dictionary_map(false);
5630 
5631   NotifyMapChange(old_map, new_map, isolate);
5632 
5633 #if TRACE_MAPS
5634   if (FLAG_trace_maps) {
5635     PrintF("[TraceMaps: SlowToFast from= %p to= %p reason= %s ]\n",
5636            reinterpret_cast<void*>(*old_map), reinterpret_cast<void*>(*new_map),
5637            reason);
5638   }
5639 #endif
5640 
5641   if (instance_descriptor_length == 0) {
5642     DisallowHeapAllocation no_gc;
5643     DCHECK_LE(unused_property_fields, inobject_props);
5644     // Transform the object.
5645     new_map->set_unused_property_fields(inobject_props);
5646     object->synchronized_set_map(*new_map);
5647     object->set_properties(isolate->heap()->empty_fixed_array());
5648     // Check that it really works.
5649     DCHECK(object->HasFastProperties());
5650     return;
5651   }
5652 
5653   // Allocate the instance descriptor.
5654   Handle<DescriptorArray> descriptors = DescriptorArray::Allocate(
5655       isolate, instance_descriptor_length, 0, TENURED);
5656 
5657   int number_of_allocated_fields =
5658       number_of_fields + unused_property_fields - inobject_props;
5659   if (number_of_allocated_fields < 0) {
5660     // There is enough inobject space for all fields (including unused).
5661     number_of_allocated_fields = 0;
5662     unused_property_fields = inobject_props - number_of_fields;
5663   }
5664 
5665   // Allocate the fixed array for the fields.
5666   Handle<FixedArray> fields = factory->NewFixedArray(
5667       number_of_allocated_fields);
5668 
5669   // Fill in the instance descriptor and the fields.
5670   int current_offset = 0;
5671   for (int i = 0; i < instance_descriptor_length; i++) {
5672     int index = Smi::cast(iteration_order->get(i))->value();
5673     Object* k = dictionary->KeyAt(index);
5674     DCHECK(dictionary->IsKey(k));
5675     // Dictionary keys are internalized upon insertion.
5676     // TODO(jkummerow): Turn this into a DCHECK if it's not hit in the wild.
5677     CHECK(k->IsUniqueName());
5678     Handle<Name> key(Name::cast(k), isolate);
5679 
5680     Object* value = dictionary->ValueAt(index);
5681 
5682     PropertyDetails details = dictionary->DetailsAt(index);
5683     DCHECK_EQ(kField, details.location());
5684     DCHECK_EQ(kMutable, details.constness());
5685     int enumeration_index = details.dictionary_index();
5686 
5687     Descriptor d;
5688     if (details.kind() == kData) {
5689       if (!FLAG_track_constant_fields && value->IsJSFunction()) {
5690         d = Descriptor::DataConstant(key, handle(value, isolate),
5691                                      details.attributes());
5692       } else {
5693         d = Descriptor::DataField(
5694             key, current_offset, details.attributes(), kDefaultFieldConstness,
5695             // TODO(verwaest): value->OptimalRepresentation();
5696             Representation::Tagged(), FieldType::Any(isolate));
5697       }
5698     } else {
5699       DCHECK_EQ(kAccessor, details.kind());
5700       d = Descriptor::AccessorConstant(key, handle(value, isolate),
5701                                        details.attributes());
5702     }
5703     details = d.GetDetails();
5704     if (details.location() == kField) {
5705       if (current_offset < inobject_props) {
5706         object->InObjectPropertyAtPut(current_offset, value,
5707                                       UPDATE_WRITE_BARRIER);
5708       } else {
5709         int offset = current_offset - inobject_props;
5710         fields->set(offset, value);
5711       }
5712       current_offset += details.field_width_in_words();
5713     }
5714     descriptors->Set(enumeration_index - 1, &d);
5715   }
5716   DCHECK(current_offset == number_of_fields);
5717 
5718   descriptors->Sort();
5719 
5720   Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
5721       new_map, descriptors, descriptors->number_of_descriptors());
5722 
5723   DisallowHeapAllocation no_gc;
5724   new_map->InitializeDescriptors(*descriptors, *layout_descriptor);
5725   new_map->set_unused_property_fields(unused_property_fields);
5726 
5727   // Transform the object.
5728   object->synchronized_set_map(*new_map);
5729 
5730   object->set_properties(*fields);
5731   DCHECK(object->IsJSObject());
5732 
5733   // Check that it really works.
5734   DCHECK(object->HasFastProperties());
5735 }
5736 
5737 
ResetElements(Handle<JSObject> object)5738 void JSObject::ResetElements(Handle<JSObject> object) {
5739   Isolate* isolate = object->GetIsolate();
5740   CHECK(object->map() != isolate->heap()->sloppy_arguments_elements_map());
5741   if (object->map()->has_dictionary_elements()) {
5742     Handle<SeededNumberDictionary> new_elements =
5743         SeededNumberDictionary::New(isolate, 0);
5744     object->set_elements(*new_elements);
5745   } else {
5746     object->set_elements(object->map()->GetInitialElements());
5747   }
5748 }
5749 
5750 
RequireSlowElements(SeededNumberDictionary * dictionary)5751 void JSObject::RequireSlowElements(SeededNumberDictionary* dictionary) {
5752   if (dictionary->requires_slow_elements()) return;
5753   dictionary->set_requires_slow_elements();
5754   if (map()->is_prototype_map()) {
5755     // If this object is a prototype (the callee will check), invalidate any
5756     // prototype chains involving it.
5757     InvalidatePrototypeChains(map());
5758   }
5759 }
5760 
5761 
NormalizeElements(Handle<JSObject> object)5762 Handle<SeededNumberDictionary> JSObject::NormalizeElements(
5763     Handle<JSObject> object) {
5764   DCHECK(!object->HasFixedTypedArrayElements());
5765   Isolate* isolate = object->GetIsolate();
5766   bool is_arguments = object->HasSloppyArgumentsElements();
5767   {
5768     DisallowHeapAllocation no_gc;
5769     FixedArrayBase* elements = object->elements();
5770 
5771     if (is_arguments) {
5772       FixedArray* parameter_map = FixedArray::cast(elements);
5773       elements = FixedArrayBase::cast(parameter_map->get(1));
5774     }
5775 
5776     if (elements->IsDictionary()) {
5777       return handle(SeededNumberDictionary::cast(elements), isolate);
5778     }
5779   }
5780 
5781   DCHECK(object->HasFastSmiOrObjectElements() ||
5782          object->HasFastDoubleElements() ||
5783          object->HasFastArgumentsElements() ||
5784          object->HasFastStringWrapperElements());
5785 
5786   Handle<SeededNumberDictionary> dictionary =
5787       object->GetElementsAccessor()->Normalize(object);
5788 
5789   // Switch to using the dictionary as the backing storage for elements.
5790   ElementsKind target_kind = is_arguments
5791                                  ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS
5792                                  : object->HasFastStringWrapperElements()
5793                                        ? SLOW_STRING_WRAPPER_ELEMENTS
5794                                        : DICTIONARY_ELEMENTS;
5795   Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind);
5796   // Set the new map first to satify the elements type assert in set_elements().
5797   JSObject::MigrateToMap(object, new_map);
5798 
5799   if (is_arguments) {
5800     FixedArray::cast(object->elements())->set(1, *dictionary);
5801   } else {
5802     object->set_elements(*dictionary);
5803   }
5804 
5805   isolate->counters()->elements_to_dictionary()->Increment();
5806 
5807 #ifdef DEBUG
5808   if (FLAG_trace_normalization) {
5809     OFStream os(stdout);
5810     os << "Object elements have been normalized:\n";
5811     object->Print(os);
5812   }
5813 #endif
5814 
5815   DCHECK(object->HasDictionaryElements() ||
5816          object->HasSlowArgumentsElements() ||
5817          object->HasSlowStringWrapperElements());
5818   return dictionary;
5819 }
5820 
5821 
5822 template <typename ProxyType>
GetOrCreateIdentityHashHelper(Isolate * isolate,Handle<ProxyType> proxy)5823 static Smi* GetOrCreateIdentityHashHelper(Isolate* isolate,
5824                                           Handle<ProxyType> proxy) {
5825   Object* maybe_hash = proxy->hash();
5826   if (maybe_hash->IsSmi()) return Smi::cast(maybe_hash);
5827 
5828   Smi* hash = Smi::FromInt(isolate->GenerateIdentityHash(Smi::kMaxValue));
5829   proxy->set_hash(hash);
5830   return hash;
5831 }
5832 
5833 // static
GetIdentityHash(Isolate * isolate,Handle<JSObject> object)5834 Object* JSObject::GetIdentityHash(Isolate* isolate, Handle<JSObject> object) {
5835   if (object->IsJSGlobalProxy()) {
5836     return JSGlobalProxy::cast(*object)->hash();
5837   }
5838   Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol();
5839   return *JSReceiver::GetDataProperty(object, hash_code_symbol);
5840 }
5841 
5842 // static
GetOrCreateIdentityHash(Isolate * isolate,Handle<JSObject> object)5843 Smi* JSObject::GetOrCreateIdentityHash(Isolate* isolate,
5844                                        Handle<JSObject> object) {
5845   if (object->IsJSGlobalProxy()) {
5846     return GetOrCreateIdentityHashHelper(isolate,
5847                                          Handle<JSGlobalProxy>::cast(object));
5848   }
5849 
5850   Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol();
5851   LookupIterator it(object, hash_code_symbol, object, LookupIterator::OWN);
5852   if (it.IsFound()) {
5853     DCHECK_EQ(LookupIterator::DATA, it.state());
5854     Object* maybe_hash = *it.GetDataValue();
5855     if (maybe_hash->IsSmi()) return Smi::cast(maybe_hash);
5856   }
5857 
5858   Smi* hash = Smi::FromInt(isolate->GenerateIdentityHash(Smi::kMaxValue));
5859   CHECK(AddDataProperty(&it, handle(hash, isolate), NONE, THROW_ON_ERROR,
5860                         CERTAINLY_NOT_STORE_FROM_KEYED)
5861             .IsJust());
5862   return hash;
5863 }
5864 
5865 // static
GetIdentityHash(Handle<JSProxy> proxy)5866 Object* JSProxy::GetIdentityHash(Handle<JSProxy> proxy) {
5867   return proxy->hash();
5868 }
5869 
GetOrCreateIdentityHash(Isolate * isolate,Handle<JSProxy> proxy)5870 Smi* JSProxy::GetOrCreateIdentityHash(Isolate* isolate, Handle<JSProxy> proxy) {
5871   return GetOrCreateIdentityHashHelper(isolate, proxy);
5872 }
5873 
5874 
DeletePropertyWithInterceptor(LookupIterator * it,ShouldThrow should_throw)5875 Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it,
5876                                                     ShouldThrow should_throw) {
5877   Isolate* isolate = it->isolate();
5878   // Make sure that the top context does not change when doing callbacks or
5879   // interceptor calls.
5880   AssertNoContextChange ncc(isolate);
5881 
5882   DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
5883   Handle<InterceptorInfo> interceptor(it->GetInterceptor());
5884   if (interceptor->deleter()->IsUndefined(isolate)) return Nothing<bool>();
5885 
5886   Handle<JSObject> holder = it->GetHolder<JSObject>();
5887   Handle<Object> receiver = it->GetReceiver();
5888   if (!receiver->IsJSReceiver()) {
5889     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
5890                                      Object::ConvertReceiver(isolate, receiver),
5891                                      Nothing<bool>());
5892   }
5893 
5894   PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
5895                                  *holder, should_throw);
5896   Handle<Object> result;
5897   if (it->IsElement()) {
5898     uint32_t index = it->index();
5899     v8::IndexedPropertyDeleterCallback deleter =
5900         v8::ToCData<v8::IndexedPropertyDeleterCallback>(interceptor->deleter());
5901     result = args.Call(deleter, index);
5902   } else if (it->name()->IsSymbol() && !interceptor->can_intercept_symbols()) {
5903     return Nothing<bool>();
5904   } else {
5905     Handle<Name> name = it->name();
5906     DCHECK(!name->IsPrivate());
5907     v8::GenericNamedPropertyDeleterCallback deleter =
5908         v8::ToCData<v8::GenericNamedPropertyDeleterCallback>(
5909             interceptor->deleter());
5910     result = args.Call(deleter, name);
5911   }
5912 
5913   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
5914   if (result.is_null()) return Nothing<bool>();
5915 
5916   DCHECK(result->IsBoolean());
5917   // Rebox CustomArguments::kReturnValueOffset before returning.
5918   return Just(result->IsTrue(isolate));
5919 }
5920 
5921 
DeleteNormalizedProperty(Handle<JSReceiver> object,Handle<Name> name,int entry)5922 void JSReceiver::DeleteNormalizedProperty(Handle<JSReceiver> object,
5923                                           Handle<Name> name, int entry) {
5924   DCHECK(!object->HasFastProperties());
5925   Isolate* isolate = object->GetIsolate();
5926 
5927   if (object->IsJSGlobalObject()) {
5928     // If we have a global object, invalidate the cell and swap in a new one.
5929     Handle<GlobalDictionary> dictionary(
5930         JSObject::cast(*object)->global_dictionary());
5931     DCHECK_NE(GlobalDictionary::kNotFound, entry);
5932 
5933     auto cell = PropertyCell::InvalidateEntry(dictionary, entry);
5934     cell->set_value(isolate->heap()->the_hole_value());
5935     cell->set_property_details(
5936         PropertyDetails::Empty(PropertyCellType::kUninitialized));
5937   } else {
5938     Handle<NameDictionary> dictionary(object->property_dictionary());
5939     DCHECK_NE(NameDictionary::kNotFound, entry);
5940 
5941     NameDictionary::DeleteProperty(dictionary, entry);
5942     Handle<NameDictionary> new_properties =
5943         NameDictionary::Shrink(dictionary, name);
5944     object->set_properties(*new_properties);
5945   }
5946 }
5947 
5948 
DeleteProperty(LookupIterator * it,LanguageMode language_mode)5949 Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
5950                                        LanguageMode language_mode) {
5951   it->UpdateProtector();
5952 
5953   Isolate* isolate = it->isolate();
5954 
5955   if (it->state() == LookupIterator::JSPROXY) {
5956     return JSProxy::DeletePropertyOrElement(it->GetHolder<JSProxy>(),
5957                                             it->GetName(), language_mode);
5958   }
5959 
5960   if (it->GetReceiver()->IsJSProxy()) {
5961     if (it->state() != LookupIterator::NOT_FOUND) {
5962       DCHECK_EQ(LookupIterator::DATA, it->state());
5963       DCHECK(it->name()->IsPrivate());
5964       it->Delete();
5965     }
5966     return Just(true);
5967   }
5968   Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
5969 
5970   for (; it->IsFound(); it->Next()) {
5971     switch (it->state()) {
5972       case LookupIterator::JSPROXY:
5973       case LookupIterator::NOT_FOUND:
5974       case LookupIterator::TRANSITION:
5975         UNREACHABLE();
5976       case LookupIterator::ACCESS_CHECK:
5977         if (it->HasAccess()) break;
5978         isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
5979         RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
5980         return Just(false);
5981       case LookupIterator::INTERCEPTOR: {
5982         ShouldThrow should_throw =
5983             is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
5984         Maybe<bool> result =
5985             JSObject::DeletePropertyWithInterceptor(it, should_throw);
5986         // An exception was thrown in the interceptor. Propagate.
5987         if (isolate->has_pending_exception()) return Nothing<bool>();
5988         // Delete with interceptor succeeded. Return result.
5989         // TODO(neis): In strict mode, we should probably throw if the
5990         // interceptor returns false.
5991         if (result.IsJust()) return result;
5992         break;
5993       }
5994       case LookupIterator::INTEGER_INDEXED_EXOTIC:
5995         return Just(true);
5996       case LookupIterator::DATA:
5997       case LookupIterator::ACCESSOR: {
5998         if (!it->IsConfigurable()) {
5999           // Fail if the property is not configurable.
6000           if (is_strict(language_mode)) {
6001             isolate->Throw(*isolate->factory()->NewTypeError(
6002                 MessageTemplate::kStrictDeleteProperty, it->GetName(),
6003                 receiver));
6004             return Nothing<bool>();
6005           }
6006           return Just(false);
6007         }
6008 
6009         it->Delete();
6010 
6011         return Just(true);
6012       }
6013     }
6014   }
6015 
6016   return Just(true);
6017 }
6018 
6019 
DeleteElement(Handle<JSReceiver> object,uint32_t index,LanguageMode language_mode)6020 Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index,
6021                                       LanguageMode language_mode) {
6022   LookupIterator it(object->GetIsolate(), object, index, object,
6023                     LookupIterator::OWN);
6024   return DeleteProperty(&it, language_mode);
6025 }
6026 
6027 
DeleteProperty(Handle<JSReceiver> object,Handle<Name> name,LanguageMode language_mode)6028 Maybe<bool> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
6029                                        Handle<Name> name,
6030                                        LanguageMode language_mode) {
6031   LookupIterator it(object, name, object, LookupIterator::OWN);
6032   return DeleteProperty(&it, language_mode);
6033 }
6034 
6035 
DeletePropertyOrElement(Handle<JSReceiver> object,Handle<Name> name,LanguageMode language_mode)6036 Maybe<bool> JSReceiver::DeletePropertyOrElement(Handle<JSReceiver> object,
6037                                                 Handle<Name> name,
6038                                                 LanguageMode language_mode) {
6039   LookupIterator it = LookupIterator::PropertyOrElement(
6040       name->GetIsolate(), object, name, object, LookupIterator::OWN);
6041   return DeleteProperty(&it, language_mode);
6042 }
6043 
6044 // ES6 19.1.2.4
6045 // static
DefineProperty(Isolate * isolate,Handle<Object> object,Handle<Object> key,Handle<Object> attributes)6046 Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object,
6047                                    Handle<Object> key,
6048                                    Handle<Object> attributes) {
6049   // 1. If Type(O) is not Object, throw a TypeError exception.
6050   if (!object->IsJSReceiver()) {
6051     Handle<String> fun_name =
6052         isolate->factory()->InternalizeUtf8String("Object.defineProperty");
6053     THROW_NEW_ERROR_RETURN_FAILURE(
6054         isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name));
6055   }
6056   // 2. Let key be ToPropertyKey(P).
6057   // 3. ReturnIfAbrupt(key).
6058   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key, ToPropertyKey(isolate, key));
6059   // 4. Let desc be ToPropertyDescriptor(Attributes).
6060   // 5. ReturnIfAbrupt(desc).
6061   PropertyDescriptor desc;
6062   if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) {
6063     return isolate->heap()->exception();
6064   }
6065   // 6. Let success be DefinePropertyOrThrow(O,key, desc).
6066   Maybe<bool> success = DefineOwnProperty(
6067       isolate, Handle<JSReceiver>::cast(object), key, &desc, THROW_ON_ERROR);
6068   // 7. ReturnIfAbrupt(success).
6069   MAYBE_RETURN(success, isolate->heap()->exception());
6070   CHECK(success.FromJust());
6071   // 8. Return O.
6072   return *object;
6073 }
6074 
6075 
6076 // ES6 19.1.2.3.1
6077 // static
DefineProperties(Isolate * isolate,Handle<Object> object,Handle<Object> properties)6078 MaybeHandle<Object> JSReceiver::DefineProperties(Isolate* isolate,
6079                                                  Handle<Object> object,
6080                                                  Handle<Object> properties) {
6081   // 1. If Type(O) is not Object, throw a TypeError exception.
6082   if (!object->IsJSReceiver()) {
6083     Handle<String> fun_name =
6084         isolate->factory()->InternalizeUtf8String("Object.defineProperties");
6085     THROW_NEW_ERROR(isolate,
6086                     NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name),
6087                     Object);
6088   }
6089   // 2. Let props be ToObject(Properties).
6090   // 3. ReturnIfAbrupt(props).
6091   Handle<JSReceiver> props;
6092   ASSIGN_RETURN_ON_EXCEPTION(isolate, props,
6093                              Object::ToObject(isolate, properties), Object);
6094 
6095   // 4. Let keys be props.[[OwnPropertyKeys]]().
6096   // 5. ReturnIfAbrupt(keys).
6097   Handle<FixedArray> keys;
6098   ASSIGN_RETURN_ON_EXCEPTION(
6099       isolate, keys, KeyAccumulator::GetKeys(props, KeyCollectionMode::kOwnOnly,
6100                                              ALL_PROPERTIES),
6101       Object);
6102   // 6. Let descriptors be an empty List.
6103   int capacity = keys->length();
6104   std::vector<PropertyDescriptor> descriptors(capacity);
6105   size_t descriptors_index = 0;
6106   // 7. Repeat for each element nextKey of keys in List order,
6107   for (int i = 0; i < keys->length(); ++i) {
6108     Handle<Object> next_key(keys->get(i), isolate);
6109     // 7a. Let propDesc be props.[[GetOwnProperty]](nextKey).
6110     // 7b. ReturnIfAbrupt(propDesc).
6111     bool success = false;
6112     LookupIterator it = LookupIterator::PropertyOrElement(
6113         isolate, props, next_key, &success, LookupIterator::OWN);
6114     DCHECK(success);
6115     Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
6116     if (!maybe.IsJust()) return MaybeHandle<Object>();
6117     PropertyAttributes attrs = maybe.FromJust();
6118     // 7c. If propDesc is not undefined and propDesc.[[Enumerable]] is true:
6119     if (attrs == ABSENT) continue;
6120     if (attrs & DONT_ENUM) continue;
6121     // 7c i. Let descObj be Get(props, nextKey).
6122     // 7c ii. ReturnIfAbrupt(descObj).
6123     Handle<Object> desc_obj;
6124     ASSIGN_RETURN_ON_EXCEPTION(isolate, desc_obj, Object::GetProperty(&it),
6125                                Object);
6126     // 7c iii. Let desc be ToPropertyDescriptor(descObj).
6127     success = PropertyDescriptor::ToPropertyDescriptor(
6128         isolate, desc_obj, &descriptors[descriptors_index]);
6129     // 7c iv. ReturnIfAbrupt(desc).
6130     if (!success) return MaybeHandle<Object>();
6131     // 7c v. Append the pair (a two element List) consisting of nextKey and
6132     //       desc to the end of descriptors.
6133     descriptors[descriptors_index].set_name(next_key);
6134     descriptors_index++;
6135   }
6136   // 8. For each pair from descriptors in list order,
6137   for (size_t i = 0; i < descriptors_index; ++i) {
6138     PropertyDescriptor* desc = &descriptors[i];
6139     // 8a. Let P be the first element of pair.
6140     // 8b. Let desc be the second element of pair.
6141     // 8c. Let status be DefinePropertyOrThrow(O, P, desc).
6142     Maybe<bool> status =
6143         DefineOwnProperty(isolate, Handle<JSReceiver>::cast(object),
6144                           desc->name(), desc, THROW_ON_ERROR);
6145     // 8d. ReturnIfAbrupt(status).
6146     if (!status.IsJust()) return MaybeHandle<Object>();
6147     CHECK(status.FromJust());
6148   }
6149   // 9. Return o.
6150   return object;
6151 }
6152 
6153 
6154 // static
DefineOwnProperty(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> key,PropertyDescriptor * desc,ShouldThrow should_throw)6155 Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate,
6156                                           Handle<JSReceiver> object,
6157                                           Handle<Object> key,
6158                                           PropertyDescriptor* desc,
6159                                           ShouldThrow should_throw) {
6160   if (object->IsJSArray()) {
6161     return JSArray::DefineOwnProperty(isolate, Handle<JSArray>::cast(object),
6162                                       key, desc, should_throw);
6163   }
6164   if (object->IsJSProxy()) {
6165     return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object),
6166                                       key, desc, should_throw);
6167   }
6168   if (object->IsJSTypedArray()) {
6169     return JSTypedArray::DefineOwnProperty(
6170         isolate, Handle<JSTypedArray>::cast(object), key, desc, should_throw);
6171   }
6172   // TODO(neis): Special case for JSModuleNamespace?
6173 
6174   // OrdinaryDefineOwnProperty, by virtue of calling
6175   // DefineOwnPropertyIgnoreAttributes, can handle arguments
6176   // (ES#sec-arguments-exotic-objects-defineownproperty-p-desc).
6177   return OrdinaryDefineOwnProperty(isolate, Handle<JSObject>::cast(object), key,
6178                                    desc, should_throw);
6179 }
6180 
6181 
6182 // static
OrdinaryDefineOwnProperty(Isolate * isolate,Handle<JSObject> object,Handle<Object> key,PropertyDescriptor * desc,ShouldThrow should_throw)6183 Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate,
6184                                                   Handle<JSObject> object,
6185                                                   Handle<Object> key,
6186                                                   PropertyDescriptor* desc,
6187                                                   ShouldThrow should_throw) {
6188   bool success = false;
6189   DCHECK(key->IsName() || key->IsNumber());  // |key| is a PropertyKey...
6190   LookupIterator it = LookupIterator::PropertyOrElement(
6191       isolate, object, key, &success, LookupIterator::OWN);
6192   DCHECK(success);  // ...so creating a LookupIterator can't fail.
6193 
6194   // Deal with access checks first.
6195   if (it.state() == LookupIterator::ACCESS_CHECK) {
6196     if (!it.HasAccess()) {
6197       isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>());
6198       RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6199       return Just(true);
6200     }
6201     it.Next();
6202   }
6203 
6204   // Handle interceptor
6205   if (it.state() == LookupIterator::INTERCEPTOR) {
6206     if (it.HolderIsReceiverOrHiddenPrototype()) {
6207       Maybe<bool> result = DefinePropertyWithInterceptorInternal(
6208           &it, it.GetInterceptor(), should_throw, *desc);
6209       if (result.IsNothing() || result.FromJust()) {
6210         return result;
6211       }
6212     }
6213   }
6214 
6215   return OrdinaryDefineOwnProperty(&it, desc, should_throw);
6216 }
6217 
6218 
6219 // ES6 9.1.6.1
6220 // static
OrdinaryDefineOwnProperty(LookupIterator * it,PropertyDescriptor * desc,ShouldThrow should_throw)6221 Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
6222                                                   PropertyDescriptor* desc,
6223                                                   ShouldThrow should_throw) {
6224   Isolate* isolate = it->isolate();
6225   // 1. Let current be O.[[GetOwnProperty]](P).
6226   // 2. ReturnIfAbrupt(current).
6227   PropertyDescriptor current;
6228   MAYBE_RETURN(GetOwnPropertyDescriptor(it, &current), Nothing<bool>());
6229 
6230   // TODO(jkummerow/verwaest): It would be nice if we didn't have to reset
6231   // the iterator every time. Currently, the reasons why we need it are:
6232   // - handle interceptors correctly
6233   // - handle accessors correctly (which might change the holder's map)
6234   it->Restart();
6235   // 3. Let extensible be the value of the [[Extensible]] internal slot of O.
6236   Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
6237   bool extensible = JSObject::IsExtensible(object);
6238 
6239   return ValidateAndApplyPropertyDescriptor(isolate, it, extensible, desc,
6240                                             &current, should_throw);
6241 }
6242 
6243 
6244 // ES6 9.1.6.2
6245 // static
IsCompatiblePropertyDescriptor(Isolate * isolate,bool extensible,PropertyDescriptor * desc,PropertyDescriptor * current,Handle<Name> property_name,ShouldThrow should_throw)6246 Maybe<bool> JSReceiver::IsCompatiblePropertyDescriptor(
6247     Isolate* isolate, bool extensible, PropertyDescriptor* desc,
6248     PropertyDescriptor* current, Handle<Name> property_name,
6249     ShouldThrow should_throw) {
6250   // 1. Return ValidateAndApplyPropertyDescriptor(undefined, undefined,
6251   //    Extensible, Desc, Current).
6252   return ValidateAndApplyPropertyDescriptor(
6253       isolate, NULL, extensible, desc, current, should_throw, property_name);
6254 }
6255 
6256 
6257 // ES6 9.1.6.3
6258 // static
ValidateAndApplyPropertyDescriptor(Isolate * isolate,LookupIterator * it,bool extensible,PropertyDescriptor * desc,PropertyDescriptor * current,ShouldThrow should_throw,Handle<Name> property_name)6259 Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor(
6260     Isolate* isolate, LookupIterator* it, bool extensible,
6261     PropertyDescriptor* desc, PropertyDescriptor* current,
6262     ShouldThrow should_throw, Handle<Name> property_name) {
6263   // We either need a LookupIterator, or a property name.
6264   DCHECK((it == NULL) != property_name.is_null());
6265   Handle<JSObject> object;
6266   if (it != NULL) object = Handle<JSObject>::cast(it->GetReceiver());
6267   bool desc_is_data_descriptor = PropertyDescriptor::IsDataDescriptor(desc);
6268   bool desc_is_accessor_descriptor =
6269       PropertyDescriptor::IsAccessorDescriptor(desc);
6270   bool desc_is_generic_descriptor =
6271       PropertyDescriptor::IsGenericDescriptor(desc);
6272   // 1. (Assert)
6273   // 2. If current is undefined, then
6274   if (current->is_empty()) {
6275     // 2a. If extensible is false, return false.
6276     if (!extensible) {
6277       RETURN_FAILURE(isolate, should_throw,
6278                      NewTypeError(MessageTemplate::kDefineDisallowed,
6279                                   it != NULL ? it->GetName() : property_name));
6280     }
6281     // 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then:
6282     // (This is equivalent to !IsAccessorDescriptor(desc).)
6283     DCHECK((desc_is_generic_descriptor || desc_is_data_descriptor) ==
6284            !desc_is_accessor_descriptor);
6285     if (!desc_is_accessor_descriptor) {
6286       // 2c i. If O is not undefined, create an own data property named P of
6287       // object O whose [[Value]], [[Writable]], [[Enumerable]] and
6288       // [[Configurable]] attribute values are described by Desc. If the value
6289       // of an attribute field of Desc is absent, the attribute of the newly
6290       // created property is set to its default value.
6291       if (it != NULL) {
6292         if (!desc->has_writable()) desc->set_writable(false);
6293         if (!desc->has_enumerable()) desc->set_enumerable(false);
6294         if (!desc->has_configurable()) desc->set_configurable(false);
6295         Handle<Object> value(
6296             desc->has_value()
6297                 ? desc->value()
6298                 : Handle<Object>::cast(isolate->factory()->undefined_value()));
6299         MaybeHandle<Object> result =
6300             JSObject::DefineOwnPropertyIgnoreAttributes(it, value,
6301                                                         desc->ToAttributes());
6302         if (result.is_null()) return Nothing<bool>();
6303       }
6304     } else {
6305       // 2d. Else Desc must be an accessor Property Descriptor,
6306       DCHECK(desc_is_accessor_descriptor);
6307       // 2d i. If O is not undefined, create an own accessor property named P
6308       // of object O whose [[Get]], [[Set]], [[Enumerable]] and
6309       // [[Configurable]] attribute values are described by Desc. If the value
6310       // of an attribute field of Desc is absent, the attribute of the newly
6311       // created property is set to its default value.
6312       if (it != NULL) {
6313         if (!desc->has_enumerable()) desc->set_enumerable(false);
6314         if (!desc->has_configurable()) desc->set_configurable(false);
6315         Handle<Object> getter(
6316             desc->has_get()
6317                 ? desc->get()
6318                 : Handle<Object>::cast(isolate->factory()->null_value()));
6319         Handle<Object> setter(
6320             desc->has_set()
6321                 ? desc->set()
6322                 : Handle<Object>::cast(isolate->factory()->null_value()));
6323         MaybeHandle<Object> result =
6324             JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes());
6325         if (result.is_null()) return Nothing<bool>();
6326       }
6327     }
6328     // 2e. Return true.
6329     return Just(true);
6330   }
6331   // 3. Return true, if every field in Desc is absent.
6332   // 4. Return true, if every field in Desc also occurs in current and the
6333   // value of every field in Desc is the same value as the corresponding field
6334   // in current when compared using the SameValue algorithm.
6335   if ((!desc->has_enumerable() ||
6336        desc->enumerable() == current->enumerable()) &&
6337       (!desc->has_configurable() ||
6338        desc->configurable() == current->configurable()) &&
6339       (!desc->has_value() ||
6340        (current->has_value() && current->value()->SameValue(*desc->value()))) &&
6341       (!desc->has_writable() ||
6342        (current->has_writable() && current->writable() == desc->writable())) &&
6343       (!desc->has_get() ||
6344        (current->has_get() && current->get()->SameValue(*desc->get()))) &&
6345       (!desc->has_set() ||
6346        (current->has_set() && current->set()->SameValue(*desc->set())))) {
6347     return Just(true);
6348   }
6349   // 5. If the [[Configurable]] field of current is false, then
6350   if (!current->configurable()) {
6351     // 5a. Return false, if the [[Configurable]] field of Desc is true.
6352     if (desc->has_configurable() && desc->configurable()) {
6353       RETURN_FAILURE(isolate, should_throw,
6354                      NewTypeError(MessageTemplate::kRedefineDisallowed,
6355                                   it != NULL ? it->GetName() : property_name));
6356     }
6357     // 5b. Return false, if the [[Enumerable]] field of Desc is present and the
6358     // [[Enumerable]] fields of current and Desc are the Boolean negation of
6359     // each other.
6360     if (desc->has_enumerable() && desc->enumerable() != current->enumerable()) {
6361       RETURN_FAILURE(isolate, should_throw,
6362                      NewTypeError(MessageTemplate::kRedefineDisallowed,
6363                                   it != NULL ? it->GetName() : property_name));
6364     }
6365   }
6366 
6367   bool current_is_data_descriptor =
6368       PropertyDescriptor::IsDataDescriptor(current);
6369   // 6. If IsGenericDescriptor(Desc) is true, no further validation is required.
6370   if (desc_is_generic_descriptor) {
6371     // Nothing to see here.
6372 
6373     // 7. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) have
6374     // different results, then:
6375   } else if (current_is_data_descriptor != desc_is_data_descriptor) {
6376     // 7a. Return false, if the [[Configurable]] field of current is false.
6377     if (!current->configurable()) {
6378       RETURN_FAILURE(isolate, should_throw,
6379                      NewTypeError(MessageTemplate::kRedefineDisallowed,
6380                                   it != NULL ? it->GetName() : property_name));
6381     }
6382     // 7b. If IsDataDescriptor(current) is true, then:
6383     if (current_is_data_descriptor) {
6384       // 7b i. If O is not undefined, convert the property named P of object O
6385       // from a data property to an accessor property. Preserve the existing
6386       // values of the converted property's [[Configurable]] and [[Enumerable]]
6387       // attributes and set the rest of the property's attributes to their
6388       // default values.
6389       // --> Folded into step 10.
6390     } else {
6391       // 7c i. If O is not undefined, convert the property named P of object O
6392       // from an accessor property to a data property. Preserve the existing
6393       // values of the converted property’s [[Configurable]] and [[Enumerable]]
6394       // attributes and set the rest of the property’s attributes to their
6395       // default values.
6396       // --> Folded into step 10.
6397     }
6398 
6399     // 8. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both
6400     // true, then:
6401   } else if (current_is_data_descriptor && desc_is_data_descriptor) {
6402     // 8a. If the [[Configurable]] field of current is false, then:
6403     if (!current->configurable()) {
6404       // 8a i. Return false, if the [[Writable]] field of current is false and
6405       // the [[Writable]] field of Desc is true.
6406       if (!current->writable() && desc->has_writable() && desc->writable()) {
6407         RETURN_FAILURE(
6408             isolate, should_throw,
6409             NewTypeError(MessageTemplate::kRedefineDisallowed,
6410                          it != NULL ? it->GetName() : property_name));
6411       }
6412       // 8a ii. If the [[Writable]] field of current is false, then:
6413       if (!current->writable()) {
6414         // 8a ii 1. Return false, if the [[Value]] field of Desc is present and
6415         // SameValue(Desc.[[Value]], current.[[Value]]) is false.
6416         if (desc->has_value() && !desc->value()->SameValue(*current->value())) {
6417           RETURN_FAILURE(
6418               isolate, should_throw,
6419               NewTypeError(MessageTemplate::kRedefineDisallowed,
6420                            it != NULL ? it->GetName() : property_name));
6421         }
6422       }
6423     }
6424   } else {
6425     // 9. Else IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc)
6426     // are both true,
6427     DCHECK(PropertyDescriptor::IsAccessorDescriptor(current) &&
6428            desc_is_accessor_descriptor);
6429     // 9a. If the [[Configurable]] field of current is false, then:
6430     if (!current->configurable()) {
6431       // 9a i. Return false, if the [[Set]] field of Desc is present and
6432       // SameValue(Desc.[[Set]], current.[[Set]]) is false.
6433       if (desc->has_set() && !desc->set()->SameValue(*current->set())) {
6434         RETURN_FAILURE(
6435             isolate, should_throw,
6436             NewTypeError(MessageTemplate::kRedefineDisallowed,
6437                          it != NULL ? it->GetName() : property_name));
6438       }
6439       // 9a ii. Return false, if the [[Get]] field of Desc is present and
6440       // SameValue(Desc.[[Get]], current.[[Get]]) is false.
6441       if (desc->has_get() && !desc->get()->SameValue(*current->get())) {
6442         RETURN_FAILURE(
6443             isolate, should_throw,
6444             NewTypeError(MessageTemplate::kRedefineDisallowed,
6445                          it != NULL ? it->GetName() : property_name));
6446       }
6447     }
6448   }
6449 
6450   // 10. If O is not undefined, then:
6451   if (it != NULL) {
6452     // 10a. For each field of Desc that is present, set the corresponding
6453     // attribute of the property named P of object O to the value of the field.
6454     PropertyAttributes attrs = NONE;
6455 
6456     if (desc->has_enumerable()) {
6457       attrs = static_cast<PropertyAttributes>(
6458           attrs | (desc->enumerable() ? NONE : DONT_ENUM));
6459     } else {
6460       attrs = static_cast<PropertyAttributes>(
6461           attrs | (current->enumerable() ? NONE : DONT_ENUM));
6462     }
6463     if (desc->has_configurable()) {
6464       attrs = static_cast<PropertyAttributes>(
6465           attrs | (desc->configurable() ? NONE : DONT_DELETE));
6466     } else {
6467       attrs = static_cast<PropertyAttributes>(
6468           attrs | (current->configurable() ? NONE : DONT_DELETE));
6469     }
6470     if (desc_is_data_descriptor ||
6471         (desc_is_generic_descriptor && current_is_data_descriptor)) {
6472       if (desc->has_writable()) {
6473         attrs = static_cast<PropertyAttributes>(
6474             attrs | (desc->writable() ? NONE : READ_ONLY));
6475       } else {
6476         attrs = static_cast<PropertyAttributes>(
6477             attrs | (current->writable() ? NONE : READ_ONLY));
6478       }
6479       Handle<Object> value(
6480           desc->has_value() ? desc->value()
6481                             : current->has_value()
6482                                   ? current->value()
6483                                   : Handle<Object>::cast(
6484                                         isolate->factory()->undefined_value()));
6485       MaybeHandle<Object> result =
6486           JSObject::DefineOwnPropertyIgnoreAttributes(it, value, attrs);
6487       if (result.is_null()) return Nothing<bool>();
6488     } else {
6489       DCHECK(desc_is_accessor_descriptor ||
6490              (desc_is_generic_descriptor &&
6491               PropertyDescriptor::IsAccessorDescriptor(current)));
6492       Handle<Object> getter(
6493           desc->has_get()
6494               ? desc->get()
6495               : current->has_get()
6496                     ? current->get()
6497                     : Handle<Object>::cast(isolate->factory()->null_value()));
6498       Handle<Object> setter(
6499           desc->has_set()
6500               ? desc->set()
6501               : current->has_set()
6502                     ? current->set()
6503                     : Handle<Object>::cast(isolate->factory()->null_value()));
6504       MaybeHandle<Object> result =
6505           JSObject::DefineAccessor(it, getter, setter, attrs);
6506       if (result.is_null()) return Nothing<bool>();
6507     }
6508   }
6509 
6510   // 11. Return true.
6511   return Just(true);
6512 }
6513 
6514 
6515 // static
CreateDataProperty(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)6516 Maybe<bool> JSReceiver::CreateDataProperty(LookupIterator* it,
6517                                            Handle<Object> value,
6518                                            ShouldThrow should_throw) {
6519   DCHECK(!it->check_prototype_chain());
6520   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
6521   Isolate* isolate = receiver->GetIsolate();
6522 
6523   if (receiver->IsJSObject()) {
6524     return JSObject::CreateDataProperty(it, value, should_throw);  // Shortcut.
6525   }
6526 
6527   PropertyDescriptor new_desc;
6528   new_desc.set_value(value);
6529   new_desc.set_writable(true);
6530   new_desc.set_enumerable(true);
6531   new_desc.set_configurable(true);
6532 
6533   return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
6534                                        &new_desc, should_throw);
6535 }
6536 
CreateDataProperty(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)6537 Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it,
6538                                          Handle<Object> value,
6539                                          ShouldThrow should_throw) {
6540   DCHECK(it->GetReceiver()->IsJSObject());
6541   MAYBE_RETURN(JSReceiver::GetPropertyAttributes(it), Nothing<bool>());
6542   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
6543   Isolate* isolate = receiver->GetIsolate();
6544 
6545   if (it->IsFound()) {
6546     Maybe<PropertyAttributes> attributes = GetPropertyAttributes(it);
6547     MAYBE_RETURN(attributes, Nothing<bool>());
6548     if ((attributes.FromJust() & DONT_DELETE) != 0) {
6549       RETURN_FAILURE(
6550           isolate, should_throw,
6551           NewTypeError(MessageTemplate::kRedefineDisallowed, it->GetName()));
6552     }
6553   } else {
6554     if (!JSObject::IsExtensible(Handle<JSObject>::cast(it->GetReceiver()))) {
6555       RETURN_FAILURE(
6556           isolate, should_throw,
6557           NewTypeError(MessageTemplate::kDefineDisallowed, it->GetName()));
6558     }
6559   }
6560 
6561   RETURN_ON_EXCEPTION_VALUE(it->isolate(),
6562                             DefineOwnPropertyIgnoreAttributes(it, value, NONE),
6563                             Nothing<bool>());
6564 
6565   return Just(true);
6566 }
6567 
6568 
6569 // TODO(jkummerow): Consider unification with FastAsArrayLength() in
6570 // accessors.cc.
PropertyKeyToArrayLength(Handle<Object> value,uint32_t * length)6571 bool PropertyKeyToArrayLength(Handle<Object> value, uint32_t* length) {
6572   DCHECK(value->IsNumber() || value->IsName());
6573   if (value->ToArrayLength(length)) return true;
6574   if (value->IsString()) return String::cast(*value)->AsArrayIndex(length);
6575   return false;
6576 }
6577 
PropertyKeyToArrayIndex(Handle<Object> index_obj,uint32_t * output)6578 bool PropertyKeyToArrayIndex(Handle<Object> index_obj, uint32_t* output) {
6579   return PropertyKeyToArrayLength(index_obj, output) && *output != kMaxUInt32;
6580 }
6581 
6582 
6583 // ES6 9.4.2.1
6584 // static
DefineOwnProperty(Isolate * isolate,Handle<JSArray> o,Handle<Object> name,PropertyDescriptor * desc,ShouldThrow should_throw)6585 Maybe<bool> JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o,
6586                                        Handle<Object> name,
6587                                        PropertyDescriptor* desc,
6588                                        ShouldThrow should_throw) {
6589   // 1. Assert: IsPropertyKey(P) is true. ("P" is |name|.)
6590   // 2. If P is "length", then:
6591   // TODO(jkummerow): Check if we need slow string comparison.
6592   if (*name == isolate->heap()->length_string()) {
6593     // 2a. Return ArraySetLength(A, Desc).
6594     return ArraySetLength(isolate, o, desc, should_throw);
6595   }
6596   // 3. Else if P is an array index, then:
6597   uint32_t index = 0;
6598   if (PropertyKeyToArrayIndex(name, &index)) {
6599     // 3a. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
6600     PropertyDescriptor old_len_desc;
6601     Maybe<bool> success = GetOwnPropertyDescriptor(
6602         isolate, o, isolate->factory()->length_string(), &old_len_desc);
6603     // 3b. (Assert)
6604     DCHECK(success.FromJust());
6605     USE(success);
6606     // 3c. Let oldLen be oldLenDesc.[[Value]].
6607     uint32_t old_len = 0;
6608     CHECK(old_len_desc.value()->ToArrayLength(&old_len));
6609     // 3d. Let index be ToUint32(P).
6610     // (Already done above.)
6611     // 3e. (Assert)
6612     // 3f. If index >= oldLen and oldLenDesc.[[Writable]] is false,
6613     //     return false.
6614     if (index >= old_len && old_len_desc.has_writable() &&
6615         !old_len_desc.writable()) {
6616       RETURN_FAILURE(isolate, should_throw,
6617                      NewTypeError(MessageTemplate::kDefineDisallowed, name));
6618     }
6619     // 3g. Let succeeded be OrdinaryDefineOwnProperty(A, P, Desc).
6620     Maybe<bool> succeeded =
6621         OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
6622     // 3h. Assert: succeeded is not an abrupt completion.
6623     //     In our case, if should_throw == THROW_ON_ERROR, it can be!
6624     // 3i. If succeeded is false, return false.
6625     if (succeeded.IsNothing() || !succeeded.FromJust()) return succeeded;
6626     // 3j. If index >= oldLen, then:
6627     if (index >= old_len) {
6628       // 3j i. Set oldLenDesc.[[Value]] to index + 1.
6629       old_len_desc.set_value(isolate->factory()->NewNumberFromUint(index + 1));
6630       // 3j ii. Let succeeded be
6631       //        OrdinaryDefineOwnProperty(A, "length", oldLenDesc).
6632       succeeded = OrdinaryDefineOwnProperty(isolate, o,
6633                                             isolate->factory()->length_string(),
6634                                             &old_len_desc, should_throw);
6635       // 3j iii. Assert: succeeded is true.
6636       DCHECK(succeeded.FromJust());
6637       USE(succeeded);
6638     }
6639     // 3k. Return true.
6640     return Just(true);
6641   }
6642 
6643   // 4. Return OrdinaryDefineOwnProperty(A, P, Desc).
6644   return OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
6645 }
6646 
6647 
6648 // Part of ES6 9.4.2.4 ArraySetLength.
6649 // static
AnythingToArrayLength(Isolate * isolate,Handle<Object> length_object,uint32_t * output)6650 bool JSArray::AnythingToArrayLength(Isolate* isolate,
6651                                     Handle<Object> length_object,
6652                                     uint32_t* output) {
6653   // Fast path: check numbers and strings that can be converted directly
6654   // and unobservably.
6655   if (length_object->ToArrayLength(output)) return true;
6656   if (length_object->IsString() &&
6657       Handle<String>::cast(length_object)->AsArrayIndex(output)) {
6658     return true;
6659   }
6660   // Slow path: follow steps in ES6 9.4.2.4 "ArraySetLength".
6661   // 3. Let newLen be ToUint32(Desc.[[Value]]).
6662   Handle<Object> uint32_v;
6663   if (!Object::ToUint32(isolate, length_object).ToHandle(&uint32_v)) {
6664     // 4. ReturnIfAbrupt(newLen).
6665     return false;
6666   }
6667   // 5. Let numberLen be ToNumber(Desc.[[Value]]).
6668   Handle<Object> number_v;
6669   if (!Object::ToNumber(length_object).ToHandle(&number_v)) {
6670     // 6. ReturnIfAbrupt(newLen).
6671     return false;
6672   }
6673   // 7. If newLen != numberLen, throw a RangeError exception.
6674   if (uint32_v->Number() != number_v->Number()) {
6675     Handle<Object> exception =
6676         isolate->factory()->NewRangeError(MessageTemplate::kInvalidArrayLength);
6677     isolate->Throw(*exception);
6678     return false;
6679   }
6680   CHECK(uint32_v->ToArrayLength(output));
6681   return true;
6682 }
6683 
6684 
6685 // ES6 9.4.2.4
6686 // static
ArraySetLength(Isolate * isolate,Handle<JSArray> a,PropertyDescriptor * desc,ShouldThrow should_throw)6687 Maybe<bool> JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a,
6688                                     PropertyDescriptor* desc,
6689                                     ShouldThrow should_throw) {
6690   // 1. If the [[Value]] field of Desc is absent, then
6691   if (!desc->has_value()) {
6692     // 1a. Return OrdinaryDefineOwnProperty(A, "length", Desc).
6693     return OrdinaryDefineOwnProperty(
6694         isolate, a, isolate->factory()->length_string(), desc, should_throw);
6695   }
6696   // 2. Let newLenDesc be a copy of Desc.
6697   // (Actual copying is not necessary.)
6698   PropertyDescriptor* new_len_desc = desc;
6699   // 3. - 7. Convert Desc.[[Value]] to newLen.
6700   uint32_t new_len = 0;
6701   if (!AnythingToArrayLength(isolate, desc->value(), &new_len)) {
6702     DCHECK(isolate->has_pending_exception());
6703     return Nothing<bool>();
6704   }
6705   // 8. Set newLenDesc.[[Value]] to newLen.
6706   // (Done below, if needed.)
6707   // 9. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
6708   PropertyDescriptor old_len_desc;
6709   Maybe<bool> success = GetOwnPropertyDescriptor(
6710       isolate, a, isolate->factory()->length_string(), &old_len_desc);
6711   // 10. (Assert)
6712   DCHECK(success.FromJust());
6713   USE(success);
6714   // 11. Let oldLen be oldLenDesc.[[Value]].
6715   uint32_t old_len = 0;
6716   CHECK(old_len_desc.value()->ToArrayLength(&old_len));
6717   // 12. If newLen >= oldLen, then
6718   if (new_len >= old_len) {
6719     // 8. Set newLenDesc.[[Value]] to newLen.
6720     // 12a. Return OrdinaryDefineOwnProperty(A, "length", newLenDesc).
6721     new_len_desc->set_value(isolate->factory()->NewNumberFromUint(new_len));
6722     return OrdinaryDefineOwnProperty(isolate, a,
6723                                      isolate->factory()->length_string(),
6724                                      new_len_desc, should_throw);
6725   }
6726   // 13. If oldLenDesc.[[Writable]] is false, return false.
6727   if (!old_len_desc.writable()) {
6728     RETURN_FAILURE(isolate, should_throw,
6729                    NewTypeError(MessageTemplate::kRedefineDisallowed,
6730                                 isolate->factory()->length_string()));
6731   }
6732   // 14. If newLenDesc.[[Writable]] is absent or has the value true,
6733   // let newWritable be true.
6734   bool new_writable = false;
6735   if (!new_len_desc->has_writable() || new_len_desc->writable()) {
6736     new_writable = true;
6737   } else {
6738     // 15. Else,
6739     // 15a. Need to defer setting the [[Writable]] attribute to false in case
6740     //      any elements cannot be deleted.
6741     // 15b. Let newWritable be false. (It's initialized as "false" anyway.)
6742     // 15c. Set newLenDesc.[[Writable]] to true.
6743     // (Not needed.)
6744   }
6745   // Most of steps 16 through 19 is implemented by JSArray::SetLength.
6746   JSArray::SetLength(a, new_len);
6747   // Steps 19d-ii, 20.
6748   if (!new_writable) {
6749     PropertyDescriptor readonly;
6750     readonly.set_writable(false);
6751     Maybe<bool> success = OrdinaryDefineOwnProperty(
6752         isolate, a, isolate->factory()->length_string(), &readonly,
6753         should_throw);
6754     DCHECK(success.FromJust());
6755     USE(success);
6756   }
6757   uint32_t actual_new_len = 0;
6758   CHECK(a->length()->ToArrayLength(&actual_new_len));
6759   // Steps 19d-v, 21. Return false if there were non-deletable elements.
6760   bool result = actual_new_len == new_len;
6761   if (!result) {
6762     RETURN_FAILURE(
6763         isolate, should_throw,
6764         NewTypeError(MessageTemplate::kStrictDeleteProperty,
6765                      isolate->factory()->NewNumberFromUint(actual_new_len - 1),
6766                      a));
6767   }
6768   return Just(result);
6769 }
6770 
6771 
6772 // ES6 9.5.6
6773 // static
DefineOwnProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Object> key,PropertyDescriptor * desc,ShouldThrow should_throw)6774 Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy,
6775                                        Handle<Object> key,
6776                                        PropertyDescriptor* desc,
6777                                        ShouldThrow should_throw) {
6778   STACK_CHECK(isolate, Nothing<bool>());
6779   if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) {
6780     return SetPrivateProperty(isolate, proxy, Handle<Symbol>::cast(key), desc,
6781                               should_throw);
6782   }
6783   Handle<String> trap_name = isolate->factory()->defineProperty_string();
6784   // 1. Assert: IsPropertyKey(P) is true.
6785   DCHECK(key->IsName() || key->IsNumber());
6786   // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
6787   Handle<Object> handler(proxy->handler(), isolate);
6788   // 3. If handler is null, throw a TypeError exception.
6789   // 4. Assert: Type(handler) is Object.
6790   if (proxy->IsRevoked()) {
6791     isolate->Throw(*isolate->factory()->NewTypeError(
6792         MessageTemplate::kProxyRevoked, trap_name));
6793     return Nothing<bool>();
6794   }
6795   // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
6796   Handle<JSReceiver> target(proxy->target(), isolate);
6797   // 6. Let trap be ? GetMethod(handler, "defineProperty").
6798   Handle<Object> trap;
6799   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
6800       isolate, trap,
6801       Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
6802       Nothing<bool>());
6803   // 7. If trap is undefined, then:
6804   if (trap->IsUndefined(isolate)) {
6805     // 7a. Return target.[[DefineOwnProperty]](P, Desc).
6806     return JSReceiver::DefineOwnProperty(isolate, target, key, desc,
6807                                          should_throw);
6808   }
6809   // 8. Let descObj be FromPropertyDescriptor(Desc).
6810   Handle<Object> desc_obj = desc->ToObject(isolate);
6811   // 9. Let booleanTrapResult be
6812   //    ToBoolean(? Call(trap, handler, «target, P, descObj»)).
6813   Handle<Name> property_name =
6814       key->IsName()
6815           ? Handle<Name>::cast(key)
6816           : Handle<Name>::cast(isolate->factory()->NumberToString(key));
6817   // Do not leak private property names.
6818   DCHECK(!property_name->IsPrivate());
6819   Handle<Object> trap_result_obj;
6820   Handle<Object> args[] = {target, property_name, desc_obj};
6821   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
6822       isolate, trap_result_obj,
6823       Execution::Call(isolate, trap, handler, arraysize(args), args),
6824       Nothing<bool>());
6825   // 10. If booleanTrapResult is false, return false.
6826   if (!trap_result_obj->BooleanValue()) {
6827     RETURN_FAILURE(isolate, should_throw,
6828                    NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
6829                                 trap_name, property_name));
6830   }
6831   // 11. Let targetDesc be ? target.[[GetOwnProperty]](P).
6832   PropertyDescriptor target_desc;
6833   Maybe<bool> target_found =
6834       JSReceiver::GetOwnPropertyDescriptor(isolate, target, key, &target_desc);
6835   MAYBE_RETURN(target_found, Nothing<bool>());
6836   // 12. Let extensibleTarget be ? IsExtensible(target).
6837   Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
6838   MAYBE_RETURN(maybe_extensible, Nothing<bool>());
6839   bool extensible_target = maybe_extensible.FromJust();
6840   // 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]]
6841   //     is false, then:
6842   // 13a. Let settingConfigFalse be true.
6843   // 14. Else let settingConfigFalse be false.
6844   bool setting_config_false = desc->has_configurable() && !desc->configurable();
6845   // 15. If targetDesc is undefined, then
6846   if (!target_found.FromJust()) {
6847     // 15a. If extensibleTarget is false, throw a TypeError exception.
6848     if (!extensible_target) {
6849       isolate->Throw(*isolate->factory()->NewTypeError(
6850           MessageTemplate::kProxyDefinePropertyNonExtensible, property_name));
6851       return Nothing<bool>();
6852     }
6853     // 15b. If settingConfigFalse is true, throw a TypeError exception.
6854     if (setting_config_false) {
6855       isolate->Throw(*isolate->factory()->NewTypeError(
6856           MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
6857       return Nothing<bool>();
6858     }
6859   } else {
6860     // 16. Else targetDesc is not undefined,
6861     // 16a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc,
6862     //      targetDesc) is false, throw a TypeError exception.
6863     Maybe<bool> valid =
6864         IsCompatiblePropertyDescriptor(isolate, extensible_target, desc,
6865                                        &target_desc, property_name, DONT_THROW);
6866     MAYBE_RETURN(valid, Nothing<bool>());
6867     if (!valid.FromJust()) {
6868       isolate->Throw(*isolate->factory()->NewTypeError(
6869           MessageTemplate::kProxyDefinePropertyIncompatible, property_name));
6870       return Nothing<bool>();
6871     }
6872     // 16b. If settingConfigFalse is true and targetDesc.[[Configurable]] is
6873     //      true, throw a TypeError exception.
6874     if (setting_config_false && target_desc.configurable()) {
6875       isolate->Throw(*isolate->factory()->NewTypeError(
6876           MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
6877       return Nothing<bool>();
6878     }
6879   }
6880   // 17. Return true.
6881   return Just(true);
6882 }
6883 
6884 
6885 // static
SetPrivateProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Symbol> private_name,PropertyDescriptor * desc,ShouldThrow should_throw)6886 Maybe<bool> JSProxy::SetPrivateProperty(Isolate* isolate, Handle<JSProxy> proxy,
6887                                         Handle<Symbol> private_name,
6888                                         PropertyDescriptor* desc,
6889                                         ShouldThrow should_throw) {
6890   // Despite the generic name, this can only add private data properties.
6891   if (!PropertyDescriptor::IsDataDescriptor(desc) ||
6892       desc->ToAttributes() != DONT_ENUM) {
6893     RETURN_FAILURE(isolate, should_throw,
6894                    NewTypeError(MessageTemplate::kProxyPrivate));
6895   }
6896   DCHECK(proxy->map()->is_dictionary_map());
6897   Handle<Object> value =
6898       desc->has_value()
6899           ? desc->value()
6900           : Handle<Object>::cast(isolate->factory()->undefined_value());
6901 
6902   LookupIterator it(proxy, private_name, proxy);
6903 
6904   if (it.IsFound()) {
6905     DCHECK_EQ(LookupIterator::DATA, it.state());
6906     DCHECK_EQ(DONT_ENUM, it.property_attributes());
6907     it.WriteDataValue(value, false);
6908     return Just(true);
6909   }
6910 
6911   Handle<NameDictionary> dict(proxy->property_dictionary());
6912   PropertyDetails details(kData, DONT_ENUM, 0, PropertyCellType::kNoCell);
6913   Handle<NameDictionary> result =
6914       NameDictionary::Add(dict, private_name, value, details);
6915   if (!dict.is_identical_to(result)) proxy->set_properties(*result);
6916   return Just(true);
6917 }
6918 
6919 
6920 // static
GetOwnPropertyDescriptor(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> key,PropertyDescriptor * desc)6921 Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate,
6922                                                  Handle<JSReceiver> object,
6923                                                  Handle<Object> key,
6924                                                  PropertyDescriptor* desc) {
6925   bool success = false;
6926   DCHECK(key->IsName() || key->IsNumber());  // |key| is a PropertyKey...
6927   LookupIterator it = LookupIterator::PropertyOrElement(
6928       isolate, object, key, &success, LookupIterator::OWN);
6929   DCHECK(success);  // ...so creating a LookupIterator can't fail.
6930   return GetOwnPropertyDescriptor(&it, desc);
6931 }
6932 
6933 namespace {
6934 
GetPropertyDescriptorWithInterceptor(LookupIterator * it,PropertyDescriptor * desc)6935 Maybe<bool> GetPropertyDescriptorWithInterceptor(LookupIterator* it,
6936                                                  PropertyDescriptor* desc) {
6937   bool has_access = true;
6938   if (it->state() == LookupIterator::ACCESS_CHECK) {
6939     has_access = it->HasAccess() || JSObject::AllCanRead(it);
6940     it->Next();
6941   }
6942 
6943   if (has_access && it->state() == LookupIterator::INTERCEPTOR) {
6944     Isolate* isolate = it->isolate();
6945     Handle<InterceptorInfo> interceptor = it->GetInterceptor();
6946     if (!interceptor->descriptor()->IsUndefined(isolate)) {
6947       Handle<Object> result;
6948       Handle<JSObject> holder = it->GetHolder<JSObject>();
6949 
6950       Handle<Object> receiver = it->GetReceiver();
6951       if (!receiver->IsJSReceiver()) {
6952         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
6953             isolate, receiver, Object::ConvertReceiver(isolate, receiver),
6954             Nothing<bool>());
6955       }
6956 
6957       PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
6958                                      *holder, Object::DONT_THROW);
6959       if (it->IsElement()) {
6960         uint32_t index = it->index();
6961         v8::IndexedPropertyDescriptorCallback descriptorCallback =
6962             v8::ToCData<v8::IndexedPropertyDescriptorCallback>(
6963                 interceptor->descriptor());
6964 
6965         result = args.Call(descriptorCallback, index);
6966       } else {
6967         Handle<Name> name = it->name();
6968         DCHECK(!name->IsPrivate());
6969         v8::GenericNamedPropertyDescriptorCallback descriptorCallback =
6970             v8::ToCData<v8::GenericNamedPropertyDescriptorCallback>(
6971                 interceptor->descriptor());
6972         result = args.Call(descriptorCallback, name);
6973       }
6974       if (!result.is_null()) {
6975         // Request successfully intercepted, try to set the property
6976         // descriptor.
6977         Utils::ApiCheck(
6978             PropertyDescriptor::ToPropertyDescriptor(isolate, result, desc),
6979             it->IsElement() ? "v8::IndexedPropertyDescriptorCallback"
6980                             : "v8::NamedPropertyDescriptorCallback",
6981             "Invalid property descriptor.");
6982 
6983         return Just(true);
6984       }
6985     }
6986   }
6987   it->Restart();
6988   return Just(false);
6989 }
6990 }  // namespace
6991 
6992 // ES6 9.1.5.1
6993 // Returns true on success, false if the property didn't exist, nothing if
6994 // an exception was thrown.
6995 // static
GetOwnPropertyDescriptor(LookupIterator * it,PropertyDescriptor * desc)6996 Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it,
6997                                                  PropertyDescriptor* desc) {
6998   Isolate* isolate = it->isolate();
6999   // "Virtual" dispatch.
7000   if (it->IsFound() && it->GetHolder<JSReceiver>()->IsJSProxy()) {
7001     return JSProxy::GetOwnPropertyDescriptor(isolate, it->GetHolder<JSProxy>(),
7002                                              it->GetName(), desc);
7003   }
7004 
7005   Maybe<bool> intercepted = GetPropertyDescriptorWithInterceptor(it, desc);
7006   MAYBE_RETURN(intercepted, Nothing<bool>());
7007   if (intercepted.FromJust()) {
7008     return Just(true);
7009   }
7010 
7011   // Request was not intercepted, continue as normal.
7012   // 1. (Assert)
7013   // 2. If O does not have an own property with key P, return undefined.
7014   Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(it);
7015   MAYBE_RETURN(maybe, Nothing<bool>());
7016   PropertyAttributes attrs = maybe.FromJust();
7017   if (attrs == ABSENT) return Just(false);
7018   DCHECK(!isolate->has_pending_exception());
7019 
7020   // 3. Let D be a newly created Property Descriptor with no fields.
7021   DCHECK(desc->is_empty());
7022   // 4. Let X be O's own property whose key is P.
7023   // 5. If X is a data property, then
7024   bool is_accessor_pair = it->state() == LookupIterator::ACCESSOR &&
7025                           it->GetAccessors()->IsAccessorPair();
7026   if (!is_accessor_pair) {
7027     // 5a. Set D.[[Value]] to the value of X's [[Value]] attribute.
7028     Handle<Object> value;
7029     if (!Object::GetProperty(it).ToHandle(&value)) {
7030       DCHECK(isolate->has_pending_exception());
7031       return Nothing<bool>();
7032     }
7033     desc->set_value(value);
7034     // 5b. Set D.[[Writable]] to the value of X's [[Writable]] attribute
7035     desc->set_writable((attrs & READ_ONLY) == 0);
7036   } else {
7037     // 6. Else X is an accessor property, so
7038     Handle<AccessorPair> accessors =
7039         Handle<AccessorPair>::cast(it->GetAccessors());
7040     // 6a. Set D.[[Get]] to the value of X's [[Get]] attribute.
7041     desc->set_get(AccessorPair::GetComponent(accessors, ACCESSOR_GETTER));
7042     // 6b. Set D.[[Set]] to the value of X's [[Set]] attribute.
7043     desc->set_set(AccessorPair::GetComponent(accessors, ACCESSOR_SETTER));
7044   }
7045 
7046   // 7. Set D.[[Enumerable]] to the value of X's [[Enumerable]] attribute.
7047   desc->set_enumerable((attrs & DONT_ENUM) == 0);
7048   // 8. Set D.[[Configurable]] to the value of X's [[Configurable]] attribute.
7049   desc->set_configurable((attrs & DONT_DELETE) == 0);
7050   // 9. Return D.
7051   DCHECK(PropertyDescriptor::IsAccessorDescriptor(desc) !=
7052          PropertyDescriptor::IsDataDescriptor(desc));
7053   return Just(true);
7054 }
7055 
7056 
7057 // ES6 9.5.5
7058 // static
GetOwnPropertyDescriptor(Isolate * isolate,Handle<JSProxy> proxy,Handle<Name> name,PropertyDescriptor * desc)7059 Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate,
7060                                               Handle<JSProxy> proxy,
7061                                               Handle<Name> name,
7062                                               PropertyDescriptor* desc) {
7063   DCHECK(!name->IsPrivate());
7064   STACK_CHECK(isolate, Nothing<bool>());
7065 
7066   Handle<String> trap_name =
7067       isolate->factory()->getOwnPropertyDescriptor_string();
7068   // 1. (Assert)
7069   // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
7070   Handle<Object> handler(proxy->handler(), isolate);
7071   // 3. If handler is null, throw a TypeError exception.
7072   // 4. Assert: Type(handler) is Object.
7073   if (proxy->IsRevoked()) {
7074     isolate->Throw(*isolate->factory()->NewTypeError(
7075         MessageTemplate::kProxyRevoked, trap_name));
7076     return Nothing<bool>();
7077   }
7078   // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
7079   Handle<JSReceiver> target(proxy->target(), isolate);
7080   // 6. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor").
7081   Handle<Object> trap;
7082   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7083       isolate, trap,
7084       Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
7085       Nothing<bool>());
7086   // 7. If trap is undefined, then
7087   if (trap->IsUndefined(isolate)) {
7088     // 7a. Return target.[[GetOwnProperty]](P).
7089     return JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, desc);
7090   }
7091   // 8. Let trapResultObj be ? Call(trap, handler, «target, P»).
7092   Handle<Object> trap_result_obj;
7093   Handle<Object> args[] = {target, name};
7094   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7095       isolate, trap_result_obj,
7096       Execution::Call(isolate, trap, handler, arraysize(args), args),
7097       Nothing<bool>());
7098   // 9. If Type(trapResultObj) is neither Object nor Undefined, throw a
7099   //    TypeError exception.
7100   if (!trap_result_obj->IsJSReceiver() &&
7101       !trap_result_obj->IsUndefined(isolate)) {
7102     isolate->Throw(*isolate->factory()->NewTypeError(
7103         MessageTemplate::kProxyGetOwnPropertyDescriptorInvalid, name));
7104     return Nothing<bool>();
7105   }
7106   // 10. Let targetDesc be ? target.[[GetOwnProperty]](P).
7107   PropertyDescriptor target_desc;
7108   Maybe<bool> found =
7109       JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
7110   MAYBE_RETURN(found, Nothing<bool>());
7111   // 11. If trapResultObj is undefined, then
7112   if (trap_result_obj->IsUndefined(isolate)) {
7113     // 11a. If targetDesc is undefined, return undefined.
7114     if (!found.FromJust()) return Just(false);
7115     // 11b. If targetDesc.[[Configurable]] is false, throw a TypeError
7116     //      exception.
7117     if (!target_desc.configurable()) {
7118       isolate->Throw(*isolate->factory()->NewTypeError(
7119           MessageTemplate::kProxyGetOwnPropertyDescriptorUndefined, name));
7120       return Nothing<bool>();
7121     }
7122     // 11c. Let extensibleTarget be ? IsExtensible(target).
7123     Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
7124     MAYBE_RETURN(extensible_target, Nothing<bool>());
7125     // 11d. (Assert)
7126     // 11e. If extensibleTarget is false, throw a TypeError exception.
7127     if (!extensible_target.FromJust()) {
7128       isolate->Throw(*isolate->factory()->NewTypeError(
7129           MessageTemplate::kProxyGetOwnPropertyDescriptorNonExtensible, name));
7130       return Nothing<bool>();
7131     }
7132     // 11f. Return undefined.
7133     return Just(false);
7134   }
7135   // 12. Let extensibleTarget be ? IsExtensible(target).
7136   Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
7137   MAYBE_RETURN(extensible_target, Nothing<bool>());
7138   // 13. Let resultDesc be ? ToPropertyDescriptor(trapResultObj).
7139   if (!PropertyDescriptor::ToPropertyDescriptor(isolate, trap_result_obj,
7140                                                 desc)) {
7141     DCHECK(isolate->has_pending_exception());
7142     return Nothing<bool>();
7143   }
7144   // 14. Call CompletePropertyDescriptor(resultDesc).
7145   PropertyDescriptor::CompletePropertyDescriptor(isolate, desc);
7146   // 15. Let valid be IsCompatiblePropertyDescriptor (extensibleTarget,
7147   //     resultDesc, targetDesc).
7148   Maybe<bool> valid =
7149       IsCompatiblePropertyDescriptor(isolate, extensible_target.FromJust(),
7150                                      desc, &target_desc, name, DONT_THROW);
7151   MAYBE_RETURN(valid, Nothing<bool>());
7152   // 16. If valid is false, throw a TypeError exception.
7153   if (!valid.FromJust()) {
7154     isolate->Throw(*isolate->factory()->NewTypeError(
7155         MessageTemplate::kProxyGetOwnPropertyDescriptorIncompatible, name));
7156     return Nothing<bool>();
7157   }
7158   // 17. If resultDesc.[[Configurable]] is false, then
7159   if (!desc->configurable()) {
7160     // 17a. If targetDesc is undefined or targetDesc.[[Configurable]] is true:
7161     if (target_desc.is_empty() || target_desc.configurable()) {
7162       // 17a i. Throw a TypeError exception.
7163       isolate->Throw(*isolate->factory()->NewTypeError(
7164           MessageTemplate::kProxyGetOwnPropertyDescriptorNonConfigurable,
7165           name));
7166       return Nothing<bool>();
7167     }
7168   }
7169   // 18. Return resultDesc.
7170   return Just(true);
7171 }
7172 
7173 
ReferencesObjectFromElements(FixedArray * elements,ElementsKind kind,Object * object)7174 bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
7175                                             ElementsKind kind,
7176                                             Object* object) {
7177   Isolate* isolate = elements->GetIsolate();
7178   if (IsFastObjectElementsKind(kind) || kind == FAST_STRING_WRAPPER_ELEMENTS) {
7179     int length = IsJSArray()
7180         ? Smi::cast(JSArray::cast(this)->length())->value()
7181         : elements->length();
7182     for (int i = 0; i < length; ++i) {
7183       Object* element = elements->get(i);
7184       if (!element->IsTheHole(isolate) && element == object) return true;
7185     }
7186   } else {
7187     DCHECK(kind == DICTIONARY_ELEMENTS || kind == SLOW_STRING_WRAPPER_ELEMENTS);
7188     Object* key =
7189         SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
7190     if (!key->IsUndefined(isolate)) return true;
7191   }
7192   return false;
7193 }
7194 
7195 
7196 // Check whether this object references another object.
ReferencesObject(Object * obj)7197 bool JSObject::ReferencesObject(Object* obj) {
7198   Map* map_of_this = map();
7199   Heap* heap = GetHeap();
7200   DisallowHeapAllocation no_allocation;
7201 
7202   // Is the object the constructor for this object?
7203   if (map_of_this->GetConstructor() == obj) {
7204     return true;
7205   }
7206 
7207   // Is the object the prototype for this object?
7208   if (map_of_this->prototype() == obj) {
7209     return true;
7210   }
7211 
7212   // Check if the object is among the named properties.
7213   Object* key = SlowReverseLookup(obj);
7214   if (!key->IsUndefined(heap->isolate())) {
7215     return true;
7216   }
7217 
7218   // Check if the object is among the indexed properties.
7219   ElementsKind kind = GetElementsKind();
7220   switch (kind) {
7221     // Raw pixels and external arrays do not reference other
7222     // objects.
7223 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                        \
7224     case TYPE##_ELEMENTS:                                                      \
7225       break;
7226 
7227     TYPED_ARRAYS(TYPED_ARRAY_CASE)
7228 #undef TYPED_ARRAY_CASE
7229 
7230     case FAST_DOUBLE_ELEMENTS:
7231     case FAST_HOLEY_DOUBLE_ELEMENTS:
7232       break;
7233     case FAST_SMI_ELEMENTS:
7234     case FAST_HOLEY_SMI_ELEMENTS:
7235       break;
7236     case FAST_ELEMENTS:
7237     case FAST_HOLEY_ELEMENTS:
7238     case DICTIONARY_ELEMENTS:
7239     case FAST_STRING_WRAPPER_ELEMENTS:
7240     case SLOW_STRING_WRAPPER_ELEMENTS: {
7241       FixedArray* elements = FixedArray::cast(this->elements());
7242       if (ReferencesObjectFromElements(elements, kind, obj)) return true;
7243       break;
7244     }
7245     case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
7246     case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
7247       FixedArray* parameter_map = FixedArray::cast(elements());
7248       // Check the mapped parameters.
7249       int length = parameter_map->length();
7250       for (int i = 2; i < length; ++i) {
7251         Object* value = parameter_map->get(i);
7252         if (!value->IsTheHole(heap->isolate()) && value == obj) return true;
7253       }
7254       // Check the arguments.
7255       FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
7256       kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS :
7257           FAST_HOLEY_ELEMENTS;
7258       if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
7259       break;
7260     }
7261     case NO_ELEMENTS:
7262       break;
7263   }
7264 
7265   // For functions check the context.
7266   if (IsJSFunction()) {
7267     // Get the constructor function for arguments array.
7268     Map* arguments_map =
7269         heap->isolate()->context()->native_context()->sloppy_arguments_map();
7270     JSFunction* arguments_function =
7271         JSFunction::cast(arguments_map->GetConstructor());
7272 
7273     // Get the context and don't check if it is the native context.
7274     JSFunction* f = JSFunction::cast(this);
7275     Context* context = f->context();
7276     if (context->IsNativeContext()) {
7277       return false;
7278     }
7279 
7280     // Check the non-special context slots.
7281     for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
7282       // Only check JS objects.
7283       if (context->get(i)->IsJSObject()) {
7284         JSObject* ctxobj = JSObject::cast(context->get(i));
7285         // If it is an arguments array check the content.
7286         if (ctxobj->map()->GetConstructor() == arguments_function) {
7287           if (ctxobj->ReferencesObject(obj)) {
7288             return true;
7289           }
7290         } else if (ctxobj == obj) {
7291           return true;
7292         }
7293       }
7294     }
7295 
7296     // Check the context extension (if any) if it can have references.
7297     if (context->has_extension() && !context->IsCatchContext()) {
7298       // With harmony scoping, a JSFunction may have a script context.
7299       // TODO(mvstanton): walk into the ScopeInfo.
7300       if (context->IsScriptContext()) {
7301         return false;
7302       }
7303 
7304       return context->extension_object()->ReferencesObject(obj);
7305     }
7306   }
7307 
7308   // No references to object.
7309   return false;
7310 }
7311 
7312 
SetIntegrityLevel(Handle<JSReceiver> receiver,IntegrityLevel level,ShouldThrow should_throw)7313 Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver,
7314                                           IntegrityLevel level,
7315                                           ShouldThrow should_throw) {
7316   DCHECK(level == SEALED || level == FROZEN);
7317 
7318   if (receiver->IsJSObject()) {
7319     Handle<JSObject> object = Handle<JSObject>::cast(receiver);
7320     if (!object->HasSloppyArgumentsElements()) {  // Fast path.
7321       if (level == SEALED) {
7322         return JSObject::PreventExtensionsWithTransition<SEALED>(object,
7323                                                                  should_throw);
7324       } else {
7325         return JSObject::PreventExtensionsWithTransition<FROZEN>(object,
7326                                                                  should_throw);
7327       }
7328     }
7329   }
7330 
7331   Isolate* isolate = receiver->GetIsolate();
7332 
7333   MAYBE_RETURN(JSReceiver::PreventExtensions(receiver, should_throw),
7334                Nothing<bool>());
7335 
7336   Handle<FixedArray> keys;
7337   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7338       isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>());
7339 
7340   PropertyDescriptor no_conf;
7341   no_conf.set_configurable(false);
7342 
7343   PropertyDescriptor no_conf_no_write;
7344   no_conf_no_write.set_configurable(false);
7345   no_conf_no_write.set_writable(false);
7346 
7347   if (level == SEALED) {
7348     for (int i = 0; i < keys->length(); ++i) {
7349       Handle<Object> key(keys->get(i), isolate);
7350       MAYBE_RETURN(
7351           DefineOwnProperty(isolate, receiver, key, &no_conf, THROW_ON_ERROR),
7352           Nothing<bool>());
7353     }
7354     return Just(true);
7355   }
7356 
7357   for (int i = 0; i < keys->length(); ++i) {
7358     Handle<Object> key(keys->get(i), isolate);
7359     PropertyDescriptor current_desc;
7360     Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
7361         isolate, receiver, key, &current_desc);
7362     MAYBE_RETURN(owned, Nothing<bool>());
7363     if (owned.FromJust()) {
7364       PropertyDescriptor desc =
7365           PropertyDescriptor::IsAccessorDescriptor(&current_desc)
7366               ? no_conf
7367               : no_conf_no_write;
7368       MAYBE_RETURN(
7369           DefineOwnProperty(isolate, receiver, key, &desc, THROW_ON_ERROR),
7370           Nothing<bool>());
7371     }
7372   }
7373   return Just(true);
7374 }
7375 
7376 
TestIntegrityLevel(Handle<JSReceiver> object,IntegrityLevel level)7377 Maybe<bool> JSReceiver::TestIntegrityLevel(Handle<JSReceiver> object,
7378                                            IntegrityLevel level) {
7379   DCHECK(level == SEALED || level == FROZEN);
7380   Isolate* isolate = object->GetIsolate();
7381 
7382   Maybe<bool> extensible = JSReceiver::IsExtensible(object);
7383   MAYBE_RETURN(extensible, Nothing<bool>());
7384   if (extensible.FromJust()) return Just(false);
7385 
7386   Handle<FixedArray> keys;
7387   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7388       isolate, keys, JSReceiver::OwnPropertyKeys(object), Nothing<bool>());
7389 
7390   for (int i = 0; i < keys->length(); ++i) {
7391     Handle<Object> key(keys->get(i), isolate);
7392     PropertyDescriptor current_desc;
7393     Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
7394         isolate, object, key, &current_desc);
7395     MAYBE_RETURN(owned, Nothing<bool>());
7396     if (owned.FromJust()) {
7397       if (current_desc.configurable()) return Just(false);
7398       if (level == FROZEN &&
7399           PropertyDescriptor::IsDataDescriptor(&current_desc) &&
7400           current_desc.writable()) {
7401         return Just(false);
7402       }
7403     }
7404   }
7405   return Just(true);
7406 }
7407 
7408 
PreventExtensions(Handle<JSReceiver> object,ShouldThrow should_throw)7409 Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object,
7410                                           ShouldThrow should_throw) {
7411   if (object->IsJSProxy()) {
7412     return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object),
7413                                       should_throw);
7414   }
7415   DCHECK(object->IsJSObject());
7416   return JSObject::PreventExtensions(Handle<JSObject>::cast(object),
7417                                      should_throw);
7418 }
7419 
7420 
PreventExtensions(Handle<JSProxy> proxy,ShouldThrow should_throw)7421 Maybe<bool> JSProxy::PreventExtensions(Handle<JSProxy> proxy,
7422                                        ShouldThrow should_throw) {
7423   Isolate* isolate = proxy->GetIsolate();
7424   STACK_CHECK(isolate, Nothing<bool>());
7425   Factory* factory = isolate->factory();
7426   Handle<String> trap_name = factory->preventExtensions_string();
7427 
7428   if (proxy->IsRevoked()) {
7429     isolate->Throw(
7430         *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
7431     return Nothing<bool>();
7432   }
7433   Handle<JSReceiver> target(proxy->target(), isolate);
7434   Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
7435 
7436   Handle<Object> trap;
7437   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7438       isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
7439   if (trap->IsUndefined(isolate)) {
7440     return JSReceiver::PreventExtensions(target, should_throw);
7441   }
7442 
7443   Handle<Object> trap_result;
7444   Handle<Object> args[] = {target};
7445   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7446       isolate, trap_result,
7447       Execution::Call(isolate, trap, handler, arraysize(args), args),
7448       Nothing<bool>());
7449   if (!trap_result->BooleanValue()) {
7450     RETURN_FAILURE(
7451         isolate, should_throw,
7452         NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
7453   }
7454 
7455   // Enforce the invariant.
7456   Maybe<bool> target_result = JSReceiver::IsExtensible(target);
7457   MAYBE_RETURN(target_result, Nothing<bool>());
7458   if (target_result.FromJust()) {
7459     isolate->Throw(*factory->NewTypeError(
7460         MessageTemplate::kProxyPreventExtensionsExtensible));
7461     return Nothing<bool>();
7462   }
7463   return Just(true);
7464 }
7465 
7466 
PreventExtensions(Handle<JSObject> object,ShouldThrow should_throw)7467 Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object,
7468                                         ShouldThrow should_throw) {
7469   Isolate* isolate = object->GetIsolate();
7470 
7471   if (!object->HasSloppyArgumentsElements()) {
7472     return PreventExtensionsWithTransition<NONE>(object, should_throw);
7473   }
7474 
7475   if (object->IsAccessCheckNeeded() &&
7476       !isolate->MayAccess(handle(isolate->context()), object)) {
7477     isolate->ReportFailedAccessCheck(object);
7478     RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
7479     RETURN_FAILURE(isolate, should_throw,
7480                    NewTypeError(MessageTemplate::kNoAccess));
7481   }
7482 
7483   if (!object->map()->is_extensible()) return Just(true);
7484 
7485   if (object->IsJSGlobalProxy()) {
7486     PrototypeIterator iter(isolate, object);
7487     if (iter.IsAtEnd()) return Just(true);
7488     DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
7489     return PreventExtensions(PrototypeIterator::GetCurrent<JSObject>(iter),
7490                              should_throw);
7491   }
7492 
7493   if (!object->HasFixedTypedArrayElements()) {
7494     // If there are fast elements we normalize.
7495     Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
7496     DCHECK(object->HasDictionaryElements() ||
7497            object->HasSlowArgumentsElements());
7498 
7499     // Make sure that we never go back to fast case.
7500     object->RequireSlowElements(*dictionary);
7501   }
7502 
7503   // Do a map transition, other objects with this map may still
7504   // be extensible.
7505   // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
7506   Handle<Map> new_map = Map::Copy(handle(object->map()), "PreventExtensions");
7507 
7508   new_map->set_is_extensible(false);
7509   JSObject::MigrateToMap(object, new_map);
7510   DCHECK(!object->map()->is_extensible());
7511 
7512   return Just(true);
7513 }
7514 
7515 
IsExtensible(Handle<JSReceiver> object)7516 Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) {
7517   if (object->IsJSProxy()) {
7518     return JSProxy::IsExtensible(Handle<JSProxy>::cast(object));
7519   }
7520   return Just(JSObject::IsExtensible(Handle<JSObject>::cast(object)));
7521 }
7522 
7523 
IsExtensible(Handle<JSProxy> proxy)7524 Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) {
7525   Isolate* isolate = proxy->GetIsolate();
7526   STACK_CHECK(isolate, Nothing<bool>());
7527   Factory* factory = isolate->factory();
7528   Handle<String> trap_name = factory->isExtensible_string();
7529 
7530   if (proxy->IsRevoked()) {
7531     isolate->Throw(
7532         *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
7533     return Nothing<bool>();
7534   }
7535   Handle<JSReceiver> target(proxy->target(), isolate);
7536   Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
7537 
7538   Handle<Object> trap;
7539   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7540       isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
7541   if (trap->IsUndefined(isolate)) {
7542     return JSReceiver::IsExtensible(target);
7543   }
7544 
7545   Handle<Object> trap_result;
7546   Handle<Object> args[] = {target};
7547   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7548       isolate, trap_result,
7549       Execution::Call(isolate, trap, handler, arraysize(args), args),
7550       Nothing<bool>());
7551 
7552   // Enforce the invariant.
7553   Maybe<bool> target_result = JSReceiver::IsExtensible(target);
7554   MAYBE_RETURN(target_result, Nothing<bool>());
7555   if (target_result.FromJust() != trap_result->BooleanValue()) {
7556     isolate->Throw(
7557         *factory->NewTypeError(MessageTemplate::kProxyIsExtensibleInconsistent,
7558                                factory->ToBoolean(target_result.FromJust())));
7559     return Nothing<bool>();
7560   }
7561   return target_result;
7562 }
7563 
7564 
IsExtensible(Handle<JSObject> object)7565 bool JSObject::IsExtensible(Handle<JSObject> object) {
7566   Isolate* isolate = object->GetIsolate();
7567   if (object->IsAccessCheckNeeded() &&
7568       !isolate->MayAccess(handle(isolate->context()), object)) {
7569     return true;
7570   }
7571   if (object->IsJSGlobalProxy()) {
7572     PrototypeIterator iter(isolate, *object);
7573     if (iter.IsAtEnd()) return false;
7574     DCHECK(iter.GetCurrent()->IsJSGlobalObject());
7575     return iter.GetCurrent<JSObject>()->map()->is_extensible();
7576   }
7577   return object->map()->is_extensible();
7578 }
7579 
7580 namespace {
7581 
7582 template <typename Dictionary>
DictionaryDetailsAtPut(Isolate * isolate,Handle<Dictionary> dictionary,int entry,PropertyDetails details)7583 void DictionaryDetailsAtPut(Isolate* isolate, Handle<Dictionary> dictionary,
7584                             int entry, PropertyDetails details) {
7585   dictionary->DetailsAtPut(entry, details);
7586 }
7587 
7588 template <>
DictionaryDetailsAtPut(Isolate * isolate,Handle<GlobalDictionary> dictionary,int entry,PropertyDetails details)7589 void DictionaryDetailsAtPut<GlobalDictionary>(
7590     Isolate* isolate, Handle<GlobalDictionary> dictionary, int entry,
7591     PropertyDetails details) {
7592   Object* value = dictionary->ValueAt(entry);
7593   DCHECK(value->IsPropertyCell());
7594   value = PropertyCell::cast(value)->value();
7595   if (value->IsTheHole(isolate)) return;
7596   PropertyCell::PrepareForValue(dictionary, entry, handle(value, isolate),
7597                                 details);
7598 }
7599 
7600 template <typename Dictionary>
ApplyAttributesToDictionary(Isolate * isolate,Handle<Dictionary> dictionary,const PropertyAttributes attributes)7601 void ApplyAttributesToDictionary(Isolate* isolate,
7602                                  Handle<Dictionary> dictionary,
7603                                  const PropertyAttributes attributes) {
7604   int capacity = dictionary->Capacity();
7605   for (int i = 0; i < capacity; i++) {
7606     Object* k = dictionary->KeyAt(i);
7607     if (dictionary->IsKey(isolate, k) &&
7608         !(k->IsSymbol() && Symbol::cast(k)->is_private())) {
7609       PropertyDetails details = dictionary->DetailsAt(i);
7610       int attrs = attributes;
7611       // READ_ONLY is an invalid attribute for JS setters/getters.
7612       if ((attributes & READ_ONLY) && details.kind() == kAccessor) {
7613         Object* v = dictionary->ValueAt(i);
7614         if (v->IsPropertyCell()) v = PropertyCell::cast(v)->value();
7615         if (v->IsAccessorPair()) attrs &= ~READ_ONLY;
7616       }
7617       details = details.CopyAddAttributes(
7618           static_cast<PropertyAttributes>(attrs));
7619       DictionaryDetailsAtPut<Dictionary>(isolate, dictionary, i, details);
7620     }
7621   }
7622 }
7623 
7624 }  // namespace
7625 
7626 template <PropertyAttributes attrs>
PreventExtensionsWithTransition(Handle<JSObject> object,ShouldThrow should_throw)7627 Maybe<bool> JSObject::PreventExtensionsWithTransition(
7628     Handle<JSObject> object, ShouldThrow should_throw) {
7629   STATIC_ASSERT(attrs == NONE || attrs == SEALED || attrs == FROZEN);
7630 
7631   // Sealing/freezing sloppy arguments should be handled elsewhere.
7632   DCHECK(!object->HasSloppyArgumentsElements());
7633 
7634   Isolate* isolate = object->GetIsolate();
7635   if (object->IsAccessCheckNeeded() &&
7636       !isolate->MayAccess(handle(isolate->context()), object)) {
7637     isolate->ReportFailedAccessCheck(object);
7638     RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
7639     RETURN_FAILURE(isolate, should_throw,
7640                    NewTypeError(MessageTemplate::kNoAccess));
7641   }
7642 
7643   if (attrs == NONE && !object->map()->is_extensible()) return Just(true);
7644 
7645   if (object->IsJSGlobalProxy()) {
7646     PrototypeIterator iter(isolate, object);
7647     if (iter.IsAtEnd()) return Just(true);
7648     DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
7649     return PreventExtensionsWithTransition<attrs>(
7650         PrototypeIterator::GetCurrent<JSObject>(iter), should_throw);
7651   }
7652 
7653   Handle<SeededNumberDictionary> new_element_dictionary;
7654   if (!object->HasFixedTypedArrayElements() &&
7655       !object->HasDictionaryElements() &&
7656       !object->HasSlowStringWrapperElements()) {
7657     int length =
7658         object->IsJSArray()
7659             ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
7660             : object->elements()->length();
7661     new_element_dictionary =
7662         length == 0 ? isolate->factory()->empty_slow_element_dictionary()
7663                     : object->GetElementsAccessor()->Normalize(object);
7664   }
7665 
7666   Handle<Symbol> transition_marker;
7667   if (attrs == NONE) {
7668     transition_marker = isolate->factory()->nonextensible_symbol();
7669   } else if (attrs == SEALED) {
7670     transition_marker = isolate->factory()->sealed_symbol();
7671   } else {
7672     DCHECK(attrs == FROZEN);
7673     transition_marker = isolate->factory()->frozen_symbol();
7674   }
7675 
7676   Handle<Map> old_map(object->map(), isolate);
7677   Map* transition =
7678       TransitionArray::SearchSpecial(*old_map, *transition_marker);
7679   if (transition != NULL) {
7680     Handle<Map> transition_map(transition, isolate);
7681     DCHECK(transition_map->has_dictionary_elements() ||
7682            transition_map->has_fixed_typed_array_elements() ||
7683            transition_map->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
7684     DCHECK(!transition_map->is_extensible());
7685     JSObject::MigrateToMap(object, transition_map);
7686   } else if (TransitionArray::CanHaveMoreTransitions(old_map)) {
7687     // Create a new descriptor array with the appropriate property attributes
7688     Handle<Map> new_map = Map::CopyForPreventExtensions(
7689         old_map, attrs, transition_marker, "CopyForPreventExtensions");
7690     JSObject::MigrateToMap(object, new_map);
7691   } else {
7692     DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map());
7693     // Slow path: need to normalize properties for safety
7694     NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0,
7695                         "SlowPreventExtensions");
7696 
7697     // Create a new map, since other objects with this map may be extensible.
7698     // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
7699     Handle<Map> new_map =
7700         Map::Copy(handle(object->map()), "SlowCopyForPreventExtensions");
7701     new_map->set_is_extensible(false);
7702     if (!new_element_dictionary.is_null()) {
7703       ElementsKind new_kind =
7704           IsStringWrapperElementsKind(old_map->elements_kind())
7705               ? SLOW_STRING_WRAPPER_ELEMENTS
7706               : DICTIONARY_ELEMENTS;
7707       new_map->set_elements_kind(new_kind);
7708     }
7709     JSObject::MigrateToMap(object, new_map);
7710 
7711     if (attrs != NONE) {
7712       if (object->IsJSGlobalObject()) {
7713         Handle<GlobalDictionary> dictionary(object->global_dictionary(),
7714                                             isolate);
7715         ApplyAttributesToDictionary(isolate, dictionary, attrs);
7716       } else {
7717         Handle<NameDictionary> dictionary(object->property_dictionary(),
7718                                           isolate);
7719         ApplyAttributesToDictionary(isolate, dictionary, attrs);
7720       }
7721     }
7722   }
7723 
7724   // Both seal and preventExtensions always go through without modifications to
7725   // typed array elements. Freeze works only if there are no actual elements.
7726   if (object->HasFixedTypedArrayElements()) {
7727     if (attrs == FROZEN &&
7728         JSArrayBufferView::cast(*object)->byte_length()->Number() > 0) {
7729       isolate->Throw(*isolate->factory()->NewTypeError(
7730           MessageTemplate::kCannotFreezeArrayBufferView));
7731       return Nothing<bool>();
7732     }
7733     return Just(true);
7734   }
7735 
7736   DCHECK(object->map()->has_dictionary_elements() ||
7737          object->map()->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
7738   if (!new_element_dictionary.is_null()) {
7739     object->set_elements(*new_element_dictionary);
7740   }
7741 
7742   if (object->elements() != isolate->heap()->empty_slow_element_dictionary()) {
7743     Handle<SeededNumberDictionary> dictionary(object->element_dictionary(),
7744                                               isolate);
7745     // Make sure we never go back to the fast case
7746     object->RequireSlowElements(*dictionary);
7747     if (attrs != NONE) {
7748       ApplyAttributesToDictionary(isolate, dictionary, attrs);
7749     }
7750   }
7751 
7752   return Just(true);
7753 }
7754 
7755 
FastPropertyAt(Handle<JSObject> object,Representation representation,FieldIndex index)7756 Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object,
7757                                         Representation representation,
7758                                         FieldIndex index) {
7759   Isolate* isolate = object->GetIsolate();
7760   if (object->IsUnboxedDoubleField(index)) {
7761     double value = object->RawFastDoublePropertyAt(index);
7762     return isolate->factory()->NewHeapNumber(value);
7763   }
7764   Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate);
7765   return Object::WrapForRead(isolate, raw_value, representation);
7766 }
7767 
7768 template <class ContextObject>
7769 class JSObjectWalkVisitor {
7770  public:
JSObjectWalkVisitor(ContextObject * site_context,bool copying,JSObject::DeepCopyHints hints)7771   JSObjectWalkVisitor(ContextObject* site_context, bool copying,
7772                       JSObject::DeepCopyHints hints)
7773     : site_context_(site_context),
7774       copying_(copying),
7775       hints_(hints) {}
7776 
7777   MUST_USE_RESULT MaybeHandle<JSObject> StructureWalk(Handle<JSObject> object);
7778 
7779  protected:
VisitElementOrProperty(Handle<JSObject> object,Handle<JSObject> value)7780   MUST_USE_RESULT inline MaybeHandle<JSObject> VisitElementOrProperty(
7781       Handle<JSObject> object,
7782       Handle<JSObject> value) {
7783     Handle<AllocationSite> current_site = site_context()->EnterNewScope();
7784     MaybeHandle<JSObject> copy_of_value = StructureWalk(value);
7785     site_context()->ExitScope(current_site, value);
7786     return copy_of_value;
7787   }
7788 
site_context()7789   inline ContextObject* site_context() { return site_context_; }
isolate()7790   inline Isolate* isolate() { return site_context()->isolate(); }
7791 
copying() const7792   inline bool copying() const { return copying_; }
7793 
7794  private:
7795   ContextObject* site_context_;
7796   const bool copying_;
7797   const JSObject::DeepCopyHints hints_;
7798 };
7799 
7800 template <class ContextObject>
StructureWalk(Handle<JSObject> object)7801 MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
7802     Handle<JSObject> object) {
7803   Isolate* isolate = this->isolate();
7804   bool copying = this->copying();
7805   bool shallow = hints_ == JSObject::kObjectIsShallow;
7806 
7807   if (!shallow) {
7808     StackLimitCheck check(isolate);
7809 
7810     if (check.HasOverflowed()) {
7811       isolate->StackOverflow();
7812       return MaybeHandle<JSObject>();
7813     }
7814   }
7815 
7816   if (object->map()->is_deprecated()) {
7817     JSObject::MigrateInstance(object);
7818   }
7819 
7820   Handle<JSObject> copy;
7821   if (copying) {
7822     // JSFunction objects are not allowed to be in normal boilerplates at all.
7823     DCHECK(!object->IsJSFunction());
7824     Handle<AllocationSite> site_to_pass;
7825     if (site_context()->ShouldCreateMemento(object)) {
7826       site_to_pass = site_context()->current();
7827     }
7828     copy = isolate->factory()->CopyJSObjectWithAllocationSite(
7829         object, site_to_pass);
7830   } else {
7831     copy = object;
7832   }
7833 
7834   DCHECK(copying || copy.is_identical_to(object));
7835 
7836   ElementsKind kind = copy->GetElementsKind();
7837   if (copying && IsFastSmiOrObjectElementsKind(kind) &&
7838       FixedArray::cast(copy->elements())->map() ==
7839         isolate->heap()->fixed_cow_array_map()) {
7840     isolate->counters()->cow_arrays_created_runtime()->Increment();
7841   }
7842 
7843   if (!shallow) {
7844     HandleScope scope(isolate);
7845 
7846     // Deep copy own properties.
7847     if (copy->HasFastProperties()) {
7848       Handle<DescriptorArray> descriptors(copy->map()->instance_descriptors());
7849       int limit = copy->map()->NumberOfOwnDescriptors();
7850       for (int i = 0; i < limit; i++) {
7851         PropertyDetails details = descriptors->GetDetails(i);
7852         if (details.location() != kField) continue;
7853         DCHECK_EQ(kData, details.kind());
7854         FieldIndex index = FieldIndex::ForDescriptor(copy->map(), i);
7855         if (object->IsUnboxedDoubleField(index)) {
7856           if (copying) {
7857             // Ensure that all bits of the double value are preserved.
7858             uint64_t value = object->RawFastDoublePropertyAsBitsAt(index);
7859             copy->RawFastDoublePropertyAsBitsAtPut(index, value);
7860           }
7861         } else {
7862           Handle<Object> value(object->RawFastPropertyAt(index), isolate);
7863           if (value->IsJSObject()) {
7864             ASSIGN_RETURN_ON_EXCEPTION(
7865                 isolate, value,
7866                 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
7867                 JSObject);
7868             if (copying) {
7869               copy->FastPropertyAtPut(index, *value);
7870             }
7871           } else {
7872             if (copying) {
7873               Representation representation = details.representation();
7874               value = Object::NewStorageFor(isolate, value, representation);
7875               copy->FastPropertyAtPut(index, *value);
7876             }
7877           }
7878         }
7879       }
7880     } else {
7881       // Only deep copy fields from the object literal expression.
7882       // In particular, don't try to copy the length attribute of
7883       // an array.
7884       PropertyFilter filter = static_cast<PropertyFilter>(
7885           ONLY_WRITABLE | ONLY_ENUMERABLE | ONLY_CONFIGURABLE);
7886       KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly, filter);
7887       accumulator.CollectOwnPropertyNames(copy, copy);
7888       Handle<FixedArray> names = accumulator.GetKeys();
7889       for (int i = 0; i < names->length(); i++) {
7890         DCHECK(names->get(i)->IsName());
7891         Handle<Name> name(Name::cast(names->get(i)));
7892         Handle<Object> value =
7893             JSObject::GetProperty(copy, name).ToHandleChecked();
7894         if (value->IsJSObject()) {
7895           Handle<JSObject> result;
7896           ASSIGN_RETURN_ON_EXCEPTION(
7897               isolate, result,
7898               VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
7899               JSObject);
7900           if (copying) {
7901             // Creating object copy for literals. No strict mode needed.
7902             JSObject::SetProperty(copy, name, result, SLOPPY).Assert();
7903           }
7904         }
7905       }
7906     }
7907 
7908     // Deep copy own elements.
7909     switch (kind) {
7910       case FAST_ELEMENTS:
7911       case FAST_HOLEY_ELEMENTS: {
7912         Handle<FixedArray> elements(FixedArray::cast(copy->elements()));
7913         if (elements->map() == isolate->heap()->fixed_cow_array_map()) {
7914 #ifdef DEBUG
7915           for (int i = 0; i < elements->length(); i++) {
7916             DCHECK(!elements->get(i)->IsJSObject());
7917           }
7918 #endif
7919         } else {
7920           for (int i = 0; i < elements->length(); i++) {
7921             Handle<Object> value(elements->get(i), isolate);
7922             if (value->IsJSObject()) {
7923               Handle<JSObject> result;
7924               ASSIGN_RETURN_ON_EXCEPTION(
7925                   isolate, result,
7926                   VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
7927                   JSObject);
7928               if (copying) {
7929                 elements->set(i, *result);
7930               }
7931             }
7932           }
7933         }
7934         break;
7935       }
7936       case DICTIONARY_ELEMENTS: {
7937         Handle<SeededNumberDictionary> element_dictionary(
7938             copy->element_dictionary());
7939         int capacity = element_dictionary->Capacity();
7940         for (int i = 0; i < capacity; i++) {
7941           Object* k = element_dictionary->KeyAt(i);
7942           if (element_dictionary->IsKey(isolate, k)) {
7943             Handle<Object> value(element_dictionary->ValueAt(i), isolate);
7944             if (value->IsJSObject()) {
7945               Handle<JSObject> result;
7946               ASSIGN_RETURN_ON_EXCEPTION(
7947                   isolate, result,
7948                   VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
7949                   JSObject);
7950               if (copying) {
7951                 element_dictionary->ValueAtPut(i, *result);
7952               }
7953             }
7954           }
7955         }
7956         break;
7957       }
7958       case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
7959       case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
7960         UNIMPLEMENTED();
7961         break;
7962       case FAST_STRING_WRAPPER_ELEMENTS:
7963       case SLOW_STRING_WRAPPER_ELEMENTS:
7964         UNREACHABLE();
7965         break;
7966 
7967 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                        \
7968       case TYPE##_ELEMENTS:                                                    \
7969 
7970       TYPED_ARRAYS(TYPED_ARRAY_CASE)
7971 #undef TYPED_ARRAY_CASE
7972       // Typed elements cannot be created using an object literal.
7973       UNREACHABLE();
7974       break;
7975 
7976       case FAST_SMI_ELEMENTS:
7977       case FAST_HOLEY_SMI_ELEMENTS:
7978       case FAST_DOUBLE_ELEMENTS:
7979       case FAST_HOLEY_DOUBLE_ELEMENTS:
7980       case NO_ELEMENTS:
7981         // No contained objects, nothing to do.
7982         break;
7983     }
7984   }
7985 
7986   return copy;
7987 }
7988 
7989 
DeepWalk(Handle<JSObject> object,AllocationSiteCreationContext * site_context)7990 MaybeHandle<JSObject> JSObject::DeepWalk(
7991     Handle<JSObject> object,
7992     AllocationSiteCreationContext* site_context) {
7993   JSObjectWalkVisitor<AllocationSiteCreationContext> v(site_context, false,
7994                                                        kNoHints);
7995   MaybeHandle<JSObject> result = v.StructureWalk(object);
7996   Handle<JSObject> for_assert;
7997   DCHECK(!result.ToHandle(&for_assert) || for_assert.is_identical_to(object));
7998   return result;
7999 }
8000 
8001 
DeepCopy(Handle<JSObject> object,AllocationSiteUsageContext * site_context,DeepCopyHints hints)8002 MaybeHandle<JSObject> JSObject::DeepCopy(
8003     Handle<JSObject> object,
8004     AllocationSiteUsageContext* site_context,
8005     DeepCopyHints hints) {
8006   JSObjectWalkVisitor<AllocationSiteUsageContext> v(site_context, true, hints);
8007   MaybeHandle<JSObject> copy = v.StructureWalk(object);
8008   Handle<JSObject> for_assert;
8009   DCHECK(!copy.ToHandle(&for_assert) || !for_assert.is_identical_to(object));
8010   return copy;
8011 }
8012 
8013 // static
ToPrimitive(Handle<JSReceiver> receiver,ToPrimitiveHint hint)8014 MaybeHandle<Object> JSReceiver::ToPrimitive(Handle<JSReceiver> receiver,
8015                                             ToPrimitiveHint hint) {
8016   Isolate* const isolate = receiver->GetIsolate();
8017   Handle<Object> exotic_to_prim;
8018   ASSIGN_RETURN_ON_EXCEPTION(
8019       isolate, exotic_to_prim,
8020       GetMethod(receiver, isolate->factory()->to_primitive_symbol()), Object);
8021   if (!exotic_to_prim->IsUndefined(isolate)) {
8022     Handle<Object> hint_string =
8023         isolate->factory()->ToPrimitiveHintString(hint);
8024     Handle<Object> result;
8025     ASSIGN_RETURN_ON_EXCEPTION(
8026         isolate, result,
8027         Execution::Call(isolate, exotic_to_prim, receiver, 1, &hint_string),
8028         Object);
8029     if (result->IsPrimitive()) return result;
8030     THROW_NEW_ERROR(isolate,
8031                     NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8032                     Object);
8033   }
8034   return OrdinaryToPrimitive(receiver, (hint == ToPrimitiveHint::kString)
8035                                            ? OrdinaryToPrimitiveHint::kString
8036                                            : OrdinaryToPrimitiveHint::kNumber);
8037 }
8038 
8039 
8040 // static
OrdinaryToPrimitive(Handle<JSReceiver> receiver,OrdinaryToPrimitiveHint hint)8041 MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive(
8042     Handle<JSReceiver> receiver, OrdinaryToPrimitiveHint hint) {
8043   Isolate* const isolate = receiver->GetIsolate();
8044   Handle<String> method_names[2];
8045   switch (hint) {
8046     case OrdinaryToPrimitiveHint::kNumber:
8047       method_names[0] = isolate->factory()->valueOf_string();
8048       method_names[1] = isolate->factory()->toString_string();
8049       break;
8050     case OrdinaryToPrimitiveHint::kString:
8051       method_names[0] = isolate->factory()->toString_string();
8052       method_names[1] = isolate->factory()->valueOf_string();
8053       break;
8054   }
8055   for (Handle<String> name : method_names) {
8056     Handle<Object> method;
8057     ASSIGN_RETURN_ON_EXCEPTION(isolate, method,
8058                                JSReceiver::GetProperty(receiver, name), Object);
8059     if (method->IsCallable()) {
8060       Handle<Object> result;
8061       ASSIGN_RETURN_ON_EXCEPTION(
8062           isolate, result, Execution::Call(isolate, method, receiver, 0, NULL),
8063           Object);
8064       if (result->IsPrimitive()) return result;
8065     }
8066   }
8067   THROW_NEW_ERROR(isolate,
8068                   NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8069                   Object);
8070 }
8071 
8072 
8073 // TODO(cbruni/jkummerow): Consider moving this into elements.cc.
HasEnumerableElements()8074 bool JSObject::HasEnumerableElements() {
8075   // TODO(cbruni): cleanup
8076   JSObject* object = this;
8077   switch (object->GetElementsKind()) {
8078     case FAST_SMI_ELEMENTS:
8079     case FAST_ELEMENTS:
8080     case FAST_DOUBLE_ELEMENTS: {
8081       int length = object->IsJSArray()
8082                        ? Smi::cast(JSArray::cast(object)->length())->value()
8083                        : object->elements()->length();
8084       return length > 0;
8085     }
8086     case FAST_HOLEY_SMI_ELEMENTS:
8087     case FAST_HOLEY_ELEMENTS: {
8088       FixedArray* elements = FixedArray::cast(object->elements());
8089       int length = object->IsJSArray()
8090                        ? Smi::cast(JSArray::cast(object)->length())->value()
8091                        : elements->length();
8092       Isolate* isolate = GetIsolate();
8093       for (int i = 0; i < length; i++) {
8094         if (!elements->is_the_hole(isolate, i)) return true;
8095       }
8096       return false;
8097     }
8098     case FAST_HOLEY_DOUBLE_ELEMENTS: {
8099       int length = object->IsJSArray()
8100                        ? Smi::cast(JSArray::cast(object)->length())->value()
8101                        : object->elements()->length();
8102       // Zero-length arrays would use the empty FixedArray...
8103       if (length == 0) return false;
8104       // ...so only cast to FixedDoubleArray otherwise.
8105       FixedDoubleArray* elements = FixedDoubleArray::cast(object->elements());
8106       for (int i = 0; i < length; i++) {
8107         if (!elements->is_the_hole(i)) return true;
8108       }
8109       return false;
8110     }
8111 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
8112     case TYPE##_ELEMENTS:
8113 
8114       TYPED_ARRAYS(TYPED_ARRAY_CASE)
8115 #undef TYPED_ARRAY_CASE
8116       {
8117         int length = object->elements()->length();
8118         return length > 0;
8119       }
8120     case DICTIONARY_ELEMENTS: {
8121       SeededNumberDictionary* elements =
8122           SeededNumberDictionary::cast(object->elements());
8123       return elements->NumberOfElementsFilterAttributes(ONLY_ENUMERABLE) > 0;
8124     }
8125     case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
8126     case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
8127       // We're approximating non-empty arguments objects here.
8128       return true;
8129     case FAST_STRING_WRAPPER_ELEMENTS:
8130     case SLOW_STRING_WRAPPER_ELEMENTS:
8131       if (String::cast(JSValue::cast(object)->value())->length() > 0) {
8132         return true;
8133       }
8134       return object->elements()->length() > 0;
8135     case NO_ELEMENTS:
8136       return false;
8137   }
8138   UNREACHABLE();
8139   return true;
8140 }
8141 
8142 
NumberOfDescribedProperties(DescriptorFlag which,PropertyFilter filter)8143 int Map::NumberOfDescribedProperties(DescriptorFlag which,
8144                                      PropertyFilter filter) {
8145   int result = 0;
8146   DescriptorArray* descs = instance_descriptors();
8147   int limit = which == ALL_DESCRIPTORS
8148       ? descs->number_of_descriptors()
8149       : NumberOfOwnDescriptors();
8150   for (int i = 0; i < limit; i++) {
8151     if ((descs->GetDetails(i).attributes() & filter) == 0 &&
8152         !descs->GetKey(i)->FilterKey(filter)) {
8153       result++;
8154     }
8155   }
8156   return result;
8157 }
8158 
8159 
NextFreePropertyIndex()8160 int Map::NextFreePropertyIndex() {
8161   int free_index = 0;
8162   int number_of_own_descriptors = NumberOfOwnDescriptors();
8163   DescriptorArray* descs = instance_descriptors();
8164   for (int i = 0; i < number_of_own_descriptors; i++) {
8165     PropertyDetails details = descs->GetDetails(i);
8166     if (details.location() == kField) {
8167       int candidate = details.field_index() + details.field_width_in_words();
8168       if (candidate > free_index) free_index = candidate;
8169     }
8170   }
8171   return free_index;
8172 }
8173 
8174 
OnlyHasSimpleProperties()8175 bool Map::OnlyHasSimpleProperties() {
8176   // Wrapped string elements aren't explicitly stored in the elements backing
8177   // store, but are loaded indirectly from the underlying string.
8178   return !IsStringWrapperElementsKind(elements_kind()) &&
8179          !IsSpecialReceiverMap() && !has_hidden_prototype() &&
8180          !is_dictionary_map();
8181 }
8182 
FastGetOwnValuesOrEntries(Isolate * isolate,Handle<JSReceiver> receiver,bool get_entries,Handle<FixedArray> * result)8183 MUST_USE_RESULT Maybe<bool> FastGetOwnValuesOrEntries(
8184     Isolate* isolate, Handle<JSReceiver> receiver, bool get_entries,
8185     Handle<FixedArray>* result) {
8186   Handle<Map> map(JSReceiver::cast(*receiver)->map(), isolate);
8187 
8188   if (!map->IsJSObjectMap()) return Just(false);
8189   if (!map->OnlyHasSimpleProperties()) return Just(false);
8190 
8191   Handle<JSObject> object(JSObject::cast(*receiver));
8192 
8193   Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
8194   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
8195   int number_of_own_elements =
8196       object->GetElementsAccessor()->GetCapacity(*object, object->elements());
8197   Handle<FixedArray> values_or_entries = isolate->factory()->NewFixedArray(
8198       number_of_own_descriptors + number_of_own_elements);
8199   int count = 0;
8200 
8201   if (object->elements() != isolate->heap()->empty_fixed_array()) {
8202     MAYBE_RETURN(object->GetElementsAccessor()->CollectValuesOrEntries(
8203                      isolate, object, values_or_entries, get_entries, &count,
8204                      ENUMERABLE_STRINGS),
8205                  Nothing<bool>());
8206   }
8207 
8208   bool stable = object->map() == *map;
8209 
8210   for (int index = 0; index < number_of_own_descriptors; index++) {
8211     Handle<Name> next_key(descriptors->GetKey(index), isolate);
8212     if (!next_key->IsString()) continue;
8213     Handle<Object> prop_value;
8214 
8215     // Directly decode from the descriptor array if |from| did not change shape.
8216     if (stable) {
8217       PropertyDetails details = descriptors->GetDetails(index);
8218       if (!details.IsEnumerable()) continue;
8219       if (details.kind() == kData) {
8220         if (details.location() == kDescriptor) {
8221           prop_value = handle(descriptors->GetValue(index), isolate);
8222         } else {
8223           Representation representation = details.representation();
8224           FieldIndex field_index = FieldIndex::ForDescriptor(*map, index);
8225           prop_value =
8226               JSObject::FastPropertyAt(object, representation, field_index);
8227         }
8228       } else {
8229         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8230             isolate, prop_value, JSReceiver::GetProperty(object, next_key),
8231             Nothing<bool>());
8232         stable = object->map() == *map;
8233       }
8234     } else {
8235       // If the map did change, do a slower lookup. We are still guaranteed that
8236       // the object has a simple shape, and that the key is a name.
8237       LookupIterator it(object, next_key, LookupIterator::OWN_SKIP_INTERCEPTOR);
8238       if (!it.IsFound()) continue;
8239       DCHECK(it.state() == LookupIterator::DATA ||
8240              it.state() == LookupIterator::ACCESSOR);
8241       if (!it.IsEnumerable()) continue;
8242       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8243           isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
8244     }
8245 
8246     if (get_entries) {
8247       prop_value = MakeEntryPair(isolate, next_key, prop_value);
8248     }
8249 
8250     values_or_entries->set(count, *prop_value);
8251     count++;
8252   }
8253 
8254   if (count < values_or_entries->length()) values_or_entries->Shrink(count);
8255   *result = values_or_entries;
8256   return Just(true);
8257 }
8258 
GetOwnValuesOrEntries(Isolate * isolate,Handle<JSReceiver> object,PropertyFilter filter,bool get_entries)8259 MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate,
8260                                               Handle<JSReceiver> object,
8261                                               PropertyFilter filter,
8262                                               bool get_entries) {
8263   Handle<FixedArray> values_or_entries;
8264   if (filter == ENUMERABLE_STRINGS) {
8265     Maybe<bool> fast_values_or_entries = FastGetOwnValuesOrEntries(
8266         isolate, object, get_entries, &values_or_entries);
8267     if (fast_values_or_entries.IsNothing()) return MaybeHandle<FixedArray>();
8268     if (fast_values_or_entries.FromJust()) return values_or_entries;
8269   }
8270 
8271   PropertyFilter key_filter =
8272       static_cast<PropertyFilter>(filter & ~ONLY_ENUMERABLE);
8273 
8274   Handle<FixedArray> keys;
8275   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8276       isolate, keys,
8277       KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, key_filter,
8278                               GetKeysConversion::kConvertToString),
8279       MaybeHandle<FixedArray>());
8280 
8281   values_or_entries = isolate->factory()->NewFixedArray(keys->length());
8282   int length = 0;
8283 
8284   for (int i = 0; i < keys->length(); ++i) {
8285     Handle<Name> key = Handle<Name>::cast(handle(keys->get(i), isolate));
8286 
8287     if (filter & ONLY_ENUMERABLE) {
8288       PropertyDescriptor descriptor;
8289       Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor(
8290           isolate, object, key, &descriptor);
8291       MAYBE_RETURN(did_get_descriptor, MaybeHandle<FixedArray>());
8292       if (!did_get_descriptor.FromJust() || !descriptor.enumerable()) continue;
8293     }
8294 
8295     Handle<Object> value;
8296     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8297         isolate, value, JSReceiver::GetPropertyOrElement(object, key),
8298         MaybeHandle<FixedArray>());
8299 
8300     if (get_entries) {
8301       Handle<FixedArray> entry_storage =
8302           isolate->factory()->NewUninitializedFixedArray(2);
8303       entry_storage->set(0, *key);
8304       entry_storage->set(1, *value);
8305       value = isolate->factory()->NewJSArrayWithElements(entry_storage,
8306                                                          FAST_ELEMENTS, 2);
8307     }
8308 
8309     values_or_entries->set(length, *value);
8310     length++;
8311   }
8312   if (length < values_or_entries->length()) values_or_entries->Shrink(length);
8313   return values_or_entries;
8314 }
8315 
GetOwnValues(Handle<JSReceiver> object,PropertyFilter filter)8316 MaybeHandle<FixedArray> JSReceiver::GetOwnValues(Handle<JSReceiver> object,
8317                                                  PropertyFilter filter) {
8318   return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, false);
8319 }
8320 
GetOwnEntries(Handle<JSReceiver> object,PropertyFilter filter)8321 MaybeHandle<FixedArray> JSReceiver::GetOwnEntries(Handle<JSReceiver> object,
8322                                                   PropertyFilter filter) {
8323   return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, true);
8324 }
8325 
DictionaryElementsInPrototypeChainOnly()8326 bool Map::DictionaryElementsInPrototypeChainOnly() {
8327   if (IsDictionaryElementsKind(elements_kind())) {
8328     return false;
8329   }
8330 
8331   for (PrototypeIterator iter(this); !iter.IsAtEnd(); iter.Advance()) {
8332     // Be conservative, don't walk into proxies.
8333     if (iter.GetCurrent()->IsJSProxy()) return true;
8334     // String wrappers have non-configurable, non-writable elements.
8335     if (iter.GetCurrent()->IsStringWrapper()) return true;
8336     JSObject* current = iter.GetCurrent<JSObject>();
8337 
8338     if (current->HasDictionaryElements() &&
8339         current->element_dictionary()->requires_slow_elements()) {
8340       return true;
8341     }
8342 
8343     if (current->HasSlowArgumentsElements()) {
8344       FixedArray* parameter_map = FixedArray::cast(current->elements());
8345       Object* arguments = parameter_map->get(1);
8346       if (SeededNumberDictionary::cast(arguments)->requires_slow_elements()) {
8347         return true;
8348       }
8349     }
8350   }
8351 
8352   return false;
8353 }
8354 
8355 
DefineAccessor(Handle<JSObject> object,Handle<Name> name,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)8356 MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
8357                                              Handle<Name> name,
8358                                              Handle<Object> getter,
8359                                              Handle<Object> setter,
8360                                              PropertyAttributes attributes) {
8361   Isolate* isolate = object->GetIsolate();
8362 
8363   LookupIterator it = LookupIterator::PropertyOrElement(
8364       isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
8365   return DefineAccessor(&it, getter, setter, attributes);
8366 }
8367 
8368 
DefineAccessor(LookupIterator * it,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)8369 MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it,
8370                                              Handle<Object> getter,
8371                                              Handle<Object> setter,
8372                                              PropertyAttributes attributes) {
8373   Isolate* isolate = it->isolate();
8374 
8375   it->UpdateProtector();
8376 
8377   if (it->state() == LookupIterator::ACCESS_CHECK) {
8378     if (!it->HasAccess()) {
8379       isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
8380       RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
8381       return isolate->factory()->undefined_value();
8382     }
8383     it->Next();
8384   }
8385 
8386   Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
8387   // Ignore accessors on typed arrays.
8388   if (it->IsElement() && object->HasFixedTypedArrayElements()) {
8389     return it->factory()->undefined_value();
8390   }
8391 
8392   DCHECK(getter->IsCallable() || getter->IsUndefined(isolate) ||
8393          getter->IsNull(isolate) || getter->IsFunctionTemplateInfo());
8394   DCHECK(setter->IsCallable() || setter->IsUndefined(isolate) ||
8395          setter->IsNull(isolate) || setter->IsFunctionTemplateInfo());
8396   it->TransitionToAccessorProperty(getter, setter, attributes);
8397 
8398   return isolate->factory()->undefined_value();
8399 }
8400 
8401 
SetAccessor(Handle<JSObject> object,Handle<AccessorInfo> info)8402 MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
8403                                           Handle<AccessorInfo> info) {
8404   Isolate* isolate = object->GetIsolate();
8405   Handle<Name> name(Name::cast(info->name()), isolate);
8406 
8407   LookupIterator it = LookupIterator::PropertyOrElement(
8408       isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
8409 
8410   // Duplicate ACCESS_CHECK outside of GetPropertyAttributes for the case that
8411   // the FailedAccessCheckCallbackFunction doesn't throw an exception.
8412   //
8413   // TODO(verwaest): Force throw an exception if the callback doesn't, so we can
8414   // remove reliance on default return values.
8415   if (it.state() == LookupIterator::ACCESS_CHECK) {
8416     if (!it.HasAccess()) {
8417       isolate->ReportFailedAccessCheck(object);
8418       RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
8419       return it.factory()->undefined_value();
8420     }
8421     it.Next();
8422   }
8423 
8424   // Ignore accessors on typed arrays.
8425   if (it.IsElement() && object->HasFixedTypedArrayElements()) {
8426     return it.factory()->undefined_value();
8427   }
8428 
8429   CHECK(GetPropertyAttributes(&it).IsJust());
8430 
8431   // ES5 forbids turning a property into an accessor if it's not
8432   // configurable. See 8.6.1 (Table 5).
8433   if (it.IsFound() && !it.IsConfigurable()) {
8434     return it.factory()->undefined_value();
8435   }
8436 
8437   it.TransitionToAccessorPair(info, info->property_attributes());
8438 
8439   return object;
8440 }
8441 
SlowReverseLookup(Object * value)8442 Object* JSObject::SlowReverseLookup(Object* value) {
8443   if (HasFastProperties()) {
8444     int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
8445     DescriptorArray* descs = map()->instance_descriptors();
8446     bool value_is_number = value->IsNumber();
8447     for (int i = 0; i < number_of_own_descriptors; i++) {
8448       PropertyDetails details = descs->GetDetails(i);
8449       if (details.location() == kField) {
8450         DCHECK_EQ(kData, details.kind());
8451         FieldIndex field_index = FieldIndex::ForDescriptor(map(), i);
8452         if (IsUnboxedDoubleField(field_index)) {
8453           if (value_is_number) {
8454             double property = RawFastDoublePropertyAt(field_index);
8455             if (property == value->Number()) {
8456               return descs->GetKey(i);
8457             }
8458           }
8459         } else {
8460           Object* property = RawFastPropertyAt(field_index);
8461           if (field_index.is_double()) {
8462             DCHECK(property->IsMutableHeapNumber());
8463             if (value_is_number && property->Number() == value->Number()) {
8464               return descs->GetKey(i);
8465             }
8466           } else if (property == value) {
8467             return descs->GetKey(i);
8468           }
8469         }
8470       } else {
8471         DCHECK_EQ(kDescriptor, details.location());
8472         if (details.kind() == kData) {
8473           if (descs->GetValue(i) == value) {
8474             return descs->GetKey(i);
8475           }
8476         }
8477       }
8478     }
8479     return GetHeap()->undefined_value();
8480   } else if (IsJSGlobalObject()) {
8481     return global_dictionary()->SlowReverseLookup(value);
8482   } else {
8483     return property_dictionary()->SlowReverseLookup(value);
8484   }
8485 }
8486 
8487 
RawCopy(Handle<Map> map,int instance_size)8488 Handle<Map> Map::RawCopy(Handle<Map> map, int instance_size) {
8489   Isolate* isolate = map->GetIsolate();
8490   Handle<Map> result =
8491       isolate->factory()->NewMap(map->instance_type(), instance_size);
8492   Handle<Object> prototype(map->prototype(), isolate);
8493   Map::SetPrototype(result, prototype);
8494   result->set_constructor_or_backpointer(map->GetConstructor());
8495   result->set_bit_field(map->bit_field());
8496   result->set_bit_field2(map->bit_field2());
8497   int new_bit_field3 = map->bit_field3();
8498   new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true);
8499   new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0);
8500   new_bit_field3 = EnumLengthBits::update(new_bit_field3,
8501                                           kInvalidEnumCacheSentinel);
8502   new_bit_field3 = Deprecated::update(new_bit_field3, false);
8503   if (!map->is_dictionary_map()) {
8504     new_bit_field3 = IsUnstable::update(new_bit_field3, false);
8505   }
8506   result->set_bit_field3(new_bit_field3);
8507   return result;
8508 }
8509 
8510 
Normalize(Handle<Map> fast_map,PropertyNormalizationMode mode,const char * reason)8511 Handle<Map> Map::Normalize(Handle<Map> fast_map, PropertyNormalizationMode mode,
8512                            const char* reason) {
8513   DCHECK(!fast_map->is_dictionary_map());
8514 
8515   Isolate* isolate = fast_map->GetIsolate();
8516   Handle<Object> maybe_cache(isolate->native_context()->normalized_map_cache(),
8517                              isolate);
8518   bool use_cache =
8519       !fast_map->is_prototype_map() && !maybe_cache->IsUndefined(isolate);
8520   Handle<NormalizedMapCache> cache;
8521   if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache);
8522 
8523   Handle<Map> new_map;
8524   if (use_cache && cache->Get(fast_map, mode).ToHandle(&new_map)) {
8525 #ifdef VERIFY_HEAP
8526     if (FLAG_verify_heap) new_map->DictionaryMapVerify();
8527 #endif
8528 #ifdef ENABLE_SLOW_DCHECKS
8529     if (FLAG_enable_slow_asserts) {
8530       // The cached map should match newly created normalized map bit-by-bit,
8531       // except for the code cache, which can contain some ics which can be
8532       // applied to the shared map, dependent code and weak cell cache.
8533       Handle<Map> fresh = Map::CopyNormalized(fast_map, mode);
8534 
8535       if (new_map->is_prototype_map()) {
8536         // For prototype maps, the PrototypeInfo is not copied.
8537         DCHECK(memcmp(fresh->address(), new_map->address(),
8538                       kTransitionsOrPrototypeInfoOffset) == 0);
8539         DCHECK(fresh->raw_transitions() == Smi::kZero);
8540         STATIC_ASSERT(kDescriptorsOffset ==
8541                       kTransitionsOrPrototypeInfoOffset + kPointerSize);
8542         DCHECK(memcmp(HeapObject::RawField(*fresh, kDescriptorsOffset),
8543                       HeapObject::RawField(*new_map, kDescriptorsOffset),
8544                       kCodeCacheOffset - kDescriptorsOffset) == 0);
8545       } else {
8546         DCHECK(memcmp(fresh->address(), new_map->address(),
8547                       Map::kCodeCacheOffset) == 0);
8548       }
8549       STATIC_ASSERT(Map::kDependentCodeOffset ==
8550                     Map::kCodeCacheOffset + kPointerSize);
8551       STATIC_ASSERT(Map::kWeakCellCacheOffset ==
8552                     Map::kDependentCodeOffset + kPointerSize);
8553       int offset = Map::kWeakCellCacheOffset + kPointerSize;
8554       DCHECK(memcmp(fresh->address() + offset,
8555                     new_map->address() + offset,
8556                     Map::kSize - offset) == 0);
8557     }
8558 #endif
8559   } else {
8560     new_map = Map::CopyNormalized(fast_map, mode);
8561     if (use_cache) {
8562       cache->Set(fast_map, new_map);
8563       isolate->counters()->maps_normalized()->Increment();
8564     }
8565 #if TRACE_MAPS
8566     if (FLAG_trace_maps) {
8567       PrintF("[TraceMaps: Normalize from= %p to= %p reason= %s ]\n",
8568              reinterpret_cast<void*>(*fast_map),
8569              reinterpret_cast<void*>(*new_map), reason);
8570     }
8571 #endif
8572   }
8573   fast_map->NotifyLeafMapLayoutChange();
8574   return new_map;
8575 }
8576 
8577 
CopyNormalized(Handle<Map> map,PropertyNormalizationMode mode)8578 Handle<Map> Map::CopyNormalized(Handle<Map> map,
8579                                 PropertyNormalizationMode mode) {
8580   int new_instance_size = map->instance_size();
8581   if (mode == CLEAR_INOBJECT_PROPERTIES) {
8582     new_instance_size -= map->GetInObjectProperties() * kPointerSize;
8583   }
8584 
8585   Handle<Map> result = RawCopy(map, new_instance_size);
8586 
8587   if (mode != CLEAR_INOBJECT_PROPERTIES) {
8588     result->SetInObjectProperties(map->GetInObjectProperties());
8589   }
8590 
8591   result->set_dictionary_map(true);
8592   result->set_migration_target(false);
8593   result->set_construction_counter(kNoSlackTracking);
8594 
8595 #ifdef VERIFY_HEAP
8596   if (FLAG_verify_heap) result->DictionaryMapVerify();
8597 #endif
8598 
8599   return result;
8600 }
8601 
8602 // Return an immutable prototype exotic object version of the input map.
8603 // Never even try to cache it in the transition tree, as it is intended
8604 // for the global object and its prototype chain, and excluding it saves
8605 // memory on the map transition tree.
8606 
8607 // static
TransitionToImmutableProto(Handle<Map> map)8608 Handle<Map> Map::TransitionToImmutableProto(Handle<Map> map) {
8609   Handle<Map> new_map = Map::Copy(map, "ImmutablePrototype");
8610   new_map->set_immutable_proto(true);
8611   return new_map;
8612 }
8613 
CopyInitialMap(Handle<Map> map,int instance_size,int in_object_properties,int unused_property_fields)8614 Handle<Map> Map::CopyInitialMap(Handle<Map> map, int instance_size,
8615                                 int in_object_properties,
8616                                 int unused_property_fields) {
8617 #ifdef DEBUG
8618   Isolate* isolate = map->GetIsolate();
8619   // Strict function maps have Function as a constructor but the
8620   // Function's initial map is a sloppy function map. Same holds for
8621   // GeneratorFunction / AsyncFunction and its initial map.
8622   Object* constructor = map->GetConstructor();
8623   DCHECK(constructor->IsJSFunction());
8624   DCHECK(*map == JSFunction::cast(constructor)->initial_map() ||
8625          *map == *isolate->strict_function_map() ||
8626          *map == *isolate->generator_function_map() ||
8627          *map == *isolate->async_function_map());
8628 #endif
8629   // Initial maps must always own their descriptors and it's descriptor array
8630   // does not contain descriptors that do not belong to the map.
8631   DCHECK(map->owns_descriptors());
8632   DCHECK_EQ(map->NumberOfOwnDescriptors(),
8633             map->instance_descriptors()->number_of_descriptors());
8634 
8635   Handle<Map> result = RawCopy(map, instance_size);
8636 
8637   // Please note instance_type and instance_size are set when allocated.
8638   result->SetInObjectProperties(in_object_properties);
8639   result->set_unused_property_fields(unused_property_fields);
8640 
8641   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
8642   if (number_of_own_descriptors > 0) {
8643     // The copy will use the same descriptors array.
8644     result->UpdateDescriptors(map->instance_descriptors(),
8645                               map->GetLayoutDescriptor());
8646     result->SetNumberOfOwnDescriptors(number_of_own_descriptors);
8647 
8648     DCHECK_EQ(result->NumberOfFields(),
8649               in_object_properties - unused_property_fields);
8650   }
8651 
8652   return result;
8653 }
8654 
8655 
CopyDropDescriptors(Handle<Map> map)8656 Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) {
8657   Handle<Map> result = RawCopy(map, map->instance_size());
8658 
8659   // Please note instance_type and instance_size are set when allocated.
8660   if (map->IsJSObjectMap()) {
8661     result->SetInObjectProperties(map->GetInObjectProperties());
8662     result->set_unused_property_fields(map->unused_property_fields());
8663   }
8664   result->ClearCodeCache(map->GetHeap());
8665   map->NotifyLeafMapLayoutChange();
8666   return result;
8667 }
8668 
8669 
ShareDescriptor(Handle<Map> map,Handle<DescriptorArray> descriptors,Descriptor * descriptor)8670 Handle<Map> Map::ShareDescriptor(Handle<Map> map,
8671                                  Handle<DescriptorArray> descriptors,
8672                                  Descriptor* descriptor) {
8673   // Sanity check. This path is only to be taken if the map owns its descriptor
8674   // array, implying that its NumberOfOwnDescriptors equals the number of
8675   // descriptors in the descriptor array.
8676   DCHECK_EQ(map->NumberOfOwnDescriptors(),
8677             map->instance_descriptors()->number_of_descriptors());
8678 
8679   Handle<Map> result = CopyDropDescriptors(map);
8680   Handle<Name> name = descriptor->GetKey();
8681 
8682   // Ensure there's space for the new descriptor in the shared descriptor array.
8683   if (descriptors->NumberOfSlackDescriptors() == 0) {
8684     int old_size = descriptors->number_of_descriptors();
8685     if (old_size == 0) {
8686       descriptors = DescriptorArray::Allocate(map->GetIsolate(), 0, 1);
8687     } else {
8688       int slack = SlackForArraySize(old_size, kMaxNumberOfDescriptors);
8689       EnsureDescriptorSlack(map, slack);
8690       descriptors = handle(map->instance_descriptors());
8691     }
8692   }
8693 
8694   Handle<LayoutDescriptor> layout_descriptor =
8695       FLAG_unbox_double_fields
8696           ? LayoutDescriptor::ShareAppend(map, descriptor->GetDetails())
8697           : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
8698 
8699   {
8700     DisallowHeapAllocation no_gc;
8701     descriptors->Append(descriptor);
8702     result->InitializeDescriptors(*descriptors, *layout_descriptor);
8703   }
8704 
8705   DCHECK(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1);
8706   ConnectTransition(map, result, name, SIMPLE_PROPERTY_TRANSITION);
8707 
8708   return result;
8709 }
8710 
8711 
8712 #if TRACE_MAPS
8713 
8714 // static
TraceTransition(const char * what,Map * from,Map * to,Name * name)8715 void Map::TraceTransition(const char* what, Map* from, Map* to, Name* name) {
8716   if (FLAG_trace_maps) {
8717     PrintF("[TraceMaps: %s from= %p to= %p name= ", what,
8718            reinterpret_cast<void*>(from), reinterpret_cast<void*>(to));
8719     name->NameShortPrint();
8720     PrintF(" ]\n");
8721   }
8722 }
8723 
8724 
8725 // static
TraceAllTransitions(Map * map)8726 void Map::TraceAllTransitions(Map* map) {
8727   Object* transitions = map->raw_transitions();
8728   int num_transitions = TransitionArray::NumberOfTransitions(transitions);
8729   for (int i = -0; i < num_transitions; ++i) {
8730     Map* target = TransitionArray::GetTarget(transitions, i);
8731     Name* key = TransitionArray::GetKey(transitions, i);
8732     Map::TraceTransition("Transition", map, target, key);
8733     Map::TraceAllTransitions(target);
8734   }
8735 }
8736 
8737 #endif  // TRACE_MAPS
8738 
8739 
ConnectTransition(Handle<Map> parent,Handle<Map> child,Handle<Name> name,SimpleTransitionFlag flag)8740 void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
8741                             Handle<Name> name, SimpleTransitionFlag flag) {
8742   if (!parent->GetBackPointer()->IsUndefined(parent->GetIsolate())) {
8743     parent->set_owns_descriptors(false);
8744   } else {
8745     // |parent| is initial map and it must keep the ownership, there must be no
8746     // descriptors in the descriptors array that do not belong to the map.
8747     DCHECK(parent->owns_descriptors());
8748     DCHECK_EQ(parent->NumberOfOwnDescriptors(),
8749               parent->instance_descriptors()->number_of_descriptors());
8750   }
8751   if (parent->is_prototype_map()) {
8752     DCHECK(child->is_prototype_map());
8753 #if TRACE_MAPS
8754     Map::TraceTransition("NoTransition", *parent, *child, *name);
8755 #endif
8756   } else {
8757     TransitionArray::Insert(parent, name, child, flag);
8758 #if TRACE_MAPS
8759     Map::TraceTransition("Transition", *parent, *child, *name);
8760 #endif
8761   }
8762 }
8763 
8764 
CopyReplaceDescriptors(Handle<Map> map,Handle<DescriptorArray> descriptors,Handle<LayoutDescriptor> layout_descriptor,TransitionFlag flag,MaybeHandle<Name> maybe_name,const char * reason,SimpleTransitionFlag simple_flag)8765 Handle<Map> Map::CopyReplaceDescriptors(
8766     Handle<Map> map, Handle<DescriptorArray> descriptors,
8767     Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag,
8768     MaybeHandle<Name> maybe_name, const char* reason,
8769     SimpleTransitionFlag simple_flag) {
8770   DCHECK(descriptors->IsSortedNoDuplicates());
8771 
8772   Handle<Map> result = CopyDropDescriptors(map);
8773 
8774   if (!map->is_prototype_map()) {
8775     if (flag == INSERT_TRANSITION &&
8776         TransitionArray::CanHaveMoreTransitions(map)) {
8777       result->InitializeDescriptors(*descriptors, *layout_descriptor);
8778 
8779       Handle<Name> name;
8780       CHECK(maybe_name.ToHandle(&name));
8781       ConnectTransition(map, result, name, simple_flag);
8782     } else {
8783       descriptors->GeneralizeAllFields();
8784       result->InitializeDescriptors(*descriptors,
8785                                     LayoutDescriptor::FastPointerLayout());
8786     }
8787   } else {
8788     result->InitializeDescriptors(*descriptors, *layout_descriptor);
8789   }
8790 #if TRACE_MAPS
8791   if (FLAG_trace_maps &&
8792       // Mirror conditions above that did not call ConnectTransition().
8793       (map->is_prototype_map() ||
8794        !(flag == INSERT_TRANSITION &&
8795          TransitionArray::CanHaveMoreTransitions(map)))) {
8796     PrintF("[TraceMaps: ReplaceDescriptors from= %p to= %p reason= %s ]\n",
8797            reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*result),
8798            reason);
8799   }
8800 #endif
8801 
8802   return result;
8803 }
8804 
8805 
8806 // Creates transition tree starting from |split_map| and adding all descriptors
8807 // starting from descriptor with index |split_map|.NumberOfOwnDescriptors().
8808 // The way how it is done is tricky because of GC and special descriptors
8809 // marking logic.
AddMissingTransitions(Handle<Map> split_map,Handle<DescriptorArray> descriptors,Handle<LayoutDescriptor> full_layout_descriptor)8810 Handle<Map> Map::AddMissingTransitions(
8811     Handle<Map> split_map, Handle<DescriptorArray> descriptors,
8812     Handle<LayoutDescriptor> full_layout_descriptor) {
8813   DCHECK(descriptors->IsSortedNoDuplicates());
8814   int split_nof = split_map->NumberOfOwnDescriptors();
8815   int nof_descriptors = descriptors->number_of_descriptors();
8816   DCHECK_LT(split_nof, nof_descriptors);
8817 
8818   // Start with creating last map which will own full descriptors array.
8819   // This is necessary to guarantee that GC will mark the whole descriptor
8820   // array if any of the allocations happening below fail.
8821   // Number of unused properties is temporarily incorrect and the layout
8822   // descriptor could unnecessarily be in slow mode but we will fix after
8823   // all the other intermediate maps are created.
8824   Handle<Map> last_map = CopyDropDescriptors(split_map);
8825   last_map->InitializeDescriptors(*descriptors, *full_layout_descriptor);
8826   last_map->set_unused_property_fields(0);
8827 
8828   // During creation of intermediate maps we violate descriptors sharing
8829   // invariant since the last map is not yet connected to the transition tree
8830   // we create here. But it is safe because GC never trims map's descriptors
8831   // if there are no dead transitions from that map and this is exactly the
8832   // case for all the intermediate maps we create here.
8833   Handle<Map> map = split_map;
8834   for (int i = split_nof; i < nof_descriptors - 1; ++i) {
8835     Handle<Map> new_map = CopyDropDescriptors(map);
8836     InstallDescriptors(map, new_map, i, descriptors, full_layout_descriptor);
8837     map = new_map;
8838   }
8839   map->NotifyLeafMapLayoutChange();
8840   InstallDescriptors(map, last_map, nof_descriptors - 1, descriptors,
8841                      full_layout_descriptor);
8842   return last_map;
8843 }
8844 
8845 
8846 // Since this method is used to rewrite an existing transition tree, it can
8847 // always insert transitions without checking.
InstallDescriptors(Handle<Map> parent,Handle<Map> child,int new_descriptor,Handle<DescriptorArray> descriptors,Handle<LayoutDescriptor> full_layout_descriptor)8848 void Map::InstallDescriptors(Handle<Map> parent, Handle<Map> child,
8849                              int new_descriptor,
8850                              Handle<DescriptorArray> descriptors,
8851                              Handle<LayoutDescriptor> full_layout_descriptor) {
8852   DCHECK(descriptors->IsSortedNoDuplicates());
8853 
8854   child->set_instance_descriptors(*descriptors);
8855   child->SetNumberOfOwnDescriptors(new_descriptor + 1);
8856 
8857   int unused_property_fields = parent->unused_property_fields();
8858   PropertyDetails details = descriptors->GetDetails(new_descriptor);
8859   if (details.location() == kField) {
8860     unused_property_fields = parent->unused_property_fields() - 1;
8861     if (unused_property_fields < 0) {
8862       unused_property_fields += JSObject::kFieldsAdded;
8863     }
8864   }
8865   child->set_unused_property_fields(unused_property_fields);
8866 
8867   if (FLAG_unbox_double_fields) {
8868     Handle<LayoutDescriptor> layout_descriptor =
8869         LayoutDescriptor::AppendIfFastOrUseFull(parent, details,
8870                                                 full_layout_descriptor);
8871     child->set_layout_descriptor(*layout_descriptor);
8872 #ifdef VERIFY_HEAP
8873     // TODO(ishell): remove these checks from VERIFY_HEAP mode.
8874     if (FLAG_verify_heap) {
8875       CHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
8876     }
8877 #else
8878     SLOW_DCHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
8879 #endif
8880     child->set_visitor_id(Heap::GetStaticVisitorIdForMap(*child));
8881   }
8882 
8883   Handle<Name> name = handle(descriptors->GetKey(new_descriptor));
8884   ConnectTransition(parent, child, name, SIMPLE_PROPERTY_TRANSITION);
8885 }
8886 
8887 
CopyAsElementsKind(Handle<Map> map,ElementsKind kind,TransitionFlag flag)8888 Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind,
8889                                     TransitionFlag flag) {
8890   Map* maybe_elements_transition_map = NULL;
8891   if (flag == INSERT_TRANSITION) {
8892     // Ensure we are requested to add elements kind transition "near the root".
8893     DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(),
8894               map->NumberOfOwnDescriptors());
8895 
8896     maybe_elements_transition_map = map->ElementsTransitionMap();
8897     DCHECK(maybe_elements_transition_map == NULL ||
8898            (maybe_elements_transition_map->elements_kind() ==
8899                 DICTIONARY_ELEMENTS &&
8900             kind == DICTIONARY_ELEMENTS));
8901     DCHECK(!IsFastElementsKind(kind) ||
8902            IsMoreGeneralElementsKindTransition(map->elements_kind(), kind));
8903     DCHECK(kind != map->elements_kind());
8904   }
8905 
8906   bool insert_transition = flag == INSERT_TRANSITION &&
8907                            TransitionArray::CanHaveMoreTransitions(map) &&
8908                            maybe_elements_transition_map == NULL;
8909 
8910   if (insert_transition) {
8911     Handle<Map> new_map = CopyForTransition(map, "CopyAsElementsKind");
8912     new_map->set_elements_kind(kind);
8913 
8914     Isolate* isolate = map->GetIsolate();
8915     Handle<Name> name = isolate->factory()->elements_transition_symbol();
8916     ConnectTransition(map, new_map, name, SPECIAL_TRANSITION);
8917     return new_map;
8918   }
8919 
8920   // Create a new free-floating map only if we are not allowed to store it.
8921   Handle<Map> new_map = Copy(map, "CopyAsElementsKind");
8922   new_map->set_elements_kind(kind);
8923   return new_map;
8924 }
8925 
8926 
AsLanguageMode(Handle<Map> initial_map,LanguageMode language_mode,FunctionKind kind)8927 Handle<Map> Map::AsLanguageMode(Handle<Map> initial_map,
8928                                 LanguageMode language_mode, FunctionKind kind) {
8929   DCHECK_EQ(JS_FUNCTION_TYPE, initial_map->instance_type());
8930   // Initial map for sloppy mode function is stored in the function
8931   // constructor. Initial maps for strict mode are cached as special transitions
8932   // using |strict_function_transition_symbol| as a key.
8933   if (language_mode == SLOPPY) return initial_map;
8934   Isolate* isolate = initial_map->GetIsolate();
8935 
8936   int map_index = Context::FunctionMapIndex(language_mode, kind);
8937   Handle<Map> function_map(
8938       Map::cast(isolate->native_context()->get(map_index)));
8939 
8940   STATIC_ASSERT(LANGUAGE_END == 2);
8941   DCHECK_EQ(STRICT, language_mode);
8942   Handle<Symbol> transition_symbol =
8943       isolate->factory()->strict_function_transition_symbol();
8944   Map* maybe_transition =
8945       TransitionArray::SearchSpecial(*initial_map, *transition_symbol);
8946   if (maybe_transition != NULL) {
8947     return handle(maybe_transition, isolate);
8948   }
8949   initial_map->NotifyLeafMapLayoutChange();
8950 
8951   // Create new map taking descriptors from the |function_map| and all
8952   // the other details from the |initial_map|.
8953   Handle<Map> map =
8954       Map::CopyInitialMap(function_map, initial_map->instance_size(),
8955                           initial_map->GetInObjectProperties(),
8956                           initial_map->unused_property_fields());
8957   map->SetConstructor(initial_map->GetConstructor());
8958   map->set_prototype(initial_map->prototype());
8959 
8960   if (TransitionArray::CanHaveMoreTransitions(initial_map)) {
8961     Map::ConnectTransition(initial_map, map, transition_symbol,
8962                            SPECIAL_TRANSITION);
8963   }
8964   return map;
8965 }
8966 
8967 
CopyForTransition(Handle<Map> map,const char * reason)8968 Handle<Map> Map::CopyForTransition(Handle<Map> map, const char* reason) {
8969   DCHECK(!map->is_prototype_map());
8970   Handle<Map> new_map = CopyDropDescriptors(map);
8971 
8972   if (map->owns_descriptors()) {
8973     // In case the map owned its own descriptors, share the descriptors and
8974     // transfer ownership to the new map.
8975     // The properties did not change, so reuse descriptors.
8976     new_map->InitializeDescriptors(map->instance_descriptors(),
8977                                    map->GetLayoutDescriptor());
8978   } else {
8979     // In case the map did not own its own descriptors, a split is forced by
8980     // copying the map; creating a new descriptor array cell.
8981     Handle<DescriptorArray> descriptors(map->instance_descriptors());
8982     int number_of_own_descriptors = map->NumberOfOwnDescriptors();
8983     Handle<DescriptorArray> new_descriptors =
8984         DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
8985     Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
8986                                                    map->GetIsolate());
8987     new_map->InitializeDescriptors(*new_descriptors, *new_layout_descriptor);
8988   }
8989 
8990 #if TRACE_MAPS
8991   if (FLAG_trace_maps) {
8992     PrintF("[TraceMaps: CopyForTransition from= %p to= %p reason= %s ]\n",
8993            reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*new_map),
8994            reason);
8995   }
8996 #endif
8997 
8998   return new_map;
8999 }
9000 
9001 
Copy(Handle<Map> map,const char * reason)9002 Handle<Map> Map::Copy(Handle<Map> map, const char* reason) {
9003   Handle<DescriptorArray> descriptors(map->instance_descriptors());
9004   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9005   Handle<DescriptorArray> new_descriptors =
9006       DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
9007   Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9008                                                  map->GetIsolate());
9009   return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9010                                 OMIT_TRANSITION, MaybeHandle<Name>(), reason,
9011                                 SPECIAL_TRANSITION);
9012 }
9013 
9014 
Create(Isolate * isolate,int inobject_properties)9015 Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) {
9016   Handle<Map> copy =
9017       Copy(handle(isolate->object_function()->initial_map()), "MapCreate");
9018 
9019   // Check that we do not overflow the instance size when adding the extra
9020   // inobject properties. If the instance size overflows, we allocate as many
9021   // properties as we can as inobject properties.
9022   int max_extra_properties =
9023       (JSObject::kMaxInstanceSize - JSObject::kHeaderSize) >> kPointerSizeLog2;
9024 
9025   if (inobject_properties > max_extra_properties) {
9026     inobject_properties = max_extra_properties;
9027   }
9028 
9029   int new_instance_size =
9030       JSObject::kHeaderSize + kPointerSize * inobject_properties;
9031 
9032   // Adjust the map with the extra inobject properties.
9033   copy->SetInObjectProperties(inobject_properties);
9034   copy->set_unused_property_fields(inobject_properties);
9035   copy->set_instance_size(new_instance_size);
9036   copy->set_visitor_id(Heap::GetStaticVisitorIdForMap(*copy));
9037   return copy;
9038 }
9039 
9040 
CopyForPreventExtensions(Handle<Map> map,PropertyAttributes attrs_to_add,Handle<Symbol> transition_marker,const char * reason)9041 Handle<Map> Map::CopyForPreventExtensions(Handle<Map> map,
9042                                           PropertyAttributes attrs_to_add,
9043                                           Handle<Symbol> transition_marker,
9044                                           const char* reason) {
9045   int num_descriptors = map->NumberOfOwnDescriptors();
9046   Isolate* isolate = map->GetIsolate();
9047   Handle<DescriptorArray> new_desc = DescriptorArray::CopyUpToAddAttributes(
9048       handle(map->instance_descriptors(), isolate), num_descriptors,
9049       attrs_to_add);
9050   Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9051                                                  isolate);
9052   Handle<Map> new_map = CopyReplaceDescriptors(
9053       map, new_desc, new_layout_descriptor, INSERT_TRANSITION,
9054       transition_marker, reason, SPECIAL_TRANSITION);
9055   new_map->set_is_extensible(false);
9056   if (!IsFixedTypedArrayElementsKind(map->elements_kind())) {
9057     ElementsKind new_kind = IsStringWrapperElementsKind(map->elements_kind())
9058                                 ? SLOW_STRING_WRAPPER_ELEMENTS
9059                                 : DICTIONARY_ELEMENTS;
9060     new_map->set_elements_kind(new_kind);
9061   }
9062   return new_map;
9063 }
9064 
9065 namespace {
9066 
CanHoldValue(DescriptorArray * descriptors,int descriptor,PropertyConstness constness,Object * value)9067 bool CanHoldValue(DescriptorArray* descriptors, int descriptor,
9068                   PropertyConstness constness, Object* value) {
9069   PropertyDetails details = descriptors->GetDetails(descriptor);
9070   if (details.location() == kField) {
9071     if (details.kind() == kData) {
9072       return IsGeneralizableTo(constness, details.constness()) &&
9073              value->FitsRepresentation(details.representation()) &&
9074              descriptors->GetFieldType(descriptor)->NowContains(value);
9075     } else {
9076       DCHECK_EQ(kAccessor, details.kind());
9077       return false;
9078     }
9079 
9080   } else {
9081     DCHECK_EQ(kDescriptor, details.location());
9082     DCHECK_EQ(kConst, details.constness());
9083     if (details.kind() == kData) {
9084       DCHECK(!FLAG_track_constant_fields);
9085       DCHECK(descriptors->GetValue(descriptor) != value ||
9086              value->FitsRepresentation(details.representation()));
9087       return descriptors->GetValue(descriptor) == value;
9088     } else {
9089       DCHECK_EQ(kAccessor, details.kind());
9090       return false;
9091     }
9092   }
9093   UNREACHABLE();
9094   return false;
9095 }
9096 
UpdateDescriptorForValue(Handle<Map> map,int descriptor,PropertyConstness constness,Handle<Object> value)9097 Handle<Map> UpdateDescriptorForValue(Handle<Map> map, int descriptor,
9098                                      PropertyConstness constness,
9099                                      Handle<Object> value) {
9100   if (CanHoldValue(map->instance_descriptors(), descriptor, constness,
9101                    *value)) {
9102     return map;
9103   }
9104 
9105   Isolate* isolate = map->GetIsolate();
9106   PropertyAttributes attributes =
9107       map->instance_descriptors()->GetDetails(descriptor).attributes();
9108   Representation representation = value->OptimalRepresentation();
9109   Handle<FieldType> type = value->OptimalType(isolate, representation);
9110 
9111   MapUpdater mu(isolate, map);
9112   return mu.ReconfigureToDataField(descriptor, attributes, constness,
9113                                    representation, type);
9114 }
9115 
9116 }  // namespace
9117 
9118 // static
PrepareForDataProperty(Handle<Map> map,int descriptor,PropertyConstness constness,Handle<Object> value)9119 Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor,
9120                                         PropertyConstness constness,
9121                                         Handle<Object> value) {
9122   // Dictionaries can store any property value.
9123   DCHECK(!map->is_dictionary_map());
9124   // Update to the newest map before storing the property.
9125   return UpdateDescriptorForValue(Update(map), descriptor, constness, value);
9126 }
9127 
TransitionToDataProperty(Handle<Map> map,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes,PropertyConstness constness,StoreFromKeyed store_mode)9128 Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
9129                                           Handle<Object> value,
9130                                           PropertyAttributes attributes,
9131                                           PropertyConstness constness,
9132                                           StoreFromKeyed store_mode) {
9133   RuntimeCallTimerScope stats_scope(
9134       *map, map->is_prototype_map()
9135                 ? &RuntimeCallStats::PrototypeMap_TransitionToDataProperty
9136                 : &RuntimeCallStats::Map_TransitionToDataProperty);
9137 
9138   DCHECK(name->IsUniqueName());
9139   DCHECK(!map->is_dictionary_map());
9140 
9141   // Migrate to the newest map before storing the property.
9142   map = Update(map);
9143 
9144   Map* maybe_transition =
9145       TransitionArray::SearchTransition(*map, kData, *name, attributes);
9146   if (maybe_transition != NULL) {
9147     Handle<Map> transition(maybe_transition);
9148     int descriptor = transition->LastAdded();
9149 
9150     DCHECK_EQ(attributes, transition->instance_descriptors()
9151                               ->GetDetails(descriptor)
9152                               .attributes());
9153 
9154     return UpdateDescriptorForValue(transition, descriptor, constness, value);
9155   }
9156 
9157   TransitionFlag flag = INSERT_TRANSITION;
9158   MaybeHandle<Map> maybe_map;
9159   if (!FLAG_track_constant_fields && value->IsJSFunction()) {
9160     maybe_map = Map::CopyWithConstant(map, name, value, attributes, flag);
9161   } else if (!map->TooManyFastProperties(store_mode)) {
9162     Isolate* isolate = name->GetIsolate();
9163     Representation representation = value->OptimalRepresentation();
9164     Handle<FieldType> type = value->OptimalType(isolate, representation);
9165     maybe_map = Map::CopyWithField(map, name, type, attributes, constness,
9166                                    representation, flag);
9167   }
9168 
9169   Handle<Map> result;
9170   if (!maybe_map.ToHandle(&result)) {
9171 #if TRACE_MAPS
9172     if (FLAG_trace_maps) {
9173       Vector<char> name_buffer = Vector<char>::New(100);
9174       name->NameShortPrint(name_buffer);
9175       Vector<char> buffer = Vector<char>::New(128);
9176       SNPrintF(buffer, "TooManyFastProperties %s", name_buffer.start());
9177       return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, buffer.start());
9178     }
9179 #endif
9180     return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES,
9181                           "TooManyFastProperties");
9182   }
9183 
9184   return result;
9185 }
9186 
9187 
ReconfigureExistingProperty(Handle<Map> map,int descriptor,PropertyKind kind,PropertyAttributes attributes)9188 Handle<Map> Map::ReconfigureExistingProperty(Handle<Map> map, int descriptor,
9189                                              PropertyKind kind,
9190                                              PropertyAttributes attributes) {
9191   // Dictionaries have to be reconfigured in-place.
9192   DCHECK(!map->is_dictionary_map());
9193 
9194   if (!map->GetBackPointer()->IsMap()) {
9195     // There is no benefit from reconstructing transition tree for maps without
9196     // back pointers.
9197     return CopyGeneralizeAllFields(map, map->elements_kind(), descriptor, kind,
9198                                    attributes,
9199                                    "GenAll_AttributesMismatchProtoMap");
9200   }
9201 
9202   if (FLAG_trace_generalization) {
9203     map->PrintReconfiguration(stdout, descriptor, kind, attributes);
9204   }
9205 
9206   Isolate* isolate = map->GetIsolate();
9207 
9208   MapUpdater mu(isolate, map);
9209   DCHECK_EQ(kData, kind);  // Only kData case is supported so far.
9210   Handle<Map> new_map = mu.ReconfigureToDataField(
9211       descriptor, attributes, kDefaultFieldConstness, Representation::None(),
9212       FieldType::None(isolate));
9213   return new_map;
9214 }
9215 
TransitionToAccessorProperty(Isolate * isolate,Handle<Map> map,Handle<Name> name,int descriptor,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)9216 Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map,
9217                                               Handle<Name> name, int descriptor,
9218                                               Handle<Object> getter,
9219                                               Handle<Object> setter,
9220                                               PropertyAttributes attributes) {
9221   RuntimeCallTimerScope stats_scope(
9222       isolate,
9223       map->is_prototype_map()
9224           ? &RuntimeCallStats::PrototypeMap_TransitionToAccessorProperty
9225           : &RuntimeCallStats::Map_TransitionToAccessorProperty);
9226 
9227   // At least one of the accessors needs to be a new value.
9228   DCHECK(!getter->IsNull(isolate) || !setter->IsNull(isolate));
9229   DCHECK(name->IsUniqueName());
9230 
9231   // Dictionary maps can always have additional data properties.
9232   if (map->is_dictionary_map()) return map;
9233 
9234   // Migrate to the newest map before transitioning to the new property.
9235   map = Update(map);
9236 
9237   PropertyNormalizationMode mode = map->is_prototype_map()
9238                                        ? KEEP_INOBJECT_PROPERTIES
9239                                        : CLEAR_INOBJECT_PROPERTIES;
9240 
9241   Map* maybe_transition =
9242       TransitionArray::SearchTransition(*map, kAccessor, *name, attributes);
9243   if (maybe_transition != NULL) {
9244     Handle<Map> transition(maybe_transition, isolate);
9245     DescriptorArray* descriptors = transition->instance_descriptors();
9246     int descriptor = transition->LastAdded();
9247     DCHECK(descriptors->GetKey(descriptor)->Equals(*name));
9248 
9249     DCHECK_EQ(kAccessor, descriptors->GetDetails(descriptor).kind());
9250     DCHECK_EQ(attributes, descriptors->GetDetails(descriptor).attributes());
9251 
9252     Handle<Object> maybe_pair(descriptors->GetValue(descriptor), isolate);
9253     if (!maybe_pair->IsAccessorPair()) {
9254       return Map::Normalize(map, mode, "TransitionToAccessorFromNonPair");
9255     }
9256 
9257     Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair);
9258     if (!pair->Equals(*getter, *setter)) {
9259       return Map::Normalize(map, mode, "TransitionToDifferentAccessor");
9260     }
9261 
9262     return transition;
9263   }
9264 
9265   Handle<AccessorPair> pair;
9266   DescriptorArray* old_descriptors = map->instance_descriptors();
9267   if (descriptor != DescriptorArray::kNotFound) {
9268     if (descriptor != map->LastAdded()) {
9269       return Map::Normalize(map, mode, "AccessorsOverwritingNonLast");
9270     }
9271     PropertyDetails old_details = old_descriptors->GetDetails(descriptor);
9272     if (old_details.kind() != kAccessor) {
9273       return Map::Normalize(map, mode, "AccessorsOverwritingNonAccessors");
9274     }
9275 
9276     if (old_details.attributes() != attributes) {
9277       return Map::Normalize(map, mode, "AccessorsWithAttributes");
9278     }
9279 
9280     Handle<Object> maybe_pair(old_descriptors->GetValue(descriptor), isolate);
9281     if (!maybe_pair->IsAccessorPair()) {
9282       return Map::Normalize(map, mode, "AccessorsOverwritingNonPair");
9283     }
9284 
9285     Handle<AccessorPair> current_pair = Handle<AccessorPair>::cast(maybe_pair);
9286     if (current_pair->Equals(*getter, *setter)) return map;
9287 
9288     bool overwriting_accessor = false;
9289     if (!getter->IsNull(isolate) &&
9290         !current_pair->get(ACCESSOR_GETTER)->IsNull(isolate) &&
9291         current_pair->get(ACCESSOR_GETTER) != *getter) {
9292       overwriting_accessor = true;
9293     }
9294     if (!setter->IsNull(isolate) &&
9295         !current_pair->get(ACCESSOR_SETTER)->IsNull(isolate) &&
9296         current_pair->get(ACCESSOR_SETTER) != *setter) {
9297       overwriting_accessor = true;
9298     }
9299     if (overwriting_accessor) {
9300       return Map::Normalize(map, mode, "AccessorsOverwritingAccessors");
9301     }
9302 
9303     pair = AccessorPair::Copy(Handle<AccessorPair>::cast(maybe_pair));
9304   } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors ||
9305              map->TooManyFastProperties(CERTAINLY_NOT_STORE_FROM_KEYED)) {
9306     return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, "TooManyAccessors");
9307   } else {
9308     pair = isolate->factory()->NewAccessorPair();
9309   }
9310 
9311   pair->SetComponents(*getter, *setter);
9312 
9313   TransitionFlag flag = INSERT_TRANSITION;
9314   Descriptor d = Descriptor::AccessorConstant(name, pair, attributes);
9315   return Map::CopyInsertDescriptor(map, &d, flag);
9316 }
9317 
9318 
CopyAddDescriptor(Handle<Map> map,Descriptor * descriptor,TransitionFlag flag)9319 Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
9320                                    Descriptor* descriptor,
9321                                    TransitionFlag flag) {
9322   Handle<DescriptorArray> descriptors(map->instance_descriptors());
9323 
9324   // Share descriptors only if map owns descriptors and it not an initial map.
9325   if (flag == INSERT_TRANSITION && map->owns_descriptors() &&
9326       !map->GetBackPointer()->IsUndefined(map->GetIsolate()) &&
9327       TransitionArray::CanHaveMoreTransitions(map)) {
9328     return ShareDescriptor(map, descriptors, descriptor);
9329   }
9330 
9331   int nof = map->NumberOfOwnDescriptors();
9332   Handle<DescriptorArray> new_descriptors =
9333       DescriptorArray::CopyUpTo(descriptors, nof, 1);
9334   new_descriptors->Append(descriptor);
9335 
9336   Handle<LayoutDescriptor> new_layout_descriptor =
9337       FLAG_unbox_double_fields
9338           ? LayoutDescriptor::New(map, new_descriptors, nof + 1)
9339           : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
9340 
9341   return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9342                                 flag, descriptor->GetKey(), "CopyAddDescriptor",
9343                                 SIMPLE_PROPERTY_TRANSITION);
9344 }
9345 
9346 
CopyInsertDescriptor(Handle<Map> map,Descriptor * descriptor,TransitionFlag flag)9347 Handle<Map> Map::CopyInsertDescriptor(Handle<Map> map,
9348                                       Descriptor* descriptor,
9349                                       TransitionFlag flag) {
9350   Handle<DescriptorArray> old_descriptors(map->instance_descriptors());
9351 
9352   // We replace the key if it is already present.
9353   int index = old_descriptors->SearchWithCache(map->GetIsolate(),
9354                                                *descriptor->GetKey(), *map);
9355   if (index != DescriptorArray::kNotFound) {
9356     return CopyReplaceDescriptor(map, old_descriptors, descriptor, index, flag);
9357   }
9358   return CopyAddDescriptor(map, descriptor, flag);
9359 }
9360 
9361 
CopyUpTo(Handle<DescriptorArray> desc,int enumeration_index,int slack)9362 Handle<DescriptorArray> DescriptorArray::CopyUpTo(
9363     Handle<DescriptorArray> desc,
9364     int enumeration_index,
9365     int slack) {
9366   return DescriptorArray::CopyUpToAddAttributes(
9367       desc, enumeration_index, NONE, slack);
9368 }
9369 
9370 
CopyUpToAddAttributes(Handle<DescriptorArray> desc,int enumeration_index,PropertyAttributes attributes,int slack)9371 Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
9372     Handle<DescriptorArray> desc,
9373     int enumeration_index,
9374     PropertyAttributes attributes,
9375     int slack) {
9376   if (enumeration_index + slack == 0) {
9377     return desc->GetIsolate()->factory()->empty_descriptor_array();
9378   }
9379 
9380   int size = enumeration_index;
9381 
9382   Handle<DescriptorArray> descriptors =
9383       DescriptorArray::Allocate(desc->GetIsolate(), size, slack);
9384 
9385   if (attributes != NONE) {
9386     for (int i = 0; i < size; ++i) {
9387       Object* value = desc->GetValue(i);
9388       Name* key = desc->GetKey(i);
9389       PropertyDetails details = desc->GetDetails(i);
9390       // Bulk attribute changes never affect private properties.
9391       if (!key->IsPrivate()) {
9392         int mask = DONT_DELETE | DONT_ENUM;
9393         // READ_ONLY is an invalid attribute for JS setters/getters.
9394         if (details.kind() != kAccessor || !value->IsAccessorPair()) {
9395           mask |= READ_ONLY;
9396         }
9397         details = details.CopyAddAttributes(
9398             static_cast<PropertyAttributes>(attributes & mask));
9399       }
9400       descriptors->Set(i, key, value, details);
9401     }
9402   } else {
9403     for (int i = 0; i < size; ++i) {
9404       descriptors->CopyFrom(i, *desc);
9405     }
9406   }
9407 
9408   if (desc->number_of_descriptors() != enumeration_index) descriptors->Sort();
9409 
9410   return descriptors;
9411 }
9412 
9413 
IsEqualUpTo(DescriptorArray * desc,int nof_descriptors)9414 bool DescriptorArray::IsEqualUpTo(DescriptorArray* desc, int nof_descriptors) {
9415   for (int i = 0; i < nof_descriptors; i++) {
9416     if (GetKey(i) != desc->GetKey(i) || GetValue(i) != desc->GetValue(i)) {
9417       return false;
9418     }
9419     PropertyDetails details = GetDetails(i);
9420     PropertyDetails other_details = desc->GetDetails(i);
9421     if (details.kind() != other_details.kind() ||
9422         details.location() != other_details.location() ||
9423         !details.representation().Equals(other_details.representation())) {
9424       return false;
9425     }
9426   }
9427   return true;
9428 }
9429 
9430 
CopyReplaceDescriptor(Handle<Map> map,Handle<DescriptorArray> descriptors,Descriptor * descriptor,int insertion_index,TransitionFlag flag)9431 Handle<Map> Map::CopyReplaceDescriptor(Handle<Map> map,
9432                                        Handle<DescriptorArray> descriptors,
9433                                        Descriptor* descriptor,
9434                                        int insertion_index,
9435                                        TransitionFlag flag) {
9436   Handle<Name> key = descriptor->GetKey();
9437   DCHECK(*key == descriptors->GetKey(insertion_index));
9438 
9439   Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
9440       descriptors, map->NumberOfOwnDescriptors());
9441 
9442   new_descriptors->Replace(insertion_index, descriptor);
9443   Handle<LayoutDescriptor> new_layout_descriptor = LayoutDescriptor::New(
9444       map, new_descriptors, new_descriptors->number_of_descriptors());
9445 
9446   SimpleTransitionFlag simple_flag =
9447       (insertion_index == descriptors->number_of_descriptors() - 1)
9448           ? SIMPLE_PROPERTY_TRANSITION
9449           : PROPERTY_TRANSITION;
9450   return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9451                                 flag, key, "CopyReplaceDescriptor",
9452                                 simple_flag);
9453 }
9454 
9455 // Helper class to manage a Map's code cache. The layout depends on the number
9456 // of entries; this is worthwhile because most code caches are very small,
9457 // but some are huge (thousands of entries).
9458 // For zero entries, the EmptyFixedArray is used.
9459 // For one entry, we use a 2-element FixedArray containing [name, code].
9460 // For 2..100 entries, we use a FixedArray with linear lookups, the layout is:
9461 //   [0] - number of slots that are currently in use
9462 //   [1] - first name
9463 //   [2] - first code
9464 //   [3] - second name
9465 //   [4] - second code
9466 //   etc.
9467 // For more than 128 entries, we use a CodeCacheHashTable.
9468 class CodeCache : public AllStatic {
9469  public:
9470   // Returns the new cache, to be stored on the map.
Put(Isolate * isolate,Handle<FixedArray> cache,Handle<Name> name,Handle<Code> code)9471   static Handle<FixedArray> Put(Isolate* isolate, Handle<FixedArray> cache,
9472                                 Handle<Name> name, Handle<Code> code) {
9473     int length = cache->length();
9474     if (length == 0) return PutFirstElement(isolate, name, code);
9475     if (length == kEntrySize) {
9476       return PutSecondElement(isolate, cache, name, code);
9477     }
9478     if (length <= kLinearMaxSize) {
9479       Handle<FixedArray> result = PutLinearElement(isolate, cache, name, code);
9480       if (!result.is_null()) return result;
9481       // Fall through if linear storage is getting too large.
9482     }
9483     return PutHashTableElement(isolate, cache, name, code);
9484   }
9485 
Lookup(FixedArray * cache,Name * name,Code::Flags flags)9486   static Code* Lookup(FixedArray* cache, Name* name, Code::Flags flags) {
9487     int length = cache->length();
9488     if (length == 0) return nullptr;
9489     if (length == kEntrySize) return OneElementLookup(cache, name, flags);
9490     if (!cache->IsCodeCacheHashTable()) {
9491       return LinearLookup(cache, name, flags);
9492     } else {
9493       return CodeCacheHashTable::cast(cache)->Lookup(name, flags);
9494     }
9495   }
9496 
9497  private:
9498   static const int kNameIndex = 0;
9499   static const int kCodeIndex = 1;
9500   static const int kEntrySize = 2;
9501 
9502   static const int kLinearUsageIndex = 0;
9503   static const int kLinearReservedSlots = 1;
9504   static const int kLinearInitialCapacity = 2;
9505   static const int kLinearMaxSize = 257;  // == LinearSizeFor(128);
9506 
9507   static const int kHashTableInitialCapacity = 200;  // Number of entries.
9508 
LinearSizeFor(int entries)9509   static int LinearSizeFor(int entries) {
9510     return kLinearReservedSlots + kEntrySize * entries;
9511   }
9512 
LinearNewSize(int old_size)9513   static int LinearNewSize(int old_size) {
9514     int old_entries = (old_size - kLinearReservedSlots) / kEntrySize;
9515     return LinearSizeFor(old_entries * 2);
9516   }
9517 
OneElementLookup(FixedArray * cache,Name * name,Code::Flags flags)9518   static Code* OneElementLookup(FixedArray* cache, Name* name,
9519                                 Code::Flags flags) {
9520     DCHECK_EQ(cache->length(), kEntrySize);
9521     if (cache->get(kNameIndex) != name) return nullptr;
9522     Code* maybe_code = Code::cast(cache->get(kCodeIndex));
9523     if (maybe_code->flags() != flags) return nullptr;
9524     return maybe_code;
9525   }
9526 
LinearLookup(FixedArray * cache,Name * name,Code::Flags flags)9527   static Code* LinearLookup(FixedArray* cache, Name* name, Code::Flags flags) {
9528     DCHECK_GE(cache->length(), kEntrySize);
9529     DCHECK(!cache->IsCodeCacheHashTable());
9530     int usage = GetLinearUsage(cache);
9531     for (int i = kLinearReservedSlots; i < usage; i += kEntrySize) {
9532       if (cache->get(i + kNameIndex) != name) continue;
9533       Code* code = Code::cast(cache->get(i + kCodeIndex));
9534       if (code->flags() == flags) return code;
9535     }
9536     return nullptr;
9537   }
9538 
PutFirstElement(Isolate * isolate,Handle<Name> name,Handle<Code> code)9539   static Handle<FixedArray> PutFirstElement(Isolate* isolate, Handle<Name> name,
9540                                             Handle<Code> code) {
9541     Handle<FixedArray> cache = isolate->factory()->NewFixedArray(kEntrySize);
9542     cache->set(kNameIndex, *name);
9543     cache->set(kCodeIndex, *code);
9544     return cache;
9545   }
9546 
PutSecondElement(Isolate * isolate,Handle<FixedArray> cache,Handle<Name> name,Handle<Code> code)9547   static Handle<FixedArray> PutSecondElement(Isolate* isolate,
9548                                              Handle<FixedArray> cache,
9549                                              Handle<Name> name,
9550                                              Handle<Code> code) {
9551     DCHECK_EQ(cache->length(), kEntrySize);
9552     Handle<FixedArray> new_cache = isolate->factory()->NewFixedArray(
9553         LinearSizeFor(kLinearInitialCapacity));
9554     new_cache->set(kLinearReservedSlots + kNameIndex, cache->get(kNameIndex));
9555     new_cache->set(kLinearReservedSlots + kCodeIndex, cache->get(kCodeIndex));
9556     new_cache->set(LinearSizeFor(1) + kNameIndex, *name);
9557     new_cache->set(LinearSizeFor(1) + kCodeIndex, *code);
9558     new_cache->set(kLinearUsageIndex, Smi::FromInt(LinearSizeFor(2)));
9559     return new_cache;
9560   }
9561 
PutLinearElement(Isolate * isolate,Handle<FixedArray> cache,Handle<Name> name,Handle<Code> code)9562   static Handle<FixedArray> PutLinearElement(Isolate* isolate,
9563                                              Handle<FixedArray> cache,
9564                                              Handle<Name> name,
9565                                              Handle<Code> code) {
9566     int length = cache->length();
9567     int usage = GetLinearUsage(*cache);
9568     DCHECK_LE(usage, length);
9569     // Check if we need to grow.
9570     if (usage == length) {
9571       int new_length = LinearNewSize(length);
9572       if (new_length > kLinearMaxSize) return Handle<FixedArray>::null();
9573       Handle<FixedArray> new_cache =
9574           isolate->factory()->NewFixedArray(new_length);
9575       for (int i = kLinearReservedSlots; i < length; i++) {
9576         new_cache->set(i, cache->get(i));
9577       }
9578       cache = new_cache;
9579     }
9580     // Store new entry.
9581     DCHECK_GE(cache->length(), usage + kEntrySize);
9582     cache->set(usage + kNameIndex, *name);
9583     cache->set(usage + kCodeIndex, *code);
9584     cache->set(kLinearUsageIndex, Smi::FromInt(usage + kEntrySize));
9585     return cache;
9586   }
9587 
PutHashTableElement(Isolate * isolate,Handle<FixedArray> cache,Handle<Name> name,Handle<Code> code)9588   static Handle<FixedArray> PutHashTableElement(Isolate* isolate,
9589                                                 Handle<FixedArray> cache,
9590                                                 Handle<Name> name,
9591                                                 Handle<Code> code) {
9592     // Check if we need to transition from linear to hash table storage.
9593     if (!cache->IsCodeCacheHashTable()) {
9594       // Check that the initial hash table capacity is large enough.
9595       DCHECK_EQ(kLinearMaxSize, LinearSizeFor(128));
9596       STATIC_ASSERT(kHashTableInitialCapacity > 128);
9597 
9598       int length = cache->length();
9599       // Only migrate from linear storage when it's full.
9600       DCHECK_EQ(length, GetLinearUsage(*cache));
9601       DCHECK_EQ(length, kLinearMaxSize);
9602       Handle<CodeCacheHashTable> table =
9603           CodeCacheHashTable::New(isolate, kHashTableInitialCapacity);
9604       HandleScope scope(isolate);
9605       for (int i = kLinearReservedSlots; i < length; i += kEntrySize) {
9606         Handle<Name> old_name(Name::cast(cache->get(i + kNameIndex)), isolate);
9607         Handle<Code> old_code(Code::cast(cache->get(i + kCodeIndex)), isolate);
9608         CodeCacheHashTable::Put(table, old_name, old_code);
9609       }
9610       cache = table;
9611     }
9612     // Store new entry.
9613     DCHECK(cache->IsCodeCacheHashTable());
9614     return CodeCacheHashTable::Put(Handle<CodeCacheHashTable>::cast(cache),
9615                                    name, code);
9616   }
9617 
GetLinearUsage(FixedArray * linear_cache)9618   static inline int GetLinearUsage(FixedArray* linear_cache) {
9619     DCHECK_GT(linear_cache->length(), kEntrySize);
9620     return Smi::cast(linear_cache->get(kLinearUsageIndex))->value();
9621   }
9622 };
9623 
UpdateCodeCache(Handle<Map> map,Handle<Name> name,Handle<Code> code)9624 void Map::UpdateCodeCache(Handle<Map> map,
9625                           Handle<Name> name,
9626                           Handle<Code> code) {
9627   Isolate* isolate = map->GetIsolate();
9628   Handle<FixedArray> cache(map->code_cache(), isolate);
9629   Handle<FixedArray> new_cache = CodeCache::Put(isolate, cache, name, code);
9630   map->set_code_cache(*new_cache);
9631 }
9632 
LookupInCodeCache(Name * name,Code::Flags flags)9633 Code* Map::LookupInCodeCache(Name* name, Code::Flags flags) {
9634   return CodeCache::Lookup(code_cache(), name, flags);
9635 }
9636 
9637 
9638 // The key in the code cache hash table consists of the property name and the
9639 // code object. The actual match is on the name and the code flags. If a key
9640 // is created using the flags and not a code object it can only be used for
9641 // lookup not to create a new entry.
9642 class CodeCacheHashTableKey : public HashTableKey {
9643  public:
CodeCacheHashTableKey(Handle<Name> name,Code::Flags flags)9644   CodeCacheHashTableKey(Handle<Name> name, Code::Flags flags)
9645       : name_(name), flags_(flags), code_() {
9646     DCHECK(name_->IsUniqueName());
9647   }
9648 
CodeCacheHashTableKey(Handle<Name> name,Handle<Code> code)9649   CodeCacheHashTableKey(Handle<Name> name, Handle<Code> code)
9650       : name_(name), flags_(code->flags()), code_(code) {
9651     DCHECK(name_->IsUniqueName());
9652   }
9653 
IsMatch(Object * other)9654   bool IsMatch(Object* other) override {
9655     DCHECK(other->IsFixedArray());
9656     FixedArray* pair = FixedArray::cast(other);
9657     Name* name = Name::cast(pair->get(0));
9658     Code::Flags flags = Code::cast(pair->get(1))->flags();
9659     if (flags != flags_) return false;
9660     DCHECK(name->IsUniqueName());
9661     return *name_ == name;
9662   }
9663 
NameFlagsHashHelper(Name * name,Code::Flags flags)9664   static uint32_t NameFlagsHashHelper(Name* name, Code::Flags flags) {
9665     return name->Hash() ^ flags;
9666   }
9667 
Hash()9668   uint32_t Hash() override { return NameFlagsHashHelper(*name_, flags_); }
9669 
HashForObject(Object * obj)9670   uint32_t HashForObject(Object* obj) override {
9671     FixedArray* pair = FixedArray::cast(obj);
9672     Name* name = Name::cast(pair->get(0));
9673     Code* code = Code::cast(pair->get(1));
9674     return NameFlagsHashHelper(name, code->flags());
9675   }
9676 
AsHandle(Isolate * isolate)9677   MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) override {
9678     Handle<Code> code = code_.ToHandleChecked();
9679     Handle<FixedArray> pair = isolate->factory()->NewFixedArray(2);
9680     pair->set(0, *name_);
9681     pair->set(1, *code);
9682     return pair;
9683   }
9684 
9685  private:
9686   Handle<Name> name_;
9687   Code::Flags flags_;
9688   // TODO(jkummerow): We should be able to get by without this.
9689   MaybeHandle<Code> code_;
9690 };
9691 
9692 
Put(Handle<CodeCacheHashTable> cache,Handle<Name> name,Handle<Code> code)9693 Handle<CodeCacheHashTable> CodeCacheHashTable::Put(
9694     Handle<CodeCacheHashTable> cache, Handle<Name> name, Handle<Code> code) {
9695   CodeCacheHashTableKey key(name, code);
9696 
9697   Handle<CodeCacheHashTable> new_cache = EnsureCapacity(cache, 1, &key);
9698 
9699   int entry = new_cache->FindInsertionEntry(key.Hash());
9700   Handle<Object> k = key.AsHandle(cache->GetIsolate());
9701 
9702   new_cache->set(EntryToIndex(entry), *k);
9703   new_cache->ElementAdded();
9704   return new_cache;
9705 }
9706 
Lookup(Name * name,Code::Flags flags)9707 Code* CodeCacheHashTable::Lookup(Name* name, Code::Flags flags) {
9708   DisallowHeapAllocation no_alloc;
9709   CodeCacheHashTableKey key(handle(name), flags);
9710   int entry = FindEntry(&key);
9711   if (entry == kNotFound) return nullptr;
9712   return Code::cast(FixedArray::cast(get(EntryToIndex(entry)))->get(1));
9713 }
9714 
SetAndGrow(Handle<FixedArray> array,int index,Handle<Object> value)9715 Handle<FixedArray> FixedArray::SetAndGrow(Handle<FixedArray> array, int index,
9716                                           Handle<Object> value) {
9717   if (index < array->length()) {
9718     array->set(index, *value);
9719     return array;
9720   }
9721   int capacity = array->length();
9722   do {
9723     capacity = JSObject::NewElementsCapacity(capacity);
9724   } while (capacity <= index);
9725   Handle<FixedArray> new_array =
9726       array->GetIsolate()->factory()->NewUninitializedFixedArray(capacity);
9727   array->CopyTo(0, *new_array, 0, array->length());
9728   new_array->FillWithHoles(array->length(), new_array->length());
9729   new_array->set(index, *value);
9730   return new_array;
9731 }
9732 
Shrink(int new_length)9733 void FixedArray::Shrink(int new_length) {
9734   DCHECK(0 <= new_length && new_length <= length());
9735   if (new_length < length()) {
9736     GetHeap()->RightTrimFixedArray(this, length() - new_length);
9737   }
9738 }
9739 
9740 
CopyTo(int pos,FixedArray * dest,int dest_pos,int len)9741 void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
9742   DisallowHeapAllocation no_gc;
9743   WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
9744   for (int index = 0; index < len; index++) {
9745     dest->set(dest_pos+index, get(pos+index), mode);
9746   }
9747 }
9748 
9749 #ifdef DEBUG
IsEqualTo(FixedArray * other)9750 bool FixedArray::IsEqualTo(FixedArray* other) {
9751   if (length() != other->length()) return false;
9752   for (int i = 0 ; i < length(); ++i) {
9753     if (get(i) != other->get(i)) return false;
9754   }
9755   return true;
9756 }
9757 #endif
9758 
9759 
9760 // static
Set(Handle<WeakFixedArray> array,int index,Handle<HeapObject> value)9761 void WeakFixedArray::Set(Handle<WeakFixedArray> array, int index,
9762                          Handle<HeapObject> value) {
9763   DCHECK(array->IsEmptySlot(index));  // Don't overwrite anything.
9764   Handle<WeakCell> cell =
9765       value->IsMap() ? Map::WeakCellForMap(Handle<Map>::cast(value))
9766                      : array->GetIsolate()->factory()->NewWeakCell(value);
9767   Handle<FixedArray>::cast(array)->set(index + kFirstIndex, *cell);
9768   if (FLAG_trace_weak_arrays) {
9769     PrintF("[WeakFixedArray: storing at index %d ]\n", index);
9770   }
9771   array->set_last_used_index(index);
9772 }
9773 
9774 
9775 // static
Add(Handle<Object> maybe_array,Handle<HeapObject> value,int * assigned_index)9776 Handle<WeakFixedArray> WeakFixedArray::Add(Handle<Object> maybe_array,
9777                                            Handle<HeapObject> value,
9778                                            int* assigned_index) {
9779   Handle<WeakFixedArray> array =
9780       (maybe_array.is_null() || !maybe_array->IsWeakFixedArray())
9781           ? Allocate(value->GetIsolate(), 1, Handle<WeakFixedArray>::null())
9782           : Handle<WeakFixedArray>::cast(maybe_array);
9783   // Try to store the new entry if there's room. Optimize for consecutive
9784   // accesses.
9785   int first_index = array->last_used_index();
9786   int length = array->Length();
9787   if (length > 0) {
9788     for (int i = first_index;;) {
9789       if (array->IsEmptySlot((i))) {
9790         WeakFixedArray::Set(array, i, value);
9791         if (assigned_index != NULL) *assigned_index = i;
9792         return array;
9793       }
9794       if (FLAG_trace_weak_arrays) {
9795         PrintF("[WeakFixedArray: searching for free slot]\n");
9796       }
9797       i = (i + 1) % length;
9798       if (i == first_index) break;
9799     }
9800   }
9801 
9802   // No usable slot found, grow the array.
9803   int new_length = length == 0 ? 1 : length + (length >> 1) + 4;
9804   Handle<WeakFixedArray> new_array =
9805       Allocate(array->GetIsolate(), new_length, array);
9806   if (FLAG_trace_weak_arrays) {
9807     PrintF("[WeakFixedArray: growing to size %d ]\n", new_length);
9808   }
9809   WeakFixedArray::Set(new_array, length, value);
9810   if (assigned_index != NULL) *assigned_index = length;
9811   return new_array;
9812 }
9813 
9814 
9815 template <class CompactionCallback>
Compact()9816 void WeakFixedArray::Compact() {
9817   FixedArray* array = FixedArray::cast(this);
9818   int new_length = kFirstIndex;
9819   for (int i = kFirstIndex; i < array->length(); i++) {
9820     Object* element = array->get(i);
9821     if (element->IsSmi()) continue;
9822     if (WeakCell::cast(element)->cleared()) continue;
9823     Object* value = WeakCell::cast(element)->value();
9824     CompactionCallback::Callback(value, i - kFirstIndex,
9825                                  new_length - kFirstIndex);
9826     array->set(new_length++, element);
9827   }
9828   array->Shrink(new_length);
9829   set_last_used_index(0);
9830 }
9831 
9832 
Reset(Object * maybe_array)9833 void WeakFixedArray::Iterator::Reset(Object* maybe_array) {
9834   if (maybe_array->IsWeakFixedArray()) {
9835     list_ = WeakFixedArray::cast(maybe_array);
9836     index_ = 0;
9837 #ifdef DEBUG
9838     last_used_index_ = list_->last_used_index();
9839 #endif  // DEBUG
9840   }
9841 }
9842 
9843 
Callback(Object * value,int old_index,int new_index)9844 void JSObject::PrototypeRegistryCompactionCallback::Callback(Object* value,
9845                                                              int old_index,
9846                                                              int new_index) {
9847   DCHECK(value->IsMap() && Map::cast(value)->is_prototype_map());
9848   Map* map = Map::cast(value);
9849   DCHECK(map->prototype_info()->IsPrototypeInfo());
9850   PrototypeInfo* proto_info = PrototypeInfo::cast(map->prototype_info());
9851   DCHECK_EQ(old_index, proto_info->registry_slot());
9852   proto_info->set_registry_slot(new_index);
9853 }
9854 
9855 
9856 template void WeakFixedArray::Compact<WeakFixedArray::NullCallback>();
9857 template void
9858 WeakFixedArray::Compact<JSObject::PrototypeRegistryCompactionCallback>();
9859 
9860 
Remove(Handle<HeapObject> value)9861 bool WeakFixedArray::Remove(Handle<HeapObject> value) {
9862   if (Length() == 0) return false;
9863   // Optimize for the most recently added element to be removed again.
9864   int first_index = last_used_index();
9865   for (int i = first_index;;) {
9866     if (Get(i) == *value) {
9867       Clear(i);
9868       // Users of WeakFixedArray should make sure that there are no duplicates.
9869       return true;
9870     }
9871     i = (i + 1) % Length();
9872     if (i == first_index) return false;
9873   }
9874   UNREACHABLE();
9875 }
9876 
9877 
9878 // static
Allocate(Isolate * isolate,int size,Handle<WeakFixedArray> initialize_from)9879 Handle<WeakFixedArray> WeakFixedArray::Allocate(
9880     Isolate* isolate, int size, Handle<WeakFixedArray> initialize_from) {
9881   DCHECK(0 <= size);
9882   Handle<FixedArray> result =
9883       isolate->factory()->NewUninitializedFixedArray(size + kFirstIndex);
9884   int index = 0;
9885   if (!initialize_from.is_null()) {
9886     DCHECK(initialize_from->Length() <= size);
9887     Handle<FixedArray> raw_source = Handle<FixedArray>::cast(initialize_from);
9888     // Copy the entries without compacting, since the PrototypeInfo relies on
9889     // the index of the entries not to change.
9890     while (index < raw_source->length()) {
9891       result->set(index, raw_source->get(index));
9892       index++;
9893     }
9894   }
9895   while (index < result->length()) {
9896     result->set(index, Smi::kZero);
9897     index++;
9898   }
9899   return Handle<WeakFixedArray>::cast(result);
9900 }
9901 
9902 
Add(Handle<ArrayList> array,Handle<Object> obj,AddMode mode)9903 Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj,
9904                                  AddMode mode) {
9905   int length = array->Length();
9906   array = EnsureSpace(array, length + 1);
9907   if (mode == kReloadLengthAfterAllocation) {
9908     DCHECK(array->Length() <= length);
9909     length = array->Length();
9910   }
9911   array->Set(length, *obj);
9912   array->SetLength(length + 1);
9913   return array;
9914 }
9915 
Add(Handle<ArrayList> array,Handle<Object> obj1,Handle<Object> obj2,AddMode mode)9916 Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj1,
9917                                  Handle<Object> obj2, AddMode mode) {
9918   int length = array->Length();
9919   array = EnsureSpace(array, length + 2);
9920   if (mode == kReloadLengthAfterAllocation) {
9921     length = array->Length();
9922   }
9923   array->Set(length, *obj1);
9924   array->Set(length + 1, *obj2);
9925   array->SetLength(length + 2);
9926   return array;
9927 }
9928 
New(Isolate * isolate,int size)9929 Handle<ArrayList> ArrayList::New(Isolate* isolate, int size) {
9930   Handle<ArrayList> result = Handle<ArrayList>::cast(
9931       isolate->factory()->NewFixedArray(size + kFirstIndex));
9932   result->SetLength(0);
9933   return result;
9934 }
9935 
IsFull()9936 bool ArrayList::IsFull() {
9937   int capacity = length();
9938   return kFirstIndex + Length() == capacity;
9939 }
9940 
9941 namespace {
9942 
EnsureSpaceInFixedArray(Handle<FixedArray> array,int length)9943 Handle<FixedArray> EnsureSpaceInFixedArray(Handle<FixedArray> array,
9944                                            int length) {
9945   int capacity = array->length();
9946   if (capacity < length) {
9947     Isolate* isolate = array->GetIsolate();
9948     int new_capacity = length;
9949     new_capacity = new_capacity + Max(new_capacity / 2, 2);
9950     int grow_by = new_capacity - capacity;
9951     array = Handle<ArrayList>::cast(
9952         isolate->factory()->CopyFixedArrayAndGrow(array, grow_by));
9953   }
9954   return array;
9955 }
9956 
9957 }  // namespace
9958 
EnsureSpace(Handle<ArrayList> array,int length)9959 Handle<ArrayList> ArrayList::EnsureSpace(Handle<ArrayList> array, int length) {
9960   const bool empty = (array->length() == 0);
9961   auto ret = Handle<ArrayList>::cast(
9962       EnsureSpaceInFixedArray(array, kFirstIndex + length));
9963   if (empty) ret->SetLength(0);
9964   return ret;
9965 }
9966 
ReserveCaptures(Handle<RegExpMatchInfo> match_info,int capture_count)9967 Handle<RegExpMatchInfo> RegExpMatchInfo::ReserveCaptures(
9968     Handle<RegExpMatchInfo> match_info, int capture_count) {
9969   DCHECK_GE(match_info->length(), kLastMatchOverhead);
9970   const int required_length = kFirstCaptureIndex + capture_count;
9971   Handle<FixedArray> result =
9972       EnsureSpaceInFixedArray(match_info, required_length);
9973   return Handle<RegExpMatchInfo>::cast(result);
9974 }
9975 
9976 // static
AppendJSFrame(Handle<FrameArray> in,Handle<Object> receiver,Handle<JSFunction> function,Handle<AbstractCode> code,int offset,int flags)9977 Handle<FrameArray> FrameArray::AppendJSFrame(Handle<FrameArray> in,
9978                                              Handle<Object> receiver,
9979                                              Handle<JSFunction> function,
9980                                              Handle<AbstractCode> code,
9981                                              int offset, int flags) {
9982   const int frame_count = in->FrameCount();
9983   const int new_length = LengthFor(frame_count + 1);
9984   Handle<FrameArray> array = EnsureSpace(in, new_length);
9985   array->SetReceiver(frame_count, *receiver);
9986   array->SetFunction(frame_count, *function);
9987   array->SetCode(frame_count, *code);
9988   array->SetOffset(frame_count, Smi::FromInt(offset));
9989   array->SetFlags(frame_count, Smi::FromInt(flags));
9990   array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));
9991   return array;
9992 }
9993 
9994 // static
AppendWasmFrame(Handle<FrameArray> in,Handle<Object> wasm_instance,int wasm_function_index,Handle<AbstractCode> code,int offset,int flags)9995 Handle<FrameArray> FrameArray::AppendWasmFrame(Handle<FrameArray> in,
9996                                                Handle<Object> wasm_instance,
9997                                                int wasm_function_index,
9998                                                Handle<AbstractCode> code,
9999                                                int offset, int flags) {
10000   const int frame_count = in->FrameCount();
10001   const int new_length = LengthFor(frame_count + 1);
10002   Handle<FrameArray> array = EnsureSpace(in, new_length);
10003   array->SetWasmInstance(frame_count, *wasm_instance);
10004   array->SetWasmFunctionIndex(frame_count, Smi::FromInt(wasm_function_index));
10005   array->SetCode(frame_count, *code);
10006   array->SetOffset(frame_count, Smi::FromInt(offset));
10007   array->SetFlags(frame_count, Smi::FromInt(flags));
10008   array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));
10009   return array;
10010 }
10011 
ShrinkToFit()10012 void FrameArray::ShrinkToFit() { Shrink(LengthFor(FrameCount())); }
10013 
10014 // static
EnsureSpace(Handle<FrameArray> array,int length)10015 Handle<FrameArray> FrameArray::EnsureSpace(Handle<FrameArray> array,
10016                                            int length) {
10017   return Handle<FrameArray>::cast(EnsureSpaceInFixedArray(array, length));
10018 }
10019 
Allocate(Isolate * isolate,int number_of_descriptors,int slack,PretenureFlag pretenure)10020 Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate,
10021                                                   int number_of_descriptors,
10022                                                   int slack,
10023                                                   PretenureFlag pretenure) {
10024   DCHECK(0 <= number_of_descriptors);
10025   Factory* factory = isolate->factory();
10026   // Do not use DescriptorArray::cast on incomplete object.
10027   int size = number_of_descriptors + slack;
10028   if (size == 0) return factory->empty_descriptor_array();
10029   // Allocate the array of keys.
10030   Handle<FixedArray> result =
10031       factory->NewFixedArray(LengthFor(size), pretenure);
10032 
10033   result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors));
10034   result->set(kEnumCacheIndex, Smi::kZero);
10035   return Handle<DescriptorArray>::cast(result);
10036 }
10037 
ClearEnumCache()10038 void DescriptorArray::ClearEnumCache() { set(kEnumCacheIndex, Smi::kZero); }
10039 
Replace(int index,Descriptor * descriptor)10040 void DescriptorArray::Replace(int index, Descriptor* descriptor) {
10041   descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index));
10042   Set(index, descriptor);
10043 }
10044 
10045 
10046 // static
SetEnumCache(Handle<DescriptorArray> descriptors,Isolate * isolate,Handle<FixedArray> new_cache,Handle<FixedArray> new_index_cache)10047 void DescriptorArray::SetEnumCache(Handle<DescriptorArray> descriptors,
10048                                    Isolate* isolate,
10049                                    Handle<FixedArray> new_cache,
10050                                    Handle<FixedArray> new_index_cache) {
10051   DCHECK(!descriptors->IsEmpty());
10052   FixedArray* bridge_storage;
10053   bool needs_new_enum_cache = !descriptors->HasEnumCache();
10054   if (needs_new_enum_cache) {
10055     bridge_storage = *isolate->factory()->NewFixedArray(
10056         DescriptorArray::kEnumCacheBridgeLength);
10057   } else {
10058     bridge_storage = FixedArray::cast(descriptors->get(kEnumCacheIndex));
10059   }
10060   bridge_storage->set(kEnumCacheBridgeCacheIndex, *new_cache);
10061   bridge_storage->set(
10062       kEnumCacheBridgeIndicesCacheIndex,
10063       new_index_cache.is_null() ? Object::cast(Smi::kZero) : *new_index_cache);
10064   if (needs_new_enum_cache) {
10065     descriptors->set(kEnumCacheIndex, bridge_storage);
10066   }
10067 }
10068 
CopyFrom(int index,DescriptorArray * src)10069 void DescriptorArray::CopyFrom(int index, DescriptorArray* src) {
10070   PropertyDetails details = src->GetDetails(index);
10071   Set(index, src->GetKey(index), src->GetValue(index), details);
10072 }
10073 
Sort()10074 void DescriptorArray::Sort() {
10075   // In-place heap sort.
10076   int len = number_of_descriptors();
10077   // Reset sorting since the descriptor array might contain invalid pointers.
10078   for (int i = 0; i < len; ++i) SetSortedKey(i, i);
10079   // Bottom-up max-heap construction.
10080   // Index of the last node with children
10081   const int max_parent_index = (len / 2) - 1;
10082   for (int i = max_parent_index; i >= 0; --i) {
10083     int parent_index = i;
10084     const uint32_t parent_hash = GetSortedKey(i)->Hash();
10085     while (parent_index <= max_parent_index) {
10086       int child_index = 2 * parent_index + 1;
10087       uint32_t child_hash = GetSortedKey(child_index)->Hash();
10088       if (child_index + 1 < len) {
10089         uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
10090         if (right_child_hash > child_hash) {
10091           child_index++;
10092           child_hash = right_child_hash;
10093         }
10094       }
10095       if (child_hash <= parent_hash) break;
10096       SwapSortedKeys(parent_index, child_index);
10097       // Now element at child_index could be < its children.
10098       parent_index = child_index;  // parent_hash remains correct.
10099     }
10100   }
10101 
10102   // Extract elements and create sorted array.
10103   for (int i = len - 1; i > 0; --i) {
10104     // Put max element at the back of the array.
10105     SwapSortedKeys(0, i);
10106     // Shift down the new top element.
10107     int parent_index = 0;
10108     const uint32_t parent_hash = GetSortedKey(parent_index)->Hash();
10109     const int max_parent_index = (i / 2) - 1;
10110     while (parent_index <= max_parent_index) {
10111       int child_index = parent_index * 2 + 1;
10112       uint32_t child_hash = GetSortedKey(child_index)->Hash();
10113       if (child_index + 1 < i) {
10114         uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
10115         if (right_child_hash > child_hash) {
10116           child_index++;
10117           child_hash = right_child_hash;
10118         }
10119       }
10120       if (child_hash <= parent_hash) break;
10121       SwapSortedKeys(parent_index, child_index);
10122       parent_index = child_index;
10123     }
10124   }
10125   DCHECK(IsSortedNoDuplicates());
10126 }
10127 
10128 
Copy(Handle<AccessorPair> pair)10129 Handle<AccessorPair> AccessorPair::Copy(Handle<AccessorPair> pair) {
10130   Handle<AccessorPair> copy = pair->GetIsolate()->factory()->NewAccessorPair();
10131   copy->set_getter(pair->getter());
10132   copy->set_setter(pair->setter());
10133   return copy;
10134 }
10135 
GetComponent(Handle<AccessorPair> accessor_pair,AccessorComponent component)10136 Handle<Object> AccessorPair::GetComponent(Handle<AccessorPair> accessor_pair,
10137                                           AccessorComponent component) {
10138   Object* accessor = accessor_pair->get(component);
10139   if (accessor->IsFunctionTemplateInfo()) {
10140     return ApiNatives::InstantiateFunction(
10141                handle(FunctionTemplateInfo::cast(accessor)))
10142         .ToHandleChecked();
10143   }
10144   Isolate* isolate = accessor_pair->GetIsolate();
10145   if (accessor->IsNull(isolate)) {
10146     return isolate->factory()->undefined_value();
10147   }
10148   return handle(accessor, isolate);
10149 }
10150 
New(Isolate * isolate,int deopt_entry_count,PretenureFlag pretenure)10151 Handle<DeoptimizationInputData> DeoptimizationInputData::New(
10152     Isolate* isolate, int deopt_entry_count, PretenureFlag pretenure) {
10153   return Handle<DeoptimizationInputData>::cast(
10154       isolate->factory()->NewFixedArray(LengthFor(deopt_entry_count),
10155                                         pretenure));
10156 }
10157 
10158 
New(Isolate * isolate,int number_of_deopt_points,PretenureFlag pretenure)10159 Handle<DeoptimizationOutputData> DeoptimizationOutputData::New(
10160     Isolate* isolate,
10161     int number_of_deopt_points,
10162     PretenureFlag pretenure) {
10163   Handle<FixedArray> result;
10164   if (number_of_deopt_points == 0) {
10165     result = isolate->factory()->empty_fixed_array();
10166   } else {
10167     result = isolate->factory()->NewFixedArray(
10168         LengthOfFixedArray(number_of_deopt_points), pretenure);
10169   }
10170   return Handle<DeoptimizationOutputData>::cast(result);
10171 }
10172 
GetInlinedFunction(int index)10173 SharedFunctionInfo* DeoptimizationInputData::GetInlinedFunction(int index) {
10174   if (index == -1) {
10175     return SharedFunctionInfo::cast(SharedFunctionInfo());
10176   } else {
10177     return SharedFunctionInfo::cast(LiteralArray()->get(index));
10178   }
10179 }
10180 
LookupRange(int pc_offset,int * data_out,CatchPrediction * prediction_out)10181 int HandlerTable::LookupRange(int pc_offset, int* data_out,
10182                               CatchPrediction* prediction_out) {
10183   int innermost_handler = -1;
10184 #ifdef DEBUG
10185   // Assuming that ranges are well nested, we don't need to track the innermost
10186   // offsets. This is just to verify that the table is actually well nested.
10187   int innermost_start = std::numeric_limits<int>::min();
10188   int innermost_end = std::numeric_limits<int>::max();
10189 #endif
10190   for (int i = 0; i < length(); i += kRangeEntrySize) {
10191     int start_offset = Smi::cast(get(i + kRangeStartIndex))->value();
10192     int end_offset = Smi::cast(get(i + kRangeEndIndex))->value();
10193     int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value();
10194     int handler_offset = HandlerOffsetField::decode(handler_field);
10195     CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
10196     int handler_data = Smi::cast(get(i + kRangeDataIndex))->value();
10197     if (pc_offset >= start_offset && pc_offset < end_offset) {
10198       DCHECK_GE(start_offset, innermost_start);
10199       DCHECK_LT(end_offset, innermost_end);
10200       innermost_handler = handler_offset;
10201 #ifdef DEBUG
10202       innermost_start = start_offset;
10203       innermost_end = end_offset;
10204 #endif
10205       if (data_out) *data_out = handler_data;
10206       if (prediction_out) *prediction_out = prediction;
10207     }
10208   }
10209   return innermost_handler;
10210 }
10211 
10212 
10213 // TODO(turbofan): Make sure table is sorted and use binary search.
LookupReturn(int pc_offset)10214 int HandlerTable::LookupReturn(int pc_offset) {
10215   for (int i = 0; i < length(); i += kReturnEntrySize) {
10216     int return_offset = Smi::cast(get(i + kReturnOffsetIndex))->value();
10217     int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value();
10218     if (pc_offset == return_offset) {
10219       return HandlerOffsetField::decode(handler_field);
10220     }
10221   }
10222   return -1;
10223 }
10224 
10225 
10226 #ifdef DEBUG
IsEqualTo(DescriptorArray * other)10227 bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
10228   if (IsEmpty()) return other->IsEmpty();
10229   if (other->IsEmpty()) return false;
10230   if (length() != other->length()) return false;
10231   for (int i = 0; i < length(); ++i) {
10232     if (get(i) != other->get(i)) return false;
10233   }
10234   return true;
10235 }
10236 #endif
10237 
10238 // static
Trim(Handle<String> string,TrimMode mode)10239 Handle<String> String::Trim(Handle<String> string, TrimMode mode) {
10240   Isolate* const isolate = string->GetIsolate();
10241   string = String::Flatten(string);
10242   int const length = string->length();
10243 
10244   // Perform left trimming if requested.
10245   int left = 0;
10246   UnicodeCache* unicode_cache = isolate->unicode_cache();
10247   if (mode == kTrim || mode == kTrimLeft) {
10248     while (left < length &&
10249            unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) {
10250       left++;
10251     }
10252   }
10253 
10254   // Perform right trimming if requested.
10255   int right = length;
10256   if (mode == kTrim || mode == kTrimRight) {
10257     while (
10258         right > left &&
10259         unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) {
10260       right--;
10261     }
10262   }
10263 
10264   return isolate->factory()->NewSubString(string, left, right);
10265 }
10266 
LooksValid()10267 bool String::LooksValid() { return GetIsolate()->heap()->Contains(this); }
10268 
10269 // static
ToFunctionName(Handle<Name> name)10270 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) {
10271   if (name->IsString()) return Handle<String>::cast(name);
10272   // ES6 section 9.2.11 SetFunctionName, step 4.
10273   Isolate* const isolate = name->GetIsolate();
10274   Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate);
10275   if (description->IsUndefined(isolate)) {
10276     return isolate->factory()->empty_string();
10277   }
10278   IncrementalStringBuilder builder(isolate);
10279   builder.AppendCharacter('[');
10280   builder.AppendString(Handle<String>::cast(description));
10281   builder.AppendCharacter(']');
10282   return builder.Finish();
10283 }
10284 
10285 // static
ToFunctionName(Handle<Name> name,Handle<String> prefix)10286 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name,
10287                                          Handle<String> prefix) {
10288   Handle<String> name_string;
10289   Isolate* const isolate = name->GetIsolate();
10290   ASSIGN_RETURN_ON_EXCEPTION(isolate, name_string, ToFunctionName(name),
10291                              String);
10292   IncrementalStringBuilder builder(isolate);
10293   builder.AppendString(prefix);
10294   builder.AppendCharacter(' ');
10295   builder.AppendString(name_string);
10296   return builder.Finish();
10297 }
10298 
10299 namespace {
10300 
AreDigits(const uint8_t * s,int from,int to)10301 bool AreDigits(const uint8_t* s, int from, int to) {
10302   for (int i = from; i < to; i++) {
10303     if (s[i] < '0' || s[i] > '9') return false;
10304   }
10305 
10306   return true;
10307 }
10308 
10309 
ParseDecimalInteger(const uint8_t * s,int from,int to)10310 int ParseDecimalInteger(const uint8_t* s, int from, int to) {
10311   DCHECK(to - from < 10);  // Overflow is not possible.
10312   DCHECK(from < to);
10313   int d = s[from] - '0';
10314 
10315   for (int i = from + 1; i < to; i++) {
10316     d = 10 * d + (s[i] - '0');
10317   }
10318 
10319   return d;
10320 }
10321 
10322 }  // namespace
10323 
10324 
10325 // static
ToNumber(Handle<String> subject)10326 Handle<Object> String::ToNumber(Handle<String> subject) {
10327   Isolate* const isolate = subject->GetIsolate();
10328 
10329   // Flatten {subject} string first.
10330   subject = String::Flatten(subject);
10331 
10332   // Fast array index case.
10333   uint32_t index;
10334   if (subject->AsArrayIndex(&index)) {
10335     return isolate->factory()->NewNumberFromUint(index);
10336   }
10337 
10338   // Fast case: short integer or some sorts of junk values.
10339   if (subject->IsSeqOneByteString()) {
10340     int len = subject->length();
10341     if (len == 0) return handle(Smi::kZero, isolate);
10342 
10343     DisallowHeapAllocation no_gc;
10344     uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars();
10345     bool minus = (data[0] == '-');
10346     int start_pos = (minus ? 1 : 0);
10347 
10348     if (start_pos == len) {
10349       return isolate->factory()->nan_value();
10350     } else if (data[start_pos] > '9') {
10351       // Fast check for a junk value. A valid string may start from a
10352       // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit
10353       // or the 'I' character ('Infinity'). All of that have codes not greater
10354       // than '9' except 'I' and &nbsp;.
10355       if (data[start_pos] != 'I' && data[start_pos] != 0xa0) {
10356         return isolate->factory()->nan_value();
10357       }
10358     } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
10359       // The maximal/minimal smi has 10 digits. If the string has less digits
10360       // we know it will fit into the smi-data type.
10361       int d = ParseDecimalInteger(data, start_pos, len);
10362       if (minus) {
10363         if (d == 0) return isolate->factory()->minus_zero_value();
10364         d = -d;
10365       } else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize &&
10366                  (len == 1 || data[0] != '0')) {
10367         // String hash is not calculated yet but all the data are present.
10368         // Update the hash field to speed up sequential convertions.
10369         uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
10370 #ifdef DEBUG
10371         subject->Hash();  // Force hash calculation.
10372         DCHECK_EQ(static_cast<int>(subject->hash_field()),
10373                   static_cast<int>(hash));
10374 #endif
10375         subject->set_hash_field(hash);
10376       }
10377       return handle(Smi::FromInt(d), isolate);
10378     }
10379   }
10380 
10381   // Slower case.
10382   int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY;
10383   return isolate->factory()->NewNumber(
10384       StringToDouble(isolate->unicode_cache(), subject, flags));
10385 }
10386 
10387 
GetFlatContent()10388 String::FlatContent String::GetFlatContent() {
10389   DCHECK(!AllowHeapAllocation::IsAllowed());
10390   int length = this->length();
10391   StringShape shape(this);
10392   String* string = this;
10393   int offset = 0;
10394   if (shape.representation_tag() == kConsStringTag) {
10395     ConsString* cons = ConsString::cast(string);
10396     if (cons->second()->length() != 0) {
10397       return FlatContent();
10398     }
10399     string = cons->first();
10400     shape = StringShape(string);
10401   } else if (shape.representation_tag() == kSlicedStringTag) {
10402     SlicedString* slice = SlicedString::cast(string);
10403     offset = slice->offset();
10404     string = slice->parent();
10405     shape = StringShape(string);
10406     DCHECK(shape.representation_tag() != kConsStringTag &&
10407            shape.representation_tag() != kSlicedStringTag);
10408   }
10409   if (shape.representation_tag() == kThinStringTag) {
10410     ThinString* thin = ThinString::cast(string);
10411     string = thin->actual();
10412     shape = StringShape(string);
10413     DCHECK(!shape.IsCons());
10414     DCHECK(!shape.IsSliced());
10415   }
10416   if (shape.encoding_tag() == kOneByteStringTag) {
10417     const uint8_t* start;
10418     if (shape.representation_tag() == kSeqStringTag) {
10419       start = SeqOneByteString::cast(string)->GetChars();
10420     } else {
10421       start = ExternalOneByteString::cast(string)->GetChars();
10422     }
10423     return FlatContent(start + offset, length);
10424   } else {
10425     DCHECK(shape.encoding_tag() == kTwoByteStringTag);
10426     const uc16* start;
10427     if (shape.representation_tag() == kSeqStringTag) {
10428       start = SeqTwoByteString::cast(string)->GetChars();
10429     } else {
10430       start = ExternalTwoByteString::cast(string)->GetChars();
10431     }
10432     return FlatContent(start + offset, length);
10433   }
10434 }
10435 
ToCString(AllowNullsFlag allow_nulls,RobustnessFlag robust_flag,int offset,int length,int * length_return)10436 std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
10437                                           RobustnessFlag robust_flag,
10438                                           int offset, int length,
10439                                           int* length_return) {
10440   if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
10441     return std::unique_ptr<char[]>();
10442   }
10443   // Negative length means the to the end of the string.
10444   if (length < 0) length = kMaxInt - offset;
10445 
10446   // Compute the size of the UTF-8 string. Start at the specified offset.
10447   StringCharacterStream stream(this, offset);
10448   int character_position = offset;
10449   int utf8_bytes = 0;
10450   int last = unibrow::Utf16::kNoPreviousCharacter;
10451   while (stream.HasMore() && character_position++ < offset + length) {
10452     uint16_t character = stream.GetNext();
10453     utf8_bytes += unibrow::Utf8::Length(character, last);
10454     last = character;
10455   }
10456 
10457   if (length_return) {
10458     *length_return = utf8_bytes;
10459   }
10460 
10461   char* result = NewArray<char>(utf8_bytes + 1);
10462 
10463   // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
10464   stream.Reset(this, offset);
10465   character_position = offset;
10466   int utf8_byte_position = 0;
10467   last = unibrow::Utf16::kNoPreviousCharacter;
10468   while (stream.HasMore() && character_position++ < offset + length) {
10469     uint16_t character = stream.GetNext();
10470     if (allow_nulls == DISALLOW_NULLS && character == 0) {
10471       character = ' ';
10472     }
10473     utf8_byte_position +=
10474         unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
10475     last = character;
10476   }
10477   result[utf8_byte_position] = 0;
10478   return std::unique_ptr<char[]>(result);
10479 }
10480 
ToCString(AllowNullsFlag allow_nulls,RobustnessFlag robust_flag,int * length_return)10481 std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
10482                                           RobustnessFlag robust_flag,
10483                                           int* length_return) {
10484   return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
10485 }
10486 
10487 
GetTwoByteData(unsigned start)10488 const uc16* String::GetTwoByteData(unsigned start) {
10489   DCHECK(!IsOneByteRepresentationUnderneath());
10490   switch (StringShape(this).representation_tag()) {
10491     case kSeqStringTag:
10492       return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
10493     case kExternalStringTag:
10494       return ExternalTwoByteString::cast(this)->
10495         ExternalTwoByteStringGetData(start);
10496     case kSlicedStringTag: {
10497       SlicedString* slice = SlicedString::cast(this);
10498       return slice->parent()->GetTwoByteData(start + slice->offset());
10499     }
10500     case kConsStringTag:
10501     case kThinStringTag:
10502       UNREACHABLE();
10503       return NULL;
10504   }
10505   UNREACHABLE();
10506   return NULL;
10507 }
10508 
10509 
SeqTwoByteStringGetData(unsigned start)10510 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
10511   return reinterpret_cast<uc16*>(
10512       reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
10513 }
10514 
10515 
PostGarbageCollectionProcessing(Isolate * isolate)10516 void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) {
10517   Relocatable* current = isolate->relocatable_top();
10518   while (current != NULL) {
10519     current->PostGarbageCollection();
10520     current = current->prev_;
10521   }
10522 }
10523 
10524 
10525 // Reserve space for statics needing saving and restoring.
ArchiveSpacePerThread()10526 int Relocatable::ArchiveSpacePerThread() {
10527   return sizeof(Relocatable*);  // NOLINT
10528 }
10529 
10530 
10531 // Archive statics that are thread-local.
ArchiveState(Isolate * isolate,char * to)10532 char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
10533   *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
10534   isolate->set_relocatable_top(NULL);
10535   return to + ArchiveSpacePerThread();
10536 }
10537 
10538 
10539 // Restore statics that are thread-local.
RestoreState(Isolate * isolate,char * from)10540 char* Relocatable::RestoreState(Isolate* isolate, char* from) {
10541   isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
10542   return from + ArchiveSpacePerThread();
10543 }
10544 
10545 
Iterate(ObjectVisitor * v,char * thread_storage)10546 char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
10547   Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
10548   Iterate(v, top);
10549   return thread_storage + ArchiveSpacePerThread();
10550 }
10551 
10552 
Iterate(Isolate * isolate,ObjectVisitor * v)10553 void Relocatable::Iterate(Isolate* isolate, ObjectVisitor* v) {
10554   Iterate(v, isolate->relocatable_top());
10555 }
10556 
10557 
Iterate(ObjectVisitor * v,Relocatable * top)10558 void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
10559   Relocatable* current = top;
10560   while (current != NULL) {
10561     current->IterateInstance(v);
10562     current = current->prev_;
10563   }
10564 }
10565 
10566 
FlatStringReader(Isolate * isolate,Handle<String> str)10567 FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
10568     : Relocatable(isolate),
10569       str_(str.location()),
10570       length_(str->length()) {
10571   PostGarbageCollection();
10572 }
10573 
10574 
FlatStringReader(Isolate * isolate,Vector<const char> input)10575 FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
10576     : Relocatable(isolate),
10577       str_(0),
10578       is_one_byte_(true),
10579       length_(input.length()),
10580       start_(input.start()) {}
10581 
10582 
PostGarbageCollection()10583 void FlatStringReader::PostGarbageCollection() {
10584   if (str_ == NULL) return;
10585   Handle<String> str(str_);
10586   DCHECK(str->IsFlat());
10587   DisallowHeapAllocation no_gc;
10588   // This does not actually prevent the vector from being relocated later.
10589   String::FlatContent content = str->GetFlatContent();
10590   DCHECK(content.IsFlat());
10591   is_one_byte_ = content.IsOneByte();
10592   if (is_one_byte_) {
10593     start_ = content.ToOneByteVector().start();
10594   } else {
10595     start_ = content.ToUC16Vector().start();
10596   }
10597 }
10598 
10599 
Initialize(ConsString * cons_string,int offset)10600 void ConsStringIterator::Initialize(ConsString* cons_string, int offset) {
10601   DCHECK(cons_string != NULL);
10602   root_ = cons_string;
10603   consumed_ = offset;
10604   // Force stack blown condition to trigger restart.
10605   depth_ = 1;
10606   maximum_depth_ = kStackSize + depth_;
10607   DCHECK(StackBlown());
10608 }
10609 
10610 
Continue(int * offset_out)10611 String* ConsStringIterator::Continue(int* offset_out) {
10612   DCHECK(depth_ != 0);
10613   DCHECK_EQ(0, *offset_out);
10614   bool blew_stack = StackBlown();
10615   String* string = NULL;
10616   // Get the next leaf if there is one.
10617   if (!blew_stack) string = NextLeaf(&blew_stack);
10618   // Restart search from root.
10619   if (blew_stack) {
10620     DCHECK(string == NULL);
10621     string = Search(offset_out);
10622   }
10623   // Ensure future calls return null immediately.
10624   if (string == NULL) Reset(NULL);
10625   return string;
10626 }
10627 
10628 
Search(int * offset_out)10629 String* ConsStringIterator::Search(int* offset_out) {
10630   ConsString* cons_string = root_;
10631   // Reset the stack, pushing the root string.
10632   depth_ = 1;
10633   maximum_depth_ = 1;
10634   frames_[0] = cons_string;
10635   const int consumed = consumed_;
10636   int offset = 0;
10637   while (true) {
10638     // Loop until the string is found which contains the target offset.
10639     String* string = cons_string->first();
10640     int length = string->length();
10641     int32_t type;
10642     if (consumed < offset + length) {
10643       // Target offset is in the left branch.
10644       // Keep going if we're still in a ConString.
10645       type = string->map()->instance_type();
10646       if ((type & kStringRepresentationMask) == kConsStringTag) {
10647         cons_string = ConsString::cast(string);
10648         PushLeft(cons_string);
10649         continue;
10650       }
10651       // Tell the stack we're done descending.
10652       AdjustMaximumDepth();
10653     } else {
10654       // Descend right.
10655       // Update progress through the string.
10656       offset += length;
10657       // Keep going if we're still in a ConString.
10658       string = cons_string->second();
10659       type = string->map()->instance_type();
10660       if ((type & kStringRepresentationMask) == kConsStringTag) {
10661         cons_string = ConsString::cast(string);
10662         PushRight(cons_string);
10663         continue;
10664       }
10665       // Need this to be updated for the current string.
10666       length = string->length();
10667       // Account for the possibility of an empty right leaf.
10668       // This happens only if we have asked for an offset outside the string.
10669       if (length == 0) {
10670         // Reset so future operations will return null immediately.
10671         Reset(NULL);
10672         return NULL;
10673       }
10674       // Tell the stack we're done descending.
10675       AdjustMaximumDepth();
10676       // Pop stack so next iteration is in correct place.
10677       Pop();
10678     }
10679     DCHECK(length != 0);
10680     // Adjust return values and exit.
10681     consumed_ = offset + length;
10682     *offset_out = consumed - offset;
10683     return string;
10684   }
10685   UNREACHABLE();
10686   return NULL;
10687 }
10688 
10689 
NextLeaf(bool * blew_stack)10690 String* ConsStringIterator::NextLeaf(bool* blew_stack) {
10691   while (true) {
10692     // Tree traversal complete.
10693     if (depth_ == 0) {
10694       *blew_stack = false;
10695       return NULL;
10696     }
10697     // We've lost track of higher nodes.
10698     if (StackBlown()) {
10699       *blew_stack = true;
10700       return NULL;
10701     }
10702     // Go right.
10703     ConsString* cons_string = frames_[OffsetForDepth(depth_ - 1)];
10704     String* string = cons_string->second();
10705     int32_t type = string->map()->instance_type();
10706     if ((type & kStringRepresentationMask) != kConsStringTag) {
10707       // Pop stack so next iteration is in correct place.
10708       Pop();
10709       int length = string->length();
10710       // Could be a flattened ConsString.
10711       if (length == 0) continue;
10712       consumed_ += length;
10713       return string;
10714     }
10715     cons_string = ConsString::cast(string);
10716     PushRight(cons_string);
10717     // Need to traverse all the way left.
10718     while (true) {
10719       // Continue left.
10720       string = cons_string->first();
10721       type = string->map()->instance_type();
10722       if ((type & kStringRepresentationMask) != kConsStringTag) {
10723         AdjustMaximumDepth();
10724         int length = string->length();
10725         if (length == 0) break;  // Skip empty left-hand sides of ConsStrings.
10726         consumed_ += length;
10727         return string;
10728       }
10729       cons_string = ConsString::cast(string);
10730       PushLeft(cons_string);
10731     }
10732   }
10733   UNREACHABLE();
10734   return NULL;
10735 }
10736 
10737 
ConsStringGet(int index)10738 uint16_t ConsString::ConsStringGet(int index) {
10739   DCHECK(index >= 0 && index < this->length());
10740 
10741   // Check for a flattened cons string
10742   if (second()->length() == 0) {
10743     String* left = first();
10744     return left->Get(index);
10745   }
10746 
10747   String* string = String::cast(this);
10748 
10749   while (true) {
10750     if (StringShape(string).IsCons()) {
10751       ConsString* cons_string = ConsString::cast(string);
10752       String* left = cons_string->first();
10753       if (left->length() > index) {
10754         string = left;
10755       } else {
10756         index -= left->length();
10757         string = cons_string->second();
10758       }
10759     } else {
10760       return string->Get(index);
10761     }
10762   }
10763 
10764   UNREACHABLE();
10765   return 0;
10766 }
10767 
ThinStringGet(int index)10768 uint16_t ThinString::ThinStringGet(int index) { return actual()->Get(index); }
10769 
SlicedStringGet(int index)10770 uint16_t SlicedString::SlicedStringGet(int index) {
10771   return parent()->Get(offset() + index);
10772 }
10773 
10774 
10775 template <typename sinkchar>
WriteToFlat(String * src,sinkchar * sink,int f,int t)10776 void String::WriteToFlat(String* src,
10777                          sinkchar* sink,
10778                          int f,
10779                          int t) {
10780   String* source = src;
10781   int from = f;
10782   int to = t;
10783   while (true) {
10784     DCHECK(0 <= from && from <= to && to <= source->length());
10785     switch (StringShape(source).full_representation_tag()) {
10786       case kOneByteStringTag | kExternalStringTag: {
10787         CopyChars(sink, ExternalOneByteString::cast(source)->GetChars() + from,
10788                   to - from);
10789         return;
10790       }
10791       case kTwoByteStringTag | kExternalStringTag: {
10792         const uc16* data =
10793             ExternalTwoByteString::cast(source)->GetChars();
10794         CopyChars(sink,
10795                   data + from,
10796                   to - from);
10797         return;
10798       }
10799       case kOneByteStringTag | kSeqStringTag: {
10800         CopyChars(sink,
10801                   SeqOneByteString::cast(source)->GetChars() + from,
10802                   to - from);
10803         return;
10804       }
10805       case kTwoByteStringTag | kSeqStringTag: {
10806         CopyChars(sink,
10807                   SeqTwoByteString::cast(source)->GetChars() + from,
10808                   to - from);
10809         return;
10810       }
10811       case kOneByteStringTag | kConsStringTag:
10812       case kTwoByteStringTag | kConsStringTag: {
10813         ConsString* cons_string = ConsString::cast(source);
10814         String* first = cons_string->first();
10815         int boundary = first->length();
10816         if (to - boundary >= boundary - from) {
10817           // Right hand side is longer.  Recurse over left.
10818           if (from < boundary) {
10819             WriteToFlat(first, sink, from, boundary);
10820             if (from == 0 && cons_string->second() == first) {
10821               CopyChars(sink + boundary, sink, boundary);
10822               return;
10823             }
10824             sink += boundary - from;
10825             from = 0;
10826           } else {
10827             from -= boundary;
10828           }
10829           to -= boundary;
10830           source = cons_string->second();
10831         } else {
10832           // Left hand side is longer.  Recurse over right.
10833           if (to > boundary) {
10834             String* second = cons_string->second();
10835             // When repeatedly appending to a string, we get a cons string that
10836             // is unbalanced to the left, a list, essentially.  We inline the
10837             // common case of sequential one-byte right child.
10838             if (to - boundary == 1) {
10839               sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
10840             } else if (second->IsSeqOneByteString()) {
10841               CopyChars(sink + boundary - from,
10842                         SeqOneByteString::cast(second)->GetChars(),
10843                         to - boundary);
10844             } else {
10845               WriteToFlat(second,
10846                           sink + boundary - from,
10847                           0,
10848                           to - boundary);
10849             }
10850             to = boundary;
10851           }
10852           source = first;
10853         }
10854         break;
10855       }
10856       case kOneByteStringTag | kSlicedStringTag:
10857       case kTwoByteStringTag | kSlicedStringTag: {
10858         SlicedString* slice = SlicedString::cast(source);
10859         unsigned offset = slice->offset();
10860         WriteToFlat(slice->parent(), sink, from + offset, to + offset);
10861         return;
10862       }
10863       case kOneByteStringTag | kThinStringTag:
10864       case kTwoByteStringTag | kThinStringTag:
10865         source = ThinString::cast(source)->actual();
10866         break;
10867     }
10868   }
10869 }
10870 
10871 
10872 
10873 template <typename SourceChar>
CalculateLineEndsImpl(Isolate * isolate,List<int> * line_ends,Vector<const SourceChar> src,bool include_ending_line)10874 static void CalculateLineEndsImpl(Isolate* isolate,
10875                                   List<int>* line_ends,
10876                                   Vector<const SourceChar> src,
10877                                   bool include_ending_line) {
10878   const int src_len = src.length();
10879   UnicodeCache* cache = isolate->unicode_cache();
10880   for (int i = 0; i < src_len - 1; i++) {
10881     SourceChar current = src[i];
10882     SourceChar next = src[i + 1];
10883     if (cache->IsLineTerminatorSequence(current, next)) line_ends->Add(i);
10884   }
10885 
10886   if (src_len > 0 && cache->IsLineTerminatorSequence(src[src_len - 1], 0)) {
10887     line_ends->Add(src_len - 1);
10888   }
10889   if (include_ending_line) {
10890     // Include one character beyond the end of script. The rewriter uses that
10891     // position for the implicit return statement.
10892     line_ends->Add(src_len);
10893   }
10894 }
10895 
10896 
CalculateLineEnds(Handle<String> src,bool include_ending_line)10897 Handle<FixedArray> String::CalculateLineEnds(Handle<String> src,
10898                                              bool include_ending_line) {
10899   src = Flatten(src);
10900   // Rough estimate of line count based on a roughly estimated average
10901   // length of (unpacked) code.
10902   int line_count_estimate = src->length() >> 4;
10903   List<int> line_ends(line_count_estimate);
10904   Isolate* isolate = src->GetIsolate();
10905   { DisallowHeapAllocation no_allocation;  // ensure vectors stay valid.
10906     // Dispatch on type of strings.
10907     String::FlatContent content = src->GetFlatContent();
10908     DCHECK(content.IsFlat());
10909     if (content.IsOneByte()) {
10910       CalculateLineEndsImpl(isolate,
10911                             &line_ends,
10912                             content.ToOneByteVector(),
10913                             include_ending_line);
10914     } else {
10915       CalculateLineEndsImpl(isolate,
10916                             &line_ends,
10917                             content.ToUC16Vector(),
10918                             include_ending_line);
10919     }
10920   }
10921   int line_count = line_ends.length();
10922   Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count);
10923   for (int i = 0; i < line_count; i++) {
10924     array->set(i, Smi::FromInt(line_ends[i]));
10925   }
10926   return array;
10927 }
10928 
10929 
10930 // Compares the contents of two strings by reading and comparing
10931 // int-sized blocks of characters.
10932 template <typename Char>
CompareRawStringContents(const Char * const a,const Char * const b,int length)10933 static inline bool CompareRawStringContents(const Char* const a,
10934                                             const Char* const b,
10935                                             int length) {
10936   return CompareChars(a, b, length) == 0;
10937 }
10938 
10939 
10940 template<typename Chars1, typename Chars2>
10941 class RawStringComparator : public AllStatic {
10942  public:
compare(const Chars1 * a,const Chars2 * b,int len)10943   static inline bool compare(const Chars1* a, const Chars2* b, int len) {
10944     DCHECK(sizeof(Chars1) != sizeof(Chars2));
10945     for (int i = 0; i < len; i++) {
10946       if (a[i] != b[i]) {
10947         return false;
10948       }
10949     }
10950     return true;
10951   }
10952 };
10953 
10954 
10955 template<>
10956 class RawStringComparator<uint16_t, uint16_t> {
10957  public:
compare(const uint16_t * a,const uint16_t * b,int len)10958   static inline bool compare(const uint16_t* a, const uint16_t* b, int len) {
10959     return CompareRawStringContents(a, b, len);
10960   }
10961 };
10962 
10963 
10964 template<>
10965 class RawStringComparator<uint8_t, uint8_t> {
10966  public:
compare(const uint8_t * a,const uint8_t * b,int len)10967   static inline bool compare(const uint8_t* a, const uint8_t* b, int len) {
10968     return CompareRawStringContents(a, b, len);
10969   }
10970 };
10971 
10972 
10973 class StringComparator {
10974   class State {
10975    public:
State()10976     State() : is_one_byte_(true), length_(0), buffer8_(NULL) {}
10977 
Init(String * string)10978     void Init(String* string) {
10979       ConsString* cons_string = String::VisitFlat(this, string);
10980       iter_.Reset(cons_string);
10981       if (cons_string != NULL) {
10982         int offset;
10983         string = iter_.Next(&offset);
10984         String::VisitFlat(this, string, offset);
10985       }
10986     }
10987 
VisitOneByteString(const uint8_t * chars,int length)10988     inline void VisitOneByteString(const uint8_t* chars, int length) {
10989       is_one_byte_ = true;
10990       buffer8_ = chars;
10991       length_ = length;
10992     }
10993 
VisitTwoByteString(const uint16_t * chars,int length)10994     inline void VisitTwoByteString(const uint16_t* chars, int length) {
10995       is_one_byte_ = false;
10996       buffer16_ = chars;
10997       length_ = length;
10998     }
10999 
Advance(int consumed)11000     void Advance(int consumed) {
11001       DCHECK(consumed <= length_);
11002       // Still in buffer.
11003       if (length_ != consumed) {
11004         if (is_one_byte_) {
11005           buffer8_ += consumed;
11006         } else {
11007           buffer16_ += consumed;
11008         }
11009         length_ -= consumed;
11010         return;
11011       }
11012       // Advance state.
11013       int offset;
11014       String* next = iter_.Next(&offset);
11015       DCHECK_EQ(0, offset);
11016       DCHECK(next != NULL);
11017       String::VisitFlat(this, next);
11018     }
11019 
11020     ConsStringIterator iter_;
11021     bool is_one_byte_;
11022     int length_;
11023     union {
11024       const uint8_t* buffer8_;
11025       const uint16_t* buffer16_;
11026     };
11027 
11028    private:
11029     DISALLOW_COPY_AND_ASSIGN(State);
11030   };
11031 
11032  public:
StringComparator()11033   inline StringComparator() {}
11034 
11035   template<typename Chars1, typename Chars2>
Equals(State * state_1,State * state_2,int to_check)11036   static inline bool Equals(State* state_1, State* state_2, int to_check) {
11037     const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_);
11038     const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_);
11039     return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check);
11040   }
11041 
Equals(String * string_1,String * string_2)11042   bool Equals(String* string_1, String* string_2) {
11043     int length = string_1->length();
11044     state_1_.Init(string_1);
11045     state_2_.Init(string_2);
11046     while (true) {
11047       int to_check = Min(state_1_.length_, state_2_.length_);
11048       DCHECK(to_check > 0 && to_check <= length);
11049       bool is_equal;
11050       if (state_1_.is_one_byte_) {
11051         if (state_2_.is_one_byte_) {
11052           is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check);
11053         } else {
11054           is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check);
11055         }
11056       } else {
11057         if (state_2_.is_one_byte_) {
11058           is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check);
11059         } else {
11060           is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check);
11061         }
11062       }
11063       // Looping done.
11064       if (!is_equal) return false;
11065       length -= to_check;
11066       // Exit condition. Strings are equal.
11067       if (length == 0) return true;
11068       state_1_.Advance(to_check);
11069       state_2_.Advance(to_check);
11070     }
11071   }
11072 
11073  private:
11074   State state_1_;
11075   State state_2_;
11076 
11077   DISALLOW_COPY_AND_ASSIGN(StringComparator);
11078 };
11079 
11080 
SlowEquals(String * other)11081 bool String::SlowEquals(String* other) {
11082   DisallowHeapAllocation no_gc;
11083   // Fast check: negative check with lengths.
11084   int len = length();
11085   if (len != other->length()) return false;
11086   if (len == 0) return true;
11087 
11088   // Fast check: if at least one ThinString is involved, dereference it/them
11089   // and restart.
11090   if (this->IsThinString() || other->IsThinString()) {
11091     if (other->IsThinString()) other = ThinString::cast(other)->actual();
11092     if (this->IsThinString()) {
11093       return ThinString::cast(this)->actual()->Equals(other);
11094     } else {
11095       return this->Equals(other);
11096     }
11097   }
11098 
11099   // Fast check: if hash code is computed for both strings
11100   // a fast negative check can be performed.
11101   if (HasHashCode() && other->HasHashCode()) {
11102 #ifdef ENABLE_SLOW_DCHECKS
11103     if (FLAG_enable_slow_asserts) {
11104       if (Hash() != other->Hash()) {
11105         bool found_difference = false;
11106         for (int i = 0; i < len; i++) {
11107           if (Get(i) != other->Get(i)) {
11108             found_difference = true;
11109             break;
11110           }
11111         }
11112         DCHECK(found_difference);
11113       }
11114     }
11115 #endif
11116     if (Hash() != other->Hash()) return false;
11117   }
11118 
11119   // We know the strings are both non-empty. Compare the first chars
11120   // before we try to flatten the strings.
11121   if (this->Get(0) != other->Get(0)) return false;
11122 
11123   if (IsSeqOneByteString() && other->IsSeqOneByteString()) {
11124     const uint8_t* str1 = SeqOneByteString::cast(this)->GetChars();
11125     const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars();
11126     return CompareRawStringContents(str1, str2, len);
11127   }
11128 
11129   StringComparator comparator;
11130   return comparator.Equals(this, other);
11131 }
11132 
11133 
SlowEquals(Handle<String> one,Handle<String> two)11134 bool String::SlowEquals(Handle<String> one, Handle<String> two) {
11135   // Fast check: negative check with lengths.
11136   int one_length = one->length();
11137   if (one_length != two->length()) return false;
11138   if (one_length == 0) return true;
11139 
11140   // Fast check: if at least one ThinString is involved, dereference it/them
11141   // and restart.
11142   if (one->IsThinString() || two->IsThinString()) {
11143     if (one->IsThinString()) one = handle(ThinString::cast(*one)->actual());
11144     if (two->IsThinString()) two = handle(ThinString::cast(*two)->actual());
11145     return String::Equals(one, two);
11146   }
11147 
11148   // Fast check: if hash code is computed for both strings
11149   // a fast negative check can be performed.
11150   if (one->HasHashCode() && two->HasHashCode()) {
11151 #ifdef ENABLE_SLOW_DCHECKS
11152     if (FLAG_enable_slow_asserts) {
11153       if (one->Hash() != two->Hash()) {
11154         bool found_difference = false;
11155         for (int i = 0; i < one_length; i++) {
11156           if (one->Get(i) != two->Get(i)) {
11157             found_difference = true;
11158             break;
11159           }
11160         }
11161         DCHECK(found_difference);
11162       }
11163     }
11164 #endif
11165     if (one->Hash() != two->Hash()) return false;
11166   }
11167 
11168   // We know the strings are both non-empty. Compare the first chars
11169   // before we try to flatten the strings.
11170   if (one->Get(0) != two->Get(0)) return false;
11171 
11172   one = String::Flatten(one);
11173   two = String::Flatten(two);
11174 
11175   DisallowHeapAllocation no_gc;
11176   String::FlatContent flat1 = one->GetFlatContent();
11177   String::FlatContent flat2 = two->GetFlatContent();
11178 
11179   if (flat1.IsOneByte() && flat2.IsOneByte()) {
11180       return CompareRawStringContents(flat1.ToOneByteVector().start(),
11181                                       flat2.ToOneByteVector().start(),
11182                                       one_length);
11183   } else {
11184     for (int i = 0; i < one_length; i++) {
11185       if (flat1.Get(i) != flat2.Get(i)) return false;
11186     }
11187     return true;
11188   }
11189 }
11190 
11191 
11192 // static
Compare(Handle<String> x,Handle<String> y)11193 ComparisonResult String::Compare(Handle<String> x, Handle<String> y) {
11194   // A few fast case tests before we flatten.
11195   if (x.is_identical_to(y)) {
11196     return ComparisonResult::kEqual;
11197   } else if (y->length() == 0) {
11198     return x->length() == 0 ? ComparisonResult::kEqual
11199                             : ComparisonResult::kGreaterThan;
11200   } else if (x->length() == 0) {
11201     return ComparisonResult::kLessThan;
11202   }
11203 
11204   int const d = x->Get(0) - y->Get(0);
11205   if (d < 0) {
11206     return ComparisonResult::kLessThan;
11207   } else if (d > 0) {
11208     return ComparisonResult::kGreaterThan;
11209   }
11210 
11211   // Slow case.
11212   x = String::Flatten(x);
11213   y = String::Flatten(y);
11214 
11215   DisallowHeapAllocation no_gc;
11216   ComparisonResult result = ComparisonResult::kEqual;
11217   int prefix_length = x->length();
11218   if (y->length() < prefix_length) {
11219     prefix_length = y->length();
11220     result = ComparisonResult::kGreaterThan;
11221   } else if (y->length() > prefix_length) {
11222     result = ComparisonResult::kLessThan;
11223   }
11224   int r;
11225   String::FlatContent x_content = x->GetFlatContent();
11226   String::FlatContent y_content = y->GetFlatContent();
11227   if (x_content.IsOneByte()) {
11228     Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
11229     if (y_content.IsOneByte()) {
11230       Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11231       r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11232     } else {
11233       Vector<const uc16> y_chars = y_content.ToUC16Vector();
11234       r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11235     }
11236   } else {
11237     Vector<const uc16> x_chars = x_content.ToUC16Vector();
11238     if (y_content.IsOneByte()) {
11239       Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11240       r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11241     } else {
11242       Vector<const uc16> y_chars = y_content.ToUC16Vector();
11243       r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11244     }
11245   }
11246   if (r < 0) {
11247     result = ComparisonResult::kLessThan;
11248   } else if (r > 0) {
11249     result = ComparisonResult::kGreaterThan;
11250   }
11251   return result;
11252 }
11253 
IndexOf(Isolate * isolate,Handle<Object> receiver,Handle<Object> search,Handle<Object> position)11254 Object* String::IndexOf(Isolate* isolate, Handle<Object> receiver,
11255                         Handle<Object> search, Handle<Object> position) {
11256   if (receiver->IsNullOrUndefined(isolate)) {
11257     THROW_NEW_ERROR_RETURN_FAILURE(
11258         isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
11259                               isolate->factory()->NewStringFromAsciiChecked(
11260                                   "String.prototype.indexOf")));
11261   }
11262   Handle<String> receiver_string;
11263   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string,
11264                                      Object::ToString(isolate, receiver));
11265 
11266   Handle<String> search_string;
11267   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
11268                                      Object::ToString(isolate, search));
11269 
11270   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11271                                      Object::ToInteger(isolate, position));
11272 
11273   uint32_t index = receiver_string->ToValidIndex(*position);
11274   return Smi::FromInt(
11275       String::IndexOf(isolate, receiver_string, search_string, index));
11276 }
11277 
11278 namespace {
11279 
11280 template <typename T>
SearchString(Isolate * isolate,String::FlatContent receiver_content,Vector<T> pat_vector,int start_index)11281 int SearchString(Isolate* isolate, String::FlatContent receiver_content,
11282                  Vector<T> pat_vector, int start_index) {
11283   if (receiver_content.IsOneByte()) {
11284     return SearchString(isolate, receiver_content.ToOneByteVector(), pat_vector,
11285                         start_index);
11286   }
11287   return SearchString(isolate, receiver_content.ToUC16Vector(), pat_vector,
11288                       start_index);
11289 }
11290 
11291 }  // namespace
11292 
IndexOf(Isolate * isolate,Handle<String> receiver,Handle<String> search,int start_index)11293 int String::IndexOf(Isolate* isolate, Handle<String> receiver,
11294                     Handle<String> search, int start_index) {
11295   DCHECK(0 <= start_index);
11296   DCHECK(start_index <= receiver->length());
11297 
11298   uint32_t search_length = search->length();
11299   if (search_length == 0) return start_index;
11300 
11301   uint32_t receiver_length = receiver->length();
11302   if (start_index + search_length > receiver_length) return -1;
11303 
11304   receiver = String::Flatten(receiver);
11305   search = String::Flatten(search);
11306 
11307   DisallowHeapAllocation no_gc;  // ensure vectors stay valid
11308   // Extract flattened substrings of cons strings before getting encoding.
11309   String::FlatContent receiver_content = receiver->GetFlatContent();
11310   String::FlatContent search_content = search->GetFlatContent();
11311 
11312   // dispatch on type of strings
11313   if (search_content.IsOneByte()) {
11314     Vector<const uint8_t> pat_vector = search_content.ToOneByteVector();
11315     return SearchString<const uint8_t>(isolate, receiver_content, pat_vector,
11316                                        start_index);
11317   }
11318   Vector<const uc16> pat_vector = search_content.ToUC16Vector();
11319   return SearchString<const uc16>(isolate, receiver_content, pat_vector,
11320                                   start_index);
11321 }
11322 
GetSubstitution(Isolate * isolate,Match * match,Handle<String> replacement)11323 MaybeHandle<String> String::GetSubstitution(Isolate* isolate, Match* match,
11324                                             Handle<String> replacement) {
11325   Factory* factory = isolate->factory();
11326 
11327   const int replacement_length = replacement->length();
11328   const int captures_length = match->CaptureCount();
11329 
11330   replacement = String::Flatten(replacement);
11331 
11332   Handle<String> dollar_string =
11333       factory->LookupSingleCharacterStringFromCode('$');
11334   int next = String::IndexOf(isolate, replacement, dollar_string, 0);
11335   if (next < 0) {
11336     return replacement;
11337   }
11338 
11339   IncrementalStringBuilder builder(isolate);
11340 
11341   if (next > 0) {
11342     builder.AppendString(factory->NewSubString(replacement, 0, next));
11343   }
11344 
11345   while (true) {
11346     int pos = next + 1;
11347     if (pos < replacement_length) {
11348       const uint16_t peek = replacement->Get(pos);
11349       if (peek == '$') {  // $$
11350         pos++;
11351         builder.AppendCharacter('$');
11352       } else if (peek == '&') {  // $& - match
11353         pos++;
11354         builder.AppendString(match->GetMatch());
11355       } else if (peek == '`') {  // $` - prefix
11356         pos++;
11357         builder.AppendString(match->GetPrefix());
11358       } else if (peek == '\'') {  // $' - suffix
11359         pos++;
11360         builder.AppendString(match->GetSuffix());
11361       } else if (peek >= '0' && peek <= '9') {
11362         // Valid indices are $1 .. $9, $01 .. $09 and $10 .. $99
11363         int scaled_index = (peek - '0');
11364         int advance = 1;
11365 
11366         if (pos + 1 < replacement_length) {
11367           const uint16_t next_peek = replacement->Get(pos + 1);
11368           if (next_peek >= '0' && next_peek <= '9') {
11369             const int new_scaled_index = scaled_index * 10 + (next_peek - '0');
11370             if (new_scaled_index < captures_length) {
11371               scaled_index = new_scaled_index;
11372               advance = 2;
11373             }
11374           }
11375         }
11376 
11377         if (scaled_index != 0 && scaled_index < captures_length) {
11378           bool capture_exists;
11379           Handle<String> capture;
11380           ASSIGN_RETURN_ON_EXCEPTION(
11381               isolate, capture,
11382               match->GetCapture(scaled_index, &capture_exists), String);
11383           if (capture_exists) builder.AppendString(capture);
11384           pos += advance;
11385         } else {
11386           builder.AppendCharacter('$');
11387         }
11388       } else {
11389         builder.AppendCharacter('$');
11390       }
11391     } else {
11392       builder.AppendCharacter('$');
11393     }
11394 
11395     // Go the the next $ in the replacement.
11396     next = String::IndexOf(isolate, replacement, dollar_string, pos);
11397 
11398     // Return if there are no more $ characters in the replacement. If we
11399     // haven't reached the end, we need to append the suffix.
11400     if (next < 0) {
11401       if (pos < replacement_length) {
11402         builder.AppendString(
11403             factory->NewSubString(replacement, pos, replacement_length));
11404       }
11405       return builder.Finish();
11406     }
11407 
11408     // Append substring between the previous and the next $ character.
11409     if (next > pos) {
11410       builder.AppendString(factory->NewSubString(replacement, pos, next));
11411     }
11412   }
11413 
11414   UNREACHABLE();
11415   return MaybeHandle<String>();
11416 }
11417 
11418 namespace {  // for String.Prototype.lastIndexOf
11419 
11420 template <typename schar, typename pchar>
StringMatchBackwards(Vector<const schar> subject,Vector<const pchar> pattern,int idx)11421 int StringMatchBackwards(Vector<const schar> subject,
11422                          Vector<const pchar> pattern, int idx) {
11423   int pattern_length = pattern.length();
11424   DCHECK(pattern_length >= 1);
11425   DCHECK(idx + pattern_length <= subject.length());
11426 
11427   if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
11428     for (int i = 0; i < pattern_length; i++) {
11429       uc16 c = pattern[i];
11430       if (c > String::kMaxOneByteCharCode) {
11431         return -1;
11432       }
11433     }
11434   }
11435 
11436   pchar pattern_first_char = pattern[0];
11437   for (int i = idx; i >= 0; i--) {
11438     if (subject[i] != pattern_first_char) continue;
11439     int j = 1;
11440     while (j < pattern_length) {
11441       if (pattern[j] != subject[i + j]) {
11442         break;
11443       }
11444       j++;
11445     }
11446     if (j == pattern_length) {
11447       return i;
11448     }
11449   }
11450   return -1;
11451 }
11452 
11453 }  // namespace
11454 
LastIndexOf(Isolate * isolate,Handle<Object> receiver,Handle<Object> search,Handle<Object> position)11455 Object* String::LastIndexOf(Isolate* isolate, Handle<Object> receiver,
11456                             Handle<Object> search, Handle<Object> position) {
11457   if (receiver->IsNullOrUndefined(isolate)) {
11458     THROW_NEW_ERROR_RETURN_FAILURE(
11459         isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
11460                               isolate->factory()->NewStringFromAsciiChecked(
11461                                   "String.prototype.lastIndexOf")));
11462   }
11463   Handle<String> receiver_string;
11464   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string,
11465                                      Object::ToString(isolate, receiver));
11466 
11467   Handle<String> search_string;
11468   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
11469                                      Object::ToString(isolate, search));
11470 
11471   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11472                                      Object::ToNumber(position));
11473 
11474   uint32_t start_index;
11475 
11476   if (position->IsNaN()) {
11477     start_index = receiver_string->length();
11478   } else {
11479     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11480                                        Object::ToInteger(isolate, position));
11481     start_index = receiver_string->ToValidIndex(*position);
11482   }
11483 
11484   uint32_t pattern_length = search_string->length();
11485   uint32_t receiver_length = receiver_string->length();
11486 
11487   if (start_index + pattern_length > receiver_length) {
11488     start_index = receiver_length - pattern_length;
11489   }
11490 
11491   if (pattern_length == 0) {
11492     return Smi::FromInt(start_index);
11493   }
11494 
11495   receiver_string = String::Flatten(receiver_string);
11496   search_string = String::Flatten(search_string);
11497 
11498   int last_index = -1;
11499   DisallowHeapAllocation no_gc;  // ensure vectors stay valid
11500 
11501   String::FlatContent receiver_content = receiver_string->GetFlatContent();
11502   String::FlatContent search_content = search_string->GetFlatContent();
11503 
11504   if (search_content.IsOneByte()) {
11505     Vector<const uint8_t> pat_vector = search_content.ToOneByteVector();
11506     if (receiver_content.IsOneByte()) {
11507       last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
11508                                         pat_vector, start_index);
11509     } else {
11510       last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
11511                                         pat_vector, start_index);
11512     }
11513   } else {
11514     Vector<const uc16> pat_vector = search_content.ToUC16Vector();
11515     if (receiver_content.IsOneByte()) {
11516       last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
11517                                         pat_vector, start_index);
11518     } else {
11519       last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
11520                                         pat_vector, start_index);
11521     }
11522   }
11523   return Smi::FromInt(last_index);
11524 }
11525 
IsUtf8EqualTo(Vector<const char> str,bool allow_prefix_match)11526 bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
11527   int slen = length();
11528   // Can't check exact length equality, but we can check bounds.
11529   int str_len = str.length();
11530   if (!allow_prefix_match &&
11531       (str_len < slen ||
11532           str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) {
11533     return false;
11534   }
11535   int i;
11536   size_t remaining_in_str = static_cast<size_t>(str_len);
11537   const uint8_t* utf8_data = reinterpret_cast<const uint8_t*>(str.start());
11538   for (i = 0; i < slen && remaining_in_str > 0; i++) {
11539     size_t cursor = 0;
11540     uint32_t r = unibrow::Utf8::ValueOf(utf8_data, remaining_in_str, &cursor);
11541     DCHECK(cursor > 0 && cursor <= remaining_in_str);
11542     if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
11543       if (i > slen - 1) return false;
11544       if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false;
11545       if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false;
11546     } else {
11547       if (Get(i) != r) return false;
11548     }
11549     utf8_data += cursor;
11550     remaining_in_str -= cursor;
11551   }
11552   return (allow_prefix_match || i == slen) && remaining_in_str == 0;
11553 }
11554 
11555 
IsOneByteEqualTo(Vector<const uint8_t> str)11556 bool String::IsOneByteEqualTo(Vector<const uint8_t> str) {
11557   int slen = length();
11558   if (str.length() != slen) return false;
11559   DisallowHeapAllocation no_gc;
11560   FlatContent content = GetFlatContent();
11561   if (content.IsOneByte()) {
11562     return CompareChars(content.ToOneByteVector().start(),
11563                         str.start(), slen) == 0;
11564   }
11565   for (int i = 0; i < slen; i++) {
11566     if (Get(i) != static_cast<uint16_t>(str[i])) return false;
11567   }
11568   return true;
11569 }
11570 
11571 
IsTwoByteEqualTo(Vector<const uc16> str)11572 bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
11573   int slen = length();
11574   if (str.length() != slen) return false;
11575   DisallowHeapAllocation no_gc;
11576   FlatContent content = GetFlatContent();
11577   if (content.IsTwoByte()) {
11578     return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
11579   }
11580   for (int i = 0; i < slen; i++) {
11581     if (Get(i) != str[i]) return false;
11582   }
11583   return true;
11584 }
11585 
11586 
ComputeAndSetHash()11587 uint32_t String::ComputeAndSetHash() {
11588   // Should only be called if hash code has not yet been computed.
11589   DCHECK(!HasHashCode());
11590 
11591   // Store the hash code in the object.
11592   uint32_t field = IteratingStringHasher::Hash(this, GetHeap()->HashSeed());
11593   set_hash_field(field);
11594 
11595   // Check the hash code is there.
11596   DCHECK(HasHashCode());
11597   uint32_t result = field >> kHashShift;
11598   DCHECK(result != 0);  // Ensure that the hash value of 0 is never computed.
11599   return result;
11600 }
11601 
11602 
ComputeArrayIndex(uint32_t * index)11603 bool String::ComputeArrayIndex(uint32_t* index) {
11604   int length = this->length();
11605   if (length == 0 || length > kMaxArrayIndexSize) return false;
11606   StringCharacterStream stream(this);
11607   return StringToArrayIndex(&stream, index);
11608 }
11609 
11610 
SlowAsArrayIndex(uint32_t * index)11611 bool String::SlowAsArrayIndex(uint32_t* index) {
11612   if (length() <= kMaxCachedArrayIndexLength) {
11613     Hash();  // force computation of hash code
11614     uint32_t field = hash_field();
11615     if ((field & kIsNotArrayIndexMask) != 0) return false;
11616     // Isolate the array index form the full hash field.
11617     *index = ArrayIndexValueBits::decode(field);
11618     return true;
11619   } else {
11620     return ComputeArrayIndex(index);
11621   }
11622 }
11623 
11624 
Truncate(Handle<SeqString> string,int new_length)11625 Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
11626   Heap* heap = string->GetHeap();
11627   if (new_length == 0) return heap->isolate()->factory()->empty_string();
11628 
11629   int new_size, old_size;
11630   int old_length = string->length();
11631   if (old_length <= new_length) return string;
11632 
11633   if (string->IsSeqOneByteString()) {
11634     old_size = SeqOneByteString::SizeFor(old_length);
11635     new_size = SeqOneByteString::SizeFor(new_length);
11636   } else {
11637     DCHECK(string->IsSeqTwoByteString());
11638     old_size = SeqTwoByteString::SizeFor(old_length);
11639     new_size = SeqTwoByteString::SizeFor(new_length);
11640   }
11641 
11642   int delta = old_size - new_size;
11643 
11644   Address start_of_string = string->address();
11645   DCHECK_OBJECT_ALIGNED(start_of_string);
11646   DCHECK_OBJECT_ALIGNED(start_of_string + new_size);
11647 
11648   // Sizes are pointer size aligned, so that we can use filler objects
11649   // that are a multiple of pointer size.
11650   heap->CreateFillerObjectAt(start_of_string + new_size, delta,
11651                              ClearRecordedSlots::kNo);
11652   heap->AdjustLiveBytes(*string, -delta);
11653 
11654   // We are storing the new length using release store after creating a filler
11655   // for the left-over space to avoid races with the sweeper thread.
11656   string->synchronized_set_length(new_length);
11657 
11658   return string;
11659 }
11660 
11661 
MakeArrayIndexHash(uint32_t value,int length)11662 uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
11663   // For array indexes mix the length into the hash as an array index could
11664   // be zero.
11665   DCHECK(length > 0);
11666   DCHECK(length <= String::kMaxArrayIndexSize);
11667   DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
11668          (1 << String::kArrayIndexValueBits));
11669 
11670   value <<= String::ArrayIndexValueBits::kShift;
11671   value |= length << String::ArrayIndexLengthBits::kShift;
11672 
11673   DCHECK((value & String::kIsNotArrayIndexMask) == 0);
11674   DCHECK_EQ(length <= String::kMaxCachedArrayIndexLength,
11675             (value & String::kContainsCachedArrayIndexMask) == 0);
11676   return value;
11677 }
11678 
11679 
GetHashField()11680 uint32_t StringHasher::GetHashField() {
11681   if (length_ <= String::kMaxHashCalcLength) {
11682     if (is_array_index_) {
11683       return MakeArrayIndexHash(array_index_, length_);
11684     }
11685     return (GetHashCore(raw_running_hash_) << String::kHashShift) |
11686            String::kIsNotArrayIndexMask;
11687   } else {
11688     return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
11689   }
11690 }
11691 
11692 
ComputeUtf8Hash(Vector<const char> chars,uint32_t seed,int * utf16_length_out)11693 uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars,
11694                                        uint32_t seed,
11695                                        int* utf16_length_out) {
11696   int vector_length = chars.length();
11697   // Handle some edge cases
11698   if (vector_length <= 1) {
11699     DCHECK(vector_length == 0 ||
11700            static_cast<uint8_t>(chars.start()[0]) <=
11701                unibrow::Utf8::kMaxOneByteChar);
11702     *utf16_length_out = vector_length;
11703     return HashSequentialString(chars.start(), vector_length, seed);
11704   }
11705   // Start with a fake length which won't affect computation.
11706   // It will be updated later.
11707   StringHasher hasher(String::kMaxArrayIndexSize, seed);
11708   size_t remaining = static_cast<size_t>(vector_length);
11709   const uint8_t* stream = reinterpret_cast<const uint8_t*>(chars.start());
11710   int utf16_length = 0;
11711   bool is_index = true;
11712   DCHECK(hasher.is_array_index_);
11713   while (remaining > 0) {
11714     size_t consumed = 0;
11715     uint32_t c = unibrow::Utf8::ValueOf(stream, remaining, &consumed);
11716     DCHECK(consumed > 0 && consumed <= remaining);
11717     stream += consumed;
11718     remaining -= consumed;
11719     bool is_two_characters = c > unibrow::Utf16::kMaxNonSurrogateCharCode;
11720     utf16_length += is_two_characters ? 2 : 1;
11721     // No need to keep hashing. But we do need to calculate utf16_length.
11722     if (utf16_length > String::kMaxHashCalcLength) continue;
11723     if (is_two_characters) {
11724       uint16_t c1 = unibrow::Utf16::LeadSurrogate(c);
11725       uint16_t c2 = unibrow::Utf16::TrailSurrogate(c);
11726       hasher.AddCharacter(c1);
11727       hasher.AddCharacter(c2);
11728       if (is_index) is_index = hasher.UpdateIndex(c1);
11729       if (is_index) is_index = hasher.UpdateIndex(c2);
11730     } else {
11731       hasher.AddCharacter(c);
11732       if (is_index) is_index = hasher.UpdateIndex(c);
11733     }
11734   }
11735   *utf16_length_out = static_cast<int>(utf16_length);
11736   // Must set length here so that hash computation is correct.
11737   hasher.length_ = utf16_length;
11738   return hasher.GetHashField();
11739 }
11740 
11741 
VisitConsString(ConsString * cons_string)11742 void IteratingStringHasher::VisitConsString(ConsString* cons_string) {
11743   // Run small ConsStrings through ConsStringIterator.
11744   if (cons_string->length() < 64) {
11745     ConsStringIterator iter(cons_string);
11746     int offset;
11747     String* string;
11748     while (nullptr != (string = iter.Next(&offset))) {
11749       DCHECK_EQ(0, offset);
11750       String::VisitFlat(this, string, 0);
11751     }
11752     return;
11753   }
11754   // Slow case.
11755   const int max_length = String::kMaxHashCalcLength;
11756   int length = std::min(cons_string->length(), max_length);
11757   if (cons_string->HasOnlyOneByteChars()) {
11758     uint8_t* buffer = new uint8_t[length];
11759     String::WriteToFlat(cons_string, buffer, 0, length);
11760     AddCharacters(buffer, length);
11761     delete[] buffer;
11762   } else {
11763     uint16_t* buffer = new uint16_t[length];
11764     String::WriteToFlat(cons_string, buffer, 0, length);
11765     AddCharacters(buffer, length);
11766     delete[] buffer;
11767   }
11768 }
11769 
11770 
PrintOn(FILE * file)11771 void String::PrintOn(FILE* file) {
11772   int length = this->length();
11773   for (int i = 0; i < length; i++) {
11774     PrintF(file, "%c", Get(i));
11775   }
11776 }
11777 
11778 
Hash()11779 int Map::Hash() {
11780   // For performance reasons we only hash the 3 most variable fields of a map:
11781   // constructor, prototype and bit_field2. For predictability reasons we
11782   // use objects' offsets in respective pages for hashing instead of raw
11783   // addresses.
11784 
11785   // Shift away the tag.
11786   int hash = ObjectAddressForHashing(GetConstructor()) >> 2;
11787 
11788   // XOR-ing the prototype and constructor directly yields too many zero bits
11789   // when the two pointers are close (which is fairly common).
11790   // To avoid this we shift the prototype bits relatively to the constructor.
11791   hash ^= ObjectAddressForHashing(prototype()) << (32 - kPageSizeBits);
11792 
11793   return hash ^ (hash >> 16) ^ bit_field2();
11794 }
11795 
11796 
11797 namespace {
11798 
CheckEquivalent(Map * first,Map * second)11799 bool CheckEquivalent(Map* first, Map* second) {
11800   return first->GetConstructor() == second->GetConstructor() &&
11801          first->prototype() == second->prototype() &&
11802          first->instance_type() == second->instance_type() &&
11803          first->bit_field() == second->bit_field() &&
11804          first->is_extensible() == second->is_extensible() &&
11805          first->new_target_is_base() == second->new_target_is_base() &&
11806          first->has_hidden_prototype() == second->has_hidden_prototype();
11807 }
11808 
11809 }  // namespace
11810 
11811 
EquivalentToForTransition(Map * other)11812 bool Map::EquivalentToForTransition(Map* other) {
11813   if (!CheckEquivalent(this, other)) return false;
11814   if (instance_type() == JS_FUNCTION_TYPE) {
11815     // JSFunctions require more checks to ensure that sloppy function is
11816     // not equvalent to strict function.
11817     int nof = Min(NumberOfOwnDescriptors(), other->NumberOfOwnDescriptors());
11818     return instance_descriptors()->IsEqualUpTo(other->instance_descriptors(),
11819                                                nof);
11820   }
11821   return true;
11822 }
11823 
11824 
EquivalentToForNormalization(Map * other,PropertyNormalizationMode mode)11825 bool Map::EquivalentToForNormalization(Map* other,
11826                                        PropertyNormalizationMode mode) {
11827   int properties =
11828       mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other->GetInObjectProperties();
11829   return CheckEquivalent(this, other) && bit_field2() == other->bit_field2() &&
11830          GetInObjectProperties() == properties &&
11831          JSObject::GetInternalFieldCount(this) ==
11832              JSObject::GetInternalFieldCount(other);
11833 }
11834 
11835 
Inlines(SharedFunctionInfo * candidate)11836 bool JSFunction::Inlines(SharedFunctionInfo* candidate) {
11837   DisallowHeapAllocation no_gc;
11838   if (shared() == candidate) return true;
11839   if (code()->kind() != Code::OPTIMIZED_FUNCTION) return false;
11840   DeoptimizationInputData* const data =
11841       DeoptimizationInputData::cast(code()->deoptimization_data());
11842   if (data->length() == 0) return false;
11843   FixedArray* const literals = data->LiteralArray();
11844   int const inlined_count = data->InlinedFunctionCount()->value();
11845   for (int i = 0; i < inlined_count; ++i) {
11846     if (SharedFunctionInfo::cast(literals->get(i)) == candidate) {
11847       return true;
11848     }
11849   }
11850   return false;
11851 }
11852 
MarkForBaseline()11853 void JSFunction::MarkForBaseline() {
11854   Isolate* isolate = GetIsolate();
11855   set_code_no_write_barrier(
11856       isolate->builtins()->builtin(Builtins::kCompileBaseline));
11857   // No write barrier required, since the builtin is part of the root set.
11858   if (FLAG_mark_shared_functions_for_tier_up) {
11859     shared()->set_marked_for_tier_up(true);
11860   }
11861 }
11862 
MarkForOptimization()11863 void JSFunction::MarkForOptimization() {
11864   Isolate* isolate = GetIsolate();
11865   DCHECK(!IsOptimized());
11866   DCHECK(shared()->allows_lazy_compilation() ||
11867          !shared()->optimization_disabled());
11868   set_code_no_write_barrier(
11869       isolate->builtins()->builtin(Builtins::kCompileOptimized));
11870   // No write barrier required, since the builtin is part of the root set.
11871   if (FLAG_mark_shared_functions_for_tier_up) {
11872     shared()->set_marked_for_tier_up(true);
11873   }
11874 }
11875 
11876 
AttemptConcurrentOptimization()11877 void JSFunction::AttemptConcurrentOptimization() {
11878   Isolate* isolate = GetIsolate();
11879   if (!isolate->concurrent_recompilation_enabled() ||
11880       isolate->bootstrapper()->IsActive()) {
11881     MarkForOptimization();
11882     return;
11883   }
11884   DCHECK(!IsInOptimizationQueue());
11885   DCHECK(!IsOptimized());
11886   DCHECK(shared()->allows_lazy_compilation() ||
11887          !shared()->optimization_disabled());
11888   DCHECK(isolate->concurrent_recompilation_enabled());
11889   if (FLAG_trace_concurrent_recompilation) {
11890     PrintF("  ** Marking ");
11891     ShortPrint();
11892     PrintF(" for concurrent recompilation.\n");
11893   }
11894 
11895   set_code_no_write_barrier(
11896       isolate->builtins()->builtin(Builtins::kCompileOptimizedConcurrent));
11897   // No write barrier required, since the builtin is part of the root set.
11898   if (FLAG_mark_shared_functions_for_tier_up) {
11899     // TODO(leszeks): The compilation isn't concurrent if we trigger it using
11900     // this bit.
11901     shared()->set_marked_for_tier_up(true);
11902   }
11903 }
11904 
11905 // static
AddToOptimizedCodeMap(Handle<SharedFunctionInfo> shared,Handle<Context> native_context,Handle<Code> code,BailoutId osr_ast_id)11906 void SharedFunctionInfo::AddToOptimizedCodeMap(
11907     Handle<SharedFunctionInfo> shared, Handle<Context> native_context,
11908     Handle<Code> code, BailoutId osr_ast_id) {
11909   Isolate* isolate = shared->GetIsolate();
11910   if (isolate->serializer_enabled()) return;
11911   DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
11912   DCHECK(native_context->IsNativeContext());
11913   STATIC_ASSERT(kEntryLength == 2);
11914   Handle<FixedArray> new_code_map;
11915   int entry;
11916 
11917   if (!osr_ast_id.IsNone()) {
11918     Context::AddToOptimizedCodeMap(native_context, shared, code, osr_ast_id);
11919     return;
11920   }
11921 
11922   DCHECK(osr_ast_id.IsNone());
11923   if (shared->OptimizedCodeMapIsCleared()) {
11924     new_code_map = isolate->factory()->NewFixedArray(kInitialLength, TENURED);
11925     entry = kEntriesStart;
11926   } else {
11927     Handle<FixedArray> old_code_map(shared->optimized_code_map(), isolate);
11928     entry = shared->SearchOptimizedCodeMapEntry(*native_context);
11929     if (entry >= kEntriesStart) {
11930       // Just set the code of the entry.
11931       Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code);
11932       old_code_map->set(entry + kCachedCodeOffset, *code_cell);
11933       return;
11934     }
11935 
11936     // Can we reuse an entry?
11937     DCHECK(entry < kEntriesStart);
11938     int length = old_code_map->length();
11939     for (int i = kEntriesStart; i < length; i += kEntryLength) {
11940       if (WeakCell::cast(old_code_map->get(i + kContextOffset))->cleared()) {
11941         new_code_map = old_code_map;
11942         entry = i;
11943         break;
11944       }
11945     }
11946 
11947     if (entry < kEntriesStart) {
11948       // Copy old optimized code map and append one new entry.
11949       new_code_map = isolate->factory()->CopyFixedArrayAndGrow(
11950           old_code_map, kEntryLength, TENURED);
11951       // TODO(mstarzinger): Temporary workaround. The allocation above might
11952       // have flushed the optimized code map and the copy we created is full of
11953       // holes. For now we just give up on adding the entry and pretend it got
11954       // flushed.
11955       if (shared->OptimizedCodeMapIsCleared()) return;
11956       entry = old_code_map->length();
11957     }
11958   }
11959 
11960   Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code);
11961   WeakCell* context_cell = native_context->self_weak_cell();
11962 
11963   new_code_map->set(entry + kContextOffset, context_cell);
11964   new_code_map->set(entry + kCachedCodeOffset, *code_cell);
11965 
11966 #ifdef DEBUG
11967   for (int i = kEntriesStart; i < new_code_map->length(); i += kEntryLength) {
11968     WeakCell* cell = WeakCell::cast(new_code_map->get(i + kContextOffset));
11969     DCHECK(cell->cleared() || cell->value()->IsNativeContext());
11970     cell = WeakCell::cast(new_code_map->get(i + kCachedCodeOffset));
11971     DCHECK(cell->cleared() ||
11972            (cell->value()->IsCode() &&
11973             Code::cast(cell->value())->kind() == Code::OPTIMIZED_FUNCTION));
11974   }
11975 #endif
11976 
11977   FixedArray* old_code_map = shared->optimized_code_map();
11978   if (old_code_map != *new_code_map) {
11979     shared->set_optimized_code_map(*new_code_map);
11980   }
11981 }
11982 
11983 
ClearOptimizedCodeMap()11984 void SharedFunctionInfo::ClearOptimizedCodeMap() {
11985   FixedArray* empty_fixed_array = GetHeap()->empty_fixed_array();
11986   set_optimized_code_map(empty_fixed_array, SKIP_WRITE_BARRIER);
11987 }
11988 
11989 
EvictFromOptimizedCodeMap(Code * optimized_code,const char * reason)11990 void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
11991                                                    const char* reason) {
11992   DisallowHeapAllocation no_gc;
11993   Isolate* isolate = GetIsolate();
11994   bool found = false;
11995 
11996   if (!OptimizedCodeMapIsCleared()) {
11997     Heap* heap = isolate->heap();
11998     FixedArray* code_map = optimized_code_map();
11999     int length = code_map->length();
12000     for (int src = kEntriesStart; src < length; src += kEntryLength) {
12001       DCHECK(WeakCell::cast(code_map->get(src))->cleared() ||
12002              WeakCell::cast(code_map->get(src))->value()->IsNativeContext());
12003       found = WeakCell::cast(code_map->get(src + kCachedCodeOffset))->value() ==
12004               optimized_code;
12005       if (found) {
12006         if (FLAG_trace_opt) {
12007           PrintF("[evicting entry from optimizing code map (%s) for ", reason);
12008           ShortPrint();
12009           PrintF("]\n");
12010         }
12011         // Just clear the code.
12012         code_map->set(src + kCachedCodeOffset, heap->empty_weak_cell(),
12013                       SKIP_WRITE_BARRIER);
12014       }
12015     }
12016   }
12017 
12018   if (!found) {
12019     // We didn't find the code in here. It must be osr'd code.
12020     isolate->EvictOSROptimizedCode(optimized_code, reason);
12021   }
12022 }
12023 
12024 // static
EnsureLiterals(Handle<JSFunction> function)12025 void JSFunction::EnsureLiterals(Handle<JSFunction> function) {
12026   Handle<SharedFunctionInfo> shared(function->shared());
12027   Isolate* isolate = shared->GetIsolate();
12028 
12029   FeedbackVectorState state = function->GetFeedbackVectorState(isolate);
12030   switch (state) {
12031     case TOP_LEVEL_SCRIPT_NEEDS_VECTOR: {
12032       // A top level script didn't get it's literals installed.
12033       Handle<FeedbackVector> feedback_vector =
12034           FeedbackVector::New(isolate, shared);
12035       Handle<Cell> new_cell =
12036           isolate->factory()->NewOneClosureCell(feedback_vector);
12037       function->set_feedback_vector_cell(*new_cell);
12038       break;
12039     }
12040     case NEEDS_VECTOR: {
12041       Handle<FeedbackVector> feedback_vector =
12042           FeedbackVector::New(isolate, shared);
12043       function->feedback_vector_cell()->set_value(*feedback_vector);
12044       break;
12045     }
12046     case HAS_VECTOR:
12047       // Nothing to do.
12048       break;
12049   }
12050 }
12051 
GetMinInobjectSlack(Map * map,void * data)12052 static void GetMinInobjectSlack(Map* map, void* data) {
12053   int slack = map->unused_property_fields();
12054   if (*reinterpret_cast<int*>(data) > slack) {
12055     *reinterpret_cast<int*>(data) = slack;
12056   }
12057 }
12058 
12059 
ShrinkInstanceSize(Map * map,void * data)12060 static void ShrinkInstanceSize(Map* map, void* data) {
12061   int slack = *reinterpret_cast<int*>(data);
12062   map->SetInObjectProperties(map->GetInObjectProperties() - slack);
12063   map->set_unused_property_fields(map->unused_property_fields() - slack);
12064   map->set_instance_size(map->instance_size() - slack * kPointerSize);
12065   map->set_construction_counter(Map::kNoSlackTracking);
12066 
12067   // Visitor id might depend on the instance size, recalculate it.
12068   map->set_visitor_id(Heap::GetStaticVisitorIdForMap(map));
12069 }
12070 
StopSlackTracking(Map * map,void * data)12071 static void StopSlackTracking(Map* map, void* data) {
12072   map->set_construction_counter(Map::kNoSlackTracking);
12073 }
12074 
CompleteInobjectSlackTracking()12075 void Map::CompleteInobjectSlackTracking() {
12076   // Has to be an initial map.
12077   DCHECK(GetBackPointer()->IsUndefined(GetIsolate()));
12078 
12079   int slack = unused_property_fields();
12080   TransitionArray::TraverseTransitionTree(this, &GetMinInobjectSlack, &slack);
12081   if (slack != 0) {
12082     // Resize the initial map and all maps in its transition tree.
12083     TransitionArray::TraverseTransitionTree(this, &ShrinkInstanceSize, &slack);
12084   } else {
12085     TransitionArray::TraverseTransitionTree(this, &StopSlackTracking, nullptr);
12086   }
12087 }
12088 
12089 
PrototypeBenefitsFromNormalization(Handle<JSObject> object)12090 static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) {
12091   DisallowHeapAllocation no_gc;
12092   if (!object->HasFastProperties()) return false;
12093   if (object->IsJSGlobalProxy()) return false;
12094   if (object->GetIsolate()->bootstrapper()->IsActive()) return false;
12095   return !object->map()->is_prototype_map() ||
12096          !object->map()->should_be_fast_prototype_map();
12097 }
12098 
12099 // static
MakePrototypesFast(Handle<Object> receiver,WhereToStart where_to_start,Isolate * isolate)12100 void JSObject::MakePrototypesFast(Handle<Object> receiver,
12101                                   WhereToStart where_to_start,
12102                                   Isolate* isolate) {
12103   if (!receiver->IsJSReceiver()) return;
12104   for (PrototypeIterator iter(isolate, Handle<JSReceiver>::cast(receiver),
12105                               where_to_start);
12106        !iter.IsAtEnd(); iter.Advance()) {
12107     Handle<Object> current = PrototypeIterator::GetCurrent(iter);
12108     if (!current->IsJSObject()) return;
12109     Handle<JSObject> current_obj = Handle<JSObject>::cast(current);
12110     Map* current_map = current_obj->map();
12111     if (current_map->is_prototype_map()) {
12112       // If the map is already marked as should be fast, we're done. Its
12113       // prototypes will have been marked already as well.
12114       if (current_map->should_be_fast_prototype_map()) return;
12115       Handle<Map> map(current_map);
12116       Map::SetShouldBeFastPrototypeMap(map, true, isolate);
12117       JSObject::OptimizeAsPrototype(current_obj, FAST_PROTOTYPE);
12118     }
12119   }
12120 }
12121 
12122 // static
OptimizeAsPrototype(Handle<JSObject> object,PrototypeOptimizationMode mode)12123 void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
12124                                    PrototypeOptimizationMode mode) {
12125   if (object->IsJSGlobalObject()) return;
12126   if (mode == FAST_PROTOTYPE && PrototypeBenefitsFromNormalization(object)) {
12127     // First normalize to ensure all JSFunctions are DATA_CONSTANT.
12128     JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0,
12129                                   "NormalizeAsPrototype");
12130   }
12131   Handle<Map> previous_map(object->map());
12132   if (object->map()->is_prototype_map()) {
12133     if (object->map()->should_be_fast_prototype_map() &&
12134         !object->HasFastProperties()) {
12135       JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype");
12136     }
12137   } else {
12138     if (object->map() == *previous_map) {
12139       Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype");
12140       JSObject::MigrateToMap(object, new_map);
12141     }
12142     object->map()->set_is_prototype_map(true);
12143 
12144     // Replace the pointer to the exact constructor with the Object function
12145     // from the same context if undetectable from JS. This is to avoid keeping
12146     // memory alive unnecessarily.
12147     Object* maybe_constructor = object->map()->GetConstructor();
12148     if (maybe_constructor->IsJSFunction()) {
12149       JSFunction* constructor = JSFunction::cast(maybe_constructor);
12150       Isolate* isolate = object->GetIsolate();
12151       if (!constructor->shared()->IsApiFunction() &&
12152           object->class_name() == isolate->heap()->Object_string()) {
12153         Context* context = constructor->context()->native_context();
12154         JSFunction* object_function = context->object_function();
12155         object->map()->SetConstructor(object_function);
12156       }
12157     }
12158   }
12159 }
12160 
12161 
12162 // static
ReoptimizeIfPrototype(Handle<JSObject> object)12163 void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) {
12164   if (!object->map()->is_prototype_map()) return;
12165   if (!object->map()->should_be_fast_prototype_map()) return;
12166   OptimizeAsPrototype(object, FAST_PROTOTYPE);
12167 }
12168 
12169 
12170 // static
LazyRegisterPrototypeUser(Handle<Map> user,Isolate * isolate)12171 void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
12172   // Contract: In line with InvalidatePrototypeChains()'s requirements,
12173   // leaf maps don't need to register as users, only prototypes do.
12174   DCHECK(user->is_prototype_map());
12175 
12176   Handle<Map> current_user = user;
12177   Handle<PrototypeInfo> current_user_info =
12178       Map::GetOrCreatePrototypeInfo(user, isolate);
12179   for (PrototypeIterator iter(user); !iter.IsAtEnd(); iter.Advance()) {
12180     // Walk up the prototype chain as far as links haven't been registered yet.
12181     if (current_user_info->registry_slot() != PrototypeInfo::UNREGISTERED) {
12182       break;
12183     }
12184     Handle<Object> maybe_proto = PrototypeIterator::GetCurrent(iter);
12185     // Proxies on the prototype chain are not supported. They make it
12186     // impossible to make any assumptions about the prototype chain anyway.
12187     if (maybe_proto->IsJSProxy()) return;
12188     Handle<JSObject> proto = Handle<JSObject>::cast(maybe_proto);
12189     Handle<PrototypeInfo> proto_info =
12190         Map::GetOrCreatePrototypeInfo(proto, isolate);
12191     Handle<Object> maybe_registry(proto_info->prototype_users(), isolate);
12192     int slot = 0;
12193     Handle<WeakFixedArray> new_array =
12194         WeakFixedArray::Add(maybe_registry, current_user, &slot);
12195     current_user_info->set_registry_slot(slot);
12196     if (!maybe_registry.is_identical_to(new_array)) {
12197       proto_info->set_prototype_users(*new_array);
12198     }
12199     if (FLAG_trace_prototype_users) {
12200       PrintF("Registering %p as a user of prototype %p (map=%p).\n",
12201              reinterpret_cast<void*>(*current_user),
12202              reinterpret_cast<void*>(*proto),
12203              reinterpret_cast<void*>(proto->map()));
12204     }
12205 
12206     current_user = handle(proto->map(), isolate);
12207     current_user_info = proto_info;
12208   }
12209 }
12210 
12211 
12212 // Can be called regardless of whether |user| was actually registered with
12213 // |prototype|. Returns true when there was a registration.
12214 // static
UnregisterPrototypeUser(Handle<Map> user,Isolate * isolate)12215 bool JSObject::UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
12216   DCHECK(user->is_prototype_map());
12217   // If it doesn't have a PrototypeInfo, it was never registered.
12218   if (!user->prototype_info()->IsPrototypeInfo()) return false;
12219   // If it had no prototype before, see if it had users that might expect
12220   // registration.
12221   if (!user->prototype()->IsJSObject()) {
12222     Object* users =
12223         PrototypeInfo::cast(user->prototype_info())->prototype_users();
12224     return users->IsWeakFixedArray();
12225   }
12226   Handle<JSObject> prototype(JSObject::cast(user->prototype()), isolate);
12227   Handle<PrototypeInfo> user_info =
12228       Map::GetOrCreatePrototypeInfo(user, isolate);
12229   int slot = user_info->registry_slot();
12230   if (slot == PrototypeInfo::UNREGISTERED) return false;
12231   DCHECK(prototype->map()->is_prototype_map());
12232   Object* maybe_proto_info = prototype->map()->prototype_info();
12233   // User knows its registry slot, prototype info and user registry must exist.
12234   DCHECK(maybe_proto_info->IsPrototypeInfo());
12235   Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info),
12236                                    isolate);
12237   Object* maybe_registry = proto_info->prototype_users();
12238   DCHECK(maybe_registry->IsWeakFixedArray());
12239   DCHECK(WeakFixedArray::cast(maybe_registry)->Get(slot) == *user);
12240   WeakFixedArray::cast(maybe_registry)->Clear(slot);
12241   if (FLAG_trace_prototype_users) {
12242     PrintF("Unregistering %p as a user of prototype %p.\n",
12243            reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype));
12244   }
12245   return true;
12246 }
12247 
12248 
InvalidatePrototypeChainsInternal(Map * map)12249 static void InvalidatePrototypeChainsInternal(Map* map) {
12250   DCHECK(map->is_prototype_map());
12251   if (FLAG_trace_prototype_users) {
12252     PrintF("Invalidating prototype map %p 's cell\n",
12253            reinterpret_cast<void*>(map));
12254   }
12255   Object* maybe_proto_info = map->prototype_info();
12256   if (!maybe_proto_info->IsPrototypeInfo()) return;
12257   PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info);
12258   Object* maybe_cell = proto_info->validity_cell();
12259   if (maybe_cell->IsCell()) {
12260     // Just set the value; the cell will be replaced lazily.
12261     Cell* cell = Cell::cast(maybe_cell);
12262     cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid));
12263   }
12264 
12265   WeakFixedArray::Iterator iterator(proto_info->prototype_users());
12266   // For now, only maps register themselves as users.
12267   Map* user;
12268   while ((user = iterator.Next<Map>())) {
12269     // Walk the prototype chain (backwards, towards leaf objects) if necessary.
12270     InvalidatePrototypeChainsInternal(user);
12271   }
12272 }
12273 
12274 
12275 // static
InvalidatePrototypeChains(Map * map)12276 void JSObject::InvalidatePrototypeChains(Map* map) {
12277   DisallowHeapAllocation no_gc;
12278   InvalidatePrototypeChainsInternal(map);
12279 }
12280 
12281 
12282 // static
GetOrCreatePrototypeInfo(Handle<JSObject> prototype,Isolate * isolate)12283 Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<JSObject> prototype,
12284                                                     Isolate* isolate) {
12285   Object* maybe_proto_info = prototype->map()->prototype_info();
12286   if (maybe_proto_info->IsPrototypeInfo()) {
12287     return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
12288   }
12289   Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
12290   prototype->map()->set_prototype_info(*proto_info);
12291   return proto_info;
12292 }
12293 
12294 
12295 // static
GetOrCreatePrototypeInfo(Handle<Map> prototype_map,Isolate * isolate)12296 Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<Map> prototype_map,
12297                                                     Isolate* isolate) {
12298   Object* maybe_proto_info = prototype_map->prototype_info();
12299   if (maybe_proto_info->IsPrototypeInfo()) {
12300     return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
12301   }
12302   Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
12303   prototype_map->set_prototype_info(*proto_info);
12304   return proto_info;
12305 }
12306 
12307 // static
SetShouldBeFastPrototypeMap(Handle<Map> map,bool value,Isolate * isolate)12308 void Map::SetShouldBeFastPrototypeMap(Handle<Map> map, bool value,
12309                                       Isolate* isolate) {
12310   if (value == false && !map->prototype_info()->IsPrototypeInfo()) {
12311     // "False" is the implicit default value, so there's nothing to do.
12312     return;
12313   }
12314   GetOrCreatePrototypeInfo(map, isolate)->set_should_be_fast_map(value);
12315 }
12316 
12317 // static
GetOrCreatePrototypeChainValidityCell(Handle<Map> map,Isolate * isolate)12318 Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
12319                                                         Isolate* isolate) {
12320   Handle<Object> maybe_prototype;
12321   if (map->IsJSGlobalObjectMap()) {
12322     DCHECK(map->is_prototype_map());
12323     // Global object is prototype of a global proxy and therefore we can
12324     // use its validity cell for guarding global object's prototype change.
12325     maybe_prototype = isolate->global_object();
12326   } else {
12327     maybe_prototype =
12328         handle(map->GetPrototypeChainRootMap(isolate)->prototype(), isolate);
12329     if (!maybe_prototype->IsJSObject()) return Handle<Cell>::null();
12330   }
12331   Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype);
12332   // Ensure the prototype is registered with its own prototypes so its cell
12333   // will be invalidated when necessary.
12334   JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate),
12335                                       isolate);
12336   Handle<PrototypeInfo> proto_info =
12337       GetOrCreatePrototypeInfo(prototype, isolate);
12338   Object* maybe_cell = proto_info->validity_cell();
12339   // Return existing cell if it's still valid.
12340   if (maybe_cell->IsCell()) {
12341     Handle<Cell> cell(Cell::cast(maybe_cell), isolate);
12342     if (cell->value() == Smi::FromInt(Map::kPrototypeChainValid)) {
12343       return cell;
12344     }
12345   }
12346   // Otherwise create a new cell.
12347   Handle<Cell> cell = isolate->factory()->NewCell(
12348       handle(Smi::FromInt(Map::kPrototypeChainValid), isolate));
12349   proto_info->set_validity_cell(*cell);
12350   return cell;
12351 }
12352 
12353 // static
GetOrCreatePrototypeWeakCell(Handle<JSObject> prototype,Isolate * isolate)12354 Handle<WeakCell> Map::GetOrCreatePrototypeWeakCell(Handle<JSObject> prototype,
12355                                                    Isolate* isolate) {
12356   DCHECK(!prototype.is_null());
12357   Handle<PrototypeInfo> proto_info =
12358       GetOrCreatePrototypeInfo(prototype, isolate);
12359   Object* maybe_cell = proto_info->weak_cell();
12360   // Return existing cell if it's already created.
12361   if (maybe_cell->IsWeakCell()) {
12362     Handle<WeakCell> cell(WeakCell::cast(maybe_cell), isolate);
12363     DCHECK(!cell->cleared());
12364     return cell;
12365   }
12366   // Otherwise create a new cell.
12367   Handle<WeakCell> cell = isolate->factory()->NewWeakCell(prototype);
12368   proto_info->set_weak_cell(*cell);
12369   return cell;
12370 }
12371 
12372 // static
SetPrototype(Handle<Map> map,Handle<Object> prototype,PrototypeOptimizationMode proto_mode)12373 void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype,
12374                        PrototypeOptimizationMode proto_mode) {
12375   RuntimeCallTimerScope stats_scope(*map, &RuntimeCallStats::Map_SetPrototype);
12376 
12377   bool is_hidden = false;
12378   if (prototype->IsJSObject()) {
12379     Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype);
12380     JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode);
12381 
12382     Object* maybe_constructor = prototype_jsobj->map()->GetConstructor();
12383     if (maybe_constructor->IsJSFunction()) {
12384       JSFunction* constructor = JSFunction::cast(maybe_constructor);
12385       Object* data = constructor->shared()->function_data();
12386       is_hidden = (data->IsFunctionTemplateInfo() &&
12387                    FunctionTemplateInfo::cast(data)->hidden_prototype()) ||
12388                   prototype->IsJSGlobalObject();
12389     }
12390   }
12391   map->set_has_hidden_prototype(is_hidden);
12392 
12393   WriteBarrierMode wb_mode = prototype->IsNull(map->GetIsolate())
12394                                  ? SKIP_WRITE_BARRIER
12395                                  : UPDATE_WRITE_BARRIER;
12396   map->set_prototype(*prototype, wb_mode);
12397 }
12398 
12399 
CacheInitialJSArrayMaps(Handle<Context> native_context,Handle<Map> initial_map)12400 Handle<Object> CacheInitialJSArrayMaps(
12401     Handle<Context> native_context, Handle<Map> initial_map) {
12402   // Replace all of the cached initial array maps in the native context with
12403   // the appropriate transitioned elements kind maps.
12404   Handle<Map> current_map = initial_map;
12405   ElementsKind kind = current_map->elements_kind();
12406   DCHECK_EQ(GetInitialFastElementsKind(), kind);
12407   native_context->set(Context::ArrayMapIndex(kind), *current_map);
12408   for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1;
12409        i < kFastElementsKindCount; ++i) {
12410     Handle<Map> new_map;
12411     ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
12412     if (Map* maybe_elements_transition = current_map->ElementsTransitionMap()) {
12413       new_map = handle(maybe_elements_transition);
12414     } else {
12415       new_map = Map::CopyAsElementsKind(
12416           current_map, next_kind, INSERT_TRANSITION);
12417     }
12418     DCHECK_EQ(next_kind, new_map->elements_kind());
12419     native_context->set(Context::ArrayMapIndex(next_kind), *new_map);
12420     current_map = new_map;
12421   }
12422   return initial_map;
12423 }
12424 
12425 
SetInstancePrototype(Handle<JSFunction> function,Handle<Object> value)12426 void JSFunction::SetInstancePrototype(Handle<JSFunction> function,
12427                                       Handle<Object> value) {
12428   Isolate* isolate = function->GetIsolate();
12429 
12430   DCHECK(value->IsJSReceiver());
12431 
12432   // Now some logic for the maps of the objects that are created by using this
12433   // function as a constructor.
12434   if (function->has_initial_map()) {
12435     // If the function has allocated the initial map replace it with a
12436     // copy containing the new prototype.  Also complete any in-object
12437     // slack tracking that is in progress at this point because it is
12438     // still tracking the old copy.
12439     function->CompleteInobjectSlackTrackingIfActive();
12440 
12441     Handle<Map> initial_map(function->initial_map(), isolate);
12442 
12443     if (!initial_map->GetIsolate()->bootstrapper()->IsActive() &&
12444         initial_map->instance_type() == JS_OBJECT_TYPE) {
12445       // Put the value in the initial map field until an initial map is needed.
12446       // At that point, a new initial map is created and the prototype is put
12447       // into the initial map where it belongs.
12448       function->set_prototype_or_initial_map(*value);
12449     } else {
12450       Handle<Map> new_map = Map::Copy(initial_map, "SetInstancePrototype");
12451       JSFunction::SetInitialMap(function, new_map, value);
12452 
12453       // If the function is used as the global Array function, cache the
12454       // updated initial maps (and transitioned versions) in the native context.
12455       Handle<Context> native_context(function->context()->native_context(),
12456                                      isolate);
12457       Handle<Object> array_function(
12458           native_context->get(Context::ARRAY_FUNCTION_INDEX), isolate);
12459       if (array_function->IsJSFunction() &&
12460           *function == JSFunction::cast(*array_function)) {
12461         CacheInitialJSArrayMaps(native_context, new_map);
12462       }
12463     }
12464 
12465     // Deoptimize all code that embeds the previous initial map.
12466     initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
12467         isolate, DependentCode::kInitialMapChangedGroup);
12468   } else {
12469     // Put the value in the initial map field until an initial map is
12470     // needed.  At that point, a new initial map is created and the
12471     // prototype is put into the initial map where it belongs.
12472     function->set_prototype_or_initial_map(*value);
12473     if (value->IsJSObject()) {
12474       // Optimize as prototype to detach it from its transition tree.
12475       JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value),
12476                                     FAST_PROTOTYPE);
12477     }
12478   }
12479   isolate->heap()->ClearInstanceofCache();
12480 }
12481 
12482 
SetPrototype(Handle<JSFunction> function,Handle<Object> value)12483 void JSFunction::SetPrototype(Handle<JSFunction> function,
12484                               Handle<Object> value) {
12485   DCHECK(function->IsConstructor() ||
12486          IsGeneratorFunction(function->shared()->kind()));
12487   Handle<Object> construct_prototype = value;
12488 
12489   // If the value is not a JSReceiver, store the value in the map's
12490   // constructor field so it can be accessed.  Also, set the prototype
12491   // used for constructing objects to the original object prototype.
12492   // See ECMA-262 13.2.2.
12493   if (!value->IsJSReceiver()) {
12494     // Copy the map so this does not affect unrelated functions.
12495     // Remove map transitions because they point to maps with a
12496     // different prototype.
12497     Handle<Map> new_map = Map::Copy(handle(function->map()), "SetPrototype");
12498 
12499     JSObject::MigrateToMap(function, new_map);
12500     new_map->SetConstructor(*value);
12501     new_map->set_non_instance_prototype(true);
12502     Isolate* isolate = new_map->GetIsolate();
12503 
12504     construct_prototype = handle(
12505         IsGeneratorFunction(function->shared()->kind())
12506             ? function->context()
12507                   ->native_context()
12508                   ->initial_generator_prototype()
12509             : function->context()->native_context()->initial_object_prototype(),
12510         isolate);
12511   } else {
12512     function->map()->set_non_instance_prototype(false);
12513   }
12514 
12515   return SetInstancePrototype(function, construct_prototype);
12516 }
12517 
12518 
RemovePrototype()12519 bool JSFunction::RemovePrototype() {
12520   Context* native_context = context()->native_context();
12521   Map* no_prototype_map =
12522       is_strict(shared()->language_mode())
12523           ? native_context->strict_function_without_prototype_map()
12524           : native_context->sloppy_function_without_prototype_map();
12525 
12526   if (map() == no_prototype_map) return true;
12527 
12528 #ifdef DEBUG
12529   if (map() != (is_strict(shared()->language_mode())
12530                     ? native_context->strict_function_map()
12531                     : native_context->sloppy_function_map())) {
12532     return false;
12533   }
12534 #endif
12535 
12536   set_map(no_prototype_map);
12537   set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value());
12538   return true;
12539 }
12540 
12541 
SetInitialMap(Handle<JSFunction> function,Handle<Map> map,Handle<Object> prototype)12542 void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
12543                                Handle<Object> prototype) {
12544   if (map->prototype() != *prototype) {
12545     Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
12546   }
12547   function->set_prototype_or_initial_map(*map);
12548   map->SetConstructor(*function);
12549 #if TRACE_MAPS
12550   if (FLAG_trace_maps) {
12551     PrintF("[TraceMaps: InitialMap map= %p SFI= %d_%s ]\n",
12552            reinterpret_cast<void*>(*map), function->shared()->unique_id(),
12553            function->shared()->DebugName()->ToCString().get());
12554   }
12555 #endif
12556 }
12557 
12558 
12559 #ifdef DEBUG
12560 namespace {
12561 
CanSubclassHaveInobjectProperties(InstanceType instance_type)12562 bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
12563   switch (instance_type) {
12564     case JS_API_OBJECT_TYPE:
12565     case JS_ARRAY_BUFFER_TYPE:
12566     case JS_ARRAY_TYPE:
12567     case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
12568     case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
12569     case JS_DATA_VIEW_TYPE:
12570     case JS_DATE_TYPE:
12571     case JS_FUNCTION_TYPE:
12572     case JS_GENERATOR_OBJECT_TYPE:
12573     case JS_MAP_ITERATOR_TYPE:
12574     case JS_MAP_TYPE:
12575     case JS_MESSAGE_OBJECT_TYPE:
12576     case JS_OBJECT_TYPE:
12577     case JS_ERROR_TYPE:
12578     case JS_ARGUMENTS_TYPE:
12579     case JS_PROMISE_TYPE:
12580     case JS_REGEXP_TYPE:
12581     case JS_SET_ITERATOR_TYPE:
12582     case JS_SET_TYPE:
12583     case JS_SPECIAL_API_OBJECT_TYPE:
12584     case JS_TYPED_ARRAY_TYPE:
12585     case JS_VALUE_TYPE:
12586     case JS_WEAK_MAP_TYPE:
12587     case JS_WEAK_SET_TYPE:
12588       return true;
12589 
12590     case BYTECODE_ARRAY_TYPE:
12591     case BYTE_ARRAY_TYPE:
12592     case CELL_TYPE:
12593     case CODE_TYPE:
12594     case FILLER_TYPE:
12595     case FIXED_ARRAY_TYPE:
12596     case FIXED_DOUBLE_ARRAY_TYPE:
12597     case FOREIGN_TYPE:
12598     case FREE_SPACE_TYPE:
12599     case HEAP_NUMBER_TYPE:
12600     case JS_BOUND_FUNCTION_TYPE:
12601     case JS_GLOBAL_OBJECT_TYPE:
12602     case JS_GLOBAL_PROXY_TYPE:
12603     case JS_PROXY_TYPE:
12604     case MAP_TYPE:
12605     case MUTABLE_HEAP_NUMBER_TYPE:
12606     case ODDBALL_TYPE:
12607     case PROPERTY_CELL_TYPE:
12608     case SHARED_FUNCTION_INFO_TYPE:
12609     case SYMBOL_TYPE:
12610     case WEAK_CELL_TYPE:
12611 
12612 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
12613   case FIXED_##TYPE##_ARRAY_TYPE:
12614 #undef TYPED_ARRAY_CASE
12615 
12616 #define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE:
12617       STRUCT_LIST(MAKE_STRUCT_CASE)
12618 #undef MAKE_STRUCT_CASE
12619       // We must not end up here for these instance types at all.
12620       UNREACHABLE();
12621     // Fall through.
12622     default:
12623       return false;
12624   }
12625 }
12626 
12627 }  // namespace
12628 #endif
12629 
12630 
EnsureHasInitialMap(Handle<JSFunction> function)12631 void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
12632   DCHECK(function->IsConstructor() ||
12633          IsResumableFunction(function->shared()->kind()));
12634   if (function->has_initial_map()) return;
12635   Isolate* isolate = function->GetIsolate();
12636 
12637   // The constructor should be compiled for the optimization hints to be
12638   // available.
12639   Compiler::Compile(function, Compiler::CLEAR_EXCEPTION);
12640 
12641   // First create a new map with the size and number of in-object properties
12642   // suggested by the function.
12643   InstanceType instance_type;
12644   if (IsResumableFunction(function->shared()->kind())) {
12645     instance_type = JS_GENERATOR_OBJECT_TYPE;
12646   } else {
12647     instance_type = JS_OBJECT_TYPE;
12648   }
12649   int instance_size;
12650   int in_object_properties;
12651   function->CalculateInstanceSize(instance_type, 0, &instance_size,
12652                                   &in_object_properties);
12653 
12654   Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size);
12655 
12656   // Fetch or allocate prototype.
12657   Handle<Object> prototype;
12658   if (function->has_instance_prototype()) {
12659     prototype = handle(function->instance_prototype(), isolate);
12660   } else {
12661     prototype = isolate->factory()->NewFunctionPrototype(function);
12662   }
12663   map->SetInObjectProperties(in_object_properties);
12664   map->set_unused_property_fields(in_object_properties);
12665   DCHECK(map->has_fast_object_elements());
12666 
12667   // Finally link initial map and constructor function.
12668   DCHECK(prototype->IsJSReceiver());
12669   JSFunction::SetInitialMap(function, map, prototype);
12670   map->StartInobjectSlackTracking();
12671 }
12672 
12673 namespace {
FastInitializeDerivedMap(Isolate * isolate,Handle<JSFunction> new_target,Handle<JSFunction> constructor,Handle<Map> constructor_initial_map)12674 bool FastInitializeDerivedMap(Isolate* isolate, Handle<JSFunction> new_target,
12675                               Handle<JSFunction> constructor,
12676                               Handle<Map> constructor_initial_map) {
12677   // Check that |function|'s initial map still in sync with the |constructor|,
12678   // otherwise we must create a new initial map for |function|.
12679   if (new_target->has_initial_map() &&
12680       new_target->initial_map()->GetConstructor() == *constructor) {
12681     DCHECK(new_target->instance_prototype()->IsJSReceiver());
12682     return true;
12683   }
12684   // Create a new map with the size and number of in-object properties
12685   // suggested by |function|.
12686 
12687   // Link initial map and constructor function if the new.target is actually a
12688   // subclass constructor.
12689   if (!IsDerivedConstructor(new_target->shared()->kind())) return false;
12690 
12691   Handle<Object> prototype(new_target->instance_prototype(), isolate);
12692   InstanceType instance_type = constructor_initial_map->instance_type();
12693   DCHECK(CanSubclassHaveInobjectProperties(instance_type));
12694 
12695   int internal_fields =
12696       JSObject::GetInternalFieldCount(*constructor_initial_map);
12697   int pre_allocated = constructor_initial_map->GetInObjectProperties() -
12698                       constructor_initial_map->unused_property_fields();
12699   int instance_size;
12700   int in_object_properties;
12701   new_target->CalculateInstanceSizeForDerivedClass(
12702       instance_type, internal_fields, &instance_size,
12703       &in_object_properties);
12704 
12705   int unused_property_fields = in_object_properties - pre_allocated;
12706   Handle<Map> map =
12707       Map::CopyInitialMap(constructor_initial_map, instance_size,
12708                           in_object_properties, unused_property_fields);
12709   map->set_new_target_is_base(false);
12710 
12711   JSFunction::SetInitialMap(new_target, map, prototype);
12712   map->SetConstructor(*constructor);
12713   map->set_construction_counter(Map::kNoSlackTracking);
12714   map->StartInobjectSlackTracking();
12715 
12716   return true;
12717 }
12718 
12719 }  // namespace
12720 
12721 // static
GetDerivedMap(Isolate * isolate,Handle<JSFunction> constructor,Handle<JSReceiver> new_target)12722 MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
12723                                            Handle<JSFunction> constructor,
12724                                            Handle<JSReceiver> new_target) {
12725   EnsureHasInitialMap(constructor);
12726 
12727   Handle<Map> constructor_initial_map(constructor->initial_map(), isolate);
12728   if (*new_target == *constructor) return constructor_initial_map;
12729 
12730   // Fast case, new.target is a subclass of constructor. The map is cacheable
12731   // (and may already have been cached). new.target.prototype is guaranteed to
12732   // be a JSReceiver.
12733   if (new_target->IsJSFunction()) {
12734     Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
12735 
12736     // Check that |function|'s initial map still in sync with the |constructor|,
12737     // otherwise we must create a new initial map for |function|.
12738     if (FastInitializeDerivedMap(isolate, function, constructor,
12739                                  constructor_initial_map)) {
12740       return handle(function->initial_map(), isolate);
12741     }
12742   }
12743 
12744   // Slow path, new.target is either a proxy or can't cache the map.
12745   // new.target.prototype is not guaranteed to be a JSReceiver, and may need to
12746   // fall back to the intrinsicDefaultProto.
12747   Handle<Object> prototype;
12748   if (new_target->IsJSFunction()) {
12749     Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
12750     // Make sure the new.target.prototype is cached.
12751     EnsureHasInitialMap(function);
12752     prototype = handle(function->prototype(), isolate);
12753   } else {
12754     Handle<String> prototype_string = isolate->factory()->prototype_string();
12755     ASSIGN_RETURN_ON_EXCEPTION(
12756         isolate, prototype,
12757         JSReceiver::GetProperty(new_target, prototype_string), Map);
12758     // The above prototype lookup might change the constructor and its
12759     // prototype, hence we have to reload the initial map.
12760     EnsureHasInitialMap(constructor);
12761     constructor_initial_map = handle(constructor->initial_map(), isolate);
12762   }
12763 
12764   // If prototype is not a JSReceiver, fetch the intrinsicDefaultProto from the
12765   // correct realm. Rather than directly fetching the .prototype, we fetch the
12766   // constructor that points to the .prototype. This relies on
12767   // constructor.prototype being FROZEN for those constructors.
12768   if (!prototype->IsJSReceiver()) {
12769     Handle<Context> context;
12770     ASSIGN_RETURN_ON_EXCEPTION(isolate, context,
12771                                JSReceiver::GetFunctionRealm(new_target), Map);
12772     DCHECK(context->IsNativeContext());
12773     Handle<Object> maybe_index = JSReceiver::GetDataProperty(
12774         constructor, isolate->factory()->native_context_index_symbol());
12775     int index = maybe_index->IsSmi() ? Smi::cast(*maybe_index)->value()
12776                                      : Context::OBJECT_FUNCTION_INDEX;
12777     Handle<JSFunction> realm_constructor(JSFunction::cast(context->get(index)));
12778     prototype = handle(realm_constructor->prototype(), isolate);
12779   }
12780 
12781   Handle<Map> map = Map::CopyInitialMap(constructor_initial_map);
12782   map->set_new_target_is_base(false);
12783   DCHECK(prototype->IsJSReceiver());
12784   if (map->prototype() != *prototype) {
12785     Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
12786   }
12787   map->SetConstructor(*constructor);
12788   return map;
12789 }
12790 
12791 
PrintName(FILE * out)12792 void JSFunction::PrintName(FILE* out) {
12793   std::unique_ptr<char[]> name = shared()->DebugName()->ToCString();
12794   PrintF(out, "%s", name.get());
12795 }
12796 
12797 
GetName(Handle<JSFunction> function)12798 Handle<String> JSFunction::GetName(Handle<JSFunction> function) {
12799   Isolate* isolate = function->GetIsolate();
12800   Handle<Object> name =
12801       JSReceiver::GetDataProperty(function, isolate->factory()->name_string());
12802   if (name->IsString()) return Handle<String>::cast(name);
12803   return handle(function->shared()->DebugName(), isolate);
12804 }
12805 
12806 
GetDebugName(Handle<JSFunction> function)12807 Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) {
12808   Isolate* isolate = function->GetIsolate();
12809   Handle<Object> name = JSReceiver::GetDataProperty(
12810       function, isolate->factory()->display_name_string());
12811   if (name->IsString()) return Handle<String>::cast(name);
12812   return JSFunction::GetName(function);
12813 }
12814 
SetName(Handle<JSFunction> function,Handle<Name> name,Handle<String> prefix)12815 void JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name,
12816                          Handle<String> prefix) {
12817   Isolate* isolate = function->GetIsolate();
12818   Handle<String> function_name = Name::ToFunctionName(name).ToHandleChecked();
12819   if (prefix->length() > 0) {
12820     IncrementalStringBuilder builder(isolate);
12821     builder.AppendString(prefix);
12822     builder.AppendCharacter(' ');
12823     builder.AppendString(function_name);
12824     function_name = builder.Finish().ToHandleChecked();
12825   }
12826   JSObject::DefinePropertyOrElementIgnoreAttributes(
12827       function, isolate->factory()->name_string(), function_name,
12828       static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY))
12829       .ToHandleChecked();
12830 }
12831 
12832 namespace {
12833 
12834 char const kNativeCodeSource[] = "function () { [native code] }";
12835 
12836 
NativeCodeFunctionSourceString(Handle<SharedFunctionInfo> shared_info)12837 Handle<String> NativeCodeFunctionSourceString(
12838     Handle<SharedFunctionInfo> shared_info) {
12839   Isolate* const isolate = shared_info->GetIsolate();
12840   if (shared_info->name()->IsString()) {
12841     IncrementalStringBuilder builder(isolate);
12842     builder.AppendCString("function ");
12843     builder.AppendString(handle(String::cast(shared_info->name()), isolate));
12844     builder.AppendCString("() { [native code] }");
12845     return builder.Finish().ToHandleChecked();
12846   }
12847   return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource);
12848 }
12849 
12850 }  // namespace
12851 
12852 
12853 // static
ToString(Handle<JSBoundFunction> function)12854 Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) {
12855   Isolate* const isolate = function->GetIsolate();
12856   return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource);
12857 }
12858 
12859 
12860 // static
ToString(Handle<JSFunction> function)12861 Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
12862   Isolate* const isolate = function->GetIsolate();
12863   Handle<SharedFunctionInfo> shared_info(function->shared(), isolate);
12864 
12865   // Check if {function} should hide its source code.
12866   if (!shared_info->IsUserJavaScript()) {
12867     return NativeCodeFunctionSourceString(shared_info);
12868   }
12869 
12870   // Check if we should print {function} as a class.
12871   Handle<Object> class_start_position = JSReceiver::GetDataProperty(
12872       function, isolate->factory()->class_start_position_symbol());
12873   if (class_start_position->IsSmi()) {
12874     Handle<Object> class_end_position = JSReceiver::GetDataProperty(
12875         function, isolate->factory()->class_end_position_symbol());
12876     Handle<String> script_source(
12877         String::cast(Script::cast(shared_info->script())->source()), isolate);
12878     return isolate->factory()->NewSubString(
12879         script_source, Handle<Smi>::cast(class_start_position)->value(),
12880         Handle<Smi>::cast(class_end_position)->value());
12881   }
12882 
12883   // Check if we have source code for the {function}.
12884   if (!shared_info->HasSourceCode()) {
12885     return NativeCodeFunctionSourceString(shared_info);
12886   }
12887 
12888   if (FLAG_harmony_function_tostring) {
12889     return Handle<String>::cast(shared_info->GetSourceCodeHarmony());
12890   }
12891 
12892   IncrementalStringBuilder builder(isolate);
12893   FunctionKind kind = shared_info->kind();
12894   if (!IsArrowFunction(kind)) {
12895     if (IsConciseMethod(kind)) {
12896       if (IsGeneratorFunction(kind)) {
12897         builder.AppendCharacter('*');
12898       } else if (IsAsyncFunction(kind)) {
12899         builder.AppendCString("async ");
12900       }
12901     } else {
12902       if (IsGeneratorFunction(kind)) {
12903         builder.AppendCString("function* ");
12904       } else if (IsAsyncFunction(kind)) {
12905         builder.AppendCString("async function ");
12906       } else {
12907         builder.AppendCString("function ");
12908       }
12909     }
12910     if (shared_info->name_should_print_as_anonymous()) {
12911       builder.AppendCString("anonymous");
12912     } else if (!shared_info->is_anonymous_expression()) {
12913       builder.AppendString(handle(String::cast(shared_info->name()), isolate));
12914     }
12915   }
12916   builder.AppendString(Handle<String>::cast(shared_info->GetSourceCode()));
12917   return builder.Finish().ToHandleChecked();
12918 }
12919 
Initialize(Isolate * isolate,Handle<Oddball> oddball,const char * to_string,Handle<Object> to_number,const char * type_of,byte kind)12920 void Oddball::Initialize(Isolate* isolate, Handle<Oddball> oddball,
12921                          const char* to_string, Handle<Object> to_number,
12922                          const char* type_of, byte kind) {
12923   Handle<String> internalized_to_string =
12924       isolate->factory()->InternalizeUtf8String(to_string);
12925   Handle<String> internalized_type_of =
12926       isolate->factory()->InternalizeUtf8String(type_of);
12927   oddball->set_to_number_raw(to_number->Number());
12928   oddball->set_to_number(*to_number);
12929   oddball->set_to_string(*internalized_to_string);
12930   oddball->set_type_of(*internalized_type_of);
12931   oddball->set_kind(kind);
12932 }
12933 
SetEvalOrigin(Handle<Script> script,Handle<SharedFunctionInfo> outer_info,int eval_position)12934 void Script::SetEvalOrigin(Handle<Script> script,
12935                            Handle<SharedFunctionInfo> outer_info,
12936                            int eval_position) {
12937   if (eval_position == kNoSourcePosition) {
12938     // If the position is missing, attempt to get the code offset from the
12939     // current activation.  Do not translate the code offset into source
12940     // position, but store it as negative value for lazy translation.
12941     StackTraceFrameIterator it(script->GetIsolate());
12942     if (!it.done() && it.is_javascript()) {
12943       FrameSummary summary = FrameSummary::GetTop(it.javascript_frame());
12944       script->set_eval_from_shared(summary.AsJavaScript().function()->shared());
12945       script->set_eval_from_position(-summary.code_offset());
12946       return;
12947     }
12948     eval_position = 0;
12949   }
12950   script->set_eval_from_shared(*outer_info);
12951   script->set_eval_from_position(eval_position);
12952 }
12953 
GetEvalPosition()12954 int Script::GetEvalPosition() {
12955   DisallowHeapAllocation no_gc;
12956   DCHECK(compilation_type() == Script::COMPILATION_TYPE_EVAL);
12957   int position = eval_from_position();
12958   if (position < 0) {
12959     // Due to laziness, the position may not have been translated from code
12960     // offset yet, which would be encoded as negative integer. In that case,
12961     // translate and set the position.
12962     if (eval_from_shared()->IsUndefined(GetIsolate())) {
12963       position = 0;
12964     } else {
12965       SharedFunctionInfo* shared = SharedFunctionInfo::cast(eval_from_shared());
12966       position = shared->abstract_code()->SourcePosition(-position);
12967     }
12968     DCHECK(position >= 0);
12969     set_eval_from_position(position);
12970   }
12971   return position;
12972 }
12973 
InitLineEnds(Handle<Script> script)12974 void Script::InitLineEnds(Handle<Script> script) {
12975   Isolate* isolate = script->GetIsolate();
12976   if (!script->line_ends()->IsUndefined(isolate)) return;
12977   DCHECK_NE(Script::TYPE_WASM, script->type());
12978 
12979   Object* src_obj = script->source();
12980   if (!src_obj->IsString()) {
12981     DCHECK(src_obj->IsUndefined(isolate));
12982     script->set_line_ends(isolate->heap()->empty_fixed_array());
12983   } else {
12984     DCHECK(src_obj->IsString());
12985     Handle<String> src(String::cast(src_obj), isolate);
12986     Handle<FixedArray> array = String::CalculateLineEnds(src, true);
12987     script->set_line_ends(*array);
12988   }
12989 
12990   DCHECK(script->line_ends()->IsFixedArray());
12991 }
12992 
GetPositionInfo(Handle<Script> script,int position,PositionInfo * info,OffsetFlag offset_flag)12993 bool Script::GetPositionInfo(Handle<Script> script, int position,
12994                              PositionInfo* info, OffsetFlag offset_flag) {
12995   // For wasm, we do not create an artificial line_ends array, but do the
12996   // translation directly.
12997   if (script->type() != Script::TYPE_WASM) InitLineEnds(script);
12998   return script->GetPositionInfo(position, info, offset_flag);
12999 }
13000 
13001 namespace {
GetPositionInfoSlow(const Script * script,int position,Script::PositionInfo * info)13002 bool GetPositionInfoSlow(const Script* script, int position,
13003                          Script::PositionInfo* info) {
13004   if (!script->source()->IsString()) return false;
13005   if (position < 0) position = 0;
13006 
13007   String* source_string = String::cast(script->source());
13008   int line = 0;
13009   int line_start = 0;
13010   int len = source_string->length();
13011   for (int pos = 0; pos <= len; ++pos) {
13012     if (pos == len || source_string->Get(pos) == '\n') {
13013       if (position <= pos) {
13014         info->line = line;
13015         info->column = position - line_start;
13016         info->line_start = line_start;
13017         info->line_end = pos;
13018         return true;
13019       }
13020       line++;
13021       line_start = pos + 1;
13022     }
13023   }
13024   return false;
13025 }
13026 }  // namespace
13027 
13028 #define SMI_VALUE(x) (Smi::cast(x)->value())
GetPositionInfo(int position,PositionInfo * info,OffsetFlag offset_flag) const13029 bool Script::GetPositionInfo(int position, PositionInfo* info,
13030                              OffsetFlag offset_flag) const {
13031   DisallowHeapAllocation no_allocation;
13032 
13033   // For wasm, we do not rely on the line_ends array, but do the translation
13034   // directly.
13035   if (type() == Script::TYPE_WASM) {
13036     Handle<WasmCompiledModule> compiled_module(
13037         WasmCompiledModule::cast(wasm_compiled_module()));
13038     DCHECK_LE(0, position);
13039     return compiled_module->GetPositionInfo(static_cast<uint32_t>(position),
13040                                             info);
13041   }
13042 
13043   if (line_ends()->IsUndefined(GetIsolate())) {
13044     // Slow mode: we do not have line_ends. We have to iterate through source.
13045     if (!GetPositionInfoSlow(this, position, info)) return false;
13046   } else {
13047     DCHECK(line_ends()->IsFixedArray());
13048     FixedArray* ends = FixedArray::cast(line_ends());
13049 
13050     const int ends_len = ends->length();
13051     if (ends_len == 0) return false;
13052 
13053     // Return early on invalid positions. Negative positions behave as if 0 was
13054     // passed, and positions beyond the end of the script return as failure.
13055     if (position < 0) {
13056       position = 0;
13057     } else if (position > SMI_VALUE(ends->get(ends_len - 1))) {
13058       return false;
13059     }
13060 
13061     // Determine line number by doing a binary search on the line ends array.
13062     if (SMI_VALUE(ends->get(0)) >= position) {
13063       info->line = 0;
13064       info->line_start = 0;
13065       info->column = position;
13066     } else {
13067       int left = 0;
13068       int right = ends_len - 1;
13069 
13070       while (right > 0) {
13071         DCHECK_LE(left, right);
13072         const int mid = (left + right) / 2;
13073         if (position > SMI_VALUE(ends->get(mid))) {
13074           left = mid + 1;
13075         } else if (position <= SMI_VALUE(ends->get(mid - 1))) {
13076           right = mid - 1;
13077         } else {
13078           info->line = mid;
13079           break;
13080         }
13081       }
13082       DCHECK(SMI_VALUE(ends->get(info->line)) >= position &&
13083              SMI_VALUE(ends->get(info->line - 1)) < position);
13084       info->line_start = SMI_VALUE(ends->get(info->line - 1)) + 1;
13085       info->column = position - info->line_start;
13086     }
13087 
13088     // Line end is position of the linebreak character.
13089     info->line_end = SMI_VALUE(ends->get(info->line));
13090     if (info->line_end > 0) {
13091       DCHECK(source()->IsString());
13092       String* src = String::cast(source());
13093       if (src->length() >= info->line_end &&
13094           src->Get(info->line_end - 1) == '\r') {
13095         info->line_end--;
13096       }
13097     }
13098   }
13099 
13100   // Add offsets if requested.
13101   if (offset_flag == WITH_OFFSET) {
13102     if (info->line == 0) {
13103       info->column += column_offset();
13104     }
13105     info->line += line_offset();
13106   }
13107 
13108   return true;
13109 }
13110 #undef SMI_VALUE
13111 
GetColumnNumber(Handle<Script> script,int code_pos)13112 int Script::GetColumnNumber(Handle<Script> script, int code_pos) {
13113   PositionInfo info;
13114   GetPositionInfo(script, code_pos, &info, WITH_OFFSET);
13115   return info.column;
13116 }
13117 
GetColumnNumber(int code_pos) const13118 int Script::GetColumnNumber(int code_pos) const {
13119   PositionInfo info;
13120   GetPositionInfo(code_pos, &info, WITH_OFFSET);
13121   return info.column;
13122 }
13123 
GetLineNumber(Handle<Script> script,int code_pos)13124 int Script::GetLineNumber(Handle<Script> script, int code_pos) {
13125   PositionInfo info;
13126   GetPositionInfo(script, code_pos, &info, WITH_OFFSET);
13127   return info.line;
13128 }
13129 
GetLineNumber(int code_pos) const13130 int Script::GetLineNumber(int code_pos) const {
13131   PositionInfo info;
13132   GetPositionInfo(code_pos, &info, WITH_OFFSET);
13133   return info.line;
13134 }
13135 
GetNameOrSourceURL()13136 Object* Script::GetNameOrSourceURL() {
13137   Isolate* isolate = GetIsolate();
13138   // Keep in sync with ScriptNameOrSourceURL in messages.js.
13139   if (!source_url()->IsUndefined(isolate)) return source_url();
13140   return name();
13141 }
13142 
13143 
GetWrapper(Handle<Script> script)13144 Handle<JSObject> Script::GetWrapper(Handle<Script> script) {
13145   Isolate* isolate = script->GetIsolate();
13146   if (!script->wrapper()->IsUndefined(isolate)) {
13147     DCHECK(script->wrapper()->IsWeakCell());
13148     Handle<WeakCell> cell(WeakCell::cast(script->wrapper()));
13149     if (!cell->cleared()) {
13150       // Return a handle for the existing script wrapper from the cache.
13151       return handle(JSObject::cast(cell->value()));
13152     }
13153     // If we found an empty WeakCell, that means the script wrapper was
13154     // GCed.  We are not notified directly of that, so we decrement here
13155     // so that we at least don't count double for any given script.
13156     isolate->counters()->script_wrappers()->Decrement();
13157   }
13158   // Construct a new script wrapper.
13159   isolate->counters()->script_wrappers()->Increment();
13160   Handle<JSFunction> constructor = isolate->script_function();
13161   Handle<JSValue> result =
13162       Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
13163   result->set_value(*script);
13164   Handle<WeakCell> cell = isolate->factory()->NewWeakCell(result);
13165   script->set_wrapper(*cell);
13166   return result;
13167 }
13168 
FindSharedFunctionInfo(Isolate * isolate,const FunctionLiteral * fun)13169 MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
13170     Isolate* isolate, const FunctionLiteral* fun) {
13171   CHECK_NE(fun->function_literal_id(), FunctionLiteral::kIdTypeInvalid);
13172   CHECK_LT(fun->function_literal_id(), shared_function_infos()->length());
13173   Object* shared = shared_function_infos()->get(fun->function_literal_id());
13174   if (shared->IsUndefined(isolate) || WeakCell::cast(shared)->cleared()) {
13175     return MaybeHandle<SharedFunctionInfo>();
13176   }
13177   return handle(SharedFunctionInfo::cast(WeakCell::cast(shared)->value()));
13178 }
13179 
Iterator(Isolate * isolate)13180 Script::Iterator::Iterator(Isolate* isolate)
13181     : iterator_(isolate->heap()->script_list()) {}
13182 
13183 
Next()13184 Script* Script::Iterator::Next() { return iterator_.Next<Script>(); }
13185 
ScriptIterator(Handle<Script> script)13186 SharedFunctionInfo::ScriptIterator::ScriptIterator(Handle<Script> script)
13187     : ScriptIterator(script->GetIsolate(),
13188                      handle(script->shared_function_infos())) {}
13189 
ScriptIterator(Isolate * isolate,Handle<FixedArray> shared_function_infos)13190 SharedFunctionInfo::ScriptIterator::ScriptIterator(
13191     Isolate* isolate, Handle<FixedArray> shared_function_infos)
13192     : isolate_(isolate),
13193       shared_function_infos_(shared_function_infos),
13194       index_(0) {}
13195 
Next()13196 SharedFunctionInfo* SharedFunctionInfo::ScriptIterator::Next() {
13197   while (index_ < shared_function_infos_->length()) {
13198     Object* raw = shared_function_infos_->get(index_++);
13199     if (raw->IsUndefined(isolate_) || WeakCell::cast(raw)->cleared()) continue;
13200     return SharedFunctionInfo::cast(WeakCell::cast(raw)->value());
13201   }
13202   return nullptr;
13203 }
13204 
Reset(Handle<Script> script)13205 void SharedFunctionInfo::ScriptIterator::Reset(Handle<Script> script) {
13206   shared_function_infos_ = handle(script->shared_function_infos());
13207   index_ = 0;
13208 }
13209 
GlobalIterator(Isolate * isolate)13210 SharedFunctionInfo::GlobalIterator::GlobalIterator(Isolate* isolate)
13211     : script_iterator_(isolate),
13212       noscript_sfi_iterator_(isolate->heap()->noscript_shared_function_infos()),
13213       sfi_iterator_(handle(script_iterator_.Next(), isolate)) {}
13214 
Next()13215 SharedFunctionInfo* SharedFunctionInfo::GlobalIterator::Next() {
13216   SharedFunctionInfo* next = noscript_sfi_iterator_.Next<SharedFunctionInfo>();
13217   if (next != nullptr) return next;
13218   for (;;) {
13219     next = sfi_iterator_.Next();
13220     if (next != nullptr) return next;
13221     Script* next_script = script_iterator_.Next();
13222     if (next_script == nullptr) return nullptr;
13223     sfi_iterator_.Reset(handle(next_script));
13224   }
13225 }
13226 
13227 
SetScript(Handle<SharedFunctionInfo> shared,Handle<Object> script_object)13228 void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
13229                                    Handle<Object> script_object) {
13230   DCHECK_NE(shared->function_literal_id(), FunctionLiteral::kIdTypeInvalid);
13231   if (shared->script() == *script_object) return;
13232   Isolate* isolate = shared->GetIsolate();
13233 
13234   // Add shared function info to new script's list. If a collection occurs,
13235   // the shared function info may be temporarily in two lists.
13236   // This is okay because the gc-time processing of these lists can tolerate
13237   // duplicates.
13238   if (script_object->IsScript()) {
13239     Handle<Script> script = Handle<Script>::cast(script_object);
13240     Handle<FixedArray> list = handle(script->shared_function_infos(), isolate);
13241 #ifdef DEBUG
13242     DCHECK_LT(shared->function_literal_id(), list->length());
13243     if (list->get(shared->function_literal_id())->IsWeakCell() &&
13244         !WeakCell::cast(list->get(shared->function_literal_id()))->cleared()) {
13245       DCHECK(
13246           WeakCell::cast(list->get(shared->function_literal_id()))->value() ==
13247           *shared);
13248     }
13249 #endif
13250     Handle<WeakCell> cell = isolate->factory()->NewWeakCell(shared);
13251     list->set(shared->function_literal_id(), *cell);
13252   } else {
13253     Handle<Object> list = isolate->factory()->noscript_shared_function_infos();
13254 
13255 #ifdef DEBUG
13256     if (FLAG_enable_slow_asserts) {
13257       WeakFixedArray::Iterator iterator(*list);
13258       SharedFunctionInfo* next;
13259       while ((next = iterator.Next<SharedFunctionInfo>())) {
13260         DCHECK_NE(next, *shared);
13261       }
13262     }
13263 #endif  // DEBUG
13264 
13265     list = WeakFixedArray::Add(list, shared);
13266 
13267     isolate->heap()->SetRootNoScriptSharedFunctionInfos(*list);
13268   }
13269 
13270   if (shared->script()->IsScript()) {
13271     // Remove shared function info from old script's list.
13272     Script* old_script = Script::cast(shared->script());
13273 
13274     // Due to liveedit, it might happen that the old_script doesn't know
13275     // about the SharedFunctionInfo, so we have to guard against that.
13276     Handle<FixedArray> infos(old_script->shared_function_infos(), isolate);
13277     if (shared->function_literal_id() < infos->length()) {
13278       Object* raw = old_script->shared_function_infos()->get(
13279           shared->function_literal_id());
13280       if (!raw->IsWeakCell() || WeakCell::cast(raw)->value() == *shared) {
13281         old_script->shared_function_infos()->set(
13282             shared->function_literal_id(), isolate->heap()->undefined_value());
13283       }
13284     }
13285   } else {
13286     // Remove shared function info from root array.
13287     Object* list = isolate->heap()->noscript_shared_function_infos();
13288     CHECK(WeakFixedArray::cast(list)->Remove(shared));
13289   }
13290 
13291   // Finally set new script.
13292   shared->set_script(*script_object);
13293 }
13294 
13295 
DebugName()13296 String* SharedFunctionInfo::DebugName() {
13297   Object* n = name();
13298   if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
13299   return String::cast(n);
13300 }
13301 
HasNoSideEffect()13302 bool SharedFunctionInfo::HasNoSideEffect() {
13303   if (!computed_has_no_side_effect()) {
13304     DisallowHeapAllocation not_handlified;
13305     Handle<SharedFunctionInfo> info(this);
13306     set_has_no_side_effect(DebugEvaluate::FunctionHasNoSideEffect(info));
13307     set_computed_has_no_side_effect(true);
13308   }
13309   return has_no_side_effect();
13310 }
13311 
13312 // The filter is a pattern that matches function names in this way:
13313 //   "*"      all; the default
13314 //   "-"      all but the top-level function
13315 //   "-name"  all but the function "name"
13316 //   ""       only the top-level function
13317 //   "name"   only the function "name"
13318 //   "name*"  only functions starting with "name"
13319 //   "~"      none; the tilde is not an identifier
PassesFilter(const char * raw_filter)13320 bool SharedFunctionInfo::PassesFilter(const char* raw_filter) {
13321   if (*raw_filter == '*') return true;
13322   String* name = DebugName();
13323   Vector<const char> filter = CStrVector(raw_filter);
13324   if (filter.length() == 0) return name->length() == 0;
13325   if (filter[0] == '-') {
13326     // Negative filter.
13327     if (filter.length() == 1) {
13328       return (name->length() != 0);
13329     } else if (name->IsUtf8EqualTo(filter.SubVector(1, filter.length()))) {
13330       return false;
13331     }
13332     if (filter[filter.length() - 1] == '*' &&
13333         name->IsUtf8EqualTo(filter.SubVector(1, filter.length() - 1), true)) {
13334       return false;
13335     }
13336     return true;
13337 
13338   } else if (name->IsUtf8EqualTo(filter)) {
13339     return true;
13340   }
13341   if (filter[filter.length() - 1] == '*' &&
13342       name->IsUtf8EqualTo(filter.SubVector(0, filter.length() - 1), true)) {
13343     return true;
13344   }
13345   return false;
13346 }
13347 
HasSourceCode() const13348 bool SharedFunctionInfo::HasSourceCode() const {
13349   Isolate* isolate = GetIsolate();
13350   return !script()->IsUndefined(isolate) &&
13351          !reinterpret_cast<Script*>(script())->source()->IsUndefined(isolate);
13352 }
13353 
13354 
GetSourceCode()13355 Handle<Object> SharedFunctionInfo::GetSourceCode() {
13356   if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value();
13357   Handle<String> source(String::cast(Script::cast(script())->source()));
13358   return GetIsolate()->factory()->NewSubString(
13359       source, start_position(), end_position());
13360 }
13361 
GetSourceCodeHarmony()13362 Handle<Object> SharedFunctionInfo::GetSourceCodeHarmony() {
13363   Isolate* isolate = GetIsolate();
13364   if (!HasSourceCode()) return isolate->factory()->undefined_value();
13365   Handle<String> script_source(String::cast(Script::cast(script())->source()));
13366   int start_pos = function_token_position();
13367   if (start_pos == kNoSourcePosition) start_pos = start_position();
13368   return isolate->factory()->NewSubString(script_source, start_pos,
13369                                           end_position());
13370 }
13371 
IsInlineable()13372 bool SharedFunctionInfo::IsInlineable() {
13373   // Check that the function has a script associated with it.
13374   if (!script()->IsScript()) return false;
13375   return !optimization_disabled();
13376 }
13377 
13378 
SourceSize()13379 int SharedFunctionInfo::SourceSize() {
13380   return end_position() - start_position();
13381 }
13382 
CalculateInstanceSizeHelper(InstanceType instance_type,int requested_internal_fields,int requested_in_object_properties,int * instance_size,int * in_object_properties)13383 void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type,
13384                                              int requested_internal_fields,
13385                                              int requested_in_object_properties,
13386                                              int* instance_size,
13387                                              int* in_object_properties) {
13388   int header_size = JSObject::GetHeaderSize(instance_type);
13389   int max_nof_fields =
13390       (JSObject::kMaxInstanceSize - header_size) >> kPointerSizeLog2;
13391   CHECK_LE(max_nof_fields, JSObject::kMaxInObjectProperties);
13392   *in_object_properties = Min(requested_in_object_properties, max_nof_fields);
13393   CHECK_LE(requested_internal_fields, max_nof_fields - *in_object_properties);
13394   *instance_size =
13395       header_size +
13396       ((requested_internal_fields + *in_object_properties) << kPointerSizeLog2);
13397   CHECK_EQ(*in_object_properties,
13398            ((*instance_size - header_size) >> kPointerSizeLog2) -
13399                requested_internal_fields);
13400 }
13401 
13402 
CalculateInstanceSize(InstanceType instance_type,int requested_internal_fields,int * instance_size,int * in_object_properties)13403 void JSFunction::CalculateInstanceSize(InstanceType instance_type,
13404                                        int requested_internal_fields,
13405                                        int* instance_size,
13406                                        int* in_object_properties) {
13407   CalculateInstanceSizeHelper(instance_type, requested_internal_fields,
13408                               shared()->expected_nof_properties(),
13409                               instance_size, in_object_properties);
13410 }
13411 
13412 
CalculateInstanceSizeForDerivedClass(InstanceType instance_type,int requested_internal_fields,int * instance_size,int * in_object_properties)13413 void JSFunction::CalculateInstanceSizeForDerivedClass(
13414     InstanceType instance_type, int requested_internal_fields,
13415     int* instance_size, int* in_object_properties) {
13416   Isolate* isolate = GetIsolate();
13417   int expected_nof_properties = 0;
13418   for (PrototypeIterator iter(isolate, this, kStartAtReceiver); !iter.IsAtEnd();
13419        iter.Advance()) {
13420     JSReceiver* current = iter.GetCurrent<JSReceiver>();
13421     if (!current->IsJSFunction()) break;
13422     JSFunction* func = JSFunction::cast(current);
13423     SharedFunctionInfo* shared = func->shared();
13424     int count = shared->expected_nof_properties();
13425     // Check that the estimate is sane.
13426     if (expected_nof_properties <= JSObject::kMaxInObjectProperties - count) {
13427       expected_nof_properties += count;
13428     } else {
13429       expected_nof_properties = JSObject::kMaxInObjectProperties;
13430     }
13431     if (!IsDerivedConstructor(shared->kind())) {
13432       break;
13433     }
13434   }
13435   CalculateInstanceSizeHelper(instance_type, requested_internal_fields,
13436                               expected_nof_properties, instance_size,
13437                               in_object_properties);
13438 }
13439 
13440 
13441 // Output the source code without any allocation in the heap.
operator <<(std::ostream & os,const SourceCodeOf & v)13442 std::ostream& operator<<(std::ostream& os, const SourceCodeOf& v) {
13443   const SharedFunctionInfo* s = v.value;
13444   // For some native functions there is no source.
13445   if (!s->HasSourceCode()) return os << "<No Source>";
13446 
13447   // Get the source for the script which this function came from.
13448   // Don't use String::cast because we don't want more assertion errors while
13449   // we are already creating a stack dump.
13450   String* script_source =
13451       reinterpret_cast<String*>(Script::cast(s->script())->source());
13452 
13453   if (!script_source->LooksValid()) return os << "<Invalid Source>";
13454 
13455   if (!s->is_toplevel()) {
13456     os << "function ";
13457     Object* name = s->name();
13458     if (name->IsString() && String::cast(name)->length() > 0) {
13459       String::cast(name)->PrintUC16(os);
13460     }
13461   }
13462 
13463   int len = s->end_position() - s->start_position();
13464   if (len <= v.max_length || v.max_length < 0) {
13465     script_source->PrintUC16(os, s->start_position(), s->end_position());
13466     return os;
13467   } else {
13468     script_source->PrintUC16(os, s->start_position(),
13469                              s->start_position() + v.max_length);
13470     return os << "...\n";
13471   }
13472 }
13473 
13474 
IsCodeEquivalent(Code * code,Code * recompiled)13475 static bool IsCodeEquivalent(Code* code, Code* recompiled) {
13476   if (code->instruction_size() != recompiled->instruction_size()) return false;
13477   ByteArray* code_relocation = code->relocation_info();
13478   ByteArray* recompiled_relocation = recompiled->relocation_info();
13479   int length = code_relocation->length();
13480   if (length != recompiled_relocation->length()) return false;
13481   int compare = memcmp(code_relocation->GetDataStartAddress(),
13482                        recompiled_relocation->GetDataStartAddress(),
13483                        length);
13484   return compare == 0;
13485 }
13486 
13487 
EnableDeoptimizationSupport(Code * recompiled)13488 void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
13489   DCHECK(!has_deoptimization_support());
13490   DisallowHeapAllocation no_allocation;
13491   Code* code = this->code();
13492   if (IsCodeEquivalent(code, recompiled)) {
13493     // Copy the deoptimization data from the recompiled code.
13494     code->set_deoptimization_data(recompiled->deoptimization_data());
13495     code->set_has_deoptimization_support(true);
13496   } else {
13497     // TODO(3025757): In case the recompiled isn't equivalent to the
13498     // old code, we have to replace it. We should try to avoid this
13499     // altogether because it flushes valuable type feedback by
13500     // effectively resetting all IC state.
13501     ReplaceCode(recompiled);
13502   }
13503   DCHECK(has_deoptimization_support());
13504 }
13505 
13506 
DisableOptimization(BailoutReason reason)13507 void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
13508   // Disable optimization for the shared function info and mark the
13509   // code as non-optimizable. The marker on the shared function info
13510   // is there because we flush non-optimized code thereby loosing the
13511   // non-optimizable information for the code. When the code is
13512   // regenerated and set on the shared function info it is marked as
13513   // non-optimizable if optimization is disabled for the shared
13514   // function info.
13515   DCHECK(reason != kNoReason);
13516   set_optimization_disabled(true);
13517   set_disable_optimization_reason(reason);
13518   // Code should be the lazy compilation stub or else unoptimized.
13519   DCHECK(abstract_code()->kind() == AbstractCode::FUNCTION ||
13520          abstract_code()->kind() == AbstractCode::INTERPRETED_FUNCTION ||
13521          abstract_code()->kind() == AbstractCode::BUILTIN);
13522   PROFILE(GetIsolate(), CodeDisableOptEvent(abstract_code(), this));
13523   if (FLAG_trace_opt) {
13524     PrintF("[disabled optimization for ");
13525     ShortPrint();
13526     PrintF(", reason: %s]\n", GetBailoutReason(reason));
13527   }
13528 }
13529 
13530 namespace {
13531 
13532 // Sets the expected number of properties based on estimate from parser.
SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared,FunctionLiteral * literal)13533 void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared,
13534                                           FunctionLiteral* literal) {
13535   int estimate = literal->expected_property_count();
13536 
13537   // If no properties are added in the constructor, they are more likely
13538   // to be added later.
13539   if (estimate == 0) estimate = 2;
13540 
13541   // TODO(yangguo): check whether those heuristics are still up-to-date.
13542   // We do not shrink objects that go into a snapshot (yet), so we adjust
13543   // the estimate conservatively.
13544   if (shared->GetIsolate()->serializer_enabled()) {
13545     estimate += 2;
13546   } else {
13547     // Inobject slack tracking will reclaim redundant inobject space later,
13548     // so we can afford to adjust the estimate generously.
13549     estimate += 8;
13550   }
13551 
13552   shared->set_expected_nof_properties(estimate);
13553 }
13554 
13555 }  // namespace
13556 
InitFromFunctionLiteral(Handle<SharedFunctionInfo> shared_info,FunctionLiteral * lit)13557 void SharedFunctionInfo::InitFromFunctionLiteral(
13558     Handle<SharedFunctionInfo> shared_info, FunctionLiteral* lit) {
13559   // When adding fields here, make sure DeclarationScope::AnalyzePartially is
13560   // updated accordingly.
13561   shared_info->set_length(lit->function_length());
13562   shared_info->set_internal_formal_parameter_count(lit->parameter_count());
13563   shared_info->set_function_token_position(lit->function_token_position());
13564   shared_info->set_start_position(lit->start_position());
13565   shared_info->set_end_position(lit->end_position());
13566   shared_info->set_is_declaration(lit->is_declaration());
13567   shared_info->set_is_named_expression(lit->is_named_expression());
13568   shared_info->set_is_anonymous_expression(lit->is_anonymous_expression());
13569   shared_info->set_inferred_name(*lit->inferred_name());
13570   shared_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
13571   shared_info->set_language_mode(lit->language_mode());
13572   shared_info->set_uses_arguments(lit->scope()->arguments() != NULL);
13573   shared_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
13574   shared_info->set_kind(lit->kind());
13575   if (!IsConstructable(lit->kind(), lit->language_mode())) {
13576     shared_info->SetConstructStub(
13577         *shared_info->GetIsolate()->builtins()->ConstructedNonConstructable());
13578   }
13579   shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
13580   shared_info->set_asm_function(lit->scope()->asm_function());
13581   shared_info->set_function_literal_id(lit->function_literal_id());
13582   SetExpectedNofPropertiesFromEstimate(shared_info, lit);
13583 }
13584 
13585 
VerifyBailoutId(BailoutId id)13586 bool SharedFunctionInfo::VerifyBailoutId(BailoutId id) {
13587   DCHECK(!id.IsNone());
13588   Code* unoptimized = code();
13589   DeoptimizationOutputData* data =
13590       DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
13591   unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
13592   USE(ignore);
13593   return true;  // Return true if there was no DCHECK.
13594 }
13595 
SetConstructStub(Code * code)13596 void SharedFunctionInfo::SetConstructStub(Code* code) {
13597   if (code->kind() == Code::BUILTIN) code->set_is_construct_stub(true);
13598   set_construct_stub(code);
13599 }
13600 
StartInobjectSlackTracking()13601 void Map::StartInobjectSlackTracking() {
13602   DCHECK(!IsInobjectSlackTrackingInProgress());
13603 
13604   // No tracking during the snapshot construction phase.
13605   Isolate* isolate = GetIsolate();
13606   if (isolate->serializer_enabled()) return;
13607 
13608   if (unused_property_fields() == 0) return;
13609 
13610   set_construction_counter(Map::kSlackTrackingCounterStart);
13611 }
13612 
13613 
ResetForNewContext(int new_ic_age)13614 void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
13615   code()->ClearInlineCaches();
13616   set_ic_age(new_ic_age);
13617   if (code()->kind() == Code::FUNCTION) {
13618     code()->set_profiler_ticks(0);
13619     if (optimization_disabled() && opt_count() >= FLAG_max_opt_count) {
13620       // Re-enable optimizations if they were disabled due to opt_count limit.
13621       set_optimization_disabled(false);
13622     }
13623     set_opt_count(0);
13624     set_deopt_count(0);
13625   } else if (IsInterpreted()) {
13626     set_profiler_ticks(0);
13627     if (optimization_disabled() && opt_count() >= FLAG_max_opt_count) {
13628       // Re-enable optimizations if they were disabled due to opt_count limit.
13629       set_optimization_disabled(false);
13630     }
13631     set_opt_count(0);
13632     set_deopt_count(0);
13633   }
13634 }
13635 
SearchOptimizedCodeMapEntry(Context * native_context)13636 int SharedFunctionInfo::SearchOptimizedCodeMapEntry(Context* native_context) {
13637   DisallowHeapAllocation no_gc;
13638   DCHECK(native_context->IsNativeContext());
13639   if (!OptimizedCodeMapIsCleared()) {
13640     FixedArray* optimized_code_map = this->optimized_code_map();
13641     int length = optimized_code_map->length();
13642     for (int i = kEntriesStart; i < length; i += kEntryLength) {
13643       if (WeakCell::cast(optimized_code_map->get(i + kContextOffset))
13644               ->value() == native_context) {
13645         return i;
13646       }
13647     }
13648   }
13649   return -1;
13650 }
13651 
ClearCodeFromOptimizedCodeMap()13652 void SharedFunctionInfo::ClearCodeFromOptimizedCodeMap() {
13653   if (!OptimizedCodeMapIsCleared()) {
13654     FixedArray* optimized_code_map = this->optimized_code_map();
13655     int length = optimized_code_map->length();
13656     WeakCell* empty_weak_cell = GetHeap()->empty_weak_cell();
13657     for (int i = kEntriesStart; i < length; i += kEntryLength) {
13658       optimized_code_map->set(i + kCachedCodeOffset, empty_weak_cell,
13659                               SKIP_WRITE_BARRIER);
13660     }
13661   }
13662 }
13663 
SearchOptimizedCodeMap(Context * native_context,BailoutId osr_ast_id)13664 Code* SharedFunctionInfo::SearchOptimizedCodeMap(Context* native_context,
13665                                                  BailoutId osr_ast_id) {
13666   Code* result = nullptr;
13667   if (!osr_ast_id.IsNone()) {
13668     return native_context->SearchOptimizedCodeMap(this, osr_ast_id);
13669   }
13670 
13671   DCHECK(osr_ast_id.IsNone());
13672   int entry = SearchOptimizedCodeMapEntry(native_context);
13673   if (entry != kNotFound) {
13674     FixedArray* code_map = optimized_code_map();
13675     DCHECK_LE(entry + kEntryLength, code_map->length());
13676     WeakCell* cell = WeakCell::cast(code_map->get(entry + kCachedCodeOffset));
13677     result = cell->cleared() ? nullptr : Code::cast(cell->value());
13678   }
13679   return result;
13680 }
13681 
13682 
13683 #define DECLARE_TAG(ignore1, name, ignore2) name,
13684 const char* const VisitorSynchronization::kTags[
13685     VisitorSynchronization::kNumberOfSyncTags] = {
13686   VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
13687 };
13688 #undef DECLARE_TAG
13689 
13690 
13691 #define DECLARE_TAG(ignore1, ignore2, name) name,
13692 const char* const VisitorSynchronization::kTagNames[
13693     VisitorSynchronization::kNumberOfSyncTags] = {
13694   VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
13695 };
13696 #undef DECLARE_TAG
13697 
13698 
VisitCodeTarget(RelocInfo * rinfo)13699 void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
13700   DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode()));
13701   Object* old_pointer = Code::GetCodeFromTargetAddress(rinfo->target_address());
13702   Object* new_pointer = old_pointer;
13703   VisitPointer(&new_pointer);
13704   DCHECK_EQ(old_pointer, new_pointer);
13705 }
13706 
13707 
VisitCodeAgeSequence(RelocInfo * rinfo)13708 void ObjectVisitor::VisitCodeAgeSequence(RelocInfo* rinfo) {
13709   DCHECK(RelocInfo::IsCodeAgeSequence(rinfo->rmode()));
13710   Object* old_pointer = rinfo->code_age_stub();
13711   Object* new_pointer = old_pointer;
13712   if (old_pointer != nullptr) {
13713     VisitPointer(&new_pointer);
13714     DCHECK_EQ(old_pointer, new_pointer);
13715   }
13716 }
13717 
13718 
VisitCodeEntry(Address entry_address)13719 void ObjectVisitor::VisitCodeEntry(Address entry_address) {
13720   Object* old_pointer = Code::GetObjectFromEntryAddress(entry_address);
13721   Object* new_pointer = old_pointer;
13722   VisitPointer(&new_pointer);
13723   DCHECK_EQ(old_pointer, new_pointer);
13724 }
13725 
13726 
VisitCell(RelocInfo * rinfo)13727 void ObjectVisitor::VisitCell(RelocInfo* rinfo) {
13728   DCHECK(rinfo->rmode() == RelocInfo::CELL);
13729   Object* old_pointer = rinfo->target_cell();
13730   Object* new_pointer = old_pointer;
13731   VisitPointer(&new_pointer);
13732   DCHECK_EQ(old_pointer, new_pointer);
13733 }
13734 
13735 
VisitDebugTarget(RelocInfo * rinfo)13736 void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
13737   DCHECK(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
13738          rinfo->IsPatchedDebugBreakSlotSequence());
13739   Object* old_pointer =
13740       Code::GetCodeFromTargetAddress(rinfo->debug_call_address());
13741   Object* new_pointer = old_pointer;
13742   VisitPointer(&new_pointer);
13743   DCHECK_EQ(old_pointer, new_pointer);
13744 }
13745 
13746 
VisitEmbeddedPointer(RelocInfo * rinfo)13747 void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
13748   DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
13749   Object* old_pointer = rinfo->target_object();
13750   Object* new_pointer = old_pointer;
13751   VisitPointer(&new_pointer);
13752   DCHECK_EQ(old_pointer, new_pointer);
13753 }
13754 
13755 
VisitExternalReference(RelocInfo * rinfo)13756 void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
13757   Address old_reference = rinfo->target_external_reference();
13758   Address new_reference = old_reference;
13759   VisitExternalReference(&new_reference);
13760   DCHECK_EQ(old_reference, new_reference);
13761 }
13762 
13763 
InvalidateRelocation()13764 void Code::InvalidateRelocation() {
13765   InvalidateEmbeddedObjects();
13766   set_relocation_info(GetHeap()->empty_byte_array());
13767 }
13768 
13769 
InvalidateEmbeddedObjects()13770 void Code::InvalidateEmbeddedObjects() {
13771   Object* undefined = GetHeap()->undefined_value();
13772   Cell* undefined_cell = GetHeap()->undefined_cell();
13773   int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
13774                   RelocInfo::ModeMask(RelocInfo::CELL);
13775   for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
13776     RelocInfo::Mode mode = it.rinfo()->rmode();
13777     if (mode == RelocInfo::EMBEDDED_OBJECT) {
13778       it.rinfo()->set_target_object(undefined, SKIP_WRITE_BARRIER);
13779     } else if (mode == RelocInfo::CELL) {
13780       it.rinfo()->set_target_cell(undefined_cell, SKIP_WRITE_BARRIER);
13781     }
13782   }
13783 }
13784 
13785 
Relocate(intptr_t delta)13786 void Code::Relocate(intptr_t delta) {
13787   for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
13788     it.rinfo()->apply(delta);
13789   }
13790   Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size());
13791 }
13792 
13793 
CopyFrom(const CodeDesc & desc)13794 void Code::CopyFrom(const CodeDesc& desc) {
13795   // copy code
13796   CopyBytes(instruction_start(), desc.buffer,
13797             static_cast<size_t>(desc.instr_size));
13798 
13799   // copy unwinding info, if any
13800   if (desc.unwinding_info) {
13801     DCHECK_GT(desc.unwinding_info_size, 0);
13802     set_unwinding_info_size(desc.unwinding_info_size);
13803     CopyBytes(unwinding_info_start(), desc.unwinding_info,
13804               static_cast<size_t>(desc.unwinding_info_size));
13805   }
13806 
13807   // copy reloc info
13808   CopyBytes(relocation_start(),
13809             desc.buffer + desc.buffer_size - desc.reloc_size,
13810             static_cast<size_t>(desc.reloc_size));
13811 
13812   // unbox handles and relocate
13813   intptr_t delta = instruction_start() - desc.buffer;
13814   int mode_mask = RelocInfo::kCodeTargetMask |
13815                   RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
13816                   RelocInfo::ModeMask(RelocInfo::CELL) |
13817                   RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
13818                   RelocInfo::kApplyMask;
13819   // Needed to find target_object and runtime_entry on X64
13820   Assembler* origin = desc.origin;
13821   AllowDeferredHandleDereference embedding_raw_address;
13822   for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
13823     RelocInfo::Mode mode = it.rinfo()->rmode();
13824     if (mode == RelocInfo::EMBEDDED_OBJECT) {
13825       Handle<Object> p = it.rinfo()->target_object_handle(origin);
13826       it.rinfo()->set_target_object(*p, UPDATE_WRITE_BARRIER,
13827                                     SKIP_ICACHE_FLUSH);
13828     } else if (mode == RelocInfo::CELL) {
13829       Handle<Cell> cell  = it.rinfo()->target_cell_handle();
13830       it.rinfo()->set_target_cell(*cell, UPDATE_WRITE_BARRIER,
13831                                   SKIP_ICACHE_FLUSH);
13832     } else if (RelocInfo::IsCodeTarget(mode)) {
13833       // rewrite code handles in inline cache targets to direct
13834       // pointers to the first instruction in the code object
13835       Handle<Object> p = it.rinfo()->target_object_handle(origin);
13836       Code* code = Code::cast(*p);
13837       it.rinfo()->set_target_address(code->instruction_start(),
13838                                      UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
13839     } else if (RelocInfo::IsRuntimeEntry(mode)) {
13840       Address p = it.rinfo()->target_runtime_entry(origin);
13841       it.rinfo()->set_target_runtime_entry(p, UPDATE_WRITE_BARRIER,
13842                                            SKIP_ICACHE_FLUSH);
13843     } else if (mode == RelocInfo::CODE_AGE_SEQUENCE) {
13844       Handle<Object> p = it.rinfo()->code_age_stub_handle(origin);
13845       Code* code = Code::cast(*p);
13846       it.rinfo()->set_code_age_stub(code, SKIP_ICACHE_FLUSH);
13847     } else {
13848       it.rinfo()->apply(delta);
13849     }
13850   }
13851   Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size());
13852 }
13853 
13854 
GetSafepointEntry(Address pc)13855 SafepointEntry Code::GetSafepointEntry(Address pc) {
13856   SafepointTable table(this);
13857   return table.FindEntry(pc);
13858 }
13859 
13860 
FindNthObject(int n,Map * match_map)13861 Object* Code::FindNthObject(int n, Map* match_map) {
13862   DCHECK(is_inline_cache_stub());
13863   DisallowHeapAllocation no_allocation;
13864   int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
13865   for (RelocIterator it(this, mask); !it.done(); it.next()) {
13866     RelocInfo* info = it.rinfo();
13867     Object* object = info->target_object();
13868     if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
13869     if (object->IsHeapObject()) {
13870       if (HeapObject::cast(object)->map() == match_map) {
13871         if (--n == 0) return object;
13872       }
13873     }
13874   }
13875   return NULL;
13876 }
13877 
13878 
FindFirstAllocationSite()13879 AllocationSite* Code::FindFirstAllocationSite() {
13880   Object* result = FindNthObject(1, GetHeap()->allocation_site_map());
13881   return (result != NULL) ? AllocationSite::cast(result) : NULL;
13882 }
13883 
13884 
FindFirstMap()13885 Map* Code::FindFirstMap() {
13886   Object* result = FindNthObject(1, GetHeap()->meta_map());
13887   return (result != NULL) ? Map::cast(result) : NULL;
13888 }
13889 
13890 
FindAndReplace(const FindAndReplacePattern & pattern)13891 void Code::FindAndReplace(const FindAndReplacePattern& pattern) {
13892   DCHECK(is_inline_cache_stub() || is_handler());
13893   DisallowHeapAllocation no_allocation;
13894   int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
13895   STATIC_ASSERT(FindAndReplacePattern::kMaxCount < 32);
13896   int current_pattern = 0;
13897   for (RelocIterator it(this, mask); !it.done(); it.next()) {
13898     RelocInfo* info = it.rinfo();
13899     Object* object = info->target_object();
13900     if (object->IsHeapObject()) {
13901       if (object->IsWeakCell()) {
13902         object = HeapObject::cast(WeakCell::cast(object)->value());
13903       }
13904       Map* map = HeapObject::cast(object)->map();
13905       if (map == *pattern.find_[current_pattern]) {
13906         info->set_target_object(*pattern.replace_[current_pattern]);
13907         if (++current_pattern == pattern.count_) return;
13908       }
13909     }
13910   }
13911   UNREACHABLE();
13912 }
13913 
13914 
ClearInlineCaches()13915 void Code::ClearInlineCaches() {
13916   int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
13917              RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
13918   for (RelocIterator it(this, mask); !it.done(); it.next()) {
13919     RelocInfo* info = it.rinfo();
13920     Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
13921     if (target->is_inline_cache_stub()) {
13922       ICUtility::Clear(this->GetIsolate(), info->pc(),
13923                        info->host()->constant_pool());
13924     }
13925   }
13926 }
13927 
SourcePosition(int offset)13928 int AbstractCode::SourcePosition(int offset) {
13929   int position = 0;
13930   // Subtract one because the current PC is one instruction after the call site.
13931   if (IsCode()) offset--;
13932   for (SourcePositionTableIterator iterator(source_position_table());
13933        !iterator.done() && iterator.code_offset() <= offset;
13934        iterator.Advance()) {
13935     position = iterator.source_position().ScriptOffset();
13936   }
13937   return position;
13938 }
13939 
SourceStatementPosition(int offset)13940 int AbstractCode::SourceStatementPosition(int offset) {
13941   // First find the closest position.
13942   int position = SourcePosition(offset);
13943   // Now find the closest statement position before the position.
13944   int statement_position = 0;
13945   for (SourcePositionTableIterator it(source_position_table()); !it.done();
13946        it.Advance()) {
13947     if (it.is_statement()) {
13948       int p = it.source_position().ScriptOffset();
13949       if (statement_position < p && p <= position) {
13950         statement_position = p;
13951       }
13952     }
13953   }
13954   return statement_position;
13955 }
13956 
ClearTypeFeedbackInfo()13957 void JSFunction::ClearTypeFeedbackInfo() {
13958   if (feedback_vector_cell()->value()->IsFeedbackVector()) {
13959     FeedbackVector* vector = feedback_vector();
13960     vector->ClearSlots(this);
13961   }
13962 }
13963 
TranslatePcOffsetToAstId(uint32_t pc_offset)13964 BailoutId Code::TranslatePcOffsetToAstId(uint32_t pc_offset) {
13965   DisallowHeapAllocation no_gc;
13966   DCHECK(kind() == FUNCTION);
13967   BackEdgeTable back_edges(this, &no_gc);
13968   for (uint32_t i = 0; i < back_edges.length(); i++) {
13969     if (back_edges.pc_offset(i) == pc_offset) return back_edges.ast_id(i);
13970   }
13971   return BailoutId::None();
13972 }
13973 
13974 
TranslateAstIdToPcOffset(BailoutId ast_id)13975 uint32_t Code::TranslateAstIdToPcOffset(BailoutId ast_id) {
13976   DisallowHeapAllocation no_gc;
13977   DCHECK(kind() == FUNCTION);
13978   BackEdgeTable back_edges(this, &no_gc);
13979   for (uint32_t i = 0; i < back_edges.length(); i++) {
13980     if (back_edges.ast_id(i) == ast_id) return back_edges.pc_offset(i);
13981   }
13982   UNREACHABLE();  // We expect to find the back edge.
13983   return 0;
13984 }
13985 
MakeCodeAgeSequenceYoung(byte * sequence,Isolate * isolate)13986 void Code::MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate) {
13987   PatchPlatformCodeAge(isolate, sequence, kNoAgeCodeAge);
13988 }
13989 
13990 
MarkCodeAsExecuted(byte * sequence,Isolate * isolate)13991 void Code::MarkCodeAsExecuted(byte* sequence, Isolate* isolate) {
13992   PatchPlatformCodeAge(isolate, sequence, kExecutedOnceCodeAge);
13993 }
13994 
13995 
13996 // NextAge defines the Code::Age state transitions during a GC cycle.
NextAge(Code::Age age)13997 static Code::Age NextAge(Code::Age age) {
13998   switch (age) {
13999     case Code::kNotExecutedCodeAge:  // Keep, until we've been executed.
14000     case Code::kToBeExecutedOnceCodeAge:  // Keep, until we've been executed.
14001     case Code::kLastCodeAge:  // Clamp at last Code::Age value.
14002       return age;
14003     case Code::kExecutedOnceCodeAge:
14004       // Pre-age code that has only been executed once.
14005       return static_cast<Code::Age>(Code::kPreAgedCodeAge + 1);
14006     default:
14007       return static_cast<Code::Age>(age + 1);  // Default case: Increase age.
14008   }
14009 }
14010 
14011 
14012 // IsOldAge defines the collection criteria for a Code object.
IsOldAge(Code::Age age)14013 static bool IsOldAge(Code::Age age) {
14014   return age >= Code::kIsOldCodeAge || age == Code::kNotExecutedCodeAge;
14015 }
14016 
14017 
MakeYoung(Isolate * isolate)14018 void Code::MakeYoung(Isolate* isolate) {
14019   byte* sequence = FindCodeAgeSequence();
14020   if (sequence != NULL) MakeCodeAgeSequenceYoung(sequence, isolate);
14021 }
14022 
PreAge(Isolate * isolate)14023 void Code::PreAge(Isolate* isolate) {
14024   byte* sequence = FindCodeAgeSequence();
14025   if (sequence != NULL) {
14026     PatchPlatformCodeAge(isolate, sequence, kPreAgedCodeAge);
14027   }
14028 }
14029 
MarkToBeExecutedOnce(Isolate * isolate)14030 void Code::MarkToBeExecutedOnce(Isolate* isolate) {
14031   byte* sequence = FindCodeAgeSequence();
14032   if (sequence != NULL) {
14033     PatchPlatformCodeAge(isolate, sequence, kToBeExecutedOnceCodeAge);
14034   }
14035 }
14036 
MakeOlder()14037 void Code::MakeOlder() {
14038   byte* sequence = FindCodeAgeSequence();
14039   if (sequence != NULL) {
14040     Isolate* isolate = GetIsolate();
14041     Age age = GetCodeAge(isolate, sequence);
14042     Age next_age = NextAge(age);
14043     if (age != next_age) {
14044       PatchPlatformCodeAge(isolate, sequence, next_age);
14045     }
14046   }
14047 }
14048 
14049 
IsOld()14050 bool Code::IsOld() {
14051   return IsOldAge(GetAge());
14052 }
14053 
14054 
FindCodeAgeSequence()14055 byte* Code::FindCodeAgeSequence() {
14056   return FLAG_age_code &&
14057       prologue_offset() != Code::kPrologueOffsetNotSet &&
14058       (kind() == OPTIMIZED_FUNCTION ||
14059        (kind() == FUNCTION && !has_debug_break_slots()))
14060       ? instruction_start() + prologue_offset()
14061       : NULL;
14062 }
14063 
14064 
GetAge()14065 Code::Age Code::GetAge() {
14066   byte* sequence = FindCodeAgeSequence();
14067   if (sequence == NULL) {
14068     return kNoAgeCodeAge;
14069   }
14070   return GetCodeAge(GetIsolate(), sequence);
14071 }
14072 
GetAgeOfCodeAgeStub(Code * code)14073 Code::Age Code::GetAgeOfCodeAgeStub(Code* code) {
14074   Isolate* isolate = code->GetIsolate();
14075   Builtins* builtins = isolate->builtins();
14076 #define HANDLE_CODE_AGE(AGE)                            \
14077   if (code == *builtins->Make##AGE##CodeYoungAgain()) { \
14078     return k##AGE##CodeAge;                             \
14079   }
14080   CODE_AGE_LIST(HANDLE_CODE_AGE)
14081 #undef HANDLE_CODE_AGE
14082   if (code == *builtins->MarkCodeAsExecutedOnce()) {
14083     return kNotExecutedCodeAge;
14084   }
14085   if (code == *builtins->MarkCodeAsExecutedTwice()) {
14086     return kExecutedOnceCodeAge;
14087   }
14088   if (code == *builtins->MarkCodeAsToBeExecutedOnce()) {
14089     return kToBeExecutedOnceCodeAge;
14090   }
14091   UNREACHABLE();
14092   return kNoAgeCodeAge;
14093 }
14094 
GetCodeAgeStub(Isolate * isolate,Age age)14095 Code* Code::GetCodeAgeStub(Isolate* isolate, Age age) {
14096   Builtins* builtins = isolate->builtins();
14097   switch (age) {
14098 #define HANDLE_CODE_AGE(AGE)                       \
14099   case k##AGE##CodeAge: {                          \
14100     return *builtins->Make##AGE##CodeYoungAgain(); \
14101   }
14102     CODE_AGE_LIST(HANDLE_CODE_AGE)
14103 #undef HANDLE_CODE_AGE
14104     case kNotExecutedCodeAge: {
14105       return *builtins->MarkCodeAsExecutedOnce();
14106     }
14107     case kExecutedOnceCodeAge: {
14108       return *builtins->MarkCodeAsExecutedTwice();
14109     }
14110     case kToBeExecutedOnceCodeAge: {
14111       return *builtins->MarkCodeAsToBeExecutedOnce();
14112     }
14113     default:
14114       UNREACHABLE();
14115       break;
14116   }
14117   return NULL;
14118 }
14119 
14120 
PrintDeoptLocation(FILE * out,Address pc)14121 void Code::PrintDeoptLocation(FILE* out, Address pc) {
14122   Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(this, pc);
14123   class SourcePosition pos = info.position;
14124   if (info.deopt_reason != DeoptimizeReason::kNoReason || pos.IsKnown()) {
14125     if (FLAG_hydrogen_track_positions) {
14126       PrintF(out, "            ;;; deoptimize at %d_%d: %s\n", pos.InliningId(),
14127              pos.ScriptOffset(), DeoptimizeReasonToString(info.deopt_reason));
14128     } else {
14129       PrintF(out, "            ;;; deoptimize at ");
14130       OFStream outstr(out);
14131       pos.Print(outstr, this);
14132       PrintF(out, ", %s\n", DeoptimizeReasonToString(info.deopt_reason));
14133     }
14134   }
14135 }
14136 
14137 
CanDeoptAt(Address pc)14138 bool Code::CanDeoptAt(Address pc) {
14139   DeoptimizationInputData* deopt_data =
14140       DeoptimizationInputData::cast(deoptimization_data());
14141   Address code_start_address = instruction_start();
14142   for (int i = 0; i < deopt_data->DeoptCount(); i++) {
14143     if (deopt_data->Pc(i)->value() == -1) continue;
14144     Address address = code_start_address + deopt_data->Pc(i)->value();
14145     if (address == pc && deopt_data->AstId(i) != BailoutId::None()) {
14146       return true;
14147     }
14148   }
14149   return false;
14150 }
14151 
14152 
14153 // Identify kind of code.
Kind2String(Kind kind)14154 const char* Code::Kind2String(Kind kind) {
14155   switch (kind) {
14156 #define CASE(name) case name: return #name;
14157     CODE_KIND_LIST(CASE)
14158 #undef CASE
14159     case NUMBER_OF_KINDS: break;
14160   }
14161   UNREACHABLE();
14162   return NULL;
14163 }
14164 
14165 // Identify kind of code.
Kind2String(Kind kind)14166 const char* AbstractCode::Kind2String(Kind kind) {
14167   if (kind < AbstractCode::INTERPRETED_FUNCTION)
14168     return Code::Kind2String((Code::Kind)kind);
14169   if (kind == AbstractCode::INTERPRETED_FUNCTION) return "INTERPRETED_FUNCTION";
14170   UNREACHABLE();
14171   return NULL;
14172 }
14173 
WeakCellFor(Handle<Code> code)14174 Handle<WeakCell> Code::WeakCellFor(Handle<Code> code) {
14175   DCHECK(code->kind() == OPTIMIZED_FUNCTION);
14176   WeakCell* raw_cell = code->CachedWeakCell();
14177   if (raw_cell != NULL) return Handle<WeakCell>(raw_cell);
14178   Handle<WeakCell> cell = code->GetIsolate()->factory()->NewWeakCell(code);
14179   DeoptimizationInputData::cast(code->deoptimization_data())
14180       ->SetWeakCellCache(*cell);
14181   return cell;
14182 }
14183 
14184 
CachedWeakCell()14185 WeakCell* Code::CachedWeakCell() {
14186   DCHECK(kind() == OPTIMIZED_FUNCTION);
14187   Object* weak_cell_cache =
14188       DeoptimizationInputData::cast(deoptimization_data())->WeakCellCache();
14189   if (weak_cell_cache->IsWeakCell()) {
14190     DCHECK(this == WeakCell::cast(weak_cell_cache)->value());
14191     return WeakCell::cast(weak_cell_cache);
14192   }
14193   return NULL;
14194 }
14195 
14196 #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
14197 
ICState2String(InlineCacheState state)14198 const char* Code::ICState2String(InlineCacheState state) {
14199   switch (state) {
14200     case UNINITIALIZED:
14201       return "UNINITIALIZED";
14202     case PREMONOMORPHIC:
14203       return "PREMONOMORPHIC";
14204     case MONOMORPHIC:
14205       return "MONOMORPHIC";
14206     case RECOMPUTE_HANDLER:
14207       return "RECOMPUTE_HANDLER";
14208     case POLYMORPHIC:
14209       return "POLYMORPHIC";
14210     case MEGAMORPHIC:
14211       return "MEGAMORPHIC";
14212     case GENERIC:
14213       return "GENERIC";
14214   }
14215   UNREACHABLE();
14216   return NULL;
14217 }
14218 
PrintExtraICState(std::ostream & os,Kind kind,ExtraICState extra)14219 void Code::PrintExtraICState(std::ostream& os,  // NOLINT
14220                              Kind kind, ExtraICState extra) {
14221   os << "extra_ic_state = ";
14222   if ((kind == STORE_IC || kind == KEYED_STORE_IC) &&
14223       is_strict(static_cast<LanguageMode>(extra))) {
14224     os << "STRICT\n";
14225   } else {
14226     os << extra << "\n";
14227   }
14228 }
14229 
14230 #endif  // defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
14231 
14232 #ifdef ENABLE_DISASSEMBLER
14233 
DeoptimizationInputDataPrint(std::ostream & os)14234 void DeoptimizationInputData::DeoptimizationInputDataPrint(
14235     std::ostream& os) {  // NOLINT
14236   disasm::NameConverter converter;
14237   int const inlined_function_count = InlinedFunctionCount()->value();
14238   os << "Inlined functions (count = " << inlined_function_count << ")\n";
14239   for (int id = 0; id < inlined_function_count; ++id) {
14240     Object* info = LiteralArray()->get(id);
14241     os << " " << Brief(SharedFunctionInfo::cast(info)) << "\n";
14242   }
14243   os << "\n";
14244   int deopt_count = DeoptCount();
14245   os << "Deoptimization Input Data (deopt points = " << deopt_count << ")\n";
14246   if (0 != deopt_count) {
14247     os << " index  ast id    argc     pc";
14248     if (FLAG_print_code_verbose) os << "  commands";
14249     os << "\n";
14250   }
14251   for (int i = 0; i < deopt_count; i++) {
14252     os << std::setw(6) << i << "  " << std::setw(6) << AstId(i).ToInt() << "  "
14253        << std::setw(6) << ArgumentsStackHeight(i)->value() << " "
14254        << std::setw(6) << Pc(i)->value();
14255 
14256     if (!FLAG_print_code_verbose) {
14257       os << "\n";
14258       continue;
14259     }
14260     // Print details of the frame translation.
14261     int translation_index = TranslationIndex(i)->value();
14262     TranslationIterator iterator(TranslationByteArray(), translation_index);
14263     Translation::Opcode opcode =
14264         static_cast<Translation::Opcode>(iterator.Next());
14265     DCHECK(Translation::BEGIN == opcode);
14266     int frame_count = iterator.Next();
14267     int jsframe_count = iterator.Next();
14268     os << "  " << Translation::StringFor(opcode)
14269        << " {frame count=" << frame_count
14270        << ", js frame count=" << jsframe_count << "}\n";
14271 
14272     while (iterator.HasNext() &&
14273            Translation::BEGIN !=
14274            (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
14275       os << std::setw(31) << "    " << Translation::StringFor(opcode) << " ";
14276 
14277       switch (opcode) {
14278         case Translation::BEGIN:
14279           UNREACHABLE();
14280           break;
14281 
14282         case Translation::JS_FRAME: {
14283           int ast_id = iterator.Next();
14284           int shared_info_id = iterator.Next();
14285           unsigned height = iterator.Next();
14286           Object* shared_info = LiteralArray()->get(shared_info_id);
14287           os << "{ast_id=" << ast_id << ", function="
14288              << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14289              << ", height=" << height << "}";
14290           break;
14291         }
14292 
14293         case Translation::INTERPRETED_FRAME: {
14294           int bytecode_offset = iterator.Next();
14295           int shared_info_id = iterator.Next();
14296           unsigned height = iterator.Next();
14297           Object* shared_info = LiteralArray()->get(shared_info_id);
14298           os << "{bytecode_offset=" << bytecode_offset << ", function="
14299              << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14300              << ", height=" << height << "}";
14301           break;
14302         }
14303 
14304         case Translation::CONSTRUCT_STUB_FRAME: {
14305           int bailout_id = iterator.Next();
14306           int shared_info_id = iterator.Next();
14307           Object* shared_info = LiteralArray()->get(shared_info_id);
14308           unsigned height = iterator.Next();
14309           os << "{bailout_id=" << bailout_id << ", function="
14310              << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14311              << ", height=" << height << "}";
14312           break;
14313         }
14314 
14315         case Translation::COMPILED_STUB_FRAME: {
14316           Code::Kind stub_kind = static_cast<Code::Kind>(iterator.Next());
14317           os << "{kind=" << stub_kind << "}";
14318           break;
14319         }
14320 
14321         case Translation::ARGUMENTS_ADAPTOR_FRAME: {
14322           int shared_info_id = iterator.Next();
14323           Object* shared_info = LiteralArray()->get(shared_info_id);
14324           unsigned height = iterator.Next();
14325           os << "{function="
14326              << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14327              << ", height=" << height << "}";
14328           break;
14329         }
14330 
14331         case Translation::TAIL_CALLER_FRAME: {
14332           int shared_info_id = iterator.Next();
14333           Object* shared_info = LiteralArray()->get(shared_info_id);
14334           os << "{function="
14335              << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14336              << "}";
14337           break;
14338         }
14339 
14340         case Translation::GETTER_STUB_FRAME:
14341         case Translation::SETTER_STUB_FRAME: {
14342           int shared_info_id = iterator.Next();
14343           Object* shared_info = LiteralArray()->get(shared_info_id);
14344           os << "{function=" << Brief(SharedFunctionInfo::cast(shared_info)
14345                                           ->DebugName()) << "}";
14346           break;
14347         }
14348 
14349         case Translation::REGISTER: {
14350           int reg_code = iterator.Next();
14351           os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
14352           break;
14353         }
14354 
14355         case Translation::INT32_REGISTER: {
14356           int reg_code = iterator.Next();
14357           os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
14358           break;
14359         }
14360 
14361         case Translation::UINT32_REGISTER: {
14362           int reg_code = iterator.Next();
14363           os << "{input=" << converter.NameOfCPURegister(reg_code)
14364              << " (unsigned)}";
14365           break;
14366         }
14367 
14368         case Translation::BOOL_REGISTER: {
14369           int reg_code = iterator.Next();
14370           os << "{input=" << converter.NameOfCPURegister(reg_code)
14371              << " (bool)}";
14372           break;
14373         }
14374 
14375         case Translation::FLOAT_REGISTER: {
14376           int reg_code = iterator.Next();
14377           os << "{input="
14378              << RegisterConfiguration::Crankshaft()->GetFloatRegisterName(
14379                     reg_code)
14380              << "}";
14381           break;
14382         }
14383 
14384         case Translation::DOUBLE_REGISTER: {
14385           int reg_code = iterator.Next();
14386           os << "{input="
14387              << RegisterConfiguration::Crankshaft()->GetDoubleRegisterName(
14388                     reg_code)
14389              << "}";
14390           break;
14391         }
14392 
14393         case Translation::STACK_SLOT: {
14394           int input_slot_index = iterator.Next();
14395           os << "{input=" << input_slot_index << "}";
14396           break;
14397         }
14398 
14399         case Translation::INT32_STACK_SLOT: {
14400           int input_slot_index = iterator.Next();
14401           os << "{input=" << input_slot_index << "}";
14402           break;
14403         }
14404 
14405         case Translation::UINT32_STACK_SLOT: {
14406           int input_slot_index = iterator.Next();
14407           os << "{input=" << input_slot_index << " (unsigned)}";
14408           break;
14409         }
14410 
14411         case Translation::BOOL_STACK_SLOT: {
14412           int input_slot_index = iterator.Next();
14413           os << "{input=" << input_slot_index << " (bool)}";
14414           break;
14415         }
14416 
14417         case Translation::FLOAT_STACK_SLOT:
14418         case Translation::DOUBLE_STACK_SLOT: {
14419           int input_slot_index = iterator.Next();
14420           os << "{input=" << input_slot_index << "}";
14421           break;
14422         }
14423 
14424         case Translation::LITERAL: {
14425           int literal_index = iterator.Next();
14426           Object* literal_value = LiteralArray()->get(literal_index);
14427           os << "{literal_id=" << literal_index << " (" << Brief(literal_value)
14428              << ")}";
14429           break;
14430         }
14431 
14432         case Translation::DUPLICATED_OBJECT: {
14433           int object_index = iterator.Next();
14434           os << "{object_index=" << object_index << "}";
14435           break;
14436         }
14437 
14438         case Translation::ARGUMENTS_OBJECT:
14439         case Translation::CAPTURED_OBJECT: {
14440           int args_length = iterator.Next();
14441           os << "{length=" << args_length << "}";
14442           break;
14443         }
14444       }
14445       os << "\n";
14446     }
14447   }
14448 }
14449 
14450 
DeoptimizationOutputDataPrint(std::ostream & os)14451 void DeoptimizationOutputData::DeoptimizationOutputDataPrint(
14452     std::ostream& os) {  // NOLINT
14453   os << "Deoptimization Output Data (deopt points = " << this->DeoptPoints()
14454      << ")\n";
14455   if (this->DeoptPoints() == 0) return;
14456 
14457   os << "ast id        pc  state\n";
14458   for (int i = 0; i < this->DeoptPoints(); i++) {
14459     int pc_and_state = this->PcAndState(i)->value();
14460     os << std::setw(6) << this->AstId(i).ToInt() << "  " << std::setw(8)
14461        << FullCodeGenerator::PcField::decode(pc_and_state) << "  "
14462        << Deoptimizer::BailoutStateToString(
14463               FullCodeGenerator::BailoutStateField::decode(pc_and_state))
14464        << "\n";
14465   }
14466 }
14467 
14468 
HandlerTableRangePrint(std::ostream & os)14469 void HandlerTable::HandlerTableRangePrint(std::ostream& os) {
14470   os << "   from   to       hdlr\n";
14471   for (int i = 0; i < length(); i += kRangeEntrySize) {
14472     int pc_start = Smi::cast(get(i + kRangeStartIndex))->value();
14473     int pc_end = Smi::cast(get(i + kRangeEndIndex))->value();
14474     int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value();
14475     int handler_offset = HandlerOffsetField::decode(handler_field);
14476     CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
14477     int data = Smi::cast(get(i + kRangeDataIndex))->value();
14478     os << "  (" << std::setw(4) << pc_start << "," << std::setw(4) << pc_end
14479        << ")  ->  " << std::setw(4) << handler_offset
14480        << " (prediction=" << prediction << ", data=" << data << ")\n";
14481   }
14482 }
14483 
14484 
HandlerTableReturnPrint(std::ostream & os)14485 void HandlerTable::HandlerTableReturnPrint(std::ostream& os) {
14486   os << "   off      hdlr (c)\n";
14487   for (int i = 0; i < length(); i += kReturnEntrySize) {
14488     int pc_offset = Smi::cast(get(i + kReturnOffsetIndex))->value();
14489     int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value();
14490     int handler_offset = HandlerOffsetField::decode(handler_field);
14491     CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
14492     os << "  " << std::setw(4) << pc_offset << "  ->  " << std::setw(4)
14493        << handler_offset << " (prediction=" << prediction << ")\n";
14494   }
14495 }
14496 
14497 
Disassemble(const char * name,std::ostream & os)14498 void Code::Disassemble(const char* name, std::ostream& os) {  // NOLINT
14499   os << "kind = " << Kind2String(kind()) << "\n";
14500   if (IsCodeStubOrIC()) {
14501     const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this));
14502     os << "major_key = " << (n == NULL ? "null" : n) << "\n";
14503   }
14504   if (is_inline_cache_stub()) {
14505     if (!IC::ICUseVector(kind())) {
14506       InlineCacheState ic_state = IC::StateFromCode(this);
14507       os << "ic_state = " << ICState2String(ic_state) << "\n";
14508       PrintExtraICState(os, kind(), extra_ic_state());
14509     }
14510     if (is_compare_ic_stub()) {
14511       DCHECK(CodeStub::GetMajorKey(this) == CodeStub::CompareIC);
14512       CompareICStub stub(stub_key(), GetIsolate());
14513       os << "compare_state = " << CompareICState::GetStateName(stub.left())
14514          << "*" << CompareICState::GetStateName(stub.right()) << " -> "
14515          << CompareICState::GetStateName(stub.state()) << "\n";
14516       os << "compare_operation = " << Token::Name(stub.op()) << "\n";
14517     }
14518   }
14519   if ((name != nullptr) && (name[0] != '\0')) {
14520     os << "name = " << name << "\n";
14521   } else if (kind() == BUILTIN) {
14522     name = GetIsolate()->builtins()->Lookup(instruction_start());
14523     if (name != nullptr) {
14524       os << "name = " << name << "\n";
14525     }
14526   } else if (kind() == BYTECODE_HANDLER) {
14527     name = GetIsolate()->interpreter()->LookupNameOfBytecodeHandler(this);
14528     if (name != nullptr) {
14529       os << "name = " << name << "\n";
14530     }
14531   }
14532   if (kind() == OPTIMIZED_FUNCTION) {
14533     os << "stack_slots = " << stack_slots() << "\n";
14534   }
14535   os << "compiler = " << (is_turbofanned()
14536                               ? "turbofan"
14537                               : is_crankshafted() ? "crankshaft"
14538                                                   : kind() == Code::FUNCTION
14539                                                         ? "full-codegen"
14540                                                         : "unknown") << "\n";
14541 
14542   os << "Instructions (size = " << instruction_size() << ")\n";
14543   {
14544     Isolate* isolate = GetIsolate();
14545     int size = instruction_size();
14546     int safepoint_offset =
14547         is_crankshafted() ? static_cast<int>(safepoint_table_offset()) : size;
14548     int back_edge_offset = (kind() == Code::FUNCTION)
14549                                ? static_cast<int>(back_edge_table_offset())
14550                                : size;
14551     int constant_pool_offset = FLAG_enable_embedded_constant_pool
14552                                    ? this->constant_pool_offset()
14553                                    : size;
14554 
14555     // Stop before reaching any embedded tables
14556     int code_size = Min(safepoint_offset, back_edge_offset);
14557     code_size = Min(code_size, constant_pool_offset);
14558     byte* begin = instruction_start();
14559     byte* end = begin + code_size;
14560     Disassembler::Decode(isolate, &os, begin, end, this);
14561 
14562     if (constant_pool_offset < size) {
14563       int constant_pool_size = size - constant_pool_offset;
14564       DCHECK((constant_pool_size & kPointerAlignmentMask) == 0);
14565       os << "\nConstant Pool (size = " << constant_pool_size << ")\n";
14566       Vector<char> buf = Vector<char>::New(50);
14567       intptr_t* ptr = reinterpret_cast<intptr_t*>(begin + constant_pool_offset);
14568       for (int i = 0; i < constant_pool_size; i += kPointerSize, ptr++) {
14569         SNPrintF(buf, "%4d %08" V8PRIxPTR, i, *ptr);
14570         os << static_cast<const void*>(ptr) << "  " << buf.start() << "\n";
14571       }
14572     }
14573   }
14574   os << "\n";
14575 
14576   SourcePositionTableIterator it(source_position_table());
14577   if (!it.done()) {
14578     os << "Source positions:\n pc offset  position\n";
14579     for (; !it.done(); it.Advance()) {
14580       os << std::setw(10) << it.code_offset() << std::setw(10)
14581          << it.source_position().ScriptOffset()
14582          << (it.is_statement() ? "  statement" : "") << "\n";
14583     }
14584     os << "\n";
14585   }
14586 
14587   if (kind() == FUNCTION) {
14588     DeoptimizationOutputData* data =
14589         DeoptimizationOutputData::cast(this->deoptimization_data());
14590     data->DeoptimizationOutputDataPrint(os);
14591   } else if (kind() == OPTIMIZED_FUNCTION) {
14592     DeoptimizationInputData* data =
14593         DeoptimizationInputData::cast(this->deoptimization_data());
14594     data->DeoptimizationInputDataPrint(os);
14595   }
14596   os << "\n";
14597 
14598   if (is_crankshafted()) {
14599     SafepointTable table(this);
14600     os << "Safepoints (size = " << table.size() << ")\n";
14601     for (unsigned i = 0; i < table.length(); i++) {
14602       unsigned pc_offset = table.GetPcOffset(i);
14603       os << static_cast<const void*>(instruction_start() + pc_offset) << "  ";
14604       os << std::setw(4) << pc_offset << "  ";
14605       table.PrintEntry(i, os);
14606       os << " (sp -> fp)  ";
14607       SafepointEntry entry = table.GetEntry(i);
14608       if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
14609         os << std::setw(6) << entry.deoptimization_index();
14610       } else {
14611         os << "<none>";
14612       }
14613       if (entry.argument_count() > 0) {
14614         os << " argc: " << entry.argument_count();
14615       }
14616       os << "\n";
14617     }
14618     os << "\n";
14619   } else if (kind() == FUNCTION) {
14620     unsigned offset = back_edge_table_offset();
14621     // If there is no back edge table, the "table start" will be at or after
14622     // (due to alignment) the end of the instruction stream.
14623     if (static_cast<int>(offset) < instruction_size()) {
14624       DisallowHeapAllocation no_gc;
14625       BackEdgeTable back_edges(this, &no_gc);
14626 
14627       os << "Back edges (size = " << back_edges.length() << ")\n";
14628       os << "ast_id  pc_offset  loop_depth\n";
14629 
14630       for (uint32_t i = 0; i < back_edges.length(); i++) {
14631         os << std::setw(6) << back_edges.ast_id(i).ToInt() << "  "
14632            << std::setw(9) << back_edges.pc_offset(i) << "  " << std::setw(10)
14633            << back_edges.loop_depth(i) << "\n";
14634       }
14635 
14636       os << "\n";
14637     }
14638 #ifdef OBJECT_PRINT
14639     if (!type_feedback_info()->IsUndefined(GetIsolate())) {
14640       TypeFeedbackInfo::cast(type_feedback_info())->TypeFeedbackInfoPrint(os);
14641       os << "\n";
14642     }
14643 #endif
14644   }
14645 
14646   if (handler_table()->length() > 0) {
14647     os << "Handler Table (size = " << handler_table()->Size() << ")\n";
14648     if (kind() == FUNCTION) {
14649       HandlerTable::cast(handler_table())->HandlerTableRangePrint(os);
14650     } else if (kind() == OPTIMIZED_FUNCTION) {
14651       HandlerTable::cast(handler_table())->HandlerTableReturnPrint(os);
14652     }
14653     os << "\n";
14654   }
14655 
14656   os << "RelocInfo (size = " << relocation_size() << ")\n";
14657   for (RelocIterator it(this); !it.done(); it.next()) {
14658     it.rinfo()->Print(GetIsolate(), os);
14659   }
14660   os << "\n";
14661 
14662   if (has_unwinding_info()) {
14663     os << "UnwindingInfo (size = " << unwinding_info_size() << ")\n";
14664     EhFrameDisassembler eh_frame_disassembler(unwinding_info_start(),
14665                                               unwinding_info_end());
14666     eh_frame_disassembler.DisassembleToStream(os);
14667     os << "\n";
14668   }
14669 }
14670 #endif  // ENABLE_DISASSEMBLER
14671 
14672 
Disassemble(std::ostream & os)14673 void BytecodeArray::Disassemble(std::ostream& os) {
14674   os << "Parameter count " << parameter_count() << "\n";
14675   os << "Frame size " << frame_size() << "\n";
14676 
14677   const uint8_t* base_address = GetFirstBytecodeAddress();
14678   SourcePositionTableIterator source_positions(source_position_table());
14679 
14680   interpreter::BytecodeArrayIterator iterator(handle(this));
14681   while (!iterator.done()) {
14682     if (!source_positions.done() &&
14683         iterator.current_offset() == source_positions.code_offset()) {
14684       os << std::setw(5) << source_positions.source_position().ScriptOffset();
14685       os << (source_positions.is_statement() ? " S> " : " E> ");
14686       source_positions.Advance();
14687     } else {
14688       os << "         ";
14689     }
14690     const uint8_t* current_address = base_address + iterator.current_offset();
14691     os << reinterpret_cast<const void*>(current_address) << " @ "
14692        << std::setw(4) << iterator.current_offset() << " : ";
14693     interpreter::BytecodeDecoder::Decode(os, current_address,
14694                                          parameter_count());
14695     if (interpreter::Bytecodes::IsJump(iterator.current_bytecode())) {
14696       const void* jump_target = base_address + iterator.GetJumpTargetOffset();
14697       os << " (" << jump_target << " @ " << iterator.GetJumpTargetOffset()
14698          << ")";
14699     }
14700     os << std::endl;
14701     iterator.Advance();
14702   }
14703 
14704   if (constant_pool()->length() > 0) {
14705     os << "Constant pool (size = " << constant_pool()->length() << ")\n";
14706     constant_pool()->Print();
14707   }
14708 
14709 #ifdef ENABLE_DISASSEMBLER
14710   if (handler_table()->length() > 0) {
14711     os << "Handler Table (size = " << handler_table()->Size() << ")\n";
14712     HandlerTable::cast(handler_table())->HandlerTableRangePrint(os);
14713   }
14714 #endif
14715 }
14716 
CopyBytecodesTo(BytecodeArray * to)14717 void BytecodeArray::CopyBytecodesTo(BytecodeArray* to) {
14718   BytecodeArray* from = this;
14719   DCHECK_EQ(from->length(), to->length());
14720   CopyBytes(to->GetFirstBytecodeAddress(), from->GetFirstBytecodeAddress(),
14721             from->length());
14722 }
14723 
MakeOlder()14724 void BytecodeArray::MakeOlder() {
14725   Age age = bytecode_age();
14726   if (age < kLastBytecodeAge) {
14727     set_bytecode_age(static_cast<Age>(age + 1));
14728   }
14729   DCHECK_GE(bytecode_age(), kFirstBytecodeAge);
14730   DCHECK_LE(bytecode_age(), kLastBytecodeAge);
14731 }
14732 
IsOld() const14733 bool BytecodeArray::IsOld() const {
14734   return bytecode_age() >= kIsOldBytecodeAge;
14735 }
14736 
14737 // static
Initialize(Handle<JSArray> array,int capacity,int length)14738 void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
14739   DCHECK(capacity >= 0);
14740   array->GetIsolate()->factory()->NewJSArrayStorage(
14741       array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
14742 }
14743 
SetLength(Handle<JSArray> array,uint32_t new_length)14744 void JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) {
14745   // We should never end in here with a pixel or external array.
14746   DCHECK(array->AllowsSetLength());
14747   if (array->SetLengthWouldNormalize(new_length)) {
14748     JSObject::NormalizeElements(array);
14749   }
14750   array->GetElementsAccessor()->SetLength(array, new_length);
14751 }
14752 
14753 
14754 // static
AddDependentCode(Handle<Map> map,DependentCode::DependencyGroup group,Handle<Code> code)14755 void Map::AddDependentCode(Handle<Map> map,
14756                            DependentCode::DependencyGroup group,
14757                            Handle<Code> code) {
14758   Handle<WeakCell> cell = Code::WeakCellFor(code);
14759   Handle<DependentCode> codes = DependentCode::InsertWeakCode(
14760       Handle<DependentCode>(map->dependent_code()), group, cell);
14761   if (*codes != map->dependent_code()) map->set_dependent_code(*codes);
14762 }
14763 
14764 
InsertCompilationDependencies(Handle<DependentCode> entries,DependencyGroup group,Handle<Foreign> info)14765 Handle<DependentCode> DependentCode::InsertCompilationDependencies(
14766     Handle<DependentCode> entries, DependencyGroup group,
14767     Handle<Foreign> info) {
14768   return Insert(entries, group, info);
14769 }
14770 
14771 
InsertWeakCode(Handle<DependentCode> entries,DependencyGroup group,Handle<WeakCell> code_cell)14772 Handle<DependentCode> DependentCode::InsertWeakCode(
14773     Handle<DependentCode> entries, DependencyGroup group,
14774     Handle<WeakCell> code_cell) {
14775   return Insert(entries, group, code_cell);
14776 }
14777 
14778 
Insert(Handle<DependentCode> entries,DependencyGroup group,Handle<Object> object)14779 Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
14780                                             DependencyGroup group,
14781                                             Handle<Object> object) {
14782   if (entries->length() == 0 || entries->group() > group) {
14783     // There is no such group.
14784     return DependentCode::New(group, object, entries);
14785   }
14786   if (entries->group() < group) {
14787     // The group comes later in the list.
14788     Handle<DependentCode> old_next(entries->next_link());
14789     Handle<DependentCode> new_next = Insert(old_next, group, object);
14790     if (!old_next.is_identical_to(new_next)) {
14791       entries->set_next_link(*new_next);
14792     }
14793     return entries;
14794   }
14795   DCHECK_EQ(group, entries->group());
14796   int count = entries->count();
14797   // Check for existing entry to avoid duplicates.
14798   for (int i = 0; i < count; i++) {
14799     if (entries->object_at(i) == *object) return entries;
14800   }
14801   if (entries->length() < kCodesStartIndex + count + 1) {
14802     entries = EnsureSpace(entries);
14803     // Count could have changed, reload it.
14804     count = entries->count();
14805   }
14806   entries->set_object_at(count, *object);
14807   entries->set_count(count + 1);
14808   return entries;
14809 }
14810 
14811 
New(DependencyGroup group,Handle<Object> object,Handle<DependentCode> next)14812 Handle<DependentCode> DependentCode::New(DependencyGroup group,
14813                                          Handle<Object> object,
14814                                          Handle<DependentCode> next) {
14815   Isolate* isolate = next->GetIsolate();
14816   Handle<DependentCode> result = Handle<DependentCode>::cast(
14817       isolate->factory()->NewFixedArray(kCodesStartIndex + 1, TENURED));
14818   result->set_next_link(*next);
14819   result->set_flags(GroupField::encode(group) | CountField::encode(1));
14820   result->set_object_at(0, *object);
14821   return result;
14822 }
14823 
14824 
EnsureSpace(Handle<DependentCode> entries)14825 Handle<DependentCode> DependentCode::EnsureSpace(
14826     Handle<DependentCode> entries) {
14827   if (entries->Compact()) return entries;
14828   Isolate* isolate = entries->GetIsolate();
14829   int capacity = kCodesStartIndex + DependentCode::Grow(entries->count());
14830   int grow_by = capacity - entries->length();
14831   return Handle<DependentCode>::cast(
14832       isolate->factory()->CopyFixedArrayAndGrow(entries, grow_by, TENURED));
14833 }
14834 
14835 
Compact()14836 bool DependentCode::Compact() {
14837   int old_count = count();
14838   int new_count = 0;
14839   for (int i = 0; i < old_count; i++) {
14840     Object* obj = object_at(i);
14841     if (!obj->IsWeakCell() || !WeakCell::cast(obj)->cleared()) {
14842       if (i != new_count) {
14843         copy(i, new_count);
14844       }
14845       new_count++;
14846     }
14847   }
14848   set_count(new_count);
14849   for (int i = new_count; i < old_count; i++) {
14850     clear_at(i);
14851   }
14852   return new_count < old_count;
14853 }
14854 
14855 
UpdateToFinishedCode(DependencyGroup group,Foreign * info,WeakCell * code_cell)14856 void DependentCode::UpdateToFinishedCode(DependencyGroup group, Foreign* info,
14857                                          WeakCell* code_cell) {
14858   if (this->length() == 0 || this->group() > group) {
14859     // There is no such group.
14860     return;
14861   }
14862   if (this->group() < group) {
14863     // The group comes later in the list.
14864     next_link()->UpdateToFinishedCode(group, info, code_cell);
14865     return;
14866   }
14867   DCHECK_EQ(group, this->group());
14868   DisallowHeapAllocation no_gc;
14869   int count = this->count();
14870   for (int i = 0; i < count; i++) {
14871     if (object_at(i) == info) {
14872       set_object_at(i, code_cell);
14873       break;
14874     }
14875   }
14876 #ifdef DEBUG
14877   for (int i = 0; i < count; i++) {
14878     DCHECK(object_at(i) != info);
14879   }
14880 #endif
14881 }
14882 
14883 
RemoveCompilationDependencies(DependentCode::DependencyGroup group,Foreign * info)14884 void DependentCode::RemoveCompilationDependencies(
14885     DependentCode::DependencyGroup group, Foreign* info) {
14886   if (this->length() == 0 || this->group() > group) {
14887     // There is no such group.
14888     return;
14889   }
14890   if (this->group() < group) {
14891     // The group comes later in the list.
14892     next_link()->RemoveCompilationDependencies(group, info);
14893     return;
14894   }
14895   DCHECK_EQ(group, this->group());
14896   DisallowHeapAllocation no_allocation;
14897   int old_count = count();
14898   // Find compilation info wrapper.
14899   int info_pos = -1;
14900   for (int i = 0; i < old_count; i++) {
14901     if (object_at(i) == info) {
14902       info_pos = i;
14903       break;
14904     }
14905   }
14906   if (info_pos == -1) return;  // Not found.
14907   // Use the last code to fill the gap.
14908   if (info_pos < old_count - 1) {
14909     copy(old_count - 1, info_pos);
14910   }
14911   clear_at(old_count - 1);
14912   set_count(old_count - 1);
14913 
14914 #ifdef DEBUG
14915   for (int i = 0; i < old_count - 1; i++) {
14916     DCHECK(object_at(i) != info);
14917   }
14918 #endif
14919 }
14920 
14921 
Contains(DependencyGroup group,WeakCell * code_cell)14922 bool DependentCode::Contains(DependencyGroup group, WeakCell* code_cell) {
14923   if (this->length() == 0 || this->group() > group) {
14924     // There is no such group.
14925     return false;
14926   }
14927   if (this->group() < group) {
14928     // The group comes later in the list.
14929     return next_link()->Contains(group, code_cell);
14930   }
14931   DCHECK_EQ(group, this->group());
14932   int count = this->count();
14933   for (int i = 0; i < count; i++) {
14934     if (object_at(i) == code_cell) return true;
14935   }
14936   return false;
14937 }
14938 
14939 
IsEmpty(DependencyGroup group)14940 bool DependentCode::IsEmpty(DependencyGroup group) {
14941   if (this->length() == 0 || this->group() > group) {
14942     // There is no such group.
14943     return true;
14944   }
14945   if (this->group() < group) {
14946     // The group comes later in the list.
14947     return next_link()->IsEmpty(group);
14948   }
14949   DCHECK_EQ(group, this->group());
14950   return count() == 0;
14951 }
14952 
14953 
MarkCodeForDeoptimization(Isolate * isolate,DependentCode::DependencyGroup group)14954 bool DependentCode::MarkCodeForDeoptimization(
14955     Isolate* isolate,
14956     DependentCode::DependencyGroup group) {
14957   if (this->length() == 0 || this->group() > group) {
14958     // There is no such group.
14959     return false;
14960   }
14961   if (this->group() < group) {
14962     // The group comes later in the list.
14963     return next_link()->MarkCodeForDeoptimization(isolate, group);
14964   }
14965   DCHECK_EQ(group, this->group());
14966   DisallowHeapAllocation no_allocation_scope;
14967   // Mark all the code that needs to be deoptimized.
14968   bool marked = false;
14969   bool invalidate_embedded_objects = group == kWeakCodeGroup;
14970   int count = this->count();
14971   for (int i = 0; i < count; i++) {
14972     Object* obj = object_at(i);
14973     if (obj->IsWeakCell()) {
14974       WeakCell* cell = WeakCell::cast(obj);
14975       if (cell->cleared()) continue;
14976       Code* code = Code::cast(cell->value());
14977       if (!code->marked_for_deoptimization()) {
14978         SetMarkedForDeoptimization(code, group);
14979         if (invalidate_embedded_objects) {
14980           code->InvalidateEmbeddedObjects();
14981         }
14982         marked = true;
14983       }
14984     } else {
14985       DCHECK(obj->IsForeign());
14986       CompilationDependencies* info =
14987           reinterpret_cast<CompilationDependencies*>(
14988               Foreign::cast(obj)->foreign_address());
14989       info->Abort();
14990     }
14991   }
14992   for (int i = 0; i < count; i++) {
14993     clear_at(i);
14994   }
14995   set_count(0);
14996   return marked;
14997 }
14998 
14999 
DeoptimizeDependentCodeGroup(Isolate * isolate,DependentCode::DependencyGroup group)15000 void DependentCode::DeoptimizeDependentCodeGroup(
15001     Isolate* isolate,
15002     DependentCode::DependencyGroup group) {
15003   DCHECK(AllowCodeDependencyChange::IsAllowed());
15004   DisallowHeapAllocation no_allocation_scope;
15005   bool marked = MarkCodeForDeoptimization(isolate, group);
15006   if (marked) Deoptimizer::DeoptimizeMarkedCode(isolate);
15007 }
15008 
15009 
SetMarkedForDeoptimization(Code * code,DependencyGroup group)15010 void DependentCode::SetMarkedForDeoptimization(Code* code,
15011                                                DependencyGroup group) {
15012   code->set_marked_for_deoptimization(true);
15013   if (FLAG_trace_deopt &&
15014       (code->deoptimization_data() != code->GetHeap()->empty_fixed_array())) {
15015     DeoptimizationInputData* deopt_data =
15016         DeoptimizationInputData::cast(code->deoptimization_data());
15017     CodeTracer::Scope scope(code->GetHeap()->isolate()->GetCodeTracer());
15018     PrintF(scope.file(), "[marking dependent code 0x%08" V8PRIxPTR
15019                          " (opt #%d) for deoptimization, reason: %s]\n",
15020            reinterpret_cast<intptr_t>(code),
15021            deopt_data->OptimizationId()->value(), DependencyGroupName(group));
15022   }
15023 }
15024 
15025 
DependencyGroupName(DependencyGroup group)15026 const char* DependentCode::DependencyGroupName(DependencyGroup group) {
15027   switch (group) {
15028     case kWeakCodeGroup:
15029       return "weak-code";
15030     case kTransitionGroup:
15031       return "transition";
15032     case kPrototypeCheckGroup:
15033       return "prototype-check";
15034     case kPropertyCellChangedGroup:
15035       return "property-cell-changed";
15036     case kFieldOwnerGroup:
15037       return "field-owner";
15038     case kInitialMapChangedGroup:
15039       return "initial-map-changed";
15040     case kAllocationSiteTenuringChangedGroup:
15041       return "allocation-site-tenuring-changed";
15042     case kAllocationSiteTransitionChangedGroup:
15043       return "allocation-site-transition-changed";
15044   }
15045   UNREACHABLE();
15046   return "?";
15047 }
15048 
15049 
TransitionToPrototype(Handle<Map> map,Handle<Object> prototype,PrototypeOptimizationMode mode)15050 Handle<Map> Map::TransitionToPrototype(Handle<Map> map,
15051                                        Handle<Object> prototype,
15052                                        PrototypeOptimizationMode mode) {
15053   Handle<Map> new_map = TransitionArray::GetPrototypeTransition(map, prototype);
15054   if (new_map.is_null()) {
15055     new_map = Copy(map, "TransitionToPrototype");
15056     TransitionArray::PutPrototypeTransition(map, prototype, new_map);
15057     Map::SetPrototype(new_map, prototype, mode);
15058   }
15059   return new_map;
15060 }
15061 
15062 
SetPrototype(Handle<JSReceiver> object,Handle<Object> value,bool from_javascript,ShouldThrow should_throw)15063 Maybe<bool> JSReceiver::SetPrototype(Handle<JSReceiver> object,
15064                                      Handle<Object> value, bool from_javascript,
15065                                      ShouldThrow should_throw) {
15066   if (object->IsJSProxy()) {
15067     return JSProxy::SetPrototype(Handle<JSProxy>::cast(object), value,
15068                                  from_javascript, should_throw);
15069   }
15070   return JSObject::SetPrototype(Handle<JSObject>::cast(object), value,
15071                                 from_javascript, should_throw);
15072 }
15073 
15074 
15075 // ES6: 9.5.2 [[SetPrototypeOf]] (V)
15076 // static
SetPrototype(Handle<JSProxy> proxy,Handle<Object> value,bool from_javascript,ShouldThrow should_throw)15077 Maybe<bool> JSProxy::SetPrototype(Handle<JSProxy> proxy, Handle<Object> value,
15078                                   bool from_javascript,
15079                                   ShouldThrow should_throw) {
15080   Isolate* isolate = proxy->GetIsolate();
15081   STACK_CHECK(isolate, Nothing<bool>());
15082   Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string();
15083   // 1. Assert: Either Type(V) is Object or Type(V) is Null.
15084   DCHECK(value->IsJSReceiver() || value->IsNull(isolate));
15085   // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
15086   Handle<Object> handler(proxy->handler(), isolate);
15087   // 3. If handler is null, throw a TypeError exception.
15088   // 4. Assert: Type(handler) is Object.
15089   if (proxy->IsRevoked()) {
15090     isolate->Throw(*isolate->factory()->NewTypeError(
15091         MessageTemplate::kProxyRevoked, trap_name));
15092     return Nothing<bool>();
15093   }
15094   // 5. Let target be the value of the [[ProxyTarget]] internal slot.
15095   Handle<JSReceiver> target(proxy->target(), isolate);
15096   // 6. Let trap be ? GetMethod(handler, "getPrototypeOf").
15097   Handle<Object> trap;
15098   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15099       isolate, trap,
15100       Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
15101       Nothing<bool>());
15102   // 7. If trap is undefined, then return target.[[SetPrototypeOf]]().
15103   if (trap->IsUndefined(isolate)) {
15104     return JSReceiver::SetPrototype(target, value, from_javascript,
15105                                     should_throw);
15106   }
15107   // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, V»)).
15108   Handle<Object> argv[] = {target, value};
15109   Handle<Object> trap_result;
15110   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15111       isolate, trap_result,
15112       Execution::Call(isolate, trap, handler, arraysize(argv), argv),
15113       Nothing<bool>());
15114   bool bool_trap_result = trap_result->BooleanValue();
15115   // 9. If booleanTrapResult is false, return false.
15116   if (!bool_trap_result) {
15117     RETURN_FAILURE(
15118         isolate, should_throw,
15119         NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15120   }
15121   // 10. Let extensibleTarget be ? IsExtensible(target).
15122   Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
15123   if (is_extensible.IsNothing()) return Nothing<bool>();
15124   // 11. If extensibleTarget is true, return true.
15125   if (is_extensible.FromJust()) {
15126     if (bool_trap_result) return Just(true);
15127     RETURN_FAILURE(
15128         isolate, should_throw,
15129         NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15130   }
15131   // 12. Let targetProto be ? target.[[GetPrototypeOf]]().
15132   Handle<Object> target_proto;
15133   ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_proto,
15134                                    JSReceiver::GetPrototype(isolate, target),
15135                                    Nothing<bool>());
15136   // 13. If SameValue(V, targetProto) is false, throw a TypeError exception.
15137   if (bool_trap_result && !value->SameValue(*target_proto)) {
15138     isolate->Throw(*isolate->factory()->NewTypeError(
15139         MessageTemplate::kProxySetPrototypeOfNonExtensible));
15140     return Nothing<bool>();
15141   }
15142   // 14. Return true.
15143   return Just(true);
15144 }
15145 
15146 
SetPrototype(Handle<JSObject> object,Handle<Object> value,bool from_javascript,ShouldThrow should_throw)15147 Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object,
15148                                    Handle<Object> value, bool from_javascript,
15149                                    ShouldThrow should_throw) {
15150   Isolate* isolate = object->GetIsolate();
15151 
15152 #ifdef DEBUG
15153   int size = object->Size();
15154 #endif
15155 
15156   if (from_javascript) {
15157     if (object->IsAccessCheckNeeded() &&
15158         !isolate->MayAccess(handle(isolate->context()), object)) {
15159       isolate->ReportFailedAccessCheck(object);
15160       RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
15161       RETURN_FAILURE(isolate, should_throw,
15162                      NewTypeError(MessageTemplate::kNoAccess));
15163     }
15164   } else {
15165     DCHECK(!object->IsAccessCheckNeeded());
15166   }
15167 
15168   Heap* heap = isolate->heap();
15169   // Silently ignore the change if value is not a JSObject or null.
15170   // SpiderMonkey behaves this way.
15171   if (!value->IsJSReceiver() && !value->IsNull(isolate)) return Just(true);
15172 
15173   bool all_extensible = object->map()->is_extensible();
15174   Handle<JSObject> real_receiver = object;
15175   if (from_javascript) {
15176     // Find the first object in the chain whose prototype object is not
15177     // hidden.
15178     PrototypeIterator iter(isolate, real_receiver, kStartAtPrototype,
15179                            PrototypeIterator::END_AT_NON_HIDDEN);
15180     while (!iter.IsAtEnd()) {
15181       // Casting to JSObject is fine because hidden prototypes are never
15182       // JSProxies.
15183       real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter);
15184       iter.Advance();
15185       all_extensible = all_extensible && real_receiver->map()->is_extensible();
15186     }
15187   }
15188   Handle<Map> map(real_receiver->map());
15189 
15190   // Nothing to do if prototype is already set.
15191   if (map->prototype() == *value) return Just(true);
15192 
15193   bool immutable_proto = map->is_immutable_proto();
15194   if (immutable_proto) {
15195     RETURN_FAILURE(
15196         isolate, should_throw,
15197         NewTypeError(MessageTemplate::kImmutablePrototypeSet, object));
15198   }
15199 
15200   // From 8.6.2 Object Internal Methods
15201   // ...
15202   // In addition, if [[Extensible]] is false the value of the [[Class]] and
15203   // [[Prototype]] internal properties of the object may not be modified.
15204   // ...
15205   // Implementation specific extensions that modify [[Class]], [[Prototype]]
15206   // or [[Extensible]] must not violate the invariants defined in the preceding
15207   // paragraph.
15208   if (!all_extensible) {
15209     RETURN_FAILURE(isolate, should_throw,
15210                    NewTypeError(MessageTemplate::kNonExtensibleProto, object));
15211   }
15212 
15213   // Before we can set the prototype we need to be sure prototype cycles are
15214   // prevented.  It is sufficient to validate that the receiver is not in the
15215   // new prototype chain.
15216   if (value->IsJSReceiver()) {
15217     for (PrototypeIterator iter(isolate, JSReceiver::cast(*value),
15218                                 kStartAtReceiver);
15219          !iter.IsAtEnd(); iter.Advance()) {
15220       if (iter.GetCurrent<JSReceiver>() == *object) {
15221         // Cycle detected.
15222         RETURN_FAILURE(isolate, should_throw,
15223                        NewTypeError(MessageTemplate::kCyclicProto));
15224       }
15225     }
15226   }
15227 
15228   // Set the new prototype of the object.
15229 
15230   isolate->UpdateArrayProtectorOnSetPrototype(real_receiver);
15231 
15232   PrototypeOptimizationMode mode =
15233       from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE;
15234   Handle<Map> new_map = Map::TransitionToPrototype(map, value, mode);
15235   DCHECK(new_map->prototype() == *value);
15236   JSObject::MigrateToMap(real_receiver, new_map);
15237 
15238   heap->ClearInstanceofCache();
15239   DCHECK(size == object->Size());
15240   return Just(true);
15241 }
15242 
15243 // static
SetImmutableProto(Handle<JSObject> object)15244 void JSObject::SetImmutableProto(Handle<JSObject> object) {
15245   DCHECK(!object->IsAccessCheckNeeded());  // Never called from JS
15246   Handle<Map> map(object->map());
15247 
15248   // Nothing to do if prototype is already set.
15249   if (map->is_immutable_proto()) return;
15250 
15251   Handle<Map> new_map = Map::TransitionToImmutableProto(map);
15252   object->set_map(*new_map);
15253 }
15254 
EnsureCanContainElements(Handle<JSObject> object,Arguments * args,uint32_t first_arg,uint32_t arg_count,EnsureElementsMode mode)15255 void JSObject::EnsureCanContainElements(Handle<JSObject> object,
15256                                         Arguments* args,
15257                                         uint32_t first_arg,
15258                                         uint32_t arg_count,
15259                                         EnsureElementsMode mode) {
15260   // Elements in |Arguments| are ordered backwards (because they're on the
15261   // stack), but the method that's called here iterates over them in forward
15262   // direction.
15263   return EnsureCanContainElements(
15264       object, args->arguments() - first_arg - (arg_count - 1), arg_count, mode);
15265 }
15266 
15267 
GetElementsAccessor()15268 ElementsAccessor* JSObject::GetElementsAccessor() {
15269   return ElementsAccessor::ForKind(GetElementsKind());
15270 }
15271 
15272 
ValidateElements(Handle<JSObject> object)15273 void JSObject::ValidateElements(Handle<JSObject> object) {
15274 #ifdef ENABLE_SLOW_DCHECKS
15275   if (FLAG_enable_slow_asserts) {
15276     ElementsAccessor* accessor = object->GetElementsAccessor();
15277     accessor->Validate(object);
15278   }
15279 #endif
15280 }
15281 
15282 
ShouldConvertToSlowElements(JSObject * object,uint32_t capacity,uint32_t index,uint32_t * new_capacity)15283 static bool ShouldConvertToSlowElements(JSObject* object, uint32_t capacity,
15284                                         uint32_t index,
15285                                         uint32_t* new_capacity) {
15286   STATIC_ASSERT(JSObject::kMaxUncheckedOldFastElementsLength <=
15287                 JSObject::kMaxUncheckedFastElementsLength);
15288   if (index < capacity) {
15289     *new_capacity = capacity;
15290     return false;
15291   }
15292   if (index - capacity >= JSObject::kMaxGap) return true;
15293   *new_capacity = JSObject::NewElementsCapacity(index + 1);
15294   DCHECK_LT(index, *new_capacity);
15295   if (*new_capacity <= JSObject::kMaxUncheckedOldFastElementsLength ||
15296       (*new_capacity <= JSObject::kMaxUncheckedFastElementsLength &&
15297        object->GetHeap()->InNewSpace(object))) {
15298     return false;
15299   }
15300   // If the fast-case backing storage takes up roughly three times as
15301   // much space (in machine words) as a dictionary backing storage
15302   // would, the object should have slow elements.
15303   int used_elements = object->GetFastElementsUsage();
15304   int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
15305                         SeededNumberDictionary::kEntrySize;
15306   return 3 * static_cast<uint32_t>(dictionary_size) <= *new_capacity;
15307 }
15308 
15309 
WouldConvertToSlowElements(uint32_t index)15310 bool JSObject::WouldConvertToSlowElements(uint32_t index) {
15311   if (HasFastElements()) {
15312     Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements()));
15313     uint32_t capacity = static_cast<uint32_t>(backing_store->length());
15314     uint32_t new_capacity;
15315     return ShouldConvertToSlowElements(this, capacity, index, &new_capacity);
15316   }
15317   return false;
15318 }
15319 
15320 
BestFittingFastElementsKind(JSObject * object)15321 static ElementsKind BestFittingFastElementsKind(JSObject* object) {
15322   if (object->HasSloppyArgumentsElements()) {
15323     return FAST_SLOPPY_ARGUMENTS_ELEMENTS;
15324   }
15325   if (object->HasStringWrapperElements()) {
15326     return FAST_STRING_WRAPPER_ELEMENTS;
15327   }
15328   DCHECK(object->HasDictionaryElements());
15329   SeededNumberDictionary* dictionary = object->element_dictionary();
15330   ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS;
15331   for (int i = 0; i < dictionary->Capacity(); i++) {
15332     Object* key = dictionary->KeyAt(i);
15333     if (key->IsNumber()) {
15334       Object* value = dictionary->ValueAt(i);
15335       if (!value->IsNumber()) return FAST_HOLEY_ELEMENTS;
15336       if (!value->IsSmi()) {
15337         if (!FLAG_unbox_double_arrays) return FAST_HOLEY_ELEMENTS;
15338         kind = FAST_HOLEY_DOUBLE_ELEMENTS;
15339       }
15340     }
15341   }
15342   return kind;
15343 }
15344 
15345 
ShouldConvertToFastElements(JSObject * object,SeededNumberDictionary * dictionary,uint32_t index,uint32_t * new_capacity)15346 static bool ShouldConvertToFastElements(JSObject* object,
15347                                         SeededNumberDictionary* dictionary,
15348                                         uint32_t index,
15349                                         uint32_t* new_capacity) {
15350   // If properties with non-standard attributes or accessors were added, we
15351   // cannot go back to fast elements.
15352   if (dictionary->requires_slow_elements()) return false;
15353 
15354   // Adding a property with this index will require slow elements.
15355   if (index >= static_cast<uint32_t>(Smi::kMaxValue)) return false;
15356 
15357   if (object->IsJSArray()) {
15358     Object* length = JSArray::cast(object)->length();
15359     if (!length->IsSmi()) return false;
15360     *new_capacity = static_cast<uint32_t>(Smi::cast(length)->value());
15361   } else {
15362     *new_capacity = dictionary->max_number_key() + 1;
15363   }
15364   *new_capacity = Max(index + 1, *new_capacity);
15365 
15366   uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
15367                              SeededNumberDictionary::kEntrySize;
15368 
15369   // Turn fast if the dictionary only saves 50% space.
15370   return 2 * dictionary_size >= *new_capacity;
15371 }
15372 
15373 
15374 // static
AddDataElement(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes)15375 MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> object,
15376                                              uint32_t index,
15377                                              Handle<Object> value,
15378                                              PropertyAttributes attributes) {
15379   MAYBE_RETURN_NULL(
15380       AddDataElement(object, index, value, attributes, THROW_ON_ERROR));
15381   return value;
15382 }
15383 
15384 
15385 // static
AddDataElement(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,ShouldThrow should_throw)15386 Maybe<bool> JSObject::AddDataElement(Handle<JSObject> object, uint32_t index,
15387                                      Handle<Object> value,
15388                                      PropertyAttributes attributes,
15389                                      ShouldThrow should_throw) {
15390   DCHECK(object->map()->is_extensible());
15391 
15392   Isolate* isolate = object->GetIsolate();
15393 
15394   uint32_t old_length = 0;
15395   uint32_t new_capacity = 0;
15396 
15397   if (object->IsJSArray()) {
15398     CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length));
15399   }
15400 
15401   ElementsKind kind = object->GetElementsKind();
15402   FixedArrayBase* elements = object->elements();
15403   ElementsKind dictionary_kind = DICTIONARY_ELEMENTS;
15404   if (IsSloppyArgumentsElements(kind)) {
15405     elements = FixedArrayBase::cast(FixedArray::cast(elements)->get(1));
15406     dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
15407   } else if (IsStringWrapperElementsKind(kind)) {
15408     dictionary_kind = SLOW_STRING_WRAPPER_ELEMENTS;
15409   }
15410 
15411   if (attributes != NONE) {
15412     kind = dictionary_kind;
15413   } else if (elements->IsSeededNumberDictionary()) {
15414     kind = ShouldConvertToFastElements(*object,
15415                                        SeededNumberDictionary::cast(elements),
15416                                        index, &new_capacity)
15417                ? BestFittingFastElementsKind(*object)
15418                : dictionary_kind;  // Overwrite in case of arguments.
15419   } else if (ShouldConvertToSlowElements(
15420                  *object, static_cast<uint32_t>(elements->length()), index,
15421                  &new_capacity)) {
15422     kind = dictionary_kind;
15423   }
15424 
15425   ElementsKind to = value->OptimalElementsKind();
15426   if (IsHoleyElementsKind(kind) || !object->IsJSArray() || index > old_length) {
15427     to = GetHoleyElementsKind(to);
15428     kind = GetHoleyElementsKind(kind);
15429   }
15430   to = GetMoreGeneralElementsKind(kind, to);
15431   ElementsAccessor* accessor = ElementsAccessor::ForKind(to);
15432   accessor->Add(object, index, value, attributes, new_capacity);
15433 
15434   if (object->IsJSArray() && index >= old_length) {
15435     Handle<Object> new_length =
15436         isolate->factory()->NewNumberFromUint(index + 1);
15437     JSArray::cast(*object)->set_length(*new_length);
15438   }
15439 
15440   return Just(true);
15441 }
15442 
15443 
SetLengthWouldNormalize(uint32_t new_length)15444 bool JSArray::SetLengthWouldNormalize(uint32_t new_length) {
15445   if (!HasFastElements()) return false;
15446   uint32_t capacity = static_cast<uint32_t>(elements()->length());
15447   uint32_t new_capacity;
15448   return JSArray::SetLengthWouldNormalize(GetHeap(), new_length) &&
15449          ShouldConvertToSlowElements(this, capacity, new_length - 1,
15450                                      &new_capacity);
15451 }
15452 
15453 
15454 const double AllocationSite::kPretenureRatio = 0.85;
15455 
15456 
ResetPretenureDecision()15457 void AllocationSite::ResetPretenureDecision() {
15458   set_pretenure_decision(kUndecided);
15459   set_memento_found_count(0);
15460   set_memento_create_count(0);
15461 }
15462 
15463 
GetPretenureMode()15464 PretenureFlag AllocationSite::GetPretenureMode() {
15465   PretenureDecision mode = pretenure_decision();
15466   // Zombie objects "decide" to be untenured.
15467   return mode == kTenure ? TENURED : NOT_TENURED;
15468 }
15469 
15470 
IsNestedSite()15471 bool AllocationSite::IsNestedSite() {
15472   DCHECK(FLAG_trace_track_allocation_sites);
15473   Object* current = GetHeap()->allocation_sites_list();
15474   while (current->IsAllocationSite()) {
15475     AllocationSite* current_site = AllocationSite::cast(current);
15476     if (current_site->nested_site() == this) {
15477       return true;
15478     }
15479     current = current_site->weak_next();
15480   }
15481   return false;
15482 }
15483 
15484 template <AllocationSiteUpdateMode update_or_check>
DigestTransitionFeedback(Handle<AllocationSite> site,ElementsKind to_kind)15485 bool AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
15486                                               ElementsKind to_kind) {
15487   Isolate* isolate = site->GetIsolate();
15488   bool result = false;
15489 
15490   if (site->SitePointsToLiteral() && site->transition_info()->IsJSArray()) {
15491     Handle<JSArray> transition_info =
15492         handle(JSArray::cast(site->transition_info()));
15493     ElementsKind kind = transition_info->GetElementsKind();
15494     // if kind is holey ensure that to_kind is as well.
15495     if (IsHoleyElementsKind(kind)) {
15496       to_kind = GetHoleyElementsKind(to_kind);
15497     }
15498     if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
15499       // If the array is huge, it's not likely to be defined in a local
15500       // function, so we shouldn't make new instances of it very often.
15501       uint32_t length = 0;
15502       CHECK(transition_info->length()->ToArrayLength(&length));
15503       if (length <= kMaximumArrayBytesToPretransition) {
15504         if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) {
15505           return true;
15506         }
15507         if (FLAG_trace_track_allocation_sites) {
15508           bool is_nested = site->IsNestedSite();
15509           PrintF(
15510               "AllocationSite: JSArray %p boilerplate %s updated %s->%s\n",
15511               reinterpret_cast<void*>(*site),
15512               is_nested ? "(nested)" : "",
15513               ElementsKindToString(kind),
15514               ElementsKindToString(to_kind));
15515         }
15516         JSObject::TransitionElementsKind(transition_info, to_kind);
15517         site->dependent_code()->DeoptimizeDependentCodeGroup(
15518             isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
15519         result = true;
15520       }
15521     }
15522   } else {
15523     ElementsKind kind = site->GetElementsKind();
15524     // if kind is holey ensure that to_kind is as well.
15525     if (IsHoleyElementsKind(kind)) {
15526       to_kind = GetHoleyElementsKind(to_kind);
15527     }
15528     if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
15529       if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) return true;
15530       if (FLAG_trace_track_allocation_sites) {
15531         PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
15532                reinterpret_cast<void*>(*site),
15533                ElementsKindToString(kind),
15534                ElementsKindToString(to_kind));
15535       }
15536       site->SetElementsKind(to_kind);
15537       site->dependent_code()->DeoptimizeDependentCodeGroup(
15538           isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
15539       result = true;
15540     }
15541   }
15542   return result;
15543 }
15544 
GetMode(ElementsKind from,ElementsKind to)15545 AllocationSiteMode AllocationSite::GetMode(ElementsKind from, ElementsKind to) {
15546   if (IsFastSmiElementsKind(from) &&
15547       IsMoreGeneralElementsKindTransition(from, to)) {
15548     return TRACK_ALLOCATION_SITE;
15549   }
15550 
15551   return DONT_TRACK_ALLOCATION_SITE;
15552 }
15553 
PretenureDecisionName(PretenureDecision decision)15554 const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) {
15555   switch (decision) {
15556     case kUndecided: return "undecided";
15557     case kDontTenure: return "don't tenure";
15558     case kMaybeTenure: return "maybe tenure";
15559     case kTenure: return "tenure";
15560     case kZombie: return "zombie";
15561     default: UNREACHABLE();
15562   }
15563   return NULL;
15564 }
15565 
15566 template <AllocationSiteUpdateMode update_or_check>
UpdateAllocationSite(Handle<JSObject> object,ElementsKind to_kind)15567 bool JSObject::UpdateAllocationSite(Handle<JSObject> object,
15568                                     ElementsKind to_kind) {
15569   if (!object->IsJSArray()) return false;
15570 
15571   Heap* heap = object->GetHeap();
15572   if (!heap->InNewSpace(*object)) return false;
15573 
15574   Handle<AllocationSite> site;
15575   {
15576     DisallowHeapAllocation no_allocation;
15577 
15578     AllocationMemento* memento =
15579         heap->FindAllocationMemento<Heap::kForRuntime>(*object);
15580     if (memento == NULL) return false;
15581 
15582     // Walk through to the Allocation Site
15583     site = handle(memento->GetAllocationSite());
15584   }
15585   return AllocationSite::DigestTransitionFeedback<update_or_check>(site,
15586                                                                    to_kind);
15587 }
15588 
15589 template bool
15590 JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kCheckOnly>(
15591     Handle<JSObject> object, ElementsKind to_kind);
15592 
15593 template bool JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kUpdate>(
15594     Handle<JSObject> object, ElementsKind to_kind);
15595 
TransitionElementsKind(Handle<JSObject> object,ElementsKind to_kind)15596 void JSObject::TransitionElementsKind(Handle<JSObject> object,
15597                                       ElementsKind to_kind) {
15598   ElementsKind from_kind = object->GetElementsKind();
15599 
15600   if (IsFastHoleyElementsKind(from_kind)) {
15601     to_kind = GetHoleyElementsKind(to_kind);
15602   }
15603 
15604   if (from_kind == to_kind) return;
15605 
15606   // This method should never be called for any other case.
15607   DCHECK(IsFastElementsKind(from_kind));
15608   DCHECK(IsFastElementsKind(to_kind));
15609   DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind);
15610 
15611   UpdateAllocationSite(object, to_kind);
15612   if (object->elements() == object->GetHeap()->empty_fixed_array() ||
15613       IsFastDoubleElementsKind(from_kind) ==
15614           IsFastDoubleElementsKind(to_kind)) {
15615     // No change is needed to the elements() buffer, the transition
15616     // only requires a map change.
15617     Handle<Map> new_map = GetElementsTransitionMap(object, to_kind);
15618     MigrateToMap(object, new_map);
15619     if (FLAG_trace_elements_transitions) {
15620       Handle<FixedArrayBase> elms(object->elements());
15621       PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms);
15622     }
15623   } else {
15624     DCHECK((IsFastSmiElementsKind(from_kind) &&
15625             IsFastDoubleElementsKind(to_kind)) ||
15626            (IsFastDoubleElementsKind(from_kind) &&
15627             IsFastObjectElementsKind(to_kind)));
15628     uint32_t c = static_cast<uint32_t>(object->elements()->length());
15629     ElementsAccessor::ForKind(to_kind)->GrowCapacityAndConvert(object, c);
15630   }
15631 }
15632 
15633 
15634 // static
IsValidElementsTransition(ElementsKind from_kind,ElementsKind to_kind)15635 bool Map::IsValidElementsTransition(ElementsKind from_kind,
15636                                     ElementsKind to_kind) {
15637   // Transitions can't go backwards.
15638   if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
15639     return false;
15640   }
15641 
15642   // Transitions from HOLEY -> PACKED are not allowed.
15643   return !IsFastHoleyElementsKind(from_kind) ||
15644       IsFastHoleyElementsKind(to_kind);
15645 }
15646 
15647 
HasReadOnlyLength(Handle<JSArray> array)15648 bool JSArray::HasReadOnlyLength(Handle<JSArray> array) {
15649   Map* map = array->map();
15650   // Fast path: "length" is the first fast property of arrays. Since it's not
15651   // configurable, it's guaranteed to be the first in the descriptor array.
15652   if (!map->is_dictionary_map()) {
15653     DCHECK(map->instance_descriptors()->GetKey(0) ==
15654            array->GetHeap()->length_string());
15655     return map->instance_descriptors()->GetDetails(0).IsReadOnly();
15656   }
15657 
15658   Isolate* isolate = array->GetIsolate();
15659   LookupIterator it(array, isolate->factory()->length_string(), array,
15660                     LookupIterator::OWN_SKIP_INTERCEPTOR);
15661   CHECK_EQ(LookupIterator::ACCESSOR, it.state());
15662   return it.IsReadOnly();
15663 }
15664 
15665 
WouldChangeReadOnlyLength(Handle<JSArray> array,uint32_t index)15666 bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array,
15667                                         uint32_t index) {
15668   uint32_t length = 0;
15669   CHECK(array->length()->ToArrayLength(&length));
15670   if (length <= index) return HasReadOnlyLength(array);
15671   return false;
15672 }
15673 
15674 
15675 template <typename BackingStore>
FastHoleyElementsUsage(JSObject * object,BackingStore * store)15676 static int FastHoleyElementsUsage(JSObject* object, BackingStore* store) {
15677   Isolate* isolate = store->GetIsolate();
15678   int limit = object->IsJSArray()
15679                   ? Smi::cast(JSArray::cast(object)->length())->value()
15680                   : store->length();
15681   int used = 0;
15682   for (int i = 0; i < limit; ++i) {
15683     if (!store->is_the_hole(isolate, i)) ++used;
15684   }
15685   return used;
15686 }
15687 
15688 
GetFastElementsUsage()15689 int JSObject::GetFastElementsUsage() {
15690   FixedArrayBase* store = elements();
15691   switch (GetElementsKind()) {
15692     case FAST_SMI_ELEMENTS:
15693     case FAST_DOUBLE_ELEMENTS:
15694     case FAST_ELEMENTS:
15695       return IsJSArray() ? Smi::cast(JSArray::cast(this)->length())->value()
15696                          : store->length();
15697     case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
15698       store = FixedArray::cast(FixedArray::cast(store)->get(1));
15699     // Fall through.
15700     case FAST_HOLEY_SMI_ELEMENTS:
15701     case FAST_HOLEY_ELEMENTS:
15702     case FAST_STRING_WRAPPER_ELEMENTS:
15703       return FastHoleyElementsUsage(this, FixedArray::cast(store));
15704     case FAST_HOLEY_DOUBLE_ELEMENTS:
15705       if (elements()->length() == 0) return 0;
15706       return FastHoleyElementsUsage(this, FixedDoubleArray::cast(store));
15707 
15708     case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
15709     case SLOW_STRING_WRAPPER_ELEMENTS:
15710     case DICTIONARY_ELEMENTS:
15711     case NO_ELEMENTS:
15712 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                      \
15713     case TYPE##_ELEMENTS:                                                    \
15714 
15715     TYPED_ARRAYS(TYPED_ARRAY_CASE)
15716 #undef TYPED_ARRAY_CASE
15717     UNREACHABLE();
15718   }
15719   return 0;
15720 }
15721 
15722 
15723 // Certain compilers request function template instantiation when they
15724 // see the definition of the other template functions in the
15725 // class. This requires us to have the template functions put
15726 // together, so even though this function belongs in objects-debug.cc,
15727 // we keep it here instead to satisfy certain compilers.
15728 #ifdef OBJECT_PRINT
15729 template <typename Derived, typename Shape, typename Key>
Print(std::ostream & os)15730 void Dictionary<Derived, Shape, Key>::Print(std::ostream& os) {  // NOLINT
15731   Isolate* isolate = this->GetIsolate();
15732   int capacity = this->Capacity();
15733   for (int i = 0; i < capacity; i++) {
15734     Object* k = this->KeyAt(i);
15735     if (this->IsKey(isolate, k)) {
15736       os << "\n   ";
15737       if (k->IsString()) {
15738         String::cast(k)->StringPrint(os);
15739       } else {
15740         os << Brief(k);
15741       }
15742       os << ": " << Brief(this->ValueAt(i)) << " ";
15743       this->DetailsAt(i).PrintAsSlowTo(os);
15744     }
15745   }
15746 }
15747 template <typename Derived, typename Shape, typename Key>
Print()15748 void Dictionary<Derived, Shape, Key>::Print() {
15749   OFStream os(stdout);
15750   Print(os);
15751 }
15752 #endif
15753 
15754 
15755 template<typename Derived, typename Shape, typename Key>
CopyValuesTo(FixedArray * elements)15756 void Dictionary<Derived, Shape, Key>::CopyValuesTo(FixedArray* elements) {
15757   Isolate* isolate = this->GetIsolate();
15758   int pos = 0;
15759   int capacity = this->Capacity();
15760   DisallowHeapAllocation no_gc;
15761   WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
15762   for (int i = 0; i < capacity; i++) {
15763     Object* k = this->KeyAt(i);
15764     if (this->IsKey(isolate, k)) {
15765       elements->set(pos++, this->ValueAt(i), mode);
15766     }
15767   }
15768   DCHECK(pos == elements->length());
15769 }
15770 
15771 
GetPropertyWithInterceptor(LookupIterator * it,bool * done)15772 MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it,
15773                                                          bool* done) {
15774   DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
15775   return GetPropertyWithInterceptorInternal(it, it->GetInterceptor(), done);
15776 }
15777 
HasRealNamedProperty(Handle<JSObject> object,Handle<Name> name)15778 Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object,
15779                                            Handle<Name> name) {
15780   LookupIterator it = LookupIterator::PropertyOrElement(
15781       name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
15782   return HasProperty(&it);
15783 }
15784 
15785 
HasRealElementProperty(Handle<JSObject> object,uint32_t index)15786 Maybe<bool> JSObject::HasRealElementProperty(Handle<JSObject> object,
15787                                              uint32_t index) {
15788   Isolate* isolate = object->GetIsolate();
15789   LookupIterator it(isolate, object, index, object,
15790                     LookupIterator::OWN_SKIP_INTERCEPTOR);
15791   return HasProperty(&it);
15792 }
15793 
15794 
HasRealNamedCallbackProperty(Handle<JSObject> object,Handle<Name> name)15795 Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
15796                                                    Handle<Name> name) {
15797   LookupIterator it = LookupIterator::PropertyOrElement(
15798       name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
15799   Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
15800   return maybe_result.IsJust() ? Just(it.state() == LookupIterator::ACCESSOR)
15801                                : Nothing<bool>();
15802 }
15803 
GetMaxLengthForNewSpaceAllocation(ElementsKind kind)15804 int FixedArrayBase::GetMaxLengthForNewSpaceAllocation(ElementsKind kind) {
15805   return ((kMaxRegularHeapObjectSize - FixedArrayBase::kHeaderSize) >>
15806           ElementsKindToShiftSize(kind));
15807 }
15808 
WasConstructedFromApiFunction()15809 bool JSObject::WasConstructedFromApiFunction() {
15810   auto instance_type = map()->instance_type();
15811   bool is_api_object = instance_type == JS_API_OBJECT_TYPE ||
15812                        instance_type == JS_SPECIAL_API_OBJECT_TYPE;
15813 #ifdef ENABLE_SLOW_DCHECKS
15814   if (FLAG_enable_slow_asserts) {
15815     Object* maybe_constructor = map()->GetConstructor();
15816     if (!maybe_constructor->IsJSFunction()) return false;
15817     JSFunction* constructor = JSFunction::cast(maybe_constructor);
15818     if (constructor->shared()->IsApiFunction()) {
15819       DCHECK(is_api_object);
15820     } else {
15821       DCHECK(!is_api_object);
15822     }
15823   }
15824 #endif
15825   return is_api_object;
15826 }
15827 
PrivateSymbolToName() const15828 const char* Symbol::PrivateSymbolToName() const {
15829   Heap* heap = GetIsolate()->heap();
15830 #define SYMBOL_CHECK_AND_PRINT(name) \
15831   if (this == heap->name()) return #name;
15832   PRIVATE_SYMBOL_LIST(SYMBOL_CHECK_AND_PRINT)
15833 #undef SYMBOL_CHECK_AND_PRINT
15834   return "UNKNOWN";
15835 }
15836 
15837 
SymbolShortPrint(std::ostream & os)15838 void Symbol::SymbolShortPrint(std::ostream& os) {
15839   os << "<Symbol:";
15840   if (!name()->IsUndefined(GetIsolate())) {
15841     os << " ";
15842     HeapStringAllocator allocator;
15843     StringStream accumulator(&allocator);
15844     String::cast(name())->StringShortPrint(&accumulator, false);
15845     os << accumulator.ToCString().get();
15846   } else {
15847     os << " (" << PrivateSymbolToName() << ")";
15848   }
15849   os << ">";
15850 }
15851 
15852 
15853 // StringSharedKeys are used as keys in the eval cache.
15854 class StringSharedKey : public HashTableKey {
15855  public:
15856   // This tuple unambiguously identifies calls to eval() or
15857   // CreateDynamicFunction() (such as through the Function() constructor).
15858   // * source is the string passed into eval(). For dynamic functions, this is
15859   //   the effective source for the function, some of which is implicitly
15860   //   generated.
15861   // * shared is the shared function info for the function containing the call
15862   //   to eval(). for dynamic functions, shared is the native context closure.
15863   // * When positive, position is the position in the source where eval is
15864   //   called. When negative, position is the negation of the position in the
15865   //   dynamic function's effective source where the ')' ends the parameters.
StringSharedKey(Handle<String> source,Handle<SharedFunctionInfo> shared,LanguageMode language_mode,int position)15866   StringSharedKey(Handle<String> source, Handle<SharedFunctionInfo> shared,
15867                   LanguageMode language_mode, int position)
15868       : source_(source),
15869         shared_(shared),
15870         language_mode_(language_mode),
15871         position_(position) {}
15872 
IsMatch(Object * other)15873   bool IsMatch(Object* other) override {
15874     DisallowHeapAllocation no_allocation;
15875     if (!other->IsFixedArray()) {
15876       if (!other->IsNumber()) return false;
15877       uint32_t other_hash = static_cast<uint32_t>(other->Number());
15878       return Hash() == other_hash;
15879     }
15880     FixedArray* other_array = FixedArray::cast(other);
15881     SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
15882     if (shared != *shared_) return false;
15883     int language_unchecked = Smi::cast(other_array->get(2))->value();
15884     DCHECK(is_valid_language_mode(language_unchecked));
15885     LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
15886     if (language_mode != language_mode_) return false;
15887     int position = Smi::cast(other_array->get(3))->value();
15888     if (position != position_) return false;
15889     String* source = String::cast(other_array->get(1));
15890     return source->Equals(*source_);
15891   }
15892 
StringSharedHashHelper(String * source,SharedFunctionInfo * shared,LanguageMode language_mode,int position)15893   static uint32_t StringSharedHashHelper(String* source,
15894                                          SharedFunctionInfo* shared,
15895                                          LanguageMode language_mode,
15896                                          int position) {
15897     uint32_t hash = source->Hash();
15898     if (shared->HasSourceCode()) {
15899       // Instead of using the SharedFunctionInfo pointer in the hash
15900       // code computation, we use a combination of the hash of the
15901       // script source code and the start position of the calling scope.
15902       // We do this to ensure that the cache entries can survive garbage
15903       // collection.
15904       Script* script(Script::cast(shared->script()));
15905       hash ^= String::cast(script->source())->Hash();
15906       STATIC_ASSERT(LANGUAGE_END == 2);
15907       if (is_strict(language_mode)) hash ^= 0x8000;
15908       hash += position;
15909     }
15910     return hash;
15911   }
15912 
Hash()15913   uint32_t Hash() override {
15914     return StringSharedHashHelper(*source_, *shared_, language_mode_,
15915                                   position_);
15916   }
15917 
HashForObject(Object * obj)15918   uint32_t HashForObject(Object* obj) override {
15919     DisallowHeapAllocation no_allocation;
15920     if (obj->IsNumber()) {
15921       return static_cast<uint32_t>(obj->Number());
15922     }
15923     FixedArray* other_array = FixedArray::cast(obj);
15924     SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
15925     String* source = String::cast(other_array->get(1));
15926     int language_unchecked = Smi::cast(other_array->get(2))->value();
15927     DCHECK(is_valid_language_mode(language_unchecked));
15928     LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
15929     int position = Smi::cast(other_array->get(3))->value();
15930     return StringSharedHashHelper(source, shared, language_mode, position);
15931   }
15932 
15933 
AsHandle(Isolate * isolate)15934   Handle<Object> AsHandle(Isolate* isolate) override {
15935     Handle<FixedArray> array = isolate->factory()->NewFixedArray(4);
15936     array->set(0, *shared_);
15937     array->set(1, *source_);
15938     array->set(2, Smi::FromInt(language_mode_));
15939     array->set(3, Smi::FromInt(position_));
15940     return array;
15941   }
15942 
15943  private:
15944   Handle<String> source_;
15945   Handle<SharedFunctionInfo> shared_;
15946   LanguageMode language_mode_;
15947   int position_;
15948 };
15949 
15950 // static
Status(int status)15951 const char* JSPromise::Status(int status) {
15952   switch (status) {
15953     case v8::Promise::kFulfilled:
15954       return "resolved";
15955     case v8::Promise::kPending:
15956       return "pending";
15957     case v8::Promise::kRejected:
15958       return "rejected";
15959   }
15960   UNREACHABLE();
15961   return NULL;
15962 }
15963 
15964 namespace {
15965 
RegExpFlagsFromString(Handle<String> flags,bool * success)15966 JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags, bool* success) {
15967   JSRegExp::Flags value = JSRegExp::kNone;
15968   int length = flags->length();
15969   // A longer flags string cannot be valid.
15970   if (length > 5) return JSRegExp::Flags(0);
15971   for (int i = 0; i < length; i++) {
15972     JSRegExp::Flag flag = JSRegExp::kNone;
15973     switch (flags->Get(i)) {
15974       case 'g':
15975         flag = JSRegExp::kGlobal;
15976         break;
15977       case 'i':
15978         flag = JSRegExp::kIgnoreCase;
15979         break;
15980       case 'm':
15981         flag = JSRegExp::kMultiline;
15982         break;
15983       case 'u':
15984         flag = JSRegExp::kUnicode;
15985         break;
15986       case 'y':
15987         flag = JSRegExp::kSticky;
15988         break;
15989       default:
15990         return JSRegExp::Flags(0);
15991     }
15992     // Duplicate flag.
15993     if (value & flag) return JSRegExp::Flags(0);
15994     value |= flag;
15995   }
15996   *success = true;
15997   return value;
15998 }
15999 
16000 }  // namespace
16001 
16002 
16003 // static
New(Handle<String> pattern,Flags flags)16004 MaybeHandle<JSRegExp> JSRegExp::New(Handle<String> pattern, Flags flags) {
16005   Isolate* isolate = pattern->GetIsolate();
16006   Handle<JSFunction> constructor = isolate->regexp_function();
16007   Handle<JSRegExp> regexp =
16008       Handle<JSRegExp>::cast(isolate->factory()->NewJSObject(constructor));
16009 
16010   return JSRegExp::Initialize(regexp, pattern, flags);
16011 }
16012 
16013 
16014 // static
Copy(Handle<JSRegExp> regexp)16015 Handle<JSRegExp> JSRegExp::Copy(Handle<JSRegExp> regexp) {
16016   Isolate* const isolate = regexp->GetIsolate();
16017   return Handle<JSRegExp>::cast(isolate->factory()->CopyJSObject(regexp));
16018 }
16019 
16020 
16021 template <typename Char>
CountRequiredEscapes(Handle<String> source)16022 inline int CountRequiredEscapes(Handle<String> source) {
16023   DisallowHeapAllocation no_gc;
16024   int escapes = 0;
16025   Vector<const Char> src = source->GetCharVector<Char>();
16026   for (int i = 0; i < src.length(); i++) {
16027     if (src[i] == '\\') {
16028       // Escape. Skip next character;
16029       i++;
16030     } else if (src[i] == '/') {
16031       // Not escaped forward-slash needs escape.
16032       escapes++;
16033     }
16034   }
16035   return escapes;
16036 }
16037 
16038 
16039 template <typename Char, typename StringType>
WriteEscapedRegExpSource(Handle<String> source,Handle<StringType> result)16040 inline Handle<StringType> WriteEscapedRegExpSource(Handle<String> source,
16041                                                    Handle<StringType> result) {
16042   DisallowHeapAllocation no_gc;
16043   Vector<const Char> src = source->GetCharVector<Char>();
16044   Vector<Char> dst(result->GetChars(), result->length());
16045   int s = 0;
16046   int d = 0;
16047   while (s < src.length()) {
16048     if (src[s] == '\\') {
16049       // Escape. Copy this and next character.
16050       dst[d++] = src[s++];
16051       if (s == src.length()) break;
16052     } else if (src[s] == '/') {
16053       // Not escaped forward-slash needs escape.
16054       dst[d++] = '\\';
16055     }
16056     dst[d++] = src[s++];
16057   }
16058   DCHECK_EQ(result->length(), d);
16059   return result;
16060 }
16061 
16062 
EscapeRegExpSource(Isolate * isolate,Handle<String> source)16063 MaybeHandle<String> EscapeRegExpSource(Isolate* isolate,
16064                                        Handle<String> source) {
16065   String::Flatten(source);
16066   if (source->length() == 0) return isolate->factory()->query_colon_string();
16067   bool one_byte = source->IsOneByteRepresentationUnderneath();
16068   int escapes = one_byte ? CountRequiredEscapes<uint8_t>(source)
16069                          : CountRequiredEscapes<uc16>(source);
16070   if (escapes == 0) return source;
16071   int length = source->length() + escapes;
16072   if (one_byte) {
16073     Handle<SeqOneByteString> result;
16074     ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
16075                                isolate->factory()->NewRawOneByteString(length),
16076                                String);
16077     return WriteEscapedRegExpSource<uint8_t>(source, result);
16078   } else {
16079     Handle<SeqTwoByteString> result;
16080     ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
16081                                isolate->factory()->NewRawTwoByteString(length),
16082                                String);
16083     return WriteEscapedRegExpSource<uc16>(source, result);
16084   }
16085 }
16086 
16087 
16088 // static
Initialize(Handle<JSRegExp> regexp,Handle<String> source,Handle<String> flags_string)16089 MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
16090                                            Handle<String> source,
16091                                            Handle<String> flags_string) {
16092   Isolate* isolate = source->GetIsolate();
16093   bool success = false;
16094   Flags flags = RegExpFlagsFromString(flags_string, &success);
16095   if (!success) {
16096     THROW_NEW_ERROR(
16097         isolate,
16098         NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string),
16099         JSRegExp);
16100   }
16101   return Initialize(regexp, source, flags);
16102 }
16103 
16104 
16105 // static
Initialize(Handle<JSRegExp> regexp,Handle<String> source,Flags flags)16106 MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
16107                                            Handle<String> source, Flags flags) {
16108   Isolate* isolate = regexp->GetIsolate();
16109   Factory* factory = isolate->factory();
16110   // If source is the empty string we set it to "(?:)" instead as
16111   // suggested by ECMA-262, 5th, section 15.10.4.1.
16112   if (source->length() == 0) source = factory->query_colon_string();
16113 
16114   Handle<String> escaped_source;
16115   ASSIGN_RETURN_ON_EXCEPTION(isolate, escaped_source,
16116                              EscapeRegExpSource(isolate, source), JSRegExp);
16117 
16118   RETURN_ON_EXCEPTION(isolate, RegExpImpl::Compile(regexp, source, flags),
16119                       JSRegExp);
16120 
16121   regexp->set_source(*escaped_source);
16122   regexp->set_flags(Smi::FromInt(flags));
16123 
16124   Map* map = regexp->map();
16125   Object* constructor = map->GetConstructor();
16126   if (constructor->IsJSFunction() &&
16127       JSFunction::cast(constructor)->initial_map() == map) {
16128     // If we still have the original map, set in-object properties directly.
16129     regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, Smi::kZero,
16130                                   SKIP_WRITE_BARRIER);
16131   } else {
16132     // Map has changed, so use generic, but slower, method.
16133     RETURN_ON_EXCEPTION(isolate, JSReceiver::SetProperty(
16134                                      regexp, factory->lastIndex_string(),
16135                                      Handle<Smi>(Smi::kZero, isolate), STRICT),
16136                         JSRegExp);
16137   }
16138 
16139   return regexp;
16140 }
16141 
16142 
16143 // RegExpKey carries the source and flags of a regular expression as key.
16144 class RegExpKey : public HashTableKey {
16145  public:
RegExpKey(Handle<String> string,JSRegExp::Flags flags)16146   RegExpKey(Handle<String> string, JSRegExp::Flags flags)
16147       : string_(string), flags_(Smi::FromInt(flags)) {}
16148 
16149   // Rather than storing the key in the hash table, a pointer to the
16150   // stored value is stored where the key should be.  IsMatch then
16151   // compares the search key to the found object, rather than comparing
16152   // a key to a key.
IsMatch(Object * obj)16153   bool IsMatch(Object* obj) override {
16154     FixedArray* val = FixedArray::cast(obj);
16155     return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
16156         && (flags_ == val->get(JSRegExp::kFlagsIndex));
16157   }
16158 
Hash()16159   uint32_t Hash() override { return RegExpHash(*string_, flags_); }
16160 
AsHandle(Isolate * isolate)16161   Handle<Object> AsHandle(Isolate* isolate) override {
16162     // Plain hash maps, which is where regexp keys are used, don't
16163     // use this function.
16164     UNREACHABLE();
16165     return MaybeHandle<Object>().ToHandleChecked();
16166   }
16167 
HashForObject(Object * obj)16168   uint32_t HashForObject(Object* obj) override {
16169     FixedArray* val = FixedArray::cast(obj);
16170     return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
16171                       Smi::cast(val->get(JSRegExp::kFlagsIndex)));
16172   }
16173 
RegExpHash(String * string,Smi * flags)16174   static uint32_t RegExpHash(String* string, Smi* flags) {
16175     return string->Hash() + flags->value();
16176   }
16177 
16178   Handle<String> string_;
16179   Smi* flags_;
16180 };
16181 
16182 
AsHandle(Isolate * isolate)16183 Handle<Object> OneByteStringKey::AsHandle(Isolate* isolate) {
16184   if (hash_field_ == 0) Hash();
16185   return isolate->factory()->NewOneByteInternalizedString(string_, hash_field_);
16186 }
16187 
16188 
AsHandle(Isolate * isolate)16189 Handle<Object> TwoByteStringKey::AsHandle(Isolate* isolate) {
16190   if (hash_field_ == 0) Hash();
16191   return isolate->factory()->NewTwoByteInternalizedString(string_, hash_field_);
16192 }
16193 
16194 
AsHandle(Isolate * isolate)16195 Handle<Object> SeqOneByteSubStringKey::AsHandle(Isolate* isolate) {
16196   if (hash_field_ == 0) Hash();
16197   return isolate->factory()->NewOneByteInternalizedSubString(
16198       string_, from_, length_, hash_field_);
16199 }
16200 
16201 
IsMatch(Object * string)16202 bool SeqOneByteSubStringKey::IsMatch(Object* string) {
16203   Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
16204   return String::cast(string)->IsOneByteEqualTo(chars);
16205 }
16206 
16207 
16208 // InternalizedStringKey carries a string/internalized-string object as key.
16209 class InternalizedStringKey : public HashTableKey {
16210  public:
InternalizedStringKey(Handle<String> string)16211   explicit InternalizedStringKey(Handle<String> string)
16212       : string_(String::Flatten(string)) {}
16213 
IsMatch(Object * string)16214   bool IsMatch(Object* string) override {
16215     return String::cast(string)->Equals(*string_);
16216   }
16217 
Hash()16218   uint32_t Hash() override { return string_->Hash(); }
16219 
HashForObject(Object * other)16220   uint32_t HashForObject(Object* other) override {
16221     return String::cast(other)->Hash();
16222   }
16223 
AsHandle(Isolate * isolate)16224   Handle<Object> AsHandle(Isolate* isolate) override {
16225     // Internalize the string if possible.
16226     MaybeHandle<Map> maybe_map =
16227         isolate->factory()->InternalizedStringMapForString(string_);
16228     Handle<Map> map;
16229     if (maybe_map.ToHandle(&map)) {
16230       string_->set_map_no_write_barrier(*map);
16231       DCHECK(string_->IsInternalizedString());
16232       return string_;
16233     }
16234     if (FLAG_thin_strings) {
16235       // External strings get special treatment, to avoid copying their
16236       // contents.
16237       if (string_->IsExternalOneByteString()) {
16238         return isolate->factory()
16239             ->InternalizeExternalString<ExternalOneByteString>(string_);
16240       } else if (string_->IsExternalTwoByteString()) {
16241         return isolate->factory()
16242             ->InternalizeExternalString<ExternalTwoByteString>(string_);
16243       }
16244     }
16245     // Otherwise allocate a new internalized string.
16246     return isolate->factory()->NewInternalizedStringImpl(
16247         string_, string_->length(), string_->hash_field());
16248   }
16249 
StringHash(Object * obj)16250   static uint32_t StringHash(Object* obj) {
16251     return String::cast(obj)->Hash();
16252   }
16253 
16254  private:
16255   Handle<String> string_;
16256 };
16257 
16258 
16259 template<typename Derived, typename Shape, typename Key>
IteratePrefix(ObjectVisitor * v)16260 void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) {
16261   BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v);
16262 }
16263 
16264 
16265 template<typename Derived, typename Shape, typename Key>
IterateElements(ObjectVisitor * v)16266 void HashTable<Derived, Shape, Key>::IterateElements(ObjectVisitor* v) {
16267   BodyDescriptorBase::IteratePointers(this, kElementsStartOffset,
16268                                       kHeaderSize + length() * kPointerSize, v);
16269 }
16270 
16271 
16272 template<typename Derived, typename Shape, typename Key>
New(Isolate * isolate,int at_least_space_for,MinimumCapacity capacity_option,PretenureFlag pretenure)16273 Handle<Derived> HashTable<Derived, Shape, Key>::New(
16274     Isolate* isolate,
16275     int at_least_space_for,
16276     MinimumCapacity capacity_option,
16277     PretenureFlag pretenure) {
16278   DCHECK(0 <= at_least_space_for);
16279   DCHECK_IMPLIES(capacity_option == USE_CUSTOM_MINIMUM_CAPACITY,
16280                  base::bits::IsPowerOfTwo32(at_least_space_for));
16281 
16282   int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
16283                      ? at_least_space_for
16284                      : ComputeCapacity(at_least_space_for);
16285   if (capacity > HashTable::kMaxCapacity) {
16286     v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
16287   }
16288   return New(isolate, capacity, pretenure);
16289 }
16290 
16291 template <typename Derived, typename Shape, typename Key>
New(Isolate * isolate,int capacity,PretenureFlag pretenure)16292 Handle<Derived> HashTable<Derived, Shape, Key>::New(Isolate* isolate,
16293                                                     int capacity,
16294                                                     PretenureFlag pretenure) {
16295   Factory* factory = isolate->factory();
16296   int length = EntryToIndex(capacity);
16297   Handle<FixedArray> array = factory->NewFixedArray(length, pretenure);
16298   array->set_map_no_write_barrier(Shape::GetMap(isolate));
16299   Handle<Derived> table = Handle<Derived>::cast(array);
16300 
16301   table->SetNumberOfElements(0);
16302   table->SetNumberOfDeletedElements(0);
16303   table->SetCapacity(capacity);
16304   return table;
16305 }
16306 
16307 // Find entry for key otherwise return kNotFound.
16308 template <typename Derived, typename Shape>
FindEntry(Handle<Name> key)16309 int NameDictionaryBase<Derived, Shape>::FindEntry(Handle<Name> key) {
16310   if (!key->IsUniqueName()) {
16311     return DerivedDictionary::FindEntry(key);
16312   }
16313 
16314   // Optimized for unique names. Knowledge of the key type allows:
16315   // 1. Move the check if the key is unique out of the loop.
16316   // 2. Avoid comparing hash codes in unique-to-unique comparison.
16317   // 3. Detect a case when a dictionary key is not unique but the key is.
16318   //    In case of positive result the dictionary key may be replaced by the
16319   //    internalized string with minimal performance penalty. It gives a chance
16320   //    to perform further lookups in code stubs (and significant performance
16321   //    boost a certain style of code).
16322 
16323   // EnsureCapacity will guarantee the hash table is never full.
16324   uint32_t capacity = this->Capacity();
16325   uint32_t entry = Derived::FirstProbe(key->Hash(), capacity);
16326   uint32_t count = 1;
16327   Isolate* isolate = this->GetIsolate();
16328   while (true) {
16329     Object* element = this->KeyAt(entry);
16330     if (element->IsUndefined(isolate)) break;  // Empty entry.
16331     if (*key == element) return entry;
16332     DCHECK(element->IsTheHole(isolate) || element->IsUniqueName());
16333     entry = Derived::NextProbe(entry, count++, capacity);
16334   }
16335   return Derived::kNotFound;
16336 }
16337 
16338 
16339 template<typename Derived, typename Shape, typename Key>
Rehash(Handle<Derived> new_table,Key key)16340 void HashTable<Derived, Shape, Key>::Rehash(
16341     Handle<Derived> new_table,
16342     Key key) {
16343   DCHECK(NumberOfElements() < new_table->Capacity());
16344 
16345   DisallowHeapAllocation no_gc;
16346   WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
16347 
16348   // Copy prefix to new array.
16349   for (int i = kPrefixStartIndex;
16350        i < kPrefixStartIndex + Shape::kPrefixSize;
16351        i++) {
16352     new_table->set(i, get(i), mode);
16353   }
16354 
16355   // Rehash the elements.
16356   int capacity = this->Capacity();
16357   Heap* heap = new_table->GetHeap();
16358   Object* the_hole = heap->the_hole_value();
16359   Object* undefined = heap->undefined_value();
16360   for (int i = 0; i < capacity; i++) {
16361     uint32_t from_index = EntryToIndex(i);
16362     Object* k = this->get(from_index);
16363     if (k != the_hole && k != undefined) {
16364       uint32_t hash = this->HashForObject(key, k);
16365       uint32_t insertion_index =
16366           EntryToIndex(new_table->FindInsertionEntry(hash));
16367       for (int j = 0; j < Shape::kEntrySize; j++) {
16368         new_table->set(insertion_index + j, get(from_index + j), mode);
16369       }
16370     }
16371   }
16372   new_table->SetNumberOfElements(NumberOfElements());
16373   new_table->SetNumberOfDeletedElements(0);
16374 }
16375 
16376 
16377 template<typename Derived, typename Shape, typename Key>
EntryForProbe(Key key,Object * k,int probe,uint32_t expected)16378 uint32_t HashTable<Derived, Shape, Key>::EntryForProbe(
16379     Key key,
16380     Object* k,
16381     int probe,
16382     uint32_t expected) {
16383   uint32_t hash = this->HashForObject(key, k);
16384   uint32_t capacity = this->Capacity();
16385   uint32_t entry = FirstProbe(hash, capacity);
16386   for (int i = 1; i < probe; i++) {
16387     if (entry == expected) return expected;
16388     entry = NextProbe(entry, i, capacity);
16389   }
16390   return entry;
16391 }
16392 
16393 
16394 template<typename Derived, typename Shape, typename Key>
Swap(uint32_t entry1,uint32_t entry2,WriteBarrierMode mode)16395 void HashTable<Derived, Shape, Key>::Swap(uint32_t entry1,
16396                                           uint32_t entry2,
16397                                           WriteBarrierMode mode) {
16398   int index1 = EntryToIndex(entry1);
16399   int index2 = EntryToIndex(entry2);
16400   Object* temp[Shape::kEntrySize];
16401   for (int j = 0; j < Shape::kEntrySize; j++) {
16402     temp[j] = get(index1 + j);
16403   }
16404   for (int j = 0; j < Shape::kEntrySize; j++) {
16405     set(index1 + j, get(index2 + j), mode);
16406   }
16407   for (int j = 0; j < Shape::kEntrySize; j++) {
16408     set(index2 + j, temp[j], mode);
16409   }
16410 }
16411 
16412 
16413 template<typename Derived, typename Shape, typename Key>
Rehash(Key key)16414 void HashTable<Derived, Shape, Key>::Rehash(Key key) {
16415   DisallowHeapAllocation no_gc;
16416   WriteBarrierMode mode = GetWriteBarrierMode(no_gc);
16417   Isolate* isolate = GetIsolate();
16418   uint32_t capacity = Capacity();
16419   bool done = false;
16420   for (int probe = 1; !done; probe++) {
16421     // All elements at entries given by one of the first _probe_ probes
16422     // are placed correctly. Other elements might need to be moved.
16423     done = true;
16424     for (uint32_t current = 0; current < capacity; current++) {
16425       Object* current_key = KeyAt(current);
16426       if (IsKey(isolate, current_key)) {
16427         uint32_t target = EntryForProbe(key, current_key, probe, current);
16428         if (current == target) continue;
16429         Object* target_key = KeyAt(target);
16430         if (!IsKey(target_key) ||
16431             EntryForProbe(key, target_key, probe, target) != target) {
16432           // Put the current element into the correct position.
16433           Swap(current, target, mode);
16434           // The other element will be processed on the next iteration.
16435           current--;
16436         } else {
16437           // The place for the current element is occupied. Leave the element
16438           // for the next probe.
16439           done = false;
16440         }
16441       }
16442     }
16443   }
16444   // Wipe deleted entries.
16445   Object* the_hole = isolate->heap()->the_hole_value();
16446   Object* undefined = isolate->heap()->undefined_value();
16447   for (uint32_t current = 0; current < capacity; current++) {
16448     if (KeyAt(current) == the_hole) {
16449       set(EntryToIndex(current) + Derived::kEntryKeyIndex, undefined);
16450     }
16451   }
16452   SetNumberOfDeletedElements(0);
16453 }
16454 
16455 
16456 template<typename Derived, typename Shape, typename Key>
EnsureCapacity(Handle<Derived> table,int n,Key key,PretenureFlag pretenure)16457 Handle<Derived> HashTable<Derived, Shape, Key>::EnsureCapacity(
16458     Handle<Derived> table,
16459     int n,
16460     Key key,
16461     PretenureFlag pretenure) {
16462   Isolate* isolate = table->GetIsolate();
16463   int capacity = table->Capacity();
16464   int nof = table->NumberOfElements() + n;
16465 
16466   if (table->HasSufficientCapacityToAdd(n)) return table;
16467 
16468   const int kMinCapacityForPretenure = 256;
16469   bool should_pretenure = pretenure == TENURED ||
16470       ((capacity > kMinCapacityForPretenure) &&
16471           !isolate->heap()->InNewSpace(*table));
16472   Handle<Derived> new_table = HashTable::New(
16473       isolate,
16474       nof * 2,
16475       USE_DEFAULT_MINIMUM_CAPACITY,
16476       should_pretenure ? TENURED : NOT_TENURED);
16477 
16478   table->Rehash(new_table, key);
16479   return new_table;
16480 }
16481 
16482 template <typename Derived, typename Shape, typename Key>
HasSufficientCapacityToAdd(int number_of_additional_elements)16483 bool HashTable<Derived, Shape, Key>::HasSufficientCapacityToAdd(
16484     int number_of_additional_elements) {
16485   int capacity = Capacity();
16486   int nof = NumberOfElements() + number_of_additional_elements;
16487   int nod = NumberOfDeletedElements();
16488   // Return true if:
16489   //   50% is still free after adding number_of_additional_elements elements and
16490   //   at most 50% of the free elements are deleted elements.
16491   if ((nof < capacity) && ((nod <= (capacity - nof) >> 1))) {
16492     int needed_free = nof >> 1;
16493     if (nof + needed_free <= capacity) return true;
16494   }
16495   return false;
16496 }
16497 
16498 
16499 template<typename Derived, typename Shape, typename Key>
Shrink(Handle<Derived> table,Key key)16500 Handle<Derived> HashTable<Derived, Shape, Key>::Shrink(Handle<Derived> table,
16501                                                        Key key) {
16502   int capacity = table->Capacity();
16503   int nof = table->NumberOfElements();
16504 
16505   // Shrink to fit the number of elements if only a quarter of the
16506   // capacity is filled with elements.
16507   if (nof > (capacity >> 2)) return table;
16508   // Allocate a new dictionary with room for at least the current
16509   // number of elements. The allocation method will make sure that
16510   // there is extra room in the dictionary for additions. Don't go
16511   // lower than room for 16 elements.
16512   int at_least_room_for = nof;
16513   if (at_least_room_for < 16) return table;
16514 
16515   Isolate* isolate = table->GetIsolate();
16516   const int kMinCapacityForPretenure = 256;
16517   bool pretenure =
16518       (at_least_room_for > kMinCapacityForPretenure) &&
16519       !isolate->heap()->InNewSpace(*table);
16520   Handle<Derived> new_table = HashTable::New(
16521       isolate,
16522       at_least_room_for,
16523       USE_DEFAULT_MINIMUM_CAPACITY,
16524       pretenure ? TENURED : NOT_TENURED);
16525 
16526   table->Rehash(new_table, key);
16527   return new_table;
16528 }
16529 
16530 
16531 template<typename Derived, typename Shape, typename Key>
FindInsertionEntry(uint32_t hash)16532 uint32_t HashTable<Derived, Shape, Key>::FindInsertionEntry(uint32_t hash) {
16533   uint32_t capacity = Capacity();
16534   uint32_t entry = FirstProbe(hash, capacity);
16535   uint32_t count = 1;
16536   // EnsureCapacity will guarantee the hash table is never full.
16537   Isolate* isolate = GetIsolate();
16538   while (true) {
16539     Object* element = KeyAt(entry);
16540     if (!IsKey(isolate, element)) break;
16541     entry = NextProbe(entry, count++, capacity);
16542   }
16543   return entry;
16544 }
16545 
16546 
16547 // Force instantiation of template instances class.
16548 // Please note this list is compiler dependent.
16549 
16550 template class HashTable<StringTable, StringTableShape, HashTableKey*>;
16551 
16552 template class HashTable<CompilationCacheTable,
16553                          CompilationCacheShape,
16554                          HashTableKey*>;
16555 
16556 template class HashTable<ObjectHashTable,
16557                          ObjectHashTableShape,
16558                          Handle<Object> >;
16559 
16560 template class HashTable<WeakHashTable, WeakHashTableShape<2>, Handle<Object> >;
16561 
16562 template class Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >;
16563 
16564 template class Dictionary<GlobalDictionary, GlobalDictionaryShape,
16565                           Handle<Name> >;
16566 
16567 template class Dictionary<SeededNumberDictionary,
16568                           SeededNumberDictionaryShape,
16569                           uint32_t>;
16570 
16571 template class Dictionary<UnseededNumberDictionary,
16572                           UnseededNumberDictionaryShape,
16573                           uint32_t>;
16574 
16575 template Handle<SeededNumberDictionary>
16576 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::New(
16577     Isolate*, int at_least_space_for, PretenureFlag pretenure,
16578     MinimumCapacity capacity_option);
16579 
16580 template Handle<SeededNumberDictionary>
16581 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
16582            uint32_t>::NewEmpty(Isolate*, PretenureFlag pretenure);
16583 
16584 template Handle<UnseededNumberDictionary>
16585 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
16586            uint32_t>::New(Isolate*, int at_least_space_for,
16587                           PretenureFlag pretenure,
16588                           MinimumCapacity capacity_option);
16589 
16590 template Handle<NameDictionary>
16591 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::New(
16592     Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
16593 
16594 template Handle<NameDictionary>
16595 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::NewEmpty(
16596     Isolate*, PretenureFlag pretenure);
16597 
16598 template Handle<GlobalDictionary>
16599 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::New(
16600     Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
16601 
16602 template Handle<SeededNumberDictionary>
16603 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
16604     AtPut(Handle<SeededNumberDictionary>, uint32_t, Handle<Object>);
16605 
16606 template Handle<UnseededNumberDictionary>
16607 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
16608     AtPut(Handle<UnseededNumberDictionary>, uint32_t, Handle<Object>);
16609 
16610 template Object*
16611 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
16612     SlowReverseLookup(Object* value);
16613 
16614 template Object*
16615 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
16616     SlowReverseLookup(Object* value);
16617 
16618 template Handle<Object>
16619 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::DeleteProperty(
16620     Handle<NameDictionary>, int);
16621 
16622 template Handle<Object>
16623 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
16624            uint32_t>::DeleteProperty(Handle<SeededNumberDictionary>, int);
16625 
16626 template Handle<Object>
16627 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
16628            uint32_t>::DeleteProperty(Handle<UnseededNumberDictionary>, int);
16629 
16630 template Handle<NameDictionary>
16631 HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
16632     New(Isolate*, int, MinimumCapacity, PretenureFlag);
16633 
16634 template Handle<ObjectHashSet> HashTable<ObjectHashSet, ObjectHashSetShape,
16635                                          Handle<Object>>::New(Isolate*, int n,
16636                                                               MinimumCapacity,
16637                                                               PretenureFlag);
16638 
16639 template Handle<NameDictionary>
16640 HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
16641     Shrink(Handle<NameDictionary>, Handle<Name>);
16642 
16643 template Handle<SeededNumberDictionary>
16644 HashTable<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
16645     Shrink(Handle<SeededNumberDictionary>, uint32_t);
16646 
16647 template Handle<UnseededNumberDictionary>
16648     HashTable<UnseededNumberDictionary, UnseededNumberDictionaryShape,
16649               uint32_t>::Shrink(Handle<UnseededNumberDictionary>, uint32_t);
16650 
16651 template Handle<NameDictionary>
16652 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::Add(
16653     Handle<NameDictionary>, Handle<Name>, Handle<Object>, PropertyDetails,
16654     int*);
16655 
16656 template Handle<GlobalDictionary>
16657 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::Add(
16658     Handle<GlobalDictionary>, Handle<Name>, Handle<Object>, PropertyDetails,
16659     int*);
16660 
16661 template Handle<FixedArray> Dictionary<
16662     NameDictionary, NameDictionaryShape,
16663     Handle<Name> >::GenerateNewEnumerationIndices(Handle<NameDictionary>);
16664 
16665 template Handle<SeededNumberDictionary>
16666 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::Add(
16667     Handle<SeededNumberDictionary>, uint32_t, Handle<Object>, PropertyDetails,
16668     int*);
16669 
16670 template Handle<UnseededNumberDictionary>
16671 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
16672            uint32_t>::Add(Handle<UnseededNumberDictionary>, uint32_t,
16673                           Handle<Object>, PropertyDetails, int*);
16674 
16675 template Handle<SeededNumberDictionary>
16676 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
16677     EnsureCapacity(Handle<SeededNumberDictionary>, int, uint32_t);
16678 
16679 template Handle<UnseededNumberDictionary>
16680 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
16681     EnsureCapacity(Handle<UnseededNumberDictionary>, int, uint32_t);
16682 
16683 template void Dictionary<NameDictionary, NameDictionaryShape,
16684                          Handle<Name> >::SetRequiresCopyOnCapacityChange();
16685 
16686 template Handle<NameDictionary>
16687 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
16688     EnsureCapacity(Handle<NameDictionary>, int, Handle<Name>);
16689 
16690 template int HashTable<SeededNumberDictionary, SeededNumberDictionaryShape,
16691                        uint32_t>::FindEntry(uint32_t);
16692 
16693 template int NameDictionaryBase<NameDictionary, NameDictionaryShape>::FindEntry(
16694     Handle<Name>);
16695 
16696 template int Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
16697     NumberOfElementsFilterAttributes(PropertyFilter filter);
16698 
16699 template int Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::
16700     NumberOfElementsFilterAttributes(PropertyFilter filter);
16701 
16702 template void
16703 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
16704     CopyEnumKeysTo(Handle<Dictionary<GlobalDictionary, GlobalDictionaryShape,
16705                                      Handle<Name>>>
16706                        dictionary,
16707                    Handle<FixedArray> storage, KeyCollectionMode mode,
16708                    KeyAccumulator* accumulator);
16709 
16710 template void
16711 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::CopyEnumKeysTo(
16712     Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>>
16713         dictionary,
16714     Handle<FixedArray> storage, KeyCollectionMode mode,
16715     KeyAccumulator* accumulator);
16716 
16717 template Handle<FixedArray>
16718 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
16719     IterationIndices(
16720         Handle<
16721             Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>>
16722             dictionary);
16723 template void
16724 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
16725     CollectKeysTo(Handle<Dictionary<GlobalDictionary, GlobalDictionaryShape,
16726                                     Handle<Name>>>
16727                       dictionary,
16728                   KeyAccumulator* keys);
16729 
16730 template Handle<FixedArray>
16731 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::IterationIndices(
16732     Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>>
16733         dictionary);
16734 template void
16735 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::CollectKeysTo(
16736     Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>>
16737         dictionary,
16738     KeyAccumulator* keys);
16739 
PrepareSlowElementsForSort(Handle<JSObject> object,uint32_t limit)16740 Handle<Object> JSObject::PrepareSlowElementsForSort(
16741     Handle<JSObject> object, uint32_t limit) {
16742   DCHECK(object->HasDictionaryElements());
16743   Isolate* isolate = object->GetIsolate();
16744   // Must stay in dictionary mode, either because of requires_slow_elements,
16745   // or because we are not going to sort (and therefore compact) all of the
16746   // elements.
16747   Handle<SeededNumberDictionary> dict(object->element_dictionary(), isolate);
16748   Handle<SeededNumberDictionary> new_dict =
16749       SeededNumberDictionary::New(isolate, dict->NumberOfElements());
16750 
16751   uint32_t pos = 0;
16752   uint32_t undefs = 0;
16753   int capacity = dict->Capacity();
16754   Handle<Smi> bailout(Smi::FromInt(-1), isolate);
16755   // Entry to the new dictionary does not cause it to grow, as we have
16756   // allocated one that is large enough for all entries.
16757   DisallowHeapAllocation no_gc;
16758   for (int i = 0; i < capacity; i++) {
16759     Object* k = dict->KeyAt(i);
16760     if (!dict->IsKey(isolate, k)) continue;
16761 
16762     DCHECK(k->IsNumber());
16763     DCHECK(!k->IsSmi() || Smi::cast(k)->value() >= 0);
16764     DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
16765     DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
16766 
16767     HandleScope scope(isolate);
16768     Handle<Object> value(dict->ValueAt(i), isolate);
16769     PropertyDetails details = dict->DetailsAt(i);
16770     if (details.kind() == kAccessor || details.IsReadOnly()) {
16771       // Bail out and do the sorting of undefineds and array holes in JS.
16772       // Also bail out if the element is not supposed to be moved.
16773       return bailout;
16774     }
16775 
16776     uint32_t key = NumberToUint32(k);
16777     if (key < limit) {
16778       if (value->IsUndefined(isolate)) {
16779         undefs++;
16780       } else if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
16781         // Adding an entry with the key beyond smi-range requires
16782         // allocation. Bailout.
16783         return bailout;
16784       } else {
16785         Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
16786             new_dict, pos, value, details, object);
16787         DCHECK(result.is_identical_to(new_dict));
16788         USE(result);
16789         pos++;
16790       }
16791     } else if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
16792       // Adding an entry with the key beyond smi-range requires
16793       // allocation. Bailout.
16794       return bailout;
16795     } else {
16796       Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
16797           new_dict, key, value, details, object);
16798       DCHECK(result.is_identical_to(new_dict));
16799       USE(result);
16800     }
16801   }
16802 
16803   uint32_t result = pos;
16804   PropertyDetails no_details = PropertyDetails::Empty();
16805   while (undefs > 0) {
16806     if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
16807       // Adding an entry with the key beyond smi-range requires
16808       // allocation. Bailout.
16809       return bailout;
16810     }
16811     HandleScope scope(isolate);
16812     Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
16813         new_dict, pos, isolate->factory()->undefined_value(), no_details,
16814         object);
16815     DCHECK(result.is_identical_to(new_dict));
16816     USE(result);
16817     pos++;
16818     undefs--;
16819   }
16820 
16821   object->set_elements(*new_dict);
16822 
16823   AllowHeapAllocation allocate_return_value;
16824   return isolate->factory()->NewNumberFromUint(result);
16825 }
16826 
16827 
16828 // Collects all defined (non-hole) and non-undefined (array) elements at
16829 // the start of the elements array.
16830 // If the object is in dictionary mode, it is converted to fast elements
16831 // mode.
PrepareElementsForSort(Handle<JSObject> object,uint32_t limit)16832 Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object,
16833                                                 uint32_t limit) {
16834   Isolate* isolate = object->GetIsolate();
16835   if (object->HasSloppyArgumentsElements() || !object->map()->is_extensible()) {
16836     return handle(Smi::FromInt(-1), isolate);
16837   }
16838 
16839   if (object->HasStringWrapperElements()) {
16840     int len = String::cast(Handle<JSValue>::cast(object)->value())->length();
16841     return handle(Smi::FromInt(len), isolate);
16842   }
16843 
16844   if (object->HasDictionaryElements()) {
16845     // Convert to fast elements containing only the existing properties.
16846     // Ordering is irrelevant, since we are going to sort anyway.
16847     Handle<SeededNumberDictionary> dict(object->element_dictionary());
16848     if (object->IsJSArray() || dict->requires_slow_elements() ||
16849         dict->max_number_key() >= limit) {
16850       return JSObject::PrepareSlowElementsForSort(object, limit);
16851     }
16852     // Convert to fast elements.
16853 
16854     Handle<Map> new_map =
16855         JSObject::GetElementsTransitionMap(object, FAST_HOLEY_ELEMENTS);
16856 
16857     PretenureFlag tenure = isolate->heap()->InNewSpace(*object) ?
16858         NOT_TENURED: TENURED;
16859     Handle<FixedArray> fast_elements =
16860         isolate->factory()->NewFixedArray(dict->NumberOfElements(), tenure);
16861     dict->CopyValuesTo(*fast_elements);
16862     JSObject::ValidateElements(object);
16863 
16864     JSObject::SetMapAndElements(object, new_map, fast_elements);
16865   } else if (object->HasFixedTypedArrayElements()) {
16866     // Typed arrays cannot have holes or undefined elements.
16867     return handle(Smi::FromInt(
16868         FixedArrayBase::cast(object->elements())->length()), isolate);
16869   } else if (!object->HasFastDoubleElements()) {
16870     EnsureWritableFastElements(object);
16871   }
16872   DCHECK(object->HasFastSmiOrObjectElements() ||
16873          object->HasFastDoubleElements());
16874 
16875   // Collect holes at the end, undefined before that and the rest at the
16876   // start, and return the number of non-hole, non-undefined values.
16877 
16878   Handle<FixedArrayBase> elements_base(object->elements());
16879   uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
16880   if (limit > elements_length) {
16881     limit = elements_length;
16882   }
16883   if (limit == 0) {
16884     return handle(Smi::kZero, isolate);
16885   }
16886 
16887   uint32_t result = 0;
16888   if (elements_base->map() == isolate->heap()->fixed_double_array_map()) {
16889     FixedDoubleArray* elements = FixedDoubleArray::cast(*elements_base);
16890     // Split elements into defined and the_hole, in that order.
16891     unsigned int holes = limit;
16892     // Assume most arrays contain no holes and undefined values, so minimize the
16893     // number of stores of non-undefined, non-the-hole values.
16894     for (unsigned int i = 0; i < holes; i++) {
16895       if (elements->is_the_hole(i)) {
16896         holes--;
16897       } else {
16898         continue;
16899       }
16900       // Position i needs to be filled.
16901       while (holes > i) {
16902         if (elements->is_the_hole(holes)) {
16903           holes--;
16904         } else {
16905           elements->set(i, elements->get_scalar(holes));
16906           break;
16907         }
16908       }
16909     }
16910     result = holes;
16911     while (holes < limit) {
16912       elements->set_the_hole(holes);
16913       holes++;
16914     }
16915   } else {
16916     FixedArray* elements = FixedArray::cast(*elements_base);
16917     DisallowHeapAllocation no_gc;
16918 
16919     // Split elements into defined, undefined and the_hole, in that order.  Only
16920     // count locations for undefined and the hole, and fill them afterwards.
16921     WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_gc);
16922     unsigned int undefs = limit;
16923     unsigned int holes = limit;
16924     // Assume most arrays contain no holes and undefined values, so minimize the
16925     // number of stores of non-undefined, non-the-hole values.
16926     for (unsigned int i = 0; i < undefs; i++) {
16927       Object* current = elements->get(i);
16928       if (current->IsTheHole(isolate)) {
16929         holes--;
16930         undefs--;
16931       } else if (current->IsUndefined(isolate)) {
16932         undefs--;
16933       } else {
16934         continue;
16935       }
16936       // Position i needs to be filled.
16937       while (undefs > i) {
16938         current = elements->get(undefs);
16939         if (current->IsTheHole(isolate)) {
16940           holes--;
16941           undefs--;
16942         } else if (current->IsUndefined(isolate)) {
16943           undefs--;
16944         } else {
16945           elements->set(i, current, write_barrier);
16946           break;
16947         }
16948       }
16949     }
16950     result = undefs;
16951     while (undefs < holes) {
16952       elements->set_undefined(isolate, undefs);
16953       undefs++;
16954     }
16955     while (holes < limit) {
16956       elements->set_the_hole(isolate, holes);
16957       holes++;
16958     }
16959   }
16960 
16961   return isolate->factory()->NewNumberFromUint(result);
16962 }
16963 
16964 namespace {
16965 
CanonicalNumericIndexString(Isolate * isolate,Handle<Object> s,Handle<Object> * index)16966 bool CanonicalNumericIndexString(Isolate* isolate, Handle<Object> s,
16967                                  Handle<Object>* index) {
16968   DCHECK(s->IsString() || s->IsSmi());
16969 
16970   Handle<Object> result;
16971   if (s->IsSmi()) {
16972     result = s;
16973   } else {
16974     result = String::ToNumber(Handle<String>::cast(s));
16975     if (!result->IsMinusZero()) {
16976       Handle<String> str = Object::ToString(isolate, result).ToHandleChecked();
16977       // Avoid treating strings like "2E1" and "20" as the same key.
16978       if (!str->SameValue(*s)) return false;
16979     }
16980   }
16981   *index = result;
16982   return true;
16983 }
16984 
16985 }  // anonymous namespace
16986 
16987 // ES#sec-integer-indexed-exotic-objects-defineownproperty-p-desc
16988 // static
DefineOwnProperty(Isolate * isolate,Handle<JSTypedArray> o,Handle<Object> key,PropertyDescriptor * desc,ShouldThrow should_throw)16989 Maybe<bool> JSTypedArray::DefineOwnProperty(Isolate* isolate,
16990                                             Handle<JSTypedArray> o,
16991                                             Handle<Object> key,
16992                                             PropertyDescriptor* desc,
16993                                             ShouldThrow should_throw) {
16994   // 1. Assert: IsPropertyKey(P) is true.
16995   DCHECK(key->IsName() || key->IsNumber());
16996   // 2. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot.
16997   // 3. If Type(P) is String, then
16998   if (key->IsString() || key->IsSmi()) {
16999     // 3a. Let numericIndex be ! CanonicalNumericIndexString(P)
17000     // 3b. If numericIndex is not undefined, then
17001     Handle<Object> numeric_index;
17002     if (CanonicalNumericIndexString(isolate, key, &numeric_index)) {
17003       // 3b i. If IsInteger(numericIndex) is false, return false.
17004       // 3b ii. If numericIndex = -0, return false.
17005       // 3b iii. If numericIndex < 0, return false.
17006       // FIXME: the standard allows up to 2^53 elements.
17007       uint32_t index;
17008       if (numeric_index->IsMinusZero() || !numeric_index->ToUint32(&index)) {
17009         RETURN_FAILURE(isolate, should_throw,
17010                        NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
17011       }
17012       // 3b iv. Let length be O.[[ArrayLength]].
17013       uint32_t length = o->length()->Number();
17014       // 3b v. If numericIndex ≥ length, return false.
17015       if (index >= length) {
17016         RETURN_FAILURE(isolate, should_throw,
17017                        NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
17018       }
17019       // 3b vi. If IsAccessorDescriptor(Desc) is true, return false.
17020       if (PropertyDescriptor::IsAccessorDescriptor(desc)) {
17021         RETURN_FAILURE(isolate, should_throw,
17022                        NewTypeError(MessageTemplate::kRedefineDisallowed, key));
17023       }
17024       // 3b vii. If Desc has a [[Configurable]] field and if
17025       //         Desc.[[Configurable]] is true, return false.
17026       // 3b viii. If Desc has an [[Enumerable]] field and if Desc.[[Enumerable]]
17027       //          is false, return false.
17028       // 3b ix. If Desc has a [[Writable]] field and if Desc.[[Writable]] is
17029       //        false, return false.
17030       if ((desc->has_configurable() && desc->configurable()) ||
17031           (desc->has_enumerable() && !desc->enumerable()) ||
17032           (desc->has_writable() && !desc->writable())) {
17033         RETURN_FAILURE(isolate, should_throw,
17034                        NewTypeError(MessageTemplate::kRedefineDisallowed, key));
17035       }
17036       // 3b x. If Desc has a [[Value]] field, then
17037       //   3b x 1. Let value be Desc.[[Value]].
17038       //   3b x 2. Return ? IntegerIndexedElementSet(O, numericIndex, value).
17039       if (desc->has_value()) {
17040         if (!desc->has_configurable()) desc->set_configurable(false);
17041         if (!desc->has_enumerable()) desc->set_enumerable(true);
17042         if (!desc->has_writable()) desc->set_writable(true);
17043         Handle<Object> value = desc->value();
17044         RETURN_ON_EXCEPTION_VALUE(isolate,
17045                                   SetOwnElementIgnoreAttributes(
17046                                       o, index, value, desc->ToAttributes()),
17047                                   Nothing<bool>());
17048       }
17049       // 3b xi. Return true.
17050       return Just(true);
17051     }
17052   }
17053   // 4. Return ! OrdinaryDefineOwnProperty(O, P, Desc).
17054   return OrdinaryDefineOwnProperty(isolate, o, key, desc, should_throw);
17055 }
17056 
type()17057 ExternalArrayType JSTypedArray::type() {
17058   switch (elements()->map()->instance_type()) {
17059 #define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype, size)            \
17060     case FIXED_##TYPE##_ARRAY_TYPE:                                           \
17061       return kExternal##Type##Array;
17062 
17063     TYPED_ARRAYS(INSTANCE_TYPE_TO_ARRAY_TYPE)
17064 #undef INSTANCE_TYPE_TO_ARRAY_TYPE
17065 
17066     default:
17067       UNREACHABLE();
17068       return static_cast<ExternalArrayType>(-1);
17069   }
17070 }
17071 
17072 
element_size()17073 size_t JSTypedArray::element_size() {
17074   switch (elements()->map()->instance_type()) {
17075 #define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype, size) \
17076   case FIXED_##TYPE##_ARRAY_TYPE:                                    \
17077     return size;
17078 
17079     TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE)
17080 #undef INSTANCE_TYPE_TO_ELEMENT_SIZE
17081 
17082     default:
17083       UNREACHABLE();
17084       return 0;
17085   }
17086 }
17087 
17088 
InvalidatePropertyCell(Handle<JSGlobalObject> global,Handle<Name> name)17089 void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global,
17090                                             Handle<Name> name) {
17091   DCHECK(!global->HasFastProperties());
17092   auto dictionary = handle(global->global_dictionary());
17093   int entry = dictionary->FindEntry(name);
17094   if (entry == GlobalDictionary::kNotFound) return;
17095   PropertyCell::InvalidateEntry(dictionary, entry);
17096 }
17097 
EnsureEmptyPropertyCell(Handle<JSGlobalObject> global,Handle<Name> name,PropertyCellType cell_type,int * entry_out)17098 Handle<PropertyCell> JSGlobalObject::EnsureEmptyPropertyCell(
17099     Handle<JSGlobalObject> global, Handle<Name> name,
17100     PropertyCellType cell_type, int* entry_out) {
17101   Isolate* isolate = global->GetIsolate();
17102   DCHECK(!global->HasFastProperties());
17103   Handle<GlobalDictionary> dictionary(global->global_dictionary(), isolate);
17104   int entry = dictionary->FindEntry(name);
17105   Handle<PropertyCell> cell;
17106   if (entry != GlobalDictionary::kNotFound) {
17107     if (entry_out) *entry_out = entry;
17108     // This call should be idempotent.
17109     DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
17110     cell = handle(PropertyCell::cast(dictionary->ValueAt(entry)));
17111     PropertyCellType original_cell_type = cell->property_details().cell_type();
17112     DCHECK(original_cell_type == PropertyCellType::kInvalidated ||
17113            original_cell_type == PropertyCellType::kUninitialized);
17114     DCHECK(cell->value()->IsTheHole(isolate));
17115     if (original_cell_type == PropertyCellType::kInvalidated) {
17116       cell = PropertyCell::InvalidateEntry(dictionary, entry);
17117     }
17118     PropertyDetails details(kData, NONE, 0, cell_type);
17119     cell->set_property_details(details);
17120     return cell;
17121   }
17122   cell = isolate->factory()->NewPropertyCell();
17123   PropertyDetails details(kData, NONE, 0, cell_type);
17124   dictionary =
17125       GlobalDictionary::Add(dictionary, name, cell, details, entry_out);
17126   // {*entry_out} is initialized inside GlobalDictionary::Add().
17127   global->set_properties(*dictionary);
17128   return cell;
17129 }
17130 
17131 
17132 // This class is used for looking up two character strings in the string table.
17133 // If we don't have a hit we don't want to waste much time so we unroll the
17134 // string hash calculation loop here for speed.  Doesn't work if the two
17135 // characters form a decimal integer, since such strings have a different hash
17136 // algorithm.
17137 class TwoCharHashTableKey : public HashTableKey {
17138  public:
TwoCharHashTableKey(uint16_t c1,uint16_t c2,uint32_t seed)17139   TwoCharHashTableKey(uint16_t c1, uint16_t c2, uint32_t seed)
17140     : c1_(c1), c2_(c2) {
17141     // Char 1.
17142     uint32_t hash = seed;
17143     hash += c1;
17144     hash += hash << 10;
17145     hash ^= hash >> 6;
17146     // Char 2.
17147     hash += c2;
17148     hash += hash << 10;
17149     hash ^= hash >> 6;
17150     // GetHash.
17151     hash += hash << 3;
17152     hash ^= hash >> 11;
17153     hash += hash << 15;
17154     if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash;
17155     hash_ = hash;
17156 #ifdef DEBUG
17157     // If this assert fails then we failed to reproduce the two-character
17158     // version of the string hashing algorithm above.  One reason could be
17159     // that we were passed two digits as characters, since the hash
17160     // algorithm is different in that case.
17161     uint16_t chars[2] = {c1, c2};
17162     uint32_t check_hash = StringHasher::HashSequentialString(chars, 2, seed);
17163     hash = (hash << String::kHashShift) | String::kIsNotArrayIndexMask;
17164     DCHECK_EQ(static_cast<int32_t>(hash), static_cast<int32_t>(check_hash));
17165 #endif
17166   }
17167 
IsMatch(Object * o)17168   bool IsMatch(Object* o) override {
17169     if (!o->IsString()) return false;
17170     String* other = String::cast(o);
17171     if (other->length() != 2) return false;
17172     if (other->Get(0) != c1_) return false;
17173     return other->Get(1) == c2_;
17174   }
17175 
Hash()17176   uint32_t Hash() override { return hash_; }
HashForObject(Object * key)17177   uint32_t HashForObject(Object* key) override {
17178     if (!key->IsString()) return 0;
17179     return String::cast(key)->Hash();
17180   }
17181 
AsHandle(Isolate * isolate)17182   Handle<Object> AsHandle(Isolate* isolate) override {
17183     // The TwoCharHashTableKey is only used for looking in the string
17184     // table, not for adding to it.
17185     UNREACHABLE();
17186     return MaybeHandle<Object>().ToHandleChecked();
17187   }
17188 
17189  private:
17190   uint16_t c1_;
17191   uint16_t c2_;
17192   uint32_t hash_;
17193 };
17194 
17195 
InternalizeStringIfExists(Isolate * isolate,Handle<String> string)17196 MaybeHandle<String> StringTable::InternalizeStringIfExists(
17197     Isolate* isolate,
17198     Handle<String> string) {
17199   if (string->IsInternalizedString()) {
17200     return string;
17201   }
17202   if (string->IsThinString()) {
17203     return handle(Handle<ThinString>::cast(string)->actual(), isolate);
17204   }
17205   return LookupStringIfExists(isolate, string);
17206 }
17207 
17208 
LookupStringIfExists(Isolate * isolate,Handle<String> string)17209 MaybeHandle<String> StringTable::LookupStringIfExists(
17210     Isolate* isolate,
17211     Handle<String> string) {
17212   Handle<StringTable> string_table = isolate->factory()->string_table();
17213   InternalizedStringKey key(string);
17214   int entry = string_table->FindEntry(&key);
17215   if (entry == kNotFound) {
17216     return MaybeHandle<String>();
17217   } else {
17218     Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
17219     DCHECK(StringShape(*result).IsInternalized());
17220     return result;
17221   }
17222 }
17223 
17224 
LookupTwoCharsStringIfExists(Isolate * isolate,uint16_t c1,uint16_t c2)17225 MaybeHandle<String> StringTable::LookupTwoCharsStringIfExists(
17226     Isolate* isolate,
17227     uint16_t c1,
17228     uint16_t c2) {
17229   Handle<StringTable> string_table = isolate->factory()->string_table();
17230   TwoCharHashTableKey key(c1, c2, isolate->heap()->HashSeed());
17231   int entry = string_table->FindEntry(&key);
17232   if (entry == kNotFound) {
17233     return MaybeHandle<String>();
17234   } else {
17235     Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
17236     DCHECK(StringShape(*result).IsInternalized());
17237     return result;
17238   }
17239 }
17240 
17241 
EnsureCapacityForDeserialization(Isolate * isolate,int expected)17242 void StringTable::EnsureCapacityForDeserialization(Isolate* isolate,
17243                                                    int expected) {
17244   Handle<StringTable> table = isolate->factory()->string_table();
17245   // We need a key instance for the virtual hash function.
17246   InternalizedStringKey dummy_key(isolate->factory()->empty_string());
17247   table = StringTable::EnsureCapacity(table, expected, &dummy_key);
17248   isolate->heap()->SetRootStringTable(*table);
17249 }
17250 
17251 namespace {
17252 
17253 template <class StringClass>
MigrateExternalStringResource(Isolate * isolate,Handle<String> from,Handle<String> to)17254 void MigrateExternalStringResource(Isolate* isolate, Handle<String> from,
17255                                    Handle<String> to) {
17256   Handle<StringClass> cast_from = Handle<StringClass>::cast(from);
17257   Handle<StringClass> cast_to = Handle<StringClass>::cast(to);
17258   const typename StringClass::Resource* to_resource = cast_to->resource();
17259   if (to_resource == nullptr) {
17260     // |to| is a just-created internalized copy of |from|. Migrate the resource.
17261     cast_to->set_resource(cast_from->resource());
17262     // Zap |from|'s resource pointer to reflect the fact that |from| has
17263     // relinquished ownership of its resource.
17264     cast_from->set_resource(nullptr);
17265   } else if (to_resource != cast_from->resource()) {
17266     // |to| already existed and has its own resource. Finalize |from|.
17267     isolate->heap()->FinalizeExternalString(*from);
17268   }
17269 }
17270 
17271 }  // namespace
17272 
LookupString(Isolate * isolate,Handle<String> string)17273 Handle<String> StringTable::LookupString(Isolate* isolate,
17274                                          Handle<String> string) {
17275   if (string->IsThinString()) {
17276     DCHECK(Handle<ThinString>::cast(string)->actual()->IsInternalizedString());
17277     return handle(Handle<ThinString>::cast(string)->actual(), isolate);
17278   }
17279   if (string->IsConsString() && string->IsFlat()) {
17280     string = handle(Handle<ConsString>::cast(string)->first(), isolate);
17281     if (string->IsInternalizedString()) return string;
17282   }
17283 
17284   InternalizedStringKey key(string);
17285   Handle<String> result = LookupKey(isolate, &key);
17286 
17287   if (FLAG_thin_strings) {
17288     if (string->IsExternalString()) {
17289       if (result->IsExternalOneByteString()) {
17290         MigrateExternalStringResource<ExternalOneByteString>(isolate, string,
17291                                                              result);
17292       } else if (result->IsExternalTwoByteString()) {
17293         MigrateExternalStringResource<ExternalTwoByteString>(isolate, string,
17294                                                              result);
17295       } else {
17296         // If the external string is duped into an existing non-external
17297         // internalized string, free its resource (it's about to be rewritten
17298         // into a ThinString below).
17299         isolate->heap()->FinalizeExternalString(*string);
17300       }
17301     }
17302 
17303     // The LookupKey() call above tries to internalize the string in-place.
17304     // In cases where that wasn't possible (e.g. new-space strings), turn them
17305     // into ThinStrings referring to their internalized versions now.
17306     if (!string->IsInternalizedString()) {
17307       DisallowHeapAllocation no_gc;
17308       bool one_byte = result->IsOneByteRepresentation();
17309       Handle<Map> map = one_byte
17310                             ? isolate->factory()->thin_one_byte_string_map()
17311                             : isolate->factory()->thin_string_map();
17312       int old_size = string->Size();
17313       DCHECK(old_size >= ThinString::kSize);
17314       string->synchronized_set_map(*map);
17315       Handle<ThinString> thin = Handle<ThinString>::cast(string);
17316       thin->set_actual(*result);
17317       Address thin_end = thin->address() + ThinString::kSize;
17318       int size_delta = old_size - ThinString::kSize;
17319       if (size_delta != 0) {
17320         Heap* heap = isolate->heap();
17321         heap->CreateFillerObjectAt(thin_end, size_delta,
17322                                    ClearRecordedSlots::kNo);
17323         heap->AdjustLiveBytes(*thin, -size_delta);
17324       }
17325     }
17326   } else {  // !FLAG_thin_strings
17327     if (string->IsConsString()) {
17328       Handle<ConsString> cons = Handle<ConsString>::cast(string);
17329       cons->set_first(*result);
17330       cons->set_second(isolate->heap()->empty_string());
17331     } else if (string->IsSlicedString()) {
17332       STATIC_ASSERT(ConsString::kSize == SlicedString::kSize);
17333       DisallowHeapAllocation no_gc;
17334       bool one_byte = result->IsOneByteRepresentation();
17335       Handle<Map> map = one_byte
17336                             ? isolate->factory()->cons_one_byte_string_map()
17337                             : isolate->factory()->cons_string_map();
17338       string->set_map(*map);
17339       Handle<ConsString> cons = Handle<ConsString>::cast(string);
17340       cons->set_first(*result);
17341       cons->set_second(isolate->heap()->empty_string());
17342     }
17343   }
17344   return result;
17345 }
17346 
17347 
LookupKey(Isolate * isolate,HashTableKey * key)17348 Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) {
17349   Handle<StringTable> table = isolate->factory()->string_table();
17350   int entry = table->FindEntry(key);
17351 
17352   // String already in table.
17353   if (entry != kNotFound) {
17354     return handle(String::cast(table->KeyAt(entry)), isolate);
17355   }
17356 
17357   // Adding new string. Grow table if needed.
17358   table = StringTable::EnsureCapacity(table, 1, key);
17359 
17360   // Create string object.
17361   Handle<Object> string = key->AsHandle(isolate);
17362   // There must be no attempts to internalize strings that could throw
17363   // InvalidStringLength error.
17364   CHECK(!string.is_null());
17365 
17366   // Add the new string and return it along with the string table.
17367   entry = table->FindInsertionEntry(key->Hash());
17368   table->set(EntryToIndex(entry), *string);
17369   table->ElementAdded();
17370 
17371   isolate->heap()->SetRootStringTable(*table);
17372   return Handle<String>::cast(string);
17373 }
17374 
17375 
LookupKeyIfExists(Isolate * isolate,HashTableKey * key)17376 String* StringTable::LookupKeyIfExists(Isolate* isolate, HashTableKey* key) {
17377   Handle<StringTable> table = isolate->factory()->string_table();
17378   int entry = table->FindEntry(key);
17379   if (entry != kNotFound) return String::cast(table->KeyAt(entry));
17380   return NULL;
17381 }
17382 
New(Isolate * isolate)17383 Handle<StringSet> StringSet::New(Isolate* isolate) {
17384   return HashTable::New(isolate, 0);
17385 }
17386 
Add(Handle<StringSet> stringset,Handle<String> name)17387 Handle<StringSet> StringSet::Add(Handle<StringSet> stringset,
17388                                  Handle<String> name) {
17389   if (!stringset->Has(name)) {
17390     stringset = EnsureCapacity(stringset, 1, *name);
17391     uint32_t hash = StringSetShape::Hash(*name);
17392     int entry = stringset->FindInsertionEntry(hash);
17393     stringset->set(EntryToIndex(entry), *name);
17394     stringset->ElementAdded();
17395   }
17396   return stringset;
17397 }
17398 
Has(Handle<String> name)17399 bool StringSet::Has(Handle<String> name) {
17400   return FindEntry(*name) != kNotFound;
17401 }
17402 
Add(Handle<ObjectHashSet> set,Handle<Object> key)17403 Handle<ObjectHashSet> ObjectHashSet::Add(Handle<ObjectHashSet> set,
17404                                          Handle<Object> key) {
17405   Isolate* isolate = set->GetIsolate();
17406   int32_t hash = Object::GetOrCreateHash(isolate, key)->value();
17407 
17408   if (!set->Has(isolate, key, hash)) {
17409     set = EnsureCapacity(set, 1, key);
17410     int entry = set->FindInsertionEntry(hash);
17411     set->set(EntryToIndex(entry), *key);
17412     set->ElementAdded();
17413   }
17414   return set;
17415 }
17416 
Lookup(Handle<String> src,Handle<Context> context,LanguageMode language_mode)17417 Handle<Object> CompilationCacheTable::Lookup(Handle<String> src,
17418                                              Handle<Context> context,
17419                                              LanguageMode language_mode) {
17420   Isolate* isolate = GetIsolate();
17421   Handle<SharedFunctionInfo> shared(context->closure()->shared());
17422   StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17423   int entry = FindEntry(&key);
17424   if (entry == kNotFound) return isolate->factory()->undefined_value();
17425   int index = EntryToIndex(entry);
17426   if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value();
17427   return Handle<Object>(get(index + 1), isolate);
17428 }
17429 
17430 namespace {
17431 
17432 const int kLiteralEntryLength = 2;
17433 const int kLiteralInitialLength = 2;
17434 const int kLiteralContextOffset = 0;
17435 const int kLiteralLiteralsOffset = 1;
17436 
SearchLiteralsMapEntry(CompilationCacheTable * cache,int cache_entry,Context * native_context)17437 int SearchLiteralsMapEntry(CompilationCacheTable* cache, int cache_entry,
17438                            Context* native_context) {
17439   DisallowHeapAllocation no_gc;
17440   DCHECK(native_context->IsNativeContext());
17441   Object* obj = cache->get(cache_entry);
17442 
17443   if (obj->IsFixedArray()) {
17444     FixedArray* literals_map = FixedArray::cast(obj);
17445     int length = literals_map->length();
17446     for (int i = 0; i < length; i += kLiteralEntryLength) {
17447       if (WeakCell::cast(literals_map->get(i + kLiteralContextOffset))
17448               ->value() == native_context) {
17449         return i;
17450       }
17451     }
17452   }
17453   return -1;
17454 }
17455 
AddToLiteralsMap(Handle<CompilationCacheTable> cache,int cache_entry,Handle<Context> native_context,Handle<Cell> literals)17456 void AddToLiteralsMap(Handle<CompilationCacheTable> cache, int cache_entry,
17457                       Handle<Context> native_context, Handle<Cell> literals) {
17458   Isolate* isolate = native_context->GetIsolate();
17459   DCHECK(native_context->IsNativeContext());
17460   STATIC_ASSERT(kLiteralEntryLength == 2);
17461   Handle<FixedArray> new_literals_map;
17462   int entry;
17463 
17464   Object* obj = cache->get(cache_entry);
17465 
17466   if (!obj->IsFixedArray() || FixedArray::cast(obj)->length() == 0) {
17467     new_literals_map =
17468         isolate->factory()->NewFixedArray(kLiteralInitialLength, TENURED);
17469     entry = 0;
17470   } else {
17471     Handle<FixedArray> old_literals_map(FixedArray::cast(obj), isolate);
17472     entry = SearchLiteralsMapEntry(*cache, cache_entry, *native_context);
17473     if (entry >= 0) {
17474       // Just set the code of the entry.
17475       Handle<WeakCell> literals_cell =
17476           isolate->factory()->NewWeakCell(literals);
17477       old_literals_map->set(entry + kLiteralLiteralsOffset, *literals_cell);
17478       return;
17479     }
17480 
17481     // Can we reuse an entry?
17482     DCHECK(entry < 0);
17483     int length = old_literals_map->length();
17484     for (int i = 0; i < length; i += kLiteralEntryLength) {
17485       if (WeakCell::cast(old_literals_map->get(i + kLiteralContextOffset))
17486               ->cleared()) {
17487         new_literals_map = old_literals_map;
17488         entry = i;
17489         break;
17490       }
17491     }
17492 
17493     if (entry < 0) {
17494       // Copy old optimized code map and append one new entry.
17495       new_literals_map = isolate->factory()->CopyFixedArrayAndGrow(
17496           old_literals_map, kLiteralEntryLength, TENURED);
17497       entry = old_literals_map->length();
17498     }
17499   }
17500 
17501   Handle<WeakCell> literals_cell = isolate->factory()->NewWeakCell(literals);
17502   WeakCell* context_cell = native_context->self_weak_cell();
17503 
17504   new_literals_map->set(entry + kLiteralContextOffset, context_cell);
17505   new_literals_map->set(entry + kLiteralLiteralsOffset, *literals_cell);
17506 
17507 #ifdef DEBUG
17508   for (int i = 0; i < new_literals_map->length(); i += kLiteralEntryLength) {
17509     WeakCell* cell =
17510         WeakCell::cast(new_literals_map->get(i + kLiteralContextOffset));
17511     DCHECK(cell->cleared() || cell->value()->IsNativeContext());
17512     cell = WeakCell::cast(new_literals_map->get(i + kLiteralLiteralsOffset));
17513     DCHECK(cell->cleared() || (cell->value()->IsCell()));
17514   }
17515 #endif
17516 
17517   Object* old_literals_map = cache->get(cache_entry);
17518   if (old_literals_map != *new_literals_map) {
17519     cache->set(cache_entry, *new_literals_map);
17520   }
17521 }
17522 
SearchLiteralsMap(CompilationCacheTable * cache,int cache_entry,Context * native_context)17523 Cell* SearchLiteralsMap(CompilationCacheTable* cache, int cache_entry,
17524                         Context* native_context) {
17525   Cell* result = nullptr;
17526   int entry = SearchLiteralsMapEntry(cache, cache_entry, native_context);
17527   if (entry >= 0) {
17528     FixedArray* literals_map = FixedArray::cast(cache->get(cache_entry));
17529     DCHECK_LE(entry + kLiteralEntryLength, literals_map->length());
17530     WeakCell* cell =
17531         WeakCell::cast(literals_map->get(entry + kLiteralLiteralsOffset));
17532 
17533     result = cell->cleared() ? nullptr : Cell::cast(cell->value());
17534   }
17535   DCHECK(result == nullptr || result->IsCell());
17536   return result;
17537 }
17538 
17539 }  // namespace
17540 
LookupScript(Handle<String> src,Handle<Context> context,LanguageMode language_mode)17541 InfoVectorPair CompilationCacheTable::LookupScript(Handle<String> src,
17542                                                    Handle<Context> context,
17543                                                    LanguageMode language_mode) {
17544   InfoVectorPair empty_result;
17545   Handle<SharedFunctionInfo> shared(context->closure()->shared());
17546   StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17547   int entry = FindEntry(&key);
17548   if (entry == kNotFound) return empty_result;
17549   int index = EntryToIndex(entry);
17550   if (!get(index)->IsFixedArray()) return empty_result;
17551   Object* obj = get(index + 1);
17552   if (obj->IsSharedFunctionInfo()) {
17553     Cell* literals =
17554         SearchLiteralsMap(this, index + 2, context->native_context());
17555     return InfoVectorPair(SharedFunctionInfo::cast(obj), literals);
17556   }
17557   return empty_result;
17558 }
17559 
LookupEval(Handle<String> src,Handle<SharedFunctionInfo> outer_info,Handle<Context> native_context,LanguageMode language_mode,int position)17560 InfoVectorPair CompilationCacheTable::LookupEval(
17561     Handle<String> src, Handle<SharedFunctionInfo> outer_info,
17562     Handle<Context> native_context, LanguageMode language_mode, int position) {
17563   InfoVectorPair empty_result;
17564   StringSharedKey key(src, outer_info, language_mode, position);
17565   int entry = FindEntry(&key);
17566   if (entry == kNotFound) return empty_result;
17567   int index = EntryToIndex(entry);
17568   if (!get(index)->IsFixedArray()) return empty_result;
17569   Object* obj = get(EntryToIndex(entry) + 1);
17570   if (obj->IsSharedFunctionInfo()) {
17571     Cell* literals =
17572         SearchLiteralsMap(this, EntryToIndex(entry) + 2, *native_context);
17573     return InfoVectorPair(SharedFunctionInfo::cast(obj), literals);
17574   }
17575   return empty_result;
17576 }
17577 
LookupRegExp(Handle<String> src,JSRegExp::Flags flags)17578 Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src,
17579                                                    JSRegExp::Flags flags) {
17580   Isolate* isolate = GetIsolate();
17581   DisallowHeapAllocation no_allocation;
17582   RegExpKey key(src, flags);
17583   int entry = FindEntry(&key);
17584   if (entry == kNotFound) return isolate->factory()->undefined_value();
17585   return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
17586 }
17587 
17588 
Put(Handle<CompilationCacheTable> cache,Handle<String> src,Handle<Context> context,LanguageMode language_mode,Handle<Object> value)17589 Handle<CompilationCacheTable> CompilationCacheTable::Put(
17590     Handle<CompilationCacheTable> cache, Handle<String> src,
17591     Handle<Context> context, LanguageMode language_mode, Handle<Object> value) {
17592   Isolate* isolate = cache->GetIsolate();
17593   Handle<SharedFunctionInfo> shared(context->closure()->shared());
17594   StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17595   Handle<Object> k = key.AsHandle(isolate);
17596   cache = EnsureCapacity(cache, 1, &key);
17597   int entry = cache->FindInsertionEntry(key.Hash());
17598   cache->set(EntryToIndex(entry), *k);
17599   cache->set(EntryToIndex(entry) + 1, *value);
17600   cache->ElementAdded();
17601   return cache;
17602 }
17603 
PutScript(Handle<CompilationCacheTable> cache,Handle<String> src,Handle<Context> context,LanguageMode language_mode,Handle<SharedFunctionInfo> value,Handle<Cell> literals)17604 Handle<CompilationCacheTable> CompilationCacheTable::PutScript(
17605     Handle<CompilationCacheTable> cache, Handle<String> src,
17606     Handle<Context> context, LanguageMode language_mode,
17607     Handle<SharedFunctionInfo> value, Handle<Cell> literals) {
17608   Isolate* isolate = cache->GetIsolate();
17609   Handle<SharedFunctionInfo> shared(context->closure()->shared());
17610   Handle<Context> native_context(context->native_context());
17611   StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17612   Handle<Object> k = key.AsHandle(isolate);
17613   cache = EnsureCapacity(cache, 1, &key);
17614   int entry = cache->FindInsertionEntry(key.Hash());
17615   cache->set(EntryToIndex(entry), *k);
17616   cache->set(EntryToIndex(entry) + 1, *value);
17617   AddToLiteralsMap(cache, EntryToIndex(entry) + 2, native_context, literals);
17618   cache->ElementAdded();
17619   return cache;
17620 }
17621 
PutEval(Handle<CompilationCacheTable> cache,Handle<String> src,Handle<SharedFunctionInfo> outer_info,Handle<SharedFunctionInfo> value,Handle<Context> native_context,Handle<Cell> literals,int position)17622 Handle<CompilationCacheTable> CompilationCacheTable::PutEval(
17623     Handle<CompilationCacheTable> cache, Handle<String> src,
17624     Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value,
17625     Handle<Context> native_context, Handle<Cell> literals, int position) {
17626   Isolate* isolate = cache->GetIsolate();
17627   StringSharedKey key(src, outer_info, value->language_mode(), position);
17628   {
17629     Handle<Object> k = key.AsHandle(isolate);
17630     int entry = cache->FindEntry(&key);
17631     if (entry != kNotFound) {
17632       cache->set(EntryToIndex(entry), *k);
17633       cache->set(EntryToIndex(entry) + 1, *value);
17634       // AddToLiteralsMap may allocate a new sub-array to live in the entry,
17635       // but it won't change the cache array. Therefore EntryToIndex and
17636       // entry remains correct.
17637       AddToLiteralsMap(cache, EntryToIndex(entry) + 2, native_context,
17638                        literals);
17639       return cache;
17640     }
17641   }
17642 
17643   cache = EnsureCapacity(cache, 1, &key);
17644   int entry = cache->FindInsertionEntry(key.Hash());
17645   Handle<Object> k =
17646       isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
17647   cache->set(EntryToIndex(entry), *k);
17648   cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
17649   cache->ElementAdded();
17650   return cache;
17651 }
17652 
17653 
PutRegExp(Handle<CompilationCacheTable> cache,Handle<String> src,JSRegExp::Flags flags,Handle<FixedArray> value)17654 Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp(
17655       Handle<CompilationCacheTable> cache, Handle<String> src,
17656       JSRegExp::Flags flags, Handle<FixedArray> value) {
17657   RegExpKey key(src, flags);
17658   cache = EnsureCapacity(cache, 1, &key);
17659   int entry = cache->FindInsertionEntry(key.Hash());
17660   // We store the value in the key slot, and compare the search key
17661   // to the stored value with a custon IsMatch function during lookups.
17662   cache->set(EntryToIndex(entry), *value);
17663   cache->set(EntryToIndex(entry) + 1, *value);
17664   cache->ElementAdded();
17665   return cache;
17666 }
17667 
17668 
Age()17669 void CompilationCacheTable::Age() {
17670   DisallowHeapAllocation no_allocation;
17671   Object* the_hole_value = GetHeap()->the_hole_value();
17672   for (int entry = 0, size = Capacity(); entry < size; entry++) {
17673     int entry_index = EntryToIndex(entry);
17674     int value_index = entry_index + 1;
17675 
17676     if (get(entry_index)->IsNumber()) {
17677       Smi* count = Smi::cast(get(value_index));
17678       count = Smi::FromInt(count->value() - 1);
17679       if (count->value() == 0) {
17680         NoWriteBarrierSet(this, entry_index, the_hole_value);
17681         NoWriteBarrierSet(this, value_index, the_hole_value);
17682         ElementRemoved();
17683       } else {
17684         NoWriteBarrierSet(this, value_index, count);
17685       }
17686     } else if (get(entry_index)->IsFixedArray()) {
17687       SharedFunctionInfo* info = SharedFunctionInfo::cast(get(value_index));
17688       bool is_old =
17689           info->IsInterpreted()
17690               ? info->bytecode_array()->IsOld()
17691               : info->code()->kind() != Code::FUNCTION || info->code()->IsOld();
17692       if (is_old) {
17693         for (int i = 0; i < kEntrySize; i++) {
17694           NoWriteBarrierSet(this, entry_index + i, the_hole_value);
17695         }
17696         ElementRemoved();
17697       }
17698     }
17699   }
17700 }
17701 
17702 
Remove(Object * value)17703 void CompilationCacheTable::Remove(Object* value) {
17704   DisallowHeapAllocation no_allocation;
17705   Object* the_hole_value = GetHeap()->the_hole_value();
17706   for (int entry = 0, size = Capacity(); entry < size; entry++) {
17707     int entry_index = EntryToIndex(entry);
17708     int value_index = entry_index + 1;
17709     if (get(value_index) == value) {
17710       for (int i = 0; i < kEntrySize; i++) {
17711         NoWriteBarrierSet(this, entry_index + i, the_hole_value);
17712       }
17713       ElementRemoved();
17714     }
17715   }
17716   return;
17717 }
17718 
17719 template <typename Derived, typename Shape, typename Key>
New(Isolate * isolate,int at_least_space_for,PretenureFlag pretenure,MinimumCapacity capacity_option)17720 Handle<Derived> Dictionary<Derived, Shape, Key>::New(
17721     Isolate* isolate, int at_least_space_for, PretenureFlag pretenure,
17722     MinimumCapacity capacity_option) {
17723   DCHECK(0 <= at_least_space_for);
17724   Handle<Derived> dict = DerivedHashTable::New(isolate, at_least_space_for,
17725                                                capacity_option, pretenure);
17726 
17727   // Initialize the next enumeration index.
17728   dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
17729   return dict;
17730 }
17731 
17732 template <typename Derived, typename Shape, typename Key>
NewEmpty(Isolate * isolate,PretenureFlag pretenure)17733 Handle<Derived> Dictionary<Derived, Shape, Key>::NewEmpty(
17734     Isolate* isolate, PretenureFlag pretenure) {
17735   Handle<Derived> dict = DerivedHashTable::New(isolate, 1, pretenure);
17736   // Attempt to add one element to the empty dictionary must cause reallocation.
17737   DCHECK(!dict->HasSufficientCapacityToAdd(1));
17738   // Initialize the next enumeration index.
17739   dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
17740   return dict;
17741 }
17742 
17743 template <typename Derived, typename Shape, typename Key>
17744 Handle<FixedArray>
GenerateNewEnumerationIndices(Handle<Derived> dictionary)17745 Dictionary<Derived, Shape, Key>::GenerateNewEnumerationIndices(
17746     Handle<Derived> dictionary) {
17747   int length = dictionary->NumberOfElements();
17748 
17749   Handle<FixedArray> iteration_order = IterationIndices(dictionary);
17750   DCHECK(iteration_order->length() == length);
17751 
17752   // Iterate over the dictionary using the enumeration order and update
17753   // the dictionary with new enumeration indices.
17754   for (int i = 0; i < length; i++) {
17755     int index = Smi::cast(iteration_order->get(i))->value();
17756     DCHECK(dictionary->IsKey(dictionary->KeyAt(index)));
17757 
17758     int enum_index = PropertyDetails::kInitialIndex + i;
17759 
17760     PropertyDetails details = dictionary->DetailsAt(index);
17761     PropertyDetails new_details = details.set_index(enum_index);
17762     dictionary->DetailsAtPut(index, new_details);
17763   }
17764 
17765   // Set the next enumeration index.
17766   dictionary->SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
17767   return iteration_order;
17768 }
17769 
17770 
17771 template <typename Derived, typename Shape, typename Key>
SetRequiresCopyOnCapacityChange()17772 void Dictionary<Derived, Shape, Key>::SetRequiresCopyOnCapacityChange() {
17773   DCHECK_EQ(0, DerivedHashTable::NumberOfElements());
17774   DCHECK_EQ(0, DerivedHashTable::NumberOfDeletedElements());
17775   // Make sure that HashTable::EnsureCapacity will create a copy.
17776   DerivedHashTable::SetNumberOfDeletedElements(DerivedHashTable::Capacity());
17777   DCHECK(!DerivedHashTable::HasSufficientCapacityToAdd(1));
17778 }
17779 
17780 
17781 template <typename Derived, typename Shape, typename Key>
EnsureCapacity(Handle<Derived> dictionary,int n,Key key)17782 Handle<Derived> Dictionary<Derived, Shape, Key>::EnsureCapacity(
17783     Handle<Derived> dictionary, int n, Key key) {
17784   // Check whether there are enough enumeration indices to add n elements.
17785   if (Shape::kIsEnumerable &&
17786       !PropertyDetails::IsValidIndex(dictionary->NextEnumerationIndex() + n)) {
17787     // If not, we generate new indices for the properties.
17788     GenerateNewEnumerationIndices(dictionary);
17789   }
17790   return DerivedHashTable::EnsureCapacity(dictionary, n, key);
17791 }
17792 
17793 
17794 template <typename Derived, typename Shape, typename Key>
DeleteProperty(Handle<Derived> dictionary,int entry)17795 Handle<Object> Dictionary<Derived, Shape, Key>::DeleteProperty(
17796     Handle<Derived> dictionary, int entry) {
17797   Factory* factory = dictionary->GetIsolate()->factory();
17798   PropertyDetails details = dictionary->DetailsAt(entry);
17799   if (!details.IsConfigurable()) return factory->false_value();
17800 
17801   dictionary->SetEntry(
17802       entry, factory->the_hole_value(), factory->the_hole_value());
17803   dictionary->ElementRemoved();
17804   return factory->true_value();
17805 }
17806 
17807 
17808 template<typename Derived, typename Shape, typename Key>
AtPut(Handle<Derived> dictionary,Key key,Handle<Object> value)17809 Handle<Derived> Dictionary<Derived, Shape, Key>::AtPut(
17810     Handle<Derived> dictionary, Key key, Handle<Object> value) {
17811   int entry = dictionary->FindEntry(key);
17812 
17813   // If the entry is present set the value;
17814   if (entry != Dictionary::kNotFound) {
17815     dictionary->ValueAtPut(entry, *value);
17816     return dictionary;
17817   }
17818 
17819   // Check whether the dictionary should be extended.
17820   dictionary = EnsureCapacity(dictionary, 1, key);
17821 #ifdef DEBUG
17822   USE(Shape::AsHandle(dictionary->GetIsolate(), key));
17823 #endif
17824   PropertyDetails details = PropertyDetails::Empty();
17825 
17826   AddEntry(dictionary, key, value, details, dictionary->Hash(key));
17827   return dictionary;
17828 }
17829 
17830 template <typename Derived, typename Shape, typename Key>
Add(Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details,int * entry_out)17831 Handle<Derived> Dictionary<Derived, Shape, Key>::Add(Handle<Derived> dictionary,
17832                                                      Key key,
17833                                                      Handle<Object> value,
17834                                                      PropertyDetails details,
17835                                                      int* entry_out) {
17836   // Valdate key is absent.
17837   SLOW_DCHECK((dictionary->FindEntry(key) == Dictionary::kNotFound));
17838   // Check whether the dictionary should be extended.
17839   dictionary = EnsureCapacity(dictionary, 1, key);
17840 
17841   int entry = AddEntry(dictionary, key, value, details, dictionary->Hash(key));
17842   if (entry_out) *entry_out = entry;
17843   return dictionary;
17844 }
17845 
17846 // Add a key, value pair to the dictionary. Returns entry value.
17847 template <typename Derived, typename Shape, typename Key>
AddEntry(Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details,uint32_t hash)17848 int Dictionary<Derived, Shape, Key>::AddEntry(Handle<Derived> dictionary,
17849                                               Key key, Handle<Object> value,
17850                                               PropertyDetails details,
17851                                               uint32_t hash) {
17852   // Compute the key object.
17853   Handle<Object> k = Shape::AsHandle(dictionary->GetIsolate(), key);
17854 
17855   uint32_t entry = dictionary->FindInsertionEntry(hash);
17856   // Insert element at empty or deleted entry
17857   if (details.dictionary_index() == 0 && Shape::kIsEnumerable) {
17858     // Assign an enumeration index to the property and update
17859     // SetNextEnumerationIndex.
17860     int index = dictionary->NextEnumerationIndex();
17861     details = details.set_index(index);
17862     dictionary->SetNextEnumerationIndex(index + 1);
17863   }
17864   dictionary->SetEntry(entry, k, value, details);
17865   DCHECK((dictionary->KeyAt(entry)->IsNumber() ||
17866           dictionary->KeyAt(entry)->IsName()));
17867   dictionary->ElementAdded();
17868   return entry;
17869 }
17870 
HasComplexElements()17871 bool SeededNumberDictionary::HasComplexElements() {
17872   if (!requires_slow_elements()) return false;
17873   Isolate* isolate = this->GetIsolate();
17874   int capacity = this->Capacity();
17875   for (int i = 0; i < capacity; i++) {
17876     Object* k = this->KeyAt(i);
17877     if (!this->IsKey(isolate, k)) continue;
17878     DCHECK(!IsDeleted(i));
17879     PropertyDetails details = this->DetailsAt(i);
17880     if (details.kind() == kAccessor) return true;
17881     PropertyAttributes attr = details.attributes();
17882     if (attr & ALL_ATTRIBUTES_MASK) return true;
17883   }
17884   return false;
17885 }
17886 
UpdateMaxNumberKey(uint32_t key,Handle<JSObject> dictionary_holder)17887 void SeededNumberDictionary::UpdateMaxNumberKey(
17888     uint32_t key, Handle<JSObject> dictionary_holder) {
17889   DisallowHeapAllocation no_allocation;
17890   // If the dictionary requires slow elements an element has already
17891   // been added at a high index.
17892   if (requires_slow_elements()) return;
17893   // Check if this index is high enough that we should require slow
17894   // elements.
17895   if (key > kRequiresSlowElementsLimit) {
17896     if (!dictionary_holder.is_null()) {
17897       dictionary_holder->RequireSlowElements(this);
17898     }
17899     set_requires_slow_elements();
17900     return;
17901   }
17902   // Update max key value.
17903   Object* max_index_object = get(kMaxNumberKeyIndex);
17904   if (!max_index_object->IsSmi() || max_number_key() < key) {
17905     FixedArray::set(kMaxNumberKeyIndex,
17906                     Smi::FromInt(key << kRequiresSlowElementsTagSize));
17907   }
17908 }
17909 
AddNumberEntry(Handle<SeededNumberDictionary> dictionary,uint32_t key,Handle<Object> value,PropertyDetails details,Handle<JSObject> dictionary_holder)17910 Handle<SeededNumberDictionary> SeededNumberDictionary::AddNumberEntry(
17911     Handle<SeededNumberDictionary> dictionary, uint32_t key,
17912     Handle<Object> value, PropertyDetails details,
17913     Handle<JSObject> dictionary_holder) {
17914   dictionary->UpdateMaxNumberKey(key, dictionary_holder);
17915   SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
17916   return Add(dictionary, key, value, details);
17917 }
17918 
17919 
AddNumberEntry(Handle<UnseededNumberDictionary> dictionary,uint32_t key,Handle<Object> value)17920 Handle<UnseededNumberDictionary> UnseededNumberDictionary::AddNumberEntry(
17921     Handle<UnseededNumberDictionary> dictionary,
17922     uint32_t key,
17923     Handle<Object> value) {
17924   SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
17925   return Add(dictionary, key, value, PropertyDetails::Empty());
17926 }
17927 
DeleteKey(Handle<UnseededNumberDictionary> dictionary,uint32_t key)17928 Handle<UnseededNumberDictionary> UnseededNumberDictionary::DeleteKey(
17929     Handle<UnseededNumberDictionary> dictionary, uint32_t key) {
17930   int entry = dictionary->FindEntry(key);
17931   if (entry == kNotFound) return dictionary;
17932 
17933   Factory* factory = dictionary->GetIsolate()->factory();
17934   dictionary->SetEntry(entry, factory->the_hole_value(),
17935                        factory->the_hole_value());
17936   dictionary->ElementRemoved();
17937   return dictionary->Shrink(dictionary, key);
17938 }
17939 
AtNumberPut(Handle<SeededNumberDictionary> dictionary,uint32_t key,Handle<Object> value,Handle<JSObject> dictionary_holder)17940 Handle<SeededNumberDictionary> SeededNumberDictionary::AtNumberPut(
17941     Handle<SeededNumberDictionary> dictionary, uint32_t key,
17942     Handle<Object> value, Handle<JSObject> dictionary_holder) {
17943   dictionary->UpdateMaxNumberKey(key, dictionary_holder);
17944   return AtPut(dictionary, key, value);
17945 }
17946 
17947 
AtNumberPut(Handle<UnseededNumberDictionary> dictionary,uint32_t key,Handle<Object> value)17948 Handle<UnseededNumberDictionary> UnseededNumberDictionary::AtNumberPut(
17949     Handle<UnseededNumberDictionary> dictionary,
17950     uint32_t key,
17951     Handle<Object> value) {
17952   return AtPut(dictionary, key, value);
17953 }
17954 
Set(Handle<SeededNumberDictionary> dictionary,uint32_t key,Handle<Object> value,PropertyDetails details,Handle<JSObject> dictionary_holder)17955 Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
17956     Handle<SeededNumberDictionary> dictionary, uint32_t key,
17957     Handle<Object> value, PropertyDetails details,
17958     Handle<JSObject> dictionary_holder) {
17959   int entry = dictionary->FindEntry(key);
17960   if (entry == kNotFound) {
17961     return AddNumberEntry(dictionary, key, value, details, dictionary_holder);
17962   }
17963   // Preserve enumeration index.
17964   details = details.set_index(dictionary->DetailsAt(entry).dictionary_index());
17965   Handle<Object> object_key =
17966       SeededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
17967   dictionary->SetEntry(entry, object_key, value, details);
17968   return dictionary;
17969 }
17970 
17971 
Set(Handle<UnseededNumberDictionary> dictionary,uint32_t key,Handle<Object> value)17972 Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
17973     Handle<UnseededNumberDictionary> dictionary,
17974     uint32_t key,
17975     Handle<Object> value) {
17976   int entry = dictionary->FindEntry(key);
17977   if (entry == kNotFound) return AddNumberEntry(dictionary, key, value);
17978   Handle<Object> object_key =
17979       UnseededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
17980   dictionary->SetEntry(entry, object_key, value);
17981   return dictionary;
17982 }
17983 
17984 
17985 template <typename Derived, typename Shape, typename Key>
NumberOfElementsFilterAttributes(PropertyFilter filter)17986 int Dictionary<Derived, Shape, Key>::NumberOfElementsFilterAttributes(
17987     PropertyFilter filter) {
17988   Isolate* isolate = this->GetIsolate();
17989   int capacity = this->Capacity();
17990   int result = 0;
17991   for (int i = 0; i < capacity; i++) {
17992     Object* k = this->KeyAt(i);
17993     if (this->IsKey(isolate, k) && !k->FilterKey(filter)) {
17994       if (this->IsDeleted(i)) continue;
17995       PropertyDetails details = this->DetailsAt(i);
17996       PropertyAttributes attr = details.attributes();
17997       if ((attr & filter) == 0) result++;
17998     }
17999   }
18000   return result;
18001 }
18002 
18003 
18004 template <typename Dictionary>
18005 struct EnumIndexComparator {
EnumIndexComparatorv8::internal::EnumIndexComparator18006   explicit EnumIndexComparator(Dictionary* dict) : dict(dict) {}
operator ()v8::internal::EnumIndexComparator18007   bool operator() (Smi* a, Smi* b) {
18008     PropertyDetails da(dict->DetailsAt(a->value()));
18009     PropertyDetails db(dict->DetailsAt(b->value()));
18010     return da.dictionary_index() < db.dictionary_index();
18011   }
18012   Dictionary* dict;
18013 };
18014 
18015 template <typename Derived, typename Shape, typename Key>
CopyEnumKeysTo(Handle<Dictionary<Derived,Shape,Key>> dictionary,Handle<FixedArray> storage,KeyCollectionMode mode,KeyAccumulator * accumulator)18016 void Dictionary<Derived, Shape, Key>::CopyEnumKeysTo(
18017     Handle<Dictionary<Derived, Shape, Key>> dictionary,
18018     Handle<FixedArray> storage, KeyCollectionMode mode,
18019     KeyAccumulator* accumulator) {
18020   DCHECK_IMPLIES(mode != KeyCollectionMode::kOwnOnly, accumulator != nullptr);
18021   Isolate* isolate = dictionary->GetIsolate();
18022   int length = storage->length();
18023   int capacity = dictionary->Capacity();
18024   int properties = 0;
18025   for (int i = 0; i < capacity; i++) {
18026     Object* key = dictionary->KeyAt(i);
18027     bool is_shadowing_key = false;
18028     if (!dictionary->IsKey(isolate, key)) continue;
18029     if (key->IsSymbol()) continue;
18030     PropertyDetails details = dictionary->DetailsAt(i);
18031     if (details.IsDontEnum()) {
18032       if (mode == KeyCollectionMode::kIncludePrototypes) {
18033         is_shadowing_key = true;
18034       } else {
18035         continue;
18036       }
18037     }
18038     if (dictionary->IsDeleted(i)) continue;
18039     if (is_shadowing_key) {
18040       accumulator->AddShadowingKey(key);
18041       continue;
18042     } else {
18043       storage->set(properties, Smi::FromInt(i));
18044     }
18045     properties++;
18046     if (mode == KeyCollectionMode::kOwnOnly && properties == length) break;
18047   }
18048 
18049   CHECK_EQ(length, properties);
18050   DisallowHeapAllocation no_gc;
18051   Dictionary<Derived, Shape, Key>* raw_dictionary = *dictionary;
18052   FixedArray* raw_storage = *storage;
18053   EnumIndexComparator<Derived> cmp(static_cast<Derived*>(*dictionary));
18054   Smi** start = reinterpret_cast<Smi**>(storage->GetFirstElementAddress());
18055   std::sort(start, start + length, cmp);
18056   for (int i = 0; i < length; i++) {
18057     int index = Smi::cast(raw_storage->get(i))->value();
18058     raw_storage->set(i, raw_dictionary->KeyAt(index));
18059   }
18060 }
18061 
18062 template <typename Derived, typename Shape, typename Key>
IterationIndices(Handle<Dictionary<Derived,Shape,Key>> dictionary)18063 Handle<FixedArray> Dictionary<Derived, Shape, Key>::IterationIndices(
18064     Handle<Dictionary<Derived, Shape, Key>> dictionary) {
18065   Isolate* isolate = dictionary->GetIsolate();
18066   int capacity = dictionary->Capacity();
18067   int length = dictionary->NumberOfElements();
18068   Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
18069   int array_size = 0;
18070   {
18071     DisallowHeapAllocation no_gc;
18072     Dictionary<Derived, Shape, Key>* raw_dict = *dictionary;
18073     for (int i = 0; i < capacity; i++) {
18074       Object* k = raw_dict->KeyAt(i);
18075       if (!raw_dict->IsKey(isolate, k)) continue;
18076       if (raw_dict->IsDeleted(i)) continue;
18077       array->set(array_size++, Smi::FromInt(i));
18078     }
18079 
18080     DCHECK_EQ(array_size, length);
18081 
18082     EnumIndexComparator<Derived> cmp(static_cast<Derived*>(raw_dict));
18083     Smi** start = reinterpret_cast<Smi**>(array->GetFirstElementAddress());
18084     std::sort(start, start + array_size, cmp);
18085   }
18086   array->Shrink(array_size);
18087   return array;
18088 }
18089 
18090 template <typename Derived, typename Shape, typename Key>
CollectKeysTo(Handle<Dictionary<Derived,Shape,Key>> dictionary,KeyAccumulator * keys)18091 void Dictionary<Derived, Shape, Key>::CollectKeysTo(
18092     Handle<Dictionary<Derived, Shape, Key>> dictionary, KeyAccumulator* keys) {
18093   Isolate* isolate = keys->isolate();
18094   int capacity = dictionary->Capacity();
18095   Handle<FixedArray> array =
18096       isolate->factory()->NewFixedArray(dictionary->NumberOfElements());
18097   int array_size = 0;
18098   PropertyFilter filter = keys->filter();
18099   {
18100     DisallowHeapAllocation no_gc;
18101     Dictionary<Derived, Shape, Key>* raw_dict = *dictionary;
18102     for (int i = 0; i < capacity; i++) {
18103       Object* k = raw_dict->KeyAt(i);
18104       if (!raw_dict->IsKey(isolate, k) || k->FilterKey(filter)) continue;
18105       if (raw_dict->IsDeleted(i)) continue;
18106       PropertyDetails details = raw_dict->DetailsAt(i);
18107       if ((details.attributes() & filter) != 0) {
18108         keys->AddShadowingKey(k);
18109         continue;
18110       }
18111       if (filter & ONLY_ALL_CAN_READ) {
18112         if (details.kind() != kAccessor) continue;
18113         Object* accessors = raw_dict->ValueAt(i);
18114         if (accessors->IsPropertyCell()) {
18115           accessors = PropertyCell::cast(accessors)->value();
18116         }
18117         if (!accessors->IsAccessorInfo()) continue;
18118         if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
18119       }
18120       array->set(array_size++, Smi::FromInt(i));
18121     }
18122 
18123     EnumIndexComparator<Derived> cmp(static_cast<Derived*>(raw_dict));
18124     Smi** start = reinterpret_cast<Smi**>(array->GetFirstElementAddress());
18125     std::sort(start, start + array_size, cmp);
18126   }
18127 
18128   bool has_seen_symbol = false;
18129   for (int i = 0; i < array_size; i++) {
18130     int index = Smi::cast(array->get(i))->value();
18131     Object* key = dictionary->KeyAt(index);
18132     if (key->IsSymbol()) {
18133       has_seen_symbol = true;
18134       continue;
18135     }
18136     keys->AddKey(key, DO_NOT_CONVERT);
18137   }
18138   if (has_seen_symbol) {
18139     for (int i = 0; i < array_size; i++) {
18140       int index = Smi::cast(array->get(i))->value();
18141       Object* key = dictionary->KeyAt(index);
18142       if (!key->IsSymbol()) continue;
18143       keys->AddKey(key, DO_NOT_CONVERT);
18144     }
18145   }
18146 }
18147 
18148 
18149 // Backwards lookup (slow).
18150 template<typename Derived, typename Shape, typename Key>
SlowReverseLookup(Object * value)18151 Object* Dictionary<Derived, Shape, Key>::SlowReverseLookup(Object* value) {
18152   Isolate* isolate = this->GetIsolate();
18153   int capacity = this->Capacity();
18154   for (int i = 0; i < capacity; i++) {
18155     Object* k = this->KeyAt(i);
18156     if (!this->IsKey(isolate, k)) continue;
18157     Object* e = this->ValueAt(i);
18158     // TODO(dcarney): this should be templatized.
18159     if (e->IsPropertyCell()) {
18160       e = PropertyCell::cast(e)->value();
18161     }
18162     if (e == value) return k;
18163   }
18164   return isolate->heap()->undefined_value();
18165 }
18166 
18167 
Lookup(Isolate * isolate,Handle<Object> key,int32_t hash)18168 Object* ObjectHashTable::Lookup(Isolate* isolate, Handle<Object> key,
18169                                 int32_t hash) {
18170   DisallowHeapAllocation no_gc;
18171   DCHECK(IsKey(isolate, *key));
18172 
18173   int entry = FindEntry(isolate, key, hash);
18174   if (entry == kNotFound) return isolate->heap()->the_hole_value();
18175   return get(EntryToIndex(entry) + 1);
18176 }
18177 
18178 
Lookup(Handle<Object> key)18179 Object* ObjectHashTable::Lookup(Handle<Object> key) {
18180   DisallowHeapAllocation no_gc;
18181 
18182   Isolate* isolate = GetIsolate();
18183   DCHECK(IsKey(isolate, *key));
18184 
18185   // If the object does not have an identity hash, it was never used as a key.
18186   Object* hash = key->GetHash();
18187   if (hash->IsUndefined(isolate)) {
18188     return isolate->heap()->the_hole_value();
18189   }
18190   return Lookup(isolate, key, Smi::cast(hash)->value());
18191 }
18192 
ValueAt(int entry)18193 Object* ObjectHashTable::ValueAt(int entry) {
18194   return get(EntryToValueIndex(entry));
18195 }
18196 
Lookup(Handle<Object> key,int32_t hash)18197 Object* ObjectHashTable::Lookup(Handle<Object> key, int32_t hash) {
18198   return Lookup(GetIsolate(), key, hash);
18199 }
18200 
18201 
Put(Handle<ObjectHashTable> table,Handle<Object> key,Handle<Object> value)18202 Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
18203                                              Handle<Object> key,
18204                                              Handle<Object> value) {
18205   Isolate* isolate = table->GetIsolate();
18206   DCHECK(table->IsKey(isolate, *key));
18207   DCHECK(!value->IsTheHole(isolate));
18208 
18209   // Make sure the key object has an identity hash code.
18210   int32_t hash = Object::GetOrCreateHash(isolate, key)->value();
18211 
18212   return Put(table, key, value, hash);
18213 }
18214 
18215 
Put(Handle<ObjectHashTable> table,Handle<Object> key,Handle<Object> value,int32_t hash)18216 Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
18217                                              Handle<Object> key,
18218                                              Handle<Object> value,
18219                                              int32_t hash) {
18220   Isolate* isolate = table->GetIsolate();
18221   DCHECK(table->IsKey(isolate, *key));
18222   DCHECK(!value->IsTheHole(isolate));
18223 
18224   int entry = table->FindEntry(isolate, key, hash);
18225 
18226   // Key is already in table, just overwrite value.
18227   if (entry != kNotFound) {
18228     table->set(EntryToIndex(entry) + 1, *value);
18229     return table;
18230   }
18231 
18232   // Rehash if more than 33% of the entries are deleted entries.
18233   // TODO(jochen): Consider to shrink the fixed array in place.
18234   if ((table->NumberOfDeletedElements() << 1) > table->NumberOfElements()) {
18235     table->Rehash(isolate->factory()->undefined_value());
18236   }
18237   // If we're out of luck, we didn't get a GC recently, and so rehashing
18238   // isn't enough to avoid a crash.
18239   if (!table->HasSufficientCapacityToAdd(1)) {
18240     int nof = table->NumberOfElements() + 1;
18241     int capacity = ObjectHashTable::ComputeCapacity(nof * 2);
18242     if (capacity > ObjectHashTable::kMaxCapacity) {
18243       for (size_t i = 0; i < 2; ++i) {
18244         isolate->heap()->CollectAllGarbage(
18245             Heap::kFinalizeIncrementalMarkingMask,
18246             GarbageCollectionReason::kFullHashtable);
18247       }
18248       table->Rehash(isolate->factory()->undefined_value());
18249     }
18250   }
18251 
18252   // Check whether the hash table should be extended.
18253   table = EnsureCapacity(table, 1, key);
18254   table->AddEntry(table->FindInsertionEntry(hash), *key, *value);
18255   return table;
18256 }
18257 
18258 
Remove(Handle<ObjectHashTable> table,Handle<Object> key,bool * was_present)18259 Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
18260                                                 Handle<Object> key,
18261                                                 bool* was_present) {
18262   DCHECK(table->IsKey(table->GetIsolate(), *key));
18263 
18264   Object* hash = key->GetHash();
18265   if (hash->IsUndefined(table->GetIsolate())) {
18266     *was_present = false;
18267     return table;
18268   }
18269 
18270   return Remove(table, key, was_present, Smi::cast(hash)->value());
18271 }
18272 
18273 
Remove(Handle<ObjectHashTable> table,Handle<Object> key,bool * was_present,int32_t hash)18274 Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
18275                                                 Handle<Object> key,
18276                                                 bool* was_present,
18277                                                 int32_t hash) {
18278   Isolate* isolate = table->GetIsolate();
18279   DCHECK(table->IsKey(isolate, *key));
18280 
18281   int entry = table->FindEntry(isolate, key, hash);
18282   if (entry == kNotFound) {
18283     *was_present = false;
18284     return table;
18285   }
18286 
18287   *was_present = true;
18288   table->RemoveEntry(entry);
18289   return Shrink(table, key);
18290 }
18291 
18292 
AddEntry(int entry,Object * key,Object * value)18293 void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
18294   set(EntryToIndex(entry), key);
18295   set(EntryToIndex(entry) + 1, value);
18296   ElementAdded();
18297 }
18298 
18299 
RemoveEntry(int entry)18300 void ObjectHashTable::RemoveEntry(int entry) {
18301   set_the_hole(EntryToIndex(entry));
18302   set_the_hole(EntryToIndex(entry) + 1);
18303   ElementRemoved();
18304 }
18305 
18306 
Lookup(Handle<HeapObject> key)18307 Object* WeakHashTable::Lookup(Handle<HeapObject> key) {
18308   DisallowHeapAllocation no_gc;
18309   Isolate* isolate = GetIsolate();
18310   DCHECK(IsKey(isolate, *key));
18311   int entry = FindEntry(key);
18312   if (entry == kNotFound) return isolate->heap()->the_hole_value();
18313   return get(EntryToValueIndex(entry));
18314 }
18315 
18316 
Put(Handle<WeakHashTable> table,Handle<HeapObject> key,Handle<HeapObject> value)18317 Handle<WeakHashTable> WeakHashTable::Put(Handle<WeakHashTable> table,
18318                                          Handle<HeapObject> key,
18319                                          Handle<HeapObject> value) {
18320   Isolate* isolate = key->GetIsolate();
18321   DCHECK(table->IsKey(isolate, *key));
18322   int entry = table->FindEntry(key);
18323   // Key is already in table, just overwrite value.
18324   if (entry != kNotFound) {
18325     table->set(EntryToValueIndex(entry), *value);
18326     return table;
18327   }
18328 
18329   Handle<WeakCell> key_cell = isolate->factory()->NewWeakCell(key);
18330 
18331   // Check whether the hash table should be extended.
18332   table = EnsureCapacity(table, 1, key, TENURED);
18333 
18334   table->AddEntry(table->FindInsertionEntry(table->Hash(key)), key_cell, value);
18335   return table;
18336 }
18337 
18338 
AddEntry(int entry,Handle<WeakCell> key_cell,Handle<HeapObject> value)18339 void WeakHashTable::AddEntry(int entry, Handle<WeakCell> key_cell,
18340                              Handle<HeapObject> value) {
18341   DisallowHeapAllocation no_allocation;
18342   set(EntryToIndex(entry), *key_cell);
18343   set(EntryToValueIndex(entry), *value);
18344   ElementAdded();
18345 }
18346 
18347 
18348 template<class Derived, class Iterator, int entrysize>
Allocate(Isolate * isolate,int capacity,PretenureFlag pretenure)18349 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Allocate(
18350     Isolate* isolate, int capacity, PretenureFlag pretenure) {
18351   // Capacity must be a power of two, since we depend on being able
18352   // to divide and multiple by 2 (kLoadFactor) to derive capacity
18353   // from number of buckets. If we decide to change kLoadFactor
18354   // to something other than 2, capacity should be stored as another
18355   // field of this object.
18356   capacity = base::bits::RoundUpToPowerOfTwo32(Max(kMinCapacity, capacity));
18357   if (capacity > kMaxCapacity) {
18358     v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
18359   }
18360   int num_buckets = capacity / kLoadFactor;
18361   Handle<FixedArray> backing_store = isolate->factory()->NewFixedArray(
18362       kHashTableStartIndex + num_buckets + (capacity * kEntrySize), pretenure);
18363   backing_store->set_map_no_write_barrier(
18364       isolate->heap()->ordered_hash_table_map());
18365   Handle<Derived> table = Handle<Derived>::cast(backing_store);
18366   for (int i = 0; i < num_buckets; ++i) {
18367     table->set(kHashTableStartIndex + i, Smi::FromInt(kNotFound));
18368   }
18369   table->SetNumberOfBuckets(num_buckets);
18370   table->SetNumberOfElements(0);
18371   table->SetNumberOfDeletedElements(0);
18372   return table;
18373 }
18374 
18375 
18376 template<class Derived, class Iterator, int entrysize>
EnsureGrowable(Handle<Derived> table)18377 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::EnsureGrowable(
18378     Handle<Derived> table) {
18379   DCHECK(!table->IsObsolete());
18380 
18381   int nof = table->NumberOfElements();
18382   int nod = table->NumberOfDeletedElements();
18383   int capacity = table->Capacity();
18384   if ((nof + nod) < capacity) return table;
18385   // Don't need to grow if we can simply clear out deleted entries instead.
18386   // Note that we can't compact in place, though, so we always allocate
18387   // a new table.
18388   return Rehash(table, (nod < (capacity >> 1)) ? capacity << 1 : capacity);
18389 }
18390 
18391 
18392 template<class Derived, class Iterator, int entrysize>
Shrink(Handle<Derived> table)18393 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Shrink(
18394     Handle<Derived> table) {
18395   DCHECK(!table->IsObsolete());
18396 
18397   int nof = table->NumberOfElements();
18398   int capacity = table->Capacity();
18399   if (nof >= (capacity >> 2)) return table;
18400   return Rehash(table, capacity / 2);
18401 }
18402 
18403 
18404 template<class Derived, class Iterator, int entrysize>
Clear(Handle<Derived> table)18405 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Clear(
18406     Handle<Derived> table) {
18407   DCHECK(!table->IsObsolete());
18408 
18409   Handle<Derived> new_table =
18410       Allocate(table->GetIsolate(),
18411                kMinCapacity,
18412                table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
18413 
18414   table->SetNextTable(*new_table);
18415   table->SetNumberOfDeletedElements(kClearedTableSentinel);
18416 
18417   return new_table;
18418 }
18419 
18420 template <class Derived, class Iterator, int entrysize>
HasKey(Handle<Derived> table,Handle<Object> key)18421 bool OrderedHashTable<Derived, Iterator, entrysize>::HasKey(
18422     Handle<Derived> table, Handle<Object> key) {
18423   DisallowHeapAllocation no_gc;
18424   Isolate* isolate = table->GetIsolate();
18425   Object* raw_key = *key;
18426   int entry = table->KeyToFirstEntry(isolate, raw_key);
18427   // Walk the chain in the bucket to find the key.
18428   while (entry != kNotFound) {
18429     Object* candidate_key = table->KeyAt(entry);
18430     if (candidate_key->SameValueZero(raw_key)) return true;
18431     entry = table->NextChainEntry(entry);
18432   }
18433   return false;
18434 }
18435 
18436 
Add(Handle<OrderedHashSet> table,Handle<Object> key)18437 Handle<OrderedHashSet> OrderedHashSet::Add(Handle<OrderedHashSet> table,
18438                                            Handle<Object> key) {
18439   int hash = Object::GetOrCreateHash(table->GetIsolate(), key)->value();
18440   int entry = table->HashToEntry(hash);
18441   // Walk the chain of the bucket and try finding the key.
18442   while (entry != kNotFound) {
18443     Object* candidate_key = table->KeyAt(entry);
18444     // Do not add if we have the key already
18445     if (candidate_key->SameValueZero(*key)) return table;
18446     entry = table->NextChainEntry(entry);
18447   }
18448 
18449   table = OrderedHashSet::EnsureGrowable(table);
18450   // Read the existing bucket values.
18451   int bucket = table->HashToBucket(hash);
18452   int previous_entry = table->HashToEntry(hash);
18453   int nof = table->NumberOfElements();
18454   // Insert a new entry at the end,
18455   int new_entry = nof + table->NumberOfDeletedElements();
18456   int new_index = table->EntryToIndex(new_entry);
18457   table->set(new_index, *key);
18458   table->set(new_index + kChainOffset, Smi::FromInt(previous_entry));
18459   // and point the bucket to the new entry.
18460   table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
18461   table->SetNumberOfElements(nof + 1);
18462   return table;
18463 }
18464 
ConvertToKeysArray(Handle<OrderedHashSet> table,GetKeysConversion convert)18465 Handle<FixedArray> OrderedHashSet::ConvertToKeysArray(
18466     Handle<OrderedHashSet> table, GetKeysConversion convert) {
18467   Isolate* isolate = table->GetIsolate();
18468   int length = table->NumberOfElements();
18469   int nof_buckets = table->NumberOfBuckets();
18470   // Convert the dictionary to a linear list.
18471   Handle<FixedArray> result = Handle<FixedArray>::cast(table);
18472   // From this point on table is no longer a valid OrderedHashSet.
18473   result->set_map(isolate->heap()->fixed_array_map());
18474   for (int i = 0; i < length; i++) {
18475     int index = kHashTableStartIndex + nof_buckets + (i * kEntrySize);
18476     Object* key = table->get(index);
18477     if (convert == GetKeysConversion::kConvertToString && key->IsNumber()) {
18478       key = *isolate->factory()->NumberToString(handle(key, isolate));
18479     }
18480     result->set(i, key);
18481   }
18482   result->Shrink(length);
18483   return result;
18484 }
18485 
18486 template<class Derived, class Iterator, int entrysize>
Rehash(Handle<Derived> table,int new_capacity)18487 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Rehash(
18488     Handle<Derived> table, int new_capacity) {
18489   Isolate* isolate = table->GetIsolate();
18490   DCHECK(!table->IsObsolete());
18491 
18492   Handle<Derived> new_table =
18493       Allocate(isolate, new_capacity,
18494                isolate->heap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
18495   int nof = table->NumberOfElements();
18496   int nod = table->NumberOfDeletedElements();
18497   int new_buckets = new_table->NumberOfBuckets();
18498   int new_entry = 0;
18499   int removed_holes_index = 0;
18500 
18501   DisallowHeapAllocation no_gc;
18502   for (int old_entry = 0; old_entry < (nof + nod); ++old_entry) {
18503     Object* key = table->KeyAt(old_entry);
18504     if (key->IsTheHole(isolate)) {
18505       table->SetRemovedIndexAt(removed_holes_index++, old_entry);
18506       continue;
18507     }
18508 
18509     Object* hash = key->GetHash();
18510     int bucket = Smi::cast(hash)->value() & (new_buckets - 1);
18511     Object* chain_entry = new_table->get(kHashTableStartIndex + bucket);
18512     new_table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
18513     int new_index = new_table->EntryToIndex(new_entry);
18514     int old_index = table->EntryToIndex(old_entry);
18515     for (int i = 0; i < entrysize; ++i) {
18516       Object* value = table->get(old_index + i);
18517       new_table->set(new_index + i, value);
18518     }
18519     new_table->set(new_index + kChainOffset, chain_entry);
18520     ++new_entry;
18521   }
18522 
18523   DCHECK_EQ(nod, removed_holes_index);
18524 
18525   new_table->SetNumberOfElements(nof);
18526   table->SetNextTable(*new_table);
18527 
18528   return new_table;
18529 }
18530 
18531 
18532 template Handle<OrderedHashSet>
18533 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Allocate(
18534     Isolate* isolate, int capacity, PretenureFlag pretenure);
18535 
18536 template Handle<OrderedHashSet>
18537 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::EnsureGrowable(
18538     Handle<OrderedHashSet> table);
18539 
18540 template Handle<OrderedHashSet>
18541 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Shrink(
18542     Handle<OrderedHashSet> table);
18543 
18544 template Handle<OrderedHashSet>
18545 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Clear(
18546     Handle<OrderedHashSet> table);
18547 
18548 template bool OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::HasKey(
18549     Handle<OrderedHashSet> table, Handle<Object> key);
18550 
18551 
18552 template Handle<OrderedHashMap>
18553 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Allocate(
18554     Isolate* isolate, int capacity, PretenureFlag pretenure);
18555 
18556 template Handle<OrderedHashMap>
18557 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::EnsureGrowable(
18558     Handle<OrderedHashMap> table);
18559 
18560 template Handle<OrderedHashMap>
18561 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Shrink(
18562     Handle<OrderedHashMap> table);
18563 
18564 template Handle<OrderedHashMap>
18565 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Clear(
18566     Handle<OrderedHashMap> table);
18567 
18568 template bool OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::HasKey(
18569     Handle<OrderedHashMap> table, Handle<Object> key);
18570 
18571 
18572 template<class Derived, class TableType>
Transition()18573 void OrderedHashTableIterator<Derived, TableType>::Transition() {
18574   DisallowHeapAllocation no_allocation;
18575   TableType* table = TableType::cast(this->table());
18576   if (!table->IsObsolete()) return;
18577 
18578   int index = Smi::cast(this->index())->value();
18579   while (table->IsObsolete()) {
18580     TableType* next_table = table->NextTable();
18581 
18582     if (index > 0) {
18583       int nod = table->NumberOfDeletedElements();
18584 
18585       if (nod == TableType::kClearedTableSentinel) {
18586         index = 0;
18587       } else {
18588         int old_index = index;
18589         for (int i = 0; i < nod; ++i) {
18590           int removed_index = table->RemovedIndexAt(i);
18591           if (removed_index >= old_index) break;
18592           --index;
18593         }
18594       }
18595     }
18596 
18597     table = next_table;
18598   }
18599 
18600   set_table(table);
18601   set_index(Smi::FromInt(index));
18602 }
18603 
18604 
18605 template<class Derived, class TableType>
HasMore()18606 bool OrderedHashTableIterator<Derived, TableType>::HasMore() {
18607   DisallowHeapAllocation no_allocation;
18608   Isolate* isolate = this->GetIsolate();
18609   if (this->table()->IsUndefined(isolate)) return false;
18610 
18611   Transition();
18612 
18613   TableType* table = TableType::cast(this->table());
18614   int index = Smi::cast(this->index())->value();
18615   int used_capacity = table->UsedCapacity();
18616 
18617   while (index < used_capacity && table->KeyAt(index)->IsTheHole(isolate)) {
18618     index++;
18619   }
18620 
18621   set_index(Smi::FromInt(index));
18622 
18623   if (index < used_capacity) return true;
18624 
18625   set_table(isolate->heap()->undefined_value());
18626   return false;
18627 }
18628 
18629 
18630 template<class Derived, class TableType>
Next(JSArray * value_array)18631 Smi* OrderedHashTableIterator<Derived, TableType>::Next(JSArray* value_array) {
18632   DisallowHeapAllocation no_allocation;
18633   if (HasMore()) {
18634     FixedArray* array = FixedArray::cast(value_array->elements());
18635     static_cast<Derived*>(this)->PopulateValueArray(array);
18636     MoveNext();
18637     return Smi::cast(kind());
18638   }
18639   return Smi::kZero;
18640 }
18641 
18642 
18643 template Smi*
18644 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Next(
18645     JSArray* value_array);
18646 
18647 template bool
18648 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::HasMore();
18649 
18650 template void
18651 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::MoveNext();
18652 
18653 template Object*
18654 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::CurrentKey();
18655 
18656 template void
18657 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Transition();
18658 
18659 
18660 template Smi*
18661 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Next(
18662     JSArray* value_array);
18663 
18664 template bool
18665 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::HasMore();
18666 
18667 template void
18668 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::MoveNext();
18669 
18670 template Object*
18671 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::CurrentKey();
18672 
18673 template void
18674 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Transition();
18675 
18676 
Initialize(Handle<JSSet> set,Isolate * isolate)18677 void JSSet::Initialize(Handle<JSSet> set, Isolate* isolate) {
18678   Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
18679   set->set_table(*table);
18680 }
18681 
18682 
Clear(Handle<JSSet> set)18683 void JSSet::Clear(Handle<JSSet> set) {
18684   Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()));
18685   table = OrderedHashSet::Clear(table);
18686   set->set_table(*table);
18687 }
18688 
18689 
Initialize(Handle<JSMap> map,Isolate * isolate)18690 void JSMap::Initialize(Handle<JSMap> map, Isolate* isolate) {
18691   Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
18692   map->set_table(*table);
18693 }
18694 
18695 
Clear(Handle<JSMap> map)18696 void JSMap::Clear(Handle<JSMap> map) {
18697   Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()));
18698   table = OrderedHashMap::Clear(table);
18699   map->set_table(*table);
18700 }
18701 
18702 
Initialize(Handle<JSWeakCollection> weak_collection,Isolate * isolate)18703 void JSWeakCollection::Initialize(Handle<JSWeakCollection> weak_collection,
18704                                   Isolate* isolate) {
18705   Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0);
18706   weak_collection->set_table(*table);
18707 }
18708 
18709 
Set(Handle<JSWeakCollection> weak_collection,Handle<Object> key,Handle<Object> value,int32_t hash)18710 void JSWeakCollection::Set(Handle<JSWeakCollection> weak_collection,
18711                            Handle<Object> key, Handle<Object> value,
18712                            int32_t hash) {
18713   DCHECK(key->IsJSReceiver() || key->IsSymbol());
18714   Handle<ObjectHashTable> table(
18715       ObjectHashTable::cast(weak_collection->table()));
18716   DCHECK(table->IsKey(*key));
18717   Handle<ObjectHashTable> new_table =
18718       ObjectHashTable::Put(table, key, value, hash);
18719   weak_collection->set_table(*new_table);
18720   if (*table != *new_table) {
18721     // Zap the old table since we didn't record slots for its elements.
18722     table->FillWithHoles(0, table->length());
18723   }
18724 }
18725 
18726 
Delete(Handle<JSWeakCollection> weak_collection,Handle<Object> key,int32_t hash)18727 bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection,
18728                               Handle<Object> key, int32_t hash) {
18729   DCHECK(key->IsJSReceiver() || key->IsSymbol());
18730   Handle<ObjectHashTable> table(
18731       ObjectHashTable::cast(weak_collection->table()));
18732   DCHECK(table->IsKey(*key));
18733   bool was_present = false;
18734   Handle<ObjectHashTable> new_table =
18735       ObjectHashTable::Remove(table, key, &was_present, hash);
18736   weak_collection->set_table(*new_table);
18737   if (*table != *new_table) {
18738     // Zap the old table since we didn't record slots for its elements.
18739     table->FillWithHoles(0, table->length());
18740   }
18741   return was_present;
18742 }
18743 
GetEntries(Handle<JSWeakCollection> holder,int max_entries)18744 Handle<JSArray> JSWeakCollection::GetEntries(Handle<JSWeakCollection> holder,
18745                                              int max_entries) {
18746   Isolate* isolate = holder->GetIsolate();
18747   Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
18748   if (max_entries == 0 || max_entries > table->NumberOfElements()) {
18749     max_entries = table->NumberOfElements();
18750   }
18751   int values_per_entry = holder->IsJSWeakMap() ? 2 : 1;
18752   Handle<FixedArray> entries =
18753       isolate->factory()->NewFixedArray(max_entries * values_per_entry);
18754   // Recompute max_values because GC could have removed elements from the table.
18755   if (max_entries > table->NumberOfElements()) {
18756     max_entries = table->NumberOfElements();
18757   }
18758 
18759   {
18760     DisallowHeapAllocation no_gc;
18761     int count = 0;
18762     for (int i = 0;
18763          count / values_per_entry < max_entries && i < table->Capacity(); i++) {
18764       Handle<Object> key(table->KeyAt(i), isolate);
18765       if (table->IsKey(isolate, *key)) {
18766         entries->set(count++, *key);
18767         if (values_per_entry > 1) {
18768           Object* value = table->Lookup(key);
18769           entries->set(count++, value);
18770         }
18771       }
18772     }
18773     DCHECK_EQ(max_entries * values_per_entry, count);
18774   }
18775   return isolate->factory()->NewJSArrayWithElements(entries);
18776 }
18777 
18778 // Check if there is a break point at this source position.
HasBreakPoint(int source_position)18779 bool DebugInfo::HasBreakPoint(int source_position) {
18780   // Get the break point info object for this code offset.
18781   Object* break_point_info = GetBreakPointInfo(source_position);
18782 
18783   // If there is no break point info object or no break points in the break
18784   // point info object there is no break point at this code offset.
18785   if (break_point_info->IsUndefined(GetIsolate())) return false;
18786   return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
18787 }
18788 
18789 // Get the break point info object for this source position.
GetBreakPointInfo(int source_position)18790 Object* DebugInfo::GetBreakPointInfo(int source_position) {
18791   Isolate* isolate = GetIsolate();
18792   if (!break_points()->IsUndefined(isolate)) {
18793     for (int i = 0; i < break_points()->length(); i++) {
18794       if (!break_points()->get(i)->IsUndefined(isolate)) {
18795         BreakPointInfo* break_point_info =
18796             BreakPointInfo::cast(break_points()->get(i));
18797         if (break_point_info->source_position() == source_position) {
18798           return break_point_info;
18799         }
18800       }
18801     }
18802   }
18803   return isolate->heap()->undefined_value();
18804 }
18805 
ClearBreakPoint(Handle<DebugInfo> debug_info,Handle<Object> break_point_object)18806 bool DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
18807                                 Handle<Object> break_point_object) {
18808   Isolate* isolate = debug_info->GetIsolate();
18809   if (debug_info->break_points()->IsUndefined(isolate)) return false;
18810 
18811   for (int i = 0; i < debug_info->break_points()->length(); i++) {
18812     if (debug_info->break_points()->get(i)->IsUndefined(isolate)) continue;
18813     Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
18814         BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
18815     if (BreakPointInfo::HasBreakPointObject(break_point_info,
18816                                             break_point_object)) {
18817       BreakPointInfo::ClearBreakPoint(break_point_info, break_point_object);
18818       return true;
18819     }
18820   }
18821   return false;
18822 }
18823 
SetBreakPoint(Handle<DebugInfo> debug_info,int source_position,Handle<Object> break_point_object)18824 void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info, int source_position,
18825                               Handle<Object> break_point_object) {
18826   Isolate* isolate = debug_info->GetIsolate();
18827   Handle<Object> break_point_info(
18828       debug_info->GetBreakPointInfo(source_position), isolate);
18829   if (!break_point_info->IsUndefined(isolate)) {
18830     BreakPointInfo::SetBreakPoint(
18831         Handle<BreakPointInfo>::cast(break_point_info),
18832         break_point_object);
18833     return;
18834   }
18835 
18836   // Adding a new break point for a code offset which did not have any
18837   // break points before. Try to find a free slot.
18838   static const int kNoBreakPointInfo = -1;
18839   int index = kNoBreakPointInfo;
18840   for (int i = 0; i < debug_info->break_points()->length(); i++) {
18841     if (debug_info->break_points()->get(i)->IsUndefined(isolate)) {
18842       index = i;
18843       break;
18844     }
18845   }
18846   if (index == kNoBreakPointInfo) {
18847     // No free slot - extend break point info array.
18848     Handle<FixedArray> old_break_points = Handle<FixedArray>(
18849         FixedArray::cast(debug_info->break_points()), isolate);
18850     Handle<FixedArray> new_break_points =
18851         isolate->factory()->NewFixedArray(
18852             old_break_points->length() +
18853             DebugInfo::kEstimatedNofBreakPointsInFunction);
18854 
18855     debug_info->set_break_points(*new_break_points);
18856     for (int i = 0; i < old_break_points->length(); i++) {
18857       new_break_points->set(i, old_break_points->get(i));
18858     }
18859     index = old_break_points->length();
18860   }
18861   DCHECK(index != kNoBreakPointInfo);
18862 
18863   // Allocate new BreakPointInfo object and set the break point.
18864   Handle<BreakPointInfo> new_break_point_info =
18865       isolate->factory()->NewBreakPointInfo(source_position);
18866   BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
18867   debug_info->break_points()->set(index, *new_break_point_info);
18868 }
18869 
18870 // Get the break point objects for a source position.
GetBreakPointObjects(int source_position)18871 Handle<Object> DebugInfo::GetBreakPointObjects(int source_position) {
18872   Object* break_point_info = GetBreakPointInfo(source_position);
18873   Isolate* isolate = GetIsolate();
18874   if (break_point_info->IsUndefined(isolate)) {
18875     return isolate->factory()->undefined_value();
18876   }
18877   return Handle<Object>(
18878       BreakPointInfo::cast(break_point_info)->break_point_objects(), isolate);
18879 }
18880 
18881 
18882 // Get the total number of break points.
GetBreakPointCount()18883 int DebugInfo::GetBreakPointCount() {
18884   Isolate* isolate = GetIsolate();
18885   if (break_points()->IsUndefined(isolate)) return 0;
18886   int count = 0;
18887   for (int i = 0; i < break_points()->length(); i++) {
18888     if (!break_points()->get(i)->IsUndefined(isolate)) {
18889       BreakPointInfo* break_point_info =
18890           BreakPointInfo::cast(break_points()->get(i));
18891       count += break_point_info->GetBreakPointCount();
18892     }
18893   }
18894   return count;
18895 }
18896 
18897 
FindBreakPointInfo(Handle<DebugInfo> debug_info,Handle<Object> break_point_object)18898 Handle<Object> DebugInfo::FindBreakPointInfo(
18899     Handle<DebugInfo> debug_info, Handle<Object> break_point_object) {
18900   Isolate* isolate = debug_info->GetIsolate();
18901   if (!debug_info->break_points()->IsUndefined(isolate)) {
18902     for (int i = 0; i < debug_info->break_points()->length(); i++) {
18903       if (!debug_info->break_points()->get(i)->IsUndefined(isolate)) {
18904         Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
18905             BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
18906         if (BreakPointInfo::HasBreakPointObject(break_point_info,
18907                                                 break_point_object)) {
18908           return break_point_info;
18909         }
18910       }
18911     }
18912   }
18913   return isolate->factory()->undefined_value();
18914 }
18915 
18916 // Remove the specified break point object.
ClearBreakPoint(Handle<BreakPointInfo> break_point_info,Handle<Object> break_point_object)18917 void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
18918                                      Handle<Object> break_point_object) {
18919   Isolate* isolate = break_point_info->GetIsolate();
18920   // If there are no break points just ignore.
18921   if (break_point_info->break_point_objects()->IsUndefined(isolate)) return;
18922   // If there is a single break point clear it if it is the same.
18923   if (!break_point_info->break_point_objects()->IsFixedArray()) {
18924     if (break_point_info->break_point_objects() == *break_point_object) {
18925       break_point_info->set_break_point_objects(
18926           isolate->heap()->undefined_value());
18927     }
18928     return;
18929   }
18930   // If there are multiple break points shrink the array
18931   DCHECK(break_point_info->break_point_objects()->IsFixedArray());
18932   Handle<FixedArray> old_array =
18933       Handle<FixedArray>(
18934           FixedArray::cast(break_point_info->break_point_objects()));
18935   Handle<FixedArray> new_array =
18936       isolate->factory()->NewFixedArray(old_array->length() - 1);
18937   int found_count = 0;
18938   for (int i = 0; i < old_array->length(); i++) {
18939     if (old_array->get(i) == *break_point_object) {
18940       DCHECK(found_count == 0);
18941       found_count++;
18942     } else {
18943       new_array->set(i - found_count, old_array->get(i));
18944     }
18945   }
18946   // If the break point was found in the list change it.
18947   if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
18948 }
18949 
18950 
18951 // Add the specified break point object.
SetBreakPoint(Handle<BreakPointInfo> break_point_info,Handle<Object> break_point_object)18952 void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
18953                                    Handle<Object> break_point_object) {
18954   Isolate* isolate = break_point_info->GetIsolate();
18955 
18956   // If there was no break point objects before just set it.
18957   if (break_point_info->break_point_objects()->IsUndefined(isolate)) {
18958     break_point_info->set_break_point_objects(*break_point_object);
18959     return;
18960   }
18961   // If the break point object is the same as before just ignore.
18962   if (break_point_info->break_point_objects() == *break_point_object) return;
18963   // If there was one break point object before replace with array.
18964   if (!break_point_info->break_point_objects()->IsFixedArray()) {
18965     Handle<FixedArray> array = isolate->factory()->NewFixedArray(2);
18966     array->set(0, break_point_info->break_point_objects());
18967     array->set(1, *break_point_object);
18968     break_point_info->set_break_point_objects(*array);
18969     return;
18970   }
18971   // If there was more than one break point before extend array.
18972   Handle<FixedArray> old_array =
18973       Handle<FixedArray>(
18974           FixedArray::cast(break_point_info->break_point_objects()));
18975   Handle<FixedArray> new_array =
18976       isolate->factory()->NewFixedArray(old_array->length() + 1);
18977   for (int i = 0; i < old_array->length(); i++) {
18978     // If the break point was there before just ignore.
18979     if (old_array->get(i) == *break_point_object) return;
18980     new_array->set(i, old_array->get(i));
18981   }
18982   // Add the new break point.
18983   new_array->set(old_array->length(), *break_point_object);
18984   break_point_info->set_break_point_objects(*new_array);
18985 }
18986 
18987 
HasBreakPointObject(Handle<BreakPointInfo> break_point_info,Handle<Object> break_point_object)18988 bool BreakPointInfo::HasBreakPointObject(
18989     Handle<BreakPointInfo> break_point_info,
18990     Handle<Object> break_point_object) {
18991   // No break point.
18992   Isolate* isolate = break_point_info->GetIsolate();
18993   if (break_point_info->break_point_objects()->IsUndefined(isolate)) {
18994     return false;
18995   }
18996   // Single break point.
18997   if (!break_point_info->break_point_objects()->IsFixedArray()) {
18998     return break_point_info->break_point_objects() == *break_point_object;
18999   }
19000   // Multiple break points.
19001   FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
19002   for (int i = 0; i < array->length(); i++) {
19003     if (array->get(i) == *break_point_object) {
19004       return true;
19005     }
19006   }
19007   return false;
19008 }
19009 
19010 
19011 // Get the number of break points.
GetBreakPointCount()19012 int BreakPointInfo::GetBreakPointCount() {
19013   // No break point.
19014   if (break_point_objects()->IsUndefined(GetIsolate())) return 0;
19015   // Single break point.
19016   if (!break_point_objects()->IsFixedArray()) return 1;
19017   // Multiple break points.
19018   return FixedArray::cast(break_point_objects())->length();
19019 }
19020 
19021 
19022 // static
New(Handle<JSFunction> constructor,Handle<JSReceiver> new_target,double tv)19023 MaybeHandle<JSDate> JSDate::New(Handle<JSFunction> constructor,
19024                                 Handle<JSReceiver> new_target, double tv) {
19025   Isolate* const isolate = constructor->GetIsolate();
19026   Handle<JSObject> result;
19027   ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
19028                              JSObject::New(constructor, new_target), JSDate);
19029   if (-DateCache::kMaxTimeInMs <= tv && tv <= DateCache::kMaxTimeInMs) {
19030     tv = DoubleToInteger(tv) + 0.0;
19031   } else {
19032     tv = std::numeric_limits<double>::quiet_NaN();
19033   }
19034   Handle<Object> value = isolate->factory()->NewNumber(tv);
19035   Handle<JSDate>::cast(result)->SetValue(*value, std::isnan(tv));
19036   return Handle<JSDate>::cast(result);
19037 }
19038 
19039 
19040 // static
CurrentTimeValue(Isolate * isolate)19041 double JSDate::CurrentTimeValue(Isolate* isolate) {
19042   if (FLAG_log_timer_events || FLAG_prof_cpp) LOG(isolate, CurrentTimeEvent());
19043 
19044   // According to ECMA-262, section 15.9.1, page 117, the precision of
19045   // the number in a Date object representing a particular instant in
19046   // time is milliseconds. Therefore, we floor the result of getting
19047   // the OS time.
19048   return Floor(FLAG_verify_predictable
19049                    ? isolate->heap()->MonotonicallyIncreasingTimeInMs()
19050                    : base::OS::TimeCurrentMillis());
19051 }
19052 
19053 
19054 // static
GetField(Object * object,Smi * index)19055 Object* JSDate::GetField(Object* object, Smi* index) {
19056   return JSDate::cast(object)->DoGetField(
19057       static_cast<FieldIndex>(index->value()));
19058 }
19059 
19060 
DoGetField(FieldIndex index)19061 Object* JSDate::DoGetField(FieldIndex index) {
19062   DCHECK(index != kDateValue);
19063 
19064   DateCache* date_cache = GetIsolate()->date_cache();
19065 
19066   if (index < kFirstUncachedField) {
19067     Object* stamp = cache_stamp();
19068     if (stamp != date_cache->stamp() && stamp->IsSmi()) {
19069       // Since the stamp is not NaN, the value is also not NaN.
19070       int64_t local_time_ms =
19071           date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
19072       SetCachedFields(local_time_ms, date_cache);
19073     }
19074     switch (index) {
19075       case kYear: return year();
19076       case kMonth: return month();
19077       case kDay: return day();
19078       case kWeekday: return weekday();
19079       case kHour: return hour();
19080       case kMinute: return min();
19081       case kSecond: return sec();
19082       default: UNREACHABLE();
19083     }
19084   }
19085 
19086   if (index >= kFirstUTCField) {
19087     return GetUTCField(index, value()->Number(), date_cache);
19088   }
19089 
19090   double time = value()->Number();
19091   if (std::isnan(time)) return GetIsolate()->heap()->nan_value();
19092 
19093   int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
19094   int days = DateCache::DaysFromTime(local_time_ms);
19095 
19096   if (index == kDays) return Smi::FromInt(days);
19097 
19098   int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
19099   if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
19100   DCHECK(index == kTimeInDay);
19101   return Smi::FromInt(time_in_day_ms);
19102 }
19103 
19104 
GetUTCField(FieldIndex index,double value,DateCache * date_cache)19105 Object* JSDate::GetUTCField(FieldIndex index,
19106                             double value,
19107                             DateCache* date_cache) {
19108   DCHECK(index >= kFirstUTCField);
19109 
19110   if (std::isnan(value)) return GetIsolate()->heap()->nan_value();
19111 
19112   int64_t time_ms = static_cast<int64_t>(value);
19113 
19114   if (index == kTimezoneOffset) {
19115     return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
19116   }
19117 
19118   int days = DateCache::DaysFromTime(time_ms);
19119 
19120   if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
19121 
19122   if (index <= kDayUTC) {
19123     int year, month, day;
19124     date_cache->YearMonthDayFromDays(days, &year, &month, &day);
19125     if (index == kYearUTC) return Smi::FromInt(year);
19126     if (index == kMonthUTC) return Smi::FromInt(month);
19127     DCHECK(index == kDayUTC);
19128     return Smi::FromInt(day);
19129   }
19130 
19131   int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
19132   switch (index) {
19133     case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
19134     case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
19135     case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
19136     case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
19137     case kDaysUTC: return Smi::FromInt(days);
19138     case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
19139     default: UNREACHABLE();
19140   }
19141 
19142   UNREACHABLE();
19143   return NULL;
19144 }
19145 
19146 
19147 // static
SetValue(Handle<JSDate> date,double v)19148 Handle<Object> JSDate::SetValue(Handle<JSDate> date, double v) {
19149   Isolate* const isolate = date->GetIsolate();
19150   Handle<Object> value = isolate->factory()->NewNumber(v);
19151   bool value_is_nan = std::isnan(v);
19152   date->SetValue(*value, value_is_nan);
19153   return value;
19154 }
19155 
19156 
SetValue(Object * value,bool is_value_nan)19157 void JSDate::SetValue(Object* value, bool is_value_nan) {
19158   set_value(value);
19159   if (is_value_nan) {
19160     HeapNumber* nan = GetIsolate()->heap()->nan_value();
19161     set_cache_stamp(nan, SKIP_WRITE_BARRIER);
19162     set_year(nan, SKIP_WRITE_BARRIER);
19163     set_month(nan, SKIP_WRITE_BARRIER);
19164     set_day(nan, SKIP_WRITE_BARRIER);
19165     set_hour(nan, SKIP_WRITE_BARRIER);
19166     set_min(nan, SKIP_WRITE_BARRIER);
19167     set_sec(nan, SKIP_WRITE_BARRIER);
19168     set_weekday(nan, SKIP_WRITE_BARRIER);
19169   } else {
19170     set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
19171   }
19172 }
19173 
19174 
SetCachedFields(int64_t local_time_ms,DateCache * date_cache)19175 void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) {
19176   int days = DateCache::DaysFromTime(local_time_ms);
19177   int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
19178   int year, month, day;
19179   date_cache->YearMonthDayFromDays(days, &year, &month, &day);
19180   int weekday = date_cache->Weekday(days);
19181   int hour = time_in_day_ms / (60 * 60 * 1000);
19182   int min = (time_in_day_ms / (60 * 1000)) % 60;
19183   int sec = (time_in_day_ms / 1000) % 60;
19184   set_cache_stamp(date_cache->stamp());
19185   set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
19186   set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
19187   set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
19188   set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
19189   set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
19190   set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
19191   set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
19192 }
19193 
19194 namespace {
19195 
ScriptFromJSValue(Object * in)19196 Script* ScriptFromJSValue(Object* in) {
19197   DCHECK(in->IsJSValue());
19198   JSValue* jsvalue = JSValue::cast(in);
19199   DCHECK(jsvalue->value()->IsScript());
19200   return Script::cast(jsvalue->value());
19201 }
19202 
19203 }  // namespace
19204 
GetLineNumber() const19205 int JSMessageObject::GetLineNumber() const {
19206   if (start_position() == -1) return Message::kNoLineNumberInfo;
19207 
19208   Handle<Script> the_script = handle(ScriptFromJSValue(script()));
19209 
19210   Script::PositionInfo info;
19211   const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
19212   if (!Script::GetPositionInfo(the_script, start_position(), &info,
19213                                offset_flag)) {
19214     return Message::kNoLineNumberInfo;
19215   }
19216 
19217   return info.line + 1;
19218 }
19219 
GetColumnNumber() const19220 int JSMessageObject::GetColumnNumber() const {
19221   if (start_position() == -1) return -1;
19222 
19223   Handle<Script> the_script = handle(ScriptFromJSValue(script()));
19224 
19225   Script::PositionInfo info;
19226   const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
19227   if (!Script::GetPositionInfo(the_script, start_position(), &info,
19228                                offset_flag)) {
19229     return -1;
19230   }
19231 
19232   return info.column;  // Note: No '+1' in contrast to GetLineNumber.
19233 }
19234 
GetSourceLine() const19235 Handle<String> JSMessageObject::GetSourceLine() const {
19236   Handle<Script> the_script = handle(ScriptFromJSValue(script()));
19237 
19238   Isolate* isolate = the_script->GetIsolate();
19239   if (the_script->type() == Script::TYPE_WASM) {
19240     return isolate->factory()->empty_string();
19241   }
19242 
19243   Script::PositionInfo info;
19244   const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
19245   if (!Script::GetPositionInfo(the_script, start_position(), &info,
19246                                offset_flag)) {
19247     return isolate->factory()->empty_string();
19248   }
19249 
19250   Handle<String> src = handle(String::cast(the_script->source()), isolate);
19251   return isolate->factory()->NewSubString(src, info.line_start, info.line_end);
19252 }
19253 
Neuter()19254 void JSArrayBuffer::Neuter() {
19255   CHECK(is_neuterable());
19256   CHECK(is_external());
19257   set_backing_store(NULL);
19258   set_byte_length(Smi::kZero);
19259   set_was_neutered(true);
19260   // Invalidate the neutering protector.
19261   Isolate* const isolate = GetIsolate();
19262   if (isolate->IsArrayBufferNeuteringIntact()) {
19263     isolate->InvalidateArrayBufferNeuteringProtector();
19264   }
19265 }
19266 
19267 
Setup(Handle<JSArrayBuffer> array_buffer,Isolate * isolate,bool is_external,void * data,size_t allocated_length,SharedFlag shared)19268 void JSArrayBuffer::Setup(Handle<JSArrayBuffer> array_buffer, Isolate* isolate,
19269                           bool is_external, void* data, size_t allocated_length,
19270                           SharedFlag shared) {
19271   DCHECK(array_buffer->GetInternalFieldCount() ==
19272          v8::ArrayBuffer::kInternalFieldCount);
19273   for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) {
19274     array_buffer->SetInternalField(i, Smi::kZero);
19275   }
19276   array_buffer->set_bit_field(0);
19277   array_buffer->set_is_external(is_external);
19278   array_buffer->set_is_neuterable(shared == SharedFlag::kNotShared);
19279   array_buffer->set_is_shared(shared == SharedFlag::kShared);
19280 
19281   Handle<Object> byte_length =
19282       isolate->factory()->NewNumberFromSize(allocated_length);
19283   CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
19284   array_buffer->set_byte_length(*byte_length);
19285   // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
19286   // are currently being constructed in the |ArrayBufferTracker|. The
19287   // registration method below handles the case of registering a buffer that has
19288   // already been promoted.
19289   array_buffer->set_backing_store(data);
19290 
19291   if (data && !is_external) {
19292     isolate->heap()->RegisterNewArrayBuffer(*array_buffer);
19293   }
19294 }
19295 
19296 
SetupAllocatingData(Handle<JSArrayBuffer> array_buffer,Isolate * isolate,size_t allocated_length,bool initialize,SharedFlag shared)19297 bool JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer> array_buffer,
19298                                         Isolate* isolate,
19299                                         size_t allocated_length,
19300                                         bool initialize, SharedFlag shared) {
19301   void* data;
19302   CHECK(isolate->array_buffer_allocator() != NULL);
19303   // Prevent creating array buffers when serializing.
19304   DCHECK(!isolate->serializer_enabled());
19305   if (allocated_length != 0) {
19306     if (initialize) {
19307       data = isolate->array_buffer_allocator()->Allocate(allocated_length);
19308     } else {
19309       data = isolate->array_buffer_allocator()->AllocateUninitialized(
19310           allocated_length);
19311     }
19312     if (data == NULL) return false;
19313   } else {
19314     data = NULL;
19315   }
19316 
19317   JSArrayBuffer::Setup(array_buffer, isolate, false, data, allocated_length,
19318                        shared);
19319   return true;
19320 }
19321 
19322 
MaterializeArrayBuffer(Handle<JSTypedArray> typed_array)19323 Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
19324     Handle<JSTypedArray> typed_array) {
19325 
19326   Handle<Map> map(typed_array->map());
19327   Isolate* isolate = typed_array->GetIsolate();
19328 
19329   DCHECK(IsFixedTypedArrayElementsKind(map->elements_kind()));
19330 
19331   Handle<FixedTypedArrayBase> fixed_typed_array(
19332       FixedTypedArrayBase::cast(typed_array->elements()));
19333 
19334   Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(typed_array->buffer()),
19335                                isolate);
19336   void* backing_store =
19337       isolate->array_buffer_allocator()->AllocateUninitialized(
19338           fixed_typed_array->DataSize());
19339   buffer->set_is_external(false);
19340   DCHECK(buffer->byte_length()->IsSmi() ||
19341          buffer->byte_length()->IsHeapNumber());
19342   DCHECK(NumberToInt32(buffer->byte_length()) == fixed_typed_array->DataSize());
19343   // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
19344   // are currently being constructed in the |ArrayBufferTracker|. The
19345   // registration method below handles the case of registering a buffer that has
19346   // already been promoted.
19347   buffer->set_backing_store(backing_store);
19348   isolate->heap()->RegisterNewArrayBuffer(*buffer);
19349   memcpy(buffer->backing_store(),
19350          fixed_typed_array->DataPtr(),
19351          fixed_typed_array->DataSize());
19352   Handle<FixedTypedArrayBase> new_elements =
19353       isolate->factory()->NewFixedTypedArrayWithExternalPointer(
19354           fixed_typed_array->length(), typed_array->type(),
19355           static_cast<uint8_t*>(buffer->backing_store()));
19356 
19357   typed_array->set_elements(*new_elements);
19358 
19359   return buffer;
19360 }
19361 
19362 
GetBuffer()19363 Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
19364   Handle<JSArrayBuffer> array_buffer(JSArrayBuffer::cast(buffer()),
19365                                      GetIsolate());
19366   if (array_buffer->was_neutered() ||
19367       array_buffer->backing_store() != nullptr) {
19368     return array_buffer;
19369   }
19370   Handle<JSTypedArray> self(this);
19371   return MaterializeArrayBuffer(self);
19372 }
19373 
InvalidateEntry(Handle<GlobalDictionary> dictionary,int entry)19374 Handle<PropertyCell> PropertyCell::InvalidateEntry(
19375     Handle<GlobalDictionary> dictionary, int entry) {
19376   Isolate* isolate = dictionary->GetIsolate();
19377   // Swap with a copy.
19378   DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
19379   Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
19380   Handle<PropertyCell> new_cell = isolate->factory()->NewPropertyCell();
19381   new_cell->set_value(cell->value());
19382   dictionary->ValueAtPut(entry, *new_cell);
19383   bool is_the_hole = cell->value()->IsTheHole(isolate);
19384   // Cell is officially mutable henceforth.
19385   PropertyDetails details = cell->property_details();
19386   details = details.set_cell_type(is_the_hole ? PropertyCellType::kUninitialized
19387                                               : PropertyCellType::kMutable);
19388   new_cell->set_property_details(details);
19389   // Old cell is ready for invalidation.
19390   if (is_the_hole) {
19391     cell->set_value(isolate->heap()->undefined_value());
19392   } else {
19393     cell->set_value(isolate->heap()->the_hole_value());
19394   }
19395   details = details.set_cell_type(PropertyCellType::kInvalidated);
19396   cell->set_property_details(details);
19397   cell->dependent_code()->DeoptimizeDependentCodeGroup(
19398       isolate, DependentCode::kPropertyCellChangedGroup);
19399   return new_cell;
19400 }
19401 
19402 
GetConstantType()19403 PropertyCellConstantType PropertyCell::GetConstantType() {
19404   if (value()->IsSmi()) return PropertyCellConstantType::kSmi;
19405   return PropertyCellConstantType::kStableMap;
19406 }
19407 
19408 
RemainsConstantType(Handle<PropertyCell> cell,Handle<Object> value)19409 static bool RemainsConstantType(Handle<PropertyCell> cell,
19410                                 Handle<Object> value) {
19411   // TODO(dcarney): double->smi and smi->double transition from kConstant
19412   if (cell->value()->IsSmi() && value->IsSmi()) {
19413     return true;
19414   } else if (cell->value()->IsHeapObject() && value->IsHeapObject()) {
19415     return HeapObject::cast(cell->value())->map() ==
19416                HeapObject::cast(*value)->map() &&
19417            HeapObject::cast(*value)->map()->is_stable();
19418   }
19419   return false;
19420 }
19421 
19422 
UpdatedType(Handle<PropertyCell> cell,Handle<Object> value,PropertyDetails details)19423 PropertyCellType PropertyCell::UpdatedType(Handle<PropertyCell> cell,
19424                                            Handle<Object> value,
19425                                            PropertyDetails details) {
19426   PropertyCellType type = details.cell_type();
19427   Isolate* isolate = cell->GetIsolate();
19428   DCHECK(!value->IsTheHole(isolate));
19429   if (cell->value()->IsTheHole(isolate)) {
19430     switch (type) {
19431       // Only allow a cell to transition once into constant state.
19432       case PropertyCellType::kUninitialized:
19433         if (value->IsUndefined(isolate)) return PropertyCellType::kUndefined;
19434         return PropertyCellType::kConstant;
19435       case PropertyCellType::kInvalidated:
19436         return PropertyCellType::kMutable;
19437       default:
19438         UNREACHABLE();
19439         return PropertyCellType::kMutable;
19440     }
19441   }
19442   switch (type) {
19443     case PropertyCellType::kUndefined:
19444       return PropertyCellType::kConstant;
19445     case PropertyCellType::kConstant:
19446       if (*value == cell->value()) return PropertyCellType::kConstant;
19447     // Fall through.
19448     case PropertyCellType::kConstantType:
19449       if (RemainsConstantType(cell, value)) {
19450         return PropertyCellType::kConstantType;
19451       }
19452     // Fall through.
19453     case PropertyCellType::kMutable:
19454       return PropertyCellType::kMutable;
19455   }
19456   UNREACHABLE();
19457   return PropertyCellType::kMutable;
19458 }
19459 
PrepareForValue(Handle<GlobalDictionary> dictionary,int entry,Handle<Object> value,PropertyDetails details)19460 Handle<PropertyCell> PropertyCell::PrepareForValue(
19461     Handle<GlobalDictionary> dictionary, int entry, Handle<Object> value,
19462     PropertyDetails details) {
19463   Isolate* isolate = dictionary->GetIsolate();
19464   DCHECK(!value->IsTheHole(isolate));
19465   DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
19466   Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
19467   const PropertyDetails original_details = cell->property_details();
19468   // Data accesses could be cached in ics or optimized code.
19469   bool invalidate =
19470       original_details.kind() == kData && details.kind() == kAccessor;
19471   int index = original_details.dictionary_index();
19472   PropertyCellType old_type = original_details.cell_type();
19473   // Preserve the enumeration index unless the property was deleted or never
19474   // initialized.
19475   if (cell->value()->IsTheHole(isolate)) {
19476     index = dictionary->NextEnumerationIndex();
19477     dictionary->SetNextEnumerationIndex(index + 1);
19478   }
19479   DCHECK(index > 0);
19480   details = details.set_index(index);
19481 
19482   PropertyCellType new_type = UpdatedType(cell, value, original_details);
19483   if (invalidate) cell = PropertyCell::InvalidateEntry(dictionary, entry);
19484 
19485   // Install new property details.
19486   details = details.set_cell_type(new_type);
19487   cell->set_property_details(details);
19488 
19489   // Deopt when transitioning from a constant type.
19490   if (!invalidate && (old_type != new_type ||
19491                       original_details.IsReadOnly() != details.IsReadOnly())) {
19492     cell->dependent_code()->DeoptimizeDependentCodeGroup(
19493         isolate, DependentCode::kPropertyCellChangedGroup);
19494   }
19495   return cell;
19496 }
19497 
19498 
19499 // static
SetValueWithInvalidation(Handle<PropertyCell> cell,Handle<Object> new_value)19500 void PropertyCell::SetValueWithInvalidation(Handle<PropertyCell> cell,
19501                                             Handle<Object> new_value) {
19502   if (cell->value() != *new_value) {
19503     cell->set_value(*new_value);
19504     Isolate* isolate = cell->GetIsolate();
19505     cell->dependent_code()->DeoptimizeDependentCodeGroup(
19506         isolate, DependentCode::kPropertyCellChangedGroup);
19507   }
19508 }
19509 
source_position() const19510 int JSGeneratorObject::source_position() const {
19511   CHECK(is_suspended());
19512   DCHECK(function()->shared()->HasBytecodeArray());
19513   DCHECK(!function()->shared()->HasBaselineCode());
19514   int code_offset = Smi::cast(input_or_debug_pos())->value();
19515   // The stored bytecode offset is relative to a different base than what
19516   // is used in the source position table, hence the subtraction.
19517   code_offset -= BytecodeArray::kHeaderSize - kHeapObjectTag;
19518   AbstractCode* code =
19519       AbstractCode::cast(function()->shared()->bytecode_array());
19520   return code->SourcePosition(code_offset);
19521 }
19522 
19523 // static
Get(Isolate * isolate,Handle<JSObject> receiver)19524 AccessCheckInfo* AccessCheckInfo::Get(Isolate* isolate,
19525                                       Handle<JSObject> receiver) {
19526   DisallowHeapAllocation no_gc;
19527   DCHECK(receiver->map()->is_access_check_needed());
19528   Object* maybe_constructor = receiver->map()->GetConstructor();
19529   // Might happen for a detached context.
19530   if (!maybe_constructor->IsJSFunction()) return nullptr;
19531   JSFunction* constructor = JSFunction::cast(maybe_constructor);
19532   // Might happen for the debug context.
19533   if (!constructor->shared()->IsApiFunction()) return nullptr;
19534 
19535   Object* data_obj =
19536       constructor->shared()->get_api_func_data()->access_check_info();
19537   if (data_obj->IsUndefined(isolate)) return nullptr;
19538 
19539   return AccessCheckInfo::cast(data_obj);
19540 }
19541 
HasProxyInPrototype(Isolate * isolate)19542 bool JSReceiver::HasProxyInPrototype(Isolate* isolate) {
19543   for (PrototypeIterator iter(isolate, this, kStartAtReceiver,
19544                               PrototypeIterator::END_AT_NULL);
19545        !iter.IsAtEnd(); iter.AdvanceIgnoringProxies()) {
19546     if (iter.GetCurrent<Object>()->IsJSProxy()) return true;
19547   }
19548   return false;
19549 }
19550 
GetExport(Handle<String> name)19551 MaybeHandle<Object> JSModuleNamespace::GetExport(Handle<String> name) {
19552   Isolate* isolate = name->GetIsolate();
19553 
19554   Handle<Object> object(module()->exports()->Lookup(name), isolate);
19555   if (object->IsTheHole(isolate)) {
19556     return isolate->factory()->undefined_value();
19557   }
19558 
19559   Handle<Object> value(Handle<Cell>::cast(object)->value(), isolate);
19560   if (value->IsTheHole(isolate)) {
19561     THROW_NEW_ERROR(
19562         isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object);
19563   }
19564 
19565   return value;
19566 }
19567 
19568 namespace {
19569 
19570 struct ModuleHandleHash {
operator ()v8::internal::__anon3bdb5a221b11::ModuleHandleHash19571   V8_INLINE size_t operator()(Handle<Module> module) const {
19572     return module->hash();
19573   }
19574 };
19575 
19576 struct ModuleHandleEqual {
operator ()v8::internal::__anon3bdb5a221b11::ModuleHandleEqual19577   V8_INLINE bool operator()(Handle<Module> lhs, Handle<Module> rhs) const {
19578     return *lhs == *rhs;
19579   }
19580 };
19581 
19582 struct StringHandleHash {
operator ()v8::internal::__anon3bdb5a221b11::StringHandleHash19583   V8_INLINE size_t operator()(Handle<String> string) const {
19584     return string->Hash();
19585   }
19586 };
19587 
19588 struct StringHandleEqual {
operator ()v8::internal::__anon3bdb5a221b11::StringHandleEqual19589   V8_INLINE bool operator()(Handle<String> lhs, Handle<String> rhs) const {
19590     return lhs->Equals(*rhs);
19591   }
19592 };
19593 
19594 class UnorderedStringSet
19595     : public std::unordered_set<Handle<String>, StringHandleHash,
19596                                 StringHandleEqual,
19597                                 zone_allocator<Handle<String>>> {
19598  public:
UnorderedStringSet(Zone * zone)19599   explicit UnorderedStringSet(Zone* zone)
19600       : std::unordered_set<Handle<String>, StringHandleHash, StringHandleEqual,
19601                            zone_allocator<Handle<String>>>(
19602             2 /* bucket count */, StringHandleHash(), StringHandleEqual(),
19603             zone_allocator<Handle<String>>(zone)) {}
19604 };
19605 
19606 class UnorderedModuleSet
19607     : public std::unordered_set<Handle<Module>, ModuleHandleHash,
19608                                 ModuleHandleEqual,
19609                                 zone_allocator<Handle<Module>>> {
19610  public:
UnorderedModuleSet(Zone * zone)19611   explicit UnorderedModuleSet(Zone* zone)
19612       : std::unordered_set<Handle<Module>, ModuleHandleHash, ModuleHandleEqual,
19613                            zone_allocator<Handle<Module>>>(
19614             2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(),
19615             zone_allocator<Handle<Module>>(zone)) {}
19616 };
19617 
19618 class UnorderedStringMap
19619     : public std::unordered_map<
19620           Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual,
19621           zone_allocator<std::pair<const Handle<String>, Handle<Object>>>> {
19622  public:
UnorderedStringMap(Zone * zone)19623   explicit UnorderedStringMap(Zone* zone)
19624       : std::unordered_map<
19625             Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual,
19626             zone_allocator<std::pair<const Handle<String>, Handle<Object>>>>(
19627             2 /* bucket count */, StringHandleHash(), StringHandleEqual(),
19628             zone_allocator<std::pair<const Handle<String>, Handle<Object>>>(
19629                 zone)) {}
19630 };
19631 
19632 }  // anonymous namespace
19633 
19634 class Module::ResolveSet
19635     : public std::unordered_map<
19636           Handle<Module>, UnorderedStringSet*, ModuleHandleHash,
19637           ModuleHandleEqual, zone_allocator<std::pair<const Handle<Module>,
19638                                                       UnorderedStringSet*>>> {
19639  public:
ResolveSet(Zone * zone)19640   explicit ResolveSet(Zone* zone)
19641       : std::unordered_map<Handle<Module>, UnorderedStringSet*,
19642                            ModuleHandleHash, ModuleHandleEqual,
19643                            zone_allocator<std::pair<const Handle<Module>,
19644                                                     UnorderedStringSet*>>>(
19645             2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(),
19646             zone_allocator<
19647                 std::pair<const Handle<Module>, UnorderedStringSet*>>(zone)),
19648         zone_(zone) {}
19649 
zone() const19650   Zone* zone() const { return zone_; }
19651 
19652  private:
19653   Zone* zone_;
19654 };
19655 
19656 namespace {
19657 
ExportIndex(int cell_index)19658 int ExportIndex(int cell_index) {
19659   DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
19660             ModuleDescriptor::kExport);
19661   return cell_index - 1;
19662 }
19663 
ImportIndex(int cell_index)19664 int ImportIndex(int cell_index) {
19665   DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
19666             ModuleDescriptor::kImport);
19667   return -cell_index - 1;
19668 }
19669 
19670 }  // anonymous namespace
19671 
CreateIndirectExport(Handle<Module> module,Handle<String> name,Handle<ModuleInfoEntry> entry)19672 void Module::CreateIndirectExport(Handle<Module> module, Handle<String> name,
19673                                   Handle<ModuleInfoEntry> entry) {
19674   Isolate* isolate = module->GetIsolate();
19675   Handle<ObjectHashTable> exports(module->exports(), isolate);
19676   DCHECK(exports->Lookup(name)->IsTheHole(isolate));
19677   exports = ObjectHashTable::Put(exports, name, entry);
19678   module->set_exports(*exports);
19679 }
19680 
CreateExport(Handle<Module> module,int cell_index,Handle<FixedArray> names)19681 void Module::CreateExport(Handle<Module> module, int cell_index,
19682                           Handle<FixedArray> names) {
19683   DCHECK_LT(0, names->length());
19684   Isolate* isolate = module->GetIsolate();
19685 
19686   Handle<Cell> cell =
19687       isolate->factory()->NewCell(isolate->factory()->undefined_value());
19688   module->regular_exports()->set(ExportIndex(cell_index), *cell);
19689 
19690   Handle<ObjectHashTable> exports(module->exports(), isolate);
19691   for (int i = 0, n = names->length(); i < n; ++i) {
19692     Handle<String> name(String::cast(names->get(i)), isolate);
19693     DCHECK(exports->Lookup(name)->IsTheHole(isolate));
19694     exports = ObjectHashTable::Put(exports, name, cell);
19695   }
19696   module->set_exports(*exports);
19697 }
19698 
LoadVariable(Handle<Module> module,int cell_index)19699 Handle<Object> Module::LoadVariable(Handle<Module> module, int cell_index) {
19700   Isolate* isolate = module->GetIsolate();
19701   Handle<Object> object;
19702   switch (ModuleDescriptor::GetCellIndexKind(cell_index)) {
19703     case ModuleDescriptor::kImport:
19704       object = handle(module->regular_imports()->get(ImportIndex(cell_index)),
19705                       isolate);
19706       break;
19707     case ModuleDescriptor::kExport:
19708       object = handle(module->regular_exports()->get(ExportIndex(cell_index)),
19709                       isolate);
19710       break;
19711     case ModuleDescriptor::kInvalid:
19712       UNREACHABLE();
19713       break;
19714   }
19715   return handle(Handle<Cell>::cast(object)->value(), isolate);
19716 }
19717 
StoreVariable(Handle<Module> module,int cell_index,Handle<Object> value)19718 void Module::StoreVariable(Handle<Module> module, int cell_index,
19719                            Handle<Object> value) {
19720   Isolate* isolate = module->GetIsolate();
19721   DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
19722             ModuleDescriptor::kExport);
19723   Handle<Object> object(module->regular_exports()->get(ExportIndex(cell_index)),
19724                         isolate);
19725   Handle<Cell>::cast(object)->set_value(*value);
19726 }
19727 
ResolveImport(Handle<Module> module,Handle<String> name,int module_request,MessageLocation loc,bool must_resolve,Module::ResolveSet * resolve_set)19728 MaybeHandle<Cell> Module::ResolveImport(Handle<Module> module,
19729                                         Handle<String> name, int module_request,
19730                                         MessageLocation loc, bool must_resolve,
19731                                         Module::ResolveSet* resolve_set) {
19732   Isolate* isolate = module->GetIsolate();
19733   Handle<Module> requested_module(
19734       Module::cast(module->requested_modules()->get(module_request)), isolate);
19735   return Module::ResolveExport(requested_module, name, loc, must_resolve,
19736                                resolve_set);
19737 }
19738 
ResolveExport(Handle<Module> module,Handle<String> name,MessageLocation loc,bool must_resolve,Module::ResolveSet * resolve_set)19739 MaybeHandle<Cell> Module::ResolveExport(Handle<Module> module,
19740                                         Handle<String> name,
19741                                         MessageLocation loc, bool must_resolve,
19742                                         Module::ResolveSet* resolve_set) {
19743   Isolate* isolate = module->GetIsolate();
19744   Handle<Object> object(module->exports()->Lookup(name), isolate);
19745   if (object->IsCell()) {
19746     // Already resolved (e.g. because it's a local export).
19747     return Handle<Cell>::cast(object);
19748   }
19749 
19750   // Check for cycle before recursing.
19751   {
19752     // Attempt insertion with a null string set.
19753     auto result = resolve_set->insert({module, nullptr});
19754     UnorderedStringSet*& name_set = result.first->second;
19755     if (result.second) {
19756       // |module| wasn't in the map previously, so allocate a new name set.
19757       Zone* zone = resolve_set->zone();
19758       name_set =
19759           new (zone->New(sizeof(UnorderedStringSet))) UnorderedStringSet(zone);
19760     } else if (name_set->count(name)) {
19761       // Cycle detected.
19762       if (must_resolve) {
19763         return isolate->Throw<Cell>(
19764             isolate->factory()->NewSyntaxError(
19765                 MessageTemplate::kCyclicModuleDependency, name),
19766             &loc);
19767       }
19768       return MaybeHandle<Cell>();
19769     }
19770     name_set->insert(name);
19771   }
19772 
19773   if (object->IsModuleInfoEntry()) {
19774     // Not yet resolved indirect export.
19775     Handle<ModuleInfoEntry> entry = Handle<ModuleInfoEntry>::cast(object);
19776     Handle<String> import_name(String::cast(entry->import_name()), isolate);
19777     Handle<Script> script(
19778         Script::cast(JSFunction::cast(module->code())->shared()->script()),
19779         isolate);
19780     MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos());
19781 
19782     Handle<Cell> cell;
19783     if (!ResolveImport(module, import_name, entry->module_request(), new_loc,
19784                        true, resolve_set)
19785              .ToHandle(&cell)) {
19786       DCHECK(isolate->has_pending_exception());
19787       return MaybeHandle<Cell>();
19788     }
19789 
19790     // The export table may have changed but the entry in question should be
19791     // unchanged.
19792     Handle<ObjectHashTable> exports(module->exports(), isolate);
19793     DCHECK(exports->Lookup(name)->IsModuleInfoEntry());
19794 
19795     exports = ObjectHashTable::Put(exports, name, cell);
19796     module->set_exports(*exports);
19797     return cell;
19798   }
19799 
19800   DCHECK(object->IsTheHole(isolate));
19801   return Module::ResolveExportUsingStarExports(module, name, loc, must_resolve,
19802                                                resolve_set);
19803 }
19804 
ResolveExportUsingStarExports(Handle<Module> module,Handle<String> name,MessageLocation loc,bool must_resolve,Module::ResolveSet * resolve_set)19805 MaybeHandle<Cell> Module::ResolveExportUsingStarExports(
19806     Handle<Module> module, Handle<String> name, MessageLocation loc,
19807     bool must_resolve, Module::ResolveSet* resolve_set) {
19808   Isolate* isolate = module->GetIsolate();
19809   if (!name->Equals(isolate->heap()->default_string())) {
19810     // Go through all star exports looking for the given name.  If multiple star
19811     // exports provide the name, make sure they all map it to the same cell.
19812     Handle<Cell> unique_cell;
19813     Handle<FixedArray> special_exports(module->info()->special_exports(),
19814                                        isolate);
19815     for (int i = 0, n = special_exports->length(); i < n; ++i) {
19816       i::Handle<i::ModuleInfoEntry> entry(
19817           i::ModuleInfoEntry::cast(special_exports->get(i)), isolate);
19818       if (!entry->export_name()->IsUndefined(isolate)) {
19819         continue;  // Indirect export.
19820       }
19821 
19822       Handle<Script> script(
19823           Script::cast(JSFunction::cast(module->code())->shared()->script()),
19824           isolate);
19825       MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos());
19826 
19827       Handle<Cell> cell;
19828       if (ResolveImport(module, name, entry->module_request(), new_loc, false,
19829                         resolve_set)
19830               .ToHandle(&cell)) {
19831         if (unique_cell.is_null()) unique_cell = cell;
19832         if (*unique_cell != *cell) {
19833           return isolate->Throw<Cell>(
19834               isolate->factory()->NewSyntaxError(
19835                   MessageTemplate::kAmbiguousExport, name),
19836               &loc);
19837         }
19838       } else if (isolate->has_pending_exception()) {
19839         return MaybeHandle<Cell>();
19840       }
19841     }
19842 
19843     if (!unique_cell.is_null()) {
19844       // Found a unique star export for this name.
19845       Handle<ObjectHashTable> exports(module->exports(), isolate);
19846       DCHECK(exports->Lookup(name)->IsTheHole(isolate));
19847       exports = ObjectHashTable::Put(exports, name, unique_cell);
19848       module->set_exports(*exports);
19849       return unique_cell;
19850     }
19851   }
19852 
19853   // Unresolvable.
19854   if (must_resolve) {
19855     return isolate->Throw<Cell>(isolate->factory()->NewSyntaxError(
19856                                     MessageTemplate::kUnresolvableExport, name),
19857                                 &loc);
19858   }
19859   return MaybeHandle<Cell>();
19860 }
19861 
Instantiate(Handle<Module> module,v8::Local<v8::Context> context,v8::Module::ResolveCallback callback)19862 bool Module::Instantiate(Handle<Module> module, v8::Local<v8::Context> context,
19863                          v8::Module::ResolveCallback callback) {
19864   if (module->instantiated()) return true;
19865 
19866   Isolate* isolate = module->GetIsolate();
19867   Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(module->code()),
19868                                     isolate);
19869   Handle<JSFunction> function =
19870       isolate->factory()->NewFunctionFromSharedFunctionInfo(
19871           shared,
19872           handle(Utils::OpenHandle(*context)->native_context(), isolate));
19873   module->set_code(*function);
19874   DCHECK(module->instantiated());
19875 
19876   Handle<ModuleInfo> module_info(shared->scope_info()->ModuleDescriptorInfo(),
19877                                  isolate);
19878 
19879   // Set up local exports.
19880   // TODO(neis): Create regular_exports array here instead of in factory method?
19881   for (int i = 0, n = module_info->RegularExportCount(); i < n; ++i) {
19882     int cell_index = module_info->RegularExportCellIndex(i);
19883     Handle<FixedArray> export_names(module_info->RegularExportExportNames(i),
19884                                     isolate);
19885     CreateExport(module, cell_index, export_names);
19886   }
19887 
19888   // Partially set up indirect exports.
19889   // For each indirect export, we create the appropriate slot in the export
19890   // table and store its ModuleInfoEntry there.  When we later find the correct
19891   // Cell in the module that actually provides the value, we replace the
19892   // ModuleInfoEntry by that Cell (see ResolveExport).
19893   Handle<FixedArray> special_exports(module_info->special_exports(), isolate);
19894   for (int i = 0, n = special_exports->length(); i < n; ++i) {
19895     Handle<ModuleInfoEntry> entry(
19896         ModuleInfoEntry::cast(special_exports->get(i)), isolate);
19897     Handle<Object> export_name(entry->export_name(), isolate);
19898     if (export_name->IsUndefined(isolate)) continue;  // Star export.
19899     CreateIndirectExport(module, Handle<String>::cast(export_name), entry);
19900   }
19901 
19902   Handle<FixedArray> module_requests(module_info->module_requests(), isolate);
19903   for (int i = 0, length = module_requests->length(); i < length; ++i) {
19904     Handle<String> specifier(String::cast(module_requests->get(i)), isolate);
19905     v8::Local<v8::Module> api_requested_module;
19906     // TODO(adamk): Revisit these failure cases once d8 knows how to
19907     // persist a module_map across multiple top-level module loads, as
19908     // the current module is left in a "half-instantiated" state.
19909     if (!callback(context, v8::Utils::ToLocal(specifier),
19910                   v8::Utils::ToLocal(module))
19911              .ToLocal(&api_requested_module)) {
19912       // TODO(adamk): Give this a better error message. But this is a
19913       // misuse of the API anyway.
19914       isolate->ThrowIllegalOperation();
19915       return false;
19916     }
19917     Handle<Module> requested_module = Utils::OpenHandle(*api_requested_module);
19918     module->requested_modules()->set(i, *requested_module);
19919     if (!Instantiate(requested_module, context, callback)) {
19920       return false;
19921     }
19922   }
19923 
19924   Zone zone(isolate->allocator(), ZONE_NAME);
19925 
19926   // Resolve imports.
19927   Handle<FixedArray> regular_imports(module_info->regular_imports(), isolate);
19928   for (int i = 0, n = regular_imports->length(); i < n; ++i) {
19929     Handle<ModuleInfoEntry> entry(
19930         ModuleInfoEntry::cast(regular_imports->get(i)), isolate);
19931     Handle<String> name(String::cast(entry->import_name()), isolate);
19932     Handle<Script> script(
19933         Script::cast(JSFunction::cast(module->code())->shared()->script()),
19934         isolate);
19935     MessageLocation loc(script, entry->beg_pos(), entry->end_pos());
19936     ResolveSet resolve_set(&zone);
19937     Handle<Cell> cell;
19938     if (!ResolveImport(module, name, entry->module_request(), loc, true,
19939                        &resolve_set)
19940              .ToHandle(&cell)) {
19941       return false;
19942     }
19943     module->regular_imports()->set(ImportIndex(entry->cell_index()), *cell);
19944   }
19945 
19946   // Resolve indirect exports.
19947   for (int i = 0, n = special_exports->length(); i < n; ++i) {
19948     Handle<ModuleInfoEntry> entry(
19949         ModuleInfoEntry::cast(special_exports->get(i)), isolate);
19950     Handle<Object> name(entry->export_name(), isolate);
19951     if (name->IsUndefined(isolate)) continue;  // Star export.
19952     Handle<Script> script(
19953         Script::cast(JSFunction::cast(module->code())->shared()->script()),
19954         isolate);
19955     MessageLocation loc(script, entry->beg_pos(), entry->end_pos());
19956     ResolveSet resolve_set(&zone);
19957     if (ResolveExport(module, Handle<String>::cast(name), loc, true,
19958                       &resolve_set)
19959             .is_null()) {
19960       return false;
19961     }
19962   }
19963 
19964   return true;
19965 }
19966 
Evaluate(Handle<Module> module)19967 MaybeHandle<Object> Module::Evaluate(Handle<Module> module) {
19968   DCHECK(module->instantiated());
19969 
19970   // Each module can only be evaluated once.
19971   Isolate* isolate = module->GetIsolate();
19972   if (module->evaluated()) return isolate->factory()->undefined_value();
19973   Handle<JSFunction> function(JSFunction::cast(module->code()), isolate);
19974   module->set_evaluated();
19975 
19976   // Initialization.
19977   DCHECK_EQ(MODULE_SCOPE, function->shared()->scope_info()->scope_type());
19978   Handle<Object> receiver = isolate->factory()->undefined_value();
19979   Handle<Object> argv[] = {module};
19980   Handle<Object> generator;
19981   ASSIGN_RETURN_ON_EXCEPTION(
19982       isolate, generator,
19983       Execution::Call(isolate, function, receiver, arraysize(argv), argv),
19984       Object);
19985 
19986   // Recursion.
19987   Handle<FixedArray> requested_modules(module->requested_modules(), isolate);
19988   for (int i = 0, length = requested_modules->length(); i < length; ++i) {
19989     Handle<Module> import(Module::cast(requested_modules->get(i)), isolate);
19990     RETURN_ON_EXCEPTION(isolate, Evaluate(import), Object);
19991   }
19992 
19993   // Evaluation of module body.
19994   Handle<JSFunction> resume(
19995       isolate->native_context()->generator_next_internal(), isolate);
19996   return Execution::Call(isolate, resume, generator, 0, nullptr);
19997 }
19998 
19999 namespace {
20000 
FetchStarExports(Handle<Module> module,Zone * zone,UnorderedModuleSet * visited)20001 void FetchStarExports(Handle<Module> module, Zone* zone,
20002                       UnorderedModuleSet* visited) {
20003   DCHECK(module->instantiated());
20004 
20005   bool cycle = !visited->insert(module).second;
20006   if (cycle) return;
20007 
20008   Isolate* isolate = module->GetIsolate();
20009   Handle<ObjectHashTable> exports(module->exports(), isolate);
20010   UnorderedStringMap more_exports(zone);
20011 
20012   // TODO(neis): Only allocate more_exports if there are star exports.
20013   // Maybe split special_exports into indirect_exports and star_exports.
20014 
20015   Handle<FixedArray> special_exports(module->info()->special_exports(),
20016                                      isolate);
20017   for (int i = 0, n = special_exports->length(); i < n; ++i) {
20018     Handle<ModuleInfoEntry> entry(
20019         ModuleInfoEntry::cast(special_exports->get(i)), isolate);
20020     if (!entry->export_name()->IsUndefined(isolate)) {
20021       continue;  // Indirect export.
20022     }
20023 
20024     Handle<Module> requested_module(
20025         Module::cast(module->requested_modules()->get(entry->module_request())),
20026         isolate);
20027 
20028     // Recurse.
20029     FetchStarExports(requested_module, zone, visited);
20030 
20031     // Collect all of [requested_module]'s exports that must be added to
20032     // [module]'s exports (i.e. to [exports]).  We record these in
20033     // [more_exports].  Ambiguities (conflicting exports) are marked by mapping
20034     // the name to undefined instead of a Cell.
20035     Handle<ObjectHashTable> requested_exports(requested_module->exports(),
20036                                               isolate);
20037     for (int i = 0, n = requested_exports->Capacity(); i < n; ++i) {
20038       Handle<Object> key(requested_exports->KeyAt(i), isolate);
20039       if (!requested_exports->IsKey(isolate, *key)) continue;
20040       Handle<String> name = Handle<String>::cast(key);
20041 
20042       if (name->Equals(isolate->heap()->default_string())) continue;
20043       if (!exports->Lookup(name)->IsTheHole(isolate)) continue;
20044 
20045       Handle<Cell> cell(Cell::cast(requested_exports->ValueAt(i)), isolate);
20046       auto insert_result = more_exports.insert(std::make_pair(name, cell));
20047       if (!insert_result.second) {
20048         auto it = insert_result.first;
20049         if (*it->second == *cell || it->second->IsUndefined(isolate)) {
20050           // We already recorded this mapping before, or the name is already
20051           // known to be ambiguous.  In either case, there's nothing to do.
20052         } else {
20053           DCHECK(it->second->IsCell());
20054           // Different star exports provide different cells for this name, hence
20055           // mark the name as ambiguous.
20056           it->second = isolate->factory()->undefined_value();
20057         }
20058       }
20059     }
20060   }
20061 
20062   // Copy [more_exports] into [exports].
20063   for (const auto& elem : more_exports) {
20064     if (elem.second->IsUndefined(isolate)) continue;  // Ambiguous export.
20065     DCHECK(!elem.first->Equals(isolate->heap()->default_string()));
20066     DCHECK(elem.second->IsCell());
20067     exports = ObjectHashTable::Put(exports, elem.first, elem.second);
20068   }
20069   module->set_exports(*exports);
20070 }
20071 
20072 }  // anonymous namespace
20073 
GetModuleNamespace(Handle<Module> module,int module_request)20074 Handle<JSModuleNamespace> Module::GetModuleNamespace(Handle<Module> module,
20075                                                      int module_request) {
20076   Isolate* isolate = module->GetIsolate();
20077   Handle<Module> requested_module(
20078       Module::cast(module->requested_modules()->get(module_request)), isolate);
20079   return Module::GetModuleNamespace(requested_module);
20080 }
20081 
GetModuleNamespace(Handle<Module> module)20082 Handle<JSModuleNamespace> Module::GetModuleNamespace(Handle<Module> module) {
20083   Isolate* isolate = module->GetIsolate();
20084 
20085   Handle<HeapObject> object(module->module_namespace(), isolate);
20086   if (!object->IsUndefined(isolate)) {
20087     // Namespace object already exists.
20088     return Handle<JSModuleNamespace>::cast(object);
20089   }
20090 
20091   // Create the namespace object (initially empty).
20092   Handle<JSModuleNamespace> ns = isolate->factory()->NewJSModuleNamespace();
20093   ns->set_module(*module);
20094   module->set_module_namespace(*ns);
20095 
20096   // Collect the export names.
20097   Zone zone(isolate->allocator(), ZONE_NAME);
20098   UnorderedModuleSet visited(&zone);
20099   FetchStarExports(module, &zone, &visited);
20100   Handle<ObjectHashTable> exports(module->exports(), isolate);
20101   ZoneVector<Handle<String>> names(&zone);
20102   names.reserve(exports->NumberOfElements());
20103   for (int i = 0, n = exports->Capacity(); i < n; ++i) {
20104     Handle<Object> key(exports->KeyAt(i), isolate);
20105     if (!exports->IsKey(isolate, *key)) continue;
20106     DCHECK(exports->ValueAt(i)->IsCell());
20107     names.push_back(Handle<String>::cast(key));
20108   }
20109   DCHECK_EQ(static_cast<int>(names.size()), exports->NumberOfElements());
20110 
20111   // Sort them alphabetically.
20112   struct {
20113     bool operator()(Handle<String> a, Handle<String> b) {
20114       return String::Compare(a, b) == ComparisonResult::kLessThan;
20115     }
20116   } StringLess;
20117   std::sort(names.begin(), names.end(), StringLess);
20118 
20119   // Create the corresponding properties in the namespace object.
20120   PropertyAttributes attr = DONT_DELETE;
20121   for (const auto& name : names) {
20122     JSObject::SetAccessor(
20123         ns, Accessors::ModuleNamespaceEntryInfo(isolate, name, attr))
20124         .Check();
20125   }
20126   JSObject::PreventExtensions(ns, THROW_ON_ERROR).ToChecked();
20127 
20128   return ns;
20129 }
20130 
TryGetCachedPropertyName(Isolate * isolate,Handle<Object> getter)20131 MaybeHandle<Name> FunctionTemplateInfo::TryGetCachedPropertyName(
20132     Isolate* isolate, Handle<Object> getter) {
20133   if (getter->IsFunctionTemplateInfo()) {
20134     Handle<FunctionTemplateInfo> fti =
20135         Handle<FunctionTemplateInfo>::cast(getter);
20136     // Check if the accessor uses a cached property.
20137     if (!fti->cached_property_name()->IsTheHole(isolate)) {
20138       return handle(Name::cast(fti->cached_property_name()));
20139     }
20140   }
20141   return MaybeHandle<Name>();
20142 }
20143 
20144 // static
ElementsKindForInstanceType(InstanceType type)20145 ElementsKind JSArrayIterator::ElementsKindForInstanceType(InstanceType type) {
20146   DCHECK_GE(type, FIRST_ARRAY_ITERATOR_TYPE);
20147   DCHECK_LE(type, LAST_ARRAY_ITERATOR_TYPE);
20148 
20149   if (type <= LAST_ARRAY_KEY_ITERATOR_TYPE) {
20150     // Should be ignored for key iterators.
20151     return FAST_ELEMENTS;
20152   } else {
20153     ElementsKind kind;
20154     if (type < FIRST_ARRAY_VALUE_ITERATOR_TYPE) {
20155       // Convert `type` to a value iterator from an entries iterator
20156       type = static_cast<InstanceType>(type +
20157                                        (FIRST_ARRAY_VALUE_ITERATOR_TYPE -
20158                                         FIRST_ARRAY_KEY_VALUE_ITERATOR_TYPE));
20159       DCHECK_GE(type, FIRST_ARRAY_VALUE_ITERATOR_TYPE);
20160       DCHECK_LE(type, LAST_ARRAY_ITERATOR_TYPE);
20161     }
20162 
20163     if (type <= JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE) {
20164       kind =
20165           static_cast<ElementsKind>(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND +
20166                                     (type - FIRST_ARRAY_VALUE_ITERATOR_TYPE));
20167       DCHECK_LE(kind, LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
20168     } else if (type < JS_GENERIC_ARRAY_VALUE_ITERATOR_TYPE) {
20169       kind = static_cast<ElementsKind>(
20170           FIRST_FAST_ELEMENTS_KIND +
20171           (type - JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE));
20172       DCHECK_LE(kind, LAST_FAST_ELEMENTS_KIND);
20173     } else {
20174       // For any slow element cases, the actual elements kind is not known.
20175       // Simply
20176       // return a slow elements kind in this case. Users of this function must
20177       // not
20178       // depend on this.
20179       return DICTIONARY_ELEMENTS;
20180     }
20181     DCHECK_LE(kind, LAST_ELEMENTS_KIND);
20182     return kind;
20183   }
20184 }
20185 
20186 }  // namespace internal
20187 }  // namespace v8
20188