1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/objects.h"
6
7 #include <cmath>
8 #include <iomanip>
9 #include <memory>
10 #include <sstream>
11 #include <unordered_map>
12 #include <unordered_set>
13
14 #include "src/objects-inl.h"
15
16 #include "src/accessors.h"
17 #include "src/allocation-site-scopes.h"
18 #include "src/api-arguments-inl.h"
19 #include "src/api-natives.h"
20 #include "src/api.h"
21 #include "src/arguments.h"
22 #include "src/base/bits.h"
23 #include "src/base/utils/random-number-generator.h"
24 #include "src/bootstrapper.h"
25 #include "src/code-stubs.h"
26 #include "src/codegen.h"
27 #include "src/compilation-dependencies.h"
28 #include "src/compiler.h"
29 #include "src/counters-inl.h"
30 #include "src/counters.h"
31 #include "src/date.h"
32 #include "src/debug/debug-evaluate.h"
33 #include "src/debug/debug.h"
34 #include "src/deoptimizer.h"
35 #include "src/elements.h"
36 #include "src/execution.h"
37 #include "src/field-index-inl.h"
38 #include "src/field-index.h"
39 #include "src/field-type.h"
40 #include "src/frames-inl.h"
41 #include "src/full-codegen/full-codegen.h"
42 #include "src/globals.h"
43 #include "src/ic/ic.h"
44 #include "src/identity-map.h"
45 #include "src/interpreter/bytecode-array-iterator.h"
46 #include "src/interpreter/bytecode-decoder.h"
47 #include "src/interpreter/interpreter.h"
48 #include "src/isolate-inl.h"
49 #include "src/keys.h"
50 #include "src/list.h"
51 #include "src/log.h"
52 #include "src/lookup.h"
53 #include "src/macro-assembler.h"
54 #include "src/map-updater.h"
55 #include "src/messages.h"
56 #include "src/objects-body-descriptors-inl.h"
57 #include "src/property-descriptor.h"
58 #include "src/prototype.h"
59 #include "src/regexp/jsregexp.h"
60 #include "src/safepoint-table.h"
61 #include "src/snapshot/code-serializer.h"
62 #include "src/source-position-table.h"
63 #include "src/string-builder.h"
64 #include "src/string-search.h"
65 #include "src/string-stream.h"
66 #include "src/utils.h"
67 #include "src/wasm/wasm-module.h"
68 #include "src/wasm/wasm-objects.h"
69 #include "src/zone/zone.h"
70
71 #ifdef ENABLE_DISASSEMBLER
72 #include "src/disasm.h"
73 #include "src/disassembler.h"
74 #include "src/eh-frame.h"
75 #endif
76
77 namespace v8 {
78 namespace internal {
79
operator <<(std::ostream & os,InstanceType instance_type)80 std::ostream& operator<<(std::ostream& os, InstanceType instance_type) {
81 switch (instance_type) {
82 #define WRITE_TYPE(TYPE) \
83 case TYPE: \
84 return os << #TYPE;
85 INSTANCE_TYPE_LIST(WRITE_TYPE)
86 #undef WRITE_TYPE
87 }
88 UNREACHABLE();
89 return os << "UNKNOWN"; // Keep the compiler happy.
90 }
91
OptimalType(Isolate * isolate,Representation representation)92 Handle<FieldType> Object::OptimalType(Isolate* isolate,
93 Representation representation) {
94 if (representation.IsNone()) return FieldType::None(isolate);
95 if (FLAG_track_field_types) {
96 if (representation.IsHeapObject() && IsHeapObject()) {
97 // We can track only JavaScript objects with stable maps.
98 Handle<Map> map(HeapObject::cast(this)->map(), isolate);
99 if (map->is_stable() && map->IsJSReceiverMap()) {
100 return FieldType::Class(map, isolate);
101 }
102 }
103 }
104 return FieldType::Any(isolate);
105 }
106
107
ToObject(Isolate * isolate,Handle<Object> object,Handle<Context> native_context)108 MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
109 Handle<Object> object,
110 Handle<Context> native_context) {
111 if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
112 Handle<JSFunction> constructor;
113 if (object->IsSmi()) {
114 constructor = handle(native_context->number_function(), isolate);
115 } else {
116 int constructor_function_index =
117 Handle<HeapObject>::cast(object)->map()->GetConstructorFunctionIndex();
118 if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
119 THROW_NEW_ERROR(isolate,
120 NewTypeError(MessageTemplate::kUndefinedOrNullToObject),
121 JSReceiver);
122 }
123 constructor = handle(
124 JSFunction::cast(native_context->get(constructor_function_index)),
125 isolate);
126 }
127 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
128 Handle<JSValue>::cast(result)->set_value(*object);
129 return result;
130 }
131
132 // ES6 section 9.2.1.2, OrdinaryCallBindThis for sloppy callee.
133 // static
ConvertReceiver(Isolate * isolate,Handle<Object> object)134 MaybeHandle<JSReceiver> Object::ConvertReceiver(Isolate* isolate,
135 Handle<Object> object) {
136 if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
137 if (*object == isolate->heap()->null_value() ||
138 object->IsUndefined(isolate)) {
139 return isolate->global_proxy();
140 }
141 return Object::ToObject(isolate, object);
142 }
143
144 // static
ConvertToNumber(Isolate * isolate,Handle<Object> input)145 MaybeHandle<Object> Object::ConvertToNumber(Isolate* isolate,
146 Handle<Object> input) {
147 while (true) {
148 if (input->IsNumber()) {
149 return input;
150 }
151 if (input->IsString()) {
152 return String::ToNumber(Handle<String>::cast(input));
153 }
154 if (input->IsOddball()) {
155 return Oddball::ToNumber(Handle<Oddball>::cast(input));
156 }
157 if (input->IsSymbol()) {
158 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber),
159 Object);
160 }
161 ASSIGN_RETURN_ON_EXCEPTION(
162 isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
163 ToPrimitiveHint::kNumber),
164 Object);
165 }
166 }
167
168 // static
ConvertToInteger(Isolate * isolate,Handle<Object> input)169 MaybeHandle<Object> Object::ConvertToInteger(Isolate* isolate,
170 Handle<Object> input) {
171 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ConvertToNumber(isolate, input),
172 Object);
173 if (input->IsSmi()) return input;
174 return isolate->factory()->NewNumber(DoubleToInteger(input->Number()));
175 }
176
177 // static
ConvertToInt32(Isolate * isolate,Handle<Object> input)178 MaybeHandle<Object> Object::ConvertToInt32(Isolate* isolate,
179 Handle<Object> input) {
180 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ConvertToNumber(isolate, input),
181 Object);
182 if (input->IsSmi()) return input;
183 return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number()));
184 }
185
186 // static
ConvertToUint32(Isolate * isolate,Handle<Object> input)187 MaybeHandle<Object> Object::ConvertToUint32(Isolate* isolate,
188 Handle<Object> input) {
189 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ConvertToNumber(isolate, input),
190 Object);
191 if (input->IsSmi()) return handle(Smi::cast(*input)->ToUint32Smi(), isolate);
192 return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number()));
193 }
194
195 // static
ConvertToName(Isolate * isolate,Handle<Object> input)196 MaybeHandle<Name> Object::ConvertToName(Isolate* isolate,
197 Handle<Object> input) {
198 ASSIGN_RETURN_ON_EXCEPTION(
199 isolate, input, Object::ToPrimitive(input, ToPrimitiveHint::kString),
200 Name);
201 if (input->IsName()) return Handle<Name>::cast(input);
202 return ToString(isolate, input);
203 }
204
205 // ES6 7.1.14
206 // static
ConvertToPropertyKey(Isolate * isolate,Handle<Object> value)207 MaybeHandle<Object> Object::ConvertToPropertyKey(Isolate* isolate,
208 Handle<Object> value) {
209 // 1. Let key be ToPrimitive(argument, hint String).
210 MaybeHandle<Object> maybe_key =
211 Object::ToPrimitive(value, ToPrimitiveHint::kString);
212 // 2. ReturnIfAbrupt(key).
213 Handle<Object> key;
214 if (!maybe_key.ToHandle(&key)) return key;
215 // 3. If Type(key) is Symbol, then return key.
216 if (key->IsSymbol()) return key;
217 // 4. Return ToString(key).
218 // Extending spec'ed behavior, we'd be happy to return an element index.
219 if (key->IsSmi()) return key;
220 if (key->IsHeapNumber()) {
221 uint32_t uint_value;
222 if (value->ToArrayLength(&uint_value) &&
223 uint_value <= static_cast<uint32_t>(Smi::kMaxValue)) {
224 return handle(Smi::FromInt(static_cast<int>(uint_value)), isolate);
225 }
226 }
227 return Object::ToString(isolate, key);
228 }
229
230 // static
ConvertToString(Isolate * isolate,Handle<Object> input)231 MaybeHandle<String> Object::ConvertToString(Isolate* isolate,
232 Handle<Object> input) {
233 while (true) {
234 if (input->IsOddball()) {
235 return handle(Handle<Oddball>::cast(input)->to_string(), isolate);
236 }
237 if (input->IsNumber()) {
238 return isolate->factory()->NumberToString(input);
239 }
240 if (input->IsSymbol()) {
241 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToString),
242 String);
243 }
244 ASSIGN_RETURN_ON_EXCEPTION(
245 isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
246 ToPrimitiveHint::kString),
247 String);
248 // The previous isString() check happened in Object::ToString and thus we
249 // put it at the end of the loop in this helper.
250 if (input->IsString()) {
251 return Handle<String>::cast(input);
252 }
253 }
254 }
255
256 namespace {
257
IsErrorObject(Isolate * isolate,Handle<Object> object)258 bool IsErrorObject(Isolate* isolate, Handle<Object> object) {
259 if (!object->IsJSReceiver()) return false;
260 Handle<Symbol> symbol = isolate->factory()->stack_trace_symbol();
261 return JSReceiver::HasOwnProperty(Handle<JSReceiver>::cast(object), symbol)
262 .FromMaybe(false);
263 }
264
AsStringOrEmpty(Isolate * isolate,Handle<Object> object)265 Handle<String> AsStringOrEmpty(Isolate* isolate, Handle<Object> object) {
266 return object->IsString() ? Handle<String>::cast(object)
267 : isolate->factory()->empty_string();
268 }
269
NoSideEffectsErrorToString(Isolate * isolate,Handle<Object> input)270 Handle<String> NoSideEffectsErrorToString(Isolate* isolate,
271 Handle<Object> input) {
272 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input);
273
274 Handle<Name> name_key = isolate->factory()->name_string();
275 Handle<Object> name = JSReceiver::GetDataProperty(receiver, name_key);
276 Handle<String> name_str = AsStringOrEmpty(isolate, name);
277
278 Handle<Name> msg_key = isolate->factory()->message_string();
279 Handle<Object> msg = JSReceiver::GetDataProperty(receiver, msg_key);
280 Handle<String> msg_str = AsStringOrEmpty(isolate, msg);
281
282 if (name_str->length() == 0) return msg_str;
283 if (msg_str->length() == 0) return name_str;
284
285 IncrementalStringBuilder builder(isolate);
286 builder.AppendString(name_str);
287 builder.AppendCString(": ");
288 builder.AppendString(msg_str);
289
290 return builder.Finish().ToHandleChecked();
291 }
292
293 } // namespace
294
295 // static
NoSideEffectsToString(Isolate * isolate,Handle<Object> input)296 Handle<String> Object::NoSideEffectsToString(Isolate* isolate,
297 Handle<Object> input) {
298 DisallowJavascriptExecution no_js(isolate);
299
300 if (input->IsString() || input->IsNumber() || input->IsOddball()) {
301 return Object::ToString(isolate, input).ToHandleChecked();
302 } else if (input->IsFunction()) {
303 // -- F u n c t i o n
304 Handle<String> fun_str;
305 if (input->IsJSBoundFunction()) {
306 fun_str = JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(input));
307 } else {
308 DCHECK(input->IsJSFunction());
309 fun_str = JSFunction::ToString(Handle<JSFunction>::cast(input));
310 }
311
312 if (fun_str->length() > 128) {
313 IncrementalStringBuilder builder(isolate);
314 builder.AppendString(isolate->factory()->NewSubString(fun_str, 0, 111));
315 builder.AppendCString("...<omitted>...");
316 builder.AppendString(isolate->factory()->NewSubString(
317 fun_str, fun_str->length() - 2, fun_str->length()));
318
319 return builder.Finish().ToHandleChecked();
320 }
321 return fun_str;
322 } else if (input->IsSymbol()) {
323 // -- S y m b o l
324 Handle<Symbol> symbol = Handle<Symbol>::cast(input);
325
326 IncrementalStringBuilder builder(isolate);
327 builder.AppendCString("Symbol(");
328 if (symbol->name()->IsString()) {
329 builder.AppendString(handle(String::cast(symbol->name()), isolate));
330 }
331 builder.AppendCharacter(')');
332
333 return builder.Finish().ToHandleChecked();
334 } else if (input->IsJSReceiver()) {
335 // -- J S R e c e i v e r
336 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input);
337 Handle<Object> to_string = JSReceiver::GetDataProperty(
338 receiver, isolate->factory()->toString_string());
339
340 if (IsErrorObject(isolate, input) ||
341 *to_string == *isolate->error_to_string()) {
342 // When internally formatting error objects, use a side-effects-free
343 // version of Error.prototype.toString independent of the actually
344 // installed toString method.
345 return NoSideEffectsErrorToString(isolate, input);
346 } else if (*to_string == *isolate->object_to_string()) {
347 Handle<Object> ctor = JSReceiver::GetDataProperty(
348 receiver, isolate->factory()->constructor_string());
349 if (ctor->IsFunction()) {
350 Handle<String> ctor_name;
351 if (ctor->IsJSBoundFunction()) {
352 ctor_name = JSBoundFunction::GetName(
353 isolate, Handle<JSBoundFunction>::cast(ctor))
354 .ToHandleChecked();
355 } else if (ctor->IsJSFunction()) {
356 Handle<Object> ctor_name_obj =
357 JSFunction::GetName(isolate, Handle<JSFunction>::cast(ctor));
358 ctor_name = AsStringOrEmpty(isolate, ctor_name_obj);
359 }
360
361 if (ctor_name->length() != 0) {
362 IncrementalStringBuilder builder(isolate);
363 builder.AppendCString("#<");
364 builder.AppendString(ctor_name);
365 builder.AppendCString(">");
366
367 return builder.Finish().ToHandleChecked();
368 }
369 }
370 }
371 }
372
373 // At this point, input is either none of the above or a JSReceiver.
374
375 Handle<JSReceiver> receiver;
376 if (input->IsJSReceiver()) {
377 receiver = Handle<JSReceiver>::cast(input);
378 } else {
379 // This is the only case where Object::ToObject throws.
380 DCHECK(!input->IsSmi());
381 int constructor_function_index =
382 Handle<HeapObject>::cast(input)->map()->GetConstructorFunctionIndex();
383 if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
384 return isolate->factory()->NewStringFromAsciiChecked("[object Unknown]");
385 }
386
387 receiver = Object::ToObject(isolate, input, isolate->native_context())
388 .ToHandleChecked();
389 }
390
391 Handle<String> builtin_tag = handle(receiver->class_name(), isolate);
392 Handle<Object> tag_obj = JSReceiver::GetDataProperty(
393 receiver, isolate->factory()->to_string_tag_symbol());
394 Handle<String> tag =
395 tag_obj->IsString() ? Handle<String>::cast(tag_obj) : builtin_tag;
396
397 IncrementalStringBuilder builder(isolate);
398 builder.AppendCString("[object ");
399 builder.AppendString(tag);
400 builder.AppendCString("]");
401
402 return builder.Finish().ToHandleChecked();
403 }
404
405 // static
ConvertToLength(Isolate * isolate,Handle<Object> input)406 MaybeHandle<Object> Object::ConvertToLength(Isolate* isolate,
407 Handle<Object> input) {
408 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
409 if (input->IsSmi()) {
410 int value = std::max(Smi::cast(*input)->value(), 0);
411 return handle(Smi::FromInt(value), isolate);
412 }
413 double len = DoubleToInteger(input->Number());
414 if (len <= 0.0) {
415 return handle(Smi::kZero, isolate);
416 } else if (len >= kMaxSafeInteger) {
417 len = kMaxSafeInteger;
418 }
419 return isolate->factory()->NewNumber(len);
420 }
421
422 // static
ConvertToIndex(Isolate * isolate,Handle<Object> input,MessageTemplate::Template error_index)423 MaybeHandle<Object> Object::ConvertToIndex(
424 Isolate* isolate, Handle<Object> input,
425 MessageTemplate::Template error_index) {
426 if (input->IsUndefined(isolate)) return handle(Smi::kZero, isolate);
427 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
428 if (input->IsSmi() && Smi::cast(*input)->value() >= 0) return input;
429 double len = DoubleToInteger(input->Number()) + 0.0;
430 auto js_len = isolate->factory()->NewNumber(len);
431 if (len < 0.0 || len > kMaxSafeInteger) {
432 THROW_NEW_ERROR(isolate, NewRangeError(error_index, js_len), Object);
433 }
434 return js_len;
435 }
436
BooleanValue()437 bool Object::BooleanValue() {
438 if (IsSmi()) return Smi::cast(this)->value() != 0;
439 DCHECK(IsHeapObject());
440 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
441 if (IsBoolean()) return IsTrue(isolate);
442 if (IsNullOrUndefined(isolate)) return false;
443 if (IsUndetectable()) return false; // Undetectable object is false.
444 if (IsString()) return String::cast(this)->length() != 0;
445 if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue();
446 return true;
447 }
448
449
450 namespace {
451
452 // TODO(bmeurer): Maybe we should introduce a marker interface Number,
453 // where we put all these methods at some point?
NumberCompare(double x,double y)454 ComparisonResult NumberCompare(double x, double y) {
455 if (std::isnan(x) || std::isnan(y)) {
456 return ComparisonResult::kUndefined;
457 } else if (x < y) {
458 return ComparisonResult::kLessThan;
459 } else if (x > y) {
460 return ComparisonResult::kGreaterThan;
461 } else {
462 return ComparisonResult::kEqual;
463 }
464 }
465
466
NumberEquals(double x,double y)467 bool NumberEquals(double x, double y) {
468 // Must check explicitly for NaN's on Windows, but -0 works fine.
469 if (std::isnan(x)) return false;
470 if (std::isnan(y)) return false;
471 return x == y;
472 }
473
474
NumberEquals(const Object * x,const Object * y)475 bool NumberEquals(const Object* x, const Object* y) {
476 return NumberEquals(x->Number(), y->Number());
477 }
478
479
NumberEquals(Handle<Object> x,Handle<Object> y)480 bool NumberEquals(Handle<Object> x, Handle<Object> y) {
481 return NumberEquals(*x, *y);
482 }
483
484 } // namespace
485
486
487 // static
Compare(Handle<Object> x,Handle<Object> y)488 Maybe<ComparisonResult> Object::Compare(Handle<Object> x, Handle<Object> y) {
489 // ES6 section 7.2.11 Abstract Relational Comparison step 3 and 4.
490 if (!Object::ToPrimitive(x, ToPrimitiveHint::kNumber).ToHandle(&x) ||
491 !Object::ToPrimitive(y, ToPrimitiveHint::kNumber).ToHandle(&y)) {
492 return Nothing<ComparisonResult>();
493 }
494 if (x->IsString() && y->IsString()) {
495 // ES6 section 7.2.11 Abstract Relational Comparison step 5.
496 return Just(
497 String::Compare(Handle<String>::cast(x), Handle<String>::cast(y)));
498 }
499 // ES6 section 7.2.11 Abstract Relational Comparison step 6.
500 if (!Object::ToNumber(x).ToHandle(&x) || !Object::ToNumber(y).ToHandle(&y)) {
501 return Nothing<ComparisonResult>();
502 }
503 return Just(NumberCompare(x->Number(), y->Number()));
504 }
505
506
507 // static
Equals(Handle<Object> x,Handle<Object> y)508 Maybe<bool> Object::Equals(Handle<Object> x, Handle<Object> y) {
509 // This is the generic version of Abstract Equality Comparison; a version in
510 // JavaScript land is available in the EqualStub and NotEqualStub. Whenever
511 // you change something functionality wise in here, remember to update the
512 // TurboFan code stubs as well.
513 while (true) {
514 if (x->IsNumber()) {
515 if (y->IsNumber()) {
516 return Just(NumberEquals(x, y));
517 } else if (y->IsBoolean()) {
518 return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
519 } else if (y->IsString()) {
520 return Just(NumberEquals(x, String::ToNumber(Handle<String>::cast(y))));
521 } else if (y->IsJSReceiver()) {
522 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
523 .ToHandle(&y)) {
524 return Nothing<bool>();
525 }
526 } else {
527 return Just(false);
528 }
529 } else if (x->IsString()) {
530 if (y->IsString()) {
531 return Just(
532 String::Equals(Handle<String>::cast(x), Handle<String>::cast(y)));
533 } else if (y->IsNumber()) {
534 x = String::ToNumber(Handle<String>::cast(x));
535 return Just(NumberEquals(x, y));
536 } else if (y->IsBoolean()) {
537 x = String::ToNumber(Handle<String>::cast(x));
538 return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
539 } else if (y->IsJSReceiver()) {
540 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
541 .ToHandle(&y)) {
542 return Nothing<bool>();
543 }
544 } else {
545 return Just(false);
546 }
547 } else if (x->IsBoolean()) {
548 if (y->IsOddball()) {
549 return Just(x.is_identical_to(y));
550 } else if (y->IsNumber()) {
551 return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
552 } else if (y->IsString()) {
553 y = String::ToNumber(Handle<String>::cast(y));
554 return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y));
555 } else if (y->IsJSReceiver()) {
556 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
557 .ToHandle(&y)) {
558 return Nothing<bool>();
559 }
560 x = Oddball::ToNumber(Handle<Oddball>::cast(x));
561 } else {
562 return Just(false);
563 }
564 } else if (x->IsSymbol()) {
565 if (y->IsSymbol()) {
566 return Just(x.is_identical_to(y));
567 } else if (y->IsJSReceiver()) {
568 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
569 .ToHandle(&y)) {
570 return Nothing<bool>();
571 }
572 } else {
573 return Just(false);
574 }
575 } else if (x->IsJSReceiver()) {
576 if (y->IsJSReceiver()) {
577 return Just(x.is_identical_to(y));
578 } else if (y->IsUndetectable()) {
579 return Just(x->IsUndetectable());
580 } else if (y->IsBoolean()) {
581 y = Oddball::ToNumber(Handle<Oddball>::cast(y));
582 } else if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(x))
583 .ToHandle(&x)) {
584 return Nothing<bool>();
585 }
586 } else {
587 return Just(x->IsUndetectable() && y->IsUndetectable());
588 }
589 }
590 }
591
592
StrictEquals(Object * that)593 bool Object::StrictEquals(Object* that) {
594 if (this->IsNumber()) {
595 if (!that->IsNumber()) return false;
596 return NumberEquals(this, that);
597 } else if (this->IsString()) {
598 if (!that->IsString()) return false;
599 return String::cast(this)->Equals(String::cast(that));
600 }
601 return this == that;
602 }
603
604
605 // static
TypeOf(Isolate * isolate,Handle<Object> object)606 Handle<String> Object::TypeOf(Isolate* isolate, Handle<Object> object) {
607 if (object->IsNumber()) return isolate->factory()->number_string();
608 if (object->IsOddball()) return handle(Oddball::cast(*object)->type_of());
609 if (object->IsUndetectable()) {
610 return isolate->factory()->undefined_string();
611 }
612 if (object->IsString()) return isolate->factory()->string_string();
613 if (object->IsSymbol()) return isolate->factory()->symbol_string();
614 if (object->IsString()) return isolate->factory()->string_string();
615 if (object->IsCallable()) return isolate->factory()->function_string();
616 return isolate->factory()->object_string();
617 }
618
619
620 // static
Multiply(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)621 MaybeHandle<Object> Object::Multiply(Isolate* isolate, Handle<Object> lhs,
622 Handle<Object> rhs) {
623 if (!lhs->IsNumber() || !rhs->IsNumber()) {
624 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
625 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
626 }
627 return isolate->factory()->NewNumber(lhs->Number() * rhs->Number());
628 }
629
630
631 // static
Divide(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)632 MaybeHandle<Object> Object::Divide(Isolate* isolate, Handle<Object> lhs,
633 Handle<Object> rhs) {
634 if (!lhs->IsNumber() || !rhs->IsNumber()) {
635 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
636 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
637 }
638 return isolate->factory()->NewNumber(lhs->Number() / rhs->Number());
639 }
640
641
642 // static
Modulus(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)643 MaybeHandle<Object> Object::Modulus(Isolate* isolate, Handle<Object> lhs,
644 Handle<Object> rhs) {
645 if (!lhs->IsNumber() || !rhs->IsNumber()) {
646 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
647 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
648 }
649 return isolate->factory()->NewNumber(modulo(lhs->Number(), rhs->Number()));
650 }
651
652
653 // static
Add(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)654 MaybeHandle<Object> Object::Add(Isolate* isolate, Handle<Object> lhs,
655 Handle<Object> rhs) {
656 if (lhs->IsNumber() && rhs->IsNumber()) {
657 return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
658 } else if (lhs->IsString() && rhs->IsString()) {
659 return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
660 Handle<String>::cast(rhs));
661 }
662 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToPrimitive(lhs), Object);
663 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToPrimitive(rhs), Object);
664 if (lhs->IsString() || rhs->IsString()) {
665 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToString(isolate, rhs),
666 Object);
667 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToString(isolate, lhs),
668 Object);
669 return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
670 Handle<String>::cast(rhs));
671 }
672 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
673 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
674 return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
675 }
676
677
678 // static
Subtract(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)679 MaybeHandle<Object> Object::Subtract(Isolate* isolate, Handle<Object> lhs,
680 Handle<Object> rhs) {
681 if (!lhs->IsNumber() || !rhs->IsNumber()) {
682 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
683 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
684 }
685 return isolate->factory()->NewNumber(lhs->Number() - rhs->Number());
686 }
687
688
689 // static
ShiftLeft(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)690 MaybeHandle<Object> Object::ShiftLeft(Isolate* isolate, Handle<Object> lhs,
691 Handle<Object> rhs) {
692 if (!lhs->IsNumber() || !rhs->IsNumber()) {
693 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
694 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
695 }
696 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs)
697 << (NumberToUint32(*rhs) & 0x1F));
698 }
699
700
701 // static
ShiftRight(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)702 MaybeHandle<Object> Object::ShiftRight(Isolate* isolate, Handle<Object> lhs,
703 Handle<Object> rhs) {
704 if (!lhs->IsNumber() || !rhs->IsNumber()) {
705 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
706 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
707 }
708 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) >>
709 (NumberToUint32(*rhs) & 0x1F));
710 }
711
712
713 // static
ShiftRightLogical(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)714 MaybeHandle<Object> Object::ShiftRightLogical(Isolate* isolate,
715 Handle<Object> lhs,
716 Handle<Object> rhs) {
717 if (!lhs->IsNumber() || !rhs->IsNumber()) {
718 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
719 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
720 }
721 return isolate->factory()->NewNumberFromUint(NumberToUint32(*lhs) >>
722 (NumberToUint32(*rhs) & 0x1F));
723 }
724
725
726 // static
BitwiseAnd(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)727 MaybeHandle<Object> Object::BitwiseAnd(Isolate* isolate, Handle<Object> lhs,
728 Handle<Object> rhs) {
729 if (!lhs->IsNumber() || !rhs->IsNumber()) {
730 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
731 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
732 }
733 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) &
734 NumberToInt32(*rhs));
735 }
736
737
738 // static
BitwiseOr(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)739 MaybeHandle<Object> Object::BitwiseOr(Isolate* isolate, Handle<Object> lhs,
740 Handle<Object> rhs) {
741 if (!lhs->IsNumber() || !rhs->IsNumber()) {
742 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
743 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
744 }
745 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) |
746 NumberToInt32(*rhs));
747 }
748
749
750 // static
BitwiseXor(Isolate * isolate,Handle<Object> lhs,Handle<Object> rhs)751 MaybeHandle<Object> Object::BitwiseXor(Isolate* isolate, Handle<Object> lhs,
752 Handle<Object> rhs) {
753 if (!lhs->IsNumber() || !rhs->IsNumber()) {
754 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
755 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
756 }
757 return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) ^
758 NumberToInt32(*rhs));
759 }
760
761 // static
OrdinaryHasInstance(Isolate * isolate,Handle<Object> callable,Handle<Object> object)762 MaybeHandle<Object> Object::OrdinaryHasInstance(Isolate* isolate,
763 Handle<Object> callable,
764 Handle<Object> object) {
765 // The {callable} must have a [[Call]] internal method.
766 if (!callable->IsCallable()) return isolate->factory()->false_value();
767
768 // Check if {callable} is a bound function, and if so retrieve its
769 // [[BoundTargetFunction]] and use that instead of {callable}.
770 if (callable->IsJSBoundFunction()) {
771 Handle<Object> bound_callable(
772 Handle<JSBoundFunction>::cast(callable)->bound_target_function(),
773 isolate);
774 return Object::InstanceOf(isolate, object, bound_callable);
775 }
776
777 // If {object} is not a receiver, return false.
778 if (!object->IsJSReceiver()) return isolate->factory()->false_value();
779
780 // Get the "prototype" of {callable}; raise an error if it's not a receiver.
781 Handle<Object> prototype;
782 ASSIGN_RETURN_ON_EXCEPTION(
783 isolate, prototype,
784 Object::GetProperty(callable, isolate->factory()->prototype_string()),
785 Object);
786 if (!prototype->IsJSReceiver()) {
787 THROW_NEW_ERROR(
788 isolate,
789 NewTypeError(MessageTemplate::kInstanceofNonobjectProto, prototype),
790 Object);
791 }
792
793 // Return whether or not {prototype} is in the prototype chain of {object}.
794 Maybe<bool> result = JSReceiver::HasInPrototypeChain(
795 isolate, Handle<JSReceiver>::cast(object), prototype);
796 if (result.IsNothing()) return MaybeHandle<Object>();
797 return isolate->factory()->ToBoolean(result.FromJust());
798 }
799
800 // static
InstanceOf(Isolate * isolate,Handle<Object> object,Handle<Object> callable)801 MaybeHandle<Object> Object::InstanceOf(Isolate* isolate, Handle<Object> object,
802 Handle<Object> callable) {
803 // The {callable} must be a receiver.
804 if (!callable->IsJSReceiver()) {
805 THROW_NEW_ERROR(isolate,
806 NewTypeError(MessageTemplate::kNonObjectInInstanceOfCheck),
807 Object);
808 }
809
810 // Lookup the @@hasInstance method on {callable}.
811 Handle<Object> inst_of_handler;
812 ASSIGN_RETURN_ON_EXCEPTION(
813 isolate, inst_of_handler,
814 JSReceiver::GetMethod(Handle<JSReceiver>::cast(callable),
815 isolate->factory()->has_instance_symbol()),
816 Object);
817 if (!inst_of_handler->IsUndefined(isolate)) {
818 // Call the {inst_of_handler} on the {callable}.
819 Handle<Object> result;
820 ASSIGN_RETURN_ON_EXCEPTION(
821 isolate, result,
822 Execution::Call(isolate, inst_of_handler, callable, 1, &object),
823 Object);
824 return isolate->factory()->ToBoolean(result->BooleanValue());
825 }
826
827 // The {callable} must have a [[Call]] internal method.
828 if (!callable->IsCallable()) {
829 THROW_NEW_ERROR(
830 isolate, NewTypeError(MessageTemplate::kNonCallableInInstanceOfCheck),
831 Object);
832 }
833
834 // Fall back to OrdinaryHasInstance with {callable} and {object}.
835 Handle<Object> result;
836 ASSIGN_RETURN_ON_EXCEPTION(
837 isolate, result,
838 JSReceiver::OrdinaryHasInstance(isolate, callable, object), Object);
839 return result;
840 }
841
IsArray(Handle<Object> object)842 Maybe<bool> Object::IsArray(Handle<Object> object) {
843 if (object->IsJSArray()) return Just(true);
844 if (object->IsJSProxy()) {
845 Handle<JSProxy> proxy = Handle<JSProxy>::cast(object);
846 Isolate* isolate = proxy->GetIsolate();
847 if (proxy->IsRevoked()) {
848 isolate->Throw(*isolate->factory()->NewTypeError(
849 MessageTemplate::kProxyRevoked,
850 isolate->factory()->NewStringFromAsciiChecked("IsArray")));
851 return Nothing<bool>();
852 }
853 return Object::IsArray(handle(proxy->target(), isolate));
854 }
855 return Just(false);
856 }
857
858
859 // static
GetMethod(Handle<JSReceiver> receiver,Handle<Name> name)860 MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
861 Handle<Name> name) {
862 Handle<Object> func;
863 Isolate* isolate = receiver->GetIsolate();
864 ASSIGN_RETURN_ON_EXCEPTION(isolate, func,
865 JSReceiver::GetProperty(receiver, name), Object);
866 if (func->IsNullOrUndefined(isolate)) {
867 return isolate->factory()->undefined_value();
868 }
869 if (!func->IsCallable()) {
870 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kPropertyNotFunction,
871 func, name, receiver),
872 Object);
873 }
874 return func;
875 }
876
877 namespace {
CreateListFromArrayLikeFastPath(Isolate * isolate,Handle<Object> object,ElementTypes element_types)878 MaybeHandle<FixedArray> CreateListFromArrayLikeFastPath(
879 Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
880 if (element_types != ElementTypes::kAll || !object->IsJSArray()) {
881 return MaybeHandle<FixedArray>();
882 }
883 Handle<JSArray> array = Handle<JSArray>::cast(object);
884 uint32_t length;
885 if (!array->HasArrayPrototype(isolate) ||
886 !array->length()->ToUint32(&length) || !array->HasFastElements() ||
887 !JSObject::PrototypeHasNoElements(isolate, *array)) {
888 return MaybeHandle<FixedArray>();
889 }
890 return array->GetElementsAccessor()->CreateListFromArray(isolate, array);
891 }
892 } // namespace
893
894 // static
CreateListFromArrayLike(Isolate * isolate,Handle<Object> object,ElementTypes element_types)895 MaybeHandle<FixedArray> Object::CreateListFromArrayLike(
896 Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
897 // Fast-path for JS_ARRAY_TYPE.
898 MaybeHandle<FixedArray> fast_result =
899 CreateListFromArrayLikeFastPath(isolate, object, element_types);
900 if (!fast_result.is_null()) return fast_result;
901 // 1. ReturnIfAbrupt(object).
902 // 2. (default elementTypes -- not applicable.)
903 // 3. If Type(obj) is not Object, throw a TypeError exception.
904 if (!object->IsJSReceiver()) {
905 THROW_NEW_ERROR(isolate,
906 NewTypeError(MessageTemplate::kCalledOnNonObject,
907 isolate->factory()->NewStringFromAsciiChecked(
908 "CreateListFromArrayLike")),
909 FixedArray);
910 }
911
912 // 4. Let len be ? ToLength(? Get(obj, "length")).
913 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
914 Handle<Object> raw_length_number;
915 ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number,
916 Object::GetLengthFromArrayLike(isolate, receiver),
917 FixedArray);
918 uint32_t len;
919 if (!raw_length_number->ToUint32(&len) ||
920 len > static_cast<uint32_t>(FixedArray::kMaxLength)) {
921 THROW_NEW_ERROR(isolate,
922 NewRangeError(MessageTemplate::kInvalidArrayLength),
923 FixedArray);
924 }
925 // 5. Let list be an empty List.
926 Handle<FixedArray> list = isolate->factory()->NewFixedArray(len);
927 // 6. Let index be 0.
928 // 7. Repeat while index < len:
929 for (uint32_t index = 0; index < len; ++index) {
930 // 7a. Let indexName be ToString(index).
931 // 7b. Let next be ? Get(obj, indexName).
932 Handle<Object> next;
933 ASSIGN_RETURN_ON_EXCEPTION(isolate, next,
934 JSReceiver::GetElement(isolate, receiver, index),
935 FixedArray);
936 switch (element_types) {
937 case ElementTypes::kAll:
938 // Nothing to do.
939 break;
940 case ElementTypes::kStringAndSymbol: {
941 // 7c. If Type(next) is not an element of elementTypes, throw a
942 // TypeError exception.
943 if (!next->IsName()) {
944 THROW_NEW_ERROR(isolate,
945 NewTypeError(MessageTemplate::kNotPropertyName, next),
946 FixedArray);
947 }
948 // 7d. Append next as the last element of list.
949 // Internalize on the fly so we can use pointer identity later.
950 next = isolate->factory()->InternalizeName(Handle<Name>::cast(next));
951 break;
952 }
953 }
954 list->set(index, *next);
955 // 7e. Set index to index + 1. (See loop header.)
956 }
957 // 8. Return list.
958 return list;
959 }
960
961
962 // static
GetLengthFromArrayLike(Isolate * isolate,Handle<Object> object)963 MaybeHandle<Object> Object::GetLengthFromArrayLike(Isolate* isolate,
964 Handle<Object> object) {
965 Handle<Object> val;
966 Handle<Object> key = isolate->factory()->length_string();
967 ASSIGN_RETURN_ON_EXCEPTION(
968 isolate, val, Runtime::GetObjectProperty(isolate, object, key), Object);
969 return Object::ToLength(isolate, val);
970 }
971
972 // static
HasProperty(LookupIterator * it)973 Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) {
974 for (; it->IsFound(); it->Next()) {
975 switch (it->state()) {
976 case LookupIterator::NOT_FOUND:
977 case LookupIterator::TRANSITION:
978 UNREACHABLE();
979 case LookupIterator::JSPROXY:
980 return JSProxy::HasProperty(it->isolate(), it->GetHolder<JSProxy>(),
981 it->GetName());
982 case LookupIterator::INTERCEPTOR: {
983 Maybe<PropertyAttributes> result =
984 JSObject::GetPropertyAttributesWithInterceptor(it);
985 if (result.IsNothing()) return Nothing<bool>();
986 if (result.FromJust() != ABSENT) return Just(true);
987 break;
988 }
989 case LookupIterator::ACCESS_CHECK: {
990 if (it->HasAccess()) break;
991 Maybe<PropertyAttributes> result =
992 JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
993 if (result.IsNothing()) return Nothing<bool>();
994 return Just(result.FromJust() != ABSENT);
995 }
996 case LookupIterator::INTEGER_INDEXED_EXOTIC:
997 // TypedArray out-of-bounds access.
998 return Just(false);
999 case LookupIterator::ACCESSOR:
1000 case LookupIterator::DATA:
1001 return Just(true);
1002 }
1003 }
1004 return Just(false);
1005 }
1006
1007
1008 // static
GetProperty(LookupIterator * it)1009 MaybeHandle<Object> Object::GetProperty(LookupIterator* it) {
1010 for (; it->IsFound(); it->Next()) {
1011 switch (it->state()) {
1012 case LookupIterator::NOT_FOUND:
1013 case LookupIterator::TRANSITION:
1014 UNREACHABLE();
1015 case LookupIterator::JSPROXY: {
1016 bool was_found;
1017 MaybeHandle<Object> result =
1018 JSProxy::GetProperty(it->isolate(), it->GetHolder<JSProxy>(),
1019 it->GetName(), it->GetReceiver(), &was_found);
1020 if (!was_found) it->NotFound();
1021 return result;
1022 }
1023 case LookupIterator::INTERCEPTOR: {
1024 bool done;
1025 Handle<Object> result;
1026 ASSIGN_RETURN_ON_EXCEPTION(
1027 it->isolate(), result,
1028 JSObject::GetPropertyWithInterceptor(it, &done), Object);
1029 if (done) return result;
1030 break;
1031 }
1032 case LookupIterator::ACCESS_CHECK:
1033 if (it->HasAccess()) break;
1034 return JSObject::GetPropertyWithFailedAccessCheck(it);
1035 case LookupIterator::ACCESSOR:
1036 return GetPropertyWithAccessor(it);
1037 case LookupIterator::INTEGER_INDEXED_EXOTIC:
1038 return it->isolate()->factory()->undefined_value();
1039 case LookupIterator::DATA:
1040 return it->GetDataValue();
1041 }
1042 }
1043 return it->isolate()->factory()->undefined_value();
1044 }
1045
1046
1047 // static
GetProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Name> name,Handle<Object> receiver,bool * was_found)1048 MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
1049 Handle<JSProxy> proxy,
1050 Handle<Name> name,
1051 Handle<Object> receiver,
1052 bool* was_found) {
1053 *was_found = true;
1054 if (receiver->IsJSGlobalObject()) {
1055 THROW_NEW_ERROR(
1056 isolate,
1057 NewTypeError(MessageTemplate::kReadGlobalReferenceThroughProxy, name),
1058 Object);
1059 }
1060
1061 DCHECK(!name->IsPrivate());
1062 STACK_CHECK(isolate, MaybeHandle<Object>());
1063 Handle<Name> trap_name = isolate->factory()->get_string();
1064 // 1. Assert: IsPropertyKey(P) is true.
1065 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
1066 Handle<Object> handler(proxy->handler(), isolate);
1067 // 3. If handler is null, throw a TypeError exception.
1068 // 4. Assert: Type(handler) is Object.
1069 if (proxy->IsRevoked()) {
1070 THROW_NEW_ERROR(isolate,
1071 NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1072 Object);
1073 }
1074 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
1075 Handle<JSReceiver> target(proxy->target(), isolate);
1076 // 6. Let trap be ? GetMethod(handler, "get").
1077 Handle<Object> trap;
1078 ASSIGN_RETURN_ON_EXCEPTION(
1079 isolate, trap,
1080 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), Object);
1081 // 7. If trap is undefined, then
1082 if (trap->IsUndefined(isolate)) {
1083 // 7.a Return target.[[Get]](P, Receiver).
1084 LookupIterator it =
1085 LookupIterator::PropertyOrElement(isolate, receiver, name, target);
1086 MaybeHandle<Object> result = Object::GetProperty(&it);
1087 *was_found = it.IsFound();
1088 return result;
1089 }
1090 // 8. Let trapResult be ? Call(trap, handler, «target, P, Receiver»).
1091 Handle<Object> trap_result;
1092 Handle<Object> args[] = {target, name, receiver};
1093 ASSIGN_RETURN_ON_EXCEPTION(
1094 isolate, trap_result,
1095 Execution::Call(isolate, trap, handler, arraysize(args), args), Object);
1096 // 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
1097 PropertyDescriptor target_desc;
1098 Maybe<bool> target_found =
1099 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
1100 MAYBE_RETURN_NULL(target_found);
1101 // 10. If targetDesc is not undefined, then
1102 if (target_found.FromJust()) {
1103 // 10.a. If IsDataDescriptor(targetDesc) and targetDesc.[[Configurable]] is
1104 // false and targetDesc.[[Writable]] is false, then
1105 // 10.a.i. If SameValue(trapResult, targetDesc.[[Value]]) is false,
1106 // throw a TypeError exception.
1107 bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
1108 !target_desc.configurable() &&
1109 !target_desc.writable() &&
1110 !trap_result->SameValue(*target_desc.value());
1111 if (inconsistent) {
1112 THROW_NEW_ERROR(
1113 isolate, NewTypeError(MessageTemplate::kProxyGetNonConfigurableData,
1114 name, target_desc.value(), trap_result),
1115 Object);
1116 }
1117 // 10.b. If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]]
1118 // is false and targetDesc.[[Get]] is undefined, then
1119 // 10.b.i. If trapResult is not undefined, throw a TypeError exception.
1120 inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
1121 !target_desc.configurable() &&
1122 target_desc.get()->IsUndefined(isolate) &&
1123 !trap_result->IsUndefined(isolate);
1124 if (inconsistent) {
1125 THROW_NEW_ERROR(
1126 isolate,
1127 NewTypeError(MessageTemplate::kProxyGetNonConfigurableAccessor, name,
1128 trap_result),
1129 Object);
1130 }
1131 }
1132 // 11. Return trap_result
1133 return trap_result;
1134 }
1135
1136
GetDataProperty(LookupIterator * it)1137 Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it) {
1138 for (; it->IsFound(); it->Next()) {
1139 switch (it->state()) {
1140 case LookupIterator::INTERCEPTOR:
1141 case LookupIterator::NOT_FOUND:
1142 case LookupIterator::TRANSITION:
1143 UNREACHABLE();
1144 case LookupIterator::ACCESS_CHECK:
1145 // Support calling this method without an active context, but refuse
1146 // access to access-checked objects in that case.
1147 if (it->isolate()->context() != nullptr && it->HasAccess()) continue;
1148 // Fall through.
1149 case LookupIterator::JSPROXY:
1150 it->NotFound();
1151 return it->isolate()->factory()->undefined_value();
1152 case LookupIterator::ACCESSOR:
1153 // TODO(verwaest): For now this doesn't call into AccessorInfo, since
1154 // clients don't need it. Update once relevant.
1155 it->NotFound();
1156 return it->isolate()->factory()->undefined_value();
1157 case LookupIterator::INTEGER_INDEXED_EXOTIC:
1158 return it->isolate()->factory()->undefined_value();
1159 case LookupIterator::DATA:
1160 return it->GetDataValue();
1161 }
1162 }
1163 return it->isolate()->factory()->undefined_value();
1164 }
1165
1166
ToInt32(int32_t * value)1167 bool Object::ToInt32(int32_t* value) {
1168 if (IsSmi()) {
1169 *value = Smi::cast(this)->value();
1170 return true;
1171 }
1172 if (IsHeapNumber()) {
1173 double num = HeapNumber::cast(this)->value();
1174 if (FastI2D(FastD2I(num)) == num) {
1175 *value = FastD2I(num);
1176 return true;
1177 }
1178 }
1179 return false;
1180 }
1181
GetOrCreateSharedFunctionInfo(Isolate * isolate,Handle<FunctionTemplateInfo> info)1182 Handle<SharedFunctionInfo> FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(
1183 Isolate* isolate, Handle<FunctionTemplateInfo> info) {
1184 Object* current_info = info->shared_function_info();
1185 if (current_info->IsSharedFunctionInfo()) {
1186 return handle(SharedFunctionInfo::cast(current_info), isolate);
1187 }
1188
1189 Handle<Object> class_name(info->class_name(), isolate);
1190 Handle<String> name = class_name->IsString()
1191 ? Handle<String>::cast(class_name)
1192 : isolate->factory()->empty_string();
1193 Handle<Code> code;
1194 if (info->call_code()->IsCallHandlerInfo() &&
1195 CallHandlerInfo::cast(info->call_code())->fast_handler()->IsCode()) {
1196 code = isolate->builtins()->HandleFastApiCall();
1197 } else {
1198 code = isolate->builtins()->HandleApiCall();
1199 }
1200 bool is_constructor = !info->remove_prototype();
1201 Handle<SharedFunctionInfo> result =
1202 isolate->factory()->NewSharedFunctionInfo(name, code, is_constructor);
1203 if (is_constructor) {
1204 result->SetConstructStub(*isolate->builtins()->JSConstructStubApi());
1205 }
1206
1207 result->set_length(info->length());
1208 if (class_name->IsString()) result->set_instance_class_name(*class_name);
1209 result->set_api_func_data(*info);
1210 result->DontAdaptArguments();
1211 DCHECK(result->IsApiFunction());
1212
1213 info->set_shared_function_info(*result);
1214 return result;
1215 }
1216
IsTemplateFor(Map * map)1217 bool FunctionTemplateInfo::IsTemplateFor(Map* map) {
1218 // There is a constraint on the object; check.
1219 if (!map->IsJSObjectMap()) return false;
1220 // Fetch the constructor function of the object.
1221 Object* cons_obj = map->GetConstructor();
1222 if (!cons_obj->IsJSFunction()) return false;
1223 JSFunction* fun = JSFunction::cast(cons_obj);
1224 // Iterate through the chain of inheriting function templates to
1225 // see if the required one occurs.
1226 for (Object* type = fun->shared()->function_data();
1227 type->IsFunctionTemplateInfo();
1228 type = FunctionTemplateInfo::cast(type)->parent_template()) {
1229 if (type == this) return true;
1230 }
1231 // Didn't find the required type in the inheritance chain.
1232 return false;
1233 }
1234
1235
1236 // static
New(Isolate * isolate,int size)1237 Handle<TemplateList> TemplateList::New(Isolate* isolate, int size) {
1238 Handle<FixedArray> list =
1239 isolate->factory()->NewFixedArray(kLengthIndex + size);
1240 list->set(kLengthIndex, Smi::kZero);
1241 return Handle<TemplateList>::cast(list);
1242 }
1243
1244 // static
Add(Isolate * isolate,Handle<TemplateList> list,Handle<i::Object> value)1245 Handle<TemplateList> TemplateList::Add(Isolate* isolate,
1246 Handle<TemplateList> list,
1247 Handle<i::Object> value) {
1248 STATIC_ASSERT(kFirstElementIndex == 1);
1249 int index = list->length() + 1;
1250 Handle<i::FixedArray> fixed_array = Handle<FixedArray>::cast(list);
1251 fixed_array = FixedArray::SetAndGrow(fixed_array, index, value);
1252 fixed_array->set(kLengthIndex, Smi::FromInt(index));
1253 return Handle<TemplateList>::cast(fixed_array);
1254 }
1255
1256 // static
New(Handle<JSFunction> constructor,Handle<JSReceiver> new_target,Handle<AllocationSite> site)1257 MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor,
1258 Handle<JSReceiver> new_target,
1259 Handle<AllocationSite> site) {
1260 // If called through new, new.target can be:
1261 // - a subclass of constructor,
1262 // - a proxy wrapper around constructor, or
1263 // - the constructor itself.
1264 // If called through Reflect.construct, it's guaranteed to be a constructor.
1265 Isolate* const isolate = constructor->GetIsolate();
1266 DCHECK(constructor->IsConstructor());
1267 DCHECK(new_target->IsConstructor());
1268 DCHECK(!constructor->has_initial_map() ||
1269 constructor->initial_map()->instance_type() != JS_FUNCTION_TYPE);
1270
1271 Handle<Map> initial_map;
1272 ASSIGN_RETURN_ON_EXCEPTION(
1273 isolate, initial_map,
1274 JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject);
1275 Handle<JSObject> result =
1276 isolate->factory()->NewJSObjectFromMap(initial_map, NOT_TENURED, site);
1277 isolate->counters()->constructed_objects()->Increment();
1278 isolate->counters()->constructed_objects_runtime()->Increment();
1279 return result;
1280 }
1281
EnsureWritableFastElements(Handle<JSObject> object)1282 void JSObject::EnsureWritableFastElements(Handle<JSObject> object) {
1283 DCHECK(object->HasFastSmiOrObjectElements() ||
1284 object->HasFastStringWrapperElements());
1285 FixedArray* raw_elems = FixedArray::cast(object->elements());
1286 Heap* heap = object->GetHeap();
1287 if (raw_elems->map() != heap->fixed_cow_array_map()) return;
1288 Isolate* isolate = heap->isolate();
1289 Handle<FixedArray> elems(raw_elems, isolate);
1290 Handle<FixedArray> writable_elems = isolate->factory()->CopyFixedArrayWithMap(
1291 elems, isolate->factory()->fixed_array_map());
1292 object->set_elements(*writable_elems);
1293 isolate->counters()->cow_arrays_converted()->Increment();
1294 }
1295
1296
1297 // ES6 9.5.1
1298 // static
GetPrototype(Handle<JSProxy> proxy)1299 MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
1300 Isolate* isolate = proxy->GetIsolate();
1301 Handle<String> trap_name = isolate->factory()->getPrototypeOf_string();
1302
1303 STACK_CHECK(isolate, MaybeHandle<Object>());
1304
1305 // 1. Let handler be the value of the [[ProxyHandler]] internal slot.
1306 // 2. If handler is null, throw a TypeError exception.
1307 // 3. Assert: Type(handler) is Object.
1308 // 4. Let target be the value of the [[ProxyTarget]] internal slot.
1309 if (proxy->IsRevoked()) {
1310 THROW_NEW_ERROR(isolate,
1311 NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
1312 Object);
1313 }
1314 Handle<JSReceiver> target(proxy->target(), isolate);
1315 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
1316
1317 // 5. Let trap be ? GetMethod(handler, "getPrototypeOf").
1318 Handle<Object> trap;
1319 ASSIGN_RETURN_ON_EXCEPTION(isolate, trap, GetMethod(handler, trap_name),
1320 Object);
1321 // 6. If trap is undefined, then return target.[[GetPrototypeOf]]().
1322 if (trap->IsUndefined(isolate)) {
1323 return JSReceiver::GetPrototype(isolate, target);
1324 }
1325 // 7. Let handlerProto be ? Call(trap, handler, «target»).
1326 Handle<Object> argv[] = {target};
1327 Handle<Object> handler_proto;
1328 ASSIGN_RETURN_ON_EXCEPTION(
1329 isolate, handler_proto,
1330 Execution::Call(isolate, trap, handler, arraysize(argv), argv), Object);
1331 // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError.
1332 if (!(handler_proto->IsJSReceiver() || handler_proto->IsNull(isolate))) {
1333 THROW_NEW_ERROR(isolate,
1334 NewTypeError(MessageTemplate::kProxyGetPrototypeOfInvalid),
1335 Object);
1336 }
1337 // 9. Let extensibleTarget be ? IsExtensible(target).
1338 Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
1339 MAYBE_RETURN_NULL(is_extensible);
1340 // 10. If extensibleTarget is true, return handlerProto.
1341 if (is_extensible.FromJust()) return handler_proto;
1342 // 11. Let targetProto be ? target.[[GetPrototypeOf]]().
1343 Handle<Object> target_proto;
1344 ASSIGN_RETURN_ON_EXCEPTION(isolate, target_proto,
1345 JSReceiver::GetPrototype(isolate, target), Object);
1346 // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError.
1347 if (!handler_proto->SameValue(*target_proto)) {
1348 THROW_NEW_ERROR(
1349 isolate,
1350 NewTypeError(MessageTemplate::kProxyGetPrototypeOfNonExtensible),
1351 Object);
1352 }
1353 // 13. Return handlerProto.
1354 return handler_proto;
1355 }
1356
GetPropertyWithAccessor(LookupIterator * it)1357 MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) {
1358 Isolate* isolate = it->isolate();
1359 Handle<Object> structure = it->GetAccessors();
1360 Handle<Object> receiver = it->GetReceiver();
1361
1362 // We should never get here to initialize a const with the hole value since a
1363 // const declaration would conflict with the getter.
1364 DCHECK(!structure->IsForeign());
1365
1366 // API style callbacks.
1367 if (structure->IsAccessorInfo()) {
1368 Handle<JSObject> holder = it->GetHolder<JSObject>();
1369 Handle<Name> name = it->GetName();
1370 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
1371 if (!info->IsCompatibleReceiver(*receiver)) {
1372 THROW_NEW_ERROR(isolate,
1373 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
1374 name, receiver),
1375 Object);
1376 }
1377
1378 v8::AccessorNameGetterCallback call_fun =
1379 v8::ToCData<v8::AccessorNameGetterCallback>(info->getter());
1380 if (call_fun == nullptr) return isolate->factory()->undefined_value();
1381
1382 if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1383 ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver,
1384 Object::ConvertReceiver(isolate, receiver),
1385 Object);
1386 }
1387
1388 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1389 Object::DONT_THROW);
1390 Handle<Object> result = args.Call(call_fun, name);
1391 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1392 if (result.is_null()) return isolate->factory()->undefined_value();
1393 Handle<Object> reboxed_result = handle(*result, isolate);
1394 if (info->replace_on_access() && receiver->IsJSReceiver()) {
1395 args.Call(reinterpret_cast<GenericNamedPropertySetterCallback>(
1396 &Accessors::ReconfigureToDataProperty),
1397 name, result);
1398 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1399 }
1400 return reboxed_result;
1401 }
1402
1403 // AccessorPair with 'cached' private property.
1404 if (it->TryLookupCachedProperty()) {
1405 return Object::GetProperty(it);
1406 }
1407
1408 // Regular accessor.
1409 Handle<Object> getter(AccessorPair::cast(*structure)->getter(), isolate);
1410 if (getter->IsFunctionTemplateInfo()) {
1411 return Builtins::InvokeApiFunction(
1412 isolate, false, Handle<FunctionTemplateInfo>::cast(getter), receiver, 0,
1413 nullptr, isolate->factory()->undefined_value());
1414 } else if (getter->IsCallable()) {
1415 // TODO(rossberg): nicer would be to cast to some JSCallable here...
1416 return Object::GetPropertyWithDefinedGetter(
1417 receiver, Handle<JSReceiver>::cast(getter));
1418 }
1419 // Getter is not a function.
1420 return isolate->factory()->undefined_value();
1421 }
1422
1423 // static
redirect(Isolate * isolate,Address address,AccessorComponent component)1424 Address AccessorInfo::redirect(Isolate* isolate, Address address,
1425 AccessorComponent component) {
1426 ApiFunction fun(address);
1427 DCHECK_EQ(ACCESSOR_GETTER, component);
1428 ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
1429 return ExternalReference(&fun, type, isolate).address();
1430 }
1431
redirected_getter() const1432 Address AccessorInfo::redirected_getter() const {
1433 Address accessor = v8::ToCData<Address>(getter());
1434 if (accessor == nullptr) return nullptr;
1435 return redirect(GetIsolate(), accessor, ACCESSOR_GETTER);
1436 }
1437
IsCompatibleReceiverMap(Isolate * isolate,Handle<AccessorInfo> info,Handle<Map> map)1438 bool AccessorInfo::IsCompatibleReceiverMap(Isolate* isolate,
1439 Handle<AccessorInfo> info,
1440 Handle<Map> map) {
1441 if (!info->HasExpectedReceiverType()) return true;
1442 if (!map->IsJSObjectMap()) return false;
1443 return FunctionTemplateInfo::cast(info->expected_receiver_type())
1444 ->IsTemplateFor(*map);
1445 }
1446
SetPropertyWithAccessor(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)1447 Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it,
1448 Handle<Object> value,
1449 ShouldThrow should_throw) {
1450 Isolate* isolate = it->isolate();
1451 Handle<Object> structure = it->GetAccessors();
1452 Handle<Object> receiver = it->GetReceiver();
1453
1454 // We should never get here to initialize a const with the hole value since a
1455 // const declaration would conflict with the setter.
1456 DCHECK(!structure->IsForeign());
1457
1458 // API style callbacks.
1459 if (structure->IsAccessorInfo()) {
1460 Handle<JSObject> holder = it->GetHolder<JSObject>();
1461 Handle<Name> name = it->GetName();
1462 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
1463 if (!info->IsCompatibleReceiver(*receiver)) {
1464 isolate->Throw(*isolate->factory()->NewTypeError(
1465 MessageTemplate::kIncompatibleMethodReceiver, name, receiver));
1466 return Nothing<bool>();
1467 }
1468
1469 // The actual type of call_fun is either v8::AccessorNameSetterCallback or
1470 // i::Accesors::AccessorNameBooleanSetterCallback, depending on whether the
1471 // AccessorInfo was created by the API or internally (see accessors.cc).
1472 // Here we handle both cases using GenericNamedPropertySetterCallback and
1473 // its Call method.
1474 GenericNamedPropertySetterCallback call_fun =
1475 v8::ToCData<GenericNamedPropertySetterCallback>(info->setter());
1476
1477 if (call_fun == nullptr) {
1478 // TODO(verwaest): We should not get here anymore once all AccessorInfos
1479 // are marked as special_data_property. They cannot both be writable and
1480 // not have a setter.
1481 return Just(true);
1482 }
1483
1484 if (info->is_sloppy() && !receiver->IsJSReceiver()) {
1485 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1486 isolate, receiver, Object::ConvertReceiver(isolate, receiver),
1487 Nothing<bool>());
1488 }
1489
1490 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
1491 should_throw);
1492 Handle<Object> result = args.Call(call_fun, name, value);
1493 // In the case of AccessorNameSetterCallback, we know that the result value
1494 // cannot have been set, so the result of Call will be null. In the case of
1495 // AccessorNameBooleanSetterCallback, the result will either be null
1496 // (signalling an exception) or a boolean Oddball.
1497 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1498 if (result.is_null()) return Just(true);
1499 DCHECK(result->BooleanValue() || should_throw == DONT_THROW);
1500 return Just(result->BooleanValue());
1501 }
1502
1503 // Regular accessor.
1504 Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
1505 if (setter->IsFunctionTemplateInfo()) {
1506 Handle<Object> argv[] = {value};
1507 RETURN_ON_EXCEPTION_VALUE(
1508 isolate, Builtins::InvokeApiFunction(
1509 isolate, false, Handle<FunctionTemplateInfo>::cast(setter),
1510 receiver, arraysize(argv), argv,
1511 isolate->factory()->undefined_value()),
1512 Nothing<bool>());
1513 return Just(true);
1514 } else if (setter->IsCallable()) {
1515 // TODO(rossberg): nicer would be to cast to some JSCallable here...
1516 return SetPropertyWithDefinedSetter(
1517 receiver, Handle<JSReceiver>::cast(setter), value, should_throw);
1518 }
1519
1520 RETURN_FAILURE(isolate, should_throw,
1521 NewTypeError(MessageTemplate::kNoSetterInCallback,
1522 it->GetName(), it->GetHolder<JSObject>()));
1523 }
1524
1525
GetPropertyWithDefinedGetter(Handle<Object> receiver,Handle<JSReceiver> getter)1526 MaybeHandle<Object> Object::GetPropertyWithDefinedGetter(
1527 Handle<Object> receiver,
1528 Handle<JSReceiver> getter) {
1529 Isolate* isolate = getter->GetIsolate();
1530
1531 // Platforms with simulators like arm/arm64 expose a funny issue. If the
1532 // simulator has a separate JS stack pointer from the C++ stack pointer, it
1533 // can miss C++ stack overflows in the stack guard at the start of JavaScript
1534 // functions. It would be very expensive to check the C++ stack pointer at
1535 // that location. The best solution seems to be to break the impasse by
1536 // adding checks at possible recursion points. What's more, we don't put
1537 // this stack check behind the USE_SIMULATOR define in order to keep
1538 // behavior the same between hardware and simulators.
1539 StackLimitCheck check(isolate);
1540 if (check.JsHasOverflowed()) {
1541 isolate->StackOverflow();
1542 return MaybeHandle<Object>();
1543 }
1544
1545 return Execution::Call(isolate, getter, receiver, 0, NULL);
1546 }
1547
1548
SetPropertyWithDefinedSetter(Handle<Object> receiver,Handle<JSReceiver> setter,Handle<Object> value,ShouldThrow should_throw)1549 Maybe<bool> Object::SetPropertyWithDefinedSetter(Handle<Object> receiver,
1550 Handle<JSReceiver> setter,
1551 Handle<Object> value,
1552 ShouldThrow should_throw) {
1553 Isolate* isolate = setter->GetIsolate();
1554
1555 Handle<Object> argv[] = { value };
1556 RETURN_ON_EXCEPTION_VALUE(isolate, Execution::Call(isolate, setter, receiver,
1557 arraysize(argv), argv),
1558 Nothing<bool>());
1559 return Just(true);
1560 }
1561
1562
1563 // static
AllCanRead(LookupIterator * it)1564 bool JSObject::AllCanRead(LookupIterator* it) {
1565 // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of
1566 // which have already been checked.
1567 DCHECK(it->state() == LookupIterator::ACCESS_CHECK ||
1568 it->state() == LookupIterator::INTERCEPTOR);
1569 for (it->Next(); it->IsFound(); it->Next()) {
1570 if (it->state() == LookupIterator::ACCESSOR) {
1571 auto accessors = it->GetAccessors();
1572 if (accessors->IsAccessorInfo()) {
1573 if (AccessorInfo::cast(*accessors)->all_can_read()) return true;
1574 }
1575 } else if (it->state() == LookupIterator::INTERCEPTOR) {
1576 if (it->GetInterceptor()->all_can_read()) return true;
1577 } else if (it->state() == LookupIterator::JSPROXY) {
1578 // Stop lookupiterating. And no, AllCanNotRead.
1579 return false;
1580 }
1581 }
1582 return false;
1583 }
1584
1585 namespace {
1586
GetPropertyWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor,bool * done)1587 MaybeHandle<Object> GetPropertyWithInterceptorInternal(
1588 LookupIterator* it, Handle<InterceptorInfo> interceptor, bool* done) {
1589 *done = false;
1590 Isolate* isolate = it->isolate();
1591 // Make sure that the top context does not change when doing callbacks or
1592 // interceptor calls.
1593 AssertNoContextChange ncc(isolate);
1594
1595 if (interceptor->getter()->IsUndefined(isolate)) {
1596 return isolate->factory()->undefined_value();
1597 }
1598
1599 Handle<JSObject> holder = it->GetHolder<JSObject>();
1600 Handle<Object> result;
1601 Handle<Object> receiver = it->GetReceiver();
1602 if (!receiver->IsJSReceiver()) {
1603 ASSIGN_RETURN_ON_EXCEPTION(
1604 isolate, receiver, Object::ConvertReceiver(isolate, receiver), Object);
1605 }
1606 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1607 *holder, Object::DONT_THROW);
1608
1609 if (it->IsElement()) {
1610 uint32_t index = it->index();
1611 v8::IndexedPropertyGetterCallback getter =
1612 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
1613 result = args.Call(getter, index);
1614 } else {
1615 Handle<Name> name = it->name();
1616 DCHECK(!name->IsPrivate());
1617
1618 if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
1619 return isolate->factory()->undefined_value();
1620 }
1621
1622 v8::GenericNamedPropertyGetterCallback getter =
1623 v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
1624 interceptor->getter());
1625 result = args.Call(getter, name);
1626 }
1627
1628 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1629 if (result.is_null()) return isolate->factory()->undefined_value();
1630 *done = true;
1631 // Rebox handle before return
1632 return handle(*result, isolate);
1633 }
1634
GetPropertyAttributesWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor)1635 Maybe<PropertyAttributes> GetPropertyAttributesWithInterceptorInternal(
1636 LookupIterator* it, Handle<InterceptorInfo> interceptor) {
1637 Isolate* isolate = it->isolate();
1638 // Make sure that the top context does not change when doing
1639 // callbacks or interceptor calls.
1640 AssertNoContextChange ncc(isolate);
1641 HandleScope scope(isolate);
1642
1643 Handle<JSObject> holder = it->GetHolder<JSObject>();
1644 if (!it->IsElement() && it->name()->IsSymbol() &&
1645 !interceptor->can_intercept_symbols()) {
1646 return Just(ABSENT);
1647 }
1648 Handle<Object> receiver = it->GetReceiver();
1649 if (!receiver->IsJSReceiver()) {
1650 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1651 Object::ConvertReceiver(isolate, receiver),
1652 Nothing<PropertyAttributes>());
1653 }
1654 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1655 *holder, Object::DONT_THROW);
1656 if (!interceptor->query()->IsUndefined(isolate)) {
1657 Handle<Object> result;
1658 if (it->IsElement()) {
1659 uint32_t index = it->index();
1660 v8::IndexedPropertyQueryCallback query =
1661 v8::ToCData<v8::IndexedPropertyQueryCallback>(interceptor->query());
1662 result = args.Call(query, index);
1663 } else {
1664 Handle<Name> name = it->name();
1665 DCHECK(!name->IsPrivate());
1666 v8::GenericNamedPropertyQueryCallback query =
1667 v8::ToCData<v8::GenericNamedPropertyQueryCallback>(
1668 interceptor->query());
1669 result = args.Call(query, name);
1670 }
1671 if (!result.is_null()) {
1672 int32_t value;
1673 CHECK(result->ToInt32(&value));
1674 return Just(static_cast<PropertyAttributes>(value));
1675 }
1676 } else if (!interceptor->getter()->IsUndefined(isolate)) {
1677 // TODO(verwaest): Use GetPropertyWithInterceptor?
1678 Handle<Object> result;
1679 if (it->IsElement()) {
1680 uint32_t index = it->index();
1681 v8::IndexedPropertyGetterCallback getter =
1682 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
1683 result = args.Call(getter, index);
1684 } else {
1685 Handle<Name> name = it->name();
1686 DCHECK(!name->IsPrivate());
1687 v8::GenericNamedPropertyGetterCallback getter =
1688 v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
1689 interceptor->getter());
1690 result = args.Call(getter, name);
1691 }
1692 if (!result.is_null()) return Just(DONT_ENUM);
1693 }
1694
1695 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
1696 return Just(ABSENT);
1697 }
1698
SetPropertyWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor,Object::ShouldThrow should_throw,Handle<Object> value)1699 Maybe<bool> SetPropertyWithInterceptorInternal(
1700 LookupIterator* it, Handle<InterceptorInfo> interceptor,
1701 Object::ShouldThrow should_throw, Handle<Object> value) {
1702 Isolate* isolate = it->isolate();
1703 // Make sure that the top context does not change when doing callbacks or
1704 // interceptor calls.
1705 AssertNoContextChange ncc(isolate);
1706
1707 if (interceptor->setter()->IsUndefined(isolate)) return Just(false);
1708
1709 Handle<JSObject> holder = it->GetHolder<JSObject>();
1710 bool result;
1711 Handle<Object> receiver = it->GetReceiver();
1712 if (!receiver->IsJSReceiver()) {
1713 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1714 Object::ConvertReceiver(isolate, receiver),
1715 Nothing<bool>());
1716 }
1717 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1718 *holder, should_throw);
1719
1720 if (it->IsElement()) {
1721 uint32_t index = it->index();
1722 v8::IndexedPropertySetterCallback setter =
1723 v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter());
1724 // TODO(neis): In the future, we may want to actually return the
1725 // interceptor's result, which then should be a boolean.
1726 result = !args.Call(setter, index, value).is_null();
1727 } else {
1728 Handle<Name> name = it->name();
1729 DCHECK(!name->IsPrivate());
1730
1731 if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
1732 return Just(false);
1733 }
1734
1735 v8::GenericNamedPropertySetterCallback setter =
1736 v8::ToCData<v8::GenericNamedPropertySetterCallback>(
1737 interceptor->setter());
1738 result = !args.Call(setter, name, value).is_null();
1739 }
1740
1741 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1742 return Just(result);
1743 }
1744
DefinePropertyWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor,Object::ShouldThrow should_throw,PropertyDescriptor & desc)1745 Maybe<bool> DefinePropertyWithInterceptorInternal(
1746 LookupIterator* it, Handle<InterceptorInfo> interceptor,
1747 Object::ShouldThrow should_throw, PropertyDescriptor& desc) {
1748 Isolate* isolate = it->isolate();
1749 // Make sure that the top context does not change when doing callbacks or
1750 // interceptor calls.
1751 AssertNoContextChange ncc(isolate);
1752
1753 if (interceptor->definer()->IsUndefined(isolate)) return Just(false);
1754
1755 Handle<JSObject> holder = it->GetHolder<JSObject>();
1756 bool result;
1757 Handle<Object> receiver = it->GetReceiver();
1758 if (!receiver->IsJSReceiver()) {
1759 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1760 Object::ConvertReceiver(isolate, receiver),
1761 Nothing<bool>());
1762 }
1763 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1764 *holder, should_throw);
1765
1766 std::unique_ptr<v8::PropertyDescriptor> descriptor(
1767 new v8::PropertyDescriptor());
1768 if (PropertyDescriptor::IsAccessorDescriptor(&desc)) {
1769 descriptor.reset(new v8::PropertyDescriptor(
1770 v8::Utils::ToLocal(desc.get()), v8::Utils::ToLocal(desc.set())));
1771 } else if (PropertyDescriptor::IsDataDescriptor(&desc)) {
1772 if (desc.has_writable()) {
1773 descriptor.reset(new v8::PropertyDescriptor(
1774 v8::Utils::ToLocal(desc.value()), desc.writable()));
1775 } else {
1776 descriptor.reset(
1777 new v8::PropertyDescriptor(v8::Utils::ToLocal(desc.value())));
1778 }
1779 }
1780 if (desc.has_enumerable()) {
1781 descriptor->set_enumerable(desc.enumerable());
1782 }
1783 if (desc.has_configurable()) {
1784 descriptor->set_configurable(desc.configurable());
1785 }
1786
1787 if (it->IsElement()) {
1788 uint32_t index = it->index();
1789 v8::IndexedPropertyDefinerCallback definer =
1790 v8::ToCData<v8::IndexedPropertyDefinerCallback>(interceptor->definer());
1791 result = !args.Call(definer, index, *descriptor).is_null();
1792 } else {
1793 Handle<Name> name = it->name();
1794 DCHECK(!name->IsPrivate());
1795
1796 if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
1797 return Just(false);
1798 }
1799
1800 v8::GenericNamedPropertyDefinerCallback definer =
1801 v8::ToCData<v8::GenericNamedPropertyDefinerCallback>(
1802 interceptor->definer());
1803 result = !args.Call(definer, name, *descriptor).is_null();
1804 }
1805
1806 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1807 return Just(result);
1808 }
1809
1810 } // namespace
1811
GetPropertyWithFailedAccessCheck(LookupIterator * it)1812 MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
1813 LookupIterator* it) {
1814 Isolate* isolate = it->isolate();
1815 Handle<JSObject> checked = it->GetHolder<JSObject>();
1816 Handle<InterceptorInfo> interceptor =
1817 it->GetInterceptorForFailedAccessCheck();
1818 if (interceptor.is_null()) {
1819 while (AllCanRead(it)) {
1820 if (it->state() == LookupIterator::ACCESSOR) {
1821 return GetPropertyWithAccessor(it);
1822 }
1823 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
1824 bool done;
1825 Handle<Object> result;
1826 ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
1827 GetPropertyWithInterceptor(it, &done), Object);
1828 if (done) return result;
1829 }
1830
1831 } else {
1832 Handle<Object> result;
1833 bool done;
1834 ASSIGN_RETURN_ON_EXCEPTION(
1835 isolate, result,
1836 GetPropertyWithInterceptorInternal(it, interceptor, &done), Object);
1837 if (done) return result;
1838 }
1839
1840 // Cross-Origin [[Get]] of Well-Known Symbols does not throw, and returns
1841 // undefined.
1842 Handle<Name> name = it->GetName();
1843 if (name->IsSymbol() && Symbol::cast(*name)->is_well_known_symbol()) {
1844 return it->factory()->undefined_value();
1845 }
1846
1847 isolate->ReportFailedAccessCheck(checked);
1848 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1849 return it->factory()->undefined_value();
1850 }
1851
1852
GetPropertyAttributesWithFailedAccessCheck(LookupIterator * it)1853 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
1854 LookupIterator* it) {
1855 Isolate* isolate = it->isolate();
1856 Handle<JSObject> checked = it->GetHolder<JSObject>();
1857 Handle<InterceptorInfo> interceptor =
1858 it->GetInterceptorForFailedAccessCheck();
1859 if (interceptor.is_null()) {
1860 while (AllCanRead(it)) {
1861 if (it->state() == LookupIterator::ACCESSOR) {
1862 return Just(it->property_attributes());
1863 }
1864 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
1865 auto result = GetPropertyAttributesWithInterceptor(it);
1866 if (isolate->has_scheduled_exception()) break;
1867 if (result.IsJust() && result.FromJust() != ABSENT) return result;
1868 }
1869 } else {
1870 Maybe<PropertyAttributes> result =
1871 GetPropertyAttributesWithInterceptorInternal(it, interceptor);
1872 if (isolate->has_pending_exception()) return Nothing<PropertyAttributes>();
1873 if (result.FromMaybe(ABSENT) != ABSENT) return result;
1874 }
1875 isolate->ReportFailedAccessCheck(checked);
1876 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
1877 return Just(ABSENT);
1878 }
1879
1880
1881 // static
AllCanWrite(LookupIterator * it)1882 bool JSObject::AllCanWrite(LookupIterator* it) {
1883 for (; it->IsFound() && it->state() != LookupIterator::JSPROXY; it->Next()) {
1884 if (it->state() == LookupIterator::ACCESSOR) {
1885 Handle<Object> accessors = it->GetAccessors();
1886 if (accessors->IsAccessorInfo()) {
1887 if (AccessorInfo::cast(*accessors)->all_can_write()) return true;
1888 }
1889 }
1890 }
1891 return false;
1892 }
1893
1894
SetPropertyWithFailedAccessCheck(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)1895 Maybe<bool> JSObject::SetPropertyWithFailedAccessCheck(
1896 LookupIterator* it, Handle<Object> value, ShouldThrow should_throw) {
1897 Isolate* isolate = it->isolate();
1898 Handle<JSObject> checked = it->GetHolder<JSObject>();
1899 Handle<InterceptorInfo> interceptor =
1900 it->GetInterceptorForFailedAccessCheck();
1901 if (interceptor.is_null()) {
1902 if (AllCanWrite(it)) {
1903 return SetPropertyWithAccessor(it, value, should_throw);
1904 }
1905 } else {
1906 Maybe<bool> result = SetPropertyWithInterceptorInternal(
1907 it, interceptor, should_throw, value);
1908 if (isolate->has_pending_exception()) return Nothing<bool>();
1909 if (result.IsJust()) return result;
1910 }
1911 isolate->ReportFailedAccessCheck(checked);
1912 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1913 return Just(true);
1914 }
1915
1916
SetNormalizedProperty(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyDetails details)1917 void JSObject::SetNormalizedProperty(Handle<JSObject> object,
1918 Handle<Name> name,
1919 Handle<Object> value,
1920 PropertyDetails details) {
1921 DCHECK(!object->HasFastProperties());
1922 if (!name->IsUniqueName()) {
1923 name = object->GetIsolate()->factory()->InternalizeString(
1924 Handle<String>::cast(name));
1925 }
1926
1927 if (object->IsJSGlobalObject()) {
1928 Handle<GlobalDictionary> dictionary(object->global_dictionary());
1929
1930 int entry = dictionary->FindEntry(name);
1931 if (entry == GlobalDictionary::kNotFound) {
1932 Isolate* isolate = object->GetIsolate();
1933 auto cell = isolate->factory()->NewPropertyCell();
1934 cell->set_value(*value);
1935 auto cell_type = value->IsUndefined(isolate)
1936 ? PropertyCellType::kUndefined
1937 : PropertyCellType::kConstant;
1938 details = details.set_cell_type(cell_type);
1939 value = cell;
1940 dictionary = GlobalDictionary::Add(dictionary, name, value, details);
1941 object->set_properties(*dictionary);
1942 } else {
1943 Handle<PropertyCell> cell =
1944 PropertyCell::PrepareForValue(dictionary, entry, value, details);
1945 cell->set_value(*value);
1946 }
1947 } else {
1948 Handle<NameDictionary> dictionary(object->property_dictionary());
1949
1950 int entry = dictionary->FindEntry(name);
1951 if (entry == NameDictionary::kNotFound) {
1952 dictionary = NameDictionary::Add(dictionary, name, value, details);
1953 object->set_properties(*dictionary);
1954 } else {
1955 PropertyDetails original_details = dictionary->DetailsAt(entry);
1956 int enumeration_index = original_details.dictionary_index();
1957 DCHECK(enumeration_index > 0);
1958 details = details.set_index(enumeration_index);
1959 dictionary->SetEntry(entry, name, value, details);
1960 }
1961 }
1962 }
1963
1964 // static
HasInPrototypeChain(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> proto)1965 Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate,
1966 Handle<JSReceiver> object,
1967 Handle<Object> proto) {
1968 PrototypeIterator iter(isolate, object, kStartAtReceiver);
1969 while (true) {
1970 if (!iter.AdvanceFollowingProxies()) return Nothing<bool>();
1971 if (iter.IsAtEnd()) return Just(false);
1972 if (PrototypeIterator::GetCurrent(iter).is_identical_to(proto)) {
1973 return Just(true);
1974 }
1975 }
1976 }
1977
1978 namespace {
1979
HasExcludedProperty(const ScopedVector<Handle<Object>> * excluded_properties,Handle<Object> search_element)1980 bool HasExcludedProperty(
1981 const ScopedVector<Handle<Object>>* excluded_properties,
1982 Handle<Object> search_element) {
1983 // TODO(gsathya): Change this to be a hashtable.
1984 for (int i = 0; i < excluded_properties->length(); i++) {
1985 if (search_element->SameValue(*excluded_properties->at(i))) {
1986 return true;
1987 }
1988 }
1989
1990 return false;
1991 }
1992
FastAssign(Handle<JSReceiver> target,Handle<Object> source,const ScopedVector<Handle<Object>> * excluded_properties,bool use_set)1993 MUST_USE_RESULT Maybe<bool> FastAssign(
1994 Handle<JSReceiver> target, Handle<Object> source,
1995 const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) {
1996 // Non-empty strings are the only non-JSReceivers that need to be handled
1997 // explicitly by Object.assign.
1998 if (!source->IsJSReceiver()) {
1999 return Just(!source->IsString() || String::cast(*source)->length() == 0);
2000 }
2001
2002 // If the target is deprecated, the object will be updated on first store. If
2003 // the source for that store equals the target, this will invalidate the
2004 // cached representation of the source. Preventively upgrade the target.
2005 // Do this on each iteration since any property load could cause deprecation.
2006 if (target->map()->is_deprecated()) {
2007 JSObject::MigrateInstance(Handle<JSObject>::cast(target));
2008 }
2009
2010 Isolate* isolate = target->GetIsolate();
2011 Handle<Map> map(JSReceiver::cast(*source)->map(), isolate);
2012
2013 if (!map->IsJSObjectMap()) return Just(false);
2014 if (!map->OnlyHasSimpleProperties()) return Just(false);
2015
2016 Handle<JSObject> from = Handle<JSObject>::cast(source);
2017 if (from->elements() != isolate->heap()->empty_fixed_array()) {
2018 return Just(false);
2019 }
2020
2021 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
2022 int length = map->NumberOfOwnDescriptors();
2023
2024 bool stable = true;
2025
2026 for (int i = 0; i < length; i++) {
2027 Handle<Name> next_key(descriptors->GetKey(i), isolate);
2028 Handle<Object> prop_value;
2029 // Directly decode from the descriptor array if |from| did not change shape.
2030 if (stable) {
2031 PropertyDetails details = descriptors->GetDetails(i);
2032 if (!details.IsEnumerable()) continue;
2033 if (details.kind() == kData) {
2034 if (details.location() == kDescriptor) {
2035 prop_value = handle(descriptors->GetValue(i), isolate);
2036 } else {
2037 Representation representation = details.representation();
2038 FieldIndex index = FieldIndex::ForDescriptor(*map, i);
2039 prop_value = JSObject::FastPropertyAt(from, representation, index);
2040 }
2041 } else {
2042 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2043 isolate, prop_value, JSReceiver::GetProperty(from, next_key),
2044 Nothing<bool>());
2045 stable = from->map() == *map;
2046 }
2047 } else {
2048 // If the map did change, do a slower lookup. We are still guaranteed that
2049 // the object has a simple shape, and that the key is a name.
2050 LookupIterator it(from, next_key, from,
2051 LookupIterator::OWN_SKIP_INTERCEPTOR);
2052 if (!it.IsFound()) continue;
2053 DCHECK(it.state() == LookupIterator::DATA ||
2054 it.state() == LookupIterator::ACCESSOR);
2055 if (!it.IsEnumerable()) continue;
2056 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2057 isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
2058 }
2059
2060 if (use_set) {
2061 LookupIterator it(target, next_key, target);
2062 bool call_to_js = it.IsFound() && it.state() != LookupIterator::DATA;
2063 Maybe<bool> result = Object::SetProperty(
2064 &it, prop_value, STRICT, Object::CERTAINLY_NOT_STORE_FROM_KEYED);
2065 if (result.IsNothing()) return result;
2066 if (stable && call_to_js) stable = from->map() == *map;
2067 } else {
2068 if (excluded_properties != nullptr &&
2069 HasExcludedProperty(excluded_properties, next_key)) {
2070 continue;
2071 }
2072
2073 // 4a ii 2. Perform ? CreateDataProperty(target, nextKey, propValue).
2074 bool success;
2075 LookupIterator it = LookupIterator::PropertyOrElement(
2076 isolate, target, next_key, &success, LookupIterator::OWN);
2077 CHECK(success);
2078 CHECK(
2079 JSObject::CreateDataProperty(&it, prop_value, Object::THROW_ON_ERROR)
2080 .FromJust());
2081 }
2082 }
2083
2084 return Just(true);
2085 }
2086 } // namespace
2087
2088 // static
SetOrCopyDataProperties(Isolate * isolate,Handle<JSReceiver> target,Handle<Object> source,const ScopedVector<Handle<Object>> * excluded_properties,bool use_set)2089 Maybe<bool> JSReceiver::SetOrCopyDataProperties(
2090 Isolate* isolate, Handle<JSReceiver> target, Handle<Object> source,
2091 const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) {
2092 Maybe<bool> fast_assign =
2093 FastAssign(target, source, excluded_properties, use_set);
2094 if (fast_assign.IsNothing()) return Nothing<bool>();
2095 if (fast_assign.FromJust()) return Just(true);
2096
2097 Handle<JSReceiver> from = Object::ToObject(isolate, source).ToHandleChecked();
2098 // 3b. Let keys be ? from.[[OwnPropertyKeys]]().
2099 Handle<FixedArray> keys;
2100 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2101 isolate, keys,
2102 KeyAccumulator::GetKeys(from, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES,
2103 GetKeysConversion::kKeepNumbers),
2104 Nothing<bool>());
2105
2106 // 4. Repeat for each element nextKey of keys in List order,
2107 for (int j = 0; j < keys->length(); ++j) {
2108 Handle<Object> next_key(keys->get(j), isolate);
2109 // 4a i. Let desc be ? from.[[GetOwnProperty]](nextKey).
2110 PropertyDescriptor desc;
2111 Maybe<bool> found =
2112 JSReceiver::GetOwnPropertyDescriptor(isolate, from, next_key, &desc);
2113 if (found.IsNothing()) return Nothing<bool>();
2114 // 4a ii. If desc is not undefined and desc.[[Enumerable]] is true, then
2115 if (found.FromJust() && desc.enumerable()) {
2116 // 4a ii 1. Let propValue be ? Get(from, nextKey).
2117 Handle<Object> prop_value;
2118 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2119 isolate, prop_value,
2120 Runtime::GetObjectProperty(isolate, from, next_key), Nothing<bool>());
2121
2122 if (use_set) {
2123 // 4c ii 2. Let status be ? Set(to, nextKey, propValue, true).
2124 Handle<Object> status;
2125 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2126 isolate, status, Runtime::SetObjectProperty(
2127 isolate, target, next_key, prop_value, STRICT),
2128 Nothing<bool>());
2129 } else {
2130 if (excluded_properties != nullptr &&
2131 HasExcludedProperty(excluded_properties, next_key)) {
2132 continue;
2133 }
2134
2135 // 4a ii 2. Perform ! CreateDataProperty(target, nextKey, propValue).
2136 bool success;
2137 LookupIterator it = LookupIterator::PropertyOrElement(
2138 isolate, target, next_key, &success, LookupIterator::OWN);
2139 CHECK(success);
2140 CHECK(JSObject::CreateDataProperty(&it, prop_value,
2141 Object::THROW_ON_ERROR)
2142 .FromJust());
2143 }
2144 }
2145 }
2146
2147 return Just(true);
2148 }
2149
GetPrototypeChainRootMap(Isolate * isolate)2150 Map* Object::GetPrototypeChainRootMap(Isolate* isolate) {
2151 DisallowHeapAllocation no_alloc;
2152 if (IsSmi()) {
2153 Context* native_context = isolate->context()->native_context();
2154 return native_context->number_function()->initial_map();
2155 }
2156
2157 // The object is either a number, a string, a symbol, a boolean, a real JS
2158 // object, or a Harmony proxy.
2159 HeapObject* heap_object = HeapObject::cast(this);
2160 return heap_object->map()->GetPrototypeChainRootMap(isolate);
2161 }
2162
GetPrototypeChainRootMap(Isolate * isolate)2163 Map* Map::GetPrototypeChainRootMap(Isolate* isolate) {
2164 DisallowHeapAllocation no_alloc;
2165 if (IsJSReceiverMap()) {
2166 return this;
2167 }
2168 int constructor_function_index = GetConstructorFunctionIndex();
2169 if (constructor_function_index != Map::kNoConstructorFunctionIndex) {
2170 Context* native_context = isolate->context()->native_context();
2171 JSFunction* constructor_function =
2172 JSFunction::cast(native_context->get(constructor_function_index));
2173 return constructor_function->initial_map();
2174 }
2175 return isolate->heap()->null_value()->map();
2176 }
2177
2178 namespace {
2179
2180 // Returns a non-SMI for JSObjects, but returns the hash code for simple
2181 // objects. This avoids a double lookup in the cases where we know we will
2182 // add the hash to the JSObject if it does not already exist.
GetSimpleHash(Object * object)2183 Object* GetSimpleHash(Object* object) {
2184 // The object is either a Smi, a HeapNumber, a name, an odd-ball, a real JS
2185 // object, or a Harmony proxy.
2186 if (object->IsSmi()) {
2187 uint32_t hash =
2188 ComputeIntegerHash(Smi::cast(object)->value(), kZeroHashSeed);
2189 return Smi::FromInt(hash & Smi::kMaxValue);
2190 }
2191 if (object->IsHeapNumber()) {
2192 double num = HeapNumber::cast(object)->value();
2193 if (std::isnan(num)) return Smi::FromInt(Smi::kMaxValue);
2194 if (i::IsMinusZero(num)) num = 0;
2195 if (IsSmiDouble(num)) {
2196 return Smi::FromInt(FastD2I(num))->GetHash();
2197 }
2198 uint32_t hash = ComputeLongHash(double_to_uint64(num));
2199 return Smi::FromInt(hash & Smi::kMaxValue);
2200 }
2201 if (object->IsName()) {
2202 uint32_t hash = Name::cast(object)->Hash();
2203 return Smi::FromInt(hash);
2204 }
2205 if (object->IsOddball()) {
2206 uint32_t hash = Oddball::cast(object)->to_string()->Hash();
2207 return Smi::FromInt(hash);
2208 }
2209 DCHECK(object->IsJSReceiver());
2210 // Simply return the receiver as it is guaranteed to not be a SMI.
2211 return object;
2212 }
2213
2214 } // namespace
2215
GetHash()2216 Object* Object::GetHash() {
2217 Object* hash = GetSimpleHash(this);
2218 if (hash->IsSmi()) return hash;
2219
2220 DisallowHeapAllocation no_gc;
2221 DCHECK(IsJSReceiver());
2222 JSReceiver* receiver = JSReceiver::cast(this);
2223 Isolate* isolate = receiver->GetIsolate();
2224 return JSReceiver::GetIdentityHash(isolate, handle(receiver, isolate));
2225 }
2226
GetOrCreateHash(Isolate * isolate,Handle<Object> object)2227 Smi* Object::GetOrCreateHash(Isolate* isolate, Handle<Object> object) {
2228 Object* hash = GetSimpleHash(*object);
2229 if (hash->IsSmi()) return Smi::cast(hash);
2230
2231 DCHECK(object->IsJSReceiver());
2232 return JSReceiver::GetOrCreateIdentityHash(isolate,
2233 Handle<JSReceiver>::cast(object));
2234 }
2235
2236
SameValue(Object * other)2237 bool Object::SameValue(Object* other) {
2238 if (other == this) return true;
2239
2240 // The object is either a number, a name, an odd-ball,
2241 // a real JS object, or a Harmony proxy.
2242 if (IsNumber() && other->IsNumber()) {
2243 double this_value = Number();
2244 double other_value = other->Number();
2245 // SameValue(NaN, NaN) is true.
2246 if (this_value != other_value) {
2247 return std::isnan(this_value) && std::isnan(other_value);
2248 }
2249 // SameValue(0.0, -0.0) is false.
2250 return (std::signbit(this_value) == std::signbit(other_value));
2251 }
2252 if (IsString() && other->IsString()) {
2253 return String::cast(this)->Equals(String::cast(other));
2254 }
2255 return false;
2256 }
2257
2258
SameValueZero(Object * other)2259 bool Object::SameValueZero(Object* other) {
2260 if (other == this) return true;
2261
2262 // The object is either a number, a name, an odd-ball,
2263 // a real JS object, or a Harmony proxy.
2264 if (IsNumber() && other->IsNumber()) {
2265 double this_value = Number();
2266 double other_value = other->Number();
2267 // +0 == -0 is true
2268 return this_value == other_value ||
2269 (std::isnan(this_value) && std::isnan(other_value));
2270 }
2271 if (IsString() && other->IsString()) {
2272 return String::cast(this)->Equals(String::cast(other));
2273 }
2274 return false;
2275 }
2276
2277
ArraySpeciesConstructor(Isolate * isolate,Handle<Object> original_array)2278 MaybeHandle<Object> Object::ArraySpeciesConstructor(
2279 Isolate* isolate, Handle<Object> original_array) {
2280 Handle<Object> default_species = isolate->array_function();
2281 if (original_array->IsJSArray() &&
2282 Handle<JSArray>::cast(original_array)->HasArrayPrototype(isolate) &&
2283 isolate->IsArraySpeciesLookupChainIntact()) {
2284 return default_species;
2285 }
2286 Handle<Object> constructor = isolate->factory()->undefined_value();
2287 Maybe<bool> is_array = Object::IsArray(original_array);
2288 MAYBE_RETURN_NULL(is_array);
2289 if (is_array.FromJust()) {
2290 ASSIGN_RETURN_ON_EXCEPTION(
2291 isolate, constructor,
2292 Object::GetProperty(original_array,
2293 isolate->factory()->constructor_string()),
2294 Object);
2295 if (constructor->IsConstructor()) {
2296 Handle<Context> constructor_context;
2297 ASSIGN_RETURN_ON_EXCEPTION(
2298 isolate, constructor_context,
2299 JSReceiver::GetFunctionRealm(Handle<JSReceiver>::cast(constructor)),
2300 Object);
2301 if (*constructor_context != *isolate->native_context() &&
2302 *constructor == constructor_context->array_function()) {
2303 constructor = isolate->factory()->undefined_value();
2304 }
2305 }
2306 if (constructor->IsJSReceiver()) {
2307 ASSIGN_RETURN_ON_EXCEPTION(
2308 isolate, constructor,
2309 JSReceiver::GetProperty(Handle<JSReceiver>::cast(constructor),
2310 isolate->factory()->species_symbol()),
2311 Object);
2312 if (constructor->IsNull(isolate)) {
2313 constructor = isolate->factory()->undefined_value();
2314 }
2315 }
2316 }
2317 if (constructor->IsUndefined(isolate)) {
2318 return default_species;
2319 } else {
2320 if (!constructor->IsConstructor()) {
2321 THROW_NEW_ERROR(isolate,
2322 NewTypeError(MessageTemplate::kSpeciesNotConstructor),
2323 Object);
2324 }
2325 return constructor;
2326 }
2327 }
2328
IterationHasObservableEffects()2329 bool Object::IterationHasObservableEffects() {
2330 // Check that this object is an array.
2331 if (!IsJSArray()) return true;
2332 JSArray* spread_array = JSArray::cast(this);
2333 Isolate* isolate = spread_array->GetIsolate();
2334
2335 // Check that we have the original ArrayPrototype.
2336 JSObject* array_proto = JSObject::cast(spread_array->map()->prototype());
2337 if (!isolate->is_initial_array_prototype(array_proto)) return true;
2338
2339 // Check that the ArrayPrototype hasn't been modified in a way that would
2340 // affect iteration.
2341 if (!isolate->IsArrayIteratorLookupChainIntact()) return true;
2342
2343 // Check that the map of the initial array iterator hasn't changed.
2344 Map* iterator_map = isolate->initial_array_iterator_prototype()->map();
2345 if (!isolate->is_initial_array_iterator_prototype_map(iterator_map)) {
2346 return true;
2347 }
2348
2349 // For FastPacked kinds, iteration will have the same effect as simply
2350 // accessing each property in order.
2351 ElementsKind array_kind = spread_array->GetElementsKind();
2352 if (IsFastPackedElementsKind(array_kind)) return false;
2353
2354 // For FastHoley kinds, an element access on a hole would cause a lookup on
2355 // the prototype. This could have different results if the prototype has been
2356 // changed.
2357 if (IsFastHoleyElementsKind(array_kind) &&
2358 isolate->IsFastArrayConstructorPrototypeChainIntact()) {
2359 return false;
2360 }
2361 return true;
2362 }
2363
ShortPrint(FILE * out)2364 void Object::ShortPrint(FILE* out) {
2365 OFStream os(out);
2366 os << Brief(this);
2367 }
2368
2369
ShortPrint(StringStream * accumulator)2370 void Object::ShortPrint(StringStream* accumulator) {
2371 std::ostringstream os;
2372 os << Brief(this);
2373 accumulator->Add(os.str().c_str());
2374 }
2375
2376
ShortPrint(std::ostream & os)2377 void Object::ShortPrint(std::ostream& os) { os << Brief(this); }
2378
2379
operator <<(std::ostream & os,const Brief & v)2380 std::ostream& operator<<(std::ostream& os, const Brief& v) {
2381 if (v.value->IsSmi()) {
2382 Smi::cast(v.value)->SmiPrint(os);
2383 } else {
2384 // TODO(svenpanne) Const-correct HeapObjectShortPrint!
2385 HeapObject* obj = const_cast<HeapObject*>(HeapObject::cast(v.value));
2386 obj->HeapObjectShortPrint(os);
2387 }
2388 return os;
2389 }
2390
SmiPrint(std::ostream & os) const2391 void Smi::SmiPrint(std::ostream& os) const { // NOLINT
2392 os << value();
2393 }
2394
2395
2396 // Should a word be prefixed by 'a' or 'an' in order to read naturally in
2397 // English? Returns false for non-ASCII or words that don't start with
2398 // a capital letter. The a/an rule follows pronunciation in English.
2399 // We don't use the BBC's overcorrect "an historic occasion" though if
2400 // you speak a dialect you may well say "an 'istoric occasion".
AnWord(String * str)2401 static bool AnWord(String* str) {
2402 if (str->length() == 0) return false; // A nothing.
2403 int c0 = str->Get(0);
2404 int c1 = str->length() > 1 ? str->Get(1) : 0;
2405 if (c0 == 'U') {
2406 if (c1 > 'Z') {
2407 return true; // An Umpire, but a UTF8String, a U.
2408 }
2409 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
2410 return true; // An Ape, an ABCBook.
2411 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
2412 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
2413 c0 == 'S' || c0 == 'X')) {
2414 return true; // An MP3File, an M.
2415 }
2416 return false;
2417 }
2418
2419
SlowFlatten(Handle<ConsString> cons,PretenureFlag pretenure)2420 Handle<String> String::SlowFlatten(Handle<ConsString> cons,
2421 PretenureFlag pretenure) {
2422 DCHECK(cons->second()->length() != 0);
2423
2424 // TurboFan can create cons strings with empty first parts.
2425 while (cons->first()->length() == 0) {
2426 // We do not want to call this function recursively. Therefore we call
2427 // String::Flatten only in those cases where String::SlowFlatten is not
2428 // called again.
2429 if (cons->second()->IsConsString() && !cons->second()->IsFlat()) {
2430 cons = handle(ConsString::cast(cons->second()));
2431 } else {
2432 return String::Flatten(handle(cons->second()));
2433 }
2434 }
2435
2436 DCHECK(AllowHeapAllocation::IsAllowed());
2437 Isolate* isolate = cons->GetIsolate();
2438 int length = cons->length();
2439 PretenureFlag tenure = isolate->heap()->InNewSpace(*cons) ? pretenure
2440 : TENURED;
2441 Handle<SeqString> result;
2442 if (cons->IsOneByteRepresentation()) {
2443 Handle<SeqOneByteString> flat = isolate->factory()->NewRawOneByteString(
2444 length, tenure).ToHandleChecked();
2445 DisallowHeapAllocation no_gc;
2446 WriteToFlat(*cons, flat->GetChars(), 0, length);
2447 result = flat;
2448 } else {
2449 Handle<SeqTwoByteString> flat = isolate->factory()->NewRawTwoByteString(
2450 length, tenure).ToHandleChecked();
2451 DisallowHeapAllocation no_gc;
2452 WriteToFlat(*cons, flat->GetChars(), 0, length);
2453 result = flat;
2454 }
2455 cons->set_first(*result);
2456 cons->set_second(isolate->heap()->empty_string());
2457 DCHECK(result->IsFlat());
2458 return result;
2459 }
2460
2461
2462
MakeExternal(v8::String::ExternalStringResource * resource)2463 bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
2464 // Externalizing twice leaks the external resource, so it's
2465 // prohibited by the API.
2466 DCHECK(!this->IsExternalString());
2467 DCHECK(!resource->IsCompressible());
2468 #ifdef ENABLE_SLOW_DCHECKS
2469 if (FLAG_enable_slow_asserts) {
2470 // Assert that the resource and the string are equivalent.
2471 DCHECK(static_cast<size_t>(this->length()) == resource->length());
2472 ScopedVector<uc16> smart_chars(this->length());
2473 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2474 DCHECK(memcmp(smart_chars.start(),
2475 resource->data(),
2476 resource->length() * sizeof(smart_chars[0])) == 0);
2477 }
2478 #endif // DEBUG
2479 int size = this->Size(); // Byte size of the original string.
2480 // Abort if size does not allow in-place conversion.
2481 if (size < ExternalString::kShortSize) return false;
2482 Heap* heap = GetHeap();
2483 bool is_one_byte = this->IsOneByteRepresentation();
2484 bool is_internalized = this->IsInternalizedString();
2485 bool has_pointers = StringShape(this).IsIndirect();
2486
2487 // Morph the string to an external string by replacing the map and
2488 // reinitializing the fields. This won't work if the space the existing
2489 // string occupies is too small for a regular external string.
2490 // Instead, we resort to a short external string instead, omitting
2491 // the field caching the address of the backing store. When we encounter
2492 // short external strings in generated code, we need to bailout to runtime.
2493 Map* new_map;
2494 if (size < ExternalString::kSize) {
2495 new_map = is_internalized
2496 ? (is_one_byte
2497 ? heap->short_external_internalized_string_with_one_byte_data_map()
2498 : heap->short_external_internalized_string_map())
2499 : (is_one_byte ? heap->short_external_string_with_one_byte_data_map()
2500 : heap->short_external_string_map());
2501 } else {
2502 new_map = is_internalized
2503 ? (is_one_byte
2504 ? heap->external_internalized_string_with_one_byte_data_map()
2505 : heap->external_internalized_string_map())
2506 : (is_one_byte ? heap->external_string_with_one_byte_data_map()
2507 : heap->external_string_map());
2508 }
2509
2510 // Byte size of the external String object.
2511 int new_size = this->SizeFromMap(new_map);
2512 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
2513 ClearRecordedSlots::kNo);
2514 if (has_pointers) {
2515 heap->ClearRecordedSlotRange(this->address(), this->address() + new_size);
2516 }
2517
2518 // We are storing the new map using release store after creating a filler for
2519 // the left-over space to avoid races with the sweeper thread.
2520 this->synchronized_set_map(new_map);
2521
2522 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
2523 self->set_resource(resource);
2524 if (is_internalized) self->Hash(); // Force regeneration of the hash value.
2525
2526 heap->AdjustLiveBytes(this, new_size - size);
2527 return true;
2528 }
2529
2530
MakeExternal(v8::String::ExternalOneByteStringResource * resource)2531 bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
2532 // Externalizing twice leaks the external resource, so it's
2533 // prohibited by the API.
2534 DCHECK(!this->IsExternalString());
2535 DCHECK(!resource->IsCompressible());
2536 #ifdef ENABLE_SLOW_DCHECKS
2537 if (FLAG_enable_slow_asserts) {
2538 // Assert that the resource and the string are equivalent.
2539 DCHECK(static_cast<size_t>(this->length()) == resource->length());
2540 if (this->IsTwoByteRepresentation()) {
2541 ScopedVector<uint16_t> smart_chars(this->length());
2542 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2543 DCHECK(String::IsOneByte(smart_chars.start(), this->length()));
2544 }
2545 ScopedVector<char> smart_chars(this->length());
2546 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
2547 DCHECK(memcmp(smart_chars.start(),
2548 resource->data(),
2549 resource->length() * sizeof(smart_chars[0])) == 0);
2550 }
2551 #endif // DEBUG
2552 int size = this->Size(); // Byte size of the original string.
2553 // Abort if size does not allow in-place conversion.
2554 if (size < ExternalString::kShortSize) return false;
2555 Heap* heap = GetHeap();
2556 bool is_internalized = this->IsInternalizedString();
2557 bool has_pointers = StringShape(this).IsIndirect();
2558
2559 // Morph the string to an external string by replacing the map and
2560 // reinitializing the fields. This won't work if the space the existing
2561 // string occupies is too small for a regular external string.
2562 // Instead, we resort to a short external string instead, omitting
2563 // the field caching the address of the backing store. When we encounter
2564 // short external strings in generated code, we need to bailout to runtime.
2565 Map* new_map;
2566 if (size < ExternalString::kSize) {
2567 new_map = is_internalized
2568 ? heap->short_external_one_byte_internalized_string_map()
2569 : heap->short_external_one_byte_string_map();
2570 } else {
2571 new_map = is_internalized
2572 ? heap->external_one_byte_internalized_string_map()
2573 : heap->external_one_byte_string_map();
2574 }
2575
2576 // Byte size of the external String object.
2577 int new_size = this->SizeFromMap(new_map);
2578 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
2579 ClearRecordedSlots::kNo);
2580 if (has_pointers) {
2581 heap->ClearRecordedSlotRange(this->address(), this->address() + new_size);
2582 }
2583
2584 // We are storing the new map using release store after creating a filler for
2585 // the left-over space to avoid races with the sweeper thread.
2586 this->synchronized_set_map(new_map);
2587
2588 ExternalOneByteString* self = ExternalOneByteString::cast(this);
2589 self->set_resource(resource);
2590 if (is_internalized) self->Hash(); // Force regeneration of the hash value.
2591
2592 heap->AdjustLiveBytes(this, new_size - size);
2593 return true;
2594 }
2595
StringShortPrint(StringStream * accumulator,bool show_details)2596 void String::StringShortPrint(StringStream* accumulator, bool show_details) {
2597 int len = length();
2598 if (len > kMaxShortPrintLength) {
2599 accumulator->Add("<Very long string[%u]>", len);
2600 return;
2601 }
2602
2603 if (!LooksValid()) {
2604 accumulator->Add("<Invalid String>");
2605 return;
2606 }
2607
2608 StringCharacterStream stream(this);
2609
2610 bool truncated = false;
2611 if (len > kMaxShortPrintLength) {
2612 len = kMaxShortPrintLength;
2613 truncated = true;
2614 }
2615 bool one_byte = true;
2616 for (int i = 0; i < len; i++) {
2617 uint16_t c = stream.GetNext();
2618
2619 if (c < 32 || c >= 127) {
2620 one_byte = false;
2621 }
2622 }
2623 stream.Reset(this);
2624 if (one_byte) {
2625 if (show_details) accumulator->Add("<String[%u]: ", length());
2626 for (int i = 0; i < len; i++) {
2627 accumulator->Put(static_cast<char>(stream.GetNext()));
2628 }
2629 if (show_details) accumulator->Put('>');
2630 } else {
2631 // Backslash indicates that the string contains control
2632 // characters and that backslashes are therefore escaped.
2633 if (show_details) accumulator->Add("<String[%u]\\: ", length());
2634 for (int i = 0; i < len; i++) {
2635 uint16_t c = stream.GetNext();
2636 if (c == '\n') {
2637 accumulator->Add("\\n");
2638 } else if (c == '\r') {
2639 accumulator->Add("\\r");
2640 } else if (c == '\\') {
2641 accumulator->Add("\\\\");
2642 } else if (c < 32 || c > 126) {
2643 accumulator->Add("\\x%02x", c);
2644 } else {
2645 accumulator->Put(static_cast<char>(c));
2646 }
2647 }
2648 if (truncated) {
2649 accumulator->Put('.');
2650 accumulator->Put('.');
2651 accumulator->Put('.');
2652 }
2653 if (show_details) accumulator->Put('>');
2654 }
2655 return;
2656 }
2657
2658
PrintUC16(std::ostream & os,int start,int end)2659 void String::PrintUC16(std::ostream& os, int start, int end) { // NOLINT
2660 if (end < 0) end = length();
2661 StringCharacterStream stream(this, start);
2662 for (int i = start; i < end && stream.HasMore(); i++) {
2663 os << AsUC16(stream.GetNext());
2664 }
2665 }
2666
2667
JSObjectShortPrint(StringStream * accumulator)2668 void JSObject::JSObjectShortPrint(StringStream* accumulator) {
2669 switch (map()->instance_type()) {
2670 case JS_ARRAY_TYPE: {
2671 double length = JSArray::cast(this)->length()->IsUndefined(GetIsolate())
2672 ? 0
2673 : JSArray::cast(this)->length()->Number();
2674 accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length));
2675 break;
2676 }
2677 case JS_BOUND_FUNCTION_TYPE: {
2678 JSBoundFunction* bound_function = JSBoundFunction::cast(this);
2679 accumulator->Add("<JS BoundFunction");
2680 accumulator->Add(
2681 " (BoundTargetFunction %p)>",
2682 reinterpret_cast<void*>(bound_function->bound_target_function()));
2683 break;
2684 }
2685 case JS_WEAK_MAP_TYPE: {
2686 accumulator->Add("<JS WeakMap>");
2687 break;
2688 }
2689 case JS_WEAK_SET_TYPE: {
2690 accumulator->Add("<JS WeakSet>");
2691 break;
2692 }
2693 case JS_REGEXP_TYPE: {
2694 accumulator->Add("<JS RegExp>");
2695 break;
2696 }
2697 case JS_FUNCTION_TYPE: {
2698 JSFunction* function = JSFunction::cast(this);
2699 Object* fun_name = function->shared()->DebugName();
2700 bool printed = false;
2701 if (fun_name->IsString()) {
2702 String* str = String::cast(fun_name);
2703 if (str->length() > 0) {
2704 accumulator->Add("<JS Function ");
2705 accumulator->Put(str);
2706 printed = true;
2707 }
2708 }
2709 if (!printed) {
2710 accumulator->Add("<JS Function");
2711 }
2712 if (FLAG_trace_file_names) {
2713 Object* source_name =
2714 Script::cast(function->shared()->script())->name();
2715 if (source_name->IsString()) {
2716 String* str = String::cast(source_name);
2717 if (str->length() > 0) {
2718 accumulator->Add(" <");
2719 accumulator->Put(str);
2720 accumulator->Add(">");
2721 }
2722 }
2723 }
2724 accumulator->Add(" (SharedFunctionInfo %p)",
2725 reinterpret_cast<void*>(function->shared()));
2726 accumulator->Put('>');
2727 break;
2728 }
2729 case JS_GENERATOR_OBJECT_TYPE: {
2730 accumulator->Add("<JS Generator>");
2731 break;
2732 }
2733 // All other JSObjects are rather similar to each other (JSObject,
2734 // JSGlobalProxy, JSGlobalObject, JSUndetectable, JSValue).
2735 default: {
2736 Map* map_of_this = map();
2737 Heap* heap = GetHeap();
2738 Object* constructor = map_of_this->GetConstructor();
2739 bool printed = false;
2740 if (constructor->IsHeapObject() &&
2741 !heap->Contains(HeapObject::cast(constructor))) {
2742 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
2743 } else {
2744 bool global_object = IsJSGlobalProxy();
2745 if (constructor->IsJSFunction()) {
2746 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
2747 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
2748 } else {
2749 Object* constructor_name =
2750 JSFunction::cast(constructor)->shared()->name();
2751 if (constructor_name->IsString()) {
2752 String* str = String::cast(constructor_name);
2753 if (str->length() > 0) {
2754 bool vowel = AnWord(str);
2755 accumulator->Add("<%sa%s ",
2756 global_object ? "Global Object: " : "",
2757 vowel ? "n" : "");
2758 accumulator->Put(str);
2759 accumulator->Add(" with %smap %p",
2760 map_of_this->is_deprecated() ? "deprecated " : "",
2761 map_of_this);
2762 printed = true;
2763 }
2764 }
2765 }
2766 }
2767 if (!printed) {
2768 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
2769 }
2770 }
2771 if (IsJSValue()) {
2772 accumulator->Add(" value = ");
2773 JSValue::cast(this)->value()->ShortPrint(accumulator);
2774 }
2775 accumulator->Put('>');
2776 break;
2777 }
2778 }
2779 }
2780
2781
PrintElementsTransition(FILE * file,Handle<JSObject> object,ElementsKind from_kind,Handle<FixedArrayBase> from_elements,ElementsKind to_kind,Handle<FixedArrayBase> to_elements)2782 void JSObject::PrintElementsTransition(
2783 FILE* file, Handle<JSObject> object,
2784 ElementsKind from_kind, Handle<FixedArrayBase> from_elements,
2785 ElementsKind to_kind, Handle<FixedArrayBase> to_elements) {
2786 if (from_kind != to_kind) {
2787 OFStream os(file);
2788 os << "elements transition [" << ElementsKindToString(from_kind) << " -> "
2789 << ElementsKindToString(to_kind) << "] in ";
2790 JavaScriptFrame::PrintTop(object->GetIsolate(), file, false, true);
2791 PrintF(file, " for ");
2792 object->ShortPrint(file);
2793 PrintF(file, " from ");
2794 from_elements->ShortPrint(file);
2795 PrintF(file, " to ");
2796 to_elements->ShortPrint(file);
2797 PrintF(file, "\n");
2798 }
2799 }
2800
2801
2802 // static
GetConstructorFunction(Handle<Map> map,Handle<Context> native_context)2803 MaybeHandle<JSFunction> Map::GetConstructorFunction(
2804 Handle<Map> map, Handle<Context> native_context) {
2805 if (map->IsPrimitiveMap()) {
2806 int const constructor_function_index = map->GetConstructorFunctionIndex();
2807 if (constructor_function_index != kNoConstructorFunctionIndex) {
2808 return handle(
2809 JSFunction::cast(native_context->get(constructor_function_index)));
2810 }
2811 }
2812 return MaybeHandle<JSFunction>();
2813 }
2814
2815
PrintReconfiguration(FILE * file,int modify_index,PropertyKind kind,PropertyAttributes attributes)2816 void Map::PrintReconfiguration(FILE* file, int modify_index, PropertyKind kind,
2817 PropertyAttributes attributes) {
2818 OFStream os(file);
2819 os << "[reconfiguring]";
2820 Name* name = instance_descriptors()->GetKey(modify_index);
2821 if (name->IsString()) {
2822 String::cast(name)->PrintOn(file);
2823 } else {
2824 os << "{symbol " << static_cast<void*>(name) << "}";
2825 }
2826 os << ": " << (kind == kData ? "kData" : "ACCESSORS") << ", attrs: ";
2827 os << attributes << " [";
2828 JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
2829 os << "]\n";
2830 }
2831
PrintGeneralization(FILE * file,const char * reason,int modify_index,int split,int descriptors,bool descriptor_to_field,Representation old_representation,Representation new_representation,MaybeHandle<FieldType> old_field_type,MaybeHandle<Object> old_value,MaybeHandle<FieldType> new_field_type,MaybeHandle<Object> new_value)2832 void Map::PrintGeneralization(
2833 FILE* file, const char* reason, int modify_index, int split,
2834 int descriptors, bool descriptor_to_field,
2835 Representation old_representation, Representation new_representation,
2836 MaybeHandle<FieldType> old_field_type, MaybeHandle<Object> old_value,
2837 MaybeHandle<FieldType> new_field_type, MaybeHandle<Object> new_value) {
2838 OFStream os(file);
2839 os << "[generalizing]";
2840 Name* name = instance_descriptors()->GetKey(modify_index);
2841 if (name->IsString()) {
2842 String::cast(name)->PrintOn(file);
2843 } else {
2844 os << "{symbol " << static_cast<void*>(name) << "}";
2845 }
2846 os << ":";
2847 if (descriptor_to_field) {
2848 os << "c";
2849 } else {
2850 os << old_representation.Mnemonic() << "{";
2851 if (old_field_type.is_null()) {
2852 os << Brief(*(old_value.ToHandleChecked()));
2853 } else {
2854 old_field_type.ToHandleChecked()->PrintTo(os);
2855 }
2856 os << "}";
2857 }
2858 os << "->" << new_representation.Mnemonic() << "{";
2859 if (new_field_type.is_null()) {
2860 os << Brief(*(new_value.ToHandleChecked()));
2861 } else {
2862 new_field_type.ToHandleChecked()->PrintTo(os);
2863 }
2864 os << "} (";
2865 if (strlen(reason) > 0) {
2866 os << reason;
2867 } else {
2868 os << "+" << (descriptors - split) << " maps";
2869 }
2870 os << ") [";
2871 JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
2872 os << "]\n";
2873 }
2874
2875
PrintInstanceMigration(FILE * file,Map * original_map,Map * new_map)2876 void JSObject::PrintInstanceMigration(FILE* file,
2877 Map* original_map,
2878 Map* new_map) {
2879 PrintF(file, "[migrating]");
2880 DescriptorArray* o = original_map->instance_descriptors();
2881 DescriptorArray* n = new_map->instance_descriptors();
2882 for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) {
2883 Representation o_r = o->GetDetails(i).representation();
2884 Representation n_r = n->GetDetails(i).representation();
2885 if (!o_r.Equals(n_r)) {
2886 String::cast(o->GetKey(i))->PrintOn(file);
2887 PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic());
2888 } else if (o->GetDetails(i).location() == kDescriptor &&
2889 n->GetDetails(i).location() == kField) {
2890 Name* name = o->GetKey(i);
2891 if (name->IsString()) {
2892 String::cast(name)->PrintOn(file);
2893 } else {
2894 PrintF(file, "{symbol %p}", static_cast<void*>(name));
2895 }
2896 PrintF(file, " ");
2897 }
2898 }
2899 PrintF(file, "\n");
2900 }
2901
2902
HeapObjectShortPrint(std::ostream & os)2903 void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
2904 Heap* heap = GetHeap();
2905 Isolate* isolate = heap->isolate();
2906 if (!heap->Contains(this)) {
2907 os << "!!!INVALID POINTER!!!";
2908 return;
2909 }
2910 if (!heap->Contains(map())) {
2911 os << "!!!INVALID MAP!!!";
2912 return;
2913 }
2914
2915 os << this << " ";
2916
2917 if (IsString()) {
2918 HeapStringAllocator allocator;
2919 StringStream accumulator(&allocator);
2920 String::cast(this)->StringShortPrint(&accumulator);
2921 os << accumulator.ToCString().get();
2922 return;
2923 }
2924 if (IsJSObject()) {
2925 HeapStringAllocator allocator;
2926 StringStream accumulator(&allocator);
2927 JSObject::cast(this)->JSObjectShortPrint(&accumulator);
2928 os << accumulator.ToCString().get();
2929 return;
2930 }
2931 switch (map()->instance_type()) {
2932 case MAP_TYPE:
2933 os << "<Map(" << ElementsKindToString(Map::cast(this)->elements_kind())
2934 << ")>";
2935 break;
2936 case FIXED_ARRAY_TYPE:
2937 os << "<FixedArray[" << FixedArray::cast(this)->length() << "]>";
2938 break;
2939 case FIXED_DOUBLE_ARRAY_TYPE:
2940 os << "<FixedDoubleArray[" << FixedDoubleArray::cast(this)->length()
2941 << "]>";
2942 break;
2943 case BYTE_ARRAY_TYPE:
2944 os << "<ByteArray[" << ByteArray::cast(this)->length() << "]>";
2945 break;
2946 case BYTECODE_ARRAY_TYPE:
2947 os << "<BytecodeArray[" << BytecodeArray::cast(this)->length() << "]>";
2948 break;
2949 case TRANSITION_ARRAY_TYPE:
2950 os << "<TransitionArray[" << TransitionArray::cast(this)->length()
2951 << "]>";
2952 break;
2953 case FREE_SPACE_TYPE:
2954 os << "<FreeSpace[" << FreeSpace::cast(this)->size() << "]>";
2955 break;
2956 #define TYPED_ARRAY_SHORT_PRINT(Type, type, TYPE, ctype, size) \
2957 case FIXED_##TYPE##_ARRAY_TYPE: \
2958 os << "<Fixed" #Type "Array[" << Fixed##Type##Array::cast(this)->length() \
2959 << "]>"; \
2960 break;
2961
2962 TYPED_ARRAYS(TYPED_ARRAY_SHORT_PRINT)
2963 #undef TYPED_ARRAY_SHORT_PRINT
2964
2965 case SHARED_FUNCTION_INFO_TYPE: {
2966 SharedFunctionInfo* shared = SharedFunctionInfo::cast(this);
2967 std::unique_ptr<char[]> debug_name = shared->DebugName()->ToCString();
2968 if (debug_name[0] != 0) {
2969 os << "<SharedFunctionInfo " << debug_name.get() << ">";
2970 } else {
2971 os << "<SharedFunctionInfo>";
2972 }
2973 break;
2974 }
2975 case JS_MESSAGE_OBJECT_TYPE:
2976 os << "<JSMessageObject>";
2977 break;
2978 #define MAKE_STRUCT_CASE(NAME, Name, name) \
2979 case NAME##_TYPE: \
2980 os << "<" #Name ">"; \
2981 break;
2982 STRUCT_LIST(MAKE_STRUCT_CASE)
2983 #undef MAKE_STRUCT_CASE
2984 case CODE_TYPE: {
2985 Code* code = Code::cast(this);
2986 os << "<Code: " << Code::Kind2String(code->kind()) << ">";
2987 break;
2988 }
2989 case ODDBALL_TYPE: {
2990 if (IsUndefined(isolate)) {
2991 os << "<undefined>";
2992 } else if (IsTheHole(isolate)) {
2993 os << "<the hole>";
2994 } else if (IsNull(isolate)) {
2995 os << "<null>";
2996 } else if (IsTrue(isolate)) {
2997 os << "<true>";
2998 } else if (IsFalse(isolate)) {
2999 os << "<false>";
3000 } else {
3001 os << "<Odd Oddball: ";
3002 os << Oddball::cast(this)->to_string()->ToCString().get();
3003 os << ">";
3004 }
3005 break;
3006 }
3007 case SYMBOL_TYPE: {
3008 Symbol* symbol = Symbol::cast(this);
3009 symbol->SymbolShortPrint(os);
3010 break;
3011 }
3012 case HEAP_NUMBER_TYPE: {
3013 os << "<Number: ";
3014 HeapNumber::cast(this)->HeapNumberPrint(os);
3015 os << ">";
3016 break;
3017 }
3018 case MUTABLE_HEAP_NUMBER_TYPE: {
3019 os << "<MutableNumber: ";
3020 HeapNumber::cast(this)->HeapNumberPrint(os);
3021 os << '>';
3022 break;
3023 }
3024 case JS_PROXY_TYPE:
3025 os << "<JSProxy>";
3026 break;
3027 case FOREIGN_TYPE:
3028 os << "<Foreign>";
3029 break;
3030 case CELL_TYPE: {
3031 os << "Cell for ";
3032 HeapStringAllocator allocator;
3033 StringStream accumulator(&allocator);
3034 Cell::cast(this)->value()->ShortPrint(&accumulator);
3035 os << accumulator.ToCString().get();
3036 break;
3037 }
3038 case PROPERTY_CELL_TYPE: {
3039 os << "PropertyCell for ";
3040 HeapStringAllocator allocator;
3041 StringStream accumulator(&allocator);
3042 PropertyCell* cell = PropertyCell::cast(this);
3043 cell->value()->ShortPrint(&accumulator);
3044 os << accumulator.ToCString().get();
3045 break;
3046 }
3047 case WEAK_CELL_TYPE: {
3048 os << "WeakCell for ";
3049 HeapStringAllocator allocator;
3050 StringStream accumulator(&allocator);
3051 WeakCell::cast(this)->value()->ShortPrint(&accumulator);
3052 os << accumulator.ToCString().get();
3053 break;
3054 }
3055 default:
3056 os << "<Other heap object (" << map()->instance_type() << ")>";
3057 break;
3058 }
3059 }
3060
3061
Iterate(ObjectVisitor * v)3062 void HeapObject::Iterate(ObjectVisitor* v) { IterateFast<ObjectVisitor>(v); }
3063
3064
IterateBody(ObjectVisitor * v)3065 void HeapObject::IterateBody(ObjectVisitor* v) {
3066 Map* m = map();
3067 IterateBodyFast<ObjectVisitor>(m->instance_type(), SizeFromMap(m), v);
3068 }
3069
3070
IterateBody(InstanceType type,int object_size,ObjectVisitor * v)3071 void HeapObject::IterateBody(InstanceType type, int object_size,
3072 ObjectVisitor* v) {
3073 IterateBodyFast<ObjectVisitor>(type, object_size, v);
3074 }
3075
3076
3077 struct CallIsValidSlot {
3078 template <typename BodyDescriptor>
applyv8::internal::CallIsValidSlot3079 static bool apply(HeapObject* obj, int offset, int) {
3080 return BodyDescriptor::IsValidSlot(obj, offset);
3081 }
3082 };
3083
3084
IsValidSlot(int offset)3085 bool HeapObject::IsValidSlot(int offset) {
3086 DCHECK_NE(0, offset);
3087 return BodyDescriptorApply<CallIsValidSlot, bool>(map()->instance_type(),
3088 this, offset, 0);
3089 }
3090
3091
HeapNumberBooleanValue()3092 bool HeapNumber::HeapNumberBooleanValue() {
3093 return DoubleToBoolean(value());
3094 }
3095
3096
HeapNumberPrint(std::ostream & os)3097 void HeapNumber::HeapNumberPrint(std::ostream& os) { // NOLINT
3098 os << value();
3099 }
3100
3101
3102 #define FIELD_ADDR_CONST(p, offset) \
3103 (reinterpret_cast<const byte*>(p) + offset - kHeapObjectTag)
3104
3105 #define READ_INT32_FIELD(p, offset) \
3106 (*reinterpret_cast<const int32_t*>(FIELD_ADDR_CONST(p, offset)))
3107
3108 #define READ_INT64_FIELD(p, offset) \
3109 (*reinterpret_cast<const int64_t*>(FIELD_ADDR_CONST(p, offset)))
3110
3111 #define READ_BYTE_FIELD(p, offset) \
3112 (*reinterpret_cast<const byte*>(FIELD_ADDR_CONST(p, offset)))
3113
class_name()3114 String* JSReceiver::class_name() {
3115 if (IsFunction()) {
3116 return GetHeap()->Function_string();
3117 }
3118 Object* maybe_constructor = map()->GetConstructor();
3119 if (maybe_constructor->IsJSFunction()) {
3120 JSFunction* constructor = JSFunction::cast(maybe_constructor);
3121 return String::cast(constructor->shared()->instance_class_name());
3122 }
3123 // If the constructor is not present, return "Object".
3124 return GetHeap()->Object_string();
3125 }
3126
3127
3128 // static
GetConstructorName(Handle<JSReceiver> receiver)3129 Handle<String> JSReceiver::GetConstructorName(Handle<JSReceiver> receiver) {
3130 Isolate* isolate = receiver->GetIsolate();
3131
3132 // If the object was instantiated simply with base == new.target, the
3133 // constructor on the map provides the most accurate name.
3134 // Don't provide the info for prototypes, since their constructors are
3135 // reclaimed and replaced by Object in OptimizeAsPrototype.
3136 if (!receiver->IsJSProxy() && receiver->map()->new_target_is_base() &&
3137 !receiver->map()->is_prototype_map()) {
3138 Object* maybe_constructor = receiver->map()->GetConstructor();
3139 if (maybe_constructor->IsJSFunction()) {
3140 JSFunction* constructor = JSFunction::cast(maybe_constructor);
3141 String* name = String::cast(constructor->shared()->name());
3142 if (name->length() == 0) name = constructor->shared()->inferred_name();
3143 if (name->length() != 0 &&
3144 !name->Equals(isolate->heap()->Object_string())) {
3145 return handle(name, isolate);
3146 }
3147 }
3148 }
3149
3150 Handle<Object> maybe_tag = JSReceiver::GetDataProperty(
3151 receiver, isolate->factory()->to_string_tag_symbol());
3152 if (maybe_tag->IsString()) return Handle<String>::cast(maybe_tag);
3153
3154 PrototypeIterator iter(isolate, receiver);
3155 if (iter.IsAtEnd()) return handle(receiver->class_name());
3156 Handle<JSReceiver> start = PrototypeIterator::GetCurrent<JSReceiver>(iter);
3157 LookupIterator it(receiver, isolate->factory()->constructor_string(), start,
3158 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
3159 Handle<Object> maybe_constructor = JSReceiver::GetDataProperty(&it);
3160 Handle<String> result = isolate->factory()->Object_string();
3161 if (maybe_constructor->IsJSFunction()) {
3162 JSFunction* constructor = JSFunction::cast(*maybe_constructor);
3163 String* name = String::cast(constructor->shared()->name());
3164 if (name->length() == 0) name = constructor->shared()->inferred_name();
3165 if (name->length() > 0) result = handle(name, isolate);
3166 }
3167
3168 return result.is_identical_to(isolate->factory()->Object_string())
3169 ? handle(receiver->class_name())
3170 : result;
3171 }
3172
GetCreationContext()3173 Handle<Context> JSReceiver::GetCreationContext() {
3174 JSReceiver* receiver = this;
3175 while (receiver->IsJSBoundFunction()) {
3176 receiver = JSBoundFunction::cast(receiver)->bound_target_function();
3177 }
3178 Object* constructor = receiver->map()->GetConstructor();
3179 JSFunction* function;
3180 if (constructor->IsJSFunction()) {
3181 function = JSFunction::cast(constructor);
3182 } else {
3183 // Functions have null as a constructor,
3184 // but any JSFunction knows its context immediately.
3185 CHECK(receiver->IsJSFunction());
3186 function = JSFunction::cast(receiver);
3187 }
3188
3189 return function->has_context()
3190 ? Handle<Context>(function->context()->native_context())
3191 : Handle<Context>::null();
3192 }
3193
WrapFieldType(Handle<FieldType> type)3194 Handle<Object> Map::WrapFieldType(Handle<FieldType> type) {
3195 if (type->IsClass()) return Map::WeakCellForMap(type->AsClass());
3196 return type;
3197 }
3198
UnwrapFieldType(Object * wrapped_type)3199 FieldType* Map::UnwrapFieldType(Object* wrapped_type) {
3200 Object* value = wrapped_type;
3201 if (value->IsWeakCell()) {
3202 if (WeakCell::cast(value)->cleared()) return FieldType::None();
3203 value = WeakCell::cast(value)->value();
3204 }
3205 return FieldType::cast(value);
3206 }
3207
CopyWithField(Handle<Map> map,Handle<Name> name,Handle<FieldType> type,PropertyAttributes attributes,PropertyConstness constness,Representation representation,TransitionFlag flag)3208 MaybeHandle<Map> Map::CopyWithField(Handle<Map> map, Handle<Name> name,
3209 Handle<FieldType> type,
3210 PropertyAttributes attributes,
3211 PropertyConstness constness,
3212 Representation representation,
3213 TransitionFlag flag) {
3214 DCHECK(DescriptorArray::kNotFound ==
3215 map->instance_descriptors()->Search(
3216 *name, map->NumberOfOwnDescriptors()));
3217
3218 // Ensure the descriptor array does not get too big.
3219 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
3220 return MaybeHandle<Map>();
3221 }
3222
3223 Isolate* isolate = map->GetIsolate();
3224
3225 // Compute the new index for new field.
3226 int index = map->NextFreePropertyIndex();
3227
3228 if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
3229 representation = Representation::Tagged();
3230 type = FieldType::Any(isolate);
3231 }
3232
3233 Handle<Object> wrapped_type(WrapFieldType(type));
3234
3235 DCHECK_IMPLIES(!FLAG_track_constant_fields, constness == kMutable);
3236 Descriptor d = Descriptor::DataField(name, index, attributes, constness,
3237 representation, wrapped_type);
3238 Handle<Map> new_map = Map::CopyAddDescriptor(map, &d, flag);
3239 int unused_property_fields = new_map->unused_property_fields() - 1;
3240 if (unused_property_fields < 0) {
3241 unused_property_fields += JSObject::kFieldsAdded;
3242 }
3243 new_map->set_unused_property_fields(unused_property_fields);
3244 return new_map;
3245 }
3246
3247
CopyWithConstant(Handle<Map> map,Handle<Name> name,Handle<Object> constant,PropertyAttributes attributes,TransitionFlag flag)3248 MaybeHandle<Map> Map::CopyWithConstant(Handle<Map> map,
3249 Handle<Name> name,
3250 Handle<Object> constant,
3251 PropertyAttributes attributes,
3252 TransitionFlag flag) {
3253 // Ensure the descriptor array does not get too big.
3254 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
3255 return MaybeHandle<Map>();
3256 }
3257
3258 if (FLAG_track_constant_fields) {
3259 Isolate* isolate = map->GetIsolate();
3260 Representation representation = constant->OptimalRepresentation();
3261 Handle<FieldType> type = constant->OptimalType(isolate, representation);
3262 return CopyWithField(map, name, type, attributes, kConst, representation,
3263 flag);
3264 } else {
3265 // Allocate new instance descriptors with (name, constant) added.
3266 Descriptor d = Descriptor::DataConstant(name, 0, constant, attributes);
3267 Handle<Map> new_map = Map::CopyAddDescriptor(map, &d, flag);
3268 return new_map;
3269 }
3270 }
3271
Mnemonic() const3272 const char* Representation::Mnemonic() const {
3273 switch (kind_) {
3274 case kNone: return "v";
3275 case kTagged: return "t";
3276 case kSmi: return "s";
3277 case kDouble: return "d";
3278 case kInteger32: return "i";
3279 case kHeapObject: return "h";
3280 case kExternal: return "x";
3281 default:
3282 UNREACHABLE();
3283 return NULL;
3284 }
3285 }
3286
TransitionRemovesTaggedField(Map * target)3287 bool Map::TransitionRemovesTaggedField(Map* target) {
3288 int inobject = GetInObjectProperties();
3289 int target_inobject = target->GetInObjectProperties();
3290 for (int i = target_inobject; i < inobject; i++) {
3291 FieldIndex index = FieldIndex::ForPropertyIndex(this, i);
3292 if (!IsUnboxedDoubleField(index)) return true;
3293 }
3294 return false;
3295 }
3296
TransitionChangesTaggedFieldToUntaggedField(Map * target)3297 bool Map::TransitionChangesTaggedFieldToUntaggedField(Map* target) {
3298 int inobject = GetInObjectProperties();
3299 int target_inobject = target->GetInObjectProperties();
3300 int limit = Min(inobject, target_inobject);
3301 for (int i = 0; i < limit; i++) {
3302 FieldIndex index = FieldIndex::ForPropertyIndex(target, i);
3303 if (!IsUnboxedDoubleField(index) && target->IsUnboxedDoubleField(index)) {
3304 return true;
3305 }
3306 }
3307 return false;
3308 }
3309
TransitionRequiresSynchronizationWithGC(Map * target)3310 bool Map::TransitionRequiresSynchronizationWithGC(Map* target) {
3311 return TransitionRemovesTaggedField(target) ||
3312 TransitionChangesTaggedFieldToUntaggedField(target);
3313 }
3314
InstancesNeedRewriting(Map * target)3315 bool Map::InstancesNeedRewriting(Map* target) {
3316 int target_number_of_fields = target->NumberOfFields();
3317 int target_inobject = target->GetInObjectProperties();
3318 int target_unused = target->unused_property_fields();
3319 int old_number_of_fields;
3320
3321 return InstancesNeedRewriting(target, target_number_of_fields,
3322 target_inobject, target_unused,
3323 &old_number_of_fields);
3324 }
3325
InstancesNeedRewriting(Map * target,int target_number_of_fields,int target_inobject,int target_unused,int * old_number_of_fields)3326 bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields,
3327 int target_inobject, int target_unused,
3328 int* old_number_of_fields) {
3329 // If fields were added (or removed), rewrite the instance.
3330 *old_number_of_fields = NumberOfFields();
3331 DCHECK(target_number_of_fields >= *old_number_of_fields);
3332 if (target_number_of_fields != *old_number_of_fields) return true;
3333
3334 // If smi descriptors were replaced by double descriptors, rewrite.
3335 DescriptorArray* old_desc = instance_descriptors();
3336 DescriptorArray* new_desc = target->instance_descriptors();
3337 int limit = NumberOfOwnDescriptors();
3338 for (int i = 0; i < limit; i++) {
3339 if (new_desc->GetDetails(i).representation().IsDouble() !=
3340 old_desc->GetDetails(i).representation().IsDouble()) {
3341 return true;
3342 }
3343 }
3344
3345 // If no fields were added, and no inobject properties were removed, setting
3346 // the map is sufficient.
3347 if (target_inobject == GetInObjectProperties()) return false;
3348 // In-object slack tracking may have reduced the object size of the new map.
3349 // In that case, succeed if all existing fields were inobject, and they still
3350 // fit within the new inobject size.
3351 DCHECK(target_inobject < GetInObjectProperties());
3352 if (target_number_of_fields <= target_inobject) {
3353 DCHECK(target_number_of_fields + target_unused == target_inobject);
3354 return false;
3355 }
3356 // Otherwise, properties will need to be moved to the backing store.
3357 return true;
3358 }
3359
3360
3361 // static
UpdatePrototypeUserRegistration(Handle<Map> old_map,Handle<Map> new_map,Isolate * isolate)3362 void JSObject::UpdatePrototypeUserRegistration(Handle<Map> old_map,
3363 Handle<Map> new_map,
3364 Isolate* isolate) {
3365 DCHECK(old_map->is_prototype_map());
3366 DCHECK(new_map->is_prototype_map());
3367 bool was_registered = JSObject::UnregisterPrototypeUser(old_map, isolate);
3368 new_map->set_prototype_info(old_map->prototype_info());
3369 old_map->set_prototype_info(Smi::kZero);
3370 if (FLAG_trace_prototype_users) {
3371 PrintF("Moving prototype_info %p from map %p to map %p.\n",
3372 reinterpret_cast<void*>(new_map->prototype_info()),
3373 reinterpret_cast<void*>(*old_map),
3374 reinterpret_cast<void*>(*new_map));
3375 }
3376 if (was_registered) {
3377 if (new_map->prototype_info()->IsPrototypeInfo()) {
3378 // The new map isn't registered with its prototype yet; reflect this fact
3379 // in the PrototypeInfo it just inherited from the old map.
3380 PrototypeInfo::cast(new_map->prototype_info())
3381 ->set_registry_slot(PrototypeInfo::UNREGISTERED);
3382 }
3383 JSObject::LazyRegisterPrototypeUser(new_map, isolate);
3384 }
3385 }
3386
3387 namespace {
3388 // To migrate a fast instance to a fast map:
3389 // - First check whether the instance needs to be rewritten. If not, simply
3390 // change the map.
3391 // - Otherwise, allocate a fixed array large enough to hold all fields, in
3392 // addition to unused space.
3393 // - Copy all existing properties in, in the following order: backing store
3394 // properties, unused fields, inobject properties.
3395 // - If all allocation succeeded, commit the state atomically:
3396 // * Copy inobject properties from the backing store back into the object.
3397 // * Trim the difference in instance size of the object. This also cleanly
3398 // frees inobject properties that moved to the backing store.
3399 // * If there are properties left in the backing store, trim of the space used
3400 // to temporarily store the inobject properties.
3401 // * If there are properties left in the backing store, install the backing
3402 // store.
MigrateFastToFast(Handle<JSObject> object,Handle<Map> new_map)3403 void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
3404 Isolate* isolate = object->GetIsolate();
3405 Handle<Map> old_map(object->map());
3406 // In case of a regular transition.
3407 if (new_map->GetBackPointer() == *old_map) {
3408 // If the map does not add named properties, simply set the map.
3409 if (old_map->NumberOfOwnDescriptors() ==
3410 new_map->NumberOfOwnDescriptors()) {
3411 object->synchronized_set_map(*new_map);
3412 return;
3413 }
3414
3415 PropertyDetails details = new_map->GetLastDescriptorDetails();
3416 // Either new_map adds an kDescriptor property, or a kField property for
3417 // which there is still space, and which does not require a mutable double
3418 // box (an out-of-object double).
3419 if (details.location() == kDescriptor ||
3420 (old_map->unused_property_fields() > 0 &&
3421 ((FLAG_unbox_double_fields && object->properties()->length() == 0) ||
3422 !details.representation().IsDouble()))) {
3423 object->synchronized_set_map(*new_map);
3424 return;
3425 }
3426
3427 // If there is still space in the object, we need to allocate a mutable
3428 // double box.
3429 if (old_map->unused_property_fields() > 0) {
3430 FieldIndex index =
3431 FieldIndex::ForDescriptor(*new_map, new_map->LastAdded());
3432 DCHECK(details.representation().IsDouble());
3433 DCHECK(!new_map->IsUnboxedDoubleField(index));
3434 Handle<Object> value = isolate->factory()->NewMutableHeapNumber();
3435 object->RawFastPropertyAtPut(index, *value);
3436 object->synchronized_set_map(*new_map);
3437 return;
3438 }
3439
3440 // This migration is a transition from a map that has run out of property
3441 // space. Extend the backing store.
3442 int grow_by = new_map->unused_property_fields() + 1;
3443 Handle<FixedArray> old_storage = handle(object->properties(), isolate);
3444 Handle<FixedArray> new_storage =
3445 isolate->factory()->CopyFixedArrayAndGrow(old_storage, grow_by);
3446
3447 // Properly initialize newly added property.
3448 Handle<Object> value;
3449 if (details.representation().IsDouble()) {
3450 value = isolate->factory()->NewMutableHeapNumber();
3451 } else {
3452 value = isolate->factory()->uninitialized_value();
3453 }
3454 DCHECK_EQ(kField, details.location());
3455 DCHECK_EQ(kData, details.kind());
3456 int target_index = details.field_index() - new_map->GetInObjectProperties();
3457 DCHECK(target_index >= 0); // Must be a backing store index.
3458 new_storage->set(target_index, *value);
3459
3460 // From here on we cannot fail and we shouldn't GC anymore.
3461 DisallowHeapAllocation no_allocation;
3462
3463 // Set the new property value and do the map transition.
3464 object->set_properties(*new_storage);
3465 object->synchronized_set_map(*new_map);
3466 return;
3467 }
3468
3469 int old_number_of_fields;
3470 int number_of_fields = new_map->NumberOfFields();
3471 int inobject = new_map->GetInObjectProperties();
3472 int unused = new_map->unused_property_fields();
3473
3474 // Nothing to do if no functions were converted to fields and no smis were
3475 // converted to doubles.
3476 if (!old_map->InstancesNeedRewriting(*new_map, number_of_fields, inobject,
3477 unused, &old_number_of_fields)) {
3478 object->synchronized_set_map(*new_map);
3479 return;
3480 }
3481
3482 int total_size = number_of_fields + unused;
3483 int external = total_size - inobject;
3484
3485 Handle<FixedArray> array = isolate->factory()->NewFixedArray(total_size);
3486
3487 Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors());
3488 Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors());
3489 int old_nof = old_map->NumberOfOwnDescriptors();
3490 int new_nof = new_map->NumberOfOwnDescriptors();
3491
3492 // This method only supports generalizing instances to at least the same
3493 // number of properties.
3494 DCHECK(old_nof <= new_nof);
3495
3496 for (int i = 0; i < old_nof; i++) {
3497 PropertyDetails details = new_descriptors->GetDetails(i);
3498 if (details.location() != kField) continue;
3499 DCHECK_EQ(kData, details.kind());
3500 PropertyDetails old_details = old_descriptors->GetDetails(i);
3501 Representation old_representation = old_details.representation();
3502 Representation representation = details.representation();
3503 Handle<Object> value;
3504 if (old_details.location() == kDescriptor) {
3505 if (old_details.kind() == kAccessor) {
3506 // In case of kAccessor -> kData property reconfiguration, the property
3507 // must already be prepared for data of certain type.
3508 DCHECK(!details.representation().IsNone());
3509 if (details.representation().IsDouble()) {
3510 value = isolate->factory()->NewMutableHeapNumber();
3511 } else {
3512 value = isolate->factory()->uninitialized_value();
3513 }
3514 } else {
3515 DCHECK_EQ(kData, old_details.kind());
3516 value = handle(old_descriptors->GetValue(i), isolate);
3517 DCHECK(!old_representation.IsDouble() && !representation.IsDouble());
3518 }
3519 } else {
3520 DCHECK_EQ(kField, old_details.location());
3521 FieldIndex index = FieldIndex::ForDescriptor(*old_map, i);
3522 if (object->IsUnboxedDoubleField(index)) {
3523 uint64_t old_bits = object->RawFastDoublePropertyAsBitsAt(index);
3524 value = isolate->factory()->NewHeapNumberFromBits(
3525 old_bits, representation.IsDouble() ? MUTABLE : IMMUTABLE);
3526
3527 } else {
3528 value = handle(object->RawFastPropertyAt(index), isolate);
3529 if (!old_representation.IsDouble() && representation.IsDouble()) {
3530 DCHECK_IMPLIES(old_representation.IsNone(),
3531 value->IsUninitialized(isolate));
3532 value = Object::NewStorageFor(isolate, value, representation);
3533 } else if (old_representation.IsDouble() &&
3534 !representation.IsDouble()) {
3535 value = Object::WrapForRead(isolate, value, old_representation);
3536 }
3537 }
3538 }
3539 DCHECK(!(representation.IsDouble() && value->IsSmi()));
3540 int target_index = new_descriptors->GetFieldIndex(i) - inobject;
3541 if (target_index < 0) target_index += total_size;
3542 array->set(target_index, *value);
3543 }
3544
3545 for (int i = old_nof; i < new_nof; i++) {
3546 PropertyDetails details = new_descriptors->GetDetails(i);
3547 if (details.location() != kField) continue;
3548 DCHECK_EQ(kData, details.kind());
3549 Handle<Object> value;
3550 if (details.representation().IsDouble()) {
3551 value = isolate->factory()->NewMutableHeapNumber();
3552 } else {
3553 value = isolate->factory()->uninitialized_value();
3554 }
3555 int target_index = new_descriptors->GetFieldIndex(i) - inobject;
3556 if (target_index < 0) target_index += total_size;
3557 array->set(target_index, *value);
3558 }
3559
3560 // From here on we cannot fail and we shouldn't GC anymore.
3561 DisallowHeapAllocation no_allocation;
3562
3563 Heap* heap = isolate->heap();
3564
3565 heap->NotifyObjectLayoutChange(*object, no_allocation);
3566
3567 // Copy (real) inobject properties. If necessary, stop at number_of_fields to
3568 // avoid overwriting |one_pointer_filler_map|.
3569 int limit = Min(inobject, number_of_fields);
3570 for (int i = 0; i < limit; i++) {
3571 FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
3572 Object* value = array->get(external + i);
3573 // Can't use JSObject::FastPropertyAtPut() because proper map was not set
3574 // yet.
3575 if (new_map->IsUnboxedDoubleField(index)) {
3576 DCHECK(value->IsMutableHeapNumber());
3577 // Ensure that all bits of the double value are preserved.
3578 object->RawFastDoublePropertyAsBitsAtPut(
3579 index, HeapNumber::cast(value)->value_as_bits());
3580 if (i < old_number_of_fields && !old_map->IsUnboxedDoubleField(index)) {
3581 // Transition from tagged to untagged slot.
3582 heap->ClearRecordedSlot(*object,
3583 HeapObject::RawField(*object, index.offset()));
3584 } else {
3585 DCHECK(!heap->HasRecordedSlot(
3586 *object, HeapObject::RawField(*object, index.offset())));
3587 }
3588 } else {
3589 object->RawFastPropertyAtPut(index, value);
3590 }
3591 }
3592
3593
3594 // If there are properties in the new backing store, trim it to the correct
3595 // size and install the backing store into the object.
3596 if (external > 0) {
3597 heap->RightTrimFixedArray(*array, inobject);
3598 object->set_properties(*array);
3599 }
3600
3601 // Create filler object past the new instance size.
3602 int new_instance_size = new_map->instance_size();
3603 int instance_size_delta = old_map->instance_size() - new_instance_size;
3604 DCHECK(instance_size_delta >= 0);
3605
3606 if (instance_size_delta > 0) {
3607 Address address = object->address();
3608 heap->CreateFillerObjectAt(address + new_instance_size, instance_size_delta,
3609 ClearRecordedSlots::kYes);
3610 heap->AdjustLiveBytes(*object, -instance_size_delta);
3611 }
3612
3613 // We are storing the new map using release store after creating a filler for
3614 // the left-over space to avoid races with the sweeper thread.
3615 object->synchronized_set_map(*new_map);
3616 }
3617
MigrateFastToSlow(Handle<JSObject> object,Handle<Map> new_map,int expected_additional_properties)3618 void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map,
3619 int expected_additional_properties) {
3620 // The global object is always normalized.
3621 DCHECK(!object->IsJSGlobalObject());
3622 // JSGlobalProxy must never be normalized
3623 DCHECK(!object->IsJSGlobalProxy());
3624
3625 Isolate* isolate = object->GetIsolate();
3626 HandleScope scope(isolate);
3627 Handle<Map> map(object->map());
3628
3629 // Allocate new content.
3630 int real_size = map->NumberOfOwnDescriptors();
3631 int property_count = real_size;
3632 if (expected_additional_properties > 0) {
3633 property_count += expected_additional_properties;
3634 } else {
3635 // Make space for two more properties.
3636 property_count += NameDictionary::kInitialCapacity;
3637 }
3638 Handle<NameDictionary> dictionary =
3639 NameDictionary::New(isolate, property_count);
3640
3641 Handle<DescriptorArray> descs(map->instance_descriptors());
3642 for (int i = 0; i < real_size; i++) {
3643 PropertyDetails details = descs->GetDetails(i);
3644 Handle<Name> key(descs->GetKey(i));
3645 Handle<Object> value;
3646 if (details.location() == kField) {
3647 FieldIndex index = FieldIndex::ForDescriptor(*map, i);
3648 if (details.kind() == kData) {
3649 if (object->IsUnboxedDoubleField(index)) {
3650 double old_value = object->RawFastDoublePropertyAt(index);
3651 value = isolate->factory()->NewHeapNumber(old_value);
3652 } else {
3653 value = handle(object->RawFastPropertyAt(index), isolate);
3654 if (details.representation().IsDouble()) {
3655 DCHECK(value->IsMutableHeapNumber());
3656 Handle<HeapNumber> old = Handle<HeapNumber>::cast(value);
3657 value = isolate->factory()->NewHeapNumber(old->value());
3658 }
3659 }
3660 } else {
3661 DCHECK_EQ(kAccessor, details.kind());
3662 value = handle(object->RawFastPropertyAt(index), isolate);
3663 }
3664
3665 } else {
3666 DCHECK_EQ(kDescriptor, details.location());
3667 value = handle(descs->GetValue(i), isolate);
3668 }
3669 DCHECK(!value.is_null());
3670 PropertyDetails d(details.kind(), details.attributes(), i + 1,
3671 PropertyCellType::kNoCell);
3672 dictionary = NameDictionary::Add(dictionary, key, value, d);
3673 }
3674
3675 // Copy the next enumeration index from instance descriptor.
3676 dictionary->SetNextEnumerationIndex(real_size + 1);
3677
3678 // From here on we cannot fail and we shouldn't GC anymore.
3679 DisallowHeapAllocation no_allocation;
3680
3681 Heap* heap = isolate->heap();
3682 heap->NotifyObjectLayoutChange(*object, no_allocation);
3683
3684 // Resize the object in the heap if necessary.
3685 int new_instance_size = new_map->instance_size();
3686 int instance_size_delta = map->instance_size() - new_instance_size;
3687 DCHECK(instance_size_delta >= 0);
3688
3689 if (instance_size_delta > 0) {
3690 heap->CreateFillerObjectAt(object->address() + new_instance_size,
3691 instance_size_delta, ClearRecordedSlots::kYes);
3692 heap->AdjustLiveBytes(*object, -instance_size_delta);
3693 }
3694
3695 // We are storing the new map using release store after creating a filler for
3696 // the left-over space to avoid races with the sweeper thread.
3697 object->synchronized_set_map(*new_map);
3698
3699 object->set_properties(*dictionary);
3700
3701 // Ensure that in-object space of slow-mode object does not contain random
3702 // garbage.
3703 int inobject_properties = new_map->GetInObjectProperties();
3704 if (inobject_properties) {
3705 Heap* heap = isolate->heap();
3706 heap->ClearRecordedSlotRange(
3707 object->address() + map->GetInObjectPropertyOffset(0),
3708 object->address() + new_instance_size);
3709
3710 for (int i = 0; i < inobject_properties; i++) {
3711 FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
3712 object->RawFastPropertyAtPut(index, Smi::kZero);
3713 }
3714 }
3715
3716 isolate->counters()->props_to_dictionary()->Increment();
3717
3718 #ifdef DEBUG
3719 if (FLAG_trace_normalization) {
3720 OFStream os(stdout);
3721 os << "Object properties have been normalized:\n";
3722 object->Print(os);
3723 }
3724 #endif
3725 }
3726
3727 } // namespace
3728
3729 // static
NotifyMapChange(Handle<Map> old_map,Handle<Map> new_map,Isolate * isolate)3730 void JSObject::NotifyMapChange(Handle<Map> old_map, Handle<Map> new_map,
3731 Isolate* isolate) {
3732 if (!old_map->is_prototype_map()) return;
3733
3734 InvalidatePrototypeChains(*old_map);
3735
3736 // If the map was registered with its prototype before, ensure that it
3737 // registers with its new prototype now. This preserves the invariant that
3738 // when a map on a prototype chain is registered with its prototype, then
3739 // all prototypes further up the chain are also registered with their
3740 // respective prototypes.
3741 UpdatePrototypeUserRegistration(old_map, new_map, isolate);
3742 }
3743
MigrateToMap(Handle<JSObject> object,Handle<Map> new_map,int expected_additional_properties)3744 void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
3745 int expected_additional_properties) {
3746 if (object->map() == *new_map) return;
3747 Handle<Map> old_map(object->map());
3748 NotifyMapChange(old_map, new_map, new_map->GetIsolate());
3749
3750 if (old_map->is_dictionary_map()) {
3751 // For slow-to-fast migrations JSObject::MigrateSlowToFast()
3752 // must be used instead.
3753 CHECK(new_map->is_dictionary_map());
3754
3755 // Slow-to-slow migration is trivial.
3756 object->set_map(*new_map);
3757 } else if (!new_map->is_dictionary_map()) {
3758 MigrateFastToFast(object, new_map);
3759 if (old_map->is_prototype_map()) {
3760 DCHECK(!old_map->is_stable());
3761 DCHECK(new_map->is_stable());
3762 // Clear out the old descriptor array to avoid problems to sharing
3763 // the descriptor array without using an explicit.
3764 old_map->InitializeDescriptors(
3765 old_map->GetHeap()->empty_descriptor_array(),
3766 LayoutDescriptor::FastPointerLayout());
3767 // Ensure that no transition was inserted for prototype migrations.
3768 DCHECK_EQ(
3769 0, TransitionArray::NumberOfTransitions(old_map->raw_transitions()));
3770 DCHECK(new_map->GetBackPointer()->IsUndefined(new_map->GetIsolate()));
3771 }
3772 } else {
3773 MigrateFastToSlow(object, new_map, expected_additional_properties);
3774 }
3775
3776 // Careful: Don't allocate here!
3777 // For some callers of this method, |object| might be in an inconsistent
3778 // state now: the new map might have a new elements_kind, but the object's
3779 // elements pointer hasn't been updated yet. Callers will fix this, but in
3780 // the meantime, (indirectly) calling JSObjectVerify() must be avoided.
3781 // When adding code here, add a DisallowHeapAllocation too.
3782 }
3783
ForceSetPrototype(Handle<JSObject> object,Handle<Object> proto)3784 void JSObject::ForceSetPrototype(Handle<JSObject> object,
3785 Handle<Object> proto) {
3786 // object.__proto__ = proto;
3787 Handle<Map> old_map = Handle<Map>(object->map());
3788 Handle<Map> new_map = Map::Copy(old_map, "ForceSetPrototype");
3789 Map::SetPrototype(new_map, proto, FAST_PROTOTYPE);
3790 JSObject::MigrateToMap(object, new_map);
3791 }
3792
NumberOfFields()3793 int Map::NumberOfFields() {
3794 DescriptorArray* descriptors = instance_descriptors();
3795 int result = 0;
3796 for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
3797 if (descriptors->GetDetails(i).location() == kField) result++;
3798 }
3799 return result;
3800 }
3801
GeneralizeAllFields()3802 void DescriptorArray::GeneralizeAllFields() {
3803 int length = number_of_descriptors();
3804 for (int i = 0; i < length; i++) {
3805 PropertyDetails details = GetDetails(i);
3806 details = details.CopyWithRepresentation(Representation::Tagged());
3807 if (details.location() == kField) {
3808 DCHECK_EQ(kData, details.kind());
3809 details = details.CopyWithConstness(kMutable);
3810 SetValue(i, FieldType::Any());
3811 }
3812 set(ToDetailsIndex(i), details.AsSmi());
3813 }
3814 }
3815
CopyGeneralizeAllFields(Handle<Map> map,ElementsKind elements_kind,int modify_index,PropertyKind kind,PropertyAttributes attributes,const char * reason)3816 Handle<Map> Map::CopyGeneralizeAllFields(Handle<Map> map,
3817 ElementsKind elements_kind,
3818 int modify_index, PropertyKind kind,
3819 PropertyAttributes attributes,
3820 const char* reason) {
3821 Isolate* isolate = map->GetIsolate();
3822 Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
3823 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
3824 Handle<DescriptorArray> descriptors =
3825 DescriptorArray::CopyUpTo(old_descriptors, number_of_own_descriptors);
3826 descriptors->GeneralizeAllFields();
3827
3828 Handle<LayoutDescriptor> new_layout_descriptor(
3829 LayoutDescriptor::FastPointerLayout(), isolate);
3830 Handle<Map> new_map = CopyReplaceDescriptors(
3831 map, descriptors, new_layout_descriptor, OMIT_TRANSITION,
3832 MaybeHandle<Name>(), reason, SPECIAL_TRANSITION);
3833
3834 // Unless the instance is being migrated, ensure that modify_index is a field.
3835 if (modify_index >= 0) {
3836 PropertyDetails details = descriptors->GetDetails(modify_index);
3837 if (details.constness() != kMutable || details.location() != kField ||
3838 details.attributes() != attributes) {
3839 int field_index = details.location() == kField
3840 ? details.field_index()
3841 : new_map->NumberOfFields();
3842 Descriptor d = Descriptor::DataField(
3843 handle(descriptors->GetKey(modify_index), isolate), field_index,
3844 attributes, Representation::Tagged());
3845 descriptors->Replace(modify_index, &d);
3846 if (details.location() != kField) {
3847 int unused_property_fields = new_map->unused_property_fields() - 1;
3848 if (unused_property_fields < 0) {
3849 unused_property_fields += JSObject::kFieldsAdded;
3850 }
3851 new_map->set_unused_property_fields(unused_property_fields);
3852 }
3853 } else {
3854 DCHECK(details.attributes() == attributes);
3855 }
3856
3857 if (FLAG_trace_generalization) {
3858 MaybeHandle<FieldType> field_type = FieldType::None(isolate);
3859 if (details.location() == kField) {
3860 field_type = handle(
3861 map->instance_descriptors()->GetFieldType(modify_index), isolate);
3862 }
3863 map->PrintGeneralization(
3864 stdout, reason, modify_index, new_map->NumberOfOwnDescriptors(),
3865 new_map->NumberOfOwnDescriptors(), details.location() == kDescriptor,
3866 details.representation(), Representation::Tagged(), field_type,
3867 MaybeHandle<Object>(), FieldType::Any(isolate),
3868 MaybeHandle<Object>());
3869 }
3870 }
3871 new_map->set_elements_kind(elements_kind);
3872 return new_map;
3873 }
3874
3875
DeprecateTransitionTree()3876 void Map::DeprecateTransitionTree() {
3877 if (is_deprecated()) return;
3878 Object* transitions = raw_transitions();
3879 int num_transitions = TransitionArray::NumberOfTransitions(transitions);
3880 for (int i = 0; i < num_transitions; ++i) {
3881 TransitionArray::GetTarget(transitions, i)->DeprecateTransitionTree();
3882 }
3883 deprecate();
3884 dependent_code()->DeoptimizeDependentCodeGroup(
3885 GetIsolate(), DependentCode::kTransitionGroup);
3886 NotifyLeafMapLayoutChange();
3887 }
3888
3889
3890 // Installs |new_descriptors| over the current instance_descriptors to ensure
3891 // proper sharing of descriptor arrays.
ReplaceDescriptors(DescriptorArray * new_descriptors,LayoutDescriptor * new_layout_descriptor)3892 void Map::ReplaceDescriptors(DescriptorArray* new_descriptors,
3893 LayoutDescriptor* new_layout_descriptor) {
3894 Isolate* isolate = GetIsolate();
3895 // Don't overwrite the empty descriptor array or initial map's descriptors.
3896 if (NumberOfOwnDescriptors() == 0 || GetBackPointer()->IsUndefined(isolate)) {
3897 return;
3898 }
3899
3900 DescriptorArray* to_replace = instance_descriptors();
3901 isolate->heap()->incremental_marking()->IterateBlackObject(to_replace);
3902 Map* current = this;
3903 while (current->instance_descriptors() == to_replace) {
3904 Object* next = current->GetBackPointer();
3905 if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map.
3906 current->SetEnumLength(kInvalidEnumCacheSentinel);
3907 current->UpdateDescriptors(new_descriptors, new_layout_descriptor);
3908 current = Map::cast(next);
3909 }
3910 set_owns_descriptors(false);
3911 }
3912
3913
FindRootMap()3914 Map* Map::FindRootMap() {
3915 Map* result = this;
3916 Isolate* isolate = GetIsolate();
3917 while (true) {
3918 Object* back = result->GetBackPointer();
3919 if (back->IsUndefined(isolate)) {
3920 // Initial map always owns descriptors and doesn't have unused entries
3921 // in the descriptor array.
3922 DCHECK(result->owns_descriptors());
3923 DCHECK_EQ(result->NumberOfOwnDescriptors(),
3924 result->instance_descriptors()->number_of_descriptors());
3925 return result;
3926 }
3927 result = Map::cast(back);
3928 }
3929 }
3930
3931
FindFieldOwner(int descriptor)3932 Map* Map::FindFieldOwner(int descriptor) {
3933 DisallowHeapAllocation no_allocation;
3934 DCHECK_EQ(kField, instance_descriptors()->GetDetails(descriptor).location());
3935 Map* result = this;
3936 Isolate* isolate = GetIsolate();
3937 while (true) {
3938 Object* back = result->GetBackPointer();
3939 if (back->IsUndefined(isolate)) break;
3940 Map* parent = Map::cast(back);
3941 if (parent->NumberOfOwnDescriptors() <= descriptor) break;
3942 result = parent;
3943 }
3944 return result;
3945 }
3946
UpdateFieldType(int descriptor,Handle<Name> name,PropertyConstness new_constness,Representation new_representation,Handle<Object> new_wrapped_type)3947 void Map::UpdateFieldType(int descriptor, Handle<Name> name,
3948 PropertyConstness new_constness,
3949 Representation new_representation,
3950 Handle<Object> new_wrapped_type) {
3951 DCHECK(new_wrapped_type->IsSmi() || new_wrapped_type->IsWeakCell());
3952 // We store raw pointers in the queue, so no allocations are allowed.
3953 DisallowHeapAllocation no_allocation;
3954 PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
3955 if (details.location() != kField) return;
3956 DCHECK_EQ(kData, details.kind());
3957
3958 Zone zone(GetIsolate()->allocator(), ZONE_NAME);
3959 ZoneQueue<Map*> backlog(&zone);
3960 backlog.push(this);
3961
3962 while (!backlog.empty()) {
3963 Map* current = backlog.front();
3964 backlog.pop();
3965
3966 Object* transitions = current->raw_transitions();
3967 int num_transitions = TransitionArray::NumberOfTransitions(transitions);
3968 for (int i = 0; i < num_transitions; ++i) {
3969 Map* target = TransitionArray::GetTarget(transitions, i);
3970 backlog.push(target);
3971 }
3972 DescriptorArray* descriptors = current->instance_descriptors();
3973 PropertyDetails details = descriptors->GetDetails(descriptor);
3974
3975 // Currently constness change implies map change.
3976 DCHECK_EQ(new_constness, details.constness());
3977
3978 // It is allowed to change representation here only from None to something.
3979 DCHECK(details.representation().Equals(new_representation) ||
3980 details.representation().IsNone());
3981
3982 // Skip if already updated the shared descriptor.
3983 if (descriptors->GetValue(descriptor) != *new_wrapped_type) {
3984 DCHECK_IMPLIES(!FLAG_track_constant_fields, new_constness == kMutable);
3985 Descriptor d = Descriptor::DataField(
3986 name, descriptors->GetFieldIndex(descriptor), details.attributes(),
3987 new_constness, new_representation, new_wrapped_type);
3988 descriptors->Replace(descriptor, &d);
3989 }
3990 }
3991 }
3992
FieldTypeIsCleared(Representation rep,FieldType * type)3993 bool FieldTypeIsCleared(Representation rep, FieldType* type) {
3994 return type->IsNone() && rep.IsHeapObject();
3995 }
3996
3997
3998 // static
GeneralizeFieldType(Representation rep1,Handle<FieldType> type1,Representation rep2,Handle<FieldType> type2,Isolate * isolate)3999 Handle<FieldType> Map::GeneralizeFieldType(Representation rep1,
4000 Handle<FieldType> type1,
4001 Representation rep2,
4002 Handle<FieldType> type2,
4003 Isolate* isolate) {
4004 // Cleared field types need special treatment. They represent lost knowledge,
4005 // so we must be conservative, so their generalization with any other type
4006 // is "Any".
4007 if (FieldTypeIsCleared(rep1, *type1) || FieldTypeIsCleared(rep2, *type2)) {
4008 return FieldType::Any(isolate);
4009 }
4010 if (type1->NowIs(type2)) return type2;
4011 if (type2->NowIs(type1)) return type1;
4012 return FieldType::Any(isolate);
4013 }
4014
4015
4016 // static
GeneralizeField(Handle<Map> map,int modify_index,PropertyConstness new_constness,Representation new_representation,Handle<FieldType> new_field_type)4017 void Map::GeneralizeField(Handle<Map> map, int modify_index,
4018 PropertyConstness new_constness,
4019 Representation new_representation,
4020 Handle<FieldType> new_field_type) {
4021 Isolate* isolate = map->GetIsolate();
4022
4023 // Check if we actually need to generalize the field type at all.
4024 Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
4025 PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
4026 PropertyConstness old_constness = old_details.constness();
4027 Representation old_representation = old_details.representation();
4028 Handle<FieldType> old_field_type(old_descriptors->GetFieldType(modify_index),
4029 isolate);
4030
4031 if (old_constness == new_constness &&
4032 old_representation.Equals(new_representation) &&
4033 !FieldTypeIsCleared(new_representation, *new_field_type) &&
4034 // Checking old_field_type for being cleared is not necessary because
4035 // the NowIs check below would fail anyway in that case.
4036 new_field_type->NowIs(old_field_type)) {
4037 DCHECK(GeneralizeFieldType(old_representation, old_field_type,
4038 new_representation, new_field_type, isolate)
4039 ->NowIs(old_field_type));
4040 return;
4041 }
4042
4043 // Determine the field owner.
4044 Handle<Map> field_owner(map->FindFieldOwner(modify_index), isolate);
4045 Handle<DescriptorArray> descriptors(
4046 field_owner->instance_descriptors(), isolate);
4047 DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index));
4048
4049 new_field_type =
4050 Map::GeneralizeFieldType(old_representation, old_field_type,
4051 new_representation, new_field_type, isolate);
4052
4053 PropertyDetails details = descriptors->GetDetails(modify_index);
4054 Handle<Name> name(descriptors->GetKey(modify_index));
4055
4056 Handle<Object> wrapped_type(WrapFieldType(new_field_type));
4057 field_owner->UpdateFieldType(modify_index, name, new_constness,
4058 new_representation, wrapped_type);
4059 field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
4060 isolate, DependentCode::kFieldOwnerGroup);
4061
4062 if (FLAG_trace_generalization) {
4063 map->PrintGeneralization(
4064 stdout, "field type generalization", modify_index,
4065 map->NumberOfOwnDescriptors(), map->NumberOfOwnDescriptors(), false,
4066 details.representation(), details.representation(), old_field_type,
4067 MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>());
4068 }
4069 }
4070
4071 // TODO(ishell): remove.
4072 // static
ReconfigureProperty(Handle<Map> map,int modify_index,PropertyKind new_kind,PropertyAttributes new_attributes,Representation new_representation,Handle<FieldType> new_field_type)4073 Handle<Map> Map::ReconfigureProperty(Handle<Map> map, int modify_index,
4074 PropertyKind new_kind,
4075 PropertyAttributes new_attributes,
4076 Representation new_representation,
4077 Handle<FieldType> new_field_type) {
4078 DCHECK_EQ(kData, new_kind); // Only kData case is supported.
4079 MapUpdater mu(map->GetIsolate(), map);
4080 return mu.ReconfigureToDataField(modify_index, new_attributes, kConst,
4081 new_representation, new_field_type);
4082 }
4083
4084 // TODO(ishell): remove.
4085 // static
ReconfigureElementsKind(Handle<Map> map,ElementsKind new_elements_kind)4086 Handle<Map> Map::ReconfigureElementsKind(Handle<Map> map,
4087 ElementsKind new_elements_kind) {
4088 MapUpdater mu(map->GetIsolate(), map);
4089 return mu.ReconfigureElementsKind(new_elements_kind);
4090 }
4091
4092 // Generalize all fields and update the transition tree.
GeneralizeAllFields(Handle<Map> map)4093 Handle<Map> Map::GeneralizeAllFields(Handle<Map> map) {
4094 Isolate* isolate = map->GetIsolate();
4095 Handle<FieldType> any_type = FieldType::Any(isolate);
4096
4097 Handle<DescriptorArray> descriptors(map->instance_descriptors());
4098 for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) {
4099 PropertyDetails details = descriptors->GetDetails(i);
4100 if (details.location() == kField) {
4101 DCHECK_EQ(kData, details.kind());
4102 MapUpdater mu(isolate, map);
4103 map = mu.ReconfigureToDataField(i, details.attributes(), kMutable,
4104 Representation::Tagged(), any_type);
4105 }
4106 }
4107 return map;
4108 }
4109
4110
4111 // static
TryUpdate(Handle<Map> old_map)4112 MaybeHandle<Map> Map::TryUpdate(Handle<Map> old_map) {
4113 DisallowHeapAllocation no_allocation;
4114 DisallowDeoptimization no_deoptimization(old_map->GetIsolate());
4115
4116 if (!old_map->is_deprecated()) return old_map;
4117
4118 // Check the state of the root map.
4119 Map* root_map = old_map->FindRootMap();
4120 if (!old_map->EquivalentToForTransition(root_map)) return MaybeHandle<Map>();
4121
4122 ElementsKind from_kind = root_map->elements_kind();
4123 ElementsKind to_kind = old_map->elements_kind();
4124 if (from_kind != to_kind) {
4125 // Try to follow existing elements kind transitions.
4126 root_map = root_map->LookupElementsTransitionMap(to_kind);
4127 if (root_map == NULL) return MaybeHandle<Map>();
4128 // From here on, use the map with correct elements kind as root map.
4129 }
4130 Map* new_map = root_map->TryReplayPropertyTransitions(*old_map);
4131 if (new_map == nullptr) return MaybeHandle<Map>();
4132 return handle(new_map);
4133 }
4134
TryReplayPropertyTransitions(Map * old_map)4135 Map* Map::TryReplayPropertyTransitions(Map* old_map) {
4136 DisallowHeapAllocation no_allocation;
4137 DisallowDeoptimization no_deoptimization(GetIsolate());
4138
4139 int root_nof = NumberOfOwnDescriptors();
4140
4141 int old_nof = old_map->NumberOfOwnDescriptors();
4142 DescriptorArray* old_descriptors = old_map->instance_descriptors();
4143
4144 Map* new_map = this;
4145 for (int i = root_nof; i < old_nof; ++i) {
4146 PropertyDetails old_details = old_descriptors->GetDetails(i);
4147 Map* transition = TransitionArray::SearchTransition(
4148 new_map, old_details.kind(), old_descriptors->GetKey(i),
4149 old_details.attributes());
4150 if (transition == NULL) return nullptr;
4151 new_map = transition;
4152 DescriptorArray* new_descriptors = new_map->instance_descriptors();
4153
4154 PropertyDetails new_details = new_descriptors->GetDetails(i);
4155 DCHECK_EQ(old_details.kind(), new_details.kind());
4156 DCHECK_EQ(old_details.attributes(), new_details.attributes());
4157 if (!IsGeneralizableTo(old_details.constness(), new_details.constness())) {
4158 return nullptr;
4159 }
4160 DCHECK(IsGeneralizableTo(old_details.location(), new_details.location()));
4161 if (!old_details.representation().fits_into(new_details.representation())) {
4162 return nullptr;
4163 }
4164 if (new_details.location() == kField) {
4165 if (new_details.kind() == kData) {
4166 FieldType* new_type = new_descriptors->GetFieldType(i);
4167 // Cleared field types need special treatment. They represent lost
4168 // knowledge, so we must first generalize the new_type to "Any".
4169 if (FieldTypeIsCleared(new_details.representation(), new_type)) {
4170 return nullptr;
4171 }
4172 DCHECK_EQ(kData, old_details.kind());
4173 if (old_details.location() == kField) {
4174 FieldType* old_type = old_descriptors->GetFieldType(i);
4175 if (FieldTypeIsCleared(old_details.representation(), old_type) ||
4176 !old_type->NowIs(new_type)) {
4177 return nullptr;
4178 }
4179 } else {
4180 DCHECK_EQ(kDescriptor, old_details.location());
4181 DCHECK(!FLAG_track_constant_fields);
4182 Object* old_value = old_descriptors->GetValue(i);
4183 if (!new_type->NowContains(old_value)) {
4184 return nullptr;
4185 }
4186 }
4187
4188 } else {
4189 DCHECK_EQ(kAccessor, new_details.kind());
4190 #ifdef DEBUG
4191 FieldType* new_type = new_descriptors->GetFieldType(i);
4192 DCHECK(new_type->IsAny());
4193 #endif
4194 UNREACHABLE();
4195 }
4196 } else {
4197 DCHECK_EQ(kDescriptor, new_details.location());
4198 Object* old_value = old_descriptors->GetValue(i);
4199 Object* new_value = new_descriptors->GetValue(i);
4200 if (old_details.location() == kField || old_value != new_value) {
4201 return nullptr;
4202 }
4203 }
4204 }
4205 if (new_map->NumberOfOwnDescriptors() != old_nof) return nullptr;
4206 return new_map;
4207 }
4208
4209
4210 // static
Update(Handle<Map> map)4211 Handle<Map> Map::Update(Handle<Map> map) {
4212 if (!map->is_deprecated()) return map;
4213 MapUpdater mu(map->GetIsolate(), map);
4214 return mu.Update();
4215 }
4216
SetPropertyWithInterceptor(LookupIterator * it,ShouldThrow should_throw,Handle<Object> value)4217 Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
4218 ShouldThrow should_throw,
4219 Handle<Object> value) {
4220 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
4221 return SetPropertyWithInterceptorInternal(it, it->GetInterceptor(),
4222 should_throw, value);
4223 }
4224
SetProperty(Handle<Object> object,Handle<Name> name,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode)4225 MaybeHandle<Object> Object::SetProperty(Handle<Object> object,
4226 Handle<Name> name, Handle<Object> value,
4227 LanguageMode language_mode,
4228 StoreFromKeyed store_mode) {
4229 LookupIterator it(object, name);
4230 MAYBE_RETURN_NULL(SetProperty(&it, value, language_mode, store_mode));
4231 return value;
4232 }
4233
4234
SetPropertyInternal(LookupIterator * it,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode,bool * found)4235 Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
4236 Handle<Object> value,
4237 LanguageMode language_mode,
4238 StoreFromKeyed store_mode,
4239 bool* found) {
4240 it->UpdateProtector();
4241 DCHECK(it->IsFound());
4242 ShouldThrow should_throw =
4243 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4244
4245 // Make sure that the top context does not change when doing callbacks or
4246 // interceptor calls.
4247 AssertNoContextChange ncc(it->isolate());
4248
4249 do {
4250 switch (it->state()) {
4251 case LookupIterator::NOT_FOUND:
4252 UNREACHABLE();
4253
4254 case LookupIterator::ACCESS_CHECK:
4255 if (it->HasAccess()) break;
4256 // Check whether it makes sense to reuse the lookup iterator. Here it
4257 // might still call into setters up the prototype chain.
4258 return JSObject::SetPropertyWithFailedAccessCheck(it, value,
4259 should_throw);
4260
4261 case LookupIterator::JSPROXY:
4262 return JSProxy::SetProperty(it->GetHolder<JSProxy>(), it->GetName(),
4263 value, it->GetReceiver(), language_mode);
4264
4265 case LookupIterator::INTERCEPTOR: {
4266 if (it->HolderIsReceiverOrHiddenPrototype()) {
4267 Maybe<bool> result =
4268 JSObject::SetPropertyWithInterceptor(it, should_throw, value);
4269 if (result.IsNothing() || result.FromJust()) return result;
4270 } else {
4271 Maybe<PropertyAttributes> maybe_attributes =
4272 JSObject::GetPropertyAttributesWithInterceptor(it);
4273 if (!maybe_attributes.IsJust()) return Nothing<bool>();
4274 if ((maybe_attributes.FromJust() & READ_ONLY) != 0) {
4275 return WriteToReadOnlyProperty(it, value, should_throw);
4276 }
4277 if (maybe_attributes.FromJust() == ABSENT) break;
4278 *found = false;
4279 return Nothing<bool>();
4280 }
4281 break;
4282 }
4283
4284 case LookupIterator::ACCESSOR: {
4285 if (it->IsReadOnly()) {
4286 return WriteToReadOnlyProperty(it, value, should_throw);
4287 }
4288 Handle<Object> accessors = it->GetAccessors();
4289 if (accessors->IsAccessorInfo() &&
4290 !it->HolderIsReceiverOrHiddenPrototype() &&
4291 AccessorInfo::cast(*accessors)->is_special_data_property()) {
4292 *found = false;
4293 return Nothing<bool>();
4294 }
4295 return SetPropertyWithAccessor(it, value, should_throw);
4296 }
4297 case LookupIterator::INTEGER_INDEXED_EXOTIC:
4298 // TODO(verwaest): We should throw an exception if holder is receiver.
4299 return Just(true);
4300
4301 case LookupIterator::DATA:
4302 if (it->IsReadOnly()) {
4303 return WriteToReadOnlyProperty(it, value, should_throw);
4304 }
4305 if (it->HolderIsReceiverOrHiddenPrototype()) {
4306 return SetDataProperty(it, value);
4307 }
4308 // Fall through.
4309 case LookupIterator::TRANSITION:
4310 *found = false;
4311 return Nothing<bool>();
4312 }
4313 it->Next();
4314 } while (it->IsFound());
4315
4316 *found = false;
4317 return Nothing<bool>();
4318 }
4319
4320
SetProperty(LookupIterator * it,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode)4321 Maybe<bool> Object::SetProperty(LookupIterator* it, Handle<Object> value,
4322 LanguageMode language_mode,
4323 StoreFromKeyed store_mode) {
4324 if (it->IsFound()) {
4325 bool found = true;
4326 Maybe<bool> result =
4327 SetPropertyInternal(it, value, language_mode, store_mode, &found);
4328 if (found) return result;
4329 }
4330
4331 // If the receiver is the JSGlobalObject, the store was contextual. In case
4332 // the property did not exist yet on the global object itself, we have to
4333 // throw a reference error in strict mode. In sloppy mode, we continue.
4334 if (is_strict(language_mode) && it->GetReceiver()->IsJSGlobalObject()) {
4335 it->isolate()->Throw(*it->isolate()->factory()->NewReferenceError(
4336 MessageTemplate::kNotDefined, it->name()));
4337 return Nothing<bool>();
4338 }
4339
4340 ShouldThrow should_throw =
4341 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4342 return AddDataProperty(it, value, NONE, should_throw, store_mode);
4343 }
4344
4345
SetSuperProperty(LookupIterator * it,Handle<Object> value,LanguageMode language_mode,StoreFromKeyed store_mode)4346 Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
4347 LanguageMode language_mode,
4348 StoreFromKeyed store_mode) {
4349 Isolate* isolate = it->isolate();
4350
4351 if (it->IsFound()) {
4352 bool found = true;
4353 Maybe<bool> result =
4354 SetPropertyInternal(it, value, language_mode, store_mode, &found);
4355 if (found) return result;
4356 }
4357
4358 it->UpdateProtector();
4359
4360 // The property either doesn't exist on the holder or exists there as a data
4361 // property.
4362
4363 ShouldThrow should_throw =
4364 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
4365
4366 if (!it->GetReceiver()->IsJSReceiver()) {
4367 return WriteToReadOnlyProperty(it, value, should_throw);
4368 }
4369 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
4370
4371 LookupIterator::Configuration c = LookupIterator::OWN;
4372 LookupIterator own_lookup =
4373 it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c)
4374 : LookupIterator(receiver, it->name(), c);
4375
4376 for (; own_lookup.IsFound(); own_lookup.Next()) {
4377 switch (own_lookup.state()) {
4378 case LookupIterator::ACCESS_CHECK:
4379 if (!own_lookup.HasAccess()) {
4380 return JSObject::SetPropertyWithFailedAccessCheck(&own_lookup, value,
4381 should_throw);
4382 }
4383 break;
4384
4385 case LookupIterator::ACCESSOR:
4386 if (own_lookup.GetAccessors()->IsAccessorInfo()) {
4387 if (own_lookup.IsReadOnly()) {
4388 return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
4389 }
4390 return JSObject::SetPropertyWithAccessor(&own_lookup, value,
4391 should_throw);
4392 }
4393 // Fall through.
4394 case LookupIterator::INTEGER_INDEXED_EXOTIC:
4395 return RedefineIncompatibleProperty(isolate, it->GetName(), value,
4396 should_throw);
4397
4398 case LookupIterator::DATA: {
4399 if (own_lookup.IsReadOnly()) {
4400 return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
4401 }
4402 return SetDataProperty(&own_lookup, value);
4403 }
4404
4405 case LookupIterator::INTERCEPTOR:
4406 case LookupIterator::JSPROXY: {
4407 PropertyDescriptor desc;
4408 Maybe<bool> owned =
4409 JSReceiver::GetOwnPropertyDescriptor(&own_lookup, &desc);
4410 MAYBE_RETURN(owned, Nothing<bool>());
4411 if (!owned.FromJust()) {
4412 return JSReceiver::CreateDataProperty(&own_lookup, value,
4413 should_throw);
4414 }
4415 if (PropertyDescriptor::IsAccessorDescriptor(&desc) ||
4416 !desc.writable()) {
4417 return RedefineIncompatibleProperty(isolate, it->GetName(), value,
4418 should_throw);
4419 }
4420
4421 PropertyDescriptor value_desc;
4422 value_desc.set_value(value);
4423 return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
4424 &value_desc, should_throw);
4425 }
4426
4427 case LookupIterator::NOT_FOUND:
4428 case LookupIterator::TRANSITION:
4429 UNREACHABLE();
4430 }
4431 }
4432
4433 return AddDataProperty(&own_lookup, value, NONE, should_throw, store_mode);
4434 }
4435
CannotCreateProperty(Isolate * isolate,Handle<Object> receiver,Handle<Object> name,Handle<Object> value,ShouldThrow should_throw)4436 Maybe<bool> Object::CannotCreateProperty(Isolate* isolate,
4437 Handle<Object> receiver,
4438 Handle<Object> name,
4439 Handle<Object> value,
4440 ShouldThrow should_throw) {
4441 RETURN_FAILURE(
4442 isolate, should_throw,
4443 NewTypeError(MessageTemplate::kStrictCannotCreateProperty, name,
4444 Object::TypeOf(isolate, receiver), receiver));
4445 }
4446
4447
WriteToReadOnlyProperty(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)4448 Maybe<bool> Object::WriteToReadOnlyProperty(LookupIterator* it,
4449 Handle<Object> value,
4450 ShouldThrow should_throw) {
4451 return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(),
4452 it->GetName(), value, should_throw);
4453 }
4454
4455
WriteToReadOnlyProperty(Isolate * isolate,Handle<Object> receiver,Handle<Object> name,Handle<Object> value,ShouldThrow should_throw)4456 Maybe<bool> Object::WriteToReadOnlyProperty(Isolate* isolate,
4457 Handle<Object> receiver,
4458 Handle<Object> name,
4459 Handle<Object> value,
4460 ShouldThrow should_throw) {
4461 RETURN_FAILURE(isolate, should_throw,
4462 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, name,
4463 Object::TypeOf(isolate, receiver), receiver));
4464 }
4465
4466
RedefineIncompatibleProperty(Isolate * isolate,Handle<Object> name,Handle<Object> value,ShouldThrow should_throw)4467 Maybe<bool> Object::RedefineIncompatibleProperty(Isolate* isolate,
4468 Handle<Object> name,
4469 Handle<Object> value,
4470 ShouldThrow should_throw) {
4471 RETURN_FAILURE(isolate, should_throw,
4472 NewTypeError(MessageTemplate::kRedefineDisallowed, name));
4473 }
4474
4475
SetDataProperty(LookupIterator * it,Handle<Object> value)4476 Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) {
4477 // Proxies are handled elsewhere. Other non-JSObjects cannot have own
4478 // properties.
4479 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
4480
4481 // Store on the holder which may be hidden behind the receiver.
4482 DCHECK(it->HolderIsReceiverOrHiddenPrototype());
4483
4484 Handle<Object> to_assign = value;
4485 // Convert the incoming value to a number for storing into typed arrays.
4486 if (it->IsElement() && receiver->HasFixedTypedArrayElements()) {
4487 if (!value->IsNumber() && !value->IsUndefined(it->isolate())) {
4488 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4489 it->isolate(), to_assign, Object::ToNumber(value), Nothing<bool>());
4490 // We have to recheck the length. However, it can only change if the
4491 // underlying buffer was neutered, so just check that.
4492 if (Handle<JSArrayBufferView>::cast(receiver)->WasNeutered()) {
4493 return Just(true);
4494 // TODO(neis): According to the spec, this should throw a TypeError.
4495 }
4496 }
4497 }
4498
4499 // Possibly migrate to the most up-to-date map that will be able to store
4500 // |value| under it->name().
4501 it->PrepareForDataProperty(to_assign);
4502
4503 // Write the property value.
4504 it->WriteDataValue(to_assign, false);
4505
4506 #if VERIFY_HEAP
4507 if (FLAG_verify_heap) {
4508 receiver->JSObjectVerify();
4509 }
4510 #endif
4511 return Just(true);
4512 }
4513
4514
AddDataProperty(LookupIterator * it,Handle<Object> value,PropertyAttributes attributes,ShouldThrow should_throw,StoreFromKeyed store_mode)4515 Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value,
4516 PropertyAttributes attributes,
4517 ShouldThrow should_throw,
4518 StoreFromKeyed store_mode) {
4519 if (!it->GetReceiver()->IsJSObject()) {
4520 if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate()) {
4521 RETURN_FAILURE(it->isolate(), should_throw,
4522 NewTypeError(MessageTemplate::kProxyPrivate));
4523 }
4524 return CannotCreateProperty(it->isolate(), it->GetReceiver(), it->GetName(),
4525 value, should_throw);
4526 }
4527
4528 DCHECK_NE(LookupIterator::INTEGER_INDEXED_EXOTIC, it->state());
4529
4530 Handle<JSObject> receiver = it->GetStoreTarget();
4531
4532 // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject)
4533 // instead. If the prototype is Null, the proxy is detached.
4534 if (receiver->IsJSGlobalProxy()) return Just(true);
4535
4536 Isolate* isolate = it->isolate();
4537
4538 if (it->ExtendingNonExtensible(receiver)) {
4539 RETURN_FAILURE(
4540 isolate, should_throw,
4541 NewTypeError(MessageTemplate::kObjectNotExtensible, it->GetName()));
4542 }
4543
4544 if (it->IsElement()) {
4545 if (receiver->IsJSArray()) {
4546 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
4547 if (JSArray::WouldChangeReadOnlyLength(array, it->index())) {
4548 RETURN_FAILURE(array->GetIsolate(), should_throw,
4549 NewTypeError(MessageTemplate::kStrictReadOnlyProperty,
4550 isolate->factory()->length_string(),
4551 Object::TypeOf(isolate, array), array));
4552 }
4553
4554 if (FLAG_trace_external_array_abuse &&
4555 array->HasFixedTypedArrayElements()) {
4556 CheckArrayAbuse(array, "typed elements write", it->index(), true);
4557 }
4558
4559 if (FLAG_trace_js_array_abuse && !array->HasFixedTypedArrayElements()) {
4560 CheckArrayAbuse(array, "elements write", it->index(), false);
4561 }
4562 }
4563
4564 Maybe<bool> result = JSObject::AddDataElement(receiver, it->index(), value,
4565 attributes, should_throw);
4566 JSObject::ValidateElements(receiver);
4567 return result;
4568 } else {
4569 it->UpdateProtector();
4570 // Migrate to the most up-to-date map that will be able to store |value|
4571 // under it->name() with |attributes|.
4572 it->PrepareTransitionToDataProperty(receiver, value, attributes,
4573 store_mode);
4574 DCHECK_EQ(LookupIterator::TRANSITION, it->state());
4575 it->ApplyTransitionToDataProperty(receiver);
4576
4577 // Write the property value.
4578 it->WriteDataValue(value, true);
4579
4580 #if VERIFY_HEAP
4581 if (FLAG_verify_heap) {
4582 receiver->JSObjectVerify();
4583 }
4584 #endif
4585 }
4586
4587 return Just(true);
4588 }
4589
4590
EnsureDescriptorSlack(Handle<Map> map,int slack)4591 void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
4592 // Only supports adding slack to owned descriptors.
4593 DCHECK(map->owns_descriptors());
4594
4595 Handle<DescriptorArray> descriptors(map->instance_descriptors());
4596 int old_size = map->NumberOfOwnDescriptors();
4597 if (slack <= descriptors->NumberOfSlackDescriptors()) return;
4598
4599 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
4600 descriptors, old_size, slack);
4601
4602 DisallowHeapAllocation no_allocation;
4603 // The descriptors are still the same, so keep the layout descriptor.
4604 LayoutDescriptor* layout_descriptor = map->GetLayoutDescriptor();
4605
4606 if (old_size == 0) {
4607 map->UpdateDescriptors(*new_descriptors, layout_descriptor);
4608 return;
4609 }
4610
4611 // If the source descriptors had an enum cache we copy it. This ensures
4612 // that the maps to which we push the new descriptor array back can rely
4613 // on a cache always being available once it is set. If the map has more
4614 // enumerated descriptors than available in the original cache, the cache
4615 // will be lazily replaced by the extended cache when needed.
4616 if (descriptors->HasEnumCache()) {
4617 new_descriptors->CopyEnumCacheFrom(*descriptors);
4618 }
4619
4620 Isolate* isolate = map->GetIsolate();
4621 // Replace descriptors by new_descriptors in all maps that share it.
4622 isolate->heap()->incremental_marking()->IterateBlackObject(*descriptors);
4623
4624 Map* current = *map;
4625 while (current->instance_descriptors() == *descriptors) {
4626 Object* next = current->GetBackPointer();
4627 if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map.
4628 current->UpdateDescriptors(*new_descriptors, layout_descriptor);
4629 current = Map::cast(next);
4630 }
4631 map->UpdateDescriptors(*new_descriptors, layout_descriptor);
4632 }
4633
4634 // static
GetObjectCreateMap(Handle<HeapObject> prototype)4635 Handle<Map> Map::GetObjectCreateMap(Handle<HeapObject> prototype) {
4636 Isolate* isolate = prototype->GetIsolate();
4637 Handle<Map> map(isolate->native_context()->object_function()->initial_map(),
4638 isolate);
4639 if (map->prototype() == *prototype) return map;
4640 if (prototype->IsNull(isolate)) {
4641 return isolate->slow_object_with_null_prototype_map();
4642 }
4643 if (prototype->IsJSObject()) {
4644 Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype);
4645 if (!js_prototype->map()->is_prototype_map()) {
4646 JSObject::OptimizeAsPrototype(js_prototype, FAST_PROTOTYPE);
4647 }
4648 Handle<PrototypeInfo> info =
4649 Map::GetOrCreatePrototypeInfo(js_prototype, isolate);
4650 // TODO(verwaest): Use inobject slack tracking for this map.
4651 if (info->HasObjectCreateMap()) {
4652 map = handle(info->ObjectCreateMap(), isolate);
4653 } else {
4654 map = Map::CopyInitialMap(map);
4655 Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
4656 PrototypeInfo::SetObjectCreateMap(info, map);
4657 }
4658 return map;
4659 }
4660
4661 return Map::TransitionToPrototype(map, prototype, REGULAR_PROTOTYPE);
4662 }
4663
4664 template <class T>
AppendUniqueCallbacks(Handle<TemplateList> callbacks,Handle<typename T::Array> array,int valid_descriptors)4665 static int AppendUniqueCallbacks(Handle<TemplateList> callbacks,
4666 Handle<typename T::Array> array,
4667 int valid_descriptors) {
4668 int nof_callbacks = callbacks->length();
4669
4670 Isolate* isolate = array->GetIsolate();
4671 // Ensure the keys are unique names before writing them into the
4672 // instance descriptor. Since it may cause a GC, it has to be done before we
4673 // temporarily put the heap in an invalid state while appending descriptors.
4674 for (int i = 0; i < nof_callbacks; ++i) {
4675 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
4676 if (entry->name()->IsUniqueName()) continue;
4677 Handle<String> key =
4678 isolate->factory()->InternalizeString(
4679 Handle<String>(String::cast(entry->name())));
4680 entry->set_name(*key);
4681 }
4682
4683 // Fill in new callback descriptors. Process the callbacks from
4684 // back to front so that the last callback with a given name takes
4685 // precedence over previously added callbacks with that name.
4686 for (int i = nof_callbacks - 1; i >= 0; i--) {
4687 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
4688 Handle<Name> key(Name::cast(entry->name()));
4689 // Check if a descriptor with this name already exists before writing.
4690 if (!T::Contains(key, entry, valid_descriptors, array)) {
4691 T::Insert(key, entry, valid_descriptors, array);
4692 valid_descriptors++;
4693 }
4694 }
4695
4696 return valid_descriptors;
4697 }
4698
4699 struct DescriptorArrayAppender {
4700 typedef DescriptorArray Array;
Containsv8::internal::DescriptorArrayAppender4701 static bool Contains(Handle<Name> key,
4702 Handle<AccessorInfo> entry,
4703 int valid_descriptors,
4704 Handle<DescriptorArray> array) {
4705 DisallowHeapAllocation no_gc;
4706 return array->Search(*key, valid_descriptors) != DescriptorArray::kNotFound;
4707 }
Insertv8::internal::DescriptorArrayAppender4708 static void Insert(Handle<Name> key,
4709 Handle<AccessorInfo> entry,
4710 int valid_descriptors,
4711 Handle<DescriptorArray> array) {
4712 DisallowHeapAllocation no_gc;
4713 Descriptor d =
4714 Descriptor::AccessorConstant(key, entry, entry->property_attributes());
4715 array->Append(&d);
4716 }
4717 };
4718
4719
4720 struct FixedArrayAppender {
4721 typedef FixedArray Array;
Containsv8::internal::FixedArrayAppender4722 static bool Contains(Handle<Name> key,
4723 Handle<AccessorInfo> entry,
4724 int valid_descriptors,
4725 Handle<FixedArray> array) {
4726 for (int i = 0; i < valid_descriptors; i++) {
4727 if (*key == AccessorInfo::cast(array->get(i))->name()) return true;
4728 }
4729 return false;
4730 }
Insertv8::internal::FixedArrayAppender4731 static void Insert(Handle<Name> key,
4732 Handle<AccessorInfo> entry,
4733 int valid_descriptors,
4734 Handle<FixedArray> array) {
4735 DisallowHeapAllocation no_gc;
4736 array->set(valid_descriptors, *entry);
4737 }
4738 };
4739
4740
AppendCallbackDescriptors(Handle<Map> map,Handle<Object> descriptors)4741 void Map::AppendCallbackDescriptors(Handle<Map> map,
4742 Handle<Object> descriptors) {
4743 int nof = map->NumberOfOwnDescriptors();
4744 Handle<DescriptorArray> array(map->instance_descriptors());
4745 Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors);
4746 DCHECK_GE(array->NumberOfSlackDescriptors(), callbacks->length());
4747 nof = AppendUniqueCallbacks<DescriptorArrayAppender>(callbacks, array, nof);
4748 map->SetNumberOfOwnDescriptors(nof);
4749 }
4750
4751
AppendUnique(Handle<Object> descriptors,Handle<FixedArray> array,int valid_descriptors)4752 int AccessorInfo::AppendUnique(Handle<Object> descriptors,
4753 Handle<FixedArray> array,
4754 int valid_descriptors) {
4755 Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors);
4756 DCHECK_GE(array->length(), callbacks->length() + valid_descriptors);
4757 return AppendUniqueCallbacks<FixedArrayAppender>(callbacks, array,
4758 valid_descriptors);
4759 }
4760
4761
ContainsMap(MapHandleList * maps,Map * map)4762 static bool ContainsMap(MapHandleList* maps, Map* map) {
4763 DCHECK_NOT_NULL(map);
4764 for (int i = 0; i < maps->length(); ++i) {
4765 if (!maps->at(i).is_null() && *maps->at(i) == map) return true;
4766 }
4767 return false;
4768 }
4769
FindElementsKindTransitionedMap(MapHandleList * candidates)4770 Map* Map::FindElementsKindTransitionedMap(MapHandleList* candidates) {
4771 DisallowHeapAllocation no_allocation;
4772 DisallowDeoptimization no_deoptimization(GetIsolate());
4773
4774 ElementsKind kind = elements_kind();
4775 bool packed = IsFastPackedElementsKind(kind);
4776
4777 Map* transition = nullptr;
4778 if (IsTransitionableFastElementsKind(kind)) {
4779 // Check the state of the root map.
4780 Map* root_map = FindRootMap();
4781 if (!EquivalentToForTransition(root_map)) return nullptr;
4782 root_map = root_map->LookupElementsTransitionMap(kind);
4783 DCHECK_NOT_NULL(root_map);
4784 // Starting from the next existing elements kind transition try to
4785 // replay the property transitions that does not involve instance rewriting
4786 // (ElementsTransitionAndStoreStub does not support that).
4787 for (root_map = root_map->ElementsTransitionMap();
4788 root_map != nullptr && root_map->has_fast_elements();
4789 root_map = root_map->ElementsTransitionMap()) {
4790 Map* current = root_map->TryReplayPropertyTransitions(this);
4791 if (current == nullptr) continue;
4792 if (InstancesNeedRewriting(current)) continue;
4793
4794 if (ContainsMap(candidates, current) &&
4795 (packed || !IsFastPackedElementsKind(current->elements_kind()))) {
4796 transition = current;
4797 packed = packed && IsFastPackedElementsKind(current->elements_kind());
4798 }
4799 }
4800 }
4801 return transition;
4802 }
4803
4804
FindClosestElementsTransition(Map * map,ElementsKind to_kind)4805 static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
4806 // Ensure we are requested to search elements kind transition "near the root".
4807 DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(),
4808 map->NumberOfOwnDescriptors());
4809 Map* current_map = map;
4810
4811 ElementsKind kind = map->elements_kind();
4812 while (kind != to_kind) {
4813 Map* next_map = current_map->ElementsTransitionMap();
4814 if (next_map == nullptr) return current_map;
4815 kind = next_map->elements_kind();
4816 current_map = next_map;
4817 }
4818
4819 DCHECK_EQ(to_kind, current_map->elements_kind());
4820 return current_map;
4821 }
4822
4823
LookupElementsTransitionMap(ElementsKind to_kind)4824 Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) {
4825 Map* to_map = FindClosestElementsTransition(this, to_kind);
4826 if (to_map->elements_kind() == to_kind) return to_map;
4827 return nullptr;
4828 }
4829
4830
IsMapInArrayPrototypeChain()4831 bool Map::IsMapInArrayPrototypeChain() {
4832 Isolate* isolate = GetIsolate();
4833 if (isolate->initial_array_prototype()->map() == this) {
4834 return true;
4835 }
4836
4837 if (isolate->initial_object_prototype()->map() == this) {
4838 return true;
4839 }
4840
4841 return false;
4842 }
4843
4844
WeakCellForMap(Handle<Map> map)4845 Handle<WeakCell> Map::WeakCellForMap(Handle<Map> map) {
4846 Isolate* isolate = map->GetIsolate();
4847 if (map->weak_cell_cache()->IsWeakCell()) {
4848 return Handle<WeakCell>(WeakCell::cast(map->weak_cell_cache()));
4849 }
4850 Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(map);
4851 map->set_weak_cell_cache(*weak_cell);
4852 return weak_cell;
4853 }
4854
4855
AddMissingElementsTransitions(Handle<Map> map,ElementsKind to_kind)4856 static Handle<Map> AddMissingElementsTransitions(Handle<Map> map,
4857 ElementsKind to_kind) {
4858 DCHECK(IsTransitionElementsKind(map->elements_kind()));
4859
4860 Handle<Map> current_map = map;
4861
4862 ElementsKind kind = map->elements_kind();
4863 TransitionFlag flag;
4864 if (map->is_prototype_map()) {
4865 flag = OMIT_TRANSITION;
4866 } else {
4867 flag = INSERT_TRANSITION;
4868 if (IsFastElementsKind(kind)) {
4869 while (kind != to_kind && !IsTerminalElementsKind(kind)) {
4870 kind = GetNextTransitionElementsKind(kind);
4871 current_map = Map::CopyAsElementsKind(current_map, kind, flag);
4872 }
4873 }
4874 }
4875
4876 // In case we are exiting the fast elements kind system, just add the map in
4877 // the end.
4878 if (kind != to_kind) {
4879 current_map = Map::CopyAsElementsKind(current_map, to_kind, flag);
4880 }
4881
4882 DCHECK(current_map->elements_kind() == to_kind);
4883 return current_map;
4884 }
4885
4886
TransitionElementsTo(Handle<Map> map,ElementsKind to_kind)4887 Handle<Map> Map::TransitionElementsTo(Handle<Map> map,
4888 ElementsKind to_kind) {
4889 ElementsKind from_kind = map->elements_kind();
4890 if (from_kind == to_kind) return map;
4891
4892 Isolate* isolate = map->GetIsolate();
4893 Context* native_context = isolate->context()->native_context();
4894 if (from_kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
4895 if (*map == native_context->fast_aliased_arguments_map()) {
4896 DCHECK_EQ(SLOW_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
4897 return handle(native_context->slow_aliased_arguments_map());
4898 }
4899 } else if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
4900 if (*map == native_context->slow_aliased_arguments_map()) {
4901 DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
4902 return handle(native_context->fast_aliased_arguments_map());
4903 }
4904 } else if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) {
4905 // Reuse map transitions for JSArrays.
4906 DisallowHeapAllocation no_gc;
4907 if (native_context->get(Context::ArrayMapIndex(from_kind)) == *map) {
4908 Object* maybe_transitioned_map =
4909 native_context->get(Context::ArrayMapIndex(to_kind));
4910 if (maybe_transitioned_map->IsMap()) {
4911 return handle(Map::cast(maybe_transitioned_map), isolate);
4912 }
4913 }
4914 }
4915
4916 DCHECK(!map->IsUndefined(isolate));
4917 // Check if we can go back in the elements kind transition chain.
4918 if (IsHoleyElementsKind(from_kind) &&
4919 to_kind == GetPackedElementsKind(from_kind) &&
4920 map->GetBackPointer()->IsMap() &&
4921 Map::cast(map->GetBackPointer())->elements_kind() == to_kind) {
4922 return handle(Map::cast(map->GetBackPointer()));
4923 }
4924
4925 bool allow_store_transition = IsTransitionElementsKind(from_kind);
4926 // Only store fast element maps in ascending generality.
4927 if (IsFastElementsKind(to_kind)) {
4928 allow_store_transition =
4929 allow_store_transition && IsTransitionableFastElementsKind(from_kind) &&
4930 IsMoreGeneralElementsKindTransition(from_kind, to_kind);
4931 }
4932
4933 if (!allow_store_transition) {
4934 return Map::CopyAsElementsKind(map, to_kind, OMIT_TRANSITION);
4935 }
4936
4937 return Map::ReconfigureElementsKind(map, to_kind);
4938 }
4939
4940
4941 // static
AsElementsKind(Handle<Map> map,ElementsKind kind)4942 Handle<Map> Map::AsElementsKind(Handle<Map> map, ElementsKind kind) {
4943 Handle<Map> closest_map(FindClosestElementsTransition(*map, kind));
4944
4945 if (closest_map->elements_kind() == kind) {
4946 return closest_map;
4947 }
4948
4949 return AddMissingElementsTransitions(closest_map, kind);
4950 }
4951
4952
GetElementsTransitionMap(Handle<JSObject> object,ElementsKind to_kind)4953 Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
4954 ElementsKind to_kind) {
4955 Handle<Map> map(object->map());
4956 return Map::TransitionElementsTo(map, to_kind);
4957 }
4958
4959
Revoke(Handle<JSProxy> proxy)4960 void JSProxy::Revoke(Handle<JSProxy> proxy) {
4961 Isolate* isolate = proxy->GetIsolate();
4962 if (!proxy->IsRevoked()) proxy->set_handler(isolate->heap()->null_value());
4963 DCHECK(proxy->IsRevoked());
4964 }
4965
4966
HasProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Name> name)4967 Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy,
4968 Handle<Name> name) {
4969 DCHECK(!name->IsPrivate());
4970 STACK_CHECK(isolate, Nothing<bool>());
4971 // 1. (Assert)
4972 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
4973 Handle<Object> handler(proxy->handler(), isolate);
4974 // 3. If handler is null, throw a TypeError exception.
4975 // 4. Assert: Type(handler) is Object.
4976 if (proxy->IsRevoked()) {
4977 isolate->Throw(*isolate->factory()->NewTypeError(
4978 MessageTemplate::kProxyRevoked, isolate->factory()->has_string()));
4979 return Nothing<bool>();
4980 }
4981 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
4982 Handle<JSReceiver> target(proxy->target(), isolate);
4983 // 6. Let trap be ? GetMethod(handler, "has").
4984 Handle<Object> trap;
4985 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4986 isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
4987 isolate->factory()->has_string()),
4988 Nothing<bool>());
4989 // 7. If trap is undefined, then
4990 if (trap->IsUndefined(isolate)) {
4991 // 7a. Return target.[[HasProperty]](P).
4992 return JSReceiver::HasProperty(target, name);
4993 }
4994 // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, P»)).
4995 Handle<Object> trap_result_obj;
4996 Handle<Object> args[] = {target, name};
4997 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4998 isolate, trap_result_obj,
4999 Execution::Call(isolate, trap, handler, arraysize(args), args),
5000 Nothing<bool>());
5001 bool boolean_trap_result = trap_result_obj->BooleanValue();
5002 // 9. If booleanTrapResult is false, then:
5003 if (!boolean_trap_result) {
5004 // 9a. Let targetDesc be ? target.[[GetOwnProperty]](P).
5005 PropertyDescriptor target_desc;
5006 Maybe<bool> target_found = JSReceiver::GetOwnPropertyDescriptor(
5007 isolate, target, name, &target_desc);
5008 MAYBE_RETURN(target_found, Nothing<bool>());
5009 // 9b. If targetDesc is not undefined, then:
5010 if (target_found.FromJust()) {
5011 // 9b i. If targetDesc.[[Configurable]] is false, throw a TypeError
5012 // exception.
5013 if (!target_desc.configurable()) {
5014 isolate->Throw(*isolate->factory()->NewTypeError(
5015 MessageTemplate::kProxyHasNonConfigurable, name));
5016 return Nothing<bool>();
5017 }
5018 // 9b ii. Let extensibleTarget be ? IsExtensible(target).
5019 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
5020 MAYBE_RETURN(extensible_target, Nothing<bool>());
5021 // 9b iii. If extensibleTarget is false, throw a TypeError exception.
5022 if (!extensible_target.FromJust()) {
5023 isolate->Throw(*isolate->factory()->NewTypeError(
5024 MessageTemplate::kProxyHasNonExtensible, name));
5025 return Nothing<bool>();
5026 }
5027 }
5028 }
5029 // 10. Return booleanTrapResult.
5030 return Just(boolean_trap_result);
5031 }
5032
5033
SetProperty(Handle<JSProxy> proxy,Handle<Name> name,Handle<Object> value,Handle<Object> receiver,LanguageMode language_mode)5034 Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name,
5035 Handle<Object> value, Handle<Object> receiver,
5036 LanguageMode language_mode) {
5037 DCHECK(!name->IsPrivate());
5038 Isolate* isolate = proxy->GetIsolate();
5039 STACK_CHECK(isolate, Nothing<bool>());
5040 Factory* factory = isolate->factory();
5041 Handle<String> trap_name = factory->set_string();
5042 ShouldThrow should_throw =
5043 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
5044
5045 if (proxy->IsRevoked()) {
5046 isolate->Throw(
5047 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
5048 return Nothing<bool>();
5049 }
5050 Handle<JSReceiver> target(proxy->target(), isolate);
5051 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
5052
5053 Handle<Object> trap;
5054 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5055 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
5056 if (trap->IsUndefined(isolate)) {
5057 LookupIterator it =
5058 LookupIterator::PropertyOrElement(isolate, receiver, name, target);
5059 return Object::SetSuperProperty(&it, value, language_mode,
5060 Object::MAY_BE_STORE_FROM_KEYED);
5061 }
5062
5063 Handle<Object> trap_result;
5064 Handle<Object> args[] = {target, name, value, receiver};
5065 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5066 isolate, trap_result,
5067 Execution::Call(isolate, trap, handler, arraysize(args), args),
5068 Nothing<bool>());
5069 if (!trap_result->BooleanValue()) {
5070 RETURN_FAILURE(isolate, should_throw,
5071 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
5072 trap_name, name));
5073 }
5074
5075 // Enforce the invariant.
5076 PropertyDescriptor target_desc;
5077 Maybe<bool> owned =
5078 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
5079 MAYBE_RETURN(owned, Nothing<bool>());
5080 if (owned.FromJust()) {
5081 bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
5082 !target_desc.configurable() &&
5083 !target_desc.writable() &&
5084 !value->SameValue(*target_desc.value());
5085 if (inconsistent) {
5086 isolate->Throw(*isolate->factory()->NewTypeError(
5087 MessageTemplate::kProxySetFrozenData, name));
5088 return Nothing<bool>();
5089 }
5090 inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
5091 !target_desc.configurable() &&
5092 target_desc.set()->IsUndefined(isolate);
5093 if (inconsistent) {
5094 isolate->Throw(*isolate->factory()->NewTypeError(
5095 MessageTemplate::kProxySetFrozenAccessor, name));
5096 return Nothing<bool>();
5097 }
5098 }
5099 return Just(true);
5100 }
5101
5102
DeletePropertyOrElement(Handle<JSProxy> proxy,Handle<Name> name,LanguageMode language_mode)5103 Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy,
5104 Handle<Name> name,
5105 LanguageMode language_mode) {
5106 DCHECK(!name->IsPrivate());
5107 ShouldThrow should_throw =
5108 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
5109 Isolate* isolate = proxy->GetIsolate();
5110 STACK_CHECK(isolate, Nothing<bool>());
5111 Factory* factory = isolate->factory();
5112 Handle<String> trap_name = factory->deleteProperty_string();
5113
5114 if (proxy->IsRevoked()) {
5115 isolate->Throw(
5116 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
5117 return Nothing<bool>();
5118 }
5119 Handle<JSReceiver> target(proxy->target(), isolate);
5120 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
5121
5122 Handle<Object> trap;
5123 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5124 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
5125 if (trap->IsUndefined(isolate)) {
5126 return JSReceiver::DeletePropertyOrElement(target, name, language_mode);
5127 }
5128
5129 Handle<Object> trap_result;
5130 Handle<Object> args[] = {target, name};
5131 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5132 isolate, trap_result,
5133 Execution::Call(isolate, trap, handler, arraysize(args), args),
5134 Nothing<bool>());
5135 if (!trap_result->BooleanValue()) {
5136 RETURN_FAILURE(isolate, should_throw,
5137 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
5138 trap_name, name));
5139 }
5140
5141 // Enforce the invariant.
5142 PropertyDescriptor target_desc;
5143 Maybe<bool> owned =
5144 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
5145 MAYBE_RETURN(owned, Nothing<bool>());
5146 if (owned.FromJust() && !target_desc.configurable()) {
5147 isolate->Throw(*factory->NewTypeError(
5148 MessageTemplate::kProxyDeletePropertyNonConfigurable, name));
5149 return Nothing<bool>();
5150 }
5151 return Just(true);
5152 }
5153
5154
5155 // static
New(Isolate * isolate,Handle<Object> target,Handle<Object> handler)5156 MaybeHandle<JSProxy> JSProxy::New(Isolate* isolate, Handle<Object> target,
5157 Handle<Object> handler) {
5158 if (!target->IsJSReceiver()) {
5159 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5160 JSProxy);
5161 }
5162 if (target->IsJSProxy() && JSProxy::cast(*target)->IsRevoked()) {
5163 THROW_NEW_ERROR(isolate,
5164 NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5165 JSProxy);
5166 }
5167 if (!handler->IsJSReceiver()) {
5168 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
5169 JSProxy);
5170 }
5171 if (handler->IsJSProxy() && JSProxy::cast(*handler)->IsRevoked()) {
5172 THROW_NEW_ERROR(isolate,
5173 NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
5174 JSProxy);
5175 }
5176 return isolate->factory()->NewJSProxy(Handle<JSReceiver>::cast(target),
5177 Handle<JSReceiver>::cast(handler));
5178 }
5179
5180
5181 // static
GetFunctionRealm(Handle<JSProxy> proxy)5182 MaybeHandle<Context> JSProxy::GetFunctionRealm(Handle<JSProxy> proxy) {
5183 DCHECK(proxy->map()->is_constructor());
5184 if (proxy->IsRevoked()) {
5185 THROW_NEW_ERROR(proxy->GetIsolate(),
5186 NewTypeError(MessageTemplate::kProxyRevoked), Context);
5187 }
5188 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()));
5189 return JSReceiver::GetFunctionRealm(target);
5190 }
5191
5192
5193 // static
GetFunctionRealm(Handle<JSBoundFunction> function)5194 MaybeHandle<Context> JSBoundFunction::GetFunctionRealm(
5195 Handle<JSBoundFunction> function) {
5196 DCHECK(function->map()->is_constructor());
5197 return JSReceiver::GetFunctionRealm(
5198 handle(function->bound_target_function()));
5199 }
5200
5201 // static
GetName(Isolate * isolate,Handle<JSBoundFunction> function)5202 MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate,
5203 Handle<JSBoundFunction> function) {
5204 Handle<String> prefix = isolate->factory()->bound__string();
5205 if (!function->bound_target_function()->IsJSFunction()) return prefix;
5206 Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()),
5207 isolate);
5208 Handle<Object> target_name = JSFunction::GetName(isolate, target);
5209 if (!target_name->IsString()) return prefix;
5210 Factory* factory = isolate->factory();
5211 return factory->NewConsString(prefix, Handle<String>::cast(target_name));
5212 }
5213
5214 // static
GetName(Isolate * isolate,Handle<JSFunction> function)5215 Handle<Object> JSFunction::GetName(Isolate* isolate,
5216 Handle<JSFunction> function) {
5217 if (function->shared()->name_should_print_as_anonymous()) {
5218 return isolate->factory()->anonymous_string();
5219 }
5220 return handle(function->shared()->name(), isolate);
5221 }
5222
5223 // static
GetLength(Isolate * isolate,Handle<JSFunction> function)5224 MaybeHandle<Smi> JSFunction::GetLength(Isolate* isolate,
5225 Handle<JSFunction> function) {
5226 int length = 0;
5227 if (function->shared()->is_compiled()) {
5228 length = function->shared()->length();
5229 } else {
5230 // If the function isn't compiled yet, the length is not computed
5231 // correctly yet. Compile it now and return the right length.
5232 if (Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) {
5233 length = function->shared()->length();
5234 }
5235 if (isolate->has_pending_exception()) return MaybeHandle<Smi>();
5236 }
5237 return handle(Smi::FromInt(length), isolate);
5238 }
5239
5240 // static
GetFunctionRealm(Handle<JSFunction> function)5241 Handle<Context> JSFunction::GetFunctionRealm(Handle<JSFunction> function) {
5242 DCHECK(function->map()->is_constructor());
5243 return handle(function->context()->native_context());
5244 }
5245
5246
5247 // static
GetFunctionRealm(Handle<JSObject> object)5248 MaybeHandle<Context> JSObject::GetFunctionRealm(Handle<JSObject> object) {
5249 DCHECK(object->map()->is_constructor());
5250 DCHECK(!object->IsJSFunction());
5251 return object->GetCreationContext();
5252 }
5253
5254
5255 // static
GetFunctionRealm(Handle<JSReceiver> receiver)5256 MaybeHandle<Context> JSReceiver::GetFunctionRealm(Handle<JSReceiver> receiver) {
5257 if (receiver->IsJSProxy()) {
5258 return JSProxy::GetFunctionRealm(Handle<JSProxy>::cast(receiver));
5259 }
5260
5261 if (receiver->IsJSFunction()) {
5262 return JSFunction::GetFunctionRealm(Handle<JSFunction>::cast(receiver));
5263 }
5264
5265 if (receiver->IsJSBoundFunction()) {
5266 return JSBoundFunction::GetFunctionRealm(
5267 Handle<JSBoundFunction>::cast(receiver));
5268 }
5269
5270 return JSObject::GetFunctionRealm(Handle<JSObject>::cast(receiver));
5271 }
5272
5273
GetPropertyAttributes(LookupIterator * it)5274 Maybe<PropertyAttributes> JSProxy::GetPropertyAttributes(LookupIterator* it) {
5275 PropertyDescriptor desc;
5276 Maybe<bool> found = JSProxy::GetOwnPropertyDescriptor(
5277 it->isolate(), it->GetHolder<JSProxy>(), it->GetName(), &desc);
5278 MAYBE_RETURN(found, Nothing<PropertyAttributes>());
5279 if (!found.FromJust()) return Just(ABSENT);
5280 return Just(desc.ToAttributes());
5281 }
5282
5283
AllocateStorageForMap(Handle<JSObject> object,Handle<Map> map)5284 void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
5285 DCHECK(object->map()->GetInObjectProperties() ==
5286 map->GetInObjectProperties());
5287 ElementsKind obj_kind = object->map()->elements_kind();
5288 ElementsKind map_kind = map->elements_kind();
5289 if (map_kind != obj_kind) {
5290 ElementsKind to_kind = GetMoreGeneralElementsKind(map_kind, obj_kind);
5291 if (IsDictionaryElementsKind(obj_kind)) {
5292 to_kind = obj_kind;
5293 }
5294 if (IsDictionaryElementsKind(to_kind)) {
5295 NormalizeElements(object);
5296 } else {
5297 TransitionElementsKind(object, to_kind);
5298 }
5299 map = Map::ReconfigureElementsKind(map, to_kind);
5300 }
5301 JSObject::MigrateToMap(object, map);
5302 }
5303
5304
MigrateInstance(Handle<JSObject> object)5305 void JSObject::MigrateInstance(Handle<JSObject> object) {
5306 Handle<Map> original_map(object->map());
5307 Handle<Map> map = Map::Update(original_map);
5308 map->set_migration_target(true);
5309 MigrateToMap(object, map);
5310 if (FLAG_trace_migration) {
5311 object->PrintInstanceMigration(stdout, *original_map, *map);
5312 }
5313 #if VERIFY_HEAP
5314 if (FLAG_verify_heap) {
5315 object->JSObjectVerify();
5316 }
5317 #endif
5318 }
5319
5320
5321 // static
TryMigrateInstance(Handle<JSObject> object)5322 bool JSObject::TryMigrateInstance(Handle<JSObject> object) {
5323 Isolate* isolate = object->GetIsolate();
5324 DisallowDeoptimization no_deoptimization(isolate);
5325 Handle<Map> original_map(object->map(), isolate);
5326 Handle<Map> new_map;
5327 if (!Map::TryUpdate(original_map).ToHandle(&new_map)) {
5328 return false;
5329 }
5330 JSObject::MigrateToMap(object, new_map);
5331 if (FLAG_trace_migration) {
5332 object->PrintInstanceMigration(stdout, *original_map, object->map());
5333 }
5334 #if VERIFY_HEAP
5335 if (FLAG_verify_heap) {
5336 object->JSObjectVerify();
5337 }
5338 #endif
5339 return true;
5340 }
5341
5342
AddProperty(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)5343 void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name,
5344 Handle<Object> value,
5345 PropertyAttributes attributes) {
5346 LookupIterator it(object, name, object, LookupIterator::OWN_SKIP_INTERCEPTOR);
5347 CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
5348 #ifdef DEBUG
5349 uint32_t index;
5350 DCHECK(!object->IsJSProxy());
5351 DCHECK(!name->AsArrayIndex(&index));
5352 Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
5353 DCHECK(maybe.IsJust());
5354 DCHECK(!it.IsFound());
5355 DCHECK(object->map()->is_extensible() || name->IsPrivate());
5356 #endif
5357 CHECK(AddDataProperty(&it, value, attributes, THROW_ON_ERROR,
5358 CERTAINLY_NOT_STORE_FROM_KEYED)
5359 .IsJust());
5360 }
5361
5362
5363 // Reconfigures a property to a data property with attributes, even if it is not
5364 // reconfigurable.
5365 // Requires a LookupIterator that does not look at the prototype chain beyond
5366 // hidden prototypes.
DefineOwnPropertyIgnoreAttributes(LookupIterator * it,Handle<Object> value,PropertyAttributes attributes,AccessorInfoHandling handling)5367 MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes(
5368 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
5369 AccessorInfoHandling handling) {
5370 MAYBE_RETURN_NULL(DefineOwnPropertyIgnoreAttributes(
5371 it, value, attributes, THROW_ON_ERROR, handling));
5372 return value;
5373 }
5374
5375
DefineOwnPropertyIgnoreAttributes(LookupIterator * it,Handle<Object> value,PropertyAttributes attributes,ShouldThrow should_throw,AccessorInfoHandling handling)5376 Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
5377 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
5378 ShouldThrow should_throw, AccessorInfoHandling handling) {
5379 it->UpdateProtector();
5380 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
5381
5382 for (; it->IsFound(); it->Next()) {
5383 switch (it->state()) {
5384 case LookupIterator::JSPROXY:
5385 case LookupIterator::NOT_FOUND:
5386 case LookupIterator::TRANSITION:
5387 UNREACHABLE();
5388
5389 case LookupIterator::ACCESS_CHECK:
5390 if (!it->HasAccess()) {
5391 it->isolate()->ReportFailedAccessCheck(it->GetHolder<JSObject>());
5392 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
5393 return Just(true);
5394 }
5395 break;
5396
5397 // If there's an interceptor, try to store the property with the
5398 // interceptor.
5399 // In case of success, the attributes will have been reset to the default
5400 // attributes of the interceptor, rather than the incoming attributes.
5401 //
5402 // TODO(verwaest): JSProxy afterwards verify the attributes that the
5403 // JSProxy claims it has, and verifies that they are compatible. If not,
5404 // they throw. Here we should do the same.
5405 case LookupIterator::INTERCEPTOR:
5406 if (handling == DONT_FORCE_FIELD) {
5407 Maybe<bool> result =
5408 JSObject::SetPropertyWithInterceptor(it, should_throw, value);
5409 if (result.IsNothing() || result.FromJust()) return result;
5410 }
5411 break;
5412
5413 case LookupIterator::ACCESSOR: {
5414 Handle<Object> accessors = it->GetAccessors();
5415
5416 // Special handling for AccessorInfo, which behaves like a data
5417 // property.
5418 if (accessors->IsAccessorInfo() && handling == DONT_FORCE_FIELD) {
5419 PropertyAttributes current_attributes = it->property_attributes();
5420 // Ensure the context isn't changed after calling into accessors.
5421 AssertNoContextChange ncc(it->isolate());
5422
5423 // Update the attributes before calling the setter. The setter may
5424 // later change the shape of the property.
5425 if (current_attributes != attributes) {
5426 it->TransitionToAccessorPair(accessors, attributes);
5427 }
5428
5429 return JSObject::SetPropertyWithAccessor(it, value, should_throw);
5430 }
5431
5432 it->ReconfigureDataProperty(value, attributes);
5433 return Just(true);
5434 }
5435 case LookupIterator::INTEGER_INDEXED_EXOTIC:
5436 return RedefineIncompatibleProperty(it->isolate(), it->GetName(), value,
5437 should_throw);
5438
5439 case LookupIterator::DATA: {
5440 // Regular property update if the attributes match.
5441 if (it->property_attributes() == attributes) {
5442 return SetDataProperty(it, value);
5443 }
5444
5445 // Special case: properties of typed arrays cannot be reconfigured to
5446 // non-writable nor to non-enumerable.
5447 if (it->IsElement() && object->HasFixedTypedArrayElements()) {
5448 return RedefineIncompatibleProperty(it->isolate(), it->GetName(),
5449 value, should_throw);
5450 }
5451
5452 // Reconfigure the data property if the attributes mismatch.
5453 it->ReconfigureDataProperty(value, attributes);
5454
5455 return Just(true);
5456 }
5457 }
5458 }
5459
5460 return AddDataProperty(it, value, attributes, should_throw,
5461 CERTAINLY_NOT_STORE_FROM_KEYED);
5462 }
5463
SetOwnPropertyIgnoreAttributes(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)5464 MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
5465 Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
5466 PropertyAttributes attributes) {
5467 DCHECK(!value->IsTheHole(object->GetIsolate()));
5468 LookupIterator it(object, name, object, LookupIterator::OWN);
5469 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
5470 }
5471
SetOwnElementIgnoreAttributes(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes)5472 MaybeHandle<Object> JSObject::SetOwnElementIgnoreAttributes(
5473 Handle<JSObject> object, uint32_t index, Handle<Object> value,
5474 PropertyAttributes attributes) {
5475 Isolate* isolate = object->GetIsolate();
5476 LookupIterator it(isolate, object, index, object, LookupIterator::OWN);
5477 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
5478 }
5479
DefinePropertyOrElementIgnoreAttributes(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)5480 MaybeHandle<Object> JSObject::DefinePropertyOrElementIgnoreAttributes(
5481 Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
5482 PropertyAttributes attributes) {
5483 Isolate* isolate = object->GetIsolate();
5484 LookupIterator it = LookupIterator::PropertyOrElement(
5485 isolate, object, name, object, LookupIterator::OWN);
5486 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
5487 }
5488
GetPropertyAttributesWithInterceptor(LookupIterator * it)5489 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
5490 LookupIterator* it) {
5491 return GetPropertyAttributesWithInterceptorInternal(it, it->GetInterceptor());
5492 }
5493
GetPropertyAttributes(LookupIterator * it)5494 Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
5495 LookupIterator* it) {
5496 for (; it->IsFound(); it->Next()) {
5497 switch (it->state()) {
5498 case LookupIterator::NOT_FOUND:
5499 case LookupIterator::TRANSITION:
5500 UNREACHABLE();
5501 case LookupIterator::JSPROXY:
5502 return JSProxy::GetPropertyAttributes(it);
5503 case LookupIterator::INTERCEPTOR: {
5504 Maybe<PropertyAttributes> result =
5505 JSObject::GetPropertyAttributesWithInterceptor(it);
5506 if (!result.IsJust()) return result;
5507 if (result.FromJust() != ABSENT) return result;
5508 break;
5509 }
5510 case LookupIterator::ACCESS_CHECK:
5511 if (it->HasAccess()) break;
5512 return JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
5513 case LookupIterator::INTEGER_INDEXED_EXOTIC:
5514 return Just(ABSENT);
5515 case LookupIterator::ACCESSOR:
5516 case LookupIterator::DATA:
5517 return Just(it->property_attributes());
5518 }
5519 }
5520 return Just(ABSENT);
5521 }
5522
5523
New(Isolate * isolate)5524 Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) {
5525 Handle<FixedArray> array(
5526 isolate->factory()->NewFixedArray(kEntries, TENURED));
5527 return Handle<NormalizedMapCache>::cast(array);
5528 }
5529
5530
Get(Handle<Map> fast_map,PropertyNormalizationMode mode)5531 MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map,
5532 PropertyNormalizationMode mode) {
5533 DisallowHeapAllocation no_gc;
5534 Object* value = FixedArray::get(GetIndex(fast_map));
5535 if (!value->IsMap() ||
5536 !Map::cast(value)->EquivalentToForNormalization(*fast_map, mode)) {
5537 return MaybeHandle<Map>();
5538 }
5539 return handle(Map::cast(value));
5540 }
5541
5542
Set(Handle<Map> fast_map,Handle<Map> normalized_map)5543 void NormalizedMapCache::Set(Handle<Map> fast_map,
5544 Handle<Map> normalized_map) {
5545 DisallowHeapAllocation no_gc;
5546 DCHECK(normalized_map->is_dictionary_map());
5547 FixedArray::set(GetIndex(fast_map), *normalized_map);
5548 }
5549
5550
Clear()5551 void NormalizedMapCache::Clear() {
5552 int entries = length();
5553 for (int i = 0; i != entries; i++) {
5554 set_undefined(i);
5555 }
5556 }
5557
5558
UpdateMapCodeCache(Handle<HeapObject> object,Handle<Name> name,Handle<Code> code)5559 void HeapObject::UpdateMapCodeCache(Handle<HeapObject> object,
5560 Handle<Name> name,
5561 Handle<Code> code) {
5562 Handle<Map> map(object->map());
5563 Map::UpdateCodeCache(map, name, code);
5564 }
5565
5566
NormalizeProperties(Handle<JSObject> object,PropertyNormalizationMode mode,int expected_additional_properties,const char * reason)5567 void JSObject::NormalizeProperties(Handle<JSObject> object,
5568 PropertyNormalizationMode mode,
5569 int expected_additional_properties,
5570 const char* reason) {
5571 if (!object->HasFastProperties()) return;
5572
5573 Handle<Map> map(object->map());
5574 Handle<Map> new_map = Map::Normalize(map, mode, reason);
5575
5576 MigrateToMap(object, new_map, expected_additional_properties);
5577 }
5578
5579
MigrateSlowToFast(Handle<JSObject> object,int unused_property_fields,const char * reason)5580 void JSObject::MigrateSlowToFast(Handle<JSObject> object,
5581 int unused_property_fields,
5582 const char* reason) {
5583 if (object->HasFastProperties()) return;
5584 DCHECK(!object->IsJSGlobalObject());
5585 Isolate* isolate = object->GetIsolate();
5586 Factory* factory = isolate->factory();
5587 Handle<NameDictionary> dictionary(object->property_dictionary());
5588
5589 // Make sure we preserve dictionary representation if there are too many
5590 // descriptors.
5591 int number_of_elements = dictionary->NumberOfElements();
5592 if (number_of_elements > kMaxNumberOfDescriptors) return;
5593
5594 Handle<FixedArray> iteration_order;
5595 if (number_of_elements != dictionary->NextEnumerationIndex()) {
5596 iteration_order =
5597 NameDictionary::DoGenerateNewEnumerationIndices(dictionary);
5598 } else {
5599 iteration_order = NameDictionary::IterationIndices(dictionary);
5600 }
5601
5602 int instance_descriptor_length = iteration_order->length();
5603 int number_of_fields = 0;
5604
5605 // Compute the length of the instance descriptor.
5606 for (int i = 0; i < instance_descriptor_length; i++) {
5607 int index = Smi::cast(iteration_order->get(i))->value();
5608 DCHECK(dictionary->IsKey(isolate, dictionary->KeyAt(index)));
5609
5610 PropertyKind kind = dictionary->DetailsAt(index).kind();
5611 if (kind == kData) {
5612 if (FLAG_track_constant_fields) {
5613 number_of_fields += 1;
5614 } else {
5615 Object* value = dictionary->ValueAt(index);
5616 if (!value->IsJSFunction()) {
5617 number_of_fields += 1;
5618 }
5619 }
5620 }
5621 }
5622
5623 Handle<Map> old_map(object->map(), isolate);
5624
5625 int inobject_props = old_map->GetInObjectProperties();
5626
5627 // Allocate new map.
5628 Handle<Map> new_map = Map::CopyDropDescriptors(old_map);
5629 new_map->set_dictionary_map(false);
5630
5631 NotifyMapChange(old_map, new_map, isolate);
5632
5633 #if TRACE_MAPS
5634 if (FLAG_trace_maps) {
5635 PrintF("[TraceMaps: SlowToFast from= %p to= %p reason= %s ]\n",
5636 reinterpret_cast<void*>(*old_map), reinterpret_cast<void*>(*new_map),
5637 reason);
5638 }
5639 #endif
5640
5641 if (instance_descriptor_length == 0) {
5642 DisallowHeapAllocation no_gc;
5643 DCHECK_LE(unused_property_fields, inobject_props);
5644 // Transform the object.
5645 new_map->set_unused_property_fields(inobject_props);
5646 object->synchronized_set_map(*new_map);
5647 object->set_properties(isolate->heap()->empty_fixed_array());
5648 // Check that it really works.
5649 DCHECK(object->HasFastProperties());
5650 return;
5651 }
5652
5653 // Allocate the instance descriptor.
5654 Handle<DescriptorArray> descriptors = DescriptorArray::Allocate(
5655 isolate, instance_descriptor_length, 0, TENURED);
5656
5657 int number_of_allocated_fields =
5658 number_of_fields + unused_property_fields - inobject_props;
5659 if (number_of_allocated_fields < 0) {
5660 // There is enough inobject space for all fields (including unused).
5661 number_of_allocated_fields = 0;
5662 unused_property_fields = inobject_props - number_of_fields;
5663 }
5664
5665 // Allocate the fixed array for the fields.
5666 Handle<FixedArray> fields = factory->NewFixedArray(
5667 number_of_allocated_fields);
5668
5669 // Fill in the instance descriptor and the fields.
5670 int current_offset = 0;
5671 for (int i = 0; i < instance_descriptor_length; i++) {
5672 int index = Smi::cast(iteration_order->get(i))->value();
5673 Object* k = dictionary->KeyAt(index);
5674 DCHECK(dictionary->IsKey(k));
5675 // Dictionary keys are internalized upon insertion.
5676 // TODO(jkummerow): Turn this into a DCHECK if it's not hit in the wild.
5677 CHECK(k->IsUniqueName());
5678 Handle<Name> key(Name::cast(k), isolate);
5679
5680 Object* value = dictionary->ValueAt(index);
5681
5682 PropertyDetails details = dictionary->DetailsAt(index);
5683 DCHECK_EQ(kField, details.location());
5684 DCHECK_EQ(kMutable, details.constness());
5685 int enumeration_index = details.dictionary_index();
5686
5687 Descriptor d;
5688 if (details.kind() == kData) {
5689 if (!FLAG_track_constant_fields && value->IsJSFunction()) {
5690 d = Descriptor::DataConstant(key, handle(value, isolate),
5691 details.attributes());
5692 } else {
5693 d = Descriptor::DataField(
5694 key, current_offset, details.attributes(), kDefaultFieldConstness,
5695 // TODO(verwaest): value->OptimalRepresentation();
5696 Representation::Tagged(), FieldType::Any(isolate));
5697 }
5698 } else {
5699 DCHECK_EQ(kAccessor, details.kind());
5700 d = Descriptor::AccessorConstant(key, handle(value, isolate),
5701 details.attributes());
5702 }
5703 details = d.GetDetails();
5704 if (details.location() == kField) {
5705 if (current_offset < inobject_props) {
5706 object->InObjectPropertyAtPut(current_offset, value,
5707 UPDATE_WRITE_BARRIER);
5708 } else {
5709 int offset = current_offset - inobject_props;
5710 fields->set(offset, value);
5711 }
5712 current_offset += details.field_width_in_words();
5713 }
5714 descriptors->Set(enumeration_index - 1, &d);
5715 }
5716 DCHECK(current_offset == number_of_fields);
5717
5718 descriptors->Sort();
5719
5720 Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
5721 new_map, descriptors, descriptors->number_of_descriptors());
5722
5723 DisallowHeapAllocation no_gc;
5724 new_map->InitializeDescriptors(*descriptors, *layout_descriptor);
5725 new_map->set_unused_property_fields(unused_property_fields);
5726
5727 // Transform the object.
5728 object->synchronized_set_map(*new_map);
5729
5730 object->set_properties(*fields);
5731 DCHECK(object->IsJSObject());
5732
5733 // Check that it really works.
5734 DCHECK(object->HasFastProperties());
5735 }
5736
5737
ResetElements(Handle<JSObject> object)5738 void JSObject::ResetElements(Handle<JSObject> object) {
5739 Isolate* isolate = object->GetIsolate();
5740 CHECK(object->map() != isolate->heap()->sloppy_arguments_elements_map());
5741 if (object->map()->has_dictionary_elements()) {
5742 Handle<SeededNumberDictionary> new_elements =
5743 SeededNumberDictionary::New(isolate, 0);
5744 object->set_elements(*new_elements);
5745 } else {
5746 object->set_elements(object->map()->GetInitialElements());
5747 }
5748 }
5749
5750
RequireSlowElements(SeededNumberDictionary * dictionary)5751 void JSObject::RequireSlowElements(SeededNumberDictionary* dictionary) {
5752 if (dictionary->requires_slow_elements()) return;
5753 dictionary->set_requires_slow_elements();
5754 if (map()->is_prototype_map()) {
5755 // If this object is a prototype (the callee will check), invalidate any
5756 // prototype chains involving it.
5757 InvalidatePrototypeChains(map());
5758 }
5759 }
5760
5761
NormalizeElements(Handle<JSObject> object)5762 Handle<SeededNumberDictionary> JSObject::NormalizeElements(
5763 Handle<JSObject> object) {
5764 DCHECK(!object->HasFixedTypedArrayElements());
5765 Isolate* isolate = object->GetIsolate();
5766 bool is_arguments = object->HasSloppyArgumentsElements();
5767 {
5768 DisallowHeapAllocation no_gc;
5769 FixedArrayBase* elements = object->elements();
5770
5771 if (is_arguments) {
5772 FixedArray* parameter_map = FixedArray::cast(elements);
5773 elements = FixedArrayBase::cast(parameter_map->get(1));
5774 }
5775
5776 if (elements->IsDictionary()) {
5777 return handle(SeededNumberDictionary::cast(elements), isolate);
5778 }
5779 }
5780
5781 DCHECK(object->HasFastSmiOrObjectElements() ||
5782 object->HasFastDoubleElements() ||
5783 object->HasFastArgumentsElements() ||
5784 object->HasFastStringWrapperElements());
5785
5786 Handle<SeededNumberDictionary> dictionary =
5787 object->GetElementsAccessor()->Normalize(object);
5788
5789 // Switch to using the dictionary as the backing storage for elements.
5790 ElementsKind target_kind = is_arguments
5791 ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS
5792 : object->HasFastStringWrapperElements()
5793 ? SLOW_STRING_WRAPPER_ELEMENTS
5794 : DICTIONARY_ELEMENTS;
5795 Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind);
5796 // Set the new map first to satify the elements type assert in set_elements().
5797 JSObject::MigrateToMap(object, new_map);
5798
5799 if (is_arguments) {
5800 FixedArray::cast(object->elements())->set(1, *dictionary);
5801 } else {
5802 object->set_elements(*dictionary);
5803 }
5804
5805 isolate->counters()->elements_to_dictionary()->Increment();
5806
5807 #ifdef DEBUG
5808 if (FLAG_trace_normalization) {
5809 OFStream os(stdout);
5810 os << "Object elements have been normalized:\n";
5811 object->Print(os);
5812 }
5813 #endif
5814
5815 DCHECK(object->HasDictionaryElements() ||
5816 object->HasSlowArgumentsElements() ||
5817 object->HasSlowStringWrapperElements());
5818 return dictionary;
5819 }
5820
5821
5822 template <typename ProxyType>
GetOrCreateIdentityHashHelper(Isolate * isolate,Handle<ProxyType> proxy)5823 static Smi* GetOrCreateIdentityHashHelper(Isolate* isolate,
5824 Handle<ProxyType> proxy) {
5825 Object* maybe_hash = proxy->hash();
5826 if (maybe_hash->IsSmi()) return Smi::cast(maybe_hash);
5827
5828 Smi* hash = Smi::FromInt(isolate->GenerateIdentityHash(Smi::kMaxValue));
5829 proxy->set_hash(hash);
5830 return hash;
5831 }
5832
5833 // static
GetIdentityHash(Isolate * isolate,Handle<JSObject> object)5834 Object* JSObject::GetIdentityHash(Isolate* isolate, Handle<JSObject> object) {
5835 if (object->IsJSGlobalProxy()) {
5836 return JSGlobalProxy::cast(*object)->hash();
5837 }
5838 Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol();
5839 return *JSReceiver::GetDataProperty(object, hash_code_symbol);
5840 }
5841
5842 // static
GetOrCreateIdentityHash(Isolate * isolate,Handle<JSObject> object)5843 Smi* JSObject::GetOrCreateIdentityHash(Isolate* isolate,
5844 Handle<JSObject> object) {
5845 if (object->IsJSGlobalProxy()) {
5846 return GetOrCreateIdentityHashHelper(isolate,
5847 Handle<JSGlobalProxy>::cast(object));
5848 }
5849
5850 Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol();
5851 LookupIterator it(object, hash_code_symbol, object, LookupIterator::OWN);
5852 if (it.IsFound()) {
5853 DCHECK_EQ(LookupIterator::DATA, it.state());
5854 Object* maybe_hash = *it.GetDataValue();
5855 if (maybe_hash->IsSmi()) return Smi::cast(maybe_hash);
5856 }
5857
5858 Smi* hash = Smi::FromInt(isolate->GenerateIdentityHash(Smi::kMaxValue));
5859 CHECK(AddDataProperty(&it, handle(hash, isolate), NONE, THROW_ON_ERROR,
5860 CERTAINLY_NOT_STORE_FROM_KEYED)
5861 .IsJust());
5862 return hash;
5863 }
5864
5865 // static
GetIdentityHash(Handle<JSProxy> proxy)5866 Object* JSProxy::GetIdentityHash(Handle<JSProxy> proxy) {
5867 return proxy->hash();
5868 }
5869
GetOrCreateIdentityHash(Isolate * isolate,Handle<JSProxy> proxy)5870 Smi* JSProxy::GetOrCreateIdentityHash(Isolate* isolate, Handle<JSProxy> proxy) {
5871 return GetOrCreateIdentityHashHelper(isolate, proxy);
5872 }
5873
5874
DeletePropertyWithInterceptor(LookupIterator * it,ShouldThrow should_throw)5875 Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it,
5876 ShouldThrow should_throw) {
5877 Isolate* isolate = it->isolate();
5878 // Make sure that the top context does not change when doing callbacks or
5879 // interceptor calls.
5880 AssertNoContextChange ncc(isolate);
5881
5882 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
5883 Handle<InterceptorInfo> interceptor(it->GetInterceptor());
5884 if (interceptor->deleter()->IsUndefined(isolate)) return Nothing<bool>();
5885
5886 Handle<JSObject> holder = it->GetHolder<JSObject>();
5887 Handle<Object> receiver = it->GetReceiver();
5888 if (!receiver->IsJSReceiver()) {
5889 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
5890 Object::ConvertReceiver(isolate, receiver),
5891 Nothing<bool>());
5892 }
5893
5894 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
5895 *holder, should_throw);
5896 Handle<Object> result;
5897 if (it->IsElement()) {
5898 uint32_t index = it->index();
5899 v8::IndexedPropertyDeleterCallback deleter =
5900 v8::ToCData<v8::IndexedPropertyDeleterCallback>(interceptor->deleter());
5901 result = args.Call(deleter, index);
5902 } else if (it->name()->IsSymbol() && !interceptor->can_intercept_symbols()) {
5903 return Nothing<bool>();
5904 } else {
5905 Handle<Name> name = it->name();
5906 DCHECK(!name->IsPrivate());
5907 v8::GenericNamedPropertyDeleterCallback deleter =
5908 v8::ToCData<v8::GenericNamedPropertyDeleterCallback>(
5909 interceptor->deleter());
5910 result = args.Call(deleter, name);
5911 }
5912
5913 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
5914 if (result.is_null()) return Nothing<bool>();
5915
5916 DCHECK(result->IsBoolean());
5917 // Rebox CustomArguments::kReturnValueOffset before returning.
5918 return Just(result->IsTrue(isolate));
5919 }
5920
5921
DeleteNormalizedProperty(Handle<JSReceiver> object,Handle<Name> name,int entry)5922 void JSReceiver::DeleteNormalizedProperty(Handle<JSReceiver> object,
5923 Handle<Name> name, int entry) {
5924 DCHECK(!object->HasFastProperties());
5925 Isolate* isolate = object->GetIsolate();
5926
5927 if (object->IsJSGlobalObject()) {
5928 // If we have a global object, invalidate the cell and swap in a new one.
5929 Handle<GlobalDictionary> dictionary(
5930 JSObject::cast(*object)->global_dictionary());
5931 DCHECK_NE(GlobalDictionary::kNotFound, entry);
5932
5933 auto cell = PropertyCell::InvalidateEntry(dictionary, entry);
5934 cell->set_value(isolate->heap()->the_hole_value());
5935 cell->set_property_details(
5936 PropertyDetails::Empty(PropertyCellType::kUninitialized));
5937 } else {
5938 Handle<NameDictionary> dictionary(object->property_dictionary());
5939 DCHECK_NE(NameDictionary::kNotFound, entry);
5940
5941 NameDictionary::DeleteProperty(dictionary, entry);
5942 Handle<NameDictionary> new_properties =
5943 NameDictionary::Shrink(dictionary, name);
5944 object->set_properties(*new_properties);
5945 }
5946 }
5947
5948
DeleteProperty(LookupIterator * it,LanguageMode language_mode)5949 Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
5950 LanguageMode language_mode) {
5951 it->UpdateProtector();
5952
5953 Isolate* isolate = it->isolate();
5954
5955 if (it->state() == LookupIterator::JSPROXY) {
5956 return JSProxy::DeletePropertyOrElement(it->GetHolder<JSProxy>(),
5957 it->GetName(), language_mode);
5958 }
5959
5960 if (it->GetReceiver()->IsJSProxy()) {
5961 if (it->state() != LookupIterator::NOT_FOUND) {
5962 DCHECK_EQ(LookupIterator::DATA, it->state());
5963 DCHECK(it->name()->IsPrivate());
5964 it->Delete();
5965 }
5966 return Just(true);
5967 }
5968 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
5969
5970 for (; it->IsFound(); it->Next()) {
5971 switch (it->state()) {
5972 case LookupIterator::JSPROXY:
5973 case LookupIterator::NOT_FOUND:
5974 case LookupIterator::TRANSITION:
5975 UNREACHABLE();
5976 case LookupIterator::ACCESS_CHECK:
5977 if (it->HasAccess()) break;
5978 isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
5979 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
5980 return Just(false);
5981 case LookupIterator::INTERCEPTOR: {
5982 ShouldThrow should_throw =
5983 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
5984 Maybe<bool> result =
5985 JSObject::DeletePropertyWithInterceptor(it, should_throw);
5986 // An exception was thrown in the interceptor. Propagate.
5987 if (isolate->has_pending_exception()) return Nothing<bool>();
5988 // Delete with interceptor succeeded. Return result.
5989 // TODO(neis): In strict mode, we should probably throw if the
5990 // interceptor returns false.
5991 if (result.IsJust()) return result;
5992 break;
5993 }
5994 case LookupIterator::INTEGER_INDEXED_EXOTIC:
5995 return Just(true);
5996 case LookupIterator::DATA:
5997 case LookupIterator::ACCESSOR: {
5998 if (!it->IsConfigurable()) {
5999 // Fail if the property is not configurable.
6000 if (is_strict(language_mode)) {
6001 isolate->Throw(*isolate->factory()->NewTypeError(
6002 MessageTemplate::kStrictDeleteProperty, it->GetName(),
6003 receiver));
6004 return Nothing<bool>();
6005 }
6006 return Just(false);
6007 }
6008
6009 it->Delete();
6010
6011 return Just(true);
6012 }
6013 }
6014 }
6015
6016 return Just(true);
6017 }
6018
6019
DeleteElement(Handle<JSReceiver> object,uint32_t index,LanguageMode language_mode)6020 Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index,
6021 LanguageMode language_mode) {
6022 LookupIterator it(object->GetIsolate(), object, index, object,
6023 LookupIterator::OWN);
6024 return DeleteProperty(&it, language_mode);
6025 }
6026
6027
DeleteProperty(Handle<JSReceiver> object,Handle<Name> name,LanguageMode language_mode)6028 Maybe<bool> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
6029 Handle<Name> name,
6030 LanguageMode language_mode) {
6031 LookupIterator it(object, name, object, LookupIterator::OWN);
6032 return DeleteProperty(&it, language_mode);
6033 }
6034
6035
DeletePropertyOrElement(Handle<JSReceiver> object,Handle<Name> name,LanguageMode language_mode)6036 Maybe<bool> JSReceiver::DeletePropertyOrElement(Handle<JSReceiver> object,
6037 Handle<Name> name,
6038 LanguageMode language_mode) {
6039 LookupIterator it = LookupIterator::PropertyOrElement(
6040 name->GetIsolate(), object, name, object, LookupIterator::OWN);
6041 return DeleteProperty(&it, language_mode);
6042 }
6043
6044 // ES6 19.1.2.4
6045 // static
DefineProperty(Isolate * isolate,Handle<Object> object,Handle<Object> key,Handle<Object> attributes)6046 Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object,
6047 Handle<Object> key,
6048 Handle<Object> attributes) {
6049 // 1. If Type(O) is not Object, throw a TypeError exception.
6050 if (!object->IsJSReceiver()) {
6051 Handle<String> fun_name =
6052 isolate->factory()->InternalizeUtf8String("Object.defineProperty");
6053 THROW_NEW_ERROR_RETURN_FAILURE(
6054 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name));
6055 }
6056 // 2. Let key be ToPropertyKey(P).
6057 // 3. ReturnIfAbrupt(key).
6058 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key, ToPropertyKey(isolate, key));
6059 // 4. Let desc be ToPropertyDescriptor(Attributes).
6060 // 5. ReturnIfAbrupt(desc).
6061 PropertyDescriptor desc;
6062 if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) {
6063 return isolate->heap()->exception();
6064 }
6065 // 6. Let success be DefinePropertyOrThrow(O,key, desc).
6066 Maybe<bool> success = DefineOwnProperty(
6067 isolate, Handle<JSReceiver>::cast(object), key, &desc, THROW_ON_ERROR);
6068 // 7. ReturnIfAbrupt(success).
6069 MAYBE_RETURN(success, isolate->heap()->exception());
6070 CHECK(success.FromJust());
6071 // 8. Return O.
6072 return *object;
6073 }
6074
6075
6076 // ES6 19.1.2.3.1
6077 // static
DefineProperties(Isolate * isolate,Handle<Object> object,Handle<Object> properties)6078 MaybeHandle<Object> JSReceiver::DefineProperties(Isolate* isolate,
6079 Handle<Object> object,
6080 Handle<Object> properties) {
6081 // 1. If Type(O) is not Object, throw a TypeError exception.
6082 if (!object->IsJSReceiver()) {
6083 Handle<String> fun_name =
6084 isolate->factory()->InternalizeUtf8String("Object.defineProperties");
6085 THROW_NEW_ERROR(isolate,
6086 NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name),
6087 Object);
6088 }
6089 // 2. Let props be ToObject(Properties).
6090 // 3. ReturnIfAbrupt(props).
6091 Handle<JSReceiver> props;
6092 ASSIGN_RETURN_ON_EXCEPTION(isolate, props,
6093 Object::ToObject(isolate, properties), Object);
6094
6095 // 4. Let keys be props.[[OwnPropertyKeys]]().
6096 // 5. ReturnIfAbrupt(keys).
6097 Handle<FixedArray> keys;
6098 ASSIGN_RETURN_ON_EXCEPTION(
6099 isolate, keys, KeyAccumulator::GetKeys(props, KeyCollectionMode::kOwnOnly,
6100 ALL_PROPERTIES),
6101 Object);
6102 // 6. Let descriptors be an empty List.
6103 int capacity = keys->length();
6104 std::vector<PropertyDescriptor> descriptors(capacity);
6105 size_t descriptors_index = 0;
6106 // 7. Repeat for each element nextKey of keys in List order,
6107 for (int i = 0; i < keys->length(); ++i) {
6108 Handle<Object> next_key(keys->get(i), isolate);
6109 // 7a. Let propDesc be props.[[GetOwnProperty]](nextKey).
6110 // 7b. ReturnIfAbrupt(propDesc).
6111 bool success = false;
6112 LookupIterator it = LookupIterator::PropertyOrElement(
6113 isolate, props, next_key, &success, LookupIterator::OWN);
6114 DCHECK(success);
6115 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
6116 if (!maybe.IsJust()) return MaybeHandle<Object>();
6117 PropertyAttributes attrs = maybe.FromJust();
6118 // 7c. If propDesc is not undefined and propDesc.[[Enumerable]] is true:
6119 if (attrs == ABSENT) continue;
6120 if (attrs & DONT_ENUM) continue;
6121 // 7c i. Let descObj be Get(props, nextKey).
6122 // 7c ii. ReturnIfAbrupt(descObj).
6123 Handle<Object> desc_obj;
6124 ASSIGN_RETURN_ON_EXCEPTION(isolate, desc_obj, Object::GetProperty(&it),
6125 Object);
6126 // 7c iii. Let desc be ToPropertyDescriptor(descObj).
6127 success = PropertyDescriptor::ToPropertyDescriptor(
6128 isolate, desc_obj, &descriptors[descriptors_index]);
6129 // 7c iv. ReturnIfAbrupt(desc).
6130 if (!success) return MaybeHandle<Object>();
6131 // 7c v. Append the pair (a two element List) consisting of nextKey and
6132 // desc to the end of descriptors.
6133 descriptors[descriptors_index].set_name(next_key);
6134 descriptors_index++;
6135 }
6136 // 8. For each pair from descriptors in list order,
6137 for (size_t i = 0; i < descriptors_index; ++i) {
6138 PropertyDescriptor* desc = &descriptors[i];
6139 // 8a. Let P be the first element of pair.
6140 // 8b. Let desc be the second element of pair.
6141 // 8c. Let status be DefinePropertyOrThrow(O, P, desc).
6142 Maybe<bool> status =
6143 DefineOwnProperty(isolate, Handle<JSReceiver>::cast(object),
6144 desc->name(), desc, THROW_ON_ERROR);
6145 // 8d. ReturnIfAbrupt(status).
6146 if (!status.IsJust()) return MaybeHandle<Object>();
6147 CHECK(status.FromJust());
6148 }
6149 // 9. Return o.
6150 return object;
6151 }
6152
6153
6154 // static
DefineOwnProperty(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> key,PropertyDescriptor * desc,ShouldThrow should_throw)6155 Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate,
6156 Handle<JSReceiver> object,
6157 Handle<Object> key,
6158 PropertyDescriptor* desc,
6159 ShouldThrow should_throw) {
6160 if (object->IsJSArray()) {
6161 return JSArray::DefineOwnProperty(isolate, Handle<JSArray>::cast(object),
6162 key, desc, should_throw);
6163 }
6164 if (object->IsJSProxy()) {
6165 return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object),
6166 key, desc, should_throw);
6167 }
6168 if (object->IsJSTypedArray()) {
6169 return JSTypedArray::DefineOwnProperty(
6170 isolate, Handle<JSTypedArray>::cast(object), key, desc, should_throw);
6171 }
6172 // TODO(neis): Special case for JSModuleNamespace?
6173
6174 // OrdinaryDefineOwnProperty, by virtue of calling
6175 // DefineOwnPropertyIgnoreAttributes, can handle arguments
6176 // (ES#sec-arguments-exotic-objects-defineownproperty-p-desc).
6177 return OrdinaryDefineOwnProperty(isolate, Handle<JSObject>::cast(object), key,
6178 desc, should_throw);
6179 }
6180
6181
6182 // static
OrdinaryDefineOwnProperty(Isolate * isolate,Handle<JSObject> object,Handle<Object> key,PropertyDescriptor * desc,ShouldThrow should_throw)6183 Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate,
6184 Handle<JSObject> object,
6185 Handle<Object> key,
6186 PropertyDescriptor* desc,
6187 ShouldThrow should_throw) {
6188 bool success = false;
6189 DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
6190 LookupIterator it = LookupIterator::PropertyOrElement(
6191 isolate, object, key, &success, LookupIterator::OWN);
6192 DCHECK(success); // ...so creating a LookupIterator can't fail.
6193
6194 // Deal with access checks first.
6195 if (it.state() == LookupIterator::ACCESS_CHECK) {
6196 if (!it.HasAccess()) {
6197 isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>());
6198 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
6199 return Just(true);
6200 }
6201 it.Next();
6202 }
6203
6204 // Handle interceptor
6205 if (it.state() == LookupIterator::INTERCEPTOR) {
6206 if (it.HolderIsReceiverOrHiddenPrototype()) {
6207 Maybe<bool> result = DefinePropertyWithInterceptorInternal(
6208 &it, it.GetInterceptor(), should_throw, *desc);
6209 if (result.IsNothing() || result.FromJust()) {
6210 return result;
6211 }
6212 }
6213 }
6214
6215 return OrdinaryDefineOwnProperty(&it, desc, should_throw);
6216 }
6217
6218
6219 // ES6 9.1.6.1
6220 // static
OrdinaryDefineOwnProperty(LookupIterator * it,PropertyDescriptor * desc,ShouldThrow should_throw)6221 Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
6222 PropertyDescriptor* desc,
6223 ShouldThrow should_throw) {
6224 Isolate* isolate = it->isolate();
6225 // 1. Let current be O.[[GetOwnProperty]](P).
6226 // 2. ReturnIfAbrupt(current).
6227 PropertyDescriptor current;
6228 MAYBE_RETURN(GetOwnPropertyDescriptor(it, ¤t), Nothing<bool>());
6229
6230 // TODO(jkummerow/verwaest): It would be nice if we didn't have to reset
6231 // the iterator every time. Currently, the reasons why we need it are:
6232 // - handle interceptors correctly
6233 // - handle accessors correctly (which might change the holder's map)
6234 it->Restart();
6235 // 3. Let extensible be the value of the [[Extensible]] internal slot of O.
6236 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
6237 bool extensible = JSObject::IsExtensible(object);
6238
6239 return ValidateAndApplyPropertyDescriptor(isolate, it, extensible, desc,
6240 ¤t, should_throw);
6241 }
6242
6243
6244 // ES6 9.1.6.2
6245 // static
IsCompatiblePropertyDescriptor(Isolate * isolate,bool extensible,PropertyDescriptor * desc,PropertyDescriptor * current,Handle<Name> property_name,ShouldThrow should_throw)6246 Maybe<bool> JSReceiver::IsCompatiblePropertyDescriptor(
6247 Isolate* isolate, bool extensible, PropertyDescriptor* desc,
6248 PropertyDescriptor* current, Handle<Name> property_name,
6249 ShouldThrow should_throw) {
6250 // 1. Return ValidateAndApplyPropertyDescriptor(undefined, undefined,
6251 // Extensible, Desc, Current).
6252 return ValidateAndApplyPropertyDescriptor(
6253 isolate, NULL, extensible, desc, current, should_throw, property_name);
6254 }
6255
6256
6257 // ES6 9.1.6.3
6258 // static
ValidateAndApplyPropertyDescriptor(Isolate * isolate,LookupIterator * it,bool extensible,PropertyDescriptor * desc,PropertyDescriptor * current,ShouldThrow should_throw,Handle<Name> property_name)6259 Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor(
6260 Isolate* isolate, LookupIterator* it, bool extensible,
6261 PropertyDescriptor* desc, PropertyDescriptor* current,
6262 ShouldThrow should_throw, Handle<Name> property_name) {
6263 // We either need a LookupIterator, or a property name.
6264 DCHECK((it == NULL) != property_name.is_null());
6265 Handle<JSObject> object;
6266 if (it != NULL) object = Handle<JSObject>::cast(it->GetReceiver());
6267 bool desc_is_data_descriptor = PropertyDescriptor::IsDataDescriptor(desc);
6268 bool desc_is_accessor_descriptor =
6269 PropertyDescriptor::IsAccessorDescriptor(desc);
6270 bool desc_is_generic_descriptor =
6271 PropertyDescriptor::IsGenericDescriptor(desc);
6272 // 1. (Assert)
6273 // 2. If current is undefined, then
6274 if (current->is_empty()) {
6275 // 2a. If extensible is false, return false.
6276 if (!extensible) {
6277 RETURN_FAILURE(isolate, should_throw,
6278 NewTypeError(MessageTemplate::kDefineDisallowed,
6279 it != NULL ? it->GetName() : property_name));
6280 }
6281 // 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then:
6282 // (This is equivalent to !IsAccessorDescriptor(desc).)
6283 DCHECK((desc_is_generic_descriptor || desc_is_data_descriptor) ==
6284 !desc_is_accessor_descriptor);
6285 if (!desc_is_accessor_descriptor) {
6286 // 2c i. If O is not undefined, create an own data property named P of
6287 // object O whose [[Value]], [[Writable]], [[Enumerable]] and
6288 // [[Configurable]] attribute values are described by Desc. If the value
6289 // of an attribute field of Desc is absent, the attribute of the newly
6290 // created property is set to its default value.
6291 if (it != NULL) {
6292 if (!desc->has_writable()) desc->set_writable(false);
6293 if (!desc->has_enumerable()) desc->set_enumerable(false);
6294 if (!desc->has_configurable()) desc->set_configurable(false);
6295 Handle<Object> value(
6296 desc->has_value()
6297 ? desc->value()
6298 : Handle<Object>::cast(isolate->factory()->undefined_value()));
6299 MaybeHandle<Object> result =
6300 JSObject::DefineOwnPropertyIgnoreAttributes(it, value,
6301 desc->ToAttributes());
6302 if (result.is_null()) return Nothing<bool>();
6303 }
6304 } else {
6305 // 2d. Else Desc must be an accessor Property Descriptor,
6306 DCHECK(desc_is_accessor_descriptor);
6307 // 2d i. If O is not undefined, create an own accessor property named P
6308 // of object O whose [[Get]], [[Set]], [[Enumerable]] and
6309 // [[Configurable]] attribute values are described by Desc. If the value
6310 // of an attribute field of Desc is absent, the attribute of the newly
6311 // created property is set to its default value.
6312 if (it != NULL) {
6313 if (!desc->has_enumerable()) desc->set_enumerable(false);
6314 if (!desc->has_configurable()) desc->set_configurable(false);
6315 Handle<Object> getter(
6316 desc->has_get()
6317 ? desc->get()
6318 : Handle<Object>::cast(isolate->factory()->null_value()));
6319 Handle<Object> setter(
6320 desc->has_set()
6321 ? desc->set()
6322 : Handle<Object>::cast(isolate->factory()->null_value()));
6323 MaybeHandle<Object> result =
6324 JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes());
6325 if (result.is_null()) return Nothing<bool>();
6326 }
6327 }
6328 // 2e. Return true.
6329 return Just(true);
6330 }
6331 // 3. Return true, if every field in Desc is absent.
6332 // 4. Return true, if every field in Desc also occurs in current and the
6333 // value of every field in Desc is the same value as the corresponding field
6334 // in current when compared using the SameValue algorithm.
6335 if ((!desc->has_enumerable() ||
6336 desc->enumerable() == current->enumerable()) &&
6337 (!desc->has_configurable() ||
6338 desc->configurable() == current->configurable()) &&
6339 (!desc->has_value() ||
6340 (current->has_value() && current->value()->SameValue(*desc->value()))) &&
6341 (!desc->has_writable() ||
6342 (current->has_writable() && current->writable() == desc->writable())) &&
6343 (!desc->has_get() ||
6344 (current->has_get() && current->get()->SameValue(*desc->get()))) &&
6345 (!desc->has_set() ||
6346 (current->has_set() && current->set()->SameValue(*desc->set())))) {
6347 return Just(true);
6348 }
6349 // 5. If the [[Configurable]] field of current is false, then
6350 if (!current->configurable()) {
6351 // 5a. Return false, if the [[Configurable]] field of Desc is true.
6352 if (desc->has_configurable() && desc->configurable()) {
6353 RETURN_FAILURE(isolate, should_throw,
6354 NewTypeError(MessageTemplate::kRedefineDisallowed,
6355 it != NULL ? it->GetName() : property_name));
6356 }
6357 // 5b. Return false, if the [[Enumerable]] field of Desc is present and the
6358 // [[Enumerable]] fields of current and Desc are the Boolean negation of
6359 // each other.
6360 if (desc->has_enumerable() && desc->enumerable() != current->enumerable()) {
6361 RETURN_FAILURE(isolate, should_throw,
6362 NewTypeError(MessageTemplate::kRedefineDisallowed,
6363 it != NULL ? it->GetName() : property_name));
6364 }
6365 }
6366
6367 bool current_is_data_descriptor =
6368 PropertyDescriptor::IsDataDescriptor(current);
6369 // 6. If IsGenericDescriptor(Desc) is true, no further validation is required.
6370 if (desc_is_generic_descriptor) {
6371 // Nothing to see here.
6372
6373 // 7. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) have
6374 // different results, then:
6375 } else if (current_is_data_descriptor != desc_is_data_descriptor) {
6376 // 7a. Return false, if the [[Configurable]] field of current is false.
6377 if (!current->configurable()) {
6378 RETURN_FAILURE(isolate, should_throw,
6379 NewTypeError(MessageTemplate::kRedefineDisallowed,
6380 it != NULL ? it->GetName() : property_name));
6381 }
6382 // 7b. If IsDataDescriptor(current) is true, then:
6383 if (current_is_data_descriptor) {
6384 // 7b i. If O is not undefined, convert the property named P of object O
6385 // from a data property to an accessor property. Preserve the existing
6386 // values of the converted property's [[Configurable]] and [[Enumerable]]
6387 // attributes and set the rest of the property's attributes to their
6388 // default values.
6389 // --> Folded into step 10.
6390 } else {
6391 // 7c i. If O is not undefined, convert the property named P of object O
6392 // from an accessor property to a data property. Preserve the existing
6393 // values of the converted property’s [[Configurable]] and [[Enumerable]]
6394 // attributes and set the rest of the property’s attributes to their
6395 // default values.
6396 // --> Folded into step 10.
6397 }
6398
6399 // 8. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both
6400 // true, then:
6401 } else if (current_is_data_descriptor && desc_is_data_descriptor) {
6402 // 8a. If the [[Configurable]] field of current is false, then:
6403 if (!current->configurable()) {
6404 // 8a i. Return false, if the [[Writable]] field of current is false and
6405 // the [[Writable]] field of Desc is true.
6406 if (!current->writable() && desc->has_writable() && desc->writable()) {
6407 RETURN_FAILURE(
6408 isolate, should_throw,
6409 NewTypeError(MessageTemplate::kRedefineDisallowed,
6410 it != NULL ? it->GetName() : property_name));
6411 }
6412 // 8a ii. If the [[Writable]] field of current is false, then:
6413 if (!current->writable()) {
6414 // 8a ii 1. Return false, if the [[Value]] field of Desc is present and
6415 // SameValue(Desc.[[Value]], current.[[Value]]) is false.
6416 if (desc->has_value() && !desc->value()->SameValue(*current->value())) {
6417 RETURN_FAILURE(
6418 isolate, should_throw,
6419 NewTypeError(MessageTemplate::kRedefineDisallowed,
6420 it != NULL ? it->GetName() : property_name));
6421 }
6422 }
6423 }
6424 } else {
6425 // 9. Else IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc)
6426 // are both true,
6427 DCHECK(PropertyDescriptor::IsAccessorDescriptor(current) &&
6428 desc_is_accessor_descriptor);
6429 // 9a. If the [[Configurable]] field of current is false, then:
6430 if (!current->configurable()) {
6431 // 9a i. Return false, if the [[Set]] field of Desc is present and
6432 // SameValue(Desc.[[Set]], current.[[Set]]) is false.
6433 if (desc->has_set() && !desc->set()->SameValue(*current->set())) {
6434 RETURN_FAILURE(
6435 isolate, should_throw,
6436 NewTypeError(MessageTemplate::kRedefineDisallowed,
6437 it != NULL ? it->GetName() : property_name));
6438 }
6439 // 9a ii. Return false, if the [[Get]] field of Desc is present and
6440 // SameValue(Desc.[[Get]], current.[[Get]]) is false.
6441 if (desc->has_get() && !desc->get()->SameValue(*current->get())) {
6442 RETURN_FAILURE(
6443 isolate, should_throw,
6444 NewTypeError(MessageTemplate::kRedefineDisallowed,
6445 it != NULL ? it->GetName() : property_name));
6446 }
6447 }
6448 }
6449
6450 // 10. If O is not undefined, then:
6451 if (it != NULL) {
6452 // 10a. For each field of Desc that is present, set the corresponding
6453 // attribute of the property named P of object O to the value of the field.
6454 PropertyAttributes attrs = NONE;
6455
6456 if (desc->has_enumerable()) {
6457 attrs = static_cast<PropertyAttributes>(
6458 attrs | (desc->enumerable() ? NONE : DONT_ENUM));
6459 } else {
6460 attrs = static_cast<PropertyAttributes>(
6461 attrs | (current->enumerable() ? NONE : DONT_ENUM));
6462 }
6463 if (desc->has_configurable()) {
6464 attrs = static_cast<PropertyAttributes>(
6465 attrs | (desc->configurable() ? NONE : DONT_DELETE));
6466 } else {
6467 attrs = static_cast<PropertyAttributes>(
6468 attrs | (current->configurable() ? NONE : DONT_DELETE));
6469 }
6470 if (desc_is_data_descriptor ||
6471 (desc_is_generic_descriptor && current_is_data_descriptor)) {
6472 if (desc->has_writable()) {
6473 attrs = static_cast<PropertyAttributes>(
6474 attrs | (desc->writable() ? NONE : READ_ONLY));
6475 } else {
6476 attrs = static_cast<PropertyAttributes>(
6477 attrs | (current->writable() ? NONE : READ_ONLY));
6478 }
6479 Handle<Object> value(
6480 desc->has_value() ? desc->value()
6481 : current->has_value()
6482 ? current->value()
6483 : Handle<Object>::cast(
6484 isolate->factory()->undefined_value()));
6485 MaybeHandle<Object> result =
6486 JSObject::DefineOwnPropertyIgnoreAttributes(it, value, attrs);
6487 if (result.is_null()) return Nothing<bool>();
6488 } else {
6489 DCHECK(desc_is_accessor_descriptor ||
6490 (desc_is_generic_descriptor &&
6491 PropertyDescriptor::IsAccessorDescriptor(current)));
6492 Handle<Object> getter(
6493 desc->has_get()
6494 ? desc->get()
6495 : current->has_get()
6496 ? current->get()
6497 : Handle<Object>::cast(isolate->factory()->null_value()));
6498 Handle<Object> setter(
6499 desc->has_set()
6500 ? desc->set()
6501 : current->has_set()
6502 ? current->set()
6503 : Handle<Object>::cast(isolate->factory()->null_value()));
6504 MaybeHandle<Object> result =
6505 JSObject::DefineAccessor(it, getter, setter, attrs);
6506 if (result.is_null()) return Nothing<bool>();
6507 }
6508 }
6509
6510 // 11. Return true.
6511 return Just(true);
6512 }
6513
6514
6515 // static
CreateDataProperty(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)6516 Maybe<bool> JSReceiver::CreateDataProperty(LookupIterator* it,
6517 Handle<Object> value,
6518 ShouldThrow should_throw) {
6519 DCHECK(!it->check_prototype_chain());
6520 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
6521 Isolate* isolate = receiver->GetIsolate();
6522
6523 if (receiver->IsJSObject()) {
6524 return JSObject::CreateDataProperty(it, value, should_throw); // Shortcut.
6525 }
6526
6527 PropertyDescriptor new_desc;
6528 new_desc.set_value(value);
6529 new_desc.set_writable(true);
6530 new_desc.set_enumerable(true);
6531 new_desc.set_configurable(true);
6532
6533 return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
6534 &new_desc, should_throw);
6535 }
6536
CreateDataProperty(LookupIterator * it,Handle<Object> value,ShouldThrow should_throw)6537 Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it,
6538 Handle<Object> value,
6539 ShouldThrow should_throw) {
6540 DCHECK(it->GetReceiver()->IsJSObject());
6541 MAYBE_RETURN(JSReceiver::GetPropertyAttributes(it), Nothing<bool>());
6542 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
6543 Isolate* isolate = receiver->GetIsolate();
6544
6545 if (it->IsFound()) {
6546 Maybe<PropertyAttributes> attributes = GetPropertyAttributes(it);
6547 MAYBE_RETURN(attributes, Nothing<bool>());
6548 if ((attributes.FromJust() & DONT_DELETE) != 0) {
6549 RETURN_FAILURE(
6550 isolate, should_throw,
6551 NewTypeError(MessageTemplate::kRedefineDisallowed, it->GetName()));
6552 }
6553 } else {
6554 if (!JSObject::IsExtensible(Handle<JSObject>::cast(it->GetReceiver()))) {
6555 RETURN_FAILURE(
6556 isolate, should_throw,
6557 NewTypeError(MessageTemplate::kDefineDisallowed, it->GetName()));
6558 }
6559 }
6560
6561 RETURN_ON_EXCEPTION_VALUE(it->isolate(),
6562 DefineOwnPropertyIgnoreAttributes(it, value, NONE),
6563 Nothing<bool>());
6564
6565 return Just(true);
6566 }
6567
6568
6569 // TODO(jkummerow): Consider unification with FastAsArrayLength() in
6570 // accessors.cc.
PropertyKeyToArrayLength(Handle<Object> value,uint32_t * length)6571 bool PropertyKeyToArrayLength(Handle<Object> value, uint32_t* length) {
6572 DCHECK(value->IsNumber() || value->IsName());
6573 if (value->ToArrayLength(length)) return true;
6574 if (value->IsString()) return String::cast(*value)->AsArrayIndex(length);
6575 return false;
6576 }
6577
PropertyKeyToArrayIndex(Handle<Object> index_obj,uint32_t * output)6578 bool PropertyKeyToArrayIndex(Handle<Object> index_obj, uint32_t* output) {
6579 return PropertyKeyToArrayLength(index_obj, output) && *output != kMaxUInt32;
6580 }
6581
6582
6583 // ES6 9.4.2.1
6584 // static
DefineOwnProperty(Isolate * isolate,Handle<JSArray> o,Handle<Object> name,PropertyDescriptor * desc,ShouldThrow should_throw)6585 Maybe<bool> JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o,
6586 Handle<Object> name,
6587 PropertyDescriptor* desc,
6588 ShouldThrow should_throw) {
6589 // 1. Assert: IsPropertyKey(P) is true. ("P" is |name|.)
6590 // 2. If P is "length", then:
6591 // TODO(jkummerow): Check if we need slow string comparison.
6592 if (*name == isolate->heap()->length_string()) {
6593 // 2a. Return ArraySetLength(A, Desc).
6594 return ArraySetLength(isolate, o, desc, should_throw);
6595 }
6596 // 3. Else if P is an array index, then:
6597 uint32_t index = 0;
6598 if (PropertyKeyToArrayIndex(name, &index)) {
6599 // 3a. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
6600 PropertyDescriptor old_len_desc;
6601 Maybe<bool> success = GetOwnPropertyDescriptor(
6602 isolate, o, isolate->factory()->length_string(), &old_len_desc);
6603 // 3b. (Assert)
6604 DCHECK(success.FromJust());
6605 USE(success);
6606 // 3c. Let oldLen be oldLenDesc.[[Value]].
6607 uint32_t old_len = 0;
6608 CHECK(old_len_desc.value()->ToArrayLength(&old_len));
6609 // 3d. Let index be ToUint32(P).
6610 // (Already done above.)
6611 // 3e. (Assert)
6612 // 3f. If index >= oldLen and oldLenDesc.[[Writable]] is false,
6613 // return false.
6614 if (index >= old_len && old_len_desc.has_writable() &&
6615 !old_len_desc.writable()) {
6616 RETURN_FAILURE(isolate, should_throw,
6617 NewTypeError(MessageTemplate::kDefineDisallowed, name));
6618 }
6619 // 3g. Let succeeded be OrdinaryDefineOwnProperty(A, P, Desc).
6620 Maybe<bool> succeeded =
6621 OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
6622 // 3h. Assert: succeeded is not an abrupt completion.
6623 // In our case, if should_throw == THROW_ON_ERROR, it can be!
6624 // 3i. If succeeded is false, return false.
6625 if (succeeded.IsNothing() || !succeeded.FromJust()) return succeeded;
6626 // 3j. If index >= oldLen, then:
6627 if (index >= old_len) {
6628 // 3j i. Set oldLenDesc.[[Value]] to index + 1.
6629 old_len_desc.set_value(isolate->factory()->NewNumberFromUint(index + 1));
6630 // 3j ii. Let succeeded be
6631 // OrdinaryDefineOwnProperty(A, "length", oldLenDesc).
6632 succeeded = OrdinaryDefineOwnProperty(isolate, o,
6633 isolate->factory()->length_string(),
6634 &old_len_desc, should_throw);
6635 // 3j iii. Assert: succeeded is true.
6636 DCHECK(succeeded.FromJust());
6637 USE(succeeded);
6638 }
6639 // 3k. Return true.
6640 return Just(true);
6641 }
6642
6643 // 4. Return OrdinaryDefineOwnProperty(A, P, Desc).
6644 return OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
6645 }
6646
6647
6648 // Part of ES6 9.4.2.4 ArraySetLength.
6649 // static
AnythingToArrayLength(Isolate * isolate,Handle<Object> length_object,uint32_t * output)6650 bool JSArray::AnythingToArrayLength(Isolate* isolate,
6651 Handle<Object> length_object,
6652 uint32_t* output) {
6653 // Fast path: check numbers and strings that can be converted directly
6654 // and unobservably.
6655 if (length_object->ToArrayLength(output)) return true;
6656 if (length_object->IsString() &&
6657 Handle<String>::cast(length_object)->AsArrayIndex(output)) {
6658 return true;
6659 }
6660 // Slow path: follow steps in ES6 9.4.2.4 "ArraySetLength".
6661 // 3. Let newLen be ToUint32(Desc.[[Value]]).
6662 Handle<Object> uint32_v;
6663 if (!Object::ToUint32(isolate, length_object).ToHandle(&uint32_v)) {
6664 // 4. ReturnIfAbrupt(newLen).
6665 return false;
6666 }
6667 // 5. Let numberLen be ToNumber(Desc.[[Value]]).
6668 Handle<Object> number_v;
6669 if (!Object::ToNumber(length_object).ToHandle(&number_v)) {
6670 // 6. ReturnIfAbrupt(newLen).
6671 return false;
6672 }
6673 // 7. If newLen != numberLen, throw a RangeError exception.
6674 if (uint32_v->Number() != number_v->Number()) {
6675 Handle<Object> exception =
6676 isolate->factory()->NewRangeError(MessageTemplate::kInvalidArrayLength);
6677 isolate->Throw(*exception);
6678 return false;
6679 }
6680 CHECK(uint32_v->ToArrayLength(output));
6681 return true;
6682 }
6683
6684
6685 // ES6 9.4.2.4
6686 // static
ArraySetLength(Isolate * isolate,Handle<JSArray> a,PropertyDescriptor * desc,ShouldThrow should_throw)6687 Maybe<bool> JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a,
6688 PropertyDescriptor* desc,
6689 ShouldThrow should_throw) {
6690 // 1. If the [[Value]] field of Desc is absent, then
6691 if (!desc->has_value()) {
6692 // 1a. Return OrdinaryDefineOwnProperty(A, "length", Desc).
6693 return OrdinaryDefineOwnProperty(
6694 isolate, a, isolate->factory()->length_string(), desc, should_throw);
6695 }
6696 // 2. Let newLenDesc be a copy of Desc.
6697 // (Actual copying is not necessary.)
6698 PropertyDescriptor* new_len_desc = desc;
6699 // 3. - 7. Convert Desc.[[Value]] to newLen.
6700 uint32_t new_len = 0;
6701 if (!AnythingToArrayLength(isolate, desc->value(), &new_len)) {
6702 DCHECK(isolate->has_pending_exception());
6703 return Nothing<bool>();
6704 }
6705 // 8. Set newLenDesc.[[Value]] to newLen.
6706 // (Done below, if needed.)
6707 // 9. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
6708 PropertyDescriptor old_len_desc;
6709 Maybe<bool> success = GetOwnPropertyDescriptor(
6710 isolate, a, isolate->factory()->length_string(), &old_len_desc);
6711 // 10. (Assert)
6712 DCHECK(success.FromJust());
6713 USE(success);
6714 // 11. Let oldLen be oldLenDesc.[[Value]].
6715 uint32_t old_len = 0;
6716 CHECK(old_len_desc.value()->ToArrayLength(&old_len));
6717 // 12. If newLen >= oldLen, then
6718 if (new_len >= old_len) {
6719 // 8. Set newLenDesc.[[Value]] to newLen.
6720 // 12a. Return OrdinaryDefineOwnProperty(A, "length", newLenDesc).
6721 new_len_desc->set_value(isolate->factory()->NewNumberFromUint(new_len));
6722 return OrdinaryDefineOwnProperty(isolate, a,
6723 isolate->factory()->length_string(),
6724 new_len_desc, should_throw);
6725 }
6726 // 13. If oldLenDesc.[[Writable]] is false, return false.
6727 if (!old_len_desc.writable()) {
6728 RETURN_FAILURE(isolate, should_throw,
6729 NewTypeError(MessageTemplate::kRedefineDisallowed,
6730 isolate->factory()->length_string()));
6731 }
6732 // 14. If newLenDesc.[[Writable]] is absent or has the value true,
6733 // let newWritable be true.
6734 bool new_writable = false;
6735 if (!new_len_desc->has_writable() || new_len_desc->writable()) {
6736 new_writable = true;
6737 } else {
6738 // 15. Else,
6739 // 15a. Need to defer setting the [[Writable]] attribute to false in case
6740 // any elements cannot be deleted.
6741 // 15b. Let newWritable be false. (It's initialized as "false" anyway.)
6742 // 15c. Set newLenDesc.[[Writable]] to true.
6743 // (Not needed.)
6744 }
6745 // Most of steps 16 through 19 is implemented by JSArray::SetLength.
6746 JSArray::SetLength(a, new_len);
6747 // Steps 19d-ii, 20.
6748 if (!new_writable) {
6749 PropertyDescriptor readonly;
6750 readonly.set_writable(false);
6751 Maybe<bool> success = OrdinaryDefineOwnProperty(
6752 isolate, a, isolate->factory()->length_string(), &readonly,
6753 should_throw);
6754 DCHECK(success.FromJust());
6755 USE(success);
6756 }
6757 uint32_t actual_new_len = 0;
6758 CHECK(a->length()->ToArrayLength(&actual_new_len));
6759 // Steps 19d-v, 21. Return false if there were non-deletable elements.
6760 bool result = actual_new_len == new_len;
6761 if (!result) {
6762 RETURN_FAILURE(
6763 isolate, should_throw,
6764 NewTypeError(MessageTemplate::kStrictDeleteProperty,
6765 isolate->factory()->NewNumberFromUint(actual_new_len - 1),
6766 a));
6767 }
6768 return Just(result);
6769 }
6770
6771
6772 // ES6 9.5.6
6773 // static
DefineOwnProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Object> key,PropertyDescriptor * desc,ShouldThrow should_throw)6774 Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy,
6775 Handle<Object> key,
6776 PropertyDescriptor* desc,
6777 ShouldThrow should_throw) {
6778 STACK_CHECK(isolate, Nothing<bool>());
6779 if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) {
6780 return SetPrivateProperty(isolate, proxy, Handle<Symbol>::cast(key), desc,
6781 should_throw);
6782 }
6783 Handle<String> trap_name = isolate->factory()->defineProperty_string();
6784 // 1. Assert: IsPropertyKey(P) is true.
6785 DCHECK(key->IsName() || key->IsNumber());
6786 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
6787 Handle<Object> handler(proxy->handler(), isolate);
6788 // 3. If handler is null, throw a TypeError exception.
6789 // 4. Assert: Type(handler) is Object.
6790 if (proxy->IsRevoked()) {
6791 isolate->Throw(*isolate->factory()->NewTypeError(
6792 MessageTemplate::kProxyRevoked, trap_name));
6793 return Nothing<bool>();
6794 }
6795 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
6796 Handle<JSReceiver> target(proxy->target(), isolate);
6797 // 6. Let trap be ? GetMethod(handler, "defineProperty").
6798 Handle<Object> trap;
6799 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
6800 isolate, trap,
6801 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
6802 Nothing<bool>());
6803 // 7. If trap is undefined, then:
6804 if (trap->IsUndefined(isolate)) {
6805 // 7a. Return target.[[DefineOwnProperty]](P, Desc).
6806 return JSReceiver::DefineOwnProperty(isolate, target, key, desc,
6807 should_throw);
6808 }
6809 // 8. Let descObj be FromPropertyDescriptor(Desc).
6810 Handle<Object> desc_obj = desc->ToObject(isolate);
6811 // 9. Let booleanTrapResult be
6812 // ToBoolean(? Call(trap, handler, «target, P, descObj»)).
6813 Handle<Name> property_name =
6814 key->IsName()
6815 ? Handle<Name>::cast(key)
6816 : Handle<Name>::cast(isolate->factory()->NumberToString(key));
6817 // Do not leak private property names.
6818 DCHECK(!property_name->IsPrivate());
6819 Handle<Object> trap_result_obj;
6820 Handle<Object> args[] = {target, property_name, desc_obj};
6821 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
6822 isolate, trap_result_obj,
6823 Execution::Call(isolate, trap, handler, arraysize(args), args),
6824 Nothing<bool>());
6825 // 10. If booleanTrapResult is false, return false.
6826 if (!trap_result_obj->BooleanValue()) {
6827 RETURN_FAILURE(isolate, should_throw,
6828 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
6829 trap_name, property_name));
6830 }
6831 // 11. Let targetDesc be ? target.[[GetOwnProperty]](P).
6832 PropertyDescriptor target_desc;
6833 Maybe<bool> target_found =
6834 JSReceiver::GetOwnPropertyDescriptor(isolate, target, key, &target_desc);
6835 MAYBE_RETURN(target_found, Nothing<bool>());
6836 // 12. Let extensibleTarget be ? IsExtensible(target).
6837 Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
6838 MAYBE_RETURN(maybe_extensible, Nothing<bool>());
6839 bool extensible_target = maybe_extensible.FromJust();
6840 // 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]]
6841 // is false, then:
6842 // 13a. Let settingConfigFalse be true.
6843 // 14. Else let settingConfigFalse be false.
6844 bool setting_config_false = desc->has_configurable() && !desc->configurable();
6845 // 15. If targetDesc is undefined, then
6846 if (!target_found.FromJust()) {
6847 // 15a. If extensibleTarget is false, throw a TypeError exception.
6848 if (!extensible_target) {
6849 isolate->Throw(*isolate->factory()->NewTypeError(
6850 MessageTemplate::kProxyDefinePropertyNonExtensible, property_name));
6851 return Nothing<bool>();
6852 }
6853 // 15b. If settingConfigFalse is true, throw a TypeError exception.
6854 if (setting_config_false) {
6855 isolate->Throw(*isolate->factory()->NewTypeError(
6856 MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
6857 return Nothing<bool>();
6858 }
6859 } else {
6860 // 16. Else targetDesc is not undefined,
6861 // 16a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc,
6862 // targetDesc) is false, throw a TypeError exception.
6863 Maybe<bool> valid =
6864 IsCompatiblePropertyDescriptor(isolate, extensible_target, desc,
6865 &target_desc, property_name, DONT_THROW);
6866 MAYBE_RETURN(valid, Nothing<bool>());
6867 if (!valid.FromJust()) {
6868 isolate->Throw(*isolate->factory()->NewTypeError(
6869 MessageTemplate::kProxyDefinePropertyIncompatible, property_name));
6870 return Nothing<bool>();
6871 }
6872 // 16b. If settingConfigFalse is true and targetDesc.[[Configurable]] is
6873 // true, throw a TypeError exception.
6874 if (setting_config_false && target_desc.configurable()) {
6875 isolate->Throw(*isolate->factory()->NewTypeError(
6876 MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
6877 return Nothing<bool>();
6878 }
6879 }
6880 // 17. Return true.
6881 return Just(true);
6882 }
6883
6884
6885 // static
SetPrivateProperty(Isolate * isolate,Handle<JSProxy> proxy,Handle<Symbol> private_name,PropertyDescriptor * desc,ShouldThrow should_throw)6886 Maybe<bool> JSProxy::SetPrivateProperty(Isolate* isolate, Handle<JSProxy> proxy,
6887 Handle<Symbol> private_name,
6888 PropertyDescriptor* desc,
6889 ShouldThrow should_throw) {
6890 // Despite the generic name, this can only add private data properties.
6891 if (!PropertyDescriptor::IsDataDescriptor(desc) ||
6892 desc->ToAttributes() != DONT_ENUM) {
6893 RETURN_FAILURE(isolate, should_throw,
6894 NewTypeError(MessageTemplate::kProxyPrivate));
6895 }
6896 DCHECK(proxy->map()->is_dictionary_map());
6897 Handle<Object> value =
6898 desc->has_value()
6899 ? desc->value()
6900 : Handle<Object>::cast(isolate->factory()->undefined_value());
6901
6902 LookupIterator it(proxy, private_name, proxy);
6903
6904 if (it.IsFound()) {
6905 DCHECK_EQ(LookupIterator::DATA, it.state());
6906 DCHECK_EQ(DONT_ENUM, it.property_attributes());
6907 it.WriteDataValue(value, false);
6908 return Just(true);
6909 }
6910
6911 Handle<NameDictionary> dict(proxy->property_dictionary());
6912 PropertyDetails details(kData, DONT_ENUM, 0, PropertyCellType::kNoCell);
6913 Handle<NameDictionary> result =
6914 NameDictionary::Add(dict, private_name, value, details);
6915 if (!dict.is_identical_to(result)) proxy->set_properties(*result);
6916 return Just(true);
6917 }
6918
6919
6920 // static
GetOwnPropertyDescriptor(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> key,PropertyDescriptor * desc)6921 Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate,
6922 Handle<JSReceiver> object,
6923 Handle<Object> key,
6924 PropertyDescriptor* desc) {
6925 bool success = false;
6926 DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
6927 LookupIterator it = LookupIterator::PropertyOrElement(
6928 isolate, object, key, &success, LookupIterator::OWN);
6929 DCHECK(success); // ...so creating a LookupIterator can't fail.
6930 return GetOwnPropertyDescriptor(&it, desc);
6931 }
6932
6933 namespace {
6934
GetPropertyDescriptorWithInterceptor(LookupIterator * it,PropertyDescriptor * desc)6935 Maybe<bool> GetPropertyDescriptorWithInterceptor(LookupIterator* it,
6936 PropertyDescriptor* desc) {
6937 bool has_access = true;
6938 if (it->state() == LookupIterator::ACCESS_CHECK) {
6939 has_access = it->HasAccess() || JSObject::AllCanRead(it);
6940 it->Next();
6941 }
6942
6943 if (has_access && it->state() == LookupIterator::INTERCEPTOR) {
6944 Isolate* isolate = it->isolate();
6945 Handle<InterceptorInfo> interceptor = it->GetInterceptor();
6946 if (!interceptor->descriptor()->IsUndefined(isolate)) {
6947 Handle<Object> result;
6948 Handle<JSObject> holder = it->GetHolder<JSObject>();
6949
6950 Handle<Object> receiver = it->GetReceiver();
6951 if (!receiver->IsJSReceiver()) {
6952 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
6953 isolate, receiver, Object::ConvertReceiver(isolate, receiver),
6954 Nothing<bool>());
6955 }
6956
6957 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
6958 *holder, Object::DONT_THROW);
6959 if (it->IsElement()) {
6960 uint32_t index = it->index();
6961 v8::IndexedPropertyDescriptorCallback descriptorCallback =
6962 v8::ToCData<v8::IndexedPropertyDescriptorCallback>(
6963 interceptor->descriptor());
6964
6965 result = args.Call(descriptorCallback, index);
6966 } else {
6967 Handle<Name> name = it->name();
6968 DCHECK(!name->IsPrivate());
6969 v8::GenericNamedPropertyDescriptorCallback descriptorCallback =
6970 v8::ToCData<v8::GenericNamedPropertyDescriptorCallback>(
6971 interceptor->descriptor());
6972 result = args.Call(descriptorCallback, name);
6973 }
6974 if (!result.is_null()) {
6975 // Request successfully intercepted, try to set the property
6976 // descriptor.
6977 Utils::ApiCheck(
6978 PropertyDescriptor::ToPropertyDescriptor(isolate, result, desc),
6979 it->IsElement() ? "v8::IndexedPropertyDescriptorCallback"
6980 : "v8::NamedPropertyDescriptorCallback",
6981 "Invalid property descriptor.");
6982
6983 return Just(true);
6984 }
6985 }
6986 }
6987 it->Restart();
6988 return Just(false);
6989 }
6990 } // namespace
6991
6992 // ES6 9.1.5.1
6993 // Returns true on success, false if the property didn't exist, nothing if
6994 // an exception was thrown.
6995 // static
GetOwnPropertyDescriptor(LookupIterator * it,PropertyDescriptor * desc)6996 Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it,
6997 PropertyDescriptor* desc) {
6998 Isolate* isolate = it->isolate();
6999 // "Virtual" dispatch.
7000 if (it->IsFound() && it->GetHolder<JSReceiver>()->IsJSProxy()) {
7001 return JSProxy::GetOwnPropertyDescriptor(isolate, it->GetHolder<JSProxy>(),
7002 it->GetName(), desc);
7003 }
7004
7005 Maybe<bool> intercepted = GetPropertyDescriptorWithInterceptor(it, desc);
7006 MAYBE_RETURN(intercepted, Nothing<bool>());
7007 if (intercepted.FromJust()) {
7008 return Just(true);
7009 }
7010
7011 // Request was not intercepted, continue as normal.
7012 // 1. (Assert)
7013 // 2. If O does not have an own property with key P, return undefined.
7014 Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(it);
7015 MAYBE_RETURN(maybe, Nothing<bool>());
7016 PropertyAttributes attrs = maybe.FromJust();
7017 if (attrs == ABSENT) return Just(false);
7018 DCHECK(!isolate->has_pending_exception());
7019
7020 // 3. Let D be a newly created Property Descriptor with no fields.
7021 DCHECK(desc->is_empty());
7022 // 4. Let X be O's own property whose key is P.
7023 // 5. If X is a data property, then
7024 bool is_accessor_pair = it->state() == LookupIterator::ACCESSOR &&
7025 it->GetAccessors()->IsAccessorPair();
7026 if (!is_accessor_pair) {
7027 // 5a. Set D.[[Value]] to the value of X's [[Value]] attribute.
7028 Handle<Object> value;
7029 if (!Object::GetProperty(it).ToHandle(&value)) {
7030 DCHECK(isolate->has_pending_exception());
7031 return Nothing<bool>();
7032 }
7033 desc->set_value(value);
7034 // 5b. Set D.[[Writable]] to the value of X's [[Writable]] attribute
7035 desc->set_writable((attrs & READ_ONLY) == 0);
7036 } else {
7037 // 6. Else X is an accessor property, so
7038 Handle<AccessorPair> accessors =
7039 Handle<AccessorPair>::cast(it->GetAccessors());
7040 // 6a. Set D.[[Get]] to the value of X's [[Get]] attribute.
7041 desc->set_get(AccessorPair::GetComponent(accessors, ACCESSOR_GETTER));
7042 // 6b. Set D.[[Set]] to the value of X's [[Set]] attribute.
7043 desc->set_set(AccessorPair::GetComponent(accessors, ACCESSOR_SETTER));
7044 }
7045
7046 // 7. Set D.[[Enumerable]] to the value of X's [[Enumerable]] attribute.
7047 desc->set_enumerable((attrs & DONT_ENUM) == 0);
7048 // 8. Set D.[[Configurable]] to the value of X's [[Configurable]] attribute.
7049 desc->set_configurable((attrs & DONT_DELETE) == 0);
7050 // 9. Return D.
7051 DCHECK(PropertyDescriptor::IsAccessorDescriptor(desc) !=
7052 PropertyDescriptor::IsDataDescriptor(desc));
7053 return Just(true);
7054 }
7055
7056
7057 // ES6 9.5.5
7058 // static
GetOwnPropertyDescriptor(Isolate * isolate,Handle<JSProxy> proxy,Handle<Name> name,PropertyDescriptor * desc)7059 Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate,
7060 Handle<JSProxy> proxy,
7061 Handle<Name> name,
7062 PropertyDescriptor* desc) {
7063 DCHECK(!name->IsPrivate());
7064 STACK_CHECK(isolate, Nothing<bool>());
7065
7066 Handle<String> trap_name =
7067 isolate->factory()->getOwnPropertyDescriptor_string();
7068 // 1. (Assert)
7069 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
7070 Handle<Object> handler(proxy->handler(), isolate);
7071 // 3. If handler is null, throw a TypeError exception.
7072 // 4. Assert: Type(handler) is Object.
7073 if (proxy->IsRevoked()) {
7074 isolate->Throw(*isolate->factory()->NewTypeError(
7075 MessageTemplate::kProxyRevoked, trap_name));
7076 return Nothing<bool>();
7077 }
7078 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
7079 Handle<JSReceiver> target(proxy->target(), isolate);
7080 // 6. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor").
7081 Handle<Object> trap;
7082 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7083 isolate, trap,
7084 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
7085 Nothing<bool>());
7086 // 7. If trap is undefined, then
7087 if (trap->IsUndefined(isolate)) {
7088 // 7a. Return target.[[GetOwnProperty]](P).
7089 return JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, desc);
7090 }
7091 // 8. Let trapResultObj be ? Call(trap, handler, «target, P»).
7092 Handle<Object> trap_result_obj;
7093 Handle<Object> args[] = {target, name};
7094 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7095 isolate, trap_result_obj,
7096 Execution::Call(isolate, trap, handler, arraysize(args), args),
7097 Nothing<bool>());
7098 // 9. If Type(trapResultObj) is neither Object nor Undefined, throw a
7099 // TypeError exception.
7100 if (!trap_result_obj->IsJSReceiver() &&
7101 !trap_result_obj->IsUndefined(isolate)) {
7102 isolate->Throw(*isolate->factory()->NewTypeError(
7103 MessageTemplate::kProxyGetOwnPropertyDescriptorInvalid, name));
7104 return Nothing<bool>();
7105 }
7106 // 10. Let targetDesc be ? target.[[GetOwnProperty]](P).
7107 PropertyDescriptor target_desc;
7108 Maybe<bool> found =
7109 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
7110 MAYBE_RETURN(found, Nothing<bool>());
7111 // 11. If trapResultObj is undefined, then
7112 if (trap_result_obj->IsUndefined(isolate)) {
7113 // 11a. If targetDesc is undefined, return undefined.
7114 if (!found.FromJust()) return Just(false);
7115 // 11b. If targetDesc.[[Configurable]] is false, throw a TypeError
7116 // exception.
7117 if (!target_desc.configurable()) {
7118 isolate->Throw(*isolate->factory()->NewTypeError(
7119 MessageTemplate::kProxyGetOwnPropertyDescriptorUndefined, name));
7120 return Nothing<bool>();
7121 }
7122 // 11c. Let extensibleTarget be ? IsExtensible(target).
7123 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
7124 MAYBE_RETURN(extensible_target, Nothing<bool>());
7125 // 11d. (Assert)
7126 // 11e. If extensibleTarget is false, throw a TypeError exception.
7127 if (!extensible_target.FromJust()) {
7128 isolate->Throw(*isolate->factory()->NewTypeError(
7129 MessageTemplate::kProxyGetOwnPropertyDescriptorNonExtensible, name));
7130 return Nothing<bool>();
7131 }
7132 // 11f. Return undefined.
7133 return Just(false);
7134 }
7135 // 12. Let extensibleTarget be ? IsExtensible(target).
7136 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
7137 MAYBE_RETURN(extensible_target, Nothing<bool>());
7138 // 13. Let resultDesc be ? ToPropertyDescriptor(trapResultObj).
7139 if (!PropertyDescriptor::ToPropertyDescriptor(isolate, trap_result_obj,
7140 desc)) {
7141 DCHECK(isolate->has_pending_exception());
7142 return Nothing<bool>();
7143 }
7144 // 14. Call CompletePropertyDescriptor(resultDesc).
7145 PropertyDescriptor::CompletePropertyDescriptor(isolate, desc);
7146 // 15. Let valid be IsCompatiblePropertyDescriptor (extensibleTarget,
7147 // resultDesc, targetDesc).
7148 Maybe<bool> valid =
7149 IsCompatiblePropertyDescriptor(isolate, extensible_target.FromJust(),
7150 desc, &target_desc, name, DONT_THROW);
7151 MAYBE_RETURN(valid, Nothing<bool>());
7152 // 16. If valid is false, throw a TypeError exception.
7153 if (!valid.FromJust()) {
7154 isolate->Throw(*isolate->factory()->NewTypeError(
7155 MessageTemplate::kProxyGetOwnPropertyDescriptorIncompatible, name));
7156 return Nothing<bool>();
7157 }
7158 // 17. If resultDesc.[[Configurable]] is false, then
7159 if (!desc->configurable()) {
7160 // 17a. If targetDesc is undefined or targetDesc.[[Configurable]] is true:
7161 if (target_desc.is_empty() || target_desc.configurable()) {
7162 // 17a i. Throw a TypeError exception.
7163 isolate->Throw(*isolate->factory()->NewTypeError(
7164 MessageTemplate::kProxyGetOwnPropertyDescriptorNonConfigurable,
7165 name));
7166 return Nothing<bool>();
7167 }
7168 }
7169 // 18. Return resultDesc.
7170 return Just(true);
7171 }
7172
7173
ReferencesObjectFromElements(FixedArray * elements,ElementsKind kind,Object * object)7174 bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
7175 ElementsKind kind,
7176 Object* object) {
7177 Isolate* isolate = elements->GetIsolate();
7178 if (IsFastObjectElementsKind(kind) || kind == FAST_STRING_WRAPPER_ELEMENTS) {
7179 int length = IsJSArray()
7180 ? Smi::cast(JSArray::cast(this)->length())->value()
7181 : elements->length();
7182 for (int i = 0; i < length; ++i) {
7183 Object* element = elements->get(i);
7184 if (!element->IsTheHole(isolate) && element == object) return true;
7185 }
7186 } else {
7187 DCHECK(kind == DICTIONARY_ELEMENTS || kind == SLOW_STRING_WRAPPER_ELEMENTS);
7188 Object* key =
7189 SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
7190 if (!key->IsUndefined(isolate)) return true;
7191 }
7192 return false;
7193 }
7194
7195
7196 // Check whether this object references another object.
ReferencesObject(Object * obj)7197 bool JSObject::ReferencesObject(Object* obj) {
7198 Map* map_of_this = map();
7199 Heap* heap = GetHeap();
7200 DisallowHeapAllocation no_allocation;
7201
7202 // Is the object the constructor for this object?
7203 if (map_of_this->GetConstructor() == obj) {
7204 return true;
7205 }
7206
7207 // Is the object the prototype for this object?
7208 if (map_of_this->prototype() == obj) {
7209 return true;
7210 }
7211
7212 // Check if the object is among the named properties.
7213 Object* key = SlowReverseLookup(obj);
7214 if (!key->IsUndefined(heap->isolate())) {
7215 return true;
7216 }
7217
7218 // Check if the object is among the indexed properties.
7219 ElementsKind kind = GetElementsKind();
7220 switch (kind) {
7221 // Raw pixels and external arrays do not reference other
7222 // objects.
7223 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
7224 case TYPE##_ELEMENTS: \
7225 break;
7226
7227 TYPED_ARRAYS(TYPED_ARRAY_CASE)
7228 #undef TYPED_ARRAY_CASE
7229
7230 case FAST_DOUBLE_ELEMENTS:
7231 case FAST_HOLEY_DOUBLE_ELEMENTS:
7232 break;
7233 case FAST_SMI_ELEMENTS:
7234 case FAST_HOLEY_SMI_ELEMENTS:
7235 break;
7236 case FAST_ELEMENTS:
7237 case FAST_HOLEY_ELEMENTS:
7238 case DICTIONARY_ELEMENTS:
7239 case FAST_STRING_WRAPPER_ELEMENTS:
7240 case SLOW_STRING_WRAPPER_ELEMENTS: {
7241 FixedArray* elements = FixedArray::cast(this->elements());
7242 if (ReferencesObjectFromElements(elements, kind, obj)) return true;
7243 break;
7244 }
7245 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
7246 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
7247 FixedArray* parameter_map = FixedArray::cast(elements());
7248 // Check the mapped parameters.
7249 int length = parameter_map->length();
7250 for (int i = 2; i < length; ++i) {
7251 Object* value = parameter_map->get(i);
7252 if (!value->IsTheHole(heap->isolate()) && value == obj) return true;
7253 }
7254 // Check the arguments.
7255 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
7256 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS :
7257 FAST_HOLEY_ELEMENTS;
7258 if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
7259 break;
7260 }
7261 case NO_ELEMENTS:
7262 break;
7263 }
7264
7265 // For functions check the context.
7266 if (IsJSFunction()) {
7267 // Get the constructor function for arguments array.
7268 Map* arguments_map =
7269 heap->isolate()->context()->native_context()->sloppy_arguments_map();
7270 JSFunction* arguments_function =
7271 JSFunction::cast(arguments_map->GetConstructor());
7272
7273 // Get the context and don't check if it is the native context.
7274 JSFunction* f = JSFunction::cast(this);
7275 Context* context = f->context();
7276 if (context->IsNativeContext()) {
7277 return false;
7278 }
7279
7280 // Check the non-special context slots.
7281 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
7282 // Only check JS objects.
7283 if (context->get(i)->IsJSObject()) {
7284 JSObject* ctxobj = JSObject::cast(context->get(i));
7285 // If it is an arguments array check the content.
7286 if (ctxobj->map()->GetConstructor() == arguments_function) {
7287 if (ctxobj->ReferencesObject(obj)) {
7288 return true;
7289 }
7290 } else if (ctxobj == obj) {
7291 return true;
7292 }
7293 }
7294 }
7295
7296 // Check the context extension (if any) if it can have references.
7297 if (context->has_extension() && !context->IsCatchContext()) {
7298 // With harmony scoping, a JSFunction may have a script context.
7299 // TODO(mvstanton): walk into the ScopeInfo.
7300 if (context->IsScriptContext()) {
7301 return false;
7302 }
7303
7304 return context->extension_object()->ReferencesObject(obj);
7305 }
7306 }
7307
7308 // No references to object.
7309 return false;
7310 }
7311
7312
SetIntegrityLevel(Handle<JSReceiver> receiver,IntegrityLevel level,ShouldThrow should_throw)7313 Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver,
7314 IntegrityLevel level,
7315 ShouldThrow should_throw) {
7316 DCHECK(level == SEALED || level == FROZEN);
7317
7318 if (receiver->IsJSObject()) {
7319 Handle<JSObject> object = Handle<JSObject>::cast(receiver);
7320 if (!object->HasSloppyArgumentsElements()) { // Fast path.
7321 if (level == SEALED) {
7322 return JSObject::PreventExtensionsWithTransition<SEALED>(object,
7323 should_throw);
7324 } else {
7325 return JSObject::PreventExtensionsWithTransition<FROZEN>(object,
7326 should_throw);
7327 }
7328 }
7329 }
7330
7331 Isolate* isolate = receiver->GetIsolate();
7332
7333 MAYBE_RETURN(JSReceiver::PreventExtensions(receiver, should_throw),
7334 Nothing<bool>());
7335
7336 Handle<FixedArray> keys;
7337 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7338 isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>());
7339
7340 PropertyDescriptor no_conf;
7341 no_conf.set_configurable(false);
7342
7343 PropertyDescriptor no_conf_no_write;
7344 no_conf_no_write.set_configurable(false);
7345 no_conf_no_write.set_writable(false);
7346
7347 if (level == SEALED) {
7348 for (int i = 0; i < keys->length(); ++i) {
7349 Handle<Object> key(keys->get(i), isolate);
7350 MAYBE_RETURN(
7351 DefineOwnProperty(isolate, receiver, key, &no_conf, THROW_ON_ERROR),
7352 Nothing<bool>());
7353 }
7354 return Just(true);
7355 }
7356
7357 for (int i = 0; i < keys->length(); ++i) {
7358 Handle<Object> key(keys->get(i), isolate);
7359 PropertyDescriptor current_desc;
7360 Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
7361 isolate, receiver, key, ¤t_desc);
7362 MAYBE_RETURN(owned, Nothing<bool>());
7363 if (owned.FromJust()) {
7364 PropertyDescriptor desc =
7365 PropertyDescriptor::IsAccessorDescriptor(¤t_desc)
7366 ? no_conf
7367 : no_conf_no_write;
7368 MAYBE_RETURN(
7369 DefineOwnProperty(isolate, receiver, key, &desc, THROW_ON_ERROR),
7370 Nothing<bool>());
7371 }
7372 }
7373 return Just(true);
7374 }
7375
7376
TestIntegrityLevel(Handle<JSReceiver> object,IntegrityLevel level)7377 Maybe<bool> JSReceiver::TestIntegrityLevel(Handle<JSReceiver> object,
7378 IntegrityLevel level) {
7379 DCHECK(level == SEALED || level == FROZEN);
7380 Isolate* isolate = object->GetIsolate();
7381
7382 Maybe<bool> extensible = JSReceiver::IsExtensible(object);
7383 MAYBE_RETURN(extensible, Nothing<bool>());
7384 if (extensible.FromJust()) return Just(false);
7385
7386 Handle<FixedArray> keys;
7387 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7388 isolate, keys, JSReceiver::OwnPropertyKeys(object), Nothing<bool>());
7389
7390 for (int i = 0; i < keys->length(); ++i) {
7391 Handle<Object> key(keys->get(i), isolate);
7392 PropertyDescriptor current_desc;
7393 Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
7394 isolate, object, key, ¤t_desc);
7395 MAYBE_RETURN(owned, Nothing<bool>());
7396 if (owned.FromJust()) {
7397 if (current_desc.configurable()) return Just(false);
7398 if (level == FROZEN &&
7399 PropertyDescriptor::IsDataDescriptor(¤t_desc) &&
7400 current_desc.writable()) {
7401 return Just(false);
7402 }
7403 }
7404 }
7405 return Just(true);
7406 }
7407
7408
PreventExtensions(Handle<JSReceiver> object,ShouldThrow should_throw)7409 Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object,
7410 ShouldThrow should_throw) {
7411 if (object->IsJSProxy()) {
7412 return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object),
7413 should_throw);
7414 }
7415 DCHECK(object->IsJSObject());
7416 return JSObject::PreventExtensions(Handle<JSObject>::cast(object),
7417 should_throw);
7418 }
7419
7420
PreventExtensions(Handle<JSProxy> proxy,ShouldThrow should_throw)7421 Maybe<bool> JSProxy::PreventExtensions(Handle<JSProxy> proxy,
7422 ShouldThrow should_throw) {
7423 Isolate* isolate = proxy->GetIsolate();
7424 STACK_CHECK(isolate, Nothing<bool>());
7425 Factory* factory = isolate->factory();
7426 Handle<String> trap_name = factory->preventExtensions_string();
7427
7428 if (proxy->IsRevoked()) {
7429 isolate->Throw(
7430 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
7431 return Nothing<bool>();
7432 }
7433 Handle<JSReceiver> target(proxy->target(), isolate);
7434 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
7435
7436 Handle<Object> trap;
7437 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7438 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
7439 if (trap->IsUndefined(isolate)) {
7440 return JSReceiver::PreventExtensions(target, should_throw);
7441 }
7442
7443 Handle<Object> trap_result;
7444 Handle<Object> args[] = {target};
7445 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7446 isolate, trap_result,
7447 Execution::Call(isolate, trap, handler, arraysize(args), args),
7448 Nothing<bool>());
7449 if (!trap_result->BooleanValue()) {
7450 RETURN_FAILURE(
7451 isolate, should_throw,
7452 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
7453 }
7454
7455 // Enforce the invariant.
7456 Maybe<bool> target_result = JSReceiver::IsExtensible(target);
7457 MAYBE_RETURN(target_result, Nothing<bool>());
7458 if (target_result.FromJust()) {
7459 isolate->Throw(*factory->NewTypeError(
7460 MessageTemplate::kProxyPreventExtensionsExtensible));
7461 return Nothing<bool>();
7462 }
7463 return Just(true);
7464 }
7465
7466
PreventExtensions(Handle<JSObject> object,ShouldThrow should_throw)7467 Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object,
7468 ShouldThrow should_throw) {
7469 Isolate* isolate = object->GetIsolate();
7470
7471 if (!object->HasSloppyArgumentsElements()) {
7472 return PreventExtensionsWithTransition<NONE>(object, should_throw);
7473 }
7474
7475 if (object->IsAccessCheckNeeded() &&
7476 !isolate->MayAccess(handle(isolate->context()), object)) {
7477 isolate->ReportFailedAccessCheck(object);
7478 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
7479 RETURN_FAILURE(isolate, should_throw,
7480 NewTypeError(MessageTemplate::kNoAccess));
7481 }
7482
7483 if (!object->map()->is_extensible()) return Just(true);
7484
7485 if (object->IsJSGlobalProxy()) {
7486 PrototypeIterator iter(isolate, object);
7487 if (iter.IsAtEnd()) return Just(true);
7488 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
7489 return PreventExtensions(PrototypeIterator::GetCurrent<JSObject>(iter),
7490 should_throw);
7491 }
7492
7493 if (!object->HasFixedTypedArrayElements()) {
7494 // If there are fast elements we normalize.
7495 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
7496 DCHECK(object->HasDictionaryElements() ||
7497 object->HasSlowArgumentsElements());
7498
7499 // Make sure that we never go back to fast case.
7500 object->RequireSlowElements(*dictionary);
7501 }
7502
7503 // Do a map transition, other objects with this map may still
7504 // be extensible.
7505 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
7506 Handle<Map> new_map = Map::Copy(handle(object->map()), "PreventExtensions");
7507
7508 new_map->set_is_extensible(false);
7509 JSObject::MigrateToMap(object, new_map);
7510 DCHECK(!object->map()->is_extensible());
7511
7512 return Just(true);
7513 }
7514
7515
IsExtensible(Handle<JSReceiver> object)7516 Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) {
7517 if (object->IsJSProxy()) {
7518 return JSProxy::IsExtensible(Handle<JSProxy>::cast(object));
7519 }
7520 return Just(JSObject::IsExtensible(Handle<JSObject>::cast(object)));
7521 }
7522
7523
IsExtensible(Handle<JSProxy> proxy)7524 Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) {
7525 Isolate* isolate = proxy->GetIsolate();
7526 STACK_CHECK(isolate, Nothing<bool>());
7527 Factory* factory = isolate->factory();
7528 Handle<String> trap_name = factory->isExtensible_string();
7529
7530 if (proxy->IsRevoked()) {
7531 isolate->Throw(
7532 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
7533 return Nothing<bool>();
7534 }
7535 Handle<JSReceiver> target(proxy->target(), isolate);
7536 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
7537
7538 Handle<Object> trap;
7539 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7540 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
7541 if (trap->IsUndefined(isolate)) {
7542 return JSReceiver::IsExtensible(target);
7543 }
7544
7545 Handle<Object> trap_result;
7546 Handle<Object> args[] = {target};
7547 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
7548 isolate, trap_result,
7549 Execution::Call(isolate, trap, handler, arraysize(args), args),
7550 Nothing<bool>());
7551
7552 // Enforce the invariant.
7553 Maybe<bool> target_result = JSReceiver::IsExtensible(target);
7554 MAYBE_RETURN(target_result, Nothing<bool>());
7555 if (target_result.FromJust() != trap_result->BooleanValue()) {
7556 isolate->Throw(
7557 *factory->NewTypeError(MessageTemplate::kProxyIsExtensibleInconsistent,
7558 factory->ToBoolean(target_result.FromJust())));
7559 return Nothing<bool>();
7560 }
7561 return target_result;
7562 }
7563
7564
IsExtensible(Handle<JSObject> object)7565 bool JSObject::IsExtensible(Handle<JSObject> object) {
7566 Isolate* isolate = object->GetIsolate();
7567 if (object->IsAccessCheckNeeded() &&
7568 !isolate->MayAccess(handle(isolate->context()), object)) {
7569 return true;
7570 }
7571 if (object->IsJSGlobalProxy()) {
7572 PrototypeIterator iter(isolate, *object);
7573 if (iter.IsAtEnd()) return false;
7574 DCHECK(iter.GetCurrent()->IsJSGlobalObject());
7575 return iter.GetCurrent<JSObject>()->map()->is_extensible();
7576 }
7577 return object->map()->is_extensible();
7578 }
7579
7580 namespace {
7581
7582 template <typename Dictionary>
DictionaryDetailsAtPut(Isolate * isolate,Handle<Dictionary> dictionary,int entry,PropertyDetails details)7583 void DictionaryDetailsAtPut(Isolate* isolate, Handle<Dictionary> dictionary,
7584 int entry, PropertyDetails details) {
7585 dictionary->DetailsAtPut(entry, details);
7586 }
7587
7588 template <>
DictionaryDetailsAtPut(Isolate * isolate,Handle<GlobalDictionary> dictionary,int entry,PropertyDetails details)7589 void DictionaryDetailsAtPut<GlobalDictionary>(
7590 Isolate* isolate, Handle<GlobalDictionary> dictionary, int entry,
7591 PropertyDetails details) {
7592 Object* value = dictionary->ValueAt(entry);
7593 DCHECK(value->IsPropertyCell());
7594 value = PropertyCell::cast(value)->value();
7595 if (value->IsTheHole(isolate)) return;
7596 PropertyCell::PrepareForValue(dictionary, entry, handle(value, isolate),
7597 details);
7598 }
7599
7600 template <typename Dictionary>
ApplyAttributesToDictionary(Isolate * isolate,Handle<Dictionary> dictionary,const PropertyAttributes attributes)7601 void ApplyAttributesToDictionary(Isolate* isolate,
7602 Handle<Dictionary> dictionary,
7603 const PropertyAttributes attributes) {
7604 int capacity = dictionary->Capacity();
7605 for (int i = 0; i < capacity; i++) {
7606 Object* k = dictionary->KeyAt(i);
7607 if (dictionary->IsKey(isolate, k) &&
7608 !(k->IsSymbol() && Symbol::cast(k)->is_private())) {
7609 PropertyDetails details = dictionary->DetailsAt(i);
7610 int attrs = attributes;
7611 // READ_ONLY is an invalid attribute for JS setters/getters.
7612 if ((attributes & READ_ONLY) && details.kind() == kAccessor) {
7613 Object* v = dictionary->ValueAt(i);
7614 if (v->IsPropertyCell()) v = PropertyCell::cast(v)->value();
7615 if (v->IsAccessorPair()) attrs &= ~READ_ONLY;
7616 }
7617 details = details.CopyAddAttributes(
7618 static_cast<PropertyAttributes>(attrs));
7619 DictionaryDetailsAtPut<Dictionary>(isolate, dictionary, i, details);
7620 }
7621 }
7622 }
7623
7624 } // namespace
7625
7626 template <PropertyAttributes attrs>
PreventExtensionsWithTransition(Handle<JSObject> object,ShouldThrow should_throw)7627 Maybe<bool> JSObject::PreventExtensionsWithTransition(
7628 Handle<JSObject> object, ShouldThrow should_throw) {
7629 STATIC_ASSERT(attrs == NONE || attrs == SEALED || attrs == FROZEN);
7630
7631 // Sealing/freezing sloppy arguments should be handled elsewhere.
7632 DCHECK(!object->HasSloppyArgumentsElements());
7633
7634 Isolate* isolate = object->GetIsolate();
7635 if (object->IsAccessCheckNeeded() &&
7636 !isolate->MayAccess(handle(isolate->context()), object)) {
7637 isolate->ReportFailedAccessCheck(object);
7638 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
7639 RETURN_FAILURE(isolate, should_throw,
7640 NewTypeError(MessageTemplate::kNoAccess));
7641 }
7642
7643 if (attrs == NONE && !object->map()->is_extensible()) return Just(true);
7644
7645 if (object->IsJSGlobalProxy()) {
7646 PrototypeIterator iter(isolate, object);
7647 if (iter.IsAtEnd()) return Just(true);
7648 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
7649 return PreventExtensionsWithTransition<attrs>(
7650 PrototypeIterator::GetCurrent<JSObject>(iter), should_throw);
7651 }
7652
7653 Handle<SeededNumberDictionary> new_element_dictionary;
7654 if (!object->HasFixedTypedArrayElements() &&
7655 !object->HasDictionaryElements() &&
7656 !object->HasSlowStringWrapperElements()) {
7657 int length =
7658 object->IsJSArray()
7659 ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
7660 : object->elements()->length();
7661 new_element_dictionary =
7662 length == 0 ? isolate->factory()->empty_slow_element_dictionary()
7663 : object->GetElementsAccessor()->Normalize(object);
7664 }
7665
7666 Handle<Symbol> transition_marker;
7667 if (attrs == NONE) {
7668 transition_marker = isolate->factory()->nonextensible_symbol();
7669 } else if (attrs == SEALED) {
7670 transition_marker = isolate->factory()->sealed_symbol();
7671 } else {
7672 DCHECK(attrs == FROZEN);
7673 transition_marker = isolate->factory()->frozen_symbol();
7674 }
7675
7676 Handle<Map> old_map(object->map(), isolate);
7677 Map* transition =
7678 TransitionArray::SearchSpecial(*old_map, *transition_marker);
7679 if (transition != NULL) {
7680 Handle<Map> transition_map(transition, isolate);
7681 DCHECK(transition_map->has_dictionary_elements() ||
7682 transition_map->has_fixed_typed_array_elements() ||
7683 transition_map->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
7684 DCHECK(!transition_map->is_extensible());
7685 JSObject::MigrateToMap(object, transition_map);
7686 } else if (TransitionArray::CanHaveMoreTransitions(old_map)) {
7687 // Create a new descriptor array with the appropriate property attributes
7688 Handle<Map> new_map = Map::CopyForPreventExtensions(
7689 old_map, attrs, transition_marker, "CopyForPreventExtensions");
7690 JSObject::MigrateToMap(object, new_map);
7691 } else {
7692 DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map());
7693 // Slow path: need to normalize properties for safety
7694 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0,
7695 "SlowPreventExtensions");
7696
7697 // Create a new map, since other objects with this map may be extensible.
7698 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
7699 Handle<Map> new_map =
7700 Map::Copy(handle(object->map()), "SlowCopyForPreventExtensions");
7701 new_map->set_is_extensible(false);
7702 if (!new_element_dictionary.is_null()) {
7703 ElementsKind new_kind =
7704 IsStringWrapperElementsKind(old_map->elements_kind())
7705 ? SLOW_STRING_WRAPPER_ELEMENTS
7706 : DICTIONARY_ELEMENTS;
7707 new_map->set_elements_kind(new_kind);
7708 }
7709 JSObject::MigrateToMap(object, new_map);
7710
7711 if (attrs != NONE) {
7712 if (object->IsJSGlobalObject()) {
7713 Handle<GlobalDictionary> dictionary(object->global_dictionary(),
7714 isolate);
7715 ApplyAttributesToDictionary(isolate, dictionary, attrs);
7716 } else {
7717 Handle<NameDictionary> dictionary(object->property_dictionary(),
7718 isolate);
7719 ApplyAttributesToDictionary(isolate, dictionary, attrs);
7720 }
7721 }
7722 }
7723
7724 // Both seal and preventExtensions always go through without modifications to
7725 // typed array elements. Freeze works only if there are no actual elements.
7726 if (object->HasFixedTypedArrayElements()) {
7727 if (attrs == FROZEN &&
7728 JSArrayBufferView::cast(*object)->byte_length()->Number() > 0) {
7729 isolate->Throw(*isolate->factory()->NewTypeError(
7730 MessageTemplate::kCannotFreezeArrayBufferView));
7731 return Nothing<bool>();
7732 }
7733 return Just(true);
7734 }
7735
7736 DCHECK(object->map()->has_dictionary_elements() ||
7737 object->map()->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
7738 if (!new_element_dictionary.is_null()) {
7739 object->set_elements(*new_element_dictionary);
7740 }
7741
7742 if (object->elements() != isolate->heap()->empty_slow_element_dictionary()) {
7743 Handle<SeededNumberDictionary> dictionary(object->element_dictionary(),
7744 isolate);
7745 // Make sure we never go back to the fast case
7746 object->RequireSlowElements(*dictionary);
7747 if (attrs != NONE) {
7748 ApplyAttributesToDictionary(isolate, dictionary, attrs);
7749 }
7750 }
7751
7752 return Just(true);
7753 }
7754
7755
FastPropertyAt(Handle<JSObject> object,Representation representation,FieldIndex index)7756 Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object,
7757 Representation representation,
7758 FieldIndex index) {
7759 Isolate* isolate = object->GetIsolate();
7760 if (object->IsUnboxedDoubleField(index)) {
7761 double value = object->RawFastDoublePropertyAt(index);
7762 return isolate->factory()->NewHeapNumber(value);
7763 }
7764 Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate);
7765 return Object::WrapForRead(isolate, raw_value, representation);
7766 }
7767
7768 template <class ContextObject>
7769 class JSObjectWalkVisitor {
7770 public:
JSObjectWalkVisitor(ContextObject * site_context,bool copying,JSObject::DeepCopyHints hints)7771 JSObjectWalkVisitor(ContextObject* site_context, bool copying,
7772 JSObject::DeepCopyHints hints)
7773 : site_context_(site_context),
7774 copying_(copying),
7775 hints_(hints) {}
7776
7777 MUST_USE_RESULT MaybeHandle<JSObject> StructureWalk(Handle<JSObject> object);
7778
7779 protected:
VisitElementOrProperty(Handle<JSObject> object,Handle<JSObject> value)7780 MUST_USE_RESULT inline MaybeHandle<JSObject> VisitElementOrProperty(
7781 Handle<JSObject> object,
7782 Handle<JSObject> value) {
7783 Handle<AllocationSite> current_site = site_context()->EnterNewScope();
7784 MaybeHandle<JSObject> copy_of_value = StructureWalk(value);
7785 site_context()->ExitScope(current_site, value);
7786 return copy_of_value;
7787 }
7788
site_context()7789 inline ContextObject* site_context() { return site_context_; }
isolate()7790 inline Isolate* isolate() { return site_context()->isolate(); }
7791
copying() const7792 inline bool copying() const { return copying_; }
7793
7794 private:
7795 ContextObject* site_context_;
7796 const bool copying_;
7797 const JSObject::DeepCopyHints hints_;
7798 };
7799
7800 template <class ContextObject>
StructureWalk(Handle<JSObject> object)7801 MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
7802 Handle<JSObject> object) {
7803 Isolate* isolate = this->isolate();
7804 bool copying = this->copying();
7805 bool shallow = hints_ == JSObject::kObjectIsShallow;
7806
7807 if (!shallow) {
7808 StackLimitCheck check(isolate);
7809
7810 if (check.HasOverflowed()) {
7811 isolate->StackOverflow();
7812 return MaybeHandle<JSObject>();
7813 }
7814 }
7815
7816 if (object->map()->is_deprecated()) {
7817 JSObject::MigrateInstance(object);
7818 }
7819
7820 Handle<JSObject> copy;
7821 if (copying) {
7822 // JSFunction objects are not allowed to be in normal boilerplates at all.
7823 DCHECK(!object->IsJSFunction());
7824 Handle<AllocationSite> site_to_pass;
7825 if (site_context()->ShouldCreateMemento(object)) {
7826 site_to_pass = site_context()->current();
7827 }
7828 copy = isolate->factory()->CopyJSObjectWithAllocationSite(
7829 object, site_to_pass);
7830 } else {
7831 copy = object;
7832 }
7833
7834 DCHECK(copying || copy.is_identical_to(object));
7835
7836 ElementsKind kind = copy->GetElementsKind();
7837 if (copying && IsFastSmiOrObjectElementsKind(kind) &&
7838 FixedArray::cast(copy->elements())->map() ==
7839 isolate->heap()->fixed_cow_array_map()) {
7840 isolate->counters()->cow_arrays_created_runtime()->Increment();
7841 }
7842
7843 if (!shallow) {
7844 HandleScope scope(isolate);
7845
7846 // Deep copy own properties.
7847 if (copy->HasFastProperties()) {
7848 Handle<DescriptorArray> descriptors(copy->map()->instance_descriptors());
7849 int limit = copy->map()->NumberOfOwnDescriptors();
7850 for (int i = 0; i < limit; i++) {
7851 PropertyDetails details = descriptors->GetDetails(i);
7852 if (details.location() != kField) continue;
7853 DCHECK_EQ(kData, details.kind());
7854 FieldIndex index = FieldIndex::ForDescriptor(copy->map(), i);
7855 if (object->IsUnboxedDoubleField(index)) {
7856 if (copying) {
7857 // Ensure that all bits of the double value are preserved.
7858 uint64_t value = object->RawFastDoublePropertyAsBitsAt(index);
7859 copy->RawFastDoublePropertyAsBitsAtPut(index, value);
7860 }
7861 } else {
7862 Handle<Object> value(object->RawFastPropertyAt(index), isolate);
7863 if (value->IsJSObject()) {
7864 ASSIGN_RETURN_ON_EXCEPTION(
7865 isolate, value,
7866 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
7867 JSObject);
7868 if (copying) {
7869 copy->FastPropertyAtPut(index, *value);
7870 }
7871 } else {
7872 if (copying) {
7873 Representation representation = details.representation();
7874 value = Object::NewStorageFor(isolate, value, representation);
7875 copy->FastPropertyAtPut(index, *value);
7876 }
7877 }
7878 }
7879 }
7880 } else {
7881 // Only deep copy fields from the object literal expression.
7882 // In particular, don't try to copy the length attribute of
7883 // an array.
7884 PropertyFilter filter = static_cast<PropertyFilter>(
7885 ONLY_WRITABLE | ONLY_ENUMERABLE | ONLY_CONFIGURABLE);
7886 KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly, filter);
7887 accumulator.CollectOwnPropertyNames(copy, copy);
7888 Handle<FixedArray> names = accumulator.GetKeys();
7889 for (int i = 0; i < names->length(); i++) {
7890 DCHECK(names->get(i)->IsName());
7891 Handle<Name> name(Name::cast(names->get(i)));
7892 Handle<Object> value =
7893 JSObject::GetProperty(copy, name).ToHandleChecked();
7894 if (value->IsJSObject()) {
7895 Handle<JSObject> result;
7896 ASSIGN_RETURN_ON_EXCEPTION(
7897 isolate, result,
7898 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
7899 JSObject);
7900 if (copying) {
7901 // Creating object copy for literals. No strict mode needed.
7902 JSObject::SetProperty(copy, name, result, SLOPPY).Assert();
7903 }
7904 }
7905 }
7906 }
7907
7908 // Deep copy own elements.
7909 switch (kind) {
7910 case FAST_ELEMENTS:
7911 case FAST_HOLEY_ELEMENTS: {
7912 Handle<FixedArray> elements(FixedArray::cast(copy->elements()));
7913 if (elements->map() == isolate->heap()->fixed_cow_array_map()) {
7914 #ifdef DEBUG
7915 for (int i = 0; i < elements->length(); i++) {
7916 DCHECK(!elements->get(i)->IsJSObject());
7917 }
7918 #endif
7919 } else {
7920 for (int i = 0; i < elements->length(); i++) {
7921 Handle<Object> value(elements->get(i), isolate);
7922 if (value->IsJSObject()) {
7923 Handle<JSObject> result;
7924 ASSIGN_RETURN_ON_EXCEPTION(
7925 isolate, result,
7926 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
7927 JSObject);
7928 if (copying) {
7929 elements->set(i, *result);
7930 }
7931 }
7932 }
7933 }
7934 break;
7935 }
7936 case DICTIONARY_ELEMENTS: {
7937 Handle<SeededNumberDictionary> element_dictionary(
7938 copy->element_dictionary());
7939 int capacity = element_dictionary->Capacity();
7940 for (int i = 0; i < capacity; i++) {
7941 Object* k = element_dictionary->KeyAt(i);
7942 if (element_dictionary->IsKey(isolate, k)) {
7943 Handle<Object> value(element_dictionary->ValueAt(i), isolate);
7944 if (value->IsJSObject()) {
7945 Handle<JSObject> result;
7946 ASSIGN_RETURN_ON_EXCEPTION(
7947 isolate, result,
7948 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
7949 JSObject);
7950 if (copying) {
7951 element_dictionary->ValueAtPut(i, *result);
7952 }
7953 }
7954 }
7955 }
7956 break;
7957 }
7958 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
7959 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
7960 UNIMPLEMENTED();
7961 break;
7962 case FAST_STRING_WRAPPER_ELEMENTS:
7963 case SLOW_STRING_WRAPPER_ELEMENTS:
7964 UNREACHABLE();
7965 break;
7966
7967 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
7968 case TYPE##_ELEMENTS: \
7969
7970 TYPED_ARRAYS(TYPED_ARRAY_CASE)
7971 #undef TYPED_ARRAY_CASE
7972 // Typed elements cannot be created using an object literal.
7973 UNREACHABLE();
7974 break;
7975
7976 case FAST_SMI_ELEMENTS:
7977 case FAST_HOLEY_SMI_ELEMENTS:
7978 case FAST_DOUBLE_ELEMENTS:
7979 case FAST_HOLEY_DOUBLE_ELEMENTS:
7980 case NO_ELEMENTS:
7981 // No contained objects, nothing to do.
7982 break;
7983 }
7984 }
7985
7986 return copy;
7987 }
7988
7989
DeepWalk(Handle<JSObject> object,AllocationSiteCreationContext * site_context)7990 MaybeHandle<JSObject> JSObject::DeepWalk(
7991 Handle<JSObject> object,
7992 AllocationSiteCreationContext* site_context) {
7993 JSObjectWalkVisitor<AllocationSiteCreationContext> v(site_context, false,
7994 kNoHints);
7995 MaybeHandle<JSObject> result = v.StructureWalk(object);
7996 Handle<JSObject> for_assert;
7997 DCHECK(!result.ToHandle(&for_assert) || for_assert.is_identical_to(object));
7998 return result;
7999 }
8000
8001
DeepCopy(Handle<JSObject> object,AllocationSiteUsageContext * site_context,DeepCopyHints hints)8002 MaybeHandle<JSObject> JSObject::DeepCopy(
8003 Handle<JSObject> object,
8004 AllocationSiteUsageContext* site_context,
8005 DeepCopyHints hints) {
8006 JSObjectWalkVisitor<AllocationSiteUsageContext> v(site_context, true, hints);
8007 MaybeHandle<JSObject> copy = v.StructureWalk(object);
8008 Handle<JSObject> for_assert;
8009 DCHECK(!copy.ToHandle(&for_assert) || !for_assert.is_identical_to(object));
8010 return copy;
8011 }
8012
8013 // static
ToPrimitive(Handle<JSReceiver> receiver,ToPrimitiveHint hint)8014 MaybeHandle<Object> JSReceiver::ToPrimitive(Handle<JSReceiver> receiver,
8015 ToPrimitiveHint hint) {
8016 Isolate* const isolate = receiver->GetIsolate();
8017 Handle<Object> exotic_to_prim;
8018 ASSIGN_RETURN_ON_EXCEPTION(
8019 isolate, exotic_to_prim,
8020 GetMethod(receiver, isolate->factory()->to_primitive_symbol()), Object);
8021 if (!exotic_to_prim->IsUndefined(isolate)) {
8022 Handle<Object> hint_string =
8023 isolate->factory()->ToPrimitiveHintString(hint);
8024 Handle<Object> result;
8025 ASSIGN_RETURN_ON_EXCEPTION(
8026 isolate, result,
8027 Execution::Call(isolate, exotic_to_prim, receiver, 1, &hint_string),
8028 Object);
8029 if (result->IsPrimitive()) return result;
8030 THROW_NEW_ERROR(isolate,
8031 NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8032 Object);
8033 }
8034 return OrdinaryToPrimitive(receiver, (hint == ToPrimitiveHint::kString)
8035 ? OrdinaryToPrimitiveHint::kString
8036 : OrdinaryToPrimitiveHint::kNumber);
8037 }
8038
8039
8040 // static
OrdinaryToPrimitive(Handle<JSReceiver> receiver,OrdinaryToPrimitiveHint hint)8041 MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive(
8042 Handle<JSReceiver> receiver, OrdinaryToPrimitiveHint hint) {
8043 Isolate* const isolate = receiver->GetIsolate();
8044 Handle<String> method_names[2];
8045 switch (hint) {
8046 case OrdinaryToPrimitiveHint::kNumber:
8047 method_names[0] = isolate->factory()->valueOf_string();
8048 method_names[1] = isolate->factory()->toString_string();
8049 break;
8050 case OrdinaryToPrimitiveHint::kString:
8051 method_names[0] = isolate->factory()->toString_string();
8052 method_names[1] = isolate->factory()->valueOf_string();
8053 break;
8054 }
8055 for (Handle<String> name : method_names) {
8056 Handle<Object> method;
8057 ASSIGN_RETURN_ON_EXCEPTION(isolate, method,
8058 JSReceiver::GetProperty(receiver, name), Object);
8059 if (method->IsCallable()) {
8060 Handle<Object> result;
8061 ASSIGN_RETURN_ON_EXCEPTION(
8062 isolate, result, Execution::Call(isolate, method, receiver, 0, NULL),
8063 Object);
8064 if (result->IsPrimitive()) return result;
8065 }
8066 }
8067 THROW_NEW_ERROR(isolate,
8068 NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
8069 Object);
8070 }
8071
8072
8073 // TODO(cbruni/jkummerow): Consider moving this into elements.cc.
HasEnumerableElements()8074 bool JSObject::HasEnumerableElements() {
8075 // TODO(cbruni): cleanup
8076 JSObject* object = this;
8077 switch (object->GetElementsKind()) {
8078 case FAST_SMI_ELEMENTS:
8079 case FAST_ELEMENTS:
8080 case FAST_DOUBLE_ELEMENTS: {
8081 int length = object->IsJSArray()
8082 ? Smi::cast(JSArray::cast(object)->length())->value()
8083 : object->elements()->length();
8084 return length > 0;
8085 }
8086 case FAST_HOLEY_SMI_ELEMENTS:
8087 case FAST_HOLEY_ELEMENTS: {
8088 FixedArray* elements = FixedArray::cast(object->elements());
8089 int length = object->IsJSArray()
8090 ? Smi::cast(JSArray::cast(object)->length())->value()
8091 : elements->length();
8092 Isolate* isolate = GetIsolate();
8093 for (int i = 0; i < length; i++) {
8094 if (!elements->is_the_hole(isolate, i)) return true;
8095 }
8096 return false;
8097 }
8098 case FAST_HOLEY_DOUBLE_ELEMENTS: {
8099 int length = object->IsJSArray()
8100 ? Smi::cast(JSArray::cast(object)->length())->value()
8101 : object->elements()->length();
8102 // Zero-length arrays would use the empty FixedArray...
8103 if (length == 0) return false;
8104 // ...so only cast to FixedDoubleArray otherwise.
8105 FixedDoubleArray* elements = FixedDoubleArray::cast(object->elements());
8106 for (int i = 0; i < length; i++) {
8107 if (!elements->is_the_hole(i)) return true;
8108 }
8109 return false;
8110 }
8111 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
8112 case TYPE##_ELEMENTS:
8113
8114 TYPED_ARRAYS(TYPED_ARRAY_CASE)
8115 #undef TYPED_ARRAY_CASE
8116 {
8117 int length = object->elements()->length();
8118 return length > 0;
8119 }
8120 case DICTIONARY_ELEMENTS: {
8121 SeededNumberDictionary* elements =
8122 SeededNumberDictionary::cast(object->elements());
8123 return elements->NumberOfElementsFilterAttributes(ONLY_ENUMERABLE) > 0;
8124 }
8125 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
8126 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
8127 // We're approximating non-empty arguments objects here.
8128 return true;
8129 case FAST_STRING_WRAPPER_ELEMENTS:
8130 case SLOW_STRING_WRAPPER_ELEMENTS:
8131 if (String::cast(JSValue::cast(object)->value())->length() > 0) {
8132 return true;
8133 }
8134 return object->elements()->length() > 0;
8135 case NO_ELEMENTS:
8136 return false;
8137 }
8138 UNREACHABLE();
8139 return true;
8140 }
8141
8142
NumberOfDescribedProperties(DescriptorFlag which,PropertyFilter filter)8143 int Map::NumberOfDescribedProperties(DescriptorFlag which,
8144 PropertyFilter filter) {
8145 int result = 0;
8146 DescriptorArray* descs = instance_descriptors();
8147 int limit = which == ALL_DESCRIPTORS
8148 ? descs->number_of_descriptors()
8149 : NumberOfOwnDescriptors();
8150 for (int i = 0; i < limit; i++) {
8151 if ((descs->GetDetails(i).attributes() & filter) == 0 &&
8152 !descs->GetKey(i)->FilterKey(filter)) {
8153 result++;
8154 }
8155 }
8156 return result;
8157 }
8158
8159
NextFreePropertyIndex()8160 int Map::NextFreePropertyIndex() {
8161 int free_index = 0;
8162 int number_of_own_descriptors = NumberOfOwnDescriptors();
8163 DescriptorArray* descs = instance_descriptors();
8164 for (int i = 0; i < number_of_own_descriptors; i++) {
8165 PropertyDetails details = descs->GetDetails(i);
8166 if (details.location() == kField) {
8167 int candidate = details.field_index() + details.field_width_in_words();
8168 if (candidate > free_index) free_index = candidate;
8169 }
8170 }
8171 return free_index;
8172 }
8173
8174
OnlyHasSimpleProperties()8175 bool Map::OnlyHasSimpleProperties() {
8176 // Wrapped string elements aren't explicitly stored in the elements backing
8177 // store, but are loaded indirectly from the underlying string.
8178 return !IsStringWrapperElementsKind(elements_kind()) &&
8179 !IsSpecialReceiverMap() && !has_hidden_prototype() &&
8180 !is_dictionary_map();
8181 }
8182
FastGetOwnValuesOrEntries(Isolate * isolate,Handle<JSReceiver> receiver,bool get_entries,Handle<FixedArray> * result)8183 MUST_USE_RESULT Maybe<bool> FastGetOwnValuesOrEntries(
8184 Isolate* isolate, Handle<JSReceiver> receiver, bool get_entries,
8185 Handle<FixedArray>* result) {
8186 Handle<Map> map(JSReceiver::cast(*receiver)->map(), isolate);
8187
8188 if (!map->IsJSObjectMap()) return Just(false);
8189 if (!map->OnlyHasSimpleProperties()) return Just(false);
8190
8191 Handle<JSObject> object(JSObject::cast(*receiver));
8192
8193 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
8194 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
8195 int number_of_own_elements =
8196 object->GetElementsAccessor()->GetCapacity(*object, object->elements());
8197 Handle<FixedArray> values_or_entries = isolate->factory()->NewFixedArray(
8198 number_of_own_descriptors + number_of_own_elements);
8199 int count = 0;
8200
8201 if (object->elements() != isolate->heap()->empty_fixed_array()) {
8202 MAYBE_RETURN(object->GetElementsAccessor()->CollectValuesOrEntries(
8203 isolate, object, values_or_entries, get_entries, &count,
8204 ENUMERABLE_STRINGS),
8205 Nothing<bool>());
8206 }
8207
8208 bool stable = object->map() == *map;
8209
8210 for (int index = 0; index < number_of_own_descriptors; index++) {
8211 Handle<Name> next_key(descriptors->GetKey(index), isolate);
8212 if (!next_key->IsString()) continue;
8213 Handle<Object> prop_value;
8214
8215 // Directly decode from the descriptor array if |from| did not change shape.
8216 if (stable) {
8217 PropertyDetails details = descriptors->GetDetails(index);
8218 if (!details.IsEnumerable()) continue;
8219 if (details.kind() == kData) {
8220 if (details.location() == kDescriptor) {
8221 prop_value = handle(descriptors->GetValue(index), isolate);
8222 } else {
8223 Representation representation = details.representation();
8224 FieldIndex field_index = FieldIndex::ForDescriptor(*map, index);
8225 prop_value =
8226 JSObject::FastPropertyAt(object, representation, field_index);
8227 }
8228 } else {
8229 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8230 isolate, prop_value, JSReceiver::GetProperty(object, next_key),
8231 Nothing<bool>());
8232 stable = object->map() == *map;
8233 }
8234 } else {
8235 // If the map did change, do a slower lookup. We are still guaranteed that
8236 // the object has a simple shape, and that the key is a name.
8237 LookupIterator it(object, next_key, LookupIterator::OWN_SKIP_INTERCEPTOR);
8238 if (!it.IsFound()) continue;
8239 DCHECK(it.state() == LookupIterator::DATA ||
8240 it.state() == LookupIterator::ACCESSOR);
8241 if (!it.IsEnumerable()) continue;
8242 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8243 isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
8244 }
8245
8246 if (get_entries) {
8247 prop_value = MakeEntryPair(isolate, next_key, prop_value);
8248 }
8249
8250 values_or_entries->set(count, *prop_value);
8251 count++;
8252 }
8253
8254 if (count < values_or_entries->length()) values_or_entries->Shrink(count);
8255 *result = values_or_entries;
8256 return Just(true);
8257 }
8258
GetOwnValuesOrEntries(Isolate * isolate,Handle<JSReceiver> object,PropertyFilter filter,bool get_entries)8259 MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate,
8260 Handle<JSReceiver> object,
8261 PropertyFilter filter,
8262 bool get_entries) {
8263 Handle<FixedArray> values_or_entries;
8264 if (filter == ENUMERABLE_STRINGS) {
8265 Maybe<bool> fast_values_or_entries = FastGetOwnValuesOrEntries(
8266 isolate, object, get_entries, &values_or_entries);
8267 if (fast_values_or_entries.IsNothing()) return MaybeHandle<FixedArray>();
8268 if (fast_values_or_entries.FromJust()) return values_or_entries;
8269 }
8270
8271 PropertyFilter key_filter =
8272 static_cast<PropertyFilter>(filter & ~ONLY_ENUMERABLE);
8273
8274 Handle<FixedArray> keys;
8275 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8276 isolate, keys,
8277 KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, key_filter,
8278 GetKeysConversion::kConvertToString),
8279 MaybeHandle<FixedArray>());
8280
8281 values_or_entries = isolate->factory()->NewFixedArray(keys->length());
8282 int length = 0;
8283
8284 for (int i = 0; i < keys->length(); ++i) {
8285 Handle<Name> key = Handle<Name>::cast(handle(keys->get(i), isolate));
8286
8287 if (filter & ONLY_ENUMERABLE) {
8288 PropertyDescriptor descriptor;
8289 Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor(
8290 isolate, object, key, &descriptor);
8291 MAYBE_RETURN(did_get_descriptor, MaybeHandle<FixedArray>());
8292 if (!did_get_descriptor.FromJust() || !descriptor.enumerable()) continue;
8293 }
8294
8295 Handle<Object> value;
8296 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
8297 isolate, value, JSReceiver::GetPropertyOrElement(object, key),
8298 MaybeHandle<FixedArray>());
8299
8300 if (get_entries) {
8301 Handle<FixedArray> entry_storage =
8302 isolate->factory()->NewUninitializedFixedArray(2);
8303 entry_storage->set(0, *key);
8304 entry_storage->set(1, *value);
8305 value = isolate->factory()->NewJSArrayWithElements(entry_storage,
8306 FAST_ELEMENTS, 2);
8307 }
8308
8309 values_or_entries->set(length, *value);
8310 length++;
8311 }
8312 if (length < values_or_entries->length()) values_or_entries->Shrink(length);
8313 return values_or_entries;
8314 }
8315
GetOwnValues(Handle<JSReceiver> object,PropertyFilter filter)8316 MaybeHandle<FixedArray> JSReceiver::GetOwnValues(Handle<JSReceiver> object,
8317 PropertyFilter filter) {
8318 return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, false);
8319 }
8320
GetOwnEntries(Handle<JSReceiver> object,PropertyFilter filter)8321 MaybeHandle<FixedArray> JSReceiver::GetOwnEntries(Handle<JSReceiver> object,
8322 PropertyFilter filter) {
8323 return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, true);
8324 }
8325
DictionaryElementsInPrototypeChainOnly()8326 bool Map::DictionaryElementsInPrototypeChainOnly() {
8327 if (IsDictionaryElementsKind(elements_kind())) {
8328 return false;
8329 }
8330
8331 for (PrototypeIterator iter(this); !iter.IsAtEnd(); iter.Advance()) {
8332 // Be conservative, don't walk into proxies.
8333 if (iter.GetCurrent()->IsJSProxy()) return true;
8334 // String wrappers have non-configurable, non-writable elements.
8335 if (iter.GetCurrent()->IsStringWrapper()) return true;
8336 JSObject* current = iter.GetCurrent<JSObject>();
8337
8338 if (current->HasDictionaryElements() &&
8339 current->element_dictionary()->requires_slow_elements()) {
8340 return true;
8341 }
8342
8343 if (current->HasSlowArgumentsElements()) {
8344 FixedArray* parameter_map = FixedArray::cast(current->elements());
8345 Object* arguments = parameter_map->get(1);
8346 if (SeededNumberDictionary::cast(arguments)->requires_slow_elements()) {
8347 return true;
8348 }
8349 }
8350 }
8351
8352 return false;
8353 }
8354
8355
DefineAccessor(Handle<JSObject> object,Handle<Name> name,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)8356 MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
8357 Handle<Name> name,
8358 Handle<Object> getter,
8359 Handle<Object> setter,
8360 PropertyAttributes attributes) {
8361 Isolate* isolate = object->GetIsolate();
8362
8363 LookupIterator it = LookupIterator::PropertyOrElement(
8364 isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
8365 return DefineAccessor(&it, getter, setter, attributes);
8366 }
8367
8368
DefineAccessor(LookupIterator * it,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)8369 MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it,
8370 Handle<Object> getter,
8371 Handle<Object> setter,
8372 PropertyAttributes attributes) {
8373 Isolate* isolate = it->isolate();
8374
8375 it->UpdateProtector();
8376
8377 if (it->state() == LookupIterator::ACCESS_CHECK) {
8378 if (!it->HasAccess()) {
8379 isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
8380 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
8381 return isolate->factory()->undefined_value();
8382 }
8383 it->Next();
8384 }
8385
8386 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
8387 // Ignore accessors on typed arrays.
8388 if (it->IsElement() && object->HasFixedTypedArrayElements()) {
8389 return it->factory()->undefined_value();
8390 }
8391
8392 DCHECK(getter->IsCallable() || getter->IsUndefined(isolate) ||
8393 getter->IsNull(isolate) || getter->IsFunctionTemplateInfo());
8394 DCHECK(setter->IsCallable() || setter->IsUndefined(isolate) ||
8395 setter->IsNull(isolate) || setter->IsFunctionTemplateInfo());
8396 it->TransitionToAccessorProperty(getter, setter, attributes);
8397
8398 return isolate->factory()->undefined_value();
8399 }
8400
8401
SetAccessor(Handle<JSObject> object,Handle<AccessorInfo> info)8402 MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
8403 Handle<AccessorInfo> info) {
8404 Isolate* isolate = object->GetIsolate();
8405 Handle<Name> name(Name::cast(info->name()), isolate);
8406
8407 LookupIterator it = LookupIterator::PropertyOrElement(
8408 isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
8409
8410 // Duplicate ACCESS_CHECK outside of GetPropertyAttributes for the case that
8411 // the FailedAccessCheckCallbackFunction doesn't throw an exception.
8412 //
8413 // TODO(verwaest): Force throw an exception if the callback doesn't, so we can
8414 // remove reliance on default return values.
8415 if (it.state() == LookupIterator::ACCESS_CHECK) {
8416 if (!it.HasAccess()) {
8417 isolate->ReportFailedAccessCheck(object);
8418 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
8419 return it.factory()->undefined_value();
8420 }
8421 it.Next();
8422 }
8423
8424 // Ignore accessors on typed arrays.
8425 if (it.IsElement() && object->HasFixedTypedArrayElements()) {
8426 return it.factory()->undefined_value();
8427 }
8428
8429 CHECK(GetPropertyAttributes(&it).IsJust());
8430
8431 // ES5 forbids turning a property into an accessor if it's not
8432 // configurable. See 8.6.1 (Table 5).
8433 if (it.IsFound() && !it.IsConfigurable()) {
8434 return it.factory()->undefined_value();
8435 }
8436
8437 it.TransitionToAccessorPair(info, info->property_attributes());
8438
8439 return object;
8440 }
8441
SlowReverseLookup(Object * value)8442 Object* JSObject::SlowReverseLookup(Object* value) {
8443 if (HasFastProperties()) {
8444 int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
8445 DescriptorArray* descs = map()->instance_descriptors();
8446 bool value_is_number = value->IsNumber();
8447 for (int i = 0; i < number_of_own_descriptors; i++) {
8448 PropertyDetails details = descs->GetDetails(i);
8449 if (details.location() == kField) {
8450 DCHECK_EQ(kData, details.kind());
8451 FieldIndex field_index = FieldIndex::ForDescriptor(map(), i);
8452 if (IsUnboxedDoubleField(field_index)) {
8453 if (value_is_number) {
8454 double property = RawFastDoublePropertyAt(field_index);
8455 if (property == value->Number()) {
8456 return descs->GetKey(i);
8457 }
8458 }
8459 } else {
8460 Object* property = RawFastPropertyAt(field_index);
8461 if (field_index.is_double()) {
8462 DCHECK(property->IsMutableHeapNumber());
8463 if (value_is_number && property->Number() == value->Number()) {
8464 return descs->GetKey(i);
8465 }
8466 } else if (property == value) {
8467 return descs->GetKey(i);
8468 }
8469 }
8470 } else {
8471 DCHECK_EQ(kDescriptor, details.location());
8472 if (details.kind() == kData) {
8473 if (descs->GetValue(i) == value) {
8474 return descs->GetKey(i);
8475 }
8476 }
8477 }
8478 }
8479 return GetHeap()->undefined_value();
8480 } else if (IsJSGlobalObject()) {
8481 return global_dictionary()->SlowReverseLookup(value);
8482 } else {
8483 return property_dictionary()->SlowReverseLookup(value);
8484 }
8485 }
8486
8487
RawCopy(Handle<Map> map,int instance_size)8488 Handle<Map> Map::RawCopy(Handle<Map> map, int instance_size) {
8489 Isolate* isolate = map->GetIsolate();
8490 Handle<Map> result =
8491 isolate->factory()->NewMap(map->instance_type(), instance_size);
8492 Handle<Object> prototype(map->prototype(), isolate);
8493 Map::SetPrototype(result, prototype);
8494 result->set_constructor_or_backpointer(map->GetConstructor());
8495 result->set_bit_field(map->bit_field());
8496 result->set_bit_field2(map->bit_field2());
8497 int new_bit_field3 = map->bit_field3();
8498 new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true);
8499 new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0);
8500 new_bit_field3 = EnumLengthBits::update(new_bit_field3,
8501 kInvalidEnumCacheSentinel);
8502 new_bit_field3 = Deprecated::update(new_bit_field3, false);
8503 if (!map->is_dictionary_map()) {
8504 new_bit_field3 = IsUnstable::update(new_bit_field3, false);
8505 }
8506 result->set_bit_field3(new_bit_field3);
8507 return result;
8508 }
8509
8510
Normalize(Handle<Map> fast_map,PropertyNormalizationMode mode,const char * reason)8511 Handle<Map> Map::Normalize(Handle<Map> fast_map, PropertyNormalizationMode mode,
8512 const char* reason) {
8513 DCHECK(!fast_map->is_dictionary_map());
8514
8515 Isolate* isolate = fast_map->GetIsolate();
8516 Handle<Object> maybe_cache(isolate->native_context()->normalized_map_cache(),
8517 isolate);
8518 bool use_cache =
8519 !fast_map->is_prototype_map() && !maybe_cache->IsUndefined(isolate);
8520 Handle<NormalizedMapCache> cache;
8521 if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache);
8522
8523 Handle<Map> new_map;
8524 if (use_cache && cache->Get(fast_map, mode).ToHandle(&new_map)) {
8525 #ifdef VERIFY_HEAP
8526 if (FLAG_verify_heap) new_map->DictionaryMapVerify();
8527 #endif
8528 #ifdef ENABLE_SLOW_DCHECKS
8529 if (FLAG_enable_slow_asserts) {
8530 // The cached map should match newly created normalized map bit-by-bit,
8531 // except for the code cache, which can contain some ics which can be
8532 // applied to the shared map, dependent code and weak cell cache.
8533 Handle<Map> fresh = Map::CopyNormalized(fast_map, mode);
8534
8535 if (new_map->is_prototype_map()) {
8536 // For prototype maps, the PrototypeInfo is not copied.
8537 DCHECK(memcmp(fresh->address(), new_map->address(),
8538 kTransitionsOrPrototypeInfoOffset) == 0);
8539 DCHECK(fresh->raw_transitions() == Smi::kZero);
8540 STATIC_ASSERT(kDescriptorsOffset ==
8541 kTransitionsOrPrototypeInfoOffset + kPointerSize);
8542 DCHECK(memcmp(HeapObject::RawField(*fresh, kDescriptorsOffset),
8543 HeapObject::RawField(*new_map, kDescriptorsOffset),
8544 kCodeCacheOffset - kDescriptorsOffset) == 0);
8545 } else {
8546 DCHECK(memcmp(fresh->address(), new_map->address(),
8547 Map::kCodeCacheOffset) == 0);
8548 }
8549 STATIC_ASSERT(Map::kDependentCodeOffset ==
8550 Map::kCodeCacheOffset + kPointerSize);
8551 STATIC_ASSERT(Map::kWeakCellCacheOffset ==
8552 Map::kDependentCodeOffset + kPointerSize);
8553 int offset = Map::kWeakCellCacheOffset + kPointerSize;
8554 DCHECK(memcmp(fresh->address() + offset,
8555 new_map->address() + offset,
8556 Map::kSize - offset) == 0);
8557 }
8558 #endif
8559 } else {
8560 new_map = Map::CopyNormalized(fast_map, mode);
8561 if (use_cache) {
8562 cache->Set(fast_map, new_map);
8563 isolate->counters()->maps_normalized()->Increment();
8564 }
8565 #if TRACE_MAPS
8566 if (FLAG_trace_maps) {
8567 PrintF("[TraceMaps: Normalize from= %p to= %p reason= %s ]\n",
8568 reinterpret_cast<void*>(*fast_map),
8569 reinterpret_cast<void*>(*new_map), reason);
8570 }
8571 #endif
8572 }
8573 fast_map->NotifyLeafMapLayoutChange();
8574 return new_map;
8575 }
8576
8577
CopyNormalized(Handle<Map> map,PropertyNormalizationMode mode)8578 Handle<Map> Map::CopyNormalized(Handle<Map> map,
8579 PropertyNormalizationMode mode) {
8580 int new_instance_size = map->instance_size();
8581 if (mode == CLEAR_INOBJECT_PROPERTIES) {
8582 new_instance_size -= map->GetInObjectProperties() * kPointerSize;
8583 }
8584
8585 Handle<Map> result = RawCopy(map, new_instance_size);
8586
8587 if (mode != CLEAR_INOBJECT_PROPERTIES) {
8588 result->SetInObjectProperties(map->GetInObjectProperties());
8589 }
8590
8591 result->set_dictionary_map(true);
8592 result->set_migration_target(false);
8593 result->set_construction_counter(kNoSlackTracking);
8594
8595 #ifdef VERIFY_HEAP
8596 if (FLAG_verify_heap) result->DictionaryMapVerify();
8597 #endif
8598
8599 return result;
8600 }
8601
8602 // Return an immutable prototype exotic object version of the input map.
8603 // Never even try to cache it in the transition tree, as it is intended
8604 // for the global object and its prototype chain, and excluding it saves
8605 // memory on the map transition tree.
8606
8607 // static
TransitionToImmutableProto(Handle<Map> map)8608 Handle<Map> Map::TransitionToImmutableProto(Handle<Map> map) {
8609 Handle<Map> new_map = Map::Copy(map, "ImmutablePrototype");
8610 new_map->set_immutable_proto(true);
8611 return new_map;
8612 }
8613
CopyInitialMap(Handle<Map> map,int instance_size,int in_object_properties,int unused_property_fields)8614 Handle<Map> Map::CopyInitialMap(Handle<Map> map, int instance_size,
8615 int in_object_properties,
8616 int unused_property_fields) {
8617 #ifdef DEBUG
8618 Isolate* isolate = map->GetIsolate();
8619 // Strict function maps have Function as a constructor but the
8620 // Function's initial map is a sloppy function map. Same holds for
8621 // GeneratorFunction / AsyncFunction and its initial map.
8622 Object* constructor = map->GetConstructor();
8623 DCHECK(constructor->IsJSFunction());
8624 DCHECK(*map == JSFunction::cast(constructor)->initial_map() ||
8625 *map == *isolate->strict_function_map() ||
8626 *map == *isolate->generator_function_map() ||
8627 *map == *isolate->async_function_map());
8628 #endif
8629 // Initial maps must always own their descriptors and it's descriptor array
8630 // does not contain descriptors that do not belong to the map.
8631 DCHECK(map->owns_descriptors());
8632 DCHECK_EQ(map->NumberOfOwnDescriptors(),
8633 map->instance_descriptors()->number_of_descriptors());
8634
8635 Handle<Map> result = RawCopy(map, instance_size);
8636
8637 // Please note instance_type and instance_size are set when allocated.
8638 result->SetInObjectProperties(in_object_properties);
8639 result->set_unused_property_fields(unused_property_fields);
8640
8641 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
8642 if (number_of_own_descriptors > 0) {
8643 // The copy will use the same descriptors array.
8644 result->UpdateDescriptors(map->instance_descriptors(),
8645 map->GetLayoutDescriptor());
8646 result->SetNumberOfOwnDescriptors(number_of_own_descriptors);
8647
8648 DCHECK_EQ(result->NumberOfFields(),
8649 in_object_properties - unused_property_fields);
8650 }
8651
8652 return result;
8653 }
8654
8655
CopyDropDescriptors(Handle<Map> map)8656 Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) {
8657 Handle<Map> result = RawCopy(map, map->instance_size());
8658
8659 // Please note instance_type and instance_size are set when allocated.
8660 if (map->IsJSObjectMap()) {
8661 result->SetInObjectProperties(map->GetInObjectProperties());
8662 result->set_unused_property_fields(map->unused_property_fields());
8663 }
8664 result->ClearCodeCache(map->GetHeap());
8665 map->NotifyLeafMapLayoutChange();
8666 return result;
8667 }
8668
8669
ShareDescriptor(Handle<Map> map,Handle<DescriptorArray> descriptors,Descriptor * descriptor)8670 Handle<Map> Map::ShareDescriptor(Handle<Map> map,
8671 Handle<DescriptorArray> descriptors,
8672 Descriptor* descriptor) {
8673 // Sanity check. This path is only to be taken if the map owns its descriptor
8674 // array, implying that its NumberOfOwnDescriptors equals the number of
8675 // descriptors in the descriptor array.
8676 DCHECK_EQ(map->NumberOfOwnDescriptors(),
8677 map->instance_descriptors()->number_of_descriptors());
8678
8679 Handle<Map> result = CopyDropDescriptors(map);
8680 Handle<Name> name = descriptor->GetKey();
8681
8682 // Ensure there's space for the new descriptor in the shared descriptor array.
8683 if (descriptors->NumberOfSlackDescriptors() == 0) {
8684 int old_size = descriptors->number_of_descriptors();
8685 if (old_size == 0) {
8686 descriptors = DescriptorArray::Allocate(map->GetIsolate(), 0, 1);
8687 } else {
8688 int slack = SlackForArraySize(old_size, kMaxNumberOfDescriptors);
8689 EnsureDescriptorSlack(map, slack);
8690 descriptors = handle(map->instance_descriptors());
8691 }
8692 }
8693
8694 Handle<LayoutDescriptor> layout_descriptor =
8695 FLAG_unbox_double_fields
8696 ? LayoutDescriptor::ShareAppend(map, descriptor->GetDetails())
8697 : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
8698
8699 {
8700 DisallowHeapAllocation no_gc;
8701 descriptors->Append(descriptor);
8702 result->InitializeDescriptors(*descriptors, *layout_descriptor);
8703 }
8704
8705 DCHECK(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1);
8706 ConnectTransition(map, result, name, SIMPLE_PROPERTY_TRANSITION);
8707
8708 return result;
8709 }
8710
8711
8712 #if TRACE_MAPS
8713
8714 // static
TraceTransition(const char * what,Map * from,Map * to,Name * name)8715 void Map::TraceTransition(const char* what, Map* from, Map* to, Name* name) {
8716 if (FLAG_trace_maps) {
8717 PrintF("[TraceMaps: %s from= %p to= %p name= ", what,
8718 reinterpret_cast<void*>(from), reinterpret_cast<void*>(to));
8719 name->NameShortPrint();
8720 PrintF(" ]\n");
8721 }
8722 }
8723
8724
8725 // static
TraceAllTransitions(Map * map)8726 void Map::TraceAllTransitions(Map* map) {
8727 Object* transitions = map->raw_transitions();
8728 int num_transitions = TransitionArray::NumberOfTransitions(transitions);
8729 for (int i = -0; i < num_transitions; ++i) {
8730 Map* target = TransitionArray::GetTarget(transitions, i);
8731 Name* key = TransitionArray::GetKey(transitions, i);
8732 Map::TraceTransition("Transition", map, target, key);
8733 Map::TraceAllTransitions(target);
8734 }
8735 }
8736
8737 #endif // TRACE_MAPS
8738
8739
ConnectTransition(Handle<Map> parent,Handle<Map> child,Handle<Name> name,SimpleTransitionFlag flag)8740 void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
8741 Handle<Name> name, SimpleTransitionFlag flag) {
8742 if (!parent->GetBackPointer()->IsUndefined(parent->GetIsolate())) {
8743 parent->set_owns_descriptors(false);
8744 } else {
8745 // |parent| is initial map and it must keep the ownership, there must be no
8746 // descriptors in the descriptors array that do not belong to the map.
8747 DCHECK(parent->owns_descriptors());
8748 DCHECK_EQ(parent->NumberOfOwnDescriptors(),
8749 parent->instance_descriptors()->number_of_descriptors());
8750 }
8751 if (parent->is_prototype_map()) {
8752 DCHECK(child->is_prototype_map());
8753 #if TRACE_MAPS
8754 Map::TraceTransition("NoTransition", *parent, *child, *name);
8755 #endif
8756 } else {
8757 TransitionArray::Insert(parent, name, child, flag);
8758 #if TRACE_MAPS
8759 Map::TraceTransition("Transition", *parent, *child, *name);
8760 #endif
8761 }
8762 }
8763
8764
CopyReplaceDescriptors(Handle<Map> map,Handle<DescriptorArray> descriptors,Handle<LayoutDescriptor> layout_descriptor,TransitionFlag flag,MaybeHandle<Name> maybe_name,const char * reason,SimpleTransitionFlag simple_flag)8765 Handle<Map> Map::CopyReplaceDescriptors(
8766 Handle<Map> map, Handle<DescriptorArray> descriptors,
8767 Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag,
8768 MaybeHandle<Name> maybe_name, const char* reason,
8769 SimpleTransitionFlag simple_flag) {
8770 DCHECK(descriptors->IsSortedNoDuplicates());
8771
8772 Handle<Map> result = CopyDropDescriptors(map);
8773
8774 if (!map->is_prototype_map()) {
8775 if (flag == INSERT_TRANSITION &&
8776 TransitionArray::CanHaveMoreTransitions(map)) {
8777 result->InitializeDescriptors(*descriptors, *layout_descriptor);
8778
8779 Handle<Name> name;
8780 CHECK(maybe_name.ToHandle(&name));
8781 ConnectTransition(map, result, name, simple_flag);
8782 } else {
8783 descriptors->GeneralizeAllFields();
8784 result->InitializeDescriptors(*descriptors,
8785 LayoutDescriptor::FastPointerLayout());
8786 }
8787 } else {
8788 result->InitializeDescriptors(*descriptors, *layout_descriptor);
8789 }
8790 #if TRACE_MAPS
8791 if (FLAG_trace_maps &&
8792 // Mirror conditions above that did not call ConnectTransition().
8793 (map->is_prototype_map() ||
8794 !(flag == INSERT_TRANSITION &&
8795 TransitionArray::CanHaveMoreTransitions(map)))) {
8796 PrintF("[TraceMaps: ReplaceDescriptors from= %p to= %p reason= %s ]\n",
8797 reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*result),
8798 reason);
8799 }
8800 #endif
8801
8802 return result;
8803 }
8804
8805
8806 // Creates transition tree starting from |split_map| and adding all descriptors
8807 // starting from descriptor with index |split_map|.NumberOfOwnDescriptors().
8808 // The way how it is done is tricky because of GC and special descriptors
8809 // marking logic.
AddMissingTransitions(Handle<Map> split_map,Handle<DescriptorArray> descriptors,Handle<LayoutDescriptor> full_layout_descriptor)8810 Handle<Map> Map::AddMissingTransitions(
8811 Handle<Map> split_map, Handle<DescriptorArray> descriptors,
8812 Handle<LayoutDescriptor> full_layout_descriptor) {
8813 DCHECK(descriptors->IsSortedNoDuplicates());
8814 int split_nof = split_map->NumberOfOwnDescriptors();
8815 int nof_descriptors = descriptors->number_of_descriptors();
8816 DCHECK_LT(split_nof, nof_descriptors);
8817
8818 // Start with creating last map which will own full descriptors array.
8819 // This is necessary to guarantee that GC will mark the whole descriptor
8820 // array if any of the allocations happening below fail.
8821 // Number of unused properties is temporarily incorrect and the layout
8822 // descriptor could unnecessarily be in slow mode but we will fix after
8823 // all the other intermediate maps are created.
8824 Handle<Map> last_map = CopyDropDescriptors(split_map);
8825 last_map->InitializeDescriptors(*descriptors, *full_layout_descriptor);
8826 last_map->set_unused_property_fields(0);
8827
8828 // During creation of intermediate maps we violate descriptors sharing
8829 // invariant since the last map is not yet connected to the transition tree
8830 // we create here. But it is safe because GC never trims map's descriptors
8831 // if there are no dead transitions from that map and this is exactly the
8832 // case for all the intermediate maps we create here.
8833 Handle<Map> map = split_map;
8834 for (int i = split_nof; i < nof_descriptors - 1; ++i) {
8835 Handle<Map> new_map = CopyDropDescriptors(map);
8836 InstallDescriptors(map, new_map, i, descriptors, full_layout_descriptor);
8837 map = new_map;
8838 }
8839 map->NotifyLeafMapLayoutChange();
8840 InstallDescriptors(map, last_map, nof_descriptors - 1, descriptors,
8841 full_layout_descriptor);
8842 return last_map;
8843 }
8844
8845
8846 // Since this method is used to rewrite an existing transition tree, it can
8847 // always insert transitions without checking.
InstallDescriptors(Handle<Map> parent,Handle<Map> child,int new_descriptor,Handle<DescriptorArray> descriptors,Handle<LayoutDescriptor> full_layout_descriptor)8848 void Map::InstallDescriptors(Handle<Map> parent, Handle<Map> child,
8849 int new_descriptor,
8850 Handle<DescriptorArray> descriptors,
8851 Handle<LayoutDescriptor> full_layout_descriptor) {
8852 DCHECK(descriptors->IsSortedNoDuplicates());
8853
8854 child->set_instance_descriptors(*descriptors);
8855 child->SetNumberOfOwnDescriptors(new_descriptor + 1);
8856
8857 int unused_property_fields = parent->unused_property_fields();
8858 PropertyDetails details = descriptors->GetDetails(new_descriptor);
8859 if (details.location() == kField) {
8860 unused_property_fields = parent->unused_property_fields() - 1;
8861 if (unused_property_fields < 0) {
8862 unused_property_fields += JSObject::kFieldsAdded;
8863 }
8864 }
8865 child->set_unused_property_fields(unused_property_fields);
8866
8867 if (FLAG_unbox_double_fields) {
8868 Handle<LayoutDescriptor> layout_descriptor =
8869 LayoutDescriptor::AppendIfFastOrUseFull(parent, details,
8870 full_layout_descriptor);
8871 child->set_layout_descriptor(*layout_descriptor);
8872 #ifdef VERIFY_HEAP
8873 // TODO(ishell): remove these checks from VERIFY_HEAP mode.
8874 if (FLAG_verify_heap) {
8875 CHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
8876 }
8877 #else
8878 SLOW_DCHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
8879 #endif
8880 child->set_visitor_id(Heap::GetStaticVisitorIdForMap(*child));
8881 }
8882
8883 Handle<Name> name = handle(descriptors->GetKey(new_descriptor));
8884 ConnectTransition(parent, child, name, SIMPLE_PROPERTY_TRANSITION);
8885 }
8886
8887
CopyAsElementsKind(Handle<Map> map,ElementsKind kind,TransitionFlag flag)8888 Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind,
8889 TransitionFlag flag) {
8890 Map* maybe_elements_transition_map = NULL;
8891 if (flag == INSERT_TRANSITION) {
8892 // Ensure we are requested to add elements kind transition "near the root".
8893 DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(),
8894 map->NumberOfOwnDescriptors());
8895
8896 maybe_elements_transition_map = map->ElementsTransitionMap();
8897 DCHECK(maybe_elements_transition_map == NULL ||
8898 (maybe_elements_transition_map->elements_kind() ==
8899 DICTIONARY_ELEMENTS &&
8900 kind == DICTIONARY_ELEMENTS));
8901 DCHECK(!IsFastElementsKind(kind) ||
8902 IsMoreGeneralElementsKindTransition(map->elements_kind(), kind));
8903 DCHECK(kind != map->elements_kind());
8904 }
8905
8906 bool insert_transition = flag == INSERT_TRANSITION &&
8907 TransitionArray::CanHaveMoreTransitions(map) &&
8908 maybe_elements_transition_map == NULL;
8909
8910 if (insert_transition) {
8911 Handle<Map> new_map = CopyForTransition(map, "CopyAsElementsKind");
8912 new_map->set_elements_kind(kind);
8913
8914 Isolate* isolate = map->GetIsolate();
8915 Handle<Name> name = isolate->factory()->elements_transition_symbol();
8916 ConnectTransition(map, new_map, name, SPECIAL_TRANSITION);
8917 return new_map;
8918 }
8919
8920 // Create a new free-floating map only if we are not allowed to store it.
8921 Handle<Map> new_map = Copy(map, "CopyAsElementsKind");
8922 new_map->set_elements_kind(kind);
8923 return new_map;
8924 }
8925
8926
AsLanguageMode(Handle<Map> initial_map,LanguageMode language_mode,FunctionKind kind)8927 Handle<Map> Map::AsLanguageMode(Handle<Map> initial_map,
8928 LanguageMode language_mode, FunctionKind kind) {
8929 DCHECK_EQ(JS_FUNCTION_TYPE, initial_map->instance_type());
8930 // Initial map for sloppy mode function is stored in the function
8931 // constructor. Initial maps for strict mode are cached as special transitions
8932 // using |strict_function_transition_symbol| as a key.
8933 if (language_mode == SLOPPY) return initial_map;
8934 Isolate* isolate = initial_map->GetIsolate();
8935
8936 int map_index = Context::FunctionMapIndex(language_mode, kind);
8937 Handle<Map> function_map(
8938 Map::cast(isolate->native_context()->get(map_index)));
8939
8940 STATIC_ASSERT(LANGUAGE_END == 2);
8941 DCHECK_EQ(STRICT, language_mode);
8942 Handle<Symbol> transition_symbol =
8943 isolate->factory()->strict_function_transition_symbol();
8944 Map* maybe_transition =
8945 TransitionArray::SearchSpecial(*initial_map, *transition_symbol);
8946 if (maybe_transition != NULL) {
8947 return handle(maybe_transition, isolate);
8948 }
8949 initial_map->NotifyLeafMapLayoutChange();
8950
8951 // Create new map taking descriptors from the |function_map| and all
8952 // the other details from the |initial_map|.
8953 Handle<Map> map =
8954 Map::CopyInitialMap(function_map, initial_map->instance_size(),
8955 initial_map->GetInObjectProperties(),
8956 initial_map->unused_property_fields());
8957 map->SetConstructor(initial_map->GetConstructor());
8958 map->set_prototype(initial_map->prototype());
8959
8960 if (TransitionArray::CanHaveMoreTransitions(initial_map)) {
8961 Map::ConnectTransition(initial_map, map, transition_symbol,
8962 SPECIAL_TRANSITION);
8963 }
8964 return map;
8965 }
8966
8967
CopyForTransition(Handle<Map> map,const char * reason)8968 Handle<Map> Map::CopyForTransition(Handle<Map> map, const char* reason) {
8969 DCHECK(!map->is_prototype_map());
8970 Handle<Map> new_map = CopyDropDescriptors(map);
8971
8972 if (map->owns_descriptors()) {
8973 // In case the map owned its own descriptors, share the descriptors and
8974 // transfer ownership to the new map.
8975 // The properties did not change, so reuse descriptors.
8976 new_map->InitializeDescriptors(map->instance_descriptors(),
8977 map->GetLayoutDescriptor());
8978 } else {
8979 // In case the map did not own its own descriptors, a split is forced by
8980 // copying the map; creating a new descriptor array cell.
8981 Handle<DescriptorArray> descriptors(map->instance_descriptors());
8982 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
8983 Handle<DescriptorArray> new_descriptors =
8984 DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
8985 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
8986 map->GetIsolate());
8987 new_map->InitializeDescriptors(*new_descriptors, *new_layout_descriptor);
8988 }
8989
8990 #if TRACE_MAPS
8991 if (FLAG_trace_maps) {
8992 PrintF("[TraceMaps: CopyForTransition from= %p to= %p reason= %s ]\n",
8993 reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*new_map),
8994 reason);
8995 }
8996 #endif
8997
8998 return new_map;
8999 }
9000
9001
Copy(Handle<Map> map,const char * reason)9002 Handle<Map> Map::Copy(Handle<Map> map, const char* reason) {
9003 Handle<DescriptorArray> descriptors(map->instance_descriptors());
9004 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
9005 Handle<DescriptorArray> new_descriptors =
9006 DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
9007 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9008 map->GetIsolate());
9009 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9010 OMIT_TRANSITION, MaybeHandle<Name>(), reason,
9011 SPECIAL_TRANSITION);
9012 }
9013
9014
Create(Isolate * isolate,int inobject_properties)9015 Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) {
9016 Handle<Map> copy =
9017 Copy(handle(isolate->object_function()->initial_map()), "MapCreate");
9018
9019 // Check that we do not overflow the instance size when adding the extra
9020 // inobject properties. If the instance size overflows, we allocate as many
9021 // properties as we can as inobject properties.
9022 int max_extra_properties =
9023 (JSObject::kMaxInstanceSize - JSObject::kHeaderSize) >> kPointerSizeLog2;
9024
9025 if (inobject_properties > max_extra_properties) {
9026 inobject_properties = max_extra_properties;
9027 }
9028
9029 int new_instance_size =
9030 JSObject::kHeaderSize + kPointerSize * inobject_properties;
9031
9032 // Adjust the map with the extra inobject properties.
9033 copy->SetInObjectProperties(inobject_properties);
9034 copy->set_unused_property_fields(inobject_properties);
9035 copy->set_instance_size(new_instance_size);
9036 copy->set_visitor_id(Heap::GetStaticVisitorIdForMap(*copy));
9037 return copy;
9038 }
9039
9040
CopyForPreventExtensions(Handle<Map> map,PropertyAttributes attrs_to_add,Handle<Symbol> transition_marker,const char * reason)9041 Handle<Map> Map::CopyForPreventExtensions(Handle<Map> map,
9042 PropertyAttributes attrs_to_add,
9043 Handle<Symbol> transition_marker,
9044 const char* reason) {
9045 int num_descriptors = map->NumberOfOwnDescriptors();
9046 Isolate* isolate = map->GetIsolate();
9047 Handle<DescriptorArray> new_desc = DescriptorArray::CopyUpToAddAttributes(
9048 handle(map->instance_descriptors(), isolate), num_descriptors,
9049 attrs_to_add);
9050 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
9051 isolate);
9052 Handle<Map> new_map = CopyReplaceDescriptors(
9053 map, new_desc, new_layout_descriptor, INSERT_TRANSITION,
9054 transition_marker, reason, SPECIAL_TRANSITION);
9055 new_map->set_is_extensible(false);
9056 if (!IsFixedTypedArrayElementsKind(map->elements_kind())) {
9057 ElementsKind new_kind = IsStringWrapperElementsKind(map->elements_kind())
9058 ? SLOW_STRING_WRAPPER_ELEMENTS
9059 : DICTIONARY_ELEMENTS;
9060 new_map->set_elements_kind(new_kind);
9061 }
9062 return new_map;
9063 }
9064
9065 namespace {
9066
CanHoldValue(DescriptorArray * descriptors,int descriptor,PropertyConstness constness,Object * value)9067 bool CanHoldValue(DescriptorArray* descriptors, int descriptor,
9068 PropertyConstness constness, Object* value) {
9069 PropertyDetails details = descriptors->GetDetails(descriptor);
9070 if (details.location() == kField) {
9071 if (details.kind() == kData) {
9072 return IsGeneralizableTo(constness, details.constness()) &&
9073 value->FitsRepresentation(details.representation()) &&
9074 descriptors->GetFieldType(descriptor)->NowContains(value);
9075 } else {
9076 DCHECK_EQ(kAccessor, details.kind());
9077 return false;
9078 }
9079
9080 } else {
9081 DCHECK_EQ(kDescriptor, details.location());
9082 DCHECK_EQ(kConst, details.constness());
9083 if (details.kind() == kData) {
9084 DCHECK(!FLAG_track_constant_fields);
9085 DCHECK(descriptors->GetValue(descriptor) != value ||
9086 value->FitsRepresentation(details.representation()));
9087 return descriptors->GetValue(descriptor) == value;
9088 } else {
9089 DCHECK_EQ(kAccessor, details.kind());
9090 return false;
9091 }
9092 }
9093 UNREACHABLE();
9094 return false;
9095 }
9096
UpdateDescriptorForValue(Handle<Map> map,int descriptor,PropertyConstness constness,Handle<Object> value)9097 Handle<Map> UpdateDescriptorForValue(Handle<Map> map, int descriptor,
9098 PropertyConstness constness,
9099 Handle<Object> value) {
9100 if (CanHoldValue(map->instance_descriptors(), descriptor, constness,
9101 *value)) {
9102 return map;
9103 }
9104
9105 Isolate* isolate = map->GetIsolate();
9106 PropertyAttributes attributes =
9107 map->instance_descriptors()->GetDetails(descriptor).attributes();
9108 Representation representation = value->OptimalRepresentation();
9109 Handle<FieldType> type = value->OptimalType(isolate, representation);
9110
9111 MapUpdater mu(isolate, map);
9112 return mu.ReconfigureToDataField(descriptor, attributes, constness,
9113 representation, type);
9114 }
9115
9116 } // namespace
9117
9118 // static
PrepareForDataProperty(Handle<Map> map,int descriptor,PropertyConstness constness,Handle<Object> value)9119 Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor,
9120 PropertyConstness constness,
9121 Handle<Object> value) {
9122 // Dictionaries can store any property value.
9123 DCHECK(!map->is_dictionary_map());
9124 // Update to the newest map before storing the property.
9125 return UpdateDescriptorForValue(Update(map), descriptor, constness, value);
9126 }
9127
TransitionToDataProperty(Handle<Map> map,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes,PropertyConstness constness,StoreFromKeyed store_mode)9128 Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
9129 Handle<Object> value,
9130 PropertyAttributes attributes,
9131 PropertyConstness constness,
9132 StoreFromKeyed store_mode) {
9133 RuntimeCallTimerScope stats_scope(
9134 *map, map->is_prototype_map()
9135 ? &RuntimeCallStats::PrototypeMap_TransitionToDataProperty
9136 : &RuntimeCallStats::Map_TransitionToDataProperty);
9137
9138 DCHECK(name->IsUniqueName());
9139 DCHECK(!map->is_dictionary_map());
9140
9141 // Migrate to the newest map before storing the property.
9142 map = Update(map);
9143
9144 Map* maybe_transition =
9145 TransitionArray::SearchTransition(*map, kData, *name, attributes);
9146 if (maybe_transition != NULL) {
9147 Handle<Map> transition(maybe_transition);
9148 int descriptor = transition->LastAdded();
9149
9150 DCHECK_EQ(attributes, transition->instance_descriptors()
9151 ->GetDetails(descriptor)
9152 .attributes());
9153
9154 return UpdateDescriptorForValue(transition, descriptor, constness, value);
9155 }
9156
9157 TransitionFlag flag = INSERT_TRANSITION;
9158 MaybeHandle<Map> maybe_map;
9159 if (!FLAG_track_constant_fields && value->IsJSFunction()) {
9160 maybe_map = Map::CopyWithConstant(map, name, value, attributes, flag);
9161 } else if (!map->TooManyFastProperties(store_mode)) {
9162 Isolate* isolate = name->GetIsolate();
9163 Representation representation = value->OptimalRepresentation();
9164 Handle<FieldType> type = value->OptimalType(isolate, representation);
9165 maybe_map = Map::CopyWithField(map, name, type, attributes, constness,
9166 representation, flag);
9167 }
9168
9169 Handle<Map> result;
9170 if (!maybe_map.ToHandle(&result)) {
9171 #if TRACE_MAPS
9172 if (FLAG_trace_maps) {
9173 Vector<char> name_buffer = Vector<char>::New(100);
9174 name->NameShortPrint(name_buffer);
9175 Vector<char> buffer = Vector<char>::New(128);
9176 SNPrintF(buffer, "TooManyFastProperties %s", name_buffer.start());
9177 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, buffer.start());
9178 }
9179 #endif
9180 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES,
9181 "TooManyFastProperties");
9182 }
9183
9184 return result;
9185 }
9186
9187
ReconfigureExistingProperty(Handle<Map> map,int descriptor,PropertyKind kind,PropertyAttributes attributes)9188 Handle<Map> Map::ReconfigureExistingProperty(Handle<Map> map, int descriptor,
9189 PropertyKind kind,
9190 PropertyAttributes attributes) {
9191 // Dictionaries have to be reconfigured in-place.
9192 DCHECK(!map->is_dictionary_map());
9193
9194 if (!map->GetBackPointer()->IsMap()) {
9195 // There is no benefit from reconstructing transition tree for maps without
9196 // back pointers.
9197 return CopyGeneralizeAllFields(map, map->elements_kind(), descriptor, kind,
9198 attributes,
9199 "GenAll_AttributesMismatchProtoMap");
9200 }
9201
9202 if (FLAG_trace_generalization) {
9203 map->PrintReconfiguration(stdout, descriptor, kind, attributes);
9204 }
9205
9206 Isolate* isolate = map->GetIsolate();
9207
9208 MapUpdater mu(isolate, map);
9209 DCHECK_EQ(kData, kind); // Only kData case is supported so far.
9210 Handle<Map> new_map = mu.ReconfigureToDataField(
9211 descriptor, attributes, kDefaultFieldConstness, Representation::None(),
9212 FieldType::None(isolate));
9213 return new_map;
9214 }
9215
TransitionToAccessorProperty(Isolate * isolate,Handle<Map> map,Handle<Name> name,int descriptor,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)9216 Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map,
9217 Handle<Name> name, int descriptor,
9218 Handle<Object> getter,
9219 Handle<Object> setter,
9220 PropertyAttributes attributes) {
9221 RuntimeCallTimerScope stats_scope(
9222 isolate,
9223 map->is_prototype_map()
9224 ? &RuntimeCallStats::PrototypeMap_TransitionToAccessorProperty
9225 : &RuntimeCallStats::Map_TransitionToAccessorProperty);
9226
9227 // At least one of the accessors needs to be a new value.
9228 DCHECK(!getter->IsNull(isolate) || !setter->IsNull(isolate));
9229 DCHECK(name->IsUniqueName());
9230
9231 // Dictionary maps can always have additional data properties.
9232 if (map->is_dictionary_map()) return map;
9233
9234 // Migrate to the newest map before transitioning to the new property.
9235 map = Update(map);
9236
9237 PropertyNormalizationMode mode = map->is_prototype_map()
9238 ? KEEP_INOBJECT_PROPERTIES
9239 : CLEAR_INOBJECT_PROPERTIES;
9240
9241 Map* maybe_transition =
9242 TransitionArray::SearchTransition(*map, kAccessor, *name, attributes);
9243 if (maybe_transition != NULL) {
9244 Handle<Map> transition(maybe_transition, isolate);
9245 DescriptorArray* descriptors = transition->instance_descriptors();
9246 int descriptor = transition->LastAdded();
9247 DCHECK(descriptors->GetKey(descriptor)->Equals(*name));
9248
9249 DCHECK_EQ(kAccessor, descriptors->GetDetails(descriptor).kind());
9250 DCHECK_EQ(attributes, descriptors->GetDetails(descriptor).attributes());
9251
9252 Handle<Object> maybe_pair(descriptors->GetValue(descriptor), isolate);
9253 if (!maybe_pair->IsAccessorPair()) {
9254 return Map::Normalize(map, mode, "TransitionToAccessorFromNonPair");
9255 }
9256
9257 Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair);
9258 if (!pair->Equals(*getter, *setter)) {
9259 return Map::Normalize(map, mode, "TransitionToDifferentAccessor");
9260 }
9261
9262 return transition;
9263 }
9264
9265 Handle<AccessorPair> pair;
9266 DescriptorArray* old_descriptors = map->instance_descriptors();
9267 if (descriptor != DescriptorArray::kNotFound) {
9268 if (descriptor != map->LastAdded()) {
9269 return Map::Normalize(map, mode, "AccessorsOverwritingNonLast");
9270 }
9271 PropertyDetails old_details = old_descriptors->GetDetails(descriptor);
9272 if (old_details.kind() != kAccessor) {
9273 return Map::Normalize(map, mode, "AccessorsOverwritingNonAccessors");
9274 }
9275
9276 if (old_details.attributes() != attributes) {
9277 return Map::Normalize(map, mode, "AccessorsWithAttributes");
9278 }
9279
9280 Handle<Object> maybe_pair(old_descriptors->GetValue(descriptor), isolate);
9281 if (!maybe_pair->IsAccessorPair()) {
9282 return Map::Normalize(map, mode, "AccessorsOverwritingNonPair");
9283 }
9284
9285 Handle<AccessorPair> current_pair = Handle<AccessorPair>::cast(maybe_pair);
9286 if (current_pair->Equals(*getter, *setter)) return map;
9287
9288 bool overwriting_accessor = false;
9289 if (!getter->IsNull(isolate) &&
9290 !current_pair->get(ACCESSOR_GETTER)->IsNull(isolate) &&
9291 current_pair->get(ACCESSOR_GETTER) != *getter) {
9292 overwriting_accessor = true;
9293 }
9294 if (!setter->IsNull(isolate) &&
9295 !current_pair->get(ACCESSOR_SETTER)->IsNull(isolate) &&
9296 current_pair->get(ACCESSOR_SETTER) != *setter) {
9297 overwriting_accessor = true;
9298 }
9299 if (overwriting_accessor) {
9300 return Map::Normalize(map, mode, "AccessorsOverwritingAccessors");
9301 }
9302
9303 pair = AccessorPair::Copy(Handle<AccessorPair>::cast(maybe_pair));
9304 } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors ||
9305 map->TooManyFastProperties(CERTAINLY_NOT_STORE_FROM_KEYED)) {
9306 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, "TooManyAccessors");
9307 } else {
9308 pair = isolate->factory()->NewAccessorPair();
9309 }
9310
9311 pair->SetComponents(*getter, *setter);
9312
9313 TransitionFlag flag = INSERT_TRANSITION;
9314 Descriptor d = Descriptor::AccessorConstant(name, pair, attributes);
9315 return Map::CopyInsertDescriptor(map, &d, flag);
9316 }
9317
9318
CopyAddDescriptor(Handle<Map> map,Descriptor * descriptor,TransitionFlag flag)9319 Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
9320 Descriptor* descriptor,
9321 TransitionFlag flag) {
9322 Handle<DescriptorArray> descriptors(map->instance_descriptors());
9323
9324 // Share descriptors only if map owns descriptors and it not an initial map.
9325 if (flag == INSERT_TRANSITION && map->owns_descriptors() &&
9326 !map->GetBackPointer()->IsUndefined(map->GetIsolate()) &&
9327 TransitionArray::CanHaveMoreTransitions(map)) {
9328 return ShareDescriptor(map, descriptors, descriptor);
9329 }
9330
9331 int nof = map->NumberOfOwnDescriptors();
9332 Handle<DescriptorArray> new_descriptors =
9333 DescriptorArray::CopyUpTo(descriptors, nof, 1);
9334 new_descriptors->Append(descriptor);
9335
9336 Handle<LayoutDescriptor> new_layout_descriptor =
9337 FLAG_unbox_double_fields
9338 ? LayoutDescriptor::New(map, new_descriptors, nof + 1)
9339 : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
9340
9341 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9342 flag, descriptor->GetKey(), "CopyAddDescriptor",
9343 SIMPLE_PROPERTY_TRANSITION);
9344 }
9345
9346
CopyInsertDescriptor(Handle<Map> map,Descriptor * descriptor,TransitionFlag flag)9347 Handle<Map> Map::CopyInsertDescriptor(Handle<Map> map,
9348 Descriptor* descriptor,
9349 TransitionFlag flag) {
9350 Handle<DescriptorArray> old_descriptors(map->instance_descriptors());
9351
9352 // We replace the key if it is already present.
9353 int index = old_descriptors->SearchWithCache(map->GetIsolate(),
9354 *descriptor->GetKey(), *map);
9355 if (index != DescriptorArray::kNotFound) {
9356 return CopyReplaceDescriptor(map, old_descriptors, descriptor, index, flag);
9357 }
9358 return CopyAddDescriptor(map, descriptor, flag);
9359 }
9360
9361
CopyUpTo(Handle<DescriptorArray> desc,int enumeration_index,int slack)9362 Handle<DescriptorArray> DescriptorArray::CopyUpTo(
9363 Handle<DescriptorArray> desc,
9364 int enumeration_index,
9365 int slack) {
9366 return DescriptorArray::CopyUpToAddAttributes(
9367 desc, enumeration_index, NONE, slack);
9368 }
9369
9370
CopyUpToAddAttributes(Handle<DescriptorArray> desc,int enumeration_index,PropertyAttributes attributes,int slack)9371 Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
9372 Handle<DescriptorArray> desc,
9373 int enumeration_index,
9374 PropertyAttributes attributes,
9375 int slack) {
9376 if (enumeration_index + slack == 0) {
9377 return desc->GetIsolate()->factory()->empty_descriptor_array();
9378 }
9379
9380 int size = enumeration_index;
9381
9382 Handle<DescriptorArray> descriptors =
9383 DescriptorArray::Allocate(desc->GetIsolate(), size, slack);
9384
9385 if (attributes != NONE) {
9386 for (int i = 0; i < size; ++i) {
9387 Object* value = desc->GetValue(i);
9388 Name* key = desc->GetKey(i);
9389 PropertyDetails details = desc->GetDetails(i);
9390 // Bulk attribute changes never affect private properties.
9391 if (!key->IsPrivate()) {
9392 int mask = DONT_DELETE | DONT_ENUM;
9393 // READ_ONLY is an invalid attribute for JS setters/getters.
9394 if (details.kind() != kAccessor || !value->IsAccessorPair()) {
9395 mask |= READ_ONLY;
9396 }
9397 details = details.CopyAddAttributes(
9398 static_cast<PropertyAttributes>(attributes & mask));
9399 }
9400 descriptors->Set(i, key, value, details);
9401 }
9402 } else {
9403 for (int i = 0; i < size; ++i) {
9404 descriptors->CopyFrom(i, *desc);
9405 }
9406 }
9407
9408 if (desc->number_of_descriptors() != enumeration_index) descriptors->Sort();
9409
9410 return descriptors;
9411 }
9412
9413
IsEqualUpTo(DescriptorArray * desc,int nof_descriptors)9414 bool DescriptorArray::IsEqualUpTo(DescriptorArray* desc, int nof_descriptors) {
9415 for (int i = 0; i < nof_descriptors; i++) {
9416 if (GetKey(i) != desc->GetKey(i) || GetValue(i) != desc->GetValue(i)) {
9417 return false;
9418 }
9419 PropertyDetails details = GetDetails(i);
9420 PropertyDetails other_details = desc->GetDetails(i);
9421 if (details.kind() != other_details.kind() ||
9422 details.location() != other_details.location() ||
9423 !details.representation().Equals(other_details.representation())) {
9424 return false;
9425 }
9426 }
9427 return true;
9428 }
9429
9430
CopyReplaceDescriptor(Handle<Map> map,Handle<DescriptorArray> descriptors,Descriptor * descriptor,int insertion_index,TransitionFlag flag)9431 Handle<Map> Map::CopyReplaceDescriptor(Handle<Map> map,
9432 Handle<DescriptorArray> descriptors,
9433 Descriptor* descriptor,
9434 int insertion_index,
9435 TransitionFlag flag) {
9436 Handle<Name> key = descriptor->GetKey();
9437 DCHECK(*key == descriptors->GetKey(insertion_index));
9438
9439 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
9440 descriptors, map->NumberOfOwnDescriptors());
9441
9442 new_descriptors->Replace(insertion_index, descriptor);
9443 Handle<LayoutDescriptor> new_layout_descriptor = LayoutDescriptor::New(
9444 map, new_descriptors, new_descriptors->number_of_descriptors());
9445
9446 SimpleTransitionFlag simple_flag =
9447 (insertion_index == descriptors->number_of_descriptors() - 1)
9448 ? SIMPLE_PROPERTY_TRANSITION
9449 : PROPERTY_TRANSITION;
9450 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
9451 flag, key, "CopyReplaceDescriptor",
9452 simple_flag);
9453 }
9454
9455 // Helper class to manage a Map's code cache. The layout depends on the number
9456 // of entries; this is worthwhile because most code caches are very small,
9457 // but some are huge (thousands of entries).
9458 // For zero entries, the EmptyFixedArray is used.
9459 // For one entry, we use a 2-element FixedArray containing [name, code].
9460 // For 2..100 entries, we use a FixedArray with linear lookups, the layout is:
9461 // [0] - number of slots that are currently in use
9462 // [1] - first name
9463 // [2] - first code
9464 // [3] - second name
9465 // [4] - second code
9466 // etc.
9467 // For more than 128 entries, we use a CodeCacheHashTable.
9468 class CodeCache : public AllStatic {
9469 public:
9470 // Returns the new cache, to be stored on the map.
Put(Isolate * isolate,Handle<FixedArray> cache,Handle<Name> name,Handle<Code> code)9471 static Handle<FixedArray> Put(Isolate* isolate, Handle<FixedArray> cache,
9472 Handle<Name> name, Handle<Code> code) {
9473 int length = cache->length();
9474 if (length == 0) return PutFirstElement(isolate, name, code);
9475 if (length == kEntrySize) {
9476 return PutSecondElement(isolate, cache, name, code);
9477 }
9478 if (length <= kLinearMaxSize) {
9479 Handle<FixedArray> result = PutLinearElement(isolate, cache, name, code);
9480 if (!result.is_null()) return result;
9481 // Fall through if linear storage is getting too large.
9482 }
9483 return PutHashTableElement(isolate, cache, name, code);
9484 }
9485
Lookup(FixedArray * cache,Name * name,Code::Flags flags)9486 static Code* Lookup(FixedArray* cache, Name* name, Code::Flags flags) {
9487 int length = cache->length();
9488 if (length == 0) return nullptr;
9489 if (length == kEntrySize) return OneElementLookup(cache, name, flags);
9490 if (!cache->IsCodeCacheHashTable()) {
9491 return LinearLookup(cache, name, flags);
9492 } else {
9493 return CodeCacheHashTable::cast(cache)->Lookup(name, flags);
9494 }
9495 }
9496
9497 private:
9498 static const int kNameIndex = 0;
9499 static const int kCodeIndex = 1;
9500 static const int kEntrySize = 2;
9501
9502 static const int kLinearUsageIndex = 0;
9503 static const int kLinearReservedSlots = 1;
9504 static const int kLinearInitialCapacity = 2;
9505 static const int kLinearMaxSize = 257; // == LinearSizeFor(128);
9506
9507 static const int kHashTableInitialCapacity = 200; // Number of entries.
9508
LinearSizeFor(int entries)9509 static int LinearSizeFor(int entries) {
9510 return kLinearReservedSlots + kEntrySize * entries;
9511 }
9512
LinearNewSize(int old_size)9513 static int LinearNewSize(int old_size) {
9514 int old_entries = (old_size - kLinearReservedSlots) / kEntrySize;
9515 return LinearSizeFor(old_entries * 2);
9516 }
9517
OneElementLookup(FixedArray * cache,Name * name,Code::Flags flags)9518 static Code* OneElementLookup(FixedArray* cache, Name* name,
9519 Code::Flags flags) {
9520 DCHECK_EQ(cache->length(), kEntrySize);
9521 if (cache->get(kNameIndex) != name) return nullptr;
9522 Code* maybe_code = Code::cast(cache->get(kCodeIndex));
9523 if (maybe_code->flags() != flags) return nullptr;
9524 return maybe_code;
9525 }
9526
LinearLookup(FixedArray * cache,Name * name,Code::Flags flags)9527 static Code* LinearLookup(FixedArray* cache, Name* name, Code::Flags flags) {
9528 DCHECK_GE(cache->length(), kEntrySize);
9529 DCHECK(!cache->IsCodeCacheHashTable());
9530 int usage = GetLinearUsage(cache);
9531 for (int i = kLinearReservedSlots; i < usage; i += kEntrySize) {
9532 if (cache->get(i + kNameIndex) != name) continue;
9533 Code* code = Code::cast(cache->get(i + kCodeIndex));
9534 if (code->flags() == flags) return code;
9535 }
9536 return nullptr;
9537 }
9538
PutFirstElement(Isolate * isolate,Handle<Name> name,Handle<Code> code)9539 static Handle<FixedArray> PutFirstElement(Isolate* isolate, Handle<Name> name,
9540 Handle<Code> code) {
9541 Handle<FixedArray> cache = isolate->factory()->NewFixedArray(kEntrySize);
9542 cache->set(kNameIndex, *name);
9543 cache->set(kCodeIndex, *code);
9544 return cache;
9545 }
9546
PutSecondElement(Isolate * isolate,Handle<FixedArray> cache,Handle<Name> name,Handle<Code> code)9547 static Handle<FixedArray> PutSecondElement(Isolate* isolate,
9548 Handle<FixedArray> cache,
9549 Handle<Name> name,
9550 Handle<Code> code) {
9551 DCHECK_EQ(cache->length(), kEntrySize);
9552 Handle<FixedArray> new_cache = isolate->factory()->NewFixedArray(
9553 LinearSizeFor(kLinearInitialCapacity));
9554 new_cache->set(kLinearReservedSlots + kNameIndex, cache->get(kNameIndex));
9555 new_cache->set(kLinearReservedSlots + kCodeIndex, cache->get(kCodeIndex));
9556 new_cache->set(LinearSizeFor(1) + kNameIndex, *name);
9557 new_cache->set(LinearSizeFor(1) + kCodeIndex, *code);
9558 new_cache->set(kLinearUsageIndex, Smi::FromInt(LinearSizeFor(2)));
9559 return new_cache;
9560 }
9561
PutLinearElement(Isolate * isolate,Handle<FixedArray> cache,Handle<Name> name,Handle<Code> code)9562 static Handle<FixedArray> PutLinearElement(Isolate* isolate,
9563 Handle<FixedArray> cache,
9564 Handle<Name> name,
9565 Handle<Code> code) {
9566 int length = cache->length();
9567 int usage = GetLinearUsage(*cache);
9568 DCHECK_LE(usage, length);
9569 // Check if we need to grow.
9570 if (usage == length) {
9571 int new_length = LinearNewSize(length);
9572 if (new_length > kLinearMaxSize) return Handle<FixedArray>::null();
9573 Handle<FixedArray> new_cache =
9574 isolate->factory()->NewFixedArray(new_length);
9575 for (int i = kLinearReservedSlots; i < length; i++) {
9576 new_cache->set(i, cache->get(i));
9577 }
9578 cache = new_cache;
9579 }
9580 // Store new entry.
9581 DCHECK_GE(cache->length(), usage + kEntrySize);
9582 cache->set(usage + kNameIndex, *name);
9583 cache->set(usage + kCodeIndex, *code);
9584 cache->set(kLinearUsageIndex, Smi::FromInt(usage + kEntrySize));
9585 return cache;
9586 }
9587
PutHashTableElement(Isolate * isolate,Handle<FixedArray> cache,Handle<Name> name,Handle<Code> code)9588 static Handle<FixedArray> PutHashTableElement(Isolate* isolate,
9589 Handle<FixedArray> cache,
9590 Handle<Name> name,
9591 Handle<Code> code) {
9592 // Check if we need to transition from linear to hash table storage.
9593 if (!cache->IsCodeCacheHashTable()) {
9594 // Check that the initial hash table capacity is large enough.
9595 DCHECK_EQ(kLinearMaxSize, LinearSizeFor(128));
9596 STATIC_ASSERT(kHashTableInitialCapacity > 128);
9597
9598 int length = cache->length();
9599 // Only migrate from linear storage when it's full.
9600 DCHECK_EQ(length, GetLinearUsage(*cache));
9601 DCHECK_EQ(length, kLinearMaxSize);
9602 Handle<CodeCacheHashTable> table =
9603 CodeCacheHashTable::New(isolate, kHashTableInitialCapacity);
9604 HandleScope scope(isolate);
9605 for (int i = kLinearReservedSlots; i < length; i += kEntrySize) {
9606 Handle<Name> old_name(Name::cast(cache->get(i + kNameIndex)), isolate);
9607 Handle<Code> old_code(Code::cast(cache->get(i + kCodeIndex)), isolate);
9608 CodeCacheHashTable::Put(table, old_name, old_code);
9609 }
9610 cache = table;
9611 }
9612 // Store new entry.
9613 DCHECK(cache->IsCodeCacheHashTable());
9614 return CodeCacheHashTable::Put(Handle<CodeCacheHashTable>::cast(cache),
9615 name, code);
9616 }
9617
GetLinearUsage(FixedArray * linear_cache)9618 static inline int GetLinearUsage(FixedArray* linear_cache) {
9619 DCHECK_GT(linear_cache->length(), kEntrySize);
9620 return Smi::cast(linear_cache->get(kLinearUsageIndex))->value();
9621 }
9622 };
9623
UpdateCodeCache(Handle<Map> map,Handle<Name> name,Handle<Code> code)9624 void Map::UpdateCodeCache(Handle<Map> map,
9625 Handle<Name> name,
9626 Handle<Code> code) {
9627 Isolate* isolate = map->GetIsolate();
9628 Handle<FixedArray> cache(map->code_cache(), isolate);
9629 Handle<FixedArray> new_cache = CodeCache::Put(isolate, cache, name, code);
9630 map->set_code_cache(*new_cache);
9631 }
9632
LookupInCodeCache(Name * name,Code::Flags flags)9633 Code* Map::LookupInCodeCache(Name* name, Code::Flags flags) {
9634 return CodeCache::Lookup(code_cache(), name, flags);
9635 }
9636
9637
9638 // The key in the code cache hash table consists of the property name and the
9639 // code object. The actual match is on the name and the code flags. If a key
9640 // is created using the flags and not a code object it can only be used for
9641 // lookup not to create a new entry.
9642 class CodeCacheHashTableKey : public HashTableKey {
9643 public:
CodeCacheHashTableKey(Handle<Name> name,Code::Flags flags)9644 CodeCacheHashTableKey(Handle<Name> name, Code::Flags flags)
9645 : name_(name), flags_(flags), code_() {
9646 DCHECK(name_->IsUniqueName());
9647 }
9648
CodeCacheHashTableKey(Handle<Name> name,Handle<Code> code)9649 CodeCacheHashTableKey(Handle<Name> name, Handle<Code> code)
9650 : name_(name), flags_(code->flags()), code_(code) {
9651 DCHECK(name_->IsUniqueName());
9652 }
9653
IsMatch(Object * other)9654 bool IsMatch(Object* other) override {
9655 DCHECK(other->IsFixedArray());
9656 FixedArray* pair = FixedArray::cast(other);
9657 Name* name = Name::cast(pair->get(0));
9658 Code::Flags flags = Code::cast(pair->get(1))->flags();
9659 if (flags != flags_) return false;
9660 DCHECK(name->IsUniqueName());
9661 return *name_ == name;
9662 }
9663
NameFlagsHashHelper(Name * name,Code::Flags flags)9664 static uint32_t NameFlagsHashHelper(Name* name, Code::Flags flags) {
9665 return name->Hash() ^ flags;
9666 }
9667
Hash()9668 uint32_t Hash() override { return NameFlagsHashHelper(*name_, flags_); }
9669
HashForObject(Object * obj)9670 uint32_t HashForObject(Object* obj) override {
9671 FixedArray* pair = FixedArray::cast(obj);
9672 Name* name = Name::cast(pair->get(0));
9673 Code* code = Code::cast(pair->get(1));
9674 return NameFlagsHashHelper(name, code->flags());
9675 }
9676
AsHandle(Isolate * isolate)9677 MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) override {
9678 Handle<Code> code = code_.ToHandleChecked();
9679 Handle<FixedArray> pair = isolate->factory()->NewFixedArray(2);
9680 pair->set(0, *name_);
9681 pair->set(1, *code);
9682 return pair;
9683 }
9684
9685 private:
9686 Handle<Name> name_;
9687 Code::Flags flags_;
9688 // TODO(jkummerow): We should be able to get by without this.
9689 MaybeHandle<Code> code_;
9690 };
9691
9692
Put(Handle<CodeCacheHashTable> cache,Handle<Name> name,Handle<Code> code)9693 Handle<CodeCacheHashTable> CodeCacheHashTable::Put(
9694 Handle<CodeCacheHashTable> cache, Handle<Name> name, Handle<Code> code) {
9695 CodeCacheHashTableKey key(name, code);
9696
9697 Handle<CodeCacheHashTable> new_cache = EnsureCapacity(cache, 1, &key);
9698
9699 int entry = new_cache->FindInsertionEntry(key.Hash());
9700 Handle<Object> k = key.AsHandle(cache->GetIsolate());
9701
9702 new_cache->set(EntryToIndex(entry), *k);
9703 new_cache->ElementAdded();
9704 return new_cache;
9705 }
9706
Lookup(Name * name,Code::Flags flags)9707 Code* CodeCacheHashTable::Lookup(Name* name, Code::Flags flags) {
9708 DisallowHeapAllocation no_alloc;
9709 CodeCacheHashTableKey key(handle(name), flags);
9710 int entry = FindEntry(&key);
9711 if (entry == kNotFound) return nullptr;
9712 return Code::cast(FixedArray::cast(get(EntryToIndex(entry)))->get(1));
9713 }
9714
SetAndGrow(Handle<FixedArray> array,int index,Handle<Object> value)9715 Handle<FixedArray> FixedArray::SetAndGrow(Handle<FixedArray> array, int index,
9716 Handle<Object> value) {
9717 if (index < array->length()) {
9718 array->set(index, *value);
9719 return array;
9720 }
9721 int capacity = array->length();
9722 do {
9723 capacity = JSObject::NewElementsCapacity(capacity);
9724 } while (capacity <= index);
9725 Handle<FixedArray> new_array =
9726 array->GetIsolate()->factory()->NewUninitializedFixedArray(capacity);
9727 array->CopyTo(0, *new_array, 0, array->length());
9728 new_array->FillWithHoles(array->length(), new_array->length());
9729 new_array->set(index, *value);
9730 return new_array;
9731 }
9732
Shrink(int new_length)9733 void FixedArray::Shrink(int new_length) {
9734 DCHECK(0 <= new_length && new_length <= length());
9735 if (new_length < length()) {
9736 GetHeap()->RightTrimFixedArray(this, length() - new_length);
9737 }
9738 }
9739
9740
CopyTo(int pos,FixedArray * dest,int dest_pos,int len)9741 void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
9742 DisallowHeapAllocation no_gc;
9743 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
9744 for (int index = 0; index < len; index++) {
9745 dest->set(dest_pos+index, get(pos+index), mode);
9746 }
9747 }
9748
9749 #ifdef DEBUG
IsEqualTo(FixedArray * other)9750 bool FixedArray::IsEqualTo(FixedArray* other) {
9751 if (length() != other->length()) return false;
9752 for (int i = 0 ; i < length(); ++i) {
9753 if (get(i) != other->get(i)) return false;
9754 }
9755 return true;
9756 }
9757 #endif
9758
9759
9760 // static
Set(Handle<WeakFixedArray> array,int index,Handle<HeapObject> value)9761 void WeakFixedArray::Set(Handle<WeakFixedArray> array, int index,
9762 Handle<HeapObject> value) {
9763 DCHECK(array->IsEmptySlot(index)); // Don't overwrite anything.
9764 Handle<WeakCell> cell =
9765 value->IsMap() ? Map::WeakCellForMap(Handle<Map>::cast(value))
9766 : array->GetIsolate()->factory()->NewWeakCell(value);
9767 Handle<FixedArray>::cast(array)->set(index + kFirstIndex, *cell);
9768 if (FLAG_trace_weak_arrays) {
9769 PrintF("[WeakFixedArray: storing at index %d ]\n", index);
9770 }
9771 array->set_last_used_index(index);
9772 }
9773
9774
9775 // static
Add(Handle<Object> maybe_array,Handle<HeapObject> value,int * assigned_index)9776 Handle<WeakFixedArray> WeakFixedArray::Add(Handle<Object> maybe_array,
9777 Handle<HeapObject> value,
9778 int* assigned_index) {
9779 Handle<WeakFixedArray> array =
9780 (maybe_array.is_null() || !maybe_array->IsWeakFixedArray())
9781 ? Allocate(value->GetIsolate(), 1, Handle<WeakFixedArray>::null())
9782 : Handle<WeakFixedArray>::cast(maybe_array);
9783 // Try to store the new entry if there's room. Optimize for consecutive
9784 // accesses.
9785 int first_index = array->last_used_index();
9786 int length = array->Length();
9787 if (length > 0) {
9788 for (int i = first_index;;) {
9789 if (array->IsEmptySlot((i))) {
9790 WeakFixedArray::Set(array, i, value);
9791 if (assigned_index != NULL) *assigned_index = i;
9792 return array;
9793 }
9794 if (FLAG_trace_weak_arrays) {
9795 PrintF("[WeakFixedArray: searching for free slot]\n");
9796 }
9797 i = (i + 1) % length;
9798 if (i == first_index) break;
9799 }
9800 }
9801
9802 // No usable slot found, grow the array.
9803 int new_length = length == 0 ? 1 : length + (length >> 1) + 4;
9804 Handle<WeakFixedArray> new_array =
9805 Allocate(array->GetIsolate(), new_length, array);
9806 if (FLAG_trace_weak_arrays) {
9807 PrintF("[WeakFixedArray: growing to size %d ]\n", new_length);
9808 }
9809 WeakFixedArray::Set(new_array, length, value);
9810 if (assigned_index != NULL) *assigned_index = length;
9811 return new_array;
9812 }
9813
9814
9815 template <class CompactionCallback>
Compact()9816 void WeakFixedArray::Compact() {
9817 FixedArray* array = FixedArray::cast(this);
9818 int new_length = kFirstIndex;
9819 for (int i = kFirstIndex; i < array->length(); i++) {
9820 Object* element = array->get(i);
9821 if (element->IsSmi()) continue;
9822 if (WeakCell::cast(element)->cleared()) continue;
9823 Object* value = WeakCell::cast(element)->value();
9824 CompactionCallback::Callback(value, i - kFirstIndex,
9825 new_length - kFirstIndex);
9826 array->set(new_length++, element);
9827 }
9828 array->Shrink(new_length);
9829 set_last_used_index(0);
9830 }
9831
9832
Reset(Object * maybe_array)9833 void WeakFixedArray::Iterator::Reset(Object* maybe_array) {
9834 if (maybe_array->IsWeakFixedArray()) {
9835 list_ = WeakFixedArray::cast(maybe_array);
9836 index_ = 0;
9837 #ifdef DEBUG
9838 last_used_index_ = list_->last_used_index();
9839 #endif // DEBUG
9840 }
9841 }
9842
9843
Callback(Object * value,int old_index,int new_index)9844 void JSObject::PrototypeRegistryCompactionCallback::Callback(Object* value,
9845 int old_index,
9846 int new_index) {
9847 DCHECK(value->IsMap() && Map::cast(value)->is_prototype_map());
9848 Map* map = Map::cast(value);
9849 DCHECK(map->prototype_info()->IsPrototypeInfo());
9850 PrototypeInfo* proto_info = PrototypeInfo::cast(map->prototype_info());
9851 DCHECK_EQ(old_index, proto_info->registry_slot());
9852 proto_info->set_registry_slot(new_index);
9853 }
9854
9855
9856 template void WeakFixedArray::Compact<WeakFixedArray::NullCallback>();
9857 template void
9858 WeakFixedArray::Compact<JSObject::PrototypeRegistryCompactionCallback>();
9859
9860
Remove(Handle<HeapObject> value)9861 bool WeakFixedArray::Remove(Handle<HeapObject> value) {
9862 if (Length() == 0) return false;
9863 // Optimize for the most recently added element to be removed again.
9864 int first_index = last_used_index();
9865 for (int i = first_index;;) {
9866 if (Get(i) == *value) {
9867 Clear(i);
9868 // Users of WeakFixedArray should make sure that there are no duplicates.
9869 return true;
9870 }
9871 i = (i + 1) % Length();
9872 if (i == first_index) return false;
9873 }
9874 UNREACHABLE();
9875 }
9876
9877
9878 // static
Allocate(Isolate * isolate,int size,Handle<WeakFixedArray> initialize_from)9879 Handle<WeakFixedArray> WeakFixedArray::Allocate(
9880 Isolate* isolate, int size, Handle<WeakFixedArray> initialize_from) {
9881 DCHECK(0 <= size);
9882 Handle<FixedArray> result =
9883 isolate->factory()->NewUninitializedFixedArray(size + kFirstIndex);
9884 int index = 0;
9885 if (!initialize_from.is_null()) {
9886 DCHECK(initialize_from->Length() <= size);
9887 Handle<FixedArray> raw_source = Handle<FixedArray>::cast(initialize_from);
9888 // Copy the entries without compacting, since the PrototypeInfo relies on
9889 // the index of the entries not to change.
9890 while (index < raw_source->length()) {
9891 result->set(index, raw_source->get(index));
9892 index++;
9893 }
9894 }
9895 while (index < result->length()) {
9896 result->set(index, Smi::kZero);
9897 index++;
9898 }
9899 return Handle<WeakFixedArray>::cast(result);
9900 }
9901
9902
Add(Handle<ArrayList> array,Handle<Object> obj,AddMode mode)9903 Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj,
9904 AddMode mode) {
9905 int length = array->Length();
9906 array = EnsureSpace(array, length + 1);
9907 if (mode == kReloadLengthAfterAllocation) {
9908 DCHECK(array->Length() <= length);
9909 length = array->Length();
9910 }
9911 array->Set(length, *obj);
9912 array->SetLength(length + 1);
9913 return array;
9914 }
9915
Add(Handle<ArrayList> array,Handle<Object> obj1,Handle<Object> obj2,AddMode mode)9916 Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj1,
9917 Handle<Object> obj2, AddMode mode) {
9918 int length = array->Length();
9919 array = EnsureSpace(array, length + 2);
9920 if (mode == kReloadLengthAfterAllocation) {
9921 length = array->Length();
9922 }
9923 array->Set(length, *obj1);
9924 array->Set(length + 1, *obj2);
9925 array->SetLength(length + 2);
9926 return array;
9927 }
9928
New(Isolate * isolate,int size)9929 Handle<ArrayList> ArrayList::New(Isolate* isolate, int size) {
9930 Handle<ArrayList> result = Handle<ArrayList>::cast(
9931 isolate->factory()->NewFixedArray(size + kFirstIndex));
9932 result->SetLength(0);
9933 return result;
9934 }
9935
IsFull()9936 bool ArrayList::IsFull() {
9937 int capacity = length();
9938 return kFirstIndex + Length() == capacity;
9939 }
9940
9941 namespace {
9942
EnsureSpaceInFixedArray(Handle<FixedArray> array,int length)9943 Handle<FixedArray> EnsureSpaceInFixedArray(Handle<FixedArray> array,
9944 int length) {
9945 int capacity = array->length();
9946 if (capacity < length) {
9947 Isolate* isolate = array->GetIsolate();
9948 int new_capacity = length;
9949 new_capacity = new_capacity + Max(new_capacity / 2, 2);
9950 int grow_by = new_capacity - capacity;
9951 array = Handle<ArrayList>::cast(
9952 isolate->factory()->CopyFixedArrayAndGrow(array, grow_by));
9953 }
9954 return array;
9955 }
9956
9957 } // namespace
9958
EnsureSpace(Handle<ArrayList> array,int length)9959 Handle<ArrayList> ArrayList::EnsureSpace(Handle<ArrayList> array, int length) {
9960 const bool empty = (array->length() == 0);
9961 auto ret = Handle<ArrayList>::cast(
9962 EnsureSpaceInFixedArray(array, kFirstIndex + length));
9963 if (empty) ret->SetLength(0);
9964 return ret;
9965 }
9966
ReserveCaptures(Handle<RegExpMatchInfo> match_info,int capture_count)9967 Handle<RegExpMatchInfo> RegExpMatchInfo::ReserveCaptures(
9968 Handle<RegExpMatchInfo> match_info, int capture_count) {
9969 DCHECK_GE(match_info->length(), kLastMatchOverhead);
9970 const int required_length = kFirstCaptureIndex + capture_count;
9971 Handle<FixedArray> result =
9972 EnsureSpaceInFixedArray(match_info, required_length);
9973 return Handle<RegExpMatchInfo>::cast(result);
9974 }
9975
9976 // static
AppendJSFrame(Handle<FrameArray> in,Handle<Object> receiver,Handle<JSFunction> function,Handle<AbstractCode> code,int offset,int flags)9977 Handle<FrameArray> FrameArray::AppendJSFrame(Handle<FrameArray> in,
9978 Handle<Object> receiver,
9979 Handle<JSFunction> function,
9980 Handle<AbstractCode> code,
9981 int offset, int flags) {
9982 const int frame_count = in->FrameCount();
9983 const int new_length = LengthFor(frame_count + 1);
9984 Handle<FrameArray> array = EnsureSpace(in, new_length);
9985 array->SetReceiver(frame_count, *receiver);
9986 array->SetFunction(frame_count, *function);
9987 array->SetCode(frame_count, *code);
9988 array->SetOffset(frame_count, Smi::FromInt(offset));
9989 array->SetFlags(frame_count, Smi::FromInt(flags));
9990 array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));
9991 return array;
9992 }
9993
9994 // static
AppendWasmFrame(Handle<FrameArray> in,Handle<Object> wasm_instance,int wasm_function_index,Handle<AbstractCode> code,int offset,int flags)9995 Handle<FrameArray> FrameArray::AppendWasmFrame(Handle<FrameArray> in,
9996 Handle<Object> wasm_instance,
9997 int wasm_function_index,
9998 Handle<AbstractCode> code,
9999 int offset, int flags) {
10000 const int frame_count = in->FrameCount();
10001 const int new_length = LengthFor(frame_count + 1);
10002 Handle<FrameArray> array = EnsureSpace(in, new_length);
10003 array->SetWasmInstance(frame_count, *wasm_instance);
10004 array->SetWasmFunctionIndex(frame_count, Smi::FromInt(wasm_function_index));
10005 array->SetCode(frame_count, *code);
10006 array->SetOffset(frame_count, Smi::FromInt(offset));
10007 array->SetFlags(frame_count, Smi::FromInt(flags));
10008 array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));
10009 return array;
10010 }
10011
ShrinkToFit()10012 void FrameArray::ShrinkToFit() { Shrink(LengthFor(FrameCount())); }
10013
10014 // static
EnsureSpace(Handle<FrameArray> array,int length)10015 Handle<FrameArray> FrameArray::EnsureSpace(Handle<FrameArray> array,
10016 int length) {
10017 return Handle<FrameArray>::cast(EnsureSpaceInFixedArray(array, length));
10018 }
10019
Allocate(Isolate * isolate,int number_of_descriptors,int slack,PretenureFlag pretenure)10020 Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate,
10021 int number_of_descriptors,
10022 int slack,
10023 PretenureFlag pretenure) {
10024 DCHECK(0 <= number_of_descriptors);
10025 Factory* factory = isolate->factory();
10026 // Do not use DescriptorArray::cast on incomplete object.
10027 int size = number_of_descriptors + slack;
10028 if (size == 0) return factory->empty_descriptor_array();
10029 // Allocate the array of keys.
10030 Handle<FixedArray> result =
10031 factory->NewFixedArray(LengthFor(size), pretenure);
10032
10033 result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors));
10034 result->set(kEnumCacheIndex, Smi::kZero);
10035 return Handle<DescriptorArray>::cast(result);
10036 }
10037
ClearEnumCache()10038 void DescriptorArray::ClearEnumCache() { set(kEnumCacheIndex, Smi::kZero); }
10039
Replace(int index,Descriptor * descriptor)10040 void DescriptorArray::Replace(int index, Descriptor* descriptor) {
10041 descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index));
10042 Set(index, descriptor);
10043 }
10044
10045
10046 // static
SetEnumCache(Handle<DescriptorArray> descriptors,Isolate * isolate,Handle<FixedArray> new_cache,Handle<FixedArray> new_index_cache)10047 void DescriptorArray::SetEnumCache(Handle<DescriptorArray> descriptors,
10048 Isolate* isolate,
10049 Handle<FixedArray> new_cache,
10050 Handle<FixedArray> new_index_cache) {
10051 DCHECK(!descriptors->IsEmpty());
10052 FixedArray* bridge_storage;
10053 bool needs_new_enum_cache = !descriptors->HasEnumCache();
10054 if (needs_new_enum_cache) {
10055 bridge_storage = *isolate->factory()->NewFixedArray(
10056 DescriptorArray::kEnumCacheBridgeLength);
10057 } else {
10058 bridge_storage = FixedArray::cast(descriptors->get(kEnumCacheIndex));
10059 }
10060 bridge_storage->set(kEnumCacheBridgeCacheIndex, *new_cache);
10061 bridge_storage->set(
10062 kEnumCacheBridgeIndicesCacheIndex,
10063 new_index_cache.is_null() ? Object::cast(Smi::kZero) : *new_index_cache);
10064 if (needs_new_enum_cache) {
10065 descriptors->set(kEnumCacheIndex, bridge_storage);
10066 }
10067 }
10068
CopyFrom(int index,DescriptorArray * src)10069 void DescriptorArray::CopyFrom(int index, DescriptorArray* src) {
10070 PropertyDetails details = src->GetDetails(index);
10071 Set(index, src->GetKey(index), src->GetValue(index), details);
10072 }
10073
Sort()10074 void DescriptorArray::Sort() {
10075 // In-place heap sort.
10076 int len = number_of_descriptors();
10077 // Reset sorting since the descriptor array might contain invalid pointers.
10078 for (int i = 0; i < len; ++i) SetSortedKey(i, i);
10079 // Bottom-up max-heap construction.
10080 // Index of the last node with children
10081 const int max_parent_index = (len / 2) - 1;
10082 for (int i = max_parent_index; i >= 0; --i) {
10083 int parent_index = i;
10084 const uint32_t parent_hash = GetSortedKey(i)->Hash();
10085 while (parent_index <= max_parent_index) {
10086 int child_index = 2 * parent_index + 1;
10087 uint32_t child_hash = GetSortedKey(child_index)->Hash();
10088 if (child_index + 1 < len) {
10089 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
10090 if (right_child_hash > child_hash) {
10091 child_index++;
10092 child_hash = right_child_hash;
10093 }
10094 }
10095 if (child_hash <= parent_hash) break;
10096 SwapSortedKeys(parent_index, child_index);
10097 // Now element at child_index could be < its children.
10098 parent_index = child_index; // parent_hash remains correct.
10099 }
10100 }
10101
10102 // Extract elements and create sorted array.
10103 for (int i = len - 1; i > 0; --i) {
10104 // Put max element at the back of the array.
10105 SwapSortedKeys(0, i);
10106 // Shift down the new top element.
10107 int parent_index = 0;
10108 const uint32_t parent_hash = GetSortedKey(parent_index)->Hash();
10109 const int max_parent_index = (i / 2) - 1;
10110 while (parent_index <= max_parent_index) {
10111 int child_index = parent_index * 2 + 1;
10112 uint32_t child_hash = GetSortedKey(child_index)->Hash();
10113 if (child_index + 1 < i) {
10114 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
10115 if (right_child_hash > child_hash) {
10116 child_index++;
10117 child_hash = right_child_hash;
10118 }
10119 }
10120 if (child_hash <= parent_hash) break;
10121 SwapSortedKeys(parent_index, child_index);
10122 parent_index = child_index;
10123 }
10124 }
10125 DCHECK(IsSortedNoDuplicates());
10126 }
10127
10128
Copy(Handle<AccessorPair> pair)10129 Handle<AccessorPair> AccessorPair::Copy(Handle<AccessorPair> pair) {
10130 Handle<AccessorPair> copy = pair->GetIsolate()->factory()->NewAccessorPair();
10131 copy->set_getter(pair->getter());
10132 copy->set_setter(pair->setter());
10133 return copy;
10134 }
10135
GetComponent(Handle<AccessorPair> accessor_pair,AccessorComponent component)10136 Handle<Object> AccessorPair::GetComponent(Handle<AccessorPair> accessor_pair,
10137 AccessorComponent component) {
10138 Object* accessor = accessor_pair->get(component);
10139 if (accessor->IsFunctionTemplateInfo()) {
10140 return ApiNatives::InstantiateFunction(
10141 handle(FunctionTemplateInfo::cast(accessor)))
10142 .ToHandleChecked();
10143 }
10144 Isolate* isolate = accessor_pair->GetIsolate();
10145 if (accessor->IsNull(isolate)) {
10146 return isolate->factory()->undefined_value();
10147 }
10148 return handle(accessor, isolate);
10149 }
10150
New(Isolate * isolate,int deopt_entry_count,PretenureFlag pretenure)10151 Handle<DeoptimizationInputData> DeoptimizationInputData::New(
10152 Isolate* isolate, int deopt_entry_count, PretenureFlag pretenure) {
10153 return Handle<DeoptimizationInputData>::cast(
10154 isolate->factory()->NewFixedArray(LengthFor(deopt_entry_count),
10155 pretenure));
10156 }
10157
10158
New(Isolate * isolate,int number_of_deopt_points,PretenureFlag pretenure)10159 Handle<DeoptimizationOutputData> DeoptimizationOutputData::New(
10160 Isolate* isolate,
10161 int number_of_deopt_points,
10162 PretenureFlag pretenure) {
10163 Handle<FixedArray> result;
10164 if (number_of_deopt_points == 0) {
10165 result = isolate->factory()->empty_fixed_array();
10166 } else {
10167 result = isolate->factory()->NewFixedArray(
10168 LengthOfFixedArray(number_of_deopt_points), pretenure);
10169 }
10170 return Handle<DeoptimizationOutputData>::cast(result);
10171 }
10172
GetInlinedFunction(int index)10173 SharedFunctionInfo* DeoptimizationInputData::GetInlinedFunction(int index) {
10174 if (index == -1) {
10175 return SharedFunctionInfo::cast(SharedFunctionInfo());
10176 } else {
10177 return SharedFunctionInfo::cast(LiteralArray()->get(index));
10178 }
10179 }
10180
LookupRange(int pc_offset,int * data_out,CatchPrediction * prediction_out)10181 int HandlerTable::LookupRange(int pc_offset, int* data_out,
10182 CatchPrediction* prediction_out) {
10183 int innermost_handler = -1;
10184 #ifdef DEBUG
10185 // Assuming that ranges are well nested, we don't need to track the innermost
10186 // offsets. This is just to verify that the table is actually well nested.
10187 int innermost_start = std::numeric_limits<int>::min();
10188 int innermost_end = std::numeric_limits<int>::max();
10189 #endif
10190 for (int i = 0; i < length(); i += kRangeEntrySize) {
10191 int start_offset = Smi::cast(get(i + kRangeStartIndex))->value();
10192 int end_offset = Smi::cast(get(i + kRangeEndIndex))->value();
10193 int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value();
10194 int handler_offset = HandlerOffsetField::decode(handler_field);
10195 CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
10196 int handler_data = Smi::cast(get(i + kRangeDataIndex))->value();
10197 if (pc_offset >= start_offset && pc_offset < end_offset) {
10198 DCHECK_GE(start_offset, innermost_start);
10199 DCHECK_LT(end_offset, innermost_end);
10200 innermost_handler = handler_offset;
10201 #ifdef DEBUG
10202 innermost_start = start_offset;
10203 innermost_end = end_offset;
10204 #endif
10205 if (data_out) *data_out = handler_data;
10206 if (prediction_out) *prediction_out = prediction;
10207 }
10208 }
10209 return innermost_handler;
10210 }
10211
10212
10213 // TODO(turbofan): Make sure table is sorted and use binary search.
LookupReturn(int pc_offset)10214 int HandlerTable::LookupReturn(int pc_offset) {
10215 for (int i = 0; i < length(); i += kReturnEntrySize) {
10216 int return_offset = Smi::cast(get(i + kReturnOffsetIndex))->value();
10217 int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value();
10218 if (pc_offset == return_offset) {
10219 return HandlerOffsetField::decode(handler_field);
10220 }
10221 }
10222 return -1;
10223 }
10224
10225
10226 #ifdef DEBUG
IsEqualTo(DescriptorArray * other)10227 bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
10228 if (IsEmpty()) return other->IsEmpty();
10229 if (other->IsEmpty()) return false;
10230 if (length() != other->length()) return false;
10231 for (int i = 0; i < length(); ++i) {
10232 if (get(i) != other->get(i)) return false;
10233 }
10234 return true;
10235 }
10236 #endif
10237
10238 // static
Trim(Handle<String> string,TrimMode mode)10239 Handle<String> String::Trim(Handle<String> string, TrimMode mode) {
10240 Isolate* const isolate = string->GetIsolate();
10241 string = String::Flatten(string);
10242 int const length = string->length();
10243
10244 // Perform left trimming if requested.
10245 int left = 0;
10246 UnicodeCache* unicode_cache = isolate->unicode_cache();
10247 if (mode == kTrim || mode == kTrimLeft) {
10248 while (left < length &&
10249 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) {
10250 left++;
10251 }
10252 }
10253
10254 // Perform right trimming if requested.
10255 int right = length;
10256 if (mode == kTrim || mode == kTrimRight) {
10257 while (
10258 right > left &&
10259 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) {
10260 right--;
10261 }
10262 }
10263
10264 return isolate->factory()->NewSubString(string, left, right);
10265 }
10266
LooksValid()10267 bool String::LooksValid() { return GetIsolate()->heap()->Contains(this); }
10268
10269 // static
ToFunctionName(Handle<Name> name)10270 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) {
10271 if (name->IsString()) return Handle<String>::cast(name);
10272 // ES6 section 9.2.11 SetFunctionName, step 4.
10273 Isolate* const isolate = name->GetIsolate();
10274 Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate);
10275 if (description->IsUndefined(isolate)) {
10276 return isolate->factory()->empty_string();
10277 }
10278 IncrementalStringBuilder builder(isolate);
10279 builder.AppendCharacter('[');
10280 builder.AppendString(Handle<String>::cast(description));
10281 builder.AppendCharacter(']');
10282 return builder.Finish();
10283 }
10284
10285 // static
ToFunctionName(Handle<Name> name,Handle<String> prefix)10286 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name,
10287 Handle<String> prefix) {
10288 Handle<String> name_string;
10289 Isolate* const isolate = name->GetIsolate();
10290 ASSIGN_RETURN_ON_EXCEPTION(isolate, name_string, ToFunctionName(name),
10291 String);
10292 IncrementalStringBuilder builder(isolate);
10293 builder.AppendString(prefix);
10294 builder.AppendCharacter(' ');
10295 builder.AppendString(name_string);
10296 return builder.Finish();
10297 }
10298
10299 namespace {
10300
AreDigits(const uint8_t * s,int from,int to)10301 bool AreDigits(const uint8_t* s, int from, int to) {
10302 for (int i = from; i < to; i++) {
10303 if (s[i] < '0' || s[i] > '9') return false;
10304 }
10305
10306 return true;
10307 }
10308
10309
ParseDecimalInteger(const uint8_t * s,int from,int to)10310 int ParseDecimalInteger(const uint8_t* s, int from, int to) {
10311 DCHECK(to - from < 10); // Overflow is not possible.
10312 DCHECK(from < to);
10313 int d = s[from] - '0';
10314
10315 for (int i = from + 1; i < to; i++) {
10316 d = 10 * d + (s[i] - '0');
10317 }
10318
10319 return d;
10320 }
10321
10322 } // namespace
10323
10324
10325 // static
ToNumber(Handle<String> subject)10326 Handle<Object> String::ToNumber(Handle<String> subject) {
10327 Isolate* const isolate = subject->GetIsolate();
10328
10329 // Flatten {subject} string first.
10330 subject = String::Flatten(subject);
10331
10332 // Fast array index case.
10333 uint32_t index;
10334 if (subject->AsArrayIndex(&index)) {
10335 return isolate->factory()->NewNumberFromUint(index);
10336 }
10337
10338 // Fast case: short integer or some sorts of junk values.
10339 if (subject->IsSeqOneByteString()) {
10340 int len = subject->length();
10341 if (len == 0) return handle(Smi::kZero, isolate);
10342
10343 DisallowHeapAllocation no_gc;
10344 uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars();
10345 bool minus = (data[0] == '-');
10346 int start_pos = (minus ? 1 : 0);
10347
10348 if (start_pos == len) {
10349 return isolate->factory()->nan_value();
10350 } else if (data[start_pos] > '9') {
10351 // Fast check for a junk value. A valid string may start from a
10352 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit
10353 // or the 'I' character ('Infinity'). All of that have codes not greater
10354 // than '9' except 'I' and .
10355 if (data[start_pos] != 'I' && data[start_pos] != 0xa0) {
10356 return isolate->factory()->nan_value();
10357 }
10358 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
10359 // The maximal/minimal smi has 10 digits. If the string has less digits
10360 // we know it will fit into the smi-data type.
10361 int d = ParseDecimalInteger(data, start_pos, len);
10362 if (minus) {
10363 if (d == 0) return isolate->factory()->minus_zero_value();
10364 d = -d;
10365 } else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize &&
10366 (len == 1 || data[0] != '0')) {
10367 // String hash is not calculated yet but all the data are present.
10368 // Update the hash field to speed up sequential convertions.
10369 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
10370 #ifdef DEBUG
10371 subject->Hash(); // Force hash calculation.
10372 DCHECK_EQ(static_cast<int>(subject->hash_field()),
10373 static_cast<int>(hash));
10374 #endif
10375 subject->set_hash_field(hash);
10376 }
10377 return handle(Smi::FromInt(d), isolate);
10378 }
10379 }
10380
10381 // Slower case.
10382 int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY;
10383 return isolate->factory()->NewNumber(
10384 StringToDouble(isolate->unicode_cache(), subject, flags));
10385 }
10386
10387
GetFlatContent()10388 String::FlatContent String::GetFlatContent() {
10389 DCHECK(!AllowHeapAllocation::IsAllowed());
10390 int length = this->length();
10391 StringShape shape(this);
10392 String* string = this;
10393 int offset = 0;
10394 if (shape.representation_tag() == kConsStringTag) {
10395 ConsString* cons = ConsString::cast(string);
10396 if (cons->second()->length() != 0) {
10397 return FlatContent();
10398 }
10399 string = cons->first();
10400 shape = StringShape(string);
10401 } else if (shape.representation_tag() == kSlicedStringTag) {
10402 SlicedString* slice = SlicedString::cast(string);
10403 offset = slice->offset();
10404 string = slice->parent();
10405 shape = StringShape(string);
10406 DCHECK(shape.representation_tag() != kConsStringTag &&
10407 shape.representation_tag() != kSlicedStringTag);
10408 }
10409 if (shape.representation_tag() == kThinStringTag) {
10410 ThinString* thin = ThinString::cast(string);
10411 string = thin->actual();
10412 shape = StringShape(string);
10413 DCHECK(!shape.IsCons());
10414 DCHECK(!shape.IsSliced());
10415 }
10416 if (shape.encoding_tag() == kOneByteStringTag) {
10417 const uint8_t* start;
10418 if (shape.representation_tag() == kSeqStringTag) {
10419 start = SeqOneByteString::cast(string)->GetChars();
10420 } else {
10421 start = ExternalOneByteString::cast(string)->GetChars();
10422 }
10423 return FlatContent(start + offset, length);
10424 } else {
10425 DCHECK(shape.encoding_tag() == kTwoByteStringTag);
10426 const uc16* start;
10427 if (shape.representation_tag() == kSeqStringTag) {
10428 start = SeqTwoByteString::cast(string)->GetChars();
10429 } else {
10430 start = ExternalTwoByteString::cast(string)->GetChars();
10431 }
10432 return FlatContent(start + offset, length);
10433 }
10434 }
10435
ToCString(AllowNullsFlag allow_nulls,RobustnessFlag robust_flag,int offset,int length,int * length_return)10436 std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
10437 RobustnessFlag robust_flag,
10438 int offset, int length,
10439 int* length_return) {
10440 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
10441 return std::unique_ptr<char[]>();
10442 }
10443 // Negative length means the to the end of the string.
10444 if (length < 0) length = kMaxInt - offset;
10445
10446 // Compute the size of the UTF-8 string. Start at the specified offset.
10447 StringCharacterStream stream(this, offset);
10448 int character_position = offset;
10449 int utf8_bytes = 0;
10450 int last = unibrow::Utf16::kNoPreviousCharacter;
10451 while (stream.HasMore() && character_position++ < offset + length) {
10452 uint16_t character = stream.GetNext();
10453 utf8_bytes += unibrow::Utf8::Length(character, last);
10454 last = character;
10455 }
10456
10457 if (length_return) {
10458 *length_return = utf8_bytes;
10459 }
10460
10461 char* result = NewArray<char>(utf8_bytes + 1);
10462
10463 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
10464 stream.Reset(this, offset);
10465 character_position = offset;
10466 int utf8_byte_position = 0;
10467 last = unibrow::Utf16::kNoPreviousCharacter;
10468 while (stream.HasMore() && character_position++ < offset + length) {
10469 uint16_t character = stream.GetNext();
10470 if (allow_nulls == DISALLOW_NULLS && character == 0) {
10471 character = ' ';
10472 }
10473 utf8_byte_position +=
10474 unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
10475 last = character;
10476 }
10477 result[utf8_byte_position] = 0;
10478 return std::unique_ptr<char[]>(result);
10479 }
10480
ToCString(AllowNullsFlag allow_nulls,RobustnessFlag robust_flag,int * length_return)10481 std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
10482 RobustnessFlag robust_flag,
10483 int* length_return) {
10484 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
10485 }
10486
10487
GetTwoByteData(unsigned start)10488 const uc16* String::GetTwoByteData(unsigned start) {
10489 DCHECK(!IsOneByteRepresentationUnderneath());
10490 switch (StringShape(this).representation_tag()) {
10491 case kSeqStringTag:
10492 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
10493 case kExternalStringTag:
10494 return ExternalTwoByteString::cast(this)->
10495 ExternalTwoByteStringGetData(start);
10496 case kSlicedStringTag: {
10497 SlicedString* slice = SlicedString::cast(this);
10498 return slice->parent()->GetTwoByteData(start + slice->offset());
10499 }
10500 case kConsStringTag:
10501 case kThinStringTag:
10502 UNREACHABLE();
10503 return NULL;
10504 }
10505 UNREACHABLE();
10506 return NULL;
10507 }
10508
10509
SeqTwoByteStringGetData(unsigned start)10510 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
10511 return reinterpret_cast<uc16*>(
10512 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
10513 }
10514
10515
PostGarbageCollectionProcessing(Isolate * isolate)10516 void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) {
10517 Relocatable* current = isolate->relocatable_top();
10518 while (current != NULL) {
10519 current->PostGarbageCollection();
10520 current = current->prev_;
10521 }
10522 }
10523
10524
10525 // Reserve space for statics needing saving and restoring.
ArchiveSpacePerThread()10526 int Relocatable::ArchiveSpacePerThread() {
10527 return sizeof(Relocatable*); // NOLINT
10528 }
10529
10530
10531 // Archive statics that are thread-local.
ArchiveState(Isolate * isolate,char * to)10532 char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
10533 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
10534 isolate->set_relocatable_top(NULL);
10535 return to + ArchiveSpacePerThread();
10536 }
10537
10538
10539 // Restore statics that are thread-local.
RestoreState(Isolate * isolate,char * from)10540 char* Relocatable::RestoreState(Isolate* isolate, char* from) {
10541 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
10542 return from + ArchiveSpacePerThread();
10543 }
10544
10545
Iterate(ObjectVisitor * v,char * thread_storage)10546 char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
10547 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
10548 Iterate(v, top);
10549 return thread_storage + ArchiveSpacePerThread();
10550 }
10551
10552
Iterate(Isolate * isolate,ObjectVisitor * v)10553 void Relocatable::Iterate(Isolate* isolate, ObjectVisitor* v) {
10554 Iterate(v, isolate->relocatable_top());
10555 }
10556
10557
Iterate(ObjectVisitor * v,Relocatable * top)10558 void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
10559 Relocatable* current = top;
10560 while (current != NULL) {
10561 current->IterateInstance(v);
10562 current = current->prev_;
10563 }
10564 }
10565
10566
FlatStringReader(Isolate * isolate,Handle<String> str)10567 FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
10568 : Relocatable(isolate),
10569 str_(str.location()),
10570 length_(str->length()) {
10571 PostGarbageCollection();
10572 }
10573
10574
FlatStringReader(Isolate * isolate,Vector<const char> input)10575 FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
10576 : Relocatable(isolate),
10577 str_(0),
10578 is_one_byte_(true),
10579 length_(input.length()),
10580 start_(input.start()) {}
10581
10582
PostGarbageCollection()10583 void FlatStringReader::PostGarbageCollection() {
10584 if (str_ == NULL) return;
10585 Handle<String> str(str_);
10586 DCHECK(str->IsFlat());
10587 DisallowHeapAllocation no_gc;
10588 // This does not actually prevent the vector from being relocated later.
10589 String::FlatContent content = str->GetFlatContent();
10590 DCHECK(content.IsFlat());
10591 is_one_byte_ = content.IsOneByte();
10592 if (is_one_byte_) {
10593 start_ = content.ToOneByteVector().start();
10594 } else {
10595 start_ = content.ToUC16Vector().start();
10596 }
10597 }
10598
10599
Initialize(ConsString * cons_string,int offset)10600 void ConsStringIterator::Initialize(ConsString* cons_string, int offset) {
10601 DCHECK(cons_string != NULL);
10602 root_ = cons_string;
10603 consumed_ = offset;
10604 // Force stack blown condition to trigger restart.
10605 depth_ = 1;
10606 maximum_depth_ = kStackSize + depth_;
10607 DCHECK(StackBlown());
10608 }
10609
10610
Continue(int * offset_out)10611 String* ConsStringIterator::Continue(int* offset_out) {
10612 DCHECK(depth_ != 0);
10613 DCHECK_EQ(0, *offset_out);
10614 bool blew_stack = StackBlown();
10615 String* string = NULL;
10616 // Get the next leaf if there is one.
10617 if (!blew_stack) string = NextLeaf(&blew_stack);
10618 // Restart search from root.
10619 if (blew_stack) {
10620 DCHECK(string == NULL);
10621 string = Search(offset_out);
10622 }
10623 // Ensure future calls return null immediately.
10624 if (string == NULL) Reset(NULL);
10625 return string;
10626 }
10627
10628
Search(int * offset_out)10629 String* ConsStringIterator::Search(int* offset_out) {
10630 ConsString* cons_string = root_;
10631 // Reset the stack, pushing the root string.
10632 depth_ = 1;
10633 maximum_depth_ = 1;
10634 frames_[0] = cons_string;
10635 const int consumed = consumed_;
10636 int offset = 0;
10637 while (true) {
10638 // Loop until the string is found which contains the target offset.
10639 String* string = cons_string->first();
10640 int length = string->length();
10641 int32_t type;
10642 if (consumed < offset + length) {
10643 // Target offset is in the left branch.
10644 // Keep going if we're still in a ConString.
10645 type = string->map()->instance_type();
10646 if ((type & kStringRepresentationMask) == kConsStringTag) {
10647 cons_string = ConsString::cast(string);
10648 PushLeft(cons_string);
10649 continue;
10650 }
10651 // Tell the stack we're done descending.
10652 AdjustMaximumDepth();
10653 } else {
10654 // Descend right.
10655 // Update progress through the string.
10656 offset += length;
10657 // Keep going if we're still in a ConString.
10658 string = cons_string->second();
10659 type = string->map()->instance_type();
10660 if ((type & kStringRepresentationMask) == kConsStringTag) {
10661 cons_string = ConsString::cast(string);
10662 PushRight(cons_string);
10663 continue;
10664 }
10665 // Need this to be updated for the current string.
10666 length = string->length();
10667 // Account for the possibility of an empty right leaf.
10668 // This happens only if we have asked for an offset outside the string.
10669 if (length == 0) {
10670 // Reset so future operations will return null immediately.
10671 Reset(NULL);
10672 return NULL;
10673 }
10674 // Tell the stack we're done descending.
10675 AdjustMaximumDepth();
10676 // Pop stack so next iteration is in correct place.
10677 Pop();
10678 }
10679 DCHECK(length != 0);
10680 // Adjust return values and exit.
10681 consumed_ = offset + length;
10682 *offset_out = consumed - offset;
10683 return string;
10684 }
10685 UNREACHABLE();
10686 return NULL;
10687 }
10688
10689
NextLeaf(bool * blew_stack)10690 String* ConsStringIterator::NextLeaf(bool* blew_stack) {
10691 while (true) {
10692 // Tree traversal complete.
10693 if (depth_ == 0) {
10694 *blew_stack = false;
10695 return NULL;
10696 }
10697 // We've lost track of higher nodes.
10698 if (StackBlown()) {
10699 *blew_stack = true;
10700 return NULL;
10701 }
10702 // Go right.
10703 ConsString* cons_string = frames_[OffsetForDepth(depth_ - 1)];
10704 String* string = cons_string->second();
10705 int32_t type = string->map()->instance_type();
10706 if ((type & kStringRepresentationMask) != kConsStringTag) {
10707 // Pop stack so next iteration is in correct place.
10708 Pop();
10709 int length = string->length();
10710 // Could be a flattened ConsString.
10711 if (length == 0) continue;
10712 consumed_ += length;
10713 return string;
10714 }
10715 cons_string = ConsString::cast(string);
10716 PushRight(cons_string);
10717 // Need to traverse all the way left.
10718 while (true) {
10719 // Continue left.
10720 string = cons_string->first();
10721 type = string->map()->instance_type();
10722 if ((type & kStringRepresentationMask) != kConsStringTag) {
10723 AdjustMaximumDepth();
10724 int length = string->length();
10725 if (length == 0) break; // Skip empty left-hand sides of ConsStrings.
10726 consumed_ += length;
10727 return string;
10728 }
10729 cons_string = ConsString::cast(string);
10730 PushLeft(cons_string);
10731 }
10732 }
10733 UNREACHABLE();
10734 return NULL;
10735 }
10736
10737
ConsStringGet(int index)10738 uint16_t ConsString::ConsStringGet(int index) {
10739 DCHECK(index >= 0 && index < this->length());
10740
10741 // Check for a flattened cons string
10742 if (second()->length() == 0) {
10743 String* left = first();
10744 return left->Get(index);
10745 }
10746
10747 String* string = String::cast(this);
10748
10749 while (true) {
10750 if (StringShape(string).IsCons()) {
10751 ConsString* cons_string = ConsString::cast(string);
10752 String* left = cons_string->first();
10753 if (left->length() > index) {
10754 string = left;
10755 } else {
10756 index -= left->length();
10757 string = cons_string->second();
10758 }
10759 } else {
10760 return string->Get(index);
10761 }
10762 }
10763
10764 UNREACHABLE();
10765 return 0;
10766 }
10767
ThinStringGet(int index)10768 uint16_t ThinString::ThinStringGet(int index) { return actual()->Get(index); }
10769
SlicedStringGet(int index)10770 uint16_t SlicedString::SlicedStringGet(int index) {
10771 return parent()->Get(offset() + index);
10772 }
10773
10774
10775 template <typename sinkchar>
WriteToFlat(String * src,sinkchar * sink,int f,int t)10776 void String::WriteToFlat(String* src,
10777 sinkchar* sink,
10778 int f,
10779 int t) {
10780 String* source = src;
10781 int from = f;
10782 int to = t;
10783 while (true) {
10784 DCHECK(0 <= from && from <= to && to <= source->length());
10785 switch (StringShape(source).full_representation_tag()) {
10786 case kOneByteStringTag | kExternalStringTag: {
10787 CopyChars(sink, ExternalOneByteString::cast(source)->GetChars() + from,
10788 to - from);
10789 return;
10790 }
10791 case kTwoByteStringTag | kExternalStringTag: {
10792 const uc16* data =
10793 ExternalTwoByteString::cast(source)->GetChars();
10794 CopyChars(sink,
10795 data + from,
10796 to - from);
10797 return;
10798 }
10799 case kOneByteStringTag | kSeqStringTag: {
10800 CopyChars(sink,
10801 SeqOneByteString::cast(source)->GetChars() + from,
10802 to - from);
10803 return;
10804 }
10805 case kTwoByteStringTag | kSeqStringTag: {
10806 CopyChars(sink,
10807 SeqTwoByteString::cast(source)->GetChars() + from,
10808 to - from);
10809 return;
10810 }
10811 case kOneByteStringTag | kConsStringTag:
10812 case kTwoByteStringTag | kConsStringTag: {
10813 ConsString* cons_string = ConsString::cast(source);
10814 String* first = cons_string->first();
10815 int boundary = first->length();
10816 if (to - boundary >= boundary - from) {
10817 // Right hand side is longer. Recurse over left.
10818 if (from < boundary) {
10819 WriteToFlat(first, sink, from, boundary);
10820 if (from == 0 && cons_string->second() == first) {
10821 CopyChars(sink + boundary, sink, boundary);
10822 return;
10823 }
10824 sink += boundary - from;
10825 from = 0;
10826 } else {
10827 from -= boundary;
10828 }
10829 to -= boundary;
10830 source = cons_string->second();
10831 } else {
10832 // Left hand side is longer. Recurse over right.
10833 if (to > boundary) {
10834 String* second = cons_string->second();
10835 // When repeatedly appending to a string, we get a cons string that
10836 // is unbalanced to the left, a list, essentially. We inline the
10837 // common case of sequential one-byte right child.
10838 if (to - boundary == 1) {
10839 sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
10840 } else if (second->IsSeqOneByteString()) {
10841 CopyChars(sink + boundary - from,
10842 SeqOneByteString::cast(second)->GetChars(),
10843 to - boundary);
10844 } else {
10845 WriteToFlat(second,
10846 sink + boundary - from,
10847 0,
10848 to - boundary);
10849 }
10850 to = boundary;
10851 }
10852 source = first;
10853 }
10854 break;
10855 }
10856 case kOneByteStringTag | kSlicedStringTag:
10857 case kTwoByteStringTag | kSlicedStringTag: {
10858 SlicedString* slice = SlicedString::cast(source);
10859 unsigned offset = slice->offset();
10860 WriteToFlat(slice->parent(), sink, from + offset, to + offset);
10861 return;
10862 }
10863 case kOneByteStringTag | kThinStringTag:
10864 case kTwoByteStringTag | kThinStringTag:
10865 source = ThinString::cast(source)->actual();
10866 break;
10867 }
10868 }
10869 }
10870
10871
10872
10873 template <typename SourceChar>
CalculateLineEndsImpl(Isolate * isolate,List<int> * line_ends,Vector<const SourceChar> src,bool include_ending_line)10874 static void CalculateLineEndsImpl(Isolate* isolate,
10875 List<int>* line_ends,
10876 Vector<const SourceChar> src,
10877 bool include_ending_line) {
10878 const int src_len = src.length();
10879 UnicodeCache* cache = isolate->unicode_cache();
10880 for (int i = 0; i < src_len - 1; i++) {
10881 SourceChar current = src[i];
10882 SourceChar next = src[i + 1];
10883 if (cache->IsLineTerminatorSequence(current, next)) line_ends->Add(i);
10884 }
10885
10886 if (src_len > 0 && cache->IsLineTerminatorSequence(src[src_len - 1], 0)) {
10887 line_ends->Add(src_len - 1);
10888 }
10889 if (include_ending_line) {
10890 // Include one character beyond the end of script. The rewriter uses that
10891 // position for the implicit return statement.
10892 line_ends->Add(src_len);
10893 }
10894 }
10895
10896
CalculateLineEnds(Handle<String> src,bool include_ending_line)10897 Handle<FixedArray> String::CalculateLineEnds(Handle<String> src,
10898 bool include_ending_line) {
10899 src = Flatten(src);
10900 // Rough estimate of line count based on a roughly estimated average
10901 // length of (unpacked) code.
10902 int line_count_estimate = src->length() >> 4;
10903 List<int> line_ends(line_count_estimate);
10904 Isolate* isolate = src->GetIsolate();
10905 { DisallowHeapAllocation no_allocation; // ensure vectors stay valid.
10906 // Dispatch on type of strings.
10907 String::FlatContent content = src->GetFlatContent();
10908 DCHECK(content.IsFlat());
10909 if (content.IsOneByte()) {
10910 CalculateLineEndsImpl(isolate,
10911 &line_ends,
10912 content.ToOneByteVector(),
10913 include_ending_line);
10914 } else {
10915 CalculateLineEndsImpl(isolate,
10916 &line_ends,
10917 content.ToUC16Vector(),
10918 include_ending_line);
10919 }
10920 }
10921 int line_count = line_ends.length();
10922 Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count);
10923 for (int i = 0; i < line_count; i++) {
10924 array->set(i, Smi::FromInt(line_ends[i]));
10925 }
10926 return array;
10927 }
10928
10929
10930 // Compares the contents of two strings by reading and comparing
10931 // int-sized blocks of characters.
10932 template <typename Char>
CompareRawStringContents(const Char * const a,const Char * const b,int length)10933 static inline bool CompareRawStringContents(const Char* const a,
10934 const Char* const b,
10935 int length) {
10936 return CompareChars(a, b, length) == 0;
10937 }
10938
10939
10940 template<typename Chars1, typename Chars2>
10941 class RawStringComparator : public AllStatic {
10942 public:
compare(const Chars1 * a,const Chars2 * b,int len)10943 static inline bool compare(const Chars1* a, const Chars2* b, int len) {
10944 DCHECK(sizeof(Chars1) != sizeof(Chars2));
10945 for (int i = 0; i < len; i++) {
10946 if (a[i] != b[i]) {
10947 return false;
10948 }
10949 }
10950 return true;
10951 }
10952 };
10953
10954
10955 template<>
10956 class RawStringComparator<uint16_t, uint16_t> {
10957 public:
compare(const uint16_t * a,const uint16_t * b,int len)10958 static inline bool compare(const uint16_t* a, const uint16_t* b, int len) {
10959 return CompareRawStringContents(a, b, len);
10960 }
10961 };
10962
10963
10964 template<>
10965 class RawStringComparator<uint8_t, uint8_t> {
10966 public:
compare(const uint8_t * a,const uint8_t * b,int len)10967 static inline bool compare(const uint8_t* a, const uint8_t* b, int len) {
10968 return CompareRawStringContents(a, b, len);
10969 }
10970 };
10971
10972
10973 class StringComparator {
10974 class State {
10975 public:
State()10976 State() : is_one_byte_(true), length_(0), buffer8_(NULL) {}
10977
Init(String * string)10978 void Init(String* string) {
10979 ConsString* cons_string = String::VisitFlat(this, string);
10980 iter_.Reset(cons_string);
10981 if (cons_string != NULL) {
10982 int offset;
10983 string = iter_.Next(&offset);
10984 String::VisitFlat(this, string, offset);
10985 }
10986 }
10987
VisitOneByteString(const uint8_t * chars,int length)10988 inline void VisitOneByteString(const uint8_t* chars, int length) {
10989 is_one_byte_ = true;
10990 buffer8_ = chars;
10991 length_ = length;
10992 }
10993
VisitTwoByteString(const uint16_t * chars,int length)10994 inline void VisitTwoByteString(const uint16_t* chars, int length) {
10995 is_one_byte_ = false;
10996 buffer16_ = chars;
10997 length_ = length;
10998 }
10999
Advance(int consumed)11000 void Advance(int consumed) {
11001 DCHECK(consumed <= length_);
11002 // Still in buffer.
11003 if (length_ != consumed) {
11004 if (is_one_byte_) {
11005 buffer8_ += consumed;
11006 } else {
11007 buffer16_ += consumed;
11008 }
11009 length_ -= consumed;
11010 return;
11011 }
11012 // Advance state.
11013 int offset;
11014 String* next = iter_.Next(&offset);
11015 DCHECK_EQ(0, offset);
11016 DCHECK(next != NULL);
11017 String::VisitFlat(this, next);
11018 }
11019
11020 ConsStringIterator iter_;
11021 bool is_one_byte_;
11022 int length_;
11023 union {
11024 const uint8_t* buffer8_;
11025 const uint16_t* buffer16_;
11026 };
11027
11028 private:
11029 DISALLOW_COPY_AND_ASSIGN(State);
11030 };
11031
11032 public:
StringComparator()11033 inline StringComparator() {}
11034
11035 template<typename Chars1, typename Chars2>
Equals(State * state_1,State * state_2,int to_check)11036 static inline bool Equals(State* state_1, State* state_2, int to_check) {
11037 const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_);
11038 const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_);
11039 return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check);
11040 }
11041
Equals(String * string_1,String * string_2)11042 bool Equals(String* string_1, String* string_2) {
11043 int length = string_1->length();
11044 state_1_.Init(string_1);
11045 state_2_.Init(string_2);
11046 while (true) {
11047 int to_check = Min(state_1_.length_, state_2_.length_);
11048 DCHECK(to_check > 0 && to_check <= length);
11049 bool is_equal;
11050 if (state_1_.is_one_byte_) {
11051 if (state_2_.is_one_byte_) {
11052 is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check);
11053 } else {
11054 is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check);
11055 }
11056 } else {
11057 if (state_2_.is_one_byte_) {
11058 is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check);
11059 } else {
11060 is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check);
11061 }
11062 }
11063 // Looping done.
11064 if (!is_equal) return false;
11065 length -= to_check;
11066 // Exit condition. Strings are equal.
11067 if (length == 0) return true;
11068 state_1_.Advance(to_check);
11069 state_2_.Advance(to_check);
11070 }
11071 }
11072
11073 private:
11074 State state_1_;
11075 State state_2_;
11076
11077 DISALLOW_COPY_AND_ASSIGN(StringComparator);
11078 };
11079
11080
SlowEquals(String * other)11081 bool String::SlowEquals(String* other) {
11082 DisallowHeapAllocation no_gc;
11083 // Fast check: negative check with lengths.
11084 int len = length();
11085 if (len != other->length()) return false;
11086 if (len == 0) return true;
11087
11088 // Fast check: if at least one ThinString is involved, dereference it/them
11089 // and restart.
11090 if (this->IsThinString() || other->IsThinString()) {
11091 if (other->IsThinString()) other = ThinString::cast(other)->actual();
11092 if (this->IsThinString()) {
11093 return ThinString::cast(this)->actual()->Equals(other);
11094 } else {
11095 return this->Equals(other);
11096 }
11097 }
11098
11099 // Fast check: if hash code is computed for both strings
11100 // a fast negative check can be performed.
11101 if (HasHashCode() && other->HasHashCode()) {
11102 #ifdef ENABLE_SLOW_DCHECKS
11103 if (FLAG_enable_slow_asserts) {
11104 if (Hash() != other->Hash()) {
11105 bool found_difference = false;
11106 for (int i = 0; i < len; i++) {
11107 if (Get(i) != other->Get(i)) {
11108 found_difference = true;
11109 break;
11110 }
11111 }
11112 DCHECK(found_difference);
11113 }
11114 }
11115 #endif
11116 if (Hash() != other->Hash()) return false;
11117 }
11118
11119 // We know the strings are both non-empty. Compare the first chars
11120 // before we try to flatten the strings.
11121 if (this->Get(0) != other->Get(0)) return false;
11122
11123 if (IsSeqOneByteString() && other->IsSeqOneByteString()) {
11124 const uint8_t* str1 = SeqOneByteString::cast(this)->GetChars();
11125 const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars();
11126 return CompareRawStringContents(str1, str2, len);
11127 }
11128
11129 StringComparator comparator;
11130 return comparator.Equals(this, other);
11131 }
11132
11133
SlowEquals(Handle<String> one,Handle<String> two)11134 bool String::SlowEquals(Handle<String> one, Handle<String> two) {
11135 // Fast check: negative check with lengths.
11136 int one_length = one->length();
11137 if (one_length != two->length()) return false;
11138 if (one_length == 0) return true;
11139
11140 // Fast check: if at least one ThinString is involved, dereference it/them
11141 // and restart.
11142 if (one->IsThinString() || two->IsThinString()) {
11143 if (one->IsThinString()) one = handle(ThinString::cast(*one)->actual());
11144 if (two->IsThinString()) two = handle(ThinString::cast(*two)->actual());
11145 return String::Equals(one, two);
11146 }
11147
11148 // Fast check: if hash code is computed for both strings
11149 // a fast negative check can be performed.
11150 if (one->HasHashCode() && two->HasHashCode()) {
11151 #ifdef ENABLE_SLOW_DCHECKS
11152 if (FLAG_enable_slow_asserts) {
11153 if (one->Hash() != two->Hash()) {
11154 bool found_difference = false;
11155 for (int i = 0; i < one_length; i++) {
11156 if (one->Get(i) != two->Get(i)) {
11157 found_difference = true;
11158 break;
11159 }
11160 }
11161 DCHECK(found_difference);
11162 }
11163 }
11164 #endif
11165 if (one->Hash() != two->Hash()) return false;
11166 }
11167
11168 // We know the strings are both non-empty. Compare the first chars
11169 // before we try to flatten the strings.
11170 if (one->Get(0) != two->Get(0)) return false;
11171
11172 one = String::Flatten(one);
11173 two = String::Flatten(two);
11174
11175 DisallowHeapAllocation no_gc;
11176 String::FlatContent flat1 = one->GetFlatContent();
11177 String::FlatContent flat2 = two->GetFlatContent();
11178
11179 if (flat1.IsOneByte() && flat2.IsOneByte()) {
11180 return CompareRawStringContents(flat1.ToOneByteVector().start(),
11181 flat2.ToOneByteVector().start(),
11182 one_length);
11183 } else {
11184 for (int i = 0; i < one_length; i++) {
11185 if (flat1.Get(i) != flat2.Get(i)) return false;
11186 }
11187 return true;
11188 }
11189 }
11190
11191
11192 // static
Compare(Handle<String> x,Handle<String> y)11193 ComparisonResult String::Compare(Handle<String> x, Handle<String> y) {
11194 // A few fast case tests before we flatten.
11195 if (x.is_identical_to(y)) {
11196 return ComparisonResult::kEqual;
11197 } else if (y->length() == 0) {
11198 return x->length() == 0 ? ComparisonResult::kEqual
11199 : ComparisonResult::kGreaterThan;
11200 } else if (x->length() == 0) {
11201 return ComparisonResult::kLessThan;
11202 }
11203
11204 int const d = x->Get(0) - y->Get(0);
11205 if (d < 0) {
11206 return ComparisonResult::kLessThan;
11207 } else if (d > 0) {
11208 return ComparisonResult::kGreaterThan;
11209 }
11210
11211 // Slow case.
11212 x = String::Flatten(x);
11213 y = String::Flatten(y);
11214
11215 DisallowHeapAllocation no_gc;
11216 ComparisonResult result = ComparisonResult::kEqual;
11217 int prefix_length = x->length();
11218 if (y->length() < prefix_length) {
11219 prefix_length = y->length();
11220 result = ComparisonResult::kGreaterThan;
11221 } else if (y->length() > prefix_length) {
11222 result = ComparisonResult::kLessThan;
11223 }
11224 int r;
11225 String::FlatContent x_content = x->GetFlatContent();
11226 String::FlatContent y_content = y->GetFlatContent();
11227 if (x_content.IsOneByte()) {
11228 Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
11229 if (y_content.IsOneByte()) {
11230 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11231 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11232 } else {
11233 Vector<const uc16> y_chars = y_content.ToUC16Vector();
11234 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11235 }
11236 } else {
11237 Vector<const uc16> x_chars = x_content.ToUC16Vector();
11238 if (y_content.IsOneByte()) {
11239 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11240 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11241 } else {
11242 Vector<const uc16> y_chars = y_content.ToUC16Vector();
11243 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
11244 }
11245 }
11246 if (r < 0) {
11247 result = ComparisonResult::kLessThan;
11248 } else if (r > 0) {
11249 result = ComparisonResult::kGreaterThan;
11250 }
11251 return result;
11252 }
11253
IndexOf(Isolate * isolate,Handle<Object> receiver,Handle<Object> search,Handle<Object> position)11254 Object* String::IndexOf(Isolate* isolate, Handle<Object> receiver,
11255 Handle<Object> search, Handle<Object> position) {
11256 if (receiver->IsNullOrUndefined(isolate)) {
11257 THROW_NEW_ERROR_RETURN_FAILURE(
11258 isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
11259 isolate->factory()->NewStringFromAsciiChecked(
11260 "String.prototype.indexOf")));
11261 }
11262 Handle<String> receiver_string;
11263 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string,
11264 Object::ToString(isolate, receiver));
11265
11266 Handle<String> search_string;
11267 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
11268 Object::ToString(isolate, search));
11269
11270 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11271 Object::ToInteger(isolate, position));
11272
11273 uint32_t index = receiver_string->ToValidIndex(*position);
11274 return Smi::FromInt(
11275 String::IndexOf(isolate, receiver_string, search_string, index));
11276 }
11277
11278 namespace {
11279
11280 template <typename T>
SearchString(Isolate * isolate,String::FlatContent receiver_content,Vector<T> pat_vector,int start_index)11281 int SearchString(Isolate* isolate, String::FlatContent receiver_content,
11282 Vector<T> pat_vector, int start_index) {
11283 if (receiver_content.IsOneByte()) {
11284 return SearchString(isolate, receiver_content.ToOneByteVector(), pat_vector,
11285 start_index);
11286 }
11287 return SearchString(isolate, receiver_content.ToUC16Vector(), pat_vector,
11288 start_index);
11289 }
11290
11291 } // namespace
11292
IndexOf(Isolate * isolate,Handle<String> receiver,Handle<String> search,int start_index)11293 int String::IndexOf(Isolate* isolate, Handle<String> receiver,
11294 Handle<String> search, int start_index) {
11295 DCHECK(0 <= start_index);
11296 DCHECK(start_index <= receiver->length());
11297
11298 uint32_t search_length = search->length();
11299 if (search_length == 0) return start_index;
11300
11301 uint32_t receiver_length = receiver->length();
11302 if (start_index + search_length > receiver_length) return -1;
11303
11304 receiver = String::Flatten(receiver);
11305 search = String::Flatten(search);
11306
11307 DisallowHeapAllocation no_gc; // ensure vectors stay valid
11308 // Extract flattened substrings of cons strings before getting encoding.
11309 String::FlatContent receiver_content = receiver->GetFlatContent();
11310 String::FlatContent search_content = search->GetFlatContent();
11311
11312 // dispatch on type of strings
11313 if (search_content.IsOneByte()) {
11314 Vector<const uint8_t> pat_vector = search_content.ToOneByteVector();
11315 return SearchString<const uint8_t>(isolate, receiver_content, pat_vector,
11316 start_index);
11317 }
11318 Vector<const uc16> pat_vector = search_content.ToUC16Vector();
11319 return SearchString<const uc16>(isolate, receiver_content, pat_vector,
11320 start_index);
11321 }
11322
GetSubstitution(Isolate * isolate,Match * match,Handle<String> replacement)11323 MaybeHandle<String> String::GetSubstitution(Isolate* isolate, Match* match,
11324 Handle<String> replacement) {
11325 Factory* factory = isolate->factory();
11326
11327 const int replacement_length = replacement->length();
11328 const int captures_length = match->CaptureCount();
11329
11330 replacement = String::Flatten(replacement);
11331
11332 Handle<String> dollar_string =
11333 factory->LookupSingleCharacterStringFromCode('$');
11334 int next = String::IndexOf(isolate, replacement, dollar_string, 0);
11335 if (next < 0) {
11336 return replacement;
11337 }
11338
11339 IncrementalStringBuilder builder(isolate);
11340
11341 if (next > 0) {
11342 builder.AppendString(factory->NewSubString(replacement, 0, next));
11343 }
11344
11345 while (true) {
11346 int pos = next + 1;
11347 if (pos < replacement_length) {
11348 const uint16_t peek = replacement->Get(pos);
11349 if (peek == '$') { // $$
11350 pos++;
11351 builder.AppendCharacter('$');
11352 } else if (peek == '&') { // $& - match
11353 pos++;
11354 builder.AppendString(match->GetMatch());
11355 } else if (peek == '`') { // $` - prefix
11356 pos++;
11357 builder.AppendString(match->GetPrefix());
11358 } else if (peek == '\'') { // $' - suffix
11359 pos++;
11360 builder.AppendString(match->GetSuffix());
11361 } else if (peek >= '0' && peek <= '9') {
11362 // Valid indices are $1 .. $9, $01 .. $09 and $10 .. $99
11363 int scaled_index = (peek - '0');
11364 int advance = 1;
11365
11366 if (pos + 1 < replacement_length) {
11367 const uint16_t next_peek = replacement->Get(pos + 1);
11368 if (next_peek >= '0' && next_peek <= '9') {
11369 const int new_scaled_index = scaled_index * 10 + (next_peek - '0');
11370 if (new_scaled_index < captures_length) {
11371 scaled_index = new_scaled_index;
11372 advance = 2;
11373 }
11374 }
11375 }
11376
11377 if (scaled_index != 0 && scaled_index < captures_length) {
11378 bool capture_exists;
11379 Handle<String> capture;
11380 ASSIGN_RETURN_ON_EXCEPTION(
11381 isolate, capture,
11382 match->GetCapture(scaled_index, &capture_exists), String);
11383 if (capture_exists) builder.AppendString(capture);
11384 pos += advance;
11385 } else {
11386 builder.AppendCharacter('$');
11387 }
11388 } else {
11389 builder.AppendCharacter('$');
11390 }
11391 } else {
11392 builder.AppendCharacter('$');
11393 }
11394
11395 // Go the the next $ in the replacement.
11396 next = String::IndexOf(isolate, replacement, dollar_string, pos);
11397
11398 // Return if there are no more $ characters in the replacement. If we
11399 // haven't reached the end, we need to append the suffix.
11400 if (next < 0) {
11401 if (pos < replacement_length) {
11402 builder.AppendString(
11403 factory->NewSubString(replacement, pos, replacement_length));
11404 }
11405 return builder.Finish();
11406 }
11407
11408 // Append substring between the previous and the next $ character.
11409 if (next > pos) {
11410 builder.AppendString(factory->NewSubString(replacement, pos, next));
11411 }
11412 }
11413
11414 UNREACHABLE();
11415 return MaybeHandle<String>();
11416 }
11417
11418 namespace { // for String.Prototype.lastIndexOf
11419
11420 template <typename schar, typename pchar>
StringMatchBackwards(Vector<const schar> subject,Vector<const pchar> pattern,int idx)11421 int StringMatchBackwards(Vector<const schar> subject,
11422 Vector<const pchar> pattern, int idx) {
11423 int pattern_length = pattern.length();
11424 DCHECK(pattern_length >= 1);
11425 DCHECK(idx + pattern_length <= subject.length());
11426
11427 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
11428 for (int i = 0; i < pattern_length; i++) {
11429 uc16 c = pattern[i];
11430 if (c > String::kMaxOneByteCharCode) {
11431 return -1;
11432 }
11433 }
11434 }
11435
11436 pchar pattern_first_char = pattern[0];
11437 for (int i = idx; i >= 0; i--) {
11438 if (subject[i] != pattern_first_char) continue;
11439 int j = 1;
11440 while (j < pattern_length) {
11441 if (pattern[j] != subject[i + j]) {
11442 break;
11443 }
11444 j++;
11445 }
11446 if (j == pattern_length) {
11447 return i;
11448 }
11449 }
11450 return -1;
11451 }
11452
11453 } // namespace
11454
LastIndexOf(Isolate * isolate,Handle<Object> receiver,Handle<Object> search,Handle<Object> position)11455 Object* String::LastIndexOf(Isolate* isolate, Handle<Object> receiver,
11456 Handle<Object> search, Handle<Object> position) {
11457 if (receiver->IsNullOrUndefined(isolate)) {
11458 THROW_NEW_ERROR_RETURN_FAILURE(
11459 isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
11460 isolate->factory()->NewStringFromAsciiChecked(
11461 "String.prototype.lastIndexOf")));
11462 }
11463 Handle<String> receiver_string;
11464 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string,
11465 Object::ToString(isolate, receiver));
11466
11467 Handle<String> search_string;
11468 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
11469 Object::ToString(isolate, search));
11470
11471 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11472 Object::ToNumber(position));
11473
11474 uint32_t start_index;
11475
11476 if (position->IsNaN()) {
11477 start_index = receiver_string->length();
11478 } else {
11479 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
11480 Object::ToInteger(isolate, position));
11481 start_index = receiver_string->ToValidIndex(*position);
11482 }
11483
11484 uint32_t pattern_length = search_string->length();
11485 uint32_t receiver_length = receiver_string->length();
11486
11487 if (start_index + pattern_length > receiver_length) {
11488 start_index = receiver_length - pattern_length;
11489 }
11490
11491 if (pattern_length == 0) {
11492 return Smi::FromInt(start_index);
11493 }
11494
11495 receiver_string = String::Flatten(receiver_string);
11496 search_string = String::Flatten(search_string);
11497
11498 int last_index = -1;
11499 DisallowHeapAllocation no_gc; // ensure vectors stay valid
11500
11501 String::FlatContent receiver_content = receiver_string->GetFlatContent();
11502 String::FlatContent search_content = search_string->GetFlatContent();
11503
11504 if (search_content.IsOneByte()) {
11505 Vector<const uint8_t> pat_vector = search_content.ToOneByteVector();
11506 if (receiver_content.IsOneByte()) {
11507 last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
11508 pat_vector, start_index);
11509 } else {
11510 last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
11511 pat_vector, start_index);
11512 }
11513 } else {
11514 Vector<const uc16> pat_vector = search_content.ToUC16Vector();
11515 if (receiver_content.IsOneByte()) {
11516 last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
11517 pat_vector, start_index);
11518 } else {
11519 last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
11520 pat_vector, start_index);
11521 }
11522 }
11523 return Smi::FromInt(last_index);
11524 }
11525
IsUtf8EqualTo(Vector<const char> str,bool allow_prefix_match)11526 bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
11527 int slen = length();
11528 // Can't check exact length equality, but we can check bounds.
11529 int str_len = str.length();
11530 if (!allow_prefix_match &&
11531 (str_len < slen ||
11532 str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) {
11533 return false;
11534 }
11535 int i;
11536 size_t remaining_in_str = static_cast<size_t>(str_len);
11537 const uint8_t* utf8_data = reinterpret_cast<const uint8_t*>(str.start());
11538 for (i = 0; i < slen && remaining_in_str > 0; i++) {
11539 size_t cursor = 0;
11540 uint32_t r = unibrow::Utf8::ValueOf(utf8_data, remaining_in_str, &cursor);
11541 DCHECK(cursor > 0 && cursor <= remaining_in_str);
11542 if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
11543 if (i > slen - 1) return false;
11544 if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false;
11545 if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false;
11546 } else {
11547 if (Get(i) != r) return false;
11548 }
11549 utf8_data += cursor;
11550 remaining_in_str -= cursor;
11551 }
11552 return (allow_prefix_match || i == slen) && remaining_in_str == 0;
11553 }
11554
11555
IsOneByteEqualTo(Vector<const uint8_t> str)11556 bool String::IsOneByteEqualTo(Vector<const uint8_t> str) {
11557 int slen = length();
11558 if (str.length() != slen) return false;
11559 DisallowHeapAllocation no_gc;
11560 FlatContent content = GetFlatContent();
11561 if (content.IsOneByte()) {
11562 return CompareChars(content.ToOneByteVector().start(),
11563 str.start(), slen) == 0;
11564 }
11565 for (int i = 0; i < slen; i++) {
11566 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
11567 }
11568 return true;
11569 }
11570
11571
IsTwoByteEqualTo(Vector<const uc16> str)11572 bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
11573 int slen = length();
11574 if (str.length() != slen) return false;
11575 DisallowHeapAllocation no_gc;
11576 FlatContent content = GetFlatContent();
11577 if (content.IsTwoByte()) {
11578 return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
11579 }
11580 for (int i = 0; i < slen; i++) {
11581 if (Get(i) != str[i]) return false;
11582 }
11583 return true;
11584 }
11585
11586
ComputeAndSetHash()11587 uint32_t String::ComputeAndSetHash() {
11588 // Should only be called if hash code has not yet been computed.
11589 DCHECK(!HasHashCode());
11590
11591 // Store the hash code in the object.
11592 uint32_t field = IteratingStringHasher::Hash(this, GetHeap()->HashSeed());
11593 set_hash_field(field);
11594
11595 // Check the hash code is there.
11596 DCHECK(HasHashCode());
11597 uint32_t result = field >> kHashShift;
11598 DCHECK(result != 0); // Ensure that the hash value of 0 is never computed.
11599 return result;
11600 }
11601
11602
ComputeArrayIndex(uint32_t * index)11603 bool String::ComputeArrayIndex(uint32_t* index) {
11604 int length = this->length();
11605 if (length == 0 || length > kMaxArrayIndexSize) return false;
11606 StringCharacterStream stream(this);
11607 return StringToArrayIndex(&stream, index);
11608 }
11609
11610
SlowAsArrayIndex(uint32_t * index)11611 bool String::SlowAsArrayIndex(uint32_t* index) {
11612 if (length() <= kMaxCachedArrayIndexLength) {
11613 Hash(); // force computation of hash code
11614 uint32_t field = hash_field();
11615 if ((field & kIsNotArrayIndexMask) != 0) return false;
11616 // Isolate the array index form the full hash field.
11617 *index = ArrayIndexValueBits::decode(field);
11618 return true;
11619 } else {
11620 return ComputeArrayIndex(index);
11621 }
11622 }
11623
11624
Truncate(Handle<SeqString> string,int new_length)11625 Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
11626 Heap* heap = string->GetHeap();
11627 if (new_length == 0) return heap->isolate()->factory()->empty_string();
11628
11629 int new_size, old_size;
11630 int old_length = string->length();
11631 if (old_length <= new_length) return string;
11632
11633 if (string->IsSeqOneByteString()) {
11634 old_size = SeqOneByteString::SizeFor(old_length);
11635 new_size = SeqOneByteString::SizeFor(new_length);
11636 } else {
11637 DCHECK(string->IsSeqTwoByteString());
11638 old_size = SeqTwoByteString::SizeFor(old_length);
11639 new_size = SeqTwoByteString::SizeFor(new_length);
11640 }
11641
11642 int delta = old_size - new_size;
11643
11644 Address start_of_string = string->address();
11645 DCHECK_OBJECT_ALIGNED(start_of_string);
11646 DCHECK_OBJECT_ALIGNED(start_of_string + new_size);
11647
11648 // Sizes are pointer size aligned, so that we can use filler objects
11649 // that are a multiple of pointer size.
11650 heap->CreateFillerObjectAt(start_of_string + new_size, delta,
11651 ClearRecordedSlots::kNo);
11652 heap->AdjustLiveBytes(*string, -delta);
11653
11654 // We are storing the new length using release store after creating a filler
11655 // for the left-over space to avoid races with the sweeper thread.
11656 string->synchronized_set_length(new_length);
11657
11658 return string;
11659 }
11660
11661
MakeArrayIndexHash(uint32_t value,int length)11662 uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
11663 // For array indexes mix the length into the hash as an array index could
11664 // be zero.
11665 DCHECK(length > 0);
11666 DCHECK(length <= String::kMaxArrayIndexSize);
11667 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
11668 (1 << String::kArrayIndexValueBits));
11669
11670 value <<= String::ArrayIndexValueBits::kShift;
11671 value |= length << String::ArrayIndexLengthBits::kShift;
11672
11673 DCHECK((value & String::kIsNotArrayIndexMask) == 0);
11674 DCHECK_EQ(length <= String::kMaxCachedArrayIndexLength,
11675 (value & String::kContainsCachedArrayIndexMask) == 0);
11676 return value;
11677 }
11678
11679
GetHashField()11680 uint32_t StringHasher::GetHashField() {
11681 if (length_ <= String::kMaxHashCalcLength) {
11682 if (is_array_index_) {
11683 return MakeArrayIndexHash(array_index_, length_);
11684 }
11685 return (GetHashCore(raw_running_hash_) << String::kHashShift) |
11686 String::kIsNotArrayIndexMask;
11687 } else {
11688 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
11689 }
11690 }
11691
11692
ComputeUtf8Hash(Vector<const char> chars,uint32_t seed,int * utf16_length_out)11693 uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars,
11694 uint32_t seed,
11695 int* utf16_length_out) {
11696 int vector_length = chars.length();
11697 // Handle some edge cases
11698 if (vector_length <= 1) {
11699 DCHECK(vector_length == 0 ||
11700 static_cast<uint8_t>(chars.start()[0]) <=
11701 unibrow::Utf8::kMaxOneByteChar);
11702 *utf16_length_out = vector_length;
11703 return HashSequentialString(chars.start(), vector_length, seed);
11704 }
11705 // Start with a fake length which won't affect computation.
11706 // It will be updated later.
11707 StringHasher hasher(String::kMaxArrayIndexSize, seed);
11708 size_t remaining = static_cast<size_t>(vector_length);
11709 const uint8_t* stream = reinterpret_cast<const uint8_t*>(chars.start());
11710 int utf16_length = 0;
11711 bool is_index = true;
11712 DCHECK(hasher.is_array_index_);
11713 while (remaining > 0) {
11714 size_t consumed = 0;
11715 uint32_t c = unibrow::Utf8::ValueOf(stream, remaining, &consumed);
11716 DCHECK(consumed > 0 && consumed <= remaining);
11717 stream += consumed;
11718 remaining -= consumed;
11719 bool is_two_characters = c > unibrow::Utf16::kMaxNonSurrogateCharCode;
11720 utf16_length += is_two_characters ? 2 : 1;
11721 // No need to keep hashing. But we do need to calculate utf16_length.
11722 if (utf16_length > String::kMaxHashCalcLength) continue;
11723 if (is_two_characters) {
11724 uint16_t c1 = unibrow::Utf16::LeadSurrogate(c);
11725 uint16_t c2 = unibrow::Utf16::TrailSurrogate(c);
11726 hasher.AddCharacter(c1);
11727 hasher.AddCharacter(c2);
11728 if (is_index) is_index = hasher.UpdateIndex(c1);
11729 if (is_index) is_index = hasher.UpdateIndex(c2);
11730 } else {
11731 hasher.AddCharacter(c);
11732 if (is_index) is_index = hasher.UpdateIndex(c);
11733 }
11734 }
11735 *utf16_length_out = static_cast<int>(utf16_length);
11736 // Must set length here so that hash computation is correct.
11737 hasher.length_ = utf16_length;
11738 return hasher.GetHashField();
11739 }
11740
11741
VisitConsString(ConsString * cons_string)11742 void IteratingStringHasher::VisitConsString(ConsString* cons_string) {
11743 // Run small ConsStrings through ConsStringIterator.
11744 if (cons_string->length() < 64) {
11745 ConsStringIterator iter(cons_string);
11746 int offset;
11747 String* string;
11748 while (nullptr != (string = iter.Next(&offset))) {
11749 DCHECK_EQ(0, offset);
11750 String::VisitFlat(this, string, 0);
11751 }
11752 return;
11753 }
11754 // Slow case.
11755 const int max_length = String::kMaxHashCalcLength;
11756 int length = std::min(cons_string->length(), max_length);
11757 if (cons_string->HasOnlyOneByteChars()) {
11758 uint8_t* buffer = new uint8_t[length];
11759 String::WriteToFlat(cons_string, buffer, 0, length);
11760 AddCharacters(buffer, length);
11761 delete[] buffer;
11762 } else {
11763 uint16_t* buffer = new uint16_t[length];
11764 String::WriteToFlat(cons_string, buffer, 0, length);
11765 AddCharacters(buffer, length);
11766 delete[] buffer;
11767 }
11768 }
11769
11770
PrintOn(FILE * file)11771 void String::PrintOn(FILE* file) {
11772 int length = this->length();
11773 for (int i = 0; i < length; i++) {
11774 PrintF(file, "%c", Get(i));
11775 }
11776 }
11777
11778
Hash()11779 int Map::Hash() {
11780 // For performance reasons we only hash the 3 most variable fields of a map:
11781 // constructor, prototype and bit_field2. For predictability reasons we
11782 // use objects' offsets in respective pages for hashing instead of raw
11783 // addresses.
11784
11785 // Shift away the tag.
11786 int hash = ObjectAddressForHashing(GetConstructor()) >> 2;
11787
11788 // XOR-ing the prototype and constructor directly yields too many zero bits
11789 // when the two pointers are close (which is fairly common).
11790 // To avoid this we shift the prototype bits relatively to the constructor.
11791 hash ^= ObjectAddressForHashing(prototype()) << (32 - kPageSizeBits);
11792
11793 return hash ^ (hash >> 16) ^ bit_field2();
11794 }
11795
11796
11797 namespace {
11798
CheckEquivalent(Map * first,Map * second)11799 bool CheckEquivalent(Map* first, Map* second) {
11800 return first->GetConstructor() == second->GetConstructor() &&
11801 first->prototype() == second->prototype() &&
11802 first->instance_type() == second->instance_type() &&
11803 first->bit_field() == second->bit_field() &&
11804 first->is_extensible() == second->is_extensible() &&
11805 first->new_target_is_base() == second->new_target_is_base() &&
11806 first->has_hidden_prototype() == second->has_hidden_prototype();
11807 }
11808
11809 } // namespace
11810
11811
EquivalentToForTransition(Map * other)11812 bool Map::EquivalentToForTransition(Map* other) {
11813 if (!CheckEquivalent(this, other)) return false;
11814 if (instance_type() == JS_FUNCTION_TYPE) {
11815 // JSFunctions require more checks to ensure that sloppy function is
11816 // not equvalent to strict function.
11817 int nof = Min(NumberOfOwnDescriptors(), other->NumberOfOwnDescriptors());
11818 return instance_descriptors()->IsEqualUpTo(other->instance_descriptors(),
11819 nof);
11820 }
11821 return true;
11822 }
11823
11824
EquivalentToForNormalization(Map * other,PropertyNormalizationMode mode)11825 bool Map::EquivalentToForNormalization(Map* other,
11826 PropertyNormalizationMode mode) {
11827 int properties =
11828 mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other->GetInObjectProperties();
11829 return CheckEquivalent(this, other) && bit_field2() == other->bit_field2() &&
11830 GetInObjectProperties() == properties &&
11831 JSObject::GetInternalFieldCount(this) ==
11832 JSObject::GetInternalFieldCount(other);
11833 }
11834
11835
Inlines(SharedFunctionInfo * candidate)11836 bool JSFunction::Inlines(SharedFunctionInfo* candidate) {
11837 DisallowHeapAllocation no_gc;
11838 if (shared() == candidate) return true;
11839 if (code()->kind() != Code::OPTIMIZED_FUNCTION) return false;
11840 DeoptimizationInputData* const data =
11841 DeoptimizationInputData::cast(code()->deoptimization_data());
11842 if (data->length() == 0) return false;
11843 FixedArray* const literals = data->LiteralArray();
11844 int const inlined_count = data->InlinedFunctionCount()->value();
11845 for (int i = 0; i < inlined_count; ++i) {
11846 if (SharedFunctionInfo::cast(literals->get(i)) == candidate) {
11847 return true;
11848 }
11849 }
11850 return false;
11851 }
11852
MarkForBaseline()11853 void JSFunction::MarkForBaseline() {
11854 Isolate* isolate = GetIsolate();
11855 set_code_no_write_barrier(
11856 isolate->builtins()->builtin(Builtins::kCompileBaseline));
11857 // No write barrier required, since the builtin is part of the root set.
11858 if (FLAG_mark_shared_functions_for_tier_up) {
11859 shared()->set_marked_for_tier_up(true);
11860 }
11861 }
11862
MarkForOptimization()11863 void JSFunction::MarkForOptimization() {
11864 Isolate* isolate = GetIsolate();
11865 DCHECK(!IsOptimized());
11866 DCHECK(shared()->allows_lazy_compilation() ||
11867 !shared()->optimization_disabled());
11868 set_code_no_write_barrier(
11869 isolate->builtins()->builtin(Builtins::kCompileOptimized));
11870 // No write barrier required, since the builtin is part of the root set.
11871 if (FLAG_mark_shared_functions_for_tier_up) {
11872 shared()->set_marked_for_tier_up(true);
11873 }
11874 }
11875
11876
AttemptConcurrentOptimization()11877 void JSFunction::AttemptConcurrentOptimization() {
11878 Isolate* isolate = GetIsolate();
11879 if (!isolate->concurrent_recompilation_enabled() ||
11880 isolate->bootstrapper()->IsActive()) {
11881 MarkForOptimization();
11882 return;
11883 }
11884 DCHECK(!IsInOptimizationQueue());
11885 DCHECK(!IsOptimized());
11886 DCHECK(shared()->allows_lazy_compilation() ||
11887 !shared()->optimization_disabled());
11888 DCHECK(isolate->concurrent_recompilation_enabled());
11889 if (FLAG_trace_concurrent_recompilation) {
11890 PrintF(" ** Marking ");
11891 ShortPrint();
11892 PrintF(" for concurrent recompilation.\n");
11893 }
11894
11895 set_code_no_write_barrier(
11896 isolate->builtins()->builtin(Builtins::kCompileOptimizedConcurrent));
11897 // No write barrier required, since the builtin is part of the root set.
11898 if (FLAG_mark_shared_functions_for_tier_up) {
11899 // TODO(leszeks): The compilation isn't concurrent if we trigger it using
11900 // this bit.
11901 shared()->set_marked_for_tier_up(true);
11902 }
11903 }
11904
11905 // static
AddToOptimizedCodeMap(Handle<SharedFunctionInfo> shared,Handle<Context> native_context,Handle<Code> code,BailoutId osr_ast_id)11906 void SharedFunctionInfo::AddToOptimizedCodeMap(
11907 Handle<SharedFunctionInfo> shared, Handle<Context> native_context,
11908 Handle<Code> code, BailoutId osr_ast_id) {
11909 Isolate* isolate = shared->GetIsolate();
11910 if (isolate->serializer_enabled()) return;
11911 DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
11912 DCHECK(native_context->IsNativeContext());
11913 STATIC_ASSERT(kEntryLength == 2);
11914 Handle<FixedArray> new_code_map;
11915 int entry;
11916
11917 if (!osr_ast_id.IsNone()) {
11918 Context::AddToOptimizedCodeMap(native_context, shared, code, osr_ast_id);
11919 return;
11920 }
11921
11922 DCHECK(osr_ast_id.IsNone());
11923 if (shared->OptimizedCodeMapIsCleared()) {
11924 new_code_map = isolate->factory()->NewFixedArray(kInitialLength, TENURED);
11925 entry = kEntriesStart;
11926 } else {
11927 Handle<FixedArray> old_code_map(shared->optimized_code_map(), isolate);
11928 entry = shared->SearchOptimizedCodeMapEntry(*native_context);
11929 if (entry >= kEntriesStart) {
11930 // Just set the code of the entry.
11931 Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code);
11932 old_code_map->set(entry + kCachedCodeOffset, *code_cell);
11933 return;
11934 }
11935
11936 // Can we reuse an entry?
11937 DCHECK(entry < kEntriesStart);
11938 int length = old_code_map->length();
11939 for (int i = kEntriesStart; i < length; i += kEntryLength) {
11940 if (WeakCell::cast(old_code_map->get(i + kContextOffset))->cleared()) {
11941 new_code_map = old_code_map;
11942 entry = i;
11943 break;
11944 }
11945 }
11946
11947 if (entry < kEntriesStart) {
11948 // Copy old optimized code map and append one new entry.
11949 new_code_map = isolate->factory()->CopyFixedArrayAndGrow(
11950 old_code_map, kEntryLength, TENURED);
11951 // TODO(mstarzinger): Temporary workaround. The allocation above might
11952 // have flushed the optimized code map and the copy we created is full of
11953 // holes. For now we just give up on adding the entry and pretend it got
11954 // flushed.
11955 if (shared->OptimizedCodeMapIsCleared()) return;
11956 entry = old_code_map->length();
11957 }
11958 }
11959
11960 Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code);
11961 WeakCell* context_cell = native_context->self_weak_cell();
11962
11963 new_code_map->set(entry + kContextOffset, context_cell);
11964 new_code_map->set(entry + kCachedCodeOffset, *code_cell);
11965
11966 #ifdef DEBUG
11967 for (int i = kEntriesStart; i < new_code_map->length(); i += kEntryLength) {
11968 WeakCell* cell = WeakCell::cast(new_code_map->get(i + kContextOffset));
11969 DCHECK(cell->cleared() || cell->value()->IsNativeContext());
11970 cell = WeakCell::cast(new_code_map->get(i + kCachedCodeOffset));
11971 DCHECK(cell->cleared() ||
11972 (cell->value()->IsCode() &&
11973 Code::cast(cell->value())->kind() == Code::OPTIMIZED_FUNCTION));
11974 }
11975 #endif
11976
11977 FixedArray* old_code_map = shared->optimized_code_map();
11978 if (old_code_map != *new_code_map) {
11979 shared->set_optimized_code_map(*new_code_map);
11980 }
11981 }
11982
11983
ClearOptimizedCodeMap()11984 void SharedFunctionInfo::ClearOptimizedCodeMap() {
11985 FixedArray* empty_fixed_array = GetHeap()->empty_fixed_array();
11986 set_optimized_code_map(empty_fixed_array, SKIP_WRITE_BARRIER);
11987 }
11988
11989
EvictFromOptimizedCodeMap(Code * optimized_code,const char * reason)11990 void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
11991 const char* reason) {
11992 DisallowHeapAllocation no_gc;
11993 Isolate* isolate = GetIsolate();
11994 bool found = false;
11995
11996 if (!OptimizedCodeMapIsCleared()) {
11997 Heap* heap = isolate->heap();
11998 FixedArray* code_map = optimized_code_map();
11999 int length = code_map->length();
12000 for (int src = kEntriesStart; src < length; src += kEntryLength) {
12001 DCHECK(WeakCell::cast(code_map->get(src))->cleared() ||
12002 WeakCell::cast(code_map->get(src))->value()->IsNativeContext());
12003 found = WeakCell::cast(code_map->get(src + kCachedCodeOffset))->value() ==
12004 optimized_code;
12005 if (found) {
12006 if (FLAG_trace_opt) {
12007 PrintF("[evicting entry from optimizing code map (%s) for ", reason);
12008 ShortPrint();
12009 PrintF("]\n");
12010 }
12011 // Just clear the code.
12012 code_map->set(src + kCachedCodeOffset, heap->empty_weak_cell(),
12013 SKIP_WRITE_BARRIER);
12014 }
12015 }
12016 }
12017
12018 if (!found) {
12019 // We didn't find the code in here. It must be osr'd code.
12020 isolate->EvictOSROptimizedCode(optimized_code, reason);
12021 }
12022 }
12023
12024 // static
EnsureLiterals(Handle<JSFunction> function)12025 void JSFunction::EnsureLiterals(Handle<JSFunction> function) {
12026 Handle<SharedFunctionInfo> shared(function->shared());
12027 Isolate* isolate = shared->GetIsolate();
12028
12029 FeedbackVectorState state = function->GetFeedbackVectorState(isolate);
12030 switch (state) {
12031 case TOP_LEVEL_SCRIPT_NEEDS_VECTOR: {
12032 // A top level script didn't get it's literals installed.
12033 Handle<FeedbackVector> feedback_vector =
12034 FeedbackVector::New(isolate, shared);
12035 Handle<Cell> new_cell =
12036 isolate->factory()->NewOneClosureCell(feedback_vector);
12037 function->set_feedback_vector_cell(*new_cell);
12038 break;
12039 }
12040 case NEEDS_VECTOR: {
12041 Handle<FeedbackVector> feedback_vector =
12042 FeedbackVector::New(isolate, shared);
12043 function->feedback_vector_cell()->set_value(*feedback_vector);
12044 break;
12045 }
12046 case HAS_VECTOR:
12047 // Nothing to do.
12048 break;
12049 }
12050 }
12051
GetMinInobjectSlack(Map * map,void * data)12052 static void GetMinInobjectSlack(Map* map, void* data) {
12053 int slack = map->unused_property_fields();
12054 if (*reinterpret_cast<int*>(data) > slack) {
12055 *reinterpret_cast<int*>(data) = slack;
12056 }
12057 }
12058
12059
ShrinkInstanceSize(Map * map,void * data)12060 static void ShrinkInstanceSize(Map* map, void* data) {
12061 int slack = *reinterpret_cast<int*>(data);
12062 map->SetInObjectProperties(map->GetInObjectProperties() - slack);
12063 map->set_unused_property_fields(map->unused_property_fields() - slack);
12064 map->set_instance_size(map->instance_size() - slack * kPointerSize);
12065 map->set_construction_counter(Map::kNoSlackTracking);
12066
12067 // Visitor id might depend on the instance size, recalculate it.
12068 map->set_visitor_id(Heap::GetStaticVisitorIdForMap(map));
12069 }
12070
StopSlackTracking(Map * map,void * data)12071 static void StopSlackTracking(Map* map, void* data) {
12072 map->set_construction_counter(Map::kNoSlackTracking);
12073 }
12074
CompleteInobjectSlackTracking()12075 void Map::CompleteInobjectSlackTracking() {
12076 // Has to be an initial map.
12077 DCHECK(GetBackPointer()->IsUndefined(GetIsolate()));
12078
12079 int slack = unused_property_fields();
12080 TransitionArray::TraverseTransitionTree(this, &GetMinInobjectSlack, &slack);
12081 if (slack != 0) {
12082 // Resize the initial map and all maps in its transition tree.
12083 TransitionArray::TraverseTransitionTree(this, &ShrinkInstanceSize, &slack);
12084 } else {
12085 TransitionArray::TraverseTransitionTree(this, &StopSlackTracking, nullptr);
12086 }
12087 }
12088
12089
PrototypeBenefitsFromNormalization(Handle<JSObject> object)12090 static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) {
12091 DisallowHeapAllocation no_gc;
12092 if (!object->HasFastProperties()) return false;
12093 if (object->IsJSGlobalProxy()) return false;
12094 if (object->GetIsolate()->bootstrapper()->IsActive()) return false;
12095 return !object->map()->is_prototype_map() ||
12096 !object->map()->should_be_fast_prototype_map();
12097 }
12098
12099 // static
MakePrototypesFast(Handle<Object> receiver,WhereToStart where_to_start,Isolate * isolate)12100 void JSObject::MakePrototypesFast(Handle<Object> receiver,
12101 WhereToStart where_to_start,
12102 Isolate* isolate) {
12103 if (!receiver->IsJSReceiver()) return;
12104 for (PrototypeIterator iter(isolate, Handle<JSReceiver>::cast(receiver),
12105 where_to_start);
12106 !iter.IsAtEnd(); iter.Advance()) {
12107 Handle<Object> current = PrototypeIterator::GetCurrent(iter);
12108 if (!current->IsJSObject()) return;
12109 Handle<JSObject> current_obj = Handle<JSObject>::cast(current);
12110 Map* current_map = current_obj->map();
12111 if (current_map->is_prototype_map()) {
12112 // If the map is already marked as should be fast, we're done. Its
12113 // prototypes will have been marked already as well.
12114 if (current_map->should_be_fast_prototype_map()) return;
12115 Handle<Map> map(current_map);
12116 Map::SetShouldBeFastPrototypeMap(map, true, isolate);
12117 JSObject::OptimizeAsPrototype(current_obj, FAST_PROTOTYPE);
12118 }
12119 }
12120 }
12121
12122 // static
OptimizeAsPrototype(Handle<JSObject> object,PrototypeOptimizationMode mode)12123 void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
12124 PrototypeOptimizationMode mode) {
12125 if (object->IsJSGlobalObject()) return;
12126 if (mode == FAST_PROTOTYPE && PrototypeBenefitsFromNormalization(object)) {
12127 // First normalize to ensure all JSFunctions are DATA_CONSTANT.
12128 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0,
12129 "NormalizeAsPrototype");
12130 }
12131 Handle<Map> previous_map(object->map());
12132 if (object->map()->is_prototype_map()) {
12133 if (object->map()->should_be_fast_prototype_map() &&
12134 !object->HasFastProperties()) {
12135 JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype");
12136 }
12137 } else {
12138 if (object->map() == *previous_map) {
12139 Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype");
12140 JSObject::MigrateToMap(object, new_map);
12141 }
12142 object->map()->set_is_prototype_map(true);
12143
12144 // Replace the pointer to the exact constructor with the Object function
12145 // from the same context if undetectable from JS. This is to avoid keeping
12146 // memory alive unnecessarily.
12147 Object* maybe_constructor = object->map()->GetConstructor();
12148 if (maybe_constructor->IsJSFunction()) {
12149 JSFunction* constructor = JSFunction::cast(maybe_constructor);
12150 Isolate* isolate = object->GetIsolate();
12151 if (!constructor->shared()->IsApiFunction() &&
12152 object->class_name() == isolate->heap()->Object_string()) {
12153 Context* context = constructor->context()->native_context();
12154 JSFunction* object_function = context->object_function();
12155 object->map()->SetConstructor(object_function);
12156 }
12157 }
12158 }
12159 }
12160
12161
12162 // static
ReoptimizeIfPrototype(Handle<JSObject> object)12163 void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) {
12164 if (!object->map()->is_prototype_map()) return;
12165 if (!object->map()->should_be_fast_prototype_map()) return;
12166 OptimizeAsPrototype(object, FAST_PROTOTYPE);
12167 }
12168
12169
12170 // static
LazyRegisterPrototypeUser(Handle<Map> user,Isolate * isolate)12171 void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
12172 // Contract: In line with InvalidatePrototypeChains()'s requirements,
12173 // leaf maps don't need to register as users, only prototypes do.
12174 DCHECK(user->is_prototype_map());
12175
12176 Handle<Map> current_user = user;
12177 Handle<PrototypeInfo> current_user_info =
12178 Map::GetOrCreatePrototypeInfo(user, isolate);
12179 for (PrototypeIterator iter(user); !iter.IsAtEnd(); iter.Advance()) {
12180 // Walk up the prototype chain as far as links haven't been registered yet.
12181 if (current_user_info->registry_slot() != PrototypeInfo::UNREGISTERED) {
12182 break;
12183 }
12184 Handle<Object> maybe_proto = PrototypeIterator::GetCurrent(iter);
12185 // Proxies on the prototype chain are not supported. They make it
12186 // impossible to make any assumptions about the prototype chain anyway.
12187 if (maybe_proto->IsJSProxy()) return;
12188 Handle<JSObject> proto = Handle<JSObject>::cast(maybe_proto);
12189 Handle<PrototypeInfo> proto_info =
12190 Map::GetOrCreatePrototypeInfo(proto, isolate);
12191 Handle<Object> maybe_registry(proto_info->prototype_users(), isolate);
12192 int slot = 0;
12193 Handle<WeakFixedArray> new_array =
12194 WeakFixedArray::Add(maybe_registry, current_user, &slot);
12195 current_user_info->set_registry_slot(slot);
12196 if (!maybe_registry.is_identical_to(new_array)) {
12197 proto_info->set_prototype_users(*new_array);
12198 }
12199 if (FLAG_trace_prototype_users) {
12200 PrintF("Registering %p as a user of prototype %p (map=%p).\n",
12201 reinterpret_cast<void*>(*current_user),
12202 reinterpret_cast<void*>(*proto),
12203 reinterpret_cast<void*>(proto->map()));
12204 }
12205
12206 current_user = handle(proto->map(), isolate);
12207 current_user_info = proto_info;
12208 }
12209 }
12210
12211
12212 // Can be called regardless of whether |user| was actually registered with
12213 // |prototype|. Returns true when there was a registration.
12214 // static
UnregisterPrototypeUser(Handle<Map> user,Isolate * isolate)12215 bool JSObject::UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
12216 DCHECK(user->is_prototype_map());
12217 // If it doesn't have a PrototypeInfo, it was never registered.
12218 if (!user->prototype_info()->IsPrototypeInfo()) return false;
12219 // If it had no prototype before, see if it had users that might expect
12220 // registration.
12221 if (!user->prototype()->IsJSObject()) {
12222 Object* users =
12223 PrototypeInfo::cast(user->prototype_info())->prototype_users();
12224 return users->IsWeakFixedArray();
12225 }
12226 Handle<JSObject> prototype(JSObject::cast(user->prototype()), isolate);
12227 Handle<PrototypeInfo> user_info =
12228 Map::GetOrCreatePrototypeInfo(user, isolate);
12229 int slot = user_info->registry_slot();
12230 if (slot == PrototypeInfo::UNREGISTERED) return false;
12231 DCHECK(prototype->map()->is_prototype_map());
12232 Object* maybe_proto_info = prototype->map()->prototype_info();
12233 // User knows its registry slot, prototype info and user registry must exist.
12234 DCHECK(maybe_proto_info->IsPrototypeInfo());
12235 Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info),
12236 isolate);
12237 Object* maybe_registry = proto_info->prototype_users();
12238 DCHECK(maybe_registry->IsWeakFixedArray());
12239 DCHECK(WeakFixedArray::cast(maybe_registry)->Get(slot) == *user);
12240 WeakFixedArray::cast(maybe_registry)->Clear(slot);
12241 if (FLAG_trace_prototype_users) {
12242 PrintF("Unregistering %p as a user of prototype %p.\n",
12243 reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype));
12244 }
12245 return true;
12246 }
12247
12248
InvalidatePrototypeChainsInternal(Map * map)12249 static void InvalidatePrototypeChainsInternal(Map* map) {
12250 DCHECK(map->is_prototype_map());
12251 if (FLAG_trace_prototype_users) {
12252 PrintF("Invalidating prototype map %p 's cell\n",
12253 reinterpret_cast<void*>(map));
12254 }
12255 Object* maybe_proto_info = map->prototype_info();
12256 if (!maybe_proto_info->IsPrototypeInfo()) return;
12257 PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info);
12258 Object* maybe_cell = proto_info->validity_cell();
12259 if (maybe_cell->IsCell()) {
12260 // Just set the value; the cell will be replaced lazily.
12261 Cell* cell = Cell::cast(maybe_cell);
12262 cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid));
12263 }
12264
12265 WeakFixedArray::Iterator iterator(proto_info->prototype_users());
12266 // For now, only maps register themselves as users.
12267 Map* user;
12268 while ((user = iterator.Next<Map>())) {
12269 // Walk the prototype chain (backwards, towards leaf objects) if necessary.
12270 InvalidatePrototypeChainsInternal(user);
12271 }
12272 }
12273
12274
12275 // static
InvalidatePrototypeChains(Map * map)12276 void JSObject::InvalidatePrototypeChains(Map* map) {
12277 DisallowHeapAllocation no_gc;
12278 InvalidatePrototypeChainsInternal(map);
12279 }
12280
12281
12282 // static
GetOrCreatePrototypeInfo(Handle<JSObject> prototype,Isolate * isolate)12283 Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<JSObject> prototype,
12284 Isolate* isolate) {
12285 Object* maybe_proto_info = prototype->map()->prototype_info();
12286 if (maybe_proto_info->IsPrototypeInfo()) {
12287 return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
12288 }
12289 Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
12290 prototype->map()->set_prototype_info(*proto_info);
12291 return proto_info;
12292 }
12293
12294
12295 // static
GetOrCreatePrototypeInfo(Handle<Map> prototype_map,Isolate * isolate)12296 Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<Map> prototype_map,
12297 Isolate* isolate) {
12298 Object* maybe_proto_info = prototype_map->prototype_info();
12299 if (maybe_proto_info->IsPrototypeInfo()) {
12300 return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
12301 }
12302 Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
12303 prototype_map->set_prototype_info(*proto_info);
12304 return proto_info;
12305 }
12306
12307 // static
SetShouldBeFastPrototypeMap(Handle<Map> map,bool value,Isolate * isolate)12308 void Map::SetShouldBeFastPrototypeMap(Handle<Map> map, bool value,
12309 Isolate* isolate) {
12310 if (value == false && !map->prototype_info()->IsPrototypeInfo()) {
12311 // "False" is the implicit default value, so there's nothing to do.
12312 return;
12313 }
12314 GetOrCreatePrototypeInfo(map, isolate)->set_should_be_fast_map(value);
12315 }
12316
12317 // static
GetOrCreatePrototypeChainValidityCell(Handle<Map> map,Isolate * isolate)12318 Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
12319 Isolate* isolate) {
12320 Handle<Object> maybe_prototype;
12321 if (map->IsJSGlobalObjectMap()) {
12322 DCHECK(map->is_prototype_map());
12323 // Global object is prototype of a global proxy and therefore we can
12324 // use its validity cell for guarding global object's prototype change.
12325 maybe_prototype = isolate->global_object();
12326 } else {
12327 maybe_prototype =
12328 handle(map->GetPrototypeChainRootMap(isolate)->prototype(), isolate);
12329 if (!maybe_prototype->IsJSObject()) return Handle<Cell>::null();
12330 }
12331 Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype);
12332 // Ensure the prototype is registered with its own prototypes so its cell
12333 // will be invalidated when necessary.
12334 JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate),
12335 isolate);
12336 Handle<PrototypeInfo> proto_info =
12337 GetOrCreatePrototypeInfo(prototype, isolate);
12338 Object* maybe_cell = proto_info->validity_cell();
12339 // Return existing cell if it's still valid.
12340 if (maybe_cell->IsCell()) {
12341 Handle<Cell> cell(Cell::cast(maybe_cell), isolate);
12342 if (cell->value() == Smi::FromInt(Map::kPrototypeChainValid)) {
12343 return cell;
12344 }
12345 }
12346 // Otherwise create a new cell.
12347 Handle<Cell> cell = isolate->factory()->NewCell(
12348 handle(Smi::FromInt(Map::kPrototypeChainValid), isolate));
12349 proto_info->set_validity_cell(*cell);
12350 return cell;
12351 }
12352
12353 // static
GetOrCreatePrototypeWeakCell(Handle<JSObject> prototype,Isolate * isolate)12354 Handle<WeakCell> Map::GetOrCreatePrototypeWeakCell(Handle<JSObject> prototype,
12355 Isolate* isolate) {
12356 DCHECK(!prototype.is_null());
12357 Handle<PrototypeInfo> proto_info =
12358 GetOrCreatePrototypeInfo(prototype, isolate);
12359 Object* maybe_cell = proto_info->weak_cell();
12360 // Return existing cell if it's already created.
12361 if (maybe_cell->IsWeakCell()) {
12362 Handle<WeakCell> cell(WeakCell::cast(maybe_cell), isolate);
12363 DCHECK(!cell->cleared());
12364 return cell;
12365 }
12366 // Otherwise create a new cell.
12367 Handle<WeakCell> cell = isolate->factory()->NewWeakCell(prototype);
12368 proto_info->set_weak_cell(*cell);
12369 return cell;
12370 }
12371
12372 // static
SetPrototype(Handle<Map> map,Handle<Object> prototype,PrototypeOptimizationMode proto_mode)12373 void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype,
12374 PrototypeOptimizationMode proto_mode) {
12375 RuntimeCallTimerScope stats_scope(*map, &RuntimeCallStats::Map_SetPrototype);
12376
12377 bool is_hidden = false;
12378 if (prototype->IsJSObject()) {
12379 Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype);
12380 JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode);
12381
12382 Object* maybe_constructor = prototype_jsobj->map()->GetConstructor();
12383 if (maybe_constructor->IsJSFunction()) {
12384 JSFunction* constructor = JSFunction::cast(maybe_constructor);
12385 Object* data = constructor->shared()->function_data();
12386 is_hidden = (data->IsFunctionTemplateInfo() &&
12387 FunctionTemplateInfo::cast(data)->hidden_prototype()) ||
12388 prototype->IsJSGlobalObject();
12389 }
12390 }
12391 map->set_has_hidden_prototype(is_hidden);
12392
12393 WriteBarrierMode wb_mode = prototype->IsNull(map->GetIsolate())
12394 ? SKIP_WRITE_BARRIER
12395 : UPDATE_WRITE_BARRIER;
12396 map->set_prototype(*prototype, wb_mode);
12397 }
12398
12399
CacheInitialJSArrayMaps(Handle<Context> native_context,Handle<Map> initial_map)12400 Handle<Object> CacheInitialJSArrayMaps(
12401 Handle<Context> native_context, Handle<Map> initial_map) {
12402 // Replace all of the cached initial array maps in the native context with
12403 // the appropriate transitioned elements kind maps.
12404 Handle<Map> current_map = initial_map;
12405 ElementsKind kind = current_map->elements_kind();
12406 DCHECK_EQ(GetInitialFastElementsKind(), kind);
12407 native_context->set(Context::ArrayMapIndex(kind), *current_map);
12408 for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1;
12409 i < kFastElementsKindCount; ++i) {
12410 Handle<Map> new_map;
12411 ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
12412 if (Map* maybe_elements_transition = current_map->ElementsTransitionMap()) {
12413 new_map = handle(maybe_elements_transition);
12414 } else {
12415 new_map = Map::CopyAsElementsKind(
12416 current_map, next_kind, INSERT_TRANSITION);
12417 }
12418 DCHECK_EQ(next_kind, new_map->elements_kind());
12419 native_context->set(Context::ArrayMapIndex(next_kind), *new_map);
12420 current_map = new_map;
12421 }
12422 return initial_map;
12423 }
12424
12425
SetInstancePrototype(Handle<JSFunction> function,Handle<Object> value)12426 void JSFunction::SetInstancePrototype(Handle<JSFunction> function,
12427 Handle<Object> value) {
12428 Isolate* isolate = function->GetIsolate();
12429
12430 DCHECK(value->IsJSReceiver());
12431
12432 // Now some logic for the maps of the objects that are created by using this
12433 // function as a constructor.
12434 if (function->has_initial_map()) {
12435 // If the function has allocated the initial map replace it with a
12436 // copy containing the new prototype. Also complete any in-object
12437 // slack tracking that is in progress at this point because it is
12438 // still tracking the old copy.
12439 function->CompleteInobjectSlackTrackingIfActive();
12440
12441 Handle<Map> initial_map(function->initial_map(), isolate);
12442
12443 if (!initial_map->GetIsolate()->bootstrapper()->IsActive() &&
12444 initial_map->instance_type() == JS_OBJECT_TYPE) {
12445 // Put the value in the initial map field until an initial map is needed.
12446 // At that point, a new initial map is created and the prototype is put
12447 // into the initial map where it belongs.
12448 function->set_prototype_or_initial_map(*value);
12449 } else {
12450 Handle<Map> new_map = Map::Copy(initial_map, "SetInstancePrototype");
12451 JSFunction::SetInitialMap(function, new_map, value);
12452
12453 // If the function is used as the global Array function, cache the
12454 // updated initial maps (and transitioned versions) in the native context.
12455 Handle<Context> native_context(function->context()->native_context(),
12456 isolate);
12457 Handle<Object> array_function(
12458 native_context->get(Context::ARRAY_FUNCTION_INDEX), isolate);
12459 if (array_function->IsJSFunction() &&
12460 *function == JSFunction::cast(*array_function)) {
12461 CacheInitialJSArrayMaps(native_context, new_map);
12462 }
12463 }
12464
12465 // Deoptimize all code that embeds the previous initial map.
12466 initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
12467 isolate, DependentCode::kInitialMapChangedGroup);
12468 } else {
12469 // Put the value in the initial map field until an initial map is
12470 // needed. At that point, a new initial map is created and the
12471 // prototype is put into the initial map where it belongs.
12472 function->set_prototype_or_initial_map(*value);
12473 if (value->IsJSObject()) {
12474 // Optimize as prototype to detach it from its transition tree.
12475 JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value),
12476 FAST_PROTOTYPE);
12477 }
12478 }
12479 isolate->heap()->ClearInstanceofCache();
12480 }
12481
12482
SetPrototype(Handle<JSFunction> function,Handle<Object> value)12483 void JSFunction::SetPrototype(Handle<JSFunction> function,
12484 Handle<Object> value) {
12485 DCHECK(function->IsConstructor() ||
12486 IsGeneratorFunction(function->shared()->kind()));
12487 Handle<Object> construct_prototype = value;
12488
12489 // If the value is not a JSReceiver, store the value in the map's
12490 // constructor field so it can be accessed. Also, set the prototype
12491 // used for constructing objects to the original object prototype.
12492 // See ECMA-262 13.2.2.
12493 if (!value->IsJSReceiver()) {
12494 // Copy the map so this does not affect unrelated functions.
12495 // Remove map transitions because they point to maps with a
12496 // different prototype.
12497 Handle<Map> new_map = Map::Copy(handle(function->map()), "SetPrototype");
12498
12499 JSObject::MigrateToMap(function, new_map);
12500 new_map->SetConstructor(*value);
12501 new_map->set_non_instance_prototype(true);
12502 Isolate* isolate = new_map->GetIsolate();
12503
12504 construct_prototype = handle(
12505 IsGeneratorFunction(function->shared()->kind())
12506 ? function->context()
12507 ->native_context()
12508 ->initial_generator_prototype()
12509 : function->context()->native_context()->initial_object_prototype(),
12510 isolate);
12511 } else {
12512 function->map()->set_non_instance_prototype(false);
12513 }
12514
12515 return SetInstancePrototype(function, construct_prototype);
12516 }
12517
12518
RemovePrototype()12519 bool JSFunction::RemovePrototype() {
12520 Context* native_context = context()->native_context();
12521 Map* no_prototype_map =
12522 is_strict(shared()->language_mode())
12523 ? native_context->strict_function_without_prototype_map()
12524 : native_context->sloppy_function_without_prototype_map();
12525
12526 if (map() == no_prototype_map) return true;
12527
12528 #ifdef DEBUG
12529 if (map() != (is_strict(shared()->language_mode())
12530 ? native_context->strict_function_map()
12531 : native_context->sloppy_function_map())) {
12532 return false;
12533 }
12534 #endif
12535
12536 set_map(no_prototype_map);
12537 set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value());
12538 return true;
12539 }
12540
12541
SetInitialMap(Handle<JSFunction> function,Handle<Map> map,Handle<Object> prototype)12542 void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
12543 Handle<Object> prototype) {
12544 if (map->prototype() != *prototype) {
12545 Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
12546 }
12547 function->set_prototype_or_initial_map(*map);
12548 map->SetConstructor(*function);
12549 #if TRACE_MAPS
12550 if (FLAG_trace_maps) {
12551 PrintF("[TraceMaps: InitialMap map= %p SFI= %d_%s ]\n",
12552 reinterpret_cast<void*>(*map), function->shared()->unique_id(),
12553 function->shared()->DebugName()->ToCString().get());
12554 }
12555 #endif
12556 }
12557
12558
12559 #ifdef DEBUG
12560 namespace {
12561
CanSubclassHaveInobjectProperties(InstanceType instance_type)12562 bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
12563 switch (instance_type) {
12564 case JS_API_OBJECT_TYPE:
12565 case JS_ARRAY_BUFFER_TYPE:
12566 case JS_ARRAY_TYPE:
12567 case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
12568 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
12569 case JS_DATA_VIEW_TYPE:
12570 case JS_DATE_TYPE:
12571 case JS_FUNCTION_TYPE:
12572 case JS_GENERATOR_OBJECT_TYPE:
12573 case JS_MAP_ITERATOR_TYPE:
12574 case JS_MAP_TYPE:
12575 case JS_MESSAGE_OBJECT_TYPE:
12576 case JS_OBJECT_TYPE:
12577 case JS_ERROR_TYPE:
12578 case JS_ARGUMENTS_TYPE:
12579 case JS_PROMISE_TYPE:
12580 case JS_REGEXP_TYPE:
12581 case JS_SET_ITERATOR_TYPE:
12582 case JS_SET_TYPE:
12583 case JS_SPECIAL_API_OBJECT_TYPE:
12584 case JS_TYPED_ARRAY_TYPE:
12585 case JS_VALUE_TYPE:
12586 case JS_WEAK_MAP_TYPE:
12587 case JS_WEAK_SET_TYPE:
12588 return true;
12589
12590 case BYTECODE_ARRAY_TYPE:
12591 case BYTE_ARRAY_TYPE:
12592 case CELL_TYPE:
12593 case CODE_TYPE:
12594 case FILLER_TYPE:
12595 case FIXED_ARRAY_TYPE:
12596 case FIXED_DOUBLE_ARRAY_TYPE:
12597 case FOREIGN_TYPE:
12598 case FREE_SPACE_TYPE:
12599 case HEAP_NUMBER_TYPE:
12600 case JS_BOUND_FUNCTION_TYPE:
12601 case JS_GLOBAL_OBJECT_TYPE:
12602 case JS_GLOBAL_PROXY_TYPE:
12603 case JS_PROXY_TYPE:
12604 case MAP_TYPE:
12605 case MUTABLE_HEAP_NUMBER_TYPE:
12606 case ODDBALL_TYPE:
12607 case PROPERTY_CELL_TYPE:
12608 case SHARED_FUNCTION_INFO_TYPE:
12609 case SYMBOL_TYPE:
12610 case WEAK_CELL_TYPE:
12611
12612 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
12613 case FIXED_##TYPE##_ARRAY_TYPE:
12614 #undef TYPED_ARRAY_CASE
12615
12616 #define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE:
12617 STRUCT_LIST(MAKE_STRUCT_CASE)
12618 #undef MAKE_STRUCT_CASE
12619 // We must not end up here for these instance types at all.
12620 UNREACHABLE();
12621 // Fall through.
12622 default:
12623 return false;
12624 }
12625 }
12626
12627 } // namespace
12628 #endif
12629
12630
EnsureHasInitialMap(Handle<JSFunction> function)12631 void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
12632 DCHECK(function->IsConstructor() ||
12633 IsResumableFunction(function->shared()->kind()));
12634 if (function->has_initial_map()) return;
12635 Isolate* isolate = function->GetIsolate();
12636
12637 // The constructor should be compiled for the optimization hints to be
12638 // available.
12639 Compiler::Compile(function, Compiler::CLEAR_EXCEPTION);
12640
12641 // First create a new map with the size and number of in-object properties
12642 // suggested by the function.
12643 InstanceType instance_type;
12644 if (IsResumableFunction(function->shared()->kind())) {
12645 instance_type = JS_GENERATOR_OBJECT_TYPE;
12646 } else {
12647 instance_type = JS_OBJECT_TYPE;
12648 }
12649 int instance_size;
12650 int in_object_properties;
12651 function->CalculateInstanceSize(instance_type, 0, &instance_size,
12652 &in_object_properties);
12653
12654 Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size);
12655
12656 // Fetch or allocate prototype.
12657 Handle<Object> prototype;
12658 if (function->has_instance_prototype()) {
12659 prototype = handle(function->instance_prototype(), isolate);
12660 } else {
12661 prototype = isolate->factory()->NewFunctionPrototype(function);
12662 }
12663 map->SetInObjectProperties(in_object_properties);
12664 map->set_unused_property_fields(in_object_properties);
12665 DCHECK(map->has_fast_object_elements());
12666
12667 // Finally link initial map and constructor function.
12668 DCHECK(prototype->IsJSReceiver());
12669 JSFunction::SetInitialMap(function, map, prototype);
12670 map->StartInobjectSlackTracking();
12671 }
12672
12673 namespace {
FastInitializeDerivedMap(Isolate * isolate,Handle<JSFunction> new_target,Handle<JSFunction> constructor,Handle<Map> constructor_initial_map)12674 bool FastInitializeDerivedMap(Isolate* isolate, Handle<JSFunction> new_target,
12675 Handle<JSFunction> constructor,
12676 Handle<Map> constructor_initial_map) {
12677 // Check that |function|'s initial map still in sync with the |constructor|,
12678 // otherwise we must create a new initial map for |function|.
12679 if (new_target->has_initial_map() &&
12680 new_target->initial_map()->GetConstructor() == *constructor) {
12681 DCHECK(new_target->instance_prototype()->IsJSReceiver());
12682 return true;
12683 }
12684 // Create a new map with the size and number of in-object properties
12685 // suggested by |function|.
12686
12687 // Link initial map and constructor function if the new.target is actually a
12688 // subclass constructor.
12689 if (!IsDerivedConstructor(new_target->shared()->kind())) return false;
12690
12691 Handle<Object> prototype(new_target->instance_prototype(), isolate);
12692 InstanceType instance_type = constructor_initial_map->instance_type();
12693 DCHECK(CanSubclassHaveInobjectProperties(instance_type));
12694
12695 int internal_fields =
12696 JSObject::GetInternalFieldCount(*constructor_initial_map);
12697 int pre_allocated = constructor_initial_map->GetInObjectProperties() -
12698 constructor_initial_map->unused_property_fields();
12699 int instance_size;
12700 int in_object_properties;
12701 new_target->CalculateInstanceSizeForDerivedClass(
12702 instance_type, internal_fields, &instance_size,
12703 &in_object_properties);
12704
12705 int unused_property_fields = in_object_properties - pre_allocated;
12706 Handle<Map> map =
12707 Map::CopyInitialMap(constructor_initial_map, instance_size,
12708 in_object_properties, unused_property_fields);
12709 map->set_new_target_is_base(false);
12710
12711 JSFunction::SetInitialMap(new_target, map, prototype);
12712 map->SetConstructor(*constructor);
12713 map->set_construction_counter(Map::kNoSlackTracking);
12714 map->StartInobjectSlackTracking();
12715
12716 return true;
12717 }
12718
12719 } // namespace
12720
12721 // static
GetDerivedMap(Isolate * isolate,Handle<JSFunction> constructor,Handle<JSReceiver> new_target)12722 MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
12723 Handle<JSFunction> constructor,
12724 Handle<JSReceiver> new_target) {
12725 EnsureHasInitialMap(constructor);
12726
12727 Handle<Map> constructor_initial_map(constructor->initial_map(), isolate);
12728 if (*new_target == *constructor) return constructor_initial_map;
12729
12730 // Fast case, new.target is a subclass of constructor. The map is cacheable
12731 // (and may already have been cached). new.target.prototype is guaranteed to
12732 // be a JSReceiver.
12733 if (new_target->IsJSFunction()) {
12734 Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
12735
12736 // Check that |function|'s initial map still in sync with the |constructor|,
12737 // otherwise we must create a new initial map for |function|.
12738 if (FastInitializeDerivedMap(isolate, function, constructor,
12739 constructor_initial_map)) {
12740 return handle(function->initial_map(), isolate);
12741 }
12742 }
12743
12744 // Slow path, new.target is either a proxy or can't cache the map.
12745 // new.target.prototype is not guaranteed to be a JSReceiver, and may need to
12746 // fall back to the intrinsicDefaultProto.
12747 Handle<Object> prototype;
12748 if (new_target->IsJSFunction()) {
12749 Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
12750 // Make sure the new.target.prototype is cached.
12751 EnsureHasInitialMap(function);
12752 prototype = handle(function->prototype(), isolate);
12753 } else {
12754 Handle<String> prototype_string = isolate->factory()->prototype_string();
12755 ASSIGN_RETURN_ON_EXCEPTION(
12756 isolate, prototype,
12757 JSReceiver::GetProperty(new_target, prototype_string), Map);
12758 // The above prototype lookup might change the constructor and its
12759 // prototype, hence we have to reload the initial map.
12760 EnsureHasInitialMap(constructor);
12761 constructor_initial_map = handle(constructor->initial_map(), isolate);
12762 }
12763
12764 // If prototype is not a JSReceiver, fetch the intrinsicDefaultProto from the
12765 // correct realm. Rather than directly fetching the .prototype, we fetch the
12766 // constructor that points to the .prototype. This relies on
12767 // constructor.prototype being FROZEN for those constructors.
12768 if (!prototype->IsJSReceiver()) {
12769 Handle<Context> context;
12770 ASSIGN_RETURN_ON_EXCEPTION(isolate, context,
12771 JSReceiver::GetFunctionRealm(new_target), Map);
12772 DCHECK(context->IsNativeContext());
12773 Handle<Object> maybe_index = JSReceiver::GetDataProperty(
12774 constructor, isolate->factory()->native_context_index_symbol());
12775 int index = maybe_index->IsSmi() ? Smi::cast(*maybe_index)->value()
12776 : Context::OBJECT_FUNCTION_INDEX;
12777 Handle<JSFunction> realm_constructor(JSFunction::cast(context->get(index)));
12778 prototype = handle(realm_constructor->prototype(), isolate);
12779 }
12780
12781 Handle<Map> map = Map::CopyInitialMap(constructor_initial_map);
12782 map->set_new_target_is_base(false);
12783 DCHECK(prototype->IsJSReceiver());
12784 if (map->prototype() != *prototype) {
12785 Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
12786 }
12787 map->SetConstructor(*constructor);
12788 return map;
12789 }
12790
12791
PrintName(FILE * out)12792 void JSFunction::PrintName(FILE* out) {
12793 std::unique_ptr<char[]> name = shared()->DebugName()->ToCString();
12794 PrintF(out, "%s", name.get());
12795 }
12796
12797
GetName(Handle<JSFunction> function)12798 Handle<String> JSFunction::GetName(Handle<JSFunction> function) {
12799 Isolate* isolate = function->GetIsolate();
12800 Handle<Object> name =
12801 JSReceiver::GetDataProperty(function, isolate->factory()->name_string());
12802 if (name->IsString()) return Handle<String>::cast(name);
12803 return handle(function->shared()->DebugName(), isolate);
12804 }
12805
12806
GetDebugName(Handle<JSFunction> function)12807 Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) {
12808 Isolate* isolate = function->GetIsolate();
12809 Handle<Object> name = JSReceiver::GetDataProperty(
12810 function, isolate->factory()->display_name_string());
12811 if (name->IsString()) return Handle<String>::cast(name);
12812 return JSFunction::GetName(function);
12813 }
12814
SetName(Handle<JSFunction> function,Handle<Name> name,Handle<String> prefix)12815 void JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name,
12816 Handle<String> prefix) {
12817 Isolate* isolate = function->GetIsolate();
12818 Handle<String> function_name = Name::ToFunctionName(name).ToHandleChecked();
12819 if (prefix->length() > 0) {
12820 IncrementalStringBuilder builder(isolate);
12821 builder.AppendString(prefix);
12822 builder.AppendCharacter(' ');
12823 builder.AppendString(function_name);
12824 function_name = builder.Finish().ToHandleChecked();
12825 }
12826 JSObject::DefinePropertyOrElementIgnoreAttributes(
12827 function, isolate->factory()->name_string(), function_name,
12828 static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY))
12829 .ToHandleChecked();
12830 }
12831
12832 namespace {
12833
12834 char const kNativeCodeSource[] = "function () { [native code] }";
12835
12836
NativeCodeFunctionSourceString(Handle<SharedFunctionInfo> shared_info)12837 Handle<String> NativeCodeFunctionSourceString(
12838 Handle<SharedFunctionInfo> shared_info) {
12839 Isolate* const isolate = shared_info->GetIsolate();
12840 if (shared_info->name()->IsString()) {
12841 IncrementalStringBuilder builder(isolate);
12842 builder.AppendCString("function ");
12843 builder.AppendString(handle(String::cast(shared_info->name()), isolate));
12844 builder.AppendCString("() { [native code] }");
12845 return builder.Finish().ToHandleChecked();
12846 }
12847 return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource);
12848 }
12849
12850 } // namespace
12851
12852
12853 // static
ToString(Handle<JSBoundFunction> function)12854 Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) {
12855 Isolate* const isolate = function->GetIsolate();
12856 return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource);
12857 }
12858
12859
12860 // static
ToString(Handle<JSFunction> function)12861 Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
12862 Isolate* const isolate = function->GetIsolate();
12863 Handle<SharedFunctionInfo> shared_info(function->shared(), isolate);
12864
12865 // Check if {function} should hide its source code.
12866 if (!shared_info->IsUserJavaScript()) {
12867 return NativeCodeFunctionSourceString(shared_info);
12868 }
12869
12870 // Check if we should print {function} as a class.
12871 Handle<Object> class_start_position = JSReceiver::GetDataProperty(
12872 function, isolate->factory()->class_start_position_symbol());
12873 if (class_start_position->IsSmi()) {
12874 Handle<Object> class_end_position = JSReceiver::GetDataProperty(
12875 function, isolate->factory()->class_end_position_symbol());
12876 Handle<String> script_source(
12877 String::cast(Script::cast(shared_info->script())->source()), isolate);
12878 return isolate->factory()->NewSubString(
12879 script_source, Handle<Smi>::cast(class_start_position)->value(),
12880 Handle<Smi>::cast(class_end_position)->value());
12881 }
12882
12883 // Check if we have source code for the {function}.
12884 if (!shared_info->HasSourceCode()) {
12885 return NativeCodeFunctionSourceString(shared_info);
12886 }
12887
12888 if (FLAG_harmony_function_tostring) {
12889 return Handle<String>::cast(shared_info->GetSourceCodeHarmony());
12890 }
12891
12892 IncrementalStringBuilder builder(isolate);
12893 FunctionKind kind = shared_info->kind();
12894 if (!IsArrowFunction(kind)) {
12895 if (IsConciseMethod(kind)) {
12896 if (IsGeneratorFunction(kind)) {
12897 builder.AppendCharacter('*');
12898 } else if (IsAsyncFunction(kind)) {
12899 builder.AppendCString("async ");
12900 }
12901 } else {
12902 if (IsGeneratorFunction(kind)) {
12903 builder.AppendCString("function* ");
12904 } else if (IsAsyncFunction(kind)) {
12905 builder.AppendCString("async function ");
12906 } else {
12907 builder.AppendCString("function ");
12908 }
12909 }
12910 if (shared_info->name_should_print_as_anonymous()) {
12911 builder.AppendCString("anonymous");
12912 } else if (!shared_info->is_anonymous_expression()) {
12913 builder.AppendString(handle(String::cast(shared_info->name()), isolate));
12914 }
12915 }
12916 builder.AppendString(Handle<String>::cast(shared_info->GetSourceCode()));
12917 return builder.Finish().ToHandleChecked();
12918 }
12919
Initialize(Isolate * isolate,Handle<Oddball> oddball,const char * to_string,Handle<Object> to_number,const char * type_of,byte kind)12920 void Oddball::Initialize(Isolate* isolate, Handle<Oddball> oddball,
12921 const char* to_string, Handle<Object> to_number,
12922 const char* type_of, byte kind) {
12923 Handle<String> internalized_to_string =
12924 isolate->factory()->InternalizeUtf8String(to_string);
12925 Handle<String> internalized_type_of =
12926 isolate->factory()->InternalizeUtf8String(type_of);
12927 oddball->set_to_number_raw(to_number->Number());
12928 oddball->set_to_number(*to_number);
12929 oddball->set_to_string(*internalized_to_string);
12930 oddball->set_type_of(*internalized_type_of);
12931 oddball->set_kind(kind);
12932 }
12933
SetEvalOrigin(Handle<Script> script,Handle<SharedFunctionInfo> outer_info,int eval_position)12934 void Script::SetEvalOrigin(Handle<Script> script,
12935 Handle<SharedFunctionInfo> outer_info,
12936 int eval_position) {
12937 if (eval_position == kNoSourcePosition) {
12938 // If the position is missing, attempt to get the code offset from the
12939 // current activation. Do not translate the code offset into source
12940 // position, but store it as negative value for lazy translation.
12941 StackTraceFrameIterator it(script->GetIsolate());
12942 if (!it.done() && it.is_javascript()) {
12943 FrameSummary summary = FrameSummary::GetTop(it.javascript_frame());
12944 script->set_eval_from_shared(summary.AsJavaScript().function()->shared());
12945 script->set_eval_from_position(-summary.code_offset());
12946 return;
12947 }
12948 eval_position = 0;
12949 }
12950 script->set_eval_from_shared(*outer_info);
12951 script->set_eval_from_position(eval_position);
12952 }
12953
GetEvalPosition()12954 int Script::GetEvalPosition() {
12955 DisallowHeapAllocation no_gc;
12956 DCHECK(compilation_type() == Script::COMPILATION_TYPE_EVAL);
12957 int position = eval_from_position();
12958 if (position < 0) {
12959 // Due to laziness, the position may not have been translated from code
12960 // offset yet, which would be encoded as negative integer. In that case,
12961 // translate and set the position.
12962 if (eval_from_shared()->IsUndefined(GetIsolate())) {
12963 position = 0;
12964 } else {
12965 SharedFunctionInfo* shared = SharedFunctionInfo::cast(eval_from_shared());
12966 position = shared->abstract_code()->SourcePosition(-position);
12967 }
12968 DCHECK(position >= 0);
12969 set_eval_from_position(position);
12970 }
12971 return position;
12972 }
12973
InitLineEnds(Handle<Script> script)12974 void Script::InitLineEnds(Handle<Script> script) {
12975 Isolate* isolate = script->GetIsolate();
12976 if (!script->line_ends()->IsUndefined(isolate)) return;
12977 DCHECK_NE(Script::TYPE_WASM, script->type());
12978
12979 Object* src_obj = script->source();
12980 if (!src_obj->IsString()) {
12981 DCHECK(src_obj->IsUndefined(isolate));
12982 script->set_line_ends(isolate->heap()->empty_fixed_array());
12983 } else {
12984 DCHECK(src_obj->IsString());
12985 Handle<String> src(String::cast(src_obj), isolate);
12986 Handle<FixedArray> array = String::CalculateLineEnds(src, true);
12987 script->set_line_ends(*array);
12988 }
12989
12990 DCHECK(script->line_ends()->IsFixedArray());
12991 }
12992
GetPositionInfo(Handle<Script> script,int position,PositionInfo * info,OffsetFlag offset_flag)12993 bool Script::GetPositionInfo(Handle<Script> script, int position,
12994 PositionInfo* info, OffsetFlag offset_flag) {
12995 // For wasm, we do not create an artificial line_ends array, but do the
12996 // translation directly.
12997 if (script->type() != Script::TYPE_WASM) InitLineEnds(script);
12998 return script->GetPositionInfo(position, info, offset_flag);
12999 }
13000
13001 namespace {
GetPositionInfoSlow(const Script * script,int position,Script::PositionInfo * info)13002 bool GetPositionInfoSlow(const Script* script, int position,
13003 Script::PositionInfo* info) {
13004 if (!script->source()->IsString()) return false;
13005 if (position < 0) position = 0;
13006
13007 String* source_string = String::cast(script->source());
13008 int line = 0;
13009 int line_start = 0;
13010 int len = source_string->length();
13011 for (int pos = 0; pos <= len; ++pos) {
13012 if (pos == len || source_string->Get(pos) == '\n') {
13013 if (position <= pos) {
13014 info->line = line;
13015 info->column = position - line_start;
13016 info->line_start = line_start;
13017 info->line_end = pos;
13018 return true;
13019 }
13020 line++;
13021 line_start = pos + 1;
13022 }
13023 }
13024 return false;
13025 }
13026 } // namespace
13027
13028 #define SMI_VALUE(x) (Smi::cast(x)->value())
GetPositionInfo(int position,PositionInfo * info,OffsetFlag offset_flag) const13029 bool Script::GetPositionInfo(int position, PositionInfo* info,
13030 OffsetFlag offset_flag) const {
13031 DisallowHeapAllocation no_allocation;
13032
13033 // For wasm, we do not rely on the line_ends array, but do the translation
13034 // directly.
13035 if (type() == Script::TYPE_WASM) {
13036 Handle<WasmCompiledModule> compiled_module(
13037 WasmCompiledModule::cast(wasm_compiled_module()));
13038 DCHECK_LE(0, position);
13039 return compiled_module->GetPositionInfo(static_cast<uint32_t>(position),
13040 info);
13041 }
13042
13043 if (line_ends()->IsUndefined(GetIsolate())) {
13044 // Slow mode: we do not have line_ends. We have to iterate through source.
13045 if (!GetPositionInfoSlow(this, position, info)) return false;
13046 } else {
13047 DCHECK(line_ends()->IsFixedArray());
13048 FixedArray* ends = FixedArray::cast(line_ends());
13049
13050 const int ends_len = ends->length();
13051 if (ends_len == 0) return false;
13052
13053 // Return early on invalid positions. Negative positions behave as if 0 was
13054 // passed, and positions beyond the end of the script return as failure.
13055 if (position < 0) {
13056 position = 0;
13057 } else if (position > SMI_VALUE(ends->get(ends_len - 1))) {
13058 return false;
13059 }
13060
13061 // Determine line number by doing a binary search on the line ends array.
13062 if (SMI_VALUE(ends->get(0)) >= position) {
13063 info->line = 0;
13064 info->line_start = 0;
13065 info->column = position;
13066 } else {
13067 int left = 0;
13068 int right = ends_len - 1;
13069
13070 while (right > 0) {
13071 DCHECK_LE(left, right);
13072 const int mid = (left + right) / 2;
13073 if (position > SMI_VALUE(ends->get(mid))) {
13074 left = mid + 1;
13075 } else if (position <= SMI_VALUE(ends->get(mid - 1))) {
13076 right = mid - 1;
13077 } else {
13078 info->line = mid;
13079 break;
13080 }
13081 }
13082 DCHECK(SMI_VALUE(ends->get(info->line)) >= position &&
13083 SMI_VALUE(ends->get(info->line - 1)) < position);
13084 info->line_start = SMI_VALUE(ends->get(info->line - 1)) + 1;
13085 info->column = position - info->line_start;
13086 }
13087
13088 // Line end is position of the linebreak character.
13089 info->line_end = SMI_VALUE(ends->get(info->line));
13090 if (info->line_end > 0) {
13091 DCHECK(source()->IsString());
13092 String* src = String::cast(source());
13093 if (src->length() >= info->line_end &&
13094 src->Get(info->line_end - 1) == '\r') {
13095 info->line_end--;
13096 }
13097 }
13098 }
13099
13100 // Add offsets if requested.
13101 if (offset_flag == WITH_OFFSET) {
13102 if (info->line == 0) {
13103 info->column += column_offset();
13104 }
13105 info->line += line_offset();
13106 }
13107
13108 return true;
13109 }
13110 #undef SMI_VALUE
13111
GetColumnNumber(Handle<Script> script,int code_pos)13112 int Script::GetColumnNumber(Handle<Script> script, int code_pos) {
13113 PositionInfo info;
13114 GetPositionInfo(script, code_pos, &info, WITH_OFFSET);
13115 return info.column;
13116 }
13117
GetColumnNumber(int code_pos) const13118 int Script::GetColumnNumber(int code_pos) const {
13119 PositionInfo info;
13120 GetPositionInfo(code_pos, &info, WITH_OFFSET);
13121 return info.column;
13122 }
13123
GetLineNumber(Handle<Script> script,int code_pos)13124 int Script::GetLineNumber(Handle<Script> script, int code_pos) {
13125 PositionInfo info;
13126 GetPositionInfo(script, code_pos, &info, WITH_OFFSET);
13127 return info.line;
13128 }
13129
GetLineNumber(int code_pos) const13130 int Script::GetLineNumber(int code_pos) const {
13131 PositionInfo info;
13132 GetPositionInfo(code_pos, &info, WITH_OFFSET);
13133 return info.line;
13134 }
13135
GetNameOrSourceURL()13136 Object* Script::GetNameOrSourceURL() {
13137 Isolate* isolate = GetIsolate();
13138 // Keep in sync with ScriptNameOrSourceURL in messages.js.
13139 if (!source_url()->IsUndefined(isolate)) return source_url();
13140 return name();
13141 }
13142
13143
GetWrapper(Handle<Script> script)13144 Handle<JSObject> Script::GetWrapper(Handle<Script> script) {
13145 Isolate* isolate = script->GetIsolate();
13146 if (!script->wrapper()->IsUndefined(isolate)) {
13147 DCHECK(script->wrapper()->IsWeakCell());
13148 Handle<WeakCell> cell(WeakCell::cast(script->wrapper()));
13149 if (!cell->cleared()) {
13150 // Return a handle for the existing script wrapper from the cache.
13151 return handle(JSObject::cast(cell->value()));
13152 }
13153 // If we found an empty WeakCell, that means the script wrapper was
13154 // GCed. We are not notified directly of that, so we decrement here
13155 // so that we at least don't count double for any given script.
13156 isolate->counters()->script_wrappers()->Decrement();
13157 }
13158 // Construct a new script wrapper.
13159 isolate->counters()->script_wrappers()->Increment();
13160 Handle<JSFunction> constructor = isolate->script_function();
13161 Handle<JSValue> result =
13162 Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
13163 result->set_value(*script);
13164 Handle<WeakCell> cell = isolate->factory()->NewWeakCell(result);
13165 script->set_wrapper(*cell);
13166 return result;
13167 }
13168
FindSharedFunctionInfo(Isolate * isolate,const FunctionLiteral * fun)13169 MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
13170 Isolate* isolate, const FunctionLiteral* fun) {
13171 CHECK_NE(fun->function_literal_id(), FunctionLiteral::kIdTypeInvalid);
13172 CHECK_LT(fun->function_literal_id(), shared_function_infos()->length());
13173 Object* shared = shared_function_infos()->get(fun->function_literal_id());
13174 if (shared->IsUndefined(isolate) || WeakCell::cast(shared)->cleared()) {
13175 return MaybeHandle<SharedFunctionInfo>();
13176 }
13177 return handle(SharedFunctionInfo::cast(WeakCell::cast(shared)->value()));
13178 }
13179
Iterator(Isolate * isolate)13180 Script::Iterator::Iterator(Isolate* isolate)
13181 : iterator_(isolate->heap()->script_list()) {}
13182
13183
Next()13184 Script* Script::Iterator::Next() { return iterator_.Next<Script>(); }
13185
ScriptIterator(Handle<Script> script)13186 SharedFunctionInfo::ScriptIterator::ScriptIterator(Handle<Script> script)
13187 : ScriptIterator(script->GetIsolate(),
13188 handle(script->shared_function_infos())) {}
13189
ScriptIterator(Isolate * isolate,Handle<FixedArray> shared_function_infos)13190 SharedFunctionInfo::ScriptIterator::ScriptIterator(
13191 Isolate* isolate, Handle<FixedArray> shared_function_infos)
13192 : isolate_(isolate),
13193 shared_function_infos_(shared_function_infos),
13194 index_(0) {}
13195
Next()13196 SharedFunctionInfo* SharedFunctionInfo::ScriptIterator::Next() {
13197 while (index_ < shared_function_infos_->length()) {
13198 Object* raw = shared_function_infos_->get(index_++);
13199 if (raw->IsUndefined(isolate_) || WeakCell::cast(raw)->cleared()) continue;
13200 return SharedFunctionInfo::cast(WeakCell::cast(raw)->value());
13201 }
13202 return nullptr;
13203 }
13204
Reset(Handle<Script> script)13205 void SharedFunctionInfo::ScriptIterator::Reset(Handle<Script> script) {
13206 shared_function_infos_ = handle(script->shared_function_infos());
13207 index_ = 0;
13208 }
13209
GlobalIterator(Isolate * isolate)13210 SharedFunctionInfo::GlobalIterator::GlobalIterator(Isolate* isolate)
13211 : script_iterator_(isolate),
13212 noscript_sfi_iterator_(isolate->heap()->noscript_shared_function_infos()),
13213 sfi_iterator_(handle(script_iterator_.Next(), isolate)) {}
13214
Next()13215 SharedFunctionInfo* SharedFunctionInfo::GlobalIterator::Next() {
13216 SharedFunctionInfo* next = noscript_sfi_iterator_.Next<SharedFunctionInfo>();
13217 if (next != nullptr) return next;
13218 for (;;) {
13219 next = sfi_iterator_.Next();
13220 if (next != nullptr) return next;
13221 Script* next_script = script_iterator_.Next();
13222 if (next_script == nullptr) return nullptr;
13223 sfi_iterator_.Reset(handle(next_script));
13224 }
13225 }
13226
13227
SetScript(Handle<SharedFunctionInfo> shared,Handle<Object> script_object)13228 void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
13229 Handle<Object> script_object) {
13230 DCHECK_NE(shared->function_literal_id(), FunctionLiteral::kIdTypeInvalid);
13231 if (shared->script() == *script_object) return;
13232 Isolate* isolate = shared->GetIsolate();
13233
13234 // Add shared function info to new script's list. If a collection occurs,
13235 // the shared function info may be temporarily in two lists.
13236 // This is okay because the gc-time processing of these lists can tolerate
13237 // duplicates.
13238 if (script_object->IsScript()) {
13239 Handle<Script> script = Handle<Script>::cast(script_object);
13240 Handle<FixedArray> list = handle(script->shared_function_infos(), isolate);
13241 #ifdef DEBUG
13242 DCHECK_LT(shared->function_literal_id(), list->length());
13243 if (list->get(shared->function_literal_id())->IsWeakCell() &&
13244 !WeakCell::cast(list->get(shared->function_literal_id()))->cleared()) {
13245 DCHECK(
13246 WeakCell::cast(list->get(shared->function_literal_id()))->value() ==
13247 *shared);
13248 }
13249 #endif
13250 Handle<WeakCell> cell = isolate->factory()->NewWeakCell(shared);
13251 list->set(shared->function_literal_id(), *cell);
13252 } else {
13253 Handle<Object> list = isolate->factory()->noscript_shared_function_infos();
13254
13255 #ifdef DEBUG
13256 if (FLAG_enable_slow_asserts) {
13257 WeakFixedArray::Iterator iterator(*list);
13258 SharedFunctionInfo* next;
13259 while ((next = iterator.Next<SharedFunctionInfo>())) {
13260 DCHECK_NE(next, *shared);
13261 }
13262 }
13263 #endif // DEBUG
13264
13265 list = WeakFixedArray::Add(list, shared);
13266
13267 isolate->heap()->SetRootNoScriptSharedFunctionInfos(*list);
13268 }
13269
13270 if (shared->script()->IsScript()) {
13271 // Remove shared function info from old script's list.
13272 Script* old_script = Script::cast(shared->script());
13273
13274 // Due to liveedit, it might happen that the old_script doesn't know
13275 // about the SharedFunctionInfo, so we have to guard against that.
13276 Handle<FixedArray> infos(old_script->shared_function_infos(), isolate);
13277 if (shared->function_literal_id() < infos->length()) {
13278 Object* raw = old_script->shared_function_infos()->get(
13279 shared->function_literal_id());
13280 if (!raw->IsWeakCell() || WeakCell::cast(raw)->value() == *shared) {
13281 old_script->shared_function_infos()->set(
13282 shared->function_literal_id(), isolate->heap()->undefined_value());
13283 }
13284 }
13285 } else {
13286 // Remove shared function info from root array.
13287 Object* list = isolate->heap()->noscript_shared_function_infos();
13288 CHECK(WeakFixedArray::cast(list)->Remove(shared));
13289 }
13290
13291 // Finally set new script.
13292 shared->set_script(*script_object);
13293 }
13294
13295
DebugName()13296 String* SharedFunctionInfo::DebugName() {
13297 Object* n = name();
13298 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
13299 return String::cast(n);
13300 }
13301
HasNoSideEffect()13302 bool SharedFunctionInfo::HasNoSideEffect() {
13303 if (!computed_has_no_side_effect()) {
13304 DisallowHeapAllocation not_handlified;
13305 Handle<SharedFunctionInfo> info(this);
13306 set_has_no_side_effect(DebugEvaluate::FunctionHasNoSideEffect(info));
13307 set_computed_has_no_side_effect(true);
13308 }
13309 return has_no_side_effect();
13310 }
13311
13312 // The filter is a pattern that matches function names in this way:
13313 // "*" all; the default
13314 // "-" all but the top-level function
13315 // "-name" all but the function "name"
13316 // "" only the top-level function
13317 // "name" only the function "name"
13318 // "name*" only functions starting with "name"
13319 // "~" none; the tilde is not an identifier
PassesFilter(const char * raw_filter)13320 bool SharedFunctionInfo::PassesFilter(const char* raw_filter) {
13321 if (*raw_filter == '*') return true;
13322 String* name = DebugName();
13323 Vector<const char> filter = CStrVector(raw_filter);
13324 if (filter.length() == 0) return name->length() == 0;
13325 if (filter[0] == '-') {
13326 // Negative filter.
13327 if (filter.length() == 1) {
13328 return (name->length() != 0);
13329 } else if (name->IsUtf8EqualTo(filter.SubVector(1, filter.length()))) {
13330 return false;
13331 }
13332 if (filter[filter.length() - 1] == '*' &&
13333 name->IsUtf8EqualTo(filter.SubVector(1, filter.length() - 1), true)) {
13334 return false;
13335 }
13336 return true;
13337
13338 } else if (name->IsUtf8EqualTo(filter)) {
13339 return true;
13340 }
13341 if (filter[filter.length() - 1] == '*' &&
13342 name->IsUtf8EqualTo(filter.SubVector(0, filter.length() - 1), true)) {
13343 return true;
13344 }
13345 return false;
13346 }
13347
HasSourceCode() const13348 bool SharedFunctionInfo::HasSourceCode() const {
13349 Isolate* isolate = GetIsolate();
13350 return !script()->IsUndefined(isolate) &&
13351 !reinterpret_cast<Script*>(script())->source()->IsUndefined(isolate);
13352 }
13353
13354
GetSourceCode()13355 Handle<Object> SharedFunctionInfo::GetSourceCode() {
13356 if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value();
13357 Handle<String> source(String::cast(Script::cast(script())->source()));
13358 return GetIsolate()->factory()->NewSubString(
13359 source, start_position(), end_position());
13360 }
13361
GetSourceCodeHarmony()13362 Handle<Object> SharedFunctionInfo::GetSourceCodeHarmony() {
13363 Isolate* isolate = GetIsolate();
13364 if (!HasSourceCode()) return isolate->factory()->undefined_value();
13365 Handle<String> script_source(String::cast(Script::cast(script())->source()));
13366 int start_pos = function_token_position();
13367 if (start_pos == kNoSourcePosition) start_pos = start_position();
13368 return isolate->factory()->NewSubString(script_source, start_pos,
13369 end_position());
13370 }
13371
IsInlineable()13372 bool SharedFunctionInfo::IsInlineable() {
13373 // Check that the function has a script associated with it.
13374 if (!script()->IsScript()) return false;
13375 return !optimization_disabled();
13376 }
13377
13378
SourceSize()13379 int SharedFunctionInfo::SourceSize() {
13380 return end_position() - start_position();
13381 }
13382
CalculateInstanceSizeHelper(InstanceType instance_type,int requested_internal_fields,int requested_in_object_properties,int * instance_size,int * in_object_properties)13383 void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type,
13384 int requested_internal_fields,
13385 int requested_in_object_properties,
13386 int* instance_size,
13387 int* in_object_properties) {
13388 int header_size = JSObject::GetHeaderSize(instance_type);
13389 int max_nof_fields =
13390 (JSObject::kMaxInstanceSize - header_size) >> kPointerSizeLog2;
13391 CHECK_LE(max_nof_fields, JSObject::kMaxInObjectProperties);
13392 *in_object_properties = Min(requested_in_object_properties, max_nof_fields);
13393 CHECK_LE(requested_internal_fields, max_nof_fields - *in_object_properties);
13394 *instance_size =
13395 header_size +
13396 ((requested_internal_fields + *in_object_properties) << kPointerSizeLog2);
13397 CHECK_EQ(*in_object_properties,
13398 ((*instance_size - header_size) >> kPointerSizeLog2) -
13399 requested_internal_fields);
13400 }
13401
13402
CalculateInstanceSize(InstanceType instance_type,int requested_internal_fields,int * instance_size,int * in_object_properties)13403 void JSFunction::CalculateInstanceSize(InstanceType instance_type,
13404 int requested_internal_fields,
13405 int* instance_size,
13406 int* in_object_properties) {
13407 CalculateInstanceSizeHelper(instance_type, requested_internal_fields,
13408 shared()->expected_nof_properties(),
13409 instance_size, in_object_properties);
13410 }
13411
13412
CalculateInstanceSizeForDerivedClass(InstanceType instance_type,int requested_internal_fields,int * instance_size,int * in_object_properties)13413 void JSFunction::CalculateInstanceSizeForDerivedClass(
13414 InstanceType instance_type, int requested_internal_fields,
13415 int* instance_size, int* in_object_properties) {
13416 Isolate* isolate = GetIsolate();
13417 int expected_nof_properties = 0;
13418 for (PrototypeIterator iter(isolate, this, kStartAtReceiver); !iter.IsAtEnd();
13419 iter.Advance()) {
13420 JSReceiver* current = iter.GetCurrent<JSReceiver>();
13421 if (!current->IsJSFunction()) break;
13422 JSFunction* func = JSFunction::cast(current);
13423 SharedFunctionInfo* shared = func->shared();
13424 int count = shared->expected_nof_properties();
13425 // Check that the estimate is sane.
13426 if (expected_nof_properties <= JSObject::kMaxInObjectProperties - count) {
13427 expected_nof_properties += count;
13428 } else {
13429 expected_nof_properties = JSObject::kMaxInObjectProperties;
13430 }
13431 if (!IsDerivedConstructor(shared->kind())) {
13432 break;
13433 }
13434 }
13435 CalculateInstanceSizeHelper(instance_type, requested_internal_fields,
13436 expected_nof_properties, instance_size,
13437 in_object_properties);
13438 }
13439
13440
13441 // Output the source code without any allocation in the heap.
operator <<(std::ostream & os,const SourceCodeOf & v)13442 std::ostream& operator<<(std::ostream& os, const SourceCodeOf& v) {
13443 const SharedFunctionInfo* s = v.value;
13444 // For some native functions there is no source.
13445 if (!s->HasSourceCode()) return os << "<No Source>";
13446
13447 // Get the source for the script which this function came from.
13448 // Don't use String::cast because we don't want more assertion errors while
13449 // we are already creating a stack dump.
13450 String* script_source =
13451 reinterpret_cast<String*>(Script::cast(s->script())->source());
13452
13453 if (!script_source->LooksValid()) return os << "<Invalid Source>";
13454
13455 if (!s->is_toplevel()) {
13456 os << "function ";
13457 Object* name = s->name();
13458 if (name->IsString() && String::cast(name)->length() > 0) {
13459 String::cast(name)->PrintUC16(os);
13460 }
13461 }
13462
13463 int len = s->end_position() - s->start_position();
13464 if (len <= v.max_length || v.max_length < 0) {
13465 script_source->PrintUC16(os, s->start_position(), s->end_position());
13466 return os;
13467 } else {
13468 script_source->PrintUC16(os, s->start_position(),
13469 s->start_position() + v.max_length);
13470 return os << "...\n";
13471 }
13472 }
13473
13474
IsCodeEquivalent(Code * code,Code * recompiled)13475 static bool IsCodeEquivalent(Code* code, Code* recompiled) {
13476 if (code->instruction_size() != recompiled->instruction_size()) return false;
13477 ByteArray* code_relocation = code->relocation_info();
13478 ByteArray* recompiled_relocation = recompiled->relocation_info();
13479 int length = code_relocation->length();
13480 if (length != recompiled_relocation->length()) return false;
13481 int compare = memcmp(code_relocation->GetDataStartAddress(),
13482 recompiled_relocation->GetDataStartAddress(),
13483 length);
13484 return compare == 0;
13485 }
13486
13487
EnableDeoptimizationSupport(Code * recompiled)13488 void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
13489 DCHECK(!has_deoptimization_support());
13490 DisallowHeapAllocation no_allocation;
13491 Code* code = this->code();
13492 if (IsCodeEquivalent(code, recompiled)) {
13493 // Copy the deoptimization data from the recompiled code.
13494 code->set_deoptimization_data(recompiled->deoptimization_data());
13495 code->set_has_deoptimization_support(true);
13496 } else {
13497 // TODO(3025757): In case the recompiled isn't equivalent to the
13498 // old code, we have to replace it. We should try to avoid this
13499 // altogether because it flushes valuable type feedback by
13500 // effectively resetting all IC state.
13501 ReplaceCode(recompiled);
13502 }
13503 DCHECK(has_deoptimization_support());
13504 }
13505
13506
DisableOptimization(BailoutReason reason)13507 void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
13508 // Disable optimization for the shared function info and mark the
13509 // code as non-optimizable. The marker on the shared function info
13510 // is there because we flush non-optimized code thereby loosing the
13511 // non-optimizable information for the code. When the code is
13512 // regenerated and set on the shared function info it is marked as
13513 // non-optimizable if optimization is disabled for the shared
13514 // function info.
13515 DCHECK(reason != kNoReason);
13516 set_optimization_disabled(true);
13517 set_disable_optimization_reason(reason);
13518 // Code should be the lazy compilation stub or else unoptimized.
13519 DCHECK(abstract_code()->kind() == AbstractCode::FUNCTION ||
13520 abstract_code()->kind() == AbstractCode::INTERPRETED_FUNCTION ||
13521 abstract_code()->kind() == AbstractCode::BUILTIN);
13522 PROFILE(GetIsolate(), CodeDisableOptEvent(abstract_code(), this));
13523 if (FLAG_trace_opt) {
13524 PrintF("[disabled optimization for ");
13525 ShortPrint();
13526 PrintF(", reason: %s]\n", GetBailoutReason(reason));
13527 }
13528 }
13529
13530 namespace {
13531
13532 // Sets the expected number of properties based on estimate from parser.
SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared,FunctionLiteral * literal)13533 void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared,
13534 FunctionLiteral* literal) {
13535 int estimate = literal->expected_property_count();
13536
13537 // If no properties are added in the constructor, they are more likely
13538 // to be added later.
13539 if (estimate == 0) estimate = 2;
13540
13541 // TODO(yangguo): check whether those heuristics are still up-to-date.
13542 // We do not shrink objects that go into a snapshot (yet), so we adjust
13543 // the estimate conservatively.
13544 if (shared->GetIsolate()->serializer_enabled()) {
13545 estimate += 2;
13546 } else {
13547 // Inobject slack tracking will reclaim redundant inobject space later,
13548 // so we can afford to adjust the estimate generously.
13549 estimate += 8;
13550 }
13551
13552 shared->set_expected_nof_properties(estimate);
13553 }
13554
13555 } // namespace
13556
InitFromFunctionLiteral(Handle<SharedFunctionInfo> shared_info,FunctionLiteral * lit)13557 void SharedFunctionInfo::InitFromFunctionLiteral(
13558 Handle<SharedFunctionInfo> shared_info, FunctionLiteral* lit) {
13559 // When adding fields here, make sure DeclarationScope::AnalyzePartially is
13560 // updated accordingly.
13561 shared_info->set_length(lit->function_length());
13562 shared_info->set_internal_formal_parameter_count(lit->parameter_count());
13563 shared_info->set_function_token_position(lit->function_token_position());
13564 shared_info->set_start_position(lit->start_position());
13565 shared_info->set_end_position(lit->end_position());
13566 shared_info->set_is_declaration(lit->is_declaration());
13567 shared_info->set_is_named_expression(lit->is_named_expression());
13568 shared_info->set_is_anonymous_expression(lit->is_anonymous_expression());
13569 shared_info->set_inferred_name(*lit->inferred_name());
13570 shared_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
13571 shared_info->set_language_mode(lit->language_mode());
13572 shared_info->set_uses_arguments(lit->scope()->arguments() != NULL);
13573 shared_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
13574 shared_info->set_kind(lit->kind());
13575 if (!IsConstructable(lit->kind(), lit->language_mode())) {
13576 shared_info->SetConstructStub(
13577 *shared_info->GetIsolate()->builtins()->ConstructedNonConstructable());
13578 }
13579 shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
13580 shared_info->set_asm_function(lit->scope()->asm_function());
13581 shared_info->set_function_literal_id(lit->function_literal_id());
13582 SetExpectedNofPropertiesFromEstimate(shared_info, lit);
13583 }
13584
13585
VerifyBailoutId(BailoutId id)13586 bool SharedFunctionInfo::VerifyBailoutId(BailoutId id) {
13587 DCHECK(!id.IsNone());
13588 Code* unoptimized = code();
13589 DeoptimizationOutputData* data =
13590 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
13591 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
13592 USE(ignore);
13593 return true; // Return true if there was no DCHECK.
13594 }
13595
SetConstructStub(Code * code)13596 void SharedFunctionInfo::SetConstructStub(Code* code) {
13597 if (code->kind() == Code::BUILTIN) code->set_is_construct_stub(true);
13598 set_construct_stub(code);
13599 }
13600
StartInobjectSlackTracking()13601 void Map::StartInobjectSlackTracking() {
13602 DCHECK(!IsInobjectSlackTrackingInProgress());
13603
13604 // No tracking during the snapshot construction phase.
13605 Isolate* isolate = GetIsolate();
13606 if (isolate->serializer_enabled()) return;
13607
13608 if (unused_property_fields() == 0) return;
13609
13610 set_construction_counter(Map::kSlackTrackingCounterStart);
13611 }
13612
13613
ResetForNewContext(int new_ic_age)13614 void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
13615 code()->ClearInlineCaches();
13616 set_ic_age(new_ic_age);
13617 if (code()->kind() == Code::FUNCTION) {
13618 code()->set_profiler_ticks(0);
13619 if (optimization_disabled() && opt_count() >= FLAG_max_opt_count) {
13620 // Re-enable optimizations if they were disabled due to opt_count limit.
13621 set_optimization_disabled(false);
13622 }
13623 set_opt_count(0);
13624 set_deopt_count(0);
13625 } else if (IsInterpreted()) {
13626 set_profiler_ticks(0);
13627 if (optimization_disabled() && opt_count() >= FLAG_max_opt_count) {
13628 // Re-enable optimizations if they were disabled due to opt_count limit.
13629 set_optimization_disabled(false);
13630 }
13631 set_opt_count(0);
13632 set_deopt_count(0);
13633 }
13634 }
13635
SearchOptimizedCodeMapEntry(Context * native_context)13636 int SharedFunctionInfo::SearchOptimizedCodeMapEntry(Context* native_context) {
13637 DisallowHeapAllocation no_gc;
13638 DCHECK(native_context->IsNativeContext());
13639 if (!OptimizedCodeMapIsCleared()) {
13640 FixedArray* optimized_code_map = this->optimized_code_map();
13641 int length = optimized_code_map->length();
13642 for (int i = kEntriesStart; i < length; i += kEntryLength) {
13643 if (WeakCell::cast(optimized_code_map->get(i + kContextOffset))
13644 ->value() == native_context) {
13645 return i;
13646 }
13647 }
13648 }
13649 return -1;
13650 }
13651
ClearCodeFromOptimizedCodeMap()13652 void SharedFunctionInfo::ClearCodeFromOptimizedCodeMap() {
13653 if (!OptimizedCodeMapIsCleared()) {
13654 FixedArray* optimized_code_map = this->optimized_code_map();
13655 int length = optimized_code_map->length();
13656 WeakCell* empty_weak_cell = GetHeap()->empty_weak_cell();
13657 for (int i = kEntriesStart; i < length; i += kEntryLength) {
13658 optimized_code_map->set(i + kCachedCodeOffset, empty_weak_cell,
13659 SKIP_WRITE_BARRIER);
13660 }
13661 }
13662 }
13663
SearchOptimizedCodeMap(Context * native_context,BailoutId osr_ast_id)13664 Code* SharedFunctionInfo::SearchOptimizedCodeMap(Context* native_context,
13665 BailoutId osr_ast_id) {
13666 Code* result = nullptr;
13667 if (!osr_ast_id.IsNone()) {
13668 return native_context->SearchOptimizedCodeMap(this, osr_ast_id);
13669 }
13670
13671 DCHECK(osr_ast_id.IsNone());
13672 int entry = SearchOptimizedCodeMapEntry(native_context);
13673 if (entry != kNotFound) {
13674 FixedArray* code_map = optimized_code_map();
13675 DCHECK_LE(entry + kEntryLength, code_map->length());
13676 WeakCell* cell = WeakCell::cast(code_map->get(entry + kCachedCodeOffset));
13677 result = cell->cleared() ? nullptr : Code::cast(cell->value());
13678 }
13679 return result;
13680 }
13681
13682
13683 #define DECLARE_TAG(ignore1, name, ignore2) name,
13684 const char* const VisitorSynchronization::kTags[
13685 VisitorSynchronization::kNumberOfSyncTags] = {
13686 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
13687 };
13688 #undef DECLARE_TAG
13689
13690
13691 #define DECLARE_TAG(ignore1, ignore2, name) name,
13692 const char* const VisitorSynchronization::kTagNames[
13693 VisitorSynchronization::kNumberOfSyncTags] = {
13694 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
13695 };
13696 #undef DECLARE_TAG
13697
13698
VisitCodeTarget(RelocInfo * rinfo)13699 void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
13700 DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode()));
13701 Object* old_pointer = Code::GetCodeFromTargetAddress(rinfo->target_address());
13702 Object* new_pointer = old_pointer;
13703 VisitPointer(&new_pointer);
13704 DCHECK_EQ(old_pointer, new_pointer);
13705 }
13706
13707
VisitCodeAgeSequence(RelocInfo * rinfo)13708 void ObjectVisitor::VisitCodeAgeSequence(RelocInfo* rinfo) {
13709 DCHECK(RelocInfo::IsCodeAgeSequence(rinfo->rmode()));
13710 Object* old_pointer = rinfo->code_age_stub();
13711 Object* new_pointer = old_pointer;
13712 if (old_pointer != nullptr) {
13713 VisitPointer(&new_pointer);
13714 DCHECK_EQ(old_pointer, new_pointer);
13715 }
13716 }
13717
13718
VisitCodeEntry(Address entry_address)13719 void ObjectVisitor::VisitCodeEntry(Address entry_address) {
13720 Object* old_pointer = Code::GetObjectFromEntryAddress(entry_address);
13721 Object* new_pointer = old_pointer;
13722 VisitPointer(&new_pointer);
13723 DCHECK_EQ(old_pointer, new_pointer);
13724 }
13725
13726
VisitCell(RelocInfo * rinfo)13727 void ObjectVisitor::VisitCell(RelocInfo* rinfo) {
13728 DCHECK(rinfo->rmode() == RelocInfo::CELL);
13729 Object* old_pointer = rinfo->target_cell();
13730 Object* new_pointer = old_pointer;
13731 VisitPointer(&new_pointer);
13732 DCHECK_EQ(old_pointer, new_pointer);
13733 }
13734
13735
VisitDebugTarget(RelocInfo * rinfo)13736 void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
13737 DCHECK(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
13738 rinfo->IsPatchedDebugBreakSlotSequence());
13739 Object* old_pointer =
13740 Code::GetCodeFromTargetAddress(rinfo->debug_call_address());
13741 Object* new_pointer = old_pointer;
13742 VisitPointer(&new_pointer);
13743 DCHECK_EQ(old_pointer, new_pointer);
13744 }
13745
13746
VisitEmbeddedPointer(RelocInfo * rinfo)13747 void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
13748 DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
13749 Object* old_pointer = rinfo->target_object();
13750 Object* new_pointer = old_pointer;
13751 VisitPointer(&new_pointer);
13752 DCHECK_EQ(old_pointer, new_pointer);
13753 }
13754
13755
VisitExternalReference(RelocInfo * rinfo)13756 void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
13757 Address old_reference = rinfo->target_external_reference();
13758 Address new_reference = old_reference;
13759 VisitExternalReference(&new_reference);
13760 DCHECK_EQ(old_reference, new_reference);
13761 }
13762
13763
InvalidateRelocation()13764 void Code::InvalidateRelocation() {
13765 InvalidateEmbeddedObjects();
13766 set_relocation_info(GetHeap()->empty_byte_array());
13767 }
13768
13769
InvalidateEmbeddedObjects()13770 void Code::InvalidateEmbeddedObjects() {
13771 Object* undefined = GetHeap()->undefined_value();
13772 Cell* undefined_cell = GetHeap()->undefined_cell();
13773 int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
13774 RelocInfo::ModeMask(RelocInfo::CELL);
13775 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
13776 RelocInfo::Mode mode = it.rinfo()->rmode();
13777 if (mode == RelocInfo::EMBEDDED_OBJECT) {
13778 it.rinfo()->set_target_object(undefined, SKIP_WRITE_BARRIER);
13779 } else if (mode == RelocInfo::CELL) {
13780 it.rinfo()->set_target_cell(undefined_cell, SKIP_WRITE_BARRIER);
13781 }
13782 }
13783 }
13784
13785
Relocate(intptr_t delta)13786 void Code::Relocate(intptr_t delta) {
13787 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
13788 it.rinfo()->apply(delta);
13789 }
13790 Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size());
13791 }
13792
13793
CopyFrom(const CodeDesc & desc)13794 void Code::CopyFrom(const CodeDesc& desc) {
13795 // copy code
13796 CopyBytes(instruction_start(), desc.buffer,
13797 static_cast<size_t>(desc.instr_size));
13798
13799 // copy unwinding info, if any
13800 if (desc.unwinding_info) {
13801 DCHECK_GT(desc.unwinding_info_size, 0);
13802 set_unwinding_info_size(desc.unwinding_info_size);
13803 CopyBytes(unwinding_info_start(), desc.unwinding_info,
13804 static_cast<size_t>(desc.unwinding_info_size));
13805 }
13806
13807 // copy reloc info
13808 CopyBytes(relocation_start(),
13809 desc.buffer + desc.buffer_size - desc.reloc_size,
13810 static_cast<size_t>(desc.reloc_size));
13811
13812 // unbox handles and relocate
13813 intptr_t delta = instruction_start() - desc.buffer;
13814 int mode_mask = RelocInfo::kCodeTargetMask |
13815 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
13816 RelocInfo::ModeMask(RelocInfo::CELL) |
13817 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
13818 RelocInfo::kApplyMask;
13819 // Needed to find target_object and runtime_entry on X64
13820 Assembler* origin = desc.origin;
13821 AllowDeferredHandleDereference embedding_raw_address;
13822 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
13823 RelocInfo::Mode mode = it.rinfo()->rmode();
13824 if (mode == RelocInfo::EMBEDDED_OBJECT) {
13825 Handle<Object> p = it.rinfo()->target_object_handle(origin);
13826 it.rinfo()->set_target_object(*p, UPDATE_WRITE_BARRIER,
13827 SKIP_ICACHE_FLUSH);
13828 } else if (mode == RelocInfo::CELL) {
13829 Handle<Cell> cell = it.rinfo()->target_cell_handle();
13830 it.rinfo()->set_target_cell(*cell, UPDATE_WRITE_BARRIER,
13831 SKIP_ICACHE_FLUSH);
13832 } else if (RelocInfo::IsCodeTarget(mode)) {
13833 // rewrite code handles in inline cache targets to direct
13834 // pointers to the first instruction in the code object
13835 Handle<Object> p = it.rinfo()->target_object_handle(origin);
13836 Code* code = Code::cast(*p);
13837 it.rinfo()->set_target_address(code->instruction_start(),
13838 UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
13839 } else if (RelocInfo::IsRuntimeEntry(mode)) {
13840 Address p = it.rinfo()->target_runtime_entry(origin);
13841 it.rinfo()->set_target_runtime_entry(p, UPDATE_WRITE_BARRIER,
13842 SKIP_ICACHE_FLUSH);
13843 } else if (mode == RelocInfo::CODE_AGE_SEQUENCE) {
13844 Handle<Object> p = it.rinfo()->code_age_stub_handle(origin);
13845 Code* code = Code::cast(*p);
13846 it.rinfo()->set_code_age_stub(code, SKIP_ICACHE_FLUSH);
13847 } else {
13848 it.rinfo()->apply(delta);
13849 }
13850 }
13851 Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size());
13852 }
13853
13854
GetSafepointEntry(Address pc)13855 SafepointEntry Code::GetSafepointEntry(Address pc) {
13856 SafepointTable table(this);
13857 return table.FindEntry(pc);
13858 }
13859
13860
FindNthObject(int n,Map * match_map)13861 Object* Code::FindNthObject(int n, Map* match_map) {
13862 DCHECK(is_inline_cache_stub());
13863 DisallowHeapAllocation no_allocation;
13864 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
13865 for (RelocIterator it(this, mask); !it.done(); it.next()) {
13866 RelocInfo* info = it.rinfo();
13867 Object* object = info->target_object();
13868 if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
13869 if (object->IsHeapObject()) {
13870 if (HeapObject::cast(object)->map() == match_map) {
13871 if (--n == 0) return object;
13872 }
13873 }
13874 }
13875 return NULL;
13876 }
13877
13878
FindFirstAllocationSite()13879 AllocationSite* Code::FindFirstAllocationSite() {
13880 Object* result = FindNthObject(1, GetHeap()->allocation_site_map());
13881 return (result != NULL) ? AllocationSite::cast(result) : NULL;
13882 }
13883
13884
FindFirstMap()13885 Map* Code::FindFirstMap() {
13886 Object* result = FindNthObject(1, GetHeap()->meta_map());
13887 return (result != NULL) ? Map::cast(result) : NULL;
13888 }
13889
13890
FindAndReplace(const FindAndReplacePattern & pattern)13891 void Code::FindAndReplace(const FindAndReplacePattern& pattern) {
13892 DCHECK(is_inline_cache_stub() || is_handler());
13893 DisallowHeapAllocation no_allocation;
13894 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
13895 STATIC_ASSERT(FindAndReplacePattern::kMaxCount < 32);
13896 int current_pattern = 0;
13897 for (RelocIterator it(this, mask); !it.done(); it.next()) {
13898 RelocInfo* info = it.rinfo();
13899 Object* object = info->target_object();
13900 if (object->IsHeapObject()) {
13901 if (object->IsWeakCell()) {
13902 object = HeapObject::cast(WeakCell::cast(object)->value());
13903 }
13904 Map* map = HeapObject::cast(object)->map();
13905 if (map == *pattern.find_[current_pattern]) {
13906 info->set_target_object(*pattern.replace_[current_pattern]);
13907 if (++current_pattern == pattern.count_) return;
13908 }
13909 }
13910 }
13911 UNREACHABLE();
13912 }
13913
13914
ClearInlineCaches()13915 void Code::ClearInlineCaches() {
13916 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
13917 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
13918 for (RelocIterator it(this, mask); !it.done(); it.next()) {
13919 RelocInfo* info = it.rinfo();
13920 Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
13921 if (target->is_inline_cache_stub()) {
13922 ICUtility::Clear(this->GetIsolate(), info->pc(),
13923 info->host()->constant_pool());
13924 }
13925 }
13926 }
13927
SourcePosition(int offset)13928 int AbstractCode::SourcePosition(int offset) {
13929 int position = 0;
13930 // Subtract one because the current PC is one instruction after the call site.
13931 if (IsCode()) offset--;
13932 for (SourcePositionTableIterator iterator(source_position_table());
13933 !iterator.done() && iterator.code_offset() <= offset;
13934 iterator.Advance()) {
13935 position = iterator.source_position().ScriptOffset();
13936 }
13937 return position;
13938 }
13939
SourceStatementPosition(int offset)13940 int AbstractCode::SourceStatementPosition(int offset) {
13941 // First find the closest position.
13942 int position = SourcePosition(offset);
13943 // Now find the closest statement position before the position.
13944 int statement_position = 0;
13945 for (SourcePositionTableIterator it(source_position_table()); !it.done();
13946 it.Advance()) {
13947 if (it.is_statement()) {
13948 int p = it.source_position().ScriptOffset();
13949 if (statement_position < p && p <= position) {
13950 statement_position = p;
13951 }
13952 }
13953 }
13954 return statement_position;
13955 }
13956
ClearTypeFeedbackInfo()13957 void JSFunction::ClearTypeFeedbackInfo() {
13958 if (feedback_vector_cell()->value()->IsFeedbackVector()) {
13959 FeedbackVector* vector = feedback_vector();
13960 vector->ClearSlots(this);
13961 }
13962 }
13963
TranslatePcOffsetToAstId(uint32_t pc_offset)13964 BailoutId Code::TranslatePcOffsetToAstId(uint32_t pc_offset) {
13965 DisallowHeapAllocation no_gc;
13966 DCHECK(kind() == FUNCTION);
13967 BackEdgeTable back_edges(this, &no_gc);
13968 for (uint32_t i = 0; i < back_edges.length(); i++) {
13969 if (back_edges.pc_offset(i) == pc_offset) return back_edges.ast_id(i);
13970 }
13971 return BailoutId::None();
13972 }
13973
13974
TranslateAstIdToPcOffset(BailoutId ast_id)13975 uint32_t Code::TranslateAstIdToPcOffset(BailoutId ast_id) {
13976 DisallowHeapAllocation no_gc;
13977 DCHECK(kind() == FUNCTION);
13978 BackEdgeTable back_edges(this, &no_gc);
13979 for (uint32_t i = 0; i < back_edges.length(); i++) {
13980 if (back_edges.ast_id(i) == ast_id) return back_edges.pc_offset(i);
13981 }
13982 UNREACHABLE(); // We expect to find the back edge.
13983 return 0;
13984 }
13985
MakeCodeAgeSequenceYoung(byte * sequence,Isolate * isolate)13986 void Code::MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate) {
13987 PatchPlatformCodeAge(isolate, sequence, kNoAgeCodeAge);
13988 }
13989
13990
MarkCodeAsExecuted(byte * sequence,Isolate * isolate)13991 void Code::MarkCodeAsExecuted(byte* sequence, Isolate* isolate) {
13992 PatchPlatformCodeAge(isolate, sequence, kExecutedOnceCodeAge);
13993 }
13994
13995
13996 // NextAge defines the Code::Age state transitions during a GC cycle.
NextAge(Code::Age age)13997 static Code::Age NextAge(Code::Age age) {
13998 switch (age) {
13999 case Code::kNotExecutedCodeAge: // Keep, until we've been executed.
14000 case Code::kToBeExecutedOnceCodeAge: // Keep, until we've been executed.
14001 case Code::kLastCodeAge: // Clamp at last Code::Age value.
14002 return age;
14003 case Code::kExecutedOnceCodeAge:
14004 // Pre-age code that has only been executed once.
14005 return static_cast<Code::Age>(Code::kPreAgedCodeAge + 1);
14006 default:
14007 return static_cast<Code::Age>(age + 1); // Default case: Increase age.
14008 }
14009 }
14010
14011
14012 // IsOldAge defines the collection criteria for a Code object.
IsOldAge(Code::Age age)14013 static bool IsOldAge(Code::Age age) {
14014 return age >= Code::kIsOldCodeAge || age == Code::kNotExecutedCodeAge;
14015 }
14016
14017
MakeYoung(Isolate * isolate)14018 void Code::MakeYoung(Isolate* isolate) {
14019 byte* sequence = FindCodeAgeSequence();
14020 if (sequence != NULL) MakeCodeAgeSequenceYoung(sequence, isolate);
14021 }
14022
PreAge(Isolate * isolate)14023 void Code::PreAge(Isolate* isolate) {
14024 byte* sequence = FindCodeAgeSequence();
14025 if (sequence != NULL) {
14026 PatchPlatformCodeAge(isolate, sequence, kPreAgedCodeAge);
14027 }
14028 }
14029
MarkToBeExecutedOnce(Isolate * isolate)14030 void Code::MarkToBeExecutedOnce(Isolate* isolate) {
14031 byte* sequence = FindCodeAgeSequence();
14032 if (sequence != NULL) {
14033 PatchPlatformCodeAge(isolate, sequence, kToBeExecutedOnceCodeAge);
14034 }
14035 }
14036
MakeOlder()14037 void Code::MakeOlder() {
14038 byte* sequence = FindCodeAgeSequence();
14039 if (sequence != NULL) {
14040 Isolate* isolate = GetIsolate();
14041 Age age = GetCodeAge(isolate, sequence);
14042 Age next_age = NextAge(age);
14043 if (age != next_age) {
14044 PatchPlatformCodeAge(isolate, sequence, next_age);
14045 }
14046 }
14047 }
14048
14049
IsOld()14050 bool Code::IsOld() {
14051 return IsOldAge(GetAge());
14052 }
14053
14054
FindCodeAgeSequence()14055 byte* Code::FindCodeAgeSequence() {
14056 return FLAG_age_code &&
14057 prologue_offset() != Code::kPrologueOffsetNotSet &&
14058 (kind() == OPTIMIZED_FUNCTION ||
14059 (kind() == FUNCTION && !has_debug_break_slots()))
14060 ? instruction_start() + prologue_offset()
14061 : NULL;
14062 }
14063
14064
GetAge()14065 Code::Age Code::GetAge() {
14066 byte* sequence = FindCodeAgeSequence();
14067 if (sequence == NULL) {
14068 return kNoAgeCodeAge;
14069 }
14070 return GetCodeAge(GetIsolate(), sequence);
14071 }
14072
GetAgeOfCodeAgeStub(Code * code)14073 Code::Age Code::GetAgeOfCodeAgeStub(Code* code) {
14074 Isolate* isolate = code->GetIsolate();
14075 Builtins* builtins = isolate->builtins();
14076 #define HANDLE_CODE_AGE(AGE) \
14077 if (code == *builtins->Make##AGE##CodeYoungAgain()) { \
14078 return k##AGE##CodeAge; \
14079 }
14080 CODE_AGE_LIST(HANDLE_CODE_AGE)
14081 #undef HANDLE_CODE_AGE
14082 if (code == *builtins->MarkCodeAsExecutedOnce()) {
14083 return kNotExecutedCodeAge;
14084 }
14085 if (code == *builtins->MarkCodeAsExecutedTwice()) {
14086 return kExecutedOnceCodeAge;
14087 }
14088 if (code == *builtins->MarkCodeAsToBeExecutedOnce()) {
14089 return kToBeExecutedOnceCodeAge;
14090 }
14091 UNREACHABLE();
14092 return kNoAgeCodeAge;
14093 }
14094
GetCodeAgeStub(Isolate * isolate,Age age)14095 Code* Code::GetCodeAgeStub(Isolate* isolate, Age age) {
14096 Builtins* builtins = isolate->builtins();
14097 switch (age) {
14098 #define HANDLE_CODE_AGE(AGE) \
14099 case k##AGE##CodeAge: { \
14100 return *builtins->Make##AGE##CodeYoungAgain(); \
14101 }
14102 CODE_AGE_LIST(HANDLE_CODE_AGE)
14103 #undef HANDLE_CODE_AGE
14104 case kNotExecutedCodeAge: {
14105 return *builtins->MarkCodeAsExecutedOnce();
14106 }
14107 case kExecutedOnceCodeAge: {
14108 return *builtins->MarkCodeAsExecutedTwice();
14109 }
14110 case kToBeExecutedOnceCodeAge: {
14111 return *builtins->MarkCodeAsToBeExecutedOnce();
14112 }
14113 default:
14114 UNREACHABLE();
14115 break;
14116 }
14117 return NULL;
14118 }
14119
14120
PrintDeoptLocation(FILE * out,Address pc)14121 void Code::PrintDeoptLocation(FILE* out, Address pc) {
14122 Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(this, pc);
14123 class SourcePosition pos = info.position;
14124 if (info.deopt_reason != DeoptimizeReason::kNoReason || pos.IsKnown()) {
14125 if (FLAG_hydrogen_track_positions) {
14126 PrintF(out, " ;;; deoptimize at %d_%d: %s\n", pos.InliningId(),
14127 pos.ScriptOffset(), DeoptimizeReasonToString(info.deopt_reason));
14128 } else {
14129 PrintF(out, " ;;; deoptimize at ");
14130 OFStream outstr(out);
14131 pos.Print(outstr, this);
14132 PrintF(out, ", %s\n", DeoptimizeReasonToString(info.deopt_reason));
14133 }
14134 }
14135 }
14136
14137
CanDeoptAt(Address pc)14138 bool Code::CanDeoptAt(Address pc) {
14139 DeoptimizationInputData* deopt_data =
14140 DeoptimizationInputData::cast(deoptimization_data());
14141 Address code_start_address = instruction_start();
14142 for (int i = 0; i < deopt_data->DeoptCount(); i++) {
14143 if (deopt_data->Pc(i)->value() == -1) continue;
14144 Address address = code_start_address + deopt_data->Pc(i)->value();
14145 if (address == pc && deopt_data->AstId(i) != BailoutId::None()) {
14146 return true;
14147 }
14148 }
14149 return false;
14150 }
14151
14152
14153 // Identify kind of code.
Kind2String(Kind kind)14154 const char* Code::Kind2String(Kind kind) {
14155 switch (kind) {
14156 #define CASE(name) case name: return #name;
14157 CODE_KIND_LIST(CASE)
14158 #undef CASE
14159 case NUMBER_OF_KINDS: break;
14160 }
14161 UNREACHABLE();
14162 return NULL;
14163 }
14164
14165 // Identify kind of code.
Kind2String(Kind kind)14166 const char* AbstractCode::Kind2String(Kind kind) {
14167 if (kind < AbstractCode::INTERPRETED_FUNCTION)
14168 return Code::Kind2String((Code::Kind)kind);
14169 if (kind == AbstractCode::INTERPRETED_FUNCTION) return "INTERPRETED_FUNCTION";
14170 UNREACHABLE();
14171 return NULL;
14172 }
14173
WeakCellFor(Handle<Code> code)14174 Handle<WeakCell> Code::WeakCellFor(Handle<Code> code) {
14175 DCHECK(code->kind() == OPTIMIZED_FUNCTION);
14176 WeakCell* raw_cell = code->CachedWeakCell();
14177 if (raw_cell != NULL) return Handle<WeakCell>(raw_cell);
14178 Handle<WeakCell> cell = code->GetIsolate()->factory()->NewWeakCell(code);
14179 DeoptimizationInputData::cast(code->deoptimization_data())
14180 ->SetWeakCellCache(*cell);
14181 return cell;
14182 }
14183
14184
CachedWeakCell()14185 WeakCell* Code::CachedWeakCell() {
14186 DCHECK(kind() == OPTIMIZED_FUNCTION);
14187 Object* weak_cell_cache =
14188 DeoptimizationInputData::cast(deoptimization_data())->WeakCellCache();
14189 if (weak_cell_cache->IsWeakCell()) {
14190 DCHECK(this == WeakCell::cast(weak_cell_cache)->value());
14191 return WeakCell::cast(weak_cell_cache);
14192 }
14193 return NULL;
14194 }
14195
14196 #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
14197
ICState2String(InlineCacheState state)14198 const char* Code::ICState2String(InlineCacheState state) {
14199 switch (state) {
14200 case UNINITIALIZED:
14201 return "UNINITIALIZED";
14202 case PREMONOMORPHIC:
14203 return "PREMONOMORPHIC";
14204 case MONOMORPHIC:
14205 return "MONOMORPHIC";
14206 case RECOMPUTE_HANDLER:
14207 return "RECOMPUTE_HANDLER";
14208 case POLYMORPHIC:
14209 return "POLYMORPHIC";
14210 case MEGAMORPHIC:
14211 return "MEGAMORPHIC";
14212 case GENERIC:
14213 return "GENERIC";
14214 }
14215 UNREACHABLE();
14216 return NULL;
14217 }
14218
PrintExtraICState(std::ostream & os,Kind kind,ExtraICState extra)14219 void Code::PrintExtraICState(std::ostream& os, // NOLINT
14220 Kind kind, ExtraICState extra) {
14221 os << "extra_ic_state = ";
14222 if ((kind == STORE_IC || kind == KEYED_STORE_IC) &&
14223 is_strict(static_cast<LanguageMode>(extra))) {
14224 os << "STRICT\n";
14225 } else {
14226 os << extra << "\n";
14227 }
14228 }
14229
14230 #endif // defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
14231
14232 #ifdef ENABLE_DISASSEMBLER
14233
DeoptimizationInputDataPrint(std::ostream & os)14234 void DeoptimizationInputData::DeoptimizationInputDataPrint(
14235 std::ostream& os) { // NOLINT
14236 disasm::NameConverter converter;
14237 int const inlined_function_count = InlinedFunctionCount()->value();
14238 os << "Inlined functions (count = " << inlined_function_count << ")\n";
14239 for (int id = 0; id < inlined_function_count; ++id) {
14240 Object* info = LiteralArray()->get(id);
14241 os << " " << Brief(SharedFunctionInfo::cast(info)) << "\n";
14242 }
14243 os << "\n";
14244 int deopt_count = DeoptCount();
14245 os << "Deoptimization Input Data (deopt points = " << deopt_count << ")\n";
14246 if (0 != deopt_count) {
14247 os << " index ast id argc pc";
14248 if (FLAG_print_code_verbose) os << " commands";
14249 os << "\n";
14250 }
14251 for (int i = 0; i < deopt_count; i++) {
14252 os << std::setw(6) << i << " " << std::setw(6) << AstId(i).ToInt() << " "
14253 << std::setw(6) << ArgumentsStackHeight(i)->value() << " "
14254 << std::setw(6) << Pc(i)->value();
14255
14256 if (!FLAG_print_code_verbose) {
14257 os << "\n";
14258 continue;
14259 }
14260 // Print details of the frame translation.
14261 int translation_index = TranslationIndex(i)->value();
14262 TranslationIterator iterator(TranslationByteArray(), translation_index);
14263 Translation::Opcode opcode =
14264 static_cast<Translation::Opcode>(iterator.Next());
14265 DCHECK(Translation::BEGIN == opcode);
14266 int frame_count = iterator.Next();
14267 int jsframe_count = iterator.Next();
14268 os << " " << Translation::StringFor(opcode)
14269 << " {frame count=" << frame_count
14270 << ", js frame count=" << jsframe_count << "}\n";
14271
14272 while (iterator.HasNext() &&
14273 Translation::BEGIN !=
14274 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
14275 os << std::setw(31) << " " << Translation::StringFor(opcode) << " ";
14276
14277 switch (opcode) {
14278 case Translation::BEGIN:
14279 UNREACHABLE();
14280 break;
14281
14282 case Translation::JS_FRAME: {
14283 int ast_id = iterator.Next();
14284 int shared_info_id = iterator.Next();
14285 unsigned height = iterator.Next();
14286 Object* shared_info = LiteralArray()->get(shared_info_id);
14287 os << "{ast_id=" << ast_id << ", function="
14288 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14289 << ", height=" << height << "}";
14290 break;
14291 }
14292
14293 case Translation::INTERPRETED_FRAME: {
14294 int bytecode_offset = iterator.Next();
14295 int shared_info_id = iterator.Next();
14296 unsigned height = iterator.Next();
14297 Object* shared_info = LiteralArray()->get(shared_info_id);
14298 os << "{bytecode_offset=" << bytecode_offset << ", function="
14299 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14300 << ", height=" << height << "}";
14301 break;
14302 }
14303
14304 case Translation::CONSTRUCT_STUB_FRAME: {
14305 int bailout_id = iterator.Next();
14306 int shared_info_id = iterator.Next();
14307 Object* shared_info = LiteralArray()->get(shared_info_id);
14308 unsigned height = iterator.Next();
14309 os << "{bailout_id=" << bailout_id << ", function="
14310 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14311 << ", height=" << height << "}";
14312 break;
14313 }
14314
14315 case Translation::COMPILED_STUB_FRAME: {
14316 Code::Kind stub_kind = static_cast<Code::Kind>(iterator.Next());
14317 os << "{kind=" << stub_kind << "}";
14318 break;
14319 }
14320
14321 case Translation::ARGUMENTS_ADAPTOR_FRAME: {
14322 int shared_info_id = iterator.Next();
14323 Object* shared_info = LiteralArray()->get(shared_info_id);
14324 unsigned height = iterator.Next();
14325 os << "{function="
14326 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14327 << ", height=" << height << "}";
14328 break;
14329 }
14330
14331 case Translation::TAIL_CALLER_FRAME: {
14332 int shared_info_id = iterator.Next();
14333 Object* shared_info = LiteralArray()->get(shared_info_id);
14334 os << "{function="
14335 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
14336 << "}";
14337 break;
14338 }
14339
14340 case Translation::GETTER_STUB_FRAME:
14341 case Translation::SETTER_STUB_FRAME: {
14342 int shared_info_id = iterator.Next();
14343 Object* shared_info = LiteralArray()->get(shared_info_id);
14344 os << "{function=" << Brief(SharedFunctionInfo::cast(shared_info)
14345 ->DebugName()) << "}";
14346 break;
14347 }
14348
14349 case Translation::REGISTER: {
14350 int reg_code = iterator.Next();
14351 os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
14352 break;
14353 }
14354
14355 case Translation::INT32_REGISTER: {
14356 int reg_code = iterator.Next();
14357 os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
14358 break;
14359 }
14360
14361 case Translation::UINT32_REGISTER: {
14362 int reg_code = iterator.Next();
14363 os << "{input=" << converter.NameOfCPURegister(reg_code)
14364 << " (unsigned)}";
14365 break;
14366 }
14367
14368 case Translation::BOOL_REGISTER: {
14369 int reg_code = iterator.Next();
14370 os << "{input=" << converter.NameOfCPURegister(reg_code)
14371 << " (bool)}";
14372 break;
14373 }
14374
14375 case Translation::FLOAT_REGISTER: {
14376 int reg_code = iterator.Next();
14377 os << "{input="
14378 << RegisterConfiguration::Crankshaft()->GetFloatRegisterName(
14379 reg_code)
14380 << "}";
14381 break;
14382 }
14383
14384 case Translation::DOUBLE_REGISTER: {
14385 int reg_code = iterator.Next();
14386 os << "{input="
14387 << RegisterConfiguration::Crankshaft()->GetDoubleRegisterName(
14388 reg_code)
14389 << "}";
14390 break;
14391 }
14392
14393 case Translation::STACK_SLOT: {
14394 int input_slot_index = iterator.Next();
14395 os << "{input=" << input_slot_index << "}";
14396 break;
14397 }
14398
14399 case Translation::INT32_STACK_SLOT: {
14400 int input_slot_index = iterator.Next();
14401 os << "{input=" << input_slot_index << "}";
14402 break;
14403 }
14404
14405 case Translation::UINT32_STACK_SLOT: {
14406 int input_slot_index = iterator.Next();
14407 os << "{input=" << input_slot_index << " (unsigned)}";
14408 break;
14409 }
14410
14411 case Translation::BOOL_STACK_SLOT: {
14412 int input_slot_index = iterator.Next();
14413 os << "{input=" << input_slot_index << " (bool)}";
14414 break;
14415 }
14416
14417 case Translation::FLOAT_STACK_SLOT:
14418 case Translation::DOUBLE_STACK_SLOT: {
14419 int input_slot_index = iterator.Next();
14420 os << "{input=" << input_slot_index << "}";
14421 break;
14422 }
14423
14424 case Translation::LITERAL: {
14425 int literal_index = iterator.Next();
14426 Object* literal_value = LiteralArray()->get(literal_index);
14427 os << "{literal_id=" << literal_index << " (" << Brief(literal_value)
14428 << ")}";
14429 break;
14430 }
14431
14432 case Translation::DUPLICATED_OBJECT: {
14433 int object_index = iterator.Next();
14434 os << "{object_index=" << object_index << "}";
14435 break;
14436 }
14437
14438 case Translation::ARGUMENTS_OBJECT:
14439 case Translation::CAPTURED_OBJECT: {
14440 int args_length = iterator.Next();
14441 os << "{length=" << args_length << "}";
14442 break;
14443 }
14444 }
14445 os << "\n";
14446 }
14447 }
14448 }
14449
14450
DeoptimizationOutputDataPrint(std::ostream & os)14451 void DeoptimizationOutputData::DeoptimizationOutputDataPrint(
14452 std::ostream& os) { // NOLINT
14453 os << "Deoptimization Output Data (deopt points = " << this->DeoptPoints()
14454 << ")\n";
14455 if (this->DeoptPoints() == 0) return;
14456
14457 os << "ast id pc state\n";
14458 for (int i = 0; i < this->DeoptPoints(); i++) {
14459 int pc_and_state = this->PcAndState(i)->value();
14460 os << std::setw(6) << this->AstId(i).ToInt() << " " << std::setw(8)
14461 << FullCodeGenerator::PcField::decode(pc_and_state) << " "
14462 << Deoptimizer::BailoutStateToString(
14463 FullCodeGenerator::BailoutStateField::decode(pc_and_state))
14464 << "\n";
14465 }
14466 }
14467
14468
HandlerTableRangePrint(std::ostream & os)14469 void HandlerTable::HandlerTableRangePrint(std::ostream& os) {
14470 os << " from to hdlr\n";
14471 for (int i = 0; i < length(); i += kRangeEntrySize) {
14472 int pc_start = Smi::cast(get(i + kRangeStartIndex))->value();
14473 int pc_end = Smi::cast(get(i + kRangeEndIndex))->value();
14474 int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value();
14475 int handler_offset = HandlerOffsetField::decode(handler_field);
14476 CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
14477 int data = Smi::cast(get(i + kRangeDataIndex))->value();
14478 os << " (" << std::setw(4) << pc_start << "," << std::setw(4) << pc_end
14479 << ") -> " << std::setw(4) << handler_offset
14480 << " (prediction=" << prediction << ", data=" << data << ")\n";
14481 }
14482 }
14483
14484
HandlerTableReturnPrint(std::ostream & os)14485 void HandlerTable::HandlerTableReturnPrint(std::ostream& os) {
14486 os << " off hdlr (c)\n";
14487 for (int i = 0; i < length(); i += kReturnEntrySize) {
14488 int pc_offset = Smi::cast(get(i + kReturnOffsetIndex))->value();
14489 int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value();
14490 int handler_offset = HandlerOffsetField::decode(handler_field);
14491 CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
14492 os << " " << std::setw(4) << pc_offset << " -> " << std::setw(4)
14493 << handler_offset << " (prediction=" << prediction << ")\n";
14494 }
14495 }
14496
14497
Disassemble(const char * name,std::ostream & os)14498 void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT
14499 os << "kind = " << Kind2String(kind()) << "\n";
14500 if (IsCodeStubOrIC()) {
14501 const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this));
14502 os << "major_key = " << (n == NULL ? "null" : n) << "\n";
14503 }
14504 if (is_inline_cache_stub()) {
14505 if (!IC::ICUseVector(kind())) {
14506 InlineCacheState ic_state = IC::StateFromCode(this);
14507 os << "ic_state = " << ICState2String(ic_state) << "\n";
14508 PrintExtraICState(os, kind(), extra_ic_state());
14509 }
14510 if (is_compare_ic_stub()) {
14511 DCHECK(CodeStub::GetMajorKey(this) == CodeStub::CompareIC);
14512 CompareICStub stub(stub_key(), GetIsolate());
14513 os << "compare_state = " << CompareICState::GetStateName(stub.left())
14514 << "*" << CompareICState::GetStateName(stub.right()) << " -> "
14515 << CompareICState::GetStateName(stub.state()) << "\n";
14516 os << "compare_operation = " << Token::Name(stub.op()) << "\n";
14517 }
14518 }
14519 if ((name != nullptr) && (name[0] != '\0')) {
14520 os << "name = " << name << "\n";
14521 } else if (kind() == BUILTIN) {
14522 name = GetIsolate()->builtins()->Lookup(instruction_start());
14523 if (name != nullptr) {
14524 os << "name = " << name << "\n";
14525 }
14526 } else if (kind() == BYTECODE_HANDLER) {
14527 name = GetIsolate()->interpreter()->LookupNameOfBytecodeHandler(this);
14528 if (name != nullptr) {
14529 os << "name = " << name << "\n";
14530 }
14531 }
14532 if (kind() == OPTIMIZED_FUNCTION) {
14533 os << "stack_slots = " << stack_slots() << "\n";
14534 }
14535 os << "compiler = " << (is_turbofanned()
14536 ? "turbofan"
14537 : is_crankshafted() ? "crankshaft"
14538 : kind() == Code::FUNCTION
14539 ? "full-codegen"
14540 : "unknown") << "\n";
14541
14542 os << "Instructions (size = " << instruction_size() << ")\n";
14543 {
14544 Isolate* isolate = GetIsolate();
14545 int size = instruction_size();
14546 int safepoint_offset =
14547 is_crankshafted() ? static_cast<int>(safepoint_table_offset()) : size;
14548 int back_edge_offset = (kind() == Code::FUNCTION)
14549 ? static_cast<int>(back_edge_table_offset())
14550 : size;
14551 int constant_pool_offset = FLAG_enable_embedded_constant_pool
14552 ? this->constant_pool_offset()
14553 : size;
14554
14555 // Stop before reaching any embedded tables
14556 int code_size = Min(safepoint_offset, back_edge_offset);
14557 code_size = Min(code_size, constant_pool_offset);
14558 byte* begin = instruction_start();
14559 byte* end = begin + code_size;
14560 Disassembler::Decode(isolate, &os, begin, end, this);
14561
14562 if (constant_pool_offset < size) {
14563 int constant_pool_size = size - constant_pool_offset;
14564 DCHECK((constant_pool_size & kPointerAlignmentMask) == 0);
14565 os << "\nConstant Pool (size = " << constant_pool_size << ")\n";
14566 Vector<char> buf = Vector<char>::New(50);
14567 intptr_t* ptr = reinterpret_cast<intptr_t*>(begin + constant_pool_offset);
14568 for (int i = 0; i < constant_pool_size; i += kPointerSize, ptr++) {
14569 SNPrintF(buf, "%4d %08" V8PRIxPTR, i, *ptr);
14570 os << static_cast<const void*>(ptr) << " " << buf.start() << "\n";
14571 }
14572 }
14573 }
14574 os << "\n";
14575
14576 SourcePositionTableIterator it(source_position_table());
14577 if (!it.done()) {
14578 os << "Source positions:\n pc offset position\n";
14579 for (; !it.done(); it.Advance()) {
14580 os << std::setw(10) << it.code_offset() << std::setw(10)
14581 << it.source_position().ScriptOffset()
14582 << (it.is_statement() ? " statement" : "") << "\n";
14583 }
14584 os << "\n";
14585 }
14586
14587 if (kind() == FUNCTION) {
14588 DeoptimizationOutputData* data =
14589 DeoptimizationOutputData::cast(this->deoptimization_data());
14590 data->DeoptimizationOutputDataPrint(os);
14591 } else if (kind() == OPTIMIZED_FUNCTION) {
14592 DeoptimizationInputData* data =
14593 DeoptimizationInputData::cast(this->deoptimization_data());
14594 data->DeoptimizationInputDataPrint(os);
14595 }
14596 os << "\n";
14597
14598 if (is_crankshafted()) {
14599 SafepointTable table(this);
14600 os << "Safepoints (size = " << table.size() << ")\n";
14601 for (unsigned i = 0; i < table.length(); i++) {
14602 unsigned pc_offset = table.GetPcOffset(i);
14603 os << static_cast<const void*>(instruction_start() + pc_offset) << " ";
14604 os << std::setw(4) << pc_offset << " ";
14605 table.PrintEntry(i, os);
14606 os << " (sp -> fp) ";
14607 SafepointEntry entry = table.GetEntry(i);
14608 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
14609 os << std::setw(6) << entry.deoptimization_index();
14610 } else {
14611 os << "<none>";
14612 }
14613 if (entry.argument_count() > 0) {
14614 os << " argc: " << entry.argument_count();
14615 }
14616 os << "\n";
14617 }
14618 os << "\n";
14619 } else if (kind() == FUNCTION) {
14620 unsigned offset = back_edge_table_offset();
14621 // If there is no back edge table, the "table start" will be at or after
14622 // (due to alignment) the end of the instruction stream.
14623 if (static_cast<int>(offset) < instruction_size()) {
14624 DisallowHeapAllocation no_gc;
14625 BackEdgeTable back_edges(this, &no_gc);
14626
14627 os << "Back edges (size = " << back_edges.length() << ")\n";
14628 os << "ast_id pc_offset loop_depth\n";
14629
14630 for (uint32_t i = 0; i < back_edges.length(); i++) {
14631 os << std::setw(6) << back_edges.ast_id(i).ToInt() << " "
14632 << std::setw(9) << back_edges.pc_offset(i) << " " << std::setw(10)
14633 << back_edges.loop_depth(i) << "\n";
14634 }
14635
14636 os << "\n";
14637 }
14638 #ifdef OBJECT_PRINT
14639 if (!type_feedback_info()->IsUndefined(GetIsolate())) {
14640 TypeFeedbackInfo::cast(type_feedback_info())->TypeFeedbackInfoPrint(os);
14641 os << "\n";
14642 }
14643 #endif
14644 }
14645
14646 if (handler_table()->length() > 0) {
14647 os << "Handler Table (size = " << handler_table()->Size() << ")\n";
14648 if (kind() == FUNCTION) {
14649 HandlerTable::cast(handler_table())->HandlerTableRangePrint(os);
14650 } else if (kind() == OPTIMIZED_FUNCTION) {
14651 HandlerTable::cast(handler_table())->HandlerTableReturnPrint(os);
14652 }
14653 os << "\n";
14654 }
14655
14656 os << "RelocInfo (size = " << relocation_size() << ")\n";
14657 for (RelocIterator it(this); !it.done(); it.next()) {
14658 it.rinfo()->Print(GetIsolate(), os);
14659 }
14660 os << "\n";
14661
14662 if (has_unwinding_info()) {
14663 os << "UnwindingInfo (size = " << unwinding_info_size() << ")\n";
14664 EhFrameDisassembler eh_frame_disassembler(unwinding_info_start(),
14665 unwinding_info_end());
14666 eh_frame_disassembler.DisassembleToStream(os);
14667 os << "\n";
14668 }
14669 }
14670 #endif // ENABLE_DISASSEMBLER
14671
14672
Disassemble(std::ostream & os)14673 void BytecodeArray::Disassemble(std::ostream& os) {
14674 os << "Parameter count " << parameter_count() << "\n";
14675 os << "Frame size " << frame_size() << "\n";
14676
14677 const uint8_t* base_address = GetFirstBytecodeAddress();
14678 SourcePositionTableIterator source_positions(source_position_table());
14679
14680 interpreter::BytecodeArrayIterator iterator(handle(this));
14681 while (!iterator.done()) {
14682 if (!source_positions.done() &&
14683 iterator.current_offset() == source_positions.code_offset()) {
14684 os << std::setw(5) << source_positions.source_position().ScriptOffset();
14685 os << (source_positions.is_statement() ? " S> " : " E> ");
14686 source_positions.Advance();
14687 } else {
14688 os << " ";
14689 }
14690 const uint8_t* current_address = base_address + iterator.current_offset();
14691 os << reinterpret_cast<const void*>(current_address) << " @ "
14692 << std::setw(4) << iterator.current_offset() << " : ";
14693 interpreter::BytecodeDecoder::Decode(os, current_address,
14694 parameter_count());
14695 if (interpreter::Bytecodes::IsJump(iterator.current_bytecode())) {
14696 const void* jump_target = base_address + iterator.GetJumpTargetOffset();
14697 os << " (" << jump_target << " @ " << iterator.GetJumpTargetOffset()
14698 << ")";
14699 }
14700 os << std::endl;
14701 iterator.Advance();
14702 }
14703
14704 if (constant_pool()->length() > 0) {
14705 os << "Constant pool (size = " << constant_pool()->length() << ")\n";
14706 constant_pool()->Print();
14707 }
14708
14709 #ifdef ENABLE_DISASSEMBLER
14710 if (handler_table()->length() > 0) {
14711 os << "Handler Table (size = " << handler_table()->Size() << ")\n";
14712 HandlerTable::cast(handler_table())->HandlerTableRangePrint(os);
14713 }
14714 #endif
14715 }
14716
CopyBytecodesTo(BytecodeArray * to)14717 void BytecodeArray::CopyBytecodesTo(BytecodeArray* to) {
14718 BytecodeArray* from = this;
14719 DCHECK_EQ(from->length(), to->length());
14720 CopyBytes(to->GetFirstBytecodeAddress(), from->GetFirstBytecodeAddress(),
14721 from->length());
14722 }
14723
MakeOlder()14724 void BytecodeArray::MakeOlder() {
14725 Age age = bytecode_age();
14726 if (age < kLastBytecodeAge) {
14727 set_bytecode_age(static_cast<Age>(age + 1));
14728 }
14729 DCHECK_GE(bytecode_age(), kFirstBytecodeAge);
14730 DCHECK_LE(bytecode_age(), kLastBytecodeAge);
14731 }
14732
IsOld() const14733 bool BytecodeArray::IsOld() const {
14734 return bytecode_age() >= kIsOldBytecodeAge;
14735 }
14736
14737 // static
Initialize(Handle<JSArray> array,int capacity,int length)14738 void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
14739 DCHECK(capacity >= 0);
14740 array->GetIsolate()->factory()->NewJSArrayStorage(
14741 array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
14742 }
14743
SetLength(Handle<JSArray> array,uint32_t new_length)14744 void JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) {
14745 // We should never end in here with a pixel or external array.
14746 DCHECK(array->AllowsSetLength());
14747 if (array->SetLengthWouldNormalize(new_length)) {
14748 JSObject::NormalizeElements(array);
14749 }
14750 array->GetElementsAccessor()->SetLength(array, new_length);
14751 }
14752
14753
14754 // static
AddDependentCode(Handle<Map> map,DependentCode::DependencyGroup group,Handle<Code> code)14755 void Map::AddDependentCode(Handle<Map> map,
14756 DependentCode::DependencyGroup group,
14757 Handle<Code> code) {
14758 Handle<WeakCell> cell = Code::WeakCellFor(code);
14759 Handle<DependentCode> codes = DependentCode::InsertWeakCode(
14760 Handle<DependentCode>(map->dependent_code()), group, cell);
14761 if (*codes != map->dependent_code()) map->set_dependent_code(*codes);
14762 }
14763
14764
InsertCompilationDependencies(Handle<DependentCode> entries,DependencyGroup group,Handle<Foreign> info)14765 Handle<DependentCode> DependentCode::InsertCompilationDependencies(
14766 Handle<DependentCode> entries, DependencyGroup group,
14767 Handle<Foreign> info) {
14768 return Insert(entries, group, info);
14769 }
14770
14771
InsertWeakCode(Handle<DependentCode> entries,DependencyGroup group,Handle<WeakCell> code_cell)14772 Handle<DependentCode> DependentCode::InsertWeakCode(
14773 Handle<DependentCode> entries, DependencyGroup group,
14774 Handle<WeakCell> code_cell) {
14775 return Insert(entries, group, code_cell);
14776 }
14777
14778
Insert(Handle<DependentCode> entries,DependencyGroup group,Handle<Object> object)14779 Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
14780 DependencyGroup group,
14781 Handle<Object> object) {
14782 if (entries->length() == 0 || entries->group() > group) {
14783 // There is no such group.
14784 return DependentCode::New(group, object, entries);
14785 }
14786 if (entries->group() < group) {
14787 // The group comes later in the list.
14788 Handle<DependentCode> old_next(entries->next_link());
14789 Handle<DependentCode> new_next = Insert(old_next, group, object);
14790 if (!old_next.is_identical_to(new_next)) {
14791 entries->set_next_link(*new_next);
14792 }
14793 return entries;
14794 }
14795 DCHECK_EQ(group, entries->group());
14796 int count = entries->count();
14797 // Check for existing entry to avoid duplicates.
14798 for (int i = 0; i < count; i++) {
14799 if (entries->object_at(i) == *object) return entries;
14800 }
14801 if (entries->length() < kCodesStartIndex + count + 1) {
14802 entries = EnsureSpace(entries);
14803 // Count could have changed, reload it.
14804 count = entries->count();
14805 }
14806 entries->set_object_at(count, *object);
14807 entries->set_count(count + 1);
14808 return entries;
14809 }
14810
14811
New(DependencyGroup group,Handle<Object> object,Handle<DependentCode> next)14812 Handle<DependentCode> DependentCode::New(DependencyGroup group,
14813 Handle<Object> object,
14814 Handle<DependentCode> next) {
14815 Isolate* isolate = next->GetIsolate();
14816 Handle<DependentCode> result = Handle<DependentCode>::cast(
14817 isolate->factory()->NewFixedArray(kCodesStartIndex + 1, TENURED));
14818 result->set_next_link(*next);
14819 result->set_flags(GroupField::encode(group) | CountField::encode(1));
14820 result->set_object_at(0, *object);
14821 return result;
14822 }
14823
14824
EnsureSpace(Handle<DependentCode> entries)14825 Handle<DependentCode> DependentCode::EnsureSpace(
14826 Handle<DependentCode> entries) {
14827 if (entries->Compact()) return entries;
14828 Isolate* isolate = entries->GetIsolate();
14829 int capacity = kCodesStartIndex + DependentCode::Grow(entries->count());
14830 int grow_by = capacity - entries->length();
14831 return Handle<DependentCode>::cast(
14832 isolate->factory()->CopyFixedArrayAndGrow(entries, grow_by, TENURED));
14833 }
14834
14835
Compact()14836 bool DependentCode::Compact() {
14837 int old_count = count();
14838 int new_count = 0;
14839 for (int i = 0; i < old_count; i++) {
14840 Object* obj = object_at(i);
14841 if (!obj->IsWeakCell() || !WeakCell::cast(obj)->cleared()) {
14842 if (i != new_count) {
14843 copy(i, new_count);
14844 }
14845 new_count++;
14846 }
14847 }
14848 set_count(new_count);
14849 for (int i = new_count; i < old_count; i++) {
14850 clear_at(i);
14851 }
14852 return new_count < old_count;
14853 }
14854
14855
UpdateToFinishedCode(DependencyGroup group,Foreign * info,WeakCell * code_cell)14856 void DependentCode::UpdateToFinishedCode(DependencyGroup group, Foreign* info,
14857 WeakCell* code_cell) {
14858 if (this->length() == 0 || this->group() > group) {
14859 // There is no such group.
14860 return;
14861 }
14862 if (this->group() < group) {
14863 // The group comes later in the list.
14864 next_link()->UpdateToFinishedCode(group, info, code_cell);
14865 return;
14866 }
14867 DCHECK_EQ(group, this->group());
14868 DisallowHeapAllocation no_gc;
14869 int count = this->count();
14870 for (int i = 0; i < count; i++) {
14871 if (object_at(i) == info) {
14872 set_object_at(i, code_cell);
14873 break;
14874 }
14875 }
14876 #ifdef DEBUG
14877 for (int i = 0; i < count; i++) {
14878 DCHECK(object_at(i) != info);
14879 }
14880 #endif
14881 }
14882
14883
RemoveCompilationDependencies(DependentCode::DependencyGroup group,Foreign * info)14884 void DependentCode::RemoveCompilationDependencies(
14885 DependentCode::DependencyGroup group, Foreign* info) {
14886 if (this->length() == 0 || this->group() > group) {
14887 // There is no such group.
14888 return;
14889 }
14890 if (this->group() < group) {
14891 // The group comes later in the list.
14892 next_link()->RemoveCompilationDependencies(group, info);
14893 return;
14894 }
14895 DCHECK_EQ(group, this->group());
14896 DisallowHeapAllocation no_allocation;
14897 int old_count = count();
14898 // Find compilation info wrapper.
14899 int info_pos = -1;
14900 for (int i = 0; i < old_count; i++) {
14901 if (object_at(i) == info) {
14902 info_pos = i;
14903 break;
14904 }
14905 }
14906 if (info_pos == -1) return; // Not found.
14907 // Use the last code to fill the gap.
14908 if (info_pos < old_count - 1) {
14909 copy(old_count - 1, info_pos);
14910 }
14911 clear_at(old_count - 1);
14912 set_count(old_count - 1);
14913
14914 #ifdef DEBUG
14915 for (int i = 0; i < old_count - 1; i++) {
14916 DCHECK(object_at(i) != info);
14917 }
14918 #endif
14919 }
14920
14921
Contains(DependencyGroup group,WeakCell * code_cell)14922 bool DependentCode::Contains(DependencyGroup group, WeakCell* code_cell) {
14923 if (this->length() == 0 || this->group() > group) {
14924 // There is no such group.
14925 return false;
14926 }
14927 if (this->group() < group) {
14928 // The group comes later in the list.
14929 return next_link()->Contains(group, code_cell);
14930 }
14931 DCHECK_EQ(group, this->group());
14932 int count = this->count();
14933 for (int i = 0; i < count; i++) {
14934 if (object_at(i) == code_cell) return true;
14935 }
14936 return false;
14937 }
14938
14939
IsEmpty(DependencyGroup group)14940 bool DependentCode::IsEmpty(DependencyGroup group) {
14941 if (this->length() == 0 || this->group() > group) {
14942 // There is no such group.
14943 return true;
14944 }
14945 if (this->group() < group) {
14946 // The group comes later in the list.
14947 return next_link()->IsEmpty(group);
14948 }
14949 DCHECK_EQ(group, this->group());
14950 return count() == 0;
14951 }
14952
14953
MarkCodeForDeoptimization(Isolate * isolate,DependentCode::DependencyGroup group)14954 bool DependentCode::MarkCodeForDeoptimization(
14955 Isolate* isolate,
14956 DependentCode::DependencyGroup group) {
14957 if (this->length() == 0 || this->group() > group) {
14958 // There is no such group.
14959 return false;
14960 }
14961 if (this->group() < group) {
14962 // The group comes later in the list.
14963 return next_link()->MarkCodeForDeoptimization(isolate, group);
14964 }
14965 DCHECK_EQ(group, this->group());
14966 DisallowHeapAllocation no_allocation_scope;
14967 // Mark all the code that needs to be deoptimized.
14968 bool marked = false;
14969 bool invalidate_embedded_objects = group == kWeakCodeGroup;
14970 int count = this->count();
14971 for (int i = 0; i < count; i++) {
14972 Object* obj = object_at(i);
14973 if (obj->IsWeakCell()) {
14974 WeakCell* cell = WeakCell::cast(obj);
14975 if (cell->cleared()) continue;
14976 Code* code = Code::cast(cell->value());
14977 if (!code->marked_for_deoptimization()) {
14978 SetMarkedForDeoptimization(code, group);
14979 if (invalidate_embedded_objects) {
14980 code->InvalidateEmbeddedObjects();
14981 }
14982 marked = true;
14983 }
14984 } else {
14985 DCHECK(obj->IsForeign());
14986 CompilationDependencies* info =
14987 reinterpret_cast<CompilationDependencies*>(
14988 Foreign::cast(obj)->foreign_address());
14989 info->Abort();
14990 }
14991 }
14992 for (int i = 0; i < count; i++) {
14993 clear_at(i);
14994 }
14995 set_count(0);
14996 return marked;
14997 }
14998
14999
DeoptimizeDependentCodeGroup(Isolate * isolate,DependentCode::DependencyGroup group)15000 void DependentCode::DeoptimizeDependentCodeGroup(
15001 Isolate* isolate,
15002 DependentCode::DependencyGroup group) {
15003 DCHECK(AllowCodeDependencyChange::IsAllowed());
15004 DisallowHeapAllocation no_allocation_scope;
15005 bool marked = MarkCodeForDeoptimization(isolate, group);
15006 if (marked) Deoptimizer::DeoptimizeMarkedCode(isolate);
15007 }
15008
15009
SetMarkedForDeoptimization(Code * code,DependencyGroup group)15010 void DependentCode::SetMarkedForDeoptimization(Code* code,
15011 DependencyGroup group) {
15012 code->set_marked_for_deoptimization(true);
15013 if (FLAG_trace_deopt &&
15014 (code->deoptimization_data() != code->GetHeap()->empty_fixed_array())) {
15015 DeoptimizationInputData* deopt_data =
15016 DeoptimizationInputData::cast(code->deoptimization_data());
15017 CodeTracer::Scope scope(code->GetHeap()->isolate()->GetCodeTracer());
15018 PrintF(scope.file(), "[marking dependent code 0x%08" V8PRIxPTR
15019 " (opt #%d) for deoptimization, reason: %s]\n",
15020 reinterpret_cast<intptr_t>(code),
15021 deopt_data->OptimizationId()->value(), DependencyGroupName(group));
15022 }
15023 }
15024
15025
DependencyGroupName(DependencyGroup group)15026 const char* DependentCode::DependencyGroupName(DependencyGroup group) {
15027 switch (group) {
15028 case kWeakCodeGroup:
15029 return "weak-code";
15030 case kTransitionGroup:
15031 return "transition";
15032 case kPrototypeCheckGroup:
15033 return "prototype-check";
15034 case kPropertyCellChangedGroup:
15035 return "property-cell-changed";
15036 case kFieldOwnerGroup:
15037 return "field-owner";
15038 case kInitialMapChangedGroup:
15039 return "initial-map-changed";
15040 case kAllocationSiteTenuringChangedGroup:
15041 return "allocation-site-tenuring-changed";
15042 case kAllocationSiteTransitionChangedGroup:
15043 return "allocation-site-transition-changed";
15044 }
15045 UNREACHABLE();
15046 return "?";
15047 }
15048
15049
TransitionToPrototype(Handle<Map> map,Handle<Object> prototype,PrototypeOptimizationMode mode)15050 Handle<Map> Map::TransitionToPrototype(Handle<Map> map,
15051 Handle<Object> prototype,
15052 PrototypeOptimizationMode mode) {
15053 Handle<Map> new_map = TransitionArray::GetPrototypeTransition(map, prototype);
15054 if (new_map.is_null()) {
15055 new_map = Copy(map, "TransitionToPrototype");
15056 TransitionArray::PutPrototypeTransition(map, prototype, new_map);
15057 Map::SetPrototype(new_map, prototype, mode);
15058 }
15059 return new_map;
15060 }
15061
15062
SetPrototype(Handle<JSReceiver> object,Handle<Object> value,bool from_javascript,ShouldThrow should_throw)15063 Maybe<bool> JSReceiver::SetPrototype(Handle<JSReceiver> object,
15064 Handle<Object> value, bool from_javascript,
15065 ShouldThrow should_throw) {
15066 if (object->IsJSProxy()) {
15067 return JSProxy::SetPrototype(Handle<JSProxy>::cast(object), value,
15068 from_javascript, should_throw);
15069 }
15070 return JSObject::SetPrototype(Handle<JSObject>::cast(object), value,
15071 from_javascript, should_throw);
15072 }
15073
15074
15075 // ES6: 9.5.2 [[SetPrototypeOf]] (V)
15076 // static
SetPrototype(Handle<JSProxy> proxy,Handle<Object> value,bool from_javascript,ShouldThrow should_throw)15077 Maybe<bool> JSProxy::SetPrototype(Handle<JSProxy> proxy, Handle<Object> value,
15078 bool from_javascript,
15079 ShouldThrow should_throw) {
15080 Isolate* isolate = proxy->GetIsolate();
15081 STACK_CHECK(isolate, Nothing<bool>());
15082 Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string();
15083 // 1. Assert: Either Type(V) is Object or Type(V) is Null.
15084 DCHECK(value->IsJSReceiver() || value->IsNull(isolate));
15085 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
15086 Handle<Object> handler(proxy->handler(), isolate);
15087 // 3. If handler is null, throw a TypeError exception.
15088 // 4. Assert: Type(handler) is Object.
15089 if (proxy->IsRevoked()) {
15090 isolate->Throw(*isolate->factory()->NewTypeError(
15091 MessageTemplate::kProxyRevoked, trap_name));
15092 return Nothing<bool>();
15093 }
15094 // 5. Let target be the value of the [[ProxyTarget]] internal slot.
15095 Handle<JSReceiver> target(proxy->target(), isolate);
15096 // 6. Let trap be ? GetMethod(handler, "getPrototypeOf").
15097 Handle<Object> trap;
15098 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15099 isolate, trap,
15100 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
15101 Nothing<bool>());
15102 // 7. If trap is undefined, then return target.[[SetPrototypeOf]]().
15103 if (trap->IsUndefined(isolate)) {
15104 return JSReceiver::SetPrototype(target, value, from_javascript,
15105 should_throw);
15106 }
15107 // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, V»)).
15108 Handle<Object> argv[] = {target, value};
15109 Handle<Object> trap_result;
15110 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
15111 isolate, trap_result,
15112 Execution::Call(isolate, trap, handler, arraysize(argv), argv),
15113 Nothing<bool>());
15114 bool bool_trap_result = trap_result->BooleanValue();
15115 // 9. If booleanTrapResult is false, return false.
15116 if (!bool_trap_result) {
15117 RETURN_FAILURE(
15118 isolate, should_throw,
15119 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15120 }
15121 // 10. Let extensibleTarget be ? IsExtensible(target).
15122 Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
15123 if (is_extensible.IsNothing()) return Nothing<bool>();
15124 // 11. If extensibleTarget is true, return true.
15125 if (is_extensible.FromJust()) {
15126 if (bool_trap_result) return Just(true);
15127 RETURN_FAILURE(
15128 isolate, should_throw,
15129 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
15130 }
15131 // 12. Let targetProto be ? target.[[GetPrototypeOf]]().
15132 Handle<Object> target_proto;
15133 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_proto,
15134 JSReceiver::GetPrototype(isolate, target),
15135 Nothing<bool>());
15136 // 13. If SameValue(V, targetProto) is false, throw a TypeError exception.
15137 if (bool_trap_result && !value->SameValue(*target_proto)) {
15138 isolate->Throw(*isolate->factory()->NewTypeError(
15139 MessageTemplate::kProxySetPrototypeOfNonExtensible));
15140 return Nothing<bool>();
15141 }
15142 // 14. Return true.
15143 return Just(true);
15144 }
15145
15146
SetPrototype(Handle<JSObject> object,Handle<Object> value,bool from_javascript,ShouldThrow should_throw)15147 Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object,
15148 Handle<Object> value, bool from_javascript,
15149 ShouldThrow should_throw) {
15150 Isolate* isolate = object->GetIsolate();
15151
15152 #ifdef DEBUG
15153 int size = object->Size();
15154 #endif
15155
15156 if (from_javascript) {
15157 if (object->IsAccessCheckNeeded() &&
15158 !isolate->MayAccess(handle(isolate->context()), object)) {
15159 isolate->ReportFailedAccessCheck(object);
15160 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
15161 RETURN_FAILURE(isolate, should_throw,
15162 NewTypeError(MessageTemplate::kNoAccess));
15163 }
15164 } else {
15165 DCHECK(!object->IsAccessCheckNeeded());
15166 }
15167
15168 Heap* heap = isolate->heap();
15169 // Silently ignore the change if value is not a JSObject or null.
15170 // SpiderMonkey behaves this way.
15171 if (!value->IsJSReceiver() && !value->IsNull(isolate)) return Just(true);
15172
15173 bool all_extensible = object->map()->is_extensible();
15174 Handle<JSObject> real_receiver = object;
15175 if (from_javascript) {
15176 // Find the first object in the chain whose prototype object is not
15177 // hidden.
15178 PrototypeIterator iter(isolate, real_receiver, kStartAtPrototype,
15179 PrototypeIterator::END_AT_NON_HIDDEN);
15180 while (!iter.IsAtEnd()) {
15181 // Casting to JSObject is fine because hidden prototypes are never
15182 // JSProxies.
15183 real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter);
15184 iter.Advance();
15185 all_extensible = all_extensible && real_receiver->map()->is_extensible();
15186 }
15187 }
15188 Handle<Map> map(real_receiver->map());
15189
15190 // Nothing to do if prototype is already set.
15191 if (map->prototype() == *value) return Just(true);
15192
15193 bool immutable_proto = map->is_immutable_proto();
15194 if (immutable_proto) {
15195 RETURN_FAILURE(
15196 isolate, should_throw,
15197 NewTypeError(MessageTemplate::kImmutablePrototypeSet, object));
15198 }
15199
15200 // From 8.6.2 Object Internal Methods
15201 // ...
15202 // In addition, if [[Extensible]] is false the value of the [[Class]] and
15203 // [[Prototype]] internal properties of the object may not be modified.
15204 // ...
15205 // Implementation specific extensions that modify [[Class]], [[Prototype]]
15206 // or [[Extensible]] must not violate the invariants defined in the preceding
15207 // paragraph.
15208 if (!all_extensible) {
15209 RETURN_FAILURE(isolate, should_throw,
15210 NewTypeError(MessageTemplate::kNonExtensibleProto, object));
15211 }
15212
15213 // Before we can set the prototype we need to be sure prototype cycles are
15214 // prevented. It is sufficient to validate that the receiver is not in the
15215 // new prototype chain.
15216 if (value->IsJSReceiver()) {
15217 for (PrototypeIterator iter(isolate, JSReceiver::cast(*value),
15218 kStartAtReceiver);
15219 !iter.IsAtEnd(); iter.Advance()) {
15220 if (iter.GetCurrent<JSReceiver>() == *object) {
15221 // Cycle detected.
15222 RETURN_FAILURE(isolate, should_throw,
15223 NewTypeError(MessageTemplate::kCyclicProto));
15224 }
15225 }
15226 }
15227
15228 // Set the new prototype of the object.
15229
15230 isolate->UpdateArrayProtectorOnSetPrototype(real_receiver);
15231
15232 PrototypeOptimizationMode mode =
15233 from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE;
15234 Handle<Map> new_map = Map::TransitionToPrototype(map, value, mode);
15235 DCHECK(new_map->prototype() == *value);
15236 JSObject::MigrateToMap(real_receiver, new_map);
15237
15238 heap->ClearInstanceofCache();
15239 DCHECK(size == object->Size());
15240 return Just(true);
15241 }
15242
15243 // static
SetImmutableProto(Handle<JSObject> object)15244 void JSObject::SetImmutableProto(Handle<JSObject> object) {
15245 DCHECK(!object->IsAccessCheckNeeded()); // Never called from JS
15246 Handle<Map> map(object->map());
15247
15248 // Nothing to do if prototype is already set.
15249 if (map->is_immutable_proto()) return;
15250
15251 Handle<Map> new_map = Map::TransitionToImmutableProto(map);
15252 object->set_map(*new_map);
15253 }
15254
EnsureCanContainElements(Handle<JSObject> object,Arguments * args,uint32_t first_arg,uint32_t arg_count,EnsureElementsMode mode)15255 void JSObject::EnsureCanContainElements(Handle<JSObject> object,
15256 Arguments* args,
15257 uint32_t first_arg,
15258 uint32_t arg_count,
15259 EnsureElementsMode mode) {
15260 // Elements in |Arguments| are ordered backwards (because they're on the
15261 // stack), but the method that's called here iterates over them in forward
15262 // direction.
15263 return EnsureCanContainElements(
15264 object, args->arguments() - first_arg - (arg_count - 1), arg_count, mode);
15265 }
15266
15267
GetElementsAccessor()15268 ElementsAccessor* JSObject::GetElementsAccessor() {
15269 return ElementsAccessor::ForKind(GetElementsKind());
15270 }
15271
15272
ValidateElements(Handle<JSObject> object)15273 void JSObject::ValidateElements(Handle<JSObject> object) {
15274 #ifdef ENABLE_SLOW_DCHECKS
15275 if (FLAG_enable_slow_asserts) {
15276 ElementsAccessor* accessor = object->GetElementsAccessor();
15277 accessor->Validate(object);
15278 }
15279 #endif
15280 }
15281
15282
ShouldConvertToSlowElements(JSObject * object,uint32_t capacity,uint32_t index,uint32_t * new_capacity)15283 static bool ShouldConvertToSlowElements(JSObject* object, uint32_t capacity,
15284 uint32_t index,
15285 uint32_t* new_capacity) {
15286 STATIC_ASSERT(JSObject::kMaxUncheckedOldFastElementsLength <=
15287 JSObject::kMaxUncheckedFastElementsLength);
15288 if (index < capacity) {
15289 *new_capacity = capacity;
15290 return false;
15291 }
15292 if (index - capacity >= JSObject::kMaxGap) return true;
15293 *new_capacity = JSObject::NewElementsCapacity(index + 1);
15294 DCHECK_LT(index, *new_capacity);
15295 if (*new_capacity <= JSObject::kMaxUncheckedOldFastElementsLength ||
15296 (*new_capacity <= JSObject::kMaxUncheckedFastElementsLength &&
15297 object->GetHeap()->InNewSpace(object))) {
15298 return false;
15299 }
15300 // If the fast-case backing storage takes up roughly three times as
15301 // much space (in machine words) as a dictionary backing storage
15302 // would, the object should have slow elements.
15303 int used_elements = object->GetFastElementsUsage();
15304 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
15305 SeededNumberDictionary::kEntrySize;
15306 return 3 * static_cast<uint32_t>(dictionary_size) <= *new_capacity;
15307 }
15308
15309
WouldConvertToSlowElements(uint32_t index)15310 bool JSObject::WouldConvertToSlowElements(uint32_t index) {
15311 if (HasFastElements()) {
15312 Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements()));
15313 uint32_t capacity = static_cast<uint32_t>(backing_store->length());
15314 uint32_t new_capacity;
15315 return ShouldConvertToSlowElements(this, capacity, index, &new_capacity);
15316 }
15317 return false;
15318 }
15319
15320
BestFittingFastElementsKind(JSObject * object)15321 static ElementsKind BestFittingFastElementsKind(JSObject* object) {
15322 if (object->HasSloppyArgumentsElements()) {
15323 return FAST_SLOPPY_ARGUMENTS_ELEMENTS;
15324 }
15325 if (object->HasStringWrapperElements()) {
15326 return FAST_STRING_WRAPPER_ELEMENTS;
15327 }
15328 DCHECK(object->HasDictionaryElements());
15329 SeededNumberDictionary* dictionary = object->element_dictionary();
15330 ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS;
15331 for (int i = 0; i < dictionary->Capacity(); i++) {
15332 Object* key = dictionary->KeyAt(i);
15333 if (key->IsNumber()) {
15334 Object* value = dictionary->ValueAt(i);
15335 if (!value->IsNumber()) return FAST_HOLEY_ELEMENTS;
15336 if (!value->IsSmi()) {
15337 if (!FLAG_unbox_double_arrays) return FAST_HOLEY_ELEMENTS;
15338 kind = FAST_HOLEY_DOUBLE_ELEMENTS;
15339 }
15340 }
15341 }
15342 return kind;
15343 }
15344
15345
ShouldConvertToFastElements(JSObject * object,SeededNumberDictionary * dictionary,uint32_t index,uint32_t * new_capacity)15346 static bool ShouldConvertToFastElements(JSObject* object,
15347 SeededNumberDictionary* dictionary,
15348 uint32_t index,
15349 uint32_t* new_capacity) {
15350 // If properties with non-standard attributes or accessors were added, we
15351 // cannot go back to fast elements.
15352 if (dictionary->requires_slow_elements()) return false;
15353
15354 // Adding a property with this index will require slow elements.
15355 if (index >= static_cast<uint32_t>(Smi::kMaxValue)) return false;
15356
15357 if (object->IsJSArray()) {
15358 Object* length = JSArray::cast(object)->length();
15359 if (!length->IsSmi()) return false;
15360 *new_capacity = static_cast<uint32_t>(Smi::cast(length)->value());
15361 } else {
15362 *new_capacity = dictionary->max_number_key() + 1;
15363 }
15364 *new_capacity = Max(index + 1, *new_capacity);
15365
15366 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
15367 SeededNumberDictionary::kEntrySize;
15368
15369 // Turn fast if the dictionary only saves 50% space.
15370 return 2 * dictionary_size >= *new_capacity;
15371 }
15372
15373
15374 // static
AddDataElement(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes)15375 MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> object,
15376 uint32_t index,
15377 Handle<Object> value,
15378 PropertyAttributes attributes) {
15379 MAYBE_RETURN_NULL(
15380 AddDataElement(object, index, value, attributes, THROW_ON_ERROR));
15381 return value;
15382 }
15383
15384
15385 // static
AddDataElement(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,ShouldThrow should_throw)15386 Maybe<bool> JSObject::AddDataElement(Handle<JSObject> object, uint32_t index,
15387 Handle<Object> value,
15388 PropertyAttributes attributes,
15389 ShouldThrow should_throw) {
15390 DCHECK(object->map()->is_extensible());
15391
15392 Isolate* isolate = object->GetIsolate();
15393
15394 uint32_t old_length = 0;
15395 uint32_t new_capacity = 0;
15396
15397 if (object->IsJSArray()) {
15398 CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length));
15399 }
15400
15401 ElementsKind kind = object->GetElementsKind();
15402 FixedArrayBase* elements = object->elements();
15403 ElementsKind dictionary_kind = DICTIONARY_ELEMENTS;
15404 if (IsSloppyArgumentsElements(kind)) {
15405 elements = FixedArrayBase::cast(FixedArray::cast(elements)->get(1));
15406 dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
15407 } else if (IsStringWrapperElementsKind(kind)) {
15408 dictionary_kind = SLOW_STRING_WRAPPER_ELEMENTS;
15409 }
15410
15411 if (attributes != NONE) {
15412 kind = dictionary_kind;
15413 } else if (elements->IsSeededNumberDictionary()) {
15414 kind = ShouldConvertToFastElements(*object,
15415 SeededNumberDictionary::cast(elements),
15416 index, &new_capacity)
15417 ? BestFittingFastElementsKind(*object)
15418 : dictionary_kind; // Overwrite in case of arguments.
15419 } else if (ShouldConvertToSlowElements(
15420 *object, static_cast<uint32_t>(elements->length()), index,
15421 &new_capacity)) {
15422 kind = dictionary_kind;
15423 }
15424
15425 ElementsKind to = value->OptimalElementsKind();
15426 if (IsHoleyElementsKind(kind) || !object->IsJSArray() || index > old_length) {
15427 to = GetHoleyElementsKind(to);
15428 kind = GetHoleyElementsKind(kind);
15429 }
15430 to = GetMoreGeneralElementsKind(kind, to);
15431 ElementsAccessor* accessor = ElementsAccessor::ForKind(to);
15432 accessor->Add(object, index, value, attributes, new_capacity);
15433
15434 if (object->IsJSArray() && index >= old_length) {
15435 Handle<Object> new_length =
15436 isolate->factory()->NewNumberFromUint(index + 1);
15437 JSArray::cast(*object)->set_length(*new_length);
15438 }
15439
15440 return Just(true);
15441 }
15442
15443
SetLengthWouldNormalize(uint32_t new_length)15444 bool JSArray::SetLengthWouldNormalize(uint32_t new_length) {
15445 if (!HasFastElements()) return false;
15446 uint32_t capacity = static_cast<uint32_t>(elements()->length());
15447 uint32_t new_capacity;
15448 return JSArray::SetLengthWouldNormalize(GetHeap(), new_length) &&
15449 ShouldConvertToSlowElements(this, capacity, new_length - 1,
15450 &new_capacity);
15451 }
15452
15453
15454 const double AllocationSite::kPretenureRatio = 0.85;
15455
15456
ResetPretenureDecision()15457 void AllocationSite::ResetPretenureDecision() {
15458 set_pretenure_decision(kUndecided);
15459 set_memento_found_count(0);
15460 set_memento_create_count(0);
15461 }
15462
15463
GetPretenureMode()15464 PretenureFlag AllocationSite::GetPretenureMode() {
15465 PretenureDecision mode = pretenure_decision();
15466 // Zombie objects "decide" to be untenured.
15467 return mode == kTenure ? TENURED : NOT_TENURED;
15468 }
15469
15470
IsNestedSite()15471 bool AllocationSite::IsNestedSite() {
15472 DCHECK(FLAG_trace_track_allocation_sites);
15473 Object* current = GetHeap()->allocation_sites_list();
15474 while (current->IsAllocationSite()) {
15475 AllocationSite* current_site = AllocationSite::cast(current);
15476 if (current_site->nested_site() == this) {
15477 return true;
15478 }
15479 current = current_site->weak_next();
15480 }
15481 return false;
15482 }
15483
15484 template <AllocationSiteUpdateMode update_or_check>
DigestTransitionFeedback(Handle<AllocationSite> site,ElementsKind to_kind)15485 bool AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
15486 ElementsKind to_kind) {
15487 Isolate* isolate = site->GetIsolate();
15488 bool result = false;
15489
15490 if (site->SitePointsToLiteral() && site->transition_info()->IsJSArray()) {
15491 Handle<JSArray> transition_info =
15492 handle(JSArray::cast(site->transition_info()));
15493 ElementsKind kind = transition_info->GetElementsKind();
15494 // if kind is holey ensure that to_kind is as well.
15495 if (IsHoleyElementsKind(kind)) {
15496 to_kind = GetHoleyElementsKind(to_kind);
15497 }
15498 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
15499 // If the array is huge, it's not likely to be defined in a local
15500 // function, so we shouldn't make new instances of it very often.
15501 uint32_t length = 0;
15502 CHECK(transition_info->length()->ToArrayLength(&length));
15503 if (length <= kMaximumArrayBytesToPretransition) {
15504 if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) {
15505 return true;
15506 }
15507 if (FLAG_trace_track_allocation_sites) {
15508 bool is_nested = site->IsNestedSite();
15509 PrintF(
15510 "AllocationSite: JSArray %p boilerplate %s updated %s->%s\n",
15511 reinterpret_cast<void*>(*site),
15512 is_nested ? "(nested)" : "",
15513 ElementsKindToString(kind),
15514 ElementsKindToString(to_kind));
15515 }
15516 JSObject::TransitionElementsKind(transition_info, to_kind);
15517 site->dependent_code()->DeoptimizeDependentCodeGroup(
15518 isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
15519 result = true;
15520 }
15521 }
15522 } else {
15523 ElementsKind kind = site->GetElementsKind();
15524 // if kind is holey ensure that to_kind is as well.
15525 if (IsHoleyElementsKind(kind)) {
15526 to_kind = GetHoleyElementsKind(to_kind);
15527 }
15528 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
15529 if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) return true;
15530 if (FLAG_trace_track_allocation_sites) {
15531 PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
15532 reinterpret_cast<void*>(*site),
15533 ElementsKindToString(kind),
15534 ElementsKindToString(to_kind));
15535 }
15536 site->SetElementsKind(to_kind);
15537 site->dependent_code()->DeoptimizeDependentCodeGroup(
15538 isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
15539 result = true;
15540 }
15541 }
15542 return result;
15543 }
15544
GetMode(ElementsKind from,ElementsKind to)15545 AllocationSiteMode AllocationSite::GetMode(ElementsKind from, ElementsKind to) {
15546 if (IsFastSmiElementsKind(from) &&
15547 IsMoreGeneralElementsKindTransition(from, to)) {
15548 return TRACK_ALLOCATION_SITE;
15549 }
15550
15551 return DONT_TRACK_ALLOCATION_SITE;
15552 }
15553
PretenureDecisionName(PretenureDecision decision)15554 const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) {
15555 switch (decision) {
15556 case kUndecided: return "undecided";
15557 case kDontTenure: return "don't tenure";
15558 case kMaybeTenure: return "maybe tenure";
15559 case kTenure: return "tenure";
15560 case kZombie: return "zombie";
15561 default: UNREACHABLE();
15562 }
15563 return NULL;
15564 }
15565
15566 template <AllocationSiteUpdateMode update_or_check>
UpdateAllocationSite(Handle<JSObject> object,ElementsKind to_kind)15567 bool JSObject::UpdateAllocationSite(Handle<JSObject> object,
15568 ElementsKind to_kind) {
15569 if (!object->IsJSArray()) return false;
15570
15571 Heap* heap = object->GetHeap();
15572 if (!heap->InNewSpace(*object)) return false;
15573
15574 Handle<AllocationSite> site;
15575 {
15576 DisallowHeapAllocation no_allocation;
15577
15578 AllocationMemento* memento =
15579 heap->FindAllocationMemento<Heap::kForRuntime>(*object);
15580 if (memento == NULL) return false;
15581
15582 // Walk through to the Allocation Site
15583 site = handle(memento->GetAllocationSite());
15584 }
15585 return AllocationSite::DigestTransitionFeedback<update_or_check>(site,
15586 to_kind);
15587 }
15588
15589 template bool
15590 JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kCheckOnly>(
15591 Handle<JSObject> object, ElementsKind to_kind);
15592
15593 template bool JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kUpdate>(
15594 Handle<JSObject> object, ElementsKind to_kind);
15595
TransitionElementsKind(Handle<JSObject> object,ElementsKind to_kind)15596 void JSObject::TransitionElementsKind(Handle<JSObject> object,
15597 ElementsKind to_kind) {
15598 ElementsKind from_kind = object->GetElementsKind();
15599
15600 if (IsFastHoleyElementsKind(from_kind)) {
15601 to_kind = GetHoleyElementsKind(to_kind);
15602 }
15603
15604 if (from_kind == to_kind) return;
15605
15606 // This method should never be called for any other case.
15607 DCHECK(IsFastElementsKind(from_kind));
15608 DCHECK(IsFastElementsKind(to_kind));
15609 DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind);
15610
15611 UpdateAllocationSite(object, to_kind);
15612 if (object->elements() == object->GetHeap()->empty_fixed_array() ||
15613 IsFastDoubleElementsKind(from_kind) ==
15614 IsFastDoubleElementsKind(to_kind)) {
15615 // No change is needed to the elements() buffer, the transition
15616 // only requires a map change.
15617 Handle<Map> new_map = GetElementsTransitionMap(object, to_kind);
15618 MigrateToMap(object, new_map);
15619 if (FLAG_trace_elements_transitions) {
15620 Handle<FixedArrayBase> elms(object->elements());
15621 PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms);
15622 }
15623 } else {
15624 DCHECK((IsFastSmiElementsKind(from_kind) &&
15625 IsFastDoubleElementsKind(to_kind)) ||
15626 (IsFastDoubleElementsKind(from_kind) &&
15627 IsFastObjectElementsKind(to_kind)));
15628 uint32_t c = static_cast<uint32_t>(object->elements()->length());
15629 ElementsAccessor::ForKind(to_kind)->GrowCapacityAndConvert(object, c);
15630 }
15631 }
15632
15633
15634 // static
IsValidElementsTransition(ElementsKind from_kind,ElementsKind to_kind)15635 bool Map::IsValidElementsTransition(ElementsKind from_kind,
15636 ElementsKind to_kind) {
15637 // Transitions can't go backwards.
15638 if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
15639 return false;
15640 }
15641
15642 // Transitions from HOLEY -> PACKED are not allowed.
15643 return !IsFastHoleyElementsKind(from_kind) ||
15644 IsFastHoleyElementsKind(to_kind);
15645 }
15646
15647
HasReadOnlyLength(Handle<JSArray> array)15648 bool JSArray::HasReadOnlyLength(Handle<JSArray> array) {
15649 Map* map = array->map();
15650 // Fast path: "length" is the first fast property of arrays. Since it's not
15651 // configurable, it's guaranteed to be the first in the descriptor array.
15652 if (!map->is_dictionary_map()) {
15653 DCHECK(map->instance_descriptors()->GetKey(0) ==
15654 array->GetHeap()->length_string());
15655 return map->instance_descriptors()->GetDetails(0).IsReadOnly();
15656 }
15657
15658 Isolate* isolate = array->GetIsolate();
15659 LookupIterator it(array, isolate->factory()->length_string(), array,
15660 LookupIterator::OWN_SKIP_INTERCEPTOR);
15661 CHECK_EQ(LookupIterator::ACCESSOR, it.state());
15662 return it.IsReadOnly();
15663 }
15664
15665
WouldChangeReadOnlyLength(Handle<JSArray> array,uint32_t index)15666 bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array,
15667 uint32_t index) {
15668 uint32_t length = 0;
15669 CHECK(array->length()->ToArrayLength(&length));
15670 if (length <= index) return HasReadOnlyLength(array);
15671 return false;
15672 }
15673
15674
15675 template <typename BackingStore>
FastHoleyElementsUsage(JSObject * object,BackingStore * store)15676 static int FastHoleyElementsUsage(JSObject* object, BackingStore* store) {
15677 Isolate* isolate = store->GetIsolate();
15678 int limit = object->IsJSArray()
15679 ? Smi::cast(JSArray::cast(object)->length())->value()
15680 : store->length();
15681 int used = 0;
15682 for (int i = 0; i < limit; ++i) {
15683 if (!store->is_the_hole(isolate, i)) ++used;
15684 }
15685 return used;
15686 }
15687
15688
GetFastElementsUsage()15689 int JSObject::GetFastElementsUsage() {
15690 FixedArrayBase* store = elements();
15691 switch (GetElementsKind()) {
15692 case FAST_SMI_ELEMENTS:
15693 case FAST_DOUBLE_ELEMENTS:
15694 case FAST_ELEMENTS:
15695 return IsJSArray() ? Smi::cast(JSArray::cast(this)->length())->value()
15696 : store->length();
15697 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
15698 store = FixedArray::cast(FixedArray::cast(store)->get(1));
15699 // Fall through.
15700 case FAST_HOLEY_SMI_ELEMENTS:
15701 case FAST_HOLEY_ELEMENTS:
15702 case FAST_STRING_WRAPPER_ELEMENTS:
15703 return FastHoleyElementsUsage(this, FixedArray::cast(store));
15704 case FAST_HOLEY_DOUBLE_ELEMENTS:
15705 if (elements()->length() == 0) return 0;
15706 return FastHoleyElementsUsage(this, FixedDoubleArray::cast(store));
15707
15708 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
15709 case SLOW_STRING_WRAPPER_ELEMENTS:
15710 case DICTIONARY_ELEMENTS:
15711 case NO_ELEMENTS:
15712 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
15713 case TYPE##_ELEMENTS: \
15714
15715 TYPED_ARRAYS(TYPED_ARRAY_CASE)
15716 #undef TYPED_ARRAY_CASE
15717 UNREACHABLE();
15718 }
15719 return 0;
15720 }
15721
15722
15723 // Certain compilers request function template instantiation when they
15724 // see the definition of the other template functions in the
15725 // class. This requires us to have the template functions put
15726 // together, so even though this function belongs in objects-debug.cc,
15727 // we keep it here instead to satisfy certain compilers.
15728 #ifdef OBJECT_PRINT
15729 template <typename Derived, typename Shape, typename Key>
Print(std::ostream & os)15730 void Dictionary<Derived, Shape, Key>::Print(std::ostream& os) { // NOLINT
15731 Isolate* isolate = this->GetIsolate();
15732 int capacity = this->Capacity();
15733 for (int i = 0; i < capacity; i++) {
15734 Object* k = this->KeyAt(i);
15735 if (this->IsKey(isolate, k)) {
15736 os << "\n ";
15737 if (k->IsString()) {
15738 String::cast(k)->StringPrint(os);
15739 } else {
15740 os << Brief(k);
15741 }
15742 os << ": " << Brief(this->ValueAt(i)) << " ";
15743 this->DetailsAt(i).PrintAsSlowTo(os);
15744 }
15745 }
15746 }
15747 template <typename Derived, typename Shape, typename Key>
Print()15748 void Dictionary<Derived, Shape, Key>::Print() {
15749 OFStream os(stdout);
15750 Print(os);
15751 }
15752 #endif
15753
15754
15755 template<typename Derived, typename Shape, typename Key>
CopyValuesTo(FixedArray * elements)15756 void Dictionary<Derived, Shape, Key>::CopyValuesTo(FixedArray* elements) {
15757 Isolate* isolate = this->GetIsolate();
15758 int pos = 0;
15759 int capacity = this->Capacity();
15760 DisallowHeapAllocation no_gc;
15761 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
15762 for (int i = 0; i < capacity; i++) {
15763 Object* k = this->KeyAt(i);
15764 if (this->IsKey(isolate, k)) {
15765 elements->set(pos++, this->ValueAt(i), mode);
15766 }
15767 }
15768 DCHECK(pos == elements->length());
15769 }
15770
15771
GetPropertyWithInterceptor(LookupIterator * it,bool * done)15772 MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it,
15773 bool* done) {
15774 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
15775 return GetPropertyWithInterceptorInternal(it, it->GetInterceptor(), done);
15776 }
15777
HasRealNamedProperty(Handle<JSObject> object,Handle<Name> name)15778 Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object,
15779 Handle<Name> name) {
15780 LookupIterator it = LookupIterator::PropertyOrElement(
15781 name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
15782 return HasProperty(&it);
15783 }
15784
15785
HasRealElementProperty(Handle<JSObject> object,uint32_t index)15786 Maybe<bool> JSObject::HasRealElementProperty(Handle<JSObject> object,
15787 uint32_t index) {
15788 Isolate* isolate = object->GetIsolate();
15789 LookupIterator it(isolate, object, index, object,
15790 LookupIterator::OWN_SKIP_INTERCEPTOR);
15791 return HasProperty(&it);
15792 }
15793
15794
HasRealNamedCallbackProperty(Handle<JSObject> object,Handle<Name> name)15795 Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
15796 Handle<Name> name) {
15797 LookupIterator it = LookupIterator::PropertyOrElement(
15798 name->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
15799 Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
15800 return maybe_result.IsJust() ? Just(it.state() == LookupIterator::ACCESSOR)
15801 : Nothing<bool>();
15802 }
15803
GetMaxLengthForNewSpaceAllocation(ElementsKind kind)15804 int FixedArrayBase::GetMaxLengthForNewSpaceAllocation(ElementsKind kind) {
15805 return ((kMaxRegularHeapObjectSize - FixedArrayBase::kHeaderSize) >>
15806 ElementsKindToShiftSize(kind));
15807 }
15808
WasConstructedFromApiFunction()15809 bool JSObject::WasConstructedFromApiFunction() {
15810 auto instance_type = map()->instance_type();
15811 bool is_api_object = instance_type == JS_API_OBJECT_TYPE ||
15812 instance_type == JS_SPECIAL_API_OBJECT_TYPE;
15813 #ifdef ENABLE_SLOW_DCHECKS
15814 if (FLAG_enable_slow_asserts) {
15815 Object* maybe_constructor = map()->GetConstructor();
15816 if (!maybe_constructor->IsJSFunction()) return false;
15817 JSFunction* constructor = JSFunction::cast(maybe_constructor);
15818 if (constructor->shared()->IsApiFunction()) {
15819 DCHECK(is_api_object);
15820 } else {
15821 DCHECK(!is_api_object);
15822 }
15823 }
15824 #endif
15825 return is_api_object;
15826 }
15827
PrivateSymbolToName() const15828 const char* Symbol::PrivateSymbolToName() const {
15829 Heap* heap = GetIsolate()->heap();
15830 #define SYMBOL_CHECK_AND_PRINT(name) \
15831 if (this == heap->name()) return #name;
15832 PRIVATE_SYMBOL_LIST(SYMBOL_CHECK_AND_PRINT)
15833 #undef SYMBOL_CHECK_AND_PRINT
15834 return "UNKNOWN";
15835 }
15836
15837
SymbolShortPrint(std::ostream & os)15838 void Symbol::SymbolShortPrint(std::ostream& os) {
15839 os << "<Symbol:";
15840 if (!name()->IsUndefined(GetIsolate())) {
15841 os << " ";
15842 HeapStringAllocator allocator;
15843 StringStream accumulator(&allocator);
15844 String::cast(name())->StringShortPrint(&accumulator, false);
15845 os << accumulator.ToCString().get();
15846 } else {
15847 os << " (" << PrivateSymbolToName() << ")";
15848 }
15849 os << ">";
15850 }
15851
15852
15853 // StringSharedKeys are used as keys in the eval cache.
15854 class StringSharedKey : public HashTableKey {
15855 public:
15856 // This tuple unambiguously identifies calls to eval() or
15857 // CreateDynamicFunction() (such as through the Function() constructor).
15858 // * source is the string passed into eval(). For dynamic functions, this is
15859 // the effective source for the function, some of which is implicitly
15860 // generated.
15861 // * shared is the shared function info for the function containing the call
15862 // to eval(). for dynamic functions, shared is the native context closure.
15863 // * When positive, position is the position in the source where eval is
15864 // called. When negative, position is the negation of the position in the
15865 // dynamic function's effective source where the ')' ends the parameters.
StringSharedKey(Handle<String> source,Handle<SharedFunctionInfo> shared,LanguageMode language_mode,int position)15866 StringSharedKey(Handle<String> source, Handle<SharedFunctionInfo> shared,
15867 LanguageMode language_mode, int position)
15868 : source_(source),
15869 shared_(shared),
15870 language_mode_(language_mode),
15871 position_(position) {}
15872
IsMatch(Object * other)15873 bool IsMatch(Object* other) override {
15874 DisallowHeapAllocation no_allocation;
15875 if (!other->IsFixedArray()) {
15876 if (!other->IsNumber()) return false;
15877 uint32_t other_hash = static_cast<uint32_t>(other->Number());
15878 return Hash() == other_hash;
15879 }
15880 FixedArray* other_array = FixedArray::cast(other);
15881 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
15882 if (shared != *shared_) return false;
15883 int language_unchecked = Smi::cast(other_array->get(2))->value();
15884 DCHECK(is_valid_language_mode(language_unchecked));
15885 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
15886 if (language_mode != language_mode_) return false;
15887 int position = Smi::cast(other_array->get(3))->value();
15888 if (position != position_) return false;
15889 String* source = String::cast(other_array->get(1));
15890 return source->Equals(*source_);
15891 }
15892
StringSharedHashHelper(String * source,SharedFunctionInfo * shared,LanguageMode language_mode,int position)15893 static uint32_t StringSharedHashHelper(String* source,
15894 SharedFunctionInfo* shared,
15895 LanguageMode language_mode,
15896 int position) {
15897 uint32_t hash = source->Hash();
15898 if (shared->HasSourceCode()) {
15899 // Instead of using the SharedFunctionInfo pointer in the hash
15900 // code computation, we use a combination of the hash of the
15901 // script source code and the start position of the calling scope.
15902 // We do this to ensure that the cache entries can survive garbage
15903 // collection.
15904 Script* script(Script::cast(shared->script()));
15905 hash ^= String::cast(script->source())->Hash();
15906 STATIC_ASSERT(LANGUAGE_END == 2);
15907 if (is_strict(language_mode)) hash ^= 0x8000;
15908 hash += position;
15909 }
15910 return hash;
15911 }
15912
Hash()15913 uint32_t Hash() override {
15914 return StringSharedHashHelper(*source_, *shared_, language_mode_,
15915 position_);
15916 }
15917
HashForObject(Object * obj)15918 uint32_t HashForObject(Object* obj) override {
15919 DisallowHeapAllocation no_allocation;
15920 if (obj->IsNumber()) {
15921 return static_cast<uint32_t>(obj->Number());
15922 }
15923 FixedArray* other_array = FixedArray::cast(obj);
15924 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
15925 String* source = String::cast(other_array->get(1));
15926 int language_unchecked = Smi::cast(other_array->get(2))->value();
15927 DCHECK(is_valid_language_mode(language_unchecked));
15928 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
15929 int position = Smi::cast(other_array->get(3))->value();
15930 return StringSharedHashHelper(source, shared, language_mode, position);
15931 }
15932
15933
AsHandle(Isolate * isolate)15934 Handle<Object> AsHandle(Isolate* isolate) override {
15935 Handle<FixedArray> array = isolate->factory()->NewFixedArray(4);
15936 array->set(0, *shared_);
15937 array->set(1, *source_);
15938 array->set(2, Smi::FromInt(language_mode_));
15939 array->set(3, Smi::FromInt(position_));
15940 return array;
15941 }
15942
15943 private:
15944 Handle<String> source_;
15945 Handle<SharedFunctionInfo> shared_;
15946 LanguageMode language_mode_;
15947 int position_;
15948 };
15949
15950 // static
Status(int status)15951 const char* JSPromise::Status(int status) {
15952 switch (status) {
15953 case v8::Promise::kFulfilled:
15954 return "resolved";
15955 case v8::Promise::kPending:
15956 return "pending";
15957 case v8::Promise::kRejected:
15958 return "rejected";
15959 }
15960 UNREACHABLE();
15961 return NULL;
15962 }
15963
15964 namespace {
15965
RegExpFlagsFromString(Handle<String> flags,bool * success)15966 JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags, bool* success) {
15967 JSRegExp::Flags value = JSRegExp::kNone;
15968 int length = flags->length();
15969 // A longer flags string cannot be valid.
15970 if (length > 5) return JSRegExp::Flags(0);
15971 for (int i = 0; i < length; i++) {
15972 JSRegExp::Flag flag = JSRegExp::kNone;
15973 switch (flags->Get(i)) {
15974 case 'g':
15975 flag = JSRegExp::kGlobal;
15976 break;
15977 case 'i':
15978 flag = JSRegExp::kIgnoreCase;
15979 break;
15980 case 'm':
15981 flag = JSRegExp::kMultiline;
15982 break;
15983 case 'u':
15984 flag = JSRegExp::kUnicode;
15985 break;
15986 case 'y':
15987 flag = JSRegExp::kSticky;
15988 break;
15989 default:
15990 return JSRegExp::Flags(0);
15991 }
15992 // Duplicate flag.
15993 if (value & flag) return JSRegExp::Flags(0);
15994 value |= flag;
15995 }
15996 *success = true;
15997 return value;
15998 }
15999
16000 } // namespace
16001
16002
16003 // static
New(Handle<String> pattern,Flags flags)16004 MaybeHandle<JSRegExp> JSRegExp::New(Handle<String> pattern, Flags flags) {
16005 Isolate* isolate = pattern->GetIsolate();
16006 Handle<JSFunction> constructor = isolate->regexp_function();
16007 Handle<JSRegExp> regexp =
16008 Handle<JSRegExp>::cast(isolate->factory()->NewJSObject(constructor));
16009
16010 return JSRegExp::Initialize(regexp, pattern, flags);
16011 }
16012
16013
16014 // static
Copy(Handle<JSRegExp> regexp)16015 Handle<JSRegExp> JSRegExp::Copy(Handle<JSRegExp> regexp) {
16016 Isolate* const isolate = regexp->GetIsolate();
16017 return Handle<JSRegExp>::cast(isolate->factory()->CopyJSObject(regexp));
16018 }
16019
16020
16021 template <typename Char>
CountRequiredEscapes(Handle<String> source)16022 inline int CountRequiredEscapes(Handle<String> source) {
16023 DisallowHeapAllocation no_gc;
16024 int escapes = 0;
16025 Vector<const Char> src = source->GetCharVector<Char>();
16026 for (int i = 0; i < src.length(); i++) {
16027 if (src[i] == '\\') {
16028 // Escape. Skip next character;
16029 i++;
16030 } else if (src[i] == '/') {
16031 // Not escaped forward-slash needs escape.
16032 escapes++;
16033 }
16034 }
16035 return escapes;
16036 }
16037
16038
16039 template <typename Char, typename StringType>
WriteEscapedRegExpSource(Handle<String> source,Handle<StringType> result)16040 inline Handle<StringType> WriteEscapedRegExpSource(Handle<String> source,
16041 Handle<StringType> result) {
16042 DisallowHeapAllocation no_gc;
16043 Vector<const Char> src = source->GetCharVector<Char>();
16044 Vector<Char> dst(result->GetChars(), result->length());
16045 int s = 0;
16046 int d = 0;
16047 while (s < src.length()) {
16048 if (src[s] == '\\') {
16049 // Escape. Copy this and next character.
16050 dst[d++] = src[s++];
16051 if (s == src.length()) break;
16052 } else if (src[s] == '/') {
16053 // Not escaped forward-slash needs escape.
16054 dst[d++] = '\\';
16055 }
16056 dst[d++] = src[s++];
16057 }
16058 DCHECK_EQ(result->length(), d);
16059 return result;
16060 }
16061
16062
EscapeRegExpSource(Isolate * isolate,Handle<String> source)16063 MaybeHandle<String> EscapeRegExpSource(Isolate* isolate,
16064 Handle<String> source) {
16065 String::Flatten(source);
16066 if (source->length() == 0) return isolate->factory()->query_colon_string();
16067 bool one_byte = source->IsOneByteRepresentationUnderneath();
16068 int escapes = one_byte ? CountRequiredEscapes<uint8_t>(source)
16069 : CountRequiredEscapes<uc16>(source);
16070 if (escapes == 0) return source;
16071 int length = source->length() + escapes;
16072 if (one_byte) {
16073 Handle<SeqOneByteString> result;
16074 ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
16075 isolate->factory()->NewRawOneByteString(length),
16076 String);
16077 return WriteEscapedRegExpSource<uint8_t>(source, result);
16078 } else {
16079 Handle<SeqTwoByteString> result;
16080 ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
16081 isolate->factory()->NewRawTwoByteString(length),
16082 String);
16083 return WriteEscapedRegExpSource<uc16>(source, result);
16084 }
16085 }
16086
16087
16088 // static
Initialize(Handle<JSRegExp> regexp,Handle<String> source,Handle<String> flags_string)16089 MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
16090 Handle<String> source,
16091 Handle<String> flags_string) {
16092 Isolate* isolate = source->GetIsolate();
16093 bool success = false;
16094 Flags flags = RegExpFlagsFromString(flags_string, &success);
16095 if (!success) {
16096 THROW_NEW_ERROR(
16097 isolate,
16098 NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string),
16099 JSRegExp);
16100 }
16101 return Initialize(regexp, source, flags);
16102 }
16103
16104
16105 // static
Initialize(Handle<JSRegExp> regexp,Handle<String> source,Flags flags)16106 MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
16107 Handle<String> source, Flags flags) {
16108 Isolate* isolate = regexp->GetIsolate();
16109 Factory* factory = isolate->factory();
16110 // If source is the empty string we set it to "(?:)" instead as
16111 // suggested by ECMA-262, 5th, section 15.10.4.1.
16112 if (source->length() == 0) source = factory->query_colon_string();
16113
16114 Handle<String> escaped_source;
16115 ASSIGN_RETURN_ON_EXCEPTION(isolate, escaped_source,
16116 EscapeRegExpSource(isolate, source), JSRegExp);
16117
16118 RETURN_ON_EXCEPTION(isolate, RegExpImpl::Compile(regexp, source, flags),
16119 JSRegExp);
16120
16121 regexp->set_source(*escaped_source);
16122 regexp->set_flags(Smi::FromInt(flags));
16123
16124 Map* map = regexp->map();
16125 Object* constructor = map->GetConstructor();
16126 if (constructor->IsJSFunction() &&
16127 JSFunction::cast(constructor)->initial_map() == map) {
16128 // If we still have the original map, set in-object properties directly.
16129 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, Smi::kZero,
16130 SKIP_WRITE_BARRIER);
16131 } else {
16132 // Map has changed, so use generic, but slower, method.
16133 RETURN_ON_EXCEPTION(isolate, JSReceiver::SetProperty(
16134 regexp, factory->lastIndex_string(),
16135 Handle<Smi>(Smi::kZero, isolate), STRICT),
16136 JSRegExp);
16137 }
16138
16139 return regexp;
16140 }
16141
16142
16143 // RegExpKey carries the source and flags of a regular expression as key.
16144 class RegExpKey : public HashTableKey {
16145 public:
RegExpKey(Handle<String> string,JSRegExp::Flags flags)16146 RegExpKey(Handle<String> string, JSRegExp::Flags flags)
16147 : string_(string), flags_(Smi::FromInt(flags)) {}
16148
16149 // Rather than storing the key in the hash table, a pointer to the
16150 // stored value is stored where the key should be. IsMatch then
16151 // compares the search key to the found object, rather than comparing
16152 // a key to a key.
IsMatch(Object * obj)16153 bool IsMatch(Object* obj) override {
16154 FixedArray* val = FixedArray::cast(obj);
16155 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
16156 && (flags_ == val->get(JSRegExp::kFlagsIndex));
16157 }
16158
Hash()16159 uint32_t Hash() override { return RegExpHash(*string_, flags_); }
16160
AsHandle(Isolate * isolate)16161 Handle<Object> AsHandle(Isolate* isolate) override {
16162 // Plain hash maps, which is where regexp keys are used, don't
16163 // use this function.
16164 UNREACHABLE();
16165 return MaybeHandle<Object>().ToHandleChecked();
16166 }
16167
HashForObject(Object * obj)16168 uint32_t HashForObject(Object* obj) override {
16169 FixedArray* val = FixedArray::cast(obj);
16170 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
16171 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
16172 }
16173
RegExpHash(String * string,Smi * flags)16174 static uint32_t RegExpHash(String* string, Smi* flags) {
16175 return string->Hash() + flags->value();
16176 }
16177
16178 Handle<String> string_;
16179 Smi* flags_;
16180 };
16181
16182
AsHandle(Isolate * isolate)16183 Handle<Object> OneByteStringKey::AsHandle(Isolate* isolate) {
16184 if (hash_field_ == 0) Hash();
16185 return isolate->factory()->NewOneByteInternalizedString(string_, hash_field_);
16186 }
16187
16188
AsHandle(Isolate * isolate)16189 Handle<Object> TwoByteStringKey::AsHandle(Isolate* isolate) {
16190 if (hash_field_ == 0) Hash();
16191 return isolate->factory()->NewTwoByteInternalizedString(string_, hash_field_);
16192 }
16193
16194
AsHandle(Isolate * isolate)16195 Handle<Object> SeqOneByteSubStringKey::AsHandle(Isolate* isolate) {
16196 if (hash_field_ == 0) Hash();
16197 return isolate->factory()->NewOneByteInternalizedSubString(
16198 string_, from_, length_, hash_field_);
16199 }
16200
16201
IsMatch(Object * string)16202 bool SeqOneByteSubStringKey::IsMatch(Object* string) {
16203 Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
16204 return String::cast(string)->IsOneByteEqualTo(chars);
16205 }
16206
16207
16208 // InternalizedStringKey carries a string/internalized-string object as key.
16209 class InternalizedStringKey : public HashTableKey {
16210 public:
InternalizedStringKey(Handle<String> string)16211 explicit InternalizedStringKey(Handle<String> string)
16212 : string_(String::Flatten(string)) {}
16213
IsMatch(Object * string)16214 bool IsMatch(Object* string) override {
16215 return String::cast(string)->Equals(*string_);
16216 }
16217
Hash()16218 uint32_t Hash() override { return string_->Hash(); }
16219
HashForObject(Object * other)16220 uint32_t HashForObject(Object* other) override {
16221 return String::cast(other)->Hash();
16222 }
16223
AsHandle(Isolate * isolate)16224 Handle<Object> AsHandle(Isolate* isolate) override {
16225 // Internalize the string if possible.
16226 MaybeHandle<Map> maybe_map =
16227 isolate->factory()->InternalizedStringMapForString(string_);
16228 Handle<Map> map;
16229 if (maybe_map.ToHandle(&map)) {
16230 string_->set_map_no_write_barrier(*map);
16231 DCHECK(string_->IsInternalizedString());
16232 return string_;
16233 }
16234 if (FLAG_thin_strings) {
16235 // External strings get special treatment, to avoid copying their
16236 // contents.
16237 if (string_->IsExternalOneByteString()) {
16238 return isolate->factory()
16239 ->InternalizeExternalString<ExternalOneByteString>(string_);
16240 } else if (string_->IsExternalTwoByteString()) {
16241 return isolate->factory()
16242 ->InternalizeExternalString<ExternalTwoByteString>(string_);
16243 }
16244 }
16245 // Otherwise allocate a new internalized string.
16246 return isolate->factory()->NewInternalizedStringImpl(
16247 string_, string_->length(), string_->hash_field());
16248 }
16249
StringHash(Object * obj)16250 static uint32_t StringHash(Object* obj) {
16251 return String::cast(obj)->Hash();
16252 }
16253
16254 private:
16255 Handle<String> string_;
16256 };
16257
16258
16259 template<typename Derived, typename Shape, typename Key>
IteratePrefix(ObjectVisitor * v)16260 void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) {
16261 BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v);
16262 }
16263
16264
16265 template<typename Derived, typename Shape, typename Key>
IterateElements(ObjectVisitor * v)16266 void HashTable<Derived, Shape, Key>::IterateElements(ObjectVisitor* v) {
16267 BodyDescriptorBase::IteratePointers(this, kElementsStartOffset,
16268 kHeaderSize + length() * kPointerSize, v);
16269 }
16270
16271
16272 template<typename Derived, typename Shape, typename Key>
New(Isolate * isolate,int at_least_space_for,MinimumCapacity capacity_option,PretenureFlag pretenure)16273 Handle<Derived> HashTable<Derived, Shape, Key>::New(
16274 Isolate* isolate,
16275 int at_least_space_for,
16276 MinimumCapacity capacity_option,
16277 PretenureFlag pretenure) {
16278 DCHECK(0 <= at_least_space_for);
16279 DCHECK_IMPLIES(capacity_option == USE_CUSTOM_MINIMUM_CAPACITY,
16280 base::bits::IsPowerOfTwo32(at_least_space_for));
16281
16282 int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
16283 ? at_least_space_for
16284 : ComputeCapacity(at_least_space_for);
16285 if (capacity > HashTable::kMaxCapacity) {
16286 v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
16287 }
16288 return New(isolate, capacity, pretenure);
16289 }
16290
16291 template <typename Derived, typename Shape, typename Key>
New(Isolate * isolate,int capacity,PretenureFlag pretenure)16292 Handle<Derived> HashTable<Derived, Shape, Key>::New(Isolate* isolate,
16293 int capacity,
16294 PretenureFlag pretenure) {
16295 Factory* factory = isolate->factory();
16296 int length = EntryToIndex(capacity);
16297 Handle<FixedArray> array = factory->NewFixedArray(length, pretenure);
16298 array->set_map_no_write_barrier(Shape::GetMap(isolate));
16299 Handle<Derived> table = Handle<Derived>::cast(array);
16300
16301 table->SetNumberOfElements(0);
16302 table->SetNumberOfDeletedElements(0);
16303 table->SetCapacity(capacity);
16304 return table;
16305 }
16306
16307 // Find entry for key otherwise return kNotFound.
16308 template <typename Derived, typename Shape>
FindEntry(Handle<Name> key)16309 int NameDictionaryBase<Derived, Shape>::FindEntry(Handle<Name> key) {
16310 if (!key->IsUniqueName()) {
16311 return DerivedDictionary::FindEntry(key);
16312 }
16313
16314 // Optimized for unique names. Knowledge of the key type allows:
16315 // 1. Move the check if the key is unique out of the loop.
16316 // 2. Avoid comparing hash codes in unique-to-unique comparison.
16317 // 3. Detect a case when a dictionary key is not unique but the key is.
16318 // In case of positive result the dictionary key may be replaced by the
16319 // internalized string with minimal performance penalty. It gives a chance
16320 // to perform further lookups in code stubs (and significant performance
16321 // boost a certain style of code).
16322
16323 // EnsureCapacity will guarantee the hash table is never full.
16324 uint32_t capacity = this->Capacity();
16325 uint32_t entry = Derived::FirstProbe(key->Hash(), capacity);
16326 uint32_t count = 1;
16327 Isolate* isolate = this->GetIsolate();
16328 while (true) {
16329 Object* element = this->KeyAt(entry);
16330 if (element->IsUndefined(isolate)) break; // Empty entry.
16331 if (*key == element) return entry;
16332 DCHECK(element->IsTheHole(isolate) || element->IsUniqueName());
16333 entry = Derived::NextProbe(entry, count++, capacity);
16334 }
16335 return Derived::kNotFound;
16336 }
16337
16338
16339 template<typename Derived, typename Shape, typename Key>
Rehash(Handle<Derived> new_table,Key key)16340 void HashTable<Derived, Shape, Key>::Rehash(
16341 Handle<Derived> new_table,
16342 Key key) {
16343 DCHECK(NumberOfElements() < new_table->Capacity());
16344
16345 DisallowHeapAllocation no_gc;
16346 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
16347
16348 // Copy prefix to new array.
16349 for (int i = kPrefixStartIndex;
16350 i < kPrefixStartIndex + Shape::kPrefixSize;
16351 i++) {
16352 new_table->set(i, get(i), mode);
16353 }
16354
16355 // Rehash the elements.
16356 int capacity = this->Capacity();
16357 Heap* heap = new_table->GetHeap();
16358 Object* the_hole = heap->the_hole_value();
16359 Object* undefined = heap->undefined_value();
16360 for (int i = 0; i < capacity; i++) {
16361 uint32_t from_index = EntryToIndex(i);
16362 Object* k = this->get(from_index);
16363 if (k != the_hole && k != undefined) {
16364 uint32_t hash = this->HashForObject(key, k);
16365 uint32_t insertion_index =
16366 EntryToIndex(new_table->FindInsertionEntry(hash));
16367 for (int j = 0; j < Shape::kEntrySize; j++) {
16368 new_table->set(insertion_index + j, get(from_index + j), mode);
16369 }
16370 }
16371 }
16372 new_table->SetNumberOfElements(NumberOfElements());
16373 new_table->SetNumberOfDeletedElements(0);
16374 }
16375
16376
16377 template<typename Derived, typename Shape, typename Key>
EntryForProbe(Key key,Object * k,int probe,uint32_t expected)16378 uint32_t HashTable<Derived, Shape, Key>::EntryForProbe(
16379 Key key,
16380 Object* k,
16381 int probe,
16382 uint32_t expected) {
16383 uint32_t hash = this->HashForObject(key, k);
16384 uint32_t capacity = this->Capacity();
16385 uint32_t entry = FirstProbe(hash, capacity);
16386 for (int i = 1; i < probe; i++) {
16387 if (entry == expected) return expected;
16388 entry = NextProbe(entry, i, capacity);
16389 }
16390 return entry;
16391 }
16392
16393
16394 template<typename Derived, typename Shape, typename Key>
Swap(uint32_t entry1,uint32_t entry2,WriteBarrierMode mode)16395 void HashTable<Derived, Shape, Key>::Swap(uint32_t entry1,
16396 uint32_t entry2,
16397 WriteBarrierMode mode) {
16398 int index1 = EntryToIndex(entry1);
16399 int index2 = EntryToIndex(entry2);
16400 Object* temp[Shape::kEntrySize];
16401 for (int j = 0; j < Shape::kEntrySize; j++) {
16402 temp[j] = get(index1 + j);
16403 }
16404 for (int j = 0; j < Shape::kEntrySize; j++) {
16405 set(index1 + j, get(index2 + j), mode);
16406 }
16407 for (int j = 0; j < Shape::kEntrySize; j++) {
16408 set(index2 + j, temp[j], mode);
16409 }
16410 }
16411
16412
16413 template<typename Derived, typename Shape, typename Key>
Rehash(Key key)16414 void HashTable<Derived, Shape, Key>::Rehash(Key key) {
16415 DisallowHeapAllocation no_gc;
16416 WriteBarrierMode mode = GetWriteBarrierMode(no_gc);
16417 Isolate* isolate = GetIsolate();
16418 uint32_t capacity = Capacity();
16419 bool done = false;
16420 for (int probe = 1; !done; probe++) {
16421 // All elements at entries given by one of the first _probe_ probes
16422 // are placed correctly. Other elements might need to be moved.
16423 done = true;
16424 for (uint32_t current = 0; current < capacity; current++) {
16425 Object* current_key = KeyAt(current);
16426 if (IsKey(isolate, current_key)) {
16427 uint32_t target = EntryForProbe(key, current_key, probe, current);
16428 if (current == target) continue;
16429 Object* target_key = KeyAt(target);
16430 if (!IsKey(target_key) ||
16431 EntryForProbe(key, target_key, probe, target) != target) {
16432 // Put the current element into the correct position.
16433 Swap(current, target, mode);
16434 // The other element will be processed on the next iteration.
16435 current--;
16436 } else {
16437 // The place for the current element is occupied. Leave the element
16438 // for the next probe.
16439 done = false;
16440 }
16441 }
16442 }
16443 }
16444 // Wipe deleted entries.
16445 Object* the_hole = isolate->heap()->the_hole_value();
16446 Object* undefined = isolate->heap()->undefined_value();
16447 for (uint32_t current = 0; current < capacity; current++) {
16448 if (KeyAt(current) == the_hole) {
16449 set(EntryToIndex(current) + Derived::kEntryKeyIndex, undefined);
16450 }
16451 }
16452 SetNumberOfDeletedElements(0);
16453 }
16454
16455
16456 template<typename Derived, typename Shape, typename Key>
EnsureCapacity(Handle<Derived> table,int n,Key key,PretenureFlag pretenure)16457 Handle<Derived> HashTable<Derived, Shape, Key>::EnsureCapacity(
16458 Handle<Derived> table,
16459 int n,
16460 Key key,
16461 PretenureFlag pretenure) {
16462 Isolate* isolate = table->GetIsolate();
16463 int capacity = table->Capacity();
16464 int nof = table->NumberOfElements() + n;
16465
16466 if (table->HasSufficientCapacityToAdd(n)) return table;
16467
16468 const int kMinCapacityForPretenure = 256;
16469 bool should_pretenure = pretenure == TENURED ||
16470 ((capacity > kMinCapacityForPretenure) &&
16471 !isolate->heap()->InNewSpace(*table));
16472 Handle<Derived> new_table = HashTable::New(
16473 isolate,
16474 nof * 2,
16475 USE_DEFAULT_MINIMUM_CAPACITY,
16476 should_pretenure ? TENURED : NOT_TENURED);
16477
16478 table->Rehash(new_table, key);
16479 return new_table;
16480 }
16481
16482 template <typename Derived, typename Shape, typename Key>
HasSufficientCapacityToAdd(int number_of_additional_elements)16483 bool HashTable<Derived, Shape, Key>::HasSufficientCapacityToAdd(
16484 int number_of_additional_elements) {
16485 int capacity = Capacity();
16486 int nof = NumberOfElements() + number_of_additional_elements;
16487 int nod = NumberOfDeletedElements();
16488 // Return true if:
16489 // 50% is still free after adding number_of_additional_elements elements and
16490 // at most 50% of the free elements are deleted elements.
16491 if ((nof < capacity) && ((nod <= (capacity - nof) >> 1))) {
16492 int needed_free = nof >> 1;
16493 if (nof + needed_free <= capacity) return true;
16494 }
16495 return false;
16496 }
16497
16498
16499 template<typename Derived, typename Shape, typename Key>
Shrink(Handle<Derived> table,Key key)16500 Handle<Derived> HashTable<Derived, Shape, Key>::Shrink(Handle<Derived> table,
16501 Key key) {
16502 int capacity = table->Capacity();
16503 int nof = table->NumberOfElements();
16504
16505 // Shrink to fit the number of elements if only a quarter of the
16506 // capacity is filled with elements.
16507 if (nof > (capacity >> 2)) return table;
16508 // Allocate a new dictionary with room for at least the current
16509 // number of elements. The allocation method will make sure that
16510 // there is extra room in the dictionary for additions. Don't go
16511 // lower than room for 16 elements.
16512 int at_least_room_for = nof;
16513 if (at_least_room_for < 16) return table;
16514
16515 Isolate* isolate = table->GetIsolate();
16516 const int kMinCapacityForPretenure = 256;
16517 bool pretenure =
16518 (at_least_room_for > kMinCapacityForPretenure) &&
16519 !isolate->heap()->InNewSpace(*table);
16520 Handle<Derived> new_table = HashTable::New(
16521 isolate,
16522 at_least_room_for,
16523 USE_DEFAULT_MINIMUM_CAPACITY,
16524 pretenure ? TENURED : NOT_TENURED);
16525
16526 table->Rehash(new_table, key);
16527 return new_table;
16528 }
16529
16530
16531 template<typename Derived, typename Shape, typename Key>
FindInsertionEntry(uint32_t hash)16532 uint32_t HashTable<Derived, Shape, Key>::FindInsertionEntry(uint32_t hash) {
16533 uint32_t capacity = Capacity();
16534 uint32_t entry = FirstProbe(hash, capacity);
16535 uint32_t count = 1;
16536 // EnsureCapacity will guarantee the hash table is never full.
16537 Isolate* isolate = GetIsolate();
16538 while (true) {
16539 Object* element = KeyAt(entry);
16540 if (!IsKey(isolate, element)) break;
16541 entry = NextProbe(entry, count++, capacity);
16542 }
16543 return entry;
16544 }
16545
16546
16547 // Force instantiation of template instances class.
16548 // Please note this list is compiler dependent.
16549
16550 template class HashTable<StringTable, StringTableShape, HashTableKey*>;
16551
16552 template class HashTable<CompilationCacheTable,
16553 CompilationCacheShape,
16554 HashTableKey*>;
16555
16556 template class HashTable<ObjectHashTable,
16557 ObjectHashTableShape,
16558 Handle<Object> >;
16559
16560 template class HashTable<WeakHashTable, WeakHashTableShape<2>, Handle<Object> >;
16561
16562 template class Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >;
16563
16564 template class Dictionary<GlobalDictionary, GlobalDictionaryShape,
16565 Handle<Name> >;
16566
16567 template class Dictionary<SeededNumberDictionary,
16568 SeededNumberDictionaryShape,
16569 uint32_t>;
16570
16571 template class Dictionary<UnseededNumberDictionary,
16572 UnseededNumberDictionaryShape,
16573 uint32_t>;
16574
16575 template Handle<SeededNumberDictionary>
16576 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::New(
16577 Isolate*, int at_least_space_for, PretenureFlag pretenure,
16578 MinimumCapacity capacity_option);
16579
16580 template Handle<SeededNumberDictionary>
16581 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
16582 uint32_t>::NewEmpty(Isolate*, PretenureFlag pretenure);
16583
16584 template Handle<UnseededNumberDictionary>
16585 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
16586 uint32_t>::New(Isolate*, int at_least_space_for,
16587 PretenureFlag pretenure,
16588 MinimumCapacity capacity_option);
16589
16590 template Handle<NameDictionary>
16591 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::New(
16592 Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
16593
16594 template Handle<NameDictionary>
16595 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::NewEmpty(
16596 Isolate*, PretenureFlag pretenure);
16597
16598 template Handle<GlobalDictionary>
16599 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::New(
16600 Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
16601
16602 template Handle<SeededNumberDictionary>
16603 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
16604 AtPut(Handle<SeededNumberDictionary>, uint32_t, Handle<Object>);
16605
16606 template Handle<UnseededNumberDictionary>
16607 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
16608 AtPut(Handle<UnseededNumberDictionary>, uint32_t, Handle<Object>);
16609
16610 template Object*
16611 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
16612 SlowReverseLookup(Object* value);
16613
16614 template Object*
16615 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
16616 SlowReverseLookup(Object* value);
16617
16618 template Handle<Object>
16619 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::DeleteProperty(
16620 Handle<NameDictionary>, int);
16621
16622 template Handle<Object>
16623 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
16624 uint32_t>::DeleteProperty(Handle<SeededNumberDictionary>, int);
16625
16626 template Handle<Object>
16627 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
16628 uint32_t>::DeleteProperty(Handle<UnseededNumberDictionary>, int);
16629
16630 template Handle<NameDictionary>
16631 HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
16632 New(Isolate*, int, MinimumCapacity, PretenureFlag);
16633
16634 template Handle<ObjectHashSet> HashTable<ObjectHashSet, ObjectHashSetShape,
16635 Handle<Object>>::New(Isolate*, int n,
16636 MinimumCapacity,
16637 PretenureFlag);
16638
16639 template Handle<NameDictionary>
16640 HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
16641 Shrink(Handle<NameDictionary>, Handle<Name>);
16642
16643 template Handle<SeededNumberDictionary>
16644 HashTable<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
16645 Shrink(Handle<SeededNumberDictionary>, uint32_t);
16646
16647 template Handle<UnseededNumberDictionary>
16648 HashTable<UnseededNumberDictionary, UnseededNumberDictionaryShape,
16649 uint32_t>::Shrink(Handle<UnseededNumberDictionary>, uint32_t);
16650
16651 template Handle<NameDictionary>
16652 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::Add(
16653 Handle<NameDictionary>, Handle<Name>, Handle<Object>, PropertyDetails,
16654 int*);
16655
16656 template Handle<GlobalDictionary>
16657 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::Add(
16658 Handle<GlobalDictionary>, Handle<Name>, Handle<Object>, PropertyDetails,
16659 int*);
16660
16661 template Handle<FixedArray> Dictionary<
16662 NameDictionary, NameDictionaryShape,
16663 Handle<Name> >::GenerateNewEnumerationIndices(Handle<NameDictionary>);
16664
16665 template Handle<SeededNumberDictionary>
16666 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::Add(
16667 Handle<SeededNumberDictionary>, uint32_t, Handle<Object>, PropertyDetails,
16668 int*);
16669
16670 template Handle<UnseededNumberDictionary>
16671 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
16672 uint32_t>::Add(Handle<UnseededNumberDictionary>, uint32_t,
16673 Handle<Object>, PropertyDetails, int*);
16674
16675 template Handle<SeededNumberDictionary>
16676 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
16677 EnsureCapacity(Handle<SeededNumberDictionary>, int, uint32_t);
16678
16679 template Handle<UnseededNumberDictionary>
16680 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
16681 EnsureCapacity(Handle<UnseededNumberDictionary>, int, uint32_t);
16682
16683 template void Dictionary<NameDictionary, NameDictionaryShape,
16684 Handle<Name> >::SetRequiresCopyOnCapacityChange();
16685
16686 template Handle<NameDictionary>
16687 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
16688 EnsureCapacity(Handle<NameDictionary>, int, Handle<Name>);
16689
16690 template int HashTable<SeededNumberDictionary, SeededNumberDictionaryShape,
16691 uint32_t>::FindEntry(uint32_t);
16692
16693 template int NameDictionaryBase<NameDictionary, NameDictionaryShape>::FindEntry(
16694 Handle<Name>);
16695
16696 template int Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
16697 NumberOfElementsFilterAttributes(PropertyFilter filter);
16698
16699 template int Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::
16700 NumberOfElementsFilterAttributes(PropertyFilter filter);
16701
16702 template void
16703 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
16704 CopyEnumKeysTo(Handle<Dictionary<GlobalDictionary, GlobalDictionaryShape,
16705 Handle<Name>>>
16706 dictionary,
16707 Handle<FixedArray> storage, KeyCollectionMode mode,
16708 KeyAccumulator* accumulator);
16709
16710 template void
16711 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::CopyEnumKeysTo(
16712 Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>>
16713 dictionary,
16714 Handle<FixedArray> storage, KeyCollectionMode mode,
16715 KeyAccumulator* accumulator);
16716
16717 template Handle<FixedArray>
16718 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
16719 IterationIndices(
16720 Handle<
16721 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>>
16722 dictionary);
16723 template void
16724 Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
16725 CollectKeysTo(Handle<Dictionary<GlobalDictionary, GlobalDictionaryShape,
16726 Handle<Name>>>
16727 dictionary,
16728 KeyAccumulator* keys);
16729
16730 template Handle<FixedArray>
16731 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::IterationIndices(
16732 Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>>
16733 dictionary);
16734 template void
16735 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::CollectKeysTo(
16736 Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>>
16737 dictionary,
16738 KeyAccumulator* keys);
16739
PrepareSlowElementsForSort(Handle<JSObject> object,uint32_t limit)16740 Handle<Object> JSObject::PrepareSlowElementsForSort(
16741 Handle<JSObject> object, uint32_t limit) {
16742 DCHECK(object->HasDictionaryElements());
16743 Isolate* isolate = object->GetIsolate();
16744 // Must stay in dictionary mode, either because of requires_slow_elements,
16745 // or because we are not going to sort (and therefore compact) all of the
16746 // elements.
16747 Handle<SeededNumberDictionary> dict(object->element_dictionary(), isolate);
16748 Handle<SeededNumberDictionary> new_dict =
16749 SeededNumberDictionary::New(isolate, dict->NumberOfElements());
16750
16751 uint32_t pos = 0;
16752 uint32_t undefs = 0;
16753 int capacity = dict->Capacity();
16754 Handle<Smi> bailout(Smi::FromInt(-1), isolate);
16755 // Entry to the new dictionary does not cause it to grow, as we have
16756 // allocated one that is large enough for all entries.
16757 DisallowHeapAllocation no_gc;
16758 for (int i = 0; i < capacity; i++) {
16759 Object* k = dict->KeyAt(i);
16760 if (!dict->IsKey(isolate, k)) continue;
16761
16762 DCHECK(k->IsNumber());
16763 DCHECK(!k->IsSmi() || Smi::cast(k)->value() >= 0);
16764 DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
16765 DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
16766
16767 HandleScope scope(isolate);
16768 Handle<Object> value(dict->ValueAt(i), isolate);
16769 PropertyDetails details = dict->DetailsAt(i);
16770 if (details.kind() == kAccessor || details.IsReadOnly()) {
16771 // Bail out and do the sorting of undefineds and array holes in JS.
16772 // Also bail out if the element is not supposed to be moved.
16773 return bailout;
16774 }
16775
16776 uint32_t key = NumberToUint32(k);
16777 if (key < limit) {
16778 if (value->IsUndefined(isolate)) {
16779 undefs++;
16780 } else if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
16781 // Adding an entry with the key beyond smi-range requires
16782 // allocation. Bailout.
16783 return bailout;
16784 } else {
16785 Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
16786 new_dict, pos, value, details, object);
16787 DCHECK(result.is_identical_to(new_dict));
16788 USE(result);
16789 pos++;
16790 }
16791 } else if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
16792 // Adding an entry with the key beyond smi-range requires
16793 // allocation. Bailout.
16794 return bailout;
16795 } else {
16796 Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
16797 new_dict, key, value, details, object);
16798 DCHECK(result.is_identical_to(new_dict));
16799 USE(result);
16800 }
16801 }
16802
16803 uint32_t result = pos;
16804 PropertyDetails no_details = PropertyDetails::Empty();
16805 while (undefs > 0) {
16806 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
16807 // Adding an entry with the key beyond smi-range requires
16808 // allocation. Bailout.
16809 return bailout;
16810 }
16811 HandleScope scope(isolate);
16812 Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
16813 new_dict, pos, isolate->factory()->undefined_value(), no_details,
16814 object);
16815 DCHECK(result.is_identical_to(new_dict));
16816 USE(result);
16817 pos++;
16818 undefs--;
16819 }
16820
16821 object->set_elements(*new_dict);
16822
16823 AllowHeapAllocation allocate_return_value;
16824 return isolate->factory()->NewNumberFromUint(result);
16825 }
16826
16827
16828 // Collects all defined (non-hole) and non-undefined (array) elements at
16829 // the start of the elements array.
16830 // If the object is in dictionary mode, it is converted to fast elements
16831 // mode.
PrepareElementsForSort(Handle<JSObject> object,uint32_t limit)16832 Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object,
16833 uint32_t limit) {
16834 Isolate* isolate = object->GetIsolate();
16835 if (object->HasSloppyArgumentsElements() || !object->map()->is_extensible()) {
16836 return handle(Smi::FromInt(-1), isolate);
16837 }
16838
16839 if (object->HasStringWrapperElements()) {
16840 int len = String::cast(Handle<JSValue>::cast(object)->value())->length();
16841 return handle(Smi::FromInt(len), isolate);
16842 }
16843
16844 if (object->HasDictionaryElements()) {
16845 // Convert to fast elements containing only the existing properties.
16846 // Ordering is irrelevant, since we are going to sort anyway.
16847 Handle<SeededNumberDictionary> dict(object->element_dictionary());
16848 if (object->IsJSArray() || dict->requires_slow_elements() ||
16849 dict->max_number_key() >= limit) {
16850 return JSObject::PrepareSlowElementsForSort(object, limit);
16851 }
16852 // Convert to fast elements.
16853
16854 Handle<Map> new_map =
16855 JSObject::GetElementsTransitionMap(object, FAST_HOLEY_ELEMENTS);
16856
16857 PretenureFlag tenure = isolate->heap()->InNewSpace(*object) ?
16858 NOT_TENURED: TENURED;
16859 Handle<FixedArray> fast_elements =
16860 isolate->factory()->NewFixedArray(dict->NumberOfElements(), tenure);
16861 dict->CopyValuesTo(*fast_elements);
16862 JSObject::ValidateElements(object);
16863
16864 JSObject::SetMapAndElements(object, new_map, fast_elements);
16865 } else if (object->HasFixedTypedArrayElements()) {
16866 // Typed arrays cannot have holes or undefined elements.
16867 return handle(Smi::FromInt(
16868 FixedArrayBase::cast(object->elements())->length()), isolate);
16869 } else if (!object->HasFastDoubleElements()) {
16870 EnsureWritableFastElements(object);
16871 }
16872 DCHECK(object->HasFastSmiOrObjectElements() ||
16873 object->HasFastDoubleElements());
16874
16875 // Collect holes at the end, undefined before that and the rest at the
16876 // start, and return the number of non-hole, non-undefined values.
16877
16878 Handle<FixedArrayBase> elements_base(object->elements());
16879 uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
16880 if (limit > elements_length) {
16881 limit = elements_length;
16882 }
16883 if (limit == 0) {
16884 return handle(Smi::kZero, isolate);
16885 }
16886
16887 uint32_t result = 0;
16888 if (elements_base->map() == isolate->heap()->fixed_double_array_map()) {
16889 FixedDoubleArray* elements = FixedDoubleArray::cast(*elements_base);
16890 // Split elements into defined and the_hole, in that order.
16891 unsigned int holes = limit;
16892 // Assume most arrays contain no holes and undefined values, so minimize the
16893 // number of stores of non-undefined, non-the-hole values.
16894 for (unsigned int i = 0; i < holes; i++) {
16895 if (elements->is_the_hole(i)) {
16896 holes--;
16897 } else {
16898 continue;
16899 }
16900 // Position i needs to be filled.
16901 while (holes > i) {
16902 if (elements->is_the_hole(holes)) {
16903 holes--;
16904 } else {
16905 elements->set(i, elements->get_scalar(holes));
16906 break;
16907 }
16908 }
16909 }
16910 result = holes;
16911 while (holes < limit) {
16912 elements->set_the_hole(holes);
16913 holes++;
16914 }
16915 } else {
16916 FixedArray* elements = FixedArray::cast(*elements_base);
16917 DisallowHeapAllocation no_gc;
16918
16919 // Split elements into defined, undefined and the_hole, in that order. Only
16920 // count locations for undefined and the hole, and fill them afterwards.
16921 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_gc);
16922 unsigned int undefs = limit;
16923 unsigned int holes = limit;
16924 // Assume most arrays contain no holes and undefined values, so minimize the
16925 // number of stores of non-undefined, non-the-hole values.
16926 for (unsigned int i = 0; i < undefs; i++) {
16927 Object* current = elements->get(i);
16928 if (current->IsTheHole(isolate)) {
16929 holes--;
16930 undefs--;
16931 } else if (current->IsUndefined(isolate)) {
16932 undefs--;
16933 } else {
16934 continue;
16935 }
16936 // Position i needs to be filled.
16937 while (undefs > i) {
16938 current = elements->get(undefs);
16939 if (current->IsTheHole(isolate)) {
16940 holes--;
16941 undefs--;
16942 } else if (current->IsUndefined(isolate)) {
16943 undefs--;
16944 } else {
16945 elements->set(i, current, write_barrier);
16946 break;
16947 }
16948 }
16949 }
16950 result = undefs;
16951 while (undefs < holes) {
16952 elements->set_undefined(isolate, undefs);
16953 undefs++;
16954 }
16955 while (holes < limit) {
16956 elements->set_the_hole(isolate, holes);
16957 holes++;
16958 }
16959 }
16960
16961 return isolate->factory()->NewNumberFromUint(result);
16962 }
16963
16964 namespace {
16965
CanonicalNumericIndexString(Isolate * isolate,Handle<Object> s,Handle<Object> * index)16966 bool CanonicalNumericIndexString(Isolate* isolate, Handle<Object> s,
16967 Handle<Object>* index) {
16968 DCHECK(s->IsString() || s->IsSmi());
16969
16970 Handle<Object> result;
16971 if (s->IsSmi()) {
16972 result = s;
16973 } else {
16974 result = String::ToNumber(Handle<String>::cast(s));
16975 if (!result->IsMinusZero()) {
16976 Handle<String> str = Object::ToString(isolate, result).ToHandleChecked();
16977 // Avoid treating strings like "2E1" and "20" as the same key.
16978 if (!str->SameValue(*s)) return false;
16979 }
16980 }
16981 *index = result;
16982 return true;
16983 }
16984
16985 } // anonymous namespace
16986
16987 // ES#sec-integer-indexed-exotic-objects-defineownproperty-p-desc
16988 // static
DefineOwnProperty(Isolate * isolate,Handle<JSTypedArray> o,Handle<Object> key,PropertyDescriptor * desc,ShouldThrow should_throw)16989 Maybe<bool> JSTypedArray::DefineOwnProperty(Isolate* isolate,
16990 Handle<JSTypedArray> o,
16991 Handle<Object> key,
16992 PropertyDescriptor* desc,
16993 ShouldThrow should_throw) {
16994 // 1. Assert: IsPropertyKey(P) is true.
16995 DCHECK(key->IsName() || key->IsNumber());
16996 // 2. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot.
16997 // 3. If Type(P) is String, then
16998 if (key->IsString() || key->IsSmi()) {
16999 // 3a. Let numericIndex be ! CanonicalNumericIndexString(P)
17000 // 3b. If numericIndex is not undefined, then
17001 Handle<Object> numeric_index;
17002 if (CanonicalNumericIndexString(isolate, key, &numeric_index)) {
17003 // 3b i. If IsInteger(numericIndex) is false, return false.
17004 // 3b ii. If numericIndex = -0, return false.
17005 // 3b iii. If numericIndex < 0, return false.
17006 // FIXME: the standard allows up to 2^53 elements.
17007 uint32_t index;
17008 if (numeric_index->IsMinusZero() || !numeric_index->ToUint32(&index)) {
17009 RETURN_FAILURE(isolate, should_throw,
17010 NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
17011 }
17012 // 3b iv. Let length be O.[[ArrayLength]].
17013 uint32_t length = o->length()->Number();
17014 // 3b v. If numericIndex ≥ length, return false.
17015 if (index >= length) {
17016 RETURN_FAILURE(isolate, should_throw,
17017 NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
17018 }
17019 // 3b vi. If IsAccessorDescriptor(Desc) is true, return false.
17020 if (PropertyDescriptor::IsAccessorDescriptor(desc)) {
17021 RETURN_FAILURE(isolate, should_throw,
17022 NewTypeError(MessageTemplate::kRedefineDisallowed, key));
17023 }
17024 // 3b vii. If Desc has a [[Configurable]] field and if
17025 // Desc.[[Configurable]] is true, return false.
17026 // 3b viii. If Desc has an [[Enumerable]] field and if Desc.[[Enumerable]]
17027 // is false, return false.
17028 // 3b ix. If Desc has a [[Writable]] field and if Desc.[[Writable]] is
17029 // false, return false.
17030 if ((desc->has_configurable() && desc->configurable()) ||
17031 (desc->has_enumerable() && !desc->enumerable()) ||
17032 (desc->has_writable() && !desc->writable())) {
17033 RETURN_FAILURE(isolate, should_throw,
17034 NewTypeError(MessageTemplate::kRedefineDisallowed, key));
17035 }
17036 // 3b x. If Desc has a [[Value]] field, then
17037 // 3b x 1. Let value be Desc.[[Value]].
17038 // 3b x 2. Return ? IntegerIndexedElementSet(O, numericIndex, value).
17039 if (desc->has_value()) {
17040 if (!desc->has_configurable()) desc->set_configurable(false);
17041 if (!desc->has_enumerable()) desc->set_enumerable(true);
17042 if (!desc->has_writable()) desc->set_writable(true);
17043 Handle<Object> value = desc->value();
17044 RETURN_ON_EXCEPTION_VALUE(isolate,
17045 SetOwnElementIgnoreAttributes(
17046 o, index, value, desc->ToAttributes()),
17047 Nothing<bool>());
17048 }
17049 // 3b xi. Return true.
17050 return Just(true);
17051 }
17052 }
17053 // 4. Return ! OrdinaryDefineOwnProperty(O, P, Desc).
17054 return OrdinaryDefineOwnProperty(isolate, o, key, desc, should_throw);
17055 }
17056
type()17057 ExternalArrayType JSTypedArray::type() {
17058 switch (elements()->map()->instance_type()) {
17059 #define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype, size) \
17060 case FIXED_##TYPE##_ARRAY_TYPE: \
17061 return kExternal##Type##Array;
17062
17063 TYPED_ARRAYS(INSTANCE_TYPE_TO_ARRAY_TYPE)
17064 #undef INSTANCE_TYPE_TO_ARRAY_TYPE
17065
17066 default:
17067 UNREACHABLE();
17068 return static_cast<ExternalArrayType>(-1);
17069 }
17070 }
17071
17072
element_size()17073 size_t JSTypedArray::element_size() {
17074 switch (elements()->map()->instance_type()) {
17075 #define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype, size) \
17076 case FIXED_##TYPE##_ARRAY_TYPE: \
17077 return size;
17078
17079 TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE)
17080 #undef INSTANCE_TYPE_TO_ELEMENT_SIZE
17081
17082 default:
17083 UNREACHABLE();
17084 return 0;
17085 }
17086 }
17087
17088
InvalidatePropertyCell(Handle<JSGlobalObject> global,Handle<Name> name)17089 void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global,
17090 Handle<Name> name) {
17091 DCHECK(!global->HasFastProperties());
17092 auto dictionary = handle(global->global_dictionary());
17093 int entry = dictionary->FindEntry(name);
17094 if (entry == GlobalDictionary::kNotFound) return;
17095 PropertyCell::InvalidateEntry(dictionary, entry);
17096 }
17097
EnsureEmptyPropertyCell(Handle<JSGlobalObject> global,Handle<Name> name,PropertyCellType cell_type,int * entry_out)17098 Handle<PropertyCell> JSGlobalObject::EnsureEmptyPropertyCell(
17099 Handle<JSGlobalObject> global, Handle<Name> name,
17100 PropertyCellType cell_type, int* entry_out) {
17101 Isolate* isolate = global->GetIsolate();
17102 DCHECK(!global->HasFastProperties());
17103 Handle<GlobalDictionary> dictionary(global->global_dictionary(), isolate);
17104 int entry = dictionary->FindEntry(name);
17105 Handle<PropertyCell> cell;
17106 if (entry != GlobalDictionary::kNotFound) {
17107 if (entry_out) *entry_out = entry;
17108 // This call should be idempotent.
17109 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
17110 cell = handle(PropertyCell::cast(dictionary->ValueAt(entry)));
17111 PropertyCellType original_cell_type = cell->property_details().cell_type();
17112 DCHECK(original_cell_type == PropertyCellType::kInvalidated ||
17113 original_cell_type == PropertyCellType::kUninitialized);
17114 DCHECK(cell->value()->IsTheHole(isolate));
17115 if (original_cell_type == PropertyCellType::kInvalidated) {
17116 cell = PropertyCell::InvalidateEntry(dictionary, entry);
17117 }
17118 PropertyDetails details(kData, NONE, 0, cell_type);
17119 cell->set_property_details(details);
17120 return cell;
17121 }
17122 cell = isolate->factory()->NewPropertyCell();
17123 PropertyDetails details(kData, NONE, 0, cell_type);
17124 dictionary =
17125 GlobalDictionary::Add(dictionary, name, cell, details, entry_out);
17126 // {*entry_out} is initialized inside GlobalDictionary::Add().
17127 global->set_properties(*dictionary);
17128 return cell;
17129 }
17130
17131
17132 // This class is used for looking up two character strings in the string table.
17133 // If we don't have a hit we don't want to waste much time so we unroll the
17134 // string hash calculation loop here for speed. Doesn't work if the two
17135 // characters form a decimal integer, since such strings have a different hash
17136 // algorithm.
17137 class TwoCharHashTableKey : public HashTableKey {
17138 public:
TwoCharHashTableKey(uint16_t c1,uint16_t c2,uint32_t seed)17139 TwoCharHashTableKey(uint16_t c1, uint16_t c2, uint32_t seed)
17140 : c1_(c1), c2_(c2) {
17141 // Char 1.
17142 uint32_t hash = seed;
17143 hash += c1;
17144 hash += hash << 10;
17145 hash ^= hash >> 6;
17146 // Char 2.
17147 hash += c2;
17148 hash += hash << 10;
17149 hash ^= hash >> 6;
17150 // GetHash.
17151 hash += hash << 3;
17152 hash ^= hash >> 11;
17153 hash += hash << 15;
17154 if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash;
17155 hash_ = hash;
17156 #ifdef DEBUG
17157 // If this assert fails then we failed to reproduce the two-character
17158 // version of the string hashing algorithm above. One reason could be
17159 // that we were passed two digits as characters, since the hash
17160 // algorithm is different in that case.
17161 uint16_t chars[2] = {c1, c2};
17162 uint32_t check_hash = StringHasher::HashSequentialString(chars, 2, seed);
17163 hash = (hash << String::kHashShift) | String::kIsNotArrayIndexMask;
17164 DCHECK_EQ(static_cast<int32_t>(hash), static_cast<int32_t>(check_hash));
17165 #endif
17166 }
17167
IsMatch(Object * o)17168 bool IsMatch(Object* o) override {
17169 if (!o->IsString()) return false;
17170 String* other = String::cast(o);
17171 if (other->length() != 2) return false;
17172 if (other->Get(0) != c1_) return false;
17173 return other->Get(1) == c2_;
17174 }
17175
Hash()17176 uint32_t Hash() override { return hash_; }
HashForObject(Object * key)17177 uint32_t HashForObject(Object* key) override {
17178 if (!key->IsString()) return 0;
17179 return String::cast(key)->Hash();
17180 }
17181
AsHandle(Isolate * isolate)17182 Handle<Object> AsHandle(Isolate* isolate) override {
17183 // The TwoCharHashTableKey is only used for looking in the string
17184 // table, not for adding to it.
17185 UNREACHABLE();
17186 return MaybeHandle<Object>().ToHandleChecked();
17187 }
17188
17189 private:
17190 uint16_t c1_;
17191 uint16_t c2_;
17192 uint32_t hash_;
17193 };
17194
17195
InternalizeStringIfExists(Isolate * isolate,Handle<String> string)17196 MaybeHandle<String> StringTable::InternalizeStringIfExists(
17197 Isolate* isolate,
17198 Handle<String> string) {
17199 if (string->IsInternalizedString()) {
17200 return string;
17201 }
17202 if (string->IsThinString()) {
17203 return handle(Handle<ThinString>::cast(string)->actual(), isolate);
17204 }
17205 return LookupStringIfExists(isolate, string);
17206 }
17207
17208
LookupStringIfExists(Isolate * isolate,Handle<String> string)17209 MaybeHandle<String> StringTable::LookupStringIfExists(
17210 Isolate* isolate,
17211 Handle<String> string) {
17212 Handle<StringTable> string_table = isolate->factory()->string_table();
17213 InternalizedStringKey key(string);
17214 int entry = string_table->FindEntry(&key);
17215 if (entry == kNotFound) {
17216 return MaybeHandle<String>();
17217 } else {
17218 Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
17219 DCHECK(StringShape(*result).IsInternalized());
17220 return result;
17221 }
17222 }
17223
17224
LookupTwoCharsStringIfExists(Isolate * isolate,uint16_t c1,uint16_t c2)17225 MaybeHandle<String> StringTable::LookupTwoCharsStringIfExists(
17226 Isolate* isolate,
17227 uint16_t c1,
17228 uint16_t c2) {
17229 Handle<StringTable> string_table = isolate->factory()->string_table();
17230 TwoCharHashTableKey key(c1, c2, isolate->heap()->HashSeed());
17231 int entry = string_table->FindEntry(&key);
17232 if (entry == kNotFound) {
17233 return MaybeHandle<String>();
17234 } else {
17235 Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
17236 DCHECK(StringShape(*result).IsInternalized());
17237 return result;
17238 }
17239 }
17240
17241
EnsureCapacityForDeserialization(Isolate * isolate,int expected)17242 void StringTable::EnsureCapacityForDeserialization(Isolate* isolate,
17243 int expected) {
17244 Handle<StringTable> table = isolate->factory()->string_table();
17245 // We need a key instance for the virtual hash function.
17246 InternalizedStringKey dummy_key(isolate->factory()->empty_string());
17247 table = StringTable::EnsureCapacity(table, expected, &dummy_key);
17248 isolate->heap()->SetRootStringTable(*table);
17249 }
17250
17251 namespace {
17252
17253 template <class StringClass>
MigrateExternalStringResource(Isolate * isolate,Handle<String> from,Handle<String> to)17254 void MigrateExternalStringResource(Isolate* isolate, Handle<String> from,
17255 Handle<String> to) {
17256 Handle<StringClass> cast_from = Handle<StringClass>::cast(from);
17257 Handle<StringClass> cast_to = Handle<StringClass>::cast(to);
17258 const typename StringClass::Resource* to_resource = cast_to->resource();
17259 if (to_resource == nullptr) {
17260 // |to| is a just-created internalized copy of |from|. Migrate the resource.
17261 cast_to->set_resource(cast_from->resource());
17262 // Zap |from|'s resource pointer to reflect the fact that |from| has
17263 // relinquished ownership of its resource.
17264 cast_from->set_resource(nullptr);
17265 } else if (to_resource != cast_from->resource()) {
17266 // |to| already existed and has its own resource. Finalize |from|.
17267 isolate->heap()->FinalizeExternalString(*from);
17268 }
17269 }
17270
17271 } // namespace
17272
LookupString(Isolate * isolate,Handle<String> string)17273 Handle<String> StringTable::LookupString(Isolate* isolate,
17274 Handle<String> string) {
17275 if (string->IsThinString()) {
17276 DCHECK(Handle<ThinString>::cast(string)->actual()->IsInternalizedString());
17277 return handle(Handle<ThinString>::cast(string)->actual(), isolate);
17278 }
17279 if (string->IsConsString() && string->IsFlat()) {
17280 string = handle(Handle<ConsString>::cast(string)->first(), isolate);
17281 if (string->IsInternalizedString()) return string;
17282 }
17283
17284 InternalizedStringKey key(string);
17285 Handle<String> result = LookupKey(isolate, &key);
17286
17287 if (FLAG_thin_strings) {
17288 if (string->IsExternalString()) {
17289 if (result->IsExternalOneByteString()) {
17290 MigrateExternalStringResource<ExternalOneByteString>(isolate, string,
17291 result);
17292 } else if (result->IsExternalTwoByteString()) {
17293 MigrateExternalStringResource<ExternalTwoByteString>(isolate, string,
17294 result);
17295 } else {
17296 // If the external string is duped into an existing non-external
17297 // internalized string, free its resource (it's about to be rewritten
17298 // into a ThinString below).
17299 isolate->heap()->FinalizeExternalString(*string);
17300 }
17301 }
17302
17303 // The LookupKey() call above tries to internalize the string in-place.
17304 // In cases where that wasn't possible (e.g. new-space strings), turn them
17305 // into ThinStrings referring to their internalized versions now.
17306 if (!string->IsInternalizedString()) {
17307 DisallowHeapAllocation no_gc;
17308 bool one_byte = result->IsOneByteRepresentation();
17309 Handle<Map> map = one_byte
17310 ? isolate->factory()->thin_one_byte_string_map()
17311 : isolate->factory()->thin_string_map();
17312 int old_size = string->Size();
17313 DCHECK(old_size >= ThinString::kSize);
17314 string->synchronized_set_map(*map);
17315 Handle<ThinString> thin = Handle<ThinString>::cast(string);
17316 thin->set_actual(*result);
17317 Address thin_end = thin->address() + ThinString::kSize;
17318 int size_delta = old_size - ThinString::kSize;
17319 if (size_delta != 0) {
17320 Heap* heap = isolate->heap();
17321 heap->CreateFillerObjectAt(thin_end, size_delta,
17322 ClearRecordedSlots::kNo);
17323 heap->AdjustLiveBytes(*thin, -size_delta);
17324 }
17325 }
17326 } else { // !FLAG_thin_strings
17327 if (string->IsConsString()) {
17328 Handle<ConsString> cons = Handle<ConsString>::cast(string);
17329 cons->set_first(*result);
17330 cons->set_second(isolate->heap()->empty_string());
17331 } else if (string->IsSlicedString()) {
17332 STATIC_ASSERT(ConsString::kSize == SlicedString::kSize);
17333 DisallowHeapAllocation no_gc;
17334 bool one_byte = result->IsOneByteRepresentation();
17335 Handle<Map> map = one_byte
17336 ? isolate->factory()->cons_one_byte_string_map()
17337 : isolate->factory()->cons_string_map();
17338 string->set_map(*map);
17339 Handle<ConsString> cons = Handle<ConsString>::cast(string);
17340 cons->set_first(*result);
17341 cons->set_second(isolate->heap()->empty_string());
17342 }
17343 }
17344 return result;
17345 }
17346
17347
LookupKey(Isolate * isolate,HashTableKey * key)17348 Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) {
17349 Handle<StringTable> table = isolate->factory()->string_table();
17350 int entry = table->FindEntry(key);
17351
17352 // String already in table.
17353 if (entry != kNotFound) {
17354 return handle(String::cast(table->KeyAt(entry)), isolate);
17355 }
17356
17357 // Adding new string. Grow table if needed.
17358 table = StringTable::EnsureCapacity(table, 1, key);
17359
17360 // Create string object.
17361 Handle<Object> string = key->AsHandle(isolate);
17362 // There must be no attempts to internalize strings that could throw
17363 // InvalidStringLength error.
17364 CHECK(!string.is_null());
17365
17366 // Add the new string and return it along with the string table.
17367 entry = table->FindInsertionEntry(key->Hash());
17368 table->set(EntryToIndex(entry), *string);
17369 table->ElementAdded();
17370
17371 isolate->heap()->SetRootStringTable(*table);
17372 return Handle<String>::cast(string);
17373 }
17374
17375
LookupKeyIfExists(Isolate * isolate,HashTableKey * key)17376 String* StringTable::LookupKeyIfExists(Isolate* isolate, HashTableKey* key) {
17377 Handle<StringTable> table = isolate->factory()->string_table();
17378 int entry = table->FindEntry(key);
17379 if (entry != kNotFound) return String::cast(table->KeyAt(entry));
17380 return NULL;
17381 }
17382
New(Isolate * isolate)17383 Handle<StringSet> StringSet::New(Isolate* isolate) {
17384 return HashTable::New(isolate, 0);
17385 }
17386
Add(Handle<StringSet> stringset,Handle<String> name)17387 Handle<StringSet> StringSet::Add(Handle<StringSet> stringset,
17388 Handle<String> name) {
17389 if (!stringset->Has(name)) {
17390 stringset = EnsureCapacity(stringset, 1, *name);
17391 uint32_t hash = StringSetShape::Hash(*name);
17392 int entry = stringset->FindInsertionEntry(hash);
17393 stringset->set(EntryToIndex(entry), *name);
17394 stringset->ElementAdded();
17395 }
17396 return stringset;
17397 }
17398
Has(Handle<String> name)17399 bool StringSet::Has(Handle<String> name) {
17400 return FindEntry(*name) != kNotFound;
17401 }
17402
Add(Handle<ObjectHashSet> set,Handle<Object> key)17403 Handle<ObjectHashSet> ObjectHashSet::Add(Handle<ObjectHashSet> set,
17404 Handle<Object> key) {
17405 Isolate* isolate = set->GetIsolate();
17406 int32_t hash = Object::GetOrCreateHash(isolate, key)->value();
17407
17408 if (!set->Has(isolate, key, hash)) {
17409 set = EnsureCapacity(set, 1, key);
17410 int entry = set->FindInsertionEntry(hash);
17411 set->set(EntryToIndex(entry), *key);
17412 set->ElementAdded();
17413 }
17414 return set;
17415 }
17416
Lookup(Handle<String> src,Handle<Context> context,LanguageMode language_mode)17417 Handle<Object> CompilationCacheTable::Lookup(Handle<String> src,
17418 Handle<Context> context,
17419 LanguageMode language_mode) {
17420 Isolate* isolate = GetIsolate();
17421 Handle<SharedFunctionInfo> shared(context->closure()->shared());
17422 StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17423 int entry = FindEntry(&key);
17424 if (entry == kNotFound) return isolate->factory()->undefined_value();
17425 int index = EntryToIndex(entry);
17426 if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value();
17427 return Handle<Object>(get(index + 1), isolate);
17428 }
17429
17430 namespace {
17431
17432 const int kLiteralEntryLength = 2;
17433 const int kLiteralInitialLength = 2;
17434 const int kLiteralContextOffset = 0;
17435 const int kLiteralLiteralsOffset = 1;
17436
SearchLiteralsMapEntry(CompilationCacheTable * cache,int cache_entry,Context * native_context)17437 int SearchLiteralsMapEntry(CompilationCacheTable* cache, int cache_entry,
17438 Context* native_context) {
17439 DisallowHeapAllocation no_gc;
17440 DCHECK(native_context->IsNativeContext());
17441 Object* obj = cache->get(cache_entry);
17442
17443 if (obj->IsFixedArray()) {
17444 FixedArray* literals_map = FixedArray::cast(obj);
17445 int length = literals_map->length();
17446 for (int i = 0; i < length; i += kLiteralEntryLength) {
17447 if (WeakCell::cast(literals_map->get(i + kLiteralContextOffset))
17448 ->value() == native_context) {
17449 return i;
17450 }
17451 }
17452 }
17453 return -1;
17454 }
17455
AddToLiteralsMap(Handle<CompilationCacheTable> cache,int cache_entry,Handle<Context> native_context,Handle<Cell> literals)17456 void AddToLiteralsMap(Handle<CompilationCacheTable> cache, int cache_entry,
17457 Handle<Context> native_context, Handle<Cell> literals) {
17458 Isolate* isolate = native_context->GetIsolate();
17459 DCHECK(native_context->IsNativeContext());
17460 STATIC_ASSERT(kLiteralEntryLength == 2);
17461 Handle<FixedArray> new_literals_map;
17462 int entry;
17463
17464 Object* obj = cache->get(cache_entry);
17465
17466 if (!obj->IsFixedArray() || FixedArray::cast(obj)->length() == 0) {
17467 new_literals_map =
17468 isolate->factory()->NewFixedArray(kLiteralInitialLength, TENURED);
17469 entry = 0;
17470 } else {
17471 Handle<FixedArray> old_literals_map(FixedArray::cast(obj), isolate);
17472 entry = SearchLiteralsMapEntry(*cache, cache_entry, *native_context);
17473 if (entry >= 0) {
17474 // Just set the code of the entry.
17475 Handle<WeakCell> literals_cell =
17476 isolate->factory()->NewWeakCell(literals);
17477 old_literals_map->set(entry + kLiteralLiteralsOffset, *literals_cell);
17478 return;
17479 }
17480
17481 // Can we reuse an entry?
17482 DCHECK(entry < 0);
17483 int length = old_literals_map->length();
17484 for (int i = 0; i < length; i += kLiteralEntryLength) {
17485 if (WeakCell::cast(old_literals_map->get(i + kLiteralContextOffset))
17486 ->cleared()) {
17487 new_literals_map = old_literals_map;
17488 entry = i;
17489 break;
17490 }
17491 }
17492
17493 if (entry < 0) {
17494 // Copy old optimized code map and append one new entry.
17495 new_literals_map = isolate->factory()->CopyFixedArrayAndGrow(
17496 old_literals_map, kLiteralEntryLength, TENURED);
17497 entry = old_literals_map->length();
17498 }
17499 }
17500
17501 Handle<WeakCell> literals_cell = isolate->factory()->NewWeakCell(literals);
17502 WeakCell* context_cell = native_context->self_weak_cell();
17503
17504 new_literals_map->set(entry + kLiteralContextOffset, context_cell);
17505 new_literals_map->set(entry + kLiteralLiteralsOffset, *literals_cell);
17506
17507 #ifdef DEBUG
17508 for (int i = 0; i < new_literals_map->length(); i += kLiteralEntryLength) {
17509 WeakCell* cell =
17510 WeakCell::cast(new_literals_map->get(i + kLiteralContextOffset));
17511 DCHECK(cell->cleared() || cell->value()->IsNativeContext());
17512 cell = WeakCell::cast(new_literals_map->get(i + kLiteralLiteralsOffset));
17513 DCHECK(cell->cleared() || (cell->value()->IsCell()));
17514 }
17515 #endif
17516
17517 Object* old_literals_map = cache->get(cache_entry);
17518 if (old_literals_map != *new_literals_map) {
17519 cache->set(cache_entry, *new_literals_map);
17520 }
17521 }
17522
SearchLiteralsMap(CompilationCacheTable * cache,int cache_entry,Context * native_context)17523 Cell* SearchLiteralsMap(CompilationCacheTable* cache, int cache_entry,
17524 Context* native_context) {
17525 Cell* result = nullptr;
17526 int entry = SearchLiteralsMapEntry(cache, cache_entry, native_context);
17527 if (entry >= 0) {
17528 FixedArray* literals_map = FixedArray::cast(cache->get(cache_entry));
17529 DCHECK_LE(entry + kLiteralEntryLength, literals_map->length());
17530 WeakCell* cell =
17531 WeakCell::cast(literals_map->get(entry + kLiteralLiteralsOffset));
17532
17533 result = cell->cleared() ? nullptr : Cell::cast(cell->value());
17534 }
17535 DCHECK(result == nullptr || result->IsCell());
17536 return result;
17537 }
17538
17539 } // namespace
17540
LookupScript(Handle<String> src,Handle<Context> context,LanguageMode language_mode)17541 InfoVectorPair CompilationCacheTable::LookupScript(Handle<String> src,
17542 Handle<Context> context,
17543 LanguageMode language_mode) {
17544 InfoVectorPair empty_result;
17545 Handle<SharedFunctionInfo> shared(context->closure()->shared());
17546 StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17547 int entry = FindEntry(&key);
17548 if (entry == kNotFound) return empty_result;
17549 int index = EntryToIndex(entry);
17550 if (!get(index)->IsFixedArray()) return empty_result;
17551 Object* obj = get(index + 1);
17552 if (obj->IsSharedFunctionInfo()) {
17553 Cell* literals =
17554 SearchLiteralsMap(this, index + 2, context->native_context());
17555 return InfoVectorPair(SharedFunctionInfo::cast(obj), literals);
17556 }
17557 return empty_result;
17558 }
17559
LookupEval(Handle<String> src,Handle<SharedFunctionInfo> outer_info,Handle<Context> native_context,LanguageMode language_mode,int position)17560 InfoVectorPair CompilationCacheTable::LookupEval(
17561 Handle<String> src, Handle<SharedFunctionInfo> outer_info,
17562 Handle<Context> native_context, LanguageMode language_mode, int position) {
17563 InfoVectorPair empty_result;
17564 StringSharedKey key(src, outer_info, language_mode, position);
17565 int entry = FindEntry(&key);
17566 if (entry == kNotFound) return empty_result;
17567 int index = EntryToIndex(entry);
17568 if (!get(index)->IsFixedArray()) return empty_result;
17569 Object* obj = get(EntryToIndex(entry) + 1);
17570 if (obj->IsSharedFunctionInfo()) {
17571 Cell* literals =
17572 SearchLiteralsMap(this, EntryToIndex(entry) + 2, *native_context);
17573 return InfoVectorPair(SharedFunctionInfo::cast(obj), literals);
17574 }
17575 return empty_result;
17576 }
17577
LookupRegExp(Handle<String> src,JSRegExp::Flags flags)17578 Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src,
17579 JSRegExp::Flags flags) {
17580 Isolate* isolate = GetIsolate();
17581 DisallowHeapAllocation no_allocation;
17582 RegExpKey key(src, flags);
17583 int entry = FindEntry(&key);
17584 if (entry == kNotFound) return isolate->factory()->undefined_value();
17585 return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
17586 }
17587
17588
Put(Handle<CompilationCacheTable> cache,Handle<String> src,Handle<Context> context,LanguageMode language_mode,Handle<Object> value)17589 Handle<CompilationCacheTable> CompilationCacheTable::Put(
17590 Handle<CompilationCacheTable> cache, Handle<String> src,
17591 Handle<Context> context, LanguageMode language_mode, Handle<Object> value) {
17592 Isolate* isolate = cache->GetIsolate();
17593 Handle<SharedFunctionInfo> shared(context->closure()->shared());
17594 StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17595 Handle<Object> k = key.AsHandle(isolate);
17596 cache = EnsureCapacity(cache, 1, &key);
17597 int entry = cache->FindInsertionEntry(key.Hash());
17598 cache->set(EntryToIndex(entry), *k);
17599 cache->set(EntryToIndex(entry) + 1, *value);
17600 cache->ElementAdded();
17601 return cache;
17602 }
17603
PutScript(Handle<CompilationCacheTable> cache,Handle<String> src,Handle<Context> context,LanguageMode language_mode,Handle<SharedFunctionInfo> value,Handle<Cell> literals)17604 Handle<CompilationCacheTable> CompilationCacheTable::PutScript(
17605 Handle<CompilationCacheTable> cache, Handle<String> src,
17606 Handle<Context> context, LanguageMode language_mode,
17607 Handle<SharedFunctionInfo> value, Handle<Cell> literals) {
17608 Isolate* isolate = cache->GetIsolate();
17609 Handle<SharedFunctionInfo> shared(context->closure()->shared());
17610 Handle<Context> native_context(context->native_context());
17611 StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
17612 Handle<Object> k = key.AsHandle(isolate);
17613 cache = EnsureCapacity(cache, 1, &key);
17614 int entry = cache->FindInsertionEntry(key.Hash());
17615 cache->set(EntryToIndex(entry), *k);
17616 cache->set(EntryToIndex(entry) + 1, *value);
17617 AddToLiteralsMap(cache, EntryToIndex(entry) + 2, native_context, literals);
17618 cache->ElementAdded();
17619 return cache;
17620 }
17621
PutEval(Handle<CompilationCacheTable> cache,Handle<String> src,Handle<SharedFunctionInfo> outer_info,Handle<SharedFunctionInfo> value,Handle<Context> native_context,Handle<Cell> literals,int position)17622 Handle<CompilationCacheTable> CompilationCacheTable::PutEval(
17623 Handle<CompilationCacheTable> cache, Handle<String> src,
17624 Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value,
17625 Handle<Context> native_context, Handle<Cell> literals, int position) {
17626 Isolate* isolate = cache->GetIsolate();
17627 StringSharedKey key(src, outer_info, value->language_mode(), position);
17628 {
17629 Handle<Object> k = key.AsHandle(isolate);
17630 int entry = cache->FindEntry(&key);
17631 if (entry != kNotFound) {
17632 cache->set(EntryToIndex(entry), *k);
17633 cache->set(EntryToIndex(entry) + 1, *value);
17634 // AddToLiteralsMap may allocate a new sub-array to live in the entry,
17635 // but it won't change the cache array. Therefore EntryToIndex and
17636 // entry remains correct.
17637 AddToLiteralsMap(cache, EntryToIndex(entry) + 2, native_context,
17638 literals);
17639 return cache;
17640 }
17641 }
17642
17643 cache = EnsureCapacity(cache, 1, &key);
17644 int entry = cache->FindInsertionEntry(key.Hash());
17645 Handle<Object> k =
17646 isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
17647 cache->set(EntryToIndex(entry), *k);
17648 cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
17649 cache->ElementAdded();
17650 return cache;
17651 }
17652
17653
PutRegExp(Handle<CompilationCacheTable> cache,Handle<String> src,JSRegExp::Flags flags,Handle<FixedArray> value)17654 Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp(
17655 Handle<CompilationCacheTable> cache, Handle<String> src,
17656 JSRegExp::Flags flags, Handle<FixedArray> value) {
17657 RegExpKey key(src, flags);
17658 cache = EnsureCapacity(cache, 1, &key);
17659 int entry = cache->FindInsertionEntry(key.Hash());
17660 // We store the value in the key slot, and compare the search key
17661 // to the stored value with a custon IsMatch function during lookups.
17662 cache->set(EntryToIndex(entry), *value);
17663 cache->set(EntryToIndex(entry) + 1, *value);
17664 cache->ElementAdded();
17665 return cache;
17666 }
17667
17668
Age()17669 void CompilationCacheTable::Age() {
17670 DisallowHeapAllocation no_allocation;
17671 Object* the_hole_value = GetHeap()->the_hole_value();
17672 for (int entry = 0, size = Capacity(); entry < size; entry++) {
17673 int entry_index = EntryToIndex(entry);
17674 int value_index = entry_index + 1;
17675
17676 if (get(entry_index)->IsNumber()) {
17677 Smi* count = Smi::cast(get(value_index));
17678 count = Smi::FromInt(count->value() - 1);
17679 if (count->value() == 0) {
17680 NoWriteBarrierSet(this, entry_index, the_hole_value);
17681 NoWriteBarrierSet(this, value_index, the_hole_value);
17682 ElementRemoved();
17683 } else {
17684 NoWriteBarrierSet(this, value_index, count);
17685 }
17686 } else if (get(entry_index)->IsFixedArray()) {
17687 SharedFunctionInfo* info = SharedFunctionInfo::cast(get(value_index));
17688 bool is_old =
17689 info->IsInterpreted()
17690 ? info->bytecode_array()->IsOld()
17691 : info->code()->kind() != Code::FUNCTION || info->code()->IsOld();
17692 if (is_old) {
17693 for (int i = 0; i < kEntrySize; i++) {
17694 NoWriteBarrierSet(this, entry_index + i, the_hole_value);
17695 }
17696 ElementRemoved();
17697 }
17698 }
17699 }
17700 }
17701
17702
Remove(Object * value)17703 void CompilationCacheTable::Remove(Object* value) {
17704 DisallowHeapAllocation no_allocation;
17705 Object* the_hole_value = GetHeap()->the_hole_value();
17706 for (int entry = 0, size = Capacity(); entry < size; entry++) {
17707 int entry_index = EntryToIndex(entry);
17708 int value_index = entry_index + 1;
17709 if (get(value_index) == value) {
17710 for (int i = 0; i < kEntrySize; i++) {
17711 NoWriteBarrierSet(this, entry_index + i, the_hole_value);
17712 }
17713 ElementRemoved();
17714 }
17715 }
17716 return;
17717 }
17718
17719 template <typename Derived, typename Shape, typename Key>
New(Isolate * isolate,int at_least_space_for,PretenureFlag pretenure,MinimumCapacity capacity_option)17720 Handle<Derived> Dictionary<Derived, Shape, Key>::New(
17721 Isolate* isolate, int at_least_space_for, PretenureFlag pretenure,
17722 MinimumCapacity capacity_option) {
17723 DCHECK(0 <= at_least_space_for);
17724 Handle<Derived> dict = DerivedHashTable::New(isolate, at_least_space_for,
17725 capacity_option, pretenure);
17726
17727 // Initialize the next enumeration index.
17728 dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
17729 return dict;
17730 }
17731
17732 template <typename Derived, typename Shape, typename Key>
NewEmpty(Isolate * isolate,PretenureFlag pretenure)17733 Handle<Derived> Dictionary<Derived, Shape, Key>::NewEmpty(
17734 Isolate* isolate, PretenureFlag pretenure) {
17735 Handle<Derived> dict = DerivedHashTable::New(isolate, 1, pretenure);
17736 // Attempt to add one element to the empty dictionary must cause reallocation.
17737 DCHECK(!dict->HasSufficientCapacityToAdd(1));
17738 // Initialize the next enumeration index.
17739 dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
17740 return dict;
17741 }
17742
17743 template <typename Derived, typename Shape, typename Key>
17744 Handle<FixedArray>
GenerateNewEnumerationIndices(Handle<Derived> dictionary)17745 Dictionary<Derived, Shape, Key>::GenerateNewEnumerationIndices(
17746 Handle<Derived> dictionary) {
17747 int length = dictionary->NumberOfElements();
17748
17749 Handle<FixedArray> iteration_order = IterationIndices(dictionary);
17750 DCHECK(iteration_order->length() == length);
17751
17752 // Iterate over the dictionary using the enumeration order and update
17753 // the dictionary with new enumeration indices.
17754 for (int i = 0; i < length; i++) {
17755 int index = Smi::cast(iteration_order->get(i))->value();
17756 DCHECK(dictionary->IsKey(dictionary->KeyAt(index)));
17757
17758 int enum_index = PropertyDetails::kInitialIndex + i;
17759
17760 PropertyDetails details = dictionary->DetailsAt(index);
17761 PropertyDetails new_details = details.set_index(enum_index);
17762 dictionary->DetailsAtPut(index, new_details);
17763 }
17764
17765 // Set the next enumeration index.
17766 dictionary->SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
17767 return iteration_order;
17768 }
17769
17770
17771 template <typename Derived, typename Shape, typename Key>
SetRequiresCopyOnCapacityChange()17772 void Dictionary<Derived, Shape, Key>::SetRequiresCopyOnCapacityChange() {
17773 DCHECK_EQ(0, DerivedHashTable::NumberOfElements());
17774 DCHECK_EQ(0, DerivedHashTable::NumberOfDeletedElements());
17775 // Make sure that HashTable::EnsureCapacity will create a copy.
17776 DerivedHashTable::SetNumberOfDeletedElements(DerivedHashTable::Capacity());
17777 DCHECK(!DerivedHashTable::HasSufficientCapacityToAdd(1));
17778 }
17779
17780
17781 template <typename Derived, typename Shape, typename Key>
EnsureCapacity(Handle<Derived> dictionary,int n,Key key)17782 Handle<Derived> Dictionary<Derived, Shape, Key>::EnsureCapacity(
17783 Handle<Derived> dictionary, int n, Key key) {
17784 // Check whether there are enough enumeration indices to add n elements.
17785 if (Shape::kIsEnumerable &&
17786 !PropertyDetails::IsValidIndex(dictionary->NextEnumerationIndex() + n)) {
17787 // If not, we generate new indices for the properties.
17788 GenerateNewEnumerationIndices(dictionary);
17789 }
17790 return DerivedHashTable::EnsureCapacity(dictionary, n, key);
17791 }
17792
17793
17794 template <typename Derived, typename Shape, typename Key>
DeleteProperty(Handle<Derived> dictionary,int entry)17795 Handle<Object> Dictionary<Derived, Shape, Key>::DeleteProperty(
17796 Handle<Derived> dictionary, int entry) {
17797 Factory* factory = dictionary->GetIsolate()->factory();
17798 PropertyDetails details = dictionary->DetailsAt(entry);
17799 if (!details.IsConfigurable()) return factory->false_value();
17800
17801 dictionary->SetEntry(
17802 entry, factory->the_hole_value(), factory->the_hole_value());
17803 dictionary->ElementRemoved();
17804 return factory->true_value();
17805 }
17806
17807
17808 template<typename Derived, typename Shape, typename Key>
AtPut(Handle<Derived> dictionary,Key key,Handle<Object> value)17809 Handle<Derived> Dictionary<Derived, Shape, Key>::AtPut(
17810 Handle<Derived> dictionary, Key key, Handle<Object> value) {
17811 int entry = dictionary->FindEntry(key);
17812
17813 // If the entry is present set the value;
17814 if (entry != Dictionary::kNotFound) {
17815 dictionary->ValueAtPut(entry, *value);
17816 return dictionary;
17817 }
17818
17819 // Check whether the dictionary should be extended.
17820 dictionary = EnsureCapacity(dictionary, 1, key);
17821 #ifdef DEBUG
17822 USE(Shape::AsHandle(dictionary->GetIsolate(), key));
17823 #endif
17824 PropertyDetails details = PropertyDetails::Empty();
17825
17826 AddEntry(dictionary, key, value, details, dictionary->Hash(key));
17827 return dictionary;
17828 }
17829
17830 template <typename Derived, typename Shape, typename Key>
Add(Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details,int * entry_out)17831 Handle<Derived> Dictionary<Derived, Shape, Key>::Add(Handle<Derived> dictionary,
17832 Key key,
17833 Handle<Object> value,
17834 PropertyDetails details,
17835 int* entry_out) {
17836 // Valdate key is absent.
17837 SLOW_DCHECK((dictionary->FindEntry(key) == Dictionary::kNotFound));
17838 // Check whether the dictionary should be extended.
17839 dictionary = EnsureCapacity(dictionary, 1, key);
17840
17841 int entry = AddEntry(dictionary, key, value, details, dictionary->Hash(key));
17842 if (entry_out) *entry_out = entry;
17843 return dictionary;
17844 }
17845
17846 // Add a key, value pair to the dictionary. Returns entry value.
17847 template <typename Derived, typename Shape, typename Key>
AddEntry(Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details,uint32_t hash)17848 int Dictionary<Derived, Shape, Key>::AddEntry(Handle<Derived> dictionary,
17849 Key key, Handle<Object> value,
17850 PropertyDetails details,
17851 uint32_t hash) {
17852 // Compute the key object.
17853 Handle<Object> k = Shape::AsHandle(dictionary->GetIsolate(), key);
17854
17855 uint32_t entry = dictionary->FindInsertionEntry(hash);
17856 // Insert element at empty or deleted entry
17857 if (details.dictionary_index() == 0 && Shape::kIsEnumerable) {
17858 // Assign an enumeration index to the property and update
17859 // SetNextEnumerationIndex.
17860 int index = dictionary->NextEnumerationIndex();
17861 details = details.set_index(index);
17862 dictionary->SetNextEnumerationIndex(index + 1);
17863 }
17864 dictionary->SetEntry(entry, k, value, details);
17865 DCHECK((dictionary->KeyAt(entry)->IsNumber() ||
17866 dictionary->KeyAt(entry)->IsName()));
17867 dictionary->ElementAdded();
17868 return entry;
17869 }
17870
HasComplexElements()17871 bool SeededNumberDictionary::HasComplexElements() {
17872 if (!requires_slow_elements()) return false;
17873 Isolate* isolate = this->GetIsolate();
17874 int capacity = this->Capacity();
17875 for (int i = 0; i < capacity; i++) {
17876 Object* k = this->KeyAt(i);
17877 if (!this->IsKey(isolate, k)) continue;
17878 DCHECK(!IsDeleted(i));
17879 PropertyDetails details = this->DetailsAt(i);
17880 if (details.kind() == kAccessor) return true;
17881 PropertyAttributes attr = details.attributes();
17882 if (attr & ALL_ATTRIBUTES_MASK) return true;
17883 }
17884 return false;
17885 }
17886
UpdateMaxNumberKey(uint32_t key,Handle<JSObject> dictionary_holder)17887 void SeededNumberDictionary::UpdateMaxNumberKey(
17888 uint32_t key, Handle<JSObject> dictionary_holder) {
17889 DisallowHeapAllocation no_allocation;
17890 // If the dictionary requires slow elements an element has already
17891 // been added at a high index.
17892 if (requires_slow_elements()) return;
17893 // Check if this index is high enough that we should require slow
17894 // elements.
17895 if (key > kRequiresSlowElementsLimit) {
17896 if (!dictionary_holder.is_null()) {
17897 dictionary_holder->RequireSlowElements(this);
17898 }
17899 set_requires_slow_elements();
17900 return;
17901 }
17902 // Update max key value.
17903 Object* max_index_object = get(kMaxNumberKeyIndex);
17904 if (!max_index_object->IsSmi() || max_number_key() < key) {
17905 FixedArray::set(kMaxNumberKeyIndex,
17906 Smi::FromInt(key << kRequiresSlowElementsTagSize));
17907 }
17908 }
17909
AddNumberEntry(Handle<SeededNumberDictionary> dictionary,uint32_t key,Handle<Object> value,PropertyDetails details,Handle<JSObject> dictionary_holder)17910 Handle<SeededNumberDictionary> SeededNumberDictionary::AddNumberEntry(
17911 Handle<SeededNumberDictionary> dictionary, uint32_t key,
17912 Handle<Object> value, PropertyDetails details,
17913 Handle<JSObject> dictionary_holder) {
17914 dictionary->UpdateMaxNumberKey(key, dictionary_holder);
17915 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
17916 return Add(dictionary, key, value, details);
17917 }
17918
17919
AddNumberEntry(Handle<UnseededNumberDictionary> dictionary,uint32_t key,Handle<Object> value)17920 Handle<UnseededNumberDictionary> UnseededNumberDictionary::AddNumberEntry(
17921 Handle<UnseededNumberDictionary> dictionary,
17922 uint32_t key,
17923 Handle<Object> value) {
17924 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
17925 return Add(dictionary, key, value, PropertyDetails::Empty());
17926 }
17927
DeleteKey(Handle<UnseededNumberDictionary> dictionary,uint32_t key)17928 Handle<UnseededNumberDictionary> UnseededNumberDictionary::DeleteKey(
17929 Handle<UnseededNumberDictionary> dictionary, uint32_t key) {
17930 int entry = dictionary->FindEntry(key);
17931 if (entry == kNotFound) return dictionary;
17932
17933 Factory* factory = dictionary->GetIsolate()->factory();
17934 dictionary->SetEntry(entry, factory->the_hole_value(),
17935 factory->the_hole_value());
17936 dictionary->ElementRemoved();
17937 return dictionary->Shrink(dictionary, key);
17938 }
17939
AtNumberPut(Handle<SeededNumberDictionary> dictionary,uint32_t key,Handle<Object> value,Handle<JSObject> dictionary_holder)17940 Handle<SeededNumberDictionary> SeededNumberDictionary::AtNumberPut(
17941 Handle<SeededNumberDictionary> dictionary, uint32_t key,
17942 Handle<Object> value, Handle<JSObject> dictionary_holder) {
17943 dictionary->UpdateMaxNumberKey(key, dictionary_holder);
17944 return AtPut(dictionary, key, value);
17945 }
17946
17947
AtNumberPut(Handle<UnseededNumberDictionary> dictionary,uint32_t key,Handle<Object> value)17948 Handle<UnseededNumberDictionary> UnseededNumberDictionary::AtNumberPut(
17949 Handle<UnseededNumberDictionary> dictionary,
17950 uint32_t key,
17951 Handle<Object> value) {
17952 return AtPut(dictionary, key, value);
17953 }
17954
Set(Handle<SeededNumberDictionary> dictionary,uint32_t key,Handle<Object> value,PropertyDetails details,Handle<JSObject> dictionary_holder)17955 Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
17956 Handle<SeededNumberDictionary> dictionary, uint32_t key,
17957 Handle<Object> value, PropertyDetails details,
17958 Handle<JSObject> dictionary_holder) {
17959 int entry = dictionary->FindEntry(key);
17960 if (entry == kNotFound) {
17961 return AddNumberEntry(dictionary, key, value, details, dictionary_holder);
17962 }
17963 // Preserve enumeration index.
17964 details = details.set_index(dictionary->DetailsAt(entry).dictionary_index());
17965 Handle<Object> object_key =
17966 SeededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
17967 dictionary->SetEntry(entry, object_key, value, details);
17968 return dictionary;
17969 }
17970
17971
Set(Handle<UnseededNumberDictionary> dictionary,uint32_t key,Handle<Object> value)17972 Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
17973 Handle<UnseededNumberDictionary> dictionary,
17974 uint32_t key,
17975 Handle<Object> value) {
17976 int entry = dictionary->FindEntry(key);
17977 if (entry == kNotFound) return AddNumberEntry(dictionary, key, value);
17978 Handle<Object> object_key =
17979 UnseededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
17980 dictionary->SetEntry(entry, object_key, value);
17981 return dictionary;
17982 }
17983
17984
17985 template <typename Derived, typename Shape, typename Key>
NumberOfElementsFilterAttributes(PropertyFilter filter)17986 int Dictionary<Derived, Shape, Key>::NumberOfElementsFilterAttributes(
17987 PropertyFilter filter) {
17988 Isolate* isolate = this->GetIsolate();
17989 int capacity = this->Capacity();
17990 int result = 0;
17991 for (int i = 0; i < capacity; i++) {
17992 Object* k = this->KeyAt(i);
17993 if (this->IsKey(isolate, k) && !k->FilterKey(filter)) {
17994 if (this->IsDeleted(i)) continue;
17995 PropertyDetails details = this->DetailsAt(i);
17996 PropertyAttributes attr = details.attributes();
17997 if ((attr & filter) == 0) result++;
17998 }
17999 }
18000 return result;
18001 }
18002
18003
18004 template <typename Dictionary>
18005 struct EnumIndexComparator {
EnumIndexComparatorv8::internal::EnumIndexComparator18006 explicit EnumIndexComparator(Dictionary* dict) : dict(dict) {}
operator ()v8::internal::EnumIndexComparator18007 bool operator() (Smi* a, Smi* b) {
18008 PropertyDetails da(dict->DetailsAt(a->value()));
18009 PropertyDetails db(dict->DetailsAt(b->value()));
18010 return da.dictionary_index() < db.dictionary_index();
18011 }
18012 Dictionary* dict;
18013 };
18014
18015 template <typename Derived, typename Shape, typename Key>
CopyEnumKeysTo(Handle<Dictionary<Derived,Shape,Key>> dictionary,Handle<FixedArray> storage,KeyCollectionMode mode,KeyAccumulator * accumulator)18016 void Dictionary<Derived, Shape, Key>::CopyEnumKeysTo(
18017 Handle<Dictionary<Derived, Shape, Key>> dictionary,
18018 Handle<FixedArray> storage, KeyCollectionMode mode,
18019 KeyAccumulator* accumulator) {
18020 DCHECK_IMPLIES(mode != KeyCollectionMode::kOwnOnly, accumulator != nullptr);
18021 Isolate* isolate = dictionary->GetIsolate();
18022 int length = storage->length();
18023 int capacity = dictionary->Capacity();
18024 int properties = 0;
18025 for (int i = 0; i < capacity; i++) {
18026 Object* key = dictionary->KeyAt(i);
18027 bool is_shadowing_key = false;
18028 if (!dictionary->IsKey(isolate, key)) continue;
18029 if (key->IsSymbol()) continue;
18030 PropertyDetails details = dictionary->DetailsAt(i);
18031 if (details.IsDontEnum()) {
18032 if (mode == KeyCollectionMode::kIncludePrototypes) {
18033 is_shadowing_key = true;
18034 } else {
18035 continue;
18036 }
18037 }
18038 if (dictionary->IsDeleted(i)) continue;
18039 if (is_shadowing_key) {
18040 accumulator->AddShadowingKey(key);
18041 continue;
18042 } else {
18043 storage->set(properties, Smi::FromInt(i));
18044 }
18045 properties++;
18046 if (mode == KeyCollectionMode::kOwnOnly && properties == length) break;
18047 }
18048
18049 CHECK_EQ(length, properties);
18050 DisallowHeapAllocation no_gc;
18051 Dictionary<Derived, Shape, Key>* raw_dictionary = *dictionary;
18052 FixedArray* raw_storage = *storage;
18053 EnumIndexComparator<Derived> cmp(static_cast<Derived*>(*dictionary));
18054 Smi** start = reinterpret_cast<Smi**>(storage->GetFirstElementAddress());
18055 std::sort(start, start + length, cmp);
18056 for (int i = 0; i < length; i++) {
18057 int index = Smi::cast(raw_storage->get(i))->value();
18058 raw_storage->set(i, raw_dictionary->KeyAt(index));
18059 }
18060 }
18061
18062 template <typename Derived, typename Shape, typename Key>
IterationIndices(Handle<Dictionary<Derived,Shape,Key>> dictionary)18063 Handle<FixedArray> Dictionary<Derived, Shape, Key>::IterationIndices(
18064 Handle<Dictionary<Derived, Shape, Key>> dictionary) {
18065 Isolate* isolate = dictionary->GetIsolate();
18066 int capacity = dictionary->Capacity();
18067 int length = dictionary->NumberOfElements();
18068 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
18069 int array_size = 0;
18070 {
18071 DisallowHeapAllocation no_gc;
18072 Dictionary<Derived, Shape, Key>* raw_dict = *dictionary;
18073 for (int i = 0; i < capacity; i++) {
18074 Object* k = raw_dict->KeyAt(i);
18075 if (!raw_dict->IsKey(isolate, k)) continue;
18076 if (raw_dict->IsDeleted(i)) continue;
18077 array->set(array_size++, Smi::FromInt(i));
18078 }
18079
18080 DCHECK_EQ(array_size, length);
18081
18082 EnumIndexComparator<Derived> cmp(static_cast<Derived*>(raw_dict));
18083 Smi** start = reinterpret_cast<Smi**>(array->GetFirstElementAddress());
18084 std::sort(start, start + array_size, cmp);
18085 }
18086 array->Shrink(array_size);
18087 return array;
18088 }
18089
18090 template <typename Derived, typename Shape, typename Key>
CollectKeysTo(Handle<Dictionary<Derived,Shape,Key>> dictionary,KeyAccumulator * keys)18091 void Dictionary<Derived, Shape, Key>::CollectKeysTo(
18092 Handle<Dictionary<Derived, Shape, Key>> dictionary, KeyAccumulator* keys) {
18093 Isolate* isolate = keys->isolate();
18094 int capacity = dictionary->Capacity();
18095 Handle<FixedArray> array =
18096 isolate->factory()->NewFixedArray(dictionary->NumberOfElements());
18097 int array_size = 0;
18098 PropertyFilter filter = keys->filter();
18099 {
18100 DisallowHeapAllocation no_gc;
18101 Dictionary<Derived, Shape, Key>* raw_dict = *dictionary;
18102 for (int i = 0; i < capacity; i++) {
18103 Object* k = raw_dict->KeyAt(i);
18104 if (!raw_dict->IsKey(isolate, k) || k->FilterKey(filter)) continue;
18105 if (raw_dict->IsDeleted(i)) continue;
18106 PropertyDetails details = raw_dict->DetailsAt(i);
18107 if ((details.attributes() & filter) != 0) {
18108 keys->AddShadowingKey(k);
18109 continue;
18110 }
18111 if (filter & ONLY_ALL_CAN_READ) {
18112 if (details.kind() != kAccessor) continue;
18113 Object* accessors = raw_dict->ValueAt(i);
18114 if (accessors->IsPropertyCell()) {
18115 accessors = PropertyCell::cast(accessors)->value();
18116 }
18117 if (!accessors->IsAccessorInfo()) continue;
18118 if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
18119 }
18120 array->set(array_size++, Smi::FromInt(i));
18121 }
18122
18123 EnumIndexComparator<Derived> cmp(static_cast<Derived*>(raw_dict));
18124 Smi** start = reinterpret_cast<Smi**>(array->GetFirstElementAddress());
18125 std::sort(start, start + array_size, cmp);
18126 }
18127
18128 bool has_seen_symbol = false;
18129 for (int i = 0; i < array_size; i++) {
18130 int index = Smi::cast(array->get(i))->value();
18131 Object* key = dictionary->KeyAt(index);
18132 if (key->IsSymbol()) {
18133 has_seen_symbol = true;
18134 continue;
18135 }
18136 keys->AddKey(key, DO_NOT_CONVERT);
18137 }
18138 if (has_seen_symbol) {
18139 for (int i = 0; i < array_size; i++) {
18140 int index = Smi::cast(array->get(i))->value();
18141 Object* key = dictionary->KeyAt(index);
18142 if (!key->IsSymbol()) continue;
18143 keys->AddKey(key, DO_NOT_CONVERT);
18144 }
18145 }
18146 }
18147
18148
18149 // Backwards lookup (slow).
18150 template<typename Derived, typename Shape, typename Key>
SlowReverseLookup(Object * value)18151 Object* Dictionary<Derived, Shape, Key>::SlowReverseLookup(Object* value) {
18152 Isolate* isolate = this->GetIsolate();
18153 int capacity = this->Capacity();
18154 for (int i = 0; i < capacity; i++) {
18155 Object* k = this->KeyAt(i);
18156 if (!this->IsKey(isolate, k)) continue;
18157 Object* e = this->ValueAt(i);
18158 // TODO(dcarney): this should be templatized.
18159 if (e->IsPropertyCell()) {
18160 e = PropertyCell::cast(e)->value();
18161 }
18162 if (e == value) return k;
18163 }
18164 return isolate->heap()->undefined_value();
18165 }
18166
18167
Lookup(Isolate * isolate,Handle<Object> key,int32_t hash)18168 Object* ObjectHashTable::Lookup(Isolate* isolate, Handle<Object> key,
18169 int32_t hash) {
18170 DisallowHeapAllocation no_gc;
18171 DCHECK(IsKey(isolate, *key));
18172
18173 int entry = FindEntry(isolate, key, hash);
18174 if (entry == kNotFound) return isolate->heap()->the_hole_value();
18175 return get(EntryToIndex(entry) + 1);
18176 }
18177
18178
Lookup(Handle<Object> key)18179 Object* ObjectHashTable::Lookup(Handle<Object> key) {
18180 DisallowHeapAllocation no_gc;
18181
18182 Isolate* isolate = GetIsolate();
18183 DCHECK(IsKey(isolate, *key));
18184
18185 // If the object does not have an identity hash, it was never used as a key.
18186 Object* hash = key->GetHash();
18187 if (hash->IsUndefined(isolate)) {
18188 return isolate->heap()->the_hole_value();
18189 }
18190 return Lookup(isolate, key, Smi::cast(hash)->value());
18191 }
18192
ValueAt(int entry)18193 Object* ObjectHashTable::ValueAt(int entry) {
18194 return get(EntryToValueIndex(entry));
18195 }
18196
Lookup(Handle<Object> key,int32_t hash)18197 Object* ObjectHashTable::Lookup(Handle<Object> key, int32_t hash) {
18198 return Lookup(GetIsolate(), key, hash);
18199 }
18200
18201
Put(Handle<ObjectHashTable> table,Handle<Object> key,Handle<Object> value)18202 Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
18203 Handle<Object> key,
18204 Handle<Object> value) {
18205 Isolate* isolate = table->GetIsolate();
18206 DCHECK(table->IsKey(isolate, *key));
18207 DCHECK(!value->IsTheHole(isolate));
18208
18209 // Make sure the key object has an identity hash code.
18210 int32_t hash = Object::GetOrCreateHash(isolate, key)->value();
18211
18212 return Put(table, key, value, hash);
18213 }
18214
18215
Put(Handle<ObjectHashTable> table,Handle<Object> key,Handle<Object> value,int32_t hash)18216 Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
18217 Handle<Object> key,
18218 Handle<Object> value,
18219 int32_t hash) {
18220 Isolate* isolate = table->GetIsolate();
18221 DCHECK(table->IsKey(isolate, *key));
18222 DCHECK(!value->IsTheHole(isolate));
18223
18224 int entry = table->FindEntry(isolate, key, hash);
18225
18226 // Key is already in table, just overwrite value.
18227 if (entry != kNotFound) {
18228 table->set(EntryToIndex(entry) + 1, *value);
18229 return table;
18230 }
18231
18232 // Rehash if more than 33% of the entries are deleted entries.
18233 // TODO(jochen): Consider to shrink the fixed array in place.
18234 if ((table->NumberOfDeletedElements() << 1) > table->NumberOfElements()) {
18235 table->Rehash(isolate->factory()->undefined_value());
18236 }
18237 // If we're out of luck, we didn't get a GC recently, and so rehashing
18238 // isn't enough to avoid a crash.
18239 if (!table->HasSufficientCapacityToAdd(1)) {
18240 int nof = table->NumberOfElements() + 1;
18241 int capacity = ObjectHashTable::ComputeCapacity(nof * 2);
18242 if (capacity > ObjectHashTable::kMaxCapacity) {
18243 for (size_t i = 0; i < 2; ++i) {
18244 isolate->heap()->CollectAllGarbage(
18245 Heap::kFinalizeIncrementalMarkingMask,
18246 GarbageCollectionReason::kFullHashtable);
18247 }
18248 table->Rehash(isolate->factory()->undefined_value());
18249 }
18250 }
18251
18252 // Check whether the hash table should be extended.
18253 table = EnsureCapacity(table, 1, key);
18254 table->AddEntry(table->FindInsertionEntry(hash), *key, *value);
18255 return table;
18256 }
18257
18258
Remove(Handle<ObjectHashTable> table,Handle<Object> key,bool * was_present)18259 Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
18260 Handle<Object> key,
18261 bool* was_present) {
18262 DCHECK(table->IsKey(table->GetIsolate(), *key));
18263
18264 Object* hash = key->GetHash();
18265 if (hash->IsUndefined(table->GetIsolate())) {
18266 *was_present = false;
18267 return table;
18268 }
18269
18270 return Remove(table, key, was_present, Smi::cast(hash)->value());
18271 }
18272
18273
Remove(Handle<ObjectHashTable> table,Handle<Object> key,bool * was_present,int32_t hash)18274 Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
18275 Handle<Object> key,
18276 bool* was_present,
18277 int32_t hash) {
18278 Isolate* isolate = table->GetIsolate();
18279 DCHECK(table->IsKey(isolate, *key));
18280
18281 int entry = table->FindEntry(isolate, key, hash);
18282 if (entry == kNotFound) {
18283 *was_present = false;
18284 return table;
18285 }
18286
18287 *was_present = true;
18288 table->RemoveEntry(entry);
18289 return Shrink(table, key);
18290 }
18291
18292
AddEntry(int entry,Object * key,Object * value)18293 void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
18294 set(EntryToIndex(entry), key);
18295 set(EntryToIndex(entry) + 1, value);
18296 ElementAdded();
18297 }
18298
18299
RemoveEntry(int entry)18300 void ObjectHashTable::RemoveEntry(int entry) {
18301 set_the_hole(EntryToIndex(entry));
18302 set_the_hole(EntryToIndex(entry) + 1);
18303 ElementRemoved();
18304 }
18305
18306
Lookup(Handle<HeapObject> key)18307 Object* WeakHashTable::Lookup(Handle<HeapObject> key) {
18308 DisallowHeapAllocation no_gc;
18309 Isolate* isolate = GetIsolate();
18310 DCHECK(IsKey(isolate, *key));
18311 int entry = FindEntry(key);
18312 if (entry == kNotFound) return isolate->heap()->the_hole_value();
18313 return get(EntryToValueIndex(entry));
18314 }
18315
18316
Put(Handle<WeakHashTable> table,Handle<HeapObject> key,Handle<HeapObject> value)18317 Handle<WeakHashTable> WeakHashTable::Put(Handle<WeakHashTable> table,
18318 Handle<HeapObject> key,
18319 Handle<HeapObject> value) {
18320 Isolate* isolate = key->GetIsolate();
18321 DCHECK(table->IsKey(isolate, *key));
18322 int entry = table->FindEntry(key);
18323 // Key is already in table, just overwrite value.
18324 if (entry != kNotFound) {
18325 table->set(EntryToValueIndex(entry), *value);
18326 return table;
18327 }
18328
18329 Handle<WeakCell> key_cell = isolate->factory()->NewWeakCell(key);
18330
18331 // Check whether the hash table should be extended.
18332 table = EnsureCapacity(table, 1, key, TENURED);
18333
18334 table->AddEntry(table->FindInsertionEntry(table->Hash(key)), key_cell, value);
18335 return table;
18336 }
18337
18338
AddEntry(int entry,Handle<WeakCell> key_cell,Handle<HeapObject> value)18339 void WeakHashTable::AddEntry(int entry, Handle<WeakCell> key_cell,
18340 Handle<HeapObject> value) {
18341 DisallowHeapAllocation no_allocation;
18342 set(EntryToIndex(entry), *key_cell);
18343 set(EntryToValueIndex(entry), *value);
18344 ElementAdded();
18345 }
18346
18347
18348 template<class Derived, class Iterator, int entrysize>
Allocate(Isolate * isolate,int capacity,PretenureFlag pretenure)18349 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Allocate(
18350 Isolate* isolate, int capacity, PretenureFlag pretenure) {
18351 // Capacity must be a power of two, since we depend on being able
18352 // to divide and multiple by 2 (kLoadFactor) to derive capacity
18353 // from number of buckets. If we decide to change kLoadFactor
18354 // to something other than 2, capacity should be stored as another
18355 // field of this object.
18356 capacity = base::bits::RoundUpToPowerOfTwo32(Max(kMinCapacity, capacity));
18357 if (capacity > kMaxCapacity) {
18358 v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
18359 }
18360 int num_buckets = capacity / kLoadFactor;
18361 Handle<FixedArray> backing_store = isolate->factory()->NewFixedArray(
18362 kHashTableStartIndex + num_buckets + (capacity * kEntrySize), pretenure);
18363 backing_store->set_map_no_write_barrier(
18364 isolate->heap()->ordered_hash_table_map());
18365 Handle<Derived> table = Handle<Derived>::cast(backing_store);
18366 for (int i = 0; i < num_buckets; ++i) {
18367 table->set(kHashTableStartIndex + i, Smi::FromInt(kNotFound));
18368 }
18369 table->SetNumberOfBuckets(num_buckets);
18370 table->SetNumberOfElements(0);
18371 table->SetNumberOfDeletedElements(0);
18372 return table;
18373 }
18374
18375
18376 template<class Derived, class Iterator, int entrysize>
EnsureGrowable(Handle<Derived> table)18377 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::EnsureGrowable(
18378 Handle<Derived> table) {
18379 DCHECK(!table->IsObsolete());
18380
18381 int nof = table->NumberOfElements();
18382 int nod = table->NumberOfDeletedElements();
18383 int capacity = table->Capacity();
18384 if ((nof + nod) < capacity) return table;
18385 // Don't need to grow if we can simply clear out deleted entries instead.
18386 // Note that we can't compact in place, though, so we always allocate
18387 // a new table.
18388 return Rehash(table, (nod < (capacity >> 1)) ? capacity << 1 : capacity);
18389 }
18390
18391
18392 template<class Derived, class Iterator, int entrysize>
Shrink(Handle<Derived> table)18393 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Shrink(
18394 Handle<Derived> table) {
18395 DCHECK(!table->IsObsolete());
18396
18397 int nof = table->NumberOfElements();
18398 int capacity = table->Capacity();
18399 if (nof >= (capacity >> 2)) return table;
18400 return Rehash(table, capacity / 2);
18401 }
18402
18403
18404 template<class Derived, class Iterator, int entrysize>
Clear(Handle<Derived> table)18405 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Clear(
18406 Handle<Derived> table) {
18407 DCHECK(!table->IsObsolete());
18408
18409 Handle<Derived> new_table =
18410 Allocate(table->GetIsolate(),
18411 kMinCapacity,
18412 table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
18413
18414 table->SetNextTable(*new_table);
18415 table->SetNumberOfDeletedElements(kClearedTableSentinel);
18416
18417 return new_table;
18418 }
18419
18420 template <class Derived, class Iterator, int entrysize>
HasKey(Handle<Derived> table,Handle<Object> key)18421 bool OrderedHashTable<Derived, Iterator, entrysize>::HasKey(
18422 Handle<Derived> table, Handle<Object> key) {
18423 DisallowHeapAllocation no_gc;
18424 Isolate* isolate = table->GetIsolate();
18425 Object* raw_key = *key;
18426 int entry = table->KeyToFirstEntry(isolate, raw_key);
18427 // Walk the chain in the bucket to find the key.
18428 while (entry != kNotFound) {
18429 Object* candidate_key = table->KeyAt(entry);
18430 if (candidate_key->SameValueZero(raw_key)) return true;
18431 entry = table->NextChainEntry(entry);
18432 }
18433 return false;
18434 }
18435
18436
Add(Handle<OrderedHashSet> table,Handle<Object> key)18437 Handle<OrderedHashSet> OrderedHashSet::Add(Handle<OrderedHashSet> table,
18438 Handle<Object> key) {
18439 int hash = Object::GetOrCreateHash(table->GetIsolate(), key)->value();
18440 int entry = table->HashToEntry(hash);
18441 // Walk the chain of the bucket and try finding the key.
18442 while (entry != kNotFound) {
18443 Object* candidate_key = table->KeyAt(entry);
18444 // Do not add if we have the key already
18445 if (candidate_key->SameValueZero(*key)) return table;
18446 entry = table->NextChainEntry(entry);
18447 }
18448
18449 table = OrderedHashSet::EnsureGrowable(table);
18450 // Read the existing bucket values.
18451 int bucket = table->HashToBucket(hash);
18452 int previous_entry = table->HashToEntry(hash);
18453 int nof = table->NumberOfElements();
18454 // Insert a new entry at the end,
18455 int new_entry = nof + table->NumberOfDeletedElements();
18456 int new_index = table->EntryToIndex(new_entry);
18457 table->set(new_index, *key);
18458 table->set(new_index + kChainOffset, Smi::FromInt(previous_entry));
18459 // and point the bucket to the new entry.
18460 table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
18461 table->SetNumberOfElements(nof + 1);
18462 return table;
18463 }
18464
ConvertToKeysArray(Handle<OrderedHashSet> table,GetKeysConversion convert)18465 Handle<FixedArray> OrderedHashSet::ConvertToKeysArray(
18466 Handle<OrderedHashSet> table, GetKeysConversion convert) {
18467 Isolate* isolate = table->GetIsolate();
18468 int length = table->NumberOfElements();
18469 int nof_buckets = table->NumberOfBuckets();
18470 // Convert the dictionary to a linear list.
18471 Handle<FixedArray> result = Handle<FixedArray>::cast(table);
18472 // From this point on table is no longer a valid OrderedHashSet.
18473 result->set_map(isolate->heap()->fixed_array_map());
18474 for (int i = 0; i < length; i++) {
18475 int index = kHashTableStartIndex + nof_buckets + (i * kEntrySize);
18476 Object* key = table->get(index);
18477 if (convert == GetKeysConversion::kConvertToString && key->IsNumber()) {
18478 key = *isolate->factory()->NumberToString(handle(key, isolate));
18479 }
18480 result->set(i, key);
18481 }
18482 result->Shrink(length);
18483 return result;
18484 }
18485
18486 template<class Derived, class Iterator, int entrysize>
Rehash(Handle<Derived> table,int new_capacity)18487 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Rehash(
18488 Handle<Derived> table, int new_capacity) {
18489 Isolate* isolate = table->GetIsolate();
18490 DCHECK(!table->IsObsolete());
18491
18492 Handle<Derived> new_table =
18493 Allocate(isolate, new_capacity,
18494 isolate->heap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
18495 int nof = table->NumberOfElements();
18496 int nod = table->NumberOfDeletedElements();
18497 int new_buckets = new_table->NumberOfBuckets();
18498 int new_entry = 0;
18499 int removed_holes_index = 0;
18500
18501 DisallowHeapAllocation no_gc;
18502 for (int old_entry = 0; old_entry < (nof + nod); ++old_entry) {
18503 Object* key = table->KeyAt(old_entry);
18504 if (key->IsTheHole(isolate)) {
18505 table->SetRemovedIndexAt(removed_holes_index++, old_entry);
18506 continue;
18507 }
18508
18509 Object* hash = key->GetHash();
18510 int bucket = Smi::cast(hash)->value() & (new_buckets - 1);
18511 Object* chain_entry = new_table->get(kHashTableStartIndex + bucket);
18512 new_table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
18513 int new_index = new_table->EntryToIndex(new_entry);
18514 int old_index = table->EntryToIndex(old_entry);
18515 for (int i = 0; i < entrysize; ++i) {
18516 Object* value = table->get(old_index + i);
18517 new_table->set(new_index + i, value);
18518 }
18519 new_table->set(new_index + kChainOffset, chain_entry);
18520 ++new_entry;
18521 }
18522
18523 DCHECK_EQ(nod, removed_holes_index);
18524
18525 new_table->SetNumberOfElements(nof);
18526 table->SetNextTable(*new_table);
18527
18528 return new_table;
18529 }
18530
18531
18532 template Handle<OrderedHashSet>
18533 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Allocate(
18534 Isolate* isolate, int capacity, PretenureFlag pretenure);
18535
18536 template Handle<OrderedHashSet>
18537 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::EnsureGrowable(
18538 Handle<OrderedHashSet> table);
18539
18540 template Handle<OrderedHashSet>
18541 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Shrink(
18542 Handle<OrderedHashSet> table);
18543
18544 template Handle<OrderedHashSet>
18545 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Clear(
18546 Handle<OrderedHashSet> table);
18547
18548 template bool OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::HasKey(
18549 Handle<OrderedHashSet> table, Handle<Object> key);
18550
18551
18552 template Handle<OrderedHashMap>
18553 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Allocate(
18554 Isolate* isolate, int capacity, PretenureFlag pretenure);
18555
18556 template Handle<OrderedHashMap>
18557 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::EnsureGrowable(
18558 Handle<OrderedHashMap> table);
18559
18560 template Handle<OrderedHashMap>
18561 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Shrink(
18562 Handle<OrderedHashMap> table);
18563
18564 template Handle<OrderedHashMap>
18565 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Clear(
18566 Handle<OrderedHashMap> table);
18567
18568 template bool OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::HasKey(
18569 Handle<OrderedHashMap> table, Handle<Object> key);
18570
18571
18572 template<class Derived, class TableType>
Transition()18573 void OrderedHashTableIterator<Derived, TableType>::Transition() {
18574 DisallowHeapAllocation no_allocation;
18575 TableType* table = TableType::cast(this->table());
18576 if (!table->IsObsolete()) return;
18577
18578 int index = Smi::cast(this->index())->value();
18579 while (table->IsObsolete()) {
18580 TableType* next_table = table->NextTable();
18581
18582 if (index > 0) {
18583 int nod = table->NumberOfDeletedElements();
18584
18585 if (nod == TableType::kClearedTableSentinel) {
18586 index = 0;
18587 } else {
18588 int old_index = index;
18589 for (int i = 0; i < nod; ++i) {
18590 int removed_index = table->RemovedIndexAt(i);
18591 if (removed_index >= old_index) break;
18592 --index;
18593 }
18594 }
18595 }
18596
18597 table = next_table;
18598 }
18599
18600 set_table(table);
18601 set_index(Smi::FromInt(index));
18602 }
18603
18604
18605 template<class Derived, class TableType>
HasMore()18606 bool OrderedHashTableIterator<Derived, TableType>::HasMore() {
18607 DisallowHeapAllocation no_allocation;
18608 Isolate* isolate = this->GetIsolate();
18609 if (this->table()->IsUndefined(isolate)) return false;
18610
18611 Transition();
18612
18613 TableType* table = TableType::cast(this->table());
18614 int index = Smi::cast(this->index())->value();
18615 int used_capacity = table->UsedCapacity();
18616
18617 while (index < used_capacity && table->KeyAt(index)->IsTheHole(isolate)) {
18618 index++;
18619 }
18620
18621 set_index(Smi::FromInt(index));
18622
18623 if (index < used_capacity) return true;
18624
18625 set_table(isolate->heap()->undefined_value());
18626 return false;
18627 }
18628
18629
18630 template<class Derived, class TableType>
Next(JSArray * value_array)18631 Smi* OrderedHashTableIterator<Derived, TableType>::Next(JSArray* value_array) {
18632 DisallowHeapAllocation no_allocation;
18633 if (HasMore()) {
18634 FixedArray* array = FixedArray::cast(value_array->elements());
18635 static_cast<Derived*>(this)->PopulateValueArray(array);
18636 MoveNext();
18637 return Smi::cast(kind());
18638 }
18639 return Smi::kZero;
18640 }
18641
18642
18643 template Smi*
18644 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Next(
18645 JSArray* value_array);
18646
18647 template bool
18648 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::HasMore();
18649
18650 template void
18651 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::MoveNext();
18652
18653 template Object*
18654 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::CurrentKey();
18655
18656 template void
18657 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Transition();
18658
18659
18660 template Smi*
18661 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Next(
18662 JSArray* value_array);
18663
18664 template bool
18665 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::HasMore();
18666
18667 template void
18668 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::MoveNext();
18669
18670 template Object*
18671 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::CurrentKey();
18672
18673 template void
18674 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Transition();
18675
18676
Initialize(Handle<JSSet> set,Isolate * isolate)18677 void JSSet::Initialize(Handle<JSSet> set, Isolate* isolate) {
18678 Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
18679 set->set_table(*table);
18680 }
18681
18682
Clear(Handle<JSSet> set)18683 void JSSet::Clear(Handle<JSSet> set) {
18684 Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()));
18685 table = OrderedHashSet::Clear(table);
18686 set->set_table(*table);
18687 }
18688
18689
Initialize(Handle<JSMap> map,Isolate * isolate)18690 void JSMap::Initialize(Handle<JSMap> map, Isolate* isolate) {
18691 Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
18692 map->set_table(*table);
18693 }
18694
18695
Clear(Handle<JSMap> map)18696 void JSMap::Clear(Handle<JSMap> map) {
18697 Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()));
18698 table = OrderedHashMap::Clear(table);
18699 map->set_table(*table);
18700 }
18701
18702
Initialize(Handle<JSWeakCollection> weak_collection,Isolate * isolate)18703 void JSWeakCollection::Initialize(Handle<JSWeakCollection> weak_collection,
18704 Isolate* isolate) {
18705 Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0);
18706 weak_collection->set_table(*table);
18707 }
18708
18709
Set(Handle<JSWeakCollection> weak_collection,Handle<Object> key,Handle<Object> value,int32_t hash)18710 void JSWeakCollection::Set(Handle<JSWeakCollection> weak_collection,
18711 Handle<Object> key, Handle<Object> value,
18712 int32_t hash) {
18713 DCHECK(key->IsJSReceiver() || key->IsSymbol());
18714 Handle<ObjectHashTable> table(
18715 ObjectHashTable::cast(weak_collection->table()));
18716 DCHECK(table->IsKey(*key));
18717 Handle<ObjectHashTable> new_table =
18718 ObjectHashTable::Put(table, key, value, hash);
18719 weak_collection->set_table(*new_table);
18720 if (*table != *new_table) {
18721 // Zap the old table since we didn't record slots for its elements.
18722 table->FillWithHoles(0, table->length());
18723 }
18724 }
18725
18726
Delete(Handle<JSWeakCollection> weak_collection,Handle<Object> key,int32_t hash)18727 bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection,
18728 Handle<Object> key, int32_t hash) {
18729 DCHECK(key->IsJSReceiver() || key->IsSymbol());
18730 Handle<ObjectHashTable> table(
18731 ObjectHashTable::cast(weak_collection->table()));
18732 DCHECK(table->IsKey(*key));
18733 bool was_present = false;
18734 Handle<ObjectHashTable> new_table =
18735 ObjectHashTable::Remove(table, key, &was_present, hash);
18736 weak_collection->set_table(*new_table);
18737 if (*table != *new_table) {
18738 // Zap the old table since we didn't record slots for its elements.
18739 table->FillWithHoles(0, table->length());
18740 }
18741 return was_present;
18742 }
18743
GetEntries(Handle<JSWeakCollection> holder,int max_entries)18744 Handle<JSArray> JSWeakCollection::GetEntries(Handle<JSWeakCollection> holder,
18745 int max_entries) {
18746 Isolate* isolate = holder->GetIsolate();
18747 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
18748 if (max_entries == 0 || max_entries > table->NumberOfElements()) {
18749 max_entries = table->NumberOfElements();
18750 }
18751 int values_per_entry = holder->IsJSWeakMap() ? 2 : 1;
18752 Handle<FixedArray> entries =
18753 isolate->factory()->NewFixedArray(max_entries * values_per_entry);
18754 // Recompute max_values because GC could have removed elements from the table.
18755 if (max_entries > table->NumberOfElements()) {
18756 max_entries = table->NumberOfElements();
18757 }
18758
18759 {
18760 DisallowHeapAllocation no_gc;
18761 int count = 0;
18762 for (int i = 0;
18763 count / values_per_entry < max_entries && i < table->Capacity(); i++) {
18764 Handle<Object> key(table->KeyAt(i), isolate);
18765 if (table->IsKey(isolate, *key)) {
18766 entries->set(count++, *key);
18767 if (values_per_entry > 1) {
18768 Object* value = table->Lookup(key);
18769 entries->set(count++, value);
18770 }
18771 }
18772 }
18773 DCHECK_EQ(max_entries * values_per_entry, count);
18774 }
18775 return isolate->factory()->NewJSArrayWithElements(entries);
18776 }
18777
18778 // Check if there is a break point at this source position.
HasBreakPoint(int source_position)18779 bool DebugInfo::HasBreakPoint(int source_position) {
18780 // Get the break point info object for this code offset.
18781 Object* break_point_info = GetBreakPointInfo(source_position);
18782
18783 // If there is no break point info object or no break points in the break
18784 // point info object there is no break point at this code offset.
18785 if (break_point_info->IsUndefined(GetIsolate())) return false;
18786 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
18787 }
18788
18789 // Get the break point info object for this source position.
GetBreakPointInfo(int source_position)18790 Object* DebugInfo::GetBreakPointInfo(int source_position) {
18791 Isolate* isolate = GetIsolate();
18792 if (!break_points()->IsUndefined(isolate)) {
18793 for (int i = 0; i < break_points()->length(); i++) {
18794 if (!break_points()->get(i)->IsUndefined(isolate)) {
18795 BreakPointInfo* break_point_info =
18796 BreakPointInfo::cast(break_points()->get(i));
18797 if (break_point_info->source_position() == source_position) {
18798 return break_point_info;
18799 }
18800 }
18801 }
18802 }
18803 return isolate->heap()->undefined_value();
18804 }
18805
ClearBreakPoint(Handle<DebugInfo> debug_info,Handle<Object> break_point_object)18806 bool DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
18807 Handle<Object> break_point_object) {
18808 Isolate* isolate = debug_info->GetIsolate();
18809 if (debug_info->break_points()->IsUndefined(isolate)) return false;
18810
18811 for (int i = 0; i < debug_info->break_points()->length(); i++) {
18812 if (debug_info->break_points()->get(i)->IsUndefined(isolate)) continue;
18813 Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
18814 BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
18815 if (BreakPointInfo::HasBreakPointObject(break_point_info,
18816 break_point_object)) {
18817 BreakPointInfo::ClearBreakPoint(break_point_info, break_point_object);
18818 return true;
18819 }
18820 }
18821 return false;
18822 }
18823
SetBreakPoint(Handle<DebugInfo> debug_info,int source_position,Handle<Object> break_point_object)18824 void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info, int source_position,
18825 Handle<Object> break_point_object) {
18826 Isolate* isolate = debug_info->GetIsolate();
18827 Handle<Object> break_point_info(
18828 debug_info->GetBreakPointInfo(source_position), isolate);
18829 if (!break_point_info->IsUndefined(isolate)) {
18830 BreakPointInfo::SetBreakPoint(
18831 Handle<BreakPointInfo>::cast(break_point_info),
18832 break_point_object);
18833 return;
18834 }
18835
18836 // Adding a new break point for a code offset which did not have any
18837 // break points before. Try to find a free slot.
18838 static const int kNoBreakPointInfo = -1;
18839 int index = kNoBreakPointInfo;
18840 for (int i = 0; i < debug_info->break_points()->length(); i++) {
18841 if (debug_info->break_points()->get(i)->IsUndefined(isolate)) {
18842 index = i;
18843 break;
18844 }
18845 }
18846 if (index == kNoBreakPointInfo) {
18847 // No free slot - extend break point info array.
18848 Handle<FixedArray> old_break_points = Handle<FixedArray>(
18849 FixedArray::cast(debug_info->break_points()), isolate);
18850 Handle<FixedArray> new_break_points =
18851 isolate->factory()->NewFixedArray(
18852 old_break_points->length() +
18853 DebugInfo::kEstimatedNofBreakPointsInFunction);
18854
18855 debug_info->set_break_points(*new_break_points);
18856 for (int i = 0; i < old_break_points->length(); i++) {
18857 new_break_points->set(i, old_break_points->get(i));
18858 }
18859 index = old_break_points->length();
18860 }
18861 DCHECK(index != kNoBreakPointInfo);
18862
18863 // Allocate new BreakPointInfo object and set the break point.
18864 Handle<BreakPointInfo> new_break_point_info =
18865 isolate->factory()->NewBreakPointInfo(source_position);
18866 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
18867 debug_info->break_points()->set(index, *new_break_point_info);
18868 }
18869
18870 // Get the break point objects for a source position.
GetBreakPointObjects(int source_position)18871 Handle<Object> DebugInfo::GetBreakPointObjects(int source_position) {
18872 Object* break_point_info = GetBreakPointInfo(source_position);
18873 Isolate* isolate = GetIsolate();
18874 if (break_point_info->IsUndefined(isolate)) {
18875 return isolate->factory()->undefined_value();
18876 }
18877 return Handle<Object>(
18878 BreakPointInfo::cast(break_point_info)->break_point_objects(), isolate);
18879 }
18880
18881
18882 // Get the total number of break points.
GetBreakPointCount()18883 int DebugInfo::GetBreakPointCount() {
18884 Isolate* isolate = GetIsolate();
18885 if (break_points()->IsUndefined(isolate)) return 0;
18886 int count = 0;
18887 for (int i = 0; i < break_points()->length(); i++) {
18888 if (!break_points()->get(i)->IsUndefined(isolate)) {
18889 BreakPointInfo* break_point_info =
18890 BreakPointInfo::cast(break_points()->get(i));
18891 count += break_point_info->GetBreakPointCount();
18892 }
18893 }
18894 return count;
18895 }
18896
18897
FindBreakPointInfo(Handle<DebugInfo> debug_info,Handle<Object> break_point_object)18898 Handle<Object> DebugInfo::FindBreakPointInfo(
18899 Handle<DebugInfo> debug_info, Handle<Object> break_point_object) {
18900 Isolate* isolate = debug_info->GetIsolate();
18901 if (!debug_info->break_points()->IsUndefined(isolate)) {
18902 for (int i = 0; i < debug_info->break_points()->length(); i++) {
18903 if (!debug_info->break_points()->get(i)->IsUndefined(isolate)) {
18904 Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
18905 BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
18906 if (BreakPointInfo::HasBreakPointObject(break_point_info,
18907 break_point_object)) {
18908 return break_point_info;
18909 }
18910 }
18911 }
18912 }
18913 return isolate->factory()->undefined_value();
18914 }
18915
18916 // Remove the specified break point object.
ClearBreakPoint(Handle<BreakPointInfo> break_point_info,Handle<Object> break_point_object)18917 void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
18918 Handle<Object> break_point_object) {
18919 Isolate* isolate = break_point_info->GetIsolate();
18920 // If there are no break points just ignore.
18921 if (break_point_info->break_point_objects()->IsUndefined(isolate)) return;
18922 // If there is a single break point clear it if it is the same.
18923 if (!break_point_info->break_point_objects()->IsFixedArray()) {
18924 if (break_point_info->break_point_objects() == *break_point_object) {
18925 break_point_info->set_break_point_objects(
18926 isolate->heap()->undefined_value());
18927 }
18928 return;
18929 }
18930 // If there are multiple break points shrink the array
18931 DCHECK(break_point_info->break_point_objects()->IsFixedArray());
18932 Handle<FixedArray> old_array =
18933 Handle<FixedArray>(
18934 FixedArray::cast(break_point_info->break_point_objects()));
18935 Handle<FixedArray> new_array =
18936 isolate->factory()->NewFixedArray(old_array->length() - 1);
18937 int found_count = 0;
18938 for (int i = 0; i < old_array->length(); i++) {
18939 if (old_array->get(i) == *break_point_object) {
18940 DCHECK(found_count == 0);
18941 found_count++;
18942 } else {
18943 new_array->set(i - found_count, old_array->get(i));
18944 }
18945 }
18946 // If the break point was found in the list change it.
18947 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
18948 }
18949
18950
18951 // Add the specified break point object.
SetBreakPoint(Handle<BreakPointInfo> break_point_info,Handle<Object> break_point_object)18952 void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
18953 Handle<Object> break_point_object) {
18954 Isolate* isolate = break_point_info->GetIsolate();
18955
18956 // If there was no break point objects before just set it.
18957 if (break_point_info->break_point_objects()->IsUndefined(isolate)) {
18958 break_point_info->set_break_point_objects(*break_point_object);
18959 return;
18960 }
18961 // If the break point object is the same as before just ignore.
18962 if (break_point_info->break_point_objects() == *break_point_object) return;
18963 // If there was one break point object before replace with array.
18964 if (!break_point_info->break_point_objects()->IsFixedArray()) {
18965 Handle<FixedArray> array = isolate->factory()->NewFixedArray(2);
18966 array->set(0, break_point_info->break_point_objects());
18967 array->set(1, *break_point_object);
18968 break_point_info->set_break_point_objects(*array);
18969 return;
18970 }
18971 // If there was more than one break point before extend array.
18972 Handle<FixedArray> old_array =
18973 Handle<FixedArray>(
18974 FixedArray::cast(break_point_info->break_point_objects()));
18975 Handle<FixedArray> new_array =
18976 isolate->factory()->NewFixedArray(old_array->length() + 1);
18977 for (int i = 0; i < old_array->length(); i++) {
18978 // If the break point was there before just ignore.
18979 if (old_array->get(i) == *break_point_object) return;
18980 new_array->set(i, old_array->get(i));
18981 }
18982 // Add the new break point.
18983 new_array->set(old_array->length(), *break_point_object);
18984 break_point_info->set_break_point_objects(*new_array);
18985 }
18986
18987
HasBreakPointObject(Handle<BreakPointInfo> break_point_info,Handle<Object> break_point_object)18988 bool BreakPointInfo::HasBreakPointObject(
18989 Handle<BreakPointInfo> break_point_info,
18990 Handle<Object> break_point_object) {
18991 // No break point.
18992 Isolate* isolate = break_point_info->GetIsolate();
18993 if (break_point_info->break_point_objects()->IsUndefined(isolate)) {
18994 return false;
18995 }
18996 // Single break point.
18997 if (!break_point_info->break_point_objects()->IsFixedArray()) {
18998 return break_point_info->break_point_objects() == *break_point_object;
18999 }
19000 // Multiple break points.
19001 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
19002 for (int i = 0; i < array->length(); i++) {
19003 if (array->get(i) == *break_point_object) {
19004 return true;
19005 }
19006 }
19007 return false;
19008 }
19009
19010
19011 // Get the number of break points.
GetBreakPointCount()19012 int BreakPointInfo::GetBreakPointCount() {
19013 // No break point.
19014 if (break_point_objects()->IsUndefined(GetIsolate())) return 0;
19015 // Single break point.
19016 if (!break_point_objects()->IsFixedArray()) return 1;
19017 // Multiple break points.
19018 return FixedArray::cast(break_point_objects())->length();
19019 }
19020
19021
19022 // static
New(Handle<JSFunction> constructor,Handle<JSReceiver> new_target,double tv)19023 MaybeHandle<JSDate> JSDate::New(Handle<JSFunction> constructor,
19024 Handle<JSReceiver> new_target, double tv) {
19025 Isolate* const isolate = constructor->GetIsolate();
19026 Handle<JSObject> result;
19027 ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
19028 JSObject::New(constructor, new_target), JSDate);
19029 if (-DateCache::kMaxTimeInMs <= tv && tv <= DateCache::kMaxTimeInMs) {
19030 tv = DoubleToInteger(tv) + 0.0;
19031 } else {
19032 tv = std::numeric_limits<double>::quiet_NaN();
19033 }
19034 Handle<Object> value = isolate->factory()->NewNumber(tv);
19035 Handle<JSDate>::cast(result)->SetValue(*value, std::isnan(tv));
19036 return Handle<JSDate>::cast(result);
19037 }
19038
19039
19040 // static
CurrentTimeValue(Isolate * isolate)19041 double JSDate::CurrentTimeValue(Isolate* isolate) {
19042 if (FLAG_log_timer_events || FLAG_prof_cpp) LOG(isolate, CurrentTimeEvent());
19043
19044 // According to ECMA-262, section 15.9.1, page 117, the precision of
19045 // the number in a Date object representing a particular instant in
19046 // time is milliseconds. Therefore, we floor the result of getting
19047 // the OS time.
19048 return Floor(FLAG_verify_predictable
19049 ? isolate->heap()->MonotonicallyIncreasingTimeInMs()
19050 : base::OS::TimeCurrentMillis());
19051 }
19052
19053
19054 // static
GetField(Object * object,Smi * index)19055 Object* JSDate::GetField(Object* object, Smi* index) {
19056 return JSDate::cast(object)->DoGetField(
19057 static_cast<FieldIndex>(index->value()));
19058 }
19059
19060
DoGetField(FieldIndex index)19061 Object* JSDate::DoGetField(FieldIndex index) {
19062 DCHECK(index != kDateValue);
19063
19064 DateCache* date_cache = GetIsolate()->date_cache();
19065
19066 if (index < kFirstUncachedField) {
19067 Object* stamp = cache_stamp();
19068 if (stamp != date_cache->stamp() && stamp->IsSmi()) {
19069 // Since the stamp is not NaN, the value is also not NaN.
19070 int64_t local_time_ms =
19071 date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
19072 SetCachedFields(local_time_ms, date_cache);
19073 }
19074 switch (index) {
19075 case kYear: return year();
19076 case kMonth: return month();
19077 case kDay: return day();
19078 case kWeekday: return weekday();
19079 case kHour: return hour();
19080 case kMinute: return min();
19081 case kSecond: return sec();
19082 default: UNREACHABLE();
19083 }
19084 }
19085
19086 if (index >= kFirstUTCField) {
19087 return GetUTCField(index, value()->Number(), date_cache);
19088 }
19089
19090 double time = value()->Number();
19091 if (std::isnan(time)) return GetIsolate()->heap()->nan_value();
19092
19093 int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
19094 int days = DateCache::DaysFromTime(local_time_ms);
19095
19096 if (index == kDays) return Smi::FromInt(days);
19097
19098 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
19099 if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
19100 DCHECK(index == kTimeInDay);
19101 return Smi::FromInt(time_in_day_ms);
19102 }
19103
19104
GetUTCField(FieldIndex index,double value,DateCache * date_cache)19105 Object* JSDate::GetUTCField(FieldIndex index,
19106 double value,
19107 DateCache* date_cache) {
19108 DCHECK(index >= kFirstUTCField);
19109
19110 if (std::isnan(value)) return GetIsolate()->heap()->nan_value();
19111
19112 int64_t time_ms = static_cast<int64_t>(value);
19113
19114 if (index == kTimezoneOffset) {
19115 return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
19116 }
19117
19118 int days = DateCache::DaysFromTime(time_ms);
19119
19120 if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
19121
19122 if (index <= kDayUTC) {
19123 int year, month, day;
19124 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
19125 if (index == kYearUTC) return Smi::FromInt(year);
19126 if (index == kMonthUTC) return Smi::FromInt(month);
19127 DCHECK(index == kDayUTC);
19128 return Smi::FromInt(day);
19129 }
19130
19131 int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
19132 switch (index) {
19133 case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
19134 case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
19135 case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
19136 case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
19137 case kDaysUTC: return Smi::FromInt(days);
19138 case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
19139 default: UNREACHABLE();
19140 }
19141
19142 UNREACHABLE();
19143 return NULL;
19144 }
19145
19146
19147 // static
SetValue(Handle<JSDate> date,double v)19148 Handle<Object> JSDate::SetValue(Handle<JSDate> date, double v) {
19149 Isolate* const isolate = date->GetIsolate();
19150 Handle<Object> value = isolate->factory()->NewNumber(v);
19151 bool value_is_nan = std::isnan(v);
19152 date->SetValue(*value, value_is_nan);
19153 return value;
19154 }
19155
19156
SetValue(Object * value,bool is_value_nan)19157 void JSDate::SetValue(Object* value, bool is_value_nan) {
19158 set_value(value);
19159 if (is_value_nan) {
19160 HeapNumber* nan = GetIsolate()->heap()->nan_value();
19161 set_cache_stamp(nan, SKIP_WRITE_BARRIER);
19162 set_year(nan, SKIP_WRITE_BARRIER);
19163 set_month(nan, SKIP_WRITE_BARRIER);
19164 set_day(nan, SKIP_WRITE_BARRIER);
19165 set_hour(nan, SKIP_WRITE_BARRIER);
19166 set_min(nan, SKIP_WRITE_BARRIER);
19167 set_sec(nan, SKIP_WRITE_BARRIER);
19168 set_weekday(nan, SKIP_WRITE_BARRIER);
19169 } else {
19170 set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
19171 }
19172 }
19173
19174
SetCachedFields(int64_t local_time_ms,DateCache * date_cache)19175 void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) {
19176 int days = DateCache::DaysFromTime(local_time_ms);
19177 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
19178 int year, month, day;
19179 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
19180 int weekday = date_cache->Weekday(days);
19181 int hour = time_in_day_ms / (60 * 60 * 1000);
19182 int min = (time_in_day_ms / (60 * 1000)) % 60;
19183 int sec = (time_in_day_ms / 1000) % 60;
19184 set_cache_stamp(date_cache->stamp());
19185 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
19186 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
19187 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
19188 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
19189 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
19190 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
19191 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
19192 }
19193
19194 namespace {
19195
ScriptFromJSValue(Object * in)19196 Script* ScriptFromJSValue(Object* in) {
19197 DCHECK(in->IsJSValue());
19198 JSValue* jsvalue = JSValue::cast(in);
19199 DCHECK(jsvalue->value()->IsScript());
19200 return Script::cast(jsvalue->value());
19201 }
19202
19203 } // namespace
19204
GetLineNumber() const19205 int JSMessageObject::GetLineNumber() const {
19206 if (start_position() == -1) return Message::kNoLineNumberInfo;
19207
19208 Handle<Script> the_script = handle(ScriptFromJSValue(script()));
19209
19210 Script::PositionInfo info;
19211 const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
19212 if (!Script::GetPositionInfo(the_script, start_position(), &info,
19213 offset_flag)) {
19214 return Message::kNoLineNumberInfo;
19215 }
19216
19217 return info.line + 1;
19218 }
19219
GetColumnNumber() const19220 int JSMessageObject::GetColumnNumber() const {
19221 if (start_position() == -1) return -1;
19222
19223 Handle<Script> the_script = handle(ScriptFromJSValue(script()));
19224
19225 Script::PositionInfo info;
19226 const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
19227 if (!Script::GetPositionInfo(the_script, start_position(), &info,
19228 offset_flag)) {
19229 return -1;
19230 }
19231
19232 return info.column; // Note: No '+1' in contrast to GetLineNumber.
19233 }
19234
GetSourceLine() const19235 Handle<String> JSMessageObject::GetSourceLine() const {
19236 Handle<Script> the_script = handle(ScriptFromJSValue(script()));
19237
19238 Isolate* isolate = the_script->GetIsolate();
19239 if (the_script->type() == Script::TYPE_WASM) {
19240 return isolate->factory()->empty_string();
19241 }
19242
19243 Script::PositionInfo info;
19244 const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
19245 if (!Script::GetPositionInfo(the_script, start_position(), &info,
19246 offset_flag)) {
19247 return isolate->factory()->empty_string();
19248 }
19249
19250 Handle<String> src = handle(String::cast(the_script->source()), isolate);
19251 return isolate->factory()->NewSubString(src, info.line_start, info.line_end);
19252 }
19253
Neuter()19254 void JSArrayBuffer::Neuter() {
19255 CHECK(is_neuterable());
19256 CHECK(is_external());
19257 set_backing_store(NULL);
19258 set_byte_length(Smi::kZero);
19259 set_was_neutered(true);
19260 // Invalidate the neutering protector.
19261 Isolate* const isolate = GetIsolate();
19262 if (isolate->IsArrayBufferNeuteringIntact()) {
19263 isolate->InvalidateArrayBufferNeuteringProtector();
19264 }
19265 }
19266
19267
Setup(Handle<JSArrayBuffer> array_buffer,Isolate * isolate,bool is_external,void * data,size_t allocated_length,SharedFlag shared)19268 void JSArrayBuffer::Setup(Handle<JSArrayBuffer> array_buffer, Isolate* isolate,
19269 bool is_external, void* data, size_t allocated_length,
19270 SharedFlag shared) {
19271 DCHECK(array_buffer->GetInternalFieldCount() ==
19272 v8::ArrayBuffer::kInternalFieldCount);
19273 for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) {
19274 array_buffer->SetInternalField(i, Smi::kZero);
19275 }
19276 array_buffer->set_bit_field(0);
19277 array_buffer->set_is_external(is_external);
19278 array_buffer->set_is_neuterable(shared == SharedFlag::kNotShared);
19279 array_buffer->set_is_shared(shared == SharedFlag::kShared);
19280
19281 Handle<Object> byte_length =
19282 isolate->factory()->NewNumberFromSize(allocated_length);
19283 CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
19284 array_buffer->set_byte_length(*byte_length);
19285 // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
19286 // are currently being constructed in the |ArrayBufferTracker|. The
19287 // registration method below handles the case of registering a buffer that has
19288 // already been promoted.
19289 array_buffer->set_backing_store(data);
19290
19291 if (data && !is_external) {
19292 isolate->heap()->RegisterNewArrayBuffer(*array_buffer);
19293 }
19294 }
19295
19296
SetupAllocatingData(Handle<JSArrayBuffer> array_buffer,Isolate * isolate,size_t allocated_length,bool initialize,SharedFlag shared)19297 bool JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer> array_buffer,
19298 Isolate* isolate,
19299 size_t allocated_length,
19300 bool initialize, SharedFlag shared) {
19301 void* data;
19302 CHECK(isolate->array_buffer_allocator() != NULL);
19303 // Prevent creating array buffers when serializing.
19304 DCHECK(!isolate->serializer_enabled());
19305 if (allocated_length != 0) {
19306 if (initialize) {
19307 data = isolate->array_buffer_allocator()->Allocate(allocated_length);
19308 } else {
19309 data = isolate->array_buffer_allocator()->AllocateUninitialized(
19310 allocated_length);
19311 }
19312 if (data == NULL) return false;
19313 } else {
19314 data = NULL;
19315 }
19316
19317 JSArrayBuffer::Setup(array_buffer, isolate, false, data, allocated_length,
19318 shared);
19319 return true;
19320 }
19321
19322
MaterializeArrayBuffer(Handle<JSTypedArray> typed_array)19323 Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
19324 Handle<JSTypedArray> typed_array) {
19325
19326 Handle<Map> map(typed_array->map());
19327 Isolate* isolate = typed_array->GetIsolate();
19328
19329 DCHECK(IsFixedTypedArrayElementsKind(map->elements_kind()));
19330
19331 Handle<FixedTypedArrayBase> fixed_typed_array(
19332 FixedTypedArrayBase::cast(typed_array->elements()));
19333
19334 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(typed_array->buffer()),
19335 isolate);
19336 void* backing_store =
19337 isolate->array_buffer_allocator()->AllocateUninitialized(
19338 fixed_typed_array->DataSize());
19339 buffer->set_is_external(false);
19340 DCHECK(buffer->byte_length()->IsSmi() ||
19341 buffer->byte_length()->IsHeapNumber());
19342 DCHECK(NumberToInt32(buffer->byte_length()) == fixed_typed_array->DataSize());
19343 // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
19344 // are currently being constructed in the |ArrayBufferTracker|. The
19345 // registration method below handles the case of registering a buffer that has
19346 // already been promoted.
19347 buffer->set_backing_store(backing_store);
19348 isolate->heap()->RegisterNewArrayBuffer(*buffer);
19349 memcpy(buffer->backing_store(),
19350 fixed_typed_array->DataPtr(),
19351 fixed_typed_array->DataSize());
19352 Handle<FixedTypedArrayBase> new_elements =
19353 isolate->factory()->NewFixedTypedArrayWithExternalPointer(
19354 fixed_typed_array->length(), typed_array->type(),
19355 static_cast<uint8_t*>(buffer->backing_store()));
19356
19357 typed_array->set_elements(*new_elements);
19358
19359 return buffer;
19360 }
19361
19362
GetBuffer()19363 Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
19364 Handle<JSArrayBuffer> array_buffer(JSArrayBuffer::cast(buffer()),
19365 GetIsolate());
19366 if (array_buffer->was_neutered() ||
19367 array_buffer->backing_store() != nullptr) {
19368 return array_buffer;
19369 }
19370 Handle<JSTypedArray> self(this);
19371 return MaterializeArrayBuffer(self);
19372 }
19373
InvalidateEntry(Handle<GlobalDictionary> dictionary,int entry)19374 Handle<PropertyCell> PropertyCell::InvalidateEntry(
19375 Handle<GlobalDictionary> dictionary, int entry) {
19376 Isolate* isolate = dictionary->GetIsolate();
19377 // Swap with a copy.
19378 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
19379 Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
19380 Handle<PropertyCell> new_cell = isolate->factory()->NewPropertyCell();
19381 new_cell->set_value(cell->value());
19382 dictionary->ValueAtPut(entry, *new_cell);
19383 bool is_the_hole = cell->value()->IsTheHole(isolate);
19384 // Cell is officially mutable henceforth.
19385 PropertyDetails details = cell->property_details();
19386 details = details.set_cell_type(is_the_hole ? PropertyCellType::kUninitialized
19387 : PropertyCellType::kMutable);
19388 new_cell->set_property_details(details);
19389 // Old cell is ready for invalidation.
19390 if (is_the_hole) {
19391 cell->set_value(isolate->heap()->undefined_value());
19392 } else {
19393 cell->set_value(isolate->heap()->the_hole_value());
19394 }
19395 details = details.set_cell_type(PropertyCellType::kInvalidated);
19396 cell->set_property_details(details);
19397 cell->dependent_code()->DeoptimizeDependentCodeGroup(
19398 isolate, DependentCode::kPropertyCellChangedGroup);
19399 return new_cell;
19400 }
19401
19402
GetConstantType()19403 PropertyCellConstantType PropertyCell::GetConstantType() {
19404 if (value()->IsSmi()) return PropertyCellConstantType::kSmi;
19405 return PropertyCellConstantType::kStableMap;
19406 }
19407
19408
RemainsConstantType(Handle<PropertyCell> cell,Handle<Object> value)19409 static bool RemainsConstantType(Handle<PropertyCell> cell,
19410 Handle<Object> value) {
19411 // TODO(dcarney): double->smi and smi->double transition from kConstant
19412 if (cell->value()->IsSmi() && value->IsSmi()) {
19413 return true;
19414 } else if (cell->value()->IsHeapObject() && value->IsHeapObject()) {
19415 return HeapObject::cast(cell->value())->map() ==
19416 HeapObject::cast(*value)->map() &&
19417 HeapObject::cast(*value)->map()->is_stable();
19418 }
19419 return false;
19420 }
19421
19422
UpdatedType(Handle<PropertyCell> cell,Handle<Object> value,PropertyDetails details)19423 PropertyCellType PropertyCell::UpdatedType(Handle<PropertyCell> cell,
19424 Handle<Object> value,
19425 PropertyDetails details) {
19426 PropertyCellType type = details.cell_type();
19427 Isolate* isolate = cell->GetIsolate();
19428 DCHECK(!value->IsTheHole(isolate));
19429 if (cell->value()->IsTheHole(isolate)) {
19430 switch (type) {
19431 // Only allow a cell to transition once into constant state.
19432 case PropertyCellType::kUninitialized:
19433 if (value->IsUndefined(isolate)) return PropertyCellType::kUndefined;
19434 return PropertyCellType::kConstant;
19435 case PropertyCellType::kInvalidated:
19436 return PropertyCellType::kMutable;
19437 default:
19438 UNREACHABLE();
19439 return PropertyCellType::kMutable;
19440 }
19441 }
19442 switch (type) {
19443 case PropertyCellType::kUndefined:
19444 return PropertyCellType::kConstant;
19445 case PropertyCellType::kConstant:
19446 if (*value == cell->value()) return PropertyCellType::kConstant;
19447 // Fall through.
19448 case PropertyCellType::kConstantType:
19449 if (RemainsConstantType(cell, value)) {
19450 return PropertyCellType::kConstantType;
19451 }
19452 // Fall through.
19453 case PropertyCellType::kMutable:
19454 return PropertyCellType::kMutable;
19455 }
19456 UNREACHABLE();
19457 return PropertyCellType::kMutable;
19458 }
19459
PrepareForValue(Handle<GlobalDictionary> dictionary,int entry,Handle<Object> value,PropertyDetails details)19460 Handle<PropertyCell> PropertyCell::PrepareForValue(
19461 Handle<GlobalDictionary> dictionary, int entry, Handle<Object> value,
19462 PropertyDetails details) {
19463 Isolate* isolate = dictionary->GetIsolate();
19464 DCHECK(!value->IsTheHole(isolate));
19465 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
19466 Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
19467 const PropertyDetails original_details = cell->property_details();
19468 // Data accesses could be cached in ics or optimized code.
19469 bool invalidate =
19470 original_details.kind() == kData && details.kind() == kAccessor;
19471 int index = original_details.dictionary_index();
19472 PropertyCellType old_type = original_details.cell_type();
19473 // Preserve the enumeration index unless the property was deleted or never
19474 // initialized.
19475 if (cell->value()->IsTheHole(isolate)) {
19476 index = dictionary->NextEnumerationIndex();
19477 dictionary->SetNextEnumerationIndex(index + 1);
19478 }
19479 DCHECK(index > 0);
19480 details = details.set_index(index);
19481
19482 PropertyCellType new_type = UpdatedType(cell, value, original_details);
19483 if (invalidate) cell = PropertyCell::InvalidateEntry(dictionary, entry);
19484
19485 // Install new property details.
19486 details = details.set_cell_type(new_type);
19487 cell->set_property_details(details);
19488
19489 // Deopt when transitioning from a constant type.
19490 if (!invalidate && (old_type != new_type ||
19491 original_details.IsReadOnly() != details.IsReadOnly())) {
19492 cell->dependent_code()->DeoptimizeDependentCodeGroup(
19493 isolate, DependentCode::kPropertyCellChangedGroup);
19494 }
19495 return cell;
19496 }
19497
19498
19499 // static
SetValueWithInvalidation(Handle<PropertyCell> cell,Handle<Object> new_value)19500 void PropertyCell::SetValueWithInvalidation(Handle<PropertyCell> cell,
19501 Handle<Object> new_value) {
19502 if (cell->value() != *new_value) {
19503 cell->set_value(*new_value);
19504 Isolate* isolate = cell->GetIsolate();
19505 cell->dependent_code()->DeoptimizeDependentCodeGroup(
19506 isolate, DependentCode::kPropertyCellChangedGroup);
19507 }
19508 }
19509
source_position() const19510 int JSGeneratorObject::source_position() const {
19511 CHECK(is_suspended());
19512 DCHECK(function()->shared()->HasBytecodeArray());
19513 DCHECK(!function()->shared()->HasBaselineCode());
19514 int code_offset = Smi::cast(input_or_debug_pos())->value();
19515 // The stored bytecode offset is relative to a different base than what
19516 // is used in the source position table, hence the subtraction.
19517 code_offset -= BytecodeArray::kHeaderSize - kHeapObjectTag;
19518 AbstractCode* code =
19519 AbstractCode::cast(function()->shared()->bytecode_array());
19520 return code->SourcePosition(code_offset);
19521 }
19522
19523 // static
Get(Isolate * isolate,Handle<JSObject> receiver)19524 AccessCheckInfo* AccessCheckInfo::Get(Isolate* isolate,
19525 Handle<JSObject> receiver) {
19526 DisallowHeapAllocation no_gc;
19527 DCHECK(receiver->map()->is_access_check_needed());
19528 Object* maybe_constructor = receiver->map()->GetConstructor();
19529 // Might happen for a detached context.
19530 if (!maybe_constructor->IsJSFunction()) return nullptr;
19531 JSFunction* constructor = JSFunction::cast(maybe_constructor);
19532 // Might happen for the debug context.
19533 if (!constructor->shared()->IsApiFunction()) return nullptr;
19534
19535 Object* data_obj =
19536 constructor->shared()->get_api_func_data()->access_check_info();
19537 if (data_obj->IsUndefined(isolate)) return nullptr;
19538
19539 return AccessCheckInfo::cast(data_obj);
19540 }
19541
HasProxyInPrototype(Isolate * isolate)19542 bool JSReceiver::HasProxyInPrototype(Isolate* isolate) {
19543 for (PrototypeIterator iter(isolate, this, kStartAtReceiver,
19544 PrototypeIterator::END_AT_NULL);
19545 !iter.IsAtEnd(); iter.AdvanceIgnoringProxies()) {
19546 if (iter.GetCurrent<Object>()->IsJSProxy()) return true;
19547 }
19548 return false;
19549 }
19550
GetExport(Handle<String> name)19551 MaybeHandle<Object> JSModuleNamespace::GetExport(Handle<String> name) {
19552 Isolate* isolate = name->GetIsolate();
19553
19554 Handle<Object> object(module()->exports()->Lookup(name), isolate);
19555 if (object->IsTheHole(isolate)) {
19556 return isolate->factory()->undefined_value();
19557 }
19558
19559 Handle<Object> value(Handle<Cell>::cast(object)->value(), isolate);
19560 if (value->IsTheHole(isolate)) {
19561 THROW_NEW_ERROR(
19562 isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object);
19563 }
19564
19565 return value;
19566 }
19567
19568 namespace {
19569
19570 struct ModuleHandleHash {
operator ()v8::internal::__anon5cc50f601b11::ModuleHandleHash19571 V8_INLINE size_t operator()(Handle<Module> module) const {
19572 return module->hash();
19573 }
19574 };
19575
19576 struct ModuleHandleEqual {
operator ()v8::internal::__anon5cc50f601b11::ModuleHandleEqual19577 V8_INLINE bool operator()(Handle<Module> lhs, Handle<Module> rhs) const {
19578 return *lhs == *rhs;
19579 }
19580 };
19581
19582 struct StringHandleHash {
operator ()v8::internal::__anon5cc50f601b11::StringHandleHash19583 V8_INLINE size_t operator()(Handle<String> string) const {
19584 return string->Hash();
19585 }
19586 };
19587
19588 struct StringHandleEqual {
operator ()v8::internal::__anon5cc50f601b11::StringHandleEqual19589 V8_INLINE bool operator()(Handle<String> lhs, Handle<String> rhs) const {
19590 return lhs->Equals(*rhs);
19591 }
19592 };
19593
19594 class UnorderedStringSet
19595 : public std::unordered_set<Handle<String>, StringHandleHash,
19596 StringHandleEqual,
19597 zone_allocator<Handle<String>>> {
19598 public:
UnorderedStringSet(Zone * zone)19599 explicit UnorderedStringSet(Zone* zone)
19600 : std::unordered_set<Handle<String>, StringHandleHash, StringHandleEqual,
19601 zone_allocator<Handle<String>>>(
19602 2 /* bucket count */, StringHandleHash(), StringHandleEqual(),
19603 zone_allocator<Handle<String>>(zone)) {}
19604 };
19605
19606 class UnorderedModuleSet
19607 : public std::unordered_set<Handle<Module>, ModuleHandleHash,
19608 ModuleHandleEqual,
19609 zone_allocator<Handle<Module>>> {
19610 public:
UnorderedModuleSet(Zone * zone)19611 explicit UnorderedModuleSet(Zone* zone)
19612 : std::unordered_set<Handle<Module>, ModuleHandleHash, ModuleHandleEqual,
19613 zone_allocator<Handle<Module>>>(
19614 2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(),
19615 zone_allocator<Handle<Module>>(zone)) {}
19616 };
19617
19618 class UnorderedStringMap
19619 : public std::unordered_map<
19620 Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual,
19621 zone_allocator<std::pair<const Handle<String>, Handle<Object>>>> {
19622 public:
UnorderedStringMap(Zone * zone)19623 explicit UnorderedStringMap(Zone* zone)
19624 : std::unordered_map<
19625 Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual,
19626 zone_allocator<std::pair<const Handle<String>, Handle<Object>>>>(
19627 2 /* bucket count */, StringHandleHash(), StringHandleEqual(),
19628 zone_allocator<std::pair<const Handle<String>, Handle<Object>>>(
19629 zone)) {}
19630 };
19631
19632 } // anonymous namespace
19633
19634 class Module::ResolveSet
19635 : public std::unordered_map<
19636 Handle<Module>, UnorderedStringSet*, ModuleHandleHash,
19637 ModuleHandleEqual, zone_allocator<std::pair<const Handle<Module>,
19638 UnorderedStringSet*>>> {
19639 public:
ResolveSet(Zone * zone)19640 explicit ResolveSet(Zone* zone)
19641 : std::unordered_map<Handle<Module>, UnorderedStringSet*,
19642 ModuleHandleHash, ModuleHandleEqual,
19643 zone_allocator<std::pair<const Handle<Module>,
19644 UnorderedStringSet*>>>(
19645 2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(),
19646 zone_allocator<
19647 std::pair<const Handle<Module>, UnorderedStringSet*>>(zone)),
19648 zone_(zone) {}
19649
zone() const19650 Zone* zone() const { return zone_; }
19651
19652 private:
19653 Zone* zone_;
19654 };
19655
19656 namespace {
19657
ExportIndex(int cell_index)19658 int ExportIndex(int cell_index) {
19659 DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
19660 ModuleDescriptor::kExport);
19661 return cell_index - 1;
19662 }
19663
ImportIndex(int cell_index)19664 int ImportIndex(int cell_index) {
19665 DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
19666 ModuleDescriptor::kImport);
19667 return -cell_index - 1;
19668 }
19669
19670 } // anonymous namespace
19671
CreateIndirectExport(Handle<Module> module,Handle<String> name,Handle<ModuleInfoEntry> entry)19672 void Module::CreateIndirectExport(Handle<Module> module, Handle<String> name,
19673 Handle<ModuleInfoEntry> entry) {
19674 Isolate* isolate = module->GetIsolate();
19675 Handle<ObjectHashTable> exports(module->exports(), isolate);
19676 DCHECK(exports->Lookup(name)->IsTheHole(isolate));
19677 exports = ObjectHashTable::Put(exports, name, entry);
19678 module->set_exports(*exports);
19679 }
19680
CreateExport(Handle<Module> module,int cell_index,Handle<FixedArray> names)19681 void Module::CreateExport(Handle<Module> module, int cell_index,
19682 Handle<FixedArray> names) {
19683 DCHECK_LT(0, names->length());
19684 Isolate* isolate = module->GetIsolate();
19685
19686 Handle<Cell> cell =
19687 isolate->factory()->NewCell(isolate->factory()->undefined_value());
19688 module->regular_exports()->set(ExportIndex(cell_index), *cell);
19689
19690 Handle<ObjectHashTable> exports(module->exports(), isolate);
19691 for (int i = 0, n = names->length(); i < n; ++i) {
19692 Handle<String> name(String::cast(names->get(i)), isolate);
19693 DCHECK(exports->Lookup(name)->IsTheHole(isolate));
19694 exports = ObjectHashTable::Put(exports, name, cell);
19695 }
19696 module->set_exports(*exports);
19697 }
19698
LoadVariable(Handle<Module> module,int cell_index)19699 Handle<Object> Module::LoadVariable(Handle<Module> module, int cell_index) {
19700 Isolate* isolate = module->GetIsolate();
19701 Handle<Object> object;
19702 switch (ModuleDescriptor::GetCellIndexKind(cell_index)) {
19703 case ModuleDescriptor::kImport:
19704 object = handle(module->regular_imports()->get(ImportIndex(cell_index)),
19705 isolate);
19706 break;
19707 case ModuleDescriptor::kExport:
19708 object = handle(module->regular_exports()->get(ExportIndex(cell_index)),
19709 isolate);
19710 break;
19711 case ModuleDescriptor::kInvalid:
19712 UNREACHABLE();
19713 break;
19714 }
19715 return handle(Handle<Cell>::cast(object)->value(), isolate);
19716 }
19717
StoreVariable(Handle<Module> module,int cell_index,Handle<Object> value)19718 void Module::StoreVariable(Handle<Module> module, int cell_index,
19719 Handle<Object> value) {
19720 Isolate* isolate = module->GetIsolate();
19721 DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
19722 ModuleDescriptor::kExport);
19723 Handle<Object> object(module->regular_exports()->get(ExportIndex(cell_index)),
19724 isolate);
19725 Handle<Cell>::cast(object)->set_value(*value);
19726 }
19727
ResolveImport(Handle<Module> module,Handle<String> name,int module_request,MessageLocation loc,bool must_resolve,Module::ResolveSet * resolve_set)19728 MaybeHandle<Cell> Module::ResolveImport(Handle<Module> module,
19729 Handle<String> name, int module_request,
19730 MessageLocation loc, bool must_resolve,
19731 Module::ResolveSet* resolve_set) {
19732 Isolate* isolate = module->GetIsolate();
19733 Handle<Module> requested_module(
19734 Module::cast(module->requested_modules()->get(module_request)), isolate);
19735 return Module::ResolveExport(requested_module, name, loc, must_resolve,
19736 resolve_set);
19737 }
19738
ResolveExport(Handle<Module> module,Handle<String> name,MessageLocation loc,bool must_resolve,Module::ResolveSet * resolve_set)19739 MaybeHandle<Cell> Module::ResolveExport(Handle<Module> module,
19740 Handle<String> name,
19741 MessageLocation loc, bool must_resolve,
19742 Module::ResolveSet* resolve_set) {
19743 Isolate* isolate = module->GetIsolate();
19744 Handle<Object> object(module->exports()->Lookup(name), isolate);
19745 if (object->IsCell()) {
19746 // Already resolved (e.g. because it's a local export).
19747 return Handle<Cell>::cast(object);
19748 }
19749
19750 // Check for cycle before recursing.
19751 {
19752 // Attempt insertion with a null string set.
19753 auto result = resolve_set->insert({module, nullptr});
19754 UnorderedStringSet*& name_set = result.first->second;
19755 if (result.second) {
19756 // |module| wasn't in the map previously, so allocate a new name set.
19757 Zone* zone = resolve_set->zone();
19758 name_set =
19759 new (zone->New(sizeof(UnorderedStringSet))) UnorderedStringSet(zone);
19760 } else if (name_set->count(name)) {
19761 // Cycle detected.
19762 if (must_resolve) {
19763 return isolate->Throw<Cell>(
19764 isolate->factory()->NewSyntaxError(
19765 MessageTemplate::kCyclicModuleDependency, name),
19766 &loc);
19767 }
19768 return MaybeHandle<Cell>();
19769 }
19770 name_set->insert(name);
19771 }
19772
19773 if (object->IsModuleInfoEntry()) {
19774 // Not yet resolved indirect export.
19775 Handle<ModuleInfoEntry> entry = Handle<ModuleInfoEntry>::cast(object);
19776 Handle<String> import_name(String::cast(entry->import_name()), isolate);
19777 Handle<Script> script(
19778 Script::cast(JSFunction::cast(module->code())->shared()->script()),
19779 isolate);
19780 MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos());
19781
19782 Handle<Cell> cell;
19783 if (!ResolveImport(module, import_name, entry->module_request(), new_loc,
19784 true, resolve_set)
19785 .ToHandle(&cell)) {
19786 DCHECK(isolate->has_pending_exception());
19787 return MaybeHandle<Cell>();
19788 }
19789
19790 // The export table may have changed but the entry in question should be
19791 // unchanged.
19792 Handle<ObjectHashTable> exports(module->exports(), isolate);
19793 DCHECK(exports->Lookup(name)->IsModuleInfoEntry());
19794
19795 exports = ObjectHashTable::Put(exports, name, cell);
19796 module->set_exports(*exports);
19797 return cell;
19798 }
19799
19800 DCHECK(object->IsTheHole(isolate));
19801 return Module::ResolveExportUsingStarExports(module, name, loc, must_resolve,
19802 resolve_set);
19803 }
19804
ResolveExportUsingStarExports(Handle<Module> module,Handle<String> name,MessageLocation loc,bool must_resolve,Module::ResolveSet * resolve_set)19805 MaybeHandle<Cell> Module::ResolveExportUsingStarExports(
19806 Handle<Module> module, Handle<String> name, MessageLocation loc,
19807 bool must_resolve, Module::ResolveSet* resolve_set) {
19808 Isolate* isolate = module->GetIsolate();
19809 if (!name->Equals(isolate->heap()->default_string())) {
19810 // Go through all star exports looking for the given name. If multiple star
19811 // exports provide the name, make sure they all map it to the same cell.
19812 Handle<Cell> unique_cell;
19813 Handle<FixedArray> special_exports(module->info()->special_exports(),
19814 isolate);
19815 for (int i = 0, n = special_exports->length(); i < n; ++i) {
19816 i::Handle<i::ModuleInfoEntry> entry(
19817 i::ModuleInfoEntry::cast(special_exports->get(i)), isolate);
19818 if (!entry->export_name()->IsUndefined(isolate)) {
19819 continue; // Indirect export.
19820 }
19821
19822 Handle<Script> script(
19823 Script::cast(JSFunction::cast(module->code())->shared()->script()),
19824 isolate);
19825 MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos());
19826
19827 Handle<Cell> cell;
19828 if (ResolveImport(module, name, entry->module_request(), new_loc, false,
19829 resolve_set)
19830 .ToHandle(&cell)) {
19831 if (unique_cell.is_null()) unique_cell = cell;
19832 if (*unique_cell != *cell) {
19833 return isolate->Throw<Cell>(
19834 isolate->factory()->NewSyntaxError(
19835 MessageTemplate::kAmbiguousExport, name),
19836 &loc);
19837 }
19838 } else if (isolate->has_pending_exception()) {
19839 return MaybeHandle<Cell>();
19840 }
19841 }
19842
19843 if (!unique_cell.is_null()) {
19844 // Found a unique star export for this name.
19845 Handle<ObjectHashTable> exports(module->exports(), isolate);
19846 DCHECK(exports->Lookup(name)->IsTheHole(isolate));
19847 exports = ObjectHashTable::Put(exports, name, unique_cell);
19848 module->set_exports(*exports);
19849 return unique_cell;
19850 }
19851 }
19852
19853 // Unresolvable.
19854 if (must_resolve) {
19855 return isolate->Throw<Cell>(isolate->factory()->NewSyntaxError(
19856 MessageTemplate::kUnresolvableExport, name),
19857 &loc);
19858 }
19859 return MaybeHandle<Cell>();
19860 }
19861
Instantiate(Handle<Module> module,v8::Local<v8::Context> context,v8::Module::ResolveCallback callback)19862 bool Module::Instantiate(Handle<Module> module, v8::Local<v8::Context> context,
19863 v8::Module::ResolveCallback callback) {
19864 if (module->instantiated()) return true;
19865
19866 Isolate* isolate = module->GetIsolate();
19867 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(module->code()),
19868 isolate);
19869 Handle<JSFunction> function =
19870 isolate->factory()->NewFunctionFromSharedFunctionInfo(
19871 shared,
19872 handle(Utils::OpenHandle(*context)->native_context(), isolate));
19873 module->set_code(*function);
19874 DCHECK(module->instantiated());
19875
19876 Handle<ModuleInfo> module_info(shared->scope_info()->ModuleDescriptorInfo(),
19877 isolate);
19878
19879 // Set up local exports.
19880 // TODO(neis): Create regular_exports array here instead of in factory method?
19881 for (int i = 0, n = module_info->RegularExportCount(); i < n; ++i) {
19882 int cell_index = module_info->RegularExportCellIndex(i);
19883 Handle<FixedArray> export_names(module_info->RegularExportExportNames(i),
19884 isolate);
19885 CreateExport(module, cell_index, export_names);
19886 }
19887
19888 // Partially set up indirect exports.
19889 // For each indirect export, we create the appropriate slot in the export
19890 // table and store its ModuleInfoEntry there. When we later find the correct
19891 // Cell in the module that actually provides the value, we replace the
19892 // ModuleInfoEntry by that Cell (see ResolveExport).
19893 Handle<FixedArray> special_exports(module_info->special_exports(), isolate);
19894 for (int i = 0, n = special_exports->length(); i < n; ++i) {
19895 Handle<ModuleInfoEntry> entry(
19896 ModuleInfoEntry::cast(special_exports->get(i)), isolate);
19897 Handle<Object> export_name(entry->export_name(), isolate);
19898 if (export_name->IsUndefined(isolate)) continue; // Star export.
19899 CreateIndirectExport(module, Handle<String>::cast(export_name), entry);
19900 }
19901
19902 Handle<FixedArray> module_requests(module_info->module_requests(), isolate);
19903 for (int i = 0, length = module_requests->length(); i < length; ++i) {
19904 Handle<String> specifier(String::cast(module_requests->get(i)), isolate);
19905 v8::Local<v8::Module> api_requested_module;
19906 // TODO(adamk): Revisit these failure cases once d8 knows how to
19907 // persist a module_map across multiple top-level module loads, as
19908 // the current module is left in a "half-instantiated" state.
19909 if (!callback(context, v8::Utils::ToLocal(specifier),
19910 v8::Utils::ToLocal(module))
19911 .ToLocal(&api_requested_module)) {
19912 // TODO(adamk): Give this a better error message. But this is a
19913 // misuse of the API anyway.
19914 isolate->ThrowIllegalOperation();
19915 return false;
19916 }
19917 Handle<Module> requested_module = Utils::OpenHandle(*api_requested_module);
19918 module->requested_modules()->set(i, *requested_module);
19919 if (!Instantiate(requested_module, context, callback)) {
19920 return false;
19921 }
19922 }
19923
19924 Zone zone(isolate->allocator(), ZONE_NAME);
19925
19926 // Resolve imports.
19927 Handle<FixedArray> regular_imports(module_info->regular_imports(), isolate);
19928 for (int i = 0, n = regular_imports->length(); i < n; ++i) {
19929 Handle<ModuleInfoEntry> entry(
19930 ModuleInfoEntry::cast(regular_imports->get(i)), isolate);
19931 Handle<String> name(String::cast(entry->import_name()), isolate);
19932 Handle<Script> script(
19933 Script::cast(JSFunction::cast(module->code())->shared()->script()),
19934 isolate);
19935 MessageLocation loc(script, entry->beg_pos(), entry->end_pos());
19936 ResolveSet resolve_set(&zone);
19937 Handle<Cell> cell;
19938 if (!ResolveImport(module, name, entry->module_request(), loc, true,
19939 &resolve_set)
19940 .ToHandle(&cell)) {
19941 return false;
19942 }
19943 module->regular_imports()->set(ImportIndex(entry->cell_index()), *cell);
19944 }
19945
19946 // Resolve indirect exports.
19947 for (int i = 0, n = special_exports->length(); i < n; ++i) {
19948 Handle<ModuleInfoEntry> entry(
19949 ModuleInfoEntry::cast(special_exports->get(i)), isolate);
19950 Handle<Object> name(entry->export_name(), isolate);
19951 if (name->IsUndefined(isolate)) continue; // Star export.
19952 Handle<Script> script(
19953 Script::cast(JSFunction::cast(module->code())->shared()->script()),
19954 isolate);
19955 MessageLocation loc(script, entry->beg_pos(), entry->end_pos());
19956 ResolveSet resolve_set(&zone);
19957 if (ResolveExport(module, Handle<String>::cast(name), loc, true,
19958 &resolve_set)
19959 .is_null()) {
19960 return false;
19961 }
19962 }
19963
19964 return true;
19965 }
19966
Evaluate(Handle<Module> module)19967 MaybeHandle<Object> Module::Evaluate(Handle<Module> module) {
19968 DCHECK(module->instantiated());
19969
19970 // Each module can only be evaluated once.
19971 Isolate* isolate = module->GetIsolate();
19972 if (module->evaluated()) return isolate->factory()->undefined_value();
19973 Handle<JSFunction> function(JSFunction::cast(module->code()), isolate);
19974 module->set_evaluated();
19975
19976 // Initialization.
19977 DCHECK_EQ(MODULE_SCOPE, function->shared()->scope_info()->scope_type());
19978 Handle<Object> receiver = isolate->factory()->undefined_value();
19979 Handle<Object> argv[] = {module};
19980 Handle<Object> generator;
19981 ASSIGN_RETURN_ON_EXCEPTION(
19982 isolate, generator,
19983 Execution::Call(isolate, function, receiver, arraysize(argv), argv),
19984 Object);
19985
19986 // Recursion.
19987 Handle<FixedArray> requested_modules(module->requested_modules(), isolate);
19988 for (int i = 0, length = requested_modules->length(); i < length; ++i) {
19989 Handle<Module> import(Module::cast(requested_modules->get(i)), isolate);
19990 RETURN_ON_EXCEPTION(isolate, Evaluate(import), Object);
19991 }
19992
19993 // Evaluation of module body.
19994 Handle<JSFunction> resume(
19995 isolate->native_context()->generator_next_internal(), isolate);
19996 return Execution::Call(isolate, resume, generator, 0, nullptr);
19997 }
19998
19999 namespace {
20000
FetchStarExports(Handle<Module> module,Zone * zone,UnorderedModuleSet * visited)20001 void FetchStarExports(Handle<Module> module, Zone* zone,
20002 UnorderedModuleSet* visited) {
20003 DCHECK(module->instantiated());
20004
20005 bool cycle = !visited->insert(module).second;
20006 if (cycle) return;
20007
20008 Isolate* isolate = module->GetIsolate();
20009 Handle<ObjectHashTable> exports(module->exports(), isolate);
20010 UnorderedStringMap more_exports(zone);
20011
20012 // TODO(neis): Only allocate more_exports if there are star exports.
20013 // Maybe split special_exports into indirect_exports and star_exports.
20014
20015 Handle<FixedArray> special_exports(module->info()->special_exports(),
20016 isolate);
20017 for (int i = 0, n = special_exports->length(); i < n; ++i) {
20018 Handle<ModuleInfoEntry> entry(
20019 ModuleInfoEntry::cast(special_exports->get(i)), isolate);
20020 if (!entry->export_name()->IsUndefined(isolate)) {
20021 continue; // Indirect export.
20022 }
20023
20024 Handle<Module> requested_module(
20025 Module::cast(module->requested_modules()->get(entry->module_request())),
20026 isolate);
20027
20028 // Recurse.
20029 FetchStarExports(requested_module, zone, visited);
20030
20031 // Collect all of [requested_module]'s exports that must be added to
20032 // [module]'s exports (i.e. to [exports]). We record these in
20033 // [more_exports]. Ambiguities (conflicting exports) are marked by mapping
20034 // the name to undefined instead of a Cell.
20035 Handle<ObjectHashTable> requested_exports(requested_module->exports(),
20036 isolate);
20037 for (int i = 0, n = requested_exports->Capacity(); i < n; ++i) {
20038 Handle<Object> key(requested_exports->KeyAt(i), isolate);
20039 if (!requested_exports->IsKey(isolate, *key)) continue;
20040 Handle<String> name = Handle<String>::cast(key);
20041
20042 if (name->Equals(isolate->heap()->default_string())) continue;
20043 if (!exports->Lookup(name)->IsTheHole(isolate)) continue;
20044
20045 Handle<Cell> cell(Cell::cast(requested_exports->ValueAt(i)), isolate);
20046 auto insert_result = more_exports.insert(std::make_pair(name, cell));
20047 if (!insert_result.second) {
20048 auto it = insert_result.first;
20049 if (*it->second == *cell || it->second->IsUndefined(isolate)) {
20050 // We already recorded this mapping before, or the name is already
20051 // known to be ambiguous. In either case, there's nothing to do.
20052 } else {
20053 DCHECK(it->second->IsCell());
20054 // Different star exports provide different cells for this name, hence
20055 // mark the name as ambiguous.
20056 it->second = isolate->factory()->undefined_value();
20057 }
20058 }
20059 }
20060 }
20061
20062 // Copy [more_exports] into [exports].
20063 for (const auto& elem : more_exports) {
20064 if (elem.second->IsUndefined(isolate)) continue; // Ambiguous export.
20065 DCHECK(!elem.first->Equals(isolate->heap()->default_string()));
20066 DCHECK(elem.second->IsCell());
20067 exports = ObjectHashTable::Put(exports, elem.first, elem.second);
20068 }
20069 module->set_exports(*exports);
20070 }
20071
20072 } // anonymous namespace
20073
GetModuleNamespace(Handle<Module> module,int module_request)20074 Handle<JSModuleNamespace> Module::GetModuleNamespace(Handle<Module> module,
20075 int module_request) {
20076 Isolate* isolate = module->GetIsolate();
20077 Handle<Module> requested_module(
20078 Module::cast(module->requested_modules()->get(module_request)), isolate);
20079 return Module::GetModuleNamespace(requested_module);
20080 }
20081
GetModuleNamespace(Handle<Module> module)20082 Handle<JSModuleNamespace> Module::GetModuleNamespace(Handle<Module> module) {
20083 Isolate* isolate = module->GetIsolate();
20084
20085 Handle<HeapObject> object(module->module_namespace(), isolate);
20086 if (!object->IsUndefined(isolate)) {
20087 // Namespace object already exists.
20088 return Handle<JSModuleNamespace>::cast(object);
20089 }
20090
20091 // Create the namespace object (initially empty).
20092 Handle<JSModuleNamespace> ns = isolate->factory()->NewJSModuleNamespace();
20093 ns->set_module(*module);
20094 module->set_module_namespace(*ns);
20095
20096 // Collect the export names.
20097 Zone zone(isolate->allocator(), ZONE_NAME);
20098 UnorderedModuleSet visited(&zone);
20099 FetchStarExports(module, &zone, &visited);
20100 Handle<ObjectHashTable> exports(module->exports(), isolate);
20101 ZoneVector<Handle<String>> names(&zone);
20102 names.reserve(exports->NumberOfElements());
20103 for (int i = 0, n = exports->Capacity(); i < n; ++i) {
20104 Handle<Object> key(exports->KeyAt(i), isolate);
20105 if (!exports->IsKey(isolate, *key)) continue;
20106 DCHECK(exports->ValueAt(i)->IsCell());
20107 names.push_back(Handle<String>::cast(key));
20108 }
20109 DCHECK_EQ(static_cast<int>(names.size()), exports->NumberOfElements());
20110
20111 // Sort them alphabetically.
20112 struct {
20113 bool operator()(Handle<String> a, Handle<String> b) {
20114 return String::Compare(a, b) == ComparisonResult::kLessThan;
20115 }
20116 } StringLess;
20117 std::sort(names.begin(), names.end(), StringLess);
20118
20119 // Create the corresponding properties in the namespace object.
20120 PropertyAttributes attr = DONT_DELETE;
20121 for (const auto& name : names) {
20122 JSObject::SetAccessor(
20123 ns, Accessors::ModuleNamespaceEntryInfo(isolate, name, attr))
20124 .Check();
20125 }
20126 JSObject::PreventExtensions(ns, THROW_ON_ERROR).ToChecked();
20127
20128 return ns;
20129 }
20130
TryGetCachedPropertyName(Isolate * isolate,Handle<Object> getter)20131 MaybeHandle<Name> FunctionTemplateInfo::TryGetCachedPropertyName(
20132 Isolate* isolate, Handle<Object> getter) {
20133 if (getter->IsFunctionTemplateInfo()) {
20134 Handle<FunctionTemplateInfo> fti =
20135 Handle<FunctionTemplateInfo>::cast(getter);
20136 // Check if the accessor uses a cached property.
20137 if (!fti->cached_property_name()->IsTheHole(isolate)) {
20138 return handle(Name::cast(fti->cached_property_name()));
20139 }
20140 }
20141 return MaybeHandle<Name>();
20142 }
20143
20144 // static
ElementsKindForInstanceType(InstanceType type)20145 ElementsKind JSArrayIterator::ElementsKindForInstanceType(InstanceType type) {
20146 DCHECK_GE(type, FIRST_ARRAY_ITERATOR_TYPE);
20147 DCHECK_LE(type, LAST_ARRAY_ITERATOR_TYPE);
20148
20149 if (type <= LAST_ARRAY_KEY_ITERATOR_TYPE) {
20150 // Should be ignored for key iterators.
20151 return FAST_ELEMENTS;
20152 } else {
20153 ElementsKind kind;
20154 if (type < FIRST_ARRAY_VALUE_ITERATOR_TYPE) {
20155 // Convert `type` to a value iterator from an entries iterator
20156 type = static_cast<InstanceType>(type +
20157 (FIRST_ARRAY_VALUE_ITERATOR_TYPE -
20158 FIRST_ARRAY_KEY_VALUE_ITERATOR_TYPE));
20159 DCHECK_GE(type, FIRST_ARRAY_VALUE_ITERATOR_TYPE);
20160 DCHECK_LE(type, LAST_ARRAY_ITERATOR_TYPE);
20161 }
20162
20163 if (type <= JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE) {
20164 kind =
20165 static_cast<ElementsKind>(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND +
20166 (type - FIRST_ARRAY_VALUE_ITERATOR_TYPE));
20167 DCHECK_LE(kind, LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
20168 } else if (type < JS_GENERIC_ARRAY_VALUE_ITERATOR_TYPE) {
20169 kind = static_cast<ElementsKind>(
20170 FIRST_FAST_ELEMENTS_KIND +
20171 (type - JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE));
20172 DCHECK_LE(kind, LAST_FAST_ELEMENTS_KIND);
20173 } else {
20174 // For any slow element cases, the actual elements kind is not known.
20175 // Simply
20176 // return a slow elements kind in this case. Users of this function must
20177 // not
20178 // depend on this.
20179 return DICTIONARY_ELEMENTS;
20180 }
20181 DCHECK_LE(kind, LAST_ELEMENTS_KIND);
20182 return kind;
20183 }
20184 }
20185
20186 } // namespace internal
20187 } // namespace v8
20188