• 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/base/bits.h"
22 #include "src/base/utils/random-number-generator.h"
23 #include "src/bootstrapper.h"
24 #include "src/code-stubs.h"
25 #include "src/codegen.h"
26 #include "src/compilation-dependencies.h"
27 #include "src/compiler.h"
28 #include "src/counters-inl.h"
29 #include "src/counters.h"
30 #include "src/date.h"
31 #include "src/debug/debug.h"
32 #include "src/deoptimizer.h"
33 #include "src/elements.h"
34 #include "src/execution.h"
35 #include "src/field-index-inl.h"
36 #include "src/field-index.h"
37 #include "src/field-type.h"
38 #include "src/frames-inl.h"
39 #include "src/full-codegen/full-codegen.h"
40 #include "src/globals.h"
41 #include "src/ic/ic.h"
42 #include "src/identity-map.h"
43 #include "src/interpreter/bytecode-array-iterator.h"
44 #include "src/interpreter/bytecode-decoder.h"
45 #include "src/interpreter/interpreter.h"
46 #include "src/isolate-inl.h"
47 #include "src/keys.h"
48 #include "src/list.h"
49 #include "src/log.h"
50 #include "src/lookup.h"
51 #include "src/macro-assembler.h"
52 #include "src/messages.h"
53 #include "src/objects-body-descriptors-inl.h"
54 #include "src/property-descriptor.h"
55 #include "src/prototype.h"
56 #include "src/regexp/jsregexp.h"
57 #include "src/safepoint-table.h"
58 #include "src/snapshot/code-serializer.h"
59 #include "src/source-position-table.h"
60 #include "src/string-builder.h"
61 #include "src/string-search.h"
62 #include "src/string-stream.h"
63 #include "src/utils.h"
64 #include "src/wasm/wasm-module.h"
65 #include "src/wasm/wasm-objects.h"
66 #include "src/zone/zone.h"
67 
68 #ifdef ENABLE_DISASSEMBLER
69 #include "src/disasm.h"
70 #include "src/disassembler.h"
71 #include "src/eh-frame.h"
72 #endif
73 
74 namespace v8 {
75 namespace internal {
76 
operator <<(std::ostream & os,InstanceType instance_type)77 std::ostream& operator<<(std::ostream& os, InstanceType instance_type) {
78   switch (instance_type) {
79 #define WRITE_TYPE(TYPE) \
80   case TYPE:             \
81     return os << #TYPE;
82     INSTANCE_TYPE_LIST(WRITE_TYPE)
83 #undef WRITE_TYPE
84   }
85   UNREACHABLE();
86   return os << "UNKNOWN";  // Keep the compiler happy.
87 }
88 
OptimalType(Isolate * isolate,Representation representation)89 Handle<FieldType> Object::OptimalType(Isolate* isolate,
90                                       Representation representation) {
91   if (representation.IsNone()) return FieldType::None(isolate);
92   if (FLAG_track_field_types) {
93     if (representation.IsHeapObject() && IsHeapObject()) {
94       // We can track only JavaScript objects with stable maps.
95       Handle<Map> map(HeapObject::cast(this)->map(), isolate);
96       if (map->is_stable() && map->IsJSReceiverMap()) {
97         return FieldType::Class(map, isolate);
98       }
99     }
100   }
101   return FieldType::Any(isolate);
102 }
103 
104 
ToObject(Isolate * isolate,Handle<Object> object,Handle<Context> native_context)105 MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
106                                          Handle<Object> object,
107                                          Handle<Context> native_context) {
108   if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
109   Handle<JSFunction> constructor;
110   if (object->IsSmi()) {
111     constructor = handle(native_context->number_function(), isolate);
112   } else {
113     int constructor_function_index =
114         Handle<HeapObject>::cast(object)->map()->GetConstructorFunctionIndex();
115     if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
116       THROW_NEW_ERROR(isolate,
117                       NewTypeError(MessageTemplate::kUndefinedOrNullToObject),
118                       JSReceiver);
119     }
120     constructor = handle(
121         JSFunction::cast(native_context->get(constructor_function_index)),
122         isolate);
123   }
124   Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
125   Handle<JSValue>::cast(result)->set_value(*object);
126   return result;
127 }
128 
129 // ES6 section 9.2.1.2, OrdinaryCallBindThis for sloppy callee.
130 // static
ConvertReceiver(Isolate * isolate,Handle<Object> object)131 MaybeHandle<JSReceiver> Object::ConvertReceiver(Isolate* isolate,
132                                                 Handle<Object> object) {
133   if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
134   if (*object == isolate->heap()->null_value() ||
135       object->IsUndefined(isolate)) {
136     return isolate->global_proxy();
137   }
138   return Object::ToObject(isolate, object);
139 }
140 
141 // static
ToNumber(Handle<Object> input)142 MaybeHandle<Object> Object::ToNumber(Handle<Object> input) {
143   while (true) {
144     if (input->IsNumber()) {
145       return input;
146     }
147     if (input->IsString()) {
148       return String::ToNumber(Handle<String>::cast(input));
149     }
150     if (input->IsOddball()) {
151       return Oddball::ToNumber(Handle<Oddball>::cast(input));
152     }
153     Isolate* const isolate = Handle<HeapObject>::cast(input)->GetIsolate();
154     if (input->IsSymbol()) {
155       THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber),
156                       Object);
157     }
158     if (input->IsSimd128Value()) {
159       THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSimdToNumber),
160                       Object);
161     }
162     ASSIGN_RETURN_ON_EXCEPTION(
163         isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
164                                                 ToPrimitiveHint::kNumber),
165         Object);
166   }
167 }
168 
169 
170 // static
ToInteger(Isolate * isolate,Handle<Object> input)171 MaybeHandle<Object> Object::ToInteger(Isolate* isolate, Handle<Object> input) {
172   ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
173   return isolate->factory()->NewNumber(DoubleToInteger(input->Number()));
174 }
175 
176 
177 // static
ToInt32(Isolate * isolate,Handle<Object> input)178 MaybeHandle<Object> Object::ToInt32(Isolate* isolate, Handle<Object> input) {
179   ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
180   return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number()));
181 }
182 
183 
184 // static
ToUint32(Isolate * isolate,Handle<Object> input)185 MaybeHandle<Object> Object::ToUint32(Isolate* isolate, Handle<Object> input) {
186   ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
187   return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number()));
188 }
189 
190 
191 // static
ConvertToName(Isolate * isolate,Handle<Object> input)192 MaybeHandle<Name> Object::ConvertToName(Isolate* isolate,
193                                         Handle<Object> input) {
194   ASSIGN_RETURN_ON_EXCEPTION(
195       isolate, input, Object::ToPrimitive(input, ToPrimitiveHint::kString),
196       Name);
197   if (input->IsName()) return Handle<Name>::cast(input);
198   return ToString(isolate, input);
199 }
200 
201 // static
ToString(Isolate * isolate,Handle<Object> input)202 MaybeHandle<String> Object::ToString(Isolate* isolate, Handle<Object> input) {
203   while (true) {
204     if (input->IsString()) {
205       return Handle<String>::cast(input);
206     }
207     if (input->IsOddball()) {
208       return handle(Handle<Oddball>::cast(input)->to_string(), isolate);
209     }
210     if (input->IsNumber()) {
211       return isolate->factory()->NumberToString(input);
212     }
213     if (input->IsSymbol()) {
214       THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToString),
215                       String);
216     }
217     if (input->IsSimd128Value()) {
218       return Simd128Value::ToString(Handle<Simd128Value>::cast(input));
219     }
220     ASSIGN_RETURN_ON_EXCEPTION(
221         isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
222                                                 ToPrimitiveHint::kString),
223         String);
224   }
225 }
226 
227 namespace {
228 
IsErrorObject(Isolate * isolate,Handle<Object> object)229 bool IsErrorObject(Isolate* isolate, Handle<Object> object) {
230   if (!object->IsJSReceiver()) return false;
231   Handle<Symbol> symbol = isolate->factory()->stack_trace_symbol();
232   return JSReceiver::HasOwnProperty(Handle<JSReceiver>::cast(object), symbol)
233       .FromMaybe(false);
234 }
235 
AsStringOrEmpty(Isolate * isolate,Handle<Object> object)236 Handle<String> AsStringOrEmpty(Isolate* isolate, Handle<Object> object) {
237   return object->IsString() ? Handle<String>::cast(object)
238                             : isolate->factory()->empty_string();
239 }
240 
NoSideEffectsErrorToString(Isolate * isolate,Handle<Object> input)241 Handle<String> NoSideEffectsErrorToString(Isolate* isolate,
242                                           Handle<Object> input) {
243   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input);
244 
245   Handle<Name> name_key = isolate->factory()->name_string();
246   Handle<Object> name = JSReceiver::GetDataProperty(receiver, name_key);
247   Handle<String> name_str = AsStringOrEmpty(isolate, name);
248 
249   Handle<Name> msg_key = isolate->factory()->message_string();
250   Handle<Object> msg = JSReceiver::GetDataProperty(receiver, msg_key);
251   Handle<String> msg_str = AsStringOrEmpty(isolate, msg);
252 
253   if (name_str->length() == 0) return msg_str;
254   if (msg_str->length() == 0) return name_str;
255 
256   IncrementalStringBuilder builder(isolate);
257   builder.AppendString(name_str);
258   builder.AppendCString(": ");
259   builder.AppendString(msg_str);
260 
261   return builder.Finish().ToHandleChecked();
262 }
263 
264 }  // namespace
265 
266 // static
NoSideEffectsToString(Isolate * isolate,Handle<Object> input)267 Handle<String> Object::NoSideEffectsToString(Isolate* isolate,
268                                              Handle<Object> input) {
269   DisallowJavascriptExecution no_js(isolate);
270 
271   if (input->IsString() || input->IsNumber() || input->IsOddball() ||
272       input->IsSimd128Value()) {
273     return Object::ToString(isolate, input).ToHandleChecked();
274   } else if (input->IsFunction()) {
275     // -- F u n c t i o n
276     Handle<String> fun_str;
277     if (input->IsJSBoundFunction()) {
278       fun_str = JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(input));
279     } else {
280       DCHECK(input->IsJSFunction());
281       fun_str = JSFunction::ToString(Handle<JSFunction>::cast(input));
282     }
283 
284     if (fun_str->length() > 128) {
285       IncrementalStringBuilder builder(isolate);
286       builder.AppendString(isolate->factory()->NewSubString(fun_str, 0, 111));
287       builder.AppendCString("...<omitted>...");
288       builder.AppendString(isolate->factory()->NewSubString(
289           fun_str, fun_str->length() - 2, fun_str->length()));
290 
291       return builder.Finish().ToHandleChecked();
292     }
293     return fun_str;
294   } else if (input->IsSymbol()) {
295     // -- S y m b o l
296     Handle<Symbol> symbol = Handle<Symbol>::cast(input);
297 
298     IncrementalStringBuilder builder(isolate);
299     builder.AppendCString("Symbol(");
300     if (symbol->name()->IsString()) {
301       builder.AppendString(handle(String::cast(symbol->name()), isolate));
302     }
303     builder.AppendCharacter(')');
304 
305     return builder.Finish().ToHandleChecked();
306   } else if (input->IsJSReceiver()) {
307     // -- J S R e c e i v e r
308     Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input);
309     Handle<Object> to_string = JSReceiver::GetDataProperty(
310         receiver, isolate->factory()->toString_string());
311 
312     if (IsErrorObject(isolate, input) ||
313         *to_string == *isolate->error_to_string()) {
314       // When internally formatting error objects, use a side-effects-free
315       // version of Error.prototype.toString independent of the actually
316       // installed toString method.
317       return NoSideEffectsErrorToString(isolate, input);
318     } else if (*to_string == *isolate->object_to_string()) {
319       Handle<Object> ctor = JSReceiver::GetDataProperty(
320           receiver, isolate->factory()->constructor_string());
321       if (ctor->IsFunction()) {
322         Handle<String> ctor_name;
323         if (ctor->IsJSBoundFunction()) {
324           ctor_name = JSBoundFunction::GetName(
325                           isolate, Handle<JSBoundFunction>::cast(ctor))
326                           .ToHandleChecked();
327         } else if (ctor->IsJSFunction()) {
328           Handle<Object> ctor_name_obj =
329               JSFunction::GetName(isolate, Handle<JSFunction>::cast(ctor));
330           ctor_name = AsStringOrEmpty(isolate, ctor_name_obj);
331         }
332 
333         if (ctor_name->length() != 0) {
334           IncrementalStringBuilder builder(isolate);
335           builder.AppendCString("#<");
336           builder.AppendString(ctor_name);
337           builder.AppendCString(">");
338 
339           return builder.Finish().ToHandleChecked();
340         }
341       }
342     }
343   }
344 
345   // At this point, input is either none of the above or a JSReceiver.
346 
347   Handle<JSReceiver> receiver;
348   if (input->IsJSReceiver()) {
349     receiver = Handle<JSReceiver>::cast(input);
350   } else {
351     // This is the only case where Object::ToObject throws.
352     DCHECK(!input->IsSmi());
353     int constructor_function_index =
354         Handle<HeapObject>::cast(input)->map()->GetConstructorFunctionIndex();
355     if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
356       return isolate->factory()->NewStringFromAsciiChecked("[object Unknown]");
357     }
358 
359     receiver = Object::ToObject(isolate, input, isolate->native_context())
360                    .ToHandleChecked();
361   }
362 
363   Handle<String> builtin_tag = handle(receiver->class_name(), isolate);
364   Handle<Object> tag_obj = JSReceiver::GetDataProperty(
365       receiver, isolate->factory()->to_string_tag_symbol());
366   Handle<String> tag =
367       tag_obj->IsString() ? Handle<String>::cast(tag_obj) : builtin_tag;
368 
369   IncrementalStringBuilder builder(isolate);
370   builder.AppendCString("[object ");
371   builder.AppendString(tag);
372   builder.AppendCString("]");
373 
374   return builder.Finish().ToHandleChecked();
375 }
376 
377 // static
ToLength(Isolate * isolate,Handle<Object> input)378 MaybeHandle<Object> Object::ToLength(Isolate* isolate, Handle<Object> input) {
379   ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
380   double len = DoubleToInteger(input->Number());
381   if (len <= 0.0) {
382     len = 0.0;
383   } else if (len >= kMaxSafeInteger) {
384     len = kMaxSafeInteger;
385   }
386   return isolate->factory()->NewNumber(len);
387 }
388 
389 // static
ToIndex(Isolate * isolate,Handle<Object> input,MessageTemplate::Template error_index)390 MaybeHandle<Object> Object::ToIndex(Isolate* isolate, Handle<Object> input,
391                                     MessageTemplate::Template error_index) {
392   if (input->IsUndefined(isolate)) return isolate->factory()->NewNumber(0.0);
393   ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
394   double len = DoubleToInteger(input->Number()) + 0.0;
395   auto js_len = isolate->factory()->NewNumber(len);
396   if (len < 0.0 || len > kMaxSafeInteger) {
397     THROW_NEW_ERROR(isolate, NewRangeError(error_index, js_len), Object);
398   }
399   return js_len;
400 }
401 
BooleanValue()402 bool Object::BooleanValue() {
403   if (IsSmi()) return Smi::cast(this)->value() != 0;
404   DCHECK(IsHeapObject());
405   Isolate* isolate = HeapObject::cast(this)->GetIsolate();
406   if (IsBoolean()) return IsTrue(isolate);
407   if (IsUndefined(isolate) || IsNull(isolate)) return false;
408   if (IsUndetectable()) return false;  // Undetectable object is false.
409   if (IsString()) return String::cast(this)->length() != 0;
410   if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue();
411   return true;
412 }
413 
414 
415 namespace {
416 
417 // TODO(bmeurer): Maybe we should introduce a marker interface Number,
418 // where we put all these methods at some point?
NumberCompare(double x,double y)419 ComparisonResult NumberCompare(double x, double y) {
420   if (std::isnan(x) || std::isnan(y)) {
421     return ComparisonResult::kUndefined;
422   } else if (x < y) {
423     return ComparisonResult::kLessThan;
424   } else if (x > y) {
425     return ComparisonResult::kGreaterThan;
426   } else {
427     return ComparisonResult::kEqual;
428   }
429 }
430 
431 
NumberEquals(double x,double y)432 bool NumberEquals(double x, double y) {
433   // Must check explicitly for NaN's on Windows, but -0 works fine.
434   if (std::isnan(x)) return false;
435   if (std::isnan(y)) return false;
436   return x == y;
437 }
438 
439 
NumberEquals(const Object * x,const Object * y)440 bool NumberEquals(const Object* x, const Object* y) {
441   return NumberEquals(x->Number(), y->Number());
442 }
443 
444 
NumberEquals(Handle<Object> x,Handle<Object> y)445 bool NumberEquals(Handle<Object> x, Handle<Object> y) {
446   return NumberEquals(*x, *y);
447 }
448 
449 }  // namespace
450 
451 
452 // static
Compare(Handle<Object> x,Handle<Object> y)453 Maybe<ComparisonResult> Object::Compare(Handle<Object> x, Handle<Object> y) {
454   // ES6 section 7.2.11 Abstract Relational Comparison step 3 and 4.
455   if (!Object::ToPrimitive(x, ToPrimitiveHint::kNumber).ToHandle(&x) ||
456       !Object::ToPrimitive(y, ToPrimitiveHint::kNumber).ToHandle(&y)) {
457     return Nothing<ComparisonResult>();
458   }
459   if (x->IsString() && y->IsString()) {
460     // ES6 section 7.2.11 Abstract Relational Comparison step 5.
461     return Just(
462         String::Compare(Handle<String>::cast(x), Handle<String>::cast(y)));
463   }
464   // ES6 section 7.2.11 Abstract Relational Comparison step 6.
465   if (!Object::ToNumber(x).ToHandle(&x) || !Object::ToNumber(y).ToHandle(&y)) {
466     return Nothing<ComparisonResult>();
467   }
468   return Just(NumberCompare(x->Number(), y->Number()));
469 }
470 
471 
472 // static
Equals(Handle<Object> x,Handle<Object> y)473 Maybe<bool> Object::Equals(Handle<Object> x, Handle<Object> y) {
474   // This is the generic version of Abstract Equality Comparison; a version in
475   // JavaScript land is available in the EqualStub and NotEqualStub. Whenever
476   // you change something functionality wise in here, remember to update the
477   // TurboFan code stubs as well.
478   while (true) {
479     if (x->IsNumber()) {
480       if (y->IsNumber()) {
481         return Just(NumberEquals(x, y));
482       } else if (y->IsBoolean()) {
483         return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
484       } else if (y->IsString()) {
485         return Just(NumberEquals(x, String::ToNumber(Handle<String>::cast(y))));
486       } else if (y->IsJSReceiver()) {
487         if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
488                  .ToHandle(&y)) {
489           return Nothing<bool>();
490         }
491       } else {
492         return Just(false);
493       }
494     } else if (x->IsString()) {
495       if (y->IsString()) {
496         return Just(
497             String::Equals(Handle<String>::cast(x), Handle<String>::cast(y)));
498       } else if (y->IsNumber()) {
499         x = String::ToNumber(Handle<String>::cast(x));
500         return Just(NumberEquals(x, y));
501       } else if (y->IsBoolean()) {
502         x = String::ToNumber(Handle<String>::cast(x));
503         return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
504       } else if (y->IsJSReceiver()) {
505         if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
506                  .ToHandle(&y)) {
507           return Nothing<bool>();
508         }
509       } else {
510         return Just(false);
511       }
512     } else if (x->IsBoolean()) {
513       if (y->IsOddball()) {
514         return Just(x.is_identical_to(y));
515       } else if (y->IsNumber()) {
516         return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
517       } else if (y->IsString()) {
518         y = String::ToNumber(Handle<String>::cast(y));
519         return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
520       } else if (y->IsJSReceiver()) {
521         if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
522                  .ToHandle(&y)) {
523           return Nothing<bool>();
524         }
525         x = Oddball::ToNumber(Handle<Oddball>::cast(x));
526       } else {
527         return Just(false);
528       }
529     } else if (x->IsSymbol()) {
530       if (y->IsSymbol()) {
531         return Just(x.is_identical_to(y));
532       } else if (y->IsJSReceiver()) {
533         if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
534                  .ToHandle(&y)) {
535           return Nothing<bool>();
536         }
537       } else {
538         return Just(false);
539       }
540     } else if (x->IsSimd128Value()) {
541       if (y->IsSimd128Value()) {
542         return Just(Simd128Value::Equals(Handle<Simd128Value>::cast(x),
543                                          Handle<Simd128Value>::cast(y)));
544       } else if (y->IsJSReceiver()) {
545         if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
546                  .ToHandle(&y)) {
547           return Nothing<bool>();
548         }
549       } else {
550         return Just(false);
551       }
552     } else if (x->IsJSReceiver()) {
553       if (y->IsJSReceiver()) {
554         return Just(x.is_identical_to(y));
555       } else if (y->IsUndetectable()) {
556         return Just(x->IsUndetectable());
557       } else if (y->IsBoolean()) {
558         y = Oddball::ToNumber(Handle<Oddball>::cast(y));
559       } else if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(x))
560                       .ToHandle(&x)) {
561         return Nothing<bool>();
562       }
563     } else {
564       return Just(x->IsUndetectable() && y->IsUndetectable());
565     }
566   }
567 }
568 
569 
StrictEquals(Object * that)570 bool Object::StrictEquals(Object* that) {
571   if (this->IsNumber()) {
572     if (!that->IsNumber()) return false;
573     return NumberEquals(this, that);
574   } else if (this->IsString()) {
575     if (!that->IsString()) return false;
576     return String::cast(this)->Equals(String::cast(that));
577   } else if (this->IsSimd128Value()) {
578     if (!that->IsSimd128Value()) return false;
579     return Simd128Value::cast(this)->Equals(Simd128Value::cast(that));
580   }
581   return this == that;
582 }
583 
584 
585 // static
TypeOf(Isolate * isolate,Handle<Object> object)586 Handle<String> Object::TypeOf(Isolate* isolate, Handle<Object> object) {
587   if (object->IsNumber()) return isolate->factory()->number_string();
588   if (object->IsOddball()) return handle(Oddball::cast(*object)->type_of());
589   if (object->IsUndetectable()) {
590     return isolate->factory()->undefined_string();
591   }
592   if (object->IsString()) return isolate->factory()->string_string();
593   if (object->IsSymbol()) return isolate->factory()->symbol_string();
594   if (object->IsString()) return isolate->factory()->string_string();
595 #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
596   if (object->Is##Type()) return isolate->factory()->type##_string();
597   SIMD128_TYPES(SIMD128_TYPE)
598 #undef SIMD128_TYPE
599   if (object->IsCallable()) return isolate->factory()->function_string();
600   return isolate->factory()->object_string();
601 }
602 
603 
604 // static
Multiply(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)605 MaybeHandle<Object> Object::Multiply(Isolate* isolate, Handle<Object> lhs,
606                                      Handle<Object> rhs) {
607   if (!lhs->IsNumber() || !rhs->IsNumber()) {
608     ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
609     ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
610   }
611   return isolate->factory()->NewNumber(lhs->Number() * rhs->Number());
612 }
613 
614 
615 // static
Divide(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)616 MaybeHandle<Object> Object::Divide(Isolate* isolate, Handle<Object> lhs,
617                                    Handle<Object> rhs) {
618   if (!lhs->IsNumber() || !rhs->IsNumber()) {
619     ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
620     ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
621   }
622   return isolate->factory()->NewNumber(lhs->Number() / rhs->Number());
623 }
624 
625 
626 // static
Modulus(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)627 MaybeHandle<Object> Object::Modulus(Isolate* isolate, Handle<Object> lhs,
628                                     Handle<Object> rhs) {
629   if (!lhs->IsNumber() || !rhs->IsNumber()) {
630     ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
631     ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
632   }
633   return isolate->factory()->NewNumber(modulo(lhs->Number(), rhs->Number()));
634 }
635 
636 
637 // static
Add(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)638 MaybeHandle<Object> Object::Add(Isolate* isolate, Handle<Object> lhs,
639                                 Handle<Object> rhs) {
640   if (lhs->IsNumber() && rhs->IsNumber()) {
641     return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
642   } else if (lhs->IsString() && rhs->IsString()) {
643     return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
644                                              Handle<String>::cast(rhs));
645   }
646   ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToPrimitive(lhs), Object);
647   ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToPrimitive(rhs), Object);
648   if (lhs->IsString() || rhs->IsString()) {
649     ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToString(isolate, rhs),
650                                Object);
651     ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToString(isolate, lhs),
652                                Object);
653     return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
654                                              Handle<String>::cast(rhs));
655   }
656   ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
657   ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
658   return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
659 }
660 
661 
662 // static
Subtract(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)663 MaybeHandle<Object> Object::Subtract(Isolate* isolate, Handle<Object> lhs,
664                                      Handle<Object> rhs) {
665   if (!lhs->IsNumber() || !rhs->IsNumber()) {
666     ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
667     ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
668   }
669   return isolate->factory()->NewNumber(lhs->Number() - rhs->Number());
670 }
671 
672 
673 // static
ShiftLeft(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)674 MaybeHandle<Object> Object::ShiftLeft(Isolate* isolate, Handle<Object> lhs,
675                                       Handle<Object> rhs) {
676   if (!lhs->IsNumber() || !rhs->IsNumber()) {
677     ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
678     ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
679   }
680   return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs)
681                                               << (NumberToUint32(*rhs) & 0x1F));
682 }
683 
684 
685 // static
ShiftRight(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)686 MaybeHandle<Object> Object::ShiftRight(Isolate* isolate, Handle<Object> lhs,
687                                        Handle<Object> rhs) {
688   if (!lhs->IsNumber() || !rhs->IsNumber()) {
689     ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
690     ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
691   }
692   return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) >>
693                                               (NumberToUint32(*rhs) & 0x1F));
694 }
695 
696 
697 // static
ShiftRightLogical(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)698 MaybeHandle<Object> Object::ShiftRightLogical(Isolate* isolate,
699                                               Handle<Object> lhs,
700                                               Handle<Object> rhs) {
701   if (!lhs->IsNumber() || !rhs->IsNumber()) {
702     ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
703     ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
704   }
705   return isolate->factory()->NewNumberFromUint(NumberToUint32(*lhs) >>
706                                                (NumberToUint32(*rhs) & 0x1F));
707 }
708 
709 
710 // static
BitwiseAnd(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)711 MaybeHandle<Object> Object::BitwiseAnd(Isolate* isolate, Handle<Object> lhs,
712                                        Handle<Object> rhs) {
713   if (!lhs->IsNumber() || !rhs->IsNumber()) {
714     ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
715     ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
716   }
717   return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) &
718                                               NumberToInt32(*rhs));
719 }
720 
721 
722 // static
BitwiseOr(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)723 MaybeHandle<Object> Object::BitwiseOr(Isolate* isolate, Handle<Object> lhs,
724                                       Handle<Object> rhs) {
725   if (!lhs->IsNumber() || !rhs->IsNumber()) {
726     ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
727     ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
728   }
729   return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) |
730                                               NumberToInt32(*rhs));
731 }
732 
733 
734 // static
BitwiseXor(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)735 MaybeHandle<Object> Object::BitwiseXor(Isolate* isolate, Handle<Object> lhs,
736                                        Handle<Object> rhs) {
737   if (!lhs->IsNumber() || !rhs->IsNumber()) {
738     ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
739     ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
740   }
741   return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) ^
742                                               NumberToInt32(*rhs));
743 }
744 
745 // static
OrdinaryHasInstance(Isolate * isolate,Handle<Object> callable,Handle<Object> object)746 MaybeHandle<Object> Object::OrdinaryHasInstance(Isolate* isolate,
747                                                 Handle<Object> callable,
748                                                 Handle<Object> object) {
749   // The {callable} must have a [[Call]] internal method.
750   if (!callable->IsCallable()) return isolate->factory()->false_value();
751 
752   // Check if {callable} is a bound function, and if so retrieve its
753   // [[BoundTargetFunction]] and use that instead of {callable}.
754   if (callable->IsJSBoundFunction()) {
755     Handle<Object> bound_callable(
756         Handle<JSBoundFunction>::cast(callable)->bound_target_function(),
757         isolate);
758     return Object::InstanceOf(isolate, object, bound_callable);
759   }
760 
761   // If {object} is not a receiver, return false.
762   if (!object->IsJSReceiver()) return isolate->factory()->false_value();
763 
764   // Get the "prototype" of {callable}; raise an error if it's not a receiver.
765   Handle<Object> prototype;
766   ASSIGN_RETURN_ON_EXCEPTION(
767       isolate, prototype,
768       Object::GetProperty(callable, isolate->factory()->prototype_string()),
769       Object);
770   if (!prototype->IsJSReceiver()) {
771     THROW_NEW_ERROR(
772         isolate,
773         NewTypeError(MessageTemplate::kInstanceofNonobjectProto, prototype),
774         Object);
775   }
776 
777   // Return whether or not {prototype} is in the prototype chain of {object}.
778   Maybe<bool> result = JSReceiver::HasInPrototypeChain(
779       isolate, Handle<JSReceiver>::cast(object), prototype);
780   if (result.IsNothing()) return MaybeHandle<Object>();
781   return isolate->factory()->ToBoolean(result.FromJust());
782 }
783 
784 // static
InstanceOf(Isolate * isolate,Handle<Object> object,Handle<Object> callable)785 MaybeHandle<Object> Object::InstanceOf(Isolate* isolate, Handle<Object> object,
786                                        Handle<Object> callable) {
787   // The {callable} must be a receiver.
788   if (!callable->IsJSReceiver()) {
789     THROW_NEW_ERROR(isolate,
790                     NewTypeError(MessageTemplate::kNonObjectInInstanceOfCheck),
791                     Object);
792   }
793 
794   // Lookup the @@hasInstance method on {callable}.
795   Handle<Object> inst_of_handler;
796   ASSIGN_RETURN_ON_EXCEPTION(
797       isolate, inst_of_handler,
798       JSReceiver::GetMethod(Handle<JSReceiver>::cast(callable),
799                             isolate->factory()->has_instance_symbol()),
800       Object);
801   if (!inst_of_handler->IsUndefined(isolate)) {
802     // Call the {inst_of_handler} on the {callable}.
803     Handle<Object> result;
804     ASSIGN_RETURN_ON_EXCEPTION(
805         isolate, result,
806         Execution::Call(isolate, inst_of_handler, callable, 1, &object),
807         Object);
808     return isolate->factory()->ToBoolean(result->BooleanValue());
809   }
810 
811   // The {callable} must have a [[Call]] internal method.
812   if (!callable->IsCallable()) {
813     THROW_NEW_ERROR(
814         isolate, NewTypeError(MessageTemplate::kNonCallableInInstanceOfCheck),
815         Object);
816   }
817 
818   // Fall back to OrdinaryHasInstance with {callable} and {object}.
819   Handle<Object> result;
820   ASSIGN_RETURN_ON_EXCEPTION(
821       isolate, result,
822       JSReceiver::OrdinaryHasInstance(isolate, callable, object), Object);
823   return result;
824 }
825 
IsArray(Handle<Object> object)826 Maybe<bool> Object::IsArray(Handle<Object> object) {
827   if (object->IsJSArray()) return Just(true);
828   if (object->IsJSProxy()) {
829     Handle<JSProxy> proxy = Handle<JSProxy>::cast(object);
830     Isolate* isolate = proxy->GetIsolate();
831     if (proxy->IsRevoked()) {
832       isolate->Throw(*isolate->factory()->NewTypeError(
833           MessageTemplate::kProxyRevoked,
834           isolate->factory()->NewStringFromAsciiChecked("IsArray")));
835       return Nothing<bool>();
836     }
837     return Object::IsArray(handle(proxy->target(), isolate));
838   }
839   return Just(false);
840 }
841 
842 
843 // static
GetMethod(Handle<JSReceiver> receiver,Handle<Name> name)844 MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
845                                       Handle<Name> name) {
846   Handle<Object> func;
847   Isolate* isolate = receiver->GetIsolate();
848   ASSIGN_RETURN_ON_EXCEPTION(isolate, func,
849                              JSReceiver::GetProperty(receiver, name), Object);
850   if (func->IsNull(isolate) || func->IsUndefined(isolate)) {
851     return isolate->factory()->undefined_value();
852   }
853   if (!func->IsCallable()) {
854     THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kPropertyNotFunction,
855                                           func, name, receiver),
856                     Object);
857   }
858   return func;
859 }
860 
861 
862 // static
CreateListFromArrayLike(Isolate * isolate,Handle<Object> object,ElementTypes element_types)863 MaybeHandle<FixedArray> Object::CreateListFromArrayLike(
864     Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
865   // 1. ReturnIfAbrupt(object).
866   // 2. (default elementTypes -- not applicable.)
867   // 3. If Type(obj) is not Object, throw a TypeError exception.
868   if (!object->IsJSReceiver()) {
869     THROW_NEW_ERROR(isolate,
870                     NewTypeError(MessageTemplate::kCalledOnNonObject,
871                                  isolate->factory()->NewStringFromAsciiChecked(
872                                      "CreateListFromArrayLike")),
873                     FixedArray);
874   }
875   // 4. Let len be ? ToLength(? Get(obj, "length")).
876   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
877   Handle<Object> raw_length_number;
878   ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number,
879                              Object::GetLengthFromArrayLike(isolate, receiver),
880                              FixedArray);
881   uint32_t len;
882   if (!raw_length_number->ToUint32(&len) ||
883       len > static_cast<uint32_t>(FixedArray::kMaxLength)) {
884     THROW_NEW_ERROR(isolate,
885                     NewRangeError(MessageTemplate::kInvalidArrayLength),
886                     FixedArray);
887   }
888   // 5. Let list be an empty List.
889   Handle<FixedArray> list = isolate->factory()->NewFixedArray(len);
890   // 6. Let index be 0.
891   // 7. Repeat while index < len:
892   for (uint32_t index = 0; index < len; ++index) {
893     // 7a. Let indexName be ToString(index).
894     // 7b. Let next be ? Get(obj, indexName).
895     Handle<Object> next;
896     ASSIGN_RETURN_ON_EXCEPTION(isolate, next,
897                                JSReceiver::GetElement(isolate, receiver, index),
898                                FixedArray);
899     switch (element_types) {
900       case ElementTypes::kAll:
901         // Nothing to do.
902         break;
903       case ElementTypes::kStringAndSymbol: {
904         // 7c. If Type(next) is not an element of elementTypes, throw a
905         //     TypeError exception.
906         if (!next->IsName()) {
907           THROW_NEW_ERROR(isolate,
908                           NewTypeError(MessageTemplate::kNotPropertyName, next),
909                           FixedArray);
910         }
911         // 7d. Append next as the last element of list.
912         // Internalize on the fly so we can use pointer identity later.
913         next = isolate->factory()->InternalizeName(Handle<Name>::cast(next));
914         break;
915       }
916     }
917     list->set(index, *next);
918     // 7e. Set index to index + 1. (See loop header.)
919   }
920   // 8. Return list.
921   return list;
922 }
923 
924 
925 // static
GetLengthFromArrayLike(Isolate * isolate,Handle<Object> object)926 MaybeHandle<Object> Object::GetLengthFromArrayLike(Isolate* isolate,
927                                                    Handle<Object> object) {
928   Handle<Object> val;
929   Handle<Object> key = isolate->factory()->length_string();
930   ASSIGN_RETURN_ON_EXCEPTION(
931       isolate, val, Runtime::GetObjectProperty(isolate, object, key), Object);
932   return Object::ToLength(isolate, val);
933 }
934 
935 // static
HasProperty(LookupIterator * it)936 Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) {
937   for (; it->IsFound(); it->Next()) {
938     switch (it->state()) {
939       case LookupIterator::NOT_FOUND:
940       case LookupIterator::TRANSITION:
941         UNREACHABLE();
942       case LookupIterator::JSPROXY:
943         return JSProxy::HasProperty(it->isolate(), it->GetHolder<JSProxy>(),
944                                     it->GetName());
945       case LookupIterator::INTERCEPTOR: {
946         Maybe<PropertyAttributes> result =
947             JSObject::GetPropertyAttributesWithInterceptor(it);
948         if (result.IsNothing()) return Nothing<bool>();
949         if (result.FromJust() != ABSENT) return Just(true);
950         break;
951       }
952       case LookupIterator::ACCESS_CHECK: {
953         if (it->HasAccess()) break;
954         Maybe<PropertyAttributes> result =
955             JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
956         if (result.IsNothing()) return Nothing<bool>();
957         return Just(result.FromJust() != ABSENT);
958       }
959       case LookupIterator::INTEGER_INDEXED_EXOTIC:
960         // TypedArray out-of-bounds access.
961         return Just(false);
962       case LookupIterator::ACCESSOR:
963       case LookupIterator::DATA:
964         return Just(true);
965     }
966   }
967   return Just(false);
968 }
969 
970 
971 // static
GetProperty(LookupIterator * it)972 MaybeHandle<Object> Object::GetProperty(LookupIterator* it) {
973   for (; it->IsFound(); it->Next()) {
974     switch (it->state()) {
975       case LookupIterator::NOT_FOUND:
976       case LookupIterator::TRANSITION:
977         UNREACHABLE();
978       case LookupIterator::JSPROXY: {
979         bool was_found;
980         MaybeHandle<Object> result =
981             JSProxy::GetProperty(it->isolate(), it->GetHolder<JSProxy>(),
982                                  it->GetName(), it->GetReceiver(), &was_found);
983         if (!was_found) it->NotFound();
984         return result;
985       }
986       case LookupIterator::INTERCEPTOR: {
987         bool done;
988         Handle<Object> result;
989         ASSIGN_RETURN_ON_EXCEPTION(
990             it->isolate(), result,
991             JSObject::GetPropertyWithInterceptor(it, &done), Object);
992         if (done) return result;
993         break;
994       }
995       case LookupIterator::ACCESS_CHECK:
996         if (it->HasAccess()) break;
997         return JSObject::GetPropertyWithFailedAccessCheck(it);
998       case LookupIterator::ACCESSOR:
999         return GetPropertyWithAccessor(it);
1000       case LookupIterator::INTEGER_INDEXED_EXOTIC:
1001         return it->isolate()->factory()->undefined_value();
1002       case LookupIterator::DATA:
1003         return it->GetDataValue();
1004     }
1005   }
1006   return it->isolate()->factory()->undefined_value();
1007 }
1008 
1009 
1010 // static
GetProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Name> name,Handle<Object> receiver,bool * was_found)1011 MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
1012                                          Handle<JSProxy> proxy,
1013                                          Handle<Name> name,
1014                                          Handle<Object> receiver,
1015                                          bool* was_found) {
1016   *was_found = true;
1017   if (receiver->IsJSGlobalObject()) {
1018     THROW_NEW_ERROR(
1019         isolate,
1020         NewTypeError(MessageTemplate::kReadGlobalReferenceThroughProxy, name),
1021         Object);
1022   }
1023 
1024   DCHECK(!name->IsPrivate());
1025   STACK_CHECK(isolate, MaybeHandle<Object>());
1026   Handle<Name> trap_name = isolate->factory()->get_string();
1027   // 1. Assert: IsPropertyKey(P) is true.
1028   // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
1029   Handle<Object> handler(proxy->handler(), isolate);
1030   // 3. If handler is null, throw a TypeError exception.
1031   // 4. Assert: Type(handler) is Object.
1032   if (proxy->IsRevoked()) {
1033     THROW_NEW_ERROR(isolate,
1034                     NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1035                     Object);
1036   }
1037   // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
1038   Handle<JSReceiver> target(proxy->target(), isolate);
1039   // 6. Let trap be ? GetMethod(handler, "get").
1040   Handle<Object> trap;
1041   ASSIGN_RETURN_ON_EXCEPTION(
1042       isolate, trap,
1043       Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), Object);
1044   // 7. If trap is undefined, then
1045   if (trap->IsUndefined(isolate)) {
1046     // 7.a Return target.[[Get]](P, Receiver).
1047     LookupIterator it =
1048         LookupIterator::PropertyOrElement(isolate, receiver, name, target);
1049     MaybeHandle<Object> result = Object::GetProperty(&it);
1050     *was_found = it.IsFound();
1051     return result;
1052   }
1053   // 8. Let trapResult be ? Call(trap, handler, «target, P, Receiver»).
1054   Handle<Object> trap_result;
1055   Handle<Object> args[] = {target, name, receiver};
1056   ASSIGN_RETURN_ON_EXCEPTION(
1057       isolate, trap_result,
1058       Execution::Call(isolate, trap, handler, arraysize(args), args), Object);
1059   // 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
1060   PropertyDescriptor target_desc;
1061   Maybe<bool> target_found =
1062       JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
1063   MAYBE_RETURN_NULL(target_found);
1064   // 10. If targetDesc is not undefined, then
1065   if (target_found.FromJust()) {
1066     // 10.a. If IsDataDescriptor(targetDesc) and targetDesc.[[Configurable]] is
1067     //       false and targetDesc.[[Writable]] is false, then
1068     // 10.a.i. If SameValue(trapResult, targetDesc.[[Value]]) is false,
1069     //        throw a TypeError exception.
1070     bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
1071                         !target_desc.configurable() &&
1072                         !target_desc.writable() &&
1073                         !trap_result->SameValue(*target_desc.value());
1074     if (inconsistent) {
1075       THROW_NEW_ERROR(
1076           isolate, NewTypeError(MessageTemplate::kProxyGetNonConfigurableData,
1077                                 name, target_desc.value(), trap_result),
1078           Object);
1079     }
1080     // 10.b. If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]]
1081     //       is false and targetDesc.[[Get]] is undefined, then
1082     // 10.b.i. If trapResult is not undefined, throw a TypeError exception.
1083     inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
1084                    !target_desc.configurable() &&
1085                    target_desc.get()->IsUndefined(isolate) &&
1086                    !trap_result->IsUndefined(isolate);
1087     if (inconsistent) {
1088       THROW_NEW_ERROR(
1089           isolate,
1090           NewTypeError(MessageTemplate::kProxyGetNonConfigurableAccessor, name,
1091                        trap_result),
1092           Object);
1093     }
1094   }
1095   // 11. Return trap_result
1096   return trap_result;
1097 }
1098 
1099 
GetDataProperty(LookupIterator * it)1100 Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it) {
1101   for (; it->IsFound(); it->Next()) {
1102     switch (it->state()) {
1103       case LookupIterator::INTERCEPTOR:
1104       case LookupIterator::NOT_FOUND:
1105       case LookupIterator::TRANSITION:
1106         UNREACHABLE();
1107       case LookupIterator::ACCESS_CHECK:
1108         // Support calling this method without an active context, but refuse
1109         // access to access-checked objects in that case.
1110         if (it->isolate()->context() != nullptr && it->HasAccess()) continue;
1111       // Fall through.
1112       case LookupIterator::JSPROXY:
1113         it->NotFound();
1114         return it->isolate()->factory()->undefined_value();
1115       case LookupIterator::ACCESSOR:
1116         // TODO(verwaest): For now this doesn't call into AccessorInfo, since
1117         // clients don't need it. Update once relevant.
1118         it->NotFound();
1119         return it->isolate()->factory()->undefined_value();
1120       case LookupIterator::INTEGER_INDEXED_EXOTIC:
1121         return it->isolate()->factory()->undefined_value();
1122       case LookupIterator::DATA:
1123         return it->GetDataValue();
1124     }
1125   }
1126   return it->isolate()->factory()->undefined_value();
1127 }
1128 
1129 
ToInt32(int32_t * value)1130 bool Object::ToInt32(int32_t* value) {
1131   if (IsSmi()) {
1132     *value = Smi::cast(this)->value();
1133     return true;
1134   }
1135   if (IsHeapNumber()) {
1136     double num = HeapNumber::cast(this)->value();
1137     if (FastI2D(FastD2I(num)) == num) {
1138       *value = FastD2I(num);
1139       return true;
1140     }
1141   }
1142   return false;
1143 }
1144 
GetOrCreateSharedFunctionInfo(Isolate * isolate,Handle<FunctionTemplateInfo> info)1145 Handle<SharedFunctionInfo> FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(
1146     Isolate* isolate, Handle<FunctionTemplateInfo> info) {
1147   Object* current_info = info->shared_function_info();
1148   if (current_info->IsSharedFunctionInfo()) {
1149     return handle(SharedFunctionInfo::cast(current_info), isolate);
1150   }
1151 
1152   Handle<Object> class_name(info->class_name(), isolate);
1153   Handle<String> name = class_name->IsString()
1154                             ? Handle<String>::cast(class_name)
1155                             : isolate->factory()->empty_string();
1156   Handle<Code> code;
1157   if (info->call_code()->IsCallHandlerInfo() &&
1158       CallHandlerInfo::cast(info->call_code())->fast_handler()->IsCode()) {
1159     code = isolate->builtins()->HandleFastApiCall();
1160   } else {
1161     code = isolate->builtins()->HandleApiCall();
1162   }
1163   bool is_constructor = !info->remove_prototype();
1164   Handle<SharedFunctionInfo> result =
1165       isolate->factory()->NewSharedFunctionInfo(name, code, is_constructor);
1166   if (is_constructor) {
1167     result->SetConstructStub(*isolate->builtins()->JSConstructStubApi());
1168   }
1169 
1170   result->set_length(info->length());
1171   if (class_name->IsString()) result->set_instance_class_name(*class_name);
1172   result->set_api_func_data(*info);
1173   result->DontAdaptArguments();
1174   DCHECK(result->IsApiFunction());
1175 
1176   info->set_shared_function_info(*result);
1177   return result;
1178 }
1179 
IsTemplateFor(Map * map)1180 bool FunctionTemplateInfo::IsTemplateFor(Map* map) {
1181   // There is a constraint on the object; check.
1182   if (!map->IsJSObjectMap()) return false;
1183   // Fetch the constructor function of the object.
1184   Object* cons_obj = map->GetConstructor();
1185   if (!cons_obj->IsJSFunction()) return false;
1186   JSFunction* fun = JSFunction::cast(cons_obj);
1187   // Iterate through the chain of inheriting function templates to
1188   // see if the required one occurs.
1189   for (Object* type = fun->shared()->function_data();
1190        type->IsFunctionTemplateInfo();
1191        type = FunctionTemplateInfo::cast(type)->parent_template()) {
1192     if (type == this) return true;
1193   }
1194   // Didn't find the required type in the inheritance chain.
1195   return false;
1196 }
1197 
1198 
1199 // static
New(Isolate * isolate,int size)1200 Handle<TemplateList> TemplateList::New(Isolate* isolate, int size) {
1201   Handle<FixedArray> list =
1202       isolate->factory()->NewFixedArray(kLengthIndex + size);
1203   list->set(kLengthIndex, Smi::kZero);
1204   return Handle<TemplateList>::cast(list);
1205 }
1206 
1207 // static
Add(Isolate * isolate,Handle<TemplateList> list,Handle<i::Object> value)1208 Handle<TemplateList> TemplateList::Add(Isolate* isolate,
1209                                        Handle<TemplateList> list,
1210                                        Handle<i::Object> value) {
1211   STATIC_ASSERT(kFirstElementIndex == 1);
1212   int index = list->length() + 1;
1213   Handle<i::FixedArray> fixed_array = Handle<FixedArray>::cast(list);
1214   fixed_array = FixedArray::SetAndGrow(fixed_array, index, value);
1215   fixed_array->set(kLengthIndex, Smi::FromInt(index));
1216   return Handle<TemplateList>::cast(fixed_array);
1217 }
1218 
1219 // static
New(Handle<JSFunction> constructor,Handle<JSReceiver> new_target,Handle<AllocationSite> site)1220 MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor,
1221                                     Handle<JSReceiver> new_target,
1222                                     Handle<AllocationSite> site) {
1223   // If called through new, new.target can be:
1224   // - a subclass of constructor,
1225   // - a proxy wrapper around constructor, or
1226   // - the constructor itself.
1227   // If called through Reflect.construct, it's guaranteed to be a constructor.
1228   Isolate* const isolate = constructor->GetIsolate();
1229   DCHECK(constructor->IsConstructor());
1230   DCHECK(new_target->IsConstructor());
1231   DCHECK(!constructor->has_initial_map() ||
1232          constructor->initial_map()->instance_type() != JS_FUNCTION_TYPE);
1233 
1234   Handle<Map> initial_map;
1235   ASSIGN_RETURN_ON_EXCEPTION(
1236       isolate, initial_map,
1237       JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject);
1238   Handle<JSObject> result =
1239       isolate->factory()->NewJSObjectFromMap(initial_map, NOT_TENURED, site);
1240   isolate->counters()->constructed_objects()->Increment();
1241   isolate->counters()->constructed_objects_runtime()->Increment();
1242   return result;
1243 }
1244 
EnsureWritableFastElements(Handle<JSObject> object)1245 void JSObject::EnsureWritableFastElements(Handle<JSObject> object) {
1246   DCHECK(object->HasFastSmiOrObjectElements() ||
1247          object->HasFastStringWrapperElements());
1248   FixedArray* raw_elems = FixedArray::cast(object->elements());
1249   Heap* heap = object->GetHeap();
1250   if (raw_elems->map() != heap->fixed_cow_array_map()) return;
1251   Isolate* isolate = heap->isolate();
1252   Handle<FixedArray> elems(raw_elems, isolate);
1253   Handle<FixedArray> writable_elems = isolate->factory()->CopyFixedArrayWithMap(
1254       elems, isolate->factory()->fixed_array_map());
1255   object->set_elements(*writable_elems);
1256   isolate->counters()->cow_arrays_converted()->Increment();
1257 }
1258 
1259 
1260 // ES6 9.5.1
1261 // static
GetPrototype(Handle<JSProxy> proxy)1262 MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
1263   Isolate* isolate = proxy->GetIsolate();
1264   Handle<String> trap_name = isolate->factory()->getPrototypeOf_string();
1265 
1266   STACK_CHECK(isolate, MaybeHandle<Object>());
1267 
1268   // 1. Let handler be the value of the [[ProxyHandler]] internal slot.
1269   // 2. If handler is null, throw a TypeError exception.
1270   // 3. Assert: Type(handler) is Object.
1271   // 4. Let target be the value of the [[ProxyTarget]] internal slot.
1272   if (proxy->IsRevoked()) {
1273     THROW_NEW_ERROR(isolate,
1274                     NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1275                     Object);
1276   }
1277   Handle<JSReceiver> target(proxy->target(), isolate);
1278   Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
1279 
1280   // 5. Let trap be ? GetMethod(handler, "getPrototypeOf").
1281   Handle<Object> trap;
1282   ASSIGN_RETURN_ON_EXCEPTION(isolate, trap, GetMethod(handler, trap_name),
1283                              Object);
1284   // 6. If trap is undefined, then return target.[[GetPrototypeOf]]().
1285   if (trap->IsUndefined(isolate)) {
1286     return JSReceiver::GetPrototype(isolate, target);
1287   }
1288   // 7. Let handlerProto be ? Call(trap, handler, «target»).
1289   Handle<Object> argv[] = {target};
1290   Handle<Object> handler_proto;
1291   ASSIGN_RETURN_ON_EXCEPTION(
1292       isolate, handler_proto,
1293       Execution::Call(isolate, trap, handler, arraysize(argv), argv), Object);
1294   // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError.
1295   if (!(handler_proto->IsJSReceiver() || handler_proto->IsNull(isolate))) {
1296     THROW_NEW_ERROR(isolate,
1297                     NewTypeError(MessageTemplate::kProxyGetPrototypeOfInvalid),
1298                     Object);
1299   }
1300   // 9. Let extensibleTarget be ? IsExtensible(target).
1301   Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
1302   MAYBE_RETURN_NULL(is_extensible);
1303   // 10. If extensibleTarget is true, return handlerProto.
1304   if (is_extensible.FromJust()) return handler_proto;
1305   // 11. Let targetProto be ? target.[[GetPrototypeOf]]().
1306   Handle<Object> target_proto;
1307   ASSIGN_RETURN_ON_EXCEPTION(isolate, target_proto,
1308                              JSReceiver::GetPrototype(isolate, target), Object);
1309   // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError.
1310   if (!handler_proto->SameValue(*target_proto)) {
1311     THROW_NEW_ERROR(
1312         isolate,
1313         NewTypeError(MessageTemplate::kProxyGetPrototypeOfNonExtensible),
1314         Object);
1315   }
1316   // 13. Return handlerProto.
1317   return handler_proto;
1318 }
1319 
GetPropertyWithAccessor(LookupIterator * it)1320 MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) {
1321   Isolate* isolate = it->isolate();
1322   Handle<Object> structure = it->GetAccessors();
1323   Handle<Object> receiver = it->GetReceiver();
1324 
1325   // We should never get here to initialize a const with the hole value since a
1326   // const declaration would conflict with the getter.
1327   DCHECK(!structure->IsForeign());
1328 
1329   // API style callbacks.
1330   if (structure->IsAccessorInfo()) {
1331     Handle<JSObject> holder = it->GetHolder<JSObject>();
1332     Handle<Name> name = it->GetName();
1333     Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
1334     if (!info->IsCompatibleReceiver(*receiver)) {
1335       THROW_NEW_ERROR(isolate,
1336                       NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
1337                                    name, receiver),
1338                       Object);
1339     }
1340 
1341     v8::AccessorNameGetterCallback call_fun =
1342         v8::ToCData<v8::AccessorNameGetterCallback>(info->getter());
1343     if (call_fun == nullptr) return isolate->factory()->undefined_value();
1344 
1345     if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1346       ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver,
1347                                  Object::ConvertReceiver(isolate, receiver),
1348                                  Object);
1349     }
1350 
1351     PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1352                                    Object::DONT_THROW);
1353     Handle<Object> result = args.Call(call_fun, name);
1354     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1355     if (result.is_null()) return isolate->factory()->undefined_value();
1356     Handle<Object> reboxed_result = handle(*result, isolate);
1357     if (info->replace_on_access() && receiver->IsJSReceiver()) {
1358       args.Call(reinterpret_cast<GenericNamedPropertySetterCallback>(
1359                     &Accessors::ReconfigureToDataProperty),
1360                 name, result);
1361       RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1362     }
1363     return reboxed_result;
1364   }
1365 
1366   // AccessorPair with 'cached' private property.
1367   if (it->TryLookupCachedProperty()) {
1368     return Object::GetProperty(it);
1369   }
1370 
1371   // Regular accessor.
1372   Handle<Object> getter(AccessorPair::cast(*structure)->getter(), isolate);
1373   if (getter->IsFunctionTemplateInfo()) {
1374     return Builtins::InvokeApiFunction(
1375         isolate, false, Handle<FunctionTemplateInfo>::cast(getter), receiver, 0,
1376         nullptr, isolate->factory()->undefined_value());
1377   } else if (getter->IsCallable()) {
1378     // TODO(rossberg): nicer would be to cast to some JSCallable here...
1379     return Object::GetPropertyWithDefinedGetter(
1380         receiver, Handle<JSReceiver>::cast(getter));
1381   }
1382   // Getter is not a function.
1383   return isolate->factory()->undefined_value();
1384 }
1385 
1386 // static
redirect(Isolate * isolate,Address address,AccessorComponent component)1387 Address AccessorInfo::redirect(Isolate* isolate, Address address,
1388                                AccessorComponent component) {
1389   ApiFunction fun(address);
1390   DCHECK_EQ(ACCESSOR_GETTER, component);
1391   ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
1392   return ExternalReference(&fun, type, isolate).address();
1393 }
1394 
redirected_getter() const1395 Address AccessorInfo::redirected_getter() const {
1396   Address accessor = v8::ToCData<Address>(getter());
1397   if (accessor == nullptr) return nullptr;
1398   return redirect(GetIsolate(), accessor, ACCESSOR_GETTER);
1399 }
1400 
IsCompatibleReceiverMap(Isolate * isolate,Handle<AccessorInfo> info,Handle<Map> map)1401 bool AccessorInfo::IsCompatibleReceiverMap(Isolate* isolate,
1402                                            Handle<AccessorInfo> info,
1403                                            Handle<Map> map) {
1404   if (!info->HasExpectedReceiverType()) return true;
1405   if (!map->IsJSObjectMap()) return false;
1406   return FunctionTemplateInfo::cast(info->expected_receiver_type())
1407       ->IsTemplateFor(*map);
1408 }
1409 
SetPropertyWithAccessor(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)1410 Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it,
1411                                             Handle<Object> value,
1412                                             ShouldThrow should_throw) {
1413   Isolate* isolate = it->isolate();
1414   Handle<Object> structure = it->GetAccessors();
1415   Handle<Object> receiver = it->GetReceiver();
1416 
1417   // We should never get here to initialize a const with the hole value since a
1418   // const declaration would conflict with the setter.
1419   DCHECK(!structure->IsForeign());
1420 
1421   // API style callbacks.
1422   if (structure->IsAccessorInfo()) {
1423     Handle<JSObject> holder = it->GetHolder<JSObject>();
1424     Handle<Name> name = it->GetName();
1425     Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
1426     if (!info->IsCompatibleReceiver(*receiver)) {
1427       isolate->Throw(*isolate->factory()->NewTypeError(
1428           MessageTemplate::kIncompatibleMethodReceiver, name, receiver));
1429       return Nothing<bool>();
1430     }
1431 
1432     // The actual type of call_fun is either v8::AccessorNameSetterCallback or
1433     // i::Accesors::AccessorNameBooleanSetterCallback, depending on whether the
1434     // AccessorInfo was created by the API or internally (see accessors.cc).
1435     // Here we handle both cases using GenericNamedPropertySetterCallback and
1436     // its Call method.
1437     GenericNamedPropertySetterCallback call_fun =
1438         v8::ToCData<GenericNamedPropertySetterCallback>(info->setter());
1439 
1440     if (call_fun == nullptr) {
1441       // TODO(verwaest): We should not get here anymore once all AccessorInfos
1442       // are marked as special_data_property. They cannot both be writable and
1443       // not have a setter.
1444       return Just(true);
1445     }
1446 
1447     if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1448       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1449           isolate, receiver, Object::ConvertReceiver(isolate, receiver),
1450           Nothing<bool>());
1451     }
1452 
1453     PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1454                                    should_throw);
1455     Handle<Object> result = args.Call(call_fun, name, value);
1456     // In the case of AccessorNameSetterCallback, we know that the result value
1457     // cannot have been set, so the result of Call will be null.  In the case of
1458     // AccessorNameBooleanSetterCallback, the result will either be null
1459     // (signalling an exception) or a boolean Oddball.
1460     RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1461     if (result.is_null()) return Just(true);
1462     DCHECK(result->BooleanValue() || should_throw == DONT_THROW);
1463     return Just(result->BooleanValue());
1464   }
1465 
1466   // Regular accessor.
1467   Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
1468   if (setter->IsFunctionTemplateInfo()) {
1469     Handle<Object> argv[] = {value};
1470     RETURN_ON_EXCEPTION_VALUE(
1471         isolate, Builtins::InvokeApiFunction(
1472                      isolate, false, Handle<FunctionTemplateInfo>::cast(setter),
1473                      receiver, arraysize(argv), argv,
1474                      isolate->factory()->undefined_value()),
1475         Nothing<bool>());
1476     return Just(true);
1477   } else if (setter->IsCallable()) {
1478     // TODO(rossberg): nicer would be to cast to some JSCallable here...
1479     return SetPropertyWithDefinedSetter(
1480         receiver, Handle<JSReceiver>::cast(setter), value, should_throw);
1481   }
1482 
1483   RETURN_FAILURE(isolate, should_throw,
1484                  NewTypeError(MessageTemplate::kNoSetterInCallback,
1485                               it->GetName(), it->GetHolder<JSObject>()));
1486 }
1487 
1488 
GetPropertyWithDefinedGetter(Handle<Object> receiver,Handle<JSReceiver> getter)1489 MaybeHandle<Object> Object::GetPropertyWithDefinedGetter(
1490     Handle<Object> receiver,
1491     Handle<JSReceiver> getter) {
1492   Isolate* isolate = getter->GetIsolate();
1493 
1494   // Platforms with simulators like arm/arm64 expose a funny issue. If the
1495   // simulator has a separate JS stack pointer from the C++ stack pointer, it
1496   // can miss C++ stack overflows in the stack guard at the start of JavaScript
1497   // functions. It would be very expensive to check the C++ stack pointer at
1498   // that location. The best solution seems to be to break the impasse by
1499   // adding checks at possible recursion points. What's more, we don't put
1500   // this stack check behind the USE_SIMULATOR define in order to keep
1501   // behavior the same between hardware and simulators.
1502   StackLimitCheck check(isolate);
1503   if (check.JsHasOverflowed()) {
1504     isolate->StackOverflow();
1505     return MaybeHandle<Object>();
1506   }
1507 
1508   return Execution::Call(isolate, getter, receiver, 0, NULL);
1509 }
1510 
1511 
SetPropertyWithDefinedSetter(Handle<Object> receiver,Handle<JSReceiver> setter,Handle<Object> value,ShouldThrow should_throw)1512 Maybe<bool> Object::SetPropertyWithDefinedSetter(Handle<Object> receiver,
1513                                                  Handle<JSReceiver> setter,
1514                                                  Handle<Object> value,
1515                                                  ShouldThrow should_throw) {
1516   Isolate* isolate = setter->GetIsolate();
1517 
1518   Handle<Object> argv[] = { value };
1519   RETURN_ON_EXCEPTION_VALUE(isolate, Execution::Call(isolate, setter, receiver,
1520                                                      arraysize(argv), argv),
1521                             Nothing<bool>());
1522   return Just(true);
1523 }
1524 
1525 
1526 // static
AllCanRead(LookupIterator * it)1527 bool JSObject::AllCanRead(LookupIterator* it) {
1528   // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of
1529   // which have already been checked.
1530   DCHECK(it->state() == LookupIterator::ACCESS_CHECK ||
1531          it->state() == LookupIterator::INTERCEPTOR);
1532   for (it->Next(); it->IsFound(); it->Next()) {
1533     if (it->state() == LookupIterator::ACCESSOR) {
1534       auto accessors = it->GetAccessors();
1535       if (accessors->IsAccessorInfo()) {
1536         if (AccessorInfo::cast(*accessors)->all_can_read()) return true;
1537       }
1538     } else if (it->state() == LookupIterator::INTERCEPTOR) {
1539       if (it->GetInterceptor()->all_can_read()) return true;
1540     } else if (it->state() == LookupIterator::JSPROXY) {
1541       // Stop lookupiterating. And no, AllCanNotRead.
1542       return false;
1543     }
1544   }
1545   return false;
1546 }
1547 
1548 namespace {
1549 
GetPropertyWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor,bool * done)1550 MaybeHandle<Object> GetPropertyWithInterceptorInternal(
1551     LookupIterator* it, Handle<InterceptorInfo> interceptor, bool* done) {
1552   *done = false;
1553   Isolate* isolate = it->isolate();
1554   // Make sure that the top context does not change when doing callbacks or
1555   // interceptor calls.
1556   AssertNoContextChange ncc(isolate);
1557 
1558   if (interceptor->getter()->IsUndefined(isolate)) {
1559     return isolate->factory()->undefined_value();
1560   }
1561 
1562   Handle<JSObject> holder = it->GetHolder<JSObject>();
1563   Handle<Object> result;
1564   Handle<Object> receiver = it->GetReceiver();
1565   if (!receiver->IsJSReceiver()) {
1566     ASSIGN_RETURN_ON_EXCEPTION(
1567         isolate, receiver, Object::ConvertReceiver(isolate, receiver), Object);
1568   }
1569   PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1570                                  *holder, Object::DONT_THROW);
1571 
1572   if (it->IsElement()) {
1573     uint32_t index = it->index();
1574     v8::IndexedPropertyGetterCallback getter =
1575         v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
1576     result = args.Call(getter, index);
1577   } else {
1578     Handle<Name> name = it->name();
1579     DCHECK(!name->IsPrivate());
1580 
1581     if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
1582       return isolate->factory()->undefined_value();
1583     }
1584 
1585     v8::GenericNamedPropertyGetterCallback getter =
1586         v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
1587             interceptor->getter());
1588     result = args.Call(getter, name);
1589   }
1590 
1591   RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1592   if (result.is_null()) return isolate->factory()->undefined_value();
1593   *done = true;
1594   // Rebox handle before return
1595   return handle(*result, isolate);
1596 }
1597 
GetPropertyAttributesWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor)1598 Maybe<PropertyAttributes> GetPropertyAttributesWithInterceptorInternal(
1599     LookupIterator* it, Handle<InterceptorInfo> interceptor) {
1600   Isolate* isolate = it->isolate();
1601   // Make sure that the top context does not change when doing
1602   // callbacks or interceptor calls.
1603   AssertNoContextChange ncc(isolate);
1604   HandleScope scope(isolate);
1605 
1606   Handle<JSObject> holder = it->GetHolder<JSObject>();
1607   if (!it->IsElement() && it->name()->IsSymbol() &&
1608       !interceptor->can_intercept_symbols()) {
1609     return Just(ABSENT);
1610   }
1611   Handle<Object> receiver = it->GetReceiver();
1612   if (!receiver->IsJSReceiver()) {
1613     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1614                                      Object::ConvertReceiver(isolate, receiver),
1615                                      Nothing<PropertyAttributes>());
1616   }
1617   PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1618                                  *holder, Object::DONT_THROW);
1619   if (!interceptor->query()->IsUndefined(isolate)) {
1620     Handle<Object> result;
1621     if (it->IsElement()) {
1622       uint32_t index = it->index();
1623       v8::IndexedPropertyQueryCallback query =
1624           v8::ToCData<v8::IndexedPropertyQueryCallback>(interceptor->query());
1625       result = args.Call(query, index);
1626     } else {
1627       Handle<Name> name = it->name();
1628       DCHECK(!name->IsPrivate());
1629       v8::GenericNamedPropertyQueryCallback query =
1630           v8::ToCData<v8::GenericNamedPropertyQueryCallback>(
1631               interceptor->query());
1632       result = args.Call(query, name);
1633     }
1634     if (!result.is_null()) {
1635       int32_t value;
1636       CHECK(result->ToInt32(&value));
1637       return Just(static_cast<PropertyAttributes>(value));
1638     }
1639   } else if (!interceptor->getter()->IsUndefined(isolate)) {
1640     // TODO(verwaest): Use GetPropertyWithInterceptor?
1641     Handle<Object> result;
1642     if (it->IsElement()) {
1643       uint32_t index = it->index();
1644       v8::IndexedPropertyGetterCallback getter =
1645           v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
1646       result = args.Call(getter, index);
1647     } else {
1648       Handle<Name> name = it->name();
1649       DCHECK(!name->IsPrivate());
1650       v8::GenericNamedPropertyGetterCallback getter =
1651           v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
1652               interceptor->getter());
1653       result = args.Call(getter, name);
1654     }
1655     if (!result.is_null()) return Just(DONT_ENUM);
1656   }
1657 
1658   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
1659   return Just(ABSENT);
1660 }
1661 
SetPropertyWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor,Object::ShouldThrow should_throw,Handle<Object> value)1662 Maybe<bool> SetPropertyWithInterceptorInternal(
1663     LookupIterator* it, Handle<InterceptorInfo> interceptor,
1664     Object::ShouldThrow should_throw, Handle<Object> value) {
1665   Isolate* isolate = it->isolate();
1666   // Make sure that the top context does not change when doing callbacks or
1667   // interceptor calls.
1668   AssertNoContextChange ncc(isolate);
1669 
1670   if (interceptor->setter()->IsUndefined(isolate)) return Just(false);
1671 
1672   Handle<JSObject> holder = it->GetHolder<JSObject>();
1673   bool result;
1674   Handle<Object> receiver = it->GetReceiver();
1675   if (!receiver->IsJSReceiver()) {
1676     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1677                                      Object::ConvertReceiver(isolate, receiver),
1678                                      Nothing<bool>());
1679   }
1680   PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1681                                  *holder, should_throw);
1682 
1683   if (it->IsElement()) {
1684     uint32_t index = it->index();
1685     v8::IndexedPropertySetterCallback setter =
1686         v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter());
1687     // TODO(neis): In the future, we may want to actually return the
1688     // interceptor's result, which then should be a boolean.
1689     result = !args.Call(setter, index, value).is_null();
1690   } else {
1691     Handle<Name> name = it->name();
1692     DCHECK(!name->IsPrivate());
1693 
1694     if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
1695       return Just(false);
1696     }
1697 
1698     v8::GenericNamedPropertySetterCallback setter =
1699         v8::ToCData<v8::GenericNamedPropertySetterCallback>(
1700             interceptor->setter());
1701     result = !args.Call(setter, name, value).is_null();
1702   }
1703 
1704   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1705   return Just(result);
1706 }
1707 
DefinePropertyWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor,Object::ShouldThrow should_throw,PropertyDescriptor & desc)1708 Maybe<bool> DefinePropertyWithInterceptorInternal(
1709     LookupIterator* it, Handle<InterceptorInfo> interceptor,
1710     Object::ShouldThrow should_throw, PropertyDescriptor& desc) {
1711   Isolate* isolate = it->isolate();
1712   // Make sure that the top context does not change when doing callbacks or
1713   // interceptor calls.
1714   AssertNoContextChange ncc(isolate);
1715 
1716   if (interceptor->definer()->IsUndefined(isolate)) return Just(false);
1717 
1718   Handle<JSObject> holder = it->GetHolder<JSObject>();
1719   bool result;
1720   Handle<Object> receiver = it->GetReceiver();
1721   if (!receiver->IsJSReceiver()) {
1722     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1723                                      Object::ConvertReceiver(isolate, receiver),
1724                                      Nothing<bool>());
1725   }
1726   PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1727                                  *holder, should_throw);
1728 
1729   std::unique_ptr<v8::PropertyDescriptor> descriptor(
1730       new v8::PropertyDescriptor());
1731   if (PropertyDescriptor::IsAccessorDescriptor(&desc)) {
1732     descriptor.reset(new v8::PropertyDescriptor(
1733         v8::Utils::ToLocal(desc.get()), v8::Utils::ToLocal(desc.set())));
1734   } else if (PropertyDescriptor::IsDataDescriptor(&desc)) {
1735     if (desc.has_writable()) {
1736       descriptor.reset(new v8::PropertyDescriptor(
1737           v8::Utils::ToLocal(desc.value()), desc.writable()));
1738     } else {
1739       descriptor.reset(
1740           new v8::PropertyDescriptor(v8::Utils::ToLocal(desc.value())));
1741     }
1742   }
1743   if (desc.has_enumerable()) {
1744     descriptor->set_enumerable(desc.enumerable());
1745   }
1746   if (desc.has_configurable()) {
1747     descriptor->set_configurable(desc.configurable());
1748   }
1749 
1750   if (it->IsElement()) {
1751     uint32_t index = it->index();
1752     v8::IndexedPropertyDefinerCallback definer =
1753         v8::ToCData<v8::IndexedPropertyDefinerCallback>(interceptor->definer());
1754     result = !args.Call(definer, index, *descriptor).is_null();
1755   } else {
1756     Handle<Name> name = it->name();
1757     DCHECK(!name->IsPrivate());
1758 
1759     if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
1760       return Just(false);
1761     }
1762 
1763     v8::GenericNamedPropertyDefinerCallback definer =
1764         v8::ToCData<v8::GenericNamedPropertyDefinerCallback>(
1765             interceptor->definer());
1766     result = !args.Call(definer, name, *descriptor).is_null();
1767   }
1768 
1769   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1770   return Just(result);
1771 }
1772 
1773 }  // namespace
1774 
GetPropertyWithFailedAccessCheck(LookupIterator * it)1775 MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
1776     LookupIterator* it) {
1777   Isolate* isolate = it->isolate();
1778   Handle<JSObject> checked = it->GetHolder<JSObject>();
1779   Handle<InterceptorInfo> interceptor =
1780       it->GetInterceptorForFailedAccessCheck();
1781   if (interceptor.is_null()) {
1782     while (AllCanRead(it)) {
1783       if (it->state() == LookupIterator::ACCESSOR) {
1784         return GetPropertyWithAccessor(it);
1785       }
1786       DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
1787       bool done;
1788       Handle<Object> result;
1789       ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
1790                                  GetPropertyWithInterceptor(it, &done), Object);
1791       if (done) return result;
1792     }
1793   } else {
1794     MaybeHandle<Object> result;
1795     bool done;
1796     result = GetPropertyWithInterceptorInternal(it, interceptor, &done);
1797     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1798     if (done) return result;
1799   }
1800 
1801   // Cross-Origin [[Get]] of Well-Known Symbols does not throw, and returns
1802   // undefined.
1803   Handle<Name> name = it->GetName();
1804   if (name->IsSymbol() && Symbol::cast(*name)->is_well_known_symbol()) {
1805     return it->factory()->undefined_value();
1806   }
1807 
1808   isolate->ReportFailedAccessCheck(checked);
1809   RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1810   return it->factory()->undefined_value();
1811 }
1812 
1813 
GetPropertyAttributesWithFailedAccessCheck(LookupIterator * it)1814 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
1815     LookupIterator* it) {
1816   Isolate* isolate = it->isolate();
1817   Handle<JSObject> checked = it->GetHolder<JSObject>();
1818   Handle<InterceptorInfo> interceptor =
1819       it->GetInterceptorForFailedAccessCheck();
1820   if (interceptor.is_null()) {
1821     while (AllCanRead(it)) {
1822       if (it->state() == LookupIterator::ACCESSOR) {
1823         return Just(it->property_attributes());
1824       }
1825       DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
1826       auto result = GetPropertyAttributesWithInterceptor(it);
1827       if (isolate->has_scheduled_exception()) break;
1828       if (result.IsJust() && result.FromJust() != ABSENT) return result;
1829     }
1830   } else {
1831     Maybe<PropertyAttributes> result =
1832         GetPropertyAttributesWithInterceptorInternal(it, interceptor);
1833     RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
1834     if (result.FromMaybe(ABSENT) != ABSENT) return result;
1835   }
1836   isolate->ReportFailedAccessCheck(checked);
1837   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
1838   return Just(ABSENT);
1839 }
1840 
1841 
1842 // static
AllCanWrite(LookupIterator * it)1843 bool JSObject::AllCanWrite(LookupIterator* it) {
1844   for (; it->IsFound() && it->state() != LookupIterator::JSPROXY; it->Next()) {
1845     if (it->state() == LookupIterator::ACCESSOR) {
1846       Handle<Object> accessors = it->GetAccessors();
1847       if (accessors->IsAccessorInfo()) {
1848         if (AccessorInfo::cast(*accessors)->all_can_write()) return true;
1849       }
1850     }
1851   }
1852   return false;
1853 }
1854 
1855 
SetPropertyWithFailedAccessCheck(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)1856 Maybe<bool> JSObject::SetPropertyWithFailedAccessCheck(
1857     LookupIterator* it, Handle<Object> value, ShouldThrow should_throw) {
1858   Isolate* isolate = it->isolate();
1859   Handle<JSObject> checked = it->GetHolder<JSObject>();
1860   Handle<InterceptorInfo> interceptor =
1861       it->GetInterceptorForFailedAccessCheck();
1862   if (interceptor.is_null()) {
1863     if (AllCanWrite(it)) {
1864       return SetPropertyWithAccessor(it, value, should_throw);
1865     }
1866   } else {
1867     Maybe<bool> result = SetPropertyWithInterceptorInternal(
1868         it, interceptor, should_throw, value);
1869     RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1870     if (result.IsJust()) return result;
1871   }
1872 
1873   isolate->ReportFailedAccessCheck(checked);
1874   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1875   return Just(true);
1876 }
1877 
1878 
SetNormalizedProperty(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyDetails details)1879 void JSObject::SetNormalizedProperty(Handle<JSObject> object,
1880                                      Handle<Name> name,
1881                                      Handle<Object> value,
1882                                      PropertyDetails details) {
1883   DCHECK(!object->HasFastProperties());
1884   if (!name->IsUniqueName()) {
1885     name = object->GetIsolate()->factory()->InternalizeString(
1886         Handle<String>::cast(name));
1887   }
1888 
1889   if (object->IsJSGlobalObject()) {
1890     Handle<GlobalDictionary> dictionary(object->global_dictionary());
1891 
1892     int entry = dictionary->FindEntry(name);
1893     if (entry == GlobalDictionary::kNotFound) {
1894       Isolate* isolate = object->GetIsolate();
1895       auto cell = isolate->factory()->NewPropertyCell();
1896       cell->set_value(*value);
1897       auto cell_type = value->IsUndefined(isolate)
1898                            ? PropertyCellType::kUndefined
1899                            : PropertyCellType::kConstant;
1900       details = details.set_cell_type(cell_type);
1901       value = cell;
1902       dictionary = GlobalDictionary::Add(dictionary, name, value, details);
1903       object->set_properties(*dictionary);
1904     } else {
1905       Handle<PropertyCell> cell =
1906           PropertyCell::PrepareForValue(dictionary, entry, value, details);
1907       cell->set_value(*value);
1908     }
1909   } else {
1910     Handle<NameDictionary> dictionary(object->property_dictionary());
1911 
1912     int entry = dictionary->FindEntry(name);
1913     if (entry == NameDictionary::kNotFound) {
1914       dictionary = NameDictionary::Add(dictionary, name, value, details);
1915       object->set_properties(*dictionary);
1916     } else {
1917       PropertyDetails original_details = dictionary->DetailsAt(entry);
1918       int enumeration_index = original_details.dictionary_index();
1919       DCHECK(enumeration_index > 0);
1920       details = details.set_index(enumeration_index);
1921       dictionary->SetEntry(entry, name, value, details);
1922     }
1923   }
1924 }
1925 
1926 // static
HasInPrototypeChain(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> proto)1927 Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate,
1928                                             Handle<JSReceiver> object,
1929                                             Handle<Object> proto) {
1930   PrototypeIterator iter(isolate, object, kStartAtReceiver);
1931   while (true) {
1932     if (!iter.AdvanceFollowingProxies()) return Nothing<bool>();
1933     if (iter.IsAtEnd()) return Just(false);
1934     if (PrototypeIterator::GetCurrent(iter).is_identical_to(proto)) {
1935       return Just(true);
1936     }
1937   }
1938 }
1939 
GetPrototypeChainRootMap(Isolate * isolate)1940 Map* Object::GetPrototypeChainRootMap(Isolate* isolate) {
1941   DisallowHeapAllocation no_alloc;
1942   if (IsSmi()) {
1943     Context* native_context = isolate->context()->native_context();
1944     return native_context->number_function()->initial_map();
1945   }
1946 
1947   // The object is either a number, a string, a symbol, a boolean, a SIMD value,
1948   // a real JS object, or a Harmony proxy.
1949   HeapObject* heap_object = HeapObject::cast(this);
1950   return heap_object->map()->GetPrototypeChainRootMap(isolate);
1951 }
1952 
GetPrototypeChainRootMap(Isolate * isolate)1953 Map* Map::GetPrototypeChainRootMap(Isolate* isolate) {
1954   DisallowHeapAllocation no_alloc;
1955   if (IsJSReceiverMap()) {
1956     return this;
1957   }
1958   int constructor_function_index = GetConstructorFunctionIndex();
1959   if (constructor_function_index != Map::kNoConstructorFunctionIndex) {
1960     Context* native_context = isolate->context()->native_context();
1961     JSFunction* constructor_function =
1962         JSFunction::cast(native_context->get(constructor_function_index));
1963     return constructor_function->initial_map();
1964   }
1965   return isolate->heap()->null_value()->map();
1966 }
1967 
1968 namespace {
1969 
1970 // Returns a non-SMI for JSObjects, but returns the hash code for simple
1971 // objects.  This avoids a double lookup in the cases where we know we will
1972 // add the hash to the JSObject if it does not already exist.
GetSimpleHash(Object * object)1973 Object* GetSimpleHash(Object* object) {
1974   // The object is either a Smi, a HeapNumber, a name, an odd-ball,
1975   // a SIMD value type, a real JS object, or a Harmony proxy.
1976   if (object->IsSmi()) {
1977     uint32_t hash =
1978         ComputeIntegerHash(Smi::cast(object)->value(), kZeroHashSeed);
1979     return Smi::FromInt(hash & Smi::kMaxValue);
1980   }
1981   if (object->IsHeapNumber()) {
1982     double num = HeapNumber::cast(object)->value();
1983     if (std::isnan(num)) return Smi::FromInt(Smi::kMaxValue);
1984     if (i::IsMinusZero(num)) num = 0;
1985     if (IsSmiDouble(num)) {
1986       return Smi::FromInt(FastD2I(num))->GetHash();
1987     }
1988     uint32_t hash = ComputeLongHash(double_to_uint64(num));
1989     return Smi::FromInt(hash & Smi::kMaxValue);
1990   }
1991   if (object->IsName()) {
1992     uint32_t hash = Name::cast(object)->Hash();
1993     return Smi::FromInt(hash);
1994   }
1995   if (object->IsOddball()) {
1996     uint32_t hash = Oddball::cast(object)->to_string()->Hash();
1997     return Smi::FromInt(hash);
1998   }
1999   if (object->IsSimd128Value()) {
2000     uint32_t hash = Simd128Value::cast(object)->Hash();
2001     return Smi::FromInt(hash & Smi::kMaxValue);
2002   }
2003   DCHECK(object->IsJSReceiver());
2004   // Simply return the receiver as it is guaranteed to not be a SMI.
2005   return object;
2006 }
2007 
2008 }  // namespace
2009 
GetHash()2010 Object* Object::GetHash() {
2011   Object* hash = GetSimpleHash(this);
2012   if (hash->IsSmi()) return hash;
2013 
2014   DisallowHeapAllocation no_gc;
2015   DCHECK(IsJSReceiver());
2016   JSReceiver* receiver = JSReceiver::cast(this);
2017   Isolate* isolate = receiver->GetIsolate();
2018   return JSReceiver::GetIdentityHash(isolate, handle(receiver, isolate));
2019 }
2020 
GetOrCreateHash(Isolate * isolate,Handle<Object> object)2021 Smi* Object::GetOrCreateHash(Isolate* isolate, Handle<Object> object) {
2022   Object* hash = GetSimpleHash(*object);
2023   if (hash->IsSmi()) return Smi::cast(hash);
2024 
2025   DCHECK(object->IsJSReceiver());
2026   return JSReceiver::GetOrCreateIdentityHash(isolate,
2027                                              Handle<JSReceiver>::cast(object));
2028 }
2029 
2030 
SameValue(Object * other)2031 bool Object::SameValue(Object* other) {
2032   if (other == this) return true;
2033 
2034   // The object is either a number, a name, an odd-ball,
2035   // a real JS object, or a Harmony proxy.
2036   if (IsNumber() && other->IsNumber()) {
2037     double this_value = Number();
2038     double other_value = other->Number();
2039     // SameValue(NaN, NaN) is true.
2040     if (this_value != other_value) {
2041       return std::isnan(this_value) && std::isnan(other_value);
2042     }
2043     // SameValue(0.0, -0.0) is false.
2044     return (std::signbit(this_value) == std::signbit(other_value));
2045   }
2046   if (IsString() && other->IsString()) {
2047     return String::cast(this)->Equals(String::cast(other));
2048   }
2049   if (IsFloat32x4() && other->IsFloat32x4()) {
2050     Float32x4* a = Float32x4::cast(this);
2051     Float32x4* b = Float32x4::cast(other);
2052     for (int i = 0; i < 4; i++) {
2053       float x = a->get_lane(i);
2054       float y = b->get_lane(i);
2055       // Implements the ES5 SameValue operation for floating point types.
2056       // http://www.ecma-international.org/ecma-262/6.0/#sec-samevalue
2057       if (x != y && !(std::isnan(x) && std::isnan(y))) return false;
2058       if (std::signbit(x) != std::signbit(y)) return false;
2059     }
2060     return true;
2061   } else if (IsSimd128Value() && other->IsSimd128Value()) {
2062     Simd128Value* a = Simd128Value::cast(this);
2063     Simd128Value* b = Simd128Value::cast(other);
2064     return a->map() == b->map() && a->BitwiseEquals(b);
2065   }
2066   return false;
2067 }
2068 
2069 
SameValueZero(Object * other)2070 bool Object::SameValueZero(Object* other) {
2071   if (other == this) return true;
2072 
2073   // The object is either a number, a name, an odd-ball,
2074   // a real JS object, or a Harmony proxy.
2075   if (IsNumber() && other->IsNumber()) {
2076     double this_value = Number();
2077     double other_value = other->Number();
2078     // +0 == -0 is true
2079     return this_value == other_value ||
2080            (std::isnan(this_value) && std::isnan(other_value));
2081   }
2082   if (IsString() && other->IsString()) {
2083     return String::cast(this)->Equals(String::cast(other));
2084   }
2085   if (IsFloat32x4() && other->IsFloat32x4()) {
2086     Float32x4* a = Float32x4::cast(this);
2087     Float32x4* b = Float32x4::cast(other);
2088     for (int i = 0; i < 4; i++) {
2089       float x = a->get_lane(i);
2090       float y = b->get_lane(i);
2091       // Implements the ES6 SameValueZero operation for floating point types.
2092       // http://www.ecma-international.org/ecma-262/6.0/#sec-samevaluezero
2093       if (x != y && !(std::isnan(x) && std::isnan(y))) return false;
2094       // SameValueZero doesn't distinguish between 0 and -0.
2095     }
2096     return true;
2097   } else if (IsSimd128Value() && other->IsSimd128Value()) {
2098     Simd128Value* a = Simd128Value::cast(this);
2099     Simd128Value* b = Simd128Value::cast(other);
2100     return a->map() == b->map() && a->BitwiseEquals(b);
2101   }
2102   return false;
2103 }
2104 
2105 
ArraySpeciesConstructor(Isolate * isolate,Handle<Object> original_array)2106 MaybeHandle<Object> Object::ArraySpeciesConstructor(
2107     Isolate* isolate, Handle<Object> original_array) {
2108   Handle<Object> default_species = isolate->array_function();
2109   if (original_array->IsJSArray() &&
2110       Handle<JSArray>::cast(original_array)->HasArrayPrototype(isolate) &&
2111       isolate->IsArraySpeciesLookupChainIntact()) {
2112     return default_species;
2113   }
2114   Handle<Object> constructor = isolate->factory()->undefined_value();
2115   Maybe<bool> is_array = Object::IsArray(original_array);
2116   MAYBE_RETURN_NULL(is_array);
2117   if (is_array.FromJust()) {
2118     ASSIGN_RETURN_ON_EXCEPTION(
2119         isolate, constructor,
2120         Object::GetProperty(original_array,
2121                             isolate->factory()->constructor_string()),
2122         Object);
2123     if (constructor->IsConstructor()) {
2124       Handle<Context> constructor_context;
2125       ASSIGN_RETURN_ON_EXCEPTION(
2126           isolate, constructor_context,
2127           JSReceiver::GetFunctionRealm(Handle<JSReceiver>::cast(constructor)),
2128           Object);
2129       if (*constructor_context != *isolate->native_context() &&
2130           *constructor == constructor_context->array_function()) {
2131         constructor = isolate->factory()->undefined_value();
2132       }
2133     }
2134     if (constructor->IsJSReceiver()) {
2135       ASSIGN_RETURN_ON_EXCEPTION(
2136           isolate, constructor,
2137           JSReceiver::GetProperty(Handle<JSReceiver>::cast(constructor),
2138                                   isolate->factory()->species_symbol()),
2139           Object);
2140       if (constructor->IsNull(isolate)) {
2141         constructor = isolate->factory()->undefined_value();
2142       }
2143     }
2144   }
2145   if (constructor->IsUndefined(isolate)) {
2146     return default_species;
2147   } else {
2148     if (!constructor->IsConstructor()) {
2149       THROW_NEW_ERROR(isolate,
2150           NewTypeError(MessageTemplate::kSpeciesNotConstructor),
2151           Object);
2152     }
2153     return constructor;
2154   }
2155 }
2156 
2157 
ShortPrint(FILE * out)2158 void Object::ShortPrint(FILE* out) {
2159   OFStream os(out);
2160   os << Brief(this);
2161 }
2162 
2163 
ShortPrint(StringStream * accumulator)2164 void Object::ShortPrint(StringStream* accumulator) {
2165   std::ostringstream os;
2166   os << Brief(this);
2167   accumulator->Add(os.str().c_str());
2168 }
2169 
2170 
ShortPrint(std::ostream & os)2171 void Object::ShortPrint(std::ostream& os) { os << Brief(this); }
2172 
2173 
operator <<(std::ostream & os,const Brief & v)2174 std::ostream& operator<<(std::ostream& os, const Brief& v) {
2175   if (v.value->IsSmi()) {
2176     Smi::cast(v.value)->SmiPrint(os);
2177   } else {
2178     // TODO(svenpanne) Const-correct HeapObjectShortPrint!
2179     HeapObject* obj = const_cast<HeapObject*>(HeapObject::cast(v.value));
2180     obj->HeapObjectShortPrint(os);
2181   }
2182   return os;
2183 }
2184 
2185 // Declaration of the static Smi::kZero constant.
2186 Smi* const Smi::kZero(nullptr);
2187 
SmiPrint(std::ostream & os) const2188 void Smi::SmiPrint(std::ostream& os) const {  // NOLINT
2189   os << value();
2190 }
2191 
2192 
2193 // Should a word be prefixed by 'a' or 'an' in order to read naturally in
2194 // English?  Returns false for non-ASCII or words that don't start with
2195 // a capital letter.  The a/an rule follows pronunciation in English.
2196 // We don't use the BBC's overcorrect "an historic occasion" though if
2197 // you speak a dialect you may well say "an 'istoric occasion".
AnWord(String * str)2198 static bool AnWord(String* str) {
2199   if (str->length() == 0) return false;  // A nothing.
2200   int c0 = str->Get(0);
2201   int c1 = str->length() > 1 ? str->Get(1) : 0;
2202   if (c0 == 'U') {
2203     if (c1 > 'Z') {
2204       return true;  // An Umpire, but a UTF8String, a U.
2205     }
2206   } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
2207     return true;    // An Ape, an ABCBook.
2208   } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
2209            (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
2210             c0 == 'S' || c0 == 'X')) {
2211     return true;    // An MP3File, an M.
2212   }
2213   return false;
2214 }
2215 
2216 
SlowFlatten(Handle<ConsString> cons,PretenureFlag pretenure)2217 Handle<String> String::SlowFlatten(Handle<ConsString> cons,
2218                                    PretenureFlag pretenure) {
2219   DCHECK(cons->second()->length() != 0);
2220 
2221   // TurboFan can create cons strings with empty first parts.
2222   if (cons->first()->length() == 0) return handle(cons->second());
2223 
2224   DCHECK(AllowHeapAllocation::IsAllowed());
2225   Isolate* isolate = cons->GetIsolate();
2226   int length = cons->length();
2227   PretenureFlag tenure = isolate->heap()->InNewSpace(*cons) ? pretenure
2228                                                             : TENURED;
2229   Handle<SeqString> result;
2230   if (cons->IsOneByteRepresentation()) {
2231     Handle<SeqOneByteString> flat = isolate->factory()->NewRawOneByteString(
2232         length, tenure).ToHandleChecked();
2233     DisallowHeapAllocation no_gc;
2234     WriteToFlat(*cons, flat->GetChars(), 0, length);
2235     result = flat;
2236   } else {
2237     Handle<SeqTwoByteString> flat = isolate->factory()->NewRawTwoByteString(
2238         length, tenure).ToHandleChecked();
2239     DisallowHeapAllocation no_gc;
2240     WriteToFlat(*cons, flat->GetChars(), 0, length);
2241     result = flat;
2242   }
2243   cons->set_first(*result);
2244   cons->set_second(isolate->heap()->empty_string());
2245   DCHECK(result->IsFlat());
2246   return result;
2247 }
2248 
2249 
2250 
MakeExternal(v8::String::ExternalStringResource * resource)2251 bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
2252   // Externalizing twice leaks the external resource, so it's
2253   // prohibited by the API.
2254   DCHECK(!this->IsExternalString());
2255   DCHECK(!resource->IsCompressible());
2256 #ifdef ENABLE_SLOW_DCHECKS
2257   if (FLAG_enable_slow_asserts) {
2258     // Assert that the resource and the string are equivalent.
2259     DCHECK(static_cast<size_t>(this->length()) == resource->length());
2260     ScopedVector<uc16> smart_chars(this->length());
2261     String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2262     DCHECK(memcmp(smart_chars.start(),
2263                   resource->data(),
2264                   resource->length() * sizeof(smart_chars[0])) == 0);
2265   }
2266 #endif  // DEBUG
2267   int size = this->Size();  // Byte size of the original string.
2268   // Abort if size does not allow in-place conversion.
2269   if (size < ExternalString::kShortSize) return false;
2270   Heap* heap = GetHeap();
2271   bool is_one_byte = this->IsOneByteRepresentation();
2272   bool is_internalized = this->IsInternalizedString();
2273   bool has_pointers = this->IsConsString() || this->IsSlicedString();
2274 
2275   // Morph the string to an external string by replacing the map and
2276   // reinitializing the fields.  This won't work if the space the existing
2277   // string occupies is too small for a regular  external string.
2278   // Instead, we resort to a short external string instead, omitting
2279   // the field caching the address of the backing store.  When we encounter
2280   // short external strings in generated code, we need to bailout to runtime.
2281   Map* new_map;
2282   if (size < ExternalString::kSize) {
2283     new_map = is_internalized
2284         ? (is_one_byte
2285            ? heap->short_external_internalized_string_with_one_byte_data_map()
2286            : heap->short_external_internalized_string_map())
2287         : (is_one_byte ? heap->short_external_string_with_one_byte_data_map()
2288                        : heap->short_external_string_map());
2289   } else {
2290     new_map = is_internalized
2291         ? (is_one_byte
2292            ? heap->external_internalized_string_with_one_byte_data_map()
2293            : heap->external_internalized_string_map())
2294         : (is_one_byte ? heap->external_string_with_one_byte_data_map()
2295                        : heap->external_string_map());
2296   }
2297 
2298   // Byte size of the external String object.
2299   int new_size = this->SizeFromMap(new_map);
2300   heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
2301                              ClearRecordedSlots::kNo);
2302   if (has_pointers) {
2303     heap->ClearRecordedSlotRange(this->address(), this->address() + new_size);
2304   }
2305 
2306   // We are storing the new map using release store after creating a filler for
2307   // the left-over space to avoid races with the sweeper thread.
2308   this->synchronized_set_map(new_map);
2309 
2310   ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
2311   self->set_resource(resource);
2312   if (is_internalized) self->Hash();  // Force regeneration of the hash value.
2313 
2314   heap->AdjustLiveBytes(this, new_size - size, Heap::CONCURRENT_TO_SWEEPER);
2315   return true;
2316 }
2317 
2318 
MakeExternal(v8::String::ExternalOneByteStringResource * resource)2319 bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
2320   // Externalizing twice leaks the external resource, so it's
2321   // prohibited by the API.
2322   DCHECK(!this->IsExternalString());
2323   DCHECK(!resource->IsCompressible());
2324 #ifdef ENABLE_SLOW_DCHECKS
2325   if (FLAG_enable_slow_asserts) {
2326     // Assert that the resource and the string are equivalent.
2327     DCHECK(static_cast<size_t>(this->length()) == resource->length());
2328     if (this->IsTwoByteRepresentation()) {
2329       ScopedVector<uint16_t> smart_chars(this->length());
2330       String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2331       DCHECK(String::IsOneByte(smart_chars.start(), this->length()));
2332     }
2333     ScopedVector<char> smart_chars(this->length());
2334     String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2335     DCHECK(memcmp(smart_chars.start(),
2336                   resource->data(),
2337                   resource->length() * sizeof(smart_chars[0])) == 0);
2338   }
2339 #endif  // DEBUG
2340   int size = this->Size();  // Byte size of the original string.
2341   // Abort if size does not allow in-place conversion.
2342   if (size < ExternalString::kShortSize) return false;
2343   Heap* heap = GetHeap();
2344   bool is_internalized = this->IsInternalizedString();
2345   bool has_pointers = this->IsConsString() || this->IsSlicedString();
2346 
2347   // Morph the string to an external string by replacing the map and
2348   // reinitializing the fields.  This won't work if the space the existing
2349   // string occupies is too small for a regular  external string.
2350   // Instead, we resort to a short external string instead, omitting
2351   // the field caching the address of the backing store.  When we encounter
2352   // short external strings in generated code, we need to bailout to runtime.
2353   Map* new_map;
2354   if (size < ExternalString::kSize) {
2355     new_map = is_internalized
2356                   ? heap->short_external_one_byte_internalized_string_map()
2357                   : heap->short_external_one_byte_string_map();
2358   } else {
2359     new_map = is_internalized
2360                   ? heap->external_one_byte_internalized_string_map()
2361                   : heap->external_one_byte_string_map();
2362   }
2363 
2364   // Byte size of the external String object.
2365   int new_size = this->SizeFromMap(new_map);
2366   heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
2367                              ClearRecordedSlots::kNo);
2368   if (has_pointers) {
2369     heap->ClearRecordedSlotRange(this->address(), this->address() + new_size);
2370   }
2371 
2372   // We are storing the new map using release store after creating a filler for
2373   // the left-over space to avoid races with the sweeper thread.
2374   this->synchronized_set_map(new_map);
2375 
2376   ExternalOneByteString* self = ExternalOneByteString::cast(this);
2377   self->set_resource(resource);
2378   if (is_internalized) self->Hash();  // Force regeneration of the hash value.
2379 
2380   heap->AdjustLiveBytes(this, new_size - size, Heap::CONCURRENT_TO_SWEEPER);
2381   return true;
2382 }
2383 
StringShortPrint(StringStream * accumulator,bool show_details)2384 void String::StringShortPrint(StringStream* accumulator, bool show_details) {
2385   int len = length();
2386   if (len > kMaxShortPrintLength) {
2387     accumulator->Add("<Very long string[%u]>", len);
2388     return;
2389   }
2390 
2391   if (!LooksValid()) {
2392     accumulator->Add("<Invalid String>");
2393     return;
2394   }
2395 
2396   StringCharacterStream stream(this);
2397 
2398   bool truncated = false;
2399   if (len > kMaxShortPrintLength) {
2400     len = kMaxShortPrintLength;
2401     truncated = true;
2402   }
2403   bool one_byte = true;
2404   for (int i = 0; i < len; i++) {
2405     uint16_t c = stream.GetNext();
2406 
2407     if (c < 32 || c >= 127) {
2408       one_byte = false;
2409     }
2410   }
2411   stream.Reset(this);
2412   if (one_byte) {
2413     if (show_details) accumulator->Add("<String[%u]: ", length());
2414     for (int i = 0; i < len; i++) {
2415       accumulator->Put(static_cast<char>(stream.GetNext()));
2416     }
2417     if (show_details) accumulator->Put('>');
2418   } else {
2419     // Backslash indicates that the string contains control
2420     // characters and that backslashes are therefore escaped.
2421     if (show_details) accumulator->Add("<String[%u]\\: ", length());
2422     for (int i = 0; i < len; i++) {
2423       uint16_t c = stream.GetNext();
2424       if (c == '\n') {
2425         accumulator->Add("\\n");
2426       } else if (c == '\r') {
2427         accumulator->Add("\\r");
2428       } else if (c == '\\') {
2429         accumulator->Add("\\\\");
2430       } else if (c < 32 || c > 126) {
2431         accumulator->Add("\\x%02x", c);
2432       } else {
2433         accumulator->Put(static_cast<char>(c));
2434       }
2435     }
2436     if (truncated) {
2437       accumulator->Put('.');
2438       accumulator->Put('.');
2439       accumulator->Put('.');
2440     }
2441     if (show_details) accumulator->Put('>');
2442   }
2443   return;
2444 }
2445 
2446 
PrintUC16(std::ostream & os,int start,int end)2447 void String::PrintUC16(std::ostream& os, int start, int end) {  // NOLINT
2448   if (end < 0) end = length();
2449   StringCharacterStream stream(this, start);
2450   for (int i = start; i < end && stream.HasMore(); i++) {
2451     os << AsUC16(stream.GetNext());
2452   }
2453 }
2454 
2455 
JSObjectShortPrint(StringStream * accumulator)2456 void JSObject::JSObjectShortPrint(StringStream* accumulator) {
2457   switch (map()->instance_type()) {
2458     case JS_ARRAY_TYPE: {
2459       double length = JSArray::cast(this)->length()->IsUndefined(GetIsolate())
2460                           ? 0
2461                           : JSArray::cast(this)->length()->Number();
2462       accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length));
2463       break;
2464     }
2465     case JS_BOUND_FUNCTION_TYPE: {
2466       JSBoundFunction* bound_function = JSBoundFunction::cast(this);
2467       accumulator->Add("<JS BoundFunction");
2468       accumulator->Add(
2469           " (BoundTargetFunction %p)>",
2470           reinterpret_cast<void*>(bound_function->bound_target_function()));
2471       break;
2472     }
2473     case JS_WEAK_MAP_TYPE: {
2474       accumulator->Add("<JS WeakMap>");
2475       break;
2476     }
2477     case JS_WEAK_SET_TYPE: {
2478       accumulator->Add("<JS WeakSet>");
2479       break;
2480     }
2481     case JS_REGEXP_TYPE: {
2482       accumulator->Add("<JS RegExp>");
2483       break;
2484     }
2485     case JS_FUNCTION_TYPE: {
2486       JSFunction* function = JSFunction::cast(this);
2487       Object* fun_name = function->shared()->DebugName();
2488       bool printed = false;
2489       if (fun_name->IsString()) {
2490         String* str = String::cast(fun_name);
2491         if (str->length() > 0) {
2492           accumulator->Add("<JS Function ");
2493           accumulator->Put(str);
2494           printed = true;
2495         }
2496       }
2497       if (!printed) {
2498         accumulator->Add("<JS Function");
2499       }
2500       if (FLAG_trace_file_names) {
2501         Object* source_name =
2502             Script::cast(function->shared()->script())->name();
2503         if (source_name->IsString()) {
2504           String* str = String::cast(source_name);
2505           if (str->length() > 0) {
2506             accumulator->Add(" <");
2507             accumulator->Put(str);
2508             accumulator->Add(">");
2509           }
2510         }
2511       }
2512       accumulator->Add(" (SharedFunctionInfo %p)",
2513                        reinterpret_cast<void*>(function->shared()));
2514       accumulator->Put('>');
2515       break;
2516     }
2517     case JS_GENERATOR_OBJECT_TYPE: {
2518       accumulator->Add("<JS Generator>");
2519       break;
2520     }
2521     // All other JSObjects are rather similar to each other (JSObject,
2522     // JSGlobalProxy, JSGlobalObject, JSUndetectable, JSValue).
2523     default: {
2524       Map* map_of_this = map();
2525       Heap* heap = GetHeap();
2526       Object* constructor = map_of_this->GetConstructor();
2527       bool printed = false;
2528       if (constructor->IsHeapObject() &&
2529           !heap->Contains(HeapObject::cast(constructor))) {
2530         accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
2531       } else {
2532         bool global_object = IsJSGlobalProxy();
2533         if (constructor->IsJSFunction()) {
2534           if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
2535             accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
2536           } else {
2537             Object* constructor_name =
2538                 JSFunction::cast(constructor)->shared()->name();
2539             if (constructor_name->IsString()) {
2540               String* str = String::cast(constructor_name);
2541               if (str->length() > 0) {
2542                 bool vowel = AnWord(str);
2543                 accumulator->Add("<%sa%s ",
2544                        global_object ? "Global Object: " : "",
2545                        vowel ? "n" : "");
2546                 accumulator->Put(str);
2547                 accumulator->Add(" with %smap %p",
2548                     map_of_this->is_deprecated() ? "deprecated " : "",
2549                     map_of_this);
2550                 printed = true;
2551               }
2552             }
2553           }
2554         }
2555         if (!printed) {
2556           accumulator->Add("<JS %sObject", global_object ? "Global " : "");
2557         }
2558       }
2559       if (IsJSValue()) {
2560         accumulator->Add(" value = ");
2561         JSValue::cast(this)->value()->ShortPrint(accumulator);
2562       }
2563       accumulator->Put('>');
2564       break;
2565     }
2566   }
2567 }
2568 
2569 
PrintElementsTransition(FILE * file,Handle<JSObject> object,ElementsKind from_kind,Handle<FixedArrayBase> from_elements,ElementsKind to_kind,Handle<FixedArrayBase> to_elements)2570 void JSObject::PrintElementsTransition(
2571     FILE* file, Handle<JSObject> object,
2572     ElementsKind from_kind, Handle<FixedArrayBase> from_elements,
2573     ElementsKind to_kind, Handle<FixedArrayBase> to_elements) {
2574   if (from_kind != to_kind) {
2575     OFStream os(file);
2576     os << "elements transition [" << ElementsKindToString(from_kind) << " -> "
2577        << ElementsKindToString(to_kind) << "] in ";
2578     JavaScriptFrame::PrintTop(object->GetIsolate(), file, false, true);
2579     PrintF(file, " for ");
2580     object->ShortPrint(file);
2581     PrintF(file, " from ");
2582     from_elements->ShortPrint(file);
2583     PrintF(file, " to ");
2584     to_elements->ShortPrint(file);
2585     PrintF(file, "\n");
2586   }
2587 }
2588 
2589 
2590 // static
GetConstructorFunction(Handle<Map> map,Handle<Context> native_context)2591 MaybeHandle<JSFunction> Map::GetConstructorFunction(
2592     Handle<Map> map, Handle<Context> native_context) {
2593   if (map->IsPrimitiveMap()) {
2594     int const constructor_function_index = map->GetConstructorFunctionIndex();
2595     if (constructor_function_index != kNoConstructorFunctionIndex) {
2596       return handle(
2597           JSFunction::cast(native_context->get(constructor_function_index)));
2598     }
2599   }
2600   return MaybeHandle<JSFunction>();
2601 }
2602 
2603 
PrintReconfiguration(FILE * file,int modify_index,PropertyKind kind,PropertyAttributes attributes)2604 void Map::PrintReconfiguration(FILE* file, int modify_index, PropertyKind kind,
2605                                PropertyAttributes attributes) {
2606   OFStream os(file);
2607   os << "[reconfiguring]";
2608   Name* name = instance_descriptors()->GetKey(modify_index);
2609   if (name->IsString()) {
2610     String::cast(name)->PrintOn(file);
2611   } else {
2612     os << "{symbol " << static_cast<void*>(name) << "}";
2613   }
2614   os << ": " << (kind == kData ? "kData" : "ACCESSORS") << ", attrs: ";
2615   os << attributes << " [";
2616   JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
2617   os << "]\n";
2618 }
2619 
PrintGeneralization(FILE * file,const char * reason,int modify_index,int split,int descriptors,bool constant_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)2620 void Map::PrintGeneralization(
2621     FILE* file, const char* reason, int modify_index, int split,
2622     int descriptors, bool constant_to_field, Representation old_representation,
2623     Representation new_representation, MaybeHandle<FieldType> old_field_type,
2624     MaybeHandle<Object> old_value, MaybeHandle<FieldType> new_field_type,
2625     MaybeHandle<Object> new_value) {
2626   OFStream os(file);
2627   os << "[generalizing]";
2628   Name* name = instance_descriptors()->GetKey(modify_index);
2629   if (name->IsString()) {
2630     String::cast(name)->PrintOn(file);
2631   } else {
2632     os << "{symbol " << static_cast<void*>(name) << "}";
2633   }
2634   os << ":";
2635   if (constant_to_field) {
2636     os << "c";
2637   } else {
2638     os << old_representation.Mnemonic() << "{";
2639     if (old_field_type.is_null()) {
2640       os << Brief(*(old_value.ToHandleChecked()));
2641     } else {
2642       old_field_type.ToHandleChecked()->PrintTo(os);
2643     }
2644     os << "}";
2645   }
2646   os << "->" << new_representation.Mnemonic() << "{";
2647   if (new_field_type.is_null()) {
2648     os << Brief(*(new_value.ToHandleChecked()));
2649   } else {
2650     new_field_type.ToHandleChecked()->PrintTo(os);
2651   }
2652   os << "} (";
2653   if (strlen(reason) > 0) {
2654     os << reason;
2655   } else {
2656     os << "+" << (descriptors - split) << " maps";
2657   }
2658   os << ") [";
2659   JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
2660   os << "]\n";
2661 }
2662 
2663 
PrintInstanceMigration(FILE * file,Map * original_map,Map * new_map)2664 void JSObject::PrintInstanceMigration(FILE* file,
2665                                       Map* original_map,
2666                                       Map* new_map) {
2667   PrintF(file, "[migrating]");
2668   DescriptorArray* o = original_map->instance_descriptors();
2669   DescriptorArray* n = new_map->instance_descriptors();
2670   for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) {
2671     Representation o_r = o->GetDetails(i).representation();
2672     Representation n_r = n->GetDetails(i).representation();
2673     if (!o_r.Equals(n_r)) {
2674       String::cast(o->GetKey(i))->PrintOn(file);
2675       PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic());
2676     } else if (o->GetDetails(i).type() == DATA_CONSTANT &&
2677                n->GetDetails(i).type() == DATA) {
2678       Name* name = o->GetKey(i);
2679       if (name->IsString()) {
2680         String::cast(name)->PrintOn(file);
2681       } else {
2682         PrintF(file, "{symbol %p}", static_cast<void*>(name));
2683       }
2684       PrintF(file, " ");
2685     }
2686   }
2687   PrintF(file, "\n");
2688 }
2689 
2690 
HeapObjectShortPrint(std::ostream & os)2691 void HeapObject::HeapObjectShortPrint(std::ostream& os) {  // NOLINT
2692   Heap* heap = GetHeap();
2693   Isolate* isolate = heap->isolate();
2694   if (!heap->Contains(this)) {
2695     os << "!!!INVALID POINTER!!!";
2696     return;
2697   }
2698   if (!heap->Contains(map())) {
2699     os << "!!!INVALID MAP!!!";
2700     return;
2701   }
2702 
2703   os << this << " ";
2704 
2705   if (IsString()) {
2706     HeapStringAllocator allocator;
2707     StringStream accumulator(&allocator);
2708     String::cast(this)->StringShortPrint(&accumulator);
2709     os << accumulator.ToCString().get();
2710     return;
2711   }
2712   if (IsJSObject()) {
2713     HeapStringAllocator allocator;
2714     StringStream accumulator(&allocator);
2715     JSObject::cast(this)->JSObjectShortPrint(&accumulator);
2716     os << accumulator.ToCString().get();
2717     return;
2718   }
2719   switch (map()->instance_type()) {
2720     case MAP_TYPE:
2721       os << "<Map(" << ElementsKindToString(Map::cast(this)->elements_kind())
2722          << ")>";
2723       break;
2724     case FIXED_ARRAY_TYPE:
2725       os << "<FixedArray[" << FixedArray::cast(this)->length() << "]>";
2726       break;
2727     case FIXED_DOUBLE_ARRAY_TYPE:
2728       os << "<FixedDoubleArray[" << FixedDoubleArray::cast(this)->length()
2729          << "]>";
2730       break;
2731     case BYTE_ARRAY_TYPE:
2732       os << "<ByteArray[" << ByteArray::cast(this)->length() << "]>";
2733       break;
2734     case BYTECODE_ARRAY_TYPE:
2735       os << "<BytecodeArray[" << BytecodeArray::cast(this)->length() << "]>";
2736       break;
2737     case TRANSITION_ARRAY_TYPE:
2738       os << "<TransitionArray[" << TransitionArray::cast(this)->length()
2739          << "]>";
2740       break;
2741     case FREE_SPACE_TYPE:
2742       os << "<FreeSpace[" << FreeSpace::cast(this)->size() << "]>";
2743       break;
2744 #define TYPED_ARRAY_SHORT_PRINT(Type, type, TYPE, ctype, size)                \
2745   case FIXED_##TYPE##_ARRAY_TYPE:                                             \
2746     os << "<Fixed" #Type "Array[" << Fixed##Type##Array::cast(this)->length() \
2747        << "]>";                                                               \
2748     break;
2749 
2750     TYPED_ARRAYS(TYPED_ARRAY_SHORT_PRINT)
2751 #undef TYPED_ARRAY_SHORT_PRINT
2752 
2753     case SHARED_FUNCTION_INFO_TYPE: {
2754       SharedFunctionInfo* shared = SharedFunctionInfo::cast(this);
2755       std::unique_ptr<char[]> debug_name = shared->DebugName()->ToCString();
2756       if (debug_name[0] != 0) {
2757         os << "<SharedFunctionInfo " << debug_name.get() << ">";
2758       } else {
2759         os << "<SharedFunctionInfo>";
2760       }
2761       break;
2762     }
2763     case JS_MESSAGE_OBJECT_TYPE:
2764       os << "<JSMessageObject>";
2765       break;
2766 #define MAKE_STRUCT_CASE(NAME, Name, name) \
2767   case NAME##_TYPE:                        \
2768     os << "<" #Name ">";                   \
2769     break;
2770   STRUCT_LIST(MAKE_STRUCT_CASE)
2771 #undef MAKE_STRUCT_CASE
2772     case CODE_TYPE: {
2773       Code* code = Code::cast(this);
2774       os << "<Code: " << Code::Kind2String(code->kind()) << ">";
2775       break;
2776     }
2777     case ODDBALL_TYPE: {
2778       if (IsUndefined(isolate)) {
2779         os << "<undefined>";
2780       } else if (IsTheHole(isolate)) {
2781         os << "<the hole>";
2782       } else if (IsNull(isolate)) {
2783         os << "<null>";
2784       } else if (IsTrue(isolate)) {
2785         os << "<true>";
2786       } else if (IsFalse(isolate)) {
2787         os << "<false>";
2788       } else {
2789         os << "<Odd Oddball: ";
2790         os << Oddball::cast(this)->to_string()->ToCString().get();
2791         os << ">";
2792       }
2793       break;
2794     }
2795     case SYMBOL_TYPE: {
2796       Symbol* symbol = Symbol::cast(this);
2797       symbol->SymbolShortPrint(os);
2798       break;
2799     }
2800     case HEAP_NUMBER_TYPE: {
2801       os << "<Number: ";
2802       HeapNumber::cast(this)->HeapNumberPrint(os);
2803       os << ">";
2804       break;
2805     }
2806     case MUTABLE_HEAP_NUMBER_TYPE: {
2807       os << "<MutableNumber: ";
2808       HeapNumber::cast(this)->HeapNumberPrint(os);
2809       os << '>';
2810       break;
2811     }
2812     case SIMD128_VALUE_TYPE: {
2813 #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
2814   if (Is##Type()) {                                           \
2815     os << "<" #Type ">";                                      \
2816     break;                                                    \
2817   }
2818       SIMD128_TYPES(SIMD128_TYPE)
2819 #undef SIMD128_TYPE
2820       UNREACHABLE();
2821       break;
2822     }
2823     case JS_PROXY_TYPE:
2824       os << "<JSProxy>";
2825       break;
2826     case FOREIGN_TYPE:
2827       os << "<Foreign>";
2828       break;
2829     case CELL_TYPE: {
2830       os << "Cell for ";
2831       HeapStringAllocator allocator;
2832       StringStream accumulator(&allocator);
2833       Cell::cast(this)->value()->ShortPrint(&accumulator);
2834       os << accumulator.ToCString().get();
2835       break;
2836     }
2837     case PROPERTY_CELL_TYPE: {
2838       os << "PropertyCell for ";
2839       HeapStringAllocator allocator;
2840       StringStream accumulator(&allocator);
2841       PropertyCell* cell = PropertyCell::cast(this);
2842       cell->value()->ShortPrint(&accumulator);
2843       os << accumulator.ToCString().get();
2844       break;
2845     }
2846     case WEAK_CELL_TYPE: {
2847       os << "WeakCell for ";
2848       HeapStringAllocator allocator;
2849       StringStream accumulator(&allocator);
2850       WeakCell::cast(this)->value()->ShortPrint(&accumulator);
2851       os << accumulator.ToCString().get();
2852       break;
2853     }
2854     default:
2855       os << "<Other heap object (" << map()->instance_type() << ")>";
2856       break;
2857   }
2858 }
2859 
2860 
Iterate(ObjectVisitor * v)2861 void HeapObject::Iterate(ObjectVisitor* v) { IterateFast<ObjectVisitor>(v); }
2862 
2863 
IterateBody(ObjectVisitor * v)2864 void HeapObject::IterateBody(ObjectVisitor* v) {
2865   Map* m = map();
2866   IterateBodyFast<ObjectVisitor>(m->instance_type(), SizeFromMap(m), v);
2867 }
2868 
2869 
IterateBody(InstanceType type,int object_size,ObjectVisitor * v)2870 void HeapObject::IterateBody(InstanceType type, int object_size,
2871                              ObjectVisitor* v) {
2872   IterateBodyFast<ObjectVisitor>(type, object_size, v);
2873 }
2874 
2875 
2876 struct CallIsValidSlot {
2877   template <typename BodyDescriptor>
applyv8::internal::CallIsValidSlot2878   static bool apply(HeapObject* obj, int offset, int) {
2879     return BodyDescriptor::IsValidSlot(obj, offset);
2880   }
2881 };
2882 
2883 
IsValidSlot(int offset)2884 bool HeapObject::IsValidSlot(int offset) {
2885   DCHECK_NE(0, offset);
2886   return BodyDescriptorApply<CallIsValidSlot, bool>(map()->instance_type(),
2887                                                     this, offset, 0);
2888 }
2889 
2890 
HeapNumberBooleanValue()2891 bool HeapNumber::HeapNumberBooleanValue() {
2892   return DoubleToBoolean(value());
2893 }
2894 
2895 
HeapNumberPrint(std::ostream & os)2896 void HeapNumber::HeapNumberPrint(std::ostream& os) {  // NOLINT
2897   os << value();
2898 }
2899 
2900 
2901 #define FIELD_ADDR_CONST(p, offset) \
2902   (reinterpret_cast<const byte*>(p) + offset - kHeapObjectTag)
2903 
2904 #define READ_INT32_FIELD(p, offset) \
2905   (*reinterpret_cast<const int32_t*>(FIELD_ADDR_CONST(p, offset)))
2906 
2907 #define READ_INT64_FIELD(p, offset) \
2908   (*reinterpret_cast<const int64_t*>(FIELD_ADDR_CONST(p, offset)))
2909 
2910 #define READ_BYTE_FIELD(p, offset) \
2911   (*reinterpret_cast<const byte*>(FIELD_ADDR_CONST(p, offset)))
2912 
2913 
2914 // static
ToString(Handle<Simd128Value> input)2915 Handle<String> Simd128Value::ToString(Handle<Simd128Value> input) {
2916 #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
2917   if (input->Is##Type()) return Type::ToString(Handle<Type>::cast(input));
2918   SIMD128_TYPES(SIMD128_TYPE)
2919 #undef SIMD128_TYPE
2920   UNREACHABLE();
2921   return Handle<String>::null();
2922 }
2923 
2924 
2925 // static
ToString(Handle<Float32x4> input)2926 Handle<String> Float32x4::ToString(Handle<Float32x4> input) {
2927   Isolate* const isolate = input->GetIsolate();
2928   char arr[100];
2929   Vector<char> buffer(arr, arraysize(arr));
2930   std::ostringstream os;
2931   os << "SIMD.Float32x4("
2932      << std::string(DoubleToCString(input->get_lane(0), buffer)) << ", "
2933      << std::string(DoubleToCString(input->get_lane(1), buffer)) << ", "
2934      << std::string(DoubleToCString(input->get_lane(2), buffer)) << ", "
2935      << std::string(DoubleToCString(input->get_lane(3), buffer)) << ")";
2936   return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str());
2937 }
2938 
2939 
2940 #define SIMD128_BOOL_TO_STRING(Type, lane_count)                            \
2941   Handle<String> Type::ToString(Handle<Type> input) {                       \
2942     Isolate* const isolate = input->GetIsolate();                           \
2943     std::ostringstream os;                                                  \
2944     os << "SIMD." #Type "(";                                                \
2945     os << (input->get_lane(0) ? "true" : "false");                          \
2946     for (int i = 1; i < lane_count; i++) {                                  \
2947       os << ", " << (input->get_lane(i) ? "true" : "false");                \
2948     }                                                                       \
2949     os << ")";                                                              \
2950     return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str()); \
2951   }
2952 SIMD128_BOOL_TO_STRING(Bool32x4, 4)
2953 SIMD128_BOOL_TO_STRING(Bool16x8, 8)
2954 SIMD128_BOOL_TO_STRING(Bool8x16, 16)
2955 #undef SIMD128_BOOL_TO_STRING
2956 
2957 
2958 #define SIMD128_INT_TO_STRING(Type, lane_count)                             \
2959   Handle<String> Type::ToString(Handle<Type> input) {                       \
2960     Isolate* const isolate = input->GetIsolate();                           \
2961     char arr[100];                                                          \
2962     Vector<char> buffer(arr, arraysize(arr));                               \
2963     std::ostringstream os;                                                  \
2964     os << "SIMD." #Type "(";                                                \
2965     os << IntToCString(input->get_lane(0), buffer);                         \
2966     for (int i = 1; i < lane_count; i++) {                                  \
2967       os << ", " << IntToCString(input->get_lane(i), buffer);               \
2968     }                                                                       \
2969     os << ")";                                                              \
2970     return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str()); \
2971   }
2972 SIMD128_INT_TO_STRING(Int32x4, 4)
2973 SIMD128_INT_TO_STRING(Uint32x4, 4)
2974 SIMD128_INT_TO_STRING(Int16x8, 8)
2975 SIMD128_INT_TO_STRING(Uint16x8, 8)
2976 SIMD128_INT_TO_STRING(Int8x16, 16)
2977 SIMD128_INT_TO_STRING(Uint8x16, 16)
2978 #undef SIMD128_INT_TO_STRING
2979 
2980 
BitwiseEquals(const Simd128Value * other) const2981 bool Simd128Value::BitwiseEquals(const Simd128Value* other) const {
2982   return READ_INT64_FIELD(this, kValueOffset) ==
2983              READ_INT64_FIELD(other, kValueOffset) &&
2984          READ_INT64_FIELD(this, kValueOffset + kInt64Size) ==
2985              READ_INT64_FIELD(other, kValueOffset + kInt64Size);
2986 }
2987 
2988 
Hash() const2989 uint32_t Simd128Value::Hash() const {
2990   uint32_t seed = v8::internal::kZeroHashSeed;
2991   uint32_t hash;
2992   hash = ComputeIntegerHash(READ_INT32_FIELD(this, kValueOffset), seed);
2993   hash = ComputeIntegerHash(
2994       READ_INT32_FIELD(this, kValueOffset + 1 * kInt32Size), hash * 31);
2995   hash = ComputeIntegerHash(
2996       READ_INT32_FIELD(this, kValueOffset + 2 * kInt32Size), hash * 31);
2997   hash = ComputeIntegerHash(
2998       READ_INT32_FIELD(this, kValueOffset + 3 * kInt32Size), hash * 31);
2999   return hash;
3000 }
3001 
3002 
CopyBits(void * destination) const3003 void Simd128Value::CopyBits(void* destination) const {
3004   memcpy(destination, &READ_BYTE_FIELD(this, kValueOffset), kSimd128Size);
3005 }
3006 
3007 
class_name()3008 String* JSReceiver::class_name() {
3009   if (IsFunction()) {
3010     return GetHeap()->Function_string();
3011   }
3012   Object* maybe_constructor = map()->GetConstructor();
3013   if (maybe_constructor->IsJSFunction()) {
3014     JSFunction* constructor = JSFunction::cast(maybe_constructor);
3015     return String::cast(constructor->shared()->instance_class_name());
3016   }
3017   // If the constructor is not present, return "Object".
3018   return GetHeap()->Object_string();
3019 }
3020 
3021 
3022 // static
GetConstructorName(Handle<JSReceiver> receiver)3023 Handle<String> JSReceiver::GetConstructorName(Handle<JSReceiver> receiver) {
3024   Isolate* isolate = receiver->GetIsolate();
3025 
3026   // If the object was instantiated simply with base == new.target, the
3027   // constructor on the map provides the most accurate name.
3028   // Don't provide the info for prototypes, since their constructors are
3029   // reclaimed and replaced by Object in OptimizeAsPrototype.
3030   if (!receiver->IsJSProxy() && receiver->map()->new_target_is_base() &&
3031       !receiver->map()->is_prototype_map()) {
3032     Object* maybe_constructor = receiver->map()->GetConstructor();
3033     if (maybe_constructor->IsJSFunction()) {
3034       JSFunction* constructor = JSFunction::cast(maybe_constructor);
3035       String* name = String::cast(constructor->shared()->name());
3036       if (name->length() == 0) name = constructor->shared()->inferred_name();
3037       if (name->length() != 0 &&
3038           !name->Equals(isolate->heap()->Object_string())) {
3039         return handle(name, isolate);
3040       }
3041     }
3042   }
3043 
3044   Handle<Object> maybe_tag = JSReceiver::GetDataProperty(
3045       receiver, isolate->factory()->to_string_tag_symbol());
3046   if (maybe_tag->IsString()) return Handle<String>::cast(maybe_tag);
3047 
3048   PrototypeIterator iter(isolate, receiver);
3049   if (iter.IsAtEnd()) return handle(receiver->class_name());
3050   Handle<JSReceiver> start = PrototypeIterator::GetCurrent<JSReceiver>(iter);
3051   LookupIterator it(receiver, isolate->factory()->constructor_string(), start,
3052                     LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
3053   Handle<Object> maybe_constructor = JSReceiver::GetDataProperty(&it);
3054   Handle<String> result = isolate->factory()->Object_string();
3055   if (maybe_constructor->IsJSFunction()) {
3056     JSFunction* constructor = JSFunction::cast(*maybe_constructor);
3057     String* name = String::cast(constructor->shared()->name());
3058     if (name->length() == 0) name = constructor->shared()->inferred_name();
3059     if (name->length() > 0) result = handle(name, isolate);
3060   }
3061 
3062   return result.is_identical_to(isolate->factory()->Object_string())
3063              ? handle(receiver->class_name())
3064              : result;
3065 }
3066 
3067 
GetCreationContext()3068 Context* JSReceiver::GetCreationContext() {
3069   JSReceiver* receiver = this;
3070   while (receiver->IsJSBoundFunction()) {
3071     receiver = JSBoundFunction::cast(receiver)->bound_target_function();
3072   }
3073   Object* constructor = receiver->map()->GetConstructor();
3074   JSFunction* function;
3075   if (constructor->IsJSFunction()) {
3076     function = JSFunction::cast(constructor);
3077   } else {
3078     // Functions have null as a constructor,
3079     // but any JSFunction knows its context immediately.
3080     CHECK(receiver->IsJSFunction());
3081     function = JSFunction::cast(receiver);
3082   }
3083 
3084   return function->context()->native_context();
3085 }
3086 
WrapType(Handle<FieldType> type)3087 static Handle<Object> WrapType(Handle<FieldType> type) {
3088   if (type->IsClass()) return Map::WeakCellForMap(type->AsClass());
3089   return type;
3090 }
3091 
CopyWithField(Handle<Map> map,Handle<Name> name,Handle<FieldType> type,PropertyAttributes attributes,Representation representation,TransitionFlag flag)3092 MaybeHandle<Map> Map::CopyWithField(Handle<Map> map, Handle<Name> name,
3093                                     Handle<FieldType> type,
3094                                     PropertyAttributes attributes,
3095                                     Representation representation,
3096                                     TransitionFlag flag) {
3097   DCHECK(DescriptorArray::kNotFound ==
3098          map->instance_descriptors()->Search(
3099              *name, map->NumberOfOwnDescriptors()));
3100 
3101   // Ensure the descriptor array does not get too big.
3102   if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
3103     return MaybeHandle<Map>();
3104   }
3105 
3106   Isolate* isolate = map->GetIsolate();
3107 
3108   // Compute the new index for new field.
3109   int index = map->NextFreePropertyIndex();
3110 
3111   if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
3112     representation = Representation::Tagged();
3113     type = FieldType::Any(isolate);
3114   }
3115 
3116   Handle<Object> wrapped_type(WrapType(type));
3117 
3118   DataDescriptor new_field_desc(name, index, wrapped_type, attributes,
3119                                 representation);
3120   Handle<Map> new_map = Map::CopyAddDescriptor(map, &new_field_desc, flag);
3121   int unused_property_fields = new_map->unused_property_fields() - 1;
3122   if (unused_property_fields < 0) {
3123     unused_property_fields += JSObject::kFieldsAdded;
3124   }
3125   new_map->set_unused_property_fields(unused_property_fields);
3126   return new_map;
3127 }
3128 
3129 
CopyWithConstant(Handle<Map> map,Handle<Name> name,Handle<Object> constant,PropertyAttributes attributes,TransitionFlag flag)3130 MaybeHandle<Map> Map::CopyWithConstant(Handle<Map> map,
3131                                        Handle<Name> name,
3132                                        Handle<Object> constant,
3133                                        PropertyAttributes attributes,
3134                                        TransitionFlag flag) {
3135   // Ensure the descriptor array does not get too big.
3136   if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
3137     return MaybeHandle<Map>();
3138   }
3139 
3140   // Allocate new instance descriptors with (name, constant) added.
3141   DataConstantDescriptor new_constant_desc(name, constant, attributes);
3142   return Map::CopyAddDescriptor(map, &new_constant_desc, flag);
3143 }
3144 
Mnemonic() const3145 const char* Representation::Mnemonic() const {
3146   switch (kind_) {
3147     case kNone: return "v";
3148     case kTagged: return "t";
3149     case kSmi: return "s";
3150     case kDouble: return "d";
3151     case kInteger32: return "i";
3152     case kHeapObject: return "h";
3153     case kExternal: return "x";
3154     default:
3155       UNREACHABLE();
3156       return NULL;
3157   }
3158 }
3159 
InstancesNeedRewriting(Map * target)3160 bool Map::InstancesNeedRewriting(Map* target) {
3161   int target_number_of_fields = target->NumberOfFields();
3162   int target_inobject = target->GetInObjectProperties();
3163   int target_unused = target->unused_property_fields();
3164   int old_number_of_fields;
3165 
3166   return InstancesNeedRewriting(target, target_number_of_fields,
3167                                 target_inobject, target_unused,
3168                                 &old_number_of_fields);
3169 }
3170 
InstancesNeedRewriting(Map * target,int target_number_of_fields,int target_inobject,int target_unused,int * old_number_of_fields)3171 bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields,
3172                                  int target_inobject, int target_unused,
3173                                  int* old_number_of_fields) {
3174   // If fields were added (or removed), rewrite the instance.
3175   *old_number_of_fields = NumberOfFields();
3176   DCHECK(target_number_of_fields >= *old_number_of_fields);
3177   if (target_number_of_fields != *old_number_of_fields) return true;
3178 
3179   // If smi descriptors were replaced by double descriptors, rewrite.
3180   DescriptorArray* old_desc = instance_descriptors();
3181   DescriptorArray* new_desc = target->instance_descriptors();
3182   int limit = NumberOfOwnDescriptors();
3183   for (int i = 0; i < limit; i++) {
3184     if (new_desc->GetDetails(i).representation().IsDouble() !=
3185         old_desc->GetDetails(i).representation().IsDouble()) {
3186       return true;
3187     }
3188   }
3189 
3190   // If no fields were added, and no inobject properties were removed, setting
3191   // the map is sufficient.
3192   if (target_inobject == GetInObjectProperties()) return false;
3193   // In-object slack tracking may have reduced the object size of the new map.
3194   // In that case, succeed if all existing fields were inobject, and they still
3195   // fit within the new inobject size.
3196   DCHECK(target_inobject < GetInObjectProperties());
3197   if (target_number_of_fields <= target_inobject) {
3198     DCHECK(target_number_of_fields + target_unused == target_inobject);
3199     return false;
3200   }
3201   // Otherwise, properties will need to be moved to the backing store.
3202   return true;
3203 }
3204 
3205 
3206 // static
UpdatePrototypeUserRegistration(Handle<Map> old_map,Handle<Map> new_map,Isolate * isolate)3207 void JSObject::UpdatePrototypeUserRegistration(Handle<Map> old_map,
3208                                                Handle<Map> new_map,
3209                                                Isolate* isolate) {
3210   DCHECK(old_map->is_prototype_map());
3211   DCHECK(new_map->is_prototype_map());
3212   bool was_registered = JSObject::UnregisterPrototypeUser(old_map, isolate);
3213   new_map->set_prototype_info(old_map->prototype_info());
3214   old_map->set_prototype_info(Smi::kZero);
3215   if (FLAG_trace_prototype_users) {
3216     PrintF("Moving prototype_info %p from map %p to map %p.\n",
3217            reinterpret_cast<void*>(new_map->prototype_info()),
3218            reinterpret_cast<void*>(*old_map),
3219            reinterpret_cast<void*>(*new_map));
3220   }
3221   if (was_registered) {
3222     if (new_map->prototype_info()->IsPrototypeInfo()) {
3223       // The new map isn't registered with its prototype yet; reflect this fact
3224       // in the PrototypeInfo it just inherited from the old map.
3225       PrototypeInfo::cast(new_map->prototype_info())
3226           ->set_registry_slot(PrototypeInfo::UNREGISTERED);
3227     }
3228     JSObject::LazyRegisterPrototypeUser(new_map, isolate);
3229   }
3230 }
3231 
3232 namespace {
3233 // To migrate a fast instance to a fast map:
3234 // - First check whether the instance needs to be rewritten. If not, simply
3235 //   change the map.
3236 // - Otherwise, allocate a fixed array large enough to hold all fields, in
3237 //   addition to unused space.
3238 // - Copy all existing properties in, in the following order: backing store
3239 //   properties, unused fields, inobject properties.
3240 // - If all allocation succeeded, commit the state atomically:
3241 //   * Copy inobject properties from the backing store back into the object.
3242 //   * Trim the difference in instance size of the object. This also cleanly
3243 //     frees inobject properties that moved to the backing store.
3244 //   * If there are properties left in the backing store, trim of the space used
3245 //     to temporarily store the inobject properties.
3246 //   * If there are properties left in the backing store, install the backing
3247 //     store.
MigrateFastToFast(Handle<JSObject> object,Handle<Map> new_map)3248 void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
3249   Isolate* isolate = object->GetIsolate();
3250   Handle<Map> old_map(object->map());
3251   // In case of a regular transition.
3252   if (new_map->GetBackPointer() == *old_map) {
3253     // If the map does not add named properties, simply set the map.
3254     if (old_map->NumberOfOwnDescriptors() ==
3255         new_map->NumberOfOwnDescriptors()) {
3256       object->synchronized_set_map(*new_map);
3257       return;
3258     }
3259 
3260     PropertyDetails details = new_map->GetLastDescriptorDetails();
3261     // Either new_map adds an kDescriptor property, or a kField property for
3262     // which there is still space, and which does not require a mutable double
3263     // box (an out-of-object double).
3264     if (details.location() == kDescriptor ||
3265         (old_map->unused_property_fields() > 0 &&
3266          ((FLAG_unbox_double_fields && object->properties()->length() == 0) ||
3267           !details.representation().IsDouble()))) {
3268       object->synchronized_set_map(*new_map);
3269       return;
3270     }
3271 
3272     // If there is still space in the object, we need to allocate a mutable
3273     // double box.
3274     if (old_map->unused_property_fields() > 0) {
3275       FieldIndex index =
3276           FieldIndex::ForDescriptor(*new_map, new_map->LastAdded());
3277       DCHECK(details.representation().IsDouble());
3278       DCHECK(!new_map->IsUnboxedDoubleField(index));
3279       Handle<Object> value = isolate->factory()->NewHeapNumber(0, MUTABLE);
3280       object->RawFastPropertyAtPut(index, *value);
3281       object->synchronized_set_map(*new_map);
3282       return;
3283     }
3284 
3285     // This migration is a transition from a map that has run out of property
3286     // space. Extend the backing store.
3287     int grow_by = new_map->unused_property_fields() + 1;
3288     Handle<FixedArray> old_storage = handle(object->properties(), isolate);
3289     Handle<FixedArray> new_storage =
3290         isolate->factory()->CopyFixedArrayAndGrow(old_storage, grow_by);
3291 
3292     // Properly initialize newly added property.
3293     Handle<Object> value;
3294     if (details.representation().IsDouble()) {
3295       value = isolate->factory()->NewHeapNumber(0, MUTABLE);
3296     } else {
3297       value = isolate->factory()->uninitialized_value();
3298     }
3299     DCHECK_EQ(DATA, details.type());
3300     int target_index = details.field_index() - new_map->GetInObjectProperties();
3301     DCHECK(target_index >= 0);  // Must be a backing store index.
3302     new_storage->set(target_index, *value);
3303 
3304     // From here on we cannot fail and we shouldn't GC anymore.
3305     DisallowHeapAllocation no_allocation;
3306 
3307     // Set the new property value and do the map transition.
3308     object->set_properties(*new_storage);
3309     object->synchronized_set_map(*new_map);
3310     return;
3311   }
3312 
3313   int old_number_of_fields;
3314   int number_of_fields = new_map->NumberOfFields();
3315   int inobject = new_map->GetInObjectProperties();
3316   int unused = new_map->unused_property_fields();
3317 
3318   // Nothing to do if no functions were converted to fields and no smis were
3319   // converted to doubles.
3320   if (!old_map->InstancesNeedRewriting(*new_map, number_of_fields, inobject,
3321                                        unused, &old_number_of_fields)) {
3322     object->synchronized_set_map(*new_map);
3323     return;
3324   }
3325 
3326   int total_size = number_of_fields + unused;
3327   int external = total_size - inobject;
3328 
3329   Handle<FixedArray> array = isolate->factory()->NewFixedArray(total_size);
3330 
3331   Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors());
3332   Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors());
3333   int old_nof = old_map->NumberOfOwnDescriptors();
3334   int new_nof = new_map->NumberOfOwnDescriptors();
3335 
3336   // This method only supports generalizing instances to at least the same
3337   // number of properties.
3338   DCHECK(old_nof <= new_nof);
3339 
3340   for (int i = 0; i < old_nof; i++) {
3341     PropertyDetails details = new_descriptors->GetDetails(i);
3342     if (details.type() != DATA) continue;
3343     PropertyDetails old_details = old_descriptors->GetDetails(i);
3344     Representation old_representation = old_details.representation();
3345     Representation representation = details.representation();
3346     Handle<Object> value;
3347     if (old_details.type() == ACCESSOR_CONSTANT) {
3348       // In case of kAccessor -> kData property reconfiguration, the property
3349       // must already be prepared for data or certain type.
3350       DCHECK(!details.representation().IsNone());
3351       if (details.representation().IsDouble()) {
3352         value = isolate->factory()->NewHeapNumber(0, MUTABLE);
3353       } else {
3354         value = isolate->factory()->uninitialized_value();
3355       }
3356     } else if (old_details.type() == DATA_CONSTANT) {
3357       value = handle(old_descriptors->GetValue(i), isolate);
3358       DCHECK(!old_representation.IsDouble() && !representation.IsDouble());
3359     } else {
3360       FieldIndex index = FieldIndex::ForDescriptor(*old_map, i);
3361       if (object->IsUnboxedDoubleField(index)) {
3362         double old = object->RawFastDoublePropertyAt(index);
3363         value = isolate->factory()->NewHeapNumber(
3364             old, representation.IsDouble() ? MUTABLE : IMMUTABLE);
3365 
3366       } else {
3367         value = handle(object->RawFastPropertyAt(index), isolate);
3368         if (!old_representation.IsDouble() && representation.IsDouble()) {
3369           if (old_representation.IsNone()) {
3370             value = handle(Smi::kZero, isolate);
3371           }
3372           value = Object::NewStorageFor(isolate, value, representation);
3373         } else if (old_representation.IsDouble() &&
3374                    !representation.IsDouble()) {
3375           value = Object::WrapForRead(isolate, value, old_representation);
3376         }
3377       }
3378     }
3379     DCHECK(!(representation.IsDouble() && value->IsSmi()));
3380     int target_index = new_descriptors->GetFieldIndex(i) - inobject;
3381     if (target_index < 0) target_index += total_size;
3382     array->set(target_index, *value);
3383   }
3384 
3385   for (int i = old_nof; i < new_nof; i++) {
3386     PropertyDetails details = new_descriptors->GetDetails(i);
3387     if (details.type() != DATA) continue;
3388     Handle<Object> value;
3389     if (details.representation().IsDouble()) {
3390       value = isolate->factory()->NewHeapNumber(0, MUTABLE);
3391     } else {
3392       value = isolate->factory()->uninitialized_value();
3393     }
3394     int target_index = new_descriptors->GetFieldIndex(i) - inobject;
3395     if (target_index < 0) target_index += total_size;
3396     array->set(target_index, *value);
3397   }
3398 
3399   // From here on we cannot fail and we shouldn't GC anymore.
3400   DisallowHeapAllocation no_allocation;
3401 
3402   Heap* heap = isolate->heap();
3403 
3404   // Copy (real) inobject properties. If necessary, stop at number_of_fields to
3405   // avoid overwriting |one_pointer_filler_map|.
3406   int limit = Min(inobject, number_of_fields);
3407   for (int i = 0; i < limit; i++) {
3408     FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
3409     Object* value = array->get(external + i);
3410     // Can't use JSObject::FastPropertyAtPut() because proper map was not set
3411     // yet.
3412     if (new_map->IsUnboxedDoubleField(index)) {
3413       DCHECK(value->IsMutableHeapNumber());
3414       object->RawFastDoublePropertyAtPut(index,
3415                                          HeapNumber::cast(value)->value());
3416       if (i < old_number_of_fields && !old_map->IsUnboxedDoubleField(index)) {
3417         // Transition from tagged to untagged slot.
3418         heap->ClearRecordedSlot(*object,
3419                                 HeapObject::RawField(*object, index.offset()));
3420       }
3421     } else {
3422       object->RawFastPropertyAtPut(index, value);
3423     }
3424   }
3425 
3426 
3427   // If there are properties in the new backing store, trim it to the correct
3428   // size and install the backing store into the object.
3429   if (external > 0) {
3430     heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(*array, inobject);
3431     object->set_properties(*array);
3432   }
3433 
3434   // Create filler object past the new instance size.
3435   int new_instance_size = new_map->instance_size();
3436   int instance_size_delta = old_map->instance_size() - new_instance_size;
3437   DCHECK(instance_size_delta >= 0);
3438 
3439   if (instance_size_delta > 0) {
3440     Address address = object->address();
3441     heap->CreateFillerObjectAt(address + new_instance_size, instance_size_delta,
3442                                ClearRecordedSlots::kYes);
3443     heap->AdjustLiveBytes(*object, -instance_size_delta,
3444                           Heap::CONCURRENT_TO_SWEEPER);
3445   }
3446 
3447   // We are storing the new map using release store after creating a filler for
3448   // the left-over space to avoid races with the sweeper thread.
3449   object->synchronized_set_map(*new_map);
3450 }
3451 
MigrateFastToSlow(Handle<JSObject> object,Handle<Map> new_map,int expected_additional_properties)3452 void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map,
3453                        int expected_additional_properties) {
3454   // The global object is always normalized.
3455   DCHECK(!object->IsJSGlobalObject());
3456   // JSGlobalProxy must never be normalized
3457   DCHECK(!object->IsJSGlobalProxy());
3458 
3459   Isolate* isolate = object->GetIsolate();
3460   HandleScope scope(isolate);
3461   Handle<Map> map(object->map());
3462 
3463   // Allocate new content.
3464   int real_size = map->NumberOfOwnDescriptors();
3465   int property_count = real_size;
3466   if (expected_additional_properties > 0) {
3467     property_count += expected_additional_properties;
3468   } else {
3469     // Make space for two more properties.
3470     property_count += NameDictionary::kInitialCapacity;
3471   }
3472   Handle<NameDictionary> dictionary =
3473       NameDictionary::New(isolate, property_count);
3474 
3475   Handle<DescriptorArray> descs(map->instance_descriptors());
3476   for (int i = 0; i < real_size; i++) {
3477     PropertyDetails details = descs->GetDetails(i);
3478     Handle<Name> key(descs->GetKey(i));
3479     switch (details.type()) {
3480       case DATA_CONSTANT: {
3481         Handle<Object> value(descs->GetConstant(i), isolate);
3482         PropertyDetails d(details.attributes(), DATA, i + 1,
3483                           PropertyCellType::kNoCell);
3484         dictionary = NameDictionary::Add(dictionary, key, value, d);
3485         break;
3486       }
3487       case DATA: {
3488         FieldIndex index = FieldIndex::ForDescriptor(*map, i);
3489         Handle<Object> value;
3490         if (object->IsUnboxedDoubleField(index)) {
3491           double old_value = object->RawFastDoublePropertyAt(index);
3492           value = isolate->factory()->NewHeapNumber(old_value);
3493         } else {
3494           value = handle(object->RawFastPropertyAt(index), isolate);
3495           if (details.representation().IsDouble()) {
3496             DCHECK(value->IsMutableHeapNumber());
3497             Handle<HeapNumber> old = Handle<HeapNumber>::cast(value);
3498             value = isolate->factory()->NewHeapNumber(old->value());
3499           }
3500         }
3501         PropertyDetails d(details.attributes(), DATA, i + 1,
3502                           PropertyCellType::kNoCell);
3503         dictionary = NameDictionary::Add(dictionary, key, value, d);
3504         break;
3505       }
3506       case ACCESSOR: {
3507         FieldIndex index = FieldIndex::ForDescriptor(*map, i);
3508         Handle<Object> value(object->RawFastPropertyAt(index), isolate);
3509         PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1,
3510                           PropertyCellType::kNoCell);
3511         dictionary = NameDictionary::Add(dictionary, key, value, d);
3512         break;
3513       }
3514       case ACCESSOR_CONSTANT: {
3515         Handle<Object> value(descs->GetCallbacksObject(i), isolate);
3516         PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1,
3517                           PropertyCellType::kNoCell);
3518         dictionary = NameDictionary::Add(dictionary, key, value, d);
3519         break;
3520       }
3521     }
3522   }
3523 
3524   // Copy the next enumeration index from instance descriptor.
3525   dictionary->SetNextEnumerationIndex(real_size + 1);
3526 
3527   // From here on we cannot fail and we shouldn't GC anymore.
3528   DisallowHeapAllocation no_allocation;
3529 
3530   // Resize the object in the heap if necessary.
3531   int new_instance_size = new_map->instance_size();
3532   int instance_size_delta = map->instance_size() - new_instance_size;
3533   DCHECK(instance_size_delta >= 0);
3534 
3535   if (instance_size_delta > 0) {
3536     Heap* heap = isolate->heap();
3537     heap->CreateFillerObjectAt(object->address() + new_instance_size,
3538                                instance_size_delta, ClearRecordedSlots::kYes);
3539     heap->AdjustLiveBytes(*object, -instance_size_delta,
3540                           Heap::CONCURRENT_TO_SWEEPER);
3541   }
3542 
3543   // We are storing the new map using release store after creating a filler for
3544   // the left-over space to avoid races with the sweeper thread.
3545   object->synchronized_set_map(*new_map);
3546 
3547   object->set_properties(*dictionary);
3548 
3549   // Ensure that in-object space of slow-mode object does not contain random
3550   // garbage.
3551   int inobject_properties = new_map->GetInObjectProperties();
3552   if (inobject_properties) {
3553     Heap* heap = isolate->heap();
3554     heap->ClearRecordedSlotRange(
3555         object->address() + map->GetInObjectPropertyOffset(0),
3556         object->address() + new_instance_size);
3557 
3558     for (int i = 0; i < inobject_properties; i++) {
3559       FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
3560       object->RawFastPropertyAtPut(index, Smi::kZero);
3561     }
3562   }
3563 
3564   isolate->counters()->props_to_dictionary()->Increment();
3565 
3566 #ifdef DEBUG
3567   if (FLAG_trace_normalization) {
3568     OFStream os(stdout);
3569     os << "Object properties have been normalized:\n";
3570     object->Print(os);
3571   }
3572 #endif
3573 }
3574 
3575 }  // namespace
3576 
3577 // static
NotifyMapChange(Handle<Map> old_map,Handle<Map> new_map,Isolate * isolate)3578 void JSObject::NotifyMapChange(Handle<Map> old_map, Handle<Map> new_map,
3579                                Isolate* isolate) {
3580   if (!old_map->is_prototype_map()) return;
3581 
3582   InvalidatePrototypeChains(*old_map);
3583 
3584   // If the map was registered with its prototype before, ensure that it
3585   // registers with its new prototype now. This preserves the invariant that
3586   // when a map on a prototype chain is registered with its prototype, then
3587   // all prototypes further up the chain are also registered with their
3588   // respective prototypes.
3589   UpdatePrototypeUserRegistration(old_map, new_map, isolate);
3590 }
3591 
MigrateToMap(Handle<JSObject> object,Handle<Map> new_map,int expected_additional_properties)3592 void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
3593                             int expected_additional_properties) {
3594   if (object->map() == *new_map) return;
3595   Handle<Map> old_map(object->map());
3596   NotifyMapChange(old_map, new_map, new_map->GetIsolate());
3597 
3598   if (old_map->is_dictionary_map()) {
3599     // For slow-to-fast migrations JSObject::MigrateSlowToFast()
3600     // must be used instead.
3601     CHECK(new_map->is_dictionary_map());
3602 
3603     // Slow-to-slow migration is trivial.
3604     object->set_map(*new_map);
3605   } else if (!new_map->is_dictionary_map()) {
3606     MigrateFastToFast(object, new_map);
3607     if (old_map->is_prototype_map()) {
3608       DCHECK(!old_map->is_stable());
3609       DCHECK(new_map->is_stable());
3610       // Clear out the old descriptor array to avoid problems to sharing
3611       // the descriptor array without using an explicit.
3612       old_map->InitializeDescriptors(
3613           old_map->GetHeap()->empty_descriptor_array(),
3614           LayoutDescriptor::FastPointerLayout());
3615       // Ensure that no transition was inserted for prototype migrations.
3616       DCHECK_EQ(
3617           0, TransitionArray::NumberOfTransitions(old_map->raw_transitions()));
3618       DCHECK(new_map->GetBackPointer()->IsUndefined(new_map->GetIsolate()));
3619     }
3620   } else {
3621     MigrateFastToSlow(object, new_map, expected_additional_properties);
3622   }
3623 
3624   // Careful: Don't allocate here!
3625   // For some callers of this method, |object| might be in an inconsistent
3626   // state now: the new map might have a new elements_kind, but the object's
3627   // elements pointer hasn't been updated yet. Callers will fix this, but in
3628   // the meantime, (indirectly) calling JSObjectVerify() must be avoided.
3629   // When adding code here, add a DisallowHeapAllocation too.
3630 }
3631 
ForceSetPrototype(Handle<JSObject> object,Handle<Object> proto)3632 void JSObject::ForceSetPrototype(Handle<JSObject> object,
3633                                  Handle<Object> proto) {
3634   // object.__proto__ = proto;
3635   Handle<Map> old_map = Handle<Map>(object->map());
3636   Handle<Map> new_map = Map::Copy(old_map, "ForceSetPrototype");
3637   Map::SetPrototype(new_map, proto, FAST_PROTOTYPE);
3638   JSObject::MigrateToMap(object, new_map);
3639 }
3640 
NumberOfFields()3641 int Map::NumberOfFields() {
3642   DescriptorArray* descriptors = instance_descriptors();
3643   int result = 0;
3644   for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
3645     if (descriptors->GetDetails(i).location() == kField) result++;
3646   }
3647   return result;
3648 }
3649 
CopyGeneralizeAllRepresentations(Handle<Map> map,ElementsKind elements_kind,int modify_index,StoreMode store_mode,PropertyKind kind,PropertyAttributes attributes,const char * reason)3650 Handle<Map> Map::CopyGeneralizeAllRepresentations(
3651     Handle<Map> map, ElementsKind elements_kind, int modify_index,
3652     StoreMode store_mode, PropertyKind kind, PropertyAttributes attributes,
3653     const char* reason) {
3654   Isolate* isolate = map->GetIsolate();
3655   Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
3656   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
3657   Handle<DescriptorArray> descriptors =
3658       DescriptorArray::CopyUpTo(old_descriptors, number_of_own_descriptors);
3659 
3660   for (int i = 0; i < number_of_own_descriptors; i++) {
3661     descriptors->SetRepresentation(i, Representation::Tagged());
3662     if (descriptors->GetDetails(i).type() == DATA) {
3663       descriptors->SetValue(i, FieldType::Any());
3664     }
3665   }
3666 
3667   Handle<LayoutDescriptor> new_layout_descriptor(
3668       LayoutDescriptor::FastPointerLayout(), isolate);
3669   Handle<Map> new_map = CopyReplaceDescriptors(
3670       map, descriptors, new_layout_descriptor, OMIT_TRANSITION,
3671       MaybeHandle<Name>(), reason, SPECIAL_TRANSITION);
3672 
3673   // Unless the instance is being migrated, ensure that modify_index is a field.
3674   if (modify_index >= 0) {
3675     PropertyDetails details = descriptors->GetDetails(modify_index);
3676     if (store_mode == FORCE_FIELD &&
3677         (details.type() != DATA || details.attributes() != attributes)) {
3678       int field_index = details.type() == DATA ? details.field_index()
3679                                                : new_map->NumberOfFields();
3680       DataDescriptor d(handle(descriptors->GetKey(modify_index), isolate),
3681                        field_index, attributes, Representation::Tagged());
3682       descriptors->Replace(modify_index, &d);
3683       if (details.type() != DATA) {
3684         int unused_property_fields = new_map->unused_property_fields() - 1;
3685         if (unused_property_fields < 0) {
3686           unused_property_fields += JSObject::kFieldsAdded;
3687         }
3688         new_map->set_unused_property_fields(unused_property_fields);
3689       }
3690     } else {
3691       DCHECK(details.attributes() == attributes);
3692     }
3693 
3694     if (FLAG_trace_generalization) {
3695       MaybeHandle<FieldType> field_type = FieldType::None(isolate);
3696       if (details.type() == DATA) {
3697         field_type = handle(
3698             map->instance_descriptors()->GetFieldType(modify_index), isolate);
3699       }
3700       map->PrintGeneralization(
3701           stdout, reason, modify_index, new_map->NumberOfOwnDescriptors(),
3702           new_map->NumberOfOwnDescriptors(),
3703           details.type() == DATA_CONSTANT && store_mode == FORCE_FIELD,
3704           details.representation(), Representation::Tagged(), field_type,
3705           MaybeHandle<Object>(), FieldType::Any(isolate),
3706           MaybeHandle<Object>());
3707     }
3708   }
3709   new_map->set_elements_kind(elements_kind);
3710   return new_map;
3711 }
3712 
3713 
DeprecateTransitionTree()3714 void Map::DeprecateTransitionTree() {
3715   if (is_deprecated()) return;
3716   Object* transitions = raw_transitions();
3717   int num_transitions = TransitionArray::NumberOfTransitions(transitions);
3718   for (int i = 0; i < num_transitions; ++i) {
3719     TransitionArray::GetTarget(transitions, i)->DeprecateTransitionTree();
3720   }
3721   deprecate();
3722   dependent_code()->DeoptimizeDependentCodeGroup(
3723       GetIsolate(), DependentCode::kTransitionGroup);
3724   NotifyLeafMapLayoutChange();
3725 }
3726 
3727 
EqualImmutableValues(Object * obj1,Object * obj2)3728 static inline bool EqualImmutableValues(Object* obj1, Object* obj2) {
3729   if (obj1 == obj2) return true;  // Valid for both kData and kAccessor kinds.
3730   // TODO(ishell): compare AccessorPairs.
3731   return false;
3732 }
3733 
3734 
3735 // Installs |new_descriptors| over the current instance_descriptors to ensure
3736 // proper sharing of descriptor arrays.
ReplaceDescriptors(DescriptorArray * new_descriptors,LayoutDescriptor * new_layout_descriptor)3737 void Map::ReplaceDescriptors(DescriptorArray* new_descriptors,
3738                              LayoutDescriptor* new_layout_descriptor) {
3739   Isolate* isolate = GetIsolate();
3740   // Don't overwrite the empty descriptor array or initial map's descriptors.
3741   if (NumberOfOwnDescriptors() == 0 || GetBackPointer()->IsUndefined(isolate)) {
3742     return;
3743   }
3744 
3745   DescriptorArray* to_replace = instance_descriptors();
3746   isolate->heap()->incremental_marking()->IterateBlackObject(to_replace);
3747   Map* current = this;
3748   while (current->instance_descriptors() == to_replace) {
3749     Object* next = current->GetBackPointer();
3750     if (next->IsUndefined(isolate)) break;  // Stop overwriting at initial map.
3751     current->SetEnumLength(kInvalidEnumCacheSentinel);
3752     current->UpdateDescriptors(new_descriptors, new_layout_descriptor);
3753     current = Map::cast(next);
3754   }
3755   set_owns_descriptors(false);
3756 }
3757 
3758 
FindRootMap()3759 Map* Map::FindRootMap() {
3760   Map* result = this;
3761   Isolate* isolate = GetIsolate();
3762   while (true) {
3763     Object* back = result->GetBackPointer();
3764     if (back->IsUndefined(isolate)) {
3765       // Initial map always owns descriptors and doesn't have unused entries
3766       // in the descriptor array.
3767       DCHECK(result->owns_descriptors());
3768       DCHECK_EQ(result->NumberOfOwnDescriptors(),
3769                 result->instance_descriptors()->number_of_descriptors());
3770       return result;
3771     }
3772     result = Map::cast(back);
3773   }
3774 }
3775 
3776 
FindLastMatchMap(int verbatim,int length,DescriptorArray * descriptors)3777 Map* Map::FindLastMatchMap(int verbatim,
3778                            int length,
3779                            DescriptorArray* descriptors) {
3780   DisallowHeapAllocation no_allocation;
3781 
3782   // This can only be called on roots of transition trees.
3783   DCHECK_EQ(verbatim, NumberOfOwnDescriptors());
3784 
3785   Map* current = this;
3786 
3787   for (int i = verbatim; i < length; i++) {
3788     Name* name = descriptors->GetKey(i);
3789     PropertyDetails details = descriptors->GetDetails(i);
3790     Map* next = TransitionArray::SearchTransition(current, details.kind(), name,
3791                                                   details.attributes());
3792     if (next == NULL) break;
3793     DescriptorArray* next_descriptors = next->instance_descriptors();
3794 
3795     PropertyDetails next_details = next_descriptors->GetDetails(i);
3796     DCHECK_EQ(details.kind(), next_details.kind());
3797     DCHECK_EQ(details.attributes(), next_details.attributes());
3798     if (details.location() != next_details.location()) break;
3799     if (!details.representation().Equals(next_details.representation())) break;
3800 
3801     if (next_details.location() == kField) {
3802       FieldType* next_field_type = next_descriptors->GetFieldType(i);
3803       if (!descriptors->GetFieldType(i)->NowIs(next_field_type)) {
3804         break;
3805       }
3806     } else {
3807       if (!EqualImmutableValues(descriptors->GetValue(i),
3808                                 next_descriptors->GetValue(i))) {
3809         break;
3810       }
3811     }
3812     current = next;
3813   }
3814   return current;
3815 }
3816 
3817 
FindFieldOwner(int descriptor)3818 Map* Map::FindFieldOwner(int descriptor) {
3819   DisallowHeapAllocation no_allocation;
3820   DCHECK_EQ(DATA, instance_descriptors()->GetDetails(descriptor).type());
3821   Map* result = this;
3822   Isolate* isolate = GetIsolate();
3823   while (true) {
3824     Object* back = result->GetBackPointer();
3825     if (back->IsUndefined(isolate)) break;
3826     Map* parent = Map::cast(back);
3827     if (parent->NumberOfOwnDescriptors() <= descriptor) break;
3828     result = parent;
3829   }
3830   return result;
3831 }
3832 
3833 
UpdateFieldType(int descriptor,Handle<Name> name,Representation new_representation,Handle<Object> new_wrapped_type)3834 void Map::UpdateFieldType(int descriptor, Handle<Name> name,
3835                           Representation new_representation,
3836                           Handle<Object> new_wrapped_type) {
3837   DCHECK(new_wrapped_type->IsSmi() || new_wrapped_type->IsWeakCell());
3838   // We store raw pointers in the queue, so no allocations are allowed.
3839   DisallowHeapAllocation no_allocation;
3840   PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
3841   if (details.type() != DATA) return;
3842 
3843   Zone zone(GetIsolate()->allocator(), ZONE_NAME);
3844   ZoneQueue<Map*> backlog(&zone);
3845   backlog.push(this);
3846 
3847   while (!backlog.empty()) {
3848     Map* current = backlog.front();
3849     backlog.pop();
3850 
3851     Object* transitions = current->raw_transitions();
3852     int num_transitions = TransitionArray::NumberOfTransitions(transitions);
3853     for (int i = 0; i < num_transitions; ++i) {
3854       Map* target = TransitionArray::GetTarget(transitions, i);
3855       backlog.push(target);
3856     }
3857     DescriptorArray* descriptors = current->instance_descriptors();
3858     PropertyDetails details = descriptors->GetDetails(descriptor);
3859 
3860     // It is allowed to change representation here only from None to something.
3861     DCHECK(details.representation().Equals(new_representation) ||
3862            details.representation().IsNone());
3863 
3864     // Skip if already updated the shared descriptor.
3865     if (descriptors->GetValue(descriptor) != *new_wrapped_type) {
3866       DataDescriptor d(name, descriptors->GetFieldIndex(descriptor),
3867                        new_wrapped_type, details.attributes(),
3868                        new_representation);
3869       descriptors->Replace(descriptor, &d);
3870     }
3871   }
3872 }
3873 
FieldTypeIsCleared(Representation rep,FieldType * type)3874 bool FieldTypeIsCleared(Representation rep, FieldType* type) {
3875   return type->IsNone() && rep.IsHeapObject();
3876 }
3877 
3878 
3879 // static
GeneralizeFieldType(Representation rep1,Handle<FieldType> type1,Representation rep2,Handle<FieldType> type2,Isolate * isolate)3880 Handle<FieldType> Map::GeneralizeFieldType(Representation rep1,
3881                                            Handle<FieldType> type1,
3882                                            Representation rep2,
3883                                            Handle<FieldType> type2,
3884                                            Isolate* isolate) {
3885   // Cleared field types need special treatment. They represent lost knowledge,
3886   // so we must be conservative, so their generalization with any other type
3887   // is "Any".
3888   if (FieldTypeIsCleared(rep1, *type1) || FieldTypeIsCleared(rep2, *type2)) {
3889     return FieldType::Any(isolate);
3890   }
3891   if (type1->NowIs(type2)) return type2;
3892   if (type2->NowIs(type1)) return type1;
3893   return FieldType::Any(isolate);
3894 }
3895 
3896 
3897 // static
GeneralizeFieldType(Handle<Map> map,int modify_index,Representation new_representation,Handle<FieldType> new_field_type)3898 void Map::GeneralizeFieldType(Handle<Map> map, int modify_index,
3899                               Representation new_representation,
3900                               Handle<FieldType> new_field_type) {
3901   Isolate* isolate = map->GetIsolate();
3902 
3903   // Check if we actually need to generalize the field type at all.
3904   Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
3905   Representation old_representation =
3906       old_descriptors->GetDetails(modify_index).representation();
3907   Handle<FieldType> old_field_type(old_descriptors->GetFieldType(modify_index),
3908                                    isolate);
3909 
3910   if (old_representation.Equals(new_representation) &&
3911       !FieldTypeIsCleared(new_representation, *new_field_type) &&
3912       // Checking old_field_type for being cleared is not necessary because
3913       // the NowIs check below would fail anyway in that case.
3914       new_field_type->NowIs(old_field_type)) {
3915     DCHECK(Map::GeneralizeFieldType(old_representation, old_field_type,
3916                                     new_representation, new_field_type, isolate)
3917                ->NowIs(old_field_type));
3918     return;
3919   }
3920 
3921   // Determine the field owner.
3922   Handle<Map> field_owner(map->FindFieldOwner(modify_index), isolate);
3923   Handle<DescriptorArray> descriptors(
3924       field_owner->instance_descriptors(), isolate);
3925   DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index));
3926 
3927   new_field_type =
3928       Map::GeneralizeFieldType(old_representation, old_field_type,
3929                                new_representation, new_field_type, isolate);
3930 
3931   PropertyDetails details = descriptors->GetDetails(modify_index);
3932   Handle<Name> name(descriptors->GetKey(modify_index));
3933 
3934   Handle<Object> wrapped_type(WrapType(new_field_type));
3935   field_owner->UpdateFieldType(modify_index, name, new_representation,
3936                                wrapped_type);
3937   field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
3938       isolate, DependentCode::kFieldOwnerGroup);
3939 
3940   if (FLAG_trace_generalization) {
3941     map->PrintGeneralization(
3942         stdout, "field type generalization", modify_index,
3943         map->NumberOfOwnDescriptors(), map->NumberOfOwnDescriptors(), false,
3944         details.representation(), details.representation(), old_field_type,
3945         MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>());
3946   }
3947 }
3948 
GetFieldType(Isolate * isolate,Handle<DescriptorArray> descriptors,int descriptor,PropertyLocation location,Representation representation)3949 static inline Handle<FieldType> GetFieldType(
3950     Isolate* isolate, Handle<DescriptorArray> descriptors, int descriptor,
3951     PropertyLocation location, Representation representation) {
3952 #ifdef DEBUG
3953   PropertyDetails details = descriptors->GetDetails(descriptor);
3954   DCHECK_EQ(kData, details.kind());
3955   DCHECK_EQ(details.location(), location);
3956 #endif
3957   if (location == kField) {
3958     return handle(descriptors->GetFieldType(descriptor), isolate);
3959   } else {
3960     return descriptors->GetValue(descriptor)
3961         ->OptimalType(isolate, representation);
3962   }
3963 }
3964 
3965 // Reconfigures elements kind to |new_elements_kind| and/or property at
3966 // |modify_index| with |new_kind|, |new_attributes|, |store_mode| and/or
3967 // |new_representation|/|new_field_type|.
3968 // If |modify_index| is negative then no properties are reconfigured but the
3969 // map is migrated to the up-to-date non-deprecated state.
3970 //
3971 // This method rewrites or completes the transition tree to reflect the new
3972 // change. To avoid high degrees over polymorphism, and to stabilize quickly,
3973 // on every rewrite the new type is deduced by merging the current type with
3974 // any potential new (partial) version of the type in the transition tree.
3975 // To do this, on each rewrite:
3976 // - Search the root of the transition tree using FindRootMap.
3977 // - Find/create a |root_map| with requested |new_elements_kind|.
3978 // - Find |target_map|, the newest matching version of this map using the
3979 //   virtually "enhanced" |old_map|'s descriptor array (i.e. whose entry at
3980 //   |modify_index| is considered to be of |new_kind| and having
3981 //   |new_attributes|) to walk the transition tree.
3982 // - Merge/generalize the "enhanced" descriptor array of the |old_map| and
3983 //   descriptor array of the |target_map|.
3984 // - Generalize the |modify_index| descriptor using |new_representation| and
3985 //   |new_field_type|.
3986 // - Walk the tree again starting from the root towards |target_map|. Stop at
3987 //   |split_map|, the first map who's descriptor array does not match the merged
3988 //   descriptor array.
3989 // - If |target_map| == |split_map|, |target_map| is in the expected state.
3990 //   Return it.
3991 // - Otherwise, invalidate the outdated transition target from |target_map|, and
3992 //   replace its transition tree with a new branch for the updated descriptors.
Reconfigure(Handle<Map> old_map,ElementsKind new_elements_kind,int modify_index,PropertyKind new_kind,PropertyAttributes new_attributes,Representation new_representation,Handle<FieldType> new_field_type,StoreMode store_mode)3993 Handle<Map> Map::Reconfigure(Handle<Map> old_map,
3994                              ElementsKind new_elements_kind, int modify_index,
3995                              PropertyKind new_kind,
3996                              PropertyAttributes new_attributes,
3997                              Representation new_representation,
3998                              Handle<FieldType> new_field_type,
3999                              StoreMode store_mode) {
4000   DCHECK_NE(kAccessor, new_kind);  // TODO(ishell): not supported yet.
4001   DCHECK(store_mode != FORCE_FIELD || modify_index >= 0);
4002   Isolate* isolate = old_map->GetIsolate();
4003 
4004   Handle<DescriptorArray> old_descriptors(
4005       old_map->instance_descriptors(), isolate);
4006   int old_nof = old_map->NumberOfOwnDescriptors();
4007 
4008   // If it's just a representation generalization case (i.e. property kind and
4009   // attributes stays unchanged) it's fine to transition from None to anything
4010   // but double without any modification to the object, because the default
4011   // uninitialized value for representation None can be overwritten by both
4012   // smi and tagged values. Doubles, however, would require a box allocation.
4013   if (modify_index >= 0 && !new_representation.IsNone() &&
4014       !new_representation.IsDouble() &&
4015       old_map->elements_kind() == new_elements_kind) {
4016     PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
4017     Representation old_representation = old_details.representation();
4018 
4019     if (old_representation.IsNone()) {
4020       DCHECK_EQ(new_kind, old_details.kind());
4021       DCHECK_EQ(new_attributes, old_details.attributes());
4022       DCHECK_EQ(DATA, old_details.type());
4023       if (FLAG_trace_generalization) {
4024         old_map->PrintGeneralization(
4025             stdout, "uninitialized field", modify_index,
4026             old_map->NumberOfOwnDescriptors(),
4027             old_map->NumberOfOwnDescriptors(), false, old_representation,
4028             new_representation,
4029             handle(old_descriptors->GetFieldType(modify_index), isolate),
4030             MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>());
4031       }
4032       Handle<Map> field_owner(old_map->FindFieldOwner(modify_index), isolate);
4033 
4034       GeneralizeFieldType(field_owner, modify_index, new_representation,
4035                           new_field_type);
4036       DCHECK(old_descriptors->GetDetails(modify_index)
4037                  .representation()
4038                  .Equals(new_representation));
4039       DCHECK(
4040           old_descriptors->GetFieldType(modify_index)->NowIs(new_field_type));
4041       return old_map;
4042     }
4043   }
4044 
4045   // Check the state of the root map.
4046   Handle<Map> root_map(old_map->FindRootMap(), isolate);
4047   if (!old_map->EquivalentToForTransition(*root_map)) {
4048     return CopyGeneralizeAllRepresentations(
4049         old_map, new_elements_kind, modify_index, store_mode, new_kind,
4050         new_attributes, "GenAll_NotEquivalent");
4051   }
4052 
4053   ElementsKind from_kind = root_map->elements_kind();
4054   ElementsKind to_kind = new_elements_kind;
4055   // TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS.
4056   if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS &&
4057       to_kind != SLOW_STRING_WRAPPER_ELEMENTS &&
4058       to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS &&
4059       !(IsTransitionableFastElementsKind(from_kind) &&
4060         IsMoreGeneralElementsKindTransition(from_kind, to_kind))) {
4061     return CopyGeneralizeAllRepresentations(
4062         old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
4063         "GenAll_InvalidElementsTransition");
4064   }
4065   int root_nof = root_map->NumberOfOwnDescriptors();
4066   if (modify_index >= 0 && modify_index < root_nof) {
4067     PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
4068     if (old_details.kind() != new_kind ||
4069         old_details.attributes() != new_attributes) {
4070       return CopyGeneralizeAllRepresentations(
4071           old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
4072           "GenAll_RootModification1");
4073     }
4074     if ((old_details.type() != DATA && store_mode == FORCE_FIELD) ||
4075         (old_details.type() == DATA &&
4076          (!new_field_type->NowIs(old_descriptors->GetFieldType(modify_index)) ||
4077           !new_representation.fits_into(old_details.representation())))) {
4078       return CopyGeneralizeAllRepresentations(
4079           old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
4080           "GenAll_RootModification2");
4081     }
4082   }
4083 
4084   // From here on, use the map with correct elements kind as root map.
4085   if (from_kind != to_kind) {
4086     root_map = Map::AsElementsKind(root_map, to_kind);
4087   }
4088 
4089   Handle<Map> target_map = root_map;
4090   for (int i = root_nof; i < old_nof; ++i) {
4091     PropertyDetails old_details = old_descriptors->GetDetails(i);
4092     PropertyKind next_kind;
4093     PropertyLocation next_location;
4094     PropertyAttributes next_attributes;
4095     Representation next_representation;
4096     bool property_kind_reconfiguration = false;
4097 
4098     if (modify_index == i) {
4099       DCHECK_EQ(FORCE_FIELD, store_mode);
4100       property_kind_reconfiguration = old_details.kind() != new_kind;
4101 
4102       next_kind = new_kind;
4103       next_location = kField;
4104       next_attributes = new_attributes;
4105       // If property kind is not reconfigured merge the result with
4106       // representation/field type from the old descriptor.
4107       next_representation = new_representation;
4108       if (!property_kind_reconfiguration) {
4109         next_representation =
4110             next_representation.generalize(old_details.representation());
4111       }
4112 
4113     } else {
4114       next_kind = old_details.kind();
4115       next_location = old_details.location();
4116       next_attributes = old_details.attributes();
4117       next_representation = old_details.representation();
4118     }
4119     Map* transition = TransitionArray::SearchTransition(
4120         *target_map, next_kind, old_descriptors->GetKey(i), next_attributes);
4121     if (transition == NULL) break;
4122     Handle<Map> tmp_map(transition, isolate);
4123 
4124     Handle<DescriptorArray> tmp_descriptors = handle(
4125         tmp_map->instance_descriptors(), isolate);
4126 
4127     // Check if target map is incompatible.
4128     PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
4129     DCHECK_EQ(next_kind, tmp_details.kind());
4130     DCHECK_EQ(next_attributes, tmp_details.attributes());
4131     if (next_kind == kAccessor &&
4132         !EqualImmutableValues(old_descriptors->GetValue(i),
4133                               tmp_descriptors->GetValue(i))) {
4134       return CopyGeneralizeAllRepresentations(
4135           old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
4136           "GenAll_Incompatible");
4137     }
4138     if (next_location == kField && tmp_details.location() == kDescriptor) break;
4139 
4140     Representation tmp_representation = tmp_details.representation();
4141     if (!next_representation.fits_into(tmp_representation)) break;
4142 
4143     PropertyLocation old_location = old_details.location();
4144     PropertyLocation tmp_location = tmp_details.location();
4145     if (tmp_location == kField) {
4146       if (next_kind == kData) {
4147         Handle<FieldType> next_field_type;
4148         if (modify_index == i) {
4149           next_field_type = new_field_type;
4150           if (!property_kind_reconfiguration) {
4151             Handle<FieldType> old_field_type =
4152                 GetFieldType(isolate, old_descriptors, i,
4153                              old_details.location(), tmp_representation);
4154             Representation old_representation = old_details.representation();
4155             next_field_type = GeneralizeFieldType(
4156                 old_representation, old_field_type, new_representation,
4157                 next_field_type, isolate);
4158           }
4159         } else {
4160           Handle<FieldType> old_field_type =
4161               GetFieldType(isolate, old_descriptors, i, old_details.location(),
4162                            tmp_representation);
4163           next_field_type = old_field_type;
4164         }
4165         GeneralizeFieldType(tmp_map, i, tmp_representation, next_field_type);
4166       }
4167     } else if (old_location == kField ||
4168                !EqualImmutableValues(old_descriptors->GetValue(i),
4169                                      tmp_descriptors->GetValue(i))) {
4170       break;
4171     }
4172     DCHECK(!tmp_map->is_deprecated());
4173     target_map = tmp_map;
4174   }
4175 
4176   // Directly change the map if the target map is more general.
4177   Handle<DescriptorArray> target_descriptors(
4178       target_map->instance_descriptors(), isolate);
4179   int target_nof = target_map->NumberOfOwnDescriptors();
4180   if (target_nof == old_nof &&
4181       (store_mode != FORCE_FIELD ||
4182        (modify_index >= 0 &&
4183         target_descriptors->GetDetails(modify_index).location() == kField))) {
4184 #ifdef DEBUG
4185     if (modify_index >= 0) {
4186       PropertyDetails details = target_descriptors->GetDetails(modify_index);
4187       DCHECK_EQ(new_kind, details.kind());
4188       DCHECK_EQ(new_attributes, details.attributes());
4189       DCHECK(new_representation.fits_into(details.representation()));
4190       DCHECK(details.location() != kField ||
4191              new_field_type->NowIs(
4192                  target_descriptors->GetFieldType(modify_index)));
4193     }
4194 #endif
4195     if (*target_map != *old_map) {
4196       old_map->NotifyLeafMapLayoutChange();
4197     }
4198     return target_map;
4199   }
4200 
4201   // Find the last compatible target map in the transition tree.
4202   for (int i = target_nof; i < old_nof; ++i) {
4203     PropertyDetails old_details = old_descriptors->GetDetails(i);
4204     PropertyKind next_kind;
4205     PropertyAttributes next_attributes;
4206     if (modify_index == i) {
4207       next_kind = new_kind;
4208       next_attributes = new_attributes;
4209     } else {
4210       next_kind = old_details.kind();
4211       next_attributes = old_details.attributes();
4212     }
4213     Map* transition = TransitionArray::SearchTransition(
4214         *target_map, next_kind, old_descriptors->GetKey(i), next_attributes);
4215     if (transition == NULL) break;
4216     Handle<Map> tmp_map(transition, isolate);
4217     Handle<DescriptorArray> tmp_descriptors(
4218         tmp_map->instance_descriptors(), isolate);
4219 
4220     // Check if target map is compatible.
4221 #ifdef DEBUG
4222     PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
4223     DCHECK_EQ(next_kind, tmp_details.kind());
4224     DCHECK_EQ(next_attributes, tmp_details.attributes());
4225 #endif
4226     if (next_kind == kAccessor &&
4227         !EqualImmutableValues(old_descriptors->GetValue(i),
4228                               tmp_descriptors->GetValue(i))) {
4229       return CopyGeneralizeAllRepresentations(
4230           old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
4231           "GenAll_Incompatible");
4232     }
4233     DCHECK(!tmp_map->is_deprecated());
4234     target_map = tmp_map;
4235   }
4236   target_nof = target_map->NumberOfOwnDescriptors();
4237   target_descriptors = handle(target_map->instance_descriptors(), isolate);
4238 
4239   // Allocate a new descriptor array large enough to hold the required
4240   // descriptors, with minimally the exact same size as the old descriptor
4241   // array.
4242   int new_slack = Max(
4243       old_nof, old_descriptors->number_of_descriptors()) - old_nof;
4244   Handle<DescriptorArray> new_descriptors = DescriptorArray::Allocate(
4245       isolate, old_nof, new_slack);
4246   DCHECK(new_descriptors->length() > target_descriptors->length() ||
4247          new_descriptors->NumberOfSlackDescriptors() > 0 ||
4248          new_descriptors->number_of_descriptors() ==
4249          old_descriptors->number_of_descriptors());
4250   DCHECK(new_descriptors->number_of_descriptors() == old_nof);
4251 
4252   // 0 -> |root_nof|
4253   int current_offset = 0;
4254   for (int i = 0; i < root_nof; ++i) {
4255     PropertyDetails old_details = old_descriptors->GetDetails(i);
4256     if (old_details.location() == kField) {
4257       current_offset += old_details.field_width_in_words();
4258     }
4259     Descriptor d(handle(old_descriptors->GetKey(i), isolate),
4260                  handle(old_descriptors->GetValue(i), isolate),
4261                  old_details);
4262     new_descriptors->Set(i, &d);
4263   }
4264 
4265   // |root_nof| -> |target_nof|
4266   for (int i = root_nof; i < target_nof; ++i) {
4267     Handle<Name> target_key(target_descriptors->GetKey(i), isolate);
4268     PropertyDetails old_details = old_descriptors->GetDetails(i);
4269     PropertyDetails target_details = target_descriptors->GetDetails(i);
4270 
4271     PropertyKind next_kind;
4272     PropertyAttributes next_attributes;
4273     PropertyLocation next_location;
4274     Representation next_representation;
4275     bool property_kind_reconfiguration = false;
4276 
4277     if (modify_index == i) {
4278       DCHECK_EQ(FORCE_FIELD, store_mode);
4279       property_kind_reconfiguration = old_details.kind() != new_kind;
4280 
4281       next_kind = new_kind;
4282       next_attributes = new_attributes;
4283       next_location = kField;
4284 
4285       // Merge new representation/field type with ones from the target
4286       // descriptor. If property kind is not reconfigured merge the result with
4287       // representation/field type from the old descriptor.
4288       next_representation =
4289           new_representation.generalize(target_details.representation());
4290       if (!property_kind_reconfiguration) {
4291         next_representation =
4292             next_representation.generalize(old_details.representation());
4293       }
4294     } else {
4295       // Merge old_descriptor and target_descriptor entries.
4296       DCHECK_EQ(target_details.kind(), old_details.kind());
4297       next_kind = target_details.kind();
4298       next_attributes = target_details.attributes();
4299       next_location =
4300           old_details.location() == kField ||
4301                   target_details.location() == kField ||
4302                   !EqualImmutableValues(target_descriptors->GetValue(i),
4303                                         old_descriptors->GetValue(i))
4304               ? kField
4305               : kDescriptor;
4306 
4307       next_representation = old_details.representation().generalize(
4308           target_details.representation());
4309     }
4310     DCHECK_EQ(next_kind, target_details.kind());
4311     DCHECK_EQ(next_attributes, target_details.attributes());
4312 
4313     if (next_location == kField) {
4314       if (next_kind == kData) {
4315         Handle<FieldType> target_field_type =
4316             GetFieldType(isolate, target_descriptors, i,
4317                          target_details.location(), next_representation);
4318 
4319         Handle<FieldType> next_field_type;
4320         if (modify_index == i) {
4321           next_field_type = GeneralizeFieldType(
4322               target_details.representation(), target_field_type,
4323               new_representation, new_field_type, isolate);
4324           if (!property_kind_reconfiguration) {
4325             Handle<FieldType> old_field_type =
4326                 GetFieldType(isolate, old_descriptors, i,
4327                              old_details.location(), next_representation);
4328             next_field_type = GeneralizeFieldType(
4329                 old_details.representation(), old_field_type,
4330                 next_representation, next_field_type, isolate);
4331           }
4332         } else {
4333           Handle<FieldType> old_field_type =
4334               GetFieldType(isolate, old_descriptors, i, old_details.location(),
4335                            next_representation);
4336           next_field_type = GeneralizeFieldType(
4337               old_details.representation(), old_field_type, next_representation,
4338               target_field_type, isolate);
4339         }
4340         Handle<Object> wrapped_type(WrapType(next_field_type));
4341         DataDescriptor d(target_key, current_offset, wrapped_type,
4342                          next_attributes, next_representation);
4343         current_offset += d.GetDetails().field_width_in_words();
4344         new_descriptors->Set(i, &d);
4345       } else {
4346         UNIMPLEMENTED();  // TODO(ishell): implement.
4347       }
4348     } else {
4349       PropertyDetails details(next_attributes, next_kind, next_location,
4350                               next_representation);
4351       Descriptor d(target_key, handle(target_descriptors->GetValue(i), isolate),
4352                    details);
4353       new_descriptors->Set(i, &d);
4354     }
4355   }
4356 
4357   // |target_nof| -> |old_nof|
4358   for (int i = target_nof; i < old_nof; ++i) {
4359     PropertyDetails old_details = old_descriptors->GetDetails(i);
4360     Handle<Name> old_key(old_descriptors->GetKey(i), isolate);
4361 
4362     // Merge old_descriptor entry and modified details together.
4363     PropertyKind next_kind;
4364     PropertyAttributes next_attributes;
4365     PropertyLocation next_location;
4366     Representation next_representation;
4367     bool property_kind_reconfiguration = false;
4368 
4369     if (modify_index == i) {
4370       DCHECK_EQ(FORCE_FIELD, store_mode);
4371       // In case of property kind reconfiguration it is not necessary to
4372       // take into account representation/field type of the old descriptor.
4373       property_kind_reconfiguration = old_details.kind() != new_kind;
4374 
4375       next_kind = new_kind;
4376       next_attributes = new_attributes;
4377       next_location = kField;
4378       next_representation = new_representation;
4379       if (!property_kind_reconfiguration) {
4380         next_representation =
4381             next_representation.generalize(old_details.representation());
4382       }
4383     } else {
4384       next_kind = old_details.kind();
4385       next_attributes = old_details.attributes();
4386       next_location = old_details.location();
4387       next_representation = old_details.representation();
4388     }
4389 
4390     if (next_location == kField) {
4391       if (next_kind == kData) {
4392         Handle<FieldType> next_field_type;
4393         if (modify_index == i) {
4394           next_field_type = new_field_type;
4395           if (!property_kind_reconfiguration) {
4396             Handle<FieldType> old_field_type =
4397                 GetFieldType(isolate, old_descriptors, i,
4398                              old_details.location(), next_representation);
4399             next_field_type = GeneralizeFieldType(
4400                 old_details.representation(), old_field_type,
4401                 next_representation, next_field_type, isolate);
4402           }
4403         } else {
4404           Handle<FieldType> old_field_type =
4405               GetFieldType(isolate, old_descriptors, i, old_details.location(),
4406                            next_representation);
4407           next_field_type = old_field_type;
4408         }
4409 
4410         Handle<Object> wrapped_type(WrapType(next_field_type));
4411 
4412         DataDescriptor d(old_key, current_offset, wrapped_type, next_attributes,
4413                          next_representation);
4414         current_offset += d.GetDetails().field_width_in_words();
4415         new_descriptors->Set(i, &d);
4416       } else {
4417         UNIMPLEMENTED();  // TODO(ishell): implement.
4418       }
4419     } else {
4420       PropertyDetails details(next_attributes, next_kind, next_location,
4421                               next_representation);
4422       Descriptor d(old_key, handle(old_descriptors->GetValue(i), isolate),
4423                    details);
4424       new_descriptors->Set(i, &d);
4425     }
4426   }
4427 
4428   new_descriptors->Sort();
4429 
4430   DCHECK(store_mode != FORCE_FIELD ||
4431          new_descriptors->GetDetails(modify_index).location() == kField);
4432 
4433   Handle<Map> split_map(root_map->FindLastMatchMap(
4434           root_nof, old_nof, *new_descriptors), isolate);
4435   int split_nof = split_map->NumberOfOwnDescriptors();
4436   DCHECK_NE(old_nof, split_nof);
4437 
4438   PropertyKind split_kind;
4439   PropertyAttributes split_attributes;
4440   if (modify_index == split_nof) {
4441     split_kind = new_kind;
4442     split_attributes = new_attributes;
4443   } else {
4444     PropertyDetails split_prop_details = old_descriptors->GetDetails(split_nof);
4445     split_kind = split_prop_details.kind();
4446     split_attributes = split_prop_details.attributes();
4447   }
4448 
4449   // Invalidate a transition target at |key|.
4450   Map* maybe_transition = TransitionArray::SearchTransition(
4451       *split_map, split_kind, old_descriptors->GetKey(split_nof),
4452       split_attributes);
4453   if (maybe_transition != NULL) {
4454     maybe_transition->DeprecateTransitionTree();
4455   }
4456 
4457   // If |maybe_transition| is not NULL then the transition array already
4458   // contains entry for given descriptor. This means that the transition
4459   // could be inserted regardless of whether transitions array is full or not.
4460   if (maybe_transition == NULL &&
4461       !TransitionArray::CanHaveMoreTransitions(split_map)) {
4462     return CopyGeneralizeAllRepresentations(
4463         old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
4464         "GenAll_CantHaveMoreTransitions");
4465   }
4466 
4467   old_map->NotifyLeafMapLayoutChange();
4468 
4469   if (FLAG_trace_generalization && modify_index >= 0) {
4470     PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
4471     PropertyDetails new_details = new_descriptors->GetDetails(modify_index);
4472     MaybeHandle<FieldType> old_field_type;
4473     MaybeHandle<FieldType> new_field_type;
4474     MaybeHandle<Object> old_value;
4475     MaybeHandle<Object> new_value;
4476     if (old_details.type() == DATA) {
4477       old_field_type =
4478           handle(old_descriptors->GetFieldType(modify_index), isolate);
4479     } else {
4480       old_value = handle(old_descriptors->GetValue(modify_index), isolate);
4481     }
4482     if (new_details.type() == DATA) {
4483       new_field_type =
4484           handle(new_descriptors->GetFieldType(modify_index), isolate);
4485     } else {
4486       new_value = handle(new_descriptors->GetValue(modify_index), isolate);
4487     }
4488 
4489     old_map->PrintGeneralization(
4490         stdout, "", modify_index, split_nof, old_nof,
4491         old_details.location() == kDescriptor && store_mode == FORCE_FIELD,
4492         old_details.representation(), new_details.representation(),
4493         old_field_type, old_value, new_field_type, new_value);
4494   }
4495 
4496   Handle<LayoutDescriptor> new_layout_descriptor =
4497       LayoutDescriptor::New(split_map, new_descriptors, old_nof);
4498 
4499   Handle<Map> new_map =
4500       AddMissingTransitions(split_map, new_descriptors, new_layout_descriptor);
4501 
4502   // Deprecated part of the transition tree is no longer reachable, so replace
4503   // current instance descriptors in the "survived" part of the tree with
4504   // the new descriptors to maintain descriptors sharing invariant.
4505   split_map->ReplaceDescriptors(*new_descriptors, *new_layout_descriptor);
4506   return new_map;
4507 }
4508 
4509 
4510 // Generalize the representation of all DATA descriptors.
GeneralizeAllFieldRepresentations(Handle<Map> map)4511 Handle<Map> Map::GeneralizeAllFieldRepresentations(
4512     Handle<Map> map) {
4513   Handle<DescriptorArray> descriptors(map->instance_descriptors());
4514   for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) {
4515     PropertyDetails details = descriptors->GetDetails(i);
4516     if (details.type() == DATA) {
4517       map = ReconfigureProperty(map, i, kData, details.attributes(),
4518                                 Representation::Tagged(),
4519                                 FieldType::Any(map->GetIsolate()), FORCE_FIELD);
4520     }
4521   }
4522   return map;
4523 }
4524 
4525 
4526 // static
TryUpdate(Handle<Map> old_map)4527 MaybeHandle<Map> Map::TryUpdate(Handle<Map> old_map) {
4528   DisallowHeapAllocation no_allocation;
4529   DisallowDeoptimization no_deoptimization(old_map->GetIsolate());
4530 
4531   if (!old_map->is_deprecated()) return old_map;
4532 
4533   // Check the state of the root map.
4534   Map* root_map = old_map->FindRootMap();
4535   if (!old_map->EquivalentToForTransition(root_map)) return MaybeHandle<Map>();
4536 
4537   ElementsKind from_kind = root_map->elements_kind();
4538   ElementsKind to_kind = old_map->elements_kind();
4539   if (from_kind != to_kind) {
4540     // Try to follow existing elements kind transitions.
4541     root_map = root_map->LookupElementsTransitionMap(to_kind);
4542     if (root_map == NULL) return MaybeHandle<Map>();
4543     // From here on, use the map with correct elements kind as root map.
4544   }
4545   Map* new_map = root_map->TryReplayPropertyTransitions(*old_map);
4546   if (new_map == nullptr) return MaybeHandle<Map>();
4547   return handle(new_map);
4548 }
4549 
TryReplayPropertyTransitions(Map * old_map)4550 Map* Map::TryReplayPropertyTransitions(Map* old_map) {
4551   DisallowHeapAllocation no_allocation;
4552   DisallowDeoptimization no_deoptimization(GetIsolate());
4553 
4554   int root_nof = NumberOfOwnDescriptors();
4555 
4556   int old_nof = old_map->NumberOfOwnDescriptors();
4557   DescriptorArray* old_descriptors = old_map->instance_descriptors();
4558 
4559   Map* new_map = this;
4560   for (int i = root_nof; i < old_nof; ++i) {
4561     PropertyDetails old_details = old_descriptors->GetDetails(i);
4562     Map* transition = TransitionArray::SearchTransition(
4563         new_map, old_details.kind(), old_descriptors->GetKey(i),
4564         old_details.attributes());
4565     if (transition == NULL) return nullptr;
4566     new_map = transition;
4567     DescriptorArray* new_descriptors = new_map->instance_descriptors();
4568 
4569     PropertyDetails new_details = new_descriptors->GetDetails(i);
4570     DCHECK_EQ(old_details.kind(), new_details.kind());
4571     DCHECK_EQ(old_details.attributes(), new_details.attributes());
4572     if (!old_details.representation().fits_into(new_details.representation())) {
4573       return nullptr;
4574     }
4575     switch (new_details.type()) {
4576       case DATA: {
4577         FieldType* new_type = new_descriptors->GetFieldType(i);
4578         // Cleared field types need special treatment. They represent lost
4579         // knowledge, so we must first generalize the new_type to "Any".
4580         if (FieldTypeIsCleared(new_details.representation(), new_type)) {
4581           return nullptr;
4582         }
4583         PropertyType old_property_type = old_details.type();
4584         if (old_property_type == DATA) {
4585           FieldType* old_type = old_descriptors->GetFieldType(i);
4586           if (FieldTypeIsCleared(old_details.representation(), old_type) ||
4587               !old_type->NowIs(new_type)) {
4588             return nullptr;
4589           }
4590         } else {
4591           DCHECK(old_property_type == DATA_CONSTANT);
4592           Object* old_value = old_descriptors->GetValue(i);
4593           if (!new_type->NowContains(old_value)) {
4594             return nullptr;
4595           }
4596         }
4597         break;
4598       }
4599       case ACCESSOR: {
4600 #ifdef DEBUG
4601         FieldType* new_type = new_descriptors->GetFieldType(i);
4602         DCHECK(new_type->IsAny());
4603 #endif
4604         break;
4605       }
4606 
4607       case DATA_CONSTANT:
4608       case ACCESSOR_CONSTANT: {
4609         Object* old_value = old_descriptors->GetValue(i);
4610         Object* new_value = new_descriptors->GetValue(i);
4611         if (old_details.location() == kField || old_value != new_value) {
4612           return nullptr;
4613         }
4614         break;
4615       }
4616     }
4617   }
4618   if (new_map->NumberOfOwnDescriptors() != old_nof) return nullptr;
4619   return new_map;
4620 }
4621 
4622 
4623 // static
Update(Handle<Map> map)4624 Handle<Map> Map::Update(Handle<Map> map) {
4625   if (!map->is_deprecated()) return map;
4626   return ReconfigureProperty(map, -1, kData, NONE, Representation::None(),
4627                              FieldType::None(map->GetIsolate()),
4628                              ALLOW_IN_DESCRIPTOR);
4629 }
4630 
SetPropertyWithInterceptor(LookupIterator * it,ShouldThrow should_throw,Handle<Object> value)4631 Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
4632                                                  ShouldThrow should_throw,
4633                                                  Handle<Object> value) {
4634   DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
4635   return SetPropertyWithInterceptorInternal(it, it->GetInterceptor(),
4636                                             should_throw, value);
4637 }
4638 
SetProperty(Handle<Object> object,Handle<Name> name,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode)4639 MaybeHandle<Object> Object::SetProperty(Handle<Object> object,
4640                                         Handle<Name> name, Handle<Object> value,
4641                                         LanguageMode language_mode,
4642                                         StoreFromKeyed store_mode) {
4643   LookupIterator it(object, name);
4644   MAYBE_RETURN_NULL(SetProperty(&it, value, language_mode, store_mode));
4645   return value;
4646 }
4647 
4648 
SetPropertyInternal(LookupIterator * it,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode,bool * found)4649 Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
4650                                         Handle<Object> value,
4651                                         LanguageMode language_mode,
4652                                         StoreFromKeyed store_mode,
4653                                         bool* found) {
4654   it->UpdateProtector();
4655   DCHECK(it->IsFound());
4656   ShouldThrow should_throw =
4657       is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4658 
4659   // Make sure that the top context does not change when doing callbacks or
4660   // interceptor calls.
4661   AssertNoContextChange ncc(it->isolate());
4662 
4663   do {
4664     switch (it->state()) {
4665       case LookupIterator::NOT_FOUND:
4666         UNREACHABLE();
4667 
4668       case LookupIterator::ACCESS_CHECK:
4669         if (it->HasAccess()) break;
4670         // Check whether it makes sense to reuse the lookup iterator. Here it
4671         // might still call into setters up the prototype chain.
4672         return JSObject::SetPropertyWithFailedAccessCheck(it, value,
4673                                                           should_throw);
4674 
4675       case LookupIterator::JSPROXY:
4676         return JSProxy::SetProperty(it->GetHolder<JSProxy>(), it->GetName(),
4677                                     value, it->GetReceiver(), language_mode);
4678 
4679       case LookupIterator::INTERCEPTOR: {
4680         if (it->HolderIsReceiverOrHiddenPrototype()) {
4681           Maybe<bool> result =
4682               JSObject::SetPropertyWithInterceptor(it, should_throw, value);
4683           if (result.IsNothing() || result.FromJust()) return result;
4684         } else {
4685           Maybe<PropertyAttributes> maybe_attributes =
4686               JSObject::GetPropertyAttributesWithInterceptor(it);
4687           if (!maybe_attributes.IsJust()) return Nothing<bool>();
4688           if ((maybe_attributes.FromJust() & READ_ONLY) != 0) {
4689             return WriteToReadOnlyProperty(it, value, should_throw);
4690           }
4691           if (maybe_attributes.FromJust() == ABSENT) break;
4692           *found = false;
4693           return Nothing<bool>();
4694         }
4695         break;
4696       }
4697 
4698       case LookupIterator::ACCESSOR: {
4699         if (it->IsReadOnly()) {
4700           return WriteToReadOnlyProperty(it, value, should_throw);
4701         }
4702         Handle<Object> accessors = it->GetAccessors();
4703         if (accessors->IsAccessorInfo() &&
4704             !it->HolderIsReceiverOrHiddenPrototype() &&
4705             AccessorInfo::cast(*accessors)->is_special_data_property()) {
4706           *found = false;
4707           return Nothing<bool>();
4708         }
4709         return SetPropertyWithAccessor(it, value, should_throw);
4710       }
4711       case LookupIterator::INTEGER_INDEXED_EXOTIC:
4712         // TODO(verwaest): We should throw an exception if holder is receiver.
4713         return Just(true);
4714 
4715       case LookupIterator::DATA:
4716         if (it->IsReadOnly()) {
4717           return WriteToReadOnlyProperty(it, value, should_throw);
4718         }
4719         if (it->HolderIsReceiverOrHiddenPrototype()) {
4720           return SetDataProperty(it, value);
4721         }
4722       // Fall through.
4723       case LookupIterator::TRANSITION:
4724         *found = false;
4725         return Nothing<bool>();
4726     }
4727     it->Next();
4728   } while (it->IsFound());
4729 
4730   *found = false;
4731   return Nothing<bool>();
4732 }
4733 
4734 
SetProperty(LookupIterator * it,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode)4735 Maybe<bool> Object::SetProperty(LookupIterator* it, Handle<Object> value,
4736                                 LanguageMode language_mode,
4737                                 StoreFromKeyed store_mode) {
4738   if (it->IsFound()) {
4739     bool found = true;
4740     Maybe<bool> result =
4741         SetPropertyInternal(it, value, language_mode, store_mode, &found);
4742     if (found) return result;
4743   }
4744 
4745   // If the receiver is the JSGlobalObject, the store was contextual. In case
4746   // the property did not exist yet on the global object itself, we have to
4747   // throw a reference error in strict mode.  In sloppy mode, we continue.
4748   if (is_strict(language_mode) && it->GetReceiver()->IsJSGlobalObject()) {
4749     it->isolate()->Throw(*it->isolate()->factory()->NewReferenceError(
4750         MessageTemplate::kNotDefined, it->name()));
4751     return Nothing<bool>();
4752   }
4753 
4754   ShouldThrow should_throw =
4755       is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4756   return AddDataProperty(it, value, NONE, should_throw, store_mode);
4757 }
4758 
4759 
SetSuperProperty(LookupIterator * it,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode)4760 Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
4761                                      LanguageMode language_mode,
4762                                      StoreFromKeyed store_mode) {
4763   Isolate* isolate = it->isolate();
4764 
4765   if (it->IsFound()) {
4766     bool found = true;
4767     Maybe<bool> result =
4768         SetPropertyInternal(it, value, language_mode, store_mode, &found);
4769     if (found) return result;
4770   }
4771 
4772   it->UpdateProtector();
4773 
4774   // The property either doesn't exist on the holder or exists there as a data
4775   // property.
4776 
4777   ShouldThrow should_throw =
4778       is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4779 
4780   if (!it->GetReceiver()->IsJSReceiver()) {
4781     return WriteToReadOnlyProperty(it, value, should_throw);
4782   }
4783   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
4784 
4785   LookupIterator::Configuration c = LookupIterator::OWN;
4786   LookupIterator own_lookup =
4787       it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c)
4788                       : LookupIterator(receiver, it->name(), c);
4789 
4790   for (; own_lookup.IsFound(); own_lookup.Next()) {
4791     switch (own_lookup.state()) {
4792       case LookupIterator::ACCESS_CHECK:
4793         if (!own_lookup.HasAccess()) {
4794           return JSObject::SetPropertyWithFailedAccessCheck(&own_lookup, value,
4795                                                             should_throw);
4796         }
4797         break;
4798 
4799       case LookupIterator::ACCESSOR:
4800         if (own_lookup.GetAccessors()->IsAccessorInfo()) {
4801           if (own_lookup.IsReadOnly()) {
4802             return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
4803           }
4804           return JSObject::SetPropertyWithAccessor(&own_lookup, value,
4805                                                    should_throw);
4806         }
4807       // Fall through.
4808       case LookupIterator::INTEGER_INDEXED_EXOTIC:
4809         return RedefineIncompatibleProperty(isolate, it->GetName(), value,
4810                                             should_throw);
4811 
4812       case LookupIterator::DATA: {
4813         if (own_lookup.IsReadOnly()) {
4814           return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
4815         }
4816         return SetDataProperty(&own_lookup, value);
4817       }
4818 
4819       case LookupIterator::INTERCEPTOR:
4820       case LookupIterator::JSPROXY: {
4821         PropertyDescriptor desc;
4822         Maybe<bool> owned =
4823             JSReceiver::GetOwnPropertyDescriptor(&own_lookup, &desc);
4824         MAYBE_RETURN(owned, Nothing<bool>());
4825         if (!owned.FromJust()) {
4826           return JSReceiver::CreateDataProperty(&own_lookup, value,
4827                                                 should_throw);
4828         }
4829         if (PropertyDescriptor::IsAccessorDescriptor(&desc) ||
4830             !desc.writable()) {
4831           return RedefineIncompatibleProperty(isolate, it->GetName(), value,
4832                                               should_throw);
4833         }
4834 
4835         PropertyDescriptor value_desc;
4836         value_desc.set_value(value);
4837         return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
4838                                              &value_desc, should_throw);
4839       }
4840 
4841       case LookupIterator::NOT_FOUND:
4842       case LookupIterator::TRANSITION:
4843         UNREACHABLE();
4844     }
4845   }
4846 
4847   return AddDataProperty(&own_lookup, value, NONE, should_throw, store_mode);
4848 }
4849 
CannotCreateProperty(Isolate * isolate,Handle<Object> receiver,Handle<Object> name,Handle<Object> value,ShouldThrow should_throw)4850 Maybe<bool> Object::CannotCreateProperty(Isolate* isolate,
4851                                          Handle<Object> receiver,
4852                                          Handle<Object> name,
4853                                          Handle<Object> value,
4854                                          ShouldThrow should_throw) {
4855   RETURN_FAILURE(
4856       isolate, should_throw,
4857       NewTypeError(MessageTemplate::kStrictCannotCreateProperty, name,
4858                    Object::TypeOf(isolate, receiver), receiver));
4859 }
4860 
4861 
WriteToReadOnlyProperty(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)4862 Maybe<bool> Object::WriteToReadOnlyProperty(LookupIterator* it,
4863                                             Handle<Object> value,
4864                                             ShouldThrow should_throw) {
4865   return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(),
4866                                  it->GetName(), value, should_throw);
4867 }
4868 
4869 
WriteToReadOnlyProperty(Isolate * isolate,Handle<Object> receiver,Handle<Object> name,Handle<Object> value,ShouldThrow should_throw)4870 Maybe<bool> Object::WriteToReadOnlyProperty(Isolate* isolate,
4871                                             Handle<Object> receiver,
4872                                             Handle<Object> name,
4873                                             Handle<Object> value,
4874                                             ShouldThrow should_throw) {
4875   RETURN_FAILURE(isolate, should_throw,
4876                  NewTypeError(MessageTemplate::kStrictReadOnlyProperty, name,
4877                               Object::TypeOf(isolate, receiver), receiver));
4878 }
4879 
4880 
RedefineIncompatibleProperty(Isolate * isolate,Handle<Object> name,Handle<Object> value,ShouldThrow should_throw)4881 Maybe<bool> Object::RedefineIncompatibleProperty(Isolate* isolate,
4882                                                  Handle<Object> name,
4883                                                  Handle<Object> value,
4884                                                  ShouldThrow should_throw) {
4885   RETURN_FAILURE(isolate, should_throw,
4886                  NewTypeError(MessageTemplate::kRedefineDisallowed, name));
4887 }
4888 
4889 
SetDataProperty(LookupIterator * it,Handle<Object> value)4890 Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) {
4891   // Proxies are handled elsewhere. Other non-JSObjects cannot have own
4892   // properties.
4893   Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
4894 
4895   // Store on the holder which may be hidden behind the receiver.
4896   DCHECK(it->HolderIsReceiverOrHiddenPrototype());
4897 
4898   Handle<Object> to_assign = value;
4899   // Convert the incoming value to a number for storing into typed arrays.
4900   if (it->IsElement() && receiver->HasFixedTypedArrayElements()) {
4901     if (!value->IsNumber() && !value->IsUndefined(it->isolate())) {
4902       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4903           it->isolate(), to_assign, Object::ToNumber(value), Nothing<bool>());
4904       // We have to recheck the length. However, it can only change if the
4905       // underlying buffer was neutered, so just check that.
4906       if (Handle<JSArrayBufferView>::cast(receiver)->WasNeutered()) {
4907         return Just(true);
4908         // TODO(neis): According to the spec, this should throw a TypeError.
4909       }
4910     }
4911   }
4912 
4913   // Possibly migrate to the most up-to-date map that will be able to store
4914   // |value| under it->name().
4915   it->PrepareForDataProperty(to_assign);
4916 
4917   // Write the property value.
4918   it->WriteDataValue(to_assign);
4919 
4920 #if VERIFY_HEAP
4921   if (FLAG_verify_heap) {
4922     receiver->JSObjectVerify();
4923   }
4924 #endif
4925   return Just(true);
4926 }
4927 
4928 
AddDataProperty(LookupIterator * it,Handle<Object> value,PropertyAttributes attributes,ShouldThrow should_throw,StoreFromKeyed store_mode)4929 Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value,
4930                                     PropertyAttributes attributes,
4931                                     ShouldThrow should_throw,
4932                                     StoreFromKeyed store_mode) {
4933   if (!it->GetReceiver()->IsJSObject()) {
4934     if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate()) {
4935       RETURN_FAILURE(it->isolate(), should_throw,
4936                      NewTypeError(MessageTemplate::kProxyPrivate));
4937     }
4938     return CannotCreateProperty(it->isolate(), it->GetReceiver(), it->GetName(),
4939                                 value, should_throw);
4940   }
4941 
4942   DCHECK_NE(LookupIterator::INTEGER_INDEXED_EXOTIC, it->state());
4943 
4944   Handle<JSObject> receiver = it->GetStoreTarget();
4945 
4946   // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject)
4947   // instead. If the prototype is Null, the proxy is detached.
4948   if (receiver->IsJSGlobalProxy()) return Just(true);
4949 
4950   Isolate* isolate = it->isolate();
4951 
4952   if (it->ExtendingNonExtensible(receiver)) {
4953     RETURN_FAILURE(
4954         isolate, should_throw,
4955         NewTypeError(MessageTemplate::kObjectNotExtensible, it->GetName()));
4956   }
4957 
4958   if (it->IsElement()) {
4959     if (receiver->IsJSArray()) {
4960       Handle<JSArray> array = Handle<JSArray>::cast(receiver);
4961       if (JSArray::WouldChangeReadOnlyLength(array, it->index())) {
4962         RETURN_FAILURE(array->GetIsolate(), should_throw,
4963                        NewTypeError(MessageTemplate::kStrictReadOnlyProperty,
4964                                     isolate->factory()->length_string(),
4965                                     Object::TypeOf(isolate, array), array));
4966       }
4967 
4968       if (FLAG_trace_external_array_abuse &&
4969           array->HasFixedTypedArrayElements()) {
4970         CheckArrayAbuse(array, "typed elements write", it->index(), true);
4971       }
4972 
4973       if (FLAG_trace_js_array_abuse && !array->HasFixedTypedArrayElements()) {
4974         CheckArrayAbuse(array, "elements write", it->index(), false);
4975       }
4976     }
4977 
4978     Maybe<bool> result = JSObject::AddDataElement(receiver, it->index(), value,
4979                                                   attributes, should_throw);
4980     JSObject::ValidateElements(receiver);
4981     return result;
4982   } else {
4983     it->UpdateProtector();
4984     // Migrate to the most up-to-date map that will be able to store |value|
4985     // under it->name() with |attributes|.
4986     it->PrepareTransitionToDataProperty(receiver, value, attributes,
4987                                         store_mode);
4988     DCHECK_EQ(LookupIterator::TRANSITION, it->state());
4989     it->ApplyTransitionToDataProperty(receiver);
4990 
4991     // Write the property value.
4992     it->WriteDataValue(value);
4993 
4994 #if VERIFY_HEAP
4995     if (FLAG_verify_heap) {
4996       receiver->JSObjectVerify();
4997     }
4998 #endif
4999   }
5000 
5001   return Just(true);
5002 }
5003 
5004 
EnsureDescriptorSlack(Handle<Map> map,int slack)5005 void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
5006   // Only supports adding slack to owned descriptors.
5007   DCHECK(map->owns_descriptors());
5008 
5009   Handle<DescriptorArray> descriptors(map->instance_descriptors());
5010   int old_size = map->NumberOfOwnDescriptors();
5011   if (slack <= descriptors->NumberOfSlackDescriptors()) return;
5012 
5013   Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
5014       descriptors, old_size, slack);
5015 
5016   DisallowHeapAllocation no_allocation;
5017   // The descriptors are still the same, so keep the layout descriptor.
5018   LayoutDescriptor* layout_descriptor = map->GetLayoutDescriptor();
5019 
5020   if (old_size == 0) {
5021     map->UpdateDescriptors(*new_descriptors, layout_descriptor);
5022     return;
5023   }
5024 
5025   // If the source descriptors had an enum cache we copy it. This ensures
5026   // that the maps to which we push the new descriptor array back can rely
5027   // on a cache always being available once it is set. If the map has more
5028   // enumerated descriptors than available in the original cache, the cache
5029   // will be lazily replaced by the extended cache when needed.
5030   if (descriptors->HasEnumCache()) {
5031     new_descriptors->CopyEnumCacheFrom(*descriptors);
5032   }
5033 
5034   Isolate* isolate = map->GetIsolate();
5035   // Replace descriptors by new_descriptors in all maps that share it.
5036   isolate->heap()->incremental_marking()->IterateBlackObject(*descriptors);
5037 
5038   Map* current = *map;
5039   while (current->instance_descriptors() == *descriptors) {
5040     Object* next = current->GetBackPointer();
5041     if (next->IsUndefined(isolate)) break;  // Stop overwriting at initial map.
5042     current->UpdateDescriptors(*new_descriptors, layout_descriptor);
5043     current = Map::cast(next);
5044   }
5045   map->UpdateDescriptors(*new_descriptors, layout_descriptor);
5046 }
5047 
5048 template <class T>
AppendUniqueCallbacks(Handle<TemplateList> callbacks,Handle<typename T::Array> array,int valid_descriptors)5049 static int AppendUniqueCallbacks(Handle<TemplateList> callbacks,
5050                                  Handle<typename T::Array> array,
5051                                  int valid_descriptors) {
5052   int nof_callbacks = callbacks->length();
5053 
5054   Isolate* isolate = array->GetIsolate();
5055   // Ensure the keys are unique names before writing them into the
5056   // instance descriptor. Since it may cause a GC, it has to be done before we
5057   // temporarily put the heap in an invalid state while appending descriptors.
5058   for (int i = 0; i < nof_callbacks; ++i) {
5059     Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
5060     if (entry->name()->IsUniqueName()) continue;
5061     Handle<String> key =
5062         isolate->factory()->InternalizeString(
5063             Handle<String>(String::cast(entry->name())));
5064     entry->set_name(*key);
5065   }
5066 
5067   // Fill in new callback descriptors.  Process the callbacks from
5068   // back to front so that the last callback with a given name takes
5069   // precedence over previously added callbacks with that name.
5070   for (int i = nof_callbacks - 1; i >= 0; i--) {
5071     Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
5072     Handle<Name> key(Name::cast(entry->name()));
5073     // Check if a descriptor with this name already exists before writing.
5074     if (!T::Contains(key, entry, valid_descriptors, array)) {
5075       T::Insert(key, entry, valid_descriptors, array);
5076       valid_descriptors++;
5077     }
5078   }
5079 
5080   return valid_descriptors;
5081 }
5082 
5083 struct DescriptorArrayAppender {
5084   typedef DescriptorArray Array;
Containsv8::internal::DescriptorArrayAppender5085   static bool Contains(Handle<Name> key,
5086                        Handle<AccessorInfo> entry,
5087                        int valid_descriptors,
5088                        Handle<DescriptorArray> array) {
5089     DisallowHeapAllocation no_gc;
5090     return array->Search(*key, valid_descriptors) != DescriptorArray::kNotFound;
5091   }
Insertv8::internal::DescriptorArrayAppender5092   static void Insert(Handle<Name> key,
5093                      Handle<AccessorInfo> entry,
5094                      int valid_descriptors,
5095                      Handle<DescriptorArray> array) {
5096     DisallowHeapAllocation no_gc;
5097     AccessorConstantDescriptor desc(key, entry, entry->property_attributes());
5098     array->Append(&desc);
5099   }
5100 };
5101 
5102 
5103 struct FixedArrayAppender {
5104   typedef FixedArray Array;
Containsv8::internal::FixedArrayAppender5105   static bool Contains(Handle<Name> key,
5106                        Handle<AccessorInfo> entry,
5107                        int valid_descriptors,
5108                        Handle<FixedArray> array) {
5109     for (int i = 0; i < valid_descriptors; i++) {
5110       if (*key == AccessorInfo::cast(array->get(i))->name()) return true;
5111     }
5112     return false;
5113   }
Insertv8::internal::FixedArrayAppender5114   static void Insert(Handle<Name> key,
5115                      Handle<AccessorInfo> entry,
5116                      int valid_descriptors,
5117                      Handle<FixedArray> array) {
5118     DisallowHeapAllocation no_gc;
5119     array->set(valid_descriptors, *entry);
5120   }
5121 };
5122 
5123 
AppendCallbackDescriptors(Handle<Map> map,Handle<Object> descriptors)5124 void Map::AppendCallbackDescriptors(Handle<Map> map,
5125                                     Handle<Object> descriptors) {
5126   int nof = map->NumberOfOwnDescriptors();
5127   Handle<DescriptorArray> array(map->instance_descriptors());
5128   Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors);
5129   DCHECK_GE(array->NumberOfSlackDescriptors(), callbacks->length());
5130   nof = AppendUniqueCallbacks<DescriptorArrayAppender>(callbacks, array, nof);
5131   map->SetNumberOfOwnDescriptors(nof);
5132 }
5133 
5134 
AppendUnique(Handle<Object> descriptors,Handle<FixedArray> array,int valid_descriptors)5135 int AccessorInfo::AppendUnique(Handle<Object> descriptors,
5136                                Handle<FixedArray> array,
5137                                int valid_descriptors) {
5138   Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors);
5139   DCHECK_GE(array->length(), callbacks->length() + valid_descriptors);
5140   return AppendUniqueCallbacks<FixedArrayAppender>(callbacks, array,
5141                                                    valid_descriptors);
5142 }
5143 
5144 
ContainsMap(MapHandleList * maps,Map * map)5145 static bool ContainsMap(MapHandleList* maps, Map* map) {
5146   DCHECK_NOT_NULL(map);
5147   for (int i = 0; i < maps->length(); ++i) {
5148     if (!maps->at(i).is_null() && *maps->at(i) == map) return true;
5149   }
5150   return false;
5151 }
5152 
FindElementsKindTransitionedMap(MapHandleList * candidates)5153 Map* Map::FindElementsKindTransitionedMap(MapHandleList* candidates) {
5154   DisallowHeapAllocation no_allocation;
5155   DisallowDeoptimization no_deoptimization(GetIsolate());
5156 
5157   ElementsKind kind = elements_kind();
5158   bool packed = IsFastPackedElementsKind(kind);
5159 
5160   Map* transition = nullptr;
5161   if (IsTransitionableFastElementsKind(kind)) {
5162     // Check the state of the root map.
5163     Map* root_map = FindRootMap();
5164     if (!EquivalentToForTransition(root_map)) return nullptr;
5165     root_map = root_map->LookupElementsTransitionMap(kind);
5166     DCHECK_NOT_NULL(root_map);
5167     // Starting from the next existing elements kind transition try to
5168     // replay the property transitions that does not involve instance rewriting
5169     // (ElementsTransitionAndStoreStub does not support that).
5170     for (root_map = root_map->ElementsTransitionMap();
5171          root_map != nullptr && root_map->has_fast_elements();
5172          root_map = root_map->ElementsTransitionMap()) {
5173       Map* current = root_map->TryReplayPropertyTransitions(this);
5174       if (current == nullptr) continue;
5175       if (InstancesNeedRewriting(current)) continue;
5176 
5177       if (ContainsMap(candidates, current) &&
5178           (packed || !IsFastPackedElementsKind(current->elements_kind()))) {
5179         transition = current;
5180         packed = packed && IsFastPackedElementsKind(current->elements_kind());
5181       }
5182     }
5183   }
5184   return transition;
5185 }
5186 
5187 
FindClosestElementsTransition(Map * map,ElementsKind to_kind)5188 static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
5189   // Ensure we are requested to search elements kind transition "near the root".
5190   DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(),
5191             map->NumberOfOwnDescriptors());
5192   Map* current_map = map;
5193 
5194   ElementsKind kind = map->elements_kind();
5195   while (kind != to_kind) {
5196     Map* next_map = current_map->ElementsTransitionMap();
5197     if (next_map == nullptr) return current_map;
5198     kind = next_map->elements_kind();
5199     current_map = next_map;
5200   }
5201 
5202   DCHECK_EQ(to_kind, current_map->elements_kind());
5203   return current_map;
5204 }
5205 
5206 
LookupElementsTransitionMap(ElementsKind to_kind)5207 Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) {
5208   Map* to_map = FindClosestElementsTransition(this, to_kind);
5209   if (to_map->elements_kind() == to_kind) return to_map;
5210   return nullptr;
5211 }
5212 
5213 
IsMapInArrayPrototypeChain()5214 bool Map::IsMapInArrayPrototypeChain() {
5215   Isolate* isolate = GetIsolate();
5216   if (isolate->initial_array_prototype()->map() == this) {
5217     return true;
5218   }
5219 
5220   if (isolate->initial_object_prototype()->map() == this) {
5221     return true;
5222   }
5223 
5224   return false;
5225 }
5226 
5227 
WeakCellForMap(Handle<Map> map)5228 Handle<WeakCell> Map::WeakCellForMap(Handle<Map> map) {
5229   Isolate* isolate = map->GetIsolate();
5230   if (map->weak_cell_cache()->IsWeakCell()) {
5231     return Handle<WeakCell>(WeakCell::cast(map->weak_cell_cache()));
5232   }
5233   Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(map);
5234   map->set_weak_cell_cache(*weak_cell);
5235   return weak_cell;
5236 }
5237 
5238 
AddMissingElementsTransitions(Handle<Map> map,ElementsKind to_kind)5239 static Handle<Map> AddMissingElementsTransitions(Handle<Map> map,
5240                                                  ElementsKind to_kind) {
5241   DCHECK(IsTransitionElementsKind(map->elements_kind()));
5242 
5243   Handle<Map> current_map = map;
5244 
5245   ElementsKind kind = map->elements_kind();
5246   TransitionFlag flag;
5247   if (map->is_prototype_map()) {
5248     flag = OMIT_TRANSITION;
5249   } else {
5250     flag = INSERT_TRANSITION;
5251     if (IsFastElementsKind(kind)) {
5252       while (kind != to_kind && !IsTerminalElementsKind(kind)) {
5253         kind = GetNextTransitionElementsKind(kind);
5254         current_map = Map::CopyAsElementsKind(current_map, kind, flag);
5255       }
5256     }
5257   }
5258 
5259   // In case we are exiting the fast elements kind system, just add the map in
5260   // the end.
5261   if (kind != to_kind) {
5262     current_map = Map::CopyAsElementsKind(current_map, to_kind, flag);
5263   }
5264 
5265   DCHECK(current_map->elements_kind() == to_kind);
5266   return current_map;
5267 }
5268 
5269 
TransitionElementsTo(Handle<Map> map,ElementsKind to_kind)5270 Handle<Map> Map::TransitionElementsTo(Handle<Map> map,
5271                                       ElementsKind to_kind) {
5272   ElementsKind from_kind = map->elements_kind();
5273   if (from_kind == to_kind) return map;
5274 
5275   Isolate* isolate = map->GetIsolate();
5276   Context* native_context = isolate->context()->native_context();
5277   if (from_kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
5278     if (*map == native_context->fast_aliased_arguments_map()) {
5279       DCHECK_EQ(SLOW_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
5280       return handle(native_context->slow_aliased_arguments_map());
5281     }
5282   } else if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
5283     if (*map == native_context->slow_aliased_arguments_map()) {
5284       DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
5285       return handle(native_context->fast_aliased_arguments_map());
5286     }
5287   } else if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) {
5288     // Reuse map transitions for JSArrays.
5289     DisallowHeapAllocation no_gc;
5290     if (native_context->get(Context::ArrayMapIndex(from_kind)) == *map) {
5291       Object* maybe_transitioned_map =
5292           native_context->get(Context::ArrayMapIndex(to_kind));
5293       if (maybe_transitioned_map->IsMap()) {
5294         return handle(Map::cast(maybe_transitioned_map), isolate);
5295       }
5296     }
5297   }
5298 
5299   DCHECK(!map->IsUndefined(isolate));
5300   // Check if we can go back in the elements kind transition chain.
5301   if (IsHoleyElementsKind(from_kind) &&
5302       to_kind == GetPackedElementsKind(from_kind) &&
5303       map->GetBackPointer()->IsMap() &&
5304       Map::cast(map->GetBackPointer())->elements_kind() == to_kind) {
5305     return handle(Map::cast(map->GetBackPointer()));
5306   }
5307 
5308   bool allow_store_transition = IsTransitionElementsKind(from_kind);
5309   // Only store fast element maps in ascending generality.
5310   if (IsFastElementsKind(to_kind)) {
5311     allow_store_transition =
5312         allow_store_transition && IsTransitionableFastElementsKind(from_kind) &&
5313         IsMoreGeneralElementsKindTransition(from_kind, to_kind);
5314   }
5315 
5316   if (!allow_store_transition) {
5317     return Map::CopyAsElementsKind(map, to_kind, OMIT_TRANSITION);
5318   }
5319 
5320   return Map::ReconfigureElementsKind(map, to_kind);
5321 }
5322 
5323 
5324 // static
AsElementsKind(Handle<Map> map,ElementsKind kind)5325 Handle<Map> Map::AsElementsKind(Handle<Map> map, ElementsKind kind) {
5326   Handle<Map> closest_map(FindClosestElementsTransition(*map, kind));
5327 
5328   if (closest_map->elements_kind() == kind) {
5329     return closest_map;
5330   }
5331 
5332   return AddMissingElementsTransitions(closest_map, kind);
5333 }
5334 
5335 
GetElementsTransitionMap(Handle<JSObject> object,ElementsKind to_kind)5336 Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
5337                                                ElementsKind to_kind) {
5338   Handle<Map> map(object->map());
5339   return Map::TransitionElementsTo(map, to_kind);
5340 }
5341 
5342 
Revoke(Handle<JSProxy> proxy)5343 void JSProxy::Revoke(Handle<JSProxy> proxy) {
5344   Isolate* isolate = proxy->GetIsolate();
5345   if (!proxy->IsRevoked()) proxy->set_handler(isolate->heap()->null_value());
5346   DCHECK(proxy->IsRevoked());
5347 }
5348 
5349 
HasProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Name> name)5350 Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy,
5351                                  Handle<Name> name) {
5352   DCHECK(!name->IsPrivate());
5353   STACK_CHECK(isolate, Nothing<bool>());
5354   // 1. (Assert)
5355   // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
5356   Handle<Object> handler(proxy->handler(), isolate);
5357   // 3. If handler is null, throw a TypeError exception.
5358   // 4. Assert: Type(handler) is Object.
5359   if (proxy->IsRevoked()) {
5360     isolate->Throw(*isolate->factory()->NewTypeError(
5361         MessageTemplate::kProxyRevoked, isolate->factory()->has_string()));
5362     return Nothing<bool>();
5363   }
5364   // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
5365   Handle<JSReceiver> target(proxy->target(), isolate);
5366   // 6. Let trap be ? GetMethod(handler, "has").
5367   Handle<Object> trap;
5368   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5369       isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
5370                                        isolate->factory()->has_string()),
5371       Nothing<bool>());
5372   // 7. If trap is undefined, then
5373   if (trap->IsUndefined(isolate)) {
5374     // 7a. Return target.[[HasProperty]](P).
5375     return JSReceiver::HasProperty(target, name);
5376   }
5377   // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, P»)).
5378   Handle<Object> trap_result_obj;
5379   Handle<Object> args[] = {target, name};
5380   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5381       isolate, trap_result_obj,
5382       Execution::Call(isolate, trap, handler, arraysize(args), args),
5383       Nothing<bool>());
5384   bool boolean_trap_result = trap_result_obj->BooleanValue();
5385   // 9. If booleanTrapResult is false, then:
5386   if (!boolean_trap_result) {
5387     // 9a. Let targetDesc be ? target.[[GetOwnProperty]](P).
5388     PropertyDescriptor target_desc;
5389     Maybe<bool> target_found = JSReceiver::GetOwnPropertyDescriptor(
5390         isolate, target, name, &target_desc);
5391     MAYBE_RETURN(target_found, Nothing<bool>());
5392     // 9b. If targetDesc is not undefined, then:
5393     if (target_found.FromJust()) {
5394       // 9b i. If targetDesc.[[Configurable]] is false, throw a TypeError
5395       //       exception.
5396       if (!target_desc.configurable()) {
5397         isolate->Throw(*isolate->factory()->NewTypeError(
5398             MessageTemplate::kProxyHasNonConfigurable, name));
5399         return Nothing<bool>();
5400       }
5401       // 9b ii. Let extensibleTarget be ? IsExtensible(target).
5402       Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
5403       MAYBE_RETURN(extensible_target, Nothing<bool>());
5404       // 9b iii. If extensibleTarget is false, throw a TypeError exception.
5405       if (!extensible_target.FromJust()) {
5406         isolate->Throw(*isolate->factory()->NewTypeError(
5407             MessageTemplate::kProxyHasNonExtensible, name));
5408         return Nothing<bool>();
5409       }
5410     }
5411   }
5412   // 10. Return booleanTrapResult.
5413   return Just(boolean_trap_result);
5414 }
5415 
5416 
SetProperty(Handle<JSProxy> proxy,Handle<Name> name,Handle<Object> value,Handle<Object> receiver,LanguageMode language_mode)5417 Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name,
5418                                  Handle<Object> value, Handle<Object> receiver,
5419                                  LanguageMode language_mode) {
5420   DCHECK(!name->IsPrivate());
5421   Isolate* isolate = proxy->GetIsolate();
5422   STACK_CHECK(isolate, Nothing<bool>());
5423   Factory* factory = isolate->factory();
5424   Handle<String> trap_name = factory->set_string();
5425   ShouldThrow should_throw =
5426       is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
5427 
5428   if (proxy->IsRevoked()) {
5429     isolate->Throw(
5430         *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
5431     return Nothing<bool>();
5432   }
5433   Handle<JSReceiver> target(proxy->target(), isolate);
5434   Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
5435 
5436   Handle<Object> trap;
5437   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5438       isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
5439   if (trap->IsUndefined(isolate)) {
5440     LookupIterator it =
5441         LookupIterator::PropertyOrElement(isolate, receiver, name, target);
5442     return Object::SetSuperProperty(&it, value, language_mode,
5443                                     Object::MAY_BE_STORE_FROM_KEYED);
5444   }
5445 
5446   Handle<Object> trap_result;
5447   Handle<Object> args[] = {target, name, value, receiver};
5448   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5449       isolate, trap_result,
5450       Execution::Call(isolate, trap, handler, arraysize(args), args),
5451       Nothing<bool>());
5452   if (!trap_result->BooleanValue()) {
5453     RETURN_FAILURE(isolate, should_throw,
5454                    NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
5455                                 trap_name, name));
5456   }
5457 
5458   // Enforce the invariant.
5459   PropertyDescriptor target_desc;
5460   Maybe<bool> owned =
5461       JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
5462   MAYBE_RETURN(owned, Nothing<bool>());
5463   if (owned.FromJust()) {
5464     bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
5465                         !target_desc.configurable() &&
5466                         !target_desc.writable() &&
5467                         !value->SameValue(*target_desc.value());
5468     if (inconsistent) {
5469       isolate->Throw(*isolate->factory()->NewTypeError(
5470           MessageTemplate::kProxySetFrozenData, name));
5471       return Nothing<bool>();
5472     }
5473     inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
5474                    !target_desc.configurable() &&
5475                    target_desc.set()->IsUndefined(isolate);
5476     if (inconsistent) {
5477       isolate->Throw(*isolate->factory()->NewTypeError(
5478           MessageTemplate::kProxySetFrozenAccessor, name));
5479       return Nothing<bool>();
5480     }
5481   }
5482   return Just(true);
5483 }
5484 
5485 
DeletePropertyOrElement(Handle<JSProxy> proxy,Handle<Name> name,LanguageMode language_mode)5486 Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy,
5487                                              Handle<Name> name,
5488                                              LanguageMode language_mode) {
5489   DCHECK(!name->IsPrivate());
5490   ShouldThrow should_throw =
5491       is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
5492   Isolate* isolate = proxy->GetIsolate();
5493   STACK_CHECK(isolate, Nothing<bool>());
5494   Factory* factory = isolate->factory();
5495   Handle<String> trap_name = factory->deleteProperty_string();
5496 
5497   if (proxy->IsRevoked()) {
5498     isolate->Throw(
5499         *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
5500     return Nothing<bool>();
5501   }
5502   Handle<JSReceiver> target(proxy->target(), isolate);
5503   Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
5504 
5505   Handle<Object> trap;
5506   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5507       isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
5508   if (trap->IsUndefined(isolate)) {
5509     return JSReceiver::DeletePropertyOrElement(target, name, language_mode);
5510   }
5511 
5512   Handle<Object> trap_result;
5513   Handle<Object> args[] = {target, name};
5514   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5515       isolate, trap_result,
5516       Execution::Call(isolate, trap, handler, arraysize(args), args),
5517       Nothing<bool>());
5518   if (!trap_result->BooleanValue()) {
5519     RETURN_FAILURE(isolate, should_throw,
5520                    NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
5521                                 trap_name, name));
5522   }
5523 
5524   // Enforce the invariant.
5525   PropertyDescriptor target_desc;
5526   Maybe<bool> owned =
5527       JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
5528   MAYBE_RETURN(owned, Nothing<bool>());
5529   if (owned.FromJust() && !target_desc.configurable()) {
5530     isolate->Throw(*factory->NewTypeError(
5531         MessageTemplate::kProxyDeletePropertyNonConfigurable, name));
5532     return Nothing<bool>();
5533   }
5534   return Just(true);
5535 }
5536 
5537 
5538 // static
New(Isolate * isolate,Handle<Object> target,Handle<Object> handler)5539 MaybeHandle<JSProxy> JSProxy::New(Isolate* isolate, Handle<Object> target,
5540                                   Handle<Object> handler) {
5541   if (!target->IsJSReceiver()) {
5542     THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5543                     JSProxy);
5544   }
5545   if (target->IsJSProxy() && JSProxy::cast(*target)->IsRevoked()) {
5546     THROW_NEW_ERROR(isolate,
5547                     NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5548                     JSProxy);
5549   }
5550   if (!handler->IsJSReceiver()) {
5551     THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5552                     JSProxy);
5553   }
5554   if (handler->IsJSProxy() && JSProxy::cast(*handler)->IsRevoked()) {
5555     THROW_NEW_ERROR(isolate,
5556                     NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5557                     JSProxy);
5558   }
5559   return isolate->factory()->NewJSProxy(Handle<JSReceiver>::cast(target),
5560                                         Handle<JSReceiver>::cast(handler));
5561 }
5562 
5563 
5564 // static
GetFunctionRealm(Handle<JSProxy> proxy)5565 MaybeHandle<Context> JSProxy::GetFunctionRealm(Handle<JSProxy> proxy) {
5566   DCHECK(proxy->map()->is_constructor());
5567   if (proxy->IsRevoked()) {
5568     THROW_NEW_ERROR(proxy->GetIsolate(),
5569                     NewTypeError(MessageTemplate::kProxyRevoked), Context);
5570   }
5571   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()));
5572   return JSReceiver::GetFunctionRealm(target);
5573 }
5574 
5575 
5576 // static
GetFunctionRealm(Handle<JSBoundFunction> function)5577 MaybeHandle<Context> JSBoundFunction::GetFunctionRealm(
5578     Handle<JSBoundFunction> function) {
5579   DCHECK(function->map()->is_constructor());
5580   return JSReceiver::GetFunctionRealm(
5581       handle(function->bound_target_function()));
5582 }
5583 
5584 // static
GetName(Isolate * isolate,Handle<JSBoundFunction> function)5585 MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate,
5586                                              Handle<JSBoundFunction> function) {
5587   Handle<String> prefix = isolate->factory()->bound__string();
5588   if (!function->bound_target_function()->IsJSFunction()) return prefix;
5589   Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()),
5590                             isolate);
5591   Handle<Object> target_name = JSFunction::GetName(isolate, target);
5592   if (!target_name->IsString()) return prefix;
5593   Factory* factory = isolate->factory();
5594   return factory->NewConsString(prefix, Handle<String>::cast(target_name));
5595 }
5596 
5597 // static
GetName(Isolate * isolate,Handle<JSFunction> function)5598 Handle<Object> JSFunction::GetName(Isolate* isolate,
5599                                    Handle<JSFunction> function) {
5600   if (function->shared()->name_should_print_as_anonymous()) {
5601     return isolate->factory()->anonymous_string();
5602   }
5603   return handle(function->shared()->name(), isolate);
5604 }
5605 
5606 // static
GetLength(Isolate * isolate,Handle<JSFunction> function)5607 MaybeHandle<Smi> JSFunction::GetLength(Isolate* isolate,
5608                                        Handle<JSFunction> function) {
5609   int length = 0;
5610   if (function->shared()->is_compiled()) {
5611     length = function->shared()->length();
5612   } else {
5613     // If the function isn't compiled yet, the length is not computed
5614     // correctly yet. Compile it now and return the right length.
5615     if (Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) {
5616       length = function->shared()->length();
5617     }
5618     if (isolate->has_pending_exception()) return MaybeHandle<Smi>();
5619   }
5620   return handle(Smi::FromInt(length), isolate);
5621 }
5622 
5623 // static
GetFunctionRealm(Handle<JSFunction> function)5624 Handle<Context> JSFunction::GetFunctionRealm(Handle<JSFunction> function) {
5625   DCHECK(function->map()->is_constructor());
5626   return handle(function->context()->native_context());
5627 }
5628 
5629 
5630 // static
GetFunctionRealm(Handle<JSObject> object)5631 MaybeHandle<Context> JSObject::GetFunctionRealm(Handle<JSObject> object) {
5632   DCHECK(object->map()->is_constructor());
5633   DCHECK(!object->IsJSFunction());
5634   return handle(object->GetCreationContext());
5635 }
5636 
5637 
5638 // static
GetFunctionRealm(Handle<JSReceiver> receiver)5639 MaybeHandle<Context> JSReceiver::GetFunctionRealm(Handle<JSReceiver> receiver) {
5640   if (receiver->IsJSProxy()) {
5641     return JSProxy::GetFunctionRealm(Handle<JSProxy>::cast(receiver));
5642   }
5643 
5644   if (receiver->IsJSFunction()) {
5645     return JSFunction::GetFunctionRealm(Handle<JSFunction>::cast(receiver));
5646   }
5647 
5648   if (receiver->IsJSBoundFunction()) {
5649     return JSBoundFunction::GetFunctionRealm(
5650         Handle<JSBoundFunction>::cast(receiver));
5651   }
5652 
5653   return JSObject::GetFunctionRealm(Handle<JSObject>::cast(receiver));
5654 }
5655 
5656 
GetPropertyAttributes(LookupIterator * it)5657 Maybe<PropertyAttributes> JSProxy::GetPropertyAttributes(LookupIterator* it) {
5658   PropertyDescriptor desc;
5659   Maybe<bool> found = JSProxy::GetOwnPropertyDescriptor(
5660       it->isolate(), it->GetHolder<JSProxy>(), it->GetName(), &desc);
5661   MAYBE_RETURN(found, Nothing<PropertyAttributes>());
5662   if (!found.FromJust()) return Just(ABSENT);
5663   return Just(desc.ToAttributes());
5664 }
5665 
5666 
AllocateStorageForMap(Handle<JSObject> object,Handle<Map> map)5667 void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
5668   DCHECK(object->map()->GetInObjectProperties() ==
5669          map->GetInObjectProperties());
5670   ElementsKind obj_kind = object->map()->elements_kind();
5671   ElementsKind map_kind = map->elements_kind();
5672   if (map_kind != obj_kind) {
5673     ElementsKind to_kind = GetMoreGeneralElementsKind(map_kind, obj_kind);
5674     if (IsDictionaryElementsKind(obj_kind)) {
5675       to_kind = obj_kind;
5676     }
5677     if (IsDictionaryElementsKind(to_kind)) {
5678       NormalizeElements(object);
5679     } else {
5680       TransitionElementsKind(object, to_kind);
5681     }
5682     map = Map::ReconfigureElementsKind(map, to_kind);
5683   }
5684   JSObject::MigrateToMap(object, map);
5685 }
5686 
5687 
MigrateInstance(Handle<JSObject> object)5688 void JSObject::MigrateInstance(Handle<JSObject> object) {
5689   Handle<Map> original_map(object->map());
5690   Handle<Map> map = Map::Update(original_map);
5691   map->set_migration_target(true);
5692   MigrateToMap(object, map);
5693   if (FLAG_trace_migration) {
5694     object->PrintInstanceMigration(stdout, *original_map, *map);
5695   }
5696 #if VERIFY_HEAP
5697   if (FLAG_verify_heap) {
5698     object->JSObjectVerify();
5699   }
5700 #endif
5701 }
5702 
5703 
5704 // static
TryMigrateInstance(Handle<JSObject> object)5705 bool JSObject::TryMigrateInstance(Handle<JSObject> object) {
5706   Isolate* isolate = object->GetIsolate();
5707   DisallowDeoptimization no_deoptimization(isolate);
5708   Handle<Map> original_map(object->map(), isolate);
5709   Handle<Map> new_map;
5710   if (!Map::TryUpdate(original_map).ToHandle(&new_map)) {
5711     return false;
5712   }
5713   JSObject::MigrateToMap(object, new_map);
5714   if (FLAG_trace_migration) {
5715     object->PrintInstanceMigration(stdout, *original_map, object->map());
5716   }
5717 #if VERIFY_HEAP
5718   if (FLAG_verify_heap) {
5719     object->JSObjectVerify();
5720   }
5721 #endif
5722   return true;
5723 }
5724 
5725 
AddProperty(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)5726 void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name,
5727                            Handle<Object> value,
5728                            PropertyAttributes attributes) {
5729   LookupIterator it(object, name, object, LookupIterator::OWN_SKIP_INTERCEPTOR);
5730   CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
5731 #ifdef DEBUG
5732   uint32_t index;
5733   DCHECK(!object->IsJSProxy());
5734   DCHECK(!name->AsArrayIndex(&index));
5735   Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
5736   DCHECK(maybe.IsJust());
5737   DCHECK(!it.IsFound());
5738   DCHECK(object->map()->is_extensible() || name->IsPrivate());
5739 #endif
5740   CHECK(AddDataProperty(&it, value, attributes, THROW_ON_ERROR,
5741                         CERTAINLY_NOT_STORE_FROM_KEYED)
5742             .IsJust());
5743 }
5744 
5745 
5746 // Reconfigures a property to a data property with attributes, even if it is not
5747 // reconfigurable.
5748 // Requires a LookupIterator that does not look at the prototype chain beyond
5749 // hidden prototypes.
DefineOwnPropertyIgnoreAttributes(LookupIterator * it,Handle<Object> value,PropertyAttributes attributes,AccessorInfoHandling handling)5750 MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes(
5751     LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
5752     AccessorInfoHandling handling) {
5753   MAYBE_RETURN_NULL(DefineOwnPropertyIgnoreAttributes(
5754       it, value, attributes, THROW_ON_ERROR, handling));
5755   return value;
5756 }
5757 
5758 
DefineOwnPropertyIgnoreAttributes(LookupIterator * it,Handle<Object> value,PropertyAttributes attributes,ShouldThrow should_throw,AccessorInfoHandling handling)5759 Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
5760     LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
5761     ShouldThrow should_throw, AccessorInfoHandling handling) {
5762   it->UpdateProtector();
5763   Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
5764 
5765   for (; it->IsFound(); it->Next()) {
5766     switch (it->state()) {
5767       case LookupIterator::JSPROXY:
5768       case LookupIterator::NOT_FOUND:
5769       case LookupIterator::TRANSITION:
5770         UNREACHABLE();
5771 
5772       case LookupIterator::ACCESS_CHECK:
5773         if (!it->HasAccess()) {
5774           it->isolate()->ReportFailedAccessCheck(it->GetHolder<JSObject>());
5775           RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
5776           return Just(true);
5777         }
5778         break;
5779 
5780       // If there's an interceptor, try to store the property with the
5781       // interceptor.
5782       // In case of success, the attributes will have been reset to the default
5783       // attributes of the interceptor, rather than the incoming attributes.
5784       //
5785       // TODO(verwaest): JSProxy afterwards verify the attributes that the
5786       // JSProxy claims it has, and verifies that they are compatible. If not,
5787       // they throw. Here we should do the same.
5788       case LookupIterator::INTERCEPTOR:
5789         if (handling == DONT_FORCE_FIELD) {
5790           Maybe<bool> result =
5791               JSObject::SetPropertyWithInterceptor(it, should_throw, value);
5792           if (result.IsNothing() || result.FromJust()) return result;
5793         }
5794         break;
5795 
5796       case LookupIterator::ACCESSOR: {
5797         Handle<Object> accessors = it->GetAccessors();
5798 
5799         // Special handling for AccessorInfo, which behaves like a data
5800         // property.
5801         if (accessors->IsAccessorInfo() && handling == DONT_FORCE_FIELD) {
5802           PropertyAttributes current_attributes = it->property_attributes();
5803           // Ensure the context isn't changed after calling into accessors.
5804           AssertNoContextChange ncc(it->isolate());
5805 
5806           // Update the attributes before calling the setter. The setter may
5807           // later change the shape of the property.
5808           if (current_attributes != attributes) {
5809             it->TransitionToAccessorPair(accessors, attributes);
5810           }
5811 
5812           return JSObject::SetPropertyWithAccessor(it, value, should_throw);
5813         }
5814 
5815         it->ReconfigureDataProperty(value, attributes);
5816         return Just(true);
5817       }
5818       case LookupIterator::INTEGER_INDEXED_EXOTIC:
5819         return RedefineIncompatibleProperty(it->isolate(), it->GetName(), value,
5820                                             should_throw);
5821 
5822       case LookupIterator::DATA: {
5823         // Regular property update if the attributes match.
5824         if (it->property_attributes() == attributes) {
5825           return SetDataProperty(it, value);
5826         }
5827 
5828         // Special case: properties of typed arrays cannot be reconfigured to
5829         // non-writable nor to non-enumerable.
5830         if (it->IsElement() && object->HasFixedTypedArrayElements()) {
5831           return RedefineIncompatibleProperty(it->isolate(), it->GetName(),
5832                                               value, should_throw);
5833         }
5834 
5835         // Reconfigure the data property if the attributes mismatch.
5836         it->ReconfigureDataProperty(value, attributes);
5837 
5838         return Just(true);
5839       }
5840     }
5841   }
5842 
5843   return AddDataProperty(it, value, attributes, should_throw,
5844                          CERTAINLY_NOT_STORE_FROM_KEYED);
5845 }
5846 
SetOwnPropertyIgnoreAttributes(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)5847 MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
5848     Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
5849     PropertyAttributes attributes) {
5850   DCHECK(!value->IsTheHole(object->GetIsolate()));
5851   LookupIterator it(object, name, object, LookupIterator::OWN);
5852   return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
5853 }
5854 
SetOwnElementIgnoreAttributes(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes)5855 MaybeHandle<Object> JSObject::SetOwnElementIgnoreAttributes(
5856     Handle<JSObject> object, uint32_t index, Handle<Object> value,
5857     PropertyAttributes attributes) {
5858   Isolate* isolate = object->GetIsolate();
5859   LookupIterator it(isolate, object, index, object, LookupIterator::OWN);
5860   return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
5861 }
5862 
DefinePropertyOrElementIgnoreAttributes(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)5863 MaybeHandle<Object> JSObject::DefinePropertyOrElementIgnoreAttributes(
5864     Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
5865     PropertyAttributes attributes) {
5866   Isolate* isolate = object->GetIsolate();
5867   LookupIterator it = LookupIterator::PropertyOrElement(
5868       isolate, object, name, object, LookupIterator::OWN);
5869   return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
5870 }
5871 
GetPropertyAttributesWithInterceptor(LookupIterator * it)5872 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
5873     LookupIterator* it) {
5874   return GetPropertyAttributesWithInterceptorInternal(it, it->GetInterceptor());
5875 }
5876 
GetPropertyAttributes(LookupIterator * it)5877 Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
5878     LookupIterator* it) {
5879   for (; it->IsFound(); it->Next()) {
5880     switch (it->state()) {
5881       case LookupIterator::NOT_FOUND:
5882       case LookupIterator::TRANSITION:
5883         UNREACHABLE();
5884       case LookupIterator::JSPROXY:
5885         return JSProxy::GetPropertyAttributes(it);
5886       case LookupIterator::INTERCEPTOR: {
5887         Maybe<PropertyAttributes> result =
5888             JSObject::GetPropertyAttributesWithInterceptor(it);
5889         if (!result.IsJust()) return result;
5890         if (result.FromJust() != ABSENT) return result;
5891         break;
5892       }
5893       case LookupIterator::ACCESS_CHECK:
5894         if (it->HasAccess()) break;
5895         return JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
5896       case LookupIterator::INTEGER_INDEXED_EXOTIC:
5897         return Just(ABSENT);
5898       case LookupIterator::ACCESSOR:
5899       case LookupIterator::DATA:
5900         return Just(it->property_attributes());
5901     }
5902   }
5903   return Just(ABSENT);
5904 }
5905 
5906 
New(Isolate * isolate)5907 Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) {
5908   Handle<FixedArray> array(
5909       isolate->factory()->NewFixedArray(kEntries, TENURED));
5910   return Handle<NormalizedMapCache>::cast(array);
5911 }
5912 
5913 
Get(Handle<Map> fast_map,PropertyNormalizationMode mode)5914 MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map,
5915                                          PropertyNormalizationMode mode) {
5916   DisallowHeapAllocation no_gc;
5917   Object* value = FixedArray::get(GetIndex(fast_map));
5918   if (!value->IsMap() ||
5919       !Map::cast(value)->EquivalentToForNormalization(*fast_map, mode)) {
5920     return MaybeHandle<Map>();
5921   }
5922   return handle(Map::cast(value));
5923 }
5924 
5925 
Set(Handle<Map> fast_map,Handle<Map> normalized_map)5926 void NormalizedMapCache::Set(Handle<Map> fast_map,
5927                              Handle<Map> normalized_map) {
5928   DisallowHeapAllocation no_gc;
5929   DCHECK(normalized_map->is_dictionary_map());
5930   FixedArray::set(GetIndex(fast_map), *normalized_map);
5931 }
5932 
5933 
Clear()5934 void NormalizedMapCache::Clear() {
5935   int entries = length();
5936   for (int i = 0; i != entries; i++) {
5937     set_undefined(i);
5938   }
5939 }
5940 
5941 
UpdateMapCodeCache(Handle<HeapObject> object,Handle<Name> name,Handle<Code> code)5942 void HeapObject::UpdateMapCodeCache(Handle<HeapObject> object,
5943                                     Handle<Name> name,
5944                                     Handle<Code> code) {
5945   Handle<Map> map(object->map());
5946   Map::UpdateCodeCache(map, name, code);
5947 }
5948 
5949 
NormalizeProperties(Handle<JSObject> object,PropertyNormalizationMode mode,int expected_additional_properties,const char * reason)5950 void JSObject::NormalizeProperties(Handle<JSObject> object,
5951                                    PropertyNormalizationMode mode,
5952                                    int expected_additional_properties,
5953                                    const char* reason) {
5954   if (!object->HasFastProperties()) return;
5955 
5956   Handle<Map> map(object->map());
5957   Handle<Map> new_map = Map::Normalize(map, mode, reason);
5958 
5959   MigrateToMap(object, new_map, expected_additional_properties);
5960 }
5961 
5962 
MigrateSlowToFast(Handle<JSObject> object,int unused_property_fields,const char * reason)5963 void JSObject::MigrateSlowToFast(Handle<JSObject> object,
5964                                  int unused_property_fields,
5965                                  const char* reason) {
5966   if (object->HasFastProperties()) return;
5967   DCHECK(!object->IsJSGlobalObject());
5968   Isolate* isolate = object->GetIsolate();
5969   Factory* factory = isolate->factory();
5970   Handle<NameDictionary> dictionary(object->property_dictionary());
5971 
5972   // Make sure we preserve dictionary representation if there are too many
5973   // descriptors.
5974   int number_of_elements = dictionary->NumberOfElements();
5975   if (number_of_elements > kMaxNumberOfDescriptors) return;
5976 
5977   Handle<FixedArray> iteration_order;
5978   if (number_of_elements != dictionary->NextEnumerationIndex()) {
5979     iteration_order =
5980         NameDictionary::DoGenerateNewEnumerationIndices(dictionary);
5981   } else {
5982     iteration_order = NameDictionary::BuildIterationIndicesArray(dictionary);
5983   }
5984 
5985   int instance_descriptor_length = iteration_order->length();
5986   int number_of_fields = 0;
5987 
5988   // Compute the length of the instance descriptor.
5989   for (int i = 0; i < instance_descriptor_length; i++) {
5990     int index = Smi::cast(iteration_order->get(i))->value();
5991     DCHECK(dictionary->IsKey(isolate, dictionary->KeyAt(index)));
5992 
5993     Object* value = dictionary->ValueAt(index);
5994     PropertyType type = dictionary->DetailsAt(index).type();
5995     if (type == DATA && !value->IsJSFunction()) {
5996       number_of_fields += 1;
5997     }
5998   }
5999 
6000   Handle<Map> old_map(object->map(), isolate);
6001 
6002   int inobject_props = old_map->GetInObjectProperties();
6003 
6004   // Allocate new map.
6005   Handle<Map> new_map = Map::CopyDropDescriptors(old_map);
6006   new_map->set_dictionary_map(false);
6007 
6008   NotifyMapChange(old_map, new_map, isolate);
6009 
6010 #if TRACE_MAPS
6011   if (FLAG_trace_maps) {
6012     PrintF("[TraceMaps: SlowToFast from= %p to= %p reason= %s ]\n",
6013            reinterpret_cast<void*>(*old_map), reinterpret_cast<void*>(*new_map),
6014            reason);
6015   }
6016 #endif
6017 
6018   if (instance_descriptor_length == 0) {
6019     DisallowHeapAllocation no_gc;
6020     DCHECK_LE(unused_property_fields, inobject_props);
6021     // Transform the object.
6022     new_map->set_unused_property_fields(inobject_props);
6023     object->synchronized_set_map(*new_map);
6024     object->set_properties(isolate->heap()->empty_fixed_array());
6025     // Check that it really works.
6026     DCHECK(object->HasFastProperties());
6027     return;
6028   }
6029 
6030   // Allocate the instance descriptor.
6031   Handle<DescriptorArray> descriptors = DescriptorArray::Allocate(
6032       isolate, instance_descriptor_length, 0, TENURED);
6033 
6034   int number_of_allocated_fields =
6035       number_of_fields + unused_property_fields - inobject_props;
6036   if (number_of_allocated_fields < 0) {
6037     // There is enough inobject space for all fields (including unused).
6038     number_of_allocated_fields = 0;
6039     unused_property_fields = inobject_props - number_of_fields;
6040   }
6041 
6042   // Allocate the fixed array for the fields.
6043   Handle<FixedArray> fields = factory->NewFixedArray(
6044       number_of_allocated_fields);
6045 
6046   // Fill in the instance descriptor and the fields.
6047   int current_offset = 0;
6048   for (int i = 0; i < instance_descriptor_length; i++) {
6049     int index = Smi::cast(iteration_order->get(i))->value();
6050     Object* k = dictionary->KeyAt(index);
6051     DCHECK(dictionary->IsKey(k));
6052     // Dictionary keys are internalized upon insertion.
6053     // TODO(jkummerow): Turn this into a DCHECK if it's not hit in the wild.
6054     CHECK(k->IsUniqueName());
6055     Handle<Name> key(Name::cast(k), isolate);
6056 
6057     Object* value = dictionary->ValueAt(index);
6058 
6059     PropertyDetails details = dictionary->DetailsAt(index);
6060     int enumeration_index = details.dictionary_index();
6061     PropertyType type = details.type();
6062 
6063     if (value->IsJSFunction()) {
6064       DataConstantDescriptor d(key, handle(value, isolate),
6065                                details.attributes());
6066       descriptors->Set(enumeration_index - 1, &d);
6067     } else if (type == DATA) {
6068       if (current_offset < inobject_props) {
6069         object->InObjectPropertyAtPut(current_offset, value,
6070                                       UPDATE_WRITE_BARRIER);
6071       } else {
6072         int offset = current_offset - inobject_props;
6073         fields->set(offset, value);
6074       }
6075       DataDescriptor d(key, current_offset, details.attributes(),
6076                        // TODO(verwaest): value->OptimalRepresentation();
6077                        Representation::Tagged());
6078       current_offset += d.GetDetails().field_width_in_words();
6079       descriptors->Set(enumeration_index - 1, &d);
6080     } else if (type == ACCESSOR_CONSTANT) {
6081       AccessorConstantDescriptor d(key, handle(value, isolate),
6082                                    details.attributes());
6083       descriptors->Set(enumeration_index - 1, &d);
6084     } else {
6085       UNREACHABLE();
6086     }
6087   }
6088   DCHECK(current_offset == number_of_fields);
6089 
6090   descriptors->Sort();
6091 
6092   Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
6093       new_map, descriptors, descriptors->number_of_descriptors());
6094 
6095   DisallowHeapAllocation no_gc;
6096   new_map->InitializeDescriptors(*descriptors, *layout_descriptor);
6097   new_map->set_unused_property_fields(unused_property_fields);
6098 
6099   // Transform the object.
6100   object->synchronized_set_map(*new_map);
6101 
6102   object->set_properties(*fields);
6103   DCHECK(object->IsJSObject());
6104 
6105   // Check that it really works.
6106   DCHECK(object->HasFastProperties());
6107 }
6108 
6109 
ResetElements(Handle<JSObject> object)6110 void JSObject::ResetElements(Handle<JSObject> object) {
6111   Isolate* isolate = object->GetIsolate();
6112   CHECK(object->map() != isolate->heap()->sloppy_arguments_elements_map());
6113   if (object->map()->has_dictionary_elements()) {
6114     Handle<SeededNumberDictionary> new_elements =
6115         SeededNumberDictionary::New(isolate, 0);
6116     object->set_elements(*new_elements);
6117   } else {
6118     object->set_elements(object->map()->GetInitialElements());
6119   }
6120 }
6121 
6122 
RequireSlowElements(SeededNumberDictionary * dictionary)6123 void JSObject::RequireSlowElements(SeededNumberDictionary* dictionary) {
6124   if (dictionary->requires_slow_elements()) return;
6125   dictionary->set_requires_slow_elements();
6126   // TODO(verwaest): Remove this hack.
6127   if (map()->is_prototype_map()) {
6128     TypeFeedbackVector::ClearAllKeyedStoreICs(GetIsolate());
6129   }
6130 }
6131 
6132 
NormalizeElements(Handle<JSObject> object)6133 Handle<SeededNumberDictionary> JSObject::NormalizeElements(
6134     Handle<JSObject> object) {
6135   DCHECK(!object->HasFixedTypedArrayElements());
6136   Isolate* isolate = object->GetIsolate();
6137   bool is_arguments = object->HasSloppyArgumentsElements();
6138   {
6139     DisallowHeapAllocation no_gc;
6140     FixedArrayBase* elements = object->elements();
6141 
6142     if (is_arguments) {
6143       FixedArray* parameter_map = FixedArray::cast(elements);
6144       elements = FixedArrayBase::cast(parameter_map->get(1));
6145     }
6146 
6147     if (elements->IsDictionary()) {
6148       return handle(SeededNumberDictionary::cast(elements), isolate);
6149     }
6150   }
6151 
6152   DCHECK(object->HasFastSmiOrObjectElements() ||
6153          object->HasFastDoubleElements() ||
6154          object->HasFastArgumentsElements() ||
6155          object->HasFastStringWrapperElements());
6156 
6157   Handle<SeededNumberDictionary> dictionary =
6158       object->GetElementsAccessor()->Normalize(object);
6159 
6160   // Switch to using the dictionary as the backing storage for elements.
6161   ElementsKind target_kind = is_arguments
6162                                  ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS
6163                                  : object->HasFastStringWrapperElements()
6164                                        ? SLOW_STRING_WRAPPER_ELEMENTS
6165                                        : DICTIONARY_ELEMENTS;
6166   Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind);
6167   // Set the new map first to satify the elements type assert in set_elements().
6168   JSObject::MigrateToMap(object, new_map);
6169 
6170   if (is_arguments) {
6171     FixedArray::cast(object->elements())->set(1, *dictionary);
6172   } else {
6173     object->set_elements(*dictionary);
6174   }
6175 
6176   isolate->counters()->elements_to_dictionary()->Increment();
6177 
6178 #ifdef DEBUG
6179   if (FLAG_trace_normalization) {
6180     OFStream os(stdout);
6181     os << "Object elements have been normalized:\n";
6182     object->Print(os);
6183   }
6184 #endif
6185 
6186   DCHECK(object->HasDictionaryElements() ||
6187          object->HasSlowArgumentsElements() ||
6188          object->HasSlowStringWrapperElements());
6189   return dictionary;
6190 }
6191 
6192 
6193 template <typename ProxyType>
GetOrCreateIdentityHashHelper(Isolate * isolate,Handle<ProxyType> proxy)6194 static Smi* GetOrCreateIdentityHashHelper(Isolate* isolate,
6195                                           Handle<ProxyType> proxy) {
6196   Object* maybe_hash = proxy->hash();
6197   if (maybe_hash->IsSmi()) return Smi::cast(maybe_hash);
6198 
6199   Smi* hash = Smi::FromInt(isolate->GenerateIdentityHash(Smi::kMaxValue));
6200   proxy->set_hash(hash);
6201   return hash;
6202 }
6203 
6204 // static
GetIdentityHash(Isolate * isolate,Handle<JSObject> object)6205 Object* JSObject::GetIdentityHash(Isolate* isolate, Handle<JSObject> object) {
6206   if (object->IsJSGlobalProxy()) {
6207     return JSGlobalProxy::cast(*object)->hash();
6208   }
6209   Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol();
6210   return *JSReceiver::GetDataProperty(object, hash_code_symbol);
6211 }
6212 
6213 // static
GetOrCreateIdentityHash(Isolate * isolate,Handle<JSObject> object)6214 Smi* JSObject::GetOrCreateIdentityHash(Isolate* isolate,
6215                                        Handle<JSObject> object) {
6216   if (object->IsJSGlobalProxy()) {
6217     return GetOrCreateIdentityHashHelper(isolate,
6218                                          Handle<JSGlobalProxy>::cast(object));
6219   }
6220 
6221   Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol();
6222   LookupIterator it(object, hash_code_symbol, object, LookupIterator::OWN);
6223   if (it.IsFound()) {
6224     DCHECK_EQ(LookupIterator::DATA, it.state());
6225     Object* maybe_hash = *it.GetDataValue();
6226     if (maybe_hash->IsSmi()) return Smi::cast(maybe_hash);
6227   }
6228 
6229   Smi* hash = Smi::FromInt(isolate->GenerateIdentityHash(Smi::kMaxValue));
6230   CHECK(AddDataProperty(&it, handle(hash, isolate), NONE, THROW_ON_ERROR,
6231                         CERTAINLY_NOT_STORE_FROM_KEYED)
6232             .IsJust());
6233   return hash;
6234 }
6235 
6236 // static
GetIdentityHash(Handle<JSProxy> proxy)6237 Object* JSProxy::GetIdentityHash(Handle<JSProxy> proxy) {
6238   return proxy->hash();
6239 }
6240 
GetOrCreateIdentityHash(Isolate * isolate,Handle<JSProxy> proxy)6241 Smi* JSProxy::GetOrCreateIdentityHash(Isolate* isolate, Handle<JSProxy> proxy) {
6242   return GetOrCreateIdentityHashHelper(isolate, proxy);
6243 }
6244 
6245 
DeletePropertyWithInterceptor(LookupIterator * it,ShouldThrow should_throw)6246 Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it,
6247                                                     ShouldThrow should_throw) {
6248   Isolate* isolate = it->isolate();
6249   // Make sure that the top context does not change when doing callbacks or
6250   // interceptor calls.
6251   AssertNoContextChange ncc(isolate);
6252 
6253   DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
6254   Handle<InterceptorInfo> interceptor(it->GetInterceptor());
6255   if (interceptor->deleter()->IsUndefined(isolate)) return Nothing<bool>();
6256 
6257   Handle<JSObject> holder = it->GetHolder<JSObject>();
6258   Handle<Object> receiver = it->GetReceiver();
6259   if (!receiver->IsJSReceiver()) {
6260     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
6261                                      Object::ConvertReceiver(isolate, receiver),
6262                                      Nothing<bool>());
6263   }
6264 
6265   PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
6266                                  *holder, should_throw);
6267   Handle<Object> result;
6268   if (it->IsElement()) {
6269     uint32_t index = it->index();
6270     v8::IndexedPropertyDeleterCallback deleter =
6271         v8::ToCData<v8::IndexedPropertyDeleterCallback>(interceptor->deleter());
6272     result = args.Call(deleter, index);
6273   } else if (it->name()->IsSymbol() && !interceptor->can_intercept_symbols()) {
6274     return Nothing<bool>();
6275   } else {
6276     Handle<Name> name = it->name();
6277     DCHECK(!name->IsPrivate());
6278     v8::GenericNamedPropertyDeleterCallback deleter =
6279         v8::ToCData<v8::GenericNamedPropertyDeleterCallback>(
6280             interceptor->deleter());
6281     result = args.Call(deleter, name);
6282   }
6283 
6284   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6285   if (result.is_null()) return Nothing<bool>();
6286 
6287   DCHECK(result->IsBoolean());
6288   // Rebox CustomArguments::kReturnValueOffset before returning.
6289   return Just(result->IsTrue(isolate));
6290 }
6291 
6292 
DeleteNormalizedProperty(Handle<JSReceiver> object,Handle<Name> name,int entry)6293 void JSReceiver::DeleteNormalizedProperty(Handle<JSReceiver> object,
6294                                           Handle<Name> name, int entry) {
6295   DCHECK(!object->HasFastProperties());
6296   Isolate* isolate = object->GetIsolate();
6297 
6298   if (object->IsJSGlobalObject()) {
6299     // If we have a global object, invalidate the cell and swap in a new one.
6300     Handle<GlobalDictionary> dictionary(
6301         JSObject::cast(*object)->global_dictionary());
6302     DCHECK_NE(GlobalDictionary::kNotFound, entry);
6303 
6304     auto cell = PropertyCell::InvalidateEntry(dictionary, entry);
6305     cell->set_value(isolate->heap()->the_hole_value());
6306     cell->set_property_details(
6307         PropertyDetails::Empty(PropertyCellType::kUninitialized));
6308   } else {
6309     Handle<NameDictionary> dictionary(object->property_dictionary());
6310     DCHECK_NE(NameDictionary::kNotFound, entry);
6311 
6312     NameDictionary::DeleteProperty(dictionary, entry);
6313     Handle<NameDictionary> new_properties =
6314         NameDictionary::Shrink(dictionary, name);
6315     object->set_properties(*new_properties);
6316   }
6317 }
6318 
6319 
DeleteProperty(LookupIterator * it,LanguageMode language_mode)6320 Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
6321                                        LanguageMode language_mode) {
6322   it->UpdateProtector();
6323 
6324   Isolate* isolate = it->isolate();
6325 
6326   if (it->state() == LookupIterator::JSPROXY) {
6327     return JSProxy::DeletePropertyOrElement(it->GetHolder<JSProxy>(),
6328                                             it->GetName(), language_mode);
6329   }
6330 
6331   if (it->GetReceiver()->IsJSProxy()) {
6332     if (it->state() != LookupIterator::NOT_FOUND) {
6333       DCHECK_EQ(LookupIterator::DATA, it->state());
6334       DCHECK(it->name()->IsPrivate());
6335       it->Delete();
6336     }
6337     return Just(true);
6338   }
6339   Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
6340 
6341   for (; it->IsFound(); it->Next()) {
6342     switch (it->state()) {
6343       case LookupIterator::JSPROXY:
6344       case LookupIterator::NOT_FOUND:
6345       case LookupIterator::TRANSITION:
6346         UNREACHABLE();
6347       case LookupIterator::ACCESS_CHECK:
6348         if (it->HasAccess()) break;
6349         isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
6350         RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6351         return Just(false);
6352       case LookupIterator::INTERCEPTOR: {
6353         ShouldThrow should_throw =
6354             is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
6355         Maybe<bool> result =
6356             JSObject::DeletePropertyWithInterceptor(it, should_throw);
6357         // An exception was thrown in the interceptor. Propagate.
6358         if (isolate->has_pending_exception()) return Nothing<bool>();
6359         // Delete with interceptor succeeded. Return result.
6360         // TODO(neis): In strict mode, we should probably throw if the
6361         // interceptor returns false.
6362         if (result.IsJust()) return result;
6363         break;
6364       }
6365       case LookupIterator::INTEGER_INDEXED_EXOTIC:
6366         return Just(true);
6367       case LookupIterator::DATA:
6368       case LookupIterator::ACCESSOR: {
6369         if (!it->IsConfigurable()) {
6370           // Fail if the property is not configurable.
6371           if (is_strict(language_mode)) {
6372             isolate->Throw(*isolate->factory()->NewTypeError(
6373                 MessageTemplate::kStrictDeleteProperty, it->GetName(),
6374                 receiver));
6375             return Nothing<bool>();
6376           }
6377           return Just(false);
6378         }
6379 
6380         it->Delete();
6381 
6382         return Just(true);
6383       }
6384     }
6385   }
6386 
6387   return Just(true);
6388 }
6389 
6390 
DeleteElement(Handle<JSReceiver> object,uint32_t index,LanguageMode language_mode)6391 Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index,
6392                                       LanguageMode language_mode) {
6393   LookupIterator it(object->GetIsolate(), object, index, object,
6394                     LookupIterator::OWN);
6395   return DeleteProperty(&it, language_mode);
6396 }
6397 
6398 
DeleteProperty(Handle<JSReceiver> object,Handle<Name> name,LanguageMode language_mode)6399 Maybe<bool> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
6400                                        Handle<Name> name,
6401                                        LanguageMode language_mode) {
6402   LookupIterator it(object, name, object, LookupIterator::OWN);
6403   return DeleteProperty(&it, language_mode);
6404 }
6405 
6406 
DeletePropertyOrElement(Handle<JSReceiver> object,Handle<Name> name,LanguageMode language_mode)6407 Maybe<bool> JSReceiver::DeletePropertyOrElement(Handle<JSReceiver> object,
6408                                                 Handle<Name> name,
6409                                                 LanguageMode language_mode) {
6410   LookupIterator it = LookupIterator::PropertyOrElement(
6411       name->GetIsolate(), object, name, object, LookupIterator::OWN);
6412   return DeleteProperty(&it, language_mode);
6413 }
6414 
6415 
6416 // ES6 7.1.14
6417 // static
ToPropertyKey(Isolate * isolate,Handle<Object> value)6418 MaybeHandle<Object> Object::ToPropertyKey(Isolate* isolate,
6419                                           Handle<Object> value) {
6420   // 1. Let key be ToPrimitive(argument, hint String).
6421   MaybeHandle<Object> maybe_key =
6422       Object::ToPrimitive(value, ToPrimitiveHint::kString);
6423   // 2. ReturnIfAbrupt(key).
6424   Handle<Object> key;
6425   if (!maybe_key.ToHandle(&key)) return key;
6426   // 3. If Type(key) is Symbol, then return key.
6427   if (key->IsSymbol()) return key;
6428   // 4. Return ToString(key).
6429   // Extending spec'ed behavior, we'd be happy to return an element index.
6430   if (key->IsSmi()) return key;
6431   if (key->IsHeapNumber()) {
6432     uint32_t uint_value;
6433     if (value->ToArrayLength(&uint_value) &&
6434         uint_value <= static_cast<uint32_t>(Smi::kMaxValue)) {
6435       return handle(Smi::FromInt(static_cast<int>(uint_value)), isolate);
6436     }
6437   }
6438   return Object::ToString(isolate, key);
6439 }
6440 
6441 
6442 // ES6 19.1.2.4
6443 // static
DefineProperty(Isolate * isolate,Handle<Object> object,Handle<Object> key,Handle<Object> attributes)6444 Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object,
6445                                    Handle<Object> key,
6446                                    Handle<Object> attributes) {
6447   // 1. If Type(O) is not Object, throw a TypeError exception.
6448   if (!object->IsJSReceiver()) {
6449     Handle<String> fun_name =
6450         isolate->factory()->InternalizeUtf8String("Object.defineProperty");
6451     THROW_NEW_ERROR_RETURN_FAILURE(
6452         isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name));
6453   }
6454   // 2. Let key be ToPropertyKey(P).
6455   // 3. ReturnIfAbrupt(key).
6456   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key, ToPropertyKey(isolate, key));
6457   // 4. Let desc be ToPropertyDescriptor(Attributes).
6458   // 5. ReturnIfAbrupt(desc).
6459   PropertyDescriptor desc;
6460   if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) {
6461     return isolate->heap()->exception();
6462   }
6463   // 6. Let success be DefinePropertyOrThrow(O,key, desc).
6464   Maybe<bool> success = DefineOwnProperty(
6465       isolate, Handle<JSReceiver>::cast(object), key, &desc, THROW_ON_ERROR);
6466   // 7. ReturnIfAbrupt(success).
6467   MAYBE_RETURN(success, isolate->heap()->exception());
6468   CHECK(success.FromJust());
6469   // 8. Return O.
6470   return *object;
6471 }
6472 
6473 
6474 // ES6 19.1.2.3.1
6475 // static
DefineProperties(Isolate * isolate,Handle<Object> object,Handle<Object> properties)6476 MaybeHandle<Object> JSReceiver::DefineProperties(Isolate* isolate,
6477                                                  Handle<Object> object,
6478                                                  Handle<Object> properties) {
6479   // 1. If Type(O) is not Object, throw a TypeError exception.
6480   if (!object->IsJSReceiver()) {
6481     Handle<String> fun_name =
6482         isolate->factory()->InternalizeUtf8String("Object.defineProperties");
6483     THROW_NEW_ERROR(isolate,
6484                     NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name),
6485                     Object);
6486   }
6487   // 2. Let props be ToObject(Properties).
6488   // 3. ReturnIfAbrupt(props).
6489   Handle<JSReceiver> props;
6490   ASSIGN_RETURN_ON_EXCEPTION(isolate, props,
6491                              Object::ToObject(isolate, properties), Object);
6492 
6493   // 4. Let keys be props.[[OwnPropertyKeys]]().
6494   // 5. ReturnIfAbrupt(keys).
6495   Handle<FixedArray> keys;
6496   ASSIGN_RETURN_ON_EXCEPTION(
6497       isolate, keys, KeyAccumulator::GetKeys(props, KeyCollectionMode::kOwnOnly,
6498                                              ALL_PROPERTIES),
6499       Object);
6500   // 6. Let descriptors be an empty List.
6501   int capacity = keys->length();
6502   std::vector<PropertyDescriptor> descriptors(capacity);
6503   size_t descriptors_index = 0;
6504   // 7. Repeat for each element nextKey of keys in List order,
6505   for (int i = 0; i < keys->length(); ++i) {
6506     Handle<Object> next_key(keys->get(i), isolate);
6507     // 7a. Let propDesc be props.[[GetOwnProperty]](nextKey).
6508     // 7b. ReturnIfAbrupt(propDesc).
6509     bool success = false;
6510     LookupIterator it = LookupIterator::PropertyOrElement(
6511         isolate, props, next_key, &success, LookupIterator::OWN);
6512     DCHECK(success);
6513     Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
6514     if (!maybe.IsJust()) return MaybeHandle<Object>();
6515     PropertyAttributes attrs = maybe.FromJust();
6516     // 7c. If propDesc is not undefined and propDesc.[[Enumerable]] is true:
6517     if (attrs == ABSENT) continue;
6518     if (attrs & DONT_ENUM) continue;
6519     // 7c i. Let descObj be Get(props, nextKey).
6520     // 7c ii. ReturnIfAbrupt(descObj).
6521     Handle<Object> desc_obj;
6522     ASSIGN_RETURN_ON_EXCEPTION(isolate, desc_obj, Object::GetProperty(&it),
6523                                Object);
6524     // 7c iii. Let desc be ToPropertyDescriptor(descObj).
6525     success = PropertyDescriptor::ToPropertyDescriptor(
6526         isolate, desc_obj, &descriptors[descriptors_index]);
6527     // 7c iv. ReturnIfAbrupt(desc).
6528     if (!success) return MaybeHandle<Object>();
6529     // 7c v. Append the pair (a two element List) consisting of nextKey and
6530     //       desc to the end of descriptors.
6531     descriptors[descriptors_index].set_name(next_key);
6532     descriptors_index++;
6533   }
6534   // 8. For each pair from descriptors in list order,
6535   for (size_t i = 0; i < descriptors_index; ++i) {
6536     PropertyDescriptor* desc = &descriptors[i];
6537     // 8a. Let P be the first element of pair.
6538     // 8b. Let desc be the second element of pair.
6539     // 8c. Let status be DefinePropertyOrThrow(O, P, desc).
6540     Maybe<bool> status =
6541         DefineOwnProperty(isolate, Handle<JSReceiver>::cast(object),
6542                           desc->name(), desc, THROW_ON_ERROR);
6543     // 8d. ReturnIfAbrupt(status).
6544     if (!status.IsJust()) return MaybeHandle<Object>();
6545     CHECK(status.FromJust());
6546   }
6547   // 9. Return o.
6548   return object;
6549 }
6550 
6551 
6552 // static
DefineOwnProperty(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> key,PropertyDescriptor * desc,ShouldThrow should_throw)6553 Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate,
6554                                           Handle<JSReceiver> object,
6555                                           Handle<Object> key,
6556                                           PropertyDescriptor* desc,
6557                                           ShouldThrow should_throw) {
6558   if (object->IsJSArray()) {
6559     return JSArray::DefineOwnProperty(isolate, Handle<JSArray>::cast(object),
6560                                       key, desc, should_throw);
6561   }
6562   if (object->IsJSProxy()) {
6563     return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object),
6564                                       key, desc, should_throw);
6565   }
6566   // TODO(neis): Special case for JSModuleNamespace?
6567 
6568   // OrdinaryDefineOwnProperty, by virtue of calling
6569   // DefineOwnPropertyIgnoreAttributes, can handle arguments (ES6 9.4.4.2)
6570   // and IntegerIndexedExotics (ES6 9.4.5.3), with one exception:
6571   // TODO(jkummerow): Setting an indexed accessor on a typed array should throw.
6572   return OrdinaryDefineOwnProperty(isolate, Handle<JSObject>::cast(object), key,
6573                                    desc, should_throw);
6574 }
6575 
6576 
6577 // static
OrdinaryDefineOwnProperty(Isolate * isolate,Handle<JSObject> object,Handle<Object> key,PropertyDescriptor * desc,ShouldThrow should_throw)6578 Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate,
6579                                                   Handle<JSObject> object,
6580                                                   Handle<Object> key,
6581                                                   PropertyDescriptor* desc,
6582                                                   ShouldThrow should_throw) {
6583   bool success = false;
6584   DCHECK(key->IsName() || key->IsNumber());  // |key| is a PropertyKey...
6585   LookupIterator it = LookupIterator::PropertyOrElement(
6586       isolate, object, key, &success, LookupIterator::OWN);
6587   DCHECK(success);  // ...so creating a LookupIterator can't fail.
6588 
6589   // Deal with access checks first.
6590   if (it.state() == LookupIterator::ACCESS_CHECK) {
6591     if (!it.HasAccess()) {
6592       isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>());
6593       RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6594       return Just(true);
6595     }
6596     it.Next();
6597   }
6598 
6599   // Handle interceptor
6600   if (it.state() == LookupIterator::INTERCEPTOR) {
6601     if (it.HolderIsReceiverOrHiddenPrototype()) {
6602       Maybe<bool> result = DefinePropertyWithInterceptorInternal(
6603           &it, it.GetInterceptor(), should_throw, *desc);
6604       if (result.IsNothing() || result.FromJust()) {
6605         return result;
6606       }
6607     }
6608   }
6609 
6610   return OrdinaryDefineOwnProperty(&it, desc, should_throw);
6611 }
6612 
6613 
6614 // ES6 9.1.6.1
6615 // static
OrdinaryDefineOwnProperty(LookupIterator * it,PropertyDescriptor * desc,ShouldThrow should_throw)6616 Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
6617                                                   PropertyDescriptor* desc,
6618                                                   ShouldThrow should_throw) {
6619   Isolate* isolate = it->isolate();
6620   // 1. Let current be O.[[GetOwnProperty]](P).
6621   // 2. ReturnIfAbrupt(current).
6622   PropertyDescriptor current;
6623   MAYBE_RETURN(GetOwnPropertyDescriptor(it, &current), Nothing<bool>());
6624 
6625   // TODO(jkummerow/verwaest): It would be nice if we didn't have to reset
6626   // the iterator every time. Currently, the reasons why we need it are:
6627   // - handle interceptors correctly
6628   // - handle accessors correctly (which might change the holder's map)
6629   it->Restart();
6630   // 3. Let extensible be the value of the [[Extensible]] internal slot of O.
6631   Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
6632   bool extensible = JSObject::IsExtensible(object);
6633 
6634   return ValidateAndApplyPropertyDescriptor(isolate, it, extensible, desc,
6635                                             &current, should_throw);
6636 }
6637 
6638 
6639 // ES6 9.1.6.2
6640 // static
IsCompatiblePropertyDescriptor(Isolate * isolate,bool extensible,PropertyDescriptor * desc,PropertyDescriptor * current,Handle<Name> property_name,ShouldThrow should_throw)6641 Maybe<bool> JSReceiver::IsCompatiblePropertyDescriptor(
6642     Isolate* isolate, bool extensible, PropertyDescriptor* desc,
6643     PropertyDescriptor* current, Handle<Name> property_name,
6644     ShouldThrow should_throw) {
6645   // 1. Return ValidateAndApplyPropertyDescriptor(undefined, undefined,
6646   //    Extensible, Desc, Current).
6647   return ValidateAndApplyPropertyDescriptor(
6648       isolate, NULL, extensible, desc, current, should_throw, property_name);
6649 }
6650 
6651 
6652 // ES6 9.1.6.3
6653 // static
ValidateAndApplyPropertyDescriptor(Isolate * isolate,LookupIterator * it,bool extensible,PropertyDescriptor * desc,PropertyDescriptor * current,ShouldThrow should_throw,Handle<Name> property_name)6654 Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor(
6655     Isolate* isolate, LookupIterator* it, bool extensible,
6656     PropertyDescriptor* desc, PropertyDescriptor* current,
6657     ShouldThrow should_throw, Handle<Name> property_name) {
6658   // We either need a LookupIterator, or a property name.
6659   DCHECK((it == NULL) != property_name.is_null());
6660   Handle<JSObject> object;
6661   if (it != NULL) object = Handle<JSObject>::cast(it->GetReceiver());
6662   bool desc_is_data_descriptor = PropertyDescriptor::IsDataDescriptor(desc);
6663   bool desc_is_accessor_descriptor =
6664       PropertyDescriptor::IsAccessorDescriptor(desc);
6665   bool desc_is_generic_descriptor =
6666       PropertyDescriptor::IsGenericDescriptor(desc);
6667   // 1. (Assert)
6668   // 2. If current is undefined, then
6669   if (current->is_empty()) {
6670     // 2a. If extensible is false, return false.
6671     if (!extensible) {
6672       RETURN_FAILURE(isolate, should_throw,
6673                      NewTypeError(MessageTemplate::kDefineDisallowed,
6674                                   it != NULL ? it->GetName() : property_name));
6675     }
6676     // 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then:
6677     // (This is equivalent to !IsAccessorDescriptor(desc).)
6678     DCHECK((desc_is_generic_descriptor || desc_is_data_descriptor) ==
6679            !desc_is_accessor_descriptor);
6680     if (!desc_is_accessor_descriptor) {
6681       // 2c i. If O is not undefined, create an own data property named P of
6682       // object O whose [[Value]], [[Writable]], [[Enumerable]] and
6683       // [[Configurable]] attribute values are described by Desc. If the value
6684       // of an attribute field of Desc is absent, the attribute of the newly
6685       // created property is set to its default value.
6686       if (it != NULL) {
6687         if (!desc->has_writable()) desc->set_writable(false);
6688         if (!desc->has_enumerable()) desc->set_enumerable(false);
6689         if (!desc->has_configurable()) desc->set_configurable(false);
6690         Handle<Object> value(
6691             desc->has_value()
6692                 ? desc->value()
6693                 : Handle<Object>::cast(isolate->factory()->undefined_value()));
6694         MaybeHandle<Object> result =
6695             JSObject::DefineOwnPropertyIgnoreAttributes(it, value,
6696                                                         desc->ToAttributes());
6697         if (result.is_null()) return Nothing<bool>();
6698       }
6699     } else {
6700       // 2d. Else Desc must be an accessor Property Descriptor,
6701       DCHECK(desc_is_accessor_descriptor);
6702       // 2d i. If O is not undefined, create an own accessor property named P
6703       // of object O whose [[Get]], [[Set]], [[Enumerable]] and
6704       // [[Configurable]] attribute values are described by Desc. If the value
6705       // of an attribute field of Desc is absent, the attribute of the newly
6706       // created property is set to its default value.
6707       if (it != NULL) {
6708         if (!desc->has_enumerable()) desc->set_enumerable(false);
6709         if (!desc->has_configurable()) desc->set_configurable(false);
6710         Handle<Object> getter(
6711             desc->has_get()
6712                 ? desc->get()
6713                 : Handle<Object>::cast(isolate->factory()->null_value()));
6714         Handle<Object> setter(
6715             desc->has_set()
6716                 ? desc->set()
6717                 : Handle<Object>::cast(isolate->factory()->null_value()));
6718         MaybeHandle<Object> result =
6719             JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes());
6720         if (result.is_null()) return Nothing<bool>();
6721       }
6722     }
6723     // 2e. Return true.
6724     return Just(true);
6725   }
6726   // 3. Return true, if every field in Desc is absent.
6727   // 4. Return true, if every field in Desc also occurs in current and the
6728   // value of every field in Desc is the same value as the corresponding field
6729   // in current when compared using the SameValue algorithm.
6730   if ((!desc->has_enumerable() ||
6731        desc->enumerable() == current->enumerable()) &&
6732       (!desc->has_configurable() ||
6733        desc->configurable() == current->configurable()) &&
6734       (!desc->has_value() ||
6735        (current->has_value() && current->value()->SameValue(*desc->value()))) &&
6736       (!desc->has_writable() ||
6737        (current->has_writable() && current->writable() == desc->writable())) &&
6738       (!desc->has_get() ||
6739        (current->has_get() && current->get()->SameValue(*desc->get()))) &&
6740       (!desc->has_set() ||
6741        (current->has_set() && current->set()->SameValue(*desc->set())))) {
6742     return Just(true);
6743   }
6744   // 5. If the [[Configurable]] field of current is false, then
6745   if (!current->configurable()) {
6746     // 5a. Return false, if the [[Configurable]] field of Desc is true.
6747     if (desc->has_configurable() && desc->configurable()) {
6748       RETURN_FAILURE(isolate, should_throw,
6749                      NewTypeError(MessageTemplate::kRedefineDisallowed,
6750                                   it != NULL ? it->GetName() : property_name));
6751     }
6752     // 5b. Return false, if the [[Enumerable]] field of Desc is present and the
6753     // [[Enumerable]] fields of current and Desc are the Boolean negation of
6754     // each other.
6755     if (desc->has_enumerable() && desc->enumerable() != current->enumerable()) {
6756       RETURN_FAILURE(isolate, should_throw,
6757                      NewTypeError(MessageTemplate::kRedefineDisallowed,
6758                                   it != NULL ? it->GetName() : property_name));
6759     }
6760   }
6761 
6762   bool current_is_data_descriptor =
6763       PropertyDescriptor::IsDataDescriptor(current);
6764   // 6. If IsGenericDescriptor(Desc) is true, no further validation is required.
6765   if (desc_is_generic_descriptor) {
6766     // Nothing to see here.
6767 
6768     // 7. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) have
6769     // different results, then:
6770   } else if (current_is_data_descriptor != desc_is_data_descriptor) {
6771     // 7a. Return false, if the [[Configurable]] field of current is false.
6772     if (!current->configurable()) {
6773       RETURN_FAILURE(isolate, should_throw,
6774                      NewTypeError(MessageTemplate::kRedefineDisallowed,
6775                                   it != NULL ? it->GetName() : property_name));
6776     }
6777     // 7b. If IsDataDescriptor(current) is true, then:
6778     if (current_is_data_descriptor) {
6779       // 7b i. If O is not undefined, convert the property named P of object O
6780       // from a data property to an accessor property. Preserve the existing
6781       // values of the converted property's [[Configurable]] and [[Enumerable]]
6782       // attributes and set the rest of the property's attributes to their
6783       // default values.
6784       // --> Folded into step 10.
6785     } else {
6786       // 7c i. If O is not undefined, convert the property named P of object O
6787       // from an accessor property to a data property. Preserve the existing
6788       // values of the converted property’s [[Configurable]] and [[Enumerable]]
6789       // attributes and set the rest of the property’s attributes to their
6790       // default values.
6791       // --> Folded into step 10.
6792     }
6793 
6794     // 8. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both
6795     // true, then:
6796   } else if (current_is_data_descriptor && desc_is_data_descriptor) {
6797     // 8a. If the [[Configurable]] field of current is false, then:
6798     if (!current->configurable()) {
6799       // 8a i. Return false, if the [[Writable]] field of current is false and
6800       // the [[Writable]] field of Desc is true.
6801       if (!current->writable() && desc->has_writable() && desc->writable()) {
6802         RETURN_FAILURE(
6803             isolate, should_throw,
6804             NewTypeError(MessageTemplate::kRedefineDisallowed,
6805                          it != NULL ? it->GetName() : property_name));
6806       }
6807       // 8a ii. If the [[Writable]] field of current is false, then:
6808       if (!current->writable()) {
6809         // 8a ii 1. Return false, if the [[Value]] field of Desc is present and
6810         // SameValue(Desc.[[Value]], current.[[Value]]) is false.
6811         if (desc->has_value() && !desc->value()->SameValue(*current->value())) {
6812           RETURN_FAILURE(
6813               isolate, should_throw,
6814               NewTypeError(MessageTemplate::kRedefineDisallowed,
6815                            it != NULL ? it->GetName() : property_name));
6816         }
6817       }
6818     }
6819   } else {
6820     // 9. Else IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc)
6821     // are both true,
6822     DCHECK(PropertyDescriptor::IsAccessorDescriptor(current) &&
6823            desc_is_accessor_descriptor);
6824     // 9a. If the [[Configurable]] field of current is false, then:
6825     if (!current->configurable()) {
6826       // 9a i. Return false, if the [[Set]] field of Desc is present and
6827       // SameValue(Desc.[[Set]], current.[[Set]]) is false.
6828       if (desc->has_set() && !desc->set()->SameValue(*current->set())) {
6829         RETURN_FAILURE(
6830             isolate, should_throw,
6831             NewTypeError(MessageTemplate::kRedefineDisallowed,
6832                          it != NULL ? it->GetName() : property_name));
6833       }
6834       // 9a ii. Return false, if the [[Get]] field of Desc is present and
6835       // SameValue(Desc.[[Get]], current.[[Get]]) is false.
6836       if (desc->has_get() && !desc->get()->SameValue(*current->get())) {
6837         RETURN_FAILURE(
6838             isolate, should_throw,
6839             NewTypeError(MessageTemplate::kRedefineDisallowed,
6840                          it != NULL ? it->GetName() : property_name));
6841       }
6842     }
6843   }
6844 
6845   // 10. If O is not undefined, then:
6846   if (it != NULL) {
6847     // 10a. For each field of Desc that is present, set the corresponding
6848     // attribute of the property named P of object O to the value of the field.
6849     PropertyAttributes attrs = NONE;
6850 
6851     if (desc->has_enumerable()) {
6852       attrs = static_cast<PropertyAttributes>(
6853           attrs | (desc->enumerable() ? NONE : DONT_ENUM));
6854     } else {
6855       attrs = static_cast<PropertyAttributes>(
6856           attrs | (current->enumerable() ? NONE : DONT_ENUM));
6857     }
6858     if (desc->has_configurable()) {
6859       attrs = static_cast<PropertyAttributes>(
6860           attrs | (desc->configurable() ? NONE : DONT_DELETE));
6861     } else {
6862       attrs = static_cast<PropertyAttributes>(
6863           attrs | (current->configurable() ? NONE : DONT_DELETE));
6864     }
6865     if (desc_is_data_descriptor ||
6866         (desc_is_generic_descriptor && current_is_data_descriptor)) {
6867       if (desc->has_writable()) {
6868         attrs = static_cast<PropertyAttributes>(
6869             attrs | (desc->writable() ? NONE : READ_ONLY));
6870       } else {
6871         attrs = static_cast<PropertyAttributes>(
6872             attrs | (current->writable() ? NONE : READ_ONLY));
6873       }
6874       Handle<Object> value(
6875           desc->has_value() ? desc->value()
6876                             : current->has_value()
6877                                   ? current->value()
6878                                   : Handle<Object>::cast(
6879                                         isolate->factory()->undefined_value()));
6880       MaybeHandle<Object> result =
6881           JSObject::DefineOwnPropertyIgnoreAttributes(it, value, attrs);
6882       if (result.is_null()) return Nothing<bool>();
6883     } else {
6884       DCHECK(desc_is_accessor_descriptor ||
6885              (desc_is_generic_descriptor &&
6886               PropertyDescriptor::IsAccessorDescriptor(current)));
6887       Handle<Object> getter(
6888           desc->has_get()
6889               ? desc->get()
6890               : current->has_get()
6891                     ? current->get()
6892                     : Handle<Object>::cast(isolate->factory()->null_value()));
6893       Handle<Object> setter(
6894           desc->has_set()
6895               ? desc->set()
6896               : current->has_set()
6897                     ? current->set()
6898                     : Handle<Object>::cast(isolate->factory()->null_value()));
6899       MaybeHandle<Object> result =
6900           JSObject::DefineAccessor(it, getter, setter, attrs);
6901       if (result.is_null()) return Nothing<bool>();
6902     }
6903   }
6904 
6905   // 11. Return true.
6906   return Just(true);
6907 }
6908 
6909 
6910 // static
CreateDataProperty(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)6911 Maybe<bool> JSReceiver::CreateDataProperty(LookupIterator* it,
6912                                            Handle<Object> value,
6913                                            ShouldThrow should_throw) {
6914   DCHECK(!it->check_prototype_chain());
6915   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
6916   Isolate* isolate = receiver->GetIsolate();
6917 
6918   if (receiver->IsJSObject()) {
6919     return JSObject::CreateDataProperty(it, value, should_throw);  // Shortcut.
6920   }
6921 
6922   PropertyDescriptor new_desc;
6923   new_desc.set_value(value);
6924   new_desc.set_writable(true);
6925   new_desc.set_enumerable(true);
6926   new_desc.set_configurable(true);
6927 
6928   return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
6929                                        &new_desc, should_throw);
6930 }
6931 
CreateDataProperty(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)6932 Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it,
6933                                          Handle<Object> value,
6934                                          ShouldThrow should_throw) {
6935   DCHECK(it->GetReceiver()->IsJSObject());
6936   MAYBE_RETURN(JSReceiver::GetPropertyAttributes(it), Nothing<bool>());
6937   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
6938   Isolate* isolate = receiver->GetIsolate();
6939 
6940   if (it->IsFound()) {
6941     Maybe<PropertyAttributes> attributes = GetPropertyAttributes(it);
6942     MAYBE_RETURN(attributes, Nothing<bool>());
6943     if ((attributes.FromJust() & DONT_DELETE) != 0) {
6944       RETURN_FAILURE(
6945           isolate, should_throw,
6946           NewTypeError(MessageTemplate::kRedefineDisallowed, it->GetName()));
6947     }
6948   } else {
6949     if (!JSObject::IsExtensible(Handle<JSObject>::cast(it->GetReceiver()))) {
6950       RETURN_FAILURE(
6951           isolate, should_throw,
6952           NewTypeError(MessageTemplate::kDefineDisallowed, it->GetName()));
6953     }
6954   }
6955 
6956   RETURN_ON_EXCEPTION_VALUE(it->isolate(),
6957                             DefineOwnPropertyIgnoreAttributes(it, value, NONE),
6958                             Nothing<bool>());
6959 
6960   return Just(true);
6961 }
6962 
6963 
6964 // TODO(jkummerow): Consider unification with FastAsArrayLength() in
6965 // accessors.cc.
PropertyKeyToArrayLength(Handle<Object> value,uint32_t * length)6966 bool PropertyKeyToArrayLength(Handle<Object> value, uint32_t* length) {
6967   DCHECK(value->IsNumber() || value->IsName());
6968   if (value->ToArrayLength(length)) return true;
6969   if (value->IsString()) return String::cast(*value)->AsArrayIndex(length);
6970   return false;
6971 }
6972 
6973 
PropertyKeyToArrayIndex(Handle<Object> index_obj,uint32_t * output)6974 bool PropertyKeyToArrayIndex(Handle<Object> index_obj, uint32_t* output) {
6975   return PropertyKeyToArrayLength(index_obj, output) && *output != kMaxUInt32;
6976 }
6977 
6978 
6979 // ES6 9.4.2.1
6980 // static
DefineOwnProperty(Isolate * isolate,Handle<JSArray> o,Handle<Object> name,PropertyDescriptor * desc,ShouldThrow should_throw)6981 Maybe<bool> JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o,
6982                                        Handle<Object> name,
6983                                        PropertyDescriptor* desc,
6984                                        ShouldThrow should_throw) {
6985   // 1. Assert: IsPropertyKey(P) is true. ("P" is |name|.)
6986   // 2. If P is "length", then:
6987   // TODO(jkummerow): Check if we need slow string comparison.
6988   if (*name == isolate->heap()->length_string()) {
6989     // 2a. Return ArraySetLength(A, Desc).
6990     return ArraySetLength(isolate, o, desc, should_throw);
6991   }
6992   // 3. Else if P is an array index, then:
6993   uint32_t index = 0;
6994   if (PropertyKeyToArrayIndex(name, &index)) {
6995     // 3a. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
6996     PropertyDescriptor old_len_desc;
6997     Maybe<bool> success = GetOwnPropertyDescriptor(
6998         isolate, o, isolate->factory()->length_string(), &old_len_desc);
6999     // 3b. (Assert)
7000     DCHECK(success.FromJust());
7001     USE(success);
7002     // 3c. Let oldLen be oldLenDesc.[[Value]].
7003     uint32_t old_len = 0;
7004     CHECK(old_len_desc.value()->ToArrayLength(&old_len));
7005     // 3d. Let index be ToUint32(P).
7006     // (Already done above.)
7007     // 3e. (Assert)
7008     // 3f. If index >= oldLen and oldLenDesc.[[Writable]] is false,
7009     //     return false.
7010     if (index >= old_len && old_len_desc.has_writable() &&
7011         !old_len_desc.writable()) {
7012       RETURN_FAILURE(isolate, should_throw,
7013                      NewTypeError(MessageTemplate::kDefineDisallowed, name));
7014     }
7015     // 3g. Let succeeded be OrdinaryDefineOwnProperty(A, P, Desc).
7016     Maybe<bool> succeeded =
7017         OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
7018     // 3h. Assert: succeeded is not an abrupt completion.
7019     //     In our case, if should_throw == THROW_ON_ERROR, it can be!
7020     // 3i. If succeeded is false, return false.
7021     if (succeeded.IsNothing() || !succeeded.FromJust()) return succeeded;
7022     // 3j. If index >= oldLen, then:
7023     if (index >= old_len) {
7024       // 3j i. Set oldLenDesc.[[Value]] to index + 1.
7025       old_len_desc.set_value(isolate->factory()->NewNumberFromUint(index + 1));
7026       // 3j ii. Let succeeded be
7027       //        OrdinaryDefineOwnProperty(A, "length", oldLenDesc).
7028       succeeded = OrdinaryDefineOwnProperty(isolate, o,
7029                                             isolate->factory()->length_string(),
7030                                             &old_len_desc, should_throw);
7031       // 3j iii. Assert: succeeded is true.
7032       DCHECK(succeeded.FromJust());
7033       USE(succeeded);
7034     }
7035     // 3k. Return true.
7036     return Just(true);
7037   }
7038 
7039   // 4. Return OrdinaryDefineOwnProperty(A, P, Desc).
7040   return OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
7041 }
7042 
7043 
7044 // Part of ES6 9.4.2.4 ArraySetLength.
7045 // static
AnythingToArrayLength(Isolate * isolate,Handle<Object> length_object,uint32_t * output)7046 bool JSArray::AnythingToArrayLength(Isolate* isolate,
7047                                     Handle<Object> length_object,
7048                                     uint32_t* output) {
7049   // Fast path: check numbers and strings that can be converted directly
7050   // and unobservably.
7051   if (length_object->ToArrayLength(output)) return true;
7052   if (length_object->IsString() &&
7053       Handle<String>::cast(length_object)->AsArrayIndex(output)) {
7054     return true;
7055   }
7056   // Slow path: follow steps in ES6 9.4.2.4 "ArraySetLength".
7057   // 3. Let newLen be ToUint32(Desc.[[Value]]).
7058   Handle<Object> uint32_v;
7059   if (!Object::ToUint32(isolate, length_object).ToHandle(&uint32_v)) {
7060     // 4. ReturnIfAbrupt(newLen).
7061     return false;
7062   }
7063   // 5. Let numberLen be ToNumber(Desc.[[Value]]).
7064   Handle<Object> number_v;
7065   if (!Object::ToNumber(length_object).ToHandle(&number_v)) {
7066     // 6. ReturnIfAbrupt(newLen).
7067     return false;
7068   }
7069   // 7. If newLen != numberLen, throw a RangeError exception.
7070   if (uint32_v->Number() != number_v->Number()) {
7071     Handle<Object> exception =
7072         isolate->factory()->NewRangeError(MessageTemplate::kInvalidArrayLength);
7073     isolate->Throw(*exception);
7074     return false;
7075   }
7076   CHECK(uint32_v->ToArrayLength(output));
7077   return true;
7078 }
7079 
7080 
7081 // ES6 9.4.2.4
7082 // static
ArraySetLength(Isolate * isolate,Handle<JSArray> a,PropertyDescriptor * desc,ShouldThrow should_throw)7083 Maybe<bool> JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a,
7084                                     PropertyDescriptor* desc,
7085                                     ShouldThrow should_throw) {
7086   // 1. If the [[Value]] field of Desc is absent, then
7087   if (!desc->has_value()) {
7088     // 1a. Return OrdinaryDefineOwnProperty(A, "length", Desc).
7089     return OrdinaryDefineOwnProperty(
7090         isolate, a, isolate->factory()->length_string(), desc, should_throw);
7091   }
7092   // 2. Let newLenDesc be a copy of Desc.
7093   // (Actual copying is not necessary.)
7094   PropertyDescriptor* new_len_desc = desc;
7095   // 3. - 7. Convert Desc.[[Value]] to newLen.
7096   uint32_t new_len = 0;
7097   if (!AnythingToArrayLength(isolate, desc->value(), &new_len)) {
7098     DCHECK(isolate->has_pending_exception());
7099     return Nothing<bool>();
7100   }
7101   // 8. Set newLenDesc.[[Value]] to newLen.
7102   // (Done below, if needed.)
7103   // 9. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
7104   PropertyDescriptor old_len_desc;
7105   Maybe<bool> success = GetOwnPropertyDescriptor(
7106       isolate, a, isolate->factory()->length_string(), &old_len_desc);
7107   // 10. (Assert)
7108   DCHECK(success.FromJust());
7109   USE(success);
7110   // 11. Let oldLen be oldLenDesc.[[Value]].
7111   uint32_t old_len = 0;
7112   CHECK(old_len_desc.value()->ToArrayLength(&old_len));
7113   // 12. If newLen >= oldLen, then
7114   if (new_len >= old_len) {
7115     // 8. Set newLenDesc.[[Value]] to newLen.
7116     // 12a. Return OrdinaryDefineOwnProperty(A, "length", newLenDesc).
7117     new_len_desc->set_value(isolate->factory()->NewNumberFromUint(new_len));
7118     return OrdinaryDefineOwnProperty(isolate, a,
7119                                      isolate->factory()->length_string(),
7120                                      new_len_desc, should_throw);
7121   }
7122   // 13. If oldLenDesc.[[Writable]] is false, return false.
7123   if (!old_len_desc.writable()) {
7124     RETURN_FAILURE(isolate, should_throw,
7125                    NewTypeError(MessageTemplate::kRedefineDisallowed,
7126                                 isolate->factory()->length_string()));
7127   }
7128   // 14. If newLenDesc.[[Writable]] is absent or has the value true,
7129   // let newWritable be true.
7130   bool new_writable = false;
7131   if (!new_len_desc->has_writable() || new_len_desc->writable()) {
7132     new_writable = true;
7133   } else {
7134     // 15. Else,
7135     // 15a. Need to defer setting the [[Writable]] attribute to false in case
7136     //      any elements cannot be deleted.
7137     // 15b. Let newWritable be false. (It's initialized as "false" anyway.)
7138     // 15c. Set newLenDesc.[[Writable]] to true.
7139     // (Not needed.)
7140   }
7141   // Most of steps 16 through 19 is implemented by JSArray::SetLength.
7142   JSArray::SetLength(a, new_len);
7143   // Steps 19d-ii, 20.
7144   if (!new_writable) {
7145     PropertyDescriptor readonly;
7146     readonly.set_writable(false);
7147     Maybe<bool> success = OrdinaryDefineOwnProperty(
7148         isolate, a, isolate->factory()->length_string(), &readonly,
7149         should_throw);
7150     DCHECK(success.FromJust());
7151     USE(success);
7152   }
7153   uint32_t actual_new_len = 0;
7154   CHECK(a->length()->ToArrayLength(&actual_new_len));
7155   // Steps 19d-v, 21. Return false if there were non-deletable elements.
7156   bool result = actual_new_len == new_len;
7157   if (!result) {
7158     RETURN_FAILURE(
7159         isolate, should_throw,
7160         NewTypeError(MessageTemplate::kStrictDeleteProperty,
7161                      isolate->factory()->NewNumberFromUint(actual_new_len - 1),
7162                      a));
7163   }
7164   return Just(result);
7165 }
7166 
7167 
7168 // ES6 9.5.6
7169 // static
DefineOwnProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Object> key,PropertyDescriptor * desc,ShouldThrow should_throw)7170 Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy,
7171                                        Handle<Object> key,
7172                                        PropertyDescriptor* desc,
7173                                        ShouldThrow should_throw) {
7174   STACK_CHECK(isolate, Nothing<bool>());
7175   if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) {
7176     return SetPrivateProperty(isolate, proxy, Handle<Symbol>::cast(key), desc,
7177                               should_throw);
7178   }
7179   Handle<String> trap_name = isolate->factory()->defineProperty_string();
7180   // 1. Assert: IsPropertyKey(P) is true.
7181   DCHECK(key->IsName() || key->IsNumber());
7182   // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
7183   Handle<Object> handler(proxy->handler(), isolate);
7184   // 3. If handler is null, throw a TypeError exception.
7185   // 4. Assert: Type(handler) is Object.
7186   if (proxy->IsRevoked()) {
7187     isolate->Throw(*isolate->factory()->NewTypeError(
7188         MessageTemplate::kProxyRevoked, trap_name));
7189     return Nothing<bool>();
7190   }
7191   // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
7192   Handle<JSReceiver> target(proxy->target(), isolate);
7193   // 6. Let trap be ? GetMethod(handler, "defineProperty").
7194   Handle<Object> trap;
7195   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7196       isolate, trap,
7197       Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
7198       Nothing<bool>());
7199   // 7. If trap is undefined, then:
7200   if (trap->IsUndefined(isolate)) {
7201     // 7a. Return target.[[DefineOwnProperty]](P, Desc).
7202     return JSReceiver::DefineOwnProperty(isolate, target, key, desc,
7203                                          should_throw);
7204   }
7205   // 8. Let descObj be FromPropertyDescriptor(Desc).
7206   Handle<Object> desc_obj = desc->ToObject(isolate);
7207   // 9. Let booleanTrapResult be
7208   //    ToBoolean(? Call(trap, handler, «target, P, descObj»)).
7209   Handle<Name> property_name =
7210       key->IsName()
7211           ? Handle<Name>::cast(key)
7212           : Handle<Name>::cast(isolate->factory()->NumberToString(key));
7213   // Do not leak private property names.
7214   DCHECK(!property_name->IsPrivate());
7215   Handle<Object> trap_result_obj;
7216   Handle<Object> args[] = {target, property_name, desc_obj};
7217   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7218       isolate, trap_result_obj,
7219       Execution::Call(isolate, trap, handler, arraysize(args), args),
7220       Nothing<bool>());
7221   // 10. If booleanTrapResult is false, return false.
7222   if (!trap_result_obj->BooleanValue()) {
7223     RETURN_FAILURE(isolate, should_throw,
7224                    NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
7225                                 trap_name, property_name));
7226   }
7227   // 11. Let targetDesc be ? target.[[GetOwnProperty]](P).
7228   PropertyDescriptor target_desc;
7229   Maybe<bool> target_found =
7230       JSReceiver::GetOwnPropertyDescriptor(isolate, target, key, &target_desc);
7231   MAYBE_RETURN(target_found, Nothing<bool>());
7232   // 12. Let extensibleTarget be ? IsExtensible(target).
7233   Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
7234   MAYBE_RETURN(maybe_extensible, Nothing<bool>());
7235   bool extensible_target = maybe_extensible.FromJust();
7236   // 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]]
7237   //     is false, then:
7238   // 13a. Let settingConfigFalse be true.
7239   // 14. Else let settingConfigFalse be false.
7240   bool setting_config_false = desc->has_configurable() && !desc->configurable();
7241   // 15. If targetDesc is undefined, then
7242   if (!target_found.FromJust()) {
7243     // 15a. If extensibleTarget is false, throw a TypeError exception.
7244     if (!extensible_target) {
7245       isolate->Throw(*isolate->factory()->NewTypeError(
7246           MessageTemplate::kProxyDefinePropertyNonExtensible, property_name));
7247       return Nothing<bool>();
7248     }
7249     // 15b. If settingConfigFalse is true, throw a TypeError exception.
7250     if (setting_config_false) {
7251       isolate->Throw(*isolate->factory()->NewTypeError(
7252           MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
7253       return Nothing<bool>();
7254     }
7255   } else {
7256     // 16. Else targetDesc is not undefined,
7257     // 16a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc,
7258     //      targetDesc) is false, throw a TypeError exception.
7259     Maybe<bool> valid =
7260         IsCompatiblePropertyDescriptor(isolate, extensible_target, desc,
7261                                        &target_desc, property_name, DONT_THROW);
7262     MAYBE_RETURN(valid, Nothing<bool>());
7263     if (!valid.FromJust()) {
7264       isolate->Throw(*isolate->factory()->NewTypeError(
7265           MessageTemplate::kProxyDefinePropertyIncompatible, property_name));
7266       return Nothing<bool>();
7267     }
7268     // 16b. If settingConfigFalse is true and targetDesc.[[Configurable]] is
7269     //      true, throw a TypeError exception.
7270     if (setting_config_false && target_desc.configurable()) {
7271       isolate->Throw(*isolate->factory()->NewTypeError(
7272           MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
7273       return Nothing<bool>();
7274     }
7275   }
7276   // 17. Return true.
7277   return Just(true);
7278 }
7279 
7280 
7281 // static
SetPrivateProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Symbol> private_name,PropertyDescriptor * desc,ShouldThrow should_throw)7282 Maybe<bool> JSProxy::SetPrivateProperty(Isolate* isolate, Handle<JSProxy> proxy,
7283                                         Handle<Symbol> private_name,
7284                                         PropertyDescriptor* desc,
7285                                         ShouldThrow should_throw) {
7286   // Despite the generic name, this can only add private data properties.
7287   if (!PropertyDescriptor::IsDataDescriptor(desc) ||
7288       desc->ToAttributes() != DONT_ENUM) {
7289     RETURN_FAILURE(isolate, should_throw,
7290                    NewTypeError(MessageTemplate::kProxyPrivate));
7291   }
7292   DCHECK(proxy->map()->is_dictionary_map());
7293   Handle<Object> value =
7294       desc->has_value()
7295           ? desc->value()
7296           : Handle<Object>::cast(isolate->factory()->undefined_value());
7297 
7298   LookupIterator it(proxy, private_name, proxy);
7299 
7300   if (it.IsFound()) {
7301     DCHECK_EQ(LookupIterator::DATA, it.state());
7302     DCHECK_EQ(DONT_ENUM, it.property_attributes());
7303     it.WriteDataValue(value);
7304     return Just(true);
7305   }
7306 
7307   Handle<NameDictionary> dict(proxy->property_dictionary());
7308   PropertyDetails details(DONT_ENUM, DATA, 0, PropertyCellType::kNoCell);
7309   Handle<NameDictionary> result =
7310       NameDictionary::Add(dict, private_name, value, details);
7311   if (!dict.is_identical_to(result)) proxy->set_properties(*result);
7312   return Just(true);
7313 }
7314 
7315 
7316 // static
GetOwnPropertyDescriptor(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> key,PropertyDescriptor * desc)7317 Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate,
7318                                                  Handle<JSReceiver> object,
7319                                                  Handle<Object> key,
7320                                                  PropertyDescriptor* desc) {
7321   bool success = false;
7322   DCHECK(key->IsName() || key->IsNumber());  // |key| is a PropertyKey...
7323   LookupIterator it = LookupIterator::PropertyOrElement(
7324       isolate, object, key, &success, LookupIterator::OWN);
7325   DCHECK(success);  // ...so creating a LookupIterator can't fail.
7326   return GetOwnPropertyDescriptor(&it, desc);
7327 }
7328 
7329 namespace {
7330 
GetPropertyDescriptorWithInterceptor(LookupIterator * it,PropertyDescriptor * desc)7331 Maybe<bool> GetPropertyDescriptorWithInterceptor(LookupIterator* it,
7332                                                  PropertyDescriptor* desc) {
7333   if (it->state() == LookupIterator::INTERCEPTOR) {
7334     Isolate* isolate = it->isolate();
7335     Handle<InterceptorInfo> interceptor = it->GetInterceptor();
7336     if (!interceptor->descriptor()->IsUndefined(isolate)) {
7337       Handle<Object> result;
7338       Handle<JSObject> holder = it->GetHolder<JSObject>();
7339 
7340       Handle<Object> receiver = it->GetReceiver();
7341       if (!receiver->IsJSReceiver()) {
7342         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7343             isolate, receiver, Object::ConvertReceiver(isolate, receiver),
7344             Nothing<bool>());
7345       }
7346 
7347       PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
7348                                      *holder, Object::DONT_THROW);
7349       if (it->IsElement()) {
7350         uint32_t index = it->index();
7351         v8::IndexedPropertyDescriptorCallback descriptorCallback =
7352             v8::ToCData<v8::IndexedPropertyDescriptorCallback>(
7353                 interceptor->descriptor());
7354 
7355         result = args.Call(descriptorCallback, index);
7356       } else {
7357         Handle<Name> name = it->name();
7358         DCHECK(!name->IsPrivate());
7359         v8::GenericNamedPropertyDescriptorCallback descriptorCallback =
7360             v8::ToCData<v8::GenericNamedPropertyDescriptorCallback>(
7361                 interceptor->descriptor());
7362         result = args.Call(descriptorCallback, name);
7363       }
7364       if (!result.is_null()) {
7365         // Request successfully intercepted, try to set the property
7366         // descriptor.
7367         Utils::ApiCheck(
7368             PropertyDescriptor::ToPropertyDescriptor(isolate, result, desc),
7369             it->IsElement() ? "v8::IndexedPropertyDescriptorCallback"
7370                             : "v8::NamedPropertyDescriptorCallback",
7371             "Invalid property descriptor.");
7372 
7373         return Just(true);
7374       }
7375     }
7376   }
7377   return Just(false);
7378 }
7379 }  // namespace
7380 
7381 // ES6 9.1.5.1
7382 // Returns true on success, false if the property didn't exist, nothing if
7383 // an exception was thrown.
7384 // static
GetOwnPropertyDescriptor(LookupIterator * it,PropertyDescriptor * desc)7385 Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it,
7386                                                  PropertyDescriptor* desc) {
7387   Isolate* isolate = it->isolate();
7388   // "Virtual" dispatch.
7389   if (it->IsFound() && it->GetHolder<JSReceiver>()->IsJSProxy()) {
7390     return JSProxy::GetOwnPropertyDescriptor(isolate, it->GetHolder<JSProxy>(),
7391                                              it->GetName(), desc);
7392   }
7393 
7394   Maybe<bool> intercepted = GetPropertyDescriptorWithInterceptor(it, desc);
7395   MAYBE_RETURN(intercepted, Nothing<bool>());
7396   if (intercepted.FromJust()) {
7397     return Just(true);
7398   }
7399 
7400   // Request was not intercepted, continue as normal.
7401   // 1. (Assert)
7402   // 2. If O does not have an own property with key P, return undefined.
7403   Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(it);
7404   MAYBE_RETURN(maybe, Nothing<bool>());
7405   PropertyAttributes attrs = maybe.FromJust();
7406   if (attrs == ABSENT) return Just(false);
7407   DCHECK(!isolate->has_pending_exception());
7408 
7409   // 3. Let D be a newly created Property Descriptor with no fields.
7410   DCHECK(desc->is_empty());
7411   // 4. Let X be O's own property whose key is P.
7412   // 5. If X is a data property, then
7413   bool is_accessor_pair = it->state() == LookupIterator::ACCESSOR &&
7414                           it->GetAccessors()->IsAccessorPair();
7415   if (!is_accessor_pair) {
7416     // 5a. Set D.[[Value]] to the value of X's [[Value]] attribute.
7417     Handle<Object> value;
7418     if (!Object::GetProperty(it).ToHandle(&value)) {
7419       DCHECK(isolate->has_pending_exception());
7420       return Nothing<bool>();
7421     }
7422     desc->set_value(value);
7423     // 5b. Set D.[[Writable]] to the value of X's [[Writable]] attribute
7424     desc->set_writable((attrs & READ_ONLY) == 0);
7425   } else {
7426     // 6. Else X is an accessor property, so
7427     Handle<AccessorPair> accessors =
7428         Handle<AccessorPair>::cast(it->GetAccessors());
7429     // 6a. Set D.[[Get]] to the value of X's [[Get]] attribute.
7430     desc->set_get(AccessorPair::GetComponent(accessors, ACCESSOR_GETTER));
7431     // 6b. Set D.[[Set]] to the value of X's [[Set]] attribute.
7432     desc->set_set(AccessorPair::GetComponent(accessors, ACCESSOR_SETTER));
7433   }
7434 
7435   // 7. Set D.[[Enumerable]] to the value of X's [[Enumerable]] attribute.
7436   desc->set_enumerable((attrs & DONT_ENUM) == 0);
7437   // 8. Set D.[[Configurable]] to the value of X's [[Configurable]] attribute.
7438   desc->set_configurable((attrs & DONT_DELETE) == 0);
7439   // 9. Return D.
7440   DCHECK(PropertyDescriptor::IsAccessorDescriptor(desc) !=
7441          PropertyDescriptor::IsDataDescriptor(desc));
7442   return Just(true);
7443 }
7444 
7445 
7446 // ES6 9.5.5
7447 // static
GetOwnPropertyDescriptor(Isolate * isolate,Handle<JSProxy> proxy,Handle<Name> name,PropertyDescriptor * desc)7448 Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate,
7449                                               Handle<JSProxy> proxy,
7450                                               Handle<Name> name,
7451                                               PropertyDescriptor* desc) {
7452   DCHECK(!name->IsPrivate());
7453   STACK_CHECK(isolate, Nothing<bool>());
7454 
7455   Handle<String> trap_name =
7456       isolate->factory()->getOwnPropertyDescriptor_string();
7457   // 1. (Assert)
7458   // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
7459   Handle<Object> handler(proxy->handler(), isolate);
7460   // 3. If handler is null, throw a TypeError exception.
7461   // 4. Assert: Type(handler) is Object.
7462   if (proxy->IsRevoked()) {
7463     isolate->Throw(*isolate->factory()->NewTypeError(
7464         MessageTemplate::kProxyRevoked, trap_name));
7465     return Nothing<bool>();
7466   }
7467   // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
7468   Handle<JSReceiver> target(proxy->target(), isolate);
7469   // 6. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor").
7470   Handle<Object> trap;
7471   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7472       isolate, trap,
7473       Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
7474       Nothing<bool>());
7475   // 7. If trap is undefined, then
7476   if (trap->IsUndefined(isolate)) {
7477     // 7a. Return target.[[GetOwnProperty]](P).
7478     return JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, desc);
7479   }
7480   // 8. Let trapResultObj be ? Call(trap, handler, «target, P»).
7481   Handle<Object> trap_result_obj;
7482   Handle<Object> args[] = {target, name};
7483   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7484       isolate, trap_result_obj,
7485       Execution::Call(isolate, trap, handler, arraysize(args), args),
7486       Nothing<bool>());
7487   // 9. If Type(trapResultObj) is neither Object nor Undefined, throw a
7488   //    TypeError exception.
7489   if (!trap_result_obj->IsJSReceiver() &&
7490       !trap_result_obj->IsUndefined(isolate)) {
7491     isolate->Throw(*isolate->factory()->NewTypeError(
7492         MessageTemplate::kProxyGetOwnPropertyDescriptorInvalid, name));
7493     return Nothing<bool>();
7494   }
7495   // 10. Let targetDesc be ? target.[[GetOwnProperty]](P).
7496   PropertyDescriptor target_desc;
7497   Maybe<bool> found =
7498       JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
7499   MAYBE_RETURN(found, Nothing<bool>());
7500   // 11. If trapResultObj is undefined, then
7501   if (trap_result_obj->IsUndefined(isolate)) {
7502     // 11a. If targetDesc is undefined, return undefined.
7503     if (!found.FromJust()) return Just(false);
7504     // 11b. If targetDesc.[[Configurable]] is false, throw a TypeError
7505     //      exception.
7506     if (!target_desc.configurable()) {
7507       isolate->Throw(*isolate->factory()->NewTypeError(
7508           MessageTemplate::kProxyGetOwnPropertyDescriptorUndefined, name));
7509       return Nothing<bool>();
7510     }
7511     // 11c. Let extensibleTarget be ? IsExtensible(target).
7512     Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
7513     MAYBE_RETURN(extensible_target, Nothing<bool>());
7514     // 11d. (Assert)
7515     // 11e. If extensibleTarget is false, throw a TypeError exception.
7516     if (!extensible_target.FromJust()) {
7517       isolate->Throw(*isolate->factory()->NewTypeError(
7518           MessageTemplate::kProxyGetOwnPropertyDescriptorNonExtensible, name));
7519       return Nothing<bool>();
7520     }
7521     // 11f. Return undefined.
7522     return Just(false);
7523   }
7524   // 12. Let extensibleTarget be ? IsExtensible(target).
7525   Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
7526   MAYBE_RETURN(extensible_target, Nothing<bool>());
7527   // 13. Let resultDesc be ? ToPropertyDescriptor(trapResultObj).
7528   if (!PropertyDescriptor::ToPropertyDescriptor(isolate, trap_result_obj,
7529                                                 desc)) {
7530     DCHECK(isolate->has_pending_exception());
7531     return Nothing<bool>();
7532   }
7533   // 14. Call CompletePropertyDescriptor(resultDesc).
7534   PropertyDescriptor::CompletePropertyDescriptor(isolate, desc);
7535   // 15. Let valid be IsCompatiblePropertyDescriptor (extensibleTarget,
7536   //     resultDesc, targetDesc).
7537   Maybe<bool> valid =
7538       IsCompatiblePropertyDescriptor(isolate, extensible_target.FromJust(),
7539                                      desc, &target_desc, name, DONT_THROW);
7540   MAYBE_RETURN(valid, Nothing<bool>());
7541   // 16. If valid is false, throw a TypeError exception.
7542   if (!valid.FromJust()) {
7543     isolate->Throw(*isolate->factory()->NewTypeError(
7544         MessageTemplate::kProxyGetOwnPropertyDescriptorIncompatible, name));
7545     return Nothing<bool>();
7546   }
7547   // 17. If resultDesc.[[Configurable]] is false, then
7548   if (!desc->configurable()) {
7549     // 17a. If targetDesc is undefined or targetDesc.[[Configurable]] is true:
7550     if (target_desc.is_empty() || target_desc.configurable()) {
7551       // 17a i. Throw a TypeError exception.
7552       isolate->Throw(*isolate->factory()->NewTypeError(
7553           MessageTemplate::kProxyGetOwnPropertyDescriptorNonConfigurable,
7554           name));
7555       return Nothing<bool>();
7556     }
7557   }
7558   // 18. Return resultDesc.
7559   return Just(true);
7560 }
7561 
7562 
ReferencesObjectFromElements(FixedArray * elements,ElementsKind kind,Object * object)7563 bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
7564                                             ElementsKind kind,
7565                                             Object* object) {
7566   Isolate* isolate = elements->GetIsolate();
7567   if (IsFastObjectElementsKind(kind) || kind == FAST_STRING_WRAPPER_ELEMENTS) {
7568     int length = IsJSArray()
7569         ? Smi::cast(JSArray::cast(this)->length())->value()
7570         : elements->length();
7571     for (int i = 0; i < length; ++i) {
7572       Object* element = elements->get(i);
7573       if (!element->IsTheHole(isolate) && element == object) return true;
7574     }
7575   } else {
7576     DCHECK(kind == DICTIONARY_ELEMENTS || kind == SLOW_STRING_WRAPPER_ELEMENTS);
7577     Object* key =
7578         SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
7579     if (!key->IsUndefined(isolate)) return true;
7580   }
7581   return false;
7582 }
7583 
7584 
7585 // Check whether this object references another object.
ReferencesObject(Object * obj)7586 bool JSObject::ReferencesObject(Object* obj) {
7587   Map* map_of_this = map();
7588   Heap* heap = GetHeap();
7589   DisallowHeapAllocation no_allocation;
7590 
7591   // Is the object the constructor for this object?
7592   if (map_of_this->GetConstructor() == obj) {
7593     return true;
7594   }
7595 
7596   // Is the object the prototype for this object?
7597   if (map_of_this->prototype() == obj) {
7598     return true;
7599   }
7600 
7601   // Check if the object is among the named properties.
7602   Object* key = SlowReverseLookup(obj);
7603   if (!key->IsUndefined(heap->isolate())) {
7604     return true;
7605   }
7606 
7607   // Check if the object is among the indexed properties.
7608   ElementsKind kind = GetElementsKind();
7609   switch (kind) {
7610     // Raw pixels and external arrays do not reference other
7611     // objects.
7612 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                        \
7613     case TYPE##_ELEMENTS:                                                      \
7614       break;
7615 
7616     TYPED_ARRAYS(TYPED_ARRAY_CASE)
7617 #undef TYPED_ARRAY_CASE
7618 
7619     case FAST_DOUBLE_ELEMENTS:
7620     case FAST_HOLEY_DOUBLE_ELEMENTS:
7621       break;
7622     case FAST_SMI_ELEMENTS:
7623     case FAST_HOLEY_SMI_ELEMENTS:
7624       break;
7625     case FAST_ELEMENTS:
7626     case FAST_HOLEY_ELEMENTS:
7627     case DICTIONARY_ELEMENTS:
7628     case FAST_STRING_WRAPPER_ELEMENTS:
7629     case SLOW_STRING_WRAPPER_ELEMENTS: {
7630       FixedArray* elements = FixedArray::cast(this->elements());
7631       if (ReferencesObjectFromElements(elements, kind, obj)) return true;
7632       break;
7633     }
7634     case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
7635     case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
7636       FixedArray* parameter_map = FixedArray::cast(elements());
7637       // Check the mapped parameters.
7638       int length = parameter_map->length();
7639       for (int i = 2; i < length; ++i) {
7640         Object* value = parameter_map->get(i);
7641         if (!value->IsTheHole(heap->isolate()) && value == obj) return true;
7642       }
7643       // Check the arguments.
7644       FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
7645       kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS :
7646           FAST_HOLEY_ELEMENTS;
7647       if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
7648       break;
7649     }
7650     case NO_ELEMENTS:
7651       break;
7652   }
7653 
7654   // For functions check the context.
7655   if (IsJSFunction()) {
7656     // Get the constructor function for arguments array.
7657     Map* arguments_map =
7658         heap->isolate()->context()->native_context()->sloppy_arguments_map();
7659     JSFunction* arguments_function =
7660         JSFunction::cast(arguments_map->GetConstructor());
7661 
7662     // Get the context and don't check if it is the native context.
7663     JSFunction* f = JSFunction::cast(this);
7664     Context* context = f->context();
7665     if (context->IsNativeContext()) {
7666       return false;
7667     }
7668 
7669     // Check the non-special context slots.
7670     for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
7671       // Only check JS objects.
7672       if (context->get(i)->IsJSObject()) {
7673         JSObject* ctxobj = JSObject::cast(context->get(i));
7674         // If it is an arguments array check the content.
7675         if (ctxobj->map()->GetConstructor() == arguments_function) {
7676           if (ctxobj->ReferencesObject(obj)) {
7677             return true;
7678           }
7679         } else if (ctxobj == obj) {
7680           return true;
7681         }
7682       }
7683     }
7684 
7685     // Check the context extension (if any) if it can have references.
7686     if (context->has_extension() && !context->IsCatchContext()) {
7687       // With harmony scoping, a JSFunction may have a script context.
7688       // TODO(mvstanton): walk into the ScopeInfo.
7689       if (context->IsScriptContext()) {
7690         return false;
7691       }
7692 
7693       return context->extension_object()->ReferencesObject(obj);
7694     }
7695   }
7696 
7697   // No references to object.
7698   return false;
7699 }
7700 
7701 
SetIntegrityLevel(Handle<JSReceiver> receiver,IntegrityLevel level,ShouldThrow should_throw)7702 Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver,
7703                                           IntegrityLevel level,
7704                                           ShouldThrow should_throw) {
7705   DCHECK(level == SEALED || level == FROZEN);
7706 
7707   if (receiver->IsJSObject()) {
7708     Handle<JSObject> object = Handle<JSObject>::cast(receiver);
7709     if (!object->HasSloppyArgumentsElements()) {  // Fast path.
7710       if (level == SEALED) {
7711         return JSObject::PreventExtensionsWithTransition<SEALED>(object,
7712                                                                  should_throw);
7713       } else {
7714         return JSObject::PreventExtensionsWithTransition<FROZEN>(object,
7715                                                                  should_throw);
7716       }
7717     }
7718   }
7719 
7720   Isolate* isolate = receiver->GetIsolate();
7721 
7722   MAYBE_RETURN(JSReceiver::PreventExtensions(receiver, should_throw),
7723                Nothing<bool>());
7724 
7725   Handle<FixedArray> keys;
7726   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7727       isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>());
7728 
7729   PropertyDescriptor no_conf;
7730   no_conf.set_configurable(false);
7731 
7732   PropertyDescriptor no_conf_no_write;
7733   no_conf_no_write.set_configurable(false);
7734   no_conf_no_write.set_writable(false);
7735 
7736   if (level == SEALED) {
7737     for (int i = 0; i < keys->length(); ++i) {
7738       Handle<Object> key(keys->get(i), isolate);
7739       MAYBE_RETURN(
7740           DefineOwnProperty(isolate, receiver, key, &no_conf, THROW_ON_ERROR),
7741           Nothing<bool>());
7742     }
7743     return Just(true);
7744   }
7745 
7746   for (int i = 0; i < keys->length(); ++i) {
7747     Handle<Object> key(keys->get(i), isolate);
7748     PropertyDescriptor current_desc;
7749     Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
7750         isolate, receiver, key, &current_desc);
7751     MAYBE_RETURN(owned, Nothing<bool>());
7752     if (owned.FromJust()) {
7753       PropertyDescriptor desc =
7754           PropertyDescriptor::IsAccessorDescriptor(&current_desc)
7755               ? no_conf
7756               : no_conf_no_write;
7757       MAYBE_RETURN(
7758           DefineOwnProperty(isolate, receiver, key, &desc, THROW_ON_ERROR),
7759           Nothing<bool>());
7760     }
7761   }
7762   return Just(true);
7763 }
7764 
7765 
TestIntegrityLevel(Handle<JSReceiver> object,IntegrityLevel level)7766 Maybe<bool> JSReceiver::TestIntegrityLevel(Handle<JSReceiver> object,
7767                                            IntegrityLevel level) {
7768   DCHECK(level == SEALED || level == FROZEN);
7769   Isolate* isolate = object->GetIsolate();
7770 
7771   Maybe<bool> extensible = JSReceiver::IsExtensible(object);
7772   MAYBE_RETURN(extensible, Nothing<bool>());
7773   if (extensible.FromJust()) return Just(false);
7774 
7775   Handle<FixedArray> keys;
7776   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7777       isolate, keys, JSReceiver::OwnPropertyKeys(object), Nothing<bool>());
7778 
7779   for (int i = 0; i < keys->length(); ++i) {
7780     Handle<Object> key(keys->get(i), isolate);
7781     PropertyDescriptor current_desc;
7782     Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
7783         isolate, object, key, &current_desc);
7784     MAYBE_RETURN(owned, Nothing<bool>());
7785     if (owned.FromJust()) {
7786       if (current_desc.configurable()) return Just(false);
7787       if (level == FROZEN &&
7788           PropertyDescriptor::IsDataDescriptor(&current_desc) &&
7789           current_desc.writable()) {
7790         return Just(false);
7791       }
7792     }
7793   }
7794   return Just(true);
7795 }
7796 
7797 
PreventExtensions(Handle<JSReceiver> object,ShouldThrow should_throw)7798 Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object,
7799                                           ShouldThrow should_throw) {
7800   if (object->IsJSProxy()) {
7801     return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object),
7802                                       should_throw);
7803   }
7804   DCHECK(object->IsJSObject());
7805   return JSObject::PreventExtensions(Handle<JSObject>::cast(object),
7806                                      should_throw);
7807 }
7808 
7809 
PreventExtensions(Handle<JSProxy> proxy,ShouldThrow should_throw)7810 Maybe<bool> JSProxy::PreventExtensions(Handle<JSProxy> proxy,
7811                                        ShouldThrow should_throw) {
7812   Isolate* isolate = proxy->GetIsolate();
7813   STACK_CHECK(isolate, Nothing<bool>());
7814   Factory* factory = isolate->factory();
7815   Handle<String> trap_name = factory->preventExtensions_string();
7816 
7817   if (proxy->IsRevoked()) {
7818     isolate->Throw(
7819         *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
7820     return Nothing<bool>();
7821   }
7822   Handle<JSReceiver> target(proxy->target(), isolate);
7823   Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
7824 
7825   Handle<Object> trap;
7826   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7827       isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
7828   if (trap->IsUndefined(isolate)) {
7829     return JSReceiver::PreventExtensions(target, should_throw);
7830   }
7831 
7832   Handle<Object> trap_result;
7833   Handle<Object> args[] = {target};
7834   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7835       isolate, trap_result,
7836       Execution::Call(isolate, trap, handler, arraysize(args), args),
7837       Nothing<bool>());
7838   if (!trap_result->BooleanValue()) {
7839     RETURN_FAILURE(
7840         isolate, should_throw,
7841         NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
7842   }
7843 
7844   // Enforce the invariant.
7845   Maybe<bool> target_result = JSReceiver::IsExtensible(target);
7846   MAYBE_RETURN(target_result, Nothing<bool>());
7847   if (target_result.FromJust()) {
7848     isolate->Throw(*factory->NewTypeError(
7849         MessageTemplate::kProxyPreventExtensionsExtensible));
7850     return Nothing<bool>();
7851   }
7852   return Just(true);
7853 }
7854 
7855 
PreventExtensions(Handle<JSObject> object,ShouldThrow should_throw)7856 Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object,
7857                                         ShouldThrow should_throw) {
7858   Isolate* isolate = object->GetIsolate();
7859 
7860   if (!object->HasSloppyArgumentsElements()) {
7861     return PreventExtensionsWithTransition<NONE>(object, should_throw);
7862   }
7863 
7864   if (object->IsAccessCheckNeeded() &&
7865       !isolate->MayAccess(handle(isolate->context()), object)) {
7866     isolate->ReportFailedAccessCheck(object);
7867     RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
7868     RETURN_FAILURE(isolate, should_throw,
7869                    NewTypeError(MessageTemplate::kNoAccess));
7870   }
7871 
7872   if (!object->map()->is_extensible()) return Just(true);
7873 
7874   if (object->IsJSGlobalProxy()) {
7875     PrototypeIterator iter(isolate, object);
7876     if (iter.IsAtEnd()) return Just(true);
7877     DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
7878     return PreventExtensions(PrototypeIterator::GetCurrent<JSObject>(iter),
7879                              should_throw);
7880   }
7881 
7882   if (!object->HasFixedTypedArrayElements()) {
7883     // If there are fast elements we normalize.
7884     Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
7885     DCHECK(object->HasDictionaryElements() ||
7886            object->HasSlowArgumentsElements());
7887 
7888     // Make sure that we never go back to fast case.
7889     object->RequireSlowElements(*dictionary);
7890   }
7891 
7892   // Do a map transition, other objects with this map may still
7893   // be extensible.
7894   // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
7895   Handle<Map> new_map = Map::Copy(handle(object->map()), "PreventExtensions");
7896 
7897   new_map->set_is_extensible(false);
7898   JSObject::MigrateToMap(object, new_map);
7899   DCHECK(!object->map()->is_extensible());
7900 
7901   return Just(true);
7902 }
7903 
7904 
IsExtensible(Handle<JSReceiver> object)7905 Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) {
7906   if (object->IsJSProxy()) {
7907     return JSProxy::IsExtensible(Handle<JSProxy>::cast(object));
7908   }
7909   return Just(JSObject::IsExtensible(Handle<JSObject>::cast(object)));
7910 }
7911 
7912 
IsExtensible(Handle<JSProxy> proxy)7913 Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) {
7914   Isolate* isolate = proxy->GetIsolate();
7915   STACK_CHECK(isolate, Nothing<bool>());
7916   Factory* factory = isolate->factory();
7917   Handle<String> trap_name = factory->isExtensible_string();
7918 
7919   if (proxy->IsRevoked()) {
7920     isolate->Throw(
7921         *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
7922     return Nothing<bool>();
7923   }
7924   Handle<JSReceiver> target(proxy->target(), isolate);
7925   Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
7926 
7927   Handle<Object> trap;
7928   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7929       isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
7930   if (trap->IsUndefined(isolate)) {
7931     return JSReceiver::IsExtensible(target);
7932   }
7933 
7934   Handle<Object> trap_result;
7935   Handle<Object> args[] = {target};
7936   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7937       isolate, trap_result,
7938       Execution::Call(isolate, trap, handler, arraysize(args), args),
7939       Nothing<bool>());
7940 
7941   // Enforce the invariant.
7942   Maybe<bool> target_result = JSReceiver::IsExtensible(target);
7943   MAYBE_RETURN(target_result, Nothing<bool>());
7944   if (target_result.FromJust() != trap_result->BooleanValue()) {
7945     isolate->Throw(
7946         *factory->NewTypeError(MessageTemplate::kProxyIsExtensibleInconsistent,
7947                                factory->ToBoolean(target_result.FromJust())));
7948     return Nothing<bool>();
7949   }
7950   return target_result;
7951 }
7952 
7953 
IsExtensible(Handle<JSObject> object)7954 bool JSObject::IsExtensible(Handle<JSObject> object) {
7955   Isolate* isolate = object->GetIsolate();
7956   if (object->IsAccessCheckNeeded() &&
7957       !isolate->MayAccess(handle(isolate->context()), object)) {
7958     return true;
7959   }
7960   if (object->IsJSGlobalProxy()) {
7961     PrototypeIterator iter(isolate, *object);
7962     if (iter.IsAtEnd()) return false;
7963     DCHECK(iter.GetCurrent()->IsJSGlobalObject());
7964     return iter.GetCurrent<JSObject>()->map()->is_extensible();
7965   }
7966   return object->map()->is_extensible();
7967 }
7968 
7969 namespace {
7970 
7971 template <typename Dictionary>
DictionaryDetailsAtPut(Isolate * isolate,Handle<Dictionary> dictionary,int entry,PropertyDetails details)7972 void DictionaryDetailsAtPut(Isolate* isolate, Handle<Dictionary> dictionary,
7973                             int entry, PropertyDetails details) {
7974   dictionary->DetailsAtPut(entry, details);
7975 }
7976 
7977 template <>
DictionaryDetailsAtPut(Isolate * isolate,Handle<GlobalDictionary> dictionary,int entry,PropertyDetails details)7978 void DictionaryDetailsAtPut<GlobalDictionary>(
7979     Isolate* isolate, Handle<GlobalDictionary> dictionary, int entry,
7980     PropertyDetails details) {
7981   Object* value = dictionary->ValueAt(entry);
7982   DCHECK(value->IsPropertyCell());
7983   value = PropertyCell::cast(value)->value();
7984   if (value->IsTheHole(isolate)) return;
7985   PropertyCell::PrepareForValue(dictionary, entry, handle(value, isolate),
7986                                 details);
7987 }
7988 
7989 template <typename Dictionary>
ApplyAttributesToDictionary(Isolate * isolate,Handle<Dictionary> dictionary,const PropertyAttributes attributes)7990 void ApplyAttributesToDictionary(Isolate* isolate,
7991                                  Handle<Dictionary> dictionary,
7992                                  const PropertyAttributes attributes) {
7993   int capacity = dictionary->Capacity();
7994   for (int i = 0; i < capacity; i++) {
7995     Object* k = dictionary->KeyAt(i);
7996     if (dictionary->IsKey(isolate, k) &&
7997         !(k->IsSymbol() && Symbol::cast(k)->is_private())) {
7998       PropertyDetails details = dictionary->DetailsAt(i);
7999       int attrs = attributes;
8000       // READ_ONLY is an invalid attribute for JS setters/getters.
8001       if ((attributes & READ_ONLY) && details.type() == ACCESSOR_CONSTANT) {
8002         Object* v = dictionary->ValueAt(i);
8003         if (v->IsPropertyCell()) v = PropertyCell::cast(v)->value();
8004         if (v->IsAccessorPair()) attrs &= ~READ_ONLY;
8005       }
8006       details = details.CopyAddAttributes(
8007           static_cast<PropertyAttributes>(attrs));
8008       DictionaryDetailsAtPut<Dictionary>(isolate, dictionary, i, details);
8009     }
8010   }
8011 }
8012 
8013 }  // namespace
8014 
8015 template <PropertyAttributes attrs>
PreventExtensionsWithTransition(Handle<JSObject> object,ShouldThrow should_throw)8016 Maybe<bool> JSObject::PreventExtensionsWithTransition(
8017     Handle<JSObject> object, ShouldThrow should_throw) {
8018   STATIC_ASSERT(attrs == NONE || attrs == SEALED || attrs == FROZEN);
8019 
8020   // Sealing/freezing sloppy arguments should be handled elsewhere.
8021   DCHECK(!object->HasSloppyArgumentsElements());
8022 
8023   Isolate* isolate = object->GetIsolate();
8024   if (object->IsAccessCheckNeeded() &&
8025       !isolate->MayAccess(handle(isolate->context()), object)) {
8026     isolate->ReportFailedAccessCheck(object);
8027     RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
8028     RETURN_FAILURE(isolate, should_throw,
8029                    NewTypeError(MessageTemplate::kNoAccess));
8030   }
8031 
8032   if (attrs == NONE && !object->map()->is_extensible()) return Just(true);
8033 
8034   if (object->IsJSGlobalProxy()) {
8035     PrototypeIterator iter(isolate, object);
8036     if (iter.IsAtEnd()) return Just(true);
8037     DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
8038     return PreventExtensionsWithTransition<attrs>(
8039         PrototypeIterator::GetCurrent<JSObject>(iter), should_throw);
8040   }
8041 
8042   Handle<SeededNumberDictionary> new_element_dictionary;
8043   if (!object->HasFixedTypedArrayElements() &&
8044       !object->HasDictionaryElements() &&
8045       !object->HasSlowStringWrapperElements()) {
8046     int length =
8047         object->IsJSArray()
8048             ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
8049             : object->elements()->length();
8050     new_element_dictionary =
8051         length == 0 ? isolate->factory()->empty_slow_element_dictionary()
8052                     : object->GetElementsAccessor()->Normalize(object);
8053   }
8054 
8055   Handle<Symbol> transition_marker;
8056   if (attrs == NONE) {
8057     transition_marker = isolate->factory()->nonextensible_symbol();
8058   } else if (attrs == SEALED) {
8059     transition_marker = isolate->factory()->sealed_symbol();
8060   } else {
8061     DCHECK(attrs == FROZEN);
8062     transition_marker = isolate->factory()->frozen_symbol();
8063   }
8064 
8065   Handle<Map> old_map(object->map(), isolate);
8066   Map* transition =
8067       TransitionArray::SearchSpecial(*old_map, *transition_marker);
8068   if (transition != NULL) {
8069     Handle<Map> transition_map(transition, isolate);
8070     DCHECK(transition_map->has_dictionary_elements() ||
8071            transition_map->has_fixed_typed_array_elements() ||
8072            transition_map->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
8073     DCHECK(!transition_map->is_extensible());
8074     JSObject::MigrateToMap(object, transition_map);
8075   } else if (TransitionArray::CanHaveMoreTransitions(old_map)) {
8076     // Create a new descriptor array with the appropriate property attributes
8077     Handle<Map> new_map = Map::CopyForPreventExtensions(
8078         old_map, attrs, transition_marker, "CopyForPreventExtensions");
8079     JSObject::MigrateToMap(object, new_map);
8080   } else {
8081     DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map());
8082     // Slow path: need to normalize properties for safety
8083     NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0,
8084                         "SlowPreventExtensions");
8085 
8086     // Create a new map, since other objects with this map may be extensible.
8087     // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
8088     Handle<Map> new_map =
8089         Map::Copy(handle(object->map()), "SlowCopyForPreventExtensions");
8090     new_map->set_is_extensible(false);
8091     if (!new_element_dictionary.is_null()) {
8092       ElementsKind new_kind =
8093           IsStringWrapperElementsKind(old_map->elements_kind())
8094               ? SLOW_STRING_WRAPPER_ELEMENTS
8095               : DICTIONARY_ELEMENTS;
8096       new_map->set_elements_kind(new_kind);
8097     }
8098     JSObject::MigrateToMap(object, new_map);
8099 
8100     if (attrs != NONE) {
8101       if (object->IsJSGlobalObject()) {
8102         Handle<GlobalDictionary> dictionary(object->global_dictionary(),
8103                                             isolate);
8104         ApplyAttributesToDictionary(isolate, dictionary, attrs);
8105       } else {
8106         Handle<NameDictionary> dictionary(object->property_dictionary(),
8107                                           isolate);
8108         ApplyAttributesToDictionary(isolate, dictionary, attrs);
8109       }
8110     }
8111   }
8112 
8113   // Both seal and preventExtensions always go through without modifications to
8114   // typed array elements. Freeze works only if there are no actual elements.
8115   if (object->HasFixedTypedArrayElements()) {
8116     if (attrs == FROZEN &&
8117         JSArrayBufferView::cast(*object)->byte_length()->Number() > 0) {
8118       isolate->Throw(*isolate->factory()->NewTypeError(
8119           MessageTemplate::kCannotFreezeArrayBufferView));
8120       return Nothing<bool>();
8121     }
8122     return Just(true);
8123   }
8124 
8125   DCHECK(object->map()->has_dictionary_elements() ||
8126          object->map()->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
8127   if (!new_element_dictionary.is_null()) {
8128     object->set_elements(*new_element_dictionary);
8129   }
8130 
8131   if (object->elements() != isolate->heap()->empty_slow_element_dictionary()) {
8132     Handle<SeededNumberDictionary> dictionary(object->element_dictionary(),
8133                                               isolate);
8134     // Make sure we never go back to the fast case
8135     object->RequireSlowElements(*dictionary);
8136     if (attrs != NONE) {
8137       ApplyAttributesToDictionary(isolate, dictionary, attrs);
8138     }
8139   }
8140 
8141   return Just(true);
8142 }
8143 
8144 
FastPropertyAt(Handle<JSObject> object,Representation representation,FieldIndex index)8145 Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object,
8146                                         Representation representation,
8147                                         FieldIndex index) {
8148   Isolate* isolate = object->GetIsolate();
8149   if (object->IsUnboxedDoubleField(index)) {
8150     double value = object->RawFastDoublePropertyAt(index);
8151     return isolate->factory()->NewHeapNumber(value);
8152   }
8153   Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate);
8154   return Object::WrapForRead(isolate, raw_value, representation);
8155 }
8156 
8157 template <class ContextObject>
8158 class JSObjectWalkVisitor {
8159  public:
JSObjectWalkVisitor(ContextObject * site_context,bool copying,JSObject::DeepCopyHints hints)8160   JSObjectWalkVisitor(ContextObject* site_context, bool copying,
8161                       JSObject::DeepCopyHints hints)
8162     : site_context_(site_context),
8163       copying_(copying),
8164       hints_(hints) {}
8165 
8166   MUST_USE_RESULT MaybeHandle<JSObject> StructureWalk(Handle<JSObject> object);
8167 
8168  protected:
VisitElementOrProperty(Handle<JSObject> object,Handle<JSObject> value)8169   MUST_USE_RESULT inline MaybeHandle<JSObject> VisitElementOrProperty(
8170       Handle<JSObject> object,
8171       Handle<JSObject> value) {
8172     Handle<AllocationSite> current_site = site_context()->EnterNewScope();
8173     MaybeHandle<JSObject> copy_of_value = StructureWalk(value);
8174     site_context()->ExitScope(current_site, value);
8175     return copy_of_value;
8176   }
8177 
site_context()8178   inline ContextObject* site_context() { return site_context_; }
isolate()8179   inline Isolate* isolate() { return site_context()->isolate(); }
8180 
copying() const8181   inline bool copying() const { return copying_; }
8182 
8183  private:
8184   ContextObject* site_context_;
8185   const bool copying_;
8186   const JSObject::DeepCopyHints hints_;
8187 };
8188 
8189 template <class ContextObject>
StructureWalk(Handle<JSObject> object)8190 MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
8191     Handle<JSObject> object) {
8192   Isolate* isolate = this->isolate();
8193   bool copying = this->copying();
8194   bool shallow = hints_ == JSObject::kObjectIsShallow;
8195 
8196   if (!shallow) {
8197     StackLimitCheck check(isolate);
8198 
8199     if (check.HasOverflowed()) {
8200       isolate->StackOverflow();
8201       return MaybeHandle<JSObject>();
8202     }
8203   }
8204 
8205   if (object->map()->is_deprecated()) {
8206     JSObject::MigrateInstance(object);
8207   }
8208 
8209   Handle<JSObject> copy;
8210   if (copying) {
8211     // JSFunction objects are not allowed to be in normal boilerplates at all.
8212     DCHECK(!object->IsJSFunction());
8213     Handle<AllocationSite> site_to_pass;
8214     if (site_context()->ShouldCreateMemento(object)) {
8215       site_to_pass = site_context()->current();
8216     }
8217     copy = isolate->factory()->CopyJSObjectWithAllocationSite(
8218         object, site_to_pass);
8219   } else {
8220     copy = object;
8221   }
8222 
8223   DCHECK(copying || copy.is_identical_to(object));
8224 
8225   ElementsKind kind = copy->GetElementsKind();
8226   if (copying && IsFastSmiOrObjectElementsKind(kind) &&
8227       FixedArray::cast(copy->elements())->map() ==
8228         isolate->heap()->fixed_cow_array_map()) {
8229     isolate->counters()->cow_arrays_created_runtime()->Increment();
8230   }
8231 
8232   if (!shallow) {
8233     HandleScope scope(isolate);
8234 
8235     // Deep copy own properties.
8236     if (copy->HasFastProperties()) {
8237       Handle<DescriptorArray> descriptors(copy->map()->instance_descriptors());
8238       int limit = copy->map()->NumberOfOwnDescriptors();
8239       for (int i = 0; i < limit; i++) {
8240         PropertyDetails details = descriptors->GetDetails(i);
8241         if (details.type() != DATA) continue;
8242         FieldIndex index = FieldIndex::ForDescriptor(copy->map(), i);
8243         if (object->IsUnboxedDoubleField(index)) {
8244           if (copying) {
8245             double value = object->RawFastDoublePropertyAt(index);
8246             copy->RawFastDoublePropertyAtPut(index, value);
8247           }
8248         } else {
8249           Handle<Object> value(object->RawFastPropertyAt(index), isolate);
8250           if (value->IsJSObject()) {
8251             ASSIGN_RETURN_ON_EXCEPTION(
8252                 isolate, value,
8253                 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
8254                 JSObject);
8255             if (copying) {
8256               copy->FastPropertyAtPut(index, *value);
8257             }
8258           } else {
8259             if (copying) {
8260               Representation representation = details.representation();
8261               value = Object::NewStorageFor(isolate, value, representation);
8262               copy->FastPropertyAtPut(index, *value);
8263             }
8264           }
8265         }
8266       }
8267     } else {
8268       // Only deep copy fields from the object literal expression.
8269       // In particular, don't try to copy the length attribute of
8270       // an array.
8271       PropertyFilter filter = static_cast<PropertyFilter>(
8272           ONLY_WRITABLE | ONLY_ENUMERABLE | ONLY_CONFIGURABLE);
8273       KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly, filter);
8274       accumulator.CollectOwnPropertyNames(copy, copy);
8275       Handle<FixedArray> names = accumulator.GetKeys();
8276       for (int i = 0; i < names->length(); i++) {
8277         DCHECK(names->get(i)->IsName());
8278         Handle<Name> name(Name::cast(names->get(i)));
8279         Handle<Object> value =
8280             JSObject::GetProperty(copy, name).ToHandleChecked();
8281         if (value->IsJSObject()) {
8282           Handle<JSObject> result;
8283           ASSIGN_RETURN_ON_EXCEPTION(
8284               isolate, result,
8285               VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
8286               JSObject);
8287           if (copying) {
8288             // Creating object copy for literals. No strict mode needed.
8289             JSObject::SetProperty(copy, name, result, SLOPPY).Assert();
8290           }
8291         }
8292       }
8293     }
8294 
8295     // Deep copy own elements.
8296     switch (kind) {
8297       case FAST_ELEMENTS:
8298       case FAST_HOLEY_ELEMENTS: {
8299         Handle<FixedArray> elements(FixedArray::cast(copy->elements()));
8300         if (elements->map() == isolate->heap()->fixed_cow_array_map()) {
8301 #ifdef DEBUG
8302           for (int i = 0; i < elements->length(); i++) {
8303             DCHECK(!elements->get(i)->IsJSObject());
8304           }
8305 #endif
8306         } else {
8307           for (int i = 0; i < elements->length(); i++) {
8308             Handle<Object> value(elements->get(i), isolate);
8309             if (value->IsJSObject()) {
8310               Handle<JSObject> result;
8311               ASSIGN_RETURN_ON_EXCEPTION(
8312                   isolate, result,
8313                   VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
8314                   JSObject);
8315               if (copying) {
8316                 elements->set(i, *result);
8317               }
8318             }
8319           }
8320         }
8321         break;
8322       }
8323       case DICTIONARY_ELEMENTS: {
8324         Handle<SeededNumberDictionary> element_dictionary(
8325             copy->element_dictionary());
8326         int capacity = element_dictionary->Capacity();
8327         for (int i = 0; i < capacity; i++) {
8328           Object* k = element_dictionary->KeyAt(i);
8329           if (element_dictionary->IsKey(isolate, k)) {
8330             Handle<Object> value(element_dictionary->ValueAt(i), isolate);
8331             if (value->IsJSObject()) {
8332               Handle<JSObject> result;
8333               ASSIGN_RETURN_ON_EXCEPTION(
8334                   isolate, result,
8335                   VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
8336                   JSObject);
8337               if (copying) {
8338                 element_dictionary->ValueAtPut(i, *result);
8339               }
8340             }
8341           }
8342         }
8343         break;
8344       }
8345       case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
8346       case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
8347         UNIMPLEMENTED();
8348         break;
8349       case FAST_STRING_WRAPPER_ELEMENTS:
8350       case SLOW_STRING_WRAPPER_ELEMENTS:
8351         UNREACHABLE();
8352         break;
8353 
8354 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                        \
8355       case TYPE##_ELEMENTS:                                                    \
8356 
8357       TYPED_ARRAYS(TYPED_ARRAY_CASE)
8358 #undef TYPED_ARRAY_CASE
8359       // Typed elements cannot be created using an object literal.
8360       UNREACHABLE();
8361       break;
8362 
8363       case FAST_SMI_ELEMENTS:
8364       case FAST_HOLEY_SMI_ELEMENTS:
8365       case FAST_DOUBLE_ELEMENTS:
8366       case FAST_HOLEY_DOUBLE_ELEMENTS:
8367       case NO_ELEMENTS:
8368         // No contained objects, nothing to do.
8369         break;
8370     }
8371   }
8372 
8373   return copy;
8374 }
8375 
8376 
DeepWalk(Handle<JSObject> object,AllocationSiteCreationContext * site_context)8377 MaybeHandle<JSObject> JSObject::DeepWalk(
8378     Handle<JSObject> object,
8379     AllocationSiteCreationContext* site_context) {
8380   JSObjectWalkVisitor<AllocationSiteCreationContext> v(site_context, false,
8381                                                        kNoHints);
8382   MaybeHandle<JSObject> result = v.StructureWalk(object);
8383   Handle<JSObject> for_assert;
8384   DCHECK(!result.ToHandle(&for_assert) || for_assert.is_identical_to(object));
8385   return result;
8386 }
8387 
8388 
DeepCopy(Handle<JSObject> object,AllocationSiteUsageContext * site_context,DeepCopyHints hints)8389 MaybeHandle<JSObject> JSObject::DeepCopy(
8390     Handle<JSObject> object,
8391     AllocationSiteUsageContext* site_context,
8392     DeepCopyHints hints) {
8393   JSObjectWalkVisitor<AllocationSiteUsageContext> v(site_context, true, hints);
8394   MaybeHandle<JSObject> copy = v.StructureWalk(object);
8395   Handle<JSObject> for_assert;
8396   DCHECK(!copy.ToHandle(&for_assert) || !for_assert.is_identical_to(object));
8397   return copy;
8398 }
8399 
8400 // static
ToPrimitive(Handle<JSReceiver> receiver,ToPrimitiveHint hint)8401 MaybeHandle<Object> JSReceiver::ToPrimitive(Handle<JSReceiver> receiver,
8402                                             ToPrimitiveHint hint) {
8403   Isolate* const isolate = receiver->GetIsolate();
8404   Handle<Object> exotic_to_prim;
8405   ASSIGN_RETURN_ON_EXCEPTION(
8406       isolate, exotic_to_prim,
8407       GetMethod(receiver, isolate->factory()->to_primitive_symbol()), Object);
8408   if (!exotic_to_prim->IsUndefined(isolate)) {
8409     Handle<Object> hint_string =
8410         isolate->factory()->ToPrimitiveHintString(hint);
8411     Handle<Object> result;
8412     ASSIGN_RETURN_ON_EXCEPTION(
8413         isolate, result,
8414         Execution::Call(isolate, exotic_to_prim, receiver, 1, &hint_string),
8415         Object);
8416     if (result->IsPrimitive()) return result;
8417     THROW_NEW_ERROR(isolate,
8418                     NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8419                     Object);
8420   }
8421   return OrdinaryToPrimitive(receiver, (hint == ToPrimitiveHint::kString)
8422                                            ? OrdinaryToPrimitiveHint::kString
8423                                            : OrdinaryToPrimitiveHint::kNumber);
8424 }
8425 
8426 
8427 // static
OrdinaryToPrimitive(Handle<JSReceiver> receiver,OrdinaryToPrimitiveHint hint)8428 MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive(
8429     Handle<JSReceiver> receiver, OrdinaryToPrimitiveHint hint) {
8430   Isolate* const isolate = receiver->GetIsolate();
8431   Handle<String> method_names[2];
8432   switch (hint) {
8433     case OrdinaryToPrimitiveHint::kNumber:
8434       method_names[0] = isolate->factory()->valueOf_string();
8435       method_names[1] = isolate->factory()->toString_string();
8436       break;
8437     case OrdinaryToPrimitiveHint::kString:
8438       method_names[0] = isolate->factory()->toString_string();
8439       method_names[1] = isolate->factory()->valueOf_string();
8440       break;
8441   }
8442   for (Handle<String> name : method_names) {
8443     Handle<Object> method;
8444     ASSIGN_RETURN_ON_EXCEPTION(isolate, method,
8445                                JSReceiver::GetProperty(receiver, name), Object);
8446     if (method->IsCallable()) {
8447       Handle<Object> result;
8448       ASSIGN_RETURN_ON_EXCEPTION(
8449           isolate, result, Execution::Call(isolate, method, receiver, 0, NULL),
8450           Object);
8451       if (result->IsPrimitive()) return result;
8452     }
8453   }
8454   THROW_NEW_ERROR(isolate,
8455                   NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8456                   Object);
8457 }
8458 
8459 
8460 // TODO(cbruni/jkummerow): Consider moving this into elements.cc.
HasEnumerableElements()8461 bool JSObject::HasEnumerableElements() {
8462   // TODO(cbruni): cleanup
8463   JSObject* object = this;
8464   switch (object->GetElementsKind()) {
8465     case FAST_SMI_ELEMENTS:
8466     case FAST_ELEMENTS:
8467     case FAST_DOUBLE_ELEMENTS: {
8468       int length = object->IsJSArray()
8469                        ? Smi::cast(JSArray::cast(object)->length())->value()
8470                        : object->elements()->length();
8471       return length > 0;
8472     }
8473     case FAST_HOLEY_SMI_ELEMENTS:
8474     case FAST_HOLEY_ELEMENTS: {
8475       FixedArray* elements = FixedArray::cast(object->elements());
8476       int length = object->IsJSArray()
8477                        ? Smi::cast(JSArray::cast(object)->length())->value()
8478                        : elements->length();
8479       Isolate* isolate = GetIsolate();
8480       for (int i = 0; i < length; i++) {
8481         if (!elements->is_the_hole(isolate, i)) return true;
8482       }
8483       return false;
8484     }
8485     case FAST_HOLEY_DOUBLE_ELEMENTS: {
8486       int length = object->IsJSArray()
8487                        ? Smi::cast(JSArray::cast(object)->length())->value()
8488                        : object->elements()->length();
8489       // Zero-length arrays would use the empty FixedArray...
8490       if (length == 0) return false;
8491       // ...so only cast to FixedDoubleArray otherwise.
8492       FixedDoubleArray* elements = FixedDoubleArray::cast(object->elements());
8493       for (int i = 0; i < length; i++) {
8494         if (!elements->is_the_hole(i)) return true;
8495       }
8496       return false;
8497     }
8498 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
8499     case TYPE##_ELEMENTS:
8500 
8501       TYPED_ARRAYS(TYPED_ARRAY_CASE)
8502 #undef TYPED_ARRAY_CASE
8503       {
8504         int length = object->elements()->length();
8505         return length > 0;
8506       }
8507     case DICTIONARY_ELEMENTS: {
8508       SeededNumberDictionary* elements =
8509           SeededNumberDictionary::cast(object->elements());
8510       return elements->NumberOfElementsFilterAttributes(ONLY_ENUMERABLE) > 0;
8511     }
8512     case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
8513     case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
8514       // We're approximating non-empty arguments objects here.
8515       return true;
8516     case FAST_STRING_WRAPPER_ELEMENTS:
8517     case SLOW_STRING_WRAPPER_ELEMENTS:
8518       if (String::cast(JSValue::cast(object)->value())->length() > 0) {
8519         return true;
8520       }
8521       return object->elements()->length() > 0;
8522     case NO_ELEMENTS:
8523       return false;
8524   }
8525   UNREACHABLE();
8526   return true;
8527 }
8528 
8529 
NumberOfDescribedProperties(DescriptorFlag which,PropertyFilter filter)8530 int Map::NumberOfDescribedProperties(DescriptorFlag which,
8531                                      PropertyFilter filter) {
8532   int result = 0;
8533   DescriptorArray* descs = instance_descriptors();
8534   int limit = which == ALL_DESCRIPTORS
8535       ? descs->number_of_descriptors()
8536       : NumberOfOwnDescriptors();
8537   for (int i = 0; i < limit; i++) {
8538     if ((descs->GetDetails(i).attributes() & filter) == 0 &&
8539         !descs->GetKey(i)->FilterKey(filter)) {
8540       result++;
8541     }
8542   }
8543   return result;
8544 }
8545 
8546 
NextFreePropertyIndex()8547 int Map::NextFreePropertyIndex() {
8548   int free_index = 0;
8549   int number_of_own_descriptors = NumberOfOwnDescriptors();
8550   DescriptorArray* descs = instance_descriptors();
8551   for (int i = 0; i < number_of_own_descriptors; i++) {
8552     PropertyDetails details = descs->GetDetails(i);
8553     if (details.location() == kField) {
8554       int candidate = details.field_index() + details.field_width_in_words();
8555       if (candidate > free_index) free_index = candidate;
8556     }
8557   }
8558   return free_index;
8559 }
8560 
8561 
OnlyHasSimpleProperties()8562 bool Map::OnlyHasSimpleProperties() {
8563   // Wrapped string elements aren't explicitly stored in the elements backing
8564   // store, but are loaded indirectly from the underlying string.
8565   return !IsStringWrapperElementsKind(elements_kind()) &&
8566          instance_type() > LAST_SPECIAL_RECEIVER_TYPE &&
8567          !has_hidden_prototype() && !is_dictionary_map();
8568 }
8569 
FastGetOwnValuesOrEntries(Isolate * isolate,Handle<JSReceiver> receiver,bool get_entries,Handle<FixedArray> * result)8570 MUST_USE_RESULT Maybe<bool> FastGetOwnValuesOrEntries(
8571     Isolate* isolate, Handle<JSReceiver> receiver, bool get_entries,
8572     Handle<FixedArray>* result) {
8573   Handle<Map> map(JSReceiver::cast(*receiver)->map(), isolate);
8574 
8575   if (!map->IsJSObjectMap()) return Just(false);
8576   if (!map->OnlyHasSimpleProperties()) return Just(false);
8577 
8578   Handle<JSObject> object(JSObject::cast(*receiver));
8579 
8580   Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
8581   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
8582   int number_of_own_elements =
8583       object->GetElementsAccessor()->GetCapacity(*object, object->elements());
8584   Handle<FixedArray> values_or_entries = isolate->factory()->NewFixedArray(
8585       number_of_own_descriptors + number_of_own_elements);
8586   int count = 0;
8587 
8588   if (object->elements() != isolate->heap()->empty_fixed_array()) {
8589     MAYBE_RETURN(object->GetElementsAccessor()->CollectValuesOrEntries(
8590                      isolate, object, values_or_entries, get_entries, &count,
8591                      ENUMERABLE_STRINGS),
8592                  Nothing<bool>());
8593   }
8594 
8595   bool stable = object->map() == *map;
8596 
8597   for (int index = 0; index < number_of_own_descriptors; index++) {
8598     Handle<Name> next_key(descriptors->GetKey(index), isolate);
8599     if (!next_key->IsString()) continue;
8600     Handle<Object> prop_value;
8601 
8602     // Directly decode from the descriptor array if |from| did not change shape.
8603     if (stable) {
8604       PropertyDetails details = descriptors->GetDetails(index);
8605       if (!details.IsEnumerable()) continue;
8606       if (details.kind() == kData) {
8607         if (details.location() == kDescriptor) {
8608           prop_value = handle(descriptors->GetValue(index), isolate);
8609         } else {
8610           Representation representation = details.representation();
8611           FieldIndex field_index = FieldIndex::ForDescriptor(*map, index);
8612           prop_value =
8613               JSObject::FastPropertyAt(object, representation, field_index);
8614         }
8615       } else {
8616         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8617             isolate, prop_value, JSReceiver::GetProperty(object, next_key),
8618             Nothing<bool>());
8619         stable = object->map() == *map;
8620       }
8621     } else {
8622       // If the map did change, do a slower lookup. We are still guaranteed that
8623       // the object has a simple shape, and that the key is a name.
8624       LookupIterator it(object, next_key, LookupIterator::OWN_SKIP_INTERCEPTOR);
8625       if (!it.IsFound()) continue;
8626       DCHECK(it.state() == LookupIterator::DATA ||
8627              it.state() == LookupIterator::ACCESSOR);
8628       if (!it.IsEnumerable()) continue;
8629       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8630           isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
8631     }
8632 
8633     if (get_entries) {
8634       prop_value = MakeEntryPair(isolate, next_key, prop_value);
8635     }
8636 
8637     values_or_entries->set(count, *prop_value);
8638     count++;
8639   }
8640 
8641   if (count < values_or_entries->length()) values_or_entries->Shrink(count);
8642   *result = values_or_entries;
8643   return Just(true);
8644 }
8645 
GetOwnValuesOrEntries(Isolate * isolate,Handle<JSReceiver> object,PropertyFilter filter,bool get_entries)8646 MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate,
8647                                               Handle<JSReceiver> object,
8648                                               PropertyFilter filter,
8649                                               bool get_entries) {
8650   Handle<FixedArray> values_or_entries;
8651   if (filter == ENUMERABLE_STRINGS) {
8652     Maybe<bool> fast_values_or_entries = FastGetOwnValuesOrEntries(
8653         isolate, object, get_entries, &values_or_entries);
8654     if (fast_values_or_entries.IsNothing()) return MaybeHandle<FixedArray>();
8655     if (fast_values_or_entries.FromJust()) return values_or_entries;
8656   }
8657 
8658   PropertyFilter key_filter =
8659       static_cast<PropertyFilter>(filter & ~ONLY_ENUMERABLE);
8660 
8661   Handle<FixedArray> keys;
8662   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8663       isolate, keys,
8664       KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, key_filter,
8665                               GetKeysConversion::kConvertToString),
8666       MaybeHandle<FixedArray>());
8667 
8668   values_or_entries = isolate->factory()->NewFixedArray(keys->length());
8669   int length = 0;
8670 
8671   for (int i = 0; i < keys->length(); ++i) {
8672     Handle<Name> key = Handle<Name>::cast(handle(keys->get(i), isolate));
8673 
8674     if (filter & ONLY_ENUMERABLE) {
8675       PropertyDescriptor descriptor;
8676       Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor(
8677           isolate, object, key, &descriptor);
8678       MAYBE_RETURN(did_get_descriptor, MaybeHandle<FixedArray>());
8679       if (!did_get_descriptor.FromJust() || !descriptor.enumerable()) continue;
8680     }
8681 
8682     Handle<Object> value;
8683     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8684         isolate, value, JSReceiver::GetPropertyOrElement(object, key),
8685         MaybeHandle<FixedArray>());
8686 
8687     if (get_entries) {
8688       Handle<FixedArray> entry_storage =
8689           isolate->factory()->NewUninitializedFixedArray(2);
8690       entry_storage->set(0, *key);
8691       entry_storage->set(1, *value);
8692       value = isolate->factory()->NewJSArrayWithElements(entry_storage,
8693                                                          FAST_ELEMENTS, 2);
8694     }
8695 
8696     values_or_entries->set(length, *value);
8697     length++;
8698   }
8699   if (length < values_or_entries->length()) values_or_entries->Shrink(length);
8700   return values_or_entries;
8701 }
8702 
GetOwnValues(Handle<JSReceiver> object,PropertyFilter filter)8703 MaybeHandle<FixedArray> JSReceiver::GetOwnValues(Handle<JSReceiver> object,
8704                                                  PropertyFilter filter) {
8705   return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, false);
8706 }
8707 
GetOwnEntries(Handle<JSReceiver> object,PropertyFilter filter)8708 MaybeHandle<FixedArray> JSReceiver::GetOwnEntries(Handle<JSReceiver> object,
8709                                                   PropertyFilter filter) {
8710   return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, true);
8711 }
8712 
DictionaryElementsInPrototypeChainOnly()8713 bool Map::DictionaryElementsInPrototypeChainOnly() {
8714   if (IsDictionaryElementsKind(elements_kind())) {
8715     return false;
8716   }
8717 
8718   for (PrototypeIterator iter(this); !iter.IsAtEnd(); iter.Advance()) {
8719     // Be conservative, don't walk into proxies.
8720     if (iter.GetCurrent()->IsJSProxy()) return true;
8721     // String wrappers have non-configurable, non-writable elements.
8722     if (iter.GetCurrent()->IsStringWrapper()) return true;
8723     JSObject* current = iter.GetCurrent<JSObject>();
8724 
8725     if (current->HasDictionaryElements() &&
8726         current->element_dictionary()->requires_slow_elements()) {
8727       return true;
8728     }
8729 
8730     if (current->HasSlowArgumentsElements()) {
8731       FixedArray* parameter_map = FixedArray::cast(current->elements());
8732       Object* arguments = parameter_map->get(1);
8733       if (SeededNumberDictionary::cast(arguments)->requires_slow_elements()) {
8734         return true;
8735       }
8736     }
8737   }
8738 
8739   return false;
8740 }
8741 
8742 
DefineAccessor(Handle<JSObject> object,Handle<Name> name,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)8743 MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
8744                                              Handle<Name> name,
8745                                              Handle<Object> getter,
8746                                              Handle<Object> setter,
8747                                              PropertyAttributes attributes) {
8748   Isolate* isolate = object->GetIsolate();
8749 
8750   LookupIterator it = LookupIterator::PropertyOrElement(
8751       isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
8752   return DefineAccessor(&it, getter, setter, attributes);
8753 }
8754 
8755 
DefineAccessor(LookupIterator * it,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)8756 MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it,
8757                                              Handle<Object> getter,
8758                                              Handle<Object> setter,
8759                                              PropertyAttributes attributes) {
8760   Isolate* isolate = it->isolate();
8761 
8762   it->UpdateProtector();
8763 
8764   if (it->state() == LookupIterator::ACCESS_CHECK) {
8765     if (!it->HasAccess()) {
8766       isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
8767       RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
8768       return isolate->factory()->undefined_value();
8769     }
8770     it->Next();
8771   }
8772 
8773   Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
8774   // Ignore accessors on typed arrays.
8775   if (it->IsElement() && object->HasFixedTypedArrayElements()) {
8776     return it->factory()->undefined_value();
8777   }
8778 
8779   DCHECK(getter->IsCallable() || getter->IsUndefined(isolate) ||
8780          getter->IsNull(isolate) || getter->IsFunctionTemplateInfo());
8781   DCHECK(setter->IsCallable() || setter->IsUndefined(isolate) ||
8782          setter->IsNull(isolate) || setter->IsFunctionTemplateInfo());
8783   it->TransitionToAccessorProperty(getter, setter, attributes);
8784 
8785   return isolate->factory()->undefined_value();
8786 }
8787 
8788 
SetAccessor(Handle<JSObject> object,Handle<AccessorInfo> info)8789 MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
8790                                           Handle<AccessorInfo> info) {
8791   Isolate* isolate = object->GetIsolate();
8792   Handle<Name> name(Name::cast(info->name()), isolate);
8793 
8794   LookupIterator it = LookupIterator::PropertyOrElement(
8795       isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
8796 
8797   // Duplicate ACCESS_CHECK outside of GetPropertyAttributes for the case that
8798   // the FailedAccessCheckCallbackFunction doesn't throw an exception.
8799   //
8800   // TODO(verwaest): Force throw an exception if the callback doesn't, so we can
8801   // remove reliance on default return values.
8802   if (it.state() == LookupIterator::ACCESS_CHECK) {
8803     if (!it.HasAccess()) {
8804       isolate->ReportFailedAccessCheck(object);
8805       RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
8806       return it.factory()->undefined_value();
8807     }
8808     it.Next();
8809   }
8810 
8811   // Ignore accessors on typed arrays.
8812   if (it.IsElement() && object->HasFixedTypedArrayElements()) {
8813     return it.factory()->undefined_value();
8814   }
8815 
8816   CHECK(GetPropertyAttributes(&it).IsJust());
8817 
8818   // ES5 forbids turning a property into an accessor if it's not
8819   // configurable. See 8.6.1 (Table 5).
8820   if (it.IsFound() && !it.IsConfigurable()) {
8821     return it.factory()->undefined_value();
8822   }
8823 
8824   it.TransitionToAccessorPair(info, info->property_attributes());
8825 
8826   return object;
8827 }
8828 
SlowReverseLookup(Object * value)8829 Object* JSObject::SlowReverseLookup(Object* value) {
8830   if (HasFastProperties()) {
8831     int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
8832     DescriptorArray* descs = map()->instance_descriptors();
8833     bool value_is_number = value->IsNumber();
8834     for (int i = 0; i < number_of_own_descriptors; i++) {
8835       if (descs->GetType(i) == DATA) {
8836         FieldIndex field_index = FieldIndex::ForDescriptor(map(), i);
8837         if (IsUnboxedDoubleField(field_index)) {
8838           if (value_is_number) {
8839             double property = RawFastDoublePropertyAt(field_index);
8840             if (property == value->Number()) {
8841               return descs->GetKey(i);
8842             }
8843           }
8844         } else {
8845           Object* property = RawFastPropertyAt(field_index);
8846           if (field_index.is_double()) {
8847             DCHECK(property->IsMutableHeapNumber());
8848             if (value_is_number && property->Number() == value->Number()) {
8849               return descs->GetKey(i);
8850             }
8851           } else if (property == value) {
8852             return descs->GetKey(i);
8853           }
8854         }
8855       } else if (descs->GetType(i) == DATA_CONSTANT) {
8856         if (descs->GetConstant(i) == value) {
8857           return descs->GetKey(i);
8858         }
8859       }
8860     }
8861     return GetHeap()->undefined_value();
8862   } else if (IsJSGlobalObject()) {
8863     return global_dictionary()->SlowReverseLookup(value);
8864   } else {
8865     return property_dictionary()->SlowReverseLookup(value);
8866   }
8867 }
8868 
8869 
RawCopy(Handle<Map> map,int instance_size)8870 Handle<Map> Map::RawCopy(Handle<Map> map, int instance_size) {
8871   Isolate* isolate = map->GetIsolate();
8872   Handle<Map> result =
8873       isolate->factory()->NewMap(map->instance_type(), instance_size);
8874   Handle<Object> prototype(map->prototype(), isolate);
8875   Map::SetPrototype(result, prototype);
8876   result->set_constructor_or_backpointer(map->GetConstructor());
8877   result->set_bit_field(map->bit_field());
8878   result->set_bit_field2(map->bit_field2());
8879   int new_bit_field3 = map->bit_field3();
8880   new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true);
8881   new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0);
8882   new_bit_field3 = EnumLengthBits::update(new_bit_field3,
8883                                           kInvalidEnumCacheSentinel);
8884   new_bit_field3 = Deprecated::update(new_bit_field3, false);
8885   if (!map->is_dictionary_map()) {
8886     new_bit_field3 = IsUnstable::update(new_bit_field3, false);
8887   }
8888   result->set_bit_field3(new_bit_field3);
8889   return result;
8890 }
8891 
8892 
Normalize(Handle<Map> fast_map,PropertyNormalizationMode mode,const char * reason)8893 Handle<Map> Map::Normalize(Handle<Map> fast_map, PropertyNormalizationMode mode,
8894                            const char* reason) {
8895   DCHECK(!fast_map->is_dictionary_map());
8896 
8897   Isolate* isolate = fast_map->GetIsolate();
8898   Handle<Object> maybe_cache(isolate->native_context()->normalized_map_cache(),
8899                              isolate);
8900   bool use_cache =
8901       !fast_map->is_prototype_map() && !maybe_cache->IsUndefined(isolate);
8902   Handle<NormalizedMapCache> cache;
8903   if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache);
8904 
8905   Handle<Map> new_map;
8906   if (use_cache && cache->Get(fast_map, mode).ToHandle(&new_map)) {
8907 #ifdef VERIFY_HEAP
8908     if (FLAG_verify_heap) new_map->DictionaryMapVerify();
8909 #endif
8910 #ifdef ENABLE_SLOW_DCHECKS
8911     if (FLAG_enable_slow_asserts) {
8912       // The cached map should match newly created normalized map bit-by-bit,
8913       // except for the code cache, which can contain some ics which can be
8914       // applied to the shared map, dependent code and weak cell cache.
8915       Handle<Map> fresh = Map::CopyNormalized(fast_map, mode);
8916 
8917       if (new_map->is_prototype_map()) {
8918         // For prototype maps, the PrototypeInfo is not copied.
8919         DCHECK(memcmp(fresh->address(), new_map->address(),
8920                       kTransitionsOrPrototypeInfoOffset) == 0);
8921         DCHECK(fresh->raw_transitions() == Smi::kZero);
8922         STATIC_ASSERT(kDescriptorsOffset ==
8923                       kTransitionsOrPrototypeInfoOffset + kPointerSize);
8924         DCHECK(memcmp(HeapObject::RawField(*fresh, kDescriptorsOffset),
8925                       HeapObject::RawField(*new_map, kDescriptorsOffset),
8926                       kCodeCacheOffset - kDescriptorsOffset) == 0);
8927       } else {
8928         DCHECK(memcmp(fresh->address(), new_map->address(),
8929                       Map::kCodeCacheOffset) == 0);
8930       }
8931       STATIC_ASSERT(Map::kDependentCodeOffset ==
8932                     Map::kCodeCacheOffset + kPointerSize);
8933       STATIC_ASSERT(Map::kWeakCellCacheOffset ==
8934                     Map::kDependentCodeOffset + kPointerSize);
8935       int offset = Map::kWeakCellCacheOffset + kPointerSize;
8936       DCHECK(memcmp(fresh->address() + offset,
8937                     new_map->address() + offset,
8938                     Map::kSize - offset) == 0);
8939     }
8940 #endif
8941   } else {
8942     new_map = Map::CopyNormalized(fast_map, mode);
8943     if (use_cache) {
8944       cache->Set(fast_map, new_map);
8945       isolate->counters()->maps_normalized()->Increment();
8946     }
8947 #if TRACE_MAPS
8948     if (FLAG_trace_maps) {
8949       PrintF("[TraceMaps: Normalize from= %p to= %p reason= %s ]\n",
8950              reinterpret_cast<void*>(*fast_map),
8951              reinterpret_cast<void*>(*new_map), reason);
8952     }
8953 #endif
8954   }
8955   fast_map->NotifyLeafMapLayoutChange();
8956   return new_map;
8957 }
8958 
8959 
CopyNormalized(Handle<Map> map,PropertyNormalizationMode mode)8960 Handle<Map> Map::CopyNormalized(Handle<Map> map,
8961                                 PropertyNormalizationMode mode) {
8962   int new_instance_size = map->instance_size();
8963   if (mode == CLEAR_INOBJECT_PROPERTIES) {
8964     new_instance_size -= map->GetInObjectProperties() * kPointerSize;
8965   }
8966 
8967   Handle<Map> result = RawCopy(map, new_instance_size);
8968 
8969   if (mode != CLEAR_INOBJECT_PROPERTIES) {
8970     result->SetInObjectProperties(map->GetInObjectProperties());
8971   }
8972 
8973   result->set_dictionary_map(true);
8974   result->set_migration_target(false);
8975   result->set_construction_counter(kNoSlackTracking);
8976 
8977 #ifdef VERIFY_HEAP
8978   if (FLAG_verify_heap) result->DictionaryMapVerify();
8979 #endif
8980 
8981   return result;
8982 }
8983 
8984 // Return an immutable prototype exotic object version of the input map.
8985 // Never even try to cache it in the transition tree, as it is intended
8986 // for the global object and its prototype chain, and excluding it saves
8987 // memory on the map transition tree.
8988 
8989 // static
TransitionToImmutableProto(Handle<Map> map)8990 Handle<Map> Map::TransitionToImmutableProto(Handle<Map> map) {
8991   Handle<Map> new_map = Map::Copy(map, "ImmutablePrototype");
8992   new_map->set_immutable_proto(true);
8993   return new_map;
8994 }
8995 
CopyInitialMap(Handle<Map> map,int instance_size,int in_object_properties,int unused_property_fields)8996 Handle<Map> Map::CopyInitialMap(Handle<Map> map, int instance_size,
8997                                 int in_object_properties,
8998                                 int unused_property_fields) {
8999 #ifdef DEBUG
9000   Isolate* isolate = map->GetIsolate();
9001   // Strict function maps have Function as a constructor but the
9002   // Function's initial map is a sloppy function map. Same holds for
9003   // GeneratorFunction and its initial map.
9004   Object* constructor = map->GetConstructor();
9005   DCHECK(constructor->IsJSFunction());
9006   DCHECK(*map == JSFunction::cast(constructor)->initial_map() ||
9007          *map == *isolate->strict_function_map() ||
9008          *map == *isolate->strict_generator_function_map());
9009 #endif
9010   // Initial maps must always own their descriptors and it's descriptor array
9011   // does not contain descriptors that do not belong to the map.
9012   DCHECK(map->owns_descriptors());
9013   DCHECK_EQ(map->NumberOfOwnDescriptors(),
9014             map->instance_descriptors()->number_of_descriptors());
9015 
9016   Handle<Map> result = RawCopy(map, instance_size);
9017 
9018   // Please note instance_type and instance_size are set when allocated.
9019   result->SetInObjectProperties(in_object_properties);
9020   result->set_unused_property_fields(unused_property_fields);
9021 
9022   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9023   if (number_of_own_descriptors > 0) {
9024     // The copy will use the same descriptors array.
9025     result->UpdateDescriptors(map->instance_descriptors(),
9026                               map->GetLayoutDescriptor());
9027     result->SetNumberOfOwnDescriptors(number_of_own_descriptors);
9028 
9029     DCHECK_EQ(result->NumberOfFields(),
9030               in_object_properties - unused_property_fields);
9031   }
9032 
9033   return result;
9034 }
9035 
9036 
CopyDropDescriptors(Handle<Map> map)9037 Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) {
9038   Handle<Map> result = RawCopy(map, map->instance_size());
9039 
9040   // Please note instance_type and instance_size are set when allocated.
9041   if (map->IsJSObjectMap()) {
9042     result->SetInObjectProperties(map->GetInObjectProperties());
9043     result->set_unused_property_fields(map->unused_property_fields());
9044   }
9045   result->ClearCodeCache(map->GetHeap());
9046   map->NotifyLeafMapLayoutChange();
9047   return result;
9048 }
9049 
9050 
ShareDescriptor(Handle<Map> map,Handle<DescriptorArray> descriptors,Descriptor * descriptor)9051 Handle<Map> Map::ShareDescriptor(Handle<Map> map,
9052                                  Handle<DescriptorArray> descriptors,
9053                                  Descriptor* descriptor) {
9054   // Sanity check. This path is only to be taken if the map owns its descriptor
9055   // array, implying that its NumberOfOwnDescriptors equals the number of
9056   // descriptors in the descriptor array.
9057   DCHECK_EQ(map->NumberOfOwnDescriptors(),
9058             map->instance_descriptors()->number_of_descriptors());
9059 
9060   Handle<Map> result = CopyDropDescriptors(map);
9061   Handle<Name> name = descriptor->GetKey();
9062 
9063   // Ensure there's space for the new descriptor in the shared descriptor array.
9064   if (descriptors->NumberOfSlackDescriptors() == 0) {
9065     int old_size = descriptors->number_of_descriptors();
9066     if (old_size == 0) {
9067       descriptors = DescriptorArray::Allocate(map->GetIsolate(), 0, 1);
9068     } else {
9069       int slack = SlackForArraySize(old_size, kMaxNumberOfDescriptors);
9070       EnsureDescriptorSlack(map, slack);
9071       descriptors = handle(map->instance_descriptors());
9072     }
9073   }
9074 
9075   Handle<LayoutDescriptor> layout_descriptor =
9076       FLAG_unbox_double_fields
9077           ? LayoutDescriptor::ShareAppend(map, descriptor->GetDetails())
9078           : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
9079 
9080   {
9081     DisallowHeapAllocation no_gc;
9082     descriptors->Append(descriptor);
9083     result->InitializeDescriptors(*descriptors, *layout_descriptor);
9084   }
9085 
9086   DCHECK(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1);
9087   ConnectTransition(map, result, name, SIMPLE_PROPERTY_TRANSITION);
9088 
9089   return result;
9090 }
9091 
9092 
9093 #if TRACE_MAPS
9094 
9095 // static
TraceTransition(const char * what,Map * from,Map * to,Name * name)9096 void Map::TraceTransition(const char* what, Map* from, Map* to, Name* name) {
9097   if (FLAG_trace_maps) {
9098     PrintF("[TraceMaps: %s from= %p to= %p name= ", what,
9099            reinterpret_cast<void*>(from), reinterpret_cast<void*>(to));
9100     name->NameShortPrint();
9101     PrintF(" ]\n");
9102   }
9103 }
9104 
9105 
9106 // static
TraceAllTransitions(Map * map)9107 void Map::TraceAllTransitions(Map* map) {
9108   Object* transitions = map->raw_transitions();
9109   int num_transitions = TransitionArray::NumberOfTransitions(transitions);
9110   for (int i = -0; i < num_transitions; ++i) {
9111     Map* target = TransitionArray::GetTarget(transitions, i);
9112     Name* key = TransitionArray::GetKey(transitions, i);
9113     Map::TraceTransition("Transition", map, target, key);
9114     Map::TraceAllTransitions(target);
9115   }
9116 }
9117 
9118 #endif  // TRACE_MAPS
9119 
9120 
ConnectTransition(Handle<Map> parent,Handle<Map> child,Handle<Name> name,SimpleTransitionFlag flag)9121 void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
9122                             Handle<Name> name, SimpleTransitionFlag flag) {
9123   if (!parent->GetBackPointer()->IsUndefined(parent->GetIsolate())) {
9124     parent->set_owns_descriptors(false);
9125   } else {
9126     // |parent| is initial map and it must keep the ownership, there must be no
9127     // descriptors in the descriptors array that do not belong to the map.
9128     DCHECK(parent->owns_descriptors());
9129     DCHECK_EQ(parent->NumberOfOwnDescriptors(),
9130               parent->instance_descriptors()->number_of_descriptors());
9131   }
9132   if (parent->is_prototype_map()) {
9133     DCHECK(child->is_prototype_map());
9134 #if TRACE_MAPS
9135     Map::TraceTransition("NoTransition", *parent, *child, *name);
9136 #endif
9137   } else {
9138     TransitionArray::Insert(parent, name, child, flag);
9139 #if TRACE_MAPS
9140     Map::TraceTransition("Transition", *parent, *child, *name);
9141 #endif
9142   }
9143 }
9144 
9145 
CopyReplaceDescriptors(Handle<Map> map,Handle<DescriptorArray> descriptors,Handle<LayoutDescriptor> layout_descriptor,TransitionFlag flag,MaybeHandle<Name> maybe_name,const char * reason,SimpleTransitionFlag simple_flag)9146 Handle<Map> Map::CopyReplaceDescriptors(
9147     Handle<Map> map, Handle<DescriptorArray> descriptors,
9148     Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag,
9149     MaybeHandle<Name> maybe_name, const char* reason,
9150     SimpleTransitionFlag simple_flag) {
9151   DCHECK(descriptors->IsSortedNoDuplicates());
9152 
9153   Handle<Map> result = CopyDropDescriptors(map);
9154 
9155   if (!map->is_prototype_map()) {
9156     if (flag == INSERT_TRANSITION &&
9157         TransitionArray::CanHaveMoreTransitions(map)) {
9158       result->InitializeDescriptors(*descriptors, *layout_descriptor);
9159 
9160       Handle<Name> name;
9161       CHECK(maybe_name.ToHandle(&name));
9162       ConnectTransition(map, result, name, simple_flag);
9163     } else {
9164       int length = descriptors->number_of_descriptors();
9165       for (int i = 0; i < length; i++) {
9166         descriptors->SetRepresentation(i, Representation::Tagged());
9167         if (descriptors->GetDetails(i).type() == DATA) {
9168           descriptors->SetValue(i, FieldType::Any());
9169         }
9170       }
9171       result->InitializeDescriptors(*descriptors,
9172                                     LayoutDescriptor::FastPointerLayout());
9173     }
9174   } else {
9175     result->InitializeDescriptors(*descriptors, *layout_descriptor);
9176   }
9177 #if TRACE_MAPS
9178   if (FLAG_trace_maps &&
9179       // Mirror conditions above that did not call ConnectTransition().
9180       (map->is_prototype_map() ||
9181        !(flag == INSERT_TRANSITION &&
9182          TransitionArray::CanHaveMoreTransitions(map)))) {
9183     PrintF("[TraceMaps: ReplaceDescriptors from= %p to= %p reason= %s ]\n",
9184            reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*result),
9185            reason);
9186   }
9187 #endif
9188 
9189   return result;
9190 }
9191 
9192 
9193 // Creates transition tree starting from |split_map| and adding all descriptors
9194 // starting from descriptor with index |split_map|.NumberOfOwnDescriptors().
9195 // The way how it is done is tricky because of GC and special descriptors
9196 // marking logic.
AddMissingTransitions(Handle<Map> split_map,Handle<DescriptorArray> descriptors,Handle<LayoutDescriptor> full_layout_descriptor)9197 Handle<Map> Map::AddMissingTransitions(
9198     Handle<Map> split_map, Handle<DescriptorArray> descriptors,
9199     Handle<LayoutDescriptor> full_layout_descriptor) {
9200   DCHECK(descriptors->IsSortedNoDuplicates());
9201   int split_nof = split_map->NumberOfOwnDescriptors();
9202   int nof_descriptors = descriptors->number_of_descriptors();
9203   DCHECK_LT(split_nof, nof_descriptors);
9204 
9205   // Start with creating last map which will own full descriptors array.
9206   // This is necessary to guarantee that GC will mark the whole descriptor
9207   // array if any of the allocations happening below fail.
9208   // Number of unused properties is temporarily incorrect and the layout
9209   // descriptor could unnecessarily be in slow mode but we will fix after
9210   // all the other intermediate maps are created.
9211   Handle<Map> last_map = CopyDropDescriptors(split_map);
9212   last_map->InitializeDescriptors(*descriptors, *full_layout_descriptor);
9213   last_map->set_unused_property_fields(0);
9214 
9215   // During creation of intermediate maps we violate descriptors sharing
9216   // invariant since the last map is not yet connected to the transition tree
9217   // we create here. But it is safe because GC never trims map's descriptors
9218   // if there are no dead transitions from that map and this is exactly the
9219   // case for all the intermediate maps we create here.
9220   Handle<Map> map = split_map;
9221   for (int i = split_nof; i < nof_descriptors - 1; ++i) {
9222     Handle<Map> new_map = CopyDropDescriptors(map);
9223     InstallDescriptors(map, new_map, i, descriptors, full_layout_descriptor);
9224     map = new_map;
9225   }
9226   map->NotifyLeafMapLayoutChange();
9227   InstallDescriptors(map, last_map, nof_descriptors - 1, descriptors,
9228                      full_layout_descriptor);
9229   return last_map;
9230 }
9231 
9232 
9233 // Since this method is used to rewrite an existing transition tree, it can
9234 // always insert transitions without checking.
InstallDescriptors(Handle<Map> parent,Handle<Map> child,int new_descriptor,Handle<DescriptorArray> descriptors,Handle<LayoutDescriptor> full_layout_descriptor)9235 void Map::InstallDescriptors(Handle<Map> parent, Handle<Map> child,
9236                              int new_descriptor,
9237                              Handle<DescriptorArray> descriptors,
9238                              Handle<LayoutDescriptor> full_layout_descriptor) {
9239   DCHECK(descriptors->IsSortedNoDuplicates());
9240 
9241   child->set_instance_descriptors(*descriptors);
9242   child->SetNumberOfOwnDescriptors(new_descriptor + 1);
9243 
9244   int unused_property_fields = parent->unused_property_fields();
9245   PropertyDetails details = descriptors->GetDetails(new_descriptor);
9246   if (details.location() == kField) {
9247     unused_property_fields = parent->unused_property_fields() - 1;
9248     if (unused_property_fields < 0) {
9249       unused_property_fields += JSObject::kFieldsAdded;
9250     }
9251   }
9252   child->set_unused_property_fields(unused_property_fields);
9253 
9254   if (FLAG_unbox_double_fields) {
9255     Handle<LayoutDescriptor> layout_descriptor =
9256         LayoutDescriptor::AppendIfFastOrUseFull(parent, details,
9257                                                 full_layout_descriptor);
9258     child->set_layout_descriptor(*layout_descriptor);
9259 #ifdef VERIFY_HEAP
9260     // TODO(ishell): remove these checks from VERIFY_HEAP mode.
9261     if (FLAG_verify_heap) {
9262       CHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
9263     }
9264 #else
9265     SLOW_DCHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
9266 #endif
9267     child->set_visitor_id(Heap::GetStaticVisitorIdForMap(*child));
9268   }
9269 
9270   Handle<Name> name = handle(descriptors->GetKey(new_descriptor));
9271   ConnectTransition(parent, child, name, SIMPLE_PROPERTY_TRANSITION);
9272 }
9273 
9274 
CopyAsElementsKind(Handle<Map> map,ElementsKind kind,TransitionFlag flag)9275 Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind,
9276                                     TransitionFlag flag) {
9277   Map* maybe_elements_transition_map = NULL;
9278   if (flag == INSERT_TRANSITION) {
9279     // Ensure we are requested to add elements kind transition "near the root".
9280     DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(),
9281               map->NumberOfOwnDescriptors());
9282 
9283     maybe_elements_transition_map = map->ElementsTransitionMap();
9284     DCHECK(maybe_elements_transition_map == NULL ||
9285            (maybe_elements_transition_map->elements_kind() ==
9286                 DICTIONARY_ELEMENTS &&
9287             kind == DICTIONARY_ELEMENTS));
9288     DCHECK(!IsFastElementsKind(kind) ||
9289            IsMoreGeneralElementsKindTransition(map->elements_kind(), kind));
9290     DCHECK(kind != map->elements_kind());
9291   }
9292 
9293   bool insert_transition = flag == INSERT_TRANSITION &&
9294                            TransitionArray::CanHaveMoreTransitions(map) &&
9295                            maybe_elements_transition_map == NULL;
9296 
9297   if (insert_transition) {
9298     Handle<Map> new_map = CopyForTransition(map, "CopyAsElementsKind");
9299     new_map->set_elements_kind(kind);
9300 
9301     Isolate* isolate = map->GetIsolate();
9302     Handle<Name> name = isolate->factory()->elements_transition_symbol();
9303     ConnectTransition(map, new_map, name, SPECIAL_TRANSITION);
9304     return new_map;
9305   }
9306 
9307   // Create a new free-floating map only if we are not allowed to store it.
9308   Handle<Map> new_map = Copy(map, "CopyAsElementsKind");
9309   new_map->set_elements_kind(kind);
9310   return new_map;
9311 }
9312 
9313 
AsLanguageMode(Handle<Map> initial_map,LanguageMode language_mode,FunctionKind kind)9314 Handle<Map> Map::AsLanguageMode(Handle<Map> initial_map,
9315                                 LanguageMode language_mode, FunctionKind kind) {
9316   DCHECK_EQ(JS_FUNCTION_TYPE, initial_map->instance_type());
9317   // Initial map for sloppy mode function is stored in the function
9318   // constructor. Initial maps for strict mode are cached as special transitions
9319   // using |strict_function_transition_symbol| as a key.
9320   if (language_mode == SLOPPY) return initial_map;
9321   Isolate* isolate = initial_map->GetIsolate();
9322 
9323   int map_index = Context::FunctionMapIndex(language_mode, kind);
9324   Handle<Map> function_map(
9325       Map::cast(isolate->native_context()->get(map_index)));
9326 
9327   STATIC_ASSERT(LANGUAGE_END == 2);
9328   DCHECK_EQ(STRICT, language_mode);
9329   Handle<Symbol> transition_symbol =
9330       isolate->factory()->strict_function_transition_symbol();
9331   Map* maybe_transition =
9332       TransitionArray::SearchSpecial(*initial_map, *transition_symbol);
9333   if (maybe_transition != NULL) {
9334     return handle(maybe_transition, isolate);
9335   }
9336   initial_map->NotifyLeafMapLayoutChange();
9337 
9338   // Create new map taking descriptors from the |function_map| and all
9339   // the other details from the |initial_map|.
9340   Handle<Map> map =
9341       Map::CopyInitialMap(function_map, initial_map->instance_size(),
9342                           initial_map->GetInObjectProperties(),
9343                           initial_map->unused_property_fields());
9344   map->SetConstructor(initial_map->GetConstructor());
9345   map->set_prototype(initial_map->prototype());
9346 
9347   if (TransitionArray::CanHaveMoreTransitions(initial_map)) {
9348     Map::ConnectTransition(initial_map, map, transition_symbol,
9349                            SPECIAL_TRANSITION);
9350   }
9351   return map;
9352 }
9353 
9354 
CopyForTransition(Handle<Map> map,const char * reason)9355 Handle<Map> Map::CopyForTransition(Handle<Map> map, const char* reason) {
9356   DCHECK(!map->is_prototype_map());
9357   Handle<Map> new_map = CopyDropDescriptors(map);
9358 
9359   if (map->owns_descriptors()) {
9360     // In case the map owned its own descriptors, share the descriptors and
9361     // transfer ownership to the new map.
9362     // The properties did not change, so reuse descriptors.
9363     new_map->InitializeDescriptors(map->instance_descriptors(),
9364                                    map->GetLayoutDescriptor());
9365   } else {
9366     // In case the map did not own its own descriptors, a split is forced by
9367     // copying the map; creating a new descriptor array cell.
9368     Handle<DescriptorArray> descriptors(map->instance_descriptors());
9369     int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9370     Handle<DescriptorArray> new_descriptors =
9371         DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
9372     Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9373                                                    map->GetIsolate());
9374     new_map->InitializeDescriptors(*new_descriptors, *new_layout_descriptor);
9375   }
9376 
9377 #if TRACE_MAPS
9378   if (FLAG_trace_maps) {
9379     PrintF("[TraceMaps: CopyForTransition from= %p to= %p reason= %s ]\n",
9380            reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*new_map),
9381            reason);
9382   }
9383 #endif
9384 
9385   return new_map;
9386 }
9387 
9388 
Copy(Handle<Map> map,const char * reason)9389 Handle<Map> Map::Copy(Handle<Map> map, const char* reason) {
9390   Handle<DescriptorArray> descriptors(map->instance_descriptors());
9391   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9392   Handle<DescriptorArray> new_descriptors =
9393       DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
9394   Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9395                                                  map->GetIsolate());
9396   return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9397                                 OMIT_TRANSITION, MaybeHandle<Name>(), reason,
9398                                 SPECIAL_TRANSITION);
9399 }
9400 
9401 
Create(Isolate * isolate,int inobject_properties)9402 Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) {
9403   Handle<Map> copy =
9404       Copy(handle(isolate->object_function()->initial_map()), "MapCreate");
9405 
9406   // Check that we do not overflow the instance size when adding the extra
9407   // inobject properties. If the instance size overflows, we allocate as many
9408   // properties as we can as inobject properties.
9409   int max_extra_properties =
9410       (JSObject::kMaxInstanceSize - JSObject::kHeaderSize) >> kPointerSizeLog2;
9411 
9412   if (inobject_properties > max_extra_properties) {
9413     inobject_properties = max_extra_properties;
9414   }
9415 
9416   int new_instance_size =
9417       JSObject::kHeaderSize + kPointerSize * inobject_properties;
9418 
9419   // Adjust the map with the extra inobject properties.
9420   copy->SetInObjectProperties(inobject_properties);
9421   copy->set_unused_property_fields(inobject_properties);
9422   copy->set_instance_size(new_instance_size);
9423   copy->set_visitor_id(Heap::GetStaticVisitorIdForMap(*copy));
9424   return copy;
9425 }
9426 
9427 
CopyForPreventExtensions(Handle<Map> map,PropertyAttributes attrs_to_add,Handle<Symbol> transition_marker,const char * reason)9428 Handle<Map> Map::CopyForPreventExtensions(Handle<Map> map,
9429                                           PropertyAttributes attrs_to_add,
9430                                           Handle<Symbol> transition_marker,
9431                                           const char* reason) {
9432   int num_descriptors = map->NumberOfOwnDescriptors();
9433   Isolate* isolate = map->GetIsolate();
9434   Handle<DescriptorArray> new_desc = DescriptorArray::CopyUpToAddAttributes(
9435       handle(map->instance_descriptors(), isolate), num_descriptors,
9436       attrs_to_add);
9437   Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9438                                                  isolate);
9439   Handle<Map> new_map = CopyReplaceDescriptors(
9440       map, new_desc, new_layout_descriptor, INSERT_TRANSITION,
9441       transition_marker, reason, SPECIAL_TRANSITION);
9442   new_map->set_is_extensible(false);
9443   if (!IsFixedTypedArrayElementsKind(map->elements_kind())) {
9444     ElementsKind new_kind = IsStringWrapperElementsKind(map->elements_kind())
9445                                 ? SLOW_STRING_WRAPPER_ELEMENTS
9446                                 : DICTIONARY_ELEMENTS;
9447     new_map->set_elements_kind(new_kind);
9448   }
9449   return new_map;
9450 }
9451 
GetFieldType(int descriptor_number)9452 FieldType* DescriptorArray::GetFieldType(int descriptor_number) {
9453   DCHECK(GetDetails(descriptor_number).location() == kField);
9454   Object* value = GetValue(descriptor_number);
9455   if (value->IsWeakCell()) {
9456     if (WeakCell::cast(value)->cleared()) return FieldType::None();
9457     value = WeakCell::cast(value)->value();
9458   }
9459   return FieldType::cast(value);
9460 }
9461 
9462 namespace {
9463 
CanHoldValue(DescriptorArray * descriptors,int descriptor,Object * value)9464 bool CanHoldValue(DescriptorArray* descriptors, int descriptor, Object* value) {
9465   PropertyDetails details = descriptors->GetDetails(descriptor);
9466   switch (details.type()) {
9467     case DATA:
9468       return value->FitsRepresentation(details.representation()) &&
9469              descriptors->GetFieldType(descriptor)->NowContains(value);
9470 
9471     case DATA_CONSTANT:
9472       DCHECK(descriptors->GetConstant(descriptor) != value ||
9473              value->FitsRepresentation(details.representation()));
9474       return descriptors->GetConstant(descriptor) == value;
9475 
9476     case ACCESSOR:
9477     case ACCESSOR_CONSTANT:
9478       return false;
9479   }
9480 
9481   UNREACHABLE();
9482   return false;
9483 }
9484 
UpdateDescriptorForValue(Handle<Map> map,int descriptor,Handle<Object> value)9485 Handle<Map> UpdateDescriptorForValue(Handle<Map> map, int descriptor,
9486                                      Handle<Object> value) {
9487   if (CanHoldValue(map->instance_descriptors(), descriptor, *value)) return map;
9488 
9489   Isolate* isolate = map->GetIsolate();
9490   PropertyAttributes attributes =
9491       map->instance_descriptors()->GetDetails(descriptor).attributes();
9492   Representation representation = value->OptimalRepresentation();
9493   Handle<FieldType> type = value->OptimalType(isolate, representation);
9494 
9495   return Map::ReconfigureProperty(map, descriptor, kData, attributes,
9496                                   representation, type, FORCE_FIELD);
9497 }
9498 
9499 }  // namespace
9500 
9501 // static
PrepareForDataProperty(Handle<Map> map,int descriptor,Handle<Object> value)9502 Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor,
9503                                         Handle<Object> value) {
9504   // Dictionaries can store any property value.
9505   DCHECK(!map->is_dictionary_map());
9506   // Update to the newest map before storing the property.
9507   return UpdateDescriptorForValue(Update(map), descriptor, value);
9508 }
9509 
9510 
TransitionToDataProperty(Handle<Map> map,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes,StoreFromKeyed store_mode)9511 Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
9512                                           Handle<Object> value,
9513                                           PropertyAttributes attributes,
9514                                           StoreFromKeyed store_mode) {
9515   RuntimeCallTimerScope stats_scope(
9516       *map, map->is_prototype_map()
9517                 ? &RuntimeCallStats::PrototypeMap_TransitionToDataProperty
9518                 : &RuntimeCallStats::Map_TransitionToDataProperty);
9519 
9520   DCHECK(name->IsUniqueName());
9521   DCHECK(!map->is_dictionary_map());
9522 
9523   // Migrate to the newest map before storing the property.
9524   map = Update(map);
9525 
9526   Map* maybe_transition =
9527       TransitionArray::SearchTransition(*map, kData, *name, attributes);
9528   if (maybe_transition != NULL) {
9529     Handle<Map> transition(maybe_transition);
9530     int descriptor = transition->LastAdded();
9531 
9532     DCHECK_EQ(attributes, transition->instance_descriptors()
9533                               ->GetDetails(descriptor)
9534                               .attributes());
9535 
9536     return UpdateDescriptorForValue(transition, descriptor, value);
9537   }
9538 
9539   TransitionFlag flag = INSERT_TRANSITION;
9540   MaybeHandle<Map> maybe_map;
9541   if (value->IsJSFunction()) {
9542     maybe_map = Map::CopyWithConstant(map, name, value, attributes, flag);
9543   } else if (!map->TooManyFastProperties(store_mode)) {
9544     Isolate* isolate = name->GetIsolate();
9545     Representation representation = value->OptimalRepresentation();
9546     Handle<FieldType> type = value->OptimalType(isolate, representation);
9547     maybe_map =
9548         Map::CopyWithField(map, name, type, attributes, representation, flag);
9549   }
9550 
9551   Handle<Map> result;
9552   if (!maybe_map.ToHandle(&result)) {
9553 #if TRACE_MAPS
9554     if (FLAG_trace_maps) {
9555       Vector<char> name_buffer = Vector<char>::New(100);
9556       name->NameShortPrint(name_buffer);
9557       Vector<char> buffer = Vector<char>::New(128);
9558       SNPrintF(buffer, "TooManyFastProperties %s", name_buffer.start());
9559       return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, buffer.start());
9560     }
9561 #endif
9562     return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES,
9563                           "TooManyFastProperties");
9564   }
9565 
9566   return result;
9567 }
9568 
9569 
ReconfigureExistingProperty(Handle<Map> map,int descriptor,PropertyKind kind,PropertyAttributes attributes)9570 Handle<Map> Map::ReconfigureExistingProperty(Handle<Map> map, int descriptor,
9571                                              PropertyKind kind,
9572                                              PropertyAttributes attributes) {
9573   // Dictionaries have to be reconfigured in-place.
9574   DCHECK(!map->is_dictionary_map());
9575 
9576   if (!map->GetBackPointer()->IsMap()) {
9577     // There is no benefit from reconstructing transition tree for maps without
9578     // back pointers.
9579     return CopyGeneralizeAllRepresentations(
9580         map, map->elements_kind(), descriptor, FORCE_FIELD, kind, attributes,
9581         "GenAll_AttributesMismatchProtoMap");
9582   }
9583 
9584   if (FLAG_trace_generalization) {
9585     map->PrintReconfiguration(stdout, descriptor, kind, attributes);
9586   }
9587 
9588   Isolate* isolate = map->GetIsolate();
9589   Handle<Map> new_map = ReconfigureProperty(
9590       map, descriptor, kind, attributes, Representation::None(),
9591       FieldType::None(isolate), FORCE_FIELD);
9592   return new_map;
9593 }
9594 
TransitionToAccessorProperty(Isolate * isolate,Handle<Map> map,Handle<Name> name,int descriptor,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)9595 Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map,
9596                                               Handle<Name> name, int descriptor,
9597                                               Handle<Object> getter,
9598                                               Handle<Object> setter,
9599                                               PropertyAttributes attributes) {
9600   RuntimeCallTimerScope stats_scope(
9601       isolate,
9602       map->is_prototype_map()
9603           ? &RuntimeCallStats::PrototypeMap_TransitionToAccessorProperty
9604           : &RuntimeCallStats::Map_TransitionToAccessorProperty);
9605 
9606   // At least one of the accessors needs to be a new value.
9607   DCHECK(!getter->IsNull(isolate) || !setter->IsNull(isolate));
9608   DCHECK(name->IsUniqueName());
9609 
9610   // Dictionary maps can always have additional data properties.
9611   if (map->is_dictionary_map()) return map;
9612 
9613   // Migrate to the newest map before transitioning to the new property.
9614   map = Update(map);
9615 
9616   PropertyNormalizationMode mode = map->is_prototype_map()
9617                                        ? KEEP_INOBJECT_PROPERTIES
9618                                        : CLEAR_INOBJECT_PROPERTIES;
9619 
9620   Map* maybe_transition =
9621       TransitionArray::SearchTransition(*map, kAccessor, *name, attributes);
9622   if (maybe_transition != NULL) {
9623     Handle<Map> transition(maybe_transition, isolate);
9624     DescriptorArray* descriptors = transition->instance_descriptors();
9625     int descriptor = transition->LastAdded();
9626     DCHECK(descriptors->GetKey(descriptor)->Equals(*name));
9627 
9628     DCHECK_EQ(kAccessor, descriptors->GetDetails(descriptor).kind());
9629     DCHECK_EQ(attributes, descriptors->GetDetails(descriptor).attributes());
9630 
9631     Handle<Object> maybe_pair(descriptors->GetValue(descriptor), isolate);
9632     if (!maybe_pair->IsAccessorPair()) {
9633       return Map::Normalize(map, mode, "TransitionToAccessorFromNonPair");
9634     }
9635 
9636     Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair);
9637     if (!pair->Equals(*getter, *setter)) {
9638       return Map::Normalize(map, mode, "TransitionToDifferentAccessor");
9639     }
9640 
9641     return transition;
9642   }
9643 
9644   Handle<AccessorPair> pair;
9645   DescriptorArray* old_descriptors = map->instance_descriptors();
9646   if (descriptor != DescriptorArray::kNotFound) {
9647     if (descriptor != map->LastAdded()) {
9648       return Map::Normalize(map, mode, "AccessorsOverwritingNonLast");
9649     }
9650     PropertyDetails old_details = old_descriptors->GetDetails(descriptor);
9651     if (old_details.type() != ACCESSOR_CONSTANT) {
9652       return Map::Normalize(map, mode, "AccessorsOverwritingNonAccessors");
9653     }
9654 
9655     if (old_details.attributes() != attributes) {
9656       return Map::Normalize(map, mode, "AccessorsWithAttributes");
9657     }
9658 
9659     Handle<Object> maybe_pair(old_descriptors->GetValue(descriptor), isolate);
9660     if (!maybe_pair->IsAccessorPair()) {
9661       return Map::Normalize(map, mode, "AccessorsOverwritingNonPair");
9662     }
9663 
9664     Handle<AccessorPair> current_pair = Handle<AccessorPair>::cast(maybe_pair);
9665     if (current_pair->Equals(*getter, *setter)) return map;
9666 
9667     bool overwriting_accessor = false;
9668     if (!getter->IsNull(isolate) &&
9669         !current_pair->get(ACCESSOR_GETTER)->IsNull(isolate) &&
9670         current_pair->get(ACCESSOR_GETTER) != *getter) {
9671       overwriting_accessor = true;
9672     }
9673     if (!setter->IsNull(isolate) &&
9674         !current_pair->get(ACCESSOR_SETTER)->IsNull(isolate) &&
9675         current_pair->get(ACCESSOR_SETTER) != *setter) {
9676       overwriting_accessor = true;
9677     }
9678     if (overwriting_accessor) {
9679       return Map::Normalize(map, mode, "AccessorsOverwritingAccessors");
9680     }
9681 
9682     pair = AccessorPair::Copy(Handle<AccessorPair>::cast(maybe_pair));
9683   } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors ||
9684              map->TooManyFastProperties(CERTAINLY_NOT_STORE_FROM_KEYED)) {
9685     return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, "TooManyAccessors");
9686   } else {
9687     pair = isolate->factory()->NewAccessorPair();
9688   }
9689 
9690   pair->SetComponents(*getter, *setter);
9691 
9692   TransitionFlag flag = INSERT_TRANSITION;
9693   AccessorConstantDescriptor new_desc(name, pair, attributes);
9694   return Map::CopyInsertDescriptor(map, &new_desc, flag);
9695 }
9696 
9697 
CopyAddDescriptor(Handle<Map> map,Descriptor * descriptor,TransitionFlag flag)9698 Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
9699                                    Descriptor* descriptor,
9700                                    TransitionFlag flag) {
9701   Handle<DescriptorArray> descriptors(map->instance_descriptors());
9702 
9703   // Share descriptors only if map owns descriptors and it not an initial map.
9704   if (flag == INSERT_TRANSITION && map->owns_descriptors() &&
9705       !map->GetBackPointer()->IsUndefined(map->GetIsolate()) &&
9706       TransitionArray::CanHaveMoreTransitions(map)) {
9707     return ShareDescriptor(map, descriptors, descriptor);
9708   }
9709 
9710   int nof = map->NumberOfOwnDescriptors();
9711   Handle<DescriptorArray> new_descriptors =
9712       DescriptorArray::CopyUpTo(descriptors, nof, 1);
9713   new_descriptors->Append(descriptor);
9714 
9715   Handle<LayoutDescriptor> new_layout_descriptor =
9716       FLAG_unbox_double_fields
9717           ? LayoutDescriptor::New(map, new_descriptors, nof + 1)
9718           : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
9719 
9720   return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9721                                 flag, descriptor->GetKey(), "CopyAddDescriptor",
9722                                 SIMPLE_PROPERTY_TRANSITION);
9723 }
9724 
9725 
CopyInsertDescriptor(Handle<Map> map,Descriptor * descriptor,TransitionFlag flag)9726 Handle<Map> Map::CopyInsertDescriptor(Handle<Map> map,
9727                                       Descriptor* descriptor,
9728                                       TransitionFlag flag) {
9729   Handle<DescriptorArray> old_descriptors(map->instance_descriptors());
9730 
9731   // We replace the key if it is already present.
9732   int index = old_descriptors->SearchWithCache(map->GetIsolate(),
9733                                                *descriptor->GetKey(), *map);
9734   if (index != DescriptorArray::kNotFound) {
9735     return CopyReplaceDescriptor(map, old_descriptors, descriptor, index, flag);
9736   }
9737   return CopyAddDescriptor(map, descriptor, flag);
9738 }
9739 
9740 
CopyUpTo(Handle<DescriptorArray> desc,int enumeration_index,int slack)9741 Handle<DescriptorArray> DescriptorArray::CopyUpTo(
9742     Handle<DescriptorArray> desc,
9743     int enumeration_index,
9744     int slack) {
9745   return DescriptorArray::CopyUpToAddAttributes(
9746       desc, enumeration_index, NONE, slack);
9747 }
9748 
9749 
CopyUpToAddAttributes(Handle<DescriptorArray> desc,int enumeration_index,PropertyAttributes attributes,int slack)9750 Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
9751     Handle<DescriptorArray> desc,
9752     int enumeration_index,
9753     PropertyAttributes attributes,
9754     int slack) {
9755   if (enumeration_index + slack == 0) {
9756     return desc->GetIsolate()->factory()->empty_descriptor_array();
9757   }
9758 
9759   int size = enumeration_index;
9760 
9761   Handle<DescriptorArray> descriptors =
9762       DescriptorArray::Allocate(desc->GetIsolate(), size, slack);
9763 
9764   if (attributes != NONE) {
9765     for (int i = 0; i < size; ++i) {
9766       Object* value = desc->GetValue(i);
9767       Name* key = desc->GetKey(i);
9768       PropertyDetails details = desc->GetDetails(i);
9769       // Bulk attribute changes never affect private properties.
9770       if (!key->IsPrivate()) {
9771         int mask = DONT_DELETE | DONT_ENUM;
9772         // READ_ONLY is an invalid attribute for JS setters/getters.
9773         if (details.type() != ACCESSOR_CONSTANT || !value->IsAccessorPair()) {
9774           mask |= READ_ONLY;
9775         }
9776         details = details.CopyAddAttributes(
9777             static_cast<PropertyAttributes>(attributes & mask));
9778       }
9779       Descriptor inner_desc(
9780           handle(key), handle(value, desc->GetIsolate()), details);
9781       descriptors->SetDescriptor(i, &inner_desc);
9782     }
9783   } else {
9784     for (int i = 0; i < size; ++i) {
9785       descriptors->CopyFrom(i, *desc);
9786     }
9787   }
9788 
9789   if (desc->number_of_descriptors() != enumeration_index) descriptors->Sort();
9790 
9791   return descriptors;
9792 }
9793 
9794 
IsEqualUpTo(DescriptorArray * desc,int nof_descriptors)9795 bool DescriptorArray::IsEqualUpTo(DescriptorArray* desc, int nof_descriptors) {
9796   for (int i = 0; i < nof_descriptors; i++) {
9797     if (GetKey(i) != desc->GetKey(i) || GetValue(i) != desc->GetValue(i)) {
9798       return false;
9799     }
9800     PropertyDetails details = GetDetails(i);
9801     PropertyDetails other_details = desc->GetDetails(i);
9802     if (details.type() != other_details.type() ||
9803         !details.representation().Equals(other_details.representation())) {
9804       return false;
9805     }
9806   }
9807   return true;
9808 }
9809 
9810 
CopyReplaceDescriptor(Handle<Map> map,Handle<DescriptorArray> descriptors,Descriptor * descriptor,int insertion_index,TransitionFlag flag)9811 Handle<Map> Map::CopyReplaceDescriptor(Handle<Map> map,
9812                                        Handle<DescriptorArray> descriptors,
9813                                        Descriptor* descriptor,
9814                                        int insertion_index,
9815                                        TransitionFlag flag) {
9816   Handle<Name> key = descriptor->GetKey();
9817   DCHECK(*key == descriptors->GetKey(insertion_index));
9818 
9819   Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
9820       descriptors, map->NumberOfOwnDescriptors());
9821 
9822   new_descriptors->Replace(insertion_index, descriptor);
9823   Handle<LayoutDescriptor> new_layout_descriptor = LayoutDescriptor::New(
9824       map, new_descriptors, new_descriptors->number_of_descriptors());
9825 
9826   SimpleTransitionFlag simple_flag =
9827       (insertion_index == descriptors->number_of_descriptors() - 1)
9828           ? SIMPLE_PROPERTY_TRANSITION
9829           : PROPERTY_TRANSITION;
9830   return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9831                                 flag, key, "CopyReplaceDescriptor",
9832                                 simple_flag);
9833 }
9834 
9835 // Helper class to manage a Map's code cache. The layout depends on the number
9836 // of entries; this is worthwhile because most code caches are very small,
9837 // but some are huge (thousands of entries).
9838 // For zero entries, the EmptyFixedArray is used.
9839 // For one entry, we use a 2-element FixedArray containing [name, code].
9840 // For 2..100 entries, we use a FixedArray with linear lookups, the layout is:
9841 //   [0] - number of slots that are currently in use
9842 //   [1] - first name
9843 //   [2] - first code
9844 //   [3] - second name
9845 //   [4] - second code
9846 //   etc.
9847 // For more than 128 entries, we use a CodeCacheHashTable.
9848 class CodeCache : public AllStatic {
9849  public:
9850   // Returns the new cache, to be stored on the map.
Put(Isolate * isolate,Handle<FixedArray> cache,Handle<Name> name,Handle<Code> code)9851   static Handle<FixedArray> Put(Isolate* isolate, Handle<FixedArray> cache,
9852                                 Handle<Name> name, Handle<Code> code) {
9853     int length = cache->length();
9854     if (length == 0) return PutFirstElement(isolate, name, code);
9855     if (length == kEntrySize) {
9856       return PutSecondElement(isolate, cache, name, code);
9857     }
9858     if (length <= kLinearMaxSize) {
9859       Handle<FixedArray> result = PutLinearElement(isolate, cache, name, code);
9860       if (!result.is_null()) return result;
9861       // Fall through if linear storage is getting too large.
9862     }
9863     return PutHashTableElement(isolate, cache, name, code);
9864   }
9865 
Lookup(FixedArray * cache,Name * name,Code::Flags flags)9866   static Code* Lookup(FixedArray* cache, Name* name, Code::Flags flags) {
9867     int length = cache->length();
9868     if (length == 0) return nullptr;
9869     if (length == kEntrySize) return OneElementLookup(cache, name, flags);
9870     if (!cache->IsCodeCacheHashTable()) {
9871       return LinearLookup(cache, name, flags);
9872     } else {
9873       return CodeCacheHashTable::cast(cache)->Lookup(name, flags);
9874     }
9875   }
9876 
9877  private:
9878   static const int kNameIndex = 0;
9879   static const int kCodeIndex = 1;
9880   static const int kEntrySize = 2;
9881 
9882   static const int kLinearUsageIndex = 0;
9883   static const int kLinearReservedSlots = 1;
9884   static const int kLinearInitialCapacity = 2;
9885   static const int kLinearMaxSize = 257;  // == LinearSizeFor(128);
9886 
9887   static const int kHashTableInitialCapacity = 200;  // Number of entries.
9888 
LinearSizeFor(int entries)9889   static int LinearSizeFor(int entries) {
9890     return kLinearReservedSlots + kEntrySize * entries;
9891   }
9892 
LinearNewSize(int old_size)9893   static int LinearNewSize(int old_size) {
9894     int old_entries = (old_size - kLinearReservedSlots) / kEntrySize;
9895     return LinearSizeFor(old_entries * 2);
9896   }
9897 
OneElementLookup(FixedArray * cache,Name * name,Code::Flags flags)9898   static Code* OneElementLookup(FixedArray* cache, Name* name,
9899                                 Code::Flags flags) {
9900     DCHECK_EQ(cache->length(), kEntrySize);
9901     if (cache->get(kNameIndex) != name) return nullptr;
9902     Code* maybe_code = Code::cast(cache->get(kCodeIndex));
9903     if (maybe_code->flags() != flags) return nullptr;
9904     return maybe_code;
9905   }
9906 
LinearLookup(FixedArray * cache,Name * name,Code::Flags flags)9907   static Code* LinearLookup(FixedArray* cache, Name* name, Code::Flags flags) {
9908     DCHECK_GE(cache->length(), kEntrySize);
9909     DCHECK(!cache->IsCodeCacheHashTable());
9910     int usage = GetLinearUsage(cache);
9911     for (int i = kLinearReservedSlots; i < usage; i += kEntrySize) {
9912       if (cache->get(i + kNameIndex) != name) continue;
9913       Code* code = Code::cast(cache->get(i + kCodeIndex));
9914       if (code->flags() == flags) return code;
9915     }
9916     return nullptr;
9917   }
9918 
PutFirstElement(Isolate * isolate,Handle<Name> name,Handle<Code> code)9919   static Handle<FixedArray> PutFirstElement(Isolate* isolate, Handle<Name> name,
9920                                             Handle<Code> code) {
9921     Handle<FixedArray> cache = isolate->factory()->NewFixedArray(kEntrySize);
9922     cache->set(kNameIndex, *name);
9923     cache->set(kCodeIndex, *code);
9924     return cache;
9925   }
9926 
PutSecondElement(Isolate * isolate,Handle<FixedArray> cache,Handle<Name> name,Handle<Code> code)9927   static Handle<FixedArray> PutSecondElement(Isolate* isolate,
9928                                              Handle<FixedArray> cache,
9929                                              Handle<Name> name,
9930                                              Handle<Code> code) {
9931     DCHECK_EQ(cache->length(), kEntrySize);
9932     Handle<FixedArray> new_cache = isolate->factory()->NewFixedArray(
9933         LinearSizeFor(kLinearInitialCapacity));
9934     new_cache->set(kLinearReservedSlots + kNameIndex, cache->get(kNameIndex));
9935     new_cache->set(kLinearReservedSlots + kCodeIndex, cache->get(kCodeIndex));
9936     new_cache->set(LinearSizeFor(1) + kNameIndex, *name);
9937     new_cache->set(LinearSizeFor(1) + kCodeIndex, *code);
9938     new_cache->set(kLinearUsageIndex, Smi::FromInt(LinearSizeFor(2)));
9939     return new_cache;
9940   }
9941 
PutLinearElement(Isolate * isolate,Handle<FixedArray> cache,Handle<Name> name,Handle<Code> code)9942   static Handle<FixedArray> PutLinearElement(Isolate* isolate,
9943                                              Handle<FixedArray> cache,
9944                                              Handle<Name> name,
9945                                              Handle<Code> code) {
9946     int length = cache->length();
9947     int usage = GetLinearUsage(*cache);
9948     DCHECK_LE(usage, length);
9949     // Check if we need to grow.
9950     if (usage == length) {
9951       int new_length = LinearNewSize(length);
9952       if (new_length > kLinearMaxSize) return Handle<FixedArray>::null();
9953       Handle<FixedArray> new_cache =
9954           isolate->factory()->NewFixedArray(new_length);
9955       for (int i = kLinearReservedSlots; i < length; i++) {
9956         new_cache->set(i, cache->get(i));
9957       }
9958       cache = new_cache;
9959     }
9960     // Store new entry.
9961     DCHECK_GE(cache->length(), usage + kEntrySize);
9962     cache->set(usage + kNameIndex, *name);
9963     cache->set(usage + kCodeIndex, *code);
9964     cache->set(kLinearUsageIndex, Smi::FromInt(usage + kEntrySize));
9965     return cache;
9966   }
9967 
PutHashTableElement(Isolate * isolate,Handle<FixedArray> cache,Handle<Name> name,Handle<Code> code)9968   static Handle<FixedArray> PutHashTableElement(Isolate* isolate,
9969                                                 Handle<FixedArray> cache,
9970                                                 Handle<Name> name,
9971                                                 Handle<Code> code) {
9972     // Check if we need to transition from linear to hash table storage.
9973     if (!cache->IsCodeCacheHashTable()) {
9974       // Check that the initial hash table capacity is large enough.
9975       DCHECK_EQ(kLinearMaxSize, LinearSizeFor(128));
9976       STATIC_ASSERT(kHashTableInitialCapacity > 128);
9977 
9978       int length = cache->length();
9979       // Only migrate from linear storage when it's full.
9980       DCHECK_EQ(length, GetLinearUsage(*cache));
9981       DCHECK_EQ(length, kLinearMaxSize);
9982       Handle<CodeCacheHashTable> table =
9983           CodeCacheHashTable::New(isolate, kHashTableInitialCapacity);
9984       HandleScope scope(isolate);
9985       for (int i = kLinearReservedSlots; i < length; i += kEntrySize) {
9986         Handle<Name> old_name(Name::cast(cache->get(i + kNameIndex)), isolate);
9987         Handle<Code> old_code(Code::cast(cache->get(i + kCodeIndex)), isolate);
9988         CodeCacheHashTable::Put(table, old_name, old_code);
9989       }
9990       cache = table;
9991     }
9992     // Store new entry.
9993     DCHECK(cache->IsCodeCacheHashTable());
9994     return CodeCacheHashTable::Put(Handle<CodeCacheHashTable>::cast(cache),
9995                                    name, code);
9996   }
9997 
GetLinearUsage(FixedArray * linear_cache)9998   static inline int GetLinearUsage(FixedArray* linear_cache) {
9999     DCHECK_GT(linear_cache->length(), kEntrySize);
10000     return Smi::cast(linear_cache->get(kLinearUsageIndex))->value();
10001   }
10002 };
10003 
UpdateCodeCache(Handle<Map> map,Handle<Name> name,Handle<Code> code)10004 void Map::UpdateCodeCache(Handle<Map> map,
10005                           Handle<Name> name,
10006                           Handle<Code> code) {
10007   Isolate* isolate = map->GetIsolate();
10008   Handle<FixedArray> cache(map->code_cache(), isolate);
10009   Handle<FixedArray> new_cache = CodeCache::Put(isolate, cache, name, code);
10010   map->set_code_cache(*new_cache);
10011 }
10012 
LookupInCodeCache(Name * name,Code::Flags flags)10013 Code* Map::LookupInCodeCache(Name* name, Code::Flags flags) {
10014   return CodeCache::Lookup(code_cache(), name, flags);
10015 }
10016 
10017 
10018 // The key in the code cache hash table consists of the property name and the
10019 // code object. The actual match is on the name and the code flags. If a key
10020 // is created using the flags and not a code object it can only be used for
10021 // lookup not to create a new entry.
10022 class CodeCacheHashTableKey : public HashTableKey {
10023  public:
CodeCacheHashTableKey(Handle<Name> name,Code::Flags flags)10024   CodeCacheHashTableKey(Handle<Name> name, Code::Flags flags)
10025       : name_(name), flags_(flags), code_() {
10026     DCHECK(name_->IsUniqueName());
10027   }
10028 
CodeCacheHashTableKey(Handle<Name> name,Handle<Code> code)10029   CodeCacheHashTableKey(Handle<Name> name, Handle<Code> code)
10030       : name_(name), flags_(code->flags()), code_(code) {
10031     DCHECK(name_->IsUniqueName());
10032   }
10033 
IsMatch(Object * other)10034   bool IsMatch(Object* other) override {
10035     DCHECK(other->IsFixedArray());
10036     FixedArray* pair = FixedArray::cast(other);
10037     Name* name = Name::cast(pair->get(0));
10038     Code::Flags flags = Code::cast(pair->get(1))->flags();
10039     if (flags != flags_) return false;
10040     DCHECK(name->IsUniqueName());
10041     return *name_ == name;
10042   }
10043 
NameFlagsHashHelper(Name * name,Code::Flags flags)10044   static uint32_t NameFlagsHashHelper(Name* name, Code::Flags flags) {
10045     return name->Hash() ^ flags;
10046   }
10047 
Hash()10048   uint32_t Hash() override { return NameFlagsHashHelper(*name_, flags_); }
10049 
HashForObject(Object * obj)10050   uint32_t HashForObject(Object* obj) override {
10051     FixedArray* pair = FixedArray::cast(obj);
10052     Name* name = Name::cast(pair->get(0));
10053     Code* code = Code::cast(pair->get(1));
10054     return NameFlagsHashHelper(name, code->flags());
10055   }
10056 
AsHandle(Isolate * isolate)10057   MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) override {
10058     Handle<Code> code = code_.ToHandleChecked();
10059     Handle<FixedArray> pair = isolate->factory()->NewFixedArray(2);
10060     pair->set(0, *name_);
10061     pair->set(1, *code);
10062     return pair;
10063   }
10064 
10065  private:
10066   Handle<Name> name_;
10067   Code::Flags flags_;
10068   // TODO(jkummerow): We should be able to get by without this.
10069   MaybeHandle<Code> code_;
10070 };
10071 
10072 
Put(Handle<CodeCacheHashTable> cache,Handle<Name> name,Handle<Code> code)10073 Handle<CodeCacheHashTable> CodeCacheHashTable::Put(
10074     Handle<CodeCacheHashTable> cache, Handle<Name> name, Handle<Code> code) {
10075   CodeCacheHashTableKey key(name, code);
10076 
10077   Handle<CodeCacheHashTable> new_cache = EnsureCapacity(cache, 1, &key);
10078 
10079   int entry = new_cache->FindInsertionEntry(key.Hash());
10080   Handle<Object> k = key.AsHandle(cache->GetIsolate());
10081 
10082   new_cache->set(EntryToIndex(entry), *k);
10083   new_cache->ElementAdded();
10084   return new_cache;
10085 }
10086 
Lookup(Name * name,Code::Flags flags)10087 Code* CodeCacheHashTable::Lookup(Name* name, Code::Flags flags) {
10088   DisallowHeapAllocation no_alloc;
10089   CodeCacheHashTableKey key(handle(name), flags);
10090   int entry = FindEntry(&key);
10091   if (entry == kNotFound) return nullptr;
10092   return Code::cast(FixedArray::cast(get(EntryToIndex(entry)))->get(1));
10093 }
10094 
SetAndGrow(Handle<FixedArray> array,int index,Handle<Object> value)10095 Handle<FixedArray> FixedArray::SetAndGrow(Handle<FixedArray> array, int index,
10096                                           Handle<Object> value) {
10097   if (index < array->length()) {
10098     array->set(index, *value);
10099     return array;
10100   }
10101   int capacity = array->length();
10102   do {
10103     capacity = JSObject::NewElementsCapacity(capacity);
10104   } while (capacity <= index);
10105   Handle<FixedArray> new_array =
10106       array->GetIsolate()->factory()->NewUninitializedFixedArray(capacity);
10107   array->CopyTo(0, *new_array, 0, array->length());
10108   new_array->FillWithHoles(array->length(), new_array->length());
10109   new_array->set(index, *value);
10110   return new_array;
10111 }
10112 
Shrink(int new_length)10113 void FixedArray::Shrink(int new_length) {
10114   DCHECK(0 <= new_length && new_length <= length());
10115   if (new_length < length()) {
10116     GetHeap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(
10117         this, length() - new_length);
10118   }
10119 }
10120 
10121 
CopyTo(int pos,FixedArray * dest,int dest_pos,int len)10122 void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
10123   DisallowHeapAllocation no_gc;
10124   WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
10125   for (int index = 0; index < len; index++) {
10126     dest->set(dest_pos+index, get(pos+index), mode);
10127   }
10128 }
10129 
10130 
10131 #ifdef DEBUG
IsEqualTo(FixedArray * other)10132 bool FixedArray::IsEqualTo(FixedArray* other) {
10133   if (length() != other->length()) return false;
10134   for (int i = 0 ; i < length(); ++i) {
10135     if (get(i) != other->get(i)) return false;
10136   }
10137   return true;
10138 }
10139 #endif
10140 
10141 
10142 // static
Set(Handle<WeakFixedArray> array,int index,Handle<HeapObject> value)10143 void WeakFixedArray::Set(Handle<WeakFixedArray> array, int index,
10144                          Handle<HeapObject> value) {
10145   DCHECK(array->IsEmptySlot(index));  // Don't overwrite anything.
10146   Handle<WeakCell> cell =
10147       value->IsMap() ? Map::WeakCellForMap(Handle<Map>::cast(value))
10148                      : array->GetIsolate()->factory()->NewWeakCell(value);
10149   Handle<FixedArray>::cast(array)->set(index + kFirstIndex, *cell);
10150   if (FLAG_trace_weak_arrays) {
10151     PrintF("[WeakFixedArray: storing at index %d ]\n", index);
10152   }
10153   array->set_last_used_index(index);
10154 }
10155 
10156 
10157 // static
Add(Handle<Object> maybe_array,Handle<HeapObject> value,int * assigned_index)10158 Handle<WeakFixedArray> WeakFixedArray::Add(Handle<Object> maybe_array,
10159                                            Handle<HeapObject> value,
10160                                            int* assigned_index) {
10161   Handle<WeakFixedArray> array =
10162       (maybe_array.is_null() || !maybe_array->IsWeakFixedArray())
10163           ? Allocate(value->GetIsolate(), 1, Handle<WeakFixedArray>::null())
10164           : Handle<WeakFixedArray>::cast(maybe_array);
10165   // Try to store the new entry if there's room. Optimize for consecutive
10166   // accesses.
10167   int first_index = array->last_used_index();
10168   int length = array->Length();
10169   if (length > 0) {
10170     for (int i = first_index;;) {
10171       if (array->IsEmptySlot((i))) {
10172         WeakFixedArray::Set(array, i, value);
10173         if (assigned_index != NULL) *assigned_index = i;
10174         return array;
10175       }
10176       if (FLAG_trace_weak_arrays) {
10177         PrintF("[WeakFixedArray: searching for free slot]\n");
10178       }
10179       i = (i + 1) % length;
10180       if (i == first_index) break;
10181     }
10182   }
10183 
10184   // No usable slot found, grow the array.
10185   int new_length = length == 0 ? 1 : length + (length >> 1) + 4;
10186   Handle<WeakFixedArray> new_array =
10187       Allocate(array->GetIsolate(), new_length, array);
10188   if (FLAG_trace_weak_arrays) {
10189     PrintF("[WeakFixedArray: growing to size %d ]\n", new_length);
10190   }
10191   WeakFixedArray::Set(new_array, length, value);
10192   if (assigned_index != NULL) *assigned_index = length;
10193   return new_array;
10194 }
10195 
10196 
10197 template <class CompactionCallback>
Compact()10198 void WeakFixedArray::Compact() {
10199   FixedArray* array = FixedArray::cast(this);
10200   int new_length = kFirstIndex;
10201   for (int i = kFirstIndex; i < array->length(); i++) {
10202     Object* element = array->get(i);
10203     if (element->IsSmi()) continue;
10204     if (WeakCell::cast(element)->cleared()) continue;
10205     Object* value = WeakCell::cast(element)->value();
10206     CompactionCallback::Callback(value, i - kFirstIndex,
10207                                  new_length - kFirstIndex);
10208     array->set(new_length++, element);
10209   }
10210   array->Shrink(new_length);
10211   set_last_used_index(0);
10212 }
10213 
10214 
Reset(Object * maybe_array)10215 void WeakFixedArray::Iterator::Reset(Object* maybe_array) {
10216   if (maybe_array->IsWeakFixedArray()) {
10217     list_ = WeakFixedArray::cast(maybe_array);
10218     index_ = 0;
10219 #ifdef DEBUG
10220     last_used_index_ = list_->last_used_index();
10221 #endif  // DEBUG
10222   }
10223 }
10224 
10225 
Callback(Object * value,int old_index,int new_index)10226 void JSObject::PrototypeRegistryCompactionCallback::Callback(Object* value,
10227                                                              int old_index,
10228                                                              int new_index) {
10229   DCHECK(value->IsMap() && Map::cast(value)->is_prototype_map());
10230   Map* map = Map::cast(value);
10231   DCHECK(map->prototype_info()->IsPrototypeInfo());
10232   PrototypeInfo* proto_info = PrototypeInfo::cast(map->prototype_info());
10233   DCHECK_EQ(old_index, proto_info->registry_slot());
10234   proto_info->set_registry_slot(new_index);
10235 }
10236 
10237 
10238 template void WeakFixedArray::Compact<WeakFixedArray::NullCallback>();
10239 template void
10240 WeakFixedArray::Compact<JSObject::PrototypeRegistryCompactionCallback>();
10241 
10242 
Remove(Handle<HeapObject> value)10243 bool WeakFixedArray::Remove(Handle<HeapObject> value) {
10244   if (Length() == 0) return false;
10245   // Optimize for the most recently added element to be removed again.
10246   int first_index = last_used_index();
10247   for (int i = first_index;;) {
10248     if (Get(i) == *value) {
10249       Clear(i);
10250       // Users of WeakFixedArray should make sure that there are no duplicates.
10251       return true;
10252     }
10253     i = (i + 1) % Length();
10254     if (i == first_index) return false;
10255   }
10256   UNREACHABLE();
10257 }
10258 
10259 
10260 // static
Allocate(Isolate * isolate,int size,Handle<WeakFixedArray> initialize_from)10261 Handle<WeakFixedArray> WeakFixedArray::Allocate(
10262     Isolate* isolate, int size, Handle<WeakFixedArray> initialize_from) {
10263   DCHECK(0 <= size);
10264   Handle<FixedArray> result =
10265       isolate->factory()->NewUninitializedFixedArray(size + kFirstIndex);
10266   int index = 0;
10267   if (!initialize_from.is_null()) {
10268     DCHECK(initialize_from->Length() <= size);
10269     Handle<FixedArray> raw_source = Handle<FixedArray>::cast(initialize_from);
10270     // Copy the entries without compacting, since the PrototypeInfo relies on
10271     // the index of the entries not to change.
10272     while (index < raw_source->length()) {
10273       result->set(index, raw_source->get(index));
10274       index++;
10275     }
10276   }
10277   while (index < result->length()) {
10278     result->set(index, Smi::kZero);
10279     index++;
10280   }
10281   return Handle<WeakFixedArray>::cast(result);
10282 }
10283 
10284 
Add(Handle<ArrayList> array,Handle<Object> obj,AddMode mode)10285 Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj,
10286                                  AddMode mode) {
10287   int length = array->Length();
10288   array = EnsureSpace(array, length + 1);
10289   if (mode == kReloadLengthAfterAllocation) {
10290     DCHECK(array->Length() <= length);
10291     length = array->Length();
10292   }
10293   array->Set(length, *obj);
10294   array->SetLength(length + 1);
10295   return array;
10296 }
10297 
Add(Handle<ArrayList> array,Handle<Object> obj1,Handle<Object> obj2,AddMode mode)10298 Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj1,
10299                                  Handle<Object> obj2, AddMode mode) {
10300   int length = array->Length();
10301   array = EnsureSpace(array, length + 2);
10302   if (mode == kReloadLengthAfterAllocation) {
10303     length = array->Length();
10304   }
10305   array->Set(length, *obj1);
10306   array->Set(length + 1, *obj2);
10307   array->SetLength(length + 2);
10308   return array;
10309 }
10310 
10311 
IsFull()10312 bool ArrayList::IsFull() {
10313   int capacity = length();
10314   return kFirstIndex + Length() == capacity;
10315 }
10316 
10317 namespace {
10318 
EnsureSpaceInFixedArray(Handle<FixedArray> array,int length)10319 Handle<FixedArray> EnsureSpaceInFixedArray(Handle<FixedArray> array,
10320                                            int length) {
10321   int capacity = array->length();
10322   if (capacity < length) {
10323     Isolate* isolate = array->GetIsolate();
10324     int new_capacity = length;
10325     new_capacity = new_capacity + Max(new_capacity / 2, 2);
10326     int grow_by = new_capacity - capacity;
10327     array = Handle<ArrayList>::cast(
10328         isolate->factory()->CopyFixedArrayAndGrow(array, grow_by));
10329   }
10330   return array;
10331 }
10332 
10333 }  // namespace
10334 
EnsureSpace(Handle<ArrayList> array,int length)10335 Handle<ArrayList> ArrayList::EnsureSpace(Handle<ArrayList> array, int length) {
10336   const bool empty = (array->length() == 0);
10337   auto ret = Handle<ArrayList>::cast(
10338       EnsureSpaceInFixedArray(array, kFirstIndex + length));
10339   if (empty) ret->SetLength(0);
10340   return ret;
10341 }
10342 
ReserveCaptures(Handle<RegExpMatchInfo> match_info,int capture_count)10343 Handle<RegExpMatchInfo> RegExpMatchInfo::ReserveCaptures(
10344     Handle<RegExpMatchInfo> match_info, int capture_count) {
10345   DCHECK_GE(match_info->length(), kLastMatchOverhead);
10346   const int required_length = kFirstCaptureIndex + capture_count;
10347   Handle<FixedArray> result =
10348       EnsureSpaceInFixedArray(match_info, required_length);
10349   return Handle<RegExpMatchInfo>::cast(result);
10350 }
10351 
10352 // static
AppendJSFrame(Handle<FrameArray> in,Handle<Object> receiver,Handle<JSFunction> function,Handle<AbstractCode> code,int offset,int flags)10353 Handle<FrameArray> FrameArray::AppendJSFrame(Handle<FrameArray> in,
10354                                              Handle<Object> receiver,
10355                                              Handle<JSFunction> function,
10356                                              Handle<AbstractCode> code,
10357                                              int offset, int flags) {
10358   const int frame_count = in->FrameCount();
10359   const int new_length = LengthFor(frame_count + 1);
10360   Handle<FrameArray> array = EnsureSpace(in, new_length);
10361   array->SetReceiver(frame_count, *receiver);
10362   array->SetFunction(frame_count, *function);
10363   array->SetCode(frame_count, *code);
10364   array->SetOffset(frame_count, Smi::FromInt(offset));
10365   array->SetFlags(frame_count, Smi::FromInt(flags));
10366   array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));
10367   return array;
10368 }
10369 
10370 // static
AppendWasmFrame(Handle<FrameArray> in,Handle<Object> wasm_instance,int wasm_function_index,Handle<AbstractCode> code,int offset,int flags)10371 Handle<FrameArray> FrameArray::AppendWasmFrame(Handle<FrameArray> in,
10372                                                Handle<Object> wasm_instance,
10373                                                int wasm_function_index,
10374                                                Handle<AbstractCode> code,
10375                                                int offset, int flags) {
10376   const int frame_count = in->FrameCount();
10377   const int new_length = LengthFor(frame_count + 1);
10378   Handle<FrameArray> array = EnsureSpace(in, new_length);
10379   array->SetWasmInstance(frame_count, *wasm_instance);
10380   array->SetWasmFunctionIndex(frame_count, Smi::FromInt(wasm_function_index));
10381   array->SetCode(frame_count, *code);
10382   array->SetOffset(frame_count, Smi::FromInt(offset));
10383   array->SetFlags(frame_count, Smi::FromInt(flags));
10384   array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));
10385   return array;
10386 }
10387 
ShrinkToFit()10388 void FrameArray::ShrinkToFit() { Shrink(LengthFor(FrameCount())); }
10389 
10390 // static
EnsureSpace(Handle<FrameArray> array,int length)10391 Handle<FrameArray> FrameArray::EnsureSpace(Handle<FrameArray> array,
10392                                            int length) {
10393   return Handle<FrameArray>::cast(EnsureSpaceInFixedArray(array, length));
10394 }
10395 
Allocate(Isolate * isolate,int number_of_descriptors,int slack,PretenureFlag pretenure)10396 Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate,
10397                                                   int number_of_descriptors,
10398                                                   int slack,
10399                                                   PretenureFlag pretenure) {
10400   DCHECK(0 <= number_of_descriptors);
10401   Factory* factory = isolate->factory();
10402   // Do not use DescriptorArray::cast on incomplete object.
10403   int size = number_of_descriptors + slack;
10404   if (size == 0) return factory->empty_descriptor_array();
10405   // Allocate the array of keys.
10406   Handle<FixedArray> result =
10407       factory->NewFixedArray(LengthFor(size), pretenure);
10408 
10409   result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors));
10410   result->set(kEnumCacheIndex, Smi::kZero);
10411   return Handle<DescriptorArray>::cast(result);
10412 }
10413 
ClearEnumCache()10414 void DescriptorArray::ClearEnumCache() { set(kEnumCacheIndex, Smi::kZero); }
10415 
Replace(int index,Descriptor * descriptor)10416 void DescriptorArray::Replace(int index, Descriptor* descriptor) {
10417   descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index));
10418   Set(index, descriptor);
10419 }
10420 
10421 
10422 // static
SetEnumCache(Handle<DescriptorArray> descriptors,Isolate * isolate,Handle<FixedArray> new_cache,Handle<FixedArray> new_index_cache)10423 void DescriptorArray::SetEnumCache(Handle<DescriptorArray> descriptors,
10424                                    Isolate* isolate,
10425                                    Handle<FixedArray> new_cache,
10426                                    Handle<FixedArray> new_index_cache) {
10427   DCHECK(!descriptors->IsEmpty());
10428   FixedArray* bridge_storage;
10429   bool needs_new_enum_cache = !descriptors->HasEnumCache();
10430   if (needs_new_enum_cache) {
10431     bridge_storage = *isolate->factory()->NewFixedArray(
10432         DescriptorArray::kEnumCacheBridgeLength);
10433   } else {
10434     bridge_storage = FixedArray::cast(descriptors->get(kEnumCacheIndex));
10435   }
10436   bridge_storage->set(kEnumCacheBridgeCacheIndex, *new_cache);
10437   bridge_storage->set(
10438       kEnumCacheBridgeIndicesCacheIndex,
10439       new_index_cache.is_null() ? Object::cast(Smi::kZero) : *new_index_cache);
10440   if (needs_new_enum_cache) {
10441     descriptors->set(kEnumCacheIndex, bridge_storage);
10442   }
10443 }
10444 
10445 
CopyFrom(int index,DescriptorArray * src)10446 void DescriptorArray::CopyFrom(int index, DescriptorArray* src) {
10447   Object* value = src->GetValue(index);
10448   PropertyDetails details = src->GetDetails(index);
10449   Descriptor desc(handle(src->GetKey(index)),
10450                   handle(value, src->GetIsolate()),
10451                   details);
10452   SetDescriptor(index, &desc);
10453 }
10454 
10455 
Sort()10456 void DescriptorArray::Sort() {
10457   // In-place heap sort.
10458   int len = number_of_descriptors();
10459   // Reset sorting since the descriptor array might contain invalid pointers.
10460   for (int i = 0; i < len; ++i) SetSortedKey(i, i);
10461   // Bottom-up max-heap construction.
10462   // Index of the last node with children
10463   const int max_parent_index = (len / 2) - 1;
10464   for (int i = max_parent_index; i >= 0; --i) {
10465     int parent_index = i;
10466     const uint32_t parent_hash = GetSortedKey(i)->Hash();
10467     while (parent_index <= max_parent_index) {
10468       int child_index = 2 * parent_index + 1;
10469       uint32_t child_hash = GetSortedKey(child_index)->Hash();
10470       if (child_index + 1 < len) {
10471         uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
10472         if (right_child_hash > child_hash) {
10473           child_index++;
10474           child_hash = right_child_hash;
10475         }
10476       }
10477       if (child_hash <= parent_hash) break;
10478       SwapSortedKeys(parent_index, child_index);
10479       // Now element at child_index could be < its children.
10480       parent_index = child_index;  // parent_hash remains correct.
10481     }
10482   }
10483 
10484   // Extract elements and create sorted array.
10485   for (int i = len - 1; i > 0; --i) {
10486     // Put max element at the back of the array.
10487     SwapSortedKeys(0, i);
10488     // Shift down the new top element.
10489     int parent_index = 0;
10490     const uint32_t parent_hash = GetSortedKey(parent_index)->Hash();
10491     const int max_parent_index = (i / 2) - 1;
10492     while (parent_index <= max_parent_index) {
10493       int child_index = parent_index * 2 + 1;
10494       uint32_t child_hash = GetSortedKey(child_index)->Hash();
10495       if (child_index + 1 < i) {
10496         uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
10497         if (right_child_hash > child_hash) {
10498           child_index++;
10499           child_hash = right_child_hash;
10500         }
10501       }
10502       if (child_hash <= parent_hash) break;
10503       SwapSortedKeys(parent_index, child_index);
10504       parent_index = child_index;
10505     }
10506   }
10507   DCHECK(IsSortedNoDuplicates());
10508 }
10509 
10510 
Copy(Handle<AccessorPair> pair)10511 Handle<AccessorPair> AccessorPair::Copy(Handle<AccessorPair> pair) {
10512   Handle<AccessorPair> copy = pair->GetIsolate()->factory()->NewAccessorPair();
10513   copy->set_getter(pair->getter());
10514   copy->set_setter(pair->setter());
10515   return copy;
10516 }
10517 
GetComponent(Handle<AccessorPair> accessor_pair,AccessorComponent component)10518 Handle<Object> AccessorPair::GetComponent(Handle<AccessorPair> accessor_pair,
10519                                           AccessorComponent component) {
10520   Object* accessor = accessor_pair->get(component);
10521   if (accessor->IsFunctionTemplateInfo()) {
10522     return ApiNatives::InstantiateFunction(
10523                handle(FunctionTemplateInfo::cast(accessor)))
10524         .ToHandleChecked();
10525   }
10526   Isolate* isolate = accessor_pair->GetIsolate();
10527   if (accessor->IsNull(isolate)) {
10528     return isolate->factory()->undefined_value();
10529   }
10530   return handle(accessor, isolate);
10531 }
10532 
New(Isolate * isolate,int deopt_entry_count,PretenureFlag pretenure)10533 Handle<DeoptimizationInputData> DeoptimizationInputData::New(
10534     Isolate* isolate, int deopt_entry_count, PretenureFlag pretenure) {
10535   return Handle<DeoptimizationInputData>::cast(
10536       isolate->factory()->NewFixedArray(LengthFor(deopt_entry_count),
10537                                         pretenure));
10538 }
10539 
10540 
New(Isolate * isolate,int number_of_deopt_points,PretenureFlag pretenure)10541 Handle<DeoptimizationOutputData> DeoptimizationOutputData::New(
10542     Isolate* isolate,
10543     int number_of_deopt_points,
10544     PretenureFlag pretenure) {
10545   Handle<FixedArray> result;
10546   if (number_of_deopt_points == 0) {
10547     result = isolate->factory()->empty_fixed_array();
10548   } else {
10549     result = isolate->factory()->NewFixedArray(
10550         LengthOfFixedArray(number_of_deopt_points), pretenure);
10551   }
10552   return Handle<DeoptimizationOutputData>::cast(result);
10553 }
10554 
GetInlinedFunction(int index)10555 SharedFunctionInfo* DeoptimizationInputData::GetInlinedFunction(int index) {
10556   if (index == -1) {
10557     return SharedFunctionInfo::cast(this->SharedFunctionInfo());
10558   } else {
10559     return SharedFunctionInfo::cast(LiteralArray()->get(index));
10560   }
10561 }
10562 
10563 const int LiteralsArray::kFeedbackVectorOffset =
10564     LiteralsArray::OffsetOfElementAt(LiteralsArray::kVectorIndex);
10565 
10566 const int LiteralsArray::kOffsetToFirstLiteral =
10567     LiteralsArray::OffsetOfElementAt(LiteralsArray::kFirstLiteralIndex);
10568 
10569 // static
New(Isolate * isolate,Handle<TypeFeedbackVector> vector,int number_of_literals,PretenureFlag pretenure)10570 Handle<LiteralsArray> LiteralsArray::New(Isolate* isolate,
10571                                          Handle<TypeFeedbackVector> vector,
10572                                          int number_of_literals,
10573                                          PretenureFlag pretenure) {
10574   if (vector->is_empty() && number_of_literals == 0) {
10575     return Handle<LiteralsArray>::cast(
10576         isolate->factory()->empty_literals_array());
10577   }
10578   Handle<FixedArray> literals = isolate->factory()->NewFixedArray(
10579       number_of_literals + kFirstLiteralIndex, pretenure);
10580   Handle<LiteralsArray> casted_literals = Handle<LiteralsArray>::cast(literals);
10581   casted_literals->set_feedback_vector(*vector);
10582   return casted_literals;
10583 }
10584 
LookupRange(int pc_offset,int * data_out,CatchPrediction * prediction_out)10585 int HandlerTable::LookupRange(int pc_offset, int* data_out,
10586                               CatchPrediction* prediction_out) {
10587   int innermost_handler = -1;
10588 #ifdef DEBUG
10589   // Assuming that ranges are well nested, we don't need to track the innermost
10590   // offsets. This is just to verify that the table is actually well nested.
10591   int innermost_start = std::numeric_limits<int>::min();
10592   int innermost_end = std::numeric_limits<int>::max();
10593 #endif
10594   for (int i = 0; i < length(); i += kRangeEntrySize) {
10595     int start_offset = Smi::cast(get(i + kRangeStartIndex))->value();
10596     int end_offset = Smi::cast(get(i + kRangeEndIndex))->value();
10597     int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value();
10598     int handler_offset = HandlerOffsetField::decode(handler_field);
10599     CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
10600     int handler_data = Smi::cast(get(i + kRangeDataIndex))->value();
10601     if (pc_offset > start_offset && pc_offset <= end_offset) {
10602       DCHECK_GE(start_offset, innermost_start);
10603       DCHECK_LT(end_offset, innermost_end);
10604       innermost_handler = handler_offset;
10605 #ifdef DEBUG
10606       innermost_start = start_offset;
10607       innermost_end = end_offset;
10608 #endif
10609       if (data_out) *data_out = handler_data;
10610       if (prediction_out) *prediction_out = prediction;
10611     }
10612   }
10613   return innermost_handler;
10614 }
10615 
10616 
10617 // TODO(turbofan): Make sure table is sorted and use binary search.
LookupReturn(int pc_offset)10618 int HandlerTable::LookupReturn(int pc_offset) {
10619   for (int i = 0; i < length(); i += kReturnEntrySize) {
10620     int return_offset = Smi::cast(get(i + kReturnOffsetIndex))->value();
10621     int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value();
10622     if (pc_offset == return_offset) {
10623       return HandlerOffsetField::decode(handler_field);
10624     }
10625   }
10626   return -1;
10627 }
10628 
10629 
10630 #ifdef DEBUG
IsEqualTo(DescriptorArray * other)10631 bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
10632   if (IsEmpty()) return other->IsEmpty();
10633   if (other->IsEmpty()) return false;
10634   if (length() != other->length()) return false;
10635   for (int i = 0; i < length(); ++i) {
10636     if (get(i) != other->get(i)) return false;
10637   }
10638   return true;
10639 }
10640 #endif
10641 
10642 // static
Trim(Handle<String> string,TrimMode mode)10643 Handle<String> String::Trim(Handle<String> string, TrimMode mode) {
10644   Isolate* const isolate = string->GetIsolate();
10645   string = String::Flatten(string);
10646   int const length = string->length();
10647 
10648   // Perform left trimming if requested.
10649   int left = 0;
10650   UnicodeCache* unicode_cache = isolate->unicode_cache();
10651   if (mode == kTrim || mode == kTrimLeft) {
10652     while (left < length &&
10653            unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) {
10654       left++;
10655     }
10656   }
10657 
10658   // Perform right trimming if requested.
10659   int right = length;
10660   if (mode == kTrim || mode == kTrimRight) {
10661     while (
10662         right > left &&
10663         unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) {
10664       right--;
10665     }
10666   }
10667 
10668   return isolate->factory()->NewSubString(string, left, right);
10669 }
10670 
LooksValid()10671 bool String::LooksValid() {
10672   if (!GetIsolate()->heap()->Contains(this)) return false;
10673   return true;
10674 }
10675 
10676 
10677 // static
ToFunctionName(Handle<Name> name)10678 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) {
10679   if (name->IsString()) return Handle<String>::cast(name);
10680   // ES6 section 9.2.11 SetFunctionName, step 4.
10681   Isolate* const isolate = name->GetIsolate();
10682   Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate);
10683   if (description->IsUndefined(isolate)) {
10684     return isolate->factory()->empty_string();
10685   }
10686   IncrementalStringBuilder builder(isolate);
10687   builder.AppendCharacter('[');
10688   builder.AppendString(Handle<String>::cast(description));
10689   builder.AppendCharacter(']');
10690   return builder.Finish();
10691 }
10692 
10693 // static
ToFunctionName(Handle<Name> name,Handle<String> prefix)10694 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name,
10695                                          Handle<String> prefix) {
10696   Handle<String> name_string;
10697   Isolate* const isolate = name->GetIsolate();
10698   ASSIGN_RETURN_ON_EXCEPTION(isolate, name_string, ToFunctionName(name),
10699                              String);
10700   IncrementalStringBuilder builder(isolate);
10701   builder.AppendString(prefix);
10702   builder.AppendCharacter(' ');
10703   builder.AppendString(name_string);
10704   return builder.Finish();
10705 }
10706 
10707 namespace {
10708 
AreDigits(const uint8_t * s,int from,int to)10709 bool AreDigits(const uint8_t* s, int from, int to) {
10710   for (int i = from; i < to; i++) {
10711     if (s[i] < '0' || s[i] > '9') return false;
10712   }
10713 
10714   return true;
10715 }
10716 
10717 
ParseDecimalInteger(const uint8_t * s,int from,int to)10718 int ParseDecimalInteger(const uint8_t* s, int from, int to) {
10719   DCHECK(to - from < 10);  // Overflow is not possible.
10720   DCHECK(from < to);
10721   int d = s[from] - '0';
10722 
10723   for (int i = from + 1; i < to; i++) {
10724     d = 10 * d + (s[i] - '0');
10725   }
10726 
10727   return d;
10728 }
10729 
10730 }  // namespace
10731 
10732 
10733 // static
ToNumber(Handle<String> subject)10734 Handle<Object> String::ToNumber(Handle<String> subject) {
10735   Isolate* const isolate = subject->GetIsolate();
10736 
10737   // Flatten {subject} string first.
10738   subject = String::Flatten(subject);
10739 
10740   // Fast array index case.
10741   uint32_t index;
10742   if (subject->AsArrayIndex(&index)) {
10743     return isolate->factory()->NewNumberFromUint(index);
10744   }
10745 
10746   // Fast case: short integer or some sorts of junk values.
10747   if (subject->IsSeqOneByteString()) {
10748     int len = subject->length();
10749     if (len == 0) return handle(Smi::kZero, isolate);
10750 
10751     DisallowHeapAllocation no_gc;
10752     uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars();
10753     bool minus = (data[0] == '-');
10754     int start_pos = (minus ? 1 : 0);
10755 
10756     if (start_pos == len) {
10757       return isolate->factory()->nan_value();
10758     } else if (data[start_pos] > '9') {
10759       // Fast check for a junk value. A valid string may start from a
10760       // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit
10761       // or the 'I' character ('Infinity'). All of that have codes not greater
10762       // than '9' except 'I' and &nbsp;.
10763       if (data[start_pos] != 'I' && data[start_pos] != 0xa0) {
10764         return isolate->factory()->nan_value();
10765       }
10766     } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
10767       // The maximal/minimal smi has 10 digits. If the string has less digits
10768       // we know it will fit into the smi-data type.
10769       int d = ParseDecimalInteger(data, start_pos, len);
10770       if (minus) {
10771         if (d == 0) return isolate->factory()->minus_zero_value();
10772         d = -d;
10773       } else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize &&
10774                  (len == 1 || data[0] != '0')) {
10775         // String hash is not calculated yet but all the data are present.
10776         // Update the hash field to speed up sequential convertions.
10777         uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
10778 #ifdef DEBUG
10779         subject->Hash();  // Force hash calculation.
10780         DCHECK_EQ(static_cast<int>(subject->hash_field()),
10781                   static_cast<int>(hash));
10782 #endif
10783         subject->set_hash_field(hash);
10784       }
10785       return handle(Smi::FromInt(d), isolate);
10786     }
10787   }
10788 
10789   // Slower case.
10790   int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY;
10791   return isolate->factory()->NewNumber(
10792       StringToDouble(isolate->unicode_cache(), subject, flags));
10793 }
10794 
10795 
GetFlatContent()10796 String::FlatContent String::GetFlatContent() {
10797   DCHECK(!AllowHeapAllocation::IsAllowed());
10798   int length = this->length();
10799   StringShape shape(this);
10800   String* string = this;
10801   int offset = 0;
10802   if (shape.representation_tag() == kConsStringTag) {
10803     ConsString* cons = ConsString::cast(string);
10804     if (cons->second()->length() != 0) {
10805       return FlatContent();
10806     }
10807     string = cons->first();
10808     shape = StringShape(string);
10809   }
10810   if (shape.representation_tag() == kSlicedStringTag) {
10811     SlicedString* slice = SlicedString::cast(string);
10812     offset = slice->offset();
10813     string = slice->parent();
10814     shape = StringShape(string);
10815     DCHECK(shape.representation_tag() != kConsStringTag &&
10816            shape.representation_tag() != kSlicedStringTag);
10817   }
10818   if (shape.encoding_tag() == kOneByteStringTag) {
10819     const uint8_t* start;
10820     if (shape.representation_tag() == kSeqStringTag) {
10821       start = SeqOneByteString::cast(string)->GetChars();
10822     } else {
10823       start = ExternalOneByteString::cast(string)->GetChars();
10824     }
10825     return FlatContent(start + offset, length);
10826   } else {
10827     DCHECK(shape.encoding_tag() == kTwoByteStringTag);
10828     const uc16* start;
10829     if (shape.representation_tag() == kSeqStringTag) {
10830       start = SeqTwoByteString::cast(string)->GetChars();
10831     } else {
10832       start = ExternalTwoByteString::cast(string)->GetChars();
10833     }
10834     return FlatContent(start + offset, length);
10835   }
10836 }
10837 
ToCString(AllowNullsFlag allow_nulls,RobustnessFlag robust_flag,int offset,int length,int * length_return)10838 std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
10839                                           RobustnessFlag robust_flag,
10840                                           int offset, int length,
10841                                           int* length_return) {
10842   if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
10843     return std::unique_ptr<char[]>();
10844   }
10845   // Negative length means the to the end of the string.
10846   if (length < 0) length = kMaxInt - offset;
10847 
10848   // Compute the size of the UTF-8 string. Start at the specified offset.
10849   StringCharacterStream stream(this, offset);
10850   int character_position = offset;
10851   int utf8_bytes = 0;
10852   int last = unibrow::Utf16::kNoPreviousCharacter;
10853   while (stream.HasMore() && character_position++ < offset + length) {
10854     uint16_t character = stream.GetNext();
10855     utf8_bytes += unibrow::Utf8::Length(character, last);
10856     last = character;
10857   }
10858 
10859   if (length_return) {
10860     *length_return = utf8_bytes;
10861   }
10862 
10863   char* result = NewArray<char>(utf8_bytes + 1);
10864 
10865   // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
10866   stream.Reset(this, offset);
10867   character_position = offset;
10868   int utf8_byte_position = 0;
10869   last = unibrow::Utf16::kNoPreviousCharacter;
10870   while (stream.HasMore() && character_position++ < offset + length) {
10871     uint16_t character = stream.GetNext();
10872     if (allow_nulls == DISALLOW_NULLS && character == 0) {
10873       character = ' ';
10874     }
10875     utf8_byte_position +=
10876         unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
10877     last = character;
10878   }
10879   result[utf8_byte_position] = 0;
10880   return std::unique_ptr<char[]>(result);
10881 }
10882 
ToCString(AllowNullsFlag allow_nulls,RobustnessFlag robust_flag,int * length_return)10883 std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
10884                                           RobustnessFlag robust_flag,
10885                                           int* length_return) {
10886   return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
10887 }
10888 
10889 
GetTwoByteData(unsigned start)10890 const uc16* String::GetTwoByteData(unsigned start) {
10891   DCHECK(!IsOneByteRepresentationUnderneath());
10892   switch (StringShape(this).representation_tag()) {
10893     case kSeqStringTag:
10894       return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
10895     case kExternalStringTag:
10896       return ExternalTwoByteString::cast(this)->
10897         ExternalTwoByteStringGetData(start);
10898     case kSlicedStringTag: {
10899       SlicedString* slice = SlicedString::cast(this);
10900       return slice->parent()->GetTwoByteData(start + slice->offset());
10901     }
10902     case kConsStringTag:
10903       UNREACHABLE();
10904       return NULL;
10905   }
10906   UNREACHABLE();
10907   return NULL;
10908 }
10909 
10910 
SeqTwoByteStringGetData(unsigned start)10911 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
10912   return reinterpret_cast<uc16*>(
10913       reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
10914 }
10915 
10916 
PostGarbageCollectionProcessing(Isolate * isolate)10917 void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) {
10918   Relocatable* current = isolate->relocatable_top();
10919   while (current != NULL) {
10920     current->PostGarbageCollection();
10921     current = current->prev_;
10922   }
10923 }
10924 
10925 
10926 // Reserve space for statics needing saving and restoring.
ArchiveSpacePerThread()10927 int Relocatable::ArchiveSpacePerThread() {
10928   return sizeof(Relocatable*);  // NOLINT
10929 }
10930 
10931 
10932 // Archive statics that are thread-local.
ArchiveState(Isolate * isolate,char * to)10933 char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
10934   *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
10935   isolate->set_relocatable_top(NULL);
10936   return to + ArchiveSpacePerThread();
10937 }
10938 
10939 
10940 // Restore statics that are thread-local.
RestoreState(Isolate * isolate,char * from)10941 char* Relocatable::RestoreState(Isolate* isolate, char* from) {
10942   isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
10943   return from + ArchiveSpacePerThread();
10944 }
10945 
10946 
Iterate(ObjectVisitor * v,char * thread_storage)10947 char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
10948   Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
10949   Iterate(v, top);
10950   return thread_storage + ArchiveSpacePerThread();
10951 }
10952 
10953 
Iterate(Isolate * isolate,ObjectVisitor * v)10954 void Relocatable::Iterate(Isolate* isolate, ObjectVisitor* v) {
10955   Iterate(v, isolate->relocatable_top());
10956 }
10957 
10958 
Iterate(ObjectVisitor * v,Relocatable * top)10959 void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
10960   Relocatable* current = top;
10961   while (current != NULL) {
10962     current->IterateInstance(v);
10963     current = current->prev_;
10964   }
10965 }
10966 
10967 
FlatStringReader(Isolate * isolate,Handle<String> str)10968 FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
10969     : Relocatable(isolate),
10970       str_(str.location()),
10971       length_(str->length()) {
10972   PostGarbageCollection();
10973 }
10974 
10975 
FlatStringReader(Isolate * isolate,Vector<const char> input)10976 FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
10977     : Relocatable(isolate),
10978       str_(0),
10979       is_one_byte_(true),
10980       length_(input.length()),
10981       start_(input.start()) {}
10982 
10983 
PostGarbageCollection()10984 void FlatStringReader::PostGarbageCollection() {
10985   if (str_ == NULL) return;
10986   Handle<String> str(str_);
10987   DCHECK(str->IsFlat());
10988   DisallowHeapAllocation no_gc;
10989   // This does not actually prevent the vector from being relocated later.
10990   String::FlatContent content = str->GetFlatContent();
10991   DCHECK(content.IsFlat());
10992   is_one_byte_ = content.IsOneByte();
10993   if (is_one_byte_) {
10994     start_ = content.ToOneByteVector().start();
10995   } else {
10996     start_ = content.ToUC16Vector().start();
10997   }
10998 }
10999 
11000 
Initialize(ConsString * cons_string,int offset)11001 void ConsStringIterator::Initialize(ConsString* cons_string, int offset) {
11002   DCHECK(cons_string != NULL);
11003   root_ = cons_string;
11004   consumed_ = offset;
11005   // Force stack blown condition to trigger restart.
11006   depth_ = 1;
11007   maximum_depth_ = kStackSize + depth_;
11008   DCHECK(StackBlown());
11009 }
11010 
11011 
Continue(int * offset_out)11012 String* ConsStringIterator::Continue(int* offset_out) {
11013   DCHECK(depth_ != 0);
11014   DCHECK_EQ(0, *offset_out);
11015   bool blew_stack = StackBlown();
11016   String* string = NULL;
11017   // Get the next leaf if there is one.
11018   if (!blew_stack) string = NextLeaf(&blew_stack);
11019   // Restart search from root.
11020   if (blew_stack) {
11021     DCHECK(string == NULL);
11022     string = Search(offset_out);
11023   }
11024   // Ensure future calls return null immediately.
11025   if (string == NULL) Reset(NULL);
11026   return string;
11027 }
11028 
11029 
Search(int * offset_out)11030 String* ConsStringIterator::Search(int* offset_out) {
11031   ConsString* cons_string = root_;
11032   // Reset the stack, pushing the root string.
11033   depth_ = 1;
11034   maximum_depth_ = 1;
11035   frames_[0] = cons_string;
11036   const int consumed = consumed_;
11037   int offset = 0;
11038   while (true) {
11039     // Loop until the string is found which contains the target offset.
11040     String* string = cons_string->first();
11041     int length = string->length();
11042     int32_t type;
11043     if (consumed < offset + length) {
11044       // Target offset is in the left branch.
11045       // Keep going if we're still in a ConString.
11046       type = string->map()->instance_type();
11047       if ((type & kStringRepresentationMask) == kConsStringTag) {
11048         cons_string = ConsString::cast(string);
11049         PushLeft(cons_string);
11050         continue;
11051       }
11052       // Tell the stack we're done descending.
11053       AdjustMaximumDepth();
11054     } else {
11055       // Descend right.
11056       // Update progress through the string.
11057       offset += length;
11058       // Keep going if we're still in a ConString.
11059       string = cons_string->second();
11060       type = string->map()->instance_type();
11061       if ((type & kStringRepresentationMask) == kConsStringTag) {
11062         cons_string = ConsString::cast(string);
11063         PushRight(cons_string);
11064         continue;
11065       }
11066       // Need this to be updated for the current string.
11067       length = string->length();
11068       // Account for the possibility of an empty right leaf.
11069       // This happens only if we have asked for an offset outside the string.
11070       if (length == 0) {
11071         // Reset so future operations will return null immediately.
11072         Reset(NULL);
11073         return NULL;
11074       }
11075       // Tell the stack we're done descending.
11076       AdjustMaximumDepth();
11077       // Pop stack so next iteration is in correct place.
11078       Pop();
11079     }
11080     DCHECK(length != 0);
11081     // Adjust return values and exit.
11082     consumed_ = offset + length;
11083     *offset_out = consumed - offset;
11084     return string;
11085   }
11086   UNREACHABLE();
11087   return NULL;
11088 }
11089 
11090 
NextLeaf(bool * blew_stack)11091 String* ConsStringIterator::NextLeaf(bool* blew_stack) {
11092   while (true) {
11093     // Tree traversal complete.
11094     if (depth_ == 0) {
11095       *blew_stack = false;
11096       return NULL;
11097     }
11098     // We've lost track of higher nodes.
11099     if (StackBlown()) {
11100       *blew_stack = true;
11101       return NULL;
11102     }
11103     // Go right.
11104     ConsString* cons_string = frames_[OffsetForDepth(depth_ - 1)];
11105     String* string = cons_string->second();
11106     int32_t type = string->map()->instance_type();
11107     if ((type & kStringRepresentationMask) != kConsStringTag) {
11108       // Pop stack so next iteration is in correct place.
11109       Pop();
11110       int length = string->length();
11111       // Could be a flattened ConsString.
11112       if (length == 0) continue;
11113       consumed_ += length;
11114       return string;
11115     }
11116     cons_string = ConsString::cast(string);
11117     PushRight(cons_string);
11118     // Need to traverse all the way left.
11119     while (true) {
11120       // Continue left.
11121       string = cons_string->first();
11122       type = string->map()->instance_type();
11123       if ((type & kStringRepresentationMask) != kConsStringTag) {
11124         AdjustMaximumDepth();
11125         int length = string->length();
11126         if (length == 0) break;  // Skip empty left-hand sides of ConsStrings.
11127         consumed_ += length;
11128         return string;
11129       }
11130       cons_string = ConsString::cast(string);
11131       PushLeft(cons_string);
11132     }
11133   }
11134   UNREACHABLE();
11135   return NULL;
11136 }
11137 
11138 
ConsStringGet(int index)11139 uint16_t ConsString::ConsStringGet(int index) {
11140   DCHECK(index >= 0 && index < this->length());
11141 
11142   // Check for a flattened cons string
11143   if (second()->length() == 0) {
11144     String* left = first();
11145     return left->Get(index);
11146   }
11147 
11148   String* string = String::cast(this);
11149 
11150   while (true) {
11151     if (StringShape(string).IsCons()) {
11152       ConsString* cons_string = ConsString::cast(string);
11153       String* left = cons_string->first();
11154       if (left->length() > index) {
11155         string = left;
11156       } else {
11157         index -= left->length();
11158         string = cons_string->second();
11159       }
11160     } else {
11161       return string->Get(index);
11162     }
11163   }
11164 
11165   UNREACHABLE();
11166   return 0;
11167 }
11168 
11169 
SlicedStringGet(int index)11170 uint16_t SlicedString::SlicedStringGet(int index) {
11171   return parent()->Get(offset() + index);
11172 }
11173 
11174 
11175 template <typename sinkchar>
WriteToFlat(String * src,sinkchar * sink,int f,int t)11176 void String::WriteToFlat(String* src,
11177                          sinkchar* sink,
11178                          int f,
11179                          int t) {
11180   String* source = src;
11181   int from = f;
11182   int to = t;
11183   while (true) {
11184     DCHECK(0 <= from && from <= to && to <= source->length());
11185     switch (StringShape(source).full_representation_tag()) {
11186       case kOneByteStringTag | kExternalStringTag: {
11187         CopyChars(sink, ExternalOneByteString::cast(source)->GetChars() + from,
11188                   to - from);
11189         return;
11190       }
11191       case kTwoByteStringTag | kExternalStringTag: {
11192         const uc16* data =
11193             ExternalTwoByteString::cast(source)->GetChars();
11194         CopyChars(sink,
11195                   data + from,
11196                   to - from);
11197         return;
11198       }
11199       case kOneByteStringTag | kSeqStringTag: {
11200         CopyChars(sink,
11201                   SeqOneByteString::cast(source)->GetChars() + from,
11202                   to - from);
11203         return;
11204       }
11205       case kTwoByteStringTag | kSeqStringTag: {
11206         CopyChars(sink,
11207                   SeqTwoByteString::cast(source)->GetChars() + from,
11208                   to - from);
11209         return;
11210       }
11211       case kOneByteStringTag | kConsStringTag:
11212       case kTwoByteStringTag | kConsStringTag: {
11213         ConsString* cons_string = ConsString::cast(source);
11214         String* first = cons_string->first();
11215         int boundary = first->length();
11216         if (to - boundary >= boundary - from) {
11217           // Right hand side is longer.  Recurse over left.
11218           if (from < boundary) {
11219             WriteToFlat(first, sink, from, boundary);
11220             if (from == 0 && cons_string->second() == first) {
11221               CopyChars(sink + boundary, sink, boundary);
11222               return;
11223             }
11224             sink += boundary - from;
11225             from = 0;
11226           } else {
11227             from -= boundary;
11228           }
11229           to -= boundary;
11230           source = cons_string->second();
11231         } else {
11232           // Left hand side is longer.  Recurse over right.
11233           if (to > boundary) {
11234             String* second = cons_string->second();
11235             // When repeatedly appending to a string, we get a cons string that
11236             // is unbalanced to the left, a list, essentially.  We inline the
11237             // common case of sequential one-byte right child.
11238             if (to - boundary == 1) {
11239               sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
11240             } else if (second->IsSeqOneByteString()) {
11241               CopyChars(sink + boundary - from,
11242                         SeqOneByteString::cast(second)->GetChars(),
11243                         to - boundary);
11244             } else {
11245               WriteToFlat(second,
11246                           sink + boundary - from,
11247                           0,
11248                           to - boundary);
11249             }
11250             to = boundary;
11251           }
11252           source = first;
11253         }
11254         break;
11255       }
11256       case kOneByteStringTag | kSlicedStringTag:
11257       case kTwoByteStringTag | kSlicedStringTag: {
11258         SlicedString* slice = SlicedString::cast(source);
11259         unsigned offset = slice->offset();
11260         WriteToFlat(slice->parent(), sink, from + offset, to + offset);
11261         return;
11262       }
11263     }
11264   }
11265 }
11266 
11267 
11268 
11269 template <typename SourceChar>
CalculateLineEndsImpl(Isolate * isolate,List<int> * line_ends,Vector<const SourceChar> src,bool include_ending_line)11270 static void CalculateLineEndsImpl(Isolate* isolate,
11271                                   List<int>* line_ends,
11272                                   Vector<const SourceChar> src,
11273                                   bool include_ending_line) {
11274   const int src_len = src.length();
11275   UnicodeCache* cache = isolate->unicode_cache();
11276   for (int i = 0; i < src_len - 1; i++) {
11277     SourceChar current = src[i];
11278     SourceChar next = src[i + 1];
11279     if (cache->IsLineTerminatorSequence(current, next)) line_ends->Add(i);
11280   }
11281 
11282   if (src_len > 0 && cache->IsLineTerminatorSequence(src[src_len - 1], 0)) {
11283     line_ends->Add(src_len - 1);
11284   }
11285   if (include_ending_line) {
11286     // Include one character beyond the end of script. The rewriter uses that
11287     // position for the implicit return statement.
11288     line_ends->Add(src_len);
11289   }
11290 }
11291 
11292 
CalculateLineEnds(Handle<String> src,bool include_ending_line)11293 Handle<FixedArray> String::CalculateLineEnds(Handle<String> src,
11294                                              bool include_ending_line) {
11295   src = Flatten(src);
11296   // Rough estimate of line count based on a roughly estimated average
11297   // length of (unpacked) code.
11298   int line_count_estimate = src->length() >> 4;
11299   List<int> line_ends(line_count_estimate);
11300   Isolate* isolate = src->GetIsolate();
11301   { DisallowHeapAllocation no_allocation;  // ensure vectors stay valid.
11302     // Dispatch on type of strings.
11303     String::FlatContent content = src->GetFlatContent();
11304     DCHECK(content.IsFlat());
11305     if (content.IsOneByte()) {
11306       CalculateLineEndsImpl(isolate,
11307                             &line_ends,
11308                             content.ToOneByteVector(),
11309                             include_ending_line);
11310     } else {
11311       CalculateLineEndsImpl(isolate,
11312                             &line_ends,
11313                             content.ToUC16Vector(),
11314                             include_ending_line);
11315     }
11316   }
11317   int line_count = line_ends.length();
11318   Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count);
11319   for (int i = 0; i < line_count; i++) {
11320     array->set(i, Smi::FromInt(line_ends[i]));
11321   }
11322   return array;
11323 }
11324 
11325 
11326 // Compares the contents of two strings by reading and comparing
11327 // int-sized blocks of characters.
11328 template <typename Char>
CompareRawStringContents(const Char * const a,const Char * const b,int length)11329 static inline bool CompareRawStringContents(const Char* const a,
11330                                             const Char* const b,
11331                                             int length) {
11332   return CompareChars(a, b, length) == 0;
11333 }
11334 
11335 
11336 template<typename Chars1, typename Chars2>
11337 class RawStringComparator : public AllStatic {
11338  public:
compare(const Chars1 * a,const Chars2 * b,int len)11339   static inline bool compare(const Chars1* a, const Chars2* b, int len) {
11340     DCHECK(sizeof(Chars1) != sizeof(Chars2));
11341     for (int i = 0; i < len; i++) {
11342       if (a[i] != b[i]) {
11343         return false;
11344       }
11345     }
11346     return true;
11347   }
11348 };
11349 
11350 
11351 template<>
11352 class RawStringComparator<uint16_t, uint16_t> {
11353  public:
compare(const uint16_t * a,const uint16_t * b,int len)11354   static inline bool compare(const uint16_t* a, const uint16_t* b, int len) {
11355     return CompareRawStringContents(a, b, len);
11356   }
11357 };
11358 
11359 
11360 template<>
11361 class RawStringComparator<uint8_t, uint8_t> {
11362  public:
compare(const uint8_t * a,const uint8_t * b,int len)11363   static inline bool compare(const uint8_t* a, const uint8_t* b, int len) {
11364     return CompareRawStringContents(a, b, len);
11365   }
11366 };
11367 
11368 
11369 class StringComparator {
11370   class State {
11371    public:
State()11372     State() : is_one_byte_(true), length_(0), buffer8_(NULL) {}
11373 
Init(String * string)11374     void Init(String* string) {
11375       ConsString* cons_string = String::VisitFlat(this, string);
11376       iter_.Reset(cons_string);
11377       if (cons_string != NULL) {
11378         int offset;
11379         string = iter_.Next(&offset);
11380         String::VisitFlat(this, string, offset);
11381       }
11382     }
11383 
VisitOneByteString(const uint8_t * chars,int length)11384     inline void VisitOneByteString(const uint8_t* chars, int length) {
11385       is_one_byte_ = true;
11386       buffer8_ = chars;
11387       length_ = length;
11388     }
11389 
VisitTwoByteString(const uint16_t * chars,int length)11390     inline void VisitTwoByteString(const uint16_t* chars, int length) {
11391       is_one_byte_ = false;
11392       buffer16_ = chars;
11393       length_ = length;
11394     }
11395 
Advance(int consumed)11396     void Advance(int consumed) {
11397       DCHECK(consumed <= length_);
11398       // Still in buffer.
11399       if (length_ != consumed) {
11400         if (is_one_byte_) {
11401           buffer8_ += consumed;
11402         } else {
11403           buffer16_ += consumed;
11404         }
11405         length_ -= consumed;
11406         return;
11407       }
11408       // Advance state.
11409       int offset;
11410       String* next = iter_.Next(&offset);
11411       DCHECK_EQ(0, offset);
11412       DCHECK(next != NULL);
11413       String::VisitFlat(this, next);
11414     }
11415 
11416     ConsStringIterator iter_;
11417     bool is_one_byte_;
11418     int length_;
11419     union {
11420       const uint8_t* buffer8_;
11421       const uint16_t* buffer16_;
11422     };
11423 
11424    private:
11425     DISALLOW_COPY_AND_ASSIGN(State);
11426   };
11427 
11428  public:
StringComparator()11429   inline StringComparator() {}
11430 
11431   template<typename Chars1, typename Chars2>
Equals(State * state_1,State * state_2,int to_check)11432   static inline bool Equals(State* state_1, State* state_2, int to_check) {
11433     const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_);
11434     const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_);
11435     return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check);
11436   }
11437 
Equals(String * string_1,String * string_2)11438   bool Equals(String* string_1, String* string_2) {
11439     int length = string_1->length();
11440     state_1_.Init(string_1);
11441     state_2_.Init(string_2);
11442     while (true) {
11443       int to_check = Min(state_1_.length_, state_2_.length_);
11444       DCHECK(to_check > 0 && to_check <= length);
11445       bool is_equal;
11446       if (state_1_.is_one_byte_) {
11447         if (state_2_.is_one_byte_) {
11448           is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check);
11449         } else {
11450           is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check);
11451         }
11452       } else {
11453         if (state_2_.is_one_byte_) {
11454           is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check);
11455         } else {
11456           is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check);
11457         }
11458       }
11459       // Looping done.
11460       if (!is_equal) return false;
11461       length -= to_check;
11462       // Exit condition. Strings are equal.
11463       if (length == 0) return true;
11464       state_1_.Advance(to_check);
11465       state_2_.Advance(to_check);
11466     }
11467   }
11468 
11469  private:
11470   State state_1_;
11471   State state_2_;
11472 
11473   DISALLOW_COPY_AND_ASSIGN(StringComparator);
11474 };
11475 
11476 
SlowEquals(String * other)11477 bool String::SlowEquals(String* other) {
11478   DisallowHeapAllocation no_gc;
11479   // Fast check: negative check with lengths.
11480   int len = length();
11481   if (len != other->length()) return false;
11482   if (len == 0) return true;
11483 
11484   // Fast check: if hash code is computed for both strings
11485   // a fast negative check can be performed.
11486   if (HasHashCode() && other->HasHashCode()) {
11487 #ifdef ENABLE_SLOW_DCHECKS
11488     if (FLAG_enable_slow_asserts) {
11489       if (Hash() != other->Hash()) {
11490         bool found_difference = false;
11491         for (int i = 0; i < len; i++) {
11492           if (Get(i) != other->Get(i)) {
11493             found_difference = true;
11494             break;
11495           }
11496         }
11497         DCHECK(found_difference);
11498       }
11499     }
11500 #endif
11501     if (Hash() != other->Hash()) return false;
11502   }
11503 
11504   // We know the strings are both non-empty. Compare the first chars
11505   // before we try to flatten the strings.
11506   if (this->Get(0) != other->Get(0)) return false;
11507 
11508   if (IsSeqOneByteString() && other->IsSeqOneByteString()) {
11509     const uint8_t* str1 = SeqOneByteString::cast(this)->GetChars();
11510     const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars();
11511     return CompareRawStringContents(str1, str2, len);
11512   }
11513 
11514   StringComparator comparator;
11515   return comparator.Equals(this, other);
11516 }
11517 
11518 
SlowEquals(Handle<String> one,Handle<String> two)11519 bool String::SlowEquals(Handle<String> one, Handle<String> two) {
11520   // Fast check: negative check with lengths.
11521   int one_length = one->length();
11522   if (one_length != two->length()) return false;
11523   if (one_length == 0) return true;
11524 
11525   // Fast check: if hash code is computed for both strings
11526   // a fast negative check can be performed.
11527   if (one->HasHashCode() && two->HasHashCode()) {
11528 #ifdef ENABLE_SLOW_DCHECKS
11529     if (FLAG_enable_slow_asserts) {
11530       if (one->Hash() != two->Hash()) {
11531         bool found_difference = false;
11532         for (int i = 0; i < one_length; i++) {
11533           if (one->Get(i) != two->Get(i)) {
11534             found_difference = true;
11535             break;
11536           }
11537         }
11538         DCHECK(found_difference);
11539       }
11540     }
11541 #endif
11542     if (one->Hash() != two->Hash()) return false;
11543   }
11544 
11545   // We know the strings are both non-empty. Compare the first chars
11546   // before we try to flatten the strings.
11547   if (one->Get(0) != two->Get(0)) return false;
11548 
11549   one = String::Flatten(one);
11550   two = String::Flatten(two);
11551 
11552   DisallowHeapAllocation no_gc;
11553   String::FlatContent flat1 = one->GetFlatContent();
11554   String::FlatContent flat2 = two->GetFlatContent();
11555 
11556   if (flat1.IsOneByte() && flat2.IsOneByte()) {
11557       return CompareRawStringContents(flat1.ToOneByteVector().start(),
11558                                       flat2.ToOneByteVector().start(),
11559                                       one_length);
11560   } else {
11561     for (int i = 0; i < one_length; i++) {
11562       if (flat1.Get(i) != flat2.Get(i)) return false;
11563     }
11564     return true;
11565   }
11566 }
11567 
11568 
11569 // static
Compare(Handle<String> x,Handle<String> y)11570 ComparisonResult String::Compare(Handle<String> x, Handle<String> y) {
11571   // A few fast case tests before we flatten.
11572   if (x.is_identical_to(y)) {
11573     return ComparisonResult::kEqual;
11574   } else if (y->length() == 0) {
11575     return x->length() == 0 ? ComparisonResult::kEqual
11576                             : ComparisonResult::kGreaterThan;
11577   } else if (x->length() == 0) {
11578     return ComparisonResult::kLessThan;
11579   }
11580 
11581   int const d = x->Get(0) - y->Get(0);
11582   if (d < 0) {
11583     return ComparisonResult::kLessThan;
11584   } else if (d > 0) {
11585     return ComparisonResult::kGreaterThan;
11586   }
11587 
11588   // Slow case.
11589   x = String::Flatten(x);
11590   y = String::Flatten(y);
11591 
11592   DisallowHeapAllocation no_gc;
11593   ComparisonResult result = ComparisonResult::kEqual;
11594   int prefix_length = x->length();
11595   if (y->length() < prefix_length) {
11596     prefix_length = y->length();
11597     result = ComparisonResult::kGreaterThan;
11598   } else if (y->length() > prefix_length) {
11599     result = ComparisonResult::kLessThan;
11600   }
11601   int r;
11602   String::FlatContent x_content = x->GetFlatContent();
11603   String::FlatContent y_content = y->GetFlatContent();
11604   if (x_content.IsOneByte()) {
11605     Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
11606     if (y_content.IsOneByte()) {
11607       Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11608       r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11609     } else {
11610       Vector<const uc16> y_chars = y_content.ToUC16Vector();
11611       r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11612     }
11613   } else {
11614     Vector<const uc16> x_chars = x_content.ToUC16Vector();
11615     if (y_content.IsOneByte()) {
11616       Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11617       r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11618     } else {
11619       Vector<const uc16> y_chars = y_content.ToUC16Vector();
11620       r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11621     }
11622   }
11623   if (r < 0) {
11624     result = ComparisonResult::kLessThan;
11625   } else if (r > 0) {
11626     result = ComparisonResult::kGreaterThan;
11627   }
11628   return result;
11629 }
11630 
IndexOf(Isolate * isolate,Handle<Object> receiver,Handle<Object> search,Handle<Object> position)11631 Object* String::IndexOf(Isolate* isolate, Handle<Object> receiver,
11632                         Handle<Object> search, Handle<Object> position) {
11633   if (receiver->IsNull(isolate) || receiver->IsUndefined(isolate)) {
11634     THROW_NEW_ERROR_RETURN_FAILURE(
11635         isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
11636                               isolate->factory()->NewStringFromAsciiChecked(
11637                                   "String.prototype.indexOf")));
11638   }
11639   Handle<String> receiver_string;
11640   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string,
11641                                      Object::ToString(isolate, receiver));
11642 
11643   Handle<String> search_string;
11644   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
11645                                      Object::ToString(isolate, search));
11646 
11647   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11648                                      Object::ToInteger(isolate, position));
11649 
11650   double index = std::max(position->Number(), 0.0);
11651   index = std::min(index, static_cast<double>(receiver_string->length()));
11652 
11653   return Smi::FromInt(String::IndexOf(isolate, receiver_string, search_string,
11654                                       static_cast<uint32_t>(index)));
11655 }
11656 
11657 namespace {
11658 
11659 template <typename T>
SearchString(Isolate * isolate,String::FlatContent receiver_content,Vector<T> pat_vector,int start_index)11660 int SearchString(Isolate* isolate, String::FlatContent receiver_content,
11661                  Vector<T> pat_vector, int start_index) {
11662   if (receiver_content.IsOneByte()) {
11663     return SearchString(isolate, receiver_content.ToOneByteVector(), pat_vector,
11664                         start_index);
11665   }
11666   return SearchString(isolate, receiver_content.ToUC16Vector(), pat_vector,
11667                       start_index);
11668 }
11669 
11670 }  // namespace
11671 
IndexOf(Isolate * isolate,Handle<String> receiver,Handle<String> search,int start_index)11672 int String::IndexOf(Isolate* isolate, Handle<String> receiver,
11673                     Handle<String> search, int start_index) {
11674   DCHECK(0 <= start_index);
11675   DCHECK(start_index <= receiver->length());
11676 
11677   uint32_t search_length = search->length();
11678   if (search_length == 0) return start_index;
11679 
11680   uint32_t receiver_length = receiver->length();
11681   if (start_index + search_length > receiver_length) return -1;
11682 
11683   receiver = String::Flatten(receiver);
11684   search = String::Flatten(search);
11685 
11686   DisallowHeapAllocation no_gc;  // ensure vectors stay valid
11687   // Extract flattened substrings of cons strings before getting encoding.
11688   String::FlatContent receiver_content = receiver->GetFlatContent();
11689   String::FlatContent search_content = search->GetFlatContent();
11690 
11691   // dispatch on type of strings
11692   if (search_content.IsOneByte()) {
11693     Vector<const uint8_t> pat_vector = search_content.ToOneByteVector();
11694     return SearchString<const uint8_t>(isolate, receiver_content, pat_vector,
11695                                        start_index);
11696   }
11697   Vector<const uc16> pat_vector = search_content.ToUC16Vector();
11698   return SearchString<const uc16>(isolate, receiver_content, pat_vector,
11699                                   start_index);
11700 }
11701 
GetSubstitution(Isolate * isolate,Match * match,Handle<String> replacement)11702 MaybeHandle<String> String::GetSubstitution(Isolate* isolate, Match* match,
11703                                             Handle<String> replacement) {
11704   Factory* factory = isolate->factory();
11705 
11706   const int replacement_length = replacement->length();
11707   const int captures_length = match->CaptureCount();
11708 
11709   replacement = String::Flatten(replacement);
11710 
11711   Handle<String> dollar_string =
11712       factory->LookupSingleCharacterStringFromCode('$');
11713   int next = String::IndexOf(isolate, replacement, dollar_string, 0);
11714   if (next < 0) {
11715     return replacement;
11716   }
11717 
11718   IncrementalStringBuilder builder(isolate);
11719 
11720   if (next > 0) {
11721     builder.AppendString(factory->NewSubString(replacement, 0, next));
11722   }
11723 
11724   while (true) {
11725     int pos = next + 1;
11726     if (pos < replacement_length) {
11727       const uint16_t peek = replacement->Get(pos);
11728       if (peek == '$') {  // $$
11729         pos++;
11730         builder.AppendCharacter('$');
11731       } else if (peek == '&') {  // $& - match
11732         pos++;
11733         builder.AppendString(match->GetMatch());
11734       } else if (peek == '`') {  // $` - prefix
11735         pos++;
11736         builder.AppendString(match->GetPrefix());
11737       } else if (peek == '\'') {  // $' - suffix
11738         pos++;
11739         builder.AppendString(match->GetSuffix());
11740       } else if (peek >= '0' && peek <= '9') {
11741         // Valid indices are $1 .. $9, $01 .. $09 and $10 .. $99
11742         int scaled_index = (peek - '0');
11743         int advance = 1;
11744 
11745         if (pos + 1 < replacement_length) {
11746           const uint16_t next_peek = replacement->Get(pos + 1);
11747           if (next_peek >= '0' && next_peek <= '9') {
11748             const int new_scaled_index = scaled_index * 10 + (next_peek - '0');
11749             if (new_scaled_index < captures_length) {
11750               scaled_index = new_scaled_index;
11751               advance = 2;
11752             }
11753           }
11754         }
11755 
11756         if (scaled_index != 0 && scaled_index < captures_length) {
11757           bool capture_exists;
11758           Handle<String> capture;
11759           ASSIGN_RETURN_ON_EXCEPTION(
11760               isolate, capture,
11761               match->GetCapture(scaled_index, &capture_exists), String);
11762           if (capture_exists) builder.AppendString(capture);
11763           pos += advance;
11764         } else {
11765           builder.AppendCharacter('$');
11766         }
11767       } else {
11768         builder.AppendCharacter('$');
11769       }
11770     } else {
11771       builder.AppendCharacter('$');
11772     }
11773 
11774     // Go the the next $ in the replacement.
11775     next = String::IndexOf(isolate, replacement, dollar_string, pos);
11776 
11777     // Return if there are no more $ characters in the replacement. If we
11778     // haven't reached the end, we need to append the suffix.
11779     if (next < 0) {
11780       if (pos < replacement_length) {
11781         builder.AppendString(
11782             factory->NewSubString(replacement, pos, replacement_length));
11783       }
11784       return builder.Finish();
11785     }
11786 
11787     // Append substring between the previous and the next $ character.
11788     if (next > pos) {
11789       builder.AppendString(factory->NewSubString(replacement, pos, next));
11790     }
11791   }
11792 
11793   UNREACHABLE();
11794   return MaybeHandle<String>();
11795 }
11796 
11797 namespace {  // for String.Prototype.lastIndexOf
11798 
11799 template <typename schar, typename pchar>
StringMatchBackwards(Vector<const schar> subject,Vector<const pchar> pattern,int idx)11800 int StringMatchBackwards(Vector<const schar> subject,
11801                          Vector<const pchar> pattern, int idx) {
11802   int pattern_length = pattern.length();
11803   DCHECK(pattern_length >= 1);
11804   DCHECK(idx + pattern_length <= subject.length());
11805 
11806   if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
11807     for (int i = 0; i < pattern_length; i++) {
11808       uc16 c = pattern[i];
11809       if (c > String::kMaxOneByteCharCode) {
11810         return -1;
11811       }
11812     }
11813   }
11814 
11815   pchar pattern_first_char = pattern[0];
11816   for (int i = idx; i >= 0; i--) {
11817     if (subject[i] != pattern_first_char) continue;
11818     int j = 1;
11819     while (j < pattern_length) {
11820       if (pattern[j] != subject[i + j]) {
11821         break;
11822       }
11823       j++;
11824     }
11825     if (j == pattern_length) {
11826       return i;
11827     }
11828   }
11829   return -1;
11830 }
11831 
11832 }  // namespace
11833 
LastIndexOf(Isolate * isolate,Handle<Object> receiver,Handle<Object> search,Handle<Object> position)11834 Object* String::LastIndexOf(Isolate* isolate, Handle<Object> receiver,
11835                             Handle<Object> search, Handle<Object> position) {
11836   if (receiver->IsNull(isolate) || receiver->IsUndefined(isolate)) {
11837     THROW_NEW_ERROR_RETURN_FAILURE(
11838         isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
11839                               isolate->factory()->NewStringFromAsciiChecked(
11840                                   "String.prototype.lastIndexOf")));
11841   }
11842   Handle<String> receiver_string;
11843   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string,
11844                                      Object::ToString(isolate, receiver));
11845 
11846   Handle<String> search_string;
11847   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
11848                                      Object::ToString(isolate, search));
11849 
11850   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11851                                      Object::ToNumber(position));
11852 
11853   uint32_t start_index;
11854 
11855   if (position->IsNaN()) {
11856     start_index = receiver_string->length();
11857   } else {
11858     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11859                                        Object::ToInteger(isolate, position));
11860 
11861     double position_number = std::max(position->Number(), 0.0);
11862     position_number = std::min(position_number,
11863                                static_cast<double>(receiver_string->length()));
11864     start_index = static_cast<uint32_t>(position_number);
11865   }
11866 
11867   uint32_t pattern_length = search_string->length();
11868   uint32_t receiver_length = receiver_string->length();
11869 
11870   if (start_index + pattern_length > receiver_length) {
11871     start_index = receiver_length - pattern_length;
11872   }
11873 
11874   if (pattern_length == 0) {
11875     return Smi::FromInt(start_index);
11876   }
11877 
11878   receiver_string = String::Flatten(receiver_string);
11879   search_string = String::Flatten(search_string);
11880 
11881   int last_index = -1;
11882   DisallowHeapAllocation no_gc;  // ensure vectors stay valid
11883 
11884   String::FlatContent receiver_content = receiver_string->GetFlatContent();
11885   String::FlatContent search_content = search_string->GetFlatContent();
11886 
11887   if (search_content.IsOneByte()) {
11888     Vector<const uint8_t> pat_vector = search_content.ToOneByteVector();
11889     if (receiver_content.IsOneByte()) {
11890       last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
11891                                         pat_vector, start_index);
11892     } else {
11893       last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
11894                                         pat_vector, start_index);
11895     }
11896   } else {
11897     Vector<const uc16> pat_vector = search_content.ToUC16Vector();
11898     if (receiver_content.IsOneByte()) {
11899       last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
11900                                         pat_vector, start_index);
11901     } else {
11902       last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
11903                                         pat_vector, start_index);
11904     }
11905   }
11906   return Smi::FromInt(last_index);
11907 }
11908 
IsUtf8EqualTo(Vector<const char> str,bool allow_prefix_match)11909 bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
11910   int slen = length();
11911   // Can't check exact length equality, but we can check bounds.
11912   int str_len = str.length();
11913   if (!allow_prefix_match &&
11914       (str_len < slen ||
11915           str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) {
11916     return false;
11917   }
11918   int i;
11919   size_t remaining_in_str = static_cast<size_t>(str_len);
11920   const uint8_t* utf8_data = reinterpret_cast<const uint8_t*>(str.start());
11921   for (i = 0; i < slen && remaining_in_str > 0; i++) {
11922     size_t cursor = 0;
11923     uint32_t r = unibrow::Utf8::ValueOf(utf8_data, remaining_in_str, &cursor);
11924     DCHECK(cursor > 0 && cursor <= remaining_in_str);
11925     if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
11926       if (i > slen - 1) return false;
11927       if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false;
11928       if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false;
11929     } else {
11930       if (Get(i) != r) return false;
11931     }
11932     utf8_data += cursor;
11933     remaining_in_str -= cursor;
11934   }
11935   return (allow_prefix_match || i == slen) && remaining_in_str == 0;
11936 }
11937 
11938 
IsOneByteEqualTo(Vector<const uint8_t> str)11939 bool String::IsOneByteEqualTo(Vector<const uint8_t> str) {
11940   int slen = length();
11941   if (str.length() != slen) return false;
11942   DisallowHeapAllocation no_gc;
11943   FlatContent content = GetFlatContent();
11944   if (content.IsOneByte()) {
11945     return CompareChars(content.ToOneByteVector().start(),
11946                         str.start(), slen) == 0;
11947   }
11948   for (int i = 0; i < slen; i++) {
11949     if (Get(i) != static_cast<uint16_t>(str[i])) return false;
11950   }
11951   return true;
11952 }
11953 
11954 
IsTwoByteEqualTo(Vector<const uc16> str)11955 bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
11956   int slen = length();
11957   if (str.length() != slen) return false;
11958   DisallowHeapAllocation no_gc;
11959   FlatContent content = GetFlatContent();
11960   if (content.IsTwoByte()) {
11961     return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
11962   }
11963   for (int i = 0; i < slen; i++) {
11964     if (Get(i) != str[i]) return false;
11965   }
11966   return true;
11967 }
11968 
11969 
ComputeAndSetHash()11970 uint32_t String::ComputeAndSetHash() {
11971   // Should only be called if hash code has not yet been computed.
11972   DCHECK(!HasHashCode());
11973 
11974   // Store the hash code in the object.
11975   uint32_t field = IteratingStringHasher::Hash(this, GetHeap()->HashSeed());
11976   set_hash_field(field);
11977 
11978   // Check the hash code is there.
11979   DCHECK(HasHashCode());
11980   uint32_t result = field >> kHashShift;
11981   DCHECK(result != 0);  // Ensure that the hash value of 0 is never computed.
11982   return result;
11983 }
11984 
11985 
ComputeArrayIndex(uint32_t * index)11986 bool String::ComputeArrayIndex(uint32_t* index) {
11987   int length = this->length();
11988   if (length == 0 || length > kMaxArrayIndexSize) return false;
11989   StringCharacterStream stream(this);
11990   return StringToArrayIndex(&stream, index);
11991 }
11992 
11993 
SlowAsArrayIndex(uint32_t * index)11994 bool String::SlowAsArrayIndex(uint32_t* index) {
11995   if (length() <= kMaxCachedArrayIndexLength) {
11996     Hash();  // force computation of hash code
11997     uint32_t field = hash_field();
11998     if ((field & kIsNotArrayIndexMask) != 0) return false;
11999     // Isolate the array index form the full hash field.
12000     *index = ArrayIndexValueBits::decode(field);
12001     return true;
12002   } else {
12003     return ComputeArrayIndex(index);
12004   }
12005 }
12006 
12007 
Truncate(Handle<SeqString> string,int new_length)12008 Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
12009   int new_size, old_size;
12010   int old_length = string->length();
12011   if (old_length <= new_length) return string;
12012 
12013   if (string->IsSeqOneByteString()) {
12014     old_size = SeqOneByteString::SizeFor(old_length);
12015     new_size = SeqOneByteString::SizeFor(new_length);
12016   } else {
12017     DCHECK(string->IsSeqTwoByteString());
12018     old_size = SeqTwoByteString::SizeFor(old_length);
12019     new_size = SeqTwoByteString::SizeFor(new_length);
12020   }
12021 
12022   int delta = old_size - new_size;
12023 
12024   Address start_of_string = string->address();
12025   DCHECK_OBJECT_ALIGNED(start_of_string);
12026   DCHECK_OBJECT_ALIGNED(start_of_string + new_size);
12027 
12028   Heap* heap = string->GetHeap();
12029   // Sizes are pointer size aligned, so that we can use filler objects
12030   // that are a multiple of pointer size.
12031   heap->CreateFillerObjectAt(start_of_string + new_size, delta,
12032                              ClearRecordedSlots::kNo);
12033   heap->AdjustLiveBytes(*string, -delta, Heap::CONCURRENT_TO_SWEEPER);
12034 
12035   // We are storing the new length using release store after creating a filler
12036   // for the left-over space to avoid races with the sweeper thread.
12037   string->synchronized_set_length(new_length);
12038 
12039   if (new_length == 0) return heap->isolate()->factory()->empty_string();
12040   return string;
12041 }
12042 
12043 
MakeArrayIndexHash(uint32_t value,int length)12044 uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
12045   // For array indexes mix the length into the hash as an array index could
12046   // be zero.
12047   DCHECK(length > 0);
12048   DCHECK(length <= String::kMaxArrayIndexSize);
12049   DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
12050          (1 << String::kArrayIndexValueBits));
12051 
12052   value <<= String::ArrayIndexValueBits::kShift;
12053   value |= length << String::ArrayIndexLengthBits::kShift;
12054 
12055   DCHECK((value & String::kIsNotArrayIndexMask) == 0);
12056   DCHECK_EQ(length <= String::kMaxCachedArrayIndexLength,
12057             (value & String::kContainsCachedArrayIndexMask) == 0);
12058   return value;
12059 }
12060 
12061 
GetHashField()12062 uint32_t StringHasher::GetHashField() {
12063   if (length_ <= String::kMaxHashCalcLength) {
12064     if (is_array_index_) {
12065       return MakeArrayIndexHash(array_index_, length_);
12066     }
12067     return (GetHashCore(raw_running_hash_) << String::kHashShift) |
12068            String::kIsNotArrayIndexMask;
12069   } else {
12070     return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
12071   }
12072 }
12073 
12074 
ComputeUtf8Hash(Vector<const char> chars,uint32_t seed,int * utf16_length_out)12075 uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars,
12076                                        uint32_t seed,
12077                                        int* utf16_length_out) {
12078   int vector_length = chars.length();
12079   // Handle some edge cases
12080   if (vector_length <= 1) {
12081     DCHECK(vector_length == 0 ||
12082            static_cast<uint8_t>(chars.start()[0]) <=
12083                unibrow::Utf8::kMaxOneByteChar);
12084     *utf16_length_out = vector_length;
12085     return HashSequentialString(chars.start(), vector_length, seed);
12086   }
12087   // Start with a fake length which won't affect computation.
12088   // It will be updated later.
12089   StringHasher hasher(String::kMaxArrayIndexSize, seed);
12090   size_t remaining = static_cast<size_t>(vector_length);
12091   const uint8_t* stream = reinterpret_cast<const uint8_t*>(chars.start());
12092   int utf16_length = 0;
12093   bool is_index = true;
12094   DCHECK(hasher.is_array_index_);
12095   while (remaining > 0) {
12096     size_t consumed = 0;
12097     uint32_t c = unibrow::Utf8::ValueOf(stream, remaining, &consumed);
12098     DCHECK(consumed > 0 && consumed <= remaining);
12099     stream += consumed;
12100     remaining -= consumed;
12101     bool is_two_characters = c > unibrow::Utf16::kMaxNonSurrogateCharCode;
12102     utf16_length += is_two_characters ? 2 : 1;
12103     // No need to keep hashing. But we do need to calculate utf16_length.
12104     if (utf16_length > String::kMaxHashCalcLength) continue;
12105     if (is_two_characters) {
12106       uint16_t c1 = unibrow::Utf16::LeadSurrogate(c);
12107       uint16_t c2 = unibrow::Utf16::TrailSurrogate(c);
12108       hasher.AddCharacter(c1);
12109       hasher.AddCharacter(c2);
12110       if (is_index) is_index = hasher.UpdateIndex(c1);
12111       if (is_index) is_index = hasher.UpdateIndex(c2);
12112     } else {
12113       hasher.AddCharacter(c);
12114       if (is_index) is_index = hasher.UpdateIndex(c);
12115     }
12116   }
12117   *utf16_length_out = static_cast<int>(utf16_length);
12118   // Must set length here so that hash computation is correct.
12119   hasher.length_ = utf16_length;
12120   return hasher.GetHashField();
12121 }
12122 
12123 
VisitConsString(ConsString * cons_string)12124 void IteratingStringHasher::VisitConsString(ConsString* cons_string) {
12125   // Run small ConsStrings through ConsStringIterator.
12126   if (cons_string->length() < 64) {
12127     ConsStringIterator iter(cons_string);
12128     int offset;
12129     String* string;
12130     while (nullptr != (string = iter.Next(&offset))) {
12131       DCHECK_EQ(0, offset);
12132       String::VisitFlat(this, string, 0);
12133     }
12134     return;
12135   }
12136   // Slow case.
12137   const int max_length = String::kMaxHashCalcLength;
12138   int length = std::min(cons_string->length(), max_length);
12139   if (cons_string->HasOnlyOneByteChars()) {
12140     uint8_t* buffer = new uint8_t[length];
12141     String::WriteToFlat(cons_string, buffer, 0, length);
12142     AddCharacters(buffer, length);
12143     delete[] buffer;
12144   } else {
12145     uint16_t* buffer = new uint16_t[length];
12146     String::WriteToFlat(cons_string, buffer, 0, length);
12147     AddCharacters(buffer, length);
12148     delete[] buffer;
12149   }
12150 }
12151 
12152 
PrintOn(FILE * file)12153 void String::PrintOn(FILE* file) {
12154   int length = this->length();
12155   for (int i = 0; i < length; i++) {
12156     PrintF(file, "%c", Get(i));
12157   }
12158 }
12159 
12160 
Hash()12161 int Map::Hash() {
12162   // For performance reasons we only hash the 3 most variable fields of a map:
12163   // constructor, prototype and bit_field2. For predictability reasons we
12164   // use objects' offsets in respective pages for hashing instead of raw
12165   // addresses.
12166 
12167   // Shift away the tag.
12168   int hash = ObjectAddressForHashing(GetConstructor()) >> 2;
12169 
12170   // XOR-ing the prototype and constructor directly yields too many zero bits
12171   // when the two pointers are close (which is fairly common).
12172   // To avoid this we shift the prototype bits relatively to the constructor.
12173   hash ^= ObjectAddressForHashing(prototype()) << (32 - kPageSizeBits);
12174 
12175   return hash ^ (hash >> 16) ^ bit_field2();
12176 }
12177 
12178 
12179 namespace {
12180 
CheckEquivalent(Map * first,Map * second)12181 bool CheckEquivalent(Map* first, Map* second) {
12182   return first->GetConstructor() == second->GetConstructor() &&
12183          first->prototype() == second->prototype() &&
12184          first->instance_type() == second->instance_type() &&
12185          first->bit_field() == second->bit_field() &&
12186          first->is_extensible() == second->is_extensible() &&
12187          first->new_target_is_base() == second->new_target_is_base() &&
12188          first->has_hidden_prototype() == second->has_hidden_prototype();
12189 }
12190 
12191 }  // namespace
12192 
12193 
EquivalentToForTransition(Map * other)12194 bool Map::EquivalentToForTransition(Map* other) {
12195   if (!CheckEquivalent(this, other)) return false;
12196   if (instance_type() == JS_FUNCTION_TYPE) {
12197     // JSFunctions require more checks to ensure that sloppy function is
12198     // not equvalent to strict function.
12199     int nof = Min(NumberOfOwnDescriptors(), other->NumberOfOwnDescriptors());
12200     return instance_descriptors()->IsEqualUpTo(other->instance_descriptors(),
12201                                                nof);
12202   }
12203   return true;
12204 }
12205 
12206 
EquivalentToForNormalization(Map * other,PropertyNormalizationMode mode)12207 bool Map::EquivalentToForNormalization(Map* other,
12208                                        PropertyNormalizationMode mode) {
12209   int properties =
12210       mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other->GetInObjectProperties();
12211   return CheckEquivalent(this, other) && bit_field2() == other->bit_field2() &&
12212          GetInObjectProperties() == properties;
12213 }
12214 
12215 
Inlines(SharedFunctionInfo * candidate)12216 bool JSFunction::Inlines(SharedFunctionInfo* candidate) {
12217   DisallowHeapAllocation no_gc;
12218   if (shared() == candidate) return true;
12219   if (code()->kind() != Code::OPTIMIZED_FUNCTION) return false;
12220   DeoptimizationInputData* const data =
12221       DeoptimizationInputData::cast(code()->deoptimization_data());
12222   if (data->length() == 0) return false;
12223   FixedArray* const literals = data->LiteralArray();
12224   int const inlined_count = data->InlinedFunctionCount()->value();
12225   for (int i = 0; i < inlined_count; ++i) {
12226     if (SharedFunctionInfo::cast(literals->get(i)) == candidate) {
12227       return true;
12228     }
12229   }
12230   return false;
12231 }
12232 
MarkForBaseline()12233 void JSFunction::MarkForBaseline() {
12234   Isolate* isolate = GetIsolate();
12235   set_code_no_write_barrier(
12236       isolate->builtins()->builtin(Builtins::kCompileBaseline));
12237   // No write barrier required, since the builtin is part of the root set.
12238   if (FLAG_mark_shared_functions_for_tier_up) {
12239     shared()->set_marked_for_tier_up(true);
12240   }
12241 }
12242 
MarkForOptimization()12243 void JSFunction::MarkForOptimization() {
12244   Isolate* isolate = GetIsolate();
12245   DCHECK(!IsOptimized());
12246   DCHECK(shared()->allows_lazy_compilation() ||
12247          !shared()->optimization_disabled());
12248   set_code_no_write_barrier(
12249       isolate->builtins()->builtin(Builtins::kCompileOptimized));
12250   // No write barrier required, since the builtin is part of the root set.
12251   if (FLAG_mark_shared_functions_for_tier_up) {
12252     shared()->set_marked_for_tier_up(true);
12253   }
12254 }
12255 
12256 
AttemptConcurrentOptimization()12257 void JSFunction::AttemptConcurrentOptimization() {
12258   Isolate* isolate = GetIsolate();
12259   if (!isolate->concurrent_recompilation_enabled() ||
12260       isolate->bootstrapper()->IsActive()) {
12261     MarkForOptimization();
12262     return;
12263   }
12264   DCHECK(!IsInOptimizationQueue());
12265   DCHECK(!IsOptimized());
12266   DCHECK(shared()->allows_lazy_compilation() ||
12267          !shared()->optimization_disabled());
12268   DCHECK(isolate->concurrent_recompilation_enabled());
12269   if (FLAG_trace_concurrent_recompilation) {
12270     PrintF("  ** Marking ");
12271     ShortPrint();
12272     PrintF(" for concurrent recompilation.\n");
12273   }
12274 
12275   set_code_no_write_barrier(
12276       isolate->builtins()->builtin(Builtins::kCompileOptimizedConcurrent));
12277   // No write barrier required, since the builtin is part of the root set.
12278   if (FLAG_mark_shared_functions_for_tier_up) {
12279     // TODO(leszeks): The compilation isn't concurrent if we trigger it using
12280     // this bit.
12281     shared()->set_marked_for_tier_up(true);
12282   }
12283 }
12284 
12285 // static
FindOrCreateLiterals(Handle<SharedFunctionInfo> shared,Handle<Context> native_context)12286 Handle<LiteralsArray> SharedFunctionInfo::FindOrCreateLiterals(
12287     Handle<SharedFunctionInfo> shared, Handle<Context> native_context) {
12288   Isolate* isolate = shared->GetIsolate();
12289   CodeAndLiterals result =
12290       shared->SearchOptimizedCodeMap(*native_context, BailoutId::None());
12291   if (result.literals != nullptr) {
12292     DCHECK(shared->feedback_metadata()->is_empty() ||
12293            !result.literals->feedback_vector()->is_empty());
12294     return handle(result.literals, isolate);
12295   }
12296 
12297   Handle<TypeFeedbackVector> feedback_vector =
12298       TypeFeedbackVector::New(isolate, handle(shared->feedback_metadata()));
12299   Handle<LiteralsArray> literals =
12300       LiteralsArray::New(isolate, feedback_vector, shared->num_literals());
12301   Handle<Code> code;
12302   if (result.code != nullptr) {
12303     code = Handle<Code>(result.code, isolate);
12304   }
12305   AddToOptimizedCodeMap(shared, native_context, code, literals,
12306                         BailoutId::None());
12307   return literals;
12308 }
12309 
12310 // static
AddToOptimizedCodeMap(Handle<SharedFunctionInfo> shared,Handle<Context> native_context,MaybeHandle<Code> code,Handle<LiteralsArray> literals,BailoutId osr_ast_id)12311 void SharedFunctionInfo::AddToOptimizedCodeMap(
12312     Handle<SharedFunctionInfo> shared, Handle<Context> native_context,
12313     MaybeHandle<Code> code, Handle<LiteralsArray> literals,
12314     BailoutId osr_ast_id) {
12315   Isolate* isolate = shared->GetIsolate();
12316   if (isolate->serializer_enabled()) return;
12317   DCHECK(code.is_null() ||
12318          code.ToHandleChecked()->kind() == Code::OPTIMIZED_FUNCTION);
12319   DCHECK(native_context->IsNativeContext());
12320   STATIC_ASSERT(kEntryLength == 4);
12321   Handle<FixedArray> new_code_map;
12322   int entry;
12323 
12324   if (shared->OptimizedCodeMapIsCleared()) {
12325     new_code_map = isolate->factory()->NewFixedArray(kInitialLength, TENURED);
12326     entry = kEntriesStart;
12327   } else {
12328     Handle<FixedArray> old_code_map(shared->optimized_code_map(), isolate);
12329     entry = shared->SearchOptimizedCodeMapEntry(*native_context, osr_ast_id);
12330     if (entry >= kEntriesStart) {
12331       // Just set the code and literals of the entry.
12332       if (!code.is_null()) {
12333         Handle<WeakCell> code_cell =
12334             isolate->factory()->NewWeakCell(code.ToHandleChecked());
12335         old_code_map->set(entry + kCachedCodeOffset, *code_cell);
12336       }
12337       Handle<WeakCell> literals_cell =
12338           isolate->factory()->NewWeakCell(literals);
12339       old_code_map->set(entry + kLiteralsOffset, *literals_cell);
12340       return;
12341     }
12342 
12343     // Can we reuse an entry?
12344     DCHECK(entry < kEntriesStart);
12345     int length = old_code_map->length();
12346     for (int i = kEntriesStart; i < length; i += kEntryLength) {
12347       if (WeakCell::cast(old_code_map->get(i + kContextOffset))->cleared()) {
12348         new_code_map = old_code_map;
12349         entry = i;
12350         break;
12351       }
12352     }
12353 
12354     if (entry < kEntriesStart) {
12355       // Copy old optimized code map and append one new entry.
12356       new_code_map = isolate->factory()->CopyFixedArrayAndGrow(
12357           old_code_map, kEntryLength, TENURED);
12358       // TODO(mstarzinger): Temporary workaround. The allocation above might
12359       // have flushed the optimized code map and the copy we created is full of
12360       // holes. For now we just give up on adding the entry and pretend it got
12361       // flushed.
12362       if (shared->OptimizedCodeMapIsCleared()) return;
12363       entry = old_code_map->length();
12364     }
12365   }
12366 
12367   Handle<WeakCell> code_cell =
12368       code.is_null() ? isolate->factory()->empty_weak_cell()
12369                      : isolate->factory()->NewWeakCell(code.ToHandleChecked());
12370   Handle<WeakCell> literals_cell = isolate->factory()->NewWeakCell(literals);
12371   WeakCell* context_cell = native_context->self_weak_cell();
12372 
12373   new_code_map->set(entry + kContextOffset, context_cell);
12374   new_code_map->set(entry + kCachedCodeOffset, *code_cell);
12375   new_code_map->set(entry + kLiteralsOffset, *literals_cell);
12376   new_code_map->set(entry + kOsrAstIdOffset, Smi::FromInt(osr_ast_id.ToInt()));
12377 
12378 #ifdef DEBUG
12379   for (int i = kEntriesStart; i < new_code_map->length(); i += kEntryLength) {
12380     WeakCell* cell = WeakCell::cast(new_code_map->get(i + kContextOffset));
12381     DCHECK(cell->cleared() || cell->value()->IsNativeContext());
12382     cell = WeakCell::cast(new_code_map->get(i + kCachedCodeOffset));
12383     DCHECK(cell->cleared() ||
12384            (cell->value()->IsCode() &&
12385             Code::cast(cell->value())->kind() == Code::OPTIMIZED_FUNCTION));
12386     cell = WeakCell::cast(new_code_map->get(i + kLiteralsOffset));
12387     DCHECK(cell->cleared() || cell->value()->IsFixedArray());
12388     DCHECK(new_code_map->get(i + kOsrAstIdOffset)->IsSmi());
12389   }
12390 #endif
12391 
12392   FixedArray* old_code_map = shared->optimized_code_map();
12393   if (old_code_map != *new_code_map) {
12394     shared->set_optimized_code_map(*new_code_map);
12395   }
12396 }
12397 
12398 
ClearOptimizedCodeMap()12399 void SharedFunctionInfo::ClearOptimizedCodeMap() {
12400   FixedArray* empty_fixed_array = GetHeap()->empty_fixed_array();
12401   set_optimized_code_map(empty_fixed_array, SKIP_WRITE_BARRIER);
12402 }
12403 
12404 
EvictFromOptimizedCodeMap(Code * optimized_code,const char * reason)12405 void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
12406                                                    const char* reason) {
12407   DisallowHeapAllocation no_gc;
12408   if (OptimizedCodeMapIsCleared()) return;
12409 
12410   Heap* heap = GetHeap();
12411   FixedArray* code_map = optimized_code_map();
12412   int dst = kEntriesStart;
12413   int length = code_map->length();
12414   for (int src = kEntriesStart; src < length; src += kEntryLength) {
12415     DCHECK(WeakCell::cast(code_map->get(src))->cleared() ||
12416            WeakCell::cast(code_map->get(src))->value()->IsNativeContext());
12417     if (WeakCell::cast(code_map->get(src + kCachedCodeOffset))->value() ==
12418         optimized_code) {
12419       BailoutId osr(Smi::cast(code_map->get(src + kOsrAstIdOffset))->value());
12420       if (FLAG_trace_opt) {
12421         PrintF("[evicting entry from optimizing code map (%s) for ", reason);
12422         ShortPrint();
12423         if (osr.IsNone()) {
12424           PrintF("]\n");
12425         } else {
12426           PrintF(" (osr ast id %d)]\n", osr.ToInt());
12427         }
12428       }
12429       if (!osr.IsNone()) {
12430         // Evict the src entry by not copying it to the dst entry.
12431         continue;
12432       }
12433       // In case of non-OSR entry just clear the code in order to proceed
12434       // sharing literals.
12435       code_map->set(src + kCachedCodeOffset, heap->empty_weak_cell(),
12436                     SKIP_WRITE_BARRIER);
12437     }
12438 
12439     // Keep the src entry by copying it to the dst entry.
12440     if (dst != src) {
12441       code_map->set(dst + kContextOffset, code_map->get(src + kContextOffset));
12442       code_map->set(dst + kCachedCodeOffset,
12443                     code_map->get(src + kCachedCodeOffset));
12444       code_map->set(dst + kLiteralsOffset,
12445                     code_map->get(src + kLiteralsOffset));
12446       code_map->set(dst + kOsrAstIdOffset,
12447                     code_map->get(src + kOsrAstIdOffset));
12448     }
12449     dst += kEntryLength;
12450   }
12451   if (dst != length) {
12452     // Always trim even when array is cleared because of heap verifier.
12453     heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(code_map,
12454                                                            length - dst);
12455     if (code_map->length() == kEntriesStart) {
12456       ClearOptimizedCodeMap();
12457     }
12458   }
12459 }
12460 
12461 
TrimOptimizedCodeMap(int shrink_by)12462 void SharedFunctionInfo::TrimOptimizedCodeMap(int shrink_by) {
12463   FixedArray* code_map = optimized_code_map();
12464   DCHECK(shrink_by % kEntryLength == 0);
12465   DCHECK(shrink_by <= code_map->length() - kEntriesStart);
12466   // Always trim even when array is cleared because of heap verifier.
12467   GetHeap()->RightTrimFixedArray<Heap::SEQUENTIAL_TO_SWEEPER>(code_map,
12468                                                               shrink_by);
12469   if (code_map->length() == kEntriesStart) {
12470     ClearOptimizedCodeMap();
12471   }
12472 }
12473 
12474 // static
EnsureLiterals(Handle<JSFunction> function)12475 void JSFunction::EnsureLiterals(Handle<JSFunction> function) {
12476   Handle<SharedFunctionInfo> shared(function->shared());
12477   Handle<Context> native_context(function->context()->native_context());
12478   if (function->literals() ==
12479       function->GetIsolate()->heap()->empty_literals_array()) {
12480     Handle<LiteralsArray> literals =
12481         SharedFunctionInfo::FindOrCreateLiterals(shared, native_context);
12482     function->set_literals(*literals);
12483   }
12484 }
12485 
GetMinInobjectSlack(Map * map,void * data)12486 static void GetMinInobjectSlack(Map* map, void* data) {
12487   int slack = map->unused_property_fields();
12488   if (*reinterpret_cast<int*>(data) > slack) {
12489     *reinterpret_cast<int*>(data) = slack;
12490   }
12491 }
12492 
12493 
ShrinkInstanceSize(Map * map,void * data)12494 static void ShrinkInstanceSize(Map* map, void* data) {
12495   int slack = *reinterpret_cast<int*>(data);
12496   map->SetInObjectProperties(map->GetInObjectProperties() - slack);
12497   map->set_unused_property_fields(map->unused_property_fields() - slack);
12498   map->set_instance_size(map->instance_size() - slack * kPointerSize);
12499   map->set_construction_counter(Map::kNoSlackTracking);
12500 
12501   // Visitor id might depend on the instance size, recalculate it.
12502   map->set_visitor_id(Heap::GetStaticVisitorIdForMap(map));
12503 }
12504 
StopSlackTracking(Map * map,void * data)12505 static void StopSlackTracking(Map* map, void* data) {
12506   map->set_construction_counter(Map::kNoSlackTracking);
12507 }
12508 
CompleteInobjectSlackTracking()12509 void Map::CompleteInobjectSlackTracking() {
12510   // Has to be an initial map.
12511   DCHECK(GetBackPointer()->IsUndefined(GetIsolate()));
12512 
12513   int slack = unused_property_fields();
12514   TransitionArray::TraverseTransitionTree(this, &GetMinInobjectSlack, &slack);
12515   if (slack != 0) {
12516     // Resize the initial map and all maps in its transition tree.
12517     TransitionArray::TraverseTransitionTree(this, &ShrinkInstanceSize, &slack);
12518   } else {
12519     TransitionArray::TraverseTransitionTree(this, &StopSlackTracking, nullptr);
12520   }
12521 }
12522 
12523 
PrototypeBenefitsFromNormalization(Handle<JSObject> object)12524 static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) {
12525   DisallowHeapAllocation no_gc;
12526   if (!object->HasFastProperties()) return false;
12527   Map* map = object->map();
12528   if (map->is_prototype_map()) return false;
12529   DescriptorArray* descriptors = map->instance_descriptors();
12530   for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
12531     PropertyDetails details = descriptors->GetDetails(i);
12532     if (details.location() == kDescriptor) continue;
12533     if (details.representation().IsHeapObject() ||
12534         details.representation().IsTagged()) {
12535       FieldIndex index = FieldIndex::ForDescriptor(map, i);
12536       if (object->RawFastPropertyAt(index)->IsJSFunction()) return true;
12537     }
12538   }
12539   return false;
12540 }
12541 
12542 // static
MakePrototypesFast(Handle<Object> receiver,WhereToStart where_to_start,Isolate * isolate)12543 void JSObject::MakePrototypesFast(Handle<Object> receiver,
12544                                   WhereToStart where_to_start,
12545                                   Isolate* isolate) {
12546   if (!receiver->IsJSReceiver()) return;
12547   for (PrototypeIterator iter(isolate, Handle<JSReceiver>::cast(receiver),
12548                               where_to_start);
12549        !iter.IsAtEnd(); iter.Advance()) {
12550     Handle<Object> current = PrototypeIterator::GetCurrent(iter);
12551     if (!current->IsJSObject()) return;
12552     Handle<JSObject> current_obj = Handle<JSObject>::cast(current);
12553     Map* current_map = current_obj->map();
12554     if (current_map->is_prototype_map() &&
12555         !current_map->should_be_fast_prototype_map()) {
12556       Handle<Map> map(current_map);
12557       Map::SetShouldBeFastPrototypeMap(map, true, isolate);
12558       JSObject::OptimizeAsPrototype(current_obj, FAST_PROTOTYPE);
12559     }
12560   }
12561 }
12562 
12563 // static
OptimizeAsPrototype(Handle<JSObject> object,PrototypeOptimizationMode mode)12564 void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
12565                                    PrototypeOptimizationMode mode) {
12566   if (object->IsJSGlobalObject()) return;
12567   if (mode == FAST_PROTOTYPE && PrototypeBenefitsFromNormalization(object)) {
12568     // First normalize to ensure all JSFunctions are DATA_CONSTANT.
12569     JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0,
12570                                   "NormalizeAsPrototype");
12571   }
12572   Handle<Map> previous_map(object->map());
12573   if (object->map()->is_prototype_map()) {
12574     if (object->map()->should_be_fast_prototype_map() &&
12575         !object->HasFastProperties()) {
12576       JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype");
12577     }
12578   } else {
12579     if (object->map() == *previous_map) {
12580       Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype");
12581       JSObject::MigrateToMap(object, new_map);
12582     }
12583     object->map()->set_is_prototype_map(true);
12584 
12585     // Replace the pointer to the exact constructor with the Object function
12586     // from the same context if undetectable from JS. This is to avoid keeping
12587     // memory alive unnecessarily.
12588     Object* maybe_constructor = object->map()->GetConstructor();
12589     if (maybe_constructor->IsJSFunction()) {
12590       JSFunction* constructor = JSFunction::cast(maybe_constructor);
12591       Isolate* isolate = object->GetIsolate();
12592       if (!constructor->shared()->IsApiFunction() &&
12593           object->class_name() == isolate->heap()->Object_string()) {
12594         Context* context = constructor->context()->native_context();
12595         JSFunction* object_function = context->object_function();
12596         object->map()->SetConstructor(object_function);
12597       }
12598     }
12599   }
12600 }
12601 
12602 
12603 // static
ReoptimizeIfPrototype(Handle<JSObject> object)12604 void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) {
12605   if (!object->map()->is_prototype_map()) return;
12606   if (!object->map()->should_be_fast_prototype_map()) return;
12607   OptimizeAsPrototype(object, FAST_PROTOTYPE);
12608 }
12609 
12610 
12611 // static
LazyRegisterPrototypeUser(Handle<Map> user,Isolate * isolate)12612 void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
12613   // Contract: In line with InvalidatePrototypeChains()'s requirements,
12614   // leaf maps don't need to register as users, only prototypes do.
12615   DCHECK(user->is_prototype_map());
12616 
12617   Handle<Map> current_user = user;
12618   Handle<PrototypeInfo> current_user_info =
12619       Map::GetOrCreatePrototypeInfo(user, isolate);
12620   for (PrototypeIterator iter(user); !iter.IsAtEnd(); iter.Advance()) {
12621     // Walk up the prototype chain as far as links haven't been registered yet.
12622     if (current_user_info->registry_slot() != PrototypeInfo::UNREGISTERED) {
12623       break;
12624     }
12625     Handle<Object> maybe_proto = PrototypeIterator::GetCurrent(iter);
12626     // Proxies on the prototype chain are not supported. They make it
12627     // impossible to make any assumptions about the prototype chain anyway.
12628     if (maybe_proto->IsJSProxy()) return;
12629     Handle<JSObject> proto = Handle<JSObject>::cast(maybe_proto);
12630     Handle<PrototypeInfo> proto_info =
12631         Map::GetOrCreatePrototypeInfo(proto, isolate);
12632     Handle<Object> maybe_registry(proto_info->prototype_users(), isolate);
12633     int slot = 0;
12634     Handle<WeakFixedArray> new_array =
12635         WeakFixedArray::Add(maybe_registry, current_user, &slot);
12636     current_user_info->set_registry_slot(slot);
12637     if (!maybe_registry.is_identical_to(new_array)) {
12638       proto_info->set_prototype_users(*new_array);
12639     }
12640     if (FLAG_trace_prototype_users) {
12641       PrintF("Registering %p as a user of prototype %p (map=%p).\n",
12642              reinterpret_cast<void*>(*current_user),
12643              reinterpret_cast<void*>(*proto),
12644              reinterpret_cast<void*>(proto->map()));
12645     }
12646 
12647     current_user = handle(proto->map(), isolate);
12648     current_user_info = proto_info;
12649   }
12650 }
12651 
12652 
12653 // Can be called regardless of whether |user| was actually registered with
12654 // |prototype|. Returns true when there was a registration.
12655 // static
UnregisterPrototypeUser(Handle<Map> user,Isolate * isolate)12656 bool JSObject::UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
12657   DCHECK(user->is_prototype_map());
12658   // If it doesn't have a PrototypeInfo, it was never registered.
12659   if (!user->prototype_info()->IsPrototypeInfo()) return false;
12660   // If it had no prototype before, see if it had users that might expect
12661   // registration.
12662   if (!user->prototype()->IsJSObject()) {
12663     Object* users =
12664         PrototypeInfo::cast(user->prototype_info())->prototype_users();
12665     return users->IsWeakFixedArray();
12666   }
12667   Handle<JSObject> prototype(JSObject::cast(user->prototype()), isolate);
12668   Handle<PrototypeInfo> user_info =
12669       Map::GetOrCreatePrototypeInfo(user, isolate);
12670   int slot = user_info->registry_slot();
12671   if (slot == PrototypeInfo::UNREGISTERED) return false;
12672   DCHECK(prototype->map()->is_prototype_map());
12673   Object* maybe_proto_info = prototype->map()->prototype_info();
12674   // User knows its registry slot, prototype info and user registry must exist.
12675   DCHECK(maybe_proto_info->IsPrototypeInfo());
12676   Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info),
12677                                    isolate);
12678   Object* maybe_registry = proto_info->prototype_users();
12679   DCHECK(maybe_registry->IsWeakFixedArray());
12680   DCHECK(WeakFixedArray::cast(maybe_registry)->Get(slot) == *user);
12681   WeakFixedArray::cast(maybe_registry)->Clear(slot);
12682   if (FLAG_trace_prototype_users) {
12683     PrintF("Unregistering %p as a user of prototype %p.\n",
12684            reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype));
12685   }
12686   return true;
12687 }
12688 
12689 
InvalidatePrototypeChainsInternal(Map * map)12690 static void InvalidatePrototypeChainsInternal(Map* map) {
12691   DCHECK(map->is_prototype_map());
12692   if (FLAG_trace_prototype_users) {
12693     PrintF("Invalidating prototype map %p 's cell\n",
12694            reinterpret_cast<void*>(map));
12695   }
12696   Object* maybe_proto_info = map->prototype_info();
12697   if (!maybe_proto_info->IsPrototypeInfo()) return;
12698   PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info);
12699   Object* maybe_cell = proto_info->validity_cell();
12700   if (maybe_cell->IsCell()) {
12701     // Just set the value; the cell will be replaced lazily.
12702     Cell* cell = Cell::cast(maybe_cell);
12703     cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid));
12704   }
12705 
12706   WeakFixedArray::Iterator iterator(proto_info->prototype_users());
12707   // For now, only maps register themselves as users.
12708   Map* user;
12709   while ((user = iterator.Next<Map>())) {
12710     // Walk the prototype chain (backwards, towards leaf objects) if necessary.
12711     InvalidatePrototypeChainsInternal(user);
12712   }
12713 }
12714 
12715 
12716 // static
InvalidatePrototypeChains(Map * map)12717 void JSObject::InvalidatePrototypeChains(Map* map) {
12718   DisallowHeapAllocation no_gc;
12719   InvalidatePrototypeChainsInternal(map);
12720 }
12721 
12722 
12723 // static
GetOrCreatePrototypeInfo(Handle<JSObject> prototype,Isolate * isolate)12724 Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<JSObject> prototype,
12725                                                     Isolate* isolate) {
12726   Object* maybe_proto_info = prototype->map()->prototype_info();
12727   if (maybe_proto_info->IsPrototypeInfo()) {
12728     return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
12729   }
12730   Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
12731   prototype->map()->set_prototype_info(*proto_info);
12732   return proto_info;
12733 }
12734 
12735 
12736 // static
GetOrCreatePrototypeInfo(Handle<Map> prototype_map,Isolate * isolate)12737 Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<Map> prototype_map,
12738                                                     Isolate* isolate) {
12739   Object* maybe_proto_info = prototype_map->prototype_info();
12740   if (maybe_proto_info->IsPrototypeInfo()) {
12741     return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
12742   }
12743   Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
12744   prototype_map->set_prototype_info(*proto_info);
12745   return proto_info;
12746 }
12747 
12748 // static
SetShouldBeFastPrototypeMap(Handle<Map> map,bool value,Isolate * isolate)12749 void Map::SetShouldBeFastPrototypeMap(Handle<Map> map, bool value,
12750                                       Isolate* isolate) {
12751   if (value == false && !map->prototype_info()->IsPrototypeInfo()) {
12752     // "False" is the implicit default value, so there's nothing to do.
12753     return;
12754   }
12755   GetOrCreatePrototypeInfo(map, isolate)->set_should_be_fast_map(value);
12756 }
12757 
12758 // static
GetOrCreatePrototypeChainValidityCell(Handle<Map> map,Isolate * isolate)12759 Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
12760                                                         Isolate* isolate) {
12761   Handle<Object> maybe_prototype(
12762       map->GetPrototypeChainRootMap(isolate)->prototype(), isolate);
12763   if (!maybe_prototype->IsJSObject()) return Handle<Cell>::null();
12764   Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype);
12765   // Ensure the prototype is registered with its own prototypes so its cell
12766   // will be invalidated when necessary.
12767   JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate),
12768                                       isolate);
12769   Handle<PrototypeInfo> proto_info =
12770       GetOrCreatePrototypeInfo(prototype, isolate);
12771   Object* maybe_cell = proto_info->validity_cell();
12772   // Return existing cell if it's still valid.
12773   if (maybe_cell->IsCell()) {
12774     Handle<Cell> cell(Cell::cast(maybe_cell), isolate);
12775     if (cell->value() == Smi::FromInt(Map::kPrototypeChainValid)) {
12776       return cell;
12777     }
12778   }
12779   // Otherwise create a new cell.
12780   Handle<Cell> cell = isolate->factory()->NewCell(
12781       handle(Smi::FromInt(Map::kPrototypeChainValid), isolate));
12782   proto_info->set_validity_cell(*cell);
12783   return cell;
12784 }
12785 
12786 // static
GetOrCreatePrototypeWeakCell(Handle<JSObject> prototype,Isolate * isolate)12787 Handle<WeakCell> Map::GetOrCreatePrototypeWeakCell(Handle<JSObject> prototype,
12788                                                    Isolate* isolate) {
12789   DCHECK(!prototype.is_null());
12790   Handle<PrototypeInfo> proto_info =
12791       GetOrCreatePrototypeInfo(prototype, isolate);
12792   Object* maybe_cell = proto_info->weak_cell();
12793   // Return existing cell if it's already created.
12794   if (maybe_cell->IsWeakCell()) {
12795     Handle<WeakCell> cell(WeakCell::cast(maybe_cell), isolate);
12796     DCHECK(!cell->cleared());
12797     return cell;
12798   }
12799   // Otherwise create a new cell.
12800   Handle<WeakCell> cell = isolate->factory()->NewWeakCell(prototype);
12801   proto_info->set_weak_cell(*cell);
12802   return cell;
12803 }
12804 
12805 // static
SetPrototype(Handle<Map> map,Handle<Object> prototype,PrototypeOptimizationMode proto_mode)12806 void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype,
12807                        PrototypeOptimizationMode proto_mode) {
12808   RuntimeCallTimerScope stats_scope(*map, &RuntimeCallStats::Map_SetPrototype);
12809 
12810   bool is_hidden = false;
12811   if (prototype->IsJSObject()) {
12812     Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype);
12813     JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode);
12814 
12815     Object* maybe_constructor = prototype_jsobj->map()->GetConstructor();
12816     if (maybe_constructor->IsJSFunction()) {
12817       JSFunction* constructor = JSFunction::cast(maybe_constructor);
12818       Object* data = constructor->shared()->function_data();
12819       is_hidden = (data->IsFunctionTemplateInfo() &&
12820                    FunctionTemplateInfo::cast(data)->hidden_prototype()) ||
12821                   prototype->IsJSGlobalObject();
12822     }
12823   }
12824   map->set_has_hidden_prototype(is_hidden);
12825 
12826   WriteBarrierMode wb_mode = prototype->IsNull(map->GetIsolate())
12827                                  ? SKIP_WRITE_BARRIER
12828                                  : UPDATE_WRITE_BARRIER;
12829   map->set_prototype(*prototype, wb_mode);
12830 }
12831 
12832 
CacheInitialJSArrayMaps(Handle<Context> native_context,Handle<Map> initial_map)12833 Handle<Object> CacheInitialJSArrayMaps(
12834     Handle<Context> native_context, Handle<Map> initial_map) {
12835   // Replace all of the cached initial array maps in the native context with
12836   // the appropriate transitioned elements kind maps.
12837   Handle<Map> current_map = initial_map;
12838   ElementsKind kind = current_map->elements_kind();
12839   DCHECK_EQ(GetInitialFastElementsKind(), kind);
12840   native_context->set(Context::ArrayMapIndex(kind), *current_map);
12841   for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1;
12842        i < kFastElementsKindCount; ++i) {
12843     Handle<Map> new_map;
12844     ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
12845     if (Map* maybe_elements_transition = current_map->ElementsTransitionMap()) {
12846       new_map = handle(maybe_elements_transition);
12847     } else {
12848       new_map = Map::CopyAsElementsKind(
12849           current_map, next_kind, INSERT_TRANSITION);
12850     }
12851     DCHECK_EQ(next_kind, new_map->elements_kind());
12852     native_context->set(Context::ArrayMapIndex(next_kind), *new_map);
12853     current_map = new_map;
12854   }
12855   return initial_map;
12856 }
12857 
12858 
SetInstancePrototype(Handle<JSFunction> function,Handle<Object> value)12859 void JSFunction::SetInstancePrototype(Handle<JSFunction> function,
12860                                       Handle<Object> value) {
12861   Isolate* isolate = function->GetIsolate();
12862 
12863   DCHECK(value->IsJSReceiver());
12864 
12865   // Now some logic for the maps of the objects that are created by using this
12866   // function as a constructor.
12867   if (function->has_initial_map()) {
12868     // If the function has allocated the initial map replace it with a
12869     // copy containing the new prototype.  Also complete any in-object
12870     // slack tracking that is in progress at this point because it is
12871     // still tracking the old copy.
12872     function->CompleteInobjectSlackTrackingIfActive();
12873 
12874     Handle<Map> initial_map(function->initial_map(), isolate);
12875 
12876     if (!initial_map->GetIsolate()->bootstrapper()->IsActive() &&
12877         initial_map->instance_type() == JS_OBJECT_TYPE) {
12878       // Put the value in the initial map field until an initial map is needed.
12879       // At that point, a new initial map is created and the prototype is put
12880       // into the initial map where it belongs.
12881       function->set_prototype_or_initial_map(*value);
12882     } else {
12883       Handle<Map> new_map = Map::Copy(initial_map, "SetInstancePrototype");
12884       JSFunction::SetInitialMap(function, new_map, value);
12885 
12886       // If the function is used as the global Array function, cache the
12887       // updated initial maps (and transitioned versions) in the native context.
12888       Handle<Context> native_context(function->context()->native_context(),
12889                                      isolate);
12890       Handle<Object> array_function(
12891           native_context->get(Context::ARRAY_FUNCTION_INDEX), isolate);
12892       if (array_function->IsJSFunction() &&
12893           *function == JSFunction::cast(*array_function)) {
12894         CacheInitialJSArrayMaps(native_context, new_map);
12895       }
12896     }
12897 
12898     // Deoptimize all code that embeds the previous initial map.
12899     initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
12900         isolate, DependentCode::kInitialMapChangedGroup);
12901   } else {
12902     // Put the value in the initial map field until an initial map is
12903     // needed.  At that point, a new initial map is created and the
12904     // prototype is put into the initial map where it belongs.
12905     function->set_prototype_or_initial_map(*value);
12906     if (value->IsJSObject()) {
12907       // Optimize as prototype to detach it from its transition tree.
12908       JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value),
12909                                     FAST_PROTOTYPE);
12910     }
12911   }
12912   isolate->heap()->ClearInstanceofCache();
12913 }
12914 
12915 
SetPrototype(Handle<JSFunction> function,Handle<Object> value)12916 void JSFunction::SetPrototype(Handle<JSFunction> function,
12917                               Handle<Object> value) {
12918   DCHECK(function->IsConstructor() ||
12919          IsGeneratorFunction(function->shared()->kind()));
12920   Handle<Object> construct_prototype = value;
12921 
12922   // If the value is not a JSReceiver, store the value in the map's
12923   // constructor field so it can be accessed.  Also, set the prototype
12924   // used for constructing objects to the original object prototype.
12925   // See ECMA-262 13.2.2.
12926   if (!value->IsJSReceiver()) {
12927     // Copy the map so this does not affect unrelated functions.
12928     // Remove map transitions because they point to maps with a
12929     // different prototype.
12930     Handle<Map> new_map = Map::Copy(handle(function->map()), "SetPrototype");
12931 
12932     JSObject::MigrateToMap(function, new_map);
12933     new_map->SetConstructor(*value);
12934     new_map->set_non_instance_prototype(true);
12935     Isolate* isolate = new_map->GetIsolate();
12936 
12937     construct_prototype = handle(
12938         IsGeneratorFunction(function->shared()->kind())
12939             ? function->context()
12940                   ->native_context()
12941                   ->initial_generator_prototype()
12942             : function->context()->native_context()->initial_object_prototype(),
12943         isolate);
12944   } else {
12945     function->map()->set_non_instance_prototype(false);
12946   }
12947 
12948   return SetInstancePrototype(function, construct_prototype);
12949 }
12950 
12951 
RemovePrototype()12952 bool JSFunction::RemovePrototype() {
12953   Context* native_context = context()->native_context();
12954   Map* no_prototype_map =
12955       is_strict(shared()->language_mode())
12956           ? native_context->strict_function_without_prototype_map()
12957           : native_context->sloppy_function_without_prototype_map();
12958 
12959   if (map() == no_prototype_map) return true;
12960 
12961 #ifdef DEBUG
12962   if (map() != (is_strict(shared()->language_mode())
12963                     ? native_context->strict_function_map()
12964                     : native_context->sloppy_function_map())) {
12965     return false;
12966   }
12967 #endif
12968 
12969   set_map(no_prototype_map);
12970   set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value());
12971   return true;
12972 }
12973 
12974 
SetInitialMap(Handle<JSFunction> function,Handle<Map> map,Handle<Object> prototype)12975 void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
12976                                Handle<Object> prototype) {
12977   if (map->prototype() != *prototype) {
12978     Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
12979   }
12980   function->set_prototype_or_initial_map(*map);
12981   map->SetConstructor(*function);
12982 #if TRACE_MAPS
12983   if (FLAG_trace_maps) {
12984     PrintF("[TraceMaps: InitialMap map= %p SFI= %d_%s ]\n",
12985            reinterpret_cast<void*>(*map), function->shared()->unique_id(),
12986            function->shared()->DebugName()->ToCString().get());
12987   }
12988 #endif
12989 }
12990 
12991 
12992 #ifdef DEBUG
12993 namespace {
12994 
CanSubclassHaveInobjectProperties(InstanceType instance_type)12995 bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
12996   switch (instance_type) {
12997     case JS_API_OBJECT_TYPE:
12998     case JS_ARRAY_BUFFER_TYPE:
12999     case JS_ARRAY_TYPE:
13000     case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
13001     case JS_DATA_VIEW_TYPE:
13002     case JS_DATE_TYPE:
13003     case JS_FUNCTION_TYPE:
13004     case JS_GENERATOR_OBJECT_TYPE:
13005     case JS_MAP_ITERATOR_TYPE:
13006     case JS_MAP_TYPE:
13007     case JS_MESSAGE_OBJECT_TYPE:
13008     case JS_OBJECT_TYPE:
13009     case JS_ERROR_TYPE:
13010     case JS_ARGUMENTS_TYPE:
13011     case JS_PROMISE_TYPE:
13012     case JS_REGEXP_TYPE:
13013     case JS_SET_ITERATOR_TYPE:
13014     case JS_SET_TYPE:
13015     case JS_SPECIAL_API_OBJECT_TYPE:
13016     case JS_TYPED_ARRAY_TYPE:
13017     case JS_VALUE_TYPE:
13018     case JS_WEAK_MAP_TYPE:
13019     case JS_WEAK_SET_TYPE:
13020       return true;
13021 
13022     case BYTECODE_ARRAY_TYPE:
13023     case BYTE_ARRAY_TYPE:
13024     case CELL_TYPE:
13025     case CODE_TYPE:
13026     case FILLER_TYPE:
13027     case FIXED_ARRAY_TYPE:
13028     case FIXED_DOUBLE_ARRAY_TYPE:
13029     case FOREIGN_TYPE:
13030     case FREE_SPACE_TYPE:
13031     case HEAP_NUMBER_TYPE:
13032     case JS_BOUND_FUNCTION_TYPE:
13033     case JS_GLOBAL_OBJECT_TYPE:
13034     case JS_GLOBAL_PROXY_TYPE:
13035     case JS_PROXY_TYPE:
13036     case MAP_TYPE:
13037     case MUTABLE_HEAP_NUMBER_TYPE:
13038     case ODDBALL_TYPE:
13039     case PROPERTY_CELL_TYPE:
13040     case SHARED_FUNCTION_INFO_TYPE:
13041     case SIMD128_VALUE_TYPE:
13042     case SYMBOL_TYPE:
13043     case WEAK_CELL_TYPE:
13044 
13045 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
13046   case FIXED_##TYPE##_ARRAY_TYPE:
13047 #undef TYPED_ARRAY_CASE
13048 
13049 #define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE:
13050       STRUCT_LIST(MAKE_STRUCT_CASE)
13051 #undef MAKE_STRUCT_CASE
13052       // We must not end up here for these instance types at all.
13053       UNREACHABLE();
13054     // Fall through.
13055     default:
13056       return false;
13057   }
13058 }
13059 
13060 }  // namespace
13061 #endif
13062 
13063 
EnsureHasInitialMap(Handle<JSFunction> function)13064 void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
13065   DCHECK(function->IsConstructor() ||
13066          IsResumableFunction(function->shared()->kind()));
13067   if (function->has_initial_map()) return;
13068   Isolate* isolate = function->GetIsolate();
13069 
13070   // The constructor should be compiled for the optimization hints to be
13071   // available.
13072   Compiler::Compile(function, Compiler::CLEAR_EXCEPTION);
13073 
13074   // First create a new map with the size and number of in-object properties
13075   // suggested by the function.
13076   InstanceType instance_type;
13077   if (IsResumableFunction(function->shared()->kind())) {
13078     instance_type = JS_GENERATOR_OBJECT_TYPE;
13079   } else {
13080     instance_type = JS_OBJECT_TYPE;
13081   }
13082   int instance_size;
13083   int in_object_properties;
13084   function->CalculateInstanceSize(instance_type, 0, &instance_size,
13085                                   &in_object_properties);
13086 
13087   Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size);
13088 
13089   // Fetch or allocate prototype.
13090   Handle<Object> prototype;
13091   if (function->has_instance_prototype()) {
13092     prototype = handle(function->instance_prototype(), isolate);
13093   } else {
13094     prototype = isolate->factory()->NewFunctionPrototype(function);
13095   }
13096   map->SetInObjectProperties(in_object_properties);
13097   map->set_unused_property_fields(in_object_properties);
13098   DCHECK(map->has_fast_object_elements());
13099 
13100   // Finally link initial map and constructor function.
13101   DCHECK(prototype->IsJSReceiver());
13102   JSFunction::SetInitialMap(function, map, prototype);
13103   map->StartInobjectSlackTracking();
13104 }
13105 
13106 
13107 // static
GetDerivedMap(Isolate * isolate,Handle<JSFunction> constructor,Handle<JSReceiver> new_target)13108 MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
13109                                            Handle<JSFunction> constructor,
13110                                            Handle<JSReceiver> new_target) {
13111   EnsureHasInitialMap(constructor);
13112 
13113   Handle<Map> constructor_initial_map(constructor->initial_map(), isolate);
13114   if (*new_target == *constructor) return constructor_initial_map;
13115 
13116   // Fast case, new.target is a subclass of constructor. The map is cacheable
13117   // (and may already have been cached). new.target.prototype is guaranteed to
13118   // be a JSReceiver.
13119   if (new_target->IsJSFunction()) {
13120     Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
13121 
13122     // Check that |function|'s initial map still in sync with the |constructor|,
13123     // otherwise we must create a new initial map for |function|.
13124     if (function->has_initial_map() &&
13125         function->initial_map()->GetConstructor() == *constructor) {
13126       return handle(function->initial_map(), isolate);
13127     }
13128 
13129     // Create a new map with the size and number of in-object properties
13130     // suggested by |function|.
13131 
13132     // Link initial map and constructor function if the new.target is actually a
13133     // subclass constructor.
13134     if (IsSubclassConstructor(function->shared()->kind())) {
13135       Handle<Object> prototype(function->instance_prototype(), isolate);
13136       InstanceType instance_type = constructor_initial_map->instance_type();
13137       DCHECK(CanSubclassHaveInobjectProperties(instance_type));
13138       int internal_fields =
13139           JSObject::GetInternalFieldCount(*constructor_initial_map);
13140       int pre_allocated = constructor_initial_map->GetInObjectProperties() -
13141                           constructor_initial_map->unused_property_fields();
13142       int instance_size;
13143       int in_object_properties;
13144       function->CalculateInstanceSizeForDerivedClass(
13145           instance_type, internal_fields, &instance_size,
13146           &in_object_properties);
13147 
13148       int unused_property_fields = in_object_properties - pre_allocated;
13149       Handle<Map> map =
13150           Map::CopyInitialMap(constructor_initial_map, instance_size,
13151                               in_object_properties, unused_property_fields);
13152       map->set_new_target_is_base(false);
13153 
13154       JSFunction::SetInitialMap(function, map, prototype);
13155       map->SetConstructor(*constructor);
13156       map->set_construction_counter(Map::kNoSlackTracking);
13157       map->StartInobjectSlackTracking();
13158       return map;
13159     }
13160   }
13161 
13162   // Slow path, new.target is either a proxy or can't cache the map.
13163   // new.target.prototype is not guaranteed to be a JSReceiver, and may need to
13164   // fall back to the intrinsicDefaultProto.
13165   Handle<Object> prototype;
13166   if (new_target->IsJSFunction()) {
13167     Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
13168     // Make sure the new.target.prototype is cached.
13169     EnsureHasInitialMap(function);
13170     prototype = handle(function->prototype(), isolate);
13171   } else {
13172     Handle<String> prototype_string = isolate->factory()->prototype_string();
13173     ASSIGN_RETURN_ON_EXCEPTION(
13174         isolate, prototype,
13175         JSReceiver::GetProperty(new_target, prototype_string), Map);
13176     // The above prototype lookup might change the constructor and its
13177     // prototype, hence we have to reload the initial map.
13178     EnsureHasInitialMap(constructor);
13179     constructor_initial_map = handle(constructor->initial_map(), isolate);
13180   }
13181 
13182   // If prototype is not a JSReceiver, fetch the intrinsicDefaultProto from the
13183   // correct realm. Rather than directly fetching the .prototype, we fetch the
13184   // constructor that points to the .prototype. This relies on
13185   // constructor.prototype being FROZEN for those constructors.
13186   if (!prototype->IsJSReceiver()) {
13187     Handle<Context> context;
13188     ASSIGN_RETURN_ON_EXCEPTION(isolate, context,
13189                                JSReceiver::GetFunctionRealm(new_target), Map);
13190     DCHECK(context->IsNativeContext());
13191     Handle<Object> maybe_index = JSReceiver::GetDataProperty(
13192         constructor, isolate->factory()->native_context_index_symbol());
13193     int index = maybe_index->IsSmi() ? Smi::cast(*maybe_index)->value()
13194                                      : Context::OBJECT_FUNCTION_INDEX;
13195     Handle<JSFunction> realm_constructor(JSFunction::cast(context->get(index)));
13196     prototype = handle(realm_constructor->prototype(), isolate);
13197   }
13198 
13199   Handle<Map> map = Map::CopyInitialMap(constructor_initial_map);
13200   map->set_new_target_is_base(false);
13201   DCHECK(prototype->IsJSReceiver());
13202   if (map->prototype() != *prototype) {
13203     Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
13204   }
13205   map->SetConstructor(*constructor);
13206   return map;
13207 }
13208 
13209 
PrintName(FILE * out)13210 void JSFunction::PrintName(FILE* out) {
13211   std::unique_ptr<char[]> name = shared()->DebugName()->ToCString();
13212   PrintF(out, "%s", name.get());
13213 }
13214 
13215 
GetName(Handle<JSFunction> function)13216 Handle<String> JSFunction::GetName(Handle<JSFunction> function) {
13217   Isolate* isolate = function->GetIsolate();
13218   Handle<Object> name =
13219       JSReceiver::GetDataProperty(function, isolate->factory()->name_string());
13220   if (name->IsString()) return Handle<String>::cast(name);
13221   return handle(function->shared()->DebugName(), isolate);
13222 }
13223 
13224 
GetDebugName(Handle<JSFunction> function)13225 Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) {
13226   Isolate* isolate = function->GetIsolate();
13227   Handle<Object> name = JSReceiver::GetDataProperty(
13228       function, isolate->factory()->display_name_string());
13229   if (name->IsString()) return Handle<String>::cast(name);
13230   return JSFunction::GetName(function);
13231 }
13232 
SetName(Handle<JSFunction> function,Handle<Name> name,Handle<String> prefix)13233 void JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name,
13234                          Handle<String> prefix) {
13235   Isolate* isolate = function->GetIsolate();
13236   Handle<String> function_name = Name::ToFunctionName(name).ToHandleChecked();
13237   if (prefix->length() > 0) {
13238     IncrementalStringBuilder builder(isolate);
13239     builder.AppendString(prefix);
13240     builder.AppendCharacter(' ');
13241     builder.AppendString(function_name);
13242     function_name = builder.Finish().ToHandleChecked();
13243   }
13244   JSObject::DefinePropertyOrElementIgnoreAttributes(
13245       function, isolate->factory()->name_string(), function_name,
13246       static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY))
13247       .ToHandleChecked();
13248 }
13249 
13250 namespace {
13251 
13252 char const kNativeCodeSource[] = "function () { [native code] }";
13253 
13254 
NativeCodeFunctionSourceString(Handle<SharedFunctionInfo> shared_info)13255 Handle<String> NativeCodeFunctionSourceString(
13256     Handle<SharedFunctionInfo> shared_info) {
13257   Isolate* const isolate = shared_info->GetIsolate();
13258   if (shared_info->name()->IsString()) {
13259     IncrementalStringBuilder builder(isolate);
13260     builder.AppendCString("function ");
13261     builder.AppendString(handle(String::cast(shared_info->name()), isolate));
13262     builder.AppendCString("() { [native code] }");
13263     return builder.Finish().ToHandleChecked();
13264   }
13265   return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource);
13266 }
13267 
13268 }  // namespace
13269 
13270 
13271 // static
ToString(Handle<JSBoundFunction> function)13272 Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) {
13273   Isolate* const isolate = function->GetIsolate();
13274   return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource);
13275 }
13276 
13277 
13278 // static
ToString(Handle<JSFunction> function)13279 Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
13280   Isolate* const isolate = function->GetIsolate();
13281   Handle<SharedFunctionInfo> shared_info(function->shared(), isolate);
13282 
13283   // Check if {function} should hide its source code.
13284   if (!shared_info->script()->IsScript() ||
13285       Script::cast(shared_info->script())->hide_source()) {
13286     return NativeCodeFunctionSourceString(shared_info);
13287   }
13288 
13289   // Check if we should print {function} as a class.
13290   Handle<Object> class_start_position = JSReceiver::GetDataProperty(
13291       function, isolate->factory()->class_start_position_symbol());
13292   if (class_start_position->IsSmi()) {
13293     Handle<Object> class_end_position = JSReceiver::GetDataProperty(
13294         function, isolate->factory()->class_end_position_symbol());
13295     Handle<String> script_source(
13296         String::cast(Script::cast(shared_info->script())->source()), isolate);
13297     return isolate->factory()->NewSubString(
13298         script_source, Handle<Smi>::cast(class_start_position)->value(),
13299         Handle<Smi>::cast(class_end_position)->value());
13300   }
13301 
13302   // Check if we have source code for the {function}.
13303   if (!shared_info->HasSourceCode()) {
13304     return NativeCodeFunctionSourceString(shared_info);
13305   }
13306 
13307   IncrementalStringBuilder builder(isolate);
13308   FunctionKind kind = shared_info->kind();
13309   if (!IsArrowFunction(kind)) {
13310     if (IsConciseMethod(kind)) {
13311       if (IsGeneratorFunction(kind)) {
13312         builder.AppendCharacter('*');
13313       } else if (IsAsyncFunction(kind)) {
13314         builder.AppendCString("async ");
13315       }
13316     } else {
13317       if (IsGeneratorFunction(kind)) {
13318         builder.AppendCString("function* ");
13319       } else if (IsAsyncFunction(kind)) {
13320         builder.AppendCString("async function ");
13321       } else {
13322         builder.AppendCString("function ");
13323       }
13324     }
13325     if (shared_info->name_should_print_as_anonymous()) {
13326       builder.AppendCString("anonymous");
13327     } else if (!shared_info->is_anonymous_expression()) {
13328       builder.AppendString(handle(String::cast(shared_info->name()), isolate));
13329     }
13330   }
13331   builder.AppendString(Handle<String>::cast(shared_info->GetSourceCode()));
13332   return builder.Finish().ToHandleChecked();
13333 }
13334 
Initialize(Isolate * isolate,Handle<Oddball> oddball,const char * to_string,Handle<Object> to_number,const char * type_of,byte kind)13335 void Oddball::Initialize(Isolate* isolate, Handle<Oddball> oddball,
13336                          const char* to_string, Handle<Object> to_number,
13337                          const char* type_of, byte kind) {
13338   Handle<String> internalized_to_string =
13339       isolate->factory()->InternalizeUtf8String(to_string);
13340   Handle<String> internalized_type_of =
13341       isolate->factory()->InternalizeUtf8String(type_of);
13342   oddball->set_to_number_raw(to_number->Number());
13343   oddball->set_to_number(*to_number);
13344   oddball->set_to_string(*internalized_to_string);
13345   oddball->set_type_of(*internalized_type_of);
13346   oddball->set_kind(kind);
13347 }
13348 
SetEvalOrigin(Handle<Script> script,Handle<SharedFunctionInfo> outer_info,int eval_position)13349 void Script::SetEvalOrigin(Handle<Script> script,
13350                            Handle<SharedFunctionInfo> outer_info,
13351                            int eval_position) {
13352   if (eval_position == kNoSourcePosition) {
13353     // If the position is missing, attempt to get the code offset from the
13354     // current activation.  Do not translate the code offset into source
13355     // position, but store it as negative value for lazy translation.
13356     StackTraceFrameIterator it(script->GetIsolate());
13357     if (!it.done() && it.is_javascript()) {
13358       FrameSummary summary = FrameSummary::GetFirst(it.javascript_frame());
13359       script->set_eval_from_shared(summary.function()->shared());
13360       script->set_eval_from_position(-summary.code_offset());
13361       return;
13362     }
13363     eval_position = 0;
13364   }
13365   script->set_eval_from_shared(*outer_info);
13366   script->set_eval_from_position(eval_position);
13367 }
13368 
GetEvalPosition()13369 int Script::GetEvalPosition() {
13370   DisallowHeapAllocation no_gc;
13371   DCHECK(compilation_type() == Script::COMPILATION_TYPE_EVAL);
13372   int position = eval_from_position();
13373   if (position < 0) {
13374     // Due to laziness, the position may not have been translated from code
13375     // offset yet, which would be encoded as negative integer. In that case,
13376     // translate and set the position.
13377     if (eval_from_shared()->IsUndefined(GetIsolate())) {
13378       position = 0;
13379     } else {
13380       SharedFunctionInfo* shared = SharedFunctionInfo::cast(eval_from_shared());
13381       position = shared->abstract_code()->SourcePosition(-position);
13382     }
13383     DCHECK(position >= 0);
13384     set_eval_from_position(position);
13385   }
13386   return position;
13387 }
13388 
InitLineEnds(Handle<Script> script)13389 void Script::InitLineEnds(Handle<Script> script) {
13390   Isolate* isolate = script->GetIsolate();
13391   if (!script->line_ends()->IsUndefined(isolate)) return;
13392   DCHECK_NE(Script::TYPE_WASM, script->type());
13393 
13394   Object* src_obj = script->source();
13395   if (!src_obj->IsString()) {
13396     DCHECK(src_obj->IsUndefined(isolate));
13397     script->set_line_ends(isolate->heap()->empty_fixed_array());
13398   } else {
13399     DCHECK(src_obj->IsString());
13400     Handle<String> src(String::cast(src_obj), isolate);
13401     Handle<FixedArray> array = String::CalculateLineEnds(src, true);
13402     script->set_line_ends(*array);
13403   }
13404 
13405   DCHECK(script->line_ends()->IsFixedArray());
13406 }
13407 
GetPositionInfo(Handle<Script> script,int position,PositionInfo * info,OffsetFlag offset_flag)13408 bool Script::GetPositionInfo(Handle<Script> script, int position,
13409                              PositionInfo* info, OffsetFlag offset_flag) {
13410   // For wasm, we do not create an artificial line_ends array, but do the
13411   // translation directly.
13412   if (script->type() == Script::TYPE_WASM) {
13413     Handle<WasmCompiledModule> compiled_module(
13414         WasmCompiledModule::cast(script->wasm_compiled_module()));
13415     DCHECK_LE(0, position);
13416     return wasm::GetPositionInfo(compiled_module,
13417                                  static_cast<uint32_t>(position), info);
13418   }
13419 
13420   InitLineEnds(script);
13421   return script->GetPositionInfo(position, info, offset_flag);
13422 }
13423 
13424 namespace {
GetPositionInfoSlow(const Script * script,int position,Script::PositionInfo * info)13425 bool GetPositionInfoSlow(const Script* script, int position,
13426                          Script::PositionInfo* info) {
13427   if (!script->source()->IsString()) return false;
13428   if (position < 0) position = 0;
13429 
13430   String* source_string = String::cast(script->source());
13431   int line = 0;
13432   int line_start = 0;
13433   int len = source_string->length();
13434   for (int pos = 0; pos <= len; ++pos) {
13435     if (pos == len || source_string->Get(pos) == '\n') {
13436       if (position <= pos) {
13437         info->line = line;
13438         info->column = position - line_start;
13439         info->line_start = line_start;
13440         info->line_end = pos;
13441         return true;
13442       }
13443       line++;
13444       line_start = pos + 1;
13445     }
13446   }
13447   return false;
13448 }
13449 }  // namespace
13450 
13451 #define SMI_VALUE(x) (Smi::cast(x)->value())
GetPositionInfo(int position,PositionInfo * info,OffsetFlag offset_flag) const13452 bool Script::GetPositionInfo(int position, PositionInfo* info,
13453                              OffsetFlag offset_flag) const {
13454   DisallowHeapAllocation no_allocation;
13455 
13456   if (line_ends()->IsUndefined(GetIsolate())) {
13457     // Slow mode: we do not have line_ends. We have to iterate through source.
13458     if (!GetPositionInfoSlow(this, position, info)) return false;
13459   } else {
13460     DCHECK(line_ends()->IsFixedArray());
13461     FixedArray* ends = FixedArray::cast(line_ends());
13462 
13463     const int ends_len = ends->length();
13464     if (ends_len == 0) return false;
13465 
13466     // Return early on invalid positions. Negative positions behave as if 0 was
13467     // passed, and positions beyond the end of the script return as failure.
13468     if (position < 0) {
13469       position = 0;
13470     } else if (position > SMI_VALUE(ends->get(ends_len - 1))) {
13471       return false;
13472     }
13473 
13474     // Determine line number by doing a binary search on the line ends array.
13475     if (SMI_VALUE(ends->get(0)) >= position) {
13476       info->line = 0;
13477       info->line_start = 0;
13478       info->column = position;
13479     } else {
13480       int left = 0;
13481       int right = ends_len - 1;
13482 
13483       while (right > 0) {
13484         DCHECK_LE(left, right);
13485         const int mid = (left + right) / 2;
13486         if (position > SMI_VALUE(ends->get(mid))) {
13487           left = mid + 1;
13488         } else if (position <= SMI_VALUE(ends->get(mid - 1))) {
13489           right = mid - 1;
13490         } else {
13491           info->line = mid;
13492           break;
13493         }
13494       }
13495       DCHECK(SMI_VALUE(ends->get(info->line)) >= position &&
13496              SMI_VALUE(ends->get(info->line - 1)) < position);
13497       info->line_start = SMI_VALUE(ends->get(info->line - 1)) + 1;
13498       info->column = position - info->line_start;
13499     }
13500 
13501     // Line end is position of the linebreak character.
13502     info->line_end = SMI_VALUE(ends->get(info->line));
13503     if (info->line_end > 0) {
13504       DCHECK(source()->IsString());
13505       String* src = String::cast(source());
13506       if (src->length() >= info->line_end &&
13507           src->Get(info->line_end - 1) == '\r') {
13508         info->line_end--;
13509       }
13510     }
13511   }
13512 
13513   // Add offsets if requested.
13514   if (offset_flag == WITH_OFFSET) {
13515     if (info->line == 0) {
13516       info->column += column_offset();
13517     }
13518     info->line += line_offset();
13519   }
13520 
13521   return true;
13522 }
13523 #undef SMI_VALUE
13524 
GetColumnNumber(Handle<Script> script,int code_pos)13525 int Script::GetColumnNumber(Handle<Script> script, int code_pos) {
13526   PositionInfo info;
13527   GetPositionInfo(script, code_pos, &info, WITH_OFFSET);
13528   return info.column;
13529 }
13530 
GetColumnNumber(int code_pos) const13531 int Script::GetColumnNumber(int code_pos) const {
13532   PositionInfo info;
13533   GetPositionInfo(code_pos, &info, WITH_OFFSET);
13534   return info.column;
13535 }
13536 
GetLineNumber(Handle<Script> script,int code_pos)13537 int Script::GetLineNumber(Handle<Script> script, int code_pos) {
13538   PositionInfo info;
13539   GetPositionInfo(script, code_pos, &info, WITH_OFFSET);
13540   return info.line;
13541 }
13542 
GetLineNumber(int code_pos) const13543 int Script::GetLineNumber(int code_pos) const {
13544   PositionInfo info;
13545   GetPositionInfo(code_pos, &info, WITH_OFFSET);
13546   return info.line;
13547 }
13548 
GetNameOrSourceURL(Handle<Script> script)13549 Handle<Object> Script::GetNameOrSourceURL(Handle<Script> script) {
13550   Isolate* isolate = script->GetIsolate();
13551 
13552   // Keep in sync with ScriptNameOrSourceURL in messages.js.
13553 
13554   if (!script->source_url()->IsUndefined(isolate)) {
13555     return handle(script->source_url(), isolate);
13556   }
13557   return handle(script->name(), isolate);
13558 }
13559 
13560 
GetWrapper(Handle<Script> script)13561 Handle<JSObject> Script::GetWrapper(Handle<Script> script) {
13562   Isolate* isolate = script->GetIsolate();
13563   if (!script->wrapper()->IsUndefined(isolate)) {
13564     DCHECK(script->wrapper()->IsWeakCell());
13565     Handle<WeakCell> cell(WeakCell::cast(script->wrapper()));
13566     if (!cell->cleared()) {
13567       // Return a handle for the existing script wrapper from the cache.
13568       return handle(JSObject::cast(cell->value()));
13569     }
13570     // If we found an empty WeakCell, that means the script wrapper was
13571     // GCed.  We are not notified directly of that, so we decrement here
13572     // so that we at least don't count double for any given script.
13573     isolate->counters()->script_wrappers()->Decrement();
13574   }
13575   // Construct a new script wrapper.
13576   isolate->counters()->script_wrappers()->Increment();
13577   Handle<JSFunction> constructor = isolate->script_function();
13578   Handle<JSValue> result =
13579       Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
13580   result->set_value(*script);
13581   Handle<WeakCell> cell = isolate->factory()->NewWeakCell(result);
13582   script->set_wrapper(*cell);
13583   return result;
13584 }
13585 
13586 
FindSharedFunctionInfo(FunctionLiteral * fun)13587 MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
13588     FunctionLiteral* fun) {
13589   WeakFixedArray::Iterator iterator(shared_function_infos());
13590   SharedFunctionInfo* shared;
13591   while ((shared = iterator.Next<SharedFunctionInfo>())) {
13592     if (fun->function_token_position() == shared->function_token_position() &&
13593         fun->start_position() == shared->start_position() &&
13594         fun->end_position() == shared->end_position()) {
13595       return Handle<SharedFunctionInfo>(shared);
13596     }
13597   }
13598   return MaybeHandle<SharedFunctionInfo>();
13599 }
13600 
13601 
Iterator(Isolate * isolate)13602 Script::Iterator::Iterator(Isolate* isolate)
13603     : iterator_(isolate->heap()->script_list()) {}
13604 
13605 
Next()13606 Script* Script::Iterator::Next() { return iterator_.Next<Script>(); }
13607 
13608 
Iterator(Isolate * isolate)13609 SharedFunctionInfo::Iterator::Iterator(Isolate* isolate)
13610     : script_iterator_(isolate),
13611       sfi_iterator_(isolate->heap()->noscript_shared_function_infos()) {}
13612 
13613 
NextScript()13614 bool SharedFunctionInfo::Iterator::NextScript() {
13615   Script* script = script_iterator_.Next();
13616   if (script == NULL) return false;
13617   sfi_iterator_.Reset(script->shared_function_infos());
13618   return true;
13619 }
13620 
13621 
Next()13622 SharedFunctionInfo* SharedFunctionInfo::Iterator::Next() {
13623   do {
13624     SharedFunctionInfo* next = sfi_iterator_.Next<SharedFunctionInfo>();
13625     if (next != NULL) return next;
13626   } while (NextScript());
13627   return NULL;
13628 }
13629 
13630 
SetScript(Handle<SharedFunctionInfo> shared,Handle<Object> script_object)13631 void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
13632                                    Handle<Object> script_object) {
13633   if (shared->script() == *script_object) return;
13634   Isolate* isolate = shared->GetIsolate();
13635 
13636   // Add shared function info to new script's list. If a collection occurs,
13637   // the shared function info may be temporarily in two lists.
13638   // This is okay because the gc-time processing of these lists can tolerate
13639   // duplicates.
13640   Handle<Object> list;
13641   if (script_object->IsScript()) {
13642     Handle<Script> script = Handle<Script>::cast(script_object);
13643     list = handle(script->shared_function_infos(), isolate);
13644   } else {
13645     list = isolate->factory()->noscript_shared_function_infos();
13646   }
13647 
13648 #ifdef DEBUG
13649   if (FLAG_enable_slow_asserts) {
13650     WeakFixedArray::Iterator iterator(*list);
13651     SharedFunctionInfo* next;
13652     while ((next = iterator.Next<SharedFunctionInfo>())) {
13653       DCHECK_NE(next, *shared);
13654     }
13655   }
13656 #endif  // DEBUG
13657   list = WeakFixedArray::Add(list, shared);
13658 
13659   if (script_object->IsScript()) {
13660     Handle<Script> script = Handle<Script>::cast(script_object);
13661     script->set_shared_function_infos(*list);
13662   } else {
13663     isolate->heap()->SetRootNoScriptSharedFunctionInfos(*list);
13664   }
13665 
13666   // Remove shared function info from old script's list.
13667   if (shared->script()->IsScript()) {
13668     Script* old_script = Script::cast(shared->script());
13669     if (old_script->shared_function_infos()->IsWeakFixedArray()) {
13670       WeakFixedArray* list =
13671           WeakFixedArray::cast(old_script->shared_function_infos());
13672       list->Remove(shared);
13673     }
13674   } else {
13675     // Remove shared function info from root array.
13676     Object* list = isolate->heap()->noscript_shared_function_infos();
13677     CHECK(WeakFixedArray::cast(list)->Remove(shared));
13678   }
13679 
13680   // Finally set new script.
13681   shared->set_script(*script_object);
13682 }
13683 
13684 
DebugName()13685 String* SharedFunctionInfo::DebugName() {
13686   Object* n = name();
13687   if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
13688   return String::cast(n);
13689 }
13690 
13691 // The filter is a pattern that matches function names in this way:
13692 //   "*"      all; the default
13693 //   "-"      all but the top-level function
13694 //   "-name"  all but the function "name"
13695 //   ""       only the top-level function
13696 //   "name"   only the function "name"
13697 //   "name*"  only functions starting with "name"
13698 //   "~"      none; the tilde is not an identifier
PassesFilter(const char * raw_filter)13699 bool SharedFunctionInfo::PassesFilter(const char* raw_filter) {
13700   if (*raw_filter == '*') return true;
13701   String* name = DebugName();
13702   Vector<const char> filter = CStrVector(raw_filter);
13703   if (filter.length() == 0) return name->length() == 0;
13704   if (filter[0] == '-') {
13705     // Negative filter.
13706     if (filter.length() == 1) {
13707       return (name->length() != 0);
13708     } else if (name->IsUtf8EqualTo(filter.SubVector(1, filter.length()))) {
13709       return false;
13710     }
13711     if (filter[filter.length() - 1] == '*' &&
13712         name->IsUtf8EqualTo(filter.SubVector(1, filter.length() - 1), true)) {
13713       return false;
13714     }
13715     return true;
13716 
13717   } else if (name->IsUtf8EqualTo(filter)) {
13718     return true;
13719   }
13720   if (filter[filter.length() - 1] == '*' &&
13721       name->IsUtf8EqualTo(filter.SubVector(0, filter.length() - 1), true)) {
13722     return true;
13723   }
13724   return false;
13725 }
13726 
HasSourceCode() const13727 bool SharedFunctionInfo::HasSourceCode() const {
13728   Isolate* isolate = GetIsolate();
13729   return !script()->IsUndefined(isolate) &&
13730          !reinterpret_cast<Script*>(script())->source()->IsUndefined(isolate);
13731 }
13732 
13733 
GetSourceCode()13734 Handle<Object> SharedFunctionInfo::GetSourceCode() {
13735   if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value();
13736   Handle<String> source(String::cast(Script::cast(script())->source()));
13737   return GetIsolate()->factory()->NewSubString(
13738       source, start_position(), end_position());
13739 }
13740 
13741 
IsInlineable()13742 bool SharedFunctionInfo::IsInlineable() {
13743   // Check that the function has a script associated with it.
13744   if (!script()->IsScript()) return false;
13745   return !optimization_disabled();
13746 }
13747 
13748 
SourceSize()13749 int SharedFunctionInfo::SourceSize() {
13750   return end_position() - start_position();
13751 }
13752 
CalculateInstanceSizeHelper(InstanceType instance_type,int requested_internal_fields,int requested_in_object_properties,int * instance_size,int * in_object_properties)13753 void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type,
13754                                              int requested_internal_fields,
13755                                              int requested_in_object_properties,
13756                                              int* instance_size,
13757                                              int* in_object_properties) {
13758   int header_size = JSObject::GetHeaderSize(instance_type);
13759   DCHECK_LE(requested_internal_fields,
13760             (JSObject::kMaxInstanceSize - header_size) >> kPointerSizeLog2);
13761   *instance_size =
13762       Min(header_size +
13763               ((requested_internal_fields + requested_in_object_properties)
13764                << kPointerSizeLog2),
13765           JSObject::kMaxInstanceSize);
13766   *in_object_properties = ((*instance_size - header_size) >> kPointerSizeLog2) -
13767                           requested_internal_fields;
13768 }
13769 
13770 
CalculateInstanceSize(InstanceType instance_type,int requested_internal_fields,int * instance_size,int * in_object_properties)13771 void JSFunction::CalculateInstanceSize(InstanceType instance_type,
13772                                        int requested_internal_fields,
13773                                        int* instance_size,
13774                                        int* in_object_properties) {
13775   CalculateInstanceSizeHelper(instance_type, requested_internal_fields,
13776                               shared()->expected_nof_properties(),
13777                               instance_size, in_object_properties);
13778 }
13779 
13780 
CalculateInstanceSizeForDerivedClass(InstanceType instance_type,int requested_internal_fields,int * instance_size,int * in_object_properties)13781 void JSFunction::CalculateInstanceSizeForDerivedClass(
13782     InstanceType instance_type, int requested_internal_fields,
13783     int* instance_size, int* in_object_properties) {
13784   Isolate* isolate = GetIsolate();
13785   int expected_nof_properties = 0;
13786   for (PrototypeIterator iter(isolate, this, kStartAtReceiver); !iter.IsAtEnd();
13787        iter.Advance()) {
13788     JSReceiver* current = iter.GetCurrent<JSReceiver>();
13789     if (!current->IsJSFunction()) break;
13790     JSFunction* func = JSFunction::cast(current);
13791     SharedFunctionInfo* shared = func->shared();
13792     expected_nof_properties += shared->expected_nof_properties();
13793     if (!IsSubclassConstructor(shared->kind())) {
13794       break;
13795     }
13796   }
13797   CalculateInstanceSizeHelper(instance_type, requested_internal_fields,
13798                               expected_nof_properties, instance_size,
13799                               in_object_properties);
13800 }
13801 
13802 
13803 // Output the source code without any allocation in the heap.
operator <<(std::ostream & os,const SourceCodeOf & v)13804 std::ostream& operator<<(std::ostream& os, const SourceCodeOf& v) {
13805   const SharedFunctionInfo* s = v.value;
13806   // For some native functions there is no source.
13807   if (!s->HasSourceCode()) return os << "<No Source>";
13808 
13809   // Get the source for the script which this function came from.
13810   // Don't use String::cast because we don't want more assertion errors while
13811   // we are already creating a stack dump.
13812   String* script_source =
13813       reinterpret_cast<String*>(Script::cast(s->script())->source());
13814 
13815   if (!script_source->LooksValid()) return os << "<Invalid Source>";
13816 
13817   if (!s->is_toplevel()) {
13818     os << "function ";
13819     Object* name = s->name();
13820     if (name->IsString() && String::cast(name)->length() > 0) {
13821       String::cast(name)->PrintUC16(os);
13822     }
13823   }
13824 
13825   int len = s->end_position() - s->start_position();
13826   if (len <= v.max_length || v.max_length < 0) {
13827     script_source->PrintUC16(os, s->start_position(), s->end_position());
13828     return os;
13829   } else {
13830     script_source->PrintUC16(os, s->start_position(),
13831                              s->start_position() + v.max_length);
13832     return os << "...\n";
13833   }
13834 }
13835 
13836 
IsCodeEquivalent(Code * code,Code * recompiled)13837 static bool IsCodeEquivalent(Code* code, Code* recompiled) {
13838   if (code->instruction_size() != recompiled->instruction_size()) return false;
13839   ByteArray* code_relocation = code->relocation_info();
13840   ByteArray* recompiled_relocation = recompiled->relocation_info();
13841   int length = code_relocation->length();
13842   if (length != recompiled_relocation->length()) return false;
13843   int compare = memcmp(code_relocation->GetDataStartAddress(),
13844                        recompiled_relocation->GetDataStartAddress(),
13845                        length);
13846   return compare == 0;
13847 }
13848 
13849 
EnableDeoptimizationSupport(Code * recompiled)13850 void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
13851   DCHECK(!has_deoptimization_support());
13852   DisallowHeapAllocation no_allocation;
13853   Code* code = this->code();
13854   if (IsCodeEquivalent(code, recompiled)) {
13855     // Copy the deoptimization data from the recompiled code.
13856     code->set_deoptimization_data(recompiled->deoptimization_data());
13857     code->set_has_deoptimization_support(true);
13858   } else {
13859     // TODO(3025757): In case the recompiled isn't equivalent to the
13860     // old code, we have to replace it. We should try to avoid this
13861     // altogether because it flushes valuable type feedback by
13862     // effectively resetting all IC state.
13863     ReplaceCode(recompiled);
13864   }
13865   DCHECK(has_deoptimization_support());
13866 }
13867 
13868 
DisableOptimization(BailoutReason reason)13869 void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
13870   // Disable optimization for the shared function info and mark the
13871   // code as non-optimizable. The marker on the shared function info
13872   // is there because we flush non-optimized code thereby loosing the
13873   // non-optimizable information for the code. When the code is
13874   // regenerated and set on the shared function info it is marked as
13875   // non-optimizable if optimization is disabled for the shared
13876   // function info.
13877   DCHECK(reason != kNoReason);
13878   set_optimization_disabled(true);
13879   set_disable_optimization_reason(reason);
13880   // Code should be the lazy compilation stub or else unoptimized.
13881   DCHECK(abstract_code()->kind() == AbstractCode::FUNCTION ||
13882          abstract_code()->kind() == AbstractCode::INTERPRETED_FUNCTION ||
13883          abstract_code()->kind() == AbstractCode::BUILTIN);
13884   PROFILE(GetIsolate(), CodeDisableOptEvent(abstract_code(), this));
13885   if (FLAG_trace_opt) {
13886     PrintF("[disabled optimization for ");
13887     ShortPrint();
13888     PrintF(", reason: %s]\n", GetBailoutReason(reason));
13889   }
13890 }
13891 
13892 namespace {
13893 
13894 // Sets the expected number of properties based on estimate from parser.
SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared,FunctionLiteral * literal)13895 void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared,
13896                                           FunctionLiteral* literal) {
13897   int estimate = literal->expected_property_count();
13898 
13899   // If no properties are added in the constructor, they are more likely
13900   // to be added later.
13901   if (estimate == 0) estimate = 2;
13902 
13903   // TODO(yangguo): check whether those heuristics are still up-to-date.
13904   // We do not shrink objects that go into a snapshot (yet), so we adjust
13905   // the estimate conservatively.
13906   if (shared->GetIsolate()->serializer_enabled()) {
13907     estimate += 2;
13908   } else {
13909     // Inobject slack tracking will reclaim redundant inobject space later,
13910     // so we can afford to adjust the estimate generously.
13911     estimate += 8;
13912   }
13913 
13914   shared->set_expected_nof_properties(estimate);
13915 }
13916 
13917 }  // namespace
13918 
InitFromFunctionLiteral(Handle<SharedFunctionInfo> shared_info,FunctionLiteral * lit)13919 void SharedFunctionInfo::InitFromFunctionLiteral(
13920     Handle<SharedFunctionInfo> shared_info, FunctionLiteral* lit) {
13921   // When adding fields here, make sure DeclarationScope::AnalyzePartially is
13922   // updated accordingly.
13923   shared_info->set_length(lit->function_length());
13924   shared_info->set_internal_formal_parameter_count(lit->parameter_count());
13925   shared_info->set_function_token_position(lit->function_token_position());
13926   shared_info->set_start_position(lit->start_position());
13927   shared_info->set_end_position(lit->end_position());
13928   shared_info->set_is_declaration(lit->is_declaration());
13929   shared_info->set_is_named_expression(lit->is_named_expression());
13930   shared_info->set_is_anonymous_expression(lit->is_anonymous_expression());
13931   shared_info->set_inferred_name(*lit->inferred_name());
13932   shared_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
13933   shared_info->set_language_mode(lit->language_mode());
13934   shared_info->set_uses_arguments(lit->scope()->arguments() != NULL);
13935   shared_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
13936   shared_info->set_is_function(lit->is_function());
13937   shared_info->set_never_compiled(true);
13938   shared_info->set_kind(lit->kind());
13939   if (!IsConstructable(lit->kind(), lit->language_mode())) {
13940     shared_info->SetConstructStub(
13941         *shared_info->GetIsolate()->builtins()->ConstructedNonConstructable());
13942   }
13943   shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
13944   shared_info->set_asm_function(lit->scope()->asm_function());
13945   shared_info->set_requires_class_field_init(lit->requires_class_field_init());
13946   shared_info->set_is_class_field_initializer(
13947       lit->is_class_field_initializer());
13948   SetExpectedNofPropertiesFromEstimate(shared_info, lit);
13949 }
13950 
13951 
VerifyBailoutId(BailoutId id)13952 bool SharedFunctionInfo::VerifyBailoutId(BailoutId id) {
13953   DCHECK(!id.IsNone());
13954   Code* unoptimized = code();
13955   DeoptimizationOutputData* data =
13956       DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
13957   unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
13958   USE(ignore);
13959   return true;  // Return true if there was no DCHECK.
13960 }
13961 
SetConstructStub(Code * code)13962 void SharedFunctionInfo::SetConstructStub(Code* code) {
13963   if (code->kind() == Code::BUILTIN) code->set_is_construct_stub(true);
13964   set_construct_stub(code);
13965 }
13966 
StartInobjectSlackTracking()13967 void Map::StartInobjectSlackTracking() {
13968   DCHECK(!IsInobjectSlackTrackingInProgress());
13969 
13970   // No tracking during the snapshot construction phase.
13971   Isolate* isolate = GetIsolate();
13972   if (isolate->serializer_enabled()) return;
13973 
13974   if (unused_property_fields() == 0) return;
13975 
13976   set_construction_counter(Map::kSlackTrackingCounterStart);
13977 }
13978 
13979 
ResetForNewContext(int new_ic_age)13980 void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
13981   code()->ClearInlineCaches();
13982   set_ic_age(new_ic_age);
13983   if (code()->kind() == Code::FUNCTION) {
13984     code()->set_profiler_ticks(0);
13985     if (optimization_disabled() && opt_count() >= FLAG_max_opt_count) {
13986       // Re-enable optimizations if they were disabled due to opt_count limit.
13987       set_optimization_disabled(false);
13988     }
13989     set_opt_count(0);
13990     set_deopt_count(0);
13991   } else if (IsInterpreted()) {
13992     set_profiler_ticks(0);
13993     if (optimization_disabled() && opt_count() >= FLAG_max_opt_count) {
13994       // Re-enable optimizations if they were disabled due to opt_count limit.
13995       set_optimization_disabled(false);
13996     }
13997     set_opt_count(0);
13998     set_deopt_count(0);
13999   }
14000 }
14001 
14002 
SearchOptimizedCodeMapEntry(Context * native_context,BailoutId osr_ast_id)14003 int SharedFunctionInfo::SearchOptimizedCodeMapEntry(Context* native_context,
14004                                                     BailoutId osr_ast_id) {
14005   DisallowHeapAllocation no_gc;
14006   DCHECK(native_context->IsNativeContext());
14007   if (!OptimizedCodeMapIsCleared()) {
14008     FixedArray* optimized_code_map = this->optimized_code_map();
14009     int length = optimized_code_map->length();
14010     Smi* osr_ast_id_smi = Smi::FromInt(osr_ast_id.ToInt());
14011     for (int i = kEntriesStart; i < length; i += kEntryLength) {
14012       if (WeakCell::cast(optimized_code_map->get(i + kContextOffset))
14013                   ->value() == native_context &&
14014           optimized_code_map->get(i + kOsrAstIdOffset) == osr_ast_id_smi) {
14015         return i;
14016       }
14017     }
14018   }
14019   return -1;
14020 }
14021 
ClearCodeFromOptimizedCodeMap()14022 void SharedFunctionInfo::ClearCodeFromOptimizedCodeMap() {
14023   if (!OptimizedCodeMapIsCleared()) {
14024     FixedArray* optimized_code_map = this->optimized_code_map();
14025     int length = optimized_code_map->length();
14026     WeakCell* empty_weak_cell = GetHeap()->empty_weak_cell();
14027     for (int i = kEntriesStart; i < length; i += kEntryLength) {
14028       optimized_code_map->set(i + kCachedCodeOffset, empty_weak_cell,
14029                               SKIP_WRITE_BARRIER);
14030     }
14031   }
14032 }
14033 
SearchOptimizedCodeMap(Context * native_context,BailoutId osr_ast_id)14034 CodeAndLiterals SharedFunctionInfo::SearchOptimizedCodeMap(
14035     Context* native_context, BailoutId osr_ast_id) {
14036   CodeAndLiterals result = {nullptr, nullptr};
14037   int entry = SearchOptimizedCodeMapEntry(native_context, osr_ast_id);
14038   if (entry != kNotFound) {
14039     FixedArray* code_map = optimized_code_map();
14040     DCHECK_LE(entry + kEntryLength, code_map->length());
14041     WeakCell* cell = WeakCell::cast(code_map->get(entry + kCachedCodeOffset));
14042     WeakCell* literals_cell =
14043         WeakCell::cast(code_map->get(entry + kLiteralsOffset));
14044 
14045     result = {cell->cleared() ? nullptr : Code::cast(cell->value()),
14046               literals_cell->cleared() ? nullptr : LiteralsArray::cast(
14047                                                        literals_cell->value())};
14048   }
14049   return result;
14050 }
14051 
14052 
14053 #define DECLARE_TAG(ignore1, name, ignore2) name,
14054 const char* const VisitorSynchronization::kTags[
14055     VisitorSynchronization::kNumberOfSyncTags] = {
14056   VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
14057 };
14058 #undef DECLARE_TAG
14059 
14060 
14061 #define DECLARE_TAG(ignore1, ignore2, name) name,
14062 const char* const VisitorSynchronization::kTagNames[
14063     VisitorSynchronization::kNumberOfSyncTags] = {
14064   VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
14065 };
14066 #undef DECLARE_TAG
14067 
14068 
VisitCodeTarget(RelocInfo * rinfo)14069 void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
14070   DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode()));
14071   Object* old_pointer = Code::GetCodeFromTargetAddress(rinfo->target_address());
14072   Object* new_pointer = old_pointer;
14073   VisitPointer(&new_pointer);
14074   DCHECK_EQ(old_pointer, new_pointer);
14075 }
14076 
14077 
VisitCodeAgeSequence(RelocInfo * rinfo)14078 void ObjectVisitor::VisitCodeAgeSequence(RelocInfo* rinfo) {
14079   DCHECK(RelocInfo::IsCodeAgeSequence(rinfo->rmode()));
14080   Object* old_pointer = rinfo->code_age_stub();
14081   Object* new_pointer = old_pointer;
14082   if (old_pointer != nullptr) {
14083     VisitPointer(&new_pointer);
14084     DCHECK_EQ(old_pointer, new_pointer);
14085   }
14086 }
14087 
14088 
VisitCodeEntry(Address entry_address)14089 void ObjectVisitor::VisitCodeEntry(Address entry_address) {
14090   Object* old_pointer = Code::GetObjectFromEntryAddress(entry_address);
14091   Object* new_pointer = old_pointer;
14092   VisitPointer(&new_pointer);
14093   DCHECK_EQ(old_pointer, new_pointer);
14094 }
14095 
14096 
VisitCell(RelocInfo * rinfo)14097 void ObjectVisitor::VisitCell(RelocInfo* rinfo) {
14098   DCHECK(rinfo->rmode() == RelocInfo::CELL);
14099   Object* old_pointer = rinfo->target_cell();
14100   Object* new_pointer = old_pointer;
14101   VisitPointer(&new_pointer);
14102   DCHECK_EQ(old_pointer, new_pointer);
14103 }
14104 
14105 
VisitDebugTarget(RelocInfo * rinfo)14106 void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
14107   DCHECK(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
14108          rinfo->IsPatchedDebugBreakSlotSequence());
14109   Object* old_pointer =
14110       Code::GetCodeFromTargetAddress(rinfo->debug_call_address());
14111   Object* new_pointer = old_pointer;
14112   VisitPointer(&new_pointer);
14113   DCHECK_EQ(old_pointer, new_pointer);
14114 }
14115 
14116 
VisitEmbeddedPointer(RelocInfo * rinfo)14117 void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
14118   DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
14119   Object* old_pointer = rinfo->target_object();
14120   Object* new_pointer = old_pointer;
14121   VisitPointer(&new_pointer);
14122   DCHECK_EQ(old_pointer, new_pointer);
14123 }
14124 
14125 
VisitExternalReference(RelocInfo * rinfo)14126 void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
14127   Address old_reference = rinfo->target_external_reference();
14128   Address new_reference = old_reference;
14129   VisitExternalReference(&new_reference);
14130   DCHECK_EQ(old_reference, new_reference);
14131 }
14132 
14133 
InvalidateRelocation()14134 void Code::InvalidateRelocation() {
14135   InvalidateEmbeddedObjects();
14136   set_relocation_info(GetHeap()->empty_byte_array());
14137 }
14138 
14139 
InvalidateEmbeddedObjects()14140 void Code::InvalidateEmbeddedObjects() {
14141   Object* undefined = GetHeap()->undefined_value();
14142   Cell* undefined_cell = GetHeap()->undefined_cell();
14143   int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
14144                   RelocInfo::ModeMask(RelocInfo::CELL);
14145   for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
14146     RelocInfo::Mode mode = it.rinfo()->rmode();
14147     if (mode == RelocInfo::EMBEDDED_OBJECT) {
14148       it.rinfo()->set_target_object(undefined, SKIP_WRITE_BARRIER);
14149     } else if (mode == RelocInfo::CELL) {
14150       it.rinfo()->set_target_cell(undefined_cell, SKIP_WRITE_BARRIER);
14151     }
14152   }
14153 }
14154 
14155 
Relocate(intptr_t delta)14156 void Code::Relocate(intptr_t delta) {
14157   for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
14158     it.rinfo()->apply(delta);
14159   }
14160   Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size());
14161 }
14162 
14163 
CopyFrom(const CodeDesc & desc)14164 void Code::CopyFrom(const CodeDesc& desc) {
14165   // copy code
14166   CopyBytes(instruction_start(), desc.buffer,
14167             static_cast<size_t>(desc.instr_size));
14168 
14169   // copy unwinding info, if any
14170   if (desc.unwinding_info) {
14171     DCHECK_GT(desc.unwinding_info_size, 0);
14172     set_unwinding_info_size(desc.unwinding_info_size);
14173     CopyBytes(unwinding_info_start(), desc.unwinding_info,
14174               static_cast<size_t>(desc.unwinding_info_size));
14175   }
14176 
14177   // copy reloc info
14178   CopyBytes(relocation_start(),
14179             desc.buffer + desc.buffer_size - desc.reloc_size,
14180             static_cast<size_t>(desc.reloc_size));
14181 
14182   // unbox handles and relocate
14183   intptr_t delta = instruction_start() - desc.buffer;
14184   int mode_mask = RelocInfo::kCodeTargetMask |
14185                   RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
14186                   RelocInfo::ModeMask(RelocInfo::CELL) |
14187                   RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
14188                   RelocInfo::kApplyMask;
14189   // Needed to find target_object and runtime_entry on X64
14190   Assembler* origin = desc.origin;
14191   AllowDeferredHandleDereference embedding_raw_address;
14192   for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
14193     RelocInfo::Mode mode = it.rinfo()->rmode();
14194     if (mode == RelocInfo::EMBEDDED_OBJECT) {
14195       Handle<Object> p = it.rinfo()->target_object_handle(origin);
14196       it.rinfo()->set_target_object(*p, UPDATE_WRITE_BARRIER,
14197                                     SKIP_ICACHE_FLUSH);
14198     } else if (mode == RelocInfo::CELL) {
14199       Handle<Cell> cell  = it.rinfo()->target_cell_handle();
14200       it.rinfo()->set_target_cell(*cell, UPDATE_WRITE_BARRIER,
14201                                   SKIP_ICACHE_FLUSH);
14202     } else if (RelocInfo::IsCodeTarget(mode)) {
14203       // rewrite code handles in inline cache targets to direct
14204       // pointers to the first instruction in the code object
14205       Handle<Object> p = it.rinfo()->target_object_handle(origin);
14206       Code* code = Code::cast(*p);
14207       it.rinfo()->set_target_address(code->instruction_start(),
14208                                      UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
14209     } else if (RelocInfo::IsRuntimeEntry(mode)) {
14210       Address p = it.rinfo()->target_runtime_entry(origin);
14211       it.rinfo()->set_target_runtime_entry(p, UPDATE_WRITE_BARRIER,
14212                                            SKIP_ICACHE_FLUSH);
14213     } else if (mode == RelocInfo::CODE_AGE_SEQUENCE) {
14214       Handle<Object> p = it.rinfo()->code_age_stub_handle(origin);
14215       Code* code = Code::cast(*p);
14216       it.rinfo()->set_code_age_stub(code, SKIP_ICACHE_FLUSH);
14217     } else {
14218       it.rinfo()->apply(delta);
14219     }
14220   }
14221   Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size());
14222 }
14223 
14224 
GetSafepointEntry(Address pc)14225 SafepointEntry Code::GetSafepointEntry(Address pc) {
14226   SafepointTable table(this);
14227   return table.FindEntry(pc);
14228 }
14229 
14230 
FindNthObject(int n,Map * match_map)14231 Object* Code::FindNthObject(int n, Map* match_map) {
14232   DCHECK(is_inline_cache_stub());
14233   DisallowHeapAllocation no_allocation;
14234   int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
14235   for (RelocIterator it(this, mask); !it.done(); it.next()) {
14236     RelocInfo* info = it.rinfo();
14237     Object* object = info->target_object();
14238     if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
14239     if (object->IsHeapObject()) {
14240       if (HeapObject::cast(object)->map() == match_map) {
14241         if (--n == 0) return object;
14242       }
14243     }
14244   }
14245   return NULL;
14246 }
14247 
14248 
FindFirstAllocationSite()14249 AllocationSite* Code::FindFirstAllocationSite() {
14250   Object* result = FindNthObject(1, GetHeap()->allocation_site_map());
14251   return (result != NULL) ? AllocationSite::cast(result) : NULL;
14252 }
14253 
14254 
FindFirstMap()14255 Map* Code::FindFirstMap() {
14256   Object* result = FindNthObject(1, GetHeap()->meta_map());
14257   return (result != NULL) ? Map::cast(result) : NULL;
14258 }
14259 
14260 
FindAndReplace(const FindAndReplacePattern & pattern)14261 void Code::FindAndReplace(const FindAndReplacePattern& pattern) {
14262   DCHECK(is_inline_cache_stub() || is_handler());
14263   DisallowHeapAllocation no_allocation;
14264   int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
14265   STATIC_ASSERT(FindAndReplacePattern::kMaxCount < 32);
14266   int current_pattern = 0;
14267   for (RelocIterator it(this, mask); !it.done(); it.next()) {
14268     RelocInfo* info = it.rinfo();
14269     Object* object = info->target_object();
14270     if (object->IsHeapObject()) {
14271       if (object->IsWeakCell()) {
14272         object = HeapObject::cast(WeakCell::cast(object)->value());
14273       }
14274       Map* map = HeapObject::cast(object)->map();
14275       if (map == *pattern.find_[current_pattern]) {
14276         info->set_target_object(*pattern.replace_[current_pattern]);
14277         if (++current_pattern == pattern.count_) return;
14278       }
14279     }
14280   }
14281   UNREACHABLE();
14282 }
14283 
14284 
ClearInlineCaches()14285 void Code::ClearInlineCaches() {
14286   int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
14287              RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
14288   for (RelocIterator it(this, mask); !it.done(); it.next()) {
14289     RelocInfo* info = it.rinfo();
14290     Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
14291     if (target->is_inline_cache_stub()) {
14292       IC::Clear(this->GetIsolate(), info->pc(), info->host()->constant_pool());
14293     }
14294   }
14295 }
14296 
SourcePosition(int offset)14297 int AbstractCode::SourcePosition(int offset) {
14298   int position = 0;
14299   // Subtract one because the current PC is one instruction after the call site.
14300   if (IsCode()) offset--;
14301   for (SourcePositionTableIterator iterator(source_position_table());
14302        !iterator.done() && iterator.code_offset() <= offset;
14303        iterator.Advance()) {
14304     position = iterator.source_position().ScriptOffset();
14305   }
14306   return position;
14307 }
14308 
SourceStatementPosition(int offset)14309 int AbstractCode::SourceStatementPosition(int offset) {
14310   // First find the closest position.
14311   int position = SourcePosition(offset);
14312   // Now find the closest statement position before the position.
14313   int statement_position = 0;
14314   for (SourcePositionTableIterator it(source_position_table()); !it.done();
14315        it.Advance()) {
14316     if (it.is_statement()) {
14317       int p = it.source_position().ScriptOffset();
14318       if (statement_position < p && p <= position) {
14319         statement_position = p;
14320       }
14321     }
14322   }
14323   return statement_position;
14324 }
14325 
ClearTypeFeedbackInfo()14326 void JSFunction::ClearTypeFeedbackInfo() {
14327   feedback_vector()->ClearSlots(shared());
14328 }
14329 
ClearTypeFeedbackInfoAtGCTime()14330 void JSFunction::ClearTypeFeedbackInfoAtGCTime() {
14331   feedback_vector()->ClearSlotsAtGCTime(shared());
14332 }
14333 
TranslatePcOffsetToAstId(uint32_t pc_offset)14334 BailoutId Code::TranslatePcOffsetToAstId(uint32_t pc_offset) {
14335   DisallowHeapAllocation no_gc;
14336   DCHECK(kind() == FUNCTION);
14337   BackEdgeTable back_edges(this, &no_gc);
14338   for (uint32_t i = 0; i < back_edges.length(); i++) {
14339     if (back_edges.pc_offset(i) == pc_offset) return back_edges.ast_id(i);
14340   }
14341   return BailoutId::None();
14342 }
14343 
14344 
TranslateAstIdToPcOffset(BailoutId ast_id)14345 uint32_t Code::TranslateAstIdToPcOffset(BailoutId ast_id) {
14346   DisallowHeapAllocation no_gc;
14347   DCHECK(kind() == FUNCTION);
14348   BackEdgeTable back_edges(this, &no_gc);
14349   for (uint32_t i = 0; i < back_edges.length(); i++) {
14350     if (back_edges.ast_id(i) == ast_id) return back_edges.pc_offset(i);
14351   }
14352   UNREACHABLE();  // We expect to find the back edge.
14353   return 0;
14354 }
14355 
LookupRangeInHandlerTable(int code_offset,int * data,HandlerTable::CatchPrediction * prediction)14356 int Code::LookupRangeInHandlerTable(int code_offset, int* data,
14357                                     HandlerTable::CatchPrediction* prediction) {
14358   DCHECK(!is_optimized_code());
14359   HandlerTable* table = HandlerTable::cast(handler_table());
14360   return table->LookupRange(code_offset, data, prediction);
14361 }
14362 
MakeCodeAgeSequenceYoung(byte * sequence,Isolate * isolate)14363 void Code::MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate) {
14364   PatchPlatformCodeAge(isolate, sequence, kNoAgeCodeAge, NO_MARKING_PARITY);
14365 }
14366 
14367 
MarkCodeAsExecuted(byte * sequence,Isolate * isolate)14368 void Code::MarkCodeAsExecuted(byte* sequence, Isolate* isolate) {
14369   PatchPlatformCodeAge(isolate, sequence, kExecutedOnceCodeAge,
14370       NO_MARKING_PARITY);
14371 }
14372 
14373 
14374 // NextAge defines the Code::Age state transitions during a GC cycle.
NextAge(Code::Age age)14375 static Code::Age NextAge(Code::Age age) {
14376   switch (age) {
14377     case Code::kNotExecutedCodeAge:  // Keep, until we've been executed.
14378     case Code::kToBeExecutedOnceCodeAge:  // Keep, until we've been executed.
14379     case Code::kLastCodeAge:  // Clamp at last Code::Age value.
14380       return age;
14381     case Code::kExecutedOnceCodeAge:
14382       // Pre-age code that has only been executed once.
14383       return static_cast<Code::Age>(Code::kPreAgedCodeAge + 1);
14384     default:
14385       return static_cast<Code::Age>(age + 1);  // Default case: Increase age.
14386   }
14387 }
14388 
14389 
14390 // IsOldAge defines the collection criteria for a Code object.
IsOldAge(Code::Age age)14391 static bool IsOldAge(Code::Age age) {
14392   return age >= Code::kIsOldCodeAge || age == Code::kNotExecutedCodeAge;
14393 }
14394 
14395 
MakeYoung(Isolate * isolate)14396 void Code::MakeYoung(Isolate* isolate) {
14397   byte* sequence = FindCodeAgeSequence();
14398   if (sequence != NULL) MakeCodeAgeSequenceYoung(sequence, isolate);
14399 }
14400 
PreAge(Isolate * isolate)14401 void Code::PreAge(Isolate* isolate) {
14402   byte* sequence = FindCodeAgeSequence();
14403   if (sequence != NULL) {
14404     PatchPlatformCodeAge(isolate, sequence, kPreAgedCodeAge, NO_MARKING_PARITY);
14405   }
14406 }
14407 
MarkToBeExecutedOnce(Isolate * isolate)14408 void Code::MarkToBeExecutedOnce(Isolate* isolate) {
14409   byte* sequence = FindCodeAgeSequence();
14410   if (sequence != NULL) {
14411     PatchPlatformCodeAge(isolate, sequence, kToBeExecutedOnceCodeAge,
14412                          NO_MARKING_PARITY);
14413   }
14414 }
14415 
MakeOlder(MarkingParity current_parity)14416 void Code::MakeOlder(MarkingParity current_parity) {
14417   byte* sequence = FindCodeAgeSequence();
14418   if (sequence != NULL) {
14419     Age age;
14420     MarkingParity code_parity;
14421     Isolate* isolate = GetIsolate();
14422     GetCodeAgeAndParity(isolate, sequence, &age, &code_parity);
14423     Age next_age = NextAge(age);
14424     if (age != next_age && code_parity != current_parity) {
14425       PatchPlatformCodeAge(isolate, sequence, next_age, current_parity);
14426     }
14427   }
14428 }
14429 
14430 
IsOld()14431 bool Code::IsOld() {
14432   return IsOldAge(GetAge());
14433 }
14434 
14435 
FindCodeAgeSequence()14436 byte* Code::FindCodeAgeSequence() {
14437   return FLAG_age_code &&
14438       prologue_offset() != Code::kPrologueOffsetNotSet &&
14439       (kind() == OPTIMIZED_FUNCTION ||
14440        (kind() == FUNCTION && !has_debug_break_slots()))
14441       ? instruction_start() + prologue_offset()
14442       : NULL;
14443 }
14444 
14445 
GetAge()14446 Code::Age Code::GetAge() {
14447   byte* sequence = FindCodeAgeSequence();
14448   if (sequence == NULL) {
14449     return kNoAgeCodeAge;
14450   }
14451   Age age;
14452   MarkingParity parity;
14453   GetCodeAgeAndParity(GetIsolate(), sequence, &age, &parity);
14454   return age;
14455 }
14456 
14457 
GetCodeAgeAndParity(Code * code,Age * age,MarkingParity * parity)14458 void Code::GetCodeAgeAndParity(Code* code, Age* age,
14459                                MarkingParity* parity) {
14460   Isolate* isolate = code->GetIsolate();
14461   Builtins* builtins = isolate->builtins();
14462   Code* stub = NULL;
14463 #define HANDLE_CODE_AGE(AGE)                                            \
14464   stub = *builtins->Make##AGE##CodeYoungAgainEvenMarking();             \
14465   if (code == stub) {                                                   \
14466     *age = k##AGE##CodeAge;                                             \
14467     *parity = EVEN_MARKING_PARITY;                                      \
14468     return;                                                             \
14469   }                                                                     \
14470   stub = *builtins->Make##AGE##CodeYoungAgainOddMarking();              \
14471   if (code == stub) {                                                   \
14472     *age = k##AGE##CodeAge;                                             \
14473     *parity = ODD_MARKING_PARITY;                                       \
14474     return;                                                             \
14475   }
14476   CODE_AGE_LIST(HANDLE_CODE_AGE)
14477 #undef HANDLE_CODE_AGE
14478   stub = *builtins->MarkCodeAsExecutedOnce();
14479   if (code == stub) {
14480     *age = kNotExecutedCodeAge;
14481     *parity = NO_MARKING_PARITY;
14482     return;
14483   }
14484   stub = *builtins->MarkCodeAsExecutedTwice();
14485   if (code == stub) {
14486     *age = kExecutedOnceCodeAge;
14487     *parity = NO_MARKING_PARITY;
14488     return;
14489   }
14490   stub = *builtins->MarkCodeAsToBeExecutedOnce();
14491   if (code == stub) {
14492     *age = kToBeExecutedOnceCodeAge;
14493     *parity = NO_MARKING_PARITY;
14494     return;
14495   }
14496   UNREACHABLE();
14497 }
14498 
14499 
GetCodeAgeStub(Isolate * isolate,Age age,MarkingParity parity)14500 Code* Code::GetCodeAgeStub(Isolate* isolate, Age age, MarkingParity parity) {
14501   Builtins* builtins = isolate->builtins();
14502   switch (age) {
14503 #define HANDLE_CODE_AGE(AGE)                                            \
14504     case k##AGE##CodeAge: {                                             \
14505       Code* stub = parity == EVEN_MARKING_PARITY                        \
14506           ? *builtins->Make##AGE##CodeYoungAgainEvenMarking()           \
14507           : *builtins->Make##AGE##CodeYoungAgainOddMarking();           \
14508       return stub;                                                      \
14509     }
14510     CODE_AGE_LIST(HANDLE_CODE_AGE)
14511 #undef HANDLE_CODE_AGE
14512     case kNotExecutedCodeAge: {
14513       DCHECK(parity == NO_MARKING_PARITY);
14514       return *builtins->MarkCodeAsExecutedOnce();
14515     }
14516     case kExecutedOnceCodeAge: {
14517       DCHECK(parity == NO_MARKING_PARITY);
14518       return *builtins->MarkCodeAsExecutedTwice();
14519     }
14520     case kToBeExecutedOnceCodeAge: {
14521       DCHECK(parity == NO_MARKING_PARITY);
14522       return *builtins->MarkCodeAsToBeExecutedOnce();
14523     }
14524     default:
14525       UNREACHABLE();
14526       break;
14527   }
14528   return NULL;
14529 }
14530 
14531 
PrintDeoptLocation(FILE * out,Address pc)14532 void Code::PrintDeoptLocation(FILE* out, Address pc) {
14533   Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(this, pc);
14534   class SourcePosition pos = info.position;
14535   if (info.deopt_reason != DeoptimizeReason::kNoReason || pos.IsKnown()) {
14536     if (FLAG_hydrogen_track_positions) {
14537       PrintF(out, "            ;;; deoptimize at %d_%d: %s\n", pos.InliningId(),
14538              pos.ScriptOffset(), DeoptimizeReasonToString(info.deopt_reason));
14539     } else {
14540       PrintF(out, "            ;;; deoptimize at ");
14541       OFStream outstr(out);
14542       pos.Print(outstr, this);
14543       PrintF(out, ", %s\n", DeoptimizeReasonToString(info.deopt_reason));
14544     }
14545   }
14546 }
14547 
14548 
CanDeoptAt(Address pc)14549 bool Code::CanDeoptAt(Address pc) {
14550   DeoptimizationInputData* deopt_data =
14551       DeoptimizationInputData::cast(deoptimization_data());
14552   Address code_start_address = instruction_start();
14553   for (int i = 0; i < deopt_data->DeoptCount(); i++) {
14554     if (deopt_data->Pc(i)->value() == -1) continue;
14555     Address address = code_start_address + deopt_data->Pc(i)->value();
14556     if (address == pc && deopt_data->AstId(i) != BailoutId::None()) {
14557       return true;
14558     }
14559   }
14560   return false;
14561 }
14562 
14563 
14564 // Identify kind of code.
Kind2String(Kind kind)14565 const char* Code::Kind2String(Kind kind) {
14566   switch (kind) {
14567 #define CASE(name) case name: return #name;
14568     CODE_KIND_LIST(CASE)
14569 #undef CASE
14570     case NUMBER_OF_KINDS: break;
14571   }
14572   UNREACHABLE();
14573   return NULL;
14574 }
14575 
14576 // Identify kind of code.
Kind2String(Kind kind)14577 const char* AbstractCode::Kind2String(Kind kind) {
14578   if (kind < AbstractCode::INTERPRETED_FUNCTION)
14579     return Code::Kind2String((Code::Kind)kind);
14580   if (kind == AbstractCode::INTERPRETED_FUNCTION) return "INTERPRETED_FUNCTION";
14581   UNREACHABLE();
14582   return NULL;
14583 }
14584 
WeakCellFor(Handle<Code> code)14585 Handle<WeakCell> Code::WeakCellFor(Handle<Code> code) {
14586   DCHECK(code->kind() == OPTIMIZED_FUNCTION);
14587   WeakCell* raw_cell = code->CachedWeakCell();
14588   if (raw_cell != NULL) return Handle<WeakCell>(raw_cell);
14589   Handle<WeakCell> cell = code->GetIsolate()->factory()->NewWeakCell(code);
14590   DeoptimizationInputData::cast(code->deoptimization_data())
14591       ->SetWeakCellCache(*cell);
14592   return cell;
14593 }
14594 
14595 
CachedWeakCell()14596 WeakCell* Code::CachedWeakCell() {
14597   DCHECK(kind() == OPTIMIZED_FUNCTION);
14598   Object* weak_cell_cache =
14599       DeoptimizationInputData::cast(deoptimization_data())->WeakCellCache();
14600   if (weak_cell_cache->IsWeakCell()) {
14601     DCHECK(this == WeakCell::cast(weak_cell_cache)->value());
14602     return WeakCell::cast(weak_cell_cache);
14603   }
14604   return NULL;
14605 }
14606 
14607 #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
14608 
ICState2String(InlineCacheState state)14609 const char* Code::ICState2String(InlineCacheState state) {
14610   switch (state) {
14611     case UNINITIALIZED:
14612       return "UNINITIALIZED";
14613     case PREMONOMORPHIC:
14614       return "PREMONOMORPHIC";
14615     case MONOMORPHIC:
14616       return "MONOMORPHIC";
14617     case RECOMPUTE_HANDLER:
14618       return "RECOMPUTE_HANDLER";
14619     case POLYMORPHIC:
14620       return "POLYMORPHIC";
14621     case MEGAMORPHIC:
14622       return "MEGAMORPHIC";
14623     case GENERIC:
14624       return "GENERIC";
14625   }
14626   UNREACHABLE();
14627   return NULL;
14628 }
14629 
PrintExtraICState(std::ostream & os,Kind kind,ExtraICState extra)14630 void Code::PrintExtraICState(std::ostream& os,  // NOLINT
14631                              Kind kind, ExtraICState extra) {
14632   os << "extra_ic_state = ";
14633   if ((kind == STORE_IC || kind == KEYED_STORE_IC) &&
14634       is_strict(static_cast<LanguageMode>(extra))) {
14635     os << "STRICT\n";
14636   } else {
14637     os << extra << "\n";
14638   }
14639 }
14640 
14641 #endif  // defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
14642 
14643 #ifdef ENABLE_DISASSEMBLER
14644 
DeoptimizationInputDataPrint(std::ostream & os)14645 void DeoptimizationInputData::DeoptimizationInputDataPrint(
14646     std::ostream& os) {  // NOLINT
14647   disasm::NameConverter converter;
14648   int const inlined_function_count = InlinedFunctionCount()->value();
14649   os << "Inlined functions (count = " << inlined_function_count << ")\n";
14650   for (int id = 0; id < inlined_function_count; ++id) {
14651     Object* info = LiteralArray()->get(id);
14652     os << " " << Brief(SharedFunctionInfo::cast(info)) << "\n";
14653   }
14654   os << "\n";
14655   int deopt_count = DeoptCount();
14656   os << "Deoptimization Input Data (deopt points = " << deopt_count << ")\n";
14657   if (0 != deopt_count) {
14658     os << " index  ast id    argc     pc";
14659     if (FLAG_print_code_verbose) os << "  commands";
14660     os << "\n";
14661   }
14662   for (int i = 0; i < deopt_count; i++) {
14663     os << std::setw(6) << i << "  " << std::setw(6) << AstId(i).ToInt() << "  "
14664        << std::setw(6) << ArgumentsStackHeight(i)->value() << " "
14665        << std::setw(6) << Pc(i)->value();
14666 
14667     if (!FLAG_print_code_verbose) {
14668       os << "\n";
14669       continue;
14670     }
14671     // Print details of the frame translation.
14672     int translation_index = TranslationIndex(i)->value();
14673     TranslationIterator iterator(TranslationByteArray(), translation_index);
14674     Translation::Opcode opcode =
14675         static_cast<Translation::Opcode>(iterator.Next());
14676     DCHECK(Translation::BEGIN == opcode);
14677     int frame_count = iterator.Next();
14678     int jsframe_count = iterator.Next();
14679     os << "  " << Translation::StringFor(opcode)
14680        << " {frame count=" << frame_count
14681        << ", js frame count=" << jsframe_count << "}\n";
14682 
14683     while (iterator.HasNext() &&
14684            Translation::BEGIN !=
14685            (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
14686       os << std::setw(31) << "    " << Translation::StringFor(opcode) << " ";
14687 
14688       switch (opcode) {
14689         case Translation::BEGIN:
14690           UNREACHABLE();
14691           break;
14692 
14693         case Translation::JS_FRAME: {
14694           int ast_id = iterator.Next();
14695           int shared_info_id = iterator.Next();
14696           unsigned height = iterator.Next();
14697           Object* shared_info = LiteralArray()->get(shared_info_id);
14698           os << "{ast_id=" << ast_id << ", function="
14699              << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14700              << ", height=" << height << "}";
14701           break;
14702         }
14703 
14704         case Translation::INTERPRETED_FRAME: {
14705           int bytecode_offset = iterator.Next();
14706           int shared_info_id = iterator.Next();
14707           unsigned height = iterator.Next();
14708           Object* shared_info = LiteralArray()->get(shared_info_id);
14709           os << "{bytecode_offset=" << bytecode_offset << ", function="
14710              << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14711              << ", height=" << height << "}";
14712           break;
14713         }
14714 
14715         case Translation::COMPILED_STUB_FRAME: {
14716           Code::Kind stub_kind = static_cast<Code::Kind>(iterator.Next());
14717           os << "{kind=" << stub_kind << "}";
14718           break;
14719         }
14720 
14721         case Translation::ARGUMENTS_ADAPTOR_FRAME:
14722         case Translation::CONSTRUCT_STUB_FRAME: {
14723           int shared_info_id = iterator.Next();
14724           Object* shared_info = LiteralArray()->get(shared_info_id);
14725           unsigned height = iterator.Next();
14726           os << "{function="
14727              << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14728              << ", height=" << height << "}";
14729           break;
14730         }
14731 
14732         case Translation::TAIL_CALLER_FRAME: {
14733           int shared_info_id = iterator.Next();
14734           Object* shared_info = LiteralArray()->get(shared_info_id);
14735           os << "{function="
14736              << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14737              << "}";
14738           break;
14739         }
14740 
14741         case Translation::GETTER_STUB_FRAME:
14742         case Translation::SETTER_STUB_FRAME: {
14743           int shared_info_id = iterator.Next();
14744           Object* shared_info = LiteralArray()->get(shared_info_id);
14745           os << "{function=" << Brief(SharedFunctionInfo::cast(shared_info)
14746                                           ->DebugName()) << "}";
14747           break;
14748         }
14749 
14750         case Translation::REGISTER: {
14751           int reg_code = iterator.Next();
14752           os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
14753           break;
14754         }
14755 
14756         case Translation::INT32_REGISTER: {
14757           int reg_code = iterator.Next();
14758           os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
14759           break;
14760         }
14761 
14762         case Translation::UINT32_REGISTER: {
14763           int reg_code = iterator.Next();
14764           os << "{input=" << converter.NameOfCPURegister(reg_code)
14765              << " (unsigned)}";
14766           break;
14767         }
14768 
14769         case Translation::BOOL_REGISTER: {
14770           int reg_code = iterator.Next();
14771           os << "{input=" << converter.NameOfCPURegister(reg_code)
14772              << " (bool)}";
14773           break;
14774         }
14775 
14776         case Translation::FLOAT_REGISTER: {
14777           int reg_code = iterator.Next();
14778           os << "{input="
14779              << RegisterConfiguration::Crankshaft()->GetFloatRegisterName(
14780                     reg_code)
14781              << "}";
14782           break;
14783         }
14784 
14785         case Translation::DOUBLE_REGISTER: {
14786           int reg_code = iterator.Next();
14787           os << "{input="
14788              << RegisterConfiguration::Crankshaft()->GetDoubleRegisterName(
14789                     reg_code)
14790              << "}";
14791           break;
14792         }
14793 
14794         case Translation::STACK_SLOT: {
14795           int input_slot_index = iterator.Next();
14796           os << "{input=" << input_slot_index << "}";
14797           break;
14798         }
14799 
14800         case Translation::INT32_STACK_SLOT: {
14801           int input_slot_index = iterator.Next();
14802           os << "{input=" << input_slot_index << "}";
14803           break;
14804         }
14805 
14806         case Translation::UINT32_STACK_SLOT: {
14807           int input_slot_index = iterator.Next();
14808           os << "{input=" << input_slot_index << " (unsigned)}";
14809           break;
14810         }
14811 
14812         case Translation::BOOL_STACK_SLOT: {
14813           int input_slot_index = iterator.Next();
14814           os << "{input=" << input_slot_index << " (bool)}";
14815           break;
14816         }
14817 
14818         case Translation::FLOAT_STACK_SLOT:
14819         case Translation::DOUBLE_STACK_SLOT: {
14820           int input_slot_index = iterator.Next();
14821           os << "{input=" << input_slot_index << "}";
14822           break;
14823         }
14824 
14825         case Translation::LITERAL: {
14826           int literal_index = iterator.Next();
14827           Object* literal_value = LiteralArray()->get(literal_index);
14828           os << "{literal_id=" << literal_index << " (" << Brief(literal_value)
14829              << ")}";
14830           break;
14831         }
14832 
14833         case Translation::DUPLICATED_OBJECT: {
14834           int object_index = iterator.Next();
14835           os << "{object_index=" << object_index << "}";
14836           break;
14837         }
14838 
14839         case Translation::ARGUMENTS_OBJECT:
14840         case Translation::CAPTURED_OBJECT: {
14841           int args_length = iterator.Next();
14842           os << "{length=" << args_length << "}";
14843           break;
14844         }
14845       }
14846       os << "\n";
14847     }
14848   }
14849 }
14850 
14851 
DeoptimizationOutputDataPrint(std::ostream & os)14852 void DeoptimizationOutputData::DeoptimizationOutputDataPrint(
14853     std::ostream& os) {  // NOLINT
14854   os << "Deoptimization Output Data (deopt points = " << this->DeoptPoints()
14855      << ")\n";
14856   if (this->DeoptPoints() == 0) return;
14857 
14858   os << "ast id        pc  state\n";
14859   for (int i = 0; i < this->DeoptPoints(); i++) {
14860     int pc_and_state = this->PcAndState(i)->value();
14861     os << std::setw(6) << this->AstId(i).ToInt() << "  " << std::setw(8)
14862        << FullCodeGenerator::PcField::decode(pc_and_state) << "  "
14863        << Deoptimizer::BailoutStateToString(
14864               FullCodeGenerator::BailoutStateField::decode(pc_and_state))
14865        << "\n";
14866   }
14867 }
14868 
14869 
HandlerTableRangePrint(std::ostream & os)14870 void HandlerTable::HandlerTableRangePrint(std::ostream& os) {
14871   os << "   from   to       hdlr\n";
14872   for (int i = 0; i < length(); i += kRangeEntrySize) {
14873     int pc_start = Smi::cast(get(i + kRangeStartIndex))->value();
14874     int pc_end = Smi::cast(get(i + kRangeEndIndex))->value();
14875     int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value();
14876     int handler_offset = HandlerOffsetField::decode(handler_field);
14877     CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
14878     int data = Smi::cast(get(i + kRangeDataIndex))->value();
14879     os << "  (" << std::setw(4) << pc_start << "," << std::setw(4) << pc_end
14880        << ")  ->  " << std::setw(4) << handler_offset
14881        << " (prediction=" << prediction << ", data=" << data << ")\n";
14882   }
14883 }
14884 
14885 
HandlerTableReturnPrint(std::ostream & os)14886 void HandlerTable::HandlerTableReturnPrint(std::ostream& os) {
14887   os << "   off      hdlr (c)\n";
14888   for (int i = 0; i < length(); i += kReturnEntrySize) {
14889     int pc_offset = Smi::cast(get(i + kReturnOffsetIndex))->value();
14890     int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value();
14891     int handler_offset = HandlerOffsetField::decode(handler_field);
14892     CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
14893     os << "  " << std::setw(4) << pc_offset << "  ->  " << std::setw(4)
14894        << handler_offset << " (prediction=" << prediction << ")\n";
14895   }
14896 }
14897 
14898 
Disassemble(const char * name,std::ostream & os)14899 void Code::Disassemble(const char* name, std::ostream& os) {  // NOLINT
14900   os << "kind = " << Kind2String(kind()) << "\n";
14901   if (IsCodeStubOrIC()) {
14902     const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this));
14903     os << "major_key = " << (n == NULL ? "null" : n) << "\n";
14904   }
14905   if (is_inline_cache_stub()) {
14906     if (!IC::ICUseVector(kind())) {
14907       InlineCacheState ic_state = IC::StateFromCode(this);
14908       os << "ic_state = " << ICState2String(ic_state) << "\n";
14909     }
14910     PrintExtraICState(os, kind(), extra_ic_state());
14911     if (is_compare_ic_stub()) {
14912       DCHECK(CodeStub::GetMajorKey(this) == CodeStub::CompareIC);
14913       CompareICStub stub(stub_key(), GetIsolate());
14914       os << "compare_state = " << CompareICState::GetStateName(stub.left())
14915          << "*" << CompareICState::GetStateName(stub.right()) << " -> "
14916          << CompareICState::GetStateName(stub.state()) << "\n";
14917       os << "compare_operation = " << Token::Name(stub.op()) << "\n";
14918     }
14919   }
14920   if ((name != nullptr) && (name[0] != '\0')) {
14921     os << "name = " << name << "\n";
14922   } else if (kind() == BUILTIN) {
14923     name = GetIsolate()->builtins()->Lookup(instruction_start());
14924     if (name != nullptr) {
14925       os << "name = " << name << "\n";
14926     }
14927   } else if (kind() == BYTECODE_HANDLER) {
14928     name = GetIsolate()->interpreter()->LookupNameOfBytecodeHandler(this);
14929     if (name != nullptr) {
14930       os << "name = " << name << "\n";
14931     }
14932   }
14933   if (kind() == OPTIMIZED_FUNCTION) {
14934     os << "stack_slots = " << stack_slots() << "\n";
14935   }
14936   os << "compiler = " << (is_turbofanned()
14937                               ? "turbofan"
14938                               : is_crankshafted() ? "crankshaft"
14939                                                   : kind() == Code::FUNCTION
14940                                                         ? "full-codegen"
14941                                                         : "unknown") << "\n";
14942 
14943   os << "Instructions (size = " << instruction_size() << ")\n";
14944   {
14945     Isolate* isolate = GetIsolate();
14946     int size = instruction_size();
14947     int safepoint_offset =
14948         is_crankshafted() ? static_cast<int>(safepoint_table_offset()) : size;
14949     int back_edge_offset = (kind() == Code::FUNCTION)
14950                                ? static_cast<int>(back_edge_table_offset())
14951                                : size;
14952     int constant_pool_offset = FLAG_enable_embedded_constant_pool
14953                                    ? this->constant_pool_offset()
14954                                    : size;
14955 
14956     // Stop before reaching any embedded tables
14957     int code_size = Min(safepoint_offset, back_edge_offset);
14958     code_size = Min(code_size, constant_pool_offset);
14959     byte* begin = instruction_start();
14960     byte* end = begin + code_size;
14961     Disassembler::Decode(isolate, &os, begin, end, this);
14962 
14963     if (constant_pool_offset < size) {
14964       int constant_pool_size = size - constant_pool_offset;
14965       DCHECK((constant_pool_size & kPointerAlignmentMask) == 0);
14966       os << "\nConstant Pool (size = " << constant_pool_size << ")\n";
14967       Vector<char> buf = Vector<char>::New(50);
14968       intptr_t* ptr = reinterpret_cast<intptr_t*>(begin + constant_pool_offset);
14969       for (int i = 0; i < constant_pool_size; i += kPointerSize, ptr++) {
14970         SNPrintF(buf, "%4d %08" V8PRIxPTR, i, *ptr);
14971         os << static_cast<const void*>(ptr) << "  " << buf.start() << "\n";
14972       }
14973     }
14974   }
14975   os << "\n";
14976 
14977   SourcePositionTableIterator it(source_position_table());
14978   if (!it.done()) {
14979     os << "Source positions:\n pc offset  position\n";
14980     for (; !it.done(); it.Advance()) {
14981       os << std::setw(10) << it.code_offset() << std::setw(10)
14982          << it.source_position().ScriptOffset()
14983          << (it.is_statement() ? "  statement" : "") << "\n";
14984     }
14985     os << "\n";
14986   }
14987 
14988   if (kind() == FUNCTION) {
14989     DeoptimizationOutputData* data =
14990         DeoptimizationOutputData::cast(this->deoptimization_data());
14991     data->DeoptimizationOutputDataPrint(os);
14992   } else if (kind() == OPTIMIZED_FUNCTION) {
14993     DeoptimizationInputData* data =
14994         DeoptimizationInputData::cast(this->deoptimization_data());
14995     data->DeoptimizationInputDataPrint(os);
14996   }
14997   os << "\n";
14998 
14999   if (is_crankshafted()) {
15000     SafepointTable table(this);
15001     os << "Safepoints (size = " << table.size() << ")\n";
15002     for (unsigned i = 0; i < table.length(); i++) {
15003       unsigned pc_offset = table.GetPcOffset(i);
15004       os << static_cast<const void*>(instruction_start() + pc_offset) << "  ";
15005       os << std::setw(4) << pc_offset << "  ";
15006       table.PrintEntry(i, os);
15007       os << " (sp -> fp)  ";
15008       SafepointEntry entry = table.GetEntry(i);
15009       if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
15010         os << std::setw(6) << entry.deoptimization_index();
15011       } else {
15012         os << "<none>";
15013       }
15014       if (entry.argument_count() > 0) {
15015         os << " argc: " << entry.argument_count();
15016       }
15017       os << "\n";
15018     }
15019     os << "\n";
15020   } else if (kind() == FUNCTION) {
15021     unsigned offset = back_edge_table_offset();
15022     // If there is no back edge table, the "table start" will be at or after
15023     // (due to alignment) the end of the instruction stream.
15024     if (static_cast<int>(offset) < instruction_size()) {
15025       DisallowHeapAllocation no_gc;
15026       BackEdgeTable back_edges(this, &no_gc);
15027 
15028       os << "Back edges (size = " << back_edges.length() << ")\n";
15029       os << "ast_id  pc_offset  loop_depth\n";
15030 
15031       for (uint32_t i = 0; i < back_edges.length(); i++) {
15032         os << std::setw(6) << back_edges.ast_id(i).ToInt() << "  "
15033            << std::setw(9) << back_edges.pc_offset(i) << "  " << std::setw(10)
15034            << back_edges.loop_depth(i) << "\n";
15035       }
15036 
15037       os << "\n";
15038     }
15039 #ifdef OBJECT_PRINT
15040     if (!type_feedback_info()->IsUndefined(GetIsolate())) {
15041       TypeFeedbackInfo::cast(type_feedback_info())->TypeFeedbackInfoPrint(os);
15042       os << "\n";
15043     }
15044 #endif
15045   }
15046 
15047   if (handler_table()->length() > 0) {
15048     os << "Handler Table (size = " << handler_table()->Size() << ")\n";
15049     if (kind() == FUNCTION) {
15050       HandlerTable::cast(handler_table())->HandlerTableRangePrint(os);
15051     } else if (kind() == OPTIMIZED_FUNCTION) {
15052       HandlerTable::cast(handler_table())->HandlerTableReturnPrint(os);
15053     }
15054     os << "\n";
15055   }
15056 
15057   os << "RelocInfo (size = " << relocation_size() << ")\n";
15058   for (RelocIterator it(this); !it.done(); it.next()) {
15059     it.rinfo()->Print(GetIsolate(), os);
15060   }
15061   os << "\n";
15062 
15063   if (has_unwinding_info()) {
15064     os << "UnwindingInfo (size = " << unwinding_info_size() << ")\n";
15065     EhFrameDisassembler eh_frame_disassembler(unwinding_info_start(),
15066                                               unwinding_info_end());
15067     eh_frame_disassembler.DisassembleToStream(os);
15068     os << "\n";
15069   }
15070 }
15071 #endif  // ENABLE_DISASSEMBLER
15072 
15073 
Disassemble(std::ostream & os)15074 void BytecodeArray::Disassemble(std::ostream& os) {
15075   os << "Parameter count " << parameter_count() << "\n";
15076   os << "Frame size " << frame_size() << "\n";
15077 
15078   const uint8_t* base_address = GetFirstBytecodeAddress();
15079   SourcePositionTableIterator source_positions(source_position_table());
15080 
15081   interpreter::BytecodeArrayIterator iterator(handle(this));
15082   while (!iterator.done()) {
15083     if (!source_positions.done() &&
15084         iterator.current_offset() == source_positions.code_offset()) {
15085       os << std::setw(5) << source_positions.source_position().ScriptOffset();
15086       os << (source_positions.is_statement() ? " S> " : " E> ");
15087       source_positions.Advance();
15088     } else {
15089       os << "         ";
15090     }
15091     const uint8_t* current_address = base_address + iterator.current_offset();
15092     os << reinterpret_cast<const void*>(current_address) << " @ "
15093        << std::setw(4) << iterator.current_offset() << " : ";
15094     interpreter::BytecodeDecoder::Decode(os, current_address,
15095                                          parameter_count());
15096     if (interpreter::Bytecodes::IsJump(iterator.current_bytecode())) {
15097       const void* jump_target = base_address + iterator.GetJumpTargetOffset();
15098       os << " (" << jump_target << " @ " << iterator.GetJumpTargetOffset()
15099          << ")";
15100     }
15101     os << std::endl;
15102     iterator.Advance();
15103   }
15104 
15105   if (constant_pool()->length() > 0) {
15106     os << "Constant pool (size = " << constant_pool()->length() << ")\n";
15107     constant_pool()->Print();
15108   }
15109 
15110 #ifdef ENABLE_DISASSEMBLER
15111   if (handler_table()->length() > 0) {
15112     os << "Handler Table (size = " << handler_table()->Size() << ")\n";
15113     HandlerTable::cast(handler_table())->HandlerTableRangePrint(os);
15114   }
15115 #endif
15116 }
15117 
CopyBytecodesTo(BytecodeArray * to)15118 void BytecodeArray::CopyBytecodesTo(BytecodeArray* to) {
15119   BytecodeArray* from = this;
15120   DCHECK_EQ(from->length(), to->length());
15121   CopyBytes(to->GetFirstBytecodeAddress(), from->GetFirstBytecodeAddress(),
15122             from->length());
15123 }
15124 
LookupRangeInHandlerTable(int code_offset,int * data,HandlerTable::CatchPrediction * prediction)15125 int BytecodeArray::LookupRangeInHandlerTable(
15126     int code_offset, int* data, HandlerTable::CatchPrediction* prediction) {
15127   HandlerTable* table = HandlerTable::cast(handler_table());
15128   code_offset++;  // Point after current bytecode.
15129   return table->LookupRange(code_offset, data, prediction);
15130 }
15131 
15132 // static
Initialize(Handle<JSArray> array,int capacity,int length)15133 void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
15134   DCHECK(capacity >= 0);
15135   array->GetIsolate()->factory()->NewJSArrayStorage(
15136       array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
15137 }
15138 
SetLength(Handle<JSArray> array,uint32_t new_length)15139 void JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) {
15140   // We should never end in here with a pixel or external array.
15141   DCHECK(array->AllowsSetLength());
15142   if (array->SetLengthWouldNormalize(new_length)) {
15143     JSObject::NormalizeElements(array);
15144   }
15145   array->GetElementsAccessor()->SetLength(array, new_length);
15146 }
15147 
15148 
15149 // static
AddDependentCode(Handle<Map> map,DependentCode::DependencyGroup group,Handle<Code> code)15150 void Map::AddDependentCode(Handle<Map> map,
15151                            DependentCode::DependencyGroup group,
15152                            Handle<Code> code) {
15153   Handle<WeakCell> cell = Code::WeakCellFor(code);
15154   Handle<DependentCode> codes = DependentCode::InsertWeakCode(
15155       Handle<DependentCode>(map->dependent_code()), group, cell);
15156   if (*codes != map->dependent_code()) map->set_dependent_code(*codes);
15157 }
15158 
15159 
InsertCompilationDependencies(Handle<DependentCode> entries,DependencyGroup group,Handle<Foreign> info)15160 Handle<DependentCode> DependentCode::InsertCompilationDependencies(
15161     Handle<DependentCode> entries, DependencyGroup group,
15162     Handle<Foreign> info) {
15163   return Insert(entries, group, info);
15164 }
15165 
15166 
InsertWeakCode(Handle<DependentCode> entries,DependencyGroup group,Handle<WeakCell> code_cell)15167 Handle<DependentCode> DependentCode::InsertWeakCode(
15168     Handle<DependentCode> entries, DependencyGroup group,
15169     Handle<WeakCell> code_cell) {
15170   return Insert(entries, group, code_cell);
15171 }
15172 
15173 
Insert(Handle<DependentCode> entries,DependencyGroup group,Handle<Object> object)15174 Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
15175                                             DependencyGroup group,
15176                                             Handle<Object> object) {
15177   if (entries->length() == 0 || entries->group() > group) {
15178     // There is no such group.
15179     return DependentCode::New(group, object, entries);
15180   }
15181   if (entries->group() < group) {
15182     // The group comes later in the list.
15183     Handle<DependentCode> old_next(entries->next_link());
15184     Handle<DependentCode> new_next = Insert(old_next, group, object);
15185     if (!old_next.is_identical_to(new_next)) {
15186       entries->set_next_link(*new_next);
15187     }
15188     return entries;
15189   }
15190   DCHECK_EQ(group, entries->group());
15191   int count = entries->count();
15192   // Check for existing entry to avoid duplicates.
15193   for (int i = 0; i < count; i++) {
15194     if (entries->object_at(i) == *object) return entries;
15195   }
15196   if (entries->length() < kCodesStartIndex + count + 1) {
15197     entries = EnsureSpace(entries);
15198     // Count could have changed, reload it.
15199     count = entries->count();
15200   }
15201   entries->set_object_at(count, *object);
15202   entries->set_count(count + 1);
15203   return entries;
15204 }
15205 
15206 
New(DependencyGroup group,Handle<Object> object,Handle<DependentCode> next)15207 Handle<DependentCode> DependentCode::New(DependencyGroup group,
15208                                          Handle<Object> object,
15209                                          Handle<DependentCode> next) {
15210   Isolate* isolate = next->GetIsolate();
15211   Handle<DependentCode> result = Handle<DependentCode>::cast(
15212       isolate->factory()->NewFixedArray(kCodesStartIndex + 1, TENURED));
15213   result->set_next_link(*next);
15214   result->set_flags(GroupField::encode(group) | CountField::encode(1));
15215   result->set_object_at(0, *object);
15216   return result;
15217 }
15218 
15219 
EnsureSpace(Handle<DependentCode> entries)15220 Handle<DependentCode> DependentCode::EnsureSpace(
15221     Handle<DependentCode> entries) {
15222   if (entries->Compact()) return entries;
15223   Isolate* isolate = entries->GetIsolate();
15224   int capacity = kCodesStartIndex + DependentCode::Grow(entries->count());
15225   int grow_by = capacity - entries->length();
15226   return Handle<DependentCode>::cast(
15227       isolate->factory()->CopyFixedArrayAndGrow(entries, grow_by, TENURED));
15228 }
15229 
15230 
Compact()15231 bool DependentCode::Compact() {
15232   int old_count = count();
15233   int new_count = 0;
15234   for (int i = 0; i < old_count; i++) {
15235     Object* obj = object_at(i);
15236     if (!obj->IsWeakCell() || !WeakCell::cast(obj)->cleared()) {
15237       if (i != new_count) {
15238         copy(i, new_count);
15239       }
15240       new_count++;
15241     }
15242   }
15243   set_count(new_count);
15244   for (int i = new_count; i < old_count; i++) {
15245     clear_at(i);
15246   }
15247   return new_count < old_count;
15248 }
15249 
15250 
UpdateToFinishedCode(DependencyGroup group,Foreign * info,WeakCell * code_cell)15251 void DependentCode::UpdateToFinishedCode(DependencyGroup group, Foreign* info,
15252                                          WeakCell* code_cell) {
15253   if (this->length() == 0 || this->group() > group) {
15254     // There is no such group.
15255     return;
15256   }
15257   if (this->group() < group) {
15258     // The group comes later in the list.
15259     next_link()->UpdateToFinishedCode(group, info, code_cell);
15260     return;
15261   }
15262   DCHECK_EQ(group, this->group());
15263   DisallowHeapAllocation no_gc;
15264   int count = this->count();
15265   for (int i = 0; i < count; i++) {
15266     if (object_at(i) == info) {
15267       set_object_at(i, code_cell);
15268       break;
15269     }
15270   }
15271 #ifdef DEBUG
15272   for (int i = 0; i < count; i++) {
15273     DCHECK(object_at(i) != info);
15274   }
15275 #endif
15276 }
15277 
15278 
RemoveCompilationDependencies(DependentCode::DependencyGroup group,Foreign * info)15279 void DependentCode::RemoveCompilationDependencies(
15280     DependentCode::DependencyGroup group, Foreign* info) {
15281   if (this->length() == 0 || this->group() > group) {
15282     // There is no such group.
15283     return;
15284   }
15285   if (this->group() < group) {
15286     // The group comes later in the list.
15287     next_link()->RemoveCompilationDependencies(group, info);
15288     return;
15289   }
15290   DCHECK_EQ(group, this->group());
15291   DisallowHeapAllocation no_allocation;
15292   int old_count = count();
15293   // Find compilation info wrapper.
15294   int info_pos = -1;
15295   for (int i = 0; i < old_count; i++) {
15296     if (object_at(i) == info) {
15297       info_pos = i;
15298       break;
15299     }
15300   }
15301   if (info_pos == -1) return;  // Not found.
15302   // Use the last code to fill the gap.
15303   if (info_pos < old_count - 1) {
15304     copy(old_count - 1, info_pos);
15305   }
15306   clear_at(old_count - 1);
15307   set_count(old_count - 1);
15308 
15309 #ifdef DEBUG
15310   for (int i = 0; i < old_count - 1; i++) {
15311     DCHECK(object_at(i) != info);
15312   }
15313 #endif
15314 }
15315 
15316 
Contains(DependencyGroup group,WeakCell * code_cell)15317 bool DependentCode::Contains(DependencyGroup group, WeakCell* code_cell) {
15318   if (this->length() == 0 || this->group() > group) {
15319     // There is no such group.
15320     return false;
15321   }
15322   if (this->group() < group) {
15323     // The group comes later in the list.
15324     return next_link()->Contains(group, code_cell);
15325   }
15326   DCHECK_EQ(group, this->group());
15327   int count = this->count();
15328   for (int i = 0; i < count; i++) {
15329     if (object_at(i) == code_cell) return true;
15330   }
15331   return false;
15332 }
15333 
15334 
IsEmpty(DependencyGroup group)15335 bool DependentCode::IsEmpty(DependencyGroup group) {
15336   if (this->length() == 0 || this->group() > group) {
15337     // There is no such group.
15338     return true;
15339   }
15340   if (this->group() < group) {
15341     // The group comes later in the list.
15342     return next_link()->IsEmpty(group);
15343   }
15344   DCHECK_EQ(group, this->group());
15345   return count() == 0;
15346 }
15347 
15348 
MarkCodeForDeoptimization(Isolate * isolate,DependentCode::DependencyGroup group)15349 bool DependentCode::MarkCodeForDeoptimization(
15350     Isolate* isolate,
15351     DependentCode::DependencyGroup group) {
15352   if (this->length() == 0 || this->group() > group) {
15353     // There is no such group.
15354     return false;
15355   }
15356   if (this->group() < group) {
15357     // The group comes later in the list.
15358     return next_link()->MarkCodeForDeoptimization(isolate, group);
15359   }
15360   DCHECK_EQ(group, this->group());
15361   DisallowHeapAllocation no_allocation_scope;
15362   // Mark all the code that needs to be deoptimized.
15363   bool marked = false;
15364   bool invalidate_embedded_objects = group == kWeakCodeGroup;
15365   int count = this->count();
15366   for (int i = 0; i < count; i++) {
15367     Object* obj = object_at(i);
15368     if (obj->IsWeakCell()) {
15369       WeakCell* cell = WeakCell::cast(obj);
15370       if (cell->cleared()) continue;
15371       Code* code = Code::cast(cell->value());
15372       if (!code->marked_for_deoptimization()) {
15373         SetMarkedForDeoptimization(code, group);
15374         if (invalidate_embedded_objects) {
15375           code->InvalidateEmbeddedObjects();
15376         }
15377         marked = true;
15378       }
15379     } else {
15380       DCHECK(obj->IsForeign());
15381       CompilationDependencies* info =
15382           reinterpret_cast<CompilationDependencies*>(
15383               Foreign::cast(obj)->foreign_address());
15384       info->Abort();
15385     }
15386   }
15387   for (int i = 0; i < count; i++) {
15388     clear_at(i);
15389   }
15390   set_count(0);
15391   return marked;
15392 }
15393 
15394 
DeoptimizeDependentCodeGroup(Isolate * isolate,DependentCode::DependencyGroup group)15395 void DependentCode::DeoptimizeDependentCodeGroup(
15396     Isolate* isolate,
15397     DependentCode::DependencyGroup group) {
15398   DCHECK(AllowCodeDependencyChange::IsAllowed());
15399   DisallowHeapAllocation no_allocation_scope;
15400   bool marked = MarkCodeForDeoptimization(isolate, group);
15401   if (marked) Deoptimizer::DeoptimizeMarkedCode(isolate);
15402 }
15403 
15404 
SetMarkedForDeoptimization(Code * code,DependencyGroup group)15405 void DependentCode::SetMarkedForDeoptimization(Code* code,
15406                                                DependencyGroup group) {
15407   code->set_marked_for_deoptimization(true);
15408   if (FLAG_trace_deopt &&
15409       (code->deoptimization_data() != code->GetHeap()->empty_fixed_array())) {
15410     DeoptimizationInputData* deopt_data =
15411         DeoptimizationInputData::cast(code->deoptimization_data());
15412     CodeTracer::Scope scope(code->GetHeap()->isolate()->GetCodeTracer());
15413     PrintF(scope.file(), "[marking dependent code 0x%08" V8PRIxPTR
15414                          " (opt #%d) for deoptimization, reason: %s]\n",
15415            reinterpret_cast<intptr_t>(code),
15416            deopt_data->OptimizationId()->value(), DependencyGroupName(group));
15417   }
15418 }
15419 
15420 
DependencyGroupName(DependencyGroup group)15421 const char* DependentCode::DependencyGroupName(DependencyGroup group) {
15422   switch (group) {
15423     case kWeakCodeGroup:
15424       return "weak-code";
15425     case kTransitionGroup:
15426       return "transition";
15427     case kPrototypeCheckGroup:
15428       return "prototype-check";
15429     case kPropertyCellChangedGroup:
15430       return "property-cell-changed";
15431     case kFieldOwnerGroup:
15432       return "field-owner";
15433     case kInitialMapChangedGroup:
15434       return "initial-map-changed";
15435     case kAllocationSiteTenuringChangedGroup:
15436       return "allocation-site-tenuring-changed";
15437     case kAllocationSiteTransitionChangedGroup:
15438       return "allocation-site-transition-changed";
15439   }
15440   UNREACHABLE();
15441   return "?";
15442 }
15443 
15444 
TransitionToPrototype(Handle<Map> map,Handle<Object> prototype,PrototypeOptimizationMode mode)15445 Handle<Map> Map::TransitionToPrototype(Handle<Map> map,
15446                                        Handle<Object> prototype,
15447                                        PrototypeOptimizationMode mode) {
15448   Handle<Map> new_map = TransitionArray::GetPrototypeTransition(map, prototype);
15449   if (new_map.is_null()) {
15450     new_map = Copy(map, "TransitionToPrototype");
15451     TransitionArray::PutPrototypeTransition(map, prototype, new_map);
15452     Map::SetPrototype(new_map, prototype, mode);
15453   }
15454   return new_map;
15455 }
15456 
15457 
SetPrototype(Handle<JSReceiver> object,Handle<Object> value,bool from_javascript,ShouldThrow should_throw)15458 Maybe<bool> JSReceiver::SetPrototype(Handle<JSReceiver> object,
15459                                      Handle<Object> value, bool from_javascript,
15460                                      ShouldThrow should_throw) {
15461   if (object->IsJSProxy()) {
15462     return JSProxy::SetPrototype(Handle<JSProxy>::cast(object), value,
15463                                  from_javascript, should_throw);
15464   }
15465   return JSObject::SetPrototype(Handle<JSObject>::cast(object), value,
15466                                 from_javascript, should_throw);
15467 }
15468 
15469 
15470 // ES6: 9.5.2 [[SetPrototypeOf]] (V)
15471 // static
SetPrototype(Handle<JSProxy> proxy,Handle<Object> value,bool from_javascript,ShouldThrow should_throw)15472 Maybe<bool> JSProxy::SetPrototype(Handle<JSProxy> proxy, Handle<Object> value,
15473                                   bool from_javascript,
15474                                   ShouldThrow should_throw) {
15475   Isolate* isolate = proxy->GetIsolate();
15476   STACK_CHECK(isolate, Nothing<bool>());
15477   Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string();
15478   // 1. Assert: Either Type(V) is Object or Type(V) is Null.
15479   DCHECK(value->IsJSReceiver() || value->IsNull(isolate));
15480   // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
15481   Handle<Object> handler(proxy->handler(), isolate);
15482   // 3. If handler is null, throw a TypeError exception.
15483   // 4. Assert: Type(handler) is Object.
15484   if (proxy->IsRevoked()) {
15485     isolate->Throw(*isolate->factory()->NewTypeError(
15486         MessageTemplate::kProxyRevoked, trap_name));
15487     return Nothing<bool>();
15488   }
15489   // 5. Let target be the value of the [[ProxyTarget]] internal slot.
15490   Handle<JSReceiver> target(proxy->target(), isolate);
15491   // 6. Let trap be ? GetMethod(handler, "getPrototypeOf").
15492   Handle<Object> trap;
15493   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15494       isolate, trap,
15495       Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
15496       Nothing<bool>());
15497   // 7. If trap is undefined, then return target.[[SetPrototypeOf]]().
15498   if (trap->IsUndefined(isolate)) {
15499     return JSReceiver::SetPrototype(target, value, from_javascript,
15500                                     should_throw);
15501   }
15502   // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, V»)).
15503   Handle<Object> argv[] = {target, value};
15504   Handle<Object> trap_result;
15505   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15506       isolate, trap_result,
15507       Execution::Call(isolate, trap, handler, arraysize(argv), argv),
15508       Nothing<bool>());
15509   bool bool_trap_result = trap_result->BooleanValue();
15510   // 9. If booleanTrapResult is false, return false.
15511   if (!bool_trap_result) {
15512     RETURN_FAILURE(
15513         isolate, should_throw,
15514         NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15515   }
15516   // 10. Let extensibleTarget be ? IsExtensible(target).
15517   Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
15518   if (is_extensible.IsNothing()) return Nothing<bool>();
15519   // 11. If extensibleTarget is true, return true.
15520   if (is_extensible.FromJust()) {
15521     if (bool_trap_result) return Just(true);
15522     RETURN_FAILURE(
15523         isolate, should_throw,
15524         NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15525   }
15526   // 12. Let targetProto be ? target.[[GetPrototypeOf]]().
15527   Handle<Object> target_proto;
15528   ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_proto,
15529                                    JSReceiver::GetPrototype(isolate, target),
15530                                    Nothing<bool>());
15531   // 13. If SameValue(V, targetProto) is false, throw a TypeError exception.
15532   if (bool_trap_result && !value->SameValue(*target_proto)) {
15533     isolate->Throw(*isolate->factory()->NewTypeError(
15534         MessageTemplate::kProxySetPrototypeOfNonExtensible));
15535     return Nothing<bool>();
15536   }
15537   // 14. Return true.
15538   return Just(true);
15539 }
15540 
15541 
SetPrototype(Handle<JSObject> object,Handle<Object> value,bool from_javascript,ShouldThrow should_throw)15542 Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object,
15543                                    Handle<Object> value, bool from_javascript,
15544                                    ShouldThrow should_throw) {
15545   Isolate* isolate = object->GetIsolate();
15546 
15547 #ifdef DEBUG
15548   int size = object->Size();
15549 #endif
15550 
15551   if (from_javascript) {
15552     if (object->IsAccessCheckNeeded() &&
15553         !isolate->MayAccess(handle(isolate->context()), object)) {
15554       isolate->ReportFailedAccessCheck(object);
15555       RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
15556       RETURN_FAILURE(isolate, should_throw,
15557                      NewTypeError(MessageTemplate::kNoAccess));
15558     }
15559   } else {
15560     DCHECK(!object->IsAccessCheckNeeded());
15561   }
15562 
15563   Heap* heap = isolate->heap();
15564   // Silently ignore the change if value is not a JSObject or null.
15565   // SpiderMonkey behaves this way.
15566   if (!value->IsJSReceiver() && !value->IsNull(isolate)) return Just(true);
15567 
15568   bool dictionary_elements_in_chain =
15569       object->map()->DictionaryElementsInPrototypeChainOnly();
15570 
15571   bool all_extensible = object->map()->is_extensible();
15572   Handle<JSObject> real_receiver = object;
15573   if (from_javascript) {
15574     // Find the first object in the chain whose prototype object is not
15575     // hidden.
15576     PrototypeIterator iter(isolate, real_receiver, kStartAtPrototype,
15577                            PrototypeIterator::END_AT_NON_HIDDEN);
15578     while (!iter.IsAtEnd()) {
15579       // Casting to JSObject is fine because hidden prototypes are never
15580       // JSProxies.
15581       real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter);
15582       iter.Advance();
15583       all_extensible = all_extensible && real_receiver->map()->is_extensible();
15584     }
15585   }
15586   Handle<Map> map(real_receiver->map());
15587 
15588   // Nothing to do if prototype is already set.
15589   if (map->prototype() == *value) return Just(true);
15590 
15591   bool immutable_proto = map->is_immutable_proto();
15592   if (immutable_proto) {
15593     RETURN_FAILURE(
15594         isolate, should_throw,
15595         NewTypeError(MessageTemplate::kImmutablePrototypeSet, object));
15596   }
15597 
15598   // From 8.6.2 Object Internal Methods
15599   // ...
15600   // In addition, if [[Extensible]] is false the value of the [[Class]] and
15601   // [[Prototype]] internal properties of the object may not be modified.
15602   // ...
15603   // Implementation specific extensions that modify [[Class]], [[Prototype]]
15604   // or [[Extensible]] must not violate the invariants defined in the preceding
15605   // paragraph.
15606   if (!all_extensible) {
15607     RETURN_FAILURE(isolate, should_throw,
15608                    NewTypeError(MessageTemplate::kNonExtensibleProto, object));
15609   }
15610 
15611   // Before we can set the prototype we need to be sure prototype cycles are
15612   // prevented.  It is sufficient to validate that the receiver is not in the
15613   // new prototype chain.
15614   if (value->IsJSReceiver()) {
15615     for (PrototypeIterator iter(isolate, JSReceiver::cast(*value),
15616                                 kStartAtReceiver);
15617          !iter.IsAtEnd(); iter.Advance()) {
15618       if (iter.GetCurrent<JSReceiver>() == *object) {
15619         // Cycle detected.
15620         RETURN_FAILURE(isolate, should_throw,
15621                        NewTypeError(MessageTemplate::kCyclicProto));
15622       }
15623     }
15624   }
15625 
15626   // Set the new prototype of the object.
15627 
15628   isolate->UpdateArrayProtectorOnSetPrototype(real_receiver);
15629 
15630   PrototypeOptimizationMode mode =
15631       from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE;
15632   Handle<Map> new_map = Map::TransitionToPrototype(map, value, mode);
15633   DCHECK(new_map->prototype() == *value);
15634   JSObject::MigrateToMap(real_receiver, new_map);
15635 
15636   if (from_javascript && !dictionary_elements_in_chain &&
15637       new_map->DictionaryElementsInPrototypeChainOnly()) {
15638     // If the prototype chain didn't previously have element callbacks, then
15639     // KeyedStoreICs need to be cleared to ensure any that involve this
15640     // map go generic.
15641     TypeFeedbackVector::ClearAllKeyedStoreICs(isolate);
15642   }
15643 
15644   heap->ClearInstanceofCache();
15645   DCHECK(size == object->Size());
15646   return Just(true);
15647 }
15648 
15649 // static
SetImmutableProto(Handle<JSObject> object)15650 void JSObject::SetImmutableProto(Handle<JSObject> object) {
15651   DCHECK(!object->IsAccessCheckNeeded());  // Never called from JS
15652   Handle<Map> map(object->map());
15653 
15654   // Nothing to do if prototype is already set.
15655   if (map->is_immutable_proto()) return;
15656 
15657   Handle<Map> new_map = Map::TransitionToImmutableProto(map);
15658   object->set_map(*new_map);
15659 }
15660 
EnsureCanContainElements(Handle<JSObject> object,Arguments * args,uint32_t first_arg,uint32_t arg_count,EnsureElementsMode mode)15661 void JSObject::EnsureCanContainElements(Handle<JSObject> object,
15662                                         Arguments* args,
15663                                         uint32_t first_arg,
15664                                         uint32_t arg_count,
15665                                         EnsureElementsMode mode) {
15666   // Elements in |Arguments| are ordered backwards (because they're on the
15667   // stack), but the method that's called here iterates over them in forward
15668   // direction.
15669   return EnsureCanContainElements(
15670       object, args->arguments() - first_arg - (arg_count - 1), arg_count, mode);
15671 }
15672 
15673 
GetElementsAccessor()15674 ElementsAccessor* JSObject::GetElementsAccessor() {
15675   return ElementsAccessor::ForKind(GetElementsKind());
15676 }
15677 
15678 
ValidateElements(Handle<JSObject> object)15679 void JSObject::ValidateElements(Handle<JSObject> object) {
15680 #ifdef ENABLE_SLOW_DCHECKS
15681   if (FLAG_enable_slow_asserts) {
15682     ElementsAccessor* accessor = object->GetElementsAccessor();
15683     accessor->Validate(object);
15684   }
15685 #endif
15686 }
15687 
15688 
ShouldConvertToSlowElements(JSObject * object,uint32_t capacity,uint32_t index,uint32_t * new_capacity)15689 static bool ShouldConvertToSlowElements(JSObject* object, uint32_t capacity,
15690                                         uint32_t index,
15691                                         uint32_t* new_capacity) {
15692   STATIC_ASSERT(JSObject::kMaxUncheckedOldFastElementsLength <=
15693                 JSObject::kMaxUncheckedFastElementsLength);
15694   if (index < capacity) {
15695     *new_capacity = capacity;
15696     return false;
15697   }
15698   if (index - capacity >= JSObject::kMaxGap) return true;
15699   *new_capacity = JSObject::NewElementsCapacity(index + 1);
15700   DCHECK_LT(index, *new_capacity);
15701   if (*new_capacity <= JSObject::kMaxUncheckedOldFastElementsLength ||
15702       (*new_capacity <= JSObject::kMaxUncheckedFastElementsLength &&
15703        object->GetHeap()->InNewSpace(object))) {
15704     return false;
15705   }
15706   // If the fast-case backing storage takes up roughly three times as
15707   // much space (in machine words) as a dictionary backing storage
15708   // would, the object should have slow elements.
15709   int used_elements = object->GetFastElementsUsage();
15710   int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
15711                         SeededNumberDictionary::kEntrySize;
15712   return 3 * static_cast<uint32_t>(dictionary_size) <= *new_capacity;
15713 }
15714 
15715 
WouldConvertToSlowElements(uint32_t index)15716 bool JSObject::WouldConvertToSlowElements(uint32_t index) {
15717   if (HasFastElements()) {
15718     Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements()));
15719     uint32_t capacity = static_cast<uint32_t>(backing_store->length());
15720     uint32_t new_capacity;
15721     return ShouldConvertToSlowElements(this, capacity, index, &new_capacity);
15722   }
15723   return false;
15724 }
15725 
15726 
BestFittingFastElementsKind(JSObject * object)15727 static ElementsKind BestFittingFastElementsKind(JSObject* object) {
15728   if (object->HasSloppyArgumentsElements()) {
15729     return FAST_SLOPPY_ARGUMENTS_ELEMENTS;
15730   }
15731   if (object->HasStringWrapperElements()) {
15732     return FAST_STRING_WRAPPER_ELEMENTS;
15733   }
15734   DCHECK(object->HasDictionaryElements());
15735   SeededNumberDictionary* dictionary = object->element_dictionary();
15736   ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS;
15737   for (int i = 0; i < dictionary->Capacity(); i++) {
15738     Object* key = dictionary->KeyAt(i);
15739     if (key->IsNumber()) {
15740       Object* value = dictionary->ValueAt(i);
15741       if (!value->IsNumber()) return FAST_HOLEY_ELEMENTS;
15742       if (!value->IsSmi()) {
15743         if (!FLAG_unbox_double_arrays) return FAST_HOLEY_ELEMENTS;
15744         kind = FAST_HOLEY_DOUBLE_ELEMENTS;
15745       }
15746     }
15747   }
15748   return kind;
15749 }
15750 
15751 
ShouldConvertToFastElements(JSObject * object,SeededNumberDictionary * dictionary,uint32_t index,uint32_t * new_capacity)15752 static bool ShouldConvertToFastElements(JSObject* object,
15753                                         SeededNumberDictionary* dictionary,
15754                                         uint32_t index,
15755                                         uint32_t* new_capacity) {
15756   // If properties with non-standard attributes or accessors were added, we
15757   // cannot go back to fast elements.
15758   if (dictionary->requires_slow_elements()) return false;
15759 
15760   // Adding a property with this index will require slow elements.
15761   if (index >= static_cast<uint32_t>(Smi::kMaxValue)) return false;
15762 
15763   if (object->IsJSArray()) {
15764     Object* length = JSArray::cast(object)->length();
15765     if (!length->IsSmi()) return false;
15766     *new_capacity = static_cast<uint32_t>(Smi::cast(length)->value());
15767   } else {
15768     *new_capacity = dictionary->max_number_key() + 1;
15769   }
15770   *new_capacity = Max(index + 1, *new_capacity);
15771 
15772   uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
15773                              SeededNumberDictionary::kEntrySize;
15774 
15775   // Turn fast if the dictionary only saves 50% space.
15776   return 2 * dictionary_size >= *new_capacity;
15777 }
15778 
15779 
15780 // static
AddDataElement(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes)15781 MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> object,
15782                                              uint32_t index,
15783                                              Handle<Object> value,
15784                                              PropertyAttributes attributes) {
15785   MAYBE_RETURN_NULL(
15786       AddDataElement(object, index, value, attributes, THROW_ON_ERROR));
15787   return value;
15788 }
15789 
15790 
15791 // static
AddDataElement(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,ShouldThrow should_throw)15792 Maybe<bool> JSObject::AddDataElement(Handle<JSObject> object, uint32_t index,
15793                                      Handle<Object> value,
15794                                      PropertyAttributes attributes,
15795                                      ShouldThrow should_throw) {
15796   DCHECK(object->map()->is_extensible());
15797 
15798   Isolate* isolate = object->GetIsolate();
15799 
15800   uint32_t old_length = 0;
15801   uint32_t new_capacity = 0;
15802 
15803   if (object->IsJSArray()) {
15804     CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length));
15805   }
15806 
15807   ElementsKind kind = object->GetElementsKind();
15808   FixedArrayBase* elements = object->elements();
15809   ElementsKind dictionary_kind = DICTIONARY_ELEMENTS;
15810   if (IsSloppyArgumentsElements(kind)) {
15811     elements = FixedArrayBase::cast(FixedArray::cast(elements)->get(1));
15812     dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
15813   } else if (IsStringWrapperElementsKind(kind)) {
15814     dictionary_kind = SLOW_STRING_WRAPPER_ELEMENTS;
15815   }
15816 
15817   if (attributes != NONE) {
15818     kind = dictionary_kind;
15819   } else if (elements->IsSeededNumberDictionary()) {
15820     kind = ShouldConvertToFastElements(*object,
15821                                        SeededNumberDictionary::cast(elements),
15822                                        index, &new_capacity)
15823                ? BestFittingFastElementsKind(*object)
15824                : dictionary_kind;  // Overwrite in case of arguments.
15825   } else if (ShouldConvertToSlowElements(
15826                  *object, static_cast<uint32_t>(elements->length()), index,
15827                  &new_capacity)) {
15828     kind = dictionary_kind;
15829   }
15830 
15831   ElementsKind to = value->OptimalElementsKind();
15832   if (IsHoleyElementsKind(kind) || !object->IsJSArray() || index > old_length) {
15833     to = GetHoleyElementsKind(to);
15834     kind = GetHoleyElementsKind(kind);
15835   }
15836   to = GetMoreGeneralElementsKind(kind, to);
15837   ElementsAccessor* accessor = ElementsAccessor::ForKind(to);
15838   accessor->Add(object, index, value, attributes, new_capacity);
15839 
15840   uint32_t new_length = old_length;
15841   Handle<Object> new_length_handle;
15842   if (object->IsJSArray() && index >= old_length) {
15843     new_length = index + 1;
15844     new_length_handle = isolate->factory()->NewNumberFromUint(new_length);
15845     JSArray::cast(*object)->set_length(*new_length_handle);
15846   }
15847 
15848   return Just(true);
15849 }
15850 
15851 
SetLengthWouldNormalize(uint32_t new_length)15852 bool JSArray::SetLengthWouldNormalize(uint32_t new_length) {
15853   if (!HasFastElements()) return false;
15854   uint32_t capacity = static_cast<uint32_t>(elements()->length());
15855   uint32_t new_capacity;
15856   return JSArray::SetLengthWouldNormalize(GetHeap(), new_length) &&
15857          ShouldConvertToSlowElements(this, capacity, new_length - 1,
15858                                      &new_capacity);
15859 }
15860 
15861 
15862 const double AllocationSite::kPretenureRatio = 0.85;
15863 
15864 
ResetPretenureDecision()15865 void AllocationSite::ResetPretenureDecision() {
15866   set_pretenure_decision(kUndecided);
15867   set_memento_found_count(0);
15868   set_memento_create_count(0);
15869 }
15870 
15871 
GetPretenureMode()15872 PretenureFlag AllocationSite::GetPretenureMode() {
15873   PretenureDecision mode = pretenure_decision();
15874   // Zombie objects "decide" to be untenured.
15875   return mode == kTenure ? TENURED : NOT_TENURED;
15876 }
15877 
15878 
IsNestedSite()15879 bool AllocationSite::IsNestedSite() {
15880   DCHECK(FLAG_trace_track_allocation_sites);
15881   Object* current = GetHeap()->allocation_sites_list();
15882   while (current->IsAllocationSite()) {
15883     AllocationSite* current_site = AllocationSite::cast(current);
15884     if (current_site->nested_site() == this) {
15885       return true;
15886     }
15887     current = current_site->weak_next();
15888   }
15889   return false;
15890 }
15891 
15892 template <AllocationSiteUpdateMode update_or_check>
DigestTransitionFeedback(Handle<AllocationSite> site,ElementsKind to_kind)15893 bool AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
15894                                               ElementsKind to_kind) {
15895   Isolate* isolate = site->GetIsolate();
15896   bool result = false;
15897 
15898   if (site->SitePointsToLiteral() && site->transition_info()->IsJSArray()) {
15899     Handle<JSArray> transition_info =
15900         handle(JSArray::cast(site->transition_info()));
15901     ElementsKind kind = transition_info->GetElementsKind();
15902     // if kind is holey ensure that to_kind is as well.
15903     if (IsHoleyElementsKind(kind)) {
15904       to_kind = GetHoleyElementsKind(to_kind);
15905     }
15906     if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
15907       // If the array is huge, it's not likely to be defined in a local
15908       // function, so we shouldn't make new instances of it very often.
15909       uint32_t length = 0;
15910       CHECK(transition_info->length()->ToArrayLength(&length));
15911       if (length <= kMaximumArrayBytesToPretransition) {
15912         if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) {
15913           return true;
15914         }
15915         if (FLAG_trace_track_allocation_sites) {
15916           bool is_nested = site->IsNestedSite();
15917           PrintF(
15918               "AllocationSite: JSArray %p boilerplate %s updated %s->%s\n",
15919               reinterpret_cast<void*>(*site),
15920               is_nested ? "(nested)" : "",
15921               ElementsKindToString(kind),
15922               ElementsKindToString(to_kind));
15923         }
15924         JSObject::TransitionElementsKind(transition_info, to_kind);
15925         site->dependent_code()->DeoptimizeDependentCodeGroup(
15926             isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
15927         result = true;
15928       }
15929     }
15930   } else {
15931     ElementsKind kind = site->GetElementsKind();
15932     // if kind is holey ensure that to_kind is as well.
15933     if (IsHoleyElementsKind(kind)) {
15934       to_kind = GetHoleyElementsKind(to_kind);
15935     }
15936     if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
15937       if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) return true;
15938       if (FLAG_trace_track_allocation_sites) {
15939         PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
15940                reinterpret_cast<void*>(*site),
15941                ElementsKindToString(kind),
15942                ElementsKindToString(to_kind));
15943       }
15944       site->SetElementsKind(to_kind);
15945       site->dependent_code()->DeoptimizeDependentCodeGroup(
15946           isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
15947       result = true;
15948     }
15949   }
15950   return result;
15951 }
15952 
GetMode(ElementsKind from,ElementsKind to)15953 AllocationSiteMode AllocationSite::GetMode(ElementsKind from, ElementsKind to) {
15954   if (IsFastSmiElementsKind(from) &&
15955       IsMoreGeneralElementsKindTransition(from, to)) {
15956     return TRACK_ALLOCATION_SITE;
15957   }
15958 
15959   return DONT_TRACK_ALLOCATION_SITE;
15960 }
15961 
PretenureDecisionName(PretenureDecision decision)15962 const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) {
15963   switch (decision) {
15964     case kUndecided: return "undecided";
15965     case kDontTenure: return "don't tenure";
15966     case kMaybeTenure: return "maybe tenure";
15967     case kTenure: return "tenure";
15968     case kZombie: return "zombie";
15969     default: UNREACHABLE();
15970   }
15971   return NULL;
15972 }
15973 
15974 template <AllocationSiteUpdateMode update_or_check>
UpdateAllocationSite(Handle<JSObject> object,ElementsKind to_kind)15975 bool JSObject::UpdateAllocationSite(Handle<JSObject> object,
15976                                     ElementsKind to_kind) {
15977   if (!object->IsJSArray()) return false;
15978 
15979   Heap* heap = object->GetHeap();
15980   if (!heap->InNewSpace(*object)) return false;
15981 
15982   Handle<AllocationSite> site;
15983   {
15984     DisallowHeapAllocation no_allocation;
15985 
15986     AllocationMemento* memento =
15987         heap->FindAllocationMemento<Heap::kForRuntime>(*object);
15988     if (memento == NULL) return false;
15989 
15990     // Walk through to the Allocation Site
15991     site = handle(memento->GetAllocationSite());
15992   }
15993   return AllocationSite::DigestTransitionFeedback<update_or_check>(site,
15994                                                                    to_kind);
15995 }
15996 
15997 template bool
15998 JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kCheckOnly>(
15999     Handle<JSObject> object, ElementsKind to_kind);
16000 
16001 template bool JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kUpdate>(
16002     Handle<JSObject> object, ElementsKind to_kind);
16003 
TransitionElementsKind(Handle<JSObject> object,ElementsKind to_kind)16004 void JSObject::TransitionElementsKind(Handle<JSObject> object,
16005                                       ElementsKind to_kind) {
16006   ElementsKind from_kind = object->GetElementsKind();
16007 
16008   if (IsFastHoleyElementsKind(from_kind)) {
16009     to_kind = GetHoleyElementsKind(to_kind);
16010   }
16011 
16012   if (from_kind == to_kind) return;
16013 
16014   // This method should never be called for any other case.
16015   DCHECK(IsFastElementsKind(from_kind));
16016   DCHECK(IsFastElementsKind(to_kind));
16017   DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind);
16018 
16019   UpdateAllocationSite(object, to_kind);
16020   if (object->elements() == object->GetHeap()->empty_fixed_array() ||
16021       IsFastDoubleElementsKind(from_kind) ==
16022           IsFastDoubleElementsKind(to_kind)) {
16023     // No change is needed to the elements() buffer, the transition
16024     // only requires a map change.
16025     Handle<Map> new_map = GetElementsTransitionMap(object, to_kind);
16026     MigrateToMap(object, new_map);
16027     if (FLAG_trace_elements_transitions) {
16028       Handle<FixedArrayBase> elms(object->elements());
16029       PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms);
16030     }
16031   } else {
16032     DCHECK((IsFastSmiElementsKind(from_kind) &&
16033             IsFastDoubleElementsKind(to_kind)) ||
16034            (IsFastDoubleElementsKind(from_kind) &&
16035             IsFastObjectElementsKind(to_kind)));
16036     uint32_t c = static_cast<uint32_t>(object->elements()->length());
16037     ElementsAccessor::ForKind(to_kind)->GrowCapacityAndConvert(object, c);
16038   }
16039 }
16040 
16041 
16042 // static
IsValidElementsTransition(ElementsKind from_kind,ElementsKind to_kind)16043 bool Map::IsValidElementsTransition(ElementsKind from_kind,
16044                                     ElementsKind to_kind) {
16045   // Transitions can't go backwards.
16046   if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
16047     return false;
16048   }
16049 
16050   // Transitions from HOLEY -> PACKED are not allowed.
16051   return !IsFastHoleyElementsKind(from_kind) ||
16052       IsFastHoleyElementsKind(to_kind);
16053 }
16054 
16055 
HasReadOnlyLength(Handle<JSArray> array)16056 bool JSArray::HasReadOnlyLength(Handle<JSArray> array) {
16057   Map* map = array->map();
16058   // Fast path: "length" is the first fast property of arrays. Since it's not
16059   // configurable, it's guaranteed to be the first in the descriptor array.
16060   if (!map->is_dictionary_map()) {
16061     DCHECK(map->instance_descriptors()->GetKey(0) ==
16062            array->GetHeap()->length_string());
16063     return map->instance_descriptors()->GetDetails(0).IsReadOnly();
16064   }
16065 
16066   Isolate* isolate = array->GetIsolate();
16067   LookupIterator it(array, isolate->factory()->length_string(), array,
16068                     LookupIterator::OWN_SKIP_INTERCEPTOR);
16069   CHECK_EQ(LookupIterator::ACCESSOR, it.state());
16070   return it.IsReadOnly();
16071 }
16072 
16073 
WouldChangeReadOnlyLength(Handle<JSArray> array,uint32_t index)16074 bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array,
16075                                         uint32_t index) {
16076   uint32_t length = 0;
16077   CHECK(array->length()->ToArrayLength(&length));
16078   if (length <= index) return HasReadOnlyLength(array);
16079   return false;
16080 }
16081 
16082 
16083 template <typename BackingStore>
FastHoleyElementsUsage(JSObject * object,BackingStore * store)16084 static int FastHoleyElementsUsage(JSObject* object, BackingStore* store) {
16085   Isolate* isolate = store->GetIsolate();
16086   int limit = object->IsJSArray()
16087                   ? Smi::cast(JSArray::cast(object)->length())->value()
16088                   : store->length();
16089   int used = 0;
16090   for (int i = 0; i < limit; ++i) {
16091     if (!store->is_the_hole(isolate, i)) ++used;
16092   }
16093   return used;
16094 }
16095 
16096 
GetFastElementsUsage()16097 int JSObject::GetFastElementsUsage() {
16098   FixedArrayBase* store = elements();
16099   switch (GetElementsKind()) {
16100     case FAST_SMI_ELEMENTS:
16101     case FAST_DOUBLE_ELEMENTS:
16102     case FAST_ELEMENTS:
16103       return IsJSArray() ? Smi::cast(JSArray::cast(this)->length())->value()
16104                          : store->length();
16105     case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
16106       store = FixedArray::cast(FixedArray::cast(store)->get(1));
16107     // Fall through.
16108     case FAST_HOLEY_SMI_ELEMENTS:
16109     case FAST_HOLEY_ELEMENTS:
16110     case FAST_STRING_WRAPPER_ELEMENTS:
16111       return FastHoleyElementsUsage(this, FixedArray::cast(store));
16112     case FAST_HOLEY_DOUBLE_ELEMENTS:
16113       if (elements()->length() == 0) return 0;
16114       return FastHoleyElementsUsage(this, FixedDoubleArray::cast(store));
16115 
16116     case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
16117     case SLOW_STRING_WRAPPER_ELEMENTS:
16118     case DICTIONARY_ELEMENTS:
16119     case NO_ELEMENTS:
16120 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                      \
16121     case TYPE##_ELEMENTS:                                                    \
16122 
16123     TYPED_ARRAYS(TYPED_ARRAY_CASE)
16124 #undef TYPED_ARRAY_CASE
16125     UNREACHABLE();
16126   }
16127   return 0;
16128 }
16129 
16130 
16131 // Certain compilers request function template instantiation when they
16132 // see the definition of the other template functions in the
16133 // class. This requires us to have the template functions put
16134 // together, so even though this function belongs in objects-debug.cc,
16135 // we keep it here instead to satisfy certain compilers.
16136 #ifdef OBJECT_PRINT
16137 template <typename Derived, typename Shape, typename Key>
Print(std::ostream & os)16138 void Dictionary<Derived, Shape, Key>::Print(std::ostream& os) {  // NOLINT
16139   Isolate* isolate = this->GetIsolate();
16140   int capacity = this->Capacity();
16141   for (int i = 0; i < capacity; i++) {
16142     Object* k = this->KeyAt(i);
16143     if (this->IsKey(isolate, k)) {
16144       os << "\n   ";
16145       if (k->IsString()) {
16146         String::cast(k)->StringPrint(os);
16147       } else {
16148         os << Brief(k);
16149       }
16150       os << ": " << Brief(this->ValueAt(i)) << " " << this->DetailsAt(i);
16151     }
16152   }
16153 }
16154 template <typename Derived, typename Shape, typename Key>
Print()16155 void Dictionary<Derived, Shape, Key>::Print() {
16156   OFStream os(stdout);
16157   Print(os);
16158 }
16159 #endif
16160 
16161 
16162 template<typename Derived, typename Shape, typename Key>
CopyValuesTo(FixedArray * elements)16163 void Dictionary<Derived, Shape, Key>::CopyValuesTo(FixedArray* elements) {
16164   Isolate* isolate = this->GetIsolate();
16165   int pos = 0;
16166   int capacity = this->Capacity();
16167   DisallowHeapAllocation no_gc;
16168   WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
16169   for (int i = 0; i < capacity; i++) {
16170     Object* k = this->KeyAt(i);
16171     if (this->IsKey(isolate, k)) {
16172       elements->set(pos++, this->ValueAt(i), mode);
16173     }
16174   }
16175   DCHECK(pos == elements->length());
16176 }
16177 
16178 
GetPropertyWithInterceptor(LookupIterator * it,bool * done)16179 MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it,
16180                                                          bool* done) {
16181   DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
16182   return GetPropertyWithInterceptorInternal(it, it->GetInterceptor(), done);
16183 }
16184 
HasRealNamedProperty(Handle<JSObject> object,Handle<Name> name)16185 Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object,
16186                                            Handle<Name> name) {
16187   LookupIterator it = LookupIterator::PropertyOrElement(
16188       name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
16189   return HasProperty(&it);
16190 }
16191 
16192 
HasRealElementProperty(Handle<JSObject> object,uint32_t index)16193 Maybe<bool> JSObject::HasRealElementProperty(Handle<JSObject> object,
16194                                              uint32_t index) {
16195   Isolate* isolate = object->GetIsolate();
16196   LookupIterator it(isolate, object, index, object,
16197                     LookupIterator::OWN_SKIP_INTERCEPTOR);
16198   return HasProperty(&it);
16199 }
16200 
16201 
HasRealNamedCallbackProperty(Handle<JSObject> object,Handle<Name> name)16202 Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
16203                                                    Handle<Name> name) {
16204   LookupIterator it = LookupIterator::PropertyOrElement(
16205       name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
16206   Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
16207   return maybe_result.IsJust() ? Just(it.state() == LookupIterator::ACCESSOR)
16208                                : Nothing<bool>();
16209 }
16210 
GetMaxLengthForNewSpaceAllocation(ElementsKind kind)16211 int FixedArrayBase::GetMaxLengthForNewSpaceAllocation(ElementsKind kind) {
16212   return ((kMaxRegularHeapObjectSize - FixedArrayBase::kHeaderSize) >>
16213           ElementsKindToShiftSize(kind));
16214 }
16215 
SwapPairs(FixedArray * numbers,int i,int j)16216 void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
16217   Object* temp = get(i);
16218   set(i, get(j));
16219   set(j, temp);
16220   if (this != numbers) {
16221     temp = numbers->get(i);
16222     numbers->set(i, Smi::cast(numbers->get(j)));
16223     numbers->set(j, Smi::cast(temp));
16224   }
16225 }
16226 
16227 
InsertionSortPairs(FixedArray * content,FixedArray * numbers,int len)16228 static void InsertionSortPairs(FixedArray* content,
16229                                FixedArray* numbers,
16230                                int len) {
16231   for (int i = 1; i < len; i++) {
16232     int j = i;
16233     while (j > 0 &&
16234            (NumberToUint32(numbers->get(j - 1)) >
16235             NumberToUint32(numbers->get(j)))) {
16236       content->SwapPairs(numbers, j - 1, j);
16237       j--;
16238     }
16239   }
16240 }
16241 
16242 
HeapSortPairs(FixedArray * content,FixedArray * numbers,int len)16243 void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
16244   // In-place heap sort.
16245   DCHECK(content->length() == numbers->length());
16246 
16247   // Bottom-up max-heap construction.
16248   for (int i = 1; i < len; ++i) {
16249     int child_index = i;
16250     while (child_index > 0) {
16251       int parent_index = ((child_index + 1) >> 1) - 1;
16252       uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
16253       uint32_t child_value = NumberToUint32(numbers->get(child_index));
16254       if (parent_value < child_value) {
16255         content->SwapPairs(numbers, parent_index, child_index);
16256       } else {
16257         break;
16258       }
16259       child_index = parent_index;
16260     }
16261   }
16262 
16263   // Extract elements and create sorted array.
16264   for (int i = len - 1; i > 0; --i) {
16265     // Put max element at the back of the array.
16266     content->SwapPairs(numbers, 0, i);
16267     // Sift down the new top element.
16268     int parent_index = 0;
16269     while (true) {
16270       int child_index = ((parent_index + 1) << 1) - 1;
16271       if (child_index >= i) break;
16272       uint32_t child1_value = NumberToUint32(numbers->get(child_index));
16273       uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
16274       uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
16275       if (child_index + 1 >= i || child1_value > child2_value) {
16276         if (parent_value > child1_value) break;
16277         content->SwapPairs(numbers, parent_index, child_index);
16278         parent_index = child_index;
16279       } else {
16280         if (parent_value > child2_value) break;
16281         content->SwapPairs(numbers, parent_index, child_index + 1);
16282         parent_index = child_index + 1;
16283       }
16284     }
16285   }
16286 }
16287 
16288 
16289 // Sort this array and the numbers as pairs wrt. the (distinct) numbers.
SortPairs(FixedArray * numbers,uint32_t len)16290 void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
16291   DCHECK(this->length() == numbers->length());
16292   // For small arrays, simply use insertion sort.
16293   if (len <= 10) {
16294     InsertionSortPairs(this, numbers, len);
16295     return;
16296   }
16297   // Check the range of indices.
16298   uint32_t min_index = NumberToUint32(numbers->get(0));
16299   uint32_t max_index = min_index;
16300   uint32_t i;
16301   for (i = 1; i < len; i++) {
16302     if (NumberToUint32(numbers->get(i)) < min_index) {
16303       min_index = NumberToUint32(numbers->get(i));
16304     } else if (NumberToUint32(numbers->get(i)) > max_index) {
16305       max_index = NumberToUint32(numbers->get(i));
16306     }
16307   }
16308   if (max_index - min_index + 1 == len) {
16309     // Indices form a contiguous range, unless there are duplicates.
16310     // Do an in-place linear time sort assuming distinct numbers, but
16311     // avoid hanging in case they are not.
16312     for (i = 0; i < len; i++) {
16313       uint32_t p;
16314       uint32_t j = 0;
16315       // While the current element at i is not at its correct position p,
16316       // swap the elements at these two positions.
16317       while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
16318              j++ < len) {
16319         SwapPairs(numbers, i, p);
16320       }
16321     }
16322   } else {
16323     HeapSortPairs(this, numbers, len);
16324     return;
16325   }
16326 }
16327 
WasConstructedFromApiFunction()16328 bool JSObject::WasConstructedFromApiFunction() {
16329   auto instance_type = map()->instance_type();
16330   bool is_api_object = instance_type == JS_API_OBJECT_TYPE ||
16331                        instance_type == JS_SPECIAL_API_OBJECT_TYPE;
16332 #ifdef ENABLE_SLOW_DCHECKS
16333   if (FLAG_enable_slow_asserts) {
16334     Object* maybe_constructor = map()->GetConstructor();
16335     if (!maybe_constructor->IsJSFunction()) return false;
16336     JSFunction* constructor = JSFunction::cast(maybe_constructor);
16337     if (constructor->shared()->IsApiFunction()) {
16338       DCHECK(is_api_object);
16339     } else {
16340       DCHECK(!is_api_object);
16341     }
16342   }
16343 #endif
16344   return is_api_object;
16345 }
16346 
ObjectProtoToString(Isolate * isolate,Handle<Object> object)16347 MaybeHandle<String> Object::ObjectProtoToString(Isolate* isolate,
16348                                                 Handle<Object> object) {
16349   if (*object == isolate->heap()->undefined_value()) {
16350     return isolate->factory()->undefined_to_string();
16351   }
16352   if (*object == isolate->heap()->null_value()) {
16353     return isolate->factory()->null_to_string();
16354   }
16355 
16356   Handle<JSReceiver> receiver =
16357       Object::ToObject(isolate, object).ToHandleChecked();
16358 
16359   // For proxies, we must check IsArray() before get(toStringTag) to comply
16360   // with the specification
16361   Maybe<bool> is_array = Nothing<bool>();
16362   InstanceType instance_type = receiver->map()->instance_type();
16363   if (instance_type == JS_PROXY_TYPE) {
16364     is_array = Object::IsArray(receiver);
16365     MAYBE_RETURN(is_array, MaybeHandle<String>());
16366   }
16367 
16368   Handle<String> tag;
16369   Handle<Object> to_string_tag;
16370   ASSIGN_RETURN_ON_EXCEPTION(
16371       isolate, to_string_tag,
16372       JSReceiver::GetProperty(receiver,
16373                               isolate->factory()->to_string_tag_symbol()),
16374       String);
16375   if (to_string_tag->IsString()) {
16376     tag = Handle<String>::cast(to_string_tag);
16377   } else {
16378     switch (instance_type) {
16379       case JS_API_OBJECT_TYPE:
16380       case JS_SPECIAL_API_OBJECT_TYPE:
16381         tag = handle(receiver->class_name(), isolate);
16382         break;
16383       case JS_ARGUMENTS_TYPE:
16384         return isolate->factory()->arguments_to_string();
16385       case JS_ARRAY_TYPE:
16386         return isolate->factory()->array_to_string();
16387       case JS_BOUND_FUNCTION_TYPE:
16388       case JS_FUNCTION_TYPE:
16389         return isolate->factory()->function_to_string();
16390       case JS_ERROR_TYPE:
16391         return isolate->factory()->error_to_string();
16392       case JS_DATE_TYPE:
16393         return isolate->factory()->date_to_string();
16394       case JS_REGEXP_TYPE:
16395         return isolate->factory()->regexp_to_string();
16396       case JS_PROXY_TYPE: {
16397         if (is_array.FromJust()) {
16398           return isolate->factory()->array_to_string();
16399         }
16400         if (receiver->IsCallable()) {
16401           return isolate->factory()->function_to_string();
16402         }
16403         return isolate->factory()->object_to_string();
16404       }
16405       case JS_VALUE_TYPE: {
16406         Object* value = JSValue::cast(*receiver)->value();
16407         if (value->IsString()) {
16408           return isolate->factory()->string_to_string();
16409         }
16410         if (value->IsNumber()) {
16411           return isolate->factory()->number_to_string();
16412         }
16413         if (value->IsBoolean()) {
16414           return isolate->factory()->boolean_to_string();
16415         }
16416         if (value->IsSymbol()) {
16417           return isolate->factory()->object_to_string();
16418         }
16419         UNREACHABLE();
16420         tag = handle(receiver->class_name(), isolate);
16421         break;
16422       }
16423       default:
16424         return isolate->factory()->object_to_string();
16425     }
16426   }
16427 
16428   IncrementalStringBuilder builder(isolate);
16429   builder.AppendCString("[object ");
16430   builder.AppendString(tag);
16431   builder.AppendCharacter(']');
16432   return builder.Finish();
16433 }
16434 
PrivateSymbolToName() const16435 const char* Symbol::PrivateSymbolToName() const {
16436   Heap* heap = GetIsolate()->heap();
16437 #define SYMBOL_CHECK_AND_PRINT(name) \
16438   if (this == heap->name()) return #name;
16439   PRIVATE_SYMBOL_LIST(SYMBOL_CHECK_AND_PRINT)
16440 #undef SYMBOL_CHECK_AND_PRINT
16441   return "UNKNOWN";
16442 }
16443 
16444 
SymbolShortPrint(std::ostream & os)16445 void Symbol::SymbolShortPrint(std::ostream& os) {
16446   os << "<Symbol:";
16447   if (!name()->IsUndefined(GetIsolate())) {
16448     os << " ";
16449     HeapStringAllocator allocator;
16450     StringStream accumulator(&allocator);
16451     String::cast(name())->StringShortPrint(&accumulator, false);
16452     os << accumulator.ToCString().get();
16453   } else {
16454     os << " (" << PrivateSymbolToName() << ")";
16455   }
16456   os << ">";
16457 }
16458 
16459 
16460 // StringSharedKeys are used as keys in the eval cache.
16461 class StringSharedKey : public HashTableKey {
16462  public:
StringSharedKey(Handle<String> source,Handle<SharedFunctionInfo> shared,LanguageMode language_mode,int scope_position)16463   StringSharedKey(Handle<String> source, Handle<SharedFunctionInfo> shared,
16464                   LanguageMode language_mode, int scope_position)
16465       : source_(source),
16466         shared_(shared),
16467         language_mode_(language_mode),
16468         scope_position_(scope_position) {}
16469 
IsMatch(Object * other)16470   bool IsMatch(Object* other) override {
16471     DisallowHeapAllocation no_allocation;
16472     if (!other->IsFixedArray()) {
16473       if (!other->IsNumber()) return false;
16474       uint32_t other_hash = static_cast<uint32_t>(other->Number());
16475       return Hash() == other_hash;
16476     }
16477     FixedArray* other_array = FixedArray::cast(other);
16478     SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
16479     if (shared != *shared_) return false;
16480     int language_unchecked = Smi::cast(other_array->get(2))->value();
16481     DCHECK(is_valid_language_mode(language_unchecked));
16482     LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
16483     if (language_mode != language_mode_) return false;
16484     int scope_position = Smi::cast(other_array->get(3))->value();
16485     if (scope_position != scope_position_) return false;
16486     String* source = String::cast(other_array->get(1));
16487     return source->Equals(*source_);
16488   }
16489 
StringSharedHashHelper(String * source,SharedFunctionInfo * shared,LanguageMode language_mode,int scope_position)16490   static uint32_t StringSharedHashHelper(String* source,
16491                                          SharedFunctionInfo* shared,
16492                                          LanguageMode language_mode,
16493                                          int scope_position) {
16494     uint32_t hash = source->Hash();
16495     if (shared->HasSourceCode()) {
16496       // Instead of using the SharedFunctionInfo pointer in the hash
16497       // code computation, we use a combination of the hash of the
16498       // script source code and the start position of the calling scope.
16499       // We do this to ensure that the cache entries can survive garbage
16500       // collection.
16501       Script* script(Script::cast(shared->script()));
16502       hash ^= String::cast(script->source())->Hash();
16503       STATIC_ASSERT(LANGUAGE_END == 2);
16504       if (is_strict(language_mode)) hash ^= 0x8000;
16505       hash += scope_position;
16506     }
16507     return hash;
16508   }
16509 
Hash()16510   uint32_t Hash() override {
16511     return StringSharedHashHelper(*source_, *shared_, language_mode_,
16512                                   scope_position_);
16513   }
16514 
HashForObject(Object * obj)16515   uint32_t HashForObject(Object* obj) override {
16516     DisallowHeapAllocation no_allocation;
16517     if (obj->IsNumber()) {
16518       return static_cast<uint32_t>(obj->Number());
16519     }
16520     FixedArray* other_array = FixedArray::cast(obj);
16521     SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
16522     String* source = String::cast(other_array->get(1));
16523     int language_unchecked = Smi::cast(other_array->get(2))->value();
16524     DCHECK(is_valid_language_mode(language_unchecked));
16525     LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
16526     int scope_position = Smi::cast(other_array->get(3))->value();
16527     return StringSharedHashHelper(source, shared, language_mode,
16528                                   scope_position);
16529   }
16530 
16531 
AsHandle(Isolate * isolate)16532   Handle<Object> AsHandle(Isolate* isolate) override {
16533     Handle<FixedArray> array = isolate->factory()->NewFixedArray(4);
16534     array->set(0, *shared_);
16535     array->set(1, *source_);
16536     array->set(2, Smi::FromInt(language_mode_));
16537     array->set(3, Smi::FromInt(scope_position_));
16538     return array;
16539   }
16540 
16541  private:
16542   Handle<String> source_;
16543   Handle<SharedFunctionInfo> shared_;
16544   LanguageMode language_mode_;
16545   int scope_position_;
16546 };
16547 
16548 
16549 namespace {
16550 
RegExpFlagsFromString(Handle<String> flags,bool * success)16551 JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags, bool* success) {
16552   JSRegExp::Flags value = JSRegExp::kNone;
16553   int length = flags->length();
16554   // A longer flags string cannot be valid.
16555   if (length > 5) return JSRegExp::Flags(0);
16556   for (int i = 0; i < length; i++) {
16557     JSRegExp::Flag flag = JSRegExp::kNone;
16558     switch (flags->Get(i)) {
16559       case 'g':
16560         flag = JSRegExp::kGlobal;
16561         break;
16562       case 'i':
16563         flag = JSRegExp::kIgnoreCase;
16564         break;
16565       case 'm':
16566         flag = JSRegExp::kMultiline;
16567         break;
16568       case 'u':
16569         flag = JSRegExp::kUnicode;
16570         break;
16571       case 'y':
16572         flag = JSRegExp::kSticky;
16573         break;
16574       default:
16575         return JSRegExp::Flags(0);
16576     }
16577     // Duplicate flag.
16578     if (value & flag) return JSRegExp::Flags(0);
16579     value |= flag;
16580   }
16581   *success = true;
16582   return value;
16583 }
16584 
16585 }  // namespace
16586 
16587 
16588 // static
New(Handle<String> pattern,Flags flags)16589 MaybeHandle<JSRegExp> JSRegExp::New(Handle<String> pattern, Flags flags) {
16590   Isolate* isolate = pattern->GetIsolate();
16591   Handle<JSFunction> constructor = isolate->regexp_function();
16592   Handle<JSRegExp> regexp =
16593       Handle<JSRegExp>::cast(isolate->factory()->NewJSObject(constructor));
16594 
16595   return JSRegExp::Initialize(regexp, pattern, flags);
16596 }
16597 
16598 
16599 // static
Copy(Handle<JSRegExp> regexp)16600 Handle<JSRegExp> JSRegExp::Copy(Handle<JSRegExp> regexp) {
16601   Isolate* const isolate = regexp->GetIsolate();
16602   return Handle<JSRegExp>::cast(isolate->factory()->CopyJSObject(regexp));
16603 }
16604 
16605 
16606 template <typename Char>
CountRequiredEscapes(Handle<String> source)16607 inline int CountRequiredEscapes(Handle<String> source) {
16608   DisallowHeapAllocation no_gc;
16609   int escapes = 0;
16610   Vector<const Char> src = source->GetCharVector<Char>();
16611   for (int i = 0; i < src.length(); i++) {
16612     if (src[i] == '\\') {
16613       // Escape. Skip next character;
16614       i++;
16615     } else if (src[i] == '/') {
16616       // Not escaped forward-slash needs escape.
16617       escapes++;
16618     }
16619   }
16620   return escapes;
16621 }
16622 
16623 
16624 template <typename Char, typename StringType>
WriteEscapedRegExpSource(Handle<String> source,Handle<StringType> result)16625 inline Handle<StringType> WriteEscapedRegExpSource(Handle<String> source,
16626                                                    Handle<StringType> result) {
16627   DisallowHeapAllocation no_gc;
16628   Vector<const Char> src = source->GetCharVector<Char>();
16629   Vector<Char> dst(result->GetChars(), result->length());
16630   int s = 0;
16631   int d = 0;
16632   while (s < src.length()) {
16633     if (src[s] == '\\') {
16634       // Escape. Copy this and next character.
16635       dst[d++] = src[s++];
16636       if (s == src.length()) break;
16637     } else if (src[s] == '/') {
16638       // Not escaped forward-slash needs escape.
16639       dst[d++] = '\\';
16640     }
16641     dst[d++] = src[s++];
16642   }
16643   DCHECK_EQ(result->length(), d);
16644   return result;
16645 }
16646 
16647 
EscapeRegExpSource(Isolate * isolate,Handle<String> source)16648 MaybeHandle<String> EscapeRegExpSource(Isolate* isolate,
16649                                        Handle<String> source) {
16650   String::Flatten(source);
16651   if (source->length() == 0) return isolate->factory()->query_colon_string();
16652   bool one_byte = source->IsOneByteRepresentationUnderneath();
16653   int escapes = one_byte ? CountRequiredEscapes<uint8_t>(source)
16654                          : CountRequiredEscapes<uc16>(source);
16655   if (escapes == 0) return source;
16656   int length = source->length() + escapes;
16657   if (one_byte) {
16658     Handle<SeqOneByteString> result;
16659     ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
16660                                isolate->factory()->NewRawOneByteString(length),
16661                                String);
16662     return WriteEscapedRegExpSource<uint8_t>(source, result);
16663   } else {
16664     Handle<SeqTwoByteString> result;
16665     ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
16666                                isolate->factory()->NewRawTwoByteString(length),
16667                                String);
16668     return WriteEscapedRegExpSource<uc16>(source, result);
16669   }
16670 }
16671 
16672 
16673 // static
Initialize(Handle<JSRegExp> regexp,Handle<String> source,Handle<String> flags_string)16674 MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
16675                                            Handle<String> source,
16676                                            Handle<String> flags_string) {
16677   Isolate* isolate = source->GetIsolate();
16678   bool success = false;
16679   Flags flags = RegExpFlagsFromString(flags_string, &success);
16680   if (!success) {
16681     THROW_NEW_ERROR(
16682         isolate,
16683         NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string),
16684         JSRegExp);
16685   }
16686   return Initialize(regexp, source, flags);
16687 }
16688 
16689 
16690 // static
Initialize(Handle<JSRegExp> regexp,Handle<String> source,Flags flags)16691 MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
16692                                            Handle<String> source, Flags flags) {
16693   Isolate* isolate = regexp->GetIsolate();
16694   Factory* factory = isolate->factory();
16695   // If source is the empty string we set it to "(?:)" instead as
16696   // suggested by ECMA-262, 5th, section 15.10.4.1.
16697   if (source->length() == 0) source = factory->query_colon_string();
16698 
16699   Handle<String> escaped_source;
16700   ASSIGN_RETURN_ON_EXCEPTION(isolate, escaped_source,
16701                              EscapeRegExpSource(isolate, source), JSRegExp);
16702 
16703   RETURN_ON_EXCEPTION(isolate, RegExpImpl::Compile(regexp, source, flags),
16704                       JSRegExp);
16705 
16706   regexp->set_source(*escaped_source);
16707   regexp->set_flags(Smi::FromInt(flags));
16708 
16709   Map* map = regexp->map();
16710   Object* constructor = map->GetConstructor();
16711   if (constructor->IsJSFunction() &&
16712       JSFunction::cast(constructor)->initial_map() == map) {
16713     // If we still have the original map, set in-object properties directly.
16714     regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, Smi::kZero,
16715                                   SKIP_WRITE_BARRIER);
16716   } else {
16717     // Map has changed, so use generic, but slower, method.
16718     RETURN_ON_EXCEPTION(isolate, JSReceiver::SetProperty(
16719                                      regexp, factory->lastIndex_string(),
16720                                      Handle<Smi>(Smi::kZero, isolate), STRICT),
16721                         JSRegExp);
16722   }
16723 
16724   return regexp;
16725 }
16726 
16727 
16728 // RegExpKey carries the source and flags of a regular expression as key.
16729 class RegExpKey : public HashTableKey {
16730  public:
RegExpKey(Handle<String> string,JSRegExp::Flags flags)16731   RegExpKey(Handle<String> string, JSRegExp::Flags flags)
16732       : string_(string), flags_(Smi::FromInt(flags)) {}
16733 
16734   // Rather than storing the key in the hash table, a pointer to the
16735   // stored value is stored where the key should be.  IsMatch then
16736   // compares the search key to the found object, rather than comparing
16737   // a key to a key.
IsMatch(Object * obj)16738   bool IsMatch(Object* obj) override {
16739     FixedArray* val = FixedArray::cast(obj);
16740     return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
16741         && (flags_ == val->get(JSRegExp::kFlagsIndex));
16742   }
16743 
Hash()16744   uint32_t Hash() override { return RegExpHash(*string_, flags_); }
16745 
AsHandle(Isolate * isolate)16746   Handle<Object> AsHandle(Isolate* isolate) override {
16747     // Plain hash maps, which is where regexp keys are used, don't
16748     // use this function.
16749     UNREACHABLE();
16750     return MaybeHandle<Object>().ToHandleChecked();
16751   }
16752 
HashForObject(Object * obj)16753   uint32_t HashForObject(Object* obj) override {
16754     FixedArray* val = FixedArray::cast(obj);
16755     return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
16756                       Smi::cast(val->get(JSRegExp::kFlagsIndex)));
16757   }
16758 
RegExpHash(String * string,Smi * flags)16759   static uint32_t RegExpHash(String* string, Smi* flags) {
16760     return string->Hash() + flags->value();
16761   }
16762 
16763   Handle<String> string_;
16764   Smi* flags_;
16765 };
16766 
16767 
AsHandle(Isolate * isolate)16768 Handle<Object> OneByteStringKey::AsHandle(Isolate* isolate) {
16769   if (hash_field_ == 0) Hash();
16770   return isolate->factory()->NewOneByteInternalizedString(string_, hash_field_);
16771 }
16772 
16773 
AsHandle(Isolate * isolate)16774 Handle<Object> TwoByteStringKey::AsHandle(Isolate* isolate) {
16775   if (hash_field_ == 0) Hash();
16776   return isolate->factory()->NewTwoByteInternalizedString(string_, hash_field_);
16777 }
16778 
16779 
AsHandle(Isolate * isolate)16780 Handle<Object> SeqOneByteSubStringKey::AsHandle(Isolate* isolate) {
16781   if (hash_field_ == 0) Hash();
16782   return isolate->factory()->NewOneByteInternalizedSubString(
16783       string_, from_, length_, hash_field_);
16784 }
16785 
16786 
IsMatch(Object * string)16787 bool SeqOneByteSubStringKey::IsMatch(Object* string) {
16788   Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
16789   return String::cast(string)->IsOneByteEqualTo(chars);
16790 }
16791 
16792 
16793 // InternalizedStringKey carries a string/internalized-string object as key.
16794 class InternalizedStringKey : public HashTableKey {
16795  public:
InternalizedStringKey(Handle<String> string)16796   explicit InternalizedStringKey(Handle<String> string)
16797       : string_(String::Flatten(string)) {}
16798 
IsMatch(Object * string)16799   bool IsMatch(Object* string) override {
16800     return String::cast(string)->Equals(*string_);
16801   }
16802 
Hash()16803   uint32_t Hash() override { return string_->Hash(); }
16804 
HashForObject(Object * other)16805   uint32_t HashForObject(Object* other) override {
16806     return String::cast(other)->Hash();
16807   }
16808 
AsHandle(Isolate * isolate)16809   Handle<Object> AsHandle(Isolate* isolate) override {
16810     // Internalize the string if possible.
16811     MaybeHandle<Map> maybe_map =
16812         isolate->factory()->InternalizedStringMapForString(string_);
16813     Handle<Map> map;
16814     if (maybe_map.ToHandle(&map)) {
16815       string_->set_map_no_write_barrier(*map);
16816       DCHECK(string_->IsInternalizedString());
16817       return string_;
16818     }
16819     // Otherwise allocate a new internalized string.
16820     return isolate->factory()->NewInternalizedStringImpl(
16821         string_, string_->length(), string_->hash_field());
16822   }
16823 
StringHash(Object * obj)16824   static uint32_t StringHash(Object* obj) {
16825     return String::cast(obj)->Hash();
16826   }
16827 
16828   Handle<String> string_;
16829 };
16830 
16831 
16832 template<typename Derived, typename Shape, typename Key>
IteratePrefix(ObjectVisitor * v)16833 void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) {
16834   BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v);
16835 }
16836 
16837 
16838 template<typename Derived, typename Shape, typename Key>
IterateElements(ObjectVisitor * v)16839 void HashTable<Derived, Shape, Key>::IterateElements(ObjectVisitor* v) {
16840   BodyDescriptorBase::IteratePointers(this, kElementsStartOffset,
16841                                       kHeaderSize + length() * kPointerSize, v);
16842 }
16843 
16844 
16845 template<typename Derived, typename Shape, typename Key>
New(Isolate * isolate,int at_least_space_for,MinimumCapacity capacity_option,PretenureFlag pretenure)16846 Handle<Derived> HashTable<Derived, Shape, Key>::New(
16847     Isolate* isolate,
16848     int at_least_space_for,
16849     MinimumCapacity capacity_option,
16850     PretenureFlag pretenure) {
16851   DCHECK(0 <= at_least_space_for);
16852   DCHECK_IMPLIES(capacity_option == USE_CUSTOM_MINIMUM_CAPACITY,
16853                  base::bits::IsPowerOfTwo32(at_least_space_for));
16854 
16855   int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
16856                      ? at_least_space_for
16857                      : ComputeCapacity(at_least_space_for);
16858   if (capacity > HashTable::kMaxCapacity) {
16859     v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
16860   }
16861 
16862   Factory* factory = isolate->factory();
16863   int length = EntryToIndex(capacity);
16864   Handle<FixedArray> array = factory->NewFixedArray(length, pretenure);
16865   array->set_map_no_write_barrier(Shape::GetMap(isolate));
16866   Handle<Derived> table = Handle<Derived>::cast(array);
16867 
16868   table->SetNumberOfElements(0);
16869   table->SetNumberOfDeletedElements(0);
16870   table->SetCapacity(capacity);
16871   return table;
16872 }
16873 
16874 
16875 // Find entry for key otherwise return kNotFound.
16876 template <typename Derived, typename Shape>
FindEntry(Handle<Name> key)16877 int NameDictionaryBase<Derived, Shape>::FindEntry(Handle<Name> key) {
16878   if (!key->IsUniqueName()) {
16879     return DerivedDictionary::FindEntry(key);
16880   }
16881 
16882   // Optimized for unique names. Knowledge of the key type allows:
16883   // 1. Move the check if the key is unique out of the loop.
16884   // 2. Avoid comparing hash codes in unique-to-unique comparison.
16885   // 3. Detect a case when a dictionary key is not unique but the key is.
16886   //    In case of positive result the dictionary key may be replaced by the
16887   //    internalized string with minimal performance penalty. It gives a chance
16888   //    to perform further lookups in code stubs (and significant performance
16889   //    boost a certain style of code).
16890 
16891   // EnsureCapacity will guarantee the hash table is never full.
16892   uint32_t capacity = this->Capacity();
16893   uint32_t entry = Derived::FirstProbe(key->Hash(), capacity);
16894   uint32_t count = 1;
16895   Isolate* isolate = this->GetIsolate();
16896   while (true) {
16897     Object* element = this->KeyAt(entry);
16898     if (element->IsUndefined(isolate)) break;  // Empty entry.
16899     if (*key == element) return entry;
16900     DCHECK(element->IsTheHole(isolate) || element->IsUniqueName());
16901     entry = Derived::NextProbe(entry, count++, capacity);
16902   }
16903   return Derived::kNotFound;
16904 }
16905 
16906 
16907 template<typename Derived, typename Shape, typename Key>
Rehash(Handle<Derived> new_table,Key key)16908 void HashTable<Derived, Shape, Key>::Rehash(
16909     Handle<Derived> new_table,
16910     Key key) {
16911   DCHECK(NumberOfElements() < new_table->Capacity());
16912 
16913   DisallowHeapAllocation no_gc;
16914   WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
16915 
16916   // Copy prefix to new array.
16917   for (int i = kPrefixStartIndex;
16918        i < kPrefixStartIndex + Shape::kPrefixSize;
16919        i++) {
16920     new_table->set(i, get(i), mode);
16921   }
16922 
16923   // Rehash the elements.
16924   int capacity = this->Capacity();
16925   Heap* heap = new_table->GetHeap();
16926   Object* the_hole = heap->the_hole_value();
16927   Object* undefined = heap->undefined_value();
16928   for (int i = 0; i < capacity; i++) {
16929     uint32_t from_index = EntryToIndex(i);
16930     Object* k = this->get(from_index);
16931     if (k != the_hole && k != undefined) {
16932       uint32_t hash = this->HashForObject(key, k);
16933       uint32_t insertion_index =
16934           EntryToIndex(new_table->FindInsertionEntry(hash));
16935       for (int j = 0; j < Shape::kEntrySize; j++) {
16936         new_table->set(insertion_index + j, get(from_index + j), mode);
16937       }
16938     }
16939   }
16940   new_table->SetNumberOfElements(NumberOfElements());
16941   new_table->SetNumberOfDeletedElements(0);
16942 }
16943 
16944 
16945 template<typename Derived, typename Shape, typename Key>
EntryForProbe(Key key,Object * k,int probe,uint32_t expected)16946 uint32_t HashTable<Derived, Shape, Key>::EntryForProbe(
16947     Key key,
16948     Object* k,
16949     int probe,
16950     uint32_t expected) {
16951   uint32_t hash = this->HashForObject(key, k);
16952   uint32_t capacity = this->Capacity();
16953   uint32_t entry = FirstProbe(hash, capacity);
16954   for (int i = 1; i < probe; i++) {
16955     if (entry == expected) return expected;
16956     entry = NextProbe(entry, i, capacity);
16957   }
16958   return entry;
16959 }
16960 
16961 
16962 template<typename Derived, typename Shape, typename Key>
Swap(uint32_t entry1,uint32_t entry2,WriteBarrierMode mode)16963 void HashTable<Derived, Shape, Key>::Swap(uint32_t entry1,
16964                                           uint32_t entry2,
16965                                           WriteBarrierMode mode) {
16966   int index1 = EntryToIndex(entry1);
16967   int index2 = EntryToIndex(entry2);
16968   Object* temp[Shape::kEntrySize];
16969   for (int j = 0; j < Shape::kEntrySize; j++) {
16970     temp[j] = get(index1 + j);
16971   }
16972   for (int j = 0; j < Shape::kEntrySize; j++) {
16973     set(index1 + j, get(index2 + j), mode);
16974   }
16975   for (int j = 0; j < Shape::kEntrySize; j++) {
16976     set(index2 + j, temp[j], mode);
16977   }
16978 }
16979 
16980 
16981 template<typename Derived, typename Shape, typename Key>
Rehash(Key key)16982 void HashTable<Derived, Shape, Key>::Rehash(Key key) {
16983   DisallowHeapAllocation no_gc;
16984   WriteBarrierMode mode = GetWriteBarrierMode(no_gc);
16985   Isolate* isolate = GetIsolate();
16986   uint32_t capacity = Capacity();
16987   bool done = false;
16988   for (int probe = 1; !done; probe++) {
16989     // All elements at entries given by one of the first _probe_ probes
16990     // are placed correctly. Other elements might need to be moved.
16991     done = true;
16992     for (uint32_t current = 0; current < capacity; current++) {
16993       Object* current_key = KeyAt(current);
16994       if (IsKey(isolate, current_key)) {
16995         uint32_t target = EntryForProbe(key, current_key, probe, current);
16996         if (current == target) continue;
16997         Object* target_key = KeyAt(target);
16998         if (!IsKey(target_key) ||
16999             EntryForProbe(key, target_key, probe, target) != target) {
17000           // Put the current element into the correct position.
17001           Swap(current, target, mode);
17002           // The other element will be processed on the next iteration.
17003           current--;
17004         } else {
17005           // The place for the current element is occupied. Leave the element
17006           // for the next probe.
17007           done = false;
17008         }
17009       }
17010     }
17011   }
17012   // Wipe deleted entries.
17013   Object* the_hole = isolate->heap()->the_hole_value();
17014   Object* undefined = isolate->heap()->undefined_value();
17015   for (uint32_t current = 0; current < capacity; current++) {
17016     if (KeyAt(current) == the_hole) {
17017       set(EntryToIndex(current) + Derived::kEntryKeyIndex, undefined);
17018     }
17019   }
17020   SetNumberOfDeletedElements(0);
17021 }
17022 
17023 
17024 template<typename Derived, typename Shape, typename Key>
EnsureCapacity(Handle<Derived> table,int n,Key key,PretenureFlag pretenure)17025 Handle<Derived> HashTable<Derived, Shape, Key>::EnsureCapacity(
17026     Handle<Derived> table,
17027     int n,
17028     Key key,
17029     PretenureFlag pretenure) {
17030   Isolate* isolate = table->GetIsolate();
17031   int capacity = table->Capacity();
17032   int nof = table->NumberOfElements() + n;
17033 
17034   if (table->HasSufficientCapacityToAdd(n)) return table;
17035 
17036   const int kMinCapacityForPretenure = 256;
17037   bool should_pretenure = pretenure == TENURED ||
17038       ((capacity > kMinCapacityForPretenure) &&
17039           !isolate->heap()->InNewSpace(*table));
17040   Handle<Derived> new_table = HashTable::New(
17041       isolate,
17042       nof * 2,
17043       USE_DEFAULT_MINIMUM_CAPACITY,
17044       should_pretenure ? TENURED : NOT_TENURED);
17045 
17046   table->Rehash(new_table, key);
17047   return new_table;
17048 }
17049 
17050 template <typename Derived, typename Shape, typename Key>
HasSufficientCapacityToAdd(int number_of_additional_elements)17051 bool HashTable<Derived, Shape, Key>::HasSufficientCapacityToAdd(
17052     int number_of_additional_elements) {
17053   int capacity = Capacity();
17054   int nof = NumberOfElements() + number_of_additional_elements;
17055   int nod = NumberOfDeletedElements();
17056   // Return true if:
17057   //   50% is still free after adding number_of_additional_elements elements and
17058   //   at most 50% of the free elements are deleted elements.
17059   if ((nof < capacity) && ((nod <= (capacity - nof) >> 1))) {
17060     int needed_free = nof >> 1;
17061     if (nof + needed_free <= capacity) return true;
17062   }
17063   return false;
17064 }
17065 
17066 
17067 template<typename Derived, typename Shape, typename Key>
Shrink(Handle<Derived> table,Key key)17068 Handle<Derived> HashTable<Derived, Shape, Key>::Shrink(Handle<Derived> table,
17069                                                        Key key) {
17070   int capacity = table->Capacity();
17071   int nof = table->NumberOfElements();
17072 
17073   // Shrink to fit the number of elements if only a quarter of the
17074   // capacity is filled with elements.
17075   if (nof > (capacity >> 2)) return table;
17076   // Allocate a new dictionary with room for at least the current
17077   // number of elements. The allocation method will make sure that
17078   // there is extra room in the dictionary for additions. Don't go
17079   // lower than room for 16 elements.
17080   int at_least_room_for = nof;
17081   if (at_least_room_for < 16) return table;
17082 
17083   Isolate* isolate = table->GetIsolate();
17084   const int kMinCapacityForPretenure = 256;
17085   bool pretenure =
17086       (at_least_room_for > kMinCapacityForPretenure) &&
17087       !isolate->heap()->InNewSpace(*table);
17088   Handle<Derived> new_table = HashTable::New(
17089       isolate,
17090       at_least_room_for,
17091       USE_DEFAULT_MINIMUM_CAPACITY,
17092       pretenure ? TENURED : NOT_TENURED);
17093 
17094   table->Rehash(new_table, key);
17095   return new_table;
17096 }
17097 
17098 
17099 template<typename Derived, typename Shape, typename Key>
FindInsertionEntry(uint32_t hash)17100 uint32_t HashTable<Derived, Shape, Key>::FindInsertionEntry(uint32_t hash) {
17101   uint32_t capacity = Capacity();
17102   uint32_t entry = FirstProbe(hash, capacity);
17103   uint32_t count = 1;
17104   // EnsureCapacity will guarantee the hash table is never full.
17105   Isolate* isolate = GetIsolate();
17106   while (true) {
17107     Object* element = KeyAt(entry);
17108     if (!IsKey(isolate, element)) break;
17109     entry = NextProbe(entry, count++, capacity);
17110   }
17111   return entry;
17112 }
17113 
17114 
17115 // Force instantiation of template instances class.
17116 // Please note this list is compiler dependent.
17117 
17118 template class HashTable<StringTable, StringTableShape, HashTableKey*>;
17119 
17120 template class HashTable<CompilationCacheTable,
17121                          CompilationCacheShape,
17122                          HashTableKey*>;
17123 
17124 template class HashTable<ObjectHashTable,
17125                          ObjectHashTableShape,
17126                          Handle<Object> >;
17127 
17128 template class HashTable<WeakHashTable, WeakHashTableShape<2>, Handle<Object> >;
17129 
17130 template class Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >;
17131 
17132 template class Dictionary<GlobalDictionary, GlobalDictionaryShape,
17133                           Handle<Name> >;
17134 
17135 template class Dictionary<SeededNumberDictionary,
17136                           SeededNumberDictionaryShape,
17137                           uint32_t>;
17138 
17139 template class Dictionary<UnseededNumberDictionary,
17140                           UnseededNumberDictionaryShape,
17141                           uint32_t>;
17142 
17143 template Handle<SeededNumberDictionary>
17144 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::New(
17145     Isolate*, int at_least_space_for, PretenureFlag pretenure,
17146     MinimumCapacity capacity_option);
17147 
17148 template Handle<UnseededNumberDictionary>
17149 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
17150            uint32_t>::New(Isolate*, int at_least_space_for,
17151                           PretenureFlag pretenure,
17152                           MinimumCapacity capacity_option);
17153 
17154 template Handle<NameDictionary>
17155 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::New(
17156     Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
17157 
17158 template Handle<GlobalDictionary>
17159 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::New(
17160     Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
17161 
17162 template Handle<SeededNumberDictionary>
17163 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
17164     AtPut(Handle<SeededNumberDictionary>, uint32_t, Handle<Object>);
17165 
17166 template Handle<UnseededNumberDictionary>
17167 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
17168     AtPut(Handle<UnseededNumberDictionary>, uint32_t, Handle<Object>);
17169 
17170 template Object*
17171 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
17172     SlowReverseLookup(Object* value);
17173 
17174 template Object*
17175 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
17176     SlowReverseLookup(Object* value);
17177 
17178 template Handle<Object>
17179 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::DeleteProperty(
17180     Handle<NameDictionary>, int);
17181 
17182 template Handle<Object>
17183 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
17184            uint32_t>::DeleteProperty(Handle<SeededNumberDictionary>, int);
17185 
17186 template Handle<Object>
17187 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
17188            uint32_t>::DeleteProperty(Handle<UnseededNumberDictionary>, int);
17189 
17190 template Handle<NameDictionary>
17191 HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
17192     New(Isolate*, int, MinimumCapacity, PretenureFlag);
17193 
17194 template Handle<ObjectHashSet> HashTable<ObjectHashSet, ObjectHashSetShape,
17195                                          Handle<Object>>::New(Isolate*, int n,
17196                                                               MinimumCapacity,
17197                                                               PretenureFlag);
17198 
17199 template Handle<NameDictionary>
17200 HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
17201     Shrink(Handle<NameDictionary>, Handle<Name>);
17202 
17203 template Handle<SeededNumberDictionary>
17204 HashTable<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
17205     Shrink(Handle<SeededNumberDictionary>, uint32_t);
17206 
17207 template Handle<UnseededNumberDictionary>
17208     HashTable<UnseededNumberDictionary, UnseededNumberDictionaryShape,
17209               uint32_t>::Shrink(Handle<UnseededNumberDictionary>, uint32_t);
17210 
17211 template Handle<NameDictionary>
17212 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::Add(
17213     Handle<NameDictionary>, Handle<Name>, Handle<Object>, PropertyDetails,
17214     int*);
17215 
17216 template Handle<GlobalDictionary>
17217 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::Add(
17218     Handle<GlobalDictionary>, Handle<Name>, Handle<Object>, PropertyDetails,
17219     int*);
17220 
17221 template Handle<FixedArray> Dictionary<
17222     NameDictionary, NameDictionaryShape,
17223     Handle<Name> >::BuildIterationIndicesArray(Handle<NameDictionary>);
17224 
17225 template Handle<FixedArray> Dictionary<
17226     NameDictionary, NameDictionaryShape,
17227     Handle<Name> >::GenerateNewEnumerationIndices(Handle<NameDictionary>);
17228 
17229 template Handle<SeededNumberDictionary>
17230 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::Add(
17231     Handle<SeededNumberDictionary>, uint32_t, Handle<Object>, PropertyDetails,
17232     int*);
17233 
17234 template Handle<UnseededNumberDictionary>
17235 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
17236            uint32_t>::Add(Handle<UnseededNumberDictionary>, uint32_t,
17237                           Handle<Object>, PropertyDetails, int*);
17238 
17239 template Handle<SeededNumberDictionary>
17240 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
17241     EnsureCapacity(Handle<SeededNumberDictionary>, int, uint32_t);
17242 
17243 template Handle<UnseededNumberDictionary>
17244 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
17245     EnsureCapacity(Handle<UnseededNumberDictionary>, int, uint32_t);
17246 
17247 template void Dictionary<NameDictionary, NameDictionaryShape,
17248                          Handle<Name> >::SetRequiresCopyOnCapacityChange();
17249 
17250 template Handle<NameDictionary>
17251 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
17252     EnsureCapacity(Handle<NameDictionary>, int, Handle<Name>);
17253 
17254 template int HashTable<SeededNumberDictionary, SeededNumberDictionaryShape,
17255                        uint32_t>::FindEntry(uint32_t);
17256 
17257 template int NameDictionaryBase<NameDictionary, NameDictionaryShape>::FindEntry(
17258     Handle<Name>);
17259 
17260 template int Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
17261     NumberOfElementsFilterAttributes(PropertyFilter filter);
17262 
17263 template int Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::
17264     NumberOfElementsFilterAttributes(PropertyFilter filter);
17265 
17266 template void
17267 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
17268     CopyEnumKeysTo(Handle<Dictionary<GlobalDictionary, GlobalDictionaryShape,
17269                                      Handle<Name>>>
17270                        dictionary,
17271                    Handle<FixedArray> storage, KeyCollectionMode mode,
17272                    KeyAccumulator* accumulator);
17273 
17274 template void
17275 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::CopyEnumKeysTo(
17276     Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>>
17277         dictionary,
17278     Handle<FixedArray> storage, KeyCollectionMode mode,
17279     KeyAccumulator* accumulator);
17280 
17281 template void
17282 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
17283     CollectKeysTo(Handle<Dictionary<GlobalDictionary, GlobalDictionaryShape,
17284                                     Handle<Name>>>
17285                       dictionary,
17286                   KeyAccumulator* keys);
17287 
17288 template void
17289 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::CollectKeysTo(
17290     Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>>
17291         dictionary,
17292     KeyAccumulator* keys);
17293 
PrepareSlowElementsForSort(Handle<JSObject> object,uint32_t limit)17294 Handle<Object> JSObject::PrepareSlowElementsForSort(
17295     Handle<JSObject> object, uint32_t limit) {
17296   DCHECK(object->HasDictionaryElements());
17297   Isolate* isolate = object->GetIsolate();
17298   // Must stay in dictionary mode, either because of requires_slow_elements,
17299   // or because we are not going to sort (and therefore compact) all of the
17300   // elements.
17301   Handle<SeededNumberDictionary> dict(object->element_dictionary(), isolate);
17302   Handle<SeededNumberDictionary> new_dict =
17303       SeededNumberDictionary::New(isolate, dict->NumberOfElements());
17304 
17305   uint32_t pos = 0;
17306   uint32_t undefs = 0;
17307   int capacity = dict->Capacity();
17308   Handle<Smi> bailout(Smi::FromInt(-1), isolate);
17309   // Entry to the new dictionary does not cause it to grow, as we have
17310   // allocated one that is large enough for all entries.
17311   DisallowHeapAllocation no_gc;
17312   for (int i = 0; i < capacity; i++) {
17313     Object* k = dict->KeyAt(i);
17314     if (!dict->IsKey(isolate, k)) continue;
17315 
17316     DCHECK(k->IsNumber());
17317     DCHECK(!k->IsSmi() || Smi::cast(k)->value() >= 0);
17318     DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
17319     DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
17320 
17321     HandleScope scope(isolate);
17322     Handle<Object> value(dict->ValueAt(i), isolate);
17323     PropertyDetails details = dict->DetailsAt(i);
17324     if (details.type() == ACCESSOR_CONSTANT || details.IsReadOnly()) {
17325       // Bail out and do the sorting of undefineds and array holes in JS.
17326       // Also bail out if the element is not supposed to be moved.
17327       return bailout;
17328     }
17329 
17330     uint32_t key = NumberToUint32(k);
17331     if (key < limit) {
17332       if (value->IsUndefined(isolate)) {
17333         undefs++;
17334       } else if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
17335         // Adding an entry with the key beyond smi-range requires
17336         // allocation. Bailout.
17337         return bailout;
17338       } else {
17339         Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
17340             new_dict, pos, value, details, object->map()->is_prototype_map());
17341         DCHECK(result.is_identical_to(new_dict));
17342         USE(result);
17343         pos++;
17344       }
17345     } else if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
17346       // Adding an entry with the key beyond smi-range requires
17347       // allocation. Bailout.
17348       return bailout;
17349     } else {
17350       Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
17351           new_dict, key, value, details, object->map()->is_prototype_map());
17352       DCHECK(result.is_identical_to(new_dict));
17353       USE(result);
17354     }
17355   }
17356 
17357   uint32_t result = pos;
17358   PropertyDetails no_details = PropertyDetails::Empty();
17359   while (undefs > 0) {
17360     if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
17361       // Adding an entry with the key beyond smi-range requires
17362       // allocation. Bailout.
17363       return bailout;
17364     }
17365     HandleScope scope(isolate);
17366     Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
17367         new_dict, pos, isolate->factory()->undefined_value(), no_details,
17368         object->map()->is_prototype_map());
17369     DCHECK(result.is_identical_to(new_dict));
17370     USE(result);
17371     pos++;
17372     undefs--;
17373   }
17374 
17375   object->set_elements(*new_dict);
17376 
17377   AllowHeapAllocation allocate_return_value;
17378   return isolate->factory()->NewNumberFromUint(result);
17379 }
17380 
17381 
17382 // Collects all defined (non-hole) and non-undefined (array) elements at
17383 // the start of the elements array.
17384 // If the object is in dictionary mode, it is converted to fast elements
17385 // mode.
PrepareElementsForSort(Handle<JSObject> object,uint32_t limit)17386 Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object,
17387                                                 uint32_t limit) {
17388   Isolate* isolate = object->GetIsolate();
17389   if (object->HasSloppyArgumentsElements()) {
17390     return handle(Smi::FromInt(-1), isolate);
17391   }
17392 
17393   if (object->HasStringWrapperElements()) {
17394     int len = String::cast(Handle<JSValue>::cast(object)->value())->length();
17395     return handle(Smi::FromInt(len), isolate);
17396   }
17397 
17398   if (object->HasDictionaryElements()) {
17399     // Convert to fast elements containing only the existing properties.
17400     // Ordering is irrelevant, since we are going to sort anyway.
17401     Handle<SeededNumberDictionary> dict(object->element_dictionary());
17402     if (object->IsJSArray() || dict->requires_slow_elements() ||
17403         dict->max_number_key() >= limit) {
17404       return JSObject::PrepareSlowElementsForSort(object, limit);
17405     }
17406     // Convert to fast elements.
17407 
17408     Handle<Map> new_map =
17409         JSObject::GetElementsTransitionMap(object, FAST_HOLEY_ELEMENTS);
17410 
17411     PretenureFlag tenure = isolate->heap()->InNewSpace(*object) ?
17412         NOT_TENURED: TENURED;
17413     Handle<FixedArray> fast_elements =
17414         isolate->factory()->NewFixedArray(dict->NumberOfElements(), tenure);
17415     dict->CopyValuesTo(*fast_elements);
17416     JSObject::ValidateElements(object);
17417 
17418     JSObject::SetMapAndElements(object, new_map, fast_elements);
17419   } else if (object->HasFixedTypedArrayElements()) {
17420     // Typed arrays cannot have holes or undefined elements.
17421     return handle(Smi::FromInt(
17422         FixedArrayBase::cast(object->elements())->length()), isolate);
17423   } else if (!object->HasFastDoubleElements()) {
17424     EnsureWritableFastElements(object);
17425   }
17426   DCHECK(object->HasFastSmiOrObjectElements() ||
17427          object->HasFastDoubleElements());
17428 
17429   // Collect holes at the end, undefined before that and the rest at the
17430   // start, and return the number of non-hole, non-undefined values.
17431 
17432   Handle<FixedArrayBase> elements_base(object->elements());
17433   uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
17434   if (limit > elements_length) {
17435     limit = elements_length;
17436   }
17437   if (limit == 0) {
17438     return handle(Smi::kZero, isolate);
17439   }
17440 
17441   uint32_t result = 0;
17442   if (elements_base->map() == isolate->heap()->fixed_double_array_map()) {
17443     FixedDoubleArray* elements = FixedDoubleArray::cast(*elements_base);
17444     // Split elements into defined and the_hole, in that order.
17445     unsigned int holes = limit;
17446     // Assume most arrays contain no holes and undefined values, so minimize the
17447     // number of stores of non-undefined, non-the-hole values.
17448     for (unsigned int i = 0; i < holes; i++) {
17449       if (elements->is_the_hole(i)) {
17450         holes--;
17451       } else {
17452         continue;
17453       }
17454       // Position i needs to be filled.
17455       while (holes > i) {
17456         if (elements->is_the_hole(holes)) {
17457           holes--;
17458         } else {
17459           elements->set(i, elements->get_scalar(holes));
17460           break;
17461         }
17462       }
17463     }
17464     result = holes;
17465     while (holes < limit) {
17466       elements->set_the_hole(holes);
17467       holes++;
17468     }
17469   } else {
17470     FixedArray* elements = FixedArray::cast(*elements_base);
17471     DisallowHeapAllocation no_gc;
17472 
17473     // Split elements into defined, undefined and the_hole, in that order.  Only
17474     // count locations for undefined and the hole, and fill them afterwards.
17475     WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_gc);
17476     unsigned int undefs = limit;
17477     unsigned int holes = limit;
17478     // Assume most arrays contain no holes and undefined values, so minimize the
17479     // number of stores of non-undefined, non-the-hole values.
17480     for (unsigned int i = 0; i < undefs; i++) {
17481       Object* current = elements->get(i);
17482       if (current->IsTheHole(isolate)) {
17483         holes--;
17484         undefs--;
17485       } else if (current->IsUndefined(isolate)) {
17486         undefs--;
17487       } else {
17488         continue;
17489       }
17490       // Position i needs to be filled.
17491       while (undefs > i) {
17492         current = elements->get(undefs);
17493         if (current->IsTheHole(isolate)) {
17494           holes--;
17495           undefs--;
17496         } else if (current->IsUndefined(isolate)) {
17497           undefs--;
17498         } else {
17499           elements->set(i, current, write_barrier);
17500           break;
17501         }
17502       }
17503     }
17504     result = undefs;
17505     while (undefs < holes) {
17506       elements->set_undefined(undefs);
17507       undefs++;
17508     }
17509     while (holes < limit) {
17510       elements->set_the_hole(holes);
17511       holes++;
17512     }
17513   }
17514 
17515   return isolate->factory()->NewNumberFromUint(result);
17516 }
17517 
17518 
type()17519 ExternalArrayType JSTypedArray::type() {
17520   switch (elements()->map()->instance_type()) {
17521 #define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype, size)            \
17522     case FIXED_##TYPE##_ARRAY_TYPE:                                           \
17523       return kExternal##Type##Array;
17524 
17525     TYPED_ARRAYS(INSTANCE_TYPE_TO_ARRAY_TYPE)
17526 #undef INSTANCE_TYPE_TO_ARRAY_TYPE
17527 
17528     default:
17529       UNREACHABLE();
17530       return static_cast<ExternalArrayType>(-1);
17531   }
17532 }
17533 
17534 
element_size()17535 size_t JSTypedArray::element_size() {
17536   switch (elements()->map()->instance_type()) {
17537 #define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype, size) \
17538   case FIXED_##TYPE##_ARRAY_TYPE:                                    \
17539     return size;
17540 
17541     TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE)
17542 #undef INSTANCE_TYPE_TO_ELEMENT_SIZE
17543 
17544     default:
17545       UNREACHABLE();
17546       return 0;
17547   }
17548 }
17549 
17550 
InvalidatePropertyCell(Handle<JSGlobalObject> global,Handle<Name> name)17551 void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global,
17552                                             Handle<Name> name) {
17553   DCHECK(!global->HasFastProperties());
17554   auto dictionary = handle(global->global_dictionary());
17555   int entry = dictionary->FindEntry(name);
17556   if (entry == GlobalDictionary::kNotFound) return;
17557   PropertyCell::InvalidateEntry(dictionary, entry);
17558 }
17559 
EnsureEmptyPropertyCell(Handle<JSGlobalObject> global,Handle<Name> name,PropertyCellType cell_type,int * entry_out)17560 Handle<PropertyCell> JSGlobalObject::EnsureEmptyPropertyCell(
17561     Handle<JSGlobalObject> global, Handle<Name> name,
17562     PropertyCellType cell_type, int* entry_out) {
17563   Isolate* isolate = global->GetIsolate();
17564   DCHECK(!global->HasFastProperties());
17565   Handle<GlobalDictionary> dictionary(global->global_dictionary(), isolate);
17566   int entry = dictionary->FindEntry(name);
17567   Handle<PropertyCell> cell;
17568   if (entry != GlobalDictionary::kNotFound) {
17569     if (entry_out) *entry_out = entry;
17570     // This call should be idempotent.
17571     DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
17572     cell = handle(PropertyCell::cast(dictionary->ValueAt(entry)));
17573     PropertyCellType original_cell_type = cell->property_details().cell_type();
17574     DCHECK(original_cell_type == PropertyCellType::kInvalidated ||
17575            original_cell_type == PropertyCellType::kUninitialized);
17576     DCHECK(cell->value()->IsTheHole(isolate));
17577     if (original_cell_type == PropertyCellType::kInvalidated) {
17578       cell = PropertyCell::InvalidateEntry(dictionary, entry);
17579     }
17580     PropertyDetails details(NONE, DATA, 0, cell_type);
17581     cell->set_property_details(details);
17582     return cell;
17583   }
17584   cell = isolate->factory()->NewPropertyCell();
17585   PropertyDetails details(NONE, DATA, 0, cell_type);
17586   dictionary =
17587       GlobalDictionary::Add(dictionary, name, cell, details, entry_out);
17588   // {*entry_out} is initialized inside GlobalDictionary::Add().
17589   global->set_properties(*dictionary);
17590   return cell;
17591 }
17592 
17593 
17594 // This class is used for looking up two character strings in the string table.
17595 // If we don't have a hit we don't want to waste much time so we unroll the
17596 // string hash calculation loop here for speed.  Doesn't work if the two
17597 // characters form a decimal integer, since such strings have a different hash
17598 // algorithm.
17599 class TwoCharHashTableKey : public HashTableKey {
17600  public:
TwoCharHashTableKey(uint16_t c1,uint16_t c2,uint32_t seed)17601   TwoCharHashTableKey(uint16_t c1, uint16_t c2, uint32_t seed)
17602     : c1_(c1), c2_(c2) {
17603     // Char 1.
17604     uint32_t hash = seed;
17605     hash += c1;
17606     hash += hash << 10;
17607     hash ^= hash >> 6;
17608     // Char 2.
17609     hash += c2;
17610     hash += hash << 10;
17611     hash ^= hash >> 6;
17612     // GetHash.
17613     hash += hash << 3;
17614     hash ^= hash >> 11;
17615     hash += hash << 15;
17616     if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash;
17617     hash_ = hash;
17618 #ifdef DEBUG
17619     // If this assert fails then we failed to reproduce the two-character
17620     // version of the string hashing algorithm above.  One reason could be
17621     // that we were passed two digits as characters, since the hash
17622     // algorithm is different in that case.
17623     uint16_t chars[2] = {c1, c2};
17624     uint32_t check_hash = StringHasher::HashSequentialString(chars, 2, seed);
17625     hash = (hash << String::kHashShift) | String::kIsNotArrayIndexMask;
17626     DCHECK_EQ(static_cast<int32_t>(hash), static_cast<int32_t>(check_hash));
17627 #endif
17628   }
17629 
IsMatch(Object * o)17630   bool IsMatch(Object* o) override {
17631     if (!o->IsString()) return false;
17632     String* other = String::cast(o);
17633     if (other->length() != 2) return false;
17634     if (other->Get(0) != c1_) return false;
17635     return other->Get(1) == c2_;
17636   }
17637 
Hash()17638   uint32_t Hash() override { return hash_; }
HashForObject(Object * key)17639   uint32_t HashForObject(Object* key) override {
17640     if (!key->IsString()) return 0;
17641     return String::cast(key)->Hash();
17642   }
17643 
AsHandle(Isolate * isolate)17644   Handle<Object> AsHandle(Isolate* isolate) override {
17645     // The TwoCharHashTableKey is only used for looking in the string
17646     // table, not for adding to it.
17647     UNREACHABLE();
17648     return MaybeHandle<Object>().ToHandleChecked();
17649   }
17650 
17651  private:
17652   uint16_t c1_;
17653   uint16_t c2_;
17654   uint32_t hash_;
17655 };
17656 
17657 
InternalizeStringIfExists(Isolate * isolate,Handle<String> string)17658 MaybeHandle<String> StringTable::InternalizeStringIfExists(
17659     Isolate* isolate,
17660     Handle<String> string) {
17661   if (string->IsInternalizedString()) {
17662     return string;
17663   }
17664   return LookupStringIfExists(isolate, string);
17665 }
17666 
17667 
LookupStringIfExists(Isolate * isolate,Handle<String> string)17668 MaybeHandle<String> StringTable::LookupStringIfExists(
17669     Isolate* isolate,
17670     Handle<String> string) {
17671   Handle<StringTable> string_table = isolate->factory()->string_table();
17672   InternalizedStringKey key(string);
17673   int entry = string_table->FindEntry(&key);
17674   if (entry == kNotFound) {
17675     return MaybeHandle<String>();
17676   } else {
17677     Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
17678     DCHECK(StringShape(*result).IsInternalized());
17679     return result;
17680   }
17681 }
17682 
17683 
LookupTwoCharsStringIfExists(Isolate * isolate,uint16_t c1,uint16_t c2)17684 MaybeHandle<String> StringTable::LookupTwoCharsStringIfExists(
17685     Isolate* isolate,
17686     uint16_t c1,
17687     uint16_t c2) {
17688   Handle<StringTable> string_table = isolate->factory()->string_table();
17689   TwoCharHashTableKey key(c1, c2, isolate->heap()->HashSeed());
17690   int entry = string_table->FindEntry(&key);
17691   if (entry == kNotFound) {
17692     return MaybeHandle<String>();
17693   } else {
17694     Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
17695     DCHECK(StringShape(*result).IsInternalized());
17696     return result;
17697   }
17698 }
17699 
17700 
EnsureCapacityForDeserialization(Isolate * isolate,int expected)17701 void StringTable::EnsureCapacityForDeserialization(Isolate* isolate,
17702                                                    int expected) {
17703   Handle<StringTable> table = isolate->factory()->string_table();
17704   // We need a key instance for the virtual hash function.
17705   InternalizedStringKey dummy_key(isolate->factory()->empty_string());
17706   table = StringTable::EnsureCapacity(table, expected, &dummy_key);
17707   isolate->heap()->SetRootStringTable(*table);
17708 }
17709 
17710 
LookupString(Isolate * isolate,Handle<String> string)17711 Handle<String> StringTable::LookupString(Isolate* isolate,
17712                                          Handle<String> string) {
17713   if (string->IsConsString() && string->IsFlat()) {
17714     string = String::Flatten(string);
17715     if (string->IsInternalizedString()) return string;
17716   }
17717 
17718   InternalizedStringKey key(string);
17719   Handle<String> result = LookupKey(isolate, &key);
17720 
17721   if (string->IsConsString()) {
17722     Handle<ConsString> cons = Handle<ConsString>::cast(string);
17723     cons->set_first(*result);
17724     cons->set_second(isolate->heap()->empty_string());
17725   } else if (string->IsSlicedString()) {
17726     STATIC_ASSERT(ConsString::kSize == SlicedString::kSize);
17727     DisallowHeapAllocation no_gc;
17728     bool one_byte = result->IsOneByteRepresentation();
17729     Handle<Map> map = one_byte ? isolate->factory()->cons_one_byte_string_map()
17730                                : isolate->factory()->cons_string_map();
17731     string->set_map(*map);
17732     Handle<ConsString> cons = Handle<ConsString>::cast(string);
17733     cons->set_first(*result);
17734     cons->set_second(isolate->heap()->empty_string());
17735   }
17736   return result;
17737 }
17738 
17739 
LookupKey(Isolate * isolate,HashTableKey * key)17740 Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) {
17741   Handle<StringTable> table = isolate->factory()->string_table();
17742   int entry = table->FindEntry(key);
17743 
17744   // String already in table.
17745   if (entry != kNotFound) {
17746     return handle(String::cast(table->KeyAt(entry)), isolate);
17747   }
17748 
17749   // Adding new string. Grow table if needed.
17750   table = StringTable::EnsureCapacity(table, 1, key);
17751 
17752   // Create string object.
17753   Handle<Object> string = key->AsHandle(isolate);
17754   // There must be no attempts to internalize strings that could throw
17755   // InvalidStringLength error.
17756   CHECK(!string.is_null());
17757 
17758   // Add the new string and return it along with the string table.
17759   entry = table->FindInsertionEntry(key->Hash());
17760   table->set(EntryToIndex(entry), *string);
17761   table->ElementAdded();
17762 
17763   isolate->heap()->SetRootStringTable(*table);
17764   return Handle<String>::cast(string);
17765 }
17766 
17767 
LookupKeyIfExists(Isolate * isolate,HashTableKey * key)17768 String* StringTable::LookupKeyIfExists(Isolate* isolate, HashTableKey* key) {
17769   Handle<StringTable> table = isolate->factory()->string_table();
17770   int entry = table->FindEntry(key);
17771   if (entry != kNotFound) return String::cast(table->KeyAt(entry));
17772   return NULL;
17773 }
17774 
New(Isolate * isolate)17775 Handle<StringSet> StringSet::New(Isolate* isolate) {
17776   return HashTable::New(isolate, 0);
17777 }
17778 
Add(Handle<StringSet> stringset,Handle<String> name)17779 Handle<StringSet> StringSet::Add(Handle<StringSet> stringset,
17780                                  Handle<String> name) {
17781   if (!stringset->Has(name)) {
17782     stringset = EnsureCapacity(stringset, 1, *name);
17783     uint32_t hash = StringSetShape::Hash(*name);
17784     int entry = stringset->FindInsertionEntry(hash);
17785     stringset->set(EntryToIndex(entry), *name);
17786     stringset->ElementAdded();
17787   }
17788   return stringset;
17789 }
17790 
Has(Handle<String> name)17791 bool StringSet::Has(Handle<String> name) {
17792   return FindEntry(*name) != kNotFound;
17793 }
17794 
Add(Handle<ObjectHashSet> set,Handle<Object> key)17795 Handle<ObjectHashSet> ObjectHashSet::Add(Handle<ObjectHashSet> set,
17796                                          Handle<Object> key) {
17797   Isolate* isolate = set->GetIsolate();
17798   int32_t hash = Object::GetOrCreateHash(isolate, key)->value();
17799 
17800   if (!set->Has(isolate, key, hash)) {
17801     set = EnsureCapacity(set, 1, key);
17802     int entry = set->FindInsertionEntry(hash);
17803     set->set(EntryToIndex(entry), *key);
17804     set->ElementAdded();
17805   }
17806   return set;
17807 }
17808 
Lookup(Handle<String> src,Handle<Context> context,LanguageMode language_mode)17809 Handle<Object> CompilationCacheTable::Lookup(Handle<String> src,
17810                                              Handle<Context> context,
17811                                              LanguageMode language_mode) {
17812   Isolate* isolate = GetIsolate();
17813   Handle<SharedFunctionInfo> shared(context->closure()->shared());
17814   StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17815   int entry = FindEntry(&key);
17816   if (entry == kNotFound) return isolate->factory()->undefined_value();
17817   int index = EntryToIndex(entry);
17818   if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value();
17819   return Handle<Object>(get(index + 1), isolate);
17820 }
17821 
17822 
LookupEval(Handle<String> src,Handle<SharedFunctionInfo> outer_info,LanguageMode language_mode,int scope_position)17823 Handle<Object> CompilationCacheTable::LookupEval(
17824     Handle<String> src, Handle<SharedFunctionInfo> outer_info,
17825     LanguageMode language_mode, int scope_position) {
17826   Isolate* isolate = GetIsolate();
17827   // Cache key is the tuple (source, outer shared function info, scope position)
17828   // to unambiguously identify the context chain the cached eval code assumes.
17829   StringSharedKey key(src, outer_info, language_mode, scope_position);
17830   int entry = FindEntry(&key);
17831   if (entry == kNotFound) return isolate->factory()->undefined_value();
17832   int index = EntryToIndex(entry);
17833   if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value();
17834   return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
17835 }
17836 
17837 
LookupRegExp(Handle<String> src,JSRegExp::Flags flags)17838 Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src,
17839                                                    JSRegExp::Flags flags) {
17840   Isolate* isolate = GetIsolate();
17841   DisallowHeapAllocation no_allocation;
17842   RegExpKey key(src, flags);
17843   int entry = FindEntry(&key);
17844   if (entry == kNotFound) return isolate->factory()->undefined_value();
17845   return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
17846 }
17847 
17848 
Put(Handle<CompilationCacheTable> cache,Handle<String> src,Handle<Context> context,LanguageMode language_mode,Handle<Object> value)17849 Handle<CompilationCacheTable> CompilationCacheTable::Put(
17850     Handle<CompilationCacheTable> cache, Handle<String> src,
17851     Handle<Context> context, LanguageMode language_mode, Handle<Object> value) {
17852   Isolate* isolate = cache->GetIsolate();
17853   Handle<SharedFunctionInfo> shared(context->closure()->shared());
17854   StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17855   Handle<Object> k = key.AsHandle(isolate);
17856   cache = EnsureCapacity(cache, 1, &key);
17857   int entry = cache->FindInsertionEntry(key.Hash());
17858   cache->set(EntryToIndex(entry), *k);
17859   cache->set(EntryToIndex(entry) + 1, *value);
17860   cache->ElementAdded();
17861   return cache;
17862 }
17863 
17864 
PutEval(Handle<CompilationCacheTable> cache,Handle<String> src,Handle<SharedFunctionInfo> outer_info,Handle<SharedFunctionInfo> value,int scope_position)17865 Handle<CompilationCacheTable> CompilationCacheTable::PutEval(
17866     Handle<CompilationCacheTable> cache, Handle<String> src,
17867     Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value,
17868     int scope_position) {
17869   Isolate* isolate = cache->GetIsolate();
17870   StringSharedKey key(src, outer_info, value->language_mode(), scope_position);
17871   {
17872     Handle<Object> k = key.AsHandle(isolate);
17873     DisallowHeapAllocation no_allocation_scope;
17874     int entry = cache->FindEntry(&key);
17875     if (entry != kNotFound) {
17876       cache->set(EntryToIndex(entry), *k);
17877       cache->set(EntryToIndex(entry) + 1, *value);
17878       return cache;
17879     }
17880   }
17881 
17882   cache = EnsureCapacity(cache, 1, &key);
17883   int entry = cache->FindInsertionEntry(key.Hash());
17884   Handle<Object> k =
17885       isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
17886   cache->set(EntryToIndex(entry), *k);
17887   cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
17888   cache->ElementAdded();
17889   return cache;
17890 }
17891 
17892 
PutRegExp(Handle<CompilationCacheTable> cache,Handle<String> src,JSRegExp::Flags flags,Handle<FixedArray> value)17893 Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp(
17894       Handle<CompilationCacheTable> cache, Handle<String> src,
17895       JSRegExp::Flags flags, Handle<FixedArray> value) {
17896   RegExpKey key(src, flags);
17897   cache = EnsureCapacity(cache, 1, &key);
17898   int entry = cache->FindInsertionEntry(key.Hash());
17899   // We store the value in the key slot, and compare the search key
17900   // to the stored value with a custon IsMatch function during lookups.
17901   cache->set(EntryToIndex(entry), *value);
17902   cache->set(EntryToIndex(entry) + 1, *value);
17903   cache->ElementAdded();
17904   return cache;
17905 }
17906 
17907 
Age()17908 void CompilationCacheTable::Age() {
17909   DisallowHeapAllocation no_allocation;
17910   Object* the_hole_value = GetHeap()->the_hole_value();
17911   for (int entry = 0, size = Capacity(); entry < size; entry++) {
17912     int entry_index = EntryToIndex(entry);
17913     int value_index = entry_index + 1;
17914 
17915     if (get(entry_index)->IsNumber()) {
17916       Smi* count = Smi::cast(get(value_index));
17917       count = Smi::FromInt(count->value() - 1);
17918       if (count->value() == 0) {
17919         NoWriteBarrierSet(this, entry_index, the_hole_value);
17920         NoWriteBarrierSet(this, value_index, the_hole_value);
17921         ElementRemoved();
17922       } else {
17923         NoWriteBarrierSet(this, value_index, count);
17924       }
17925     } else if (get(entry_index)->IsFixedArray()) {
17926       SharedFunctionInfo* info = SharedFunctionInfo::cast(get(value_index));
17927       if (info->code()->kind() != Code::FUNCTION || info->code()->IsOld()) {
17928         NoWriteBarrierSet(this, entry_index, the_hole_value);
17929         NoWriteBarrierSet(this, value_index, the_hole_value);
17930         ElementRemoved();
17931       }
17932     }
17933   }
17934 }
17935 
17936 
Remove(Object * value)17937 void CompilationCacheTable::Remove(Object* value) {
17938   DisallowHeapAllocation no_allocation;
17939   Object* the_hole_value = GetHeap()->the_hole_value();
17940   for (int entry = 0, size = Capacity(); entry < size; entry++) {
17941     int entry_index = EntryToIndex(entry);
17942     int value_index = entry_index + 1;
17943     if (get(value_index) == value) {
17944       NoWriteBarrierSet(this, entry_index, the_hole_value);
17945       NoWriteBarrierSet(this, value_index, the_hole_value);
17946       ElementRemoved();
17947     }
17948   }
17949   return;
17950 }
17951 
17952 template <typename Derived, typename Shape, typename Key>
New(Isolate * isolate,int at_least_space_for,PretenureFlag pretenure,MinimumCapacity capacity_option)17953 Handle<Derived> Dictionary<Derived, Shape, Key>::New(
17954     Isolate* isolate, int at_least_space_for, PretenureFlag pretenure,
17955     MinimumCapacity capacity_option) {
17956   DCHECK(0 <= at_least_space_for);
17957   Handle<Derived> dict = DerivedHashTable::New(isolate, at_least_space_for,
17958                                                capacity_option, pretenure);
17959 
17960   // Initialize the next enumeration index.
17961   dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
17962   return dict;
17963 }
17964 
17965 
17966 template <typename Derived, typename Shape, typename Key>
BuildIterationIndicesArray(Handle<Derived> dictionary)17967 Handle<FixedArray> Dictionary<Derived, Shape, Key>::BuildIterationIndicesArray(
17968     Handle<Derived> dictionary) {
17969   Isolate* isolate = dictionary->GetIsolate();
17970   Factory* factory = isolate->factory();
17971   int length = dictionary->NumberOfElements();
17972 
17973   Handle<FixedArray> iteration_order = factory->NewFixedArray(length);
17974   Handle<FixedArray> enumeration_order = factory->NewFixedArray(length);
17975 
17976   // Fill both the iteration order array and the enumeration order array
17977   // with property details.
17978   int capacity = dictionary->Capacity();
17979   int pos = 0;
17980   for (int i = 0; i < capacity; i++) {
17981     if (dictionary->IsKey(isolate, dictionary->KeyAt(i))) {
17982       int index = dictionary->DetailsAt(i).dictionary_index();
17983       iteration_order->set(pos, Smi::FromInt(i));
17984       enumeration_order->set(pos, Smi::FromInt(index));
17985       pos++;
17986     }
17987   }
17988   DCHECK(pos == length);
17989 
17990   // Sort the arrays wrt. enumeration order.
17991   iteration_order->SortPairs(*enumeration_order, enumeration_order->length());
17992   return iteration_order;
17993 }
17994 
17995 
17996 template <typename Derived, typename Shape, typename Key>
17997 Handle<FixedArray>
GenerateNewEnumerationIndices(Handle<Derived> dictionary)17998 Dictionary<Derived, Shape, Key>::GenerateNewEnumerationIndices(
17999     Handle<Derived> dictionary) {
18000   int length = dictionary->NumberOfElements();
18001 
18002   Handle<FixedArray> iteration_order = BuildIterationIndicesArray(dictionary);
18003   DCHECK(iteration_order->length() == length);
18004 
18005   // Iterate over the dictionary using the enumeration order and update
18006   // the dictionary with new enumeration indices.
18007   for (int i = 0; i < length; i++) {
18008     int index = Smi::cast(iteration_order->get(i))->value();
18009     DCHECK(dictionary->IsKey(dictionary->KeyAt(index)));
18010 
18011     int enum_index = PropertyDetails::kInitialIndex + i;
18012 
18013     PropertyDetails details = dictionary->DetailsAt(index);
18014     PropertyDetails new_details = details.set_index(enum_index);
18015     dictionary->DetailsAtPut(index, new_details);
18016   }
18017 
18018   // Set the next enumeration index.
18019   dictionary->SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
18020   return iteration_order;
18021 }
18022 
18023 
18024 template <typename Derived, typename Shape, typename Key>
SetRequiresCopyOnCapacityChange()18025 void Dictionary<Derived, Shape, Key>::SetRequiresCopyOnCapacityChange() {
18026   DCHECK_EQ(0, DerivedHashTable::NumberOfElements());
18027   DCHECK_EQ(0, DerivedHashTable::NumberOfDeletedElements());
18028   // Make sure that HashTable::EnsureCapacity will create a copy.
18029   DerivedHashTable::SetNumberOfDeletedElements(DerivedHashTable::Capacity());
18030   DCHECK(!DerivedHashTable::HasSufficientCapacityToAdd(1));
18031 }
18032 
18033 
18034 template <typename Derived, typename Shape, typename Key>
EnsureCapacity(Handle<Derived> dictionary,int n,Key key)18035 Handle<Derived> Dictionary<Derived, Shape, Key>::EnsureCapacity(
18036     Handle<Derived> dictionary, int n, Key key) {
18037   // Check whether there are enough enumeration indices to add n elements.
18038   if (Shape::kIsEnumerable &&
18039       !PropertyDetails::IsValidIndex(dictionary->NextEnumerationIndex() + n)) {
18040     // If not, we generate new indices for the properties.
18041     GenerateNewEnumerationIndices(dictionary);
18042   }
18043   return DerivedHashTable::EnsureCapacity(dictionary, n, key);
18044 }
18045 
18046 
18047 template <typename Derived, typename Shape, typename Key>
DeleteProperty(Handle<Derived> dictionary,int entry)18048 Handle<Object> Dictionary<Derived, Shape, Key>::DeleteProperty(
18049     Handle<Derived> dictionary, int entry) {
18050   Factory* factory = dictionary->GetIsolate()->factory();
18051   PropertyDetails details = dictionary->DetailsAt(entry);
18052   if (!details.IsConfigurable()) return factory->false_value();
18053 
18054   dictionary->SetEntry(
18055       entry, factory->the_hole_value(), factory->the_hole_value());
18056   dictionary->ElementRemoved();
18057   return factory->true_value();
18058 }
18059 
18060 
18061 template<typename Derived, typename Shape, typename Key>
AtPut(Handle<Derived> dictionary,Key key,Handle<Object> value)18062 Handle<Derived> Dictionary<Derived, Shape, Key>::AtPut(
18063     Handle<Derived> dictionary, Key key, Handle<Object> value) {
18064   int entry = dictionary->FindEntry(key);
18065 
18066   // If the entry is present set the value;
18067   if (entry != Dictionary::kNotFound) {
18068     dictionary->ValueAtPut(entry, *value);
18069     return dictionary;
18070   }
18071 
18072   // Check whether the dictionary should be extended.
18073   dictionary = EnsureCapacity(dictionary, 1, key);
18074 #ifdef DEBUG
18075   USE(Shape::AsHandle(dictionary->GetIsolate(), key));
18076 #endif
18077   PropertyDetails details = PropertyDetails::Empty();
18078 
18079   AddEntry(dictionary, key, value, details, dictionary->Hash(key));
18080   return dictionary;
18081 }
18082 
18083 template <typename Derived, typename Shape, typename Key>
Add(Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details,int * entry_out)18084 Handle<Derived> Dictionary<Derived, Shape, Key>::Add(Handle<Derived> dictionary,
18085                                                      Key key,
18086                                                      Handle<Object> value,
18087                                                      PropertyDetails details,
18088                                                      int* entry_out) {
18089   // Valdate key is absent.
18090   SLOW_DCHECK((dictionary->FindEntry(key) == Dictionary::kNotFound));
18091   // Check whether the dictionary should be extended.
18092   dictionary = EnsureCapacity(dictionary, 1, key);
18093 
18094   int entry = AddEntry(dictionary, key, value, details, dictionary->Hash(key));
18095   if (entry_out) *entry_out = entry;
18096   return dictionary;
18097 }
18098 
18099 // Add a key, value pair to the dictionary. Returns entry value.
18100 template <typename Derived, typename Shape, typename Key>
AddEntry(Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details,uint32_t hash)18101 int Dictionary<Derived, Shape, Key>::AddEntry(Handle<Derived> dictionary,
18102                                               Key key, Handle<Object> value,
18103                                               PropertyDetails details,
18104                                               uint32_t hash) {
18105   // Compute the key object.
18106   Handle<Object> k = Shape::AsHandle(dictionary->GetIsolate(), key);
18107 
18108   uint32_t entry = dictionary->FindInsertionEntry(hash);
18109   // Insert element at empty or deleted entry
18110   if (details.dictionary_index() == 0 && Shape::kIsEnumerable) {
18111     // Assign an enumeration index to the property and update
18112     // SetNextEnumerationIndex.
18113     int index = dictionary->NextEnumerationIndex();
18114     details = details.set_index(index);
18115     dictionary->SetNextEnumerationIndex(index + 1);
18116   }
18117   dictionary->SetEntry(entry, k, value, details);
18118   DCHECK((dictionary->KeyAt(entry)->IsNumber() ||
18119           dictionary->KeyAt(entry)->IsName()));
18120   dictionary->ElementAdded();
18121   return entry;
18122 }
18123 
HasComplexElements()18124 bool SeededNumberDictionary::HasComplexElements() {
18125   if (!requires_slow_elements()) return false;
18126   Isolate* isolate = this->GetIsolate();
18127   int capacity = this->Capacity();
18128   for (int i = 0; i < capacity; i++) {
18129     Object* k = this->KeyAt(i);
18130     if (!this->IsKey(isolate, k)) continue;
18131     DCHECK(!IsDeleted(i));
18132     PropertyDetails details = this->DetailsAt(i);
18133     if (details.type() == ACCESSOR_CONSTANT) return true;
18134     PropertyAttributes attr = details.attributes();
18135     if (attr & ALL_ATTRIBUTES_MASK) return true;
18136   }
18137   return false;
18138 }
18139 
UpdateMaxNumberKey(uint32_t key,bool used_as_prototype)18140 void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key,
18141                                                 bool used_as_prototype) {
18142   DisallowHeapAllocation no_allocation;
18143   // If the dictionary requires slow elements an element has already
18144   // been added at a high index.
18145   if (requires_slow_elements()) return;
18146   // Check if this index is high enough that we should require slow
18147   // elements.
18148   if (key > kRequiresSlowElementsLimit) {
18149     if (used_as_prototype) {
18150       // TODO(verwaest): Remove this hack.
18151       TypeFeedbackVector::ClearAllKeyedStoreICs(GetIsolate());
18152     }
18153     set_requires_slow_elements();
18154     return;
18155   }
18156   // Update max key value.
18157   Object* max_index_object = get(kMaxNumberKeyIndex);
18158   if (!max_index_object->IsSmi() || max_number_key() < key) {
18159     FixedArray::set(kMaxNumberKeyIndex,
18160                     Smi::FromInt(key << kRequiresSlowElementsTagSize));
18161   }
18162 }
18163 
18164 
AddNumberEntry(Handle<SeededNumberDictionary> dictionary,uint32_t key,Handle<Object> value,PropertyDetails details,bool used_as_prototype)18165 Handle<SeededNumberDictionary> SeededNumberDictionary::AddNumberEntry(
18166     Handle<SeededNumberDictionary> dictionary, uint32_t key,
18167     Handle<Object> value, PropertyDetails details, bool used_as_prototype) {
18168   dictionary->UpdateMaxNumberKey(key, used_as_prototype);
18169   SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
18170   return Add(dictionary, key, value, details);
18171 }
18172 
18173 
AddNumberEntry(Handle<UnseededNumberDictionary> dictionary,uint32_t key,Handle<Object> value)18174 Handle<UnseededNumberDictionary> UnseededNumberDictionary::AddNumberEntry(
18175     Handle<UnseededNumberDictionary> dictionary,
18176     uint32_t key,
18177     Handle<Object> value) {
18178   SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
18179   return Add(dictionary, key, value, PropertyDetails::Empty());
18180 }
18181 
DeleteKey(Handle<UnseededNumberDictionary> dictionary,uint32_t key)18182 Handle<UnseededNumberDictionary> UnseededNumberDictionary::DeleteKey(
18183     Handle<UnseededNumberDictionary> dictionary, uint32_t key) {
18184   int entry = dictionary->FindEntry(key);
18185   if (entry == kNotFound) return dictionary;
18186 
18187   Factory* factory = dictionary->GetIsolate()->factory();
18188   dictionary->SetEntry(entry, factory->the_hole_value(),
18189                        factory->the_hole_value());
18190   dictionary->ElementRemoved();
18191   return dictionary->Shrink(dictionary, key);
18192 }
18193 
AtNumberPut(Handle<SeededNumberDictionary> dictionary,uint32_t key,Handle<Object> value,bool used_as_prototype)18194 Handle<SeededNumberDictionary> SeededNumberDictionary::AtNumberPut(
18195     Handle<SeededNumberDictionary> dictionary, uint32_t key,
18196     Handle<Object> value, bool used_as_prototype) {
18197   dictionary->UpdateMaxNumberKey(key, used_as_prototype);
18198   return AtPut(dictionary, key, value);
18199 }
18200 
18201 
AtNumberPut(Handle<UnseededNumberDictionary> dictionary,uint32_t key,Handle<Object> value)18202 Handle<UnseededNumberDictionary> UnseededNumberDictionary::AtNumberPut(
18203     Handle<UnseededNumberDictionary> dictionary,
18204     uint32_t key,
18205     Handle<Object> value) {
18206   return AtPut(dictionary, key, value);
18207 }
18208 
18209 
Set(Handle<SeededNumberDictionary> dictionary,uint32_t key,Handle<Object> value,PropertyDetails details,bool used_as_prototype)18210 Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
18211     Handle<SeededNumberDictionary> dictionary, uint32_t key,
18212     Handle<Object> value, PropertyDetails details, bool used_as_prototype) {
18213   int entry = dictionary->FindEntry(key);
18214   if (entry == kNotFound) {
18215     return AddNumberEntry(dictionary, key, value, details, used_as_prototype);
18216   }
18217   // Preserve enumeration index.
18218   details = details.set_index(dictionary->DetailsAt(entry).dictionary_index());
18219   Handle<Object> object_key =
18220       SeededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
18221   dictionary->SetEntry(entry, object_key, value, details);
18222   return dictionary;
18223 }
18224 
18225 
Set(Handle<UnseededNumberDictionary> dictionary,uint32_t key,Handle<Object> value)18226 Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
18227     Handle<UnseededNumberDictionary> dictionary,
18228     uint32_t key,
18229     Handle<Object> value) {
18230   int entry = dictionary->FindEntry(key);
18231   if (entry == kNotFound) return AddNumberEntry(dictionary, key, value);
18232   Handle<Object> object_key =
18233       UnseededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
18234   dictionary->SetEntry(entry, object_key, value);
18235   return dictionary;
18236 }
18237 
18238 
18239 template <typename Derived, typename Shape, typename Key>
NumberOfElementsFilterAttributes(PropertyFilter filter)18240 int Dictionary<Derived, Shape, Key>::NumberOfElementsFilterAttributes(
18241     PropertyFilter filter) {
18242   Isolate* isolate = this->GetIsolate();
18243   int capacity = this->Capacity();
18244   int result = 0;
18245   for (int i = 0; i < capacity; i++) {
18246     Object* k = this->KeyAt(i);
18247     if (this->IsKey(isolate, k) && !k->FilterKey(filter)) {
18248       if (this->IsDeleted(i)) continue;
18249       PropertyDetails details = this->DetailsAt(i);
18250       PropertyAttributes attr = details.attributes();
18251       if ((attr & filter) == 0) result++;
18252     }
18253   }
18254   return result;
18255 }
18256 
18257 
18258 template <typename Dictionary>
18259 struct EnumIndexComparator {
EnumIndexComparatorv8::internal::EnumIndexComparator18260   explicit EnumIndexComparator(Dictionary* dict) : dict(dict) {}
operator ()v8::internal::EnumIndexComparator18261   bool operator() (Smi* a, Smi* b) {
18262     PropertyDetails da(dict->DetailsAt(a->value()));
18263     PropertyDetails db(dict->DetailsAt(b->value()));
18264     return da.dictionary_index() < db.dictionary_index();
18265   }
18266   Dictionary* dict;
18267 };
18268 
18269 template <typename Derived, typename Shape, typename Key>
CopyEnumKeysTo(Handle<Dictionary<Derived,Shape,Key>> dictionary,Handle<FixedArray> storage,KeyCollectionMode mode,KeyAccumulator * accumulator)18270 void Dictionary<Derived, Shape, Key>::CopyEnumKeysTo(
18271     Handle<Dictionary<Derived, Shape, Key>> dictionary,
18272     Handle<FixedArray> storage, KeyCollectionMode mode,
18273     KeyAccumulator* accumulator) {
18274   Isolate* isolate = dictionary->GetIsolate();
18275   int length = storage->length();
18276   int capacity = dictionary->Capacity();
18277   int properties = 0;
18278   for (int i = 0; i < capacity; i++) {
18279     Object* key = dictionary->KeyAt(i);
18280     bool is_shadowing_key = false;
18281     if (!dictionary->IsKey(isolate, key)) continue;
18282     if (key->IsSymbol()) continue;
18283     PropertyDetails details = dictionary->DetailsAt(i);
18284     if (details.IsDontEnum()) {
18285       if (mode == KeyCollectionMode::kIncludePrototypes) {
18286         is_shadowing_key = true;
18287       } else {
18288         continue;
18289       }
18290     }
18291     if (dictionary->IsDeleted(i)) continue;
18292     if (is_shadowing_key) {
18293       accumulator->AddShadowingKey(key);
18294       continue;
18295     } else {
18296       storage->set(properties, Smi::FromInt(i));
18297     }
18298     properties++;
18299     if (properties == length) break;
18300   }
18301 
18302   CHECK_EQ(length, properties);
18303   DisallowHeapAllocation no_gc;
18304   Dictionary<Derived, Shape, Key>* raw_dictionary = *dictionary;
18305   FixedArray* raw_storage = *storage;
18306   EnumIndexComparator<Derived> cmp(static_cast<Derived*>(*dictionary));
18307   Smi** start = reinterpret_cast<Smi**>(storage->GetFirstElementAddress());
18308   std::sort(start, start + length, cmp);
18309   for (int i = 0; i < length; i++) {
18310     int index = Smi::cast(raw_storage->get(i))->value();
18311     raw_storage->set(i, raw_dictionary->KeyAt(index));
18312   }
18313 }
18314 
18315 template <typename Derived, typename Shape, typename Key>
CollectKeysTo(Handle<Dictionary<Derived,Shape,Key>> dictionary,KeyAccumulator * keys)18316 void Dictionary<Derived, Shape, Key>::CollectKeysTo(
18317     Handle<Dictionary<Derived, Shape, Key>> dictionary, KeyAccumulator* keys) {
18318   Isolate* isolate = keys->isolate();
18319   int capacity = dictionary->Capacity();
18320   Handle<FixedArray> array =
18321       isolate->factory()->NewFixedArray(dictionary->NumberOfElements());
18322   int array_size = 0;
18323   PropertyFilter filter = keys->filter();
18324   {
18325     DisallowHeapAllocation no_gc;
18326     Dictionary<Derived, Shape, Key>* raw_dict = *dictionary;
18327     for (int i = 0; i < capacity; i++) {
18328       Object* k = raw_dict->KeyAt(i);
18329       if (!raw_dict->IsKey(isolate, k) || k->FilterKey(filter)) continue;
18330       if (raw_dict->IsDeleted(i)) continue;
18331       PropertyDetails details = raw_dict->DetailsAt(i);
18332       if ((details.attributes() & filter) != 0) {
18333         keys->AddShadowingKey(k);
18334         continue;
18335       }
18336       if (filter & ONLY_ALL_CAN_READ) {
18337         if (details.kind() != kAccessor) continue;
18338         Object* accessors = raw_dict->ValueAt(i);
18339         if (accessors->IsPropertyCell()) {
18340           accessors = PropertyCell::cast(accessors)->value();
18341         }
18342         if (!accessors->IsAccessorInfo()) continue;
18343         if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
18344       }
18345       array->set(array_size++, Smi::FromInt(i));
18346     }
18347 
18348     EnumIndexComparator<Derived> cmp(static_cast<Derived*>(raw_dict));
18349     Smi** start = reinterpret_cast<Smi**>(array->GetFirstElementAddress());
18350     std::sort(start, start + array_size, cmp);
18351   }
18352 
18353   bool has_seen_symbol = false;
18354   for (int i = 0; i < array_size; i++) {
18355     int index = Smi::cast(array->get(i))->value();
18356     Object* key = dictionary->KeyAt(index);
18357     if (key->IsSymbol()) {
18358       has_seen_symbol = true;
18359       continue;
18360     }
18361     keys->AddKey(key, DO_NOT_CONVERT);
18362   }
18363   if (has_seen_symbol) {
18364     for (int i = 0; i < array_size; i++) {
18365       int index = Smi::cast(array->get(i))->value();
18366       Object* key = dictionary->KeyAt(index);
18367       if (!key->IsSymbol()) continue;
18368       keys->AddKey(key, DO_NOT_CONVERT);
18369     }
18370   }
18371 }
18372 
18373 
18374 // Backwards lookup (slow).
18375 template<typename Derived, typename Shape, typename Key>
SlowReverseLookup(Object * value)18376 Object* Dictionary<Derived, Shape, Key>::SlowReverseLookup(Object* value) {
18377   Isolate* isolate = this->GetIsolate();
18378   int capacity = this->Capacity();
18379   for (int i = 0; i < capacity; i++) {
18380     Object* k = this->KeyAt(i);
18381     if (!this->IsKey(isolate, k)) continue;
18382     Object* e = this->ValueAt(i);
18383     // TODO(dcarney): this should be templatized.
18384     if (e->IsPropertyCell()) {
18385       e = PropertyCell::cast(e)->value();
18386     }
18387     if (e == value) return k;
18388   }
18389   return isolate->heap()->undefined_value();
18390 }
18391 
18392 
Lookup(Isolate * isolate,Handle<Object> key,int32_t hash)18393 Object* ObjectHashTable::Lookup(Isolate* isolate, Handle<Object> key,
18394                                 int32_t hash) {
18395   DisallowHeapAllocation no_gc;
18396   DCHECK(IsKey(isolate, *key));
18397 
18398   int entry = FindEntry(isolate, key, hash);
18399   if (entry == kNotFound) return isolate->heap()->the_hole_value();
18400   return get(EntryToIndex(entry) + 1);
18401 }
18402 
18403 
Lookup(Handle<Object> key)18404 Object* ObjectHashTable::Lookup(Handle<Object> key) {
18405   DisallowHeapAllocation no_gc;
18406 
18407   Isolate* isolate = GetIsolate();
18408   DCHECK(IsKey(isolate, *key));
18409 
18410   // If the object does not have an identity hash, it was never used as a key.
18411   Object* hash = key->GetHash();
18412   if (hash->IsUndefined(isolate)) {
18413     return isolate->heap()->the_hole_value();
18414   }
18415   return Lookup(isolate, key, Smi::cast(hash)->value());
18416 }
18417 
ValueAt(int entry)18418 Object* ObjectHashTable::ValueAt(int entry) {
18419   return get(EntryToValueIndex(entry));
18420 }
18421 
Lookup(Handle<Object> key,int32_t hash)18422 Object* ObjectHashTable::Lookup(Handle<Object> key, int32_t hash) {
18423   return Lookup(GetIsolate(), key, hash);
18424 }
18425 
18426 
Put(Handle<ObjectHashTable> table,Handle<Object> key,Handle<Object> value)18427 Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
18428                                              Handle<Object> key,
18429                                              Handle<Object> value) {
18430   Isolate* isolate = table->GetIsolate();
18431   DCHECK(table->IsKey(isolate, *key));
18432   DCHECK(!value->IsTheHole(isolate));
18433 
18434   // Make sure the key object has an identity hash code.
18435   int32_t hash = Object::GetOrCreateHash(isolate, key)->value();
18436 
18437   return Put(table, key, value, hash);
18438 }
18439 
18440 
Put(Handle<ObjectHashTable> table,Handle<Object> key,Handle<Object> value,int32_t hash)18441 Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
18442                                              Handle<Object> key,
18443                                              Handle<Object> value,
18444                                              int32_t hash) {
18445   Isolate* isolate = table->GetIsolate();
18446   DCHECK(table->IsKey(isolate, *key));
18447   DCHECK(!value->IsTheHole(isolate));
18448 
18449   int entry = table->FindEntry(isolate, key, hash);
18450 
18451   // Key is already in table, just overwrite value.
18452   if (entry != kNotFound) {
18453     table->set(EntryToIndex(entry) + 1, *value);
18454     return table;
18455   }
18456 
18457   // Rehash if more than 33% of the entries are deleted entries.
18458   // TODO(jochen): Consider to shrink the fixed array in place.
18459   if ((table->NumberOfDeletedElements() << 1) > table->NumberOfElements()) {
18460     table->Rehash(isolate->factory()->undefined_value());
18461   }
18462   // If we're out of luck, we didn't get a GC recently, and so rehashing
18463   // isn't enough to avoid a crash.
18464   if (!table->HasSufficientCapacityToAdd(1)) {
18465     int nof = table->NumberOfElements() + 1;
18466     int capacity = ObjectHashTable::ComputeCapacity(nof * 2);
18467     if (capacity > ObjectHashTable::kMaxCapacity) {
18468       for (size_t i = 0; i < 2; ++i) {
18469         isolate->heap()->CollectAllGarbage(
18470             Heap::kFinalizeIncrementalMarkingMask,
18471             GarbageCollectionReason::kFullHashtable);
18472       }
18473       table->Rehash(isolate->factory()->undefined_value());
18474     }
18475   }
18476 
18477   // Check whether the hash table should be extended.
18478   table = EnsureCapacity(table, 1, key);
18479   table->AddEntry(table->FindInsertionEntry(hash), *key, *value);
18480   return table;
18481 }
18482 
18483 
Remove(Handle<ObjectHashTable> table,Handle<Object> key,bool * was_present)18484 Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
18485                                                 Handle<Object> key,
18486                                                 bool* was_present) {
18487   DCHECK(table->IsKey(table->GetIsolate(), *key));
18488 
18489   Object* hash = key->GetHash();
18490   if (hash->IsUndefined(table->GetIsolate())) {
18491     *was_present = false;
18492     return table;
18493   }
18494 
18495   return Remove(table, key, was_present, Smi::cast(hash)->value());
18496 }
18497 
18498 
Remove(Handle<ObjectHashTable> table,Handle<Object> key,bool * was_present,int32_t hash)18499 Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
18500                                                 Handle<Object> key,
18501                                                 bool* was_present,
18502                                                 int32_t hash) {
18503   Isolate* isolate = table->GetIsolate();
18504   DCHECK(table->IsKey(isolate, *key));
18505 
18506   int entry = table->FindEntry(isolate, key, hash);
18507   if (entry == kNotFound) {
18508     *was_present = false;
18509     return table;
18510   }
18511 
18512   *was_present = true;
18513   table->RemoveEntry(entry);
18514   return Shrink(table, key);
18515 }
18516 
18517 
AddEntry(int entry,Object * key,Object * value)18518 void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
18519   set(EntryToIndex(entry), key);
18520   set(EntryToIndex(entry) + 1, value);
18521   ElementAdded();
18522 }
18523 
18524 
RemoveEntry(int entry)18525 void ObjectHashTable::RemoveEntry(int entry) {
18526   set_the_hole(EntryToIndex(entry));
18527   set_the_hole(EntryToIndex(entry) + 1);
18528   ElementRemoved();
18529 }
18530 
18531 
Lookup(Handle<HeapObject> key)18532 Object* WeakHashTable::Lookup(Handle<HeapObject> key) {
18533   DisallowHeapAllocation no_gc;
18534   Isolate* isolate = GetIsolate();
18535   DCHECK(IsKey(isolate, *key));
18536   int entry = FindEntry(key);
18537   if (entry == kNotFound) return isolate->heap()->the_hole_value();
18538   return get(EntryToValueIndex(entry));
18539 }
18540 
18541 
Put(Handle<WeakHashTable> table,Handle<HeapObject> key,Handle<HeapObject> value)18542 Handle<WeakHashTable> WeakHashTable::Put(Handle<WeakHashTable> table,
18543                                          Handle<HeapObject> key,
18544                                          Handle<HeapObject> value) {
18545   Isolate* isolate = key->GetIsolate();
18546   DCHECK(table->IsKey(isolate, *key));
18547   int entry = table->FindEntry(key);
18548   // Key is already in table, just overwrite value.
18549   if (entry != kNotFound) {
18550     table->set(EntryToValueIndex(entry), *value);
18551     return table;
18552   }
18553 
18554   Handle<WeakCell> key_cell = isolate->factory()->NewWeakCell(key);
18555 
18556   // Check whether the hash table should be extended.
18557   table = EnsureCapacity(table, 1, key, TENURED);
18558 
18559   table->AddEntry(table->FindInsertionEntry(table->Hash(key)), key_cell, value);
18560   return table;
18561 }
18562 
18563 
AddEntry(int entry,Handle<WeakCell> key_cell,Handle<HeapObject> value)18564 void WeakHashTable::AddEntry(int entry, Handle<WeakCell> key_cell,
18565                              Handle<HeapObject> value) {
18566   DisallowHeapAllocation no_allocation;
18567   set(EntryToIndex(entry), *key_cell);
18568   set(EntryToValueIndex(entry), *value);
18569   ElementAdded();
18570 }
18571 
18572 
18573 template<class Derived, class Iterator, int entrysize>
Allocate(Isolate * isolate,int capacity,PretenureFlag pretenure)18574 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Allocate(
18575     Isolate* isolate, int capacity, PretenureFlag pretenure) {
18576   // Capacity must be a power of two, since we depend on being able
18577   // to divide and multiple by 2 (kLoadFactor) to derive capacity
18578   // from number of buckets. If we decide to change kLoadFactor
18579   // to something other than 2, capacity should be stored as another
18580   // field of this object.
18581   capacity = base::bits::RoundUpToPowerOfTwo32(Max(kMinCapacity, capacity));
18582   if (capacity > kMaxCapacity) {
18583     v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
18584   }
18585   int num_buckets = capacity / kLoadFactor;
18586   Handle<FixedArray> backing_store = isolate->factory()->NewFixedArray(
18587       kHashTableStartIndex + num_buckets + (capacity * kEntrySize), pretenure);
18588   backing_store->set_map_no_write_barrier(
18589       isolate->heap()->ordered_hash_table_map());
18590   Handle<Derived> table = Handle<Derived>::cast(backing_store);
18591   for (int i = 0; i < num_buckets; ++i) {
18592     table->set(kHashTableStartIndex + i, Smi::FromInt(kNotFound));
18593   }
18594   table->SetNumberOfBuckets(num_buckets);
18595   table->SetNumberOfElements(0);
18596   table->SetNumberOfDeletedElements(0);
18597   return table;
18598 }
18599 
18600 
18601 template<class Derived, class Iterator, int entrysize>
EnsureGrowable(Handle<Derived> table)18602 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::EnsureGrowable(
18603     Handle<Derived> table) {
18604   DCHECK(!table->IsObsolete());
18605 
18606   int nof = table->NumberOfElements();
18607   int nod = table->NumberOfDeletedElements();
18608   int capacity = table->Capacity();
18609   if ((nof + nod) < capacity) return table;
18610   // Don't need to grow if we can simply clear out deleted entries instead.
18611   // Note that we can't compact in place, though, so we always allocate
18612   // a new table.
18613   return Rehash(table, (nod < (capacity >> 1)) ? capacity << 1 : capacity);
18614 }
18615 
18616 
18617 template<class Derived, class Iterator, int entrysize>
Shrink(Handle<Derived> table)18618 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Shrink(
18619     Handle<Derived> table) {
18620   DCHECK(!table->IsObsolete());
18621 
18622   int nof = table->NumberOfElements();
18623   int capacity = table->Capacity();
18624   if (nof >= (capacity >> 2)) return table;
18625   return Rehash(table, capacity / 2);
18626 }
18627 
18628 
18629 template<class Derived, class Iterator, int entrysize>
Clear(Handle<Derived> table)18630 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Clear(
18631     Handle<Derived> table) {
18632   DCHECK(!table->IsObsolete());
18633 
18634   Handle<Derived> new_table =
18635       Allocate(table->GetIsolate(),
18636                kMinCapacity,
18637                table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
18638 
18639   table->SetNextTable(*new_table);
18640   table->SetNumberOfDeletedElements(kClearedTableSentinel);
18641 
18642   return new_table;
18643 }
18644 
18645 template <class Derived, class Iterator, int entrysize>
HasKey(Handle<Derived> table,Handle<Object> key)18646 bool OrderedHashTable<Derived, Iterator, entrysize>::HasKey(
18647     Handle<Derived> table, Handle<Object> key) {
18648   DisallowHeapAllocation no_gc;
18649   Isolate* isolate = table->GetIsolate();
18650   Object* raw_key = *key;
18651   int entry = table->KeyToFirstEntry(isolate, raw_key);
18652   // Walk the chain in the bucket to find the key.
18653   while (entry != kNotFound) {
18654     Object* candidate_key = table->KeyAt(entry);
18655     if (candidate_key->SameValueZero(raw_key)) return true;
18656     entry = table->NextChainEntry(entry);
18657   }
18658   return false;
18659 }
18660 
18661 
Add(Handle<OrderedHashSet> table,Handle<Object> key)18662 Handle<OrderedHashSet> OrderedHashSet::Add(Handle<OrderedHashSet> table,
18663                                            Handle<Object> key) {
18664   int hash = Object::GetOrCreateHash(table->GetIsolate(), key)->value();
18665   int entry = table->HashToEntry(hash);
18666   // Walk the chain of the bucket and try finding the key.
18667   while (entry != kNotFound) {
18668     Object* candidate_key = table->KeyAt(entry);
18669     // Do not add if we have the key already
18670     if (candidate_key->SameValueZero(*key)) return table;
18671     entry = table->NextChainEntry(entry);
18672   }
18673 
18674   table = OrderedHashSet::EnsureGrowable(table);
18675   // Read the existing bucket values.
18676   int bucket = table->HashToBucket(hash);
18677   int previous_entry = table->HashToEntry(hash);
18678   int nof = table->NumberOfElements();
18679   // Insert a new entry at the end,
18680   int new_entry = nof + table->NumberOfDeletedElements();
18681   int new_index = table->EntryToIndex(new_entry);
18682   table->set(new_index, *key);
18683   table->set(new_index + kChainOffset, Smi::FromInt(previous_entry));
18684   // and point the bucket to the new entry.
18685   table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
18686   table->SetNumberOfElements(nof + 1);
18687   return table;
18688 }
18689 
ConvertToKeysArray(Handle<OrderedHashSet> table,GetKeysConversion convert)18690 Handle<FixedArray> OrderedHashSet::ConvertToKeysArray(
18691     Handle<OrderedHashSet> table, GetKeysConversion convert) {
18692   Isolate* isolate = table->GetIsolate();
18693   int length = table->NumberOfElements();
18694   int nof_buckets = table->NumberOfBuckets();
18695   // Convert the dictionary to a linear list.
18696   Handle<FixedArray> result = Handle<FixedArray>::cast(table);
18697   // From this point on table is no longer a valid OrderedHashSet.
18698   result->set_map(isolate->heap()->fixed_array_map());
18699   for (int i = 0; i < length; i++) {
18700     int index = kHashTableStartIndex + nof_buckets + (i * kEntrySize);
18701     Object* key = table->get(index);
18702     if (convert == GetKeysConversion::kConvertToString && key->IsNumber()) {
18703       key = *isolate->factory()->NumberToString(handle(key, isolate));
18704     }
18705     result->set(i, key);
18706   }
18707   result->Shrink(length);
18708   return result;
18709 }
18710 
18711 template<class Derived, class Iterator, int entrysize>
Rehash(Handle<Derived> table,int new_capacity)18712 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Rehash(
18713     Handle<Derived> table, int new_capacity) {
18714   Isolate* isolate = table->GetIsolate();
18715   DCHECK(!table->IsObsolete());
18716 
18717   Handle<Derived> new_table =
18718       Allocate(isolate, new_capacity,
18719                isolate->heap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
18720   int nof = table->NumberOfElements();
18721   int nod = table->NumberOfDeletedElements();
18722   int new_buckets = new_table->NumberOfBuckets();
18723   int new_entry = 0;
18724   int removed_holes_index = 0;
18725 
18726   DisallowHeapAllocation no_gc;
18727   for (int old_entry = 0; old_entry < (nof + nod); ++old_entry) {
18728     Object* key = table->KeyAt(old_entry);
18729     if (key->IsTheHole(isolate)) {
18730       table->SetRemovedIndexAt(removed_holes_index++, old_entry);
18731       continue;
18732     }
18733 
18734     Object* hash = key->GetHash();
18735     int bucket = Smi::cast(hash)->value() & (new_buckets - 1);
18736     Object* chain_entry = new_table->get(kHashTableStartIndex + bucket);
18737     new_table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
18738     int new_index = new_table->EntryToIndex(new_entry);
18739     int old_index = table->EntryToIndex(old_entry);
18740     for (int i = 0; i < entrysize; ++i) {
18741       Object* value = table->get(old_index + i);
18742       new_table->set(new_index + i, value);
18743     }
18744     new_table->set(new_index + kChainOffset, chain_entry);
18745     ++new_entry;
18746   }
18747 
18748   DCHECK_EQ(nod, removed_holes_index);
18749 
18750   new_table->SetNumberOfElements(nof);
18751   table->SetNextTable(*new_table);
18752 
18753   return new_table;
18754 }
18755 
18756 
18757 template Handle<OrderedHashSet>
18758 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Allocate(
18759     Isolate* isolate, int capacity, PretenureFlag pretenure);
18760 
18761 template Handle<OrderedHashSet>
18762 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::EnsureGrowable(
18763     Handle<OrderedHashSet> table);
18764 
18765 template Handle<OrderedHashSet>
18766 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Shrink(
18767     Handle<OrderedHashSet> table);
18768 
18769 template Handle<OrderedHashSet>
18770 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Clear(
18771     Handle<OrderedHashSet> table);
18772 
18773 template bool OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::HasKey(
18774     Handle<OrderedHashSet> table, Handle<Object> key);
18775 
18776 
18777 template Handle<OrderedHashMap>
18778 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Allocate(
18779     Isolate* isolate, int capacity, PretenureFlag pretenure);
18780 
18781 template Handle<OrderedHashMap>
18782 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::EnsureGrowable(
18783     Handle<OrderedHashMap> table);
18784 
18785 template Handle<OrderedHashMap>
18786 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Shrink(
18787     Handle<OrderedHashMap> table);
18788 
18789 template Handle<OrderedHashMap>
18790 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Clear(
18791     Handle<OrderedHashMap> table);
18792 
18793 template bool OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::HasKey(
18794     Handle<OrderedHashMap> table, Handle<Object> key);
18795 
18796 
18797 template<class Derived, class TableType>
Transition()18798 void OrderedHashTableIterator<Derived, TableType>::Transition() {
18799   DisallowHeapAllocation no_allocation;
18800   TableType* table = TableType::cast(this->table());
18801   if (!table->IsObsolete()) return;
18802 
18803   int index = Smi::cast(this->index())->value();
18804   while (table->IsObsolete()) {
18805     TableType* next_table = table->NextTable();
18806 
18807     if (index > 0) {
18808       int nod = table->NumberOfDeletedElements();
18809 
18810       if (nod == TableType::kClearedTableSentinel) {
18811         index = 0;
18812       } else {
18813         int old_index = index;
18814         for (int i = 0; i < nod; ++i) {
18815           int removed_index = table->RemovedIndexAt(i);
18816           if (removed_index >= old_index) break;
18817           --index;
18818         }
18819       }
18820     }
18821 
18822     table = next_table;
18823   }
18824 
18825   set_table(table);
18826   set_index(Smi::FromInt(index));
18827 }
18828 
18829 
18830 template<class Derived, class TableType>
HasMore()18831 bool OrderedHashTableIterator<Derived, TableType>::HasMore() {
18832   DisallowHeapAllocation no_allocation;
18833   Isolate* isolate = this->GetIsolate();
18834   if (this->table()->IsUndefined(isolate)) return false;
18835 
18836   Transition();
18837 
18838   TableType* table = TableType::cast(this->table());
18839   int index = Smi::cast(this->index())->value();
18840   int used_capacity = table->UsedCapacity();
18841 
18842   while (index < used_capacity && table->KeyAt(index)->IsTheHole(isolate)) {
18843     index++;
18844   }
18845 
18846   set_index(Smi::FromInt(index));
18847 
18848   if (index < used_capacity) return true;
18849 
18850   set_table(isolate->heap()->undefined_value());
18851   return false;
18852 }
18853 
18854 
18855 template<class Derived, class TableType>
Next(JSArray * value_array)18856 Smi* OrderedHashTableIterator<Derived, TableType>::Next(JSArray* value_array) {
18857   DisallowHeapAllocation no_allocation;
18858   if (HasMore()) {
18859     FixedArray* array = FixedArray::cast(value_array->elements());
18860     static_cast<Derived*>(this)->PopulateValueArray(array);
18861     MoveNext();
18862     return Smi::cast(kind());
18863   }
18864   return Smi::kZero;
18865 }
18866 
18867 
18868 template Smi*
18869 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Next(
18870     JSArray* value_array);
18871 
18872 template bool
18873 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::HasMore();
18874 
18875 template void
18876 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::MoveNext();
18877 
18878 template Object*
18879 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::CurrentKey();
18880 
18881 template void
18882 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Transition();
18883 
18884 
18885 template Smi*
18886 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Next(
18887     JSArray* value_array);
18888 
18889 template bool
18890 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::HasMore();
18891 
18892 template void
18893 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::MoveNext();
18894 
18895 template Object*
18896 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::CurrentKey();
18897 
18898 template void
18899 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Transition();
18900 
18901 
Initialize(Handle<JSSet> set,Isolate * isolate)18902 void JSSet::Initialize(Handle<JSSet> set, Isolate* isolate) {
18903   Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
18904   set->set_table(*table);
18905 }
18906 
18907 
Clear(Handle<JSSet> set)18908 void JSSet::Clear(Handle<JSSet> set) {
18909   Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()));
18910   table = OrderedHashSet::Clear(table);
18911   set->set_table(*table);
18912 }
18913 
18914 
Initialize(Handle<JSMap> map,Isolate * isolate)18915 void JSMap::Initialize(Handle<JSMap> map, Isolate* isolate) {
18916   Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
18917   map->set_table(*table);
18918 }
18919 
18920 
Clear(Handle<JSMap> map)18921 void JSMap::Clear(Handle<JSMap> map) {
18922   Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()));
18923   table = OrderedHashMap::Clear(table);
18924   map->set_table(*table);
18925 }
18926 
18927 
Initialize(Handle<JSWeakCollection> weak_collection,Isolate * isolate)18928 void JSWeakCollection::Initialize(Handle<JSWeakCollection> weak_collection,
18929                                   Isolate* isolate) {
18930   Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0);
18931   weak_collection->set_table(*table);
18932 }
18933 
18934 
Set(Handle<JSWeakCollection> weak_collection,Handle<Object> key,Handle<Object> value,int32_t hash)18935 void JSWeakCollection::Set(Handle<JSWeakCollection> weak_collection,
18936                            Handle<Object> key, Handle<Object> value,
18937                            int32_t hash) {
18938   DCHECK(key->IsJSReceiver() || key->IsSymbol());
18939   Handle<ObjectHashTable> table(
18940       ObjectHashTable::cast(weak_collection->table()));
18941   DCHECK(table->IsKey(*key));
18942   Handle<ObjectHashTable> new_table =
18943       ObjectHashTable::Put(table, key, value, hash);
18944   weak_collection->set_table(*new_table);
18945   if (*table != *new_table) {
18946     // Zap the old table since we didn't record slots for its elements.
18947     table->FillWithHoles(0, table->length());
18948   }
18949 }
18950 
18951 
Delete(Handle<JSWeakCollection> weak_collection,Handle<Object> key,int32_t hash)18952 bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection,
18953                               Handle<Object> key, int32_t hash) {
18954   DCHECK(key->IsJSReceiver() || key->IsSymbol());
18955   Handle<ObjectHashTable> table(
18956       ObjectHashTable::cast(weak_collection->table()));
18957   DCHECK(table->IsKey(*key));
18958   bool was_present = false;
18959   Handle<ObjectHashTable> new_table =
18960       ObjectHashTable::Remove(table, key, &was_present, hash);
18961   weak_collection->set_table(*new_table);
18962   if (*table != *new_table) {
18963     // Zap the old table since we didn't record slots for its elements.
18964     table->FillWithHoles(0, table->length());
18965   }
18966   return was_present;
18967 }
18968 
18969 // Check if there is a break point at this source position.
HasBreakPoint(int source_position)18970 bool DebugInfo::HasBreakPoint(int source_position) {
18971   // Get the break point info object for this code offset.
18972   Object* break_point_info = GetBreakPointInfo(source_position);
18973 
18974   // If there is no break point info object or no break points in the break
18975   // point info object there is no break point at this code offset.
18976   if (break_point_info->IsUndefined(GetIsolate())) return false;
18977   return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
18978 }
18979 
18980 // Get the break point info object for this source position.
GetBreakPointInfo(int source_position)18981 Object* DebugInfo::GetBreakPointInfo(int source_position) {
18982   Isolate* isolate = GetIsolate();
18983   if (!break_points()->IsUndefined(isolate)) {
18984     for (int i = 0; i < break_points()->length(); i++) {
18985       if (!break_points()->get(i)->IsUndefined(isolate)) {
18986         BreakPointInfo* break_point_info =
18987             BreakPointInfo::cast(break_points()->get(i));
18988         if (break_point_info->source_position() == source_position) {
18989           return break_point_info;
18990         }
18991       }
18992     }
18993   }
18994   return isolate->heap()->undefined_value();
18995 }
18996 
ClearBreakPoint(Handle<DebugInfo> debug_info,Handle<Object> break_point_object)18997 bool DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
18998                                 Handle<Object> break_point_object) {
18999   Isolate* isolate = debug_info->GetIsolate();
19000   if (debug_info->break_points()->IsUndefined(isolate)) return false;
19001 
19002   for (int i = 0; i < debug_info->break_points()->length(); i++) {
19003     if (debug_info->break_points()->get(i)->IsUndefined(isolate)) continue;
19004     Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
19005         BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
19006     if (BreakPointInfo::HasBreakPointObject(break_point_info,
19007                                             break_point_object)) {
19008       BreakPointInfo::ClearBreakPoint(break_point_info, break_point_object);
19009       return true;
19010     }
19011   }
19012   return false;
19013 }
19014 
SetBreakPoint(Handle<DebugInfo> debug_info,int source_position,Handle<Object> break_point_object)19015 void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info, int source_position,
19016                               Handle<Object> break_point_object) {
19017   Isolate* isolate = debug_info->GetIsolate();
19018   Handle<Object> break_point_info(
19019       debug_info->GetBreakPointInfo(source_position), isolate);
19020   if (!break_point_info->IsUndefined(isolate)) {
19021     BreakPointInfo::SetBreakPoint(
19022         Handle<BreakPointInfo>::cast(break_point_info),
19023         break_point_object);
19024     return;
19025   }
19026 
19027   // Adding a new break point for a code offset which did not have any
19028   // break points before. Try to find a free slot.
19029   static const int kNoBreakPointInfo = -1;
19030   int index = kNoBreakPointInfo;
19031   for (int i = 0; i < debug_info->break_points()->length(); i++) {
19032     if (debug_info->break_points()->get(i)->IsUndefined(isolate)) {
19033       index = i;
19034       break;
19035     }
19036   }
19037   if (index == kNoBreakPointInfo) {
19038     // No free slot - extend break point info array.
19039     Handle<FixedArray> old_break_points = Handle<FixedArray>(
19040         FixedArray::cast(debug_info->break_points()), isolate);
19041     Handle<FixedArray> new_break_points =
19042         isolate->factory()->NewFixedArray(
19043             old_break_points->length() +
19044             DebugInfo::kEstimatedNofBreakPointsInFunction);
19045 
19046     debug_info->set_break_points(*new_break_points);
19047     for (int i = 0; i < old_break_points->length(); i++) {
19048       new_break_points->set(i, old_break_points->get(i));
19049     }
19050     index = old_break_points->length();
19051   }
19052   DCHECK(index != kNoBreakPointInfo);
19053 
19054   // Allocate new BreakPointInfo object and set the break point.
19055   Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
19056       isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
19057   new_break_point_info->set_source_position(source_position);
19058   new_break_point_info->set_break_point_objects(
19059       isolate->heap()->undefined_value());
19060   BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
19061   debug_info->break_points()->set(index, *new_break_point_info);
19062 }
19063 
19064 // Get the break point objects for a source position.
GetBreakPointObjects(int source_position)19065 Handle<Object> DebugInfo::GetBreakPointObjects(int source_position) {
19066   Object* break_point_info = GetBreakPointInfo(source_position);
19067   Isolate* isolate = GetIsolate();
19068   if (break_point_info->IsUndefined(isolate)) {
19069     return isolate->factory()->undefined_value();
19070   }
19071   return Handle<Object>(
19072       BreakPointInfo::cast(break_point_info)->break_point_objects(), isolate);
19073 }
19074 
19075 
19076 // Get the total number of break points.
GetBreakPointCount()19077 int DebugInfo::GetBreakPointCount() {
19078   Isolate* isolate = GetIsolate();
19079   if (break_points()->IsUndefined(isolate)) return 0;
19080   int count = 0;
19081   for (int i = 0; i < break_points()->length(); i++) {
19082     if (!break_points()->get(i)->IsUndefined(isolate)) {
19083       BreakPointInfo* break_point_info =
19084           BreakPointInfo::cast(break_points()->get(i));
19085       count += break_point_info->GetBreakPointCount();
19086     }
19087   }
19088   return count;
19089 }
19090 
19091 
FindBreakPointInfo(Handle<DebugInfo> debug_info,Handle<Object> break_point_object)19092 Handle<Object> DebugInfo::FindBreakPointInfo(
19093     Handle<DebugInfo> debug_info, Handle<Object> break_point_object) {
19094   Isolate* isolate = debug_info->GetIsolate();
19095   if (!debug_info->break_points()->IsUndefined(isolate)) {
19096     for (int i = 0; i < debug_info->break_points()->length(); i++) {
19097       if (!debug_info->break_points()->get(i)->IsUndefined(isolate)) {
19098         Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
19099             BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
19100         if (BreakPointInfo::HasBreakPointObject(break_point_info,
19101                                                 break_point_object)) {
19102           return break_point_info;
19103         }
19104       }
19105     }
19106   }
19107   return isolate->factory()->undefined_value();
19108 }
19109 
19110 // Remove the specified break point object.
ClearBreakPoint(Handle<BreakPointInfo> break_point_info,Handle<Object> break_point_object)19111 void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
19112                                      Handle<Object> break_point_object) {
19113   Isolate* isolate = break_point_info->GetIsolate();
19114   // If there are no break points just ignore.
19115   if (break_point_info->break_point_objects()->IsUndefined(isolate)) return;
19116   // If there is a single break point clear it if it is the same.
19117   if (!break_point_info->break_point_objects()->IsFixedArray()) {
19118     if (break_point_info->break_point_objects() == *break_point_object) {
19119       break_point_info->set_break_point_objects(
19120           isolate->heap()->undefined_value());
19121     }
19122     return;
19123   }
19124   // If there are multiple break points shrink the array
19125   DCHECK(break_point_info->break_point_objects()->IsFixedArray());
19126   Handle<FixedArray> old_array =
19127       Handle<FixedArray>(
19128           FixedArray::cast(break_point_info->break_point_objects()));
19129   Handle<FixedArray> new_array =
19130       isolate->factory()->NewFixedArray(old_array->length() - 1);
19131   int found_count = 0;
19132   for (int i = 0; i < old_array->length(); i++) {
19133     if (old_array->get(i) == *break_point_object) {
19134       DCHECK(found_count == 0);
19135       found_count++;
19136     } else {
19137       new_array->set(i - found_count, old_array->get(i));
19138     }
19139   }
19140   // If the break point was found in the list change it.
19141   if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
19142 }
19143 
19144 
19145 // Add the specified break point object.
SetBreakPoint(Handle<BreakPointInfo> break_point_info,Handle<Object> break_point_object)19146 void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
19147                                    Handle<Object> break_point_object) {
19148   Isolate* isolate = break_point_info->GetIsolate();
19149 
19150   // If there was no break point objects before just set it.
19151   if (break_point_info->break_point_objects()->IsUndefined(isolate)) {
19152     break_point_info->set_break_point_objects(*break_point_object);
19153     return;
19154   }
19155   // If the break point object is the same as before just ignore.
19156   if (break_point_info->break_point_objects() == *break_point_object) return;
19157   // If there was one break point object before replace with array.
19158   if (!break_point_info->break_point_objects()->IsFixedArray()) {
19159     Handle<FixedArray> array = isolate->factory()->NewFixedArray(2);
19160     array->set(0, break_point_info->break_point_objects());
19161     array->set(1, *break_point_object);
19162     break_point_info->set_break_point_objects(*array);
19163     return;
19164   }
19165   // If there was more than one break point before extend array.
19166   Handle<FixedArray> old_array =
19167       Handle<FixedArray>(
19168           FixedArray::cast(break_point_info->break_point_objects()));
19169   Handle<FixedArray> new_array =
19170       isolate->factory()->NewFixedArray(old_array->length() + 1);
19171   for (int i = 0; i < old_array->length(); i++) {
19172     // If the break point was there before just ignore.
19173     if (old_array->get(i) == *break_point_object) return;
19174     new_array->set(i, old_array->get(i));
19175   }
19176   // Add the new break point.
19177   new_array->set(old_array->length(), *break_point_object);
19178   break_point_info->set_break_point_objects(*new_array);
19179 }
19180 
19181 
HasBreakPointObject(Handle<BreakPointInfo> break_point_info,Handle<Object> break_point_object)19182 bool BreakPointInfo::HasBreakPointObject(
19183     Handle<BreakPointInfo> break_point_info,
19184     Handle<Object> break_point_object) {
19185   // No break point.
19186   Isolate* isolate = break_point_info->GetIsolate();
19187   if (break_point_info->break_point_objects()->IsUndefined(isolate)) {
19188     return false;
19189   }
19190   // Single break point.
19191   if (!break_point_info->break_point_objects()->IsFixedArray()) {
19192     return break_point_info->break_point_objects() == *break_point_object;
19193   }
19194   // Multiple break points.
19195   FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
19196   for (int i = 0; i < array->length(); i++) {
19197     if (array->get(i) == *break_point_object) {
19198       return true;
19199     }
19200   }
19201   return false;
19202 }
19203 
19204 
19205 // Get the number of break points.
GetBreakPointCount()19206 int BreakPointInfo::GetBreakPointCount() {
19207   // No break point.
19208   if (break_point_objects()->IsUndefined(GetIsolate())) return 0;
19209   // Single break point.
19210   if (!break_point_objects()->IsFixedArray()) return 1;
19211   // Multiple break points.
19212   return FixedArray::cast(break_point_objects())->length();
19213 }
19214 
19215 
19216 // static
New(Handle<JSFunction> constructor,Handle<JSReceiver> new_target,double tv)19217 MaybeHandle<JSDate> JSDate::New(Handle<JSFunction> constructor,
19218                                 Handle<JSReceiver> new_target, double tv) {
19219   Isolate* const isolate = constructor->GetIsolate();
19220   Handle<JSObject> result;
19221   ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
19222                              JSObject::New(constructor, new_target), JSDate);
19223   if (-DateCache::kMaxTimeInMs <= tv && tv <= DateCache::kMaxTimeInMs) {
19224     tv = DoubleToInteger(tv) + 0.0;
19225   } else {
19226     tv = std::numeric_limits<double>::quiet_NaN();
19227   }
19228   Handle<Object> value = isolate->factory()->NewNumber(tv);
19229   Handle<JSDate>::cast(result)->SetValue(*value, std::isnan(tv));
19230   return Handle<JSDate>::cast(result);
19231 }
19232 
19233 
19234 // static
CurrentTimeValue(Isolate * isolate)19235 double JSDate::CurrentTimeValue(Isolate* isolate) {
19236   if (FLAG_log_timer_events || FLAG_prof_cpp) LOG(isolate, CurrentTimeEvent());
19237 
19238   // According to ECMA-262, section 15.9.1, page 117, the precision of
19239   // the number in a Date object representing a particular instant in
19240   // time is milliseconds. Therefore, we floor the result of getting
19241   // the OS time.
19242   return Floor(FLAG_verify_predictable
19243                    ? isolate->heap()->MonotonicallyIncreasingTimeInMs()
19244                    : base::OS::TimeCurrentMillis());
19245 }
19246 
19247 
19248 // static
GetField(Object * object,Smi * index)19249 Object* JSDate::GetField(Object* object, Smi* index) {
19250   return JSDate::cast(object)->DoGetField(
19251       static_cast<FieldIndex>(index->value()));
19252 }
19253 
19254 
DoGetField(FieldIndex index)19255 Object* JSDate::DoGetField(FieldIndex index) {
19256   DCHECK(index != kDateValue);
19257 
19258   DateCache* date_cache = GetIsolate()->date_cache();
19259 
19260   if (index < kFirstUncachedField) {
19261     Object* stamp = cache_stamp();
19262     if (stamp != date_cache->stamp() && stamp->IsSmi()) {
19263       // Since the stamp is not NaN, the value is also not NaN.
19264       int64_t local_time_ms =
19265           date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
19266       SetCachedFields(local_time_ms, date_cache);
19267     }
19268     switch (index) {
19269       case kYear: return year();
19270       case kMonth: return month();
19271       case kDay: return day();
19272       case kWeekday: return weekday();
19273       case kHour: return hour();
19274       case kMinute: return min();
19275       case kSecond: return sec();
19276       default: UNREACHABLE();
19277     }
19278   }
19279 
19280   if (index >= kFirstUTCField) {
19281     return GetUTCField(index, value()->Number(), date_cache);
19282   }
19283 
19284   double time = value()->Number();
19285   if (std::isnan(time)) return GetIsolate()->heap()->nan_value();
19286 
19287   int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
19288   int days = DateCache::DaysFromTime(local_time_ms);
19289 
19290   if (index == kDays) return Smi::FromInt(days);
19291 
19292   int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
19293   if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
19294   DCHECK(index == kTimeInDay);
19295   return Smi::FromInt(time_in_day_ms);
19296 }
19297 
19298 
GetUTCField(FieldIndex index,double value,DateCache * date_cache)19299 Object* JSDate::GetUTCField(FieldIndex index,
19300                             double value,
19301                             DateCache* date_cache) {
19302   DCHECK(index >= kFirstUTCField);
19303 
19304   if (std::isnan(value)) return GetIsolate()->heap()->nan_value();
19305 
19306   int64_t time_ms = static_cast<int64_t>(value);
19307 
19308   if (index == kTimezoneOffset) {
19309     return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
19310   }
19311 
19312   int days = DateCache::DaysFromTime(time_ms);
19313 
19314   if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
19315 
19316   if (index <= kDayUTC) {
19317     int year, month, day;
19318     date_cache->YearMonthDayFromDays(days, &year, &month, &day);
19319     if (index == kYearUTC) return Smi::FromInt(year);
19320     if (index == kMonthUTC) return Smi::FromInt(month);
19321     DCHECK(index == kDayUTC);
19322     return Smi::FromInt(day);
19323   }
19324 
19325   int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
19326   switch (index) {
19327     case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
19328     case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
19329     case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
19330     case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
19331     case kDaysUTC: return Smi::FromInt(days);
19332     case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
19333     default: UNREACHABLE();
19334   }
19335 
19336   UNREACHABLE();
19337   return NULL;
19338 }
19339 
19340 
19341 // static
SetValue(Handle<JSDate> date,double v)19342 Handle<Object> JSDate::SetValue(Handle<JSDate> date, double v) {
19343   Isolate* const isolate = date->GetIsolate();
19344   Handle<Object> value = isolate->factory()->NewNumber(v);
19345   bool value_is_nan = std::isnan(v);
19346   date->SetValue(*value, value_is_nan);
19347   return value;
19348 }
19349 
19350 
SetValue(Object * value,bool is_value_nan)19351 void JSDate::SetValue(Object* value, bool is_value_nan) {
19352   set_value(value);
19353   if (is_value_nan) {
19354     HeapNumber* nan = GetIsolate()->heap()->nan_value();
19355     set_cache_stamp(nan, SKIP_WRITE_BARRIER);
19356     set_year(nan, SKIP_WRITE_BARRIER);
19357     set_month(nan, SKIP_WRITE_BARRIER);
19358     set_day(nan, SKIP_WRITE_BARRIER);
19359     set_hour(nan, SKIP_WRITE_BARRIER);
19360     set_min(nan, SKIP_WRITE_BARRIER);
19361     set_sec(nan, SKIP_WRITE_BARRIER);
19362     set_weekday(nan, SKIP_WRITE_BARRIER);
19363   } else {
19364     set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
19365   }
19366 }
19367 
19368 
19369 // static
ToPrimitive(Handle<JSReceiver> receiver,Handle<Object> hint)19370 MaybeHandle<Object> JSDate::ToPrimitive(Handle<JSReceiver> receiver,
19371                                         Handle<Object> hint) {
19372   Isolate* const isolate = receiver->GetIsolate();
19373   if (hint->IsString()) {
19374     Handle<String> hint_string = Handle<String>::cast(hint);
19375     if (hint_string->Equals(isolate->heap()->number_string())) {
19376       return JSReceiver::OrdinaryToPrimitive(receiver,
19377                                              OrdinaryToPrimitiveHint::kNumber);
19378     }
19379     if (hint_string->Equals(isolate->heap()->default_string()) ||
19380         hint_string->Equals(isolate->heap()->string_string())) {
19381       return JSReceiver::OrdinaryToPrimitive(receiver,
19382                                              OrdinaryToPrimitiveHint::kString);
19383     }
19384   }
19385   THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kInvalidHint, hint),
19386                   Object);
19387 }
19388 
19389 
SetCachedFields(int64_t local_time_ms,DateCache * date_cache)19390 void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) {
19391   int days = DateCache::DaysFromTime(local_time_ms);
19392   int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
19393   int year, month, day;
19394   date_cache->YearMonthDayFromDays(days, &year, &month, &day);
19395   int weekday = date_cache->Weekday(days);
19396   int hour = time_in_day_ms / (60 * 60 * 1000);
19397   int min = (time_in_day_ms / (60 * 1000)) % 60;
19398   int sec = (time_in_day_ms / 1000) % 60;
19399   set_cache_stamp(date_cache->stamp());
19400   set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
19401   set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
19402   set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
19403   set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
19404   set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
19405   set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
19406   set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
19407 }
19408 
19409 namespace {
19410 
ScriptFromJSValue(Object * in)19411 Script* ScriptFromJSValue(Object* in) {
19412   DCHECK(in->IsJSValue());
19413   JSValue* jsvalue = JSValue::cast(in);
19414   DCHECK(jsvalue->value()->IsScript());
19415   return Script::cast(jsvalue->value());
19416 }
19417 
19418 }  // namespace
19419 
GetLineNumber() const19420 int JSMessageObject::GetLineNumber() const {
19421   if (start_position() == -1) return Message::kNoLineNumberInfo;
19422 
19423   Handle<Script> the_script = handle(ScriptFromJSValue(script()));
19424 
19425   Script::PositionInfo info;
19426   const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
19427   if (!Script::GetPositionInfo(the_script, start_position(), &info,
19428                                offset_flag)) {
19429     return Message::kNoLineNumberInfo;
19430   }
19431 
19432   return info.line + 1;
19433 }
19434 
GetColumnNumber() const19435 int JSMessageObject::GetColumnNumber() const {
19436   if (start_position() == -1) return -1;
19437 
19438   Handle<Script> the_script = handle(ScriptFromJSValue(script()));
19439 
19440   Script::PositionInfo info;
19441   const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
19442   if (!Script::GetPositionInfo(the_script, start_position(), &info,
19443                                offset_flag)) {
19444     return -1;
19445   }
19446 
19447   return info.column;  // Note: No '+1' in contrast to GetLineNumber.
19448 }
19449 
GetSourceLine() const19450 Handle<String> JSMessageObject::GetSourceLine() const {
19451   Handle<Script> the_script = handle(ScriptFromJSValue(script()));
19452 
19453   Isolate* isolate = the_script->GetIsolate();
19454   if (the_script->type() == Script::TYPE_WASM) {
19455     return isolate->factory()->empty_string();
19456   }
19457 
19458   Script::PositionInfo info;
19459   const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
19460   if (!Script::GetPositionInfo(the_script, start_position(), &info,
19461                                offset_flag)) {
19462     return isolate->factory()->empty_string();
19463   }
19464 
19465   Handle<String> src = handle(String::cast(the_script->source()), isolate);
19466   return isolate->factory()->NewSubString(src, info.line_start, info.line_end);
19467 }
19468 
Neuter()19469 void JSArrayBuffer::Neuter() {
19470   CHECK(is_neuterable());
19471   CHECK(is_external());
19472   set_backing_store(NULL);
19473   set_byte_length(Smi::kZero);
19474   set_was_neutered(true);
19475 }
19476 
19477 
Setup(Handle<JSArrayBuffer> array_buffer,Isolate * isolate,bool is_external,void * data,size_t allocated_length,SharedFlag shared)19478 void JSArrayBuffer::Setup(Handle<JSArrayBuffer> array_buffer, Isolate* isolate,
19479                           bool is_external, void* data, size_t allocated_length,
19480                           SharedFlag shared) {
19481   DCHECK(array_buffer->GetInternalFieldCount() ==
19482          v8::ArrayBuffer::kInternalFieldCount);
19483   for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) {
19484     array_buffer->SetInternalField(i, Smi::kZero);
19485   }
19486   array_buffer->set_bit_field(0);
19487   array_buffer->set_is_external(is_external);
19488   array_buffer->set_is_neuterable(shared == SharedFlag::kNotShared);
19489   array_buffer->set_is_shared(shared == SharedFlag::kShared);
19490 
19491   Handle<Object> byte_length =
19492       isolate->factory()->NewNumberFromSize(allocated_length);
19493   CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
19494   array_buffer->set_byte_length(*byte_length);
19495   // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
19496   // are currently being constructed in the |ArrayBufferTracker|. The
19497   // registration method below handles the case of registering a buffer that has
19498   // already been promoted.
19499   array_buffer->set_backing_store(data);
19500 
19501   if (data && !is_external) {
19502     isolate->heap()->RegisterNewArrayBuffer(*array_buffer);
19503   }
19504 }
19505 
19506 
SetupAllocatingData(Handle<JSArrayBuffer> array_buffer,Isolate * isolate,size_t allocated_length,bool initialize,SharedFlag shared)19507 bool JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer> array_buffer,
19508                                         Isolate* isolate,
19509                                         size_t allocated_length,
19510                                         bool initialize, SharedFlag shared) {
19511   void* data;
19512   CHECK(isolate->array_buffer_allocator() != NULL);
19513   // Prevent creating array buffers when serializing.
19514   DCHECK(!isolate->serializer_enabled());
19515   if (allocated_length != 0) {
19516     if (initialize) {
19517       data = isolate->array_buffer_allocator()->Allocate(allocated_length);
19518     } else {
19519       data = isolate->array_buffer_allocator()->AllocateUninitialized(
19520           allocated_length);
19521     }
19522     if (data == NULL) return false;
19523   } else {
19524     data = NULL;
19525   }
19526 
19527   JSArrayBuffer::Setup(array_buffer, isolate, false, data, allocated_length,
19528                        shared);
19529   return true;
19530 }
19531 
19532 
MaterializeArrayBuffer(Handle<JSTypedArray> typed_array)19533 Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
19534     Handle<JSTypedArray> typed_array) {
19535 
19536   Handle<Map> map(typed_array->map());
19537   Isolate* isolate = typed_array->GetIsolate();
19538 
19539   DCHECK(IsFixedTypedArrayElementsKind(map->elements_kind()));
19540 
19541   Handle<FixedTypedArrayBase> fixed_typed_array(
19542       FixedTypedArrayBase::cast(typed_array->elements()));
19543 
19544   Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(typed_array->buffer()),
19545                                isolate);
19546   void* backing_store =
19547       isolate->array_buffer_allocator()->AllocateUninitialized(
19548           fixed_typed_array->DataSize());
19549   buffer->set_is_external(false);
19550   DCHECK(buffer->byte_length()->IsSmi() ||
19551          buffer->byte_length()->IsHeapNumber());
19552   DCHECK(NumberToInt32(buffer->byte_length()) == fixed_typed_array->DataSize());
19553   // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
19554   // are currently being constructed in the |ArrayBufferTracker|. The
19555   // registration method below handles the case of registering a buffer that has
19556   // already been promoted.
19557   buffer->set_backing_store(backing_store);
19558   isolate->heap()->RegisterNewArrayBuffer(*buffer);
19559   memcpy(buffer->backing_store(),
19560          fixed_typed_array->DataPtr(),
19561          fixed_typed_array->DataSize());
19562   Handle<FixedTypedArrayBase> new_elements =
19563       isolate->factory()->NewFixedTypedArrayWithExternalPointer(
19564           fixed_typed_array->length(), typed_array->type(),
19565           static_cast<uint8_t*>(buffer->backing_store()));
19566 
19567   typed_array->set_elements(*new_elements);
19568 
19569   return buffer;
19570 }
19571 
19572 
GetBuffer()19573 Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
19574   Handle<JSArrayBuffer> array_buffer(JSArrayBuffer::cast(buffer()),
19575                                      GetIsolate());
19576   if (array_buffer->was_neutered() ||
19577       array_buffer->backing_store() != nullptr) {
19578     return array_buffer;
19579   }
19580   Handle<JSTypedArray> self(this);
19581   return MaterializeArrayBuffer(self);
19582 }
19583 
InvalidateEntry(Handle<GlobalDictionary> dictionary,int entry)19584 Handle<PropertyCell> PropertyCell::InvalidateEntry(
19585     Handle<GlobalDictionary> dictionary, int entry) {
19586   Isolate* isolate = dictionary->GetIsolate();
19587   // Swap with a copy.
19588   DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
19589   Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
19590   Handle<PropertyCell> new_cell = isolate->factory()->NewPropertyCell();
19591   new_cell->set_value(cell->value());
19592   dictionary->ValueAtPut(entry, *new_cell);
19593   bool is_the_hole = cell->value()->IsTheHole(isolate);
19594   // Cell is officially mutable henceforth.
19595   PropertyDetails details = cell->property_details();
19596   details = details.set_cell_type(is_the_hole ? PropertyCellType::kUninitialized
19597                                               : PropertyCellType::kMutable);
19598   new_cell->set_property_details(details);
19599   // Old cell is ready for invalidation.
19600   if (is_the_hole) {
19601     cell->set_value(isolate->heap()->undefined_value());
19602   } else {
19603     cell->set_value(isolate->heap()->the_hole_value());
19604   }
19605   details = details.set_cell_type(PropertyCellType::kInvalidated);
19606   cell->set_property_details(details);
19607   cell->dependent_code()->DeoptimizeDependentCodeGroup(
19608       isolate, DependentCode::kPropertyCellChangedGroup);
19609   return new_cell;
19610 }
19611 
19612 
GetConstantType()19613 PropertyCellConstantType PropertyCell::GetConstantType() {
19614   if (value()->IsSmi()) return PropertyCellConstantType::kSmi;
19615   return PropertyCellConstantType::kStableMap;
19616 }
19617 
19618 
RemainsConstantType(Handle<PropertyCell> cell,Handle<Object> value)19619 static bool RemainsConstantType(Handle<PropertyCell> cell,
19620                                 Handle<Object> value) {
19621   // TODO(dcarney): double->smi and smi->double transition from kConstant
19622   if (cell->value()->IsSmi() && value->IsSmi()) {
19623     return true;
19624   } else if (cell->value()->IsHeapObject() && value->IsHeapObject()) {
19625     return HeapObject::cast(cell->value())->map() ==
19626                HeapObject::cast(*value)->map() &&
19627            HeapObject::cast(*value)->map()->is_stable();
19628   }
19629   return false;
19630 }
19631 
19632 
UpdatedType(Handle<PropertyCell> cell,Handle<Object> value,PropertyDetails details)19633 PropertyCellType PropertyCell::UpdatedType(Handle<PropertyCell> cell,
19634                                            Handle<Object> value,
19635                                            PropertyDetails details) {
19636   PropertyCellType type = details.cell_type();
19637   Isolate* isolate = cell->GetIsolate();
19638   DCHECK(!value->IsTheHole(isolate));
19639   if (cell->value()->IsTheHole(isolate)) {
19640     switch (type) {
19641       // Only allow a cell to transition once into constant state.
19642       case PropertyCellType::kUninitialized:
19643         if (value->IsUndefined(isolate)) return PropertyCellType::kUndefined;
19644         return PropertyCellType::kConstant;
19645       case PropertyCellType::kInvalidated:
19646         return PropertyCellType::kMutable;
19647       default:
19648         UNREACHABLE();
19649         return PropertyCellType::kMutable;
19650     }
19651   }
19652   switch (type) {
19653     case PropertyCellType::kUndefined:
19654       return PropertyCellType::kConstant;
19655     case PropertyCellType::kConstant:
19656       if (*value == cell->value()) return PropertyCellType::kConstant;
19657     // Fall through.
19658     case PropertyCellType::kConstantType:
19659       if (RemainsConstantType(cell, value)) {
19660         return PropertyCellType::kConstantType;
19661       }
19662     // Fall through.
19663     case PropertyCellType::kMutable:
19664       return PropertyCellType::kMutable;
19665   }
19666   UNREACHABLE();
19667   return PropertyCellType::kMutable;
19668 }
19669 
PrepareForValue(Handle<GlobalDictionary> dictionary,int entry,Handle<Object> value,PropertyDetails details)19670 Handle<PropertyCell> PropertyCell::PrepareForValue(
19671     Handle<GlobalDictionary> dictionary, int entry, Handle<Object> value,
19672     PropertyDetails details) {
19673   Isolate* isolate = dictionary->GetIsolate();
19674   DCHECK(!value->IsTheHole(isolate));
19675   DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
19676   Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
19677   const PropertyDetails original_details = cell->property_details();
19678   // Data accesses could be cached in ics or optimized code.
19679   bool invalidate =
19680       original_details.kind() == kData && details.kind() == kAccessor;
19681   int index = original_details.dictionary_index();
19682   PropertyCellType old_type = original_details.cell_type();
19683   // Preserve the enumeration index unless the property was deleted or never
19684   // initialized.
19685   if (cell->value()->IsTheHole(isolate)) {
19686     index = dictionary->NextEnumerationIndex();
19687     dictionary->SetNextEnumerationIndex(index + 1);
19688   }
19689   DCHECK(index > 0);
19690   details = details.set_index(index);
19691 
19692   PropertyCellType new_type = UpdatedType(cell, value, original_details);
19693   if (invalidate) cell = PropertyCell::InvalidateEntry(dictionary, entry);
19694 
19695   // Install new property details.
19696   details = details.set_cell_type(new_type);
19697   cell->set_property_details(details);
19698 
19699   // Deopt when transitioning from a constant type.
19700   if (!invalidate && (old_type != new_type ||
19701                       original_details.IsReadOnly() != details.IsReadOnly())) {
19702     cell->dependent_code()->DeoptimizeDependentCodeGroup(
19703         isolate, DependentCode::kPropertyCellChangedGroup);
19704   }
19705   return cell;
19706 }
19707 
19708 
19709 // static
SetValueWithInvalidation(Handle<PropertyCell> cell,Handle<Object> new_value)19710 void PropertyCell::SetValueWithInvalidation(Handle<PropertyCell> cell,
19711                                             Handle<Object> new_value) {
19712   if (cell->value() != *new_value) {
19713     cell->set_value(*new_value);
19714     Isolate* isolate = cell->GetIsolate();
19715     cell->dependent_code()->DeoptimizeDependentCodeGroup(
19716         isolate, DependentCode::kPropertyCellChangedGroup);
19717   }
19718 }
19719 
source_position() const19720 int JSGeneratorObject::source_position() const {
19721   CHECK(is_suspended());
19722   AbstractCode* code;
19723   int code_offset;
19724   if (function()->shared()->HasBytecodeArray()) {
19725     // New-style generators.
19726     DCHECK(!function()->shared()->HasBaselineCode());
19727     code_offset = Smi::cast(input_or_debug_pos())->value();
19728     // The stored bytecode offset is relative to a different base than what
19729     // is used in the source position table, hence the subtraction.
19730     code_offset -= BytecodeArray::kHeaderSize - kHeapObjectTag;
19731     code = AbstractCode::cast(function()->shared()->bytecode_array());
19732   } else {
19733     // Old-style generators.
19734     DCHECK(function()->shared()->HasBaselineCode());
19735     code_offset = continuation();
19736     CHECK(0 <= code_offset);
19737     CHECK(code_offset < function()->code()->instruction_size());
19738     code = AbstractCode::cast(function()->shared()->code());
19739   }
19740   return code->SourcePosition(code_offset);
19741 }
19742 
19743 // static
Get(Isolate * isolate,Handle<JSObject> receiver)19744 AccessCheckInfo* AccessCheckInfo::Get(Isolate* isolate,
19745                                       Handle<JSObject> receiver) {
19746   DisallowHeapAllocation no_gc;
19747   DCHECK(receiver->map()->is_access_check_needed());
19748   Object* maybe_constructor = receiver->map()->GetConstructor();
19749   // Might happen for a detached context.
19750   if (!maybe_constructor->IsJSFunction()) return nullptr;
19751   JSFunction* constructor = JSFunction::cast(maybe_constructor);
19752   // Might happen for the debug context.
19753   if (!constructor->shared()->IsApiFunction()) return nullptr;
19754 
19755   Object* data_obj =
19756       constructor->shared()->get_api_func_data()->access_check_info();
19757   if (data_obj->IsUndefined(isolate)) return nullptr;
19758 
19759   return AccessCheckInfo::cast(data_obj);
19760 }
19761 
HasProxyInPrototype(Isolate * isolate)19762 bool JSReceiver::HasProxyInPrototype(Isolate* isolate) {
19763   for (PrototypeIterator iter(isolate, this, kStartAtReceiver,
19764                               PrototypeIterator::END_AT_NULL);
19765        !iter.IsAtEnd(); iter.AdvanceIgnoringProxies()) {
19766     if (iter.GetCurrent<Object>()->IsJSProxy()) return true;
19767   }
19768   return false;
19769 }
19770 
GetExport(Handle<String> name)19771 MaybeHandle<Object> JSModuleNamespace::GetExport(Handle<String> name) {
19772   Isolate* isolate = name->GetIsolate();
19773 
19774   Handle<Object> object(module()->exports()->Lookup(name), isolate);
19775   if (object->IsTheHole(isolate)) {
19776     return isolate->factory()->undefined_value();
19777   }
19778 
19779   Handle<Object> value(Handle<Cell>::cast(object)->value(), isolate);
19780   if (value->IsTheHole(isolate)) {
19781     THROW_NEW_ERROR(
19782         isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object);
19783   }
19784 
19785   return value;
19786 }
19787 
19788 namespace {
19789 
19790 struct ModuleHandleHash {
operator ()v8::internal::__anon91478ca21511::ModuleHandleHash19791   V8_INLINE size_t operator()(Handle<Module> module) const {
19792     return module->hash();
19793   }
19794 };
19795 
19796 struct ModuleHandleEqual {
operator ()v8::internal::__anon91478ca21511::ModuleHandleEqual19797   V8_INLINE bool operator()(Handle<Module> lhs, Handle<Module> rhs) const {
19798     return *lhs == *rhs;
19799   }
19800 };
19801 
19802 struct StringHandleHash {
operator ()v8::internal::__anon91478ca21511::StringHandleHash19803   V8_INLINE size_t operator()(Handle<String> string) const {
19804     return string->Hash();
19805   }
19806 };
19807 
19808 struct StringHandleEqual {
operator ()v8::internal::__anon91478ca21511::StringHandleEqual19809   V8_INLINE bool operator()(Handle<String> lhs, Handle<String> rhs) const {
19810     return lhs->Equals(*rhs);
19811   }
19812 };
19813 
19814 class UnorderedStringSet
19815     : public std::unordered_set<Handle<String>, StringHandleHash,
19816                                 StringHandleEqual,
19817                                 zone_allocator<Handle<String>>> {
19818  public:
UnorderedStringSet(Zone * zone)19819   explicit UnorderedStringSet(Zone* zone)
19820       : std::unordered_set<Handle<String>, StringHandleHash, StringHandleEqual,
19821                            zone_allocator<Handle<String>>>(
19822             2 /* bucket count */, StringHandleHash(), StringHandleEqual(),
19823             zone_allocator<Handle<String>>(zone)) {}
19824 };
19825 
19826 class UnorderedModuleSet
19827     : public std::unordered_set<Handle<Module>, ModuleHandleHash,
19828                                 ModuleHandleEqual,
19829                                 zone_allocator<Handle<Module>>> {
19830  public:
UnorderedModuleSet(Zone * zone)19831   explicit UnorderedModuleSet(Zone* zone)
19832       : std::unordered_set<Handle<Module>, ModuleHandleHash, ModuleHandleEqual,
19833                            zone_allocator<Handle<Module>>>(
19834             2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(),
19835             zone_allocator<Handle<Module>>(zone)) {}
19836 };
19837 
19838 class UnorderedStringMap
19839     : public std::unordered_map<
19840           Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual,
19841           zone_allocator<std::pair<const Handle<String>, Handle<Object>>>> {
19842  public:
UnorderedStringMap(Zone * zone)19843   explicit UnorderedStringMap(Zone* zone)
19844       : std::unordered_map<
19845             Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual,
19846             zone_allocator<std::pair<const Handle<String>, Handle<Object>>>>(
19847             2 /* bucket count */, StringHandleHash(), StringHandleEqual(),
19848             zone_allocator<std::pair<const Handle<String>, Handle<Object>>>(
19849                 zone)) {}
19850 };
19851 
19852 }  // anonymous namespace
19853 
19854 class Module::ResolveSet
19855     : public std::unordered_map<
19856           Handle<Module>, UnorderedStringSet*, ModuleHandleHash,
19857           ModuleHandleEqual, zone_allocator<std::pair<const Handle<Module>,
19858                                                       UnorderedStringSet*>>> {
19859  public:
ResolveSet(Zone * zone)19860   explicit ResolveSet(Zone* zone)
19861       : std::unordered_map<Handle<Module>, UnorderedStringSet*,
19862                            ModuleHandleHash, ModuleHandleEqual,
19863                            zone_allocator<std::pair<const Handle<Module>,
19864                                                     UnorderedStringSet*>>>(
19865             2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(),
19866             zone_allocator<
19867                 std::pair<const Handle<Module>, UnorderedStringSet*>>(zone)),
19868         zone_(zone) {}
19869 
zone() const19870   Zone* zone() const { return zone_; }
19871 
19872  private:
19873   Zone* zone_;
19874 };
19875 
19876 namespace {
19877 
ExportIndex(int cell_index)19878 int ExportIndex(int cell_index) {
19879   DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
19880             ModuleDescriptor::kExport);
19881   return cell_index - 1;
19882 }
19883 
ImportIndex(int cell_index)19884 int ImportIndex(int cell_index) {
19885   DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
19886             ModuleDescriptor::kImport);
19887   return -cell_index - 1;
19888 }
19889 
19890 }  // anonymous namespace
19891 
CreateIndirectExport(Handle<Module> module,Handle<String> name,Handle<ModuleInfoEntry> entry)19892 void Module::CreateIndirectExport(Handle<Module> module, Handle<String> name,
19893                                   Handle<ModuleInfoEntry> entry) {
19894   Isolate* isolate = module->GetIsolate();
19895   Handle<ObjectHashTable> exports(module->exports(), isolate);
19896   DCHECK(exports->Lookup(name)->IsTheHole(isolate));
19897   exports = ObjectHashTable::Put(exports, name, entry);
19898   module->set_exports(*exports);
19899 }
19900 
CreateExport(Handle<Module> module,int cell_index,Handle<FixedArray> names)19901 void Module::CreateExport(Handle<Module> module, int cell_index,
19902                           Handle<FixedArray> names) {
19903   DCHECK_LT(0, names->length());
19904   Isolate* isolate = module->GetIsolate();
19905 
19906   Handle<Cell> cell =
19907       isolate->factory()->NewCell(isolate->factory()->undefined_value());
19908   module->regular_exports()->set(ExportIndex(cell_index), *cell);
19909 
19910   Handle<ObjectHashTable> exports(module->exports(), isolate);
19911   for (int i = 0, n = names->length(); i < n; ++i) {
19912     Handle<String> name(String::cast(names->get(i)), isolate);
19913     DCHECK(exports->Lookup(name)->IsTheHole(isolate));
19914     exports = ObjectHashTable::Put(exports, name, cell);
19915   }
19916   module->set_exports(*exports);
19917 }
19918 
LoadVariable(Handle<Module> module,int cell_index)19919 Handle<Object> Module::LoadVariable(Handle<Module> module, int cell_index) {
19920   Isolate* isolate = module->GetIsolate();
19921   Handle<Object> object;
19922   switch (ModuleDescriptor::GetCellIndexKind(cell_index)) {
19923     case ModuleDescriptor::kImport:
19924       object = handle(module->regular_imports()->get(ImportIndex(cell_index)),
19925                       isolate);
19926       break;
19927     case ModuleDescriptor::kExport:
19928       object = handle(module->regular_exports()->get(ExportIndex(cell_index)),
19929                       isolate);
19930       break;
19931     case ModuleDescriptor::kInvalid:
19932       UNREACHABLE();
19933       break;
19934   }
19935   return handle(Handle<Cell>::cast(object)->value(), isolate);
19936 }
19937 
StoreVariable(Handle<Module> module,int cell_index,Handle<Object> value)19938 void Module::StoreVariable(Handle<Module> module, int cell_index,
19939                            Handle<Object> value) {
19940   Isolate* isolate = module->GetIsolate();
19941   DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
19942             ModuleDescriptor::kExport);
19943   Handle<Object> object(module->regular_exports()->get(ExportIndex(cell_index)),
19944                         isolate);
19945   Handle<Cell>::cast(object)->set_value(*value);
19946 }
19947 
ResolveImport(Handle<Module> module,Handle<String> name,int module_request,MessageLocation loc,bool must_resolve,Module::ResolveSet * resolve_set)19948 MaybeHandle<Cell> Module::ResolveImport(Handle<Module> module,
19949                                         Handle<String> name, int module_request,
19950                                         MessageLocation loc, bool must_resolve,
19951                                         Module::ResolveSet* resolve_set) {
19952   Isolate* isolate = module->GetIsolate();
19953   Handle<Module> requested_module(
19954       Module::cast(module->requested_modules()->get(module_request)), isolate);
19955   return Module::ResolveExport(requested_module, name, loc, must_resolve,
19956                                resolve_set);
19957 }
19958 
ResolveExport(Handle<Module> module,Handle<String> name,MessageLocation loc,bool must_resolve,Module::ResolveSet * resolve_set)19959 MaybeHandle<Cell> Module::ResolveExport(Handle<Module> module,
19960                                         Handle<String> name,
19961                                         MessageLocation loc, bool must_resolve,
19962                                         Module::ResolveSet* resolve_set) {
19963   Isolate* isolate = module->GetIsolate();
19964   Handle<Object> object(module->exports()->Lookup(name), isolate);
19965   if (object->IsCell()) {
19966     // Already resolved (e.g. because it's a local export).
19967     return Handle<Cell>::cast(object);
19968   }
19969 
19970   // Check for cycle before recursing.
19971   {
19972     // Attempt insertion with a null string set.
19973     auto result = resolve_set->insert({module, nullptr});
19974     UnorderedStringSet*& name_set = result.first->second;
19975     if (result.second) {
19976       // |module| wasn't in the map previously, so allocate a new name set.
19977       Zone* zone = resolve_set->zone();
19978       name_set =
19979           new (zone->New(sizeof(UnorderedStringSet))) UnorderedStringSet(zone);
19980     } else if (name_set->count(name)) {
19981       // Cycle detected.
19982       if (must_resolve) {
19983         return isolate->Throw<Cell>(
19984             isolate->factory()->NewSyntaxError(
19985                 MessageTemplate::kCyclicModuleDependency, name),
19986             &loc);
19987       }
19988       return MaybeHandle<Cell>();
19989     }
19990     name_set->insert(name);
19991   }
19992 
19993   if (object->IsModuleInfoEntry()) {
19994     // Not yet resolved indirect export.
19995     Handle<ModuleInfoEntry> entry = Handle<ModuleInfoEntry>::cast(object);
19996     Handle<String> import_name(String::cast(entry->import_name()), isolate);
19997     Handle<Script> script(
19998         Script::cast(JSFunction::cast(module->code())->shared()->script()),
19999         isolate);
20000     MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos());
20001 
20002     Handle<Cell> cell;
20003     if (!ResolveImport(module, import_name, entry->module_request(), new_loc,
20004                        true, resolve_set)
20005              .ToHandle(&cell)) {
20006       DCHECK(isolate->has_pending_exception());
20007       return MaybeHandle<Cell>();
20008     }
20009 
20010     // The export table may have changed but the entry in question should be
20011     // unchanged.
20012     Handle<ObjectHashTable> exports(module->exports(), isolate);
20013     DCHECK(exports->Lookup(name)->IsModuleInfoEntry());
20014 
20015     exports = ObjectHashTable::Put(exports, name, cell);
20016     module->set_exports(*exports);
20017     return cell;
20018   }
20019 
20020   DCHECK(object->IsTheHole(isolate));
20021   return Module::ResolveExportUsingStarExports(module, name, loc, must_resolve,
20022                                                resolve_set);
20023 }
20024 
ResolveExportUsingStarExports(Handle<Module> module,Handle<String> name,MessageLocation loc,bool must_resolve,Module::ResolveSet * resolve_set)20025 MaybeHandle<Cell> Module::ResolveExportUsingStarExports(
20026     Handle<Module> module, Handle<String> name, MessageLocation loc,
20027     bool must_resolve, Module::ResolveSet* resolve_set) {
20028   Isolate* isolate = module->GetIsolate();
20029   if (!name->Equals(isolate->heap()->default_string())) {
20030     // Go through all star exports looking for the given name.  If multiple star
20031     // exports provide the name, make sure they all map it to the same cell.
20032     Handle<Cell> unique_cell;
20033     Handle<FixedArray> special_exports(module->info()->special_exports(),
20034                                        isolate);
20035     for (int i = 0, n = special_exports->length(); i < n; ++i) {
20036       i::Handle<i::ModuleInfoEntry> entry(
20037           i::ModuleInfoEntry::cast(special_exports->get(i)), isolate);
20038       if (!entry->export_name()->IsUndefined(isolate)) {
20039         continue;  // Indirect export.
20040       }
20041 
20042       Handle<Script> script(
20043           Script::cast(JSFunction::cast(module->code())->shared()->script()),
20044           isolate);
20045       MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos());
20046 
20047       Handle<Cell> cell;
20048       if (ResolveImport(module, name, entry->module_request(), new_loc, false,
20049                         resolve_set)
20050               .ToHandle(&cell)) {
20051         if (unique_cell.is_null()) unique_cell = cell;
20052         if (*unique_cell != *cell) {
20053           return isolate->Throw<Cell>(
20054               isolate->factory()->NewSyntaxError(
20055                   MessageTemplate::kAmbiguousExport, name),
20056               &loc);
20057         }
20058       } else if (isolate->has_pending_exception()) {
20059         return MaybeHandle<Cell>();
20060       }
20061     }
20062 
20063     if (!unique_cell.is_null()) {
20064       // Found a unique star export for this name.
20065       Handle<ObjectHashTable> exports(module->exports(), isolate);
20066       DCHECK(exports->Lookup(name)->IsTheHole(isolate));
20067       exports = ObjectHashTable::Put(exports, name, unique_cell);
20068       module->set_exports(*exports);
20069       return unique_cell;
20070     }
20071   }
20072 
20073   // Unresolvable.
20074   if (must_resolve) {
20075     return isolate->Throw<Cell>(isolate->factory()->NewSyntaxError(
20076                                     MessageTemplate::kUnresolvableExport, name),
20077                                 &loc);
20078   }
20079   return MaybeHandle<Cell>();
20080 }
20081 
Instantiate(Handle<Module> module,v8::Local<v8::Context> context,v8::Module::ResolveCallback callback)20082 bool Module::Instantiate(Handle<Module> module, v8::Local<v8::Context> context,
20083                          v8::Module::ResolveCallback callback) {
20084   if (module->instantiated()) return true;
20085 
20086   Isolate* isolate = module->GetIsolate();
20087   Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(module->code()),
20088                                     isolate);
20089   Handle<JSFunction> function =
20090       isolate->factory()->NewFunctionFromSharedFunctionInfo(
20091           shared,
20092           handle(Utils::OpenHandle(*context)->native_context(), isolate));
20093   module->set_code(*function);
20094   DCHECK(module->instantiated());
20095 
20096   Handle<ModuleInfo> module_info(shared->scope_info()->ModuleDescriptorInfo(),
20097                                  isolate);
20098 
20099   // Set up local exports.
20100   // TODO(neis): Create regular_exports array here instead of in factory method?
20101   for (int i = 0, n = module_info->RegularExportCount(); i < n; ++i) {
20102     int cell_index = module_info->RegularExportCellIndex(i);
20103     Handle<FixedArray> export_names(module_info->RegularExportExportNames(i),
20104                                     isolate);
20105     CreateExport(module, cell_index, export_names);
20106   }
20107 
20108   // Partially set up indirect exports.
20109   // For each indirect export, we create the appropriate slot in the export
20110   // table and store its ModuleInfoEntry there.  When we later find the correct
20111   // Cell in the module that actually provides the value, we replace the
20112   // ModuleInfoEntry by that Cell (see ResolveExport).
20113   Handle<FixedArray> special_exports(module_info->special_exports(), isolate);
20114   for (int i = 0, n = special_exports->length(); i < n; ++i) {
20115     Handle<ModuleInfoEntry> entry(
20116         ModuleInfoEntry::cast(special_exports->get(i)), isolate);
20117     Handle<Object> export_name(entry->export_name(), isolate);
20118     if (export_name->IsUndefined(isolate)) continue;  // Star export.
20119     CreateIndirectExport(module, Handle<String>::cast(export_name), entry);
20120   }
20121 
20122   Handle<FixedArray> module_requests(module_info->module_requests(), isolate);
20123   for (int i = 0, length = module_requests->length(); i < length; ++i) {
20124     Handle<String> specifier(String::cast(module_requests->get(i)), isolate);
20125     v8::Local<v8::Module> api_requested_module;
20126     // TODO(adamk): Revisit these failure cases once d8 knows how to
20127     // persist a module_map across multiple top-level module loads, as
20128     // the current module is left in a "half-instantiated" state.
20129     if (!callback(context, v8::Utils::ToLocal(specifier),
20130                   v8::Utils::ToLocal(module))
20131              .ToLocal(&api_requested_module)) {
20132       // TODO(adamk): Give this a better error message. But this is a
20133       // misuse of the API anyway.
20134       isolate->ThrowIllegalOperation();
20135       return false;
20136     }
20137     Handle<Module> requested_module = Utils::OpenHandle(*api_requested_module);
20138     module->requested_modules()->set(i, *requested_module);
20139     if (!Instantiate(requested_module, context, callback)) {
20140       return false;
20141     }
20142   }
20143 
20144   Zone zone(isolate->allocator(), ZONE_NAME);
20145 
20146   // Resolve imports.
20147   Handle<FixedArray> regular_imports(module_info->regular_imports(), isolate);
20148   for (int i = 0, n = regular_imports->length(); i < n; ++i) {
20149     Handle<ModuleInfoEntry> entry(
20150         ModuleInfoEntry::cast(regular_imports->get(i)), isolate);
20151     Handle<String> name(String::cast(entry->import_name()), isolate);
20152     Handle<Script> script(
20153         Script::cast(JSFunction::cast(module->code())->shared()->script()),
20154         isolate);
20155     MessageLocation loc(script, entry->beg_pos(), entry->end_pos());
20156     ResolveSet resolve_set(&zone);
20157     Handle<Cell> cell;
20158     if (!ResolveImport(module, name, entry->module_request(), loc, true,
20159                        &resolve_set)
20160              .ToHandle(&cell)) {
20161       return false;
20162     }
20163     module->regular_imports()->set(ImportIndex(entry->cell_index()), *cell);
20164   }
20165 
20166   // Resolve indirect exports.
20167   for (int i = 0, n = special_exports->length(); i < n; ++i) {
20168     Handle<ModuleInfoEntry> entry(
20169         ModuleInfoEntry::cast(special_exports->get(i)), isolate);
20170     Handle<Object> name(entry->export_name(), isolate);
20171     if (name->IsUndefined(isolate)) continue;  // Star export.
20172     Handle<Script> script(
20173         Script::cast(JSFunction::cast(module->code())->shared()->script()),
20174         isolate);
20175     MessageLocation loc(script, entry->beg_pos(), entry->end_pos());
20176     ResolveSet resolve_set(&zone);
20177     if (ResolveExport(module, Handle<String>::cast(name), loc, true,
20178                       &resolve_set)
20179             .is_null()) {
20180       return false;
20181     }
20182   }
20183 
20184   return true;
20185 }
20186 
Evaluate(Handle<Module> module)20187 MaybeHandle<Object> Module::Evaluate(Handle<Module> module) {
20188   DCHECK(module->instantiated());
20189 
20190   // Each module can only be evaluated once.
20191   Isolate* isolate = module->GetIsolate();
20192   if (module->evaluated()) return isolate->factory()->undefined_value();
20193   Handle<JSFunction> function(JSFunction::cast(module->code()), isolate);
20194   module->set_evaluated();
20195 
20196   // Initialization.
20197   DCHECK_EQ(MODULE_SCOPE, function->shared()->scope_info()->scope_type());
20198   Handle<Object> receiver = isolate->factory()->undefined_value();
20199   Handle<Object> argv[] = {module};
20200   Handle<Object> generator;
20201   ASSIGN_RETURN_ON_EXCEPTION(
20202       isolate, generator,
20203       Execution::Call(isolate, function, receiver, arraysize(argv), argv),
20204       Object);
20205 
20206   // Recursion.
20207   Handle<FixedArray> requested_modules(module->requested_modules(), isolate);
20208   for (int i = 0, length = requested_modules->length(); i < length; ++i) {
20209     Handle<Module> import(Module::cast(requested_modules->get(i)), isolate);
20210     RETURN_ON_EXCEPTION(isolate, Evaluate(import), Object);
20211   }
20212 
20213   // Evaluation of module body.
20214   Handle<JSFunction> resume(
20215       isolate->native_context()->generator_next_internal(), isolate);
20216   return Execution::Call(isolate, resume, generator, 0, nullptr);
20217 }
20218 
20219 namespace {
20220 
FetchStarExports(Handle<Module> module,Zone * zone,UnorderedModuleSet * visited)20221 void FetchStarExports(Handle<Module> module, Zone* zone,
20222                       UnorderedModuleSet* visited) {
20223   DCHECK(module->instantiated());
20224 
20225   bool cycle = !visited->insert(module).second;
20226   if (cycle) return;
20227 
20228   Isolate* isolate = module->GetIsolate();
20229   Handle<ObjectHashTable> exports(module->exports(), isolate);
20230   UnorderedStringMap more_exports(zone);
20231 
20232   // TODO(neis): Only allocate more_exports if there are star exports.
20233   // Maybe split special_exports into indirect_exports and star_exports.
20234 
20235   Handle<FixedArray> special_exports(module->info()->special_exports(),
20236                                      isolate);
20237   for (int i = 0, n = special_exports->length(); i < n; ++i) {
20238     Handle<ModuleInfoEntry> entry(
20239         ModuleInfoEntry::cast(special_exports->get(i)), isolate);
20240     if (!entry->export_name()->IsUndefined(isolate)) {
20241       continue;  // Indirect export.
20242     }
20243 
20244     Handle<Module> requested_module(
20245         Module::cast(module->requested_modules()->get(entry->module_request())),
20246         isolate);
20247 
20248     // Recurse.
20249     FetchStarExports(requested_module, zone, visited);
20250 
20251     // Collect all of [requested_module]'s exports that must be added to
20252     // [module]'s exports (i.e. to [exports]).  We record these in
20253     // [more_exports].  Ambiguities (conflicting exports) are marked by mapping
20254     // the name to undefined instead of a Cell.
20255     Handle<ObjectHashTable> requested_exports(requested_module->exports(),
20256                                               isolate);
20257     for (int i = 0, n = requested_exports->Capacity(); i < n; ++i) {
20258       Handle<Object> key(requested_exports->KeyAt(i), isolate);
20259       if (!requested_exports->IsKey(isolate, *key)) continue;
20260       Handle<String> name = Handle<String>::cast(key);
20261 
20262       if (name->Equals(isolate->heap()->default_string())) continue;
20263       if (!exports->Lookup(name)->IsTheHole(isolate)) continue;
20264 
20265       Handle<Cell> cell(Cell::cast(requested_exports->ValueAt(i)), isolate);
20266       auto insert_result = more_exports.insert(std::make_pair(name, cell));
20267       if (!insert_result.second) {
20268         auto it = insert_result.first;
20269         if (*it->second == *cell || it->second->IsUndefined(isolate)) {
20270           // We already recorded this mapping before, or the name is already
20271           // known to be ambiguous.  In either case, there's nothing to do.
20272         } else {
20273           DCHECK(it->second->IsCell());
20274           // Different star exports provide different cells for this name, hence
20275           // mark the name as ambiguous.
20276           it->second = isolate->factory()->undefined_value();
20277         }
20278       }
20279     }
20280   }
20281 
20282   // Copy [more_exports] into [exports].
20283   for (const auto& elem : more_exports) {
20284     if (elem.second->IsUndefined(isolate)) continue;  // Ambiguous export.
20285     DCHECK(!elem.first->Equals(isolate->heap()->default_string()));
20286     DCHECK(elem.second->IsCell());
20287     exports = ObjectHashTable::Put(exports, elem.first, elem.second);
20288   }
20289   module->set_exports(*exports);
20290 }
20291 
20292 }  // anonymous namespace
20293 
GetModuleNamespace(Handle<Module> module,int module_request)20294 Handle<JSModuleNamespace> Module::GetModuleNamespace(Handle<Module> module,
20295                                                      int module_request) {
20296   Isolate* isolate = module->GetIsolate();
20297   Handle<Module> requested_module(
20298       Module::cast(module->requested_modules()->get(module_request)), isolate);
20299   return Module::GetModuleNamespace(requested_module);
20300 }
20301 
GetModuleNamespace(Handle<Module> module)20302 Handle<JSModuleNamespace> Module::GetModuleNamespace(Handle<Module> module) {
20303   Isolate* isolate = module->GetIsolate();
20304 
20305   Handle<HeapObject> object(module->module_namespace(), isolate);
20306   if (!object->IsUndefined(isolate)) {
20307     // Namespace object already exists.
20308     return Handle<JSModuleNamespace>::cast(object);
20309   }
20310 
20311   // Create the namespace object (initially empty).
20312   Handle<JSModuleNamespace> ns = isolate->factory()->NewJSModuleNamespace();
20313   ns->set_module(*module);
20314   module->set_module_namespace(*ns);
20315 
20316   // Collect the export names.
20317   Zone zone(isolate->allocator(), ZONE_NAME);
20318   UnorderedModuleSet visited(&zone);
20319   FetchStarExports(module, &zone, &visited);
20320   Handle<ObjectHashTable> exports(module->exports(), isolate);
20321   ZoneVector<Handle<String>> names(&zone);
20322   names.reserve(exports->NumberOfElements());
20323   for (int i = 0, n = exports->Capacity(); i < n; ++i) {
20324     Handle<Object> key(exports->KeyAt(i), isolate);
20325     if (!exports->IsKey(isolate, *key)) continue;
20326     DCHECK(exports->ValueAt(i)->IsCell());
20327     names.push_back(Handle<String>::cast(key));
20328   }
20329   DCHECK_EQ(static_cast<int>(names.size()), exports->NumberOfElements());
20330 
20331   // Sort them alphabetically.
20332   struct {
20333     bool operator()(Handle<String> a, Handle<String> b) {
20334       return String::Compare(a, b) == ComparisonResult::kLessThan;
20335     }
20336   } StringLess;
20337   std::sort(names.begin(), names.end(), StringLess);
20338 
20339   // Create the corresponding properties in the namespace object.
20340   PropertyAttributes attr = DONT_DELETE;
20341   for (const auto& name : names) {
20342     JSObject::SetAccessor(
20343         ns, Accessors::ModuleNamespaceEntryInfo(isolate, name, attr))
20344         .Check();
20345   }
20346   JSObject::PreventExtensions(ns, THROW_ON_ERROR).ToChecked();
20347 
20348   return ns;
20349 }
20350 
TryGetCachedPropertyName(Isolate * isolate,Handle<Object> getter)20351 MaybeHandle<Name> FunctionTemplateInfo::TryGetCachedPropertyName(
20352     Isolate* isolate, Handle<Object> getter) {
20353   if (getter->IsFunctionTemplateInfo()) {
20354     Handle<FunctionTemplateInfo> fti =
20355         Handle<FunctionTemplateInfo>::cast(getter);
20356     // Check if the accessor uses a cached property.
20357     if (!fti->cached_property_name()->IsTheHole(isolate)) {
20358       return handle(Name::cast(fti->cached_property_name()));
20359     }
20360   }
20361   return MaybeHandle<Name>();
20362 }
20363 
20364 // static
ElementsKindForInstanceType(InstanceType type)20365 ElementsKind JSArrayIterator::ElementsKindForInstanceType(InstanceType type) {
20366   DCHECK_GE(type, FIRST_ARRAY_ITERATOR_TYPE);
20367   DCHECK_LE(type, LAST_ARRAY_ITERATOR_TYPE);
20368 
20369   if (type <= LAST_ARRAY_KEY_ITERATOR_TYPE) {
20370     // Should be ignored for key iterators.
20371     return FAST_ELEMENTS;
20372   } else {
20373     ElementsKind kind;
20374     if (type < FIRST_ARRAY_VALUE_ITERATOR_TYPE) {
20375       // Convert `type` to a value iterator from an entries iterator
20376       type = static_cast<InstanceType>(type +
20377                                        (FIRST_ARRAY_VALUE_ITERATOR_TYPE -
20378                                         FIRST_ARRAY_KEY_VALUE_ITERATOR_TYPE));
20379       DCHECK_GE(type, FIRST_ARRAY_VALUE_ITERATOR_TYPE);
20380       DCHECK_LE(type, LAST_ARRAY_ITERATOR_TYPE);
20381     }
20382 
20383     if (type <= JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE) {
20384       kind =
20385           static_cast<ElementsKind>(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND +
20386                                     (type - FIRST_ARRAY_VALUE_ITERATOR_TYPE));
20387       DCHECK_LE(kind, LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
20388     } else if (type < JS_GENERIC_ARRAY_VALUE_ITERATOR_TYPE) {
20389       kind = static_cast<ElementsKind>(
20390           FIRST_FAST_ELEMENTS_KIND +
20391           (type - JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE));
20392       DCHECK_LE(kind, LAST_FAST_ELEMENTS_KIND);
20393     } else {
20394       // For any slow element cases, the actual elements kind is not known.
20395       // Simply
20396       // return a slow elements kind in this case. Users of this function must
20397       // not
20398       // depend on this.
20399       return DICTIONARY_ELEMENTS;
20400     }
20401     DCHECK_LE(kind, LAST_ELEMENTS_KIND);
20402     return kind;
20403   }
20404 }
20405 
20406 }  // namespace internal
20407 }  // namespace v8
20408